hotshot_types/
signature_key.rs

1// Copyright (c) 2021-2024 Espresso Systems (espressosys.com)
2// This file is part of the HotShot repository.
3
4// You should have received a copy of the MIT License
5// along with the HotShot repository. If not, see <https://mit-license.org/>.
6
7//! Types and structs for the hotshot signature keys
8
9use alloy::primitives::U256;
10use ark_serialize::SerializationError;
11use bitvec::{slice::BitSlice, vec::BitVec};
12use digest::generic_array::GenericArray;
13use jf_signature::{
14    bls_over_bn254::{BLSOverBN254CurveSignatureScheme, KeyPair, SignKey, VerKey},
15    SignatureError, SignatureScheme,
16};
17use rand::SeedableRng;
18use rand_chacha::ChaCha20Rng;
19use tracing::instrument;
20
21use crate::{
22    light_client::{CircuitField, LightClientState, StakeTableState},
23    qc::{BitVectorQc, QcParams},
24    stake_table::StakeTableEntry,
25    traits::{
26        qc::QuorumCertificateScheme,
27        signature_key::{
28            BuilderSignatureKey, LCV1StateSignatureKey, LCV2StateSignatureKey,
29            LCV3StateSignatureKey, PrivateSignatureKey, SignatureKey, StateSignatureKey,
30        },
31    },
32};
33
34/// BLS private key used to sign a consensus message
35pub type BLSPrivKey = SignKey;
36/// BLS public key used to verify a consensus signature
37pub type BLSPubKey = VerKey;
38/// BLS key pair used to sign and verify a consensus message
39pub type BLSKeyPair = KeyPair;
40/// Public parameters for BLS signature scheme
41pub type BLSPublicParam = ();
42/// BLS signature type for consensus votes
43pub type BLSSignature = jf_signature::bls_over_bn254::Signature;
44
45impl PrivateSignatureKey for BLSPrivKey {
46    fn to_bytes(&self) -> Vec<u8> {
47        self.to_bytes()
48    }
49
50    fn from_bytes(bytes: &[u8]) -> anyhow::Result<Self> {
51        Ok(Self::from_bytes(bytes))
52    }
53
54    fn to_tagged_base64(&self) -> Result<tagged_base64::TaggedBase64, tagged_base64::Tb64Error> {
55        self.to_tagged_base64()
56    }
57}
58
59impl SignatureKey for BLSPubKey {
60    type PrivateKey = BLSPrivKey;
61    type StakeTableEntry = StakeTableEntry<VerKey>;
62    type QcParams<'a> = QcParams<
63        'a,
64        BLSPubKey,
65        <BLSOverBN254CurveSignatureScheme as SignatureScheme>::PublicParameter,
66    >;
67    type PureAssembledSignatureType =
68        <BLSOverBN254CurveSignatureScheme as SignatureScheme>::Signature;
69    type QcType = (Self::PureAssembledSignatureType, BitVec);
70    type SignError = SignatureError;
71
72    #[instrument(skip(self))]
73    fn validate(&self, signature: &Self::PureAssembledSignatureType, data: &[u8]) -> bool {
74        // This is the validation for QC partial signature before append().
75        BLSOverBN254CurveSignatureScheme::verify(&(), self, data, signature).is_ok()
76    }
77
78    fn sign(
79        sk: &Self::PrivateKey,
80        data: &[u8],
81    ) -> Result<Self::PureAssembledSignatureType, Self::SignError> {
82        BitVectorQc::<BLSOverBN254CurveSignatureScheme>::sign(
83            &(),
84            sk,
85            data,
86            &mut rand::thread_rng(),
87        )
88    }
89
90    fn from_private(private_key: &Self::PrivateKey) -> Self {
91        BLSPubKey::from(private_key)
92    }
93
94    fn to_bytes(&self) -> Vec<u8> {
95        let mut buf = vec![];
96        ark_serialize::CanonicalSerialize::serialize_compressed(self, &mut buf)
97            .expect("Serialization should not fail.");
98        buf
99    }
100
101    fn from_bytes(bytes: &[u8]) -> Result<Self, SerializationError> {
102        ark_serialize::CanonicalDeserialize::deserialize_compressed(bytes)
103    }
104
105    fn generated_from_seed_indexed(seed: [u8; 32], index: u64) -> (Self, Self::PrivateKey) {
106        let mut hasher = blake3::Hasher::new();
107        hasher.update(&seed);
108        hasher.update(&index.to_le_bytes());
109        let new_seed = *hasher.finalize().as_bytes();
110        let kp = KeyPair::generate(&mut ChaCha20Rng::from_seed(new_seed));
111        (kp.ver_key(), kp.sign_key_ref().clone())
112    }
113
114    fn stake_table_entry(&self, stake: U256) -> Self::StakeTableEntry {
115        StakeTableEntry {
116            stake_key: *self,
117            stake_amount: stake,
118        }
119    }
120
121    fn public_key(entry: &Self::StakeTableEntry) -> Self {
122        entry.stake_key
123    }
124
125    fn public_parameter(
126        stake_entries: &'_ [Self::StakeTableEntry],
127        threshold: U256,
128    ) -> Self::QcParams<'_> {
129        QcParams {
130            stake_entries,
131            threshold,
132            agg_sig_pp: (),
133        }
134    }
135
136    fn check(
137        real_qc_pp: &Self::QcParams<'_>,
138        data: &[u8],
139        qc: &Self::QcType,
140    ) -> Result<(), SignatureError> {
141        let msg = GenericArray::from_slice(data);
142        BitVectorQc::<BLSOverBN254CurveSignatureScheme>::check(real_qc_pp, msg, qc).map(|_| ())
143    }
144
145    fn sig_proof(signature: &Self::QcType) -> (Self::PureAssembledSignatureType, BitVec) {
146        signature.clone()
147    }
148
149    fn assemble(
150        real_qc_pp: &Self::QcParams<'_>,
151        signers: &BitSlice,
152        sigs: &[Self::PureAssembledSignatureType],
153    ) -> Self::QcType {
154        BitVectorQc::<BLSOverBN254CurveSignatureScheme>::assemble(real_qc_pp, signers, sigs)
155            .expect("this assembling shouldn't fail")
156    }
157
158    fn genesis_proposer_pk() -> Self {
159        let kp = KeyPair::generate(&mut ChaCha20Rng::from_seed([0u8; 32]));
160        kp.ver_key()
161    }
162}
163
164// Currently implement builder signature key for BLS
165// So copy pasta here, but actually Sequencer will implement the same trait for ethereum types
166/// Builder signature key
167pub type BuilderKey = BLSPubKey;
168
169impl BuilderSignatureKey for BuilderKey {
170    type BuilderPrivateKey = BLSPrivKey;
171    type BuilderSignature = <BLSOverBN254CurveSignatureScheme as SignatureScheme>::Signature;
172    type SignError = SignatureError;
173
174    fn sign_builder_message(
175        private_key: &Self::BuilderPrivateKey,
176        data: &[u8],
177    ) -> Result<Self::BuilderSignature, Self::SignError> {
178        BitVectorQc::<BLSOverBN254CurveSignatureScheme>::sign(
179            &(),
180            private_key,
181            data,
182            &mut rand::thread_rng(),
183        )
184    }
185
186    fn validate_builder_signature(&self, signature: &Self::BuilderSignature, data: &[u8]) -> bool {
187        BLSOverBN254CurveSignatureScheme::verify(&(), self, data, signature).is_ok()
188    }
189
190    fn generated_from_seed_indexed(seed: [u8; 32], index: u64) -> (Self, Self::BuilderPrivateKey) {
191        let mut hasher = blake3::Hasher::new();
192        hasher.update(&seed);
193        hasher.update(&index.to_le_bytes());
194        let new_seed = *hasher.finalize().as_bytes();
195        let kp = KeyPair::generate(&mut ChaCha20Rng::from_seed(new_seed));
196        (kp.ver_key(), kp.sign_key_ref().clone())
197    }
198}
199
200pub type SchnorrPubKey = jf_signature::schnorr::VerKey<ark_ed_on_bn254::EdwardsConfig>;
201pub type SchnorrPrivKey = jf_signature::schnorr::SignKey<ark_ed_on_bn254::Fr>;
202pub type SchnorrSignatureScheme =
203    jf_signature::schnorr::SchnorrSignatureScheme<ark_ed_on_bn254::EdwardsConfig>;
204
205impl PrivateSignatureKey for SchnorrPrivKey {
206    fn to_bytes(&self) -> Vec<u8> {
207        self.to_bytes()
208    }
209
210    fn from_bytes(bytes: &[u8]) -> anyhow::Result<Self> {
211        Ok(Self::from_bytes(bytes))
212    }
213
214    fn to_tagged_base64(&self) -> Result<tagged_base64::TaggedBase64, tagged_base64::Tb64Error> {
215        self.to_tagged_base64()
216    }
217}
218
219impl StateSignatureKey for SchnorrPubKey {
220    type StatePrivateKey = SchnorrPrivKey;
221
222    type StateSignature = jf_signature::schnorr::Signature<ark_ed_on_bn254::EdwardsConfig>;
223
224    type SignError = SignatureError;
225
226    fn generated_from_seed_indexed(seed: [u8; 32], index: u64) -> (Self, Self::StatePrivateKey) {
227        let mut hasher = blake3::Hasher::new();
228        hasher.update(&seed);
229        hasher.update(&index.to_le_bytes());
230        let new_seed = *hasher.finalize().as_bytes();
231        let kp = jf_signature::schnorr::KeyPair::generate(&mut ChaCha20Rng::from_seed(new_seed));
232        (kp.ver_key(), kp.sign_key())
233    }
234}
235
236impl LCV1StateSignatureKey for SchnorrPubKey {
237    fn sign_state(
238        sk: &Self::StatePrivateKey,
239        light_client_state: &LightClientState,
240    ) -> Result<Self::StateSignature, Self::SignError> {
241        let state_msg: [_; 3] = light_client_state.into();
242        SchnorrSignatureScheme::sign(&(), sk, state_msg, &mut rand::thread_rng())
243    }
244
245    fn verify_state_sig(
246        &self,
247        signature: &Self::StateSignature,
248        light_client_state: &LightClientState,
249    ) -> bool {
250        let state_msg: [_; 3] = light_client_state.into();
251        SchnorrSignatureScheme::verify(&(), self, state_msg, signature).is_ok()
252    }
253}
254
255impl LCV2StateSignatureKey for SchnorrPubKey {
256    fn sign_state(
257        sk: &Self::StatePrivateKey,
258        light_client_state: &LightClientState,
259        next_stake_table_state: &StakeTableState,
260    ) -> Result<Self::StateSignature, Self::SignError> {
261        let mut msg = Vec::with_capacity(7);
262        let state_msg: [_; 3] = light_client_state.into();
263        msg.extend_from_slice(&state_msg);
264        let adv_st_state_msg: [_; 4] = (*next_stake_table_state).into();
265        msg.extend_from_slice(&adv_st_state_msg);
266        SchnorrSignatureScheme::sign(&(), sk, msg, &mut rand::thread_rng())
267    }
268
269    fn verify_state_sig(
270        &self,
271        signature: &Self::StateSignature,
272        light_client_state: &LightClientState,
273        next_stake_table_state: &StakeTableState,
274    ) -> bool {
275        let mut msg = Vec::with_capacity(7);
276        let state_msg: [_; 3] = light_client_state.into();
277        msg.extend_from_slice(&state_msg);
278        let adv_st_state_msg: [_; 4] = (*next_stake_table_state).into();
279        msg.extend_from_slice(&adv_st_state_msg);
280        SchnorrSignatureScheme::verify(&(), self, msg, signature).is_ok()
281    }
282}
283
284impl LCV3StateSignatureKey for SchnorrPubKey {
285    /// Sign the light client state
286    /// The input `msg` should be the keccak256 hash of ABI encodings of the light client state,
287    /// next stake table state, and the auth root.
288    fn sign_state(
289        private_key: &Self::StatePrivateKey,
290        msg: CircuitField,
291    ) -> Result<Self::StateSignature, Self::SignError> {
292        SchnorrSignatureScheme::sign(&(), private_key, [msg], &mut rand::thread_rng())
293    }
294
295    /// Verify the light client state signature
296    /// The input `msg` should be the keccak256 hash of ABI encodings of the light client state,
297    /// next stake table state, and the auth root.
298    fn verify_state_sig(&self, signature: &Self::StateSignature, msg: CircuitField) -> bool {
299        SchnorrSignatureScheme::verify(&(), self, [msg], signature).is_ok()
300    }
301}