-
Notifications
You must be signed in to change notification settings - Fork 253
SIMD-0387: BLS Pubkey Management in Vote Account. #387
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SIMD-0387: BLS Pubkey Management in Vote Account. #387
Conversation
wen-coding
commented
Oct 27, 2025
- Add BLS Pubkey Management in Vote Account for Alpenglow.
| 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). |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
| - 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) |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
| 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. |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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".
| - 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) |
There was a problem hiding this comment.
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.
| // 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), |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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!
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| 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. |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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:
- Generate a random BLS keypair and put that in vote account
- 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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
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?
| 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. |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
|
Thanks, @lidatong!
|
qkniep
left a comment
There was a problem hiding this 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 |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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:
- it's hard to perform cross account check in vote program transactions
- it should be cryptographically hard to generate the same private key as others
- 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.
Co-authored-by: Quentin Kniep <[email protected]>
Co-authored-by: Quentin Kniep <[email protected]>
|
Thanks, @bw-solana!
|
|
✅ All approvals received! @wen-coding, you can now merge this by commenting ✅ Status: Ready to merge |
/merge |
|
/merge |
|
✅ Merge successful! @wen-coding's PR has been merged. |