1use crate::{utils::challenge_scalar, utils::common::DomSep, utils::straus::short_msm, *};
26
27pub trait ThinVrfSuite: Suite {}
31
32impl<T> ThinVrfSuite for T where T: Suite {}
33
34#[derive(Debug, Clone, CanonicalSerialize, CanonicalDeserialize)]
43pub struct Proof<S: ThinVrfSuite> {
44 pub r: AffinePoint<S>,
46 pub s: ScalarField<S>,
48}
49
50#[inline(always)]
51fn vrf_transcript<S: ThinVrfSuite>(
52 public: AffinePoint<S>,
53 ios: impl AsRef<[VrfIo<S>]>,
54 ad: impl AsRef<[u8]>,
55) -> (S::Transcript, VrfIo<S>) {
56 utils::vrf_transcript_with_schnorr(DomSep::ThinVrf, public, ios, ad)
57}
58
59#[inline(always)]
60fn vrf_transcript_scalars<S: ThinVrfSuite>(
61 public: AffinePoint<S>,
62 ios: impl AsRef<[VrfIo<S>]>,
63 ad: impl AsRef<[u8]>,
64) -> (S::Transcript, Vec<ScalarField<S>>) {
65 utils::vrf_transcript_scalars_with_schnorr(DomSep::ThinVrf, public, ios, ad)
66}
67
68pub trait Prover<S: ThinVrfSuite> {
70 fn prove(&self, ios: impl AsRef<[VrfIo<S>]>, ad: impl AsRef<[u8]>) -> Proof<S>;
74}
75
76pub trait Verifier<S: ThinVrfSuite> {
90 fn verify(
96 &self,
97 ios: impl AsRef<[VrfIo<S>]>,
98 ad: impl AsRef<[u8]>,
99 proof: &Proof<S>,
100 ) -> Result<(), Error>;
101}
102
103impl<S: ThinVrfSuite> Prover<S> for Secret<S> {
104 fn prove(&self, ios: impl AsRef<[VrfIo<S>]>, ad: impl AsRef<[u8]>) -> Proof<S> {
105 let (t, merged) = vrf_transcript::<S>(self.public.0, ios, ad);
106
107 let k = S::nonce(&self.scalar, Some(t.clone()));
109
110 let r = smul!(merged.input.0, k).into_affine();
112
113 let c = S::challenge(&[&r], Some(t));
115
116 let s = k + c * self.scalar;
118
119 Proof { r, s }
120 }
121}
122
123impl<S: ThinVrfSuite> Verifier<S> for Public<S> {
124 fn verify(
125 &self,
126 ios: impl AsRef<[VrfIo<S>]>,
127 ad: impl AsRef<[u8]>,
128 proof: &Proof<S>,
129 ) -> Result<(), Error> {
130 let Proof { r, s } = proof;
131 let (t, merged) = vrf_transcript::<S>(self.0, ios, ad);
132
133 let c = S::challenge(&[r], Some(t));
135
136 let lhs = short_msm(&[merged.input.0, merged.output.0], &[*s, -c], 2);
138 if lhs != r.into_group() {
139 return Err(Error::VerificationFailure);
140 }
141
142 Ok(())
143 }
144}
145
146pub struct BatchItem<S: ThinVrfSuite> {
152 c: ScalarField<S>,
153 pk: AffinePoint<S>,
154 ios: Vec<VrfIo<S>>,
155 zs: Vec<ScalarField<S>>,
156 r: AffinePoint<S>,
157 s: ScalarField<S>,
158}
159
160pub struct BatchVerifier<S: ThinVrfSuite> {
168 items: Vec<BatchItem<S>>,
169}
170
171impl<S: ThinVrfSuite> Default for BatchVerifier<S> {
172 fn default() -> Self {
173 Self { items: Vec::new() }
174 }
175}
176
177impl<S: ThinVrfSuite> BatchVerifier<S> {
178 pub fn new() -> Self {
180 Self::default()
181 }
182
183 pub fn prepare(
189 public: &Public<S>,
190 ios: impl AsRef<[VrfIo<S>]>,
191 ad: impl AsRef<[u8]>,
192 proof: &Proof<S>,
193 ) -> BatchItem<S> {
194 let ios = ios.as_ref();
195 let (t, zs) = vrf_transcript_scalars::<S>(public.0, ios, ad);
196 let c = S::challenge(&[&proof.r], Some(t));
197 BatchItem {
198 c,
199 pk: public.0,
200 ios: ios.to_vec(),
201 zs,
202 r: proof.r,
203 s: proof.s,
204 }
205 }
206
207 pub fn push_prepared(&mut self, entry: BatchItem<S>) {
209 self.items.push(entry);
210 }
211
212 pub fn push(
214 &mut self,
215 public: &Public<S>,
216 ios: impl AsRef<[VrfIo<S>]>,
217 ad: impl AsRef<[u8]>,
218 proof: &Proof<S>,
219 ) {
220 let entry = Self::prepare(public, ios, ad, proof);
221 self.push_prepared(entry);
222 }
223
224 pub fn verify(&self) -> Result<(), Error> {
235 use ark_ec::VariableBaseMSM;
236 use ark_ff::Zero;
237
238 let items = &self.items;
239 if items.is_empty() {
240 return Ok(());
241 }
242
243 let mut t = S::Transcript::new(S::SUITE_ID);
245 t.absorb_raw(&[DomSep::ThinBatch as u8]);
246 for e in items {
247 t.absorb_serialize(&e.c);
248 t.absorb_serialize(&e.s);
249 }
250
251 let total_points: usize = items.iter().map(|e| 2 + 2 * e.ios.len()).sum::<usize>() + 1;
253 let mut bases = Vec::with_capacity(total_points);
254 let mut scalars = Vec::with_capacity(total_points);
255 let mut g_scalar = ScalarField::<S>::zero();
256
257 for item in items.iter() {
258 let w = challenge_scalar::<S>(&mut t);
260
261 let wc = w * item.c;
262 let ws = w * item.s;
263
264 bases.push(item.r);
266 scalars.push(w);
267
268 bases.push(item.pk);
270 scalars.push(wc * item.zs[0]);
271
272 g_scalar -= ws * item.zs[0];
274
275 for (i, io) in item.ios.iter().enumerate() {
277 bases.push(io.output.0);
278 scalars.push(wc * item.zs[i + 1]);
279
280 bases.push(io.input.0);
281 scalars.push(-(ws * item.zs[i + 1]));
282 }
283 }
284
285 bases.push(S::generator());
287 scalars.push(g_scalar);
288
289 let result = <S::Affine as AffineRepr>::Group::msm_unchecked(&bases, &scalars);
290 if !result.is_zero() {
291 return Err(Error::VerificationFailure);
292 }
293
294 Ok(())
295 }
296}
297
298#[cfg(test)]
299pub(crate) mod testing {
300 use super::*;
301 use crate::testing::{self as common, SuiteExt, TEST_SEED, random_val};
302
303 pub fn prove_verify<S: ThinVrfSuite>() {
304 use thin::{Prover, Verifier};
305
306 let secret = Secret::<S>::from_seed(TEST_SEED);
307 let public = secret.public();
308 let input = Input::from_affine_unchecked(random_val(None));
309 let io = secret.vrf_io(input);
310
311 let proof = secret.prove(io, b"foo");
312 let result = public.verify(io, b"foo", &proof);
313 assert!(result.is_ok());
314 }
315
316 pub fn batch_verify<S: ThinVrfSuite>() {
317 use thin::{BatchVerifier, Prover, Verifier};
318
319 let secret = Secret::<S>::from_seed(TEST_SEED);
320 let public = secret.public();
321 let input = Input::from_affine_unchecked(random_val(None));
322 let io = secret.vrf_io(input);
323
324 let proof1 = secret.prove(io, b"foo");
325 let proof2 = secret.prove(io, b"bar");
326
327 assert!(public.verify(io, b"foo", &proof1).is_ok());
329 assert!(public.verify(io, b"bar", &proof2).is_ok());
330
331 let mut batch = BatchVerifier::new();
333 batch.push(&public, io, b"foo", &proof1);
334 batch.push(&public, io, b"bar", &proof2);
335 assert!(batch.verify().is_ok());
336
337 let mut batch = BatchVerifier::new();
339 let entry1 = BatchVerifier::prepare(&public, io, b"foo", &proof1);
340 let entry2 = BatchVerifier::prepare(&public, io, b"bar", &proof2);
341 batch.push_prepared(entry1);
342 batch.push_prepared(entry2);
343 assert!(batch.verify().is_ok());
344
345 let batch = BatchVerifier::<S>::new();
347 assert!(batch.verify().is_ok());
348
349 let mut batch = BatchVerifier::new();
351 batch.push(&public, io, b"foo", &proof1);
352 batch.push(&public, io, b"wrong", &proof2);
353 assert!(batch.verify().is_err());
354 }
355
356 pub fn prove_verify_multi_single<S: ThinVrfSuite>() {
358 use thin::{Prover, Verifier};
359
360 let secret = Secret::<S>::from_seed(TEST_SEED);
361 let public = secret.public();
362 let input = Input::from_affine_unchecked(random_val(None));
363 let io = secret.vrf_io(input);
364
365 let proof_single = secret.prove(io, b"foo");
366 let proof_slice = secret.prove([io], b"foo");
367
368 let encode = |p: &thin::Proof<S>| {
370 let mut buf = Vec::new();
371 p.serialize_compressed(&mut buf).unwrap();
372 buf
373 };
374 assert_eq!(encode(&proof_single), encode(&proof_slice));
375
376 assert!(public.verify(io, b"foo", &proof_slice).is_ok());
378 assert!(public.verify([io], b"foo", &proof_single).is_ok());
379 }
380
381 pub fn prove_verify_multi<S: ThinVrfSuite>() {
383 use thin::{Prover, Verifier};
384
385 let secret = Secret::<S>::from_seed(TEST_SEED);
386 let public = secret.public();
387
388 let ios: Vec<VrfIo<S>> = (0..3u8)
389 .map(|i| {
390 let input = Input::new(&[i + 1]).unwrap();
391 secret.vrf_io(input)
392 })
393 .collect();
394
395 let proof = secret.prove(&ios[..], b"bar");
396 assert!(public.verify(&ios[..], b"bar", &proof).is_ok());
397
398 let mut bad_ios = ios.clone();
400 bad_ios[1].output = secret.output(ios[0].input);
401 assert!(public.verify(&bad_ios[..], b"bar", &proof).is_err());
402
403 let mut bad_ios = ios.clone();
405 bad_ios[0].input = ios[1].input;
406 assert!(public.verify(&bad_ios[..], b"bar", &proof).is_err());
407
408 assert!(public.verify(&ios[..], b"baz", &proof).is_err());
410 }
411
412 pub fn prove_verify_multi_empty<S: ThinVrfSuite>() {
414 use thin::{Prover, Verifier};
415
416 let secret = Secret::<S>::from_seed(TEST_SEED);
417 let public = secret.public();
418
419 let proof = secret.prove([], b"bar");
420 assert!(public.verify([], b"bar", &proof).is_ok());
421
422 assert!(public.verify([], b"baz", &proof).is_err());
424 }
425
426 #[macro_export]
427 macro_rules! thin_suite_tests {
428 ($suite:ty) => {
429 mod thin {
430 use super::*;
431
432 #[test]
433 fn prove_verify() {
434 $crate::thin::testing::prove_verify::<$suite>();
435 }
436
437 #[test]
438 fn prove_verify_multi_single() {
439 $crate::thin::testing::prove_verify_multi_single::<$suite>();
440 }
441
442 #[test]
443 fn prove_verify_multi() {
444 $crate::thin::testing::prove_verify_multi::<$suite>();
445 }
446
447 #[test]
448 fn prove_verify_multi_empty() {
449 $crate::thin::testing::prove_verify_multi_empty::<$suite>();
450 }
451
452 #[test]
453 fn batch_verify() {
454 $crate::thin::testing::batch_verify::<$suite>();
455 }
456
457 $crate::test_vectors!($crate::thin::testing::TestVector<$suite>);
458 }
459 };
460 }
461
462 pub struct TestVector<S: ThinVrfSuite> {
463 pub base: common::TestVector<S>,
464 pub proof_r: AffinePoint<S>,
465 pub proof_s: ScalarField<S>,
466 }
467
468 impl<S: ThinVrfSuite> core::fmt::Debug for TestVector<S> {
469 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
470 let r = hex::encode(common::point_encode::<S>(&self.proof_r));
471 let s = hex::encode(common::scalar_encode::<S>(&self.proof_s));
472 f.debug_struct("TestVector")
473 .field("base", &self.base)
474 .field("proof_r", &r)
475 .field("proof_s", &s)
476 .finish()
477 }
478 }
479
480 impl<S> common::TestVectorTrait for TestVector<S>
481 where
482 S: ThinVrfSuite + SuiteExt + std::fmt::Debug,
483 {
484 fn name() -> String {
485 S::SUITE_NAME.to_string() + "_thin"
486 }
487
488 fn new(comment: &str, seed: &[u8; 32], alpha: &[u8], ad: &[u8]) -> Self {
489 use super::Prover;
490 let base = common::TestVector::new(comment, seed, alpha, ad);
491 let io = VrfIo {
492 input: Input::<S>::from_affine_unchecked(base.h),
493 output: Output::from_affine_unchecked(base.gamma),
494 };
495 let secret = Secret::from_scalar(base.sk);
496 let proof: Proof<S> = secret.prove(io, ad);
497 Self {
498 base,
499 proof_r: proof.r,
500 proof_s: proof.s,
501 }
502 }
503
504 fn from_map(map: &common::TestVectorMap) -> Self {
505 let base = common::TestVector::from_map(map);
506 let proof_r = common::point_decode::<S>(&map.get_bytes("proof_r")).unwrap();
507 let proof_s = common::scalar_decode::<S>(&map.get_bytes("proof_s"));
508 Self {
509 base,
510 proof_r,
511 proof_s,
512 }
513 }
514
515 fn to_map(&self) -> common::TestVectorMap {
516 let items = [
517 (
518 "proof_r",
519 hex::encode(common::point_encode::<S>(&self.proof_r)),
520 ),
521 (
522 "proof_s",
523 hex::encode(common::scalar_encode::<S>(&self.proof_s)),
524 ),
525 ];
526 let mut map = self.base.to_map();
527 items.into_iter().for_each(|(name, value)| {
528 map.0.insert(name.to_string(), value);
529 });
530 map
531 }
532
533 fn run(&self) {
534 self.base.run();
535 let io = VrfIo {
536 input: Input::<S>::from_affine_unchecked(self.base.h),
537 output: Output::from_affine_unchecked(self.base.gamma),
538 };
539 let sk = Secret::from_scalar(self.base.sk);
540 let proof = sk.prove(io, &self.base.ad);
541 assert_eq!(self.proof_r, proof.r, "Thin VRF proof R mismatch");
542 assert_eq!(self.proof_s, proof.s, "Thin VRF proof s mismatch");
543
544 let pk = Public(self.base.pk);
545 assert!(pk.verify(io, &self.base.ad, &proof).is_ok());
546 }
547 }
548
549 #[test]
555 fn known_dlog_input_forgery() {
556 use ark_ff::Field;
557
558 type S = crate::suites::testing::TestSuite;
559 type Sc = ScalarField<S>;
560
561 let g = S::generator();
562
563 let sk = Sc::from(42);
565 let pk = (g * sk).into_affine();
566
567 let d = Sc::from(7);
569 let input_pt = (g * d).into_affine();
570 let input = Input::<S>::from_affine_unchecked(input_pt);
571
572 let honest_output = (input_pt * sk).into_affine();
574
575 let t_scalar = Sc::from(1234);
577 let fake_output_pt = (g * t_scalar).into_affine();
578 assert_ne!(fake_output_pt, honest_output);
579 let fake_output = Output::<S>::from_affine_unchecked(fake_output_pt);
580
581 let ad: &[u8] = b"attack";
582 let fake_io = VrfIo {
583 input,
584 output: fake_output,
585 };
586
587 let fake_ios: &[VrfIo<S>] = &[fake_io];
589 let (transcript, zs) = vrf_transcript_scalars::<S>(pk, fake_ios, ad);
590 let (z0, z1) = (zs[0], zs[1]);
591
592 let merged_input = (g * z0 + input_pt * z1).into_affine();
594
595 let x = (z0 * sk + z1 * t_scalar) * (z0 + z1 * d).inverse().unwrap();
601
602 let k = Sc::from(9999);
604 let r = (merged_input * k).into_affine();
605 let c = S::challenge(&[&r], Some(transcript));
606 let s = k + c * x;
607
608 let forged_proof = Proof::<S> { r, s };
609
610 let public = Public::<S>(pk);
627 assert!(
628 public.verify(fake_io, ad, &forged_proof).is_ok(),
629 "Forged proof must verify when input discrete log is known"
630 );
631 }
632}