From 68e06976289e8a73e6e5163c2269c1fcb347fe98 Mon Sep 17 00:00:00 2001 From: hangleang Date: Fri, 17 Jan 2025 11:49:02 +0700 Subject: [PATCH] PeerDAS: Add raw functions like eip4844 * fix clippy * add comments after debug * add placeholder byte into `recovered_cells` and `recovered_proofs` --- kzg/src/das.rs | 143 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 139 insertions(+), 4 deletions(-) diff --git a/kzg/src/das.rs b/kzg/src/das.rs index e815f264d..73a2e95ba 100644 --- a/kzg/src/das.rs +++ b/kzg/src/das.rs @@ -4,6 +4,7 @@ use core::fmt::Debug; use rayon::prelude::*; use alloc::{ + format, string::{String, ToString}, vec, vec::Vec, @@ -12,15 +13,18 @@ use alloc::{ use crate::{ common_utils::{reverse_bit_order, reverse_bits_limited}, eip_4844::{ - blob_to_polynomial, compute_powers, hash, hash_to_bls_field, BYTES_PER_COMMITMENT, - BYTES_PER_FIELD_ELEMENT, BYTES_PER_PROOF, + blob_to_polynomial, bytes_to_blob, compute_powers, hash, hash_to_bls_field, BYTES_PER_BLOB, + BYTES_PER_COMMITMENT, BYTES_PER_FIELD_ELEMENT, BYTES_PER_PROOF, }, - eth, FFTFr, FFTSettings, Fr, G1Affine, G1Fp, G1LinComb, KZGSettings, PairingVerify, Poly, - FFTG1, G1, G2, + eth::{self, BYTES_PER_CELL, CELLS_PER_EXT_BLOB, FIELD_ELEMENTS_PER_CELL, FIELD_ELEMENTS_PER_EXT_BLOB}, + FFTFr, FFTSettings, Fr, G1Affine, G1Fp, G1LinComb, KZGSettings, PairingVerify, Poly, FFTG1, G1, + G2, }; pub const RANDOM_CHALLENGE_KZG_CELL_BATCH_DOMAIN: [u8; 16] = *b"RCKZGCBATCH__V1_"; +pub type CellsKzgProofs = (Vec<[u8; BYTES_PER_CELL]>, Vec<[u8; BYTES_PER_PROOF]>); + macro_rules! cfg_iter_mut { ($collection:expr) => {{ #[cfg(feature = "parallel")] @@ -216,6 +220,40 @@ pub trait DAS { Ok(()) } + // TODO: there might be some fishy is the bytes conversion + fn recover_cells_and_kzg_proofs_raw( + &self, + cell_indices: &[usize], + cells: &[[u8; BYTES_PER_CELL]], + ) -> Result + where + ::G1: Copy, + ::Fr: Copy, + { + let nested_cells = cfg_iter!(cells) + .map(|bytes| bytes_to_cell::(bytes)) + .collect::>, _>>()?; + let cells = nested_cells.into_iter().flatten().collect::>(); + + let mut recovered_cells = [B::Fr::zero(); FIELD_ELEMENTS_PER_EXT_BLOB]; + let mut recovered_proofs = [B::G1::zero(); CELLS_PER_EXT_BLOB]; + + let _ = self.recover_cells_and_kzg_proofs( + &mut recovered_cells, + Some(&mut recovered_proofs), + cell_indices, + &cells, + ); + + let converted_cells = cells_elements_to_cells_bytes::(&recovered_cells)?; + let converted_proofs = recovered_proofs + .into_iter() + .map(|proof| proof.to_bytes()) + .collect::>(); + + Ok((converted_cells, converted_proofs)) + } + fn compute_cells_and_kzg_proofs( &self, cells: Option<&mut [B::Fr]>, @@ -261,6 +299,35 @@ pub trait DAS { Ok(()) } + // TODO: same as above + fn compute_cells_and_kzg_proofs_raw( + &self, + blob: [u8; BYTES_PER_BLOB], + ) -> Result + where + ::G1: Copy, + ::Fr: Copy, + { + let blob = bytes_to_blob(&blob)?; + + let mut recovered_cells = [B::Fr::zero(); FIELD_ELEMENTS_PER_EXT_BLOB]; + let mut recovered_proofs = [B::G1::zero(); CELLS_PER_EXT_BLOB]; + + let _ = self.compute_cells_and_kzg_proofs( + Some(&mut recovered_cells), + Some(&mut recovered_proofs), + &blob, + ); + + let converted_cells = cells_elements_to_cells_bytes::(&recovered_cells)?; + let converted_proofs = recovered_proofs + .into_iter() + .map(|proof| proof.to_bytes()) + .collect::>(); + + Ok((converted_cells, converted_proofs)) + } + fn verify_cell_kzg_proof_batch( &self, commitments: &[B::G1], @@ -362,6 +429,74 @@ pub trait DAS { power_of_s, )) } + + fn verify_cell_kzg_proof_batch_raw( + &self, + commitments: &[[u8; BYTES_PER_COMMITMENT]], + cell_indices: &[usize], + cells: &[[u8; BYTES_PER_CELL]], + proofs: &[[u8; BYTES_PER_PROOF]], + ) -> Result { + let commitments = cfg_iter!(commitments) + .map(|commitment| B::G1::from_bytes(commitment)) + .collect::, _>>()?; + + let nested_cells = cfg_iter!(cells) + .map(|bytes| bytes_to_cell::(bytes)) + .collect::>, _>>()?; + let cells = nested_cells.into_iter().flatten().collect::>(); + + let proofs = cfg_iter!(proofs) + .map(|proof| B::G1::from_bytes(proof)) + .collect::, _>>()?; + + self.verify_cell_kzg_proof_batch(&commitments, cell_indices, &cells, &proofs) + } +} + +fn bytes_to_cell(bytes: &[u8]) -> Result, String> { + if bytes.len() != BYTES_PER_CELL { + return Err(format!( + "Invalid byte length. Expected {} got {}", + BYTES_PER_CELL, + bytes.len(), + )); + } + + bytes + .chunks(BYTES_PER_FIELD_ELEMENT) + .map(B::Fr::from_bytes) + .collect() +} + +fn cells_elements_to_cells_bytes( + bytes: &[B::Fr], +) -> Result, String> { + // NOTE: chunk_size = BYTES_PER_CELL / BYTES_PER_FIELD_ELEMENT + let chunk_size = FIELD_ELEMENTS_PER_CELL; + if bytes.len() % chunk_size != 0 { + return Err(format!("Invalid byte length. got {}", bytes.len(),)); + } + + bytes + .chunks(chunk_size) + .map(|cell_bytes| { + let mut result = [0u8; BYTES_PER_CELL]; + for (idx, field_element) in cell_bytes.iter().enumerate() { + let bytes_element = field_element.to_bytes(); + let start = idx * BYTES_PER_FIELD_ELEMENT; + let end = start + BYTES_PER_FIELD_ELEMENT; + if end > BYTES_PER_CELL { + return Err(format!( + "Invalid cell byte length. Expected {} got {}", + BYTES_PER_CELL, end, + )); + } + result[start..end].copy_from_slice(&bytes_element); + } + Ok(result) + }) + .collect() } fn shift_poly(poly: &mut [B::Fr], shift_factor: &B::Fr) {