diff --git a/src/asm_compiler/mod.rs b/src/asm_compiler/mod.rs index 187f608ac..963cd9043 100644 --- a/src/asm_compiler/mod.rs +++ b/src/asm_compiler/mod.rs @@ -670,7 +670,7 @@ pc' = (((instr_jmpz * ((XIsZero * instr_jmpz_param_l) + ((1 - XIsZero) * (pc + 1 pol constant line(i) { i }; pol commit X_free_value(i) query (i, pc, (0, ("input", 1)), (3, ("input", (CNT + 1))), (7, ("input", 0))); pol constant p_X_const = [0, 0, 0, 0, 0, 0, 0, 0, 0]; -pol constant p_X_read_free = [1, 0, 0, 1, 0, 0, 0, 1, 0]; +pol constant p_X_read_free = [1, 0, 0, 1, 0, 0, 0, -1, 0]; pol constant p_instr_assert_zero = [0, 0, 0, 0, 0, 0, 0, 0, 1]; pol constant p_instr_dec_CNT = [0, 0, 0, 0, 1, 0, 0, 0, 0]; pol constant p_instr_jmp = [0, 0, 0, 0, 0, 1, 0, 0, 0]; diff --git a/src/commit_evaluator/affine_expression.rs b/src/commit_evaluator/affine_expression.rs index 43410f145..9065c252e 100644 --- a/src/commit_evaluator/affine_expression.rs +++ b/src/commit_evaluator/affine_expression.rs @@ -1,6 +1,8 @@ // TODO this should probably rather be a finite field element. use crate::number::{is_zero, AbstractNumberType}; +const GOLDILOCKS_MOD: u64 = 0xffffffff00000001u64; + /// An expression affine in the committed polynomials. #[derive(Debug, Clone, PartialEq)] pub struct AffineExpression { @@ -12,7 +14,7 @@ impl From for AffineExpression { fn from(value: AbstractNumberType) -> Self { AffineExpression { coefficients: Vec::new(), - offset: value, + offset: clamp(value), } } } @@ -21,7 +23,7 @@ impl From for AffineExpression { fn from(value: u32) -> Self { AffineExpression { coefficients: Vec::new(), - offset: value.into(), + offset: clamp(value.into()), } } } @@ -47,10 +49,11 @@ impl AffineExpression { } pub fn mul(mut self, factor: AbstractNumberType) -> AffineExpression { + let fac = clamp(factor); for f in &mut self.coefficients { - *f *= factor.clone(); + *f = clamp(f.clone() * fac.clone()); } - self.offset *= factor; + self.offset = clamp(self.offset.clone() * fac); self } @@ -66,7 +69,18 @@ impl AffineExpression { nonzero.next().and_then(|(i, c)| { if nonzero.next().is_none() { // c * a + o = 0 <=> a = -o/c - Some((i, -self.offset.clone() / c)) + if *c == 1.into() { + Some((i, clamp(-self.offset.clone()))) + } else if *c == (-1).into() || *c == (GOLDILOCKS_MOD - 1).into() { + Some((i, self.offset.clone())) + } else { + Some(( + i, + clamp(-clamp( + self.offset.clone() * inv(c.clone(), GOLDILOCKS_MOD.into()), + )), + )) + } } else { None } @@ -74,6 +88,37 @@ impl AffineExpression { } } +fn clamp(mut x: AbstractNumberType) -> AbstractNumberType { + while x < 0.into() { + x += GOLDILOCKS_MOD + } + x % GOLDILOCKS_MOD +} + +fn pow( + mut x: AbstractNumberType, + mut y: AbstractNumberType, + m: AbstractNumberType, +) -> AbstractNumberType { + assert!(y >= 0.into()); + if y == 0.into() { + return 1.into(); + } + let mut r: AbstractNumberType = 1.into(); + while y >= 2.into() { + if y.bit(0) { + r = (r * x.clone()) % m.clone(); + } + x = (x.clone() * x) % m.clone(); + y = y.clone() >> 1; + } + (r * x) % m +} + +fn inv(x: AbstractNumberType, m: AbstractNumberType) -> AbstractNumberType { + pow(x, m.clone() - 2, m) +} + impl std::ops::Add for AffineExpression { type Output = AffineExpression; @@ -83,11 +128,11 @@ impl std::ops::Add for AffineExpression { coefficients.resize(self.coefficients.len(), 0.into()); } for (i, v) in self.coefficients.iter().enumerate() { - coefficients[i] += v; + coefficients[i] = clamp(coefficients[i].clone() + v); } AffineExpression { coefficients, - offset: self.offset + rhs.offset, + offset: clamp(self.offset + rhs.offset), } } } @@ -98,8 +143,8 @@ impl std::ops::Neg for AffineExpression { fn neg(mut self) -> Self::Output { self.coefficients .iter_mut() - .for_each(|v| *v = v.clone().neg()); - self.offset = -self.offset; + .for_each(|v| *v = clamp(-v.clone())); + self.offset = clamp(-self.offset); self } } @@ -114,9 +159,10 @@ impl std::ops::Sub for AffineExpression { #[cfg(test)] mod test { + use super::*; use crate::number::AbstractNumberType; - use super::AffineExpression; + use super::{AffineExpression, GOLDILOCKS_MOD}; fn convert(input: Vec) -> Vec { input.into_iter().map(|x| x.into()).collect() @@ -131,8 +177,12 @@ mod test { assert_eq!( -a, AffineExpression { - coefficients: convert(vec![-1, -0, -2]), - offset: (-9).into(), + coefficients: vec![ + (GOLDILOCKS_MOD - 1).into(), + 0.into(), + (GOLDILOCKS_MOD - 2).into() + ], + offset: (GOLDILOCKS_MOD - 9).into(), }, ); } @@ -156,4 +206,21 @@ mod test { ); assert_eq!(b.clone() + a.clone(), a + b,); } + + #[test] + pub fn mod_arith() { + assert_eq!(pow(7.into(), 0.into(), GOLDILOCKS_MOD.into()), 1.into()); + assert_eq!(pow(7.into(), 1.into(), GOLDILOCKS_MOD.into()), 7.into()); + assert_eq!( + pow(7.into(), 2.into(), GOLDILOCKS_MOD.into()), + (7 * 7).into() + ); + assert_eq!(inv(1.into(), GOLDILOCKS_MOD.into()), 1.into()); + let inverse_of_four = 13835058052060938241u64; + assert_eq!(inv(4.into(), GOLDILOCKS_MOD.into()), inverse_of_four.into()); + assert_eq!( + (4u128 * inverse_of_four as u128) % GOLDILOCKS_MOD as u128, + 1 + ); + } }