1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
use crate::{
    fun::{
        self, derive_nonce,
        digest::{generic_array::typenum::U32, Digest},
        g,
        hash::{AddTag, HashAdd, Tagged},
        marker::*,
        nonce::{NonceChallengeBundle, NonceGen},
        s, Point, Scalar, Slice, XOnly,
    },
    KeyPair, Signature,
};

/// An instance of a [BIP-340] style Schnorr signature scheme.
///
/// Each instance is defined by its:
/// - `G`: Public generator (usually [`G`])
/// - `challenge_hash`: The hash function instance that is used to produce the [_Fiat-Shamir_] challenge.
/// - `nonce_gen`: The [`NonceGen`] used to hash the signing inputs (and perhaps additional randomness) to produce the secret nonce.
///
/// [_Fiat-Shamir_]: https://en.wikipedia.org/wiki/Fiat%E2%80%93Shamir_heuristic
/// [`G`]: crate::fun::G
/// [`NonceGen<H>`]: crate::fun::hash::NonceGen
/// [BIP-340]: https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki
#[derive(Clone)]
pub struct Schnorr<CH, NG = (), GT = BasePoint> {
    /// The generator point the Schnorr signature scheme is defined with.
    G: Point<GT>,
    /// The [`NonceGen`] and NonceChalengeBundlesh.
    ///
    /// [`NonceGen`]: crate::nonce::NonceGen
    nonce_challenge_bundle: NonceChallengeBundle<CH, NG>,
    application_tag: Option<[u8; 64]>,
}

/// Describes the kind of messages that will be signed with a [`Schnorr`] instance.
///
/// [`Schnorr`]: crate::Schnorr
#[derive(Debug, Clone, Copy)]
pub enum MessageKind {
    /// Sign a pre-hashed message.
    /// This is used by [BIP-341] to authorize transactions.
    /// If you also want to sign hashed messages in your applicatin you should use a [_tagged hash_] specific to your application.
    ///
    /// [BIP-341]: https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki
    /// [_tagged hash_]: crate::fun::hash::Tagged
    Prehashed,
    /// Sign an ordinary variable length message.
    Plain {
        /// You must provide a tag to separate signatures from your application
        /// from other applications. If two [`Schnorr`] instances are created
        /// with a different `tag` then a signature valid for one will never be
        /// valid for the other. It will also never be valid for `Prehashed`
        /// instances. The specific method of domain separation used is
        /// described [here].
        ///
        /// [here]: https://github.com/sipa/bips/issues/207#issuecomment-673681901
        tag: &'static str,
    },
}

impl<H: Digest<OutputSize = U32> + Tagged> Schnorr<H, (), BasePoint> {
    /// Create a new instance that doesn't
    ///
    /// Creates a `Schnorr` instance to verifying signatures of a particular [`MessageKind`].
    /// The instance will use the standard value of [`G`].
    ///
    /// # Examples
    ///
    /// ```
    /// use schnorr_fun::{MessageKind, Schnorr};
    /// // An instance that can verify Bitcoin Taproot transactions
    /// let taproot_schnorr = Schnorr::<sha2::Sha256>::verify_only(MessageKind::Prehashed);
    /// // An instance for verifying transactions in your application
    /// let myapp_schnorr = Schnorr::<sha2::Sha256>::verify_only(MessageKind::Plain { tag: "myapp" });
    /// ```
    /// [`MessageKind`]: crate::MessageKind
    /// [`G`]: crate::fun::G
    pub fn verify_only(msgkind: MessageKind) -> Self {
        Self::new((), msgkind)
    }
}

impl<CH, NG> Schnorr<CH, NG, BasePoint>
where
    CH: Digest<OutputSize = U32> + Tagged,
    NG: AddTag,
{
    /// Creates a instance capable of signing and verifying.
    ///
    ///
    /// # Examples
    /// ```
    /// use rand::rngs::ThreadRng;
    /// use schnorr_fun::{
    ///     nonce::{Deterministic, GlobalRng, Synthetic},
    ///     MessageKind, Schnorr,
    /// };
    /// use sha2::Sha256;
    /// // Use synthetic nonces (preferred)
    /// let nonce_gen = Synthetic::<Sha256, GlobalRng<ThreadRng>>::default();
    /// // Use deterministic nonces.
    /// let nonce_gen = Deterministic::<Sha256>::default();
    /// // Sign pre-hashed messges as in BIP-341.
    /// let schnorr = Schnorr::<Sha256, _>::new(nonce_gen.clone(), MessageKind::Prehashed);
    /// // Sign ordinary messages in your own application.
    /// let schnorr = Schnorr::<Sha256, _>::new(nonce_gen, MessageKind::Plain { tag: "my-app" });
    /// ```
    pub fn new(nonce_gen: NG, msgkind: MessageKind) -> Self {
        let mut nonce_challenge_bundle = NonceChallengeBundle {
            challenge_hash: CH::default(),
            nonce_gen,
        }
        .add_protocol_tag("BIP0340");

        let application_tag = match msgkind {
            MessageKind::Prehashed => None,
            MessageKind::Plain { tag } => {
                assert!(tag.len() <= 64);
                // Only add the application tag to nonce gen since we will be
                // separately adding the tag to the challenge hash in self.challenge()
                nonce_challenge_bundle.nonce_gen =
                    nonce_challenge_bundle.nonce_gen.add_application_tag(tag);
                let mut application_tag = [0u8; 64];
                application_tag[..tag.len()].copy_from_slice(tag.as_bytes());
                Some(application_tag)
            }
        };

        Self {
            G: fun::G.clone(),
            nonce_challenge_bundle,
            application_tag,
        }
    }
}

impl<NG, CH, GT> Schnorr<CH, NG, GT>
where
    CH: Digest<OutputSize = U32> + Clone,
    NG: NonceGen,
{
    /// Sign a message using a secret key and a particular nonce derivation scheme.
    ///
    /// # Examples
    ///
    /// ```
    /// use schnorr_fun::{
    ///     fun::{marker::*, Scalar},
    ///     MessageKind,
    /// };
    /// # let schnorr = schnorr_fun::test_instance!();
    /// let keypair = schnorr.new_keypair(Scalar::random(&mut rand::thread_rng()));
    /// let message = b"Chancellor on brink of second bailout for banks"
    ///     .as_ref()
    ///     .mark::<Public>();
    /// let signature = schnorr.sign(&keypair, message);
    /// assert!(schnorr.verify(&keypair.verification_key(), message, &signature));
    /// ```
    pub fn sign(&self, keypair: &KeyPair, message: Slice<'_, impl Secrecy>) -> Signature {
        let (x, X) = keypair.as_tuple();

        let mut r = derive_nonce!(
            nonce_gen => self.nonce_gen(),
            secret => x,
            public => [X, message]
        );

        let R = XOnly::from_scalar_mul(&self.G, &mut r);
        let c = self.challenge(&R, X, message);
        let s = s!(r + c * x).mark::<Public>();

        Signature { R, s }
    }

    /// Returns the [`NonceGen`] instance being used to genreate nonces.
    ///
    /// [`NonceGen`]: crate::nonce::NonceGen
    pub fn nonce_gen(&self) -> &NG {
        &self.nonce_challenge_bundle.nonce_gen
    }
}

impl<NG, CH: Digest<OutputSize = U32> + Clone, GT> Schnorr<CH, NG, GT> {
    /// Returns the generator point being used for the scheme.
    pub fn G(&self) -> &Point<GT> {
        &self.G
    }

    /// Returns the challenge hash being used to sign/verify signatures
    pub fn challenge_hash(&self) -> CH {
        self.nonce_challenge_bundle.challenge_hash.clone()
    }
    /// Converts a non-zero scalar to a key-pair by interpreting it as a secret key.
    ///
    /// **The secret key in the resulting key is not guaranteed to be the same
    /// as the input**. For half the input values the result will be the
    /// negation of it. This happens because the corresponding [`Point`] may not
    /// have an y-coordinate that is even (see [`EvenY`])
    ///
    /// [`Point`]: crate::fun::Point
    /// [`EvenY`]: crate::fun::marker::EvenY
    pub fn new_keypair(&self, mut sk: Scalar) -> KeyPair {
        let pk = XOnly::from_scalar_mul(&self.G, &mut sk);
        KeyPair { sk, pk }
    }

    /// Produces the Fiat-Shamir challenge for a Schnorr signature in the form specified by BIP-340.
    ///
    /// Concretely computes the hash `H(R || X || m)`.
    ///
    /// # Example
    ///
    /// Here's how you could use this to roll your own signatures.
    ///
    /// ```
    /// use schnorr_fun::{
    ///     fun::{marker::*, s, Scalar, XOnly},
    ///     Schnorr, Signature,
    /// };
    /// # let schnorr = schnorr_fun::test_instance!();
    /// let message = b"we rolled our own sign!".as_ref().mark::<Public>();
    /// let keypair = schnorr.new_keypair(Scalar::random(&mut rand::thread_rng()));
    /// let mut r = Scalar::random(&mut rand::thread_rng());
    /// let R = XOnly::from_scalar_mul(schnorr.G(), &mut r);
    /// let challenge = schnorr.challenge(&R, keypair.public_key(), message);
    /// let s = s!(r + challenge * { keypair.secret_key() });
    /// let signature = Signature { R, s };
    /// assert!(schnorr.verify(&keypair.verification_key(), message, &signature));
    /// ```
    pub fn challenge<S: Secrecy>(&self, R: &XOnly, X: &XOnly, m: Slice<'_, S>) -> Scalar<S, Zero> {
        let hash = self.nonce_challenge_bundle.challenge_hash.clone();
        let mut hash = hash.add(R).add(X);

        if let Some(tag) = self.application_tag {
            hash.update(&tag[..]);
        }

        let challenge = Scalar::from_hash(hash.add(&m));

        challenge
            // Since the challenge pre-image is adversarially controlled we
            // conservatively allow for it to be zero
            .mark::<Zero>()
            // The resulting challenge should take the secrecy of the message
            .mark::<S>()
    }

    /// Verifies a signature on a message under a given public key.  Note that a full
    /// `Point<EvenY,..>` is passed in rather than a `XOnly` because it's more efficient
    /// for repeated verification (where as `XOnly` is more efficient for repeated
    /// signing).
    ///
    /// For an example see the [Synopsis](crate#synopsis)
    #[must_use]
    pub fn verify(
        &self,
        public_key: &Point<EvenY, impl Secrecy>,
        message: Slice<'_, impl Secrecy>,
        signature: &Signature<impl Secrecy>,
    ) -> bool {
        let X = public_key;
        let (R, s) = signature.as_tuple();
        let c = self.challenge(R, &X.to_xonly(), message);
        let R_tmp = g!(s * self.G - c * X).mark::<Normal>();
        R_tmp == *R
    }

    /// _Anticipates_ a Schnorr signature given the nonce `R` that will be used ahead of time.
    /// Deterministically returns the group element that corresponds to the scalar value of the
    /// signature. i.e `R + c * X`
    pub fn anticipate_signature(
        &self,
        X: &Point<EvenY, impl Secrecy>,
        R: &Point<EvenY, impl Secrecy>,
        m: Slice<'_, impl Secrecy>,
    ) -> Point<Jacobian, Public, Zero> {
        let c = self.challenge(&R.to_xonly(), &X.to_xonly(), m);
        g!(R + c * X)
    }
}

#[cfg(test)]
pub mod test {
    use fun::nonce::Deterministic;

    use super::*;
    use crate::fun::TEST_SOUNDNESS;
    crate::fun::test_plus_wasm! {

        fn anticipated_signature_on_should_correspond_to_actual_signature() {
            for _ in 0..TEST_SOUNDNESS {
                let schnorr = crate::test_instance!();
                let keypair = schnorr.new_keypair(Scalar::random(&mut rand::thread_rng()));
                let msg = b"Chancellor on brink of second bailout for banks".as_ref().mark::<Public>();
                let signature = schnorr.sign(&keypair,msg);
                let anticipated_signature = schnorr.anticipate_signature(
                    &keypair.verification_key(),
                    &signature.R.to_point(),
                    msg,
                );

                assert_eq!(
                    anticipated_signature,
                    g!(signature.s * schnorr.G),
                    "should anticipate the same value as actual signature"
                )
            }
        }

        fn sign_deterministic() {
            let schnorr = crate::test_instance!();
            for _ in 0..TEST_SOUNDNESS {
                let keypair_1 = schnorr.new_keypair(Scalar::random(&mut rand::thread_rng()));
                let keypair_2 = schnorr.new_keypair(Scalar::random(&mut rand::thread_rng()));
                let msg_atkdwn = b"attack at dawn".as_ref().mark::<Public>();
                let msg_rtrtnoon = b"retreat at noon".as_ref().mark::<Public>();
                let signature_1 = schnorr.sign(&keypair_1, msg_atkdwn);
                let signature_2 = schnorr.sign(&keypair_1, msg_atkdwn);
                let signature_3 = schnorr.sign(&keypair_1, msg_rtrtnoon);
                let signature_4 = schnorr.sign(&keypair_2, msg_atkdwn);

                assert!(schnorr.verify(
                    &keypair_1.verification_key(),
                    msg_atkdwn,
                    &signature_1
                ));
                assert_eq!(signature_1, signature_2);
                assert_ne!(signature_3.R, signature_1.R);
                assert_ne!(signature_1.R, signature_4.R);
            }
        }

        fn deterministic_nonces_for_different_message_kinds() {
            use sha2::Sha256;
            let schnorr_1 = Schnorr::<Sha256,_>::new(Deterministic::<Sha256>::default(), MessageKind::Prehashed);
            let schnorr_2 = Schnorr::<Sha256,_>::new(Deterministic::<Sha256>::default(), MessageKind::Plain { tag: "two" });
            let schnorr_3 = Schnorr::<Sha256,_>::new(Deterministic::<Sha256>::default(), MessageKind::Plain { tag: "three" });
            let x =  Scalar::from_str("18451f9e08af9530814243e202a4a977130e672079f5c14dcf15bd4dee723072").unwrap();
            let keypair = schnorr_1.new_keypair(x);
            let message = b"foo".as_ref().mark::<Public>();
            assert_ne!(schnorr_1.sign(&keypair, message).R, schnorr_2.sign(&keypair, message).R);
            assert_ne!(schnorr_1.sign(&keypair, message).R, schnorr_3.sign(&keypair, message).R);

            // make sure deterministic signatures don't change
            use core::str::FromStr;
            assert_eq!(schnorr_1.sign(&keypair, message), Signature::<Public>::from_str("fe9e5d0319d5d221988d6fd7fe1c4bedd2fb4465f592f1002f461503332a266977bb4a0b00c00d07072c796212cbea0957ebaaa5139143761c45d997ebe36cbe").unwrap());
            assert_eq!(schnorr_2.sign(&keypair, message), Signature::<Public>::from_str("6cad3863f4d01494ce4c40f3422e4916c616356d730bc4ffe33e386f038b328ba1dc9621e626992c2612f33cdb35f4be4badc464c1f4bf3de15517e7aedcf615").unwrap());
        }
    }
}