finite field arith.

This commit is contained in:
chriseth
2023-03-01 15:32:59 +01:00
parent acc974f3fc
commit ebc374d214
2 changed files with 80 additions and 13 deletions

View File

@@ -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];

View File

@@ -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<AbstractNumberType> for AffineExpression {
fn from(value: AbstractNumberType) -> Self {
AffineExpression {
coefficients: Vec::new(),
offset: value,
offset: clamp(value),
}
}
}
@@ -21,7 +23,7 @@ impl From<u32> 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<i32>) -> Vec<AbstractNumberType> {
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
);
}
}