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.
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.
Added. I don't think we have the actual numbers now, need to test that.
There was a problem hiding this comment.
@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.
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.
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.
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.
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.
Sounds good, do I need to write that into this SIMD?
There was a problem hiding this comment.
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.
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.
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.
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.
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.
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.
I'm totally fine with that. @jstarry what do you think?
There was a problem hiding this comment.
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.
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.
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.
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.
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.
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.
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.
Changed, how does this look?
There was a problem hiding this comment.
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.
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.
VoteInstruction::Authorize and AuthorizeWithSeed also exist. We need to address changes for those instructions as well
| 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.
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.
Yup, already asked Tao and he estimate 1.15ms running time translates to 34,500 CU. Updated that in the PR.
|
Thanks, @lidatong!
|
qkniep
left a comment
There was a problem hiding this comment.
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.
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.
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 <hello@quentinkniep.com>
Co-authored-by: Quentin Kniep <hello@quentinkniep.com>
|
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. |