p3_challenger/
grinding_challenger.rs
1use p3_field::{Field, PrimeField, PrimeField32, PrimeField64};
2use p3_maybe_rayon::prelude::*;
3use p3_symmetric::CryptographicPermutation;
4use tracing::instrument;
5
6use crate::{CanObserve, CanSampleBits, DuplexChallenger, MultiField32Challenger};
7
8pub trait GrindingChallenger:
9 CanObserve<Self::Witness> + CanSampleBits<usize> + Sync + Clone
10{
11 type Witness: Field;
12
13 fn grind(&mut self, bits: usize) -> Self::Witness;
14
15 #[must_use]
16 fn check_witness(&mut self, bits: usize, witness: Self::Witness) -> bool {
17 self.observe(witness);
18 self.sample_bits(bits) == 0
19 }
20}
21
22impl<F, P, const WIDTH: usize, const RATE: usize> GrindingChallenger
23 for DuplexChallenger<F, P, WIDTH, RATE>
24where
25 F: PrimeField64,
26 P: CryptographicPermutation<[F; WIDTH]>,
27{
28 type Witness = F;
29
30 #[instrument(name = "grind for proof-of-work witness", skip_all)]
31 fn grind(&mut self, bits: usize) -> Self::Witness {
32 assert!(bits < (usize::BITS as usize));
33 assert!((1 << bits) < F::ORDER_U64);
34
35 let witness = (0..F::ORDER_U64)
36 .into_par_iter()
37 .map(|i| F::from_canonical_u64(i))
38 .find_any(|witness| self.clone().check_witness(bits, *witness))
39 .expect("failed to find witness");
40 assert!(self.check_witness(bits, witness));
41 witness
42 }
43}
44
45impl<F, PF, P, const WIDTH: usize, const RATE: usize> GrindingChallenger
46 for MultiField32Challenger<F, PF, P, WIDTH, RATE>
47where
48 F: PrimeField32,
49 PF: PrimeField,
50 P: CryptographicPermutation<[PF; WIDTH]>,
51{
52 type Witness = F;
53
54 #[instrument(name = "grind for proof-of-work witness", skip_all)]
55 fn grind(&mut self, bits: usize) -> Self::Witness {
56 assert!(bits < (usize::BITS as usize));
57 assert!((1 << bits) < F::ORDER_U64);
58 let witness = (0..F::ORDER_U64)
59 .into_par_iter()
60 .map(F::from_canonical_u64)
61 .find_any(|witness| self.clone().check_witness(bits, *witness))
62 .expect("failed to find witness");
63 assert!(self.check_witness(bits, witness));
64 witness
65 }
66}