schnorrkel/
musig.rs

1// -*- mode: rust; -*-
2//
3// This file is part of schnorrkel.
4// Copyright (c) 2019 Web 3 Foundation
5// See LICENSE for licensing information.
6//
7// Authors:
8// - jeffrey Burdges <jeff@web3.foundation>
9
10//! Implementation for Ristretto Schnorr signatures of
11//! "Simple Schnorr Multi-Signatures with Applications to Bitcoin" by
12//! Gregory Maxwell, Andrew Poelstra, Yannick Seurin, and Pieter Wuille
13//! https://eprint.iacr.org/2018/068
14//!
15//! We observe the security arguments from the
16//! [original 2-round version](https://eprint.iacr.org/2018/068/20180118:124757)
17//! were found lacking in
18//! "On the Provable Security of Two-Round Multi-Signatures" by
19//! Manu Drijvers, Kasra Edalatnejad, Bryan Ford, and Gregory Neven
20//! https://eprint.iacr.org/2018/417
21//! ([slides](https://rwc.iacr.org/2019/slides/neven.pdf))
22//! so we implement only the
23//! [3-round version](https://eprint.iacr.org/2018/068/20180520:191909).
24//!
25//! Appendix A of the [MuSig paper](https://eprint.iacr.org/2018/068)
26//! discusses Interactive Aggregate Signatures (IAS) in which cosigners'
27//! messages differ.  Appendix A.3 gives a secure scheme that correctly
28//! binds signers to their messages.  See
29//! https://github.com/w3f/schnorrkel/issues/5#issuecomment-477912319
30
31// See also https://github.com/lovesh/signature-schemes/issues/2
32
33
34use core::borrow::{Borrow};  // BorrowMut
35
36#[cfg(feature = "alloc")]
37use alloc::{collections::btree_map::{BTreeMap, Entry}};
38
39use arrayref::array_ref;
40use arrayvec::ArrayVec;
41
42use merlin::Transcript;
43
44use curve25519_dalek::constants;
45use curve25519_dalek::ristretto::{CompressedRistretto,RistrettoPoint};
46use curve25519_dalek::scalar::Scalar;
47
48use super::*;
49use crate::context::SigningTranscript;
50use crate::errors::MultiSignatureStage;
51
52
53/// Rewinding immunity count plus one
54///
55/// At least two so that our 2-round escape hatch `add_trusted`
56/// provides some protection against the Wagner's k-sum attacks on
57/// 2-round multi-signatures.
58const REWINDS: usize = 3;
59
60
61// === Agagregate public keys for multi-signatures === //
62
63/// Compute a transcript from which we may compute public key weightings.
64///
65/// Incorrect weightings shall occur if the iterator provided does not
66/// run in the same sorted ordering as `BTreeMap::iter`/`keys`/etc.
67/// We avoided a context: &'static [u8] here and in callers because they
68/// seem irrelevant to the security arguments in the MuSig paper.
69#[inline(always)]
70fn commit_public_keys<'a,I>(keys: I) -> Transcript
71where I: Iterator<Item=&'a PublicKey>
72{
73    let mut t = Transcript::new(b"MuSig-aggregate-public_key");
74    for pk in keys {
75        t.commit_point(b"pk-set", pk.as_compressed() );
76    }
77    t
78}
79
80/// Computes the weighting from the transcript returnned by
81/// `commit_public_keys` and a public key.
82///
83/// We cannot verify that the public key was ever entered into the
84/// transcript, so user facing callers should check this.
85fn compute_weighting(mut t: Transcript, pk: &PublicKey) -> Scalar {
86    t.commit_point(b"pk-choice", pk.as_compressed() );
87    t.challenge_scalar(b"")
88}
89
90/// Any data structure used for aggregating public keys.
91///
92/// Internally, these must usually iterate over the public keys being
93/// aggregated in lexicographic order, so any `BTreeMap<PublicKey,V>`
94/// works.  Alternative designs sound plausible when working with some
95/// blockchain scheme.
96pub trait AggregatePublicKey {
97    /// Return delinearization weighting for one of many public keys being aggregated.
98    fn weighting(&self, choice: &PublicKey) -> Option<Scalar>;
99
100    /// Returns aggregated public key.
101    fn public_key(&self) -> PublicKey;
102}
103
104impl<K,V> AggregatePublicKey for BTreeMap<K,V>
105where K: Borrow<PublicKey>+Ord
106{
107    fn weighting(&self, choice: &PublicKey) -> Option<Scalar> {
108        if !self.contains_key(choice) {
109            return None;
110        }
111        let t0 = commit_public_keys( self.keys().map(|pk| pk.borrow()) );
112        Some(compute_weighting(t0, choice))
113    }
114
115    fn public_key(&self) -> PublicKey {
116        let t0 = commit_public_keys( self.keys().map(|pk| pk.borrow()) );
117        let point = self.keys().map(|pk| {
118            let pk = pk.borrow();
119            compute_weighting(t0.clone(), pk) * pk.as_point()
120        }).sum();
121        PublicKey::from_point(point)
122    }
123}
124
125/// Aggregation helper for public keys kept in slices
126pub struct AggregatePublicKeySlice<'a,K>(&'a [K])
127where K: Borrow<PublicKey>;
128
129/// Aggregate public keys stored in a mutable slice
130pub fn aggregate_public_key_from_slice<'a>(public_keys: &'a mut [PublicKey])
131 -> Option<AggregatePublicKeySlice<'a,PublicKey>>
132{
133    if public_keys.len() == 1 { return None; }
134    public_keys.sort_unstable();
135    if public_keys.windows(2).any(|x| x[0]==x[1]) { return None; }
136    Some(AggregatePublicKeySlice(public_keys))
137}
138
139/// Aggregate public keys stored in a mutable slice
140pub fn aggregate_public_key_from_refs_slice<'a>(public_keys: &'a mut [&'a PublicKey])
141 -> Option<AggregatePublicKeySlice<'a,&'a PublicKey>>
142{
143    if public_keys.len() == 1 { return None; }
144    public_keys.sort_unstable();
145    if public_keys.windows(2).any(|x| x[0]==x[1]) { return None; }
146    Some(AggregatePublicKeySlice(public_keys))
147}
148
149/// Aggregate public keys stored in a sorted slice
150pub fn aggregate_public_key_from_sorted_slice<'a,K>(public_keys: &'a mut [K])
151 -> Option<AggregatePublicKeySlice<'a,K>>
152where K: Borrow<PublicKey>+PartialOrd<K>
153{
154    if public_keys.len() == 1 { return None; }
155    if public_keys.windows(2).any(|x| x[0] >= x[1]) { return None; }
156    Some(AggregatePublicKeySlice(public_keys))
157}
158
159impl<'a,K> AggregatePublicKey for AggregatePublicKeySlice<'a,K>
160where K: Borrow<PublicKey>+PartialEq<K>
161{
162    fn weighting(&self, choice: &PublicKey) -> Option<Scalar> {
163        if self.0.iter().any(|pk| pk.borrow() == choice) {
164            return None;
165        }
166        let t0 = commit_public_keys( self.0.iter().map(|pk| pk.borrow()) );
167        Some(compute_weighting(t0, choice))
168    }
169
170    fn public_key(&self) -> PublicKey {
171        let t0 = commit_public_keys( self.0.iter().map(|pk| pk.borrow()) );
172        let point = self.0.iter().map(|pk| {
173            let pk = pk.borrow();
174            compute_weighting(t0.clone(), pk) * pk.as_point()
175        } ).sum();
176        PublicKey::from_point(point)
177    }
178}
179
180
181// === Multi-signature protocol === //
182
183const COMMITMENT_SIZE : usize = 16;
184
185/// Commitments to `R_i` values shared between cosigners during signing
186#[derive(Debug,Clone,Copy,PartialEq,Eq)]
187pub struct Commitment(pub [u8; COMMITMENT_SIZE]);
188
189impl Commitment {
190    #[allow(non_snake_case)]
191    fn for_R<I>(R: I) -> Commitment
192    where I: IntoIterator<Item=CompressedRistretto>
193    {
194        let mut t = Transcript::new(b"MuSig-commitment");
195        for R0 in R.into_iter() { t.commit_point(b"sign:R",&R0); }
196        let mut commit = [0u8; COMMITMENT_SIZE];
197        t.challenge_bytes(b"commitment",&mut commit[..]);
198        Commitment(commit)
199    }
200}
201// TODO: serde_boilerplate!(Commitment);
202
203// TODO: serde_boilerplate!(Commitment);
204
205
206/// Internal representation of revealed points 
207#[derive(Debug,Clone,PartialEq,Eq)]
208struct RevealedPoints([RistrettoPoint; REWINDS]);
209
210impl RevealedPoints {
211    /*
212    #[allow(non_snake_case)]
213    fn to_commitment(&self) -> Commitment {
214        // self.check_length() ?;
215        Commitment::for_R( self.0.iter().map(|R| R.compress()) )
216    }
217    */
218
219    fn to_reveal(&self) -> Reveal {
220        // self.check_length() ?;
221        let mut reveal = [0u8; 32*REWINDS];
222        for (o,i) in reveal.chunks_mut(32).zip(&self.0) {
223            o.copy_from_slice(i.compress().as_bytes()); 
224        }
225        Reveal(reveal)
226    }
227}
228
229/// Revealed `R_i` values shared between cosigners during signing
230// #[derive(Debug,Clone,PartialEq,Eq)]
231pub struct Reveal(pub [u8; 32*REWINDS]);
232// TODO: serde_boilerplate!(Reveal);
233
234impl Clone for Reveal {
235    fn clone(&self) -> Reveal { Reveal(self.0) }
236}
237impl PartialEq<Reveal> for Reveal {
238    #[inline]
239    fn eq(&self, other: &Reveal) -> bool {
240        self.0[..] == other.0[..]
241    }
242}
243impl Eq for Reveal { }
244
245impl Reveal {
246    fn check_length(&self) -> SignatureResult<()> {
247        if self.0.len() % 32 == 0 { Ok(()) } else { Err(SignatureError::PointDecompressionError) }
248    }
249
250    #[allow(non_snake_case)]
251    fn iter_points<'a>(&'a self) -> impl Iterator<Item=CompressedRistretto> + 'a {
252        self.0.chunks(32).map( |R| CompressedRistretto( *array_ref![R,0,32] ) )
253    }
254
255    fn to_commitment(&self) -> SignatureResult<Commitment> {
256        self.check_length() ?;
257        Ok(Commitment::for_R( self.iter_points() )) 
258    }
259
260    #[allow(clippy::wrong_self_convention)]
261    fn into_points(&self) -> SignatureResult<RevealedPoints> {
262        self.check_length() ?;
263        let a = self.iter_points().map(
264            |x| x.decompress().ok_or(SignatureError::PointDecompressionError)
265        ).collect::<SignatureResult<ArrayVec<RistrettoPoint,REWINDS>>>() ?;
266        Ok( RevealedPoints( a.into_inner().unwrap() ) )
267    }
268}
269
270
271#[allow(non_snake_case)]
272#[derive(Debug,Clone,PartialEq,Eq)]
273enum CoR {
274    Commit(Commitment),       // H(R_i)
275    Reveal(RevealedPoints),   // R_i
276    Cosigned { s: Scalar },   // s_i extracted from Cosignature type
277    Collect { reveal: RevealedPoints, s: Scalar },
278}
279
280impl CoR {
281    /*
282    #[allow(non_snake_case)]
283    fn get_reveal(&self) -> Option<&Reveal> {
284        match self {
285            CoR::Commit(_) => None,
286            CoR::Reveal(R) => Some(R),
287            CoR::Cosigned { .. } => None,  // panic! ???
288            CoR::Collect { reveal, .. } => Some(reveal),
289        }
290    }
291
292    fn get_s(&self) -> Option<&RistrettoPoint> {
293        match self {
294            CoR::Commit(_) => None,
295            CoR::Reveal(_) => None,
296            CoR::Cosigned { s } => Some(s),
297            CoR::Collect { s, .. } => Some(s),
298        }
299    }
300    */
301
302    fn set_revealed(&mut self, reveal: Reveal) -> SignatureResult<()> {
303        let commitment = reveal.to_commitment() ?;
304        let reveal = reveal.into_points() ?;
305        match self.clone() {  // TODO: Remove .clone() here with #![feature(nll)]
306            CoR::Collect { .. } => panic!("Internal error, set_reveal during collection phase."),
307            CoR::Cosigned { .. } => panic!("Internal error, cosigning during reveal phase."),
308            CoR::Commit(c_old) =>
309                if c_old==commitment {  // TODO: Restore *c_old here with #![feature(nll)]
310                    *self = CoR::Reveal(reveal);
311                    Ok(())
312                } else {
313                    let musig_stage = MultiSignatureStage::Commitment;
314                    Err(SignatureError::MuSigInconsistent { musig_stage, duplicate: false, })
315                },
316            CoR::Reveal(reveal_old) =>
317                if reveal_old == reveal { Ok(()) } else {  // TODO: Restore *R_old here with #![feature(nll)]
318                    let musig_stage = MultiSignatureStage::Reveal;
319                    Err(SignatureError::MuSigInconsistent { musig_stage, duplicate: true, })
320                },  // Should we have a general duplicate reveal error for this case?
321        }
322    }
323
324    #[allow(non_snake_case)]
325    fn set_cosigned(&mut self, s: Scalar) -> SignatureResult<()> {
326        match self {
327            CoR::Collect { .. } => panic!("Internal error, set_cosigned during collection phase."),
328            CoR::Commit(_) => {
329                    let musig_stage = MultiSignatureStage::Reveal;
330                    Err(SignatureError::MuSigAbsent { musig_stage, })
331                },
332            CoR::Reveal(_) => {
333                    *self = CoR::Cosigned { s };
334                    Ok(())
335                },
336            CoR::Cosigned { s: s_old } =>
337                if *s_old==s { Ok(()) } else {
338                    let musig_stage = MultiSignatureStage::Cosignature;
339                    Err(SignatureError::MuSigInconsistent { musig_stage, duplicate: true, })
340                },
341        }
342    }
343}
344
345
346/// Schnorr multi-signature (MuSig) container generic over its session types
347#[allow(non_snake_case)]
348pub struct MuSig<T: SigningTranscript+Clone,S> {
349    t: T,
350    Rs: BTreeMap<PublicKey,CoR>,
351    stage: S
352}
353
354impl<T: SigningTranscript+Clone,S> MuSig<T,S> {
355    /// Iterates over public keys.
356    ///
357    /// If `require_reveal=true` then we count only public key that revealed their `R` values.
358    pub fn public_keys(&self, require_reveal: bool) -> impl Iterator<Item=&PublicKey> {
359        self.Rs.iter().filter_map( move |(pk,cor)| match cor {
360            CoR::Commit(_) => if require_reveal { None } else { Some(pk) },
361            CoR::Reveal(_) => Some(pk),
362            CoR::Cosigned { .. } => Some(pk),
363            CoR::Collect { .. } => Some(pk),
364        } )
365    }
366
367    /// Aggregate public key
368    ///
369    /// If `require_reveal=true` then we count only public key that revealed their `R` values.
370    fn compute_public_key(&self, require_reveal: bool) -> PublicKey {
371        let t0 = commit_public_keys(self.public_keys(require_reveal));
372        let point = self.public_keys(require_reveal).map( |pk|
373            compute_weighting(t0.clone(), pk) * pk.as_point()
374        ).sum();
375        PublicKey::from_point(point)
376    }
377
378    /// Aggregate public key given currently revealed `R` values
379    pub fn public_key(&self) -> PublicKey
380        {  self.compute_public_key(true)  }
381
382    /// Aggregate public key expected if all currently committed nodes fully participate
383    pub fn expected_public_key(&self) -> PublicKey
384        {  self.compute_public_key(false)  }
385
386    /// Iterator over the Rs values we actually use.
387    ///
388    /// Only compatable with `compute_public_key` when calling it with `require_reveal=true`
389    #[allow(non_snake_case)]
390    fn iter_Rs(&self) -> impl Iterator<Item = (&PublicKey,&RevealedPoints)> {
391        self.Rs.iter().filter_map( |(pk,cor)| match cor {
392            CoR::Commit(_) => None,
393            CoR::Reveal(reveal) => Some((pk,reveal)),
394            CoR::Cosigned { .. } => panic!("Internal error, compute_R called during cosigning phase."),
395            CoR::Collect { reveal, .. } => Some((pk,reveal)),
396        } )
397    }
398
399    /// Computes the delinearizing `R` values.
400    ///
401    /// Requires `self.t` be in its final state. 
402    /// Only compatable with `compute_public_key` when calling it with `require_reveal=true`
403    #[allow(non_snake_case)]
404    fn rewinder(&self) -> impl Fn(&PublicKey) -> [Scalar; REWINDS] {
405        let mut t0 = self.t.clone();
406        for (pk,R) in self.iter_Rs() {
407            t0.commit_point(b"pk-set", pk.as_compressed() );
408            for anR in R.0.iter() {
409                t0.commit_point(b"R",& anR.compress());
410            }
411        }
412        move |pk| {
413            let mut t1 = t0.clone();
414            t1.commit_point(b"pk-choice", pk.as_compressed() );
415            let mut a = ArrayVec::<Scalar, REWINDS>::new();
416            while !a.is_full() {
417                a.push( t1.challenge_scalar(b"R") );
418            }
419            a.into_inner().unwrap()
420        }
421    }
422
423    /// Computes final `R` value.
424    ///
425    /// Requires that `rewinder` be the result of `self.rewinder`.
426    /// Only compatable with `compute_public_key` when calling it with `require_reveal=true`
427    #[allow(non_snake_case)]
428    fn compute_R<F>(&self, rewinder: F) -> CompressedRistretto
429    where F: Fn(&PublicKey) -> [Scalar; REWINDS]
430    {
431        self.iter_Rs().map( |(pk,R)|
432            R.0.iter().zip(&rewinder(pk)).map(|(y,x)| x*y).sum::<RistrettoPoint>()
433        ).sum::<RistrettoPoint>().compress()
434    }
435}
436
437
438/// Initial cosigning stages during which transcript modification
439/// remains possible but not advisable.
440pub trait TranscriptStages {}
441impl<K> TranscriptStages for CommitStage<K> where K: Borrow<Keypair> {}
442impl<K> TranscriptStages for RevealStage<K> where K: Borrow<Keypair> {}
443impl<T,S> MuSig<T,S> 
444where T: SigningTranscript+Clone, S: TranscriptStages
445{
446    /// We permit extending the transcript whenever you like, so
447    /// that say the message may be agreed upon in parallel to the
448    /// commitments.  We advise against doing so however, as this
449    /// requires absolute faith in your random number generator,
450    /// usually `rand::thread_rng()`.
451    pub fn transcript(&mut self) -> &mut T { &mut self.t }
452}
453
454impl Keypair {
455    /// Initialize a multi-signature aka cosignature protocol run.
456    ///
457    /// We borrow the keypair here to discurage keeping too many
458    /// copies of the private key, but the `MuSig::new` method
459    /// can create an owned version, or use `Rc` or `Arc`.
460    #[allow(non_snake_case)]
461    pub fn musig<'k,T>(&'k self, t: T) -> MuSig<T,CommitStage<&'k Keypair>>
462    where T: SigningTranscript+Clone {
463        MuSig::new(self,t)
464    }
465}
466
467/// Commitment stage for cosigner's `R` values
468#[allow(non_snake_case)]
469pub struct CommitStage<K: Borrow<Keypair>> {
470    keypair: K,
471    r_me: [Scalar; REWINDS],
472    R_me: Reveal,
473}
474
475impl<K,T> MuSig<T,CommitStage<K>>
476where K: Borrow<Keypair>, T: SigningTranscript+Clone
477{
478    /// Initialize a multi-signature aka cosignature protocol run.
479    ///
480    /// We encourage borrowing the `Keypair` to minimize copies of
481    /// the private key, so we provide the `Keypair::musig` method
482    /// for the `K = &'k Keypair` case.  You could use `Rc` or `Arc`
483    /// with this `MuSig::new` method, or even pass in an owned copy.
484    #[allow(non_snake_case)]
485    pub fn new(keypair: K, t: T) -> MuSig<T,CommitStage<K>> {
486        let nonce = &keypair.borrow().secret.nonce;
487
488        let mut r_me = ArrayVec::<Scalar, REWINDS>::new();
489        for i in 0..REWINDS {
490            r_me.push( t.witness_scalar(b"MuSigWitness",&[nonce,&i.to_le_bytes()]) );
491        }
492        let r_me = r_me.into_inner().unwrap();
493        // context, message, nonce, but not &self.public.compressed
494
495        let B = constants::RISTRETTO_BASEPOINT_TABLE;
496        let R_me_points: ArrayVec<RistrettoPoint, REWINDS> = r_me.iter()
497            .map(|r_me_i| r_me_i * B).collect();
498        let R_me_points = RevealedPoints(R_me_points.into_inner().unwrap());
499        let R_me = R_me_points.to_reveal();
500
501        let mut Rs = BTreeMap::new();
502        Rs.insert(keypair.borrow().public, CoR::Reveal( R_me_points ));
503
504        let stage = CommitStage { keypair, r_me, R_me };
505        MuSig { t, Rs, stage, }
506    }
507
508    /// Our commitment to our `R` to send to all other cosigners
509    pub fn our_commitment(&self) -> Commitment {
510        self.stage.R_me.to_commitment().unwrap()
511    }
512
513    /// Add a new cosigner's public key and associated `R` bypassing our commitment phase.
514    pub fn add_their_commitment(&mut self, them: PublicKey, theirs: Commitment)
515     -> SignatureResult<()>
516    {
517        let theirs = CoR::Commit(theirs);
518        match self.Rs.entry(them) {
519            Entry::Vacant(v) => { v.insert(theirs); },
520            Entry::Occupied(o) =>
521                if o.get() != &theirs {
522                    let musig_stage = MultiSignatureStage::Commitment;
523                    return Err(SignatureError::MuSigInconsistent { musig_stage, duplicate: true, });
524                },
525        }
526        Ok(())
527    }
528
529    /// Commit to reveal phase transition.
530    #[allow(non_snake_case)]
531    pub fn reveal_stage(self) -> MuSig<T,RevealStage<K>> {
532        let MuSig { t, Rs, stage: CommitStage { keypair, r_me, R_me, }, } = self;
533        MuSig { t, Rs, stage: RevealStage { keypair, r_me, R_me, }, }
534    }
535}
536
537/// Reveal stage for cosigner's `R` values
538#[allow(non_snake_case)]
539pub struct RevealStage<K: Borrow<Keypair>> {
540    keypair: K,
541    r_me: [Scalar; REWINDS],
542    R_me: Reveal,
543}
544
545impl<K,T> MuSig<T,RevealStage<K>> 
546where K: Borrow<Keypair>, T: SigningTranscript+Clone
547{
548    /// Reveal our `R` contribution to send to all other cosigners
549    pub fn our_reveal(&self) -> &Reveal { &self.stage.R_me }
550
551    // TODO: Permit `add_their_reveal` and `add_trusted` in `CommitStage`
552    // using const generics, const fn, and replacing the `*Stage` types
553    // with some enum.
554
555    /// Include a revealed `R` value from a previously committed cosigner
556    pub fn add_their_reveal(&mut self, them: PublicKey, theirs: Reveal)
557     -> SignatureResult<()>
558    {
559        match self.Rs.entry(them) {
560            Entry::Vacant(_) => {
561                let musig_stage = MultiSignatureStage::Commitment;
562                Err(SignatureError::MuSigAbsent { musig_stage, })
563            },
564            Entry::Occupied(mut o) =>
565                o.get_mut().set_revealed(theirs),
566        }
567    }
568
569    /// Add a new cosigner's public key and associated `R` bypassing our
570    /// commitment phase.
571    ///
572    /// We implemented defenses that reduce the risks posed by this
573    /// method, but anyone who wishes provable security should heed
574    /// the advice below:
575    ///
576    /// Avoid using this due to the attack described in
577    /// "On the Provable Security of Two-Round Multi-Signatures" by
578    /// Manu Drijvers, Kasra Edalatnejad, Bryan Ford, and Gregory Neven
579    /// https://eprint.iacr.org/2018/417
580    /// Avoid using this for public keys held by networked devices
581    /// in particular.
582    ///
583    /// There are however limited scenarios in which using this appears
584    /// secure, primarily if the trusted device is (a) air gapped,
585    /// (b) stateful, and (c) infrequently used, via some constrained
586    /// channel like manually scanning QR code.  Almost all hardware
587    /// wallets designs fail (b), but non-hardware wallets fail (a),
588    /// with the middle ground being only something like Parity Signer.
589    /// Also, any public keys controlled by an organization likely
590    /// fail (c) too, making this only useful for individuals.
591    pub fn add_trusted(&mut self, them: PublicKey, theirs: Reveal)
592     -> SignatureResult<()>
593    {
594        let reveal = theirs.into_points() ?;
595        let theirs = CoR::Reveal(reveal);
596        match self.Rs.entry(them) {
597            Entry::Vacant(v) => { v.insert(theirs); },
598            Entry::Occupied(o) =>
599                if o.get() != &theirs {
600                    let musig_stage = MultiSignatureStage::Reveal;
601                    return Err(SignatureError::MuSigInconsistent { musig_stage, duplicate: true, });
602                },
603        }
604        Ok(())
605    }
606
607    /// Reveal to cosign phase transition.
608    #[allow(non_snake_case)]
609    pub fn cosign_stage(mut self) -> MuSig<T,CosignStage> {
610        self.t.proto_name(b"Schnorr-sig");
611
612        let pk = *self.public_key().as_compressed();
613        self.t.commit_point(b"sign:pk",&pk);
614
615        let rewinder = self.rewinder();
616        let rewinds = rewinder(&self.stage.keypair.borrow().public);
617        let R = self.compute_R(rewinder);
618        self.t.commit_point(b"sign:R",&R);
619
620        let t0 = commit_public_keys(self.public_keys(true));
621        let a_me = compute_weighting(t0, &self.stage.keypair.borrow().public);
622        let c = self.t.challenge_scalar(b"sign:c");  // context, message, A/public_key, R=rG
623
624        let mut s_me: Scalar = self.stage.r_me.iter().zip(&rewinds).map(|(y,x)| x*y).sum();
625        s_me += c * a_me * self.stage.keypair.borrow().secret.key;
626
627        zeroize::Zeroize::zeroize(&mut self.stage.r_me);
628
629        let MuSig { t, mut Rs, stage: RevealStage { .. }, } = self;
630        *(Rs.get_mut(&self.stage.keypair.borrow().public).expect("Rs known to contain this public; qed")) = CoR::Cosigned { s: s_me };
631        MuSig { t, Rs, stage: CosignStage { R, s_me }, }
632    }
633}
634
635/// Final cosigning stage collection
636#[allow(non_snake_case)]
637pub struct CosignStage {
638    /// Collective `R` value
639    R: CompressedRistretto,
640    /// Our `s` contribution
641    s_me: Scalar,
642}
643
644/// Cosignatures shared between cosigners during signing
645#[derive(Debug,Clone,Copy,PartialEq,Eq)]
646pub struct Cosignature(pub [u8; 32]);
647
648impl<T: SigningTranscript+Clone> MuSig<T,CosignStage> {
649    /// Reveals our signature contribution
650    pub fn our_cosignature(&self) -> Cosignature {
651        Cosignature(self.stage.s_me.to_bytes())
652    }
653
654    /// Include a cosignature from another cosigner
655    pub fn add_their_cosignature(&mut self, them: PublicKey, theirs: Cosignature)
656     -> SignatureResult<()>
657    {
658        let theirs = crate::scalar_from_canonical_bytes(theirs.0)
659            .ok_or(SignatureError::ScalarFormatError) ?;
660        match self.Rs.entry(them) {
661            Entry::Vacant(_) => {
662                    let musig_stage = MultiSignatureStage::Reveal;
663                    Err(SignatureError::MuSigAbsent { musig_stage, })
664                },
665            Entry::Occupied(mut o) => o.get_mut().set_cosigned(theirs)
666        }
667    }
668
669    /// Interate over the cosigners who successfully revaled and
670    /// later cosigned.
671    pub fn cosigned(&self) -> impl Iterator<Item=&PublicKey> {
672        self.Rs.iter().filter_map( |(pk,cor)| match cor {
673            CoR::Commit(_) => None,
674            CoR::Reveal(_) => None,
675            CoR::Cosigned { .. } => Some(pk),
676            CoR::Collect { .. } => panic!("Collect found in Cosign phase.")
677        } )
678    }
679
680    /// Interate over the possible cosigners who successfully committed
681    /// and revaled, but actually cosigned.
682    pub fn uncosigned(&self) -> impl Iterator<Item=&PublicKey> {
683        self.Rs.iter().filter_map( |(pk,cor)| match cor {
684            CoR::Commit(_) => None,
685            CoR::Reveal(_) => Some(pk),
686            CoR::Cosigned { .. } => None,
687            CoR::Collect { .. } => panic!("Collect found in Cosign phase."),
688        } )
689    }
690
691    /// Actually computes the cosignature
692    #[allow(non_snake_case)]
693    pub fn sign(&self) -> Option<Signature> {
694        // if self.uncosigned().all(|_| false) { return None; }  // TODO:  why does this fail?
695        if self.uncosigned().last().is_some() { return None; }
696        let s: Scalar = self.Rs.iter()
697            .filter_map( |(_pk,cor)| match cor {
698                CoR::Commit(_) => None,
699                CoR::Reveal(_) => panic!("Internal error, MuSig<T,CosignStage>::uncosigned broken."),
700                CoR::Cosigned { s, .. } => Some(s),
701                CoR::Collect { .. } => panic!("Collect found in Cosign phase."),
702            } ).sum();
703        Some(Signature { s, R: self.stage.R, })
704    }
705}
706
707
708/// Initialize a collector of cosignatures who does not themselves cosign.
709#[allow(non_snake_case)]
710pub fn collect_cosignatures<T: SigningTranscript+Clone>(mut t: T) -> MuSig<T,CollectStage> {
711    t.proto_name(b"Schnorr-sig");
712    MuSig { t, Rs: BTreeMap::new(), stage: CollectStage, }
713}
714
715/// Initial stage for cosignature collectors who do not themselves cosign.
716pub struct CollectStage;
717
718impl<T: SigningTranscript+Clone> MuSig<T,CollectStage> {
719    /// Adds revealed `R` and cosignature into a cosignature collector
720    #[allow(non_snake_case)]
721    pub fn add(&mut self, them: PublicKey, their_reveal: Reveal, their_cosignature: Cosignature)
722     -> SignatureResult<()>
723    {
724        let reveal = their_reveal.into_points() ?;
725        let s = crate::scalar_from_canonical_bytes(their_cosignature.0)
726            .ok_or(SignatureError::ScalarFormatError) ?;
727        let cor = CoR::Collect { reveal, s };
728
729        match self.Rs.entry(them) {
730            Entry::Vacant(v) => { v.insert(cor); },
731            Entry::Occupied(o) =>
732                if o.get() != &cor {
733                    let musig_stage = MultiSignatureStage::Reveal;
734                    return Err(SignatureError::MuSigInconsistent { musig_stage, duplicate: true, });
735                },
736        }
737        Ok(())
738    }
739
740    /// Actually computes the collected cosignature.
741    #[allow(non_snake_case)]
742    pub fn signature(mut self) -> Signature {
743        let pk = *self.public_key().as_compressed();
744        self.t.commit_point(b"sign:pk",&pk);
745
746        let R = self.compute_R(self.rewinder());
747
748        let s: Scalar = self.Rs.values().map(|cor| match cor {
749                CoR::Collect { s, .. } => s,
750                _ => panic!("Reached CollectStage from another stage"),
751            }).sum();
752        Signature { s, R, }
753    }
754}
755
756
757#[cfg(test)]
758mod tests {
759    #[cfg(feature = "alloc")]
760    use alloc::vec::Vec;
761
762    use super::*;
763
764    #[test]
765    fn aggregation_btreeemap_vs_slice() {
766        let mut vec: Vec<PublicKey> = (0..16).map(|_| SecretKey::generate().to_public()).collect();
767        let btm: BTreeMap<PublicKey,()> = vec.iter().map( |x| (x.clone(),()) ).collect();
768        debug_assert_eq!(
769            btm.public_key(),
770            aggregate_public_key_from_slice(vec.as_mut_slice()).unwrap().public_key()
771        );
772        // NLL aggregate_public_key_from_sorted_slice
773    }
774
775    #[test]
776    fn multi_signature() {
777        let keypairs: Vec<Keypair> = (0..16).map(|_| Keypair::generate()).collect();
778
779        let t = signing_context(b"multi-sig").bytes(b"We are legion!");
780        let mut commits: Vec<_> = keypairs.iter().map( |k| k.musig(t.clone()) ).collect();
781        for i in 0..commits.len() {
782        let r = commits[i].our_commitment();
783            for j in commits.iter_mut() {
784                assert!( j.add_their_commitment(keypairs[i].public.clone(),r)
785                    .is_ok() != (r == j.our_commitment()) );
786            }
787        }
788
789        let mut reveal_msgs: Vec<Reveal> = Vec::with_capacity(commits.len());
790        let mut reveals: Vec<_> = commits.drain(..).map( |c| c.reveal_stage() ).collect();
791        for i in 0..reveals.len() {
792            let r = reveals[i].our_reveal().clone();
793            for j in reveals.iter_mut() {
794                j.add_their_reveal(keypairs[i].public.clone(),r.clone()).unwrap();
795            }
796            reveal_msgs.push(r);
797        }
798        let pk = reveals[0].public_key();
799
800        let mut cosign_msgs: Vec<Cosignature> = Vec::with_capacity(reveals.len());
801        let mut cosigns: Vec<_> = reveals.drain(..).map( |c| { assert_eq!(pk, c.public_key()); c.cosign_stage() } ).collect();
802        for i in 0..cosigns.len() {
803            assert_eq!(pk, cosigns[i].public_key());
804            let r = cosigns[i].our_cosignature();
805            for j in cosigns.iter_mut() {
806                j.add_their_cosignature(keypairs[i].public.clone(),r).unwrap();
807            }
808            cosign_msgs.push(r);
809            assert_eq!(pk, cosigns[i].public_key());
810        }
811
812        // let signature = cosigns[0].sign().unwrap();
813        let mut c = collect_cosignatures(t.clone());
814        for i in 0..cosigns.len() {
815            c.add(keypairs[i].public.clone(),reveal_msgs[i].clone(),cosign_msgs[i].clone()).unwrap();
816        }
817        let signature = c.signature();
818
819        assert!( pk.verify(t,&signature).is_ok() );
820        for i in 0..cosigns.len() {
821            assert_eq!(pk, cosigns[i].public_key());
822            assert_eq!(signature, cosigns[i].sign().unwrap());
823        }
824    }
825}