diff --git a/nomos-da/kzgrs-backend/src/encoder.rs b/nomos-da/kzgrs-backend/src/encoder.rs index da211f20..c8d98397 100644 --- a/nomos-da/kzgrs-backend/src/encoder.rs +++ b/nomos-da/kzgrs-backend/src/encoder.rs @@ -1,6 +1,7 @@ use crate::common::{hash_column_and_commitment, Chunk, ChunksMatrix, Row}; use crate::global::{DOMAIN, GLOBAL_PARAMETERS}; use ark_poly::univariate::DensePolynomial; +use kzgrs::common::bytes_to_polynomial_unchecked; use kzgrs::{ bytes_to_polynomial, commit_polynomial, encode, generate_element_proof, Commitment, Evaluations, KzgRsError, Polynomial, Proof, BYTES_PER_FIELD_ELEMENT, @@ -62,11 +63,15 @@ impl DaEncoder { matrix .rows() .map(|r| { - bytes_to_polynomial::(r.as_bytes().as_ref(), *DOMAIN) - .and_then(|(evals, poly)| { - commit_polynomial(&poly, &GLOBAL_PARAMETERS) - .map(|commitment| ((evals, poly), commitment)) - }) + // Using the unchecked version here. Because during the process of chunkifiying + // we already make sure to have the chunks of proper elements. + // Also, after rs encoding, we are sure all `Fr` elements already fits within modulus. + let (evals, poly) = bytes_to_polynomial_unchecked::( + r.as_bytes().as_ref(), + *DOMAIN, + ); + commit_polynomial(&poly, &GLOBAL_PARAMETERS) + .map(|commitment| ((evals, poly), commitment)) }) .collect() } @@ -217,4 +222,12 @@ pub mod test { assert_eq!(row.0[0].len(), BYTES_PER_FIELD_ELEMENT); } } + + #[test] + fn test_compute_row_kzg_commitments() { + let data = rand_data(32); + let matrix = ENCODER.chunkify(data.as_ref()); + let commitments_data = DaEncoder::compute_kzg_row_commitments(&matrix).unwrap(); + assert_eq!(commitments_data.len(), matrix.len()); + } } diff --git a/nomos-da/kzgrs/src/common.rs b/nomos-da/kzgrs/src/common.rs index 1dcb968b..79f51ee2 100644 --- a/nomos-da/kzgrs/src/common.rs +++ b/nomos-da/kzgrs/src/common.rs @@ -1,6 +1,6 @@ // std // crates -use crate::Commitment; +use crate::{Commitment, BYTES_PER_FIELD_ELEMENT}; use ark_bls12_381::fr::Fr; use ark_ff::{BigInteger256, PrimeField, Zero}; use ark_poly::domain::general::GeneralEvaluationDomain; @@ -53,7 +53,7 @@ pub fn bytes_to_polynomial( data: &[u8], domain: GeneralEvaluationDomain, ) -> Result<(Evaluations, DensePolynomial), KzgRsError> { - if CHUNK_SIZE >= 32 { + if CHUNK_SIZE > BYTES_PER_FIELD_ELEMENT { return Err(KzgRsError::ChunkSizeTooBig(CHUNK_SIZE)); } if data.len() % CHUNK_SIZE != 0 { @@ -62,9 +62,21 @@ pub fn bytes_to_polynomial( current_size: data.len(), }); } + Ok(bytes_to_polynomial_unchecked::(data, domain)) +} + +/// Transform chunks of bytes (of size `CHUNK_SIZE`) into `Fr` which are considered evaluations of a +/// polynomial. Then use FFT to transform that polynomial into coefficient form. +/// No extra checks are done for the caller. +/// Caller need to ensure that `CHUNK_SIZE` is not bigger than the underlying `Fr` element can be +/// decoded from. +pub fn bytes_to_polynomial_unchecked( + data: &[u8], + domain: GeneralEvaluationDomain, +) -> (Evaluations, DensePolynomial) { let evals = bytes_to_evaluations::(data, domain); let coefficients = evals.interpolate_by_ref(); - Ok((evals, coefficients)) + (evals, coefficients) } #[cfg(test)]