From 4d327318ba5fad334ffd9c5b2c0c0fc280cf2b4a Mon Sep 17 00:00:00 2001 From: Michael Zhu Date: Mon, 4 Dec 2023 15:52:49 -0500 Subject: [PATCH 1/5] Fill in all prove/verify subroutines (except r1cs) --- jolt-core/src/benches/bench.rs | 10 +- jolt-core/src/jolt/trace/rv.rs | 31 +++- jolt-core/src/jolt/vm/instruction_lookups.rs | 26 ++-- jolt-core/src/jolt/vm/mod.rs | 142 +++++++++++-------- jolt-core/src/jolt/vm/pc.rs | 44 +++--- jolt-core/src/jolt/vm/rv32i_vm.rs | 19 ++- 6 files changed, 166 insertions(+), 106 deletions(-) diff --git a/jolt-core/src/benches/bench.rs b/jolt-core/src/benches/bench.rs index 7b56e4806..dd6f2f75e 100644 --- a/jolt-core/src/benches/bench.rs +++ b/jolt-core/src/benches/bench.rs @@ -17,10 +17,10 @@ use crate::jolt::vm::instruction_lookups::InstructionLookupsProof; use crate::jolt::vm::rv32i_vm::{RV32IJoltVM, RV32I}; use crate::jolt::vm::Jolt; use crate::lasso::surge::Surge; -use crate::utils::math::Math; +use crate::utils::{math::Math, random::RandomTape}; use crate::{jolt::instruction::xor::XORInstruction, utils::gen_random_point}; use ark_curve25519::{EdwardsProjective, Fr}; -use ark_std::{test_rng}; +use ark_std::test_rng; use merlin::Transcript; use rand_chacha::rand_core::RngCore; @@ -152,12 +152,12 @@ fn rv32i_lookup_benchmarks() -> Vec<(tracing::Span, Box)> { println!("Running {:?}", ops.len()); let work = Box::new(|| { - let r: Vec = gen_random_point::(ops.len().log_2()); let mut prover_transcript = Transcript::new(b"example"); + let mut random_tape = RandomTape::new(b"test_tape"); let proof: InstructionLookupsProof = - RV32IJoltVM::prove_instruction_lookups(ops, r.clone(), &mut prover_transcript); + RV32IJoltVM::prove_instruction_lookups(ops, &mut prover_transcript, &mut random_tape); let mut verifier_transcript = Transcript::new(b"example"); - assert!(RV32IJoltVM::verify_instruction_lookups(proof, r, &mut verifier_transcript).is_ok()); + assert!(RV32IJoltVM::verify_instruction_lookups(proof, &mut verifier_transcript).is_ok()); }); vec![(tracing::info_span!("RV32IM"), work)] } diff --git a/jolt-core/src/jolt/trace/rv.rs b/jolt-core/src/jolt/trace/rv.rs index 99ee9268f..915c76cef 100644 --- a/jolt-core/src/jolt/trace/rv.rs +++ b/jolt-core/src/jolt/trace/rv.rs @@ -18,8 +18,8 @@ use crate::jolt::instruction::sltu::SLTUInstruction; use crate::jolt::instruction::sra::SRAInstruction; use crate::jolt::instruction::srl::SRLInstruction; use crate::jolt::instruction::xor::XORInstruction; -use crate::jolt::instruction::{add::ADDInstruction, sub::SUBInstruction}; use crate::jolt::instruction::JoltInstruction; +use crate::jolt::instruction::{add::ADDInstruction, sub::SUBInstruction}; use crate::jolt::vm::{pc::ELFRow, rv32i_vm::RV32I}; use common::{constants::REGISTER_COUNT, RV32InstructionFormat, RV32IM}; @@ -1070,19 +1070,32 @@ mod tests { .into_iter() .map(|common| RVTraceRow::from_common(common)) .collect(); + let _: Vec = converted_trace + .iter() + .map(|row| row.to_pc_trace()) + .collect(); let mut num_errors = 0; for row in &converted_trace { if let Err(e) = row.validate() { - // if row.opcode != RV32IM::SLLI { println!("Validation error: {} \n{:#?}\n\n", e, row); - // } num_errors += 1; } } println!("Total errors: {num_errors}"); } + #[test] + fn load_bytecode() { + use common::path::JoltPaths; + use common::serializable::Serializable; + + let bytecode_location = JoltPaths::bytecode_path("fibonacci"); + let instructions = Vec::::deserialize_from_file(&bytecode_location) + .expect("deserialization failed"); + let _: Vec = instructions.iter().map(|x| ELFRow::from(x)).collect(); + } + #[test] fn fib_e2e() { use crate::jolt::vm::rv32i_vm::RV32I; @@ -1115,13 +1128,18 @@ mod tests { .into_iter() .flat_map(|row| row.to_jolt_instructions()) .collect(); - let r: Vec = gen_random_point::(lookup_ops.len().log_2()); let mut prover_transcript = Transcript::new(b"example"); + let mut random_tape = RandomTape::new(b"test_tape"); + let proof: InstructionLookupsProof = - RV32IJoltVM::prove_instruction_lookups(lookup_ops, r.clone(), &mut prover_transcript); + RV32IJoltVM::prove_instruction_lookups( + lookup_ops, + &mut prover_transcript, + &mut random_tape, + ); let mut verifier_transcript = Transcript::new(b"example"); assert!( - RV32IJoltVM::verify_instruction_lookups(proof, r, &mut verifier_transcript).is_ok() + RV32IJoltVM::verify_instruction_lookups(proof, &mut verifier_transcript).is_ok() ); // Prove memory @@ -1141,7 +1159,6 @@ mod tests { let batched_polys = rw_memory.batch(); let commitments = ReadWriteMemory::commit(&batched_polys); - let mut random_tape = RandomTape::new(b"test_tape"); let proof = rw_memory.prove_memory_checking( &rw_memory, &batched_polys, diff --git a/jolt-core/src/jolt/vm/instruction_lookups.rs b/jolt-core/src/jolt/vm/instruction_lookups.rs index 8aa1bafa7..0758e8801 100644 --- a/jolt-core/src/jolt/vm/instruction_lookups.rs +++ b/jolt-core/src/jolt/vm/instruction_lookups.rs @@ -778,10 +778,11 @@ where pub fn prove_lookups( &self, - r: Vec, transcript: &mut Transcript, + random_tape: &mut RandomTape, ) -> InstructionLookupsProof { >::append_protocol_name(transcript, Self::protocol_name()); + let polynomials = self.polynomialize(); let batched_polys = polynomials.batch(); let commitment = InstructionPolynomials::commit(&batched_polys); @@ -790,7 +791,13 @@ where .E_commitment .append_to_transcript(b"comm_poly_row_col_ops_val", transcript); - let eq = EqPolynomial::new(r.to_vec()); + let r_eq = >::challenge_vector( + transcript, + b"Jolt instruction lookups", + self.ops.len().log_2(), + ); + + let eq = EqPolynomial::new(r_eq.to_vec()); let sumcheck_claim = Self::compute_sumcheck_claim(&self.ops, &polynomials.E_polys, &eq); >::append_scalar( @@ -799,7 +806,7 @@ where &sumcheck_claim, ); - let mut eq_poly = DensePolynomial::new(EqPolynomial::new(r).evals()); + let mut eq_poly = DensePolynomial::new(EqPolynomial::new(r_eq).evals()); let num_rounds = self.ops.len().log_2(); // TODO: compartmentalize all primary sumcheck logic @@ -814,8 +821,6 @@ where transcript, ); - let mut random_tape = RandomTape::new(b"proof"); - // Create a single opening proof for the flag_evals and memory_evals let sumcheck_openings = PrimarySumcheckOpenings::prove_openings( &batched_polys, @@ -823,7 +828,7 @@ where &r_primary_sumcheck, (E_evals, flag_evals), transcript, - &mut random_tape, + random_tape, ); let primary_sumcheck = PrimarySumcheck { @@ -838,7 +843,7 @@ where &batched_polys, &commitment, transcript, - &mut random_tape, + random_tape, ); InstructionLookupsProof { @@ -850,7 +855,6 @@ where pub fn verify( proof: InstructionLookupsProof, - r_eq: &[G::ScalarField], transcript: &mut Transcript, ) -> Result<(), ProofVerifyError> { >::append_protocol_name(transcript, Self::protocol_name()); @@ -860,6 +864,12 @@ where .E_commitment .append_to_transcript(b"comm_poly_row_col_ops_val", transcript); + let r_eq = >::challenge_vector( + transcript, + b"Jolt instruction lookups", + proof.primary_sumcheck.num_rounds, + ); + >::append_scalar( transcript, b"claim_eval_scalar_product", diff --git a/jolt-core/src/jolt/vm/mod.rs b/jolt-core/src/jolt/vm/mod.rs index a6497b432..83d174d94 100644 --- a/jolt-core/src/jolt/vm/mod.rs +++ b/jolt-core/src/jolt/vm/mod.rs @@ -4,9 +4,12 @@ use merlin::Transcript; use std::any::TypeId; use strum::{EnumCount, IntoEnumIterator}; -use crate::lasso::{ - memory_checking::MemoryCheckingProver, - surge::Surge, +use crate::{ + lasso::{ + memory_checking::{MemoryCheckingProof, MemoryCheckingProver, MemoryCheckingVerifier}, + surge::{Surge, SurgeProof}, + }, + utils::math::Math, }; use crate::jolt::{ @@ -17,7 +20,10 @@ use crate::poly::structured_poly::BatchablePolynomials; use crate::utils::{errors::ProofVerifyError, random::RandomTape}; use self::instruction_lookups::{InstructionLookups, InstructionLookupsProof}; -use self::read_write_memory::{MemoryCommitment, MemoryOp, ReadWriteMemory}; +use self::pc::{ELFRow, PCInitFinalOpenings, PCPolys, PCReadWriteOpenings, ProgramCommitment}; +use self::read_write_memory::{ + MemoryCommitment, MemoryInitFinalOpenings, MemoryOp, MemoryReadWriteOpenings, ReadWriteMemory, +}; pub trait Jolt, const C: usize, const M: usize> { type InstructionSet: JoltInstruction + Opcode + IntoEnumIterator + EnumCount; @@ -35,77 +41,75 @@ pub trait Jolt, const C: usize, co fn prove_instruction_lookups( ops: Vec, - r: Vec, transcript: &mut Transcript, + random_tape: &mut RandomTape, ) -> InstructionLookupsProof { let instruction_lookups = InstructionLookups::::new(ops); - instruction_lookups.prove_lookups(r, transcript) + instruction_lookups.prove_lookups(transcript, random_tape) } fn verify_instruction_lookups( proof: InstructionLookupsProof, - r: Vec, transcript: &mut Transcript, ) -> Result<(), ProofVerifyError> { InstructionLookups::::verify( - proof, &r, transcript, + proof, transcript, ) } fn prove_program_code( - program_code: &[u64], - access_sequence: &[usize], - code_size: usize, - contiguous_reads_per_access: usize, - r_mem_check: &(F, F), + mut program: Vec, + mut trace: Vec, transcript: &mut Transcript, + random_tape: &mut RandomTape, + ) -> ( + MemoryCheckingProof, PCReadWriteOpenings, PCInitFinalOpenings>, + ProgramCommitment, ) { - // let (gamma, tau) = r_mem_check; - // let hash_func = |a: &F, v: &F, t: &F| -> F { *t * gamma.square() + *v * *gamma + *a - tau }; - - // let m: usize = (access_sequence.len() * contiguous_reads_per_access).next_power_of_two(); - // // TODO(moodlezoup): resize access_sequence? - - // let mut read_addrs: Vec = Vec::with_capacity(m); - // let mut final_cts: Vec = vec![0; code_size]; - // let mut read_cts: Vec = Vec::with_capacity(m); - // let mut read_values: Vec = Vec::with_capacity(m); - - // for (j, code_address) in access_sequence.iter().enumerate() { - // debug_assert!(code_address + contiguous_reads_per_access <= code_size); - // debug_assert!(code_address % contiguous_reads_per_access == 0); - - // for offset in 0..contiguous_reads_per_access { - // let addr = code_address + offset; - // let counter = final_cts[addr]; - // read_addrs.push(addr); - // read_values.push(program_code[addr]); - // read_cts.push(counter); - // final_cts[addr] = counter + 1; - // } - // } - - // let E_poly: DensePolynomial = DensePolynomial::from_u64(&read_values); // v_ops - // let dim: DensePolynomial = DensePolynomial::from_usize(access_sequence); // a_ops - // let read_cts: DensePolynomial = DensePolynomial::from_usize(&read_cts); // t_read - // let final_cts: DensePolynomial = DensePolynomial::from_usize(&final_cts); // t_final - // let init_values: DensePolynomial = DensePolynomial::from_u64(program_code); // v_mem - - // let polys = PCPolys::new(dim, E_poly, init_values, read_cts, final_cts, 0); - // let (gens, commitments) = polys.commit::(); - - todo!("decide how to represent nested proofs, gens, commitments"); - // MemoryCheckingProof::>::prove( - // &polys, - // r_fingerprints, - // &gens, - // &mut transcript, - // &mut random_tape, - // ) + let polys: PCPolys = PCPolys::new_program(program, trace); + let batched_polys = polys.batch(); + let commitments = PCPolys::commit(&batched_polys); + + ( + polys.prove_memory_checking( + &polys, + &batched_polys, + &commitments, + transcript, + random_tape, + ), + commitments, + ) + } + + fn verify_program_code( + proof: MemoryCheckingProof< + G, + PCPolys, + PCReadWriteOpenings, + PCInitFinalOpenings, + >, + commitment: ProgramCommitment, + transcript: &mut Transcript, + ) -> Result<(), ProofVerifyError> { + PCPolys::verify_memory_checking(proof, &commitment, transcript) } - fn prove_memory(memory_trace: Vec, memory_size: usize, transcript: &mut Transcript) { + fn prove_memory( + memory_trace: Vec, + memory_size: usize, + transcript: &mut Transcript, + random_tape: &mut RandomTape, + ) -> ( + MemoryCheckingProof< + G, + ReadWriteMemory, + MemoryReadWriteOpenings, + MemoryInitFinalOpenings, + >, + SurgeProof, + ) { const MAX_TRACE_SIZE: usize = 1 << 22; // TODO: Support longer traces assert!(memory_trace.len() <= MAX_TRACE_SIZE); @@ -116,13 +120,12 @@ pub trait Jolt, const C: usize, co let batched_polys = memory.batch(); let commitments: MemoryCommitment = ReadWriteMemory::commit(&batched_polys); - let mut random_tape = RandomTape::new(b"proof"); - memory.prove_memory_checking( + let memory_checking_proof = memory.prove_memory_checking( &memory, &batched_polys, &commitments, transcript, - &mut random_tape, + random_tape, ); let timestamp_validity_lookups: Vec = read_timestamps @@ -134,6 +137,27 @@ pub trait Jolt, const C: usize, co let timestamp_validity_proof = >::new(timestamp_validity_lookups) .prove(transcript); + + (memory_checking_proof, timestamp_validity_proof) + } + + fn verify_memory( + memory_checking_proof: MemoryCheckingProof< + G, + ReadWriteMemory, + MemoryReadWriteOpenings, + MemoryInitFinalOpenings, + >, + commitment: MemoryCommitment, + transcript: &mut Transcript, + timestamp_validity_proof: SurgeProof, + ) -> Result<(), ProofVerifyError> { + const MAX_TRACE_SIZE: usize = 1 << 22; + ReadWriteMemory::verify_memory_checking(memory_checking_proof, &commitment, transcript)?; + >::verify( + timestamp_validity_proof, + transcript, + ) } fn prove_r1cs() { diff --git a/jolt-core/src/jolt/vm/pc.rs b/jolt-core/src/jolt/vm/pc.rs index 215b28024..99f9710c4 100644 --- a/jolt-core/src/jolt/vm/pc.rs +++ b/jolt-core/src/jolt/vm/pc.rs @@ -1,8 +1,9 @@ -use std::{collections::HashMap, marker::PhantomData}; - use ark_ec::CurveGroup; use ark_ff::PrimeField; use merlin::Transcript; +use std::{collections::HashMap, marker::PhantomData}; + +use common::ELFInstruction; use crate::{ lasso::memory_checking::{MemoryCheckingProver, MemoryCheckingVerifier}, @@ -57,6 +58,20 @@ impl ELFRow { } } +// TODO(JOLT-74): Consolidate ELFInstruction and ELFRow +impl From<&ELFInstruction> for ELFRow { + fn from(value: &ELFInstruction) -> Self { + Self::new( + value.address as usize, + value.opcode as u64, + value.rd.unwrap_or(0), + value.rs1.unwrap_or(0), + value.rs2.unwrap_or(0), + value.imm.unwrap_or(0) as u64, // imm is always cast to its 32-bit repr, signed or unsigned + ) + } +} + /// Polynomial representation of bytecode as expected by Jolt –– each bytecode address maps to a /// tuple, containing information about the instruction and its operands. pub struct FiveTuplePoly { @@ -306,9 +321,7 @@ where } } -pub struct PCProof(PhantomData); - -impl MemoryCheckingProver> for PCProof +impl MemoryCheckingProver> for PCPolys where F: PrimeField, G: CurveGroup, @@ -439,7 +452,7 @@ where } } -impl MemoryCheckingVerifier> for PCProof +impl MemoryCheckingVerifier> for PCPolys where F: PrimeField, G: CurveGroup, @@ -706,11 +719,10 @@ mod tests { let polys: PCPolys = PCPolys::new_program(program, trace); let (gamma, tau) = (&Fr::from(100), &Fr::from(35)); - let pc_prover: PCProof = PCProof(PhantomData::<_>); - let init_leaves: Vec> = pc_prover.init_leaves(&polys, gamma, tau); - let read_leaves: Vec> = pc_prover.read_leaves(&polys, gamma, tau); - let write_leaves: Vec> = pc_prover.write_leaves(&polys, gamma, tau); - let final_leaves: Vec> = pc_prover.final_leaves(&polys, gamma, tau); + let init_leaves: Vec> = polys.init_leaves(&polys, gamma, tau); + let read_leaves: Vec> = polys.read_leaves(&polys, gamma, tau); + let write_leaves: Vec> = polys.write_leaves(&polys, gamma, tau); + let final_leaves: Vec> = polys.final_leaves(&polys, gamma, tau); let init_leaves = &init_leaves[0]; let read_leaves = &read_leaves[0]; @@ -736,14 +748,13 @@ mod tests { ELFRow::new(2, 8u64, 8u64, 8u64, 8u64, 8u64), ]; let polys: PCPolys = PCPolys::new_program(program, trace); - let pc_prover: PCProof = PCProof(PhantomData::<_>); let mut transcript = Transcript::new(b"test_transcript"); let mut random_tape = RandomTape::new(b"test_tape"); let batched_polys = polys.batch(); let commitments = PCPolys::commit(&batched_polys); - let proof = pc_prover.prove_memory_checking( + let proof = polys.prove_memory_checking( &polys, &batched_polys, &commitments, @@ -752,7 +763,7 @@ mod tests { ); let mut transcript = Transcript::new(b"test_transcript"); - PCProof::verify_memory_checking(proof, &commitments, &mut transcript) + PCPolys::verify_memory_checking(proof, &commitments, &mut transcript) .expect("proof should verify"); } @@ -771,7 +782,6 @@ mod tests { ELFRow::new(4, 32u64, 32u64, 32u64, 32u64, 32u64), ]; - let pc_prover: PCProof = PCProof(PhantomData::<_>); let polys: PCPolys = PCPolys::new_program(program, trace); let batch = polys.batch(); let commitments = PCPolys::commit(&batch); @@ -779,7 +789,7 @@ mod tests { let mut transcript = Transcript::new(b"test_transcript"); let mut random_tape = RandomTape::new(b"test_tape"); - let proof = pc_prover.prove_memory_checking( + let proof = polys.prove_memory_checking( &polys, &batch, &commitments, @@ -788,7 +798,7 @@ mod tests { ); let mut transcript = Transcript::new(b"test_transcript"); - PCProof::verify_memory_checking(proof, &commitments, &mut transcript) + PCPolys::verify_memory_checking(proof, &commitments, &mut transcript) .expect("should verify"); } diff --git a/jolt-core/src/jolt/vm/rv32i_vm.rs b/jolt-core/src/jolt/vm/rv32i_vm.rs index ed1aa099b..48f993ca5 100644 --- a/jolt-core/src/jolt/vm/rv32i_vm.rs +++ b/jolt-core/src/jolt/vm/rv32i_vm.rs @@ -7,11 +7,11 @@ use strum_macros::{EnumCount as EnumCountMacro, EnumIter}; use super::Jolt; use crate::jolt::instruction::add::ADD32Instruction; use crate::jolt::instruction::{ - and::ANDInstruction, beq::BEQInstruction, bge::BGEInstruction, - bgeu::BGEUInstruction, blt::BLTInstruction, bltu::BLTUInstruction, bne::BNEInstruction, - jal::JALInstruction, jalr::JALRInstruction, or::ORInstruction, sll::SLLInstruction, - slt::SLTInstruction, sltu::SLTUInstruction, sra::SRAInstruction, srl::SRLInstruction, - sub::SUBInstruction, xor::XORInstruction, JoltInstruction, Opcode, + and::ANDInstruction, beq::BEQInstruction, bge::BGEInstruction, bgeu::BGEUInstruction, + blt::BLTInstruction, bltu::BLTUInstruction, bne::BNEInstruction, jal::JALInstruction, + jalr::JALRInstruction, or::ORInstruction, sll::SLLInstruction, slt::SLTInstruction, + sltu::SLTUInstruction, sra::SRAInstruction, srl::SRLInstruction, sub::SUBInstruction, + xor::XORInstruction, JoltInstruction, Opcode, }; use crate::jolt::subtable::{ and::AndSubtable, eq::EqSubtable, eq_abs::EqAbsSubtable, eq_msb::EqMSBSubtable, @@ -199,14 +199,13 @@ mod tests { RV32I::XOR(XORInstruction(rng.next_u32() as u64, rng.next_u32() as u64)), ]; - let r: Vec = gen_random_point::(ops.len().log_2()); let mut prover_transcript = Transcript::new(b"example"); + let mut random_tape = RandomTape::new(b"test_tape"); + let proof: InstructionLookupsProof = - RV32IJoltVM::prove_instruction_lookups(ops, r.clone(), &mut prover_transcript); + RV32IJoltVM::prove_instruction_lookups(ops, &mut prover_transcript, &mut random_tape); let mut verifier_transcript = Transcript::new(b"example"); - assert!( - RV32IJoltVM::verify_instruction_lookups(proof, r, &mut verifier_transcript).is_ok() - ); + assert!(RV32IJoltVM::verify_instruction_lookups(proof, &mut verifier_transcript).is_ok()); } #[test] From 15336a5ee1d3414050db0377f10ce1f1611b69d9 Mon Sep 17 00:00:00 2001 From: Michael Zhu Date: Mon, 4 Dec 2023 16:46:38 -0500 Subject: [PATCH 2/5] Rename PC -> Bytecode --- jolt-core/src/jolt/trace/mod.rs | 2 +- jolt-core/src/jolt/trace/rv.rs | 2 +- jolt-core/src/jolt/vm/{pc.rs => bytecode.rs} | 143 ++++++++++--------- jolt-core/src/jolt/vm/mod.rs | 45 +++--- 4 files changed, 106 insertions(+), 86 deletions(-) rename jolt-core/src/jolt/vm/{pc.rs => bytecode.rs} (84%) diff --git a/jolt-core/src/jolt/trace/mod.rs b/jolt-core/src/jolt/trace/mod.rs index 06b23aaf9..8b78357b1 100644 --- a/jolt-core/src/jolt/trace/mod.rs +++ b/jolt-core/src/jolt/trace/mod.rs @@ -2,7 +2,7 @@ use ark_ff::PrimeField; use super::{ instruction::JoltInstruction, - vm::{pc::ELFRow, read_write_memory::MemoryOp}, + vm::{bytecode::ELFRow, read_write_memory::MemoryOp}, }; trait JoltProvableTrace { diff --git a/jolt-core/src/jolt/trace/rv.rs b/jolt-core/src/jolt/trace/rv.rs index 915c76cef..6e47f28b5 100644 --- a/jolt-core/src/jolt/trace/rv.rs +++ b/jolt-core/src/jolt/trace/rv.rs @@ -20,7 +20,7 @@ use crate::jolt::instruction::srl::SRLInstruction; use crate::jolt::instruction::xor::XORInstruction; use crate::jolt::instruction::JoltInstruction; use crate::jolt::instruction::{add::ADDInstruction, sub::SUBInstruction}; -use crate::jolt::vm::{pc::ELFRow, rv32i_vm::RV32I}; +use crate::jolt::vm::{bytecode::ELFRow, rv32i_vm::RV32I}; use common::{constants::REGISTER_COUNT, RV32InstructionFormat, RV32IM}; use super::JoltProvableTrace; diff --git a/jolt-core/src/jolt/vm/pc.rs b/jolt-core/src/jolt/vm/bytecode.rs similarity index 84% rename from jolt-core/src/jolt/vm/pc.rs rename to jolt-core/src/jolt/vm/bytecode.rs index 99f9710c4..f2afc15d4 100644 --- a/jolt-core/src/jolt/vm/pc.rs +++ b/jolt-core/src/jolt/vm/bytecode.rs @@ -137,7 +137,7 @@ impl FiveTuplePoly { } } -pub struct PCPolys> { +pub struct BytecodePolynomials> { _group: PhantomData, /// MLE of read/write addresses. For offline memory checking, each read is paired with a "virtual" write, /// so the read addresses and write addresses are the same. @@ -156,19 +156,19 @@ pub struct PCPolys> { t_final: DensePolynomial, } -impl> PCPolys { - pub fn new_program(mut program: Vec, mut trace: Vec) -> Self { - Self::validate_program(&program, &trace); - Self::preprocess(&mut program, &mut trace); +impl> BytecodePolynomials { + pub fn new(mut bytecode: Vec, mut trace: Vec) -> Self { + Self::validate_bytecode(&bytecode, &trace); + Self::preprocess(&mut bytecode, &mut trace); // Preprocessing should deal with padding. - assert!(is_power_of_two(program.len())); + assert!(is_power_of_two(bytecode.len())); assert!(is_power_of_two(trace.len())); let num_ops = trace.len().next_power_of_two(); - let code_size = program.len().next_power_of_two(); + let code_size = bytecode.len().next_power_of_two(); - println!("PCPolys::new_program num_ops {num_ops} code_size {code_size}"); + println!("BytecodePolynomials::new num_ops {num_ops} code_size {code_size}"); let mut a_read_write_usize: Vec = vec![0; num_ops]; let mut read_cts: Vec = vec![0; num_ops]; @@ -184,7 +184,7 @@ impl> PCPolys { } let v_read_write = FiveTuplePoly::from_elf(&trace); - let v_init_final = FiveTuplePoly::from_elf(&program); + let v_init_final = FiveTuplePoly::from_elf(&bytecode); let a_read_write = DensePolynomial::from_usize(&a_read_write_usize); let t_read = DensePolynomial::from_usize(&read_cts); @@ -200,37 +200,37 @@ impl> PCPolys { } } - fn validate_program(program: &Vec, trace: &Vec) { - let mut pc = program[0].address; + fn validate_bytecode(bytecode: &Vec, trace: &Vec) { + let mut pc = bytecode[0].address; assert!(pc < 10_000); - let mut program_map: HashMap = HashMap::new(); + let mut bytecode_map: HashMap = HashMap::new(); - for program_row in program.iter().skip(1) { - program_map.insert(program_row.address, program_row); - assert_eq!(program_row.address, pc + ADDRESS_INCREMENT); + for bytecode_row in bytecode.iter().skip(1) { + bytecode_map.insert(bytecode_row.address, bytecode_row); + assert_eq!(bytecode_row.address, pc + ADDRESS_INCREMENT); - pc = program_row.address; + pc = bytecode_row.address; } for trace_row in trace { assert_eq!( - **program_map + **bytecode_map .get(&trace_row.address) - .expect("couldn't find in program"), + .expect("couldn't find in bytecode"), *trace_row ); } } - fn preprocess(program: &mut Vec, trace: &mut Vec) { - // Program: Add single no_op instruction at adddress | ELF + 1 | - let no_op_address = program.last().unwrap().address + ADDRESS_INCREMENT; - program.push(ELFRow::no_op(no_op_address)); + fn preprocess(bytecode: &mut Vec, trace: &mut Vec) { + // Bytecode: Add single no_op instruction at adddress | ELF + 1 | + let no_op_address = bytecode.last().unwrap().address + ADDRESS_INCREMENT; + bytecode.push(ELFRow::no_op(no_op_address)); - // Program: Pad to nearest power of 2 - for _program_i in program.len()..program.len().next_power_of_two() { - program.push(ELFRow::no_op(0)); + // Bytecode: Pad to nearest power of 2 + for _ in bytecode.len()..bytecode.len().next_power_of_two() { + bytecode.push(ELFRow::no_op(0)); } // Trace: Pad to nearest power of 2 @@ -241,7 +241,7 @@ impl> PCPolys { } } -pub struct BatchedPCPolys { +pub struct BatchedBytecodePolynomials { /// Contains: /// - a_read_write, t_read, v_read_write combined_read_write: DensePolynomial, @@ -251,8 +251,8 @@ pub struct BatchedPCPolys { combined_init_final: DensePolynomial, } -pub struct ProgramCommitment { - generators: PCCommitmentGenerators, +pub struct BytecodeCommitment { + generators: BytecodeCommitmentGenerators, /// Combined commitment for: /// - a_read_write, t_read, v_read_write pub read_write_commitments: CombinedTableCommitment, @@ -262,18 +262,18 @@ pub struct ProgramCommitment { pub init_final_commitments: CombinedTableCommitment, } -pub struct PCCommitmentGenerators { +pub struct BytecodeCommitmentGenerators { pub gens_read_write: PolyCommitmentGens, pub gens_init_final: PolyCommitmentGens, } -impl BatchablePolynomials for PCPolys +impl BatchablePolynomials for BytecodePolynomials where F: PrimeField, G: CurveGroup, { - type BatchedPolynomials = BatchedPCPolys; - type Commitment = ProgramCommitment; + type BatchedPolynomials = BatchedBytecodePolynomials; + type Commitment = BytecodeCommitment; fn batch(&self) -> Self::BatchedPolynomials { let combined_read_write = DensePolynomial::merge(&vec![ @@ -303,12 +303,12 @@ where fn commit(batched_polys: &Self::BatchedPolynomials) -> Self::Commitment { let (gens_read_write, read_write_commitments) = batched_polys .combined_read_write - .combined_commit(b"BatchedPCPolys.read_write"); + .combined_commit(b"BatchedBytecodePolynomials.read_write"); let (gens_init_final, init_final_commitments) = batched_polys .combined_init_final - .combined_commit(b"BatchedPCPolys.init_final"); + .combined_commit(b"BatchedBytecodePolynomials.init_final"); - let generators = PCCommitmentGenerators { + let generators = BytecodeCommitmentGenerators { gens_read_write, gens_init_final, }; @@ -321,13 +321,13 @@ where } } -impl MemoryCheckingProver> for PCPolys +impl MemoryCheckingProver> for BytecodePolynomials where F: PrimeField, G: CurveGroup, { - type ReadWriteOpenings = PCReadWriteOpenings; - type InitFinalOpenings = PCInitFinalOpenings; + type ReadWriteOpenings = BytecodeReadWriteOpenings; + type InitFinalOpenings = BytecodeInitFinalOpenings; // [a, opcode, rd, rs1, rs2, imm, t] type MemoryTuple = [F; 7]; @@ -344,14 +344,14 @@ where fn read_leaves( &self, - polynomials: &PCPolys, + polynomials: &BytecodePolynomials, gamma: &F, tau: &F, ) -> Vec> { let num_ops = polynomials.a_read_write.len(); let read_fingerprints = (0..num_ops) .map(|i| { - >>::fingerprint( + >>::fingerprint( &[ polynomials.a_read_write[i], polynomials.v_read_write.opcode[i], @@ -370,14 +370,14 @@ where } fn write_leaves( &self, - polynomials: &PCPolys, + polynomials: &BytecodePolynomials, gamma: &F, tau: &F, ) -> Vec> { let num_ops = polynomials.a_read_write.len(); let read_fingerprints = (0..num_ops) .map(|i| { - >>::fingerprint( + >>::fingerprint( &[ polynomials.a_read_write[i], polynomials.v_read_write.opcode[i], @@ -396,14 +396,14 @@ where } fn init_leaves( &self, - polynomials: &PCPolys, + polynomials: &BytecodePolynomials, gamma: &F, tau: &F, ) -> Vec> { let memory_size = polynomials.v_init_final.opcode.len(); let init_fingerprints = (0..memory_size) .map(|i| { - >>::fingerprint( + >>::fingerprint( &[ F::from(i as u64), polynomials.v_init_final.opcode[i], @@ -422,14 +422,14 @@ where } fn final_leaves( &self, - polynomials: &PCPolys, + polynomials: &BytecodePolynomials, gamma: &F, tau: &F, ) -> Vec> { let memory_size = polynomials.v_init_final.opcode.len(); let init_fingerprints = (0..memory_size) .map(|i| { - >>::fingerprint( + >>::fingerprint( &[ F::from(i as u64), polynomials.v_init_final.opcode[i], @@ -452,7 +452,7 @@ where } } -impl MemoryCheckingVerifier> for PCPolys +impl MemoryCheckingVerifier> for BytecodePolynomials where F: PrimeField, G: CurveGroup, @@ -508,7 +508,7 @@ where } } -pub struct PCReadWriteOpenings +pub struct BytecodeReadWriteOpenings where F: PrimeField, G: CurveGroup, @@ -523,14 +523,15 @@ where read_write_opening_proof: CombinedTableEvalProof, } -impl StructuredOpeningProof> for PCReadWriteOpenings +impl StructuredOpeningProof> + for BytecodeReadWriteOpenings where F: PrimeField, G: CurveGroup, { type Openings = (F, Vec, F); - fn open(polynomials: &PCPolys, opening_point: &Vec) -> Self::Openings { + fn open(polynomials: &BytecodePolynomials, opening_point: &Vec) -> Self::Openings { ( polynomials.a_read_write.evaluate(&opening_point), polynomials.v_read_write.evaluate(&opening_point), @@ -539,8 +540,8 @@ where } fn prove_openings( - polynomials: &BatchedPCPolys, - commitment: &ProgramCommitment, + polynomials: &BatchedBytecodePolynomials, + commitment: &BytecodeCommitment, opening_point: &Vec, openings: (F, Vec, F), transcript: &mut Transcript, @@ -573,7 +574,7 @@ where fn verify_openings( &self, - commitment: &ProgramCommitment, + commitment: &BytecodeCommitment, opening_point: &Vec, transcript: &mut Transcript, ) -> Result<(), ProofVerifyError> { @@ -593,7 +594,7 @@ where } } -pub struct PCInitFinalOpenings +pub struct BytecodeInitFinalOpenings where F: PrimeField, G: CurveGroup, @@ -608,14 +609,15 @@ where init_final_opening_proof: CombinedTableEvalProof, } -impl StructuredOpeningProof> for PCInitFinalOpenings +impl StructuredOpeningProof> + for BytecodeInitFinalOpenings where F: PrimeField, G: CurveGroup, { type Openings = (Vec, F); - fn open(polynomials: &PCPolys, opening_point: &Vec) -> Self::Openings { + fn open(polynomials: &BytecodePolynomials, opening_point: &Vec) -> Self::Openings { ( polynomials.v_init_final.evaluate(&opening_point), polynomials.t_final.evaluate(&opening_point), @@ -623,8 +625,8 @@ where } fn prove_openings( - polynomials: &BatchedPCPolys, - commitment: &ProgramCommitment, + polynomials: &BatchedBytecodePolynomials, + commitment: &BytecodeCommitment, opening_point: &Vec, openings: Self::Openings, transcript: &mut Transcript, @@ -654,7 +656,7 @@ where fn verify_openings( &self, - commitment: &ProgramCommitment, + commitment: &BytecodeCommitment, opening_point: &Vec, transcript: &mut Transcript, ) -> Result<(), ProofVerifyError> { @@ -716,7 +718,8 @@ mod tests { ELFRow::new(3, 16u64, 16u64, 16u64, 16u64, 16u64), ELFRow::new(2, 8u64, 8u64, 8u64, 8u64, 8u64), ]; - let polys: PCPolys = PCPolys::new_program(program, trace); + let polys: BytecodePolynomials = + BytecodePolynomials::new(program, trace); let (gamma, tau) = (&Fr::from(100), &Fr::from(35)); let init_leaves: Vec> = polys.init_leaves(&polys, gamma, tau); @@ -747,13 +750,14 @@ mod tests { ELFRow::new(3, 16u64, 16u64, 16u64, 16u64, 16u64), ELFRow::new(2, 8u64, 8u64, 8u64, 8u64, 8u64), ]; - let polys: PCPolys = PCPolys::new_program(program, trace); + let polys: BytecodePolynomials = + BytecodePolynomials::new(program, trace); let mut transcript = Transcript::new(b"test_transcript"); let mut random_tape = RandomTape::new(b"test_tape"); let batched_polys = polys.batch(); - let commitments = PCPolys::commit(&batched_polys); + let commitments = BytecodePolynomials::commit(&batched_polys); let proof = polys.prove_memory_checking( &polys, &batched_polys, @@ -763,7 +767,7 @@ mod tests { ); let mut transcript = Transcript::new(b"test_transcript"); - PCPolys::verify_memory_checking(proof, &commitments, &mut transcript) + BytecodePolynomials::verify_memory_checking(proof, &commitments, &mut transcript) .expect("proof should verify"); } @@ -782,9 +786,10 @@ mod tests { ELFRow::new(4, 32u64, 32u64, 32u64, 32u64, 32u64), ]; - let polys: PCPolys = PCPolys::new_program(program, trace); + let polys: BytecodePolynomials = + BytecodePolynomials::new(program, trace); let batch = polys.batch(); - let commitments = PCPolys::commit(&batch); + let commitments = BytecodePolynomials::commit(&batch); let mut transcript = Transcript::new(b"test_transcript"); let mut random_tape = RandomTape::new(b"test_tape"); @@ -798,7 +803,7 @@ mod tests { ); let mut transcript = Transcript::new(b"test_transcript"); - PCPolys::verify_memory_checking(proof, &commitments, &mut transcript) + BytecodePolynomials::verify_memory_checking(proof, &commitments, &mut transcript) .expect("should verify"); } @@ -817,7 +822,8 @@ mod tests { ELFRow::new(2, 8u64, 8u64, 8u64, 8u64, 8u64), ELFRow::new(5, 0u64, 0u64, 0u64, 0u64, 0u64), // no_op: shouldn't exist in pgoram ]; - let _polys: PCPolys = PCPolys::new_program(program, trace); + let _polys: BytecodePolynomials = + BytecodePolynomials::new(program, trace); } #[test] @@ -833,6 +839,7 @@ mod tests { ELFRow::new(3, 16u64, 16u64, 16u64, 16u64, 16u64), ELFRow::new(2, 8u64, 8u64, 8u64, 8u64, 8u64), ]; - let _polys: PCPolys = PCPolys::new_program(program, trace); + let _polys: BytecodePolynomials = + BytecodePolynomials::new(program, trace); } } diff --git a/jolt-core/src/jolt/vm/mod.rs b/jolt-core/src/jolt/vm/mod.rs index 83d174d94..616c1070d 100644 --- a/jolt-core/src/jolt/vm/mod.rs +++ b/jolt-core/src/jolt/vm/mod.rs @@ -19,12 +19,19 @@ use crate::jolt::{ use crate::poly::structured_poly::BatchablePolynomials; use crate::utils::{errors::ProofVerifyError, random::RandomTape}; +use self::bytecode::{ + BytecodeCommitment, BytecodeInitFinalOpenings, BytecodePolynomials, BytecodeReadWriteOpenings, + ELFRow, +}; use self::instruction_lookups::{InstructionLookups, InstructionLookupsProof}; -use self::pc::{ELFRow, PCInitFinalOpenings, PCPolys, PCReadWriteOpenings, ProgramCommitment}; use self::read_write_memory::{ MemoryCommitment, MemoryInitFinalOpenings, MemoryOp, MemoryReadWriteOpenings, ReadWriteMemory, }; +struct JoltProof> { + instruction_lookups: InstructionLookupsProof, +} + pub trait Jolt, const C: usize, const M: usize> { type InstructionSet: JoltInstruction + Opcode + IntoEnumIterator + EnumCount; type Subtables: LassoSubtable + IntoEnumIterator + EnumCount + From + Into; @@ -32,7 +39,7 @@ pub trait Jolt, const C: usize, co fn prove() { // preprocess? // emulate - // prove_program_code + // prove_bytecode // prove_memory // prove_lookups // prove_r1cs @@ -58,18 +65,23 @@ pub trait Jolt, const C: usize, co ) } - fn prove_program_code( - mut program: Vec, + fn prove_bytecode( + mut bytecode: Vec, mut trace: Vec, transcript: &mut Transcript, random_tape: &mut RandomTape, ) -> ( - MemoryCheckingProof, PCReadWriteOpenings, PCInitFinalOpenings>, - ProgramCommitment, + MemoryCheckingProof< + G, + BytecodePolynomials, + BytecodeReadWriteOpenings, + BytecodeInitFinalOpenings, + >, + BytecodeCommitment, ) { - let polys: PCPolys = PCPolys::new_program(program, trace); + let polys: BytecodePolynomials = BytecodePolynomials::new(bytecode, trace); let batched_polys = polys.batch(); - let commitments = PCPolys::commit(&batched_polys); + let commitments = BytecodePolynomials::commit(&batched_polys); ( polys.prove_memory_checking( @@ -83,17 +95,17 @@ pub trait Jolt, const C: usize, co ) } - fn verify_program_code( + fn verify_bytecode( proof: MemoryCheckingProof< G, - PCPolys, - PCReadWriteOpenings, - PCInitFinalOpenings, + BytecodePolynomials, + BytecodeReadWriteOpenings, + BytecodeInitFinalOpenings, >, - commitment: ProgramCommitment, + commitment: BytecodeCommitment, transcript: &mut Transcript, ) -> Result<(), ProofVerifyError> { - PCPolys::verify_memory_checking(proof, &commitment, transcript) + BytecodePolynomials::verify_memory_checking(proof, &commitment, transcript) } fn prove_memory( @@ -108,6 +120,7 @@ pub trait Jolt, const C: usize, co MemoryReadWriteOpenings, MemoryInitFinalOpenings, >, + MemoryCommitment, SurgeProof, ) { const MAX_TRACE_SIZE: usize = 1 << 22; @@ -138,7 +151,7 @@ pub trait Jolt, const C: usize, co >::new(timestamp_validity_lookups) .prove(transcript); - (memory_checking_proof, timestamp_validity_proof) + (memory_checking_proof, commitments, timestamp_validity_proof) } fn verify_memory( @@ -165,7 +178,7 @@ pub trait Jolt, const C: usize, co } } +pub mod bytecode; pub mod instruction_lookups; -pub mod pc; pub mod read_write_memory; pub mod rv32i_vm; From b1fb20ca7d9ca5464ab0281a7fd1c5a69911ec43 Mon Sep 17 00:00:00 2001 From: Michael Zhu Date: Tue, 5 Dec 2023 10:17:57 -0500 Subject: [PATCH 3/5] Fill in JoltProof and inner proof structs --- jolt-core/src/jolt/vm/bytecode.rs | 16 ++- jolt-core/src/jolt/vm/mod.rs | 118 ++++++++++----------- jolt-core/src/jolt/vm/read_write_memory.rs | 18 +++- 3 files changed, 88 insertions(+), 64 deletions(-) diff --git a/jolt-core/src/jolt/vm/bytecode.rs b/jolt-core/src/jolt/vm/bytecode.rs index f2afc15d4..ed8aa947b 100644 --- a/jolt-core/src/jolt/vm/bytecode.rs +++ b/jolt-core/src/jolt/vm/bytecode.rs @@ -6,7 +6,7 @@ use std::{collections::HashMap, marker::PhantomData}; use common::ELFInstruction; use crate::{ - lasso::memory_checking::{MemoryCheckingProver, MemoryCheckingVerifier}, + lasso::memory_checking::{MemoryCheckingProof, MemoryCheckingProver, MemoryCheckingVerifier}, poly::{ dense_mlpoly::{DensePolynomial, PolyCommitmentGens}, identity_poly::IdentityPolynomial, @@ -18,6 +18,20 @@ use crate::{ const ADDRESS_INCREMENT: usize = 1; +pub struct BytecodeProof +where + F: PrimeField, + G: CurveGroup, +{ + pub memory_checking_proof: MemoryCheckingProof< + G, + BytecodePolynomials, + BytecodeReadWriteOpenings, + BytecodeInitFinalOpenings, + >, + pub commitment: BytecodeCommitment, +} + #[derive(Debug, Clone, PartialEq)] pub struct ELFRow { /// Memory address as read from the ELF. diff --git a/jolt-core/src/jolt/vm/mod.rs b/jolt-core/src/jolt/vm/mod.rs index 616c1070d..fdd7ac94c 100644 --- a/jolt-core/src/jolt/vm/mod.rs +++ b/jolt-core/src/jolt/vm/mod.rs @@ -4,6 +4,12 @@ use merlin::Transcript; use std::any::TypeId; use strum::{EnumCount, IntoEnumIterator}; +use crate::jolt::{ + instruction::{sltu::SLTUInstruction, JoltInstruction, Opcode}, + subtable::LassoSubtable, +}; +use crate::poly::structured_poly::BatchablePolynomials; +use crate::utils::{errors::ProofVerifyError, random::RandomTape}; use crate::{ lasso::{ memory_checking::{MemoryCheckingProof, MemoryCheckingProver, MemoryCheckingVerifier}, @@ -12,31 +18,28 @@ use crate::{ utils::math::Math, }; -use crate::jolt::{ - instruction::{sltu::SLTUInstruction, JoltInstruction, Opcode}, - subtable::LassoSubtable, -}; -use crate::poly::structured_poly::BatchablePolynomials; -use crate::utils::{errors::ProofVerifyError, random::RandomTape}; - use self::bytecode::{ - BytecodeCommitment, BytecodeInitFinalOpenings, BytecodePolynomials, BytecodeReadWriteOpenings, - ELFRow, + BytecodeCommitment, BytecodeInitFinalOpenings, BytecodePolynomials, BytecodeProof, + BytecodeReadWriteOpenings, ELFRow, }; use self::instruction_lookups::{InstructionLookups, InstructionLookupsProof}; use self::read_write_memory::{ MemoryCommitment, MemoryInitFinalOpenings, MemoryOp, MemoryReadWriteOpenings, ReadWriteMemory, + ReadWriteMemoryProof, }; struct JoltProof> { instruction_lookups: InstructionLookupsProof, + read_write_memory: ReadWriteMemoryProof, + bytecode: BytecodeProof, + // TODO: r1cs } pub trait Jolt, const C: usize, const M: usize> { type InstructionSet: JoltInstruction + Opcode + IntoEnumIterator + EnumCount; type Subtables: LassoSubtable + IntoEnumIterator + EnumCount + From + Into; - fn prove() { + fn prove() -> JoltProof { // preprocess? // emulate // prove_bytecode @@ -46,6 +49,14 @@ pub trait Jolt, const C: usize, co unimplemented!("todo"); } + fn verify(proof: JoltProof) -> Result<(), ProofVerifyError> { + let mut transcript = Transcript::new(b"Jolt"); + Self::verify_bytecode(proof.bytecode, &mut transcript)?; + Self::verify_memory(proof.read_write_memory, &mut transcript)?; + Self::verify_instruction_lookups(proof.instruction_lookups, &mut transcript)?; + todo!("r1cs"); + } + fn prove_instruction_lookups( ops: Vec, transcript: &mut Transcript, @@ -70,42 +81,33 @@ pub trait Jolt, const C: usize, co mut trace: Vec, transcript: &mut Transcript, random_tape: &mut RandomTape, - ) -> ( - MemoryCheckingProof< - G, - BytecodePolynomials, - BytecodeReadWriteOpenings, - BytecodeInitFinalOpenings, - >, - BytecodeCommitment, - ) { + ) -> BytecodeProof { let polys: BytecodePolynomials = BytecodePolynomials::new(bytecode, trace); let batched_polys = polys.batch(); - let commitments = BytecodePolynomials::commit(&batched_polys); - - ( - polys.prove_memory_checking( - &polys, - &batched_polys, - &commitments, - transcript, - random_tape, - ), - commitments, - ) + let commitment = BytecodePolynomials::commit(&batched_polys); + + let memory_checking_proof = polys.prove_memory_checking( + &polys, + &batched_polys, + &commitment, + transcript, + random_tape, + ); + BytecodeProof { + memory_checking_proof, + commitment, + } } fn verify_bytecode( - proof: MemoryCheckingProof< - G, - BytecodePolynomials, - BytecodeReadWriteOpenings, - BytecodeInitFinalOpenings, - >, - commitment: BytecodeCommitment, + proof: BytecodeProof, transcript: &mut Transcript, ) -> Result<(), ProofVerifyError> { - BytecodePolynomials::verify_memory_checking(proof, &commitment, transcript) + BytecodePolynomials::verify_memory_checking( + proof.memory_checking_proof, + &proof.commitment, + transcript, + ) } fn prove_memory( @@ -113,16 +115,7 @@ pub trait Jolt, const C: usize, co memory_size: usize, transcript: &mut Transcript, random_tape: &mut RandomTape, - ) -> ( - MemoryCheckingProof< - G, - ReadWriteMemory, - MemoryReadWriteOpenings, - MemoryInitFinalOpenings, - >, - MemoryCommitment, - SurgeProof, - ) { + ) -> ReadWriteMemoryProof { const MAX_TRACE_SIZE: usize = 1 << 22; // TODO: Support longer traces assert!(memory_trace.len() <= MAX_TRACE_SIZE); @@ -131,12 +124,12 @@ pub trait Jolt, const C: usize, co let (memory, read_timestamps) = ReadWriteMemory::new(memory_trace, memory_size, transcript); let batched_polys = memory.batch(); - let commitments: MemoryCommitment = ReadWriteMemory::commit(&batched_polys); + let commitment: MemoryCommitment = ReadWriteMemory::commit(&batched_polys); let memory_checking_proof = memory.prove_memory_checking( &memory, &batched_polys, - &commitments, + &commitment, transcript, random_tape, ); @@ -151,24 +144,25 @@ pub trait Jolt, const C: usize, co >::new(timestamp_validity_lookups) .prove(transcript); - (memory_checking_proof, commitments, timestamp_validity_proof) + ReadWriteMemoryProof { + memory_checking_proof, + commitment, + timestamp_validity_proof, + } } fn verify_memory( - memory_checking_proof: MemoryCheckingProof< - G, - ReadWriteMemory, - MemoryReadWriteOpenings, - MemoryInitFinalOpenings, - >, - commitment: MemoryCommitment, + proof: ReadWriteMemoryProof, transcript: &mut Transcript, - timestamp_validity_proof: SurgeProof, ) -> Result<(), ProofVerifyError> { const MAX_TRACE_SIZE: usize = 1 << 22; - ReadWriteMemory::verify_memory_checking(memory_checking_proof, &commitment, transcript)?; + ReadWriteMemory::verify_memory_checking( + proof.memory_checking_proof, + &proof.commitment, + transcript, + )?; >::verify( - timestamp_validity_proof, + proof.timestamp_validity_proof, transcript, ) } diff --git a/jolt-core/src/jolt/vm/read_write_memory.rs b/jolt-core/src/jolt/vm/read_write_memory.rs index 68bdc2898..965c33e87 100644 --- a/jolt-core/src/jolt/vm/read_write_memory.rs +++ b/jolt-core/src/jolt/vm/read_write_memory.rs @@ -5,7 +5,8 @@ use ark_ff::PrimeField; use merlin::Transcript; use crate::{ - lasso::memory_checking::{MemoryCheckingProver, MemoryCheckingVerifier}, + lasso::memory_checking::{MemoryCheckingProof, MemoryCheckingProver, MemoryCheckingVerifier}, + lasso::surge::SurgeProof, poly::{ dense_mlpoly::{DensePolynomial, PolyCommitmentGens}, identity_poly::IdentityPolynomial, @@ -16,6 +17,21 @@ use crate::{ }; use common::constants::{RAM_START_ADDRESS, REGISTER_COUNT}; +pub struct ReadWriteMemoryProof +where + F: PrimeField, + G: CurveGroup, +{ + pub memory_checking_proof: MemoryCheckingProof< + G, + ReadWriteMemory, + MemoryReadWriteOpenings, + MemoryInitFinalOpenings, + >, + pub commitment: MemoryCommitment, + pub timestamp_validity_proof: SurgeProof, +} + #[derive(Debug, PartialEq, Clone)] pub enum MemoryOp { Read(u64, u64), // (address, value) From 18108c7725d546d0143b565713456eea6ae1c128 Mon Sep 17 00:00:00 2001 From: Michael Zhu Date: Tue, 5 Dec 2023 11:12:03 -0500 Subject: [PATCH 4/5] Rename to_pc_trace -> to_bytecode_trace --- jolt-core/src/jolt/trace/mod.rs | 2 +- jolt-core/src/jolt/trace/rv.rs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/jolt-core/src/jolt/trace/mod.rs b/jolt-core/src/jolt/trace/mod.rs index 8b78357b1..c9fa70683 100644 --- a/jolt-core/src/jolt/trace/mod.rs +++ b/jolt-core/src/jolt/trace/mod.rs @@ -9,7 +9,7 @@ trait JoltProvableTrace { type JoltInstructionEnum: JoltInstruction; fn to_jolt_instructions(&self) -> Vec; fn to_ram_ops(&self) -> Vec; - fn to_pc_trace(&self) -> ELFRow; + fn to_bytecode_trace(&self) -> ELFRow; fn to_circuit_flags(&self) -> Vec; } diff --git a/jolt-core/src/jolt/trace/rv.rs b/jolt-core/src/jolt/trace/rv.rs index 6e47f28b5..4dddd8ea6 100644 --- a/jolt-core/src/jolt/trace/rv.rs +++ b/jolt-core/src/jolt/trace/rv.rs @@ -843,7 +843,7 @@ impl JoltProvableTrace for RVTraceRow { } } - fn to_pc_trace(&self) -> ELFRow { + fn to_bytecode_trace(&self) -> ELFRow { ELFRow::new( self.pc.try_into().unwrap(), self.opcode as u64, @@ -1016,10 +1016,10 @@ mod tests { use std::convert; #[test] - fn to_pc_trace() { + fn to_bytecode_trace() { // ADD let add_row = RVTraceRow::RType(2, RV32IM::ADD, 12, 10, 11, 0, 35, 15, 20); - let add_pc = add_row.to_pc_trace(); + let add_pc = add_row.to_bytecode_trace(); let expected_pc = ELFRow::new(2, RV32IM::ADD as u64, 12, 10, 11, 0u64); assert_eq!(add_pc, expected_pc); @@ -1027,7 +1027,7 @@ mod tests { let imm = 20; let rd_update = 20 << 12; let lui_row = RVTraceRow::UType(0, RV32IM::LUI, 10, 0, rd_update, imm); - let lui_pc = lui_row.to_pc_trace(); + let lui_pc = lui_row.to_bytecode_trace(); let expected_pc = ELFRow::new(0, RV32IM::LUI as u64, 10, 0, 0, 20u64); assert_eq!(lui_pc, expected_pc); } @@ -1072,7 +1072,7 @@ mod tests { .collect(); let _: Vec = converted_trace .iter() - .map(|row| row.to_pc_trace()) + .map(|row| row.to_bytecode_trace()) .collect(); let mut num_errors = 0; From b1d4c16c643a096f459cbe60240221da7b9d370f Mon Sep 17 00:00:00 2001 From: Michael Zhu Date: Tue, 5 Dec 2023 11:50:45 -0500 Subject: [PATCH 5/5] Fill in prove --- jolt-core/src/jolt/vm/mod.rs | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/jolt-core/src/jolt/vm/mod.rs b/jolt-core/src/jolt/vm/mod.rs index fdd7ac94c..6fd90ef42 100644 --- a/jolt-core/src/jolt/vm/mod.rs +++ b/jolt-core/src/jolt/vm/mod.rs @@ -39,18 +39,31 @@ pub trait Jolt, const C: usize, co type InstructionSet: JoltInstruction + Opcode + IntoEnumIterator + EnumCount; type Subtables: LassoSubtable + IntoEnumIterator + EnumCount + From + Into; - fn prove() -> JoltProof { - // preprocess? - // emulate - // prove_bytecode - // prove_memory - // prove_lookups - // prove_r1cs - unimplemented!("todo"); + fn prove( + mut bytecode: Vec, + mut bytecode_trace: Vec, + memory_trace: Vec, + memory_size: usize, + instructions: Vec, + ) -> JoltProof { + let mut transcript = Transcript::new(b"Jolt transcript"); + let mut random_tape = RandomTape::new(b"Jolt prover randomness"); + let bytecode_proof = + Self::prove_bytecode(bytecode, bytecode_trace, &mut transcript, &mut random_tape); + let memory_proof = + Self::prove_memory(memory_trace, memory_size, &mut transcript, &mut random_tape); + let instruction_lookups = + Self::prove_instruction_lookups(instructions, &mut transcript, &mut random_tape); + todo!("rics"); + JoltProof { + instruction_lookups, + read_write_memory: memory_proof, + bytecode: bytecode_proof, + } } fn verify(proof: JoltProof) -> Result<(), ProofVerifyError> { - let mut transcript = Transcript::new(b"Jolt"); + let mut transcript = Transcript::new(b"Jolt transcript"); Self::verify_bytecode(proof.bytecode, &mut transcript)?; Self::verify_memory(proof.read_write_memory, &mut transcript)?; Self::verify_instruction_lookups(proof.instruction_lookups, &mut transcript)?;