mirror of
https://github.com/powdr-labs/powdr.git
synced 2026-05-13 03:00:26 -04:00
finite field arith.
This commit is contained in:
@@ -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];
|
||||
|
||||
@@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user