From 70809e5967a8b8c32585bcb87ee9dd3ea99bb3c7 Mon Sep 17 00:00:00 2001 From: Agustin Garassino Date: Mon, 15 Jul 2024 16:56:21 -0300 Subject: [PATCH] add line poly Co-authored-by: ajgara --- stwo_cairo_verifier/src/lib.cairo | 1 + stwo_cairo_verifier/src/poly.cairo | 2 + stwo_cairo_verifier/src/poly/line.cairo | 88 ++++++++++++++++++++++++ stwo_cairo_verifier/src/poly/utils.cairo | 35 ++++++++++ 4 files changed, 126 insertions(+) create mode 100644 stwo_cairo_verifier/src/poly.cairo create mode 100644 stwo_cairo_verifier/src/poly/line.cairo create mode 100644 stwo_cairo_verifier/src/poly/utils.cairo diff --git a/stwo_cairo_verifier/src/lib.cairo b/stwo_cairo_verifier/src/lib.cairo index 25f60c38..35fa7705 100644 --- a/stwo_cairo_verifier/src/lib.cairo +++ b/stwo_cairo_verifier/src/lib.cairo @@ -1,6 +1,7 @@ mod channel; mod circle; mod fields; +mod poly; mod utils; mod vcs; diff --git a/stwo_cairo_verifier/src/poly.cairo b/stwo_cairo_verifier/src/poly.cairo new file mode 100644 index 00000000..54bc5d3a --- /dev/null +++ b/stwo_cairo_verifier/src/poly.cairo @@ -0,0 +1,2 @@ +mod line; +mod utils; diff --git a/stwo_cairo_verifier/src/poly/line.cairo b/stwo_cairo_verifier/src/poly/line.cairo new file mode 100644 index 00000000..74dfaba4 --- /dev/null +++ b/stwo_cairo_verifier/src/poly/line.cairo @@ -0,0 +1,88 @@ +use stwo_cairo_verifier::fields::SecureField; +use stwo_cairo_verifier::fields::m31::m31; +use stwo_cairo_verifier::poly::utils::fold; + +/// A univariate polynomial represented by its coefficients in the line part of the FFT-basis +/// in bit reversed order. +#[derive(Drop, Clone)] +pub struct LinePoly { + pub coeffs: Array, + pub log_size: u32, +} + +#[generate_trait] +pub impl LinePolyImpl of LinePolyTrait { + fn len(self: @LinePoly) -> usize { + self.coeffs.len() + } + + fn eval_at_point(self: @LinePoly, mut x: SecureField) -> SecureField { + let mut doublings = array![]; + let mut i = 0; + while i < *self.log_size { + doublings.append(x); + let x_square = x * x; + x = x_square + x_square - m31(1).into(); + i += 1; + }; + + fold(self.coeffs, @doublings, 0, 0, self.coeffs.len()) + } +} + + +#[cfg(test)] +mod tests { + use super::{LinePoly, LinePolyTrait}; + use stwo_cairo_verifier::fields::qm31::qm31; + use stwo_cairo_verifier::fields::m31::m31; + + #[test] + fn test_eval_at_point_1() { + let line_poly = LinePoly { + coeffs: array![ + qm31(1080276375, 1725024947, 477465525, 102017026), + qm31(1080276375, 1725024947, 477465525, 102017026) + ], + log_size: 1 + }; + let x = m31(590768354); + let result = line_poly.eval_at_point(x.into()); + let expected_result = qm31(515899232, 1030391528, 1006544539, 11142505); + assert_eq!(expected_result, result); + } + + #[test] + fn test_eval_at_point_2() { + let line_poly = LinePoly { + coeffs: array![qm31(1, 2, 3, 4), qm31(5, 6, 7, 8)], log_size: 1 + }; + let x = m31(10); + let result = line_poly.eval_at_point(x.into()); + let expected_result = qm31(51, 62, 73, 84); + assert_eq!(expected_result, result); + } + + #[test] + fn test_eval_at_point_3() { + let poly = LinePoly { + coeffs: array![ + qm31(1, 2, 3, 4), + qm31(5, 6, 7, 8), + qm31(9, 10, 11, 12), + qm31(13, 14, 15, 16), + qm31(17, 18, 19, 20), + qm31(21, 22, 23, 24), + qm31(25, 26, 27, 28), + qm31(29, 30, 31, 32), + ], + log_size: 3 + }; + let x = qm31(2, 5, 7, 11); + + let result = poly.eval_at_point(x); + + let expected_result = qm31(1857853974, 839310133, 939318020, 651207981); + assert_eq!(expected_result, result); + } +} diff --git a/stwo_cairo_verifier/src/poly/utils.cairo b/stwo_cairo_verifier/src/poly/utils.cairo new file mode 100644 index 00000000..31e0ca10 --- /dev/null +++ b/stwo_cairo_verifier/src/poly/utils.cairo @@ -0,0 +1,35 @@ +use stwo_cairo_verifier::fields::SecureField; + +/// Folds values recursively in `O(n)` by a hierarchical application of folding factors. +/// +/// i.e. folding `n = 8` values with `folding_factors = [x, y, z]`: +/// +/// ```text +/// n2=n1+x*n2 +/// / \ +/// n1=n3+y*n4 n2=n5+y*n6 +/// / \ / \ +/// n3=a+z*b n4=c+z*d n5=e+z*f n6=g+z*h +/// / \ / \ / \ / \ +/// a b c d e f g h +/// ``` +/// +/// # Panics +/// +/// Panics if the number of values is not a power of two or if an incorrect number of of folding +/// factors is provided. +pub fn fold( + values: @Array, + folding_factors: @Array, + index: usize, + level: usize, + n: usize +) -> SecureField { + if n == 1 { + return *values[index]; + } + + let lhs_val = fold(values, folding_factors, index, level + 1, n / 2); + let rhs_val = fold(values, folding_factors, index + n / 2, level + 1, n / 2); + return lhs_val + rhs_val * *folding_factors[level]; +}