p3_challenger/
grinding_challenger.rs1use p3_field::{Field, PrimeField, PrimeField32, PrimeField64};
2use p3_maybe_rayon::prelude::*;
3use p3_symmetric::CryptographicPermutation;
4use tracing::instrument;
5
6use crate::{
7 CanObserve, CanSampleBits, CanSampleUniformBits, DuplexChallenger, MultiField32Challenger,
8 UniformSamplingField,
9};
10
11pub trait GrindingChallenger:
21 CanObserve<Self::Witness> + CanSampleBits<usize> + Sync + Clone
22{
23 type Witness: Field;
25
26 fn grind(&mut self, bits: usize) -> Self::Witness;
32
33 #[must_use]
40 fn check_witness(&mut self, bits: usize, witness: Self::Witness) -> bool {
41 if bits == 0 {
42 return true;
43 }
44 self.observe(witness);
45 self.sample_bits(bits) == 0
46 }
47}
48
49pub trait UniformGrindingChallenger:
52 GrindingChallenger + CanSampleUniformBits<Self::Witness>
53{
54 fn grind_uniform(&mut self, bits: usize) -> Self::Witness;
60
61 fn grind_uniform_may_error(&mut self, bits: usize) -> Self::Witness;
67
68 fn check_witness_uniform(&mut self, bits: usize, witness: Self::Witness) -> bool {
76 self.observe(witness);
77 self.sample_uniform_bits::<true>(bits)
78 .expect("Error impossible here due to resampling strategy")
79 == 0
80 }
81
82 fn check_witness_uniform_may_error(&mut self, bits: usize, witness: Self::Witness) -> bool {
91 self.observe(witness);
92 self.sample_uniform_bits::<false>(bits)
93 .is_ok_and(|v| v == 0)
94 }
95}
96
97impl<F, P, const WIDTH: usize, const RATE: usize> GrindingChallenger
98 for DuplexChallenger<F, P, WIDTH, RATE>
99where
100 F: PrimeField64,
101 P: CryptographicPermutation<[F; WIDTH]>,
102{
103 type Witness = F;
104
105 #[instrument(name = "grind for proof-of-work witness", skip_all)]
106 fn grind(&mut self, bits: usize) -> Self::Witness {
107 assert!(bits < (usize::BITS as usize), "bit count must be valid");
108 assert!((1 << bits) < F::ORDER_U64);
109
110 let witness = (0..F::ORDER_U64)
111 .into_par_iter()
112 .map(|i| unsafe {
113 F::from_canonical_unchecked(i)
115 })
116 .find_any(|witness| self.clone().check_witness(bits, *witness))
117 .expect("failed to find witness");
118 assert!(self.check_witness(bits, witness));
119 witness
120 }
121}
122
123impl<F, P, const WIDTH: usize, const RATE: usize> UniformGrindingChallenger
124 for DuplexChallenger<F, P, WIDTH, RATE>
125where
126 F: UniformSamplingField + PrimeField64,
127 P: CryptographicPermutation<[F; WIDTH]>,
128{
129 #[instrument(name = "grind uniform for proof-of-work witness", skip_all)]
130 fn grind_uniform(&mut self, bits: usize) -> Self::Witness {
131 self.grind_generic(bits, |challenger, witness| {
133 challenger.check_witness_uniform(bits, witness)
134 })
135 }
136 #[instrument(name = "grind uniform may error for proof-of-work witness", skip_all)]
137 fn grind_uniform_may_error(&mut self, bits: usize) -> Self::Witness {
138 self.grind_generic(bits, |challenger, witness| {
140 challenger.check_witness_uniform_may_error(bits, witness)
141 })
142 }
143}
144impl<F, P, const WIDTH: usize, const RATE: usize> DuplexChallenger<F, P, WIDTH, RATE>
145where
146 F: PrimeField64,
147 P: CryptographicPermutation<[F; WIDTH]>,
148{
149 fn grind_generic<CHECK>(&mut self, bits: usize, check_fn: CHECK) -> F
151 where
152 CHECK: Fn(&mut Self, F) -> bool + Sync + Send,
153 {
154 assert!(bits < (usize::BITS as usize), "bit count must be valid");
156 assert!(
157 (1u64 << bits) < F::ORDER_U64,
158 "bit count exceeds field order"
159 );
160 let witness = (0..F::ORDER_U64)
162 .into_par_iter()
163 .map(|i| unsafe {
164 F::from_canonical_unchecked(i)
166 })
167 .find_any(|&witness| check_fn(&mut self.clone(), witness))
168 .expect("failed to find proof-of-work witness");
169 assert!(check_fn(self, witness));
172 witness
173 }
174}
175
176impl<F, PF, P, const WIDTH: usize, const RATE: usize> GrindingChallenger
177 for MultiField32Challenger<F, PF, P, WIDTH, RATE>
178where
179 F: PrimeField32,
180 PF: PrimeField,
181 P: CryptographicPermutation<[PF; WIDTH]>,
182{
183 type Witness = F;
184
185 #[instrument(name = "grind for proof-of-work witness", skip_all)]
186 fn grind(&mut self, bits: usize) -> Self::Witness {
187 assert!(bits < (usize::BITS as usize), "bit count must be valid");
188 assert!((1 << bits) < F::ORDER_U32);
189 let witness = (0..F::ORDER_U32)
190 .into_par_iter()
191 .map(|i| unsafe {
192 F::from_canonical_unchecked(i)
194 })
195 .find_any(|witness| self.clone().check_witness(bits, *witness))
196 .expect("failed to find witness");
197 assert!(self.check_witness(bits, witness));
198 witness
199 }
200}