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