1use 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}; #[cfg(feature = "alloc")]
92use curve25519_dalek::traits::{MultiscalarMul, VartimeMultiscalarMul};
93
94use merlin::Transcript;
95
96use super::*;
97use crate::context::SigningTranscript;
98use crate::points::RistrettoBoth;
99pub const KUSAMA_VRF: bool = true;
120
121pub const VRF_PREOUT_LENGTH: usize = 32;
123
124pub const VRF_PROOF_LENGTH: usize = 64;
126
127pub const VRF_PROOF_BATCHABLE_LENGTH: usize = 96;
129
130pub trait VRFSigningTranscript {
136 type T: SigningTranscript;
138 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#[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
179pub 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 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 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#[deprecated(since = "0.9.2", note = "Please use VRFPreOut instead of VRFOutput")]
215pub type VRFOutput = VRFPreOut;
216
217#[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 #[inline]
238 pub fn to_bytes(&self) -> [u8; VRF_PREOUT_LENGTH] {
239 self.0
240 }
241
242 #[inline]
244 pub fn as_bytes(&self) -> &[u8; VRF_PREOUT_LENGTH] {
245 &self.0
246 }
247
248 #[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 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#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
284pub struct VRFInOut {
285 pub input: RistrettoBoth,
287 pub output: RistrettoBoth,
289}
290
291impl SecretKey {
292 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 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 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 pub fn as_output_bytes(&self) -> &[u8; 32] {
321 self.output.as_compressed().as_bytes()
322 }
323
324 pub fn to_preout(&self) -> VRFPreOut {
326 VRFPreOut(self.output.as_compressed().to_bytes())
327 }
328
329 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 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 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 #[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 #[inline(always)]
396 pub fn make_merlin_rng(&self, context: &[u8]) -> merlin::TranscriptRng {
397 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 #[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 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; 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#[derive(Debug, Clone, PartialEq, Eq)] pub struct VRFProof {
501 c: Scalar,
503 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 #[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 #[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#[derive(Debug, Clone, PartialEq, Eq)] #[allow(non_snake_case)]
548pub struct VRFProofBatchable {
549 R: CompressedRistretto,
551 Hr: CompressedRistretto,
553 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 #[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 #[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 #[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: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"), s: self.s,
615 }
616 }
617
618 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)?; let t0 = Transcript::new(b"VRF"); Ok(self.shorten_dleq(t0, public, &p, KUSAMA_VRF))
635 }
636}
637
638serde_boilerplate!(VRFProofBatchable);
639
640impl Keypair {
641 #[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:h", p.input.as_compressed());
656 if !kusama { t.commit_point(b"vrf:pk", self.public.as_compressed()); }
657
658 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 t.commit_point(b"vrf:h^sk", p.output.as_compressed());
669
670 let c = t.challenge_scalar(b"prove"); 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 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 }
693
694 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 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 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 #[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 #[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 #[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:h", p.input.as_compressed());
816 if !kusama { t.commit_point(b"vrf:pk", self.as_compressed()); }
817
818 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 #[cfg(not(feature = "alloc"))]
829 let Hr = (&proof.c * p.output.as_point()) + (&proof.s * p.input.as_point());
830
831 #[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 t.commit_point(b"vrf:h^sk", p.output.as_compressed());
844
845 let VRFProof { c, s } = *proof;
847 if c == t.challenge_scalar(b"prove") {
848 Ok(VRFProofBatchable { R, Hr, s }) } else {
850 Err(SignatureError::EquationFalse)
851 }
852 }
853
854 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 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 #[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 #[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#[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 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 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 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 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 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#[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 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}