diff --git a/src/circuit_builder.rs b/src/circuit_builder.rs index a2c94f83..ccca4e2b 100644 --- a/src/circuit_builder.rs +++ b/src/circuit_builder.rs @@ -149,6 +149,11 @@ impl, const D: usize> CircuitBuilder { self.copy_constraints.push((x, y)); } + pub fn assert_zero(&mut self, x: Target) { + let zero = self.zero(); + self.assert_equal(x, zero); + } + pub fn add_generators(&mut self, generators: Vec>>) { self.generators.extend(generators); } diff --git a/src/fri/recursive_verifier.rs b/src/fri/recursive_verifier.rs index a64b02fe..6c245167 100644 --- a/src/fri/recursive_verifier.rs +++ b/src/fri/recursive_verifier.rs @@ -49,14 +49,7 @@ impl, const D: usize> CircuitBuilder { inputs.push(proof.pow_witness); let hash = self.hash_n_to_m(inputs, 1, false)[0]; - let purported_hash_bits = self.split_le_virtual(hash, 64); - // for &b in &purported_hash_bits { - // self.generate_copy(b, self.zero()); - // } - // ensure!( - // hash.to_canonical_u64().trailing_zeros() >= config.proof_of_work_bits, - // "Invalid proof of work witness." - // ); + self.assert_trailing_zeros(hash, config.proof_of_work_bits); Ok(()) } diff --git a/src/gadgets/mod.rs b/src/gadgets/mod.rs index 9a6a728e..22bef43b 100644 --- a/src/gadgets/mod.rs +++ b/src/gadgets/mod.rs @@ -1,4 +1,5 @@ pub mod arithmetic; pub mod hash; pub mod polynomial; +pub mod split_base; pub(crate) mod split_join; diff --git a/src/gadgets/split_base.rs b/src/gadgets/split_base.rs new file mode 100644 index 00000000..e622be75 --- /dev/null +++ b/src/gadgets/split_base.rs @@ -0,0 +1,33 @@ +use crate::circuit_builder::CircuitBuilder; +use crate::field::extension_field::Extendable; +use crate::field::field::Field; +use crate::gates::base_sum::{BaseSplitGenerator, BaseSumGate}; +use crate::generator::{SimpleGenerator, WitnessGenerator}; +use crate::target::Target; +use crate::util::ceil_div_usize; +use crate::wire::Wire; +use crate::witness::PartialWitness; + +impl, const D: usize> CircuitBuilder { + /// Split the given element into a list of 11 targets, where each one represents a + /// base-64 limb of the element, with little-endian ordering. + pub(crate) fn split_le_base64(&mut self, x: Target) -> Vec { + let gate = self.add_gate(BaseSumGate::<64>::new(11), vec![]); + let sum = Target::Wire(Wire { + gate, + input: BaseSumGate::<64>::WIRE_SUM, + }); + self.route(x, sum); + (BaseSumGate::<64>::WIRE_LIMBS_START..BaseSumGate::<64>::WIRE_LIMBS_START + 11) + .map(|i| Target::Wire(Wire { gate, input: i })) + .collect() + } + + /// Asserts that `x`'s bit representation has at least `trailing_zeros` trailing zeros. + pub(crate) fn assert_trailing_zeros(&mut self, x: Target, trailing_zeros: u32) { + let limbs = self.split_le_base64(x); + for i in 0..ceil_div_usize(trailing_zeros as usize, 6) { + self.assert_zero(limbs[i]); + } + } +} diff --git a/src/gates/base_sum.rs b/src/gates/base_sum.rs index f7ebd3a0..9190e19c 100644 --- a/src/gates/base_sum.rs +++ b/src/gates/base_sum.rs @@ -19,10 +19,8 @@ pub struct BaseSumGate { } impl BaseSumGate { - pub fn new, const D: usize>(config: &CircuitConfig) -> GateRef { - GateRef::new(BaseSumGate:: { - num_limbs: config.num_routed_wires - 1, - }) + pub fn new, const D: usize>(num_limbs: usize) -> GateRef { + GateRef::new(BaseSumGate:: { num_limbs }) } pub const WIRE_SUM: usize = 0; @@ -36,7 +34,7 @@ impl BaseSumGate { impl, const D: usize, const B: usize> Gate for BaseSumGate { fn id(&self) -> String { - format!("{:?}", self) + format!("{:?} + Base: {}", self, B) } fn eval_unfiltered(&self, vars: EvaluationVars) -> Vec { @@ -163,7 +161,6 @@ mod tests { #[test] fn low_degree() { - let config = CircuitConfig::default(); - test_low_degree(BaseSumGate::<6>::new::(&config)) + test_low_degree(BaseSumGate::<6>::new::(11)) } } diff --git a/src/gates/mod.rs b/src/gates/mod.rs index b25337ff..49c37bae 100644 --- a/src/gates/mod.rs +++ b/src/gates/mod.rs @@ -1,10 +1,10 @@ pub(crate) mod arithmetic; +pub mod base_sum; pub mod constant; pub(crate) mod gate; pub mod gmimc; mod interpolation; pub(crate) mod noop; -mod base_sum; #[cfg(test)] mod gate_testing;