From 0fb8d9e0567662a22b37873f2eb4a2f6436f6173 Mon Sep 17 00:00:00 2001 From: mw2000 Date: Mon, 17 Jun 2024 11:27:22 -0700 Subject: [PATCH 01/43] feat(m-extensions): Adding div and rem We are now adding the m-extension instructions - div and rem to the codebase --- jolt-core/src/jolt/instruction/div.rs | 265 ++++++++++++++++++++++++++ jolt-core/src/jolt/instruction/mod.rs | 2 + jolt-core/src/jolt/instruction/rem.rs | 262 +++++++++++++++++++++++++ 3 files changed, 529 insertions(+) create mode 100644 jolt-core/src/jolt/instruction/div.rs create mode 100644 jolt-core/src/jolt/instruction/rem.rs diff --git a/jolt-core/src/jolt/instruction/div.rs b/jolt-core/src/jolt/instruction/div.rs new file mode 100644 index 000000000..e40555f9b --- /dev/null +++ b/jolt-core/src/jolt/instruction/div.rs @@ -0,0 +1,265 @@ +use common::constants::virtual_register_index; +use tracer::{ELFInstruction, RVTraceRow, RegisterState, RV32IM}; + +use super::VirtualInstructionSequence; +use crate::jolt::instruction::{ + add::ADDInstruction, beq::BEQInstruction, mul::MULInstruction, virtual_advice::ADVICEInstruction, virtual_assert_eq_signs::ASSERTEQSIGNSInstruction, virtual_assert_lt_abs::ASSERTLTABSInstruction, JoltInstruction +}; +/// Perform signed*unsigned multiplication and return the upper WORD_SIZE bits +pub struct DIVInstruction; + +impl VirtualInstructionSequence for DIVInstruction { + fn virtual_sequence(trace_row: RVTraceRow) -> Vec { + assert_eq!(trace_row.instruction.opcode, RV32IM::DIV); + // DIV operands + let x = trace_row.register_state.rs1_val.unwrap(); + let y = trace_row.register_state.rs2_val.unwrap(); + // DIV source registers + let r_x = trace_row.instruction.rs1; + let r_y = trace_row.instruction.rs2; + // Virtual registers used in sequence + let v_0 = Some(virtual_register_index(0)); + let v_r: Option = Some(virtual_register_index(1)); + let v_qy = Some(virtual_register_index(2)); + + let mut virtual_sequence = vec![]; + + let quotient = (x as i64 / y as i64) as u64; + let remainder = (x as i64 - quotient as i64 * y as i64) as u64; + + let q = ADVICEInstruction::(quotient).lookup_entry(); + virtual_sequence.push(RVTraceRow { + instruction: ELFInstruction { + address: trace_row.instruction.address, + opcode: RV32IM::VIRTUAL_ADVICE, + rs1: None, + rs2: None, + rd: trace_row.instruction.rd, + imm: None, + virtual_sequence_index: Some(0), + }, + register_state: RegisterState { + rs1_val: None, + rs2_val: None, + rd_post_val: Some(q), + }, + memory_state: None, + advice_value: Some(quotient), // What should advice value be here? + }); + + let r = ADVICEInstruction::(remainder).lookup_entry(); + virtual_sequence.push(RVTraceRow { + instruction: ELFInstruction { + address: trace_row.instruction.address, + opcode: RV32IM::VIRTUAL_ADVICE, + rs1: None, + rs2: None, + rd: v_r, + imm: None, + virtual_sequence_index: Some(1), + }, + register_state: RegisterState { + rs1_val: None, + rs2_val: None, + rd_post_val: Some(r), + }, + memory_state: None, + advice_value: Some(remainder), // What should advice value be here? + }); + + let _lt_abs: u64 = ASSERTLTABSInstruction::(r, y).lookup_entry(); + virtual_sequence.push(RVTraceRow { + instruction: ELFInstruction { + address: trace_row.instruction.address, + opcode: RV32IM::VIRTUAL_ASSERT_LT_ABS, + rs1: v_r, + rs2: r_y, + rd: None, + imm: None, + virtual_sequence_index: Some(2), + }, + register_state: RegisterState { + rs1_val: Some(r), + rs2_val: Some(y), + rd_post_val: None, + }, + memory_state: None, + advice_value: None, + }); + + let _assert_eq_signs = ASSERTEQSIGNSInstruction(r, y).lookup_entry(); + virtual_sequence.push(RVTraceRow { + instruction: ELFInstruction { + address: trace_row.instruction.address, + opcode: RV32IM::VIRTUAL_ASSERT_EQ_SIGNS, + rs1: v_r, + rs2: r_y, + rd: None, + imm: None, + virtual_sequence_index: Some(3), + }, + register_state: RegisterState { + rs1_val: Some(r), + rs2_val: Some(y), + rd_post_val: None, + }, + memory_state: None, + advice_value: None, + }); + + let q_y = MULInstruction::(q, y).lookup_entry(); + virtual_sequence.push(RVTraceRow { + instruction: ELFInstruction { + address: trace_row.instruction.address, + opcode: RV32IM::MUL, + rs1: trace_row.instruction.rd, + rs2: r_y, + rd: v_qy, + imm: None, + virtual_sequence_index: Some(4), + }, + register_state: RegisterState { + rs1_val: Some(q), + rs2_val: Some(y), + rd_post_val: Some(q_y), + }, + memory_state: None, + advice_value: None, + }); + + let add_0 = ADDInstruction::(q_y, r).lookup_entry(); + virtual_sequence.push(RVTraceRow { + instruction: ELFInstruction { + address: trace_row.instruction.address, + opcode: RV32IM::ADD, + rs1: v_qy, + rs2: v_r, + rd: v_0, + imm: None, + virtual_sequence_index: Some(5), + }, + register_state: RegisterState { + rs1_val: Some(q_y), + rs2_val: Some(r), + rd_post_val: Some(add_0), + }, + memory_state: None, + advice_value: None, + }); + + let _assert_eq = BEQInstruction(add_0, x).lookup_entry(); + virtual_sequence.push(RVTraceRow { + instruction: ELFInstruction { + address: trace_row.instruction.address, + opcode: RV32IM::VIRTUAL_ASSERT_EQ, + rs1: v_0, + rs2: r_x, + rd: None, + imm: None, + virtual_sequence_index: Some(6), + }, + register_state: RegisterState { + rs1_val: Some(add_0), + rs2_val: Some(x), + rd_post_val: None, + }, + memory_state: None, + advice_value: None, + }); + + virtual_sequence + } +} + +#[cfg(test)] +mod test { + use ark_std::test_rng; + use common::constants::REGISTER_COUNT; + use rand_chacha::rand_core::RngCore; + + use crate::jolt::vm::rv32i_vm::RV32I; + + use super::*; + + #[test] + // TODO(moodlezoup): Turn this into a macro, similar to the `jolt_instruction_test` macro + fn div_virtual_sequence_32() { + let mut rng = test_rng(); + + let r_x = rng.next_u64() % 32; + let r_y = rng.next_u64() % 32; + let rd = rng.next_u64() % 32; + + let x = rng.next_u32() as u64; + let y = if r_y == r_x { x } else { rng.next_u32() as u64 }; + let result = (x as i64 / y as i64) as u64; + + let div_trace_row = RVTraceRow { + instruction: ELFInstruction { + address: rng.next_u64(), + opcode: RV32IM::DIV, + rs1: Some(r_x), + rs2: Some(r_y), + rd: Some(rd), + imm: None, + virtual_sequence_index: None, + }, + register_state: RegisterState { + rs1_val: Some(x), + rs2_val: Some(y), + rd_post_val: Some(result as u64), + }, + memory_state: None, + advice_value: None, + }; + + let virtual_sequence = DIVInstruction::<32>::virtual_sequence(div_trace_row); + let mut registers = vec![0u64; REGISTER_COUNT as usize]; + registers[r_x as usize] = x; + registers[r_y as usize] = y; + + for row in virtual_sequence { + if let Some(rs1_val) = row.register_state.rs1_val { + assert_eq!(registers[row.instruction.rs1.unwrap() as usize], rs1_val); + } + if let Some(rs2_val) = row.register_state.rs2_val { + assert_eq!(registers[row.instruction.rs2.unwrap() as usize], rs2_val); + } + + println!( + "rs1 {} rs2 {} instruction {:?}", + row.register_state.rs1_val.unwrap_or(0), + row.register_state.rs2_val.unwrap_or(0), + row.instruction + ); + + let lookup = RV32I::try_from(&row).unwrap(); + let output = lookup.lookup_entry(); + if let Some(rd) = row.instruction.rd { + registers[rd as usize] = output; + assert_eq!( + registers[rd as usize], + row.register_state.rd_post_val.unwrap() + ); + } else { + assert!(output == 1) + } + } + + for (index, val) in registers.iter().enumerate() { + if index as u64 == r_x { + // Check that r_x hasn't been clobbered + assert_eq!(*val, x); + } else if index as u64 == r_y { + // Check that r_y hasn't been clobbered + assert_eq!(*val, y); + } else if index as u64 == rd { + // Check that result was written to rd + assert_eq!(*val, result as u64); + } else if index < 32 { + // None of the other "real" registers were touched + assert_eq!(*val, 0); + } + } + } +} diff --git a/jolt-core/src/jolt/instruction/mod.rs b/jolt-core/src/jolt/instruction/mod.rs index 0b6c42eb8..32e1e1876 100644 --- a/jolt-core/src/jolt/instruction/mod.rs +++ b/jolt-core/src/jolt/instruction/mod.rs @@ -133,6 +133,7 @@ pub mod beq; pub mod bge; pub mod bgeu; pub mod bne; +pub mod div; pub mod divu; pub mod lb; pub mod lh; @@ -143,6 +144,7 @@ pub mod mulhsu; pub mod mulhu; pub mod mulu; pub mod or; +pub mod rem; pub mod remu; pub mod sb; pub mod sh; diff --git a/jolt-core/src/jolt/instruction/rem.rs b/jolt-core/src/jolt/instruction/rem.rs new file mode 100644 index 000000000..10d9049e3 --- /dev/null +++ b/jolt-core/src/jolt/instruction/rem.rs @@ -0,0 +1,262 @@ +use common::constants::virtual_register_index; +use tracer::{ELFInstruction, RVTraceRow, RegisterState, RV32IM}; + +use super::VirtualInstructionSequence; +use crate::jolt::instruction::{ + add::ADDInstruction, beq::BEQInstruction, mul::MULInstruction, virtual_advice::ADVICEInstruction, virtual_assert_eq_signs::ASSERTEQSIGNSInstruction, virtual_assert_lt_abs::ASSERTLTABSInstruction, JoltInstruction +}; + +/// Perform signed*unsigned multiplication and return the upper WORD_SIZE bits +pub struct REMInstruction; + +impl VirtualInstructionSequence for REMInstruction { + fn virtual_sequence(trace_row: RVTraceRow) -> Vec { + assert_eq!(trace_row.instruction.opcode, RV32IM::REM); + // REM operands + let x = trace_row.register_state.rs1_val.unwrap(); + let y = trace_row.register_state.rs2_val.unwrap(); + // REM source registers + let r_x = trace_row.instruction.rs1; + let r_y = trace_row.instruction.rs2; + // Virtual registers used in sequence + let v_0 = Some(virtual_register_index(0)); + let v_q = Some(virtual_register_index(1)); + let v_qy = Some(virtual_register_index(2)); + + let mut virtual_sequence = vec![]; + + let quotient = x / y; + let remainder = x - quotient * y; + + let q = ADVICEInstruction::(quotient).lookup_entry(); + virtual_sequence.push(RVTraceRow { + instruction: ELFInstruction { + address: trace_row.instruction.address, + opcode: RV32IM::VIRTUAL_ADVICE, + rs1: None, + rs2: None, + rd: v_q, + imm: None, + virtual_sequence_index: Some(0), + }, + register_state: RegisterState { + rs1_val: None, + rs2_val: None, + rd_post_val: Some(q), + }, + memory_state: None, + advice_value: Some(quotient), + }); + + let r = ADVICEInstruction::(remainder).lookup_entry(); + virtual_sequence.push(RVTraceRow { + instruction: ELFInstruction { + address: trace_row.instruction.address, + opcode: RV32IM::VIRTUAL_ADVICE, + rs1: None, + rs2: None, + rd: trace_row.instruction.rd, + imm: None, + virtual_sequence_index: Some(1), + }, + register_state: RegisterState { + rs1_val: None, + rs2_val: None, + rd_post_val: Some(r), + }, + memory_state: None, + advice_value: Some(remainder), + }); + + let _lt_abs = ASSERTLTABSInstruction::(r, y).lookup_entry(); + virtual_sequence.push(RVTraceRow { + instruction: ELFInstruction { + address: trace_row.instruction.address, + opcode: RV32IM::VIRTUAL_ASSERT_LT_ABS, + rs1: trace_row.instruction.rd, + rs2: r_y, + rd: None, + imm: None, + virtual_sequence_index: Some(2), + }, + register_state: RegisterState { + rs1_val: Some(r), + rs2_val: Some(y), + rd_post_val: None, + }, + memory_state: None, + advice_value: None, + }); + + let _assert_eq_signs = ASSERTEQSIGNSInstruction(r, y).lookup_entry(); + virtual_sequence.push(RVTraceRow { + instruction: ELFInstruction { + address: trace_row.instruction.address, + opcode: RV32IM::VIRTUAL_ASSERT_EQ_SIGNS, + rs1: trace_row.instruction.rd, + rs2: r_y, + rd: None, + imm: None, + virtual_sequence_index: Some(3), + }, + register_state: RegisterState { + rs1_val: Some(r), + rs2_val: Some(y), + rd_post_val: None, + }, + memory_state: None, + advice_value: None, + }); + + let q_y = MULInstruction::(q, y).lookup_entry(); + virtual_sequence.push(RVTraceRow { + instruction: ELFInstruction { + address: trace_row.instruction.address, + opcode: RV32IM::MUL, + rs1: v_q, + rs2: r_y, + rd: v_qy, + imm: None, + virtual_sequence_index: Some(4), + }, + register_state: RegisterState { + rs1_val: Some(q), + rs2_val: Some(y), + rd_post_val: Some(q_y), + }, + memory_state: None, + advice_value: None, + }); + + let add_0: u64 = ADDInstruction::(q_y, r).lookup_entry(); + virtual_sequence.push(RVTraceRow { + instruction: ELFInstruction { + address: trace_row.instruction.address, + opcode: RV32IM::ADD, + rs1: v_qy, + rs2: trace_row.instruction.rd, + rd: v_0, + imm: None, + virtual_sequence_index: Some(5), + }, + register_state: RegisterState { + rs1_val: Some(q_y), + rs2_val: Some(r), + rd_post_val: Some(add_0), + }, + memory_state: None, + advice_value: None, + }); + + let _assert_eq = BEQInstruction(add_0, x).lookup_entry(); + virtual_sequence.push(RVTraceRow { + instruction: ELFInstruction { + address: trace_row.instruction.address, + opcode: RV32IM::VIRTUAL_ASSERT_EQ, + rs1: v_0, + rs2: r_x, + rd: None, + imm: None, + virtual_sequence_index: Some(6), + }, + register_state: RegisterState { + rs1_val: Some(add_0), + rs2_val: Some(x), + rd_post_val: None, + }, + memory_state: None, + advice_value: None, + }); + + virtual_sequence + } +} + +#[cfg(test)] +mod test { + use ark_std::test_rng; + use common::constants::REGISTER_COUNT; + use rand_chacha::rand_core::RngCore; + + use crate::jolt::vm::rv32i_vm::RV32I; + + use super::*; + + #[test] + // TODO(moodlezoup): Turn this into a macro, similar to the `jolt_instruction_test` macro + fn rem_virtual_sequence_32() { + let mut rng = test_rng(); + + let r_x = rng.next_u64() % 32; + let r_y = rng.next_u64() % 32; + let rd = rng.next_u64() % 32; + + let x = rng.next_u32() as u64; + let y = if r_x == r_y { x } else { rng.next_u32() as u64 }; + let quotient = x / y; + let result = x - quotient * y; + + let rem_trace_row = RVTraceRow { + instruction: ELFInstruction { + address: rng.next_u64(), + opcode: RV32IM::REM, + rs1: Some(r_x), + rs2: Some(r_y), + rd: Some(rd), + imm: None, + virtual_sequence_index: None, + }, + register_state: RegisterState { + rs1_val: Some(x), + rs2_val: Some(y), + rd_post_val: Some(result as u64), + }, + memory_state: None, + advice_value: None, + }; + + let virtual_sequence = REMInstruction::<32>::virtual_sequence(rem_trace_row); + let mut registers = vec![0u64; REGISTER_COUNT as usize]; + registers[r_x as usize] = x; + registers[r_y as usize] = y; + + for row in virtual_sequence { + println!("{:?}", row.instruction); + if let Some(rs1_val) = row.register_state.rs1_val { + assert_eq!(registers[row.instruction.rs1.unwrap() as usize], rs1_val); + } + if let Some(rs2_val) = row.register_state.rs2_val { + assert_eq!(registers[row.instruction.rs2.unwrap() as usize], rs2_val); + } + + let lookup = RV32I::try_from(&row).unwrap(); + let output = lookup.lookup_entry(); + if let Some(rd) = row.instruction.rd { + registers[rd as usize] = output; + assert_eq!( + registers[rd as usize], + row.register_state.rd_post_val.unwrap() + ); + } else { + // Virtual assert instruction + // assert!(output == 1); + } + } + + for (index, val) in registers.iter().enumerate() { + if index as u64 == r_x { + // Check that r_x hasn't been clobbered + assert_eq!(*val, x); + } else if index as u64 == r_y { + // Check that r_y hasn't been clobbered + assert_eq!(*val, y); + } else if index as u64 == rd { + // Check that result was written to rd + assert_eq!(*val, result as u64); + } else if index < 32 { + // None of the other "real" registers were touched + assert_eq!(*val, 0); + } + } + } +} From c12b53843b4ead80c549dde1ffae2dbec9a8d604 Mon Sep 17 00:00:00 2001 From: mw2000 Date: Mon, 17 Jun 2024 17:15:41 -0700 Subject: [PATCH 02/43] chore: fixing cargo fmt --- jolt-core/src/jolt/instruction/div.rs | 4 +++- jolt-core/src/jolt/instruction/rem.rs | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/jolt-core/src/jolt/instruction/div.rs b/jolt-core/src/jolt/instruction/div.rs index e40555f9b..6acac272f 100644 --- a/jolt-core/src/jolt/instruction/div.rs +++ b/jolt-core/src/jolt/instruction/div.rs @@ -3,7 +3,9 @@ use tracer::{ELFInstruction, RVTraceRow, RegisterState, RV32IM}; use super::VirtualInstructionSequence; use crate::jolt::instruction::{ - add::ADDInstruction, beq::BEQInstruction, mul::MULInstruction, virtual_advice::ADVICEInstruction, virtual_assert_eq_signs::ASSERTEQSIGNSInstruction, virtual_assert_lt_abs::ASSERTLTABSInstruction, JoltInstruction + add::ADDInstruction, beq::BEQInstruction, mul::MULInstruction, + virtual_advice::ADVICEInstruction, virtual_assert_eq_signs::ASSERTEQSIGNSInstruction, + virtual_assert_lt_abs::ASSERTLTABSInstruction, JoltInstruction, }; /// Perform signed*unsigned multiplication and return the upper WORD_SIZE bits pub struct DIVInstruction; diff --git a/jolt-core/src/jolt/instruction/rem.rs b/jolt-core/src/jolt/instruction/rem.rs index 10d9049e3..35b954af9 100644 --- a/jolt-core/src/jolt/instruction/rem.rs +++ b/jolt-core/src/jolt/instruction/rem.rs @@ -3,7 +3,9 @@ use tracer::{ELFInstruction, RVTraceRow, RegisterState, RV32IM}; use super::VirtualInstructionSequence; use crate::jolt::instruction::{ - add::ADDInstruction, beq::BEQInstruction, mul::MULInstruction, virtual_advice::ADVICEInstruction, virtual_assert_eq_signs::ASSERTEQSIGNSInstruction, virtual_assert_lt_abs::ASSERTLTABSInstruction, JoltInstruction + add::ADDInstruction, beq::BEQInstruction, mul::MULInstruction, + virtual_advice::ADVICEInstruction, virtual_assert_eq_signs::ASSERTEQSIGNSInstruction, + virtual_assert_lt_abs::ASSERTLTABSInstruction, JoltInstruction, }; /// Perform signed*unsigned multiplication and return the upper WORD_SIZE bits From 2e13acdb1b1e6a5ccdf7a87749447a6283da57a3 Mon Sep 17 00:00:00 2001 From: sragss Date: Fri, 21 Jun 2024 19:30:35 -0700 Subject: [PATCH 03/43] init working sparsity --- jolt-core/src/jolt/vm/mod.rs | 6 +- jolt-core/src/poly/dense_mlpoly.rs | 14 +- jolt-core/src/r1cs/builder.rs | 127 +++++- jolt-core/src/r1cs/spartan.rs | 148 ++----- jolt-core/src/r1cs/special_polys.rs | 553 ++++++++++++++++++++++++- jolt-core/src/subprotocols/sumcheck.rs | 116 +++--- 6 files changed, 778 insertions(+), 186 deletions(-) diff --git a/jolt-core/src/jolt/vm/mod.rs b/jolt-core/src/jolt/vm/mod.rs index fb3b5e55d..06f63c004 100644 --- a/jolt-core/src/jolt/vm/mod.rs +++ b/jolt-core/src/jolt/vm/mod.rs @@ -4,6 +4,7 @@ use crate::field::JoltField; use crate::r1cs::builder::CombinedUniformBuilder; use crate::r1cs::jolt_constraints::{construct_jolt_constraints, JoltIn}; use crate::r1cs::spartan::{self, UniformSpartanProof}; +use crate::utils::profiling; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use ark_std::log2; use common::constants::RAM_START_ADDRESS; @@ -402,8 +403,10 @@ pub trait Jolt, const C: usize, c &mut transcript, ); - drop_in_background_thread(jolt_polynomials); + // drop_in_background_thread(jolt_polynomials); + drop(jolt_polynomials); + profiling::print_current_memory_usage("pre_spartan"); let spartan_proof = UniformSpartanProof::::prove_precommitted( &preprocessing.generators, r1cs_builder, @@ -412,6 +415,7 @@ pub trait Jolt, const C: usize, c &mut transcript, ) .expect("r1cs proof failed"); + profiling::print_current_memory_usage("post_spartan"); let r1cs_proof = R1CSProof { key: spartan_key, proof: spartan_proof, diff --git a/jolt-core/src/poly/dense_mlpoly.rs b/jolt-core/src/poly/dense_mlpoly.rs index 992b7fe69..6eb701531 100644 --- a/jolt-core/src/poly/dense_mlpoly.rs +++ b/jolt-core/src/poly/dense_mlpoly.rs @@ -1,6 +1,6 @@ #![allow(clippy::too_many_arguments)] use crate::poly::eq_poly::EqPolynomial; -use crate::utils::thread::unsafe_allocate_zero_vec; +use crate::utils::thread::{drop_in_background_thread, unsafe_allocate_zero_vec}; use crate::utils::{self, compute_dotproduct, compute_dotproduct_low_optimized}; use crate::field::JoltField; @@ -201,11 +201,17 @@ impl DensePolynomial { } } + #[tracing::instrument(skip_all)] pub fn bound_poly_var_bot(&mut self, r: &F) { let n = self.len() / 2; - for i in 0..n { - self.Z[i] = self.Z[2 * i] + *r * (self.Z[2 * i + 1] - self.Z[2 * i]); - } + let mut new_z = unsafe_allocate_zero_vec(n); + new_z.par_iter_mut().enumerate().for_each(|(i, z)| { + *z = self.Z[2*i] + *r * (self.Z[2 * i + 1] - self.Z[2 * i]); + }); + + let old_Z = std::mem::replace(&mut self.Z, new_z); + drop_in_background_thread(old_Z); + self.num_vars -= 1; self.len = n; } diff --git a/jolt-core/src/r1cs/builder.rs b/jolt-core/src/r1cs/builder.rs index d0c1c409e..e16bd7f7f 100644 --- a/jolt-core/src/r1cs/builder.rs +++ b/jolt-core/src/r1cs/builder.rs @@ -2,8 +2,7 @@ use crate::{ field::{JoltField, OptimizedMul}, r1cs::key::{SparseConstraints, UniformR1CS}, utils::{ - mul_0_1_optimized, - thread::{drop_in_background_thread, unsafe_allocate_zero_vec}, + math::Math, mul_0_1_optimized, thread::{drop_in_background_thread, unsafe_allocate_zero_vec} }, }; #[allow(unused_imports)] // clippy thinks these aren't needed lol @@ -13,7 +12,7 @@ use std::{collections::HashMap, fmt::Debug}; use super::{ key::{NonUniformR1CS, SparseEqualityItem}, - ops::{ConstraintInput, Term, Variable, LC}, + ops::{ConstraintInput, Term, Variable, LC}, special_polys::SparsePolynomial, }; pub trait R1CSConstraintBuilder { @@ -848,13 +847,127 @@ impl CombinedUniformBuilder { (Az, Bz, Cz) } + /// inputs should be of the format [[I::0, I::0, ...], [I::1, I::1, ...], ... [I::N, I::N]] + /// aux should be of the format [[Aux(0), Aux(0), ...], ... [Aux(self.next_aux - 1), ...]] + #[tracing::instrument(skip_all, name = "CombinedUniformBuilder::compute_spartan")] + pub fn compute_spartan_Az_Bz_Cz_sparse( + &self, + inputs: &[Vec], + aux: &[Vec], + ) -> (SparsePolynomial, SparsePolynomial, SparsePolynomial) { + assert_eq!(inputs.len(), I::COUNT); + let num_aux = self.uniform_builder.num_aux(); + assert_eq!(aux.len(), num_aux); + assert!(inputs + .iter() + .chain(aux.iter()) + .all(|inner_input| inner_input.len() == self.uniform_repeat)); + + let uniform_constraint_rows = self.uniform_repeat_constraint_rows(); + // TODO(sragss): Allocation can overshoot by up to a factor of 2, Spartan could handle non-pow-2 Az,Bz,Cz + let constraint_rows = self.constraint_rows(); + let (mut Az, mut Bz, mut Cz) = ( + unsafe_allocate_zero_vec(constraint_rows), + unsafe_allocate_zero_vec(constraint_rows), + unsafe_allocate_zero_vec(constraint_rows), + ); + + let batch_inputs = |lc: &LC| batch_inputs(lc, inputs, aux); + + // uniform_constraints: Xz[0..uniform_constraint_rows] + // TODO(sragss): Attempt moving onto key and computing from materialized rows rather than linear combos + let span = tracing::span!(tracing::Level::DEBUG, "compute_constraints"); + let enter = span.enter(); + let az_chunks = Az.par_chunks_mut(self.uniform_repeat); + let bz_chunks = Bz.par_chunks_mut(self.uniform_repeat); + let cz_chunks = Cz.par_chunks_mut(self.uniform_repeat); + + self.uniform_builder + .constraints + .par_iter() + .zip(az_chunks.zip(bz_chunks.zip(cz_chunks))) + .for_each(|(constraint, (az_chunk, (bz_chunk, cz_chunk)))| { + let a_inputs = batch_inputs(&constraint.a); + let b_inputs = batch_inputs(&constraint.b); + let c_inputs = batch_inputs(&constraint.c); + + constraint.a.evaluate_batch_mut(&a_inputs, az_chunk); + constraint.b.evaluate_batch_mut(&b_inputs, bz_chunk); + constraint.c.evaluate_batch_mut(&c_inputs, cz_chunk); + }); + drop(enter); + + // offset_equality_constraints: Xz[uniform_constraint_rows..uniform_constraint_rows + 1] + // (a - b) * condition == 0 + // For the final step we will not compute the offset terms, and will assume the condition to be set to 0 + let span = tracing::span!(tracing::Level::DEBUG, "offset_eq"); + let _enter = span.enter(); + + let constr = &self.offset_equality_constraint; + let condition_evals = constr + .cond + .1 + .evaluate_batch(&batch_inputs(&constr.cond.1), self.uniform_repeat); + let eq_a_evals = constr + .a + .1 + .evaluate_batch(&batch_inputs(&constr.a.1), self.uniform_repeat); + let eq_b_evals = constr + .b + .1 + .evaluate_batch(&batch_inputs(&constr.b.1), self.uniform_repeat); + + let Az_off = Az[uniform_constraint_rows..uniform_constraint_rows + self.uniform_repeat] + .par_iter_mut(); + let Bz_off = Bz[uniform_constraint_rows..uniform_constraint_rows + self.uniform_repeat] + .par_iter_mut(); + + (0..self.uniform_repeat) + .into_par_iter() + .zip(Az_off.zip(Bz_off)) + .for_each(|(step_index, (az, bz))| { + // Write corresponding values, if outside the step range, only include the constant. + let a_step = step_index + if constr.a.0 { 1 } else { 0 }; + let b_step = step_index + if constr.b.0 { 1 } else { 0 }; + let a = eq_a_evals + .get(a_step) + .cloned() + .unwrap_or(constr.a.1.constant_term_field()); + let b = eq_b_evals + .get(b_step) + .cloned() + .unwrap_or(constr.b.1.constant_term_field()); + *az = a - b; + + let condition_step = step_index + if constr.cond.0 { 1 } else { 0 }; + *bz = condition_evals + .get(condition_step) + .cloned() + .unwrap_or(constr.cond.1.constant_term_field()); + }); + drop(_enter); + + #[cfg(test)] + self.assert_valid(&Az, &Bz, &Cz); + + let num_vars = self.constraint_rows().next_power_of_two().log_2(); + let (az_poly, (bz_poly, cz_poly)) = rayon::join( + || SparsePolynomial::from_dense_evals(num_vars, Az), + || rayon::join( + || SparsePolynomial::from_dense_evals(num_vars, Bz), + || SparsePolynomial::from_dense_evals(num_vars, Cz) + ) + ); + + (az_poly, bz_poly, cz_poly) + } + + #[cfg(test)] pub fn assert_valid(&self, az: &[F], bz: &[F], cz: &[F]) { let rows = az.len(); - let expected_rows = self.constraint_rows().next_power_of_two(); - assert_eq!(az.len(), expected_rows); - assert_eq!(bz.len(), expected_rows); - assert_eq!(cz.len(), expected_rows); + assert_eq!(bz.len(), rows); + assert_eq!(cz.len(), rows); for constraint_index in 0..rows { if az[constraint_index] * bz[constraint_index] != cz[constraint_index] { let uniform_constraint_index = constraint_index / self.uniform_repeat; diff --git a/jolt-core/src/r1cs/spartan.rs b/jolt-core/src/r1cs/spartan.rs index 6a19d6a41..256ab9b14 100644 --- a/jolt-core/src/r1cs/spartan.rs +++ b/jolt-core/src/r1cs/spartan.rs @@ -4,8 +4,9 @@ use crate::field::JoltField; use crate::poly::commitment::commitment_scheme::BatchType; use crate::poly::commitment::commitment_scheme::CommitmentScheme; use crate::r1cs::key::UniformSpartanKey; -use crate::utils::compute_dotproduct_low_optimized; +use crate::r1cs::special_polys::SegmentedPaddedWitness; use crate::utils::math::Math; +use crate::utils::profiling; use crate::utils::thread::drop_in_background_thread; use crate::utils::transcript::ProofTranscript; @@ -58,87 +59,6 @@ pub enum SpartanError { InvalidPCSProof, } -// TODO: Rather than use these adhoc virtual indexable polys – create a DensePolynomial which takes any impl Index inner -// and can run all the normal DensePolynomial ops. -#[derive(Clone)] -pub struct SegmentedPaddedWitness { - total_len: usize, - segments: Vec>, - segment_len: usize, - zero: F, -} - -impl SegmentedPaddedWitness { - pub fn new(total_len: usize, segments: Vec>) -> Self { - let segment_len = segments[0].len(); - assert!(segment_len.is_power_of_two()); - for segment in &segments { - assert_eq!( - segment.len(), - segment_len, - "All segments must be the same length" - ); - } - SegmentedPaddedWitness { - total_len, - segments, - segment_len, - zero: F::zero(), - } - } - - pub fn len(&self) -> usize { - self.total_len - } - - #[tracing::instrument(skip_all, name = "SegmentedPaddedWitness::evaluate_all")] - pub fn evaluate_all(&self, point: Vec) -> Vec { - let chi = EqPolynomial::evals(&point); - assert!(chi.len() >= self.segment_len); - - let evals = self - .segments - .par_iter() - .map(|segment| compute_dotproduct_low_optimized(&chi[0..self.segment_len], segment)) - .collect(); - drop_in_background_thread(chi); - evals - } - - pub fn into_dense_polys(self) -> Vec> { - self.segments - .into_iter() - .map(|poly| DensePolynomial::new(poly)) - .collect() - } -} - -impl std::ops::Index for SegmentedPaddedWitness { - type Output = F; - - fn index(&self, index: usize) -> &Self::Output { - if index >= self.segments.len() * self.segment_len { - &self.zero - } else if index >= self.total_len { - panic!("index too high"); - } else { - let segment_index = index / self.segment_len; - let inner_index = index % self.segment_len; - &self.segments[segment_index][inner_index] - } - } -} - -impl IndexablePoly for SegmentedPaddedWitness { - fn len(&self) -> usize { - self.total_len - } -} - -pub trait IndexablePoly: std::ops::Index + Sync { - fn len(&self) -> usize; -} - /// A succinct proof of knowledge of a witness to a relaxed R1CS instance /// The proof is produced using Spartan's combination of the sum-check and /// the commitment to a vector viewed as a polynomial commitment @@ -188,38 +108,15 @@ impl> UniformSpartanProof { let tau = (0..num_rounds_x) .map(|_i| transcript.challenge_scalar(b"t")) .collect::>(); + profiling::print_current_memory_usage("pre_poly_tau"); let mut poly_tau = DensePolynomial::new(EqPolynomial::evals(&tau)); + profiling::print_current_memory_usage("post_poly_tau"); let inputs = &segmented_padded_witness.segments[0..I::COUNT]; let aux = &segmented_padded_witness.segments[I::COUNT..]; - let (az, bz, cz) = constraint_builder.compute_spartan_Az_Bz_Cz(inputs, aux); - // TODO: Do not require these padded, Sumcheck should handle sparsity. - assert!(az.len().is_power_of_two()); - assert!(bz.len().is_power_of_two()); - assert!(cz.len().is_power_of_two()); - - let mut poly_Az = DensePolynomial::new(az); - let mut poly_Bz = DensePolynomial::new(bz); - let mut poly_Cz = DensePolynomial::new(cz); - - #[cfg(test)] - { - // Check that Z is a satisfying assignment - for (i, ((az, bz), cz)) in poly_Az - .evals_ref() - .iter() - .zip(poly_Bz.evals_ref()) - .zip(poly_Cz.evals_ref()) - .enumerate() - { - if *az * *bz != *cz { - let padded_segment_len = segmented_padded_witness.segment_len; - let error_segment_index = i / padded_segment_len; - let error_step_index = i % padded_segment_len; - panic!("witness is not a satisfying assignment. Failed on segment {error_segment_index} at step {error_step_index}"); - } - } - } + profiling::print_current_memory_usage("pre_az_bz_cz"); + let (mut az, mut bz, mut cz) = constraint_builder.compute_spartan_Az_Bz_Cz_sparse(inputs, aux); + profiling::print_current_memory_usage("post_az_bz_cz"); let comb_func_outer = |A: &F, B: &F, C: &F, D: &F| -> F { // Below is an optimized form of: *A * (*B * *C - *D) @@ -230,25 +127,32 @@ impl> UniformSpartanProof { *A * (-(*D)) } } else { - *A * (*B * *C - *D) + let inner = *B * *C - *D; + if inner.is_zero() { + F::zero() + } else { + *A * inner + } } }; + // profiling::start_memory_tracing_span("outersumcheck"); + profiling::print_current_memory_usage("pre_outersumcheck"); let (outer_sumcheck_proof, outer_sumcheck_r, outer_sumcheck_claims) = SumcheckInstanceProof::prove_spartan_cubic::<_>( &F::zero(), // claim is zero num_rounds_x, &mut poly_tau, - &mut poly_Az, - &mut poly_Bz, - &mut poly_Cz, + &mut az, + &mut bz, + &mut cz, comb_func_outer, transcript, ); - drop_in_background_thread(poly_Az); - drop_in_background_thread(poly_Bz); - drop_in_background_thread(poly_Cz); - drop_in_background_thread(poly_tau); + let outer_sumcheck_r: Vec = outer_sumcheck_r.into_iter().rev().collect(); + // drop_in_background_thread((poly_Az, poly_Bz, poly_Cz, poly_tau)); + drop((az, bz, cz, poly_tau)); + profiling::print_current_memory_usage("post_outersumcheck"); // claims from the end of sum-check // claim_Az is the (scalar) value v_A = \sum_y A(r_x, y) * z(r_x) where r_x is the sumcheck randomness @@ -276,8 +180,10 @@ impl> UniformSpartanProof { .ilog2(); let (rx_con, rx_ts) = outer_sumcheck_r.split_at(outer_sumcheck_r.len() - num_steps_bits as usize); + profiling::print_current_memory_usage("pre_poly_ABC"); let mut poly_ABC = DensePolynomial::new(key.evaluate_r1cs_mle_rlc(rx_con, rx_ts, r_inner_sumcheck_RLC)); + profiling::print_current_memory_usage("post_poly_ABC"); let (inner_sumcheck_proof, inner_sumcheck_r, _claims_inner) = SumcheckInstanceProof::prove_spartan_quadratic::>( @@ -287,7 +193,8 @@ impl> UniformSpartanProof { &segmented_padded_witness, transcript, ); - drop_in_background_thread(poly_ABC); + // drop_in_background_thread(poly_ABC); + drop(poly_ABC); // Requires 'r_col_segment_bits' to index the (const, segment). Within that segment we index the step using 'r_col_step' let r_col_segment_bits = key.uniform_r1cs.num_vars.next_power_of_two().log_2() + 1; @@ -346,6 +253,9 @@ impl> UniformSpartanProof { .verify(F::zero(), num_rounds_x, 3, transcript) .map_err(|_| SpartanError::InvalidOuterSumcheckProof)?; + // Outer sumcheck is bound from the top, reverse the fiat shamir randomness + let r_x: Vec = r_x.into_iter().rev().collect(); + // verify claim_outer_final let (claim_Az, claim_Bz, claim_Cz) = self.outer_sumcheck_claims; let taus_bound_rx = EqPolynomial::new(tau).evaluate(&r_x); diff --git a/jolt-core/src/r1cs/special_polys.rs b/jolt-core/src/r1cs/special_polys.rs index 54dacc491..64371a447 100644 --- a/jolt-core/src/r1cs/special_polys.rs +++ b/jolt-core/src/r1cs/special_polys.rs @@ -1,33 +1,50 @@ -use crate::field::JoltField; +use crate::{field::JoltField, poly::{dense_mlpoly::DensePolynomial, eq_poly::EqPolynomial}, utils::{compute_dotproduct_low_optimized, math::Math, thread::{drop_in_background_thread, unsafe_allocate_zero_vec}}}; +use num_integer::Integer; use rayon::prelude::*; +#[derive(Clone)] pub struct SparsePolynomial { num_vars: usize, + Z: Vec<(usize, F)>, } -impl SparsePolynomial { - pub fn new(num_vars: usize, Z: Vec<(usize, Scalar)>) -> Self { +impl SparsePolynomial { + pub fn new(num_vars: usize, Z: Vec<(usize, F)>) -> Self { SparsePolynomial { num_vars, Z } } + // TODO(sragss): rm + #[tracing::instrument(skip_all)] + pub fn from_dense_evals(num_vars: usize, evals: Vec) -> Self { + assert!(num_vars.pow2() >= evals.len()); + let non_zero_count: usize = evals.par_iter().filter(|f| !f.is_zero()).count(); + let mut sparse: Vec<(usize, F)> = Vec::with_capacity(non_zero_count); + evals.into_iter().enumerate().for_each(|(dense_index, f)| { + if !f.is_zero() { + sparse.push((dense_index, f)); + } + }); + Self::new(num_vars, sparse) + } + /// Computes the $\tilde{eq}$ extension polynomial. /// return 1 when a == r, otherwise return 0. - fn compute_chi(a: &[bool], r: &[Scalar]) -> Scalar { + fn compute_chi(a: &[bool], r: &[F]) -> F { assert_eq!(a.len(), r.len()); - let mut chi_i = Scalar::one(); + let mut chi_i = F::one(); for j in 0..r.len() { if a[j] { chi_i *= r[j]; } else { - chi_i *= Scalar::one() - r[j]; + chi_i *= F::one() - r[j]; } } chi_i } // Takes O(n log n) - pub fn evaluate(&self, r: &[Scalar]) -> Scalar { + pub fn evaluate(&self, r: &[F]) -> F { assert_eq!(self.num_vars, r.len()); (0..self.Z.len()) @@ -38,6 +55,400 @@ impl SparsePolynomial { }) .sum() } + + /// Returns n chunks of roughly even size without orphaning siblings (adjacent dense indices). Additionally returns a vector of (low, high] dense index ranges. + fn chunk_no_orphans(&self, n: usize) -> (Vec<&[(usize, F)]>, Vec<(usize, usize)>) { + if self.Z.len() < n * 2 { + return (vec![(&self.Z)], vec![(0, self.num_vars.pow2())]); + } + + let target_chunk_size = self.Z.len() / n; + let mut chunks: Vec<&[(usize, F)]> = Vec::with_capacity(n); + let mut dense_ranges: Vec<(usize, usize)> = Vec::with_capacity(n); + let mut dense_start_index = 0; + let mut sparse_start_index = 0; + let mut sparse_end_index = target_chunk_size; + for _ in 1..n { + let mut dense_end_index = self.Z[sparse_end_index].0; + if dense_end_index % 2 != 0 { + dense_end_index += 1; + sparse_end_index += 1; + } + chunks.push(&self.Z[sparse_start_index..sparse_end_index]); + dense_ranges.push((dense_start_index, dense_end_index)); + dense_start_index = dense_end_index; + + sparse_start_index = sparse_end_index; + sparse_end_index = std::cmp::min(sparse_end_index + target_chunk_size, self.Z.len() - 1); + } + chunks.push(&self.Z[sparse_start_index..]); + // TODO(sragss): likely makes more sense to return full range then truncate when needed (triple iterator) + let highest_non_zero = self.Z.last().map(|&(index, _)| index).unwrap(); + dense_ranges.push((dense_start_index, highest_non_zero + 1)); + assert_eq!(chunks.len(), n); + assert_eq!(dense_ranges.len(), n); + + // TODO(sragss): To use chunk_no_orphans in the triple iterator, we have to overwrite the top of the dense_ranges. + + (chunks, dense_ranges) + } + + #[tracing::instrument(skip_all)] + pub fn bound_poly_var_bot(&mut self, r: &F) { + // TODO(sragss): Do this with a scan instead. + let n = self.Z.len(); + let span = tracing::span!(tracing::Level::DEBUG, "allocate"); + let _enter = span.enter(); + let mut new_Z: Vec<(usize, F)> = Vec::with_capacity(n); + drop(_enter); + for (sparse_index, (dense_index, value)) in self.Z.iter().enumerate() { + if dense_index.is_even() { + let new_dense_index = dense_index / 2; + // TODO(sragss): Can likely combine these conditions for better speculative execution. + if self.Z.len() >= 2 && sparse_index <= self.Z.len() - 2 && self.Z[sparse_index + 1].0 == dense_index + 1 { + let upper = self.Z[sparse_index + 1].1; + let eval = *value + *r * (upper - value); + new_Z.push((new_dense_index, eval)); + } else { + new_Z.push((new_dense_index, (F::one() - r) * value)); + } + } else { + if sparse_index > 0 && self.Z[sparse_index - 1].0 == dense_index - 1 { + continue; + } else { + let new_dense_index = (dense_index - 1) / 2; + new_Z.push((new_dense_index, *r * value)); + } + } + } + self.Z = new_Z; + self.num_vars -= 1; + } + + #[tracing::instrument(skip_all)] + pub fn bound_poly_var_bot_par(&mut self, r: &F) { + // TODO(sragss): Do this with a scan instead. + let n = self.Z.len(); + // let mut new_Z: Vec<(usize, F)> = Vec::with_capacity(n); + + let (chunks, _range) = self.chunk_no_orphans(rayon::current_num_threads() * 8); + // TODO(sragsss): We can scan up front and collect directly into the thing. + let new_Z: Vec<(usize, F)> = chunks.into_par_iter().map(|chunk| { + // TODO(sragss): Do this with a scan instead; + let mut chunk_Z: Vec<(usize, F)> = Vec::with_capacity(chunk.len()); + for (sparse_index, (dense_index, value)) in chunk.iter().enumerate() { + if dense_index.is_even() { + let new_dense_index = dense_index / 2; + // TODO(sragss): Can likely combine these conditions for better speculative execution. + if self.Z.len() >= 2 && sparse_index <= self.Z.len() - 2 && self.Z[sparse_index + 1].0 == dense_index + 1 { + let upper = self.Z[sparse_index + 1].1; + let eval = *value + *r * (upper - value); + chunk_Z.push((new_dense_index, eval)); + } else { + chunk_Z.push((new_dense_index, (F::one() - r) * value)); + } + } else { + if sparse_index > 0 && self.Z[sparse_index - 1].0 == dense_index - 1 { + continue; + } else { + let new_dense_index = (dense_index - 1) / 2; + chunk_Z.push((new_dense_index, *r * value)); + } + } + } + + chunk_Z + }).flatten().collect(); + + // for (sparse_index, (dense_index, value)) in self.Z.iter().enumerate() { + // if dense_index.is_even() { + // let new_dense_index = dense_index / 2; + // // TODO(sragss): Can likely combine these conditions for better speculative execution. + // if self.Z.len() >= 2 && sparse_index <= self.Z.len() - 2 && self.Z[sparse_index + 1].0 == dense_index + 1 { + // let upper = self.Z[sparse_index + 1].1; + // let eval = *value + *r * (upper - value); + // new_Z.push((new_dense_index, eval)); + // } else { + // new_Z.push((new_dense_index, (F::one() - r) * value)); + // } + // } else { + // if sparse_index > 0 && self.Z[sparse_index - 1].0 == dense_index - 1 { + // continue; + // } else { + // let new_dense_index = (dense_index - 1) / 2; + // new_Z.push((new_dense_index, *r * value)); + // } + // } + // } + self.Z = new_Z; + self.num_vars -= 1; + } + + pub fn final_eval(&self) -> F { + assert_eq!(self.num_vars, 0); + if self.Z.len() == 0 { + F::zero() + } else { + assert_eq!(self.Z.len(), 1); + let item = self.Z[0]; + assert_eq!(item.0, 0); + item.1 + } + } + + #[cfg(test)] + #[tracing::instrument(skip_all)] + pub fn to_dense(self) -> DensePolynomial { + use crate::utils::math::Math; + + let mut evals = unsafe_allocate_zero_vec(self.num_vars.pow2()); + + for (index, value) in self.Z { + evals[index] = value; + } + + DensePolynomial::new(evals) + } +} + +pub struct SparseTripleIterator<'a, F: JoltField> { + dense_index: usize, + end_index: usize, + a: &'a [(usize, F)], + b: &'a [(usize, F)], + c: &'a [(usize, F)], +} + +impl<'a, F: JoltField> SparseTripleIterator<'a, F> { + #[tracing::instrument(skip_all)] + pub fn chunks(a: &'a SparsePolynomial, b: &'a SparsePolynomial, c: &'a SparsePolynomial, n: usize) -> Vec { + // When the instance is small enough, don't worry about parallelism + let total_len = a.num_vars.pow2(); + if n * 2 > b.Z.len() { + return vec![SparseTripleIterator { + dense_index: 0, + end_index: total_len, + a: &a.Z, + b: &b.Z, + c: &c.Z + }]; + } + // Can be made more generic, but this is an optimization / simplification. + assert!(b.Z.len() >= a.Z.len() && b.Z.len() >= c.Z.len(), "b.Z.len() assumed to be longest of a, b, and c"); + + // TODO(sragss): Explain the strategy + + let target_chunk_size = b.Z.len() / n; + let mut b_chunks: Vec<&[(usize, F)]> = Vec::with_capacity(n); + let mut dense_ranges: Vec<(usize, usize)> = Vec::with_capacity(n); + let mut dense_start_index = 0; + let mut sparse_start_index = 0; + let mut sparse_end_index = target_chunk_size; + for _ in 1..n { + let mut dense_end_index = b.Z[sparse_end_index].0; + if dense_end_index % 2 != 0 { + dense_end_index += 1; + sparse_end_index += 1; + } + b_chunks.push(&b.Z[sparse_start_index..sparse_end_index]); + dense_ranges.push((dense_start_index, dense_end_index)); + dense_start_index = dense_end_index; + + sparse_start_index = sparse_end_index; + sparse_end_index = std::cmp::min(sparse_end_index + target_chunk_size, b.Z.len() - 1); + } + b_chunks.push(&b.Z[sparse_start_index..]); + let highest_non_zero = { + let a_last = a.Z.last().map(|&(index, _)| index); + let b_last = b.Z.last().map(|&(index, _)| index); + let c_last = c.Z.last().map(|&(index, _)| index); + *a_last.iter().chain(b_last.iter()).chain(c_last.iter()).max().unwrap() + }; + dense_ranges.push((dense_start_index, highest_non_zero + 1)); + assert_eq!(b_chunks.len(), n); + assert_eq!(dense_ranges.len(), n); + + // Create chunks which overlap with b's sparse indices + let mut a_chunks: Vec<&[(usize, F)]> = vec![&[]; n]; + let mut c_chunks: Vec<&[(usize, F)]> = vec![&[]; n]; + let mut a_i = 0; + let mut c_i = 0; + let span = tracing::span!(tracing::Level::DEBUG, "a, c scanning"); + let _enter = span.enter(); + for (chunk_index, range) in dense_ranges.iter().enumerate().skip(1) { + // Find the corresponding a, c chunks + let prev_chunk_end = range.0; + + if a_i < a.Z.len() && a.Z[a_i].0 < prev_chunk_end { + let a_start = a_i; + while a_i < a.Z.len() && a.Z[a_i].0 < prev_chunk_end { + a_i += 1; + } + + a_chunks[chunk_index - 1] = &a.Z[a_start..a_i]; + } + + if c_i < c.Z.len() && c.Z[c_i].0 < prev_chunk_end { + let c_start = c_i; + while c_i < c.Z.len() && c.Z[c_i].0 < prev_chunk_end { + c_i += 1; + } + + c_chunks[chunk_index - 1] = &c.Z[c_start..c_i]; + } + + } + drop(_enter); + a_chunks[n-1] = &a.Z[a_i..]; + c_chunks[n-1] = &c.Z[c_i..]; + + #[cfg(test)] + { + assert_eq!(a_chunks.concat(), a.Z); + assert_eq!(b_chunks.concat(), b.Z); + assert_eq!(c_chunks.concat(), c.Z); + } + + let mut iterators: Vec> = Vec::with_capacity(n); + for (((a_chunk, b_chunk), c_chunk), range) in a_chunks.iter().zip(b_chunks.iter()).zip(c_chunks.iter()).zip(dense_ranges.iter()) { + #[cfg(test)] + { + assert!(a_chunk.iter().all(|(index, _)| *index >= range.0 && *index <= range.1)); + assert!(b_chunk.iter().all(|(index, _)| *index >= range.0 && *index <= range.1)); + assert!(c_chunk.iter().all(|(index, _)| *index >= range.0 && *index <= range.1)); + } + let iter = SparseTripleIterator { + dense_index: range.0, + end_index: range.1, + a: a_chunk, + b: b_chunk, + c: c_chunk + }; + iterators.push(iter); + } + + iterators + } + + pub fn has_next(&self) -> bool { + self.dense_index < self.end_index + } + + pub fn next_pairs(&mut self) -> (usize, F, F, F, F, F, F) { + // TODO(sragss): We can store a map of big ranges of zeros and skip them rather than hitting each dense index. + let low_index = self.dense_index; + let match_and_advance = |slice: &mut &[(usize, F)], index: usize| -> F { + if let Some(first_item) = slice.first() { + if first_item.0 == index { + let ret = first_item.1; + *slice = &slice[1..]; + ret + } else { + F::zero() + } + } else { + F::zero() + } + }; + + let a_lower_val = match_and_advance(&mut self.a, self.dense_index); + let b_lower_val = match_and_advance(&mut self.b, self.dense_index); + let c_lower_val = match_and_advance(&mut self.c, self.dense_index); + self.dense_index += 1; + let a_upper_val = match_and_advance(&mut self.a, self.dense_index); + let b_upper_val = match_and_advance(&mut self.b, self.dense_index); + let c_upper_val = match_and_advance(&mut self.c, self.dense_index); + self.dense_index += 1; + + (low_index, a_lower_val, a_upper_val, b_lower_val, b_upper_val, c_lower_val, c_upper_val) + } +} + +pub trait IndexablePoly: std::ops::Index + Sync { + fn len(&self) -> usize; +} + +impl IndexablePoly for DensePolynomial { + fn len(&self) -> usize { + self.Z.len() + } +} + +// TODO: Rather than use these adhoc virtual indexable polys – create a DensePolynomial which takes any impl Index inner +// and can run all the normal DensePolynomial ops. +#[derive(Clone)] +pub struct SegmentedPaddedWitness { + total_len: usize, + pub segments: Vec>, + pub segment_len: usize, + zero: F, +} + +impl SegmentedPaddedWitness { + pub fn new(total_len: usize, segments: Vec>) -> Self { + let segment_len = segments[0].len(); + assert!(segment_len.is_power_of_two()); + for segment in &segments { + assert_eq!( + segment.len(), + segment_len, + "All segments must be the same length" + ); + } + SegmentedPaddedWitness { + total_len, + segments, + segment_len, + zero: F::zero(), + } + } + + pub fn len(&self) -> usize { + self.total_len + } + + #[tracing::instrument(skip_all, name = "SegmentedPaddedWitness::evaluate_all")] + pub fn evaluate_all(&self, point: Vec) -> Vec { + let chi = EqPolynomial::evals(&point); + assert!(chi.len() >= self.segment_len); + + let evals = self + .segments + .par_iter() + .map(|segment| compute_dotproduct_low_optimized(&chi[0..self.segment_len], segment)) + .collect(); + drop_in_background_thread(chi); + evals + } + + pub fn into_dense_polys(self) -> Vec> { + self.segments + .into_iter() + .map(|poly| DensePolynomial::new(poly)) + .collect() + } +} + +impl std::ops::Index for SegmentedPaddedWitness { + type Output = F; + + fn index(&self, index: usize) -> &Self::Output { + if index >= self.segments.len() * self.segment_len { + &self.zero + } else if index >= self.total_len { + panic!("index too high"); + } else { + let segment_index = index / self.segment_len; + let inner_index = index % self.segment_len; + &self.segments[segment_index][inner_index] + } + } +} + +impl IndexablePoly for SegmentedPaddedWitness { + fn len(&self) -> usize { + self.total_len + } } /// Returns the `num_bits` from n in a canonical order @@ -73,3 +484,131 @@ pub fn eq_plus_one(x: &[F], y: &[F], l: usize) -> F { }) .sum() } + +#[cfg(test)] +mod tests { + use super::*; + use ark_bn254::Fr; + use ark_std::Zero; + + #[test] + fn sparse_bound_bot_all_left() { + let dense_evals = vec![Fr::from(10), Fr::zero(), Fr::from(20), Fr::zero()]; + let sparse_evals = vec![(0, Fr::from(10)), (2, Fr::from(20))]; + + let mut dense = DensePolynomial::new(dense_evals); + let mut sparse = SparsePolynomial::new(2, sparse_evals); + + assert_eq!(sparse.clone().to_dense(), dense); + + let r = Fr::from(121); + sparse.bound_poly_var_bot(&r); + dense.bound_poly_var_bot(&r); + assert_eq!(sparse.to_dense(), dense); + } + + #[test] + fn sparse_bound_bot_all_right() { + let dense_evals = vec![Fr::zero(), Fr::from(10), Fr::zero(), Fr::from(20)]; + let sparse_evals = vec![(1, Fr::from(10)), (3, Fr::from(20))]; + + let mut dense = DensePolynomial::new(dense_evals); + let mut sparse = SparsePolynomial::new(2, sparse_evals); + + assert_eq!(sparse.clone().to_dense(), dense); + + let r = Fr::from(121); + sparse.bound_poly_var_bot(&r); + dense.bound_poly_var_bot(&r); + assert_eq!(sparse.to_dense(), dense); + } + + #[test] + fn sparse_bound_bot_mixed() { + let dense_evals = vec![Fr::zero(), Fr::from(10), Fr::zero(), Fr::from(20), Fr::from(30), Fr::from(40), Fr::zero(), Fr::from(50)]; + let sparse_evals = vec![(1, Fr::from(10)), (3, Fr::from(20)), (4, Fr::from(30)), (5, Fr::from(40)), (7, Fr::from(50))]; + + let mut dense = DensePolynomial::new(dense_evals); + let mut sparse = SparsePolynomial::new(3, sparse_evals); + + assert_eq!(sparse.clone().to_dense(), dense); + + let r = Fr::from(121); + sparse.bound_poly_var_bot(&r); + dense.bound_poly_var_bot(&r); + assert_eq!(sparse.to_dense(), dense); + } + + #[test] + fn sparse_triple_iterator() { + let a = vec![(9, Fr::from(9)), (10, Fr::from(10)), (12, Fr::from(12))]; + let b = vec![(0, Fr::from(100)), (1, Fr::from(1)), (2, Fr::from(2)), (3, Fr::from(3)), (4, Fr::from(4)), (5, Fr::from(5)), (6, Fr::from(6)), (7, Fr::from(7)), (8, Fr::from(8)), (9, Fr::from(9)), (10, Fr::from(10)), (11, Fr::from(11)), (12, Fr::from(12)), (13, Fr::from(13)), (14, Fr::from(14)), (15, Fr::from(15))]; + let c = vec![(0, Fr::from(12)), (3, Fr::from(3))]; + + let a_poly = SparsePolynomial::new(4, a); + let b_poly = SparsePolynomial::new(4, b); + let c_poly = SparsePolynomial::new(4, c); + + let iterators = SparseTripleIterator::chunks(&a_poly, &b_poly, &c_poly, 4); + assert_eq!(iterators.len(), 4); + } + + #[test] + fn sparse_triple_iterator_random() { + use rand::Rng; + + let mut rng = rand::thread_rng(); + + let prob_exists = 0.32; + let num_vars = 10; + let total_len = 1 << num_vars; + + let mut a = vec![]; + let mut b = vec![]; + let mut c = vec![]; + + for i in 0usize..total_len { + if rng.gen::() < prob_exists { + a.push((i, Fr::from(i as u64))); + } + if rng.gen::() < prob_exists * 2f64 { + b.push((i, Fr::from(i as u64))); + } + if rng.gen::() < prob_exists { + c.push((i, Fr::from(i as u64))); + } + } + + let a_poly = SparsePolynomial::new(num_vars, a); + let b_poly = SparsePolynomial::new(num_vars, b); + let c_poly = SparsePolynomial::new(num_vars, c); + + let mut iterators = SparseTripleIterator::chunks(&a_poly, &b_poly, &c_poly, 8); + + let mut new_a = vec![Fr::zero(); total_len]; + let mut new_b = vec![Fr::zero(); total_len]; + let mut new_c = vec![Fr::zero(); total_len]; + let mut expected_dense_index = 0; + for iterator in iterators.iter_mut() { + while iterator.has_next() { + let (dense_index, a_low, a_high, b_low, b_high, c_low, c_high) = iterator.next_pairs(); + + new_a[dense_index] = a_low; + new_a[dense_index+1] = a_high; + + new_b[dense_index] = b_low; + new_b[dense_index+1] = b_high; + + new_c[dense_index] = c_low; + new_c[dense_index+1] = c_high; + + assert_eq!(dense_index, expected_dense_index); + expected_dense_index += 2; + } + } + + assert_eq!(a_poly.to_dense().Z, new_a); + assert_eq!(b_poly.to_dense().Z, new_b); + assert_eq!(c_poly.to_dense().Z, new_c); + } +} \ No newline at end of file diff --git a/jolt-core/src/subprotocols/sumcheck.rs b/jolt-core/src/subprotocols/sumcheck.rs index 0b841de14..abf6ea7eb 100644 --- a/jolt-core/src/subprotocols/sumcheck.rs +++ b/jolt-core/src/subprotocols/sumcheck.rs @@ -4,7 +4,7 @@ use crate::field::JoltField; use crate::poly::dense_mlpoly::DensePolynomial; use crate::poly::unipoly::{CompressedUniPoly, UniPoly}; -use crate::r1cs::spartan::IndexablePoly; +use crate::r1cs::special_polys::{IndexablePoly, SparsePolynomial, SparseTripleIterator}; use crate::utils::errors::ProofVerifyError; use crate::utils::mul_0_optimized; use crate::utils::thread::drop_in_background_thread; @@ -179,51 +179,65 @@ impl SumcheckInstanceProof { skip_all, name = "Spartan2::sumcheck::compute_eval_points_spartan_cubic" )] + /// Binds from the bottom rather than the top. pub fn compute_eval_points_spartan_cubic( - poly_A: &DensePolynomial, - poly_B: &DensePolynomial, - poly_C: &DensePolynomial, - poly_D: &DensePolynomial, + poly_eq: &DensePolynomial, + poly_A: &SparsePolynomial, + poly_B: &SparsePolynomial, + poly_C: &SparsePolynomial, comb_func: &Func, ) -> (F, F, F) where Func: Fn(&F, &F, &F, &F) -> F + Sync, { - let len = poly_A.len() / 2; - (0..len) - .into_par_iter() - .map(|i| { - // eval 0: bound_func is A(low) - let eval_point_0 = comb_func(&poly_A[i], &poly_B[i], &poly_C[i], &poly_D[i]); + // num_threads * 8 enables better work stealing + let mut iterators = + SparseTripleIterator::chunks(poly_A, poly_B, poly_C, rayon::current_num_threads() * 16); + iterators + .par_iter_mut() + .map(|iterator| { + let span = tracing::span!(tracing::Level::DEBUG, "eval_par_inner"); + let _enter = span.enter(); + let mut eval_point_0 = F::zero(); + let mut eval_point_2 = F::zero(); + let mut eval_point_3 = F::zero(); + while iterator.has_next() { + let (dense_index, a_low, a_high, b_low, b_high, c_low, c_high) = + iterator.next_pairs(); + assert!(dense_index % 2 == 0); - let m_A = poly_A[len + i] - poly_A[i]; - let m_B = poly_B[len + i] - poly_B[i]; - let m_C = poly_C[len + i] - poly_C[i]; - let m_D = poly_D[len + i] - poly_D[i]; + // eval 0: bound_func is A(low) + eval_point_0 += comb_func(&poly_eq[dense_index], &a_low, &b_low, &c_low); + + let m_eq = poly_eq[dense_index + 1] - poly_eq[dense_index]; + let m_A = a_high - a_low; + let m_B = b_high - b_low; + let m_C = c_high - c_low; + + // eval 2 + let poly_A_bound_point = poly_eq[dense_index + 1] + m_eq; + let poly_B_bound_point = a_high + m_A; + let poly_C_bound_point = b_high + m_B; + let poly_D_bound_point = c_high + m_C; + eval_point_2 += comb_func( + &poly_A_bound_point, + &poly_B_bound_point, + &poly_C_bound_point, + &poly_D_bound_point, + ); - // eval 2: bound_func is -A(low) + 2*A(high) - let poly_A_bound_point = poly_A[len + i] + m_A; - let poly_B_bound_point = poly_B[len + i] + m_B; - let poly_C_bound_point = poly_C[len + i] + m_C; - let poly_D_bound_point = poly_D[len + i] + m_D; - let eval_point_2 = comb_func( - &poly_A_bound_point, - &poly_B_bound_point, - &poly_C_bound_point, - &poly_D_bound_point, - ); - - // eval 3: bound_func is -2A(low) + 3A(high); computed incrementally with bound_func applied to eval(2) - let poly_A_bound_point = poly_A_bound_point + m_A; - let poly_B_bound_point = poly_B_bound_point + m_B; - let poly_C_bound_point = poly_C_bound_point + m_C; - let poly_D_bound_point = poly_D_bound_point + m_D; - let eval_point_3 = comb_func( - &poly_A_bound_point, - &poly_B_bound_point, - &poly_C_bound_point, - &poly_D_bound_point, - ); + // eval 3 + let poly_A_bound_point = poly_A_bound_point + m_eq; + let poly_B_bound_point = poly_B_bound_point + m_A; + let poly_C_bound_point = poly_C_bound_point + m_B; + let poly_D_bound_point = poly_D_bound_point + m_C; + eval_point_3 += comb_func( + &poly_A_bound_point, + &poly_B_bound_point, + &poly_C_bound_point, + &poly_D_bound_point, + ); + } (eval_point_0, eval_point_2, eval_point_3) }) .reduce( @@ -236,10 +250,10 @@ impl SumcheckInstanceProof { pub fn prove_spartan_cubic( claim: &F, num_rounds: usize, - poly_A: &mut DensePolynomial, - poly_B: &mut DensePolynomial, - poly_C: &mut DensePolynomial, - poly_D: &mut DensePolynomial, + poly_eq: &mut DensePolynomial, + poly_A: &mut SparsePolynomial, + poly_B: &mut SparsePolynomial, + poly_C: &mut SparsePolynomial, comb_func: Func, transcript: &mut ProofTranscript, ) -> (Self, Vec, Vec) @@ -255,7 +269,7 @@ impl SumcheckInstanceProof { // Make an iterator returning the contributions to the evaluations let (eval_point_0, eval_point_2, eval_point_3) = Self::compute_eval_points_spartan_cubic( - poly_A, poly_B, poly_C, poly_D, &comb_func, + poly_eq, poly_A, poly_B, poly_C, &comb_func, ); let evals = [ @@ -264,6 +278,7 @@ impl SumcheckInstanceProof { eval_point_2, eval_point_3, ]; + UniPoly::from_evals(&evals) }; @@ -280,14 +295,14 @@ impl SumcheckInstanceProof { // bound all tables to the verifier's challenege rayon::join( - || poly_A.bound_poly_var_top_par(&r_i), + || poly_eq.bound_poly_var_bot(&r_i), || { rayon::join( - || poly_B.bound_poly_var_top_zero_optimized(&r_i), + || poly_A.bound_poly_var_bot(&r_i), || { rayon::join( - || poly_C.bound_poly_var_top_zero_optimized(&r_i), - || poly_D.bound_poly_var_top_zero_optimized(&r_i), + || poly_B.bound_poly_var_bot(&r_i), + || poly_C.bound_poly_var_bot(&r_i), ) }, ) @@ -298,7 +313,12 @@ impl SumcheckInstanceProof { ( SumcheckInstanceProof::new(polys), r, - vec![poly_A[0], poly_B[0], poly_C[0], poly_D[0]], + vec![ + poly_eq[0], + poly_A.final_eval(), + poly_B.final_eval(), + poly_C.final_eval(), + ], ) } From 17e6d3f2be3bf0b4407fa6470b389614e18989d0 Mon Sep 17 00:00:00 2001 From: sragss Date: Sat, 22 Jun 2024 08:49:41 -0700 Subject: [PATCH 04/43] par binding algos --- jolt-core/src/poly/dense_mlpoly.rs | 9 ++- jolt-core/src/r1cs/special_polys.rs | 103 ++++++++++++++++++++----- jolt-core/src/subprotocols/sumcheck.rs | 32 ++++---- jolt-core/src/utils/thread.rs | 26 +++++++ 4 files changed, 134 insertions(+), 36 deletions(-) diff --git a/jolt-core/src/poly/dense_mlpoly.rs b/jolt-core/src/poly/dense_mlpoly.rs index 6eb701531..928b63915 100644 --- a/jolt-core/src/poly/dense_mlpoly.rs +++ b/jolt-core/src/poly/dense_mlpoly.rs @@ -206,7 +206,14 @@ impl DensePolynomial { let n = self.len() / 2; let mut new_z = unsafe_allocate_zero_vec(n); new_z.par_iter_mut().enumerate().for_each(|(i, z)| { - *z = self.Z[2*i] + *r * (self.Z[2 * i + 1] - self.Z[2 * i]); + let m = self.Z[2*i + 1] - self.Z[2*i]; + *z = if m.is_zero() { + self.Z[2*i] + } else if m.is_one() { + self.Z[2*i] + r + }else { + self.Z[2*i] + *r * m + } }); let old_Z = std::mem::replace(&mut self.Z, new_z); diff --git a/jolt-core/src/r1cs/special_polys.rs b/jolt-core/src/r1cs/special_polys.rs index 64371a447..76b1aab3f 100644 --- a/jolt-core/src/r1cs/special_polys.rs +++ b/jolt-core/src/r1cs/special_polys.rs @@ -1,4 +1,4 @@ -use crate::{field::JoltField, poly::{dense_mlpoly::DensePolynomial, eq_poly::EqPolynomial}, utils::{compute_dotproduct_low_optimized, math::Math, thread::{drop_in_background_thread, unsafe_allocate_zero_vec}}}; +use crate::{field::JoltField, poly::{dense_mlpoly::DensePolynomial, eq_poly::EqPolynomial}, utils::{compute_dotproduct_low_optimized, math::Math, mul_0_1_optimized, thread::{drop_in_background_thread, unsafe_allocate_sparse_zero_vec, unsafe_allocate_zero_vec}}}; use num_integer::Integer; use rayon::prelude::*; @@ -57,6 +57,7 @@ impl SparsePolynomial { } /// Returns n chunks of roughly even size without orphaning siblings (adjacent dense indices). Additionally returns a vector of (low, high] dense index ranges. + #[tracing::instrument(skip_all)] fn chunk_no_orphans(&self, n: usize) -> (Vec<&[(usize, F)]>, Vec<(usize, usize)>) { if self.Z.len() < n * 2 { return (vec![(&self.Z)], vec![(0, self.num_vars.pow2())]); @@ -83,12 +84,12 @@ impl SparsePolynomial { } chunks.push(&self.Z[sparse_start_index..]); // TODO(sragss): likely makes more sense to return full range then truncate when needed (triple iterator) + // TODO(sragss): To use chunk_no_orphans in the triple iterator, we have to overwrite the top of the dense_ranges. let highest_non_zero = self.Z.last().map(|&(index, _)| index).unwrap(); dense_ranges.push((dense_start_index, highest_non_zero + 1)); assert_eq!(chunks.len(), n); assert_eq!(dense_ranges.len(), n); - // TODO(sragss): To use chunk_no_orphans in the triple iterator, we have to overwrite the top of the dense_ranges. (chunks, dense_ranges) } @@ -127,38 +128,75 @@ impl SparsePolynomial { #[tracing::instrument(skip_all)] pub fn bound_poly_var_bot_par(&mut self, r: &F) { - // TODO(sragss): Do this with a scan instead. - let n = self.Z.len(); - // let mut new_Z: Vec<(usize, F)> = Vec::with_capacity(n); - + // TODO(sragss): better parallelism. + let count_span = tracing::span!(tracing::Level::DEBUG, "counting"); + let count_enter = count_span.enter(); let (chunks, _range) = self.chunk_no_orphans(rayon::current_num_threads() * 8); + let chunk_sizes: Vec = chunks.par_iter().map(|chunk| { + let mut chunk_size = 0; + let mut i = 0; + while i < chunk.len() { + chunk_size += 1; + + // If they're siblings, avoid double counting + if chunk[i].0.is_even() && i + 1 < chunk.len() && chunk[i].0 + 1 == chunk[i + 1].0 { + i += 1; + } + i += 1; + } + chunk_size + }).collect(); + drop(count_enter); + + let alloc_span = tracing::span!(tracing::Level::DEBUG, "alloc_new_Z"); + let alloc_enter = alloc_span.enter(); + let total_len: usize = chunk_sizes.iter().sum(); + let mut new_Z: Vec<(usize, F)> = unsafe_allocate_sparse_zero_vec(total_len); + drop(alloc_enter); + + let mut mutable_chunks: Vec<&mut [(usize, F)]> = vec![]; + let mut remainder = new_Z.as_mut_slice(); + for chunk_size in chunk_sizes { + let (first, second) = remainder.split_at_mut(chunk_size); + mutable_chunks.push(first); + remainder = second; + } + assert_eq!(mutable_chunks.len(), chunks.len()); + // TODO(sragsss): We can scan up front and collect directly into the thing. - let new_Z: Vec<(usize, F)> = chunks.into_par_iter().map(|chunk| { + chunks.into_par_iter().zip(mutable_chunks.par_iter_mut()).for_each(|(chunk, mutable)| { + let span = tracing::span!(tracing::Level::DEBUG, "chunk"); + let _enter = span.enter(); // TODO(sragss): Do this with a scan instead; - let mut chunk_Z: Vec<(usize, F)> = Vec::with_capacity(chunk.len()); + // let mut chunk_Z: Vec<(usize, F)> = Vec::with_capacity(chunk.len()); + let mut write_index = 0; for (sparse_index, (dense_index, value)) in chunk.iter().enumerate() { if dense_index.is_even() { let new_dense_index = dense_index / 2; // TODO(sragss): Can likely combine these conditions for better speculative execution. - if self.Z.len() >= 2 && sparse_index <= self.Z.len() - 2 && self.Z[sparse_index + 1].0 == dense_index + 1 { - let upper = self.Z[sparse_index + 1].1; - let eval = *value + *r * (upper - value); - chunk_Z.push((new_dense_index, eval)); - } else { - chunk_Z.push((new_dense_index, (F::one() - r) * value)); + + // All exist + if chunk.len() >= 2 && sparse_index <= chunk.len() - 2 && chunk[sparse_index + 1].0 == dense_index + 1 { + let upper = chunk[sparse_index + 1].1; + let eval = *value + mul_0_1_optimized(r, &(upper - value)); + mutable[write_index] = (new_dense_index, eval); + write_index += 1; + } else { // low exists + mutable[write_index] = (new_dense_index, mul_0_1_optimized(&(F::one() - r), value)); + write_index += 1; } } else { - if sparse_index > 0 && self.Z[sparse_index - 1].0 == dense_index - 1 { + // low and high exist + if sparse_index > 0 && chunk[sparse_index - 1].0 == dense_index - 1 { continue; - } else { + } else { // high only exists let new_dense_index = (dense_index - 1) / 2; - chunk_Z.push((new_dense_index, *r * value)); + mutable[write_index] = (new_dense_index, mul_0_1_optimized(r, value)); + write_index += 1; } } } - - chunk_Z - }).flatten().collect(); + }); // for (sparse_index, (dense_index, value)) in self.Z.iter().enumerate() { // if dense_index.is_even() { @@ -180,7 +218,8 @@ impl SparsePolynomial { // } // } // } - self.Z = new_Z; + let old_Z = std::mem::replace(&mut self.Z, new_Z); + drop_in_background_thread(old_Z); self.num_vars -= 1; } @@ -611,4 +650,26 @@ mod tests { assert_eq!(b_poly.to_dense().Z, new_b); assert_eq!(c_poly.to_dense().Z, new_c); } + + #[test] + fn binding() { + use rand::Rng; + + let mut rng = rand::thread_rng(); + let prob_exists = 0.32; + let num_vars = 6; + let total_len = 1 << num_vars; + let mut a = vec![]; + for i in 0usize..total_len { + if rng.gen::() < prob_exists { + a.push((i, Fr::from(i as u64))); + } + } + + let mut a_poly = SparsePolynomial::new(num_vars, a); + + let r = Fr::from(100); + assert_eq!(a_poly.clone().bound_poly_var_bot(&r), a_poly.bound_poly_var_bot_par(&r)); + + } } \ No newline at end of file diff --git a/jolt-core/src/subprotocols/sumcheck.rs b/jolt-core/src/subprotocols/sumcheck.rs index abf6ea7eb..ab5d919c9 100644 --- a/jolt-core/src/subprotocols/sumcheck.rs +++ b/jolt-core/src/subprotocols/sumcheck.rs @@ -294,20 +294,24 @@ impl SumcheckInstanceProof { claim_per_round = poly.evaluate(&r_i); // bound all tables to the verifier's challenege - rayon::join( - || poly_eq.bound_poly_var_bot(&r_i), - || { - rayon::join( - || poly_A.bound_poly_var_bot(&r_i), - || { - rayon::join( - || poly_B.bound_poly_var_bot(&r_i), - || poly_C.bound_poly_var_bot(&r_i), - ) - }, - ) - }, - ); + poly_eq.bound_poly_var_bot(&r_i); + poly_A.bound_poly_var_bot_par(&r_i); + poly_B.bound_poly_var_bot_par(&r_i); + poly_C.bound_poly_var_bot_par(&r_i); + // rayon::join( + // || poly_eq.bound_poly_var_bot(&r_i), + // || { + // rayon::join( + // || poly_A.bound_poly_var_bot_par(&r_i), + // || { + // rayon::join( + // || poly_B.bound_poly_var_bot_par(&r_i), + // || poly_C.bound_poly_var_bot_par(&r_i), + // ) + // }, + // ) + // }, + // ); } ( diff --git a/jolt-core/src/utils/thread.rs b/jolt-core/src/utils/thread.rs index 196d9f8a5..eda50a466 100644 --- a/jolt-core/src/utils/thread.rs +++ b/jolt-core/src/utils/thread.rs @@ -44,6 +44,32 @@ pub fn unsafe_allocate_zero_vec(size: usize) -> Vec { result } +#[tracing::instrument(skip_all, name = "unsafe_allocate_sparse_zero_vec")] +pub fn unsafe_allocate_sparse_zero_vec(size: usize) -> Vec<(usize, F)> { + // Check for safety of 0 allocation + unsafe { + let value = &F::zero(); + let ptr = value as *const F as *const u8; + let bytes = std::slice::from_raw_parts(ptr, std::mem::size_of::()); + assert!(bytes.iter().all(|&byte| byte == 0)); + } + + // Bulk allocate zeros, unsafely + let result: Vec<(usize, F)>; + unsafe { + let layout = std::alloc::Layout::array::<(usize, F)>(size).unwrap(); + let ptr = std::alloc::alloc_zeroed(layout) as *mut (usize, F); + + if ptr.is_null() { + panic!("Zero vec allocation failed"); + } + + result = Vec::from_raw_parts(ptr, size, size); + } + result +} + + pub fn join_triple(oper_a: A, oper_b: B, oper_c: C) -> (RA, RB, RC) where A: FnOnce() -> RA + Send, From 12294987980d4db36dfdedd8f8649d6c7d0b3f60 Mon Sep 17 00:00:00 2001 From: Michael Zhu Date: Tue, 25 Jun 2024 14:08:29 -0400 Subject: [PATCH 05/43] Add IsZero, LeftMSB, and RightMSB subtables --- jolt-core/src/jolt/subtable/is_zero.rs | 68 +++++++++++++++++++++++ jolt-core/src/jolt/subtable/left_msb.rs | 70 ++++++++++++++++++++++++ jolt-core/src/jolt/subtable/mod.rs | 3 + jolt-core/src/jolt/subtable/right_msb.rs | 70 ++++++++++++++++++++++++ 4 files changed, 211 insertions(+) create mode 100644 jolt-core/src/jolt/subtable/is_zero.rs create mode 100644 jolt-core/src/jolt/subtable/left_msb.rs create mode 100644 jolt-core/src/jolt/subtable/right_msb.rs diff --git a/jolt-core/src/jolt/subtable/is_zero.rs b/jolt-core/src/jolt/subtable/is_zero.rs new file mode 100644 index 000000000..81fc4e0a5 --- /dev/null +++ b/jolt-core/src/jolt/subtable/is_zero.rs @@ -0,0 +1,68 @@ +use crate::field::JoltField; +use ark_std::log2; +use std::marker::PhantomData; + +use super::LassoSubtable; + +#[derive(Default)] +pub struct IsZeroSubtable { + _field: PhantomData, +} + +impl IsZeroSubtable { + pub fn new() -> Self { + Self { + _field: PhantomData, + } + } +} + +impl LassoSubtable for IsZeroSubtable { + fn materialize(&self, M: usize) -> Vec { + let mut entries: Vec = vec![F::zero(); M]; + + for idx in 0..(1 << (log2(M) / 2)) { + entries[idx] = F::one(); + } + + entries + } + + fn evaluate_mle(&self, point: &[F]) -> F { + // \prod_i (1 - x_i) + debug_assert!(point.len() % 2 == 0); + let b = point.len() / 2; + let (x, _) = point.split_at(b); + + let mut result = F::one(); + for i in 0..b { + result *= F::one() - x[i]; + } + result + } +} + +#[cfg(test)] +mod test { + use ark_bn254::Fr; + use binius_field::BinaryField128b; + + use crate::{ + field::binius::BiniusField, + jolt::subtable::{is_zero::IsZeroSubtable, LassoSubtable}, + subtable_materialize_mle_parity_test, + }; + + subtable_materialize_mle_parity_test!( + is_zero_materialize_mle_parity, + IsZeroSubtable, + Fr, + 256 + ); + subtable_materialize_mle_parity_test!( + is_zero_binius_materialize_mle_parity, + IsZeroSubtable>, + BiniusField, + 1 << 16 + ); +} diff --git a/jolt-core/src/jolt/subtable/left_msb.rs b/jolt-core/src/jolt/subtable/left_msb.rs new file mode 100644 index 000000000..6130bf099 --- /dev/null +++ b/jolt-core/src/jolt/subtable/left_msb.rs @@ -0,0 +1,70 @@ +use crate::field::JoltField; +use ark_std::log2; +use std::marker::PhantomData; + +use super::LassoSubtable; +use crate::utils::split_bits; + +#[derive(Default)] +pub struct LeftMSBSubtable { + _field: PhantomData, +} + +impl LeftMSBSubtable { + pub fn new() -> Self { + Self { + _field: PhantomData, + } + } +} + +impl LassoSubtable for LeftMSBSubtable { + fn materialize(&self, M: usize) -> Vec { + let mut entries: Vec = Vec::with_capacity(M); + let bits_per_operand = (log2(M) / 2) as usize; + let high_bit = 1usize << (bits_per_operand - 1); + + // Materialize table entries in order from 0..M + for idx in 0..M { + let (x, _) = split_bits(idx, bits_per_operand); + entries.push(if x & high_bit != 0 { + F::one() + } else { + F::zero() + }); + } + entries + } + + fn evaluate_mle(&self, point: &[F]) -> F { + debug_assert!(point.len() % 2 == 0); + let b = point.len() / 2; + let (x, _) = point.split_at(b); + x[0] + } +} + +#[cfg(test)] +mod test { + use ark_bn254::Fr; + use binius_field::BinaryField128b; + + use crate::{ + field::binius::BiniusField, + jolt::subtable::{left_msb::LeftMSBSubtable, LassoSubtable}, + subtable_materialize_mle_parity_test, + }; + + subtable_materialize_mle_parity_test!( + left_msb_materialize_mle_parity, + LeftMSBSubtable, + Fr, + 256 + ); + subtable_materialize_mle_parity_test!( + left_msb_binius_materialize_mle_parity, + LeftMSBSubtable>, + BiniusField, + 1 << 16 + ); +} diff --git a/jolt-core/src/jolt/subtable/mod.rs b/jolt-core/src/jolt/subtable/mod.rs index 8ccbc2d6a..e8c28aba7 100644 --- a/jolt-core/src/jolt/subtable/mod.rs +++ b/jolt-core/src/jolt/subtable/mod.rs @@ -35,9 +35,12 @@ pub mod eq_abs; pub mod eq_msb; pub mod gt_msb; pub mod identity; +pub mod is_zero; +pub mod left_msb; pub mod lt_abs; pub mod ltu; pub mod or; +pub mod right_msb; pub mod sign_extend; pub mod sll; pub mod sra_sign; diff --git a/jolt-core/src/jolt/subtable/right_msb.rs b/jolt-core/src/jolt/subtable/right_msb.rs new file mode 100644 index 000000000..65608a11c --- /dev/null +++ b/jolt-core/src/jolt/subtable/right_msb.rs @@ -0,0 +1,70 @@ +use crate::field::JoltField; +use ark_std::log2; +use std::marker::PhantomData; + +use super::LassoSubtable; +use crate::utils::split_bits; + +#[derive(Default)] +pub struct RightMSBSubtable { + _field: PhantomData, +} + +impl RightMSBSubtable { + pub fn new() -> Self { + Self { + _field: PhantomData, + } + } +} + +impl LassoSubtable for RightMSBSubtable { + fn materialize(&self, M: usize) -> Vec { + let mut entries: Vec = Vec::with_capacity(M); + let bits_per_operand = (log2(M) / 2) as usize; + let high_bit = 1usize << (bits_per_operand - 1); + + // Materialize table entries in order from 0..M + for idx in 0..M { + let (_, y) = split_bits(idx, bits_per_operand); + entries.push(if y & high_bit != 0 { + F::one() + } else { + F::zero() + }); + } + entries + } + + fn evaluate_mle(&self, point: &[F]) -> F { + debug_assert!(point.len() % 2 == 0); + let b = point.len() / 2; + let (_, y) = point.split_at(b); + y[0] + } +} + +#[cfg(test)] +mod test { + use ark_bn254::Fr; + use binius_field::BinaryField128b; + + use crate::{ + field::binius::BiniusField, + jolt::subtable::{right_msb::RightMSBSubtable, LassoSubtable}, + subtable_materialize_mle_parity_test, + }; + + subtable_materialize_mle_parity_test!( + right_msb_materialize_mle_parity, + RightMSBSubtable, + Fr, + 256 + ); + subtable_materialize_mle_parity_test!( + right_msb_binius_materialize_mle_parity, + RightMSBSubtable>, + BiniusField, + 1 << 16 + ); +} From 3a43ee0fc5ed3ec059936e85fe4440d1956b38e7 Mon Sep 17 00:00:00 2001 From: Michael Zhu Date: Tue, 25 Jun 2024 14:23:26 -0400 Subject: [PATCH 06/43] Replace GtMSB and EqMSB with LeftMSB and RightMSB subtables --- jolt-core/src/jolt/instruction/bge.rs | 8 +-- jolt-core/src/jolt/instruction/slt.rs | 16 +++-- .../instruction/virtual_assert_eq_signs.rs | 11 ++- .../jolt/instruction/virtual_assert_lte.rs | 16 +++-- jolt-core/src/jolt/subtable/eq_msb.rs | 68 ------------------- jolt-core/src/jolt/subtable/gt_msb.rs | 68 ------------------- jolt-core/src/jolt/subtable/mod.rs | 2 - jolt-core/src/jolt/vm/rv32i_vm.rs | 14 ++-- 8 files changed, 37 insertions(+), 166 deletions(-) delete mode 100644 jolt-core/src/jolt/subtable/eq_msb.rs delete mode 100644 jolt-core/src/jolt/subtable/gt_msb.rs diff --git a/jolt-core/src/jolt/instruction/bge.rs b/jolt-core/src/jolt/instruction/bge.rs index 30e1c96b9..381b4877b 100644 --- a/jolt-core/src/jolt/instruction/bge.rs +++ b/jolt-core/src/jolt/instruction/bge.rs @@ -6,8 +6,8 @@ use super::{slt::SLTInstruction, JoltInstruction, SubtableIndices}; use crate::{ field::JoltField, jolt::subtable::{ - eq::EqSubtable, eq_abs::EqAbsSubtable, eq_msb::EqMSBSubtable, gt_msb::GtMSBSubtable, - lt_abs::LtAbsSubtable, ltu::LtuSubtable, LassoSubtable, + eq::EqSubtable, eq_abs::EqAbsSubtable, left_msb::LeftMSBSubtable, lt_abs::LtAbsSubtable, + ltu::LtuSubtable, right_msb::RightMSBSubtable, LassoSubtable, }, utils::instruction_utils::chunk_and_concatenate_operands, }; @@ -35,8 +35,8 @@ impl JoltInstruction for BGEInstruction { _: usize, ) -> Vec<(Box>, SubtableIndices)> { vec![ - (Box::new(GtMSBSubtable::new()), SubtableIndices::from(0)), - (Box::new(EqMSBSubtable::new()), SubtableIndices::from(0)), + (Box::new(LeftMSBSubtable::new()), SubtableIndices::from(0)), + (Box::new(RightMSBSubtable::new()), SubtableIndices::from(0)), (Box::new(LtuSubtable::new()), SubtableIndices::from(1..C)), (Box::new(EqSubtable::new()), SubtableIndices::from(1..C)), (Box::new(LtAbsSubtable::new()), SubtableIndices::from(0)), diff --git a/jolt-core/src/jolt/instruction/slt.rs b/jolt-core/src/jolt/instruction/slt.rs index b475eb44c..1a809f249 100644 --- a/jolt-core/src/jolt/instruction/slt.rs +++ b/jolt-core/src/jolt/instruction/slt.rs @@ -6,8 +6,8 @@ use serde::{Deserialize, Serialize}; use super::{JoltInstruction, SubtableIndices}; use crate::{ jolt::subtable::{ - eq::EqSubtable, eq_abs::EqAbsSubtable, eq_msb::EqMSBSubtable, gt_msb::GtMSBSubtable, - lt_abs::LtAbsSubtable, ltu::LtuSubtable, LassoSubtable, + eq::EqSubtable, eq_abs::EqAbsSubtable, left_msb::LeftMSBSubtable, lt_abs::LtAbsSubtable, + ltu::LtuSubtable, right_msb::RightMSBSubtable, LassoSubtable, }, utils::instruction_utils::chunk_and_concatenate_operands, }; @@ -23,8 +23,8 @@ impl JoltInstruction for SLTInstruction { fn combine_lookups(&self, vals: &[F], C: usize, M: usize) -> F { let vals_by_subtable = self.slice_values(vals, C, M); - let gt_msb = vals_by_subtable[0]; - let eq_msb = vals_by_subtable[1]; + let left_msb = vals_by_subtable[0]; + let right_msb = vals_by_subtable[1]; let ltu = vals_by_subtable[2]; let eq = vals_by_subtable[3]; let lt_abs = vals_by_subtable[4]; @@ -41,7 +41,9 @@ impl JoltInstruction for SLTInstruction { } // x_s * (1 - y_s) + EQ(x_s, y_s) * LTU(x_{ usize { @@ -54,8 +56,8 @@ impl JoltInstruction for SLTInstruction { _: usize, ) -> Vec<(Box>, SubtableIndices)> { vec![ - (Box::new(GtMSBSubtable::new()), SubtableIndices::from(0)), - (Box::new(EqMSBSubtable::new()), SubtableIndices::from(0)), + (Box::new(LeftMSBSubtable::new()), SubtableIndices::from(0)), + (Box::new(RightMSBSubtable::new()), SubtableIndices::from(0)), (Box::new(LtuSubtable::new()), SubtableIndices::from(1..C)), (Box::new(EqSubtable::new()), SubtableIndices::from(1..C)), (Box::new(LtAbsSubtable::new()), SubtableIndices::from(0)), diff --git a/jolt-core/src/jolt/instruction/virtual_assert_eq_signs.rs b/jolt-core/src/jolt/instruction/virtual_assert_eq_signs.rs index c519a743e..c544d1cb8 100644 --- a/jolt-core/src/jolt/instruction/virtual_assert_eq_signs.rs +++ b/jolt-core/src/jolt/instruction/virtual_assert_eq_signs.rs @@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize}; use super::{JoltInstruction, SubtableIndices}; use crate::{ - jolt::subtable::{eq_msb::EqMSBSubtable, LassoSubtable}, + jolt::subtable::{left_msb::LeftMSBSubtable, right_msb::RightMSBSubtable, LassoSubtable}, utils::instruction_utils::chunk_and_concatenate_operands, }; @@ -18,7 +18,9 @@ impl JoltInstruction for ASSERTEQSIGNSInstruction { } fn combine_lookups(&self, vals: &[F], _: usize, _: usize) -> F { - vals[0] + let left_msb = vals[0]; + let right_msb = vals[1]; + (left_msb * right_msb) + (F::one() - left_msb) * (F::one() - right_msb) } fn g_poly_degree(&self, _: usize) -> usize { @@ -30,7 +32,10 @@ impl JoltInstruction for ASSERTEQSIGNSInstruction { _: usize, _: usize, ) -> Vec<(Box>, SubtableIndices)> { - vec![(Box::new(EqMSBSubtable::new()), SubtableIndices::from(0))] + vec![ + (Box::new(LeftMSBSubtable::new()), SubtableIndices::from(0)), + (Box::new(RightMSBSubtable::new()), SubtableIndices::from(0)), + ] } fn to_indices(&self, C: usize, log_M: usize) -> Vec { diff --git a/jolt-core/src/jolt/instruction/virtual_assert_lte.rs b/jolt-core/src/jolt/instruction/virtual_assert_lte.rs index 8526a8495..9887a60e7 100644 --- a/jolt-core/src/jolt/instruction/virtual_assert_lte.rs +++ b/jolt-core/src/jolt/instruction/virtual_assert_lte.rs @@ -6,8 +6,8 @@ use super::{JoltInstruction, SubtableIndices}; use crate::{ field::JoltField, jolt::subtable::{ - eq::EqSubtable, eq_abs::EqAbsSubtable, eq_msb::EqMSBSubtable, gt_msb::GtMSBSubtable, - lt_abs::LtAbsSubtable, ltu::LtuSubtable, LassoSubtable, + eq::EqSubtable, eq_abs::EqAbsSubtable, left_msb::LeftMSBSubtable, lt_abs::LtAbsSubtable, + ltu::LtuSubtable, right_msb::RightMSBSubtable, LassoSubtable, }, utils::instruction_utils::chunk_and_concatenate_operands, }; @@ -24,8 +24,8 @@ impl JoltInstruction for ASSERTLTEInstruction { // LTS(x,y) let vals_by_subtable = self.slice_values(vals, C, M); - let gt_msb = vals_by_subtable[0]; - let eq_msb = vals_by_subtable[1]; + let left_msb = vals_by_subtable[0]; + let right_msb = vals_by_subtable[1]; let ltu = vals_by_subtable[2]; let eq = vals_by_subtable[3]; let lt_abs = vals_by_subtable[4]; @@ -42,7 +42,9 @@ impl JoltInstruction for ASSERTLTEInstruction { } // x_s * (1 - y_s) + EQ(x_s, y_s) * LTU(x_{(); @@ -61,8 +63,8 @@ impl JoltInstruction for ASSERTLTEInstruction { _: usize, ) -> Vec<(Box>, SubtableIndices)> { vec![ - (Box::new(GtMSBSubtable::new()), SubtableIndices::from(0)), - (Box::new(EqMSBSubtable::new()), SubtableIndices::from(0)), + (Box::new(LeftMSBSubtable::new()), SubtableIndices::from(0)), + (Box::new(RightMSBSubtable::new()), SubtableIndices::from(0)), (Box::new(LtuSubtable::new()), SubtableIndices::from(1..C)), (Box::new(EqSubtable::new()), SubtableIndices::from(0..C)), (Box::new(LtAbsSubtable::new()), SubtableIndices::from(0)), diff --git a/jolt-core/src/jolt/subtable/eq_msb.rs b/jolt-core/src/jolt/subtable/eq_msb.rs deleted file mode 100644 index 196d59012..000000000 --- a/jolt-core/src/jolt/subtable/eq_msb.rs +++ /dev/null @@ -1,68 +0,0 @@ -use crate::field::JoltField; -use ark_std::log2; -use std::marker::PhantomData; - -use super::LassoSubtable; -use crate::utils::split_bits; - -#[derive(Default)] -pub struct EqMSBSubtable { - _field: PhantomData, -} - -impl EqMSBSubtable { - pub fn new() -> Self { - Self { - _field: PhantomData, - } - } -} - -impl LassoSubtable for EqMSBSubtable { - fn materialize(&self, M: usize) -> Vec { - let mut entries: Vec = Vec::with_capacity(M); - let bits_per_operand = (log2(M) / 2) as usize; - let high_bit = 1usize << (bits_per_operand - 1); - - // Materialize table entries in order from 0..M - for idx in 0..M { - let (x, y) = split_bits(idx, bits_per_operand); - let row = (x & high_bit) == (y & high_bit); - entries.push(if row { F::one() } else { F::zero() }); - } - entries - } - - fn evaluate_mle(&self, point: &[F]) -> F { - debug_assert!(point.len() % 2 == 0); - let b = point.len() / 2; - let (x, y) = point.split_at(b); - // x_0 * y_0 + (1 - x_0) * (1 - y_0) - x[0] * y[0] + (F::one() - x[0]) * (F::one() - y[0]) - } -} - -#[cfg(test)] -mod test { - use ark_bn254::Fr; - use binius_field::BinaryField128b; - - use crate::{ - field::binius::BiniusField, - jolt::subtable::{eq_msb::EqMSBSubtable, LassoSubtable}, - subtable_materialize_mle_parity_test, - }; - - subtable_materialize_mle_parity_test!( - eq_msb_materialize_mle_parity, - EqMSBSubtable, - Fr, - 256 - ); - subtable_materialize_mle_parity_test!( - eq_msb_binius_materialize_mle_parity, - EqMSBSubtable>, - BiniusField, - 1 << 16 - ); -} diff --git a/jolt-core/src/jolt/subtable/gt_msb.rs b/jolt-core/src/jolt/subtable/gt_msb.rs deleted file mode 100644 index 8796a240f..000000000 --- a/jolt-core/src/jolt/subtable/gt_msb.rs +++ /dev/null @@ -1,68 +0,0 @@ -use crate::field::JoltField; -use ark_std::log2; -use std::marker::PhantomData; - -use super::LassoSubtable; -use crate::utils::split_bits; - -#[derive(Default)] -pub struct GtMSBSubtable { - _field: PhantomData, -} - -impl GtMSBSubtable { - pub fn new() -> Self { - Self { - _field: PhantomData, - } - } -} - -impl LassoSubtable for GtMSBSubtable { - fn materialize(&self, M: usize) -> Vec { - let mut entries: Vec = Vec::with_capacity(M); - let bits_per_operand = (log2(M) / 2) as usize; - let high_bit = 1usize << (bits_per_operand - 1); - - // Materialize table entries in order from 0..M - for idx in 0..M { - let (x, y) = split_bits(idx, bits_per_operand); - let row = (x & high_bit) > (y & high_bit); - entries.push(if row { F::one() } else { F::zero() }); - } - entries - } - - fn evaluate_mle(&self, point: &[F]) -> F { - debug_assert!(point.len() % 2 == 0); - let b = point.len() / 2; - let (x, y) = point.split_at(b); - // x_0 * (1 - y_0) - x[0] * (F::one() - y[0]) - } -} - -#[cfg(test)] -mod test { - use ark_bn254::Fr; - use binius_field::BinaryField128b; - - use crate::{ - field::binius::BiniusField, - jolt::subtable::{gt_msb::GtMSBSubtable, LassoSubtable}, - subtable_materialize_mle_parity_test, - }; - - subtable_materialize_mle_parity_test!( - gt_msb_materialize_mle_parity, - GtMSBSubtable, - Fr, - 256 - ); - subtable_materialize_mle_parity_test!( - gt_msb_binius_materialize_mle_parity, - GtMSBSubtable>, - BiniusField, - 1 << 16 - ); -} diff --git a/jolt-core/src/jolt/subtable/mod.rs b/jolt-core/src/jolt/subtable/mod.rs index e8c28aba7..72c03608c 100644 --- a/jolt-core/src/jolt/subtable/mod.rs +++ b/jolt-core/src/jolt/subtable/mod.rs @@ -32,8 +32,6 @@ pub trait JoltSubtableSet: pub mod and; pub mod eq; pub mod eq_abs; -pub mod eq_msb; -pub mod gt_msb; pub mod identity; pub mod is_zero; pub mod left_msb; diff --git a/jolt-core/src/jolt/vm/rv32i_vm.rs b/jolt-core/src/jolt/vm/rv32i_vm.rs index 98a1e5816..594d99ffb 100644 --- a/jolt-core/src/jolt/vm/rv32i_vm.rs +++ b/jolt-core/src/jolt/vm/rv32i_vm.rs @@ -19,11 +19,11 @@ use crate::jolt::instruction::{ xor::XORInstruction, JoltInstruction, JoltInstructionSet, SubtableIndices, }; use crate::jolt::subtable::{ - and::AndSubtable, eq::EqSubtable, eq_abs::EqAbsSubtable, eq_msb::EqMSBSubtable, - gt_msb::GtMSBSubtable, identity::IdentitySubtable, lt_abs::LtAbsSubtable, ltu::LtuSubtable, - or::OrSubtable, sign_extend::SignExtendSubtable, sll::SllSubtable, sra_sign::SraSignSubtable, - srl::SrlSubtable, truncate_overflow::TruncateOverflowSubtable, xor::XorSubtable, - JoltSubtableSet, LassoSubtable, SubtableId, + and::AndSubtable, eq::EqSubtable, eq_abs::EqAbsSubtable, identity::IdentitySubtable, + left_msb::LeftMSBSubtable, lt_abs::LtAbsSubtable, ltu::LtuSubtable, or::OrSubtable, + right_msb::RightMSBSubtable, sign_extend::SignExtendSubtable, sll::SllSubtable, + sra_sign::SraSignSubtable, srl::SrlSubtable, truncate_overflow::TruncateOverflowSubtable, + xor::XorSubtable, JoltSubtableSet, LassoSubtable, SubtableId, }; use crate::poly::commitment::commitment_scheme::CommitmentScheme; @@ -117,9 +117,9 @@ subtable_enum!( RV32ISubtables, AND: AndSubtable, EQ_ABS: EqAbsSubtable, - EQ_MSB: EqMSBSubtable, EQ: EqSubtable, - GT_MSB: GtMSBSubtable, + LEFT_MSB: LeftMSBSubtable, + RIGHT_MSB: RightMSBSubtable, IDENTITY: IdentitySubtable, LT_ABS: LtAbsSubtable, LTU: LtuSubtable, From 37718f3966ce19a793a8cc6d2e0bc83feefa78ce Mon Sep 17 00:00:00 2001 From: Michael Zhu Date: Tue, 25 Jun 2024 15:15:51 -0400 Subject: [PATCH 07/43] virtual ASSERTVALIDREMAINDER instruction --- jolt-core/src/jolt/instruction/mod.rs | 1 + .../virtual_assert_valid_remainder.rs | 171 ++++++++++++++++++ .../subtable/{is_zero.rs => left_is_zero.rs} | 16 +- jolt-core/src/jolt/subtable/mod.rs | 2 +- 4 files changed, 181 insertions(+), 9 deletions(-) create mode 100644 jolt-core/src/jolt/instruction/virtual_assert_valid_remainder.rs rename jolt-core/src/jolt/subtable/{is_zero.rs => left_is_zero.rs} (73%) diff --git a/jolt-core/src/jolt/instruction/mod.rs b/jolt-core/src/jolt/instruction/mod.rs index 32e1e1876..d1d175aee 100644 --- a/jolt-core/src/jolt/instruction/mod.rs +++ b/jolt-core/src/jolt/instruction/mod.rs @@ -159,6 +159,7 @@ pub mod virtual_advice; pub mod virtual_assert_eq_signs; pub mod virtual_assert_lt_abs; pub mod virtual_assert_lte; +pub mod virtual_assert_valid_remainder; pub mod xor; #[cfg(test)] diff --git a/jolt-core/src/jolt/instruction/virtual_assert_valid_remainder.rs b/jolt-core/src/jolt/instruction/virtual_assert_valid_remainder.rs new file mode 100644 index 000000000..5fd1ea11a --- /dev/null +++ b/jolt-core/src/jolt/instruction/virtual_assert_valid_remainder.rs @@ -0,0 +1,171 @@ +use crate::field::JoltField; +use rand::prelude::StdRng; +use rand::RngCore; +use serde::{Deserialize, Serialize}; + +use super::{JoltInstruction, SubtableIndices}; +use crate::{ + jolt::subtable::{ + eq::EqSubtable, eq_abs::EqAbsSubtable, left_is_zero::LeftIsZeroSubtable, + left_msb::LeftMSBSubtable, lt_abs::LtAbsSubtable, ltu::LtuSubtable, + right_msb::RightMSBSubtable, LassoSubtable, + }, + utils::instruction_utils::chunk_and_concatenate_operands, +}; + +#[derive(Copy, Clone, Default, Debug, Serialize, Deserialize)] +/// (remainder, divisor) +pub struct ASSERTVALIDREMAINDERInstruction(pub u64, pub u64); + +impl JoltInstruction for ASSERTVALIDREMAINDERInstruction { + fn operands(&self) -> (u64, u64) { + (self.0, self.1) + } + + fn combine_lookups(&self, vals: &[F], C: usize, M: usize) -> F { + let vals_by_subtable = self.slice_values(vals, C, M); + + let left_msb = vals_by_subtable[0]; + let right_msb = vals_by_subtable[1]; + let eq = vals_by_subtable[2]; + let ltu = vals_by_subtable[3]; + let eq_abs = vals_by_subtable[4]; + let lt_abs = vals_by_subtable[5]; + let remainder_is_zero: F = vals_by_subtable[6].iter().product(); + + // Accumulator for LTU(x_{ usize { + C + 1 + } + + fn subtables( + &self, + C: usize, + _: usize, + ) -> Vec<(Box>, SubtableIndices)> { + vec![ + (Box::new(LeftMSBSubtable::new()), SubtableIndices::from(0)), + (Box::new(RightMSBSubtable::new()), SubtableIndices::from(0)), + (Box::new(EqSubtable::new()), SubtableIndices::from(1..C)), + (Box::new(LtuSubtable::new()), SubtableIndices::from(1..C)), + (Box::new(EqAbsSubtable::new()), SubtableIndices::from(0)), + (Box::new(LtAbsSubtable::new()), SubtableIndices::from(0)), + ( + Box::new(LeftIsZeroSubtable::new()), + SubtableIndices::from(0..C), + ), + ] + } + + fn to_indices(&self, C: usize, log_M: usize) -> Vec { + chunk_and_concatenate_operands(self.0, self.1, C, log_M) + } + + fn lookup_entry(&self) -> u64 { + match WORD_SIZE { + 32 => { + let remainder = self.0 as u32 as i32; + let divisor = self.1 as u32 as i32; + let is_remainder_zero = remainder == 0; + + if is_remainder_zero { + 1 + } else { + let remainder_sign = remainder >> 31; + let divisor_sign = divisor >> 31; + (remainder.abs() < divisor.abs() && remainder_sign == divisor_sign).into() + } + } + 64 => { + let remainder = self.0 as i64; + let divisor = self.1 as i64; + let is_remainder_zero = remainder == 0; + + if is_remainder_zero { + 1 + } else { + let remainder_sign = remainder >> 63; + let divisor_sign = divisor >> 63; + (remainder.abs() < divisor.abs() && remainder_sign == divisor_sign).into() + } + } + _ => panic!("Unsupported WORD_SIZE: {}", WORD_SIZE), + } + } + + fn random(&self, rng: &mut StdRng) -> Self { + Self(rng.next_u32() as u64, rng.next_u32() as u64) + } +} + +#[cfg(test)] +mod test { + use ark_bn254::Fr; + use ark_std::test_rng; + use rand_chacha::rand_core::RngCore; + + use crate::{jolt::instruction::JoltInstruction, jolt_instruction_test}; + + use super::ASSERTVALIDREMAINDERInstruction; + + #[test] + fn assert_valid_remainder_instruction_32_e2e() { + let mut rng = test_rng(); + const C: usize = 4; + const M: usize = 1 << 16; + + for _ in 0..256 { + let x = rng.next_u32() as u64; + let y = rng.next_u32() as u64; + let instruction = ASSERTVALIDREMAINDERInstruction::<32>(x, y); + jolt_instruction_test!(instruction); + } + let u32_max: u64 = u32::MAX as u64; + let instructions = vec![ + ASSERTVALIDREMAINDERInstruction::<32>(100, 0), + ASSERTVALIDREMAINDERInstruction::<32>(0, 100), + ASSERTVALIDREMAINDERInstruction::<32>(1, 0), + ASSERTVALIDREMAINDERInstruction::<32>(0, u32_max), + ASSERTVALIDREMAINDERInstruction::<32>(u32_max, 0), + ASSERTVALIDREMAINDERInstruction::<32>(u32_max, u32_max), + ASSERTVALIDREMAINDERInstruction::<32>(u32_max, 1 << 8), + ASSERTVALIDREMAINDERInstruction::<32>(1 << 8, u32_max), + ]; + for instruction in instructions { + jolt_instruction_test!(instruction); + } + } + + #[test] + fn assert_valid_remainder_instruction_64_e2e() { + let mut rng = test_rng(); + const C: usize = 8; + const M: usize = 1 << 16; + + for _ in 0..256 { + let (x, y) = (rng.next_u64(), rng.next_u64()); + let instruction = ASSERTVALIDREMAINDERInstruction::<64>(x, y); + jolt_instruction_test!(instruction); + } + for _ in 0..256 { + let x = rng.next_u64(); + let instruction = ASSERTVALIDREMAINDERInstruction::<64>(x, x); + jolt_instruction_test!(instruction); + } + } +} diff --git a/jolt-core/src/jolt/subtable/is_zero.rs b/jolt-core/src/jolt/subtable/left_is_zero.rs similarity index 73% rename from jolt-core/src/jolt/subtable/is_zero.rs rename to jolt-core/src/jolt/subtable/left_is_zero.rs index 81fc4e0a5..ca17e5fe9 100644 --- a/jolt-core/src/jolt/subtable/is_zero.rs +++ b/jolt-core/src/jolt/subtable/left_is_zero.rs @@ -5,11 +5,11 @@ use std::marker::PhantomData; use super::LassoSubtable; #[derive(Default)] -pub struct IsZeroSubtable { +pub struct LeftIsZeroSubtable { _field: PhantomData, } -impl IsZeroSubtable { +impl LeftIsZeroSubtable { pub fn new() -> Self { Self { _field: PhantomData, @@ -17,7 +17,7 @@ impl IsZeroSubtable { } } -impl LassoSubtable for IsZeroSubtable { +impl LassoSubtable for LeftIsZeroSubtable { fn materialize(&self, M: usize) -> Vec { let mut entries: Vec = vec![F::zero(); M]; @@ -49,19 +49,19 @@ mod test { use crate::{ field::binius::BiniusField, - jolt::subtable::{is_zero::IsZeroSubtable, LassoSubtable}, + jolt::subtable::{left_is_zero::LeftIsZeroSubtable, LassoSubtable}, subtable_materialize_mle_parity_test, }; subtable_materialize_mle_parity_test!( - is_zero_materialize_mle_parity, - IsZeroSubtable, + left_is_zero_materialize_mle_parity, + LeftIsZeroSubtable, Fr, 256 ); subtable_materialize_mle_parity_test!( - is_zero_binius_materialize_mle_parity, - IsZeroSubtable>, + left_is_zero_binius_materialize_mle_parity, + LeftIsZeroSubtable>, BiniusField, 1 << 16 ); diff --git a/jolt-core/src/jolt/subtable/mod.rs b/jolt-core/src/jolt/subtable/mod.rs index 72c03608c..0d4aecfe9 100644 --- a/jolt-core/src/jolt/subtable/mod.rs +++ b/jolt-core/src/jolt/subtable/mod.rs @@ -33,7 +33,7 @@ pub mod and; pub mod eq; pub mod eq_abs; pub mod identity; -pub mod is_zero; +pub mod left_is_zero; pub mod left_msb; pub mod lt_abs; pub mod ltu; From e88dcb1d892ea28529e13b62910556487887f453 Mon Sep 17 00:00:00 2001 From: Michael Zhu Date: Tue, 25 Jun 2024 15:57:59 -0400 Subject: [PATCH 08/43] Use ASSERTVALIDREMAINDERInstruction in DIV and REM --- common/src/rv_trace.rs | 9 +- jolt-core/src/jolt/instruction/div.rs | 81 ++++++----- jolt-core/src/jolt/instruction/mod.rs | 2 - jolt-core/src/jolt/instruction/rem.rs | 77 +++++----- .../instruction/virtual_assert_eq_signs.rs | 93 ------------ .../jolt/instruction/virtual_assert_lt_abs.rs | 132 ------------------ jolt-core/src/jolt/trace/rv.rs | 9 +- jolt-core/src/jolt/vm/rv32i_vm.rs | 9 +- 8 files changed, 90 insertions(+), 322 deletions(-) delete mode 100644 jolt-core/src/jolt/instruction/virtual_assert_eq_signs.rs delete mode 100644 jolt-core/src/jolt/instruction/virtual_assert_lt_abs.rs diff --git a/common/src/rv_trace.rs b/common/src/rv_trace.rs index c86409cea..4da128767 100644 --- a/common/src/rv_trace.rs +++ b/common/src/rv_trace.rs @@ -351,8 +351,7 @@ impl ELFInstruction { RV32IM::VIRTUAL_ASSERT_EQ | RV32IM::VIRTUAL_ASSERT_LTE | RV32IM::VIRTUAL_ASSERT_LTU | - RV32IM::VIRTUAL_ASSERT_LT_ABS | - RV32IM::VIRTUAL_ASSERT_EQ_SIGNS, + RV32IM::VIRTUAL_ASSERT_VALID_REMAINDER, ); flags @@ -447,8 +446,7 @@ pub enum RV32IM { VIRTUAL_ADVICE, VIRTUAL_ASSERT_LTU, VIRTUAL_ASSERT_LTE, - VIRTUAL_ASSERT_LT_ABS, - VIRTUAL_ASSERT_EQ_SIGNS, + VIRTUAL_ASSERT_VALID_REMAINDER, VIRTUAL_ASSERT_EQ, } @@ -578,8 +576,7 @@ impl RV32IM { RV32IM::VIRTUAL_ASSERT_EQ | RV32IM::VIRTUAL_ASSERT_LTE | RV32IM::VIRTUAL_ASSERT_LTU | - RV32IM::VIRTUAL_ASSERT_LT_ABS | - RV32IM::VIRTUAL_ASSERT_EQ_SIGNS => RV32InstructionFormat::SB, + RV32IM::VIRTUAL_ASSERT_VALID_REMAINDER => RV32InstructionFormat::SB, RV32IM::LUI | RV32IM::AUIPC | diff --git a/jolt-core/src/jolt/instruction/div.rs b/jolt-core/src/jolt/instruction/div.rs index 6acac272f..7a231d843 100644 --- a/jolt-core/src/jolt/instruction/div.rs +++ b/jolt-core/src/jolt/instruction/div.rs @@ -4,10 +4,10 @@ use tracer::{ELFInstruction, RVTraceRow, RegisterState, RV32IM}; use super::VirtualInstructionSequence; use crate::jolt::instruction::{ add::ADDInstruction, beq::BEQInstruction, mul::MULInstruction, - virtual_advice::ADVICEInstruction, virtual_assert_eq_signs::ASSERTEQSIGNSInstruction, - virtual_assert_lt_abs::ASSERTLTABSInstruction, JoltInstruction, + virtual_advice::ADVICEInstruction, + virtual_assert_valid_remainder::ASSERTVALIDREMAINDERInstruction, JoltInstruction, }; -/// Perform signed*unsigned multiplication and return the upper WORD_SIZE bits +/// Perform signed division and return the result pub struct DIVInstruction; impl VirtualInstructionSequence for DIVInstruction { @@ -26,8 +26,27 @@ impl VirtualInstructionSequence for DIVInstruction { + let mut quotient = x as i32 / y as i32; + let mut remainder = x as i32 % y as i32; + if (remainder < 0 && (y as i32) > 0) || (remainder > 0 && (y as i32) < 0) { + remainder += y as i32; + quotient -= 1; + } + (quotient as u32 as u64, remainder as u32 as u64) + } + 64 => { + let mut quotient = (x as i64 / y as i64) as i64; + let mut remainder = (x as i64 % y as i64) as i64; + if (remainder < 0 && (y as i64) > 0) || (remainder > 0 && (y as i64) < 0) { + remainder += y as i64; + quotient -= 1; + } + (quotient as u64, remainder as u64) + } + _ => panic!("Unsupported WORD_SIZE: {}", WORD_SIZE), + }; let q = ADVICEInstruction::(quotient).lookup_entry(); virtual_sequence.push(RVTraceRow { @@ -38,7 +57,7 @@ impl VirtualInstructionSequence for DIVInstruction VirtualInstructionSequence for DIVInstruction VirtualInstructionSequence for DIVInstruction(r, y).lookup_entry(); + let is_valid: u64 = ASSERTVALIDREMAINDERInstruction::(r, y).lookup_entry(); + assert_eq!(is_valid, 1); virtual_sequence.push(RVTraceRow { instruction: ELFInstruction { address: trace_row.instruction.address, - opcode: RV32IM::VIRTUAL_ASSERT_LT_ABS, + opcode: RV32IM::VIRTUAL_ASSERT_VALID_REMAINDER, rs1: v_r, rs2: r_y, rd: None, imm: None, - virtual_sequence_index: Some(2), - }, - register_state: RegisterState { - rs1_val: Some(r), - rs2_val: Some(y), - rd_post_val: None, - }, - memory_state: None, - advice_value: None, - }); - - let _assert_eq_signs = ASSERTEQSIGNSInstruction(r, y).lookup_entry(); - virtual_sequence.push(RVTraceRow { - instruction: ELFInstruction { - address: trace_row.instruction.address, - opcode: RV32IM::VIRTUAL_ASSERT_EQ_SIGNS, - rs1: v_r, - rs2: r_y, - rd: None, - imm: None, - virtual_sequence_index: Some(3), + virtual_sequence_index: Some(virtual_sequence.len()), }, register_state: RegisterState { rs1_val: Some(r), @@ -118,7 +118,7 @@ impl VirtualInstructionSequence for DIVInstruction VirtualInstructionSequence for DIVInstruction VirtualInstructionSequence for DIVInstruction 0) || (remainder > 0 && (y as i32) < 0) { + quotient -= 1; + } + let result = quotient as u32 as u64; let div_trace_row = RVTraceRow { instruction: ELFInstruction { @@ -228,13 +234,6 @@ mod test { assert_eq!(registers[row.instruction.rs2.unwrap() as usize], rs2_val); } - println!( - "rs1 {} rs2 {} instruction {:?}", - row.register_state.rs1_val.unwrap_or(0), - row.register_state.rs2_val.unwrap_or(0), - row.instruction - ); - let lookup = RV32I::try_from(&row).unwrap(); let output = lookup.lookup_entry(); if let Some(rd) = row.instruction.rd { diff --git a/jolt-core/src/jolt/instruction/mod.rs b/jolt-core/src/jolt/instruction/mod.rs index d1d175aee..ade6bb342 100644 --- a/jolt-core/src/jolt/instruction/mod.rs +++ b/jolt-core/src/jolt/instruction/mod.rs @@ -156,8 +156,6 @@ pub mod srl; pub mod sub; pub mod sw; pub mod virtual_advice; -pub mod virtual_assert_eq_signs; -pub mod virtual_assert_lt_abs; pub mod virtual_assert_lte; pub mod virtual_assert_valid_remainder; pub mod xor; diff --git a/jolt-core/src/jolt/instruction/rem.rs b/jolt-core/src/jolt/instruction/rem.rs index 35b954af9..e330e2569 100644 --- a/jolt-core/src/jolt/instruction/rem.rs +++ b/jolt-core/src/jolt/instruction/rem.rs @@ -4,11 +4,11 @@ use tracer::{ELFInstruction, RVTraceRow, RegisterState, RV32IM}; use super::VirtualInstructionSequence; use crate::jolt::instruction::{ add::ADDInstruction, beq::BEQInstruction, mul::MULInstruction, - virtual_advice::ADVICEInstruction, virtual_assert_eq_signs::ASSERTEQSIGNSInstruction, - virtual_assert_lt_abs::ASSERTLTABSInstruction, JoltInstruction, + virtual_advice::ADVICEInstruction, + virtual_assert_valid_remainder::ASSERTVALIDREMAINDERInstruction, JoltInstruction, }; -/// Perform signed*unsigned multiplication and return the upper WORD_SIZE bits +/// Perform signed division and return the remainder pub struct REMInstruction; impl VirtualInstructionSequence for REMInstruction { @@ -27,8 +27,27 @@ impl VirtualInstructionSequence for REMInstruction { + let mut quotient = x as i32 / y as i32; + let mut remainder = x as i32 % y as i32; + if (remainder < 0 && (y as i32) > 0) || (remainder > 0 && (y as i32) < 0) { + remainder += y as i32; + quotient -= 1; + } + (quotient as u32 as u64, remainder as u32 as u64) + } + 64 => { + let mut quotient = (x as i64 / y as i64) as i64; + let mut remainder = (x as i64 % y as i64) as i64; + if (remainder < 0 && (y as i64) > 0) || (remainder > 0 && (y as i64) < 0) { + remainder += y as i64; + quotient -= 1; + } + (quotient as u64, remainder as u64) + } + _ => panic!("Unsupported WORD_SIZE: {}", WORD_SIZE), + }; let q = ADVICEInstruction::(quotient).lookup_entry(); virtual_sequence.push(RVTraceRow { @@ -39,7 +58,7 @@ impl VirtualInstructionSequence for REMInstruction VirtualInstructionSequence for REMInstruction VirtualInstructionSequence for REMInstruction(r, y).lookup_entry(); - virtual_sequence.push(RVTraceRow { - instruction: ELFInstruction { - address: trace_row.instruction.address, - opcode: RV32IM::VIRTUAL_ASSERT_LT_ABS, - rs1: trace_row.instruction.rd, - rs2: r_y, - rd: None, - imm: None, - virtual_sequence_index: Some(2), - }, - register_state: RegisterState { - rs1_val: Some(r), - rs2_val: Some(y), - rd_post_val: None, - }, - memory_state: None, - advice_value: None, - }); - - let _assert_eq_signs = ASSERTEQSIGNSInstruction(r, y).lookup_entry(); + let is_valid: u64 = ASSERTVALIDREMAINDERInstruction::(r, y).lookup_entry(); + assert_eq!(is_valid, 1); virtual_sequence.push(RVTraceRow { instruction: ELFInstruction { address: trace_row.instruction.address, - opcode: RV32IM::VIRTUAL_ASSERT_EQ_SIGNS, + opcode: RV32IM::VIRTUAL_ASSERT_VALID_REMAINDER, rs1: trace_row.instruction.rd, rs2: r_y, rd: None, imm: None, - virtual_sequence_index: Some(3), + virtual_sequence_index: Some(virtual_sequence.len()), }, register_state: RegisterState { rs1_val: Some(r), @@ -119,7 +119,7 @@ impl VirtualInstructionSequence for REMInstruction VirtualInstructionSequence for REMInstruction VirtualInstructionSequence for REMInstruction 0) || (remainder > 0 && (y as i32) < 0) { + remainder += y as i32; + } + let result = remainder as u32 as u64; let rem_trace_row = RVTraceRow { instruction: ELFInstruction { @@ -223,7 +227,6 @@ mod test { registers[r_y as usize] = y; for row in virtual_sequence { - println!("{:?}", row.instruction); if let Some(rs1_val) = row.register_state.rs1_val { assert_eq!(registers[row.instruction.rs1.unwrap() as usize], rs1_val); } @@ -241,7 +244,7 @@ mod test { ); } else { // Virtual assert instruction - // assert!(output == 1); + assert!(output == 1); } } diff --git a/jolt-core/src/jolt/instruction/virtual_assert_eq_signs.rs b/jolt-core/src/jolt/instruction/virtual_assert_eq_signs.rs deleted file mode 100644 index c544d1cb8..000000000 --- a/jolt-core/src/jolt/instruction/virtual_assert_eq_signs.rs +++ /dev/null @@ -1,93 +0,0 @@ -use crate::field::JoltField; -use rand::prelude::StdRng; -use rand::RngCore; -use serde::{Deserialize, Serialize}; - -use super::{JoltInstruction, SubtableIndices}; -use crate::{ - jolt::subtable::{left_msb::LeftMSBSubtable, right_msb::RightMSBSubtable, LassoSubtable}, - utils::instruction_utils::chunk_and_concatenate_operands, -}; - -#[derive(Copy, Clone, Default, Debug, Serialize, Deserialize)] -pub struct ASSERTEQSIGNSInstruction(pub u64, pub u64); - -impl JoltInstruction for ASSERTEQSIGNSInstruction { - fn operands(&self) -> (u64, u64) { - (self.0, self.1) - } - - fn combine_lookups(&self, vals: &[F], _: usize, _: usize) -> F { - let left_msb = vals[0]; - let right_msb = vals[1]; - (left_msb * right_msb) + (F::one() - left_msb) * (F::one() - right_msb) - } - - fn g_poly_degree(&self, _: usize) -> usize { - 1 - } - - fn subtables( - &self, - _: usize, - _: usize, - ) -> Vec<(Box>, SubtableIndices)> { - vec![ - (Box::new(LeftMSBSubtable::new()), SubtableIndices::from(0)), - (Box::new(RightMSBSubtable::new()), SubtableIndices::from(0)), - ] - } - - fn to_indices(&self, C: usize, log_M: usize) -> Vec { - chunk_and_concatenate_operands(self.0, self.1, C, log_M) - } - - fn lookup_entry(&self) -> u64 { - ((self.0 as i32).signum() < 0 && (self.1 as i32).signum() < 0 - || (self.0 as i32).signum() >= 0 && (self.1 as i32).signum() >= 0) - .into() - } - - fn random(&self, rng: &mut StdRng) -> Self { - Self(rng.next_u32() as u64, rng.next_u32() as u64) - } -} - -#[cfg(test)] -mod test { - use ark_bn254::Fr; - use ark_std::test_rng; - use rand_chacha::rand_core::RngCore; - - use crate::{jolt::instruction::JoltInstruction, jolt_instruction_test}; - - use super::ASSERTEQSIGNSInstruction; - - #[test] - fn eq_signs_instruction_32_e2e() { - let mut rng = test_rng(); - const C: usize = 4; - const M: usize = 1 << 16; - - for _ in 0..256 { - let x = rng.next_u32() as u64; - let y = rng.next_u32() as u64; - let instruction = ASSERTEQSIGNSInstruction(x, y); - jolt_instruction_test!(instruction); - } - let u32_max: u64 = u32::MAX as u64; - let instructions = vec![ - ASSERTEQSIGNSInstruction(100, 0), - ASSERTEQSIGNSInstruction(0, 100), - ASSERTEQSIGNSInstruction(1, 0), - ASSERTEQSIGNSInstruction(0, u32_max), - ASSERTEQSIGNSInstruction(u32_max, 0), - ASSERTEQSIGNSInstruction(u32_max, u32_max), - ASSERTEQSIGNSInstruction(u32_max, 1 << 8), - ASSERTEQSIGNSInstruction(1 << 8, u32_max), - ]; - for instruction in instructions { - jolt_instruction_test!(instruction); - } - } -} diff --git a/jolt-core/src/jolt/instruction/virtual_assert_lt_abs.rs b/jolt-core/src/jolt/instruction/virtual_assert_lt_abs.rs deleted file mode 100644 index 36d138ab1..000000000 --- a/jolt-core/src/jolt/instruction/virtual_assert_lt_abs.rs +++ /dev/null @@ -1,132 +0,0 @@ -use crate::field::JoltField; -use rand::prelude::StdRng; -use rand::RngCore; -use serde::{Deserialize, Serialize}; - -use super::{JoltInstruction, SubtableIndices}; -use crate::{ - jolt::subtable::{ - eq::EqSubtable, eq_abs::EqAbsSubtable, lt_abs::LtAbsSubtable, ltu::LtuSubtable, - LassoSubtable, - }, - utils::instruction_utils::chunk_and_concatenate_operands, -}; - -#[derive(Copy, Clone, Default, Debug, Serialize, Deserialize)] -pub struct ASSERTLTABSInstruction(pub u64, pub u64); - -impl JoltInstruction for ASSERTLTABSInstruction { - fn operands(&self) -> (u64, u64) { - (self.0, self.1) - } - - fn combine_lookups(&self, vals: &[F], C: usize, M: usize) -> F { - let vals_by_subtable = self.slice_values(vals, C, M); - - let ltu = vals_by_subtable[0]; - let eq = vals_by_subtable[1]; - let lt_abs = vals_by_subtable[2]; - let eq_abs = vals_by_subtable[3]; - - // Accumulator for LTU(x_{ usize { - C + 1 - } - - fn subtables( - &self, - C: usize, - _: usize, - ) -> Vec<(Box>, SubtableIndices)> { - vec![ - (Box::new(LtuSubtable::new()), SubtableIndices::from(1..C)), - (Box::new(EqSubtable::new()), SubtableIndices::from(1..C)), - (Box::new(LtAbsSubtable::new()), SubtableIndices::from(0)), - (Box::new(EqAbsSubtable::new()), SubtableIndices::from(0)), - ] - } - - fn to_indices(&self, C: usize, log_M: usize) -> Vec { - chunk_and_concatenate_operands(self.0, self.1, C, log_M) - } - - fn lookup_entry(&self) -> u64 { - // 0b01111...11 - let lower_bits_mask = (1 << (WORD_SIZE - 1)) - 1; - ((self.0 & lower_bits_mask) < (self.1 & lower_bits_mask)).into() - } - - fn random(&self, rng: &mut StdRng) -> Self { - Self(rng.next_u32() as u64, rng.next_u32() as u64) - } -} - -#[cfg(test)] -mod test { - use ark_bn254::Fr; - use ark_std::test_rng; - use rand_chacha::rand_core::RngCore; - - use crate::{jolt::instruction::JoltInstruction, jolt_instruction_test}; - - use super::ASSERTLTABSInstruction; - - #[test] - fn lt_abs_instruction_32_e2e() { - let mut rng = test_rng(); - const C: usize = 4; - const M: usize = 1 << 16; - - for _ in 0..256 { - let x = rng.next_u32() as u64; - let y = rng.next_u32() as u64; - let instruction = ASSERTLTABSInstruction::<32>(x, y); - jolt_instruction_test!(instruction); - } - let u32_max: u64 = u32::MAX as u64; - let instructions = vec![ - ASSERTLTABSInstruction::<32>(100, 0), - ASSERTLTABSInstruction::<32>(0, 100), - ASSERTLTABSInstruction::<32>(1, 0), - ASSERTLTABSInstruction::<32>(0, u32_max), - ASSERTLTABSInstruction::<32>(u32_max, 0), - ASSERTLTABSInstruction::<32>(u32_max, u32_max), - ASSERTLTABSInstruction::<32>(u32_max, 1 << 8), - ASSERTLTABSInstruction::<32>(1 << 8, u32_max), - ]; - for instruction in instructions { - jolt_instruction_test!(instruction); - } - } - - #[test] - fn lt_abs_instruction_64_e2e() { - let mut rng = test_rng(); - const C: usize = 8; - const M: usize = 1 << 16; - - for _ in 0..256 { - let (x, y) = (rng.next_u64(), rng.next_u64()); - let instruction = ASSERTLTABSInstruction::<64>(x, y); - jolt_instruction_test!(instruction); - } - for _ in 0..256 { - let x = rng.next_u64(); - let instruction = ASSERTLTABSInstruction::<64>(x, x); - jolt_instruction_test!(instruction); - } - } -} diff --git a/jolt-core/src/jolt/trace/rv.rs b/jolt-core/src/jolt/trace/rv.rs index 3b9e5f4c4..aeeb06e5d 100644 --- a/jolt-core/src/jolt/trace/rv.rs +++ b/jolt-core/src/jolt/trace/rv.rs @@ -19,9 +19,8 @@ use crate::jolt::instruction::srl::SRLInstruction; use crate::jolt::instruction::sub::SUBInstruction; use crate::jolt::instruction::sw::SWInstruction; use crate::jolt::instruction::virtual_advice::ADVICEInstruction; -use crate::jolt::instruction::virtual_assert_eq_signs::ASSERTEQSIGNSInstruction; -use crate::jolt::instruction::virtual_assert_lt_abs::ASSERTLTABSInstruction; use crate::jolt::instruction::virtual_assert_lte::ASSERTLTEInstruction; +use crate::jolt::instruction::virtual_assert_valid_remainder::ASSERTVALIDREMAINDERInstruction; use crate::jolt::instruction::xor::XORInstruction; use crate::jolt::instruction::{add::ADDInstruction, movsign::MOVSIGNInstruction}; use crate::jolt::vm::rv32i_vm::RV32I; @@ -84,8 +83,7 @@ impl TryFrom<&ELFInstruction> for RV32I { RV32IM::VIRTUAL_ASSERT_EQ => Ok(BEQInstruction::default().into()), RV32IM::VIRTUAL_ASSERT_LTE => Ok(ASSERTLTEInstruction::default().into()), RV32IM::VIRTUAL_ASSERT_LTU => Ok(SLTUInstruction::default().into()), - RV32IM::VIRTUAL_ASSERT_LT_ABS => Ok(ASSERTLTABSInstruction::default().into()), - RV32IM::VIRTUAL_ASSERT_EQ_SIGNS => Ok(ASSERTEQSIGNSInstruction::default().into()), + RV32IM::VIRTUAL_ASSERT_VALID_REMAINDER => Ok(ASSERTVALIDREMAINDERInstruction::default().into()), _ => Err("No corresponding RV32I instruction") } @@ -149,8 +147,7 @@ impl TryFrom<&RVTraceRow> for RV32I { RV32IM::VIRTUAL_ASSERT_EQ => Ok(BEQInstruction(row.register_state.rs1_val.unwrap(), row.register_state.rs2_val.unwrap()).into()), RV32IM::VIRTUAL_ASSERT_LTE => Ok(ASSERTLTEInstruction(row.register_state.rs1_val.unwrap(), row.register_state.rs2_val.unwrap()).into()), RV32IM::VIRTUAL_ASSERT_LTU => Ok(SLTUInstruction(row.register_state.rs1_val.unwrap(), row.register_state.rs2_val.unwrap()).into()), - RV32IM::VIRTUAL_ASSERT_LT_ABS => Ok(ASSERTLTABSInstruction(row.register_state.rs1_val.unwrap(), row.register_state.rs2_val.unwrap()).into()), - RV32IM::VIRTUAL_ASSERT_EQ_SIGNS => Ok(ASSERTEQSIGNSInstruction(row.register_state.rs1_val.unwrap(), row.register_state.rs2_val.unwrap()).into()), + RV32IM::VIRTUAL_ASSERT_VALID_REMAINDER => Ok(ASSERTVALIDREMAINDERInstruction(row.register_state.rs1_val.unwrap(), row.register_state.rs2_val.unwrap()).into()), _ => Err("No corresponding RV32I instruction") } diff --git a/jolt-core/src/jolt/vm/rv32i_vm.rs b/jolt-core/src/jolt/vm/rv32i_vm.rs index 594d99ffb..909b908ed 100644 --- a/jolt-core/src/jolt/vm/rv32i_vm.rs +++ b/jolt-core/src/jolt/vm/rv32i_vm.rs @@ -14,9 +14,9 @@ use crate::jolt::instruction::{ mulu::MULUInstruction, or::ORInstruction, sb::SBInstruction, sh::SHInstruction, sll::SLLInstruction, slt::SLTInstruction, sltu::SLTUInstruction, sra::SRAInstruction, srl::SRLInstruction, sub::SUBInstruction, sw::SWInstruction, virtual_advice::ADVICEInstruction, - virtual_assert_eq_signs::ASSERTEQSIGNSInstruction, - virtual_assert_lt_abs::ASSERTLTABSInstruction, virtual_assert_lte::ASSERTLTEInstruction, - xor::XORInstruction, JoltInstruction, JoltInstructionSet, SubtableIndices, + virtual_assert_lte::ASSERTLTEInstruction, + virtual_assert_valid_remainder::ASSERTVALIDREMAINDERInstruction, xor::XORInstruction, + JoltInstruction, JoltInstructionSet, SubtableIndices, }; use crate::jolt::subtable::{ and::AndSubtable, eq::EqSubtable, eq_abs::EqAbsSubtable, identity::IdentitySubtable, @@ -110,8 +110,7 @@ instruction_set!( MULHU: MULHUInstruction, VIRTUAL_ADVICE: ADVICEInstruction, VIRTUAL_ASSERT_LTE: ASSERTLTEInstruction, - VIRTUAL_ASSERT_LT_ABS: ASSERTLTABSInstruction, - VIRTUAL_ASSERT_EQ_SIGNS: ASSERTEQSIGNSInstruction + VIRTUAL_ASSERT_VALID_REMAINDER: ASSERTVALIDREMAINDERInstruction ); subtable_enum!( RV32ISubtables, From 295c8bbd48b018f5ab03aa56b42d33a3ce43567a Mon Sep 17 00:00:00 2001 From: Michael Zhu Date: Tue, 25 Jun 2024 16:08:36 -0400 Subject: [PATCH 09/43] clippy --- jolt-core/src/jolt/instruction/div.rs | 4 ++-- jolt-core/src/jolt/instruction/rem.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/jolt-core/src/jolt/instruction/div.rs b/jolt-core/src/jolt/instruction/div.rs index 7a231d843..7d9985a72 100644 --- a/jolt-core/src/jolt/instruction/div.rs +++ b/jolt-core/src/jolt/instruction/div.rs @@ -37,8 +37,8 @@ impl VirtualInstructionSequence for DIVInstruction { - let mut quotient = (x as i64 / y as i64) as i64; - let mut remainder = (x as i64 % y as i64) as i64; + let mut quotient = x as i64 / y as i64; + let mut remainder = x as i64 % y as i64; if (remainder < 0 && (y as i64) > 0) || (remainder > 0 && (y as i64) < 0) { remainder += y as i64; quotient -= 1; diff --git a/jolt-core/src/jolt/instruction/rem.rs b/jolt-core/src/jolt/instruction/rem.rs index e330e2569..09d79e21d 100644 --- a/jolt-core/src/jolt/instruction/rem.rs +++ b/jolt-core/src/jolt/instruction/rem.rs @@ -38,8 +38,8 @@ impl VirtualInstructionSequence for REMInstruction { - let mut quotient = (x as i64 / y as i64) as i64; - let mut remainder = (x as i64 % y as i64) as i64; + let mut quotient = x as i64 / y as i64; + let mut remainder = x as i64 % y as i64; if (remainder < 0 && (y as i64) > 0) || (remainder > 0 && (y as i64) < 0) { remainder += y as i64; quotient -= 1; From 4e21ce7106886f3e0d1431a96d909c3e18a80466 Mon Sep 17 00:00:00 2001 From: Michael Zhu Date: Tue, 25 Jun 2024 16:30:30 -0400 Subject: [PATCH 10/43] Fix tests --- jolt-core/src/jolt/vm/rv32i_vm.rs | 12 +++++++----- jolt-core/src/r1cs/jolt_constraints.rs | 10 ++++++---- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/jolt-core/src/jolt/vm/rv32i_vm.rs b/jolt-core/src/jolt/vm/rv32i_vm.rs index 909b908ed..f4ebddf48 100644 --- a/jolt-core/src/jolt/vm/rv32i_vm.rs +++ b/jolt-core/src/jolt/vm/rv32i_vm.rs @@ -20,10 +20,11 @@ use crate::jolt::instruction::{ }; use crate::jolt::subtable::{ and::AndSubtable, eq::EqSubtable, eq_abs::EqAbsSubtable, identity::IdentitySubtable, - left_msb::LeftMSBSubtable, lt_abs::LtAbsSubtable, ltu::LtuSubtable, or::OrSubtable, - right_msb::RightMSBSubtable, sign_extend::SignExtendSubtable, sll::SllSubtable, - sra_sign::SraSignSubtable, srl::SrlSubtable, truncate_overflow::TruncateOverflowSubtable, - xor::XorSubtable, JoltSubtableSet, LassoSubtable, SubtableId, + left_is_zero::LeftIsZeroSubtable, left_msb::LeftMSBSubtable, lt_abs::LtAbsSubtable, + ltu::LtuSubtable, or::OrSubtable, right_msb::RightMSBSubtable, sign_extend::SignExtendSubtable, + sll::SllSubtable, sra_sign::SraSignSubtable, srl::SrlSubtable, + truncate_overflow::TruncateOverflowSubtable, xor::XorSubtable, JoltSubtableSet, LassoSubtable, + SubtableId, }; use crate::poly::commitment::commitment_scheme::CommitmentScheme; @@ -136,7 +137,8 @@ subtable_enum!( SRL3: SrlSubtable, TRUNCATE: TruncateOverflowSubtable, TRUNCATE_BYTE: TruncateOverflowSubtable, - XOR: XorSubtable + XOR: XorSubtable, + LEFT_IS_ZERO: LeftIsZeroSubtable ); // ==================== JOLT ==================== diff --git a/jolt-core/src/r1cs/jolt_constraints.rs b/jolt-core/src/r1cs/jolt_constraints.rs index 2df3cdd28..0edae7ddb 100644 --- a/jolt-core/src/r1cs/jolt_constraints.rs +++ b/jolt-core/src/r1cs/jolt_constraints.rs @@ -125,8 +125,7 @@ pub enum JoltIn { IF_MulHu, IF_Virt_Adv, IF_Virt_Assert_LTE, - IF_Virt_Assert_LT_ABS, - IF_Virt_Assert_EQ_SIGNS, + IF_Virt_Assert_VALID_REMAINDER, } impl_r1cs_input_lc_conversions!(JoltIn); impl ConstraintInput for JoltIn {} @@ -150,7 +149,10 @@ impl UniformJoltConstraints { impl R1CSConstraintBuilder for UniformJoltConstraints { type Inputs = JoltIn; fn build_constraints(&self, cs: &mut R1CSBuilder) { - let flags = input_range!(JoltIn::OpFlags_IsRs1Rs2, JoltIn::IF_Virt_Assert_EQ_SIGNS); + let flags = input_range!( + JoltIn::OpFlags_IsRs1Rs2, + JoltIn::IF_Virt_Assert_VALID_REMAINDER + ); for flag in flags { cs.constrain_binary(flag); } @@ -294,7 +296,7 @@ mod tests { #[test] fn instruction_flags_length() { assert_eq!( - input_range!(JoltIn::IF_Add, JoltIn::IF_Virt_Assert_EQ_SIGNS).len(), + input_range!(JoltIn::IF_Add, JoltIn::IF_Virt_Assert_VALID_REMAINDER).len(), RV32I::COUNT ); } From 3647c37cf7caf7105da0f4c18011c09fda0f953e Mon Sep 17 00:00:00 2001 From: sragss Date: Tue, 25 Jun 2024 17:21:51 -0700 Subject: [PATCH 11/43] switch sparsity ordering --- jolt-core/src/r1cs/builder.rs | 27 ++++- jolt-core/src/r1cs/key.rs | 2 +- jolt-core/src/r1cs/ops.rs | 5 + jolt-core/src/r1cs/special_polys.rs | 174 ++++++++++++---------------- jolt-core/src/utils/thread.rs | 8 +- 5 files changed, 109 insertions(+), 107 deletions(-) diff --git a/jolt-core/src/r1cs/builder.rs b/jolt-core/src/r1cs/builder.rs index e16bd7f7f..1a350547e 100644 --- a/jolt-core/src/r1cs/builder.rs +++ b/jolt-core/src/r1cs/builder.rs @@ -878,15 +878,16 @@ impl CombinedUniformBuilder { // TODO(sragss): Attempt moving onto key and computing from materialized rows rather than linear combos let span = tracing::span!(tracing::Level::DEBUG, "compute_constraints"); let enter = span.enter(); - let az_chunks = Az.par_chunks_mut(self.uniform_repeat); - let bz_chunks = Bz.par_chunks_mut(self.uniform_repeat); - let cz_chunks = Cz.par_chunks_mut(self.uniform_repeat); + let az_chunks = Az.chunks_mut(self.uniform_repeat); + let bz_chunks = Bz.chunks_mut(self.uniform_repeat); + let cz_chunks = Cz.chunks_mut(self.uniform_repeat); self.uniform_builder .constraints - .par_iter() + .iter() + .enumerate() .zip(az_chunks.zip(bz_chunks.zip(cz_chunks))) - .for_each(|(constraint, (az_chunk, (bz_chunk, cz_chunk)))| { + .for_each(|((constraint_index, constraint), (az_chunk, (bz_chunk, cz_chunk)))| { let a_inputs = batch_inputs(&constraint.a); let b_inputs = batch_inputs(&constraint.b); let c_inputs = batch_inputs(&constraint.c); @@ -894,9 +895,25 @@ impl CombinedUniformBuilder { constraint.a.evaluate_batch_mut(&a_inputs, az_chunk); constraint.b.evaluate_batch_mut(&b_inputs, bz_chunk); constraint.c.evaluate_batch_mut(&c_inputs, cz_chunk); + + let az_zero = az_chunk.iter().filter(|item| item.is_zero()).count(); + let bz_zero = bz_chunk.iter().filter(|item| item.is_zero()).count(); + let cz_zero = cz_chunk.iter().filter(|item| item.is_zero()).count(); + + println!("[{constraint_index}] empty map az: {} bz: {} cz: {}", az_zero == az_chunk.len(), bz_zero == bz_chunk.len(), cz_zero == cz_chunk.len()); }); drop(enter); + let az_non_zero = Az.iter().filter(|item| !item.is_zero()).count(); + let bz_non_zero = Bz.iter().filter(|item| !item.is_zero()).count(); + let cz_non_zero = Cz.iter().filter(|item| !item.is_zero()).count(); + + println!("Uniform repeat: {}", self.uniform_repeat); + println!("Num constraints: {constraint_rows}"); + println!("Az sparsity: {az_non_zero}/{}", Az.len()); + println!("Bz sparsity: {bz_non_zero}/{}", Bz.len()); + println!("Cz sparsity: {cz_non_zero}/{}", Cz.len()); + // offset_equality_constraints: Xz[uniform_constraint_rows..uniform_constraint_rows + 1] // (a - b) * condition == 0 // For the final step we will not compute the offset terms, and will assume the condition to be set to 0 diff --git a/jolt-core/src/r1cs/key.rs b/jolt-core/src/r1cs/key.rs index f361c03dd..f4dcfb166 100644 --- a/jolt-core/src/r1cs/key.rs +++ b/jolt-core/src/r1cs/key.rs @@ -269,7 +269,7 @@ impl UniformSpartanKey { let eval_variables: F = (0..self.uniform_r1cs.num_vars) .map(|var_index| r_var_eq[var_index] * segment_evals[var_index]) .sum(); - let const_poly = SparsePolynomial::new(self.num_vars_total().log_2(), vec![(0, F::one())]); + let const_poly = SparsePolynomial::new(self.num_vars_total().log_2(), vec![(F::one(), 0)]); let eval_const = const_poly.evaluate(r_rest); (F::one() - r_const) * eval_variables + r_const * eval_const diff --git a/jolt-core/src/r1cs/ops.rs b/jolt-core/src/r1cs/ops.rs index 48d6c06bf..6cb179490 100644 --- a/jolt-core/src/r1cs/ops.rs +++ b/jolt-core/src/r1cs/ops.rs @@ -129,6 +129,11 @@ impl LC { let terms: Vec = self.to_field_elements(); + if terms.len() == 0 { + println!("no terms"); + return; + } + output .par_iter_mut() .enumerate() diff --git a/jolt-core/src/r1cs/special_polys.rs b/jolt-core/src/r1cs/special_polys.rs index 76b1aab3f..dba878c9c 100644 --- a/jolt-core/src/r1cs/special_polys.rs +++ b/jolt-core/src/r1cs/special_polys.rs @@ -6,11 +6,11 @@ use rayon::prelude::*; pub struct SparsePolynomial { num_vars: usize, - Z: Vec<(usize, F)>, + Z: Vec<(F, usize)>, } impl SparsePolynomial { - pub fn new(num_vars: usize, Z: Vec<(usize, F)>) -> Self { + pub fn new(num_vars: usize, Z: Vec<(F, usize)>) -> Self { SparsePolynomial { num_vars, Z } } @@ -18,13 +18,23 @@ impl SparsePolynomial { #[tracing::instrument(skip_all)] pub fn from_dense_evals(num_vars: usize, evals: Vec) -> Self { assert!(num_vars.pow2() >= evals.len()); - let non_zero_count: usize = evals.par_iter().filter(|f| !f.is_zero()).count(); - let mut sparse: Vec<(usize, F)> = Vec::with_capacity(non_zero_count); - evals.into_iter().enumerate().for_each(|(dense_index, f)| { - if !f.is_zero() { - sparse.push((dense_index, f)); + let non_zero_count: usize = evals.par_chunks(10_000).map(|chunk| chunk.iter().filter(|f| !f.is_zero()).count()).sum(); + + let span_allocate = tracing::span!(tracing::Level::DEBUG, "allocate"); + let _enter_allocate = span_allocate.enter(); + let mut sparse: Vec<(F, usize)> = unsafe_allocate_sparse_zero_vec(non_zero_count); + drop(_enter_allocate); + + let span_copy = tracing::span!(tracing::Level::DEBUG, "copy"); + let _enter_copy = span_copy.enter(); + let mut sparse_index = 0; + for (dense_index, dense) in evals.iter().enumerate() { + if !dense.is_zero() { + sparse[sparse_index] = (*dense, dense_index); + sparse_index += 1; } - }); + } + drop(_enter_copy); Self::new(num_vars, sparse) } @@ -50,27 +60,27 @@ impl SparsePolynomial { (0..self.Z.len()) .into_par_iter() .map(|i| { - let bits = get_bits(self.Z[0].0, r.len()); - SparsePolynomial::compute_chi(&bits, r) * self.Z[i].1 + let bits = get_bits(self.Z[0].1, r.len()); + SparsePolynomial::compute_chi(&bits, r) * self.Z[i].0 }) .sum() } /// Returns n chunks of roughly even size without orphaning siblings (adjacent dense indices). Additionally returns a vector of (low, high] dense index ranges. #[tracing::instrument(skip_all)] - fn chunk_no_orphans(&self, n: usize) -> (Vec<&[(usize, F)]>, Vec<(usize, usize)>) { + fn chunk_no_orphans(&self, n: usize) -> (Vec<&[(F, usize)]>, Vec<(usize, usize)>) { if self.Z.len() < n * 2 { return (vec![(&self.Z)], vec![(0, self.num_vars.pow2())]); } let target_chunk_size = self.Z.len() / n; - let mut chunks: Vec<&[(usize, F)]> = Vec::with_capacity(n); + let mut chunks: Vec<&[(F, usize)]> = Vec::with_capacity(n); let mut dense_ranges: Vec<(usize, usize)> = Vec::with_capacity(n); let mut dense_start_index = 0; let mut sparse_start_index = 0; let mut sparse_end_index = target_chunk_size; for _ in 1..n { - let mut dense_end_index = self.Z[sparse_end_index].0; + let mut dense_end_index = self.Z[sparse_end_index].1; if dense_end_index % 2 != 0 { dense_end_index += 1; sparse_end_index += 1; @@ -83,9 +93,7 @@ impl SparsePolynomial { sparse_end_index = std::cmp::min(sparse_end_index + target_chunk_size, self.Z.len() - 1); } chunks.push(&self.Z[sparse_start_index..]); - // TODO(sragss): likely makes more sense to return full range then truncate when needed (triple iterator) - // TODO(sragss): To use chunk_no_orphans in the triple iterator, we have to overwrite the top of the dense_ranges. - let highest_non_zero = self.Z.last().map(|&(index, _)| index).unwrap(); + let highest_non_zero = self.Z.last().map(|&(_, index)| index).unwrap(); dense_ranges.push((dense_start_index, highest_non_zero + 1)); assert_eq!(chunks.len(), n); assert_eq!(dense_ranges.len(), n); @@ -100,25 +108,24 @@ impl SparsePolynomial { let n = self.Z.len(); let span = tracing::span!(tracing::Level::DEBUG, "allocate"); let _enter = span.enter(); - let mut new_Z: Vec<(usize, F)> = Vec::with_capacity(n); + let mut new_Z: Vec<(F, usize)> = Vec::with_capacity(n); drop(_enter); - for (sparse_index, (dense_index, value)) in self.Z.iter().enumerate() { + for (sparse_index, (value, dense_index)) in self.Z.iter().enumerate() { if dense_index.is_even() { let new_dense_index = dense_index / 2; - // TODO(sragss): Can likely combine these conditions for better speculative execution. - if self.Z.len() >= 2 && sparse_index <= self.Z.len() - 2 && self.Z[sparse_index + 1].0 == dense_index + 1 { - let upper = self.Z[sparse_index + 1].1; + if self.Z.len() >= 2 && sparse_index <= self.Z.len() - 2 && self.Z[sparse_index + 1].1 == dense_index + 1 { + let upper = self.Z[sparse_index + 1].0; let eval = *value + *r * (upper - value); - new_Z.push((new_dense_index, eval)); + new_Z.push((eval, new_dense_index)); } else { - new_Z.push((new_dense_index, (F::one() - r) * value)); + new_Z.push(((F::one() - r) * value, new_dense_index)); } } else { - if sparse_index > 0 && self.Z[sparse_index - 1].0 == dense_index - 1 { + if sparse_index > 0 && self.Z[sparse_index - 1].1 == dense_index - 1 { continue; } else { let new_dense_index = (dense_index - 1) / 2; - new_Z.push((new_dense_index, *r * value)); + new_Z.push((*r * value, new_dense_index)); } } } @@ -139,7 +146,7 @@ impl SparsePolynomial { chunk_size += 1; // If they're siblings, avoid double counting - if chunk[i].0.is_even() && i + 1 < chunk.len() && chunk[i].0 + 1 == chunk[i + 1].0 { + if chunk[i].1.is_even() && i + 1 < chunk.len() && chunk[i].1 + 1 == chunk[i + 1].1 { i += 1; } i += 1; @@ -151,10 +158,10 @@ impl SparsePolynomial { let alloc_span = tracing::span!(tracing::Level::DEBUG, "alloc_new_Z"); let alloc_enter = alloc_span.enter(); let total_len: usize = chunk_sizes.iter().sum(); - let mut new_Z: Vec<(usize, F)> = unsafe_allocate_sparse_zero_vec(total_len); + let mut new_Z: Vec<(F, usize)> = unsafe_allocate_sparse_zero_vec(total_len); drop(alloc_enter); - let mut mutable_chunks: Vec<&mut [(usize, F)]> = vec![]; + let mut mutable_chunks: Vec<&mut [(F, usize)]> = vec![]; let mut remainder = new_Z.as_mut_slice(); for chunk_size in chunk_sizes { let (first, second) = remainder.split_at_mut(chunk_size); @@ -163,61 +170,34 @@ impl SparsePolynomial { } assert_eq!(mutable_chunks.len(), chunks.len()); - // TODO(sragsss): We can scan up front and collect directly into the thing. chunks.into_par_iter().zip(mutable_chunks.par_iter_mut()).for_each(|(chunk, mutable)| { let span = tracing::span!(tracing::Level::DEBUG, "chunk"); let _enter = span.enter(); - // TODO(sragss): Do this with a scan instead; - // let mut chunk_Z: Vec<(usize, F)> = Vec::with_capacity(chunk.len()); let mut write_index = 0; - for (sparse_index, (dense_index, value)) in chunk.iter().enumerate() { + for (sparse_index, (value, dense_index)) in chunk.iter().enumerate() { if dense_index.is_even() { let new_dense_index = dense_index / 2; - // TODO(sragss): Can likely combine these conditions for better speculative execution. - - // All exist - if chunk.len() >= 2 && sparse_index <= chunk.len() - 2 && chunk[sparse_index + 1].0 == dense_index + 1 { - let upper = chunk[sparse_index + 1].1; + if chunk.len() >= 2 && sparse_index <= chunk.len() - 2 && chunk[sparse_index + 1].1 == dense_index + 1 { + let upper = chunk[sparse_index + 1].0; let eval = *value + mul_0_1_optimized(r, &(upper - value)); - mutable[write_index] = (new_dense_index, eval); + mutable[write_index] = (eval, new_dense_index); write_index += 1; - } else { // low exists - mutable[write_index] = (new_dense_index, mul_0_1_optimized(&(F::one() - r), value)); + } else { + mutable[write_index] = (mul_0_1_optimized(&(F::one() - r), value), new_dense_index); write_index += 1; } } else { - // low and high exist - if sparse_index > 0 && chunk[sparse_index - 1].0 == dense_index - 1 { + if sparse_index > 0 && chunk[sparse_index - 1].1 == dense_index - 1 { continue; - } else { // high only exists + } else { let new_dense_index = (dense_index - 1) / 2; - mutable[write_index] = (new_dense_index, mul_0_1_optimized(r, value)); + mutable[write_index] = (mul_0_1_optimized(r, value), new_dense_index); write_index += 1; } } } }); - // for (sparse_index, (dense_index, value)) in self.Z.iter().enumerate() { - // if dense_index.is_even() { - // let new_dense_index = dense_index / 2; - // // TODO(sragss): Can likely combine these conditions for better speculative execution. - // if self.Z.len() >= 2 && sparse_index <= self.Z.len() - 2 && self.Z[sparse_index + 1].0 == dense_index + 1 { - // let upper = self.Z[sparse_index + 1].1; - // let eval = *value + *r * (upper - value); - // new_Z.push((new_dense_index, eval)); - // } else { - // new_Z.push((new_dense_index, (F::one() - r) * value)); - // } - // } else { - // if sparse_index > 0 && self.Z[sparse_index - 1].0 == dense_index - 1 { - // continue; - // } else { - // let new_dense_index = (dense_index - 1) / 2; - // new_Z.push((new_dense_index, *r * value)); - // } - // } - // } let old_Z = std::mem::replace(&mut self.Z, new_Z); drop_in_background_thread(old_Z); self.num_vars -= 1; @@ -230,8 +210,8 @@ impl SparsePolynomial { } else { assert_eq!(self.Z.len(), 1); let item = self.Z[0]; - assert_eq!(item.0, 0); - item.1 + assert_eq!(item.1, 0); + item.0 } } @@ -242,7 +222,7 @@ impl SparsePolynomial { let mut evals = unsafe_allocate_zero_vec(self.num_vars.pow2()); - for (index, value) in self.Z { + for (value, index) in self.Z { evals[index] = value; } @@ -253,9 +233,9 @@ impl SparsePolynomial { pub struct SparseTripleIterator<'a, F: JoltField> { dense_index: usize, end_index: usize, - a: &'a [(usize, F)], - b: &'a [(usize, F)], - c: &'a [(usize, F)], + a: &'a [(F, usize)], + b: &'a [(F, usize)], + c: &'a [(F, usize)], } impl<'a, F: JoltField> SparseTripleIterator<'a, F> { @@ -278,13 +258,13 @@ impl<'a, F: JoltField> SparseTripleIterator<'a, F> { // TODO(sragss): Explain the strategy let target_chunk_size = b.Z.len() / n; - let mut b_chunks: Vec<&[(usize, F)]> = Vec::with_capacity(n); + let mut b_chunks: Vec<&[(F, usize)]> = Vec::with_capacity(n); let mut dense_ranges: Vec<(usize, usize)> = Vec::with_capacity(n); let mut dense_start_index = 0; let mut sparse_start_index = 0; let mut sparse_end_index = target_chunk_size; for _ in 1..n { - let mut dense_end_index = b.Z[sparse_end_index].0; + let mut dense_end_index = b.Z[sparse_end_index].1; if dense_end_index % 2 != 0 { dense_end_index += 1; sparse_end_index += 1; @@ -298,9 +278,9 @@ impl<'a, F: JoltField> SparseTripleIterator<'a, F> { } b_chunks.push(&b.Z[sparse_start_index..]); let highest_non_zero = { - let a_last = a.Z.last().map(|&(index, _)| index); - let b_last = b.Z.last().map(|&(index, _)| index); - let c_last = c.Z.last().map(|&(index, _)| index); + let a_last = a.Z.last().map(|&(_, index)| index); + let b_last = b.Z.last().map(|&(_, index)| index); + let c_last = c.Z.last().map(|&(_, index)| index); *a_last.iter().chain(b_last.iter()).chain(c_last.iter()).max().unwrap() }; dense_ranges.push((dense_start_index, highest_non_zero + 1)); @@ -308,8 +288,8 @@ impl<'a, F: JoltField> SparseTripleIterator<'a, F> { assert_eq!(dense_ranges.len(), n); // Create chunks which overlap with b's sparse indices - let mut a_chunks: Vec<&[(usize, F)]> = vec![&[]; n]; - let mut c_chunks: Vec<&[(usize, F)]> = vec![&[]; n]; + let mut a_chunks: Vec<&[(F, usize)]> = vec![&[]; n]; + let mut c_chunks: Vec<&[(F, usize)]> = vec![&[]; n]; let mut a_i = 0; let mut c_i = 0; let span = tracing::span!(tracing::Level::DEBUG, "a, c scanning"); @@ -318,18 +298,18 @@ impl<'a, F: JoltField> SparseTripleIterator<'a, F> { // Find the corresponding a, c chunks let prev_chunk_end = range.0; - if a_i < a.Z.len() && a.Z[a_i].0 < prev_chunk_end { + if a_i < a.Z.len() && a.Z[a_i].1 < prev_chunk_end { let a_start = a_i; - while a_i < a.Z.len() && a.Z[a_i].0 < prev_chunk_end { + while a_i < a.Z.len() && a.Z[a_i].1 < prev_chunk_end { a_i += 1; } a_chunks[chunk_index - 1] = &a.Z[a_start..a_i]; } - if c_i < c.Z.len() && c.Z[c_i].0 < prev_chunk_end { + if c_i < c.Z.len() && c.Z[c_i].1 < prev_chunk_end { let c_start = c_i; - while c_i < c.Z.len() && c.Z[c_i].0 < prev_chunk_end { + while c_i < c.Z.len() && c.Z[c_i].1 < prev_chunk_end { c_i += 1; } @@ -352,9 +332,9 @@ impl<'a, F: JoltField> SparseTripleIterator<'a, F> { for (((a_chunk, b_chunk), c_chunk), range) in a_chunks.iter().zip(b_chunks.iter()).zip(c_chunks.iter()).zip(dense_ranges.iter()) { #[cfg(test)] { - assert!(a_chunk.iter().all(|(index, _)| *index >= range.0 && *index <= range.1)); - assert!(b_chunk.iter().all(|(index, _)| *index >= range.0 && *index <= range.1)); - assert!(c_chunk.iter().all(|(index, _)| *index >= range.0 && *index <= range.1)); + assert!(a_chunk.iter().all(|(_, index)| *index >= range.0 && *index <= range.1)); + assert!(b_chunk.iter().all(|(_, index)| *index >= range.0 && *index <= range.1)); + assert!(c_chunk.iter().all(|(_, index)| *index >= range.0 && *index <= range.1)); } let iter = SparseTripleIterator { dense_index: range.0, @@ -376,10 +356,10 @@ impl<'a, F: JoltField> SparseTripleIterator<'a, F> { pub fn next_pairs(&mut self) -> (usize, F, F, F, F, F, F) { // TODO(sragss): We can store a map of big ranges of zeros and skip them rather than hitting each dense index. let low_index = self.dense_index; - let match_and_advance = |slice: &mut &[(usize, F)], index: usize| -> F { + let match_and_advance = |slice: &mut &[(F, usize)], index: usize| -> F { if let Some(first_item) = slice.first() { - if first_item.0 == index { - let ret = first_item.1; + if first_item.1 == index { + let ret = first_item.0; *slice = &slice[1..]; ret } else { @@ -533,7 +513,7 @@ mod tests { #[test] fn sparse_bound_bot_all_left() { let dense_evals = vec![Fr::from(10), Fr::zero(), Fr::from(20), Fr::zero()]; - let sparse_evals = vec![(0, Fr::from(10)), (2, Fr::from(20))]; + let sparse_evals = vec![(Fr::from(10), 0), (Fr::from(20), 2)]; let mut dense = DensePolynomial::new(dense_evals); let mut sparse = SparsePolynomial::new(2, sparse_evals); @@ -549,7 +529,7 @@ mod tests { #[test] fn sparse_bound_bot_all_right() { let dense_evals = vec![Fr::zero(), Fr::from(10), Fr::zero(), Fr::from(20)]; - let sparse_evals = vec![(1, Fr::from(10)), (3, Fr::from(20))]; + let sparse_evals = vec![(Fr::from(10), 1), (Fr::from(20), 3)]; let mut dense = DensePolynomial::new(dense_evals); let mut sparse = SparsePolynomial::new(2, sparse_evals); @@ -565,7 +545,7 @@ mod tests { #[test] fn sparse_bound_bot_mixed() { let dense_evals = vec![Fr::zero(), Fr::from(10), Fr::zero(), Fr::from(20), Fr::from(30), Fr::from(40), Fr::zero(), Fr::from(50)]; - let sparse_evals = vec![(1, Fr::from(10)), (3, Fr::from(20)), (4, Fr::from(30)), (5, Fr::from(40)), (7, Fr::from(50))]; + let sparse_evals = vec![(Fr::from(10), 1), (Fr::from(20), 3), (Fr::from(30), 4), (Fr::from(40), 5), (Fr::from(50), 7)]; let mut dense = DensePolynomial::new(dense_evals); let mut sparse = SparsePolynomial::new(3, sparse_evals); @@ -580,9 +560,9 @@ mod tests { #[test] fn sparse_triple_iterator() { - let a = vec![(9, Fr::from(9)), (10, Fr::from(10)), (12, Fr::from(12))]; - let b = vec![(0, Fr::from(100)), (1, Fr::from(1)), (2, Fr::from(2)), (3, Fr::from(3)), (4, Fr::from(4)), (5, Fr::from(5)), (6, Fr::from(6)), (7, Fr::from(7)), (8, Fr::from(8)), (9, Fr::from(9)), (10, Fr::from(10)), (11, Fr::from(11)), (12, Fr::from(12)), (13, Fr::from(13)), (14, Fr::from(14)), (15, Fr::from(15))]; - let c = vec![(0, Fr::from(12)), (3, Fr::from(3))]; + let a = vec![(Fr::from(9), 9), (Fr::from(10), 10), (Fr::from(12), 12)]; + let b = vec![(Fr::from(100), 0), (Fr::from(1), 1), (Fr::from(2), 2), (Fr::from(3), 3), (Fr::from(4), 4), (Fr::from(5), 5), (Fr::from(6), 6), (Fr::from(7), 7), (Fr::from(8), 8), (Fr::from(9), 9), (Fr::from(10), 10), (Fr::from(11), 11), (Fr::from(12), 12), (Fr::from(13), 13), (Fr::from(14), 14), (Fr::from(15), 15)]; + let c = vec![(Fr::from(12), 0), (Fr::from(3), 3)]; let a_poly = SparsePolynomial::new(4, a); let b_poly = SparsePolynomial::new(4, b); @@ -608,13 +588,13 @@ mod tests { for i in 0usize..total_len { if rng.gen::() < prob_exists { - a.push((i, Fr::from(i as u64))); + a.push((Fr::from(i as u64), i)); } if rng.gen::() < prob_exists * 2f64 { - b.push((i, Fr::from(i as u64))); + b.push((Fr::from(i as u64), i)); } if rng.gen::() < prob_exists { - c.push((i, Fr::from(i as u64))); + c.push((Fr::from(i as u64), i)); } } @@ -662,7 +642,7 @@ mod tests { let mut a = vec![]; for i in 0usize..total_len { if rng.gen::() < prob_exists { - a.push((i, Fr::from(i as u64))); + a.push((Fr::from(i as u64), i)); } } diff --git a/jolt-core/src/utils/thread.rs b/jolt-core/src/utils/thread.rs index eda50a466..7deaa28e6 100644 --- a/jolt-core/src/utils/thread.rs +++ b/jolt-core/src/utils/thread.rs @@ -45,7 +45,7 @@ pub fn unsafe_allocate_zero_vec(size: usize) -> Vec { } #[tracing::instrument(skip_all, name = "unsafe_allocate_sparse_zero_vec")] -pub fn unsafe_allocate_sparse_zero_vec(size: usize) -> Vec<(usize, F)> { +pub fn unsafe_allocate_sparse_zero_vec(size: usize) -> Vec<(F, usize)> { // Check for safety of 0 allocation unsafe { let value = &F::zero(); @@ -55,10 +55,10 @@ pub fn unsafe_allocate_sparse_zero_vec(size: usize) -> Vec } // Bulk allocate zeros, unsafely - let result: Vec<(usize, F)>; + let result: Vec<(F, usize)>; unsafe { - let layout = std::alloc::Layout::array::<(usize, F)>(size).unwrap(); - let ptr = std::alloc::alloc_zeroed(layout) as *mut (usize, F); + let layout = std::alloc::Layout::array::<(F, usize)>(size).unwrap(); + let ptr = std::alloc::alloc_zeroed(layout) as *mut (F, usize); if ptr.is_null() { panic!("Zero vec allocation failed"); From 7817ca785193e9a2fa4f1d95087f8b1f22248494 Mon Sep 17 00:00:00 2001 From: sragss Date: Tue, 25 Jun 2024 21:24:44 -0700 Subject: [PATCH 12/43] e2e sparsity working --- jolt-core/src/r1cs/builder.rs | 154 ++++++++++++++++------------ jolt-core/src/r1cs/ops.rs | 5 - jolt-core/src/r1cs/special_polys.rs | 2 +- jolt-core/src/utils/thread.rs | 48 ++++++++- 4 files changed, 137 insertions(+), 72 deletions(-) diff --git a/jolt-core/src/r1cs/builder.rs b/jolt-core/src/r1cs/builder.rs index 1a350547e..340f2edde 100644 --- a/jolt-core/src/r1cs/builder.rs +++ b/jolt-core/src/r1cs/builder.rs @@ -2,7 +2,7 @@ use crate::{ field::{JoltField, OptimizedMul}, r1cs::key::{SparseConstraints, UniformR1CS}, utils::{ - math::Math, mul_0_1_optimized, thread::{drop_in_background_thread, unsafe_allocate_zero_vec} + math::Math, mul_0_1_optimized, thread::{drop_in_background_thread, par_flatten_triple, unsafe_allocate_sparse_zero_vec, unsafe_allocate_zero_vec} }, }; #[allow(unused_imports)] // clippy thinks these aren't needed lol @@ -21,12 +21,19 @@ pub trait R1CSConstraintBuilder { fn build_constraints(&self, builder: &mut R1CSBuilder); } +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum EvaluationHint { + Zero = 0, + Other = 2, +} + /// Constraints over a single row. Each variable points to a single item in Z and the corresponding coefficient. #[derive(Clone, Debug)] struct Constraint { a: LC, b: LC, c: LC, + evaluation_hint: (EvaluationHint, EvaluationHint, EvaluationHint) } impl Constraint { @@ -224,6 +231,7 @@ impl R1CSBuilder { a, b, c: LC::zero(), + evaluation_hint: (EvaluationHint::Zero, EvaluationHint::Other, EvaluationHint::Zero) }; self.constraints.push(constraint); } @@ -242,7 +250,7 @@ impl R1CSBuilder { let a = condition; let b = left - right; let c = LC::zero(); - let constraint = Constraint { a, b, c }; + let constraint = Constraint { a, b, c, evaluation_hint: (EvaluationHint::Other, EvaluationHint::Other, EvaluationHint::Zero) }; // TODO(sragss): Can do better on middle term. self.constraints.push(constraint); } @@ -250,11 +258,12 @@ impl R1CSBuilder { let one: LC = Variable::Constant.into(); let a: LC = value.into(); let b = one - a.clone(); - // value * (1 - value) + // value * (1 - value) == 0 let constraint = Constraint { a, b, c: LC::zero(), + evaluation_hint: (EvaluationHint::Other, EvaluationHint::Other, EvaluationHint::Zero) }; self.constraints.push(constraint); } @@ -278,6 +287,7 @@ impl R1CSBuilder { a: condition.clone(), b: (result_true - result_false.clone()), c: (alleged_result - result_false), + evaluation_hint: (EvaluationHint::Other, EvaluationHint::Other, EvaluationHint::Other) // TODO(sragss): Is this the best we can do? }; self.constraints.push(constraint); } @@ -423,6 +433,7 @@ impl R1CSBuilder { a: x.into(), b: y.into(), c: z.into(), + evaluation_hint: (EvaluationHint::Other, EvaluationHint::Other, EvaluationHint::Other) }; self.constraints.push(constraint); } @@ -849,7 +860,7 @@ impl CombinedUniformBuilder { /// inputs should be of the format [[I::0, I::0, ...], [I::1, I::1, ...], ... [I::N, I::N]] /// aux should be of the format [[Aux(0), Aux(0), ...], ... [Aux(self.next_aux - 1), ...]] - #[tracing::instrument(skip_all, name = "CombinedUniformBuilder::compute_spartan")] + #[tracing::instrument(skip_all, name = "CombinedUniformBuilder::compute_spartan_sparse")] pub fn compute_spartan_Az_Bz_Cz_sparse( &self, inputs: &[Vec], @@ -864,55 +875,69 @@ impl CombinedUniformBuilder { .all(|inner_input| inner_input.len() == self.uniform_repeat)); let uniform_constraint_rows = self.uniform_repeat_constraint_rows(); - // TODO(sragss): Allocation can overshoot by up to a factor of 2, Spartan could handle non-pow-2 Az,Bz,Cz - let constraint_rows = self.constraint_rows(); - let (mut Az, mut Bz, mut Cz) = ( - unsafe_allocate_zero_vec(constraint_rows), - unsafe_allocate_zero_vec(constraint_rows), - unsafe_allocate_zero_vec(constraint_rows), - ); let batch_inputs = |lc: &LC| batch_inputs(lc, inputs, aux); - // uniform_constraints: Xz[0..uniform_constraint_rows] - // TODO(sragss): Attempt moving onto key and computing from materialized rows rather than linear combos - let span = tracing::span!(tracing::Level::DEBUG, "compute_constraints"); - let enter = span.enter(); - let az_chunks = Az.chunks_mut(self.uniform_repeat); - let bz_chunks = Bz.chunks_mut(self.uniform_repeat); - let cz_chunks = Cz.chunks_mut(self.uniform_repeat); - - self.uniform_builder - .constraints - .iter() - .enumerate() - .zip(az_chunks.zip(bz_chunks.zip(cz_chunks))) - .for_each(|((constraint_index, constraint), (az_chunk, (bz_chunk, cz_chunk)))| { + // Enforce correctness of hints. + // TODO(sragss): Can be moved into assert_valid. + #[cfg(test)] + self.uniform_builder.constraints.iter().enumerate().for_each(|(constraint_index, constraint)| { + let assert_hint = |constraint: &Constraint| { let a_inputs = batch_inputs(&constraint.a); let b_inputs = batch_inputs(&constraint.b); let c_inputs = batch_inputs(&constraint.c); - constraint.a.evaluate_batch_mut(&a_inputs, az_chunk); - constraint.b.evaluate_batch_mut(&b_inputs, bz_chunk); - constraint.c.evaluate_batch_mut(&c_inputs, cz_chunk); + let a = constraint.a.evaluate_batch(&a_inputs, self.uniform_repeat); + let b = constraint.b.evaluate_batch(&b_inputs, self.uniform_repeat); + let c = constraint.c.evaluate_batch(&c_inputs, self.uniform_repeat); - let az_zero = az_chunk.iter().filter(|item| item.is_zero()).count(); - let bz_zero = bz_chunk.iter().filter(|item| item.is_zero()).count(); - let cz_zero = cz_chunk.iter().filter(|item| item.is_zero()).count(); + if constraint.evaluation_hint.0 == EvaluationHint::Zero { + a.iter().for_each(|item| assert_eq!(*item, F::zero(), "Wrong hint: {constraint_index} {constraint:?}")); + } + if constraint.evaluation_hint.1 == EvaluationHint::Zero { + b.iter().for_each(|item| assert_eq!(*item, F::zero(), "Wrong hint: {constraint_index} {constraint:?}")); + } + if constraint.evaluation_hint.2 == EvaluationHint::Zero { + c.iter().for_each(|item| assert_eq!(*item, F::zero(), "Wrong hint: {constraint_index} {constraint:?}")); + } + }; - println!("[{constraint_index}] empty map az: {} bz: {} cz: {}", az_zero == az_chunk.len(), bz_zero == bz_chunk.len(), cz_zero == cz_chunk.len()); - }); - drop(enter); + assert_hint(constraint); + }); + + // uniform_constraints: Xz[0..uniform_constraint_rows] + let span = tracing::span!(tracing::Level::DEBUG, "uniform_evals"); + let _enter = span.enter(); + let uni_constraint_evals: Vec<(Vec<(F, usize)>, Vec<(F, usize)>, Vec<(F, usize)>)> = self.uniform_builder.constraints.par_iter().enumerate().map(|(constraint_index, constraint)| { + let mut dense_output_buffer = unsafe_allocate_zero_vec(self.uniform_repeat); + + let mut evaluate_lc_chunk = |hint, lc: &LC| { + if hint != EvaluationHint::Zero { + let inputs = batch_inputs(lc); + lc.evaluate_batch_mut(&inputs, &mut dense_output_buffer); + + // Take only the non-zero elements and represent them as sparse tuples (eval, dense_index) + let mut sparse = Vec::with_capacity(self.uniform_repeat); // overshoot + dense_output_buffer.iter().enumerate().for_each(|(local_index, item)| { + if !item.is_zero() { + let global_index = constraint_index * self.uniform_repeat + local_index; + sparse.push((*item, global_index)); + } + }); + sparse + } else { + vec![] + } + }; - let az_non_zero = Az.iter().filter(|item| !item.is_zero()).count(); - let bz_non_zero = Bz.iter().filter(|item| !item.is_zero()).count(); - let cz_non_zero = Cz.iter().filter(|item| !item.is_zero()).count(); + let a_chunk: Vec<(F, usize)> = evaluate_lc_chunk(constraint.evaluation_hint.0, &constraint.a); + let b_chunk: Vec<(F, usize)> = evaluate_lc_chunk(constraint.evaluation_hint.1, &constraint.b); + let c_chunk: Vec<(F, usize)> = evaluate_lc_chunk(constraint.evaluation_hint.2, &constraint.c); - println!("Uniform repeat: {}", self.uniform_repeat); - println!("Num constraints: {constraint_rows}"); - println!("Az sparsity: {az_non_zero}/{}", Az.len()); - println!("Bz sparsity: {bz_non_zero}/{}", Bz.len()); - println!("Cz sparsity: {cz_non_zero}/{}", Cz.len()); + (a_chunk, b_chunk, c_chunk) + }).collect(); + + let (mut az_sparse, mut bz_sparse, cz_sparse) = par_flatten_triple(uni_constraint_evals, unsafe_allocate_sparse_zero_vec, self.uniform_repeat); // offset_equality_constraints: Xz[uniform_constraint_rows..uniform_constraint_rows + 1] // (a - b) * condition == 0 @@ -934,15 +959,9 @@ impl CombinedUniformBuilder { .1 .evaluate_batch(&batch_inputs(&constr.b.1), self.uniform_repeat); - let Az_off = Az[uniform_constraint_rows..uniform_constraint_rows + self.uniform_repeat] - .par_iter_mut(); - let Bz_off = Bz[uniform_constraint_rows..uniform_constraint_rows + self.uniform_repeat] - .par_iter_mut(); - - (0..self.uniform_repeat) + let dense_az_bz: Vec<(F, F)> = (0..self.uniform_repeat) .into_par_iter() - .zip(Az_off.zip(Bz_off)) - .for_each(|(step_index, (az, bz))| { + .map(|step_index| { // Write corresponding values, if outside the step range, only include the constant. let a_step = step_index + if constr.a.0 { 1 } else { 0 }; let b_step = step_index + if constr.b.0 { 1 } else { 0 }; @@ -954,27 +973,34 @@ impl CombinedUniformBuilder { .get(b_step) .cloned() .unwrap_or(constr.b.1.constant_term_field()); - *az = a - b; + let az = a - b; let condition_step = step_index + if constr.cond.0 { 1 } else { 0 }; - *bz = condition_evals + let bz = condition_evals .get(condition_step) .cloned() .unwrap_or(constr.cond.1.constant_term_field()); - }); - drop(_enter); - - #[cfg(test)] - self.assert_valid(&Az, &Bz, &Cz); + (az, bz) + }).collect(); + + // Sparsify: take only the non-zero elements + for (local_index, (az, bz)) in dense_az_bz.iter().enumerate() { + let global_index = uniform_constraint_rows + local_index; + if !az.is_zero() { + az_sparse.push((*az, global_index)); + } + if !bz.is_zero() { + bz_sparse.push((*bz, global_index)); + } + } let num_vars = self.constraint_rows().next_power_of_two().log_2(); - let (az_poly, (bz_poly, cz_poly)) = rayon::join( - || SparsePolynomial::from_dense_evals(num_vars, Az), - || rayon::join( - || SparsePolynomial::from_dense_evals(num_vars, Bz), - || SparsePolynomial::from_dense_evals(num_vars, Cz) - ) - ); + let az_poly = SparsePolynomial::new(num_vars, az_sparse); + let bz_poly = SparsePolynomial::new(num_vars, bz_sparse); + let cz_poly = SparsePolynomial::new(num_vars, cz_sparse); + + #[cfg(test)] + self.assert_valid(&az_poly.clone().to_dense().evals_ref(), &bz_poly.clone().to_dense().evals_ref(), &cz_poly.clone().to_dense().evals_ref()); (az_poly, bz_poly, cz_poly) } diff --git a/jolt-core/src/r1cs/ops.rs b/jolt-core/src/r1cs/ops.rs index 6cb179490..48d6c06bf 100644 --- a/jolt-core/src/r1cs/ops.rs +++ b/jolt-core/src/r1cs/ops.rs @@ -129,11 +129,6 @@ impl LC { let terms: Vec = self.to_field_elements(); - if terms.len() == 0 { - println!("no terms"); - return; - } - output .par_iter_mut() .enumerate() diff --git a/jolt-core/src/r1cs/special_polys.rs b/jolt-core/src/r1cs/special_polys.rs index dba878c9c..cf53420fc 100644 --- a/jolt-core/src/r1cs/special_polys.rs +++ b/jolt-core/src/r1cs/special_polys.rs @@ -2,7 +2,7 @@ use crate::{field::JoltField, poly::{dense_mlpoly::DensePolynomial, eq_poly::EqP use num_integer::Integer; use rayon::prelude::*; -#[derive(Clone)] +#[derive(Clone, Debug, PartialEq)] pub struct SparsePolynomial { num_vars: usize, diff --git a/jolt-core/src/utils/thread.rs b/jolt-core/src/utils/thread.rs index 7deaa28e6..4678022a7 100644 --- a/jolt-core/src/utils/thread.rs +++ b/jolt-core/src/utils/thread.rs @@ -1,4 +1,5 @@ use std::thread::{self, JoinHandle}; +use rayon::prelude::*; use crate::field::JoltField; @@ -17,7 +18,7 @@ pub fn allocate_vec_in_background( thread::spawn(move || vec![value; size]) } -#[tracing::instrument(skip_all, name = "unsafe_allocate_zero_vec")] +#[tracing::instrument(skip_all)] pub fn unsafe_allocate_zero_vec(size: usize) -> Vec { // https://stackoverflow.com/questions/59314686/how-to-efficiently-create-a-large-vector-of-items-initialized-to-the-same-value @@ -44,7 +45,7 @@ pub fn unsafe_allocate_zero_vec(size: usize) -> Vec { result } -#[tracing::instrument(skip_all, name = "unsafe_allocate_sparse_zero_vec")] +#[tracing::instrument(skip_all)] pub fn unsafe_allocate_sparse_zero_vec(size: usize) -> Vec<(F, usize)> { // Check for safety of 0 allocation unsafe { @@ -69,6 +70,49 @@ pub fn unsafe_allocate_sparse_zero_vec(size: usize) -> Vec result } +#[tracing::instrument(skip_all)] +pub fn par_flatten_triple Vec>( + triple: Vec<(Vec, Vec, Vec)>, + allocate: F, + excess_alloc: usize) -> (Vec, Vec, Vec) { + let az_len: usize = triple.iter().map(|item| item.0.len()).sum(); + let bz_len: usize = triple.iter().map(|item| item.1.len()).sum(); + let cz_len: usize = triple.iter().map(|item| item.2.len()).sum(); + + let (mut a_sparse, mut b_sparse, mut c_sparse): (Vec, Vec, Vec) = ( + allocate(az_len), + allocate(bz_len), + allocate(cz_len), + ); + + let mut a_slices = Vec::with_capacity(triple.len() + excess_alloc); + let mut b_slices = Vec::with_capacity(triple.len() + excess_alloc); + let mut c_slices = Vec::with_capacity(triple.len() + excess_alloc); + + let mut a_rest: &mut [T] = a_sparse.as_mut_slice(); + let mut b_rest: &mut [T] = b_sparse.as_mut_slice(); + let mut c_rest: &mut [T] = c_sparse.as_mut_slice(); + + for item in &triple { + let (a_chunk, a_new_rest) = a_rest.split_at_mut(item.0.len()); + a_slices.push(a_chunk); + a_rest = a_new_rest; + + let (b_chunk, b_new_rest) = b_rest.split_at_mut(item.1.len()); + b_slices.push(b_chunk); + b_rest = b_new_rest; + + let (c_chunk, c_new_rest) = c_rest.split_at_mut(item.2.len()); + c_slices.push(c_chunk); + c_rest = c_new_rest; + } + + triple.into_par_iter().zip(a_slices.par_iter_mut().zip(b_slices.par_iter_mut().zip(c_slices.par_iter_mut()))).for_each(|(chunk, (a, (b, c)))| { + join_triple(|| a.copy_from_slice(&chunk.0), || b.copy_from_slice(&chunk.1), || c.copy_from_slice(&chunk.2)); + }); + + (a_sparse, b_sparse, c_sparse) +} pub fn join_triple(oper_a: A, oper_b: B, oper_c: C) -> (RA, RB, RC) where From 968b050d45a400d0584d7a70dc2b32070c665153 Mon Sep 17 00:00:00 2001 From: sragss Date: Tue, 25 Jun 2024 21:25:42 -0700 Subject: [PATCH 13/43] cargo fmt --- jolt-core/src/poly/dense_mlpoly.rs | 10 +- jolt-core/src/r1cs/builder.rs | 180 ++++++++++++++-------- jolt-core/src/r1cs/spartan.rs | 3 +- jolt-core/src/r1cs/special_polys.rs | 228 ++++++++++++++++++++-------- jolt-core/src/utils/thread.rs | 35 +++-- 5 files changed, 310 insertions(+), 146 deletions(-) diff --git a/jolt-core/src/poly/dense_mlpoly.rs b/jolt-core/src/poly/dense_mlpoly.rs index 928b63915..6bfd3aab2 100644 --- a/jolt-core/src/poly/dense_mlpoly.rs +++ b/jolt-core/src/poly/dense_mlpoly.rs @@ -206,13 +206,13 @@ impl DensePolynomial { let n = self.len() / 2; let mut new_z = unsafe_allocate_zero_vec(n); new_z.par_iter_mut().enumerate().for_each(|(i, z)| { - let m = self.Z[2*i + 1] - self.Z[2*i]; + let m = self.Z[2 * i + 1] - self.Z[2 * i]; *z = if m.is_zero() { - self.Z[2*i] + self.Z[2 * i] } else if m.is_one() { - self.Z[2*i] + r - }else { - self.Z[2*i] + *r * m + self.Z[2 * i] + r + } else { + self.Z[2 * i] + *r * m } }); diff --git a/jolt-core/src/r1cs/builder.rs b/jolt-core/src/r1cs/builder.rs index 340f2edde..0a5bc5859 100644 --- a/jolt-core/src/r1cs/builder.rs +++ b/jolt-core/src/r1cs/builder.rs @@ -2,7 +2,12 @@ use crate::{ field::{JoltField, OptimizedMul}, r1cs::key::{SparseConstraints, UniformR1CS}, utils::{ - math::Math, mul_0_1_optimized, thread::{drop_in_background_thread, par_flatten_triple, unsafe_allocate_sparse_zero_vec, unsafe_allocate_zero_vec} + math::Math, + mul_0_1_optimized, + thread::{ + drop_in_background_thread, par_flatten_triple, unsafe_allocate_sparse_zero_vec, + unsafe_allocate_zero_vec, + }, }, }; #[allow(unused_imports)] // clippy thinks these aren't needed lol @@ -12,7 +17,8 @@ use std::{collections::HashMap, fmt::Debug}; use super::{ key::{NonUniformR1CS, SparseEqualityItem}, - ops::{ConstraintInput, Term, Variable, LC}, special_polys::SparsePolynomial, + ops::{ConstraintInput, Term, Variable, LC}, + special_polys::SparsePolynomial, }; pub trait R1CSConstraintBuilder { @@ -33,7 +39,7 @@ struct Constraint { a: LC, b: LC, c: LC, - evaluation_hint: (EvaluationHint, EvaluationHint, EvaluationHint) + evaluation_hint: (EvaluationHint, EvaluationHint, EvaluationHint), } impl Constraint { @@ -231,7 +237,11 @@ impl R1CSBuilder { a, b, c: LC::zero(), - evaluation_hint: (EvaluationHint::Zero, EvaluationHint::Other, EvaluationHint::Zero) + evaluation_hint: ( + EvaluationHint::Zero, + EvaluationHint::Other, + EvaluationHint::Zero, + ), }; self.constraints.push(constraint); } @@ -250,7 +260,16 @@ impl R1CSBuilder { let a = condition; let b = left - right; let c = LC::zero(); - let constraint = Constraint { a, b, c, evaluation_hint: (EvaluationHint::Other, EvaluationHint::Other, EvaluationHint::Zero) }; // TODO(sragss): Can do better on middle term. + let constraint = Constraint { + a, + b, + c, + evaluation_hint: ( + EvaluationHint::Other, + EvaluationHint::Other, + EvaluationHint::Zero, + ), + }; // TODO(sragss): Can do better on middle term. self.constraints.push(constraint); } @@ -263,7 +282,11 @@ impl R1CSBuilder { a, b, c: LC::zero(), - evaluation_hint: (EvaluationHint::Other, EvaluationHint::Other, EvaluationHint::Zero) + evaluation_hint: ( + EvaluationHint::Other, + EvaluationHint::Other, + EvaluationHint::Zero, + ), }; self.constraints.push(constraint); } @@ -287,7 +310,11 @@ impl R1CSBuilder { a: condition.clone(), b: (result_true - result_false.clone()), c: (alleged_result - result_false), - evaluation_hint: (EvaluationHint::Other, EvaluationHint::Other, EvaluationHint::Other) // TODO(sragss): Is this the best we can do? + evaluation_hint: ( + EvaluationHint::Other, + EvaluationHint::Other, + EvaluationHint::Other, + ), // TODO(sragss): Is this the best we can do? }; self.constraints.push(constraint); } @@ -433,7 +460,11 @@ impl R1CSBuilder { a: x.into(), b: y.into(), c: z.into(), - evaluation_hint: (EvaluationHint::Other, EvaluationHint::Other, EvaluationHint::Other) + evaluation_hint: ( + EvaluationHint::Other, + EvaluationHint::Other, + EvaluationHint::Other, + ), }; self.constraints.push(constraint); } @@ -858,14 +889,18 @@ impl CombinedUniformBuilder { (Az, Bz, Cz) } - /// inputs should be of the format [[I::0, I::0, ...], [I::1, I::1, ...], ... [I::N, I::N]] + /// inputs should be of the format [[I::0, I::0, ...], [I::1, I::1, ...], ... [I::N, I::N]] /// aux should be of the format [[Aux(0), Aux(0), ...], ... [Aux(self.next_aux - 1), ...]] #[tracing::instrument(skip_all, name = "CombinedUniformBuilder::compute_spartan_sparse")] pub fn compute_spartan_Az_Bz_Cz_sparse( &self, inputs: &[Vec], aux: &[Vec], - ) -> (SparsePolynomial, SparsePolynomial, SparsePolynomial) { + ) -> ( + SparsePolynomial, + SparsePolynomial, + SparsePolynomial, + ) { assert_eq!(inputs.len(), I::COUNT); let num_aux = self.uniform_builder.num_aux(); assert_eq!(aux.len(), num_aux); @@ -881,63 +916,82 @@ impl CombinedUniformBuilder { // Enforce correctness of hints. // TODO(sragss): Can be moved into assert_valid. #[cfg(test)] - self.uniform_builder.constraints.iter().enumerate().for_each(|(constraint_index, constraint)| { - let assert_hint = |constraint: &Constraint| { - let a_inputs = batch_inputs(&constraint.a); - let b_inputs = batch_inputs(&constraint.b); - let c_inputs = batch_inputs(&constraint.c); - - let a = constraint.a.evaluate_batch(&a_inputs, self.uniform_repeat); - let b = constraint.b.evaluate_batch(&b_inputs, self.uniform_repeat); - let c = constraint.c.evaluate_batch(&c_inputs, self.uniform_repeat); - - if constraint.evaluation_hint.0 == EvaluationHint::Zero { - a.iter().for_each(|item| assert_eq!(*item, F::zero(), "Wrong hint: {constraint_index} {constraint:?}")); - } - if constraint.evaluation_hint.1 == EvaluationHint::Zero { - b.iter().for_each(|item| assert_eq!(*item, F::zero(), "Wrong hint: {constraint_index} {constraint:?}")); - } - if constraint.evaluation_hint.2 == EvaluationHint::Zero { - c.iter().for_each(|item| assert_eq!(*item, F::zero(), "Wrong hint: {constraint_index} {constraint:?}")); - } - }; + self.uniform_builder + .constraints + .iter() + .for_each(|constraint| { + let assert_hint = |constraint: &Constraint| { + let a_inputs = batch_inputs(&constraint.a); + let b_inputs = batch_inputs(&constraint.b); + let c_inputs = batch_inputs(&constraint.c); + + let a = constraint.a.evaluate_batch(&a_inputs, self.uniform_repeat); + let b = constraint.b.evaluate_batch(&b_inputs, self.uniform_repeat); + let c = constraint.c.evaluate_batch(&c_inputs, self.uniform_repeat); + + if constraint.evaluation_hint.0 == EvaluationHint::Zero { + a.iter().for_each(|item| assert_eq!(*item, F::zero(),)); + } + if constraint.evaluation_hint.1 == EvaluationHint::Zero { + b.iter().for_each(|item| assert_eq!(*item, F::zero(),)); + } + if constraint.evaluation_hint.2 == EvaluationHint::Zero { + c.iter().for_each(|item| assert_eq!(*item, F::zero(),)); + } + }; - assert_hint(constraint); - }); + assert_hint(constraint); + }); // uniform_constraints: Xz[0..uniform_constraint_rows] let span = tracing::span!(tracing::Level::DEBUG, "uniform_evals"); let _enter = span.enter(); - let uni_constraint_evals: Vec<(Vec<(F, usize)>, Vec<(F, usize)>, Vec<(F, usize)>)> = self.uniform_builder.constraints.par_iter().enumerate().map(|(constraint_index, constraint)| { - let mut dense_output_buffer = unsafe_allocate_zero_vec(self.uniform_repeat); - - let mut evaluate_lc_chunk = |hint, lc: &LC| { - if hint != EvaluationHint::Zero { - let inputs = batch_inputs(lc); - lc.evaluate_batch_mut(&inputs, &mut dense_output_buffer); - - // Take only the non-zero elements and represent them as sparse tuples (eval, dense_index) - let mut sparse = Vec::with_capacity(self.uniform_repeat); // overshoot - dense_output_buffer.iter().enumerate().for_each(|(local_index, item)| { - if !item.is_zero() { - let global_index = constraint_index * self.uniform_repeat + local_index; - sparse.push((*item, global_index)); + let uni_constraint_evals: Vec<(Vec<(F, usize)>, Vec<(F, usize)>, Vec<(F, usize)>)> = + self.uniform_builder + .constraints + .par_iter() + .enumerate() + .map(|(constraint_index, constraint)| { + let mut dense_output_buffer = unsafe_allocate_zero_vec(self.uniform_repeat); + + let mut evaluate_lc_chunk = |hint, lc: &LC| { + if hint != EvaluationHint::Zero { + let inputs = batch_inputs(lc); + lc.evaluate_batch_mut(&inputs, &mut dense_output_buffer); + + // Take only the non-zero elements and represent them as sparse tuples (eval, dense_index) + let mut sparse = Vec::with_capacity(self.uniform_repeat); // overshoot + dense_output_buffer.iter().enumerate().for_each( + |(local_index, item)| { + if !item.is_zero() { + let global_index = + constraint_index * self.uniform_repeat + local_index; + sparse.push((*item, global_index)); + } + }, + ); + sparse + } else { + vec![] } - }); - sparse - } else { - vec![] - } - }; + }; - let a_chunk: Vec<(F, usize)> = evaluate_lc_chunk(constraint.evaluation_hint.0, &constraint.a); - let b_chunk: Vec<(F, usize)> = evaluate_lc_chunk(constraint.evaluation_hint.1, &constraint.b); - let c_chunk: Vec<(F, usize)> = evaluate_lc_chunk(constraint.evaluation_hint.2, &constraint.c); + let a_chunk: Vec<(F, usize)> = + evaluate_lc_chunk(constraint.evaluation_hint.0, &constraint.a); + let b_chunk: Vec<(F, usize)> = + evaluate_lc_chunk(constraint.evaluation_hint.1, &constraint.b); + let c_chunk: Vec<(F, usize)> = + evaluate_lc_chunk(constraint.evaluation_hint.2, &constraint.c); - (a_chunk, b_chunk, c_chunk) - }).collect(); + (a_chunk, b_chunk, c_chunk) + }) + .collect(); - let (mut az_sparse, mut bz_sparse, cz_sparse) = par_flatten_triple(uni_constraint_evals, unsafe_allocate_sparse_zero_vec, self.uniform_repeat); + let (mut az_sparse, mut bz_sparse, cz_sparse) = par_flatten_triple( + uni_constraint_evals, + unsafe_allocate_sparse_zero_vec, + self.uniform_repeat, + ); // offset_equality_constraints: Xz[uniform_constraint_rows..uniform_constraint_rows + 1] // (a - b) * condition == 0 @@ -981,7 +1035,8 @@ impl CombinedUniformBuilder { .cloned() .unwrap_or(constr.cond.1.constant_term_field()); (az, bz) - }).collect(); + }) + .collect(); // Sparsify: take only the non-zero elements for (local_index, (az, bz)) in dense_az_bz.iter().enumerate() { @@ -1000,12 +1055,15 @@ impl CombinedUniformBuilder { let cz_poly = SparsePolynomial::new(num_vars, cz_sparse); #[cfg(test)] - self.assert_valid(&az_poly.clone().to_dense().evals_ref(), &bz_poly.clone().to_dense().evals_ref(), &cz_poly.clone().to_dense().evals_ref()); + self.assert_valid( + &az_poly.clone().to_dense().evals_ref(), + &bz_poly.clone().to_dense().evals_ref(), + &cz_poly.clone().to_dense().evals_ref(), + ); (az_poly, bz_poly, cz_poly) } - #[cfg(test)] pub fn assert_valid(&self, az: &[F], bz: &[F], cz: &[F]) { let rows = az.len(); diff --git a/jolt-core/src/r1cs/spartan.rs b/jolt-core/src/r1cs/spartan.rs index 256ab9b14..b436769e3 100644 --- a/jolt-core/src/r1cs/spartan.rs +++ b/jolt-core/src/r1cs/spartan.rs @@ -115,7 +115,8 @@ impl> UniformSpartanProof { let inputs = &segmented_padded_witness.segments[0..I::COUNT]; let aux = &segmented_padded_witness.segments[I::COUNT..]; profiling::print_current_memory_usage("pre_az_bz_cz"); - let (mut az, mut bz, mut cz) = constraint_builder.compute_spartan_Az_Bz_Cz_sparse(inputs, aux); + let (mut az, mut bz, mut cz) = + constraint_builder.compute_spartan_Az_Bz_Cz_sparse(inputs, aux); profiling::print_current_memory_usage("post_az_bz_cz"); let comb_func_outer = |A: &F, B: &F, C: &F, D: &F| -> F { diff --git a/jolt-core/src/r1cs/special_polys.rs b/jolt-core/src/r1cs/special_polys.rs index cf53420fc..d757a24c7 100644 --- a/jolt-core/src/r1cs/special_polys.rs +++ b/jolt-core/src/r1cs/special_polys.rs @@ -1,11 +1,22 @@ -use crate::{field::JoltField, poly::{dense_mlpoly::DensePolynomial, eq_poly::EqPolynomial}, utils::{compute_dotproduct_low_optimized, math::Math, mul_0_1_optimized, thread::{drop_in_background_thread, unsafe_allocate_sparse_zero_vec, unsafe_allocate_zero_vec}}}; +use crate::{ + field::JoltField, + poly::{dense_mlpoly::DensePolynomial, eq_poly::EqPolynomial}, + utils::{ + compute_dotproduct_low_optimized, + math::Math, + mul_0_1_optimized, + thread::{ + drop_in_background_thread, unsafe_allocate_sparse_zero_vec, unsafe_allocate_zero_vec, + }, + }, +}; use num_integer::Integer; use rayon::prelude::*; #[derive(Clone, Debug, PartialEq)] pub struct SparsePolynomial { num_vars: usize, - + Z: Vec<(F, usize)>, } @@ -18,7 +29,10 @@ impl SparsePolynomial { #[tracing::instrument(skip_all)] pub fn from_dense_evals(num_vars: usize, evals: Vec) -> Self { assert!(num_vars.pow2() >= evals.len()); - let non_zero_count: usize = evals.par_chunks(10_000).map(|chunk| chunk.iter().filter(|f| !f.is_zero()).count()).sum(); + let non_zero_count: usize = evals + .par_chunks(10_000) + .map(|chunk| chunk.iter().filter(|f| !f.is_zero()).count()) + .sum(); let span_allocate = tracing::span!(tracing::Level::DEBUG, "allocate"); let _enter_allocate = span_allocate.enter(); @@ -90,7 +104,8 @@ impl SparsePolynomial { dense_start_index = dense_end_index; sparse_start_index = sparse_end_index; - sparse_end_index = std::cmp::min(sparse_end_index + target_chunk_size, self.Z.len() - 1); + sparse_end_index = + std::cmp::min(sparse_end_index + target_chunk_size, self.Z.len() - 1); } chunks.push(&self.Z[sparse_start_index..]); let highest_non_zero = self.Z.last().map(|&(_, index)| index).unwrap(); @@ -98,7 +113,6 @@ impl SparsePolynomial { assert_eq!(chunks.len(), n); assert_eq!(dense_ranges.len(), n); - (chunks, dense_ranges) } @@ -113,9 +127,12 @@ impl SparsePolynomial { for (sparse_index, (value, dense_index)) in self.Z.iter().enumerate() { if dense_index.is_even() { let new_dense_index = dense_index / 2; - if self.Z.len() >= 2 && sparse_index <= self.Z.len() - 2 && self.Z[sparse_index + 1].1 == dense_index + 1 { + if self.Z.len() >= 2 + && sparse_index <= self.Z.len() - 2 + && self.Z[sparse_index + 1].1 == dense_index + 1 + { let upper = self.Z[sparse_index + 1].0; - let eval = *value + *r * (upper - value); + let eval = *value + *r * (upper - value); new_Z.push((eval, new_dense_index)); } else { new_Z.push(((F::one() - r) * value, new_dense_index)); @@ -139,20 +156,26 @@ impl SparsePolynomial { let count_span = tracing::span!(tracing::Level::DEBUG, "counting"); let count_enter = count_span.enter(); let (chunks, _range) = self.chunk_no_orphans(rayon::current_num_threads() * 8); - let chunk_sizes: Vec = chunks.par_iter().map(|chunk| { - let mut chunk_size = 0; - let mut i = 0; - while i < chunk.len() { - chunk_size += 1; - - // If they're siblings, avoid double counting - if chunk[i].1.is_even() && i + 1 < chunk.len() && chunk[i].1 + 1 == chunk[i + 1].1 { + let chunk_sizes: Vec = chunks + .par_iter() + .map(|chunk| { + let mut chunk_size = 0; + let mut i = 0; + while i < chunk.len() { + chunk_size += 1; + + // If they're siblings, avoid double counting + if chunk[i].1.is_even() + && i + 1 < chunk.len() + && chunk[i].1 + 1 == chunk[i + 1].1 + { + i += 1; + } i += 1; } - i += 1; - } - chunk_size - }).collect(); + chunk_size + }) + .collect(); drop(count_enter); let alloc_span = tracing::span!(tracing::Level::DEBUG, "alloc_new_Z"); @@ -170,33 +193,40 @@ impl SparsePolynomial { } assert_eq!(mutable_chunks.len(), chunks.len()); - chunks.into_par_iter().zip(mutable_chunks.par_iter_mut()).for_each(|(chunk, mutable)| { - let span = tracing::span!(tracing::Level::DEBUG, "chunk"); - let _enter = span.enter(); - let mut write_index = 0; - for (sparse_index, (value, dense_index)) in chunk.iter().enumerate() { - if dense_index.is_even() { - let new_dense_index = dense_index / 2; - if chunk.len() >= 2 && sparse_index <= chunk.len() - 2 && chunk[sparse_index + 1].1 == dense_index + 1 { - let upper = chunk[sparse_index + 1].0; - let eval = *value + mul_0_1_optimized(r, &(upper - value)); - mutable[write_index] = (eval, new_dense_index); - write_index += 1; - } else { - mutable[write_index] = (mul_0_1_optimized(&(F::one() - r), value), new_dense_index); - write_index += 1; - } - } else { - if sparse_index > 0 && chunk[sparse_index - 1].1 == dense_index - 1 { - continue; + chunks + .into_par_iter() + .zip(mutable_chunks.par_iter_mut()) + .for_each(|(chunk, mutable)| { + let span = tracing::span!(tracing::Level::DEBUG, "chunk"); + let _enter = span.enter(); + let mut write_index = 0; + for (sparse_index, (value, dense_index)) in chunk.iter().enumerate() { + if dense_index.is_even() { + let new_dense_index = dense_index / 2; + if chunk.len() >= 2 + && sparse_index <= chunk.len() - 2 + && chunk[sparse_index + 1].1 == dense_index + 1 + { + let upper = chunk[sparse_index + 1].0; + let eval = *value + mul_0_1_optimized(r, &(upper - value)); + mutable[write_index] = (eval, new_dense_index); + write_index += 1; + } else { + mutable[write_index] = + (mul_0_1_optimized(&(F::one() - r), value), new_dense_index); + write_index += 1; + } } else { - let new_dense_index = (dense_index - 1) / 2; - mutable[write_index] = (mul_0_1_optimized(r, value), new_dense_index); - write_index += 1; + if sparse_index > 0 && chunk[sparse_index - 1].1 == dense_index - 1 { + continue; + } else { + let new_dense_index = (dense_index - 1) / 2; + mutable[write_index] = (mul_0_1_optimized(r, value), new_dense_index); + write_index += 1; + } } } - } - }); + }); let old_Z = std::mem::replace(&mut self.Z, new_Z); drop_in_background_thread(old_Z); @@ -240,7 +270,12 @@ pub struct SparseTripleIterator<'a, F: JoltField> { impl<'a, F: JoltField> SparseTripleIterator<'a, F> { #[tracing::instrument(skip_all)] - pub fn chunks(a: &'a SparsePolynomial, b: &'a SparsePolynomial, c: &'a SparsePolynomial, n: usize) -> Vec { + pub fn chunks( + a: &'a SparsePolynomial, + b: &'a SparsePolynomial, + c: &'a SparsePolynomial, + n: usize, + ) -> Vec { // When the instance is small enough, don't worry about parallelism let total_len = a.num_vars.pow2(); if n * 2 > b.Z.len() { @@ -249,11 +284,14 @@ impl<'a, F: JoltField> SparseTripleIterator<'a, F> { end_index: total_len, a: &a.Z, b: &b.Z, - c: &c.Z + c: &c.Z, }]; } // Can be made more generic, but this is an optimization / simplification. - assert!(b.Z.len() >= a.Z.len() && b.Z.len() >= c.Z.len(), "b.Z.len() assumed to be longest of a, b, and c"); + assert!( + b.Z.len() >= a.Z.len() && b.Z.len() >= c.Z.len(), + "b.Z.len() assumed to be longest of a, b, and c" + ); // TODO(sragss): Explain the strategy @@ -281,7 +319,12 @@ impl<'a, F: JoltField> SparseTripleIterator<'a, F> { let a_last = a.Z.last().map(|&(_, index)| index); let b_last = b.Z.last().map(|&(_, index)| index); let c_last = c.Z.last().map(|&(_, index)| index); - *a_last.iter().chain(b_last.iter()).chain(c_last.iter()).max().unwrap() + *a_last + .iter() + .chain(b_last.iter()) + .chain(c_last.iter()) + .max() + .unwrap() }; dense_ranges.push((dense_start_index, highest_non_zero + 1)); assert_eq!(b_chunks.len(), n); @@ -315,11 +358,10 @@ impl<'a, F: JoltField> SparseTripleIterator<'a, F> { c_chunks[chunk_index - 1] = &c.Z[c_start..c_i]; } - } drop(_enter); - a_chunks[n-1] = &a.Z[a_i..]; - c_chunks[n-1] = &c.Z[c_i..]; + a_chunks[n - 1] = &a.Z[a_i..]; + c_chunks[n - 1] = &c.Z[c_i..]; #[cfg(test)] { @@ -329,19 +371,30 @@ impl<'a, F: JoltField> SparseTripleIterator<'a, F> { } let mut iterators: Vec> = Vec::with_capacity(n); - for (((a_chunk, b_chunk), c_chunk), range) in a_chunks.iter().zip(b_chunks.iter()).zip(c_chunks.iter()).zip(dense_ranges.iter()) { + for (((a_chunk, b_chunk), c_chunk), range) in a_chunks + .iter() + .zip(b_chunks.iter()) + .zip(c_chunks.iter()) + .zip(dense_ranges.iter()) + { #[cfg(test)] { - assert!(a_chunk.iter().all(|(_, index)| *index >= range.0 && *index <= range.1)); - assert!(b_chunk.iter().all(|(_, index)| *index >= range.0 && *index <= range.1)); - assert!(c_chunk.iter().all(|(_, index)| *index >= range.0 && *index <= range.1)); + assert!(a_chunk + .iter() + .all(|(_, index)| *index >= range.0 && *index <= range.1)); + assert!(b_chunk + .iter() + .all(|(_, index)| *index >= range.0 && *index <= range.1)); + assert!(c_chunk + .iter() + .all(|(_, index)| *index >= range.0 && *index <= range.1)); } let iter = SparseTripleIterator { dense_index: range.0, end_index: range.1, a: a_chunk, b: b_chunk, - c: c_chunk + c: c_chunk, }; iterators.push(iter); } @@ -379,7 +432,15 @@ impl<'a, F: JoltField> SparseTripleIterator<'a, F> { let c_upper_val = match_and_advance(&mut self.c, self.dense_index); self.dense_index += 1; - (low_index, a_lower_val, a_upper_val, b_lower_val, b_upper_val, c_lower_val, c_upper_val) + ( + low_index, + a_lower_val, + a_upper_val, + b_lower_val, + b_upper_val, + c_lower_val, + c_upper_val, + ) } } @@ -544,8 +605,23 @@ mod tests { #[test] fn sparse_bound_bot_mixed() { - let dense_evals = vec![Fr::zero(), Fr::from(10), Fr::zero(), Fr::from(20), Fr::from(30), Fr::from(40), Fr::zero(), Fr::from(50)]; - let sparse_evals = vec![(Fr::from(10), 1), (Fr::from(20), 3), (Fr::from(30), 4), (Fr::from(40), 5), (Fr::from(50), 7)]; + let dense_evals = vec![ + Fr::zero(), + Fr::from(10), + Fr::zero(), + Fr::from(20), + Fr::from(30), + Fr::from(40), + Fr::zero(), + Fr::from(50), + ]; + let sparse_evals = vec![ + (Fr::from(10), 1), + (Fr::from(20), 3), + (Fr::from(30), 4), + (Fr::from(40), 5), + (Fr::from(50), 7), + ]; let mut dense = DensePolynomial::new(dense_evals); let mut sparse = SparsePolynomial::new(3, sparse_evals); @@ -561,7 +637,24 @@ mod tests { #[test] fn sparse_triple_iterator() { let a = vec![(Fr::from(9), 9), (Fr::from(10), 10), (Fr::from(12), 12)]; - let b = vec![(Fr::from(100), 0), (Fr::from(1), 1), (Fr::from(2), 2), (Fr::from(3), 3), (Fr::from(4), 4), (Fr::from(5), 5), (Fr::from(6), 6), (Fr::from(7), 7), (Fr::from(8), 8), (Fr::from(9), 9), (Fr::from(10), 10), (Fr::from(11), 11), (Fr::from(12), 12), (Fr::from(13), 13), (Fr::from(14), 14), (Fr::from(15), 15)]; + let b = vec![ + (Fr::from(100), 0), + (Fr::from(1), 1), + (Fr::from(2), 2), + (Fr::from(3), 3), + (Fr::from(4), 4), + (Fr::from(5), 5), + (Fr::from(6), 6), + (Fr::from(7), 7), + (Fr::from(8), 8), + (Fr::from(9), 9), + (Fr::from(10), 10), + (Fr::from(11), 11), + (Fr::from(12), 12), + (Fr::from(13), 13), + (Fr::from(14), 14), + (Fr::from(15), 15), + ]; let c = vec![(Fr::from(12), 0), (Fr::from(3), 3)]; let a_poly = SparsePolynomial::new(4, a); @@ -610,16 +703,17 @@ mod tests { let mut expected_dense_index = 0; for iterator in iterators.iter_mut() { while iterator.has_next() { - let (dense_index, a_low, a_high, b_low, b_high, c_low, c_high) = iterator.next_pairs(); + let (dense_index, a_low, a_high, b_low, b_high, c_low, c_high) = + iterator.next_pairs(); new_a[dense_index] = a_low; - new_a[dense_index+1] = a_high; + new_a[dense_index + 1] = a_high; new_b[dense_index] = b_low; - new_b[dense_index+1] = b_high; + new_b[dense_index + 1] = b_high; new_c[dense_index] = c_low; - new_c[dense_index+1] = c_high; + new_c[dense_index + 1] = c_high; assert_eq!(dense_index, expected_dense_index); expected_dense_index += 2; @@ -649,7 +743,9 @@ mod tests { let mut a_poly = SparsePolynomial::new(num_vars, a); let r = Fr::from(100); - assert_eq!(a_poly.clone().bound_poly_var_bot(&r), a_poly.bound_poly_var_bot_par(&r)); - + assert_eq!( + a_poly.clone().bound_poly_var_bot(&r), + a_poly.bound_poly_var_bot_par(&r) + ); } -} \ No newline at end of file +} diff --git a/jolt-core/src/utils/thread.rs b/jolt-core/src/utils/thread.rs index 4678022a7..92754a095 100644 --- a/jolt-core/src/utils/thread.rs +++ b/jolt-core/src/utils/thread.rs @@ -1,5 +1,5 @@ -use std::thread::{self, JoinHandle}; use rayon::prelude::*; +use std::thread::{self, JoinHandle}; use crate::field::JoltField; @@ -45,7 +45,7 @@ pub fn unsafe_allocate_zero_vec(size: usize) -> Vec { result } -#[tracing::instrument(skip_all)] +#[tracing::instrument(skip_all)] pub fn unsafe_allocate_sparse_zero_vec(size: usize) -> Vec<(F, usize)> { // Check for safety of 0 allocation unsafe { @@ -72,18 +72,16 @@ pub fn unsafe_allocate_sparse_zero_vec(size: usize) -> Vec #[tracing::instrument(skip_all)] pub fn par_flatten_triple Vec>( - triple: Vec<(Vec, Vec, Vec)>, - allocate: F, - excess_alloc: usize) -> (Vec, Vec, Vec) { + triple: Vec<(Vec, Vec, Vec)>, + allocate: F, + excess_alloc: usize, +) -> (Vec, Vec, Vec) { let az_len: usize = triple.iter().map(|item| item.0.len()).sum(); let bz_len: usize = triple.iter().map(|item| item.1.len()).sum(); let cz_len: usize = triple.iter().map(|item| item.2.len()).sum(); - let (mut a_sparse, mut b_sparse, mut c_sparse): (Vec, Vec, Vec) = ( - allocate(az_len), - allocate(bz_len), - allocate(cz_len), - ); + let (mut a_sparse, mut b_sparse, mut c_sparse): (Vec, Vec, Vec) = + (allocate(az_len), allocate(bz_len), allocate(cz_len)); let mut a_slices = Vec::with_capacity(triple.len() + excess_alloc); let mut b_slices = Vec::with_capacity(triple.len() + excess_alloc); @@ -107,9 +105,20 @@ pub fn par_flatten_triple Vec>( c_rest = c_new_rest; } - triple.into_par_iter().zip(a_slices.par_iter_mut().zip(b_slices.par_iter_mut().zip(c_slices.par_iter_mut()))).for_each(|(chunk, (a, (b, c)))| { - join_triple(|| a.copy_from_slice(&chunk.0), || b.copy_from_slice(&chunk.1), || c.copy_from_slice(&chunk.2)); - }); + triple + .into_par_iter() + .zip( + a_slices + .par_iter_mut() + .zip(b_slices.par_iter_mut().zip(c_slices.par_iter_mut())), + ) + .for_each(|(chunk, (a, (b, c)))| { + join_triple( + || a.copy_from_slice(&chunk.0), + || b.copy_from_slice(&chunk.1), + || c.copy_from_slice(&chunk.2), + ); + }); (a_sparse, b_sparse, c_sparse) } From 9f73a04bfbb8be512d891ebde13e8626d350a43b Mon Sep 17 00:00:00 2001 From: sragss Date: Wed, 26 Jun 2024 10:38:27 -0700 Subject: [PATCH 14/43] rm non sparse Builder::compute_spartan --- jolt-core/src/jolt/vm/mod.rs | 7 +- jolt-core/src/r1cs/builder.rs | 253 ++++++------------------- jolt-core/src/r1cs/jolt_constraints.rs | 4 +- jolt-core/src/r1cs/key.rs | 2 +- jolt-core/src/r1cs/spartan.rs | 16 +- 5 files changed, 65 insertions(+), 217 deletions(-) diff --git a/jolt-core/src/jolt/vm/mod.rs b/jolt-core/src/jolt/vm/mod.rs index 06f63c004..e0d0188d6 100644 --- a/jolt-core/src/jolt/vm/mod.rs +++ b/jolt-core/src/jolt/vm/mod.rs @@ -403,10 +403,8 @@ pub trait Jolt, const C: usize, c &mut transcript, ); - // drop_in_background_thread(jolt_polynomials); - drop(jolt_polynomials); + drop_in_background_thread(jolt_polynomials); - profiling::print_current_memory_usage("pre_spartan"); let spartan_proof = UniformSpartanProof::::prove_precommitted( &preprocessing.generators, r1cs_builder, @@ -415,7 +413,6 @@ pub trait Jolt, const C: usize, c &mut transcript, ) .expect("r1cs proof failed"); - profiling::print_current_memory_usage("post_spartan"); let r1cs_proof = R1CSProof { key: spartan_key, proof: spartan_proof, @@ -593,7 +590,7 @@ pub trait Jolt, const C: usize, c #[cfg(test)] { - let (az, bz, cz) = builder.compute_spartan_Az_Bz_Cz(&inputs_flat, &aux); + let (az, bz, cz) = builder.compute_spartan_Az_Bz_Cz_sparse(&inputs_flat, &aux); builder.assert_valid(&az, &bz, &cz); } diff --git a/jolt-core/src/r1cs/builder.rs b/jolt-core/src/r1cs/builder.rs index 0a5bc5859..124ec573d 100644 --- a/jolt-core/src/r1cs/builder.rs +++ b/jolt-core/src/r1cs/builder.rs @@ -28,9 +28,9 @@ pub trait R1CSConstraintBuilder { } #[derive(Debug, Clone, Copy, PartialEq)] -pub enum EvaluationHint { +pub enum EvalHint { Zero = 0, - Other = 2, + Other = 1, } /// Constraints over a single row. Each variable points to a single item in Z and the corresponding coefficient. @@ -39,7 +39,9 @@ struct Constraint { a: LC, b: LC, c: LC, - evaluation_hint: (EvaluationHint, EvaluationHint, EvaluationHint), + + /// Shortcut for evaluation of a, b, c for an honest prover + eval_hint: (EvalHint, EvalHint, EvalHint), } impl Constraint { @@ -237,11 +239,7 @@ impl R1CSBuilder { a, b, c: LC::zero(), - evaluation_hint: ( - EvaluationHint::Zero, - EvaluationHint::Other, - EvaluationHint::Zero, - ), + eval_hint: (EvalHint::Zero, EvalHint::Other, EvalHint::Zero), }; self.constraints.push(constraint); } @@ -264,11 +262,7 @@ impl R1CSBuilder { a, b, c, - evaluation_hint: ( - EvaluationHint::Other, - EvaluationHint::Other, - EvaluationHint::Zero, - ), + eval_hint: (EvalHint::Other, EvalHint::Other, EvalHint::Zero), }; // TODO(sragss): Can do better on middle term. self.constraints.push(constraint); } @@ -282,11 +276,7 @@ impl R1CSBuilder { a, b, c: LC::zero(), - evaluation_hint: ( - EvaluationHint::Other, - EvaluationHint::Other, - EvaluationHint::Zero, - ), + eval_hint: (EvalHint::Other, EvalHint::Other, EvalHint::Zero), }; self.constraints.push(constraint); } @@ -310,11 +300,7 @@ impl R1CSBuilder { a: condition.clone(), b: (result_true - result_false.clone()), c: (alleged_result - result_false), - evaluation_hint: ( - EvaluationHint::Other, - EvaluationHint::Other, - EvaluationHint::Other, - ), // TODO(sragss): Is this the best we can do? + eval_hint: (EvalHint::Other, EvalHint::Other, EvalHint::Other), // TODO(sragss): Is this the best we can do? }; self.constraints.push(constraint); } @@ -460,11 +446,7 @@ impl R1CSBuilder { a: x.into(), b: y.into(), c: z.into(), - evaluation_hint: ( - EvaluationHint::Other, - EvaluationHint::Other, - EvaluationHint::Other, - ), + eval_hint: (EvalHint::Other, EvalHint::Other, EvalHint::Other), }; self.constraints.push(constraint); } @@ -787,108 +769,6 @@ impl CombinedUniformBuilder { NonUniformR1CS::new(eq, condition) } - /// inputs should be of the format [[I::0, I::0, ...], [I::1, I::1, ...], ... [I::N, I::N]] - /// aux should be of the format [[Aux(0), Aux(0), ...], ... [Aux(self.next_aux - 1), ...]] - #[tracing::instrument(skip_all, name = "CombinedUniformBuilder::compute_spartan")] - pub fn compute_spartan_Az_Bz_Cz( - &self, - inputs: &[Vec], - aux: &[Vec], - ) -> (Vec, Vec, Vec) { - assert_eq!(inputs.len(), I::COUNT); - let num_aux = self.uniform_builder.num_aux(); - assert_eq!(aux.len(), num_aux); - assert!(inputs - .iter() - .chain(aux.iter()) - .all(|inner_input| inner_input.len() == self.uniform_repeat)); - - let uniform_constraint_rows = self.uniform_repeat_constraint_rows(); - // TODO(sragss): Allocation can overshoot by up to a factor of 2, Spartan could handle non-pow-2 Az,Bz,Cz - let constraint_rows = self.constraint_rows().next_power_of_two(); - let (mut Az, mut Bz, mut Cz) = ( - unsafe_allocate_zero_vec(constraint_rows), - unsafe_allocate_zero_vec(constraint_rows), - unsafe_allocate_zero_vec(constraint_rows), - ); - - let batch_inputs = |lc: &LC| batch_inputs(lc, inputs, aux); - - // uniform_constraints: Xz[0..uniform_constraint_rows] - // TODO(sragss): Attempt moving onto key and computing from materialized rows rather than linear combos - let span = tracing::span!(tracing::Level::DEBUG, "compute_constraints"); - let enter = span.enter(); - let az_chunks = Az.par_chunks_mut(self.uniform_repeat); - let bz_chunks = Bz.par_chunks_mut(self.uniform_repeat); - let cz_chunks = Cz.par_chunks_mut(self.uniform_repeat); - - self.uniform_builder - .constraints - .par_iter() - .zip(az_chunks.zip(bz_chunks.zip(cz_chunks))) - .for_each(|(constraint, (az_chunk, (bz_chunk, cz_chunk)))| { - let a_inputs = batch_inputs(&constraint.a); - let b_inputs = batch_inputs(&constraint.b); - let c_inputs = batch_inputs(&constraint.c); - - constraint.a.evaluate_batch_mut(&a_inputs, az_chunk); - constraint.b.evaluate_batch_mut(&b_inputs, bz_chunk); - constraint.c.evaluate_batch_mut(&c_inputs, cz_chunk); - }); - drop(enter); - - // offset_equality_constraints: Xz[uniform_constraint_rows..uniform_constraint_rows + 1] - // (a - b) * condition == 0 - // For the final step we will not compute the offset terms, and will assume the condition to be set to 0 - let span = tracing::span!(tracing::Level::DEBUG, "offset_eq"); - let _enter = span.enter(); - - let constr = &self.offset_equality_constraint; - let condition_evals = constr - .cond - .1 - .evaluate_batch(&batch_inputs(&constr.cond.1), self.uniform_repeat); - let eq_a_evals = constr - .a - .1 - .evaluate_batch(&batch_inputs(&constr.a.1), self.uniform_repeat); - let eq_b_evals = constr - .b - .1 - .evaluate_batch(&batch_inputs(&constr.b.1), self.uniform_repeat); - - let Az_off = Az[uniform_constraint_rows..uniform_constraint_rows + self.uniform_repeat] - .par_iter_mut(); - let Bz_off = Bz[uniform_constraint_rows..uniform_constraint_rows + self.uniform_repeat] - .par_iter_mut(); - - (0..self.uniform_repeat) - .into_par_iter() - .zip(Az_off.zip(Bz_off)) - .for_each(|(step_index, (az, bz))| { - // Write corresponding values, if outside the step range, only include the constant. - let a_step = step_index + if constr.a.0 { 1 } else { 0 }; - let b_step = step_index + if constr.b.0 { 1 } else { 0 }; - let a = eq_a_evals - .get(a_step) - .cloned() - .unwrap_or(constr.a.1.constant_term_field()); - let b = eq_b_evals - .get(b_step) - .cloned() - .unwrap_or(constr.b.1.constant_term_field()); - *az = a - b; - - let condition_step = step_index + if constr.cond.0 { 1 } else { 0 }; - *bz = condition_evals - .get(condition_step) - .cloned() - .unwrap_or(constr.cond.1.constant_term_field()); - }); - - (Az, Bz, Cz) - } - /// inputs should be of the format [[I::0, I::0, ...], [I::1, I::1, ...], ... [I::N, I::N]] /// aux should be of the format [[Aux(0), Aux(0), ...], ... [Aux(self.next_aux - 1), ...]] #[tracing::instrument(skip_all, name = "CombinedUniformBuilder::compute_spartan_sparse")] @@ -913,36 +793,6 @@ impl CombinedUniformBuilder { let batch_inputs = |lc: &LC| batch_inputs(lc, inputs, aux); - // Enforce correctness of hints. - // TODO(sragss): Can be moved into assert_valid. - #[cfg(test)] - self.uniform_builder - .constraints - .iter() - .for_each(|constraint| { - let assert_hint = |constraint: &Constraint| { - let a_inputs = batch_inputs(&constraint.a); - let b_inputs = batch_inputs(&constraint.b); - let c_inputs = batch_inputs(&constraint.c); - - let a = constraint.a.evaluate_batch(&a_inputs, self.uniform_repeat); - let b = constraint.b.evaluate_batch(&b_inputs, self.uniform_repeat); - let c = constraint.c.evaluate_batch(&c_inputs, self.uniform_repeat); - - if constraint.evaluation_hint.0 == EvaluationHint::Zero { - a.iter().for_each(|item| assert_eq!(*item, F::zero(),)); - } - if constraint.evaluation_hint.1 == EvaluationHint::Zero { - b.iter().for_each(|item| assert_eq!(*item, F::zero(),)); - } - if constraint.evaluation_hint.2 == EvaluationHint::Zero { - c.iter().for_each(|item| assert_eq!(*item, F::zero(),)); - } - }; - - assert_hint(constraint); - }); - // uniform_constraints: Xz[0..uniform_constraint_rows] let span = tracing::span!(tracing::Level::DEBUG, "uniform_evals"); let _enter = span.enter(); @@ -955,7 +805,7 @@ impl CombinedUniformBuilder { let mut dense_output_buffer = unsafe_allocate_zero_vec(self.uniform_repeat); let mut evaluate_lc_chunk = |hint, lc: &LC| { - if hint != EvaluationHint::Zero { + if hint != EvalHint::Zero { let inputs = batch_inputs(lc); lc.evaluate_batch_mut(&inputs, &mut dense_output_buffer); @@ -977,11 +827,11 @@ impl CombinedUniformBuilder { }; let a_chunk: Vec<(F, usize)> = - evaluate_lc_chunk(constraint.evaluation_hint.0, &constraint.a); + evaluate_lc_chunk(constraint.eval_hint.0, &constraint.a); let b_chunk: Vec<(F, usize)> = - evaluate_lc_chunk(constraint.evaluation_hint.1, &constraint.b); + evaluate_lc_chunk(constraint.eval_hint.1, &constraint.b); let c_chunk: Vec<(F, usize)> = - evaluate_lc_chunk(constraint.evaluation_hint.2, &constraint.c); + evaluate_lc_chunk(constraint.eval_hint.2, &constraint.c); (a_chunk, b_chunk, c_chunk) }) @@ -990,7 +840,7 @@ impl CombinedUniformBuilder { let (mut az_sparse, mut bz_sparse, cz_sparse) = par_flatten_triple( uni_constraint_evals, unsafe_allocate_sparse_zero_vec, - self.uniform_repeat, + self.uniform_repeat, // Capacity overhead for offset_eq constraints. ); // offset_equality_constraints: Xz[uniform_constraint_rows..uniform_constraint_rows + 1] @@ -1055,23 +905,29 @@ impl CombinedUniformBuilder { let cz_poly = SparsePolynomial::new(num_vars, cz_sparse); #[cfg(test)] - self.assert_valid( - &az_poly.clone().to_dense().evals_ref(), - &bz_poly.clone().to_dense().evals_ref(), - &cz_poly.clone().to_dense().evals_ref(), - ); + self.assert_valid(&az_poly, &bz_poly, &cz_poly); (az_poly, bz_poly, cz_poly) } #[cfg(test)] - pub fn assert_valid(&self, az: &[F], bz: &[F], cz: &[F]) { + pub fn assert_valid( + &self, + az: &SparsePolynomial, + bz: &SparsePolynomial, + cz: &SparsePolynomial, + ) { + let az = az.clone().to_dense(); + let bz = bz.clone().to_dense(); + let cz = cz.clone().to_dense(); + let rows = az.len(); assert_eq!(bz.len(), rows); assert_eq!(cz.len(), rows); + for constraint_index in 0..rows { + let uniform_constraint_index = constraint_index / self.uniform_repeat; if az[constraint_index] * bz[constraint_index] != cz[constraint_index] { - let uniform_constraint_index = constraint_index / self.uniform_repeat; let step_index = constraint_index % self.uniform_repeat; panic!( "Mismatch at global constraint {constraint_index} => {:?}\n\ @@ -1080,6 +936,20 @@ impl CombinedUniformBuilder { self.uniform_builder.constraints[uniform_constraint_index] ); } + // Verify hints + if constraint_index < self.uniform_repeat_constraint_rows() { + let (hint_a, hint_b, hint_c) = + self.uniform_builder.constraints[uniform_constraint_index].eval_hint; + if hint_a == EvalHint::Zero { + assert_eq!(az[constraint_index], F::zero(), "Mismatch at global constraint {constraint_index} uniform constraint: {uniform_constraint_index}"); + } + if hint_b == EvalHint::Zero { + assert_eq!(bz[constraint_index], F::zero(), "Mismatch at global constraint {constraint_index} uniform constraint: {uniform_constraint_index}"); + } + if hint_c == EvalHint::Zero { + assert_eq!(cz[constraint_index], F::zero(), "Mismatch at global constraint {constraint_index} uniform constraint: {uniform_constraint_index}"); + } + } } } } @@ -1482,11 +1352,7 @@ mod tests { let aux = combined_builder.compute_aux(&inputs); assert_eq!(aux, vec![vec![Fr::from(5 * 7), Fr::from(11 * 13)]]); - let (az, bz, cz) = combined_builder.compute_spartan_Az_Bz_Cz(&inputs, &aux); - assert_eq!(az.len(), 4); - assert_eq!(bz.len(), 4); - assert_eq!(cz.len(), 4); - + let (az, bz, cz) = combined_builder.compute_spartan_Az_Bz_Cz_sparse(&inputs, &aux); combined_builder.assert_valid(&az, &bz, &cz); } @@ -1546,11 +1412,7 @@ mod tests { ] ); - let (az, bz, cz) = combined_builder.compute_spartan_Az_Bz_Cz(&inputs, &aux); - assert_eq!(az.len(), 16); - assert_eq!(bz.len(), 16); - assert_eq!(cz.len(), 16); - + let (az, bz, cz) = combined_builder.compute_spartan_Az_Bz_Cz_sparse(&inputs, &aux); combined_builder.assert_valid(&az, &bz, &cz); } @@ -1594,11 +1456,7 @@ mod tests { let aux = combined_builder.compute_aux(&inputs); assert_eq!(aux, vec![vec![Fr::from(5 * 7), Fr::from(5 * 13)]]); - let (az, bz, cz) = combined_builder.compute_spartan_Az_Bz_Cz(&inputs, &aux); - assert_eq!(az.len(), 4); - assert_eq!(bz.len(), 4); - assert_eq!(cz.len(), 4); - + let (az, bz, cz) = combined_builder.compute_spartan_Az_Bz_Cz_sparse(&inputs, &aux); combined_builder.assert_valid(&az, &bz, &cz); } @@ -1669,11 +1527,16 @@ mod tests { flat_witness.resize(flat_witness.len().next_power_of_two(), Fr::zero()); flat_witness.push(Fr::one()); flat_witness.resize(flat_witness.len().next_power_of_two(), Fr::zero()); - let (mut builder_az, mut builder_bz, mut builder_cz) = - builder.compute_spartan_Az_Bz_Cz(&witness_segments, &[]); - builder_az.resize(key.num_rows_total(), Fr::zero()); - builder_bz.resize(key.num_rows_total(), Fr::zero()); - builder_cz.resize(key.num_rows_total(), Fr::zero()); + + let (builder_az, builder_bz, builder_cz) = + builder.compute_spartan_Az_Bz_Cz_sparse(&witness_segments, &[]); + let mut dense_az = builder_az.to_dense().evals(); + let mut dense_bz = builder_bz.to_dense().evals(); + let mut dense_cz = builder_cz.to_dense().evals(); + dense_az.resize(key.num_rows_total(), Fr::zero()); + dense_bz.resize(key.num_rows_total(), Fr::zero()); + dense_cz.resize(key.num_rows_total(), Fr::zero()); + for row in 0..key.num_rows_total() { let mut az_eval = Fr::zero(); let mut bz_eval = Fr::zero(); @@ -1685,9 +1548,9 @@ mod tests { } // Row 11 is the problem! Builder thinks this row should be 0. big_a thinks this row should be 17 (13 + 4) - assert_eq!(builder_az[row], az_eval, "Row {row} failed in az_eval."); - assert_eq!(builder_bz[row], bz_eval, "Row {row} failed in bz_eval."); - assert_eq!(builder_cz[row], cz_eval, "Row {row} failed in cz_eval."); + assert_eq!(dense_az[row], az_eval, "Row {row} failed in az_eval."); + assert_eq!(dense_bz[row], bz_eval, "Row {row} failed in bz_eval."); + assert_eq!(dense_cz[row], cz_eval, "Row {row} failed in cz_eval."); } } } diff --git a/jolt-core/src/r1cs/jolt_constraints.rs b/jolt-core/src/r1cs/jolt_constraints.rs index 2df3cdd28..e59207e1d 100644 --- a/jolt-core/src/r1cs/jolt_constraints.rs +++ b/jolt-core/src/r1cs/jolt_constraints.rs @@ -334,8 +334,8 @@ mod tests { inputs[JoltIn::OpFlags_IsImm as usize][0] = Fr::zero(); // second_operand = rs2 => immediate let aux = combined_builder.compute_aux(&inputs); - let (az, bz, cz) = combined_builder.compute_spartan_Az_Bz_Cz(&inputs, &aux); - combined_builder.assert_valid(&az, &bz, &cz); + // Implicitly asserts validity + let (az, bz, cz) = combined_builder.compute_spartan_Az_Bz_Cz_sparse(&inputs, &aux); } } diff --git a/jolt-core/src/r1cs/key.rs b/jolt-core/src/r1cs/key.rs index f4dcfb166..400524af6 100644 --- a/jolt-core/src/r1cs/key.rs +++ b/jolt-core/src/r1cs/key.rs @@ -566,7 +566,7 @@ mod test { inputs[TestInputs::OpFlags1 as usize][3] = Fr::from(3); // Confirms validity of constraints - let (_az, _bz, _cz) = combined_builder.compute_spartan_Az_Bz_Cz(&inputs, &[]); + let (_az, _bz, _cz) = combined_builder.compute_spartan_Az_Bz_Cz_sparse(&inputs, &[]); let key = UniformSpartanKey::from_builder(&combined_builder); diff --git a/jolt-core/src/r1cs/spartan.rs b/jolt-core/src/r1cs/spartan.rs index b436769e3..f6e1d5ee7 100644 --- a/jolt-core/src/r1cs/spartan.rs +++ b/jolt-core/src/r1cs/spartan.rs @@ -6,7 +6,6 @@ use crate::poly::commitment::commitment_scheme::CommitmentScheme; use crate::r1cs::key::UniformSpartanKey; use crate::r1cs::special_polys::SegmentedPaddedWitness; use crate::utils::math::Math; -use crate::utils::profiling; use crate::utils::thread::drop_in_background_thread; use crate::utils::transcript::ProofTranscript; @@ -108,16 +107,12 @@ impl> UniformSpartanProof { let tau = (0..num_rounds_x) .map(|_i| transcript.challenge_scalar(b"t")) .collect::>(); - profiling::print_current_memory_usage("pre_poly_tau"); let mut poly_tau = DensePolynomial::new(EqPolynomial::evals(&tau)); - profiling::print_current_memory_usage("post_poly_tau"); let inputs = &segmented_padded_witness.segments[0..I::COUNT]; let aux = &segmented_padded_witness.segments[I::COUNT..]; - profiling::print_current_memory_usage("pre_az_bz_cz"); let (mut az, mut bz, mut cz) = constraint_builder.compute_spartan_Az_Bz_Cz_sparse(inputs, aux); - profiling::print_current_memory_usage("post_az_bz_cz"); let comb_func_outer = |A: &F, B: &F, C: &F, D: &F| -> F { // Below is an optimized form of: *A * (*B * *C - *D) @@ -137,8 +132,6 @@ impl> UniformSpartanProof { } }; - // profiling::start_memory_tracing_span("outersumcheck"); - profiling::print_current_memory_usage("pre_outersumcheck"); let (outer_sumcheck_proof, outer_sumcheck_r, outer_sumcheck_claims) = SumcheckInstanceProof::prove_spartan_cubic::<_>( &F::zero(), // claim is zero @@ -151,9 +144,7 @@ impl> UniformSpartanProof { transcript, ); let outer_sumcheck_r: Vec = outer_sumcheck_r.into_iter().rev().collect(); - // drop_in_background_thread((poly_Az, poly_Bz, poly_Cz, poly_tau)); - drop((az, bz, cz, poly_tau)); - profiling::print_current_memory_usage("post_outersumcheck"); + drop_in_background_thread((az, bz, cz, poly_tau)); // claims from the end of sum-check // claim_Az is the (scalar) value v_A = \sum_y A(r_x, y) * z(r_x) where r_x is the sumcheck randomness @@ -181,10 +172,8 @@ impl> UniformSpartanProof { .ilog2(); let (rx_con, rx_ts) = outer_sumcheck_r.split_at(outer_sumcheck_r.len() - num_steps_bits as usize); - profiling::print_current_memory_usage("pre_poly_ABC"); let mut poly_ABC = DensePolynomial::new(key.evaluate_r1cs_mle_rlc(rx_con, rx_ts, r_inner_sumcheck_RLC)); - profiling::print_current_memory_usage("post_poly_ABC"); let (inner_sumcheck_proof, inner_sumcheck_r, _claims_inner) = SumcheckInstanceProof::prove_spartan_quadratic::>( @@ -194,8 +183,7 @@ impl> UniformSpartanProof { &segmented_padded_witness, transcript, ); - // drop_in_background_thread(poly_ABC); - drop(poly_ABC); + drop_in_background_thread(poly_ABC); // Requires 'r_col_segment_bits' to index the (const, segment). Within that segment we index the step using 'r_col_step' let r_col_segment_bits = key.uniform_r1cs.num_vars.next_power_of_two().log_2() + 1; From fa4fefb1e2d7acbfc80ec440ca660c831ec16e76 Mon Sep 17 00:00:00 2001 From: sragss Date: Wed, 26 Jun 2024 11:39:39 -0700 Subject: [PATCH 15/43] remove duplicate code (chunk_no_ophans) --- jolt-core/src/jolt/vm/mod.rs | 3 +- jolt-core/src/r1cs/builder.rs | 10 +-- jolt-core/src/r1cs/jolt_constraints.rs | 2 +- jolt-core/src/r1cs/key.rs | 2 +- jolt-core/src/r1cs/spartan.rs | 3 +- jolt-core/src/r1cs/special_polys.rs | 120 +++++++++---------------- jolt-core/src/subprotocols/sumcheck.rs | 14 --- 7 files changed, 53 insertions(+), 101 deletions(-) diff --git a/jolt-core/src/jolt/vm/mod.rs b/jolt-core/src/jolt/vm/mod.rs index e0d0188d6..fb3b5e55d 100644 --- a/jolt-core/src/jolt/vm/mod.rs +++ b/jolt-core/src/jolt/vm/mod.rs @@ -4,7 +4,6 @@ use crate::field::JoltField; use crate::r1cs::builder::CombinedUniformBuilder; use crate::r1cs::jolt_constraints::{construct_jolt_constraints, JoltIn}; use crate::r1cs::spartan::{self, UniformSpartanProof}; -use crate::utils::profiling; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use ark_std::log2; use common::constants::RAM_START_ADDRESS; @@ -590,7 +589,7 @@ pub trait Jolt, const C: usize, c #[cfg(test)] { - let (az, bz, cz) = builder.compute_spartan_Az_Bz_Cz_sparse(&inputs_flat, &aux); + let (az, bz, cz) = builder.compute_spartan_Az_Bz_Cz(&inputs_flat, &aux); builder.assert_valid(&az, &bz, &cz); } diff --git a/jolt-core/src/r1cs/builder.rs b/jolt-core/src/r1cs/builder.rs index 124ec573d..e2cf70af9 100644 --- a/jolt-core/src/r1cs/builder.rs +++ b/jolt-core/src/r1cs/builder.rs @@ -772,7 +772,7 @@ impl CombinedUniformBuilder { /// inputs should be of the format [[I::0, I::0, ...], [I::1, I::1, ...], ... [I::N, I::N]] /// aux should be of the format [[Aux(0), Aux(0), ...], ... [Aux(self.next_aux - 1), ...]] #[tracing::instrument(skip_all, name = "CombinedUniformBuilder::compute_spartan_sparse")] - pub fn compute_spartan_Az_Bz_Cz_sparse( + pub fn compute_spartan_Az_Bz_Cz( &self, inputs: &[Vec], aux: &[Vec], @@ -1352,7 +1352,7 @@ mod tests { let aux = combined_builder.compute_aux(&inputs); assert_eq!(aux, vec![vec![Fr::from(5 * 7), Fr::from(11 * 13)]]); - let (az, bz, cz) = combined_builder.compute_spartan_Az_Bz_Cz_sparse(&inputs, &aux); + let (az, bz, cz) = combined_builder.compute_spartan_Az_Bz_Cz(&inputs, &aux); combined_builder.assert_valid(&az, &bz, &cz); } @@ -1412,7 +1412,7 @@ mod tests { ] ); - let (az, bz, cz) = combined_builder.compute_spartan_Az_Bz_Cz_sparse(&inputs, &aux); + let (az, bz, cz) = combined_builder.compute_spartan_Az_Bz_Cz(&inputs, &aux); combined_builder.assert_valid(&az, &bz, &cz); } @@ -1456,7 +1456,7 @@ mod tests { let aux = combined_builder.compute_aux(&inputs); assert_eq!(aux, vec![vec![Fr::from(5 * 7), Fr::from(5 * 13)]]); - let (az, bz, cz) = combined_builder.compute_spartan_Az_Bz_Cz_sparse(&inputs, &aux); + let (az, bz, cz) = combined_builder.compute_spartan_Az_Bz_Cz(&inputs, &aux); combined_builder.assert_valid(&az, &bz, &cz); } @@ -1529,7 +1529,7 @@ mod tests { flat_witness.resize(flat_witness.len().next_power_of_two(), Fr::zero()); let (builder_az, builder_bz, builder_cz) = - builder.compute_spartan_Az_Bz_Cz_sparse(&witness_segments, &[]); + builder.compute_spartan_Az_Bz_Cz(&witness_segments, &[]); let mut dense_az = builder_az.to_dense().evals(); let mut dense_bz = builder_bz.to_dense().evals(); let mut dense_cz = builder_cz.to_dense().evals(); diff --git a/jolt-core/src/r1cs/jolt_constraints.rs b/jolt-core/src/r1cs/jolt_constraints.rs index e59207e1d..6b1ef1125 100644 --- a/jolt-core/src/r1cs/jolt_constraints.rs +++ b/jolt-core/src/r1cs/jolt_constraints.rs @@ -336,6 +336,6 @@ mod tests { let aux = combined_builder.compute_aux(&inputs); // Implicitly asserts validity - let (az, bz, cz) = combined_builder.compute_spartan_Az_Bz_Cz_sparse(&inputs, &aux); + let (az, bz, cz) = combined_builder.compute_spartan_Az_Bz_Cz(&inputs, &aux); } } diff --git a/jolt-core/src/r1cs/key.rs b/jolt-core/src/r1cs/key.rs index 400524af6..f4dcfb166 100644 --- a/jolt-core/src/r1cs/key.rs +++ b/jolt-core/src/r1cs/key.rs @@ -566,7 +566,7 @@ mod test { inputs[TestInputs::OpFlags1 as usize][3] = Fr::from(3); // Confirms validity of constraints - let (_az, _bz, _cz) = combined_builder.compute_spartan_Az_Bz_Cz_sparse(&inputs, &[]); + let (_az, _bz, _cz) = combined_builder.compute_spartan_Az_Bz_Cz(&inputs, &[]); let key = UniformSpartanKey::from_builder(&combined_builder); diff --git a/jolt-core/src/r1cs/spartan.rs b/jolt-core/src/r1cs/spartan.rs index f6e1d5ee7..7e015c3f5 100644 --- a/jolt-core/src/r1cs/spartan.rs +++ b/jolt-core/src/r1cs/spartan.rs @@ -111,8 +111,7 @@ impl> UniformSpartanProof { let inputs = &segmented_padded_witness.segments[0..I::COUNT]; let aux = &segmented_padded_witness.segments[I::COUNT..]; - let (mut az, mut bz, mut cz) = - constraint_builder.compute_spartan_Az_Bz_Cz_sparse(inputs, aux); + let (mut az, mut bz, mut cz) = constraint_builder.compute_spartan_Az_Bz_Cz(inputs, aux); let comb_func_outer = |A: &F, B: &F, C: &F, D: &F| -> F { // Below is an optimized form of: *A * (*B * *C - *D) diff --git a/jolt-core/src/r1cs/special_polys.rs b/jolt-core/src/r1cs/special_polys.rs index d757a24c7..8a4361f04 100644 --- a/jolt-core/src/r1cs/special_polys.rs +++ b/jolt-core/src/r1cs/special_polys.rs @@ -5,9 +5,7 @@ use crate::{ compute_dotproduct_low_optimized, math::Math, mul_0_1_optimized, - thread::{ - drop_in_background_thread, unsafe_allocate_sparse_zero_vec, unsafe_allocate_zero_vec, - }, + thread::{drop_in_background_thread, unsafe_allocate_sparse_zero_vec}, }, }; use num_integer::Integer; @@ -80,9 +78,9 @@ impl SparsePolynomial { .sum() } - /// Returns n chunks of roughly even size without orphaning siblings (adjacent dense indices). Additionally returns a vector of (low, high] dense index ranges. + /// Returns `n` chunks of roughly even size without separating siblings (adjacent dense indices). Additionally returns a vector of [low, high) dense index ranges. #[tracing::instrument(skip_all)] - fn chunk_no_orphans(&self, n: usize) -> (Vec<&[(F, usize)]>, Vec<(usize, usize)>) { + fn chunk_no_split_siblings(&self, n: usize) -> (Vec<&[(F, usize)]>, Vec<(usize, usize)>) { if self.Z.len() < n * 2 { return (vec![(&self.Z)], vec![(0, self.num_vars.pow2())]); } @@ -153,38 +151,34 @@ impl SparsePolynomial { #[tracing::instrument(skip_all)] pub fn bound_poly_var_bot_par(&mut self, r: &F) { // TODO(sragss): better parallelism. + let (chunks, _range) = self.chunk_no_split_siblings(rayon::current_num_threads() * 8); + + // Calc chunk sizes post-binding for pre-allocation. let count_span = tracing::span!(tracing::Level::DEBUG, "counting"); let count_enter = count_span.enter(); - let (chunks, _range) = self.chunk_no_orphans(rayon::current_num_threads() * 8); let chunk_sizes: Vec = chunks .par_iter() .map(|chunk| { - let mut chunk_size = 0; - let mut i = 0; - while i < chunk.len() { - chunk_size += 1; - - // If they're siblings, avoid double counting - if chunk[i].1.is_even() - && i + 1 < chunk.len() - && chunk[i].1 + 1 == chunk[i + 1].1 - { - i += 1; - } - i += 1; - } - chunk_size + // Count each pair of siblings if at least one is present. + chunk + .iter() + .enumerate() + .filter(|(i, (_value, index))| { + // Always count odd, only count even indices when the paired odd index is not present. + !index.is_even() || i + 1 >= chunk.len() || index + 1 != chunk[i + 1].1 + }) + .count() }) .collect(); drop(count_enter); - let alloc_span = tracing::span!(tracing::Level::DEBUG, "alloc_new_Z"); + let alloc_span = tracing::span!(tracing::Level::DEBUG, "alloc"); let alloc_enter = alloc_span.enter(); let total_len: usize = chunk_sizes.iter().sum(); let mut new_Z: Vec<(F, usize)> = unsafe_allocate_sparse_zero_vec(total_len); drop(alloc_enter); - let mut mutable_chunks: Vec<&mut [(F, usize)]> = vec![]; + let mut mutable_chunks: Vec<&mut [(F, usize)]> = Vec::with_capacity(chunk_sizes.len()); let mut remainder = new_Z.as_mut_slice(); for chunk_size in chunk_sizes { let (first, second) = remainder.split_at_mut(chunk_size); @@ -193,6 +187,7 @@ impl SparsePolynomial { } assert_eq!(mutable_chunks.len(), chunks.len()); + // Bind each chunk in parallel chunks .into_par_iter() .zip(mutable_chunks.par_iter_mut()) @@ -203,23 +198,28 @@ impl SparsePolynomial { for (sparse_index, (value, dense_index)) in chunk.iter().enumerate() { if dense_index.is_even() { let new_dense_index = dense_index / 2; + if chunk.len() >= 2 && sparse_index <= chunk.len() - 2 && chunk[sparse_index + 1].1 == dense_index + 1 { + // (low, high) present let upper = chunk[sparse_index + 1].0; let eval = *value + mul_0_1_optimized(r, &(upper - value)); mutable[write_index] = (eval, new_dense_index); write_index += 1; } else { + // (low, _) present mutable[write_index] = (mul_0_1_optimized(&(F::one() - r), value), new_dense_index); write_index += 1; } } else { if sparse_index > 0 && chunk[sparse_index - 1].1 == dense_index - 1 { + // (low, high) present, but handeled prior continue; } else { + // (_, high) present let new_dense_index = (dense_index - 1) / 2; mutable[write_index] = (mul_0_1_optimized(r, value), new_dense_index); write_index += 1; @@ -248,7 +248,7 @@ impl SparsePolynomial { #[cfg(test)] #[tracing::instrument(skip_all)] pub fn to_dense(self) -> DensePolynomial { - use crate::utils::math::Math; + use crate::utils::{math::Math, thread::unsafe_allocate_zero_vec}; let mut evals = unsafe_allocate_zero_vec(self.num_vars.pow2()); @@ -276,9 +276,9 @@ impl<'a, F: JoltField> SparseTripleIterator<'a, F> { c: &'a SparsePolynomial, n: usize, ) -> Vec { - // When the instance is small enough, don't worry about parallelism + // Don't chunk for small instances let total_len = a.num_vars.pow2(); - if n * 2 > b.Z.len() { + if b.Z.len() < n * 2 { return vec![SparseTripleIterator { dense_index: 0, end_index: total_len, @@ -287,55 +287,28 @@ impl<'a, F: JoltField> SparseTripleIterator<'a, F> { c: &c.Z, }]; } - // Can be made more generic, but this is an optimization / simplification. - assert!( - b.Z.len() >= a.Z.len() && b.Z.len() >= c.Z.len(), - "b.Z.len() assumed to be longest of a, b, and c" - ); - // TODO(sragss): Explain the strategy + // B is assumed most dense. Parallelism depends on evenly distributing B across threads. + assert!(b.Z.len() >= a.Z.len() && b.Z.len() >= c.Z.len()); - let target_chunk_size = b.Z.len() / n; - let mut b_chunks: Vec<&[(F, usize)]> = Vec::with_capacity(n); - let mut dense_ranges: Vec<(usize, usize)> = Vec::with_capacity(n); - let mut dense_start_index = 0; - let mut sparse_start_index = 0; - let mut sparse_end_index = target_chunk_size; - for _ in 1..n { - let mut dense_end_index = b.Z[sparse_end_index].1; - if dense_end_index % 2 != 0 { - dense_end_index += 1; - sparse_end_index += 1; - } - b_chunks.push(&b.Z[sparse_start_index..sparse_end_index]); - dense_ranges.push((dense_start_index, dense_end_index)); - dense_start_index = dense_end_index; + // TODO(sragss): Explain the strategy - sparse_start_index = sparse_end_index; - sparse_end_index = std::cmp::min(sparse_end_index + target_chunk_size, b.Z.len() - 1); - } - b_chunks.push(&b.Z[sparse_start_index..]); - let highest_non_zero = { - let a_last = a.Z.last().map(|&(_, index)| index); - let b_last = b.Z.last().map(|&(_, index)| index); - let c_last = c.Z.last().map(|&(_, index)| index); - *a_last - .iter() - .chain(b_last.iter()) - .chain(c_last.iter()) - .max() - .unwrap() - }; - dense_ranges.push((dense_start_index, highest_non_zero + 1)); + let (b_chunks, mut dense_ranges) = b.chunk_no_split_siblings(n); + let highest_non_zero = [&a.Z, &b.Z, &c.Z] + .iter() + .filter_map(|z| z.last().map(|&(_, index)| index)) + .max() + .unwrap(); + dense_ranges.last_mut().unwrap().1 = highest_non_zero + 1; assert_eq!(b_chunks.len(), n); assert_eq!(dense_ranges.len(), n); - // Create chunks which overlap with b's sparse indices + // Create chunks of (a, c) which overlap with b's sparse indices let mut a_chunks: Vec<&[(F, usize)]> = vec![&[]; n]; let mut c_chunks: Vec<&[(F, usize)]> = vec![&[]; n]; let mut a_i = 0; let mut c_i = 0; - let span = tracing::span!(tracing::Level::DEBUG, "a, c scanning"); + let span = tracing::span!(tracing::Level::DEBUG, "a_c_chunking"); let _enter = span.enter(); for (chunk_index, range) in dense_ranges.iter().enumerate().skip(1) { // Find the corresponding a, c chunks @@ -378,17 +351,12 @@ impl<'a, F: JoltField> SparseTripleIterator<'a, F> { .zip(dense_ranges.iter()) { #[cfg(test)] - { - assert!(a_chunk - .iter() - .all(|(_, index)| *index >= range.0 && *index <= range.1)); - assert!(b_chunk - .iter() - .all(|(_, index)| *index >= range.0 && *index <= range.1)); - assert!(c_chunk - .iter() - .all(|(_, index)| *index >= range.0 && *index <= range.1)); + for chunk in &[a_chunk, b_chunk, c_chunk] { + for (_, index) in chunk.iter() { + assert!(*index >= range.0 && *index <= range.1); + } } + let iter = SparseTripleIterator { dense_index: range.0, end_index: range.1, @@ -672,7 +640,7 @@ mod tests { let mut rng = rand::thread_rng(); let prob_exists = 0.32; - let num_vars = 10; + let num_vars = 5; let total_len = 1 << num_vars; let mut a = vec![]; diff --git a/jolt-core/src/subprotocols/sumcheck.rs b/jolt-core/src/subprotocols/sumcheck.rs index ab5d919c9..a405fbfa3 100644 --- a/jolt-core/src/subprotocols/sumcheck.rs +++ b/jolt-core/src/subprotocols/sumcheck.rs @@ -298,20 +298,6 @@ impl SumcheckInstanceProof { poly_A.bound_poly_var_bot_par(&r_i); poly_B.bound_poly_var_bot_par(&r_i); poly_C.bound_poly_var_bot_par(&r_i); - // rayon::join( - // || poly_eq.bound_poly_var_bot(&r_i), - // || { - // rayon::join( - // || poly_A.bound_poly_var_bot_par(&r_i), - // || { - // rayon::join( - // || poly_B.bound_poly_var_bot_par(&r_i), - // || poly_C.bound_poly_var_bot_par(&r_i), - // ) - // }, - // ) - // }, - // ); } ( From 403b66a252c55df9a1f265d6213cf0e2c5eaadc5 Mon Sep 17 00:00:00 2001 From: sragss Date: Wed, 26 Jun 2024 11:42:59 -0700 Subject: [PATCH 16/43] warnings --- jolt-core/src/r1cs/spartan.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/jolt-core/src/r1cs/spartan.rs b/jolt-core/src/r1cs/spartan.rs index 7e015c3f5..0058f91e2 100644 --- a/jolt-core/src/r1cs/spartan.rs +++ b/jolt-core/src/r1cs/spartan.rs @@ -11,7 +11,6 @@ use crate::utils::thread::drop_in_background_thread; use crate::utils::transcript::ProofTranscript; use ark_serialize::CanonicalDeserialize; use ark_serialize::CanonicalSerialize; -use rayon::prelude::*; use thiserror::Error; From 5d51a234e0d72fdabfb19d5137f478a93871a39d Mon Sep 17 00:00:00 2001 From: sragss Date: Wed, 26 Jun 2024 11:47:30 -0700 Subject: [PATCH 17/43] clippy --- jolt-core/src/lib.rs | 2 +- jolt-core/src/poly/commitment/mock.rs | 4 +-- jolt-core/src/r1cs/builder.rs | 5 ++-- jolt-core/src/r1cs/jolt_constraints.rs | 2 +- jolt-core/src/r1cs/special_polys.rs | 29 +++++++++---------- .../src/subprotocols/grand_product_quarks.rs | 4 +-- 6 files changed, 21 insertions(+), 25 deletions(-) diff --git a/jolt-core/src/lib.rs b/jolt-core/src/lib.rs index f808ed946..e2dc21197 100644 --- a/jolt-core/src/lib.rs +++ b/jolt-core/src/lib.rs @@ -8,7 +8,7 @@ #![feature(generic_const_exprs)] #![feature(iter_next_chunk)] #![allow(long_running_const_eval)] - +#[allow(clippy::len_without_is_empty)] #[cfg(feature = "host")] pub mod benches; diff --git a/jolt-core/src/poly/commitment/mock.rs b/jolt-core/src/poly/commitment/mock.rs index e191ff454..ab283a53f 100644 --- a/jolt-core/src/poly/commitment/mock.rs +++ b/jolt-core/src/poly/commitment/mock.rs @@ -41,9 +41,7 @@ impl CommitmentScheme for MockCommitScheme { type Proof = MockProof; type BatchedProof = MockProof; - fn setup(_shapes: &[CommitShape]) -> Self::Setup { - () - } + fn setup(_shapes: &[CommitShape]) -> Self::Setup {} fn commit(poly: &DensePolynomial, _setup: &Self::Setup) -> Self::Commitment { MockCommitment { poly: poly.to_owned(), diff --git a/jolt-core/src/r1cs/builder.rs b/jolt-core/src/r1cs/builder.rs index e2cf70af9..f0297fbe9 100644 --- a/jolt-core/src/r1cs/builder.rs +++ b/jolt-core/src/r1cs/builder.rs @@ -46,7 +46,7 @@ struct Constraint { impl Constraint { #[cfg(test)] - fn is_sat(&self, inputs: &Vec) -> bool { + fn is_sat(&self, inputs: &[i64]) -> bool { // Find the number of variables and the number of aux. Inputs should be equal to this combined length let num_inputs = I::COUNT; @@ -772,6 +772,7 @@ impl CombinedUniformBuilder { /// inputs should be of the format [[I::0, I::0, ...], [I::1, I::1, ...], ... [I::N, I::N]] /// aux should be of the format [[Aux(0), Aux(0), ...], ... [Aux(self.next_aux - 1), ...]] #[tracing::instrument(skip_all, name = "CombinedUniformBuilder::compute_spartan_sparse")] + #[allow(clippy::type_complexity)] pub fn compute_spartan_Az_Bz_Cz( &self, inputs: &[Vec], @@ -967,7 +968,7 @@ mod tests { ) -> F { let multi_step_inputs: Vec> = single_step_inputs .iter() - .map(|input| vec![input.clone()]) + .map(|input| vec![*input]) .collect(); let multi_step_inputs_ref: Vec<&[F]> = multi_step_inputs.iter().map(|v| v.as_slice()).collect(); diff --git a/jolt-core/src/r1cs/jolt_constraints.rs b/jolt-core/src/r1cs/jolt_constraints.rs index 6b1ef1125..221d9a7c8 100644 --- a/jolt-core/src/r1cs/jolt_constraints.rs +++ b/jolt-core/src/r1cs/jolt_constraints.rs @@ -335,7 +335,7 @@ mod tests { let aux = combined_builder.compute_aux(&inputs); - // Implicitly asserts validity let (az, bz, cz) = combined_builder.compute_spartan_Az_Bz_Cz(&inputs, &aux); + combined_builder.assert_valid(&az, &bz, &cz); } } diff --git a/jolt-core/src/r1cs/special_polys.rs b/jolt-core/src/r1cs/special_polys.rs index 8a4361f04..47f291ce9 100644 --- a/jolt-core/src/r1cs/special_polys.rs +++ b/jolt-core/src/r1cs/special_polys.rs @@ -80,6 +80,7 @@ impl SparsePolynomial { /// Returns `n` chunks of roughly even size without separating siblings (adjacent dense indices). Additionally returns a vector of [low, high) dense index ranges. #[tracing::instrument(skip_all)] + #[allow(clippy::type_complexity)] fn chunk_no_split_siblings(&self, n: usize) -> (Vec<&[(F, usize)]>, Vec<(usize, usize)>) { if self.Z.len() < n * 2 { return (vec![(&self.Z)], vec![(0, self.num_vars.pow2())]); @@ -135,13 +136,11 @@ impl SparsePolynomial { } else { new_Z.push(((F::one() - r) * value, new_dense_index)); } + } else if sparse_index > 0 && self.Z[sparse_index - 1].1 == dense_index - 1 { + continue; } else { - if sparse_index > 0 && self.Z[sparse_index - 1].1 == dense_index - 1 { - continue; - } else { - let new_dense_index = (dense_index - 1) / 2; - new_Z.push((*r * value, new_dense_index)); - } + let new_dense_index = (dense_index - 1) / 2; + new_Z.push((*r * value, new_dense_index)); } } self.Z = new_Z; @@ -214,16 +213,14 @@ impl SparsePolynomial { (mul_0_1_optimized(&(F::one() - r), value), new_dense_index); write_index += 1; } + } else if sparse_index > 0 && chunk[sparse_index - 1].1 == dense_index - 1 { + // (low, high) present, but handeled prior + continue; } else { - if sparse_index > 0 && chunk[sparse_index - 1].1 == dense_index - 1 { - // (low, high) present, but handeled prior - continue; - } else { - // (_, high) present - let new_dense_index = (dense_index - 1) / 2; - mutable[write_index] = (mul_0_1_optimized(r, value), new_dense_index); - write_index += 1; - } + // (_, high) present + let new_dense_index = (dense_index - 1) / 2; + mutable[write_index] = (mul_0_1_optimized(r, value), new_dense_index); + write_index += 1; } } }); @@ -235,7 +232,7 @@ impl SparsePolynomial { pub fn final_eval(&self) -> F { assert_eq!(self.num_vars, 0); - if self.Z.len() == 0 { + if self.Z.is_empty() { F::zero() } else { assert_eq!(self.Z.len(), 1); diff --git a/jolt-core/src/subprotocols/grand_product_quarks.rs b/jolt-core/src/subprotocols/grand_product_quarks.rs index 2ceb7ac9e..e74a79f72 100644 --- a/jolt-core/src/subprotocols/grand_product_quarks.rs +++ b/jolt-core/src/subprotocols/grand_product_quarks.rs @@ -618,7 +618,7 @@ mod quark_grand_product_tests { fn quark_e2e() { const LAYER_SIZE: usize = 1 << 8; - let mut rng = rand_chacha::ChaCha20Rng::seed_from_u64(9 as u64); + let mut rng = rand_chacha::ChaCha20Rng::seed_from_u64(9_u64); let leaves_1: Vec = std::iter::repeat_with(|| Fr::random(&mut rng)) .take(LAYER_SIZE) @@ -647,7 +647,7 @@ mod quark_grand_product_tests { fn quark_hybrid_e2e() { const LAYER_SIZE: usize = 1 << 8; - let mut rng = rand_chacha::ChaCha20Rng::seed_from_u64(9 as u64); + let mut rng = rand_chacha::ChaCha20Rng::seed_from_u64(9_u64); let leaves_1: Vec = std::iter::repeat_with(|| Fr::random(&mut rng)) .take(LAYER_SIZE) From fbeba2e6f7742aefb77e85eb5502e2629b90015e Mon Sep 17 00:00:00 2001 From: sragss Date: Wed, 26 Jun 2024 11:50:04 -0700 Subject: [PATCH 18/43] more clippy --- jolt-core/src/lib.rs | 3 ++- jolt-core/src/r1cs/special_polys.rs | 14 ++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/jolt-core/src/lib.rs b/jolt-core/src/lib.rs index e2dc21197..965f9f090 100644 --- a/jolt-core/src/lib.rs +++ b/jolt-core/src/lib.rs @@ -8,7 +8,8 @@ #![feature(generic_const_exprs)] #![feature(iter_next_chunk)] #![allow(long_running_const_eval)] -#[allow(clippy::len_without_is_empty)] +#![allow(clippy::len_without_is_empty)] + #[cfg(feature = "host")] pub mod benches; diff --git a/jolt-core/src/r1cs/special_polys.rs b/jolt-core/src/r1cs/special_polys.rs index 47f291ce9..a42b01dab 100644 --- a/jolt-core/src/r1cs/special_polys.rs +++ b/jolt-core/src/r1cs/special_polys.rs @@ -705,12 +705,14 @@ mod tests { } } - let mut a_poly = SparsePolynomial::new(num_vars, a); - + let a_poly = SparsePolynomial::new(num_vars, a); let r = Fr::from(100); - assert_eq!( - a_poly.clone().bound_poly_var_bot(&r), - a_poly.bound_poly_var_bot_par(&r) - ); + + let mut regular = a_poly.clone(); + regular.bound_poly_var_bot(&r); + + let mut par = a_poly.clone(); + par.bound_poly_var_bot(&r); + assert_eq!(regular, par); } } From 4f0293c44e56a2748ea9210f25c8039a9ebd2ec2 Mon Sep 17 00:00:00 2001 From: sragss Date: Wed, 26 Jun 2024 12:09:46 -0700 Subject: [PATCH 19/43] rm eval_hint --- jolt-core/src/r1cs/builder.rs | 47 +++++------------------------------ 1 file changed, 6 insertions(+), 41 deletions(-) diff --git a/jolt-core/src/r1cs/builder.rs b/jolt-core/src/r1cs/builder.rs index f0297fbe9..e69cdecc8 100644 --- a/jolt-core/src/r1cs/builder.rs +++ b/jolt-core/src/r1cs/builder.rs @@ -27,21 +27,12 @@ pub trait R1CSConstraintBuilder { fn build_constraints(&self, builder: &mut R1CSBuilder); } -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum EvalHint { - Zero = 0, - Other = 1, -} - /// Constraints over a single row. Each variable points to a single item in Z and the corresponding coefficient. #[derive(Clone, Debug)] struct Constraint { a: LC, b: LC, c: LC, - - /// Shortcut for evaluation of a, b, c for an honest prover - eval_hint: (EvalHint, EvalHint, EvalHint), } impl Constraint { @@ -239,7 +230,6 @@ impl R1CSBuilder { a, b, c: LC::zero(), - eval_hint: (EvalHint::Zero, EvalHint::Other, EvalHint::Zero), }; self.constraints.push(constraint); } @@ -258,12 +248,7 @@ impl R1CSBuilder { let a = condition; let b = left - right; let c = LC::zero(); - let constraint = Constraint { - a, - b, - c, - eval_hint: (EvalHint::Other, EvalHint::Other, EvalHint::Zero), - }; // TODO(sragss): Can do better on middle term. + let constraint = Constraint { a, b, c }; // TODO(sragss): Can do better on middle term. self.constraints.push(constraint); } @@ -276,7 +261,6 @@ impl R1CSBuilder { a, b, c: LC::zero(), - eval_hint: (EvalHint::Other, EvalHint::Other, EvalHint::Zero), }; self.constraints.push(constraint); } @@ -300,7 +284,6 @@ impl R1CSBuilder { a: condition.clone(), b: (result_true - result_false.clone()), c: (alleged_result - result_false), - eval_hint: (EvalHint::Other, EvalHint::Other, EvalHint::Other), // TODO(sragss): Is this the best we can do? }; self.constraints.push(constraint); } @@ -446,7 +429,6 @@ impl R1CSBuilder { a: x.into(), b: y.into(), c: z.into(), - eval_hint: (EvalHint::Other, EvalHint::Other, EvalHint::Other), }; self.constraints.push(constraint); } @@ -805,8 +787,8 @@ impl CombinedUniformBuilder { .map(|(constraint_index, constraint)| { let mut dense_output_buffer = unsafe_allocate_zero_vec(self.uniform_repeat); - let mut evaluate_lc_chunk = |hint, lc: &LC| { - if hint != EvalHint::Zero { + let mut evaluate_lc_chunk = |lc: &LC| { + if lc.terms().len() != 0 { let inputs = batch_inputs(lc); lc.evaluate_batch_mut(&inputs, &mut dense_output_buffer); @@ -827,12 +809,9 @@ impl CombinedUniformBuilder { } }; - let a_chunk: Vec<(F, usize)> = - evaluate_lc_chunk(constraint.eval_hint.0, &constraint.a); - let b_chunk: Vec<(F, usize)> = - evaluate_lc_chunk(constraint.eval_hint.1, &constraint.b); - let c_chunk: Vec<(F, usize)> = - evaluate_lc_chunk(constraint.eval_hint.2, &constraint.c); + let a_chunk: Vec<(F, usize)> = evaluate_lc_chunk(&constraint.a); + let b_chunk: Vec<(F, usize)> = evaluate_lc_chunk(&constraint.b); + let c_chunk: Vec<(F, usize)> = evaluate_lc_chunk(&constraint.c); (a_chunk, b_chunk, c_chunk) }) @@ -937,20 +916,6 @@ impl CombinedUniformBuilder { self.uniform_builder.constraints[uniform_constraint_index] ); } - // Verify hints - if constraint_index < self.uniform_repeat_constraint_rows() { - let (hint_a, hint_b, hint_c) = - self.uniform_builder.constraints[uniform_constraint_index].eval_hint; - if hint_a == EvalHint::Zero { - assert_eq!(az[constraint_index], F::zero(), "Mismatch at global constraint {constraint_index} uniform constraint: {uniform_constraint_index}"); - } - if hint_b == EvalHint::Zero { - assert_eq!(bz[constraint_index], F::zero(), "Mismatch at global constraint {constraint_index} uniform constraint: {uniform_constraint_index}"); - } - if hint_c == EvalHint::Zero { - assert_eq!(cz[constraint_index], F::zero(), "Mismatch at global constraint {constraint_index} uniform constraint: {uniform_constraint_index}"); - } - } } } } From 55592e1eca74ef1ed06a5b40e7f867576ba9c4b2 Mon Sep 17 00:00:00 2001 From: sragss Date: Wed, 26 Jun 2024 12:15:12 -0700 Subject: [PATCH 20/43] clippy fix --- jolt-core/src/r1cs/builder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jolt-core/src/r1cs/builder.rs b/jolt-core/src/r1cs/builder.rs index e69cdecc8..440e7ab66 100644 --- a/jolt-core/src/r1cs/builder.rs +++ b/jolt-core/src/r1cs/builder.rs @@ -788,7 +788,7 @@ impl CombinedUniformBuilder { let mut dense_output_buffer = unsafe_allocate_zero_vec(self.uniform_repeat); let mut evaluate_lc_chunk = |lc: &LC| { - if lc.terms().len() != 0 { + if !lc.terms().is_empty() { let inputs = batch_inputs(lc); lc.evaluate_batch_mut(&inputs, &mut dense_output_buffer); From c4af5f253e0d3464a12e657985b1424173c0fd8b Mon Sep 17 00:00:00 2001 From: Michael Zhu Date: Thu, 27 Jun 2024 15:29:48 -0400 Subject: [PATCH 21/43] Handle division by zero --- common/src/rv_trace.rs | 19 +-- jolt-core/src/jolt/instruction/div.rs | 29 ++++- jolt-core/src/jolt/instruction/divu.rs | 50 ++++++-- jolt-core/src/jolt/instruction/mod.rs | 6 +- jolt-core/src/jolt/instruction/mulh.rs | 4 +- jolt-core/src/jolt/instruction/mulhsu.rs | 4 +- jolt-core/src/jolt/instruction/rem.rs | 6 +- jolt-core/src/jolt/instruction/remu.rs | 25 ++-- .../instruction/virtual_assert_valid_div0.rs | 117 ++++++++++++++++++ ... virtual_assert_valid_signed_remainder.rs} | 48 ++++--- ...virtual_assert_valid_unsigned_remainder.rs | 115 +++++++++++++++++ .../{movsign.rs => virtual_movsign.rs} | 4 +- jolt-core/src/jolt/subtable/mod.rs | 2 + jolt-core/src/jolt/subtable/right_is_ones.rs | 71 +++++++++++ jolt-core/src/jolt/subtable/right_is_zero.rs | 71 +++++++++++ jolt-core/src/jolt/trace/rv.rs | 16 ++- jolt-core/src/jolt/vm/rv32i_vm.rs | 26 ++-- 17 files changed, 532 insertions(+), 81 deletions(-) create mode 100644 jolt-core/src/jolt/instruction/virtual_assert_valid_div0.rs rename jolt-core/src/jolt/instruction/{virtual_assert_valid_remainder.rs => virtual_assert_valid_signed_remainder.rs} (73%) create mode 100644 jolt-core/src/jolt/instruction/virtual_assert_valid_unsigned_remainder.rs rename jolt-core/src/jolt/instruction/{movsign.rs => virtual_movsign.rs} (97%) create mode 100644 jolt-core/src/jolt/subtable/right_is_ones.rs create mode 100644 jolt-core/src/jolt/subtable/right_is_zero.rs diff --git a/common/src/rv_trace.rs b/common/src/rv_trace.rs index 4da128767..0120d2cbd 100644 --- a/common/src/rv_trace.rs +++ b/common/src/rv_trace.rs @@ -348,10 +348,11 @@ impl ELFInstruction { None => false }; flags[10] = matches!(self.opcode, - RV32IM::VIRTUAL_ASSERT_EQ | - RV32IM::VIRTUAL_ASSERT_LTE | - RV32IM::VIRTUAL_ASSERT_LTU | - RV32IM::VIRTUAL_ASSERT_VALID_REMAINDER, + RV32IM::VIRTUAL_ASSERT_EQ | + RV32IM::VIRTUAL_ASSERT_LTE | + RV32IM::VIRTUAL_ASSERT_VALID_SIGNED_REMAINDER | + RV32IM::VIRTUAL_ASSERT_VALID_UNSIGNED_REMAINDER | + RV32IM::VIRTUAL_ASSERT_VALID_DIV0, ); flags @@ -444,10 +445,11 @@ pub enum RV32IM { // Virtual instructions VIRTUAL_MOVSIGN, VIRTUAL_ADVICE, - VIRTUAL_ASSERT_LTU, VIRTUAL_ASSERT_LTE, - VIRTUAL_ASSERT_VALID_REMAINDER, + VIRTUAL_ASSERT_VALID_UNSIGNED_REMAINDER, + VIRTUAL_ASSERT_VALID_SIGNED_REMAINDER, VIRTUAL_ASSERT_EQ, + VIRTUAL_ASSERT_VALID_DIV0, } impl FromStr for RV32IM { @@ -575,8 +577,9 @@ impl RV32IM { RV32IM::BGEU | RV32IM::VIRTUAL_ASSERT_EQ | RV32IM::VIRTUAL_ASSERT_LTE | - RV32IM::VIRTUAL_ASSERT_LTU | - RV32IM::VIRTUAL_ASSERT_VALID_REMAINDER => RV32InstructionFormat::SB, + RV32IM::VIRTUAL_ASSERT_VALID_DIV0 | + RV32IM::VIRTUAL_ASSERT_VALID_SIGNED_REMAINDER | + RV32IM::VIRTUAL_ASSERT_VALID_UNSIGNED_REMAINDER => RV32InstructionFormat::SB, RV32IM::LUI | RV32IM::AUIPC | diff --git a/jolt-core/src/jolt/instruction/div.rs b/jolt-core/src/jolt/instruction/div.rs index 7d9985a72..2b18328f1 100644 --- a/jolt-core/src/jolt/instruction/div.rs +++ b/jolt-core/src/jolt/instruction/div.rs @@ -4,8 +4,8 @@ use tracer::{ELFInstruction, RVTraceRow, RegisterState, RV32IM}; use super::VirtualInstructionSequence; use crate::jolt::instruction::{ add::ADDInstruction, beq::BEQInstruction, mul::MULInstruction, - virtual_advice::ADVICEInstruction, - virtual_assert_valid_remainder::ASSERTVALIDREMAINDERInstruction, JoltInstruction, + virtual_advice::ADVICEInstruction, virtual_assert_valid_div0::AssertValidDiv0Instruction, + virtual_assert_valid_signed_remainder::AssertValidSignedRemainderInstruction, JoltInstruction, }; /// Perform signed division and return the result pub struct DIVInstruction; @@ -88,12 +88,12 @@ impl VirtualInstructionSequence for DIVInstruction(r, y).lookup_entry(); + let is_valid: u64 = AssertValidSignedRemainderInstruction::(r, y).lookup_entry(); assert_eq!(is_valid, 1); virtual_sequence.push(RVTraceRow { instruction: ELFInstruction { address: trace_row.instruction.address, - opcode: RV32IM::VIRTUAL_ASSERT_VALID_REMAINDER, + opcode: RV32IM::VIRTUAL_ASSERT_VALID_SIGNED_REMAINDER, rs1: v_r, rs2: r_y, rd: None, @@ -109,6 +109,27 @@ impl VirtualInstructionSequence for DIVInstruction(y, q).lookup_entry(); + assert_eq!(is_valid, 1); + virtual_sequence.push(RVTraceRow { + instruction: ELFInstruction { + address: trace_row.instruction.address, + opcode: RV32IM::VIRTUAL_ASSERT_VALID_DIV0, + rs1: r_y, + rs2: trace_row.instruction.rd, + rd: None, + imm: None, + virtual_sequence_index: Some(virtual_sequence.len()), + }, + register_state: RegisterState { + rs1_val: Some(y), + rs2_val: Some(q), + rd_post_val: None, + }, + memory_state: None, + advice_value: None, + }); + let q_y = MULInstruction::(q, y).lookup_entry(); virtual_sequence.push(RVTraceRow { instruction: ELFInstruction { diff --git a/jolt-core/src/jolt/instruction/divu.rs b/jolt-core/src/jolt/instruction/divu.rs index 963ee57c2..481e27f84 100644 --- a/jolt-core/src/jolt/instruction/divu.rs +++ b/jolt-core/src/jolt/instruction/divu.rs @@ -3,8 +3,11 @@ use tracer::{ELFInstruction, RVTraceRow, RegisterState, RV32IM}; use super::VirtualInstructionSequence; use crate::jolt::instruction::{ - add::ADDInstruction, beq::BEQInstruction, mulu::MULUInstruction, sltu::SLTUInstruction, - virtual_advice::ADVICEInstruction, virtual_assert_lte::ASSERTLTEInstruction, JoltInstruction, + add::ADDInstruction, beq::BEQInstruction, mulu::MULUInstruction, + virtual_advice::ADVICEInstruction, virtual_assert_lte::ASSERTLTEInstruction, + virtual_assert_valid_div0::AssertValidDiv0Instruction, + virtual_assert_valid_unsigned_remainder::AssertValidUnsignedRemainderInstruction, + JoltInstruction, }; /// Perform unsigned division and return quotient pub struct DIVUInstruction; @@ -37,7 +40,7 @@ impl VirtualInstructionSequence for DIVUInstruction VirtualInstructionSequence for DIVUInstruction VirtualInstructionSequence for DIVUInstruction VirtualInstructionSequence for DIVUInstruction VirtualInstructionSequence for DIVUInstruction VirtualInstructionSequence for DIVUInstruction VirtualInstructionSequence for DIVUInstruction(y, q).lookup_entry(); + assert_eq!(is_valid, 1); + virtual_sequence.push(RVTraceRow { + instruction: ELFInstruction { + address: trace_row.instruction.address, + opcode: RV32IM::VIRTUAL_ASSERT_VALID_DIV0, + rs1: r_y, + rs2: trace_row.instruction.rd, + rd: None, + imm: None, + virtual_sequence_index: Some(virtual_sequence.len()), + }, + register_state: RegisterState { + rs1_val: Some(y), + rs2_val: Some(q), + rd_post_val: None, + }, + memory_state: None, + advice_value: None, + }); + let add_0 = ADDInstruction::(q_y, r).lookup_entry(); virtual_sequence.push(RVTraceRow { instruction: ELFInstruction { @@ -137,7 +163,7 @@ impl VirtualInstructionSequence for DIVUInstruction VirtualInstructionSequence for DIVUInstruction; diff --git a/jolt-core/src/jolt/instruction/mulhsu.rs b/jolt-core/src/jolt/instruction/mulhsu.rs index c3bf6631d..9a69250e2 100644 --- a/jolt-core/src/jolt/instruction/mulhsu.rs +++ b/jolt-core/src/jolt/instruction/mulhsu.rs @@ -3,8 +3,8 @@ use tracer::{ELFInstruction, RVTraceRow, RegisterState, RV32IM}; use super::VirtualInstructionSequence; use crate::jolt::instruction::{ - add::ADDInstruction, movsign::MOVSIGNInstruction, mulhu::MULHUInstruction, - mulu::MULUInstruction, JoltInstruction, + add::ADDInstruction, mulhu::MULHUInstruction, mulu::MULUInstruction, + virtual_movsign::MOVSIGNInstruction, JoltInstruction, }; /// Perform signed*unsigned multiplication and return the upper WORD_SIZE bits diff --git a/jolt-core/src/jolt/instruction/rem.rs b/jolt-core/src/jolt/instruction/rem.rs index 09d79e21d..5d5687d66 100644 --- a/jolt-core/src/jolt/instruction/rem.rs +++ b/jolt-core/src/jolt/instruction/rem.rs @@ -5,7 +5,7 @@ use super::VirtualInstructionSequence; use crate::jolt::instruction::{ add::ADDInstruction, beq::BEQInstruction, mul::MULInstruction, virtual_advice::ADVICEInstruction, - virtual_assert_valid_remainder::ASSERTVALIDREMAINDERInstruction, JoltInstruction, + virtual_assert_valid_signed_remainder::AssertValidSignedRemainderInstruction, JoltInstruction, }; /// Perform signed division and return the remainder @@ -89,12 +89,12 @@ impl VirtualInstructionSequence for REMInstruction(r, y).lookup_entry(); + let is_valid: u64 = AssertValidSignedRemainderInstruction::(r, y).lookup_entry(); assert_eq!(is_valid, 1); virtual_sequence.push(RVTraceRow { instruction: ELFInstruction { address: trace_row.instruction.address, - opcode: RV32IM::VIRTUAL_ASSERT_VALID_REMAINDER, + opcode: RV32IM::VIRTUAL_ASSERT_VALID_SIGNED_REMAINDER, rs1: trace_row.instruction.rd, rs2: r_y, rd: None, diff --git a/jolt-core/src/jolt/instruction/remu.rs b/jolt-core/src/jolt/instruction/remu.rs index 48d85e0e7..e12171f5d 100644 --- a/jolt-core/src/jolt/instruction/remu.rs +++ b/jolt-core/src/jolt/instruction/remu.rs @@ -3,8 +3,10 @@ use tracer::{ELFInstruction, RVTraceRow, RegisterState, RV32IM}; use super::VirtualInstructionSequence; use crate::jolt::instruction::{ - add::ADDInstruction, beq::BEQInstruction, mulu::MULUInstruction, sltu::SLTUInstruction, - virtual_advice::ADVICEInstruction, virtual_assert_lte::ASSERTLTEInstruction, JoltInstruction, + add::ADDInstruction, beq::BEQInstruction, mulu::MULUInstruction, + virtual_advice::ADVICEInstruction, virtual_assert_lte::ASSERTLTEInstruction, + virtual_assert_valid_unsigned_remainder::AssertValidUnsignedRemainderInstruction, + JoltInstruction, }; /// Perform unsigned divison and return remainder @@ -38,7 +40,7 @@ impl VirtualInstructionSequence for REMUInstruction VirtualInstructionSequence for REMUInstruction VirtualInstructionSequence for REMUInstruction VirtualInstructionSequence for REMUInstruction VirtualInstructionSequence for REMUInstruction VirtualInstructionSequence for REMUInstruction VirtualInstructionSequence for REMUInstruction(pub u64, pub u64); + +impl JoltInstruction for AssertValidDiv0Instruction { + fn operands(&self) -> (u64, u64) { + (self.0, self.1) + } + + fn combine_lookups(&self, vals: &[F], C: usize, M: usize) -> F { + let vals_by_subtable = self.slice_values(vals, C, M); + let divisor_is_zero: F = vals_by_subtable[0].iter().product(); + let quotient_is_ones: F = vals_by_subtable[1].iter().product(); + + F::one() - divisor_is_zero + divisor_is_zero * quotient_is_ones + } + + fn g_poly_degree(&self, C: usize) -> usize { + C + } + + fn subtables( + &self, + C: usize, + _: usize, + ) -> Vec<(Box>, SubtableIndices)> { + vec![ + ( + Box::new(LeftIsZeroSubtable::new()), + SubtableIndices::from(0..C), + ), + ( + Box::new(RightIsOnesSubtable::new()), + SubtableIndices::from(0..C), + ), + ] + } + + fn to_indices(&self, C: usize, log_M: usize) -> Vec { + chunk_and_concatenate_operands(self.0, self.1, C, log_M) + } + + fn lookup_entry(&self) -> u64 { + let divisor = self.0; + let quotient = self.1; + if divisor == 0 { + match WORD_SIZE { + 32 => (quotient == u32::MAX as u64).into(), + 64 => (quotient == u64::MAX).into(), + _ => panic!("Unsupported WORD_SIZE: {}", WORD_SIZE), + } + } else { + 1 + } + } + + fn random(&self, rng: &mut StdRng) -> Self { + Self(rng.next_u32() as u64, rng.next_u32() as u64) + } +} + +#[cfg(test)] +mod test { + use ark_bn254::Fr; + use ark_std::test_rng; + use rand_chacha::rand_core::RngCore; + + use crate::{jolt::instruction::JoltInstruction, jolt_instruction_test}; + + use super::AssertValidDiv0Instruction; + + #[test] + fn assert_valid_div0_instruction_32_e2e() { + let mut rng = test_rng(); + const C: usize = 4; + const M: usize = 1 << 16; + + for _ in 0..256 { + let (x, y) = (rng.next_u32() as u64, rng.next_u32() as u64); + let instruction = AssertValidDiv0Instruction::<32>(x, y); + jolt_instruction_test!(instruction); + } + for _ in 0..256 { + let x = rng.next_u32() as u64; + jolt_instruction_test!(AssertValidDiv0Instruction::<32>(x, x)); + } + + let u32_max: u64 = u32::MAX as u64; + let instructions = vec![ + AssertValidDiv0Instruction::<32>(100, 0), + AssertValidDiv0Instruction(0, 100), + AssertValidDiv0Instruction(1, 0), + AssertValidDiv0Instruction(0, u32_max), + AssertValidDiv0Instruction(u32_max, 0), + AssertValidDiv0Instruction(u32_max, u32_max), + AssertValidDiv0Instruction(u32_max, 1 << 8), + AssertValidDiv0Instruction(1 << 8, u32_max), + ]; + for instruction in instructions { + jolt_instruction_test!(instruction); + } + } +} diff --git a/jolt-core/src/jolt/instruction/virtual_assert_valid_remainder.rs b/jolt-core/src/jolt/instruction/virtual_assert_valid_signed_remainder.rs similarity index 73% rename from jolt-core/src/jolt/instruction/virtual_assert_valid_remainder.rs rename to jolt-core/src/jolt/instruction/virtual_assert_valid_signed_remainder.rs index 5fd1ea11a..66384bbdc 100644 --- a/jolt-core/src/jolt/instruction/virtual_assert_valid_remainder.rs +++ b/jolt-core/src/jolt/instruction/virtual_assert_valid_signed_remainder.rs @@ -1,4 +1,4 @@ -use crate::field::JoltField; +use crate::{field::JoltField, jolt::subtable::right_is_zero::RightIsZeroSubtable}; use rand::prelude::StdRng; use rand::RngCore; use serde::{Deserialize, Serialize}; @@ -15,9 +15,9 @@ use crate::{ #[derive(Copy, Clone, Default, Debug, Serialize, Deserialize)] /// (remainder, divisor) -pub struct ASSERTVALIDREMAINDERInstruction(pub u64, pub u64); +pub struct AssertValidSignedRemainderInstruction(pub u64, pub u64); -impl JoltInstruction for ASSERTVALIDREMAINDERInstruction { +impl JoltInstruction for AssertValidSignedRemainderInstruction { fn operands(&self) -> (u64, u64) { (self.0, self.1) } @@ -32,6 +32,7 @@ impl JoltInstruction for ASSERTVALIDREMAINDERInstruction let eq_abs = vals_by_subtable[4]; let lt_abs = vals_by_subtable[5]; let remainder_is_zero: F = vals_by_subtable[6].iter().product(); + let divisor_is_zero: F = vals_by_subtable[7].iter().product(); // Accumulator for LTU(x_{ JoltInstruction for ASSERTVALIDREMAINDERInstruction eq_prod *= *eq_i; } - // (1 - x_s - y_s) * LTU(x_{ usize { @@ -69,6 +71,10 @@ impl JoltInstruction for ASSERTVALIDREMAINDERInstruction Box::new(LeftIsZeroSubtable::new()), SubtableIndices::from(0..C), ), + ( + Box::new(RightIsZeroSubtable::new()), + SubtableIndices::from(0..C), + ), ] } @@ -82,8 +88,9 @@ impl JoltInstruction for ASSERTVALIDREMAINDERInstruction let remainder = self.0 as u32 as i32; let divisor = self.1 as u32 as i32; let is_remainder_zero = remainder == 0; + let is_divisor_zero = divisor == 0; - if is_remainder_zero { + if is_remainder_zero || is_divisor_zero { 1 } else { let remainder_sign = remainder >> 31; @@ -95,8 +102,9 @@ impl JoltInstruction for ASSERTVALIDREMAINDERInstruction let remainder = self.0 as i64; let divisor = self.1 as i64; let is_remainder_zero = remainder == 0; + let is_divisor_zero = divisor == 0; - if is_remainder_zero { + if is_remainder_zero || is_divisor_zero { 1 } else { let remainder_sign = remainder >> 63; @@ -121,10 +129,10 @@ mod test { use crate::{jolt::instruction::JoltInstruction, jolt_instruction_test}; - use super::ASSERTVALIDREMAINDERInstruction; + use super::AssertValidSignedRemainderInstruction; #[test] - fn assert_valid_remainder_instruction_32_e2e() { + fn assert_valid_signed_remainder_instruction_32_e2e() { let mut rng = test_rng(); const C: usize = 4; const M: usize = 1 << 16; @@ -132,19 +140,19 @@ mod test { for _ in 0..256 { let x = rng.next_u32() as u64; let y = rng.next_u32() as u64; - let instruction = ASSERTVALIDREMAINDERInstruction::<32>(x, y); + let instruction = AssertValidSignedRemainderInstruction::<32>(x, y); jolt_instruction_test!(instruction); } let u32_max: u64 = u32::MAX as u64; let instructions = vec![ - ASSERTVALIDREMAINDERInstruction::<32>(100, 0), - ASSERTVALIDREMAINDERInstruction::<32>(0, 100), - ASSERTVALIDREMAINDERInstruction::<32>(1, 0), - ASSERTVALIDREMAINDERInstruction::<32>(0, u32_max), - ASSERTVALIDREMAINDERInstruction::<32>(u32_max, 0), - ASSERTVALIDREMAINDERInstruction::<32>(u32_max, u32_max), - ASSERTVALIDREMAINDERInstruction::<32>(u32_max, 1 << 8), - ASSERTVALIDREMAINDERInstruction::<32>(1 << 8, u32_max), + AssertValidSignedRemainderInstruction::<32>(100, 0), + AssertValidSignedRemainderInstruction::<32>(0, 100), + AssertValidSignedRemainderInstruction::<32>(1, 0), + AssertValidSignedRemainderInstruction::<32>(0, u32_max), + AssertValidSignedRemainderInstruction::<32>(u32_max, 0), + AssertValidSignedRemainderInstruction::<32>(u32_max, u32_max), + AssertValidSignedRemainderInstruction::<32>(u32_max, 1 << 8), + AssertValidSignedRemainderInstruction::<32>(1 << 8, u32_max), ]; for instruction in instructions { jolt_instruction_test!(instruction); @@ -152,19 +160,19 @@ mod test { } #[test] - fn assert_valid_remainder_instruction_64_e2e() { + fn assert_valid_signed_remainder_instruction_64_e2e() { let mut rng = test_rng(); const C: usize = 8; const M: usize = 1 << 16; for _ in 0..256 { let (x, y) = (rng.next_u64(), rng.next_u64()); - let instruction = ASSERTVALIDREMAINDERInstruction::<64>(x, y); + let instruction = AssertValidSignedRemainderInstruction::<64>(x, y); jolt_instruction_test!(instruction); } for _ in 0..256 { let x = rng.next_u64(); - let instruction = ASSERTVALIDREMAINDERInstruction::<64>(x, x); + let instruction = AssertValidSignedRemainderInstruction::<64>(x, x); jolt_instruction_test!(instruction); } } diff --git a/jolt-core/src/jolt/instruction/virtual_assert_valid_unsigned_remainder.rs b/jolt-core/src/jolt/instruction/virtual_assert_valid_unsigned_remainder.rs new file mode 100644 index 000000000..647ad84c8 --- /dev/null +++ b/jolt-core/src/jolt/instruction/virtual_assert_valid_unsigned_remainder.rs @@ -0,0 +1,115 @@ +use crate::{field::JoltField, jolt::subtable::right_is_zero::RightIsZeroSubtable}; +use rand::prelude::StdRng; +use rand::RngCore; +use serde::{Deserialize, Serialize}; + +use super::JoltInstruction; +use crate::{ + jolt::{ + instruction::SubtableIndices, + subtable::{eq::EqSubtable, ltu::LtuSubtable, LassoSubtable}, + }, + utils::instruction_utils::chunk_and_concatenate_operands, +}; + +#[derive(Copy, Clone, Default, Debug, Serialize, Deserialize)] +pub struct AssertValidUnsignedRemainderInstruction(pub u64, pub u64); + +impl JoltInstruction for AssertValidUnsignedRemainderInstruction { + fn operands(&self) -> (u64, u64) { + (self.0, self.1) + } + + fn combine_lookups(&self, vals: &[F], C: usize, M: usize) -> F { + let vals_by_subtable = self.slice_values(vals, C, M); + let ltu = vals_by_subtable[0]; + let eq = vals_by_subtable[1]; + let divisor_is_zero: F = vals_by_subtable[2].iter().product(); + + let mut sum = F::zero(); + let mut eq_prod = F::one(); + + for i in 0..C { + sum += ltu[i] * eq_prod; + eq_prod *= eq[i]; + } + // LTU(r, y) + EQ(y, 0) + sum + divisor_is_zero + } + + fn g_poly_degree(&self, C: usize) -> usize { + C + } + + fn subtables( + &self, + C: usize, + _: usize, + ) -> Vec<(Box>, SubtableIndices)> { + vec![ + (Box::new(LtuSubtable::new()), SubtableIndices::from(0..C)), + (Box::new(EqSubtable::new()), SubtableIndices::from(0..C)), + ( + Box::new(RightIsZeroSubtable::new()), + SubtableIndices::from(0..C), + ), + ] + } + + fn to_indices(&self, C: usize, log_M: usize) -> Vec { + chunk_and_concatenate_operands(self.0, self.1, C, log_M) + } + + fn lookup_entry(&self) -> u64 { + let remainder = self.0; + let divisor = self.1; + (divisor == 0 || remainder < divisor).into() + } + + fn random(&self, rng: &mut StdRng) -> Self { + Self(rng.next_u32() as u64, rng.next_u32() as u64) + } +} + +#[cfg(test)] +mod test { + use ark_bn254::Fr; + use ark_std::test_rng; + use rand_chacha::rand_core::RngCore; + + use crate::{jolt::instruction::JoltInstruction, jolt_instruction_test}; + + use super::AssertValidUnsignedRemainderInstruction; + + #[test] + fn assert_valid_unsigned_remainder_instruction_32_e2e() { + let mut rng = test_rng(); + const C: usize = 4; + const M: usize = 1 << 16; + + for _ in 0..256 { + let (x, y) = (rng.next_u32() as u64, rng.next_u32() as u64); + let instruction = AssertValidUnsignedRemainderInstruction(x, y); + jolt_instruction_test!(instruction); + } + for _ in 0..256 { + let x = rng.next_u32() as u64; + jolt_instruction_test!(AssertValidUnsignedRemainderInstruction(x, x)); + } + + let u32_max: u64 = u32::MAX as u64; + let instructions = vec![ + AssertValidUnsignedRemainderInstruction(100, 0), + AssertValidUnsignedRemainderInstruction(0, 100), + AssertValidUnsignedRemainderInstruction(1, 0), + AssertValidUnsignedRemainderInstruction(0, u32_max), + AssertValidUnsignedRemainderInstruction(u32_max, 0), + AssertValidUnsignedRemainderInstruction(u32_max, u32_max), + AssertValidUnsignedRemainderInstruction(u32_max, 1 << 8), + AssertValidUnsignedRemainderInstruction(1 << 8, u32_max), + ]; + for instruction in instructions { + jolt_instruction_test!(instruction); + } + } +} diff --git a/jolt-core/src/jolt/instruction/movsign.rs b/jolt-core/src/jolt/instruction/virtual_movsign.rs similarity index 97% rename from jolt-core/src/jolt/instruction/movsign.rs rename to jolt-core/src/jolt/instruction/virtual_movsign.rs index f3429c2fb..45405c05d 100644 --- a/jolt-core/src/jolt/instruction/movsign.rs +++ b/jolt-core/src/jolt/instruction/virtual_movsign.rs @@ -91,7 +91,7 @@ mod test { use super::MOVSIGNInstruction; #[test] - fn movsign_instruction_32_e2e() { + fn virtual_movsign_instruction_32_e2e() { let mut rng = test_rng(); const C: usize = 4; const M: usize = 1 << 16; @@ -105,7 +105,7 @@ mod test { } #[test] - fn movsign_instruction_64_e2e() { + fn virtual_movsign_instruction_64_e2e() { let mut rng = test_rng(); const C: usize = 8; const M: usize = 1 << 16; diff --git a/jolt-core/src/jolt/subtable/mod.rs b/jolt-core/src/jolt/subtable/mod.rs index 0d4aecfe9..d5c43a97e 100644 --- a/jolt-core/src/jolt/subtable/mod.rs +++ b/jolt-core/src/jolt/subtable/mod.rs @@ -38,6 +38,8 @@ pub mod left_msb; pub mod lt_abs; pub mod ltu; pub mod or; +pub mod right_is_ones; +pub mod right_is_zero; pub mod right_msb; pub mod sign_extend; pub mod sll; diff --git a/jolt-core/src/jolt/subtable/right_is_ones.rs b/jolt-core/src/jolt/subtable/right_is_ones.rs new file mode 100644 index 000000000..18607df50 --- /dev/null +++ b/jolt-core/src/jolt/subtable/right_is_ones.rs @@ -0,0 +1,71 @@ +use crate::field::JoltField; +use ark_std::log2; +use std::marker::PhantomData; + +use super::LassoSubtable; + +#[derive(Default)] +pub struct RightIsOnesSubtable { + _field: PhantomData, +} + +impl RightIsOnesSubtable { + pub fn new() -> Self { + Self { + _field: PhantomData, + } + } +} + +impl LassoSubtable for RightIsOnesSubtable { + fn materialize(&self, M: usize) -> Vec { + let mut entries: Vec = vec![F::zero(); M]; + let right_operand_bits = (1 << (log2(M) / 2)) - 1; + + for idx in 0..M { + if (idx & right_operand_bits) == right_operand_bits { + entries[idx] = F::one(); + } + } + + entries + } + + fn evaluate_mle(&self, point: &[F]) -> F { + // \prod_i y_i + debug_assert!(point.len() % 2 == 0); + let b = point.len() / 2; + let (_, y) = point.split_at(b); + + let mut result = F::one(); + for i in 0..b { + result *= y[i]; + } + result + } +} + +#[cfg(test)] +mod test { + use ark_bn254::Fr; + use binius_field::BinaryField128b; + + use crate::{ + field::binius::BiniusField, + jolt::subtable::{right_is_ones::RightIsOnesSubtable, LassoSubtable}, + subtable_materialize_mle_parity_test, + }; + + subtable_materialize_mle_parity_test!( + right_is_ones_materialize_mle_parity, + RightIsOnesSubtable, + Fr, + 256 + ); + subtable_materialize_mle_parity_test!( + right_is_ones_binius_materialize_mle_parity, + RightIsOnesSubtable>, + BiniusField, + 1 << 16 + ); +} diff --git a/jolt-core/src/jolt/subtable/right_is_zero.rs b/jolt-core/src/jolt/subtable/right_is_zero.rs new file mode 100644 index 000000000..9e75192fb --- /dev/null +++ b/jolt-core/src/jolt/subtable/right_is_zero.rs @@ -0,0 +1,71 @@ +use crate::field::JoltField; +use ark_std::log2; +use std::marker::PhantomData; + +use super::LassoSubtable; + +#[derive(Default)] +pub struct RightIsZeroSubtable { + _field: PhantomData, +} + +impl RightIsZeroSubtable { + pub fn new() -> Self { + Self { + _field: PhantomData, + } + } +} + +impl LassoSubtable for RightIsZeroSubtable { + fn materialize(&self, M: usize) -> Vec { + let mut entries: Vec = vec![F::zero(); M]; + let right_operand_bits = (1 << (log2(M) / 2)) - 1; + + for idx in 0..M { + if (idx & right_operand_bits) == 0 { + entries[idx] = F::one(); + } + } + + entries + } + + fn evaluate_mle(&self, point: &[F]) -> F { + // \prod_i (1 - y_i) + debug_assert!(point.len() % 2 == 0); + let b = point.len() / 2; + let (_, y) = point.split_at(b); + + let mut result = F::one(); + for i in 0..b { + result *= F::one() - y[i]; + } + result + } +} + +#[cfg(test)] +mod test { + use ark_bn254::Fr; + use binius_field::BinaryField128b; + + use crate::{ + field::binius::BiniusField, + jolt::subtable::{right_is_zero::RightIsZeroSubtable, LassoSubtable}, + subtable_materialize_mle_parity_test, + }; + + subtable_materialize_mle_parity_test!( + right_is_zero_materialize_mle_parity, + RightIsZeroSubtable, + Fr, + 256 + ); + subtable_materialize_mle_parity_test!( + right_is_zero_binius_materialize_mle_parity, + RightIsZeroSubtable>, + BiniusField, + 1 << 16 + ); +} diff --git a/jolt-core/src/jolt/trace/rv.rs b/jolt-core/src/jolt/trace/rv.rs index aeeb06e5d..90ee82166 100644 --- a/jolt-core/src/jolt/trace/rv.rs +++ b/jolt-core/src/jolt/trace/rv.rs @@ -20,9 +20,11 @@ use crate::jolt::instruction::sub::SUBInstruction; use crate::jolt::instruction::sw::SWInstruction; use crate::jolt::instruction::virtual_advice::ADVICEInstruction; use crate::jolt::instruction::virtual_assert_lte::ASSERTLTEInstruction; -use crate::jolt::instruction::virtual_assert_valid_remainder::ASSERTVALIDREMAINDERInstruction; +use crate::jolt::instruction::virtual_assert_valid_div0::AssertValidDiv0Instruction; +use crate::jolt::instruction::virtual_assert_valid_signed_remainder::AssertValidSignedRemainderInstruction; +use crate::jolt::instruction::virtual_assert_valid_unsigned_remainder::AssertValidUnsignedRemainderInstruction; use crate::jolt::instruction::xor::XORInstruction; -use crate::jolt::instruction::{add::ADDInstruction, movsign::MOVSIGNInstruction}; +use crate::jolt::instruction::{add::ADDInstruction, virtual_movsign::MOVSIGNInstruction}; use crate::jolt::vm::rv32i_vm::RV32I; use common::rv_trace::{ELFInstruction, MemoryState, RVTraceRow, RV32IM}; @@ -82,8 +84,9 @@ impl TryFrom<&ELFInstruction> for RV32I { RV32IM::VIRTUAL_MOVSIGN => Ok(MOVSIGNInstruction::default().into()), RV32IM::VIRTUAL_ASSERT_EQ => Ok(BEQInstruction::default().into()), RV32IM::VIRTUAL_ASSERT_LTE => Ok(ASSERTLTEInstruction::default().into()), - RV32IM::VIRTUAL_ASSERT_LTU => Ok(SLTUInstruction::default().into()), - RV32IM::VIRTUAL_ASSERT_VALID_REMAINDER => Ok(ASSERTVALIDREMAINDERInstruction::default().into()), + RV32IM::VIRTUAL_ASSERT_VALID_UNSIGNED_REMAINDER => Ok(AssertValidUnsignedRemainderInstruction::default().into()), + RV32IM::VIRTUAL_ASSERT_VALID_SIGNED_REMAINDER => Ok(AssertValidSignedRemainderInstruction::default().into()), + RV32IM::VIRTUAL_ASSERT_VALID_DIV0 => Ok(AssertValidDiv0Instruction::default().into()), _ => Err("No corresponding RV32I instruction") } @@ -146,8 +149,9 @@ impl TryFrom<&RVTraceRow> for RV32I { RV32IM::VIRTUAL_MOVSIGN => Ok(MOVSIGNInstruction(row.register_state.rs1_val.unwrap()).into()), RV32IM::VIRTUAL_ASSERT_EQ => Ok(BEQInstruction(row.register_state.rs1_val.unwrap(), row.register_state.rs2_val.unwrap()).into()), RV32IM::VIRTUAL_ASSERT_LTE => Ok(ASSERTLTEInstruction(row.register_state.rs1_val.unwrap(), row.register_state.rs2_val.unwrap()).into()), - RV32IM::VIRTUAL_ASSERT_LTU => Ok(SLTUInstruction(row.register_state.rs1_val.unwrap(), row.register_state.rs2_val.unwrap()).into()), - RV32IM::VIRTUAL_ASSERT_VALID_REMAINDER => Ok(ASSERTVALIDREMAINDERInstruction(row.register_state.rs1_val.unwrap(), row.register_state.rs2_val.unwrap()).into()), + RV32IM::VIRTUAL_ASSERT_VALID_UNSIGNED_REMAINDER => Ok(AssertValidUnsignedRemainderInstruction(row.register_state.rs1_val.unwrap(), row.register_state.rs2_val.unwrap()).into()), + RV32IM::VIRTUAL_ASSERT_VALID_SIGNED_REMAINDER => Ok(AssertValidSignedRemainderInstruction(row.register_state.rs1_val.unwrap(), row.register_state.rs2_val.unwrap()).into()), + RV32IM::VIRTUAL_ASSERT_VALID_DIV0 => Ok(AssertValidDiv0Instruction(row.register_state.rs1_val.unwrap(), row.register_state.rs2_val.unwrap()).into()), _ => Err("No corresponding RV32I instruction") } diff --git a/jolt-core/src/jolt/vm/rv32i_vm.rs b/jolt-core/src/jolt/vm/rv32i_vm.rs index f4ebddf48..a93ccccd6 100644 --- a/jolt-core/src/jolt/vm/rv32i_vm.rs +++ b/jolt-core/src/jolt/vm/rv32i_vm.rs @@ -1,4 +1,8 @@ use crate::field::JoltField; +use crate::jolt::instruction::virtual_assert_valid_div0::AssertValidDiv0Instruction; +use crate::jolt::instruction::virtual_assert_valid_unsigned_remainder::AssertValidUnsignedRemainderInstruction; +use crate::jolt::subtable::right_is_ones::RightIsOnesSubtable; +use crate::jolt::subtable::right_is_zero::RightIsZeroSubtable; use enum_dispatch::enum_dispatch; use rand::{prelude::StdRng, RngCore}; use serde::{Deserialize, Serialize}; @@ -10,13 +14,13 @@ use super::{Jolt, JoltProof}; use crate::jolt::instruction::{ add::ADDInstruction, and::ANDInstruction, beq::BEQInstruction, bge::BGEInstruction, bgeu::BGEUInstruction, bne::BNEInstruction, lb::LBInstruction, lh::LHInstruction, - movsign::MOVSIGNInstruction, mul::MULInstruction, mulhu::MULHUInstruction, - mulu::MULUInstruction, or::ORInstruction, sb::SBInstruction, sh::SHInstruction, - sll::SLLInstruction, slt::SLTInstruction, sltu::SLTUInstruction, sra::SRAInstruction, - srl::SRLInstruction, sub::SUBInstruction, sw::SWInstruction, virtual_advice::ADVICEInstruction, - virtual_assert_lte::ASSERTLTEInstruction, - virtual_assert_valid_remainder::ASSERTVALIDREMAINDERInstruction, xor::XORInstruction, - JoltInstruction, JoltInstructionSet, SubtableIndices, + mul::MULInstruction, mulhu::MULHUInstruction, mulu::MULUInstruction, or::ORInstruction, + sb::SBInstruction, sh::SHInstruction, sll::SLLInstruction, slt::SLTInstruction, + sltu::SLTUInstruction, sra::SRAInstruction, srl::SRLInstruction, sub::SUBInstruction, + sw::SWInstruction, virtual_advice::ADVICEInstruction, virtual_assert_lte::ASSERTLTEInstruction, + virtual_assert_valid_signed_remainder::AssertValidSignedRemainderInstruction, + virtual_movsign::MOVSIGNInstruction, xor::XORInstruction, JoltInstruction, JoltInstructionSet, + SubtableIndices, }; use crate::jolt::subtable::{ and::AndSubtable, eq::EqSubtable, eq_abs::EqAbsSubtable, identity::IdentitySubtable, @@ -111,7 +115,9 @@ instruction_set!( MULHU: MULHUInstruction, VIRTUAL_ADVICE: ADVICEInstruction, VIRTUAL_ASSERT_LTE: ASSERTLTEInstruction, - VIRTUAL_ASSERT_VALID_REMAINDER: ASSERTVALIDREMAINDERInstruction + VIRTUAL_ASSERT_VALID_SIGNED_REMAINDER: AssertValidSignedRemainderInstruction, + VIRTUAL_ASSERT_VALID_UNSIGNED_REMAINDER: AssertValidUnsignedRemainderInstruction, + VIRTUAL_ASSERT_VALID_DIV0: AssertValidDiv0Instruction ); subtable_enum!( RV32ISubtables, @@ -138,7 +144,9 @@ subtable_enum!( TRUNCATE: TruncateOverflowSubtable, TRUNCATE_BYTE: TruncateOverflowSubtable, XOR: XorSubtable, - LEFT_IS_ZERO: LeftIsZeroSubtable + LEFT_IS_ZERO: LeftIsZeroSubtable, + RIGHT_IS_ZERO: RightIsZeroSubtable, + RIGHT_IS_ONES: RightIsOnesSubtable ); // ==================== JOLT ==================== From bf365766cd5a154c3a7c956a8df2a5867f07b3a5 Mon Sep 17 00:00:00 2001 From: Michael Zhu Date: Thu, 27 Jun 2024 15:35:55 -0400 Subject: [PATCH 22/43] Fix constraints --- jolt-core/src/r1cs/jolt_constraints.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/jolt-core/src/r1cs/jolt_constraints.rs b/jolt-core/src/r1cs/jolt_constraints.rs index 0edae7ddb..f05ac7edc 100644 --- a/jolt-core/src/r1cs/jolt_constraints.rs +++ b/jolt-core/src/r1cs/jolt_constraints.rs @@ -125,7 +125,9 @@ pub enum JoltIn { IF_MulHu, IF_Virt_Adv, IF_Virt_Assert_LTE, - IF_Virt_Assert_VALID_REMAINDER, + IF_Virt_Assert_VALID_SIGNED_REMAINDER, + IF_Virt_Assert_VALID_UNSIGNED_REMAINDER, + IF_Virt_Assert_VALID_DIV0, } impl_r1cs_input_lc_conversions!(JoltIn); impl ConstraintInput for JoltIn {} @@ -149,10 +151,7 @@ impl UniformJoltConstraints { impl R1CSConstraintBuilder for UniformJoltConstraints { type Inputs = JoltIn; fn build_constraints(&self, cs: &mut R1CSBuilder) { - let flags = input_range!( - JoltIn::OpFlags_IsRs1Rs2, - JoltIn::IF_Virt_Assert_VALID_REMAINDER - ); + let flags = input_range!(JoltIn::OpFlags_IsRs1Rs2, JoltIn::IF_Virt_Assert_VALID_DIV0); for flag in flags { cs.constrain_binary(flag); } @@ -296,7 +295,7 @@ mod tests { #[test] fn instruction_flags_length() { assert_eq!( - input_range!(JoltIn::IF_Add, JoltIn::IF_Virt_Assert_VALID_REMAINDER).len(), + input_range!(JoltIn::IF_Add, JoltIn::IF_Virt_Assert_VALID_DIV0).len(), RV32I::COUNT ); } From 9b0cd80da6b06f10c4ba29c7e79e7effea61731e Mon Sep 17 00:00:00 2001 From: PatStiles Date: Wed, 12 Jun 2024 12:50:18 -0700 Subject: [PATCH 23/43] odify tracer functions + move Proof to rv32ivm --- jolt-core/src/host/mod.rs | 7 ++++-- jolt-core/src/jolt/vm/rv32i_vm.rs | 40 +++++++++++++++++++++++++++++- jolt-sdk/macros/src/lib.rs | 16 ++++++------ jolt-sdk/src/host_utils.rs | 40 ++---------------------------- jolt-sdk/src/lib.rs | 2 +- jolt.proof | Bin 0 -> 523160 bytes tracer/src/lib.rs | 6 +++-- 7 files changed, 59 insertions(+), 52 deletions(-) create mode 100644 jolt.proof diff --git a/jolt-core/src/host/mod.rs b/jolt-core/src/host/mod.rs index 6bcd8a1e6..860da86a2 100644 --- a/jolt-core/src/host/mod.rs +++ b/jolt-core/src/host/mod.rs @@ -3,7 +3,7 @@ use core::str::FromStr; use std::{ fs::{self, File}, - io::{self, Write}, + io::{self, Write, Read}, path::PathBuf, process::Command, }; @@ -157,7 +157,10 @@ impl Program { pub fn decode(&mut self) -> (Vec, Vec<(u64, u8)>) { self.build(); let elf = self.elf.as_ref().unwrap(); - tracer::decode(elf) + let mut elf_file = File::open(elf).unwrap(); + let mut elf_contents = Vec::new(); + elf_file.read_to_end(&mut elf_contents).unwrap(); + tracer::decode(&elf_contents) } // TODO(moodlezoup): Make this generic over InstructionSet diff --git a/jolt-core/src/jolt/vm/rv32i_vm.rs b/jolt-core/src/jolt/vm/rv32i_vm.rs index 98a1e5816..5bc79ffbc 100644 --- a/jolt-core/src/jolt/vm/rv32i_vm.rs +++ b/jolt-core/src/jolt/vm/rv32i_vm.rs @@ -1,4 +1,7 @@ use crate::field::JoltField; +use crate::poly::commitment::hyrax::HyraxScheme; +use ark_bn254::{Fr, G1Projective}; +use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use enum_dispatch::enum_dispatch; use rand::{prelude::StdRng, RngCore}; use serde::{Deserialize, Serialize}; @@ -6,7 +9,7 @@ use std::any::TypeId; use strum::{EnumCount, IntoEnumIterator}; use strum_macros::{EnumCount as EnumCountMacro, EnumIter}; -use super::{Jolt, JoltProof}; +use super::{Jolt, JoltCommitments, JoltProof}; use crate::jolt::instruction::{ add::ADDInstruction, and::ANDInstruction, beq::BEQInstruction, bge::BGEInstruction, bgeu::BGEUInstruction, bne::BNEInstruction, lb::LBInstruction, lh::LHInstruction, @@ -158,6 +161,41 @@ where pub type RV32IJoltProof = JoltProof>; +use std::fs::File; +use std::path::PathBuf; +use eyre::Result; + +pub type PCS = HyraxScheme; + +#[derive(CanonicalSerialize, CanonicalDeserialize)] +pub struct RV32IHyraxProof { + pub proof: RV32IJoltProof, + pub commitments: JoltCommitments, +} + +impl RV32IHyraxProof{ + /// Gets the byte size of the full proof + pub fn size(&self) -> Result { + let mut buffer = Vec::new(); + self.serialize_compressed(&mut buffer)?; + Ok(buffer.len()) + } + + /// Saves the proof to a file + pub fn save_to_file>(&self, path: P) -> Result<()> { + let file = File::create(path.into())?; + self.serialize_compressed(file)?; + Ok(()) + } + + /// Reads a proof from a file + pub fn from_file>(path: P) -> Result { + let file = File::open(path.into())?; + Ok(RV32IHyraxProof::deserialize_compressed(file)?) + } +} + + // ==================== TEST ==================== #[cfg(test)] diff --git a/jolt-sdk/macros/src/lib.rs b/jolt-sdk/macros/src/lib.rs index c98e7b43f..8a27b66f5 100644 --- a/jolt-sdk/macros/src/lib.rs +++ b/jolt-sdk/macros/src/lib.rs @@ -93,7 +93,7 @@ impl MacroBuilder { #[cfg(not(feature = "guest"))] pub fn #build_fn_name() -> ( impl Fn(#(#input_types),*) -> #prove_output_ty, - impl Fn(jolt::Proof) -> bool + impl Fn(jolt::RV32IHyraxProof) -> bool ) { #imports let (program, preprocessing) = #preprocess_fn_name(); @@ -110,7 +110,7 @@ impl MacroBuilder { }; - let verify_closure = move |proof: jolt::Proof| { + let verify_closure = move |proof: jolt::RV32IHyraxProof| { let program = (*program_cp).clone(); let preprocessing = (*preprocessing_cp).clone(); RV32IJoltVM::verify(preprocessing, proof.proof, proof.commitments).is_ok() @@ -179,7 +179,7 @@ impl MacroBuilder { #[cfg(not(feature = "guest"))] pub fn #preprocess_fn_name() -> ( jolt::host::Program, - jolt::JoltPreprocessing + jolt::JoltPreprocessing ) { #imports @@ -190,7 +190,7 @@ impl MacroBuilder { let (bytecode, memory_init) = program.decode(); // TODO(moodlezoup): Feed in size parameters via macro - let preprocessing: JoltPreprocessing = + let preprocessing: JoltPreprocessing = RV32IJoltVM::preprocess( bytecode, memory_init, @@ -231,7 +231,7 @@ impl MacroBuilder { #[cfg(not(feature = "guest"))] pub fn #prove_fn_name( mut program: jolt::host::Program, - preprocessing: jolt::JoltPreprocessing, + preprocessing: jolt::JoltPreprocessing, #inputs ) -> #prove_output_ty { #imports @@ -252,7 +252,7 @@ impl MacroBuilder { #handle_return - let proof = jolt::Proof { + let proof = jolt::RV32IHyraxProof { proof: jolt_proof, commitments: jolt_commitments, }; @@ -487,10 +487,10 @@ impl MacroBuilder { fn get_prove_output_type(&self) -> TokenStream2 { match &self.func.sig.output { ReturnType::Default => quote! { - ((), jolt::Proof) + ((), jolt::RV32IHyraxProof) }, ReturnType::Type(_, ty) => quote! { - (#ty, jolt::Proof) + (#ty, jolt::RV32IHyraxProof) }, } } diff --git a/jolt-sdk/src/host_utils.rs b/jolt-sdk/src/host_utils.rs index fa42787ba..819890f92 100644 --- a/jolt-sdk/src/host_utils.rs +++ b/jolt-sdk/src/host_utils.rs @@ -1,13 +1,7 @@ -use std::fs::File; -use std::path::PathBuf; - -use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; -use eyre::Result; pub use ark_bn254::{Fr as F, G1Projective as G}; pub use ark_ec::CurveGroup; pub use jolt_core::field::JoltField; -use jolt_core::poly::commitment::hyrax::HyraxScheme; pub use common::{ constants::MEMORY_OPS_PER_INSTRUCTION, @@ -17,37 +11,7 @@ pub use jolt_core::host; pub use jolt_core::jolt::instruction; pub use jolt_core::jolt::vm::{ bytecode::BytecodeRow, - rv32i_vm::{RV32IJoltProof, RV32IJoltVM, RV32I}, + rv32i_vm::{RV32IJoltProof, PCS, RV32IHyraxProof, RV32IJoltVM, RV32I}, Jolt, JoltCommitments, JoltPreprocessing, JoltProof, }; -pub use tracer; - -pub type CommitmentScheme = HyraxScheme; - -#[derive(CanonicalSerialize, CanonicalDeserialize)] -pub struct Proof { - pub proof: RV32IJoltProof, - pub commitments: JoltCommitments, -} - -impl Proof { - /// Gets the byte size of the full proof - pub fn size(&self) -> Result { - let mut buffer = Vec::new(); - self.serialize_compressed(&mut buffer)?; - Ok(buffer.len()) - } - - /// Saves the proof to a file - pub fn save_to_file>(&self, path: P) -> Result<()> { - let file = File::create(path.into())?; - self.serialize_compressed(file)?; - Ok(()) - } - - /// Reads a proof from a file - pub fn from_file>(path: P) -> Result { - let file = File::open(path.into())?; - Ok(Proof::deserialize_compressed(file)?) - } -} +pub use tracer; \ No newline at end of file diff --git a/jolt-sdk/src/lib.rs b/jolt-sdk/src/lib.rs index bf3235bc8..160eaebb5 100644 --- a/jolt-sdk/src/lib.rs +++ b/jolt-sdk/src/lib.rs @@ -11,4 +11,4 @@ pub mod host_utils; pub use host_utils::*; pub mod alloc; -pub use alloc::*; +pub use alloc::*; \ No newline at end of file diff --git a/jolt.proof b/jolt.proof new file mode 100644 index 0000000000000000000000000000000000000000..c8728335f3ffcb5c50d324d9643b2ee04aacf0a0 GIT binary patch literal 523160 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

pWl9_{V|2!-SgPk(k7)# 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%0A4dm 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

}I${!yPm{~nd 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 literal 0 HcmV?d00001 diff --git a/tracer/src/lib.rs b/tracer/src/lib.rs index 468a079ed..56f7197a6 100644 --- a/tracer/src/lib.rs +++ b/tracer/src/lib.rs @@ -70,12 +70,14 @@ pub fn trace( } #[tracing::instrument(skip_all)] -pub fn decode(elf: &PathBuf) -> (Vec, Vec<(u64, u8)>) { +pub fn decode(elf: &[u8]) -> (Vec, Vec<(u64, u8)>) { + /* let mut elf_file = File::open(elf).unwrap(); let mut elf_contents = Vec::new(); elf_file.read_to_end(&mut elf_contents).unwrap(); - let obj = object::File::parse(&*elf_contents).unwrap(); + */ + let obj = object::File::parse(&*elf).unwrap(); let sections = obj .sections() From e12b65ca11c57d68a4d0e44da019e76ef6605c07 Mon Sep 17 00:00:00 2001 From: PatStiles Date: Thu, 13 Jun 2024 00:04:24 -0700 Subject: [PATCH 24/43] add write to macro --- jolt-core/src/host/mod.rs | 10 ++++++++++ jolt-sdk/macros/src/lib.rs | 21 ++++++++++++++++++++- jolt.proof | Bin 523160 -> 0 bytes 3 files changed, 30 insertions(+), 1 deletion(-) delete mode 100644 jolt.proof diff --git a/jolt-core/src/host/mod.rs b/jolt-core/src/host/mod.rs index 860da86a2..6d3eebb57 100644 --- a/jolt-core/src/host/mod.rs +++ b/jolt-core/src/host/mod.rs @@ -257,6 +257,16 @@ impl Program { fn linker_path(&self) -> String { format!("/tmp/jolt-guest-linkers/{}.ld", self.guest) } + + /// Saves the proof to a file + pub fn save_elf(&self) { + if !PathBuf::from("elf/").exists() { + fs::create_dir_all("elf/").expect("could not create elf directory"); + } + let elf = self.elf.as_ref().unwrap(); + fs::copy(elf, format!("elf/{}.elf", self.guest)).expect("could not save elf to local directory"); + } + } const LINKER_SCRIPT_TEMPLATE: &str = r#" diff --git a/jolt-sdk/macros/src/lib.rs b/jolt-sdk/macros/src/lib.rs index 8a27b66f5..bf4b100e5 100644 --- a/jolt-sdk/macros/src/lib.rs +++ b/jolt-sdk/macros/src/lib.rs @@ -206,6 +206,7 @@ impl MacroBuilder { fn make_prove_func(&self) -> TokenStream2 { let prove_output_ty = self.get_prove_output_type(); + let write_to_file = self.make_write_to_file(); let handle_return = match &self.func.sig.output { ReturnType::Default => quote! { @@ -239,7 +240,7 @@ impl MacroBuilder { #(#set_program_args;)* let (io_device, trace, circuit_flags) = - program.trace(); + program.clone().trace(); let output_bytes = io_device.outputs.clone(); @@ -257,6 +258,8 @@ impl MacroBuilder { commitments: jolt_commitments, }; + #write_to_file + (ret_val, proof) } } @@ -443,6 +446,18 @@ impl MacroBuilder { } } + fn make_write_to_file(&self) -> TokenStream2 { + if self.get_jolt_save() { + let fn_name = self.get_guest_name(); + quote! { + jolt::RV32IHyraxProof::save_to_file(&proof, format!("./{}.proof", #fn_name)).unwrap(); + program.save_elf(); + } + } else { + quote! {} + } + } + fn parse_attributes(&self) -> Attributes { let mut attributes = HashMap::<_, u64>::new(); for attr in &self.attr { @@ -523,6 +538,10 @@ impl MacroBuilder { fn get_func_selector(&self) -> Option { proc_macro::tracked_env::var("JOLT_FUNC_NAME").ok() } + + fn get_jolt_save(&self) -> bool { + proc_macro::tracked_env::var("JOLT_SAVE").is_ok() + } } struct Attributes { diff --git a/jolt.proof b/jolt.proof deleted file mode 100644 index c8728335f3ffcb5c50d324d9643b2ee04aacf0a0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 523160 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

pWl9_{V|2!-SgPk(k7)# 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%0A4dm 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

}I${!yPm{~nd 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 From 79f90e051a6bf4e3c07f0c46f0902bf5076e9bd8 Mon Sep 17 00:00:00 2001 From: PatStiles Date: Thu, 13 Jun 2024 00:06:56 -0700 Subject: [PATCH 25/43] rm comment --- tracer/src/lib.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tracer/src/lib.rs b/tracer/src/lib.rs index 56f7197a6..11d0a2a8f 100644 --- a/tracer/src/lib.rs +++ b/tracer/src/lib.rs @@ -71,12 +71,6 @@ pub fn trace( #[tracing::instrument(skip_all)] pub fn decode(elf: &[u8]) -> (Vec, Vec<(u64, u8)>) { - /* - let mut elf_file = File::open(elf).unwrap(); - let mut elf_contents = Vec::new(); - elf_file.read_to_end(&mut elf_contents).unwrap(); - - */ let obj = object::File::parse(&*elf).unwrap(); let sections = obj From 161f991ea6938aac488d6b71406348f3dc857bcf Mon Sep 17 00:00:00 2001 From: PatStiles Date: Thu, 13 Jun 2024 00:16:39 -0700 Subject: [PATCH 26/43] fmt --- jolt-core/src/host/mod.rs | 6 +++--- jolt-core/src/jolt/vm/rv32i_vm.rs | 5 ++--- jolt-sdk/src/host_utils.rs | 5 ++--- jolt-sdk/src/lib.rs | 2 +- 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/jolt-core/src/host/mod.rs b/jolt-core/src/host/mod.rs index 6d3eebb57..e18989400 100644 --- a/jolt-core/src/host/mod.rs +++ b/jolt-core/src/host/mod.rs @@ -3,7 +3,7 @@ use core::str::FromStr; use std::{ fs::{self, File}, - io::{self, Write, Read}, + io::{self, Read, Write}, path::PathBuf, process::Command, }; @@ -264,9 +264,9 @@ impl Program { fs::create_dir_all("elf/").expect("could not create elf directory"); } let elf = self.elf.as_ref().unwrap(); - fs::copy(elf, format!("elf/{}.elf", self.guest)).expect("could not save elf to local directory"); + fs::copy(elf, format!("elf/{}.elf", self.guest)) + .expect("could not save elf to local directory"); } - } const LINKER_SCRIPT_TEMPLATE: &str = r#" diff --git a/jolt-core/src/jolt/vm/rv32i_vm.rs b/jolt-core/src/jolt/vm/rv32i_vm.rs index 5bc79ffbc..b1151c34c 100644 --- a/jolt-core/src/jolt/vm/rv32i_vm.rs +++ b/jolt-core/src/jolt/vm/rv32i_vm.rs @@ -161,9 +161,9 @@ where pub type RV32IJoltProof = JoltProof>; +use eyre::Result; use std::fs::File; use std::path::PathBuf; -use eyre::Result; pub type PCS = HyraxScheme; @@ -173,7 +173,7 @@ pub struct RV32IHyraxProof { pub commitments: JoltCommitments, } -impl RV32IHyraxProof{ +impl RV32IHyraxProof { /// Gets the byte size of the full proof pub fn size(&self) -> Result { let mut buffer = Vec::new(); @@ -195,7 +195,6 @@ impl RV32IHyraxProof{ } } - // ==================== TEST ==================== #[cfg(test)] diff --git a/jolt-sdk/src/host_utils.rs b/jolt-sdk/src/host_utils.rs index 819890f92..f5e4bf31f 100644 --- a/jolt-sdk/src/host_utils.rs +++ b/jolt-sdk/src/host_utils.rs @@ -1,4 +1,3 @@ - pub use ark_bn254::{Fr as F, G1Projective as G}; pub use ark_ec::CurveGroup; pub use jolt_core::field::JoltField; @@ -11,7 +10,7 @@ pub use jolt_core::host; pub use jolt_core::jolt::instruction; pub use jolt_core::jolt::vm::{ bytecode::BytecodeRow, - rv32i_vm::{RV32IJoltProof, PCS, RV32IHyraxProof, RV32IJoltVM, RV32I}, + rv32i_vm::{RV32IHyraxProof, RV32IJoltProof, RV32IJoltVM, PCS, RV32I}, Jolt, JoltCommitments, JoltPreprocessing, JoltProof, }; -pub use tracer; \ No newline at end of file +pub use tracer; diff --git a/jolt-sdk/src/lib.rs b/jolt-sdk/src/lib.rs index 160eaebb5..bf3235bc8 100644 --- a/jolt-sdk/src/lib.rs +++ b/jolt-sdk/src/lib.rs @@ -11,4 +11,4 @@ pub mod host_utils; pub use host_utils::*; pub mod alloc; -pub use alloc::*; \ No newline at end of file +pub use alloc::*; From ac46ee6af0742f4a6a99551e53ad722e6d61a52e Mon Sep 17 00:00:00 2001 From: PatStiles Date: Thu, 13 Jun 2024 00:17:40 -0700 Subject: [PATCH 27/43] clippy --- tracer/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tracer/src/lib.rs b/tracer/src/lib.rs index 11d0a2a8f..8d5ac1bb1 100644 --- a/tracer/src/lib.rs +++ b/tracer/src/lib.rs @@ -71,7 +71,7 @@ pub fn trace( #[tracing::instrument(skip_all)] pub fn decode(elf: &[u8]) -> (Vec, Vec<(u64, u8)>) { - let obj = object::File::parse(&*elf).unwrap(); + let obj = object::File::parse(elf).unwrap(); let sections = obj .sections() From cb1588bbd9e6736f444b0318408f2d66535ec2fc Mon Sep 17 00:00:00 2001 From: PatStiles Date: Tue, 2 Jul 2024 14:31:42 -0700 Subject: [PATCH 28/43] mv proof to host --- jolt-sdk/src/host_utils.rs | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/jolt-sdk/src/host_utils.rs b/jolt-sdk/src/host_utils.rs index f5e4bf31f..66804d269 100644 --- a/jolt-sdk/src/host_utils.rs +++ b/jolt-sdk/src/host_utils.rs @@ -2,6 +2,11 @@ pub use ark_bn254::{Fr as F, G1Projective as G}; pub use ark_ec::CurveGroup; pub use jolt_core::field::JoltField; +use eyre::Result; +use std::fs::File; +use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; +use std::path::PathBuf; + pub use common::{ constants::MEMORY_OPS_PER_INSTRUCTION, rv_trace::{MemoryOp, RV32IM}, @@ -14,3 +19,33 @@ pub use jolt_core::jolt::vm::{ Jolt, JoltCommitments, JoltPreprocessing, JoltProof, }; pub use tracer; + +pub type ProofPCS = HyraxScheme; + +#[derive(CanonicalSerialize, CanonicalDeserialize)] +pub struct Proof { + pub proof: RV32IJoltProof, + pub commitments: JoltCommitments, +} + +impl Proof { + /// Gets the byte size of the full proof + pub fn size(&self) -> Result { + let mut buffer = Vec::new(); + self.serialize_compressed(&mut buffer)?; + Ok(buffer.len()) + } + + /// Saves the proof to a file + pub fn save_to_file>(&self, path: P) -> Result<()> { + let file = File::create(path.into())?; + self.serialize_compressed(file)?; + Ok(()) + } + + /// Reads a proof from a file + pub fn from_file>(path: P) -> Result { + let file = File::open(path.into())?; + Ok(RV32IHyraxProof::deserialize_compressed(file)?) + } +} From ed0cf827e442a126987106b619e3a28366696b5e Mon Sep 17 00:00:00 2001 From: PatStiles Date: Tue, 2 Jul 2024 14:44:00 -0700 Subject: [PATCH 29/43] nits --- jolt-sdk/src/host_utils.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jolt-sdk/src/host_utils.rs b/jolt-sdk/src/host_utils.rs index 66804d269..000239f0b 100644 --- a/jolt-sdk/src/host_utils.rs +++ b/jolt-sdk/src/host_utils.rs @@ -1,6 +1,6 @@ pub use ark_bn254::{Fr as F, G1Projective as G}; pub use ark_ec::CurveGroup; -pub use jolt_core::field::JoltField; +pub use jolt_core::{poly::commitment::hyrax::HyraxScheme, field::JoltField}; use eyre::Result; use std::fs::File; @@ -20,11 +20,11 @@ pub use jolt_core::jolt::vm::{ }; pub use tracer; -pub type ProofPCS = HyraxScheme; +pub type ProofPCS = HyraxScheme; #[derive(CanonicalSerialize, CanonicalDeserialize)] pub struct Proof { - pub proof: RV32IJoltProof, + pub proof: RV32IJoltProof, pub commitments: JoltCommitments, } From 252a907920e493f3ede7545782c7483213ec902f Mon Sep 17 00:00:00 2001 From: PatStiles Date: Tue, 2 Jul 2024 14:47:11 -0700 Subject: [PATCH 30/43] nit --- jolt-sdk/src/host_utils.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jolt-sdk/src/host_utils.rs b/jolt-sdk/src/host_utils.rs index 000239f0b..377e45a0b 100644 --- a/jolt-sdk/src/host_utils.rs +++ b/jolt-sdk/src/host_utils.rs @@ -46,6 +46,6 @@ impl Proof { /// Reads a proof from a file pub fn from_file>(path: P) -> Result { let file = File::open(path.into())?; - Ok(RV32IHyraxProof::deserialize_compressed(file)?) + Ok(Proof::deserialize_compressed(file)?) } } From 967f795f673c1fef9461a42b4bdf4386521230b0 Mon Sep 17 00:00:00 2001 From: PatStiles Date: Tue, 2 Jul 2024 20:16:38 -0700 Subject: [PATCH 31/43] mv'd proof back to vm --- jolt-sdk/src/host_utils.rs | 37 +------------------------------------ 1 file changed, 1 insertion(+), 36 deletions(-) diff --git a/jolt-sdk/src/host_utils.rs b/jolt-sdk/src/host_utils.rs index 377e45a0b..5c5aafb31 100644 --- a/jolt-sdk/src/host_utils.rs +++ b/jolt-sdk/src/host_utils.rs @@ -2,11 +2,6 @@ pub use ark_bn254::{Fr as F, G1Projective as G}; pub use ark_ec::CurveGroup; pub use jolt_core::{poly::commitment::hyrax::HyraxScheme, field::JoltField}; -use eyre::Result; -use std::fs::File; -use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; -use std::path::PathBuf; - pub use common::{ constants::MEMORY_OPS_PER_INSTRUCTION, rv_trace::{MemoryOp, RV32IM}, @@ -18,34 +13,4 @@ pub use jolt_core::jolt::vm::{ rv32i_vm::{RV32IHyraxProof, RV32IJoltProof, RV32IJoltVM, PCS, RV32I}, Jolt, JoltCommitments, JoltPreprocessing, JoltProof, }; -pub use tracer; - -pub type ProofPCS = HyraxScheme; - -#[derive(CanonicalSerialize, CanonicalDeserialize)] -pub struct Proof { - pub proof: RV32IJoltProof, - pub commitments: JoltCommitments, -} - -impl Proof { - /// Gets the byte size of the full proof - pub fn size(&self) -> Result { - let mut buffer = Vec::new(); - self.serialize_compressed(&mut buffer)?; - Ok(buffer.len()) - } - - /// Saves the proof to a file - pub fn save_to_file>(&self, path: P) -> Result<()> { - let file = File::create(path.into())?; - self.serialize_compressed(file)?; - Ok(()) - } - - /// Reads a proof from a file - pub fn from_file>(path: P) -> Result { - let file = File::open(path.into())?; - Ok(Proof::deserialize_compressed(file)?) - } -} +pub use tracer; \ No newline at end of file From 6693ae9e6e5aa946a91261d670a16cc7e5d70aff Mon Sep 17 00:00:00 2001 From: PatStiles Date: Thu, 4 Jul 2024 16:09:03 -0700 Subject: [PATCH 32/43] integrate feedback --- jolt-core/src/host/mod.rs | 10 ---------- jolt-sdk/macros/src/lib.rs | 21 +-------------------- 2 files changed, 1 insertion(+), 30 deletions(-) diff --git a/jolt-core/src/host/mod.rs b/jolt-core/src/host/mod.rs index e18989400..74622881d 100644 --- a/jolt-core/src/host/mod.rs +++ b/jolt-core/src/host/mod.rs @@ -257,16 +257,6 @@ impl Program { fn linker_path(&self) -> String { format!("/tmp/jolt-guest-linkers/{}.ld", self.guest) } - - /// Saves the proof to a file - pub fn save_elf(&self) { - if !PathBuf::from("elf/").exists() { - fs::create_dir_all("elf/").expect("could not create elf directory"); - } - let elf = self.elf.as_ref().unwrap(); - fs::copy(elf, format!("elf/{}.elf", self.guest)) - .expect("could not save elf to local directory"); - } } const LINKER_SCRIPT_TEMPLATE: &str = r#" diff --git a/jolt-sdk/macros/src/lib.rs b/jolt-sdk/macros/src/lib.rs index bf4b100e5..8a27b66f5 100644 --- a/jolt-sdk/macros/src/lib.rs +++ b/jolt-sdk/macros/src/lib.rs @@ -206,7 +206,6 @@ impl MacroBuilder { fn make_prove_func(&self) -> TokenStream2 { let prove_output_ty = self.get_prove_output_type(); - let write_to_file = self.make_write_to_file(); let handle_return = match &self.func.sig.output { ReturnType::Default => quote! { @@ -240,7 +239,7 @@ impl MacroBuilder { #(#set_program_args;)* let (io_device, trace, circuit_flags) = - program.clone().trace(); + program.trace(); let output_bytes = io_device.outputs.clone(); @@ -258,8 +257,6 @@ impl MacroBuilder { commitments: jolt_commitments, }; - #write_to_file - (ret_val, proof) } } @@ -446,18 +443,6 @@ impl MacroBuilder { } } - fn make_write_to_file(&self) -> TokenStream2 { - if self.get_jolt_save() { - let fn_name = self.get_guest_name(); - quote! { - jolt::RV32IHyraxProof::save_to_file(&proof, format!("./{}.proof", #fn_name)).unwrap(); - program.save_elf(); - } - } else { - quote! {} - } - } - fn parse_attributes(&self) -> Attributes { let mut attributes = HashMap::<_, u64>::new(); for attr in &self.attr { @@ -538,10 +523,6 @@ impl MacroBuilder { fn get_func_selector(&self) -> Option { proc_macro::tracked_env::var("JOLT_FUNC_NAME").ok() } - - fn get_jolt_save(&self) -> bool { - proc_macro::tracked_env::var("JOLT_SAVE").is_ok() - } } struct Attributes { From 954054344cd481e59ae35c8fa20f367f658e7c77 Mon Sep 17 00:00:00 2001 From: PatStiles Date: Thu, 4 Jul 2024 16:12:56 -0700 Subject: [PATCH 33/43] fmt --- jolt-sdk/src/host_utils.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jolt-sdk/src/host_utils.rs b/jolt-sdk/src/host_utils.rs index 5c5aafb31..a11c9b16b 100644 --- a/jolt-sdk/src/host_utils.rs +++ b/jolt-sdk/src/host_utils.rs @@ -1,6 +1,6 @@ pub use ark_bn254::{Fr as F, G1Projective as G}; pub use ark_ec::CurveGroup; -pub use jolt_core::{poly::commitment::hyrax::HyraxScheme, field::JoltField}; +pub use jolt_core::{field::JoltField, poly::commitment::hyrax::HyraxScheme}; pub use common::{ constants::MEMORY_OPS_PER_INSTRUCTION, @@ -13,4 +13,4 @@ pub use jolt_core::jolt::vm::{ rv32i_vm::{RV32IHyraxProof, RV32IJoltProof, RV32IJoltVM, PCS, RV32I}, Jolt, JoltCommitments, JoltPreprocessing, JoltProof, }; -pub use tracer; \ No newline at end of file +pub use tracer; From 77fe6a184b7b781cd83a2fcc693d95a146b9e19b Mon Sep 17 00:00:00 2001 From: sragss Date: Tue, 16 Jul 2024 21:40:28 -0700 Subject: [PATCH 34/43] address comments round 1 --- jolt-core/src/poly/dense_mlpoly.rs | 10 ++++ jolt-core/src/r1cs/builder.rs | 66 ++++++++++++------------ jolt-core/src/r1cs/spartan.rs | 12 ++--- jolt-core/src/r1cs/special_polys.rs | 70 ++++++++++---------------- jolt-core/src/subprotocols/sumcheck.rs | 2 +- 5 files changed, 76 insertions(+), 84 deletions(-) diff --git a/jolt-core/src/poly/dense_mlpoly.rs b/jolt-core/src/poly/dense_mlpoly.rs index 6bfd3aab2..34b9932c5 100644 --- a/jolt-core/src/poly/dense_mlpoly.rs +++ b/jolt-core/src/poly/dense_mlpoly.rs @@ -203,6 +203,16 @@ impl DensePolynomial { #[tracing::instrument(skip_all)] pub fn bound_poly_var_bot(&mut self, r: &F) { + let n = self.len() / 2; + for i in 0..n { + self.Z[i] = self.Z[2 * i] + *r * (self.Z[2 * i + 1] - self.Z[2 * i]); + } + + self.num_vars -= 1; + self.len = n; + } + + pub fn bound_poly_var_bot_01_optimized(&mut self, r: &F) { let n = self.len() / 2; let mut new_z = unsafe_allocate_zero_vec(n); new_z.par_iter_mut().enumerate().for_each(|(i, z)| { diff --git a/jolt-core/src/r1cs/builder.rs b/jolt-core/src/r1cs/builder.rs index 440e7ab66..c6e69c62e 100644 --- a/jolt-core/src/r1cs/builder.rs +++ b/jolt-core/src/r1cs/builder.rs @@ -779,43 +779,41 @@ impl CombinedUniformBuilder { // uniform_constraints: Xz[0..uniform_constraint_rows] let span = tracing::span!(tracing::Level::DEBUG, "uniform_evals"); let _enter = span.enter(); - let uni_constraint_evals: Vec<(Vec<(F, usize)>, Vec<(F, usize)>, Vec<(F, usize)>)> = - self.uniform_builder - .constraints - .par_iter() - .enumerate() - .map(|(constraint_index, constraint)| { - let mut dense_output_buffer = unsafe_allocate_zero_vec(self.uniform_repeat); - - let mut evaluate_lc_chunk = |lc: &LC| { - if !lc.terms().is_empty() { - let inputs = batch_inputs(lc); - lc.evaluate_batch_mut(&inputs, &mut dense_output_buffer); - - // Take only the non-zero elements and represent them as sparse tuples (eval, dense_index) - let mut sparse = Vec::with_capacity(self.uniform_repeat); // overshoot - dense_output_buffer.iter().enumerate().for_each( - |(local_index, item)| { - if !item.is_zero() { - let global_index = - constraint_index * self.uniform_repeat + local_index; - sparse.push((*item, global_index)); - } - }, - ); - sparse - } else { - vec![] + let uni_constraint_evals: Vec<(Vec<(F, usize)>, Vec<(F, usize)>, Vec<(F, usize)>)> = self + .uniform_builder + .constraints + .par_iter() + .enumerate() + .map(|(constraint_index, constraint)| { + let mut dense_output_buffer = unsafe_allocate_zero_vec(self.uniform_repeat); + + let mut evaluate_lc_chunk = |lc: &LC| { + if !lc.terms().is_empty() { + let inputs = batch_inputs(lc); + lc.evaluate_batch_mut(&inputs, &mut dense_output_buffer); + + // Take only the non-zero elements and represent them as sparse tuples (eval, dense_index) + let mut sparse = Vec::with_capacity(self.uniform_repeat); // overshoot + for (local_index, item) in dense_output_buffer.iter().enumerate() { + if !item.is_zero() { + let global_index = + constraint_index * self.uniform_repeat + local_index; + sparse.push((*item, global_index)); + } } - }; + sparse + } else { + vec![] + } + }; - let a_chunk: Vec<(F, usize)> = evaluate_lc_chunk(&constraint.a); - let b_chunk: Vec<(F, usize)> = evaluate_lc_chunk(&constraint.b); - let c_chunk: Vec<(F, usize)> = evaluate_lc_chunk(&constraint.c); + let a_chunk: Vec<(F, usize)> = evaluate_lc_chunk(&constraint.a); + let b_chunk: Vec<(F, usize)> = evaluate_lc_chunk(&constraint.b); + let c_chunk: Vec<(F, usize)> = evaluate_lc_chunk(&constraint.c); - (a_chunk, b_chunk, c_chunk) - }) - .collect(); + (a_chunk, b_chunk, c_chunk) + }) + .collect(); let (mut az_sparse, mut bz_sparse, cz_sparse) = par_flatten_triple( uni_constraint_evals, diff --git a/jolt-core/src/r1cs/spartan.rs b/jolt-core/src/r1cs/spartan.rs index 0058f91e2..4e603a574 100644 --- a/jolt-core/src/r1cs/spartan.rs +++ b/jolt-core/src/r1cs/spartan.rs @@ -112,20 +112,20 @@ impl> UniformSpartanProof { let aux = &segmented_padded_witness.segments[I::COUNT..]; let (mut az, mut bz, mut cz) = constraint_builder.compute_spartan_Az_Bz_Cz(inputs, aux); - let comb_func_outer = |A: &F, B: &F, C: &F, D: &F| -> F { + let comb_func_outer = |eq: &F, az: &F, bz: &F, cz: &F| -> F { // Below is an optimized form of: *A * (*B * *C - *D) - if B.is_zero() || C.is_zero() { - if D.is_zero() { + if az.is_zero() || bz.is_zero() { + if cz.is_zero() { F::zero() } else { - *A * (-(*D)) + *eq * (-(*cz)) } } else { - let inner = *B * *C - *D; + let inner = *az * *bz - *cz; if inner.is_zero() { F::zero() } else { - *A * inner + *eq * inner } } }; diff --git a/jolt-core/src/r1cs/special_polys.rs b/jolt-core/src/r1cs/special_polys.rs index a42b01dab..9dfb637e3 100644 --- a/jolt-core/src/r1cs/special_polys.rs +++ b/jolt-core/src/r1cs/special_polys.rs @@ -23,33 +23,6 @@ impl SparsePolynomial { SparsePolynomial { num_vars, Z } } - // TODO(sragss): rm - #[tracing::instrument(skip_all)] - pub fn from_dense_evals(num_vars: usize, evals: Vec) -> Self { - assert!(num_vars.pow2() >= evals.len()); - let non_zero_count: usize = evals - .par_chunks(10_000) - .map(|chunk| chunk.iter().filter(|f| !f.is_zero()).count()) - .sum(); - - let span_allocate = tracing::span!(tracing::Level::DEBUG, "allocate"); - let _enter_allocate = span_allocate.enter(); - let mut sparse: Vec<(F, usize)> = unsafe_allocate_sparse_zero_vec(non_zero_count); - drop(_enter_allocate); - - let span_copy = tracing::span!(tracing::Level::DEBUG, "copy"); - let _enter_copy = span_copy.enter(); - let mut sparse_index = 0; - for (dense_index, dense) in evals.iter().enumerate() { - if !dense.is_zero() { - sparse[sparse_index] = (*dense, dense_index); - sparse_index += 1; - } - } - drop(_enter_copy); - Self::new(num_vars, sparse) - } - /// Computes the $\tilde{eq}$ extension polynomial. /// return 1 when a == r, otherwise return 0. fn compute_chi(a: &[bool], r: &[F]) -> F { @@ -288,7 +261,14 @@ impl<'a, F: JoltField> SparseTripleIterator<'a, F> { // B is assumed most dense. Parallelism depends on evenly distributing B across threads. assert!(b.Z.len() >= a.Z.len() && b.Z.len() >= c.Z.len()); - // TODO(sragss): Explain the strategy + // We'd like to scan over 3 SparsePolynomials (a,b,c) in `n` chunks for parallelism. + // With dense polynomials we could split directly by index, with SparsePolynomials we don't + // know the distribution of indices in the polynomials in advance. + // Further, the dense indices do not match: a[i].dense_index != b[i].dense_index != c[i].dense_index + // We expect b.len() >> max(a.len(), c.len()), so we'll split b first and use as a guide for (a,c). + // We'll split it into `n` chunks of roughly even length, but we will not split "sibling" dense indices across + // chunks as the presence of the pair is relevant to downstream algos. + // Dense siblings: (0,1), (2,3), ... let (b_chunks, mut dense_ranges) = b.chunk_no_split_siblings(n); let highest_non_zero = [&a.Z, &b.Z, &c.Z] @@ -303,35 +283,38 @@ impl<'a, F: JoltField> SparseTripleIterator<'a, F> { // Create chunks of (a, c) which overlap with b's sparse indices let mut a_chunks: Vec<&[(F, usize)]> = vec![&[]; n]; let mut c_chunks: Vec<&[(F, usize)]> = vec![&[]; n]; - let mut a_i = 0; - let mut c_i = 0; + let mut a_sparse_i = 0; + let mut c_sparse_i = 0; let span = tracing::span!(tracing::Level::DEBUG, "a_c_chunking"); let _enter = span.enter(); + // Using b's dense_ranges as a guide, fill out (a_chunks, c_chunks) for (chunk_index, range) in dense_ranges.iter().enumerate().skip(1) { // Find the corresponding a, c chunks - let prev_chunk_end = range.0; + let dense_range_end = range.0; - if a_i < a.Z.len() && a.Z[a_i].1 < prev_chunk_end { - let a_start = a_i; - while a_i < a.Z.len() && a.Z[a_i].1 < prev_chunk_end { - a_i += 1; + if a_sparse_i < a.Z.len() && a.Z[a_sparse_i].1 < dense_range_end { + let a_start = a_sparse_i; + // Scan over a until the corresponding dense index is out of range + while a_sparse_i < a.Z.len() && a.Z[a_sparse_i].1 < dense_range_end { + a_sparse_i += 1; } - a_chunks[chunk_index - 1] = &a.Z[a_start..a_i]; + a_chunks[chunk_index - 1] = &a.Z[a_start..a_sparse_i]; } - if c_i < c.Z.len() && c.Z[c_i].1 < prev_chunk_end { - let c_start = c_i; - while c_i < c.Z.len() && c.Z[c_i].1 < prev_chunk_end { - c_i += 1; + if c_sparse_i < c.Z.len() && c.Z[c_sparse_i].1 < dense_range_end { + let c_start = c_sparse_i; + // Scan over c until the corresponding dense index is out of range + while c_sparse_i < c.Z.len() && c.Z[c_sparse_i].1 < dense_range_end { + c_sparse_i += 1; } - c_chunks[chunk_index - 1] = &c.Z[c_start..c_i]; + c_chunks[chunk_index - 1] = &c.Z[c_start..c_sparse_i]; } } drop(_enter); - a_chunks[n - 1] = &a.Z[a_i..]; - c_chunks[n - 1] = &c.Z[c_i..]; + a_chunks[n - 1] = &a.Z[a_sparse_i..]; + c_chunks[n - 1] = &c.Z[c_sparse_i..]; #[cfg(test)] { @@ -340,6 +323,7 @@ impl<'a, F: JoltField> SparseTripleIterator<'a, F> { assert_eq!(c_chunks.concat(), c.Z); } + // Assemble the triple iterator objects let mut iterators: Vec> = Vec::with_capacity(n); for (((a_chunk, b_chunk), c_chunk), range) in a_chunks .iter() diff --git a/jolt-core/src/subprotocols/sumcheck.rs b/jolt-core/src/subprotocols/sumcheck.rs index a405fbfa3..151c73334 100644 --- a/jolt-core/src/subprotocols/sumcheck.rs +++ b/jolt-core/src/subprotocols/sumcheck.rs @@ -294,7 +294,7 @@ impl SumcheckInstanceProof { claim_per_round = poly.evaluate(&r_i); // bound all tables to the verifier's challenege - poly_eq.bound_poly_var_bot(&r_i); + poly_eq.bound_poly_var_bot_01_optimized(&r_i); poly_A.bound_poly_var_bot_par(&r_i); poly_B.bound_poly_var_bot_par(&r_i); poly_C.bound_poly_var_bot_par(&r_i); From 193dcf04dc65fac738ec2029e5423cb16eca0d2d Mon Sep 17 00:00:00 2001 From: sragss Date: Tue, 16 Jul 2024 23:06:59 -0700 Subject: [PATCH 35/43] clean up sparse non-uniform calc --- jolt-core/src/r1cs/builder.rs | 56 ++++++++++++++++------------------- 1 file changed, 25 insertions(+), 31 deletions(-) diff --git a/jolt-core/src/r1cs/builder.rs b/jolt-core/src/r1cs/builder.rs index c6e69c62e..b823f0b88 100644 --- a/jolt-core/src/r1cs/builder.rs +++ b/jolt-core/src/r1cs/builder.rs @@ -841,41 +841,35 @@ impl CombinedUniformBuilder { .1 .evaluate_batch(&batch_inputs(&constr.b.1), self.uniform_repeat); - let dense_az_bz: Vec<(F, F)> = (0..self.uniform_repeat) - .into_par_iter() - .map(|step_index| { - // Write corresponding values, if outside the step range, only include the constant. - let a_step = step_index + if constr.a.0 { 1 } else { 0 }; - let b_step = step_index + if constr.b.0 { 1 } else { 0 }; - let a = eq_a_evals - .get(a_step) - .cloned() - .unwrap_or(constr.a.1.constant_term_field()); - let b = eq_b_evals - .get(b_step) - .cloned() - .unwrap_or(constr.b.1.constant_term_field()); - let az = a - b; - - let condition_step = step_index + if constr.cond.0 { 1 } else { 0 }; - let bz = condition_evals - .get(condition_step) - .cloned() - .unwrap_or(constr.cond.1.constant_term_field()); - (az, bz) - }) - .collect(); - - // Sparsify: take only the non-zero elements - for (local_index, (az, bz)) in dense_az_bz.iter().enumerate() { - let global_index = uniform_constraint_rows + local_index; + (0..self.uniform_repeat).into_iter().for_each(|step_index| { + // Write corresponding values, if outside the step range, only include the constant. + let a_step = step_index + constr.a.0 as usize; + let b_step = step_index + constr.b.0 as usize; + let a = eq_a_evals + .get(a_step) + .cloned() + .unwrap_or(constr.a.1.constant_term_field()); + let b = eq_b_evals + .get(b_step) + .cloned() + .unwrap_or(constr.b.1.constant_term_field()); + let az = a - b; + + let global_index = uniform_constraint_rows + step_index; if !az.is_zero() { - az_sparse.push((*az, global_index)); + az_sparse.push((az, global_index)); } + + let condition_step = step_index + constr.cond.0 as usize; + let bz = condition_evals + .get(condition_step) + .cloned() + .unwrap_or(constr.cond.1.constant_term_field()); if !bz.is_zero() { - bz_sparse.push((*bz, global_index)); + bz_sparse.push((bz, global_index)); } - } + }); + drop(_enter); let num_vars = self.constraint_rows().next_power_of_two().log_2(); let az_poly = SparsePolynomial::new(num_vars, az_sparse); From be5e655def748df82d7f4e84b68d44f8f64c4664 Mon Sep 17 00:00:00 2001 From: sragss Date: Tue, 16 Jul 2024 23:36:33 -0700 Subject: [PATCH 36/43] fix tests --- jolt-core/src/poly/dense_mlpoly.rs | 1 + jolt-core/src/r1cs/special_polys.rs | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/jolt-core/src/poly/dense_mlpoly.rs b/jolt-core/src/poly/dense_mlpoly.rs index 34b9932c5..f28d4ff2a 100644 --- a/jolt-core/src/poly/dense_mlpoly.rs +++ b/jolt-core/src/poly/dense_mlpoly.rs @@ -201,6 +201,7 @@ impl DensePolynomial { } } + /// Note: does not truncate #[tracing::instrument(skip_all)] pub fn bound_poly_var_bot(&mut self, r: &F) { let n = self.len() / 2; diff --git a/jolt-core/src/r1cs/special_polys.rs b/jolt-core/src/r1cs/special_polys.rs index 9dfb637e3..e643d728f 100644 --- a/jolt-core/src/r1cs/special_polys.rs +++ b/jolt-core/src/r1cs/special_polys.rs @@ -532,7 +532,7 @@ mod tests { let r = Fr::from(121); sparse.bound_poly_var_bot(&r); - dense.bound_poly_var_bot(&r); + dense.bound_poly_var_bot_01_optimized(&r); assert_eq!(sparse.to_dense(), dense); } @@ -548,7 +548,7 @@ mod tests { let r = Fr::from(121); sparse.bound_poly_var_bot(&r); - dense.bound_poly_var_bot(&r); + dense.bound_poly_var_bot_01_optimized(&r); assert_eq!(sparse.to_dense(), dense); } @@ -579,7 +579,7 @@ mod tests { let r = Fr::from(121); sparse.bound_poly_var_bot(&r); - dense.bound_poly_var_bot(&r); + dense.bound_poly_var_bot_01_optimized(&r); assert_eq!(sparse.to_dense(), dense); } From cc5598c4dabf0be9ee359044453861fa9f638d4a Mon Sep 17 00:00:00 2001 From: sragss Date: Tue, 16 Jul 2024 23:40:40 -0700 Subject: [PATCH 37/43] fix clippy --- jolt-core/src/r1cs/builder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jolt-core/src/r1cs/builder.rs b/jolt-core/src/r1cs/builder.rs index b823f0b88..c09aa5dea 100644 --- a/jolt-core/src/r1cs/builder.rs +++ b/jolt-core/src/r1cs/builder.rs @@ -841,7 +841,7 @@ impl CombinedUniformBuilder { .1 .evaluate_batch(&batch_inputs(&constr.b.1), self.uniform_repeat); - (0..self.uniform_repeat).into_iter().for_each(|step_index| { + (0..self.uniform_repeat).for_each(|step_index| { // Write corresponding values, if outside the step range, only include the constant. let a_step = step_index + constr.a.0 as usize; let b_step = step_index + constr.b.0 as usize; From 1e10bfede7919ee918c68e77b940d9e83f4421d3 Mon Sep 17 00:00:00 2001 From: sragss Date: Thu, 18 Jul 2024 17:04:05 -0700 Subject: [PATCH 38/43] fix discriminant --- jolt-core/src/jolt/instruction/mod.rs | 4 +++- jolt-core/src/jolt/vm/rv32i_vm.rs | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/jolt-core/src/jolt/instruction/mod.rs b/jolt-core/src/jolt/instruction/mod.rs index 0b6c42eb8..b5e823136 100644 --- a/jolt-core/src/jolt/instruction/mod.rs +++ b/jolt-core/src/jolt/instruction/mod.rs @@ -74,7 +74,9 @@ pub trait JoltInstructionSet: JoltInstruction + IntoEnumIterator + EnumCount + for<'a> TryFrom<&'a ELFInstruction> + Send + Sync { fn enum_index(instruction: &Self) -> usize { - unsafe { *<*const _>::from(instruction).cast::() as usize } + // Discriminant: https://doc.rust-lang.org/reference/items/enumerations.html#pointer-casting + let byte = unsafe { *(instruction as *const Self as *const u8) }; + byte as usize } } diff --git a/jolt-core/src/jolt/vm/rv32i_vm.rs b/jolt-core/src/jolt/vm/rv32i_vm.rs index 98a1e5816..d38fe7cf6 100644 --- a/jolt-core/src/jolt/vm/rv32i_vm.rs +++ b/jolt-core/src/jolt/vm/rv32i_vm.rs @@ -57,7 +57,7 @@ macro_rules! instruction_set { macro_rules! subtable_enum { ($enum_name:ident, $($alias:ident: $struct:ty),+) => { #[allow(non_camel_case_types)] - #[repr(usize)] + #[repr(u8)] #[enum_dispatch(LassoSubtable)] #[derive(EnumCountMacro, EnumIter)] pub enum $enum_name { $($alias($struct)),+ } @@ -74,7 +74,9 @@ macro_rules! subtable_enum { impl From<$enum_name> for usize { fn from(subtable: $enum_name) -> usize { - unsafe { *<*const _>::from(&subtable).cast::() } + // Discriminant: https://doc.rust-lang.org/reference/items/enumerations.html#pointer-casting + let byte = unsafe { *(&subtable as *const $enum_name as *const u8) }; + byte as usize } } impl JoltSubtableSet for $enum_name {} From 829aa49fc66a7bc6322739a7529f14da416f1092 Mon Sep 17 00:00:00 2001 From: sragss Date: Thu, 18 Jul 2024 17:09:16 -0700 Subject: [PATCH 39/43] rename sumcheck A,B,C,D -> eq,A,B,C --- jolt-core/src/subprotocols/sumcheck.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/jolt-core/src/subprotocols/sumcheck.rs b/jolt-core/src/subprotocols/sumcheck.rs index 151c73334..b3e2f011f 100644 --- a/jolt-core/src/subprotocols/sumcheck.rs +++ b/jolt-core/src/subprotocols/sumcheck.rs @@ -215,27 +215,27 @@ impl SumcheckInstanceProof { let m_C = c_high - c_low; // eval 2 - let poly_A_bound_point = poly_eq[dense_index + 1] + m_eq; - let poly_B_bound_point = a_high + m_A; - let poly_C_bound_point = b_high + m_B; - let poly_D_bound_point = c_high + m_C; + let poly_eq_bound_point = poly_eq[dense_index + 1] + m_eq; + let poly_A_bound_point = a_high + m_A; + let poly_B_bound_point = b_high + m_B; + let poly_C_bound_point = c_high + m_C; eval_point_2 += comb_func( + &poly_eq_bound_point, &poly_A_bound_point, &poly_B_bound_point, &poly_C_bound_point, - &poly_D_bound_point, ); // eval 3 - let poly_A_bound_point = poly_A_bound_point + m_eq; - let poly_B_bound_point = poly_B_bound_point + m_A; - let poly_C_bound_point = poly_C_bound_point + m_B; - let poly_D_bound_point = poly_D_bound_point + m_C; + let poly_eq_bound_point = poly_eq_bound_point + m_eq; + let poly_A_bound_point = poly_A_bound_point + m_A; + let poly_B_bound_point = poly_B_bound_point + m_B; + let poly_C_bound_point = poly_C_bound_point + m_C; eval_point_3 += comb_func( + &poly_eq_bound_point, &poly_A_bound_point, &poly_B_bound_point, &poly_C_bound_point, - &poly_D_bound_point, ); } (eval_point_0, eval_point_2, eval_point_3) From 5c0f58a26e4a5b627a372291beb6ac9b33fb9e0e Mon Sep 17 00:00:00 2001 From: aleph_v <20227705+aleph-v@users.noreply.github.com> Date: Fri, 19 Jul 2024 17:00:15 +0200 Subject: [PATCH 40/43] use compressed polys in the transcript so they have a point --- jolt-core/src/jolt/vm/instruction_lookups.rs | 2 +- jolt-core/src/poly/unipoly.rs | 10 +++++++ jolt-core/src/subprotocols/sumcheck.rs | 28 ++++++++++++-------- 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/jolt-core/src/jolt/vm/instruction_lookups.rs b/jolt-core/src/jolt/vm/instruction_lookups.rs index bfa27cee7..2228cea21 100644 --- a/jolt-core/src/jolt/vm/instruction_lookups.rs +++ b/jolt-core/src/jolt/vm/instruction_lookups.rs @@ -1261,7 +1261,7 @@ where round_uni_poly: UniPoly, transcript: &mut ProofTranscript, ) -> F { - round_uni_poly.append_to_transcript(transcript); + round_uni_poly.compress().append_to_transcript(transcript); transcript.challenge_scalar::() } diff --git a/jolt-core/src/poly/unipoly.rs b/jolt-core/src/poly/unipoly.rs index 5c963fb2f..843f76de2 100644 --- a/jolt-core/src/poly/unipoly.rs +++ b/jolt-core/src/poly/unipoly.rs @@ -234,6 +234,16 @@ impl AppendToTranscript for UniPoly { } } +impl AppendToTranscript for CompressedUniPoly { + fn append_to_transcript(&self, transcript: &mut ProofTranscript) { + transcript.append_message(b"UniPoly_begin"); + for i in 0..self.coeffs_except_linear_term.len() { + transcript.append_scalar(&self.coeffs_except_linear_term[i]); + } + transcript.append_message(b"UniPoly_end"); + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/jolt-core/src/subprotocols/sumcheck.rs b/jolt-core/src/subprotocols/sumcheck.rs index bf3db2a49..1a64aef51 100644 --- a/jolt-core/src/subprotocols/sumcheck.rs +++ b/jolt-core/src/subprotocols/sumcheck.rs @@ -40,8 +40,9 @@ pub trait BatchedCubicSumcheck: Sync { for _round in 0..self.num_rounds() { let cubic_poly = self.compute_cubic(coeffs, eq_poly, previous_claim); + let compressed_poly = cubic_poly.compress(); // append the prover's message to the transcript - cubic_poly.append_to_transcript(transcript); + compressed_poly.append_to_transcript(transcript); //derive the verifier's challenge for the next round let r_j = transcript.challenge_scalar(); @@ -50,7 +51,7 @@ pub trait BatchedCubicSumcheck: Sync { self.bind(eq_poly, &r_j); previous_claim = cubic_poly.evaluate(&r_j); - cubic_polys.push(cubic_poly.compress()); + cubic_polys.push(compressed_poly); } debug_assert_eq!(eq_poly.len(), 1); @@ -156,9 +157,10 @@ impl SumcheckInstanceProof { }); let round_uni_poly = UniPoly::from_evals(&eval_points); + let round_compressed_poly = round_uni_poly.compress(); // append the prover's message to the transcript - round_uni_poly.append_to_transcript(transcript); + round_compressed_poly.append_to_transcript(transcript); let r_j = transcript.challenge_scalar(); r.push(r_j); @@ -166,7 +168,7 @@ impl SumcheckInstanceProof { polys .par_iter_mut() .for_each(|poly| poly.bound_poly_var_top(&r_j)); - compressed_polys.push(round_uni_poly.compress()); + compressed_polys.push(round_compressed_poly); } let final_evals = polys.iter().map(|poly| poly[0]).collect(); @@ -282,13 +284,15 @@ impl SumcheckInstanceProof { UniPoly::from_evals(&evals) }; + let compressed_poly = poly.compress(); + // append the prover's message to the transcript - poly.append_to_transcript(transcript); + compressed_poly.append_to_transcript(transcript); //derive the verifier's challenge for the next round let r_i = transcript.challenge_scalar(); r.push(r_i); - polys.push(poly.compress()); + polys.push(compressed_poly); // Set up next round claim_per_round = poly.evaluate(&r_i); @@ -370,13 +374,14 @@ impl SumcheckInstanceProof { UniPoly::from_evals(&evals) }; + let compressed_poly = poly.compress(); // append the prover's message to the transcript - poly.append_to_transcript(transcript); + compressed_poly.append_to_transcript(transcript); //derive the verifier's challenge for the next round let r_i: F = transcript.challenge_scalar(); r.push(r_i); - polys.push(poly.compress()); + polys.push(compressed_poly); // Set up next round claim_per_round = poly.evaluate(&r_i); @@ -417,14 +422,15 @@ impl SumcheckInstanceProof { UniPoly::from_evals(&evals) }; + let compressed_poly = poly.compress(); // append the prover's message to the transcript - poly.append_to_transcript(transcript); + compressed_poly.append_to_transcript(transcript); //derive the verifier's challenge for the next round let r_i: F = transcript.challenge_scalar(); r.push(r_i); - polys.push(poly.compress()); + polys.push(compressed_poly); // Set up next round claim_per_round = poly.evaluate(&r_i); @@ -528,7 +534,7 @@ impl SumcheckInstanceProof { assert_eq!(poly.eval_at_zero() + poly.eval_at_one(), e); // append the prover's message to the transcript - poly.append_to_transcript(transcript); + self.compressed_polys[i].append_to_transcript(transcript); //derive the verifier's challenge for the next round let r_i = transcript.challenge_scalar(); From c66784bae2a4d28ab2c24d344a60ff4b3414ad28 Mon Sep 17 00:00:00 2001 From: PatStiles Date: Fri, 19 Jul 2024 08:46:10 -0700 Subject: [PATCH 41/43] fmt --- jolt-core/src/poly/commitment/kzg.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/jolt-core/src/poly/commitment/kzg.rs b/jolt-core/src/poly/commitment/kzg.rs index 272b5333b..a4537df85 100644 --- a/jolt-core/src/poly/commitment/kzg.rs +++ b/jolt-core/src/poly/commitment/kzg.rs @@ -1,5 +1,5 @@ use crate::field::JoltField; -use crate::msm::VariableBaseMSM; +use crate::msm::{Icicle, VariableBaseMSM}; use crate::poly::unipoly::UniPoly; use crate::utils::errors::ProofVerifyError; use ark_ec::scalar_mul::fixed_base::FixedBase; @@ -118,6 +118,7 @@ pub struct UnivariateKZG { impl UnivariateKZG

where

::ScalarField: JoltField, +

::G1: Icicle, { #[tracing::instrument(skip_all, name = "KZG::commit_offset")] pub fn commit_offset( From 8e76d85341e836a93bb5f4aa1c1ca8e350937378 Mon Sep 17 00:00:00 2001 From: PatStiles Date: Fri, 19 Jul 2024 08:49:25 -0700 Subject: [PATCH 42/43] nit --- jolt-core/src/poly/commitment/kzg.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/jolt-core/src/poly/commitment/kzg.rs b/jolt-core/src/poly/commitment/kzg.rs index a4537df85..272b5333b 100644 --- a/jolt-core/src/poly/commitment/kzg.rs +++ b/jolt-core/src/poly/commitment/kzg.rs @@ -1,5 +1,5 @@ use crate::field::JoltField; -use crate::msm::{Icicle, VariableBaseMSM}; +use crate::msm::VariableBaseMSM; use crate::poly::unipoly::UniPoly; use crate::utils::errors::ProofVerifyError; use ark_ec::scalar_mul::fixed_base::FixedBase; @@ -118,7 +118,6 @@ pub struct UnivariateKZG { impl UnivariateKZG

where

::ScalarField: JoltField, -

::G1: Icicle, { #[tracing::instrument(skip_all, name = "KZG::commit_offset")] pub fn commit_offset( From 90bba10278a8fb86fb035b792d61af33b218fb74 Mon Sep 17 00:00:00 2001 From: Michael Zhu Date: Fri, 19 Jul 2024 15:18:02 -0400 Subject: [PATCH 43/43] Address comments --- .../instruction/virtual_assert_valid_div0.rs | 8 ++--- .../virtual_assert_valid_signed_remainder.rs | 2 +- .../{right_is_ones.rs => div_by_zero.rs} | 29 ++++++++++--------- jolt-core/src/jolt/subtable/mod.rs | 2 +- jolt-core/src/jolt/vm/rv32i_vm.rs | 4 +-- 5 files changed, 23 insertions(+), 22 deletions(-) rename jolt-core/src/jolt/subtable/{right_is_ones.rs => div_by_zero.rs} (57%) diff --git a/jolt-core/src/jolt/instruction/virtual_assert_valid_div0.rs b/jolt-core/src/jolt/instruction/virtual_assert_valid_div0.rs index b72577412..abd80663a 100644 --- a/jolt-core/src/jolt/instruction/virtual_assert_valid_div0.rs +++ b/jolt-core/src/jolt/instruction/virtual_assert_valid_div0.rs @@ -1,6 +1,6 @@ use crate::{ field::JoltField, - jolt::subtable::{left_is_zero::LeftIsZeroSubtable, right_is_ones::RightIsOnesSubtable}, + jolt::subtable::{div_by_zero::DivByZeroSubtable, left_is_zero::LeftIsZeroSubtable}, }; use rand::prelude::StdRng; use rand::RngCore; @@ -24,9 +24,9 @@ impl JoltInstruction for AssertValidDiv0Instruction(&self, vals: &[F], C: usize, M: usize) -> F { let vals_by_subtable = self.slice_values(vals, C, M); let divisor_is_zero: F = vals_by_subtable[0].iter().product(); - let quotient_is_ones: F = vals_by_subtable[1].iter().product(); + let is_valid_div_by_zero: F = vals_by_subtable[1].iter().product(); - F::one() - divisor_is_zero + divisor_is_zero * quotient_is_ones + F::one() - divisor_is_zero + is_valid_div_by_zero } fn g_poly_degree(&self, C: usize) -> usize { @@ -44,7 +44,7 @@ impl JoltInstruction for AssertValidDiv0Instruction JoltInstruction for AssertValidSignedRemainderInstr } fn g_poly_degree(&self, C: usize) -> usize { - C + 1 + C + 2 } fn subtables( diff --git a/jolt-core/src/jolt/subtable/right_is_ones.rs b/jolt-core/src/jolt/subtable/div_by_zero.rs similarity index 57% rename from jolt-core/src/jolt/subtable/right_is_ones.rs rename to jolt-core/src/jolt/subtable/div_by_zero.rs index 18607df50..95532bf86 100644 --- a/jolt-core/src/jolt/subtable/right_is_ones.rs +++ b/jolt-core/src/jolt/subtable/div_by_zero.rs @@ -1,15 +1,15 @@ -use crate::field::JoltField; +use crate::{field::JoltField, utils::split_bits}; use ark_std::log2; use std::marker::PhantomData; use super::LassoSubtable; #[derive(Default)] -pub struct RightIsOnesSubtable { +pub struct DivByZeroSubtable { _field: PhantomData, } -impl RightIsOnesSubtable { +impl DivByZeroSubtable { pub fn new() -> Self { Self { _field: PhantomData, @@ -17,13 +17,14 @@ impl RightIsOnesSubtable { } } -impl LassoSubtable for RightIsOnesSubtable { +impl LassoSubtable for DivByZeroSubtable { fn materialize(&self, M: usize) -> Vec { let mut entries: Vec = vec![F::zero(); M]; - let right_operand_bits = (1 << (log2(M) / 2)) - 1; + let bits_per_operand = (log2(M) / 2) as usize; for idx in 0..M { - if (idx & right_operand_bits) == right_operand_bits { + let (x, y) = split_bits(idx, bits_per_operand); + if x == 0 && (y == (1 << bits_per_operand) - 1) { entries[idx] = F::one(); } } @@ -32,14 +33,14 @@ impl LassoSubtable for RightIsOnesSubtable { } fn evaluate_mle(&self, point: &[F]) -> F { - // \prod_i y_i + // \prod_i (1 - x_i) * y_i debug_assert!(point.len() % 2 == 0); let b = point.len() / 2; - let (_, y) = point.split_at(b); + let (x, y) = point.split_at(b); let mut result = F::one(); for i in 0..b { - result *= y[i]; + result *= (F::one() - x[i]) * y[i]; } result } @@ -52,19 +53,19 @@ mod test { use crate::{ field::binius::BiniusField, - jolt::subtable::{right_is_ones::RightIsOnesSubtable, LassoSubtable}, + jolt::subtable::{div_by_zero::DivByZeroSubtable, LassoSubtable}, subtable_materialize_mle_parity_test, }; subtable_materialize_mle_parity_test!( - right_is_ones_materialize_mle_parity, - RightIsOnesSubtable, + div_by_zero_materialize_mle_parity, + DivByZeroSubtable, Fr, 256 ); subtable_materialize_mle_parity_test!( - right_is_ones_binius_materialize_mle_parity, - RightIsOnesSubtable>, + div_by_zero_binius_materialize_mle_parity, + DivByZeroSubtable>, BiniusField, 1 << 16 ); diff --git a/jolt-core/src/jolt/subtable/mod.rs b/jolt-core/src/jolt/subtable/mod.rs index d5c43a97e..977f9b436 100644 --- a/jolt-core/src/jolt/subtable/mod.rs +++ b/jolt-core/src/jolt/subtable/mod.rs @@ -30,6 +30,7 @@ pub trait JoltSubtableSet: } pub mod and; +pub mod div_by_zero; pub mod eq; pub mod eq_abs; pub mod identity; @@ -38,7 +39,6 @@ pub mod left_msb; pub mod lt_abs; pub mod ltu; pub mod or; -pub mod right_is_ones; pub mod right_is_zero; pub mod right_msb; pub mod sign_extend; diff --git a/jolt-core/src/jolt/vm/rv32i_vm.rs b/jolt-core/src/jolt/vm/rv32i_vm.rs index a93ccccd6..e85147fc9 100644 --- a/jolt-core/src/jolt/vm/rv32i_vm.rs +++ b/jolt-core/src/jolt/vm/rv32i_vm.rs @@ -1,7 +1,7 @@ use crate::field::JoltField; use crate::jolt::instruction::virtual_assert_valid_div0::AssertValidDiv0Instruction; use crate::jolt::instruction::virtual_assert_valid_unsigned_remainder::AssertValidUnsignedRemainderInstruction; -use crate::jolt::subtable::right_is_ones::RightIsOnesSubtable; +use crate::jolt::subtable::div_by_zero::DivByZeroSubtable; use crate::jolt::subtable::right_is_zero::RightIsZeroSubtable; use enum_dispatch::enum_dispatch; use rand::{prelude::StdRng, RngCore}; @@ -146,7 +146,7 @@ subtable_enum!( XOR: XorSubtable, LEFT_IS_ZERO: LeftIsZeroSubtable, RIGHT_IS_ZERO: RightIsZeroSubtable, - RIGHT_IS_ONES: RightIsOnesSubtable + DIV_BY_ZERO: DivByZeroSubtable ); // ==================== JOLT ====================