From a4c6e2bbcde0183157e3be9b45ed07e481d0f1c0 Mon Sep 17 00:00:00 2001 From: mmagician Date: Tue, 27 Jun 2023 12:07:59 +0200 Subject: [PATCH 001/108] Stub out the PolynomialCommitment trait for Ligero --- src/lib.rs | 5 ++ src/ligero/mod.rs | 183 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 188 insertions(+) create mode 100644 src/ligero/mod.rs diff --git a/src/lib.rs b/src/lib.rs index 772f7f3d..5d7ae548 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -125,6 +125,11 @@ pub use marlin::marlin_pst13_pc; /// [bdfg]: https://eprint.iacr.org/2020/081.pdf pub mod streaming_kzg; +/// Scheme based on the Ligero construction in [[Ligero]][ligero]. +/// +/// [ligero]: https://eprint.iacr.org/2022/1608 +pub mod ligero; + /// `QuerySet` is the set of queries that are to be made to a set of labeled polynomials/equations /// `p` that have previously been committed to. Each element of a `QuerySet` is a pair of /// `(label, (point_label, point))`, where `label` is the label of a polynomial in `p`, diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs new file mode 100644 index 00000000..933cc949 --- /dev/null +++ b/src/ligero/mod.rs @@ -0,0 +1,183 @@ +use ark_crypto_primitives::sponge::CryptographicSponge; +use ark_ff::PrimeField; +use ark_poly::Polynomial; + +use crate::{ + Error, PCCommitment, PCCommitterKey, PCPreparedCommitment, PCPreparedVerifierKey, PCRandomness, + PCUniversalParams, PCVerifierKey, PolynomialCommitment, +}; + +use ark_std::rand::RngCore; + +// TODO: Disclaimer: no hiding prop +/// The Ligero polynomial commitment scheme. +pub struct Ligero {} + +type LigeroPCUniversalParams = (); + +impl PCUniversalParams for LigeroPCUniversalParams { + fn max_degree(&self) -> usize { + todo!() + } +} + +type LigeroPCCommitterKey = (); + +impl PCCommitterKey for LigeroPCCommitterKey { + fn max_degree(&self) -> usize { + todo!() + } + + fn supported_degree(&self) -> usize { + todo!() + } +} + +type LigeroPCVerifierKey = (); + +impl PCVerifierKey for LigeroPCVerifierKey { + fn max_degree(&self) -> usize { + todo!() + } + + fn supported_degree(&self) -> usize { + todo!() + } +} + +type LigeroPCPreparedVerifierKey = (); + +impl PCPreparedVerifierKey for LigeroPCPreparedVerifierKey { + fn prepare(vk: &Unprepared) -> Self { + todo!() + } +} + +type LigeroPCCommitment = (); + +impl PCCommitment for LigeroPCCommitment { + fn empty() -> Self { + todo!() + } + + fn has_degree_bound(&self) -> bool { + todo!() + } +} + +type LigeroPCPreparedCommitment = (); + +impl PCPreparedCommitment for LigeroPCPreparedCommitment { + fn prepare(cm: &Unprepared) -> Self { + todo!() + } +} + +type LigeroPCRandomness = (); + +impl PCRandomness for LigeroPCRandomness { + fn empty() -> Self { + todo!() + } + + fn rand( + num_queries: usize, + has_degree_bound: bool, + num_vars: Option, + rng: &mut R, + ) -> Self { + todo!() + } +} + +type LigeroPCProof = (); + +impl, S: CryptographicSponge> PolynomialCommitment + for Ligero +{ + type UniversalParams = LigeroPCUniversalParams; + + type CommitterKey = LigeroPCCommitterKey; + + type VerifierKey = LigeroPCVerifierKey; + + type PreparedVerifierKey = LigeroPCPreparedVerifierKey; + + type Commitment = LigeroPCCommitment; + + type PreparedCommitment = LigeroPCPreparedCommitment; + + type Randomness = LigeroPCRandomness; + + type Proof = LigeroPCProof; + + type BatchProof = Vec; + + type Error = Error; + + fn setup( + max_degree: usize, + num_vars: Option, + rng: &mut R, + ) -> Result { + todo!() + } + + fn trim( + pp: &Self::UniversalParams, + supported_degree: usize, + supported_hiding_bound: usize, + enforced_degree_bounds: Option<&[usize]>, + ) -> Result<(Self::CommitterKey, Self::VerifierKey), Self::Error> { + todo!() + } + + fn commit<'a>( + ck: &Self::CommitterKey, + polynomials: impl IntoIterator>, + rng: Option<&mut dyn RngCore>, + ) -> Result< + ( + Vec>, + Vec, + ), + Self::Error, + > + where + P: 'a, + { + todo!() + } + + fn open<'a>( + ck: &Self::CommitterKey, + labeled_polynomials: impl IntoIterator>, + commitments: impl IntoIterator>, + point: &'a P::Point, + challenge_generator: &mut crate::challenge::ChallengeGenerator, + rands: impl IntoIterator, + rng: Option<&mut dyn RngCore>, + ) -> Result + where + P: 'a, + Self::Randomness: 'a, + Self::Commitment: 'a, + { + todo!() + } + + fn check<'a>( + vk: &Self::VerifierKey, + commitments: impl IntoIterator>, + point: &'a P::Point, + values: impl IntoIterator, + proof: &Self::Proof, + challenge_generator: &mut crate::challenge::ChallengeGenerator, + rng: Option<&mut dyn RngCore>, + ) -> Result + where + Self::Commitment: 'a, + { + todo!() + } +} From 8f6becdeeae29a80657755460a8a6108798a05ff Mon Sep 17 00:00:00 2001 From: AntonioMG Date: Tue, 27 Jun 2023 13:19:27 +0200 Subject: [PATCH 002/108] implementing matrix functionality, not tested --- src/ligero/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 933cc949..8684de62 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -9,6 +9,8 @@ use crate::{ use ark_std::rand::RngCore; +mod utils; + // TODO: Disclaimer: no hiding prop /// The Ligero polynomial commitment scheme. pub struct Ligero {} @@ -146,6 +148,8 @@ impl, S: CryptographicSponge> PolynomialCommitme where P: 'a, { + let f = polynomials.into_iter().next().unwrap(); + todo!() } From aa944942188dde1cd6150dea8837ef728aec4918 Mon Sep 17 00:00:00 2001 From: AntonioMG Date: Tue, 27 Jun 2023 14:55:49 +0200 Subject: [PATCH 003/108] further matrix functionality, commit function started --- src/ligero/mod.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 8684de62..db056a91 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -10,6 +10,7 @@ use crate::{ use ark_std::rand::RngCore; mod utils; +use utils::Matrix; // TODO: Disclaimer: no hiding prop /// The Ligero polynomial commitment scheme. @@ -148,7 +149,17 @@ impl, S: CryptographicSponge> PolynomialCommitme where P: 'a, { - let f = polynomials.into_iter().next().unwrap(); + let f = polynomials.into_iter().next().unwrap().polynomial(); + + let coeffs = f.coefficients(); // TODO f does not have a coefficients method + + let m = ceil(sqrt(f.degree() + 1)); + + // padding the coefficient vector with zeroes + // TODO is this the most efficient way to do it? + coeffs.resize(m * m, F::zero()); + + let M = Matrix::new_from_flat(coeffs, m, m); todo!() } From d0f00b1dd14852e177f5a8e323e63edc1d8caf12 Mon Sep 17 00:00:00 2001 From: AntonioMG Date: Tue, 27 Jun 2023 16:16:59 +0200 Subject: [PATCH 004/108] testing commit signing --- .vscode/settings.json | 5 +++ src/ligero/mod.rs | 5 ++- src/ligero/tests.rs | 0 src/ligero/utils.rs | 78 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 .vscode/settings.json create mode 100644 src/ligero/tests.rs create mode 100644 src/ligero/utils.rs diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..352a6265 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "rust-analyzer.linkedProjects": [ + "./Cargo.toml" + ] +} \ No newline at end of file diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index db056a91..da481c09 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -153,7 +153,8 @@ impl, S: CryptographicSponge> PolynomialCommitme let coeffs = f.coefficients(); // TODO f does not have a coefficients method - let m = ceil(sqrt(f.degree() + 1)); + //let m = ceil(sqrt(f.degree() + 1)); + //(f.degree() + 1)..sqrt(); // padding the coefficient vector with zeroes // TODO is this the most efficient way to do it? @@ -161,6 +162,8 @@ impl, S: CryptographicSponge> PolynomialCommitme let M = Matrix::new_from_flat(coeffs, m, m); + + todo!() } diff --git a/src/ligero/tests.rs b/src/ligero/tests.rs new file mode 100644 index 00000000..e69de29b diff --git a/src/ligero/utils.rs b/src/ligero/utils.rs new file mode 100644 index 00000000..51f5cbb4 --- /dev/null +++ b/src/ligero/utils.rs @@ -0,0 +1,78 @@ +use ark_ff::PrimeField; + +use rayon::{iter::{ParallelIterator, IntoParallelRefIterator}, prelude::IndexedParallelIterator}; + +pub(crate) struct Matrix { + n: usize, + m: usize, + entries: Vec> +} + +impl Matrix { + + /// Returns a Matrix of dimensions n x m given a list of n * m field elements. + /// The list should be ordered row-first, i.e. [a11, ..., a1m, a21, ..., a2m, ...]. + /// + /// # Panics + /// Panics if the dimensions do not match the length of the list + pub(crate) fn new_from_flat(n: usize, m: usize, entry_list: &[F]) -> Self { + assert_eq!(entry_list.len(), n * m, "Invalid matrix construction: dimensions are {} x {} but entry vector has {} entries", m, n, entry_list.len()); + + // TODO more efficient to run linearly? + let entries: Vec> = (0..n).map(|row| (0..m).map(|col| entry_list[n * row + m]).collect()).collect(); + + Self {n, m, entries} + } + + /// Returns a Matrix given a list of its rows, each in turn represented as a list of field elements. + /// + /// # Panics + /// Panics if the sub-lists do not all have the same length. + pub(crate) fn new_from_row_list(n: usize, m: usize, row_list: Vec>) -> Self { + let mut m = row_list[0].len(); + + for row in row_list { + assert_eq!(row.len(), m, "Invalid matrix construction: not all rows have the same length"); + m = row.len() + } + + Self {n: row_list.len(), m, entries: row_list} + } + + // Returns the number of rows of self. + pub(crate) fn num_rows(&self) -> usize { + self.n + } + + // Returns the number of columns of self. + pub(crate) fn num_cols(&self) -> usize { + self.m + } + + /// Returns the entry in position (i, j). **Indexing starts at 0 in both coordinates**, + /// i.e. the first element is in position (0, 0) and the last one in (n - 1, j - 1), + /// where n and m are the number of rows and columns, respectively. + /// + /// Index bound checks are waived for efficiency and behaviour under invalid indexing is undefined + pub(crate) fn entry(&self, i: usize, j: usize) -> F { + return self.entries[i][j] + } + + /// Returns the product x * self, where x is interpreted as a row vector. In other words, + /// it returns a linear combination of the rows of self with coefficients given by f. + /// + /// Panics if the length of x is different from the number of rows of self. + pub(crate) fn row_mul(&self, x: &[F]) -> Vec { + assert_eq!(x.len(), self.n, "Invalid row multiplication x has {} elements whereas the matrix has {}", x.len(), self.n); + + (0..self.m).map(|col| inner_product( + x, &(0..self.n).map(|row| self.entries[row][col]).collect::>() + )).collect() + } + +} + +#[inline] +fn inner_product(v1: &[F], v2: &[F]) -> F { + ark_std::cfg_iter!(v1).zip(v2).map(|(li, ri)| *li * ri).sum() +} \ No newline at end of file From 848933b7f3a922eed080bb51853536204cf1ac3f Mon Sep 17 00:00:00 2001 From: AntonioMG Date: Tue, 27 Jun 2023 17:57:05 +0200 Subject: [PATCH 005/108] first part of commit function compiling --- src/ligero/mod.rs | 19 ++++++++++--------- src/ligero/utils.rs | 2 +- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index da481c09..b6f26ef4 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -1,6 +1,6 @@ use ark_crypto_primitives::sponge::CryptographicSponge; use ark_ff::PrimeField; -use ark_poly::Polynomial; +use ark_poly::DenseUVPolynomial; use crate::{ Error, PCCommitment, PCCommitterKey, PCPreparedCommitment, PCPreparedVerifierKey, PCRandomness, @@ -95,7 +95,7 @@ impl PCRandomness for LigeroPCRandomness { type LigeroPCProof = (); -impl, S: CryptographicSponge> PolynomialCommitment +impl, S: CryptographicSponge> PolynomialCommitment for Ligero { type UniversalParams = LigeroPCUniversalParams; @@ -151,18 +151,19 @@ impl, S: CryptographicSponge> PolynomialCommitme { let f = polynomials.into_iter().next().unwrap().polynomial(); - let coeffs = f.coefficients(); // TODO f does not have a coefficients method - - //let m = ceil(sqrt(f.degree() + 1)); - //(f.degree() + 1)..sqrt(); + let mut coeffs = f.coeffs().to_vec(); + + // want: ceil(sqrt(f.degree() + 1)); need to deal with usize -> f64 conversion + let num_elems = f.degree() + 1; + // TODO move this check to the constructor? + assert_eq!((num_elems as f64) as usize, num_elems, "Degree of polynomial + 1 cannot be converted to f64: aborting"); + let m = (num_elems as f64).sqrt().ceil() as usize; // padding the coefficient vector with zeroes // TODO is this the most efficient way to do it? coeffs.resize(m * m, F::zero()); - let M = Matrix::new_from_flat(coeffs, m, m); - - + let M = Matrix::new_from_flat( m, m, &coeffs); todo!() } diff --git a/src/ligero/utils.rs b/src/ligero/utils.rs index 51f5cbb4..843fc663 100644 --- a/src/ligero/utils.rs +++ b/src/ligero/utils.rs @@ -31,7 +31,7 @@ impl Matrix { pub(crate) fn new_from_row_list(n: usize, m: usize, row_list: Vec>) -> Self { let mut m = row_list[0].len(); - for row in row_list { + for row in row_list.iter() { assert_eq!(row.len(), m, "Invalid matrix construction: not all rows have the same length"); m = row.len() } From 543c8e1de60c7f0c1dfc755c2f89aa847f2c46f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mej=C3=ADas=20Gil?= Date: Wed, 28 Jun 2023 06:49:16 +0200 Subject: [PATCH 006/108] requested PR changes implemented --- .gitignore | 2 +- src/ligero/utils.rs | 15 ++------------- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index be1aec0a..547bf087 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,4 @@ Cargo.lock *.ipynb_checkpoints *.pyc *.sage.py -params +params \ No newline at end of file diff --git a/src/ligero/utils.rs b/src/ligero/utils.rs index 843fc663..a515e936 100644 --- a/src/ligero/utils.rs +++ b/src/ligero/utils.rs @@ -29,26 +29,15 @@ impl Matrix { /// # Panics /// Panics if the sub-lists do not all have the same length. pub(crate) fn new_from_row_list(n: usize, m: usize, row_list: Vec>) -> Self { - let mut m = row_list[0].len(); + let m = row_list[0].len(); - for row in row_list.iter() { + for row in row_list.iter().skip(1) { assert_eq!(row.len(), m, "Invalid matrix construction: not all rows have the same length"); - m = row.len() } Self {n: row_list.len(), m, entries: row_list} } - // Returns the number of rows of self. - pub(crate) fn num_rows(&self) -> usize { - self.n - } - - // Returns the number of columns of self. - pub(crate) fn num_cols(&self) -> usize { - self.m - } - /// Returns the entry in position (i, j). **Indexing starts at 0 in both coordinates**, /// i.e. the first element is in position (0, 0) and the last one in (n - 1, j - 1), /// where n and m are the number of rows and columns, respectively. From a39289d4df2b56142752239dca69e37eaef7da9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mej=C3=ADas=20Gil?= Date: Wed, 28 Jun 2023 08:03:40 +0200 Subject: [PATCH 007/108] added to_field function one-liner and tests for all existing matrix functions --- src/ligero/mod.rs | 3 ++- src/ligero/tests.rs | 60 +++++++++++++++++++++++++++++++++++++++++++++ src/ligero/utils.rs | 21 ++++++++++------ 3 files changed, 75 insertions(+), 9 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index b6f26ef4..769bc829 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -11,6 +11,7 @@ use ark_std::rand::RngCore; mod utils; use utils::Matrix; +mod tests; // TODO: Disclaimer: no hiding prop /// The Ligero polynomial commitment scheme. @@ -163,7 +164,7 @@ impl, S: CryptographicSponge> PolynomialC // TODO is this the most efficient way to do it? coeffs.resize(m * m, F::zero()); - let M = Matrix::new_from_flat( m, m, &coeffs); + let mat = Matrix::new_from_flat( m, m, &coeffs); todo!() } diff --git a/src/ligero/tests.rs b/src/ligero/tests.rs index e69de29b..4d61e520 100644 --- a/src/ligero/tests.rs +++ b/src/ligero/tests.rs @@ -0,0 +1,60 @@ + +#[cfg(test)] +mod tests { + + use ark_bls12_381::Fq as F; + + use crate::ligero::utils::*; + + #[test] + fn test_matrix_constructor_flat() { + let entries: Vec = to_field(vec![10, 100, 4, 67, 44, 50]); + let mat = Matrix::new_from_flat(2, 3, &entries); + assert_eq!(mat.entry(1, 2), F::from(50)); + } + + #[test] + #[should_panic] + fn test_matrix_constructor_flat_panic() { + let entries: Vec = to_field(vec![10, 100, 4, 67, 44]); + Matrix::new_from_flat(2, 3, &entries); + } + + #[test] + fn test_matrix_constructor_rows() { + let rows: Vec> = vec!( + to_field(vec![10, 100, 4]), + to_field(vec![23, 1, 0]), + to_field(vec![55, 58, 9]), + ); + let mat = Matrix::new_from_rows(rows); + assert_eq!(mat.entry(2, 0), F::from(55)); + } + + #[test] + #[should_panic] + fn test_matrix_constructor_rows_panic() { + let rows: Vec> = vec!( + to_field(vec![10, 100, 4]), + to_field(vec![23, 1, 0]), + to_field(vec![55, 58]), + ); + Matrix::new_from_rows(rows); + } + + #[test] + fn test_row_mul() { + let rows: Vec> = vec!( + to_field(vec![10, 100, 4]), + to_field(vec![23, 1, 0]), + to_field(vec![55, 58, 9]), + ); + + let mat = Matrix::new_from_rows(rows); + let v: Vec = to_field(vec![12, 41, 55]); + // by giving the result in the integers and then converting to F + // we ensure the test will still pass even if F changes + assert_eq!(mat.row_mul(&v), to_field::(vec![4088, 4431, 543])); + } + +} \ No newline at end of file diff --git a/src/ligero/utils.rs b/src/ligero/utils.rs index a515e936..dbe3a3a8 100644 --- a/src/ligero/utils.rs +++ b/src/ligero/utils.rs @@ -28,7 +28,7 @@ impl Matrix { /// /// # Panics /// Panics if the sub-lists do not all have the same length. - pub(crate) fn new_from_row_list(n: usize, m: usize, row_list: Vec>) -> Self { + pub(crate) fn new_from_rows(row_list: Vec>) -> Self { let m = row_list[0].len(); for row in row_list.iter().skip(1) { @@ -47,21 +47,26 @@ impl Matrix { return self.entries[i][j] } - /// Returns the product x * self, where x is interpreted as a row vector. In other words, - /// it returns a linear combination of the rows of self with coefficients given by f. + /// Returns the product v * self, where v is interpreted as a row vector. In other words, + /// it returns a linear combination of the rows of self with coefficients given by v. /// - /// Panics if the length of x is different from the number of rows of self. - pub(crate) fn row_mul(&self, x: &[F]) -> Vec { - assert_eq!(x.len(), self.n, "Invalid row multiplication x has {} elements whereas the matrix has {}", x.len(), self.n); + /// Panics if the length of v is different from the number of rows of self. + pub(crate) fn row_mul(&self, v: &[F]) -> Vec { + assert_eq!(v.len(), self.n, "Invalid row multiplication x has {} elements whereas the matrix has {}", v.len(), self.n); (0..self.m).map(|col| inner_product( - x, &(0..self.n).map(|row| self.entries[row][col]).collect::>() + v, &(0..self.n).map(|row| self.entries[row][col]).collect::>() )).collect() } } #[inline] -fn inner_product(v1: &[F], v2: &[F]) -> F { +pub(crate) fn inner_product(v1: &[F], v2: &[F]) -> F { ark_std::cfg_iter!(v1).zip(v2).map(|(li, ri)| *li * ri).sum() +} + +#[inline] +pub(crate) fn to_field(v: Vec) -> Vec { + v.iter().map(|x| F::from(*x)).collect::>() } \ No newline at end of file From d82c4e3d03feccfba77b22661de6f6ba2f6f5dea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mej=C3=ADas=20Gil?= Date: Wed, 28 Jun 2023 08:20:45 +0200 Subject: [PATCH 008/108] changed matrix-related functions from F:PrimeField to F:Field --- src/ligero/mod.rs | 3 +++ src/ligero/utils.rs | 12 +++++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 769bc829..4e089e8b 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -166,6 +166,9 @@ impl, S: CryptographicSponge> PolynomialC let mat = Matrix::new_from_flat( m, m, &coeffs); + // applying Reed-Solomon code row-wise + // let ext_mat = + todo!() } diff --git a/src/ligero/utils.rs b/src/ligero/utils.rs index dbe3a3a8..dc752ae2 100644 --- a/src/ligero/utils.rs +++ b/src/ligero/utils.rs @@ -1,14 +1,14 @@ -use ark_ff::PrimeField; +use ark_ff::Field; use rayon::{iter::{ParallelIterator, IntoParallelRefIterator}, prelude::IndexedParallelIterator}; -pub(crate) struct Matrix { +pub(crate) struct Matrix { n: usize, m: usize, entries: Vec> } -impl Matrix { +impl Matrix { /// Returns a Matrix of dimensions n x m given a list of n * m field elements. /// The list should be ordered row-first, i.e. [a11, ..., a1m, a21, ..., a2m, ...]. @@ -61,12 +61,14 @@ impl Matrix { } +//fn reed_solomon() + #[inline] -pub(crate) fn inner_product(v1: &[F], v2: &[F]) -> F { +pub(crate) fn inner_product(v1: &[F], v2: &[F]) -> F { ark_std::cfg_iter!(v1).zip(v2).map(|(li, ri)| *li * ri).sum() } #[inline] -pub(crate) fn to_field(v: Vec) -> Vec { +pub(crate) fn to_field(v: Vec) -> Vec { v.iter().map(|x| F::from(*x)).collect::>() } \ No newline at end of file From c20d28d6f629e6507ae9cd9260ea0485526cbada Mon Sep 17 00:00:00 2001 From: mmagician Date: Wed, 28 Jun 2023 09:13:59 +0200 Subject: [PATCH 009/108] Add params and generics to the Ligero constructor --- src/ligero/mod.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 933cc949..1991e2f5 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -1,4 +1,6 @@ -use ark_crypto_primitives::sponge::CryptographicSponge; +use core::marker::PhantomData; + +use ark_crypto_primitives::{crh::TwoToOneCRHScheme, sponge::CryptographicSponge}; use ark_ff::PrimeField; use ark_poly::Polynomial; @@ -11,7 +13,18 @@ use ark_std::rand::RngCore; // TODO: Disclaimer: no hiding prop /// The Ligero polynomial commitment scheme. -pub struct Ligero {} +pub struct Ligero { + /// one over the rate rho + rho_inv: usize, + + /// security parameter, used to calculate `t` + sec_param: usize, + + /// number of columns that the verifier queries + t: usize, + + _phantom: PhantomData<(F, H)>, +} type LigeroPCUniversalParams = (); From 008151bf19376dcf823529298bfb16a84afb9d76 Mon Sep 17 00:00:00 2001 From: mmagician Date: Wed, 28 Jun 2023 09:27:29 +0200 Subject: [PATCH 010/108] Create a custom and default constructors for Ligero PCS struct --- Cargo.toml | 2 +- src/ligero/mod.rs | 39 ++++++++++++++++++++++++++++++++++----- 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index aec77249..5d159a13 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ ark-serialize = { version = "^0.4.0", default-features = false, features = [ "de ark-ff = { version = "^0.4.0", default-features = false } ark-ec = { version = "^0.4.0", default-features = false } ark-poly = {version = "^0.4.0", default-features = false } -ark-crypto-primitives = {version = "^0.4.0", default-features = false, features = ["sponge"] } +ark-crypto-primitives = {version = "^0.4.0", default-features = false, features = ["sponge", "crh"] } ark-std = { version = "^0.4.0", default-features = false } ark-relations = { version = "^0.4.0", default-features = false, optional = true } diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 1991e2f5..070e8a22 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -17,15 +17,44 @@ pub struct Ligero { /// one over the rate rho rho_inv: usize, - /// security parameter, used to calculate `t` - sec_param: usize, - /// number of columns that the verifier queries t: usize, _phantom: PhantomData<(F, H)>, } +// TODO come up with reasonable defaults +const DEFAULT_RHO_INV: usize = 2; +const DEFAULT_SEC_PARAM: usize = 128; + +fn calculate_t(rho_inv: usize, sec_param: usize) -> usize { + // TODO calculate t somehow + let t = 5; + t +} + +impl Ligero { + /// Create a new instance of Ligero. + /// If either or both parameters are None, their default values are used. + pub fn new(rho_inv: Option, sec_param: Option) -> Self { + let rho_inv = rho_inv.unwrap_or(DEFAULT_RHO_INV); + let t = calculate_t(rho_inv, sec_param.unwrap_or(DEFAULT_SEC_PARAM)); + + Self { + rho_inv, + t, + _phantom: PhantomData, + } + } +} + +impl Default for Ligero { + /// Create an instance of Ligero with the default rho (inverse: DEFAULT_RHO_INV) and security parameter (DEFAULT_SEC_PARAM). + fn default() -> Self { + Self::new(Some(DEFAULT_RHO_INV), Some(DEFAULT_SEC_PARAM)) + } +} + type LigeroPCUniversalParams = (); impl PCUniversalParams for LigeroPCUniversalParams { @@ -105,8 +134,8 @@ impl PCRandomness for LigeroPCRandomness { type LigeroPCProof = (); -impl, S: CryptographicSponge> PolynomialCommitment - for Ligero +impl, S: CryptographicSponge, H: TwoToOneCRHScheme> + PolynomialCommitment for Ligero { type UniversalParams = LigeroPCUniversalParams; From 91184aa4a436e172fd40c71bdfd9df3112806cd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mej=C3=ADas=20Gil?= Date: Wed, 28 Jun 2023 09:51:30 +0200 Subject: [PATCH 011/108] in the middle of commit function, not compiling --- src/ligero/mod.rs | 4 +++- src/ligero/utils.rs | 7 +++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 4e089e8b..f226d3ff 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -167,7 +167,9 @@ impl, S: CryptographicSponge> PolynomialC let mat = Matrix::new_from_flat( m, m, &coeffs); // applying Reed-Solomon code row-wise - // let ext_mat = + let ext_mat = Matrix::new_from_rows( + mat.rows().map(|r| reed_solomon(row, self.rho_inv())) + ); todo!() } diff --git a/src/ligero/utils.rs b/src/ligero/utils.rs index dc752ae2..09abef52 100644 --- a/src/ligero/utils.rs +++ b/src/ligero/utils.rs @@ -1,4 +1,4 @@ -use ark_ff::Field; +use ark_ff::{Field, FftField}; use rayon::{iter::{ParallelIterator, IntoParallelRefIterator}, prelude::IndexedParallelIterator}; @@ -61,7 +61,10 @@ impl Matrix { } -//fn reed_solomon() +// here we restrict F to PrimeField +pub(crate) fn reed_solomon(msg: &[F], rho: usize) -> Vec { + todo!() +} #[inline] pub(crate) fn inner_product(v1: &[F], v2: &[F]) -> F { From 4ef9adb84de77a772491c91fc26af6a8245af127 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mej=C3=ADas=20Gil?= Date: Wed, 28 Jun 2023 11:57:29 +0200 Subject: [PATCH 012/108] added reed-solomon encoding and a test for the fft interface --- src/ligero/mod.rs | 13 +++++++++++-- src/ligero/tests.rs | 21 +++++++++++++++++++++ src/ligero/utils.rs | 33 +++++++++++++++++++++++++++++++-- 3 files changed, 63 insertions(+), 4 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index b05c2439..2c731076 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -6,7 +6,7 @@ use ark_poly::DenseUVPolynomial; use crate::{ Error, PCCommitment, PCCommitterKey, PCPreparedCommitment, PCPreparedVerifierKey, PCRandomness, - PCUniversalParams, PCVerifierKey, PolynomialCommitment, + PCUniversalParams, PCVerifierKey, PolynomialCommitment, ligero::utils::reed_solomon, }; use ark_std::rand::RngCore; @@ -42,6 +42,11 @@ impl Ligero { /// If either or both parameters are None, their default values are used. pub fn new(rho_inv: Option, sec_param: Option) -> Self { let rho_inv = rho_inv.unwrap_or(DEFAULT_RHO_INV); + + if rho_inv == 0 { + panic!("rho_inv cannot be zero"); + } + let t = calculate_t(rho_inv, sec_param.unwrap_or(DEFAULT_SEC_PARAM)); Self { @@ -192,6 +197,7 @@ impl, S: CryptographicSponge, H: TwoToOne where P: 'a, { + // TODO loop over all polys let f = polynomials.into_iter().next().unwrap().polynomial(); let mut coeffs = f.coeffs().to_vec(); @@ -208,11 +214,14 @@ impl, S: CryptographicSponge, H: TwoToOne let mat = Matrix::new_from_flat( m, m, &coeffs); + // TODO rho_inv not part of self? // applying Reed-Solomon code row-wise let ext_mat = Matrix::new_from_rows( - mat.rows().map(|r| reed_solomon(row, self.rho_inv())) + mat.rows().iter().map(|r| reed_solomon(r, self.rho_inv)).collect() ); + + todo!() } diff --git a/src/ligero/tests.rs b/src/ligero/tests.rs index 4d61e520..dbeae0c2 100644 --- a/src/ligero/tests.rs +++ b/src/ligero/tests.rs @@ -3,6 +3,7 @@ mod tests { use ark_bls12_381::Fq as F; + use ark_poly::{domain::general::GeneralEvaluationDomain, EvaluationDomain, DenseUVPolynomial, univariate::DensePolynomial, Polynomial}; use crate::ligero::utils::*; @@ -57,4 +58,24 @@ mod tests { assert_eq!(mat.row_mul(&v), to_field::(vec![4088, 4431, 543])); } + #[test] + fn test_fft_interface() { + + // we use this polynomial to generate the the values we will ask the fft to interpolate + let pol_coeffs: Vec = to_field(vec![30, 2, 91]); + let pol: DensePolynomial = DensePolynomial::from_coefficients_slice(&pol_coeffs); + + let fft_domain = GeneralEvaluationDomain::::new(pol_coeffs.len()).unwrap(); + + // generating the values + let mut vals = Vec::new(); + + for i in 0..4 { + vals.push(pol.evaluate(&fft_domain.element(i))); + } + + // the fft should recover the original polynomial + assert_eq!(fft_domain.ifft(&vals), pol_coeffs); + } + } \ No newline at end of file diff --git a/src/ligero/utils.rs b/src/ligero/utils.rs index 09abef52..1ab4548d 100644 --- a/src/ligero/utils.rs +++ b/src/ligero/utils.rs @@ -1,5 +1,6 @@ use ark_ff::{Field, FftField}; +use ark_poly::{GeneralEvaluationDomain, EvaluationDomain, univariate::DensePolynomial, DenseUVPolynomial, Polynomial}; use rayon::{iter::{ParallelIterator, IntoParallelRefIterator}, prelude::IndexedParallelIterator}; pub(crate) struct Matrix { @@ -47,6 +48,11 @@ impl Matrix { return self.entries[i][j] } + /// Returns self as a list of rows + pub(crate) fn rows(&self) -> Vec> { + return self.entries.clone() + } + /// Returns the product v * self, where v is interpreted as a row vector. In other words, /// it returns a linear combination of the rows of self with coefficients given by v. /// @@ -61,9 +67,32 @@ impl Matrix { } +// TODO batch for all rows? possibly minimal savings due to not having to create fft_domain every time // here we restrict F to PrimeField -pub(crate) fn reed_solomon(msg: &[F], rho: usize) -> Vec { - todo!() +pub(crate) fn reed_solomon(msg: &[F], rho_inverse: usize) -> Vec { + + // TODO is this check worth it? + // rho_inverse = 0 should never happen; rho_inverse = 1 means no expansion + if rho_inverse <= 1 { + return msg.to_vec(); + } + + let m = msg.len(); + + let fft_domain = GeneralEvaluationDomain::::new(m).unwrap(); + + let pol: DensePolynomial = DensePolynomial::from_coefficients_slice(&fft_domain.ifft(msg)); + + let mut encoding = msg.to_vec(); + + for zeta in m..rho_inverse * m { + // TODO better way? evaluate_over_domain, coset, ...? + // e.g. pass to the smallest subgroup containing these values, then trim? + encoding.push(pol.evaluate(&fft_domain.element(zeta))) + } + + encoding + } #[inline] From b008983c8f2aedf805dccb3e49e49ebb4eff877d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mej=C3=ADas=20Gil?= Date: Wed, 28 Jun 2023 12:42:57 +0200 Subject: [PATCH 013/108] continued commit method, left placeholders for Merkle-tree parts; NOT compiling --- src/ligero/mod.rs | 38 ++++++++++++++++++++++++++++++-------- src/ligero/tests.rs | 13 +++++++++++++ src/ligero/utils.rs | 5 +++++ 3 files changed, 48 insertions(+), 8 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 2c731076..0ddc8642 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -6,7 +6,7 @@ use ark_poly::DenseUVPolynomial; use crate::{ Error, PCCommitment, PCCommitterKey, PCPreparedCommitment, PCPreparedVerifierKey, PCRandomness, - PCUniversalParams, PCVerifierKey, PolynomialCommitment, ligero::utils::reed_solomon, + PCUniversalParams, PCVerifierKey, PolynomialCommitment, ligero::utils::reed_solomon, LabeledCommitment, LabeledPolynomial, }; use ark_std::rand::RngCore; @@ -104,7 +104,13 @@ impl PCPreparedVerifierKey for LigeroPCPr } } -type LigeroPCCommitment = (); +struct Commitment { + m: usize, // number of rows of the square matrix containing the coefficients of the polynomial + r: (), // TODO merkle tree root + // TODO transcript with the randomly selected colums/their hashes; is this the "randomness?" +} + +type LigeroPCCommitment = Commitment; impl PCCommitment for LigeroPCCommitment { fn empty() -> Self { @@ -198,12 +204,12 @@ impl, S: CryptographicSponge, H: TwoToOne P: 'a, { // TODO loop over all polys - let f = polynomials.into_iter().next().unwrap().polynomial(); + let LabeledPolynomial{label, polynomial, degree_bound, ..} = *polynomials.into_iter().next().unwrap(); - let mut coeffs = f.coeffs().to_vec(); + let mut coeffs = polynomial.coeffs().to_vec(); // want: ceil(sqrt(f.degree() + 1)); need to deal with usize -> f64 conversion - let num_elems = f.degree() + 1; + let num_elems = polynomial.degree() + 1; // TODO move this check to the constructor? assert_eq!((num_elems as f64) as usize, num_elems, "Degree of polynomial + 1 cannot be converted to f64: aborting"); let m = (num_elems as f64).sqrt().ceil() as usize; @@ -215,14 +221,28 @@ impl, S: CryptographicSponge, H: TwoToOne let mat = Matrix::new_from_flat( m, m, &coeffs); // TODO rho_inv not part of self? + let rho_inv = 2; // self.rho_inv // applying Reed-Solomon code row-wise + let ext_mat = Matrix::new_from_rows( - mat.rows().iter().map(|r| reed_solomon(r, self.rho_inv)).collect() + mat.rows().iter().map(|r| reed_solomon(r, rho_inv)).collect() ); - + let col_hashes = Vec(); - todo!() + for col in ext_mat.cols() { + // col_hashes.push(hash of col) + } + + // let tree = Merkle tree from col_hashes (the library might take care of padding to a power of 2) + // let r = root of the tree + // + + let commitment = LigeroPCCommitment::new(root: r); + + Ok(LabeledCommitment::new(label, commitment, degree_bound)) + + // TODO when should this return Err? } fn open<'a>( @@ -257,3 +277,5 @@ impl, S: CryptographicSponge, H: TwoToOne todo!() } } + +// TODO start considering degree bound \ No newline at end of file diff --git a/src/ligero/tests.rs b/src/ligero/tests.rs index dbeae0c2..8f1f9e34 100644 --- a/src/ligero/tests.rs +++ b/src/ligero/tests.rs @@ -43,6 +43,19 @@ mod tests { Matrix::new_from_rows(rows); } + #[test] + fn test_cols() { + let rows: Vec> = vec!( + to_field(vec![4, 76]), + to_field(vec![14, 92,]), + to_field(vec![17, 89]), + ); + + let mat = Matrix::new_from_rows(rows); + + assert_eq!(mat.cols()[1], to_field(vec![76, 92, 89])); + } + #[test] fn test_row_mul() { let rows: Vec> = vec!( diff --git a/src/ligero/utils.rs b/src/ligero/utils.rs index 1ab4548d..16224558 100644 --- a/src/ligero/utils.rs +++ b/src/ligero/utils.rs @@ -53,6 +53,11 @@ impl Matrix { return self.entries.clone() } + /// Returns self as a list of columns + pub(crate) fn cols(&self) -> Vec> { + (0..self.m).map(|col| (0..self.n).map(|row| self.entries[row][col]).collect()).collect() + } + /// Returns the product v * self, where v is interpreted as a row vector. In other words, /// it returns a linear combination of the rows of self with coefficients given by v. /// From c13cf2870c1f0874eb1e705b652cf6bc805d5fb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mej=C3=ADas=20Gil?= Date: Wed, 28 Jun 2023 15:04:53 +0200 Subject: [PATCH 014/108] changed reed-solomon code to receive fft_domain from caller; continued work on commit function --- src/ligero/mod.rs | 47 +++++++++++++++++++++++++++++++++++---------- src/ligero/utils.rs | 22 +++++++++++++-------- 2 files changed, 51 insertions(+), 18 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 0ddc8642..ef4799a8 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -2,7 +2,7 @@ use core::marker::PhantomData; use ark_crypto_primitives::{crh::TwoToOneCRHScheme, sponge::CryptographicSponge}; use ark_ff::PrimeField; -use ark_poly::DenseUVPolynomial; +use ark_poly::{DenseUVPolynomial, GeneralEvaluationDomain}; use crate::{ Error, PCCommitment, PCCommitterKey, PCPreparedCommitment, PCPreparedVerifierKey, PCRandomness, @@ -104,14 +104,12 @@ impl PCPreparedVerifierKey for LigeroPCPr } } -struct Commitment { +struct LigeroPCCommitment { m: usize, // number of rows of the square matrix containing the coefficients of the polynomial - r: (), // TODO merkle tree root + tree_root: (), // TODO merkle tree root // TODO transcript with the randomly selected colums/their hashes; is this the "randomness?" } -type LigeroPCCommitment = Commitment; - impl PCCommitment for LigeroPCCommitment { fn empty() -> Self { todo!() @@ -214,6 +212,8 @@ impl, S: CryptographicSponge, H: TwoToOne assert_eq!((num_elems as f64) as usize, num_elems, "Degree of polynomial + 1 cannot be converted to f64: aborting"); let m = (num_elems as f64).sqrt().ceil() as usize; + // TODO: check if fft_domain.compute_size_of_domain(m) is large enough + // padding the coefficient vector with zeroes // TODO is this the most efficient way to do it? coeffs.resize(m * m, F::zero()); @@ -224,13 +224,23 @@ impl, S: CryptographicSponge, H: TwoToOne let rho_inv = 2; // self.rho_inv // applying Reed-Solomon code row-wise + let fft_domain = GeneralEvaluationDomain::::new(m).unwrap(); + let domain_iter = fft_domain.elements(); + let ext_mat = Matrix::new_from_rows( - mat.rows().iter().map(|r| reed_solomon(r, rho_inv)).collect() + mat.rows().iter().map(|r| reed_solomon( + r, + rho_inv, + fft_domain, + domain_iter + )).collect() ); - let col_hashes = Vec(); + let col_hashes = Vec::new(); + + let mat_cols = ext_mat.cols(); - for col in ext_mat.cols() { + for col in mat_cols { // col_hashes.push(hash of col) } @@ -238,10 +248,27 @@ impl, S: CryptographicSponge, H: TwoToOne // let r = root of the tree // - let commitment = LigeroPCCommitment::new(root: r); + // generating transcript for the verification of well-formedness + let random_lc_coeffs = // generate m coefficients by hashing the root + let random_lc = ext_mat.row_mul(random_lc_coeffs); + + wf_transcript.random_lc = random_lc; + + let queried_columns =; // generate t column indices by hashing random_lc (the last element in the transcript) + + let mat_cols = mat.cols(); + + for i in queried_columns { + wf_transcript.colums.push(mat_cols[i]); + wf_transcript.column_proofs.push(merkle._tree_proof(i)); + } + + //... - Ok(LabeledCommitment::new(label, commitment, degree_bound)) + let commitment = Commitment::new(m, root, wf_transcript); + Ok(LabeledCommitment::new(label, commitment, degree_bound)); + // TODO when should this return Err? } diff --git a/src/ligero/utils.rs b/src/ligero/utils.rs index 16224558..af82a913 100644 --- a/src/ligero/utils.rs +++ b/src/ligero/utils.rs @@ -1,6 +1,6 @@ use ark_ff::{Field, FftField}; -use ark_poly::{GeneralEvaluationDomain, EvaluationDomain, univariate::DensePolynomial, DenseUVPolynomial, Polynomial}; +use ark_poly::{GeneralEvaluationDomain, EvaluationDomain, univariate::DensePolynomial, DenseUVPolynomial, Polynomial, domain::general::GeneralElements}; use rayon::{iter::{ParallelIterator, IntoParallelRefIterator}, prelude::IndexedParallelIterator}; pub(crate) struct Matrix { @@ -74,7 +74,12 @@ impl Matrix { // TODO batch for all rows? possibly minimal savings due to not having to create fft_domain every time // here we restrict F to PrimeField -pub(crate) fn reed_solomon(msg: &[F], rho_inverse: usize) -> Vec { +pub(crate) fn reed_solomon( + msg: &[F], + rho_inverse: usize, + fft_domain: GeneralEvaluationDomain::, + &mut domain_iter: GeneralElements:: +) -> Vec { // TODO is this check worth it? // rho_inverse = 0 should never happen; rho_inverse = 1 means no expansion @@ -84,16 +89,17 @@ pub(crate) fn reed_solomon(msg: &[F], rho_inverse: usize) -> Vec let m = msg.len(); - let fft_domain = GeneralEvaluationDomain::::new(m).unwrap(); - let pol: DensePolynomial = DensePolynomial::from_coefficients_slice(&fft_domain.ifft(msg)); let mut encoding = msg.to_vec(); - for zeta in m..rho_inverse * m { - // TODO better way? evaluate_over_domain, coset, ...? - // e.g. pass to the smallest subgroup containing these values, then trim? - encoding.push(pol.evaluate(&fft_domain.element(zeta))) + domain_iter.nth(m - 1); + + for _ in 0..(rho_inverse - 1) * m { + // TODO make sure the domain has enough elements in the caller or check here + let zeta = domain_iter.next().unwrap(); + encoding.push(pol.evaluate(zeta)); + } encoding From dd7e28ffd98ba59107b9123732f366ec2840d360 Mon Sep 17 00:00:00 2001 From: mmagician Date: Wed, 28 Jun 2023 15:19:14 +0200 Subject: [PATCH 015/108] make a Commitment struct with MT root & transcipt --- Cargo.toml | 2 +- src/ligero/mod.rs | 71 ++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 62 insertions(+), 11 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5d159a13..1e66e976 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ ark-serialize = { version = "^0.4.0", default-features = false, features = [ "de ark-ff = { version = "^0.4.0", default-features = false } ark-ec = { version = "^0.4.0", default-features = false } ark-poly = {version = "^0.4.0", default-features = false } -ark-crypto-primitives = {version = "^0.4.0", default-features = false, features = ["sponge", "crh"] } +ark-crypto-primitives = {version = "^0.4.0", default-features = false, features = ["sponge","merkle_tree" ] } ark-std = { version = "^0.4.0", default-features = false } ark-relations = { version = "^0.4.0", default-features = false, optional = true } diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 070e8a22..dee9de06 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -1,8 +1,12 @@ use core::marker::PhantomData; -use ark_crypto_primitives::{crh::TwoToOneCRHScheme, sponge::CryptographicSponge}; +use ark_crypto_primitives::{ + merkle_tree::{Config, Path}, + sponge::CryptographicSponge, +}; use ark_ff::PrimeField; use ark_poly::Polynomial; +use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use crate::{ Error, PCCommitment, PCCommitterKey, PCPreparedCommitment, PCPreparedVerifierKey, PCRandomness, @@ -13,14 +17,14 @@ use ark_std::rand::RngCore; // TODO: Disclaimer: no hiding prop /// The Ligero polynomial commitment scheme. -pub struct Ligero { +pub struct Ligero { /// one over the rate rho rho_inv: usize, /// number of columns that the verifier queries t: usize, - _phantom: PhantomData<(F, H)>, + _phantom: PhantomData<(F, C)>, } // TODO come up with reasonable defaults @@ -33,7 +37,7 @@ fn calculate_t(rho_inv: usize, sec_param: usize) -> usize { t } -impl Ligero { +impl Ligero { /// Create a new instance of Ligero. /// If either or both parameters are None, their default values are used. pub fn new(rho_inv: Option, sec_param: Option) -> Self { @@ -48,7 +52,7 @@ impl Ligero { } } -impl Default for Ligero { +impl Default for Ligero { /// Create an instance of Ligero with the default rho (inverse: DEFAULT_RHO_INV) and security parameter (DEFAULT_SEC_PARAM). fn default() -> Self { Self::new(Some(DEFAULT_RHO_INV), Some(DEFAULT_SEC_PARAM)) @@ -95,9 +99,52 @@ impl PCPreparedVerifierKey for LigeroPCPr } } -type LigeroPCCommitment = (); +#[derive(Derivative, CanonicalSerialize, CanonicalDeserialize)] +#[derivative( + Default(bound = ""), + Clone(bound = ""), + Debug(bound = ""), +)] + +struct CommitmentTranscript { + /// the randomness generated by the verifier + r: Vec, + + /// set of indices at which the verifier queries the commitment matrtix + q: Vec, + + /// For each of the indices in q, `paths` contains the path from the root of the merkle tree to the leaf + paths: Vec>, + + columns: Vec>, +} + +/// The commitment to a polynomial is a root of the merkle tree, +/// where each node is a hash of the column of the encoded coefficient matrix U. +#[derive(Derivative, CanonicalSerialize, CanonicalDeserialize)] +#[derivative(Default(bound = ""), Clone(bound = ""), Debug(bound = ""))] +pub struct LigeroPCCommitment { + // TODO is InnerDigest the right type? + root: C::InnerDigest, + transcript: CommitmentTranscript, +} -impl PCCommitment for LigeroPCCommitment { +// impl LigeroPCCommitment { +// /// The verifier can check the well-formedness of the commitment by taking random linear combinations. +// fn verify(&self) -> bool { +// let col_hashes = Vec::new(); +// for c in self.transcript.columns { +// // TODO some hashing +// } + +// for i in 0..self.transcript.q.len() { +// self.transcript.paths[i].verify(&self.root, &col_hashes[i]]); +// } +// todo!() +// } +// } + +impl PCCommitment for LigeroPCCommitment { fn empty() -> Self { todo!() } @@ -134,8 +181,12 @@ impl PCRandomness for LigeroPCRandomness { type LigeroPCProof = (); -impl, S: CryptographicSponge, H: TwoToOneCRHScheme> - PolynomialCommitment for Ligero +impl PolynomialCommitment for Ligero +where + F: PrimeField, + P: Polynomial, + S: CryptographicSponge, + C: Config + 'static, { type UniversalParams = LigeroPCUniversalParams; @@ -145,7 +196,7 @@ impl, S: CryptographicSponge, H: TwoToOneCRHSche type PreparedVerifierKey = LigeroPCPreparedVerifierKey; - type Commitment = LigeroPCCommitment; + type Commitment = LigeroPCCommitment; type PreparedCommitment = LigeroPCPreparedCommitment; From bb3b6bb8b76deba1ad6ab67138906ebd0b6136c9 Mon Sep 17 00:00:00 2001 From: mmagician Date: Wed, 28 Jun 2023 15:40:42 +0200 Subject: [PATCH 016/108] stub out the Commitment verify method (well-formedness check) --- src/ligero/mod.rs | 61 +++++++++++++++++++++++++++++++---------------- 1 file changed, 40 insertions(+), 21 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index dee9de06..b1bf3b5a 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -1,7 +1,7 @@ -use core::marker::PhantomData; +use core::{borrow::Borrow, marker::PhantomData}; use ark_crypto_primitives::{ - merkle_tree::{Config, Path}, + merkle_tree::{Config, LeafParam, Path, TwoToOneParam}, sponge::CryptographicSponge, }; use ark_ff::PrimeField; @@ -100,11 +100,7 @@ impl PCPreparedVerifierKey for LigeroPCPr } #[derive(Derivative, CanonicalSerialize, CanonicalDeserialize)] -#[derivative( - Default(bound = ""), - Clone(bound = ""), - Debug(bound = ""), -)] +#[derivative(Default(bound = ""), Clone(bound = ""), Debug(bound = ""))] struct CommitmentTranscript { /// the randomness generated by the verifier @@ -129,20 +125,43 @@ pub struct LigeroPCCommitment { transcript: CommitmentTranscript, } -// impl LigeroPCCommitment { -// /// The verifier can check the well-formedness of the commitment by taking random linear combinations. -// fn verify(&self) -> bool { -// let col_hashes = Vec::new(); -// for c in self.transcript.columns { -// // TODO some hashing -// } - -// for i in 0..self.transcript.q.len() { -// self.transcript.paths[i].verify(&self.root, &col_hashes[i]]); -// } -// todo!() -// } -// } +impl LigeroPCCommitment +where + F: PrimeField + Borrow<::Leaf>, + C: Config, +{ + /// The verifier can check the well-formedness of the commitment by taking random linear combinations. + fn verify( + &self, + leaf_hash_params: &LeafParam, + two_to_one_params: &TwoToOneParam, + ) -> Result<(), Error> { + // 1. Hash the received columns, to get the leaf hashes + let col_hashes: Vec = vec![F::zero(); self.transcript.columns.len()]; + for c in self.transcript.columns.iter() { + // TODO some hashing + } + + // 2. Verify the paths for each of the leaf hashes + for (i, leaf) in col_hashes.iter().enumerate() { + // TODO handle the error here + self.transcript.paths[i] + .verify( + leaf_hash_params, + two_to_one_params, + &self.root, + leaf.clone(), + ) + .unwrap(); + } + + + // 3. verify the random linear combinations + + // 4. Verify the Fiat-Shamir transformation + todo!() + } +} impl PCCommitment for LigeroPCCommitment { fn empty() -> Self { From 1d6c30bc8367338139a379a47452b00350e70b63 Mon Sep 17 00:00:00 2001 From: mmagician Date: Wed, 28 Jun 2023 18:59:25 +0200 Subject: [PATCH 017/108] Ligero with a sponge for Fiat-Shamir Commitment well-formed check --- src/ligero/mod.rs | 148 +++++++++++++++++++++++++++------------------- 1 file changed, 88 insertions(+), 60 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index b1bf3b5a..18a1e69e 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -2,11 +2,12 @@ use core::{borrow::Borrow, marker::PhantomData}; use ark_crypto_primitives::{ merkle_tree::{Config, LeafParam, Path, TwoToOneParam}, - sponge::CryptographicSponge, + sponge::{Absorb, CryptographicSponge}, }; use ark_ff::PrimeField; use ark_poly::Polynomial; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; +use digest::Digest; use crate::{ Error, PCCommitment, PCCommitterKey, PCPreparedCommitment, PCPreparedVerifierKey, PCRandomness, @@ -17,14 +18,20 @@ use ark_std::rand::RngCore; // TODO: Disclaimer: no hiding prop /// The Ligero polynomial commitment scheme. -pub struct Ligero { +pub struct Ligero< + F: PrimeField, + C: Config, + D: Digest, + S: CryptographicSponge, /// one over the rate rho - rho_inv: usize, - - /// number of columns that the verifier queries - t: usize, - - _phantom: PhantomData<(F, C)>, + const rho_inv: usize, + /// security parameter, used in calculating t + const sec_param: usize, +> { + _field: PhantomData, + _config: PhantomData, + _digest: PhantomData, + _sponge: PhantomData, } // TODO come up with reasonable defaults @@ -37,25 +44,78 @@ fn calculate_t(rho_inv: usize, sec_param: usize) -> usize { t } -impl Ligero { +impl + Ligero +where + F: PrimeField + Borrow<::Leaf> + Absorb, + C: Config, + C::InnerDigest: Absorb, + D: Digest, + S: CryptographicSponge, +{ /// Create a new instance of Ligero. /// If either or both parameters are None, their default values are used. - pub fn new(rho_inv: Option, sec_param: Option) -> Self { - let rho_inv = rho_inv.unwrap_or(DEFAULT_RHO_INV); - let t = calculate_t(rho_inv, sec_param.unwrap_or(DEFAULT_SEC_PARAM)); - + pub fn new() -> Self { Self { - rho_inv, - t, - _phantom: PhantomData, + _config: PhantomData, + _field: PhantomData, + _digest: PhantomData, + _sponge: PhantomData, } } -} -impl Default for Ligero { - /// Create an instance of Ligero with the default rho (inverse: DEFAULT_RHO_INV) and security parameter (DEFAULT_SEC_PARAM). - fn default() -> Self { - Self::new(Some(DEFAULT_RHO_INV), Some(DEFAULT_SEC_PARAM)) + /// The verifier can check the well-formedness of the commitment by taking random linear combinations. + fn verify( + commitment: &LigeroPCCommitment, + leaf_hash_params: &LeafParam, + two_to_one_params: &TwoToOneParam, + sponge: &mut S, + ) -> Result<(), Error> { + let t = calculate_t(rho_inv, sec_param); + + // 1. Hash the received columns, to get the leaf hashes + let col_hashes: Vec = vec![F::zero(); t]; + for c in commitment.transcript.columns.iter() { + // TODO some hashing, with the digest? + } + + // 2. Verify the paths for each of the leaf hashes + // TODO need a way to relate the index to the leaf hash + for (i, leaf) in col_hashes.iter().enumerate() { + // TODO handle the error here + commitment.transcript.paths[i] + .verify( + leaf_hash_params, + two_to_one_params, + &commitment.root, + leaf.clone(), + ) + .unwrap(); + } + + // 3. verify the random linear combinations + + // 4. Verify the Fiat-Shamir transformation + sponge.absorb(&commitment.root); + let verifiers_randomness: Vec = sponge.squeeze_field_elements(t); + assert_eq!(verifiers_randomness, commitment.transcript.r); + // Upon sending `v` to the Verifier, add it to the sponge + sponge.absorb(&commitment.transcript.v); + + // we want to squeeze enough bytes to get the indices in the range [0, rho_inv * m) + // TODO check whether this is right + let bytes_to_squeeze = ((commitment.m * rho_inv) >> 8) + 1; + let mut indices = Vec::with_capacity(t); + for _ in 0..t { + let ind = sponge.squeeze_bytes(bytes_to_squeeze); + + // get the usize from Vec: + let ind = ind.iter().fold(0, |acc, &x| (acc << 8) + x as usize); + // modulo the number of columns in the encoded matrix + indices.push(ind % (rho_inv * commitment.m)); + } + + todo!() } } @@ -112,6 +172,9 @@ struct CommitmentTranscript { /// For each of the indices in q, `paths` contains the path from the root of the merkle tree to the leaf paths: Vec>, + /// v, s.t. E(v) = w + v: Vec, + columns: Vec>, } @@ -122,47 +185,10 @@ struct CommitmentTranscript { pub struct LigeroPCCommitment { // TODO is InnerDigest the right type? root: C::InnerDigest, + m: usize, transcript: CommitmentTranscript, } -impl LigeroPCCommitment -where - F: PrimeField + Borrow<::Leaf>, - C: Config, -{ - /// The verifier can check the well-formedness of the commitment by taking random linear combinations. - fn verify( - &self, - leaf_hash_params: &LeafParam, - two_to_one_params: &TwoToOneParam, - ) -> Result<(), Error> { - // 1. Hash the received columns, to get the leaf hashes - let col_hashes: Vec = vec![F::zero(); self.transcript.columns.len()]; - for c in self.transcript.columns.iter() { - // TODO some hashing - } - - // 2. Verify the paths for each of the leaf hashes - for (i, leaf) in col_hashes.iter().enumerate() { - // TODO handle the error here - self.transcript.paths[i] - .verify( - leaf_hash_params, - two_to_one_params, - &self.root, - leaf.clone(), - ) - .unwrap(); - } - - - // 3. verify the random linear combinations - - // 4. Verify the Fiat-Shamir transformation - todo!() - } -} - impl PCCommitment for LigeroPCCommitment { fn empty() -> Self { todo!() @@ -200,12 +226,14 @@ impl PCRandomness for LigeroPCRandomness { type LigeroPCProof = (); -impl PolynomialCommitment for Ligero +impl PolynomialCommitment + for Ligero where F: PrimeField, P: Polynomial, S: CryptographicSponge, C: Config + 'static, + D: Digest, { type UniversalParams = LigeroPCUniversalParams; From 129cbfbd32c5cee50ce070ef6b718ca21787e4a5 Mon Sep 17 00:00:00 2001 From: mmagician Date: Wed, 28 Jun 2023 23:12:40 +0200 Subject: [PATCH 018/108] use jf_primitives for IOPTranscript for FS transform --- Cargo.toml | 1 + src/ligero/mod.rs | 27 ++++++++++++++++++++------- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1e66e976..56557b0b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ hashbrown = { version = "0.13", default-features = false, optional = true } digest = "0.10" derivative = { version = "2", features = [ "use_core" ] } rayon = { version = "1", optional = true } +jf-primitives = { version = "0.4.0-pre.0", git = "https://github.com/tessico/jellyfish", branch = "make-iop-transcipt-pub" } [dev-dependencies] ark-ed-on-bls12-381 = { version = "^0.4.0", default-features = false } diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 18a1e69e..d7e7bc1a 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -1,4 +1,5 @@ use core::{borrow::Borrow, marker::PhantomData}; +use jf_primitives::pcs::transcript::IOPTranscript; use ark_crypto_primitives::{ merkle_tree::{Config, LeafParam, Path, TwoToOneParam}, @@ -59,6 +60,7 @@ where Self { _config: PhantomData, _field: PhantomData, + // TODO potentially can get rid of digest and sponge _digest: PhantomData, _sponge: PhantomData, } @@ -69,7 +71,6 @@ where commitment: &LigeroPCCommitment, leaf_hash_params: &LeafParam, two_to_one_params: &TwoToOneParam, - sponge: &mut S, ) -> Result<(), Error> { let t = calculate_t(rho_inv, sec_param); @@ -96,21 +97,33 @@ where // 3. verify the random linear combinations // 4. Verify the Fiat-Shamir transformation - sponge.absorb(&commitment.root); - let verifiers_randomness: Vec = sponge.squeeze_field_elements(t); - assert_eq!(verifiers_randomness, commitment.transcript.r); + // TODO replace unwraps by proper error handling + let mut transcript: IOPTranscript = IOPTranscript::new(b"test"); + transcript + .append_serializable_element(b"root", &commitment.root) + .unwrap(); + + let mut r = Vec::new(); + for _ in 0..t { + r.push(transcript.get_and_append_challenge(b"r").unwrap()); + } // Upon sending `v` to the Verifier, add it to the sponge - sponge.absorb(&commitment.transcript.v); + transcript + .append_serializable_element(b"v", &commitment.transcript.v) + .unwrap(); // we want to squeeze enough bytes to get the indices in the range [0, rho_inv * m) // TODO check whether this is right let bytes_to_squeeze = ((commitment.m * rho_inv) >> 8) + 1; let mut indices = Vec::with_capacity(t); for _ in 0..t { - let ind = sponge.squeeze_bytes(bytes_to_squeeze); + let mut bytes: Vec = vec![0; bytes_to_squeeze]; + let _ = transcript + .get_and_append_byte_challenge(b"i", &mut bytes) + .unwrap(); // get the usize from Vec: - let ind = ind.iter().fold(0, |acc, &x| (acc << 8) + x as usize); + let ind = bytes.iter().fold(0, |acc, &x| (acc << 8) + x as usize); // modulo the number of columns in the encoded matrix indices.push(ind % (rho_inv * commitment.m)); } From 7183c1e1a16bc6fa43eb45ca32bfb7b219924637 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mej=C3=ADas=20Gil?= Date: Thu, 29 Jun 2023 09:03:27 +0200 Subject: [PATCH 019/108] deleted settings.json file --- .vscode/settings.json | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 352a6265..00000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "rust-analyzer.linkedProjects": [ - "./Cargo.toml" - ] -} \ No newline at end of file From fe63bc2a926b1bf3555d738cc1446e7aecc5084f Mon Sep 17 00:00:00 2001 From: mmagician Date: Thu, 29 Jun 2023 09:16:01 +0200 Subject: [PATCH 020/108] remove merge artifacts --- src/ligero/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 34c2f60a..c9a23ae8 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -188,7 +188,7 @@ struct CommitmentTranscript { /// For each of the indices in q, `paths` contains the path from the root of the merkle tree to the leaf paths: Vec>, -gg + /// v, s.t. E(v) = w v: Vec, @@ -248,7 +248,7 @@ impl PolynomialComm for Ligero where F: PrimeField, - P: P: DenseUVPolynomial, + P: DenseUVPolynomial, S: CryptographicSponge, C: Config + 'static, D: Digest, From d58c366e7c32ae97e65b0b984a20b784bddc96e1 Mon Sep 17 00:00:00 2001 From: mmagician Date: Thu, 29 Jun 2023 10:18:39 +0200 Subject: [PATCH 021/108] Fix getting the indices from the transcript --- src/ligero/mod.rs | 23 +++++----- src/ligero/tests.rs | 10 +++++ src/ligero/utils.rs | 101 +++++++++++++++++++++++++++++++------------- 3 files changed, 95 insertions(+), 39 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index c9a23ae8..99d331b2 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -6,13 +6,15 @@ use ark_crypto_primitives::{ sponge::{Absorb, CryptographicSponge}, }; use ark_ff::PrimeField; +use ark_poly::{DenseUVPolynomial, GeneralEvaluationDomain}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use digest::Digest; -use ark_poly::{DenseUVPolynomial, GeneralEvaluationDomain}; use crate::{ - Error, PCCommitment, PCCommitterKey, PCPreparedCommitment, PCPreparedVerifierKey, PCRandomness, - PCUniversalParams, PCVerifierKey, PolynomialCommitment, ligero::utils::reed_solomon, LabeledCommitment, LabeledPolynomial, + ligero::utils::{get_num_bytes, reed_solomon}, + Error, LabeledCommitment, LabeledPolynomial, PCCommitment, PCCommitterKey, + PCPreparedCommitment, PCPreparedVerifierKey, PCRandomness, PCUniversalParams, PCVerifierKey, + PolynomialCommitment, }; use ark_std::rand::RngCore; @@ -71,7 +73,7 @@ where } /// The verifier can check the well-formedness of the commitment by taking random linear combinations. - fn verify( + fn well_formedness_check( commitment: &LigeroPCCommitment, leaf_hash_params: &LeafParam, two_to_one_params: &TwoToOneParam, @@ -98,9 +100,7 @@ where .unwrap(); } - // 3. verify the random linear combinations - - // 4. Verify the Fiat-Shamir transformation + // 3. Verify the Fiat-Shamir transformation // TODO replace unwraps by proper error handling let mut transcript: IOPTranscript = IOPTranscript::new(b"test"); transcript @@ -111,14 +111,16 @@ where for _ in 0..t { r.push(transcript.get_and_append_challenge(b"r").unwrap()); } - // Upon sending `v` to the Verifier, add it to the sponge + // Upon sending `v` to the Verifier, add it to the sponge. Claim is that v = r.M transcript .append_serializable_element(b"v", &commitment.transcript.v) .unwrap(); // we want to squeeze enough bytes to get the indices in the range [0, rho_inv * m) // TODO check whether this is right - let bytes_to_squeeze = ((commitment.m * rho_inv) >> 8) + 1; + + let num_encoded_rows = commitment.m * rho_inv; + let bytes_to_squeeze = get_num_bytes(num_encoded_rows); let mut indices = Vec::with_capacity(t); for _ in 0..t { let mut bytes: Vec = vec![0; bytes_to_squeeze]; @@ -129,9 +131,10 @@ where // get the usize from Vec: let ind = bytes.iter().fold(0, |acc, &x| (acc << 8) + x as usize); // modulo the number of columns in the encoded matrix - indices.push(ind % (rho_inv * commitment.m)); + indices.push(ind % num_encoded_rows); } + // 4. verify the random linear combinations todo!() } } diff --git a/src/ligero/tests.rs b/src/ligero/tests.rs index 8f1f9e34..11ca6c1f 100644 --- a/src/ligero/tests.rs +++ b/src/ligero/tests.rs @@ -91,4 +91,14 @@ mod tests { assert_eq!(fft_domain.ifft(&vals), pol_coeffs); } + #[test] + fn test_get_num_bytes() { + assert_eq!(get_num_bytes(0), 0); + assert_eq!(get_num_bytes(1), 1); + assert_eq!(get_num_bytes(9), 1); + assert_eq!(get_num_bytes(1 << 11), 2); + assert_eq!(get_num_bytes(1 << 32 - 1), 4); + assert_eq!(get_num_bytes(1 << 32), 5); + assert_eq!(get_num_bytes(1 << 32 + 1), 5); + } } \ No newline at end of file diff --git a/src/ligero/utils.rs b/src/ligero/utils.rs index af82a913..e5bf5b7a 100644 --- a/src/ligero/utils.rs +++ b/src/ligero/utils.rs @@ -1,28 +1,44 @@ -use ark_ff::{Field, FftField}; +use ark_ff::{FftField, Field}; -use ark_poly::{GeneralEvaluationDomain, EvaluationDomain, univariate::DensePolynomial, DenseUVPolynomial, Polynomial, domain::general::GeneralElements}; -use rayon::{iter::{ParallelIterator, IntoParallelRefIterator}, prelude::IndexedParallelIterator}; +use ark_poly::{ + domain::general::GeneralElements, univariate::DensePolynomial, DenseUVPolynomial, + EvaluationDomain, GeneralEvaluationDomain, Polynomial, +}; +use rayon::{ + iter::{IntoParallelRefIterator, ParallelIterator}, + prelude::IndexedParallelIterator, +}; + +use crate::streaming_kzg::ceil_div; pub(crate) struct Matrix { n: usize, m: usize, - entries: Vec> + entries: Vec>, } impl Matrix { - /// Returns a Matrix of dimensions n x m given a list of n * m field elements. /// The list should be ordered row-first, i.e. [a11, ..., a1m, a21, ..., a2m, ...]. /// /// # Panics /// Panics if the dimensions do not match the length of the list pub(crate) fn new_from_flat(n: usize, m: usize, entry_list: &[F]) -> Self { - assert_eq!(entry_list.len(), n * m, "Invalid matrix construction: dimensions are {} x {} but entry vector has {} entries", m, n, entry_list.len()); + assert_eq!( + entry_list.len(), + n * m, + "Invalid matrix construction: dimensions are {} x {} but entry vector has {} entries", + m, + n, + entry_list.len() + ); // TODO more efficient to run linearly? - let entries: Vec> = (0..n).map(|row| (0..m).map(|col| entry_list[n * row + m]).collect()).collect(); + let entries: Vec> = (0..n) + .map(|row| (0..m).map(|col| entry_list[n * row + m]).collect()) + .collect(); - Self {n, m, entries} + Self { n, m, entries } } /// Returns a Matrix given a list of its rows, each in turn represented as a list of field elements. @@ -33,43 +49,65 @@ impl Matrix { let m = row_list[0].len(); for row in row_list.iter().skip(1) { - assert_eq!(row.len(), m, "Invalid matrix construction: not all rows have the same length"); + assert_eq!( + row.len(), + m, + "Invalid matrix construction: not all rows have the same length" + ); } - Self {n: row_list.len(), m, entries: row_list} + Self { + n: row_list.len(), + m, + entries: row_list, + } } /// Returns the entry in position (i, j). **Indexing starts at 0 in both coordinates**, /// i.e. the first element is in position (0, 0) and the last one in (n - 1, j - 1), /// where n and m are the number of rows and columns, respectively. - /// + /// /// Index bound checks are waived for efficiency and behaviour under invalid indexing is undefined pub(crate) fn entry(&self, i: usize, j: usize) -> F { - return self.entries[i][j] + return self.entries[i][j]; } /// Returns self as a list of rows pub(crate) fn rows(&self) -> Vec> { - return self.entries.clone() + return self.entries.clone(); } /// Returns self as a list of columns pub(crate) fn cols(&self) -> Vec> { - (0..self.m).map(|col| (0..self.n).map(|row| self.entries[row][col]).collect()).collect() + (0..self.m) + .map(|col| (0..self.n).map(|row| self.entries[row][col]).collect()) + .collect() } - + /// Returns the product v * self, where v is interpreted as a row vector. In other words, /// it returns a linear combination of the rows of self with coefficients given by v. /// /// Panics if the length of v is different from the number of rows of self. pub(crate) fn row_mul(&self, v: &[F]) -> Vec { - assert_eq!(v.len(), self.n, "Invalid row multiplication x has {} elements whereas the matrix has {}", v.len(), self.n); - - (0..self.m).map(|col| inner_product( - v, &(0..self.n).map(|row| self.entries[row][col]).collect::>() - )).collect() + assert_eq!( + v.len(), + self.n, + "Invalid row multiplication x has {} elements whereas the matrix has {}", + v.len(), + self.n + ); + + (0..self.m) + .map(|col| { + inner_product( + v, + &(0..self.n) + .map(|row| self.entries[row][col]) + .collect::>(), + ) + }) + .collect() } - } // TODO batch for all rows? possibly minimal savings due to not having to create fft_domain every time @@ -77,10 +115,9 @@ impl Matrix { pub(crate) fn reed_solomon( msg: &[F], rho_inverse: usize, - fft_domain: GeneralEvaluationDomain::, - &mut domain_iter: GeneralElements:: + fft_domain: GeneralEvaluationDomain, + domain_iter: &mut GeneralElements, ) -> Vec { - // TODO is this check worth it? // rho_inverse = 0 should never happen; rho_inverse = 1 means no expansion if rho_inverse <= 1 { @@ -98,20 +135,26 @@ pub(crate) fn reed_solomon( for _ in 0..(rho_inverse - 1) * m { // TODO make sure the domain has enough elements in the caller or check here let zeta = domain_iter.next().unwrap(); - encoding.push(pol.evaluate(zeta)); - + encoding.push(pol.evaluate(&zeta)); } encoding - } #[inline] pub(crate) fn inner_product(v1: &[F], v2: &[F]) -> F { - ark_std::cfg_iter!(v1).zip(v2).map(|(li, ri)| *li * ri).sum() + ark_std::cfg_iter!(v1) + .zip(v2) + .map(|(li, ri)| *li * ri) + .sum() } #[inline] pub(crate) fn to_field(v: Vec) -> Vec { v.iter().map(|x| F::from(*x)).collect::>() -} \ No newline at end of file +} + +#[inline] +pub(crate) fn get_num_bytes(n: usize) -> usize { + ceil_div((usize::BITS - n.leading_zeros()) as usize, 8) +} From aa913efbbf05e185cc8965d793861136b2622861 Mon Sep 17 00:00:00 2001 From: mmagician Date: Thu, 29 Jun 2023 10:32:16 +0200 Subject: [PATCH 022/108] path verification with the random index retrieved from the transcript --- src/ligero/mod.rs | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 99d331b2..5c7029fb 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -86,27 +86,13 @@ where // TODO some hashing, with the digest? } - // 2. Verify the paths for each of the leaf hashes - // TODO need a way to relate the index to the leaf hash - for (i, leaf) in col_hashes.iter().enumerate() { - // TODO handle the error here - commitment.transcript.paths[i] - .verify( - leaf_hash_params, - two_to_one_params, - &commitment.root, - leaf.clone(), - ) - .unwrap(); - } - - // 3. Verify the Fiat-Shamir transformation // TODO replace unwraps by proper error handling let mut transcript: IOPTranscript = IOPTranscript::new(b"test"); transcript .append_serializable_element(b"root", &commitment.root) .unwrap(); + // 2. Get the linear combination coefficients from the transcript let mut r = Vec::new(); for _ in 0..t { r.push(transcript.get_and_append_challenge(b"r").unwrap()); @@ -117,8 +103,7 @@ where .unwrap(); // we want to squeeze enough bytes to get the indices in the range [0, rho_inv * m) - // TODO check whether this is right - + // 3. Compute t column indices to check the linear combination at let num_encoded_rows = commitment.m * rho_inv; let bytes_to_squeeze = get_num_bytes(num_encoded_rows); let mut indices = Vec::with_capacity(t); @@ -134,7 +119,28 @@ where indices.push(ind % num_encoded_rows); } + // 3. Verify the paths for each of the leaf hashes + for (leaf, i) in col_hashes.into_iter().zip(indices.iter()) { + // TODO handle the error here + let path = &commitment.transcript.paths[*i]; + assert!(path.leaf_index == *i, "Path is for a different index!"); + + path.verify( + leaf_hash_params, + two_to_one_params, + &commitment.root, + leaf, + ) + .unwrap(); + } + // 4. verify the random linear combinations + // Compute the encoding of v, s.t. E(v) = w + let w = &commitment.transcript.v; + for index in indices { + // check that r.M_i = w_i + // transcript + } todo!() } } From 243be3d1a718dc4a70985dca29a988f88f4d76cb Mon Sep 17 00:00:00 2001 From: mmagician Date: Thu, 29 Jun 2023 10:41:06 +0200 Subject: [PATCH 023/108] verify the random linear combinations in the F-S commitment check --- src/ligero/mod.rs | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 5c7029fb..f3f2d45e 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -6,12 +6,12 @@ use ark_crypto_primitives::{ sponge::{Absorb, CryptographicSponge}, }; use ark_ff::PrimeField; -use ark_poly::{DenseUVPolynomial, GeneralEvaluationDomain}; +use ark_poly::{DenseUVPolynomial, EvaluationDomain, GeneralEvaluationDomain}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use digest::Digest; use crate::{ - ligero::utils::{get_num_bytes, reed_solomon}, + ligero::utils::{get_num_bytes, inner_product, reed_solomon}, Error, LabeledCommitment, LabeledPolynomial, PCCommitment, PCCommitterKey, PCPreparedCommitment, PCPreparedVerifierKey, PCRandomness, PCUniversalParams, PCVerifierKey, PolynomialCommitment, @@ -125,23 +125,32 @@ where let path = &commitment.transcript.paths[*i]; assert!(path.leaf_index == *i, "Path is for a different index!"); - path.verify( - leaf_hash_params, - two_to_one_params, - &commitment.root, - leaf, - ) - .unwrap(); + path.verify(leaf_hash_params, two_to_one_params, &commitment.root, leaf) + .unwrap(); } - // 4. verify the random linear combinations - // Compute the encoding of v, s.t. E(v) = w - let w = &commitment.transcript.v; - for index in indices { - // check that r.M_i = w_i - // transcript + // 4. Compute the encoding of v, s.t. E(v) = w + let fft_domain = GeneralEvaluationDomain::::new(commitment.m).unwrap(); + let mut domain_iter = fft_domain.elements(); + let w = reed_solomon( + &commitment.transcript.v, + rho_inv, + fft_domain, + &mut domain_iter, + ); + + // 5. verify the random linear combinations + for (transcript_index, matrix_index) in indices.into_iter().enumerate() { + if inner_product(&r, &commitment.transcript.columns[transcript_index]) + != w[matrix_index] + { + // TODO return proper error + return Err(Error::IncorrectInputLength( + "Incorrect linear combination".to_string(), + )); + } } - todo!() + Ok(()) } } From 4c7631d8c22fe9ba7623461856895f6f93f839e8 Mon Sep 17 00:00:00 2001 From: mmagician Date: Thu, 29 Jun 2023 10:58:20 +0200 Subject: [PATCH 024/108] hashing columns - WIP --- src/ligero/mod.rs | 15 ++++++++------- src/ligero/utils.rs | 10 +++++++++- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index f3f2d45e..e5d9d1b7 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -322,12 +322,13 @@ where where P: 'a, { - // TODO loop over all polys + unimplemented!() + /* // TODO loop over all polys let LabeledPolynomial{label, polynomial, degree_bound, ..} = *polynomials.into_iter().next().unwrap(); let mut coeffs = polynomial.coeffs().to_vec(); - // want: ceil(sqrt(f.degree() + 1)); need to deal with usize -> f64 conversion + // want: ceil(sqrt(f.degree() + 1)); need to deal with usize -> f64 conversion let num_elems = polynomial.degree() + 1; // TODO move this check to the constructor? assert_eq!((num_elems as f64) as usize, num_elems, "Degree of polynomial + 1 cannot be converted to f64: aborting"); @@ -337,7 +338,7 @@ where // padding the coefficient vector with zeroes // TODO is this the most efficient way to do it? - coeffs.resize(m * m, F::zero()); + coeffs.resize(m * m, F::zero()); let mat = Matrix::new_from_flat( m, m, &coeffs); @@ -347,7 +348,7 @@ where let fft_domain = GeneralEvaluationDomain::::new(m).unwrap(); let domain_iter = fft_domain.elements(); - + let ext_mat = Matrix::new_from_rows( mat.rows().iter().map(|r| reed_solomon( r, @@ -389,8 +390,8 @@ where let commitment = Commitment::new(m, root, wf_transcript); Ok(LabeledCommitment::new(label, commitment, degree_bound)); - - // TODO when should this return Err? + + // TODO when should this return Err? */ } fn open<'a>( @@ -426,4 +427,4 @@ where } } -// TODO start considering degree bound \ No newline at end of file +// TODO start considering degree bound diff --git a/src/ligero/utils.rs b/src/ligero/utils.rs index e5bf5b7a..ab639bff 100644 --- a/src/ligero/utils.rs +++ b/src/ligero/utils.rs @@ -1,9 +1,10 @@ -use ark_ff::{FftField, Field}; +use ark_ff::{FftField, Field, PrimeField}; use ark_poly::{ domain::general::GeneralElements, univariate::DensePolynomial, DenseUVPolynomial, EvaluationDomain, GeneralEvaluationDomain, Polynomial, }; +use digest::Digest; use rayon::{ iter::{IntoParallelRefIterator, ParallelIterator}, prelude::IndexedParallelIterator, @@ -158,3 +159,10 @@ pub(crate) fn to_field(v: Vec) -> Vec { pub(crate) fn get_num_bytes(n: usize) -> usize { ceil_div((usize::BITS - n.leading_zeros()) as usize, 8) } + +pub(crate) fn hash_array(array: &[F]) -> Vec { + + let data = array.to_bytes(); + let dig = D::new(); + D::digest(data).to_vec() +} \ No newline at end of file From 348c88e0ae063ee16ddd2089be52146a79d71ddc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mej=C3=ADas=20Gil?= Date: Thu, 29 Jun 2023 11:27:18 +0200 Subject: [PATCH 025/108] well_formedness_check completed, not tested --- src/lib.rs | 16 ++++++++-------- src/ligero/mod.rs | 8 ++++++-- src/ligero/tests.rs | 5 +++++ src/ligero/utils.rs | 26 +++++++++++++++++++++----- 4 files changed, 40 insertions(+), 15 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 5d7ae548..20dbdd03 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,13 +1,13 @@ #![cfg_attr(not(feature = "std"), no_std)] //! A crate for polynomial commitment schemes. -#![deny(unused_import_braces, unused_qualifications, trivial_casts)] -#![deny(trivial_numeric_casts, private_in_public, variant_size_differences)] -#![deny(stable_features, unreachable_pub, non_shorthand_field_patterns)] -#![deny(unused_attributes, unused_mut)] -#![deny(missing_docs)] -#![deny(unused_imports)] -#![deny(renamed_and_removed_lints, stable_features, unused_allocation)] -#![deny(unused_comparisons, bare_trait_objects, unused_must_use)] +// #![deny(unused_import_braces, unused_qualifications, trivial_casts)] +// #![deny(trivial_numeric_casts, private_in_public, variant_size_differences)] +// #![deny(stable_features, unreachable_pub, non_shorthand_field_patterns)] +// #![deny(unused_attributes, unused_mut)] +// #![deny(missing_docs)] +// #![deny(unused_imports)] +// #![deny(renamed_and_removed_lints, stable_features, unused_allocation)] +// #![deny(unused_comparisons, bare_trait_objects, unused_must_use)] #![forbid(unsafe_code)] #[allow(unused)] diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index e5d9d1b7..f2b75746 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -21,6 +21,8 @@ use ark_std::rand::RngCore; mod utils; use utils::Matrix; + +use self::utils::hash_array; mod tests; // TODO: Disclaimer: no hiding prop @@ -54,7 +56,8 @@ fn calculate_t(rho_inv: usize, sec_param: usize) -> usize { impl Ligero where - F: PrimeField + Borrow<::Leaf> + Absorb, + F: PrimeField + Absorb, + Vec: Borrow<::Leaf>, C: Config, C::InnerDigest: Absorb, D: Digest, @@ -81,8 +84,9 @@ where let t = calculate_t(rho_inv, sec_param); // 1. Hash the received columns, to get the leaf hashes - let col_hashes: Vec = vec![F::zero(); t]; + let mut col_hashes = Vec::new(); for c in commitment.transcript.columns.iter() { + col_hashes.push(hash_array::(c)) // TODO some hashing, with the digest? } diff --git a/src/ligero/tests.rs b/src/ligero/tests.rs index 11ca6c1f..ab994a6e 100644 --- a/src/ligero/tests.rs +++ b/src/ligero/tests.rs @@ -101,4 +101,9 @@ mod tests { assert_eq!(get_num_bytes(1 << 32), 5); assert_eq!(get_num_bytes(1 << 32 + 1), 5); } + +/* #[test] + fn test_well_formedness { + + } */ } \ No newline at end of file diff --git a/src/ligero/utils.rs b/src/ligero/utils.rs index ab639bff..7a14050c 100644 --- a/src/ligero/utils.rs +++ b/src/ligero/utils.rs @@ -4,6 +4,7 @@ use ark_poly::{ domain::general::GeneralElements, univariate::DensePolynomial, DenseUVPolynomial, EvaluationDomain, GeneralEvaluationDomain, Polynomial, }; +use ark_serialize::CanonicalSerialize; use digest::Digest; use rayon::{ iter::{IntoParallelRefIterator, ParallelIterator}, @@ -160,9 +161,24 @@ pub(crate) fn get_num_bytes(n: usize) -> usize { ceil_div((usize::BITS - n.leading_zeros()) as usize, 8) } -pub(crate) fn hash_array(array: &[F]) -> Vec { +/// Takes as input a struct, and converts them to a series of bytes. All traits +/// that implement `CanonicalSerialize` can be automatically converted to bytes +/// in this manner. +/// From jellyfish lib +#[macro_export] +macro_rules! to_bytes { + ($x:expr) => {{ + let mut buf = ark_std::vec![]; + ark_serialize::CanonicalSerialize::serialize_compressed($x, &mut buf).map(|_| buf) + }}; +} + +#[inline] +pub(crate) fn hash_array(array: &[F]) -> Vec { - let data = array.to_bytes(); - let dig = D::new(); - D::digest(data).to_vec() -} \ No newline at end of file + let mut dig = D::new(); + for elem in array { + dig.update(to_bytes!(elem).unwrap()); + } + dig.finalize().to_vec() +} From 0b7ee4a288d2355e5cbfd1da17ddb2f90d39577c Mon Sep 17 00:00:00 2001 From: mmagician Date: Thu, 29 Jun 2023 11:51:32 +0200 Subject: [PATCH 026/108] change trait bounds on C::Leaf --- src/ligero/mod.rs | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index f2b75746..15184ae9 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -56,9 +56,9 @@ fn calculate_t(rho_inv: usize, sec_param: usize) -> usize { impl Ligero where - F: PrimeField + Absorb, - Vec: Borrow<::Leaf>, + F: PrimeField, C: Config, + C::Leaf: Sized + From>, C::InnerDigest: Absorb, D: Digest, S: CryptographicSponge, @@ -84,9 +84,9 @@ where let t = calculate_t(rho_inv, sec_param); // 1. Hash the received columns, to get the leaf hashes - let mut col_hashes = Vec::new(); + let mut col_hashes: Vec = Vec::new(); for c in commitment.transcript.columns.iter() { - col_hashes.push(hash_array::(c)) + col_hashes.push(hash_array::(c).into()); // TODO some hashing, with the digest? } @@ -142,7 +142,7 @@ where fft_domain, &mut domain_iter, ); - + // 5. verify the random linear combinations for (transcript_index, matrix_index) in indices.into_iter().enumerate() { if inner_product(&r, &commitment.transcript.columns[transcript_index]) @@ -202,12 +202,6 @@ impl PCPreparedVerifierKey for LigeroPCPr #[derivative(Default(bound = ""), Clone(bound = ""), Debug(bound = ""))] struct CommitmentTranscript { - /// the randomness generated by the verifier - r: Vec, - - /// set of indices at which the verifier queries the commitment matrtix - q: Vec, - /// For each of the indices in q, `paths` contains the path from the root of the merkle tree to the leaf paths: Vec>, @@ -273,6 +267,8 @@ where P: DenseUVPolynomial, S: CryptographicSponge, C: Config + 'static, + C::Leaf: Sized + From>, + C::InnerDigest: Absorb, D: Digest, { type UniversalParams = LigeroPCUniversalParams; @@ -427,6 +423,15 @@ where where Self::Commitment: 'a, { + let labeled_commitment = commitments.into_iter().next().unwrap(); + // // check if we've seen this commitment before. If not, we should verify it. + let leaf_hash_params = vk.leaf_hash_params; + let two_to_one_params = vk.two_to_one_params; + Self::well_formedness_check( + labeled_commitment.commitment(), + leaf_hash_params, + two_to_one_params, + ); todo!() } } From 5a309e2fb4f6084ea8ee8fb5b1259c100c68d297 Mon Sep 17 00:00:00 2001 From: mmagician Date: Thu, 29 Jun 2023 12:39:23 +0200 Subject: [PATCH 027/108] temp remove hash params --- src/ligero/mod.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 15184ae9..1381f721 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -425,13 +425,13 @@ where { let labeled_commitment = commitments.into_iter().next().unwrap(); // // check if we've seen this commitment before. If not, we should verify it. - let leaf_hash_params = vk.leaf_hash_params; - let two_to_one_params = vk.two_to_one_params; - Self::well_formedness_check( - labeled_commitment.commitment(), - leaf_hash_params, - two_to_one_params, - ); + // let leaf_hash_params = vk.leaf_hash_params; + // let two_to_one_params = vk.two_to_one_params; + // Self::well_formedness_check( + // labeled_commitment.commitment(), + // leaf_hash_params, + // two_to_one_params, + // ); todo!() } } From 89286fe37a2335cb08e03de5b80ccdf535242d57 Mon Sep 17 00:00:00 2001 From: mmagician Date: Thu, 29 Jun 2023 14:18:28 +0200 Subject: [PATCH 028/108] create the MT Config params using the setup function --- src/ligero/mod.rs | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 1381f721..f73ae6d7 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -1,6 +1,5 @@ -use core::{borrow::Borrow, marker::PhantomData}; -use jf_primitives::pcs::transcript::IOPTranscript; - +use ark_crypto_primitives::crh::CRHScheme; +use ark_crypto_primitives::crh::TwoToOneCRHScheme; use ark_crypto_primitives::{ merkle_tree::{Config, LeafParam, Path, TwoToOneParam}, sponge::{Absorb, CryptographicSponge}, @@ -8,7 +7,9 @@ use ark_crypto_primitives::{ use ark_ff::PrimeField; use ark_poly::{DenseUVPolynomial, EvaluationDomain, GeneralEvaluationDomain}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; +use core::{borrow::Borrow, marker::PhantomData}; use digest::Digest; +use jf_primitives::pcs::transcript::IOPTranscript; use crate::{ ligero::utils::{get_num_bytes, inner_product, reed_solomon}, @@ -423,15 +424,16 @@ where where Self::Commitment: 'a, { + let mut rng = rng.unwrap(); let labeled_commitment = commitments.into_iter().next().unwrap(); - // // check if we've seen this commitment before. If not, we should verify it. - // let leaf_hash_params = vk.leaf_hash_params; - // let two_to_one_params = vk.two_to_one_params; - // Self::well_formedness_check( - // labeled_commitment.commitment(), - // leaf_hash_params, - // two_to_one_params, - // ); + // check if we've seen this commitment before. If not, we should verify it. + let leaf_hash_params = C::LeafHash::setup(&mut rng).unwrap(); + let two_to_one_params = C::TwoToOneHash::setup(&mut rng).unwrap(); + Self::well_formedness_check( + labeled_commitment.commitment(), + &leaf_hash_params, + &two_to_one_params, + ); todo!() } } From 0775b2464708633ac5b6e1688f43f2b38352a960 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mej=C3=ADas=20Gil?= Date: Thu, 29 Jun 2023 15:04:51 +0200 Subject: [PATCH 029/108] commit finished up to leaf parameters --- src/ligero/mod.rs | 121 ++++++++++++++++++++++++++++++-------------- src/ligero/utils.rs | 13 ++++- 2 files changed, 94 insertions(+), 40 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index f73ae6d7..3cba96bd 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -1,7 +1,7 @@ use ark_crypto_primitives::crh::CRHScheme; use ark_crypto_primitives::crh::TwoToOneCRHScheme; use ark_crypto_primitives::{ - merkle_tree::{Config, LeafParam, Path, TwoToOneParam}, + merkle_tree::{Config, LeafParam, Path, TwoToOneParam, MerkleTree}, sponge::{Absorb, CryptographicSponge}, }; use ark_ff::PrimeField; @@ -92,7 +92,7 @@ where } // TODO replace unwraps by proper error handling - let mut transcript: IOPTranscript = IOPTranscript::new(b"test"); + let mut transcript: IOPTranscript = IOPTranscript::new(b"well_formedness_transcript"); transcript .append_serializable_element(b"root", &commitment.root) .unwrap(); @@ -124,7 +124,7 @@ where indices.push(ind % num_encoded_rows); } - // 3. Verify the paths for each of the leaf hashes + // 4. Verify the paths for each of the leaf hashes for (leaf, i) in col_hashes.into_iter().zip(indices.iter()) { // TODO handle the error here let path = &commitment.transcript.paths[*i]; @@ -134,7 +134,7 @@ where .unwrap(); } - // 4. Compute the encoding of v, s.t. E(v) = w + // 5. Compute the encoding of v, s.t. E(v) = w let fft_domain = GeneralEvaluationDomain::::new(commitment.m).unwrap(); let mut domain_iter = fft_domain.elements(); let w = reed_solomon( @@ -143,8 +143,8 @@ where fft_domain, &mut domain_iter, ); - - // 5. verify the random linear combinations + + // 6. Verify the random linear combinations for (transcript_index, matrix_index) in indices.into_iter().enumerate() { if inner_product(&r, &commitment.transcript.columns[transcript_index]) != w[matrix_index] @@ -167,7 +167,11 @@ impl PCUniversalParams for LigeroPCUniversalParams { } } -type LigeroPCCommitterKey = (); +struct LigeroPCCommitterKey { + leaf_crh_params: (), + two_to_one_params: (), + t: usize, // number of columns to test the random linear combination at +} impl PCCommitterKey for LigeroPCCommitterKey { fn max_degree(&self) -> usize { @@ -202,7 +206,7 @@ impl PCPreparedVerifierKey for LigeroPCPr #[derive(Derivative, CanonicalSerialize, CanonicalDeserialize)] #[derivative(Default(bound = ""), Clone(bound = ""), Debug(bound = ""))] -struct CommitmentTranscript { +struct Proof { /// For each of the indices in q, `paths` contains the path from the root of the merkle tree to the leaf paths: Vec>, @@ -217,11 +221,11 @@ struct CommitmentTranscript { #[derive(Derivative, CanonicalSerialize, CanonicalDeserialize)] #[derivative(Default(bound = ""), Clone(bound = ""), Debug(bound = ""))] pub struct LigeroPCCommitment { - // TODO is InnerDigest the right type? - root: C::InnerDigest, // number of rows of the square matrix containing the coefficients of the polynomial m: usize, - transcript: CommitmentTranscript, + // TODO is InnerDigest the right type? + root: C::InnerDigest, + proof: Proof, } impl PCCommitment for LigeroPCCommitment { @@ -323,30 +327,30 @@ where where P: 'a, { - unimplemented!() - /* // TODO loop over all polys + + // TODO loop over all polynomials let LabeledPolynomial{label, polynomial, degree_bound, ..} = *polynomials.into_iter().next().unwrap(); let mut coeffs = polynomial.coeffs().to_vec(); + // 1. Computing parameters and initial matrix // want: ceil(sqrt(f.degree() + 1)); need to deal with usize -> f64 conversion let num_elems = polynomial.degree() + 1; + // TODO move this check to the constructor? assert_eq!((num_elems as f64) as usize, num_elems, "Degree of polynomial + 1 cannot be converted to f64: aborting"); let m = (num_elems as f64).sqrt().ceil() as usize; - // TODO: check if fft_domain.compute_size_of_domain(m) is large enough // padding the coefficient vector with zeroes - // TODO is this the most efficient way to do it? + // TODO is this the most efficient/safest way to do it? coeffs.resize(m * m, F::zero()); let mat = Matrix::new_from_flat( m, m, &coeffs); - // TODO rho_inv not part of self? + // 2. Apply Reed-Solomon encoding row-wise let rho_inv = 2; // self.rho_inv - // applying Reed-Solomon code row-wise - + let fft_domain = GeneralEvaluationDomain::::new(m).unwrap(); let domain_iter = fft_domain.elements(); @@ -355,44 +359,83 @@ where r, rho_inv, fft_domain, - domain_iter + &mut domain_iter )).collect() ); + // 3. Create the Merkle tree from the hashes of the columns let col_hashes = Vec::new(); + let ext_mat_cols = ext_mat.cols(); - let mat_cols = ext_mat.cols(); - - for col in mat_cols { - // col_hashes.push(hash of col) + for col in ext_mat_cols { + col_hashes.push(hash_array(&col)); } - // let tree = Merkle tree from col_hashes (the library might take care of padding to a power of 2) - // let r = root of the tree - // + let col_tree = MerkleTree::new::( + &ck.leaf_crh_params, + &ck.two_to_one_params, + col_hashes, + ).unwrap(); - // generating transcript for the verification of well-formedness - let random_lc_coeffs = // generate m coefficients by hashing the root - let random_lc = ext_mat.row_mul(random_lc_coeffs); + let root = col_tree.root(); - wf_transcript.random_lc = random_lc; + // 4. Add root to transcript and generate random linear combination with it + let mut transcript: IOPTranscript = IOPTranscript::new(b"well_formedness_transcript"); + transcript + .append_serializable_element(b"root", root) + .unwrap(); - let queried_columns =; // generate t column indices by hashing random_lc (the last element in the transcript) + // 5. Generate linear combination using the matrix and random coefficients + let mut r = Vec::new(); + for _ in 0..ck.t { + r.push(transcript.get_and_append_challenge(b"r").unwrap()); + } + + let v = mat.row_mul(r); - let mat_cols = mat.cols(); + transcript + .append_serializable_element(b"v", v) + .unwrap(); + + // 6. Generate t column indices to test the linear combination on + let num_encoded_rows = m * rho_inv; + let bytes_to_squeeze = get_num_bytes(num_encoded_rows); + let mut indices = Vec::with_capacity(ck.t); + for _ in 0..ck.t { + let mut bytes: Vec = vec![0; bytes_to_squeeze]; + let _ = transcript + .get_and_append_byte_challenge(b"i", &mut bytes) + .unwrap(); + + // get the usize from Vec: + let ind = bytes.iter().fold(0, |acc, &x| (acc << 8) + x as usize); + // modulo the number of columns in the encoded matrix + indices.push(ind % num_encoded_rows); + } + + // 7. Compute Merkle tree paths for the columns + let queried_columns = Vec::new(); + let paths = Vec::new(); - for i in queried_columns { - wf_transcript.colums.push(mat_cols[i]); - wf_transcript.column_proofs.push(merkle._tree_proof(i)); + for i in indices { + queried_columns.push(ext_mat_cols[i]); + paths.push(col_tree.generate_proof(i)); } - //... + let proof: Proof = Proof { + paths, + v, + columns: queried_columns, + }; - let commitment = Commitment::new(m, root, wf_transcript); + let commitment = LigeroPCCommitment::new( + m, + root, + proof, + ); Ok(LabeledCommitment::new(label, commitment, degree_bound)); - - // TODO when should this return Err? */ + // TODO when should this return Err? } fn open<'a>( diff --git a/src/ligero/utils.rs b/src/ligero/utils.rs index 7a14050c..438066d0 100644 --- a/src/ligero/utils.rs +++ b/src/ligero/utils.rs @@ -143,6 +143,17 @@ pub(crate) fn reed_solomon( encoding } +/* DummyCK { + t: int; +} + +impl DummyCK { + fn new() -> Self { + println!("WARNING: You are using dummy parameters"), + + } +} + */ #[inline] pub(crate) fn inner_product(v1: &[F], v2: &[F]) -> F { ark_std::cfg_iter!(v1) @@ -175,7 +186,7 @@ macro_rules! to_bytes { #[inline] pub(crate) fn hash_array(array: &[F]) -> Vec { - + let mut dig = D::new(); for elem in array { dig.update(to_bytes!(elem).unwrap()); From 74c7c54ebf066d6dcc4e26aee7821acf871fc710 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mej=C3=ADas=20Gil?= Date: Thu, 29 Jun 2023 18:04:59 +0200 Subject: [PATCH 030/108] one remaining compilation error in commit: construction of the tree --- src/ligero/mod.rs | 78 ++++++++++++++++++++++++--------------------- src/ligero/tests.rs | 2 +- src/ligero/utils.rs | 13 +------- 3 files changed, 43 insertions(+), 50 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 3cba96bd..c2eac563 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -4,6 +4,8 @@ use ark_crypto_primitives::{ merkle_tree::{Config, LeafParam, Path, TwoToOneParam, MerkleTree}, sponge::{Absorb, CryptographicSponge}, }; +use ark_ff::BigInt; +use ark_ff::BigInteger256; use ark_ff::PrimeField; use ark_poly::{DenseUVPolynomial, EvaluationDomain, GeneralEvaluationDomain}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; @@ -51,6 +53,7 @@ const DEFAULT_SEC_PARAM: usize = 128; fn calculate_t(rho_inv: usize, sec_param: usize) -> usize { // TODO calculate t somehow let t = 5; + println!("WARNING: you are using dummy t = {t}"); t } @@ -79,14 +82,14 @@ where /// The verifier can check the well-formedness of the commitment by taking random linear combinations. fn well_formedness_check( commitment: &LigeroPCCommitment, - leaf_hash_params: &LeafParam, - two_to_one_params: &TwoToOneParam, + leaf_hash_param: &LeafParam, + two_to_one_param: &TwoToOneParam, ) -> Result<(), Error> { let t = calculate_t(rho_inv, sec_param); // 1. Hash the received columns, to get the leaf hashes let mut col_hashes: Vec = Vec::new(); - for c in commitment.transcript.columns.iter() { + for c in commitment.proof.columns.iter() { col_hashes.push(hash_array::(c).into()); // TODO some hashing, with the digest? } @@ -104,7 +107,7 @@ where } // Upon sending `v` to the Verifier, add it to the sponge. Claim is that v = r.M transcript - .append_serializable_element(b"v", &commitment.transcript.v) + .append_serializable_element(b"v", &commitment.proof.v) .unwrap(); // we want to squeeze enough bytes to get the indices in the range [0, rho_inv * m) @@ -125,12 +128,12 @@ where } // 4. Verify the paths for each of the leaf hashes - for (leaf, i) in col_hashes.into_iter().zip(indices.iter()) { + for (leaf, i) in col_hashes.into_iter().zip(indices.into_iter()) { // TODO handle the error here - let path = &commitment.transcript.paths[*i]; - assert!(path.leaf_index == *i, "Path is for a different index!"); + let path = &commitment.proof.paths[i]; + assert!(path.leaf_index == i, "Path is for a different index!"); - path.verify(leaf_hash_params, two_to_one_params, &commitment.root, leaf) + path.verify(leaf_hash_param, two_to_one_param, &commitment.root, leaf) .unwrap(); } @@ -138,7 +141,7 @@ where let fft_domain = GeneralEvaluationDomain::::new(commitment.m).unwrap(); let mut domain_iter = fft_domain.elements(); let w = reed_solomon( - &commitment.transcript.v, + &commitment.proof.v, rho_inv, fft_domain, &mut domain_iter, @@ -146,7 +149,7 @@ where // 6. Verify the random linear combinations for (transcript_index, matrix_index) in indices.into_iter().enumerate() { - if inner_product(&r, &commitment.transcript.columns[transcript_index]) + if inner_product(&r, &commitment.proof.columns[transcript_index]) != w[matrix_index] { // TODO return proper error @@ -167,11 +170,7 @@ impl PCUniversalParams for LigeroPCUniversalParams { } } -struct LigeroPCCommitterKey { - leaf_crh_params: (), - two_to_one_params: (), - t: usize, // number of columns to test the random linear combination at -} +type LigeroPCCommitterKey = (); impl PCCommitterKey for LigeroPCCommitterKey { fn max_degree(&self) -> usize { @@ -327,7 +326,12 @@ where where P: 'a, { - + // 0. Recovering parameters + let t = calculate_t(rho_inv, sec_param); + let mut optional = crate::optional_rng::OptionalRng(rng); // TODO taken from Marlin code; change in the future? + let leaf_hash_param = C::LeafHash::setup(&mut optional).unwrap(); + let two_to_one_param = C::TwoToOneHash::setup(&mut optional).unwrap(); + // TODO loop over all polynomials let LabeledPolynomial{label, polynomial, degree_bound, ..} = *polynomials.into_iter().next().unwrap(); @@ -352,7 +356,7 @@ where let rho_inv = 2; // self.rho_inv let fft_domain = GeneralEvaluationDomain::::new(m).unwrap(); - let domain_iter = fft_domain.elements(); + let mut domain_iter = fft_domain.elements(); let ext_mat = Matrix::new_from_rows( mat.rows().iter().map(|r| reed_solomon( @@ -364,16 +368,16 @@ where ); // 3. Create the Merkle tree from the hashes of the columns - let col_hashes = Vec::new(); + let mut col_hashes = Vec::new(); let ext_mat_cols = ext_mat.cols(); for col in ext_mat_cols { col_hashes.push(hash_array(&col)); } - let col_tree = MerkleTree::new::( - &ck.leaf_crh_params, - &ck.two_to_one_params, + let col_tree = MerkleTree::::new( + &leaf_hash_param, + &two_to_one_param, col_hashes, ).unwrap(); @@ -382,26 +386,26 @@ where // 4. Add root to transcript and generate random linear combination with it let mut transcript: IOPTranscript = IOPTranscript::new(b"well_formedness_transcript"); transcript - .append_serializable_element(b"root", root) + .append_serializable_element(b"root", &root) .unwrap(); // 5. Generate linear combination using the matrix and random coefficients let mut r = Vec::new(); - for _ in 0..ck.t { + for _ in 0..m { r.push(transcript.get_and_append_challenge(b"r").unwrap()); } - let v = mat.row_mul(r); + let v = mat.row_mul(&r); transcript - .append_serializable_element(b"v", v) + .append_serializable_element(b"v", &v) .unwrap(); // 6. Generate t column indices to test the linear combination on let num_encoded_rows = m * rho_inv; let bytes_to_squeeze = get_num_bytes(num_encoded_rows); - let mut indices = Vec::with_capacity(ck.t); - for _ in 0..ck.t { + let mut indices = Vec::with_capacity(t); + for _ in 0..t { let mut bytes: Vec = vec![0; bytes_to_squeeze]; let _ = transcript .get_and_append_byte_challenge(b"i", &mut bytes) @@ -414,12 +418,12 @@ where } // 7. Compute Merkle tree paths for the columns - let queried_columns = Vec::new(); - let paths = Vec::new(); + let mut queried_columns = Vec::new(); + let mut paths = Vec::new(); for i in indices { queried_columns.push(ext_mat_cols[i]); - paths.push(col_tree.generate_proof(i)); + paths.push(col_tree.generate_proof(i).unwrap()); } let proof: Proof = Proof { @@ -428,13 +432,13 @@ where columns: queried_columns, }; - let commitment = LigeroPCCommitment::new( + let commitment = LigeroPCCommitment { m, root, proof, - ); + }; - Ok(LabeledCommitment::new(label, commitment, degree_bound)); + Ok((vec![LabeledCommitment::new(label, commitment, degree_bound)], Vec::new())) // TODO when should this return Err? } @@ -470,12 +474,12 @@ where let mut rng = rng.unwrap(); let labeled_commitment = commitments.into_iter().next().unwrap(); // check if we've seen this commitment before. If not, we should verify it. - let leaf_hash_params = C::LeafHash::setup(&mut rng).unwrap(); - let two_to_one_params = C::TwoToOneHash::setup(&mut rng).unwrap(); + let leaf_hash_param = C::LeafHash::setup(&mut rng).unwrap(); + let two_to_one_param = C::TwoToOneHash::setup(&mut rng).unwrap(); Self::well_formedness_check( labeled_commitment.commitment(), - &leaf_hash_params, - &two_to_one_params, + &leaf_hash_param, + &two_to_one_param, ); todo!() } diff --git a/src/ligero/tests.rs b/src/ligero/tests.rs index ab994a6e..1efd498d 100644 --- a/src/ligero/tests.rs +++ b/src/ligero/tests.rs @@ -104,6 +104,6 @@ mod tests { /* #[test] fn test_well_formedness { - + Ligero } */ } \ No newline at end of file diff --git a/src/ligero/utils.rs b/src/ligero/utils.rs index 438066d0..0e4dca45 100644 --- a/src/ligero/utils.rs +++ b/src/ligero/utils.rs @@ -143,17 +143,6 @@ pub(crate) fn reed_solomon( encoding } -/* DummyCK { - t: int; -} - -impl DummyCK { - fn new() -> Self { - println!("WARNING: You are using dummy parameters"), - - } -} - */ #[inline] pub(crate) fn inner_product(v1: &[F], v2: &[F]) -> F { ark_std::cfg_iter!(v1) @@ -192,4 +181,4 @@ pub(crate) fn hash_array(array: & dig.update(to_bytes!(elem).unwrap()); } dig.finalize().to_vec() -} +} \ No newline at end of file From 092a22a21b5d18b6c31063eed19f95cf93bdbc08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mej=C3=ADas=20Gil?= Date: Thu, 29 Jun 2023 22:28:49 +0200 Subject: [PATCH 031/108] commit function compiling --- src/ligero/mod.rs | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index c2eac563..a656c45d 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -9,10 +9,12 @@ use ark_ff::BigInteger256; use ark_ff::PrimeField; use ark_poly::{DenseUVPolynomial, EvaluationDomain, GeneralEvaluationDomain}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; +use core::ops::Deref; use core::{borrow::Borrow, marker::PhantomData}; use digest::Digest; use jf_primitives::pcs::transcript::IOPTranscript; +use crate::PolynomialLabel; use crate::{ ligero::utils::{get_num_bytes, inner_product, reed_solomon}, Error, LabeledCommitment, LabeledPolynomial, PCCommitment, PCCommitterKey, @@ -128,10 +130,10 @@ where } // 4. Verify the paths for each of the leaf hashes - for (leaf, i) in col_hashes.into_iter().zip(indices.into_iter()) { + for (leaf, i) in col_hashes.into_iter().zip(indices.iter()) { // TODO handle the error here - let path = &commitment.proof.paths[i]; - assert!(path.leaf_index == i, "Path is for a different index!"); + let path = &commitment.proof.paths[*i]; + assert!(path.leaf_index == *i, "Path is for a different index!"); path.verify(leaf_hash_param, two_to_one_param, &commitment.root, leaf) .unwrap(); @@ -333,7 +335,11 @@ where let two_to_one_param = C::TwoToOneHash::setup(&mut optional).unwrap(); // TODO loop over all polynomials - let LabeledPolynomial{label, polynomial, degree_bound, ..} = *polynomials.into_iter().next().unwrap(); + + // TODO decide what to do with label and degree bound (these are private! but the commitment also has them) + let labeled_polynomial = polynomials.into_iter().next().unwrap(); + + let polynomial = labeled_polynomial.polynomial(); let mut coeffs = polynomial.coeffs().to_vec(); @@ -352,9 +358,7 @@ where let mat = Matrix::new_from_flat( m, m, &coeffs); - // 2. Apply Reed-Solomon encoding row-wise - let rho_inv = 2; // self.rho_inv - + // 2. Apply Reed-Solomon encoding row-wise let fft_domain = GeneralEvaluationDomain::::new(m).unwrap(); let mut domain_iter = fft_domain.elements(); @@ -371,8 +375,8 @@ where let mut col_hashes = Vec::new(); let ext_mat_cols = ext_mat.cols(); - for col in ext_mat_cols { - col_hashes.push(hash_array(&col)); + for col in ext_mat_cols.iter() { + col_hashes.push(C::Leaf::from(hash_array::(col))); } let col_tree = MerkleTree::::new( @@ -422,7 +426,7 @@ where let mut paths = Vec::new(); for i in indices { - queried_columns.push(ext_mat_cols[i]); + queried_columns.push(ext_mat_cols[i].clone()); paths.push(col_tree.generate_proof(i).unwrap()); } @@ -438,7 +442,11 @@ where proof, }; - Ok((vec![LabeledCommitment::new(label, commitment, degree_bound)], Vec::new())) + Ok((vec![LabeledCommitment::new( + labeled_polynomial.label().clone(), + commitment, + None, // TODO think about this (degree_bound) + )], Vec::new())) // TODO when should this return Err? } From 64ff2d32105efeb768697d12b8faeb0b7d4c97fc Mon Sep 17 00:00:00 2001 From: mmagician Date: Fri, 30 Jun 2023 09:19:54 +0200 Subject: [PATCH 032/108] (self) PR review --- src/ligero/mod.rs | 89 +++++++++++++++++---------------------------- src/ligero/utils.rs | 27 ++++++++++++-- 2 files changed, 58 insertions(+), 58 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index a656c45d..a64621db 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -1,7 +1,7 @@ use ark_crypto_primitives::crh::CRHScheme; use ark_crypto_primitives::crh::TwoToOneCRHScheme; use ark_crypto_primitives::{ - merkle_tree::{Config, LeafParam, Path, TwoToOneParam, MerkleTree}, + merkle_tree::{Config, LeafParam, MerkleTree, Path, TwoToOneParam}, sponge::{Absorb, CryptographicSponge}, }; use ark_ff::BigInt; @@ -27,6 +27,7 @@ use ark_std::rand::RngCore; mod utils; use utils::Matrix; +use self::utils::get_indices_from_transcript; use self::utils::hash_array; mod tests; @@ -115,19 +116,8 @@ where // we want to squeeze enough bytes to get the indices in the range [0, rho_inv * m) // 3. Compute t column indices to check the linear combination at let num_encoded_rows = commitment.m * rho_inv; - let bytes_to_squeeze = get_num_bytes(num_encoded_rows); - let mut indices = Vec::with_capacity(t); - for _ in 0..t { - let mut bytes: Vec = vec![0; bytes_to_squeeze]; - let _ = transcript - .get_and_append_byte_challenge(b"i", &mut bytes) - .unwrap(); - // get the usize from Vec: - let ind = bytes.iter().fold(0, |acc, &x| (acc << 8) + x as usize); - // modulo the number of columns in the encoded matrix - indices.push(ind % num_encoded_rows); - } + let indices = get_indices_from_transcript::(num_encoded_rows, t, &mut transcript); // 4. Verify the paths for each of the leaf hashes for (leaf, i) in col_hashes.into_iter().zip(indices.iter()) { @@ -142,18 +132,11 @@ where // 5. Compute the encoding of v, s.t. E(v) = w let fft_domain = GeneralEvaluationDomain::::new(commitment.m).unwrap(); let mut domain_iter = fft_domain.elements(); - let w = reed_solomon( - &commitment.proof.v, - rho_inv, - fft_domain, - &mut domain_iter, - ); - + let w = reed_solomon(&commitment.proof.v, rho_inv, fft_domain, &mut domain_iter); + // 6. Verify the random linear combinations for (transcript_index, matrix_index) in indices.into_iter().enumerate() { - if inner_product(&r, &commitment.proof.columns[transcript_index]) - != w[matrix_index] - { + if inner_product(&r, &commitment.proof.columns[transcript_index]) != w[matrix_index] { // TODO return proper error return Err(Error::IncorrectInputLength( "Incorrect linear combination".to_string(), @@ -333,9 +316,9 @@ where let mut optional = crate::optional_rng::OptionalRng(rng); // TODO taken from Marlin code; change in the future? let leaf_hash_param = C::LeafHash::setup(&mut optional).unwrap(); let two_to_one_param = C::TwoToOneHash::setup(&mut optional).unwrap(); - + // TODO loop over all polynomials - + // TODO decide what to do with label and degree bound (these are private! but the commitment also has them) let labeled_polynomial = polynomials.into_iter().next().unwrap(); @@ -348,7 +331,11 @@ where let num_elems = polynomial.degree() + 1; // TODO move this check to the constructor? - assert_eq!((num_elems as f64) as usize, num_elems, "Degree of polynomial + 1 cannot be converted to f64: aborting"); + assert_eq!( + (num_elems as f64) as usize, + num_elems, + "Degree of polynomial + 1 cannot be converted to f64: aborting" + ); let m = (num_elems as f64).sqrt().ceil() as usize; // TODO: check if fft_domain.compute_size_of_domain(m) is large enough @@ -356,34 +343,29 @@ where // TODO is this the most efficient/safest way to do it? coeffs.resize(m * m, F::zero()); - let mat = Matrix::new_from_flat( m, m, &coeffs); + let mat = Matrix::new_from_flat(m, m, &coeffs); - // 2. Apply Reed-Solomon encoding row-wise + // 2. Apply Reed-Solomon encoding row-wise let fft_domain = GeneralEvaluationDomain::::new(m).unwrap(); let mut domain_iter = fft_domain.elements(); let ext_mat = Matrix::new_from_rows( - mat.rows().iter().map(|r| reed_solomon( - r, - rho_inv, - fft_domain, - &mut domain_iter - )).collect() + mat.rows() + .iter() + .map(|r| reed_solomon(r, rho_inv, fft_domain, &mut domain_iter)) + .collect(), ); // 3. Create the Merkle tree from the hashes of the columns - let mut col_hashes = Vec::new(); + let mut col_hashes: Vec = Vec::new(); let ext_mat_cols = ext_mat.cols(); for col in ext_mat_cols.iter() { - col_hashes.push(C::Leaf::from(hash_array::(col))); + col_hashes.push(hash_array::(col).into()); } - let col_tree = MerkleTree::::new( - &leaf_hash_param, - &two_to_one_param, - col_hashes, - ).unwrap(); + let col_tree = + MerkleTree::::new(&leaf_hash_param, &two_to_one_param, col_hashes).unwrap(); let root = col_tree.root(); @@ -398,12 +380,10 @@ where for _ in 0..m { r.push(transcript.get_and_append_challenge(b"r").unwrap()); } - + let v = mat.row_mul(&r); - transcript - .append_serializable_element(b"v", &v) - .unwrap(); + transcript.append_serializable_element(b"v", &v).unwrap(); // 6. Generate t column indices to test the linear combination on let num_encoded_rows = m * rho_inv; @@ -436,17 +416,16 @@ where columns: queried_columns, }; - let commitment = LigeroPCCommitment { - m, - root, - proof, - }; + let commitment = LigeroPCCommitment { m, root, proof }; - Ok((vec![LabeledCommitment::new( - labeled_polynomial.label().clone(), - commitment, - None, // TODO think about this (degree_bound) - )], Vec::new())) + Ok(( + vec![LabeledCommitment::new( + labeled_polynomial.label().clone(), + commitment, + None, // TODO think about this (degree_bound) + )], + Vec::new(), + )) // TODO when should this return Err? } diff --git a/src/ligero/utils.rs b/src/ligero/utils.rs index 0e4dca45..94535257 100644 --- a/src/ligero/utils.rs +++ b/src/ligero/utils.rs @@ -6,6 +6,7 @@ use ark_poly::{ }; use ark_serialize::CanonicalSerialize; use digest::Digest; +use jf_primitives::pcs::transcript::IOPTranscript; use rayon::{ iter::{IntoParallelRefIterator, ParallelIterator}, prelude::IndexedParallelIterator, @@ -175,10 +176,30 @@ macro_rules! to_bytes { #[inline] pub(crate) fn hash_array(array: &[F]) -> Vec { - let mut dig = D::new(); for elem in array { dig.update(to_bytes!(elem).unwrap()); - } + } dig.finalize().to_vec() -} \ No newline at end of file +} + +pub(crate) fn get_indices_from_transcript( + n: usize, + t: usize, + transcript: &mut IOPTranscript, +) -> Vec { + let bytes_to_squeeze = get_num_bytes(n); + let mut indices = Vec::with_capacity(t); + for _ in 0..t { + let mut bytes: Vec = vec![0; bytes_to_squeeze]; + let _ = transcript + .get_and_append_byte_challenge(b"i", &mut bytes) + .unwrap(); + + // get the usize from Vec: + let ind = bytes.iter().fold(0, |acc, &x| (acc << 8) + x as usize); + // modulo the number of columns in the encoded matrix + indices.push(ind % n); + } + indices +} From 958d9ccc507d3b888631f10c59f11fe5fad0ba8b Mon Sep 17 00:00:00 2001 From: mmagician Date: Fri, 30 Jun 2023 09:20:48 +0200 Subject: [PATCH 033/108] bring back lints --- src/lib.rs | 16 ++++++++-------- src/ligero/mod.rs | 24 ++++++++++-------------- 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 20dbdd03..5d7ae548 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,13 +1,13 @@ #![cfg_attr(not(feature = "std"), no_std)] //! A crate for polynomial commitment schemes. -// #![deny(unused_import_braces, unused_qualifications, trivial_casts)] -// #![deny(trivial_numeric_casts, private_in_public, variant_size_differences)] -// #![deny(stable_features, unreachable_pub, non_shorthand_field_patterns)] -// #![deny(unused_attributes, unused_mut)] -// #![deny(missing_docs)] -// #![deny(unused_imports)] -// #![deny(renamed_and_removed_lints, stable_features, unused_allocation)] -// #![deny(unused_comparisons, bare_trait_objects, unused_must_use)] +#![deny(unused_import_braces, unused_qualifications, trivial_casts)] +#![deny(trivial_numeric_casts, private_in_public, variant_size_differences)] +#![deny(stable_features, unreachable_pub, non_shorthand_field_patterns)] +#![deny(unused_attributes, unused_mut)] +#![deny(missing_docs)] +#![deny(unused_imports)] +#![deny(renamed_and_removed_lints, stable_features, unused_allocation)] +#![deny(unused_comparisons, bare_trait_objects, unused_must_use)] #![forbid(unsafe_code)] #[allow(unused)] diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index a64621db..edbee3d5 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -4,22 +4,18 @@ use ark_crypto_primitives::{ merkle_tree::{Config, LeafParam, MerkleTree, Path, TwoToOneParam}, sponge::{Absorb, CryptographicSponge}, }; -use ark_ff::BigInt; -use ark_ff::BigInteger256; use ark_ff::PrimeField; use ark_poly::{DenseUVPolynomial, EvaluationDomain, GeneralEvaluationDomain}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; -use core::ops::Deref; -use core::{borrow::Borrow, marker::PhantomData}; +use core::marker::PhantomData; use digest::Digest; use jf_primitives::pcs::transcript::IOPTranscript; -use crate::PolynomialLabel; +use crate::LabeledPolynomial; use crate::{ ligero::utils::{get_num_bytes, inner_product, reed_solomon}, - Error, LabeledCommitment, LabeledPolynomial, PCCommitment, PCCommitterKey, - PCPreparedCommitment, PCPreparedVerifierKey, PCRandomness, PCUniversalParams, PCVerifierKey, - PolynomialCommitment, + Error, LabeledCommitment, PCCommitment, PCCommitterKey, PCPreparedCommitment, + PCPreparedVerifierKey, PCRandomness, PCUniversalParams, PCVerifierKey, PolynomialCommitment, }; use ark_std::rand::RngCore; @@ -299,11 +295,11 @@ where fn commit<'a>( ck: &Self::CommitterKey, - polynomials: impl IntoIterator>, + polynomials: impl IntoIterator>, rng: Option<&mut dyn RngCore>, ) -> Result< ( - Vec>, + Vec>, Vec, ), Self::Error, @@ -431,8 +427,8 @@ where fn open<'a>( ck: &Self::CommitterKey, - labeled_polynomials: impl IntoIterator>, - commitments: impl IntoIterator>, + labeled_polynomials: impl IntoIterator>, + commitments: impl IntoIterator>, point: &'a P::Point, challenge_generator: &mut crate::challenge::ChallengeGenerator, rands: impl IntoIterator, @@ -448,7 +444,7 @@ where fn check<'a>( vk: &Self::VerifierKey, - commitments: impl IntoIterator>, + commitments: impl IntoIterator>, point: &'a P::Point, values: impl IntoIterator, proof: &Self::Proof, @@ -467,7 +463,7 @@ where labeled_commitment.commitment(), &leaf_hash_param, &two_to_one_param, - ); + ).unwrap(); todo!() } } From f8bed31bfebd812b4e3a7a2b4f8a26bd4829281c Mon Sep 17 00:00:00 2001 From: mmagician Date: Fri, 30 Jun 2023 09:29:59 +0200 Subject: [PATCH 034/108] fmt tests --- src/ligero/tests.rs | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/ligero/tests.rs b/src/ligero/tests.rs index 1efd498d..615b606c 100644 --- a/src/ligero/tests.rs +++ b/src/ligero/tests.rs @@ -1,9 +1,11 @@ - #[cfg(test)] mod tests { use ark_bls12_381::Fq as F; - use ark_poly::{domain::general::GeneralEvaluationDomain, EvaluationDomain, DenseUVPolynomial, univariate::DensePolynomial, Polynomial}; + use ark_poly::{ + domain::general::GeneralEvaluationDomain, univariate::DensePolynomial, DenseUVPolynomial, + EvaluationDomain, Polynomial, + }; use crate::ligero::utils::*; @@ -23,11 +25,11 @@ mod tests { #[test] fn test_matrix_constructor_rows() { - let rows: Vec> = vec!( + let rows: Vec> = vec![ to_field(vec![10, 100, 4]), to_field(vec![23, 1, 0]), to_field(vec![55, 58, 9]), - ); + ]; let mat = Matrix::new_from_rows(rows); assert_eq!(mat.entry(2, 0), F::from(55)); } @@ -35,21 +37,21 @@ mod tests { #[test] #[should_panic] fn test_matrix_constructor_rows_panic() { - let rows: Vec> = vec!( + let rows: Vec> = vec![ to_field(vec![10, 100, 4]), to_field(vec![23, 1, 0]), to_field(vec![55, 58]), - ); + ]; Matrix::new_from_rows(rows); } #[test] fn test_cols() { - let rows: Vec> = vec!( + let rows: Vec> = vec![ to_field(vec![4, 76]), - to_field(vec![14, 92,]), + to_field(vec![14, 92]), to_field(vec![17, 89]), - ); + ]; let mat = Matrix::new_from_rows(rows); @@ -58,11 +60,11 @@ mod tests { #[test] fn test_row_mul() { - let rows: Vec> = vec!( + let rows: Vec> = vec![ to_field(vec![10, 100, 4]), to_field(vec![23, 1, 0]), to_field(vec![55, 58, 9]), - ); + ]; let mat = Matrix::new_from_rows(rows); let v: Vec = to_field(vec![12, 41, 55]); @@ -73,11 +75,10 @@ mod tests { #[test] fn test_fft_interface() { - // we use this polynomial to generate the the values we will ask the fft to interpolate let pol_coeffs: Vec = to_field(vec![30, 2, 91]); let pol: DensePolynomial = DensePolynomial::from_coefficients_slice(&pol_coeffs); - + let fft_domain = GeneralEvaluationDomain::::new(pol_coeffs.len()).unwrap(); // generating the values @@ -102,8 +103,8 @@ mod tests { assert_eq!(get_num_bytes(1 << 32 + 1), 5); } -/* #[test] + /* #[test] fn test_well_formedness { Ligero } */ -} \ No newline at end of file +} From 1b00e2525b792e32e03aef66f882e7aa6f7a85bb Mon Sep 17 00:00:00 2001 From: mmagician Date: Fri, 30 Jun 2023 11:01:54 +0200 Subject: [PATCH 035/108] use the utils function for getting the indices, since its shared by both --- src/ligero/mod.rs | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index edbee3d5..6e186131 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -383,19 +383,7 @@ where // 6. Generate t column indices to test the linear combination on let num_encoded_rows = m * rho_inv; - let bytes_to_squeeze = get_num_bytes(num_encoded_rows); - let mut indices = Vec::with_capacity(t); - for _ in 0..t { - let mut bytes: Vec = vec![0; bytes_to_squeeze]; - let _ = transcript - .get_and_append_byte_challenge(b"i", &mut bytes) - .unwrap(); - - // get the usize from Vec: - let ind = bytes.iter().fold(0, |acc, &x| (acc << 8) + x as usize); - // modulo the number of columns in the encoded matrix - indices.push(ind % num_encoded_rows); - } + let indices = get_indices_from_transcript::(num_encoded_rows, t, &mut transcript); // 7. Compute Merkle tree paths for the columns let mut queried_columns = Vec::new(); From a2addcc5545e482802ab1dd3fd7ccdf375601758 Mon Sep 17 00:00:00 2001 From: mmagician Date: Fri, 30 Jun 2023 11:03:24 +0200 Subject: [PATCH 036/108] write first construction tests for LigeroPCS --- src/ligero/mod.rs | 54 +++++++++++++++++++++++++++++---------------- src/ligero/tests.rs | 50 ++++++++++++++++++++++++++++++++++++----- 2 files changed, 80 insertions(+), 24 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 6e186131..6d3f7ef5 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -1,5 +1,6 @@ use ark_crypto_primitives::crh::CRHScheme; use ark_crypto_primitives::crh::TwoToOneCRHScheme; +use ark_crypto_primitives::to_uncompressed_bytes; use ark_crypto_primitives::{ merkle_tree::{Config, LeafParam, MerkleTree, Path, TwoToOneParam}, sponge::{Absorb, CryptographicSponge}, @@ -10,6 +11,7 @@ use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use core::marker::PhantomData; use digest::Digest; use jf_primitives::pcs::transcript::IOPTranscript; +use std::borrow::Borrow; use crate::LabeledPolynomial; use crate::{ @@ -34,6 +36,7 @@ pub struct Ligero< C: Config, D: Digest, S: CryptographicSponge, + P: DenseUVPolynomial, /// one over the rate rho const rho_inv: usize, /// security parameter, used in calculating t @@ -43,6 +46,7 @@ pub struct Ligero< _config: PhantomData, _digest: PhantomData, _sponge: PhantomData, + _poly: PhantomData

, } // TODO come up with reasonable defaults @@ -56,15 +60,17 @@ fn calculate_t(rho_inv: usize, sec_param: usize) -> usize { t } -impl - Ligero +impl + Ligero where F: PrimeField, C: Config, - C::Leaf: Sized + From>, + Vec: Borrow, + // C::Leaf: Sized + From>, C::InnerDigest: Absorb, D: Digest, S: CryptographicSponge, + P: DenseUVPolynomial, { /// Create a new instance of Ligero. /// If either or both parameters are None, their default values are used. @@ -75,6 +81,7 @@ where // TODO potentially can get rid of digest and sponge _digest: PhantomData, _sponge: PhantomData, + _poly: PhantomData, } } @@ -87,11 +94,12 @@ where let t = calculate_t(rho_inv, sec_param); // 1. Hash the received columns, to get the leaf hashes - let mut col_hashes: Vec = Vec::new(); - for c in commitment.proof.columns.iter() { - col_hashes.push(hash_array::(c).into()); - // TODO some hashing, with the digest? - } + let col_hashes: Vec<_> = commitment + .proof + .columns + .iter() + .map(|col| hash_array::(col)) + .collect(); // TODO replace unwraps by proper error handling let mut transcript: IOPTranscript = IOPTranscript::new(b"well_formedness_transcript"); @@ -116,13 +124,18 @@ where let indices = get_indices_from_transcript::(num_encoded_rows, t, &mut transcript); // 4. Verify the paths for each of the leaf hashes - for (leaf, i) in col_hashes.into_iter().zip(indices.iter()) { + for (leaf, i) in col_hashes.iter().zip(indices.iter()) { // TODO handle the error here let path = &commitment.proof.paths[*i]; assert!(path.leaf_index == *i, "Path is for a different index!"); - path.verify(leaf_hash_param, two_to_one_param, &commitment.root, leaf) - .unwrap(); + path.verify( + leaf_hash_param, + two_to_one_param, + &commitment.root, + leaf.clone(), + ) + .unwrap(); } // 5. Compute the encoding of v, s.t. E(v) = w @@ -246,13 +259,15 @@ impl PCRandomness for LigeroPCRandomness { type LigeroPCProof = (); impl PolynomialCommitment - for Ligero + for Ligero where F: PrimeField, P: DenseUVPolynomial, S: CryptographicSponge, C: Config + 'static, - C::Leaf: Sized + From>, + // &[u8]: Borrow<::Leaf>, + Vec: Borrow, + // C::Leaf: Sized + From>, C::InnerDigest: Absorb, D: Digest, { @@ -281,7 +296,7 @@ where num_vars: Option, rng: &mut R, ) -> Result { - todo!() + Ok(LigeroPCUniversalParams::default()) } fn trim( @@ -353,12 +368,12 @@ where ); // 3. Create the Merkle tree from the hashes of the columns - let mut col_hashes: Vec = Vec::new(); let ext_mat_cols = ext_mat.cols(); - for col in ext_mat_cols.iter() { - col_hashes.push(hash_array::(col).into()); - } + let col_hashes: Vec<_> = ext_mat_cols + .iter() + .map(|col| hash_array::(col)) + .collect(); let col_tree = MerkleTree::::new(&leaf_hash_param, &two_to_one_param, col_hashes).unwrap(); @@ -451,7 +466,8 @@ where labeled_commitment.commitment(), &leaf_hash_param, &two_to_one_param, - ).unwrap(); + ) + .unwrap(); todo!() } } diff --git a/src/ligero/tests.rs b/src/ligero/tests.rs index 615b606c..2eac1a2f 100644 --- a/src/ligero/tests.rs +++ b/src/ligero/tests.rs @@ -6,8 +6,45 @@ mod tests { domain::general::GeneralEvaluationDomain, univariate::DensePolynomial, DenseUVPolynomial, EvaluationDomain, Polynomial, }; + use ark_std::test_rng; + use blake2::Blake2s256; + + use crate::ligero::{utils::*, Ligero, PolynomialCommitment}; + use ark_crypto_primitives::{ + crh::{pedersen, sha256::Sha256, CRHScheme, TwoToOneCRHScheme}, + merkle_tree::{ByteDigestConverter, Config, LeafParam, Path, TwoToOneParam}, + sponge::{poseidon::PoseidonSponge, Absorb, CryptographicSponge}, + }; + + type UniPoly = DensePolynomial; + #[derive(Clone)] + pub(super) struct Window4x256; + impl pedersen::Window for Window4x256 { + const WINDOW_SIZE: usize = 4; + const NUM_WINDOWS: usize = 256; + } + + type LeafH = Sha256; //::CRH; + type CompressH = Sha256; //pedersen::TwoToOneCRH; + + struct MerkleTreeParams; + + impl Config for MerkleTreeParams { + type Leaf = [u8]; + // type Leaf = Vec; - use crate::ligero::utils::*; + type LeafDigest = ::Output; + type LeafInnerDigestConverter = ByteDigestConverter; + type InnerDigest = ::Output; + + type LeafHash = LeafH; + type TwoToOneHash = CompressH; + } + + type MTConfig = MerkleTreeParams; + type Sponge = PoseidonSponge; + type PC = Ligero; + type LigeroPCS = PC; #[test] fn test_matrix_constructor_flat() { @@ -103,8 +140,11 @@ mod tests { assert_eq!(get_num_bytes(1 << 32 + 1), 5); } - /* #[test] - fn test_well_formedness { - Ligero - } */ + #[test] + fn test_construction() { + let rng = &mut test_rng(); + let pp = LigeroPCS::setup(2, None, rng).unwrap(); + // This fails since trim is not implemented + let (ck, vk) = LigeroPCS::trim(&pp, 0, 2, Some(&[0])).unwrap(); + } } From d48145f4cf432eaaf94d8eb6729576d41a1d0782 Mon Sep 17 00:00:00 2001 From: mmagician Date: Fri, 30 Jun 2023 11:03:43 +0200 Subject: [PATCH 037/108] rename hash_array -> hash_column --- src/ligero/mod.rs | 6 +++--- src/ligero/utils.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 6d3f7ef5..ba486386 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -26,7 +26,7 @@ mod utils; use utils::Matrix; use self::utils::get_indices_from_transcript; -use self::utils::hash_array; +use self::utils::hash_column; mod tests; // TODO: Disclaimer: no hiding prop @@ -98,7 +98,7 @@ where .proof .columns .iter() - .map(|col| hash_array::(col)) + .map(|col| hash_column::(col)) .collect(); // TODO replace unwraps by proper error handling @@ -372,7 +372,7 @@ where let col_hashes: Vec<_> = ext_mat_cols .iter() - .map(|col| hash_array::(col)) + .map(|col| hash_column::(col)) .collect(); let col_tree = diff --git a/src/ligero/utils.rs b/src/ligero/utils.rs index 94535257..f35d5a3d 100644 --- a/src/ligero/utils.rs +++ b/src/ligero/utils.rs @@ -175,7 +175,7 @@ macro_rules! to_bytes { } #[inline] -pub(crate) fn hash_array(array: &[F]) -> Vec { +pub(crate) fn hash_column(array: &[F]) -> Vec { let mut dig = D::new(); for elem in array { dig.update(to_bytes!(elem).unwrap()); From dde6fb2d4eaf208852d3784a3343e371a038115e Mon Sep 17 00:00:00 2001 From: mmagician Date: Fri, 30 Jun 2023 11:06:09 +0200 Subject: [PATCH 038/108] remove stale code and unused imports --- src/ligero/mod.rs | 6 +----- src/ligero/tests.rs | 4 ++-- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index ba486386..89872380 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -1,6 +1,5 @@ use ark_crypto_primitives::crh::CRHScheme; use ark_crypto_primitives::crh::TwoToOneCRHScheme; -use ark_crypto_primitives::to_uncompressed_bytes; use ark_crypto_primitives::{ merkle_tree::{Config, LeafParam, MerkleTree, Path, TwoToOneParam}, sponge::{Absorb, CryptographicSponge}, @@ -15,7 +14,7 @@ use std::borrow::Borrow; use crate::LabeledPolynomial; use crate::{ - ligero::utils::{get_num_bytes, inner_product, reed_solomon}, + ligero::utils::{inner_product, reed_solomon}, Error, LabeledCommitment, PCCommitment, PCCommitterKey, PCPreparedCommitment, PCPreparedVerifierKey, PCRandomness, PCUniversalParams, PCVerifierKey, PolynomialCommitment, }; @@ -66,7 +65,6 @@ where F: PrimeField, C: Config, Vec: Borrow, - // C::Leaf: Sized + From>, C::InnerDigest: Absorb, D: Digest, S: CryptographicSponge, @@ -265,9 +263,7 @@ where P: DenseUVPolynomial, S: CryptographicSponge, C: Config + 'static, - // &[u8]: Borrow<::Leaf>, Vec: Borrow, - // C::Leaf: Sized + From>, C::InnerDigest: Absorb, D: Digest, { diff --git a/src/ligero/tests.rs b/src/ligero/tests.rs index 2eac1a2f..7b4bda48 100644 --- a/src/ligero/tests.rs +++ b/src/ligero/tests.rs @@ -12,8 +12,8 @@ mod tests { use crate::ligero::{utils::*, Ligero, PolynomialCommitment}; use ark_crypto_primitives::{ crh::{pedersen, sha256::Sha256, CRHScheme, TwoToOneCRHScheme}, - merkle_tree::{ByteDigestConverter, Config, LeafParam, Path, TwoToOneParam}, - sponge::{poseidon::PoseidonSponge, Absorb, CryptographicSponge}, + merkle_tree::{ByteDigestConverter, Config}, + sponge::poseidon::PoseidonSponge, }; type UniPoly = DensePolynomial; From 7e0b9b2c9bf23459e4499e16e56de3d4f871870e Mon Sep 17 00:00:00 2001 From: mmagician Date: Fri, 30 Jun 2023 12:14:09 +0200 Subject: [PATCH 039/108] Place params under VerifierKey replace local path with HungryCatsStudio fork of crypto-primitives --- Cargo.toml | 2 +- src/ligero/mod.rs | 36 +++++++++++++++++++++++++----------- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 56557b0b..47255b43 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ ark-serialize = { version = "^0.4.0", default-features = false, features = [ "de ark-ff = { version = "^0.4.0", default-features = false } ark-ec = { version = "^0.4.0", default-features = false } ark-poly = {version = "^0.4.0", default-features = false } -ark-crypto-primitives = {version = "^0.4.0", default-features = false, features = ["sponge","merkle_tree" ] } +ark-crypto-primitives = { version = "^0.4.0", default-features = false, features = ["sponge","merkle_tree" ], git = "https://github.com/HungryCatsStudio/crypto-primitives.git", branch = "trait-bounds-for-crh" } ark-std = { version = "^0.4.0", default-features = false } ark-relations = { version = "^0.4.0", default-features = false, optional = true } diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 89872380..477d42c1 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -1,5 +1,4 @@ -use ark_crypto_primitives::crh::CRHScheme; -use ark_crypto_primitives::crh::TwoToOneCRHScheme; +use ark_crypto_primitives::crh::{CRHScheme, TwoToOneCRHScheme}; use ark_crypto_primitives::{ merkle_tree::{Config, LeafParam, MerkleTree, Path, TwoToOneParam}, sponge::{Absorb, CryptographicSponge}, @@ -7,6 +6,7 @@ use ark_crypto_primitives::{ use ark_ff::PrimeField; use ark_poly::{DenseUVPolynomial, EvaluationDomain, GeneralEvaluationDomain}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; +use ark_std::fmt::Debug; use core::marker::PhantomData; use digest::Digest; use jf_primitives::pcs::transcript::IOPTranscript; @@ -173,10 +173,25 @@ impl PCCommitterKey for LigeroPCCommitterKey { todo!() } } +/// The verifier key which holds some scheme parameters +#[derive(Derivative, CanonicalSerialize, CanonicalDeserialize)] +#[derivative(Clone(bound = ""), Debug(bound = ""))] +pub struct LigeroPCVerifierKey +where + C: Config, + <::TwoToOneHash as TwoToOneCRHScheme>::Parameters: Debug, + <::LeafHash as CRHScheme>::Parameters: Debug, +{ + leaf_hash_params: LeafParam, + two_to_one_params: TwoToOneParam, +} -type LigeroPCVerifierKey = (); - -impl PCVerifierKey for LigeroPCVerifierKey { +impl PCVerifierKey for LigeroPCVerifierKey +where + C: Config, + <::TwoToOneHash as TwoToOneCRHScheme>::Parameters: Debug, + <::LeafHash as CRHScheme>::Parameters: Debug, +{ fn max_degree(&self) -> usize { todo!() } @@ -264,6 +279,8 @@ where S: CryptographicSponge, C: Config + 'static, Vec: Borrow, + <::TwoToOneHash as TwoToOneCRHScheme>::Parameters: Debug, + <::LeafHash as CRHScheme>::Parameters: Debug, C::InnerDigest: Absorb, D: Digest, { @@ -271,7 +288,7 @@ where type CommitterKey = LigeroPCCommitterKey; - type VerifierKey = LigeroPCVerifierKey; + type VerifierKey = LigeroPCVerifierKey; type PreparedVerifierKey = LigeroPCPreparedVerifierKey; @@ -453,15 +470,12 @@ where where Self::Commitment: 'a, { - let mut rng = rng.unwrap(); let labeled_commitment = commitments.into_iter().next().unwrap(); // check if we've seen this commitment before. If not, we should verify it. - let leaf_hash_param = C::LeafHash::setup(&mut rng).unwrap(); - let two_to_one_param = C::TwoToOneHash::setup(&mut rng).unwrap(); Self::well_formedness_check( labeled_commitment.commitment(), - &leaf_hash_param, - &two_to_one_param, + &vk.leaf_hash_params, + &vk.two_to_one_params, ) .unwrap(); todo!() From 48e55986628ed5b0b20e86fc38efa2f042865310 Mon Sep 17 00:00:00 2001 From: mmagician Date: Fri, 30 Jun 2023 12:07:21 +0200 Subject: [PATCH 040/108] Place params under CommitterKey --- src/ligero/mod.rs | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 477d42c1..f8021897 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -162,9 +162,26 @@ impl PCUniversalParams for LigeroPCUniversalParams { } } -type LigeroPCCommitterKey = (); +#[derive(Derivative, CanonicalSerialize, CanonicalDeserialize)] +#[derivative(Clone(bound = ""), Debug(bound = ""))] +pub struct LigeroPCCommitterKey +where + C: Config, + <::TwoToOneHash as TwoToOneCRHScheme>::Parameters: Debug, + <::LeafHash as CRHScheme>::Parameters: Debug, +{ + #[derivative(Debug = "ignore")] + leaf_hash_params: LeafParam, + #[derivative(Debug = "ignore")] + two_to_one_params: TwoToOneParam, +} -impl PCCommitterKey for LigeroPCCommitterKey { +impl PCCommitterKey for LigeroPCCommitterKey +where + C: Config, + <::TwoToOneHash as TwoToOneCRHScheme>::Parameters: Debug, + <::LeafHash as CRHScheme>::Parameters: Debug, +{ fn max_degree(&self) -> usize { todo!() } @@ -286,7 +303,7 @@ where { type UniversalParams = LigeroPCUniversalParams; - type CommitterKey = LigeroPCCommitterKey; + type CommitterKey = LigeroPCCommitterKey; type VerifierKey = LigeroPCVerifierKey; @@ -337,9 +354,6 @@ where { // 0. Recovering parameters let t = calculate_t(rho_inv, sec_param); - let mut optional = crate::optional_rng::OptionalRng(rng); // TODO taken from Marlin code; change in the future? - let leaf_hash_param = C::LeafHash::setup(&mut optional).unwrap(); - let two_to_one_param = C::TwoToOneHash::setup(&mut optional).unwrap(); // TODO loop over all polynomials @@ -389,7 +403,7 @@ where .collect(); let col_tree = - MerkleTree::::new(&leaf_hash_param, &two_to_one_param, col_hashes).unwrap(); + MerkleTree::::new(&ck.leaf_hash_params, &ck.two_to_one_params, col_hashes).unwrap(); let root = col_tree.root(); From 2108414f185aec5d0b489fa94f273e0948faafbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mej=C3=ADas=20Gil?= Date: Fri, 30 Jun 2023 13:19:52 +0200 Subject: [PATCH 041/108] check and check_well_formedness finished and refactored --- src/ligero/mod.rs | 217 +++++++++++++++++++++++++++++++++----------- src/ligero/utils.rs | 1 + 2 files changed, 166 insertions(+), 52 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index edbee3d5..42669633 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -13,7 +13,7 @@ use jf_primitives::pcs::transcript::IOPTranscript; use crate::LabeledPolynomial; use crate::{ - ligero::utils::{get_num_bytes, inner_product, reed_solomon}, + ligero::utils::{inner_product, reed_solomon}, Error, LabeledCommitment, PCCommitment, PCCommitterKey, PCPreparedCommitment, PCPreparedVerifierKey, PCRandomness, PCUniversalParams, PCVerifierKey, PolynomialCommitment, }; @@ -79,20 +79,13 @@ where } /// The verifier can check the well-formedness of the commitment by taking random linear combinations. - fn well_formedness_check( + fn check_well_formedness( commitment: &LigeroPCCommitment, leaf_hash_param: &LeafParam, two_to_one_param: &TwoToOneParam, ) -> Result<(), Error> { let t = calculate_t(rho_inv, sec_param); - // 1. Hash the received columns, to get the leaf hashes - let mut col_hashes: Vec = Vec::new(); - for c in commitment.proof.columns.iter() { - col_hashes.push(hash_array::(c).into()); - // TODO some hashing, with the digest? - } - // TODO replace unwraps by proper error handling let mut transcript: IOPTranscript = IOPTranscript::new(b"well_formedness_transcript"); transcript @@ -109,37 +102,61 @@ where .append_serializable_element(b"v", &commitment.proof.v) .unwrap(); - // we want to squeeze enough bytes to get the indices in the range [0, rho_inv * m) - // 3. Compute t column indices to check the linear combination at + Self::check_random_linear_combination( + &r, + commitment, + t, + &mut transcript, + leaf_hash_param, + two_to_one_param + ) + } + fn check_random_linear_combination( + coeffs: &[F], + commitment: &LigeroPCCommitment, + t: usize, + transcript: &mut IOPTranscript, + leaf_hash_param: &<::LeafHash as CRHScheme>::Parameters, + two_to_one_param: &<::TwoToOneHash as TwoToOneCRHScheme>::Parameters + ) -> Result<(), Error> + { + // 1. Hash the received columns into leaf hashes + let mut col_hashes: Vec = Vec::new(); + for c in commitment.proof.columns.iter() { + col_hashes.push(hash_array::(c).into()); + } + + // 2. Compute t column indices to check the linear combination at let num_encoded_rows = commitment.m * rho_inv; + let indices = get_indices_from_transcript::(num_encoded_rows, t, transcript); - let indices = get_indices_from_transcript::(num_encoded_rows, t, &mut transcript); - - // 4. Verify the paths for each of the leaf hashes + // 3. Verify the paths for each of the leaf hashes for (leaf, i) in col_hashes.into_iter().zip(indices.iter()) { // TODO handle the error here let path = &commitment.proof.paths[*i]; - assert!(path.leaf_index == *i, "Path is for a different index!"); + assert!(path.leaf_index == *i, "Path is for a different index!"); // TODO return an error path.verify(leaf_hash_param, two_to_one_param, &commitment.root, leaf) .unwrap(); } - // 5. Compute the encoding of v, s.t. E(v) = w + // 4. Compute the encoding w = E(v) let fft_domain = GeneralEvaluationDomain::::new(commitment.m).unwrap(); let mut domain_iter = fft_domain.elements(); let w = reed_solomon(&commitment.proof.v, rho_inv, fft_domain, &mut domain_iter); - // 6. Verify the random linear combinations + // 5. Verify the random linear combinations for (transcript_index, matrix_index) in indices.into_iter().enumerate() { - if inner_product(&r, &commitment.proof.columns[transcript_index]) != w[matrix_index] { + if inner_product(coeffs, &commitment.proof.columns[transcript_index]) != w[matrix_index] { // TODO return proper error return Err(Error::IncorrectInputLength( "Incorrect linear combination".to_string(), )); } } + Ok(()) + } } @@ -183,19 +200,6 @@ impl PCPreparedVerifierKey for LigeroPCPr } } -#[derive(Derivative, CanonicalSerialize, CanonicalDeserialize)] -#[derivative(Default(bound = ""), Clone(bound = ""), Debug(bound = ""))] - -struct Proof { - /// For each of the indices in q, `paths` contains the path from the root of the merkle tree to the leaf - paths: Vec>, - - /// v, s.t. E(v) = w - v: Vec, - - columns: Vec>, -} - /// The commitment to a polynomial is a root of the merkle tree, /// where each node is a hash of the column of the encoded coefficient matrix U. #[derive(Derivative, CanonicalSerialize, CanonicalDeserialize)] @@ -205,7 +209,7 @@ pub struct LigeroPCCommitment { m: usize, // TODO is InnerDigest the right type? root: C::InnerDigest, - proof: Proof, + proof: LigeroPCProof, } impl PCCommitment for LigeroPCCommitment { @@ -243,7 +247,22 @@ impl PCRandomness for LigeroPCRandomness { } } -type LigeroPCProof = (); +/// Ligero proof +#[derive(Derivative, CanonicalSerialize, CanonicalDeserialize)] +#[derivative(Default(bound = ""), Clone(bound = ""), Debug(bound = ""))] +pub struct LigeroPCProof +where + F: PrimeField, + C: Config +{ + /// For each of the indices in q, `paths` contains the path from the root of the merkle tree to the leaf + paths: Vec>, + + /// v, s.t. E(v) = w + v: Vec, + + columns: Vec>, +} impl PolynomialCommitment for Ligero @@ -270,7 +289,7 @@ where type Randomness = LigeroPCRandomness; - type Proof = LigeroPCProof; + type Proof = LigeroPCProof; type BatchProof = Vec; @@ -382,20 +401,7 @@ where transcript.append_serializable_element(b"v", &v).unwrap(); // 6. Generate t column indices to test the linear combination on - let num_encoded_rows = m * rho_inv; - let bytes_to_squeeze = get_num_bytes(num_encoded_rows); - let mut indices = Vec::with_capacity(t); - for _ in 0..t { - let mut bytes: Vec = vec![0; bytes_to_squeeze]; - let _ = transcript - .get_and_append_byte_challenge(b"i", &mut bytes) - .unwrap(); - - // get the usize from Vec: - let ind = bytes.iter().fold(0, |acc, &x| (acc << 8) + x as usize); - // modulo the number of columns in the encoded matrix - indices.push(ind % num_encoded_rows); - } + let indices = get_indices_from_transcript(m * rho_inv, t, &mut transcript); // 7. Compute Merkle tree paths for the columns let mut queried_columns = Vec::new(); @@ -406,7 +412,7 @@ where paths.push(col_tree.generate_proof(i).unwrap()); } - let proof: Proof = Proof { + let proof = LigeroPCProof { paths, v, columns: queried_columns, @@ -439,6 +445,69 @@ where Self::Randomness: 'a, Self::Commitment: 'a, { + let labeled_polynomial = labeled_polynomials.into_iter().next().unwrap(); + let polynomial = labeled_polynomial.polynomial(); + let num_elems = polynomial.degree() + 1; + let m = (num_elems as f64).sqrt().ceil() as usize; + let t = calculate_t(rho_inv, sec_param); + let mut optional = crate::optional_rng::OptionalRng(rng); + let leaf_hash_param = C::LeafHash::setup(&mut optional).unwrap(); + let two_to_one_param = C::TwoToOneHash::setup(&mut optional).unwrap(); + + let mut coeffs = polynomial.coeffs().to_vec(); + coeffs.resize(m * m, F::zero()); + let mat = Matrix::new_from_flat(m, m, &coeffs); + + let mut transcript: IOPTranscript = IOPTranscript::new(b"opening_transcript"); + + // 1. Generate vector b + let mut b = Vec::new(); + let point_pow_m = point.pow([m as u64]); + let mut acc_b = F::one(); + for _ in 0..m { + b.push(acc_b); + acc_b *= point_pow_m; + } + + let v = mat.row_mul(&b); + transcript.append_serializable_element(b"v", &v).unwrap(); + + // 2. Generate t column indices to test the linear combination on + let indices = get_indices_from_transcript(m * rho_inv, t, &mut transcript); + + // 3. Apply Reed-Solomon encoding row-wise + let fft_domain = GeneralEvaluationDomain::::new(m).unwrap(); + let mut domain_iter = fft_domain.elements(); + + let ext_mat = Matrix::new_from_rows( + mat.rows() + .iter() + .map(|r| reed_solomon(r, rho_inv, fft_domain, &mut domain_iter)) + .collect(), + ); + + // 3. Create the Merkle tree from the hashes of the columns + let mut col_hashes: Vec = Vec::new(); + let ext_mat_cols = ext_mat.cols(); + + for col in ext_mat_cols.iter() { + col_hashes.push(hash_array::(col).into()); + } + + let col_tree = + MerkleTree::::new(&leaf_hash_param, &two_to_one_param, col_hashes).unwrap(); + + let root = col_tree.root(); + + // 7. Compute Merkle tree paths for the columns + let mut queried_columns = Vec::new(); + let mut paths = Vec::new(); + + for i in indices { + queried_columns.push(ext_mat_cols[i].clone()); + paths.push(col_tree.generate_proof(i).unwrap()); + } + todo!() } @@ -456,14 +525,58 @@ where { let mut rng = rng.unwrap(); let labeled_commitment = commitments.into_iter().next().unwrap(); - // check if we've seen this commitment before. If not, we should verify it. + let commitment = labeled_commitment.commitment(); + + let m = commitment.m; + let t = calculate_t(rho_inv, sec_param); + let leaf_hash_param = C::LeafHash::setup(&mut rng).unwrap(); let two_to_one_param = C::TwoToOneHash::setup(&mut rng).unwrap(); - Self::well_formedness_check( - labeled_commitment.commitment(), + + // check if we've seen this commitment before. If not, we should verify it. + Self::check_well_formedness( + commitment, &leaf_hash_param, &two_to_one_param, ).unwrap(); + + // 1. Seed the transcript with the point and generate t random indices + // TODO replace unwraps by proper error handling + let mut transcript: IOPTranscript = IOPTranscript::new(b"opening_transcript"); + transcript + .append_serializable_element(b"point", point) + .unwrap(); + + let indices = get_indices_from_transcript(m * rho_inv, t, &mut transcript);; + + // 2. Compute a and b + let mut a = Vec::new(); + let mut acc_a = F::one(); + for i in 0..m { + a.push(acc_a); + acc_a *= point; + } + + // by now acc_a = point^m + let mut b = Vec::new(); + let mut acc_b = F::one(); + for i in 0..m { + b.push(acc_b); + acc_b *= acc_a; + } + + Self::check_random_linear_combination( + &b, + commitment, + t, + &mut transcript, + &leaf_hash_param, + &two_to_one_param + )?; + + return Ok(inner_product(&commitment.proof.v, &a) == values.into_iter().next().unwrap()); + + // TODO what is "values"? does it contain the actual evaluations? todo!() } } diff --git a/src/ligero/utils.rs b/src/ligero/utils.rs index 94535257..e3aacc74 100644 --- a/src/ligero/utils.rs +++ b/src/ligero/utils.rs @@ -183,6 +183,7 @@ pub(crate) fn hash_array(array: & dig.finalize().to_vec() } +/// Generate `t` (not necessarily distinct) random points in `[0, n)` using the current state of `transcript` pub(crate) fn get_indices_from_transcript( n: usize, t: usize, From 5bdee22e412687438115dcf3806a0d4da883eea0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mej=C3=ADas=20Gil?= Date: Fri, 30 Jun 2023 14:05:36 +0200 Subject: [PATCH 042/108] open implemented --- src/ligero/mod.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 42669633..7840143e 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -486,7 +486,7 @@ where .collect(), ); - // 3. Create the Merkle tree from the hashes of the columns + // 4. Create the Merkle tree from the hashes of the columns let mut col_hashes: Vec = Vec::new(); let ext_mat_cols = ext_mat.cols(); @@ -497,9 +497,7 @@ where let col_tree = MerkleTree::::new(&leaf_hash_param, &two_to_one_param, col_hashes).unwrap(); - let root = col_tree.root(); - - // 7. Compute Merkle tree paths for the columns + // 5. Compute Merkle tree paths for the columns let mut queried_columns = Vec::new(); let mut paths = Vec::new(); @@ -508,7 +506,12 @@ where paths.push(col_tree.generate_proof(i).unwrap()); } - todo!() + Ok( + LigeroPCProof { + paths, + v, + columns: queried_columns, + }) } fn check<'a>( From f89680142ec0e6eac6a2dbcc76badec3610cdc7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mej=C3=ADas=20Gil?= Date: Fri, 30 Jun 2023 14:40:29 +0200 Subject: [PATCH 043/108] compiling --- src/ligero/mod.rs | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index d45b910b..2d709cf5 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -86,8 +86,8 @@ where /// The verifier can check the well-formedness of the commitment by taking random linear combinations. fn check_well_formedness( commitment: &LigeroPCCommitment, - leaf_hash_param: &LeafParam, - two_to_one_param: &TwoToOneParam, + leaf_hash_params: &LeafParam, + two_to_one_params: &TwoToOneParam, ) -> Result<(), Error> { let t = calculate_t(rho_inv, sec_param); @@ -112,8 +112,8 @@ where commitment, t, &mut transcript, - leaf_hash_param, - two_to_one_param + leaf_hash_params, + two_to_one_params ) } fn check_random_linear_combination( @@ -121,12 +121,12 @@ where commitment: &LigeroPCCommitment, t: usize, transcript: &mut IOPTranscript, - leaf_hash_param: &<::LeafHash as CRHScheme>::Parameters, - two_to_one_param: &<::TwoToOneHash as TwoToOneCRHScheme>::Parameters + leaf_hash_params: &<::LeafHash as CRHScheme>::Parameters, + two_to_one_params: &<::TwoToOneHash as TwoToOneCRHScheme>::Parameters ) -> Result<(), Error> { // 1. Hash the received columns into leaf hashes - let mut col_hashes: Vec = Vec::new(); + let mut col_hashes: Vec> = Vec::new(); for c in commitment.proof.columns.iter() { col_hashes.push(hash_column::(c).into()); } @@ -142,8 +142,8 @@ where assert!(path.leaf_index == *i, "Path is for a different index!"); // TODO return an error path.verify( - leaf_hash_param, - two_to_one_param, + leaf_hash_params, + two_to_one_params, &commitment.root, leaf.clone(), ) @@ -178,6 +178,7 @@ impl PCUniversalParams for LigeroPCUniversalParams { } } +/// Ligero commitment structure #[derive(Derivative, CanonicalSerialize, CanonicalDeserialize)] #[derivative(Clone(bound = ""), Debug(bound = ""))] pub struct LigeroPCCommitterKey @@ -416,11 +417,11 @@ where ); // 3. Create the Merkle tree from the hashes of the columns - let mut col_hashes: Vec = Vec::new(); + let mut col_hashes: Vec> = Vec::new(); let ext_mat_cols = ext_mat.cols(); for col in ext_mat_cols.iter() { - col_hashes.push(hash_array::(col).into()); + col_hashes.push(hash_column::(col).into()); } let col_tree = @@ -531,11 +532,11 @@ where ); // 4. Create the Merkle tree from the hashes of the columns - let mut col_hashes: Vec = Vec::new(); + let mut col_hashes: Vec> = Vec::new(); let ext_mat_cols = ext_mat.cols(); for col in ext_mat_cols.iter() { - col_hashes.push(hash_array::(col).into()); + col_hashes.push(hash_column::(col).into()); } let col_tree = @@ -576,14 +577,11 @@ where let m = commitment.m; let t = calculate_t(rho_inv, sec_param); - let leaf_hash_param = C::LeafHash::setup(&mut rng).unwrap(); - let two_to_one_param = C::TwoToOneHash::setup(&mut rng).unwrap(); - // check if we've seen this commitment before. If not, we should verify it. Self::check_well_formedness( commitment, - &leaf_hash_param, - &two_to_one_param, + &vk.leaf_hash_params, + &vk.two_to_one_params, ).unwrap(); // 1. Seed the transcript with the point and generate t random indices @@ -616,8 +614,8 @@ where commitment, t, &mut transcript, - &leaf_hash_param, - &two_to_one_param + &vk.leaf_hash_params, + &vk.two_to_one_params )?; return Ok(inner_product(&commitment.proof.v, &a) == values.into_iter().next().unwrap()); From d1a6b6cba8b4ad745d3ea3e60db26082bdf8c8e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mej=C3=ADas=20Gil?= Date: Fri, 30 Jun 2023 15:20:00 +0200 Subject: [PATCH 044/108] changed access to params --- src/ligero/mod.rs | 62 ++++++++++++++++++----------------------------- 1 file changed, 24 insertions(+), 38 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 2d709cf5..d22dae1f 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -113,7 +113,7 @@ where t, &mut transcript, leaf_hash_params, - two_to_one_params + two_to_one_params, ) } fn check_random_linear_combination( @@ -122,15 +122,14 @@ where t: usize, transcript: &mut IOPTranscript, leaf_hash_params: &<::LeafHash as CRHScheme>::Parameters, - two_to_one_params: &<::TwoToOneHash as TwoToOneCRHScheme>::Parameters - ) -> Result<(), Error> - { + two_to_one_params: &<::TwoToOneHash as TwoToOneCRHScheme>::Parameters, + ) -> Result<(), Error> { // 1. Hash the received columns into leaf hashes let mut col_hashes: Vec> = Vec::new(); for c in commitment.proof.columns.iter() { col_hashes.push(hash_column::(c).into()); } - + // 2. Compute t column indices to check the linear combination at let num_encoded_rows = commitment.m * rho_inv; let indices = get_indices_from_transcript::(num_encoded_rows, t, transcript); @@ -157,7 +156,8 @@ where // 5. Verify the random linear combinations for (transcript_index, matrix_index) in indices.into_iter().enumerate() { - if inner_product(coeffs, &commitment.proof.columns[transcript_index]) != w[matrix_index] { + if inner_product(coeffs, &commitment.proof.columns[transcript_index]) != w[matrix_index] + { // TODO return proper error return Err(Error::IncorrectInputLength( "Incorrect linear combination".to_string(), @@ -166,7 +166,6 @@ where } Ok(()) - } } @@ -293,10 +292,10 @@ impl PCRandomness for LigeroPCRandomness { /// Ligero proof #[derive(Derivative, CanonicalSerialize, CanonicalDeserialize)] #[derivative(Default(bound = ""), Clone(bound = ""), Debug(bound = ""))] -pub struct LigeroPCProof -where - F: PrimeField, - C: Config +pub struct LigeroPCProof +where + F: PrimeField, + C: Config, { /// For each of the indices in q, `paths` contains the path from the root of the merkle tree to the leaf paths: Vec>, @@ -354,7 +353,7 @@ where supported_hiding_bound: usize, enforced_degree_bounds: Option<&[usize]>, ) -> Result<(Self::CommitterKey, Self::VerifierKey), Self::Error> { - todo!() + todo!(); } fn commit<'a>( @@ -373,9 +372,6 @@ where { // 0. Recovering parameters let t = calculate_t(rho_inv, sec_param); - let mut optional = crate::optional_rng::OptionalRng(rng); // TODO taken from Marlin code; change in the future? - let leaf_hash_param = C::LeafHash::setup(&mut optional).unwrap(); - let two_to_one_param = C::TwoToOneHash::setup(&mut optional).unwrap(); // TODO loop over all polynomials @@ -495,9 +491,6 @@ where let num_elems = polynomial.degree() + 1; let m = (num_elems as f64).sqrt().ceil() as usize; let t = calculate_t(rho_inv, sec_param); - let mut optional = crate::optional_rng::OptionalRng(rng); - let leaf_hash_param = C::LeafHash::setup(&mut optional).unwrap(); - let two_to_one_param = C::TwoToOneHash::setup(&mut optional).unwrap(); let mut coeffs = polynomial.coeffs().to_vec(); coeffs.resize(m * m, F::zero()); @@ -540,7 +533,7 @@ where } let col_tree = - MerkleTree::::new(&leaf_hash_param, &two_to_one_param, col_hashes).unwrap(); + MerkleTree::::new(&ck.leaf_hash_params, &ck.two_to_one_params, col_hashes).unwrap(); // 5. Compute Merkle tree paths for the columns let mut queried_columns = Vec::new(); @@ -550,13 +543,12 @@ where queried_columns.push(ext_mat_cols[i].clone()); paths.push(col_tree.generate_proof(i).unwrap()); } - - Ok( - LigeroPCProof { - paths, - v, - columns: queried_columns, - }) + + Ok(LigeroPCProof { + paths, + v, + columns: queried_columns, + }) } fn check<'a>( @@ -573,16 +565,13 @@ where { let labeled_commitment = commitments.into_iter().next().unwrap(); let commitment = labeled_commitment.commitment(); - + let m = commitment.m; let t = calculate_t(rho_inv, sec_param); // check if we've seen this commitment before. If not, we should verify it. - Self::check_well_formedness( - commitment, - &vk.leaf_hash_params, - &vk.two_to_one_params, - ).unwrap(); + Self::check_well_formedness(commitment, &vk.leaf_hash_params, &vk.two_to_one_params) + .unwrap(); // 1. Seed the transcript with the point and generate t random indices // TODO replace unwraps by proper error handling @@ -591,7 +580,7 @@ where .append_serializable_element(b"point", point) .unwrap(); - let indices = get_indices_from_transcript(m * rho_inv, t, &mut transcript);; + let indices = get_indices_from_transcript(m * rho_inv, t, &mut transcript); // 2. Compute a and b let mut a = Vec::new(); @@ -615,13 +604,10 @@ where t, &mut transcript, &vk.leaf_hash_params, - &vk.two_to_one_params + &vk.two_to_one_params, )?; - return Ok(inner_product(&commitment.proof.v, &a) == values.into_iter().next().unwrap()); - - // TODO what is "values"? does it contain the actual evaluations? - todo!() + Ok(inner_product(&commitment.proof.v, &a) == values.into_iter().next().unwrap()) } } From 614d5862ed7b882f558efe748a02b850e4ada1d7 Mon Sep 17 00:00:00 2001 From: mmagician Date: Fri, 30 Jun 2023 16:32:02 +0200 Subject: [PATCH 045/108] test: if matrix is square, panics --- src/ligero/tests.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/ligero/tests.rs b/src/ligero/tests.rs index 7b4bda48..35476321 100644 --- a/src/ligero/tests.rs +++ b/src/ligero/tests.rs @@ -53,6 +53,13 @@ mod tests { assert_eq!(mat.entry(1, 2), F::from(50)); } + #[test] + fn test_matrix_constructor_flat_square() { + let entries: Vec = to_field(vec![10, 100, 4, 67]); + let mat = Matrix::new_from_flat(2, 2, &entries); + assert_eq!(mat.entry(1, 1), F::from(67)); + } + #[test] #[should_panic] fn test_matrix_constructor_flat_panic() { From 5dcad7b5e1583c246b9d80eeee48c7c666c318a2 Mon Sep 17 00:00:00 2001 From: mmagician Date: Fri, 30 Jun 2023 16:32:18 +0200 Subject: [PATCH 046/108] fix the indexing: should no longer panic on index out of bounds --- src/ligero/utils.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ligero/utils.rs b/src/ligero/utils.rs index 57a20860..201113f6 100644 --- a/src/ligero/utils.rs +++ b/src/ligero/utils.rs @@ -38,7 +38,7 @@ impl Matrix { // TODO more efficient to run linearly? let entries: Vec> = (0..n) - .map(|row| (0..m).map(|col| entry_list[n * row + m]).collect()) + .map(|row| (0..m).map(|col| entry_list[m * row + col]).collect()) .collect(); Self { n, m, entries } From 48df32fba4dd54226312a2f45879f5011cde67d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mej=C3=ADas=20Gil?= Date: Fri, 30 Jun 2023 17:39:13 +0200 Subject: [PATCH 047/108] compiling --- src/ligero/mod.rs | 403 ++++++++++++++------------------------------ src/ligero/utils.rs | 12 +- 2 files changed, 134 insertions(+), 281 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index d22dae1f..b2de3dd5 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -1,22 +1,19 @@ use ark_crypto_primitives::crh::{CRHScheme, TwoToOneCRHScheme}; use ark_crypto_primitives::{ - merkle_tree::{Config, LeafParam, MerkleTree, Path, TwoToOneParam}, + merkle_tree::{Config, LeafParam, MerkleTree, TwoToOneParam}, sponge::{Absorb, CryptographicSponge}, }; use ark_ff::PrimeField; use ark_poly::{DenseUVPolynomial, EvaluationDomain, GeneralEvaluationDomain}; -use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use ark_std::fmt::Debug; use core::marker::PhantomData; use digest::Digest; use jf_primitives::pcs::transcript::IOPTranscript; use std::borrow::Borrow; -use crate::LabeledPolynomial; +use crate::{LabeledPolynomial, PolynomialCommitment, Error, LabeledCommitment}; use crate::{ ligero::utils::{inner_product, reed_solomon}, - Error, LabeledCommitment, PCCommitment, PCCommitterKey, PCPreparedCommitment, - PCPreparedVerifierKey, PCRandomness, PCUniversalParams, PCVerifierKey, PolynomialCommitment, }; use ark_std::rand::RngCore; @@ -24,40 +21,13 @@ use ark_std::rand::RngCore; mod utils; use utils::Matrix; -use self::utils::get_indices_from_transcript; -use self::utils::hash_column; -mod tests; - -// TODO: Disclaimer: no hiding prop -/// The Ligero polynomial commitment scheme. -pub struct Ligero< - F: PrimeField, - C: Config, - D: Digest, - S: CryptographicSponge, - P: DenseUVPolynomial, - /// one over the rate rho - const rho_inv: usize, - /// security parameter, used in calculating t - const sec_param: usize, -> { - _field: PhantomData, - _config: PhantomData, - _digest: PhantomData, - _sponge: PhantomData, - _poly: PhantomData

, -} +mod data_structures; +use data_structures::*; -// TODO come up with reasonable defaults -const DEFAULT_RHO_INV: usize = 2; -const DEFAULT_SEC_PARAM: usize = 128; +pub use data_structures::{Ligero, LigeroPCCommitterKey, LigeroPCVerifierKey}; -fn calculate_t(rho_inv: usize, sec_param: usize) -> usize { - // TODO calculate t somehow - let t = 5; - println!("WARNING: you are using dummy t = {t}"); - t -} +use utils::{get_indices_from_transcript, calculate_t, hash_column}; +mod tests; impl Ligero @@ -167,143 +137,93 @@ where Ok(()) } -} + fn compute_matrices(polynomial: &P) -> (Matrix, Matrix) { -type LigeroPCUniversalParams = (); - -impl PCUniversalParams for LigeroPCUniversalParams { - fn max_degree(&self) -> usize { - todo!() - } -} + let mut coeffs = polynomial.coeffs().to_vec(); -/// Ligero commitment structure -#[derive(Derivative, CanonicalSerialize, CanonicalDeserialize)] -#[derivative(Clone(bound = ""), Debug(bound = ""))] -pub struct LigeroPCCommitterKey -where - C: Config, - <::TwoToOneHash as TwoToOneCRHScheme>::Parameters: Debug, - <::LeafHash as CRHScheme>::Parameters: Debug, -{ - #[derivative(Debug = "ignore")] - leaf_hash_params: LeafParam, - #[derivative(Debug = "ignore")] - two_to_one_params: TwoToOneParam, -} + // 1. Computing parameters and initial matrix + // want: ceil(sqrt(f.degree() + 1)); need to deal with usize -> f64 conversion + let num_elems = polynomial.degree() + 1; -impl PCCommitterKey for LigeroPCCommitterKey -where - C: Config, - <::TwoToOneHash as TwoToOneCRHScheme>::Parameters: Debug, - <::LeafHash as CRHScheme>::Parameters: Debug, -{ - fn max_degree(&self) -> usize { - todo!() - } + // TODO move this check to the constructor? + assert_eq!( + (num_elems as f64) as usize, + num_elems, + "Degree of polynomial + 1 cannot be converted to f64: aborting" + ); + let m = (num_elems as f64).sqrt().ceil() as usize; + // TODO: check if fft_domain.compute_size_of_domain(m) is large enough - fn supported_degree(&self) -> usize { - todo!() - } -} -/// The verifier key which holds some scheme parameters -#[derive(Derivative, CanonicalSerialize, CanonicalDeserialize)] -#[derivative(Clone(bound = ""), Debug(bound = ""))] -pub struct LigeroPCVerifierKey -where - C: Config, - <::TwoToOneHash as TwoToOneCRHScheme>::Parameters: Debug, - <::LeafHash as CRHScheme>::Parameters: Debug, -{ - leaf_hash_params: LeafParam, - two_to_one_params: TwoToOneParam, -} + // padding the coefficient vector with zeroes + // TODO is this the most efficient/safest way to do it? + coeffs.resize(m * m, F::zero()); -impl PCVerifierKey for LigeroPCVerifierKey -where - C: Config, - <::TwoToOneHash as TwoToOneCRHScheme>::Parameters: Debug, - <::LeafHash as CRHScheme>::Parameters: Debug, -{ - fn max_degree(&self) -> usize { - todo!() - } + let mat = Matrix::new_from_flat(m, m, &coeffs); - fn supported_degree(&self) -> usize { - todo!() - } -} + // 2. Apply Reed-Solomon encoding row-wise + let fft_domain = GeneralEvaluationDomain::::new(m).unwrap(); + let mut domain_iter = fft_domain.elements(); -type LigeroPCPreparedVerifierKey = (); + let ext_mat = Matrix::new_from_rows( + mat.rows() + .iter() + .map(|r| reed_solomon(r, rho_inv, fft_domain, &mut domain_iter)) + .collect(), + ); -impl PCPreparedVerifierKey for LigeroPCPreparedVerifierKey { - fn prepare(vk: &Unprepared) -> Self { - todo!() + (mat, ext_mat) } -} - -/// The commitment to a polynomial is a root of the merkle tree, -/// where each node is a hash of the column of the encoded coefficient matrix U. -#[derive(Derivative, CanonicalSerialize, CanonicalDeserialize)] -#[derivative(Default(bound = ""), Clone(bound = ""), Debug(bound = ""))] -pub struct LigeroPCCommitment { - // number of rows of the square matrix containing the coefficients of the polynomial - m: usize, - // TODO is InnerDigest the right type? - root: C::InnerDigest, - proof: LigeroPCProof, -} + fn create_merkle_tree( + ext_mat: &Matrix, + leaf_hash_params: &<::LeafHash as CRHScheme>::Parameters, + two_to_one_params: &<::TwoToOneHash as TwoToOneCRHScheme>::Parameters, + ) -> MerkleTree:: + { + let mut col_hashes: Vec> = Vec::new(); + let ext_mat_cols = ext_mat.cols(); -impl PCCommitment for LigeroPCCommitment { - fn empty() -> Self { - todo!() - } + for col in ext_mat_cols.iter() { + col_hashes.push(hash_column::(col).into()); + } - fn has_degree_bound(&self) -> bool { - todo!() + MerkleTree::::new(leaf_hash_params, two_to_one_params, col_hashes).unwrap() } -} + fn generate_proof( + coeffs: &[F], + mat: &Matrix, + ext_mat: &Matrix, + col_tree: &MerkleTree, + transcript: &mut IOPTranscript + ) -> LigeroPCProof { -type LigeroPCPreparedCommitment = (); + let m = mat.m; + let t = calculate_t(rho_inv, sec_param); -impl PCPreparedCommitment for LigeroPCPreparedCommitment { - fn prepare(cm: &Unprepared) -> Self { - todo!() - } -} + // 1. Compute the linear combination using the random coefficients + let v = mat.row_mul(coeffs); -type LigeroPCRandomness = (); + transcript.append_serializable_element(b"v", &v).unwrap(); -impl PCRandomness for LigeroPCRandomness { - fn empty() -> Self { - todo!() - } + // 2. Generate t column indices to test the linear combination on + let indices = get_indices_from_transcript(m * rho_inv, t, transcript); - fn rand( - num_queries: usize, - has_degree_bound: bool, - num_vars: Option, - rng: &mut R, - ) -> Self { - todo!() - } -} + // 3. Compute Merkle tree paths for the columns + let mut queried_columns = Vec::new(); + let mut paths = Vec::new(); -/// Ligero proof -#[derive(Derivative, CanonicalSerialize, CanonicalDeserialize)] -#[derivative(Default(bound = ""), Clone(bound = ""), Debug(bound = ""))] -pub struct LigeroPCProof -where - F: PrimeField, - C: Config, -{ - /// For each of the indices in q, `paths` contains the path from the root of the merkle tree to the leaf - paths: Vec>, + let ext_mat_cols = ext_mat.cols(); - /// v, s.t. E(v) = w - v: Vec, + for i in indices { + queried_columns.push(ext_mat_cols[i].clone()); + paths.push(col_tree.generate_proof(i).unwrap()); + } - columns: Vec>, + LigeroPCProof { + paths, + v, + columns: queried_columns, + } + } } impl PolynomialCommitment @@ -370,9 +290,6 @@ where where P: 'a, { - // 0. Recovering parameters - let t = calculate_t(rho_inv, sec_param); - // TODO loop over all polynomials // TODO decide what to do with label and degree bound (these are private! but the commitment also has them) @@ -380,84 +297,38 @@ where let polynomial = labeled_polynomial.polynomial(); - let mut coeffs = polynomial.coeffs().to_vec(); + // 1. Compute matrices + let (mat, ext_mat) = Self::compute_matrices(polynomial); - // 1. Computing parameters and initial matrix - // want: ceil(sqrt(f.degree() + 1)); need to deal with usize -> f64 conversion - let num_elems = polynomial.degree() + 1; - - // TODO move this check to the constructor? - assert_eq!( - (num_elems as f64) as usize, - num_elems, - "Degree of polynomial + 1 cannot be converted to f64: aborting" - ); - let m = (num_elems as f64).sqrt().ceil() as usize; - // TODO: check if fft_domain.compute_size_of_domain(m) is large enough - - // padding the coefficient vector with zeroes - // TODO is this the most efficient/safest way to do it? - coeffs.resize(m * m, F::zero()); - - let mat = Matrix::new_from_flat(m, m, &coeffs); - - // 2. Apply Reed-Solomon encoding row-wise - let fft_domain = GeneralEvaluationDomain::::new(m).unwrap(); - let mut domain_iter = fft_domain.elements(); - - let ext_mat = Matrix::new_from_rows( - mat.rows() - .iter() - .map(|r| reed_solomon(r, rho_inv, fft_domain, &mut domain_iter)) - .collect(), + // 2. Create the Merkle tree from the hashes of the columns + let col_tree = Self::create_merkle_tree( + &ext_mat, + &ck.leaf_hash_params, + &ck.two_to_one_params ); - // 3. Create the Merkle tree from the hashes of the columns - let mut col_hashes: Vec> = Vec::new(); - let ext_mat_cols = ext_mat.cols(); - - for col in ext_mat_cols.iter() { - col_hashes.push(hash_column::(col).into()); - } - - let col_tree = - MerkleTree::::new(&ck.leaf_hash_params, &ck.two_to_one_params, col_hashes).unwrap(); - + // 3. Add root to transcript and generate random linear combination with it let root = col_tree.root(); - // 4. Add root to transcript and generate random linear combination with it let mut transcript: IOPTranscript = IOPTranscript::new(b"well_formedness_transcript"); transcript .append_serializable_element(b"root", &root) .unwrap(); - // 5. Generate linear combination using the matrix and random coefficients + let m = mat.m; let mut r = Vec::new(); for _ in 0..m { r.push(transcript.get_and_append_challenge(b"r").unwrap()); } - let v = mat.row_mul(&r); - - transcript.append_serializable_element(b"v", &v).unwrap(); - - // 6. Generate t column indices to test the linear combination on - let indices = get_indices_from_transcript(m * rho_inv, t, &mut transcript); - - // 7. Compute Merkle tree paths for the columns - let mut queried_columns = Vec::new(); - let mut paths = Vec::new(); - - for i in indices { - queried_columns.push(ext_mat_cols[i].clone()); - paths.push(col_tree.generate_proof(i).unwrap()); - } - - let proof = LigeroPCProof { - paths, - v, - columns: queried_columns, - }; + // 4. Generate the proof by choosing random columns and proving their paths in the tree + let proof = Self::generate_proof( + &r, + &mat, + &ext_mat, + &col_tree, + &mut transcript + ); let commitment = LigeroPCCommitment { m, root, proof }; @@ -488,17 +359,20 @@ where { let labeled_polynomial = labeled_polynomials.into_iter().next().unwrap(); let polynomial = labeled_polynomial.polynomial(); - let num_elems = polynomial.degree() + 1; - let m = (num_elems as f64).sqrt().ceil() as usize; - let t = calculate_t(rho_inv, sec_param); - let mut coeffs = polynomial.coeffs().to_vec(); - coeffs.resize(m * m, F::zero()); - let mat = Matrix::new_from_flat(m, m, &coeffs); + // 1. Compute matrices + let (mat, ext_mat) = Self::compute_matrices(polynomial); - let mut transcript: IOPTranscript = IOPTranscript::new(b"opening_transcript"); + // 2. Create the Merkle tree from the hashes of the columns + let col_tree = Self::create_merkle_tree( + &ext_mat, + &ck.leaf_hash_params, + &ck.two_to_one_params + ); + + // 3. Generate vector b and add v = b·M to the transcript + let m = mat.m; - // 1. Generate vector b let mut b = Vec::new(); let point_pow_m = point.pow([m as u64]); let mut acc_b = F::one(); @@ -507,48 +381,19 @@ where acc_b *= point_pow_m; } + let mut transcript: IOPTranscript = IOPTranscript::new(b"opening_transcript"); + let v = mat.row_mul(&b); + transcript.append_serializable_element(b"point", point).unwrap(); transcript.append_serializable_element(b"v", &v).unwrap(); - // 2. Generate t column indices to test the linear combination on - let indices = get_indices_from_transcript(m * rho_inv, t, &mut transcript); - - // 3. Apply Reed-Solomon encoding row-wise - let fft_domain = GeneralEvaluationDomain::::new(m).unwrap(); - let mut domain_iter = fft_domain.elements(); - - let ext_mat = Matrix::new_from_rows( - mat.rows() - .iter() - .map(|r| reed_solomon(r, rho_inv, fft_domain, &mut domain_iter)) - .collect(), - ); - - // 4. Create the Merkle tree from the hashes of the columns - let mut col_hashes: Vec> = Vec::new(); - let ext_mat_cols = ext_mat.cols(); - - for col in ext_mat_cols.iter() { - col_hashes.push(hash_column::(col).into()); - } - - let col_tree = - MerkleTree::::new(&ck.leaf_hash_params, &ck.two_to_one_params, col_hashes).unwrap(); - - // 5. Compute Merkle tree paths for the columns - let mut queried_columns = Vec::new(); - let mut paths = Vec::new(); - - for i in indices { - queried_columns.push(ext_mat_cols[i].clone()); - paths.push(col_tree.generate_proof(i).unwrap()); - } - - Ok(LigeroPCProof { - paths, - v, - columns: queried_columns, - }) + Ok(Self::generate_proof( + &b, + &mat, + &ext_mat, + &col_tree, + &mut transcript + )) } fn check<'a>( @@ -573,19 +418,10 @@ where Self::check_well_formedness(commitment, &vk.leaf_hash_params, &vk.two_to_one_params) .unwrap(); - // 1. Seed the transcript with the point and generate t random indices - // TODO replace unwraps by proper error handling - let mut transcript: IOPTranscript = IOPTranscript::new(b"opening_transcript"); - transcript - .append_serializable_element(b"point", point) - .unwrap(); - - let indices = get_indices_from_transcript(m * rho_inv, t, &mut transcript); - - // 2. Compute a and b + // 1. Compute a and b let mut a = Vec::new(); let mut acc_a = F::one(); - for i in 0..m { + for _ in 0..m { a.push(acc_a); acc_a *= point; } @@ -593,11 +429,20 @@ where // by now acc_a = point^m let mut b = Vec::new(); let mut acc_b = F::one(); - for i in 0..m { + for _ in 0..m { b.push(acc_b); acc_b *= acc_a; } + // 2. Seed the transcript with the point and generate t random indices + // TODO replace unwraps by proper error handling + let mut transcript: IOPTranscript = IOPTranscript::new(b"opening_transcript"); + transcript + .append_serializable_element(b"point", point) + .unwrap(); + transcript.append_serializable_element(b"v", &proof.v).unwrap(); + + // 3. Check the linear combination in the proof Self::check_random_linear_combination( &b, commitment, diff --git a/src/ligero/utils.rs b/src/ligero/utils.rs index 57a20860..6ab31e0e 100644 --- a/src/ligero/utils.rs +++ b/src/ligero/utils.rs @@ -15,8 +15,8 @@ use rayon::{ use crate::streaming_kzg::ceil_div; pub(crate) struct Matrix { - n: usize, - m: usize, + pub(crate) n: usize, + pub(crate) m: usize, entries: Vec>, } @@ -204,3 +204,11 @@ pub(crate) fn get_indices_from_transcript( } indices } + +#[inline] +pub(crate) fn calculate_t(rho_inv: usize, sec_param: usize) -> usize { + // TODO calculate t somehow + let t = 5; + println!("WARNING: you are using dummy t = {t}"); + t +} \ No newline at end of file From 0dfed86d6ef0a6ff9f3b1c9af2a166c49b122f48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mej=C3=ADas=20Gil?= Date: Fri, 30 Jun 2023 17:49:14 +0200 Subject: [PATCH 048/108] added data_structures.rs --- src/ligero/data_structures.rs | 184 ++++++++++++++++++++++++++++++++++ 1 file changed, 184 insertions(+) create mode 100644 src/ligero/data_structures.rs diff --git a/src/ligero/data_structures.rs b/src/ligero/data_structures.rs new file mode 100644 index 00000000..737b3fa3 --- /dev/null +++ b/src/ligero/data_structures.rs @@ -0,0 +1,184 @@ +use ark_crypto_primitives::crh::{CRHScheme, TwoToOneCRHScheme}; +use ark_crypto_primitives::{ + merkle_tree::{Config, LeafParam, Path, TwoToOneParam}, + sponge::CryptographicSponge, +}; +use ark_ff::PrimeField; +use ark_poly::DenseUVPolynomial; +use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; +use ark_std::fmt::Debug; +use core::marker::PhantomData; +use digest::Digest; + +use crate::{ + PCCommitment, PCCommitterKey, PCPreparedCommitment, + PCPreparedVerifierKey, PCRandomness, PCUniversalParams, PCVerifierKey, +}; + +use ark_std::rand::RngCore; + + +// TODO: Disclaimer: no hiding prop +/// The Ligero polynomial commitment scheme. +pub struct Ligero< + F: PrimeField, + C: Config, + D: Digest, + S: CryptographicSponge, + P: DenseUVPolynomial, + /// one over the rate rho + const rho_inv: usize, + /// security parameter, used in calculating t + const sec_param: usize, +> { + pub(crate) _field: PhantomData, + pub(crate) _config: PhantomData, + pub(crate) _digest: PhantomData, + pub(crate) _sponge: PhantomData, + pub(crate) _poly: PhantomData

, +} + +// TODO come up with reasonable defaults +const DEFAULT_RHO_INV: usize = 2; +const DEFAULT_SEC_PARAM: usize = 128; + +pub(crate) type LigeroPCUniversalParams = (); + +impl PCUniversalParams for LigeroPCUniversalParams { + fn max_degree(&self) -> usize { + todo!() + } +} + +/// Ligero commitment structure +#[derive(Derivative, CanonicalSerialize, CanonicalDeserialize)] +#[derivative(Clone(bound = ""), Debug(bound = ""))] +pub struct LigeroPCCommitterKey +where + C: Config, + <::TwoToOneHash as TwoToOneCRHScheme>::Parameters: Debug, + <::LeafHash as CRHScheme>::Parameters: Debug, +{ + #[derivative(Debug = "ignore")] + /// Parameters for hash function of Merkle tree leaves + pub leaf_hash_params: LeafParam, + #[derivative(Debug = "ignore")] + /// Parameters for hash function of Merke tree combining two nodes into one + pub two_to_one_params: TwoToOneParam, +} + +impl PCCommitterKey for LigeroPCCommitterKey +where + C: Config, + <::TwoToOneHash as TwoToOneCRHScheme>::Parameters: Debug, + <::LeafHash as CRHScheme>::Parameters: Debug, +{ + fn max_degree(&self) -> usize { + todo!() + } + + fn supported_degree(&self) -> usize { + todo!() + } +} +/// The verifier key which holds some scheme parameters +#[derive(Derivative, CanonicalSerialize, CanonicalDeserialize)] +#[derivative(Clone(bound = ""), Debug(bound = ""))] +pub struct LigeroPCVerifierKey +where + C: Config, + <::TwoToOneHash as TwoToOneCRHScheme>::Parameters: Debug, + <::LeafHash as CRHScheme>::Parameters: Debug, +{ + /// Parameters for hash function of Merkle tree leaves + pub leaf_hash_params: LeafParam, + /// Parameters for hash function of Merke tree combining two nodes into one + pub two_to_one_params: TwoToOneParam, +} + +impl PCVerifierKey for LigeroPCVerifierKey +where + C: Config, + <::TwoToOneHash as TwoToOneCRHScheme>::Parameters: Debug, + <::LeafHash as CRHScheme>::Parameters: Debug, +{ + fn max_degree(&self) -> usize { + todo!() + } + + fn supported_degree(&self) -> usize { + todo!() + } +} + +pub(crate) type LigeroPCPreparedVerifierKey = (); + +impl PCPreparedVerifierKey for LigeroPCPreparedVerifierKey { + fn prepare(vk: &Unprepared) -> Self { + todo!() + } +} + +/// The commitment to a polynomial is a root of the merkle tree, +/// where each node is a hash of the column of the encoded coefficient matrix U. +#[derive(Derivative, CanonicalSerialize, CanonicalDeserialize)] +#[derivative(Default(bound = ""), Clone(bound = ""), Debug(bound = ""))] +pub struct LigeroPCCommitment { + // number of rows of the square matrix containing the coefficients of the polynomial + pub(crate) m: usize, + // TODO is InnerDigest the right type? + pub(crate) root: C::InnerDigest, + pub(crate) proof: LigeroPCProof, +} + +impl PCCommitment for LigeroPCCommitment { + fn empty() -> Self { + todo!() + } + + fn has_degree_bound(&self) -> bool { + todo!() + } +} + +pub(crate) type LigeroPCPreparedCommitment = (); + +impl PCPreparedCommitment for LigeroPCPreparedCommitment { + fn prepare(cm: &Unprepared) -> Self { + todo!() + } +} + +pub(crate) type LigeroPCRandomness = (); + +impl PCRandomness for LigeroPCRandomness { + fn empty() -> Self { + todo!() + } + + fn rand( + num_queries: usize, + has_degree_bound: bool, + num_vars: Option, + rng: &mut R, + ) -> Self { + todo!() + } +} + +/// Ligero proof +#[derive(Derivative, CanonicalSerialize, CanonicalDeserialize)] +#[derivative(Default(bound = ""), Clone(bound = ""), Debug(bound = ""))] +pub struct LigeroPCProof +where + F: PrimeField, + C: Config, +{ + /// For each of the indices in q, `paths` contains the path from the root of the merkle tree to the leaf + pub(crate) paths: Vec>, + + /// v, s.t. E(v) = w + pub(crate) v: Vec, + + pub(crate) columns: Vec>, +} \ No newline at end of file From 983f7e8aa4d1175421fc45de25c3909eaee4ed01 Mon Sep 17 00:00:00 2001 From: mmagician Date: Fri, 30 Jun 2023 16:02:21 +0200 Subject: [PATCH 049/108] Call the commit function - currently failing --- src/ligero/tests.rs | 53 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 5 deletions(-) diff --git a/src/ligero/tests.rs b/src/ligero/tests.rs index 35476321..b98c5738 100644 --- a/src/ligero/tests.rs +++ b/src/ligero/tests.rs @@ -2,14 +2,21 @@ mod tests { use ark_bls12_381::Fq as F; + use ark_ff::PrimeField; use ark_poly::{ domain::general::GeneralEvaluationDomain, univariate::DensePolynomial, DenseUVPolynomial, EvaluationDomain, Polynomial, }; use ark_std::test_rng; use blake2::Blake2s256; + use rand_chacha::{rand_core::SeedableRng, ChaCha20Rng}; - use crate::ligero::{utils::*, Ligero, PolynomialCommitment}; + use crate::{ + ligero::{ + utils::*, Ligero, LigeroPCCommitterKey, LigeroPCVerifierKey, PolynomialCommitment, + }, + LabeledPolynomial, + }; use ark_crypto_primitives::{ crh::{pedersen, sha256::Sha256, CRHScheme, TwoToOneCRHScheme}, merkle_tree::{ByteDigestConverter, Config}, @@ -147,11 +154,47 @@ mod tests { assert_eq!(get_num_bytes(1 << 32 + 1), 5); } + fn rand_poly( + degree: usize, + _: Option, + rng: &mut ChaCha20Rng, + ) -> DensePolynomial { + DensePolynomial::rand(degree, rng) + } + + fn constant_poly( + _: usize, + _: Option, + rng: &mut ChaCha20Rng, + ) -> DensePolynomial { + DensePolynomial::from_coefficients_slice(&[F::rand(rng)]) + } + #[test] fn test_construction() { - let rng = &mut test_rng(); - let pp = LigeroPCS::setup(2, None, rng).unwrap(); - // This fails since trim is not implemented - let (ck, vk) = LigeroPCS::trim(&pp, 0, 2, Some(&[0])).unwrap(); + let mut rng = &mut test_rng(); + let leaf_hash_params = ::setup(&mut rng).unwrap(); + let two_to_one_params = ::setup(&mut rng) + .unwrap() + .clone(); + + let ck: LigeroPCCommitterKey = LigeroPCCommitterKey { + leaf_hash_params, + two_to_one_params, + }; + let vk: LigeroPCVerifierKey = LigeroPCVerifierKey { + leaf_hash_params, + two_to_one_params, + }; + + let rand_chacha = &mut ChaCha20Rng::from_rng(test_rng()).unwrap(); + // let = ChaCha20Rng::from_seed([0u8; 32]); + let labeled_poly = LabeledPolynomial::new( + "test".to_string(), + rand_poly(4, None, rand_chacha), + None, + None, + ); + let c = LigeroPCS::commit(&ck, &[labeled_poly], None).unwrap(); } } From 7e013401e3a29bfb76e2c5ff8a5c77f01e70239b Mon Sep 17 00:00:00 2001 From: mmagician Date: Fri, 30 Jun 2023 18:24:15 +0200 Subject: [PATCH 050/108] comments on const generics are not part of doc --- src/ligero/data_structures.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ligero/data_structures.rs b/src/ligero/data_structures.rs index 737b3fa3..c82823f6 100644 --- a/src/ligero/data_structures.rs +++ b/src/ligero/data_structures.rs @@ -26,9 +26,9 @@ pub struct Ligero< D: Digest, S: CryptographicSponge, P: DenseUVPolynomial, - /// one over the rate rho + // one over the rate rho const rho_inv: usize, - /// security parameter, used in calculating t + // security parameter, used in calculating t const sec_param: usize, > { pub(crate) _field: PhantomData, From 3da40e1ed8517be70984a19b3b2b15aab2979a9d Mon Sep 17 00:00:00 2001 From: mmagician Date: Sat, 1 Jul 2023 21:29:00 +0200 Subject: [PATCH 051/108] Use FFTs to compute Reed-Solomon encoding of the vectors --- src/ligero/mod.rs | 9 ++------- src/ligero/utils.rs | 26 +++++++++++--------------- 2 files changed, 13 insertions(+), 22 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index b2de3dd5..2d8d2c1e 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -120,9 +120,7 @@ where } // 4. Compute the encoding w = E(v) - let fft_domain = GeneralEvaluationDomain::::new(commitment.m).unwrap(); - let mut domain_iter = fft_domain.elements(); - let w = reed_solomon(&commitment.proof.v, rho_inv, fft_domain, &mut domain_iter); + let w = reed_solomon(&commitment.proof.v, rho_inv); // 5. Verify the random linear combinations for (transcript_index, matrix_index) in indices.into_iter().enumerate() { @@ -161,13 +159,10 @@ where let mat = Matrix::new_from_flat(m, m, &coeffs); // 2. Apply Reed-Solomon encoding row-wise - let fft_domain = GeneralEvaluationDomain::::new(m).unwrap(); - let mut domain_iter = fft_domain.elements(); - let ext_mat = Matrix::new_from_rows( mat.rows() .iter() - .map(|r| reed_solomon(r, rho_inv, fft_domain, &mut domain_iter)) + .map(|r| reed_solomon(r, rho_inv)) .collect(), ); diff --git a/src/ligero/utils.rs b/src/ligero/utils.rs index efdfa47f..22a2fe90 100644 --- a/src/ligero/utils.rs +++ b/src/ligero/utils.rs @@ -116,10 +116,9 @@ impl Matrix { // TODO batch for all rows? possibly minimal savings due to not having to create fft_domain every time // here we restrict F to PrimeField pub(crate) fn reed_solomon( + // msg, of length m, is interpreted as a vector of coefficients of a polynomial of degree m - 1 msg: &[F], rho_inverse: usize, - fft_domain: GeneralEvaluationDomain, - domain_iter: &mut GeneralElements, ) -> Vec { // TODO is this check worth it? // rho_inverse = 0 should never happen; rho_inverse = 1 means no expansion @@ -129,19 +128,16 @@ pub(crate) fn reed_solomon( let m = msg.len(); - let pol: DensePolynomial = DensePolynomial::from_coefficients_slice(&fft_domain.ifft(msg)); + let domain = GeneralEvaluationDomain::::new(m).unwrap(); + let poly_coeffs = domain.ifft(msg).to_vec(); + let mut out = msg.to_vec(); + assert!(out.len() == m); - let mut encoding = msg.to_vec(); - - domain_iter.nth(m - 1); - - for _ in 0..(rho_inverse - 1) * m { - // TODO make sure the domain has enough elements in the caller or check here - let zeta = domain_iter.next().unwrap(); - encoding.push(pol.evaluate(&zeta)); - } - - encoding + // TODO if rho_inv == 2, then with a systematic encoding the second half will be the same as first - is that an issue? + let domain = GeneralEvaluationDomain::::new(m * (rho_inverse - 1)).unwrap(); + let mut encoded = domain.fft(&poly_coeffs); + out.extend_from_slice(&encoded[..((rho_inverse - 1) * m)]); + out } #[inline] @@ -211,4 +207,4 @@ pub(crate) fn calculate_t(rho_inv: usize, sec_param: usize) -> usize { let t = 5; println!("WARNING: you are using dummy t = {t}"); t -} \ No newline at end of file +} From 00a1557d85321ec235cd92efa0049aaad3d590ff Mon Sep 17 00:00:00 2001 From: mmagician Date: Sat, 1 Jul 2023 21:30:12 +0200 Subject: [PATCH 052/108] Expand the FFT interface test, and add Reed-Solomon --- src/ligero/tests.rs | 82 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 72 insertions(+), 10 deletions(-) diff --git a/src/ligero/tests.rs b/src/ligero/tests.rs index b98c5738..b3fa7d70 100644 --- a/src/ligero/tests.rs +++ b/src/ligero/tests.rs @@ -125,22 +125,84 @@ mod tests { } #[test] - fn test_fft_interface() { + fn test_reed_solomon() { // we use this polynomial to generate the the values we will ask the fft to interpolate - let pol_coeffs: Vec = to_field(vec![30, 2, 91]); - let pol: DensePolynomial = DensePolynomial::from_coefficients_slice(&pol_coeffs); + // let pol_evals: Vec = to_field(vec![30, 2, 91, 4, 8]); + // TODO try for different values of m + // for i in 0..16 + + let rho_inv = 3; + // `i` is the min number of evaluations we need to interpolate a poly of degree `i - 1` + for i in 1..10 { + let rand_chacha = &mut ChaCha20Rng::from_rng(test_rng()).unwrap(); + let pol = rand_poly::(i - 1, None, rand_chacha); + + let coeffs = &pol.coeffs; + assert_eq!( + pol.degree(), + coeffs.len() - 1, + "degree of poly and coeffs mismatch" + ); + assert_eq!(coeffs.len(), i, "length of coeffs and m mismatch"); + + let small_domain = GeneralEvaluationDomain::::new(i).unwrap(); + + // size of evals might be larger than i (the min. number of evals needed to interpolate): we could still do R-S encoding on smaller evals, but the resulting polynomial will differ, so for this test to work we should pass it in full + let evals = small_domain.fft(&coeffs); + let m = evals.len(); - let fft_domain = GeneralEvaluationDomain::::new(pol_coeffs.len()).unwrap(); + let coeffs_again = small_domain.ifft(&evals); + assert_eq!(coeffs_again[..i], *coeffs); - // generating the values - let mut vals = Vec::new(); + let encoded = reed_solomon(&evals, rho_inv); + // Assert that the encoded vector is of the right length + assert_eq!(encoded.len(), rho_inv * m); - for i in 0..4 { - vals.push(pol.evaluate(&fft_domain.element(i))); + // first elements of encoded should be itself, since the code is systematic + assert_eq!(encoded[..m], evals); + + let large_domain = GeneralEvaluationDomain::::new(m * (rho_inv - 1)).unwrap(); + + // The rest of the elements should agree with the domain + for j in 0..((rho_inv - 1) * m) { + println!("j: {:?}", j); + assert_eq!(pol.evaluate(&large_domain.element(j)), encoded[j + m]); + } } + } - // the fft should recover the original polynomial - assert_eq!(fft_domain.ifft(&vals), pol_coeffs); + #[test] + fn test_fft_interface() { + // This test is probably too verbose, and should be merged with the RS test + let rho = 2; + for m in 1..10 { + // rand poly of degree m + let domain = GeneralEvaluationDomain::::new(m).unwrap(); + let poly = UniPoly::rand(m - 1, &mut test_rng()); + // get its evaluations at the entire domain + let evals = (0..domain.size()) + .map(|i| poly.evaluate(&domain.element(i))) + .collect::>(); + + // convert back to the coefficients + let coeffs = domain.ifft(&evals); + assert_eq!(coeffs[..m], poly.coeffs); + + let evals2 = domain.fft(&coeffs.to_vec()); + assert_eq!(evals[..m], evals2[..m]); + + // now we try with a larger domain + let large_domain = GeneralEvaluationDomain::::new(m * rho).unwrap(); + + let evals3 = large_domain.fft(&coeffs.to_vec()); + let evals4: Vec<_> = (0..large_domain.size()) + .map(|i| poly.evaluate(&large_domain.element(i))) + .collect::>(); + + assert_eq!(evals3[..m], evals4[..m]); + + let coeffs2 = large_domain.ifft(&evals3); + } } #[test] From aa19604e747c1a67c7eb1dd0552d0b6231d3d5d0 Mon Sep 17 00:00:00 2001 From: mmagician Date: Sat, 1 Jul 2023 21:55:15 +0200 Subject: [PATCH 053/108] Setup should check that rho_inv is >=1 --- src/ligero/mod.rs | 1 + src/ligero/utils.rs | 6 ------ 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 2d8d2c1e..b0965e45 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -259,6 +259,7 @@ where num_vars: Option, rng: &mut R, ) -> Result { + assert!(rho_inv >= 1, "rho_inv is the inverse of the rate and must be at least 1"); Ok(LigeroPCUniversalParams::default()) } diff --git a/src/ligero/utils.rs b/src/ligero/utils.rs index 22a2fe90..5cb8ecc8 100644 --- a/src/ligero/utils.rs +++ b/src/ligero/utils.rs @@ -120,12 +120,6 @@ pub(crate) fn reed_solomon( msg: &[F], rho_inverse: usize, ) -> Vec { - // TODO is this check worth it? - // rho_inverse = 0 should never happen; rho_inverse = 1 means no expansion - if rho_inverse <= 1 { - return msg.to_vec(); - } - let m = msg.len(); let domain = GeneralEvaluationDomain::::new(m).unwrap(); From d1c7b6242aafa926ff35520d7e9b24eefd12a656 Mon Sep 17 00:00:00 2001 From: mmagician Date: Sat, 1 Jul 2023 21:55:49 +0200 Subject: [PATCH 054/108] Test that there is a large enough FFT domain on our field --- src/ligero/mod.rs | 3 +++ src/ligero/tests.rs | 22 +++++++++++++++++----- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index b0965e45..9a58b6bd 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -260,6 +260,9 @@ where rng: &mut R, ) -> Result { assert!(rho_inv >= 1, "rho_inv is the inverse of the rate and must be at least 1"); + // The domain will have size m * rho_inv, but we already have the first m elements + GeneralEvaluationDomain::::compute_size_of_domain(max_degree * (rho_inv - 1)).ok_or(Error::UnsupportedDegreeBound(max_degree))?; + Ok(LigeroPCUniversalParams::default()) } diff --git a/src/ligero/tests.rs b/src/ligero/tests.rs index b3fa7d70..a9346dc6 100644 --- a/src/ligero/tests.rs +++ b/src/ligero/tests.rs @@ -50,8 +50,8 @@ mod tests { type MTConfig = MerkleTreeParams; type Sponge = PoseidonSponge; - type PC = Ligero; - type LigeroPCS = PC; + type PC = Ligero; + type LigeroPCS = PC; #[test] fn test_matrix_constructor_flat() { @@ -232,9 +232,21 @@ mod tests { DensePolynomial::from_coefficients_slice(&[F::rand(rng)]) } + #[test] + fn test_setup() { + let mut rng = &mut test_rng(); + let _ = LigeroPCS::<2>::setup(10, None, rng).unwrap(); + + // the field we use doesnt have such large domains + assert_eq!(LigeroPCS::<5>::setup(10, None, rng).is_err(), true); + } + #[test] fn test_construction() { + let degree = 4; let mut rng = &mut test_rng(); + // just to make sure we have the right degree given the FFT domain for our field + LigeroPCS::<2>::setup(degree, None, rng).unwrap(); let leaf_hash_params = ::setup(&mut rng).unwrap(); let two_to_one_params = ::setup(&mut rng) .unwrap() @@ -250,13 +262,13 @@ mod tests { }; let rand_chacha = &mut ChaCha20Rng::from_rng(test_rng()).unwrap(); - // let = ChaCha20Rng::from_seed([0u8; 32]); let labeled_poly = LabeledPolynomial::new( "test".to_string(), - rand_poly(4, None, rand_chacha), + rand_poly(degree, None, rand_chacha), None, None, ); - let c = LigeroPCS::commit(&ck, &[labeled_poly], None).unwrap(); + + let c = LigeroPCS::<2>::commit(&ck, &[labeled_poly], None).unwrap(); } } From 3614b6c6fddd0564a899308c5a39b90aaf90a331 Mon Sep 17 00:00:00 2001 From: mmagician Date: Sat, 1 Jul 2023 21:57:27 +0200 Subject: [PATCH 055/108] fmt and remove unused imports --- src/ligero/mod.rs | 59 +++++++++++++++++++-------------------------- src/ligero/tests.rs | 2 +- src/ligero/utils.rs | 7 ++---- 3 files changed, 28 insertions(+), 40 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 9a58b6bd..b55943b4 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -11,10 +11,8 @@ use digest::Digest; use jf_primitives::pcs::transcript::IOPTranscript; use std::borrow::Borrow; -use crate::{LabeledPolynomial, PolynomialCommitment, Error, LabeledCommitment}; -use crate::{ - ligero::utils::{inner_product, reed_solomon}, -}; +use crate::ligero::utils::{inner_product, reed_solomon}; +use crate::{Error, LabeledCommitment, LabeledPolynomial, PolynomialCommitment}; use ark_std::rand::RngCore; @@ -26,7 +24,7 @@ use data_structures::*; pub use data_structures::{Ligero, LigeroPCCommitterKey, LigeroPCVerifierKey}; -use utils::{get_indices_from_transcript, calculate_t, hash_column}; +use utils::{calculate_t, get_indices_from_transcript, hash_column}; mod tests; impl @@ -136,7 +134,6 @@ where Ok(()) } fn compute_matrices(polynomial: &P) -> (Matrix, Matrix) { - let mut coeffs = polynomial.coeffs().to_vec(); // 1. Computing parameters and initial matrix @@ -172,8 +169,7 @@ where ext_mat: &Matrix, leaf_hash_params: &<::LeafHash as CRHScheme>::Parameters, two_to_one_params: &<::TwoToOneHash as TwoToOneCRHScheme>::Parameters, - ) -> MerkleTree:: - { + ) -> MerkleTree { let mut col_hashes: Vec> = Vec::new(); let ext_mat_cols = ext_mat.cols(); @@ -188,11 +184,10 @@ where mat: &Matrix, ext_mat: &Matrix, col_tree: &MerkleTree, - transcript: &mut IOPTranscript - ) -> LigeroPCProof { - + transcript: &mut IOPTranscript, + ) -> LigeroPCProof { let m = mat.m; - let t = calculate_t(rho_inv, sec_param); + let t = calculate_t(rho_inv, sec_param); // 1. Compute the linear combination using the random coefficients let v = mat.row_mul(coeffs); @@ -259,9 +254,13 @@ where num_vars: Option, rng: &mut R, ) -> Result { - assert!(rho_inv >= 1, "rho_inv is the inverse of the rate and must be at least 1"); + assert!( + rho_inv >= 1, + "rho_inv is the inverse of the rate and must be at least 1" + ); // The domain will have size m * rho_inv, but we already have the first m elements - GeneralEvaluationDomain::::compute_size_of_domain(max_degree * (rho_inv - 1)).ok_or(Error::UnsupportedDegreeBound(max_degree))?; + GeneralEvaluationDomain::::compute_size_of_domain(max_degree * (rho_inv - 1)) + .ok_or(Error::UnsupportedDegreeBound(max_degree))?; Ok(LigeroPCUniversalParams::default()) } @@ -300,11 +299,8 @@ where let (mat, ext_mat) = Self::compute_matrices(polynomial); // 2. Create the Merkle tree from the hashes of the columns - let col_tree = Self::create_merkle_tree( - &ext_mat, - &ck.leaf_hash_params, - &ck.two_to_one_params - ); + let col_tree = + Self::create_merkle_tree(&ext_mat, &ck.leaf_hash_params, &ck.two_to_one_params); // 3. Add root to transcript and generate random linear combination with it let root = col_tree.root(); @@ -321,13 +317,7 @@ where } // 4. Generate the proof by choosing random columns and proving their paths in the tree - let proof = Self::generate_proof( - &r, - &mat, - &ext_mat, - &col_tree, - &mut transcript - ); + let proof = Self::generate_proof(&r, &mat, &ext_mat, &col_tree, &mut transcript); let commitment = LigeroPCCommitment { m, root, proof }; @@ -363,11 +353,8 @@ where let (mat, ext_mat) = Self::compute_matrices(polynomial); // 2. Create the Merkle tree from the hashes of the columns - let col_tree = Self::create_merkle_tree( - &ext_mat, - &ck.leaf_hash_params, - &ck.two_to_one_params - ); + let col_tree = + Self::create_merkle_tree(&ext_mat, &ck.leaf_hash_params, &ck.two_to_one_params); // 3. Generate vector b and add v = b·M to the transcript let m = mat.m; @@ -383,7 +370,9 @@ where let mut transcript: IOPTranscript = IOPTranscript::new(b"opening_transcript"); let v = mat.row_mul(&b); - transcript.append_serializable_element(b"point", point).unwrap(); + transcript + .append_serializable_element(b"point", point) + .unwrap(); transcript.append_serializable_element(b"v", &v).unwrap(); Ok(Self::generate_proof( @@ -391,7 +380,7 @@ where &mat, &ext_mat, &col_tree, - &mut transcript + &mut transcript, )) } @@ -439,7 +428,9 @@ where transcript .append_serializable_element(b"point", point) .unwrap(); - transcript.append_serializable_element(b"v", &proof.v).unwrap(); + transcript + .append_serializable_element(b"v", &proof.v) + .unwrap(); // 3. Check the linear combination in the proof Self::check_random_linear_combination( diff --git a/src/ligero/tests.rs b/src/ligero/tests.rs index a9346dc6..5a961b8e 100644 --- a/src/ligero/tests.rs +++ b/src/ligero/tests.rs @@ -234,7 +234,7 @@ mod tests { #[test] fn test_setup() { - let mut rng = &mut test_rng(); + let rng = &mut test_rng(); let _ = LigeroPCS::<2>::setup(10, None, rng).unwrap(); // the field we use doesnt have such large domains diff --git a/src/ligero/utils.rs b/src/ligero/utils.rs index 5cb8ecc8..b9e03875 100644 --- a/src/ligero/utils.rs +++ b/src/ligero/utils.rs @@ -1,9 +1,6 @@ use ark_ff::{FftField, Field, PrimeField}; -use ark_poly::{ - domain::general::GeneralElements, univariate::DensePolynomial, DenseUVPolynomial, - EvaluationDomain, GeneralEvaluationDomain, Polynomial, -}; +use ark_poly::{EvaluationDomain, GeneralEvaluationDomain}; use ark_serialize::CanonicalSerialize; use digest::Digest; use jf_primitives::pcs::transcript::IOPTranscript; @@ -129,7 +126,7 @@ pub(crate) fn reed_solomon( // TODO if rho_inv == 2, then with a systematic encoding the second half will be the same as first - is that an issue? let domain = GeneralEvaluationDomain::::new(m * (rho_inverse - 1)).unwrap(); - let mut encoded = domain.fft(&poly_coeffs); + let encoded = domain.fft(&poly_coeffs); out.extend_from_slice(&encoded[..((rho_inverse - 1) * m)]); out } From da676d34cb37e766a861b17a4e76ebbbd73f616d Mon Sep 17 00:00:00 2001 From: mmagician Date: Sat, 1 Jul 2023 22:03:17 +0200 Subject: [PATCH 056/108] Apply suggestions from (self) code review --- src/ligero/tests.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/ligero/tests.rs b/src/ligero/tests.rs index 5a961b8e..716a6e57 100644 --- a/src/ligero/tests.rs +++ b/src/ligero/tests.rs @@ -127,9 +127,6 @@ mod tests { #[test] fn test_reed_solomon() { // we use this polynomial to generate the the values we will ask the fft to interpolate - // let pol_evals: Vec = to_field(vec![30, 2, 91, 4, 8]); - // TODO try for different values of m - // for i in 0..16 let rho_inv = 3; // `i` is the min number of evaluations we need to interpolate a poly of degree `i - 1` @@ -165,7 +162,6 @@ mod tests { // The rest of the elements should agree with the domain for j in 0..((rho_inv - 1) * m) { - println!("j: {:?}", j); assert_eq!(pol.evaluate(&large_domain.element(j)), encoded[j + m]); } } From 62071b30e663511e216bb290f574812a49b82721 Mon Sep 17 00:00:00 2001 From: mmagician Date: Sat, 1 Jul 2023 22:30:38 +0200 Subject: [PATCH 057/108] Swap the test field for one with large FFT domain and add an extra test for a small-FFT-domain-field --- src/ligero/tests.rs | 67 ++++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 31 deletions(-) diff --git a/src/ligero/tests.rs b/src/ligero/tests.rs index 716a6e57..325c4956 100644 --- a/src/ligero/tests.rs +++ b/src/ligero/tests.rs @@ -1,7 +1,7 @@ #[cfg(test)] mod tests { - use ark_bls12_381::Fq as F; + use ark_bls12_377::Fq; use ark_ff::PrimeField; use ark_poly::{ domain::general::GeneralEvaluationDomain, univariate::DensePolynomial, DenseUVPolynomial, @@ -23,7 +23,7 @@ mod tests { sponge::poseidon::PoseidonSponge, }; - type UniPoly = DensePolynomial; + type UniPoly = DensePolynomial; #[derive(Clone)] pub(super) struct Window4x256; impl pedersen::Window for Window4x256 { @@ -49,46 +49,48 @@ mod tests { } type MTConfig = MerkleTreeParams; - type Sponge = PoseidonSponge; + type Sponge = PoseidonSponge; type PC = Ligero; - type LigeroPCS = PC; + type LigeroPCS = PC; + type LigeroPCS_F = + PC, rho_inv>; #[test] fn test_matrix_constructor_flat() { - let entries: Vec = to_field(vec![10, 100, 4, 67, 44, 50]); + let entries: Vec = to_field(vec![10, 100, 4, 67, 44, 50]); let mat = Matrix::new_from_flat(2, 3, &entries); - assert_eq!(mat.entry(1, 2), F::from(50)); + assert_eq!(mat.entry(1, 2), Fq::from(50)); } #[test] fn test_matrix_constructor_flat_square() { - let entries: Vec = to_field(vec![10, 100, 4, 67]); + let entries: Vec = to_field(vec![10, 100, 4, 67]); let mat = Matrix::new_from_flat(2, 2, &entries); - assert_eq!(mat.entry(1, 1), F::from(67)); + assert_eq!(mat.entry(1, 1), Fq::from(67)); } #[test] #[should_panic] fn test_matrix_constructor_flat_panic() { - let entries: Vec = to_field(vec![10, 100, 4, 67, 44]); + let entries: Vec = to_field(vec![10, 100, 4, 67, 44]); Matrix::new_from_flat(2, 3, &entries); } #[test] fn test_matrix_constructor_rows() { - let rows: Vec> = vec![ + let rows: Vec> = vec![ to_field(vec![10, 100, 4]), to_field(vec![23, 1, 0]), to_field(vec![55, 58, 9]), ]; let mat = Matrix::new_from_rows(rows); - assert_eq!(mat.entry(2, 0), F::from(55)); + assert_eq!(mat.entry(2, 0), Fq::from(55)); } #[test] #[should_panic] fn test_matrix_constructor_rows_panic() { - let rows: Vec> = vec![ + let rows: Vec> = vec![ to_field(vec![10, 100, 4]), to_field(vec![23, 1, 0]), to_field(vec![55, 58]), @@ -98,7 +100,7 @@ mod tests { #[test] fn test_cols() { - let rows: Vec> = vec![ + let rows: Vec> = vec![ to_field(vec![4, 76]), to_field(vec![14, 92]), to_field(vec![17, 89]), @@ -111,17 +113,17 @@ mod tests { #[test] fn test_row_mul() { - let rows: Vec> = vec![ + let rows: Vec> = vec![ to_field(vec![10, 100, 4]), to_field(vec![23, 1, 0]), to_field(vec![55, 58, 9]), ]; let mat = Matrix::new_from_rows(rows); - let v: Vec = to_field(vec![12, 41, 55]); - // by giving the result in the integers and then converting to F - // we ensure the test will still pass even if F changes - assert_eq!(mat.row_mul(&v), to_field::(vec![4088, 4431, 543])); + let v: Vec = to_field(vec![12, 41, 55]); + // by giving the result in the integers and then converting to Fq + // we ensure the test will still pass even if Fq changes + assert_eq!(mat.row_mul(&v), to_field::(vec![4088, 4431, 543])); } #[test] @@ -132,7 +134,7 @@ mod tests { // `i` is the min number of evaluations we need to interpolate a poly of degree `i - 1` for i in 1..10 { let rand_chacha = &mut ChaCha20Rng::from_rng(test_rng()).unwrap(); - let pol = rand_poly::(i - 1, None, rand_chacha); + let pol = rand_poly::(i - 1, None, rand_chacha); let coeffs = &pol.coeffs; assert_eq!( @@ -142,7 +144,7 @@ mod tests { ); assert_eq!(coeffs.len(), i, "length of coeffs and m mismatch"); - let small_domain = GeneralEvaluationDomain::::new(i).unwrap(); + let small_domain = GeneralEvaluationDomain::::new(i).unwrap(); // size of evals might be larger than i (the min. number of evals needed to interpolate): we could still do R-S encoding on smaller evals, but the resulting polynomial will differ, so for this test to work we should pass it in full let evals = small_domain.fft(&coeffs); @@ -158,7 +160,7 @@ mod tests { // first elements of encoded should be itself, since the code is systematic assert_eq!(encoded[..m], evals); - let large_domain = GeneralEvaluationDomain::::new(m * (rho_inv - 1)).unwrap(); + let large_domain = GeneralEvaluationDomain::::new(m * (rho_inv - 1)).unwrap(); // The rest of the elements should agree with the domain for j in 0..((rho_inv - 1) * m) { @@ -173,7 +175,7 @@ mod tests { let rho = 2; for m in 1..10 { // rand poly of degree m - let domain = GeneralEvaluationDomain::::new(m).unwrap(); + let domain = GeneralEvaluationDomain::::new(m).unwrap(); let poly = UniPoly::rand(m - 1, &mut test_rng()); // get its evaluations at the entire domain let evals = (0..domain.size()) @@ -188,7 +190,7 @@ mod tests { assert_eq!(evals[..m], evals2[..m]); // now we try with a larger domain - let large_domain = GeneralEvaluationDomain::::new(m * rho).unwrap(); + let large_domain = GeneralEvaluationDomain::::new(m * rho).unwrap(); let evals3 = large_domain.fft(&coeffs.to_vec()); let evals4: Vec<_> = (0..large_domain.size()) @@ -212,29 +214,32 @@ mod tests { assert_eq!(get_num_bytes(1 << 32 + 1), 5); } - fn rand_poly( + fn rand_poly( degree: usize, _: Option, rng: &mut ChaCha20Rng, - ) -> DensePolynomial { + ) -> DensePolynomial { DensePolynomial::rand(degree, rng) } - fn constant_poly( + fn constant_poly( _: usize, _: Option, rng: &mut ChaCha20Rng, - ) -> DensePolynomial { - DensePolynomial::from_coefficients_slice(&[F::rand(rng)]) + ) -> DensePolynomial { + DensePolynomial::from_coefficients_slice(&[Fq::rand(rng)]) } #[test] fn test_setup() { let rng = &mut test_rng(); - let _ = LigeroPCS::<2>::setup(10, None, rng).unwrap(); + let _ = LigeroPCS::<2>::setup(1 << 44, None, rng).unwrap(); - // the field we use doesnt have such large domains - assert_eq!(LigeroPCS::<5>::setup(10, None, rng).is_err(), true); + assert_eq!(LigeroPCS::<5>::setup(1 << 45, None, rng).is_err(), true); + + // but the base field of bls12_381 doesnt have such large domains + use ark_bls12_381::Fq as F_381; + assert_eq!(LigeroPCS_F::<5, F_381>::setup(10, None, rng).is_err(), true); } #[test] From 43d7fbb8ae860aeeab62f4e51653cea4beccf3cf Mon Sep 17 00:00:00 2001 From: mmagician Date: Mon, 3 Jul 2023 09:57:00 +0200 Subject: [PATCH 058/108] Pad the leaves with zeros to create MT --- src/ligero/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index b55943b4..4d4f0099 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -177,6 +177,10 @@ where col_hashes.push(hash_column::(col).into()); } + // pad the column hashes with zeroes + let next_pow_of_two = col_hashes.len().next_power_of_two(); + col_hashes.resize(next_pow_of_two, vec![0; ::output_size()]); + MerkleTree::::new(leaf_hash_params, two_to_one_params, col_hashes).unwrap() } fn generate_proof( From 136a639d9bcc44deaae03aad4e9ab357291780bf Mon Sep 17 00:00:00 2001 From: mmagician Date: Mon, 3 Jul 2023 09:57:12 +0200 Subject: [PATCH 059/108] test MT creation and proof verification --- src/ligero/tests.rs | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/ligero/tests.rs b/src/ligero/tests.rs index 325c4956..b929c81a 100644 --- a/src/ligero/tests.rs +++ b/src/ligero/tests.rs @@ -203,6 +203,40 @@ mod tests { } } + #[test] + fn test_merkle_tree() { + let mut rng = &mut test_rng(); + let leaf_hash_params = ::setup(&mut rng).unwrap(); + let two_to_one_params = ::setup(&mut rng) + .unwrap() + .clone(); + + let rows: Vec> = vec![ + to_field(vec![4, 76]), + to_field(vec![14, 92]), + to_field(vec![17, 89]), + ]; + + let mat = Matrix::new_from_rows(rows); + let mt = LigeroPCS::<2>::create_merkle_tree(&mat, &leaf_hash_params, &two_to_one_params); + + let root = mt.root(); + + for (i, col) in mat.cols().iter().enumerate() { + let col_hash = hash_column::(col); + + let proof = mt.generate_proof(i).unwrap(); + assert!(proof + .verify( + &leaf_hash_params, + &two_to_one_params, + &root, + col_hash.clone() + ) + .unwrap()); + } + } + #[test] fn test_get_num_bytes() { assert_eq!(get_num_bytes(0), 0); From b8ca9c8b3a31fd9b9a88fe450a5e504207ad66a1 Mon Sep 17 00:00:00 2001 From: mmagician Date: Mon, 3 Jul 2023 10:08:36 +0200 Subject: [PATCH 060/108] Test open & check methods --- src/ligero/tests.rs | 69 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 58 insertions(+), 11 deletions(-) diff --git a/src/ligero/tests.rs b/src/ligero/tests.rs index b929c81a..765ae849 100644 --- a/src/ligero/tests.rs +++ b/src/ligero/tests.rs @@ -1,27 +1,30 @@ #[cfg(test)] mod tests { - use ark_bls12_377::Fq; - use ark_ff::PrimeField; - use ark_poly::{ - domain::general::GeneralEvaluationDomain, univariate::DensePolynomial, DenseUVPolynomial, - EvaluationDomain, Polynomial, - }; - use ark_std::test_rng; - use blake2::Blake2s256; - use rand_chacha::{rand_core::SeedableRng, ChaCha20Rng}; - + use crate::ark_std::UniformRand; use crate::{ + challenge::ChallengeGenerator, ligero::{ utils::*, Ligero, LigeroPCCommitterKey, LigeroPCVerifierKey, PolynomialCommitment, }, LabeledPolynomial, }; + use ark_bls12_377::Fq; + use ark_crypto_primitives::sponge::poseidon::PoseidonConfig; + use ark_crypto_primitives::sponge::CryptographicSponge; use ark_crypto_primitives::{ crh::{pedersen, sha256::Sha256, CRHScheme, TwoToOneCRHScheme}, merkle_tree::{ByteDigestConverter, Config}, sponge::poseidon::PoseidonSponge, }; + use ark_ff::PrimeField; + use ark_poly::{ + domain::general::GeneralEvaluationDomain, univariate::DensePolynomial, DenseUVPolynomial, + EvaluationDomain, Polynomial, + }; + use ark_std::test_rng; + use blake2::Blake2s256; + use rand_chacha::{rand_core::SeedableRng, ChaCha20Rng}; type UniPoly = DensePolynomial; #[derive(Clone)] @@ -264,6 +267,33 @@ mod tests { DensePolynomial::from_coefficients_slice(&[Fq::rand(rng)]) } + // TODO: replace by https://github.com/arkworks-rs/crypto-primitives/issues/112. + fn test_sponge() -> PoseidonSponge { + let full_rounds = 8; + let partial_rounds = 31; + let alpha = 17; + + let mds = vec![ + vec![F::one(), F::zero(), F::one()], + vec![F::one(), F::one(), F::zero()], + vec![F::zero(), F::one(), F::one()], + ]; + + let mut v = Vec::new(); + let mut ark_rng = test_rng(); + + for _ in 0..(full_rounds + partial_rounds) { + let mut res = Vec::new(); + + for _ in 0..3 { + res.push(F::rand(&mut ark_rng)); + } + v.push(res); + } + let config = PoseidonConfig::new(full_rounds, partial_rounds, alpha, mds, v, 2, 1); + PoseidonSponge::new(&config) + } + #[test] fn test_setup() { let rng = &mut test_rng(); @@ -304,6 +334,23 @@ mod tests { None, ); - let c = LigeroPCS::<2>::commit(&ck, &[labeled_poly], None).unwrap(); + let mut test_sponge = test_sponge::(); + let (c, rands) = LigeroPCS::<2>::commit(&ck, &[labeled_poly.clone()], None).unwrap(); + + let point = Fq::rand(rand_chacha); + + let mut challenge_generator: ChallengeGenerator> = + ChallengeGenerator::new_univariate(&mut test_sponge); + + let proof = LigeroPCS::<2>::open( + &ck, + &[labeled_poly], + &c, + &point, + &mut challenge_generator, + &rands, + None, + ) + .unwrap(); } } From a6db789ba963ddd9c43054af1a716cbc5285ba7c Mon Sep 17 00:00:00 2001 From: mmagician Date: Mon, 3 Jul 2023 12:08:40 +0200 Subject: [PATCH 061/108] test well formedness and verifier's check --- src/ligero/tests.rs | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/ligero/tests.rs b/src/ligero/tests.rs index 765ae849..9b17a12a 100644 --- a/src/ligero/tests.rs +++ b/src/ligero/tests.rs @@ -339,18 +339,40 @@ mod tests { let point = Fq::rand(rand_chacha); + let value = labeled_poly.evaluate(&point); + let mut challenge_generator: ChallengeGenerator> = ChallengeGenerator::new_univariate(&mut test_sponge); + assert!( + LigeroPCS::<2>::check_well_formedness( + &c[0].commitment(), + &leaf_hash_params, + &two_to_one_params + ) + .is_ok(), + "Well formedness check failed" + ); + let proof = LigeroPCS::<2>::open( &ck, &[labeled_poly], &c, &point, - &mut challenge_generator, + &mut (challenge_generator.clone()), &rands, None, ) .unwrap(); + assert!(LigeroPCS::<2>::check( + &vk, + &c, + &point, + [value], + &proof, + &mut challenge_generator, + None + ) + .unwrap()); } } From 9c91d727e5d1cb35e8336cf6281cf51838f243af Mon Sep 17 00:00:00 2001 From: mmagician Date: Mon, 3 Jul 2023 12:09:27 +0200 Subject: [PATCH 062/108] bug fix: length of r should be m, not t --- src/ligero/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 4d4f0099..9db9f660 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -67,7 +67,7 @@ where // 2. Get the linear combination coefficients from the transcript let mut r = Vec::new(); - for _ in 0..t { + for _ in 0..commitment.m { r.push(transcript.get_and_append_challenge(b"r").unwrap()); } // Upon sending `v` to the Verifier, add it to the sponge. Claim is that v = r.M From 27320ec3bb36c82c63f07c01e7c6559d08d97ba9 Mon Sep 17 00:00:00 2001 From: mmagician Date: Mon, 3 Jul 2023 12:12:27 +0200 Subject: [PATCH 063/108] Fix the Path checking: index into paths by loop index, not q_i --- src/ligero/mod.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 9db9f660..dc46740a 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -103,10 +103,15 @@ where let indices = get_indices_from_transcript::(num_encoded_rows, t, transcript); // 3. Verify the paths for each of the leaf hashes - for (leaf, i) in col_hashes.into_iter().zip(indices.iter()) { + for (i, (leaf, q_i)) in col_hashes.into_iter().zip(indices.iter()).enumerate() { // TODO handle the error here - let path = &commitment.proof.paths[*i]; - assert!(path.leaf_index == *i, "Path is for a different index!"); // TODO return an error + let path = &commitment.proof.paths[i]; + assert!( + path.leaf_index == *q_i, + "Path is for a different index: i: {}, leaf index: {}!", + q_i, + path.leaf_index + ); // TODO return an error path.verify( leaf_hash_params, From 16ecc28371f34204e65ba72cfbb89f96355a8132 Mon Sep 17 00:00:00 2001 From: mmagician Date: Mon, 3 Jul 2023 12:26:28 +0200 Subject: [PATCH 064/108] fix the transcript consistency between prover and verifier --- src/ligero/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index dc46740a..a3cf7691 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -382,7 +382,6 @@ where transcript .append_serializable_element(b"point", point) .unwrap(); - transcript.append_serializable_element(b"v", &v).unwrap(); Ok(Self::generate_proof( &b, From d8d71329b0eb5e5b5e7ff74b26eaed092ffa7c75 Mon Sep 17 00:00:00 2001 From: mmagician Date: Mon, 3 Jul 2023 12:34:57 +0200 Subject: [PATCH 065/108] refactor `check_linear_combinations` to take proof, m & root, not comm --- src/ligero/mod.rs | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index a3cf7691..542633eb 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -77,16 +77,21 @@ where Self::check_random_linear_combination( &r, - commitment, + &commitment.proof, + &commitment.root, + commitment.m, t, &mut transcript, leaf_hash_params, two_to_one_params, ) } + fn check_random_linear_combination( coeffs: &[F], - commitment: &LigeroPCCommitment, + proof: &LigeroPCProof, + root: &C::InnerDigest, + m: usize, t: usize, transcript: &mut IOPTranscript, leaf_hash_params: &<::LeafHash as CRHScheme>::Parameters, @@ -94,18 +99,18 @@ where ) -> Result<(), Error> { // 1. Hash the received columns into leaf hashes let mut col_hashes: Vec> = Vec::new(); - for c in commitment.proof.columns.iter() { + for c in proof.columns.iter() { col_hashes.push(hash_column::(c).into()); } // 2. Compute t column indices to check the linear combination at - let num_encoded_rows = commitment.m * rho_inv; + let num_encoded_rows = m * rho_inv; let indices = get_indices_from_transcript::(num_encoded_rows, t, transcript); // 3. Verify the paths for each of the leaf hashes for (i, (leaf, q_i)) in col_hashes.into_iter().zip(indices.iter()).enumerate() { // TODO handle the error here - let path = &commitment.proof.paths[i]; + let path = &proof.paths[i]; assert!( path.leaf_index == *q_i, "Path is for a different index: i: {}, leaf index: {}!", @@ -113,22 +118,16 @@ where path.leaf_index ); // TODO return an error - path.verify( - leaf_hash_params, - two_to_one_params, - &commitment.root, - leaf.clone(), - ) - .unwrap(); + path.verify(leaf_hash_params, two_to_one_params, root, leaf.clone()) + .unwrap(); } // 4. Compute the encoding w = E(v) - let w = reed_solomon(&commitment.proof.v, rho_inv); + let w = reed_solomon(&proof.v, rho_inv); // 5. Verify the random linear combinations for (transcript_index, matrix_index) in indices.into_iter().enumerate() { - if inner_product(coeffs, &commitment.proof.columns[transcript_index]) != w[matrix_index] - { + if inner_product(coeffs, &proof.columns[transcript_index]) != w[matrix_index] { // TODO return proper error return Err(Error::IncorrectInputLength( "Incorrect linear combination".to_string(), @@ -443,7 +442,9 @@ where // 3. Check the linear combination in the proof Self::check_random_linear_combination( &b, - commitment, + proof, + &commitment.root, + m, t, &mut transcript, &vk.leaf_hash_params, From 99fa3a76971ee939a5c46e09ef92dbaf33143cfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mej=C3=ADas=20Gil?= Date: Mon, 3 Jul 2023 14:43:28 +0200 Subject: [PATCH 066/108] reed solomon function and test working --- .vscode/launch.json | 16 ++++++++ src/ligero/data_structures.rs | 7 ++-- src/ligero/tests.rs | 76 +++++++++++------------------------ src/ligero/utils.rs | 30 +++++++++----- 4 files changed, 61 insertions(+), 68 deletions(-) create mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..10efcb2f --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,16 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "lldb", + "request": "launch", + "name": "Debug", + "program": "${workspaceFolder}/", + "args": [], + "cwd": "${workspaceFolder}" + } + ] +} \ No newline at end of file diff --git a/src/ligero/data_structures.rs b/src/ligero/data_structures.rs index c82823f6..8775ebb3 100644 --- a/src/ligero/data_structures.rs +++ b/src/ligero/data_structures.rs @@ -11,13 +11,12 @@ use core::marker::PhantomData; use digest::Digest; use crate::{ - PCCommitment, PCCommitterKey, PCPreparedCommitment, - PCPreparedVerifierKey, PCRandomness, PCUniversalParams, PCVerifierKey, + PCCommitment, PCCommitterKey, PCPreparedCommitment, PCPreparedVerifierKey, PCRandomness, + PCUniversalParams, PCVerifierKey, }; use ark_std::rand::RngCore; - // TODO: Disclaimer: no hiding prop /// The Ligero polynomial commitment scheme. pub struct Ligero< @@ -181,4 +180,4 @@ where pub(crate) v: Vec, pub(crate) columns: Vec>, -} \ No newline at end of file +} diff --git a/src/ligero/tests.rs b/src/ligero/tests.rs index 9b17a12a..dcb711dc 100644 --- a/src/ligero/tests.rs +++ b/src/ligero/tests.rs @@ -135,77 +135,47 @@ mod tests { let rho_inv = 3; // `i` is the min number of evaluations we need to interpolate a poly of degree `i - 1` - for i in 1..10 { + for i in 2..10 { + let deg = (1 << i) - 1; + let rand_chacha = &mut ChaCha20Rng::from_rng(test_rng()).unwrap(); - let pol = rand_poly::(i - 1, None, rand_chacha); + let mut pol = rand_poly::(deg, None, rand_chacha); + + while pol.degree() != deg { + pol = rand_poly::(deg, None, rand_chacha); + } let coeffs = &pol.coeffs; - assert_eq!( - pol.degree(), - coeffs.len() - 1, - "degree of poly and coeffs mismatch" - ); - assert_eq!(coeffs.len(), i, "length of coeffs and m mismatch"); - let small_domain = GeneralEvaluationDomain::::new(i).unwrap(); + let small_domain = GeneralEvaluationDomain::::new(deg + 1).unwrap(); - // size of evals might be larger than i (the min. number of evals needed to interpolate): we could still do R-S encoding on smaller evals, but the resulting polynomial will differ, so for this test to work we should pass it in full + // size of evals might be larger than deg + 1 (the min. number of evals needed to interpolate): we could still do R-S encoding on smaller evals, but the resulting polynomial will differ, so for this test to work we should pass it in full let evals = small_domain.fft(&coeffs); let m = evals.len(); + // checking that ifft is really the inverse of fft let coeffs_again = small_domain.ifft(&evals); - assert_eq!(coeffs_again[..i], *coeffs); + + assert_eq!(coeffs_again[..deg + 1], *coeffs); let encoded = reed_solomon(&evals, rho_inv); - // Assert that the encoded vector is of the right length - assert_eq!(encoded.len(), rho_inv * m); + let m_p = encoded.len(); - // first elements of encoded should be itself, since the code is systematic - assert_eq!(encoded[..m], evals); + // the m original elements should be interleaved in the encoded message + let ratio = m_p / m; + for j in 0..m { + assert_eq!(evals[j], encoded[j * ratio]); + } - let large_domain = GeneralEvaluationDomain::::new(m * (rho_inv - 1)).unwrap(); + let large_domain = GeneralEvaluationDomain::::new(m * rho_inv).unwrap(); - // The rest of the elements should agree with the domain - for j in 0..((rho_inv - 1) * m) { - assert_eq!(pol.evaluate(&large_domain.element(j)), encoded[j + m]); + // the encoded elements should agree with the evaluations of the polynomial in the larger domain + for j in 0..(rho_inv * m) { + assert_eq!(pol.evaluate(&large_domain.element(j)), encoded[j]); } } } - #[test] - fn test_fft_interface() { - // This test is probably too verbose, and should be merged with the RS test - let rho = 2; - for m in 1..10 { - // rand poly of degree m - let domain = GeneralEvaluationDomain::::new(m).unwrap(); - let poly = UniPoly::rand(m - 1, &mut test_rng()); - // get its evaluations at the entire domain - let evals = (0..domain.size()) - .map(|i| poly.evaluate(&domain.element(i))) - .collect::>(); - - // convert back to the coefficients - let coeffs = domain.ifft(&evals); - assert_eq!(coeffs[..m], poly.coeffs); - - let evals2 = domain.fft(&coeffs.to_vec()); - assert_eq!(evals[..m], evals2[..m]); - - // now we try with a larger domain - let large_domain = GeneralEvaluationDomain::::new(m * rho).unwrap(); - - let evals3 = large_domain.fft(&coeffs.to_vec()); - let evals4: Vec<_> = (0..large_domain.size()) - .map(|i| poly.evaluate(&large_domain.element(i))) - .collect::>(); - - assert_eq!(evals3[..m], evals4[..m]); - - let coeffs2 = large_domain.ifft(&evals3); - } - } - #[test] fn test_merkle_tree() { let mut rng = &mut test_rng(); diff --git a/src/ligero/utils.rs b/src/ligero/utils.rs index b9e03875..69b6c00a 100644 --- a/src/ligero/utils.rs +++ b/src/ligero/utils.rs @@ -110,25 +110,33 @@ impl Matrix { } } -// TODO batch for all rows? possibly minimal savings due to not having to create fft_domain every time -// here we restrict F to PrimeField +/// apply reed-solomon encoding to msg +/// assumes msg.len() is equal to the order of an FFT domain in F +/// returns a vector of length equal to the smallest FFT domain of size at least msg.len() * rho_inv pub(crate) fn reed_solomon( // msg, of length m, is interpreted as a vector of coefficients of a polynomial of degree m - 1 msg: &[F], - rho_inverse: usize, + rho_inv: usize, ) -> Vec { let m = msg.len(); let domain = GeneralEvaluationDomain::::new(m).unwrap(); + assert_eq!( + m, + domain.size(), + "The evaluation vector has length {} elements \\ + but the smallest FFT domain admitting that many elements has order {}", + m, + domain.size() + ); let poly_coeffs = domain.ifft(msg).to_vec(); - let mut out = msg.to_vec(); - assert!(out.len() == m); - - // TODO if rho_inv == 2, then with a systematic encoding the second half will be the same as first - is that an issue? - let domain = GeneralEvaluationDomain::::new(m * (rho_inverse - 1)).unwrap(); - let encoded = domain.fft(&poly_coeffs); - out.extend_from_slice(&encoded[..((rho_inverse - 1) * m)]); - out + + let extended_domain = GeneralEvaluationDomain::::new(m * rho_inv).expect(&format!( + "The field F cannot accomodate FFT for msg.len() * rho_inv = {} elements (too many)", + m * rho_inv + )); + + extended_domain.fft(&poly_coeffs) } #[inline] From e74a5225853faf3fe940ae64e2506b93c383691f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mej=C3=ADas=20Gil?= Date: Mon, 3 Jul 2023 15:07:49 +0200 Subject: [PATCH 067/108] changed test bound --- src/ligero/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ligero/tests.rs b/src/ligero/tests.rs index dcb711dc..56afa7c7 100644 --- a/src/ligero/tests.rs +++ b/src/ligero/tests.rs @@ -135,7 +135,7 @@ mod tests { let rho_inv = 3; // `i` is the min number of evaluations we need to interpolate a poly of degree `i - 1` - for i in 2..10 { + for i in 1..10 { let deg = (1 << i) - 1; let rand_chacha = &mut ChaCha20Rng::from_rng(test_rng()).unwrap(); From e31deb4bf7aff84563cab7b830e9f94213da7fe9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mej=C3=ADas=20Gil?= Date: Mon, 3 Jul 2023 15:24:25 +0200 Subject: [PATCH 068/108] .vscode/* deleted and added to gitignore --- .gitignore | 3 ++- .vscode/launch.json | 16 ---------------- 2 files changed, 2 insertions(+), 17 deletions(-) delete mode 100644 .vscode/launch.json diff --git a/.gitignore b/.gitignore index 547bf087..5b91bc3c 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ Cargo.lock *.ipynb_checkpoints *.pyc *.sage.py -params \ No newline at end of file +params +.vscode/* \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 10efcb2f..00000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "type": "lldb", - "request": "launch", - "name": "Debug", - "program": "${workspaceFolder}/", - "args": [], - "cwd": "${workspaceFolder}" - } - ] -} \ No newline at end of file From 0bd313acbc144d66100acd45a78892e8744b1d14 Mon Sep 17 00:00:00 2001 From: mmagician Date: Mon, 3 Jul 2023 15:29:14 +0200 Subject: [PATCH 069/108] Update .gitignore --- .gitignore | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 5b91bc3c..547bf087 100644 --- a/.gitignore +++ b/.gitignore @@ -6,5 +6,4 @@ Cargo.lock *.ipynb_checkpoints *.pyc *.sage.py -params -.vscode/* \ No newline at end of file +params \ No newline at end of file From f510f549fb57624364c5d23b745db586e1dddd4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mej=C3=ADas=20Gil?= Date: Tue, 4 Jul 2023 09:34:23 +0200 Subject: [PATCH 070/108] adapted to new RS, now leaf index check failing --- src/ligero/data_structures.rs | 7 +-- src/ligero/mod.rs | 80 ++++++++++++++++++++--------------- src/ligero/utils.rs | 26 +++++++++--- 3 files changed, 70 insertions(+), 43 deletions(-) diff --git a/src/ligero/data_structures.rs b/src/ligero/data_structures.rs index 8775ebb3..4503e06e 100644 --- a/src/ligero/data_structures.rs +++ b/src/ligero/data_structures.rs @@ -123,9 +123,10 @@ impl PCPreparedVerifierKey for LigeroPCPr #[derive(Derivative, CanonicalSerialize, CanonicalDeserialize)] #[derivative(Default(bound = ""), Clone(bound = ""), Debug(bound = ""))] pub struct LigeroPCCommitment { - // number of rows of the square matrix containing the coefficients of the polynomial - pub(crate) m: usize, - // TODO is InnerDigest the right type? + // number of rows resp. columns of the square matrix containing the coefficients of the polynomial + pub(crate) n_rows: usize, + pub(crate) n_cols: usize, + pub(crate) n_ext_cols: usize, pub(crate) root: C::InnerDigest, pub(crate) proof: LigeroPCProof, } diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 542633eb..36ad47f9 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -25,6 +25,8 @@ use data_structures::*; pub use data_structures::{Ligero, LigeroPCCommitterKey, LigeroPCVerifierKey}; use utils::{calculate_t, get_indices_from_transcript, hash_column}; + +use self::utils::compute_dimensions; mod tests; impl @@ -67,7 +69,7 @@ where // 2. Get the linear combination coefficients from the transcript let mut r = Vec::new(); - for _ in 0..commitment.m { + for _ in 0..commitment.n_rows { r.push(transcript.get_and_append_challenge(b"r").unwrap()); } // Upon sending `v` to the Verifier, add it to the sponge. Claim is that v = r.M @@ -75,11 +77,12 @@ where .append_serializable_element(b"v", &commitment.proof.v) .unwrap(); + println!("* Calling check lc from check well formedness"); Self::check_random_linear_combination( &r, &commitment.proof, &commitment.root, - commitment.m, + commitment.n_ext_cols, t, &mut transcript, leaf_hash_params, @@ -91,7 +94,7 @@ where coeffs: &[F], proof: &LigeroPCProof, root: &C::InnerDigest, - m: usize, + n_ext_cols: usize, t: usize, transcript: &mut IOPTranscript, leaf_hash_params: &<::LeafHash as CRHScheme>::Parameters, @@ -104,10 +107,12 @@ where } // 2. Compute t column indices to check the linear combination at - let num_encoded_rows = m * rho_inv; - let indices = get_indices_from_transcript::(num_encoded_rows, t, transcript); + let indices = get_indices_from_transcript::(n_ext_cols, t, transcript); // 3. Verify the paths for each of the leaf hashes + println!("INDICES: {:?}", indices); + println!("LEAF INDICES: {:?}", proof.paths.iter().map(|p| p.leaf_index).collect::>()); + for (i, (leaf, q_i)) in col_hashes.into_iter().zip(indices.iter()).enumerate() { // TODO handle the error here let path = &proof.paths[i]; @@ -141,23 +146,13 @@ where let mut coeffs = polynomial.coeffs().to_vec(); // 1. Computing parameters and initial matrix - // want: ceil(sqrt(f.degree() + 1)); need to deal with usize -> f64 conversion - let num_elems = polynomial.degree() + 1; - - // TODO move this check to the constructor? - assert_eq!( - (num_elems as f64) as usize, - num_elems, - "Degree of polynomial + 1 cannot be converted to f64: aborting" - ); - let m = (num_elems as f64).sqrt().ceil() as usize; - // TODO: check if fft_domain.compute_size_of_domain(m) is large enough + let (n_rows, n_cols) = compute_dimensions::(polynomial.degree() + 1); // padding the coefficient vector with zeroes // TODO is this the most efficient/safest way to do it? - coeffs.resize(m * m, F::zero()); + coeffs.resize(n_rows * n_cols, F::zero()); - let mat = Matrix::new_from_flat(m, m, &coeffs); + let mat = Matrix::new_from_flat(n_rows, n_cols, &coeffs); // 2. Apply Reed-Solomon encoding row-wise let ext_mat = Matrix::new_from_rows( @@ -194,8 +189,8 @@ where col_tree: &MerkleTree, transcript: &mut IOPTranscript, ) -> LigeroPCProof { - let m = mat.m; - let t = calculate_t(rho_inv, sec_param); + let n_rows = mat.n; + let t = calculate_t(rho_inv, sec_param); // TODO this function will now probably need to take into account the number of rows/cols of the extended matrix // 1. Compute the linear combination using the random coefficients let v = mat.row_mul(coeffs); @@ -203,7 +198,8 @@ where transcript.append_serializable_element(b"v", &v).unwrap(); // 2. Generate t column indices to test the linear combination on - let indices = get_indices_from_transcript(m * rho_inv, t, transcript); + let indices = get_indices_from_transcript(ext_mat.m, t, transcript); + println!("INDICES T IN GENERATE_PROOF: {:?}", indices); // 3. Compute Merkle tree paths for the columns let mut queried_columns = Vec::new(); @@ -318,16 +314,20 @@ where .append_serializable_element(b"root", &root) .unwrap(); - let m = mat.m; + let n_rows = mat.n; + let n_cols = mat.m; + let n_ext_cols = ext_mat.m; + let mut r = Vec::new(); - for _ in 0..m { + for _ in 0..n_rows { r.push(transcript.get_and_append_challenge(b"r").unwrap()); } // 4. Generate the proof by choosing random columns and proving their paths in the tree + println!("* Calling generate proof from commit"); let proof = Self::generate_proof(&r, &mat, &ext_mat, &col_tree, &mut transcript); - let commitment = LigeroPCCommitment { m, root, proof }; + let commitment = LigeroPCCommitment { n_rows, n_cols, n_ext_cols, root, proof }; Ok(( vec![LabeledCommitment::new( @@ -357,6 +357,9 @@ where let labeled_polynomial = labeled_polynomials.into_iter().next().unwrap(); let polynomial = labeled_polynomial.polynomial(); + // TODO we receive a list of polynomials and a list of commitments + // are we to understand that the first commitment is for the first polynomial, ...etc? + // 1. Compute matrices let (mat, ext_mat) = Self::compute_matrices(polynomial); @@ -365,14 +368,14 @@ where Self::create_merkle_tree(&ext_mat, &ck.leaf_hash_params, &ck.two_to_one_params); // 3. Generate vector b and add v = b·M to the transcript - let m = mat.m; + let commitment = commitments.into_iter().next().unwrap().commitment(); let mut b = Vec::new(); - let point_pow_m = point.pow([m as u64]); + let point_pow = point.pow([commitment.n_cols as u64]); // TODO this and other conversions could potentially fail let mut acc_b = F::one(); - for _ in 0..m { + for _ in 0..commitment.n_rows { b.push(acc_b); - acc_b *= point_pow_m; + acc_b *= point_pow; } let mut transcript: IOPTranscript = IOPTranscript::new(b"opening_transcript"); @@ -382,6 +385,7 @@ where .append_serializable_element(b"point", point) .unwrap(); + println!("* Calling generate proof from open"); Ok(Self::generate_proof( &b, &mat, @@ -406,45 +410,53 @@ where let labeled_commitment = commitments.into_iter().next().unwrap(); let commitment = labeled_commitment.commitment(); - let m = commitment.m; let t = calculate_t(rho_inv, sec_param); + // TODO maybe check that the parameters have been calculated honestly (n_rows/cols/ext_cols); + // could they be used to cheat? + // check if we've seen this commitment before. If not, we should verify it. Self::check_well_formedness(commitment, &vk.leaf_hash_params, &vk.two_to_one_params) .unwrap(); + let point = F::from(2u64); + // 1. Compute a and b let mut a = Vec::new(); let mut acc_a = F::one(); - for _ in 0..m { + for _ in 0..commitment.n_cols { a.push(acc_a); acc_a *= point; } - // by now acc_a = point^m + // by now acc_a = point^n_cols let mut b = Vec::new(); let mut acc_b = F::one(); - for _ in 0..m { + for _ in 0..commitment.n_rows { b.push(acc_b); acc_b *= acc_a; } + println!("A: {a:?}"); + println!("B: {b:?}"); + // 2. Seed the transcript with the point and generate t random indices // TODO replace unwraps by proper error handling let mut transcript: IOPTranscript = IOPTranscript::new(b"opening_transcript"); transcript - .append_serializable_element(b"point", point) + .append_serializable_element(b"point", &point) .unwrap(); transcript .append_serializable_element(b"v", &proof.v) .unwrap(); // 3. Check the linear combination in the proof + println!("* Calling check lc from check"); Self::check_random_linear_combination( &b, proof, &commitment.root, - m, + commitment.n_ext_cols, t, &mut transcript, &vk.leaf_hash_params, diff --git a/src/ligero/utils.rs b/src/ligero/utils.rs index 69b6c00a..18c645d5 100644 --- a/src/ligero/utils.rs +++ b/src/ligero/utils.rs @@ -28,8 +28,8 @@ impl Matrix { entry_list.len(), n * m, "Invalid matrix construction: dimensions are {} x {} but entry vector has {} entries", - m, n, + m, entry_list.len() ); @@ -92,7 +92,7 @@ impl Matrix { assert_eq!( v.len(), self.n, - "Invalid row multiplication x has {} elements whereas the matrix has {}", + "Invalid row multiplication: vectir has {} elements whereas each matrix column has {}", v.len(), self.n ); @@ -110,9 +110,23 @@ impl Matrix { } } -/// apply reed-solomon encoding to msg -/// assumes msg.len() is equal to the order of an FFT domain in F -/// returns a vector of length equal to the smallest FFT domain of size at least msg.len() * rho_inv +/// Compute the dimensions of an FFT-friendly (over F) matrix with at least n entries. +/// The return pair (n, m) corresponds to the dimensions n x m. +pub(crate) fn compute_dimensions(n: usize) -> (usize, usize) { + + assert_eq!((n as f64) as usize, n, "n cannot be converted to f64: aborting"); + + let m0 = (n as f64).sqrt().ceil() as usize; + let m = GeneralEvaluationDomain::::new(m0) + .expect("Field F does not admit FFT with m elements") + .size(); + + (m, ceil_div(n, m)) +} + +/// Apply reed-solomon encoding to msg. +/// Assumes msg.len() is equal to the order of an FFT domain in F. +/// Returns a vector of length equal to the smallest FFT domain of size at least msg.len() * rho_inv. pub(crate) fn reed_solomon( // msg, of length m, is interpreted as a vector of coefficients of a polynomial of degree m - 1 msg: &[F], @@ -203,7 +217,7 @@ pub(crate) fn get_indices_from_transcript( #[inline] pub(crate) fn calculate_t(rho_inv: usize, sec_param: usize) -> usize { // TODO calculate t somehow - let t = 5; + let t = 3; println!("WARNING: you are using dummy t = {t}"); t } From ff3b27b0489df94f842eaa8774c296b3cdfc44c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mej=C3=ADas=20Gil?= Date: Tue, 4 Jul 2023 10:48:41 +0200 Subject: [PATCH 071/108] non-randomised test working --- src/ligero/mod.rs | 22 ++++------------------ src/ligero/tests.rs | 14 ++++++++++++-- src/ligero/utils.rs | 1 + 3 files changed, 17 insertions(+), 20 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 36ad47f9..fac5ca37 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -24,9 +24,8 @@ use data_structures::*; pub use data_structures::{Ligero, LigeroPCCommitterKey, LigeroPCVerifierKey}; -use utils::{calculate_t, get_indices_from_transcript, hash_column}; +use utils::{calculate_t, get_indices_from_transcript, hash_column, compute_dimensions}; -use self::utils::compute_dimensions; mod tests; impl @@ -77,7 +76,6 @@ where .append_serializable_element(b"v", &commitment.proof.v) .unwrap(); - println!("* Calling check lc from check well formedness"); Self::check_random_linear_combination( &r, &commitment.proof, @@ -110,9 +108,6 @@ where let indices = get_indices_from_transcript::(n_ext_cols, t, transcript); // 3. Verify the paths for each of the leaf hashes - println!("INDICES: {:?}", indices); - println!("LEAF INDICES: {:?}", proof.paths.iter().map(|p| p.leaf_index).collect::>()); - for (i, (leaf, q_i)) in col_hashes.into_iter().zip(indices.iter()).enumerate() { // TODO handle the error here let path = &proof.paths[i]; @@ -146,7 +141,7 @@ where let mut coeffs = polynomial.coeffs().to_vec(); // 1. Computing parameters and initial matrix - let (n_rows, n_cols) = compute_dimensions::(polynomial.degree() + 1); + let (n_rows, n_cols) = compute_dimensions::(polynomial.degree() + 1); // for 6 coefficients, this is returning 4 x 2 with a row of 0s: fix // padding the coefficient vector with zeroes // TODO is this the most efficient/safest way to do it? @@ -199,7 +194,6 @@ where // 2. Generate t column indices to test the linear combination on let indices = get_indices_from_transcript(ext_mat.m, t, transcript); - println!("INDICES T IN GENERATE_PROOF: {:?}", indices); // 3. Compute Merkle tree paths for the columns let mut queried_columns = Vec::new(); @@ -324,7 +318,6 @@ where } // 4. Generate the proof by choosing random columns and proving their paths in the tree - println!("* Calling generate proof from commit"); let proof = Self::generate_proof(&r, &mat, &ext_mat, &col_tree, &mut transcript); let commitment = LigeroPCCommitment { n_rows, n_cols, n_ext_cols, root, proof }; @@ -385,7 +378,6 @@ where .append_serializable_element(b"point", point) .unwrap(); - println!("* Calling generate proof from open"); Ok(Self::generate_proof( &b, &mat, @@ -419,8 +411,6 @@ where Self::check_well_formedness(commitment, &vk.leaf_hash_params, &vk.two_to_one_params) .unwrap(); - let point = F::from(2u64); - // 1. Compute a and b let mut a = Vec::new(); let mut acc_a = F::one(); @@ -437,21 +427,17 @@ where acc_b *= acc_a; } - println!("A: {a:?}"); - println!("B: {b:?}"); - // 2. Seed the transcript with the point and generate t random indices // TODO replace unwraps by proper error handling let mut transcript: IOPTranscript = IOPTranscript::new(b"opening_transcript"); transcript - .append_serializable_element(b"point", &point) + .append_serializable_element(b"point", point) .unwrap(); transcript .append_serializable_element(b"v", &proof.v) .unwrap(); // 3. Check the linear combination in the proof - println!("* Calling check lc from check"); Self::check_random_linear_combination( &b, proof, @@ -463,7 +449,7 @@ where &vk.two_to_one_params, )?; - Ok(inner_product(&commitment.proof.v, &a) == values.into_iter().next().unwrap()) + Ok(inner_product(&proof.v, &a) == values.into_iter().next().unwrap()) } } diff --git a/src/ligero/tests.rs b/src/ligero/tests.rs index 56afa7c7..4d225c8a 100644 --- a/src/ligero/tests.rs +++ b/src/ligero/tests.rs @@ -297,17 +297,27 @@ mod tests { }; let rand_chacha = &mut ChaCha20Rng::from_rng(test_rng()).unwrap(); - let labeled_poly = LabeledPolynomial::new( +/* let labeled_poly = LabeledPolynomial::new( "test".to_string(), rand_poly(degree, None, rand_chacha), None, None, - ); + ); */ + + let labeled_poly = LabeledPolynomial::new( + "test".to_string(), + DensePolynomial::from_coefficients_vec( + vec![2, 1, 0, 0, 3, 2].iter().map(|x| Fq::from(*x as u64)).collect() + ), + None, + None, + ); // TODO REMOVE! let mut test_sponge = test_sponge::(); let (c, rands) = LigeroPCS::<2>::commit(&ck, &[labeled_poly.clone()], None).unwrap(); let point = Fq::rand(rand_chacha); + let point = Fq::from(2u64); // TODO REMOVE! let value = labeled_poly.evaluate(&point); diff --git a/src/ligero/utils.rs b/src/ligero/utils.rs index 18c645d5..365a4f20 100644 --- a/src/ligero/utils.rs +++ b/src/ligero/utils.rs @@ -11,6 +11,7 @@ use rayon::{ use crate::streaming_kzg::ceil_div; +#[derive(Debug)] pub(crate) struct Matrix { pub(crate) n: usize, pub(crate) m: usize, From 7b36322fc119f02652368e86f1f26541b23df895 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mej=C3=ADas=20Gil?= Date: Tue, 4 Jul 2023 10:53:31 +0200 Subject: [PATCH 072/108] randomised test also working --- src/ligero/tests.rs | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/ligero/tests.rs b/src/ligero/tests.rs index 4d225c8a..56afa7c7 100644 --- a/src/ligero/tests.rs +++ b/src/ligero/tests.rs @@ -297,27 +297,17 @@ mod tests { }; let rand_chacha = &mut ChaCha20Rng::from_rng(test_rng()).unwrap(); -/* let labeled_poly = LabeledPolynomial::new( - "test".to_string(), - rand_poly(degree, None, rand_chacha), - None, - None, - ); */ - let labeled_poly = LabeledPolynomial::new( "test".to_string(), - DensePolynomial::from_coefficients_vec( - vec![2, 1, 0, 0, 3, 2].iter().map(|x| Fq::from(*x as u64)).collect() - ), + rand_poly(degree, None, rand_chacha), None, None, - ); // TODO REMOVE! + ); let mut test_sponge = test_sponge::(); let (c, rands) = LigeroPCS::<2>::commit(&ck, &[labeled_poly.clone()], None).unwrap(); let point = Fq::rand(rand_chacha); - let point = Fq::from(2u64); // TODO REMOVE! let value = labeled_poly.evaluate(&point); From 4b1647f8d3781c4dc29c4761d971d89fddce0bf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mej=C3=ADas=20Gil?= Date: Tue, 4 Jul 2023 11:07:07 +0200 Subject: [PATCH 073/108] matrix dimension computation fixed; formatted --- src/ligero/mod.rs | 12 +++++++++--- src/ligero/utils.rs | 15 +++++++++------ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index fac5ca37..9e1432e8 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -24,7 +24,7 @@ use data_structures::*; pub use data_structures::{Ligero, LigeroPCCommitterKey, LigeroPCVerifierKey}; -use utils::{calculate_t, get_indices_from_transcript, hash_column, compute_dimensions}; +use utils::{calculate_t, compute_dimensions, get_indices_from_transcript, hash_column}; mod tests; @@ -320,7 +320,13 @@ where // 4. Generate the proof by choosing random columns and proving their paths in the tree let proof = Self::generate_proof(&r, &mat, &ext_mat, &col_tree, &mut transcript); - let commitment = LigeroPCCommitment { n_rows, n_cols, n_ext_cols, root, proof }; + let commitment = LigeroPCCommitment { + n_rows, + n_cols, + n_ext_cols, + root, + proof, + }; Ok(( vec![LabeledCommitment::new( @@ -404,7 +410,7 @@ where let t = calculate_t(rho_inv, sec_param); - // TODO maybe check that the parameters have been calculated honestly (n_rows/cols/ext_cols); + // TODO maybe check that the parameters have been calculated honestly (n_rows/cols/ext_cols); // could they be used to cheat? // check if we've seen this commitment before. If not, we should verify it. diff --git a/src/ligero/utils.rs b/src/ligero/utils.rs index 365a4f20..4faa884b 100644 --- a/src/ligero/utils.rs +++ b/src/ligero/utils.rs @@ -114,16 +114,19 @@ impl Matrix { /// Compute the dimensions of an FFT-friendly (over F) matrix with at least n entries. /// The return pair (n, m) corresponds to the dimensions n x m. pub(crate) fn compute_dimensions(n: usize) -> (usize, usize) { + assert_eq!( + (n as f64) as usize, + n, + "n cannot be converted to f64: aborting" + ); - assert_eq!((n as f64) as usize, n, "n cannot be converted to f64: aborting"); - - let m0 = (n as f64).sqrt().ceil() as usize; - let m = GeneralEvaluationDomain::::new(m0) + let aux = (n as f64).sqrt().ceil() as usize; + let n_cols = GeneralEvaluationDomain::::new(aux) .expect("Field F does not admit FFT with m elements") .size(); - (m, ceil_div(n, m)) -} + (ceil_div(n, n_cols), n_cols) +} /// Apply reed-solomon encoding to msg. /// Assumes msg.len() is equal to the order of an FFT domain in F. From 660cd1db41bd0986e9677d50a2d002029c8305c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mej=C3=ADas=20Gil?= Date: Thu, 6 Jul 2023 21:49:11 +0200 Subject: [PATCH 074/108] commit now runs over all polynomials --- src/ligero/mod.rs | 86 +++++++++++++++++++++++++---------------------- 1 file changed, 45 insertions(+), 41 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 9e1432e8..6b73703f 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -286,56 +286,59 @@ where where P: 'a, { - // TODO loop over all polynomials + + let mut commitments = Vec::new(); - // TODO decide what to do with label and degree bound (these are private! but the commitment also has them) - let labeled_polynomial = polynomials.into_iter().next().unwrap(); + for labeled_polynomial in polynomials.into_iter() { - let polynomial = labeled_polynomial.polynomial(); + let polynomial = labeled_polynomial.polynomial(); - // 1. Compute matrices - let (mat, ext_mat) = Self::compute_matrices(polynomial); + // 1. Compute matrices + let (mat, ext_mat) = Self::compute_matrices(polynomial); - // 2. Create the Merkle tree from the hashes of the columns - let col_tree = - Self::create_merkle_tree(&ext_mat, &ck.leaf_hash_params, &ck.two_to_one_params); - - // 3. Add root to transcript and generate random linear combination with it - let root = col_tree.root(); + // 2. Create the Merkle tree from the hashes of the columns + let col_tree = + Self::create_merkle_tree(&ext_mat, &ck.leaf_hash_params, &ck.two_to_one_params); - let mut transcript: IOPTranscript = IOPTranscript::new(b"well_formedness_transcript"); - transcript - .append_serializable_element(b"root", &root) - .unwrap(); + // 3. Add root to transcript and generate random linear combination with it + let root = col_tree.root(); - let n_rows = mat.n; - let n_cols = mat.m; - let n_ext_cols = ext_mat.m; + let mut transcript: IOPTranscript = IOPTranscript::new(b"well_formedness_transcript"); + transcript + .append_serializable_element(b"root", &root) + .unwrap(); - let mut r = Vec::new(); - for _ in 0..n_rows { - r.push(transcript.get_and_append_challenge(b"r").unwrap()); - } + let n_rows = mat.n; + let n_cols = mat.m; + let n_ext_cols = ext_mat.m; - // 4. Generate the proof by choosing random columns and proving their paths in the tree - let proof = Self::generate_proof(&r, &mat, &ext_mat, &col_tree, &mut transcript); + let mut r = Vec::new(); + for _ in 0..n_rows { + r.push(transcript.get_and_append_challenge(b"r").unwrap()); + } - let commitment = LigeroPCCommitment { - n_rows, - n_cols, - n_ext_cols, - root, - proof, - }; - - Ok(( - vec![LabeledCommitment::new( - labeled_polynomial.label().clone(), - commitment, - None, // TODO think about this (degree_bound) - )], - Vec::new(), - )) + // 4. Generate the proof by choosing random columns and proving their paths in the tree + let proof = Self::generate_proof(&r, &mat, &ext_mat, &col_tree, &mut transcript); + + let commitment = LigeroPCCommitment { + n_rows, + n_cols, + n_ext_cols, + root, + proof, + }; + + commitments.push( + LabeledCommitment::new( + labeled_polynomial.label().clone(), + commitment, + None, // TODO think about this (degree_bound) + ) + ); + } + + // randomness is returned inside the proof, so we return an empty vector here + Ok((commitments, Vec::new())) // TODO when should this return Err? } @@ -353,6 +356,7 @@ where Self::Randomness: 'a, Self::Commitment: 'a, { + let labeled_polynomial = labeled_polynomials.into_iter().next().unwrap(); let polynomial = labeled_polynomial.polynomial(); From 3c5d05614c4104d54854e1a810cc360ecfa6e5f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mej=C3=ADas=20Gil?= Date: Thu, 6 Jul 2023 22:24:54 +0200 Subject: [PATCH 075/108] changed proof type to array of former proofs (matching open()) --- src/ligero/data_structures.rs | 2 + src/ligero/mod.rs | 78 +++++++++++++++++++---------------- 2 files changed, 45 insertions(+), 35 deletions(-) diff --git a/src/ligero/data_structures.rs b/src/ligero/data_structures.rs index 4503e06e..a5d63d27 100644 --- a/src/ligero/data_structures.rs +++ b/src/ligero/data_structures.rs @@ -182,3 +182,5 @@ where pub(crate) columns: Vec>, } + +pub type LigeroPCProofArray = Vec>; \ No newline at end of file diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 6b73703f..53109bed 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -241,7 +241,7 @@ where type Randomness = LigeroPCRandomness; - type Proof = LigeroPCProof; + type Proof = LigeroPCProofArray; type BatchProof = Vec; @@ -347,54 +347,62 @@ where labeled_polynomials: impl IntoIterator>, commitments: impl IntoIterator>, point: &'a P::Point, - challenge_generator: &mut crate::challenge::ChallengeGenerator, - rands: impl IntoIterator, - rng: Option<&mut dyn RngCore>, + _challenge_generator: &mut crate::challenge::ChallengeGenerator, + _rands: impl IntoIterator, + _rng: Option<&mut dyn RngCore>, ) -> Result where P: 'a, Self::Randomness: 'a, Self::Commitment: 'a, { - - let labeled_polynomial = labeled_polynomials.into_iter().next().unwrap(); - let polynomial = labeled_polynomial.polynomial(); + let proof_array = LigeroPCProofArray::new(); - // TODO we receive a list of polynomials and a list of commitments - // are we to understand that the first commitment is for the first polynomial, ...etc? + for labeled_polynomial in labeled_polynomials.into_iter() { - // 1. Compute matrices - let (mat, ext_mat) = Self::compute_matrices(polynomial); + let polynomial = labeled_polynomial.polynomial(); - // 2. Create the Merkle tree from the hashes of the columns - let col_tree = - Self::create_merkle_tree(&ext_mat, &ck.leaf_hash_params, &ck.two_to_one_params); + // TODO we receive a list of polynomials and a list of commitments + // are we to understand that the first commitment is for the first polynomial, ...etc? - // 3. Generate vector b and add v = b·M to the transcript - let commitment = commitments.into_iter().next().unwrap().commitment(); + // 1. Compute matrices + let (mat, ext_mat) = Self::compute_matrices(polynomial); - let mut b = Vec::new(); - let point_pow = point.pow([commitment.n_cols as u64]); // TODO this and other conversions could potentially fail - let mut acc_b = F::one(); - for _ in 0..commitment.n_rows { - b.push(acc_b); - acc_b *= point_pow; - } + // 2. Create the Merkle tree from the hashes of the columns + let col_tree = + Self::create_merkle_tree(&ext_mat, &ck.leaf_hash_params, &ck.two_to_one_params); - let mut transcript: IOPTranscript = IOPTranscript::new(b"opening_transcript"); + // 3. Generate vector b and add v = b·M to the transcript + let commitment = commitments.into_iter().next().unwrap().commitment(); - let v = mat.row_mul(&b); - transcript - .append_serializable_element(b"point", point) - .unwrap(); + let mut b = Vec::new(); + let point_pow = point.pow([commitment.n_cols as u64]); // TODO this and other conversions could potentially fail + let mut acc_b = F::one(); + for _ in 0..commitment.n_rows { + b.push(acc_b); + acc_b *= point_pow; + } + + let mut transcript: IOPTranscript = IOPTranscript::new(b"opening_transcript"); + + let v = mat.row_mul(&b); + transcript + .append_serializable_element(b"point", point) + .unwrap(); + + proof_array.push( + Self::generate_proof( + &b, + &mat, + &ext_mat, + &col_tree, + &mut transcript + ) + ) + } + + Ok(proof_array) - Ok(Self::generate_proof( - &b, - &mat, - &ext_mat, - &col_tree, - &mut transcript, - )) } fn check<'a>( From 817f56626a958b3a37d9d01daeade17d999b294b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mej=C3=ADas=20Gil?= Date: Fri, 7 Jul 2023 08:54:25 +0200 Subject: [PATCH 076/108] compiling with new multi-polynomial functionality, old tests passing --- src/ligero/data_structures.rs | 3 +- src/ligero/mod.rs | 131 +++++++++++++++++++++------------- 2 files changed, 84 insertions(+), 50 deletions(-) diff --git a/src/ligero/data_structures.rs b/src/ligero/data_structures.rs index a5d63d27..8ad52a62 100644 --- a/src/ligero/data_structures.rs +++ b/src/ligero/data_structures.rs @@ -166,7 +166,7 @@ impl PCRandomness for LigeroPCRandomness { } } -/// Ligero proof +/// Proof of an individual Ligero well-formedness check or opening #[derive(Derivative, CanonicalSerialize, CanonicalDeserialize)] #[derivative(Default(bound = ""), Clone(bound = ""), Debug(bound = ""))] pub struct LigeroPCProof @@ -183,4 +183,5 @@ where pub(crate) columns: Vec>, } +/// The Proof type for Ligero, which amounts to an array of individual ligero proofs pub type LigeroPCProofArray = Vec>; \ No newline at end of file diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 53109bed..52bbbde5 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -22,7 +22,7 @@ use utils::Matrix; mod data_structures; use data_structures::*; -pub use data_structures::{Ligero, LigeroPCCommitterKey, LigeroPCVerifierKey}; +pub use data_structures::{Ligero, LigeroPCCommitterKey, LigeroPCVerifierKey, LigeroPCProofArray}; use utils::{calculate_t, compute_dimensions, get_indices_from_transcript, hash_column}; @@ -356,15 +356,27 @@ where Self::Randomness: 'a, Self::Commitment: 'a, { - let proof_array = LigeroPCProofArray::new(); + let mut proof_array = LigeroPCProofArray::new(); + let labeled_commitments: Vec<&'a LabeledCommitment> = commitments.into_iter().collect(); + let labeled_polynomials: Vec<&'a LabeledPolynomial> = labeled_polynomials.into_iter().collect(); + + assert_eq!(labeled_commitments.len(), labeled_polynomials.len(), + // maybe return Err? + "Mismatched lengths: {} commitments, {} polynomials", + labeled_commitments.len(), labeled_polynomials.len() + ); - for labeled_polynomial in labeled_polynomials.into_iter() { + for i in 0..labeled_polynomials.len() { - let polynomial = labeled_polynomial.polynomial(); + let polynomial = labeled_polynomials[i].polynomial(); + let commitment = labeled_commitments[i].commitment(); // TODO we receive a list of polynomials and a list of commitments // are we to understand that the first commitment is for the first polynomial, ...etc? + // TODO we should maybe check that these two lists match,b ut that would imply recomputing merkle trees... + // at least check labels? + // 1. Compute matrices let (mat, ext_mat) = Self::compute_matrices(polynomial); @@ -373,8 +385,6 @@ where Self::create_merkle_tree(&ext_mat, &ck.leaf_hash_params, &ck.two_to_one_params); // 3. Generate vector b and add v = b·M to the transcript - let commitment = commitments.into_iter().next().unwrap().commitment(); - let mut b = Vec::new(); let point_pow = point.pow([commitment.n_cols as u64]); // TODO this and other conversions could potentially fail let mut acc_b = F::one(); @@ -417,57 +427,80 @@ where where Self::Commitment: 'a, { - let labeled_commitment = commitments.into_iter().next().unwrap(); - let commitment = labeled_commitment.commitment(); - let t = calculate_t(rho_inv, sec_param); + let labeled_commitments: Vec<&'a LabeledCommitment> = commitments.into_iter().collect(); + let values: Vec = values.into_iter().collect(); - // TODO maybe check that the parameters have been calculated honestly (n_rows/cols/ext_cols); - // could they be used to cheat? + let t = calculate_t(rho_inv, sec_param); // TODO include in ck/vk? - // check if we've seen this commitment before. If not, we should verify it. - Self::check_well_formedness(commitment, &vk.leaf_hash_params, &vk.two_to_one_params) - .unwrap(); - - // 1. Compute a and b - let mut a = Vec::new(); - let mut acc_a = F::one(); - for _ in 0..commitment.n_cols { - a.push(acc_a); - acc_a *= point; + if labeled_commitments.len() != proof.len() || labeled_commitments.len() != values.len() { + // maybe return Err? + panic!("Mismatched lengths: {} proofs of were provided for {} commitments with {} claimed values", + labeled_commitments.len(), proof.len(), values.len()); } - // by now acc_a = point^n_cols - let mut b = Vec::new(); - let mut acc_b = F::one(); - for _ in 0..commitment.n_rows { - b.push(acc_b); - acc_b *= acc_a; - } + for (i, labeled_commitment) in labeled_commitments.iter().enumerate() { - // 2. Seed the transcript with the point and generate t random indices - // TODO replace unwraps by proper error handling - let mut transcript: IOPTranscript = IOPTranscript::new(b"opening_transcript"); - transcript - .append_serializable_element(b"point", point) - .unwrap(); - transcript - .append_serializable_element(b"v", &proof.v) - .unwrap(); + let commitment = labeled_commitment.commitment(); - // 3. Check the linear combination in the proof - Self::check_random_linear_combination( - &b, - proof, - &commitment.root, - commitment.n_ext_cols, - t, - &mut transcript, - &vk.leaf_hash_params, - &vk.two_to_one_params, - )?; + // TODO maybe check that the parameters have been calculated honestly (n_rows/cols/ext_cols); + // could they be used to cheat? + + // check if we've seen this commitment before. If not, we should verify it. + if Self::check_well_formedness(commitment, &vk.leaf_hash_params, &vk.two_to_one_params) + .is_err() { + println!("Function check failed verification of well-formedness of commitment with index {i}"); + return Ok(false); + } + + // 1. Compute a and b + let mut a = Vec::new(); + let mut acc_a = F::one(); + for _ in 0..commitment.n_cols { + a.push(acc_a); + acc_a *= point; + } + + // by now acc_a = point^n_cols + let mut b = Vec::new(); + let mut acc_b = F::one(); + for _ in 0..commitment.n_rows { + b.push(acc_b); + acc_b *= acc_a; + } + + // 2. Seed the transcript with the point and generate t random indices + // TODO replace unwraps by proper error handling + let mut transcript: IOPTranscript = IOPTranscript::new(b"opening_transcript"); + transcript + .append_serializable_element(b"point", point) + .unwrap(); + transcript + .append_serializable_element(b"v", &proof[i].v) + .unwrap(); + + // 3. Check the linear combination in the proof + if Self::check_random_linear_combination( + &b, + &proof[i], + &commitment.root, + commitment.n_ext_cols, + t, + &mut transcript, + &vk.leaf_hash_params, + &vk.two_to_one_params, + ).is_err() { + println!("Function check failed verification of opening with index {i}"); + return Ok(false); + } + + if inner_product(&proof[i].v, &a) != values[i] { + println!("Funcion check: passed value at index {i} does not match prover's claimed value at the same infex"); + return Ok(false); + } + } - Ok(inner_product(&proof.v, &a) == values.into_iter().next().unwrap()) + Ok(true) } } From f5f2f568f62b87674ec3502f4d36e7db28611f33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mej=C3=ADas=20Gil?= Date: Fri, 7 Jul 2023 09:33:16 +0200 Subject: [PATCH 077/108] new tests for new multi-polynomial functionality passing --- src/ligero/mod.rs | 1 + src/ligero/tests.rs | 212 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 213 insertions(+) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 52bbbde5..3db29112 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -490,6 +490,7 @@ where &vk.leaf_hash_params, &vk.two_to_one_params, ).is_err() { + // I think this can never be called since check_random_linear_combination will panick itself; must improve error handling println!("Function check failed verification of opening with index {i}"); return Ok(false); } diff --git a/src/ligero/tests.rs b/src/ligero/tests.rs index 56afa7c7..b4ae61e9 100644 --- a/src/ligero/tests.rs +++ b/src/ligero/tests.rs @@ -345,4 +345,216 @@ mod tests { ) .unwrap()); } + + #[test] + fn test_several_polynomials() { + let degrees = [4_usize, 13_usize, 30_usize]; + let mut rng = &mut test_rng(); + + LigeroPCS::<2>::setup(*degrees.iter().max().unwrap(), None, rng).unwrap(); + let leaf_hash_params = ::setup(&mut rng).unwrap(); + let two_to_one_params = ::setup(&mut rng) + .unwrap() + .clone(); + + let ck: LigeroPCCommitterKey = LigeroPCCommitterKey { + leaf_hash_params, + two_to_one_params, + }; + let vk: LigeroPCVerifierKey = LigeroPCVerifierKey { + leaf_hash_params, + two_to_one_params, + }; + + let rand_chacha = &mut ChaCha20Rng::from_rng(test_rng()).unwrap(); + let mut test_sponge = test_sponge::(); + let mut challenge_generator: ChallengeGenerator> = + ChallengeGenerator::new_univariate(&mut test_sponge); + + let mut labeled_polys = Vec::new(); + let mut values = Vec::new(); + + let point = Fq::rand(rand_chacha); + + for degree in degrees { + let labeled_poly = LabeledPolynomial::new( + "test".to_string(), + rand_poly(degree, None, rand_chacha), + None, + None, + ); + + values.push(labeled_poly.evaluate(&point)); + labeled_polys.push(labeled_poly); + } + + let (commitments, randomness) = LigeroPCS::<2>::commit(&ck, &labeled_polys, None).unwrap(); + + let proof = LigeroPCS::<2>::open( + &ck, + &labeled_polys, + &commitments, + &point, + &mut (challenge_generator.clone()), + &randomness, + None, + ) + .unwrap(); + assert!(LigeroPCS::<2>::check( + &vk, + &commitments, + &point, + values, + &proof, + &mut challenge_generator, + None + ) + .unwrap()); + } + + #[test] + #[should_panic] + fn test_several_polynomials_swap_proofs() { + // in this test we work with three polynomials and swap the proofs of the first and last openings + let degrees = [4_usize, 13_usize, 30_usize]; + let mut rng = &mut test_rng(); + + LigeroPCS::<2>::setup(*degrees.iter().max().unwrap(), None, rng).unwrap(); + let leaf_hash_params = ::setup(&mut rng).unwrap(); + let two_to_one_params = ::setup(&mut rng) + .unwrap() + .clone(); + + let ck: LigeroPCCommitterKey = LigeroPCCommitterKey { + leaf_hash_params, + two_to_one_params, + }; + let vk: LigeroPCVerifierKey = LigeroPCVerifierKey { + leaf_hash_params, + two_to_one_params, + }; + + let rand_chacha = &mut ChaCha20Rng::from_rng(test_rng()).unwrap(); + let mut test_sponge = test_sponge::(); + let mut challenge_generator: ChallengeGenerator> = + ChallengeGenerator::new_univariate(&mut test_sponge); + + let mut labeled_polys = Vec::new(); + let mut values = Vec::new(); + + let point = Fq::rand(rand_chacha); + + for degree in degrees { + let labeled_poly = LabeledPolynomial::new( + "test".to_string(), + rand_poly(degree, None, rand_chacha), + None, + None, + ); + + values.push(labeled_poly.evaluate(&point)); + labeled_polys.push(labeled_poly); + } + + let (commitments, randomness) = LigeroPCS::<2>::commit(&ck, &labeled_polys, None).unwrap(); + + let mut proof = LigeroPCS::<2>::open( + &ck, + &labeled_polys, + &commitments, + &point, + &mut (challenge_generator.clone()), + &randomness, + None, + ) + .unwrap(); + + // to do swap opening proofs + proof.swap(0, 2); + + assert!(LigeroPCS::<2>::check( + &vk, + &commitments, + &point, + values, + &proof, + &mut challenge_generator, + None + ) + .unwrap()); + } + + #[test] + #[should_panic] + fn test_several_polynomials_swap_values() { + // in this test we work with three polynomials and swap the second + // and third values passed to the verifier externally + let degrees = [4_usize, 13_usize, 30_usize]; + let mut rng = &mut test_rng(); + + LigeroPCS::<2>::setup(*degrees.iter().max().unwrap(), None, rng).unwrap(); + let leaf_hash_params = ::setup(&mut rng).unwrap(); + let two_to_one_params = ::setup(&mut rng) + .unwrap() + .clone(); + + let ck: LigeroPCCommitterKey = LigeroPCCommitterKey { + leaf_hash_params, + two_to_one_params, + }; + let vk: LigeroPCVerifierKey = LigeroPCVerifierKey { + leaf_hash_params, + two_to_one_params, + }; + + let rand_chacha = &mut ChaCha20Rng::from_rng(test_rng()).unwrap(); + let mut test_sponge = test_sponge::(); + let mut challenge_generator: ChallengeGenerator> = + ChallengeGenerator::new_univariate(&mut test_sponge); + + let mut labeled_polys = Vec::new(); + let mut values = Vec::new(); + + let point = Fq::rand(rand_chacha); + + for degree in degrees { + let labeled_poly = LabeledPolynomial::new( + "test".to_string(), + rand_poly(degree, None, rand_chacha), + None, + None, + ); + + values.push(labeled_poly.evaluate(&point)); + labeled_polys.push(labeled_poly); + } + + let (commitments, randomness) = LigeroPCS::<2>::commit(&ck, &labeled_polys, None).unwrap(); + + let proof = LigeroPCS::<2>::open( + &ck, + &labeled_polys, + &commitments, + &point, + &mut (challenge_generator.clone()), + &randomness, + None, + ) + .unwrap(); + + // swap values externally passed to verifier + values.swap(1, 2); + + assert!(LigeroPCS::<2>::check( + &vk, + &commitments, + &point, + values, + &proof, + &mut challenge_generator, + None + ) + .unwrap()); + } + } From 990782defac3da89914905370a3b271f44d316f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mej=C3=ADas=20Gil?= Date: Fri, 7 Jul 2023 10:01:15 +0200 Subject: [PATCH 078/108] cleaned up unnecessary variables --- src/ligero/mod.rs | 2 -- src/ligero/tests.rs | 70 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 2 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 3db29112..828bb71d 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -184,7 +184,6 @@ where col_tree: &MerkleTree, transcript: &mut IOPTranscript, ) -> LigeroPCProof { - let n_rows = mat.n; let t = calculate_t(rho_inv, sec_param); // TODO this function will now probably need to take into account the number of rows/cols of the extended matrix // 1. Compute the linear combination using the random coefficients @@ -395,7 +394,6 @@ where let mut transcript: IOPTranscript = IOPTranscript::new(b"opening_transcript"); - let v = mat.row_mul(&b); transcript .append_serializable_element(b"point", point) .unwrap(); diff --git a/src/ligero/tests.rs b/src/ligero/tests.rs index b4ae61e9..5eb25a5e 100644 --- a/src/ligero/tests.rs +++ b/src/ligero/tests.rs @@ -412,6 +412,76 @@ mod tests { .unwrap()); } + + #[test] + #[should_panic] + fn test_several_polynomials_mismatched_lengths() { + // here we go through the same motions as in test_several_polynomials, + // but pass to check() one fewer value than we should + let degrees = [4_usize, 13_usize, 30_usize]; + let mut rng = &mut test_rng(); + + LigeroPCS::<2>::setup(*degrees.iter().max().unwrap(), None, rng).unwrap(); + let leaf_hash_params = ::setup(&mut rng).unwrap(); + let two_to_one_params = ::setup(&mut rng) + .unwrap() + .clone(); + + let ck: LigeroPCCommitterKey = LigeroPCCommitterKey { + leaf_hash_params, + two_to_one_params, + }; + let vk: LigeroPCVerifierKey = LigeroPCVerifierKey { + leaf_hash_params, + two_to_one_params, + }; + + let rand_chacha = &mut ChaCha20Rng::from_rng(test_rng()).unwrap(); + let mut test_sponge = test_sponge::(); + let mut challenge_generator: ChallengeGenerator> = + ChallengeGenerator::new_univariate(&mut test_sponge); + + let mut labeled_polys = Vec::new(); + let mut values = Vec::new(); + + let point = Fq::rand(rand_chacha); + + for degree in degrees { + let labeled_poly = LabeledPolynomial::new( + "test".to_string(), + rand_poly(degree, None, rand_chacha), + None, + None, + ); + + values.push(labeled_poly.evaluate(&point)); + labeled_polys.push(labeled_poly); + } + + let (commitments, randomness) = LigeroPCS::<2>::commit(&ck, &labeled_polys, None).unwrap(); + + let proof = LigeroPCS::<2>::open( + &ck, + &labeled_polys, + &commitments, + &point, + &mut (challenge_generator.clone()), + &randomness, + None, + ) + .unwrap(); + assert!(LigeroPCS::<2>::check( + &vk, + &commitments, + &point, + values[0..2].to_vec(), + &proof, + &mut challenge_generator, + None + ) + .unwrap()); + } + #[test] #[should_panic] fn test_several_polynomials_swap_proofs() { From 5f9dbf329926005c8c31397e402a7f01cf2e0923 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mej=C3=ADas=20Gil?= Date: Fri, 7 Jul 2023 14:49:31 +0200 Subject: [PATCH 079/108] addressed minor requested changes to the PR --- src/ligero/data_structures.rs | 2 +- src/ligero/mod.rs | 75 +++++++++++++++++------------------ src/ligero/tests.rs | 18 ++++----- 3 files changed, 46 insertions(+), 49 deletions(-) diff --git a/src/ligero/data_structures.rs b/src/ligero/data_structures.rs index 8ad52a62..c7a2ea45 100644 --- a/src/ligero/data_structures.rs +++ b/src/ligero/data_structures.rs @@ -184,4 +184,4 @@ where } /// The Proof type for Ligero, which amounts to an array of individual ligero proofs -pub type LigeroPCProofArray = Vec>; \ No newline at end of file +pub type LigeroPCProofArray = Vec>; diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 828bb71d..361ccb62 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -22,7 +22,7 @@ use utils::Matrix; mod data_structures; use data_structures::*; -pub use data_structures::{Ligero, LigeroPCCommitterKey, LigeroPCVerifierKey, LigeroPCProofArray}; +pub use data_structures::{Ligero, LigeroPCCommitterKey, LigeroPCProofArray, LigeroPCVerifierKey}; use utils::{calculate_t, compute_dimensions, get_indices_from_transcript, hash_column}; @@ -285,11 +285,9 @@ where where P: 'a, { - let mut commitments = Vec::new(); for labeled_polynomial in polynomials.into_iter() { - let polynomial = labeled_polynomial.polynomial(); // 1. Compute matrices @@ -302,7 +300,8 @@ where // 3. Add root to transcript and generate random linear combination with it let root = col_tree.root(); - let mut transcript: IOPTranscript = IOPTranscript::new(b"well_formedness_transcript"); + let mut transcript: IOPTranscript = + IOPTranscript::new(b"well_formedness_transcript"); transcript .append_serializable_element(b"root", &root) .unwrap(); @@ -327,16 +326,13 @@ where proof, }; - commitments.push( - LabeledCommitment::new( - labeled_polynomial.label().clone(), - commitment, - None, // TODO think about this (degree_bound) - ) - ); - } + commitments.push(LabeledCommitment::new( + labeled_polynomial.label().clone(), + commitment, + None, // TODO think about this (degree_bound) + )); + } - // randomness is returned inside the proof, so we return an empty vector here Ok((commitments, Vec::new())) // TODO when should this return Err? } @@ -356,24 +352,28 @@ where Self::Commitment: 'a, { let mut proof_array = LigeroPCProofArray::new(); - let labeled_commitments: Vec<&'a LabeledCommitment> = commitments.into_iter().collect(); - let labeled_polynomials: Vec<&'a LabeledPolynomial> = labeled_polynomials.into_iter().collect(); - - assert_eq!(labeled_commitments.len(), labeled_polynomials.len(), + let labeled_commitments: Vec<&'a LabeledCommitment> = + commitments.into_iter().collect(); + let labeled_polynomials: Vec<&'a LabeledPolynomial> = + labeled_polynomials.into_iter().collect(); + + assert_eq!( + labeled_commitments.len(), + labeled_polynomials.len(), // maybe return Err? "Mismatched lengths: {} commitments, {} polynomials", - labeled_commitments.len(), labeled_polynomials.len() + labeled_commitments.len(), + labeled_polynomials.len() ); for i in 0..labeled_polynomials.len() { - let polynomial = labeled_polynomials[i].polynomial(); let commitment = labeled_commitments[i].commitment(); // TODO we receive a list of polynomials and a list of commitments // are we to understand that the first commitment is for the first polynomial, ...etc? - // TODO we should maybe check that these two lists match,b ut that would imply recomputing merkle trees... + // TODO we should maybe check that these two lists match, but that would imply recomputing merkle trees... // at least check labels? // 1. Compute matrices @@ -398,19 +398,16 @@ where .append_serializable_element(b"point", point) .unwrap(); - proof_array.push( - Self::generate_proof( - &b, - &mat, - &ext_mat, - &col_tree, - &mut transcript - ) - ) + proof_array.push(Self::generate_proof( + &b, + &mat, + &ext_mat, + &col_tree, + &mut transcript, + )) } Ok(proof_array) - } fn check<'a>( @@ -425,20 +422,19 @@ where where Self::Commitment: 'a, { - - let labeled_commitments: Vec<&'a LabeledCommitment> = commitments.into_iter().collect(); + let labeled_commitments: Vec<&'a LabeledCommitment> = + commitments.into_iter().collect(); let values: Vec = values.into_iter().collect(); let t = calculate_t(rho_inv, sec_param); // TODO include in ck/vk? if labeled_commitments.len() != proof.len() || labeled_commitments.len() != values.len() { // maybe return Err? - panic!("Mismatched lengths: {} proofs of were provided for {} commitments with {} claimed values", + panic!("Mismatched lengths: {} proofs were provided for {} commitments with {} claimed values", labeled_commitments.len(), proof.len(), values.len()); } for (i, labeled_commitment) in labeled_commitments.iter().enumerate() { - let commitment = labeled_commitment.commitment(); // TODO maybe check that the parameters have been calculated honestly (n_rows/cols/ext_cols); @@ -446,9 +442,10 @@ where // check if we've seen this commitment before. If not, we should verify it. if Self::check_well_formedness(commitment, &vk.leaf_hash_params, &vk.two_to_one_params) - .is_err() { - println!("Function check failed verification of well-formedness of commitment with index {i}"); - return Ok(false); + .is_err() + { + println!("Function check failed verification of well-formedness of commitment with index {i}"); + return Ok(false); } // 1. Compute a and b @@ -487,7 +484,9 @@ where &mut transcript, &vk.leaf_hash_params, &vk.two_to_one_params, - ).is_err() { + ) + .is_err() + { // I think this can never be called since check_random_linear_combination will panick itself; must improve error handling println!("Function check failed verification of opening with index {i}"); return Ok(false); diff --git a/src/ligero/tests.rs b/src/ligero/tests.rs index 5eb25a5e..672524ee 100644 --- a/src/ligero/tests.rs +++ b/src/ligero/tests.rs @@ -373,7 +373,7 @@ mod tests { let mut labeled_polys = Vec::new(); let mut values = Vec::new(); - + let point = Fq::rand(rand_chacha); for degree in degrees { @@ -389,7 +389,7 @@ mod tests { } let (commitments, randomness) = LigeroPCS::<2>::commit(&ck, &labeled_polys, None).unwrap(); - + let proof = LigeroPCS::<2>::open( &ck, &labeled_polys, @@ -412,7 +412,6 @@ mod tests { .unwrap()); } - #[test] #[should_panic] fn test_several_polynomials_mismatched_lengths() { @@ -443,7 +442,7 @@ mod tests { let mut labeled_polys = Vec::new(); let mut values = Vec::new(); - + let point = Fq::rand(rand_chacha); for degree in degrees { @@ -459,7 +458,7 @@ mod tests { } let (commitments, randomness) = LigeroPCS::<2>::commit(&ck, &labeled_polys, None).unwrap(); - + let proof = LigeroPCS::<2>::open( &ck, &labeled_polys, @@ -511,7 +510,7 @@ mod tests { let mut labeled_polys = Vec::new(); let mut values = Vec::new(); - + let point = Fq::rand(rand_chacha); for degree in degrees { @@ -527,7 +526,7 @@ mod tests { } let (commitments, randomness) = LigeroPCS::<2>::commit(&ck, &labeled_polys, None).unwrap(); - + let mut proof = LigeroPCS::<2>::open( &ck, &labeled_polys, @@ -584,7 +583,7 @@ mod tests { let mut labeled_polys = Vec::new(); let mut values = Vec::new(); - + let point = Fq::rand(rand_chacha); for degree in degrees { @@ -600,7 +599,7 @@ mod tests { } let (commitments, randomness) = LigeroPCS::<2>::commit(&ck, &labeled_polys, None).unwrap(); - + let proof = LigeroPCS::<2>::open( &ck, &labeled_polys, @@ -626,5 +625,4 @@ mod tests { ) .unwrap()); } - } From 5f4774d121ce6fd76c32427269035b3d19c5eab8 Mon Sep 17 00:00:00 2001 From: mmagician Date: Thu, 13 Jul 2023 22:47:55 +0200 Subject: [PATCH 080/108] pin dependencies to original upstreams, not forks --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 47255b43..e623f884 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ ark-serialize = { version = "^0.4.0", default-features = false, features = [ "de ark-ff = { version = "^0.4.0", default-features = false } ark-ec = { version = "^0.4.0", default-features = false } ark-poly = {version = "^0.4.0", default-features = false } -ark-crypto-primitives = { version = "^0.4.0", default-features = false, features = ["sponge","merkle_tree" ], git = "https://github.com/HungryCatsStudio/crypto-primitives.git", branch = "trait-bounds-for-crh" } +ark-crypto-primitives = { version = "^0.4.0", default-features = false, features = ["sponge","merkle_tree" ], git = "https://github.com/arkworks-rs/crypto-primitives" } ark-std = { version = "^0.4.0", default-features = false } ark-relations = { version = "^0.4.0", default-features = false, optional = true } @@ -25,7 +25,7 @@ hashbrown = { version = "0.13", default-features = false, optional = true } digest = "0.10" derivative = { version = "2", features = [ "use_core" ] } rayon = { version = "1", optional = true } -jf-primitives = { version = "0.4.0-pre.0", git = "https://github.com/tessico/jellyfish", branch = "make-iop-transcipt-pub" } +jf-primitives = { version = "0.4.0-pre.0", git = "https://github.com/EspressoSystems/jellyfish/", rev = "6210b1f" } [dev-dependencies] ark-ed-on-bls12-381 = { version = "^0.4.0", default-features = false } From 9df98d2e3a17d1779f8ade4415e4d0bee93aceec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mej=C3=ADas=20Gil?= Date: Fri, 14 Jul 2023 10:31:39 +0200 Subject: [PATCH 081/108] added expected panic messages to tests, formatted/clipped only ligero files --- src/ligero/data_structures.rs | 12 ++++++------ src/ligero/mod.rs | 27 ++++++++++++++------------- src/ligero/tests.rs | 8 ++++---- src/ligero/utils.rs | 14 ++++++-------- 4 files changed, 30 insertions(+), 31 deletions(-) diff --git a/src/ligero/data_structures.rs b/src/ligero/data_structures.rs index c7a2ea45..159ac237 100644 --- a/src/ligero/data_structures.rs +++ b/src/ligero/data_structures.rs @@ -113,7 +113,7 @@ where pub(crate) type LigeroPCPreparedVerifierKey = (); impl PCPreparedVerifierKey for LigeroPCPreparedVerifierKey { - fn prepare(vk: &Unprepared) -> Self { + fn prepare(_vk: &Unprepared) -> Self { todo!() } } @@ -144,7 +144,7 @@ impl PCCommitment for LigeroPCCommitment { pub(crate) type LigeroPCPreparedCommitment = (); impl PCPreparedCommitment for LigeroPCPreparedCommitment { - fn prepare(cm: &Unprepared) -> Self { + fn prepare(_cm: &Unprepared) -> Self { todo!() } } @@ -157,10 +157,10 @@ impl PCRandomness for LigeroPCRandomness { } fn rand( - num_queries: usize, - has_degree_bound: bool, - num_vars: Option, - rng: &mut R, + _num_queries: usize, + _has_degree_bound: bool, + _num_vars: Option, + _rng: &mut R, ) -> Self { todo!() } diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 361ccb62..0b5875f5 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -101,7 +101,7 @@ where // 1. Hash the received columns into leaf hashes let mut col_hashes: Vec> = Vec::new(); for c in proof.columns.iter() { - col_hashes.push(hash_column::(c).into()); + col_hashes.push(hash_column::(c)); } // 2. Compute t column indices to check the linear combination at @@ -168,7 +168,7 @@ where let ext_mat_cols = ext_mat.cols(); for col in ext_mat_cols.iter() { - col_hashes.push(hash_column::(col).into()); + col_hashes.push(hash_column::(col)); } // pad the column hashes with zeroes @@ -248,8 +248,8 @@ where fn setup( max_degree: usize, - num_vars: Option, - rng: &mut R, + _num_vars: Option, + _rng: &mut R, ) -> Result { assert!( rho_inv >= 1, @@ -259,14 +259,15 @@ where GeneralEvaluationDomain::::compute_size_of_domain(max_degree * (rho_inv - 1)) .ok_or(Error::UnsupportedDegreeBound(max_degree))?; - Ok(LigeroPCUniversalParams::default()) + LigeroPCUniversalParams::default(); + Ok(()) } fn trim( - pp: &Self::UniversalParams, - supported_degree: usize, - supported_hiding_bound: usize, - enforced_degree_bounds: Option<&[usize]>, + _pp: &Self::UniversalParams, + _supported_degree: usize, + _supported_hiding_bound: usize, + _enforced_degree_bounds: Option<&[usize]>, ) -> Result<(Self::CommitterKey, Self::VerifierKey), Self::Error> { todo!(); } @@ -274,7 +275,7 @@ where fn commit<'a>( ck: &Self::CommitterKey, polynomials: impl IntoIterator>, - rng: Option<&mut dyn RngCore>, + _rng: Option<&mut dyn RngCore>, ) -> Result< ( Vec>, @@ -416,8 +417,8 @@ where point: &'a P::Point, values: impl IntoIterator, proof: &Self::Proof, - challenge_generator: &mut crate::challenge::ChallengeGenerator, - rng: Option<&mut dyn RngCore>, + _challenge_generator: &mut crate::challenge::ChallengeGenerator, + _rng: Option<&mut dyn RngCore>, ) -> Result where Self::Commitment: 'a, @@ -493,7 +494,7 @@ where } if inner_product(&proof[i].v, &a) != values[i] { - println!("Funcion check: passed value at index {i} does not match prover's claimed value at the same infex"); + println!("Function check: claimed value in position {i} does not match the evaluation of the committed polynomial in the same position"); return Ok(false); } } diff --git a/src/ligero/tests.rs b/src/ligero/tests.rs index 672524ee..8423ebd4 100644 --- a/src/ligero/tests.rs +++ b/src/ligero/tests.rs @@ -73,7 +73,7 @@ mod tests { } #[test] - #[should_panic] + #[should_panic(expected = "dimensions are 2 x 3 but entry vector has 5 entries")] fn test_matrix_constructor_flat_panic() { let entries: Vec = to_field(vec![10, 100, 4, 67, 44]); Matrix::new_from_flat(2, 3, &entries); @@ -91,7 +91,7 @@ mod tests { } #[test] - #[should_panic] + #[should_panic(expected = "not all rows have the same length")] fn test_matrix_constructor_rows_panic() { let rows: Vec> = vec![ to_field(vec![10, 100, 4]), @@ -413,7 +413,7 @@ mod tests { } #[test] - #[should_panic] + #[should_panic(expected = "Mismatched lengths")] fn test_several_polynomials_mismatched_lengths() { // here we go through the same motions as in test_several_polynomials, // but pass to check() one fewer value than we should @@ -554,7 +554,7 @@ mod tests { } #[test] - #[should_panic] + #[should_panic()] fn test_several_polynomials_swap_values() { // in this test we work with three polynomials and swap the second // and third values passed to the verifier externally diff --git a/src/ligero/utils.rs b/src/ligero/utils.rs index 4faa884b..5016795c 100644 --- a/src/ligero/utils.rs +++ b/src/ligero/utils.rs @@ -70,12 +70,12 @@ impl Matrix { /// /// Index bound checks are waived for efficiency and behaviour under invalid indexing is undefined pub(crate) fn entry(&self, i: usize, j: usize) -> F { - return self.entries[i][j]; + self.entries[i][j] } /// Returns self as a list of rows pub(crate) fn rows(&self) -> Vec> { - return self.entries.clone(); + self.entries.clone() } /// Returns self as a list of columns @@ -149,10 +149,8 @@ pub(crate) fn reed_solomon( ); let poly_coeffs = domain.ifft(msg).to_vec(); - let extended_domain = GeneralEvaluationDomain::::new(m * rho_inv).expect(&format!( - "The field F cannot accomodate FFT for msg.len() * rho_inv = {} elements (too many)", - m * rho_inv - )); + let extended_domain = GeneralEvaluationDomain::::new(m * rho_inv).unwrap_or_else(|| panic!("The field F cannot accomodate FFT for msg.len() * rho_inv = {} elements (too many)", + m * rho_inv)); extended_domain.fft(&poly_coeffs) } @@ -206,7 +204,7 @@ pub(crate) fn get_indices_from_transcript( let mut indices = Vec::with_capacity(t); for _ in 0..t { let mut bytes: Vec = vec![0; bytes_to_squeeze]; - let _ = transcript + transcript .get_and_append_byte_challenge(b"i", &mut bytes) .unwrap(); @@ -219,7 +217,7 @@ pub(crate) fn get_indices_from_transcript( } #[inline] -pub(crate) fn calculate_t(rho_inv: usize, sec_param: usize) -> usize { +pub(crate) fn calculate_t(_rho_inv: usize, _sec_param: usize) -> usize { // TODO calculate t somehow let t = 3; println!("WARNING: you are using dummy t = {t}"); From ba00e0af12016fccb042ec8e6a2c8b04ec3ba1b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mej=C3=ADas=20Gil?= Date: Fri, 14 Jul 2023 10:41:50 +0200 Subject: [PATCH 082/108] formatted utils.rs --- src/ligero/utils.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/ligero/utils.rs b/src/ligero/utils.rs index 5016795c..c3e3ed2b 100644 --- a/src/ligero/utils.rs +++ b/src/ligero/utils.rs @@ -149,8 +149,12 @@ pub(crate) fn reed_solomon( ); let poly_coeffs = domain.ifft(msg).to_vec(); - let extended_domain = GeneralEvaluationDomain::::new(m * rho_inv).unwrap_or_else(|| panic!("The field F cannot accomodate FFT for msg.len() * rho_inv = {} elements (too many)", - m * rho_inv)); + let extended_domain = GeneralEvaluationDomain::::new(m * rho_inv).unwrap_or_else(|| { + panic!( + "The field F cannot accomodate FFT for msg.len() * rho_inv = {} elements (too many)", + m * rho_inv + ) + }); extended_domain.fft(&poly_coeffs) } From 4105abef4c2fd10620070c16955cdd1a3f660c17 Mon Sep 17 00:00:00 2001 From: mmagician Date: Mon, 11 Sep 2023 11:56:02 +0200 Subject: [PATCH 083/108] change the git dependency to rely on our own fork we dont yet want to have `AdditiveGroup` and other algebra changes post-0.4 in --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index e623f884..af142092 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ ark-serialize = { version = "^0.4.0", default-features = false, features = [ "de ark-ff = { version = "^0.4.0", default-features = false } ark-ec = { version = "^0.4.0", default-features = false } ark-poly = {version = "^0.4.0", default-features = false } -ark-crypto-primitives = { version = "^0.4.0", default-features = false, features = ["sponge","merkle_tree" ], git = "https://github.com/arkworks-rs/crypto-primitives" } +ark-crypto-primitives = { version = "^0.4.0", default-features = false, features = ["sponge","merkle_tree" ], git = "https://github.com/HungryCatsStudio/crypto-primitives" } ark-std = { version = "^0.4.0", default-features = false } ark-relations = { version = "^0.4.0", default-features = false, optional = true } From 1af21e59bc9f44bd7349bfe9af9df127e86fa000 Mon Sep 17 00:00:00 2001 From: mmagician Date: Mon, 11 Sep 2023 12:00:17 +0200 Subject: [PATCH 084/108] add back newline to gitignore --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 547bf087..be1aec0a 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,4 @@ Cargo.lock *.ipynb_checkpoints *.pyc *.sage.py -params \ No newline at end of file +params From ef6be5dee802ace669947a49c2ef8522cd1f64c5 Mon Sep 17 00:00:00 2001 From: mmagician Date: Mon, 25 Sep 2023 08:21:48 -0600 Subject: [PATCH 085/108] Well-formedness checks refactor (#24) * Add a flag for keeping the wellformedness check * Rename generics to capital case * WIP: Refactor many checks and data structure * Add the calculation of t * Make the calculation more precise * Fix some error handling and move around stuff * Adjust transcript order, make clippy a bit happy, and fix tests * fix: the loop over merkle paths should use a different index j * refactor: well-formedness check only contains `v` since we're using the same indices as for the opening proof, we can re-use these * remove outdated TODOs; update comments old todo fix some more commetns * rename `well_formedness_proof` var to `well_formedness` * replace panic by error handling * avoid vector size reallocation * replace into_iter with iter * Undo the change in `src/lib.rs` --------- Co-authored-by: Hossein Moghaddas --- src/error.rs | 9 + src/ligero/data_structures.rs | 38 +++- src/ligero/mod.rs | 374 +++++++++++++++++----------------- src/ligero/tests.rs | 45 ++-- src/ligero/utils.rs | 34 +++- 5 files changed, 282 insertions(+), 218 deletions(-) diff --git a/src/error.rs b/src/error.rs index de7091eb..0f883803 100644 --- a/src/error.rs +++ b/src/error.rs @@ -93,6 +93,13 @@ pub enum Error { /// Index of the offending polynomial. label: String, }, + + /// This means a failure in verifying the commitment or the opening. + InvalidCommitment, + + /// For PCS which rely on Fiat-Shamir to be rendered non-interactive, + /// these are errors that result from incorrect transcript manipulation. + TranscriptError, } impl core::fmt::Display for Error { @@ -179,6 +186,8 @@ impl core::fmt::Display for Error { support up to degree ({:?})", label, poly_degree, supported_degree ), Error::IncorrectInputLength(err) => write!(f, "{}", err), + Error::InvalidCommitment => write!(f, "Failed to verify the commitment"), + Error::TranscriptError => write!(f, "Incorrect transcript manipulation"), } } } diff --git a/src/ligero/data_structures.rs b/src/ligero/data_structures.rs index 159ac237..2322312a 100644 --- a/src/ligero/data_structures.rs +++ b/src/ligero/data_structures.rs @@ -26,9 +26,9 @@ pub struct Ligero< S: CryptographicSponge, P: DenseUVPolynomial, // one over the rate rho - const rho_inv: usize, + const RHO_INV: usize, // security parameter, used in calculating t - const sec_param: usize, + const SEC_PARAM: usize, > { pub(crate) _field: PhantomData, pub(crate) _config: PhantomData, @@ -41,7 +41,14 @@ pub struct Ligero< const DEFAULT_RHO_INV: usize = 2; const DEFAULT_SEC_PARAM: usize = 128; -pub(crate) type LigeroPCUniversalParams = (); +#[derive(Derivative, CanonicalSerialize, CanonicalDeserialize)] +#[derivative(Clone(bound = ""), Debug(bound = ""))] +pub struct LigeroPCUniversalParams { + /// number of rows resp. columns of the square matrix containing the coefficients of the polynomial + pub(crate) num_rows: usize, + pub(crate) num_cols: usize, + pub(crate) num_ext_cols: usize, +} impl PCUniversalParams for LigeroPCUniversalParams { fn max_degree(&self) -> usize { @@ -64,6 +71,8 @@ where #[derivative(Debug = "ignore")] /// Parameters for hash function of Merke tree combining two nodes into one pub two_to_one_params: TwoToOneParam, + /// This is a flag which determines if the random linear combination is done. + pub check_well_formedness: bool, } impl PCCommitterKey for LigeroPCCommitterKey @@ -93,6 +102,8 @@ where pub leaf_hash_params: LeafParam, /// Parameters for hash function of Merke tree combining two nodes into one pub two_to_one_params: TwoToOneParam, + /// This is a flag which determines if the random linear combination is done. + pub check_well_formedness: bool, } impl PCVerifierKey for LigeroPCVerifierKey @@ -122,16 +133,15 @@ impl PCPreparedVerifierKey for LigeroPCPr /// where each node is a hash of the column of the encoded coefficient matrix U. #[derive(Derivative, CanonicalSerialize, CanonicalDeserialize)] #[derivative(Default(bound = ""), Clone(bound = ""), Debug(bound = ""))] -pub struct LigeroPCCommitment { +pub struct LigeroPCCommitment { // number of rows resp. columns of the square matrix containing the coefficients of the polynomial pub(crate) n_rows: usize, pub(crate) n_cols: usize, pub(crate) n_ext_cols: usize, pub(crate) root: C::InnerDigest, - pub(crate) proof: LigeroPCProof, } -impl PCCommitment for LigeroPCCommitment { +impl PCCommitment for LigeroPCCommitment { fn empty() -> Self { todo!() } @@ -169,7 +179,7 @@ impl PCRandomness for LigeroPCRandomness { /// Proof of an individual Ligero well-formedness check or opening #[derive(Derivative, CanonicalSerialize, CanonicalDeserialize)] #[derivative(Default(bound = ""), Clone(bound = ""), Debug(bound = ""))] -pub struct LigeroPCProof +pub(crate) struct LigeroPCProofSingle where F: PrimeField, C: Config, @@ -184,4 +194,16 @@ where } /// The Proof type for Ligero, which amounts to an array of individual ligero proofs -pub type LigeroPCProofArray = Vec>; +#[derive(Derivative, CanonicalSerialize, CanonicalDeserialize)] +#[derivative(Default(bound = ""), Clone(bound = ""), Debug(bound = ""))] +pub struct LigeroPCProof +where + F: PrimeField, + C: Config, +{ + pub(crate) opening: LigeroPCProofSingle, + pub(crate) well_formedness: Option>, +} + +// Multiple poly at one point +pub(crate) type LPCPArray = Vec>; diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 0b5875f5..948c5b2a 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -1,6 +1,6 @@ use ark_crypto_primitives::crh::{CRHScheme, TwoToOneCRHScheme}; use ark_crypto_primitives::{ - merkle_tree::{Config, LeafParam, MerkleTree, TwoToOneParam}, + merkle_tree::{Config, MerkleTree}, sponge::{Absorb, CryptographicSponge}, }; use ark_ff::PrimeField; @@ -22,14 +22,14 @@ use utils::Matrix; mod data_structures; use data_structures::*; -pub use data_structures::{Ligero, LigeroPCCommitterKey, LigeroPCProofArray, LigeroPCVerifierKey}; +pub use data_structures::{Ligero, LigeroPCCommitterKey, LigeroPCProof, LigeroPCVerifierKey}; use utils::{calculate_t, compute_dimensions, get_indices_from_transcript, hash_column}; mod tests; -impl - Ligero +impl + Ligero where F: PrimeField, C: Config, @@ -52,91 +52,6 @@ where } } - /// The verifier can check the well-formedness of the commitment by taking random linear combinations. - fn check_well_formedness( - commitment: &LigeroPCCommitment, - leaf_hash_params: &LeafParam, - two_to_one_params: &TwoToOneParam, - ) -> Result<(), Error> { - let t = calculate_t(rho_inv, sec_param); - - // TODO replace unwraps by proper error handling - let mut transcript: IOPTranscript = IOPTranscript::new(b"well_formedness_transcript"); - transcript - .append_serializable_element(b"root", &commitment.root) - .unwrap(); - - // 2. Get the linear combination coefficients from the transcript - let mut r = Vec::new(); - for _ in 0..commitment.n_rows { - r.push(transcript.get_and_append_challenge(b"r").unwrap()); - } - // Upon sending `v` to the Verifier, add it to the sponge. Claim is that v = r.M - transcript - .append_serializable_element(b"v", &commitment.proof.v) - .unwrap(); - - Self::check_random_linear_combination( - &r, - &commitment.proof, - &commitment.root, - commitment.n_ext_cols, - t, - &mut transcript, - leaf_hash_params, - two_to_one_params, - ) - } - - fn check_random_linear_combination( - coeffs: &[F], - proof: &LigeroPCProof, - root: &C::InnerDigest, - n_ext_cols: usize, - t: usize, - transcript: &mut IOPTranscript, - leaf_hash_params: &<::LeafHash as CRHScheme>::Parameters, - two_to_one_params: &<::TwoToOneHash as TwoToOneCRHScheme>::Parameters, - ) -> Result<(), Error> { - // 1. Hash the received columns into leaf hashes - let mut col_hashes: Vec> = Vec::new(); - for c in proof.columns.iter() { - col_hashes.push(hash_column::(c)); - } - - // 2. Compute t column indices to check the linear combination at - let indices = get_indices_from_transcript::(n_ext_cols, t, transcript); - - // 3. Verify the paths for each of the leaf hashes - for (i, (leaf, q_i)) in col_hashes.into_iter().zip(indices.iter()).enumerate() { - // TODO handle the error here - let path = &proof.paths[i]; - assert!( - path.leaf_index == *q_i, - "Path is for a different index: i: {}, leaf index: {}!", - q_i, - path.leaf_index - ); // TODO return an error - - path.verify(leaf_hash_params, two_to_one_params, root, leaf.clone()) - .unwrap(); - } - - // 4. Compute the encoding w = E(v) - let w = reed_solomon(&proof.v, rho_inv); - - // 5. Verify the random linear combinations - for (transcript_index, matrix_index) in indices.into_iter().enumerate() { - if inner_product(coeffs, &proof.columns[transcript_index]) != w[matrix_index] { - // TODO return proper error - return Err(Error::IncorrectInputLength( - "Incorrect linear combination".to_string(), - )); - } - } - - Ok(()) - } fn compute_matrices(polynomial: &P) -> (Matrix, Matrix) { let mut coeffs = polynomial.coeffs().to_vec(); @@ -153,7 +68,7 @@ where let ext_mat = Matrix::new_from_rows( mat.rows() .iter() - .map(|r| reed_solomon(r, rho_inv)) + .map(|r| reed_solomon(r, RHO_INV)) .collect(), ); @@ -183,16 +98,18 @@ where ext_mat: &Matrix, col_tree: &MerkleTree, transcript: &mut IOPTranscript, - ) -> LigeroPCProof { - let t = calculate_t(rho_inv, sec_param); // TODO this function will now probably need to take into account the number of rows/cols of the extended matrix + ) -> Result, Error> { + let t = calculate_t(RHO_INV, SEC_PARAM); // TODO this function will now probably need to take into account the number of rows/cols of the extended matrix // 1. Compute the linear combination using the random coefficients let v = mat.row_mul(coeffs); - transcript.append_serializable_element(b"v", &v).unwrap(); + transcript + .append_serializable_element(b"v", &v) + .map_err(|_| Error::TranscriptError)?; // 2. Generate t column indices to test the linear combination on - let indices = get_indices_from_transcript(ext_mat.m, t, transcript); + let indices = get_indices_from_transcript(ext_mat.m, t, transcript)?; // 3. Compute Merkle tree paths for the columns let mut queried_columns = Vec::new(); @@ -202,19 +119,23 @@ where for i in indices { queried_columns.push(ext_mat_cols[i].clone()); - paths.push(col_tree.generate_proof(i).unwrap()); + paths.push( + col_tree + .generate_proof(i) + .map_err(|_| Error::TranscriptError)?, + ); } - LigeroPCProof { + Ok(LigeroPCProofSingle { paths, v, columns: queried_columns, - } + }) } } -impl PolynomialCommitment - for Ligero +impl PolynomialCommitment + for Ligero where F: PrimeField, P: DenseUVPolynomial, @@ -234,13 +155,13 @@ where type PreparedVerifierKey = LigeroPCPreparedVerifierKey; - type Commitment = LigeroPCCommitment; + type Commitment = LigeroPCCommitment; type PreparedCommitment = LigeroPCPreparedCommitment; type Randomness = LigeroPCRandomness; - type Proof = LigeroPCProofArray; + type Proof = LPCPArray; type BatchProof = Vec; @@ -252,15 +173,18 @@ where _rng: &mut R, ) -> Result { assert!( - rho_inv >= 1, - "rho_inv is the inverse of the rate and must be at least 1" + RHO_INV >= 1, + "RHO_INV is the inverse of the rate and must be at least 1" ); - // The domain will have size m * rho_inv, but we already have the first m elements - GeneralEvaluationDomain::::compute_size_of_domain(max_degree * (rho_inv - 1)) + // The domain will have size m * RHO_INV, but we already have the first m elements + GeneralEvaluationDomain::::compute_size_of_domain(max_degree * (RHO_INV - 1)) .ok_or(Error::UnsupportedDegreeBound(max_degree))?; - LigeroPCUniversalParams::default(); - Ok(()) + Ok(LigeroPCUniversalParams { + num_rows: 0, + num_cols: 0, + num_ext_cols: 0, + }) } fn trim( @@ -301,30 +225,22 @@ where // 3. Add root to transcript and generate random linear combination with it let root = col_tree.root(); - let mut transcript: IOPTranscript = - IOPTranscript::new(b"well_formedness_transcript"); + let mut transcript: IOPTranscript = IOPTranscript::new(b"transcript"); transcript .append_serializable_element(b"root", &root) - .unwrap(); + .map_err(|_| Error::TranscriptError)?; let n_rows = mat.n; let n_cols = mat.m; let n_ext_cols = ext_mat.m; - let mut r = Vec::new(); - for _ in 0..n_rows { - r.push(transcript.get_and_append_challenge(b"r").unwrap()); - } - // 4. Generate the proof by choosing random columns and proving their paths in the tree - let proof = Self::generate_proof(&r, &mat, &ext_mat, &col_tree, &mut transcript); let commitment = LigeroPCCommitment { n_rows, n_cols, n_ext_cols, root, - proof, }; commitments.push(LabeledCommitment::new( @@ -352,31 +268,24 @@ where Self::Randomness: 'a, Self::Commitment: 'a, { - let mut proof_array = LigeroPCProofArray::new(); + let mut proof_array = LPCPArray::default(); let labeled_commitments: Vec<&'a LabeledCommitment> = commitments.into_iter().collect(); let labeled_polynomials: Vec<&'a LabeledPolynomial> = labeled_polynomials.into_iter().collect(); - assert_eq!( - labeled_commitments.len(), - labeled_polynomials.len(), - // maybe return Err? - "Mismatched lengths: {} commitments, {} polynomials", - labeled_commitments.len(), - labeled_polynomials.len() - ); + if labeled_commitments.len() != labeled_polynomials.len() { + return Err(Error::IncorrectInputLength(format!( + "Mismatched lengths: {} commitments, {} polynomials", + labeled_commitments.len(), + labeled_polynomials.len() + ))); + } for i in 0..labeled_polynomials.len() { let polynomial = labeled_polynomials[i].polynomial(); let commitment = labeled_commitments[i].commitment(); - // TODO we receive a list of polynomials and a list of commitments - // are we to understand that the first commitment is for the first polynomial, ...etc? - - // TODO we should maybe check that these two lists match, but that would imply recomputing merkle trees... - // at least check labels? - // 1. Compute matrices let (mat, ext_mat) = Self::compute_matrices(polynomial); @@ -384,7 +293,7 @@ where let col_tree = Self::create_merkle_tree(&ext_mat, &ck.leaf_hash_params, &ck.two_to_one_params); - // 3. Generate vector b and add v = b·M to the transcript + // 3. Generate vector b let mut b = Vec::new(); let point_pow = point.pow([commitment.n_cols as u64]); // TODO this and other conversions could potentially fail let mut acc_b = F::one(); @@ -393,19 +302,41 @@ where acc_b *= point_pow; } - let mut transcript: IOPTranscript = IOPTranscript::new(b"opening_transcript"); + let mut transcript = IOPTranscript::new(b"transcript"); + transcript + .append_serializable_element(b"root", &commitment.root) + .map_err(|_| Error::TranscriptError)?; + + // If we are checking well-formedness, we need to compute the well-formedness proof (which is just r.M) and append it to the transcript. + let well_formedness = if ck.check_well_formedness { + let n_rows = mat.n; + let mut r = Vec::new(); + for _ in 0..n_rows { + r.push( + transcript + .get_and_append_challenge(b"r") + .map_err(|_| Error::TranscriptError)?, + ); + } + let v = mat.row_mul(&r); + + transcript + .append_serializable_element(b"v", &v) + .map_err(|_| Error::TranscriptError)?; + Some(v) + } else { + None + }; transcript .append_serializable_element(b"point", point) - .unwrap(); - - proof_array.push(Self::generate_proof( - &b, - &mat, - &ext_mat, - &col_tree, - &mut transcript, - )) + .map_err(|_| Error::TranscriptError)?; + + proof_array.push(LigeroPCProof { + // compute the opening proof and append b.M to the transcript + opening: Self::generate_proof(&b, &mat, &ext_mat, &col_tree, &mut transcript)?, + well_formedness, + }); } Ok(proof_array) @@ -416,7 +347,7 @@ where commitments: impl IntoIterator>, point: &'a P::Point, values: impl IntoIterator, - proof: &Self::Proof, + proof_array: &Self::Proof, _challenge_generator: &mut crate::challenge::ChallengeGenerator, _rng: Option<&mut dyn RngCore>, ) -> Result @@ -427,30 +358,50 @@ where commitments.into_iter().collect(); let values: Vec = values.into_iter().collect(); - let t = calculate_t(rho_inv, sec_param); // TODO include in ck/vk? - - if labeled_commitments.len() != proof.len() || labeled_commitments.len() != values.len() { - // maybe return Err? - panic!("Mismatched lengths: {} proofs were provided for {} commitments with {} claimed values", - labeled_commitments.len(), proof.len(), values.len()); + if labeled_commitments.len() != proof_array.len() + || labeled_commitments.len() != values.len() + { + return Err(Error::IncorrectInputLength( + format!( + "Mismatched lengths: {} proofs were provided for {} commitments with {} claimed values",labeled_commitments.len(), proof_array.len(), values.len() + ) + )); } for (i, labeled_commitment) in labeled_commitments.iter().enumerate() { let commitment = labeled_commitment.commitment(); - // TODO maybe check that the parameters have been calculated honestly (n_rows/cols/ext_cols); - // could they be used to cheat? - - // check if we've seen this commitment before. If not, we should verify it. - if Self::check_well_formedness(commitment, &vk.leaf_hash_params, &vk.two_to_one_params) - .is_err() - { - println!("Function check failed verification of well-formedness of commitment with index {i}"); - return Ok(false); - } + let mut transcript = IOPTranscript::new(b"transcript"); + transcript + .append_serializable_element(b"root", &commitment.root) + .map_err(|_| Error::TranscriptError)?; + + let out = if vk.check_well_formedness { + if proof_array[i].well_formedness.is_none() { + return Err(Error::InvalidCommitment); + } + let tmp = &proof_array[i].well_formedness.as_ref(); + let well_formedness = tmp.unwrap(); + let mut r = Vec::with_capacity(commitment.n_rows); + for _ in 0..commitment.n_rows { + r.push( + transcript + .get_and_append_challenge(b"r") + .map_err(|_| Error::TranscriptError)?, + ); + } + // Upon sending `v` to the Verifier, add it to the sponge. Claim is that v = r.M + transcript + .append_serializable_element(b"v", well_formedness) + .map_err(|_| Error::TranscriptError)?; + + (Some(well_formedness), Some(r)) + } else { + (None, None) + }; // 1. Compute a and b - let mut a = Vec::new(); + let mut a = Vec::with_capacity(commitment.n_cols); let mut acc_a = F::one(); for _ in 0..commitment.n_cols { a.push(acc_a); @@ -458,42 +409,95 @@ where } // by now acc_a = point^n_cols - let mut b = Vec::new(); + let mut b = Vec::with_capacity(commitment.n_rows); let mut acc_b = F::one(); for _ in 0..commitment.n_rows { b.push(acc_b); acc_b *= acc_a; } + let t = calculate_t(RHO_INV, SEC_PARAM); // TODO include in ck/vk? // 2. Seed the transcript with the point and generate t random indices - // TODO replace unwraps by proper error handling - let mut transcript: IOPTranscript = IOPTranscript::new(b"opening_transcript"); + // TODO Consider removing the evaluation point from the transcript. transcript .append_serializable_element(b"point", point) - .unwrap(); + .map_err(|_| Error::TranscriptError)?; transcript - .append_serializable_element(b"v", &proof[i].v) - .unwrap(); - - // 3. Check the linear combination in the proof - if Self::check_random_linear_combination( - &b, - &proof[i], - &commitment.root, - commitment.n_ext_cols, - t, - &mut transcript, - &vk.leaf_hash_params, - &vk.two_to_one_params, - ) - .is_err() - { - // I think this can never be called since check_random_linear_combination will panick itself; must improve error handling - println!("Function check failed verification of opening with index {i}"); - return Ok(false); + .append_serializable_element(b"v", &proof_array[i].opening.v) + .map_err(|_| Error::TranscriptError)?; + + // 3. Evaluate and check for the given point + let coeffs: &[F] = &b; + let root = &commitment.root; + let n_ext_cols = commitment.n_ext_cols; + let leaf_hash_params: &<::LeafHash as CRHScheme>::Parameters = + &vk.leaf_hash_params; + let two_to_one_params: &<::TwoToOneHash as TwoToOneCRHScheme>::Parameters = + &vk.two_to_one_params; + // 1. Hash the received columns into leaf hashes + let col_hashes: Vec<_> = proof_array[i] + .opening + .columns + .iter() + .map(|c| hash_column::(c)) + .collect(); + + // 2. Compute t column indices to check the linear combination at + let indices = get_indices_from_transcript::(n_ext_cols, t, &mut transcript)?; + + // 3. Verify the paths for each of the leaf hashes - this is only run once, + // even if we have a well-formedness check (i.e., we save sending and checking the columns). + // See "Concrete optimizations to the commitment scheme", p.12 of [Brakedown](https://eprint.iacr.org/2021/1043.pdf) + for (j, (leaf, q_j)) in col_hashes.iter().zip(indices.iter()).enumerate() { + let path = &proof_array[i].opening.paths[j]; + if path.leaf_index != *q_j { + return Err(Error::InvalidCommitment); + } + + path.verify(leaf_hash_params, two_to_one_params, root, leaf.clone()) + .map_err(|_| Error::InvalidCommitment)?; + } + + // 4. Compute the encoding w = E(v) + let w = reed_solomon(&proof_array[i].opening.v, RHO_INV); + + // helper closure for checking that a.b = c + let check_inner_product = |a, b, c| -> Result<(), Error> { + if inner_product(a, b) != c { + return Err(Error::InvalidCommitment); + } + + Ok(()) + }; + + // 5. Probabilistic checks that whatever the prover sent, + // matches with what the verifier computed for himself. + // Note: we sacrifice some code repetition in order not to repeat execution. + if let (Some(well_formedness), Some(r)) = out { + let w_well_formedness = reed_solomon(&well_formedness, RHO_INV); + for (transcript_index, matrix_index) in indices.iter().enumerate() { + check_inner_product( + &r, + &proof_array[i].opening.columns[transcript_index], + w_well_formedness[*matrix_index], + )?; + check_inner_product( + coeffs, + &proof_array[i].opening.columns[transcript_index], + w[*matrix_index], + )?; + } + } else { + for (transcript_index, matrix_index) in indices.iter().enumerate() { + check_inner_product( + coeffs, + &proof_array[i].opening.columns[transcript_index], + w[*matrix_index], + )?; + } } - if inner_product(&proof[i].v, &a) != values[i] { + if inner_product(&proof_array[i].opening.v, &a) != values[i] { println!("Function check: claimed value in position {i} does not match the evaluation of the committed polynomial in the same position"); return Ok(false); } diff --git a/src/ligero/tests.rs b/src/ligero/tests.rs index 8423ebd4..0ca1fa9b 100644 --- a/src/ligero/tests.rs +++ b/src/ligero/tests.rs @@ -53,10 +53,10 @@ mod tests { type MTConfig = MerkleTreeParams; type Sponge = PoseidonSponge; - type PC = Ligero; - type LigeroPCS = PC; - type LigeroPCS_F = - PC, rho_inv>; + type PC = Ligero; + type LigeroPCS = PC; + type LigeroPcsF = + PC, RHO_INV>; #[test] fn test_matrix_constructor_flat() { @@ -273,7 +273,7 @@ mod tests { // but the base field of bls12_381 doesnt have such large domains use ark_bls12_381::Fq as F_381; - assert_eq!(LigeroPCS_F::<5, F_381>::setup(10, None, rng).is_err(), true); + assert_eq!(LigeroPcsF::<5, F_381>::setup(10, None, rng).is_err(), true); } #[test] @@ -286,14 +286,17 @@ mod tests { let two_to_one_params = ::setup(&mut rng) .unwrap() .clone(); + let check_well_formedness = true; let ck: LigeroPCCommitterKey = LigeroPCCommitterKey { leaf_hash_params, two_to_one_params, + check_well_formedness, }; let vk: LigeroPCVerifierKey = LigeroPCVerifierKey { leaf_hash_params, two_to_one_params, + check_well_formedness, }; let rand_chacha = &mut ChaCha20Rng::from_rng(test_rng()).unwrap(); @@ -314,15 +317,15 @@ mod tests { let mut challenge_generator: ChallengeGenerator> = ChallengeGenerator::new_univariate(&mut test_sponge); - assert!( - LigeroPCS::<2>::check_well_formedness( - &c[0].commitment(), - &leaf_hash_params, - &two_to_one_params - ) - .is_ok(), - "Well formedness check failed" - ); + // assert!( + // LigeroPCS::<2>::check_well_formedness( + // &c[0].commitment(), + // &leaf_hash_params, + // &two_to_one_params + // ) + // .is_ok(), + // "Well formedness check failed" + // ); let proof = LigeroPCS::<2>::open( &ck, @@ -356,14 +359,17 @@ mod tests { let two_to_one_params = ::setup(&mut rng) .unwrap() .clone(); + let check_well_formedness = true; let ck: LigeroPCCommitterKey = LigeroPCCommitterKey { leaf_hash_params, two_to_one_params, + check_well_formedness, }; let vk: LigeroPCVerifierKey = LigeroPCVerifierKey { leaf_hash_params, two_to_one_params, + check_well_formedness, }; let rand_chacha = &mut ChaCha20Rng::from_rng(test_rng()).unwrap(); @@ -426,13 +432,16 @@ mod tests { .unwrap() .clone(); + let check_well_formedness = true; let ck: LigeroPCCommitterKey = LigeroPCCommitterKey { leaf_hash_params, two_to_one_params, + check_well_formedness, }; let vk: LigeroPCVerifierKey = LigeroPCVerifierKey { leaf_hash_params, two_to_one_params, + check_well_formedness, }; let rand_chacha = &mut ChaCha20Rng::from_rng(test_rng()).unwrap(); @@ -493,14 +502,17 @@ mod tests { let two_to_one_params = ::setup(&mut rng) .unwrap() .clone(); + let check_well_formedness = true; let ck: LigeroPCCommitterKey = LigeroPCCommitterKey { leaf_hash_params, two_to_one_params, + check_well_formedness, }; let vk: LigeroPCVerifierKey = LigeroPCVerifierKey { leaf_hash_params, two_to_one_params, + check_well_formedness, }; let rand_chacha = &mut ChaCha20Rng::from_rng(test_rng()).unwrap(); @@ -554,7 +566,7 @@ mod tests { } #[test] - #[should_panic()] + #[should_panic] fn test_several_polynomials_swap_values() { // in this test we work with three polynomials and swap the second // and third values passed to the verifier externally @@ -566,14 +578,17 @@ mod tests { let two_to_one_params = ::setup(&mut rng) .unwrap() .clone(); + let check_well_formedness = true; let ck: LigeroPCCommitterKey = LigeroPCCommitterKey { leaf_hash_params, two_to_one_params, + check_well_formedness, }; let vk: LigeroPCVerifierKey = LigeroPCVerifierKey { leaf_hash_params, two_to_one_params, + check_well_formedness, }; let rand_chacha = &mut ChaCha20Rng::from_rng(test_rng()).unwrap(); diff --git a/src/ligero/utils.rs b/src/ligero/utils.rs index c3e3ed2b..11692cea 100644 --- a/src/ligero/utils.rs +++ b/src/ligero/utils.rs @@ -10,6 +10,7 @@ use rayon::{ }; use crate::streaming_kzg::ceil_div; +use crate::Error; #[derive(Debug)] pub(crate) struct Matrix { @@ -130,7 +131,7 @@ pub(crate) fn compute_dimensions(n: usize) -> (usize, usize) { /// Apply reed-solomon encoding to msg. /// Assumes msg.len() is equal to the order of an FFT domain in F. -/// Returns a vector of length equal to the smallest FFT domain of size at least msg.len() * rho_inv. +/// Returns a vector of length equal to the smallest FFT domain of size at least msg.len() * RHO_INV. pub(crate) fn reed_solomon( // msg, of length m, is interpreted as a vector of coefficients of a polynomial of degree m - 1 msg: &[F], @@ -151,7 +152,7 @@ pub(crate) fn reed_solomon( let extended_domain = GeneralEvaluationDomain::::new(m * rho_inv).unwrap_or_else(|| { panic!( - "The field F cannot accomodate FFT for msg.len() * rho_inv = {} elements (too many)", + "The field F cannot accomodate FFT for msg.len() * RHO_INV = {} elements (too many)", m * rho_inv ) }); @@ -203,27 +204,40 @@ pub(crate) fn get_indices_from_transcript( n: usize, t: usize, transcript: &mut IOPTranscript, -) -> Vec { +) -> Result, Error> { let bytes_to_squeeze = get_num_bytes(n); let mut indices = Vec::with_capacity(t); for _ in 0..t { let mut bytes: Vec = vec![0; bytes_to_squeeze]; transcript .get_and_append_byte_challenge(b"i", &mut bytes) - .unwrap(); + .map_err(|_| Error::TranscriptError)?; // get the usize from Vec: let ind = bytes.iter().fold(0, |acc, &x| (acc << 8) + x as usize); // modulo the number of columns in the encoded matrix indices.push(ind % n); } - indices + Ok(indices) } #[inline] -pub(crate) fn calculate_t(_rho_inv: usize, _sec_param: usize) -> usize { - // TODO calculate t somehow - let t = 3; - println!("WARNING: you are using dummy t = {t}"); - t +pub(crate) fn calculate_t(rho_inv: usize, sec_param: usize) -> usize { + // Double-check with BCI+20 if you can simply replace + // $\delta = \frac{1-\rho}{3}$ with $\frac{1-\rho}{2}$. In that case, we + // will find the smallest t such that + // $(1-\delta)^t + (\rho+\delta)^t + n/F < 2^(-\lambda)$. Since we do not + // have $n/F$ here and and it is negligible for security less than 230 bits, + // we eliminate it here. With \delta = \frac{1-\rho}{2}, the expreesion is + // 2 * (1-\delta)^t < 2^(-\lambda). Then + // $t * log2 (1-\delta) < - \lambda - 1$. + + // TODO: Maybe we should not eliminate $n/F$. In original Ligero, this was + // $d/F$ for $\delta = \frac{1-\rho}{3}$. But from expression 1.1 from + // BCI+20, I wrote $n/F$ for $\delta = \frac{1-\rho}{3}$. It is negligible + // anyways. + let sec_param = sec_param as f64; + let nom = -sec_param - 1.0; + let denom = (0.5 + 0.5 / rho_inv as f64).log2(); + (nom / denom).ceil() as usize // This is the `t` } From 1e3afeeca4ca2cb7925922ab349ab47014017925 Mon Sep 17 00:00:00 2001 From: mmagician Date: Mon, 25 Sep 2023 09:05:40 -0600 Subject: [PATCH 086/108] Change encoding function (#25) * reed_solomon -> linear_encode; no longer doing iFFT + FFT; just FFT now * revert naming `linear_encode` -> `reed_solomon` * Update src/ligero/tests.rs --- src/ligero/tests.rs | 21 +++------------------ src/ligero/utils.rs | 13 +------------ 2 files changed, 4 insertions(+), 30 deletions(-) diff --git a/src/ligero/tests.rs b/src/ligero/tests.rs index 0ca1fa9b..93d970f1 100644 --- a/src/ligero/tests.rs +++ b/src/ligero/tests.rs @@ -130,7 +130,7 @@ mod tests { } #[test] - fn test_reed_solomon() { + fn test_encoding() { // we use this polynomial to generate the the values we will ask the fft to interpolate let rho_inv = 3; @@ -147,25 +147,10 @@ mod tests { let coeffs = &pol.coeffs; - let small_domain = GeneralEvaluationDomain::::new(deg + 1).unwrap(); - // size of evals might be larger than deg + 1 (the min. number of evals needed to interpolate): we could still do R-S encoding on smaller evals, but the resulting polynomial will differ, so for this test to work we should pass it in full - let evals = small_domain.fft(&coeffs); - let m = evals.len(); - - // checking that ifft is really the inverse of fft - let coeffs_again = small_domain.ifft(&evals); - - assert_eq!(coeffs_again[..deg + 1], *coeffs); + let m = deg + 1; - let encoded = reed_solomon(&evals, rho_inv); - let m_p = encoded.len(); - - // the m original elements should be interleaved in the encoded message - let ratio = m_p / m; - for j in 0..m { - assert_eq!(evals[j], encoded[j * ratio]); - } + let encoded = reed_solomon(&coeffs, rho_inv); let large_domain = GeneralEvaluationDomain::::new(m * rho_inv).unwrap(); diff --git a/src/ligero/utils.rs b/src/ligero/utils.rs index 11692cea..2f9c140c 100644 --- a/src/ligero/utils.rs +++ b/src/ligero/utils.rs @@ -139,17 +139,6 @@ pub(crate) fn reed_solomon( ) -> Vec { let m = msg.len(); - let domain = GeneralEvaluationDomain::::new(m).unwrap(); - assert_eq!( - m, - domain.size(), - "The evaluation vector has length {} elements \\ - but the smallest FFT domain admitting that many elements has order {}", - m, - domain.size() - ); - let poly_coeffs = domain.ifft(msg).to_vec(); - let extended_domain = GeneralEvaluationDomain::::new(m * rho_inv).unwrap_or_else(|| { panic!( "The field F cannot accomodate FFT for msg.len() * RHO_INV = {} elements (too many)", @@ -157,7 +146,7 @@ pub(crate) fn reed_solomon( ) }); - extended_domain.fft(&poly_coeffs) + extended_domain.fft(&msg) } #[inline] From 01a0f94a80efe1b3ca942c831ea0e14989c613f3 Mon Sep 17 00:00:00 2001 From: Hossein Moghaddas Date: Tue, 26 Sep 2023 11:22:35 +0200 Subject: [PATCH 087/108] Change the signature of `calculate_t` --- src/ligero/utils.rs | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/ligero/utils.rs b/src/ligero/utils.rs index 2f9c140c..8fe31b3b 100644 --- a/src/ligero/utils.rs +++ b/src/ligero/utils.rs @@ -211,22 +211,23 @@ pub(crate) fn get_indices_from_transcript( } #[inline] -pub(crate) fn calculate_t(rho_inv: usize, sec_param: usize) -> usize { - // Double-check with BCI+20 if you can simply replace - // $\delta = \frac{1-\rho}{3}$ with $\frac{1-\rho}{2}$. In that case, we - // will find the smallest t such that - // $(1-\delta)^t + (\rho+\delta)^t + n/F < 2^(-\lambda)$. Since we do not - // have $n/F$ here and and it is negligible for security less than 230 bits, - // we eliminate it here. With \delta = \frac{1-\rho}{2}, the expreesion is - // 2 * (1-\delta)^t < 2^(-\lambda). Then - // $t * log2 (1-\delta) < - \lambda - 1$. - - // TODO: Maybe we should not eliminate $n/F$. In original Ligero, this was - // $d/F$ for $\delta = \frac{1-\rho}{3}$. But from expression 1.1 from - // BCI+20, I wrote $n/F$ for $\delta = \frac{1-\rho}{3}$. It is negligible - // anyways. - let sec_param = sec_param as f64; - let nom = -sec_param - 1.0; +pub(crate) fn calculate_t( + rho_inv: usize, + sec_param: usize, + block_length: usize, +) -> usize { + // Took from the analysis by BCI+20 and Ligero + // We will find the smallest $t$ such that + // $(1-\delta)^t + (\rho+\delta)^t + \frac{n}{F} < 2^{-\lambda}$. + // With $\delta = \frac{1-\rho}{2}$, the expreesion is + // $2 * (\frac{1+\rho}{2})^t + \frac{n}{F} < 2^(-\lambda)$. + + let block_length = block_length as i32; + let field_bits = F::MODULUS_BIT_SIZE as i32; + let sec_param = sec_param as i32; + + let residual = block_length as f64 / 2.0_f64.powi(field_bits); + let nom = (2.0_f64.powi(-sec_param) - residual).log2() - 1.0; let denom = (0.5 + 0.5 / rho_inv as f64).log2(); (nom / denom).ceil() as usize // This is the `t` } From c61ec6d038e37901f7082d3af4ca27cfb99d3556 Mon Sep 17 00:00:00 2001 From: Hossein Moghaddas Date: Tue, 26 Sep 2023 11:38:02 +0200 Subject: [PATCH 088/108] Rebase to `ligero` and fixing callers of `calculate_t` --- src/ligero/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 948c5b2a..d7e2ba20 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -99,7 +99,7 @@ where col_tree: &MerkleTree, transcript: &mut IOPTranscript, ) -> Result, Error> { - let t = calculate_t(RHO_INV, SEC_PARAM); // TODO this function will now probably need to take into account the number of rows/cols of the extended matrix + let t = calculate_t::(RHO_INV, SEC_PARAM,ext_mat.n); // TODO this function will now probably need to take into account the number of rows/cols of the extended matrix // 1. Compute the linear combination using the random coefficients let v = mat.row_mul(coeffs); @@ -415,7 +415,7 @@ where b.push(acc_b); acc_b *= acc_a; } - let t = calculate_t(RHO_INV, SEC_PARAM); // TODO include in ck/vk? + let t = calculate_t::(RHO_INV, SEC_PARAM, commitment.n_ext_cols); // TODO include in ck/vk? // 2. Seed the transcript with the point and generate t random indices // TODO Consider removing the evaluation point from the transcript. From 498613d05d5cc524797a5d64a85935372f122812 Mon Sep 17 00:00:00 2001 From: Hossein Moghaddas Date: Tue, 26 Sep 2023 11:42:52 +0200 Subject: [PATCH 089/108] Delete extra TODO --- src/ligero/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index d7e2ba20..18d8780e 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -99,7 +99,7 @@ where col_tree: &MerkleTree, transcript: &mut IOPTranscript, ) -> Result, Error> { - let t = calculate_t::(RHO_INV, SEC_PARAM,ext_mat.n); // TODO this function will now probably need to take into account the number of rows/cols of the extended matrix + let t = calculate_t::(RHO_INV, SEC_PARAM, ext_mat.n); // 1. Compute the linear combination using the random coefficients let v = mat.row_mul(coeffs); @@ -415,7 +415,7 @@ where b.push(acc_b); acc_b *= acc_a; } - let t = calculate_t::(RHO_INV, SEC_PARAM, commitment.n_ext_cols); // TODO include in ck/vk? + let t = calculate_t::(RHO_INV, SEC_PARAM, commitment.n_ext_cols); // 2. Seed the transcript with the point and generate t random indices // TODO Consider removing the evaluation point from the transcript. From d5b7e6fad5189804c43c6d66e9845549fd9290b2 Mon Sep 17 00:00:00 2001 From: Hossein Moghaddas Date: Tue, 26 Sep 2023 13:51:01 +0200 Subject: [PATCH 090/108] Add sanity check for `t` --- src/error.rs | 5 +++++ src/ligero/mod.rs | 6 ++++-- src/ligero/utils.rs | 14 +++++++++----- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/error.rs b/src/error.rs index 0f883803..478d2427 100644 --- a/src/error.rs +++ b/src/error.rs @@ -100,6 +100,10 @@ pub enum Error { /// For PCS which rely on Fiat-Shamir to be rendered non-interactive, /// these are errors that result from incorrect transcript manipulation. TranscriptError, + + /// This means the required soundness error bound is inherently impossible. + /// E.g., the field is not big enough. + InvalidSecurityGuarantee, } impl core::fmt::Display for Error { @@ -188,6 +192,7 @@ impl core::fmt::Display for Error { Error::IncorrectInputLength(err) => write!(f, "{}", err), Error::InvalidCommitment => write!(f, "Failed to verify the commitment"), Error::TranscriptError => write!(f, "Incorrect transcript manipulation"), + Error::InvalidSecurityGuarantee => write!(f, "The required bound on soundness error is impossible"), } } } diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 18d8780e..698a594a 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -99,7 +99,8 @@ where col_tree: &MerkleTree, transcript: &mut IOPTranscript, ) -> Result, Error> { - let t = calculate_t::(RHO_INV, SEC_PARAM, ext_mat.n); + let t = calculate_t::(RHO_INV, SEC_PARAM, ext_mat.n) + .map_err(|_| Error::InvalidSecurityGuarantee)?; // 1. Compute the linear combination using the random coefficients let v = mat.row_mul(coeffs); @@ -415,7 +416,8 @@ where b.push(acc_b); acc_b *= acc_a; } - let t = calculate_t::(RHO_INV, SEC_PARAM, commitment.n_ext_cols); + let t = calculate_t::(RHO_INV, SEC_PARAM, commitment.n_ext_cols) + .map_err(|_| Error::TranscriptError)?; // 2. Seed the transcript with the point and generate t random indices // TODO Consider removing the evaluation point from the transcript. diff --git a/src/ligero/utils.rs b/src/ligero/utils.rs index 8fe31b3b..8ed85447 100644 --- a/src/ligero/utils.rs +++ b/src/ligero/utils.rs @@ -214,20 +214,24 @@ pub(crate) fn get_indices_from_transcript( pub(crate) fn calculate_t( rho_inv: usize, sec_param: usize, - block_length: usize, -) -> usize { + codeword_len: usize, +) -> Result { // Took from the analysis by BCI+20 and Ligero // We will find the smallest $t$ such that // $(1-\delta)^t + (\rho+\delta)^t + \frac{n}{F} < 2^{-\lambda}$. // With $\delta = \frac{1-\rho}{2}$, the expreesion is // $2 * (\frac{1+\rho}{2})^t + \frac{n}{F} < 2^(-\lambda)$. - let block_length = block_length as i32; + let codeword_len = codeword_len as i32; let field_bits = F::MODULUS_BIT_SIZE as i32; let sec_param = sec_param as i32; - let residual = block_length as f64 / 2.0_f64.powi(field_bits); + let residual = codeword_len as f64 / 2.0_f64.powi(field_bits); + let rhs = 2.0_f64.powi(-sec_param) - residual; + if !(rhs > 0.0) { + return Err(Error::InvalidSecurityGuarantee); + } let nom = (2.0_f64.powi(-sec_param) - residual).log2() - 1.0; let denom = (0.5 + 0.5 / rho_inv as f64).log2(); - (nom / denom).ceil() as usize // This is the `t` + Ok((nom / denom).ceil() as usize) // This is the `t` } From e1e5a1f91a4bf9b7a73836b5452e63a3e16d49e8 Mon Sep 17 00:00:00 2001 From: Hossein Moghaddas Date: Tue, 26 Sep 2023 14:08:19 +0200 Subject: [PATCH 091/108] Use `is_normal` instead of manual check --- src/ligero/utils.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ligero/utils.rs b/src/ligero/utils.rs index 8ed85447..9aaed53d 100644 --- a/src/ligero/utils.rs +++ b/src/ligero/utils.rs @@ -227,11 +227,11 @@ pub(crate) fn calculate_t( let sec_param = sec_param as i32; let residual = codeword_len as f64 / 2.0_f64.powi(field_bits); - let rhs = 2.0_f64.powi(-sec_param) - residual; - if !(rhs > 0.0) { + let rhs = (2.0_f64.powi(-sec_param) - residual).log2(); + if !(rhs.is_normal()) { return Err(Error::InvalidSecurityGuarantee); } - let nom = (2.0_f64.powi(-sec_param) - residual).log2() - 1.0; + let nom = rhs - 1.0; let denom = (0.5 + 0.5 / rho_inv as f64).log2(); Ok((nom / denom).ceil() as usize) // This is the `t` } From bce06707be4ac14653952eff8e08c52957fac867 Mon Sep 17 00:00:00 2001 From: Hossein Moghaddas Date: Tue, 26 Sep 2023 14:16:41 +0200 Subject: [PATCH 092/108] Delete `map_error` since it was unnecessary --- src/ligero/mod.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 698a594a..8842b069 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -99,8 +99,7 @@ where col_tree: &MerkleTree, transcript: &mut IOPTranscript, ) -> Result, Error> { - let t = calculate_t::(RHO_INV, SEC_PARAM, ext_mat.n) - .map_err(|_| Error::InvalidSecurityGuarantee)?; + let t = calculate_t::(RHO_INV, SEC_PARAM, ext_mat.n)?; // 1. Compute the linear combination using the random coefficients let v = mat.row_mul(coeffs); @@ -416,8 +415,7 @@ where b.push(acc_b); acc_b *= acc_a; } - let t = calculate_t::(RHO_INV, SEC_PARAM, commitment.n_ext_cols) - .map_err(|_| Error::TranscriptError)?; + let t = calculate_t::(RHO_INV, SEC_PARAM, commitment.n_ext_cols)?; // 2. Seed the transcript with the point and generate t random indices // TODO Consider removing the evaluation point from the transcript. From 7abaffbdd6d455a4509ad823e8fc121872afaecf Mon Sep 17 00:00:00 2001 From: Hossein Moghaddas Date: Tue, 26 Sep 2023 14:57:40 +0200 Subject: [PATCH 093/108] Add test for `calculate_t` --- src/ligero/tests.rs | 12 ++++++++++++ src/ligero/utils.rs | 4 ++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/ligero/tests.rs b/src/ligero/tests.rs index 93d970f1..43d8c617 100644 --- a/src/ligero/tests.rs +++ b/src/ligero/tests.rs @@ -625,4 +625,16 @@ mod tests { ) .unwrap()); } + + #[test] + fn test_calculate_t_with_good_parameters() { + assert!(calculate_t::(4, 128, 2_usize.pow(32)).unwrap() < 200); + assert!(calculate_t::(4, 256, 2_usize.pow(32)).unwrap() < 400); + } + + #[test] + fn test_calculate_t_with_bad_parameters() { + calculate_t::(4, 317, 2_usize.pow(Fq::MODULUS_BIT_SIZE - 317)).unwrap_err(); + calculate_t::(4, 400, 2_usize.pow(32)).unwrap_err(); + } } diff --git a/src/ligero/utils.rs b/src/ligero/utils.rs index 9aaed53d..bd7b35e3 100644 --- a/src/ligero/utils.rs +++ b/src/ligero/utils.rs @@ -222,11 +222,11 @@ pub(crate) fn calculate_t( // With $\delta = \frac{1-\rho}{2}$, the expreesion is // $2 * (\frac{1+\rho}{2})^t + \frac{n}{F} < 2^(-\lambda)$. - let codeword_len = codeword_len as i32; + let codeword_len = codeword_len as f64; let field_bits = F::MODULUS_BIT_SIZE as i32; let sec_param = sec_param as i32; - let residual = codeword_len as f64 / 2.0_f64.powi(field_bits); + let residual = codeword_len / 2.0_f64.powi(field_bits); let rhs = (2.0_f64.powi(-sec_param) - residual).log2(); if !(rhs.is_normal()) { return Err(Error::InvalidSecurityGuarantee); From 61d58fec803922f9f26498ad8bc1218add57b537 Mon Sep 17 00:00:00 2001 From: mmagician Date: Tue, 26 Sep 2023 07:49:02 -0600 Subject: [PATCH 094/108] Cleanup (#26) * checking RHO_INV >=1 is too verbose of a sanity check * default params are not used * Revert "checking RHO_INV >=1 is too verbose of a sanity check" This reverts commit fdc1f717cd634e0d550c4c39307719a56288fc4b. * rename `InvalidSecurityGuarantee` -> `InvalidParameters`; add string err * replace assert with error handling in setup ensure that RHO_INV > 1 * fix error formatting * fix: swap the condidtion on RHO_INV * Improve error description Co-authored-by: Hossein Moghaddas --------- Co-authored-by: Hossein Moghaddas --- src/error.rs | 4 ++-- src/ligero/data_structures.rs | 4 ---- src/ligero/mod.rs | 9 +++++---- src/ligero/utils.rs | 2 +- 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/error.rs b/src/error.rs index 478d2427..1daf45b0 100644 --- a/src/error.rs +++ b/src/error.rs @@ -103,7 +103,7 @@ pub enum Error { /// This means the required soundness error bound is inherently impossible. /// E.g., the field is not big enough. - InvalidSecurityGuarantee, + InvalidParameters(String), } impl core::fmt::Display for Error { @@ -192,7 +192,7 @@ impl core::fmt::Display for Error { Error::IncorrectInputLength(err) => write!(f, "{}", err), Error::InvalidCommitment => write!(f, "Failed to verify the commitment"), Error::TranscriptError => write!(f, "Incorrect transcript manipulation"), - Error::InvalidSecurityGuarantee => write!(f, "The required bound on soundness error is impossible"), + Error::InvalidParameters(err) => write!(f, "{}", err), } } } diff --git a/src/ligero/data_structures.rs b/src/ligero/data_structures.rs index 2322312a..22cb8ee0 100644 --- a/src/ligero/data_structures.rs +++ b/src/ligero/data_structures.rs @@ -37,10 +37,6 @@ pub struct Ligero< pub(crate) _poly: PhantomData

, } -// TODO come up with reasonable defaults -const DEFAULT_RHO_INV: usize = 2; -const DEFAULT_SEC_PARAM: usize = 128; - #[derive(Derivative, CanonicalSerialize, CanonicalDeserialize)] #[derivative(Clone(bound = ""), Debug(bound = ""))] pub struct LigeroPCUniversalParams { diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 8842b069..f4e7322b 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -172,10 +172,11 @@ where _num_vars: Option, _rng: &mut R, ) -> Result { - assert!( - RHO_INV >= 1, - "RHO_INV is the inverse of the rate and must be at least 1" - ); + if RHO_INV <= 1 { + return Err(Error::InvalidParameters(format!( + "RHO_INV must be an interger greater than 1", + ))); + } // The domain will have size m * RHO_INV, but we already have the first m elements GeneralEvaluationDomain::::compute_size_of_domain(max_degree * (RHO_INV - 1)) .ok_or(Error::UnsupportedDegreeBound(max_degree))?; diff --git a/src/ligero/utils.rs b/src/ligero/utils.rs index bd7b35e3..fed882cc 100644 --- a/src/ligero/utils.rs +++ b/src/ligero/utils.rs @@ -229,7 +229,7 @@ pub(crate) fn calculate_t( let residual = codeword_len / 2.0_f64.powi(field_bits); let rhs = (2.0_f64.powi(-sec_param) - residual).log2(); if !(rhs.is_normal()) { - return Err(Error::InvalidSecurityGuarantee); + return Err(Error::InvalidParameters("For the given codeword length and the required security guarantee, the field is not big enough.".to_string())); } let nom = rhs - 1.0; let denom = (0.5 + 0.5 / rho_inv as f64).log2(); From 356ecd8e4859652c1e18076e6b2ebae57fbef72a Mon Sep 17 00:00:00 2001 From: Hossein Moghaddas Date: Thu, 28 Sep 2023 10:06:23 +0200 Subject: [PATCH 095/108] Implementation of `setup` and `trim` + Update tests + Clean up (#28) * Change `setup` * Make `setup` and `trim` compatible to arkworks, use a default setup, remove some generics Co-authored-by: mmagician * Fix tests Co-authored-by: mmagician * Add `Metadate` and clean up --------- Co-authored-by: mmagician --- src/ligero/data_structures.rs | 107 +++++++++++---- src/ligero/mod.rs | 206 ++++++++++++++++------------ src/ligero/tests.rs | 243 +++++++++++++++++++--------------- src/ligero/utils.rs | 2 +- 4 files changed, 336 insertions(+), 222 deletions(-) diff --git a/src/ligero/data_structures.rs b/src/ligero/data_structures.rs index 22cb8ee0..f424306d 100644 --- a/src/ligero/data_structures.rs +++ b/src/ligero/data_structures.rs @@ -25,10 +25,6 @@ pub struct Ligero< D: Digest, S: CryptographicSponge, P: DenseUVPolynomial, - // one over the rate rho - const RHO_INV: usize, - // security parameter, used in calculating t - const SEC_PARAM: usize, > { pub(crate) _field: PhantomData, pub(crate) _config: PhantomData, @@ -39,81 +35,129 @@ pub struct Ligero< #[derive(Derivative, CanonicalSerialize, CanonicalDeserialize)] #[derivative(Clone(bound = ""), Debug(bound = ""))] -pub struct LigeroPCUniversalParams { - /// number of rows resp. columns of the square matrix containing the coefficients of the polynomial - pub(crate) num_rows: usize, - pub(crate) num_cols: usize, - pub(crate) num_ext_cols: usize, +pub struct LigeroPCUniversalParams +where + C: Config, + <::TwoToOneHash as TwoToOneCRHScheme>::Parameters: Debug, + <::LeafHash as CRHScheme>::Parameters: Debug, +{ + pub _field: PhantomData, + /// The security parameter + pub sec_param: usize, + /// The inverse of the code rate. + pub rho_inv: usize, + /// This is a flag which determines if the random linear combination is done. + pub check_well_formedness: bool, + /// Parameters for hash function of Merkle tree leaves + #[derivative(Debug = "ignore")] + pub leaf_hash_params: LeafParam, + /// Parameters for hash function of Merke tree combining two nodes into one + #[derivative(Debug = "ignore")] + pub two_to_one_params: TwoToOneParam, } -impl PCUniversalParams for LigeroPCUniversalParams { +impl PCUniversalParams for LigeroPCUniversalParams +where + F: PrimeField, + C: Config, + <::TwoToOneHash as TwoToOneCRHScheme>::Parameters: Debug, + <::LeafHash as CRHScheme>::Parameters: Debug, +{ fn max_degree(&self) -> usize { - todo!() + if F::TWO_ADICITY < self.rho_inv as u32 { + 0 + } else if (F::TWO_ADICITY - self.rho_inv as u32) * 2 < 64 { + 2_usize.pow((F::TWO_ADICITY - self.rho_inv as u32) * 2) + } else { + usize::MAX + } } } /// Ligero commitment structure #[derive(Derivative, CanonicalSerialize, CanonicalDeserialize)] #[derivative(Clone(bound = ""), Debug(bound = ""))] -pub struct LigeroPCCommitterKey +pub struct LigeroPCCommitterKey where + F: PrimeField, C: Config, <::TwoToOneHash as TwoToOneCRHScheme>::Parameters: Debug, <::LeafHash as CRHScheme>::Parameters: Debug, { - #[derivative(Debug = "ignore")] + pub(crate) _field: PhantomData, + /// The security parameter + pub(crate) sec_param: usize, + /// The inverse of code rate + pub(crate) rho_inv: usize, /// Parameters for hash function of Merkle tree leaves - pub leaf_hash_params: LeafParam, #[derivative(Debug = "ignore")] + pub(crate) leaf_hash_params: LeafParam, /// Parameters for hash function of Merke tree combining two nodes into one - pub two_to_one_params: TwoToOneParam, + #[derivative(Debug = "ignore")] + pub(crate) two_to_one_params: TwoToOneParam, /// This is a flag which determines if the random linear combination is done. - pub check_well_formedness: bool, + pub(crate) check_well_formedness: bool, } -impl PCCommitterKey for LigeroPCCommitterKey +impl PCCommitterKey for LigeroPCCommitterKey where + F: PrimeField, C: Config, <::TwoToOneHash as TwoToOneCRHScheme>::Parameters: Debug, <::LeafHash as CRHScheme>::Parameters: Debug, { fn max_degree(&self) -> usize { - todo!() + if (F::TWO_ADICITY - self.rho_inv as u32) * 2 < 64 { + 2_usize.pow((F::TWO_ADICITY - self.rho_inv as u32) * 2) + } else { + usize::MAX + } } fn supported_degree(&self) -> usize { - todo!() + self.max_degree() } } /// The verifier key which holds some scheme parameters #[derive(Derivative, CanonicalSerialize, CanonicalDeserialize)] #[derivative(Clone(bound = ""), Debug(bound = ""))] -pub struct LigeroPCVerifierKey +pub struct LigeroPCVerifierKey where + F: PrimeField, C: Config, <::TwoToOneHash as TwoToOneCRHScheme>::Parameters: Debug, <::LeafHash as CRHScheme>::Parameters: Debug, { + pub(crate) _field: PhantomData, + /// The security parameter + pub(crate) sec_param: usize, + /// The inverse of code rate + pub(crate) rho_inv: usize, /// Parameters for hash function of Merkle tree leaves - pub leaf_hash_params: LeafParam, + pub(crate) leaf_hash_params: LeafParam, /// Parameters for hash function of Merke tree combining two nodes into one - pub two_to_one_params: TwoToOneParam, + pub(crate) two_to_one_params: TwoToOneParam, /// This is a flag which determines if the random linear combination is done. - pub check_well_formedness: bool, + pub(crate) check_well_formedness: bool, } -impl PCVerifierKey for LigeroPCVerifierKey +impl PCVerifierKey for LigeroPCVerifierKey where + F: PrimeField, C: Config, <::TwoToOneHash as TwoToOneCRHScheme>::Parameters: Debug, <::LeafHash as CRHScheme>::Parameters: Debug, { fn max_degree(&self) -> usize { - todo!() + if (F::TWO_ADICITY - self.rho_inv as u32) * 2 < 64 { + 2_usize.pow((F::TWO_ADICITY - self.rho_inv as u32) * 2) + } else { + usize::MAX + } } fn supported_degree(&self) -> usize { - todo!() + self.max_degree() } } @@ -124,6 +168,13 @@ impl PCPreparedVerifierKey for LigeroPCPr todo!() } } +#[derive(Derivative, CanonicalSerialize, CanonicalDeserialize)] +#[derivative(Default(bound = ""), Clone(bound = ""), Debug(bound = ""))] +pub(crate) struct Metadata { + pub(crate) n_rows: usize, + pub(crate) n_cols: usize, + pub(crate) n_ext_cols: usize, +} /// The commitment to a polynomial is a root of the merkle tree, /// where each node is a hash of the column of the encoded coefficient matrix U. @@ -131,9 +182,7 @@ impl PCPreparedVerifierKey for LigeroPCPr #[derivative(Default(bound = ""), Clone(bound = ""), Debug(bound = ""))] pub struct LigeroPCCommitment { // number of rows resp. columns of the square matrix containing the coefficients of the polynomial - pub(crate) n_rows: usize, - pub(crate) n_cols: usize, - pub(crate) n_ext_cols: usize, + pub(crate) metadata: Metadata, pub(crate) root: C::InnerDigest, } diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index f4e7322b..f0c33bd9 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -4,7 +4,7 @@ use ark_crypto_primitives::{ sponge::{Absorb, CryptographicSponge}, }; use ark_ff::PrimeField; -use ark_poly::{DenseUVPolynomial, EvaluationDomain, GeneralEvaluationDomain}; +use ark_poly::DenseUVPolynomial; use ark_std::fmt::Debug; use core::marker::PhantomData; use digest::Digest; @@ -12,7 +12,7 @@ use jf_primitives::pcs::transcript::IOPTranscript; use std::borrow::Borrow; use crate::ligero::utils::{inner_product, reed_solomon}; -use crate::{Error, LabeledCommitment, LabeledPolynomial, PolynomialCommitment}; +use crate::{Error, LabeledCommitment, LabeledPolynomial, PCUniversalParams, PolynomialCommitment}; use ark_std::rand::RngCore; @@ -28,8 +28,7 @@ use utils::{calculate_t, compute_dimensions, get_indices_from_transcript, hash_c mod tests; -impl - Ligero +impl Ligero where F: PrimeField, C: Config, @@ -52,7 +51,7 @@ where } } - fn compute_matrices(polynomial: &P) -> (Matrix, Matrix) { + fn compute_matrices(polynomial: &P, rho_inv: usize) -> (Matrix, Matrix) { let mut coeffs = polynomial.coeffs().to_vec(); // 1. Computing parameters and initial matrix @@ -68,7 +67,7 @@ where let ext_mat = Matrix::new_from_rows( mat.rows() .iter() - .map(|r| reed_solomon(r, RHO_INV)) + .map(|r| reed_solomon(r, rho_inv)) .collect(), ); @@ -93,13 +92,15 @@ where MerkleTree::::new(leaf_hash_params, two_to_one_params, col_hashes).unwrap() } fn generate_proof( + sec_param: usize, + rho_inv: usize, coeffs: &[F], mat: &Matrix, ext_mat: &Matrix, col_tree: &MerkleTree, transcript: &mut IOPTranscript, ) -> Result, Error> { - let t = calculate_t::(RHO_INV, SEC_PARAM, ext_mat.n)?; + let t = calculate_t::(sec_param, rho_inv, ext_mat.n)?; // 1. Compute the linear combination using the random coefficients let v = mat.row_mul(coeffs); @@ -134,8 +135,7 @@ where } } -impl PolynomialCommitment - for Ligero +impl PolynomialCommitment for Ligero where F: PrimeField, P: DenseUVPolynomial, @@ -147,11 +147,11 @@ where C::InnerDigest: Absorb, D: Digest, { - type UniversalParams = LigeroPCUniversalParams; + type UniversalParams = LigeroPCUniversalParams; - type CommitterKey = LigeroPCCommitterKey; + type CommitterKey = LigeroPCCommitterKey; - type VerifierKey = LigeroPCVerifierKey; + type VerifierKey = LigeroPCVerifierKey; type PreparedVerifierKey = LigeroPCPreparedVerifierKey; @@ -167,34 +167,61 @@ where type Error = Error; + /// This is only a default setup. fn setup( max_degree: usize, _num_vars: Option, - _rng: &mut R, + rng: &mut R, ) -> Result { - if RHO_INV <= 1 { - return Err(Error::InvalidParameters(format!( - "RHO_INV must be an interger greater than 1", - ))); + let leaf_hash_params = ::setup(rng).unwrap(); + let two_to_one_params = ::setup(rng) + .unwrap() + .clone(); + let pp = Self::UniversalParams { + _field: PhantomData, + sec_param: 128, + rho_inv: 4, + check_well_formedness: true, + leaf_hash_params, + two_to_one_params, + }; + let real_max_degree = pp.max_degree(); + if max_degree > real_max_degree || real_max_degree == 0 { + return Err(Error::InvalidParameters( + "This field is not suitable for the proposed parameters".to_string(), + )); } - // The domain will have size m * RHO_INV, but we already have the first m elements - GeneralEvaluationDomain::::compute_size_of_domain(max_degree * (RHO_INV - 1)) - .ok_or(Error::UnsupportedDegreeBound(max_degree))?; - - Ok(LigeroPCUniversalParams { - num_rows: 0, - num_cols: 0, - num_ext_cols: 0, - }) + Ok(pp) } fn trim( - _pp: &Self::UniversalParams, + pp: &Self::UniversalParams, _supported_degree: usize, _supported_hiding_bound: usize, _enforced_degree_bounds: Option<&[usize]>, ) -> Result<(Self::CommitterKey, Self::VerifierKey), Self::Error> { - todo!(); + if pp.max_degree() == 0 { + return Err(Error::InvalidParameters( + "This field is not suitable for the proposed parameters".to_string(), + )); + } + let ck = LigeroPCCommitterKey:: { + _field: PhantomData, + sec_param: pp.sec_param, + rho_inv: pp.rho_inv, + leaf_hash_params: pp.leaf_hash_params.clone(), + two_to_one_params: pp.two_to_one_params.clone(), + check_well_formedness: pp.check_well_formedness, + }; + let vk = LigeroPCVerifierKey:: { + _field: PhantomData, + sec_param: pp.sec_param, + rho_inv: pp.rho_inv, + leaf_hash_params: pp.leaf_hash_params.clone(), + two_to_one_params: pp.two_to_one_params.clone(), + check_well_formedness: pp.check_well_formedness, + }; + Ok((ck, vk)) } fn commit<'a>( @@ -217,7 +244,7 @@ where let polynomial = labeled_polynomial.polynomial(); // 1. Compute matrices - let (mat, ext_mat) = Self::compute_matrices(polynomial); + let (mat, ext_mat) = Self::compute_matrices(polynomial, ck.rho_inv); // 2. Create the Merkle tree from the hashes of the columns let col_tree = @@ -238,9 +265,11 @@ where // 4. Generate the proof by choosing random columns and proving their paths in the tree let commitment = LigeroPCCommitment { - n_rows, - n_cols, - n_ext_cols, + metadata: Metadata { + n_rows, + n_cols, + n_ext_cols, + }, root, }; @@ -250,8 +279,8 @@ where None, // TODO think about this (degree_bound) )); } - - Ok((commitments, Vec::new())) + let com_len = &commitments.len(); + Ok((commitments, vec![Self::Randomness::default(); *com_len])) // TODO when should this return Err? } @@ -286,9 +315,12 @@ where for i in 0..labeled_polynomials.len() { let polynomial = labeled_polynomials[i].polynomial(); let commitment = labeled_commitments[i].commitment(); + let n_rows = commitment.metadata.n_rows; + let n_cols = commitment.metadata.n_cols; + let root = &commitment.root; // 1. Compute matrices - let (mat, ext_mat) = Self::compute_matrices(polynomial); + let (mat, ext_mat) = Self::compute_matrices(polynomial, ck.rho_inv); // 2. Create the Merkle tree from the hashes of the columns let col_tree = @@ -296,21 +328,20 @@ where // 3. Generate vector b let mut b = Vec::new(); - let point_pow = point.pow([commitment.n_cols as u64]); // TODO this and other conversions could potentially fail - let mut acc_b = F::one(); - for _ in 0..commitment.n_rows { - b.push(acc_b); - acc_b *= point_pow; + let point_pow = point.pow([n_cols as u64]); // TODO this and other conversions could potentially fail + let mut pow_b = F::one(); + for _ in 0..n_rows { + b.push(pow_b); + pow_b *= point_pow; } let mut transcript = IOPTranscript::new(b"transcript"); transcript - .append_serializable_element(b"root", &commitment.root) + .append_serializable_element(b"root", root) .map_err(|_| Error::TranscriptError)?; // If we are checking well-formedness, we need to compute the well-formedness proof (which is just r.M) and append it to the transcript. let well_formedness = if ck.check_well_formedness { - let n_rows = mat.n; let mut r = Vec::new(); for _ in 0..n_rows { r.push( @@ -335,7 +366,15 @@ where proof_array.push(LigeroPCProof { // compute the opening proof and append b.M to the transcript - opening: Self::generate_proof(&b, &mat, &ext_mat, &col_tree, &mut transcript)?, + opening: Self::generate_proof( + ck.sec_param, + ck.rho_inv, + &b, + &mat, + &ext_mat, + &col_tree, + &mut transcript, + )?, well_formedness, }); } @@ -368,9 +407,18 @@ where ) )); } + let leaf_hash_params: &<::LeafHash as CRHScheme>::Parameters = + &vk.leaf_hash_params; + let two_to_one_params: &<::TwoToOneHash as TwoToOneCRHScheme>::Parameters = + &vk.two_to_one_params; for (i, labeled_commitment) in labeled_commitments.iter().enumerate() { let commitment = labeled_commitment.commitment(); + let n_rows = commitment.metadata.n_rows; + let n_cols = commitment.metadata.n_cols; + let n_ext_cols = commitment.metadata.n_ext_cols; + let root = &commitment.root; + let t = calculate_t::(vk.sec_param, vk.rho_inv, n_ext_cols)?; let mut transcript = IOPTranscript::new(b"transcript"); transcript @@ -383,8 +431,8 @@ where } let tmp = &proof_array[i].well_formedness.as_ref(); let well_formedness = tmp.unwrap(); - let mut r = Vec::with_capacity(commitment.n_rows); - for _ in 0..commitment.n_rows { + let mut r = Vec::with_capacity(n_rows); + for _ in 0..n_rows { r.push( transcript .get_and_append_challenge(b"r") @@ -401,24 +449,7 @@ where (None, None) }; - // 1. Compute a and b - let mut a = Vec::with_capacity(commitment.n_cols); - let mut acc_a = F::one(); - for _ in 0..commitment.n_cols { - a.push(acc_a); - acc_a *= point; - } - - // by now acc_a = point^n_cols - let mut b = Vec::with_capacity(commitment.n_rows); - let mut acc_b = F::one(); - for _ in 0..commitment.n_rows { - b.push(acc_b); - acc_b *= acc_a; - } - let t = calculate_t::(RHO_INV, SEC_PARAM, commitment.n_ext_cols)?; - - // 2. Seed the transcript with the point and generate t random indices + // 1. Seed the transcript with the point and the recieved vector // TODO Consider removing the evaluation point from the transcript. transcript .append_serializable_element(b"point", point) @@ -427,15 +458,10 @@ where .append_serializable_element(b"v", &proof_array[i].opening.v) .map_err(|_| Error::TranscriptError)?; - // 3. Evaluate and check for the given point - let coeffs: &[F] = &b; - let root = &commitment.root; - let n_ext_cols = commitment.n_ext_cols; - let leaf_hash_params: &<::LeafHash as CRHScheme>::Parameters = - &vk.leaf_hash_params; - let two_to_one_params: &<::TwoToOneHash as TwoToOneCRHScheme>::Parameters = - &vk.two_to_one_params; - // 1. Hash the received columns into leaf hashes + // 2. Ask random oracle for the `t` indices where the checks happen + let indices = get_indices_from_transcript::(n_ext_cols, t, &mut transcript)?; + + // 3. Hash the received columns into leaf hashes let col_hashes: Vec<_> = proof_array[i] .opening .columns @@ -443,10 +469,7 @@ where .map(|c| hash_column::(c)) .collect(); - // 2. Compute t column indices to check the linear combination at - let indices = get_indices_from_transcript::(n_ext_cols, t, &mut transcript)?; - - // 3. Verify the paths for each of the leaf hashes - this is only run once, + // 4. Verify the paths for each of the leaf hashes - this is only run once, // even if we have a well-formedness check (i.e., we save sending and checking the columns). // See "Concrete optimizations to the commitment scheme", p.12 of [Brakedown](https://eprint.iacr.org/2021/1043.pdf) for (j, (leaf, q_j)) in col_hashes.iter().zip(indices.iter()).enumerate() { @@ -459,10 +482,7 @@ where .map_err(|_| Error::InvalidCommitment)?; } - // 4. Compute the encoding w = E(v) - let w = reed_solomon(&proof_array[i].opening.v, RHO_INV); - - // helper closure for checking that a.b = c + // helper closure: checks if a.b = c let check_inner_product = |a, b, c| -> Result<(), Error> { if inner_product(a, b) != c { return Err(Error::InvalidCommitment); @@ -471,11 +491,33 @@ where Ok(()) }; - // 5. Probabilistic checks that whatever the prover sent, + // 5. Compute the encoding w = E(v) + let w = reed_solomon(&proof_array[i].opening.v, vk.rho_inv); + + // 6. Compute a = [1, z, z^2, ..., z^(n_cols_1)] + // where z denotes the `point`. Following Justin Thaler's notation + let mut a = Vec::with_capacity(n_cols); + let mut pow_a = F::one(); + for _ in 0..n_cols { + a.push(pow_a); + pow_a *= point; + } + + // Here, pow_z = z^n_cols. + // Compute b = [1, z^n_cols, z^(2*n_cols), ..., z^((n_rows-1)*n_cols)] + let mut b = Vec::with_capacity(n_rows); + let mut pow_b = F::one(); + for _ in 0..n_rows { + b.push(pow_b); + pow_b *= pow_a; + } + let coeffs: &[F] = &b; + + // 7. Probabilistic checks that whatever the prover sent, // matches with what the verifier computed for himself. // Note: we sacrifice some code repetition in order not to repeat execution. if let (Some(well_formedness), Some(r)) = out { - let w_well_formedness = reed_solomon(&well_formedness, RHO_INV); + let w_well_formedness = reed_solomon(&well_formedness, vk.rho_inv); for (transcript_index, matrix_index) in indices.iter().enumerate() { check_inner_product( &r, diff --git a/src/ligero/tests.rs b/src/ligero/tests.rs index 43d8c617..23bfaf5a 100644 --- a/src/ligero/tests.rs +++ b/src/ligero/tests.rs @@ -4,12 +4,13 @@ mod tests { use crate::ark_std::UniformRand; use crate::{ challenge::ChallengeGenerator, - ligero::{ - utils::*, Ligero, LigeroPCCommitterKey, LigeroPCVerifierKey, PolynomialCommitment, - }, + ligero::{utils::*, Ligero, LigeroPCUniversalParams, PolynomialCommitment}, LabeledPolynomial, }; - use ark_bls12_377::Fq; + use ark_bls12_377::Fr; + use ark_bls12_377::{Bls12_377, Fq}; + use ark_bls12_381::Bls12_381; + use ark_bls12_381::Fr as Fr381; use ark_crypto_primitives::sponge::poseidon::PoseidonConfig; use ark_crypto_primitives::sponge::CryptographicSponge; use ark_crypto_primitives::{ @@ -17,6 +18,7 @@ mod tests { merkle_tree::{ByteDigestConverter, Config}, sponge::poseidon::PoseidonSponge, }; + use ark_ec::pairing::Pairing; use ark_ff::PrimeField; use ark_poly::{ domain::general::GeneralEvaluationDomain, univariate::DensePolynomial, DenseUVPolynomial, @@ -24,9 +26,10 @@ mod tests { }; use ark_std::test_rng; use blake2::Blake2s256; + use core::marker::PhantomData; use rand_chacha::{rand_core::SeedableRng, ChaCha20Rng}; - type UniPoly = DensePolynomial; + type UniPoly = DensePolynomial; #[derive(Clone)] pub(super) struct Window4x256; impl pedersen::Window for Window4x256 { @@ -52,48 +55,47 @@ mod tests { } type MTConfig = MerkleTreeParams; - type Sponge = PoseidonSponge; - type PC = Ligero; - type LigeroPCS = PC; - type LigeroPcsF = - PC, RHO_INV>; + type Sponge = PoseidonSponge; + type PC = Ligero; + type LigeroPCS = PC; + type LigeroPcsF = PC>; #[test] fn test_matrix_constructor_flat() { - let entries: Vec = to_field(vec![10, 100, 4, 67, 44, 50]); + let entries: Vec = to_field(vec![10, 100, 4, 67, 44, 50]); let mat = Matrix::new_from_flat(2, 3, &entries); - assert_eq!(mat.entry(1, 2), Fq::from(50)); + assert_eq!(mat.entry(1, 2), Fr::from(50)); } #[test] fn test_matrix_constructor_flat_square() { - let entries: Vec = to_field(vec![10, 100, 4, 67]); + let entries: Vec = to_field(vec![10, 100, 4, 67]); let mat = Matrix::new_from_flat(2, 2, &entries); - assert_eq!(mat.entry(1, 1), Fq::from(67)); + assert_eq!(mat.entry(1, 1), Fr::from(67)); } #[test] #[should_panic(expected = "dimensions are 2 x 3 but entry vector has 5 entries")] fn test_matrix_constructor_flat_panic() { - let entries: Vec = to_field(vec![10, 100, 4, 67, 44]); + let entries: Vec = to_field(vec![10, 100, 4, 67, 44]); Matrix::new_from_flat(2, 3, &entries); } #[test] fn test_matrix_constructor_rows() { - let rows: Vec> = vec![ + let rows: Vec> = vec![ to_field(vec![10, 100, 4]), to_field(vec![23, 1, 0]), to_field(vec![55, 58, 9]), ]; let mat = Matrix::new_from_rows(rows); - assert_eq!(mat.entry(2, 0), Fq::from(55)); + assert_eq!(mat.entry(2, 0), Fr::from(55)); } #[test] #[should_panic(expected = "not all rows have the same length")] fn test_matrix_constructor_rows_panic() { - let rows: Vec> = vec![ + let rows: Vec> = vec![ to_field(vec![10, 100, 4]), to_field(vec![23, 1, 0]), to_field(vec![55, 58]), @@ -103,7 +105,7 @@ mod tests { #[test] fn test_cols() { - let rows: Vec> = vec![ + let rows: Vec> = vec![ to_field(vec![4, 76]), to_field(vec![14, 92]), to_field(vec![17, 89]), @@ -116,17 +118,17 @@ mod tests { #[test] fn test_row_mul() { - let rows: Vec> = vec![ + let rows: Vec> = vec![ to_field(vec![10, 100, 4]), to_field(vec![23, 1, 0]), to_field(vec![55, 58, 9]), ]; let mat = Matrix::new_from_rows(rows); - let v: Vec = to_field(vec![12, 41, 55]); - // by giving the result in the integers and then converting to Fq - // we ensure the test will still pass even if Fq changes - assert_eq!(mat.row_mul(&v), to_field::(vec![4088, 4431, 543])); + let v: Vec = to_field(vec![12, 41, 55]); + // by giving the result in the integers and then converting to Fr + // we ensure the test will still pass even if Fr changes + assert_eq!(mat.row_mul(&v), to_field::(vec![4088, 4431, 543])); } #[test] @@ -139,10 +141,10 @@ mod tests { let deg = (1 << i) - 1; let rand_chacha = &mut ChaCha20Rng::from_rng(test_rng()).unwrap(); - let mut pol = rand_poly::(deg, None, rand_chacha); + let mut pol = rand_poly::(deg, None, rand_chacha); while pol.degree() != deg { - pol = rand_poly::(deg, None, rand_chacha); + pol = rand_poly::(deg, None, rand_chacha); } let coeffs = &pol.coeffs; @@ -152,7 +154,7 @@ mod tests { let encoded = reed_solomon(&coeffs, rho_inv); - let large_domain = GeneralEvaluationDomain::::new(m * rho_inv).unwrap(); + let large_domain = GeneralEvaluationDomain::::new(m * rho_inv).unwrap(); // the encoded elements should agree with the evaluations of the polynomial in the larger domain for j in 0..(rho_inv * m) { @@ -169,19 +171,19 @@ mod tests { .unwrap() .clone(); - let rows: Vec> = vec![ + let rows: Vec> = vec![ to_field(vec![4, 76]), to_field(vec![14, 92]), to_field(vec![17, 89]), ]; let mat = Matrix::new_from_rows(rows); - let mt = LigeroPCS::<2>::create_merkle_tree(&mat, &leaf_hash_params, &two_to_one_params); + let mt = LigeroPCS::create_merkle_tree(&mat, &leaf_hash_params, &two_to_one_params); let root = mt.root(); for (i, col) in mat.cols().iter().enumerate() { - let col_hash = hash_column::(col); + let col_hash = hash_column::(col); let proof = mt.generate_proof(i).unwrap(); assert!(proof @@ -206,20 +208,20 @@ mod tests { assert_eq!(get_num_bytes(1 << 32 + 1), 5); } - fn rand_poly( + fn rand_poly( degree: usize, _: Option, rng: &mut ChaCha20Rng, - ) -> DensePolynomial { + ) -> DensePolynomial { DensePolynomial::rand(degree, rng) } - fn constant_poly( + fn constant_poly( _: usize, _: Option, rng: &mut ChaCha20Rng, - ) -> DensePolynomial { - DensePolynomial::from_coefficients_slice(&[Fq::rand(rng)]) + ) -> DensePolynomial { + DensePolynomial::from_coefficients_slice(&[Fr::rand(rng)]) } // TODO: replace by https://github.com/arkworks-rs/crypto-primitives/issues/112. @@ -252,13 +254,10 @@ mod tests { #[test] fn test_setup() { let rng = &mut test_rng(); - let _ = LigeroPCS::<2>::setup(1 << 44, None, rng).unwrap(); - - assert_eq!(LigeroPCS::<5>::setup(1 << 45, None, rng).is_err(), true); - + let _ = LigeroPcsF::::setup(1 << 44, None, rng).unwrap(); // but the base field of bls12_381 doesnt have such large domains use ark_bls12_381::Fq as F_381; - assert_eq!(LigeroPcsF::<5, F_381>::setup(10, None, rng).is_err(), true); + assert_eq!(LigeroPcsF::::setup(20, None, rng).is_err(), true); } #[test] @@ -266,24 +265,24 @@ mod tests { let degree = 4; let mut rng = &mut test_rng(); // just to make sure we have the right degree given the FFT domain for our field - LigeroPCS::<2>::setup(degree, None, rng).unwrap(); + LigeroPCS::setup(degree, None, rng).unwrap(); let leaf_hash_params = ::setup(&mut rng).unwrap(); let two_to_one_params = ::setup(&mut rng) .unwrap() .clone(); let check_well_formedness = true; - let ck: LigeroPCCommitterKey = LigeroPCCommitterKey { - leaf_hash_params, - two_to_one_params, + let pp: LigeroPCUniversalParams = LigeroPCUniversalParams { + _field: PhantomData, + sec_param: 128, + rho_inv: 4, check_well_formedness, - }; - let vk: LigeroPCVerifierKey = LigeroPCVerifierKey { leaf_hash_params, two_to_one_params, - check_well_formedness, }; + let (ck, vk) = LigeroPCS::trim(&pp, 0, 0, None).unwrap(); + let rand_chacha = &mut ChaCha20Rng::from_rng(test_rng()).unwrap(); let labeled_poly = LabeledPolynomial::new( "test".to_string(), @@ -292,18 +291,18 @@ mod tests { None, ); - let mut test_sponge = test_sponge::(); - let (c, rands) = LigeroPCS::<2>::commit(&ck, &[labeled_poly.clone()], None).unwrap(); + let mut test_sponge = test_sponge::(); + let (c, rands) = LigeroPCS::commit(&ck, &[labeled_poly.clone()], None).unwrap(); - let point = Fq::rand(rand_chacha); + let point = Fr::rand(rand_chacha); let value = labeled_poly.evaluate(&point); - let mut challenge_generator: ChallengeGenerator> = + let mut challenge_generator: ChallengeGenerator> = ChallengeGenerator::new_univariate(&mut test_sponge); // assert!( - // LigeroPCS::<2>::check_well_formedness( + // LigeroPCS::check_well_formedness( // &c[0].commitment(), // &leaf_hash_params, // &two_to_one_params @@ -312,7 +311,7 @@ mod tests { // "Well formedness check failed" // ); - let proof = LigeroPCS::<2>::open( + let proof = LigeroPCS::open( &ck, &[labeled_poly], &c, @@ -322,7 +321,7 @@ mod tests { None, ) .unwrap(); - assert!(LigeroPCS::<2>::check( + assert!(LigeroPCS::check( &vk, &c, &point, @@ -339,33 +338,33 @@ mod tests { let degrees = [4_usize, 13_usize, 30_usize]; let mut rng = &mut test_rng(); - LigeroPCS::<2>::setup(*degrees.iter().max().unwrap(), None, rng).unwrap(); + LigeroPCS::setup(*degrees.iter().max().unwrap(), None, rng).unwrap(); let leaf_hash_params = ::setup(&mut rng).unwrap(); let two_to_one_params = ::setup(&mut rng) .unwrap() .clone(); let check_well_formedness = true; - let ck: LigeroPCCommitterKey = LigeroPCCommitterKey { - leaf_hash_params, - two_to_one_params, + let pp: LigeroPCUniversalParams = LigeroPCUniversalParams { + _field: PhantomData, + sec_param: 128, + rho_inv: 4, check_well_formedness, - }; - let vk: LigeroPCVerifierKey = LigeroPCVerifierKey { leaf_hash_params, two_to_one_params, - check_well_formedness, }; + let (ck, vk) = LigeroPCS::trim(&pp, 0, 0, None).unwrap(); + let rand_chacha = &mut ChaCha20Rng::from_rng(test_rng()).unwrap(); - let mut test_sponge = test_sponge::(); - let mut challenge_generator: ChallengeGenerator> = + let mut test_sponge = test_sponge::(); + let mut challenge_generator: ChallengeGenerator> = ChallengeGenerator::new_univariate(&mut test_sponge); let mut labeled_polys = Vec::new(); let mut values = Vec::new(); - let point = Fq::rand(rand_chacha); + let point = Fr::rand(rand_chacha); for degree in degrees { let labeled_poly = LabeledPolynomial::new( @@ -379,9 +378,9 @@ mod tests { labeled_polys.push(labeled_poly); } - let (commitments, randomness) = LigeroPCS::<2>::commit(&ck, &labeled_polys, None).unwrap(); + let (commitments, randomness) = LigeroPCS::commit(&ck, &labeled_polys, None).unwrap(); - let proof = LigeroPCS::<2>::open( + let proof = LigeroPCS::open( &ck, &labeled_polys, &commitments, @@ -391,7 +390,7 @@ mod tests { None, ) .unwrap(); - assert!(LigeroPCS::<2>::check( + assert!(LigeroPCS::check( &vk, &commitments, &point, @@ -411,33 +410,34 @@ mod tests { let degrees = [4_usize, 13_usize, 30_usize]; let mut rng = &mut test_rng(); - LigeroPCS::<2>::setup(*degrees.iter().max().unwrap(), None, rng).unwrap(); + LigeroPCS::setup(*degrees.iter().max().unwrap(), None, rng).unwrap(); let leaf_hash_params = ::setup(&mut rng).unwrap(); let two_to_one_params = ::setup(&mut rng) .unwrap() .clone(); let check_well_formedness = true; - let ck: LigeroPCCommitterKey = LigeroPCCommitterKey { - leaf_hash_params, - two_to_one_params, + + let pp: LigeroPCUniversalParams = LigeroPCUniversalParams { + _field: PhantomData, + sec_param: 128, + rho_inv: 4, check_well_formedness, - }; - let vk: LigeroPCVerifierKey = LigeroPCVerifierKey { leaf_hash_params, two_to_one_params, - check_well_formedness, }; + let (ck, vk) = LigeroPCS::trim(&pp, 0, 0, None).unwrap(); + let rand_chacha = &mut ChaCha20Rng::from_rng(test_rng()).unwrap(); - let mut test_sponge = test_sponge::(); - let mut challenge_generator: ChallengeGenerator> = + let mut test_sponge = test_sponge::(); + let mut challenge_generator: ChallengeGenerator> = ChallengeGenerator::new_univariate(&mut test_sponge); let mut labeled_polys = Vec::new(); let mut values = Vec::new(); - let point = Fq::rand(rand_chacha); + let point = Fr::rand(rand_chacha); for degree in degrees { let labeled_poly = LabeledPolynomial::new( @@ -451,9 +451,9 @@ mod tests { labeled_polys.push(labeled_poly); } - let (commitments, randomness) = LigeroPCS::<2>::commit(&ck, &labeled_polys, None).unwrap(); + let (commitments, randomness) = LigeroPCS::commit(&ck, &labeled_polys, None).unwrap(); - let proof = LigeroPCS::<2>::open( + let proof = LigeroPCS::open( &ck, &labeled_polys, &commitments, @@ -463,7 +463,7 @@ mod tests { None, ) .unwrap(); - assert!(LigeroPCS::<2>::check( + assert!(LigeroPCS::check( &vk, &commitments, &point, @@ -482,33 +482,33 @@ mod tests { let degrees = [4_usize, 13_usize, 30_usize]; let mut rng = &mut test_rng(); - LigeroPCS::<2>::setup(*degrees.iter().max().unwrap(), None, rng).unwrap(); + LigeroPCS::setup(*degrees.iter().max().unwrap(), None, rng).unwrap(); let leaf_hash_params = ::setup(&mut rng).unwrap(); let two_to_one_params = ::setup(&mut rng) .unwrap() .clone(); let check_well_formedness = true; - let ck: LigeroPCCommitterKey = LigeroPCCommitterKey { - leaf_hash_params, - two_to_one_params, + let pp: LigeroPCUniversalParams = LigeroPCUniversalParams { + _field: PhantomData, + sec_param: 128, + rho_inv: 4, check_well_formedness, - }; - let vk: LigeroPCVerifierKey = LigeroPCVerifierKey { leaf_hash_params, two_to_one_params, - check_well_formedness, }; + let (ck, vk) = LigeroPCS::trim(&pp, 0, 0, None).unwrap(); + let rand_chacha = &mut ChaCha20Rng::from_rng(test_rng()).unwrap(); - let mut test_sponge = test_sponge::(); - let mut challenge_generator: ChallengeGenerator> = + let mut test_sponge = test_sponge::(); + let mut challenge_generator: ChallengeGenerator> = ChallengeGenerator::new_univariate(&mut test_sponge); let mut labeled_polys = Vec::new(); let mut values = Vec::new(); - let point = Fq::rand(rand_chacha); + let point = Fr::rand(rand_chacha); for degree in degrees { let labeled_poly = LabeledPolynomial::new( @@ -522,9 +522,9 @@ mod tests { labeled_polys.push(labeled_poly); } - let (commitments, randomness) = LigeroPCS::<2>::commit(&ck, &labeled_polys, None).unwrap(); + let (commitments, randomness) = LigeroPCS::commit(&ck, &labeled_polys, None).unwrap(); - let mut proof = LigeroPCS::<2>::open( + let mut proof = LigeroPCS::open( &ck, &labeled_polys, &commitments, @@ -538,7 +538,7 @@ mod tests { // to do swap opening proofs proof.swap(0, 2); - assert!(LigeroPCS::<2>::check( + assert!(LigeroPCS::check( &vk, &commitments, &point, @@ -558,33 +558,33 @@ mod tests { let degrees = [4_usize, 13_usize, 30_usize]; let mut rng = &mut test_rng(); - LigeroPCS::<2>::setup(*degrees.iter().max().unwrap(), None, rng).unwrap(); + LigeroPCS::setup(*degrees.iter().max().unwrap(), None, rng).unwrap(); let leaf_hash_params = ::setup(&mut rng).unwrap(); let two_to_one_params = ::setup(&mut rng) .unwrap() .clone(); let check_well_formedness = true; - let ck: LigeroPCCommitterKey = LigeroPCCommitterKey { - leaf_hash_params, - two_to_one_params, + let pp: LigeroPCUniversalParams = LigeroPCUniversalParams { + _field: PhantomData, + sec_param: 128, + rho_inv: 4, check_well_formedness, - }; - let vk: LigeroPCVerifierKey = LigeroPCVerifierKey { leaf_hash_params, two_to_one_params, - check_well_formedness, }; + let (ck, vk) = LigeroPCS::trim(&pp, 0, 0, None).unwrap(); + let rand_chacha = &mut ChaCha20Rng::from_rng(test_rng()).unwrap(); - let mut test_sponge = test_sponge::(); - let mut challenge_generator: ChallengeGenerator> = + let mut test_sponge = test_sponge::(); + let mut challenge_generator: ChallengeGenerator> = ChallengeGenerator::new_univariate(&mut test_sponge); let mut labeled_polys = Vec::new(); let mut values = Vec::new(); - let point = Fq::rand(rand_chacha); + let point = Fr::rand(rand_chacha); for degree in degrees { let labeled_poly = LabeledPolynomial::new( @@ -598,9 +598,9 @@ mod tests { labeled_polys.push(labeled_poly); } - let (commitments, randomness) = LigeroPCS::<2>::commit(&ck, &labeled_polys, None).unwrap(); + let (commitments, randomness) = LigeroPCS::commit(&ck, &labeled_polys, None).unwrap(); - let proof = LigeroPCS::<2>::open( + let proof = LigeroPCS::open( &ck, &labeled_polys, &commitments, @@ -614,7 +614,7 @@ mod tests { // swap values externally passed to verifier values.swap(1, 2); - assert!(LigeroPCS::<2>::check( + assert!(LigeroPCS::check( &vk, &commitments, &point, @@ -628,13 +628,36 @@ mod tests { #[test] fn test_calculate_t_with_good_parameters() { - assert!(calculate_t::(4, 128, 2_usize.pow(32)).unwrap() < 200); - assert!(calculate_t::(4, 256, 2_usize.pow(32)).unwrap() < 400); + assert!(calculate_t::(128, 4, 2_usize.pow(32)).unwrap() < 200); + assert!(calculate_t::(256, 4, 2_usize.pow(32)).unwrap() < 400); } #[test] fn test_calculate_t_with_bad_parameters() { - calculate_t::(4, 317, 2_usize.pow(Fq::MODULUS_BIT_SIZE - 317)).unwrap_err(); - calculate_t::(4, 400, 2_usize.pow(32)).unwrap_err(); + calculate_t::((Fq::MODULUS_BIT_SIZE - 60) as usize, 4, 2_usize.pow(60)).unwrap_err(); + calculate_t::(400, 4, 2_usize.pow(32)).unwrap_err(); + } + + fn rand_point(_: Option, rng: &mut ChaCha20Rng) -> E::ScalarField { + E::ScalarField::rand(rng) + } + + #[test] + fn single_poly_test() { + use crate::tests::*; + single_poly_test::<_, _, LigeroPCS, _>( + None, + rand_poly::, + rand_point::, + poseidon_sponge_for_test, + ) + .expect("test failed for bls12-377"); + single_poly_test::<_, _, LigeroPcsF, _>( + None, + rand_poly::, + rand_point::, + poseidon_sponge_for_test, + ) + .expect("test failed for bls12-381"); } } diff --git a/src/ligero/utils.rs b/src/ligero/utils.rs index fed882cc..25724f78 100644 --- a/src/ligero/utils.rs +++ b/src/ligero/utils.rs @@ -212,8 +212,8 @@ pub(crate) fn get_indices_from_transcript( #[inline] pub(crate) fn calculate_t( - rho_inv: usize, sec_param: usize, + rho_inv: usize, codeword_len: usize, ) -> Result { // Took from the analysis by BCI+20 and Ligero From d450683900650a7ea1fad336fd679b856ce41daf Mon Sep 17 00:00:00 2001 From: Hossein Moghaddas Date: Thu, 28 Sep 2023 10:07:43 +0200 Subject: [PATCH 096/108] Add Breakdown and Ligero to `README.md` (#27) * Add Breakdown and Ligero to `README.md` * Fix newline * Apply suggestions from code review remove brakedown reference for now --------- Co-authored-by: mmagician --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index a468f981..37f24ca0 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,7 @@ Unless you explicitly state otherwise, any contribution that you submit to this [aurora-light]: https://ia.cr/2019/601 [pcd-acc]: https://ia.cr/2020/499 [pst]: https://ia.cr/2011/587 +[ligero]: https://ia.cr/2022/1608 ## Reference papers @@ -82,6 +83,10 @@ TCC 2020 Charalampos Papamanthou, Elaine Shi, Roberto Tamassia TCC 2013 +[Ligero: Lightweight Sublinear Arguments Without a Trusted Setup][ligero] +Scott Ames, Carmit Hazay, Yuval Ishai, Muthuramakrishnan Venkitasubramaniam +CCS 2017 + ## Acknowledgements This work was supported by: an Engineering and Physical Sciences Research Council grant; a Google Faculty Award; the RISELab at UC Berkeley; and donations from the Ethereum Foundation and the Interchain Foundation. From 2b72639c165776706152991f4476ae4fd566fb30 Mon Sep 17 00:00:00 2001 From: mmagician Date: Fri, 29 Sep 2023 01:29:19 -0600 Subject: [PATCH 097/108] code and comments cleanup (#30) --- src/ligero/data_structures.rs | 2 +- src/ligero/mod.rs | 47 ++++++++++++++++++----------------- 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/src/ligero/data_structures.rs b/src/ligero/data_structures.rs index f424306d..de512d4d 100644 --- a/src/ligero/data_structures.rs +++ b/src/ligero/data_structures.rs @@ -208,7 +208,7 @@ pub(crate) type LigeroPCRandomness = (); impl PCRandomness for LigeroPCRandomness { fn empty() -> Self { - todo!() + () } fn rand( diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index f0c33bd9..e4e78783 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -11,6 +11,7 @@ use digest::Digest; use jf_primitives::pcs::transcript::IOPTranscript; use std::borrow::Borrow; +use crate::data_structures::PCRandomness; use crate::ligero::utils::{inner_product, reed_solomon}; use crate::{Error, LabeledCommitment, LabeledPolynomial, PCUniversalParams, PolynomialCommitment}; @@ -39,7 +40,6 @@ where P: DenseUVPolynomial, { /// Create a new instance of Ligero. - /// If either or both parameters are None, their default values are used. pub fn new() -> Self { Self { _config: PhantomData, @@ -91,10 +91,11 @@ where MerkleTree::::new(leaf_hash_params, two_to_one_params, col_hashes).unwrap() } + fn generate_proof( sec_param: usize, rho_inv: usize, - coeffs: &[F], + b: &[F], mat: &Matrix, ext_mat: &Matrix, col_tree: &MerkleTree, @@ -102,8 +103,9 @@ where ) -> Result, Error> { let t = calculate_t::(sec_param, rho_inv, ext_mat.n)?; - // 1. Compute the linear combination using the random coefficients - let v = mat.row_mul(coeffs); + // 1. left-multiply the matrix by `b`, where for a requested query point `z`, + // `b = [1, z^m, z^(2m), ..., z^((m-1)m)]` + let v = mat.row_mul(b); transcript .append_serializable_element(b"v", &v) @@ -112,9 +114,9 @@ where // 2. Generate t column indices to test the linear combination on let indices = get_indices_from_transcript(ext_mat.m, t, transcript)?; - // 3. Compute Merkle tree paths for the columns - let mut queried_columns = Vec::new(); - let mut paths = Vec::new(); + // 3. Compute Merkle tree paths for the requested columns + let mut queried_columns = Vec::with_capacity(t); + let mut paths = Vec::with_capacity(t); let ext_mat_cols = ext_mat.cols(); @@ -243,17 +245,19 @@ where for labeled_polynomial in polynomials.into_iter() { let polynomial = labeled_polynomial.polynomial(); - // 1. Compute matrices + // 1. Arrange the coefficients of the polynomial into a matrix, + // and apply Reed-Solomon encoding to get `ext_mat`. let (mat, ext_mat) = Self::compute_matrices(polynomial, ck.rho_inv); - // 2. Create the Merkle tree from the hashes of the columns + // 2. Create the Merkle tree from the hashes of each column. let col_tree = Self::create_merkle_tree(&ext_mat, &ck.leaf_hash_params, &ck.two_to_one_params); - // 3. Add root to transcript and generate random linear combination with it + // 3. Obtain the MT root and add it to the transcript. let root = col_tree.root(); let mut transcript: IOPTranscript = IOPTranscript::new(b"transcript"); + transcript .append_serializable_element(b"root", &root) .map_err(|_| Error::TranscriptError)?; @@ -262,8 +266,7 @@ where let n_cols = mat.m; let n_ext_cols = ext_mat.m; - // 4. Generate the proof by choosing random columns and proving their paths in the tree - + // 4. The commitment is just the root, but since each commitment could be to a differently-sized polynomial, we also add some metadata. let commitment = LigeroPCCommitment { metadata: Metadata { n_rows, @@ -276,12 +279,11 @@ where commitments.push(LabeledCommitment::new( labeled_polynomial.label().clone(), commitment, - None, // TODO think about this (degree_bound) + None, )); } let com_len = &commitments.len(); - Ok((commitments, vec![Self::Randomness::default(); *com_len])) - // TODO when should this return Err? + Ok((commitments, vec![Self::Randomness::empty(); *com_len])) } fn open<'a>( @@ -319,16 +321,18 @@ where let n_cols = commitment.metadata.n_cols; let root = &commitment.root; - // 1. Compute matrices + // 1. Arrange the coefficients of the polynomial into a matrix, + // and apply Reed-Solomon encoding to get `ext_mat`. let (mat, ext_mat) = Self::compute_matrices(polynomial, ck.rho_inv); - // 2. Create the Merkle tree from the hashes of the columns + // 2. Create the Merkle tree from the hashes of each column. let col_tree = Self::create_merkle_tree(&ext_mat, &ck.leaf_hash_params, &ck.two_to_one_params); - // 3. Generate vector b + // 3. Generate vector `b = [1, z^m, z^(2m), ..., z^((m-1)m)]` let mut b = Vec::new(); - let point_pow = point.pow([n_cols as u64]); // TODO this and other conversions could potentially fail + // This could potentially fail when n_cols > 1<<64, but `ck` won't allow commiting to such polynomials. + let point_pow = point.pow([n_cols as u64]); let mut pow_b = F::one(); for _ in 0..n_rows { b.push(pow_b); @@ -495,7 +499,7 @@ where let w = reed_solomon(&proof_array[i].opening.v, vk.rho_inv); // 6. Compute a = [1, z, z^2, ..., z^(n_cols_1)] - // where z denotes the `point`. Following Justin Thaler's notation + // where z denotes the query `point`. let mut a = Vec::with_capacity(n_cols); let mut pow_a = F::one(); for _ in 0..n_cols { @@ -503,7 +507,6 @@ where pow_a *= point; } - // Here, pow_z = z^n_cols. // Compute b = [1, z^n_cols, z^(2*n_cols), ..., z^((n_rows-1)*n_cols)] let mut b = Vec::with_capacity(n_rows); let mut pow_b = F::one(); @@ -549,5 +552,3 @@ where Ok(true) } } - -// TODO start considering degree bound From 845989d5ffb5338055b7e63433d89755a4cf2bab Mon Sep 17 00:00:00 2001 From: mmagician Date: Fri, 29 Sep 2023 01:38:31 -0600 Subject: [PATCH 098/108] Bring in remaining tests from the test suite (#29) * make test util functions cfg-gated * Add constant_poly_test * Add quadratic tests * Add linear poly tests * Add all other tests from test suite * fix check_combinations fix combinations remove prints remove old comments * remove deprecated deny * change the signature of rand_point to allow other fields * remove tests superseded by automated test suite * Create a `new` method for `LigeroPCUniversalParams` * document `LigeroPCUniversalParams` --- src/lib.rs | 21 +- src/ligero/data_structures.rs | 71 ++++- src/ligero/mod.rs | 17 +- src/ligero/tests.rs | 510 ++++++++++++++-------------------- src/ligero/utils.rs | 2 + 5 files changed, 296 insertions(+), 325 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 5d7ae548..7452588e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,7 @@ #![cfg_attr(not(feature = "std"), no_std)] //! A crate for polynomial commitment schemes. #![deny(unused_import_braces, unused_qualifications, trivial_casts)] -#![deny(trivial_numeric_casts, private_in_public, variant_size_differences)] +#![deny(trivial_numeric_casts, variant_size_differences)] #![deny(stable_features, unreachable_pub, non_shorthand_field_patterns)] #![deny(unused_attributes, unused_mut)] #![deny(missing_docs)] @@ -359,16 +359,21 @@ pub trait PolynomialCommitment, S: Cryptographic Self::Commitment: 'a, { let BatchLCProof { proof, evals } = proof; - let lc_s = BTreeMap::from_iter(linear_combinations.into_iter().map(|lc| (lc.label(), lc))); let poly_query_set = lc_query_set_to_poly_query_set(lc_s.values().copied(), eqn_query_set); + let sorted_by_poly_and_query_label: BTreeSet<_> = poly_query_set + .iter() + .map(|(poly_label, v)| ((poly_label.clone(), v.1.clone()), v.0.clone())) + .collect(); + let poly_evals = Evaluations::from_iter( - poly_query_set + sorted_by_poly_and_query_label .iter() - .map(|(_, point)| point) - .cloned() - .zip(evals.clone().unwrap()), + .zip(evals.clone().unwrap()) + .map(|(((poly_label, point), _query_label), eval)| { + ((poly_label.clone(), point.clone()), eval) + }), ); for &(ref lc_label, (_, ref point)) in eqn_query_set { @@ -386,7 +391,9 @@ pub trait PolynomialCommitment, S: Cryptographic LCTerm::One => F::one(), LCTerm::PolyLabel(l) => *poly_evals .get(&(l.clone().into(), point.clone())) - .ok_or(Error::MissingEvaluation { label: l.clone() })?, + .ok_or(Error::MissingEvaluation { + label: format!("{}-{:?}", l.clone(), point.clone()), + })?, }; actual_rhs += &(*coeff * eval); diff --git a/src/ligero/data_structures.rs b/src/ligero/data_structures.rs index de512d4d..a3e7b54b 100644 --- a/src/ligero/data_structures.rs +++ b/src/ligero/data_structures.rs @@ -33,6 +33,39 @@ pub struct Ligero< pub(crate) _poly: PhantomData

, } +/// The public parameters for the Ligero polynomial commitment scheme. +/// This is only a default setup with reasonable parameters. +/// To create your own public parameters, use: +/// # Example +/// ```rust +/// use ark_bls12_377::Fr; +/// use ark_crypto_primitives::{ +/// crh::{pedersen, sha256::Sha256, CRHScheme, TwoToOneCRHScheme}, +/// merkle_tree::{ByteDigestConverter, Config}, +/// }; +/// use ark_std::test_rng; +/// use ark_poly_commit::ligero::LigeroPCUniversalParams; +/// use core::marker::PhantomData; +/// +/// type LeafH = Sha256; +/// type CompressH = Sha256; +/// struct MerkleTreeParams; +/// impl Config for MerkleTreeParams { +/// type Leaf = [u8]; +/// type LeafDigest = ::Output; +/// type LeafInnerDigestConverter = ByteDigestConverter; +/// type InnerDigest = ::Output; +/// type LeafHash = LeafH; +/// type TwoToOneHash = CompressH; +/// } +/// type MTConfig = MerkleTreeParams; +/// let mut rng = &mut test_rng(); +/// let leaf_hash_params = ::setup(&mut rng).unwrap(); +/// let two_to_one_params = ::setup(&mut rng) +/// .unwrap() +/// .clone(); +/// let pp: LigeroPCUniversalParams = LigeroPCUniversalParams::new(128, 2, true, +/// leaf_hash_params, two_to_one_params); #[derive(Derivative, CanonicalSerialize, CanonicalDeserialize)] #[derivative(Clone(bound = ""), Debug(bound = ""))] pub struct LigeroPCUniversalParams @@ -41,19 +74,45 @@ where <::TwoToOneHash as TwoToOneCRHScheme>::Parameters: Debug, <::LeafHash as CRHScheme>::Parameters: Debug, { - pub _field: PhantomData, + _field: PhantomData, /// The security parameter - pub sec_param: usize, + pub(crate) sec_param: usize, /// The inverse of the code rate. - pub rho_inv: usize, + pub(crate) rho_inv: usize, /// This is a flag which determines if the random linear combination is done. - pub check_well_formedness: bool, + pub(crate) check_well_formedness: bool, /// Parameters for hash function of Merkle tree leaves #[derivative(Debug = "ignore")] - pub leaf_hash_params: LeafParam, + pub(crate) leaf_hash_params: LeafParam, /// Parameters for hash function of Merke tree combining two nodes into one #[derivative(Debug = "ignore")] - pub two_to_one_params: TwoToOneParam, + pub(crate) two_to_one_params: TwoToOneParam, +} + +impl LigeroPCUniversalParams +where + F: PrimeField, + C: Config, + <::TwoToOneHash as TwoToOneCRHScheme>::Parameters: Debug, + <::LeafHash as CRHScheme>::Parameters: Debug, +{ + /// Create new LigeroPCUniversalParams + pub fn new( + sec_param: usize, + rho_inv: usize, + check_well_formedness: bool, + leaf_hash_params: LeafParam, + two_to_one_params: TwoToOneParam, + ) -> Self { + Self { + _field: PhantomData, + sec_param, + rho_inv, + check_well_formedness, + leaf_hash_params, + two_to_one_params, + } + } } impl PCUniversalParams for LigeroPCUniversalParams diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index e4e78783..94138635 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -23,7 +23,9 @@ use utils::Matrix; mod data_structures; use data_structures::*; -pub use data_structures::{Ligero, LigeroPCCommitterKey, LigeroPCProof, LigeroPCVerifierKey}; +pub use data_structures::{ + Ligero, LigeroPCCommitterKey, LigeroPCProof, LigeroPCUniversalParams, LigeroPCVerifierKey, +}; use utils::{calculate_t, compute_dimensions, get_indices_from_transcript, hash_column}; @@ -169,7 +171,9 @@ where type Error = Error; - /// This is only a default setup. + /// This is only a default setup with reasonable parameters. + /// To create your own public parameters (from which vk/ck can be derived by `trim`), + /// see the documentation for `LigeroPCUniversalParams`. fn setup( max_degree: usize, _num_vars: Option, @@ -179,14 +183,7 @@ where let two_to_one_params = ::setup(rng) .unwrap() .clone(); - let pp = Self::UniversalParams { - _field: PhantomData, - sec_param: 128, - rho_inv: 4, - check_well_formedness: true, - leaf_hash_params, - two_to_one_params, - }; + let pp = Self::UniversalParams::new(128, 4, true, leaf_hash_params, two_to_one_params); let real_max_degree = pp.max_degree(); if max_degree > real_max_degree || real_max_degree == 0 { return Err(Error::InvalidParameters( diff --git a/src/ligero/tests.rs b/src/ligero/tests.rs index 23bfaf5a..4f91a1bb 100644 --- a/src/ligero/tests.rs +++ b/src/ligero/tests.rs @@ -7,9 +7,8 @@ mod tests { ligero::{utils::*, Ligero, LigeroPCUniversalParams, PolynomialCommitment}, LabeledPolynomial, }; + use ark_bls12_377::Fq; use ark_bls12_377::Fr; - use ark_bls12_377::{Bls12_377, Fq}; - use ark_bls12_381::Bls12_381; use ark_bls12_381::Fr as Fr381; use ark_crypto_primitives::sponge::poseidon::PoseidonConfig; use ark_crypto_primitives::sponge::CryptographicSponge; @@ -18,8 +17,7 @@ mod tests { merkle_tree::{ByteDigestConverter, Config}, sponge::poseidon::PoseidonSponge, }; - use ark_ec::pairing::Pairing; - use ark_ff::PrimeField; + use ark_ff::{Field, PrimeField}; use ark_poly::{ domain::general::GeneralEvaluationDomain, univariate::DensePolynomial, DenseUVPolynomial, EvaluationDomain, Polynomial, @@ -37,14 +35,13 @@ mod tests { const NUM_WINDOWS: usize = 256; } - type LeafH = Sha256; //::CRH; - type CompressH = Sha256; //pedersen::TwoToOneCRH; + type LeafH = Sha256; + type CompressH = Sha256; struct MerkleTreeParams; impl Config for MerkleTreeParams { type Leaf = [u8]; - // type Leaf = Vec; type LeafDigest = ::Output; type LeafInnerDigestConverter = ByteDigestConverter; @@ -251,15 +248,6 @@ mod tests { PoseidonSponge::new(&config) } - #[test] - fn test_setup() { - let rng = &mut test_rng(); - let _ = LigeroPcsF::::setup(1 << 44, None, rng).unwrap(); - // but the base field of bls12_381 doesnt have such large domains - use ark_bls12_381::Fq as F_381; - assert_eq!(LigeroPcsF::::setup(20, None, rng).is_err(), true); - } - #[test] fn test_construction() { let degree = 4; @@ -301,16 +289,6 @@ mod tests { let mut challenge_generator: ChallengeGenerator> = ChallengeGenerator::new_univariate(&mut test_sponge); - // assert!( - // LigeroPCS::check_well_formedness( - // &c[0].commitment(), - // &leaf_hash_params, - // &two_to_one_params - // ) - // .is_ok(), - // "Well formedness check failed" - // ); - let proof = LigeroPCS::open( &ck, &[labeled_poly], @@ -334,330 +312,258 @@ mod tests { } #[test] - fn test_several_polynomials() { - let degrees = [4_usize, 13_usize, 30_usize]; - let mut rng = &mut test_rng(); - - LigeroPCS::setup(*degrees.iter().max().unwrap(), None, rng).unwrap(); - let leaf_hash_params = ::setup(&mut rng).unwrap(); - let two_to_one_params = ::setup(&mut rng) - .unwrap() - .clone(); - let check_well_formedness = true; - - let pp: LigeroPCUniversalParams = LigeroPCUniversalParams { - _field: PhantomData, - sec_param: 128, - rho_inv: 4, - check_well_formedness, - leaf_hash_params, - two_to_one_params, - }; - - let (ck, vk) = LigeroPCS::trim(&pp, 0, 0, None).unwrap(); - - let rand_chacha = &mut ChaCha20Rng::from_rng(test_rng()).unwrap(); - let mut test_sponge = test_sponge::(); - let mut challenge_generator: ChallengeGenerator> = - ChallengeGenerator::new_univariate(&mut test_sponge); - - let mut labeled_polys = Vec::new(); - let mut values = Vec::new(); - - let point = Fr::rand(rand_chacha); - - for degree in degrees { - let labeled_poly = LabeledPolynomial::new( - "test".to_string(), - rand_poly(degree, None, rand_chacha), - None, - None, - ); + fn test_calculate_t_with_good_parameters() { + assert!(calculate_t::(128, 4, 2_usize.pow(32)).unwrap() < 200); + assert!(calculate_t::(256, 4, 2_usize.pow(32)).unwrap() < 400); + } - values.push(labeled_poly.evaluate(&point)); - labeled_polys.push(labeled_poly); - } + #[test] + fn test_calculate_t_with_bad_parameters() { + calculate_t::((Fq::MODULUS_BIT_SIZE - 60) as usize, 4, 2_usize.pow(60)).unwrap_err(); + calculate_t::(400, 4, 2_usize.pow(32)).unwrap_err(); + } - let (commitments, randomness) = LigeroPCS::commit(&ck, &labeled_polys, None).unwrap(); + fn rand_point(_: Option, rng: &mut ChaCha20Rng) -> F { + F::rand(rng) + } - let proof = LigeroPCS::open( - &ck, - &labeled_polys, - &commitments, - &point, - &mut (challenge_generator.clone()), - &randomness, + #[test] + fn single_poly_test() { + use crate::tests::*; + single_poly_test::<_, _, LigeroPCS, _>( None, + rand_poly::, + rand_point::, + poseidon_sponge_for_test, ) - .unwrap(); - assert!(LigeroPCS::check( - &vk, - &commitments, - &point, - values, - &proof, - &mut challenge_generator, - None + .expect("test failed for bls12-377"); + single_poly_test::<_, _, LigeroPcsF, _>( + None, + rand_poly::, + rand_point::, + poseidon_sponge_for_test, ) - .unwrap()); + .expect("test failed for bls12-381"); } #[test] - #[should_panic(expected = "Mismatched lengths")] - fn test_several_polynomials_mismatched_lengths() { - // here we go through the same motions as in test_several_polynomials, - // but pass to check() one fewer value than we should - let degrees = [4_usize, 13_usize, 30_usize]; - let mut rng = &mut test_rng(); - - LigeroPCS::setup(*degrees.iter().max().unwrap(), None, rng).unwrap(); - let leaf_hash_params = ::setup(&mut rng).unwrap(); - let two_to_one_params = ::setup(&mut rng) - .unwrap() - .clone(); - - let check_well_formedness = true; - - let pp: LigeroPCUniversalParams = LigeroPCUniversalParams { - _field: PhantomData, - sec_param: 128, - rho_inv: 4, - check_well_formedness, - leaf_hash_params, - two_to_one_params, - }; - - let (ck, vk) = LigeroPCS::trim(&pp, 0, 0, None).unwrap(); - - let rand_chacha = &mut ChaCha20Rng::from_rng(test_rng()).unwrap(); - let mut test_sponge = test_sponge::(); - let mut challenge_generator: ChallengeGenerator> = - ChallengeGenerator::new_univariate(&mut test_sponge); - - let mut labeled_polys = Vec::new(); - let mut values = Vec::new(); - - let point = Fr::rand(rand_chacha); - - for degree in degrees { - let labeled_poly = LabeledPolynomial::new( - "test".to_string(), - rand_poly(degree, None, rand_chacha), - None, - None, - ); - - values.push(labeled_poly.evaluate(&point)); - labeled_polys.push(labeled_poly); - } - - let (commitments, randomness) = LigeroPCS::commit(&ck, &labeled_polys, None).unwrap(); - - let proof = LigeroPCS::open( - &ck, - &labeled_polys, - &commitments, - &point, - &mut (challenge_generator.clone()), - &randomness, + fn constant_poly_test() { + use crate::tests::*; + single_poly_test::<_, _, LigeroPCS, _>( None, + constant_poly::, + rand_point::, + poseidon_sponge_for_test, ) - .unwrap(); - assert!(LigeroPCS::check( - &vk, - &commitments, - &point, - values[0..2].to_vec(), - &proof, - &mut challenge_generator, - None + .expect("test failed for bls12-377"); + single_poly_test::<_, _, LigeroPcsF, _>( + None, + constant_poly::, + rand_point::, + poseidon_sponge_for_test, ) - .unwrap()); + .expect("test failed for bls12-381"); } #[test] - #[should_panic] - fn test_several_polynomials_swap_proofs() { - // in this test we work with three polynomials and swap the proofs of the first and last openings - let degrees = [4_usize, 13_usize, 30_usize]; - let mut rng = &mut test_rng(); - - LigeroPCS::setup(*degrees.iter().max().unwrap(), None, rng).unwrap(); - let leaf_hash_params = ::setup(&mut rng).unwrap(); - let two_to_one_params = ::setup(&mut rng) - .unwrap() - .clone(); - let check_well_formedness = true; - - let pp: LigeroPCUniversalParams = LigeroPCUniversalParams { - _field: PhantomData, - sec_param: 128, - rho_inv: 4, - check_well_formedness, - leaf_hash_params, - two_to_one_params, - }; - - let (ck, vk) = LigeroPCS::trim(&pp, 0, 0, None).unwrap(); - - let rand_chacha = &mut ChaCha20Rng::from_rng(test_rng()).unwrap(); - let mut test_sponge = test_sponge::(); - let mut challenge_generator: ChallengeGenerator> = - ChallengeGenerator::new_univariate(&mut test_sponge); - - let mut labeled_polys = Vec::new(); - let mut values = Vec::new(); - - let point = Fr::rand(rand_chacha); - - for degree in degrees { - let labeled_poly = LabeledPolynomial::new( - "test".to_string(), - rand_poly(degree, None, rand_chacha), - None, - None, - ); - - values.push(labeled_poly.evaluate(&point)); - labeled_polys.push(labeled_poly); - } - - let (commitments, randomness) = LigeroPCS::commit(&ck, &labeled_polys, None).unwrap(); - - let mut proof = LigeroPCS::open( - &ck, - &labeled_polys, - &commitments, - &point, - &mut (challenge_generator.clone()), - &randomness, - None, + fn quadratic_poly_degree_bound_multiple_queries_test() { + use crate::tests::*; + quadratic_poly_degree_bound_multiple_queries_test::<_, _, LigeroPCS, _>( + rand_poly::, + rand_point::, + poseidon_sponge_for_test, ) - .unwrap(); - - // to do swap opening proofs - proof.swap(0, 2); - - assert!(LigeroPCS::check( - &vk, - &commitments, - &point, - values, - &proof, - &mut challenge_generator, - None + .expect("test failed for bls12-377"); + quadratic_poly_degree_bound_multiple_queries_test::<_, _, LigeroPcsF, _>( + rand_poly::, + rand_point::, + poseidon_sponge_for_test, ) - .unwrap()); + .expect("test failed for bls12-381"); } #[test] - #[should_panic] - fn test_several_polynomials_swap_values() { - // in this test we work with three polynomials and swap the second - // and third values passed to the verifier externally - let degrees = [4_usize, 13_usize, 30_usize]; - let mut rng = &mut test_rng(); - - LigeroPCS::setup(*degrees.iter().max().unwrap(), None, rng).unwrap(); - let leaf_hash_params = ::setup(&mut rng).unwrap(); - let two_to_one_params = ::setup(&mut rng) - .unwrap() - .clone(); - let check_well_formedness = true; - - let pp: LigeroPCUniversalParams = LigeroPCUniversalParams { - _field: PhantomData, - sec_param: 128, - rho_inv: 4, - check_well_formedness, - leaf_hash_params, - two_to_one_params, - }; - - let (ck, vk) = LigeroPCS::trim(&pp, 0, 0, None).unwrap(); - - let rand_chacha = &mut ChaCha20Rng::from_rng(test_rng()).unwrap(); - let mut test_sponge = test_sponge::(); - let mut challenge_generator: ChallengeGenerator> = - ChallengeGenerator::new_univariate(&mut test_sponge); - - let mut labeled_polys = Vec::new(); - let mut values = Vec::new(); - - let point = Fr::rand(rand_chacha); + fn linear_poly_degree_bound_test() { + use crate::tests::*; + linear_poly_degree_bound_test::<_, _, LigeroPCS, _>( + rand_poly::, + rand_point::, + poseidon_sponge_for_test, + ) + .expect("test failed for bls12-377"); + linear_poly_degree_bound_test::<_, _, LigeroPcsF, _>( + rand_poly::, + rand_point::, + poseidon_sponge_for_test, + ) + .expect("test failed for bls12-381"); + } - for degree in degrees { - let labeled_poly = LabeledPolynomial::new( - "test".to_string(), - rand_poly(degree, None, rand_chacha), - None, - None, - ); + #[test] + fn single_poly_degree_bound_test() { + use crate::tests::*; + single_poly_degree_bound_test::<_, _, LigeroPCS, _>( + rand_poly::, + rand_point::, + poseidon_sponge_for_test, + ) + .expect("test failed for bls12-377"); + single_poly_degree_bound_test::<_, _, LigeroPcsF, _>( + rand_poly::, + rand_point::, + poseidon_sponge_for_test, + ) + .expect("test failed for bls12-381"); + } - values.push(labeled_poly.evaluate(&point)); - labeled_polys.push(labeled_poly); - } + #[test] + fn single_poly_degree_bound_multiple_queries_test() { + use crate::tests::*; + single_poly_degree_bound_multiple_queries_test::<_, _, LigeroPCS, _>( + rand_poly::, + rand_point::, + poseidon_sponge_for_test, + ) + .expect("test failed for bls12-377"); + single_poly_degree_bound_multiple_queries_test::<_, _, LigeroPcsF, _>( + rand_poly::, + rand_point::, + poseidon_sponge_for_test, + ) + .expect("test failed for bls12-381"); + } - let (commitments, randomness) = LigeroPCS::commit(&ck, &labeled_polys, None).unwrap(); + #[test] + fn two_polys_degree_bound_single_query_test() { + use crate::tests::*; + two_polys_degree_bound_single_query_test::<_, _, LigeroPCS, _>( + rand_poly::, + rand_point::, + poseidon_sponge_for_test, + ) + .expect("test failed for bls12-377"); + two_polys_degree_bound_single_query_test::<_, _, LigeroPcsF, _>( + rand_poly::, + rand_point::, + poseidon_sponge_for_test, + ) + .expect("test failed for bls12-381"); + } - let proof = LigeroPCS::open( - &ck, - &labeled_polys, - &commitments, - &point, - &mut (challenge_generator.clone()), - &randomness, + #[test] + fn full_end_to_end_test() { + use crate::tests::*; + full_end_to_end_test::<_, _, LigeroPCS, _>( None, + rand_poly::, + rand_point::, + poseidon_sponge_for_test, ) - .unwrap(); - - // swap values externally passed to verifier - values.swap(1, 2); - - assert!(LigeroPCS::check( - &vk, - &commitments, - &point, - values, - &proof, - &mut challenge_generator, - None + .expect("test failed for bls12-377"); + println!("Finished bls12-377"); + full_end_to_end_test::<_, _, LigeroPcsF, _>( + None, + rand_poly::, + rand_point::, + poseidon_sponge_for_test, ) - .unwrap()); + .expect("test failed for bls12-381"); + println!("Finished bls12-381"); } #[test] - fn test_calculate_t_with_good_parameters() { - assert!(calculate_t::(128, 4, 2_usize.pow(32)).unwrap() < 200); - assert!(calculate_t::(256, 4, 2_usize.pow(32)).unwrap() < 400); + fn single_equation_test() { + use crate::tests::*; + single_equation_test::<_, _, LigeroPCS, _>( + None, + rand_poly::, + rand_point::, + poseidon_sponge_for_test, + ) + .expect("test failed for bls12-377"); + println!("Finished bls12-377"); + single_equation_test::<_, _, LigeroPcsF, _>( + None, + rand_poly::, + rand_point::, + poseidon_sponge_for_test, + ) + .expect("test failed for bls12-381"); + println!("Finished bls12-381"); } #[test] - fn test_calculate_t_with_bad_parameters() { - calculate_t::((Fq::MODULUS_BIT_SIZE - 60) as usize, 4, 2_usize.pow(60)).unwrap_err(); - calculate_t::(400, 4, 2_usize.pow(32)).unwrap_err(); + fn two_equation_test() { + use crate::tests::*; + two_equation_test::<_, _, LigeroPCS, _>( + None, + rand_poly::, + rand_point::, + poseidon_sponge_for_test, + ) + .expect("test failed for bls12-377"); + println!("Finished bls12-377"); + two_equation_test::<_, _, LigeroPcsF, _>( + None, + rand_poly::, + rand_point::, + poseidon_sponge_for_test, + ) + .expect("test failed for bls12-381"); + println!("Finished bls12-381"); } - fn rand_point(_: Option, rng: &mut ChaCha20Rng) -> E::ScalarField { - E::ScalarField::rand(rng) + #[test] + fn two_equation_degree_bound_test() { + use crate::tests::*; + two_equation_degree_bound_test::<_, _, LigeroPCS, _>( + rand_poly::, + rand_point::, + poseidon_sponge_for_test, + ) + .expect("test failed for bls12-377"); + println!("Finished bls12-377"); + two_equation_degree_bound_test::<_, _, LigeroPcsF, _>( + rand_poly::, + rand_point::, + poseidon_sponge_for_test, + ) + .expect("test failed for bls12-381"); + println!("Finished bls12-381"); } #[test] - fn single_poly_test() { + fn full_end_to_end_equation_test() { use crate::tests::*; - single_poly_test::<_, _, LigeroPCS, _>( + full_end_to_end_equation_test::<_, _, LigeroPCS, _>( None, rand_poly::, - rand_point::, + rand_point::, poseidon_sponge_for_test, ) .expect("test failed for bls12-377"); - single_poly_test::<_, _, LigeroPcsF, _>( + println!("Finished bls12-377"); + full_end_to_end_equation_test::<_, _, LigeroPcsF, _>( None, rand_poly::, - rand_point::, + rand_point::, poseidon_sponge_for_test, ) .expect("test failed for bls12-381"); + println!("Finished bls12-381"); + } + + #[test] + #[should_panic] + fn bad_degree_bound_test() { + use crate::tests::*; + use ark_bls12_381::Fq as Fq381; + bad_degree_bound_test::<_, _, LigeroPcsF, _>( + rand_poly::, + rand_point::, + poseidon_sponge_for_test, + ) + .expect("test failed for bls12-377"); + println!("Finished bls12-377"); } } diff --git a/src/ligero/utils.rs b/src/ligero/utils.rs index 25724f78..d9409edb 100644 --- a/src/ligero/utils.rs +++ b/src/ligero/utils.rs @@ -70,6 +70,7 @@ impl Matrix { /// where n and m are the number of rows and columns, respectively. /// /// Index bound checks are waived for efficiency and behaviour under invalid indexing is undefined + #[cfg(test)] pub(crate) fn entry(&self, i: usize, j: usize) -> F { self.entries[i][j] } @@ -158,6 +159,7 @@ pub(crate) fn inner_product(v1: &[F], v2: &[F]) -> F { } #[inline] +#[cfg(test)] pub(crate) fn to_field(v: Vec) -> Vec { v.iter().map(|x| F::from(*x)).collect::>() } From 332fde51cd757747ff141e7d6155aba10092f030 Mon Sep 17 00:00:00 2001 From: mmagician Date: Fri, 29 Sep 2023 02:25:12 -0600 Subject: [PATCH 099/108] Fix `todo()`; Move `Ligero` implementation to data_structures; minor clippy lints (#31) * replace direct construction by `new` call to LigeroPCUniversalParams * some clippy fixes * replace `todo()`s by `default()` or `()` * move implementation of `Ligero` to data_structures * Add more info to `Ligero` struct incl. link and no-hiding note --- src/ligero/data_structures.rs | 151 +++++++++++++++++++++++++++++----- src/ligero/mod.rs | 118 +------------------------- src/ligero/tests.rs | 10 +-- src/ligero/utils.rs | 2 +- 4 files changed, 141 insertions(+), 140 deletions(-) diff --git a/src/ligero/data_structures.rs b/src/ligero/data_structures.rs index a3e7b54b..646ef4c7 100644 --- a/src/ligero/data_structures.rs +++ b/src/ligero/data_structures.rs @@ -1,4 +1,10 @@ +use crate::{ + Error, PCCommitment, PCCommitterKey, PCPreparedCommitment, PCPreparedVerifierKey, PCRandomness, + PCUniversalParams, PCVerifierKey, +}; use ark_crypto_primitives::crh::{CRHScheme, TwoToOneCRHScheme}; +use ark_crypto_primitives::merkle_tree::MerkleTree; +use ark_crypto_primitives::sponge::Absorb; use ark_crypto_primitives::{ merkle_tree::{Config, LeafParam, Path, TwoToOneParam}, sponge::CryptographicSponge, @@ -9,16 +15,22 @@ use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use ark_std::fmt::Debug; use core::marker::PhantomData; use digest::Digest; - -use crate::{ - PCCommitment, PCCommitterKey, PCPreparedCommitment, PCPreparedVerifierKey, PCRandomness, - PCUniversalParams, PCVerifierKey, -}; +use jf_primitives::pcs::transcript::IOPTranscript; +use std::borrow::Borrow; use ark_std::rand::RngCore; -// TODO: Disclaimer: no hiding prop -/// The Ligero polynomial commitment scheme. +use super::utils::Matrix; +use super::utils::{ + calculate_t, compute_dimensions, get_indices_from_transcript, hash_column, reed_solomon, +}; + +/// The univariate Ligero polynomial commitment scheme based on [[Ligero]][ligero]. +/// The scheme defaults to the naive batching strategy. +/// +/// Note: The scheme currently does not support hiding. +/// +/// [ligero]: https://eprint.iacr.org/2022/1608.pdf pub struct Ligero< F: PrimeField, C: Config, @@ -33,6 +45,114 @@ pub struct Ligero< pub(crate) _poly: PhantomData

, } +impl Ligero +where + F: PrimeField, + C: Config, + Vec: Borrow, + C::InnerDigest: Absorb, + D: Digest, + S: CryptographicSponge, + P: DenseUVPolynomial, +{ + /// Create a new instance of Ligero. + pub fn new() -> Self { + Self { + _config: PhantomData, + _field: PhantomData, + // TODO potentially can get rid of digest and sponge + _digest: PhantomData, + _sponge: PhantomData, + _poly: PhantomData, + } + } + + pub(crate) fn compute_matrices(polynomial: &P, rho_inv: usize) -> (Matrix, Matrix) { + let mut coeffs = polynomial.coeffs().to_vec(); + + // 1. Computing parameters and initial matrix + let (n_rows, n_cols) = compute_dimensions::(polynomial.degree() + 1); // for 6 coefficients, this is returning 4 x 2 with a row of 0s: fix + + // padding the coefficient vector with zeroes + // TODO is this the most efficient/safest way to do it? + coeffs.resize(n_rows * n_cols, F::zero()); + + let mat = Matrix::new_from_flat(n_rows, n_cols, &coeffs); + + // 2. Apply Reed-Solomon encoding row-wise + let ext_mat = Matrix::new_from_rows( + mat.rows() + .iter() + .map(|r| reed_solomon(r, rho_inv)) + .collect(), + ); + + (mat, ext_mat) + } + pub(crate) fn create_merkle_tree( + ext_mat: &Matrix, + leaf_hash_params: &<::LeafHash as CRHScheme>::Parameters, + two_to_one_params: &<::TwoToOneHash as TwoToOneCRHScheme>::Parameters, + ) -> MerkleTree { + let mut col_hashes: Vec> = Vec::new(); + let ext_mat_cols = ext_mat.cols(); + + for col in ext_mat_cols.iter() { + col_hashes.push(hash_column::(col)); + } + + // pad the column hashes with zeroes + let next_pow_of_two = col_hashes.len().next_power_of_two(); + col_hashes.resize(next_pow_of_two, vec![0; ::output_size()]); + + MerkleTree::::new(leaf_hash_params, two_to_one_params, col_hashes).unwrap() + } + + pub(crate) fn generate_proof( + sec_param: usize, + rho_inv: usize, + b: &[F], + mat: &Matrix, + ext_mat: &Matrix, + col_tree: &MerkleTree, + transcript: &mut IOPTranscript, + ) -> Result, Error> { + let t = calculate_t::(sec_param, rho_inv, ext_mat.n)?; + + // 1. left-multiply the matrix by `b`, where for a requested query point `z`, + // `b = [1, z^m, z^(2m), ..., z^((m-1)m)]` + let v = mat.row_mul(b); + + transcript + .append_serializable_element(b"v", &v) + .map_err(|_| Error::TranscriptError)?; + + // 2. Generate t column indices to test the linear combination on + let indices = get_indices_from_transcript(ext_mat.m, t, transcript)?; + + // 3. Compute Merkle tree paths for the requested columns + let mut queried_columns = Vec::with_capacity(t); + let mut paths = Vec::with_capacity(t); + + let ext_mat_cols = ext_mat.cols(); + + for i in indices { + queried_columns.push(ext_mat_cols[i].clone()); + paths.push( + col_tree + .generate_proof(i) + .map_err(|_| Error::TranscriptError)?, + ); + } + + Ok(LigeroPCProofSingle { + paths, + v, + columns: queried_columns, + }) + } +} + /// The public parameters for the Ligero polynomial commitment scheme. /// This is only a default setup with reasonable parameters. /// To create your own public parameters, use: @@ -223,9 +343,7 @@ where pub(crate) type LigeroPCPreparedVerifierKey = (); impl PCPreparedVerifierKey for LigeroPCPreparedVerifierKey { - fn prepare(_vk: &Unprepared) -> Self { - todo!() - } + fn prepare(_vk: &Unprepared) -> Self {} } #[derive(Derivative, CanonicalSerialize, CanonicalDeserialize)] #[derivative(Default(bound = ""), Clone(bound = ""), Debug(bound = ""))] @@ -247,28 +365,24 @@ pub struct LigeroPCCommitment { impl PCCommitment for LigeroPCCommitment { fn empty() -> Self { - todo!() + LigeroPCCommitment::default() } fn has_degree_bound(&self) -> bool { - todo!() + false } } pub(crate) type LigeroPCPreparedCommitment = (); impl PCPreparedCommitment for LigeroPCPreparedCommitment { - fn prepare(_cm: &Unprepared) -> Self { - todo!() - } + fn prepare(_cm: &Unprepared) -> Self {} } pub(crate) type LigeroPCRandomness = (); impl PCRandomness for LigeroPCRandomness { - fn empty() -> Self { - () - } + fn empty() -> Self {} fn rand( _num_queries: usize, @@ -276,7 +390,6 @@ impl PCRandomness for LigeroPCRandomness { _num_vars: Option, _rng: &mut R, ) -> Self { - todo!() } } diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 94138635..2a2754c3 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -1,11 +1,12 @@ use ark_crypto_primitives::crh::{CRHScheme, TwoToOneCRHScheme}; use ark_crypto_primitives::{ - merkle_tree::{Config, MerkleTree}, + merkle_tree::Config, sponge::{Absorb, CryptographicSponge}, }; use ark_ff::PrimeField; use ark_poly::DenseUVPolynomial; use ark_std::fmt::Debug; +use ark_std::rand::RngCore; use core::marker::PhantomData; use digest::Digest; use jf_primitives::pcs::transcript::IOPTranscript; @@ -15,10 +16,7 @@ use crate::data_structures::PCRandomness; use crate::ligero::utils::{inner_product, reed_solomon}; use crate::{Error, LabeledCommitment, LabeledPolynomial, PCUniversalParams, PolynomialCommitment}; -use ark_std::rand::RngCore; - mod utils; -use utils::Matrix; mod data_structures; use data_structures::*; @@ -27,118 +25,10 @@ pub use data_structures::{ Ligero, LigeroPCCommitterKey, LigeroPCProof, LigeroPCUniversalParams, LigeroPCVerifierKey, }; -use utils::{calculate_t, compute_dimensions, get_indices_from_transcript, hash_column}; +use utils::{calculate_t, get_indices_from_transcript, hash_column}; mod tests; -impl Ligero -where - F: PrimeField, - C: Config, - Vec: Borrow, - C::InnerDigest: Absorb, - D: Digest, - S: CryptographicSponge, - P: DenseUVPolynomial, -{ - /// Create a new instance of Ligero. - pub fn new() -> Self { - Self { - _config: PhantomData, - _field: PhantomData, - // TODO potentially can get rid of digest and sponge - _digest: PhantomData, - _sponge: PhantomData, - _poly: PhantomData, - } - } - - fn compute_matrices(polynomial: &P, rho_inv: usize) -> (Matrix, Matrix) { - let mut coeffs = polynomial.coeffs().to_vec(); - - // 1. Computing parameters and initial matrix - let (n_rows, n_cols) = compute_dimensions::(polynomial.degree() + 1); // for 6 coefficients, this is returning 4 x 2 with a row of 0s: fix - - // padding the coefficient vector with zeroes - // TODO is this the most efficient/safest way to do it? - coeffs.resize(n_rows * n_cols, F::zero()); - - let mat = Matrix::new_from_flat(n_rows, n_cols, &coeffs); - - // 2. Apply Reed-Solomon encoding row-wise - let ext_mat = Matrix::new_from_rows( - mat.rows() - .iter() - .map(|r| reed_solomon(r, rho_inv)) - .collect(), - ); - - (mat, ext_mat) - } - fn create_merkle_tree( - ext_mat: &Matrix, - leaf_hash_params: &<::LeafHash as CRHScheme>::Parameters, - two_to_one_params: &<::TwoToOneHash as TwoToOneCRHScheme>::Parameters, - ) -> MerkleTree { - let mut col_hashes: Vec> = Vec::new(); - let ext_mat_cols = ext_mat.cols(); - - for col in ext_mat_cols.iter() { - col_hashes.push(hash_column::(col)); - } - - // pad the column hashes with zeroes - let next_pow_of_two = col_hashes.len().next_power_of_two(); - col_hashes.resize(next_pow_of_two, vec![0; ::output_size()]); - - MerkleTree::::new(leaf_hash_params, two_to_one_params, col_hashes).unwrap() - } - - fn generate_proof( - sec_param: usize, - rho_inv: usize, - b: &[F], - mat: &Matrix, - ext_mat: &Matrix, - col_tree: &MerkleTree, - transcript: &mut IOPTranscript, - ) -> Result, Error> { - let t = calculate_t::(sec_param, rho_inv, ext_mat.n)?; - - // 1. left-multiply the matrix by `b`, where for a requested query point `z`, - // `b = [1, z^m, z^(2m), ..., z^((m-1)m)]` - let v = mat.row_mul(b); - - transcript - .append_serializable_element(b"v", &v) - .map_err(|_| Error::TranscriptError)?; - - // 2. Generate t column indices to test the linear combination on - let indices = get_indices_from_transcript(ext_mat.m, t, transcript)?; - - // 3. Compute Merkle tree paths for the requested columns - let mut queried_columns = Vec::with_capacity(t); - let mut paths = Vec::with_capacity(t); - - let ext_mat_cols = ext_mat.cols(); - - for i in indices { - queried_columns.push(ext_mat_cols[i].clone()); - paths.push( - col_tree - .generate_proof(i) - .map_err(|_| Error::TranscriptError)?, - ); - } - - Ok(LigeroPCProofSingle { - paths, - v, - columns: queried_columns, - }) - } -} - impl PolynomialCommitment for Ligero where F: PrimeField, @@ -517,7 +407,7 @@ where // matches with what the verifier computed for himself. // Note: we sacrifice some code repetition in order not to repeat execution. if let (Some(well_formedness), Some(r)) = out { - let w_well_formedness = reed_solomon(&well_formedness, vk.rho_inv); + let w_well_formedness = reed_solomon(well_formedness, vk.rho_inv); for (transcript_index, matrix_index) in indices.iter().enumerate() { check_inner_product( &r, diff --git a/src/ligero/tests.rs b/src/ligero/tests.rs index 4f91a1bb..0cb7ffa9 100644 --- a/src/ligero/tests.rs +++ b/src/ligero/tests.rs @@ -24,7 +24,6 @@ mod tests { }; use ark_std::test_rng; use blake2::Blake2s256; - use core::marker::PhantomData; use rand_chacha::{rand_core::SeedableRng, ChaCha20Rng}; type UniPoly = DensePolynomial; @@ -260,14 +259,13 @@ mod tests { .clone(); let check_well_formedness = true; - let pp: LigeroPCUniversalParams = LigeroPCUniversalParams { - _field: PhantomData, - sec_param: 128, - rho_inv: 4, + let pp: LigeroPCUniversalParams = LigeroPCUniversalParams::new( + 128, + 4, check_well_formedness, leaf_hash_params, two_to_one_params, - }; + ); let (ck, vk) = LigeroPCS::trim(&pp, 0, 0, None).unwrap(); diff --git a/src/ligero/utils.rs b/src/ligero/utils.rs index d9409edb..e49e6a66 100644 --- a/src/ligero/utils.rs +++ b/src/ligero/utils.rs @@ -147,7 +147,7 @@ pub(crate) fn reed_solomon( ) }); - extended_domain.fft(&msg) + extended_domain.fft(msg) } #[inline] From 9e40efb3bf809095cc307588007b5f8d8b1dafdf Mon Sep 17 00:00:00 2001 From: Hossein Moghaddas Date: Fri, 29 Sep 2023 12:47:23 +0200 Subject: [PATCH 100/108] Copy from `jellyfish` and patch dependency (#32) * Copy from `jellyfish` and patch dependency * Use `borrow` from `ark-std` * Remove default from `PhantomData` --- Cargo.toml | 7 ++- src/ligero/data_structures.rs | 9 ++-- src/ligero/mod.rs | 7 ++- src/ligero/utils.rs | 83 ++++++++++++++++++++++++++++++++++- 4 files changed, 94 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index af142092..e5760168 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ ark-serialize = { version = "^0.4.0", default-features = false, features = [ "de ark-ff = { version = "^0.4.0", default-features = false } ark-ec = { version = "^0.4.0", default-features = false } ark-poly = {version = "^0.4.0", default-features = false } -ark-crypto-primitives = { version = "^0.4.0", default-features = false, features = ["sponge","merkle_tree" ], git = "https://github.com/HungryCatsStudio/crypto-primitives" } +ark-crypto-primitives = { version = "^0.4.0", default-features = false, features = ["sponge","merkle_tree" ] } ark-std = { version = "^0.4.0", default-features = false } ark-relations = { version = "^0.4.0", default-features = false, optional = true } @@ -25,7 +25,7 @@ hashbrown = { version = "0.13", default-features = false, optional = true } digest = "0.10" derivative = { version = "2", features = [ "use_core" ] } rayon = { version = "1", optional = true } -jf-primitives = { version = "0.4.0-pre.0", git = "https://github.com/EspressoSystems/jellyfish/", rev = "6210b1f" } +merlin = { version = "3.0.0", default-features = false } [dev-dependencies] ark-ed-on-bls12-381 = { version = "^0.4.0", default-features = false } @@ -52,3 +52,6 @@ std = [ "ark-ff/std", "ark-ec/std", "ark-poly/std", "ark-std/std", "ark-relation r1cs = [ "ark-relations", "ark-r1cs-std", "hashbrown", "ark-crypto-primitives/r1cs"] print-trace = [ "ark-std/print-trace" ] parallel = [ "std", "ark-ff/parallel", "ark-ec/parallel", "ark-poly/parallel", "ark-std/parallel", "rayon" ] + +[patch.crates-io] +ark-crypto-primitives = { git = "https://github.com/arkworks-rs/crypto-primitives/", rev = "a0e1e85f4920ea45c0193663798b7732fa119925" } \ No newline at end of file diff --git a/src/ligero/data_structures.rs b/src/ligero/data_structures.rs index 646ef4c7..4af646fe 100644 --- a/src/ligero/data_structures.rs +++ b/src/ligero/data_structures.rs @@ -12,17 +12,16 @@ use ark_crypto_primitives::{ use ark_ff::PrimeField; use ark_poly::DenseUVPolynomial; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; +use ark_std::borrow::Borrow; use ark_std::fmt::Debug; -use core::marker::PhantomData; -use digest::Digest; -use jf_primitives::pcs::transcript::IOPTranscript; -use std::borrow::Borrow; - +use ark_std::marker::PhantomData; use ark_std::rand::RngCore; +use digest::Digest; use super::utils::Matrix; use super::utils::{ calculate_t, compute_dimensions, get_indices_from_transcript, hash_column, reed_solomon, + IOPTranscript, }; /// The univariate Ligero polynomial commitment scheme based on [[Ligero]][ligero]. diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 2a2754c3..79f38963 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -5,15 +5,14 @@ use ark_crypto_primitives::{ }; use ark_ff::PrimeField; use ark_poly::DenseUVPolynomial; +use ark_std::borrow::Borrow; use ark_std::fmt::Debug; +use ark_std::marker::PhantomData; use ark_std::rand::RngCore; -use core::marker::PhantomData; use digest::Digest; -use jf_primitives::pcs::transcript::IOPTranscript; -use std::borrow::Borrow; use crate::data_structures::PCRandomness; -use crate::ligero::utils::{inner_product, reed_solomon}; +use crate::ligero::utils::{inner_product, reed_solomon, IOPTranscript}; use crate::{Error, LabeledCommitment, LabeledPolynomial, PCUniversalParams, PolynomialCommitment}; mod utils; diff --git a/src/ligero/utils.rs b/src/ligero/utils.rs index e49e6a66..eafda8e1 100644 --- a/src/ligero/utils.rs +++ b/src/ligero/utils.rs @@ -2,8 +2,9 @@ use ark_ff::{FftField, Field, PrimeField}; use ark_poly::{EvaluationDomain, GeneralEvaluationDomain}; use ark_serialize::CanonicalSerialize; +use ark_std::marker::PhantomData; use digest::Digest; -use jf_primitives::pcs::transcript::IOPTranscript; +use merlin::Transcript; use rayon::{ iter::{IntoParallelRefIterator, ParallelIterator}, prelude::IndexedParallelIterator, @@ -181,6 +182,86 @@ macro_rules! to_bytes { }}; } +/// The following struct is taken from jellyfish repository. Once they change +/// their dependency on `crypto-primitive`, we use their crate instead of +/// a copy-paste. We needed the newer `crypto-primitive` for serializing. +#[derive(Clone)] +pub(crate) struct IOPTranscript { + transcript: Transcript, + is_empty: bool, + #[doc(hidden)] + phantom: PhantomData, +} + +// TODO: merge this with jf_plonk::transcript +impl IOPTranscript { + /// Create a new IOP transcript. + pub(crate) fn new(label: &'static [u8]) -> Self { + Self { + transcript: Transcript::new(label), + is_empty: true, + phantom: PhantomData, + } + } + + /// Append the message to the transcript. + pub(crate) fn append_message(&mut self, label: &'static [u8], msg: &[u8]) -> Result<(), Error> { + self.transcript.append_message(label, msg); + self.is_empty = false; + Ok(()) + } + + /// Append the message to the transcript. + pub(crate) fn append_serializable_element( + &mut self, + label: &'static [u8], + group_elem: &S, + ) -> Result<(), Error> { + self.append_message( + label, + &to_bytes!(group_elem).map_err(|_| Error::TranscriptError)?, + ) + } + + /// Generate the challenge from the current transcript + /// and append it to the transcript. + /// + /// The output field element is statistical uniform as long + /// as the field has a size less than 2^384. + pub(crate) fn get_and_append_challenge(&mut self, label: &'static [u8]) -> Result { + // we need to reject when transcript is empty + if self.is_empty { + return Err(Error::TranscriptError); + } + + let mut buf = [0u8; 64]; + self.transcript.challenge_bytes(label, &mut buf); + let challenge = F::from_le_bytes_mod_order(&buf); + self.append_serializable_element(label, &challenge)?; + Ok(challenge) + } + + /// Generate the challenge from the current transcript + /// and append it to the transcript. + /// + /// Without exposing the internal field `transcript`, + /// this is a wrapper around getting bytes as opposed to field elements. + pub(crate) fn get_and_append_byte_challenge( + &mut self, + label: &'static [u8], + dest: &mut [u8], + ) -> Result<(), Error> { + // we need to reject when transcript is empty + if self.is_empty { + return Err(Error::TranscriptError); + } + + self.transcript.challenge_bytes(label, dest); + self.append_message(label, dest)?; + Ok(()) + } +} + #[inline] pub(crate) fn hash_column(array: &[F]) -> Vec { let mut dig = D::new(); From 840ee52da23acc2856cd362a5653d297dc04f66c Mon Sep 17 00:00:00 2001 From: mmagician Date: Fri, 29 Sep 2023 05:56:14 -0600 Subject: [PATCH 101/108] no-std compat (#33) * use Vec/ToString from ark_std * rayon should only be enabled under the parallel feature * for no-std targets, enable Float arithmetic from num_traits --- Cargo.toml | 3 +++ src/ligero/data_structures.rs | 2 ++ src/ligero/mod.rs | 5 ++++- src/ligero/utils.rs | 5 +++++ 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index e5760168..5dcc2068 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,5 +53,8 @@ r1cs = [ "ark-relations", "ark-r1cs-std", "hashbrown", "ark-crypto-primitives/r1 print-trace = [ "ark-std/print-trace" ] parallel = [ "std", "ark-ff/parallel", "ark-ec/parallel", "ark-poly/parallel", "ark-std/parallel", "rayon" ] +[target.'cfg(target_arch = "aarch64")'.dependencies] +num-traits = { version = "0.2", default-features = false, features = ["libm"] } + [patch.crates-io] ark-crypto-primitives = { git = "https://github.com/arkworks-rs/crypto-primitives/", rev = "a0e1e85f4920ea45c0193663798b7732fa119925" } \ No newline at end of file diff --git a/src/ligero/data_structures.rs b/src/ligero/data_structures.rs index 4af646fe..64265045 100644 --- a/src/ligero/data_structures.rs +++ b/src/ligero/data_structures.rs @@ -16,6 +16,8 @@ use ark_std::borrow::Borrow; use ark_std::fmt::Debug; use ark_std::marker::PhantomData; use ark_std::rand::RngCore; +use ark_std::vec::Vec; + use digest::Digest; use super::utils::Matrix; diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 79f38963..07d0c13d 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -9,6 +9,9 @@ use ark_std::borrow::Borrow; use ark_std::fmt::Debug; use ark_std::marker::PhantomData; use ark_std::rand::RngCore; +use ark_std::vec::Vec; +use ark_std::string::ToString; + use digest::Digest; use crate::data_structures::PCRandomness; @@ -430,7 +433,7 @@ where } if inner_product(&proof_array[i].opening.v, &a) != values[i] { - println!("Function check: claimed value in position {i} does not match the evaluation of the committed polynomial in the same position"); + eprintln!("Function check: claimed value in position {i} does not match the evaluation of the committed polynomial in the same position"); return Ok(false); } } diff --git a/src/ligero/utils.rs b/src/ligero/utils.rs index eafda8e1..4e78e68e 100644 --- a/src/ligero/utils.rs +++ b/src/ligero/utils.rs @@ -3,8 +3,13 @@ use ark_ff::{FftField, Field, PrimeField}; use ark_poly::{EvaluationDomain, GeneralEvaluationDomain}; use ark_serialize::CanonicalSerialize; use ark_std::marker::PhantomData; +use ark_std::string::ToString; +use ark_std::vec::Vec; use digest::Digest; use merlin::Transcript; +#[cfg(not(feature = "std"))] +use num_traits::Float; +#[cfg(feature = "parallel")] use rayon::{ iter::{IntoParallelRefIterator, ParallelIterator}, prelude::IndexedParallelIterator, From 46a6a859c3fb15427a1659124d119c550b415701 Mon Sep 17 00:00:00 2001 From: mmagician Date: Fri, 29 Sep 2023 19:22:52 +0200 Subject: [PATCH 102/108] post merge fmt --- src/ligero/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 07d0c13d..0cc22732 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -9,8 +9,8 @@ use ark_std::borrow::Borrow; use ark_std::fmt::Debug; use ark_std::marker::PhantomData; use ark_std::rand::RngCore; -use ark_std::vec::Vec; use ark_std::string::ToString; +use ark_std::vec::Vec; use digest::Digest; From a46ea2543aea6ff3c426a21b571586bd9e5fd7fe Mon Sep 17 00:00:00 2001 From: mmagician Date: Fri, 29 Sep 2023 19:25:40 +0200 Subject: [PATCH 103/108] place all PhantomData in one struct --- src/ligero/data_structures.rs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/ligero/data_structures.rs b/src/ligero/data_structures.rs index 64265045..28074c91 100644 --- a/src/ligero/data_structures.rs +++ b/src/ligero/data_structures.rs @@ -39,11 +39,7 @@ pub struct Ligero< S: CryptographicSponge, P: DenseUVPolynomial, > { - pub(crate) _field: PhantomData, - pub(crate) _config: PhantomData, - pub(crate) _digest: PhantomData, - pub(crate) _sponge: PhantomData, - pub(crate) _poly: PhantomData

, + _phantom: PhantomData<(F, C, D, S, P)>, } impl Ligero @@ -59,12 +55,7 @@ where /// Create a new instance of Ligero. pub fn new() -> Self { Self { - _config: PhantomData, - _field: PhantomData, - // TODO potentially can get rid of digest and sponge - _digest: PhantomData, - _sponge: PhantomData, - _poly: PhantomData, + _phantom: PhantomData, } } From 61f3c64324b31017ffe1f9b9d09b4c4f85e754ab Mon Sep 17 00:00:00 2001 From: mmagician Date: Wed, 4 Oct 2023 20:58:49 +0200 Subject: [PATCH 104/108] remove Debug bounds --- src/ligero/data_structures.rs | 17 ++--------------- src/ligero/mod.rs | 3 --- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/src/ligero/data_structures.rs b/src/ligero/data_structures.rs index 28074c91..75eba365 100644 --- a/src/ligero/data_structures.rs +++ b/src/ligero/data_structures.rs @@ -13,7 +13,6 @@ use ark_ff::PrimeField; use ark_poly::DenseUVPolynomial; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use ark_std::borrow::Borrow; -use ark_std::fmt::Debug; use ark_std::marker::PhantomData; use ark_std::rand::RngCore; use ark_std::vec::Vec; @@ -183,8 +182,6 @@ where pub struct LigeroPCUniversalParams where C: Config, - <::TwoToOneHash as TwoToOneCRHScheme>::Parameters: Debug, - <::LeafHash as CRHScheme>::Parameters: Debug, { _field: PhantomData, /// The security parameter @@ -205,8 +202,6 @@ impl LigeroPCUniversalParams where F: PrimeField, C: Config, - <::TwoToOneHash as TwoToOneCRHScheme>::Parameters: Debug, - <::LeafHash as CRHScheme>::Parameters: Debug, { /// Create new LigeroPCUniversalParams pub fn new( @@ -231,8 +226,6 @@ impl PCUniversalParams for LigeroPCUniversalParams where F: PrimeField, C: Config, - <::TwoToOneHash as TwoToOneCRHScheme>::Parameters: Debug, - <::LeafHash as CRHScheme>::Parameters: Debug, { fn max_degree(&self) -> usize { if F::TWO_ADICITY < self.rho_inv as u32 { @@ -252,8 +245,6 @@ pub struct LigeroPCCommitterKey where F: PrimeField, C: Config, - <::TwoToOneHash as TwoToOneCRHScheme>::Parameters: Debug, - <::LeafHash as CRHScheme>::Parameters: Debug, { pub(crate) _field: PhantomData, /// The security parameter @@ -274,8 +265,6 @@ impl PCCommitterKey for LigeroPCCommitterKey where F: PrimeField, C: Config, - <::TwoToOneHash as TwoToOneCRHScheme>::Parameters: Debug, - <::LeafHash as CRHScheme>::Parameters: Debug, { fn max_degree(&self) -> usize { if (F::TWO_ADICITY - self.rho_inv as u32) * 2 < 64 { @@ -296,8 +285,6 @@ pub struct LigeroPCVerifierKey where F: PrimeField, C: Config, - <::TwoToOneHash as TwoToOneCRHScheme>::Parameters: Debug, - <::LeafHash as CRHScheme>::Parameters: Debug, { pub(crate) _field: PhantomData, /// The security parameter @@ -305,8 +292,10 @@ where /// The inverse of code rate pub(crate) rho_inv: usize, /// Parameters for hash function of Merkle tree leaves + #[derivative(Debug = "ignore")] pub(crate) leaf_hash_params: LeafParam, /// Parameters for hash function of Merke tree combining two nodes into one + #[derivative(Debug = "ignore")] pub(crate) two_to_one_params: TwoToOneParam, /// This is a flag which determines if the random linear combination is done. pub(crate) check_well_formedness: bool, @@ -316,8 +305,6 @@ impl PCVerifierKey for LigeroPCVerifierKey where F: PrimeField, C: Config, - <::TwoToOneHash as TwoToOneCRHScheme>::Parameters: Debug, - <::LeafHash as CRHScheme>::Parameters: Debug, { fn max_degree(&self) -> usize { if (F::TWO_ADICITY - self.rho_inv as u32) * 2 < 64 { diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 0cc22732..6e580228 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -6,7 +6,6 @@ use ark_crypto_primitives::{ use ark_ff::PrimeField; use ark_poly::DenseUVPolynomial; use ark_std::borrow::Borrow; -use ark_std::fmt::Debug; use ark_std::marker::PhantomData; use ark_std::rand::RngCore; use ark_std::string::ToString; @@ -38,8 +37,6 @@ where S: CryptographicSponge, C: Config + 'static, Vec: Borrow, - <::TwoToOneHash as TwoToOneCRHScheme>::Parameters: Debug, - <::LeafHash as CRHScheme>::Parameters: Debug, C::InnerDigest: Absorb, D: Digest, { From 44d20048a3c61c81ac80ec3d54296c52d506ac1e Mon Sep 17 00:00:00 2001 From: mmagician Date: Wed, 4 Oct 2023 21:17:01 +0200 Subject: [PATCH 105/108] PreparedCommitment = Commitment --- src/ligero/data_structures.rs | 10 +++++++--- src/ligero/mod.rs | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/ligero/data_structures.rs b/src/ligero/data_structures.rs index 75eba365..c83ca7de 100644 --- a/src/ligero/data_structures.rs +++ b/src/ligero/data_structures.rs @@ -352,10 +352,14 @@ impl PCCommitment for LigeroPCCommitment { } } -pub(crate) type LigeroPCPreparedCommitment = (); +pub(crate) type LigeroPCPreparedCommitment = LigeroPCCommitment; -impl PCPreparedCommitment for LigeroPCPreparedCommitment { - fn prepare(_cm: &Unprepared) -> Self {} +impl PCPreparedCommitment + for LigeroPCPreparedCommitment +{ + fn prepare(_cm: &Unprepared) -> Self { + LigeroPCPreparedCommitment::default() + } } pub(crate) type LigeroPCRandomness = (); diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 6e580228..7adf657a 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -50,7 +50,7 @@ where type Commitment = LigeroPCCommitment; - type PreparedCommitment = LigeroPCPreparedCommitment; + type PreparedCommitment = LigeroPCPreparedCommitment; type Randomness = LigeroPCRandomness; From 780f5257ad7953fe1e06b8668804775214016a6a Mon Sep 17 00:00:00 2001 From: mmagician Date: Wed, 4 Oct 2023 21:26:47 +0200 Subject: [PATCH 106/108] define an error string once, reuse in setup and trim --- src/ligero/mod.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 7adf657a..59eea2f8 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -30,6 +30,8 @@ use utils::{calculate_t, get_indices_from_transcript, hash_column}; mod tests; +const FIELD_SIZE_ERROR: &str = "This field is not suitable for the proposed parameters"; + impl PolynomialCommitment for Ligero where F: PrimeField, @@ -75,9 +77,7 @@ where let pp = Self::UniversalParams::new(128, 4, true, leaf_hash_params, two_to_one_params); let real_max_degree = pp.max_degree(); if max_degree > real_max_degree || real_max_degree == 0 { - return Err(Error::InvalidParameters( - "This field is not suitable for the proposed parameters".to_string(), - )); + return Err(Error::InvalidParameters(FIELD_SIZE_ERROR.to_string())); } Ok(pp) } @@ -89,9 +89,7 @@ where _enforced_degree_bounds: Option<&[usize]>, ) -> Result<(Self::CommitterKey, Self::VerifierKey), Self::Error> { if pp.max_degree() == 0 { - return Err(Error::InvalidParameters( - "This field is not suitable for the proposed parameters".to_string(), - )); + return Err(Error::InvalidParameters(FIELD_SIZE_ERROR.to_string())); } let ck = LigeroPCCommitterKey:: { _field: PhantomData, From 8d15d4ea35fbebe0a77ded5e1cd4b5b24bb02e0d Mon Sep 17 00:00:00 2001 From: mmagician Date: Wed, 4 Oct 2023 22:50:47 +0200 Subject: [PATCH 107/108] LigeroPCRandomness left temporarily unimplemented --- src/ligero/data_structures.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ligero/data_structures.rs b/src/ligero/data_structures.rs index c83ca7de..c64326db 100644 --- a/src/ligero/data_structures.rs +++ b/src/ligero/data_structures.rs @@ -365,7 +365,9 @@ impl PCPreparedCommitment pub(crate) type LigeroPCRandomness = (); impl PCRandomness for LigeroPCRandomness { - fn empty() -> Self {} + fn empty() -> Self { + unimplemented!() + } fn rand( _num_queries: usize, @@ -373,6 +375,7 @@ impl PCRandomness for LigeroPCRandomness { _num_vars: Option, _rng: &mut R, ) -> Self { + unimplemented!() } } From 6f3c6636050a15d6988c4c9a3b5a511703e98252 Mon Sep 17 00:00:00 2001 From: mmagician Date: Wed, 4 Oct 2023 23:57:29 +0200 Subject: [PATCH 108/108] `empty` is unimplemented, so let's explicitly insert `()` --- src/ligero/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ligero/mod.rs b/src/ligero/mod.rs index 59eea2f8..c26aafd3 100644 --- a/src/ligero/mod.rs +++ b/src/ligero/mod.rs @@ -13,7 +13,6 @@ use ark_std::vec::Vec; use digest::Digest; -use crate::data_structures::PCRandomness; use crate::ligero::utils::{inner_product, reed_solomon, IOPTranscript}; use crate::{Error, LabeledCommitment, LabeledPolynomial, PCUniversalParams, PolynomialCommitment}; @@ -167,7 +166,7 @@ where )); } let com_len = &commitments.len(); - Ok((commitments, vec![Self::Randomness::empty(); *com_len])) + Ok((commitments, vec![(); *com_len])) } fn open<'a>(