1use super::*;
27use utils::common::DomSep;
28use utils::straus::short_msm;
29
30pub trait TinySuite: Suite {}
34
35impl<T> TinySuite for T where T: Suite {}
36
37#[inline(always)]
38fn vrf_transcript<S: TinySuite>(
39 public: AffinePoint<S>,
40 ios: impl AsRef<[VrfIo<S>]>,
41 ad: impl AsRef<[u8]>,
42) -> (S::Transcript, VrfIo<S>) {
43 utils::vrf_transcript_with_schnorr(DomSep::TinyVrf, public, ios, ad)
44}
45
46#[derive(Debug, Clone)]
52pub struct Proof<S: TinySuite> {
53 pub c: ScalarField<S>,
55 pub s: ScalarField<S>,
57}
58
59impl<S: TinySuite> CanonicalSerialize for Proof<S> {
60 fn serialize_with_mode<W: ark_serialize::Write>(
61 &self,
62 mut writer: W,
63 compress: ark_serialize::Compress,
64 ) -> Result<(), ark_serialize::SerializationError> {
65 let scalar_len = ScalarField::<S>::MODULUS_BIT_SIZE.div_ceil(8) as usize;
66 if scalar_len < utils::common::CHALLENGE_LEN {
67 return Err(ark_serialize::SerializationError::InvalidData);
69 }
70 let mut c_buf = [0; 128];
71 self.c
72 .serialize_compressed(&mut c_buf[..])
73 .expect("c_buf is big enough");
74 let c_buf = &c_buf[..utils::common::CHALLENGE_LEN];
75 writer.write_all(c_buf)?;
76 self.s.serialize_with_mode(&mut writer, compress)?;
77 Ok(())
78 }
79
80 fn serialized_size(&self, compress: ark_serialize::Compress) -> usize {
81 utils::common::CHALLENGE_LEN + self.s.serialized_size(compress)
82 }
83}
84
85impl<S: TinySuite> CanonicalDeserialize for Proof<S> {
86 fn deserialize_with_mode<R: ark_serialize::Read>(
87 mut reader: R,
88 compress: ark_serialize::Compress,
89 validate: ark_serialize::Validate,
90 ) -> Result<Self, ark_serialize::SerializationError> {
91 let mut c_buf = [0u8; utils::common::CHALLENGE_LEN];
92 if reader.read_exact(&mut c_buf[..]).is_err() {
93 return Err(ark_serialize::SerializationError::InvalidData);
94 }
95 let c = ScalarField::<S>::from_le_bytes_mod_order(&c_buf);
96 let s = <ScalarField<S> as CanonicalDeserialize>::deserialize_with_mode(
97 &mut reader,
98 compress,
99 validate,
100 )?;
101 Ok(Proof { c, s })
102 }
103}
104
105impl<S: TinySuite> ark_serialize::Valid for Proof<S> {
106 fn check(&self) -> Result<(), ark_serialize::SerializationError> {
107 self.c.check()?;
108 self.s.check()?;
109 Ok(())
110 }
111}
112
113pub trait Prover<S: TinySuite> {
115 fn prove(&self, ios: impl AsRef<[VrfIo<S>]>, ad: impl AsRef<[u8]>) -> Proof<S>;
119}
120
121pub trait Verifier<S: TinySuite> {
138 fn verify(
146 &self,
147 ios: impl AsRef<[VrfIo<S>]>,
148 aux: impl AsRef<[u8]>,
149 proof: &Proof<S>,
150 ) -> Result<(), Error>;
151}
152
153impl<S: TinySuite> Prover<S> for Secret<S> {
154 fn prove(&self, ios: impl AsRef<[VrfIo<S>]>, ad: impl AsRef<[u8]>) -> Proof<S> {
164 let (t, io) = vrf_transcript::<S>(self.public.0, ios, ad);
165
166 let k = S::nonce(&self.scalar, Some(t.clone()));
167
168 let r = smul!(io.input.0, k).into_affine();
170
171 let c = S::challenge(&[&r], Some(t));
172 let s = k + c * self.scalar;
173 Proof { c, s }
174 }
175}
176
177impl<S: TinySuite> Verifier<S> for Public<S> {
178 fn verify(
184 &self,
185 ios: impl AsRef<[VrfIo<S>]>,
186 ad: impl AsRef<[u8]>,
187 proof: &Proof<S>,
188 ) -> Result<(), Error> {
189 if self.is_identity() {
192 return Err(Error::InvalidData);
193 }
194
195 let ios = ios.as_ref();
198 if ios.iter().any(VrfIo::has_identity) {
199 return Err(Error::InvalidData);
200 }
201
202 let (t, io) = vrf_transcript::<S>(self.0, ios, ad);
203
204 let Proof { c, s } = proof;
205
206 let r = short_msm(&[io.input.0, io.output.0], &[*s, -*c], 2).into_affine();
208
209 let c_exp = S::challenge(&[&r], Some(t));
210 (c_exp == *c)
211 .then_some(())
212 .ok_or(Error::VerificationFailure)
213 }
214}
215
216#[cfg(test)]
217pub mod testing {
218 use super::*;
219 use crate::testing::{self as common, SuiteExt};
220
221 pub fn prove_verify<S: TinySuite>() {
222 let secret = Secret::<S>::from_seed(common::TEST_SEED);
223 let public = secret.public();
224 let input = Input::from_affine_unchecked(common::random_val(None));
225 let io = secret.vrf_io(input);
226
227 let proof = secret.prove(io, b"foo");
228 let result = public.verify(io, b"foo", &proof);
229 assert!(result.is_ok());
230 }
231
232 pub fn prove_verify_multi_empty<S: TinySuite>() {
233 let secret = Secret::<S>::from_seed(common::TEST_SEED);
234 let public = secret.public();
235
236 let ios: [VrfIo<S>; 0] = [];
237 let proof = secret.prove(ios, b"bar");
238
239 assert!(public.verify(ios, b"bar", &proof).is_ok());
240
241 assert!(public.verify(ios, b"baz", &proof).is_err());
243 }
244
245 pub fn prove_verify_multi_single<S: TinySuite>() {
247 let secret = Secret::<S>::from_seed(common::TEST_SEED);
248 let public = secret.public();
249 let input = Input::from_affine_unchecked(common::random_val(None));
250 let io = secret.vrf_io(input);
251
252 let proof_single = secret.prove(io, b"foo");
253 let proof_slice = secret.prove([io], b"foo");
254
255 let encode = |p: &tiny::Proof<S>| {
257 let mut buf = Vec::new();
258 p.serialize_compressed(&mut buf).unwrap();
259 buf
260 };
261 assert_eq!(encode(&proof_single), encode(&proof_slice));
262
263 assert!(public.verify(io, b"foo", &proof_slice).is_ok());
265 assert!(public.verify([io], b"foo", &proof_single).is_ok());
266 }
267
268 pub fn identity_public_key_rejected<S: TinySuite>() {
275 let identity = Public::<S>(AffinePoint::<S>::zero());
276 let zero_secret = Secret::<S>::from_scalar(ScalarField::<S>::zero());
277
278 let proof = zero_secret.prove([], b"forgery");
279 assert!(identity.verify([], b"forgery", &proof).is_err());
280 }
281
282 pub fn identity_io_pair_rejected<S: TinySuite>() {
291 let identity_io = VrfIo::<S> {
292 input: Input(AffinePoint::<S>::zero()),
293 output: Output(AffinePoint::<S>::zero()),
294 };
295
296 for seed in [common::TEST_SEED, [0x11; 32]] {
297 let secret = Secret::<S>::from_seed(seed);
298 let public = secret.public();
299
300 let proof = secret.prove([identity_io], b"forgery");
301 assert!(public.verify([identity_io], b"forgery", &proof).is_err());
302
303 let good_io = secret.vrf_io(Input::new(b"good").unwrap());
304 let ios = [good_io, identity_io];
305 let proof = secret.prove(ios, b"forgery");
306 assert!(public.verify(ios, b"forgery", &proof).is_err());
307 }
308 }
309
310 pub fn prove_verify_multi<S: TinySuite>() {
312 let secret = Secret::<S>::from_seed(common::TEST_SEED);
313 let public = secret.public();
314
315 let mut ios: Vec<VrfIo<S>> = (0..3u8)
316 .map(|i| {
317 let input = Input::new(&[i + 1]).unwrap();
318 secret.vrf_io(input)
319 })
320 .collect();
321 ios.push(VrfIo {
322 input: Input(S::Affine::generator()),
323 output: Output(public.0),
324 });
325
326 let proof = secret.prove(&ios[..], b"bar");
327 assert!(public.verify(&ios[..], b"bar", &proof).is_ok());
328
329 let mut bad_ios = ios.clone();
331 bad_ios[1].output = secret.output(ios[0].input);
332 assert!(public.verify(&bad_ios[..], b"bar", &proof).is_err());
333
334 let mut bad_ios = ios.clone();
336 bad_ios[0].input = ios[1].input;
337 assert!(public.verify(&bad_ios[..], b"bar", &proof).is_err());
338
339 assert!(public.verify(&ios[..], b"baz", &proof).is_err());
341 }
342
343 #[macro_export]
344 macro_rules! tiny_suite_tests {
345 ($suite:ty) => {
346 mod tiny {
347 use super::*;
348
349 #[test]
350 fn prove_verify() {
351 $crate::tiny::testing::prove_verify::<$suite>();
352 }
353
354 #[test]
355 fn prove_verify_multi_single() {
356 $crate::tiny::testing::prove_verify_multi_single::<$suite>();
357 }
358
359 #[test]
360 fn prove_verify_multi() {
361 $crate::tiny::testing::prove_verify_multi::<$suite>();
362 }
363
364 #[test]
365 fn prove_verify_multi_empty() {
366 $crate::tiny::testing::prove_verify_multi_empty::<$suite>();
367 }
368
369 #[test]
370 fn identity_public_key_rejected() {
371 $crate::tiny::testing::identity_public_key_rejected::<$suite>();
372 }
373
374 #[test]
375 fn identity_io_pair_rejected() {
376 $crate::tiny::testing::identity_io_pair_rejected::<$suite>();
377 }
378
379 $crate::test_vectors!($crate::tiny::testing::TestVector<$suite>);
380 }
381 };
382 }
383
384 pub struct TestVector<S: TinySuite> {
385 pub base: common::TestVector<S>,
386 pub c: ScalarField<S>,
387 pub s: ScalarField<S>,
388 }
389
390 impl<S: TinySuite> core::fmt::Debug for TestVector<S> {
391 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
392 let c = hex::encode(common::scalar_encode::<S>(&self.c));
393 let s = hex::encode(common::scalar_encode::<S>(&self.s));
394 f.debug_struct("TestVector")
395 .field("base", &self.base)
396 .field("proof_c", &c)
397 .field("proof_s", &s)
398 .finish()
399 }
400 }
401
402 impl<S> common::TestVectorTrait for TestVector<S>
403 where
404 S: TinySuite + SuiteExt + std::fmt::Debug,
405 {
406 fn name() -> String {
407 S::SUITE_NAME.to_string() + "_tiny"
408 }
409
410 fn new(comment: &str, seed: &[u8; 32], alpha: &[u8], ad: &[u8]) -> Self {
411 use super::Prover;
412 let base = common::TestVector::new(comment, seed, alpha, ad);
413 let io = VrfIo {
414 input: Input::from_affine_unchecked(base.h),
415 output: Output::from_affine_unchecked(base.gamma),
416 };
417 let sk = Secret::from_scalar(base.sk);
418 let proof: Proof<S> = sk.prove(io, ad);
419 Self {
420 base,
421 c: proof.c,
422 s: proof.s,
423 }
424 }
425
426 fn from_map(map: &common::TestVectorMap) -> Self {
427 let base = common::TestVector::from_map(map);
428 let c = common::scalar_decode::<S>(&map.get_bytes("proof_c"));
429 let s = common::scalar_decode::<S>(&map.get_bytes("proof_s"));
430 Self { base, c, s }
431 }
432
433 fn to_map(&self) -> common::TestVectorMap {
434 let buf = common::scalar_encode::<S>(&self.c);
435 let proof_c = &buf[..utils::common::CHALLENGE_LEN];
436 let items = [
437 ("proof_c", hex::encode(proof_c)),
438 ("proof_s", hex::encode(common::scalar_encode::<S>(&self.s))),
439 ];
440 let mut map = self.base.to_map();
441 items.into_iter().for_each(|(name, value)| {
442 map.0.insert(name.to_string(), value);
443 });
444 map
445 }
446
447 fn run(&self) {
448 self.base.run();
449 let io = VrfIo {
450 input: Input::<S>::from_affine_unchecked(self.base.h),
451 output: Output::from_affine_unchecked(self.base.gamma),
452 };
453 let sk = Secret::from_scalar(self.base.sk);
454 let proof = sk.prove(io, &self.base.ad);
455 assert_eq!(self.c, proof.c, "VRF proof challenge ('c') mismatch");
456 assert_eq!(self.s, proof.s, "VRF proof response ('s') mismatch");
457
458 let pk = Public(self.base.pk);
459 assert!(pk.verify(io, &self.base.ad, &proof).is_ok());
460 }
461 }
462}