use p3_commit::{Encoder, Mmcs};
use p3_field::Field;
use p3_matrix::dense::{DenseMatrix, RowMajorMatrix, RowMajorMatrixView, RowMajorMatrixViewMut};
use p3_maybe_rayon::prelude::*;
use p3_multilinear_util::poly::Poly;
use tracing::info_span;
use crate::strategy::VariableOrder;
const COPY_CHUNK: usize = 1 << 16;
pub fn write_stacked_message<F: Field>(
order: VariableOrder,
poly: &Poly<F>,
folding: usize,
message: &mut [F],
) {
let values = poly.as_slice();
assert_eq!(
message.len(),
values.len(),
"message must cover the whole stacked hypercube"
);
let width = 1 << folding;
match order {
VariableOrder::Prefix => info_span!("transpose").in_scope(|| {
let view = RowMajorMatrixView::new(values, values.len() / width);
let mut prefix = RowMajorMatrixViewMut::new(message, width);
view.transpose_into(&mut prefix);
}),
VariableOrder::Suffix => message
.par_chunks_mut(COPY_CHUNK)
.zip(values.par_chunks(COPY_CHUNK))
.for_each(|(destination, source)| destination.copy_from_slice(source)),
}
}
pub fn commit_base<F, E, MT>(
encoder: &E,
mmcs: &MT,
num_variables: usize,
folding: usize,
starting_log_inv_rate: usize,
write_message: impl FnOnce(&mut [F]),
) -> (MT::Commitment, MT::ProverData<DenseMatrix<F>>)
where
F: Field,
E: Encoder<F>,
MT: Mmcs<F>,
{
let width = 1 << folding;
let message_height = 1 << (num_variables - folding);
let codeword_height = message_height << starting_log_inv_rate;
let mut values = F::zero_vec(codeword_height * width);
write_message(&mut values[..message_height * width]);
let message = RowMajorMatrix::new(values, width);
let encoded = info_span!("encode", height = codeword_height, width)
.in_scope(|| encoder.encode_batch_padded(message, starting_log_inv_rate));
info_span!("commit_matrix").in_scope(|| mmcs.commit_matrix(encoded))
}
#[cfg(test)]
mod tests {
use alloc::vec::Vec;
use p3_baby_bear::{BabyBear, Poseidon2BabyBear};
use p3_commit::{Encoder, Mmcs};
use p3_field::{Field, PrimeCharacteristicRing};
use p3_matrix::dense::RowMajorMatrix;
use p3_merkle_tree::MerkleTreeMmcs;
use p3_multilinear_util::poly::Poly;
use p3_symmetric::{PaddingFreeSponge, TruncatedPermutation};
use rand::SeedableRng;
use rand::rngs::SmallRng;
use super::{commit_base, write_stacked_message};
use crate::strategy::VariableOrder;
type F = BabyBear;
type Perm = Poseidon2BabyBear<16>;
type MyHash = PaddingFreeSponge<Perm, 16, 8, 8>;
type MyCompress = TruncatedPermutation<Perm, 2, 8, 16>;
type PackedF = <F as Field>::Packing;
type MyMmcs = MerkleTreeMmcs<PackedF, PackedF, MyHash, MyCompress, 2, 8>;
#[derive(Clone, Debug)]
struct DoublingEncoder;
impl Encoder<F> for DoublingEncoder {
fn encode_batch(
&self,
mut message: RowMajorMatrix<F>,
log_inv_rate: usize,
) -> RowMajorMatrix<F> {
message.values.iter_mut().for_each(|v| *v = v.double());
message
.values
.resize(message.values.len() << log_inv_rate, F::ZERO);
message
}
}
fn mmcs() -> MyMmcs {
let mut rng = SmallRng::seed_from_u64(1);
let perm = Perm::new_from_rng_128(&mut rng);
MyMmcs::new(MyHash::new(perm.clone()), MyCompress::new(perm), 0)
}
fn check_commits_encoder_output(order: VariableOrder, expected_message: RowMajorMatrix<F>) {
const NUM_VARIABLES: usize = 5;
const FOLDING: usize = 2;
const LOG_INV_RATE: usize = 1;
let poly = Poly::new(
(0..1 << NUM_VARIABLES)
.map(F::from_usize)
.collect::<Vec<_>>(),
);
let mmcs = mmcs();
let (root, _data) = commit_base(
&DoublingEncoder,
&mmcs,
NUM_VARIABLES,
FOLDING,
LOG_INV_RATE,
|message| write_stacked_message(order, &poly, FOLDING, message),
);
let expected_codeword = DoublingEncoder.encode_batch(expected_message, LOG_INV_RATE);
let (expected_root, _) = mmcs.commit_matrix(expected_codeword);
assert_eq!(root, expected_root);
}
#[test]
fn prefix_commits_the_transposed_message() {
let expected =
RowMajorMatrix::new((0..32).map(F::from_usize).collect::<Vec<_>>(), 1 << 3).transpose();
check_commits_encoder_output(VariableOrder::Prefix, expected);
}
#[test]
fn suffix_commits_the_contiguous_message() {
let expected = RowMajorMatrix::new((0..32).map(F::from_usize).collect::<Vec<_>>(), 1 << 2);
check_commits_encoder_output(VariableOrder::Suffix, expected);
}
}