chie_crypto/
threshold.rs

1//! Threshold signatures and multi-signature schemes.
2//!
3//! This module provides simple threshold signature functionality
4//! for scenarios where multiple parties need to sign together.
5
6use crate::{PublicKey, SignatureBytes};
7use thiserror::Error;
8
9/// Threshold signature error types.
10#[derive(Debug, Error)]
11pub enum ThresholdError {
12    #[error("Not enough signatures: need {threshold}, got {actual}")]
13    InsufficientSignatures { threshold: usize, actual: usize },
14
15    #[error("Invalid signature at index {0}")]
16    InvalidSignature(usize),
17
18    #[error("Duplicate public key")]
19    DuplicatePublicKey,
20
21    #[error("Invalid threshold: {0}")]
22    InvalidThreshold(String),
23
24    #[error("Signing error: {0}")]
25    SigningError(#[from] crate::SigningError),
26}
27
28/// Multi-signature aggregator.
29///
30/// This aggregates signatures from multiple parties on the same message.
31/// All parties must sign for the multi-sig to be valid.
32#[derive(Debug, Clone)]
33pub struct MultiSig {
34    /// Public keys of all signers.
35    pub signers: Vec<PublicKey>,
36    /// Signatures from each signer (must be in same order as signers).
37    pub signatures: Vec<SignatureBytes>,
38}
39
40impl MultiSig {
41    /// Create a new multi-signature.
42    pub fn new(signers: Vec<PublicKey>, signatures: Vec<SignatureBytes>) -> Self {
43        Self {
44            signers,
45            signatures,
46        }
47    }
48
49    /// Verify all signatures.
50    pub fn verify(&self, message: &[u8]) -> Result<(), ThresholdError> {
51        use crate::signing::verify;
52
53        if self.signers.len() != self.signatures.len() {
54            return Err(ThresholdError::InsufficientSignatures {
55                threshold: self.signers.len(),
56                actual: self.signatures.len(),
57            });
58        }
59
60        for (i, (pubkey, sig)) in self.signers.iter().zip(self.signatures.iter()).enumerate() {
61            verify(pubkey, message, sig).map_err(|_| ThresholdError::InvalidSignature(i))?;
62        }
63
64        Ok(())
65    }
66
67    /// Get the number of signers.
68    pub fn signer_count(&self) -> usize {
69        self.signers.len()
70    }
71}
72
73/// Threshold signature scheme (M-of-N).
74///
75/// Requires at least M signatures out of N possible signers.
76#[derive(Debug, Clone)]
77pub struct ThresholdSig {
78    /// All possible signers (N).
79    pub possible_signers: Vec<PublicKey>,
80    /// Minimum required signatures (M).
81    pub threshold: usize,
82    /// Actual signatures provided (pubkey, signature pairs).
83    pub signatures: Vec<(PublicKey, SignatureBytes)>,
84}
85
86impl ThresholdSig {
87    /// Create a new threshold signature.
88    pub fn new(possible_signers: Vec<PublicKey>, threshold: usize) -> Result<Self, ThresholdError> {
89        if threshold == 0 || threshold > possible_signers.len() {
90            return Err(ThresholdError::InvalidThreshold(format!(
91                "threshold must be 1 <= M <= {}, got {}",
92                possible_signers.len(),
93                threshold
94            )));
95        }
96
97        // Check for duplicates
98        let mut sorted = possible_signers.clone();
99        sorted.sort();
100        for i in 1..sorted.len() {
101            if sorted[i] == sorted[i - 1] {
102                return Err(ThresholdError::DuplicatePublicKey);
103            }
104        }
105
106        Ok(Self {
107            possible_signers,
108            threshold,
109            signatures: Vec::new(),
110        })
111    }
112
113    /// Add a signature from one of the signers.
114    pub fn add_signature(
115        &mut self,
116        signer: PublicKey,
117        signature: SignatureBytes,
118    ) -> Result<(), ThresholdError> {
119        // Check the signer is in the possible signers list
120        if !self.possible_signers.contains(&signer) {
121            return Err(ThresholdError::InvalidSignature(0));
122        }
123
124        // Check for duplicate signature from same signer
125        if self.signatures.iter().any(|(pk, _)| pk == &signer) {
126            return Err(ThresholdError::DuplicatePublicKey);
127        }
128
129        self.signatures.push((signer, signature));
130        Ok(())
131    }
132
133    /// Verify the threshold signature.
134    pub fn verify(&self, message: &[u8]) -> Result<(), ThresholdError> {
135        use crate::signing::verify;
136
137        if self.signatures.len() < self.threshold {
138            return Err(ThresholdError::InsufficientSignatures {
139                threshold: self.threshold,
140                actual: self.signatures.len(),
141            });
142        }
143
144        // Verify each signature
145        for (i, (pubkey, sig)) in self.signatures.iter().enumerate() {
146            // Ensure the signer is in the allowed list
147            if !self.possible_signers.contains(pubkey) {
148                return Err(ThresholdError::InvalidSignature(i));
149            }
150
151            // Verify the signature
152            verify(pubkey, message, sig).map_err(|_| ThresholdError::InvalidSignature(i))?;
153        }
154
155        Ok(())
156    }
157
158    /// Check if threshold is met.
159    pub fn is_complete(&self) -> bool {
160        self.signatures.len() >= self.threshold
161    }
162
163    /// Get the number of signatures collected.
164    pub fn signature_count(&self) -> usize {
165        self.signatures.len()
166    }
167}
168
169/// Multi-party signature builder for collecting signatures.
170pub struct MultiSigBuilder {
171    signers: Vec<PublicKey>,
172    signatures: Vec<Option<SignatureBytes>>,
173}
174
175impl MultiSigBuilder {
176    /// Create a new multi-sig builder.
177    pub fn new(signers: Vec<PublicKey>) -> Self {
178        let count = signers.len();
179        Self {
180            signers,
181            signatures: vec![None; count],
182        }
183    }
184
185    /// Add a signature from a signer.
186    pub fn add_signature(
187        &mut self,
188        signer: &PublicKey,
189        signature: SignatureBytes,
190    ) -> Result<(), ThresholdError> {
191        let index = self
192            .signers
193            .iter()
194            .position(|pk| pk == signer)
195            .ok_or(ThresholdError::InvalidSignature(0))?;
196
197        self.signatures[index] = Some(signature);
198        Ok(())
199    }
200
201    /// Check if all signatures are collected.
202    pub fn is_complete(&self) -> bool {
203        self.signatures.iter().all(|s| s.is_some())
204    }
205
206    /// Build the final multi-signature.
207    pub fn build(self) -> Result<MultiSig, ThresholdError> {
208        let signatures: Option<Vec<SignatureBytes>> = self.signatures.into_iter().collect();
209
210        match signatures {
211            Some(sigs) => Ok(MultiSig::new(self.signers, sigs)),
212            None => Err(ThresholdError::InsufficientSignatures {
213                threshold: self.signers.len(),
214                actual: 0,
215            }),
216        }
217    }
218}
219
220/// Simple coordinator-based threshold signing.
221///
222/// This provides a simple threshold signing scheme where a coordinator
223/// collects partial signatures and combines them.
224pub struct ThresholdCoordinator {
225    /// Threshold signature being built.
226    threshold_sig: ThresholdSig,
227    /// Message being signed.
228    message: Vec<u8>,
229}
230
231impl ThresholdCoordinator {
232    /// Create a new threshold coordinator.
233    pub fn new(
234        possible_signers: Vec<PublicKey>,
235        threshold: usize,
236        message: Vec<u8>,
237    ) -> Result<Self, ThresholdError> {
238        let threshold_sig = ThresholdSig::new(possible_signers, threshold)?;
239
240        Ok(Self {
241            threshold_sig,
242            message,
243        })
244    }
245
246    /// Add a signature from a participant.
247    pub fn add_signature(
248        &mut self,
249        signer: PublicKey,
250        signature: SignatureBytes,
251    ) -> Result<(), ThresholdError> {
252        use crate::signing::verify;
253
254        // Verify the signature before adding
255        verify(&signer, &self.message, &signature)?;
256
257        self.threshold_sig.add_signature(signer, signature)
258    }
259
260    /// Check if threshold is met.
261    pub fn is_complete(&self) -> bool {
262        self.threshold_sig.is_complete()
263    }
264
265    /// Finalize and get the threshold signature.
266    pub fn finalize(self) -> Result<ThresholdSig, ThresholdError> {
267        if !self.threshold_sig.is_complete() {
268            return Err(ThresholdError::InsufficientSignatures {
269                threshold: self.threshold_sig.threshold,
270                actual: self.threshold_sig.signature_count(),
271            });
272        }
273
274        Ok(self.threshold_sig)
275    }
276}
277
278#[cfg(test)]
279mod tests {
280    use super::*;
281    use crate::signing::KeyPair;
282
283    #[test]
284    fn test_multi_sig() {
285        let message = b"Multi-sig test message";
286
287        // Create 3 signers
288        let kp1 = KeyPair::generate();
289        let kp2 = KeyPair::generate();
290        let kp3 = KeyPair::generate();
291
292        let signers = vec![kp1.public_key(), kp2.public_key(), kp3.public_key()];
293
294        let signatures = vec![kp1.sign(message), kp2.sign(message), kp3.sign(message)];
295
296        let multi_sig = MultiSig::new(signers, signatures);
297        assert!(multi_sig.verify(message).is_ok());
298    }
299
300    #[test]
301    fn test_multi_sig_invalid() {
302        let message = b"Test message";
303        let wrong_message = b"Wrong message";
304
305        let kp1 = KeyPair::generate();
306        let kp2 = KeyPair::generate();
307
308        let signers = vec![kp1.public_key(), kp2.public_key()];
309        let signatures = vec![kp1.sign(message), kp2.sign(wrong_message)];
310
311        let multi_sig = MultiSig::new(signers, signatures);
312        assert!(multi_sig.verify(message).is_err());
313    }
314
315    #[test]
316    fn test_threshold_sig_2_of_3() {
317        let message = b"Threshold sig test";
318
319        let kp1 = KeyPair::generate();
320        let kp2 = KeyPair::generate();
321        let kp3 = KeyPair::generate();
322
323        let possible_signers = vec![kp1.public_key(), kp2.public_key(), kp3.public_key()];
324
325        let mut threshold_sig = ThresholdSig::new(possible_signers, 2).unwrap();
326
327        // Add first signature
328        threshold_sig
329            .add_signature(kp1.public_key(), kp1.sign(message))
330            .unwrap();
331        assert!(!threshold_sig.is_complete());
332
333        // Add second signature - now threshold is met
334        threshold_sig
335            .add_signature(kp2.public_key(), kp2.sign(message))
336            .unwrap();
337        assert!(threshold_sig.is_complete());
338
339        // Verify
340        assert!(threshold_sig.verify(message).is_ok());
341    }
342
343    #[test]
344    fn test_threshold_insufficient_signatures() {
345        let message = b"Test";
346
347        let kp1 = KeyPair::generate();
348        let kp2 = KeyPair::generate();
349        let kp3 = KeyPair::generate();
350
351        let possible_signers = vec![kp1.public_key(), kp2.public_key(), kp3.public_key()];
352
353        let mut threshold_sig = ThresholdSig::new(possible_signers, 2).unwrap();
354
355        // Only add one signature
356        threshold_sig
357            .add_signature(kp1.public_key(), kp1.sign(message))
358            .unwrap();
359
360        // Verify should fail - not enough signatures
361        assert!(threshold_sig.verify(message).is_err());
362    }
363
364    #[test]
365    fn test_multi_sig_builder() {
366        let message = b"Builder test";
367
368        let kp1 = KeyPair::generate();
369        let kp2 = KeyPair::generate();
370
371        let signers = vec![kp1.public_key(), kp2.public_key()];
372        let mut builder = MultiSigBuilder::new(signers);
373
374        assert!(!builder.is_complete());
375
376        builder
377            .add_signature(&kp1.public_key(), kp1.sign(message))
378            .unwrap();
379        assert!(!builder.is_complete());
380
381        builder
382            .add_signature(&kp2.public_key(), kp2.sign(message))
383            .unwrap();
384        assert!(builder.is_complete());
385
386        let multi_sig = builder.build().unwrap();
387        assert!(multi_sig.verify(message).is_ok());
388    }
389
390    #[test]
391    fn test_threshold_coordinator() {
392        let message = b"Coordinator test";
393
394        let kp1 = KeyPair::generate();
395        let kp2 = KeyPair::generate();
396        let kp3 = KeyPair::generate();
397
398        let signers = vec![kp1.public_key(), kp2.public_key(), kp3.public_key()];
399
400        let mut coordinator = ThresholdCoordinator::new(signers, 2, message.to_vec()).unwrap();
401
402        coordinator
403            .add_signature(kp1.public_key(), kp1.sign(message))
404            .unwrap();
405        assert!(!coordinator.is_complete());
406
407        coordinator
408            .add_signature(kp2.public_key(), kp2.sign(message))
409            .unwrap();
410        assert!(coordinator.is_complete());
411
412        let threshold_sig = coordinator.finalize().unwrap();
413        assert!(threshold_sig.verify(message).is_ok());
414    }
415
416    #[test]
417    fn test_invalid_threshold() {
418        let kp1 = KeyPair::generate();
419        let signers = vec![kp1.public_key()];
420
421        // Threshold 0 should fail
422        assert!(ThresholdSig::new(signers.clone(), 0).is_err());
423
424        // Threshold > N should fail
425        assert!(ThresholdSig::new(signers, 2).is_err());
426    }
427}