Skip to content

Commit

Permalink
Merge Commit multiple columns using a single Merkle Tree (lambdaclass#47
Browse files Browse the repository at this point in the history
)
  • Loading branch information
schouhy authored and feltroidprime committed Jun 15, 2023
1 parent 2a5427f commit b9654c6
Show file tree
Hide file tree
Showing 9 changed files with 206 additions and 173 deletions.
9 changes: 6 additions & 3 deletions Cargo.toml
Expand Up @@ -8,15 +8,18 @@ rust-version = "1.66"

[dependencies]
rand = "0.8.5"
lambdaworks-math = { git = "https://github.com/lambdaclass/lambdaworks", rev = "ca0c68a" }
lambdaworks-crypto = { git = "https://github.com/lambdaclass/lambdaworks", rev = "ca0c68a" }
lambdaworks-fft = { git = "https://github.com/lambdaclass/lambdaworks", rev = "ca0c68a" }
lambdaworks-math = { git = "https://github.com/lambdaclass/lambdaworks", rev = "133ffb3" }
lambdaworks-crypto = { git = "https://github.com/lambdaclass/lambdaworks", rev = "133ffb3" }
lambdaworks-fft = { git = "https://github.com/lambdaclass/lambdaworks", rev = "133ffb3" }
thiserror = "1.0.38"
log = "0.4.17"
bincode = { version = "2.0.0-rc.2", tag = "v2.0.0-rc.2", git = "https://github.com/bincode-org/bincode.git" }
cairo-vm = { git = "https://github.com/lambdaclass/cairo-rs/" }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
sha3 = "0.10.6"
hex="0.4.3"

[dev-dependencies]
hex = "0.4.3"
criterion = "0.4"
Expand Down
1 change: 0 additions & 1 deletion README.md
Expand Up @@ -14,6 +14,5 @@ To be added:
- Grinding
- Skipping FRI layers
- Optimizing verifier operations
- Batch proofs in Merkle trees
- Range check and Pedersen built-ins
- Different layouts
9 changes: 6 additions & 3 deletions src/fri/fri_commitment.rs
Expand Up @@ -6,12 +6,15 @@ use lambdaworks_math::{
traits::ByteConversion,
};

use super::HASHER;
pub use super::{FriMerkleTree, Polynomial};
use lambdaworks_fft::polynomial::FFTPoly;

#[derive(Clone)]
pub struct FriLayer<F: IsField> {
pub struct FriLayer<F>
where
F: IsField,
FieldElement<F>: ByteConversion,
{
pub poly: Polynomial<FieldElement<F>>,
pub evaluation: Vec<FieldElement<F>>,
pub merkle_tree: FriMerkleTree<F>,
Expand All @@ -33,7 +36,7 @@ where
.evaluate_offset_fft(1, Some(domain_size), coset_offset)
.unwrap(); // TODO: return error

let merkle_tree = FriMerkleTree::build(&evaluation, Box::new(HASHER));
let merkle_tree = FriMerkleTree::build(&evaluation);

Self {
poly,
Expand Down
6 changes: 4 additions & 2 deletions src/fri/fri_decommit.rs
Expand Up @@ -3,10 +3,12 @@ use lambdaworks_crypto::merkle_tree::proof::Proof;
use lambdaworks_math::field::element::FieldElement;
use lambdaworks_math::field::traits::IsField;

use super::Commitment;

#[derive(Debug, Clone)]
pub struct FriDecommitment<F: IsField> {
pub layers_auth_paths_sym: Vec<Proof<F>>,
pub layers_auth_paths_sym: Vec<Proof<Commitment>>,
pub layers_evaluations_sym: Vec<FieldElement<F>>,
pub first_layer_evaluation: FieldElement<F>,
pub first_layer_auth_path: Proof<F>,
pub first_layer_auth_path: Proof<Commitment>,
}
11 changes: 6 additions & 5 deletions src/fri/mod.rs
Expand Up @@ -4,9 +4,9 @@ mod fri_functions;
use crate::air::traits::AIR;
use crate::fri::fri_commitment::FriLayer;
use crate::{transcript_to_field, transcript_to_usize};
use lambdaworks_crypto::hash::sha3::Sha3Hasher;

pub use lambdaworks_crypto::fiat_shamir::transcript::Transcript;
use lambdaworks_crypto::merkle_tree::merkle::FieldElementBackend;
pub use lambdaworks_crypto::merkle_tree::merkle::MerkleTree;
use lambdaworks_math::field::traits::{IsFFTField, IsField};
use lambdaworks_math::traits::ByteConversion;
Expand All @@ -18,8 +18,9 @@ pub use lambdaworks_math::{
use self::fri_decommit::FriDecommitment;
use self::fri_functions::fold_polynomial;

pub type FriMerkleTree<F> = MerkleTree<F>;
pub(crate) const HASHER: Sha3Hasher = Sha3Hasher::new();
pub type Commitment = [u8; 32];
pub type FriMerkleBackend<F> = FieldElementBackend<F>;
pub type FriMerkleTree<F> = MerkleTree<FieldElementBackend<F>>;

pub fn fri_commit_phase<F: IsField + IsFFTField, T: Transcript>(
number_layers: usize,
Expand All @@ -38,7 +39,7 @@ where
fri_layer_list.push(current_layer.clone());

// >>>> Send commitment: [p₀]
transcript.append(&current_layer.merkle_tree.root.to_bytes_be());
transcript.append(&current_layer.merkle_tree.root);

let mut coset_offset = coset_offset.clone();

Expand All @@ -51,7 +52,7 @@ where
// Compute layer polynomial and domain
let next_poly = fold_polynomial(&current_layer.poly, &zeta);
current_layer = FriLayer::new(next_poly, &coset_offset, domain_size);
let new_data = &current_layer.merkle_tree.root.to_bytes_be();
let new_data = &current_layer.merkle_tree.root;
fri_layer_list.push(current_layer.clone()); // TODO: remove this clone

// >>>> Send commitment: [pₖ]
Expand Down
53 changes: 51 additions & 2 deletions src/lib.rs
Expand Up @@ -6,17 +6,22 @@ pub mod proof;
pub mod prover;
pub mod verifier;

use std::marker::PhantomData;

use air::traits::AIR;
use lambdaworks_crypto::fiat_shamir::transcript::Transcript;
use lambdaworks_crypto::{
fiat_shamir::transcript::Transcript, merkle_tree::traits::IsMerkleTreeBackend,
};
use lambdaworks_fft::roots_of_unity::get_powers_of_primitive_root_coset;
use lambdaworks_math::{
field::{
element::FieldElement,
fields::fft_friendly::stark_252_prime_field::Stark252PrimeField,
traits::{IsFFTField, IsPrimeField},
traits::{IsFFTField, IsField, IsPrimeField},
},
traits::ByteConversion,
};
use sha3::{Digest, Sha3_256};

pub struct ProofConfig {
pub count_queries: usize,
Expand Down Expand Up @@ -145,6 +150,50 @@ impl<F: IsFFTField> Domain<F> {
}
}

/// A Merkle tree backend for vectors of field elements.
/// This is used by the Stark prover to commit to
/// multiple trace columns using a single Merkle tree.
#[derive(Clone)]
pub struct BatchStarkProverBackend<F> {
phantom: PhantomData<F>,
}

impl<F> Default for BatchStarkProverBackend<F> {
fn default() -> Self {
Self {
phantom: PhantomData,
}
}
}

impl<F> IsMerkleTreeBackend for BatchStarkProverBackend<F>
where
F: IsField,
FieldElement<F>: ByteConversion,
{
type Node = [u8; 32];
type Data = Vec<FieldElement<F>>;

fn hash_data(&self, input: &Vec<FieldElement<F>>) -> [u8; 32] {
let mut hasher = Sha3_256::new();
for element in input.iter() {
hasher.update(element.to_bytes_be());
}
let mut result_hash = [0_u8; 32];
result_hash.copy_from_slice(&hasher.finalize());
result_hash
}

fn hash_new_parent(&self, left: &[u8; 32], right: &[u8; 32]) -> [u8; 32] {
let mut hasher = Sha3_256::new();
hasher.update(left);
hasher.update(right);
let mut result_hash = [0_u8; 32];
result_hash.copy_from_slice(&hasher.finalize());
result_hash
}
}

#[cfg(test)]
mod tests {
use lambdaworks_math::{
Expand Down
71 changes: 24 additions & 47 deletions src/proof.rs
@@ -1,35 +1,36 @@
use crate::{air::frame::Frame, fri::fri_decommit::FriDecommitment};
use crate::{
air::frame::Frame,
fri::{fri_decommit::FriDecommitment, Commitment},
};
use hex;
use lambdaworks_crypto::merkle_tree::proof::Proof;
use lambdaworks_math::field::{element::FieldElement, traits::IsFFTField};
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone)]
pub struct DeepPolynomialOpenings<F: IsFFTField> {
pub lde_composition_poly_even_proof: Proof<F>,
pub lde_composition_poly_proof: Proof<Commitment>,
pub lde_composition_poly_even_evaluation: FieldElement<F>,
pub lde_composition_poly_odd_proof: Proof<F>,
pub lde_composition_poly_odd_evaluation: FieldElement<F>,
pub lde_trace_merkle_proofs: Vec<Proof<F>>,
pub lde_trace_merkle_proofs: Vec<Proof<Commitment>>,
pub lde_trace_evaluations: Vec<FieldElement<F>>,
}

#[derive(Debug, Clone)]
pub struct StarkProof<F: IsFFTField> {
// Commitments of the trace columns
// [tⱼ]
pub lde_trace_merkle_roots: Vec<FieldElement<F>>,
pub lde_trace_merkle_roots: Vec<Commitment>,
// tⱼ(zgᵏ)
pub trace_ood_frame_evaluations: Frame<F>,
// [H₁]
pub composition_poly_even_root: FieldElement<F>,
// [H₁] and [H₂]
pub composition_poly_root: Commitment,
// H₁(z²)
pub composition_poly_even_ood_evaluation: FieldElement<F>,
// [H₂]
pub composition_poly_odd_root: FieldElement<F>,
// H₂(z²)
pub composition_poly_odd_ood_evaluation: FieldElement<F>,
// [pₖ]
pub fri_layers_merkle_roots: Vec<FieldElement<F>>,
pub fri_layers_merkle_roots: Vec<Commitment>,
// pₙ
pub fri_last_value: FieldElement<F>,
// Open(p₀(D₀), 𝜐ₛ), Opwn(pₖ(Dₖ), −𝜐ₛ^(2ᵏ))
Expand All @@ -43,9 +44,8 @@ pub struct StarkProofString {
pub lde_trace_merkle_roots: Vec<String>,
pub trace_ood_frame_evaluations: Vec<String>,
pub trace_ood_frame_evaluations_row_width: usize,
pub composition_poly_even_root: String,
pub composition_poly_root: String,
pub composition_poly_even_ood_evaluation: String,
pub composition_poly_odd_root: String,
pub composition_poly_odd_ood_evaluation: String,
pub fri_layers_merkle_roots: Vec<String>,
pub fri_last_value: String,
Expand All @@ -62,9 +62,8 @@ pub struct FriDecommitmentString {

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeepPolynomialOpeningsString {
pub lde_composition_poly_even_proof: ProofString,
pub lde_composition_poly_proof: ProofString,
pub lde_composition_poly_even_evaluation: String,
pub lde_composition_poly_odd_proof: ProofString,
pub lde_composition_poly_odd_evaluation: String,
pub lde_trace_merkle_proofs: Vec<ProofString>,
pub lde_trace_evaluations: Vec<String>,
Expand All @@ -79,7 +78,7 @@ pub fn convert_stark_proof_to_string<F: IsFFTField>(proof: StarkProof<F>) -> Sta
let lde_trace_merkle_roots: Vec<String> = proof
.lde_trace_merkle_roots
.iter()
.map(|fe| fe.representative().to_string())
.map(|fe| hex::encode(fe))
.collect();
let trace_ood_frame_evaluations: Vec<String> = proof
.trace_ood_frame_evaluations
Expand All @@ -88,16 +87,11 @@ pub fn convert_stark_proof_to_string<F: IsFFTField>(proof: StarkProof<F>) -> Sta
.map(|fe| fe.representative().to_string())
.collect();
let trace_ood_frame_evaluations_row_width: usize = proof.trace_ood_frame_evaluations.row_width;
let composition_poly_even_root: String = proof
.composition_poly_even_root
.representative()
.to_string();
let composition_poly_root: String = hex::encode(proof.composition_poly_root);
let composition_poly_even_ood_evaluation: String = proof
.composition_poly_even_ood_evaluation
.representative()
.to_string();
let composition_poly_odd_root: String =
proof.composition_poly_odd_root.representative().to_string();

let composition_poly_odd_ood_evaluation = proof
.composition_poly_odd_ood_evaluation
Expand All @@ -107,7 +101,7 @@ pub fn convert_stark_proof_to_string<F: IsFFTField>(proof: StarkProof<F>) -> Sta
let fri_layers_merkle_roots = proof
.fri_layers_merkle_roots
.iter()
.map(|fe| fe.representative().to_string())
.map(|fe| hex::encode(fe))
.collect();

let fri_last_value = proof.fri_last_value.representative().to_string();
Expand All @@ -120,11 +114,7 @@ pub fn convert_stark_proof_to_string<F: IsFFTField>(proof: StarkProof<F>) -> Sta
.layers_auth_paths_sym
.iter()
.map(|proof| ProofString {
merkle_path: proof
.merkle_path
.iter()
.map(|fe| fe.representative().to_string())
.collect(),
merkle_path: proof.merkle_path.iter().map(|fe| hex::encode(fe)).collect(),
})
.collect(),
layers_evaluations_sym: decommitment
Expand All @@ -141,36 +131,28 @@ pub fn convert_stark_proof_to_string<F: IsFFTField>(proof: StarkProof<F>) -> Sta
.first_layer_auth_path
.merkle_path
.iter()
.map(|fe| fe.representative().to_string())
.map(|fe| hex::encode(fe))
.collect(),
},
})
.collect();

let deep_poly_openings = DeepPolynomialOpeningsString {
lde_composition_poly_even_proof: ProofString {
lde_composition_poly_proof: ProofString {
merkle_path: proof
.deep_poly_openings
.lde_composition_poly_even_proof
.lde_composition_poly_proof
.merkle_path
.iter()
.map(|fe| fe.representative().to_string())
.map(|fe| hex::encode(fe))
.collect(),
},
lde_composition_poly_even_evaluation: proof
.deep_poly_openings
.lde_composition_poly_even_evaluation
.representative()
.to_string(),
lde_composition_poly_odd_proof: ProofString {
merkle_path: proof
.deep_poly_openings
.lde_composition_poly_odd_proof
.merkle_path
.iter()
.map(|fe| fe.representative().to_string())
.collect(),
},

lde_composition_poly_odd_evaluation: proof
.deep_poly_openings
.lde_composition_poly_odd_evaluation
Expand All @@ -181,11 +163,7 @@ pub fn convert_stark_proof_to_string<F: IsFFTField>(proof: StarkProof<F>) -> Sta
.lde_trace_merkle_proofs
.iter()
.map(|proof| ProofString {
merkle_path: proof
.merkle_path
.iter()
.map(|fe| fe.representative().to_string())
.collect(),
merkle_path: proof.merkle_path.iter().map(|fe| hex::encode(fe)).collect(),
})
.collect(),
lde_trace_evaluations: proof
Expand All @@ -199,9 +177,8 @@ pub fn convert_stark_proof_to_string<F: IsFFTField>(proof: StarkProof<F>) -> Sta
lde_trace_merkle_roots: lde_trace_merkle_roots,
trace_ood_frame_evaluations: trace_ood_frame_evaluations,
trace_ood_frame_evaluations_row_width: trace_ood_frame_evaluations_row_width,
composition_poly_even_root: composition_poly_even_root,
composition_poly_root: composition_poly_root,
composition_poly_even_ood_evaluation: composition_poly_even_ood_evaluation,
composition_poly_odd_root: composition_poly_odd_root,
composition_poly_odd_ood_evaluation: composition_poly_odd_ood_evaluation,
fri_layers_merkle_roots: fri_layers_merkle_roots,
fri_last_value: fri_last_value,
Expand Down

0 comments on commit b9654c6

Please sign in to comment.