// Copyright (c) 2023 Espresso Systems (espressosys.com) // This file is part of the HyperPlonk library. // You should have received a copy of the MIT License // along with the HyperPlonk library. If not, see . // TODO: remove #![allow(dead_code)] use crate::{bit_decompose, ArithErrors}; use ark_ff::PrimeField; use ark_poly::{ univariate::DensePolynomial, EvaluationDomain, Evaluations, Radix2EvaluationDomain, }; use ark_std::log2; /// Given a list of points, build `l(points)` which is a list of univariate /// polynomials that goes through the points; extend the dimension of the points /// by `log(points.len())` if `with_suffix` is set. pub fn build_l( points: &[Vec], domain: &Radix2EvaluationDomain, with_suffix: bool, ) -> Result>, ArithErrors> { let mut uni_polys = Vec::new(); if with_suffix { // 1.1 build the indexes and the univariate polys that go through the indexes let prefix_len = log2(points.len()) as usize; let indexes: Vec> = (0..points.len()) .map(|x| bit_decompose(x as u64, prefix_len)) .collect(); for i in 0..prefix_len { let eval: Vec = indexes .iter() .map(|x| F::from(x[prefix_len - i - 1])) .collect(); uni_polys.push(Evaluations::from_vec_and_domain(eval, *domain).interpolate()); } } // 1.2 build the actual univariate polys that go through the points uni_polys.extend_from_slice(build_l_internal(points, domain)?.as_slice()); Ok(uni_polys) } /// Given a list of points, build `l(points)` which is a list of univariate /// polynomials that goes through the points. pub(crate) fn build_l_internal( points: &[Vec], domain: &Radix2EvaluationDomain, ) -> Result>, ArithErrors> { let mut uni_polys = Vec::new(); let num_var = points[0].len(); // build the actual univariate polys that go through the points for i in 0..num_var { let mut eval: Vec = points.iter().map(|x| x[i]).collect(); eval.extend_from_slice(vec![F::zero(); domain.size as usize - eval.len()].as_slice()); uni_polys.push(Evaluations::from_vec_and_domain(eval, *domain).interpolate()) } Ok(uni_polys) } /// get the domain for the univariate polynomial #[inline] pub fn get_uni_domain( uni_poly_degree: usize, ) -> Result, ArithErrors> { let domain = match Radix2EvaluationDomain::::new(uni_poly_degree) { Some(p) => p, None => { return Err(ArithErrors::InvalidParameters( "failed to build radix 2 domain".to_string(), )) }, }; Ok(domain) } #[cfg(test)] mod test { use super::*; use ark_bls12_381::Fr; use ark_ff::{field_new, One}; use ark_poly::UVPolynomial; #[test] fn test_build_l_with_suffix() -> Result<(), ArithErrors> { test_build_l_with_suffix_helper::() } fn test_build_l_with_suffix_helper() -> Result<(), ArithErrors> { // point 1 is [1, 2] let point1 = vec![Fr::from(1u64), Fr::from(2u64)]; // point 2 is [3, 4] let point2 = vec![Fr::from(3u64), Fr::from(4u64)]; // point 3 is [5, 6] let point3 = vec![Fr::from(5u64), Fr::from(6u64)]; { let domain = get_uni_domain::(2)?; let l = build_l(&[point1.clone(), point2.clone()], &domain, true)?; // roots: [1, -1] // l0 = -1/2 * x + 1/2 // l1 = -x + 2 // l2 = -x + 3 let l0 = DensePolynomial::from_coefficients_vec(vec![ Fr::one() / Fr::from(2u64), -Fr::one() / Fr::from(2u64), ]); let l1 = DensePolynomial::from_coefficients_vec(vec![Fr::from(2u64), -Fr::one()]); let l2 = DensePolynomial::from_coefficients_vec(vec![Fr::from(3u64), -Fr::one()]); assert_eq!(l0, l[0], "l0 not equal"); assert_eq!(l1, l[1], "l1 not equal"); assert_eq!(l2, l[2], "l2 not equal"); } { let domain = get_uni_domain::(3)?; let l = build_l(&[point1, point2, point3], &domain, true)?; // sage: q = 52435875175126190479447740508185965837690552500527637822603658699938581184513 // sage: P. = PolynomialRing(Zmod(q)) // sage: root1 = 1 // sage: root2 = 0x8D51CCCE760304D0EC030002760300000001000000000000 // sage: root3 = -1 // sage: root4 = -root2 // Arkwork's code is a bit wired: it also interpolate (root4, 0) // which returns a degree 3 polynomial, instead of degree 2 // ======================== // l0: [0, 0, 1] // ======================== // sage: points = [(root1, 0), (root2, 0), (root3, 1), (root4, 0)] // sage: P.lagrange_polynomial(points) // 13108968793781547619861935127046491459422638125131909455650914674984645296128*x^3 + // 39326906381344642859585805381139474378267914375395728366952744024953935888385*x^2 + // 13108968793781547619861935127046491459422638125131909455650914674984645296128*x + // 39326906381344642859585805381139474378267914375395728366952744024953935888385 let l0 = DensePolynomial::from_coefficients_vec(vec![ field_new!( Fr, "39326906381344642859585805381139474378267914375395728366952744024953935888385" ), field_new!( Fr, "13108968793781547619861935127046491459422638125131909455650914674984645296128" ), field_new!( Fr, "39326906381344642859585805381139474378267914375395728366952744024953935888385" ), field_new!( Fr, "13108968793781547619861935127046491459422638125131909455650914674984645296128" ), ]); // ======================== // l1: [0, 1, 0] // ======================== // sage: points = [(root1, 0), (root2, 1), (root3, 0), (root4, 0)] // sage: P.lagrange_polynomial(points) // 866286206518413079694067382671935694567563117191340490752*x^3 + // 13108968793781547619861935127046491459422638125131909455650914674984645296128*x^2 + // 52435875175126190478581454301667552757996485117855702128036095582747240693761*x + // 39326906381344642859585805381139474378267914375395728366952744024953935888385 let l1 = DensePolynomial::from_coefficients_vec(vec![ field_new!( Fr, "39326906381344642859585805381139474378267914375395728366952744024953935888385" ), field_new!( Fr, "52435875175126190478581454301667552757996485117855702128036095582747240693761" ), field_new!( Fr, "13108968793781547619861935127046491459422638125131909455650914674984645296128" ), field_new!( Fr, "866286206518413079694067382671935694567563117191340490752" ), ]); // ======================== // l2: [1, 3, 5] // ======================== // sage: points = [(root1, 1), (root2, 3), (root3, 5), (root4, 0)] // sage: P.lagrange_polynomial(points) // 2598858619555239239082202148015807083702689351574021472255*x^3 + // 13108968793781547619861935127046491459422638125131909455650914674984645296129*x^2 + // 52435875175126190476848881888630726598608350352511830738900969348364559712256*x + // 39326906381344642859585805381139474378267914375395728366952744024953935888387 let l2 = DensePolynomial::from_coefficients_vec(vec![ field_new!( Fr, "39326906381344642859585805381139474378267914375395728366952744024953935888387" ), field_new!( Fr, "52435875175126190476848881888630726598608350352511830738900969348364559712256" ), field_new!( Fr, "13108968793781547619861935127046491459422638125131909455650914674984645296129" ), field_new!( Fr, "2598858619555239239082202148015807083702689351574021472255" ), ]); // ======================== // l3: [2, 4, 6] // ======================== // sage: points = [(root1, 2), (root2, 4), (root3, 6), (root4, 0)] // sage: P.lagrange_polynomial(points) // 3465144826073652318776269530687742778270252468765361963007*x^3 + // x^2 + // 52435875175126190475982595682112313518914282969839895044333406231173219221504*x + // 3 let l3 = DensePolynomial::from_coefficients_vec(vec![ Fr::from(3u64), field_new!( Fr, "52435875175126190475982595682112313518914282969839895044333406231173219221504" ), Fr::one(), field_new!( Fr, "3465144826073652318776269530687742778270252468765361963007" ), ]); assert_eq!(l0, l[0], "l0 not equal"); assert_eq!(l1, l[1], "l1 not equal"); assert_eq!(l2, l[2], "l2 not equal"); assert_eq!(l3, l[3], "l3 not equal"); } Ok(()) } #[test] fn test_build_l() -> Result<(), ArithErrors> { test_build_l_helper::() } fn test_build_l_helper() -> Result<(), ArithErrors> { // point 1 is [1, 2] let point1 = vec![Fr::from(1u64), Fr::from(2u64)]; // point 2 is [3, 4] let point2 = vec![Fr::from(3u64), Fr::from(4u64)]; // point 3 is [5, 6] let point3 = vec![Fr::from(5u64), Fr::from(6u64)]; { let domain = get_uni_domain::(2)?; let l = build_l(&[point1.clone(), point2.clone()], &domain, false)?; // roots: [1, -1] // l0 = -x + 2 // l1 = -x + 3 let l0 = DensePolynomial::from_coefficients_vec(vec![Fr::from(2u64), -Fr::one()]); let l1 = DensePolynomial::from_coefficients_vec(vec![Fr::from(3u64), -Fr::one()]); assert_eq!(l0, l[0], "l0 not equal"); assert_eq!(l1, l[1], "l1 not equal"); } { let domain = get_uni_domain::(3)?; let l = build_l(&[point1, point2, point3], &domain, false)?; // sage: q = 52435875175126190479447740508185965837690552500527637822603658699938581184513 // sage: P. = PolynomialRing(Zmod(q)) // sage: root1 = 1 // sage: root2 = 0x8D51CCCE760304D0EC030002760300000001000000000000 // sage: root3 = -1 // sage: root4 = -root2 // Arkwork's code is a bit wired: it also interpolate (root4, 0) // which returns a degree 3 polynomial, instead of degree 2 // ======================== // l0: [1, 3, 5] // ======================== // sage: points = [(root1, 1), (root2, 3), (root3, 5), (root4, 0)] // sage: P.lagrange_polynomial(points) // 2598858619555239239082202148015807083702689351574021472255*x^3 + // 13108968793781547619861935127046491459422638125131909455650914674984645296129*x^2 + // 52435875175126190476848881888630726598608350352511830738900969348364559712256*x + // 39326906381344642859585805381139474378267914375395728366952744024953935888387 let l0 = DensePolynomial::from_coefficients_vec(vec![ field_new!( Fr, "39326906381344642859585805381139474378267914375395728366952744024953935888387" ), field_new!( Fr, "52435875175126190476848881888630726598608350352511830738900969348364559712256" ), field_new!( Fr, "13108968793781547619861935127046491459422638125131909455650914674984645296129" ), field_new!( Fr, "2598858619555239239082202148015807083702689351574021472255" ), ]); // ======================== // l1: [2, 4, 6] // ======================== // sage: points = [(root1, 2), (root2, 4), (root3, 6), (root4, 0)] // sage: P.lagrange_polynomial(points) // 3465144826073652318776269530687742778270252468765361963007*x^3 + // x^2 + // 52435875175126190475982595682112313518914282969839895044333406231173219221504*x + // 3 let l1 = DensePolynomial::from_coefficients_vec(vec![ Fr::from(3u64), field_new!( Fr, "52435875175126190475982595682112313518914282969839895044333406231173219221504" ), Fr::one(), field_new!( Fr, "3465144826073652318776269530687742778270252468765361963007" ), ]); assert_eq!(l0, l[0], "l0 not equal"); assert_eq!(l1, l[1], "l1 not equal"); } Ok(()) } }