use solana_bls_signatures::{
keypair::Keypair as BlsKeypair, PubkeyCompressed, BLS_PROOF_OF_POSSESSION_COMPRESSED_SIZE,
BLS_PUBLIC_KEY_COMPRESSED_SIZE,
};
use solana_sdk::{pubkey::Pubkey, signature::Signer};
const BLS_KEYPAIR_DERIVE_SEED: &[u8] = b"alpenglow";
const POP_LABEL: &[u8; 9] = b"ALPENGLOW";
const POP_MESSAGE_SIZE: usize =
POP_LABEL.len() + std::mem::size_of::<Pubkey>() + BLS_PUBLIC_KEY_COMPRESSED_SIZE;
pub struct DerivedBls {
pub pubkey: [u8; BLS_PUBLIC_KEY_COMPRESSED_SIZE],
pub proof_of_possession: [u8; BLS_PROOF_OF_POSSESSION_COMPRESSED_SIZE],
pub display: String,
}
pub fn derive_pubkey_and_pop(
identity: &dyn Signer,
vote_account: &Pubkey,
) -> eyre::Result<DerivedBls> {
let bls_keypair = BlsKeypair::derive_from_signer(identity, BLS_KEYPAIR_DERIVE_SEED)
.map_err(|e| eyre::eyre!("Failed to derive BLS keypair from identity: {e}"))?;
let pubkey = bls_keypair.public.to_bytes_compressed();
let message = generate_pop_message(vote_account, &pubkey);
let proof_of_possession = bls_keypair
.proof_of_possession(Some(&message))
.to_bytes_compressed();
let display = PubkeyCompressed(pubkey).to_string();
Ok(DerivedBls {
pubkey,
proof_of_possession,
display,
})
}
fn generate_pop_message(
vote_account: &Pubkey,
bls_pubkey: &[u8; BLS_PUBLIC_KEY_COMPRESSED_SIZE],
) -> [u8; POP_MESSAGE_SIZE] {
let mut message = [0u8; POP_MESSAGE_SIZE];
let (label, rest) = message.split_at_mut(POP_LABEL.len());
let (pubkey, bls) = rest.split_at_mut(std::mem::size_of::<Pubkey>());
label.copy_from_slice(POP_LABEL);
pubkey.copy_from_slice(vote_account.as_ref());
bls.copy_from_slice(bls_pubkey);
message
}