1use crate::Suite;
32use crate::utils;
33use crate::utils::common::DomSep;
34use crate::utils::straus::short_msm;
35use crate::*;
36use ark_ec::VariableBaseMSM;
37
38pub const PEDERSEN_BLINDING_BASE_SEED: &[u8] = b"pedersen-blinding";
40
41pub trait PedersenSuite: Suite {
45 const BLINDING_BASE: AffinePoint<Self>;
47
48 fn blinding(secret: &ScalarField<Self>, mut transcript: Self::Transcript) -> ScalarField<Self> {
52 transcript.absorb_raw(&[DomSep::PedersenBlinding as u8]);
53 Self::nonce(secret, Some(transcript))
54 }
55}
56
57#[derive(Debug, Clone, CanonicalSerialize, CanonicalDeserialize)]
69pub struct Proof<S: PedersenSuite> {
70 pk_com: AffinePoint<S>,
71 r: AffinePoint<S>,
72 ok: AffinePoint<S>,
73 s: ScalarField<S>,
74 sb: ScalarField<S>,
75}
76
77impl<S: PedersenSuite> Proof<S> {
78 pub fn key_commitment(&self) -> AffinePoint<S> {
80 self.pk_com
81 }
82}
83
84pub trait Prover<S: PedersenSuite> {
86 fn prove(
92 &self,
93 ios: impl AsRef<[VrfIo<S>]>,
94 ad: impl AsRef<[u8]>,
95 ) -> (Proof<S>, ScalarField<S>);
96}
97
98pub trait Verifier<S: PedersenSuite> {
122 fn verify(
130 ios: impl AsRef<[VrfIo<S>]>,
131 ad: impl AsRef<[u8]>,
132 proof: &Proof<S>,
133 ) -> Result<(), Error>;
134}
135
136impl<S: PedersenSuite> Prover<S> for Secret<S> {
137 fn prove(
138 &self,
139 ios: impl AsRef<[VrfIo<S>]>,
140 ad: impl AsRef<[u8]>,
141 ) -> (Proof<S>, ScalarField<S>) {
142 let (mut t, io) = utils::vrf_transcript::<S>(DomSep::PedersenVrf, ios, ad);
143
144 let blinding = S::blinding(&self.scalar, t.clone());
146
147 let bb = smul!(S::BLINDING_BASE, blinding);
149 let pk_com = (self.public.0.into_group() + bb).into_affine();
150
151 t.absorb_serialize(&pk_com);
153
154 let k = S::nonce(&self.scalar, Some(t.clone()));
156 let kb = S::nonce(&blinding, Some(t.clone()));
157
158 let kg = smul!(S::generator(), k);
160 let kbb = smul!(S::BLINDING_BASE, kb);
161 let r = kg + kbb;
162
163 let ok = smul!(io.input.0, k);
165
166 let norms = CurveGroup::normalize_batch(&[r, ok]);
167 let (r, ok) = (norms[0], norms[1]);
168
169 let c = S::challenge(&[&r, &ok], Some(t));
171
172 let s = k + c * self.scalar;
174 let sb = kb + c * blinding;
176
177 let proof = Proof {
178 pk_com,
179 r,
180 ok,
181 s,
182 sb,
183 };
184 (proof, blinding)
185 }
186}
187
188impl<S: PedersenSuite> Verifier<S> for Public<S> {
189 fn verify(
190 ios: impl AsRef<[VrfIo<S>]>,
191 ad: impl AsRef<[u8]>,
192 proof: &Proof<S>,
193 ) -> Result<(), Error> {
194 let Proof {
195 pk_com,
196 r,
197 ok,
198 s,
199 sb,
200 } = proof;
201
202 if pk_com.is_zero() {
205 return Err(Error::InvalidData);
206 }
207
208 let ios = ios.as_ref();
211 if ios.iter().any(VrfIo::has_identity) {
212 return Err(Error::InvalidData);
213 }
214
215 let (mut t, io) = utils::vrf_transcript::<S>(DomSep::PedersenVrf, ios, ad);
216
217 t.absorb_serialize(pk_com);
219
220 let c = S::challenge(&[r, ok], Some(t));
222
223 let neg_c = -c;
224
225 let lhs1 = short_msm(&[io.input.0, io.output.0], &[*s, neg_c], 2);
230 if lhs1 != ok.into_group() {
231 return Err(Error::VerificationFailure);
232 }
233
234 let lhs2 = short_msm(
239 &[S::generator(), S::BLINDING_BASE, *pk_com],
240 &[*s, *sb, neg_c],
241 2,
242 );
243 if lhs2 != r.into_group() {
244 return Err(Error::VerificationFailure);
245 }
246
247 Ok(())
248 }
249}
250
251pub struct BatchItem<S: PedersenSuite> {
256 c: ScalarField<S>,
257 input: AffinePoint<S>,
258 output: AffinePoint<S>,
259 pk_com: AffinePoint<S>,
260 r: AffinePoint<S>,
261 ok: AffinePoint<S>,
262 s: ScalarField<S>,
263 sb: ScalarField<S>,
264 io_identity: bool,
268}
269
270impl<S: PedersenSuite> BatchItem<S> {
271 pub fn new(ios: impl AsRef<[VrfIo<S>]>, ad: impl AsRef<[u8]>, proof: &Proof<S>) -> Self {
277 let ios = ios.as_ref();
278 let io_identity = ios.iter().any(VrfIo::has_identity);
279 let (mut t, io) = utils::vrf_transcript::<S>(DomSep::PedersenVrf, ios, ad);
280 t.absorb_serialize(&proof.pk_com);
281 let c = S::challenge(&[&proof.r, &proof.ok], Some(t));
282 Self {
283 c,
284 input: io.input.0,
285 output: io.output.0,
286 pk_com: proof.pk_com,
287 r: proof.r,
288 ok: proof.ok,
289 s: proof.s,
290 sb: proof.sb,
291 io_identity,
292 }
293 }
294}
295
296pub struct BatchVerifier<S: PedersenSuite> {
304 items: Vec<BatchItem<S>>,
305}
306
307impl<S: PedersenSuite> Default for BatchVerifier<S> {
308 fn default() -> Self {
309 Self { items: Vec::new() }
310 }
311}
312
313impl<S: PedersenSuite> BatchVerifier<S> {
314 pub fn new() -> Self {
316 Self::default()
317 }
318
319 pub fn push_prepared(&mut self, entry: BatchItem<S>) {
321 self.items.push(entry);
322 }
323
324 pub fn push(&mut self, ios: impl AsRef<[VrfIo<S>]>, ad: impl AsRef<[u8]>, proof: &Proof<S>) {
326 self.push_prepared(BatchItem::new(ios, ad, proof));
327 }
328
329 pub fn verify(&self) -> Result<(), Error> {
342 let items = &self.items;
343 if items.is_empty() {
344 return Ok(());
345 }
346
347 if items
349 .iter()
350 .any(|item| item.pk_com.is_zero() || item.io_identity)
351 {
352 return Err(Error::InvalidData);
353 }
354
355 let n = items.len();
356
357 let mut t = S::Transcript::new(S::SUITE_ID);
362 t.absorb_raw(&[DomSep::BatchVerify as u8]);
363 for e in items {
364 t.absorb_serialize(&e.c);
365 t.absorb_serialize(&e.s);
366 t.absorb_serialize(&e.sb);
367 }
368 let random_scalars: Vec<(ScalarField<S>, ScalarField<S>)> = (0..n)
374 .map(|_| {
375 let mut buf = [0u8; 32];
376 t.squeeze_raw(&mut buf);
377 let t = ScalarField::<S>::from_le_bytes_mod_order(&buf[..16]);
378 let u = ScalarField::<S>::from_le_bytes_mod_order(&buf[16..]);
379 (t, u)
380 })
381 .collect();
382
383 let mut bases = Vec::with_capacity(5 * n + 2);
385 let mut scalars = Vec::with_capacity(5 * n + 2);
386
387 let mut g_scalar = ScalarField::<S>::zero();
388 let mut b_scalar = ScalarField::<S>::zero();
389
390 for (e, (t, u)) in items.iter().zip(random_scalars.iter()) {
391 bases.push(e.output);
393 scalars.push(*t * e.c);
394
395 bases.push(e.ok);
396 scalars.push(*t);
397
398 bases.push(e.input);
399 scalars.push(-(*t * e.s));
400
401 bases.push(e.pk_com);
403 scalars.push(*u * e.c);
404
405 bases.push(e.r);
406 scalars.push(*u);
407
408 g_scalar += *u * e.s;
410 b_scalar += *u * e.sb;
411 }
412
413 bases.push(S::generator());
415 scalars.push(-g_scalar);
416
417 bases.push(S::BLINDING_BASE);
418 scalars.push(-b_scalar);
419
420 let result = <S::Affine as AffineRepr>::Group::msm_unchecked(&bases, &scalars);
421 if !result.is_zero() {
422 return Err(Error::VerificationFailure);
423 }
424
425 Ok(())
426 }
427}
428
429#[cfg(test)]
430pub(crate) mod testing {
431 use super::*;
432 use crate::testing::{self as common, CheckPoint, SuiteExt, TEST_SEED, random_val};
433
434 pub fn prove_verify<S: PedersenSuite>() {
435 use pedersen::{Prover, Verifier};
436
437 let secret = Secret::<S>::from_seed(TEST_SEED);
438 let input = Input::from_affine_unchecked(random_val(None));
439 let io = secret.vrf_io(input);
440
441 let (proof, blinding) = secret.prove(io, b"foo");
442 let result = Public::verify(io, b"foo", &proof);
443 assert!(result.is_ok());
444
445 assert_eq!(
446 proof.key_commitment(),
447 (secret.public().0 + S::BLINDING_BASE * blinding).into()
448 );
449 }
450
451 pub fn batch_verify<S: PedersenSuite>() {
452 use pedersen::{BatchItem, BatchVerifier, Prover, Verifier};
453
454 let secret = Secret::<S>::from_seed(TEST_SEED);
455 let input = Input::from_affine_unchecked(random_val(None));
456 let io = secret.vrf_io(input);
457
458 let (proof1, _) = secret.prove(io, b"foo");
459 let (proof2, _) = secret.prove(io, b"bar");
460
461 assert!(Public::verify(io, b"foo", &proof1).is_ok());
463 assert!(Public::verify(io, b"bar", &proof2).is_ok());
464
465 let mut batch = BatchVerifier::new();
467 batch.push(io, b"foo", &proof1);
468 batch.push(io, b"bar", &proof2);
469 assert!(batch.verify().is_ok());
470
471 let mut batch = BatchVerifier::new();
473 let entry1 = BatchItem::new(io, b"foo", &proof1);
474 let entry2 = BatchItem::new(io, b"bar", &proof2);
475 batch.push_prepared(entry1);
476 batch.push_prepared(entry2);
477 assert!(batch.verify().is_ok());
478
479 let batch = BatchVerifier::<S>::new();
481 assert!(batch.verify().is_ok());
482
483 let mut batch = BatchVerifier::new();
485 batch.push(io, b"foo", &proof1);
486 batch.push(io, b"wrong", &proof2);
487 assert!(batch.verify().is_err());
488 }
489
490 pub fn prove_verify_multi_single<S: PedersenSuite>() {
492 use pedersen::{Prover, Verifier};
493
494 let secret = Secret::<S>::from_seed(TEST_SEED);
495 let input = Input::from_affine_unchecked(random_val(None));
496 let io = secret.vrf_io(input);
497
498 let (proof_single, blinding_single) = secret.prove(io, b"foo");
499 let (proof_slice, blinding_slice) = secret.prove([io], b"foo");
500
501 let encode = |p: &pedersen::Proof<S>| {
503 let mut buf = Vec::new();
504 p.serialize_compressed(&mut buf).unwrap();
505 buf
506 };
507 assert_eq!(encode(&proof_single), encode(&proof_slice));
508 assert_eq!(blinding_single, blinding_slice);
509
510 assert!(Public::verify(io, b"foo", &proof_slice).is_ok());
512 assert!(Public::verify([io], b"foo", &proof_single).is_ok());
513 }
514
515 pub fn prove_verify_multi<S: PedersenSuite>() {
517 use pedersen::{Prover, Verifier};
518
519 let secret = Secret::<S>::from_seed(TEST_SEED);
520
521 let mut ios: Vec<VrfIo<S>> = (0..3u8)
522 .map(|i| {
523 let input = Input::new(&[i + 1]).unwrap();
524 secret.vrf_io(input)
525 })
526 .collect();
527 ios.push(VrfIo {
528 input: Input(S::Affine::generator()),
529 output: Output(secret.public().0),
530 });
531
532 let (proof, _) = secret.prove(&ios[..], b"bar");
533 assert!(Public::verify(&ios[..], b"bar", &proof).is_ok());
534
535 let mut bad_ios = ios.clone();
537 bad_ios[1].output = secret.output(ios[0].input);
538 assert!(Public::verify(&bad_ios[..], b"bar", &proof).is_err());
539
540 let mut bad_ios = ios.clone();
542 bad_ios[0].input = ios[1].input;
543 assert!(Public::verify(&bad_ios[..], b"bar", &proof).is_err());
544
545 assert!(Public::verify(&ios[..], b"baz", &proof).is_err());
547 }
548
549 pub fn prove_verify_multi_empty<S: PedersenSuite>() {
551 use pedersen::{Prover, Verifier};
552
553 let secret = Secret::<S>::from_seed(TEST_SEED);
554
555 let ios: [VrfIo<S>; 0] = [];
556 let (proof, _) = secret.prove(ios, b"bar");
557
558 assert!(Public::verify(ios, b"bar", &proof).is_ok());
559
560 assert!(Public::verify(ios, b"baz", &proof).is_err());
562 }
563
564 pub fn identity_io_pair_rejected<S: PedersenSuite>() {
573 use pedersen::{BatchVerifier, Prover, Verifier};
574
575 let identity_io = VrfIo::<S> {
576 input: Input(AffinePoint::<S>::zero()),
577 output: Output(AffinePoint::<S>::zero()),
578 };
579
580 for seed in [TEST_SEED, [0x11; 32]] {
581 let secret = Secret::<S>::from_seed(seed);
582
583 let (proof, _) = secret.prove([identity_io], b"forgery");
584 assert!(Public::verify([identity_io], b"forgery", &proof).is_err());
585
586 let mut batch = BatchVerifier::new();
587 batch.push([identity_io], b"forgery", &proof);
588 assert!(batch.verify().is_err());
589
590 let good_io = secret.vrf_io(Input::new(b"good").unwrap());
591 let ios = [good_io, identity_io];
592 let (proof, _) = secret.prove(ios, b"forgery");
593 assert!(Public::verify(ios, b"forgery", &proof).is_err());
594
595 let mut batch = BatchVerifier::new();
596 batch.push(ios, b"forgery", &proof);
597 assert!(batch.verify().is_err());
598 }
599 }
600
601 pub fn identity_key_commitment_rejected<S: PedersenSuite>() {
608 use pedersen::{BatchVerifier, Verifier};
609
610 let ios: [VrfIo<S>; 0] = [];
611 let ad = b"forgery";
612
613 let (mut t, io) = utils::vrf_transcript::<S>(DomSep::PedersenVrf, ios, ad);
614 let pk_com = AffinePoint::<S>::zero();
615 t.absorb_serialize(&pk_com);
616
617 let k = ScalarField::<S>::from(7u64);
618 let kb = ScalarField::<S>::from(11u64);
619 let r = (S::generator() * k + S::BLINDING_BASE * kb).into_affine();
620 let ok = (io.input.0 * k).into_affine();
621
622 let proof = Proof {
623 pk_com,
624 r,
625 ok,
626 s: k,
627 sb: kb,
628 };
629
630 assert!(Public::verify(ios, ad, &proof).is_err());
631
632 let mut batch = BatchVerifier::new();
633 batch.push(ios, ad, &proof);
634 assert!(batch.verify().is_err());
635 }
636
637 pub fn blinding_base_check<S: PedersenSuite>()
638 where
639 AffinePoint<S>: CheckPoint,
640 {
641 assert_eq!(
643 S::BLINDING_BASE,
644 S::data_to_point(PEDERSEN_BLINDING_BASE_SEED).unwrap()
645 );
646 assert!(S::BLINDING_BASE.check(true).is_ok());
648 }
649
650 #[macro_export]
651 macro_rules! pedersen_suite_tests {
652 ($suite:ty) => {
653 mod pedersen {
654 use super::*;
655
656 #[test]
657 fn prove_verify() {
658 $crate::pedersen::testing::prove_verify::<$suite>();
659 }
660
661 #[test]
662 fn prove_verify_multi_single() {
663 $crate::pedersen::testing::prove_verify_multi_single::<$suite>();
664 }
665
666 #[test]
667 fn prove_verify_multi() {
668 $crate::pedersen::testing::prove_verify_multi::<$suite>();
669 }
670
671 #[test]
672 fn prove_verify_multi_empty() {
673 $crate::pedersen::testing::prove_verify_multi_empty::<$suite>();
674 }
675
676 #[test]
677 fn batch_verify() {
678 $crate::pedersen::testing::batch_verify::<$suite>();
679 }
680
681 #[test]
682 fn identity_io_pair_rejected() {
683 $crate::pedersen::testing::identity_io_pair_rejected::<$suite>();
684 }
685
686 #[test]
687 fn identity_key_commitment_rejected() {
688 $crate::pedersen::testing::identity_key_commitment_rejected::<$suite>();
689 }
690
691 #[test]
692 fn blinding_base_check() {
693 $crate::pedersen::testing::blinding_base_check::<$suite>();
694 }
695
696 $crate::test_vectors!($crate::pedersen::testing::TestVector<$suite>);
697 }
698 };
699 }
700
701 pub struct TestVector<S: PedersenSuite> {
702 pub base: common::TestVector<S>,
703 pub blind: ScalarField<S>,
704 pub proof: Proof<S>,
705 }
706
707 impl<S: PedersenSuite> core::fmt::Debug for TestVector<S> {
708 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
709 f.debug_struct("TestVector")
710 .field("base", &self.base)
711 .field("blinding", &self.blind)
712 .field("proof_pk_com", &self.proof.pk_com)
713 .field("proof_r", &self.proof.r)
714 .field("proof_ok", &self.proof.ok)
715 .field("proof_s", &self.proof.s)
716 .field("proof_sb", &self.proof.sb)
717 .finish()
718 }
719 }
720
721 impl<S> common::TestVectorTrait for TestVector<S>
722 where
723 S: PedersenSuite + SuiteExt + std::fmt::Debug,
724 {
725 fn name() -> String {
726 S::SUITE_NAME.to_string() + "_pedersen"
727 }
728
729 fn new(comment: &str, seed: &[u8; 32], alpha: &[u8], ad: &[u8]) -> Self {
730 use super::Prover;
731 let base = common::TestVector::new(comment, seed, alpha, ad);
732 let io = VrfIo {
733 input: Input::<S>::from_affine_unchecked(base.h),
734 output: Output::from_affine_unchecked(base.gamma),
735 };
736 let secret = Secret::from_scalar(base.sk);
737 let (proof, blind) = secret.prove(io, ad);
738 Self { base, blind, proof }
739 }
740
741 fn from_map(map: &common::TestVectorMap) -> Self {
742 let base = common::TestVector::from_map(map);
743 let blind = common::scalar_decode::<S>(&map.get_bytes("blinding"));
744 let pk_com = common::point_decode::<S>(&map.get_bytes("proof_pk_com")).unwrap();
745 let r = common::point_decode::<S>(&map.get_bytes("proof_r")).unwrap();
746 let ok = common::point_decode::<S>(&map.get_bytes("proof_ok")).unwrap();
747 let s = common::scalar_decode::<S>(&map.get_bytes("proof_s"));
748 let sb = common::scalar_decode::<S>(&map.get_bytes("proof_sb"));
749 let proof = Proof {
750 pk_com,
751 r,
752 ok,
753 s,
754 sb,
755 };
756 Self { base, blind, proof }
757 }
758
759 fn to_map(&self) -> common::TestVectorMap {
760 let items = [
761 (
762 "blinding",
763 hex::encode(common::scalar_encode::<S>(&self.blind)),
764 ),
765 (
766 "proof_pk_com",
767 hex::encode(common::point_encode::<S>(&self.proof.pk_com)),
768 ),
769 (
770 "proof_r",
771 hex::encode(common::point_encode::<S>(&self.proof.r)),
772 ),
773 (
774 "proof_ok",
775 hex::encode(common::point_encode::<S>(&self.proof.ok)),
776 ),
777 (
778 "proof_s",
779 hex::encode(common::scalar_encode::<S>(&self.proof.s)),
780 ),
781 (
782 "proof_sb",
783 hex::encode(common::scalar_encode::<S>(&self.proof.sb)),
784 ),
785 ];
786 let mut map = self.base.to_map();
787 items.into_iter().for_each(|(name, value)| {
788 map.0.insert(name.to_string(), value);
789 });
790 map
791 }
792
793 fn run(&self) {
794 self.base.run();
795 let io = VrfIo {
796 input: Input::<S>::from_affine_unchecked(self.base.h),
797 output: Output::from_affine_unchecked(self.base.gamma),
798 };
799 let sk = Secret::from_scalar(self.base.sk);
800 let (proof, blind) = sk.prove(io, &self.base.ad);
801 assert_eq!(self.blind, blind, "Blinding factor mismatch");
802 assert_eq!(self.proof.pk_com, proof.pk_com, "Proof pkb mismatch");
803 assert_eq!(self.proof.r, proof.r, "Proof r mismatch");
804 assert_eq!(self.proof.ok, proof.ok, "Proof ok mismatch");
805 assert_eq!(self.proof.s, proof.s, "Proof s mismatch");
806 assert_eq!(self.proof.sb, proof.sb, "Proof sb mismatch");
807
808 assert!(Public::verify(io, &self.base.ad, &proof).is_ok());
809 }
810 }
811}