diff --git a/benchmark/fft_batch/fft_batch_runner.h b/benchmark/fft_batch/fft_batch_runner.h index d88aacecb..5779a3a16 100644 --- a/benchmark/fft_batch/fft_batch_runner.h +++ b/benchmark/fft_batch/fft_batch_runner.h @@ -37,7 +37,7 @@ class FFTBatchRunner { Domain::Create(static_cast(input.rows())); base::TimeTicks start = base::TimeTicks::Now(); if (run_coset_lde) { - domain->CosetLDEBatch(result, 0, F::Zero()); + result = domain->CosetLDEBatch(result, 0, F::Zero()); } else { domain->FFTBatch(result); } diff --git a/benchmark/fft_batch/plonky3/src/lib.rs b/benchmark/fft_batch/plonky3/src/lib.rs index 56f9b83c4..5d7944327 100644 --- a/benchmark/fft_batch/plonky3/src/lib.rs +++ b/benchmark/fft_batch/plonky3/src/lib.rs @@ -41,7 +41,9 @@ pub extern "C" fn run_coset_lde_batch_plonky3_baby_bear( let start = Instant::now(); let shift = BabyBear::zero(); - let dft_result = dft.coset_lde_batch(messages, 0, shift).to_row_major_matrix(); + let dft_result = dft + .coset_lde_batch(messages, 0, shift) + .to_row_major_matrix(); unsafe { duration.write(start.elapsed().as_micros() as u64); } diff --git a/benchmark/fri/README.md b/benchmark/fri/README.md index bae5c423f..53e140c4b 100644 --- a/benchmark/fri/README.md +++ b/benchmark/fri/README.md @@ -18,18 +18,18 @@ CPU Caches: ``` ```shell -bazel run -c opt --//:has_openmp --//:has_rtti --//:has_matplotlib //benchmark/fri:fri_benchmark -- -k 18 -k 19 -k 20 -k 21 -k 22 --batch_size 100 --input_num 4 --log_blowup 2 --vendor plonky3 --check_results +bazel run -c opt --//:has_openmp --//:has_rtti --//:has_matplotlib //benchmark/fri:fri_benchmark -- -k 18 -k 19 -k 20 -k 21 -k 22 --batch_size 100 --input_num 4 --round_num 4 --log_blowup 2 --vendor plonky3 --check_results ``` ## On Intel i9-13900K | Exponent | Tachyon | Plonky3 | | :------- | ----------- | ------- | -| 18 | **1.49223** | 1.70032 | -| 19 | **2.84027** | 3.45716 | -| 20 | **5.77075** | 6.91221 | -| 21 | **11.6113** | 13.8407 | -| 22 | **23.3140** | 27.9832 | +| 18 | **2.97871** | 3.73433 | +| 19 | **5.76021** | 7.22556 | +| 20 | **11.2744** | 14.3306 | +| 21 | **22.5167** | 28.8935 | +| 22 | **47.6511** | 58.5402 | ![image](/benchmark/fri/fri_benchmark_ubuntu_i9.png) diff --git a/benchmark/fri/fri_benchmark.cc b/benchmark/fri/fri_benchmark.cc index 1a3317a3e..abae2ab25 100644 --- a/benchmark/fri/fri_benchmark.cc +++ b/benchmark/fri/fri_benchmark.cc @@ -28,13 +28,13 @@ namespace tachyon::benchmark { extern "C" tachyon_baby_bear* run_fri_plonky3_baby_bear( - const tachyon_baby_bear* data, const size_t* raw_degrees, - size_t num_of_degrees, size_t batch_size, uint32_t log_blowup, + const tachyon_baby_bear* data, size_t input_num, size_t round_num, + size_t max_degree, size_t batch_size, uint32_t log_blowup, uint64_t* duration); -template -void CheckResult(bool check_results, const Commitment& tachyon_result, - const Commitment& vendor_result) { +template +void CheckResult(bool check_results, const Result& tachyon_result, + const Result& vendor_result) { if (check_results) { CHECK_EQ(tachyon_result, vendor_result) << "Results not matched"; } @@ -70,7 +70,7 @@ void Run(const FRIConfig& config) { using Challenger = crypto::DuplexChallenger; using MyPCS = crypto::TwoAdicFRI; - PackedF::Init(); + ExtF::Init(); ExtPackedF::Init(); crypto::Poseidon2Config poseidon2_config = @@ -95,6 +95,7 @@ void Run(const FRIConfig& config) { crypto::FRIConfig fri_config{config.log_blowup(), 10, 8, challenge_mmcs}; MyPCS pcs = MyPCS(std::move(mmcs), std::move(fri_config)); + Challenger challenger = Challenger(std::move(sponge)); SimpleReporter reporter; std::string name; @@ -106,7 +107,7 @@ void Run(const FRIConfig& config) { config.exponents(), [](uint32_t exponent) { return base::NumberToString(exponent); })); - FRIRunner runner(reporter, config, pcs); + FRIRunner runner(reporter, config, pcs, challenger); std::vector degrees = config.GetDegrees(); @@ -119,16 +120,17 @@ void Run(const FRIConfig& config) { math::RowMajorMatrix input = math::RowMajorMatrix::Random(degree, config.batch_size()); - F tachyon_commit = runner.Run(Vendor::Tachyon(), input); + ExtF tachyon_result, vendor_result; for (const Vendor vendor : config.vendors()) { if (vendor.value() == Vendor::kPlonky3) { - F vendor_commit = + vendor_result = runner.RunExternal(vendor, run_fri_plonky3_baby_bear, input); - CheckResult(config.check_results(), tachyon_commit, vendor_commit); } else { NOTREACHED(); } } + tachyon_result = runner.Run(Vendor::Tachyon(), input); + CheckResult(config.check_results(), tachyon_result, vendor_result); } reporter.Show(); diff --git a/benchmark/fri/fri_benchmark_ubuntu_i9.png b/benchmark/fri/fri_benchmark_ubuntu_i9.png index 96f4ffb8e..111f9cee5 100644 Binary files a/benchmark/fri/fri_benchmark_ubuntu_i9.png and b/benchmark/fri/fri_benchmark_ubuntu_i9.png differ diff --git a/benchmark/fri/fri_config.cc b/benchmark/fri/fri_config.cc index fe1dc364e..9f449ed1b 100644 --- a/benchmark/fri/fri_config.cc +++ b/benchmark/fri/fri_config.cc @@ -24,6 +24,11 @@ FRIConfig::FRIConfig() { .set_default_value(4) .set_help( "Specify the number of inputs in a single round. By default, 4."); + parser_.AddFlag>(&round_num_) + .set_short_name("-r") + .set_long_name("--round_num") + .set_default_value(4) + .set_help("Specify the number of rounds. By default, 4."); parser_.AddFlag>(&log_blowup_) .set_short_name("-l") .set_long_name("--log_blowup") diff --git a/benchmark/fri/fri_config.h b/benchmark/fri/fri_config.h index b89b7a22e..d7f7fe5ba 100644 --- a/benchmark/fri/fri_config.h +++ b/benchmark/fri/fri_config.h @@ -20,6 +20,7 @@ class FRIConfig : public Config { const std::vector& exponents() const { return exponents_; } size_t batch_size() const { return batch_size_; } size_t input_num() const { return input_num_; } + size_t round_num() const { return round_num_; } uint32_t log_blowup() const { return log_blowup_; } std::vector GetDegrees() const; @@ -32,6 +33,7 @@ class FRIConfig : public Config { std::vector exponents_; size_t batch_size_; size_t input_num_; + size_t round_num_; uint32_t log_blowup_; }; diff --git a/benchmark/fri/fri_runner.h b/benchmark/fri/fri_runner.h index dbe18177f..f7732d499 100644 --- a/benchmark/fri/fri_runner.h +++ b/benchmark/fri/fri_runner.h @@ -23,63 +23,98 @@ template class FRIRunner { public: using F = typename PCS::F; - using Domain = crypto::TwoAdicMultiplicativeCoset; + using ExtF = typename PCS::ExtF; + using Domain = typename PCS::Domain; + using Challenger = typename PCS::Challenger; + using Commitment = typename PCS::Commitment; + using ProverData = typename PCS::ProverData; + using FRIProof = typename PCS::FRIProof; + using OpenedValues = typename PCS::OpenedValues; typedef tachyon_baby_bear* (*ExternalFn)(const tachyon_baby_bear* data, - const size_t* degrees, - size_t num_of_degrees, - size_t batch_size, + size_t input_num, size_t round_num, + size_t max_degree, size_t batch_size, uint32_t log_blowup, uint64_t* duration); - FRIRunner(SimpleReporter& reporter, const FRIConfig& config, PCS& pcs) - : reporter_(reporter), config_(config), pcs_(pcs) {} + FRIRunner(SimpleReporter& reporter, const FRIConfig& config, PCS& pcs, + Challenger& challenger) + : reporter_(reporter), + config_(config), + pcs_(pcs), + challenger_(challenger) {} - F Run(Vendor vendor, const math::RowMajorMatrix& input) { + ExtF Run(Vendor vendor, const math::RowMajorMatrix& input) { size_t max_degree = static_cast(input.rows()); - std::vector degrees = GetInputDegrees(max_degree); - - std::vector> inner_polys = - base::Map(degrees, [this, input](size_t degree) { - math::RowMajorMatrix ret = - Eigen::Map>( - &input.data()[0], degree, config_.batch_size()); - return ret; - }); - - std::vector inner_domains = - base::Map(degrees, [this](size_t degree) { - return this->pcs_.GetNaturalDomainForDegree(degree); - }); + std::vector commits_by_round(config_.round_num()); + std::vector data_by_round(config_.round_num()); + std::vector> domains_by_round(config_.round_num()); + std::vector>> inner_polys_by_round( + config_.round_num()); + + Challenger p_challenger = challenger_; + + for (size_t round = 0; round < config_.round_num(); round++) { + std::vector degrees = GetInputDegrees(max_degree, round); + + domains_by_round[round] = base::Map(degrees, [this](size_t degree) { + return this->pcs_.GetNaturalDomainForDegree(degree); + }); + + inner_polys_by_round[round] = + base::Map(degrees, [this, round, input](size_t degree) { + math::RowMajorMatrix ret = + Eigen::Map>( + &input.data()[round], degree, config_.batch_size()); + return ret; + }); + } base::TimeTicks start = base::TimeTicks::Now(); - typename PCS::Commitment commit; - typename PCS::ProverData prover_data; - CHECK(pcs_.Commit(inner_domains, inner_polys, &commit, &prover_data)); + for (size_t round = 0; round < config_.round_num(); round++) { + CHECK(pcs_.Commit(domains_by_round[round], inner_polys_by_round[round], + &commits_by_round[round], &data_by_round[round])); + } + p_challenger.ObserveContainer2D(commits_by_round); + ExtF zeta = p_challenger.template SampleExtElement(); + + std::vector>> points_by_round( + config_.round_num()); + for (size_t round = 0; round < config_.round_num(); ++round) { + points_by_round[round] = + std::vector>(config_.input_num(), {zeta}); + } + OpenedValues openings; + FRIProof fri_proof; + CHECK(pcs_.CreateOpeningProof(data_by_round, points_by_round, p_challenger, + &openings, &fri_proof, pow_witness_)); reporter_.AddTime(vendor, base::TimeTicks::Now() - start); - return commit[1]; + return fri_proof.final_eval; } - F RunExternal(Vendor vendor, ExternalFn fn, - const math::RowMajorMatrix& input) { + ExtF RunExternal(Vendor vendor, ExternalFn fn, + const math::RowMajorMatrix& input) { size_t max_degree = static_cast(input.rows()); - std::vector degrees = GetInputDegrees(max_degree); uint64_t duration_in_us = 0; tachyon_baby_bear* data = - fn(c::base::c_cast(input.data()), °rees[0], degrees.size(), - config_.batch_size(), config_.log_blowup(), &duration_in_us); + fn(c::base::c_cast(input.data()), config_.input_num(), + config_.round_num(), max_degree, config_.batch_size(), + config_.log_blowup(), &duration_in_us); reporter_.AddTime(vendor, base::Microseconds(duration_in_us)); - return c::base::native_cast(data)[1]; + pow_witness_ = c::base::native_cast(data)[0]; + ExtF final_eval{ + c::base::native_cast(data)[1], c::base::native_cast(data)[2], + c::base::native_cast(data)[3], c::base::native_cast(data)[4]}; + return final_eval; } private: - std::vector GetInputDegrees(size_t max_degree) { + std::vector GetInputDegrees(size_t max_degree, size_t round) { std::vector degrees; degrees.reserve(config_.input_num()); - for (size_t d = max_degree >> (config_.input_num() - 1); d <= max_degree; - d <<= 1) { - degrees.push_back(d); + for (size_t i = 0; i < config_.input_num(); ++i) { + degrees.push_back(max_degree >> (i + round)); } return degrees; } @@ -87,6 +122,8 @@ class FRIRunner { SimpleReporter& reporter_; const FRIConfig& config_; PCS& pcs_; + Challenger& challenger_; + std::optional pow_witness_; }; } // namespace tachyon::benchmark diff --git a/benchmark/fri/plonky3/src/lib.rs b/benchmark/fri/plonky3/src/lib.rs index e78198f16..4baf6b516 100644 --- a/benchmark/fri/plonky3/src/lib.rs +++ b/benchmark/fri/plonky3/src/lib.rs @@ -6,8 +6,8 @@ use p3_challenger::{CanObserve, DuplexChallenger, FieldChallenger}; use p3_commit::{ExtensionMmcs, Pcs, PolynomialSpace}; use p3_dft::Radix2DitParallel; use p3_field::extension::BinomialExtensionField; -use p3_field::{AbstractField, ExtensionField, Field}; -use p3_fri::{FriConfig, TwoAdicFriPcs}; +use p3_field::{AbstractExtensionField, AbstractField, ExtensionField, Field}; +use p3_fri::{FriConfig, TwoAdicFriPcs, TwoAdicFriPcsProof}; use p3_matrix::dense::RowMajorMatrix; use p3_merkle_tree::FieldMerkleTreeMmcs; use p3_poseidon2::{Poseidon2, Poseidon2ExternalMatrixHL}; @@ -83,60 +83,100 @@ fn get_pcs(log_blowup: usize, log_n: usize) -> (MyPcs, Challenger) { (pcs, Challenger::new(perm.clone())) } -fn do_test_fri( - (pcs, _challenger): &(P, Challenger), - degrees: Vec, - data: Vec>, +fn do_test_fri( + (pcs, challenger): &(P, Challenger), + degrees_by_round: Vec>, + data: *const Val, + batch_size: usize, duration: *mut u64, ) -> *mut CppBabyBear where P: Pcs, P::Domain: PolynomialSpace, - Val: Field, Challenge: ExtensionField, + P: Pcs< + Challenge, + Challenger, + Proof = TwoAdicFriPcsProof, + >, Challenger: Clone + CanObserve + FieldChallenger,

>::Commitment: Debug, { - let domains: Vec<_> = degrees + let num_rounds = degrees_by_round.len(); + let mut p_challenger = challenger.clone(); + + let domains_and_polys_by_round: Vec> = degrees_by_round .iter() - .map(|°ree| pcs.natural_domain_for_degree(degree)) + .enumerate() + .map(|(r, degrees)| { + degrees + .iter() + .map(|°ree| { + let size = degree * batch_size; + let values: Vec = unsafe { + std::slice::from_raw_parts(data.add(r) as *mut Val, size).to_vec() + }; + ( + pcs.natural_domain_for_degree(degree), + RowMajorMatrix::::new(values, batch_size), + ) + }) + .collect() + }) .collect(); - let domains_and_polys: Vec<(P::Domain, RowMajorMatrix)> = - domains.into_iter().zip(data.into_iter()).collect(); let start = Instant::now(); - let (commit, _data) = pcs.commit(domains_and_polys); + let (commits_by_round, data_by_round): (Vec<_>, Vec<_>) = domains_and_polys_by_round + .iter() + .map(|domains_and_polys| pcs.commit(domains_and_polys.clone())) + .unzip(); + assert_eq!(commits_by_round.len(), num_rounds); + assert_eq!(data_by_round.len(), num_rounds); + p_challenger.observe_slice(&commits_by_round); + + let zeta: Challenge = p_challenger.sample_ext_element(); + + let points_by_round: Vec<_> = degrees_by_round + .iter() + .map(|log_degrees| vec![vec![zeta]; log_degrees.len()]) + .collect(); + let data_and_points = data_by_round.iter().zip(points_by_round).collect(); + let (_opening_by_round, proof) = pcs.open(data_and_points, &mut p_challenger); unsafe { duration.write(start.elapsed().as_micros() as u64); } - Box::into_raw(Box::new(commit)) as *mut CppBabyBear + + let mut ret_values: [Val; 5] = [Val::zero(); 5]; + ret_values[0] = proof.fri_proof.pow_witness; + ret_values[1..].copy_from_slice(proof.fri_proof.final_poly.as_base_slice()); + Box::into_raw(Box::new(ret_values)) as *mut CppBabyBear } #[no_mangle] pub extern "C" fn run_fri_plonky3_baby_bear( data: *const BabyBear, - raw_degrees: *const usize, - num_of_degrees: usize, + input_num: usize, + round_num: usize, + max_degree: usize, batch_size: usize, log_blowup: u32, duration: *mut u64, ) -> *mut CppBabyBear { - let degrees = - unsafe { std::slice::from_raw_parts(raw_degrees as *mut usize, num_of_degrees).to_vec() }; - - let (pcs, challenger) = get_pcs( - log_blowup as usize, - log2_strict_usize(*degrees.last().unwrap()), - ); - - let polys: Vec> = degrees - .iter() - .map(|°ree| { - let size = degree * batch_size; - let values: Vec = - unsafe { std::slice::from_raw_parts(data as *mut BabyBear, size).to_vec() }; - RowMajorMatrix::::new(values, batch_size) + let degrees_by_round: Vec> = (0..round_num) + .map(|r| { + (0..input_num) + .map(|i| max_degree >> (r + i)) + .collect::>() }) .collect(); - do_test_fri(&(pcs, challenger), degrees, polys, duration) + + let (pcs, challenger) = get_pcs(log_blowup as usize, log2_strict_usize(max_degree)); + + do_test_fri( + &(pcs, challenger), + degrees_by_round, + data, + batch_size, + duration, + ) } diff --git a/tachyon/c/crypto/commitments/fri/two_adic_fri_impl.h b/tachyon/c/crypto/commitments/fri/two_adic_fri_impl.h index 4f0941a7e..2e8840287 100644 --- a/tachyon/c/crypto/commitments/fri/two_adic_fri_impl.h +++ b/tachyon/c/crypto/commitments/fri/two_adic_fri_impl.h @@ -33,9 +33,8 @@ class TwoAdicFRIImpl template absl::Span CosetLDEBatch(Eigen::MatrixBase& matrix, F shift) { Domain coset = this->GetNaturalDomainForDegree(matrix.rows()); - tachyon::math::RowMajorMatrix mat = - coset.domain()->CosetLDEBatch(matrix, this->fri_.log_blowup, shift); - ReverseMatrixIndexBits(mat); + tachyon::math::RowMajorMatrix mat = coset.domain()->CosetLDEBatch( + matrix, this->fri_.log_blowup, shift, /*reverse_at_last=*/false); absl::Span ret(mat.data(), mat.size()); this->ldes_.push_back(std::move(mat)); return ret; diff --git a/tachyon/crypto/challenger/challenger.h b/tachyon/crypto/challenger/challenger.h index 797585e10..4d36f0a6b 100644 --- a/tachyon/crypto/challenger/challenger.h +++ b/tachyon/crypto/challenger/challenger.h @@ -84,11 +84,13 @@ class Challenger { return rand_size & ((uint32_t{1} << bits) - 1); } - Field Grind(uint32_t bits) { - return Grind(bits, base::Range::Until(Field::Config::kModulus)); + Field Grind(uint32_t bits, std::optional pow_witness = std::nullopt) { + return Grind(bits, base::Range::Until(Field::Config::kModulus), + pow_witness); } - Field Grind(uint32_t bits, base::Range range) { + Field Grind(uint32_t bits, base::Range range, + std::optional pow_witness = std::nullopt) { std::vector ret = base::ParallelizeMap( range.GetSize(), [this, bits, range](uint32_t len, uint32_t chunk_offset, @@ -111,11 +113,15 @@ class Challenger { return v != std::numeric_limits::max(); }); CHECK(it != ret.end()); - CheckWitness(bits, Field(*it)); + if (pow_witness) { + CHECK(CheckWitness(bits, *pow_witness)); + return *pow_witness; + } + CHECK(CheckWitness(bits, Field(*it))); return Field(*it); } - bool CheckWitness(uint32_t bits, const Field& witness) { + [[nodiscard]] bool CheckWitness(uint32_t bits, const Field& witness) { Observe(witness); return SampleBits(bits) == 0; } diff --git a/tachyon/crypto/commitments/fri/prove.h b/tachyon/crypto/commitments/fri/prove.h index 8b58e4c67..83adb4f98 100644 --- a/tachyon/crypto/commitments/fri/prove.h +++ b/tachyon/crypto/commitments/fri/prove.h @@ -41,21 +41,22 @@ CommitPhaseResult CommitPhase(const FRIConfig& config, data.reserve(total_folds); while (folded.size() > config.Blowup()) { - math::RowMajorMatrix leaves((folded.size() + 1) / 2, 2); + std::vector> leaves; + leaves.emplace_back((folded.size() + 1) / 2, 2); base::Parallelize( folded, [&leaves](absl::Span chunk, size_t chunk_offset, size_t chunk_size) { size_t chunk_start = chunk_offset * chunk_size; for (size_t i = chunk_start; i < chunk_start + chunk.size(); ++i) { - leaves(i / 2, i % 2) = std::move(chunk[i - chunk_start]); + leaves[0](i / 2, i % 2) = std::move(chunk[i - chunk_start]); } }, kThreshold); Commitment commit; ProverData prover_data; - CHECK(config.mmcs.Commit({std::move(leaves)}, &commit, &prover_data)); + CHECK(config.mmcs.Commit(std::move(leaves), &commit, &prover_data)); commits.push_back(std::move(commit)); data.push_back(std::move(prover_data)); @@ -122,7 +123,8 @@ template ::BaseField> FRIProof Prove(const FRIConfig& config, std::vector>&& inputs, - Challenger& challenger, OpenInputCallback open_input) { + Challenger& challenger, OpenInputCallback open_input, + std::optional pow_witness_for_testing = std::nullopt) { using QueryProof = QueryProof; #if DCHECK_IS_ON() @@ -137,7 +139,8 @@ FRIProof Prove(const FRIConfig& config, uint32_t log_max_num_rows = base::bits::CheckedLog2(inputs[0].size()); CommitPhaseResult commit_phase_result = CommitPhase(config, std::move(inputs), challenger); - F pow_witness = challenger.Grind(config.proof_of_work_bits); + F pow_witness = + challenger.Grind(config.proof_of_work_bits, pow_witness_for_testing); VLOG(2) << "FRI(pow): " << pow_witness.ToHexString(true); std::vector query_proofs = base::CreateVector( diff --git a/tachyon/crypto/commitments/fri/two_adic_fri.h b/tachyon/crypto/commitments/fri/two_adic_fri.h index 04321a70b..c9d457839 100644 --- a/tachyon/crypto/commitments/fri/two_adic_fri.h +++ b/tachyon/crypto/commitments/fri/two_adic_fri.h @@ -38,12 +38,14 @@ class TwoAdicFRIImpl; namespace crypto { -template +template class TwoAdicFRI { public: + using ExtF = _ExtF; using InputMMCS = _InputMMCS; using ChallengeMMCS = _ChallengeMMCS; + using Challenger = _Challenger; using F = typename math::ExtensionFieldTraits::BaseField; using Domain = TwoAdicMultiplicativeCoset; @@ -74,14 +76,11 @@ class TwoAdicFRI { TRACE_EVENT("ProofGeneration", "TwoAdicFRI::Commit"); std::vector> ldes = base::Map(cosets, [this, &matrices](size_t i, const Domain& coset) { - math::RowMajorMatrix& mat = matrices[i]; - CHECK_EQ(coset.domain()->size(), static_cast(mat.rows())); - math::RowMajorMatrix ret = coset.domain()->CosetLDEBatch( - mat, fri_.log_blowup, + return coset.domain()->CosetLDEBatch( + matrices[i], fri_.log_blowup, F::FromMontgomery(F::Config::kSubgroupGenerator) * - coset.domain()->offset_inv()); - ReverseMatrixIndexBits(ret); - return ret; + coset.domain()->offset_inv(), + /*reverse_at_last=*/false); }); return mmcs_.Commit(std::move(ldes), commitment, prover_data); } @@ -89,7 +88,8 @@ class TwoAdicFRI { [[nodiscard]] bool CreateOpeningProof( const std::vector& prover_data_by_round, const OpeningPoints& points_by_round, Challenger& challenger, - OpenedValues* opened_values_out, FRIProof* proof) const { + OpenedValues* opened_values_out, FRIProof* proof, + std::optional pow_witness_for_testing = std::nullopt) const { TRACE_EVENT("ProofGeneration", "TwoAdicFRI::CreateOpeningProof"); ExtF alpha = challenger.template SampleExtElement(); VLOG(2) << "FRI(alpha): " << alpha.ToHexString(true); @@ -136,40 +136,40 @@ class TwoAdicFRI { std::vector& reduced_opening_for_log_num_rows = reduced_openings[log_num_rows]; CHECK_EQ(reduced_opening_for_log_num_rows.size(), num_rows); + + math::RowMajorMatrix block = + mat.topRows(num_rows >> fri_.log_blowup); + ReverseMatrixIndexBits(block); + std::vector reduced_rows = DotExtPowers(mat, alpha); + // TODO(ashjeong): Determine if using a matrix is a better fit. - opened_values_for_round[matrix_idx] = base::CreateVector( - points[matrix_idx].size(), - [this, matrix_idx, num_rows, num_cols, log_num_rows, &points, &mat, - &alpha, &num_reduced, &inv_denoms, - &reduced_opening_for_log_num_rows](size_t point_idx) { - const ExtF& point = points[matrix_idx][point_idx]; - math::RowMajorMatrix block = - mat.topRows(num_rows >> fri_.log_blowup); - ReverseMatrixIndexBits(block); - std::vector ys = InterpolateCoset( - block, F::FromMontgomery(F::Config::kSubgroupGenerator), - point); - const ExtF alpha_pow_offset = - alpha.Pow(num_reduced[log_num_rows]); - ExtF alpha_pow = ExtF::One(); - ExtF reduced_ys = ExtF::Zero(); - for (size_t c = 0; c < num_cols - 1; ++c) { - reduced_ys += alpha_pow * ys[c]; - alpha_pow *= alpha; - } - reduced_ys += alpha_pow * ys[num_cols - 1]; - std::vector reduced_rows = DotExtPowers(mat, alpha); - const std::vector& inv_denom = inv_denoms[point]; - OMP_PARALLEL_FOR(size_t i = 0; - i < reduced_opening_for_log_num_rows.size(); - ++i) { - reduced_opening_for_log_num_rows[i] += - alpha_pow_offset * (reduced_rows[i] - reduced_ys) * - inv_denom[i]; - } - num_reduced[log_num_rows] += num_cols; - return ys; - }); + opened_values_for_round[matrix_idx].reserve(points[matrix_idx].size()); + for (size_t point_idx = 0; point_idx < points[matrix_idx].size(); + ++point_idx) { + const ExtF& point = points[matrix_idx][point_idx]; + std::vector ys = InterpolateCoset( + block, F::FromMontgomery(F::Config::kSubgroupGenerator), point); + + ExtF alpha_pow = ExtF::One(); + ExtF reduced_ys = ExtF::Zero(); + for (size_t c = 0; c < num_cols - 1; ++c) { + reduced_ys += alpha_pow * ys[c]; + alpha_pow *= alpha; + } + reduced_ys += alpha_pow * ys[num_cols - 1]; + + const ExtF alpha_pow_offset = alpha.Pow(num_reduced[log_num_rows]); + num_reduced[log_num_rows] += num_cols; + + const std::vector& inv_denom = inv_denoms[point]; + OMP_PARALLEL_FOR(size_t i = 0; + i < reduced_opening_for_log_num_rows.size(); ++i) { + reduced_opening_for_log_num_rows[i] += + alpha_pow_offset * (reduced_rows[i] - reduced_ys) * + inv_denom[i]; + } + opened_values_for_round[matrix_idx].emplace_back(std::move(ys)); + } } opened_values[round] = std::move(opened_values_for_round); } @@ -202,7 +202,8 @@ class TwoAdicFRI { return BatchOpening{std::move(openings), std::move(proof)}; }); - }); + }, + pow_witness_for_testing); return true; } diff --git a/tachyon/crypto/commitments/merkle_tree/field_merkle_tree/field_merkle_tree.h b/tachyon/crypto/commitments/merkle_tree/field_merkle_tree/field_merkle_tree.h index 27288825b..9ca136598 100644 --- a/tachyon/crypto/commitments/merkle_tree/field_merkle_tree/field_merkle_tree.h +++ b/tachyon/crypto/commitments/merkle_tree/field_merkle_tree/field_merkle_tree.h @@ -86,8 +86,9 @@ class FieldMerkleTree { absl::MakeSpan(sorted_leaves.data() + first_layer_size, sorted_leaves.size() - first_layer_size); - std::vector> digest_layers{ - CreateFirstDigestLayer(hasher, packed_hasher, tallest_matrices)}; + std::vector> digest_layers; + digest_layers.emplace_back( + CreateFirstDigestLayer(hasher, packed_hasher, tallest_matrices)); while (true) { const std::vector& prev_layer = digest_layers.back(); diff --git a/tachyon/crypto/commitments/merkle_tree/field_merkle_tree/field_merkle_tree_mmcs.h b/tachyon/crypto/commitments/merkle_tree/field_merkle_tree/field_merkle_tree_mmcs.h index 92f2e409a..5c62a0bf5 100644 --- a/tachyon/crypto/commitments/merkle_tree/field_merkle_tree/field_merkle_tree_mmcs.h +++ b/tachyon/crypto/commitments/merkle_tree/field_merkle_tree/field_merkle_tree_mmcs.h @@ -126,7 +126,7 @@ class FieldMerkleTreeMMCS final }); *proof = - base::CreateVector(log_max_row_size, [prover_data, index](size_t i) { + base::CreateVector(log_max_row_size, [&prover_data, index](size_t i) { // NOTE(chokobole): Let v be |index >> i|. If v is even, v ^ 1 is v // + 1. Otherwise, v ^ 1 is v - 1. return prover_data.digest_layers()[i][(index >> i) ^ 1]; diff --git a/tachyon/math/polynomials/univariate/radix2_evaluation_domain.h b/tachyon/math/polynomials/univariate/radix2_evaluation_domain.h index 3605da725..d5e2d3692 100644 --- a/tachyon/math/polynomials/univariate/radix2_evaluation_domain.h +++ b/tachyon/math/polynomials/univariate/radix2_evaluation_domain.h @@ -120,7 +120,8 @@ class Radix2EvaluationDomain template CONSTEXPR_IF_NOT_OPENMP RowMajorMatrix CosetLDEBatch( - Eigen::MatrixBase& mat, size_t added_bits, F shift) const { + Eigen::MatrixBase& mat, size_t added_bits, F shift, + bool reverse_at_last = true) const { TRACE_EVENT("EvaluationDomain", "Radix2EvaluationDomain::CosetLDEBatch"); if constexpr (F::Config::kModulusBits > 32) { NOTREACHED(); @@ -177,7 +178,9 @@ class Radix2EvaluationDomain ReverseMatrixIndexBits(ret); domain->RunParallelRowChunksReversed(ret, domain->cache_->rev_roots_vec, domain->cache_->packed_roots_vec[1]); - ReverseMatrixIndexBits(ret); + if (reverse_at_last) { + ReverseMatrixIndexBits(ret); + } return ret; }