1use alloc::vec::Vec;
2use core::marker::PhantomData;
3
4use p3_field::{BasedVectorSpace, PrimeField32, PrimeField64};
5use p3_maybe_rayon::prelude::*;
6use p3_symmetric::{CryptographicHasher, Hash, MerkleCap};
7use p3_util::log2_ceil_u64;
8use tracing::instrument;
9
10use crate::{
11 CanFinalizeDigest, CanObserve, CanSample, CanSampleBits, CanSampleUniformBits, FieldChallenger,
12 GrindingChallenger, HashChallenger, ResamplingError,
13};
14
15#[derive(Clone, Debug)]
25pub struct SerializingChallenger32<F, Inner> {
26 inner: Inner,
27 _marker: PhantomData<F>,
28}
29
30#[derive(Clone, Debug)]
40pub struct SerializingChallenger64<F, Inner> {
41 inner: Inner,
42 _marker: PhantomData<F>,
43}
44
45impl<F: PrimeField32, Inner: CanObserve<u8>> SerializingChallenger32<F, Inner> {
46 pub const fn new(inner: Inner) -> Self {
47 Self {
48 inner,
49 _marker: PhantomData,
50 }
51 }
52}
53
54impl<F, H> SerializingChallenger32<F, HashChallenger<u8, H, 32>>
55where
56 F: PrimeField32,
57 H: CryptographicHasher<u8, [u8; 32]>,
58{
59 pub const fn from_hasher(initial_state: Vec<u8>, hasher: H) -> Self {
60 Self::new(HashChallenger::new(initial_state, hasher))
61 }
62}
63
64impl<F: PrimeField32, Inner: CanObserve<u8>> CanObserve<F> for SerializingChallenger32<F, Inner> {
65 fn observe(&mut self, value: F) {
66 self.inner
67 .observe_slice(&value.to_unique_u32().to_le_bytes());
68 }
69}
70
71impl<F: PrimeField32, const N: usize, Inner: CanObserve<u8>> CanObserve<Hash<F, u8, N>>
72 for SerializingChallenger32<F, Inner>
73{
74 fn observe(&mut self, values: Hash<F, u8, N>) {
75 for value in values {
76 self.inner.observe(value);
77 }
78 }
79}
80
81impl<F: PrimeField32, const N: usize, Inner: CanObserve<u8>> CanObserve<Hash<F, u64, N>>
82 for SerializingChallenger32<F, Inner>
83{
84 fn observe(&mut self, values: Hash<F, u64, N>) {
85 for value in values {
86 self.inner.observe_slice(&value.to_le_bytes());
87 }
88 }
89}
90
91impl<F: PrimeField32, const N: usize, Inner: CanObserve<u8>> CanObserve<&MerkleCap<F, [u8; N]>>
92 for SerializingChallenger32<F, Inner>
93{
94 fn observe(&mut self, cap: &MerkleCap<F, [u8; N]>) {
95 for digest in cap.roots() {
96 for value in digest {
97 self.inner.observe(*value);
98 }
99 }
100 }
101}
102
103impl<F: PrimeField32, const N: usize, Inner: CanObserve<u8>> CanObserve<MerkleCap<F, [u8; N]>>
104 for SerializingChallenger32<F, Inner>
105{
106 fn observe(&mut self, cap: MerkleCap<F, [u8; N]>) {
107 self.observe(&cap);
108 }
109}
110
111impl<F: PrimeField32, const N: usize, Inner: CanObserve<u8>> CanObserve<&MerkleCap<F, [u64; N]>>
112 for SerializingChallenger32<F, Inner>
113{
114 fn observe(&mut self, cap: &MerkleCap<F, [u64; N]>) {
115 for digest in cap.roots() {
116 for value in digest {
117 self.inner.observe_slice(&value.to_le_bytes());
118 }
119 }
120 }
121}
122
123impl<F: PrimeField32, const N: usize, Inner: CanObserve<u8>> CanObserve<MerkleCap<F, [u64; N]>>
124 for SerializingChallenger32<F, Inner>
125{
126 fn observe(&mut self, cap: MerkleCap<F, [u64; N]>) {
127 self.observe(&cap);
128 }
129}
130
131impl<F, EF, Inner> CanSample<EF> for SerializingChallenger32<F, Inner>
132where
133 F: PrimeField32,
134 EF: BasedVectorSpace<F>,
135 Inner: CanSample<u8>,
136{
137 fn sample(&mut self) -> EF {
138 let modulus = F::ORDER_U32;
139 let log_size = log2_ceil_u64(F::ORDER_U64);
140 let pow_of_two_bound = ((1u64 << log_size) - 1) as u32;
142 let sample_base = |inner: &mut Inner| loop {
144 let value = u32::from_le_bytes(inner.sample_array());
145 let value = value & pow_of_two_bound;
146 if value < modulus {
147 return unsafe {
148 F::from_canonical_unchecked(value)
150 };
151 }
152 };
153 EF::from_basis_coefficients_fn(|_| sample_base(&mut self.inner))
154 }
155}
156
157impl<F, Inner> CanSampleBits<usize> for SerializingChallenger32<F, Inner>
158where
159 F: PrimeField32,
160 Inner: CanSample<u8>,
161{
162 fn sample_bits(&mut self, bits: usize) -> usize {
163 assert!(bits < (usize::BITS as usize));
164 assert!(
167 (1u64 << bits) < F::ORDER_U64,
168 "requested bit count must fit within the field order"
169 );
170 let rand_usize = u32::from_le_bytes(self.inner.sample_array()) as usize;
171 rand_usize & ((1 << bits) - 1)
172 }
173}
174
175impl<F, Inner> CanSampleUniformBits<F> for SerializingChallenger32<F, Inner>
176where
177 F: PrimeField32,
178 Inner: CanSample<u8>,
179{
180 fn sample_uniform_bits<const RESAMPLE: bool>(
193 &mut self,
194 bits: usize,
195 ) -> Result<usize, ResamplingError> {
196 Ok(self.sample_bits(bits))
199 }
200}
201
202impl<F, Inner> GrindingChallenger for SerializingChallenger32<F, Inner>
203where
204 F: PrimeField32,
205 Inner: CanSample<u8> + CanObserve<u8> + Clone + Send + Sync,
206{
207 type Witness = F;
208
209 #[instrument(name = "grind for proof-of-work witness", skip_all)]
210 fn grind(&mut self, bits: usize) -> Self::Witness {
211 assert!(bits < (usize::BITS as usize));
212 assert!(
215 (1u64 << bits) < F::ORDER_U64,
216 "requested bit count must fit within the field order"
217 );
218
219 if bits == 0 {
221 return F::ZERO;
222 }
223
224 let witness = (0..F::ORDER_U32)
225 .into_par_iter()
226 .map(|i| unsafe {
227 F::from_canonical_unchecked(i)
229 })
230 .find_any(|witness| self.clone().check_witness(bits, *witness))
231 .expect("failed to find witness");
232 assert!(self.check_witness(bits, witness));
233 witness
234 }
235}
236
237impl<F, Inner> FieldChallenger<F> for SerializingChallenger32<F, Inner>
238where
239 F: PrimeField32,
240 Inner: CanSample<u8> + CanObserve<u8> + Clone + Send + Sync,
241{
242}
243
244impl<F: PrimeField64, Inner: CanObserve<u8>> SerializingChallenger64<F, Inner> {
245 pub const fn new(inner: Inner) -> Self {
246 Self {
247 inner,
248 _marker: PhantomData,
249 }
250 }
251}
252
253impl<F, H> SerializingChallenger64<F, HashChallenger<u8, H, 32>>
254where
255 F: PrimeField64,
256 H: CryptographicHasher<u8, [u8; 32]>,
257{
258 pub const fn from_hasher(initial_state: Vec<u8>, hasher: H) -> Self {
259 Self::new(HashChallenger::new(initial_state, hasher))
260 }
261}
262
263impl<F: PrimeField64, Inner: CanObserve<u8>> CanObserve<F> for SerializingChallenger64<F, Inner> {
264 fn observe(&mut self, value: F) {
265 self.inner
266 .observe_slice(&value.to_unique_u64().to_le_bytes());
267 }
268}
269
270impl<F: PrimeField64, const N: usize, Inner: CanObserve<u8>> CanObserve<Hash<F, u8, N>>
271 for SerializingChallenger64<F, Inner>
272{
273 fn observe(&mut self, values: Hash<F, u8, N>) {
274 for value in values {
275 self.inner.observe(value);
276 }
277 }
278}
279
280impl<F: PrimeField64, const N: usize, Inner: CanObserve<u8>> CanObserve<Hash<F, u64, N>>
281 for SerializingChallenger64<F, Inner>
282{
283 fn observe(&mut self, values: Hash<F, u64, N>) {
284 for value in values {
285 self.inner.observe_slice(&value.to_le_bytes());
286 }
287 }
288}
289
290impl<F: PrimeField64, const N: usize, Inner: CanObserve<u8>> CanObserve<&MerkleCap<F, [u8; N]>>
291 for SerializingChallenger64<F, Inner>
292{
293 fn observe(&mut self, cap: &MerkleCap<F, [u8; N]>) {
294 for digest in cap.roots() {
295 for value in digest {
296 self.inner.observe(*value);
297 }
298 }
299 }
300}
301
302impl<F: PrimeField64, const N: usize, Inner: CanObserve<u8>> CanObserve<MerkleCap<F, [u8; N]>>
303 for SerializingChallenger64<F, Inner>
304{
305 fn observe(&mut self, cap: MerkleCap<F, [u8; N]>) {
306 self.observe(&cap);
307 }
308}
309
310impl<F: PrimeField64, const N: usize, Inner: CanObserve<u8>> CanObserve<&MerkleCap<F, [u64; N]>>
311 for SerializingChallenger64<F, Inner>
312{
313 fn observe(&mut self, cap: &MerkleCap<F, [u64; N]>) {
314 for digest in cap.roots() {
315 for value in digest {
316 self.inner.observe_slice(&value.to_le_bytes());
317 }
318 }
319 }
320}
321
322impl<F: PrimeField64, const N: usize, Inner: CanObserve<u8>> CanObserve<MerkleCap<F, [u64; N]>>
323 for SerializingChallenger64<F, Inner>
324{
325 fn observe(&mut self, cap: MerkleCap<F, [u64; N]>) {
326 self.observe(&cap);
327 }
328}
329
330impl<F, EF, Inner> CanSample<EF> for SerializingChallenger64<F, Inner>
331where
332 F: PrimeField64,
333 EF: BasedVectorSpace<F>,
334 Inner: CanSample<u8>,
335{
336 fn sample(&mut self) -> EF {
337 let modulus = F::ORDER_U64;
338 let log_size = log2_ceil_u64(F::ORDER_U64) as u32;
339 let pow_of_two_bound = ((1u128 << log_size) - 1) as u64;
341
342 let sample_base = |inner: &mut Inner| loop {
344 let value = u64::from_le_bytes(inner.sample_array());
345 let value = value & pow_of_two_bound;
346 if value < modulus {
347 return unsafe {
348 F::from_canonical_unchecked(value)
350 };
351 }
352 };
353 EF::from_basis_coefficients_fn(|_| sample_base(&mut self.inner))
354 }
355}
356
357impl<F, Inner> CanSampleBits<usize> for SerializingChallenger64<F, Inner>
358where
359 F: PrimeField64,
360 Inner: CanSample<u8>,
361{
362 fn sample_bits(&mut self, bits: usize) -> usize {
363 assert!(bits < (usize::BITS as usize));
364 assert!((1u64 << bits) <= F::ORDER_U64);
365 let rand_u64 = u64::from_le_bytes(self.inner.sample_array());
366 (rand_u64 & ((1u64 << bits) - 1)) as usize
367 }
368}
369
370impl<F, Inner> CanSampleUniformBits<F> for SerializingChallenger64<F, Inner>
371where
372 F: PrimeField64,
373 Inner: CanSample<u8>,
374{
375 fn sample_uniform_bits<const RESAMPLE: bool>(
388 &mut self,
389 bits: usize,
390 ) -> Result<usize, ResamplingError> {
391 Ok(self.sample_bits(bits))
394 }
395}
396
397impl<F, Inner> GrindingChallenger for SerializingChallenger64<F, Inner>
398where
399 F: PrimeField64,
400 Inner: CanSample<u8> + CanObserve<u8> + Clone + Send + Sync,
401{
402 type Witness = F;
403
404 #[instrument(name = "grind for proof-of-work witness", skip_all)]
405 fn grind(&mut self, bits: usize) -> Self::Witness {
406 assert!(bits < 64);
407 assert!((1u64 << bits) < F::ORDER_U64);
408
409 if bits == 0 {
411 return F::ZERO;
412 }
413
414 let witness = (0..F::ORDER_U64)
415 .into_par_iter()
416 .map(|i| unsafe {
417 F::from_canonical_unchecked(i)
419 })
420 .find_any(|witness| self.clone().check_witness(bits, *witness))
421 .expect("failed to find witness");
422 assert!(self.check_witness(bits, witness));
423 witness
424 }
425}
426
427impl<F, Inner> FieldChallenger<F> for SerializingChallenger64<F, Inner>
428where
429 F: PrimeField64,
430 Inner: CanSample<u8> + CanObserve<u8> + Clone + Send + Sync,
431{
432}
433
434impl<F, Inner> CanFinalizeDigest for SerializingChallenger32<F, Inner>
435where
436 Inner: CanFinalizeDigest,
437{
438 type Digest = Inner::Digest;
439
440 fn finalize(self) -> Self::Digest {
441 self.inner.finalize()
442 }
443}
444
445impl<F, Inner> CanFinalizeDigest for SerializingChallenger64<F, Inner>
446where
447 Inner: CanFinalizeDigest,
448{
449 type Digest = Inner::Digest;
450
451 fn finalize(self) -> Self::Digest {
452 self.inner.finalize()
453 }
454}
455
456#[cfg(test)]
457mod tests {
458 use alloc::vec;
459
460 use p3_baby_bear::BabyBear;
461 use p3_field::PrimeCharacteristicRing;
462 use p3_goldilocks::Goldilocks;
463 use p3_symmetric::CryptographicHasher;
464
465 use super::*;
466 use crate::HashChallenger;
467
468 #[derive(Clone)]
472 struct ByteCountHasher;
473
474 impl CryptographicHasher<u8, [u8; 32]> for ByteCountHasher {
475 fn hash_iter<I>(&self, input: I) -> [u8; 32]
476 where
477 I: IntoIterator<Item = u8>,
478 {
479 let len = input.into_iter().count() as u8;
480 core::array::from_fn(|i| len.wrapping_add(i as u8))
481 }
482
483 fn hash_iter_slices<'a, I>(&self, input: I) -> [u8; 32]
484 where
485 I: IntoIterator<Item = &'a [u8]>,
486 {
487 let len = input.into_iter().map(<[u8]>::len).sum::<usize>() as u8;
488 core::array::from_fn(|i| len.wrapping_add(i as u8))
489 }
490 }
491
492 type Inner = HashChallenger<u8, ByteCountHasher, 32>;
493
494 #[test]
495 fn test_serializing_challenger32_grind_zero_bits_returns_zero() {
496 type F = BabyBear;
498 let inner = Inner::new(vec![0, 1, 2, 3], ByteCountHasher);
499 let mut challenger = SerializingChallenger32::<F, Inner>::new(inner);
500
501 let mut shadow = challenger.clone();
503
504 let witness = challenger.grind(0);
505
506 assert_eq!(witness, F::ZERO);
507 let after_grind: u8 = challenger.inner.sample();
508 let no_grind: u8 = shadow.inner.sample();
509 assert_eq!(after_grind, no_grind);
510 }
511
512 #[test]
513 fn test_serializing_challenger64_grind_zero_bits_returns_zero() {
514 type F = Goldilocks;
516 let inner = Inner::new(vec![0, 1, 2, 3], ByteCountHasher);
517 let mut challenger = SerializingChallenger64::<F, Inner>::new(inner);
518
519 let mut shadow = challenger.clone();
521
522 let witness = challenger.grind(0);
523
524 assert_eq!(witness, F::ZERO);
525 let after_grind: u8 = challenger.inner.sample();
526 let no_grind: u8 = shadow.inner.sample();
527 assert_eq!(after_grind, no_grind);
528 }
529
530 #[test]
531 #[should_panic = "requested bit count must fit within the field order"]
532 fn test_serializing_challenger32_sample_bits_rejects_oversized_request() {
533 type F = BabyBear;
536 let inner = Inner::new(vec![0, 1, 2, 3], ByteCountHasher);
537 let mut challenger = SerializingChallenger32::<F, Inner>::new(inner);
538 let _ = challenger.sample_bits(32);
539 }
540
541 #[test]
542 #[should_panic = "requested bit count must fit within the field order"]
543 fn test_serializing_challenger32_grind_rejects_oversized_request() {
544 type F = BabyBear;
546 let inner = Inner::new(vec![0, 1, 2, 3], ByteCountHasher);
547 let mut challenger = SerializingChallenger32::<F, Inner>::new(inner);
548 let _ = challenger.grind(32);
549 }
550}