|
|
@@ -0,0 +1,251 @@
|
|
|
+---
|
|
|
+simd: '0387'
|
|
|
+title: BLS Pubkey management in vote account
|
|
|
+authors:
|
|
|
+ - Sam Kim (Anza)
|
|
|
+ - Quentin Kniep (Anza)
|
|
|
+ - Wen Xu (Anza)
|
|
|
+category: Standard
|
|
|
+type: Core
|
|
|
+status: Review
|
|
|
+created: 2025-10-27
|
|
|
+feature: (fill in with feature key and github tracking issues once accepted)
|
|
|
+---
|
|
|
+
|
|
|
+## Summary
|
|
|
+
|
|
|
+This proposal specifies in detail how a BLS public key can be generated by
|
|
|
+users via updated existing tools and how they can put the generated BLS public
|
|
|
+keys into their vote accounts for voting in Alpenglow.
|
|
|
+
|
|
|
+It also describes in detail the data structure changes needed.
|
|
|
+
|
|
|
+## Motivation
|
|
|
+
|
|
|
+The Alpenglow SIMD (326) described the new consensus protocol which will be
|
|
|
+launched on Solana. The protocol requires efficient and safe aggregation of
|
|
|
+validator votes to succinctly prove certain state transitions can safely happen
|
|
|
+(for example, 60% of the validators voted to skip a slot). The ed25519
|
|
|
+signatures we currently use are not the best fit for this purpose, so instead
|
|
|
+we will be using the Boneh–Lynn–Shacham (BLS) aggregate signature scheme to
|
|
|
+sign Alpenglow votes.
|
|
|
+
|
|
|
+However, the BLS public key is entirely different from an ed25519 public key
|
|
|
+(as BLS operates over a different elliptic curve), so we can’t naively reuse
|
|
|
+the current ed25519 public keys in vote accounts either. Each validator must
|
|
|
+add a BLS public key into their vote account before the network enables Alpenglow
|
|
|
+in order to vote.
|
|
|
+
|
|
|
+## New Terminology
|
|
|
+
|
|
|
+N/A
|
|
|
+
|
|
|
+## Dependencies
|
|
|
+
|
|
|
+- Alpenglow is specified in [SIMD 326](https://github.com/solana-foundation/solana-improvement-documents/pull/326)
|
|
|
+
|
|
|
+- VoteStateV4 is specified in [SIMD 185](https://github.com/solana-foundation/solana-improvement-documents/pull/185)
|
|
|
+and it adds an optional BLS public key field
|
|
|
+
|
|
|
+- Requiring BLS public key for Alpenglow is specified in [SIMD 357](https://github.com/solana-foundation/solana-improvement-documents/pull/357)
|
|
|
+
|
|
|
+## Detailed Design
|
|
|
+
|
|
|
+BLS keypairs can be generated randomly like ed25519 keypairs. But to save the
|
|
|
+users some trouble on keypair management, the current plan is to initially
|
|
|
+derive their BLS keypair used in Alpenglow votes based on their ed25519 vote
|
|
|
+keypair. In other words, with an existing ed25519 vote keypair, the operators
|
|
|
+can safely regenerate the associated BLS keypair on demand. Also during
|
|
|
+validator operations, the users still only need to supply the vote keypair as
|
|
|
+before.
|
|
|
+
|
|
|
+The association of BLS keypair with vote authority ed25519 keypair is the
|
|
|
+default client behavior to simplify Alpenglow launch. After Alpenglow launches
|
|
|
+we may get rid of ed25519 vote keypair and allow users to randomly generate BLS
|
|
|
+keypairs.
|
|
|
+
|
|
|
+When users create vote accounts, they must register their BLS public key by
|
|
|
+storing it in the newly created vote account. When they modify their vote
|
|
|
+authority, they must re-register the new corresponding BLS key.
|
|
|
+
|
|
|
+### Changes to vote program
|
|
|
+
|
|
|
+Whenever a new BLS public key is being updated in the vote account, we need
|
|
|
+to perform BLS verification on its validity, see "Security Considerations"
|
|
|
+for details. We plan to implement this by calling BLS library from the vote
|
|
|
+program, see "Alternatives Considered" for comparison with other solutions.
|
|
|
+
|
|
|
+Since BLS verification is expensive (around 1.15ms), each verification will cost
|
|
|
+34,500 CUs. Any Vote program instruction that performs a BLS verification will
|
|
|
+therefore add 34,500 CUs per verification on top of its baseline cost. As a result,
|
|
|
+Vote program instructions - which currently all cost 2,100 CUs - will have
|
|
|
+differentiated CU costs depending on whether they include BLS verification. The
|
|
|
+updated CU values are detailed in later sections.
|
|
|
+
|
|
|
+Note the 34,500 CUs for BLS verification will be consumed immediately before
|
|
|
+the verification is performed.
|
|
|
+
|
|
|
+Currently the vote program is allocated a budget of 3,000 CUs in the validator's
|
|
|
+builtin program cost modeling mechanism. Simple vote transactions (containing a
|
|
|
+`Vote` instruction) already bypass this mechanism, and other Vote program
|
|
|
+instructions that may use BLS verification are fairly infrequent. As a result,
|
|
|
+the Vote program will be removed from builtin program cost modeling.
|
|
|
+
|
|
|
+#### Disallow change of vote authority by old instructions
|
|
|
+
|
|
|
+After the feature gate associated with this SIMD is activated, the previous
|
|
|
+instructions will be disallowed to change vote authority after off-chain tools
|
|
|
+are upgraded, they will result in transaction errors. These include:
|
|
|
+
|
|
|
+- Authorize(Pubkey, VoteAuthorize): when VoteAuthorize is VoteAuthorize::Voter
|
|
|
+and the account has BLS public key it will fail
|
|
|
+
|
|
|
+- AuthorizeWithSeed(VoteAuthorizeWithSeedArgs): when authorization_type is
|
|
|
+VoteAuthorize::Voter and the account has BLS public key it will fail
|
|
|
+
|
|
|
+- AuthorizeChecked(VoteAuthorize): when VoteAuthorize is VoteAuthorize::Voter
|
|
|
+and the account has BLS public key it will fail
|
|
|
+
|
|
|
+- AuthorizeCheckedWithSeed(VoteAuthorizeCheckedWithSeedArgs): when
|
|
|
+authorization_type is VoteAuthorize::Voter and the account has BLS public key
|
|
|
+it will fail
|
|
|
+
|
|
|
+#### Proof of Possession calculation and verification
|
|
|
+
|
|
|
+While a standard Proof of Possession (PoP) is simply a signature over the
|
|
|
+public key itself (`σ=Signsk(pk)`), this can leave room for "binding theft"
|
|
|
+where a valid PoP is intercepted and registered to an attacker's vote account.
|
|
|
+To prevent this and cross-chain replay, the PoP must sign a domain-separated
|
|
|
+message binding the key to its specific context.
|
|
|
+
|
|
|
+The PoP calculation and verification must use the following message structure:
|
|
|
+
|
|
|
+```rust
|
|
|
+message=label ∣∣ chain_id ∣∣ authorized_voter_pubkey ∣∣ bls_pubkey_bytes
|
|
|
+```
|
|
|
+
|
|
|
+Where: (|| above is concatenation)
|
|
|
+
|
|
|
+- `label` is a constant string, we will make it "ALPENGLOW" here (all upper
|
|
|
+case).
|
|
|
+
|
|
|
+- `chain_id` is the genesis hash of the chain.
|
|
|
+
|
|
|
+- `authorized_voter_pubkey` is the authorized_voter Ed25519 public key.
|
|
|
+
|
|
|
+- `bls_pubkey_bytes` is the compressed new BLS public key (48 bytes).
|
|
|
+
|
|
|
+See "Security Considerations" for why the fields are needed.
|
|
|
+
|
|
|
+During PoP calculation, the CLI will generate the BLS keypair, then use the BLS
|
|
|
+private key to sign this message to generate the signature, compress it, and
|
|
|
+save it in `authorized_voter_bls_proof_of_possession`.
|
|
|
+
|
|
|
+During PoP verification, the validators will construct the same message, then
|
|
|
+check that the `authorized_voter_bls_proof_of_possession` is the correct
|
|
|
+signature.
|
|
|
+
|
|
|
+#### Add InitializeAccountV2
|
|
|
+
|
|
|
+```rust
|
|
|
+InitializeAccountV2(VoteInitV2),
|
|
|
+```
|
|
|
+
|
|
|
+```rust
|
|
|
+pub const BLS_PUBLIC_KEY_COMPRESSED_SIZE: usize = 48;
|
|
|
+pub const BLS_SIGNATURE_COMPRESSED_SIZE: usize = 96;
|
|
|
+
|
|
|
+pub struct VoteInitV2 {
|
|
|
+ pub node_pubkey: Pubkey,
|
|
|
+ pub authorized_voter: Pubkey,
|
|
|
+ pub authorized_voter_bls_pubkey: [u8; BLS_PUBLIC_KEY_COMPRESSED_SIZE],
|
|
|
+ pub authorized_voter_bls_proof_of_possession: [u8; BLS_SIGNATURE_COMPRESSED_SIZE],
|
|
|
+ pub authorized_withdrawer: Pubkey,
|
|
|
+ pub inflation_rewards_commission_bps: u16,
|
|
|
+ pub inflation_rewards_collector: Pubkey,
|
|
|
+ pub block_revenue_commission_bps: u16,
|
|
|
+ pub block_revenue_collector: Pubkey,
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+Upon receiving the transaction, the vote program will perform a BLS
|
|
|
+verification on submitted BLS public key and associated proof of possession.
|
|
|
+The transaction will fail if the verification failed. Otherwise the new vote
|
|
|
+account is created with given parameters.
|
|
|
+
|
|
|
+#### Add new variant of VoteAuthorize
|
|
|
+
|
|
|
+```rust
|
|
|
+pub struct VoterWithBLSArgs {
|
|
|
+ bls_pub_key: [u8; BLS_PUBLIC_KEY_COMPRESSED_SIZE],
|
|
|
+ bls_proof_of_possession: [u8; BLS_SIGNATURE_COMPRESSED_SIZE],
|
|
|
+}
|
|
|
+
|
|
|
+pub enum VoteAuthorize {
|
|
|
+ Voter,
|
|
|
+ Withdrawer,
|
|
|
+ VoterWithBLS(VoterWithBLSArgs),
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+Upon receiving the transaction, if the parameter is of the new variant, the
|
|
|
+vote program will perform a BLS verification on submitted BLS public key and
|
|
|
+associated proof of possession. The transaction will fail if the verification
|
|
|
+failed. Otherwise the vote authority change will be recorded in vote account.
|
|
|
+
|
|
|
+## Impact
|
|
|
+
|
|
|
+### Before feature gate in this SIMD is activated
|
|
|
+
|
|
|
+There is no change, users cannot update their BLS public key in vote account.
|
|
|
+
|
|
|
+### After the feature gate in this SIMD is activated but before Alpenglow launch
|
|
|
+
|
|
|
+Users can update their BLS public key in the vote account.
|
|
|
+
|
|
|
+### After Alpenglow launch
|
|
|
+
|
|
|
+Per SIMD 357, only vote accounts with updated BLS public key can participate
|
|
|
+in the voting process.
|
|
|
+
|
|
|
+When starting a validator, the operators are supposed to provide all ed25519
|
|
|
+keypairs like before. The BLS keypair will automatically be derived from the
|
|
|
+vote authority keypair (if that’s missing, then the identity keypair is used
|
|
|
+like now). The operations needed to switch the keypair and the operations
|
|
|
+needed to switch to a standby node are the same as today.
|
|
|
+
|
|
|
+## Security Considerations
|
|
|
+
|
|
|
+The safety of BLS votes in Alpenglow is still guarded by the ed25519 vote
|
|
|
+authority keypair, so users are supposed to safe guard it like before.
|
|
|
+
|
|
|
+We need to have the proof of possession in the instruction inputs so we can
|
|
|
+guard against BLS rogue-key attack. If anyone is allowed to randomly choose a
|
|
|
+public key, then an attacker can select a particular public key which interacts
|
|
|
+with other participants' keys so a forged aggregate signature verifies even
|
|
|
+though not all honest parties actually signed.
|
|
|
+
|
|
|
+We need to put `authorized_voter_pubkey` in Proof of Possession calculation
|
|
|
+because a replay attack exists:
|
|
|
+
|
|
|
+- User A wants to update vote authority, calculates PoP signature
|
|
|
+
|
|
|
+- The attacker sees this PoP signature in the transaction and sends in another
|
|
|
+transaction grabbing the BLS public key before user A
|
|
|
+
|
|
|
+- Now user A cannot use the BLS public key generated for his own vote account
|
|
|
+
|
|
|
+We also add a `label` so in the future we can update the version, and add a
|
|
|
+`chain_id` so attackers can't do cross-chain replay attack.
|
|
|
+
|
|
|
+## Alternatives Considered
|
|
|
+
|
|
|
+### Moving BLS verification to a syscall and/or a different program
|
|
|
+
|
|
|
+We can put BLS verification into a separate program or into a syscall, this is
|
|
|
+conceptually cleaner.
|
|
|
+
|
|
|
+We choose not to do this now because currently vote program needs to handle
|
|
|
+a lot of vote transactions so it's a native program. We may explore this
|
|
|
+option later if the vote program is migrated to an on-chain BPF program after
|
|
|
+Alpenglow launches.
|