Implement row proofs tests
Fix fieldelement encoding/decoding bug
This commit is contained in:
parent
76bc6a4a6c
commit
fa61a80a1d
|
@ -15,3 +15,6 @@ once_cell = "1.19"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
|
itertools = "0.12"
|
||||||
|
ark-ff = "0.4"
|
||||||
|
num-bigint = "0.4.4"
|
|
@ -3,7 +3,7 @@ use blake2::digest::{Update, VariableOutput};
|
||||||
use kzgrs::Commitment;
|
use kzgrs::Commitment;
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Eq, PartialEq, Debug)]
|
||||||
pub struct Chunk(pub Vec<u8>);
|
pub struct Chunk(pub Vec<u8>);
|
||||||
pub struct Row(pub Vec<Chunk>);
|
pub struct Row(pub Vec<Chunk>);
|
||||||
pub struct Column(pub Vec<Chunk>);
|
pub struct Column(pub Vec<Chunk>);
|
||||||
|
@ -29,6 +29,9 @@ impl From<&[u8]> for Chunk {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Row {
|
impl Row {
|
||||||
|
pub fn iter(&self) -> impl Iterator<Item = &Chunk> {
|
||||||
|
self.0.iter()
|
||||||
|
}
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.0.len()
|
self.0.len()
|
||||||
}
|
}
|
||||||
|
@ -38,6 +41,9 @@ impl Row {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Column {
|
impl Column {
|
||||||
|
pub fn iter(&self) -> impl Iterator<Item = &Chunk> {
|
||||||
|
self.0.iter()
|
||||||
|
}
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.0.len()
|
self.0.len()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
// std
|
||||||
|
use ark_ff::{BigInteger, PrimeField};
|
||||||
|
use std::ops::Div;
|
||||||
|
// crates
|
||||||
|
|
||||||
|
// internal
|
||||||
use crate::common::{hash_column_and_commitment, Chunk, ChunksMatrix, Row};
|
use crate::common::{hash_column_and_commitment, Chunk, ChunksMatrix, Row};
|
||||||
use crate::global::{DOMAIN, GLOBAL_PARAMETERS};
|
use crate::global::{DOMAIN, GLOBAL_PARAMETERS};
|
||||||
use ark_poly::univariate::DensePolynomial;
|
use ark_poly::univariate::DensePolynomial;
|
||||||
|
@ -42,7 +48,8 @@ impl DaEncoder {
|
||||||
|
|
||||||
fn chunkify(&self, data: &[u8]) -> ChunksMatrix {
|
fn chunkify(&self, data: &[u8]) -> ChunksMatrix {
|
||||||
let chunk_size =
|
let chunk_size =
|
||||||
self.params.column_count * DaEncoderParams::MAX_BLS12_381_ENCODING_CHUNK_SIZE;
|
// column count is divided by two, as later on rows are encoded to twice the size
|
||||||
|
self.params.column_count.div(2) * DaEncoderParams::MAX_BLS12_381_ENCODING_CHUNK_SIZE;
|
||||||
data.chunks(chunk_size)
|
data.chunks(chunk_size)
|
||||||
.map(|d| {
|
.map(|d| {
|
||||||
d.chunks(DaEncoderParams::MAX_BLS12_381_ENCODING_CHUNK_SIZE)
|
d.chunks(DaEncoderParams::MAX_BLS12_381_ENCODING_CHUNK_SIZE)
|
||||||
|
@ -89,13 +96,13 @@ impl DaEncoder {
|
||||||
fn compute_rows_proofs(
|
fn compute_rows_proofs(
|
||||||
polynomials: &[Polynomial],
|
polynomials: &[Polynomial],
|
||||||
commitments: &[Commitment],
|
commitments: &[Commitment],
|
||||||
size: usize,
|
proof_count: usize,
|
||||||
) -> Result<Vec<Vec<Proof>>, KzgRsError> {
|
) -> Result<Vec<Vec<Proof>>, KzgRsError> {
|
||||||
polynomials
|
polynomials
|
||||||
.iter()
|
.iter()
|
||||||
.zip(commitments.iter())
|
.zip(commitments.iter())
|
||||||
.map(|(poly, commitment)| {
|
.map(|(poly, commitment)| {
|
||||||
(0..size)
|
(0..proof_count)
|
||||||
.map(|i| generate_element_proof(i, poly, &GLOBAL_PARAMETERS, *DOMAIN))
|
.map(|i| generate_element_proof(i, poly, &GLOBAL_PARAMETERS, *DOMAIN))
|
||||||
.collect()
|
.collect()
|
||||||
})
|
})
|
||||||
|
@ -149,9 +156,7 @@ impl DaEncoder {
|
||||||
Row(eval
|
Row(eval
|
||||||
.evals
|
.evals
|
||||||
.iter()
|
.iter()
|
||||||
.map(|point| {
|
.map(|point| Chunk(point.into_bigint().to_bytes_le()))
|
||||||
Chunk(point.0 .0.iter().flat_map(|n| n.to_le_bytes()).collect())
|
|
||||||
})
|
|
||||||
.collect())
|
.collect())
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
|
@ -196,9 +201,12 @@ impl DaEncoder {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub mod test {
|
pub mod test {
|
||||||
use crate::encoder::{DaEncoder, DaEncoderParams};
|
use crate::encoder::{DaEncoder, DaEncoderParams};
|
||||||
use crate::global::DOMAIN;
|
use crate::global::{DOMAIN, GLOBAL_PARAMETERS};
|
||||||
|
use ark_ff::{BigInt, BigInteger, PrimeField};
|
||||||
|
use itertools::izip;
|
||||||
use kzgrs::common::bytes_to_polynomial_unchecked;
|
use kzgrs::common::bytes_to_polynomial_unchecked;
|
||||||
use kzgrs::{decode, BYTES_PER_FIELD_ELEMENT};
|
use kzgrs::{decode, verify_element_proof, FieldElement, BYTES_PER_FIELD_ELEMENT};
|
||||||
|
use num_bigint::BigUint;
|
||||||
use rand::RngCore;
|
use rand::RngCore;
|
||||||
use std::ops::Div;
|
use std::ops::Div;
|
||||||
|
|
||||||
|
@ -215,12 +223,12 @@ pub mod test {
|
||||||
fn test_chunkify() {
|
fn test_chunkify() {
|
||||||
let params = DaEncoderParams::default_with(2);
|
let params = DaEncoderParams::default_with(2);
|
||||||
let elements = 10usize;
|
let elements = 10usize;
|
||||||
let data = rand_data(10);
|
let data = rand_data(elements);
|
||||||
let encoder = DaEncoder::new(params);
|
let encoder = DaEncoder::new(params);
|
||||||
let matrix = encoder.chunkify(&data);
|
let matrix = encoder.chunkify(&data);
|
||||||
assert_eq!(matrix.len(), elements.div(params.column_count));
|
assert_eq!(matrix.len(), elements.div(params.column_count.div(2)));
|
||||||
for row in matrix.rows() {
|
for row in matrix.rows() {
|
||||||
assert_eq!(row.len(), params.column_count);
|
assert_eq!(row.len(), params.column_count.div(2));
|
||||||
assert_eq!(row.0[0].len(), BYTES_PER_FIELD_ELEMENT);
|
assert_eq!(row.0[0].len(), BYTES_PER_FIELD_ELEMENT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -234,7 +242,7 @@ pub mod test {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_rs_encode_rows() {
|
fn test_evals_to_chunk_matrix() {
|
||||||
let data = rand_data(32);
|
let data = rand_data(32);
|
||||||
let matrix = ENCODER.chunkify(data.as_ref());
|
let matrix = ENCODER.chunkify(data.as_ref());
|
||||||
let (poly_data, _): (Vec<_>, Vec<_>) = DaEncoder::compute_kzg_row_commitments(&matrix)
|
let (poly_data, _): (Vec<_>, Vec<_>) = DaEncoder::compute_kzg_row_commitments(&matrix)
|
||||||
|
@ -243,8 +251,35 @@ pub mod test {
|
||||||
.unzip();
|
.unzip();
|
||||||
let extended_rows = DaEncoder::rs_encode_rows(&poly_data);
|
let extended_rows = DaEncoder::rs_encode_rows(&poly_data);
|
||||||
let extended_matrix = DaEncoder::evals_to_chunk_matrix(&extended_rows);
|
let extended_matrix = DaEncoder::evals_to_chunk_matrix(&extended_rows);
|
||||||
for ((r1, r2), evals) in matrix.iter().zip(extended_matrix.iter()).zip(extended_rows) {
|
for (r1, r2) in izip!(matrix.iter(), extended_matrix.iter()) {
|
||||||
|
for (c1, c2) in izip!(r1.iter(), r2.iter()) {
|
||||||
|
assert_eq!(c1, c2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rs_encode_rows() {
|
||||||
|
let data = rand_data(32);
|
||||||
|
let matrix = ENCODER.chunkify(data.as_ref());
|
||||||
|
let (poly_data, _): (Vec<_>, Vec<_>) = DaEncoder::compute_kzg_row_commitments(&matrix)
|
||||||
|
.unwrap()
|
||||||
|
.into_iter()
|
||||||
|
.unzip();
|
||||||
|
let extended_rows = DaEncoder::rs_encode_rows(&poly_data);
|
||||||
|
let (evals, _): (Vec<_>, Vec<_>) = poly_data.into_iter().unzip();
|
||||||
|
// check encoding went well, original evaluation points vs extended ones
|
||||||
|
for (e1, e2) in izip!(evals.iter(), extended_rows.iter()) {
|
||||||
|
for (c1, c2) in izip!(&e1.evals, &e2.evals) {
|
||||||
|
assert_eq!(c1, c2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let extended_matrix = DaEncoder::evals_to_chunk_matrix(&extended_rows);
|
||||||
|
for (r1, r2, evals) in izip!(matrix.iter(), extended_matrix.iter(), extended_rows) {
|
||||||
assert_eq!(r1.len(), r2.len().div(2));
|
assert_eq!(r1.len(), r2.len().div(2));
|
||||||
|
for (c1, c2) in izip!(r1.iter(), r2.iter()) {
|
||||||
|
assert_eq!(c1, c2);
|
||||||
|
}
|
||||||
let points: Vec<_> = evals.evals.iter().cloned().map(Some).collect();
|
let points: Vec<_> = evals.evals.iter().cloned().map(Some).collect();
|
||||||
let poly_2 = decode(r1.len(), &points, *DOMAIN);
|
let poly_2 = decode(r1.len(), &points, *DOMAIN);
|
||||||
let (poly_1, _) = bytes_to_polynomial_unchecked::<BYTES_PER_FIELD_ELEMENT>(
|
let (poly_1, _) = bytes_to_polynomial_unchecked::<BYTES_PER_FIELD_ELEMENT>(
|
||||||
|
@ -254,4 +289,56 @@ pub mod test {
|
||||||
assert_eq!(poly_1, poly_2);
|
assert_eq!(poly_1, poly_2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_compute_row_proofs() {
|
||||||
|
let data = rand_data(32);
|
||||||
|
let matrix = ENCODER.chunkify(data.as_ref());
|
||||||
|
let (poly_data, commitments): (Vec<_>, Vec<_>) =
|
||||||
|
DaEncoder::compute_kzg_row_commitments(&matrix)
|
||||||
|
.unwrap()
|
||||||
|
.into_iter()
|
||||||
|
.unzip();
|
||||||
|
let extended_rows = DaEncoder::rs_encode_rows(&poly_data);
|
||||||
|
let (evals, polynomials): (Vec<_>, Vec<_>) = poly_data.into_iter().unzip();
|
||||||
|
let extended_matrix = DaEncoder::evals_to_chunk_matrix(&extended_rows);
|
||||||
|
let original_proofs =
|
||||||
|
DaEncoder::compute_rows_proofs(&polynomials, &commitments, PARAMS.column_count.div(2))
|
||||||
|
.unwrap();
|
||||||
|
let extended_proofs =
|
||||||
|
DaEncoder::compute_rows_proofs(&polynomials, &commitments, PARAMS.column_count)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let checks = izip!(matrix.iter(), &commitments, &original_proofs);
|
||||||
|
for (row, commitment, proofs) in checks {
|
||||||
|
assert_eq!(proofs.len(), row.len());
|
||||||
|
for (i, chunk) in row.iter().enumerate() {
|
||||||
|
let element = FieldElement::from_le_bytes_mod_order(chunk.as_bytes().as_ref());
|
||||||
|
assert!(verify_element_proof(
|
||||||
|
i,
|
||||||
|
&element,
|
||||||
|
&commitment,
|
||||||
|
&proofs[i],
|
||||||
|
*DOMAIN,
|
||||||
|
&GLOBAL_PARAMETERS
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let checks = izip!(extended_matrix.iter(), &commitments, &extended_proofs);
|
||||||
|
for (row, commitment, proofs) in checks {
|
||||||
|
assert_eq!(proofs.len(), row.len());
|
||||||
|
for (i, chunk) in row.iter().enumerate() {
|
||||||
|
println!("{i}");
|
||||||
|
let element = FieldElement::from_le_bytes_mod_order(chunk.as_bytes().as_ref());
|
||||||
|
assert!(verify_element_proof(
|
||||||
|
i,
|
||||||
|
&element,
|
||||||
|
&commitment,
|
||||||
|
&proofs[i],
|
||||||
|
*DOMAIN,
|
||||||
|
&GLOBAL_PARAMETERS
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ use ark_ff::{BigInteger256, PrimeField, Zero};
|
||||||
use ark_poly::domain::general::GeneralEvaluationDomain;
|
use ark_poly::domain::general::GeneralEvaluationDomain;
|
||||||
use ark_poly::evaluations::univariate::Evaluations;
|
use ark_poly::evaluations::univariate::Evaluations;
|
||||||
use ark_poly::univariate::DensePolynomial;
|
use ark_poly::univariate::DensePolynomial;
|
||||||
|
use num_bigint::BigUint;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
// internal
|
// internal
|
||||||
|
|
||||||
|
@ -34,10 +35,8 @@ pub fn bytes_to_evaluations<const CHUNK_SIZE: usize>(
|
||||||
.map(|e| {
|
.map(|e| {
|
||||||
// use little endian for convenience as shortening 1 byte (<32 supported)
|
// use little endian for convenience as shortening 1 byte (<32 supported)
|
||||||
// do not matter in this endianness
|
// do not matter in this endianness
|
||||||
let bint: BigInteger256 = Fr::from_le_bytes_mod_order(e)
|
let bui = BigUint::from_bytes_le(e);
|
||||||
.try_into()
|
Fr::from(bui)
|
||||||
.expect("Bytes size should fit for an 256 bits integer");
|
|
||||||
Fr::new(bint)
|
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
domain,
|
domain,
|
||||||
|
|
|
@ -49,7 +49,7 @@ pub fn verify_element_proof(
|
||||||
element: &Fr,
|
element: &Fr,
|
||||||
commitment: &Commitment<Bls12_381>,
|
commitment: &Commitment<Bls12_381>,
|
||||||
proof: &Proof<Bls12_381>,
|
proof: &Proof<Bls12_381>,
|
||||||
domain: &GeneralEvaluationDomain<Fr>,
|
domain: GeneralEvaluationDomain<Fr>,
|
||||||
global_parameters: &UniversalParams<Bls12_381>,
|
global_parameters: &UniversalParams<Bls12_381>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let u = domain.element(element_index);
|
let u = domain.element(element_index);
|
||||||
|
|
Loading…
Reference in New Issue