diff --git a/crates/katana/primitives/src/da/blob.rs b/crates/katana/primitives/src/da/blob.rs index 2706df3d8a..76e7033503 100644 --- a/crates/katana/primitives/src/da/blob.rs +++ b/crates/katana/primitives/src/da/blob.rs @@ -2,7 +2,7 @@ use num_bigint::BigUint; use num_traits::Num; use super::eip4844::{BLOB_LEN, BLS_MODULUS, GENERATOR}; -use super::math::ifft; +use super::math::{fft, ifft}; /// Recovers the original data from a given blob. /// @@ -27,3 +27,15 @@ pub fn recover(data: Vec) -> Vec { ifft(data, xs, &BLS_MODULUS) } + +pub fn transform(data: Vec) -> Vec { + let xs: Vec = (0..BLOB_LEN) + .map(|i| { + let bin = format!("{:012b}", i); + let bin_rev = bin.chars().rev().collect::(); + GENERATOR.modpow(&BigUint::from_str_radix(&bin_rev, 2).unwrap(), &BLS_MODULUS) + }) + .collect(); + + fft(data, xs, &BLS_MODULUS) +} diff --git a/crates/katana/primitives/src/da/math.rs b/crates/katana/primitives/src/da/math.rs index fe82dc6e66..0973f6e6e6 100644 --- a/crates/katana/primitives/src/da/math.rs +++ b/crates/katana/primitives/src/da/math.rs @@ -5,6 +5,22 @@ lazy_static! { pub static ref TWO: BigUint = 2u32.to_biguint().unwrap(); } +pub fn fft(elements: Vec, xs: Vec, p: &BigUint) -> Vec { + let n = elements.len(); + let mut transform = vec![BigUint::ZERO; n]; + + for i in 0..n { + for j in (0..n).rev() { + let value = &transform[i] * &xs[i]; + let value = value + &elements[j]; + let value = value % p; + transform[i] = value; + } + } + + transform +} + /// Performs the inverse Fast Fourier Transform on a vector of `BigUint`. /// /// # Arguments diff --git a/crates/katana/primitives/tests/blobs.rs b/crates/katana/primitives/tests/blobs.rs index 9ae0d85ba1..831d653b74 100644 --- a/crates/katana/primitives/tests/blobs.rs +++ b/crates/katana/primitives/tests/blobs.rs @@ -1,4 +1,5 @@ use anyhow::Result; +use katana_primitives::da::eip4844::BLOB_LEN; use katana_primitives::da::encoding::encode_state_updates; use katana_primitives::da::serde::parse_str_to_blob_data; use katana_primitives::da::{blob, encoding}; @@ -17,8 +18,25 @@ fn read(path: &str) -> Vec { #[case("./tests/test-data/blobs/block_636263.txt")] #[case("./tests/test-data/blobs/block_636264.txt")] fn parse_blobs_rt(#[case] blob: &str) -> Result<()> { - let encoded = blob::recover(read(blob)); + // the fft'd version + let fftd = read(blob); + // the ifft'd version + let encoded = blob::recover(fftd.clone()); + let state_update = encoding::decode_state_updates(&encoded)?; - let _ = encode_state_updates(state_update); + let mut reencoded = encode_state_updates(state_update); + + // TODO: put this directly in the encoding module + while reencoded.len() < BLOB_LEN { + reencoded.push(BigUint::ZERO); + } + + // re-fft the reencoded data + let refftd = blob::transform(reencoded.clone()); + + // assert that our encoding and transformation functions are correct + similar_asserts::assert_eq!(encoded, reencoded); + similar_asserts::assert_eq!(fftd, refftd); + Ok(()) }