Skip to main content
Technical proposal SIMD-0387 Review

BLS Pubkey management in vote account

  1. Idea
  2. Draft
  3. Review
  4. Accept
  5. Implement
  6. Active

Decision brief

Why this proposal matters

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.

Source-backed reading aid · source language: EN

Proposal at a glance

What changes

  • 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

Stakeholder map

Who is affected

Builders & client teams Medium impact

BLS keypairs can be generated or derived however users choose; the Vote program does not enforce any particular derivation scheme.

Action requirement unknown
Validators & operators Medium impact

There is no change, users cannot update their BLS public key in vote account.

Action requirement unknown
Users & stakers Medium impact

There is no change, users cannot update their BLS public key in vote account.

Action requirement unknown
Governance & ecosystem Medium impact

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.

Action requirement unknown

Exact source revision

Full proposal document

Source-language document. Technical identifiers and evidence remain unchanged. 0616093b2952

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

This proposal depends on the following previously accepted proposals:

  • SIMD-0185: Vote Account v4

    Adds the vote state v4 structure including the BLS public key field

  • SIMD-0326: Alpenglow

    Specifies the new consensus protocol that requires BLS signatures

  • SIMD-0357: Require BLS Public Key for Alpenglow

    Specifies that vote accounts must have a BLS public key to participate in voting

  • SIMD-0458: Stop Using Static SimpleVote Transaction Cost

    Removes statically defined compute unit costs for Simple Vote transactions

Detailed Design

BLS keypairs can be generated or derived however users choose; the Vote program does not enforce any particular derivation scheme.

Registering a BLS public key on a vote state v4 account is done via the VoteAuthorize instruction with the new VoterWithBLS variant, as described in the later section. A proof of possession that verifies ownership of the BLS keypair is required, as described in the later section.

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:

message=label ∣∣ vote_account_pubkey ∣∣ bls_pubkey_bytes

Where: (|| above is concatenation)

  • label is a constant string, we will make it "ALPENGLOW" here (all upper case).

  • vote_account_pubkey is the Ed25519 address of the vote account.

  • 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 new variant of VoteAuthorize

pub const BLS_PUBLIC_KEY_COMPRESSED_SIZE: usize = 48;
pub const BLS_SIGNATURE_COMPRESSED_SIZE: usize = 96;

pub struct VoterWithBLSArgs {
    bls_pubkey: [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.

Voters can set or update their BLS public key without changing their authorized voter by calling VoteAuthorize with VoterWithBLS and providing the current authorized voter.

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

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.

Evidence graph

Related proposals and rollout

One or more sources are unavailable.

Upstream review record

Upstream discussion & review

GitHub review is editorial context, not evidence of on-chain support, voting, or outcome.

PR #387 · merged SIMD-0387: BLS Pubkey Management in Vote Account. 90 comments and reviews · Jan 26, 2026
@qkniep

suggestion During PoP calculation, the CLI will generate the BLS keypair, then use the BLS

GitHub ↗
@qkniep

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

GitHub ↗
@wen-coding

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.

GitHub ↗
@simd-botbot

Thanks, @bw-solana! ⚠️ Status: Cannot merge yet - Missing approval from: Firedancer (@ptaffet-jump, @topointon-jump, @0x0ece, @lidatong, @ripatel-fd)

GitHub ↗
@simd-botbot

✅ All approvals received! @wen-coding, you can now merge this by commenting /merge. ✅ Status: Ready to merge

GitHub ↗
@wen-coding

✅ All approvals received! @wen-coding, you can now merge this by commenting /merge. ✅ Status: Ready to merge /merge

GitHub ↗
@simd-botbot

✅ Merge successful! @wen-coding's PR has been merged.

GitHub ↗

simd.watch community discussion · SIMD-0387

Powered by Giscus · Sign in with GitHub to comment

Community comments load when this section approaches the viewport.

Provenance

Evidence & technical details

Rollout or chain data, source revisions, freshness and integrity.
2

SIMD

Deployment Status

Document lifecycleReview
CategoryCore protocol
Devnetinactive
Testnetinactive
Mainnet-Betainactive
2uxQgtKa2ECHGs67Zdj7dgmzn2w9HiqhdcedwCWfYzzq

Exact source revision

Sources & integrity

  • Proposal document pinned_commit_blob
    0616093b2952ed6de52c4a27d66aadd11d48d4f9
  • simd-document document · stale · Sep 10, 2026
    0616093b2952ed6de52c4a27d66aadd11d48d4f9

One or more sources are unavailable.