Skip to main content

commonware_cryptography/
lib.rs

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