commonware_cryptography/bls12381/
mod.rs

1//! Distributed Key Generation (DKG), Resharing, Signatures, and Threshold Signatures over the BLS12-381 curve.
2//!
3//! # Features
4//!
5//! This crate has the following features:
6//!
7//! - `portable`: Enables `portable` feature on `blst` (<https://github.com/supranational/blst?tab=readme-ov-file#platform-and-language-compatibility>).
8
9pub mod dkg;
10pub mod primitives;
11mod scheme;
12pub use scheme::{Bls12381, PrivateKey, PublicKey, Signature};
13
14#[cfg(test)]
15mod tests {
16    use super::*;
17    use dkg::ops::generate_shares;
18    use primitives::group::Private;
19    use primitives::ops::{
20        partial_sign_message, partial_verify_message, threshold_signature_recover, verify_message,
21    };
22    use primitives::poly::public;
23    use primitives::Error;
24    use rand::{rngs::StdRng, SeedableRng};
25
26    #[test]
27    fn test_partial_aggregate_signature() {
28        let (n, t) = (5, 4);
29        let mut rng = StdRng::seed_from_u64(0);
30
31        // Create the private key polynomial and evaluate it at `n`
32        // points to generate the shares.
33        //
34        // If receiving a share from an untrusted party, the recipient
35        // should verify the share is on the public polynomial.
36        let (group, shares) = generate_shares(&mut rng, None, n, t);
37
38        // Generate the partial signatures
39        let namespace = Some(&b"test"[..]);
40        let msg = b"hello";
41        let partials = shares
42            .iter()
43            .map(|s| partial_sign_message(s, namespace, msg))
44            .collect::<Vec<_>>();
45
46        // Each partial sig can be partially verified against the public polynomial
47        partials.iter().for_each(|partial| {
48            partial_verify_message(&group, namespace, msg, partial).unwrap();
49        });
50
51        // Generate and verify the threshold sig
52        let threshold_sig = threshold_signature_recover(t, partials).unwrap();
53        let threshold_pub = public(&group);
54        verify_message(&threshold_pub, namespace, msg, &threshold_sig).unwrap();
55    }
56
57    #[test]
58    fn test_partial_aggregate_signature_bad_namespace() {
59        let (n, t) = (5, 4);
60        let mut rng = StdRng::seed_from_u64(0);
61
62        // Create the private key polynomial and evaluate it at `n`
63        // points to generate the shares.
64        //
65        // If receiving a share from an untrusted party, the recipient
66        // should verify the share is on the public polynomial.
67        let (group, shares) = generate_shares(&mut rng, None, n, t);
68
69        // Generate the partial signatures
70        let namespace = Some(&b"test"[..]);
71        let msg = b"hello";
72        let partials = shares
73            .iter()
74            .map(|s| partial_sign_message(s, namespace, msg))
75            .collect::<Vec<_>>();
76
77        // Each partial sig can be partially verified against the public polynomial
78        let namespace = Some(&b"bad"[..]);
79        partials.iter().for_each(|partial| {
80            assert!(matches!(
81                partial_verify_message(&group, namespace, msg, partial).unwrap_err(),
82                Error::InvalidSignature
83            ));
84        });
85
86        // Generate and verify the threshold sig
87        let threshold_sig = threshold_signature_recover(t, partials).unwrap();
88        let threshold_pub = public(&group);
89        assert!(matches!(
90            verify_message(&threshold_pub, namespace, msg, &threshold_sig).unwrap_err(),
91            Error::InvalidSignature
92        ));
93    }
94
95    #[test]
96    fn test_partial_aggregate_signature_insufficient() {
97        let (n, t) = (5, 4);
98        let mut rng = StdRng::seed_from_u64(0);
99
100        // Create the private key polynomial and evaluate it at `n`
101        // points to generate the shares
102        let (group, shares) = generate_shares(&mut rng, None, n, t);
103
104        // Only take t-1 shares
105        let shares = shares.into_iter().take(t as usize - 1).collect::<Vec<_>>();
106
107        // Generate the partial signatures
108        let namespace = Some(&b"test"[..]);
109        let msg = b"hello";
110        let partials = shares
111            .iter()
112            .map(|s| partial_sign_message(s, namespace, msg))
113            .collect::<Vec<_>>();
114
115        // Each partial sig can be partially verified against the public polynomial
116        partials.iter().for_each(|partial| {
117            partial_verify_message(&group, namespace, msg, partial).unwrap();
118        });
119
120        // Generate the threshold sig
121        assert!(matches!(
122            threshold_signature_recover(t, partials).unwrap_err(),
123            Error::NotEnoughPartialSignatures(4, 3)
124        ));
125    }
126
127    #[test]
128    fn test_partial_aggregate_signature_insufficient_duplicates() {
129        let (n, t) = (5, 4);
130        let mut rng = StdRng::seed_from_u64(0);
131
132        // Create the private key polynomial and evaluate it at `n`
133        // points to generate the shares
134        let (group, shares) = generate_shares(&mut rng, None, n, t);
135
136        // Only take t-1 shares
137        let mut shares = shares.into_iter().take(t as usize - 1).collect::<Vec<_>>();
138        shares.push(shares[0]);
139
140        // Generate the partial signatures
141        let namespace = Some(&b"test"[..]);
142        let msg = b"hello";
143        let partials = shares
144            .iter()
145            .map(|s| partial_sign_message(s, namespace, msg))
146            .collect::<Vec<_>>();
147
148        // Each partial sig can be partially verified against the public polynomial
149        partials.iter().for_each(|partial| {
150            partial_verify_message(&group, namespace, msg, partial).unwrap();
151        });
152
153        // Generate the threshold sig
154        assert!(matches!(
155            threshold_signature_recover(t, partials).unwrap_err(),
156            Error::DuplicateEval,
157        ));
158    }
159
160    #[test]
161    #[should_panic(expected = "InvalidSignature")]
162    fn test_partial_aggregate_signature_bad_share() {
163        let (n, t) = (5, 4);
164        let mut rng = StdRng::seed_from_u64(0);
165
166        // Create the private key polynomial and evaluate it at `n`
167        // points to generate the shares
168        let (group, mut shares) = generate_shares(&mut rng, None, n, t);
169
170        // Corrupt a share
171        let share = shares.get_mut(3).unwrap();
172        share.private = Private::rand(&mut rand::thread_rng());
173
174        // Generate the partial signatures
175        let namespace = Some(&b"test"[..]);
176        let msg = b"hello";
177        let partials = shares
178            .iter()
179            .map(|s| partial_sign_message(s, namespace, msg))
180            .collect::<Vec<_>>();
181
182        // Each partial sig can be partially verified against the public polynomial
183        partials.iter().for_each(|partial| {
184            partial_verify_message(&group, namespace, msg, partial).unwrap();
185        });
186
187        // Generate and verify the threshold sig
188        let threshold_sig = threshold_signature_recover(t, partials).unwrap();
189        let threshold_pub = public(&group);
190        verify_message(&threshold_pub, namespace, msg, &threshold_sig).unwrap();
191    }
192}