diff --git a/Cargo.lock b/Cargo.lock index 8295764350..1b1a7be893 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1983,6 +1983,7 @@ dependencies = [ "log", "mina-curves", "mina-poseidon", + "num-bigint", "o1-utils", "os_pipe", "poly-commitment", diff --git a/o1vm/Cargo.toml b/o1vm/Cargo.toml index 1e57ce7c0d..20e19349c8 100644 --- a/o1vm/Cargo.toml +++ b/o1vm/Cargo.toml @@ -48,6 +48,7 @@ libflate.workspace = true log.workspace = true mina-curves.workspace = true mina-poseidon.workspace = true +num-bigint.workspace = true o1-utils.workspace = true os_pipe.workspace = true poly-commitment.workspace = true diff --git a/o1vm/src/interpreters/mips/tests_helpers.rs b/o1vm/src/interpreters/mips/tests_helpers.rs index 1682196588..ba3e096316 100644 --- a/o1vm/src/interpreters/mips/tests_helpers.rs +++ b/o1vm/src/interpreters/mips/tests_helpers.rs @@ -7,14 +7,14 @@ use crate::{ }, preimage_oracle::PreImageOracleT, }; +use ark_ff::Zero; +use num_bigint::BigUint; use rand::{CryptoRng, Rng, RngCore}; use std::{fs, path::PathBuf}; // FIXME: we should parametrize the tests with different fields. use ark_bn254::Fr as Fp; -use super::column::{SCRATCH_SIZE, SCRATCH_SIZE_INVERSE}; - const PAGE_INDEX_EXECUTABLE_MEMORY: u32 = 1; pub(crate) struct OnDiskPreImageOracle; @@ -90,8 +90,8 @@ where registers_write_index: Registers::default(), scratch_state_idx: 0, scratch_state_idx_inverse: 0, - scratch_state: [Fp::from(0); SCRATCH_SIZE], - scratch_state_inverse: [Fp::from(0); SCRATCH_SIZE_INVERSE], + scratch_state: std::array::from_fn(|_| BigUint::zero()), + scratch_state_inverse: std::array::from_fn(|_| BigUint::zero()), selector: crate::interpreters::mips::column::N_MIPS_SEL_COLS, halt: false, // Keccak related diff --git a/o1vm/src/interpreters/mips/witness.rs b/o1vm/src/interpreters/mips/witness.rs index 991b946c8d..48e32f30d1 100644 --- a/o1vm/src/interpreters/mips/witness.rs +++ b/o1vm/src/interpreters/mips/witness.rs @@ -24,10 +24,11 @@ use crate::{ preimage_oracle::PreImageOracleT, utils::memory_size, }; -use ark_ff::Field; +use ark_ff::{PrimeField, Zero}; use core::panic; -use kimchi::o1_utils::Two; use log::{debug, info}; +use num_bigint::BigUint; +use o1_utils::FieldHelpers; use std::{ array, fs::File, @@ -69,7 +70,7 @@ impl SyscallEnv { /// machine has access to its internal state and some external memory. In /// addition to that, it has access to the environment of the Keccak interpreter /// that is used to verify the preimage requested during the execution. -pub struct Env { +pub struct Env { pub instruction_counter: u64, pub memory: Vec<(u32, Vec)>, pub last_memory_accesses: [usize; 3], @@ -79,8 +80,8 @@ pub struct Env { pub registers_write_index: Registers, pub scratch_state_idx: usize, pub scratch_state_idx_inverse: usize, - pub scratch_state: [Fp; SCRATCH_SIZE], - pub scratch_state_inverse: [Fp; SCRATCH_SIZE_INVERSE], + pub scratch_state: [BigUint; SCRATCH_SIZE], + pub scratch_state_inverse: [BigUint; SCRATCH_SIZE_INVERSE], pub halt: bool, pub syscall_env: SyscallEnv, pub selector: usize, @@ -92,11 +93,11 @@ pub struct Env { pub hash_counter: u64, } -fn fresh_scratch_state() -> [Fp; N] { - array::from_fn(|_| Fp::zero()) +fn fresh_scratch_state() -> [BigUint; N] { + array::from_fn(|_| BigUint::zero()) } -impl InterpreterEnv for Env { +impl InterpreterEnv for Env { type Position = Column; fn alloc_scratch(&mut self) -> Self::Position { @@ -325,11 +326,7 @@ impl InterpreterEnv for Env InterpreterEnv for Env Self::Variable { // We replicate is_zero(x-y), but working on field elt, // to avoid subtraction overflow in the witness interpreter for u32 - let to_zero_test = Fp::from(*x) - Fp::from(*y); let res = { let pos = self.alloc_scratch(); - let is_zero: u64 = if to_zero_test == Fp::zero() { 1 } else { 0 }; + let is_zero: u64 = if x == y { 1 } else { 0 }; self.write_column(pos, is_zero); is_zero }; let pos = self.alloc_scratch_inverse(); - if to_zero_test == Fp::zero() { - self.write_field_column(pos, Fp::zero()); + if x > y { + let res = BigUint::from(x - y); + self.write_biguint_column(pos, res); } else { - self.write_field_column(pos, to_zero_test); - }; + let res = Fp::modulus_biguint().clone() - BigUint::from(y - x); + self.write_biguint_column(pos, res) + } res } @@ -739,10 +737,10 @@ impl InterpreterEnv for Env::new( @@ -819,7 +817,7 @@ impl InterpreterEnv for Env Env { +impl Env { pub fn create(page_size: usize, state: State, preimage_oracle: PreImageOracle) -> Self { let initial_instruction_pointer = state.pc; let next_instruction_pointer = state.next_pc; @@ -906,10 +904,10 @@ impl Env { } pub fn write_column(&mut self, column: Column, value: u64) { - self.write_field_column(column, value.into()) + self.write_biguint_column(column, value.into()) } - pub fn write_field_column(&mut self, column: Column, value: Fp) { + pub fn write_biguint_column(&mut self, column: Column, value: BigUint) { match column { Column::ScratchState(idx) => self.scratch_state[idx] = value, Column::ScratchStateInverse(idx) => self.scratch_state_inverse[idx] = value, diff --git a/o1vm/src/legacy/main.rs b/o1vm/src/legacy/main.rs index 749f5722b6..da7e25f295 100644 --- a/o1vm/src/legacy/main.rs +++ b/o1vm/src/legacy/main.rs @@ -159,7 +159,7 @@ pub fn main() -> ExitCode { for i in 0..N_MIPS_REL_COLS { match i.cmp(&SCRATCH_SIZE) { Ordering::Less => mips_trace.trace.get_mut(&instr).unwrap().witness.cols[i] - .push(mips_wit_env.scratch_state[i]), + .push(mips_wit_env.scratch_state[i].clone().into()), Ordering::Equal => mips_trace.trace.get_mut(&instr).unwrap().witness.cols[i] .push(Fp::from(mips_wit_env.instruction_counter)), Ordering::Greater => { diff --git a/o1vm/src/pickles/main.rs b/o1vm/src/pickles/main.rs index 5083d7d58d..e273d4e022 100644 --- a/o1vm/src/pickles/main.rs +++ b/o1vm/src/pickles/main.rs @@ -1,4 +1,3 @@ -use ark_ff::UniformRand; use kimchi::circuits::domains::EvaluationDomains; use kimchi_msm::expr::E; use log::debug; @@ -7,6 +6,7 @@ use mina_poseidon::{ constants::PlonkSpongeConstantsKimchi, sponge::{DefaultFqSponge, DefaultFrSponge}, }; +use num_bigint::BigUint; use o1vm::{ cannon::{self, Meta, Start, State}, cannon_cli, @@ -95,7 +95,7 @@ pub fn main() -> ExitCode { constraints }; - let mut curr_proof_inputs: ProofInputs = ProofInputs::new(DOMAIN_SIZE); + let mut curr_proof_inputs: ProofInputs = ProofInputs::new(DOMAIN_SIZE); while !mips_wit_env.halt { let _instr: Instruction = mips_wit_env.step(&configuration, &meta, &start); for (scratch, scratch_chunk) in mips_wit_env @@ -103,26 +103,28 @@ pub fn main() -> ExitCode { .iter() .zip(curr_proof_inputs.evaluations.scratch.iter_mut()) { - scratch_chunk.push(*scratch); + scratch_chunk.push(scratch.clone()); } for (scratch, scratch_chunk) in mips_wit_env .scratch_state_inverse .iter() .zip(curr_proof_inputs.evaluations.scratch_inverse.iter_mut()) { - scratch_chunk.push(*scratch); + scratch_chunk.push(scratch.clone()); } curr_proof_inputs .evaluations .instruction_counter - .push(Fp::from(mips_wit_env.instruction_counter)); + .push(BigUint::from(mips_wit_env.instruction_counter)); // FIXME: Might be another value - curr_proof_inputs.evaluations.error.push(Fp::rand(&mut rng)); - curr_proof_inputs .evaluations - .selector - .push(Fp::from((mips_wit_env.selector - N_MIPS_REL_COLS) as u64)); + .error + .push(BigUint::from(42_u32)); + + curr_proof_inputs.evaluations.selector.push(BigUint::from( + (mips_wit_env.selector - N_MIPS_REL_COLS) as u64, + )); if curr_proof_inputs.evaluations.instruction_counter.len() == DOMAIN_SIZE { // FIXME diff --git a/o1vm/src/pickles/proof.rs b/o1vm/src/pickles/proof.rs index 40529a3409..14854f620e 100644 --- a/o1vm/src/pickles/proof.rs +++ b/o1vm/src/pickles/proof.rs @@ -1,4 +1,5 @@ use kimchi::{curve::KimchiCurve, proof::PointEvaluations}; +use num_bigint::BigUint; use poly_commitment::{ipa::OpeningProof, PolyComm}; use crate::interpreters::mips::column::{N_MIPS_SEL_COLS, SCRATCH_SIZE, SCRATCH_SIZE_INVERSE}; @@ -11,11 +12,11 @@ pub struct WitnessColumns { pub selector: S, } -pub struct ProofInputs { - pub evaluations: WitnessColumns, Vec>, +pub struct ProofInputs { + pub evaluations: WitnessColumns, Vec>, } -impl ProofInputs { +impl ProofInputs { pub fn new(domain_size: usize) -> Self { ProofInputs { evaluations: WitnessColumns { diff --git a/o1vm/src/pickles/prover.rs b/o1vm/src/pickles/prover.rs index dc0ac2dd08..0a3cb07b59 100644 --- a/o1vm/src/pickles/prover.rs +++ b/o1vm/src/pickles/prover.rs @@ -15,7 +15,8 @@ use kimchi::{ }; use log::debug; use mina_poseidon::{sponge::ScalarChallenge, FqSponge}; -use o1_utils::ExtendedDensePolynomial; +use num_bigint::BigUint; +use o1_utils::{ExtendedDensePolynomial, FieldHelpers}; use poly_commitment::{ commitment::{absorb_commitment, PolyComm}, ipa::{DensePolynomialOrEvaluations, OpeningProof, SRS}, @@ -59,7 +60,7 @@ pub fn prove< >( domain: EvaluationDomains, srs: &SRS, - inputs: ProofInputs, + inputs: ProofInputs, constraints: &[E], rng: &mut RNG, ) -> Result, ProverError> @@ -93,19 +94,23 @@ where let domain_size = domain.d1.size as usize; // Build the selectors - let selector: [Vec; N_MIPS_SEL_COLS] = array::from_fn(|i| { + let selector: [Vec; N_MIPS_SEL_COLS] = array::from_fn(|i| { let mut s_i = Vec::with_capacity(domain_size); for s in &selector { - s_i.push(if G::ScalarField::from(i as u64) == *s { - G::ScalarField::one() + s_i.push(if BigUint::from(i as u64) == *s { + BigUint::one() } else { - G::ScalarField::zero() + BigUint::zero() }) } s_i }); - let eval_col = |evals: Vec| { + let eval_col = |evals: Vec| { + let evals: Vec = evals + .into_par_iter() + .map(|x| G::ScalarField::from_biguint(&x).unwrap()) + .collect(); Evaluations::>::from_vec_and_domain(evals, domain.d1) .interpolate() }; @@ -113,9 +118,16 @@ where let scratch = scratch.into_par_iter().map(eval_col).collect::>(); let scratch_inverse = scratch_inverse .into_par_iter() - .map(|mut evals| { + .map(|evals| { + let mut evals: Vec = evals + .into_par_iter() + .map(|x| G::ScalarField::from_biguint(&x).unwrap()) + .collect(); ark_ff::batch_inversion(&mut evals); - eval_col(evals) + Evaluations::>::from_vec_and_domain( + evals, domain.d1, + ) + .interpolate() }) .collect::>(); let selector = selector.into_par_iter().map(eval_col).collect::>(); diff --git a/o1vm/src/pickles/tests.rs b/o1vm/src/pickles/tests.rs index b4bb102dc7..ba2128055b 100644 --- a/o1vm/src/pickles/tests.rs +++ b/o1vm/src/pickles/tests.rs @@ -23,6 +23,7 @@ use mina_poseidon::{ constants::PlonkSpongeConstantsKimchi, sponge::{DefaultFqSponge, DefaultFrSponge}, }; +use num_bigint::BigUint; use o1_utils::tests::make_test_rng; use poly_commitment::SRS; use strum::IntoEnumIterator; @@ -55,24 +56,24 @@ fn test_regression_constraints_with_selectors() { assert_eq!(max_degree, MAXIMUM_DEGREE_CONSTRAINTS); } -fn zero_to_n_minus_one(n: usize) -> Vec { - (0..n).map(|i| Fq::from((i) as u64)).collect() +fn zero_to_n_minus_one(n: usize) -> Vec { + (0..n).map(|i| BigUint::from((i) as u64)).collect() } #[test] fn test_small_circuit() { let domain = EvaluationDomains::::create(8).unwrap(); let srs = SRS::create(8); - let proof_input = ProofInputs:: { + let proof_input = ProofInputs { evaluations: WitnessColumns { scratch: std::array::from_fn(|_| zero_to_n_minus_one(8)), - scratch_inverse: std::array::from_fn(|_| (0..8).map(|_| Fq::zero()).collect()), + scratch_inverse: std::array::from_fn(|_| (0..8).map(|_| BigUint::zero()).collect()), instruction_counter: zero_to_n_minus_one(8) .into_iter() - .map(|x| x + Fq::one()) + .map(|x| x + BigUint::one()) .collect(), error: (0..8) - .map(|i| -Fq::from((i * SCRATCH_SIZE + (i + 1)) as u64)) + .map(|i| BigUint::from((i * SCRATCH_SIZE + (i + 1)) as u64)) .collect(), selector: zero_to_n_minus_one(8), },