Hello everyone,
I would like to propose a new LIP for the roadmap objective “Enhance signature scheme.” This LIP specifies how BLS public keys are added to validator accounts, which is a requirement for the certificate generation. Moreover, we introduce forging keys which is a security feature for validators; in particular for those running a node on a remote data center.
I’m looking forward to your feedback.
Here is the complete LIP draft:
LIP: <LIP number>
Title: Add BLS and forging public key to validator account
Author: Andreas Kendziorra <andreas.kendziorra@lightcurve.io>
Type: Standards Track
Created: <YYYY-MM-DD>
Updated: <YYYY-MM-DD>
Requires: LIP 0038, Introduce a certificate generation mechanism LIP
Abstract
The Introduce a certificate generation mechanism LIP requires that every validator has a registered BLS public key. In this LIP we specify how a BLS public key is added to a validator account. Moreover, we introduce forging keys for validator accounts. A forging key is an Ed25519 public key, and block signatures must be valid with regard to the forging key. This allows that validators only need to store the encrypted passphrase or secret key for the forging key on a node, but not the secret key or passphrase for the regular account key pair that is used for transaction signatures.
Copyright
This LIP is licensed under the Creative Commons Zero 1.0 Universal.
Motivation
BLS Public Key
As specified in the LIP Introduce a certificate generation mechanism, each validator needs to create some BLS signatures for commits. In order to do so, a BLS public key needs to be added to each validator account. This will be specified in this proposal.
Forging Key
To be able to create block signatures, the secret key of the validator account needs to be accessible for a forging node. The most common approach is to store the encrypted passphrase that yields the secret key (or the encrypted secret key) on the node, where the encryption key is derived from a password-based key derivation function. This results in a small security risk: If an attacker is able to get the encrypted passphrase (or encrypted secret key) and the password for the encryption key derivation, the attacker has full control over the validator account. This may be a bigger concern for validators running a Lisk node on a remote data center.
To mitigate this risk, we propose to add an extra key pair to a validator account that is used for creating block signatures. Then, a forging node only requires access to the secret forging key, but not to the secret that is used for signing transactions. To increase security even further, validators should be able to update the forging key pair at any time.
Specification
Constants
The following constants will be used in the remainder of this document:
Name | Value |
---|---|
MODULE_ID_DPOS |
5 |
MODULE_ID_POA |
TBA |
ASSET_ID_DELEGATE_REG |
0 |
ASSET_ID_DELEGATE_REG_NEW |
4 |
ASSET_ID_AUTHORITY_REG |
1 |
New Properties
Validator accounts need to store the two additional properties validatorBLSKey
and forgingKey
, where both are of type bytes. The validatorBLSKey
property contains a BLS public key. This property cannot be updated. The forgingKey
property contains an Ed25519 public key. This property can be updated via an update forging key transaction.
Moreover, the additional property BLSKeys
needs to be stored in the state. This property is an array for which the items are of type bytes. This array contains the validatorBLSKey
values from all registered validators in the chain, in registration order.
Updated Registration Transactions
New validators registering either via a delegate registration transaction or an authority registration transaction need to provide the validatorBLSKey
and the forgingKey
in their registration transaction. Hence, the two registration transactions need to be updated.
Note that both transactions have the same schema, validity rules and similar effect on the state of their respective modules. Therefore, the updates for the schema, validity rules and state changes in the following subsections apply for both the delegate registration transaction and the authority registration transaction. In fact, the current delegate registration (module ID = MODULE_ID_DPOS
, asset ID = ASSET_ID_DELEGATE_REG
) is replaced by a new one (module ID = MODULE_ID_DPOS
, asset ID = ASSET_ID_DELEGATE_REG_NEW
). Since the currently proposed authority registration transaction (module ID = MODULE_ID_POA
, asset ID = ASSET_ID_AUTHORITY_REG
) has not been implemented yet, we propose to update its initial version and therefore keep the asset ID.
How a valid delegate registration transaction or authority registration transaction can be created is described in the appendix.
Asset Schema
The asset property of the delegate registration transaction and authority registration transaction must obey the following schema:
registrationTransactionAssetSchema = {
"type": "object",
"properties": {
"username": {
"dataType": "string",
"fieldNumber": 1
},
"validatorBLSKey": {
"dataType": "bytes",
"fieldNumber": 2
},
"proofOfPossession": {
"dataType": "bytes",
"fieldNumber": 3
},
"forgingKey": {
"dataType": "bytes",
"fieldNumber": 4
}
},
"required": ["username", "validatorBLSKey", "proofOfPossession", "forgingKey"]
}
Validity Rules
The existing validity rules for the delegate registration transaction and authority registration transaction get extended by the new validity rules listed in the following. For this, let tx
be a delegate registration transaction or an authority registration transaction and let account
denote the account corresponding to tx.senderPublicKey
:
-
BLSKeys
must not containtx.asset.validatorBLSKey
. -
PopVerify(tx.asset.validatorBLSKey, tx.asset.proofOfPossession)
must returnVALID
, wherePopVerify
is part of the BLS signature scheme. -
tx.asset.forgingKey
must have length 32.
State Changes
Next to the existing apply rules, the following additional state changes must be applied when a delegate registration transaction or authority registration transaction transaction tx
is applied:
- The
validatorBLSKey
property of the sending account is set totx.asset.validatorBLSKey
. - Append
tx.asset.validatorBLSKey
toBLSKeys
. - The
forgingKey
property of the sending account is set totx.asset.forgingKey
.
Updating the Forging Key
Forging keys can be updated via update forging key transactions which are described in the following subsection.
Update Forging Key Transaction
Asset Schema
The asset property of an update forging key transaction must obey the following schema.
updateForgingKeyAssetSchema = {
"type": "object",
"properties": {
"forgingKey": {
"dataType": "bytes",
"fieldNumber": 1
}
},
"required": ["forgingKey"]
}
Validity Rules
An update forging key transaction tx
must fulfill the following points in order to be valid, where account
denotes the account corresponding to tx.senderPublicKey
:
-
account
is a validator account. -
tx.asset.forgingKey
must have length 32.
State Changes
Applying an update forging key transaction tx
results in the following state change:
- The
forgingKey
property of the sending account is set totx.asset.forgingKey
.
Block Header Schema and Block Validation
Block Header Schema
The block header schema is changed: The generatorPublicKey
property is replaced by the generatorAddress
property which is of type bytes.
Block Validation
For a block b
to be valid, the following additional points must hold:
-
b.header.generatorAddress
must have a length of 20 bytes. - There must be a validator account
account
corresponding tob.header.generatorAddress
. -
account
must be the validator account that is assigned to the block slot corresponding tob.header.timestamp
. -
b.header.signature
must be a valid signature with regard to the forging key ofaccount
.
Existing Validators on Lisk Mainchain
The specifications up to here are sufficient for chains that incorporate this proposal from their genesis block on. For the Lisk mainchain, however, it is not sufficient. A migration strategy needs to be defined that ensures that from a certain height on, every non-banned validator on the mainchain has its forgingKey
and validatorBLSKey
properties set. As the exact migration strategy for the Lisk mainchain should be defined once the list of incorporated LIPs is complete, we only add some proposals to the appendix.
Rationale
Why can the Validator BLS Key not be updated?
Two chains that interoperate with each other maintain the set of validators and their BLS keys from the other chain, and the keys are used to validate certificates contained in cross-chain update transactions. If updates for validator BLS keys were allowed, the process for keeping the other chain up-to-date about the validator set would become much more complex.
Why is the Block Header Schema Changed?
Without this proposal, the generatorPublicKey
property of a block header was fulfilling two purposes: 1) The validator account was deduced by deriving the address from it, and 2) the block signature could be validated without any on-chain data. The first purpose is obviously a must whereas the second is not. In order to fulfill point 1), one could keep the generatorPublicKey
property and require that the value must yield the address of the validator account eligible to forge the block for the corresponding block slot. The signature validation could, however, not be done without on-chain data, because the forging key of the account is not contained in the block. Hence, there is no further drawback in replacing the generatorPublicKey
property by the generatorAddress
property, while it has the advantages of reducing the size of the block header by a few bytes and skipping the address derivation step during block validation.
Backwards Compatibility
Running chains that adopt this proposal must do this via a hard fork, because
- the structure of validator accounts changes,
- the delegate registration transaction is replaced by a new one (we assume that running chains use DPoS) and
- the block header schema and the block validation changes.
Such a hard fork requires a migration strategy as proposed in the appendix.
Appendix
Creating a Delegate or Authority Registration Transaction
To register as a validator, a user needs to submit a delegate registration transaction or an authority registration transaction, depending on the choice between DPoS and PoA. A delegate registration transaction or authority registration transaction transaction tx
is created by:
- Setting
tx.asset.username
to the desired user name. - Setting
tx.asset.forgingKey
to the desired Ed25519 public key. - Choosing a BLS key pair
(sk, pk)
as described in the “Keypair Creation” section of LIP 0038 and settingtx.asset.validatorBLSKey
to the public keypk
. - Setting
tx.asset.proofOfPossession
to the proof of possession generated byPopProve(sk)
as described in the “Public Key Registration and Proof of Possession” section of LIP 0038.
Lisk Mainchain Migration
The exact migration strategy for the Lisk mainchain for the hard fork that incorporates this LIP should be defined once the list of incorporated LIPs is complete. Here, we present some proposals for this LIP that could be used.
Set Forging Keys
For the forgingKey
property, we have two proposals for the migration. The first one utilizes a snapshot block. The second one proposes a migration phase in which validators need to set their forging key.
Proposal 1: Set Forging Keys in a Snapshot Block
A snapshot block, similar to the one defined in LIP 0035, is used. This block contains every validator account and every validator account has the forgingKey
property.
Creating the Snapshot Block
The forgingKey
property of a validator account is set to senderPublicKey
of the delegate registration transaction. Hence, creating the snapshot block requires to have the whole transaction history of the Lisk mainchain available.
Note that with this approach the initial forging key-pair is exactly the key-pair that was used before by the validator for every transaction and block signature. Validators should perform an update forging key transaction after the snapshot block to make use of the security features of this proposal.
Validating the Snapshot Block
Although not every node may be able to create the snapshot block, every node is able to validate it. During the validation, it must be checked that the address derived from forgingKey
is the one of the validator account.
Proposal 2: Validators set Forging Keys during Migration Phase
This proposal uses two hard forks, say at heights h1
and h2
. The period between h1
and h2
is called migration phase.
When applying the block at h1
, every validator account gets the forgingKey
property which is set to the empty bytes value. For blocks with height < h2
, the changes regarding the block header schema and block validation are not applied. That means, block headers have the generatorPublicKey
property and block signatures are validated against this one. During the migration phase, validators must send an update forging key transaction that must be included before h2
.
When applying the block at h2
, every validator account with forgingKey
equal to the empty bytes value is banned. Moreover, the changes regarding the block header schema and block validation are applied from h2
on.
Set Validator BLS Keys
This proposal is almost equivalent to the second proposal for forging keys which uses a migration phase. Let h1
and h2
be as before and let the period between h1
and h2
again be called migration phase.
Then, every validator account gets the validatorBLSKey
property which is set to the empty bytes value when the block at height h1
is applied. During the migration phase, validators must send an add validator BLS key transaction (defined below) that must be included before h2
.
When applying the block at h2
, every validator account with validatorBLSKey
equal to the empty bytes value is banned.
Add Validator BLS Key Transaction
Asset Schema
The asset property of an add validator BLS key transaction must obey the following schema.
addValidatorBLSKeyAssetSchema = {
"type": "object",
"properties": {
"validatorBLSKey": {
"dataType": "bytes",
"fieldNumber": 1
},
"proofOfPossession": {
"dataType": "bytes",
"fieldNumber": 2
}
},
"required": ["validatorBLSKey", "proofOfPossession"]
}
Creating a Add Validator BLS Key Transaction
An add validator BLS key transaction tx
is created by:
- Choosing a BLS key pair
(sk, pk)
as described in the “Keypair Creation” section of LIP 0038 and settingtx.asset.validatorBLSKey
to the public keypk
. - Setting
tx.asset.proofOfPossession
to the proof of possession generated byPopProve(sk)
as described in the “Public Key Registration and Proof of Possession” section of LIP 0038.
Validity Rules
An add validator BLS key transaction tx
must fulfill the following points in order to be valid, where account
denotes the account corresponding to tx.senderPublicKey
:
-
account
is a validator account. - The
validatorBLSKey
property ofaccount
is equal to the empty bytes value. -
BLSKeys
does not containtx.asset.validatorBLSKey
. -
PopVerify(tx.asset.validatorBLSKey, tx.asset.proofOfPossession)
must returnVALID
, wherePopVerify
is part of the BLS signature scheme.
State Changes
Applying an add validator BLS key transaction tx
results in the following state changes:
- The
validatorBLSKey
property of the sending account is set totx.asset.validatorBLSKey
. - Append
tx.asset.validatorBLSKey
toBLSKeys
.