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