Skip to main content

commonware_cryptography/
lib.rs

1//! Generate keys, sign arbitrary messages, and deterministically verify signatures.
2//!
3//! # Status
4//!
5//! Stability varies by primitive. See [README](https://github.com/commonwarexyz/monorepo#stability) for details.
6
7#![doc(
8    html_logo_url = "https://commonware.xyz/imgs/rustdoc_logo.svg",
9    html_favicon_url = "https://commonware.xyz/favicon.ico"
10)]
11#![cfg_attr(not(any(feature = "std", test)), no_std)]
12
13#[cfg(not(feature = "std"))]
14extern crate alloc;
15
16// Modules containing #[macro_export] macros must use verbose cfg.
17// See rust-lang/rust#52234: macro-expanded macro_export macros cannot be referenced by absolute paths.
18#[cfg(not(any(
19    commonware_stability_GAMMA,
20    commonware_stability_DELTA,
21    commonware_stability_EPSILON,
22    commonware_stability_RESERVED
23)))] // BETA
24pub mod bls12381;
25#[cfg(not(any(
26    commonware_stability_GAMMA,
27    commonware_stability_DELTA,
28    commonware_stability_EPSILON,
29    commonware_stability_RESERVED
30)))] // BETA
31pub mod ed25519;
32#[cfg(not(any(
33    commonware_stability_BETA,
34    commonware_stability_GAMMA,
35    commonware_stability_DELTA,
36    commonware_stability_EPSILON,
37    commonware_stability_RESERVED
38)))] // ALPHA
39pub mod secp256r1;
40
41commonware_macros::stability_scope!(ALPHA {
42    #[cfg(feature = "std")]
43    pub mod banderwagon;
44    pub mod bloomfilter;
45    pub use crate::bloomfilter::BloomFilter;
46
47    pub mod lthash;
48    pub use crate::lthash::LtHash;
49
50    pub mod reed_solomon;
51
52    pub mod zk;
53});
54commonware_macros::stability_scope!(BETA {
55    use commonware_codec::{Encode, ReadExt};
56    use commonware_math::algebra::Random;
57    use commonware_parallel::Strategy;
58    use commonware_utils::Array;
59    use rand_core::SeedableRng as _;
60    use rand_chacha::ChaCha20Rng;
61    use rand_core::CryptoRng;
62
63    pub mod secret;
64    pub use crate::secret::Secret;
65
66    pub mod certificate;
67    pub mod transcript;
68
69    pub mod sha256;
70    pub use crate::sha256::{CoreSha256, Sha256};
71    pub mod blake3;
72    pub use crate::blake3::{Blake3, CoreBlake3};
73    #[cfg(feature = "std")]
74    pub mod crc32;
75    #[cfg(feature = "std")]
76    pub use crate::crc32::Crc32;
77
78    #[cfg(feature = "std")]
79    pub mod handshake;
80
81    /// Produces [Signature]s over messages that can be verified with a corresponding [PublicKey].
82    pub trait Signer: Random + Send + Sync + Clone + 'static {
83        /// The type of [Signature] produced by this [Signer].
84        type Signature: Signature;
85
86        /// The corresponding [PublicKey] type.
87        type PublicKey: PublicKey<Signature = Self::Signature>;
88
89        /// Returns the [PublicKey] corresponding to this [Signer].
90        fn public_key(&self) -> Self::PublicKey;
91
92        /// Sign a message with the given namespace.
93        ///
94        /// The message should not be hashed prior to calling this function. If a particular scheme
95        /// requires a payload to be hashed before it is signed, it will be done internally.
96        ///
97        /// A namespace must be used to prevent cross-domain attacks (where a signature can be reused
98        /// in a different context). It must be prepended to the message so that a signature meant for
99        /// one context cannot be used unexpectedly in another (i.e. signing a message on the network
100        /// layer can't accidentally spend funds on the execution layer). See
101        /// [commonware_utils::union_unique] for details.
102        fn sign(&self, namespace: &[u8], msg: &[u8]) -> Self::Signature;
103
104        /// Create a [Signer] from a seed.
105        ///
106        /// # Warning
107        ///
108        /// This function is insecure and should only be used for examples
109        /// and testing.
110        fn from_seed(seed: u64) -> Self {
111            Self::random(ChaCha20Rng::seed_from_u64(seed))
112        }
113    }
114
115    /// A [Signer] that can be serialized/deserialized.
116    pub trait PrivateKey: Signer + Sized + ReadExt + Encode {}
117
118    /// Verifies [Signature]s over messages.
119    pub trait Verifier {
120        /// The type of [Signature] that this verifier can verify.
121        type Signature: Signature;
122
123        /// Verify that a [Signature] is a valid over a given message.
124        ///
125        /// The message should not be hashed prior to calling this function. If a particular
126        /// scheme requires a payload to be hashed before it is signed, it will be done internally.
127        ///
128        /// Because namespace is prepended to message before signing, the namespace provided here must
129        /// match the namespace provided during signing.
130        fn verify(&self, namespace: &[u8], msg: &[u8], sig: &Self::Signature) -> bool;
131    }
132
133    /// A [PublicKey], able to verify [Signature]s.
134    pub trait PublicKey: Verifier + Sized + ReadExt + Encode + PartialEq + Array {}
135
136    /// A [Signature] over a message.
137    pub trait Signature: Sized + Clone + ReadExt + Encode + PartialEq + Array {}
138
139    /// An extension of [Signature] that supports public key recovery.
140    pub trait Recoverable: Signature {
141        /// The type of [PublicKey] that can be recovered from this [Signature].
142        type PublicKey: PublicKey<Signature = Self>;
143
144        /// Recover the [PublicKey] of the signer that created this [Signature] over the given message.
145        ///
146        /// The message should not be hashed prior to calling this function. If a particular
147        /// scheme requires a payload to be hashed before it is signed, it will be done internally.
148        ///
149        /// Like when verifying a signature, the namespace must match what was used during signing exactly.
150        fn recover_signer(&self, namespace: &[u8], msg: &[u8]) -> Option<Self::PublicKey>;
151    }
152
153    /// Verifies whether all [Signature]s are correct or that some [Signature] is incorrect.
154    pub trait BatchVerifier {
155        /// The type of public keys that this verifier can accept.
156        type PublicKey: PublicKey;
157
158        /// Create a new batch verifier with capacity for at least `capacity` items.
159        ///
160        /// The capacity is a hint: more than `capacity` items may be added, and
161        /// implementations may ignore it.
162        fn new(capacity: usize) -> Self;
163
164        /// Append item to the batch.
165        ///
166        /// The message should not be hashed prior to calling this function. If a particular scheme
167        /// requires a payload to be hashed before it is signed, it will be done internally.
168        ///
169        /// A namespace must be used to prevent replay attacks. It will be prepended to the message so
170        /// that a signature meant for one context cannot be used unexpectedly in another (i.e. signing
171        /// a message on the network layer can't accidentally spend funds on the execution layer). See
172        /// [commonware_utils::union_unique] for details.
173        fn add(
174            &mut self,
175            namespace: &[u8],
176            message: &[u8],
177            public_key: &Self::PublicKey,
178            signature: &<Self::PublicKey as Verifier>::Signature,
179        ) -> bool;
180
181        /// Verify all items added to the batch.
182        ///
183        /// Returns `true` if all items are valid, `false` otherwise.
184        ///
185        /// # Why Randomness?
186        ///
187        /// When performing batch verification, it is often important to add some randomness
188        /// to prevent an attacker from constructing a malicious batch of signatures that pass
189        /// batch verification but are invalid individually. Abstractly, think of this as
190        /// there existing two valid signatures (`c_1` and `c_2`) and an attacker proposing
191        /// (`c_1 + d` and `c_2 - d`).
192        ///
193        /// You can read more about this [here](https://ethresear.ch/t/security-of-bls-batch-verification/10748#the-importance-of-randomness-4).
194        fn verify<R: CryptoRng>(self, rng: &mut R, strategy: &impl Strategy) -> bool;
195    }
196
197    /// Specializes the [commonware_utils::Array] trait with the Copy trait for cryptographic digests
198    /// (which should be cheap to clone).
199    ///
200    /// # Warning
201    ///
202    /// This trait requires [`Random::random`], but generating a digest at random is
203    /// typically reserved for testing, and not production use.
204    pub trait Digest: Array + Copy + Random {
205        /// An empty (all-zero) digest.
206        const EMPTY: Self;
207    }
208
209    /// An object that can be uniquely represented as a [Digest].
210    pub trait Digestible: Clone + Sized + Send + Sync + 'static {
211        /// The type of digest produced by this object.
212        type Digest: Digest;
213
214        /// Returns a unique representation of the object as a [Digest].
215        ///
216        /// If many objects with [Digest]s are related (map to some higher-level
217        /// group [Digest]), you should also implement [Committable].
218        fn digest(&self) -> Self::Digest;
219    }
220
221    /// An object that can produce a commitment of itself.
222    pub trait Committable: Clone + Sized + Send + Sync + 'static {
223        /// The type of commitment produced by this object.
224        type Commitment: Digest;
225
226        /// Returns the unique commitment of the object as a [Digest].
227        ///
228        /// For simple objects (like a block), this is often just the digest of the object
229        /// itself. For more complex objects, however, this may represent some root or base
230        /// of a proof structure (where many unique objects map to the same commitment).
231        ///
232        /// # Warning
233        ///
234        /// It must not be possible for two objects with the same [Digest] to map
235        /// to different commitments. Primitives assume there is a one-to-one
236        /// relation between digest and commitment and a one-to-many relation
237        /// between commitment and digest.
238        fn commitment(&self) -> Self::Commitment;
239    }
240
241    pub type DigestOf<H> = <H as Hasher>::Digest;
242
243    /// Interface that commonware crates rely on for hashing.
244    ///
245    /// Hash functions in commonware primitives are not typically hardcoded
246    /// to a specific algorithm (e.g. SHA-256) because different hash functions
247    /// may work better with different cryptographic schemes, may be more efficient
248    /// to use in STARK/SNARK proofs, or provide different levels of security (with some
249    /// performance/size penalty).
250    ///
251    /// This trait is required to implement the `Clone` trait because it is often
252    /// part of a struct that is cloned. In practice, implementations do not actually
253    /// clone the hasher state but users should not rely on this behavior and call `reset`
254    /// after cloning.
255    pub trait Hasher: Default + Clone + Send + Sync + 'static {
256        /// Digest generated by the hasher.
257        type Digest: Digest;
258
259        /// Create a new, empty hasher.
260        fn new() -> Self {
261            Self::default()
262        }
263
264        /// Append message to previously recorded data.
265        fn update(&mut self, message: &[u8]) -> &mut Self;
266
267        /// Hash all recorded data and reset the hasher
268        /// to the initial state.
269        fn finalize(&mut self) -> Self::Digest;
270
271        /// Reset the hasher without generating a hash.
272        ///
273        /// This function does not need to be called after `finalize`.
274        fn reset(&mut self) -> &mut Self;
275
276        /// Hash a single message with a one-time-use hasher.
277        fn hash(message: &[u8]) -> Self::Digest {
278            Self::new().update(message).finalize()
279        }
280    }
281});
282
283#[cfg(test)]
284mod tests {
285    use super::*;
286    use commonware_codec::{DecodeExt, FixedSize};
287    use commonware_utils::test_rng;
288
289    fn test_validate<C: PrivateKey>() {
290        let private_key = C::random(test_rng());
291        let public_key = private_key.public_key();
292        assert!(C::PublicKey::decode(public_key.as_ref()).is_ok());
293    }
294
295    fn test_validate_invalid_public_key<C: Signer>() {
296        let result = C::PublicKey::decode(vec![0; 1024].as_ref());
297        assert!(result.is_err());
298    }
299
300    fn test_sign_and_verify<C: PrivateKey>() {
301        let private_key = C::from_seed(0);
302        let namespace = b"test_namespace";
303        let message = b"test_message";
304        let signature = private_key.sign(namespace, message);
305        let public_key = private_key.public_key();
306        assert!(public_key.verify(namespace, message, &signature));
307    }
308
309    fn test_sign_and_verify_wrong_message<C: PrivateKey>() {
310        let private_key = C::from_seed(0);
311        let namespace = b"test_namespace";
312        let message = b"test_message";
313        let wrong_message = b"wrong_message";
314        let signature = private_key.sign(namespace, message);
315        let public_key = private_key.public_key();
316        assert!(!public_key.verify(namespace, wrong_message, &signature));
317    }
318
319    fn test_sign_and_verify_wrong_namespace<C: PrivateKey>() {
320        let private_key = C::from_seed(0);
321        let namespace = b"test_namespace";
322        let wrong_namespace = b"wrong_namespace";
323        let message = b"test_message";
324        let signature = private_key.sign(namespace, message);
325        let public_key = private_key.public_key();
326        assert!(!public_key.verify(wrong_namespace, message, &signature));
327    }
328
329    fn test_empty_namespace<C: PrivateKey>() {
330        let private_key = C::from_seed(0);
331        let empty_namespace = b"";
332        let message = b"test_message";
333        let signature = private_key.sign(empty_namespace, message);
334        let public_key = private_key.public_key();
335        assert!(public_key.verify(empty_namespace, message, &signature));
336    }
337
338    fn test_signature_determinism<C: PrivateKey>() {
339        let private_key_1 = C::from_seed(0);
340        let private_key_2 = C::from_seed(0);
341        let namespace = b"test_namespace";
342        let message = b"test_message";
343        let signature_1 = private_key_1.sign(namespace, message);
344        let signature_2 = private_key_2.sign(namespace, message);
345        assert_eq!(private_key_1.public_key(), private_key_2.public_key());
346        assert_eq!(signature_1, signature_2);
347    }
348
349    fn test_invalid_signature_publickey_pair<C: PrivateKey>() {
350        let private_key = C::from_seed(0);
351        let private_key_2 = C::from_seed(1);
352        let namespace = b"test_namespace";
353        let message = b"test_message";
354        let signature = private_key.sign(namespace, message);
355        let public_key = private_key_2.public_key();
356        assert!(!public_key.verify(namespace, message, &signature));
357    }
358
359    #[test]
360    fn test_ed25519_validate() {
361        test_validate::<ed25519::PrivateKey>();
362    }
363
364    #[test]
365    fn test_ed25519_validate_invalid_public_key() {
366        test_validate_invalid_public_key::<ed25519::PrivateKey>();
367    }
368
369    #[test]
370    fn test_ed25519_sign_and_verify() {
371        test_sign_and_verify::<ed25519::PrivateKey>();
372    }
373
374    #[test]
375    fn test_ed25519_sign_and_verify_wrong_message() {
376        test_sign_and_verify_wrong_message::<ed25519::PrivateKey>();
377    }
378
379    #[test]
380    fn test_ed25519_sign_and_verify_wrong_namespace() {
381        test_sign_and_verify_wrong_namespace::<ed25519::PrivateKey>();
382    }
383
384    #[test]
385    fn test_ed25519_empty_namespace() {
386        test_empty_namespace::<ed25519::PrivateKey>();
387    }
388
389    #[test]
390    fn test_ed25519_signature_determinism() {
391        test_signature_determinism::<ed25519::PrivateKey>();
392    }
393
394    #[test]
395    fn test_ed25519_invalid_signature_publickey_pair() {
396        test_invalid_signature_publickey_pair::<ed25519::PrivateKey>();
397    }
398
399    #[test]
400    fn test_ed25519_len() {
401        assert_eq!(ed25519::PublicKey::SIZE, 32);
402        assert_eq!(ed25519::Signature::SIZE, 64);
403    }
404
405    #[test]
406    fn test_bls12381_validate() {
407        test_validate::<bls12381::PrivateKey>();
408    }
409
410    #[test]
411    fn test_bls12381_validate_invalid_public_key() {
412        test_validate_invalid_public_key::<bls12381::PrivateKey>();
413    }
414
415    #[test]
416    fn test_bls12381_sign_and_verify() {
417        test_sign_and_verify::<bls12381::PrivateKey>();
418    }
419
420    #[test]
421    fn test_bls12381_sign_and_verify_wrong_message() {
422        test_sign_and_verify_wrong_message::<bls12381::PrivateKey>();
423    }
424
425    #[test]
426    fn test_bls12381_sign_and_verify_wrong_namespace() {
427        test_sign_and_verify_wrong_namespace::<bls12381::PrivateKey>();
428    }
429
430    #[test]
431    fn test_bls12381_empty_namespace() {
432        test_empty_namespace::<bls12381::PrivateKey>();
433    }
434
435    #[test]
436    fn test_bls12381_signature_determinism() {
437        test_signature_determinism::<bls12381::PrivateKey>();
438    }
439
440    #[test]
441    fn test_bls12381_invalid_signature_publickey_pair() {
442        test_invalid_signature_publickey_pair::<bls12381::PrivateKey>();
443    }
444
445    #[test]
446    fn test_bls12381_len() {
447        assert_eq!(bls12381::PublicKey::SIZE, 48);
448        assert_eq!(bls12381::Signature::SIZE, 96);
449    }
450
451    #[test]
452    fn test_secp256r1_standard_validate() {
453        test_validate::<secp256r1::standard::PrivateKey>();
454    }
455
456    #[test]
457    fn test_secp256r1_standard_validate_invalid_public_key() {
458        test_validate_invalid_public_key::<secp256r1::standard::PrivateKey>();
459    }
460
461    #[test]
462    fn test_secp256r1_standard_sign_and_verify() {
463        test_sign_and_verify::<secp256r1::standard::PrivateKey>();
464    }
465
466    #[test]
467    fn test_secp256r1_standard_sign_and_verify_wrong_message() {
468        test_sign_and_verify_wrong_message::<secp256r1::standard::PrivateKey>();
469    }
470
471    #[test]
472    fn test_secp256r1_standard_sign_and_verify_wrong_namespace() {
473        test_sign_and_verify_wrong_namespace::<secp256r1::standard::PrivateKey>();
474    }
475
476    #[test]
477    fn test_secp256r1_standard_empty_namespace() {
478        test_empty_namespace::<secp256r1::standard::PrivateKey>();
479    }
480
481    #[test]
482    fn test_secp256r1_standard_signature_determinism() {
483        test_signature_determinism::<secp256r1::standard::PrivateKey>();
484    }
485
486    #[test]
487    fn test_secp256r1_standard_invalid_signature_publickey_pair() {
488        test_invalid_signature_publickey_pair::<secp256r1::standard::PrivateKey>();
489    }
490
491    #[test]
492    fn test_secp256r1_standard_len() {
493        assert_eq!(secp256r1::standard::PublicKey::SIZE, 33);
494        assert_eq!(secp256r1::standard::Signature::SIZE, 64);
495    }
496
497    #[test]
498    fn test_secp256r1_recoverable_validate() {
499        test_validate::<secp256r1::recoverable::PrivateKey>();
500    }
501
502    #[test]
503    fn test_secp256r1_recoverable_validate_invalid_public_key() {
504        test_validate_invalid_public_key::<secp256r1::recoverable::PrivateKey>();
505    }
506
507    #[test]
508    fn test_secp256r1_recoverable_sign_and_verify() {
509        test_sign_and_verify::<secp256r1::recoverable::PrivateKey>();
510    }
511
512    #[test]
513    fn test_secp256r1_recoverable_sign_and_verify_wrong_message() {
514        test_sign_and_verify_wrong_message::<secp256r1::recoverable::PrivateKey>();
515    }
516
517    #[test]
518    fn test_secp256r1_recoverable_sign_and_verify_wrong_namespace() {
519        test_sign_and_verify_wrong_namespace::<secp256r1::recoverable::PrivateKey>();
520    }
521
522    #[test]
523    fn test_secp256r1_recoverable_empty_namespace() {
524        test_empty_namespace::<secp256r1::recoverable::PrivateKey>();
525    }
526
527    #[test]
528    fn test_secp256r1_recoverable_signature_determinism() {
529        test_signature_determinism::<secp256r1::recoverable::PrivateKey>();
530    }
531
532    #[test]
533    fn test_secp256r1_recoverable_invalid_signature_publickey_pair() {
534        test_invalid_signature_publickey_pair::<secp256r1::recoverable::PrivateKey>();
535    }
536
537    #[test]
538    fn test_secp256r1_recoverable_len() {
539        assert_eq!(secp256r1::recoverable::PublicKey::SIZE, 33);
540        assert_eq!(secp256r1::recoverable::Signature::SIZE, 65);
541    }
542
543    fn test_hasher_multiple_runs<H: Hasher>() {
544        // Generate initial hash
545        let mut hasher = H::new();
546        hasher.update(b"hello world");
547        let digest = hasher.finalize();
548        assert!(H::Digest::decode(digest.as_ref()).is_ok());
549        assert_eq!(digest.as_ref().len(), H::Digest::SIZE);
550
551        // Reuse hasher without reset
552        hasher.update(b"hello world");
553        let digest_again = hasher.finalize();
554        assert!(H::Digest::decode(digest_again.as_ref()).is_ok());
555        assert_eq!(digest, digest_again);
556
557        // Reuse hasher with reset
558        hasher.update(b"hello mars");
559        hasher.reset();
560        hasher.update(b"hello world");
561        let digest_reset = hasher.finalize();
562        assert!(H::Digest::decode(digest_reset.as_ref()).is_ok());
563        assert_eq!(digest, digest_reset);
564
565        // Hash different data
566        hasher.update(b"hello mars");
567        let digest_mars = hasher.finalize();
568        assert!(H::Digest::decode(digest_mars.as_ref()).is_ok());
569        assert_ne!(digest, digest_mars);
570    }
571
572    fn test_hasher_multiple_updates<H: Hasher>() {
573        // Generate initial hash
574        let mut hasher = H::new();
575        hasher.update(b"hello");
576        hasher.update(b" world");
577        let digest = hasher.finalize();
578        assert!(H::Digest::decode(digest.as_ref()).is_ok());
579
580        // Generate hash in oneshot
581        let mut hasher = H::new();
582        hasher.update(b"hello world");
583        let digest_oneshot = hasher.finalize();
584        assert!(H::Digest::decode(digest_oneshot.as_ref()).is_ok());
585        assert_eq!(digest, digest_oneshot);
586    }
587
588    fn test_hasher_empty_input<H: Hasher>() {
589        let mut hasher = H::new();
590        let digest = hasher.finalize();
591        assert!(H::Digest::decode(digest.as_ref()).is_ok());
592    }
593
594    fn test_hasher_large_input<H: Hasher>() {
595        let mut hasher = H::new();
596        let data = vec![1; 1024];
597        hasher.update(&data);
598        let digest = hasher.finalize();
599        assert!(H::Digest::decode(digest.as_ref()).is_ok());
600    }
601
602    #[test]
603    fn test_sha256_hasher_multiple_runs() {
604        test_hasher_multiple_runs::<Sha256>();
605    }
606
607    #[test]
608    fn test_sha256_hasher_multiple_updates() {
609        test_hasher_multiple_updates::<Sha256>();
610    }
611
612    #[test]
613    fn test_sha256_hasher_empty_input() {
614        test_hasher_empty_input::<Sha256>();
615    }
616
617    #[test]
618    fn test_sha256_hasher_large_input() {
619        test_hasher_large_input::<Sha256>();
620    }
621}