From 2cb08df71f06fa3a52a99d31e3e27862de4afc9f Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 28 Feb 2024 13:56:38 +0100 Subject: [PATCH 01/12] InterpreterEnv: add additional trait to Variable --- msm/src/serialization/interpreter.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/msm/src/serialization/interpreter.rs b/msm/src/serialization/interpreter.rs index 309d1b0f27..77a9c8957d 100644 --- a/msm/src/serialization/interpreter.rs +++ b/msm/src/serialization/interpreter.rs @@ -1,7 +1,11 @@ pub trait InterpreterEnv { type Position; - type Variable; + type Variable: Clone + + std::ops::Add + + std::ops::Sub + + std::ops::Mul + + std::fmt::Debug; /// Check that the value is in the range [0, 2^15-1] fn range_check15(&mut self, _value: &Self::Variable) { From 1934fbcf8f23553f674fb1cb6ea5f768c5229243 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 28 Feb 2024 15:18:44 +0100 Subject: [PATCH 02/12] Remove column --- msm/src/serialization/columns.rs | 30 ------------------------------ msm/src/serialization/mod.rs | 1 - 2 files changed, 31 deletions(-) delete mode 100644 msm/src/serialization/columns.rs diff --git a/msm/src/serialization/columns.rs b/msm/src/serialization/columns.rs deleted file mode 100644 index 3ad2a4a7eb..0000000000 --- a/msm/src/serialization/columns.rs +++ /dev/null @@ -1,30 +0,0 @@ -use crate::columns::Column; -use crate::columns::ColumnIndexer; -use crate::LIMBS_NUM; - -/// Columns for the circuit splitting the bulletproof challenges in limbs used -/// by the MSM. -pub enum DecompositionColumnIndexer { - KimchiLimbs(usize), - MSMLimbs(usize), - IntermediateKimchiLimbs(usize), -} - -impl ColumnIndexer for DecompositionColumnIndexer { - fn ix_to_column(self) -> Column { - match self { - DecompositionColumnIndexer::KimchiLimbs(i) => { - assert!(i < 3); - Column::X(i) - } - DecompositionColumnIndexer::MSMLimbs(i) => { - assert!(i < LIMBS_NUM); - Column::X(3 + i) - } - DecompositionColumnIndexer::IntermediateKimchiLimbs(i) => { - assert!(i < 3 + LIMBS_NUM); - Column::X(3 + LIMBS_NUM + i) - } - } - } -} diff --git a/msm/src/serialization/mod.rs b/msm/src/serialization/mod.rs index 1ec99048fd..765e9556ed 100644 --- a/msm/src/serialization/mod.rs +++ b/msm/src/serialization/mod.rs @@ -1,3 +1,2 @@ -pub mod columns; pub mod interpreter; pub mod witness; From 473029015f340fbe1a52b94db4e1f748ad06d35d Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 28 Feb 2024 15:39:16 +0100 Subject: [PATCH 03/12] Bitmask: use u32 instead of u128 --- msm/src/serialization/interpreter.rs | 4 ++-- msm/src/serialization/witness.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/msm/src/serialization/interpreter.rs b/msm/src/serialization/interpreter.rs index 77a9c8957d..577ae703b6 100644 --- a/msm/src/serialization/interpreter.rs +++ b/msm/src/serialization/interpreter.rs @@ -23,8 +23,8 @@ pub trait InterpreterEnv { fn bitmask( &mut self, x: &Self::Variable, - highest_bit: u128, - lowest_bit: u128, + highest_bit: u32, + lowest_bit: u32, position: Self::Position, ) -> Self::Variable; diff --git a/msm/src/serialization/witness.rs b/msm/src/serialization/witness.rs index 622dcf1ba2..6c835195b4 100644 --- a/msm/src/serialization/witness.rs +++ b/msm/src/serialization/witness.rs @@ -34,8 +34,8 @@ impl InterpreterEnv for Env { fn bitmask( &mut self, x: &Self::Variable, - highest_bit: u128, - lowest_bit: u128, + highest_bit: u32, + lowest_bit: u32, position: Self::Position, ) -> Self::Variable { let x: u128 = *x; From eea52bf628a745358828f3e541bbca3ae0397954 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 28 Feb 2024 15:39:42 +0100 Subject: [PATCH 04/12] Env: introduce constant function --- msm/src/serialization/interpreter.rs | 2 ++ msm/src/serialization/witness.rs | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/msm/src/serialization/interpreter.rs b/msm/src/serialization/interpreter.rs index 577ae703b6..835166ba7a 100644 --- a/msm/src/serialization/interpreter.rs +++ b/msm/src/serialization/interpreter.rs @@ -17,6 +17,8 @@ pub trait InterpreterEnv { // TODO } + fn constant(value: u128) -> Self::Variable; + /// Extract the bits from the variable `x` between `highest_bit` and `lowest_bit`, and store /// the result in `position`. /// `lowest_bit` becomes the least-significant bit of the resulting value. diff --git a/msm/src/serialization/witness.rs b/msm/src/serialization/witness.rs index 6c835195b4..d4d83298c7 100644 --- a/msm/src/serialization/witness.rs +++ b/msm/src/serialization/witness.rs @@ -27,6 +27,10 @@ impl InterpreterEnv for Env { fn deserialize_field_element(&mut self) { // TODO + fn constant(value: u128) -> Self::Variable { + value + } + } /// Returns the bits between [highest_bit, lowest_bit] of the variable `x`, From 4270eebfc8e88338a081b70027ab5107fdbf50f3 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 28 Feb 2024 15:40:24 +0100 Subject: [PATCH 05/12] Env: get column for intermediate limbs --- msm/src/serialization/interpreter.rs | 2 ++ msm/src/serialization/witness.rs | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/msm/src/serialization/interpreter.rs b/msm/src/serialization/interpreter.rs index 835166ba7a..7a613c5689 100644 --- a/msm/src/serialization/interpreter.rs +++ b/msm/src/serialization/interpreter.rs @@ -7,6 +7,8 @@ pub trait InterpreterEnv { + std::ops::Mul + std::fmt::Debug; + fn get_column_for_intermediate_limb(j: usize) -> Self::Position; + /// Check that the value is in the range [0, 2^15-1] fn range_check15(&mut self, _value: &Self::Variable) { // TODO diff --git a/msm/src/serialization/witness.rs b/msm/src/serialization/witness.rs index d4d83298c7..f58bb11959 100644 --- a/msm/src/serialization/witness.rs +++ b/msm/src/serialization/witness.rs @@ -31,6 +31,10 @@ impl InterpreterEnv for Env { value } + fn get_column_for_intermediate_limb(j: usize) -> Self::Position { + assert!(j < 19); + Column::X(3 + LIMBS_NUM + j) + Column::X(3 + j) } /// Returns the bits between [highest_bit, lowest_bit] of the variable `x`, From f4d7d95d4049e85623e7cc2ee8bf17272061d9a5 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 28 Feb 2024 15:40:51 +0100 Subject: [PATCH 06/12] Env: remove functions unrelated to env --- msm/src/serialization/interpreter.rs | 8 -------- msm/src/serialization/witness.rs | 2 -- 2 files changed, 10 deletions(-) diff --git a/msm/src/serialization/interpreter.rs b/msm/src/serialization/interpreter.rs index 7a613c5689..0dd33b8933 100644 --- a/msm/src/serialization/interpreter.rs +++ b/msm/src/serialization/interpreter.rs @@ -31,12 +31,4 @@ pub trait InterpreterEnv { lowest_bit: u32, position: Self::Position, ) -> Self::Variable; - - /// Deserialize the next field element given as input - fn deserialize_field_element(&mut self); - - /// Copy the value `value` in the column `position` - fn copy(&mut self, _position: Self::Position, _value: Self::Variable) { - // TODO - } } diff --git a/msm/src/serialization/witness.rs b/msm/src/serialization/witness.rs index f58bb11959..c49ded2091 100644 --- a/msm/src/serialization/witness.rs +++ b/msm/src/serialization/witness.rs @@ -25,8 +25,6 @@ impl InterpreterEnv for Env { // values. Let's see later type Variable = u128; - fn deserialize_field_element(&mut self) { - // TODO fn constant(value: u128) -> Self::Variable { value } From c0968c381a0fb265e432a8f4a31d9efab7912ac1 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 28 Feb 2024 15:41:24 +0100 Subject: [PATCH 07/12] Env: not parametrized by N --- msm/src/serialization/witness.rs | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/msm/src/serialization/witness.rs b/msm/src/serialization/witness.rs index c49ded2091..b4e4e47514 100644 --- a/msm/src/serialization/witness.rs +++ b/msm/src/serialization/witness.rs @@ -5,11 +5,7 @@ use crate::serialization::interpreter::InterpreterEnv; use crate::LIMBS_NUM; /// Environment for the serializer interpreter -/// It is parametrized by the number of field elements to be serialized and the -/// field -pub struct Env { - pub step: usize, - pub kimchi_limbs: [[Fp; 3]; N], +pub struct Env { pub current_kimchi_limbs: [Fp; 3], /// The LIMB_NUM limbs that is used to encode a field element for the MSM pub msm_limbs: [Fp; LIMBS_NUM], @@ -18,7 +14,7 @@ pub struct Env { pub intermediate_limbs: [Fp; 19], } -impl InterpreterEnv for Env { +impl InterpreterEnv for Env { type Position = Column; // FIXME: is u128 ok? I think so, we only have 15 bits, 88 bits and 4 bits @@ -51,7 +47,7 @@ impl InterpreterEnv for Env { } } -impl Env { +impl Env { pub fn write_column(&mut self, position: Column, value: u128) { match position { Column::X(i) => { @@ -69,11 +65,9 @@ impl Env { } } -impl Env { - pub fn create(kimchi_limbs: [[Fp; 3]; N]) -> Self { +impl Env { + pub fn create() -> Self { Self { - step: 0, - kimchi_limbs, current_kimchi_limbs: [Fp::zero(); 3], msm_limbs: [Fp::zero(); LIMBS_NUM], intermediate_limbs: [Fp::zero(); 19], From 5d421a00fac2d336330dd13949ca21b54a744e83 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 28 Feb 2024 15:43:32 +0100 Subject: [PATCH 08/12] InterpreterEnv: add get_column_for_msm_limb --- msm/src/serialization/interpreter.rs | 2 ++ msm/src/serialization/witness.rs | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/msm/src/serialization/interpreter.rs b/msm/src/serialization/interpreter.rs index 0dd33b8933..192a3f1933 100644 --- a/msm/src/serialization/interpreter.rs +++ b/msm/src/serialization/interpreter.rs @@ -9,6 +9,8 @@ pub trait InterpreterEnv { fn get_column_for_intermediate_limb(j: usize) -> Self::Position; + fn get_column_for_msm_limb(j: usize) -> Self::Position; + /// Check that the value is in the range [0, 2^15-1] fn range_check15(&mut self, _value: &Self::Variable) { // TODO diff --git a/msm/src/serialization/witness.rs b/msm/src/serialization/witness.rs index b4e4e47514..f072f94234 100644 --- a/msm/src/serialization/witness.rs +++ b/msm/src/serialization/witness.rs @@ -28,6 +28,10 @@ impl InterpreterEnv for Env { fn get_column_for_intermediate_limb(j: usize) -> Self::Position { assert!(j < 19); Column::X(3 + LIMBS_NUM + j) + } + + fn get_column_for_msm_limb(j: usize) -> Self::Position { + assert!(j < LIMBS_NUM); Column::X(3 + j) } From 05f6f2db978ce331a4b02724a4de187bc3138954 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 28 Feb 2024 16:11:25 +0100 Subject: [PATCH 09/12] Env: get column for kimchi limb --- msm/src/serialization/interpreter.rs | 2 ++ msm/src/serialization/witness.rs | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/msm/src/serialization/interpreter.rs b/msm/src/serialization/interpreter.rs index 192a3f1933..ee8cb8359a 100644 --- a/msm/src/serialization/interpreter.rs +++ b/msm/src/serialization/interpreter.rs @@ -7,6 +7,8 @@ pub trait InterpreterEnv { + std::ops::Mul + std::fmt::Debug; + fn get_column_for_kimchi_limb(j: usize) -> Self::Position; + fn get_column_for_intermediate_limb(j: usize) -> Self::Position; fn get_column_for_msm_limb(j: usize) -> Self::Position; diff --git a/msm/src/serialization/witness.rs b/msm/src/serialization/witness.rs index f072f94234..d48457878b 100644 --- a/msm/src/serialization/witness.rs +++ b/msm/src/serialization/witness.rs @@ -25,6 +25,11 @@ impl InterpreterEnv for Env { value } + fn get_column_for_kimchi_limb(j: usize) -> Self::Position { + assert!(j < 3); + Column::X(j) + } + fn get_column_for_intermediate_limb(j: usize) -> Self::Position { assert!(j < 19); Column::X(3 + LIMBS_NUM + j) From dd5d2e8fca901fb1eb84c74105d38a94faca5d6e Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 28 Feb 2024 17:52:16 +0100 Subject: [PATCH 10/12] Env: implement copy --- msm/src/serialization/interpreter.rs | 2 ++ msm/src/serialization/witness.rs | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/msm/src/serialization/interpreter.rs b/msm/src/serialization/interpreter.rs index ee8cb8359a..932cc83a06 100644 --- a/msm/src/serialization/interpreter.rs +++ b/msm/src/serialization/interpreter.rs @@ -7,6 +7,8 @@ pub trait InterpreterEnv { + std::ops::Mul + std::fmt::Debug; + fn copy(&mut self, x: &Self::Variable, position: Self::Position) -> Self::Variable; + fn get_column_for_kimchi_limb(j: usize) -> Self::Position; fn get_column_for_intermediate_limb(j: usize) -> Self::Position; diff --git a/msm/src/serialization/witness.rs b/msm/src/serialization/witness.rs index d48457878b..d577450370 100644 --- a/msm/src/serialization/witness.rs +++ b/msm/src/serialization/witness.rs @@ -35,6 +35,11 @@ impl InterpreterEnv for Env { Column::X(3 + LIMBS_NUM + j) } + fn copy(&mut self, x: &Self::Variable, position: Self::Position) -> Self::Variable { + self.write_column(position, *x); + *x + } + fn get_column_for_msm_limb(j: usize) -> Self::Position { assert!(j < LIMBS_NUM); Column::X(3 + j) From 1a89a91794a73adca2cb300aeb94bfcac7134314 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Wed, 28 Feb 2024 15:41:33 +0100 Subject: [PATCH 11/12] Implement the main interpreter function outside of the env --- msm/src/serialization/interpreter.rs | 3 +- msm/src/serialization/witness.rs | 240 ++++++++++++++++++++++++++- 2 files changed, 241 insertions(+), 2 deletions(-) diff --git a/msm/src/serialization/interpreter.rs b/msm/src/serialization/interpreter.rs index 932cc83a06..fc57b7b52e 100644 --- a/msm/src/serialization/interpreter.rs +++ b/msm/src/serialization/interpreter.rs @@ -30,7 +30,8 @@ pub trait InterpreterEnv { /// Extract the bits from the variable `x` between `highest_bit` and `lowest_bit`, and store /// the result in `position`. /// `lowest_bit` becomes the least-significant bit of the resulting value. - fn bitmask( + /// The value `x` is expected to be encoded in big-endian + fn bitmask_be( &mut self, x: &Self::Variable, highest_bit: u32, diff --git a/msm/src/serialization/witness.rs b/msm/src/serialization/witness.rs index d577450370..11acd9efe5 100644 --- a/msm/src/serialization/witness.rs +++ b/msm/src/serialization/witness.rs @@ -47,7 +47,8 @@ impl InterpreterEnv for Env { /// Returns the bits between [highest_bit, lowest_bit] of the variable `x`, /// and copy the result in the column `position`. - fn bitmask( + /// The value `x` is expected to be encoded in big-endian + fn bitmask_be( &mut self, x: &Self::Variable, highest_bit: u32, @@ -88,3 +89,240 @@ impl Env { } } } + +/// Deserialize a field element of the scalar field of Vesta or Pallas given as +/// a sequence of 3 limbs of 88 bits. +/// It will deserialize into limbs of 15 bits. +/// Given a scalar field element of Vesta or Pallas, here the decomposition: +/// limbs = [limbs0, limbs1, limbs2] +/// | limbs0 | limbs1 | limbs2 | +/// | 0 ... 87 | 88 ... 175 | 176 .. 264 | +/// ---- ---- ---- +/// / \ / \ / \ +/// (1) (2) (3) +/// (1): c0 = 0...14, c1 = 15..29, c2 = 30..44, c3 = 45..59, c4 = 60..74 +/// (1) and (2): c5 = limbs0[75]..limbs0[87] || limbs1[0]..limbs1[1] +/// (2): c6 = 2...16, c7 = 17..31, c8 = 32..46, c9 = 47..61, c10 = 62..76 +/// (2) and (3): c11 = limbs1[77]..limbs1[87] || limbs2[0]..limbs2[3] +/// (3) c12 = 4...18, c13 = 19..33, c14 = 34..48, c15 = 49..63, c16 = 64..78 +/// And we can ignore the last 10 bits (i.e. limbs2[78..87]) as a field element +/// is 254bits long. +pub fn deserialize_field_element(env: &mut Env, limbs: [u128; 3]) { + // Use this to constrain later + let kimchi_limbs0 = Env::get_column_for_kimchi_limb(0); + let kimchi_limbs1 = Env::get_column_for_kimchi_limb(1); + let kimchi_limbs2 = Env::get_column_for_kimchi_limb(2); + + let input_limb0 = Env::constant(limbs[0]); + let input_limb1 = Env::constant(limbs[1]); + let input_limb2 = Env::constant(limbs[2]); + + // TODO: Do we need to check it is only 88 bits? + env.copy(&input_limb0, kimchi_limbs0); + env.copy(&input_limb1, kimchi_limbs1); + env.copy(&input_limb2, kimchi_limbs2); + + // Compute individual 4 bits limbs of b2 + for j in 0..19 { + let position = Env::get_column_for_intermediate_limb(j); + env.bitmask_be(&input_limb2, 4 * (j + 1) as u32, 4 * j as u32, position); + } + + // FIXME: range check + let c0 = Env::get_column_for_msm_limb(0); + let c1 = Env::get_column_for_msm_limb(1); + let c2 = Env::get_column_for_msm_limb(2); + let c3 = Env::get_column_for_msm_limb(3); + let c4 = Env::get_column_for_msm_limb(4); + let c5 = Env::get_column_for_msm_limb(5); + + env.bitmask_be(&input_limb0, 15, 0, c0); + env.bitmask_be(&input_limb0, 30, 15, c1); + env.bitmask_be(&input_limb0, 45, 30, c2); + env.bitmask_be(&input_limb0, 60, 45, c3); + env.bitmask_be(&input_limb0, 75, 60, c4); + { + let res = (limbs[0] >> 75) & ((1 << (88 - 75)) - 1); + let res_prime = limbs[1] & ((1 << 2) - 1); + let res = Env::constant(res + (res_prime << (15 - 2))); + env.copy(&res, c5); + } + + // Processing limbs1 + // FIXME: range check + let c6 = Env::get_column_for_msm_limb(6); + let c7 = Env::get_column_for_msm_limb(7); + let c8 = Env::get_column_for_msm_limb(8); + let c9 = Env::get_column_for_msm_limb(9); + let c10 = Env::get_column_for_msm_limb(10); + let c11 = Env::get_column_for_msm_limb(11); + env.bitmask_be(&input_limb1, 17, 2, c6); + env.bitmask_be(&input_limb1, 32, 17, c7); + env.bitmask_be(&input_limb1, 47, 32, c8); + env.bitmask_be(&input_limb1, 62, 47, c9); + env.bitmask_be(&input_limb1, 77, 62, c10); + { + let res = (limbs[1] >> 77) & ((1 << (88 - 77)) - 1); + let res_prime = limbs[2] & ((1 << 4) - 1); + let res = Env::constant(res + (res_prime << (15 - 4))); + env.copy(&res, c11); + } + + // FIXME: range check + let c12 = Env::get_column_for_msm_limb(12); + let c13 = Env::get_column_for_msm_limb(13); + let c14 = Env::get_column_for_msm_limb(14); + let c15 = Env::get_column_for_msm_limb(15); + let c16 = Env::get_column_for_msm_limb(16); + env.bitmask_be(&input_limb2, 19, 4, c12); + env.bitmask_be(&input_limb2, 34, 19, c13); + env.bitmask_be(&input_limb2, 49, 34, c14); + env.bitmask_be(&input_limb2, 64, 49, c15); + env.bitmask_be(&input_limb2, 79, 64, c16); +} + +#[cfg(test)] +mod tests { + use std::str::FromStr; + + use crate::{LIMBS_NUM, LIMB_BITSIZE}; + + use super::deserialize_field_element; + use super::Env; + use ark_ff::BigInteger; + use ark_ff::FpParameters as _; + use ark_ff::PrimeField; + use ark_ff::{One, UniformRand, Zero}; + use mina_curves::pasta::Fp; + use num_bigint::BigUint; + use o1_utils::{tests::make_test_rng, FieldHelpers}; + use rand::Rng; + + fn test_decomposition_generic(x: Fp) { + let bits = x.to_bits(); + let limb0: u128 = { + let limb0_le_bits: &[bool] = &bits.clone().into_iter().take(88).collect::>(); + let limb0 = Fp::from_bits(limb0_le_bits).unwrap(); + limb0.to_biguint().try_into().unwrap() + }; + let limb1: u128 = { + let limb0_le_bits: &[bool] = &bits + .clone() + .into_iter() + .skip(88) + .take(88) + .collect::>(); + let limb0 = Fp::from_bits(limb0_le_bits).unwrap(); + limb0.to_biguint().try_into().unwrap() + }; + let limb2: u128 = { + let limb0_le_bits: &[bool] = &bits + .clone() + .into_iter() + .skip(2 * 88) + .take(79) + .collect::>(); + let limb0 = Fp::from_bits(limb0_le_bits).unwrap(); + limb0.to_biguint().try_into().unwrap() + }; + let mut dummy_env = Env::::create(); + deserialize_field_element(&mut dummy_env, [limb0, limb1, limb2]); + + // Check limb are copied into the environment + assert_eq!(Fp::from(limb0), dummy_env.current_kimchi_limbs[0]); + assert_eq!(Fp::from(limb1), dummy_env.current_kimchi_limbs[1]); + assert_eq!(Fp::from(limb2), dummy_env.current_kimchi_limbs[2]); + + // Check intermediate limbs + { + let bits = Fp::from(limb2).to_bits(); + for j in 0..19 { + let le_bits: &[bool] = &bits + .clone() + .into_iter() + .skip(j * 4) + .take(4) + .collect::>(); + let t = Fp::from_bits(le_bits).unwrap(); + assert_eq!( + t, + dummy_env.intermediate_limbs[j], + "{}", + format_args!( + "Intermediate limb {j}. Exp value is {:?}, computed is {:?}", + t.to_biguint(), + dummy_env.intermediate_limbs[j].to_biguint() + ) + ) + } + } + + // Checking msm limbs + for i in 0..LIMBS_NUM { + let le_bits: &[bool] = &bits + .clone() + .into_iter() + .skip(i * LIMB_BITSIZE) + .take(LIMB_BITSIZE) + .collect::>(); + let t = Fp::from_bits(le_bits).unwrap(); + assert_eq!( + t, + dummy_env.msm_limbs[i], + "{}", + format_args!( + "MSM limb {i}. Exp value is {:?}, computed is {:?}", + t.to_biguint(), + dummy_env.msm_limbs[i].to_biguint() + ) + ) + } + } + + #[test] + fn test_decomposition_zero() { + test_decomposition_generic(Fp::zero()); + } + + #[test] + fn test_decomposition_one() { + test_decomposition_generic(Fp::one()); + } + + #[test] + fn test_decomposition_random_first_limb_only() { + let mut rng = make_test_rng(); + let x = rng.gen_range(0..2u128.pow(88) - 1); + test_decomposition_generic(Fp::from(x)); + } + + #[test] + fn test_decomposition_second_limb_only() { + test_decomposition_generic(Fp::from(2u128.pow(88))); + test_decomposition_generic(Fp::from(2u128.pow(88) + 1)); + test_decomposition_generic(Fp::from(2u128.pow(88) + 2)); + test_decomposition_generic(Fp::from(2u128.pow(88) + 16)); + test_decomposition_generic(Fp::from(2u128.pow(88) + 23234)); + } + + #[test] + fn test_decomposition_random_second_limb_only() { + let mut rng = make_test_rng(); + let x = rng.gen_range(0..2u128.pow(88) - 1); + test_decomposition_generic(Fp::from(2u128.pow(88) + x)); + } + + #[test] + fn test_decomposition_random() { + let mut rng = make_test_rng(); + test_decomposition_generic(Fp::rand(&mut rng)); + } + + #[test] + fn test_decomposition_order_minus_one() { + let x = BigUint::from_bytes_be(&::Params::MODULUS.to_bytes_be()) + - BigUint::from_str("1").unwrap(); + + test_decomposition_generic(Fp::from(x)); + } +} From 0a27b4063b62c748e4a1e52c588ba372bba6065c Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Thu, 29 Feb 2024 10:55:22 +0100 Subject: [PATCH 12/12] Serialization/MSM: fix doc generation --- msm/src/serialization/witness.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/msm/src/serialization/witness.rs b/msm/src/serialization/witness.rs index 11acd9efe5..4c04e91d9a 100644 --- a/msm/src/serialization/witness.rs +++ b/msm/src/serialization/witness.rs @@ -94,6 +94,7 @@ impl Env { /// a sequence of 3 limbs of 88 bits. /// It will deserialize into limbs of 15 bits. /// Given a scalar field element of Vesta or Pallas, here the decomposition: +/// ```text /// limbs = [limbs0, limbs1, limbs2] /// | limbs0 | limbs1 | limbs2 | /// | 0 ... 87 | 88 ... 175 | 176 .. 264 | @@ -105,7 +106,8 @@ impl Env { /// (2): c6 = 2...16, c7 = 17..31, c8 = 32..46, c9 = 47..61, c10 = 62..76 /// (2) and (3): c11 = limbs1[77]..limbs1[87] || limbs2[0]..limbs2[3] /// (3) c12 = 4...18, c13 = 19..33, c14 = 34..48, c15 = 49..63, c16 = 64..78 -/// And we can ignore the last 10 bits (i.e. limbs2[78..87]) as a field element +/// ``` +/// And we can ignore the last 10 bits (i.e. `limbs2[78..87]`) as a field element /// is 254bits long. pub fn deserialize_field_element(env: &mut Env, limbs: [u128; 3]) { // Use this to constrain later