Skip to content

Conversation

@wen-coding
Copy link
Contributor

  • Add BLS Pubkey Management in Vote Account for Alpenglow.

@wen-coding wen-coding changed the title SIMD-387: BLS Pubkey Management in Vote Account. SIMD-0387: BLS Pubkey Management in Vote Account. Oct 28, 2025
Comment on lines 91 to 93
Since BLS verification is expensive (in the order of ~1 millisecond), these
operations changing BLS public key will need to have correct CU specified to
succeed (actual numbers to be measured and published later).
Copy link
Contributor

Choose a reason for hiding this comment

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

Are you saying we should change the Vote program to use different CU consumption amounts per-instruction? That should be specified in here, and we should probably include the new values themselves.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added. I don't think we have the actual numbers now, need to test that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@samkim-crypto confirmed it's about 801us to 1.15ms in benchmark. I'll check with @tao-stones the actual CU numbers we would need.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes it is 801us on my local machine and 1.15ms on my remote dev machine. My remote dev machine matches the ed25519 sigverify cost pretty closely, so 1.15 is probably a more correct number.

But the precise CU would depend on how/where we execute the verification: one syscall, multiple syscalls inside the vote program or CPI into a BLS program.

Copy link
Contributor

Choose a reason for hiding this comment

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

To be consistent, using current conversion rate of 30cu per 1 micro-sec, 1.15ms converts to 34,500 CU. It exceeds 3,000 MAX builtin allocation CUs. (As a reference, currently all vote instructions have 2,100 CUs). So the v2 vote needs to be excluded from "builtin " list. Also, to echo @buffalojoec 's point, are all instructions do same BLS verifications therefore cost same CUs, or they can be different?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks! The new instructions/new variants all do the same BLS verification and they should cost the same amount of CUs.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah we should exclude these from the builtin list.. We could exclude the vote program completely since AFAIK simple vote transactions don't go through that code path and other vote related transactions are relatively rare and then 3k -> 200k default cost per vote ix is not very impactful.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sounds good, do I need to write that into this SIMD?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, I think so — excluding the Vote program from the built-in list would affect consensus. It’d be great if you could include what @jstarry mentioned in the section where the Vote program is defined.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added, see if what I added make sense?

Comment on lines 129 to 133
- AuthorizeCheckedWithBLS(VoteAuthorizeWithBLS)

Changing the vote authority public key and BLS public key for existing vote
account without using seed: (we can also use it to add BLS public key to
existing vote account, just check vote authority public key didn’t change)
Copy link
Contributor

Choose a reason for hiding this comment

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

If the BLS key is set, I can't use the old instruction to change my vote authority, right? Otherwise, the BLS key would be out-of-step. So, we need to deprecate and fully disable that instruction in order to add this one.

You could alternatively just add a new variant for the instruction input. Then you can use the existing instruction, and the SIMD can specify Vote program behavior that rejects updates to voter address without corresponding BLS proof of possession, if BLS key is set.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think the alternative above would also allow AuthorizeCheckedWithSeed to just have a behavioral change and also capture the new variant in authorization_type.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I actually only care about touching vote authority pubkey, for other changes I'm fine to have old instructions go through, but it's going to be confusing to user, so maybe better to move everything to new instructions.

If capturing the new variant in authorization_type does the work, then I'm fine with it. All I care is:

  • Must specify BLS pubkey when creating new account
  • Whenever vote authority pubkey changes, BLS pubkey must change with it

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't see why we couldn't do a new variant in VoteAuthorize. I think the program would just have to have a feature gate that changes its behavior once the new variant is activated. It should disallow changes to the Voter variant if a BLS pubkey is set.

We would need this behavior with the existing instruction anyway, so IMO it's cleaner to just add a variant to the input rather than a new instruction.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm totally fine with that. @jstarry what do you think?

Copy link
Contributor

Choose a reason for hiding this comment

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

Chatted a bit with @buffalojoec about this. I don't mind either approach (new variant in VoteAuthorize or new instruction). But I think that if we go with a new instruction it would be pretty nice because we could remove the clock sysvar account input and make it specific to the vote authority and not need to worry about supporting "WithSeed" because that's really only useful for the withdraw authority anyways.

In either case, @buffalojoec is right that we can't allow voters to use the old instruction (or variant) to change the vote authority if a BLS key is already set. This behavior needs to be detailed in this SIMD.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed.

Copy link
Contributor

Choose a reason for hiding this comment

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

While I can appreciate the ability to remove the sysvar accounts, my opinion is that it feels a bit like scope creep and I think the new VoteAuthorize variant is a cleaner solution right now. Vote and VoteSwitch will still need Clock anyway, and we can always just remove the need for such accounts, in a completely backwards-compatible way, either separate from this SIMD or whenever the program is migrated on-chain post-Alpenglow.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Does the current change look correct then?

@wen-coding wen-coding requested a review from apfitzge October 28, 2025 17:29
Comment on lines 96 to 98
corresponding BLS keypair. Then the vote program can do a syscall to actually
verify the validity of BLS public key. If the verification fails, the
transaction will fail.
Copy link
Contributor

Choose a reason for hiding this comment

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

There's no precedent for native programs making syscalls that I know of. We should probably add a BLS program which can verify the BLS key proof of possession. Then, the vote program can invoke the BLS program to verify the proof.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added that to "Alternatives Considered".

Comment on lines 129 to 133
- AuthorizeCheckedWithBLS(VoteAuthorizeWithBLS)

Changing the vote authority public key and BLS public key for existing vote
account without using seed: (we can also use it to add BLS public key to
existing vote account, just check vote authority public key didn’t change)
Copy link
Contributor

Choose a reason for hiding this comment

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

Chatted a bit with @buffalojoec about this. I don't mind either approach (new variant in VoteAuthorize or new instruction). But I think that if we go with a new instruction it would be pretty nice because we could remove the clock sysvar account input and make it specific to the vote authority and not need to worry about supporting "WithSeed" because that's really only useful for the withdraw authority anyways.

In either case, @buffalojoec is right that we can't allow voters to use the old instruction (or variant) to change the vote authority if a BLS key is already set. This behavior needs to be detailed in this SIMD.

Comment on lines 107 to 112
// Will be totally forbidden, use InitializeAccountV2
InitializeAccount(VoteInit),
// Forbidden when VoteAuthorize is VoteAuthorize::Voter
AuthorizeChecked(VoteAuthorize),
// Forbidden when authorization_type is VoteAuthorize::Voter
AuthorizeCheckedWithSeed(VoteAuthorizeWithSeedArgs),
Copy link
Contributor

Choose a reason for hiding this comment

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

We should have a period of time where both legacy and alpenglow instructions are active to give us time to migrate offchain tooling like the CLI commands for creating vote accounts. But as discussed, we should not allow using the VoteAuthorize::Voter variant if the BLS pubkey is already configured for a vote account.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed, how does this look?

Copy link
Contributor

Choose a reason for hiding this comment

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

Is this comment still relevant if we don't do new instructions and instead do the new VoteAuthorize variant? I think no - since it appears outdated - but wanted to double-check as I review!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think forbid VoteAuthorize::Voter when the BLS pubkey is already configured is probably enough, this guarantees once you have a BLS pubkey it is always valid. For those people rejecting to write BLS pubkey to their vote account, allowing them to do VoteAuthorize::Voter is not end of the world, we will kick them out eventually per SIMD 357.

operations changing BLS public key will need to have correct CU specified to
succeed (actual numbers to be measured and added to this PR).

#### Disallow change of vote authority by old instructions
Copy link
Contributor

Choose a reason for hiding this comment

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

VoteInstruction::Authorize and AuthorizeWithSeed also exist. We need to address changes for those instructions as well

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added.

program, see "Alternatives Considered" for comparison with other solutions.

Since BLS verification is expensive (in the order of ~1 millisecond), these
operations changing BLS public key will need to have correct CU specified to
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you clarify that CU's must be consumed right before doing BLS signature verification? And cc @tao-stones for discussing the CU number given time for BLS verification.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yup, already asked Tao and he estimate 1.15ms running time translates to 34,500 CU. Updated that in the PR.

Copy link
Contributor

Choose a reason for hiding this comment

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

34,500 CU for BLS verification is based on current 30cu per 1us - questioned here if vote program be excluded from "builtin". @jstarry if this is the case?

@wen-coding wen-coding requested a review from jstarry November 5, 2025 05:10
Comment on lines 55 to 59
BLS keypairs can be generated randomly like ed25519 keypairs. But to save the
users some trouble on keypair management, we chose to derive their BLS keypair
used in Alpenglow votes based on their ed25519 vote keypair. In other words,
with an existing ed25519 vote keypair, the users can safely regenerate the
associated BLS keypair on demand.
Copy link
Contributor

Choose a reason for hiding this comment

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

we should be clear as to whether it MUST be this way or not. This reads as if it's just 1 (perceived easier) option. Is it okay if I generate a BLS pubkey that is completely unrelated to my ed25519 key, stick that in my vote account and use it to sign?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's actually possible, and we have no way to verify the two are related. So users can do:

  1. Generate a random BLS keypair and put that in vote account
  2. Change code to use the given BLS keypair instead of using the vote authority keypair

The protocol works as long as the users use the same BLS keypair in step 1 and 2.

The long term plan after Alpenglow migration is that we should get rid of vote authority keypair and have BLS keypair only, then users supply BLS keypair to validator execution.

Clarified it a bit.

Copy link
Contributor

Choose a reason for hiding this comment

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

might be nice to specify what the "we chose to derive" pertains to. I believe what it means is that we (Azna) chose to make the Agave client default implementation infer the BLS keypair from the ed25519 keypair and use this for signing votes.

I have mixed thoughts as to whether this client implementation detail belongs in a SIMD.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, I originally didn't want to put it in the SIMD, but then the users may have the question: "Do I need to generate a BLS keypair and put it in my wallet?" So this is user visible.

We mainly chose current route so during the migration epoch, we don't need to tell users: "Please explicitly load both keypairs in your wallet, you will need the BLS keypair suddenly in the middle".

After Alpenglow launches it matters less, we can relax this association and remove vote authority ed25519 keypair completely.

Changed.

Copy link
Contributor

Choose a reason for hiding this comment

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

yeah, makes sense. I'm assuming FD will do this the same way. Might be good to spell out this is the default client behavior (as opposed to something in protocol)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure, changed it to be:

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.

How does this look?

Comment on lines +17 to +19
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.
Copy link
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
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.

lidatong
lidatong previously approved these changes Nov 20, 2025
@simd-bot
Copy link

simd-bot bot commented Nov 20, 2025

Thanks, @lidatong!

⚠️ Status: Cannot merge yet

Copy link
Contributor

@qkniep qkniep left a comment

Choose a reason for hiding this comment

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

Looks good to me, just some last nits. Thanks for adding the PoP specification.

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

@simd-bot
Copy link

simd-bot bot commented Nov 21, 2025

Thanks, @bw-solana!

⚠️ Status: Cannot merge yet

@simd-bot
Copy link

simd-bot bot commented Nov 21, 2025

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

Status: Ready to merge

@wen-coding
Copy link
Contributor Author

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

Status: Ready to merge

/merge

@wen-coding
Copy link
Contributor Author

/merge

@simd-bot simd-bot bot merged commit a47c8f1 into solana-foundation:main Nov 21, 2025
2 checks passed
@simd-bot
Copy link

simd-bot bot commented Nov 21, 2025

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants