diff --git a/challenger/src/serializing_challenger.rs b/challenger/src/serializing_challenger.rs index 57796e65..d7f66f93 100644 --- a/challenger/src/serializing_challenger.rs +++ b/challenger/src/serializing_challenger.rs @@ -21,9 +21,9 @@ use crate::{ /// - Samples a field element in a prime field of size `p` by sampling uniformly an element in the /// range (0..1 << log_2(p)). This avoids modulo bias. #[derive(Clone, Debug)] -pub struct SerializingChallenger32 { +pub struct SerializingChallenger32 { inner: Inner, - _marker: PhantomData, + _marker: PhantomData<(F, T)>, } /// Given a challenger that can observe and sample bytes, produces a challenger that is able to @@ -41,7 +41,7 @@ pub struct SerializingChallenger64 { _marker: PhantomData, } -impl> SerializingChallenger32 { +impl> SerializingChallenger32 { pub fn new(inner: Inner) -> Self { Self { inner, @@ -50,34 +50,45 @@ impl> SerializingChallenger32 { } } -impl SerializingChallenger32> +impl SerializingChallenger32> where F: PrimeField32, - H: CryptographicHasher, + H: CryptographicHasher, + T: Clone, { - pub fn from_hasher(initial_state: Vec, hasher: H) -> Self { + pub fn from_hasher(initial_state: Vec, hasher: H) -> Self { Self::new(HashChallenger::new(initial_state, hasher)) } } -impl> CanObserve for SerializingChallenger32 { +impl> CanObserve + for SerializingChallenger32 +{ fn observe(&mut self, value: F) { self.inner .observe_slice(&value.as_canonical_u32().to_le_bytes()); } } -impl> CanObserve> - for SerializingChallenger32 +impl> CanObserve + for SerializingChallenger32 { - fn observe(&mut self, values: Hash) { + fn observe(&mut self, value: F) { + self.inner.observe(value.as_canonical_u32()); + } +} + +impl> CanObserve> + for SerializingChallenger32 +{ + fn observe(&mut self, values: Hash) { for value in values { self.inner.observe(value); } } } -impl CanSample for SerializingChallenger32 +impl CanSample for SerializingChallenger32 where F: PrimeField32, EF: ExtensionField, @@ -99,7 +110,29 @@ where } } -impl CanSampleBits for SerializingChallenger32 +impl CanSample for SerializingChallenger32 +where + F: PrimeField32, + EF: ExtensionField, + Inner: CanSample, +{ + fn sample(&mut self) -> EF { + let modulus = F::ORDER_U64 as u32; + let log_size = log2_ceil_u64(F::ORDER_U64); + let pow_of_two_bound = (1 << log_size) - 1; + // Perform rejection sampling over the uniform range (0..log2_ceil(p)) + let sample_base = |inner: &mut Inner| loop { + let value = inner.sample(); + let value = value & pow_of_two_bound; + if value < modulus { + return F::from_canonical_u32(value); + } + }; + EF::from_base_fn(|_| sample_base(&mut self.inner)) + } +} + +impl CanSampleBits for SerializingChallenger32 where F: PrimeField32, Inner: CanSample, @@ -113,7 +146,21 @@ where } } -impl GrindingChallenger for SerializingChallenger32 +impl CanSampleBits for SerializingChallenger32 +where + F: PrimeField32, + Inner: CanSample, +{ + fn sample_bits(&mut self, bits: usize) -> usize { + debug_assert!(bits < (usize::BITS as usize)); + // Limiting the number of bits to the field size + debug_assert!((1 << bits) <= F::ORDER_U64 as usize); + let rand_usize = self.inner.sample() as usize; + rand_usize & ((1 << bits) - 1) + } +} + +impl GrindingChallenger for SerializingChallenger32 where F: PrimeField32, Inner: CanSample + CanObserve + Clone + Send + Sync, @@ -132,13 +179,39 @@ where } } -impl FieldChallenger for SerializingChallenger32 +impl GrindingChallenger for SerializingChallenger32 +where + F: PrimeField32, + Inner: CanSample + CanObserve + Clone + Send + Sync, +{ + type Witness = F; + + #[instrument(name = "grind for proof-of-work witness", skip_all)] + fn grind(&mut self, bits: usize) -> Self::Witness { + let witness = (0..F::ORDER_U64) + .into_par_iter() + .map(|i| F::from_canonical_u64(i)) + .find_any(|witness| self.clone().check_witness(bits, *witness)) + .expect("failed to find witness"); + assert!(self.check_witness(bits, witness)); + witness + } +} + +impl FieldChallenger for SerializingChallenger32 where F: PrimeField32, Inner: CanSample + CanObserve + Clone + Send + Sync, { } +impl FieldChallenger for SerializingChallenger32 +where + F: PrimeField32, + Inner: CanSample + CanObserve + Clone + Send + Sync, +{ +} + impl> SerializingChallenger64 { pub fn new(inner: Inner) -> Self { Self { diff --git a/keccak-air/examples/prove_baby_bear_keccak.rs b/keccak-air/examples/prove_baby_bear_keccak.rs index 73fde40c..0c308e8e 100644 --- a/keccak-air/examples/prove_baby_bear_keccak.rs +++ b/keccak-air/examples/prove_baby_bear_keccak.rs @@ -48,7 +48,7 @@ fn main() -> Result<(), VerificationError> { type Dft = Radix2DitParallel; let dft = Dft {}; - type Challenger = SerializingChallenger32>; + type Challenger = SerializingChallenger32>; let fri_config = FriConfig { log_blowup: 1,