schnorrkel/
vrf.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 of a Verifiable Random Function (VRF) using Ristretto points and Schnorr DLEQ proofs.
11//!
12//! *Warning*  We warn that our VRF construction supports malleable
13//! outputs via the `*malleable*` methods.  These are insecure when
14//! used in  conjunction with our HDKD provided in dervie.rs.
15//! Attackers could translate malleable VRF outputs from one soft subkey
16//! to another soft subkey, gaining early knowledge of the VRF output.
17//! We suggest using either non-malleable VRFs or using implicit
18//! certificates instead of HDKD when using VRFs.
19//!
20//! We model the VRF on "Making NSEC5 Practical for DNSSEC" by
21//! Dimitrios Papadopoulos, Duane Wessels, Shumon Huque, Moni Naor,
22//! Jan Včelák, Leonid Rezyin, andd Sharon Goldberg.
23//! https://eprint.iacr.org/2017/099.pdf
24//! We note the V(X)EdDSA signature scheme by Trevor Perrin at
25//! https://www.signal.org/docs/specifications/xeddsa/#vxeddsa
26//! is almost identical to the NSEC5 construction, except that
27//! V(X)Ed25519 fails to be a VRF by giving signers multiple
28//! outputs per input.  There is another even later variant at
29//! https://datatracker.ietf.org/doc/draft-irtf-cfrg-vrf/
30//!
31//! We support individual signers merging numerous VRF outputs created
32//! with the same keypair, which follows the "DLEQ Proofs" and "Batching
33//! the Proofs" sections of "Privacy Pass - The Math" by Alex Davidson,
34//! https://new.blog.cloudflare.com/privacy-pass-the-math/#dleqproofs
35//! and "Privacy Pass: Bypassing Internet Challenges Anonymously"
36//! by Alex Davidson, Ian Goldberg, Nick Sullivan, George Tankersley,
37//! and Filippo Valsorda.
38//! https://www.petsymposium.org/2018/files/papers/issue3/popets-2018-0026.pdf
39//!
40//! As noted there, our merging technique's soundness appeals to
41//! Theorem 3.17 on page 74 of Ryan Henry's PhD thesis
42//! "Efficient Zero-Knowledge Proofs and Applications"
43//! https://uwspace.uwaterloo.ca/bitstream/handle/10012/8621/Henry_Ryan.pdf
44//! See also the attack on Peng and Bao’s batch proof protocol in
45//! "Batch Proofs of Partial Knowledge" by Ryan Henry and Ian Goldberg
46//! https://www.cypherpunks.ca/~iang/pubs/batchzkp-acns.pdf
47//!
48//! We might reasonably ask if the VRF signer's public key should
49//! really be hashed when creating the scalars in `vrfs_merge*`.
50//! After all, there is no similar requirement when the values being
51//! hashed are BLS public keys in say
52//! https://crypto.stanford.edu/~dabo/pubs/papers/BLSmultisig.html
53//! In fact, we expect the public key could be dropped both in
54//! Privacy Pass' case, due to using randomness in the messages,
55//! and in the VRF case, provided the message depends upon shared
56//! randomness created after the public key.  Yet, there are VRF
57//! applications outside these two cases, and DLEQ proof applications
58//! where the points are not even hashes.  At minimum, we expect
59//! hashing the public key prevents malicious signers from choosing
60//! their key to cancel out the blinding of a particular point,
61//! which might become important in a some anonymity applications.
62//! In any case, there is no cost to hashing the public key for VRF
63//! applications, but important such an approach cannot yield a
64//! verifiable shuffle.
65//! TODO: Explain better!
66//!
67//! We also implement verifier side batching analogous to batched
68//! verification of Schnorr signatures, but note this requires an
69//! extra curve point, which enlarges the VRF proofs from 64 bytes
70//! to 96 bytes.  We provide `shorten_*` methods to produce the
71//! non-batchable proof from the batchable proof because doing so
72//! is an inherent part of the batch verification anyways.
73//! TODO: Security arguments!
74//!
75//! We do not provide DLEQ proofs optimized for the same signer using
76//! multiple public keys because such constructions sound more the
77//! domain of zero-knowledge proof libraries.
78
79use core::borrow::Borrow;
80
81#[cfg(feature = "alloc")]
82use core::iter::once;
83
84#[cfg(feature = "alloc")]
85use alloc::{boxed::Box, vec::Vec};
86
87use curve25519_dalek::constants;
88use curve25519_dalek::ristretto::{CompressedRistretto, RistrettoPoint};
89use curve25519_dalek::scalar::Scalar;
90use curve25519_dalek::traits::{IsIdentity}; // Identity
91#[cfg(feature = "alloc")]
92use curve25519_dalek::traits::{MultiscalarMul, VartimeMultiscalarMul};
93
94use merlin::Transcript;
95
96use super::*;
97use crate::context::SigningTranscript;
98use crate::points::RistrettoBoth;
99// use crate::errors::SignatureError;
100
101/// Value for `kusama` paramater to `*dleq*` methods that yields the VRF for kusama.
102///
103/// Greg Maxwell argue that nonce generation should hash all parameters
104/// that challenge generation does in https://moderncrypto.org/mail-archive/curves/2020/001012.html
105/// We support this position in principle as a defense in depth against
106/// attacks that cause missalignment between the public and secret keys.
107///
108/// We did this for signatures but not for the VRF deployed in Kusama.
109/// We cannot justify add this defense to the deployed VRF because
110/// several layers already address this attack, including merlin's
111/// witnesses and that signers normally only sign VRF outputs once.
112///
113/// We suggest using Greg Maxwell's trick if you use a stand alone DLEQ
114/// proof though, meaning call `*dleq*` methods with `kusama: false`.
115///
116/// see: https://github.com/w3f/schnorrkel/issues/53
117// We currently lack tests for the case when this is false, but you can
118// rerun cargo test with this set to false for that.
119pub const KUSAMA_VRF: bool = true;
120
121/// Length of VRF output.
122pub const VRF_PREOUT_LENGTH: usize = 32;
123
124/// Length of the short VRF proof which lacks support for batch verification.
125pub const VRF_PROOF_LENGTH: usize = 64;
126
127/// Length of the longer VRF proof which supports batch verification.
128pub const VRF_PROOF_BATCHABLE_LENGTH: usize = 96;
129
130/// `SigningTranscript` helper trait that manages VRF output malleability.
131///
132/// In short, `VRFSigningTranscript` acts like a default argument
133/// `malleabe : bool = false` for every mathod that uses it instead of
134/// `SigningTranscript`.
135pub trait VRFSigningTranscript {
136    /// Real underlying `SigningTranscript`
137    type T: SigningTranscript;
138    /// Return the underlying `SigningTranscript` after addressing
139    /// VRF output malleability, usually by making it non-malleable,
140    fn transcript_with_malleability_addressed(self, publickey: &PublicKey) -> Self::T;
141}
142
143impl<T> VRFSigningTranscript for T
144where
145    T: SigningTranscript,
146{
147    type T = T;
148    #[inline(always)]
149    fn transcript_with_malleability_addressed(mut self, publickey: &PublicKey) -> T {
150        self.commit_point(b"vrf-nm-pk", publickey.as_compressed());
151        self
152    }
153}
154
155/// VRF SigningTranscript for malleable VRF outputs.
156///
157/// *Warning*  We caution that malleable VRF outputs are insecure when
158/// used in conjunction with HDKD, as provided in dervie.rs. 
159/// Attackers could translate malleable VRF outputs from one soft subkey 
160/// to another soft subkey, gaining early knowledge of the VRF output.
161/// We think most VRF applications for which HDKH sounds suitable
162/// benefit from using implicit certificates instead of HDKD anyways,
163/// which should also be secure in combination with HDKD.
164/// We always use non-malleable VRF inputs in our convenience methods.
165#[derive(Clone)]
166#[rustfmt::skip]
167pub struct Malleable<T: SigningTranscript>(pub T);
168impl<T> VRFSigningTranscript for Malleable<T>
169where
170    T: SigningTranscript,
171{
172    type T = T;
173    #[inline(always)]
174    fn transcript_with_malleability_addressed(self, _publickey: &PublicKey) -> T {
175        self.0
176    }
177}
178
179/// Create a malleable VRF input point by hashing a transcript to a point.
180///
181/// *Warning*  We caution that malleable VRF inputs are insecure when
182/// used in conjunction with HDKD, as provided in dervie.rs.
183/// Attackers could translate malleable VRF outputs from one soft subkey
184/// to another soft subkey, gaining early knowledge of the VRF output.
185/// We think most VRF applications for which HDKH sounds suitable
186/// benefit from using implicit certificates instead of HDKD anyways,
187/// which should also be secure in combination with HDKH.
188/// We always use non-malleable VRF inputs in our convenience methods.
189pub fn vrf_malleable_hash<T: SigningTranscript>(mut t: T) -> RistrettoBoth {
190    let mut b = [0u8; 64];
191    t.challenge_bytes(b"VRFHash", &mut b);
192    RistrettoBoth::from_point(RistrettoPoint::from_uniform_bytes(&b))
193}
194
195impl PublicKey {
196    /// Create a non-malleable VRF input point by hashing a transcript to a point.
197    pub fn vrf_hash<T>(&self, t: T) -> RistrettoBoth
198    where
199        T: VRFSigningTranscript,
200    {
201        vrf_malleable_hash(t.transcript_with_malleability_addressed(self))
202    }
203
204    /// Pair a non-malleable VRF output with the hash of the given transcript.
205    pub fn vrf_attach_hash<T>(&self, output: VRFPreOut, t: T) -> SignatureResult<VRFInOut>
206    where
207        T: VRFSigningTranscript,
208    {
209        output.attach_input_hash(self, t)
210    }
211}
212
213/// VRF pre-output, possibly unverified.
214#[deprecated(since = "0.9.2", note = "Please use VRFPreOut instead of VRFOutput")]
215pub type VRFOutput = VRFPreOut;
216
217/// VRF pre-output, possibly unverified.
218///
219/// Internally, we keep both `RistrettoPoint` and `CompressedRistretto`
220/// forms using `RistrettoBoth`.
221///
222/// We'd actually love to statically distinguish here between inputs
223/// and outputs, as well as whether outputs were verified, but doing
224/// so would disrupt our general purpose DLEQ proof mechanism, so
225/// users must be responsible for this themselves.  We do however
226/// consume by value in actual output methods, and do not implement
227/// `Copy`, as a reminder that VRF outputs should only be used once
228/// and should be checked before usage.
229#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
230pub struct VRFPreOut(pub [u8; PUBLIC_KEY_LENGTH]);
231
232impl VRFPreOut {
233    const DESCRIPTION: &'static str =
234        "A Ristretto Schnorr VRF output represented as a 32-byte Ristretto compressed point";
235
236    /// Convert this VRF output to a byte array.
237    #[inline]
238    pub fn to_bytes(&self) -> [u8; VRF_PREOUT_LENGTH] {
239        self.0
240    }
241
242    /// View this secret key as a byte array.
243    #[inline]
244    pub fn as_bytes(&self) -> &[u8; VRF_PREOUT_LENGTH] {
245        &self.0
246    }
247
248    /// Construct a `VRFPreOut` from a slice of bytes.
249    #[inline]
250    pub fn from_bytes(bytes: &[u8]) -> SignatureResult<VRFPreOut> {
251        if bytes.len() != VRF_PREOUT_LENGTH {
252            return Err(SignatureError::BytesLengthError {
253                name: "VRFPreOut",
254                description: VRFPreOut::DESCRIPTION,
255                length: VRF_PREOUT_LENGTH,
256            });
257        }
258        let mut bits: [u8; 32] = [0u8; 32];
259        bits.copy_from_slice(&bytes[..32]);
260        Ok(VRFPreOut(bits))
261    }
262
263    /// Pair a non-malleable VRF output with the hash of the given transcript.
264    pub fn attach_input_hash<T>(&self, public: &PublicKey, t: T) -> SignatureResult<VRFInOut>
265    where
266        T: VRFSigningTranscript,
267    {
268        let input = public.vrf_hash(t);
269        let output = RistrettoBoth::from_bytes_ser("VRFPreOut", VRFPreOut::DESCRIPTION, &self.0)?;
270        if output.as_point().is_identity() {
271            return Err(SignatureError::PointDecompressionError);
272        }
273        Ok(VRFInOut { input, output })
274    }
275}
276
277serde_boilerplate!(VRFPreOut);
278
279/// VRF input and output paired together, possibly unverified.
280///
281/// Internally, we keep both `RistrettoPoint` and `CompressedRistretto`
282/// forms using `RistrettoBoth`.
283#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
284pub struct VRFInOut {
285    /// VRF input point
286    pub input: RistrettoBoth,
287    /// VRF output point
288    pub output: RistrettoBoth,
289}
290
291impl SecretKey {
292    /// Evaluate the VRF-like multiplication on an uncompressed point,
293    /// probably not useful in this form.
294    pub fn vrf_create_from_point(&self, input: RistrettoBoth) -> VRFInOut {
295        let output = RistrettoBoth::from_point(self.key * input.as_point());
296        VRFInOut { input, output }
297    }
298
299    /// Evaluate the VRF-like multiplication on a compressed point,
300    /// useful for proving key exchanges, OPRFs, or sequential VRFs.
301    ///
302    /// We caution that such protocols could provide signing oracles
303    /// and note that `vrf_create_from_point` cannot check for
304    /// problematic inputs like `attach_input_hash` does.
305    pub fn vrf_create_from_compressed_point(&self, input: &VRFPreOut) -> SignatureResult<VRFInOut> {
306        let input = RistrettoBoth::from_compressed(CompressedRistretto(input.0))?;
307        Ok(self.vrf_create_from_point(input))
308    }
309}
310
311impl Keypair {
312    /// Evaluate the VRF on the given transcript.
313    pub fn vrf_create_hash<T: VRFSigningTranscript>(&self, t: T) -> VRFInOut {
314        self.secret.vrf_create_from_point(self.public.vrf_hash(t))
315    }
316}
317
318impl VRFInOut {
319    /// VRF output point bytes for serialization.
320    pub fn as_output_bytes(&self) -> &[u8; 32] {
321        self.output.as_compressed().as_bytes()
322    }
323
324    /// VRF output point bytes for serialization.
325    pub fn to_preout(&self) -> VRFPreOut {
326        VRFPreOut(self.output.as_compressed().to_bytes())
327    }
328
329    /// Commit VRF input and output to a transcript.
330    ///
331    /// We commit both the input and output to provide the 2Hash-DH
332    /// construction from Theorem 2 on page 32 in appendix C of
333    /// ["Ouroboros Praos: An adaptively-secure, semi-synchronous proof-of-stake blockchain"](https://eprint.iacr.org/2017/573.pdf)
334    /// by Bernardo David, Peter Gazi, Aggelos Kiayias, and Alexander Russell.
335    ///
336    /// We use this construction both for the VRF usage methods
337    /// `VRFInOut::make_*` as well as for signer side batching.
338    pub fn commit<T: SigningTranscript>(&self, t: &mut T) {
339        t.commit_point(b"vrf-in", self.input.as_compressed());
340        t.commit_point(b"vrf-out", self.output.as_compressed());
341    }
342
343    /// Raw bytes output from the VRF.
344    ///
345    /// If you are not the signer then you must verify the VRF before calling this method.
346    ///
347    /// If called with distinct contexts then outputs should be independent.
348    ///
349    /// We incorporate both the input and output to provide the 2Hash-DH
350    /// construction from Theorem 2 on page 32 in appendix C of
351    /// ["Ouroboros Praos: An adaptively-secure, semi-synchronous proof-of-stake blockchain"](https://eprint.iacr.org/2017/573.pdf)
352    /// by Bernardo David, Peter Gazi, Aggelos Kiayias, and Alexander Russell.
353    pub fn make_bytes<B: Default + AsMut<[u8]>>(&self, context: &[u8]) -> B {
354        let mut t = Transcript::new(b"VRFResult");
355        t.append_message(b"", context);
356        self.commit(&mut t);
357        let mut seed = B::default();
358        t.challenge_bytes(b"", seed.as_mut());
359        seed
360    }
361
362    /// VRF output converted into any `SeedableRng`.
363    ///
364    /// If you are not the signer then you must verify the VRF before calling this method.
365    ///
366    /// We expect most users would prefer the less generic `VRFInOut::make_chacharng` method.
367    pub fn make_rng<R: rand_core::SeedableRng>(&self, context: &[u8]) -> R {
368        R::from_seed(self.make_bytes::<R::Seed>(context))
369    }
370
371    /// VRF output converted into a `ChaChaRng`.
372    ///
373    /// If you are not the signer then you must verify the VRF before calling this method.
374    ///
375    /// If called with distinct contexts then outputs should be independent.
376    /// Independent output streams are available via `ChaChaRng::set_stream` too.
377    ///
378    /// We incorporate both the input and output to provide the 2Hash-DH
379    /// construction from Theorem 2 on page 32 in appendix C of
380    /// ["Ouroboros Praos: An adaptively-secure, semi-synchronous proof-of-stake blockchain"](https://eprint.iacr.org/2017/573.pdf)
381    /// by Bernardo David, Peter Gazi, Aggelos Kiayias, and Alexander Russell.
382    #[cfg(feature = "rand_chacha")]
383    pub fn make_chacharng(&self, context: &[u8]) -> rand_chacha::ChaChaRng {
384        self.make_rng::<::rand_chacha::ChaChaRng>(context)
385    }
386
387    /// VRF output converted into Merlin's Keccek based `Rng`.
388    ///
389    /// If you are not the signer then you must verify the VRF before calling this method.
390    ///
391    /// We think this might be marginally slower than `ChaChaRng`
392    /// when considerable output is required, but it should reduce
393    /// the final linked binary size slightly, and improves domain
394    /// separation.
395    #[inline(always)]
396    pub fn make_merlin_rng(&self, context: &[u8]) -> merlin::TranscriptRng {
397        // Very insecure hack except for our commit_witness_bytes below
398        struct ZeroFakeRng;
399        #[rustfmt::skip]
400        impl rand_core::RngCore for ZeroFakeRng {
401            fn next_u32(&mut self) -> u32 {  panic!()  }
402            fn next_u64(&mut self) -> u64 {  panic!()  }
403            fn fill_bytes(&mut self, dest: &mut [u8]) {
404                for i in dest.iter_mut() {  *i = 0;  }
405            }
406            fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> {
407                self.fill_bytes(dest);
408                Ok(())
409            }
410        }
411        impl rand_core::CryptoRng for ZeroFakeRng {}
412
413        let mut t = Transcript::new(b"VRFResult");
414        t.append_message(b"", context);
415        self.commit(&mut t);
416        t.build_rng().finalize(&mut ZeroFakeRng)
417    }
418}
419
420fn challenge_scalar_128<T: SigningTranscript>(mut t: T) -> Scalar {
421    let mut s = [0u8; 16];
422    t.challenge_bytes(b"", &mut s);
423    Scalar::from(u128::from_le_bytes(s))
424}
425
426impl PublicKey {
427    /// Merge VRF input and output pairs from the same signer,
428    /// using variable time arithmetic
429    ///
430    /// You should use `vartime=true` when verifying VRF proofs batched
431    /// by the singer.  You could usually use `vartime=true` even when
432    /// producing proofs, provided the set being signed is not secret.
433    ///
434    /// There is sadly no constant time 128 bit multiplication in dalek,
435    /// making `vartime=false` somewhat slower than necessary.  It should
436    /// only impact signers in niche scenarios however, so the slower
437    /// variant should normally be unnecessary.
438    ///
439    /// Panics if given an empty points list.
440    ///
441    /// TODO: Add constant time 128 bit batched multiplication to dalek.
442    /// TODO: Is rand_chacha's `gen::<u128>()` standardizable enough to
443    /// prefer it over merlin for the output?
444    #[rustfmt::skip]
445    pub fn vrfs_merge<B>(&self, ps: &[B], vartime: bool) -> VRFInOut
446    where
447        B: Borrow<VRFInOut>,
448    {
449        assert!(!ps.is_empty());
450        let mut t = merlin::Transcript::new(b"MergeVRFs");
451        t.commit_point(b"vrf:pk", self.as_compressed());
452        for p in ps.iter() {
453            p.borrow().commit(&mut t);
454        }
455
456        let zf = || ps.iter().map(|p| {
457            let mut t0 = t.clone();
458            p.borrow().commit(&mut t0);
459            challenge_scalar_128(t0)
460        });
461        #[cfg(feature = "alloc")]
462        let zs: Vec<Scalar> = zf().collect();
463        #[cfg(feature = "alloc")]
464        let zf = || zs.iter();
465
466        // We need actual fns here because closures cannot easily take
467        // closures as arguments, due to Rust lacking polymorphic
468        // closures but giving all closures unique types.
469        fn get_input(p: &VRFInOut) -> &RistrettoPoint { p.input.as_point() }
470        fn get_output(p: &VRFInOut) -> &RistrettoPoint { p.output.as_point() }
471        #[cfg(feature = "alloc")]
472        let go = |io: fn(p: &VRFInOut) -> &RistrettoPoint| {
473            let ps = ps.iter().map( |p| io(p.borrow()) );
474            RistrettoBoth::from_point(if vartime {
475                RistrettoPoint::vartime_multiscalar_mul(zf(), ps)
476            } else {
477                RistrettoPoint::multiscalar_mul(zf(), ps)
478            })
479        };
480        #[cfg(not(feature = "alloc"))]
481        let go = |io: fn(p: &VRFInOut) -> &RistrettoPoint| {
482            let _ = vartime; // ignore unused variable
483            use curve25519_dalek::traits::Identity;
484            let mut acc = RistrettoPoint::identity();
485            for (z,p) in zf().zip(ps) {
486                acc += z * io(p.borrow());
487            }
488            RistrettoBoth::from_point(acc)
489        };
490
491        let input = go( get_input );
492        let output = go( get_output );
493        VRFInOut { input, output }
494    }
495}
496
497/// Short proof of correctness for associated VRF output,
498/// for which no batched verification works.
499#[derive(Debug, Clone, PartialEq, Eq)] // PartialOrd, Ord, Hash
500pub struct VRFProof {
501    /// Challenge
502    c: Scalar,
503    /// Schnorr proof
504    s: Scalar,
505}
506
507impl VRFProof {
508    const DESCRIPTION : &'static str = "A Ristretto Schnorr VRF proof without batch verification support, which consists of two scalars, making it 64 bytes.";
509
510    /// Convert this `VRFProof` to a byte array.
511    #[inline]
512    pub fn to_bytes(&self) -> [u8; VRF_PROOF_LENGTH] {
513        let mut bytes = [0u8; VRF_PROOF_LENGTH];
514
515        bytes[..32].copy_from_slice(&self.c.as_bytes()[..]);
516        bytes[32..].copy_from_slice(&self.s.as_bytes()[..]);
517        bytes
518    }
519
520    /// Construct a `VRFProof` from a slice of bytes.
521    #[inline]
522    pub fn from_bytes(bytes: &[u8]) -> SignatureResult<VRFProof> {
523        if bytes.len() != VRF_PROOF_LENGTH {
524            return Err(SignatureError::BytesLengthError {
525                name: "VRFProof",
526                description: VRFProof::DESCRIPTION,
527                length: VRF_PROOF_LENGTH,
528            });
529        }
530        let mut c: [u8; 32] = [0u8; 32];
531        let mut s: [u8; 32] = [0u8; 32];
532
533        c.copy_from_slice(&bytes[..32]);
534        s.copy_from_slice(&bytes[32..]);
535
536        let c = crate::scalar_from_canonical_bytes(c).ok_or(SignatureError::ScalarFormatError)?;
537        let s = crate::scalar_from_canonical_bytes(s).ok_or(SignatureError::ScalarFormatError)?;
538        Ok(VRFProof { c, s })
539    }
540}
541
542serde_boilerplate!(VRFProof);
543
544/// Longer proof of correctness for associated VRF output,
545/// which supports batching.
546#[derive(Debug, Clone, PartialEq, Eq)] // PartialOrd, Ord, Hash
547#[allow(non_snake_case)]
548pub struct VRFProofBatchable {
549    /// Our nonce R = r G to permit batching the first verification equation
550    R: CompressedRistretto,
551    /// Our input hashed and raised to r to permit batching the second verification equation
552    Hr: CompressedRistretto,
553    /// Schnorr proof
554    s: Scalar,
555}
556
557impl VRFProofBatchable {
558    const DESCRIPTION : &'static str = "A Ristretto Schnorr VRF proof that supports batch verification, which consists of two Ristretto compressed points and one scalar, making it 96 bytes.";
559
560    /// Convert this `VRFProofBatchable` to a byte array.
561    #[allow(non_snake_case)]
562    #[inline]
563    pub fn to_bytes(&self) -> [u8; VRF_PROOF_BATCHABLE_LENGTH] {
564        let mut bytes = [0u8; VRF_PROOF_BATCHABLE_LENGTH];
565
566        bytes[0..32].copy_from_slice(&self.R.as_bytes()[..]);
567        bytes[32..64].copy_from_slice(&self.Hr.as_bytes()[..]);
568        bytes[64..96].copy_from_slice(&self.s.as_bytes()[..]);
569        bytes
570    }
571
572    /// Construct a `VRFProofBatchable` from a slice of bytes.
573    #[allow(non_snake_case)]
574    #[inline]
575    pub fn from_bytes(bytes: &[u8]) -> SignatureResult<VRFProofBatchable> {
576        if bytes.len() != VRF_PROOF_BATCHABLE_LENGTH {
577            return Err(SignatureError::BytesLengthError {
578                name: "VRFProofBatchable",
579                description: VRFProofBatchable::DESCRIPTION,
580                length: VRF_PROOF_BATCHABLE_LENGTH,
581            });
582        }
583        let mut R: [u8; 32] = [0u8; 32];
584        let mut Hr: [u8; 32] = [0u8; 32];
585        let mut s: [u8; 32] = [0u8; 32];
586
587        R.copy_from_slice(&bytes[0..32]);
588        Hr.copy_from_slice(&bytes[32..64]);
589        s.copy_from_slice(&bytes[64..96]);
590
591        let s = crate::scalar_from_canonical_bytes(s).ok_or(SignatureError::ScalarFormatError)?;
592        Ok(VRFProofBatchable { R: CompressedRistretto(R), Hr: CompressedRistretto(Hr), s })
593    }
594
595    /// Return the shortened `VRFProof` for retransmitting in not batched situations
596    #[allow(non_snake_case)]
597    #[rustfmt::skip]
598    pub fn shorten_dleq<T>(&self, mut t: T, public: &PublicKey, p: &VRFInOut, kusama: bool) -> VRFProof
599    where T: SigningTranscript,
600    {
601        t.proto_name(b"DLEQProof");
602        // t.commit_point(b"vrf:g",constants::RISTRETTO_BASEPOINT_TABLE.basepoint().compress());
603        t.commit_point(b"vrf:h", p.input.as_compressed());
604        if !kusama {  t.commit_point(b"vrf:pk", public.as_compressed());  }
605
606        t.commit_point(b"vrf:R=g^r", &self.R);
607        t.commit_point(b"vrf:h^r", &self.Hr);
608
609        if kusama {  t.commit_point(b"vrf:pk", public.as_compressed());  }
610        t.commit_point(b"vrf:h^sk", p.output.as_compressed());
611
612        VRFProof {
613            c: t.challenge_scalar(b"prove"), // context, message, A/public_key, R=rG
614            s: self.s,
615        }
616    }
617
618    /// Return the shortened `VRFProof` for retransmitting in non-batched situations
619    ///
620    /// TODO: Avoid the error path here by avoiding decompressing,
621    /// either locally here, or more likely by decompressing
622    /// `VRFPreOut` in deserialization.
623    pub fn shorten_vrf<T>(
624        &self,
625        public: &PublicKey,
626        t: T,
627        out: &VRFPreOut,
628    ) -> SignatureResult<VRFProof>
629    where
630        T: VRFSigningTranscript,
631    {
632        let p = out.attach_input_hash(public, t)?; // Avoidable errors if decompressed earlier
633        let t0 = Transcript::new(b"VRF"); // We have context in t and another hear confuses batching
634        Ok(self.shorten_dleq(t0, public, &p, KUSAMA_VRF))
635    }
636}
637
638serde_boilerplate!(VRFProofBatchable);
639
640impl Keypair {
641    /// Produce DLEQ proof.
642    ///
643    /// We assume the `VRFInOut` paramater has been computed correctly
644    /// by multiplying every input point by `self.secret`, like by
645    /// using one of the `vrf_create_*` methods on `SecretKey`.
646    /// If so, we produce a proof that this multiplication was done correctly.
647    #[allow(non_snake_case)]
648    #[rustfmt::skip]
649    pub fn dleq_proove<T>(&self, mut t: T, p: &VRFInOut, kusama: bool) -> (VRFProof, VRFProofBatchable)
650    where
651        T: SigningTranscript,
652    {
653        t.proto_name(b"DLEQProof");
654        // t.commit_point(b"vrf:g",constants::RISTRETTO_BASEPOINT_TABLE.basepoint().compress());
655        t.commit_point(b"vrf:h", p.input.as_compressed());
656        if !kusama {  t.commit_point(b"vrf:pk", self.public.as_compressed());  }
657
658        // We compute R after adding pk and all h.
659        let mut r = t.witness_scalar(b"proving\x000",&[&self.secret.nonce]);
660        let R = (&r * constants::RISTRETTO_BASEPOINT_TABLE).compress();
661        t.commit_point(b"vrf:R=g^r", &R);
662
663        let Hr = (r * p.input.as_point()).compress();
664        t.commit_point(b"vrf:h^r", &Hr);
665
666        if kusama {  t.commit_point(b"vrf:pk", self.public.as_compressed());  }
667        // We add h^sk last to save an allocation if we ever need to hash multiple h together.
668        t.commit_point(b"vrf:h^sk", p.output.as_compressed());
669
670        let c = t.challenge_scalar(b"prove"); // context, message, A/public_key, R=rG
671        let s = r - c * self.secret.key;
672
673        zeroize::Zeroize::zeroize(&mut r);
674
675        (VRFProof { c, s }, VRFProofBatchable { R, Hr, s })
676    }
677
678    /// Run VRF on one single input transcript, producing the outpus
679    /// and corresponding short proof.
680    ///
681    /// There are schemes like Ouroboros Praos in which nodes evaluate
682    /// VRFs repeatedly until they win some contest.  In these case,
683    /// you should probably use vrf_sign_n_check to gain access to the
684    /// `VRFInOut` from `vrf_create_hash` first, and then avoid computing
685    /// the proof whenever you do not win.
686    pub fn vrf_sign<T>(&self, t: T) -> (VRFInOut, VRFProof, VRFProofBatchable)
687    where
688        T: VRFSigningTranscript,
689    {
690        self.vrf_sign_extra(t, Transcript::new(b"VRF"))
691        // We have context in t and another hear confuses batching
692    }
693
694    /// Run VRF on one single input transcript and an extra message transcript,
695    /// producing the outpus and corresponding short proof.
696    pub fn vrf_sign_extra<T, E>(&self, t: T, extra: E) -> (VRFInOut, VRFProof, VRFProofBatchable)
697    where
698        T: VRFSigningTranscript,
699        E: SigningTranscript,
700    {
701        let p = self.vrf_create_hash(t);
702        let (proof, proof_batchable) = self.dleq_proove(extra, &p, KUSAMA_VRF);
703        (p, proof, proof_batchable)
704    }
705
706    /// Run VRF on one single input transcript, producing the outpus
707    /// and corresponding short proof only if the result first passes
708    /// some check.
709    ///
710    /// There are schemes like Ouroboros Praos in which nodes evaluate
711    /// VRFs repeatedly until they win some contest.  In these case,
712    /// you might use this function to short circuit computing the full
713    /// proof.
714    pub fn vrf_sign_after_check<T, F>(
715        &self,
716        t: T,
717        mut check: F,
718    ) -> Option<(VRFInOut, VRFProof, VRFProofBatchable)>
719    where
720        T: VRFSigningTranscript,
721        F: FnMut(&VRFInOut) -> bool,
722    {
723        self.vrf_sign_extra_after_check(t, |io| {
724            if check(io) {
725                Some(Transcript::new(b"VRF"))
726            } else {
727                None
728            }
729        })
730    }
731
732    /// Run VRF on one single input transcript, producing the outpus
733    /// and corresponding short proof only if the result first passes
734    /// some check, which itself returns an extra message transcript.
735    pub fn vrf_sign_extra_after_check<T, E, F>(
736        &self,
737        t: T,
738        mut check: F,
739    ) -> Option<(VRFInOut, VRFProof, VRFProofBatchable)>
740    where
741        T: VRFSigningTranscript,
742        E: SigningTranscript,
743        F: FnMut(&VRFInOut) -> Option<E>,
744    {
745        let p = self.vrf_create_hash(t);
746        let extra = check(&p)?;
747        let (proof, proof_batchable) = self.dleq_proove(extra, &p, KUSAMA_VRF);
748        Some((p, proof, proof_batchable))
749    }
750
751    /// Run VRF on several input transcripts, producing their outputs
752    /// and a common short proof.
753    ///
754    /// We merge the VRF outputs using variable time arithmetic, so
755    /// if even the hash of the message being signed is sensitive then
756    /// you might reimplement some constant time variant.
757    #[cfg(feature = "alloc")]
758    pub fn vrfs_sign<T, I>(&self, ts: I) -> (Box<[VRFInOut]>, VRFProof, VRFProofBatchable)
759    where
760        T: VRFSigningTranscript,
761        I: IntoIterator<Item = T>,
762    {
763        self.vrfs_sign_extra(ts, Transcript::new(b"VRF"))
764    }
765
766    /// Run VRF on several input transcripts and an extra message transcript,
767    /// producing their outputs and a common short proof.
768    ///
769    /// We merge the VRF outputs using variable time arithmetic, so
770    /// if even the hash of the message being signed is sensitive then
771    /// you might reimplement some constant time variant.
772    #[cfg(feature = "alloc")]
773    pub fn vrfs_sign_extra<T, E, I>(
774        &self,
775        ts: I,
776        extra: E,
777    ) -> (Box<[VRFInOut]>, VRFProof, VRFProofBatchable)
778    where
779        T: VRFSigningTranscript,
780        E: SigningTranscript,
781        I: IntoIterator<Item = T>,
782    {
783        let ps = ts.into_iter().map(|t| self.vrf_create_hash(t)).collect::<Vec<VRFInOut>>();
784        let p = self.public.vrfs_merge(&ps, true);
785        let (proof, proof_batchable) = self.dleq_proove(extra, &p, KUSAMA_VRF);
786        (ps.into_boxed_slice(), proof, proof_batchable)
787    }
788}
789
790impl PublicKey {
791    /// Verify DLEQ proof that `p.output = s * p.input` where `self`
792    /// `s` times the basepoint.
793    ///
794    /// We return an enlarged `VRFProofBatchable` instead of just true,
795    /// so that verifiers can forward batchable proofs.
796    ///
797    /// In principle, one might provide "blindly verifiable" VRFs that
798    /// avoid requiring `self` here, but naively such constructions
799    /// risk the same flaws as DLEQ based blind signatures, and this
800    /// version exploits the slightly faster basepoint arithmetic.
801    #[allow(non_snake_case)]
802    #[rustfmt::skip]
803    pub fn dleq_verify<T>(
804        &self,
805        mut t: T,
806        p: &VRFInOut,
807        proof: &VRFProof,
808        kusama: bool,
809    ) -> SignatureResult<VRFProofBatchable>
810    where
811        T: SigningTranscript,
812    {
813        t.proto_name(b"DLEQProof");
814        // t.commit_point(b"vrf:g",constants::RISTRETTO_BASEPOINT_TABLE.basepoint().compress());
815        t.commit_point(b"vrf:h", p.input.as_compressed());
816        if !kusama {  t.commit_point(b"vrf:pk", self.as_compressed());  }
817
818        // We recompute R aka u from the proof
819        // let R = (&proof.c * self.as_point()) + (&proof.s * &constants::RISTRETTO_BASEPOINT_TABLE);
820        let R = RistrettoPoint::vartime_double_scalar_mul_basepoint(
821            &proof.c,
822            self.as_point(),
823            &proof.s,
824        ).compress();
825        t.commit_point(b"vrf:R=g^r", &R);
826
827        // We also recompute h^r aka u using the proof
828        #[cfg(not(feature = "alloc"))]
829        let Hr = (&proof.c * p.output.as_point()) + (&proof.s * p.input.as_point());
830
831        // TODO: Verify if this is actually faster using benchmarks
832        #[cfg(feature = "alloc")]
833        let Hr = RistrettoPoint::vartime_multiscalar_mul(
834            &[proof.c, proof.s],
835            &[*p.output.as_point(), *p.input.as_point()],
836        );
837
838        let Hr = Hr.compress();
839        t.commit_point(b"vrf:h^r", &Hr);
840
841        if kusama {  t.commit_point(b"vrf:pk", self.as_compressed());  }
842        // We add h^sk last to save an allocation if we ever need to hash multiple h together.
843        t.commit_point(b"vrf:h^sk", p.output.as_compressed());
844
845        // We need not check that h^pk lies on the curve because Ristretto ensures this.
846        let VRFProof { c, s } = *proof;
847        if c == t.challenge_scalar(b"prove") {
848            Ok(VRFProofBatchable { R, Hr, s }) // Scalar: Copy ?!?
849        } else {
850            Err(SignatureError::EquationFalse)
851        }
852    }
853
854    /// Verify VRF proof for one single input transcript and corresponding output.
855    pub fn vrf_verify<T: VRFSigningTranscript>(
856        &self,
857        t: T,
858        out: &VRFPreOut,
859        proof: &VRFProof,
860    ) -> SignatureResult<(VRFInOut, VRFProofBatchable)> {
861        self.vrf_verify_extra(t, out, proof, Transcript::new(b"VRF"))
862    }
863
864    /// Verify VRF proof for one single input transcript and corresponding output.
865    pub fn vrf_verify_extra<T, E>(
866        &self,
867        t: T,
868        out: &VRFPreOut,
869        proof: &VRFProof,
870        extra: E,
871    ) -> SignatureResult<(VRFInOut, VRFProofBatchable)>
872    where
873        T: VRFSigningTranscript,
874        E: SigningTranscript,
875    {
876        let p = out.attach_input_hash(self, t)?;
877        let proof_batchable = self.dleq_verify(extra, &p, proof, KUSAMA_VRF)?;
878        Ok((p, proof_batchable))
879    }
880
881    /// Verify a common VRF short proof for several input transcripts and corresponding outputs.
882    #[cfg(feature = "alloc")]
883    pub fn vrfs_verify<T, I, O>(
884        &self,
885        transcripts: I,
886        outs: &[O],
887        proof: &VRFProof,
888    ) -> SignatureResult<(Box<[VRFInOut]>, VRFProofBatchable)>
889    where
890        T: VRFSigningTranscript,
891        I: IntoIterator<Item = T>,
892        O: Borrow<VRFPreOut>,
893    {
894        self.vrfs_verify_extra(transcripts, outs, proof, Transcript::new(b"VRF"))
895    }
896
897    /// Verify a common VRF short proof for several input transcripts and corresponding outputs.
898    #[cfg(feature = "alloc")]
899    #[rustfmt::skip]
900    pub fn vrfs_verify_extra<T,E,I,O>(
901        &self,
902        transcripts: I,
903        outs: &[O],
904        proof: &VRFProof,
905        extra: E,
906    ) -> SignatureResult<(Box<[VRFInOut]>, VRFProofBatchable)>
907    where
908        T: VRFSigningTranscript,
909        E: SigningTranscript,
910        I: IntoIterator<Item = T>,
911        O: Borrow<VRFPreOut>,
912    {
913        let mut ts = transcripts.into_iter();
914        let ps = ts.by_ref().zip(outs)
915            .map(|(t, out)| out.borrow().attach_input_hash(self,t))
916            .collect::<SignatureResult<Vec<VRFInOut>>>()?;
917        assert!(ts.next().is_none(), "Too few VRF outputs for VRF inputs.");
918        assert!(
919            ps.len() == outs.len(),
920            "Too few VRF inputs for VRF outputs."
921        );
922        let p = self.vrfs_merge(&ps[..],true);
923        let proof_batchable = self.dleq_verify(extra, &p, proof, KUSAMA_VRF)?;
924        Ok((ps.into_boxed_slice(), proof_batchable))
925    }
926}
927
928/// Batch verify DLEQ proofs where the public keys were held by
929/// different parties.
930///
931/// We first reconstruct the `c`s present in the `VRFProof`s but absent
932/// in the `VRFProofBatchable`s, using `shorten_dleq`.  We then verify
933/// the `R` and `Hr` components of the `VRFProofBatchable`s using the
934/// two equations a normal verification uses to discover them.
935/// We do this by delinearizing both verification equations with
936/// random numbers.
937///
938/// TODO: Assess when the two verification equations should be
939/// combined, presumably by benchmarking both forms.  At smaller batch
940/// sizes then we should clearly benefit form the combined form, but
941/// any combination doubles the scalar by scalar multiplications
942/// and hashing, so large enough batch verifications should favor two
943/// separate calls.
944#[cfg(feature = "alloc")]
945#[allow(non_snake_case)]
946#[rustfmt::skip]
947pub fn dleq_verify_batch(
948    ps: &[VRFInOut],
949    proofs: &[VRFProofBatchable],
950    public_keys: &[PublicKey],
951    kusama: bool,
952) -> SignatureResult<()> {
953    const ASSERT_MESSAGE: &str = "The number of messages/transcripts / input points, output points, proofs, and public keys must be equal.";
954    assert!(ps.len() == proofs.len(), "{}", ASSERT_MESSAGE);
955    assert!(proofs.len() == public_keys.len(), "{}", ASSERT_MESSAGE);
956
957    // Use a random number generator keyed by the public keys, the
958    // inout and putput points, and the system random number generator.
959    let mut csprng = {
960        let mut t = Transcript::new(b"VB-RNG");
961        for (pk,p) in public_keys.iter().zip(ps) {
962            t.commit_point(b"",pk.as_compressed());
963            p.commit(&mut t);
964        }
965        t.build_rng().finalize(&mut getrandom_or_panic())
966    };
967
968    // Select a random 128-bit scalar for each signature.
969    // We may represent these as scalars because we use
970    // variable time 256 bit multiplication below.
971    let rnd_128bit_scalar = |_| {
972        let mut r = [0u8; 16];
973        csprng.fill_bytes(&mut r);
974        Scalar::from(u128::from_le_bytes(r))
975    };
976    let zz: Vec<Scalar> = proofs.iter().map(rnd_128bit_scalar).collect();
977
978    let z_s: Vec<Scalar> = zz.iter().zip(proofs)
979        .map(|(z, proof)| z * proof.s)
980        .collect();
981
982    // Compute the basepoint coefficient, ∑ s[i] z[i] (mod l)
983    let B_coefficient: Scalar = z_s.iter().sum();
984
985    let t0 = Transcript::new(b"VRF");
986    let z_c: Vec<Scalar> = zz.iter().enumerate()
987        .map( |(i, z)| z * proofs[i].shorten_dleq(t0.clone(), &public_keys[i], &ps[i], kusama).c )
988        .collect();
989
990    // Compute (∑ z[i] s[i] (mod l)) B + ∑ (z[i] c[i] (mod l)) A[i] - ∑ z[i] R[i] = 0
991    let mut b = RistrettoPoint::optional_multiscalar_mul(
992        zz.iter().map(|z| -z)
993            .chain(z_c.iter().cloned())
994            .chain(once(B_coefficient)),
995        proofs.iter().map(|proof| proof.R.decompress())
996            .chain(public_keys.iter().map(|pk| Some(*pk.as_point())))
997            .chain(once(Some(constants::RISTRETTO_BASEPOINT_POINT))),
998    ).map(|id| id.is_identity()).unwrap_or(false);
999
1000    // Compute (∑ z[i] s[i] (mod l)) Input[i] + ∑ (z[i] c[i] (mod l)) Output[i] - ∑ z[i] Hr[i] = 0
1001    b &= RistrettoPoint::optional_multiscalar_mul(
1002        zz.iter().map(|z| -z)
1003            .chain(z_c)
1004            .chain(z_s),
1005        proofs.iter().map(|proof| proof.Hr.decompress())
1006            .chain(ps.iter().map(|p| Some(*p.output.as_point())))
1007            .chain(ps.iter().map(|p| Some(*p.input.as_point()))),
1008    ).map(|id| id.is_identity()).unwrap_or(false);
1009
1010    if b { Ok(()) } else { Err(SignatureError::EquationFalse) }
1011}
1012
1013/// Batch verify VRFs by different signers
1014///
1015///
1016#[cfg(feature = "alloc")]
1017pub fn vrf_verify_batch<T, I>(
1018    transcripts: I,
1019    outs: &[VRFPreOut],
1020    proofs: &[VRFProofBatchable],
1021    publickeys: &[PublicKey],
1022) -> SignatureResult<Box<[VRFInOut]>>
1023where
1024    T: VRFSigningTranscript,
1025    I: IntoIterator<Item = T>,
1026{
1027    let mut ts = transcripts.into_iter();
1028    let ps = ts
1029        .by_ref()
1030        .zip(publickeys)
1031        .zip(outs)
1032        .map(|((t, pk), out)| out.attach_input_hash(pk, t))
1033        .collect::<SignatureResult<Vec<VRFInOut>>>()?;
1034    assert!(ts.next().is_none(), "Too few VRF outputs for VRF inputs.");
1035    assert!(ps.len() == outs.len(), "Too few VRF inputs for VRF outputs.");
1036    if dleq_verify_batch(&ps[..], proofs, publickeys, KUSAMA_VRF).is_ok() {
1037        Ok(ps.into_boxed_slice())
1038    } else {
1039        Err(SignatureError::EquationFalse)
1040    }
1041}
1042
1043#[cfg(test)]
1044mod tests {
1045    #[cfg(feature = "alloc")]
1046    use alloc::vec::Vec;
1047
1048    use super::*;
1049
1050    #[cfg(feature = "getrandom")]
1051    #[test]
1052    fn vrf_single() {
1053        let mut csprng = rand_core::OsRng;
1054
1055        let keypair1 = Keypair::generate_with(&mut csprng);
1056
1057        let ctx = signing_context(b"yo!");
1058        let msg = b"meow";
1059        let (io1, proof1, proof1batchable) = keypair1.vrf_sign(ctx.bytes(msg));
1060        let out1 = &io1.to_preout();
1061        assert_eq!(
1062            proof1,
1063            proof1batchable.shorten_vrf(&keypair1.public, ctx.bytes(msg), &out1).unwrap(),
1064            "Oops `shorten_vrf` failed"
1065        );
1066        let (io1too, proof1too) = keypair1
1067            .public
1068            .vrf_verify(ctx.bytes(msg), &out1, &proof1)
1069            .expect("Correct VRF verification failed!");
1070        assert_eq!(io1too, io1, "Output differs between signing and verification!");
1071        assert_eq!(
1072            proof1batchable, proof1too,
1073            "VRF verification yielded incorrect batchable proof"
1074        );
1075        assert_eq!(keypair1.vrf_sign(ctx.bytes(msg)).0, io1, "Rerunning VRF gave different output");
1076
1077        assert!(
1078            keypair1.public.vrf_verify(ctx.bytes(b"not meow"), &out1, &proof1).is_err(),
1079            "VRF verification with incorrect message passed!"
1080        );
1081
1082        let keypair2 = Keypair::generate_with(&mut csprng);
1083        assert!(
1084            keypair2.public.vrf_verify(ctx.bytes(msg), &out1, &proof1).is_err(),
1085            "VRF verification with incorrect signer passed!"
1086        );
1087    }
1088
1089    #[cfg(feature = "getrandom")]
1090    #[test]
1091    fn vrf_malleable() {
1092        let mut csprng = rand_core::OsRng;
1093
1094        let keypair1 = Keypair::generate_with(&mut csprng);
1095
1096        let ctx = signing_context(b"yo!");
1097        let msg = b"meow";
1098        let (io1, proof1, proof1batchable) = keypair1.vrf_sign(Malleable(ctx.bytes(msg)));
1099        let out1 = &io1.to_preout();
1100        assert_eq!(
1101            proof1,
1102            proof1batchable
1103                .shorten_vrf(&keypair1.public, Malleable(ctx.bytes(msg)), &out1)
1104                .unwrap(),
1105            "Oops `shorten_vrf` failed"
1106        );
1107        let (io1too, proof1too) = keypair1
1108            .public
1109            .vrf_verify(Malleable(ctx.bytes(msg)), &out1, &proof1)
1110            .expect("Correct VRF verification failed!");
1111        assert_eq!(io1too, io1, "Output differs between signing and verification!");
1112        assert_eq!(
1113            proof1batchable, proof1too,
1114            "VRF verification yielded incorrect batchable proof"
1115        );
1116        assert_eq!(
1117            keypair1.vrf_sign(Malleable(ctx.bytes(msg))).0,
1118            io1,
1119            "Rerunning VRF gave different output"
1120        );
1121        assert!(
1122            keypair1
1123                .public
1124                .vrf_verify(Malleable(ctx.bytes(b"not meow")), &out1, &proof1)
1125                .is_err(),
1126            "VRF verification with incorrect message passed!"
1127        );
1128
1129        let keypair2 = Keypair::generate_with(&mut csprng);
1130        assert!(
1131            keypair2.public.vrf_verify(Malleable(ctx.bytes(msg)), &out1, &proof1).is_err(),
1132            "VRF verification with incorrect signer passed!"
1133        );
1134        let (io2, _proof2, _proof2batchable) = keypair2.vrf_sign(Malleable(ctx.bytes(msg)));
1135        let out2 = &io2.to_preout();
1136
1137        // Verified key exchange, aka sequential two party VRF.
1138        let t0 = Transcript::new(b"VRF");
1139        let io21 = keypair2.secret.vrf_create_from_compressed_point(out1).unwrap();
1140        let proofs21 = keypair2.dleq_proove(t0.clone(), &io21, KUSAMA_VRF);
1141        let io12 = keypair1.secret.vrf_create_from_compressed_point(out2).unwrap();
1142        let proofs12 = keypair1.dleq_proove(t0.clone(), &io12, KUSAMA_VRF);
1143        assert_eq!(io12.output, io21.output, "Sequential two-party VRF failed");
1144        assert_eq!(
1145            proofs21.0,
1146            proofs21.1.shorten_dleq(t0.clone(), &keypair2.public, &io21, KUSAMA_VRF),
1147            "Oops `shorten_dleq` failed"
1148        );
1149        assert_eq!(
1150            proofs12.0,
1151            proofs12.1.shorten_dleq(t0.clone(), &keypair1.public, &io12, KUSAMA_VRF),
1152            "Oops `shorten_dleq` failed"
1153        );
1154        assert!(keypair1.public.dleq_verify(t0.clone(), &io12, &proofs12.0, KUSAMA_VRF).is_ok());
1155        assert!(keypair2.public.dleq_verify(t0.clone(), &io21, &proofs21.0, KUSAMA_VRF).is_ok());
1156    }
1157
1158    #[cfg(feature = "alloc")]
1159    #[test]
1160    fn vrfs_merged_and_batched() {
1161        let mut csprng = rand_core::OsRng;
1162        let keypairs: Vec<Keypair> = (0..4).map(|_| Keypair::generate_with(&mut csprng)).collect();
1163
1164        let ctx = signing_context(b"yo!");
1165        let messages: [&[u8; 4]; 2] = [b"meow", b"woof"];
1166        let ts = || messages.iter().map(|m| ctx.bytes(*m));
1167
1168        let ios_n_proofs = keypairs.iter().map(|k| k.vrfs_sign(ts())).collect::<Vec<(
1169            Box<[VRFInOut]>,
1170            VRFProof,
1171            VRFProofBatchable,
1172        )>>();
1173
1174        for (k, (ios, proof, proof_batchable)) in keypairs.iter().zip(&ios_n_proofs) {
1175            let outs = ios.iter().map(|io| io.to_preout()).collect::<Vec<VRFPreOut>>();
1176            let (ios_too, proof_too) = k
1177                .public
1178                .vrfs_verify(ts(), &outs, &proof)
1179                .expect("Valid VRF output verification failed!");
1180            assert_eq!(ios_too, *ios, "Output differs between signing and verification!");
1181            assert_eq!(proof_too, *proof_batchable, "Returning batchable proof failed!");
1182        }
1183        for (k, (ios, proof, _proof_batchable)) in keypairs.iter().zip(&ios_n_proofs) {
1184            let outs = ios.iter().rev().map(|io| io.to_preout()).collect::<Vec<VRFPreOut>>();
1185            assert!(
1186                k.public.vrfs_verify(ts(), &outs, &proof).is_err(),
1187                "Incorrect VRF output verification passed!"
1188            );
1189        }
1190        for (k, (ios, proof, _proof_batchable)) in keypairs.iter().rev().zip(&ios_n_proofs) {
1191            let outs = ios.iter().map(|io| io.to_preout()).collect::<Vec<VRFPreOut>>();
1192            assert!(
1193                k.public.vrfs_verify(ts(), &outs, &proof).is_err(),
1194                "VRF output verification by a different signer passed!"
1195            );
1196        }
1197
1198        let mut ios = keypairs
1199            .iter()
1200            .enumerate()
1201            .map(|(i, keypair)| keypair.public.vrfs_merge(&ios_n_proofs[i].0, true))
1202            .collect::<Vec<VRFInOut>>();
1203
1204        let mut proofs = ios_n_proofs
1205            .iter()
1206            .map(|(_ios, _proof, proof_batchable)| proof_batchable.clone())
1207            .collect::<Vec<VRFProofBatchable>>();
1208
1209        let mut public_keys = keypairs
1210            .iter()
1211            .map(|keypair| keypair.public.clone())
1212            .collect::<Vec<PublicKey>>();
1213
1214        assert!(
1215            dleq_verify_batch(&ios, &proofs, &public_keys, KUSAMA_VRF).is_ok(),
1216            "Batch verification failed!"
1217        );
1218        proofs.reverse();
1219        assert!(
1220            dleq_verify_batch(&ios, &proofs, &public_keys, KUSAMA_VRF).is_err(),
1221            "Batch verification with incorrect proofs passed!"
1222        );
1223        proofs.reverse();
1224        public_keys.reverse();
1225        assert!(
1226            dleq_verify_batch(&ios, &proofs, &public_keys, KUSAMA_VRF).is_err(),
1227            "Batch verification with incorrect public keys passed!"
1228        );
1229        public_keys.reverse();
1230        ios.reverse();
1231        assert!(
1232            dleq_verify_batch(&ios, &proofs, &public_keys, KUSAMA_VRF).is_err(),
1233            "Batch verification with incorrect points passed!"
1234        );
1235    }
1236}