hotshot_types/traits/
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//! Minimal compatibility over public key signatures
8
9// data is serialized as big-endian for signing purposes
10#![forbid(clippy::little_endian_bytes)]
11
12use std::{
13    fmt::{Debug, Display},
14    hash::Hash,
15};
16
17use alloy::primitives::U256;
18use ark_serialize::SerializationError;
19use bitvec::prelude::*;
20use committable::Committable;
21use jf_signature::SignatureError;
22use serde::{de::DeserializeOwned, Deserialize, Serialize};
23use tagged_base64::{TaggedBase64, Tb64Error};
24
25use super::EncodeBytes;
26use crate::{
27    bundle::Bundle,
28    data::VidCommitment,
29    light_client::{LightClientState, StakeTableState, ToFieldsLightClientCompat},
30    traits::node_implementation::NodeType,
31    utils::BuilderCommitment,
32};
33
34/// Type representing stake table entries in a `StakeTable`
35pub trait StakeTableEntryType<K> {
36    /// Get the stake value
37    fn stake(&self) -> U256;
38    /// Get the public key
39    fn public_key(&self) -> K;
40}
41
42/// Trait for abstracting private signature key
43pub trait PrivateSignatureKey:
44    Send + Sync + Sized + Clone + Debug + Eq + Hash + for<'a> TryFrom<&'a TaggedBase64>
45{
46    /// Serialize the private key into bytes
47    fn to_bytes(&self) -> Vec<u8>;
48
49    /// Deserialize the private key from bytes
50    /// # Errors
51    /// If deserialization fails.
52    fn from_bytes(bytes: &[u8]) -> anyhow::Result<Self>;
53
54    /// Serialize the private key into TaggedBase64 blob.
55    /// # Errors
56    /// If serialization fails.
57    fn to_tagged_base64(&self) -> Result<TaggedBase64, Tb64Error>;
58}
59
60/// Trait for abstracting public key signatures
61/// Self is the public key type
62pub trait SignatureKey:
63    Send
64    + Sync
65    + Clone
66    + Sized
67    + Debug
68    + Hash
69    + Serialize
70    + for<'a> Deserialize<'a>
71    + PartialEq
72    + Eq
73    + PartialOrd
74    + Ord
75    + Display
76    + ToFieldsLightClientCompat
77    + for<'a> TryFrom<&'a TaggedBase64>
78    + Into<TaggedBase64>
79{
80    /// The private key type for this signature algorithm
81    type PrivateKey: PrivateSignatureKey;
82    /// The type of the entry that contain both public key and stake value
83    type StakeTableEntry: StakeTableEntryType<Self>
84        + Send
85        + Sync
86        + Sized
87        + Clone
88        + Debug
89        + Hash
90        + Eq
91        + Serialize
92        + for<'a> Deserialize<'a>;
93    /// The type of the quorum certificate parameters used for assembled signature
94    type QcParams<'a>: Send + Sync + Sized + Clone + Debug + Hash;
95    /// The type of the assembled signature, without `BitVec`
96    type PureAssembledSignatureType: Send
97        + Sync
98        + Sized
99        + Clone
100        + Debug
101        + Hash
102        + PartialEq
103        + Eq
104        + Serialize
105        + for<'a> Deserialize<'a>
106        + Into<TaggedBase64>
107        + for<'a> TryFrom<&'a TaggedBase64>;
108    /// The type of the assembled qc: assembled signature + `BitVec`
109    type QcType: Send
110        + Sync
111        + Sized
112        + Clone
113        + Debug
114        + Hash
115        + PartialEq
116        + Eq
117        + Serialize
118        + for<'a> Deserialize<'a>;
119
120    /// Type of error that can occur when signing data
121    type SignError: std::error::Error + Send + Sync;
122
123    // Signature type represented as a vec/slice of bytes to let the implementer handle the nuances
124    // of serialization, to avoid Cryptographic pitfalls
125    /// Validate a signature
126    fn validate(&self, signature: &Self::PureAssembledSignatureType, data: &[u8]) -> bool;
127
128    /// Produce a signature
129    /// # Errors
130    /// If unable to sign the data with the key
131    fn sign(
132        private_key: &Self::PrivateKey,
133        data: &[u8],
134    ) -> Result<Self::PureAssembledSignatureType, Self::SignError>;
135
136    /// Produce a public key from a private key
137    fn from_private(private_key: &Self::PrivateKey) -> Self;
138    /// Serialize a public key to bytes
139    fn to_bytes(&self) -> Vec<u8>;
140    /// Deserialize a public key from bytes
141    /// # Errors
142    ///
143    /// Will return `Err` if deserialization fails
144    fn from_bytes(bytes: &[u8]) -> Result<Self, SerializationError>;
145
146    /// Generate a new key pair
147    fn generated_from_seed_indexed(seed: [u8; 32], index: u64) -> (Self, Self::PrivateKey);
148
149    /// get the stake table entry from the public key and stake value
150    fn stake_table_entry(&self, stake: U256) -> Self::StakeTableEntry;
151
152    /// only get the public key from the stake table entry
153    fn public_key(entry: &Self::StakeTableEntry) -> Self;
154
155    /// get the public parameter for the assembled signature checking
156    fn public_parameter(
157        stake_entries: &[Self::StakeTableEntry],
158        threshold: U256,
159    ) -> Self::QcParams<'_>;
160
161    /// check the quorum certificate for the assembled signature, returning `Ok(())` if it is valid.
162    ///
163    /// # Errors
164    /// Returns an error if the signature key fails to validate
165    fn check(
166        real_qc_pp: &Self::QcParams<'_>,
167        data: &[u8],
168        qc: &Self::QcType,
169    ) -> Result<(), SignatureError>;
170
171    /// get the assembled signature and the `BitVec` separately from the assembled signature
172    fn sig_proof(signature: &Self::QcType) -> (Self::PureAssembledSignatureType, BitVec);
173
174    /// assemble the signature from the partial signature and the indication of signers in `BitVec`
175    fn assemble(
176        real_qc_pp: &Self::QcParams<'_>,
177        signers: &BitSlice,
178        sigs: &[Self::PureAssembledSignatureType],
179    ) -> Self::QcType;
180
181    /// generates the genesis public key. Meant to be dummy/filler
182    #[must_use]
183    fn genesis_proposer_pk() -> Self;
184}
185
186/// Builder Signature Key trait with minimal requirements
187pub trait BuilderSignatureKey:
188    Send
189    + Sync
190    + Clone
191    + Sized
192    + Debug
193    + Hash
194    + Serialize
195    + DeserializeOwned
196    + PartialEq
197    + Eq
198    + PartialOrd
199    + Ord
200    + Display
201{
202    /// The type of the keys builder would use to sign its messages
203    type BuilderPrivateKey: PrivateSignatureKey;
204
205    /// The type of the signature builder would use to sign its messages
206    type BuilderSignature: Send
207        + Sync
208        + Sized
209        + Clone
210        + Debug
211        + Eq
212        + Serialize
213        + for<'a> Deserialize<'a>
214        + Hash;
215
216    /// Type of error that can occur when signing data
217    type SignError: std::error::Error + Send + Sync;
218
219    /// validate the message with the builder's public key
220    fn validate_builder_signature(&self, signature: &Self::BuilderSignature, data: &[u8]) -> bool;
221
222    /// validate signature over sequencing fee information
223    /// with the builder's public key
224    fn validate_fee_signature<Metadata: EncodeBytes>(
225        &self,
226        signature: &Self::BuilderSignature,
227        fee_amount: u64,
228        metadata: &Metadata,
229    ) -> bool {
230        self.validate_builder_signature(signature, &aggregate_fee_data(fee_amount, metadata))
231    }
232
233    /// validate signature over sequencing fee information
234    /// with the builder's public key, including vid commitment
235    fn validate_fee_signature_with_vid_commitment<Metadata: EncodeBytes>(
236        &self,
237        signature: &Self::BuilderSignature,
238        fee_amount: u64,
239        metadata: &Metadata,
240        vid_commitment: &VidCommitment,
241    ) -> bool {
242        self.validate_builder_signature(
243            signature,
244            &aggregate_fee_data_with_vid_commitment(fee_amount, metadata, vid_commitment),
245        )
246    }
247
248    /// validate signature over sequencing fee information
249    /// with the builder's public key (marketplace version)
250    fn validate_sequencing_fee_signature_marketplace(
251        &self,
252        signature: &Self::BuilderSignature,
253        fee_amount: u64,
254        view_number: u64,
255    ) -> bool {
256        self.validate_builder_signature(
257            signature,
258            &aggregate_fee_data_marketplace(fee_amount, view_number),
259        )
260    }
261
262    /// validate the bundle's signature using the builder's public key
263    fn validate_bundle_signature<TYPES: NodeType<BuilderSignatureKey = Self>>(
264        &self,
265        bundle: Bundle<TYPES>,
266    ) -> bool where {
267        let commitments = bundle
268            .transactions
269            .iter()
270            .flat_map(|txn| <[u8; 32]>::from(txn.commit()))
271            .collect::<Vec<u8>>();
272
273        self.validate_builder_signature(&bundle.signature, &commitments)
274    }
275
276    /// validate signature over block information with the builder's public key
277    fn validate_block_info_signature(
278        &self,
279        signature: &Self::BuilderSignature,
280        block_size: u64,
281        fee_amount: u64,
282        payload_commitment: &BuilderCommitment,
283    ) -> bool {
284        self.validate_builder_signature(
285            signature,
286            &aggregate_block_info_data(block_size, fee_amount, payload_commitment),
287        )
288    }
289
290    /// sign the message with the builder's private key
291    /// # Errors
292    /// If unable to sign the data with the key
293    fn sign_builder_message(
294        private_key: &Self::BuilderPrivateKey,
295        data: &[u8],
296    ) -> Result<Self::BuilderSignature, Self::SignError>;
297
298    /// sign sequencing fee offer
299    /// # Errors
300    /// If unable to sign the data with the key
301    fn sign_fee<Metadata: EncodeBytes>(
302        private_key: &Self::BuilderPrivateKey,
303        fee_amount: u64,
304        metadata: &Metadata,
305    ) -> Result<Self::BuilderSignature, Self::SignError> {
306        Self::sign_builder_message(private_key, &aggregate_fee_data(fee_amount, metadata))
307    }
308
309    /// sign sequencing fee offer, with the payload commitment included
310    /// # Errors
311    /// If unable to sign the data with the key
312    fn sign_fee_with_vid_commitment<Metadata: EncodeBytes>(
313        private_key: &Self::BuilderPrivateKey,
314        fee_amount: u64,
315        metadata: &Metadata,
316        vid_commitment: &VidCommitment,
317    ) -> Result<Self::BuilderSignature, Self::SignError> {
318        Self::sign_builder_message(
319            private_key,
320            &aggregate_fee_data_with_vid_commitment(fee_amount, metadata, vid_commitment),
321        )
322    }
323
324    /// sign fee offer (marketplace version)
325    /// # Errors
326    /// If unable to sign the data with the key
327    fn sign_sequencing_fee_marketplace(
328        private_key: &Self::BuilderPrivateKey,
329        fee_amount: u64,
330        view_number: u64,
331    ) -> Result<Self::BuilderSignature, Self::SignError> {
332        Self::sign_builder_message(
333            private_key,
334            &aggregate_fee_data_marketplace(fee_amount, view_number),
335        )
336    }
337
338    /// sign transactions (marketplace version)
339    /// # Errors
340    /// If unable to sign the data with the key
341    fn sign_bundle<TYPES: NodeType>(
342        private_key: &Self::BuilderPrivateKey,
343        transactions: &[TYPES::Transaction],
344    ) -> Result<Self::BuilderSignature, Self::SignError> {
345        let commitments = transactions
346            .iter()
347            .flat_map(|txn| <[u8; 32]>::from(txn.commit()))
348            .collect::<Vec<u8>>();
349
350        Self::sign_builder_message(private_key, &commitments)
351    }
352
353    /// sign information about offered block
354    /// # Errors
355    /// If unable to sign the data with the key
356    fn sign_block_info(
357        private_key: &Self::BuilderPrivateKey,
358        block_size: u64,
359        fee_amount: u64,
360        payload_commitment: &BuilderCommitment,
361    ) -> Result<Self::BuilderSignature, Self::SignError> {
362        Self::sign_builder_message(
363            private_key,
364            &aggregate_block_info_data(block_size, fee_amount, payload_commitment),
365        )
366    }
367
368    /// Generate a new key pair
369    fn generated_from_seed_indexed(seed: [u8; 32], index: u64) -> (Self, Self::BuilderPrivateKey);
370}
371
372/// Aggregate all inputs used for signature over fee data
373fn aggregate_fee_data<Metadata: EncodeBytes>(fee_amount: u64, metadata: &Metadata) -> Vec<u8> {
374    let mut fee_info = Vec::new();
375
376    fee_info.extend_from_slice(fee_amount.to_be_bytes().as_ref());
377    fee_info.extend_from_slice(metadata.encode().as_ref());
378
379    fee_info
380}
381
382/// Aggregate all inputs used for signature over fee data, including the vid commitment
383fn aggregate_fee_data_with_vid_commitment<Metadata: EncodeBytes>(
384    fee_amount: u64,
385    metadata: &Metadata,
386    vid_commitment: &VidCommitment,
387) -> Vec<u8> {
388    let mut fee_info = Vec::new();
389
390    fee_info.extend_from_slice(fee_amount.to_be_bytes().as_ref());
391    fee_info.extend_from_slice(metadata.encode().as_ref());
392    fee_info.extend_from_slice(vid_commitment.as_ref());
393
394    fee_info
395}
396
397/// Aggregate all inputs used for signature over fee data
398fn aggregate_fee_data_marketplace(fee_amount: u64, view_number: u64) -> Vec<u8> {
399    let mut fee_info = Vec::new();
400    fee_info.extend_from_slice(fee_amount.to_be_bytes().as_ref());
401    fee_info.extend_from_slice(view_number.to_be_bytes().as_ref());
402    fee_info
403}
404
405/// Aggregate all inputs used for signature over block info
406fn aggregate_block_info_data(
407    block_size: u64,
408    fee_amount: u64,
409    payload_commitment: &BuilderCommitment,
410) -> Vec<u8> {
411    let mut block_info = Vec::new();
412    block_info.extend_from_slice(block_size.to_be_bytes().as_ref());
413    block_info.extend_from_slice(fee_amount.to_be_bytes().as_ref());
414    block_info.extend_from_slice(payload_commitment.as_ref());
415    block_info
416}
417
418/// Light client state signature key with minimal requirements
419pub trait StateSignatureKey:
420    Send
421    + Sync
422    + Clone
423    + Sized
424    + Debug
425    + Hash
426    + Serialize
427    + for<'a> Deserialize<'a>
428    + PartialEq
429    + Eq
430    + Display
431    + Default
432    + ToFieldsLightClientCompat
433    + for<'a> TryFrom<&'a TaggedBase64>
434    + Into<TaggedBase64>
435{
436    /// The private key type
437    type StatePrivateKey: PrivateSignatureKey;
438
439    /// The type of the signature
440    type StateSignature: Send
441        + Sync
442        + Sized
443        + Clone
444        + Debug
445        + Eq
446        + Serialize
447        + for<'a> Deserialize<'a>
448        + Hash;
449
450    /// Type of error that can occur when signing data
451    type SignError: std::error::Error + Send + Sync;
452
453    /// Sign the light client state
454    fn sign_state(
455        private_key: &Self::StatePrivateKey,
456        light_client_state: &LightClientState,
457        next_stake_table_state: &StakeTableState,
458    ) -> Result<Self::StateSignature, Self::SignError>;
459
460    /// Verify the light client state signature
461    fn verify_state_sig(
462        &self,
463        signature: &Self::StateSignature,
464        light_client_state: &LightClientState,
465        next_stake_table_state: &StakeTableState,
466    ) -> bool;
467
468    /// Generate a new key pair
469    fn generated_from_seed_indexed(seed: [u8; 32], index: u64) -> (Self, Self::StatePrivateKey);
470}