Skip to content
Merged
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
6f8f199
SIMD-387: BLS Pubkey Management in Vote Account.
wen-coding Oct 27, 2025
29a6d38
Add in missing sections.
wen-coding Oct 27, 2025
9c9ead5
Make linter happy.
wen-coding Oct 27, 2025
229b601
Explain alternatives.
wen-coding Oct 27, 2025
eed2c38
Mention BLS rogue-key attack in security considerations.
wen-coding Oct 28, 2025
e8e24d3
Reword the BLS rogue key attack a bit.
wen-coding Oct 28, 2025
39033d5
Proof of knowledge -> Proof of possession
wen-coding Oct 28, 2025
d0dde55
Address pr comments.
wen-coding Oct 28, 2025
5de2954
Specify that it's a compressed BLS pubkey.
wen-coding Oct 30, 2025
a8e44f9
Clarify the new vote program additions and add BLS syscall/program to…
wen-coding Oct 30, 2025
b71247b
Specifying the new variant will fail in all other instructions.
wen-coding Oct 30, 2025
3197a17
Make linter happy.
wen-coding Oct 30, 2025
629daad
Some small fixes.
wen-coding Nov 3, 2025
561edb2
Update enum new variant definition.
wen-coding Nov 4, 2025
34a576b
Address pr comments.
wen-coding Nov 5, 2025
109feee
Add proposal to remove vote program from using builtin CU limit.
wen-coding Nov 6, 2025
4129dd0
Update proposals/0387-bls-pubkey-management-in-vote-account.md
wen-coding Nov 18, 2025
2166bb6
Update proposals/0387-bls-pubkey-management-in-vote-account.md
wen-coding Nov 18, 2025
c6c617c
Update proposals/0387-bls-pubkey-management-in-vote-account.md
wen-coding Nov 18, 2025
d61ea12
Make linter happy.
wen-coding Nov 18, 2025
d6ffd1d
Shorten some paragraphs.
wen-coding Nov 18, 2025
fa25fbb
Address comments.
wen-coding Nov 18, 2025
6c46ae4
Small change.
wen-coding Nov 18, 2025
e7f6719
Address Sam's comments, fix typo and add PoP definition.
wen-coding Nov 19, 2025
89d114e
Fix typo again
wen-coding Nov 19, 2025
b5330ae
Make linter happy.
wen-coding Nov 19, 2025
aee4d34
Clarify proof of possession calculation.
wen-coding Nov 19, 2025
c423fa8
Add newlines between items.
wen-coding Nov 19, 2025
03cff65
Describe the replay attack in PoP generation.
wen-coding Nov 19, 2025
eb96fd6
Explain the other fields as well.
wen-coding Nov 19, 2025
8b00dae
Clarify the fields in security considerations.
wen-coding Nov 19, 2025
01e8865
Clarify label is upper case.
wen-coding Nov 19, 2025
a6a8ef0
Address pr comments.
wen-coding Nov 20, 2025
02cc97c
Make linter happy.
wen-coding Nov 20, 2025
c3813cb
Explain PoP calculation and verification.
wen-coding Nov 20, 2025
9382ffa
Clarify a bit.
wen-coding Nov 20, 2025
e81fa9e
Clarify more.
wen-coding Nov 20, 2025
5296d19
Address pr comments.
wen-coding Nov 20, 2025
cba1c98
Clarify the cli will do everything for the user.
wen-coding Nov 20, 2025
3ec7407
Fix english.
wen-coding Nov 20, 2025
b88c205
Clarify a bit.
wen-coding Nov 20, 2025
3a55e37
Address pr comments.
wen-coding Nov 20, 2025
20b5657
Update proposals/0387-bls-pubkey-management-in-vote-account.md
wen-coding Nov 21, 2025
e1f1a07
Update proposals/0387-bls-pubkey-management-in-vote-account.md
wen-coding Nov 21, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
251 changes: 251 additions & 0 deletions proposals/0387-bls-pubkey-management-in-vote-account.md
Original file line number Diff line number Diff line change
@@ -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.
Comment on lines +17 to +19
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should mention a critical piece of the proposal here, which is how the network verifies PoP

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Proof of Possession Calculation actually is the verification method as well, reworked that section.


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.
Comment thread
bw-solana marked this conversation as resolved.

## 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
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we say that we check whether the public key is already in use? I don't see it.

Copy link
Copy Markdown
Contributor Author

@wen-coding wen-coding Nov 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't enforce it anywhere, but we can emit a warning in CLI if the public key is already in use. The reasons being:

  1. it's hard to perform cross account check in vote program transactions
  2. it should be cryptographically hard to generate the same private key as others
  3. the PoP proof above guarantees you can't easily claim a BLS keypair you don't own by replay attack
    So without checking we should still be okay.


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.
Loading