1use super::concat;
7use crate::{simple::TrancheIndex, Entropy, TicketId};
8use ark_vrf::{
9 reexports::ark_serialize::{CanonicalDeserialize, CanonicalSerialize},
10 suites::bandersnatch::{self, AffinePoint, Secret as SecretImpl},
11};
12use codec::{Decode, Encode, MaxEncodedLen};
13use jam_types::{AnyVec, OpaqueBandersnatchPublic, TicketAttempt};
14
15pub use ark_vrf::Error;
16
17const SCALAR_SERIALIZED_SIZE: usize = 32;
18const POINT_SERIALIZED_SIZE: usize = 32;
19
20pub const PUBLIC_SERIALIZED_SIZE: usize = POINT_SERIALIZED_SIZE;
21pub const PREOUT_SERIALIZED_SIZE: usize = POINT_SERIALIZED_SIZE;
22
23const ERR_MSG: &str = "object length is constant and checked by test; qed";
24
25type Seed = [u8; SCALAR_SERIALIZED_SIZE];
27
28#[derive(Clone, Copy, PartialEq, Eq, Hash, Encode, Decode, MaxEncodedLen, Default)]
30pub struct Public(pub [u8; PUBLIC_SERIALIZED_SIZE]);
31
32impl Public {
33 pub fn is_valid(&self) -> bool {
34 AffinePoint::deserialize_compressed_unchecked(&self.0[..]).is_ok()
35 }
36}
37
38impl std::fmt::Debug for Public {
39 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40 write!(f, "{:?}", AnyVec(self.0.to_vec()))
41 }
42}
43
44impl std::fmt::Display for Public {
45 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46 write!(f, "{}", AnyVec(self.0.to_vec()))
47 }
48}
49
50impl From<OpaqueBandersnatchPublic> for Public {
51 fn from(opaque: OpaqueBandersnatchPublic) -> Self {
52 Self(opaque.0)
53 }
54}
55impl From<Public> for OpaqueBandersnatchPublic {
56 fn from(public: Public) -> Self {
57 Self(public.0)
58 }
59}
60
61#[derive(Clone)]
63pub struct Secret(SecretImpl);
64
65impl Secret {
66 pub fn new(rng: &mut impl rand::CryptoRng) -> Self {
68 Self::from_seed(rand::Rng::random(rng))
69 }
70
71 pub fn from_seed(seed: Seed) -> Self {
73 Self(SecretImpl::from_seed(&seed))
74 }
75
76 pub fn public(&self) -> Public {
78 let public = self.0.public();
79 let mut raw = [0; PUBLIC_SERIALIZED_SIZE];
80 public.serialize_compressed(raw.as_mut_slice()).expect(ERR_MSG);
81 Public(raw)
82 }
83
84 pub fn generate() -> Self {
86 Self::new(&mut rand::rng())
87 }
88}
89
90pub enum Message {
92 TicketSeal(Entropy, TicketAttempt),
94 FallbackSeal(Entropy),
96 Entropy(TicketId),
98 AuditInitial(Entropy),
100 AuditSubsequent(Entropy, jam_types::WorkReportHash, TrancheIndex),
102}
103
104impl Message {
105 pub fn using_encoded<R>(&self, f: impl FnOnce(&[u8]) -> R) -> R {
107 match self {
108 Self::TicketSeal(entropy, attempt) =>
109 f(concat(&mut [0; 15 + 32 + 1], &[b"jam_ticket_seal", &entropy.0, &[*attempt]])),
110 Self::FallbackSeal(entropy) =>
111 f(concat(&mut [0; 17 + 32], &[b"jam_fallback_seal", &entropy.0])),
112 Self::Entropy(ticket_id) =>
113 f(concat(&mut [0; 11 + 32], &[b"jam_entropy", &ticket_id.0])),
114 Self::AuditInitial(entropy_source) =>
115 f(concat(&mut [0; 9 + 32], &[b"jam_audit", &entropy_source.0])),
116 Self::AuditSubsequent(entropy_source, report, index) => f(concat(
117 &mut [0; 9 + 64 + 1],
118 &[b"jam_audit", &entropy_source.0, &report.0, &[*index]],
119 )),
120 }
121 }
122}
123
124#[inline(always)]
126fn vrf_input(message: &Message) -> bandersnatch::Input {
127 message
128 .using_encoded(|enc| bandersnatch::Input::new(enc).expect("Elligator2 H2C is infallible"))
129}
130
131pub mod vrf {
133 use super::*;
134 use ark_vrf::ietf::{Prover, Verifier};
135 use codec::ConstEncodedLen;
136
137 pub(crate) const PROOF_SERIALIZED_SIZE: usize = 64;
138 pub const SIGNATURE_SERIALIZED_SIZE: usize = PREOUT_SERIALIZED_SIZE + PROOF_SERIALIZED_SIZE;
139
140 #[derive(Clone, Debug, PartialEq, Eq, Encode, Decode, MaxEncodedLen)]
142 pub struct Signature(pub [u8; SIGNATURE_SERIALIZED_SIZE]);
143
144 impl ConstEncodedLen for Signature {}
145
146 impl Signature {
147 pub fn vrf_output(&self) -> Entropy {
149 bandersnatch::Output::deserialize_compressed_unchecked(
150 &self.0[..PREOUT_SERIALIZED_SIZE],
151 )
152 .map(|p| {
153 let mut raw = [0u8; 32];
154 raw.copy_from_slice(&p.hash()[..32]);
155 Entropy(raw)
156 })
157 .unwrap_or_default()
158 }
159
160 pub fn vrf_verify(
162 &self,
163 message: &Message,
164 aux_data: &[u8],
165 public: &Public,
166 ) -> Result<(), Error> {
167 public.vrf_verify(message, aux_data, self)
168 }
169 }
170
171 impl Secret {
172 pub fn vrf_sign(&self, message: &Message, aux_data: &[u8]) -> Signature {
176 let input = vrf_input(message);
177 let output = self.0.output(input);
178 let proof = self.0.prove(input, output, aux_data);
179 let mut raw = [0_u8; SIGNATURE_SERIALIZED_SIZE];
180 output.serialize_compressed(&mut raw[..PREOUT_SERIALIZED_SIZE]).expect(ERR_MSG);
181 proof.serialize_compressed(&mut raw[PREOUT_SERIALIZED_SIZE..]).expect(ERR_MSG);
182 Signature(raw)
183 }
184
185 pub fn vrf_output(&self, message: &Message) -> Entropy {
187 let input = vrf_input(message);
188 let hash = self.0.output(input).hash();
189 let mut raw = [0u8; 32];
190 raw.copy_from_slice(&hash[..32]);
191 Entropy(raw)
192 }
193 }
194
195 impl Public {
196 pub fn vrf_verify(
198 &self,
199 message: &Message,
200 aux_data: &[u8],
201 signature: &Signature,
202 ) -> Result<(), Error> {
203 let public = bandersnatch::Public::deserialize_compressed_unchecked(self.0.as_ref())
204 .map_err(|_| Error::InvalidData)?;
205 let output = bandersnatch::Output::deserialize_compressed_unchecked(
206 &signature.0[..PREOUT_SERIALIZED_SIZE],
207 )
208 .map_err(|_| Error::InvalidData)?;
209 let proof = bandersnatch::IetfProof::deserialize_compressed_unchecked(
210 &signature.0[PREOUT_SERIALIZED_SIZE..],
211 )
212 .map_err(|_| Error::InvalidData)?;
213 let input = vrf_input(message);
214 public.verify(input, output, aux_data, &proof)
215 }
216 }
217
218 impl AsRef<[u8]> for Public {
219 fn as_ref(&self) -> &[u8] {
220 &self.0
221 }
222 }
223}
224
225pub mod ring_vrf {
226 use super::*;
227 use ark_vrf::ring::{Prover, Verifier};
228 use bandersnatch::{RingCommitment as RingCommitmentImpl, RingProofParams};
229 pub use bandersnatch::{RingProver, RingVerifier};
230
231 pub const RING_COMMITMENT_SERIALIZED_SIZE: usize = 144;
232
233 pub const RING_PROOF_SERIALIZED_SIZE: usize = 752;
234
235 pub const RING_SIGNATURE_SERIALIZED_SIZE: usize =
236 PREOUT_SERIALIZED_SIZE + RING_PROOF_SERIALIZED_SIZE;
237
238 #[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen)]
239 pub struct RingCommitment(pub [u8; RING_COMMITMENT_SERIALIZED_SIZE]);
240
241 #[derive(Clone, Debug, PartialEq, Eq, Encode, Decode, MaxEncodedLen)]
243 pub struct Signature(pub [u8; RING_SIGNATURE_SERIALIZED_SIZE]);
244
245 impl Signature {
246 pub fn ring_vrf_verify(
251 &self,
252 message: &Message,
253 aux_data: &[u8],
254 verifier: &RingVerifier,
255 ) -> Result<(), Error> {
256 let output = bandersnatch::Output::deserialize_compressed_unchecked(
257 &self.0[..PREOUT_SERIALIZED_SIZE],
258 )
259 .map_err(|_| Error::InvalidData)?;
260 let proof = bandersnatch::RingProof::deserialize_compressed_unchecked(
261 &self.0[PREOUT_SERIALIZED_SIZE..],
262 )
263 .map_err(|_| Error::InvalidData)?;
264 let input = vrf_input(message);
265 bandersnatch::Public::verify(input, output, aux_data, &proof, verifier)
266 }
267
268 pub fn vrf_output(&self) -> Entropy {
270 bandersnatch::Output::deserialize_compressed_unchecked(
271 &self.0[..PREOUT_SERIALIZED_SIZE],
272 )
273 .map(|p| {
274 let mut raw = [0u8; 32];
275 raw.copy_from_slice(&p.hash()[..32]);
276 Entropy(raw)
277 })
278 .unwrap_or_default()
279 }
280 }
281
282 impl Secret {
283 pub fn ring_vrf_sign(
287 &self,
288 message: &Message,
289 aux_data: &[u8],
290 prover: &RingProver,
291 ) -> Signature {
292 let input = vrf_input(message);
293 let output = self.0.output(input);
294 let proof = self.0.prove(input, output, aux_data, prover);
295 let mut raw = [0_u8; RING_SIGNATURE_SERIALIZED_SIZE];
296 output.serialize_compressed(&mut raw[..PREOUT_SERIALIZED_SIZE]).expect(ERR_MSG);
297 proof.serialize_compressed(&mut raw[PREOUT_SERIALIZED_SIZE..]).expect(ERR_MSG);
298 Signature(raw)
299 }
300 }
301
302 #[derive(Clone)]
304 pub struct RingContext;
305
306 impl RingContext {
307 pub fn params() -> &'static RingProofParams {
309 use std::sync::OnceLock;
310 static PARAMS: OnceLock<RingProofParams> = OnceLock::new();
311 PARAMS.get_or_init(|| {
312 use bandersnatch::PcsParams;
313 let buf = include_bytes!(concat!(
315 env!("CARGO_MANIFEST_DIR"),
316 "/data/zcash-srs-2-11-uncompressed.bin"
317 ));
318 let pcs_params = PcsParams::deserialize_uncompressed_unchecked(&mut &buf[..])
319 .expect("Error deserializing PcsParam");
320 RingProofParams::from_pcs_params(jam_types::val_count() as usize, pcs_params)
321 .expect("Error constructing RingProofParams from PcsParams")
322 })
323 }
324
325 pub fn prover(public_keys: &[Public], public_index: usize) -> RingProver {
329 let params = Self::params();
330 let pks = public_to_affine(public_keys);
331 let prover_key = params.prover_key(&pks);
332 params.prover(prover_key, public_index)
333 }
334
335 pub fn verifier(public_keys: &[Public]) -> RingVerifier {
339 let params = Self::params();
340 let pks = public_to_affine(public_keys);
341 let verifier_key = params.verifier_key(&pks);
342 params.verifier(verifier_key)
343 }
344
345 pub fn commitment(public_keys: &[Public]) -> RingCommitment {
349 let params = Self::params();
350 let pks = public_to_affine(public_keys);
351 let verifier_key = params.verifier_key(&pks);
352 let commitment = verifier_key.commitment();
353 let mut raw = [0; RING_COMMITMENT_SERIALIZED_SIZE];
354 commitment.serialize_compressed(&mut raw[..]).expect(ERR_MSG);
355 RingCommitment(raw)
356 }
357
358 pub fn verifier_from_commitment(commitment: RingCommitment) -> Result<RingVerifier, Error> {
360 let params = Self::params();
361 let mut raw = &commitment.0[..];
362 let commitment = RingCommitmentImpl::deserialize_compressed_unchecked(&mut raw)
363 .map_err(|_| Error::InvalidData)?;
364 let verifier_key = params.verifier_key_from_commitment(commitment);
365 Ok(params.verifier(verifier_key))
366 }
367 }
368
369 #[inline(always)]
374 fn public_to_affine(pks: &[Public]) -> Vec<AffinePoint> {
375 pks.iter()
376 .map(|pk| {
377 AffinePoint::deserialize_compressed_unchecked(&pk.0[..])
378 .unwrap_or(RingProofParams::padding_point())
379 })
380 .collect()
381 }
382}
383
384#[cfg(all(test, feature = "full-test-suite"))]
385mod tests {
386 #![allow(clippy::unwrap_used)]
387 use super::{ring_vrf::*, vrf::*, *};
388 use crate::NewNull;
389 use ring_vrf::RING_COMMITMENT_SERIALIZED_SIZE;
390
391 const SEED_SERIALIZED_SIZE: usize = 32;
392 const RING_KEYSET_SIZE: usize = 1023;
393
394 const DEV_SEED: [u8; SEED_SERIALIZED_SIZE] = [0xcb; SEED_SERIALIZED_SIZE];
395
396 #[allow(dead_code)]
397 fn serialize<T: CanonicalSerialize>(obj: &T) -> Vec<u8> {
398 let mut buf = Vec::new();
399 obj.serialize_compressed(&mut buf).unwrap();
400 buf
401 }
402
403 #[test]
404 fn backend_assumptions_check() {
405 use ark_vrf::reexports::ark_std;
406 use bandersnatch::RingProofParams;
407 const EXPECTED_DOMAIN_OVERHEAD: usize = 257;
408
409 let ctx = RingProofParams::from_seed(RING_KEYSET_SIZE, [0; 32]);
410
411 let expected_domain_size = 1 << ark_std::log2(RING_KEYSET_SIZE + EXPECTED_DOMAIN_OVERHEAD);
412 assert_eq!(ctx.max_ring_size(), expected_domain_size - EXPECTED_DOMAIN_OVERHEAD);
413
414 let pks: Vec<_> =
415 (0..16).map(|i| SecretImpl::from_seed(&[i as u8; 32]).public().0).collect();
416
417 let secret = SecretImpl::from_seed(&[0u8; 32]);
418
419 let public = secret.public();
420 assert_eq!(public.compressed_size(), PUBLIC_SERIALIZED_SIZE);
421
422 let input = vrf_input(&Message::FallbackSeal(Default::default()));
423 let output = secret.output(input);
424 assert_eq!(output.compressed_size(), PREOUT_SERIALIZED_SIZE);
425
426 let prover_key = ctx.prover_key(&pks);
427 let prover = ctx.prover(prover_key, 0);
428
429 let verifier_key = ctx.verifier_key(&pks);
430 let commitment = verifier_key.commitment();
431 assert_eq!(commitment.compressed_size(), RING_COMMITMENT_SERIALIZED_SIZE);
432
433 let ietf_proof = {
434 use ark_vrf::ietf::Prover;
435 secret.prove(input, output, [])
436 };
437 assert_eq!(ietf_proof.compressed_size(), PROOF_SERIALIZED_SIZE);
438
439 let ring_proof = {
440 use ark_vrf::ring::Prover;
441 secret.prove(input, output, [], &prover)
442 };
443 assert_eq!(ring_proof.compressed_size(), RING_PROOF_SERIALIZED_SIZE);
444
445 let padding_raw = [
448 0x92, 0xca, 0x79, 0xe6, 0x1d, 0xd9, 0x0c, 0x15, 0x73, 0xa8, 0x69, 0x3f, 0x19, 0x9b,
449 0xf6, 0xe1, 0xe8, 0x68, 0x35, 0xcc, 0x71, 0x5c, 0xdc, 0xf9, 0x3f, 0x5e, 0xf2, 0x22,
450 0x56, 0x00, 0x23, 0xaa,
451 ];
452 let padding_point = AffinePoint::deserialize_compressed(&padding_raw[..]).unwrap();
453 assert_eq!(RingProofParams::padding_point(), padding_point);
454 }
455
456 fn encode_decode<T: Encode + Decode + PartialEq + std::fmt::Debug>(expected_len: usize) {
457 let obj = T::new_null();
458 let buf = obj.encode();
459 assert_eq!(buf.len(), expected_len);
460 let dec = T::decode(&mut buf.as_slice()).unwrap();
461 assert_eq!(obj, dec);
462 }
463
464 #[test]
465 fn codec_works() {
466 encode_decode::<Public>(PUBLIC_SERIALIZED_SIZE);
467 encode_decode::<vrf::Signature>(SIGNATURE_SERIALIZED_SIZE);
468 encode_decode::<ring_vrf::Signature>(RING_SIGNATURE_SERIALIZED_SIZE);
469 }
470
471 #[test]
472 fn vrf_sign_verify() {
473 let secret = Secret::from_seed(DEV_SEED);
474 let public = secret.public();
475
476 let input = Message::FallbackSeal(Default::default());
477 let ad = b"data";
478
479 let signature = secret.vrf_sign(&input, ad);
480
481 assert!(public.vrf_verify(&input, ad, &signature).is_ok());
482
483 assert!(public.vrf_verify(&input, b"bad", &signature).is_err());
485
486 assert!(public
488 .vrf_verify(&Message::FallbackSeal([1; 32].into()), ad, &signature)
489 .is_err());
490 }
491
492 #[test]
493 fn vrf_output_hash_matches() {
494 let secret = Secret::from_seed(DEV_SEED);
495
496 let input = Message::FallbackSeal(Default::default());
497 let signature = secret.vrf_sign(&input, b"data");
498
499 let output1 = secret.vrf_output(&input);
500 let output2 = signature.vrf_output();
501 assert_eq!(output1, output2);
502 }
503
504 #[test]
505 fn ring_vrf_sign_verify() {
506 let mut pks: Vec<_> = (0..16).map(|i| Secret::from_seed([i as u8; 32]).public()).collect();
507 assert!(pks.len() <= RING_KEYSET_SIZE);
508
509 let secret = Secret::from_seed(DEV_SEED);
510
511 let input = Message::FallbackSeal(Default::default());
512 let ad = b"data";
513
514 let prover_index = 3;
516 pks[prover_index] = secret.public();
517
518 let prover = RingContext::prover(&pks, prover_index);
519 let signature = secret.ring_vrf_sign(&input, ad, &prover);
520
521 let verifier = RingContext::verifier(&pks);
522 assert!(signature.ring_vrf_verify(&input, ad, &verifier).is_ok());
523
524 assert!(signature.ring_vrf_verify(&input, b"bad", &verifier).is_err());
526
527 assert!(signature
529 .ring_vrf_verify(&Message::FallbackSeal([1; 32].into()), ad, &verifier)
530 .is_err());
531 }
532
533 #[test]
534 fn ring_vrf_sign_verify_with_out_of_ring_key() {
535 let pks: Vec<_> = (0..16).map(|i| Secret::from_seed([i as u8; 32]).public()).collect();
536 let secret = Secret::from_seed(DEV_SEED);
537
538 let input = Message::FallbackSeal(Default::default());
539 let ad = b"data";
540
541 let prover = RingContext::prover(&pks, 0);
543 let signature = secret.ring_vrf_sign(&input, ad, &prover);
544
545 let verifier = RingContext::verifier(&pks);
546 assert!(signature.ring_vrf_verify(&input, ad, &verifier).is_err());
547 }
548
549 #[test]
550 fn ring_vrf_make_bytes_matches() {
551 let mut pks: Vec<_> = (0..16).map(|i| Secret::from_seed([i as u8; 32]).public()).collect();
552 assert!(pks.len() <= RING_KEYSET_SIZE);
553
554 let secret = Secret::from_seed(DEV_SEED);
555
556 let prover_index = 3;
558 pks[prover_index] = secret.public();
559
560 let input = Message::FallbackSeal(Default::default());
561
562 let prover = RingContext::prover(&pks, prover_index);
563 let signature = secret.ring_vrf_sign(&input, b"data", &prover);
564
565 let output1 = secret.vrf_output(&input);
566 let output2 = signature.vrf_output();
567 assert_eq!(output1, output2);
568 }
569}