Skip to content

Commit

Permalink
compute_cells_and_kzg_proof
Browse files Browse the repository at this point in the history
  • Loading branch information
owanikin committed Aug 22, 2024
1 parent ddb5221 commit a8ac123
Show file tree
Hide file tree
Showing 3 changed files with 186 additions and 52 deletions.
155 changes: 104 additions & 51 deletions kzg/src/eip_4844.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,25 @@ use alloc::string::ToString;
use alloc::sync::Arc;
use alloc::vec;
use alloc::vec::Vec;
use std::ops::{Sub, Rem, Div};
use std::fmt::Debug;
use sha2::digest::generic_array::sequence;
use core::cell;
use core::result;
pub use blst::{blst_fr, blst_p1, blst_p2};
// use core::cell;
use core::ffi::c_uint;
use core::hash::Hash;
use core::hash::Hasher;
// use core::primitive;
use sha2::{Digest, Sha256};
use siphasher::sip::SipHasher;

use kzg::{FFTFr, Fr};
use crate::common_utils::reverse_bit_order;
use crate::msm::precompute::PrecomputationTable;
use crate::FFTFr;
use crate::G1Affine;
use crate::G1Fp;
use crate::G1GetFp;
use crate::G1LinComb;
use crate::{FFTSettings, Fr, G1Mul, KZGSettings, PairingVerify, Poly, G1, G2};
use crate::fk20_proof::{KzgFK20SingleSettings, KzgFK20MultiSettings, FK20SingleSettings, FK20MultiSettings, fk20_single_da_opt, fk20_multi_da_opt};

#[cfg(feature = "parallel")]
use rayon::prelude::*;
Expand All @@ -40,11 +41,6 @@ pub const BYTES_PER_BLOB: usize = BYTES_PER_FIELD_ELEMENT * FIELD_ELEMENTS_PER_B
pub const BYTES_PER_FIELD_ELEMENT: usize = 32;
pub const BYTES_PER_PROOF: usize = 48;
pub const BYTES_PER_COMMITMENT: usize = 48;
pub const BLS_MODULUS: [u8; BYTES_PER_FIELD_ELEMENT] = [
0x73, 0xED, 0xA7, 0x53, 0x29, 0x9D, 0x7D, 0x48, 0x33, 0x39, 0xD8, 0x08, 0x09, 0xA1, 0xD8,
0x05, 0x53, 0xBD, 0xA4, 0x02, 0xFF, 0xFE, 0x5B, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x01,
];

pub const TRUSTED_SETUP_PATH: &str = "src/trusted_setup.txt";

Expand Down Expand Up @@ -120,10 +116,14 @@ pub struct CKZGSettings {
pub g2_values: *mut blst_p2,
}

#[repr(C)]
pub struct Cell {
bytes: [u8; BYTES_PER_CELL],
}

#[repr(C)]
pub struct CellIndex(u64);

pub struct PrecomputationTableManager<TFr, TG1, TG1Fp, TG1Affine>
where
TFr: Fr,
Expand Down Expand Up @@ -732,14 +732,6 @@ pub fn verify_blob_kzg_proof_batch_rust<
}
}

fn compute_cell_evaulation_point<TFr: Fr>(cell_index: usize) -> Result<TFr, String> {
if cell_index >= CELLS_PER_EXT_BLOB {
return Err("Cell index out of range".to_string());
let primitive_root = TFr::from_u64(5);
Ok(primitive_root.pow(cell_index + 1))
}
}


#[allow(clippy::useless_conversion)]
pub fn bytes_to_blob<TFr: Fr>(bytes: &[u8]) -> Result<Vec<TFr>, String> {
Expand Down Expand Up @@ -946,44 +938,105 @@ pub fn load_trusted_setup_rust<

////////////////////////////// Trait based implementations of functions for EIP-7594 //////////////////////////////

pub fn compute_roots_of_unity<TFr: Fr>(order: usize) -> Vec<TFr> {
// Convert the BLS modulus to a field element type TFr
let bls_modulus_elem = TFr::from_bytes(&BLS_MODULUS).unwrap();

// Ensure order divides (MODULUS - 1)
assert_eq!((bls_modulus_elem).sub(&TFr::one()).modulo(&TFr::from_u64(order as u64)), TFr::zero(), "Order must divide MODULUS - 1");
// This code is a function that processes a "blob" of data to produce two main outputs: cells and proofs. Here's a simplified explanation:

// Compute the primitive root of unity
let primitive_root: TFr = TFr::from_u64(7u64);
let exponent = bls_modulus_elem.sub(TFr::one().div(&TFr::from_u64(order.try_into().unwrap())));
let root_of_unity = primitive_root.pow(exponent);
// Purpose: It takes a large piece of data (blob) and breaks it down into smaller pieces (cells) and creates mathematical proofs for each cell.
// Inputs:

// Compute powers
compute_powers(&root_of_unity, order)
}
// A blob of data
// Some pre-computed settings (KZGSettings)

fn _fft_field<
TFr: Fr,

// Outputs:

// An array of cells (smaller pieces of the original data)
// An array of proofs (one for each cell)


// Main steps:

// Convert the blob into a mathematical representation (polynomial)
// If cells are requested:

// Transform the polynomial to get data points
// Rearrange these points
// Convert the points into the cell format


// If proofs are requested:

// Compute proofs using the polynomial
// Rearrange the proofs
// Convert the proofs into the desired format



// **********************
// Key features:

// It can compute cells, proofs, or both
// It uses several mathematical operations (FFT, polynomial transformations)
// It includes error checking and memory management


// Usage: This function is likely part of a larger system dealing with data integrity or cryptographic operations, possibly related to blockchain or distributed systems.

// The code is complex and uses advanced mathematical concepts, but its core purpose is to process a large piece of data into smaller, verifiable pieces with associated proofs.

pub fn compute_cells_and_kzg_proofs_rust<
TFr: Fr,
TPoly: Poly<TFr>,
TG1: G1 + G1Mul<TFr> + G1GetFp<TG1Fp> + PairingVerify<TG1, TG2>,
TG2: G2,
TFFTSettings: FFTSettings<TFr>,
TPoly: Poly<TFr>,
TKZGSettings: KZGSettings<TFr, TG1, TG2, TFFTSettings, TPoly, TG1Fp, TG1Affine>,
TG1Fp: G1Fp,
TG1Affine: G1Affine<TG1, TG1Fp>,
>(vals: &[TFr], roots_of_unity: &[TFr]) -> Vec<TFr> {
if vals.len() == 1 {
return vals.to_vec();
}
let l = _fft_field(&vals.iter().step_by(2).cloned().collect::<Vec<_>>(), &roots_of_unity.iter().step_by(2).cloned().collect::<Vec<_>>());
let r = _fft_field(&vals.iter().skip(1).step_by(2).cloned().collect::<Vec<_>>(), &roots_of_unity.iter().step_by(2).cloned().collect::<Vec<_>>());
let mut o = vec![TFr::zero(); vals.len()];

for i in 0..l.len() {
let modulus_as_tfr = TFr::from_bytes(&BLS_MODULUS).expect("Invalid modulus bytes");
let y_times_root = (r[i].mul(&roots_of_unity[i])).modulo(BLS_MODULUS);
o[i] = (l[i].add(&y_times_root)).modulo(BLS_MODULUS);
o[i.add(l.len())] = (l[i].sub(&y_times_root).add(&modulus_as_tfr)).modulo(BLS_MODULUS);
}
o
}
TFFTSettings: FFTSettings<TFr> + FFTFr<TFr>,
TKZGSettings: KZGSettings<TFr, TG1, TG2, TFFTSettings, TPoly, TG1Fp, TG1Affine>,
>(
blob: &[TFr],
s: &TKZGSettings,
) -> Result<
(
Vec<Cell>,
Vec<KZGProof>
), String>{
// Ensure blob length is equal to Bytes per blob
if blob.len() != BYTES_PER_BLOB {
return Err(String::from("Blob length must be BYTES_PER_BLOB"));
}
// Convert the blob to a polynomial.
polynomial = blob_to_polynomial(blob)?;

// Allocate arrays to hold cells and proofs
let mut cells = vec![TFr::default(); CELLS_PER_EXT_BLOB];
let mut proofs = vec![TFr::default(); CELLS_PER_EXT_BLOB];

// Compute cells
let mut data_fr = vec![TFr::zero(); FIELD_ELEMENTS_PER_EXT_BLOB];

// Perform FFT on the polynomial
data_fr = s.get_fft_settings().fft_fr(&polynomial.get_coeffs(), false)?;

// Perform bit reversal permutation
bit_reversal_permutation(&mut data_fr)?;

// Covert field elements to cell bytes
for (i, cell) in cells.iter_mut().enumerate() {
for j in 0..FIELD_ELEMENTS_PER_CELL {
let index = i * FIELD_ELEMENTS_PER_CELL + j;
let fr_bytes = data_fr[index].to_bytes();
cell.bytes[j * BYTES_PER_FIELD_ELEMENT..(j+1) * BYTES_PER_FIELD_ELEMENT].copy_from_slice(&fr_bytes);
}
}

// Compute proofs
let mut proofs_g1 = vec![TG1::identity(); CELLS_PER_EXT_BLOB];
compute_fk20_proofs(&mut proofs_g1, &polynomial, FIELD_ELEMENTS_PER_BLOB, s);
bit_reversal_permutation(&mut proofs_g1)?;

Ok((cells, proofs))

}


80 changes: 80 additions & 0 deletions kzg/src/fk20_proof.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
use crate::consts::G1_IDENTITY;
use crate::eip_4844::FIELD_ELEMENTS_PER_CELL;
use crate::kzg_types::{ArkG1, ArkFr as BlstFr};
use crate::utils::PolyData;
use crate::{FFTFr, G1Mul, KZGSettings, G1};
use crate::utils::PolyData;
use kzg::{G1, G1Mul, FFTSetings, FFTFr};


fn compute_fk20_proofs<
TFr: FFTFr,
TG1: G1 + G1Mul
>(
p: &PolyData,
n: usize,
s: &KZGSettings
) -> Result<Vec<TG1>, String>{
let k = n / FIELD_ELEMENTS_PER_CELL;
let k2 = k * 2;

let mut toeplitz_coeff = vec![TG1::default(); k2];
let mut h = vec![TG1::identity(); k2];
let mut h_ext_fft = vec![TG1::identity(); k2];

for i in 0..FIELD_ELEMENTS_PER_CELL {
toeplitz_coeffs_stride(p, &mut toeplitz_coeffs, n, FIELD_ELEMENTS_PER_CELL)?;
s.get_fft_settings().fft_fr(&toeplitz_coeffs, false)?;
for j in 0..k2 {
h_ext_fft[j] = h_ext_fft[j].add_or_dbl(&s.x_ext_fft[j].mul(&toeplitz_coeffs[j]));
}
}

s.get_fft_settings().fft_g1(&h_ext_fft, false)?;

for i in h.iter_mut().take(k) {
*i = h_ext_fft[i.len() - 1];
}
for i in h.iter_mut().take(k2).skip(k) {
*i = G1_IDENTITY;
}

s.get_fft_settings().fft_g1(h.as_mut_slice(), false)?;

Ok(h)

}

fn toeplitz_coeffs_stride(
poly: &PolyData,
offset: usize,
stride: usize,
outlen: usize,
) -> Result<PolyData, String> {
let n = poly.len();

if stride == 0 {
return Err(String::from("stride must be greater than 0"));
}

let k = n / stride;
let k2 = k * 2;

if outlen < k2 {
return Err(String::from("outlen must be equal or greater than k2"));
}

let mut out = PolyData::new(outlen);
out.set_coeff_at(0, &poly.coeffs[n - 1 - offset]);
let mut i = 1;
while i <= (k + 1) && i < k2 {
out.set_coeff_at(i, &BlstFr::zero());
i += 1;
}
let mut j = 2 * stride - offset - 1;
for i in (k + 2)..k2 {
out.set_coeff_at(i, &poly.coeffs[j]);
j += stride;
}
Ok(out)
}
3 changes: 2 additions & 1 deletion kzg/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use msm::precompute::PrecomputationTable;
pub mod common_utils;
pub mod eip_4844;
pub mod msm;
pub mod fk20_proof;

pub trait Fr: Default + Clone + PartialEq + Sync {
fn null() -> Self;
Expand Down Expand Up @@ -134,7 +135,7 @@ pub trait G1GetFp<TFp: G1Fp>: G1 + Clone {
}

pub trait G1Mul<TFr: Fr>: G1 + Clone {
fn mul(&self, b: &TFr) -> Self;
fn mul(&self, b: &TFr) -> Self;
}

pub trait G1LinComb<TFr: Fr, TG1Fp: G1Fp, TG1Affine: G1Affine<Self, TG1Fp>>:
Expand Down

1 comment on commit a8ac123

@owanikin
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @sauliusgrigaitis , just an update on computing cells and kzg proofs. I'm still working on fk20proofs and bit_reversal_permutation. Will appreciate a feedback. You also mentioned a test to use from c-kzg, kindly point me to that.
Thank you!

Please sign in to comment.