diff --git a/Cargo.Bazel.lock b/Cargo.Bazel.lock index a18a101cd0..6eb764bf43 100644 --- a/Cargo.Bazel.lock +++ b/Cargo.Bazel.lock @@ -1,5 +1,5 @@ { - "checksum": "f18b47b24d322559ba405f9cb8683e71d3b1c15dedbda6554ce1275594c7e08f", + "checksum": "493a31da6b3ac2a5605ba241c05d083f25487a1fdd2efcb09d582c8b3be8cba9", "crates": { "addchain 0.2.0": { "name": "addchain", @@ -18158,6 +18158,19 @@ ], "selects": {} }, + "deps_dev": { + "common": [ + { + "id": "rand 0.8.5", + "target": "rand" + }, + { + "id": "rand_chacha 0.3.1", + "target": "rand_chacha" + } + ], + "selects": {} + }, "edition": "2021", "version": "0.0.1" }, diff --git a/Cargo.lock b/Cargo.lock index ccaa92b2e9..3c2aa8214f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3520,6 +3520,8 @@ dependencies = [ "p3-poseidon2", "p3-symmetric", "p3-util", + "rand 0.8.5", + "rand_chacha", "sp1-core", "sp1-primitives", "sp1-prover", diff --git a/vendors/sp1/BUILD.bazel b/vendors/sp1/BUILD.bazel index 6518df1ae6..2adb0677cc 100644 --- a/vendors/sp1/BUILD.bazel +++ b/vendors/sp1/BUILD.bazel @@ -16,6 +16,8 @@ tachyon_rust_library( deps = all_crate_deps(normal = True) + [ ":baby_bear_poseidon2_cxx_bridge", ":baby_bear_poseidon2_duplex_challenger", + ":baby_bear_poseidon2_prover_data", + ":baby_bear_poseidon2_two_adic_fri_pcs", "//tachyon/rs:tachyon_rs", ], ) @@ -59,9 +61,14 @@ rust_cxx_bridge( tachyon_cc_library( name = "baby_bear_poseidon2_api_hdrs", - hdrs = ["include/baby_bear_poseidon2_duplex_challenger.h"], + hdrs = [ + "include/baby_bear_poseidon2_duplex_challenger.h", + "include/baby_bear_poseidon2_prover_data.h", + "include/baby_bear_poseidon2_two_adic_fri_pcs.h", + ], deps = [ "//tachyon/c/zk/air/sp1:baby_bear_poseidon2_duplex_challenger", + "//tachyon/c/zk/air/sp1:baby_bear_poseidon2_two_adic_fri_pcs", "@cxx.rs//:core", ], ) @@ -74,3 +81,21 @@ tachyon_cc_library( ":baby_bear_poseidon2_cxx_bridge/include", ], ) + +tachyon_cc_library( + name = "baby_bear_poseidon2_prover_data", + srcs = ["src/baby_bear_poseidon2_prover_data.cc"], + deps = [ + ":baby_bear_poseidon2_api_hdrs", + ":baby_bear_poseidon2_cxx_bridge/include", + ], +) + +tachyon_cc_library( + name = "baby_bear_poseidon2_two_adic_fri_pcs", + srcs = ["src/baby_bear_poseidon2_two_adic_fri_pcs.cc"], + deps = [ + ":baby_bear_poseidon2_api_hdrs", + ":baby_bear_poseidon2_cxx_bridge/include", + ], +) diff --git a/vendors/sp1/Cargo.toml b/vendors/sp1/Cargo.toml index f467413ae4..6d710de904 100644 --- a/vendors/sp1/Cargo.toml +++ b/vendors/sp1/Cargo.toml @@ -34,6 +34,8 @@ sp1-primitives = { git = "https://github.com/kroma-network/sp1.git", rev = "dd03 tachyon_rs = { path = "../../tachyon/rs" } [dev-dependencies] +rand = "0.8.5" +rand_chacha = "0.3.1" [features] default = [] diff --git a/vendors/sp1/include/baby_bear_poseidon2_prover_data.h b/vendors/sp1/include/baby_bear_poseidon2_prover_data.h new file mode 100644 index 0000000000..f4dd570cb0 --- /dev/null +++ b/vendors/sp1/include/baby_bear_poseidon2_prover_data.h @@ -0,0 +1,42 @@ +#ifndef VENDORS_SP1_INCLUDE_BABY_BEAR_POSEIDON2_PROVER_DATA_H_ +#define VENDORS_SP1_INCLUDE_BABY_BEAR_POSEIDON2_PROVER_DATA_H_ + +#include + +#include "rust/cxx.h" + +#include "tachyon/c/math/finite_fields/baby_bear/baby_bear.h" +#include "tachyon/c/zk/air/sp1/baby_bear_poseidon2_constants.h" +#include "tachyon/c/zk/air/sp1/baby_bear_poseidon2_field_merkle_tree.h" + +namespace tachyon::sp1_api::baby_bear_poseidon2 { + +struct TachyonBabyBear; + +class ProverData { + public: + ProverData() = default; + ProverData(tachyon_sp1_baby_bear_poseidon2_field_merkle_tree* tree, + bool owned_tree) + : tree_(tree), owned_tree_(owned_tree) {} + ProverData(const ProverData& other) = delete; + ProverData& operator=(const ProverData& other) = delete; + ~ProverData(); + + tachyon_baby_bear* commitment() { return commitment_; } + tachyon_sp1_baby_bear_poseidon2_field_merkle_tree** tree_ptr() { + return &tree_; + } + + void write_commit(rust::Slice values) const; + std::unique_ptr clone() const; + + private: + tachyon_baby_bear commitment_[TACHYON_PLONKY3_BABY_BEAR_POSEIDON2_CHUNK]; + tachyon_sp1_baby_bear_poseidon2_field_merkle_tree* tree_ = nullptr; + bool owned_tree_ = false; +}; + +} // namespace tachyon::sp1_api::baby_bear_poseidon2 + +#endif // VENDORS_SP1_INCLUDE_BABY_BEAR_POSEIDON2_PROVER_DATA_H_ diff --git a/vendors/sp1/include/baby_bear_poseidon2_two_adic_fri_pcs.h b/vendors/sp1/include/baby_bear_poseidon2_two_adic_fri_pcs.h new file mode 100644 index 0000000000..a3a2c297ac --- /dev/null +++ b/vendors/sp1/include/baby_bear_poseidon2_two_adic_fri_pcs.h @@ -0,0 +1,43 @@ +#ifndef VENDORS_SP1_INCLUDE_BABY_BEAR_POSEIDON2_TWO_ADIC_FRI_PCS_H_ +#define VENDORS_SP1_INCLUDE_BABY_BEAR_POSEIDON2_TWO_ADIC_FRI_PCS_H_ + +#include +#include + +#include + +#include "rust/cxx.h" + +#include "tachyon/c/zk/air/sp1/baby_bear_poseidon2_two_adic_fri_pcs.h" + +namespace tachyon::sp1_api::baby_bear_poseidon2 { + +class CommitResult; +class ProverData; +struct TachyonBabyBear; + +class TwoAdicFriPcs { + public: + TwoAdicFriPcs(size_t log_blowup, size_t num_queries, + size_t proof_of_work_bits); + TwoAdicFriPcs(const TwoAdicFriPcs& other) = delete; + TwoAdicFriPcs& operator=(const TwoAdicFriPcs& other) = delete; + ~TwoAdicFriPcs(); + + void allocate_ldes(size_t size) const; + rust::Slice coset_lde_batch( + rust::Slice values, size_t cols, + const TachyonBabyBear& shift) const; + std::unique_ptr commit() const; + + private: + tachyon_sp1_baby_bear_poseidon2_two_adic_fri_pcs* pcs_; +}; + +std::unique_ptr new_two_adic_fri_pcs(size_t log_blowup, + size_t num_queries, + size_t proof_of_work_bits); + +} // namespace tachyon::sp1_api::baby_bear_poseidon2 + +#endif // VENDORS_SP1_INCLUDE_BABY_BEAR_POSEIDON2_TWO_ADIC_FRI_PCS_H_ diff --git a/vendors/sp1/src/baby_bear_poseidon2.rs b/vendors/sp1/src/baby_bear_poseidon2.rs index 0f0210ddbb..0bf928182a 100644 --- a/vendors/sp1/src/baby_bear_poseidon2.rs +++ b/vendors/sp1/src/baby_bear_poseidon2.rs @@ -1,8 +1,18 @@ use std::{fmt::Debug, marker::PhantomData}; -use p3_challenger::{CanObserve, CanSample}; -use p3_field::Field; -use p3_symmetric::CryptographicPermutation; +use p3_baby_bear::BabyBear; +use p3_challenger::{CanObserve, CanSample, GrindingChallenger}; +use p3_commit::{Mmcs, OpenedValues, Pcs, PolynomialSpace, TwoAdicMultiplicativeCoset}; +use p3_dft::TwoAdicSubgroupDft; +use p3_field::{ExtensionField, Field, PackedField, PackedValue, TwoAdicField}; +use p3_fri::{FriConfig, TwoAdicFriPcsProof, VerificationError}; +use p3_matrix::{ + bitrev::BitReversableMatrix, + dense::{DenseMatrix, RowMajorMatrix}, + Matrix, +}; +use p3_symmetric::{CryptographicPermutation, Hash}; +use p3_util::log2_strict_usize; use tachyon_rs::math::finite_fields::baby_bear::BabyBear as TachyonBabyBearImpl; pub struct TachyonBabyBear(pub TachyonBabyBearImpl); @@ -23,6 +33,35 @@ pub mod ffi { fn sample(self: Pin<&mut DuplexChallenger>) -> Box; fn clone(&self) -> UniquePtr; } + + unsafe extern "C++" { + include!("vendors/sp1/include/baby_bear_poseidon2_prover_data.h"); + + type ProverData; + + fn write_commit(&self, values: &mut [TachyonBabyBear]); + fn clone(&self) -> UniquePtr; + } + + unsafe extern "C++" { + include!("vendors/sp1/include/baby_bear_poseidon2_two_adic_fri_pcs.h"); + + type TwoAdicFriPcs; + + fn new_two_adic_fri_pcs( + log_blowup: usize, + num_queries: usize, + proof_of_work_bits: usize, + ) -> UniquePtr; + fn allocate_ldes(&self, size: usize); + fn coset_lde_batch( + &self, + values: &mut [TachyonBabyBear], + cols: usize, + shift: &TachyonBabyBear, + ) -> &mut [TachyonBabyBear]; + fn commit(&self) -> UniquePtr; + } } pub struct DuplexChallenger { @@ -105,3 +144,200 @@ where *unsafe { std::mem::transmute::<_, Box>(self.inner.pin_mut().sample()) } } } + +pub struct ProverData { + inner: cxx::UniquePtr, + pub ldes: Vec>, +} + +impl Clone for ProverData { + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + ldes: self.ldes.clone(), + } + } +} + +impl Debug for ProverData { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("ProverData").finish() + } +} + +impl ProverData { + pub fn new(inner: cxx::UniquePtr) -> Self { + Self { + inner, + ldes: vec![], + } + } + + pub fn write_commit(&self, values: &mut [BabyBear]) { + self.inner + .write_commit(unsafe { std::mem::transmute(values) }) + } +} + +pub struct TwoAdicFriPcs { + log_n: usize, + inner: cxx::UniquePtr, + _marker: PhantomData<(Val, Dft, InputMmcs, FriMmcs)>, +} + +impl Debug for TwoAdicFriPcs { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("TwoAdicFriPcs").finish() + } +} + +impl TwoAdicFriPcs +where + Val: TwoAdicField, +{ + pub fn new( + log_n: usize, + fri_config: &FriConfig, + ) -> TwoAdicFriPcs { + Self { + log_n, + inner: ffi::new_two_adic_fri_pcs( + fri_config.log_blowup, + fri_config.num_queries, + fri_config.proof_of_work_bits, + ), + _marker: PhantomData, + } + } + + pub fn allocate_ldes(&self, size: usize) { + self.inner.allocate_ldes(size) + } + + pub fn coset_lde_batch( + &self, + evals: &mut RowMajorMatrix, + shift: Val, + ) -> RowMajorMatrix { + unsafe { + let data = self.inner.coset_lde_batch( + std::mem::transmute(evals.values.as_mut_slice()), + evals.width, + std::mem::transmute(&shift), + ); + + let vec = Vec::from_raw_parts( + std::mem::transmute(data.as_mut_ptr()), + data.len(), + data.len(), + ); + RowMajorMatrix::new(vec, evals.width) + } + } + + pub fn do_commit(&self) -> ProverData { + ProverData::new(self.inner.commit()) + } +} + +impl Pcs + for TwoAdicFriPcs +where + Val: TwoAdicField, + Dft: TwoAdicSubgroupDft, + InputMmcs: Mmcs, + FriMmcs: Mmcs, + Challenge: TwoAdicField + ExtensionField, + Challenger: + CanObserve + CanSample + GrindingChallenger, + >::ProverData>: Clone, +{ + type Domain = TwoAdicMultiplicativeCoset; + type Commitment = Hash< + <::Packing as PackedField>::Scalar, + <::Packing as PackedValue>::Value, + 8, + >; + type ProverData = crate::baby_bear_poseidon2::ProverData; + type Proof = TwoAdicFriPcsProof; + type Error = VerificationError; + + fn natural_domain_for_degree(&self, degree: usize) -> Self::Domain { + let log_n = log2_strict_usize(degree); + assert!(log_n <= self.log_n); + TwoAdicMultiplicativeCoset { + log_n, + shift: Val::one(), + } + } + + fn commit( + &self, + evaluations: Vec<(Self::Domain, RowMajorMatrix)>, + ) -> (Self::Commitment, Self::ProverData) { + self.allocate_ldes(evaluations.len()); + let mut ldes = vec![]; + for (domain, mut evals) in evaluations.into_iter() { + assert_eq!(domain.size(), evals.height()); + let shift = Val::generator() / domain.shift; + ldes.push(self.coset_lde_batch(&mut evals, shift)); + } + let mut prover_data = self.do_commit(); + prover_data.ldes = ldes; + let mut value = [<::Packing as PackedValue>::Value::default(); 8]; + prover_data.write_commit(unsafe { std::mem::transmute(value.as_mut_slice()) }); + (Self::Commitment::from(value), prover_data) + } + + fn get_evaluations_on_domain<'a>( + &self, + prover_data: &'a Self::ProverData, + idx: usize, + domain: Self::Domain, + ) -> impl Matrix + 'a { + assert_eq!(domain.shift, Val::generator()); + let lde = &prover_data.ldes[idx]; + assert!(lde.height() >= domain.size()); + lde.split_rows(domain.size()).0.bit_reverse_rows() + } + + fn open( + &self, + // For each round, + rounds: Vec<( + &Self::ProverData, + // for each matrix, + Vec< + // points to open + Vec, + >, + )>, + challenger: &mut Challenger, + ) -> (OpenedValues, Self::Proof) { + todo!() + } + + fn verify( + &self, + // For each round: + rounds: Vec<( + Self::Commitment, + // for each matrix: + Vec<( + // its domain, + Self::Domain, + // for each point: + Vec<( + // the point, + Challenge, + // values at the point + Vec, + )>, + )>, + )>, + proof: &Self::Proof, + challenger: &mut Challenger, + ) -> Result<(), Self::Error> { + todo!() + } +} diff --git a/vendors/sp1/src/baby_bear_poseidon2_prover_data.cc b/vendors/sp1/src/baby_bear_poseidon2_prover_data.cc new file mode 100644 index 0000000000..f0849c30ed --- /dev/null +++ b/vendors/sp1/src/baby_bear_poseidon2_prover_data.cc @@ -0,0 +1,28 @@ +#include "vendors/sp1/include/baby_bear_poseidon2_prover_data.h" + +#include + +#include "tachyon/base/logging.h" +#include "vendors/sp1/src/baby_bear_poseidon2.rs.h" + +namespace tachyon::sp1_api::baby_bear_poseidon2 { + +ProverData::~ProverData() { + if (owned_tree_) { + tachyon_sp1_baby_bear_poseidon2_field_merkle_tree_destroy(tree_); + } +} + +void ProverData::write_commit(rust::Slice values) const { + CHECK_EQ(values.size(), size_t{TACHYON_PLONKY3_BABY_BEAR_POSEIDON2_CHUNK}); + for (size_t i = 0; i < values.size(); ++i) { + memcpy(&values[i], &commitment_[i], sizeof(uint32_t)); + } +} + +std::unique_ptr ProverData::clone() const { + return std::make_unique( + tachyon_sp1_baby_bear_poseidon2_field_merkle_tree_clone(tree_), true); +} + +} // namespace tachyon::sp1_api::baby_bear_poseidon2 diff --git a/vendors/sp1/src/baby_bear_poseidon2_two_adic_fri_pcs.cc b/vendors/sp1/src/baby_bear_poseidon2_two_adic_fri_pcs.cc new file mode 100644 index 0000000000..ac2fa3eb27 --- /dev/null +++ b/vendors/sp1/src/baby_bear_poseidon2_two_adic_fri_pcs.cc @@ -0,0 +1,51 @@ +#include "vendors/sp1/include/baby_bear_poseidon2_two_adic_fri_pcs.h" + +#include "vendors/sp1/src/baby_bear_poseidon2.rs.h" + +namespace tachyon::sp1_api::baby_bear_poseidon2 { + +TwoAdicFriPcs::TwoAdicFriPcs(size_t log_blowup, size_t num_queries, + size_t proof_of_work_bits) + : pcs_(tachyon_sp1_baby_bear_poseidon2_two_adic_fri_pcs_create( + static_cast(log_blowup), num_queries, proof_of_work_bits)) { +} + +TwoAdicFriPcs::~TwoAdicFriPcs() { + tachyon_sp1_baby_bear_poseidon2_two_adic_fri_pcs_destroy(pcs_); +} + +void TwoAdicFriPcs::allocate_ldes(size_t size) const { + tachyon_sp1_baby_bear_poseidon2_two_adic_fri_pcs_allocate_ldes( + const_cast(pcs_), + size); +} + +rust::Slice TwoAdicFriPcs::coset_lde_batch( + rust::Slice values, size_t cols, + const TachyonBabyBear& shift) const { + size_t new_rows; + tachyon_baby_bear* data = + tachyon_sp1_baby_bear_poseidon2_two_adic_fri_pcs_coset_lde_batch( + const_cast(pcs_), + reinterpret_cast(values.data()), + values.size() / cols, cols, + reinterpret_cast(shift), &new_rows); + return {reinterpret_cast(data), new_rows * cols}; +} + +std::unique_ptr TwoAdicFriPcs::commit() const { + std::unique_ptr ret(new ProverData); + tachyon_sp1_baby_bear_poseidon2_two_adic_fri_pcs_commit( + const_cast(pcs_), + ret->commitment(), ret->tree_ptr()); + return ret; +} + +std::unique_ptr new_two_adic_fri_pcs(size_t log_blowup, + size_t num_queries, + size_t proof_of_work_bits) { + return std::make_unique(log_blowup, num_queries, + proof_of_work_bits); +} + +} // namespace tachyon::sp1_api::baby_bear_poseidon2 diff --git a/vendors/sp1/src/lib.rs b/vendors/sp1/src/lib.rs index f40231c2b0..df152a2243 100644 --- a/vendors/sp1/src/lib.rs +++ b/vendors/sp1/src/lib.rs @@ -1,6 +1,6 @@ pub mod baby_bear_poseidon2; pub mod challenger; -pub mod sp1; +pub mod two_adic_fri_pcs; #[cfg(test)] mod test { diff --git a/vendors/sp1/src/sp1.rs b/vendors/sp1/src/sp1.rs deleted file mode 100644 index ccfef87fb1..0000000000 --- a/vendors/sp1/src/sp1.rs +++ /dev/null @@ -1,128 +0,0 @@ -use std::marker::PhantomData; - -use p3_challenger::{CanObserve, CanSample, GrindingChallenger}; -use p3_commit::{Mmcs, OpenedValues, Pcs, PolynomialSpace, TwoAdicMultiplicativeCoset}; -use p3_dft::TwoAdicSubgroupDft; -use p3_field::{ExtensionField, TwoAdicField}; -use p3_fri::{FriConfig, TwoAdicFriPcsProof, VerificationError}; -use p3_matrix::bitrev::BitReversableMatrix; -use p3_matrix::dense::RowMajorMatrix; -use p3_matrix::Matrix; -use p3_util::log2_strict_usize; - -#[derive(Debug)] -pub struct TwoAdicFriPcs { - // degree bound - log_n: usize, - dft: Dft, - mmcs: InputMmcs, - fri: FriConfig, - _phantom: PhantomData, -} - -impl Pcs - for TwoAdicFriPcs -where - Val: TwoAdicField, - Dft: TwoAdicSubgroupDft, - InputMmcs: Mmcs, - FriMmcs: Mmcs, - Challenge: TwoAdicField + ExtensionField, - Challenger: - CanObserve + CanSample + GrindingChallenger, - >::ProverData>: Clone, -{ - type Domain = TwoAdicMultiplicativeCoset; - - type Commitment = InputMmcs::Commitment; - - type ProverData = InputMmcs::ProverData>; - - type Proof = TwoAdicFriPcsProof; - - type Error = VerificationError; - - fn natural_domain_for_degree(&self, degree: usize) -> Self::Domain { - let log_n = log2_strict_usize(degree); - assert!(log_n <= self.log_n); - TwoAdicMultiplicativeCoset { - log_n, - shift: Val::one(), - } - } - - fn commit( - &self, - evaluations: Vec<(Self::Domain, RowMajorMatrix)>, - ) -> (Self::Commitment, Self::ProverData) { - let ldes: Vec<_> = evaluations - .into_iter() - .map(|(domain, evals)| { - assert_eq!(domain.size(), evals.height()); - let log_n = log2_strict_usize(domain.size()); - assert!(log_n <= self.log_n); - let shift = Val::generator() / domain.shift; - // Commit to the bit-reversed LDE. - self.dft - .coset_lde_batch(evals, self.fri.log_blowup, shift) - .bit_reverse_rows() - .to_row_major_matrix() - }) - .collect(); - - self.mmcs.commit(ldes) - } - - fn get_evaluations_on_domain<'a>( - &self, - prover_data: &'a Self::ProverData, - idx: usize, - domain: Self::Domain, - ) -> impl Matrix + 'a { - // todo: handle extrapolation for LDEs we don't have - assert_eq!(domain.shift, Val::generator()); - let lde = self.mmcs.get_matrices(prover_data)[idx]; - assert!(lde.height() >= domain.size()); - lde.split_rows(domain.size()).0.bit_reverse_rows() - } - - fn open( - &self, - // For each round, - rounds: Vec<( - &Self::ProverData, - // for each matrix, - Vec< - // points to open - Vec, - >, - )>, - challenger: &mut Challenger, - ) -> (OpenedValues, Self::Proof) { - todo!() - } - - fn verify( - &self, - // For each round: - rounds: Vec<( - Self::Commitment, - // for each matrix: - Vec<( - // its domain, - Self::Domain, - // for each point: - Vec<( - // the point, - Challenge, - // values at the point - Vec, - )>, - )>, - )>, - proof: &Self::Proof, - challenger: &mut Challenger, - ) -> Result<(), Self::Error> { - todo!() - } -} diff --git a/vendors/sp1/src/two_adic_fri_pcs.rs b/vendors/sp1/src/two_adic_fri_pcs.rs new file mode 100644 index 0000000000..6f16864dc7 --- /dev/null +++ b/vendors/sp1/src/two_adic_fri_pcs.rs @@ -0,0 +1,123 @@ +#[cfg(test)] +mod test { + use p3_commit::Pcs; + use p3_commit::PolynomialSpace; + use p3_dft::TwoAdicSubgroupDft; + use p3_field::AbstractField; + use p3_fri::TwoAdicFriPcs; + use p3_matrix::{bitrev::BitReversableMatrix, dense::RowMajorMatrix, Matrix}; + use p3_util::log2_strict_usize; + use rand::{Rng, SeedableRng}; + use rand_chacha::ChaCha20Rng; + use sp1_core::utils::baby_bear_poseidon2::{ + default_fri_config, my_perm, Challenge, ChallengeMmcs, Challenger, Dft, MyCompress, MyHash, + Val, ValMmcs, + }; + + use crate::baby_bear_poseidon2::TwoAdicFriPcs as TachyonTwoAdicFriPcs; + + fn seeded_rng() -> impl Rng { + ChaCha20Rng::seed_from_u64(0) + } + + #[test] + fn test_two_adic_fri_pcs() { + const ROWS: usize = 32; + const COLS: usize = 5; + const LOG_N: usize = 20; + + let perm = my_perm(); + let hash = MyHash::new(perm.clone()); + let compress = MyCompress::new(perm.clone()); + let val_mmcs = ValMmcs::new(hash, compress); + let dft = Dft {}; + let fri_config = default_fri_config(); + + let pcs = TwoAdicFriPcs::::new( + LOG_N, dft, val_mmcs, fri_config, + ); + + let fri_config = default_fri_config(); + let tachyon_pcs = + TachyonTwoAdicFriPcs::::new(LOG_N, &fri_config); + + let mut rng = seeded_rng(); + let log_degrees_by_round = [[3, 4], [3, 4]]; + + let domains_and_polys_by_round = log_degrees_by_round + .iter() + .map(|log_degrees| { + log_degrees + .iter() + .map(|&log_degree| { + let d = 1 << log_degree; + // random width 5-15 + let width = 5 + rng.gen_range(0..=10); + ( + as Pcs< + Challenge, + Challenger, + >>::natural_domain_for_degree(&pcs, d), + RowMajorMatrix::::rand(&mut rng, d, width), + ) + }) + .collect::>() + }) + .collect::>(); + + let (commits_by_round, data_by_round): (Vec<_>, Vec<_>) = domains_and_polys_by_round + .iter() + .map(|domains_and_polys| { + as Pcs< + Challenge, + Challenger, + >>::commit(&pcs, domains_and_polys.clone()) + }) + .unzip(); + + let (tachyon_commits_by_round, tachyon_data_by_round): (Vec<_>, Vec<_>) = + domains_and_polys_by_round + .iter() + .map(|domains_and_polys| { + as Pcs< + Challenge, + Challenger, + >>::commit(&tachyon_pcs, domains_and_polys.clone()) + }) + .unzip(); + + assert_eq!(commits_by_round, tachyon_commits_by_round); + + let ldes_vec = domains_and_polys_by_round + .iter() + .map(|domains_and_polys| { + domains_and_polys + .into_iter() + .map(|(domain, evals)| { + assert_eq!(domain.size(), evals.height()); + let log_n = log2_strict_usize(domain.size()); + let shift = Val::generator() / domain.shift; + // Commit to the bit-reversed LDE. + Dft {} + .coset_lde_batch(evals.clone(), fri_config.log_blowup, shift) + .bit_reverse_rows() + .to_row_major_matrix() + }) + .collect::>() + }) + .collect::>(); + + for (i, ldes) in ldes_vec.clone().into_iter().enumerate() { + for (j, lde) in ldes.into_iter().enumerate() { + let v = assert_eq!( + lde.to_row_major_matrix(), + tachyon_data_by_round[i].ldes[j] + .clone() + .to_row_major_matrix() + ); + } + } + // TODO(chokobole): `std::mem::forget` was used to prevent it from double-free. We need to figure out a more elegant solution. + std::mem::forget(tachyon_data_by_round); + } +}