diff --git a/jolt-core/src/jolt/trace/rv.rs b/jolt-core/src/jolt/trace/rv.rs index 3aae8ff7b..d456bb904 100644 --- a/jolt-core/src/jolt/trace/rv.rs +++ b/jolt-core/src/jolt/trace/rv.rs @@ -273,7 +273,7 @@ impl RVTraceRow { // Assert instruction correctness if arithmetic let lookups = self.to_jolt_instructions(); assert!(lookups.len() == 1); - if (lookups.len() == 1 && self.rd.unwrap() != 0) { + if lookups.len() == 1 && self.rd.unwrap() != 0 { assert_eq!(lookups.len(), 1, "{self:?}"); let expected_result: Fr = lookups[0].lookup_entry(C, M); let bigint = expected_result.into_bigint(); @@ -760,7 +760,7 @@ impl JoltProvableTrace for RVTraceRow { fn sum_u64_i32(a: u64, b: i32) -> u64 { if b.is_negative() { let abs_b = b.abs() as u64; - if (a < abs_b) { + if a < abs_b { panic!("overflow") } a - abs_b @@ -774,6 +774,7 @@ fn sum_u64_i32(a: u64, b: i32) -> u64 { #[cfg(test)] mod tests { use ark_curve25519::EdwardsProjective; + use itertools::Itertools; use merlin::Transcript; use crate::{jolt::vm::{instruction_lookups::InstructionLookupsProof, rv32i_vm::RV32IJoltVM, Jolt, read_write_memory::ReadWriteMemory}, utils::{gen_random_point, math::Math, random::RandomTape}, poly::structured_poly::BatchablePolynomials}; @@ -819,7 +820,7 @@ mod tests { } #[test] - fn load_conversion() { + fn load_trace() { // 1. Load common::RVTraceRow from file // 2. Convert via RVTraceRow::from_common // 3. Run validation @@ -831,21 +832,29 @@ mod tests { let trace_location = JoltPaths::trace_path("fibonacci"); let loaded_trace: Vec = Vec::::deserialize_from_file(&trace_location).expect("deserialization failed"); - let converted_trace: Vec = loaded_trace.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); - // } + println!("Validation error: {} \n{:#?}\n\n", e, row); num_errors += 1; } } println!("Total errors: {num_errors}"); } + #[test] + fn load_bytecode() { + use common::serializable::Serializable; + use common::path::JoltPaths; + + 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 common::serializable::Serializable; diff --git a/jolt-core/src/jolt/vm/mod.rs b/jolt-core/src/jolt/vm/mod.rs index f0d50cdd1..d06c0a125 100644 --- a/jolt-core/src/jolt/vm/mod.rs +++ b/jolt-core/src/jolt/vm/mod.rs @@ -3,6 +3,7 @@ use ark_ff::PrimeField; use ark_serialize::Read; use merlin::Transcript; use std::any::TypeId; +use std::marker::PhantomData; use strum::{EnumCount, IntoEnumIterator}; use crate::lasso::{ @@ -18,6 +19,7 @@ use crate::poly::structured_poly::BatchablePolynomials; use crate::utils::{errors::ProofVerifyError, random::RandomTape}; use self::instruction_lookups::{InstructionLookups, InstructionLookupsProof}; +use self::pc::{ELFRow, PCInitFinalOpenings, PCPolys, PCReadWriteOpenings}; use self::read_write_memory::{ MemoryCommitment, MemoryInitFinalOpenings, MemoryOp, MemoryReadWriteOpenings, ReadWriteMemory, }; @@ -26,7 +28,16 @@ pub trait Jolt, const C: usize, co type InstructionSet: JoltInstruction + Opcode + IntoEnumIterator + EnumCount; type Subtables: LassoSubtable + IntoEnumIterator + EnumCount + From + Into; - fn prove() { + fn prove(program_path: &str) { + // let trace_location = JoltPaths::trace_path(program_path); + // let loaded_trace: Vec = + // Vec::::deserialize_from_file(&trace_location) + // .expect("deserialization failed"); + + // let converted_trace: Vec = loaded_trace + // .into_iter() + // .map(|common| RVTraceRow::from_common(common)) + // .collect(); // preprocess? // emulate // prove_program_code @@ -57,55 +68,23 @@ pub trait Jolt, const C: usize, co } 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, - ) { - // 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, - // ) + random_tape: &mut RandomTape, + ) -> MemoryCheckingProof, PCReadWriteOpenings, PCInitFinalOpenings> + { + 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, + ) } fn prove_memory( diff --git a/jolt-core/src/jolt/vm/pc.rs b/jolt-core/src/jolt/vm/pc.rs index d583a38c1..cbfc4b9e6 100644 --- a/jolt-core/src/jolt/vm/pc.rs +++ b/jolt-core/src/jolt/vm/pc.rs @@ -16,6 +16,8 @@ use crate::{ utils::{errors::ProofVerifyError, is_power_of_two, random::RandomTape}, }; +use common::ELFInstruction; + const ADDRESS_INCREMENT: usize = 1; #[derive(Debug, Clone, PartialEq)] @@ -52,6 +54,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 + ) + } +} + pub struct FiveTuplePoly { opcode: DensePolynomial, rd: DensePolynomial, @@ -286,9 +302,7 @@ where } } -pub struct PCProof(PhantomData); - -impl MemoryCheckingProver> for PCProof +impl MemoryCheckingProver> for PCPolys where F: PrimeField, G: CurveGroup, @@ -419,7 +433,7 @@ where } } -impl MemoryCheckingVerifier> for PCProof +impl MemoryCheckingVerifier> for PCPolys where F: PrimeField, G: CurveGroup, @@ -679,11 +693,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]; @@ -709,14 +722,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, @@ -725,7 +737,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"); } @@ -744,7 +756,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); @@ -752,16 +763,16 @@ 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, &mut transcript, - &mut random_tape + &mut random_tape, ); let mut transcript = Transcript::new(b"test_transcript"); - PCProof::verify_memory_checking(proof, &commitments, &mut transcript).expect("should verify"); + PCPolys::verify_memory_checking(proof, &commitments, &mut transcript).expect("should verify"); } #[test]