Add BLS and forging public key to validator account

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 contain tx.asset.validatorBLSKey.
  • PopVerify(tx.asset.validatorBLSKey, tx.asset.proofOfPossession) must return VALID, where PopVerify 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 to tx.asset.validatorBLSKey.
  • Append tx.asset.validatorBLSKey to BLSKeys.
  • The forgingKey property of the sending account is set to tx.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 to tx.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 to b.header.generatorAddress.
  • account must be the validator account that is assigned to the block slot corresponding to b.header.timestamp.
  • b.header.signature must be a valid signature with regard to the forging key of account.

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 setting tx.asset.validatorBLSKey to the public key pk.
  • Setting tx.asset.proofOfPossession to the proof of possession generated by PopProve(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 setting tx.asset.validatorBLSKey to the public key pk.
  • Setting tx.asset.proofOfPossession to the proof of possession generated by PopProve(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 of account is equal to the empty bytes value.
  • BLSKeys does not contain tx.asset.validatorBLSKey.
  • PopVerify(tx.asset.validatorBLSKey, tx.asset.proofOfPossession) must return VALID, where PopVerify 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 to tx.asset.validatorBLSKey.
  • Append tx.asset.validatorBLSKey to BLSKeys.
2 Likes