From 41a1e1189e494679d9d980fd46b0fa8559aa7816 Mon Sep 17 00:00:00 2001 From: leopardracer <136604165+leopardracer@users.noreply.github.com> Date: Tue, 19 Nov 2024 17:58:49 +0200 Subject: [PATCH 001/165] Update gates.md --- book/src/kimchi/gates.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/src/kimchi/gates.md b/book/src/kimchi/gates.md index f15693eaa4..e09c3becb1 100644 --- a/book/src/kimchi/gates.md +++ b/book/src/kimchi/gates.md @@ -186,7 +186,7 @@ Finally, providing $q(X) = \text{gates}(X)/v_{\mathbb{G}}(X)$ and performing the _The prover knows a polynomial_ $\text{gates}(X)$ _that equals zero on any_ $x\in\{1,g,g^2,g^3\}$. -Nonetheless, it would still remain to verify that $\text{gates}(X)$ actually corresponds to the encoding of the actual constraints. Meaning, checking that this polynomial encodes the column witnesses, and the agreed circuit. So instead of providing just $\text{gates}(X)$ (actually, a commitment to it), the prover can send commitments to each of th $15$ witness polynomials, so that the verifier can reconstruct the huge constraint using the encodings of the circuit (which is known ahead). +Nonetheless, it would still remain to verify that $\text{gates}(X)$ actually corresponds to the encoding of the actual constraints. Meaning, checking that this polynomial encodes the column witnesses, and the agreed circuit. So instead of providing just $\text{gates}(X)$ (actually, a commitment to it), the prover can send commitments to each of the $15$ witness polynomials, so that the verifier can reconstruct the huge constraint using the encodings of the circuit (which is known ahead). From 8d7e831d4c8791656b92bc5802b1266e61c384d1 Mon Sep 17 00:00:00 2001 From: leopardracer <136604165+leopardracer@users.noreply.github.com> Date: Tue, 19 Nov 2024 18:15:18 +0200 Subject: [PATCH 002/165] Update lookup.md --- book/src/kimchi/lookup.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/src/kimchi/lookup.md b/book/src/kimchi/lookup.md index 7893d92121..c5ab58146e 100644 --- a/book/src/kimchi/lookup.md +++ b/book/src/kimchi/lookup.md @@ -217,7 +217,7 @@ The denominator thus becomes $\prod_{k=1}^{5} (\gamma (1+\beta) + s_{kn+i-1} + \ There are two things that we haven't touched on: -* The vector $t$ representing the **combined lookup table** (after its columns have been combined with a joint combiner $j$). The **non-combined loookup table** is fixed at setup time and derived based on the lookup tables used in the circuit. +* The vector $t$ representing the **combined lookup table** (after its columns have been combined with a joint combiner $j$). The **non-combined lookup table** is fixed at setup time and derived based on the lookup tables used in the circuit. * The vector $s$ representing the sorted multiset of both the queries and the lookup table. This is created by the prover and sent as commitment to the verifier. The first vector $t$ is quite straightforward to think about: From 0bcde57290ed10e75b6c381a23913c07f4731df4 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 20 Nov 2024 16:21:01 +0100 Subject: [PATCH 003/165] o1vm/riscv32: implement mul_hi_signed --- o1vm/src/interpreters/riscv32im/constraints.rs | 9 +++++++++ o1vm/src/interpreters/riscv32im/interpreter.rs | 14 ++++++++++++++ o1vm/src/interpreters/riscv32im/witness.rs | 15 +++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/o1vm/src/interpreters/riscv32im/constraints.rs b/o1vm/src/interpreters/riscv32im/constraints.rs index c8b7bec2c2..11dee8a230 100644 --- a/o1vm/src/interpreters/riscv32im/constraints.rs +++ b/o1vm/src/interpreters/riscv32im/constraints.rs @@ -327,6 +327,15 @@ impl InterpreterEnv for Env { (self.variable(position_hi), self.variable(position_lo)) } + unsafe fn mul_hi_signed( + &mut self, + _x: &Self::Variable, + _y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable { + self.variable(position) + } + unsafe fn mul_hi_lo( &mut self, _x: &Self::Variable, diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index 6eeaa28623..1e41918b20 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -1201,6 +1201,20 @@ pub trait InterpreterEnv { position: Self::Position, ) -> Self::Variable; + /// Returns `((x * y) >> 32`, storing the results in `position`. + /// + /// # Safety + /// + /// There are no constraints on the returned values; callers must manually add constraints to + /// ensure that the pair of returned values correspond to the given values `x` and `y`, and + /// that they fall within the desired range. + unsafe fn mul_hi_signed( + &mut self, + x: &Self::Variable, + y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable; + /// Returns `((x * y) >> 32, (x * y) & ((1 << 32) - 1))`, storing the results in `position_hi` /// and `position_lo` respectively. /// diff --git a/o1vm/src/interpreters/riscv32im/witness.rs b/o1vm/src/interpreters/riscv32im/witness.rs index 1fbe44552b..b0d2adccda 100644 --- a/o1vm/src/interpreters/riscv32im/witness.rs +++ b/o1vm/src/interpreters/riscv32im/witness.rs @@ -441,6 +441,21 @@ impl InterpreterEnv for Env { res } + unsafe fn mul_hi_signed( + &mut self, + x: &Self::Variable, + y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable { + let x: u32 = (*x).try_into().unwrap(); + let y: u32 = (*y).try_into().unwrap(); + let res = (((x as i32) as i64) * ((y as i32) as i64)) as u64; + let res = (res >> 32) as u32; + let res = res as u64; + self.write_column(position, res); + res + } + unsafe fn mul_hi_lo_signed( &mut self, x: &Self::Variable, From 3153e27e690113345a594393264d616b413ebe84 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 20 Nov 2024 16:22:33 +0100 Subject: [PATCH 004/165] o1vm/riscv32: implement mul_lo_signed --- o1vm/src/interpreters/riscv32im/constraints.rs | 9 +++++++++ o1vm/src/interpreters/riscv32im/interpreter.rs | 14 ++++++++++++++ o1vm/src/interpreters/riscv32im/witness.rs | 15 +++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/o1vm/src/interpreters/riscv32im/constraints.rs b/o1vm/src/interpreters/riscv32im/constraints.rs index 11dee8a230..82b9cd5105 100644 --- a/o1vm/src/interpreters/riscv32im/constraints.rs +++ b/o1vm/src/interpreters/riscv32im/constraints.rs @@ -336,6 +336,15 @@ impl InterpreterEnv for Env { self.variable(position) } + unsafe fn mul_lo_signed( + &mut self, + _x: &Self::Variable, + _y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable { + self.variable(position) + } + unsafe fn mul_hi_lo( &mut self, _x: &Self::Variable, diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index 1e41918b20..2cd83827a1 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -1215,6 +1215,20 @@ pub trait InterpreterEnv { position: Self::Position, ) -> Self::Variable; + /// Returns `(x * y) & ((1 << 32) - 1))`, storing the results in `position` + /// + /// # Safety + /// + /// There are no constraints on the returned values; callers must manually add constraints to + /// ensure that the pair of returned values correspond to the given values `x` and `y`, and + /// that they fall within the desired range. + unsafe fn mul_lo_signed( + &mut self, + x: &Self::Variable, + y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable; + /// Returns `((x * y) >> 32, (x * y) & ((1 << 32) - 1))`, storing the results in `position_hi` /// and `position_lo` respectively. /// diff --git a/o1vm/src/interpreters/riscv32im/witness.rs b/o1vm/src/interpreters/riscv32im/witness.rs index b0d2adccda..b122ff6a5b 100644 --- a/o1vm/src/interpreters/riscv32im/witness.rs +++ b/o1vm/src/interpreters/riscv32im/witness.rs @@ -456,6 +456,21 @@ impl InterpreterEnv for Env { res } + unsafe fn mul_lo_signed( + &mut self, + x: &Self::Variable, + y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable { + let x: u32 = (*x).try_into().unwrap(); + let y: u32 = (*y).try_into().unwrap(); + let res = (((x as i32) as i64) * ((y as i32) as i64)) as u64; + let res = (res & ((1 << 32) - 1)) as u32; + let res = res as u64; + self.write_column(position, res); + res + } + unsafe fn mul_hi_lo_signed( &mut self, x: &Self::Variable, From f707007fcb8567e8b97b8142e878314b6ebd2d20 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 20 Nov 2024 16:23:37 +0100 Subject: [PATCH 005/165] o1vm/riscv32: implement mul_hi --- o1vm/src/interpreters/riscv32im/constraints.rs | 9 +++++++++ o1vm/src/interpreters/riscv32im/interpreter.rs | 14 ++++++++++++++ o1vm/src/interpreters/riscv32im/witness.rs | 15 +++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/o1vm/src/interpreters/riscv32im/constraints.rs b/o1vm/src/interpreters/riscv32im/constraints.rs index 82b9cd5105..ef1496ae80 100644 --- a/o1vm/src/interpreters/riscv32im/constraints.rs +++ b/o1vm/src/interpreters/riscv32im/constraints.rs @@ -345,6 +345,15 @@ impl InterpreterEnv for Env { self.variable(position) } + unsafe fn mul_hi( + &mut self, + _x: &Self::Variable, + _y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable { + self.variable(position) + } + unsafe fn mul_hi_lo( &mut self, _x: &Self::Variable, diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index 2cd83827a1..905efe547f 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -1245,6 +1245,20 @@ pub trait InterpreterEnv { position_lo: Self::Position, ) -> (Self::Variable, Self::Variable); + /// Returns `((x * y) >> 32`, storing the results in `position`. + /// + /// # Safety + /// + /// There are no constraints on the returned values; callers must manually add constraints to + /// ensure that the pair of returned values correspond to the given values `x` and `y`, and + /// that they fall within the desired range. + unsafe fn mul_hi( + &mut self, + x: &Self::Variable, + y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable; + /// Returns `((x * y) >> 32, (x * y) & ((1 << 32) - 1))`, storing the results in `position_hi` /// and `position_lo` respectively. /// diff --git a/o1vm/src/interpreters/riscv32im/witness.rs b/o1vm/src/interpreters/riscv32im/witness.rs index b122ff6a5b..476684d289 100644 --- a/o1vm/src/interpreters/riscv32im/witness.rs +++ b/o1vm/src/interpreters/riscv32im/witness.rs @@ -490,6 +490,21 @@ impl InterpreterEnv for Env { (hi, lo) } + unsafe fn mul_hi( + &mut self, + x: &Self::Variable, + y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable { + let x: u32 = (*x).try_into().unwrap(); + let y: u32 = (*y).try_into().unwrap(); + let res = (x as u64) * (y as u64); + let res = (res >> 32) as u32; + let res = res as u64; + self.write_column(position, res); + res + } + unsafe fn mul_hi_lo( &mut self, x: &Self::Variable, From e0c1e8910b24ede4dd0120a714cbd2c6e776a93e Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 20 Nov 2024 16:26:54 +0100 Subject: [PATCH 006/165] o1vm/riscv32: implement M type instruction Mul --- o1vm/src/interpreters/riscv32im/interpreter.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index 905efe547f..da07859a8f 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -2075,7 +2075,7 @@ pub fn interpret_syscall(env: &mut Env, _instr: SyscallInst /// [here](https://www.cs.cornell.edu/courses/cs3410/2024fa/assignments/cpusim/riscv-instructions.pdf) pub fn interpret_mtype(env: &mut Env, instr: MInstruction) { let instruction_pointer = env.get_instruction_pointer(); - let _next_instruction_pointer = env.get_next_instruction_pointer(); + let next_instruction_pointer = env.get_next_instruction_pointer(); let instruction = { let v0 = env.read_memory(&instruction_pointer); @@ -2146,7 +2146,17 @@ pub fn interpret_mtype(env: &mut Env, instr: MInstruction) match instr { MInstruction::Mul => { - unimplemented!("Mul") + let rs1 = env.read_register(&rs1); + let rs2 = env.read_register(&rs2); + // FIXME: constrain + let res = { + let pos = env.alloc_scratch(); + unsafe { env.mul_lo_signed(&rs1, &rs2, pos) } + }; + env.write_register(&rd, res); + + env.set_instruction_pointer(next_instruction_pointer.clone()); + env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); } MInstruction::Mulh => { unimplemented!("Mulh") From 83aec4b125d176d58aacc5f9d4c2fb51e15a015b Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 20 Nov 2024 16:28:03 +0100 Subject: [PATCH 007/165] o1vm/riscv32: implement mulh --- o1vm/src/interpreters/riscv32im/interpreter.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index da07859a8f..44a2094a1c 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -2159,7 +2159,17 @@ pub fn interpret_mtype(env: &mut Env, instr: MInstruction) env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); } MInstruction::Mulh => { - unimplemented!("Mulh") + let rs1 = env.read_register(&rs1); + let rs2 = env.read_register(&rs2); + // FIXME: constrain + let res = { + let pos = env.alloc_scratch(); + unsafe { env.mul_hi_signed(&rs1, &rs2, pos) } + }; + env.write_register(&rd, res); + + env.set_instruction_pointer(next_instruction_pointer.clone()); + env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); } MInstruction::Mulhsu => { unimplemented!("Mulhsu") From d8c8311acdad558b060b0f7947bd3254820c51aa Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 20 Nov 2024 16:30:38 +0100 Subject: [PATCH 008/165] o1vm/riscv32: implement Mulhu --- o1vm/src/interpreters/riscv32im/interpreter.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index 44a2094a1c..eda089592a 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -2175,7 +2175,17 @@ pub fn interpret_mtype(env: &mut Env, instr: MInstruction) unimplemented!("Mulhsu") } MInstruction::Mulhu => { - unimplemented!("Mulhu") + let rs1 = env.read_register(&rs1); + let rs2 = env.read_register(&rs2); + // FIXME: constrain + let res = { + let pos = env.alloc_scratch(); + unsafe { env.mul_hi(&rs1, &rs2, pos) } + }; + env.write_register(&rd, res); + + env.set_instruction_pointer(next_instruction_pointer.clone()); + env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); } MInstruction::Div => { unimplemented!("Div") From 188b7c66978ad7a75c118eb7bf0a4432f8a172de Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 20 Nov 2024 16:34:33 +0100 Subject: [PATCH 009/165] o1vm/riscv32: remove unused mul_hi_lo_signed The method is splitted in two different methods, comparetively to MIPS. --- .../src/interpreters/riscv32im/constraints.rs | 10 ---------- .../src/interpreters/riscv32im/interpreter.rs | 16 ---------------- o1vm/src/interpreters/riscv32im/witness.rs | 19 ------------------- 3 files changed, 45 deletions(-) diff --git a/o1vm/src/interpreters/riscv32im/constraints.rs b/o1vm/src/interpreters/riscv32im/constraints.rs index ef1496ae80..bedb51f275 100644 --- a/o1vm/src/interpreters/riscv32im/constraints.rs +++ b/o1vm/src/interpreters/riscv32im/constraints.rs @@ -317,16 +317,6 @@ impl InterpreterEnv for Env { self.variable(position) } - unsafe fn mul_hi_lo_signed( - &mut self, - _x: &Self::Variable, - _y: &Self::Variable, - position_hi: Self::Position, - position_lo: Self::Position, - ) -> (Self::Variable, Self::Variable) { - (self.variable(position_hi), self.variable(position_lo)) - } - unsafe fn mul_hi_signed( &mut self, _x: &Self::Variable, diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index eda089592a..9be87df3d8 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -1229,22 +1229,6 @@ pub trait InterpreterEnv { position: Self::Position, ) -> Self::Variable; - /// Returns `((x * y) >> 32, (x * y) & ((1 << 32) - 1))`, storing the results in `position_hi` - /// and `position_lo` respectively. - /// - /// # Safety - /// - /// There are no constraints on the returned values; callers must manually add constraints to - /// ensure that the pair of returned values correspond to the given values `x` and `y`, and - /// that they fall within the desired range. - unsafe fn mul_hi_lo_signed( - &mut self, - x: &Self::Variable, - y: &Self::Variable, - position_hi: Self::Position, - position_lo: Self::Position, - ) -> (Self::Variable, Self::Variable); - /// Returns `((x * y) >> 32`, storing the results in `position`. /// /// # Safety diff --git a/o1vm/src/interpreters/riscv32im/witness.rs b/o1vm/src/interpreters/riscv32im/witness.rs index 476684d289..b567d7aba4 100644 --- a/o1vm/src/interpreters/riscv32im/witness.rs +++ b/o1vm/src/interpreters/riscv32im/witness.rs @@ -471,25 +471,6 @@ impl InterpreterEnv for Env { res } - unsafe fn mul_hi_lo_signed( - &mut self, - x: &Self::Variable, - y: &Self::Variable, - position_hi: Self::Position, - position_lo: Self::Position, - ) -> (Self::Variable, Self::Variable) { - let x: u32 = (*x).try_into().unwrap(); - let y: u32 = (*y).try_into().unwrap(); - let mul = (((x as i32) as i64) * ((y as i32) as i64)) as u64; - let hi = (mul >> 32) as u32; - let lo = (mul & ((1 << 32) - 1)) as u32; - let hi = hi as u64; - let lo = lo as u64; - self.write_column(position_hi, hi); - self.write_column(position_lo, lo); - (hi, lo) - } - unsafe fn mul_hi( &mut self, x: &Self::Variable, From 9a8de6323398844db5401780f004aec7071d11cf Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 20 Nov 2024 16:36:28 +0100 Subject: [PATCH 010/165] o1vm/riscv32: remove unused mul_hi_lo. Like mul_hi_lo_signed, the method is splitted in two different methods: mul_hi and mul_lo. --- .../src/interpreters/riscv32im/constraints.rs | 10 ---------- .../src/interpreters/riscv32im/interpreter.rs | 16 ---------------- o1vm/src/interpreters/riscv32im/witness.rs | 19 ------------------- 3 files changed, 45 deletions(-) diff --git a/o1vm/src/interpreters/riscv32im/constraints.rs b/o1vm/src/interpreters/riscv32im/constraints.rs index bedb51f275..cc46e96b67 100644 --- a/o1vm/src/interpreters/riscv32im/constraints.rs +++ b/o1vm/src/interpreters/riscv32im/constraints.rs @@ -344,16 +344,6 @@ impl InterpreterEnv for Env { self.variable(position) } - unsafe fn mul_hi_lo( - &mut self, - _x: &Self::Variable, - _y: &Self::Variable, - position_hi: Self::Position, - position_lo: Self::Position, - ) -> (Self::Variable, Self::Variable) { - (self.variable(position_hi), self.variable(position_lo)) - } - unsafe fn divmod_signed( &mut self, _x: &Self::Variable, diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index 9be87df3d8..b1ad6418ab 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -1243,22 +1243,6 @@ pub trait InterpreterEnv { position: Self::Position, ) -> Self::Variable; - /// Returns `((x * y) >> 32, (x * y) & ((1 << 32) - 1))`, storing the results in `position_hi` - /// and `position_lo` respectively. - /// - /// # Safety - /// - /// There are no constraints on the returned values; callers must manually add constraints to - /// ensure that the pair of returned values correspond to the given values `x` and `y`, and - /// that they fall within the desired range. - unsafe fn mul_hi_lo( - &mut self, - x: &Self::Variable, - y: &Self::Variable, - position_hi: Self::Position, - position_lo: Self::Position, - ) -> (Self::Variable, Self::Variable); - /// Returns `(x / y, x % y)`, storing the results in `position_quotient` and /// `position_remainder` respectively. /// diff --git a/o1vm/src/interpreters/riscv32im/witness.rs b/o1vm/src/interpreters/riscv32im/witness.rs index b567d7aba4..29163ce038 100644 --- a/o1vm/src/interpreters/riscv32im/witness.rs +++ b/o1vm/src/interpreters/riscv32im/witness.rs @@ -486,25 +486,6 @@ impl InterpreterEnv for Env { res } - unsafe fn mul_hi_lo( - &mut self, - x: &Self::Variable, - y: &Self::Variable, - position_hi: Self::Position, - position_lo: Self::Position, - ) -> (Self::Variable, Self::Variable) { - let x: u32 = (*x).try_into().unwrap(); - let y: u32 = (*y).try_into().unwrap(); - let mul = (x as u64) * (y as u64); - let hi = (mul >> 32) as u32; - let lo = (mul & ((1 << 32) - 1)) as u32; - let hi = hi as u64; - let lo = lo as u64; - self.write_column(position_hi, hi); - self.write_column(position_lo, lo); - (hi, lo) - } - unsafe fn divmod_signed( &mut self, x: &Self::Variable, From 250bce5861e0278ecc4a65a7173d023095367a2a Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 20 Nov 2024 16:42:28 +0100 Subject: [PATCH 011/165] o1vm/riscv32: implement div_signed --- o1vm/src/interpreters/riscv32im/constraints.rs | 9 +++++++++ o1vm/src/interpreters/riscv32im/interpreter.rs | 14 ++++++++++++++ o1vm/src/interpreters/riscv32im/witness.rs | 14 ++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/o1vm/src/interpreters/riscv32im/constraints.rs b/o1vm/src/interpreters/riscv32im/constraints.rs index cc46e96b67..14799e2aed 100644 --- a/o1vm/src/interpreters/riscv32im/constraints.rs +++ b/o1vm/src/interpreters/riscv32im/constraints.rs @@ -344,6 +344,15 @@ impl InterpreterEnv for Env { self.variable(position) } + unsafe fn div_signed( + &mut self, + _x: &Self::Variable, + _y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable { + self.variable(position) + } + unsafe fn divmod_signed( &mut self, _x: &Self::Variable, diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index b1ad6418ab..61a7ecb15c 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -1243,6 +1243,20 @@ pub trait InterpreterEnv { position: Self::Position, ) -> Self::Variable; + /// Returns `x / y`, storing the results in `position`. + /// + /// # Safety + /// + /// There are no constraints on the returned values; callers must manually add constraints to + /// ensure that the pair of returned values correspond to the given values `x` and `y`, and + /// that they fall within the desired range. + unsafe fn div_signed( + &mut self, + x: &Self::Variable, + y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable; + /// Returns `(x / y, x % y)`, storing the results in `position_quotient` and /// `position_remainder` respectively. /// diff --git a/o1vm/src/interpreters/riscv32im/witness.rs b/o1vm/src/interpreters/riscv32im/witness.rs index 29163ce038..cc940c0612 100644 --- a/o1vm/src/interpreters/riscv32im/witness.rs +++ b/o1vm/src/interpreters/riscv32im/witness.rs @@ -486,6 +486,20 @@ impl InterpreterEnv for Env { res } + unsafe fn div_signed( + &mut self, + x: &Self::Variable, + y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable { + let x: u32 = (*x).try_into().unwrap(); + let y: u32 = (*y).try_into().unwrap(); + let res = ((x as i32) / (y as i32)) as u32; + let res = res as u64; + self.write_column(position, res); + res + } + unsafe fn divmod_signed( &mut self, x: &Self::Variable, From 2340ce1ab370b7bf254ef98d506eedc1d29140aa Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 20 Nov 2024 16:43:33 +0100 Subject: [PATCH 012/165] o1vm/riscv32: implement M type instruction div --- o1vm/src/interpreters/riscv32im/interpreter.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index 61a7ecb15c..11090b0e86 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -2170,7 +2170,17 @@ pub fn interpret_mtype(env: &mut Env, instr: MInstruction) env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); } MInstruction::Div => { - unimplemented!("Div") + let rs1 = env.read_register(&rs1); + let rs2 = env.read_register(&rs2); + // FIXME: constrain + let res = { + let pos = env.alloc_scratch(); + unsafe { env.div_signed(&rs1, &rs2, pos) } + }; + env.write_register(&rd, res); + + env.set_instruction_pointer(next_instruction_pointer.clone()); + env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); } MInstruction::Divu => { unimplemented!("Divu") From 8f304aa2245a23e07ea38e3aced209c4532fa2a2 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 20 Nov 2024 16:47:06 +0100 Subject: [PATCH 013/165] o1vm/riscv32: implement mod_signed It will be used to implement MInstruction::Rem in a follow-up PR. --- o1vm/src/interpreters/riscv32im/constraints.rs | 9 +++++++++ o1vm/src/interpreters/riscv32im/interpreter.rs | 14 ++++++++++++++ o1vm/src/interpreters/riscv32im/witness.rs | 14 ++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/o1vm/src/interpreters/riscv32im/constraints.rs b/o1vm/src/interpreters/riscv32im/constraints.rs index 14799e2aed..0b672e2675 100644 --- a/o1vm/src/interpreters/riscv32im/constraints.rs +++ b/o1vm/src/interpreters/riscv32im/constraints.rs @@ -353,6 +353,15 @@ impl InterpreterEnv for Env { self.variable(position) } + unsafe fn mod_signed( + &mut self, + _x: &Self::Variable, + _y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable { + self.variable(position) + } + unsafe fn divmod_signed( &mut self, _x: &Self::Variable, diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index 11090b0e86..7762d921fc 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -1257,6 +1257,20 @@ pub trait InterpreterEnv { position: Self::Position, ) -> Self::Variable; + /// Returns `x % y`, storing the results in `position`. + /// + /// # Safety + /// + /// There are no constraints on the returned values; callers must manually add constraints to + /// ensure that the pair of returned values correspond to the given values `x` and `y`, and + /// that they fall within the desired range. + unsafe fn mod_signed( + &mut self, + x: &Self::Variable, + y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable; + /// Returns `(x / y, x % y)`, storing the results in `position_quotient` and /// `position_remainder` respectively. /// diff --git a/o1vm/src/interpreters/riscv32im/witness.rs b/o1vm/src/interpreters/riscv32im/witness.rs index cc940c0612..3173192157 100644 --- a/o1vm/src/interpreters/riscv32im/witness.rs +++ b/o1vm/src/interpreters/riscv32im/witness.rs @@ -500,6 +500,20 @@ impl InterpreterEnv for Env { res } + unsafe fn mod_signed( + &mut self, + x: &Self::Variable, + y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable { + let x: u32 = (*x).try_into().unwrap(); + let y: u32 = (*y).try_into().unwrap(); + let res = ((x as i32) % (y as i32)) as u32; + let res = res as u64; + self.write_column(position, res); + res + } + unsafe fn divmod_signed( &mut self, x: &Self::Variable, From de7f623ba21e3618d1ee6a0bac34059c5c71441a Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 20 Nov 2024 16:49:00 +0100 Subject: [PATCH 014/165] o1vm/riscv32: remove unused divmod_signed As for mul_hi_lo(_signed), the method is splitted. --- o1vm/src/interpreters/riscv32im/constraints.rs | 13 ------------- o1vm/src/interpreters/riscv32im/interpreter.rs | 16 ---------------- o1vm/src/interpreters/riscv32im/witness.rs | 18 ------------------ 3 files changed, 47 deletions(-) diff --git a/o1vm/src/interpreters/riscv32im/constraints.rs b/o1vm/src/interpreters/riscv32im/constraints.rs index 0b672e2675..d414d3dfee 100644 --- a/o1vm/src/interpreters/riscv32im/constraints.rs +++ b/o1vm/src/interpreters/riscv32im/constraints.rs @@ -362,19 +362,6 @@ impl InterpreterEnv for Env { self.variable(position) } - unsafe fn divmod_signed( - &mut self, - _x: &Self::Variable, - _y: &Self::Variable, - position_quotient: Self::Position, - position_remainder: Self::Position, - ) -> (Self::Variable, Self::Variable) { - ( - self.variable(position_quotient), - self.variable(position_remainder), - ) - } - unsafe fn divmod( &mut self, _x: &Self::Variable, diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index 7762d921fc..5df1050c8d 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -1271,22 +1271,6 @@ pub trait InterpreterEnv { position: Self::Position, ) -> Self::Variable; - /// Returns `(x / y, x % y)`, storing the results in `position_quotient` and - /// `position_remainder` respectively. - /// - /// # Safety - /// - /// There are no constraints on the returned values; callers must manually add constraints to - /// ensure that the pair of returned values correspond to the given values `x` and `y`, and - /// that they fall within the desired range. - unsafe fn divmod_signed( - &mut self, - x: &Self::Variable, - y: &Self::Variable, - position_quotient: Self::Position, - position_remainder: Self::Position, - ) -> (Self::Variable, Self::Variable); - /// Returns `(x / y, x % y)`, storing the results in `position_quotient` and /// `position_remainder` respectively. /// diff --git a/o1vm/src/interpreters/riscv32im/witness.rs b/o1vm/src/interpreters/riscv32im/witness.rs index 3173192157..cf1ab12fa5 100644 --- a/o1vm/src/interpreters/riscv32im/witness.rs +++ b/o1vm/src/interpreters/riscv32im/witness.rs @@ -514,24 +514,6 @@ impl InterpreterEnv for Env { res } - unsafe fn divmod_signed( - &mut self, - x: &Self::Variable, - y: &Self::Variable, - position_quotient: Self::Position, - position_remainder: Self::Position, - ) -> (Self::Variable, Self::Variable) { - let x: u32 = (*x).try_into().unwrap(); - let y: u32 = (*y).try_into().unwrap(); - let q = ((x as i32) / (y as i32)) as u32; - let r = ((x as i32) % (y as i32)) as u32; - let q = q as u64; - let r = r as u64; - self.write_column(position_quotient, q); - self.write_column(position_remainder, r); - (q, r) - } - unsafe fn divmod( &mut self, x: &Self::Variable, From eaafc714bf679d2d1c6fcad7c16d3e189c0c4836 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 20 Nov 2024 16:51:28 +0100 Subject: [PATCH 015/165] o1vm/riscv32: implement M type instruction Rem --- o1vm/src/interpreters/riscv32im/interpreter.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index 5df1050c8d..855d70ba09 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -2184,7 +2184,17 @@ pub fn interpret_mtype(env: &mut Env, instr: MInstruction) unimplemented!("Divu") } MInstruction::Rem => { - unimplemented!("Rem") + let rs1 = env.read_register(&rs1); + let rs2 = env.read_register(&rs2); + // FIXME: constrain + let res = { + let pos = env.alloc_scratch(); + unsafe { env.mod_signed(&rs1, &rs2, pos) } + }; + env.write_register(&rd, res); + + env.set_instruction_pointer(next_instruction_pointer.clone()); + env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); } MInstruction::Remu => { unimplemented!("Remu") From 124d8be36023f95fdd64e0d00897b2a12e62b8ad Mon Sep 17 00:00:00 2001 From: Mikhail Volkhov Date: Wed, 20 Nov 2024 15:51:59 +0000 Subject: [PATCH 016/165] Rename xi into polyscale --- poly-commitment/src/commitment.rs | 14 +++++++------- poly-commitment/src/kzg.rs | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/poly-commitment/src/commitment.rs b/poly-commitment/src/commitment.rs index ba4d180134..f756e5b110 100644 --- a/poly-commitment/src/commitment.rs +++ b/poly-commitment/src/commitment.rs @@ -511,7 +511,7 @@ pub fn combined_inner_product( // final combined evaluation result let mut res = F::zero(); // polyscale^i - let mut xi_i = F::one(); + let mut polyscale_i = F::one(); for evals_tr in polys.iter().filter(|evals_tr| !evals_tr[0].is_empty()) { // Transpose the evaluations. @@ -523,7 +523,7 @@ pub fn combined_inner_product( // Iterating over the polynomial segments. // Each segment gets its own polyscale^i, each segment element j is multiplied by evalscale^j. - // Given that xi_i = polyscale^i0 at this point, after this loop we have: + // Given that polyscale_i = polyscale^i0 at this point, after this loop we have: // // res += Σ polyscale^{i0+i} ( Σ evals_tr[j][i] * evalscale^j ) // i j @@ -531,8 +531,8 @@ pub fn combined_inner_product( for eval in &evals { // p_i(evalscale) let term = DensePolynomial::::eval_polynomial(eval, *evalscale); - res += &(xi_i * term); - xi_i *= polyscale; + res += &(polyscale_i * term); + polyscale_i *= polyscale; } } res @@ -607,16 +607,16 @@ pub fn combine_commitments( rand_base: G::ScalarField, ) { // will contain the power of polyscale - let mut xi_i = G::ScalarField::one(); + let mut polyscale_i = G::ScalarField::one(); for Evaluation { commitment, .. } in evaluations.iter().filter(|x| !x.commitment.is_empty()) { // iterating over the polynomial segments for comm_ch in &commitment.chunks { - scalars.push(rand_base * xi_i); + scalars.push(rand_base * polyscale_i); points.push(*comm_ch); // compute next power of polyscale - xi_i *= polyscale; + polyscale_i *= polyscale; } } } diff --git a/poly-commitment/src/kzg.rs b/poly-commitment/src/kzg.rs index 9a448b4207..8d4d8ed7c6 100644 --- a/poly-commitment/src/kzg.rs +++ b/poly-commitment/src/kzg.rs @@ -55,7 +55,7 @@ pub fn combine_evaluations( evaluations: &Vec>, polyscale: G::ScalarField, ) -> Vec { - let mut xi_i = G::ScalarField::one(); + let mut polyscale_i = G::ScalarField::one(); let mut acc = { let num_evals = if !evaluations.is_empty() { evaluations[0].evaluations.len() @@ -74,9 +74,9 @@ pub fn combine_evaluations( for chunk_idx in 0..evaluations[0].len() { // supposes that all evaluations are of the same size for eval_pt_idx in 0..evaluations.len() { - acc[eval_pt_idx] += evaluations[eval_pt_idx][chunk_idx] * xi_i; + acc[eval_pt_idx] += evaluations[eval_pt_idx][chunk_idx] * polyscale_i; } - xi_i *= polyscale; + polyscale_i *= polyscale; } } From bad13ef58c5c55db4d9dff73408e4404b7c587ff Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 20 Nov 2024 16:55:11 +0100 Subject: [PATCH 017/165] o1vm/riscv32: implement div for unsigned 32bits Will be used to implement MInstruction::Divu --- o1vm/src/interpreters/riscv32im/constraints.rs | 9 +++++++++ o1vm/src/interpreters/riscv32im/interpreter.rs | 14 ++++++++++++++ o1vm/src/interpreters/riscv32im/witness.rs | 14 ++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/o1vm/src/interpreters/riscv32im/constraints.rs b/o1vm/src/interpreters/riscv32im/constraints.rs index d414d3dfee..55940dff9b 100644 --- a/o1vm/src/interpreters/riscv32im/constraints.rs +++ b/o1vm/src/interpreters/riscv32im/constraints.rs @@ -362,6 +362,15 @@ impl InterpreterEnv for Env { self.variable(position) } + unsafe fn div( + &mut self, + _x: &Self::Variable, + _y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable { + self.variable(position) + } + unsafe fn divmod( &mut self, _x: &Self::Variable, diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index 855d70ba09..ba799f0d94 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -1271,6 +1271,20 @@ pub trait InterpreterEnv { position: Self::Position, ) -> Self::Variable; + /// Returns `x / y`, storing the results in `position`. + /// + /// # Safety + /// + /// There are no constraints on the returned values; callers must manually add constraints to + /// ensure that the pair of returned values correspond to the given values `x` and `y`, and + /// that they fall within the desired range. + unsafe fn div( + &mut self, + x: &Self::Variable, + y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable; + /// Returns `(x / y, x % y)`, storing the results in `position_quotient` and /// `position_remainder` respectively. /// diff --git a/o1vm/src/interpreters/riscv32im/witness.rs b/o1vm/src/interpreters/riscv32im/witness.rs index cf1ab12fa5..9fa8145656 100644 --- a/o1vm/src/interpreters/riscv32im/witness.rs +++ b/o1vm/src/interpreters/riscv32im/witness.rs @@ -514,6 +514,20 @@ impl InterpreterEnv for Env { res } + unsafe fn div( + &mut self, + x: &Self::Variable, + y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable { + let x: u32 = (*x).try_into().unwrap(); + let y: u32 = (*y).try_into().unwrap(); + let res = x / y; + let res = res as u64; + self.write_column(position, res); + res + } + unsafe fn divmod( &mut self, x: &Self::Variable, From bf08bdfbd972082d245dd39b6832a77f2537f58c Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 20 Nov 2024 16:57:29 +0100 Subject: [PATCH 018/165] o1vm/riscv32: implement mod_ It will be used to implement MInstruction::Remu in a follow-up PR. --- o1vm/src/interpreters/riscv32im/constraints.rs | 9 +++++++++ o1vm/src/interpreters/riscv32im/interpreter.rs | 14 ++++++++++++++ o1vm/src/interpreters/riscv32im/witness.rs | 14 ++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/o1vm/src/interpreters/riscv32im/constraints.rs b/o1vm/src/interpreters/riscv32im/constraints.rs index 55940dff9b..313f87e486 100644 --- a/o1vm/src/interpreters/riscv32im/constraints.rs +++ b/o1vm/src/interpreters/riscv32im/constraints.rs @@ -371,6 +371,15 @@ impl InterpreterEnv for Env { self.variable(position) } + unsafe fn mod_( + &mut self, + _x: &Self::Variable, + _y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable { + self.variable(position) + } + unsafe fn divmod( &mut self, _x: &Self::Variable, diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index ba799f0d94..338473277d 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -1285,6 +1285,20 @@ pub trait InterpreterEnv { position: Self::Position, ) -> Self::Variable; + /// Returns `x % y`, storing the results in `position`. + /// + /// # Safety + /// + /// There are no constraints on the returned values; callers must manually add constraints to + /// ensure that the pair of returned values correspond to the given values `x` and `y`, and + /// that they fall within the desired range. + unsafe fn mod_( + &mut self, + x: &Self::Variable, + y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable; + /// Returns `(x / y, x % y)`, storing the results in `position_quotient` and /// `position_remainder` respectively. /// diff --git a/o1vm/src/interpreters/riscv32im/witness.rs b/o1vm/src/interpreters/riscv32im/witness.rs index 9fa8145656..391d01a1e8 100644 --- a/o1vm/src/interpreters/riscv32im/witness.rs +++ b/o1vm/src/interpreters/riscv32im/witness.rs @@ -528,6 +528,20 @@ impl InterpreterEnv for Env { res } + unsafe fn mod_( + &mut self, + x: &Self::Variable, + y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable { + let x: u32 = (*x).try_into().unwrap(); + let y: u32 = (*y).try_into().unwrap(); + let res = x % y; + let res = res as u64; + self.write_column(position, res); + res + } + unsafe fn divmod( &mut self, x: &Self::Variable, From d7e039d71ddae5ae2e8e68dc35fbc1ae5c0eaa90 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 20 Nov 2024 16:59:21 +0100 Subject: [PATCH 019/165] o1vm/riscv32: remove unused divmod As for mul_hi_lo(_signed), the method is splitted as there are individual instructions for div and mod. --- o1vm/src/interpreters/riscv32im/constraints.rs | 13 ------------- o1vm/src/interpreters/riscv32im/interpreter.rs | 16 ---------------- o1vm/src/interpreters/riscv32im/witness.rs | 18 ------------------ 3 files changed, 47 deletions(-) diff --git a/o1vm/src/interpreters/riscv32im/constraints.rs b/o1vm/src/interpreters/riscv32im/constraints.rs index 313f87e486..087a388c38 100644 --- a/o1vm/src/interpreters/riscv32im/constraints.rs +++ b/o1vm/src/interpreters/riscv32im/constraints.rs @@ -380,19 +380,6 @@ impl InterpreterEnv for Env { self.variable(position) } - unsafe fn divmod( - &mut self, - _x: &Self::Variable, - _y: &Self::Variable, - position_quotient: Self::Position, - position_remainder: Self::Position, - ) -> (Self::Variable, Self::Variable) { - ( - self.variable(position_quotient), - self.variable(position_remainder), - ) - } - unsafe fn count_leading_zeros( &mut self, _x: &Self::Variable, diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index 338473277d..9f4f4106cc 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -1299,22 +1299,6 @@ pub trait InterpreterEnv { position: Self::Position, ) -> Self::Variable; - /// Returns `(x / y, x % y)`, storing the results in `position_quotient` and - /// `position_remainder` respectively. - /// - /// # Safety - /// - /// There are no constraints on the returned values; callers must manually add constraints to - /// ensure that the pair of returned values correspond to the given values `x` and `y`, and - /// that they fall within the desired range. - unsafe fn divmod( - &mut self, - x: &Self::Variable, - y: &Self::Variable, - position_quotient: Self::Position, - position_remainder: Self::Position, - ) -> (Self::Variable, Self::Variable); - /// Returns the number of leading 0s in `x`, storing the result in `position`. /// /// # Safety diff --git a/o1vm/src/interpreters/riscv32im/witness.rs b/o1vm/src/interpreters/riscv32im/witness.rs index 391d01a1e8..3d08cd6ee0 100644 --- a/o1vm/src/interpreters/riscv32im/witness.rs +++ b/o1vm/src/interpreters/riscv32im/witness.rs @@ -542,24 +542,6 @@ impl InterpreterEnv for Env { res } - unsafe fn divmod( - &mut self, - x: &Self::Variable, - y: &Self::Variable, - position_quotient: Self::Position, - position_remainder: Self::Position, - ) -> (Self::Variable, Self::Variable) { - let x: u32 = (*x).try_into().unwrap(); - let y: u32 = (*y).try_into().unwrap(); - let q = x / y; - let r = x % y; - let q = q as u64; - let r = r as u64; - self.write_column(position_quotient, q); - self.write_column(position_remainder, r); - (q, r) - } - unsafe fn count_leading_zeros( &mut self, x: &Self::Variable, From b44fedc6a625e694eed86fe5d877173f2e4350a0 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 20 Nov 2024 17:03:05 +0100 Subject: [PATCH 020/165] o1vm/riscv32: implement M type instruction divu --- o1vm/src/interpreters/riscv32im/interpreter.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index 9f4f4106cc..d220c0fb96 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -2193,7 +2193,17 @@ pub fn interpret_mtype(env: &mut Env, instr: MInstruction) env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); } MInstruction::Divu => { - unimplemented!("Divu") + let rs1 = env.read_register(&rs1); + let rs2 = env.read_register(&rs2); + // FIXME: constrain + let res = { + let pos = env.alloc_scratch(); + unsafe { env.div(&rs1, &rs2, pos) } + }; + env.write_register(&rd, res); + + env.set_instruction_pointer(next_instruction_pointer.clone()); + env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); } MInstruction::Rem => { let rs1 = env.read_register(&rs1); From ade00c9be61fa506d626282e9701fd5f2a7d033a Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 20 Nov 2024 17:04:21 +0100 Subject: [PATCH 021/165] o1vm/riscv32: implement M type instruction Remu --- o1vm/src/interpreters/riscv32im/interpreter.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index d220c0fb96..fd9fdebabb 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -2219,7 +2219,17 @@ pub fn interpret_mtype(env: &mut Env, instr: MInstruction) env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); } MInstruction::Remu => { - unimplemented!("Remu") + let rs1 = env.read_register(&rs1); + let rs2 = env.read_register(&rs2); + // FIXME: constrain + let res = { + let pos = env.alloc_scratch(); + unsafe { env.mod_(&rs1, &rs2, pos) } + }; + env.write_register(&rd, res); + + env.set_instruction_pointer(next_instruction_pointer.clone()); + env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); } } } From eb01801380d168245be781b18f309c8fadfa2c3e Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 20 Nov 2024 17:14:02 +0100 Subject: [PATCH 022/165] o1vm/riscv32: implement mul_hi_signed_unsigned to be used for Mulhsu --- o1vm/src/interpreters/riscv32im/constraints.rs | 9 +++++++++ o1vm/src/interpreters/riscv32im/interpreter.rs | 14 ++++++++++++++ o1vm/src/interpreters/riscv32im/witness.rs | 15 +++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/o1vm/src/interpreters/riscv32im/constraints.rs b/o1vm/src/interpreters/riscv32im/constraints.rs index 087a388c38..b27d2115ce 100644 --- a/o1vm/src/interpreters/riscv32im/constraints.rs +++ b/o1vm/src/interpreters/riscv32im/constraints.rs @@ -344,6 +344,15 @@ impl InterpreterEnv for Env { self.variable(position) } + unsafe fn mul_hi_signed_unsigned( + &mut self, + _x: &Self::Variable, + _y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable { + self.variable(position) + } + unsafe fn div_signed( &mut self, _x: &Self::Variable, diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index fd9fdebabb..7df3ad4288 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -1243,6 +1243,20 @@ pub trait InterpreterEnv { position: Self::Position, ) -> Self::Variable; + /// Returns `((x * y) >> 32`, storing the results in `position`. + /// + /// # Safety + /// + /// There are no constraints on the returned values; callers must manually add constraints to + /// ensure that the pair of returned values correspond to the given values `x` and `y`, and + /// that they fall within the desired range. + unsafe fn mul_hi_signed_unsigned( + &mut self, + x: &Self::Variable, + y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable; + /// Returns `x / y`, storing the results in `position`. /// /// # Safety diff --git a/o1vm/src/interpreters/riscv32im/witness.rs b/o1vm/src/interpreters/riscv32im/witness.rs index 3d08cd6ee0..61db4cdd2a 100644 --- a/o1vm/src/interpreters/riscv32im/witness.rs +++ b/o1vm/src/interpreters/riscv32im/witness.rs @@ -486,6 +486,21 @@ impl InterpreterEnv for Env { res } + unsafe fn mul_hi_signed_unsigned( + &mut self, + x: &Self::Variable, + y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable { + let x: u32 = (*x).try_into().unwrap(); + let y: u32 = (*y).try_into().unwrap(); + let res = (((x as i32) as i64) * (y as i64)) as u64; + let res = (res >> 32) as u32; + let res = res as u64; + self.write_column(position, res); + res + } + unsafe fn div_signed( &mut self, x: &Self::Variable, From 3a9e1bf8ea148a2785c55ad420ec369a37219633 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 20 Nov 2024 17:16:14 +0100 Subject: [PATCH 023/165] o1vm/riscv32: implement M type instruction Mulhsu --- o1vm/src/interpreters/riscv32im/interpreter.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index 7df3ad4288..804334168f 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -2178,7 +2178,17 @@ pub fn interpret_mtype(env: &mut Env, instr: MInstruction) env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); } MInstruction::Mulhsu => { - unimplemented!("Mulhsu") + let rs1 = env.read_register(&rs1); + let rs2 = env.read_register(&rs2); + // FIXME: constrain + let res = { + let pos = env.alloc_scratch(); + unsafe { env.mul_hi_signed_unsigned(&rs1, &rs2, pos) } + }; + env.write_register(&rd, res); + + env.set_instruction_pointer(next_instruction_pointer.clone()); + env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); } MInstruction::Mulhu => { let rs1 = env.read_register(&rs1); From 761d053ce4984115384143b2d2abd0dc83dd0e20 Mon Sep 17 00:00:00 2001 From: Mikhail Volkhov Date: Wed, 20 Nov 2024 16:18:56 +0000 Subject: [PATCH 024/165] Variable names in combine_polys: get rid of omegas --- poly-commitment/src/ipa.rs | 41 ++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/poly-commitment/src/ipa.rs b/poly-commitment/src/ipa.rs index af4e439818..aeea83c584 100644 --- a/poly-commitment/src/ipa.rs +++ b/poly-commitment/src/ipa.rs @@ -103,10 +103,10 @@ impl<'a, F: Field> ScaledChunkedPolynomial { /// Example: /// Given the three polynomials `p1(X)`, and `p3(X)` in coefficients /// forms, p2(X) in evaluation form, -/// and the scaling factor `s`, the result will be the polynomial: +/// and the scaling factor `polyscale`, the result will be the polynomial: /// /// ```text -/// p1(X) + s * i_fft(chunks(p2))(X) + s^2 p3(X) +/// p1(X) + polyscale * i_fft(chunks(p2))(X) + polyscale^2 p3(X) /// ``` /// /// Additional complexity is added to handle chunks. @@ -140,16 +140,19 @@ pub fn combine_polys>( vec![G::ScalarField::zero(); degree] }; - let mut omega = G::ScalarField::zero(); - let mut scale = G::ScalarField::one(); + // Will contain ∑ comm_chunk * polyscale^i + let mut combined_comm = G::ScalarField::zero(); + + // Will contain polyscale^i + let mut polyscale_to_i = G::ScalarField::one(); // Iterating over polynomials in the batch. - // Note that `omegas` are given as `PolyComm`. They are + // Note that the chunks in the commitment `p_i_comm` are given as `PolyComm`. They are // evaluations. // We do modify two different structures depending on the form of the // polynomial we are currently processing: `plnm` and `plnm_evals_part`. // We do need to treat both forms separately. - for (p_i, omegas) in plnms { + for (p_i, p_i_comm) in plnms { match p_i { // Here we scale the polynomial in evaluations forms // Note that based on the check above, sub_domain.size() always give @@ -161,11 +164,11 @@ pub fn combine_polys>( .par_iter_mut() .enumerate() .for_each(|(i, x)| { - *x += scale * evals[i * stride]; + *x += polyscale_to_i * evals[i * stride]; }); - for chunk in omegas.into_iter() { - omega += &(*chunk * scale); - scale *= &polyscale; + for comm_chunk in p_i_comm.into_iter() { + combined_comm += &(*comm_chunk * polyscale_to_i); + polyscale_to_i *= &polyscale; } } @@ -173,13 +176,13 @@ pub fn combine_polys>( DensePolynomialOrEvaluations::DensePolynomial(p_i) => { let mut offset = 0; // iterating over chunks of the polynomial - for chunk in omegas.into_iter() { + for comm_chunk in p_i_comm.into_iter() { let segment = &p_i.coeffs[std::cmp::min(offset, p_i.coeffs.len()) ..std::cmp::min(offset + srs_length, p_i.coeffs.len())]; - plnm_coefficients.add_poly(scale, segment); + plnm_coefficients.add_poly(polyscale_to_i, segment); - omega += &(*chunk * scale); - scale *= &polyscale; + combined_comm += &(*comm_chunk * polyscale_to_i); + polyscale_to_i *= &polyscale; offset += srs_length; } } @@ -191,7 +194,7 @@ pub fn combine_polys>( // plnm will be our final combined polynomial. We first treat the // polynomials in coefficients forms, which is simply scaling the // coefficients and add them. - let mut plnm = plnm_coefficients.to_dense_polynomial(); + let mut combined_plnm = plnm_coefficients.to_dense_polynomial(); if !plnm_evals_part.is_empty() { // n is the number of evaluations, which is a multiple of the @@ -202,13 +205,13 @@ pub fn combine_polys>( // equiv to divceil, but unstable in rust < 1.73. let num_chunks = n / max_poly_size + if n % max_poly_size == 0 { 0 } else { 1 }; // Interpolation on the whole domain, i.e. it can be d2, d4, etc. - plnm += &Evaluations::from_vec_and_domain(plnm_evals_part, D::new(n).unwrap()) + combined_plnm += &Evaluations::from_vec_and_domain(plnm_evals_part, D::new(n).unwrap()) .interpolate() .to_chunked_polynomial(num_chunks, max_poly_size) .linearize(polyscale); } - (plnm, omega) + (combined_plnm, combined_comm) } #[serde_as] @@ -744,6 +747,10 @@ impl SRS { let mut g = self.g.clone(); g.extend(vec![G::zero(); padding]); + // Combines polynomials roughly as follows: p(X) := ∑_i polyscale^i p_i(X) + // + // `blinding_factor` is a combined set of commitments that are + // paired with polynomials in `plnms`. let (p, blinding_factor) = combine_polys::(plnms, polyscale, self.g.len()); // The initial evaluation vector for polynomial commitment b_init is not From e800dcfe9baaa88b0362e46d15e5baa38c596c40 Mon Sep 17 00:00:00 2001 From: Mikhail Volkhov Date: Wed, 20 Nov 2024 16:30:56 +0000 Subject: [PATCH 025/165] Move combine_polys and related structs into utils.rs --- ivc/src/prover.rs | 2 +- kimchi/src/prover.rs | 2 +- msm/src/prover.rs | 2 +- o1vm/src/pickles/prover.rs | 3 +- poly-commitment/benches/ipa.rs | 4 +- poly-commitment/src/ipa.rs | 194 +----------------------- poly-commitment/src/kzg.rs | 5 +- poly-commitment/src/lib.rs | 3 +- poly-commitment/src/utils.rs | 186 +++++++++++++++++++++++ poly-commitment/tests/batch_15_wires.rs | 3 +- poly-commitment/tests/commitment.rs | 3 +- poly-commitment/tests/ipa_commitment.rs | 6 +- poly-commitment/tests/kzg.rs | 6 +- 13 files changed, 214 insertions(+), 205 deletions(-) create mode 100644 poly-commitment/src/utils.rs diff --git a/ivc/src/prover.rs b/ivc/src/prover.rs index f123612d9c..719b2a8f61 100644 --- a/ivc/src/prover.rs +++ b/ivc/src/prover.rs @@ -31,8 +31,8 @@ use mina_poseidon::{sponge::ScalarChallenge, FqSponge}; use o1_utils::ExtendedDensePolynomial; use poly_commitment::{ commitment::{absorb_commitment, CommitmentCurve, PolyComm}, - ipa::DensePolynomialOrEvaluations, kzg::{KZGProof, PairingSRS}, + utils::DensePolynomialOrEvaluations, OpenProof, SRS, }; use rand::{CryptoRng, RngCore}; diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index 9156aee482..755592ca60 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -46,7 +46,7 @@ use poly_commitment::{ commitment::{ absorb_commitment, b_poly_coefficients, BlindedCommitment, CommitmentCurve, PolyComm, }, - ipa::DensePolynomialOrEvaluations, + utils::DensePolynomialOrEvaluations, OpenProof, SRS as _, }; use rand_core::{CryptoRng, RngCore}; diff --git a/msm/src/prover.rs b/msm/src/prover.rs index 138005a3e2..53cab9b287 100644 --- a/msm/src/prover.rs +++ b/msm/src/prover.rs @@ -30,7 +30,7 @@ use mina_poseidon::{sponge::ScalarChallenge, FqSponge}; use o1_utils::ExtendedDensePolynomial; use poly_commitment::{ commitment::{absorb_commitment, PolyComm}, - ipa::DensePolynomialOrEvaluations, + utils::DensePolynomialOrEvaluations, OpenProof, SRS, }; use rand::{CryptoRng, RngCore}; diff --git a/o1vm/src/pickles/prover.rs b/o1vm/src/pickles/prover.rs index 2f40787546..8978952d35 100644 --- a/o1vm/src/pickles/prover.rs +++ b/o1vm/src/pickles/prover.rs @@ -18,7 +18,8 @@ use mina_poseidon::{sponge::ScalarChallenge, FqSponge}; use o1_utils::ExtendedDensePolynomial; use poly_commitment::{ commitment::{absorb_commitment, PolyComm}, - ipa::{DensePolynomialOrEvaluations, OpeningProof, SRS}, + ipa::{OpeningProof, SRS}, + utils::DensePolynomialOrEvaluations, OpenProof as _, SRS as _, }; use rand::{CryptoRng, RngCore}; diff --git a/poly-commitment/benches/ipa.rs b/poly-commitment/benches/ipa.rs index 76c0cd3ea9..6c2abe5ef2 100644 --- a/poly-commitment/benches/ipa.rs +++ b/poly-commitment/benches/ipa.rs @@ -5,9 +5,7 @@ use groupmap::GroupMap; use mina_curves::pasta::{Fp, Vesta, VestaParameters}; use mina_poseidon::{constants::PlonkSpongeConstantsKimchi, sponge::DefaultFqSponge, FqSponge}; use poly_commitment::{ - commitment::CommitmentCurve, - ipa::{DensePolynomialOrEvaluations, SRS}, - PolyComm, SRS as _, + commitment::CommitmentCurve, ipa::SRS, utils::DensePolynomialOrEvaluations, PolyComm, SRS as _, }; fn benchmark_ipa_open(c: &mut Criterion) { diff --git a/poly-commitment/src/ipa.rs b/poly-commitment/src/ipa.rs index aeea83c584..c56fc2d13e 100644 --- a/poly-commitment/src/ipa.rs +++ b/poly-commitment/src/ipa.rs @@ -5,18 +5,18 @@ use crate::{ commitment::{ - b_poly, b_poly_coefficients, combine_commitments, shift_scalar, BatchEvaluationProof, - CommitmentCurve, *, + b_poly, b_poly_coefficients, combine_commitments, shift_scalar, squeeze_challenge, + squeeze_prechallenge, BatchEvaluationProof, CommitmentCurve, EndoCurve, }, error::CommitmentError, hash_map_cache::HashMapCache, + utils::combine_polys, BlindedCommitment, PolyComm, PolynomialsToCombine, SRS as SRSTrait, }; use ark_ec::{AffineRepr, CurveGroup, VariableBaseMSM}; -use ark_ff::{BigInteger, FftField, Field, One, PrimeField, UniformRand, Zero}; +use ark_ff::{BigInteger, Field, One, PrimeField, UniformRand, Zero}; use ark_poly::{ - univariate::DensePolynomial, DenseUVPolynomial, EvaluationDomain, Evaluations, - Radix2EvaluationDomain as D, + univariate::DensePolynomial, EvaluationDomain, Evaluations, Radix2EvaluationDomain as D, }; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use blake2::{Blake2b512, Digest}; @@ -24,7 +24,7 @@ use groupmap::GroupMap; use mina_poseidon::{sponge::ScalarChallenge, FqSponge}; use o1_utils::{ field_helpers::{inner_prod, pows}, - math, ExtendedDensePolynomial, + math, }; use rand::{CryptoRng, RngCore}; use rayon::prelude::*; @@ -32,188 +32,6 @@ use serde::{Deserialize, Serialize}; use serde_with::serde_as; use std::{cmp::min, iter::Iterator, ops::AddAssign}; -/// A formal sum of the form -/// `s_0 * p_0 + ... s_n * p_n` -/// where each `s_i` is a scalar and each `p_i` is a polynomial. -/// The parameter `P` is expected to be the coefficients of the polynomial -/// `p_i`, even though we could treat it as the evaluations. -/// -/// This hypothesis is important if `to_dense_polynomial` is called. -#[derive(Default)] -struct ScaledChunkedPolynomial(Vec<(F, P)>); - -/// Represent a polynomial either with its coefficients or its evaluations -pub enum DensePolynomialOrEvaluations<'a, F: FftField, D: EvaluationDomain> { - /// Polynomial represented by its coefficients - DensePolynomial(&'a DensePolynomial), - /// Polynomial represented by its evaluations over a domain D - Evaluations(&'a Evaluations, D), -} - -impl ScaledChunkedPolynomial { - fn add_poly(&mut self, scale: F, p: P) { - self.0.push((scale, p)) - } -} - -impl<'a, F: Field> ScaledChunkedPolynomial { - /// Compute the resulting scaled polynomial. - /// Example: - /// Given the two polynomials `1 + 2X` and `3 + 4X`, and the scaling - /// factors `2` and `3`, the result is the polynomial `11 + 16X`. - /// ```text - /// 2 * [1, 2] + 3 * [3, 4] = [2, 4] + [9, 12] = [11, 16] - /// ``` - fn to_dense_polynomial(&self) -> DensePolynomial { - // Note: using a reference to avoid reallocation of the result. - let mut res = DensePolynomial::::zero(); - - let scaled: Vec<_> = self - .0 - .par_iter() - .map(|(scale, segment)| { - let scale = *scale; - // We simply scale each coefficients. - // It is simply because DensePolynomial doesn't have a method - // `scale`. - let v = segment.par_iter().map(|x| scale * *x).collect(); - DensePolynomial::from_coefficients_vec(v) - }) - .collect(); - - for p in scaled { - res += &p; - } - - res - } -} - -/// Combine the polynomials using a scalar (`polyscale`), creating a single -/// unified polynomial to open. This function also accepts polynomials in -/// evaluations form. In this case it applies an IFFT, and, if necessarry, -/// applies chunking to it (ie. split it in multiple polynomials of -/// degree less than the SRS size). -/// Parameters: -/// - plnms: vector of polynomials, either in evaluations or coefficients form. -/// The order of the output follows the order of this structure. -/// - polyscale: scalar to combine the polynomials, which will be scaled based -/// on the number of polynomials to combine. -/// -/// Example: -/// Given the three polynomials `p1(X)`, and `p3(X)` in coefficients -/// forms, p2(X) in evaluation form, -/// and the scaling factor `polyscale`, the result will be the polynomial: -/// -/// ```text -/// p1(X) + polyscale * i_fft(chunks(p2))(X) + polyscale^2 p3(X) -/// ``` -/// -/// Additional complexity is added to handle chunks. -// TODO: move into utils? It is useful for multiple PCS -pub fn combine_polys>( - plnms: PolynomialsToCombine, - polyscale: G::ScalarField, - srs_length: usize, -) -> (DensePolynomial, G::ScalarField) { - // Initialising the output for the combined coefficients forms - let mut plnm_coefficients = - ScaledChunkedPolynomial::::default(); - // Initialising the output for the combined evaluations forms - let mut plnm_evals_part = { - // For now just check that all the evaluation polynomials are the same - // degree so that we can do just a single FFT. - // If/when we change this, we can add more complicated code to handle - // different degrees. - let degree = plnms - .iter() - .fold(None, |acc, (p, _)| match p { - DensePolynomialOrEvaluations::DensePolynomial(_) => acc, - DensePolynomialOrEvaluations::Evaluations(_, d) => { - if let Some(n) = acc { - assert_eq!(n, d.size()); - } - Some(d.size()) - } - }) - .unwrap_or(0); - vec![G::ScalarField::zero(); degree] - }; - - // Will contain ∑ comm_chunk * polyscale^i - let mut combined_comm = G::ScalarField::zero(); - - // Will contain polyscale^i - let mut polyscale_to_i = G::ScalarField::one(); - - // Iterating over polynomials in the batch. - // Note that the chunks in the commitment `p_i_comm` are given as `PolyComm`. They are - // evaluations. - // We do modify two different structures depending on the form of the - // polynomial we are currently processing: `plnm` and `plnm_evals_part`. - // We do need to treat both forms separately. - for (p_i, p_i_comm) in plnms { - match p_i { - // Here we scale the polynomial in evaluations forms - // Note that based on the check above, sub_domain.size() always give - // the same value - DensePolynomialOrEvaluations::Evaluations(evals_i, sub_domain) => { - let stride = evals_i.evals.len() / sub_domain.size(); - let evals = &evals_i.evals; - plnm_evals_part - .par_iter_mut() - .enumerate() - .for_each(|(i, x)| { - *x += polyscale_to_i * evals[i * stride]; - }); - for comm_chunk in p_i_comm.into_iter() { - combined_comm += &(*comm_chunk * polyscale_to_i); - polyscale_to_i *= &polyscale; - } - } - - // Here we scale the polynomial in coefficient forms - DensePolynomialOrEvaluations::DensePolynomial(p_i) => { - let mut offset = 0; - // iterating over chunks of the polynomial - for comm_chunk in p_i_comm.into_iter() { - let segment = &p_i.coeffs[std::cmp::min(offset, p_i.coeffs.len()) - ..std::cmp::min(offset + srs_length, p_i.coeffs.len())]; - plnm_coefficients.add_poly(polyscale_to_i, segment); - - combined_comm += &(*comm_chunk * polyscale_to_i); - polyscale_to_i *= &polyscale; - offset += srs_length; - } - } - } - } - - // Now, we will combine both evaluations and coefficients forms - - // plnm will be our final combined polynomial. We first treat the - // polynomials in coefficients forms, which is simply scaling the - // coefficients and add them. - let mut combined_plnm = plnm_coefficients.to_dense_polynomial(); - - if !plnm_evals_part.is_empty() { - // n is the number of evaluations, which is a multiple of the - // domain size. - // We treat now each chunk. - let n = plnm_evals_part.len(); - let max_poly_size = srs_length; - // equiv to divceil, but unstable in rust < 1.73. - let num_chunks = n / max_poly_size + if n % max_poly_size == 0 { 0 } else { 1 }; - // Interpolation on the whole domain, i.e. it can be d2, d4, etc. - combined_plnm += &Evaluations::from_vec_and_domain(plnm_evals_part, D::new(n).unwrap()) - .interpolate() - .to_chunked_polynomial(num_chunks, max_poly_size) - .linearize(polyscale); - } - - (combined_plnm, combined_comm) -} - #[serde_as] #[derive(Debug, Clone, Default, Serialize, Deserialize)] #[serde(bound = "G: CanonicalDeserialize + CanonicalSerialize")] diff --git a/poly-commitment/src/kzg.rs b/poly-commitment/src/kzg.rs index 8d4d8ed7c6..958b2b494c 100644 --- a/poly-commitment/src/kzg.rs +++ b/poly-commitment/src/kzg.rs @@ -10,9 +10,8 @@ //! parameter. use crate::{ - commitment::*, - ipa::{combine_polys, SRS}, - CommitmentError, PolynomialsToCombine, SRS as SRSTrait, + commitment::*, ipa::SRS, utils::combine_polys, CommitmentError, PolynomialsToCombine, + SRS as SRSTrait, }; use ark_ec::{pairing::Pairing, AffineRepr, VariableBaseMSM}; diff --git a/poly-commitment/src/lib.rs b/poly-commitment/src/lib.rs index d6389a4203..9037a0a6ae 100644 --- a/poly-commitment/src/lib.rs +++ b/poly-commitment/src/lib.rs @@ -4,6 +4,7 @@ pub mod error; pub mod hash_map_cache; pub mod ipa; pub mod kzg; +pub mod utils; // Exposing property based tests for the SRS trait pub mod pbt_srs; @@ -13,7 +14,7 @@ pub use commitment::PolyComm; use crate::{ commitment::{BatchEvaluationProof, BlindedCommitment, CommitmentCurve}, error::CommitmentError, - ipa::DensePolynomialOrEvaluations, + utils::DensePolynomialOrEvaluations, }; use ark_ec::AffineRepr; use ark_ff::UniformRand; diff --git a/poly-commitment/src/utils.rs b/poly-commitment/src/utils.rs new file mode 100644 index 0000000000..4dea685144 --- /dev/null +++ b/poly-commitment/src/utils.rs @@ -0,0 +1,186 @@ +use crate::{commitment::CommitmentCurve, PolynomialsToCombine}; +use ark_ff::{FftField, Field, One, Zero}; +use ark_poly::{univariate::DensePolynomial, DenseUVPolynomial, EvaluationDomain, Evaluations}; +use o1_utils::ExtendedDensePolynomial; +use rayon::prelude::*; + +/// Represent a polynomial either with its coefficients or its evaluations +pub enum DensePolynomialOrEvaluations<'a, F: FftField, D: EvaluationDomain> { + /// Polynomial represented by its coefficients + DensePolynomial(&'a DensePolynomial), + /// Polynomial represented by its evaluations over a domain D + Evaluations(&'a Evaluations, D), +} + +/// A formal sum of the form +/// `s_0 * p_0 + ... s_n * p_n` +/// where each `s_i` is a scalar and each `p_i` is a polynomial. +/// The parameter `P` is expected to be the coefficients of the polynomial +/// `p_i`, even though we could treat it as the evaluations. +/// +/// This hypothesis is important if `to_dense_polynomial` is called. +#[derive(Default)] +struct ScaledChunkedPolynomial(Vec<(F, P)>); + +impl ScaledChunkedPolynomial { + fn add_poly(&mut self, scale: F, p: P) { + self.0.push((scale, p)) + } +} + +impl<'a, F: Field> ScaledChunkedPolynomial { + /// Compute the resulting scaled polynomial. + /// Example: + /// Given the two polynomials `1 + 2X` and `3 + 4X`, and the scaling + /// factors `2` and `3`, the result is the polynomial `11 + 16X`. + /// ```text + /// 2 * [1, 2] + 3 * [3, 4] = [2, 4] + [9, 12] = [11, 16] + /// ``` + fn to_dense_polynomial(&self) -> DensePolynomial { + // Note: using a reference to avoid reallocation of the result. + let mut res = DensePolynomial::::zero(); + + let scaled: Vec<_> = self + .0 + .par_iter() + .map(|(scale, segment)| { + let scale = *scale; + // We simply scale each coefficients. + // It is simply because DensePolynomial doesn't have a method + // `scale`. + let v = segment.par_iter().map(|x| scale * *x).collect(); + DensePolynomial::from_coefficients_vec(v) + }) + .collect(); + + for p in scaled { + res += &p; + } + + res + } +} + +/// Combine the polynomials using a scalar (`polyscale`), creating a single +/// unified polynomial to open. This function also accepts polynomials in +/// evaluations form. In this case it applies an IFFT, and, if necessarry, +/// applies chunking to it (ie. split it in multiple polynomials of +/// degree less than the SRS size). +/// Parameters: +/// - plnms: vector of polynomials, either in evaluations or coefficients form. +/// The order of the output follows the order of this structure. +/// - polyscale: scalar to combine the polynomials, which will be scaled based +/// on the number of polynomials to combine. +/// +/// Example: +/// Given the three polynomials `p1(X)`, and `p3(X)` in coefficients +/// forms, p2(X) in evaluation form, +/// and the scaling factor `polyscale`, the result will be the polynomial: +/// +/// ```text +/// p1(X) + polyscale * i_fft(chunks(p2))(X) + polyscale^2 p3(X) +/// ``` +/// +/// Additional complexity is added to handle chunks. +pub fn combine_polys>( + plnms: PolynomialsToCombine, + polyscale: G::ScalarField, + srs_length: usize, +) -> (DensePolynomial, G::ScalarField) { + // Initialising the output for the combined coefficients forms + let mut plnm_coefficients = + ScaledChunkedPolynomial::::default(); + // Initialising the output for the combined evaluations forms + let mut plnm_evals_part = { + // For now just check that all the evaluation polynomials are the same + // degree so that we can do just a single FFT. + // If/when we change this, we can add more complicated code to handle + // different degrees. + let degree = plnms + .iter() + .fold(None, |acc, (p, _)| match p { + DensePolynomialOrEvaluations::DensePolynomial(_) => acc, + DensePolynomialOrEvaluations::Evaluations(_, d) => { + if let Some(n) = acc { + assert_eq!(n, d.size()); + } + Some(d.size()) + } + }) + .unwrap_or(0); + vec![G::ScalarField::zero(); degree] + }; + + // Will contain ∑ comm_chunk * polyscale^i + let mut combined_comm = G::ScalarField::zero(); + + // Will contain polyscale^i + let mut polyscale_to_i = G::ScalarField::one(); + + // Iterating over polynomials in the batch. + // Note that the chunks in the commitment `p_i_comm` are given as `PolyComm`. They are + // evaluations. + // We do modify two different structures depending on the form of the + // polynomial we are currently processing: `plnm` and `plnm_evals_part`. + // We do need to treat both forms separately. + for (p_i, p_i_comm) in plnms { + match p_i { + // Here we scale the polynomial in evaluations forms + // Note that based on the check above, sub_domain.size() always give + // the same value + DensePolynomialOrEvaluations::Evaluations(evals_i, sub_domain) => { + let stride = evals_i.evals.len() / sub_domain.size(); + let evals = &evals_i.evals; + plnm_evals_part + .par_iter_mut() + .enumerate() + .for_each(|(i, x)| { + *x += polyscale_to_i * evals[i * stride]; + }); + for comm_chunk in p_i_comm.into_iter() { + combined_comm += &(*comm_chunk * polyscale_to_i); + polyscale_to_i *= &polyscale; + } + } + + // Here we scale the polynomial in coefficient forms + DensePolynomialOrEvaluations::DensePolynomial(p_i) => { + let mut offset = 0; + // iterating over chunks of the polynomial + for comm_chunk in p_i_comm.into_iter() { + let segment = &p_i.coeffs[std::cmp::min(offset, p_i.coeffs.len()) + ..std::cmp::min(offset + srs_length, p_i.coeffs.len())]; + plnm_coefficients.add_poly(polyscale_to_i, segment); + + combined_comm += &(*comm_chunk * polyscale_to_i); + polyscale_to_i *= &polyscale; + offset += srs_length; + } + } + } + } + + // Now, we will combine both evaluations and coefficients forms + + // plnm will be our final combined polynomial. We first treat the + // polynomials in coefficients forms, which is simply scaling the + // coefficients and add them. + let mut combined_plnm = plnm_coefficients.to_dense_polynomial(); + + if !plnm_evals_part.is_empty() { + // n is the number of evaluations, which is a multiple of the + // domain size. + // We treat now each chunk. + let n = plnm_evals_part.len(); + let max_poly_size = srs_length; + // equiv to divceil, but unstable in rust < 1.73. + let num_chunks = n / max_poly_size + if n % max_poly_size == 0 { 0 } else { 1 }; + // Interpolation on the whole domain, i.e. it can be d2, d4, etc. + combined_plnm += &Evaluations::from_vec_and_domain(plnm_evals_part, D::new(n).unwrap()) + .interpolate() + .to_chunked_polynomial(num_chunks, max_poly_size) + .linearize(polyscale); + } + + (combined_plnm, combined_comm) +} diff --git a/poly-commitment/tests/batch_15_wires.rs b/poly-commitment/tests/batch_15_wires.rs index 0efbc27170..eafeba8f5b 100644 --- a/poly-commitment/tests/batch_15_wires.rs +++ b/poly-commitment/tests/batch_15_wires.rs @@ -12,7 +12,8 @@ use mina_poseidon::{ use o1_utils::ExtendedDensePolynomial as _; use poly_commitment::{ commitment::{combined_inner_product, BatchEvaluationProof, CommitmentCurve, Evaluation}, - ipa::{DensePolynomialOrEvaluations, SRS}, + ipa::SRS, + utils::DensePolynomialOrEvaluations, SRS as _, }; use rand::Rng; diff --git a/poly-commitment/tests/commitment.rs b/poly-commitment/tests/commitment.rs index dac48427c4..b22b1e9853 100644 --- a/poly-commitment/tests/commitment.rs +++ b/poly-commitment/tests/commitment.rs @@ -14,7 +14,8 @@ use poly_commitment::{ combined_inner_product, BatchEvaluationProof, BlindedCommitment, CommitmentCurve, Evaluation, PolyComm, }, - ipa::{DensePolynomialOrEvaluations, OpeningProof, SRS}, + ipa::{OpeningProof, SRS}, + utils::DensePolynomialOrEvaluations, SRS as _, }; use rand::{CryptoRng, Rng, SeedableRng}; diff --git a/poly-commitment/tests/ipa_commitment.rs b/poly-commitment/tests/ipa_commitment.rs index 9bf96a1c06..bbab4def03 100644 --- a/poly-commitment/tests/ipa_commitment.rs +++ b/poly-commitment/tests/ipa_commitment.rs @@ -11,8 +11,10 @@ use mina_poseidon::{ use o1_utils::ExtendedDensePolynomial; use poly_commitment::{ commitment::{combined_inner_product, BatchEvaluationProof, CommitmentCurve, Evaluation}, - ipa::{DensePolynomialOrEvaluations, SRS}, - pbt_srs, PolyComm, SRS as _, + ipa::SRS, + pbt_srs, + utils::DensePolynomialOrEvaluations, + PolyComm, SRS as _, }; use rand::Rng; use std::array; diff --git a/poly-commitment/tests/kzg.rs b/poly-commitment/tests/kzg.rs index 682b5eb9f8..0b553fa1fb 100644 --- a/poly-commitment/tests/kzg.rs +++ b/poly-commitment/tests/kzg.rs @@ -9,9 +9,11 @@ use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use mina_curves::pasta::{Fp, Vesta as VestaG}; use poly_commitment::{ commitment::Evaluation, - ipa::{DensePolynomialOrEvaluations, SRS}, + ipa::SRS, kzg::{combine_evaluations, KZGProof, PairingSRS}, - pbt_srs, PolyComm, SRS as _, + pbt_srs, + utils::DensePolynomialOrEvaluations, + PolyComm, SRS as _, }; #[test] From 42002f8cb12274678ed48ada1c8facda25d5329c Mon Sep 17 00:00:00 2001 From: Mikhail Volkhov Date: Wed, 20 Nov 2024 16:48:32 +0000 Subject: [PATCH 026/165] Rename erroneous d1_size into num_chunks in prover --- kimchi/src/prover.rs | 14 +++++++------- msm/src/prover.rs | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index 755592ca60..b135d20836 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -1238,8 +1238,12 @@ where //~ 1. Create a list of all polynomials that will require evaluations //~ (and evaluation proofs) in the protocol. //~ First, include the previous challenges, in case we are in a recursive prover. - let non_hiding = |d1_size: usize| PolyComm { - chunks: vec![G::ScalarField::zero(); d1_size], + let non_hiding = |n_chunks: usize| PolyComm { + chunks: vec![G::ScalarField::zero(); n_chunks], + }; + + let fixed_hiding = |n_chunks: usize| PolyComm { + chunks: vec![G::ScalarField::one(); n_chunks], }; let coefficients_form = DensePolynomialOrEvaluations::DensePolynomial; @@ -1247,13 +1251,9 @@ where let mut polynomials = polys .iter() - .map(|(p, d1_size)| (coefficients_form(p), non_hiding(*d1_size))) + .map(|(p, n_chunks)| (coefficients_form(p), non_hiding(*n_chunks))) .collect::>(); - let fixed_hiding = |d1_size: usize| PolyComm { - chunks: vec![G::ScalarField::one(); d1_size], - }; - //~ 1. Then, include: //~~ * the negated public polynomial //~~ * the ft polynomial diff --git a/msm/src/prover.rs b/msm/src/prover.rs index 53cab9b287..2ea2534da2 100644 --- a/msm/src/prover.rs +++ b/msm/src/prover.rs @@ -490,11 +490,11 @@ where let u = u_chal.to_field(endo_r); let coefficients_form = DensePolynomialOrEvaluations::DensePolynomial; - let non_hiding = |d1_size| PolyComm { - chunks: vec![G::ScalarField::zero(); d1_size], + let non_hiding = |n_chunks| PolyComm { + chunks: vec![G::ScalarField::zero(); n_chunks], }; - let hiding = |d1_size| PolyComm { - chunks: vec![G::ScalarField::one(); d1_size], + let hiding = |n_chunks| PolyComm { + chunks: vec![G::ScalarField::one(); n_chunks], }; // Gathering all polynomials to use in the opening proof From 0ba848267cb52edd9c4c61403337682d9355e262 Mon Sep 17 00:00:00 2001 From: Mikhail Volkhov Date: Wed, 20 Nov 2024 16:53:53 +0000 Subject: [PATCH 027/165] More comments on ipa#open --- poly-commitment/src/ipa.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/poly-commitment/src/ipa.rs b/poly-commitment/src/ipa.rs index c56fc2d13e..77b98c99a1 100644 --- a/poly-commitment/src/ipa.rs +++ b/poly-commitment/src/ipa.rs @@ -568,15 +568,17 @@ impl SRS { // Combines polynomials roughly as follows: p(X) := ∑_i polyscale^i p_i(X) // // `blinding_factor` is a combined set of commitments that are - // paired with polynomials in `plnms`. + // paired with polynomials in `plnms`. In kimchi, these input commitments + // are blinders, so often `[G::ScalarField::one(); num_chunks]` or zeroes. let (p, blinding_factor) = combine_polys::(plnms, polyscale, self.g.len()); // The initial evaluation vector for polynomial commitment b_init is not - // just the powers of a single point as in the original IPA, but rather - // a vector of linearly combined powers with `evalscale` as recombiner. + // just the powers of a single point as in the original IPA (1,ζ,ζ^2,...) + // + // but rather a vector of linearly combined powers with `evalscale` as recombiner. // // b_init[j] = Σ_i evalscale^i elm_i^j - // = ζ^j + evalscale * ζ^j ω^j (in the specific case of opening) + // = ζ^j + evalscale * ζ^j ω^j (in the specific case of challenges (ζ,ζω)) let b_init = { // randomise/scale the eval powers let mut scale = G::ScalarField::one(); From d694a2270452d2ad00e128b28d07eeeb401a22fd Mon Sep 17 00:00:00 2001 From: Mikhail Volkhov Date: Wed, 20 Nov 2024 17:58:28 +0000 Subject: [PATCH 028/165] Improve combine_poly docs --- poly-commitment/src/utils.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/poly-commitment/src/utils.rs b/poly-commitment/src/utils.rs index 4dea685144..fc43883aff 100644 --- a/poly-commitment/src/utils.rs +++ b/poly-commitment/src/utils.rs @@ -66,11 +66,16 @@ impl<'a, F: Field> ScaledChunkedPolynomial { /// evaluations form. In this case it applies an IFFT, and, if necessarry, /// applies chunking to it (ie. split it in multiple polynomials of /// degree less than the SRS size). +/// /// Parameters: -/// - plnms: vector of polynomials, either in evaluations or coefficients form. -/// The order of the output follows the order of this structure. -/// - polyscale: scalar to combine the polynomials, which will be scaled based -/// on the number of polynomials to combine. +/// - `plnms`: vector of polynomials, either in evaluations or coefficients form, together with +/// a set of scalars representing their blinders. +/// - `polyscale`: scalar to combine the polynomials, which will be scaled based on the number of +/// polynomials to combine. +/// +/// Output: +/// - `combined_poly`: combined polynomial. The order of the output follows the order of `plnms`. +/// - `combined_comm`: combined scalars representing the blinder commitment. /// /// Example: /// Given the three polynomials `p1(X)`, and `p3(X)` in coefficients From b3ef6eab6fdc0cee34c3de2ddeb14012c2dd2bc1 Mon Sep 17 00:00:00 2001 From: Mikhail Volkhov Date: Wed, 20 Nov 2024 17:59:08 +0000 Subject: [PATCH 029/165] Improve docs for PolynomialsToCombine --- poly-commitment/src/lib.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/poly-commitment/src/lib.rs b/poly-commitment/src/lib.rs index 9037a0a6ae..06e546a9e7 100644 --- a/poly-commitment/src/lib.rs +++ b/poly-commitment/src/lib.rs @@ -169,8 +169,9 @@ pub trait SRS: Clone + Sized { } #[allow(type_alias_bounds)] -/// Simply an alias to represent a polynomial with its commitment, possibly with -/// a blinder. +/// An alias to represent a polynomial (in either coefficient or +/// evaluation form), with a set of *scalar field* elements that +/// represent the exponent of its blinder. // TODO: add a string to name the polynomial type PolynomialsToCombine<'a, G: CommitmentCurve, D: EvaluationDomain> = &'a [( DensePolynomialOrEvaluations<'a, G::ScalarField, D>, From 654266619ec4660f11b8c4256dd7d5849a9fef11 Mon Sep 17 00:00:00 2001 From: Mikhail Volkhov Date: Wed, 20 Nov 2024 17:59:40 +0000 Subject: [PATCH 030/165] Improve docs for IPA, improve some variable names --- poly-commitment/src/ipa.rs | 55 +++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 19 deletions(-) diff --git a/poly-commitment/src/ipa.rs b/poly-commitment/src/ipa.rs index 77b98c99a1..d68216f67c 100644 --- a/poly-commitment/src/ipa.rs +++ b/poly-commitment/src/ipa.rs @@ -183,8 +183,8 @@ impl SRS { { sponge.absorb_fr(&[shift_scalar::(*combined_inner_product)]); - let t = sponge.challenge_fq(); - let u: G = { + let u_base: G = { + let t = sponge.challenge_fq(); let (x, y) = group_map.to_group(t); G::of_coordinates(x, y) }; @@ -240,7 +240,7 @@ impl SRS { // TERM // -rand_base_i * (z1 * b0 * U) scalars.push(neg_rand_base_i * (opening.z1 * b0)); - points.push(u); + points.push(u_base); // TERM // rand_base_i c_i Q_i @@ -269,7 +269,7 @@ impl SRS { ); scalars.push(rand_base_i_c_i * *combined_inner_product); - points.push(u); + points.push(u_base); scalars.push(rand_base_i); points.push(opening.delta); @@ -569,7 +569,7 @@ impl SRS { // // `blinding_factor` is a combined set of commitments that are // paired with polynomials in `plnms`. In kimchi, these input commitments - // are blinders, so often `[G::ScalarField::one(); num_chunks]` or zeroes. + // are poly com blinders, so often `[G::ScalarField::one(); num_chunks]` or zeroes. let (p, blinding_factor) = combine_polys::(plnms, polyscale, self.g.len()); // The initial evaluation vector for polynomial commitment b_init is not @@ -579,6 +579,13 @@ impl SRS { // // b_init[j] = Σ_i evalscale^i elm_i^j // = ζ^j + evalscale * ζ^j ω^j (in the specific case of challenges (ζ,ζω)) + // + // So in our case b_init is the following vector: + // 1 + evalscale + // ζ + evalscale * ζ ω + // ζ^2 + evalscale * (ζ ω)^2 + // ζ^3 + evalscale * (ζ ω)^3 + // ... let b_init = { // randomise/scale the eval powers let mut scale = G::ScalarField::one(); @@ -593,7 +600,7 @@ impl SRS { res }; - // Combined polynomial p, evaluated at the combined point b_init. + // Combined polynomial p(X) evaluated at the combined eval point b_init. let combined_inner_product = p .coeffs .iter() @@ -610,8 +617,9 @@ impl SRS { // See the `shift_scalar`` doc. sponge.absorb_fr(&[shift_scalar::(combined_inner_product)]); - let t = sponge.challenge_fq(); - let u: G = { + // Generate another randomisation base U; our commitments will be w.r.t bases {G_i},H,U. + let u_base: G = { + let t = sponge.challenge_fq(); let (x, y) = group_map.to_group(t); G::of_coordinates(x, y) }; @@ -645,7 +653,7 @@ impl SRS { // Pedersen commitment to a_lo,rand_l, let l = G::Group::msm_bigint( - &[g_lo, &[self.h, u]].concat(), + &[g_lo, &[self.h, u_base]].concat(), &[a_hi, &[rand_l, inner_prod(a_hi, b_lo)]] .concat() .iter() @@ -655,7 +663,7 @@ impl SRS { .into_affine(); let r = G::Group::msm_bigint( - &[g_hi, &[self.h, u]].concat(), + &[g_hi, &[self.h, u_base]].concat(), &[a_lo, &[rand_r, inner_prod(a_lo, b_hi)]] .concat() .iter() @@ -670,7 +678,9 @@ impl SRS { sponge.absorb_g(&[l]); sponge.absorb_g(&[r]); - // Round #i challenges + // Round #i challenges; + // - not to be confused with "u_base" + // - not to be confused with "u" as "polyscale" let u_pre = squeeze_prechallenge(&mut sponge); let u = u_pre.to_field(&endo_r); let u_inv = u.inverse().unwrap(); @@ -716,11 +726,15 @@ impl SRS { let b0 = b[0]; let g0 = g[0]; - // Schnorr/Sigma-protocol part - - // r_prime = blinding_factor + \sum_i (rand_l[i] * (u[i]^{-1}) + rand_r * u[i]) - // where u is a vector of folding challenges, and rand_l/rand_r are - // intermediate L/R blinders + // Compute r_prime, a folded blinder. It combines blinders on + // each individual step of the IPA folding process together + // with the final blinding_factor of the polynomial. + // + // r_prime := ∑_i (rand_l[i] * u[i]^{-1} + rand_r * u[i]) + // + blinding_factor + // + // where u is a vector of folding challenges, and rand_l/rand_r are + // intermediate L/R blinders. let r_prime = blinders .iter() .zip(chals.iter().zip(chal_invs.iter())) @@ -730,13 +744,16 @@ impl SRS { let d = ::rand(rng); let r_delta = ::rand(rng); - // delta = (g0 + u*b0)*d + h*r_delta - let delta = ((g0.into_group() + (u.mul(b0))).into_affine().mul(d) + self.h.mul(r_delta)) - .into_affine(); + // Compute delta, the commitment + // delta = G0^d * U_base^{b0*d} * H^r_delta (as a group element, in multiplicative notation) + let delta = ((g0.into_group() + (u_base.mul(b0))).into_affine().mul(d) + + self.h.mul(r_delta)) + .into_affine(); sponge.absorb_g(&[delta]); let c = ScalarChallenge(sponge.challenge()).to_field(&endo_r); + // (?) Schnorr-like responses showing the knowledge of r_prime and a0. let z1 = a0 * c + d; let z2 = r_prime * c + r_delta; From ebcd6bb5bfd09720c9a6c28ddae34ea4f593d45b Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 20 Nov 2024 16:22:33 +0100 Subject: [PATCH 031/165] o1vm/riscv32: implement mul_lo_signed --- o1vm/src/interpreters/riscv32im/constraints.rs | 9 +++++++++ o1vm/src/interpreters/riscv32im/interpreter.rs | 14 ++++++++++++++ o1vm/src/interpreters/riscv32im/witness.rs | 15 +++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/o1vm/src/interpreters/riscv32im/constraints.rs b/o1vm/src/interpreters/riscv32im/constraints.rs index 11dee8a230..82b9cd5105 100644 --- a/o1vm/src/interpreters/riscv32im/constraints.rs +++ b/o1vm/src/interpreters/riscv32im/constraints.rs @@ -336,6 +336,15 @@ impl InterpreterEnv for Env { self.variable(position) } + unsafe fn mul_lo_signed( + &mut self, + _x: &Self::Variable, + _y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable { + self.variable(position) + } + unsafe fn mul_hi_lo( &mut self, _x: &Self::Variable, diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index 1e41918b20..2cd83827a1 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -1215,6 +1215,20 @@ pub trait InterpreterEnv { position: Self::Position, ) -> Self::Variable; + /// Returns `(x * y) & ((1 << 32) - 1))`, storing the results in `position` + /// + /// # Safety + /// + /// There are no constraints on the returned values; callers must manually add constraints to + /// ensure that the pair of returned values correspond to the given values `x` and `y`, and + /// that they fall within the desired range. + unsafe fn mul_lo_signed( + &mut self, + x: &Self::Variable, + y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable; + /// Returns `((x * y) >> 32, (x * y) & ((1 << 32) - 1))`, storing the results in `position_hi` /// and `position_lo` respectively. /// diff --git a/o1vm/src/interpreters/riscv32im/witness.rs b/o1vm/src/interpreters/riscv32im/witness.rs index 0418852ae9..658048bf99 100644 --- a/o1vm/src/interpreters/riscv32im/witness.rs +++ b/o1vm/src/interpreters/riscv32im/witness.rs @@ -456,6 +456,21 @@ impl InterpreterEnv for Env { res } + unsafe fn mul_lo_signed( + &mut self, + x: &Self::Variable, + y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable { + let x: u32 = (*x).try_into().unwrap(); + let y: u32 = (*y).try_into().unwrap(); + let res = (((x as i32) as i64) * ((y as i32) as i64)) as u64; + let res = (res & ((1 << 32) - 1)) as u32; + let res = res as u64; + self.write_column(position, res); + res + } + unsafe fn mul_hi_lo_signed( &mut self, x: &Self::Variable, From 95098af4c18c79cc880f1e2da0dd76399b470423 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Mon, 25 Nov 2024 10:46:42 +0100 Subject: [PATCH 032/165] o1vm/riscv32im: simplify mul_lo_signed implementation --- o1vm/src/interpreters/riscv32im/witness.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/o1vm/src/interpreters/riscv32im/witness.rs b/o1vm/src/interpreters/riscv32im/witness.rs index 658048bf99..3484ad0a10 100644 --- a/o1vm/src/interpreters/riscv32im/witness.rs +++ b/o1vm/src/interpreters/riscv32im/witness.rs @@ -462,9 +462,9 @@ impl InterpreterEnv for Env { y: &Self::Variable, position: Self::Position, ) -> Self::Variable { - let x: u32 = (*x).try_into().unwrap(); - let y: u32 = (*y).try_into().unwrap(); - let res = (((x as i32) as i64) * ((y as i32) as i64)) as u64; + let x: i32 = (*x).try_into().unwrap(); + let y: i32 = (*y).try_into().unwrap(); + let res = ((x as i64) * (y as i64)) as u64; let res = (res & ((1 << 32) - 1)) as u32; let res = res as u64; self.write_column(position, res); From 1ab19958b1dfc4358eea62a12f48bfb7737e7c6c Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Mon, 25 Nov 2024 11:10:35 +0100 Subject: [PATCH 033/165] o1vm/riscv32im: improve documentation reg. semantic of op --- o1vm/src/interpreters/riscv32im/interpreter.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index 804334168f..5eb4635430 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -20,6 +20,14 @@ //! and copied in this file for offline reference. //! If you are the author of the above documentations and would like to add or //! modify the credits, please open a pull request. +//! +//! For each instruction, we provide the format, description, and the +//! semantic in pseudo-code of the instruction. +//! When `signed` is mentioned in the pseudo-code, it means that the +//! operation is performed as a signed operation (i.e. signed(v) where `v` is a +//! 32 bits value means that `v` must be interpreted as a i32 value in Rust, the +//! most significant bit being the sign - 1 for negative, 0 for positive). +//! By default, unsigned operations are performed. use super::registers::{REGISTER_CURRENT_IP, REGISTER_HEAP_POINTER, REGISTER_NEXT_IP}; use crate::lookups::{Lookup, LookupTableIDs}; From 89b4085b6a9623acb12214e17187a0434135919c Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Mon, 25 Nov 2024 11:11:00 +0100 Subject: [PATCH 034/165] o1vm/riscv32im: add semantic for MInstruction --- o1vm/src/interpreters/riscv32im/interpreter.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index 5eb4635430..2a3e89cbae 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -2160,6 +2160,7 @@ pub fn interpret_mtype(env: &mut Env, instr: MInstruction) match instr { MInstruction::Mul => { + // x[rd] = x[rs1] * x[rs2] let rs1 = env.read_register(&rs1); let rs2 = env.read_register(&rs2); // FIXME: constrain @@ -2173,6 +2174,7 @@ pub fn interpret_mtype(env: &mut Env, instr: MInstruction) env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); } MInstruction::Mulh => { + // x[rd] = (signed(x[rs1]) * signed(x[rs2])) >> 32 let rs1 = env.read_register(&rs1); let rs2 = env.read_register(&rs2); // FIXME: constrain @@ -2186,6 +2188,7 @@ pub fn interpret_mtype(env: &mut Env, instr: MInstruction) env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); } MInstruction::Mulhsu => { + // x[rd] = (signed(x[rs1]) * x[rs2]) >> 32 let rs1 = env.read_register(&rs1); let rs2 = env.read_register(&rs2); // FIXME: constrain @@ -2199,6 +2202,7 @@ pub fn interpret_mtype(env: &mut Env, instr: MInstruction) env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); } MInstruction::Mulhu => { + // x[rd] = (x[rs1] * x[rs2]) >> 32 let rs1 = env.read_register(&rs1); let rs2 = env.read_register(&rs2); // FIXME: constrain @@ -2212,6 +2216,7 @@ pub fn interpret_mtype(env: &mut Env, instr: MInstruction) env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); } MInstruction::Div => { + // x[rd] = signed(x[rs1]) / signed(x[rs2]) let rs1 = env.read_register(&rs1); let rs2 = env.read_register(&rs2); // FIXME: constrain @@ -2225,6 +2230,7 @@ pub fn interpret_mtype(env: &mut Env, instr: MInstruction) env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); } MInstruction::Divu => { + // x[rd] = x[rs1] / x[rs2] let rs1 = env.read_register(&rs1); let rs2 = env.read_register(&rs2); // FIXME: constrain @@ -2238,6 +2244,7 @@ pub fn interpret_mtype(env: &mut Env, instr: MInstruction) env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); } MInstruction::Rem => { + // x[rd] = signed(x[rs1]) % signed(x[rs2]) let rs1 = env.read_register(&rs1); let rs2 = env.read_register(&rs2); // FIXME: constrain @@ -2251,6 +2258,7 @@ pub fn interpret_mtype(env: &mut Env, instr: MInstruction) env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); } MInstruction::Remu => { + // x[rd] = x[rs1] % x[rs2] let rs1 = env.read_register(&rs1); let rs2 = env.read_register(&rs2); // FIXME: constrain From 6aaa8f63af771215fe25191d833ff4d78141fa51 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Mon, 25 Nov 2024 15:13:40 +0100 Subject: [PATCH 035/165] o1vm/riscv32im: test decoding add --- o1vm/src/interpreters/riscv32im/mod.rs | 3 ++ o1vm/src/interpreters/riscv32im/tests.rs | 57 ++++++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 o1vm/src/interpreters/riscv32im/tests.rs diff --git a/o1vm/src/interpreters/riscv32im/mod.rs b/o1vm/src/interpreters/riscv32im/mod.rs index 5b78cb702b..14c2485756 100644 --- a/o1vm/src/interpreters/riscv32im/mod.rs +++ b/o1vm/src/interpreters/riscv32im/mod.rs @@ -21,3 +21,6 @@ pub mod interpreter; pub mod registers; pub mod witness; + +#[cfg(test)] +pub mod tests; diff --git a/o1vm/src/interpreters/riscv32im/tests.rs b/o1vm/src/interpreters/riscv32im/tests.rs new file mode 100644 index 0000000000..5a322278d8 --- /dev/null +++ b/o1vm/src/interpreters/riscv32im/tests.rs @@ -0,0 +1,57 @@ +use super::{registers::Registers, witness::Env, INSTRUCTION_SET_SIZE, PAGE_SIZE, SCRATCH_SIZE}; +use crate::interpreters::riscv32im::interpreter::{Instruction, RInstruction}; +use ark_ff::Zero; +use mina_curves::pasta::Fp; +use rand::{CryptoRng, Rng, RngCore}; + +pub fn dummy_env() -> Env { + Env { + instruction_counter: 0, + memory: vec![(0, vec![0; PAGE_SIZE.try_into().unwrap()])], + last_memory_accesses: [0; 3], + memory_write_index: vec![(0, vec![0; PAGE_SIZE.try_into().unwrap()])], + last_memory_write_index_accesses: [0; 3], + registers: Registers::default(), + registers_write_index: Registers::default(), + scratch_state_idx: 0, + scratch_state: [Fp::zero(); SCRATCH_SIZE], + halt: false, + selector: INSTRUCTION_SET_SIZE, + } +} + +pub fn generate_random_add_instruction(rng: &mut RNG) -> [u8; 4] { + let opcode = 0b0110011; + let rd = rng.gen_range(0..32); + let funct3 = 0b000; + let rs1 = rng.gen_range(0..32); + let rs2 = rng.gen_range(0..32); + let funct2 = 0b00; + let funct5 = 0b00000; + let instruction = opcode + | (rd << 7) + | (funct3 << 12) + | (rs1 << 15) + | (rs2 << 20) + | (funct2 << 25) + | (funct5 << 27); + [ + instruction as u8, + (instruction >> 8) as u8, + (instruction >> 16) as u8, + (instruction >> 24) as u8, + ] +} + +#[test] +pub fn test_instruction_decoding_add() { + let mut env: Env = dummy_env(); + let mut rng = o1_utils::tests::make_test_rng(None); + let instruction = generate_random_add_instruction(&mut rng); + env.memory[0].1[0] = instruction[0]; + env.memory[0].1[1] = instruction[1]; + env.memory[0].1[2] = instruction[2]; + env.memory[0].1[3] = instruction[3]; + let (opcode, _instruction) = env.decode_instruction(); + assert_eq!(opcode, Instruction::RType(RInstruction::Add)); +} From 520bd77bab29301b6ddd5a043eb3e075af403971 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Mon, 25 Nov 2024 15:22:47 +0100 Subject: [PATCH 036/165] o1vm/riscv32im: test decoding sub --- o1vm/src/interpreters/riscv32im/tests.rs | 36 ++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/o1vm/src/interpreters/riscv32im/tests.rs b/o1vm/src/interpreters/riscv32im/tests.rs index 5a322278d8..9042b3425a 100644 --- a/o1vm/src/interpreters/riscv32im/tests.rs +++ b/o1vm/src/interpreters/riscv32im/tests.rs @@ -43,6 +43,29 @@ pub fn generate_random_add_instruction(rng: &mut RNG) ] } +pub fn generate_random_sub_instruction(rng: &mut RNG) -> [u8; 4] { + let opcode = 0b0110011; + let rd = rng.gen_range(0..32); + let funct3 = 0b000; + let rs1 = rng.gen_range(0..32); + let rs2 = rng.gen_range(0..32); + let funct2 = 0b00; + let funct5 = 0b01000; + let instruction = opcode + | (rd << 7) + | (funct3 << 12) + | (rs1 << 15) + | (rs2 << 20) + | (funct2 << 25) + | (funct5 << 27); + [ + instruction as u8, + (instruction >> 8) as u8, + (instruction >> 16) as u8, + (instruction >> 24) as u8, + ] +} + #[test] pub fn test_instruction_decoding_add() { let mut env: Env = dummy_env(); @@ -55,3 +78,16 @@ pub fn test_instruction_decoding_add() { let (opcode, _instruction) = env.decode_instruction(); assert_eq!(opcode, Instruction::RType(RInstruction::Add)); } + +#[test] +pub fn test_instruction_decoding_sub() { + let mut env: Env = dummy_env(); + let mut rng = o1_utils::tests::make_test_rng(None); + let instruction = generate_random_sub_instruction(&mut rng); + env.memory[0].1[0] = instruction[0]; + env.memory[0].1[1] = instruction[1]; + env.memory[0].1[2] = instruction[2]; + env.memory[0].1[3] = instruction[3]; + let (opcode, _instruction) = env.decode_instruction(); + assert_eq!(opcode, Instruction::RType(RInstruction::Sub)); +} From c3808c91101f481d8e0ab81e414fa56778894486 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Mon, 25 Nov 2024 15:24:11 +0100 Subject: [PATCH 037/165] o1vm/riscv32im: test decoding sll --- o1vm/src/interpreters/riscv32im/tests.rs | 36 ++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/o1vm/src/interpreters/riscv32im/tests.rs b/o1vm/src/interpreters/riscv32im/tests.rs index 9042b3425a..30c07c7b2a 100644 --- a/o1vm/src/interpreters/riscv32im/tests.rs +++ b/o1vm/src/interpreters/riscv32im/tests.rs @@ -66,6 +66,29 @@ pub fn generate_random_sub_instruction(rng: &mut RNG) ] } +pub fn generate_random_sll_instruction(rng: &mut RNG) -> [u8; 4] { + let opcode = 0b0110011; + let rd = rng.gen_range(0..32); + let funct3 = 0b001; + let rs1 = rng.gen_range(0..32); + let rs2 = rng.gen_range(0..32); + let funct2 = 0b00; + let funct5 = 0b00000; + let instruction = opcode + | (rd << 7) + | (funct3 << 12) + | (rs1 << 15) + | (rs2 << 20) + | (funct2 << 25) + | (funct5 << 27); + [ + instruction as u8, + (instruction >> 8) as u8, + (instruction >> 16) as u8, + (instruction >> 24) as u8, + ] +} + #[test] pub fn test_instruction_decoding_add() { let mut env: Env = dummy_env(); @@ -91,3 +114,16 @@ pub fn test_instruction_decoding_sub() { let (opcode, _instruction) = env.decode_instruction(); assert_eq!(opcode, Instruction::RType(RInstruction::Sub)); } + +#[test] +pub fn test_instruction_decoding_sll() { + let mut env: Env = dummy_env(); + let mut rng = o1_utils::tests::make_test_rng(None); + let instruction = generate_random_sll_instruction(&mut rng); + env.memory[0].1[0] = instruction[0]; + env.memory[0].1[1] = instruction[1]; + env.memory[0].1[2] = instruction[2]; + env.memory[0].1[3] = instruction[3]; + let (opcode, _instruction) = env.decode_instruction(); + assert_eq!(opcode, Instruction::RType(RInstruction::ShiftLeftLogical)); +} From 03a0f8a406e6e97656cbb0c48bb0840d870dbe73 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Mon, 25 Nov 2024 15:25:34 +0100 Subject: [PATCH 038/165] o1vm/riscv32im: test decoding slt --- o1vm/src/interpreters/riscv32im/tests.rs | 36 ++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/o1vm/src/interpreters/riscv32im/tests.rs b/o1vm/src/interpreters/riscv32im/tests.rs index 30c07c7b2a..e1cf1eaaf9 100644 --- a/o1vm/src/interpreters/riscv32im/tests.rs +++ b/o1vm/src/interpreters/riscv32im/tests.rs @@ -89,6 +89,29 @@ pub fn generate_random_sll_instruction(rng: &mut RNG) ] } +pub fn generate_random_slt_instruction(rng: &mut RNG) -> [u8; 4] { + let opcode = 0b0110011; + let rd = rng.gen_range(0..32); + let funct3 = 0b010; + let rs1 = rng.gen_range(0..32); + let rs2 = rng.gen_range(0..32); + let funct2 = 0b00; + let funct5 = 0b00000; + let instruction = opcode + | (rd << 7) + | (funct3 << 12) + | (rs1 << 15) + | (rs2 << 20) + | (funct2 << 25) + | (funct5 << 27); + [ + instruction as u8, + (instruction >> 8) as u8, + (instruction >> 16) as u8, + (instruction >> 24) as u8, + ] +} + #[test] pub fn test_instruction_decoding_add() { let mut env: Env = dummy_env(); @@ -127,3 +150,16 @@ pub fn test_instruction_decoding_sll() { let (opcode, _instruction) = env.decode_instruction(); assert_eq!(opcode, Instruction::RType(RInstruction::ShiftLeftLogical)); } + +#[test] +pub fn test_instruction_decoding_slt() { + let mut env: Env = dummy_env(); + let mut rng = o1_utils::tests::make_test_rng(None); + let instruction = generate_random_slt_instruction(&mut rng); + env.memory[0].1[0] = instruction[0]; + env.memory[0].1[1] = instruction[1]; + env.memory[0].1[2] = instruction[2]; + env.memory[0].1[3] = instruction[3]; + let (opcode, _instruction) = env.decode_instruction(); + assert_eq!(opcode, Instruction::RType(RInstruction::SetLessThan)); +} From 7fe11496e885065283ba269f13adf82b959ec0dd Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Mon, 25 Nov 2024 15:28:35 +0100 Subject: [PATCH 039/165] o1vm/riscv32im: test decoding sltu --- o1vm/src/interpreters/riscv32im/tests.rs | 39 ++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/o1vm/src/interpreters/riscv32im/tests.rs b/o1vm/src/interpreters/riscv32im/tests.rs index e1cf1eaaf9..730361fc63 100644 --- a/o1vm/src/interpreters/riscv32im/tests.rs +++ b/o1vm/src/interpreters/riscv32im/tests.rs @@ -112,6 +112,29 @@ pub fn generate_random_slt_instruction(rng: &mut RNG) ] } +pub fn generate_random_sltu_instruction(rng: &mut RNG) -> [u8; 4] { + let opcode = 0b0110011; + let rd = rng.gen_range(0..32); + let funct3 = 0b011; + let rs1 = rng.gen_range(0..32); + let rs2 = rng.gen_range(0..32); + let funct2 = 0b00; + let funct5 = 0b00000; + let instruction = opcode + | (rd << 7) + | (funct3 << 12) + | (rs1 << 15) + | (rs2 << 20) + | (funct2 << 25) + | (funct5 << 27); + [ + instruction as u8, + (instruction >> 8) as u8, + (instruction >> 16) as u8, + (instruction >> 24) as u8, + ] +} + #[test] pub fn test_instruction_decoding_add() { let mut env: Env = dummy_env(); @@ -163,3 +186,19 @@ pub fn test_instruction_decoding_slt() { let (opcode, _instruction) = env.decode_instruction(); assert_eq!(opcode, Instruction::RType(RInstruction::SetLessThan)); } + +#[test] +pub fn test_instruction_decoding_sltu() { + let mut env: Env = dummy_env(); + let mut rng = o1_utils::tests::make_test_rng(None); + let instruction = generate_random_sltu_instruction(&mut rng); + env.memory[0].1[0] = instruction[0]; + env.memory[0].1[1] = instruction[1]; + env.memory[0].1[2] = instruction[2]; + env.memory[0].1[3] = instruction[3]; + let (opcode, _instruction) = env.decode_instruction(); + assert_eq!( + opcode, + Instruction::RType(RInstruction::SetLessThanUnsigned) + ); +} From c12f57805234ed65f899f39583dbbe8746b2662e Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Mon, 25 Nov 2024 15:30:50 +0100 Subject: [PATCH 040/165] o1vm/riscv32im: test decoding xor --- o1vm/src/interpreters/riscv32im/tests.rs | 36 ++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/o1vm/src/interpreters/riscv32im/tests.rs b/o1vm/src/interpreters/riscv32im/tests.rs index 730361fc63..025a81f17c 100644 --- a/o1vm/src/interpreters/riscv32im/tests.rs +++ b/o1vm/src/interpreters/riscv32im/tests.rs @@ -112,6 +112,29 @@ pub fn generate_random_slt_instruction(rng: &mut RNG) ] } +pub fn generate_random_xor_instruction(rng: &mut RNG) -> [u8; 4] { + let opcode = 0b0110011; + let rd = rng.gen_range(0..32); + let funct3 = 0b100; + let rs1 = rng.gen_range(0..32); + let rs2 = rng.gen_range(0..32); + let funct2 = 0b00; + let funct5 = 0b00000; + let instruction = opcode + | (rd << 7) + | (funct3 << 12) + | (rs1 << 15) + | (rs2 << 20) + | (funct2 << 25) + | (funct5 << 27); + [ + instruction as u8, + (instruction >> 8) as u8, + (instruction >> 16) as u8, + (instruction >> 24) as u8, + ] +} + pub fn generate_random_sltu_instruction(rng: &mut RNG) -> [u8; 4] { let opcode = 0b0110011; let rd = rng.gen_range(0..32); @@ -202,3 +225,16 @@ pub fn test_instruction_decoding_sltu() { Instruction::RType(RInstruction::SetLessThanUnsigned) ); } + +#[test] +pub fn test_instruction_decoding_xor() { + let mut env: Env = dummy_env(); + let mut rng = o1_utils::tests::make_test_rng(None); + let instruction = generate_random_xor_instruction(&mut rng); + env.memory[0].1[0] = instruction[0]; + env.memory[0].1[1] = instruction[1]; + env.memory[0].1[2] = instruction[2]; + env.memory[0].1[3] = instruction[3]; + let (opcode, _instruction) = env.decode_instruction(); + assert_eq!(opcode, Instruction::RType(RInstruction::Xor)); +} From 37d0db095d52f5754a5391f57e968b132ff09141 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Mon, 25 Nov 2024 15:32:50 +0100 Subject: [PATCH 041/165] o1vm/riscv32im: test decoding srl --- o1vm/src/interpreters/riscv32im/tests.rs | 36 ++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/o1vm/src/interpreters/riscv32im/tests.rs b/o1vm/src/interpreters/riscv32im/tests.rs index 025a81f17c..66d474932f 100644 --- a/o1vm/src/interpreters/riscv32im/tests.rs +++ b/o1vm/src/interpreters/riscv32im/tests.rs @@ -158,6 +158,29 @@ pub fn generate_random_sltu_instruction(rng: &mut RNG) ] } +pub fn generate_random_srl_instruction(rng: &mut RNG) -> [u8; 4] { + let opcode = 0b0110011; + let rd = rng.gen_range(0..32); + let funct3 = 0b101; + let rs1 = rng.gen_range(0..32); + let rs2 = rng.gen_range(0..32); + let funct2 = 0b00; + let funct5 = 0b00000; + let instruction = opcode + | (rd << 7) + | (funct3 << 12) + | (rs1 << 15) + | (rs2 << 20) + | (funct2 << 25) + | (funct5 << 27); + [ + instruction as u8, + (instruction >> 8) as u8, + (instruction >> 16) as u8, + (instruction >> 24) as u8, + ] +} + #[test] pub fn test_instruction_decoding_add() { let mut env: Env = dummy_env(); @@ -238,3 +261,16 @@ pub fn test_instruction_decoding_xor() { let (opcode, _instruction) = env.decode_instruction(); assert_eq!(opcode, Instruction::RType(RInstruction::Xor)); } + +#[test] +pub fn test_instruction_decoding_srl() { + let mut env: Env = dummy_env(); + let mut rng = o1_utils::tests::make_test_rng(None); + let instruction = generate_random_srl_instruction(&mut rng); + env.memory[0].1[0] = instruction[0]; + env.memory[0].1[1] = instruction[1]; + env.memory[0].1[2] = instruction[2]; + env.memory[0].1[3] = instruction[3]; + let (opcode, _instruction) = env.decode_instruction(); + assert_eq!(opcode, Instruction::RType(RInstruction::ShiftRightLogical)); +} From f98062c2db308a5628de8a7ca9f61de55cb21432 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Mon, 25 Nov 2024 15:34:37 +0100 Subject: [PATCH 042/165] o1vm/riscv32im: test decoding sra --- o1vm/src/interpreters/riscv32im/tests.rs | 39 ++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/o1vm/src/interpreters/riscv32im/tests.rs b/o1vm/src/interpreters/riscv32im/tests.rs index 66d474932f..ea674b5298 100644 --- a/o1vm/src/interpreters/riscv32im/tests.rs +++ b/o1vm/src/interpreters/riscv32im/tests.rs @@ -181,6 +181,29 @@ pub fn generate_random_srl_instruction(rng: &mut RNG) ] } +pub fn generate_random_sra_instruction(rng: &mut RNG) -> [u8; 4] { + let opcode = 0b0110011; + let rd = rng.gen_range(0..32); + let funct3 = 0b101; + let rs1 = rng.gen_range(0..32); + let rs2 = rng.gen_range(0..32); + let funct2 = 0b00; + let funct5 = 0b01000; + let instruction = opcode + | (rd << 7) + | (funct3 << 12) + | (rs1 << 15) + | (rs2 << 20) + | (funct2 << 25) + | (funct5 << 27); + [ + instruction as u8, + (instruction >> 8) as u8, + (instruction >> 16) as u8, + (instruction >> 24) as u8, + ] +} + #[test] pub fn test_instruction_decoding_add() { let mut env: Env = dummy_env(); @@ -274,3 +297,19 @@ pub fn test_instruction_decoding_srl() { let (opcode, _instruction) = env.decode_instruction(); assert_eq!(opcode, Instruction::RType(RInstruction::ShiftRightLogical)); } + +#[test] +pub fn test_instruction_decoding_sr1() { + let mut env: Env = dummy_env(); + let mut rng = o1_utils::tests::make_test_rng(None); + let instruction = generate_random_sra_instruction(&mut rng); + env.memory[0].1[0] = instruction[0]; + env.memory[0].1[1] = instruction[1]; + env.memory[0].1[2] = instruction[2]; + env.memory[0].1[3] = instruction[3]; + let (opcode, _instruction) = env.decode_instruction(); + assert_eq!( + opcode, + Instruction::RType(RInstruction::ShiftRightArithmetic) + ); +} From 71c27a784a6f8337ad913f6de582ff9d66cd5ac5 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Mon, 25 Nov 2024 15:36:50 +0100 Subject: [PATCH 043/165] o1vm/riscv32im: test decoding or --- o1vm/src/interpreters/riscv32im/tests.rs | 36 ++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/o1vm/src/interpreters/riscv32im/tests.rs b/o1vm/src/interpreters/riscv32im/tests.rs index ea674b5298..50e9b04e1d 100644 --- a/o1vm/src/interpreters/riscv32im/tests.rs +++ b/o1vm/src/interpreters/riscv32im/tests.rs @@ -204,6 +204,29 @@ pub fn generate_random_sra_instruction(rng: &mut RNG) ] } +pub fn generate_random_or_instruction(rng: &mut RNG) -> [u8; 4] { + let opcode = 0b0110011; + let rd = rng.gen_range(0..32); + let funct3 = 0b110; + let rs1 = rng.gen_range(0..32); + let rs2 = rng.gen_range(0..32); + let funct2 = 0b00; + let funct5 = 0b00000; + let instruction = opcode + | (rd << 7) + | (funct3 << 12) + | (rs1 << 15) + | (rs2 << 20) + | (funct2 << 25) + | (funct5 << 27); + [ + instruction as u8, + (instruction >> 8) as u8, + (instruction >> 16) as u8, + (instruction >> 24) as u8, + ] +} + #[test] pub fn test_instruction_decoding_add() { let mut env: Env = dummy_env(); @@ -313,3 +336,16 @@ pub fn test_instruction_decoding_sr1() { Instruction::RType(RInstruction::ShiftRightArithmetic) ); } + +#[test] +pub fn test_instruction_decoding_or() { + let mut env: Env = dummy_env(); + let mut rng = o1_utils::tests::make_test_rng(None); + let instruction = generate_random_or_instruction(&mut rng); + env.memory[0].1[0] = instruction[0]; + env.memory[0].1[1] = instruction[1]; + env.memory[0].1[2] = instruction[2]; + env.memory[0].1[3] = instruction[3]; + let (opcode, _instruction) = env.decode_instruction(); + assert_eq!(opcode, Instruction::RType(RInstruction::Or)); +} From d4d42ae4f48acf6d1ab97cbff4dea40f16f25813 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Mon, 25 Nov 2024 15:40:57 +0100 Subject: [PATCH 044/165] o1vm/riscv32im: test decoding and --- o1vm/src/interpreters/riscv32im/tests.rs | 36 ++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/o1vm/src/interpreters/riscv32im/tests.rs b/o1vm/src/interpreters/riscv32im/tests.rs index 50e9b04e1d..41b1c5b830 100644 --- a/o1vm/src/interpreters/riscv32im/tests.rs +++ b/o1vm/src/interpreters/riscv32im/tests.rs @@ -227,6 +227,29 @@ pub fn generate_random_or_instruction(rng: &mut RNG) - ] } +pub fn generate_random_and_instruction(rng: &mut RNG) -> [u8; 4] { + let opcode = 0b0110011; + let rd = rng.gen_range(0..32); + let funct3 = 0b111; + let rs1 = rng.gen_range(0..32); + let rs2 = rng.gen_range(0..32); + let funct2 = 0b00; + let funct5 = 0b00000; + let instruction = opcode + | (rd << 7) + | (funct3 << 12) + | (rs1 << 15) + | (rs2 << 20) + | (funct2 << 25) + | (funct5 << 27); + [ + instruction as u8, + (instruction >> 8) as u8, + (instruction >> 16) as u8, + (instruction >> 24) as u8, + ] +} + #[test] pub fn test_instruction_decoding_add() { let mut env: Env = dummy_env(); @@ -349,3 +372,16 @@ pub fn test_instruction_decoding_or() { let (opcode, _instruction) = env.decode_instruction(); assert_eq!(opcode, Instruction::RType(RInstruction::Or)); } + +#[test] +pub fn test_instruction_decoding_and() { + let mut env: Env = dummy_env(); + let mut rng = o1_utils::tests::make_test_rng(None); + let instruction = generate_random_and_instruction(&mut rng); + env.memory[0].1[0] = instruction[0]; + env.memory[0].1[1] = instruction[1]; + env.memory[0].1[2] = instruction[2]; + env.memory[0].1[3] = instruction[3]; + let (opcode, _instruction) = env.decode_instruction(); + assert_eq!(opcode, Instruction::RType(RInstruction::And)); +} From 52dfdea6693f475f9d9b24441aba6613acd1958b Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Mon, 25 Nov 2024 11:23:07 +0100 Subject: [PATCH 045/165] o1vm/riscv32im: decode M instruction type --- o1vm/src/interpreters/riscv32im/witness.rs | 93 +++++++++++++++------- 1 file changed, 66 insertions(+), 27 deletions(-) diff --git a/o1vm/src/interpreters/riscv32im/witness.rs b/o1vm/src/interpreters/riscv32im/witness.rs index 61db4cdd2a..d08bd4b0f9 100644 --- a/o1vm/src/interpreters/riscv32im/witness.rs +++ b/o1vm/src/interpreters/riscv32im/witness.rs @@ -3,8 +3,8 @@ use super::{ column::Column, interpreter::{ - self, IInstruction, Instruction, InterpreterEnv, RInstruction, SBInstruction, SInstruction, - SyscallInstruction, UInstruction, UJInstruction, + self, IInstruction, Instruction, InterpreterEnv, MInstruction, RInstruction, SBInstruction, + SInstruction, SyscallInstruction, UInstruction, UJInstruction, }, registers::Registers, INSTRUCTION_SET_SIZE, SCRATCH_SIZE, @@ -735,31 +735,70 @@ impl Env { }, _ => panic!("Unknown IType instruction with full inst {}", instruction), }, - 0b0110011 => - match (instruction >> 12) & 0x7 // bits 12-14 for func3 - { - 0b000 => - match (instruction >> 30) & 0x1 // bit 30 of funct5 component in RType - { - 0b0 => Instruction::RType(RInstruction::Add), - 0b1 => Instruction::RType(RInstruction::Sub), - _ => panic!("Unknown RType in add/sub instructions with full inst {}", instruction), - }, - 0b001 => Instruction::RType(RInstruction::ShiftLeftLogical), - 0b010 => Instruction::RType(RInstruction::SetLessThan), - 0b011 => Instruction::RType(RInstruction::SetLessThanUnsigned), - 0b100 => Instruction::RType(RInstruction::Xor), - 0b101 => - match (instruction >> 30) & 0x1 // bit 30 of funct5 component in RType - { - 0b0 => Instruction::RType(RInstruction::ShiftRightLogical), - 0b1 => Instruction::RType(RInstruction::ShiftRightArithmetic), - _ => panic!("Unknown RType in shift right instructions with full inst {}", instruction), - }, - 0b110 => Instruction::RType(RInstruction::Or), - 0b111 => Instruction::RType(RInstruction::And), - _ => panic!("Unknown RType 0110011 instruction with full inst {}", instruction), - }, + 0b0110011 => { + let funct5 = instruction >> 27 & 0x1F; // bits 27-31 for funct5 + let funct2 = instruction >> 25 & 0x3; // bits 25-26 for func2 + let funct3 = instruction >> 12 & 0x7; // bits 12-14 for func3 + match funct2 { + // These are the instructions for the base integer set + 0b00 => { + // The integer set have two sets of instructions + // using a different funct5 value + match funct5 { + 0b00000 => { + // Note: all possible values are handled here + match funct3 { + 0b000 => Instruction::RType(RInstruction::Add), + 0b001 => Instruction::RType(RInstruction::ShiftLeftLogical), + 0b010 => Instruction::RType(RInstruction::SetLessThan), + 0b011 => Instruction::RType(RInstruction::SetLessThanUnsigned), + 0b100 => Instruction::RType(RInstruction::Xor), + 0b101 => Instruction::RType(RInstruction::ShiftRightLogical), + 0b110 => Instruction::RType(RInstruction::Or), + 0b111 => Instruction::RType(RInstruction::And), + _ => panic!("This case should never happen as funct3 is 8 bits long and all possible case are implemented. However, we still have an unknown opcode 0110011 instruction with full inst {} (funct5 = {}, funct2 = {}, funct3 = {})", instruction, funct5, funct2, funct3), + } + }, + // Note that there are still some values unhandled here. + 0b01000 => { + // Note that there are still 6 values unhandled here. + match funct3 { + 0b000 => Instruction::RType(RInstruction::Sub), + 0b101 => Instruction::RType(RInstruction::ShiftRightArithmetic), + _ => panic!("Unknown opcode 0110011 instruction with full inst {} (funct5 = {}, funct2 = {}, funct3 = {})", instruction, funct5, funct2, funct3), + } + }, + // All the unhandled cases + 1_u32..=7_u32 | 9_u32..=u32::MAX => + panic!("Unknown opcode 0110011 instruction with full inst {} (funct5 = {}, funct2 = {}, funct3 = {})", instruction, funct5, funct2, funct3), + } + }, + // These are the instructions for the M type + 0b01 => { + match funct5 { + // All instructions for the M type have the same + // funct5 value. Still catching it here to be + // sure we do not misinterpret an instruction + 0b00000 => { + match funct3 { + 0b000 => Instruction::MType(MInstruction::Mul), + 0b001 => Instruction::MType(MInstruction::Mulh), + 0b010 => Instruction::MType(MInstruction::Mulhsu), + 0b011 => Instruction::MType(MInstruction::Mulhu), + 0b100 => Instruction::MType(MInstruction::Div), + 0b101 => Instruction::MType(MInstruction::Divu), + 0b110 => Instruction::MType(MInstruction::Rem), + 0b111 => Instruction::MType(MInstruction::Remu), + _ => panic!("This case should never happen as funct3 is 8 bits long and all possible case are implemented. However, we still have an unknown opcode 0110011 instruction with full inst {} (funct5 = {}, funct2 = {}, funct3 = {})", instruction, funct5, funct2, funct3), + } + }, + // Note that there are still some values unhandled here. + 1_u32..=u32::MAX => panic!("Unknown 0110011 instruction with full inst {} (funct5 = {}, funct2 = {}, funct3 = {})", instruction, funct5, funct2, funct3), + } + }, + _ => panic!("Unknown RType 0110011 instruction with full inst {} (funct5 = {}, funct2 = {}, funct3 = {})", instruction, funct5, funct2, funct3), + } + } 0b0001111 => match (instruction >> 12) & 0x7 // bits 12-14 for func3 { From db6c0f3047b4fa37e963c67255d168159e2f8ad3 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Mon, 25 Nov 2024 15:49:36 +0100 Subject: [PATCH 046/165] o1vm/riscv32im: test decoding mul --- o1vm/src/interpreters/riscv32im/tests.rs | 38 +++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/o1vm/src/interpreters/riscv32im/tests.rs b/o1vm/src/interpreters/riscv32im/tests.rs index 41b1c5b830..8965109c34 100644 --- a/o1vm/src/interpreters/riscv32im/tests.rs +++ b/o1vm/src/interpreters/riscv32im/tests.rs @@ -1,5 +1,5 @@ use super::{registers::Registers, witness::Env, INSTRUCTION_SET_SIZE, PAGE_SIZE, SCRATCH_SIZE}; -use crate::interpreters::riscv32im::interpreter::{Instruction, RInstruction}; +use crate::interpreters::riscv32im::interpreter::{Instruction, MInstruction, RInstruction}; use ark_ff::Zero; use mina_curves::pasta::Fp; use rand::{CryptoRng, Rng, RngCore}; @@ -250,6 +250,29 @@ pub fn generate_random_and_instruction(rng: &mut RNG) ] } +pub fn generate_random_mul_instruction(rng: &mut RNG) -> [u8; 4] { + let opcode = 0b0110011; + let rd = rng.gen_range(0..32); + let funct3 = 0b000; + let rs1 = rng.gen_range(0..32); + let rs2 = rng.gen_range(0..32); + let funct2 = 0b01; + let funct5 = 0b00000; + let instruction = opcode + | (rd << 7) + | (funct3 << 12) + | (rs1 << 15) + | (rs2 << 20) + | (funct2 << 25) + | (funct5 << 27); + [ + instruction as u8, + (instruction >> 8) as u8, + (instruction >> 16) as u8, + (instruction >> 24) as u8, + ] +} + #[test] pub fn test_instruction_decoding_add() { let mut env: Env = dummy_env(); @@ -385,3 +408,16 @@ pub fn test_instruction_decoding_and() { let (opcode, _instruction) = env.decode_instruction(); assert_eq!(opcode, Instruction::RType(RInstruction::And)); } + +#[test] +pub fn test_instruction_decoding_mul() { + let mut env: Env = dummy_env(); + let mut rng = o1_utils::tests::make_test_rng(None); + let instruction = generate_random_mul_instruction(&mut rng); + env.memory[0].1[0] = instruction[0]; + env.memory[0].1[1] = instruction[1]; + env.memory[0].1[2] = instruction[2]; + env.memory[0].1[3] = instruction[3]; + let (opcode, _instruction) = env.decode_instruction(); + assert_eq!(opcode, Instruction::MType(MInstruction::Mul)); +} From 0ac97b1dfc8f6098ad865bd62c1223742ce32a86 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Mon, 25 Nov 2024 15:51:31 +0100 Subject: [PATCH 047/165] o1vm/riscv32im: test decoding mulh --- o1vm/src/interpreters/riscv32im/tests.rs | 36 ++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/o1vm/src/interpreters/riscv32im/tests.rs b/o1vm/src/interpreters/riscv32im/tests.rs index 8965109c34..53184b9a69 100644 --- a/o1vm/src/interpreters/riscv32im/tests.rs +++ b/o1vm/src/interpreters/riscv32im/tests.rs @@ -273,6 +273,29 @@ pub fn generate_random_mul_instruction(rng: &mut RNG) ] } +pub fn generate_random_mulh_instruction(rng: &mut RNG) -> [u8; 4] { + let opcode = 0b0110011; + let rd = rng.gen_range(0..32); + let funct3 = 0b001; + let rs1 = rng.gen_range(0..32); + let rs2 = rng.gen_range(0..32); + let funct2 = 0b01; + let funct5 = 0b00000; + let instruction = opcode + | (rd << 7) + | (funct3 << 12) + | (rs1 << 15) + | (rs2 << 20) + | (funct2 << 25) + | (funct5 << 27); + [ + instruction as u8, + (instruction >> 8) as u8, + (instruction >> 16) as u8, + (instruction >> 24) as u8, + ] +} + #[test] pub fn test_instruction_decoding_add() { let mut env: Env = dummy_env(); @@ -421,3 +444,16 @@ pub fn test_instruction_decoding_mul() { let (opcode, _instruction) = env.decode_instruction(); assert_eq!(opcode, Instruction::MType(MInstruction::Mul)); } + +#[test] +pub fn test_instruction_decoding_mulh() { + let mut env: Env = dummy_env(); + let mut rng = o1_utils::tests::make_test_rng(None); + let instruction = generate_random_mulh_instruction(&mut rng); + env.memory[0].1[0] = instruction[0]; + env.memory[0].1[1] = instruction[1]; + env.memory[0].1[2] = instruction[2]; + env.memory[0].1[3] = instruction[3]; + let (opcode, _instruction) = env.decode_instruction(); + assert_eq!(opcode, Instruction::MType(MInstruction::Mulh)); +} From d0238b14743ddc1f0001caabc269f9880e9a6795 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Mon, 25 Nov 2024 15:53:53 +0100 Subject: [PATCH 048/165] o1vm/riscv32im: test decoding mulhsu --- o1vm/src/interpreters/riscv32im/tests.rs | 36 ++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/o1vm/src/interpreters/riscv32im/tests.rs b/o1vm/src/interpreters/riscv32im/tests.rs index 53184b9a69..046de2f4cd 100644 --- a/o1vm/src/interpreters/riscv32im/tests.rs +++ b/o1vm/src/interpreters/riscv32im/tests.rs @@ -296,6 +296,29 @@ pub fn generate_random_mulh_instruction(rng: &mut RNG) ] } +pub fn generate_random_mulhsu_instruction(rng: &mut RNG) -> [u8; 4] { + let opcode = 0b0110011; + let rd = rng.gen_range(0..32); + let funct3 = 0b010; + let rs1 = rng.gen_range(0..32); + let rs2 = rng.gen_range(0..32); + let funct2 = 0b01; + let funct5 = 0b00000; + let instruction = opcode + | (rd << 7) + | (funct3 << 12) + | (rs1 << 15) + | (rs2 << 20) + | (funct2 << 25) + | (funct5 << 27); + [ + instruction as u8, + (instruction >> 8) as u8, + (instruction >> 16) as u8, + (instruction >> 24) as u8, + ] +} + #[test] pub fn test_instruction_decoding_add() { let mut env: Env = dummy_env(); @@ -457,3 +480,16 @@ pub fn test_instruction_decoding_mulh() { let (opcode, _instruction) = env.decode_instruction(); assert_eq!(opcode, Instruction::MType(MInstruction::Mulh)); } + +#[test] +pub fn test_instruction_decoding_mulhsu() { + let mut env: Env = dummy_env(); + let mut rng = o1_utils::tests::make_test_rng(None); + let instruction = generate_random_mulhsu_instruction(&mut rng); + env.memory[0].1[0] = instruction[0]; + env.memory[0].1[1] = instruction[1]; + env.memory[0].1[2] = instruction[2]; + env.memory[0].1[3] = instruction[3]; + let (opcode, _instruction) = env.decode_instruction(); + assert_eq!(opcode, Instruction::MType(MInstruction::Mulhsu)); +} From dce529cdca704a2aed559618a3993b9c4910a6a1 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Mon, 25 Nov 2024 15:55:45 +0100 Subject: [PATCH 049/165] o1vm/riscv32im: test decoding mulhu --- o1vm/src/interpreters/riscv32im/tests.rs | 36 ++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/o1vm/src/interpreters/riscv32im/tests.rs b/o1vm/src/interpreters/riscv32im/tests.rs index 046de2f4cd..b50df9f05e 100644 --- a/o1vm/src/interpreters/riscv32im/tests.rs +++ b/o1vm/src/interpreters/riscv32im/tests.rs @@ -319,6 +319,29 @@ pub fn generate_random_mulhsu_instruction(rng: &mut RN ] } +pub fn generate_random_mulhu_instruction(rng: &mut RNG) -> [u8; 4] { + let opcode = 0b0110011; + let rd = rng.gen_range(0..32); + let funct3 = 0b011; + let rs1 = rng.gen_range(0..32); + let rs2 = rng.gen_range(0..32); + let funct2 = 0b01; + let funct5 = 0b00000; + let instruction = opcode + | (rd << 7) + | (funct3 << 12) + | (rs1 << 15) + | (rs2 << 20) + | (funct2 << 25) + | (funct5 << 27); + [ + instruction as u8, + (instruction >> 8) as u8, + (instruction >> 16) as u8, + (instruction >> 24) as u8, + ] +} + #[test] pub fn test_instruction_decoding_add() { let mut env: Env = dummy_env(); @@ -493,3 +516,16 @@ pub fn test_instruction_decoding_mulhsu() { let (opcode, _instruction) = env.decode_instruction(); assert_eq!(opcode, Instruction::MType(MInstruction::Mulhsu)); } + +#[test] +pub fn test_instruction_decoding_mulhu() { + let mut env: Env = dummy_env(); + let mut rng = o1_utils::tests::make_test_rng(None); + let instruction = generate_random_mulhu_instruction(&mut rng); + env.memory[0].1[0] = instruction[0]; + env.memory[0].1[1] = instruction[1]; + env.memory[0].1[2] = instruction[2]; + env.memory[0].1[3] = instruction[3]; + let (opcode, _instruction) = env.decode_instruction(); + assert_eq!(opcode, Instruction::MType(MInstruction::Mulhu)); +} From 299eb881a676cecccc3457fdbfa9c7d1a0411dc8 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Mon, 25 Nov 2024 15:57:38 +0100 Subject: [PATCH 050/165] o1vm/riscv32im: test decoding div --- o1vm/src/interpreters/riscv32im/tests.rs | 36 ++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/o1vm/src/interpreters/riscv32im/tests.rs b/o1vm/src/interpreters/riscv32im/tests.rs index b50df9f05e..3f1d131e80 100644 --- a/o1vm/src/interpreters/riscv32im/tests.rs +++ b/o1vm/src/interpreters/riscv32im/tests.rs @@ -342,6 +342,29 @@ pub fn generate_random_mulhu_instruction(rng: &mut RNG ] } +pub fn generate_random_div_instruction(rng: &mut RNG) -> [u8; 4] { + let opcode = 0b0110011; + let rd = rng.gen_range(0..32); + let funct3 = 0b100; + let rs1 = rng.gen_range(0..32); + let rs2 = rng.gen_range(0..32); + let funct2 = 0b01; + let funct5 = 0b00000; + let instruction = opcode + | (rd << 7) + | (funct3 << 12) + | (rs1 << 15) + | (rs2 << 20) + | (funct2 << 25) + | (funct5 << 27); + [ + instruction as u8, + (instruction >> 8) as u8, + (instruction >> 16) as u8, + (instruction >> 24) as u8, + ] +} + #[test] pub fn test_instruction_decoding_add() { let mut env: Env = dummy_env(); @@ -529,3 +552,16 @@ pub fn test_instruction_decoding_mulhu() { let (opcode, _instruction) = env.decode_instruction(); assert_eq!(opcode, Instruction::MType(MInstruction::Mulhu)); } + +#[test] +pub fn test_instruction_decoding_div() { + let mut env: Env = dummy_env(); + let mut rng = o1_utils::tests::make_test_rng(None); + let instruction = generate_random_div_instruction(&mut rng); + env.memory[0].1[0] = instruction[0]; + env.memory[0].1[1] = instruction[1]; + env.memory[0].1[2] = instruction[2]; + env.memory[0].1[3] = instruction[3]; + let (opcode, _instruction) = env.decode_instruction(); + assert_eq!(opcode, Instruction::MType(MInstruction::Div)); +} From 8734221cbad53da2971d5902055d4ee6ac994043 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Mon, 25 Nov 2024 15:58:41 +0100 Subject: [PATCH 051/165] o1vm/riscv32im: test decoding divu --- o1vm/src/interpreters/riscv32im/tests.rs | 36 ++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/o1vm/src/interpreters/riscv32im/tests.rs b/o1vm/src/interpreters/riscv32im/tests.rs index 3f1d131e80..de63b16e70 100644 --- a/o1vm/src/interpreters/riscv32im/tests.rs +++ b/o1vm/src/interpreters/riscv32im/tests.rs @@ -365,6 +365,29 @@ pub fn generate_random_div_instruction(rng: &mut RNG) ] } +pub fn generate_random_divu_instruction(rng: &mut RNG) -> [u8; 4] { + let opcode = 0b0110011; + let rd = rng.gen_range(0..32); + let funct3 = 0b101; + let rs1 = rng.gen_range(0..32); + let rs2 = rng.gen_range(0..32); + let funct2 = 0b01; + let funct5 = 0b00000; + let instruction = opcode + | (rd << 7) + | (funct3 << 12) + | (rs1 << 15) + | (rs2 << 20) + | (funct2 << 25) + | (funct5 << 27); + [ + instruction as u8, + (instruction >> 8) as u8, + (instruction >> 16) as u8, + (instruction >> 24) as u8, + ] +} + #[test] pub fn test_instruction_decoding_add() { let mut env: Env = dummy_env(); @@ -565,3 +588,16 @@ pub fn test_instruction_decoding_div() { let (opcode, _instruction) = env.decode_instruction(); assert_eq!(opcode, Instruction::MType(MInstruction::Div)); } + +#[test] +pub fn test_instruction_decoding_divu() { + let mut env: Env = dummy_env(); + let mut rng = o1_utils::tests::make_test_rng(None); + let instruction = generate_random_divu_instruction(&mut rng); + env.memory[0].1[0] = instruction[0]; + env.memory[0].1[1] = instruction[1]; + env.memory[0].1[2] = instruction[2]; + env.memory[0].1[3] = instruction[3]; + let (opcode, _instruction) = env.decode_instruction(); + assert_eq!(opcode, Instruction::MType(MInstruction::Divu)); +} From e11965e774d0b83baf2556c428f862e665106778 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Mon, 25 Nov 2024 15:59:53 +0100 Subject: [PATCH 052/165] o1vm/riscv32im: test decoding rem --- o1vm/src/interpreters/riscv32im/tests.rs | 36 ++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/o1vm/src/interpreters/riscv32im/tests.rs b/o1vm/src/interpreters/riscv32im/tests.rs index de63b16e70..548f96ca56 100644 --- a/o1vm/src/interpreters/riscv32im/tests.rs +++ b/o1vm/src/interpreters/riscv32im/tests.rs @@ -388,6 +388,29 @@ pub fn generate_random_divu_instruction(rng: &mut RNG) ] } +pub fn generate_random_rem_instruction(rng: &mut RNG) -> [u8; 4] { + let opcode = 0b0110011; + let rd = rng.gen_range(0..32); + let funct3 = 0b110; + let rs1 = rng.gen_range(0..32); + let rs2 = rng.gen_range(0..32); + let funct2 = 0b01; + let funct5 = 0b00000; + let instruction = opcode + | (rd << 7) + | (funct3 << 12) + | (rs1 << 15) + | (rs2 << 20) + | (funct2 << 25) + | (funct5 << 27); + [ + instruction as u8, + (instruction >> 8) as u8, + (instruction >> 16) as u8, + (instruction >> 24) as u8, + ] +} + #[test] pub fn test_instruction_decoding_add() { let mut env: Env = dummy_env(); @@ -601,3 +624,16 @@ pub fn test_instruction_decoding_divu() { let (opcode, _instruction) = env.decode_instruction(); assert_eq!(opcode, Instruction::MType(MInstruction::Divu)); } + +#[test] +pub fn test_instruction_decoding_rem() { + let mut env: Env = dummy_env(); + let mut rng = o1_utils::tests::make_test_rng(None); + let instruction = generate_random_rem_instruction(&mut rng); + env.memory[0].1[0] = instruction[0]; + env.memory[0].1[1] = instruction[1]; + env.memory[0].1[2] = instruction[2]; + env.memory[0].1[3] = instruction[3]; + let (opcode, _instruction) = env.decode_instruction(); + assert_eq!(opcode, Instruction::MType(MInstruction::Rem)); +} From f518c8d6aa280f7f30ad7755e32f2fa7be02a23e Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Mon, 25 Nov 2024 16:01:32 +0100 Subject: [PATCH 053/165] o1vm/riscv32im: test decoding remu --- o1vm/src/interpreters/riscv32im/tests.rs | 36 ++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/o1vm/src/interpreters/riscv32im/tests.rs b/o1vm/src/interpreters/riscv32im/tests.rs index 548f96ca56..4c2305f825 100644 --- a/o1vm/src/interpreters/riscv32im/tests.rs +++ b/o1vm/src/interpreters/riscv32im/tests.rs @@ -411,6 +411,29 @@ pub fn generate_random_rem_instruction(rng: &mut RNG) ] } +pub fn generate_random_remu_instruction(rng: &mut RNG) -> [u8; 4] { + let opcode = 0b0110011; + let rd = rng.gen_range(0..32); + let funct3 = 0b111; + let rs1 = rng.gen_range(0..32); + let rs2 = rng.gen_range(0..32); + let funct2 = 0b01; + let funct5 = 0b00000; + let instruction = opcode + | (rd << 7) + | (funct3 << 12) + | (rs1 << 15) + | (rs2 << 20) + | (funct2 << 25) + | (funct5 << 27); + [ + instruction as u8, + (instruction >> 8) as u8, + (instruction >> 16) as u8, + (instruction >> 24) as u8, + ] +} + #[test] pub fn test_instruction_decoding_add() { let mut env: Env = dummy_env(); @@ -637,3 +660,16 @@ pub fn test_instruction_decoding_rem() { let (opcode, _instruction) = env.decode_instruction(); assert_eq!(opcode, Instruction::MType(MInstruction::Rem)); } + +#[test] +pub fn test_instruction_decoding_remu() { + let mut env: Env = dummy_env(); + let mut rng = o1_utils::tests::make_test_rng(None); + let instruction = generate_random_remu_instruction(&mut rng); + env.memory[0].1[0] = instruction[0]; + env.memory[0].1[1] = instruction[1]; + env.memory[0].1[2] = instruction[2]; + env.memory[0].1[3] = instruction[3]; + let (opcode, _instruction) = env.decode_instruction(); + assert_eq!(opcode, Instruction::MType(MInstruction::Remu)); +} From 20b29d3b59b8e8b7f73e28ffb6f0a6e4993004a7 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Mon, 25 Nov 2024 16:32:03 +0100 Subject: [PATCH 054/165] o1vm: reorganize dependencies in alphabetical order --- o1vm/Cargo.toml | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/o1vm/Cargo.toml b/o1vm/Cargo.toml index 1c14712ece..1e57ce7c0d 100644 --- a/o1vm/Cargo.toml +++ b/o1vm/Cargo.toml @@ -25,41 +25,41 @@ name = "pickles_o1vm" path = "src/pickles/main.rs" [dependencies] -o1-utils.workspace = true # FIXME: Only activate this when legacy_o1vm is built ark-bn254.workspace = true # FIXME: Only activate this when legacy_o1vm is built folding.workspace = true # FIXME: Only activate this when legacy_o1vm is built kimchi = { workspace = true, features = [ "bn254" ] } -kimchi-msm.workspace = true -poly-commitment.workspace = true +ark-ec.workspace = true +ark-ff.workspace = true +ark-poly.workspace = true +base64.workspace = true +clap.workspace = true +command-fds.workspace = true +elf.workspace = true +env_logger.workspace = true groupmap.workspace = true +hex.workspace = true +itertools.workspace = true +kimchi-msm.workspace = true +libc.workspace = true +libflate.workspace = true +log.workspace = true mina-curves.workspace = true mina-poseidon.workspace = true -elf.workspace = true +o1-utils.workspace = true +os_pipe.workspace = true +poly-commitment.workspace = true +rand.workspace = true +rayon.workspace = true +regex.workspace = true rmp-serde.workspace = true -serde_json.workspace = true serde.workspace = true +serde_json.workspace = true serde_with.workspace = true stacker = "0.1" -ark-poly.workspace = true -ark-ff.workspace = true -ark-ec.workspace = true -clap.workspace = true -hex.workspace = true -regex.workspace = true -libflate.workspace = true -base64.workspace = true strum.workspace = true strum_macros.workspace = true -log.workspace = true -env_logger.workspace = true -command-fds.workspace = true -os_pipe.workspace = true -rand.workspace = true -libc.workspace = true -rayon.workspace = true sha3.workspace = true -itertools.workspace = true thiserror.workspace = true \ No newline at end of file From ba54734692ad33ecb7a4627efe0fd53b7f372896 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 20 Nov 2024 16:23:37 +0100 Subject: [PATCH 055/165] o1vm/riscv32: implement mul_hi --- o1vm/src/interpreters/riscv32im/constraints.rs | 9 +++++++++ o1vm/src/interpreters/riscv32im/interpreter.rs | 14 ++++++++++++++ o1vm/src/interpreters/riscv32im/witness.rs | 15 +++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/o1vm/src/interpreters/riscv32im/constraints.rs b/o1vm/src/interpreters/riscv32im/constraints.rs index 82b9cd5105..ef1496ae80 100644 --- a/o1vm/src/interpreters/riscv32im/constraints.rs +++ b/o1vm/src/interpreters/riscv32im/constraints.rs @@ -345,6 +345,15 @@ impl InterpreterEnv for Env { self.variable(position) } + unsafe fn mul_hi( + &mut self, + _x: &Self::Variable, + _y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable { + self.variable(position) + } + unsafe fn mul_hi_lo( &mut self, _x: &Self::Variable, diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index 2cd83827a1..905efe547f 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -1245,6 +1245,20 @@ pub trait InterpreterEnv { position_lo: Self::Position, ) -> (Self::Variable, Self::Variable); + /// Returns `((x * y) >> 32`, storing the results in `position`. + /// + /// # Safety + /// + /// There are no constraints on the returned values; callers must manually add constraints to + /// ensure that the pair of returned values correspond to the given values `x` and `y`, and + /// that they fall within the desired range. + unsafe fn mul_hi( + &mut self, + x: &Self::Variable, + y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable; + /// Returns `((x * y) >> 32, (x * y) & ((1 << 32) - 1))`, storing the results in `position_hi` /// and `position_lo` respectively. /// diff --git a/o1vm/src/interpreters/riscv32im/witness.rs b/o1vm/src/interpreters/riscv32im/witness.rs index 3484ad0a10..fa919adb16 100644 --- a/o1vm/src/interpreters/riscv32im/witness.rs +++ b/o1vm/src/interpreters/riscv32im/witness.rs @@ -490,6 +490,21 @@ impl InterpreterEnv for Env { (hi, lo) } + unsafe fn mul_hi( + &mut self, + x: &Self::Variable, + y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable { + let x: u32 = (*x).try_into().unwrap(); + let y: u32 = (*y).try_into().unwrap(); + let res = (x as u64) * (y as u64); + let res = (res >> 32) as u32; + let res = res as u64; + self.write_column(position, res); + res + } + unsafe fn mul_hi_lo( &mut self, x: &Self::Variable, From 840066e8613d15a3bd7cfeab8c88ba8aece0eb8f Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 20 Nov 2024 16:24:28 +0100 Subject: [PATCH 056/165] o1vm/riscv32: implement mul_lo --- o1vm/src/interpreters/riscv32im/constraints.rs | 9 +++++++++ o1vm/src/interpreters/riscv32im/interpreter.rs | 14 ++++++++++++++ o1vm/src/interpreters/riscv32im/witness.rs | 15 +++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/o1vm/src/interpreters/riscv32im/constraints.rs b/o1vm/src/interpreters/riscv32im/constraints.rs index ef1496ae80..e173e8fecb 100644 --- a/o1vm/src/interpreters/riscv32im/constraints.rs +++ b/o1vm/src/interpreters/riscv32im/constraints.rs @@ -354,6 +354,15 @@ impl InterpreterEnv for Env { self.variable(position) } + unsafe fn mul_lo( + &mut self, + _x: &Self::Variable, + _y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable { + self.variable(position) + } + unsafe fn mul_hi_lo( &mut self, _x: &Self::Variable, diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index 905efe547f..0633895a46 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -1259,6 +1259,20 @@ pub trait InterpreterEnv { position: Self::Position, ) -> Self::Variable; + /// Returns `(x * y) & ((1 << 32) - 1))`, storing the results in `position`. + /// + /// # Safety + /// + /// There are no constraints on the returned values; callers must manually add constraints to + /// ensure that the pair of returned values correspond to the given values `x` and `y`, and + /// that they fall within the desired range. + unsafe fn mul_lo( + &mut self, + x: &Self::Variable, + y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable; + /// Returns `((x * y) >> 32, (x * y) & ((1 << 32) - 1))`, storing the results in `position_hi` /// and `position_lo` respectively. /// diff --git a/o1vm/src/interpreters/riscv32im/witness.rs b/o1vm/src/interpreters/riscv32im/witness.rs index fa919adb16..e358051512 100644 --- a/o1vm/src/interpreters/riscv32im/witness.rs +++ b/o1vm/src/interpreters/riscv32im/witness.rs @@ -505,6 +505,21 @@ impl InterpreterEnv for Env { res } + unsafe fn mul_lo( + &mut self, + x: &Self::Variable, + y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable { + let x: u32 = (*x).try_into().unwrap(); + let y: u32 = (*y).try_into().unwrap(); + let res = (x as u64) * (y as u64); + let res = (res & ((1 << 32) - 1)) as u32; + let res = res as u64; + self.write_column(position, res); + res + } + unsafe fn mul_hi_lo( &mut self, x: &Self::Variable, From 4d833a21d54529aa8406bd74370e196ab8662444 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 20 Nov 2024 16:26:54 +0100 Subject: [PATCH 057/165] o1vm/riscv32: implement M type instruction Mul --- o1vm/src/interpreters/riscv32im/interpreter.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index 0633895a46..3ad530280c 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -2089,7 +2089,7 @@ pub fn interpret_syscall(env: &mut Env, _instr: SyscallInst /// [here](https://www.cs.cornell.edu/courses/cs3410/2024fa/assignments/cpusim/riscv-instructions.pdf) pub fn interpret_mtype(env: &mut Env, instr: MInstruction) { let instruction_pointer = env.get_instruction_pointer(); - let _next_instruction_pointer = env.get_next_instruction_pointer(); + let next_instruction_pointer = env.get_next_instruction_pointer(); let instruction = { let v0 = env.read_memory(&instruction_pointer); @@ -2160,7 +2160,17 @@ pub fn interpret_mtype(env: &mut Env, instr: MInstruction) match instr { MInstruction::Mul => { - unimplemented!("Mul") + let rs1 = env.read_register(&rs1); + let rs2 = env.read_register(&rs2); + // FIXME: constrain + let res = { + let pos = env.alloc_scratch(); + unsafe { env.mul_lo_signed(&rs1, &rs2, pos) } + }; + env.write_register(&rd, res); + + env.set_instruction_pointer(next_instruction_pointer.clone()); + env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); } MInstruction::Mulh => { unimplemented!("Mulh") From 93afc08c23c615005589282136d4a90e2b08e0b0 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 20 Nov 2024 16:28:03 +0100 Subject: [PATCH 058/165] o1vm/riscv32: implement mulh --- o1vm/src/interpreters/riscv32im/interpreter.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index ec959f514d..96a15a9130 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -2222,7 +2222,17 @@ pub fn interpret_mtype(env: &mut Env, instr: MInstruction) env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); } MInstruction::Mulh => { - unimplemented!("Mulh") + let rs1 = env.read_register(&rs1); + let rs2 = env.read_register(&rs2); + // FIXME: constrain + let res = { + let pos = env.alloc_scratch(); + unsafe { env.mul_hi_signed(&rs1, &rs2, pos) } + }; + env.write_register(&rd, res); + + env.set_instruction_pointer(next_instruction_pointer.clone()); + env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); } MInstruction::Mulhsu => { unimplemented!("Mulhsu") From e752cac243d2827994467cb4dcc8fb89e09de95e Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 20 Nov 2024 16:30:38 +0100 Subject: [PATCH 059/165] o1vm/riscv32: implement Mulhu --- o1vm/src/interpreters/riscv32im/interpreter.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index 96a15a9130..721a4de4aa 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -2238,7 +2238,17 @@ pub fn interpret_mtype(env: &mut Env, instr: MInstruction) unimplemented!("Mulhsu") } MInstruction::Mulhu => { - unimplemented!("Mulhu") + let rs1 = env.read_register(&rs1); + let rs2 = env.read_register(&rs2); + // FIXME: constrain + let res = { + let pos = env.alloc_scratch(); + unsafe { env.mul_hi(&rs1, &rs2, pos) } + }; + env.write_register(&rd, res); + + env.set_instruction_pointer(next_instruction_pointer.clone()); + env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); } MInstruction::Div => { unimplemented!("Div") From 4641725fc3dd6eec122f44c23463d9452b07e553 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 20 Nov 2024 16:34:33 +0100 Subject: [PATCH 060/165] o1vm/riscv32: remove unused mul_hi_lo_signed The method is splitted in two different methods, comparetively to MIPS. --- .../src/interpreters/riscv32im/constraints.rs | 10 ---------- .../src/interpreters/riscv32im/interpreter.rs | 16 ---------------- o1vm/src/interpreters/riscv32im/witness.rs | 19 ------------------- 3 files changed, 45 deletions(-) diff --git a/o1vm/src/interpreters/riscv32im/constraints.rs b/o1vm/src/interpreters/riscv32im/constraints.rs index e173e8fecb..21d7ca1fce 100644 --- a/o1vm/src/interpreters/riscv32im/constraints.rs +++ b/o1vm/src/interpreters/riscv32im/constraints.rs @@ -317,16 +317,6 @@ impl InterpreterEnv for Env { self.variable(position) } - unsafe fn mul_hi_lo_signed( - &mut self, - _x: &Self::Variable, - _y: &Self::Variable, - position_hi: Self::Position, - position_lo: Self::Position, - ) -> (Self::Variable, Self::Variable) { - (self.variable(position_hi), self.variable(position_lo)) - } - unsafe fn mul_hi_signed( &mut self, _x: &Self::Variable, diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index 721a4de4aa..82d3b73c8d 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -1229,22 +1229,6 @@ pub trait InterpreterEnv { position: Self::Position, ) -> Self::Variable; - /// Returns `((x * y) >> 32, (x * y) & ((1 << 32) - 1))`, storing the results in `position_hi` - /// and `position_lo` respectively. - /// - /// # Safety - /// - /// There are no constraints on the returned values; callers must manually add constraints to - /// ensure that the pair of returned values correspond to the given values `x` and `y`, and - /// that they fall within the desired range. - unsafe fn mul_hi_lo_signed( - &mut self, - x: &Self::Variable, - y: &Self::Variable, - position_hi: Self::Position, - position_lo: Self::Position, - ) -> (Self::Variable, Self::Variable); - /// Returns `((x * y) >> 32`, storing the results in `position`. /// /// # Safety diff --git a/o1vm/src/interpreters/riscv32im/witness.rs b/o1vm/src/interpreters/riscv32im/witness.rs index e358051512..24cc710f46 100644 --- a/o1vm/src/interpreters/riscv32im/witness.rs +++ b/o1vm/src/interpreters/riscv32im/witness.rs @@ -471,25 +471,6 @@ impl InterpreterEnv for Env { res } - unsafe fn mul_hi_lo_signed( - &mut self, - x: &Self::Variable, - y: &Self::Variable, - position_hi: Self::Position, - position_lo: Self::Position, - ) -> (Self::Variable, Self::Variable) { - let x: u32 = (*x).try_into().unwrap(); - let y: u32 = (*y).try_into().unwrap(); - let mul = (((x as i32) as i64) * ((y as i32) as i64)) as u64; - let hi = (mul >> 32) as u32; - let lo = (mul & ((1 << 32) - 1)) as u32; - let hi = hi as u64; - let lo = lo as u64; - self.write_column(position_hi, hi); - self.write_column(position_lo, lo); - (hi, lo) - } - unsafe fn mul_hi( &mut self, x: &Self::Variable, From f07b581dee5bffd18d0cc352feebba283f079994 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 20 Nov 2024 16:36:28 +0100 Subject: [PATCH 061/165] o1vm/riscv32: remove unused mul_hi_lo. Like mul_hi_lo_signed, the method is splitted in two different methods: mul_hi and mul_lo. --- .../src/interpreters/riscv32im/constraints.rs | 10 ---------- .../src/interpreters/riscv32im/interpreter.rs | 16 ---------------- o1vm/src/interpreters/riscv32im/witness.rs | 19 ------------------- 3 files changed, 45 deletions(-) diff --git a/o1vm/src/interpreters/riscv32im/constraints.rs b/o1vm/src/interpreters/riscv32im/constraints.rs index 21d7ca1fce..c270bee34a 100644 --- a/o1vm/src/interpreters/riscv32im/constraints.rs +++ b/o1vm/src/interpreters/riscv32im/constraints.rs @@ -353,16 +353,6 @@ impl InterpreterEnv for Env { self.variable(position) } - unsafe fn mul_hi_lo( - &mut self, - _x: &Self::Variable, - _y: &Self::Variable, - position_hi: Self::Position, - position_lo: Self::Position, - ) -> (Self::Variable, Self::Variable) { - (self.variable(position_hi), self.variable(position_lo)) - } - unsafe fn divmod_signed( &mut self, _x: &Self::Variable, diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index 82d3b73c8d..cb399f8c61 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -1257,22 +1257,6 @@ pub trait InterpreterEnv { position: Self::Position, ) -> Self::Variable; - /// Returns `((x * y) >> 32, (x * y) & ((1 << 32) - 1))`, storing the results in `position_hi` - /// and `position_lo` respectively. - /// - /// # Safety - /// - /// There are no constraints on the returned values; callers must manually add constraints to - /// ensure that the pair of returned values correspond to the given values `x` and `y`, and - /// that they fall within the desired range. - unsafe fn mul_hi_lo( - &mut self, - x: &Self::Variable, - y: &Self::Variable, - position_hi: Self::Position, - position_lo: Self::Position, - ) -> (Self::Variable, Self::Variable); - /// Returns `(x / y, x % y)`, storing the results in `position_quotient` and /// `position_remainder` respectively. /// diff --git a/o1vm/src/interpreters/riscv32im/witness.rs b/o1vm/src/interpreters/riscv32im/witness.rs index 24cc710f46..10d6508721 100644 --- a/o1vm/src/interpreters/riscv32im/witness.rs +++ b/o1vm/src/interpreters/riscv32im/witness.rs @@ -501,25 +501,6 @@ impl InterpreterEnv for Env { res } - unsafe fn mul_hi_lo( - &mut self, - x: &Self::Variable, - y: &Self::Variable, - position_hi: Self::Position, - position_lo: Self::Position, - ) -> (Self::Variable, Self::Variable) { - let x: u32 = (*x).try_into().unwrap(); - let y: u32 = (*y).try_into().unwrap(); - let mul = (x as u64) * (y as u64); - let hi = (mul >> 32) as u32; - let lo = (mul & ((1 << 32) - 1)) as u32; - let hi = hi as u64; - let lo = lo as u64; - self.write_column(position_hi, hi); - self.write_column(position_lo, lo); - (hi, lo) - } - unsafe fn divmod_signed( &mut self, x: &Self::Variable, From 3815c8a5f69c7d9a748c30c830bdf9bde2f05664 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 20 Nov 2024 16:42:28 +0100 Subject: [PATCH 062/165] o1vm/riscv32: implement div_signed --- o1vm/src/interpreters/riscv32im/constraints.rs | 9 +++++++++ o1vm/src/interpreters/riscv32im/interpreter.rs | 14 ++++++++++++++ o1vm/src/interpreters/riscv32im/witness.rs | 14 ++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/o1vm/src/interpreters/riscv32im/constraints.rs b/o1vm/src/interpreters/riscv32im/constraints.rs index c270bee34a..5f8236aed7 100644 --- a/o1vm/src/interpreters/riscv32im/constraints.rs +++ b/o1vm/src/interpreters/riscv32im/constraints.rs @@ -344,6 +344,15 @@ impl InterpreterEnv for Env { self.variable(position) } + unsafe fn div_signed( + &mut self, + _x: &Self::Variable, + _y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable { + self.variable(position) + } + unsafe fn mul_lo( &mut self, _x: &Self::Variable, diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index df9dd7176e..036107a200 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -1257,6 +1257,20 @@ pub trait InterpreterEnv { position: Self::Position, ) -> Self::Variable; + /// Returns `x / y`, storing the results in `position`. + /// + /// # Safety + /// + /// There are no constraints on the returned values; callers must manually add constraints to + /// ensure that the pair of returned values correspond to the given values `x` and `y`, and + /// that they fall within the desired range. + unsafe fn div_signed( + &mut self, + x: &Self::Variable, + y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable; + /// Returns `(x / y, x % y)`, storing the results in `position_quotient` and /// `position_remainder` respectively. /// diff --git a/o1vm/src/interpreters/riscv32im/witness.rs b/o1vm/src/interpreters/riscv32im/witness.rs index 10d6508721..8b29db4f63 100644 --- a/o1vm/src/interpreters/riscv32im/witness.rs +++ b/o1vm/src/interpreters/riscv32im/witness.rs @@ -486,6 +486,20 @@ impl InterpreterEnv for Env { res } + unsafe fn div_signed( + &mut self, + x: &Self::Variable, + y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable { + let x: u32 = (*x).try_into().unwrap(); + let y: u32 = (*y).try_into().unwrap(); + let res = ((x as i32) / (y as i32)) as u32; + let res = res as u64; + self.write_column(position, res); + res + } + unsafe fn mul_lo( &mut self, x: &Self::Variable, From bb6f118d49fd5fa9b61550e1798d6760a38d6c00 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Mon, 25 Nov 2024 10:53:12 +0100 Subject: [PATCH 063/165] o1vm/riscv32im: simplify div_signed --- o1vm/src/interpreters/riscv32im/witness.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/o1vm/src/interpreters/riscv32im/witness.rs b/o1vm/src/interpreters/riscv32im/witness.rs index 8b29db4f63..895ab46e1c 100644 --- a/o1vm/src/interpreters/riscv32im/witness.rs +++ b/o1vm/src/interpreters/riscv32im/witness.rs @@ -492,9 +492,9 @@ impl InterpreterEnv for Env { y: &Self::Variable, position: Self::Position, ) -> Self::Variable { - let x: u32 = (*x).try_into().unwrap(); - let y: u32 = (*y).try_into().unwrap(); - let res = ((x as i32) / (y as i32)) as u32; + let x: i32 = (*x).try_into().unwrap(); + let y: i32 = (*y).try_into().unwrap(); + let res = (x / y) as u32; let res = res as u64; self.write_column(position, res); res From 7367e4b86bfdd08903ffd5ec4e27bb7be7731eff Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 20 Nov 2024 16:43:33 +0100 Subject: [PATCH 064/165] o1vm/riscv32: implement M type instruction div --- o1vm/src/interpreters/riscv32im/interpreter.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index 036107a200..438abaa065 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -2250,7 +2250,17 @@ pub fn interpret_mtype(env: &mut Env, instr: MInstruction) env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); } MInstruction::Div => { - unimplemented!("Div") + let rs1 = env.read_register(&rs1); + let rs2 = env.read_register(&rs2); + // FIXME: constrain + let res = { + let pos = env.alloc_scratch(); + unsafe { env.div_signed(&rs1, &rs2, pos) } + }; + env.write_register(&rd, res); + + env.set_instruction_pointer(next_instruction_pointer.clone()); + env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); } MInstruction::Divu => { unimplemented!("Divu") From 0ad5fea2a06952e9f1c5dcf10bd08ef9404fcad1 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 20 Nov 2024 16:47:06 +0100 Subject: [PATCH 065/165] o1vm/riscv32: implement mod_signed It will be used to implement MInstruction::Rem in a follow-up PR. --- o1vm/src/interpreters/riscv32im/constraints.rs | 9 +++++++++ o1vm/src/interpreters/riscv32im/interpreter.rs | 14 ++++++++++++++ o1vm/src/interpreters/riscv32im/witness.rs | 14 ++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/o1vm/src/interpreters/riscv32im/constraints.rs b/o1vm/src/interpreters/riscv32im/constraints.rs index 5f8236aed7..67bfa46fea 100644 --- a/o1vm/src/interpreters/riscv32im/constraints.rs +++ b/o1vm/src/interpreters/riscv32im/constraints.rs @@ -353,6 +353,15 @@ impl InterpreterEnv for Env { self.variable(position) } + unsafe fn mod_signed( + &mut self, + _x: &Self::Variable, + _y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable { + self.variable(position) + } + unsafe fn mul_lo( &mut self, _x: &Self::Variable, diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index 438abaa065..7e0826abad 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -1271,6 +1271,20 @@ pub trait InterpreterEnv { position: Self::Position, ) -> Self::Variable; + /// Returns `x % y`, storing the results in `position`. + /// + /// # Safety + /// + /// There are no constraints on the returned values; callers must manually add constraints to + /// ensure that the pair of returned values correspond to the given values `x` and `y`, and + /// that they fall within the desired range. + unsafe fn mod_signed( + &mut self, + x: &Self::Variable, + y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable; + /// Returns `(x / y, x % y)`, storing the results in `position_quotient` and /// `position_remainder` respectively. /// diff --git a/o1vm/src/interpreters/riscv32im/witness.rs b/o1vm/src/interpreters/riscv32im/witness.rs index 895ab46e1c..6c87d64b8e 100644 --- a/o1vm/src/interpreters/riscv32im/witness.rs +++ b/o1vm/src/interpreters/riscv32im/witness.rs @@ -515,6 +515,20 @@ impl InterpreterEnv for Env { res } + unsafe fn mod_signed( + &mut self, + x: &Self::Variable, + y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable { + let x: u32 = (*x).try_into().unwrap(); + let y: u32 = (*y).try_into().unwrap(); + let res = ((x as i32) % (y as i32)) as u32; + let res = res as u64; + self.write_column(position, res); + res + } + unsafe fn divmod_signed( &mut self, x: &Self::Variable, From 4e0220dbd6c09aaff3578d8f8a3f322674f4c9f4 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Mon, 25 Nov 2024 10:57:40 +0100 Subject: [PATCH 066/165] o1vm/riscv32im: simplify mod_signed --- o1vm/src/interpreters/riscv32im/witness.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/o1vm/src/interpreters/riscv32im/witness.rs b/o1vm/src/interpreters/riscv32im/witness.rs index 6c87d64b8e..bb0e0cf6c5 100644 --- a/o1vm/src/interpreters/riscv32im/witness.rs +++ b/o1vm/src/interpreters/riscv32im/witness.rs @@ -521,9 +521,9 @@ impl InterpreterEnv for Env { y: &Self::Variable, position: Self::Position, ) -> Self::Variable { - let x: u32 = (*x).try_into().unwrap(); - let y: u32 = (*y).try_into().unwrap(); - let res = ((x as i32) % (y as i32)) as u32; + let x: i32 = (*x).try_into().unwrap(); + let y: i32 = (*y).try_into().unwrap(); + let res = (x % y) as u32; let res = res as u64; self.write_column(position, res); res From 77a50c46fa2c2a4feb16d81cab098bda86207d6d Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 20 Nov 2024 16:49:00 +0100 Subject: [PATCH 067/165] o1vm/riscv32: remove unused divmod_signed As for mul_hi_lo(_signed), the method is splitted. --- o1vm/src/interpreters/riscv32im/constraints.rs | 13 ------------- o1vm/src/interpreters/riscv32im/interpreter.rs | 16 ---------------- o1vm/src/interpreters/riscv32im/witness.rs | 18 ------------------ 3 files changed, 47 deletions(-) diff --git a/o1vm/src/interpreters/riscv32im/constraints.rs b/o1vm/src/interpreters/riscv32im/constraints.rs index 67bfa46fea..cf154f1cca 100644 --- a/o1vm/src/interpreters/riscv32im/constraints.rs +++ b/o1vm/src/interpreters/riscv32im/constraints.rs @@ -371,19 +371,6 @@ impl InterpreterEnv for Env { self.variable(position) } - unsafe fn divmod_signed( - &mut self, - _x: &Self::Variable, - _y: &Self::Variable, - position_quotient: Self::Position, - position_remainder: Self::Position, - ) -> (Self::Variable, Self::Variable) { - ( - self.variable(position_quotient), - self.variable(position_remainder), - ) - } - unsafe fn divmod( &mut self, _x: &Self::Variable, diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index 7e0826abad..bec354f46e 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -1285,22 +1285,6 @@ pub trait InterpreterEnv { position: Self::Position, ) -> Self::Variable; - /// Returns `(x / y, x % y)`, storing the results in `position_quotient` and - /// `position_remainder` respectively. - /// - /// # Safety - /// - /// There are no constraints on the returned values; callers must manually add constraints to - /// ensure that the pair of returned values correspond to the given values `x` and `y`, and - /// that they fall within the desired range. - unsafe fn divmod_signed( - &mut self, - x: &Self::Variable, - y: &Self::Variable, - position_quotient: Self::Position, - position_remainder: Self::Position, - ) -> (Self::Variable, Self::Variable); - /// Returns `(x / y, x % y)`, storing the results in `position_quotient` and /// `position_remainder` respectively. /// diff --git a/o1vm/src/interpreters/riscv32im/witness.rs b/o1vm/src/interpreters/riscv32im/witness.rs index bb0e0cf6c5..a2e169b76c 100644 --- a/o1vm/src/interpreters/riscv32im/witness.rs +++ b/o1vm/src/interpreters/riscv32im/witness.rs @@ -529,24 +529,6 @@ impl InterpreterEnv for Env { res } - unsafe fn divmod_signed( - &mut self, - x: &Self::Variable, - y: &Self::Variable, - position_quotient: Self::Position, - position_remainder: Self::Position, - ) -> (Self::Variable, Self::Variable) { - let x: u32 = (*x).try_into().unwrap(); - let y: u32 = (*y).try_into().unwrap(); - let q = ((x as i32) / (y as i32)) as u32; - let r = ((x as i32) % (y as i32)) as u32; - let q = q as u64; - let r = r as u64; - self.write_column(position_quotient, q); - self.write_column(position_remainder, r); - (q, r) - } - unsafe fn divmod( &mut self, x: &Self::Variable, From deedbff6e1496f94adf57a766de90a949d8f3426 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 20 Nov 2024 16:51:28 +0100 Subject: [PATCH 068/165] o1vm/riscv32: implement M type instruction Rem --- o1vm/src/interpreters/riscv32im/interpreter.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index bec354f46e..87fe1861e7 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -2264,7 +2264,17 @@ pub fn interpret_mtype(env: &mut Env, instr: MInstruction) unimplemented!("Divu") } MInstruction::Rem => { - unimplemented!("Rem") + let rs1 = env.read_register(&rs1); + let rs2 = env.read_register(&rs2); + // FIXME: constrain + let res = { + let pos = env.alloc_scratch(); + unsafe { env.mod_signed(&rs1, &rs2, pos) } + }; + env.write_register(&rd, res); + + env.set_instruction_pointer(next_instruction_pointer.clone()); + env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); } MInstruction::Remu => { unimplemented!("Remu") From 85639cae3edeef7cd92f6ba2fe7aa6eaac1713a2 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 20 Nov 2024 16:55:11 +0100 Subject: [PATCH 069/165] o1vm/riscv32: implement div for unsigned 32bits Will be used to implement MInstruction::Divu --- o1vm/src/interpreters/riscv32im/constraints.rs | 9 +++++++++ o1vm/src/interpreters/riscv32im/interpreter.rs | 14 ++++++++++++++ o1vm/src/interpreters/riscv32im/witness.rs | 14 ++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/o1vm/src/interpreters/riscv32im/constraints.rs b/o1vm/src/interpreters/riscv32im/constraints.rs index cf154f1cca..41084472d1 100644 --- a/o1vm/src/interpreters/riscv32im/constraints.rs +++ b/o1vm/src/interpreters/riscv32im/constraints.rs @@ -362,6 +362,15 @@ impl InterpreterEnv for Env { self.variable(position) } + unsafe fn div( + &mut self, + _x: &Self::Variable, + _y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable { + self.variable(position) + } + unsafe fn mul_lo( &mut self, _x: &Self::Variable, diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index 87fe1861e7..be39806fbc 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -1285,6 +1285,20 @@ pub trait InterpreterEnv { position: Self::Position, ) -> Self::Variable; + /// Returns `x / y`, storing the results in `position`. + /// + /// # Safety + /// + /// There are no constraints on the returned values; callers must manually add constraints to + /// ensure that the pair of returned values correspond to the given values `x` and `y`, and + /// that they fall within the desired range. + unsafe fn div( + &mut self, + x: &Self::Variable, + y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable; + /// Returns `(x / y, x % y)`, storing the results in `position_quotient` and /// `position_remainder` respectively. /// diff --git a/o1vm/src/interpreters/riscv32im/witness.rs b/o1vm/src/interpreters/riscv32im/witness.rs index a2e169b76c..d29b3d863e 100644 --- a/o1vm/src/interpreters/riscv32im/witness.rs +++ b/o1vm/src/interpreters/riscv32im/witness.rs @@ -529,6 +529,20 @@ impl InterpreterEnv for Env { res } + unsafe fn div( + &mut self, + x: &Self::Variable, + y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable { + let x: u32 = (*x).try_into().unwrap(); + let y: u32 = (*y).try_into().unwrap(); + let res = x / y; + let res = res as u64; + self.write_column(position, res); + res + } + unsafe fn divmod( &mut self, x: &Self::Variable, From c9207b8ea3bbda2cde7ea9c6b7147ea9d04e9805 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 20 Nov 2024 16:57:29 +0100 Subject: [PATCH 070/165] o1vm/riscv32: implement mod_ It will be used to implement MInstruction::Remu in a follow-up PR. --- o1vm/src/interpreters/riscv32im/constraints.rs | 9 +++++++++ o1vm/src/interpreters/riscv32im/interpreter.rs | 14 ++++++++++++++ o1vm/src/interpreters/riscv32im/witness.rs | 14 ++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/o1vm/src/interpreters/riscv32im/constraints.rs b/o1vm/src/interpreters/riscv32im/constraints.rs index 41084472d1..1713346ab4 100644 --- a/o1vm/src/interpreters/riscv32im/constraints.rs +++ b/o1vm/src/interpreters/riscv32im/constraints.rs @@ -371,6 +371,15 @@ impl InterpreterEnv for Env { self.variable(position) } + unsafe fn mod_( + &mut self, + _x: &Self::Variable, + _y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable { + self.variable(position) + } + unsafe fn mul_lo( &mut self, _x: &Self::Variable, diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index be39806fbc..3f9a60f645 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -1299,6 +1299,20 @@ pub trait InterpreterEnv { position: Self::Position, ) -> Self::Variable; + /// Returns `x % y`, storing the results in `position`. + /// + /// # Safety + /// + /// There are no constraints on the returned values; callers must manually add constraints to + /// ensure that the pair of returned values correspond to the given values `x` and `y`, and + /// that they fall within the desired range. + unsafe fn mod_( + &mut self, + x: &Self::Variable, + y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable; + /// Returns `(x / y, x % y)`, storing the results in `position_quotient` and /// `position_remainder` respectively. /// diff --git a/o1vm/src/interpreters/riscv32im/witness.rs b/o1vm/src/interpreters/riscv32im/witness.rs index d29b3d863e..06a9bc00ac 100644 --- a/o1vm/src/interpreters/riscv32im/witness.rs +++ b/o1vm/src/interpreters/riscv32im/witness.rs @@ -543,6 +543,20 @@ impl InterpreterEnv for Env { res } + unsafe fn mod_( + &mut self, + x: &Self::Variable, + y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable { + let x: u32 = (*x).try_into().unwrap(); + let y: u32 = (*y).try_into().unwrap(); + let res = x % y; + let res = res as u64; + self.write_column(position, res); + res + } + unsafe fn divmod( &mut self, x: &Self::Variable, From 517924f0015fa80ce1e5516ee7cc75fa63eb25c0 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Mon, 25 Nov 2024 10:56:05 +0100 Subject: [PATCH 071/165] o1vm/riscv32im: rename mod_ in mod_unsigned for readability --- o1vm/src/interpreters/riscv32im/constraints.rs | 2 +- o1vm/src/interpreters/riscv32im/interpreter.rs | 2 +- o1vm/src/interpreters/riscv32im/witness.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/o1vm/src/interpreters/riscv32im/constraints.rs b/o1vm/src/interpreters/riscv32im/constraints.rs index 1713346ab4..9fbdb8fbc8 100644 --- a/o1vm/src/interpreters/riscv32im/constraints.rs +++ b/o1vm/src/interpreters/riscv32im/constraints.rs @@ -371,7 +371,7 @@ impl InterpreterEnv for Env { self.variable(position) } - unsafe fn mod_( + unsafe fn mod_unsigned( &mut self, _x: &Self::Variable, _y: &Self::Variable, diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index 3f9a60f645..0222924c78 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -1306,7 +1306,7 @@ pub trait InterpreterEnv { /// There are no constraints on the returned values; callers must manually add constraints to /// ensure that the pair of returned values correspond to the given values `x` and `y`, and /// that they fall within the desired range. - unsafe fn mod_( + unsafe fn mod_unsigned( &mut self, x: &Self::Variable, y: &Self::Variable, diff --git a/o1vm/src/interpreters/riscv32im/witness.rs b/o1vm/src/interpreters/riscv32im/witness.rs index 06a9bc00ac..8a1502c6ea 100644 --- a/o1vm/src/interpreters/riscv32im/witness.rs +++ b/o1vm/src/interpreters/riscv32im/witness.rs @@ -543,7 +543,7 @@ impl InterpreterEnv for Env { res } - unsafe fn mod_( + unsafe fn mod_unsigned( &mut self, x: &Self::Variable, y: &Self::Variable, From 7482d1b4d356a6f4c906836535742387c6deb3cc Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 20 Nov 2024 16:59:21 +0100 Subject: [PATCH 072/165] o1vm/riscv32: remove unused divmod As for mul_hi_lo(_signed), the method is splitted as there are individual instructions for div and mod. --- o1vm/src/interpreters/riscv32im/constraints.rs | 13 ------------- o1vm/src/interpreters/riscv32im/interpreter.rs | 16 ---------------- o1vm/src/interpreters/riscv32im/witness.rs | 18 ------------------ 3 files changed, 47 deletions(-) diff --git a/o1vm/src/interpreters/riscv32im/constraints.rs b/o1vm/src/interpreters/riscv32im/constraints.rs index 9fbdb8fbc8..2b02d708eb 100644 --- a/o1vm/src/interpreters/riscv32im/constraints.rs +++ b/o1vm/src/interpreters/riscv32im/constraints.rs @@ -389,19 +389,6 @@ impl InterpreterEnv for Env { self.variable(position) } - unsafe fn divmod( - &mut self, - _x: &Self::Variable, - _y: &Self::Variable, - position_quotient: Self::Position, - position_remainder: Self::Position, - ) -> (Self::Variable, Self::Variable) { - ( - self.variable(position_quotient), - self.variable(position_remainder), - ) - } - unsafe fn count_leading_zeros( &mut self, _x: &Self::Variable, diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index 0222924c78..c7a5e3bc17 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -1313,22 +1313,6 @@ pub trait InterpreterEnv { position: Self::Position, ) -> Self::Variable; - /// Returns `(x / y, x % y)`, storing the results in `position_quotient` and - /// `position_remainder` respectively. - /// - /// # Safety - /// - /// There are no constraints on the returned values; callers must manually add constraints to - /// ensure that the pair of returned values correspond to the given values `x` and `y`, and - /// that they fall within the desired range. - unsafe fn divmod( - &mut self, - x: &Self::Variable, - y: &Self::Variable, - position_quotient: Self::Position, - position_remainder: Self::Position, - ) -> (Self::Variable, Self::Variable); - /// Returns the number of leading 0s in `x`, storing the result in `position`. /// /// # Safety diff --git a/o1vm/src/interpreters/riscv32im/witness.rs b/o1vm/src/interpreters/riscv32im/witness.rs index 8a1502c6ea..61d2868886 100644 --- a/o1vm/src/interpreters/riscv32im/witness.rs +++ b/o1vm/src/interpreters/riscv32im/witness.rs @@ -557,24 +557,6 @@ impl InterpreterEnv for Env { res } - unsafe fn divmod( - &mut self, - x: &Self::Variable, - y: &Self::Variable, - position_quotient: Self::Position, - position_remainder: Self::Position, - ) -> (Self::Variable, Self::Variable) { - let x: u32 = (*x).try_into().unwrap(); - let y: u32 = (*y).try_into().unwrap(); - let q = x / y; - let r = x % y; - let q = q as u64; - let r = r as u64; - self.write_column(position_quotient, q); - self.write_column(position_remainder, r); - (q, r) - } - unsafe fn count_leading_zeros( &mut self, x: &Self::Variable, From 3dd7fe66ba9044856b8b41ed71ead2a4f63c9706 Mon Sep 17 00:00:00 2001 From: Mikhail Volkhov Date: Tue, 3 Dec 2024 11:40:49 +0000 Subject: [PATCH 073/165] Change comment notation to additive --- poly-commitment/src/ipa.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poly-commitment/src/ipa.rs b/poly-commitment/src/ipa.rs index d68216f67c..17c561bb3d 100644 --- a/poly-commitment/src/ipa.rs +++ b/poly-commitment/src/ipa.rs @@ -745,7 +745,7 @@ impl SRS { let r_delta = ::rand(rng); // Compute delta, the commitment - // delta = G0^d * U_base^{b0*d} * H^r_delta (as a group element, in multiplicative notation) + // delta = [d] G0 + [b0*d] U_base + [r_delta] H^r (as a group element, in additive notation) let delta = ((g0.into_group() + (u_base.mul(b0))).into_affine().mul(d) + self.h.mul(r_delta)) .into_affine(); From 2e4d75418562c1964e1959eb4cb9f2b90b32719e Mon Sep 17 00:00:00 2001 From: Mikhail Volkhov Date: Tue, 3 Dec 2024 11:44:33 +0000 Subject: [PATCH 074/165] Rename d1_size to n_chunks in IVC prover --- ivc/src/prover.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ivc/src/prover.rs b/ivc/src/prover.rs index 719b2a8f61..8e318ad7a7 100644 --- a/ivc/src/prover.rs +++ b/ivc/src/prover.rs @@ -437,11 +437,11 @@ where let u = u_chal.to_field(endo_r); let coefficients_form = DensePolynomialOrEvaluations::DensePolynomial; - let non_hiding = |d1_size| PolyComm { - chunks: vec![Fp::zero(); d1_size], + let non_hiding = |n_chunks| PolyComm { + chunks: vec![Fp::zero(); n_chunks], }; - let hiding = |d1_size| PolyComm { - chunks: vec![Fp::one(); d1_size], + let hiding = |n_chunks| PolyComm { + chunks: vec![Fp::one(); n_chunks], }; // Gathering all polynomials_to_open to use in the opening proof From e08400805ac9c27353a5c244d4bcf7be7c038b55 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 20 Nov 2024 17:03:05 +0100 Subject: [PATCH 075/165] o1vm/riscv32: implement M type instruction divu --- o1vm/src/interpreters/riscv32im/interpreter.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index c7a5e3bc17..d0e6630e07 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -2273,7 +2273,17 @@ pub fn interpret_mtype(env: &mut Env, instr: MInstruction) env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); } MInstruction::Divu => { - unimplemented!("Divu") + let rs1 = env.read_register(&rs1); + let rs2 = env.read_register(&rs2); + // FIXME: constrain + let res = { + let pos = env.alloc_scratch(); + unsafe { env.div(&rs1, &rs2, pos) } + }; + env.write_register(&rd, res); + + env.set_instruction_pointer(next_instruction_pointer.clone()); + env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); } MInstruction::Rem => { let rs1 = env.read_register(&rs1); From 4c5bff90bafd0f2fc984d01cb0a3d90a32fa904a Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 20 Nov 2024 17:04:21 +0100 Subject: [PATCH 076/165] o1vm/riscv32: implement M type instruction Remu --- o1vm/src/interpreters/riscv32im/interpreter.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index d0e6630e07..1797dde93e 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -2299,7 +2299,17 @@ pub fn interpret_mtype(env: &mut Env, instr: MInstruction) env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); } MInstruction::Remu => { - unimplemented!("Remu") + let rs1 = env.read_register(&rs1); + let rs2 = env.read_register(&rs2); + // FIXME: constrain + let res = { + let pos = env.alloc_scratch(); + unsafe { env.mod_unsigned(&rs1, &rs2, pos) } + }; + env.write_register(&rd, res); + + env.set_instruction_pointer(next_instruction_pointer.clone()); + env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); } } } From 1708293192548d66f1f3d9ad7f1cced7df0ab9af Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 20 Nov 2024 17:14:02 +0100 Subject: [PATCH 077/165] o1vm/riscv32: implement mul_hi_signed_unsigned to be used for Mulhsu --- o1vm/src/interpreters/riscv32im/constraints.rs | 9 +++++++++ o1vm/src/interpreters/riscv32im/interpreter.rs | 14 ++++++++++++++ o1vm/src/interpreters/riscv32im/witness.rs | 15 +++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/o1vm/src/interpreters/riscv32im/constraints.rs b/o1vm/src/interpreters/riscv32im/constraints.rs index 2b02d708eb..ba1633e1a7 100644 --- a/o1vm/src/interpreters/riscv32im/constraints.rs +++ b/o1vm/src/interpreters/riscv32im/constraints.rs @@ -344,6 +344,15 @@ impl InterpreterEnv for Env { self.variable(position) } + unsafe fn mul_hi_signed_unsigned( + &mut self, + _x: &Self::Variable, + _y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable { + self.variable(position) + } + unsafe fn div_signed( &mut self, _x: &Self::Variable, diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index 1797dde93e..59fa7a6bd2 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -1257,6 +1257,20 @@ pub trait InterpreterEnv { position: Self::Position, ) -> Self::Variable; + /// Returns `((x * y) >> 32`, storing the results in `position`. + /// + /// # Safety + /// + /// There are no constraints on the returned values; callers must manually add constraints to + /// ensure that the pair of returned values correspond to the given values `x` and `y`, and + /// that they fall within the desired range. + unsafe fn mul_hi_signed_unsigned( + &mut self, + x: &Self::Variable, + y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable; + /// Returns `x / y`, storing the results in `position`. /// /// # Safety diff --git a/o1vm/src/interpreters/riscv32im/witness.rs b/o1vm/src/interpreters/riscv32im/witness.rs index 61d2868886..e9a976ca13 100644 --- a/o1vm/src/interpreters/riscv32im/witness.rs +++ b/o1vm/src/interpreters/riscv32im/witness.rs @@ -486,6 +486,21 @@ impl InterpreterEnv for Env { res } + unsafe fn mul_hi_signed_unsigned( + &mut self, + x: &Self::Variable, + y: &Self::Variable, + position: Self::Position, + ) -> Self::Variable { + let x: u32 = (*x).try_into().unwrap(); + let y: u32 = (*y).try_into().unwrap(); + let res = (((x as i32) as i64) * (y as i64)) as u64; + let res = (res >> 32) as u32; + let res = res as u64; + self.write_column(position, res); + res + } + unsafe fn div_signed( &mut self, x: &Self::Variable, From 277cec86f478a800ed3b169e9ef2a6041bd34d96 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 20 Nov 2024 17:16:14 +0100 Subject: [PATCH 078/165] o1vm/riscv32: implement M type instruction Mulhsu --- o1vm/src/interpreters/riscv32im/interpreter.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index 59fa7a6bd2..b657699967 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -2258,7 +2258,17 @@ pub fn interpret_mtype(env: &mut Env, instr: MInstruction) env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); } MInstruction::Mulhsu => { - unimplemented!("Mulhsu") + let rs1 = env.read_register(&rs1); + let rs2 = env.read_register(&rs2); + // FIXME: constrain + let res = { + let pos = env.alloc_scratch(); + unsafe { env.mul_hi_signed_unsigned(&rs1, &rs2, pos) } + }; + env.write_register(&rd, res); + + env.set_instruction_pointer(next_instruction_pointer.clone()); + env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); } MInstruction::Mulhu => { let rs1 = env.read_register(&rs1); From 54edc550095010a9eeda7132e78acaeaeb413022 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Mon, 25 Nov 2024 11:10:35 +0100 Subject: [PATCH 079/165] o1vm/riscv32im: improve documentation reg. semantic of op --- o1vm/src/interpreters/riscv32im/interpreter.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index b657699967..f13e3aa68e 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -20,6 +20,14 @@ //! and copied in this file for offline reference. //! If you are the author of the above documentations and would like to add or //! modify the credits, please open a pull request. +//! +//! For each instruction, we provide the format, description, and the +//! semantic in pseudo-code of the instruction. +//! When `signed` is mentioned in the pseudo-code, it means that the +//! operation is performed as a signed operation (i.e. signed(v) where `v` is a +//! 32 bits value means that `v` must be interpreted as a i32 value in Rust, the +//! most significant bit being the sign - 1 for negative, 0 for positive). +//! By default, unsigned operations are performed. use super::registers::{REGISTER_CURRENT_IP, REGISTER_HEAP_POINTER, REGISTER_NEXT_IP}; use crate::lookups::{Lookup, LookupTableIDs}; From 964cfeb7ad91aa21475cd0c8784b94800ac7b952 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Mon, 25 Nov 2024 11:11:00 +0100 Subject: [PATCH 080/165] o1vm/riscv32im: add semantic for MInstruction --- o1vm/src/interpreters/riscv32im/interpreter.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index f13e3aa68e..0bc94d1c7e 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -2240,6 +2240,7 @@ pub fn interpret_mtype(env: &mut Env, instr: MInstruction) match instr { MInstruction::Mul => { + // x[rd] = x[rs1] * x[rs2] let rs1 = env.read_register(&rs1); let rs2 = env.read_register(&rs2); // FIXME: constrain @@ -2253,6 +2254,7 @@ pub fn interpret_mtype(env: &mut Env, instr: MInstruction) env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); } MInstruction::Mulh => { + // x[rd] = (signed(x[rs1]) * signed(x[rs2])) >> 32 let rs1 = env.read_register(&rs1); let rs2 = env.read_register(&rs2); // FIXME: constrain @@ -2266,6 +2268,7 @@ pub fn interpret_mtype(env: &mut Env, instr: MInstruction) env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); } MInstruction::Mulhsu => { + // x[rd] = (signed(x[rs1]) * x[rs2]) >> 32 let rs1 = env.read_register(&rs1); let rs2 = env.read_register(&rs2); // FIXME: constrain @@ -2279,6 +2282,7 @@ pub fn interpret_mtype(env: &mut Env, instr: MInstruction) env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); } MInstruction::Mulhu => { + // x[rd] = (x[rs1] * x[rs2]) >> 32 let rs1 = env.read_register(&rs1); let rs2 = env.read_register(&rs2); // FIXME: constrain @@ -2292,6 +2296,7 @@ pub fn interpret_mtype(env: &mut Env, instr: MInstruction) env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); } MInstruction::Div => { + // x[rd] = signed(x[rs1]) / signed(x[rs2]) let rs1 = env.read_register(&rs1); let rs2 = env.read_register(&rs2); // FIXME: constrain @@ -2305,6 +2310,7 @@ pub fn interpret_mtype(env: &mut Env, instr: MInstruction) env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); } MInstruction::Divu => { + // x[rd] = x[rs1] / x[rs2] let rs1 = env.read_register(&rs1); let rs2 = env.read_register(&rs2); // FIXME: constrain @@ -2318,6 +2324,7 @@ pub fn interpret_mtype(env: &mut Env, instr: MInstruction) env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); } MInstruction::Rem => { + // x[rd] = signed(x[rs1]) % signed(x[rs2]) let rs1 = env.read_register(&rs1); let rs2 = env.read_register(&rs2); // FIXME: constrain @@ -2331,6 +2338,7 @@ pub fn interpret_mtype(env: &mut Env, instr: MInstruction) env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); } MInstruction::Remu => { + // x[rd] = x[rs1] % x[rs2] let rs1 = env.read_register(&rs1); let rs2 = env.read_register(&rs2); // FIXME: constrain From 673954a3dafcc9f257f67f06f05ca72a2f2dc2d4 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 4 Dec 2024 13:31:39 +0100 Subject: [PATCH 081/165] CI/o1vm: deactivating path dependent execution As we enforce some GH actions to pass when targeting master, it can make PR stalled and unmergeable. I do not see any options in GH settings at the moment to include these conditions. --- .github/workflows/o1vm-ci.yml | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/.github/workflows/o1vm-ci.yml b/.github/workflows/o1vm-ci.yml index 75763778ca..f657d3c879 100644 --- a/.github/workflows/o1vm-ci.yml +++ b/.github/workflows/o1vm-ci.yml @@ -3,37 +3,9 @@ name: o1vm CI on: workflow_dispatch: pull_request: - paths: - [ - "o1vm/**", - "folding/**", - "groupmap/**", - "kimchi/**", - "msm/**", - "curves/**", - "poseidon/**", - "poly-commitment/", - "internal-tracing/**", - "srs/**", - "utils/**", - ] push: branches: - master - paths: - [ - "o1vm/**", - "folding/**", - "groupmap/**", - "kimchi/**", - "msm/**", - "curves/**", - "poseidon/**", - "poly-commitment/", - "internal-tracing/**", - "srs/**", - "utils/**", - ] env: # https://doc.rust-lang.org/cargo/reference/profiles.html#release From 9b2ad579850297374fcc028966a33cba97ceea28 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Tue, 12 Nov 2024 11:50:24 +0100 Subject: [PATCH 082/165] Mina-signer: make secret field of KeyPair public --- signer/src/keypair.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/signer/src/keypair.rs b/signer/src/keypair.rs index e2397c8f9d..8f76383020 100644 --- a/signer/src/keypair.rs +++ b/signer/src/keypair.rs @@ -27,7 +27,7 @@ pub type Result = std::result::Result; #[derive(Clone, PartialEq, Eq)] pub struct Keypair { /// Secret key - pub(crate) secret: SecKey, + pub secret: SecKey, /// Public key pub public: PubKey, } From faecb5c7341a7962ae2d062b3c49abcc574652f9 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Thu, 5 Dec 2024 13:14:09 +0100 Subject: [PATCH 083/165] o1vm/ricv32im: regression tests for bitmask Checking that the count of the bit index starts at 0, i.e. the number of bits that bitmask returns if `higher_bit - lower_bit`. --- o1vm/src/interpreters/riscv32im/tests.rs | 32 ++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/o1vm/src/interpreters/riscv32im/tests.rs b/o1vm/src/interpreters/riscv32im/tests.rs index e382dee701..8da6e462ef 100644 --- a/o1vm/src/interpreters/riscv32im/tests.rs +++ b/o1vm/src/interpreters/riscv32im/tests.rs @@ -2,8 +2,8 @@ use super::{registers::Registers, witness::Env, INSTRUCTION_SET_SIZE, PAGE_SIZE, use crate::interpreters::riscv32im::{ constraints, interpreter::{ - IInstruction, Instruction, MInstruction, RInstruction, SBInstruction, SInstruction, - SyscallInstruction, UInstruction, UJInstruction, + IInstruction, Instruction, InterpreterEnv, MInstruction, RInstruction, SBInstruction, + SInstruction, SyscallInstruction, UInstruction, UJInstruction, }, }; use ark_ff::Zero; @@ -419,3 +419,31 @@ pub fn test_instruction_decoding_and() { let (opcode, _instruction) = env.decode_instruction(); assert_eq!(opcode, Instruction::RType(RInstruction::And)); } + +#[test] +pub fn test_witness_bitmask_bounds() { + let mut env: Env = dummy_env(); + // Checking that the bit position given as upper bound is not included in + // the output, i.e. the output is v[LOWER_BOUND:UPPER_BOUND-1] + { + // We take only 4 bits on the 5. + let input = 0b10000; + let output = { + let pos = env.alloc_scratch(); + unsafe { env.bitmask(&input, 4, 0, pos) } + }; + let exp_output = 0b0000; + assert_eq!(output, exp_output); + } + + { + // We take 5 bits + let input = 0b10000; + let output = { + let pos = env.alloc_scratch(); + unsafe { env.bitmask(&input, 5, 0, pos) } + }; + let exp_output = 0b10000; + assert_eq!(output, exp_output); + } +} From 98e7c359ae45efd5d7684b721742e9d69b83ad29 Mon Sep 17 00:00:00 2001 From: martyall Date: Thu, 5 Dec 2024 11:20:39 -0800 Subject: [PATCH 084/165] self helping Makefile --- Makefile | 57 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/Makefile b/Makefile index 4b4281bb62..53253a15e0 100644 --- a/Makefile +++ b/Makefile @@ -21,11 +21,10 @@ setup: @echo "Git submodules synced." @echo "" -# Install test dependencies # https://nexte.st/book/pre-built-binaries.html#using-nextest-in-github-actions # FIXME: update to 0.9.68 when we get rid of 1.71 and 1.72. # FIXME: latest 0.8.19+ requires rustc 1.74+ -install-test-deps: +install-test-deps: ## Install test dependencies @echo "" @echo "Installing the test dependencies." @echo "" @@ -36,73 +35,73 @@ install-test-deps: @echo "Test dependencies installed." @echo "" -# Clean the project -clean: + +clean: ## Clean the project cargo clean -# Build the project -build: + +build: ## Build the project cargo build --all-targets --all-features -# Build the project in release mode -release: + +release: ## Build the project in release mode cargo build --release --all-targets --all-features -# Test the project's docs comments -test-doc: + +test-doc: ## Test the project's docs comments cargo test --all-features --release --doc test-doc-with-coverage: $(COVERAGE_ENV) $(MAKE) test-doc -# Test the project with non-heavy tests and using native cargo test runner -test: + +test: ## Test the project with non-heavy tests and using native cargo test runner cargo test --all-features --release $(CARGO_EXTRA_ARGS) -- --nocapture --skip heavy $(BIN_EXTRA_ARGS) test-with-coverage: $(COVERAGE_ENV) CARGO_EXTRA_ARGS="$(CARGO_EXTRA_ARGS)" BIN_EXTRA_ARGS="$(BIN_EXTRA_ARGS)" $(MAKE) test -# Test the project with heavy tests and using native cargo test runner -test-heavy: + +test-heavy: ## Test the project with heavy tests and using native cargo test runner cargo test --all-features --release $(CARGO_EXTRA_ARGS) -- --nocapture heavy $(BIN_EXTRA_ARGS) test-heavy-with-coverage: $(COVERAGE_ENV) CARGO_EXTRA_ARGS="$(CARGO_EXTRA_ARGS)" BIN_EXTRA_ARGS="$(BIN_EXTRA_ARGS)" $(MAKE) test-heavy -# Test the project with all tests and using native cargo test runner -test-all: + +test-all: ## Test the project with all tests and using native cargo test runner cargo test --all-features --release $(CARGO_EXTRA_ARGS) -- --nocapture $(BIN_EXTRA_ARGS) test-all-with-coverage: $(COVERAGE_ENV) CARGO_EXTRA_ARGS="$(CARGO_EXTRA_ARGS)" BIN_EXTRA_ARGS="$(BIN_EXTRA_ARGS)" $(MAKE) test-all -# Test the project with non-heavy tests and using nextest test runner -nextest: + +nextest: ## Test the project with non-heavy tests and using nextest test runner cargo nextest run --all-features --release --profile ci -E "not test(heavy)" $(BIN_EXTRA_ARGS) nextest-with-coverage: $(COVERAGE_ENV) BIN_EXTRA_ARGS="$(BIN_EXTRA_ARGS)" $(MAKE) nextest -# Test the project with heavy tests and using nextest test runner -nextest-heavy: + +nextest-heavy: ## Test the project with heavy tests and using nextest test runner cargo nextest run --all-features --release --profile ci -E "test(heavy)" $(BIN_EXTRA_ARGS) nextest-heavy-with-coverage: $(COVERAGE_ENV) BIN_EXTRA_ARGS="$(BIN_EXTRA_ARGS)" $(MAKE) nextest-heavy -# Test the project with all tests and using nextest test runner -nextest-all: + +nextest-all: ## Test the project with all tests and using nextest test runner cargo nextest run --all-features --release --profile ci $(BIN_EXTRA_ARGS) nextest-all-with-coverage: $(COVERAGE_ENV) BIN_EXTRA_ARGS="$(BIN_EXTRA_ARGS)" $(MAKE) nextest-all -# Format the code -format: + +format: ## Format the code cargo +nightly fmt -- --check -# Lint the code -lint: + +lint: ## Lint the code cargo clippy --all-features --all-targets --tests $(CARGO_EXTRA_ARGS) -- -W clippy::all -D warnings generate-test-coverage-report: @@ -128,4 +127,8 @@ generate-doc: @echo "The documentation is available at: ./target/doc" @echo "" -.PHONY: all setup install-test-deps clean build release test-doc test-doc-with-coverage test test-with-coverage test-heavy test-heavy-with-coverage test-all test-all-with-coverage nextest nextest-with-coverage nextest-heavy nextest-heavy-with-coverage nextest-all nextest-all-with-coverage format lint generate-test-coverage-report generate-doc +help: ## Ask for help! + @grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' + + +.PHONY: all setup install-test-deps clean build release test-doc test-doc-with-coverage test test-with-coverage test-heavy test-heavy-with-coverage test-all test-all-with-coverage nextest nextest-with-coverage nextest-heavy nextest-heavy-with-coverage nextest-all nextest-all-with-coverage format lint generate-test-coverage-report generate-doc help From a2e6871cfab7b5ede11a1a61ffa3ce3d86158e38 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Thu, 5 Dec 2024 16:55:46 +0100 Subject: [PATCH 085/165] o1vm/resources: move binaries into a subdirectory of programs The idea is to move source files into a `src` directory at the same level than bin. --- .../programs/riscv32im/{ => bin}/fibonacci | Bin .../programs/riscv32im/{ => bin}/fibonacci-7 | Bin .../programs/riscv32im/{ => bin}/is_prime_naive | Bin .../programs/riscv32im/{ => bin}/no-action | Bin o1vm/tests/test_elf_loader.rs | 2 +- o1vm/tests/test_riscv_elf.rs | 4 ++-- 6 files changed, 3 insertions(+), 3 deletions(-) rename o1vm/resources/programs/riscv32im/{ => bin}/fibonacci (100%) rename o1vm/resources/programs/riscv32im/{ => bin}/fibonacci-7 (100%) rename o1vm/resources/programs/riscv32im/{ => bin}/is_prime_naive (100%) rename o1vm/resources/programs/riscv32im/{ => bin}/no-action (100%) diff --git a/o1vm/resources/programs/riscv32im/fibonacci b/o1vm/resources/programs/riscv32im/bin/fibonacci similarity index 100% rename from o1vm/resources/programs/riscv32im/fibonacci rename to o1vm/resources/programs/riscv32im/bin/fibonacci diff --git a/o1vm/resources/programs/riscv32im/fibonacci-7 b/o1vm/resources/programs/riscv32im/bin/fibonacci-7 similarity index 100% rename from o1vm/resources/programs/riscv32im/fibonacci-7 rename to o1vm/resources/programs/riscv32im/bin/fibonacci-7 diff --git a/o1vm/resources/programs/riscv32im/is_prime_naive b/o1vm/resources/programs/riscv32im/bin/is_prime_naive similarity index 100% rename from o1vm/resources/programs/riscv32im/is_prime_naive rename to o1vm/resources/programs/riscv32im/bin/is_prime_naive diff --git a/o1vm/resources/programs/riscv32im/no-action b/o1vm/resources/programs/riscv32im/bin/no-action similarity index 100% rename from o1vm/resources/programs/riscv32im/no-action rename to o1vm/resources/programs/riscv32im/bin/no-action diff --git a/o1vm/tests/test_elf_loader.rs b/o1vm/tests/test_elf_loader.rs index eba0fdf28e..e473c38ccb 100644 --- a/o1vm/tests/test_elf_loader.rs +++ b/o1vm/tests/test_elf_loader.rs @@ -5,7 +5,7 @@ fn test_correctly_parsing_elf() { let curr_dir = std::env::current_dir().unwrap(); let path = curr_dir.join(std::path::PathBuf::from( - "resources/programs/riscv32im/fibonacci", + "resources/programs/riscv32im/bin/fibonacci", )); let state = o1vm::elf_loader::parse_riscv32(&path).unwrap(); diff --git a/o1vm/tests/test_riscv_elf.rs b/o1vm/tests/test_riscv_elf.rs index 7b278a3a8e..520d634ae0 100644 --- a/o1vm/tests/test_riscv_elf.rs +++ b/o1vm/tests/test_riscv_elf.rs @@ -27,7 +27,7 @@ fn test_instruction_can_be_converted_into_string() { fn test_no_action() { let curr_dir = std::env::current_dir().unwrap(); let path = curr_dir.join(std::path::PathBuf::from( - "resources/programs/riscv32im/no-action", + "resources/programs/riscv32im/bin/no-action", )); let state = o1vm::elf_loader::parse_riscv32(&path).unwrap(); let mut witness = Env::::create(PAGE_SIZE.try_into().unwrap(), state); @@ -56,7 +56,7 @@ fn test_no_action() { fn test_fibonacci_7() { let curr_dir = std::env::current_dir().unwrap(); let path = curr_dir.join(std::path::PathBuf::from( - "resources/programs/riscv32im/fibonacci-7", + "resources/programs/riscv32im/bin/fibonacci-7", )); let state = o1vm::elf_loader::parse_riscv32(&path).unwrap(); let mut witness = Env::::create(PAGE_SIZE.try_into().unwrap(), state); From ce29aa65383a275bc99de896cbc9a0c6229e8eb8 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Thu, 5 Dec 2024 16:56:28 +0100 Subject: [PATCH 086/165] Makefile: intro target setup-riscv32-toolchain to build RISC-V deps --- .gitignore | 3 +++ Makefile | 16 +++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 8fb024dbfc..67a6dff458 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,6 @@ o1vm/op-program-db* o1vm/state.json meta.json state.json + +# Directory for the RISC-V 32bits toolchain +_riscv32-gnu-toolchain \ No newline at end of file diff --git a/Makefile b/Makefile index 53253a15e0..f462d1dbbf 100644 --- a/Makefile +++ b/Makefile @@ -7,6 +7,7 @@ COVERAGE_ENV = CARGO_INCREMENTAL=0 RUSTFLAGS='-Cinstrument-coverage' RUSTDOCFLAGS="-Cinstrument-coverage" LLVM_PROFILE_FILE=$(shell pwd)/target/profraw/cargo-test-%p-%m.profraw # FIXME: In latest 0.8.19+ -t CLI argument can accept comma separated list of custom output types, hence, no need in double invocation GRCOV_CALL = grcov ./target/profraw --binary-path ./target/release/deps/ -s . --branch --ignore-not-existing --ignore "**/tests/**" +RISCV32_TOOLCHAIN_PATH = $(shell pwd)/_riscv32-gnu-toolchain # Default target all: release @@ -131,4 +132,17 @@ help: ## Ask for help! @grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' -.PHONY: all setup install-test-deps clean build release test-doc test-doc-with-coverage test test-with-coverage test-heavy test-heavy-with-coverage test-all test-all-with-coverage nextest nextest-with-coverage nextest-heavy nextest-heavy-with-coverage nextest-all nextest-all-with-coverage format lint generate-test-coverage-report generate-doc help +setup-riscv32-toolchain: + @echo "" + @echo "Setting up the RISC-V 32-bit toolchain" + @echo "" + if [ ! -d $(RISCV32_TOOLCHAIN_PATH) ]; then \ + git clone https://github.com/riscv-collab/riscv-gnu-toolchain ${RISCV32_TOOLCHAIN_PATH}; \ + fi + cd ${RISCV32_TOOLCHAIN_PATH} && ./configure --with-arch=rv32gc --with-abi=ilp32d --prefix=${RISCV32_TOOLCHAIN_PATH}/build + cd ${RISCV32_TOOLCHAIN_PATH} && make -j 32 # require a good internet connection and some minutes + @echo "" + @echo "RISC-V 32-bits toolchain is ready in ${RISCV32_TOOLCHAIN_PATH}/build" + @echo "" + +.PHONY: all setup install-test-deps clean build release test-doc test-doc-with-coverage test test-with-coverage test-heavy test-heavy-with-coverage test-all test-all-with-coverage nextest nextest-with-coverage nextest-heavy nextest-heavy-with-coverage nextest-all nextest-all-with-coverage format lint generate-test-coverage-report generate-doc setup-riscv32-toolchain help From 52294c0c01d9251daee8221a9cbbd0a6ab0c7dfc Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Thu, 5 Dec 2024 16:57:20 +0100 Subject: [PATCH 087/165] Makefile: introduce fclean target --- Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f462d1dbbf..7e93df0bd1 100644 --- a/Makefile +++ b/Makefile @@ -145,4 +145,7 @@ setup-riscv32-toolchain: @echo "RISC-V 32-bits toolchain is ready in ${RISCV32_TOOLCHAIN_PATH}/build" @echo "" -.PHONY: all setup install-test-deps clean build release test-doc test-doc-with-coverage test test-with-coverage test-heavy test-heavy-with-coverage test-all test-all-with-coverage nextest nextest-with-coverage nextest-heavy nextest-heavy-with-coverage nextest-all nextest-all-with-coverage format lint generate-test-coverage-report generate-doc setup-riscv32-toolchain help +fclean: clean + rm -rf ${RISCV32_TOOLCHAIN_PATH} + +.PHONY: all setup install-test-deps clean build release test-doc test-doc-with-coverage test test-with-coverage test-heavy test-heavy-with-coverage test-all test-all-with-coverage nextest nextest-with-coverage nextest-heavy nextest-heavy-with-coverage nextest-all nextest-all-with-coverage format lint generate-test-coverage-report generate-doc setup-riscv32-toolchain help fclean From b2fcef7a5d54ffec853fe4f6e3ca95c32ff7d2d7 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Thu, 5 Dec 2024 16:57:36 +0100 Subject: [PATCH 088/165] o1vm/README: add a section reg. test programs --- o1vm/README.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/o1vm/README.md b/o1vm/README.md index 0a7cc6540b..827a496056 100644 --- a/o1vm/README.md +++ b/o1vm/README.md @@ -175,3 +175,37 @@ RUN_WITH_CACHED_DATA="y" FILENAME="env-for-latest-l2-block.sh" O1VM_FLAVOR="pick ```shell ./clear-e2e-testing-cache.sh ``` + +## Running test programs + +Different programs written either in Rust or directly in assembly are given in +the folder `resources/programs`. For each different architecture, you can see +examples. + +As installing the toolchain for each ISA might not be easy on every development +platform, we do provide the source code and the corresponding assembly +respectively in `resources/programs/[ISA]/src` and +`resources/programs/[ISA]/bin`. + +### RISC-V 32 bits (riscv32i, riscv32im) + +For the RISC-V 32 bits architecture, the user can install the toolchain by using +`make setup-riscv32-toolchain`. + +If you encounter any issue with the build dependencies, you can refer to [this +GitHub repository](https://github.com/riscv-collab/riscv-gnu-toolchain). + +The toolchain will be available in the directory +`_riscv32-gnu-toolchain/build` at the root of this repository (see variable +`RISCV32_TOOLCHAIN_PATH` in the [Makefile](../Makefile). + +To compile on of the source files available in +`resources/programs/riscv32im/src`, the user can use: + +```shell +FILENAME=sll.s + +_riscv32-gnu-toolchain/build/riscv32-unknown-elf-as \ + -o a.out \ + o1vm/resources/programs/riscv32im/src/${FILENAME} +``` From d6a4763b77b077c83d6201838d337b91d6b0e239 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Thu, 5 Dec 2024 17:35:25 +0100 Subject: [PATCH 089/165] Makefile: simply 80 limits --- Makefile | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 7e93df0bd1..0202f2258e 100644 --- a/Makefile +++ b/Makefile @@ -2,10 +2,12 @@ # Known coverage limitations and issues: # - https://github.com/rust-lang/rust/issues/79417 # - https://github.com/nextest-rs/nextest/issues/16 -# FIXME: Update or remove the `codecov.yml` file to enable the `patch` coverage report and the corresponding PR check, -# once situation with the Rust's Doctests will be improved. +# FIXME: Update or remove the `codecov.yml` file to enable the `patch` coverage +# report and the corresponding PR check, once situation with the Rust's Doctests +# will be improved. COVERAGE_ENV = CARGO_INCREMENTAL=0 RUSTFLAGS='-Cinstrument-coverage' RUSTDOCFLAGS="-Cinstrument-coverage" LLVM_PROFILE_FILE=$(shell pwd)/target/profraw/cargo-test-%p-%m.profraw -# FIXME: In latest 0.8.19+ -t CLI argument can accept comma separated list of custom output types, hence, no need in double invocation +# FIXME: In latest 0.8.19+ -t CLI argument can accept comma separated list of +# custom output types, hence, no need in double invocation GRCOV_CALL = grcov ./target/profraw --binary-path ./target/release/deps/ -s . --branch --ignore-not-existing --ignore "**/tests/**" RISCV32_TOOLCHAIN_PATH = $(shell pwd)/_riscv32-gnu-toolchain From fc53f67ee9fbeb507fd79986d447097f94ff3358 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Thu, 5 Dec 2024 17:37:05 +0100 Subject: [PATCH 090/165] Makefile: introduce new target to build riscv32im programs --- Makefile | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 0202f2258e..206426feed 100644 --- a/Makefile +++ b/Makefile @@ -11,6 +11,13 @@ COVERAGE_ENV = CARGO_INCREMENTAL=0 RUSTFLAGS='-Cinstrument-coverage' RUSTDOCFLAG GRCOV_CALL = grcov ./target/profraw --binary-path ./target/release/deps/ -s . --branch --ignore-not-existing --ignore "**/tests/**" RISCV32_TOOLCHAIN_PATH = $(shell pwd)/_riscv32-gnu-toolchain +O1VM_RESOURCES_PATH = $(shell pwd)/o1vm/resources/programs +O1VM_RISCV32IM_SOURCE_DIR = ${O1VM_RESOURCES_PATH}/riscv32im/src +O1VM_RISCV32IM_SOURCE_FILES = $(wildcard ${O1VM_RISCV32IM_SOURCE_DIR}/*.S) +O1VM_RISCV32IM_BIN_DIR = ${O1VM_RESOURCES_PATH}/riscv32im/bin +O1VM_RISCV32IM_BIN_FILES = $(patsubst ${O1VM_RISCV32IM_SOURCE_DIR}/%.S,${O1VM_RISCV32IM_BIN_DIR}/%.o,${O1VM_RISCV32IM_SOURCE_FILES}) +RISCV32_AS_FLAGS = --warn --fatal-warnings + # Default target all: release @@ -147,7 +154,18 @@ setup-riscv32-toolchain: @echo "RISC-V 32-bits toolchain is ready in ${RISCV32_TOOLCHAIN_PATH}/build" @echo "" +build-riscv32-programs: setup-riscv32-toolchain ${O1VM_RISCV32IM_BIN_FILES} + +${O1VM_RISCV32IM_BIN_DIR}/%.o: ${O1VM_RISCV32IM_SOURCE_DIR}/%.S + @echo "" + @echo "Building the RISC-V 32-bits binary: $@ using $<" + @echo "" + mkdir -p ${O1VM_RISCV32IM_BIN_DIR} + ${RISCV32_TOOLCHAIN_PATH}/build/bin/riscv32-unknown-elf-as ${RISCV32_AS_FLAGS} -o $@ $< + ${RISCV32_TOOLCHAIN_PATH}/build/bin/riscv32-unknown-elf-ld -s -o $(basename $@) $@ + @echo "" + fclean: clean rm -rf ${RISCV32_TOOLCHAIN_PATH} -.PHONY: all setup install-test-deps clean build release test-doc test-doc-with-coverage test test-with-coverage test-heavy test-heavy-with-coverage test-all test-all-with-coverage nextest nextest-with-coverage nextest-heavy nextest-heavy-with-coverage nextest-all nextest-all-with-coverage format lint generate-test-coverage-report generate-doc setup-riscv32-toolchain help fclean +.PHONY: all setup install-test-deps clean build release test-doc test-doc-with-coverage test test-with-coverage test-heavy test-heavy-with-coverage test-all test-all-with-coverage nextest nextest-with-coverage nextest-heavy nextest-heavy-with-coverage nextest-all nextest-all-with-coverage format lint generate-test-coverage-report generate-doc setup-riscv32-toolchain help fclean build-riscv32-programs From 26c0f7f6068b4bb24d7a21b31c8d63db23d3bb63 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Thu, 5 Dec 2024 17:35:44 +0100 Subject: [PATCH 091/165] o1vm/riscv32im: introduce sll.S --- o1vm/resources/programs/riscv32im/src/sll.S | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 o1vm/resources/programs/riscv32im/src/sll.S diff --git a/o1vm/resources/programs/riscv32im/src/sll.S b/o1vm/resources/programs/riscv32im/src/sll.S new file mode 100644 index 0000000000..0f8cedd065 --- /dev/null +++ b/o1vm/resources/programs/riscv32im/src/sll.S @@ -0,0 +1,17 @@ +.global _start + +exit_success: + li a0, 0 + li a1, 0 + li a2, 0 + li a3, 0 + li a4, 0 + li a5, 0 + li a6, 0 + li a7, 42 + ecall + +_start: + lui t0, 0x42 + sll t0, t0, 2 + jal exit_success From 522153e8634ef11a6ff5a01a7a619a0186a7bb4b Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Thu, 5 Dec 2024 17:37:20 +0100 Subject: [PATCH 092/165] o1vm/riscv32im: add output of make build-riscv32-programs --- o1vm/resources/programs/riscv32im/bin/sll | Bin 0 -> 456 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100755 o1vm/resources/programs/riscv32im/bin/sll diff --git a/o1vm/resources/programs/riscv32im/bin/sll b/o1vm/resources/programs/riscv32im/bin/sll new file mode 100755 index 0000000000000000000000000000000000000000..f5a7fc75b1f62ac9d2aebd97981d7a0843554b68 GIT binary patch literal 456 zcma)2F;2rk5L`P6i9`eP2T*8IS>(tED4?RG=5#TRI4K6}ZWEz2{DCx-6#Ri_fkchO zOpHyNv1Vs>HK+6K^X2tbk|fe1m2YA9iaLW%(Db1*IgwN*@I8D|zqbdV_RllNvt)y& zW0o9ncqEd+Y{BdR3T8tnn2n&Lw=^R5G49LuWh|dx_UGajgWzMamgEL@5Z33$n|f+1 zQ=eH!w=lJ_cPtxU#K8H+FUp6aL=e8JR?8`kbJb&GmLV2!B6+-z8r01t*YZgv-`$lv z)!^qVE%`tD;t)Z;8qX4iQz)+Jz#S3CAosXyP`ICVkDRqTq$1a$hrwyr{pWrG=_EaK literal 0 HcmV?d00001 From 5fded0f0f90ed411033a2fd8fbe2df54cde29676 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Thu, 5 Dec 2024 18:23:28 +0100 Subject: [PATCH 093/165] o1vm/tests: test_sll --- o1vm/tests/test_riscv_elf.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/o1vm/tests/test_riscv_elf.rs b/o1vm/tests/test_riscv_elf.rs index 520d634ae0..4152a5d4bc 100644 --- a/o1vm/tests/test_riscv_elf.rs +++ b/o1vm/tests/test_riscv_elf.rs @@ -73,3 +73,22 @@ fn test_fibonacci_7() { } } } + +// FIXME: stop ignore when all the instructions necessary for running this +// program are implemented. +#[test] +#[ignore] +fn test_sll() { + let curr_dir = std::env::current_dir().unwrap(); + let path = curr_dir.join(std::path::PathBuf::from( + "resources/programs/riscv32im/bin/sll", + )); + let state = o1vm::elf_loader::parse_riscv32(&path).unwrap(); + let mut witness = Env::::create(PAGE_SIZE.try_into().unwrap(), state); + + while !witness.halt { + witness.step(); + } + + // FIXME: check the state of the registers after the program has run. +} From 9c9dfd4a5c35bd2f7b2ffd8ad3544518f37d5c3a Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Thu, 5 Dec 2024 19:32:24 +0100 Subject: [PATCH 094/165] o1vm/README: add a section to reg. new test examples --- o1vm/README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/o1vm/README.md b/o1vm/README.md index 827a496056..31d7dd7dc7 100644 --- a/o1vm/README.md +++ b/o1vm/README.md @@ -209,3 +209,11 @@ _riscv32-gnu-toolchain/build/riscv32-unknown-elf-as \ -o a.out \ o1vm/resources/programs/riscv32im/src/${FILENAME} ``` + +### Write new test examples + +The Makefile at the top-level of this repository will automatically detect new +`.S` files in the directory `o1vm/resources/programs/riscv32im/src/` when the +target `build-riscv32-programs` is called. Any change to the existing files will +also be detected by the target, and you can commit the changes of the resulting +binary. From 710eaba203c7aa8fe6ecf70b4063b5107fe2504d Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Thu, 5 Dec 2024 19:34:05 +0100 Subject: [PATCH 095/165] Makefile: clean object files rel. to riscv32im programs --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 206426feed..3b19ceb0d4 100644 --- a/Makefile +++ b/Makefile @@ -48,6 +48,7 @@ install-test-deps: ## Install test dependencies clean: ## Clean the project cargo clean + rm -rf $(O1VM_RISCV32IM_BIN_FILES) build: ## Build the project From af395a4fe73b9f84d8dde06ec3a571192036dd85 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Thu, 5 Dec 2024 21:15:26 +0100 Subject: [PATCH 096/165] Makefile: add missing documentation to targets --- Makefile | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 3b19ceb0d4..c86e935ea1 100644 --- a/Makefile +++ b/Makefile @@ -115,7 +115,7 @@ format: ## Format the code lint: ## Lint the code cargo clippy --all-features --all-targets --tests $(CARGO_EXTRA_ARGS) -- -W clippy::all -D warnings -generate-test-coverage-report: +generate-test-coverage-report: ## Generate the code coverage report @echo "" @echo "Generating the test coverage report." @echo "" @@ -129,7 +129,7 @@ generate-test-coverage-report: @echo "The test coverage report is available at: ./target/coverage" @echo "" -generate-doc: +generate-doc: ## Generate the Rust documentation @echo "" @echo "Generating the documentation." @echo "" @@ -142,7 +142,7 @@ help: ## Ask for help! @grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' -setup-riscv32-toolchain: +setup-riscv32-toolchain: ## Download and compile the RISC-V 32bits toolchain @echo "" @echo "Setting up the RISC-V 32-bit toolchain" @echo "" @@ -155,7 +155,7 @@ setup-riscv32-toolchain: @echo "RISC-V 32-bits toolchain is ready in ${RISCV32_TOOLCHAIN_PATH}/build" @echo "" -build-riscv32-programs: setup-riscv32-toolchain ${O1VM_RISCV32IM_BIN_FILES} +build-riscv32-programs: setup-riscv32-toolchain ${O1VM_RISCV32IM_BIN_FILES} ## Build all RISC-V 32 bits programs written for the o1vm ${O1VM_RISCV32IM_BIN_DIR}/%.o: ${O1VM_RISCV32IM_SOURCE_DIR}/%.S @echo "" @@ -166,7 +166,7 @@ ${O1VM_RISCV32IM_BIN_DIR}/%.o: ${O1VM_RISCV32IM_SOURCE_DIR}/%.S ${RISCV32_TOOLCHAIN_PATH}/build/bin/riscv32-unknown-elf-ld -s -o $(basename $@) $@ @echo "" -fclean: clean +fclean: clean ## Clean the tooling artefacts in addition to running clean rm -rf ${RISCV32_TOOLCHAIN_PATH} .PHONY: all setup install-test-deps clean build release test-doc test-doc-with-coverage test test-with-coverage test-heavy test-heavy-with-coverage test-all test-all-with-coverage nextest nextest-with-coverage nextest-heavy nextest-heavy-with-coverage nextest-all nextest-all-with-coverage format lint generate-test-coverage-report generate-doc setup-riscv32-toolchain help fclean build-riscv32-programs From 5b737653eb805cef04f4f12cf073bd182928fd79 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Fri, 6 Dec 2024 13:44:27 +0100 Subject: [PATCH 097/165] Update o1vm/README.md Co-authored-by: Martin Allen <31280145+martyall@users.noreply.github.com> --- o1vm/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/o1vm/README.md b/o1vm/README.md index 31d7dd7dc7..4073dd7ae6 100644 --- a/o1vm/README.md +++ b/o1vm/README.md @@ -193,7 +193,7 @@ For the RISC-V 32 bits architecture, the user can install the toolchain by using `make setup-riscv32-toolchain`. If you encounter any issue with the build dependencies, you can refer to [this -GitHub repository](https://github.com/riscv-collab/riscv-gnu-toolchain). +GitHub repository](https://github.com/riscv-collab/riscv-gnu-toolchain?tab=readme-ov-file#prerequisites). The toolchain will be available in the directory `_riscv32-gnu-toolchain/build` at the root of this repository (see variable From a1f7931939455f024b8c0cec649627adfb2e3aa3 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Fri, 6 Dec 2024 13:44:36 +0100 Subject: [PATCH 098/165] Update o1vm/README.md Co-authored-by: Martin Allen <31280145+martyall@users.noreply.github.com> --- o1vm/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/o1vm/README.md b/o1vm/README.md index 4073dd7ae6..de0a8773c0 100644 --- a/o1vm/README.md +++ b/o1vm/README.md @@ -203,7 +203,7 @@ To compile on of the source files available in `resources/programs/riscv32im/src`, the user can use: ```shell -FILENAME=sll.s +FILENAME=sll.S _riscv32-gnu-toolchain/build/riscv32-unknown-elf-as \ -o a.out \ From 4c913481d17a62e8815c7c2b0317527245837b8b Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 11 Dec 2024 15:58:22 +0100 Subject: [PATCH 099/165] Update o1vm/README.md Co-authored-by: Martin Allen <31280145+martyall@users.noreply.github.com> --- o1vm/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/o1vm/README.md b/o1vm/README.md index de0a8773c0..d8dbd5d3d0 100644 --- a/o1vm/README.md +++ b/o1vm/README.md @@ -205,7 +205,7 @@ To compile on of the source files available in ```shell FILENAME=sll.S -_riscv32-gnu-toolchain/build/riscv32-unknown-elf-as \ +_riscv32-gnu-toolchain/build/bin/riscv32-unknown-elf-as -o a.out \ o1vm/resources/programs/riscv32im/src/${FILENAME} ``` From eb0c6a95a6303826eee9cb6e7c65d32f5ccd00b9 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 16 Oct 2024 17:13:36 +0200 Subject: [PATCH 100/165] MVPoly/PBT: remove a flaky test for multilinearity It does depend on maximum degree given in parameter. The probability is not negligible if 2 is given. --- mvpoly/src/pbt.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/mvpoly/src/pbt.rs b/mvpoly/src/pbt.rs index b517f0107f..130c6c9fc4 100644 --- a/mvpoly/src/pbt.rs +++ b/mvpoly/src/pbt.rs @@ -556,12 +556,6 @@ pub fn test_is_multilinear>() { From 55acf93dfe75aa9676aa8d72c6a0330d8269ce13 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 16 Oct 2024 17:13:12 +0200 Subject: [PATCH 101/165] MVPoly/monomials: improve generation of random generation --- mvpoly/src/monomials.rs | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/mvpoly/src/monomials.rs b/mvpoly/src/monomials.rs index 8fb495ef02..3a11fe4ef5 100644 --- a/mvpoly/src/monomials.rs +++ b/mvpoly/src/monomials.rs @@ -1,7 +1,7 @@ use ark_ff::{One, PrimeField, Zero}; use kimchi::circuits::{expr::Variable, gate::CurrOrNext}; use num_integer::binomial; -use rand::RngCore; +use rand::{Rng, RngCore}; use std::{ collections::HashMap, fmt::Debug, @@ -291,9 +291,31 @@ impl MVPoly for Sparse(rng: &mut RNG, max_degree: Option) -> Self { - // IMPROVEME: using prime::Dense::random to ease the implementaiton. - // Feel free to change - prime::Dense::random(rng, max_degree).into() + let degree = max_degree.unwrap_or(D); + // Generating all monomials with degree <= degree^N + let nested_loops_indices: Vec> = compute_indices_nested_loop(vec![degree; N]); + // Filtering the monomials with degree <= degree + let exponents: Vec> = nested_loops_indices + .into_iter() + .filter(|indices| { + let sum = indices.iter().sum::(); + sum <= degree + }) + .collect(); + // We add 10% of zeroes. + let exponents: Vec<_> = exponents + .into_iter() + .filter(|_indices| rng.gen_range(0..10) != 0) + .collect(); + // Generating random coefficients for the 90% + let monomials: HashMap<[usize; N], F> = exponents + .into_iter() + .map(|indices| { + let coeff = F::rand(rng); + (indices.try_into().unwrap(), coeff) + }) + .collect(); + Self { monomials } } fn from_variable>( From ac2500fd05694919bcc06687486f0dc2ed3bc820 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 11 Dec 2024 15:38:51 +0100 Subject: [PATCH 102/165] mvpoly: introduce optional param upper bound to compute nested loops using filter_map speeds up the computation by avoiding creating a bigger map than expected if a low upper bound is given with large number of indices. --- mvpoly/src/monomials.rs | 9 ++++++--- mvpoly/src/utils.rs | 20 ++++++++++++++++---- mvpoly/tests/utils.rs | 29 +++++++++++++++++++++-------- 3 files changed, 43 insertions(+), 15 deletions(-) diff --git a/mvpoly/src/monomials.rs b/mvpoly/src/monomials.rs index 3a11fe4ef5..275d322a5a 100644 --- a/mvpoly/src/monomials.rs +++ b/mvpoly/src/monomials.rs @@ -293,7 +293,8 @@ impl MVPoly for Sparse(rng: &mut RNG, max_degree: Option) -> Self { let degree = max_degree.unwrap_or(D); // Generating all monomials with degree <= degree^N - let nested_loops_indices: Vec> = compute_indices_nested_loop(vec![degree; N]); + let nested_loops_indices: Vec> = + compute_indices_nested_loop(vec![degree; N], max_degree); // Filtering the monomials with degree <= degree let exponents: Vec> = nested_loops_indices .into_iter() @@ -409,8 +410,10 @@ impl MVPoly for Sparse) -> Vec> { +pub fn compute_indices_nested_loop( + nested_loop_sizes: Vec, + upper_bound: Option, +) -> Vec> { let n = nested_loop_sizes.iter().product(); (0..n) - .map(|i| { + .filter_map(|i| { let mut div = 1; // Compute indices for the loop, step i let indices: Vec = nested_loop_sizes @@ -268,7 +272,15 @@ pub fn compute_indices_nested_loop(nested_loop_sizes: Vec) -> Vec() <= upper_bound { + Some(indices) + } else { + None + } + } else { + Some(indices) + } }) .collect() } diff --git a/mvpoly/tests/utils.rs b/mvpoly/tests/utils.rs index dad2abe4d3..032f36ec77 100644 --- a/mvpoly/tests/utils.rs +++ b/mvpoly/tests/utils.rs @@ -232,7 +232,7 @@ pub fn test_compute_indices_nested_loop() { // sorting to get the same order let mut exp_indices = vec![vec![0, 0], vec![0, 1], vec![1, 0], vec![1, 1]]; exp_indices.sort(); - let mut comp_indices = compute_indices_nested_loop(nested_loops); + let mut comp_indices = compute_indices_nested_loop(nested_loops, None); comp_indices.sort(); assert_eq!(exp_indices, comp_indices); @@ -247,7 +247,7 @@ pub fn test_compute_indices_nested_loop() { vec![2, 1], ]; exp_indices.sort(); - let mut comp_indices = compute_indices_nested_loop(nested_loops); + let mut comp_indices = compute_indices_nested_loop(nested_loops, None); comp_indices.sort(); assert_eq!(exp_indices, comp_indices); @@ -292,38 +292,51 @@ pub fn test_compute_indices_nested_loop() { vec![2, 2, 1, 1], ]; exp_indices.sort(); - let mut comp_indices = compute_indices_nested_loop(nested_loops); + let mut comp_indices = compute_indices_nested_loop(nested_loops, None); comp_indices.sort(); assert_eq!(exp_indices, comp_indices); // Simple and single loop let nested_loops = vec![3]; let exp_indices = vec![vec![0], vec![1], vec![2]]; - let mut comp_indices = compute_indices_nested_loop(nested_loops); + let mut comp_indices = compute_indices_nested_loop(nested_loops, None); comp_indices.sort(); assert_eq!(exp_indices, comp_indices); // relatively large loops let nested_loops = vec![10, 10]; - let comp_indices = compute_indices_nested_loop(nested_loops); + let comp_indices = compute_indices_nested_loop(nested_loops, None); // Only checking the length as it would take too long to unroll the result assert_eq!(comp_indices.len(), 100); // Non-uniform loop sizes, relatively large let nested_loops = vec![5, 7, 3]; - let comp_indices = compute_indices_nested_loop(nested_loops); + let comp_indices = compute_indices_nested_loop(nested_loops, None); assert_eq!(comp_indices.len(), 5 * 7 * 3); } #[test] fn test_compute_indices_nested_loop_edge_cases() { let nested_loops = vec![]; - let comp_indices: Vec> = compute_indices_nested_loop(nested_loops); + let comp_indices: Vec> = compute_indices_nested_loop(nested_loops, None); let exp_output: Vec> = vec![vec![]]; assert_eq!(comp_indices, exp_output); // With one empty loop. Should match the documentation let nested_loops = vec![3, 0, 2]; - let comp_indices = compute_indices_nested_loop(nested_loops); + let comp_indices = compute_indices_nested_loop(nested_loops, None); assert_eq!(comp_indices.len(), 0); } + +#[test] +fn test_compute_indices_nested_loops_upper_bound() { + let nested_loops = vec![3, 3]; + let comp_indices = compute_indices_nested_loop(nested_loops.clone(), Some(0)); + assert_eq!(comp_indices.len(), 1); + + let comp_indices = compute_indices_nested_loop(nested_loops.clone(), Some(1)); + assert_eq!(comp_indices.len(), 3); + + let comp_indices = compute_indices_nested_loop(nested_loops, Some(2)); + assert_eq!(comp_indices.len(), 6); +} From 29b12a8df5b163e173a6b48c2513ac9bcdae69eb Mon Sep 17 00:00:00 2001 From: svv232 Date: Wed, 11 Dec 2024 11:19:28 -0500 Subject: [PATCH 103/165] correctly parse the shant --- o1vm/src/interpreters/riscv32im/interpreter.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index 54070f55ce..eefccaee39 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -1756,7 +1756,7 @@ pub fn interpret_itype(env: &mut Env, instr: IInstruction) let local_rs1 = env.read_register(&rs1); let shamt = { let pos = env.alloc_scratch(); - unsafe { env.bitmask(&imm, 4, 0, pos) } + unsafe { env.bitmask(&imm, 5, 0, pos) } }; // parse shamt from imm as 20-24 of instruction and 0-4 wrt to imm let rd_scratch = env.alloc_scratch(); From c5a30739b7defda1c61443ce54f8e44eb41cc4ff Mon Sep 17 00:00:00 2001 From: svv232 Date: Wed, 11 Dec 2024 11:22:49 -0500 Subject: [PATCH 104/165] keep the standard variable allocation syntax for interpreter variables for clarity --- o1vm/src/interpreters/riscv32im/interpreter.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index eefccaee39..c5e52c2760 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -1759,8 +1759,10 @@ pub fn interpret_itype(env: &mut Env, instr: IInstruction) unsafe { env.bitmask(&imm, 5, 0, pos) } }; // parse shamt from imm as 20-24 of instruction and 0-4 wrt to imm - let rd_scratch = env.alloc_scratch(); - let local_rd = unsafe { env.shift_left(&local_rs1, &shamt, rd_scratch) }; + let local_rd = { + let pos = env.alloc_scratch(); + unsafe { env.shift_left(&local_rs1, &shamt, pos) } + }; env.write_register(&rd, local_rd); env.set_instruction_pointer(next_instruction_pointer.clone()); From 801c127d94bc63576948119ce236ed5bc375b8ee Mon Sep 17 00:00:00 2001 From: svv232 Date: Wed, 11 Dec 2024 11:26:24 -0500 Subject: [PATCH 105/165] standardize variable allocation and correctly parse the shant --- o1vm/src/interpreters/riscv32im/interpreter.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index 0dfc52a796..1433e09bf3 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -1771,11 +1771,13 @@ pub fn interpret_itype(env: &mut Env, instr: IInstruction) let local_rs1 = env.read_register(&rs1); let shamt = { let pos = env.alloc_scratch(); - unsafe { env.bitmask(&imm, 4, 0, pos) } + unsafe { env.bitmask(&imm, 5, 0, pos) } }; // parse shamt from imm as 20-24 of instruction and 0-4 wrt to imm - let rd_scratch = env.alloc_scratch(); - let local_rd = unsafe { env.shift_right(&local_rs1, &shamt, rd_scratch) }; + let local_rd = { + let pos = env.alloc_scratch(); + unsafe { env.shift_right(&local_rs1, &shamt, pos) } + }; env.write_register(&rd, local_rd); env.set_instruction_pointer(next_instruction_pointer.clone()); env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); From 82941a9ce532fc97da92d78f391c379e92f36ea3 Mon Sep 17 00:00:00 2001 From: svv232 Date: Wed, 11 Dec 2024 11:57:32 -0500 Subject: [PATCH 106/165] correctly parse the shamt for asr and limit scope of the position variable --- o1vm/src/interpreters/riscv32im/interpreter.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index 84ea43aee4..fb53f3fda4 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -1785,14 +1785,16 @@ pub fn interpret_itype(env: &mut Env, instr: IInstruction) let local_rs1 = env.read_register(&rs1); let shamt = { let pos = env.alloc_scratch(); - unsafe { env.bitmask(&imm, 4, 0, pos) } + unsafe { env.bitmask(&imm, 5, 0, pos) } }; // parse shamt from imm as 20-24 of instruction and 0-4 wrt to imm // sign extend shamt for arithmetic shift let shamt = env.sign_extend(&shamt, 4); - let rd_scratch = env.alloc_scratch(); - let local_rd = unsafe { env.shift_right_arithmetic(&local_rs1, &shamt, rd_scratch) }; + let local_rd = { + let pos = env.alloc_scratch(); + unsafe { env.shift_right_arithmetic(&local_rs1, &shamt, pos) } + }; env.write_register(&rd, local_rd); env.set_instruction_pointer(next_instruction_pointer.clone()); env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); From 3aea474bc8810ef45e5bc018e8376c26c93d9f16 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 11 Dec 2024 18:19:00 +0100 Subject: [PATCH 107/165] Arrabbiata: use arrabbiata instead of arrabiata --- Cargo.lock | 2 +- Cargo.toml | 4 ++-- {arrabiata => arrabbiata}/Cargo.toml | 4 ++-- {arrabiata => arrabbiata}/README.md | 2 +- {arrabiata => arrabbiata}/notes.md | 0 {arrabiata => arrabbiata}/src/column_env.rs | 0 {arrabiata => arrabbiata}/src/columns.rs | 0 {arrabiata => arrabbiata}/src/constraints.rs | 0 {arrabiata => arrabbiata}/src/interpreter.rs | 0 {arrabiata => arrabbiata}/src/lib.rs | 0 {arrabiata => arrabbiata}/src/logup.rs | 0 {arrabiata => arrabbiata}/src/main.rs | 2 +- {arrabiata => arrabbiata}/src/poseidon_3_60_0_5_5_fp.rs | 0 {arrabiata => arrabbiata}/src/poseidon_3_60_0_5_5_fq.rs | 0 {arrabiata => arrabbiata}/src/proof.rs | 0 {arrabiata => arrabbiata}/src/prover.rs | 0 {arrabiata => arrabbiata}/src/verifier.rs | 0 {arrabiata => arrabbiata}/src/witness.rs | 0 {arrabiata => arrabbiata}/tests/constraints.rs | 2 +- {arrabiata => arrabbiata}/tests/utils.rs | 0 {arrabiata => arrabbiata}/tests/witness.rs | 2 +- {arrabiata => arrabbiata}/tests/witness_utils.rs | 2 +- mvpoly/tests/monomials.rs | 2 +- mvpoly/tests/prime.rs | 2 +- 24 files changed, 12 insertions(+), 12 deletions(-) rename {arrabiata => arrabbiata}/Cargo.toml (95%) rename {arrabiata => arrabbiata}/README.md (97%) rename {arrabiata => arrabbiata}/notes.md (100%) rename {arrabiata => arrabbiata}/src/column_env.rs (100%) rename {arrabiata => arrabbiata}/src/columns.rs (100%) rename {arrabiata => arrabbiata}/src/constraints.rs (100%) rename {arrabiata => arrabbiata}/src/interpreter.rs (100%) rename {arrabiata => arrabbiata}/src/lib.rs (100%) rename {arrabiata => arrabbiata}/src/logup.rs (100%) rename {arrabiata => arrabbiata}/src/main.rs (99%) rename {arrabiata => arrabbiata}/src/poseidon_3_60_0_5_5_fp.rs (100%) rename {arrabiata => arrabbiata}/src/poseidon_3_60_0_5_5_fq.rs (100%) rename {arrabiata => arrabbiata}/src/proof.rs (100%) rename {arrabiata => arrabbiata}/src/prover.rs (100%) rename {arrabiata => arrabbiata}/src/verifier.rs (100%) rename {arrabiata => arrabbiata}/src/witness.rs (100%) rename {arrabiata => arrabbiata}/tests/constraints.rs (99%) rename {arrabiata => arrabbiata}/tests/utils.rs (100%) rename {arrabiata => arrabbiata}/tests/witness.rs (99%) rename {arrabiata => arrabbiata}/tests/witness_utils.rs (97%) diff --git a/Cargo.lock b/Cargo.lock index 8295764350..917bab5d39 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -275,7 +275,7 @@ dependencies = [ ] [[package]] -name = "arrabiata" +name = "arrabbiata" version = "0.1.0" dependencies = [ "ark-ec", diff --git a/Cargo.toml b/Cargo.toml index fb82149618..6e35076b45 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [workspace] members = [ - "arrabiata", + "arrabbiata", "book", "turshi", "curves", @@ -81,7 +81,7 @@ tinytemplate = "1.1" wasm-bindgen = "=0.2.90" -arrabiata = { path = "./arrabiata", version = "0.1.0" } +arrabbiata = { path = "./arrabbiata", version = "0.1.0" } folding = { path = "./folding", version = "0.1.0" } groupmap = { path = "./groupmap", version = "0.1.0" } internal-tracing = { path = "./internal-tracing", version = "0.1.0" } diff --git a/arrabiata/Cargo.toml b/arrabbiata/Cargo.toml similarity index 95% rename from arrabiata/Cargo.toml rename to arrabbiata/Cargo.toml index 599b627ec9..6ed50d574e 100644 --- a/arrabiata/Cargo.toml +++ b/arrabbiata/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "arrabiata" +name = "arrabbiata" version = "0.1.0" repository = "https://github.com/o1-labs/proof-systems" homepage = "https://o1-labs.github.io/proof-systems/" @@ -8,7 +8,7 @@ edition = "2021" license = "Apache-2.0" [[bin]] -name = "arrabiata" +name = "arrabbiata" path = "src/main.rs" [dependencies] diff --git a/arrabiata/README.md b/arrabbiata/README.md similarity index 97% rename from arrabiata/README.md rename to arrabbiata/README.md index 81b68bd077..e92025b244 100644 --- a/arrabiata/README.md +++ b/arrabbiata/README.md @@ -1,4 +1,4 @@ -## Arrabiata - a generic recursive zero-knowledge argument implementation based on folding schemes +## Arrabbiata - a generic recursive zero-knowledge argument implementation based on folding schemes ### Motivation diff --git a/arrabiata/notes.md b/arrabbiata/notes.md similarity index 100% rename from arrabiata/notes.md rename to arrabbiata/notes.md diff --git a/arrabiata/src/column_env.rs b/arrabbiata/src/column_env.rs similarity index 100% rename from arrabiata/src/column_env.rs rename to arrabbiata/src/column_env.rs diff --git a/arrabiata/src/columns.rs b/arrabbiata/src/columns.rs similarity index 100% rename from arrabiata/src/columns.rs rename to arrabbiata/src/columns.rs diff --git a/arrabiata/src/constraints.rs b/arrabbiata/src/constraints.rs similarity index 100% rename from arrabiata/src/constraints.rs rename to arrabbiata/src/constraints.rs diff --git a/arrabiata/src/interpreter.rs b/arrabbiata/src/interpreter.rs similarity index 100% rename from arrabiata/src/interpreter.rs rename to arrabbiata/src/interpreter.rs diff --git a/arrabiata/src/lib.rs b/arrabbiata/src/lib.rs similarity index 100% rename from arrabiata/src/lib.rs rename to arrabbiata/src/lib.rs diff --git a/arrabiata/src/logup.rs b/arrabbiata/src/logup.rs similarity index 100% rename from arrabiata/src/logup.rs rename to arrabbiata/src/logup.rs diff --git a/arrabiata/src/main.rs b/arrabbiata/src/main.rs similarity index 99% rename from arrabiata/src/main.rs rename to arrabbiata/src/main.rs index 5d68a9ff6b..c242401495 100644 --- a/arrabiata/src/main.rs +++ b/arrabbiata/src/main.rs @@ -1,4 +1,4 @@ -use arrabiata::{ +use arrabbiata::{ interpreter::{self, InterpreterEnv}, witness::Env, IVC_CIRCUIT_SIZE, MIN_SRS_LOG2_SIZE, POSEIDON_STATE_SIZE, diff --git a/arrabiata/src/poseidon_3_60_0_5_5_fp.rs b/arrabbiata/src/poseidon_3_60_0_5_5_fp.rs similarity index 100% rename from arrabiata/src/poseidon_3_60_0_5_5_fp.rs rename to arrabbiata/src/poseidon_3_60_0_5_5_fp.rs diff --git a/arrabiata/src/poseidon_3_60_0_5_5_fq.rs b/arrabbiata/src/poseidon_3_60_0_5_5_fq.rs similarity index 100% rename from arrabiata/src/poseidon_3_60_0_5_5_fq.rs rename to arrabbiata/src/poseidon_3_60_0_5_5_fq.rs diff --git a/arrabiata/src/proof.rs b/arrabbiata/src/proof.rs similarity index 100% rename from arrabiata/src/proof.rs rename to arrabbiata/src/proof.rs diff --git a/arrabiata/src/prover.rs b/arrabbiata/src/prover.rs similarity index 100% rename from arrabiata/src/prover.rs rename to arrabbiata/src/prover.rs diff --git a/arrabiata/src/verifier.rs b/arrabbiata/src/verifier.rs similarity index 100% rename from arrabiata/src/verifier.rs rename to arrabbiata/src/verifier.rs diff --git a/arrabiata/src/witness.rs b/arrabbiata/src/witness.rs similarity index 100% rename from arrabiata/src/witness.rs rename to arrabbiata/src/witness.rs diff --git a/arrabiata/tests/constraints.rs b/arrabbiata/tests/constraints.rs similarity index 99% rename from arrabiata/tests/constraints.rs rename to arrabbiata/tests/constraints.rs index 8506e5a183..5ed9196b55 100644 --- a/arrabiata/tests/constraints.rs +++ b/arrabbiata/tests/constraints.rs @@ -1,7 +1,7 @@ use num_bigint::BigInt; use std::collections::HashMap; -use arrabiata::{ +use arrabbiata::{ columns::Gadget, constraints, interpreter::{self, Instruction}, diff --git a/arrabiata/tests/utils.rs b/arrabbiata/tests/utils.rs similarity index 100% rename from arrabiata/tests/utils.rs rename to arrabbiata/tests/utils.rs diff --git a/arrabiata/tests/witness.rs b/arrabbiata/tests/witness.rs similarity index 99% rename from arrabiata/tests/witness.rs rename to arrabbiata/tests/witness.rs index 5c8239d889..402cd9d9fa 100644 --- a/arrabiata/tests/witness.rs +++ b/arrabbiata/tests/witness.rs @@ -1,6 +1,6 @@ use ark_ec::{AffineRepr, Group}; use ark_ff::{PrimeField, UniformRand}; -use arrabiata::{ +use arrabbiata::{ interpreter::{self, Instruction, InterpreterEnv}, poseidon_3_60_0_5_5_fp, witness::Env, diff --git a/arrabiata/tests/witness_utils.rs b/arrabbiata/tests/witness_utils.rs similarity index 97% rename from arrabiata/tests/witness_utils.rs rename to arrabbiata/tests/witness_utils.rs index 7e6c78e876..7d71aba2f4 100644 --- a/arrabiata/tests/witness_utils.rs +++ b/arrabbiata/tests/witness_utils.rs @@ -3,7 +3,7 @@ //! A user is expected to use the gadget methods. //! The API of the utilities is more subject to changes. -use arrabiata::{interpreter::InterpreterEnv, witness::Env, POSEIDON_STATE_SIZE}; +use arrabbiata::{interpreter::InterpreterEnv, witness::Env, POSEIDON_STATE_SIZE}; use mina_curves::pasta::{Fp, Fq, Pallas, Vesta}; use num_bigint::BigInt; use o1_utils::FieldHelpers; diff --git a/mvpoly/tests/monomials.rs b/mvpoly/tests/monomials.rs index 902a3fcfbc..514ab7cc7b 100644 --- a/mvpoly/tests/monomials.rs +++ b/mvpoly/tests/monomials.rs @@ -575,7 +575,7 @@ fn test_build_from_variable_next_row_with_offset_given() { fn test_from_expr_ec_addition() { // Simulate a real usecase // The following lines/design look similar to the ones we use in - // o1vm/arrabiata + // o1vm/arrabbiata #[derive(Clone, Copy, PartialEq)] enum Column { X(usize), diff --git a/mvpoly/tests/prime.rs b/mvpoly/tests/prime.rs index 17cc6a3eb1..f86a2262cf 100644 --- a/mvpoly/tests/prime.rs +++ b/mvpoly/tests/prime.rs @@ -365,7 +365,7 @@ fn test_evaluation_predefined_polynomial() { fn test_from_expr_ec_addition() { // Simulate a real usecase // The following lines/design look similar to the ones we use in - // o1vm/arrabiata + // o1vm/arrabbiata #[derive(Clone, Copy, PartialEq)] enum Column { X(usize), From 4ba3d5836550e46e78fabb849b0be26850e0ddf8 Mon Sep 17 00:00:00 2001 From: svv232 Date: Wed, 11 Dec 2024 12:37:25 -0500 Subject: [PATCH 108/165] parse the shamt at the top level and add correct range and value check --- .../src/interpreters/riscv32im/interpreter.rs | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index c5e52c2760..7113ea56c6 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -1637,6 +1637,21 @@ pub fn interpret_itype(env: &mut Env, instr: IInstruction) env.range_check16(&imm, 12); + let shamt = { + let pos = env.alloc_scratch(); + unsafe { env.bitmask(&imm, 5, 0, pos) } + }; + env.range_check8(&shamt, 5); + + let imm_header = { + let pos = env.alloc_scratch(); + unsafe { env.bitmask(&imm, 12, 5, pos) } + }; + env.range_check8(&imm_header, 7); + + // check the correctness of the immediate and shamt + env.add_constraint(imm.clone() - (imm_header.clone() * Env::constant(1 << 5)) - shamt.clone()); + // check correctness of decomposition env.add_constraint( instruction @@ -1754,14 +1769,10 @@ pub fn interpret_itype(env: &mut Env, instr: IInstruction) IInstruction::ShiftLeftLogicalImmediate => { // slli: x[rd] = x[rs1] << shamt let local_rs1 = env.read_register(&rs1); - let shamt = { - let pos = env.alloc_scratch(); - unsafe { env.bitmask(&imm, 5, 0, pos) } - }; - // parse shamt from imm as 20-24 of instruction and 0-4 wrt to imm + let local_rd = { let pos = env.alloc_scratch(); - unsafe { env.shift_left(&local_rs1, &shamt, pos) } + unsafe { env.shift_left(&local_rs1, &shamt.clone(), pos) } }; env.write_register(&rd, local_rd); From d5c6f81a6e3e1cd1811190714b6aa1f2df4cdb9e Mon Sep 17 00:00:00 2001 From: svv232 Date: Wed, 11 Dec 2024 12:44:59 -0500 Subject: [PATCH 109/165] remove shamt parsing from the instruction implementation and utilize top level constraints --- o1vm/src/interpreters/riscv32im/interpreter.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index d56bd49a38..83cf250fbd 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -1782,13 +1782,8 @@ pub fn interpret_itype(env: &mut Env, instr: IInstruction) IInstruction::ShiftRightLogicalImmediate => { // srli: x[rd] = x[rs1] >> shamt let local_rs1 = env.read_register(&rs1); - let shamt = { - let pos = env.alloc_scratch(); - unsafe { env.bitmask(&imm, 4, 0, pos) } - }; - // parse shamt from imm as 20-24 of instruction and 0-4 wrt to imm let rd_scratch = env.alloc_scratch(); - let local_rd = unsafe { env.shift_right(&local_rs1, &shamt, rd_scratch) }; + let local_rd = unsafe { env.shift_right(&local_rs1, &shamt.clone(), rd_scratch) }; env.write_register(&rd, local_rd); env.set_instruction_pointer(next_instruction_pointer.clone()); env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); From 26f96e5ab5d6c9c6282fc52646e38e023cfdaa48 Mon Sep 17 00:00:00 2001 From: svv232 Date: Wed, 11 Dec 2024 12:48:04 -0500 Subject: [PATCH 110/165] remove shamt parsing from the instruction implementation and utilize top level constraints --- o1vm/src/interpreters/riscv32im/interpreter.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index 4d0586ea04..e511f8df62 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -1782,11 +1782,6 @@ pub fn interpret_itype(env: &mut Env, instr: IInstruction) IInstruction::ShiftRightLogicalImmediate => { // srli: x[rd] = x[rs1] >> shamt let local_rs1 = env.read_register(&rs1); - let shamt = { - let pos = env.alloc_scratch(); - unsafe { env.bitmask(&imm, 5, 0, pos) } - }; - // parse shamt from imm as 20-24 of instruction and 0-4 wrt to imm let local_rd = { let pos = env.alloc_scratch(); unsafe { env.shift_right(&local_rs1, &shamt, pos) } From becb4eeef3898d0feda72f8515e133ba3ca5e860 Mon Sep 17 00:00:00 2001 From: svv232 Date: Wed, 11 Dec 2024 13:00:41 -0500 Subject: [PATCH 111/165] remove shamt parsing in shift right arithmetic in favor of top level shamt --- o1vm/src/interpreters/riscv32im/interpreter.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index a90567e32c..6f053def0a 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -1793,13 +1793,6 @@ pub fn interpret_itype(env: &mut Env, instr: IInstruction) IInstruction::ShiftRightArithmeticImmediate => { // srai: x[rd] = x[rs1] >> shamt let local_rs1 = env.read_register(&rs1); - let shamt = { - let pos = env.alloc_scratch(); - unsafe { env.bitmask(&imm, 5, 0, pos) } - }; - // parse shamt from imm as 20-24 of instruction and 0-4 wrt to imm - // sign extend shamt for arithmetic shift - let shamt = env.sign_extend(&shamt, 4); let local_rd = { let pos = env.alloc_scratch(); From 79583b78ebab0fef038fb278b204919b2380cb86 Mon Sep 17 00:00:00 2001 From: Ocenka Date: Sun, 15 Dec 2024 11:00:35 +0000 Subject: [PATCH 112/165] typos README.md --- book/specifications/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/specifications/README.md b/book/specifications/README.md index 0afc221331..14dbb43ccd 100644 --- a/book/specifications/README.md +++ b/book/specifications/README.md @@ -49,4 +49,4 @@ The idea is to keep as much of the specification close to the source, so that mo The specifications are built into the Mina book, and deployed to Github pages, via [this Github Action](/.github/workflows/website.yml). -The Github Action ensures that the generated specifications that are pushed to the remote repository are also up to date. +The Github Action ensures that the generated specifications that are pushed to the remote repository are also up-to-date. From 7ac31f96745028c473aca98d4702487f1f453a19 Mon Sep 17 00:00:00 2001 From: Ocenka Date: Sun, 15 Dec 2024 11:01:13 +0000 Subject: [PATCH 113/165] typos pap.md --- book/src/fundamentals/zkbook_2pc/pap.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/book/src/fundamentals/zkbook_2pc/pap.md b/book/src/fundamentals/zkbook_2pc/pap.md index 504333f83c..971485a0fd 100644 --- a/book/src/fundamentals/zkbook_2pc/pap.md +++ b/book/src/fundamentals/zkbook_2pc/pap.md @@ -24,7 +24,7 @@ The point-and-permute optimization of garbled circuit in [BMR90](https://www.cs. |$(\one,\zero,\one)$|$\enc_{X_a^1,X_b^1}(X_c^1)$| |$(\one,\one,\zero)$|$\enc_{X_a^1,X_b^0}(X_c^0)$| -- When the evaluator gets the input label, say $X_a^1,X_b^1$, the evaluator first extracts the `color` bits $(\lsb(X_a^1),\lsb(X_b^1)) = (\one,\zero)$ and decrypts the corresponding ciphertext (the third one in the above example) to get a output label. +- When the evaluator gets the input label, say $X_a^1,X_b^1$, the evaluator first extracts the `color` bits $(\lsb(X_a^1),\lsb(X_b^1)) = (\one,\zero)$ and decrypts the corresponding ciphertext (the third one in the above example) to get an output label. ## Encryption Instantiation The encryption algorithm is instantiated with hash function (modeled as random oracle) and one-time pad. @@ -44,4 +44,4 @@ For security and efficiency reasons, one usually uses tweakable hash functions: |$(\zero,\zero,\zero)$|$\sH(\gid,X_a^0,X_b^1)\oplus X_c^0$| |$(\zero,\one,\zero)$|$\sH(\gid,X_a^0,X_b^0)\oplus X_c^0$| |$(\one,\zero,\one)$|$\sH(\gid,X_a^1,X_b^1)\oplus X_c^1$| -|$(\one,\one,\zero)$|$\sH(\gid,X_a^1,X_b^0)\oplus X_c^0$| \ No newline at end of file +|$(\one,\one,\zero)$|$\sH(\gid,X_a^1,X_b^0)\oplus X_c^0$| From bfe057d75e6c70af712b3b4474f7c891dc000db0 Mon Sep 17 00:00:00 2001 From: Ocenka Date: Sun, 15 Dec 2024 11:01:57 +0000 Subject: [PATCH 114/165] typos final_check.md --- book/src/kimchi/final_check.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/src/kimchi/final_check.md b/book/src/kimchi/final_check.md index fad1059659..8da20039d4 100644 --- a/book/src/kimchi/final_check.md +++ b/book/src/kimchi/final_check.md @@ -73,7 +73,7 @@ $$ \end{align} $$ -So at the end, when we have to check for the identity $f(\zeta) = Z_H(\zeta) t(\zeta)$ we'll actually have to check something like this (I colored the missing parts on the left hand side of the equation): +So at the end, when we have to check for the identity $f(\zeta) = Z_H(\zeta) t(\zeta)$ we'll actually have to check something like this (I colored the missing parts on the left-hand side of the equation): $$ \begin{align} From 58220b18210337e27c73b120466a798ab18e8e39 Mon Sep 17 00:00:00 2001 From: futreall <86553580+futreall@users.noreply.github.com> Date: Mon, 16 Dec 2024 15:54:37 +0200 Subject: [PATCH 115/165] Update README.md --- hasher/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hasher/README.md b/hasher/README.md index 81c77c7c6d..f490956b5b 100644 --- a/hasher/README.md +++ b/hasher/README.md @@ -1,6 +1,6 @@ # Mina hasher -This crate provides an API and framework for Mina hashing. It is a safe wrapper around Mina's instances of the [Poseidon arithmetic sponge](https://github.com/o1-labs/cryptography-rfcs/blob/master/mina/001-poseidon-sponge.md) that converts it from a sponge into a hash interface. +This crate provides an API and framework for Mina hashing. It is a safe wrapper around Mina's instances of the [Poseidon arithmetic sponge](https://o1-labs.github.io/proof-systems/specs/poseidon.html) that converts it from a sponge into a hash interface. ## Hasher interface From 29ca8f1007baf1b890d7f378f0b412bb49742bf9 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 9 Oct 2024 21:42:26 +0200 Subject: [PATCH 116/165] Arrabiata/main: add more future tasks to remind --- arrabbiata/src/main.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arrabbiata/src/main.rs b/arrabbiata/src/main.rs index c242401495..150d56c4d5 100644 --- a/arrabbiata/src/main.rs +++ b/arrabbiata/src/main.rs @@ -101,6 +101,12 @@ pub fn main() { // FIXME: // Compute the accumulator for the permutation argument + // FIXME: + // Commit to the accumulator and absorb the commitment + + // FIXME: + // Coin challenge α for combining the constraints + // FIXME: // Compute the cross-terms From 56552900c6c16bd832b992cdbf07075be24d6e52 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Tue, 15 Oct 2024 10:51:25 +0200 Subject: [PATCH 117/165] Arrabiata/Column: implement column to usize --- arrabbiata/src/columns.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/arrabbiata/src/columns.rs b/arrabbiata/src/columns.rs index 3efc6e8616..7afa3e3643 100644 --- a/arrabbiata/src/columns.rs +++ b/arrabbiata/src/columns.rs @@ -36,6 +36,22 @@ pub enum Column { X(usize), } +/// Convert a column to a usize. This is used by the library [mvpoly] when we +/// need to compute the cross-terms. +/// For now, we only support the conversion of the private inputs, i.e. the `X` +/// variant. +/// Also, for now, the [mvpoly] library expects the columns to be mapped to a +/// prime number as the prime representation is used under the hood. This must +/// be changed. +impl From for usize { + fn from(val: Column) -> usize { + match val { + Column::X(i) => i, + _ => unimplemented!("Only the private inputs are supported for now"), + } + } +} + pub struct Challenges { /// Challenge used to aggregate the constraints pub alpha: F, From 0083c30e1407c5d71f9a09a6e743e34643c9f17d Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Tue, 15 Oct 2024 16:47:11 +0200 Subject: [PATCH 118/165] Arrabiata/Column: support conversion of public inputs into usize We do suppose evaluations of the public inputs will be given after the witness. --- arrabbiata/src/columns.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/arrabbiata/src/columns.rs b/arrabbiata/src/columns.rs index 7afa3e3643..e9c078c5db 100644 --- a/arrabbiata/src/columns.rs +++ b/arrabbiata/src/columns.rs @@ -8,6 +8,8 @@ use std::{ }; use strum_macros::{EnumCount as EnumCountMacro, EnumIter}; +use crate::NUMBER_OF_COLUMNS; + /// This enum represents the different gadgets that can be used in the circuit. /// The selectors are defined at setup time, can take only the values `0` or /// `1` and are public. @@ -38,16 +40,21 @@ pub enum Column { /// Convert a column to a usize. This is used by the library [mvpoly] when we /// need to compute the cross-terms. -/// For now, we only support the conversion of the private inputs, i.e. the `X` -/// variant. -/// Also, for now, the [mvpoly] library expects the columns to be mapped to a -/// prime number as the prime representation is used under the hood. This must -/// be changed. +/// For now, only the private inputs and the public inputs are converted, +/// because there might not need to treat the selectors in the polynomial while +/// computing the cross-terms (FIXME: check this later, but pretty sure it's the +/// case). +/// +/// Also, the [mvpoly::monomials] implementation of the trait [mvpoly::MVPoly] +/// will be used, and the mapping here is consistent with the one expected by +/// this implementation, i.e. we simply map to an increasing number starting at +/// 0, without any gap. impl From for usize { fn from(val: Column) -> usize { match val { Column::X(i) => i, - _ => unimplemented!("Only the private inputs are supported for now"), + Column::PublicInput(i) => NUMBER_OF_COLUMNS + i, + Column::Selector(_) => unimplemented!("Selectors are not supported. This method is supposed to be called only to compute the cross-term and an optimisation is in progress to avoid the inclusion of the selectors in the multi-variate polynomial."), } } } From c6851c2bd15d6a441357517f6d78af147e2ada87 Mon Sep 17 00:00:00 2001 From: Skylar Ray <137945430+sky-coderay@users.noreply.github.com> Date: Mon, 16 Dec 2024 20:46:16 +0200 Subject: [PATCH 119/165] Update README.md --- arrabbiata/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arrabbiata/README.md b/arrabbiata/README.md index e92025b244..4f46cf7270 100644 --- a/arrabbiata/README.md +++ b/arrabbiata/README.md @@ -54,7 +54,7 @@ activated gate on each row. Different built-in examples are provided. For instance: ``` -cargo run --bin arrabiata --release -- square-root --n 10 --srs-size 16 +cargo run --bin arrabbiata --release -- square-root --n 10 --srs-size 16 ``` will generate 10 full folding iterations of the polynomial-time function `f(X, Y) = From ef0ecc77fd258d794b3edce2e3c098c4379b4368 Mon Sep 17 00:00:00 2001 From: planetBoy <140164174+Guayaba221@users.noreply.github.com> Date: Mon, 16 Dec 2024 20:08:41 +0100 Subject: [PATCH 120/165] Update README.md --- mvpoly/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mvpoly/README.md b/mvpoly/README.md index 447e56811f..26a94c5596 100644 --- a/mvpoly/README.md +++ b/mvpoly/README.md @@ -1,4 +1,4 @@ -# MVPoly: play with multi-variate poynomials +# MVPoly: play with multi-variate polynomials This library aims to provide algorithms and different representations to manipulate multivariate polynomials. From b2ccce478af5a6a89d5d7336b4b6fec58c00de1f Mon Sep 17 00:00:00 2001 From: Danil <37103154+Danyylka@users.noreply.github.com> Date: Mon, 16 Dec 2024 20:56:33 +0100 Subject: [PATCH 121/165] Update domain.md --- book/src/plonk/domain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/src/plonk/domain.md b/book/src/plonk/domain.md index 4dd79da36a..45ec4a78c0 100644 --- a/book/src/plonk/domain.md +++ b/book/src/plonk/domain.md @@ -31,7 +31,7 @@ The code above also defines a generator $g$ for it, such that $g^{2^{32}} = 1$ a [Lagrange's theorem](https://en.wikipedia.org/wiki/Lagrange%27s_theorem_(group_theory)) tells us that if we have a group of order $n$, then we'll have subgroups with orders dividing $n$. So in our case, we have subgroups with all the powers of 2, up to the 32-th power of 2. -To find any of these groups, it is pretty straight forward as well. Notice that: +To find any of these groups, it is pretty straightforward as well. Notice that: * let $h = g^2$, then $h^{2^{31}} = g^{2^{32}} = 1$ and so $h$ generates a subgroup of order 31 * let $t = g^{2^2}$, then $t^{2^{30}} = g^{2^{32}} = 1$ and so $t$ generates a subgroup of order 30 From c635349882a7cda5861bdde09322f2cd6e540040 Mon Sep 17 00:00:00 2001 From: Danil <37103154+Danyylka@users.noreply.github.com> Date: Mon, 16 Dec 2024 20:59:35 +0100 Subject: [PATCH 122/165] Update urs.md --- book/src/specs/urs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/src/specs/urs.md b/book/src/specs/urs.md index dd63174520..8abb969b4b 100644 --- a/book/src/specs/urs.md +++ b/book/src/specs/urs.md @@ -9,7 +9,7 @@ This needs to be fixed. The URS comprises of: * `Gs`: an arbitrary ordered list of curve points that can be used to commit to a polynomial in a non-hiding way. -* `H`: a blinding curve point that can be used to add hidding to a polynomial commitment scheme. +* `H`: a blinding curve point that can be used to add hiding to a polynomial commitment scheme. The URS is generated deterministically, and thus can be rederived if not stored. From 31f2ab40b3016adcbbf6bbe0a4e8ba6975b1077a Mon Sep 17 00:00:00 2001 From: svv232 Date: Tue, 17 Dec 2024 00:41:48 -0500 Subject: [PATCH 123/165] limit scope of the rd position to a local variable --- o1vm/src/interpreters/riscv32im/interpreter.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index 9874e53f0c..7ed1cfc383 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -1801,8 +1801,10 @@ pub fn interpret_itype(env: &mut Env, instr: IInstruction) // slti: x[rd] = (x[rs1] < sext(immediate)) ? 1 : 0 let local_rs1 = env.read_register(&rs1); let local_imm = env.sign_extend(&imm, 12); - let rd_scratch = env.alloc_scratch(); - let local_rd = unsafe { env.test_less_than_signed(&local_rs1, &local_imm, rd_scratch) }; + let local_rd = { + let pos = env.alloc_scratch(); + unsafe { env.test_less_than_signed(&local_rs1, &local_imm, pos) } + }; env.write_register(&rd, local_rd); env.set_instruction_pointer(next_instruction_pointer.clone()); env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); From fddf9f26be5ac88848a37ac686b3041f44165b9a Mon Sep 17 00:00:00 2001 From: svv232 Date: Tue, 17 Dec 2024 00:43:56 -0500 Subject: [PATCH 124/165] limit scope of the rd position to a local variable in set less than immediate --- o1vm/src/interpreters/riscv32im/interpreter.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index c9a3903586..a9bce93289 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -1811,8 +1811,10 @@ pub fn interpret_itype(env: &mut Env, instr: IInstruction) // sltiu: x[rd] = (x[rs1] < (u)sext(immediate)) ? 1 : 0 let local_rs1 = env.read_register(&rs1); let local_imm = env.sign_extend(&imm, 12); - let rd_scratch = env.alloc_scratch(); - let local_rd = unsafe { env.test_less_than(&local_rs1, &local_imm, rd_scratch) }; + let local_rd = { + let pos = env.alloc_scratch(); + unsafe { env.test_less_than(&local_rs1, &local_imm, pos) } + }; env.write_register(&rd, local_rd); env.set_instruction_pointer(next_instruction_pointer.clone()); env.set_next_instruction_pointer(next_instruction_pointer + Env::constant(4u32)); From 75bc47d418797bd307199744bc53385ad32ec335 Mon Sep 17 00:00:00 2001 From: svv232 Date: Tue, 17 Dec 2024 00:56:11 -0500 Subject: [PATCH 125/165] move position scratch variables into local scope for interpreter variable --- o1vm/src/interpreters/riscv32im/interpreter.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index 3ae830de49..5f36fffbcb 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -2212,10 +2212,11 @@ pub fn interpret_utype(env: &mut Env, instr: UInstruction) env.sign_extend(&shifted_imm, 32) }; let local_pc = instruction_pointer.clone(); - let pos = env.alloc_scratch(); - let overflow_pos = env.alloc_scratch(); - let (local_rd, _) = - unsafe { env.add_witness(&local_pc, &local_imm, pos, overflow_pos) }; + let (local_rd, _) = { + let pos = env.alloc_scratch(); + let overflow_pos = env.alloc_scratch(); + unsafe { env.add_witness(&local_pc, &local_imm, pos, overflow_pos) } + }; env.write_register(&rd, local_rd); env.set_instruction_pointer(next_instruction_pointer.clone()); From b16a94e698bfcd77ab59bcb0269711a77df632af Mon Sep 17 00:00:00 2001 From: martyall Date: Wed, 18 Dec 2024 08:21:52 -0800 Subject: [PATCH 126/165] add more robust cli framework --- Cargo.lock | 15 ++++- o1vm/Cargo.toml | 6 +- o1vm/run-vm.sh | 2 +- o1vm/src/cannon.rs | 71 +++++++++++---------- o1vm/src/cannon_cli.rs | 112 --------------------------------- o1vm/src/cli/cannon.rs | 111 ++++++++++++++++++++++++++++++++ o1vm/src/cli/mod.rs | 14 +++++ o1vm/src/legacy/main.rs | 24 +++++-- o1vm/src/lib.rs | 5 +- o1vm/src/pickles/main.rs | 29 ++++++--- o1vm/src/test_preimage_read.rs | 29 +++------ o1vm/test_preimage_read.sh | 4 +- 12 files changed, 229 insertions(+), 193 deletions(-) delete mode 100644 o1vm/src/cannon_cli.rs create mode 100644 o1vm/src/cli/cannon.rs create mode 100644 o1vm/src/cli/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 917bab5d39..456d4ce2d5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -592,7 +592,7 @@ checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" dependencies = [ "atty", "bitflags 1.3.2", - "clap_derive", + "clap_derive 3.2.25", "clap_lex 0.2.4", "indexmap 1.9.3", "once_cell", @@ -608,6 +608,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" dependencies = [ "clap_builder", + "clap_derive 4.4.7", ] [[package]] @@ -635,6 +636,18 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "clap_derive" +version = "4.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "clap_lex" version = "0.2.4" diff --git a/o1vm/Cargo.toml b/o1vm/Cargo.toml index 1e57ce7c0d..a91b75d54c 100644 --- a/o1vm/Cargo.toml +++ b/o1vm/Cargo.toml @@ -12,10 +12,6 @@ license = "Apache-2.0" [lib] path = "src/lib.rs" -[[bin]] -name = "test_optimism_preimage_read" -path = "src/test_preimage_read.rs" - [[bin]] name = "legacy_o1vm" path = "src/legacy/main.rs" @@ -35,7 +31,7 @@ ark-ec.workspace = true ark-ff.workspace = true ark-poly.workspace = true base64.workspace = true -clap.workspace = true +clap = { workspace = true, features = ["derive"] } command-fds.workspace = true elf.workspace = true env_logger.workspace = true diff --git a/o1vm/run-vm.sh b/o1vm/run-vm.sh index 34e61f4da7..bd970354cc 100755 --- a/o1vm/run-vm.sh +++ b/o1vm/run-vm.sh @@ -30,7 +30,7 @@ fi cargo run --bin ${BINARY_FLAVOR} \ --all-features \ --release \ - -p o1vm -- \ + -p o1vm cannon run -- \ --pprof.cpu \ --info-at "${INFO_AT:-%10000000}" \ --snapshot-state-at "${SNAPSHOT_STATE_AT:-%10000000}" \ diff --git a/o1vm/src/cannon.rs b/o1vm/src/cannon.rs index 1a47a3041f..e9ae23d699 100644 --- a/o1vm/src/cannon.rs +++ b/o1vm/src/cannon.rs @@ -147,33 +147,36 @@ pub enum StepFrequency { Range(u64, Option), } -// Simple parser for Cannon's "frequency format" -// A frequency input is either -// - never/always -// - = (only at step n) -// - % (every steps multiple of n) -// - n..[m] (from n on, until m excluded if specified, until the end otherwise) -pub fn step_frequency_parser(s: &str) -> std::result::Result { - use StepFrequency::*; - - let mod_re = Regex::new(r"^%([0-9]+)").unwrap(); - let eq_re = Regex::new(r"^=([0-9]+)").unwrap(); - let ival_re = Regex::new(r"^([0-9]+)..([0-9]+)?").unwrap(); - - match s { - "never" => Ok(Never), - "always" => Ok(Always), - s => { - if let Some(m) = mod_re.captures(s) { - Ok(Every(m[1].parse::().unwrap())) - } else if let Some(m) = eq_re.captures(s) { - Ok(Exactly(m[1].parse::().unwrap())) - } else if let Some(m) = ival_re.captures(s) { - let lo = m[1].parse::().unwrap(); - let hi_opt = m.get(2).map(|x| x.as_str().parse::().unwrap()); - Ok(Range(lo, hi_opt)) - } else { - Err(format!("Unknown frequency format {}", s)) +impl FromStr for StepFrequency { + type Err = String; + // Simple parser for Cannon's "frequency format" + // A frequency input is either + // - never/always + // - = (only at step n) + // - % (every steps multiple of n) + // - n..[m] (from n on, until m excluded if specified, until the end otherwise) + fn from_str(s: &str) -> std::result::Result { + use StepFrequency::*; + + let mod_re = Regex::new(r"^%([0-9]+)").unwrap(); + let eq_re = Regex::new(r"^=([0-9]+)").unwrap(); + let ival_re = Regex::new(r"^([0-9]+)..([0-9]+)?").unwrap(); + + match s { + "never" => Ok(Never), + "always" => Ok(Always), + s => { + if let Some(m) = mod_re.captures(s) { + Ok(Every(m[1].parse::().unwrap())) + } else if let Some(m) = eq_re.captures(s) { + Ok(Exactly(m[1].parse::().unwrap())) + } else if let Some(m) = ival_re.captures(s) { + let lo = m[1].parse::().unwrap(); + let hi_opt = m.get(2).map(|x| x.as_str().parse::().unwrap()); + Ok(Range(lo, hi_opt)) + } else { + Err(format!("Unknown frequency format {}", s)) + } } } } @@ -296,13 +299,13 @@ mod tests { #[test] fn sp_parser() { use StepFrequency::*; - assert_eq!(step_frequency_parser("never"), Ok(Never)); - assert_eq!(step_frequency_parser("always"), Ok(Always)); - assert_eq!(step_frequency_parser("=123"), Ok(Exactly(123))); - assert_eq!(step_frequency_parser("%123"), Ok(Every(123))); - assert_eq!(step_frequency_parser("1..3"), Ok(Range(1, Some(3)))); - assert_eq!(step_frequency_parser("1.."), Ok(Range(1, None))); - assert!(step_frequency_parser("@123").is_err()); + assert_eq!(StepFrequency::from_str("never"), Ok(Never)); + assert_eq!(StepFrequency::from_str("always"), Ok(Always)); + assert_eq!(StepFrequency::from_str("=123"), Ok(Exactly(123))); + assert_eq!(StepFrequency::from_str("%123"), Ok(Every(123))); + assert_eq!(StepFrequency::from_str("1..3"), Ok(Range(1, Some(3)))); + assert_eq!(StepFrequency::from_str("1.."), Ok(Range(1, None))); + assert!(StepFrequency::from_str("@123").is_err()); } // This sample is a subset taken from a Cannon-generated "meta.json" file diff --git a/o1vm/src/cannon_cli.rs b/o1vm/src/cannon_cli.rs deleted file mode 100644 index d894570a5f..0000000000 --- a/o1vm/src/cannon_cli.rs +++ /dev/null @@ -1,112 +0,0 @@ -use crate::cannon::*; -use clap::{arg, value_parser, Arg, ArgAction}; - -pub fn main_cli() -> clap::Command { - let app_name = "o1vm"; - clap::Command::new(app_name) - .version("0.1") - .about("o1vm - a generic purpose zero-knowledge virtual machine") - .arg(arg!(--input "initial state file").default_value("state.json")) - .arg(arg!(--output "output state file").default_value("out.json")) - .arg(arg!(--meta "metadata file").default_value("meta.json")) - // The CLI arguments below this line are ignored at this point - .arg( - Arg::new("proof-at") - .short('p') - .long("proof-at") - .value_name("FREQ") - .default_value("never") - .value_parser(step_frequency_parser), - ) - .arg( - Arg::new("proof-fmt") - .long("proof-fmt") - .value_name("FORMAT") - .default_value("proof-%d.json"), - ) - .arg( - Arg::new("snapshot-fmt") - .long("snapshot-fmt") - .value_name("FORMAT") - .default_value("state-%d.json"), - ) - .arg( - Arg::new("stop-at") - .long("stop-at") - .value_name("FREQ") - .default_value("never") - .value_parser(step_frequency_parser), - ) - .arg( - Arg::new("info-at") - .long("info-at") - .value_name("FREQ") - .default_value("never") - .value_parser(step_frequency_parser), - ) - .arg( - Arg::new("pprof-cpu") - .long("pprof.cpu") - .action(ArgAction::SetTrue), - ) - .arg( - arg!(host: [HOST] "host program specification [host program arguments]") - .num_args(1..) - .last(true) - .value_parser(value_parser!(String)), - ) - .arg( - Arg::new("snapshot-state-at") - .long("snapshot-state-at") - .value_name("FREQ") - .default_value("never") - .value_parser(step_frequency_parser), - ) -} - -pub fn read_configuration(cli: &clap::ArgMatches) -> VmConfiguration { - let input_state_file = cli.get_one::("input").unwrap(); - let output_state_file = cli.get_one::("output").unwrap(); - let metadata_file = cli.get_one::("meta").unwrap(); - - let proof_at = cli.get_one::("proof-at").unwrap(); - let info_at = cli.get_one::("info-at").unwrap(); - let stop_at = cli.get_one::("stop-at").unwrap(); - let snapshot_state_at = cli.get_one::("snapshot-state-at").unwrap(); - - let proof_fmt = cli.get_one::("proof-fmt").unwrap(); - let snapshot_fmt = cli.get_one::("snapshot-fmt").unwrap(); - let pprof_cpu = cli.get_one::("pprof-cpu").unwrap(); - - let host_spec = cli - .get_many::("host") - .map(|vals| vals.collect::>()) - .unwrap_or_default(); - - let host = if host_spec.is_empty() { - None - } else { - Some(HostProgram { - name: host_spec[0].to_string(), - arguments: host_spec[1..] - .to_vec() - .iter() - .map(|x| x.to_string()) - .collect(), - }) - }; - - VmConfiguration { - input_state_file: input_state_file.to_string(), - output_state_file: output_state_file.to_string(), - metadata_file: metadata_file.to_string(), - proof_at: proof_at.clone(), - stop_at: stop_at.clone(), - snapshot_state_at: snapshot_state_at.clone(), - info_at: info_at.clone(), - proof_fmt: proof_fmt.to_string(), - snapshot_fmt: snapshot_fmt.to_string(), - pprof_cpu: *pprof_cpu, - host, - } -} diff --git a/o1vm/src/cli/cannon.rs b/o1vm/src/cli/cannon.rs new file mode 100644 index 0000000000..58d2384375 --- /dev/null +++ b/o1vm/src/cli/cannon.rs @@ -0,0 +1,111 @@ +use crate::cannon::*; +use clap::{arg, Parser, Subcommand}; + +#[derive(Parser, Debug, Clone)] +pub struct MipsVmConfigurationArgs { + #[arg( + long, + value_name = "FILE", + default_value = "state.json", + help = "initial state file" + )] + input: String, + + #[arg( + long, + value_name = "FILE", + default_value = "out.json", + help = "output state file" + )] + output: String, + + #[arg( + long, + value_name = "FILE", + default_value = "meta.json", + help = "metadata file" + )] + meta: String, + + #[arg( + long = "proof-at", + short = 'p', + long, + value_name = "FREQ", + default_value = "never" + )] + proof_at: StepFrequency, + + #[arg( + long = "proof-fmt", + value_name = "FORMAT", + default_value = "proof-%d.json" + )] + proof_fmt: String, + + #[arg( + long = "snapshot-fmt", + value_name = "FORMAT", + default_value = "state-%d.json" + )] + snapshot_fmt: String, + + #[arg(long = "stop-at", value_name = "FREQ", default_value = "never")] + stop_at: StepFrequency, + + #[arg(long = "info-at", value_name = "FREQ", default_value = "never")] + info_at: StepFrequency, + + #[arg(long = "pprof.cpu", action = clap::ArgAction::SetTrue)] + pprof_cpu: bool, + + #[arg( + long = "snapshot-state-at", + value_name = "FREQ", + default_value = "never" + )] + snapshot_state_at: StepFrequency, + + #[arg(name = "host", value_name = "HOST", help = "host program specification [host program arguments]", num_args = 1.., last = true)] + host: Vec, +} + +impl From for VmConfiguration { + fn from(cfg: MipsVmConfigurationArgs) -> Self { + VmConfiguration { + input_state_file: cfg.input, + output_state_file: cfg.output, + metadata_file: cfg.meta, + proof_at: cfg.proof_at, + stop_at: cfg.stop_at, + snapshot_state_at: cfg.snapshot_state_at, + info_at: cfg.info_at, + proof_fmt: cfg.proof_fmt, + snapshot_fmt: cfg.snapshot_fmt, + pprof_cpu: cfg.pprof_cpu, + host: if cfg.host.is_empty() { + None + } else { + Some(HostProgram { + name: cfg.host[0].to_string(), + arguments: cfg.host[1..].to_vec(), + }) + }, + } + } +} + +#[derive(Parser, Debug, Clone)] +pub struct RunArgs { + #[command(flatten)] + pub vm_cfg: MipsVmConfigurationArgs, + #[arg(long = "preimage-db-dir", value_name = "PREIMAGE_DB_DIR")] + pub preimage_db_dir: Option, +} + +#[derive(Subcommand, Clone, Debug)] +pub enum Cannon { + Run(RunArgs), + #[command(name = "test-optimism-preimage-read")] + TestPreimageRead(RunArgs), +} diff --git a/o1vm/src/cli/mod.rs b/o1vm/src/cli/mod.rs new file mode 100644 index 0000000000..7f915aee74 --- /dev/null +++ b/o1vm/src/cli/mod.rs @@ -0,0 +1,14 @@ +use clap::Parser; + +pub mod cannon; + +#[derive(Parser, Debug, Clone)] +#[command( + name = "o1vm", + version = "0.1", + about = "o1vm - a generic purpose zero-knowledge virtual machine" +)] +pub enum Commands { + #[command(subcommand)] + Cannon(cannon::Cannon), +} diff --git a/o1vm/src/legacy/main.rs b/o1vm/src/legacy/main.rs index 749f5722b6..de34b29e80 100644 --- a/o1vm/src/legacy/main.rs +++ b/o1vm/src/legacy/main.rs @@ -1,11 +1,12 @@ use ark_ff::UniformRand; +use clap::Parser; use folding::decomposable_folding::DecomposableFoldingScheme; use kimchi::o1_utils; use kimchi_msm::{proof::ProofInputs, prover::prove, verifier::verify, witness::Witness}; use log::debug; use o1vm::{ cannon::{self, Meta, Start, State}, - cannon_cli, + cli, interpreters::{ keccak::{ column::{Steps, N_ZKVM_KECCAK_COLS, N_ZKVM_KECCAK_REL_COLS, N_ZKVM_KECCAK_SEL_COLS}, @@ -29,6 +30,7 @@ use o1vm::{ }, lookups::LookupTableIDs, preimage_oracle::PreImageOracle, + test_preimage_read, }; use poly_commitment::SRS as _; use std::{cmp::Ordering, collections::HashMap, fs::File, io::BufReader, process::ExitCode}; @@ -38,10 +40,8 @@ use strum::IntoEnumIterator; /// program. pub const DOMAIN_SIZE: usize = 1 << 15; -pub fn main() -> ExitCode { - let cli = cannon_cli::main_cli(); - - let configuration = cannon_cli::read_configuration(&cli.get_matches()); +pub fn cannon_main(args: cli::cannon::RunArgs) { + let configuration: cannon::VmConfiguration = args.vm_cfg.into(); let file = File::open(&configuration.input_state_file).expect("Error opening input state file "); @@ -327,5 +327,19 @@ pub fn main() -> ExitCode { } // TODO: Logic +} + +pub fn main() -> ExitCode { + let args = cli::Commands::parse(); + match args { + cli::Commands::Cannon(args) => match args { + cli::cannon::Cannon::Run(args) => { + cannon_main(args); + } + cli::cannon::Cannon::TestPreimageRead(args) => { + test_preimage_read::main(args); + } + }, + } ExitCode::SUCCESS } diff --git a/o1vm/src/lib.rs b/o1vm/src/lib.rs index 0ee9c5edd4..335442a57f 100644 --- a/o1vm/src/lib.rs +++ b/o1vm/src/lib.rs @@ -1,8 +1,7 @@ /// Modules mimicking the defined structures used by Cannon CLI. pub mod cannon; -/// A CLI mimicking the Cannon CLI. -pub mod cannon_cli; +pub mod cli; /// A module to load ELF files. pub mod elf_loader; @@ -28,6 +27,8 @@ pub mod ramlookup; pub mod utils; +pub mod test_preimage_read; + use kimchi::circuits::{ berkeley_columns::BerkeleyChallengeTerm, expr::{ConstantExpr, Expr}, diff --git a/o1vm/src/pickles/main.rs b/o1vm/src/pickles/main.rs index 5083d7d58d..1fca1f0d85 100644 --- a/o1vm/src/pickles/main.rs +++ b/o1vm/src/pickles/main.rs @@ -1,15 +1,16 @@ use ark_ff::UniformRand; +use clap::Parser; use kimchi::circuits::domains::EvaluationDomains; use kimchi_msm::expr::E; use log::debug; -use mina_curves::pasta::VestaParameters; +use mina_curves::pasta::{Fp, Vesta, VestaParameters}; use mina_poseidon::{ constants::PlonkSpongeConstantsKimchi, sponge::{DefaultFqSponge, DefaultFrSponge}, }; use o1vm::{ cannon::{self, Meta, Start, State}, - cannon_cli, + cli, interpreters::mips::{ column::N_MIPS_REL_COLS, constraints as mips_constraints, @@ -19,21 +20,18 @@ use o1vm::{ }, pickles::{proof::ProofInputs, prover, verifier}, preimage_oracle::PreImageOracle, + test_preimage_read, }; use poly_commitment::{ipa::SRS, SRS as _}; use std::{fs::File, io::BufReader, process::ExitCode, time::Instant}; use strum::IntoEnumIterator; -use mina_curves::pasta::{Fp, Vesta}; - pub const DOMAIN_SIZE: usize = 1 << 15; -pub fn main() -> ExitCode { - let cli = cannon_cli::main_cli(); - +pub fn cannon_main(args: cli::cannon::RunArgs) { let mut rng = rand::thread_rng(); - let configuration = cannon_cli::read_configuration(&cli.get_matches()); + let configuration: cannon::VmConfiguration = args.vm_cfg.into(); let file = File::open(&configuration.input_state_file).expect("Error opening input state file "); @@ -158,6 +156,19 @@ pub fn main() -> ExitCode { curr_proof_inputs = ProofInputs::new(DOMAIN_SIZE); } } - // TODO: Logic +} + +pub fn main() -> ExitCode { + let args = cli::Commands::parse(); + match args { + cli::Commands::Cannon(args) => match args { + cli::cannon::Cannon::Run(args) => { + cannon_main(args); + } + cli::cannon::Cannon::TestPreimageRead(args) => { + test_preimage_read::main(args); + } + }, + } ExitCode::SUCCESS } diff --git a/o1vm/src/test_preimage_read.rs b/o1vm/src/test_preimage_read.rs index 094702a8fc..ce68f0cd43 100644 --- a/o1vm/src/test_preimage_read.rs +++ b/o1vm/src/test_preimage_read.rs @@ -1,10 +1,9 @@ -use clap::Arg; -use log::{debug, error}; -use o1vm::{ - cannon::PreimageKey, - cannon_cli::{main_cli, read_configuration}, +use crate::{ + cannon::{PreimageKey, VmConfiguration}, + cli, preimage_oracle::{PreImageOracle, PreImageOracleT}, }; +use log::{debug, error}; use std::{ io::{self}, path::{Path, PathBuf}, @@ -12,25 +11,11 @@ use std::{ str::FromStr, }; -fn main() -> ExitCode { +pub fn main(args: cli::cannon::RunArgs) -> ExitCode { use rand::Rng; - env_logger::init(); - - // Add command-line parameter to read the Optimism op-program DB directory - let cli = main_cli().arg( - Arg::new("preimage-db-dir") - .long("preimage-db-dir") - .value_name("PREIMAGE_DB_DIR"), - ); - - // Now read matches with the additional argument(s) - let matches = cli.get_matches(); - - let configuration = read_configuration(&matches); - - // Get DB directory and abort if unset - let preimage_db_dir = matches.get_one::("preimage-db-dir"); + let configuration: VmConfiguration = args.vm_cfg.into(); + let preimage_db_dir = args.preimage_db_dir; if let Some(preimage_key_dir) = preimage_db_dir { let mut po = PreImageOracle::create(&configuration.host); diff --git a/o1vm/test_preimage_read.sh b/o1vm/test_preimage_read.sh index de5b68fc7e..f16303cb4c 100755 --- a/o1vm/test_preimage_read.sh +++ b/o1vm/test_preimage_read.sh @@ -2,7 +2,7 @@ # Test preimage read from VM request to server response # Usage: test_preimage_read.sh [OP_DB_DIR] [NETWORK_NAME] -source rpcs.sh +source ./rpcs.sh set +u if [ -z "${FILENAME}" ]; then @@ -36,7 +36,7 @@ NETWORK=${2:-sepolia} ################################################# # Run test with debug on -RUST_LOG=debug cargo run -r --bin test_optimism_preimage_read -- \ +RUST_LOG=debug cargo run -r --bin pickles_o1vm -- cannon test-optimism-preimage-read -- \ --preimage-db-dir ${DATADIR} -- \ op-program \ --log.level DEBUG \ From 8001eeae55d54959852488d232082abb9be7ef71 Mon Sep 17 00:00:00 2001 From: martyall Date: Wed, 18 Dec 2024 08:29:08 -0800 Subject: [PATCH 127/165] initialize logger in right place --- o1vm/src/legacy/main.rs | 3 +-- o1vm/src/pickles/main.rs | 3 +-- o1vm/test_preimage_read.sh | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/o1vm/src/legacy/main.rs b/o1vm/src/legacy/main.rs index de34b29e80..ade183ede2 100644 --- a/o1vm/src/legacy/main.rs +++ b/o1vm/src/legacy/main.rs @@ -70,8 +70,6 @@ pub fn cannon_main(args: cli::cannon::RunArgs) { // Initialize some data used for statistical computations let start = Start::create(state.step as usize); - env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init(); - let domain = kimchi::circuits::domains::EvaluationDomains::::create(DOMAIN_SIZE).unwrap(); let mut rng = o1_utils::tests::make_test_rng(None); @@ -330,6 +328,7 @@ pub fn cannon_main(args: cli::cannon::RunArgs) { } pub fn main() -> ExitCode { + env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init(); let args = cli::Commands::parse(); match args { cli::Commands::Cannon(args) => match args { diff --git a/o1vm/src/pickles/main.rs b/o1vm/src/pickles/main.rs index 1fca1f0d85..03ce2c7fa8 100644 --- a/o1vm/src/pickles/main.rs +++ b/o1vm/src/pickles/main.rs @@ -60,8 +60,6 @@ pub fn cannon_main(args: cli::cannon::RunArgs) { // Initialize some data used for statistical computations let start = Start::create(state.step as usize); - env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init(); - let domain_fp = EvaluationDomains::::create(DOMAIN_SIZE).unwrap(); let srs: SRS = { let srs = SRS::create(DOMAIN_SIZE); @@ -159,6 +157,7 @@ pub fn cannon_main(args: cli::cannon::RunArgs) { } pub fn main() -> ExitCode { + env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init(); let args = cli::Commands::parse(); match args { cli::Commands::Cannon(args) => match args { diff --git a/o1vm/test_preimage_read.sh b/o1vm/test_preimage_read.sh index f16303cb4c..e9826e71d7 100755 --- a/o1vm/test_preimage_read.sh +++ b/o1vm/test_preimage_read.sh @@ -2,7 +2,7 @@ # Test preimage read from VM request to server response # Usage: test_preimage_read.sh [OP_DB_DIR] [NETWORK_NAME] -source ./rpcs.sh +source rpcs.sh set +u if [ -z "${FILENAME}" ]; then From 14a906fd3b7f55796147906fe71af04ca7d1556d Mon Sep 17 00:00:00 2001 From: martyall Date: Wed, 18 Dec 2024 08:55:30 -0800 Subject: [PATCH 128/165] it's important that host is last --- o1vm/src/cli/cannon.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/o1vm/src/cli/cannon.rs b/o1vm/src/cli/cannon.rs index 58d2384375..879036e083 100644 --- a/o1vm/src/cli/cannon.rs +++ b/o1vm/src/cli/cannon.rs @@ -97,10 +97,11 @@ impl From for VmConfiguration { #[derive(Parser, Debug, Clone)] pub struct RunArgs { - #[command(flatten)] - pub vm_cfg: MipsVmConfigurationArgs, #[arg(long = "preimage-db-dir", value_name = "PREIMAGE_DB_DIR")] pub preimage_db_dir: Option, + // it's important that vm_cfg is last in order to properly parse the host field + #[command(flatten)] + pub vm_cfg: MipsVmConfigurationArgs, } #[derive(Subcommand, Clone, Debug)] From 2d2265cad121efff053f160aed226bb17701ba31 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Mon, 16 Dec 2024 19:51:50 +0100 Subject: [PATCH 129/165] mvpoly: compute cross terms of a scaled polynomial --- mvpoly/src/lib.rs | 39 +++++++++++++++++ mvpoly/src/monomials.rs | 46 +++++++++++++++++--- mvpoly/src/prime.rs | 12 +++++ mvpoly/tests/monomials.rs | 92 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 183 insertions(+), 6 deletions(-) diff --git a/mvpoly/src/lib.rs b/mvpoly/src/lib.rs index 6e8d35b7bf..87d0532862 100644 --- a/mvpoly/src/lib.rs +++ b/mvpoly/src/lib.rs @@ -254,6 +254,45 @@ pub trait MVPoly: u2: F, ) -> HashMap; + /// Compute the cross-terms of the given polynomial, scaled by the given + /// scalar. + /// + /// More explicitly, given a polynomial `P(X1, ..., Xn)` and a scalar α, the + /// method computes the the cross-terms of the polynomial `Q(X1, ..., Xn, α) + /// = α * P(X1, ..., Xn)`. For this reason, the method takes as input the + /// two different scalars `scalar1` and `scalar2` as we are considering the + /// scaling factor as a variable. + /// + /// This method is particularly useful when you need to compute a + /// (possibly random) combinaison of polynomials `P1(X1, ..., Xn), ..., + /// Pm(X1, ..., Xn)`, like when computing a quotient polynomial in the PlonK + /// PIOP, as the result is the sum of individual "scaled" polynomials: + /// ```text + /// Q(X_1, ..., X_n, α_1, ..., α_m) = + /// α_1 P1(X_1, ..., X_n) + + /// ... + /// α_m Pm(X_1, ..., X_n) + + /// ``` + /// + /// The polynomial must not necessarily be homogeneous. For this reason, the + /// values `u1` and `u2` represents the extra variable that is used to make + /// the polynomial homogeneous. + /// + /// The homogeneous degree is supposed to be the one defined by the type of + /// the polynomial `P`, i.e. `D`. + /// + /// The output is a map of `D` values that represents the cross-terms + /// for each power of `r`. + fn compute_cross_terms_scaled( + &self, + eval1: &[F; N], + eval2: &[F; N], + u1: F, + u2: F, + scalar1: F, + scalar2: F, + ) -> HashMap; + /// Modify the monomial in the polynomial to the new value `coeff`. fn modify_monomial(&mut self, exponents: [usize; N], coeff: F); diff --git a/mvpoly/src/monomials.rs b/mvpoly/src/monomials.rs index 275d322a5a..67d3127403 100644 --- a/mvpoly/src/monomials.rs +++ b/mvpoly/src/monomials.rs @@ -1,3 +1,8 @@ +use crate::{ + prime, + utils::{compute_indices_nested_loop, naive_prime_factors, PrimeNumberGenerator}, + MVPoly, +}; use ark_ff::{One, PrimeField, Zero}; use kimchi::circuits::{expr::Variable, gate::CurrOrNext}; use num_integer::binomial; @@ -8,12 +13,6 @@ use std::{ ops::{Add, Mul, Neg, Sub}, }; -use crate::{ - prime, - utils::{compute_indices_nested_loop, naive_prime_factors, PrimeNumberGenerator}, - MVPoly, -}; - /// Represents a multivariate polynomial in `N` variables with coefficients in /// `F`. The polynomial is represented as a sparse polynomial, where each /// monomial is represented by a vector of `N` exponents. @@ -472,6 +471,41 @@ impl MVPoly for Sparse HashMap { + assert!( + D >= 2, + "The degree of the polynomial must be greater than 2" + ); + let cross_terms = self.compute_cross_terms(eval1, eval2, u1, u2); + + let mut res: HashMap = HashMap::new(); + cross_terms.iter().for_each(|(power_r, coeff)| { + res.insert(*power_r, *coeff * scalar1); + }); + cross_terms.iter().for_each(|(power_r, coeff)| { + res.entry(*power_r + 1) + .and_modify(|e| *e += *coeff * scalar2) + .or_insert(*coeff * scalar2); + }); + let eval1_hom = self.homogeneous_eval(eval1, u1); + res.entry(1) + .and_modify(|e| *e += eval1_hom * scalar2) + .or_insert(eval1_hom * scalar2); + let eval2_hom = self.homogeneous_eval(eval2, u2); + res.entry(D) + .and_modify(|e| *e += eval2_hom * scalar1) + .or_insert(eval2_hom * scalar1); + res + } + fn modify_monomial(&mut self, exponents: [usize; N], coeff: F) { self.monomials .entry(exponents) diff --git a/mvpoly/src/prime.rs b/mvpoly/src/prime.rs index 498cc1c7ee..41398663f8 100644 --- a/mvpoly/src/prime.rs +++ b/mvpoly/src/prime.rs @@ -432,6 +432,18 @@ impl MVPoly for Dense HashMap { + unimplemented!() + } + fn modify_monomial(&mut self, exponents: [usize; N], coeff: F) { let mut prime_gen = PrimeNumberGenerator::new(); let primes = prime_gen.get_first_nth_primes(N); diff --git a/mvpoly/tests/monomials.rs b/mvpoly/tests/monomials.rs index 514ab7cc7b..b169f8bc01 100644 --- a/mvpoly/tests/monomials.rs +++ b/mvpoly/tests/monomials.rs @@ -712,3 +712,95 @@ fn test_from_expr_ec_addition() { assert_eq!(eval, exp_eval); } } + +#[test] +fn test_cross_terms_fixed_polynomial_and_eval_homogeneous_degree_3() { + // X + let x = { + // We say it is of degree 2 for the cross-term computation + let mut x = Sparse::::zero(); + x.add_monomial([1], Fp::one()); + x + }; + // X * Y + let scaled_x = { + let scaling_var = { + let mut v = Sparse::::zero(); + v.add_monomial([0, 1], Fp::one()); + v + }; + let x: Sparse = { + let x: Result, String> = x.clone().into(); + x.unwrap() + }; + x.clone() * scaling_var + }; + // x1 = 42, α1 = 1 + // x2 = 42, α2 = 2 + let eval1: [Fp; 2] = [Fp::from(42), Fp::one()]; + let eval2: [Fp; 2] = [Fp::from(42), Fp::one() + Fp::one()]; + let u1 = Fp::one(); + let u2 = Fp::one() + Fp::one(); + let scalar1 = eval1[1]; + let scalar2 = eval2[1]; + + let cross_terms_scaled_p1 = { + // When computing the cross-terms, the method supposes that the polynomial + // is of degree D - 1. + // We do suppose we homogenize to degree 3. + let scaled_x: Sparse = { + let p: Result, String> = scaled_x.clone().into(); + p.unwrap() + }; + scaled_x.compute_cross_terms(&eval1, &eval2, u1, u2) + }; + let cross_terms = { + let x: Sparse = { + let x: Result, String> = x.clone().into(); + x.unwrap() + }; + x.compute_cross_terms_scaled( + &eval1[0..1].try_into().unwrap(), + &eval2[0..1].try_into().unwrap(), + u1, + u2, + scalar1, + scalar2, + ) + }; + assert_eq!(cross_terms, cross_terms_scaled_p1); +} + +#[test] +fn test_cross_terms_scaled() { + let mut rng = o1_utils::tests::make_test_rng(None); + let p1 = unsafe { Sparse::::random(&mut rng, None) }; + let scaled_p1 = { + // Scaling variable is U. We do this by adding a new variable. + let scaling_variable: Sparse = { + let mut p: Sparse = Sparse::::zero(); + p.add_monomial([0, 0, 0, 0, 1], Fp::one()); + p + }; + // Simply transforming p1 in the expected degree and with the right + // number of variables + let p1 = { + let p1: Result, String> = p1.clone().into(); + p1.unwrap() + }; + scaling_variable.clone() * p1.clone() + }; + let random_eval1: [Fp; 5] = std::array::from_fn(|_| Fp::rand(&mut rng)); + let random_eval2: [Fp; 5] = std::array::from_fn(|_| Fp::rand(&mut rng)); + let scalar1 = random_eval1[4]; + let scalar2 = random_eval2[4]; + let u1 = Fp::rand(&mut rng); + let u2 = Fp::rand(&mut rng); + let cross_terms = { + let eval1: [Fp; 4] = random_eval1[0..4].try_into().unwrap(); + let eval2: [Fp; 4] = random_eval2[0..4].try_into().unwrap(); + p1.compute_cross_terms_scaled(&eval1, &eval2, u1, u2, scalar1, scalar2) + }; + let scaled_cross_terms = scaled_p1.compute_cross_terms(&random_eval1, &random_eval2, u1, u2); + assert_eq!(cross_terms, scaled_cross_terms); +} From 00a6119c8071450016ca3e8cd0afe2823d6853cc Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Tue, 17 Dec 2024 16:44:35 +0100 Subject: [PATCH 130/165] mvpoly/monomials: allow to artificially increase the degree --- mvpoly/src/monomials.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/mvpoly/src/monomials.rs b/mvpoly/src/monomials.rs index 67d3127403..e08be206fa 100644 --- a/mvpoly/src/monomials.rs +++ b/mvpoly/src/monomials.rs @@ -554,12 +554,19 @@ impl From for Sparse } } -impl From> - for Result, String> +impl + From> for Result, String> { - fn from(poly: Sparse) -> Result, String> { + fn from(poly: Sparse) -> Result, String> { if M < N { - return Err("The number of variables must be greater than N".to_string()); + return Err(format!( + "The final number of variables {M} must be greater than {N}" + )); + } + if D_PRIME < D { + return Err(format!( + "The final degree {D_PRIME} must be greater than initial degree {D}" + )); } let mut monomials = HashMap::new(); poly.monomials.iter().for_each(|(exponents, coeff)| { From cbf5b1f8d43ac8cac610e33075ea9fb70fe8e9cf Mon Sep 17 00:00:00 2001 From: martyall Date: Wed, 18 Dec 2024 14:49:08 -0800 Subject: [PATCH 131/165] remove extra -- --- o1vm/run-vm.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/o1vm/run-vm.sh b/o1vm/run-vm.sh index bd970354cc..b617ab68d3 100755 --- a/o1vm/run-vm.sh +++ b/o1vm/run-vm.sh @@ -30,7 +30,7 @@ fi cargo run --bin ${BINARY_FLAVOR} \ --all-features \ --release \ - -p o1vm cannon run -- \ + -p o1vm cannon run \ --pprof.cpu \ --info-at "${INFO_AT:-%10000000}" \ --snapshot-state-at "${SNAPSHOT_STATE_AT:-%10000000}" \ From fa30cc25ebd0bd3e86bc681d4bf031db2fd5a289 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Thu, 17 Oct 2024 15:04:39 +0200 Subject: [PATCH 132/165] Arrabbiata: intro the notion of ArrabbiataCurve Replicating the idea of KimchiCurve. --- arrabbiata/src/curve.rs | 73 +++++++++++++++++++++++++++++++++++++++ arrabbiata/src/lib.rs | 1 + arrabbiata/src/prover.rs | 7 ++-- arrabbiata/src/witness.rs | 17 ++++----- kimchi/src/curve.rs | 4 +-- 5 files changed, 88 insertions(+), 14 deletions(-) create mode 100644 arrabbiata/src/curve.rs diff --git a/arrabbiata/src/curve.rs b/arrabbiata/src/curve.rs new file mode 100644 index 0000000000..3a58ee22da --- /dev/null +++ b/arrabbiata/src/curve.rs @@ -0,0 +1,73 @@ +//! This file defines a trait similar to [kimchi::curve::KimchiCurve] for Pallas and +//! Vesta. It aims to define all the parameters that are needed by a curve to be +//! used in Arrabbiata. For instance, the sponge parameters, the endomorphism +//! coefficients, etc. +//! The goal of this trait is to parametrize the whole library with the +//! different curves. + +use ark_ec::short_weierstrass::Affine; +use kimchi::curve::{pallas_endos, vesta_endos}; +use mina_curves::pasta::curves::{pallas::PallasParameters, vesta::VestaParameters}; +use mina_poseidon::poseidon::ArithmeticSpongeParams; +use poly_commitment::commitment::{CommitmentCurve, EndoCurve}; + +/// Represents additional information that a curve needs in order to be used +/// with Arrabbiata. +pub trait ArrabbiataCurve: CommitmentCurve + EndoCurve { + /// A human readable name. + const NAME: &'static str; + + /// Provides the sponge params to be used with this curve. + fn sponge_params() -> &'static ArithmeticSpongeParams; + + /// Provides the sponge params to be used with the other curve. + fn other_curve_sponge_params() -> &'static ArithmeticSpongeParams; + + /// Provides the coefficients for the curve endomorphism, called (q,r) in + /// some places. + fn endos() -> &'static (Self::BaseField, Self::ScalarField); + + /// Provides the coefficient for the curve endomorphism over the other + /// field, called q in some places. + fn other_curve_endo() -> &'static Self::ScalarField; +} + +impl ArrabbiataCurve for Affine { + const NAME: &'static str = "pallas"; + + fn sponge_params() -> &'static ArithmeticSpongeParams { + crate::poseidon_3_60_0_5_5_fq::static_params() + } + + fn other_curve_sponge_params() -> &'static ArithmeticSpongeParams { + crate::poseidon_3_60_0_5_5_fp::static_params() + } + + fn endos() -> &'static (Self::BaseField, Self::ScalarField) { + pallas_endos() + } + + fn other_curve_endo() -> &'static Self::ScalarField { + &vesta_endos().0 + } +} + +impl ArrabbiataCurve for Affine { + const NAME: &'static str = "vesta"; + + fn sponge_params() -> &'static ArithmeticSpongeParams { + crate::poseidon_3_60_0_5_5_fp::static_params() + } + + fn other_curve_sponge_params() -> &'static ArithmeticSpongeParams { + crate::poseidon_3_60_0_5_5_fq::static_params() + } + + fn endos() -> &'static (Self::BaseField, Self::ScalarField) { + vesta_endos() + } + + fn other_curve_endo() -> &'static Self::ScalarField { + &pallas_endos().0 + } +} diff --git a/arrabbiata/src/lib.rs b/arrabbiata/src/lib.rs index e43a1b2fa0..654d0691fa 100644 --- a/arrabbiata/src/lib.rs +++ b/arrabbiata/src/lib.rs @@ -3,6 +3,7 @@ use strum::EnumCount as _; pub mod column_env; pub mod columns; pub mod constraints; +pub mod curve; pub mod interpreter; pub mod logup; pub mod poseidon_3_60_0_5_5_fp; diff --git a/arrabbiata/src/prover.rs b/arrabbiata/src/prover.rs index 7e9ea7b36b..9fbac08c9b 100644 --- a/arrabbiata/src/prover.rs +++ b/arrabbiata/src/prover.rs @@ -1,7 +1,6 @@ //! A prover for the folding/accumulation scheme -use crate::proof::Proof; -use ark_ec::AffineRepr; +use crate::{curve::ArrabbiataCurve, proof::Proof}; use ark_ff::PrimeField; use crate::witness::Env; @@ -12,8 +11,8 @@ use crate::witness::Env; pub fn prove< Fp: PrimeField, Fq: PrimeField, - E1: AffineRepr, - E2: AffineRepr, + E1: ArrabbiataCurve, + E2: ArrabbiataCurve, >( _env: &Env, ) -> Result { diff --git a/arrabbiata/src/witness.rs b/arrabbiata/src/witness.rs index 179e9d520a..e5bc957f18 100644 --- a/arrabbiata/src/witness.rs +++ b/arrabbiata/src/witness.rs @@ -1,4 +1,4 @@ -use ark_ec::{models::short_weierstrass::SWCurveConfig, AffineRepr}; +use ark_ec::models::short_weierstrass::SWCurveConfig; use ark_ff::PrimeField; use ark_poly::Evaluations; use kimchi::circuits::{domains::EvaluationDomains, gate::CurrOrNext}; @@ -6,12 +6,13 @@ use log::{debug, info}; use num_bigint::{BigInt, BigUint}; use num_integer::Integer; use o1_utils::field_helpers::FieldHelpers; -use poly_commitment::{commitment::CommitmentCurve, ipa::SRS, PolyComm, SRS as _}; +use poly_commitment::{ipa::SRS, PolyComm, SRS as _}; use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; use std::time::Instant; use crate::{ columns::{Column, Gadget}, + curve::ArrabbiataCurve, interpreter::{Instruction, InterpreterEnv, Side}, poseidon_3_60_0_5_5_fp, poseidon_3_60_0_5_5_fq, MAXIMUM_FIELD_SIZE_IN_BITS, NUMBER_OF_COLUMNS, NUMBER_OF_PUBLIC_INPUTS, NUMBER_OF_SELECTORS, NUMBER_OF_VALUES_TO_ABSORB_PUBLIC_IO, @@ -31,8 +32,8 @@ pub const IVC_STARTING_INSTRUCTION: Instruction = Instruction::Poseidon(0); pub struct Env< Fp: PrimeField, Fq: PrimeField, - E1: AffineRepr, - E2: AffineRepr, + E1: ArrabbiataCurve, + E2: ArrabbiataCurve, > { // ---------------- // Setup related (domains + SRS) @@ -184,8 +185,8 @@ pub struct Env< impl< Fp: PrimeField, Fq: PrimeField, - E1: CommitmentCurve, - E2: CommitmentCurve, + E1: ArrabbiataCurve, + E2: ArrabbiataCurve, > InterpreterEnv for Env where ::BaseField: PrimeField, @@ -755,8 +756,8 @@ where impl< Fp: PrimeField, Fq: PrimeField, - E1: CommitmentCurve, - E2: CommitmentCurve, + E1: ArrabbiataCurve, + E2: ArrabbiataCurve, > Env { pub fn new( diff --git a/kimchi/src/curve.rs b/kimchi/src/curve.rs index b82ce74ebb..ea863c3593 100644 --- a/kimchi/src/curve.rs +++ b/kimchi/src/curve.rs @@ -38,7 +38,7 @@ pub trait KimchiCurve: CommitmentCurve + EndoCurve { fn other_curve_generator() -> (Self::ScalarField, Self::ScalarField); } -fn vesta_endos() -> &'static ( +pub fn vesta_endos() -> &'static ( ::BaseField, ::ScalarField, ) { @@ -49,7 +49,7 @@ fn vesta_endos() -> &'static ( &VESTA_ENDOS } -fn pallas_endos() -> &'static ( +pub fn pallas_endos() -> &'static ( ::BaseField, ::ScalarField, ) { From 0d0e137b87cf69e868a369b9e76101e07abd6be6 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Thu, 17 Oct 2024 15:19:19 +0200 Subject: [PATCH 133/165] Arrabbiata: instantiate constraints env with ArrabbiataCurve --- arrabbiata/src/constraints.rs | 29 ++++++++++++++++------------- arrabbiata/tests/constraints.rs | 21 ++++++++++----------- 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/arrabbiata/src/constraints.rs b/arrabbiata/src/constraints.rs index d3a22655de..c0e8c6077a 100644 --- a/arrabbiata/src/constraints.rs +++ b/arrabbiata/src/constraints.rs @@ -1,10 +1,10 @@ use super::{columns::Column, interpreter::InterpreterEnv}; use crate::{ columns::{Gadget, E}, + curve::ArrabbiataCurve, interpreter::{self, Instruction, Side}, MAX_DEGREE, NUMBER_OF_COLUMNS, NUMBER_OF_PUBLIC_INPUTS, }; -use ark_ff::{Field, PrimeField}; use kimchi::circuits::{ expr::{ConstantTerm::Literal, Expr, ExprInner, Operations, Variable}, gate::CurrOrNext, @@ -14,8 +14,8 @@ use num_bigint::BigInt; use o1_utils::FieldHelpers; #[derive(Clone, Debug)] -pub struct Env { - pub poseidon_mds: Vec>, +pub struct Env { + pub poseidon_mds: Vec>, /// The parameter a is the coefficients of the elliptic curve in affine /// coordinates. // FIXME: this is ugly. Let use the curve as a parameter. Only lazy for now. @@ -23,14 +23,17 @@ pub struct Env { pub idx_var: usize, pub idx_var_next_row: usize, pub idx_var_pi: usize, - pub constraints: Vec>, + pub constraints: Vec>, pub activated_gadget: Option, } -impl Env { - pub fn new(poseidon_mds: Vec>, a: BigInt) -> Self { +impl Env { + pub fn new(poseidon_mds: Vec>, a: BigInt) -> Self { // This check might not be useful - assert!(a < Fp::modulus_biguint().into(), "a is too large"); + assert!( + a < C::ScalarField::modulus_biguint().into(), + "a is too large" + ); Self { poseidon_mds, a, @@ -48,10 +51,10 @@ impl Env { /// proof. /// The constraint environment must be instantiated only once, at the last step /// of the computation. -impl InterpreterEnv for Env { +impl InterpreterEnv for Env { type Position = (Column, CurrOrNext); - type Variable = E; + type Variable = E; fn allocate(&mut self) -> Self::Position { assert!(self.idx_var < NUMBER_OF_COLUMNS, "Maximum number of columns reached ({NUMBER_OF_COLUMNS}), increase the number of columns"); @@ -81,7 +84,7 @@ impl InterpreterEnv for Env { fn constant(&self, value: BigInt) -> Self::Variable { let v = value.to_biguint().unwrap(); - let v = Fp::from_biguint(&v).unwrap(); + let v = C::ScalarField::from_biguint(&v).unwrap(); let v_inner = Operations::from(Literal(v)); Self::Variable::constant(v_inner) } @@ -304,7 +307,7 @@ impl InterpreterEnv for Env { } } -impl Env { +impl Env { /// Get all the constraints for the IVC circuit, only. /// /// The following gadgets are used in the IVC circuit: @@ -317,7 +320,7 @@ impl Env { // the computation of the challenges. // FIXME: add a test checking that whatever the value given in parameter of // the gadget, the constraints are the same - pub fn get_all_constraints_for_ivc(&self) -> Vec> { + pub fn get_all_constraints_for_ivc(&self) -> Vec> { // Copying the instance we got in parameter, and making it mutable to // avoid modifying the original instance. let mut env = self.clone(); @@ -354,7 +357,7 @@ impl Env { // FIXME: the application should be given as an argument to handle Rust // zkApp. It is only for the PoC. // FIXME: the selectors are not added for now. - pub fn get_all_constraints(&self) -> Vec> { + pub fn get_all_constraints(&self) -> Vec> { let mut constraints = self.get_all_constraints_for_ivc(); // Copying the instance we got in parameter, and making it mutable to diff --git a/arrabbiata/tests/constraints.rs b/arrabbiata/tests/constraints.rs index 5ed9196b55..8febfc7495 100644 --- a/arrabbiata/tests/constraints.rs +++ b/arrabbiata/tests/constraints.rs @@ -1,18 +1,17 @@ -use num_bigint::BigInt; -use std::collections::HashMap; - use arrabbiata::{ columns::Gadget, constraints, interpreter::{self, Instruction}, poseidon_3_60_0_5_5_fp, poseidon_3_60_0_5_5_fq, }; -use mina_curves::pasta::fields::{Fp, Fq}; +use mina_curves::pasta::{curves::vesta::Vesta, Pallas}; +use num_bigint::BigInt; +use std::collections::HashMap; fn helper_compute_constraints_gadget(instr: Instruction, exp_constraints: usize) { let mut constraints_fp = { let poseidon_mds = poseidon_3_60_0_5_5_fp::static_params().mds.clone(); - constraints::Env::::new(poseidon_mds.to_vec(), BigInt::from(0_usize)) + constraints::Env::::new(poseidon_mds.to_vec(), BigInt::from(0_usize)) }; interpreter::run_ivc(&mut constraints_fp, instr); @@ -20,7 +19,7 @@ fn helper_compute_constraints_gadget(instr: Instruction, exp_constraints: usize) let mut constraints_fq = { let poseidon_mds = poseidon_3_60_0_5_5_fq::static_params().mds.clone(); - constraints::Env::::new(poseidon_mds.to_vec(), BigInt::from(0_usize)) + constraints::Env::::new(poseidon_mds.to_vec(), BigInt::from(0_usize)) }; interpreter::run_ivc(&mut constraints_fq, instr); assert_eq!(constraints_fq.constraints.len(), exp_constraints); @@ -29,7 +28,7 @@ fn helper_compute_constraints_gadget(instr: Instruction, exp_constraints: usize) fn helper_check_expected_degree_constraints(instr: Instruction, exp_degrees: HashMap) { let mut constraints_fp = { let poseidon_mds = poseidon_3_60_0_5_5_fp::static_params().mds.clone(); - constraints::Env::::new(poseidon_mds.to_vec(), BigInt::from(0_usize)) + constraints::Env::::new(poseidon_mds.to_vec(), BigInt::from(0_usize)) }; interpreter::run_ivc(&mut constraints_fp, instr); @@ -61,7 +60,7 @@ fn helper_gadget_number_of_columns_used( ) { let mut constraints_fp = { let poseidon_mds = poseidon_3_60_0_5_5_fp::static_params().mds.clone(); - constraints::Env::::new(poseidon_mds.to_vec(), BigInt::from(0_usize)) + constraints::Env::::new(poseidon_mds.to_vec(), BigInt::from(0_usize)) }; interpreter::run_ivc(&mut constraints_fp, instr); @@ -75,7 +74,7 @@ fn helper_gadget_number_of_columns_used( fn helper_check_gadget_activated(instr: Instruction, gadget: Gadget) { let mut constraints_fp = { let poseidon_mds = poseidon_3_60_0_5_5_fp::static_params().mds.clone(); - constraints::Env::::new(poseidon_mds.to_vec(), BigInt::from(0_usize)) + constraints::Env::::new(poseidon_mds.to_vec(), BigInt::from(0_usize)) }; interpreter::run_ivc(&mut constraints_fp, instr); @@ -119,7 +118,7 @@ fn test_gadget_elliptic_curve_addition() { fn test_ivc_total_number_of_constraints_ivc() { let constraints_fp = { let poseidon_mds = poseidon_3_60_0_5_5_fp::static_params().mds.clone(); - constraints::Env::::new(poseidon_mds.to_vec(), BigInt::from(0_usize)) + constraints::Env::::new(poseidon_mds.to_vec(), BigInt::from(0_usize)) }; let constraints = constraints_fp.get_all_constraints_for_ivc(); @@ -130,7 +129,7 @@ fn test_ivc_total_number_of_constraints_ivc() { fn test_degree_of_constraints_ivc() { let constraints_fp = { let poseidon_mds = poseidon_3_60_0_5_5_fp::static_params().mds.clone(); - constraints::Env::::new(poseidon_mds.to_vec(), BigInt::from(0_usize)) + constraints::Env::::new(poseidon_mds.to_vec(), BigInt::from(0_usize)) }; let constraints = constraints_fp.get_all_constraints_for_ivc(); From 555a772858e520b9f6710b58d808a891612f0a63 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Thu, 17 Oct 2024 15:32:06 +0200 Subject: [PATCH 134/165] Arrabiata/Constraints: use poseidon params from curve trait --- arrabbiata/src/constraints.rs | 6 ++---- arrabbiata/tests/constraints.rs | 36 +++++++-------------------------- 2 files changed, 9 insertions(+), 33 deletions(-) diff --git a/arrabbiata/src/constraints.rs b/arrabbiata/src/constraints.rs index c0e8c6077a..22b7b08f1e 100644 --- a/arrabbiata/src/constraints.rs +++ b/arrabbiata/src/constraints.rs @@ -15,7 +15,6 @@ use o1_utils::FieldHelpers; #[derive(Clone, Debug)] pub struct Env { - pub poseidon_mds: Vec>, /// The parameter a is the coefficients of the elliptic curve in affine /// coordinates. // FIXME: this is ugly. Let use the curve as a parameter. Only lazy for now. @@ -28,14 +27,13 @@ pub struct Env { } impl Env { - pub fn new(poseidon_mds: Vec>, a: BigInt) -> Self { + pub fn new(a: BigInt) -> Self { // This check might not be useful assert!( a < C::ScalarField::modulus_biguint().into(), "a is too large" ); Self { - poseidon_mds, a, idx_var: 0, idx_var_next_row: 0, @@ -183,7 +181,7 @@ impl InterpreterEnv for Env { } fn get_poseidon_mds_matrix(&mut self, i: usize, j: usize) -> Self::Variable { - let v = self.poseidon_mds[i][j]; + let v = C::sponge_params().mds[i][j]; let v_inner = Operations::from(Literal(v)); Self::Variable::constant(v_inner) } diff --git a/arrabbiata/tests/constraints.rs b/arrabbiata/tests/constraints.rs index 8febfc7495..6d992e4ba8 100644 --- a/arrabbiata/tests/constraints.rs +++ b/arrabbiata/tests/constraints.rs @@ -2,34 +2,24 @@ use arrabbiata::{ columns::Gadget, constraints, interpreter::{self, Instruction}, - poseidon_3_60_0_5_5_fp, poseidon_3_60_0_5_5_fq, }; use mina_curves::pasta::{curves::vesta::Vesta, Pallas}; use num_bigint::BigInt; use std::collections::HashMap; fn helper_compute_constraints_gadget(instr: Instruction, exp_constraints: usize) { - let mut constraints_fp = { - let poseidon_mds = poseidon_3_60_0_5_5_fp::static_params().mds.clone(); - constraints::Env::::new(poseidon_mds.to_vec(), BigInt::from(0_usize)) - }; + let mut constraints_fp = constraints::Env::::new(BigInt::from(0_usize)); interpreter::run_ivc(&mut constraints_fp, instr); assert_eq!(constraints_fp.constraints.len(), exp_constraints); - let mut constraints_fq = { - let poseidon_mds = poseidon_3_60_0_5_5_fq::static_params().mds.clone(); - constraints::Env::::new(poseidon_mds.to_vec(), BigInt::from(0_usize)) - }; + let mut constraints_fq = constraints::Env::::new(BigInt::from(0_usize)); interpreter::run_ivc(&mut constraints_fq, instr); assert_eq!(constraints_fq.constraints.len(), exp_constraints); } fn helper_check_expected_degree_constraints(instr: Instruction, exp_degrees: HashMap) { - let mut constraints_fp = { - let poseidon_mds = poseidon_3_60_0_5_5_fp::static_params().mds.clone(); - constraints::Env::::new(poseidon_mds.to_vec(), BigInt::from(0_usize)) - }; + let mut constraints_fp = constraints::Env::::new(BigInt::from(0_usize)); interpreter::run_ivc(&mut constraints_fp, instr); let mut actual_degrees: HashMap = HashMap::new(); @@ -58,10 +48,7 @@ fn helper_gadget_number_of_columns_used( exp_nb_columns: usize, exp_nb_public_input: usize, ) { - let mut constraints_fp = { - let poseidon_mds = poseidon_3_60_0_5_5_fp::static_params().mds.clone(); - constraints::Env::::new(poseidon_mds.to_vec(), BigInt::from(0_usize)) - }; + let mut constraints_fp = constraints::Env::::new(BigInt::from(0_usize)); interpreter::run_ivc(&mut constraints_fp, instr); let nb_columns = constraints_fp.idx_var; @@ -72,10 +59,7 @@ fn helper_gadget_number_of_columns_used( } fn helper_check_gadget_activated(instr: Instruction, gadget: Gadget) { - let mut constraints_fp = { - let poseidon_mds = poseidon_3_60_0_5_5_fp::static_params().mds.clone(); - constraints::Env::::new(poseidon_mds.to_vec(), BigInt::from(0_usize)) - }; + let mut constraints_fp = constraints::Env::::new(BigInt::from(0_usize)); interpreter::run_ivc(&mut constraints_fp, instr); assert_eq!(constraints_fp.activated_gadget, Some(gadget)); @@ -116,10 +100,7 @@ fn test_gadget_elliptic_curve_addition() { #[test] fn test_ivc_total_number_of_constraints_ivc() { - let constraints_fp = { - let poseidon_mds = poseidon_3_60_0_5_5_fp::static_params().mds.clone(); - constraints::Env::::new(poseidon_mds.to_vec(), BigInt::from(0_usize)) - }; + let constraints_fp = constraints::Env::::new(BigInt::from(0_usize)); let constraints = constraints_fp.get_all_constraints_for_ivc(); assert_eq!(constraints.len(), 28); @@ -127,10 +108,7 @@ fn test_ivc_total_number_of_constraints_ivc() { #[test] fn test_degree_of_constraints_ivc() { - let constraints_fp = { - let poseidon_mds = poseidon_3_60_0_5_5_fp::static_params().mds.clone(); - constraints::Env::::new(poseidon_mds.to_vec(), BigInt::from(0_usize)) - }; + let constraints_fp = constraints::Env::::new(BigInt::from(0_usize)); let constraints = constraints_fp.get_all_constraints_for_ivc(); From f0316f311f6a5e6076743fa5e2139996d7cedba5 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Thu, 17 Oct 2024 16:23:50 +0200 Subject: [PATCH 135/165] Arrabiata/Witness: use curve for poseidon parameters --- arrabbiata/src/witness.rs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/arrabbiata/src/witness.rs b/arrabbiata/src/witness.rs index e5bc957f18..4ad8a197ad 100644 --- a/arrabbiata/src/witness.rs +++ b/arrabbiata/src/witness.rs @@ -14,9 +14,9 @@ use crate::{ columns::{Column, Gadget}, curve::ArrabbiataCurve, interpreter::{Instruction, InterpreterEnv, Side}, - poseidon_3_60_0_5_5_fp, poseidon_3_60_0_5_5_fq, MAXIMUM_FIELD_SIZE_IN_BITS, NUMBER_OF_COLUMNS, - NUMBER_OF_PUBLIC_INPUTS, NUMBER_OF_SELECTORS, NUMBER_OF_VALUES_TO_ABSORB_PUBLIC_IO, - POSEIDON_ALPHA, POSEIDON_ROUNDS_FULL, POSEIDON_STATE_SIZE, + MAXIMUM_FIELD_SIZE_IN_BITS, NUMBER_OF_COLUMNS, NUMBER_OF_PUBLIC_INPUTS, NUMBER_OF_SELECTORS, + NUMBER_OF_VALUES_TO_ABSORB_PUBLIC_IO, POSEIDON_ALPHA, POSEIDON_ROUNDS_FULL, + POSEIDON_STATE_SIZE, }; pub const IVC_STARTING_INSTRUCTION: Instruction = Instruction::Poseidon(0); @@ -392,11 +392,11 @@ where i: usize, ) -> Self::Variable { let rc = if self.current_iteration % 2 == 0 { - poseidon_3_60_0_5_5_fp::static_params().round_constants[round][i] + E1::sponge_params().round_constants[round][i] .to_biguint() .into() } else { - poseidon_3_60_0_5_5_fq::static_params().round_constants[round][i] + E2::sponge_params().round_constants[round][i] .to_biguint() .into() }; @@ -405,13 +405,9 @@ where fn get_poseidon_mds_matrix(&mut self, i: usize, j: usize) -> Self::Variable { if self.current_iteration % 2 == 0 { - poseidon_3_60_0_5_5_fp::static_params().mds[i][j] - .to_biguint() - .into() + E1::sponge_params().mds[i][j].to_biguint().into() } else { - poseidon_3_60_0_5_5_fq::static_params().mds[i][j] - .to_biguint() - .into() + E2::sponge_params().mds[i][j].to_biguint().into() } } From bb851c535436d160fbe568507a5615f11001ec47 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Thu, 17 Oct 2024 17:04:02 +0200 Subject: [PATCH 136/165] Arrabbiata/Sponge: define PlonkSpongeConstants in curve and use it --- arrabbiata/src/curve.rs | 17 ++++++++++++++- arrabbiata/src/interpreter.rs | 35 +++++++++++++++++++------------ arrabbiata/src/lib.rs | 12 ----------- arrabbiata/src/main.rs | 7 +++++-- arrabbiata/src/witness.rs | 26 ++++++++++++----------- arrabbiata/tests/witness.rs | 33 ++++++++++------------------- arrabbiata/tests/witness_utils.rs | 15 ++++++++----- 7 files changed, 78 insertions(+), 67 deletions(-) diff --git a/arrabbiata/src/curve.rs b/arrabbiata/src/curve.rs index 3a58ee22da..5453dd298e 100644 --- a/arrabbiata/src/curve.rs +++ b/arrabbiata/src/curve.rs @@ -8,9 +8,24 @@ use ark_ec::short_weierstrass::Affine; use kimchi::curve::{pallas_endos, vesta_endos}; use mina_curves::pasta::curves::{pallas::PallasParameters, vesta::VestaParameters}; -use mina_poseidon::poseidon::ArithmeticSpongeParams; +use mina_poseidon::{constants::SpongeConstants, poseidon::ArithmeticSpongeParams}; use poly_commitment::commitment::{CommitmentCurve, EndoCurve}; +#[derive(Clone)] +pub struct PlonkSpongeConstants {} + +impl SpongeConstants for PlonkSpongeConstants { + const SPONGE_CAPACITY: usize = 1; + const SPONGE_WIDTH: usize = 3; + const SPONGE_RATE: usize = 2; + const PERM_ROUNDS_FULL: usize = 60; + const PERM_ROUNDS_PARTIAL: usize = 0; + const PERM_HALF_ROUNDS_FULL: usize = 0; + const PERM_SBOX: u32 = 5; + const PERM_FULL_MDS: bool = true; + const PERM_INITIAL_ARK: bool = false; +} + /// Represents additional information that a curve needs in order to be used /// with Arrabbiata. pub trait ArrabbiataCurve: CommitmentCurve + EndoCurve { diff --git a/arrabbiata/src/interpreter.rs b/arrabbiata/src/interpreter.rs index 025b2ac0a2..648eea6458 100644 --- a/arrabbiata/src/interpreter.rs +++ b/arrabbiata/src/interpreter.rs @@ -87,7 +87,8 @@ //! //! Hashing is a crucial part of the IVC scheme. The hash function the //! interpreter does use for the moment is an instance of the Poseidon hash -//! function with a fixed state size of [POSEIDON_STATE_SIZE]. Increasing the +//! function with a fixed state size of +//! [crate::curve::PlonkSpongeConstants::SPONGE_WIDTH]. Increasing the //! state size can be considered as it would potentially optimize the //! number of rounds, and allow hashing more data on one row. We leave this for //! future works. @@ -338,11 +339,11 @@ //! there. use crate::{ - columns::Gadget, MAXIMUM_FIELD_SIZE_IN_BITS, NUMBER_OF_COLUMNS, POSEIDON_ROUNDS_FULL, - POSEIDON_STATE_SIZE, + columns::Gadget, curve::PlonkSpongeConstants, MAXIMUM_FIELD_SIZE_IN_BITS, NUMBER_OF_COLUMNS, }; use ark_ff::{One, Zero}; use log::debug; +use mina_poseidon::constants::SpongeConstants; use num_bigint::BigInt; /// A list of instruction/gadget implemented in the interpreter. @@ -830,19 +831,23 @@ pub fn run_ivc(env: &mut E, instr: Instruction) { Instruction::Poseidon(curr_round) => { env.activate_gadget(Gadget::Poseidon); debug!("Executing instruction Poseidon({curr_round})"); - if curr_round < POSEIDON_ROUNDS_FULL { + if curr_round < PlonkSpongeConstants::PERM_ROUNDS_FULL { // Values to be absorbed are 0 when when the round is not zero, // i.e. when we are processing the rounds. - let values_to_absorb: Vec = (0..POSEIDON_STATE_SIZE - 1) + let values_to_absorb: Vec = (0..PlonkSpongeConstants::SPONGE_WIDTH + - 1) .map(|_i| { let pos = env.allocate_public_input(); // fetch_value_to_absorb is supposed to return 0 if curr_round != 0. unsafe { env.fetch_value_to_absorb(pos, curr_round) } }) .collect(); - let round_input_positions: Vec = - (0..POSEIDON_STATE_SIZE).map(|_i| env.allocate()).collect(); - let round_output_positions: Vec = (0..POSEIDON_STATE_SIZE) + let round_input_positions: Vec = (0 + ..PlonkSpongeConstants::SPONGE_WIDTH) + .map(|_i| env.allocate()) + .collect(); + let round_output_positions: Vec = (0 + ..PlonkSpongeConstants::SPONGE_WIDTH) .map(|_i| env.allocate_next_row()) .collect(); // If we are at the first round, we load the state from the environment. @@ -856,8 +861,9 @@ pub fn run_ivc(env: &mut E, instr: Instruction) { .enumerate() .map(|(i, pos)| { let res = env.load_poseidon_state(*pos, i); - // Absorb value. The capacity is POSEIDON_STATE_SIZE - 1 - if i < POSEIDON_STATE_SIZE - 1 { + // Absorb value. The capacity is + // PlonkSpongeConstants::SPONGE_WIDTH - 1 + if i < PlonkSpongeConstants::SPONGE_WIDTH - 1 { res + values_to_absorb[i].clone() } else { res @@ -882,7 +888,7 @@ pub fn run_ivc(env: &mut E, instr: Instruction) { let round = curr_round + idx_round; - let rcs: Vec = (0..POSEIDON_STATE_SIZE) + let rcs: Vec = (0..PlonkSpongeConstants::SPONGE_WIDTH) .map(|i| { let pos = env.allocate_public_input(); env.get_poseidon_round_constant(pos, round, i) @@ -915,7 +921,7 @@ pub fn run_ivc(env: &mut E, instr: Instruction) { // now, we will save the state at the end of the last round // and reload it at the beginning of the next Poseidon full // hash. - if round == POSEIDON_ROUNDS_FULL - 1 { + if round == PlonkSpongeConstants::PERM_ROUNDS_FULL - 1 { state.iter().enumerate().for_each(|(i, x)| { unsafe { env.save_poseidon_state(x.clone(), i) }; }); @@ -924,7 +930,10 @@ pub fn run_ivc(env: &mut E, instr: Instruction) { state }); } else { - panic!("Invalid index: it is supposed to be less than {POSEIDON_ROUNDS_FULL}"); + panic!( + "Invalid index: it is supposed to be less than {}", + PlonkSpongeConstants::PERM_ROUNDS_FULL + ); } } Instruction::NoOp => {} diff --git a/arrabbiata/src/lib.rs b/arrabbiata/src/lib.rs index 654d0691fa..dbc0d28bff 100644 --- a/arrabbiata/src/lib.rs +++ b/arrabbiata/src/lib.rs @@ -35,18 +35,6 @@ pub const NUMBER_OF_COLUMNS: usize = 15; /// to absorb. pub const NUMBER_OF_PUBLIC_INPUTS: usize = 15 + 2; -/// The low-exponentiation value used by the Poseidon hash function for the -/// substitution box. -/// -/// The value is used to perform initialisation checks with the fields. -pub const POSEIDON_ALPHA: u64 = 5; - -/// The number of full rounds in the Poseidon hash function. -pub const POSEIDON_ROUNDS_FULL: usize = 60; - -/// The number of elements in the state of the Poseidon hash function. -pub const POSEIDON_STATE_SIZE: usize = 3; - /// The maximum number of bits the fields can be. /// It is critical as we have some assumptions for the gadgets describing the /// IVC. diff --git a/arrabbiata/src/main.rs b/arrabbiata/src/main.rs index 150d56c4d5..de0ecf23c2 100644 --- a/arrabbiata/src/main.rs +++ b/arrabbiata/src/main.rs @@ -1,10 +1,12 @@ use arrabbiata::{ + curve::PlonkSpongeConstants, interpreter::{self, InterpreterEnv}, witness::Env, - IVC_CIRCUIT_SIZE, MIN_SRS_LOG2_SIZE, POSEIDON_STATE_SIZE, + IVC_CIRCUIT_SIZE, MIN_SRS_LOG2_SIZE, }; use log::{debug, info}; use mina_curves::pasta::{Fp, Fq, Pallas, Vesta}; +use mina_poseidon::constants::SpongeConstants; use num_bigint::BigInt; use std::time::Instant; @@ -47,7 +49,8 @@ pub fn main() { let domain_size = 1 << srs_log2_size; // FIXME: setup correctly the initial sponge state - let sponge_e1: [BigInt; POSEIDON_STATE_SIZE] = std::array::from_fn(|_i| BigInt::from(42u64)); + let sponge_e1: [BigInt; PlonkSpongeConstants::SPONGE_WIDTH] = + std::array::from_fn(|_i| BigInt::from(42u64)); // FIXME: make a setup phase to build the selectors let mut env = Env::::new( *srs_log2_size, diff --git a/arrabbiata/src/witness.rs b/arrabbiata/src/witness.rs index 4ad8a197ad..ee6d056f41 100644 --- a/arrabbiata/src/witness.rs +++ b/arrabbiata/src/witness.rs @@ -3,6 +3,7 @@ use ark_ff::PrimeField; use ark_poly::Evaluations; use kimchi::circuits::{domains::EvaluationDomains, gate::CurrOrNext}; use log::{debug, info}; +use mina_poseidon::constants::SpongeConstants; use num_bigint::{BigInt, BigUint}; use num_integer::Integer; use o1_utils::field_helpers::FieldHelpers; @@ -12,11 +13,10 @@ use std::time::Instant; use crate::{ columns::{Column, Gadget}, - curve::ArrabbiataCurve, + curve::{ArrabbiataCurve, PlonkSpongeConstants}, interpreter::{Instruction, InterpreterEnv, Side}, MAXIMUM_FIELD_SIZE_IN_BITS, NUMBER_OF_COLUMNS, NUMBER_OF_PUBLIC_INPUTS, NUMBER_OF_SELECTORS, - NUMBER_OF_VALUES_TO_ABSORB_PUBLIC_IO, POSEIDON_ALPHA, POSEIDON_ROUNDS_FULL, - POSEIDON_STATE_SIZE, + NUMBER_OF_VALUES_TO_ABSORB_PUBLIC_IO, }; pub const IVC_STARTING_INSTRUCTION: Instruction = Instruction::Poseidon(0); @@ -119,8 +119,8 @@ pub struct Env< /// public IO. // IMPROVEME: use a list of BigInt? It might be faster as the CPU will // already have in its cache the values, and we can use a flat array - pub sponge_e1: [BigInt; POSEIDON_STATE_SIZE], - pub sponge_e2: [BigInt; POSEIDON_STATE_SIZE], + pub sponge_e1: [BigInt; PlonkSpongeConstants::SPONGE_WIDTH], + pub sponge_e2: [BigInt; PlonkSpongeConstants::SPONGE_WIDTH], /// The current iteration of the IVC pub current_iteration: u64, @@ -759,23 +759,25 @@ impl< pub fn new( srs_log2_size: usize, z0: BigInt, - sponge_e1: [BigInt; 3], - sponge_e2: [BigInt; 3], + sponge_e1: [BigInt; PlonkSpongeConstants::SPONGE_WIDTH], + sponge_e2: [BigInt; PlonkSpongeConstants::SPONGE_WIDTH], ) -> Self { { assert!(Fp::MODULUS_BIT_SIZE <= MAXIMUM_FIELD_SIZE_IN_BITS.try_into().unwrap(), "The size of the field Fp is too large, it should be less than {MAXIMUM_FIELD_SIZE_IN_BITS}"); assert!(Fq::MODULUS_BIT_SIZE <= MAXIMUM_FIELD_SIZE_IN_BITS.try_into().unwrap(), "The size of the field Fq is too large, it should be less than {MAXIMUM_FIELD_SIZE_IN_BITS}"); let modulus_fp = Fp::modulus_biguint(); + let alpha = PlonkSpongeConstants::PERM_SBOX; assert!( - (modulus_fp - BigUint::from(1_u64)).gcd(&BigUint::from(POSEIDON_ALPHA)) + (modulus_fp - BigUint::from(1_u64)).gcd(&BigUint::from(alpha)) == BigUint::from(1_u64), - "The modulus of Fp should be coprime with {POSEIDON_ALPHA}" + "The modulus of Fp should be coprime with {alpha}" ); let modulus_fq = Fq::modulus_biguint(); + let alpha = PlonkSpongeConstants::PERM_SBOX; assert!( - (modulus_fq - BigUint::from(1_u64)).gcd(&BigUint::from(POSEIDON_ALPHA)) + (modulus_fq - BigUint::from(1_u64)).gcd(&BigUint::from(alpha)) == BigUint::from(1_u64), - "The modulus of Fq should be coprime with {POSEIDON_ALPHA}" + "The modulus of Fq should be coprime with {alpha}" ); } let srs_size = 1 << srs_log2_size; @@ -1012,7 +1014,7 @@ impl< pub fn fetch_next_instruction(&mut self) -> Instruction { match self.current_instruction { Instruction::Poseidon(i) => { - if i < POSEIDON_ROUNDS_FULL - 5 { + if i < PlonkSpongeConstants::PERM_ROUNDS_FULL - 5 { Instruction::Poseidon(i + 5) } else { // FIXME: we continue absorbing diff --git a/arrabbiata/tests/witness.rs b/arrabbiata/tests/witness.rs index 402cd9d9fa..dadeb7dee2 100644 --- a/arrabbiata/tests/witness.rs +++ b/arrabbiata/tests/witness.rs @@ -1,10 +1,11 @@ use ark_ec::{AffineRepr, Group}; use ark_ff::{PrimeField, UniformRand}; use arrabbiata::{ + curve::PlonkSpongeConstants, interpreter::{self, Instruction, InterpreterEnv}, poseidon_3_60_0_5_5_fp, witness::Env, - MAXIMUM_FIELD_SIZE_IN_BITS, POSEIDON_ROUNDS_FULL, POSEIDON_STATE_SIZE, + MAXIMUM_FIELD_SIZE_IN_BITS, }; use mina_curves::pasta::{Fp, Fq, Pallas, ProjectivePallas, Vesta}; use mina_poseidon::{constants::SpongeConstants, permutation::poseidon_block_cipher}; @@ -13,26 +14,11 @@ use o1_utils::FieldHelpers; use poly_commitment::{commitment::CommitmentCurve, PolyComm}; use rand::{CryptoRng, RngCore}; -// Used by the mina_poseidon library. Only for testing. -#[derive(Clone)] -pub struct PlonkSpongeConstants {} - -impl SpongeConstants for PlonkSpongeConstants { - const SPONGE_CAPACITY: usize = 1; - const SPONGE_WIDTH: usize = POSEIDON_STATE_SIZE; - const SPONGE_RATE: usize = 2; - const PERM_ROUNDS_FULL: usize = POSEIDON_ROUNDS_FULL; - const PERM_ROUNDS_PARTIAL: usize = 0; - const PERM_HALF_ROUNDS_FULL: usize = 0; - const PERM_SBOX: u32 = 5; - const PERM_FULL_MDS: bool = true; - const PERM_INITIAL_ARK: bool = false; -} - #[test] fn test_unit_witness_poseidon_next_row_gadget_one_full_hash() { let srs_log2_size = 6; - let sponge: [BigInt; POSEIDON_STATE_SIZE] = std::array::from_fn(|_i| BigInt::from(42u64)); + let sponge: [BigInt; PlonkSpongeConstants::SPONGE_WIDTH] = + std::array::from_fn(|_i| BigInt::from(42u64)); let mut env = Env::::new( srs_log2_size, BigInt::from(1u64), @@ -42,7 +28,7 @@ fn test_unit_witness_poseidon_next_row_gadget_one_full_hash() { env.current_instruction = Instruction::Poseidon(0); - (0..(POSEIDON_ROUNDS_FULL / 5)).for_each(|i| { + (0..(PlonkSpongeConstants::PERM_ROUNDS_FULL / 5)).for_each(|i| { interpreter::run_ivc(&mut env, Instruction::Poseidon(5 * i)); env.reset(); }); @@ -76,7 +62,8 @@ fn test_unit_witness_poseidon_next_row_gadget_one_full_hash() { #[test] fn test_unit_witness_elliptic_curve_addition() { let srs_log2_size = 6; - let sponge_e1: [BigInt; POSEIDON_STATE_SIZE] = std::array::from_fn(|_i| BigInt::from(42u64)); + let sponge_e1: [BigInt; PlonkSpongeConstants::SPONGE_WIDTH] = + std::array::from_fn(|_i| BigInt::from(42u64)); let mut env = Env::::new( srs_log2_size, BigInt::from(1u64), @@ -150,7 +137,8 @@ fn test_unit_witness_elliptic_curve_addition() { fn test_witness_double_elliptic_curve_point() { let mut rng = o1_utils::tests::make_test_rng(None); let srs_log2_size = 6; - let sponge_e1: [BigInt; POSEIDON_STATE_SIZE] = std::array::from_fn(|_i| BigInt::from(42u64)); + let sponge_e1: [BigInt; PlonkSpongeConstants::SPONGE_WIDTH] = + std::array::from_fn(|_i| BigInt::from(42u64)); let mut env = Env::::new( srs_log2_size, BigInt::from(1u64), @@ -186,7 +174,8 @@ where RNG: RngCore + CryptoRng, { let srs_log2_size = 10; - let sponge_e1: [BigInt; POSEIDON_STATE_SIZE] = std::array::from_fn(|_i| r.clone()); + let sponge_e1: [BigInt; PlonkSpongeConstants::SPONGE_WIDTH] = + std::array::from_fn(|_i| r.clone()); let mut env = Env::::new( srs_log2_size, BigInt::from(1u64), diff --git a/arrabbiata/tests/witness_utils.rs b/arrabbiata/tests/witness_utils.rs index 7d71aba2f4..1034014806 100644 --- a/arrabbiata/tests/witness_utils.rs +++ b/arrabbiata/tests/witness_utils.rs @@ -3,8 +3,9 @@ //! A user is expected to use the gadget methods. //! The API of the utilities is more subject to changes. -use arrabbiata::{interpreter::InterpreterEnv, witness::Env, POSEIDON_STATE_SIZE}; +use arrabbiata::{curve::PlonkSpongeConstants, interpreter::InterpreterEnv, witness::Env}; use mina_curves::pasta::{Fp, Fq, Pallas, Vesta}; +use mina_poseidon::constants::SpongeConstants; use num_bigint::BigInt; use o1_utils::FieldHelpers; @@ -14,7 +15,8 @@ fn test_constrain_boolean_witness_negative_value() { let srs_log2_size = 2; let mut env = { let z0 = BigInt::from(1u64); - let sponge_e1: [BigInt; POSEIDON_STATE_SIZE] = std::array::from_fn(|_i| BigInt::from(0u64)); + let sponge_e1: [BigInt; PlonkSpongeConstants::SPONGE_WIDTH] = + std::array::from_fn(|_i| BigInt::from(0u64)); Env::::new(srs_log2_size, z0, sponge_e1.clone(), sponge_e1.clone()) }; @@ -26,7 +28,8 @@ fn test_constrain_boolean_witness_positive_and_negative_modulus() { let srs_log2_size = 2; let mut env = { let z0 = BigInt::from(1u64); - let sponge_e1: [BigInt; POSEIDON_STATE_SIZE] = std::array::from_fn(|_i| BigInt::from(0u64)); + let sponge_e1: [BigInt; PlonkSpongeConstants::SPONGE_WIDTH] = + std::array::from_fn(|_i| BigInt::from(0u64)); Env::::new(srs_log2_size, z0, sponge_e1.clone(), sponge_e1.clone()) }; @@ -40,7 +43,8 @@ fn test_constrain_boolean_witness_positive_and_negative_modulus() { #[test] fn test_write_column_return_the_result_reduced_in_field() { let srs_log2_size = 6; - let sponge_e1: [BigInt; POSEIDON_STATE_SIZE] = std::array::from_fn(|_i| BigInt::from(42u64)); + let sponge_e1: [BigInt; PlonkSpongeConstants::SPONGE_WIDTH] = + std::array::from_fn(|_i| BigInt::from(42u64)); let mut env = Env::::new( srs_log2_size, BigInt::from(1u64), @@ -57,7 +61,8 @@ fn test_write_column_return_the_result_reduced_in_field() { #[test] fn test_write_public_return_the_result_reduced_in_field() { let srs_log2_size = 6; - let sponge_e1: [BigInt; POSEIDON_STATE_SIZE] = std::array::from_fn(|_i| BigInt::from(42u64)); + let sponge_e1: [BigInt; PlonkSpongeConstants::SPONGE_WIDTH] = + std::array::from_fn(|_i| BigInt::from(42u64)); let mut env = Env::::new( srs_log2_size, BigInt::from(1u64), From fd36b40babb843f52938559cd71f66f04f3d9796 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Thu, 17 Oct 2024 17:14:02 +0200 Subject: [PATCH 137/165] Arrabiata/curve: define SPONGE_CONSTANTS for ArrabiataCurve --- arrabbiata/src/curve.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/arrabbiata/src/curve.rs b/arrabbiata/src/curve.rs index 5453dd298e..cc1a72b2c7 100644 --- a/arrabbiata/src/curve.rs +++ b/arrabbiata/src/curve.rs @@ -32,6 +32,13 @@ pub trait ArrabbiataCurve: CommitmentCurve + EndoCurve { /// A human readable name. const NAME: &'static str; + // FIXME: use this in the codebase. + // We might want to use different sponge constants for different curves. + // For now, it does use the same constants for both curves. + type SpongeConstants: SpongeConstants; + + const SPONGE_CONSTANTS: Self::SpongeConstants; + /// Provides the sponge params to be used with this curve. fn sponge_params() -> &'static ArithmeticSpongeParams; @@ -50,6 +57,10 @@ pub trait ArrabbiataCurve: CommitmentCurve + EndoCurve { impl ArrabbiataCurve for Affine { const NAME: &'static str = "pallas"; + type SpongeConstants = PlonkSpongeConstants; + + const SPONGE_CONSTANTS: Self::SpongeConstants = PlonkSpongeConstants {}; + fn sponge_params() -> &'static ArithmeticSpongeParams { crate::poseidon_3_60_0_5_5_fq::static_params() } @@ -70,6 +81,10 @@ impl ArrabbiataCurve for Affine { impl ArrabbiataCurve for Affine { const NAME: &'static str = "vesta"; + type SpongeConstants = PlonkSpongeConstants; + + const SPONGE_CONSTANTS: Self::SpongeConstants = PlonkSpongeConstants {}; + fn sponge_params() -> &'static ArithmeticSpongeParams { crate::poseidon_3_60_0_5_5_fp::static_params() } From ef5a1dc8b5da227f10b1f80bd46f76ef9903ad3a Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Thu, 17 Oct 2024 17:49:26 +0200 Subject: [PATCH 138/165] Arrabbiata: get rid of the `a` parameter in the constraints env --- arrabbiata/src/constraints.rs | 21 ++++++++++++++++++--- arrabbiata/tests/constraints.rs | 15 +++++++-------- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/arrabbiata/src/constraints.rs b/arrabbiata/src/constraints.rs index 22b7b08f1e..02e1bc5e0e 100644 --- a/arrabbiata/src/constraints.rs +++ b/arrabbiata/src/constraints.rs @@ -5,6 +5,8 @@ use crate::{ interpreter::{self, Instruction, Side}, MAX_DEGREE, NUMBER_OF_COLUMNS, NUMBER_OF_PUBLIC_INPUTS, }; +use ark_ec::{short_weierstrass::SWCurveConfig, CurveConfig}; +use ark_ff::PrimeField; use kimchi::circuits::{ expr::{ConstantTerm::Literal, Expr, ExprInner, Operations, Variable}, gate::CurrOrNext, @@ -12,12 +14,12 @@ use kimchi::circuits::{ use log::debug; use num_bigint::BigInt; use o1_utils::FieldHelpers; +use poly_commitment::commitment::CommitmentCurve; #[derive(Clone, Debug)] pub struct Env { /// The parameter a is the coefficients of the elliptic curve in affine /// coordinates. - // FIXME: this is ugly. Let use the curve as a parameter. Only lazy for now. pub a: BigInt, pub idx_var: usize, pub idx_var_next_row: usize, @@ -26,9 +28,13 @@ pub struct Env { pub activated_gadget: Option, } -impl Env { - pub fn new(a: BigInt) -> Self { +impl Env +where + <::Params as CurveConfig>::BaseField: PrimeField, +{ + pub fn new() -> Self { // This check might not be useful + let a: BigInt = ::Params::COEFF_A.to_biguint().into(); assert!( a < C::ScalarField::modulus_biguint().into(), "a is too large" @@ -371,3 +377,12 @@ impl Env { constraints } } + +impl Default for Env +where + <::Params as CurveConfig>::BaseField: PrimeField, +{ + fn default() -> Self { + Self::new() + } +} diff --git a/arrabbiata/tests/constraints.rs b/arrabbiata/tests/constraints.rs index 6d992e4ba8..b15984fd86 100644 --- a/arrabbiata/tests/constraints.rs +++ b/arrabbiata/tests/constraints.rs @@ -4,22 +4,21 @@ use arrabbiata::{ interpreter::{self, Instruction}, }; use mina_curves::pasta::{curves::vesta::Vesta, Pallas}; -use num_bigint::BigInt; use std::collections::HashMap; fn helper_compute_constraints_gadget(instr: Instruction, exp_constraints: usize) { - let mut constraints_fp = constraints::Env::::new(BigInt::from(0_usize)); + let mut constraints_fp = constraints::Env::::new(); interpreter::run_ivc(&mut constraints_fp, instr); assert_eq!(constraints_fp.constraints.len(), exp_constraints); - let mut constraints_fq = constraints::Env::::new(BigInt::from(0_usize)); + let mut constraints_fq = constraints::Env::::new(); interpreter::run_ivc(&mut constraints_fq, instr); assert_eq!(constraints_fq.constraints.len(), exp_constraints); } fn helper_check_expected_degree_constraints(instr: Instruction, exp_degrees: HashMap) { - let mut constraints_fp = constraints::Env::::new(BigInt::from(0_usize)); + let mut constraints_fp = constraints::Env::::new(); interpreter::run_ivc(&mut constraints_fp, instr); let mut actual_degrees: HashMap = HashMap::new(); @@ -48,7 +47,7 @@ fn helper_gadget_number_of_columns_used( exp_nb_columns: usize, exp_nb_public_input: usize, ) { - let mut constraints_fp = constraints::Env::::new(BigInt::from(0_usize)); + let mut constraints_fp = constraints::Env::::new(); interpreter::run_ivc(&mut constraints_fp, instr); let nb_columns = constraints_fp.idx_var; @@ -59,7 +58,7 @@ fn helper_gadget_number_of_columns_used( } fn helper_check_gadget_activated(instr: Instruction, gadget: Gadget) { - let mut constraints_fp = constraints::Env::::new(BigInt::from(0_usize)); + let mut constraints_fp = constraints::Env::::new(); interpreter::run_ivc(&mut constraints_fp, instr); assert_eq!(constraints_fp.activated_gadget, Some(gadget)); @@ -100,7 +99,7 @@ fn test_gadget_elliptic_curve_addition() { #[test] fn test_ivc_total_number_of_constraints_ivc() { - let constraints_fp = constraints::Env::::new(BigInt::from(0_usize)); + let constraints_fp = constraints::Env::::new(); let constraints = constraints_fp.get_all_constraints_for_ivc(); assert_eq!(constraints.len(), 28); @@ -108,7 +107,7 @@ fn test_ivc_total_number_of_constraints_ivc() { #[test] fn test_degree_of_constraints_ivc() { - let constraints_fp = constraints::Env::::new(BigInt::from(0_usize)); + let constraints_fp = constraints::Env::::new(); let constraints = constraints_fp.get_all_constraints_for_ivc(); From 73b4bf429d760115652757d428d671adf3b77c9b Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Thu, 19 Dec 2024 11:55:01 +0100 Subject: [PATCH 139/165] mvpoly: compute the cross terms of a list of polynomials --- mvpoly/src/lib.rs | 36 +++++++++++++++++++++++ mvpoly/tests/monomials.rs | 60 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) diff --git a/mvpoly/src/lib.rs b/mvpoly/src/lib.rs index 87d0532862..1b4683948a 100644 --- a/mvpoly/src/lib.rs +++ b/mvpoly/src/lib.rs @@ -300,3 +300,39 @@ pub trait MVPoly: /// variable in each monomial is of maximum degree 1. fn is_multilinear(&self) -> bool; } + +/// Compute the cross terms of a list of polynomials. The polynomials are +/// linearly combined using the power of a combiner, often called `α`. +pub fn compute_combined_cross_terms< + F: PrimeField, + const N: usize, + const D: usize, + T: MVPoly, +>( + polys: Vec, + eval1: [F; N], + eval2: [F; N], + u1: F, + u2: F, + combiner1: F, + combiner2: F, +) -> HashMap { + // These should never happen as they should be random + // It also makes the code cleaner as we do not need to handle 0^0 + assert!(combiner1 != F::zero()); + assert!(combiner2 != F::zero()); + assert!(u1 != F::zero()); + assert!(u2 != F::zero()); + polys + .into_iter() + .enumerate() + .fold(HashMap::new(), |mut acc, (i, poly)| { + let scalar1 = combiner1.pow([i as u64]); + let scalar2 = combiner2.pow([i as u64]); + let res = poly.compute_cross_terms_scaled(&eval1, &eval2, u1, u2, scalar1, scalar2); + res.iter().for_each(|(p, r)| { + acc.entry(*p).and_modify(|e| *e += r).or_insert(*r); + }); + acc + }) +} diff --git a/mvpoly/tests/monomials.rs b/mvpoly/tests/monomials.rs index b169f8bc01..b81ad623fd 100644 --- a/mvpoly/tests/monomials.rs +++ b/mvpoly/tests/monomials.rs @@ -1,4 +1,5 @@ use ark_ff::{Field, One, UniformRand, Zero}; +use core::cmp::Ordering; use kimchi::circuits::{ berkeley_columns::BerkeleyChallengeTerm, expr::{ConstantExpr, Expr, ExprInner, Variable}, @@ -804,3 +805,62 @@ fn test_cross_terms_scaled() { let scaled_cross_terms = scaled_p1.compute_cross_terms(&random_eval1, &random_eval2, u1, u2); assert_eq!(cross_terms, scaled_cross_terms); } + +#[test] +fn test_cross_terms_aggregated_polynomial() { + let mut rng = o1_utils::tests::make_test_rng(None); + const M: usize = 20; + let polys: Vec> = (0..M) + .map(|_| unsafe { Sparse::::random(&mut rng, None) }) + .collect(); + + let random_eval1: [Fp; 5] = std::array::from_fn(|_| Fp::rand(&mut rng)); + let random_eval2: [Fp; 5] = std::array::from_fn(|_| Fp::rand(&mut rng)); + let u1 = Fp::rand(&mut rng); + let u2 = Fp::rand(&mut rng); + let scalar1: Fp = Fp::rand(&mut rng); + let scalar2: Fp = Fp::rand(&mut rng); + + const N: usize = 5 + M; + const D: usize = 4 + 1; + let aggregated_poly: Sparse = { + let vars: [Sparse; M] = std::array::from_fn(|j| { + let mut res = Sparse::::zero(); + let monomial: [usize; N] = std::array::from_fn(|i| if i == 5 + j { 1 } else { 0 }); + res.add_monomial(monomial, Fp::one()); + res + }); + polys + .iter() + .enumerate() + .fold(Sparse::::zero(), |acc, (j, poly)| { + let poly: Result, String> = (*poly).clone().into(); + let poly: Sparse = poly.unwrap(); + poly * vars[j].clone() + acc + }) + }; + + let res = mvpoly::compute_combined_cross_terms( + polys, + random_eval1, + random_eval2, + u1, + u2, + scalar1, + scalar2, + ); + let random_eval1_prime: [Fp; N] = std::array::from_fn(|i| match i.cmp(&5) { + Ordering::Greater => scalar1.pow([(i as u64) - 5_u64]), + Ordering::Less => random_eval1[i], + Ordering::Equal => Fp::one(), + }); + + let random_eval2_prime: [Fp; N] = std::array::from_fn(|i| match i.cmp(&5) { + Ordering::Greater => scalar2.pow([(i as u64) - 5_u64]), + Ordering::Less => random_eval2[i], + Ordering::Equal => Fp::one(), + }); + let cross_terms_aggregated = + aggregated_poly.compute_cross_terms(&random_eval1_prime, &random_eval2_prime, u1, u2); + assert_eq!(res, cross_terms_aggregated); +} From d418ff51c5c1318882022f60fcd5139ef1017736 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Thu, 19 Dec 2024 14:24:12 +0100 Subject: [PATCH 140/165] mvpoly/tests: check the output size of ct_scaled Checking that the specification is correctly followed. --- mvpoly/tests/monomials.rs | 40 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/mvpoly/tests/monomials.rs b/mvpoly/tests/monomials.rs index b81ad623fd..676122062b 100644 --- a/mvpoly/tests/monomials.rs +++ b/mvpoly/tests/monomials.rs @@ -864,3 +864,43 @@ fn test_cross_terms_aggregated_polynomial() { aggregated_poly.compute_cross_terms(&random_eval1_prime, &random_eval2_prime, u1, u2); assert_eq!(res, cross_terms_aggregated); } + +#[test] +fn test_cross_terms_scaled_invariant_output_size() { + let mut rng = o1_utils::tests::make_test_rng(None); + + let random_eval1: [Fp; 4] = std::array::from_fn(|_| Fp::rand(&mut rng)); + let random_eval2: [Fp; 4] = std::array::from_fn(|_| Fp::rand(&mut rng)); + let u1 = Fp::rand(&mut rng); + let u2 = Fp::rand(&mut rng); + let scalar1 = Fp::rand(&mut rng); + let scalar2 = Fp::rand(&mut rng); + + { + let p1 = unsafe { Sparse::::random(&mut rng, None) }; + let cross_terms = + p1.compute_cross_terms_scaled(&random_eval1, &random_eval2, u1, u2, scalar1, scalar2); + assert_eq!(cross_terms.len(), 4); + } + + { + let p1 = Sparse::::zero(); + let cross_terms = + p1.compute_cross_terms_scaled(&random_eval1, &random_eval2, u1, u2, scalar1, scalar2); + assert_eq!(cross_terms.len(), 4); + } + + { + let p1 = Sparse::::one(); + let cross_terms = + p1.compute_cross_terms_scaled(&random_eval1, &random_eval2, u1, u2, scalar1, scalar2); + assert_eq!(cross_terms.len(), 7); + } + + { + let p1 = Sparse::::from(Fp::from(42)); + let cross_terms = + p1.compute_cross_terms_scaled(&random_eval1, &random_eval2, u1, u2, scalar1, scalar2); + assert_eq!(cross_terms.len(), 12); + } +} From 37fc3464a40529d9df0f5227f9e8754645941881 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Thu, 19 Dec 2024 18:45:16 +0100 Subject: [PATCH 141/165] o1vm/elf: additional context when pc is 0 --- o1vm/src/elf_loader.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/o1vm/src/elf_loader.rs b/o1vm/src/elf_loader.rs index 0fc26a4788..ecdaf895fe 100644 --- a/o1vm/src/elf_loader.rs +++ b/o1vm/src/elf_loader.rs @@ -115,7 +115,7 @@ pub fn parse_riscv32(path: &Path) -> Result { // Entry point of the program let pc: u32 = file.ehdr.e_entry as u32; - assert!(pc != 0, "Entry point is 0. The documentation of the ELF library says that it means the ELF doesn't have an entry point. This is not supported."); + assert!(pc != 0, "Entry point is 0. The documentation of the ELF library says that it means the ELF doesn't have an entry point. This is not supported. This can happen if the binary given is an object file and not an executable file. You might need to call the linker (ld) before running the binary."); let next_pc: u32 = pc + 4u32; let state = State { From acc66025849d19fed1ac5f4cabc26e552c7cf1fb Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Sat, 21 Dec 2024 10:13:30 +0100 Subject: [PATCH 142/165] MVPoly: additional checks reg. multiplication of polynomials The degree is in the type, but we suppose the user will be careful when using the library, which is a bad assumption. --- mvpoly/src/monomials.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mvpoly/src/monomials.rs b/mvpoly/src/monomials.rs index e08be206fa..828d1b7ea1 100644 --- a/mvpoly/src/monomials.rs +++ b/mvpoly/src/monomials.rs @@ -102,6 +102,9 @@ impl Mul for Sparse { fn mul(self, other: Self) -> Self { let mut monomials = HashMap::new(); + let degree_lhs = unsafe { self.degree() }; + let degree_rhs = unsafe { other.degree() }; + assert!(degree_lhs + degree_rhs <= D, "The degree of the output is expected to be maximum {D}, but the resulting output would be larger than {D} ({res})", res=degree_lhs + degree_rhs); self.monomials.iter().for_each(|(exponents1, coeff1)| { other .monomials From 4a3161db65117500e14de45a7dc39c2a0402928b Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Sun, 22 Dec 2024 14:46:29 +0100 Subject: [PATCH 143/165] o1vm/riscv32: add alias for registers --- o1vm/src/interpreters/riscv32im/registers.rs | 99 ++++++++++++++++++++ o1vm/tests/test_riscv_elf.rs | 14 +++ 2 files changed, 113 insertions(+) diff --git a/o1vm/src/interpreters/riscv32im/registers.rs b/o1vm/src/interpreters/riscv32im/registers.rs index ca5906bd54..6a73eca625 100644 --- a/o1vm/src/interpreters/riscv32im/registers.rs +++ b/o1vm/src/interpreters/riscv32im/registers.rs @@ -64,3 +64,102 @@ impl IndexMut for Registers { } } } + +/// This enum provides aliases for the registers. +/// This is useful for debugging and for providing a more readable interface. +/// It can be used to index the registers in the witness. +pub enum RegisterAlias { + Zero, + /// Return address + Ra, + /// Stack pointer + Sp, + /// Global pointer + Gp, + /// Thread pointer + Tp, + /// Temporary/alternate register + T0, + /// Temporaries + T1, + T2, + /// Frame pointer/saved register. This is the same register. + Fp, + S0, + /// Saved registers + S1, + /// Function arguments/results + A0, + A1, + A2, + A3, + A4, + A5, + A6, + A7, + S2, + S3, + S4, + S5, + S6, + S7, + S8, + S9, + S10, + S11, + T3, + T4, + T5, + T6, + /// Current instruction pointer + Ip, + /// Next instruction pointer + NextIp, + HeapPointer, +} + +impl Index for Registers { + type Output = T; + + fn index(&self, index: RegisterAlias) -> &Self::Output { + match index { + RegisterAlias::Zero => &self.general_purpose[0], + RegisterAlias::Ra => &self.general_purpose[1], + RegisterAlias::Sp => &self.general_purpose[2], + RegisterAlias::Gp => &self.general_purpose[3], + RegisterAlias::Tp => &self.general_purpose[4], + RegisterAlias::T0 => &self.general_purpose[5], + RegisterAlias::T1 => &self.general_purpose[6], + RegisterAlias::T2 => &self.general_purpose[7], + // Frame pointer and first saved register are the same register. + RegisterAlias::Fp => &self.general_purpose[8], + RegisterAlias::S0 => &self.general_purpose[8], + RegisterAlias::S1 => &self.general_purpose[9], + RegisterAlias::A0 => &self.general_purpose[10], + RegisterAlias::A1 => &self.general_purpose[11], + RegisterAlias::A2 => &self.general_purpose[12], + RegisterAlias::A3 => &self.general_purpose[13], + RegisterAlias::A4 => &self.general_purpose[14], + RegisterAlias::A5 => &self.general_purpose[15], + RegisterAlias::A6 => &self.general_purpose[16], + RegisterAlias::A7 => &self.general_purpose[17], + RegisterAlias::S2 => &self.general_purpose[18], + RegisterAlias::S3 => &self.general_purpose[19], + RegisterAlias::S4 => &self.general_purpose[20], + RegisterAlias::S5 => &self.general_purpose[21], + RegisterAlias::S6 => &self.general_purpose[22], + RegisterAlias::S7 => &self.general_purpose[23], + RegisterAlias::S8 => &self.general_purpose[24], + RegisterAlias::S9 => &self.general_purpose[25], + RegisterAlias::S10 => &self.general_purpose[26], + RegisterAlias::S11 => &self.general_purpose[27], + RegisterAlias::T3 => &self.general_purpose[28], + RegisterAlias::T4 => &self.general_purpose[29], + RegisterAlias::T5 => &self.general_purpose[30], + RegisterAlias::T6 => &self.general_purpose[31], + RegisterAlias::Ip => &self.current_instruction_pointer, + RegisterAlias::NextIp => &self.next_instruction_pointer, + RegisterAlias::HeapPointer => &self.heap_pointer, + } + } +} diff --git a/o1vm/tests/test_riscv_elf.rs b/o1vm/tests/test_riscv_elf.rs index 4152a5d4bc..8aba68fd3f 100644 --- a/o1vm/tests/test_riscv_elf.rs +++ b/o1vm/tests/test_riscv_elf.rs @@ -1,10 +1,24 @@ use mina_curves::pasta::Fp; use o1vm::interpreters::riscv32im::{ interpreter::{IInstruction, Instruction, RInstruction}, + registers::RegisterAlias::*, witness::Env, PAGE_SIZE, }; +#[test] +fn test_registers_indexed_by_alias() { + let curr_dir = std::env::current_dir().unwrap(); + let path = curr_dir.join(std::path::PathBuf::from( + "resources/programs/riscv32im/bin/sll", + )); + let state = o1vm::elf_loader::parse_riscv32(&path).unwrap(); + let witness = Env::::create(PAGE_SIZE.try_into().unwrap(), state); + + assert_eq!(witness.registers[Ip], 65688); + assert_eq!(witness.registers[NextIp], 65692); +} + #[test] // Checking an instruction can be converted into a string. // It is mostly because we would want to use it to debug or write better error From 3ed7c54772609e45ea8fc42de2afd3a453465551 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Sun, 22 Dec 2024 15:24:51 +0100 Subject: [PATCH 144/165] o1vm/riscv32im: add runtime assertion for input invariants --- o1vm/src/interpreters/riscv32im/witness.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/o1vm/src/interpreters/riscv32im/witness.rs b/o1vm/src/interpreters/riscv32im/witness.rs index c02b240bb4..011185339b 100644 --- a/o1vm/src/interpreters/riscv32im/witness.rs +++ b/o1vm/src/interpreters/riscv32im/witness.rs @@ -214,6 +214,14 @@ impl InterpreterEnv for Env { lowest_bit: u32, position: Self::Position, ) -> Self::Variable { + assert!( + lowest_bit < highest_bit, + "The lowest bit must be strictly lower than the highest bit" + ); + assert!( + highest_bit <= 32, + "The interpreter is for a 32bits architecture" + ); let x: u32 = (*x).try_into().unwrap(); let res = (x >> lowest_bit) & ((1 << (highest_bit - lowest_bit)) - 1); let res = res as u64; From e2b64e30fb06e4c7d8df5b2543a6922007d6aa6d Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Sun, 22 Dec 2024 15:25:27 +0100 Subject: [PATCH 145/165] o1vm/riscv32: sign_extend - add runtime assert for input invariants --- o1vm/src/interpreters/riscv32im/interpreter.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index f27d89ec4e..6338616219 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -1388,6 +1388,7 @@ pub trait InterpreterEnv { /// Given a variable `x`, this function extends it to a signed integer of /// `bitlength` bits. fn sign_extend(&mut self, x: &Self::Variable, bitlength: u32) -> Self::Variable { + assert!(bitlength <= 32); // FIXME: Constrain `high_bit` let high_bit = { let pos = self.alloc_scratch(); From 921811bd41c0ce1b786712ebe307ce1198bfb017 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Sun, 22 Dec 2024 15:25:58 +0100 Subject: [PATCH 146/165] o1vm/riscv32im: sign_extend - make it friendly with overflow checks When bitlength = 0 and when compiling with `-Coverflow-checks=y`, the runtime alerts us that there is an overflow while shifting. Lifting the type to u64 and cast the value as u32 when the computation is done. --- o1vm/src/interpreters/riscv32im/interpreter.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index 6338616219..e960a93fb4 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -1394,7 +1394,13 @@ pub trait InterpreterEnv { let pos = self.alloc_scratch(); unsafe { self.bitmask(x, bitlength, bitlength - 1, pos) } }; - high_bit * Self::constant(((1 << (32 - bitlength)) - 1) << bitlength) + x.clone() + // Casting in u64 for special case of bitlength = 0 to avoid overflow. + // No condition for constant time execution. + // Decomposing the steps for readability. + let v: u64 = (1u64 << (32 - bitlength)) - 1; + let v: u64 = v << bitlength; + let v: u32 = v as u32; + high_bit * Self::constant(v) + x.clone() } fn report_exit(&mut self, exit_code: &Self::Variable); From 177a9d5d245d1e438d2be6b279e343b575c39d00 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Sun, 22 Dec 2024 14:00:22 +0100 Subject: [PATCH 147/165] o1vm/riscv: sll tests - inline exit_success --- o1vm/resources/programs/riscv32im/src/sll.S | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/o1vm/resources/programs/riscv32im/src/sll.S b/o1vm/resources/programs/riscv32im/src/sll.S index 0f8cedd065..daf76f7fb8 100644 --- a/o1vm/resources/programs/riscv32im/src/sll.S +++ b/o1vm/resources/programs/riscv32im/src/sll.S @@ -1,6 +1,8 @@ .global _start -exit_success: +_start: + lui t0, 0x42 + sll t0, t0, 2 li a0, 0 li a1, 0 li a2, 0 @@ -10,8 +12,3 @@ exit_success: li a6, 0 li a7, 42 ecall - -_start: - lui t0, 0x42 - sll t0, t0, 2 - jal exit_success From d2d8d97309c6b9bd3843afaef6c6c0e3d57ecd4b Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Sun, 22 Dec 2024 14:00:46 +0100 Subject: [PATCH 148/165] o1vm/riscv32: run build-riscv32-programs --- o1vm/resources/programs/riscv32im/bin/sll | Bin 456 -> 452 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/o1vm/resources/programs/riscv32im/bin/sll b/o1vm/resources/programs/riscv32im/bin/sll index f5a7fc75b1f62ac9d2aebd97981d7a0843554b68..a6fbe52b56bbec3057643a92f1fd6c6ed9c74f29 100755 GIT binary patch delta 91 zcmX@Xe1v&|1ZN2YBZCP81B1#$MRCRj6D_sH7XW!6%nHN|0t^h>l~@=iPg0s#tU7VY d0Y;t4sf@~u3nq6ms!RL_Do_Tgf&xY;4FGX*5QhK& delta 86 zcmX@Ye1ds`1m_F}Mg|iG1_q6ZisFn*CR%FqF9GsEm=%Z_1Q;e(tMY7DVqus(Nr~b8 lhxoq}7aU+Tn4HL{%nDKzKY1gg@Z>p+0!++|lh-kd0RVou72E&- From 763521614321f795e5e1a5d44db4f684c493fa20 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Sun, 22 Dec 2024 14:01:19 +0100 Subject: [PATCH 149/165] o1vm/riscv32: stop ignoring sll.S test --- o1vm/tests/test_riscv_elf.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/o1vm/tests/test_riscv_elf.rs b/o1vm/tests/test_riscv_elf.rs index 8aba68fd3f..343cbfb73c 100644 --- a/o1vm/tests/test_riscv_elf.rs +++ b/o1vm/tests/test_riscv_elf.rs @@ -88,10 +88,7 @@ fn test_fibonacci_7() { } } -// FIXME: stop ignore when all the instructions necessary for running this -// program are implemented. #[test] -#[ignore] fn test_sll() { let curr_dir = std::env::current_dir().unwrap(); let path = curr_dir.join(std::path::PathBuf::from( From ae5870f163a5da2bc398674ae280f6d1883cd91e Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Sun, 22 Dec 2024 14:01:52 +0100 Subject: [PATCH 150/165] Ignore object files from o1vm programs --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 67a6dff458..c6f644327e 100644 --- a/.gitignore +++ b/.gitignore @@ -41,4 +41,5 @@ meta.json state.json # Directory for the RISC-V 32bits toolchain -_riscv32-gnu-toolchain \ No newline at end of file +_riscv32-gnu-toolchain +o1vm/resources/programs/riscv32im/bin/*.o \ No newline at end of file From 5dc6d5759b45ead66c2d033793bf738387ae97dc Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Sun, 22 Dec 2024 14:14:07 +0100 Subject: [PATCH 151/165] o1vm/riscv32: update sll program to get a more predictable input --- o1vm/resources/programs/riscv32im/src/sll.S | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/o1vm/resources/programs/riscv32im/src/sll.S b/o1vm/resources/programs/riscv32im/src/sll.S index daf76f7fb8..e343543e81 100644 --- a/o1vm/resources/programs/riscv32im/src/sll.S +++ b/o1vm/resources/programs/riscv32im/src/sll.S @@ -1,7 +1,9 @@ .global _start _start: - lui t0, 0x42 + # Load 2^12 in the register t0 + lui t0, 0b1 + # Multiply by 4 sll t0, t0, 2 li a0, 0 li a1, 0 From e267608fc3df2db7602b9eb2c0a91c01b7561826 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Sun, 22 Dec 2024 14:14:32 +0100 Subject: [PATCH 152/165] o1vm/riscv32: run make build-riscv32im-programs --- o1vm/resources/programs/riscv32im/bin/sll | Bin 452 -> 452 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/o1vm/resources/programs/riscv32im/bin/sll b/o1vm/resources/programs/riscv32im/bin/sll index a6fbe52b56bbec3057643a92f1fd6c6ed9c74f29..14d0b82f86ad9a542d07cfc83ab024dc1483e35a 100755 GIT binary patch delta 13 UcmX@Ye1v&IDU%Sx#&Taq03f9V9smFU delta 13 UcmX@Ye1v&IDU%Y*#&Taq03jI!G5`Po From 1c0c81ec13214b69c3027852a7ba45b021de5843 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Sun, 22 Dec 2024 14:14:47 +0100 Subject: [PATCH 153/165] o1vm/riscv32: update with expected output --- o1vm/tests/test_riscv_elf.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/o1vm/tests/test_riscv_elf.rs b/o1vm/tests/test_riscv_elf.rs index 343cbfb73c..287e91d9b2 100644 --- a/o1vm/tests/test_riscv_elf.rs +++ b/o1vm/tests/test_riscv_elf.rs @@ -101,5 +101,6 @@ fn test_sll() { witness.step(); } - // FIXME: check the state of the registers after the program has run. + // Expected output of the program + assert_eq!(witness.registers.general_purpose[5], 1 << 14) } From 826c154c1b3a36a95c86439b71ca549109a23162 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Mon, 23 Dec 2024 15:18:53 +0100 Subject: [PATCH 154/165] o1vm/riscv32im: update IP for sll As the program changed, the initial IP also changed. --- o1vm/tests/test_riscv_elf.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/o1vm/tests/test_riscv_elf.rs b/o1vm/tests/test_riscv_elf.rs index 287e91d9b2..c2925b7b10 100644 --- a/o1vm/tests/test_riscv_elf.rs +++ b/o1vm/tests/test_riscv_elf.rs @@ -15,8 +15,8 @@ fn test_registers_indexed_by_alias() { let state = o1vm::elf_loader::parse_riscv32(&path).unwrap(); let witness = Env::::create(PAGE_SIZE.try_into().unwrap(), state); - assert_eq!(witness.registers[Ip], 65688); - assert_eq!(witness.registers[NextIp], 65692); + assert_eq!(witness.registers[Ip], 65652); + assert_eq!(witness.registers[NextIp], 65656); } #[test] From 1c9586156a7f7c2179c588fab28e7c921750a141 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Mon, 23 Dec 2024 13:40:20 +0100 Subject: [PATCH 155/165] o1vm/riscv32im: add example and test for addi --- o1vm/resources/programs/riscv32im/bin/addi | Bin 0 -> 452 bytes o1vm/resources/programs/riscv32im/src/addi.S | 20 +++++++++++++++++++ o1vm/tests/test_riscv_elf.rs | 16 +++++++++++++++ 3 files changed, 36 insertions(+) create mode 100755 o1vm/resources/programs/riscv32im/bin/addi create mode 100644 o1vm/resources/programs/riscv32im/src/addi.S diff --git a/o1vm/resources/programs/riscv32im/bin/addi b/o1vm/resources/programs/riscv32im/bin/addi new file mode 100755 index 0000000000000000000000000000000000000000..4ad4f72babb9e2542acaa7a09fb1b83828c1b2ef GIT binary patch literal 452 zcma)2K~BRk5S#=GmAHWN0VFtZKoK?l00%g6LY#@*kP1r;ME15qy&&<0e87L?0Wh23 za%HU9nO#j3dp~aP@3JgILXIzJC#-YoIh%dz9H+=}LBGd?E^?Mo{Tj{bx5^P?7uhH$ zB#wbTkLW)iP;k(b#Q~Kp4yj}@rA}iW7{7U9@h;RGWRJ8HzqvNfbhD~8-Bo4PElp>t zXDwS-2e0$3TQ;wC!ytXzu2(ZP*0yh>S@}@Y0cCgz;>9jdO7ku#hkun;#Jj~>8ok4R ram1j$m`@q@C)7(aLHDCLA$5mC!xG7~L!G7lsWP|2H{IE;`^)_RiD5f$ literal 0 HcmV?d00001 diff --git a/o1vm/resources/programs/riscv32im/src/addi.S b/o1vm/resources/programs/riscv32im/src/addi.S new file mode 100644 index 0000000000..f4e50282bf --- /dev/null +++ b/o1vm/resources/programs/riscv32im/src/addi.S @@ -0,0 +1,20 @@ +.section .text +.globl _start + +_start: + # Initialize register + li t0, 10 # Load immediate value 10 into t0 + + # Perform addition + addi t0, t0, 5 # Add 5 to the value in t0 and store the result back in t0 + + # Custom exit syscall + li a0, 0 # Set a0 to 0 + li a1, 0 # Set a1 to 0 + li a2, 0 # Set a2 to 0 + li a3, 0 # Set a3 to 0 + li a4, 0 # Set a4 to 0 + li a5, 0 # Set a5 to 0 + li a6, 0 # Set a6 to 0 + li a7, 42 # Set a7 to 42 (custom ecall number) + ecall diff --git a/o1vm/tests/test_riscv_elf.rs b/o1vm/tests/test_riscv_elf.rs index c2925b7b10..444249b11b 100644 --- a/o1vm/tests/test_riscv_elf.rs +++ b/o1vm/tests/test_riscv_elf.rs @@ -104,3 +104,19 @@ fn test_sll() { // Expected output of the program assert_eq!(witness.registers.general_purpose[5], 1 << 14) } + +#[test] +fn test_addi() { + let curr_dir = std::env::current_dir().unwrap(); + let path = curr_dir.join(std::path::PathBuf::from( + "resources/programs/riscv32im/bin/addi", + )); + let state = o1vm::elf_loader::parse_riscv32(&path).unwrap(); + let mut witness = Env::::create(PAGE_SIZE.try_into().unwrap(), state); + + while !witness.halt { + witness.step(); + } + + assert_eq!(witness.registers[T0], 15); +} From a7849d839fe2dc8fb08898c8834050f681009ebf Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Mon, 23 Dec 2024 13:53:49 +0100 Subject: [PATCH 156/165] o1vm/riscv32im: simple example with multiple add calls --- o1vm/resources/programs/riscv32im/bin/add_1 | Bin 0 -> 488 bytes o1vm/resources/programs/riscv32im/src/add_1.S | 29 ++++++++++++++++++ o1vm/tests/test_riscv_elf.rs | 16 ++++++++++ 3 files changed, 45 insertions(+) create mode 100755 o1vm/resources/programs/riscv32im/bin/add_1 create mode 100644 o1vm/resources/programs/riscv32im/src/add_1.S diff --git a/o1vm/resources/programs/riscv32im/bin/add_1 b/o1vm/resources/programs/riscv32im/bin/add_1 new file mode 100755 index 0000000000000000000000000000000000000000..6fc6fe9837f2bc1c9cc707dc662a75eab8cd0ea2 GIT binary patch literal 488 zcma)2!A-+J5S+6KL_!Kd*FdCvcv*=_0q_9v;E@M!EZaE3QViDJB|`Zir3E)Y59t6= z0VU7^4KQnS;mcaHGrO8Q+w*#Ld##j$uK?eW$+6GKHyjSgGmH@6j5_3l`okX}C%;;J za#qk)H;Gr!ljRU-0zijDG~oz(FhMi8fIgXHx6KGcysO>zllW4ahZ;g3k_ml8CUl?N ze+w+Hyu4>KrOnq+ca%M|K99?|o+edXPm)yBBCg})LE5Iwt&#nvTog}vK_hilt(H>} zX<9vZVrgtn1w{7II^)s|kt<#tqV`=;>YORFl`G^M{#(a1N-F%7He*Mg6TT!vsZ&C7 YZU;8W&*v;VpRq7~`x::create(PAGE_SIZE.try_into().unwrap(), state); + + while !witness.halt { + witness.step(); + } + + assert_eq!(witness.registers[T0], 15); +} From 8a260b3b38428b04ff7244f078294ed222346879 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Mon, 23 Dec 2024 14:00:09 +0100 Subject: [PATCH 157/165] o1vm/riscv32im: tests for add, a bit more complicated --- o1vm/resources/programs/riscv32im/bin/add_2 | Bin 0 -> 476 bytes o1vm/resources/programs/riscv32im/src/add_2.S | 32 ++++++++++++++++++ o1vm/tests/test_riscv_elf.rs | 22 ++++++++++++ 3 files changed, 54 insertions(+) create mode 100755 o1vm/resources/programs/riscv32im/bin/add_2 create mode 100644 o1vm/resources/programs/riscv32im/src/add_2.S diff --git a/o1vm/resources/programs/riscv32im/bin/add_2 b/o1vm/resources/programs/riscv32im/bin/add_2 new file mode 100755 index 0000000000000000000000000000000000000000..6a35810533d1bec5a325af15ca95b9ddcef7fe6e GIT binary patch literal 476 zcma)2F;2rk5M0}YL_!LnD`+T?Xs9fFPDz6VR4FK^vChU3C&gghT_ThMcmXN=0iJ;5 zhX3#cKESNag_gBuXLdDrw&&$?dKCl#`3mWqcyj0y@EL|J@Pv*iq!Z`}57nRk066>A z?BlbHzWRy1i~%qAh??+YD5BTHCb~}2x18GXGo@=o?e165uE!)`Yyhzh2E-5yh!J@7 z9$H*;ev4+bEtVAAKn~0@m0H$GR>}G_Q>Odl~e4>Cr5Gju2?x|biQyUf5U%k2S!c;ztZLEz!!io&W&py;B31A WjWhGv^3LbV4Bw^>usGgKf4(0-&q5sl literal 0 HcmV?d00001 diff --git a/o1vm/resources/programs/riscv32im/src/add_2.S b/o1vm/resources/programs/riscv32im/src/add_2.S new file mode 100644 index 0000000000..83f4063ef1 --- /dev/null +++ b/o1vm/resources/programs/riscv32im/src/add_2.S @@ -0,0 +1,32 @@ +.section .text +.globl _start + +_start: + # Initialize registers with some numbers + li t0, 123 # First number + li t1, 456 # Second number + li t2, 789 # Third number + + # Perform first addition + add t3, t0, t1 # t3 = t0 + t1 (123 + 456 = 579) + + # Perform second addition + add t4, t3, t2 # t4 = t3 + t2 (579 + 789 = 1368) + + # Add all numbers in a more complex way for redundancy + add t5, t0, t2 # t5 = t0 + t2 (123 + 789 = 912) + add t6, t1, t5 # t6 = t1 + t5 (456 + 912 = 1368) + + # Ensure final result matches expectations + add t6, t4, x0 # t6 = t4 + x0 (Copy t4 to t6 for validation) + + # Custom exit syscall + li a0, 0 # Set a0 to 0 + li a1, 0 # Set a1 to 0 + li a2, 0 # Set a2 to 0 + li a3, 0 # Set a3 to 0 + li a4, 0 # Set a4 to 0 + li a5, 0 # Set a5 to 0 + li a6, 0 # Set a6 to 0 + li a7, 42 # Set a7 to 42 (custom ecall number) + ecall # Trigger syscall diff --git a/o1vm/tests/test_riscv_elf.rs b/o1vm/tests/test_riscv_elf.rs index ba3940ef4a..de5709fc23 100644 --- a/o1vm/tests/test_riscv_elf.rs +++ b/o1vm/tests/test_riscv_elf.rs @@ -136,3 +136,25 @@ fn test_add_1() { assert_eq!(witness.registers[T0], 15); } + +#[test] +fn test_add_2() { + let curr_dir = std::env::current_dir().unwrap(); + let path = curr_dir.join(std::path::PathBuf::from( + "resources/programs/riscv32im/bin/add_2", + )); + let state = o1vm::elf_loader::parse_riscv32(&path).unwrap(); + let mut witness = Env::::create(PAGE_SIZE.try_into().unwrap(), state); + + while !witness.halt { + witness.step(); + } + + assert_eq!(witness.registers[T0], 123); // First number + assert_eq!(witness.registers[T1], 456); // Second number + assert_eq!(witness.registers[T2], 789); // Third number + assert_eq!(witness.registers[T3], 579); // t3 = t0 + t1 + assert_eq!(witness.registers[T4], 1368); // t4 = t3 + t2 + assert_eq!(witness.registers[T5], 912); // t5 = t0 + t2 + assert_eq!(witness.registers[T6], 1368); // t6 = t4 + x0 (Copy t4 to t6) +} From 83e516ca4d0aad9e55b3457068817da64a555a00 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Mon, 23 Dec 2024 15:07:02 +0100 Subject: [PATCH 158/165] o1vm/riscv32im: add tests for add with overflows --- .../programs/riscv32im/bin/add_overflow | Bin 0 -> 468 bytes .../programs/riscv32im/src/add_overflow.S | 31 ++++++++++++++++++ o1vm/tests/test_riscv_elf.rs | 20 +++++++++++ 3 files changed, 51 insertions(+) create mode 100755 o1vm/resources/programs/riscv32im/bin/add_overflow create mode 100644 o1vm/resources/programs/riscv32im/src/add_overflow.S diff --git a/o1vm/resources/programs/riscv32im/bin/add_overflow b/o1vm/resources/programs/riscv32im/bin/add_overflow new file mode 100755 index 0000000000000000000000000000000000000000..0af6dd1bcc4eec53b8f47e2c125f106151701e74 GIT binary patch literal 468 zcma)2F;2rk5L`P1A|ZvK`v4LRl|_z}G!#%#Qe&MRN1PM~>+TYvG$43FKEM-@Qt&MV z4+t|hPFmKQo!Ql_Y|r!c?M)O#(pD@#!YQDSz#|NMWI2&o&Y(MZr21$N!0Df+kGDiq z%|tKJ<#HhM8OzJ+^?Rc_16jXiqWWK(b$=!bh83Xp!GJmd1F8q^y~iHsSNCYn`g|eL z9c0%nF0|FvFfDa;o*Jr&u5>zPTiV<^?w58_%<=+8=(3zohZM$?kByi*pF@cx{=o+q zOeRSvo`NLxyAl(Ev)Mcp{D%M5A&g7_zf$KJz?VQ<%!_plFw=TKV^(dZ+_ia<;oH^` K7N^^3=lcaNdO?5y literal 0 HcmV?d00001 diff --git a/o1vm/resources/programs/riscv32im/src/add_overflow.S b/o1vm/resources/programs/riscv32im/src/add_overflow.S new file mode 100644 index 0000000000..1d3616f36b --- /dev/null +++ b/o1vm/resources/programs/riscv32im/src/add_overflow.S @@ -0,0 +1,31 @@ +# The addition performed by `add` is simply a bit-wise addition +# The lowest 32 bits are kept, and no overflow bit is kept. +.section .text +.globl _start + +_start: + # Large positive values + # It is equal to + # 0b01111111111111111111111111111111 + + # 0b00000000000000000000000000000001 = + # 0b10000000000000000000000000000000 = + li t0, 2147483647 # t0 = 2147483647 (Max 32-bit signed int) + li t1, 1 # t1 = 1 + add t2, t0, t1 # t2 = t0 + t1 + + # 0b11111111111111111111111111111111 + + # 0b00000000000000000000000000000001 = + # 0b00000000000000000000000000000000 = + li t3, 0b11111111111111111111111111111111 + add t4, t3, t1 # t4 = t3 + t1 (Expected: overflow, wrap around) + + # Custom exit syscall + li a0, 0 + li a1, 0 + li a2, 0 + li a3, 0 + li a4, 0 + li a5, 0 + li a6, 0 + li a7, 42 + ecall diff --git a/o1vm/tests/test_riscv_elf.rs b/o1vm/tests/test_riscv_elf.rs index de5709fc23..7d3d7be7d2 100644 --- a/o1vm/tests/test_riscv_elf.rs +++ b/o1vm/tests/test_riscv_elf.rs @@ -158,3 +158,23 @@ fn test_add_2() { assert_eq!(witness.registers[T5], 912); // t5 = t0 + t2 assert_eq!(witness.registers[T6], 1368); // t6 = t4 + x0 (Copy t4 to t6) } + +#[test] +fn test_add_overflow() { + let curr_dir = std::env::current_dir().unwrap(); + let path = curr_dir.join(std::path::PathBuf::from( + "resources/programs/riscv32im/bin/add_overflow", + )); + let state = o1vm::elf_loader::parse_riscv32(&path).unwrap(); + let mut witness = Env::::create(PAGE_SIZE.try_into().unwrap(), state); + + while !witness.halt { + witness.step(); + } + + assert_eq!(witness.registers[T0], 0b01111111111111111111111111111111); + assert_eq!(witness.registers[T1], 0b00000000000000000000000000000001); + assert_eq!(witness.registers[T2], 0b10000000000000000000000000000000); + assert_eq!(witness.registers[T3], 0b11111111111111111111111111111111); + assert_eq!(witness.registers[T4], 0b00000000000000000000000000000000); +} From 911df441c2b861026c5f3935a6e258be367ca203 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Mon, 23 Dec 2024 15:13:19 +0100 Subject: [PATCH 159/165] o1vm/riscv32im: add tests for addi with negative values --- .../programs/riscv32im/bin/addi_negative | Bin 0 -> 456 bytes .../programs/riscv32im/src/addi_negative.S | 22 ++++++++++++++++++ o1vm/tests/test_riscv_elf.rs | 18 ++++++++++++++ 3 files changed, 40 insertions(+) create mode 100755 o1vm/resources/programs/riscv32im/bin/addi_negative create mode 100644 o1vm/resources/programs/riscv32im/src/addi_negative.S diff --git a/o1vm/resources/programs/riscv32im/bin/addi_negative b/o1vm/resources/programs/riscv32im/bin/addi_negative new file mode 100755 index 0000000000000000000000000000000000000000..f610f7df86b0c65ba290b0ec29a2b2bf9aab3055 GIT binary patch literal 456 zcma)2F;2rk5M0|yh(rUr4V>+_vN_pn2^yVO=! z^Q_d>EHiW~UFqzRgfGkOW=>;F`P`a~^EsSI>eoKFV3v}GVjm=J z?n+Gv&Mvp1;6MBqrx@suXR0L2wOm=SRfGRLMtVLn}soOKyevDYKPVA6Mgdq::create(PAGE_SIZE.try_into().unwrap(), state); + + while !witness.halt { + witness.step(); + } + + assert_eq!(witness.registers[T0], 100); + assert_eq!(witness.registers[T1], 50); + assert_eq!(witness.registers[T2], (-50_i32) as u32); +} From 909e6cb5609b7dfa8acae616b680b46142157a0f Mon Sep 17 00:00:00 2001 From: "fuder.eth" <139509124+vtjl10@users.noreply.github.com> Date: Mon, 23 Dec 2024 20:56:27 +0100 Subject: [PATCH 160/165] Update README-optimism.md --- o1vm/README-optimism.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/o1vm/README-optimism.md b/o1vm/README-optimism.md index 740d495a34..4ce5014df5 100644 --- a/o1vm/README-optimism.md +++ b/o1vm/README-optimism.md @@ -3,7 +3,7 @@ Install the first dependencies: ``` sudo apt update -# chrony will ensure the system clock is open to date +# chrony will ensure the system clock is up to date sudo apt install build-essential git vim chrony ufw -y ``` From 767719a0ce0afb214ab8a8b065f80278dbe7bfa5 Mon Sep 17 00:00:00 2001 From: svv232 Date: Mon, 23 Dec 2024 15:04:17 -0500 Subject: [PATCH 161/165] removing comments for instruction parsing, as these are now clarified by the tests --- o1vm/src/interpreters/riscv32im/interpreter.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index 04d50853f2..5da6951177 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -2066,9 +2066,7 @@ pub fn interpret_stype(env: &mut Env, instr: SInstruction) /// Following the documentation found /// [here](https://www.cs.cornell.edu/courses/cs3410/2024fa/assignments/cpusim/riscv-instructions.pdf) pub fn interpret_sbtype(env: &mut Env, instr: SBInstruction) { - /* fetch instruction pointer from the program state */ let instruction_pointer = env.get_instruction_pointer(); - /* compute the next instruction ptr and add one, as well record raml lookup */ let _next_instruction_pointer = env.get_next_instruction_pointer(); /* read instruction from ip address */ let instruction = { @@ -2081,13 +2079,11 @@ pub fn interpret_sbtype(env: &mut Env, instr: SBInstruction + (v1 * Env::constant(1 << 8)) + v0 }; - /* fetch opcode from instruction bit 0 - 6 for a total len of 7 */ - let opcode = { let pos = env.alloc_scratch(); unsafe { env.bitmask(&instruction, 7, 0, pos) } }; - /* verify opcode is 7 bits */ + env.range_check8(&opcode, 7); let funct3 = { From 758fb1ef50ef62c673d34afe08b1938bc0af49be Mon Sep 17 00:00:00 2001 From: svv232 Date: Mon, 23 Dec 2024 15:16:13 -0500 Subject: [PATCH 162/165] replace range check 8 for size one with assert_boolean --- o1vm/src/interpreters/riscv32im/interpreter.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index 5da6951177..2d8c51ebd2 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -2110,7 +2110,7 @@ pub fn interpret_sbtype(env: &mut Env, instr: SBInstruction unsafe { env.bitmask(&instruction, 8, 7, pos) } }; - env.range_check8(&imm11, 1); + env.assert_boolean(&imm11); let imm1_4 = { let pos = env.alloc_scratch(); @@ -2128,7 +2128,7 @@ pub fn interpret_sbtype(env: &mut Env, instr: SBInstruction let pos = env.alloc_scratch(); unsafe { env.bitmask(&instruction, 32, 31, pos) } }; - env.range_check8(&imm12, 1); + env.assert_boolean(&imm12); // check correctness of decomposition of SB type function env.add_constraint( From f43e34d1eb9edf219c1eb58d7d9b28b40f8a190a Mon Sep 17 00:00:00 2001 From: "fuder.eth" <139509124+vtjl10@users.noreply.github.com> Date: Mon, 23 Dec 2024 21:23:43 +0100 Subject: [PATCH 163/165] Update zkpm.md --- book/src/plonk/zkpm.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/src/plonk/zkpm.md b/book/src/plonk/zkpm.md index 4820a55095..e35dcff645 100644 --- a/book/src/plonk/zkpm.md +++ b/book/src/plonk/zkpm.md @@ -58,7 +58,7 @@ $$ = Z(\omega h)[(a(h) + \beta S_{\sigma1}(h) + \gamma)(b(h) + \beta S_{\sigma2}(h) + \gamma)(c(h) + \beta S_{\sigma3}(h) + \gamma)]$$ -The modified permuation checks that ensures that the check is performed only on all the values except the last $k$ elements in the witness polynomials are as follows. +The modified permutation checks that ensures that the check is performed only on all the values except the last $k$ elements in the witness polynomials are as follows. * For all $h \in H$, $L_1(h)(Z(h) - 1) = 0$ * For all $h \in \blue{H\setminus \{h_{n-k}, \ldots, h_n\}}$, $$\begin{aligned} & Z(h)[(a(h) + \beta h + \gamma)(b(h) + \beta k_1 h + \gamma)(c(h) + \beta k_2 h + \gamma)] \\ From b7849aa50f06e68c4494d302e484e3289e8e056b Mon Sep 17 00:00:00 2001 From: "fuder.eth" <139509124+vtjl10@users.noreply.github.com> Date: Mon, 23 Dec 2024 21:27:35 +0100 Subject: [PATCH 164/165] Update SUMMARY.md --- book/src/SUMMARY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index be318bb0a6..5c70bf9b8c 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -17,7 +17,7 @@ - [Commitments](./fundamentals/zkbook_commitment.md) - [Polynomial Commitments](./plonk/polynomial_commitments.md) - [Inner Product Argument](./plonk/inner_product.md) - - [Different Functionnalities](./plonk/inner_product_api.md) + - [Different Functionalities](./plonk/inner_product_api.md) - [Two Party Computation](./fundamentals/zkbook_2pc/overview.md) - [Garbled Circuits](./fundamentals/zkbook_2pc/gc.md) - [Basics](./fundamentals/zkbook_2pc/basics.md) From 037f60ade8101ba5d72324cd982b843f802eed5a Mon Sep 17 00:00:00 2001 From: svv232 Date: Mon, 23 Dec 2024 15:33:41 -0500 Subject: [PATCH 165/165] passing in reference to assert_boolean --- o1vm/src/interpreters/riscv32im/interpreter.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/o1vm/src/interpreters/riscv32im/interpreter.rs b/o1vm/src/interpreters/riscv32im/interpreter.rs index 2d8c51ebd2..702e7ba2ab 100644 --- a/o1vm/src/interpreters/riscv32im/interpreter.rs +++ b/o1vm/src/interpreters/riscv32im/interpreter.rs @@ -594,9 +594,9 @@ pub trait InterpreterEnv { fn check_boolean(x: &Self::Variable); /// Assert that the value `x` is boolean, and add a constraint in the proof system. - fn assert_boolean(&mut self, x: Self::Variable) { - Self::check_boolean(&x); - self.add_constraint(x.clone() * x.clone() - x); + fn assert_boolean(&mut self, x: &Self::Variable) { + Self::check_boolean(x); + self.add_constraint(x.clone() * x.clone() - x.clone()); } fn add_lookup(&mut self, lookup: Lookup);