From b82a0ea98157687cc0f39a4fd544169403d2e5fc Mon Sep 17 00:00:00 2001 From: 0xkanekiken <100861945+0xKanekiKen@users.noreply.github.com> Date: Mon, 11 Mar 2024 15:48:11 +0000 Subject: [PATCH 01/18] refactor: make limbs generic to accept limb size to support point from diff curves Signed-off-by: 0xkanekiken <100861945+0xKanekiKen@users.noreply.github.com> --- core/src/operations/field/field_den.rs | 66 ++++---- .../operations/field/field_inner_product.rs | 63 ++++---- core/src/operations/field/field_op.rs | 60 ++++---- core/src/operations/field/field_sqrt.rs | 52 ++++--- core/src/operations/field/params.rs | 34 +++-- core/src/operations/field/util_air.rs | 2 +- core/src/runtime/record.rs | 81 +++++----- core/src/runtime/syscall.rs | 32 ++-- core/src/stark/air.rs | 44 +++--- .../src/syscall/precompiles/edwards/ed_add.rs | 142 +++++++++++++----- .../precompiles/edwards/ed_decompress.rs | 43 ++++-- core/src/syscall/precompiles/edwards/mod.rs | 6 + .../syscall/precompiles/k256/decompress.rs | 12 +- core/src/syscall/precompiles/k256/mod.rs | 3 + core/src/syscall/precompiles/mod.rs | 25 +-- .../syscall/precompiles/weierstrass/mod.rs | 3 + .../weierstrass/weierstrass_add.rs | 35 ++--- .../weierstrass/weierstrass_double.rs | 44 +++--- core/src/utils/ec/edwards/ed25519.rs | 11 +- core/src/utils/ec/edwards/mod.rs | 37 +++-- core/src/utils/ec/field.rs | 7 +- core/src/utils/ec/mod.rs | 57 ++++--- core/src/utils/ec/scalar_mul.rs | 20 +-- core/src/utils/ec/utils.rs | 13 +- core/src/utils/ec/weierstrass/bn254.rs | 14 +- core/src/utils/ec/weierstrass/mod.rs | 32 ++-- core/src/utils/ec/weierstrass/secp256k1.rs | 13 +- core/src/utils/mod.rs | 6 +- derive/src/lib.rs | 33 ++++ .../program/elf/riscv32im-succinct-zkvm-elf | Bin 102912 -> 117804 bytes tests/ed-add/Cargo.lock | 33 ++-- tests/ed-add/elf/riscv32im-succinct-zkvm-elf | Bin 85932 -> 101672 bytes tests/ed-decompress/Cargo.lock | 16 +- .../elf/riscv32im-succinct-zkvm-elf | Bin 85744 -> 101600 bytes 34 files changed, 609 insertions(+), 430 deletions(-) diff --git a/core/src/operations/field/field_den.rs b/core/src/operations/field/field_den.rs index d2a41934bc..eec6f123af 100644 --- a/core/src/operations/field/field_den.rs +++ b/core/src/operations/field/field_den.rs @@ -1,15 +1,13 @@ use super::params::Limbs; -use super::params::NUM_WITNESS_LIMBS; use super::util::{compute_root_quotient_and_shift, split_u16_limbs_to_u8_limbs}; use super::util_air::eval_field_operation; use crate::air::Polynomial; use crate::air::SP1AirBuilder; use crate::utils::ec::field::FieldParameters; use core::borrow::{Borrow, BorrowMut}; -use core::mem::size_of; use num::BigUint; use p3_field::PrimeField32; -use sp1_derive::AlignedBorrow; +use sp1_derive::AlignedBorrowWithGenerics; use std::fmt::Debug; /// A set of columns to compute `FieldDen(a, b)` where `a`, `b` are field elements. @@ -19,18 +17,18 @@ use std::fmt::Debug; /// /// Right now the number of limbs is assumed to be a constant, although this could be macro-ed /// or made generic in the future. -#[derive(Debug, Clone, AlignedBorrow)] +#[derive(Debug, Clone, AlignedBorrowWithGenerics)] #[repr(C)] -pub struct FieldDenCols { +pub struct FieldDenCols { /// The result of `a den b`, where a, b are field elements - pub result: Limbs, - pub(crate) carry: Limbs, - pub(crate) witness_low: [T; NUM_WITNESS_LIMBS], - pub(crate) witness_high: [T; NUM_WITNESS_LIMBS], + pub result: Limbs, + pub(crate) carry: Limbs, + pub(crate) witness_low: [T; M], + pub(crate) witness_high: [T; M], } -impl FieldDenCols { - pub fn populate( +impl FieldDenCols { + pub fn populate>( &mut self, a: &BigUint, b: &BigUint, @@ -85,13 +83,13 @@ impl FieldDenCols { } } -impl FieldDenCols { +impl FieldDenCols { #[allow(unused_variables)] - pub fn eval, P: FieldParameters>( + pub fn eval, P: FieldParameters>( &self, builder: &mut AB, - a: &Limbs, - b: &Limbs, + a: &Limbs, + b: &Limbs, sign: bool, ) where V: Into, @@ -120,7 +118,7 @@ impl FieldDenCols { let p_witness_low = self.witness_low.iter().into(); let p_witness_high = self.witness_high.iter().into(); - eval_field_operation::(builder, &p_vanishing, &p_witness_low, &p_witness_high); + eval_field_operation::(builder, &p_vanishing, &p_witness_low, &p_witness_high); } } @@ -147,22 +145,26 @@ mod tests { use p3_matrix::dense::RowMajorMatrix; use p3_matrix::MatrixRowSlices; use rand::thread_rng; - use sp1_derive::AlignedBorrow; - #[derive(AlignedBorrow, Debug, Clone)] - pub struct TestCols { - pub a: Limbs, - pub b: Limbs, - pub a_den_b: FieldDenCols, + use sp1_derive::AlignedBorrowWithGenerics; + + #[derive(Debug, Clone, AlignedBorrowWithGenerics)] + pub struct TestCols { + pub a: Limbs, + pub b: Limbs, + pub a_den_b: FieldDenCols, } - pub const NUM_TEST_COLS: usize = size_of::>(); + const NUM_LIMBS: usize = 32; + const NUM_WITNESS_LIMBS: usize = NUM_LIMBS * 2 - 2; + + pub const NUM_TEST_COLS: usize = size_of::>(); - struct FieldDenChip { + struct FieldDenChip> { pub sign: bool, pub _phantom: std::marker::PhantomData

, } - impl FieldDenChip

{ + impl> FieldDenChip

{ pub fn new(sign: bool) -> Self { Self { sign, @@ -171,7 +173,7 @@ mod tests { } } - impl MachineAir for FieldDenChip

{ + impl> MachineAir for FieldDenChip

{ fn name(&self) -> String { "FieldDen".to_string() } @@ -205,7 +207,8 @@ mod tests { .iter() .map(|(a, b)| { let mut row = [F::zero(); NUM_TEST_COLS]; - let cols: &mut TestCols = row.as_mut_slice().borrow_mut(); + let cols: &mut TestCols = + row.as_mut_slice().borrow_mut(); cols.a = P::to_limbs_field::(a); cols.b = P::to_limbs_field::(b); cols.a_den_b.populate::

(a, b, self.sign); @@ -223,19 +226,20 @@ mod tests { } } - impl BaseAir for FieldDenChip

{ + impl> BaseAir for FieldDenChip

{ fn width(&self) -> usize { NUM_TEST_COLS } } - impl Air for FieldDenChip

+ impl> Air for FieldDenChip

where AB: SP1AirBuilder, { fn eval(&self, builder: &mut AB) { let main = builder.main(); - let local: &TestCols = main.row_slice(0).borrow(); + let local: &TestCols = + main.row_slice(0).borrow(); local .a_den_b .eval::(builder, &local.a, &local.b, self.sign); @@ -257,7 +261,7 @@ mod tests { } #[test] - fn prove_babybear() { + fn prove_field_den_babybear() { let config = BabyBearPoseidon2::new(); let mut challenger = config.challenger(); diff --git a/core/src/operations/field/field_inner_product.rs b/core/src/operations/field/field_inner_product.rs index 150055e01e..202a781031 100644 --- a/core/src/operations/field/field_inner_product.rs +++ b/core/src/operations/field/field_inner_product.rs @@ -1,33 +1,31 @@ use super::params::Limbs; -use super::params::NUM_WITNESS_LIMBS; use super::util::{compute_root_quotient_and_shift, split_u16_limbs_to_u8_limbs}; use super::util_air::eval_field_operation; use crate::air::Polynomial; use crate::air::SP1AirBuilder; use crate::utils::ec::field::FieldParameters; use core::borrow::{Borrow, BorrowMut}; -use core::mem::size_of; use num::BigUint; use num::Zero; use p3_field::{AbstractField, PrimeField32}; -use sp1_derive::AlignedBorrow; +use sp1_derive::AlignedBorrowWithGenerics; use std::fmt::Debug; /// A set of columns to compute `FieldInnerProduct(Vec, Vec)` where a, b are field elements. /// Right now the number of limbs is assumed to be a constant, although this could be macro-ed /// or made generic in the future. -#[derive(Debug, Clone, AlignedBorrow)] +#[derive(Debug, Clone, AlignedBorrowWithGenerics)] #[repr(C)] -pub struct FieldInnerProductCols { +pub struct FieldInnerProductCols { /// The result of `a inner product b`, where a, b are field elements - pub result: Limbs, - pub(crate) carry: Limbs, - pub(crate) witness_low: [T; NUM_WITNESS_LIMBS], - pub(crate) witness_high: [T; NUM_WITNESS_LIMBS], + pub result: Limbs, + pub(crate) carry: Limbs, + pub(crate) witness_low: [T; M], + pub(crate) witness_high: [T; M], } -impl FieldInnerProductCols { - pub fn populate(&mut self, a: &[BigUint], b: &[BigUint]) -> BigUint { +impl FieldInnerProductCols { + pub fn populate>(&mut self, a: &[BigUint], b: &[BigUint]) -> BigUint { let p_a_vec: Vec> = a.iter().map(|x| P::to_limbs_field::(x).into()).collect(); let p_b_vec: Vec> = @@ -75,13 +73,13 @@ impl FieldInnerProductCols { } } -impl FieldInnerProductCols { +impl FieldInnerProductCols { #[allow(unused_variables)] - pub fn eval, P: FieldParameters>( + pub fn eval, P: FieldParameters>( &self, builder: &mut AB, - a: &[Limbs], - b: &[Limbs], + a: &[Limbs], + b: &[Limbs], ) where V: Into, { @@ -108,7 +106,7 @@ impl FieldInnerProductCols { let p_witness_low = self.witness_low.iter().into(); let p_witness_high = self.witness_high.iter().into(); - eval_field_operation::(builder, &p_vanishing, &p_witness_low, &p_witness_high); + eval_field_operation::(builder, &p_vanishing, &p_witness_low, &p_witness_high); } } @@ -135,22 +133,25 @@ mod tests { use p3_matrix::dense::RowMajorMatrix; use p3_matrix::MatrixRowSlices; use rand::thread_rng; - use sp1_derive::AlignedBorrow; + use sp1_derive::AlignedBorrowWithGenerics; - #[derive(AlignedBorrow, Debug, Clone)] - pub struct TestCols { - pub a: [Limbs; 1], - pub b: [Limbs; 1], - pub a_ip_b: FieldInnerProductCols, + #[derive(AlignedBorrowWithGenerics, Debug, Clone)] + pub struct TestCols { + pub a: [Limbs; 1], + pub b: [Limbs; 1], + pub a_ip_b: FieldInnerProductCols, } - pub const NUM_TEST_COLS: usize = size_of::>(); + const NUM_LIMBS: usize = 32; + const NUM_WITNESS_LIMBS: usize = 2 * NUM_LIMBS - 2; - struct FieldIpChip { + pub const NUM_TEST_COLS: usize = size_of::>(); + + struct FieldIpChip> { pub _phantom: std::marker::PhantomData

, } - impl FieldIpChip

{ + impl> FieldIpChip

{ pub fn new() -> Self { Self { _phantom: std::marker::PhantomData, @@ -158,7 +159,7 @@ mod tests { } } - impl MachineAir for FieldIpChip

{ + impl> MachineAir for FieldIpChip

{ fn name(&self) -> String { "FieldInnerProduct".to_string() } @@ -188,7 +189,8 @@ mod tests { .iter() .map(|(a, b)| { let mut row = [F::zero(); NUM_TEST_COLS]; - let cols: &mut TestCols = row.as_mut_slice().borrow_mut(); + let cols: &mut TestCols = + row.as_mut_slice().borrow_mut(); cols.a[0] = P::to_limbs_field::(&a[0]); cols.b[0] = P::to_limbs_field::(&b[0]); cols.a_ip_b.populate::

(a, b); @@ -208,19 +210,20 @@ mod tests { } } - impl BaseAir for FieldIpChip

{ + impl> BaseAir for FieldIpChip

{ fn width(&self) -> usize { NUM_TEST_COLS } } - impl Air for FieldIpChip

+ impl> Air for FieldIpChip

where AB: SP1AirBuilder, { fn eval(&self, builder: &mut AB) { let main = builder.main(); - let local: &TestCols = main.row_slice(0).borrow(); + let local: &TestCols = + main.row_slice(0).borrow(); local.a_ip_b.eval::(builder, &local.a, &local.b); // A dummy constraint to keep the degree 3. diff --git a/core/src/operations/field/field_op.rs b/core/src/operations/field/field_op.rs index b1126a43e8..fc31c4d9d4 100644 --- a/core/src/operations/field/field_op.rs +++ b/core/src/operations/field/field_op.rs @@ -1,17 +1,16 @@ use super::params::Limbs; -use super::params::NUM_WITNESS_LIMBS; use super::util::{compute_root_quotient_and_shift, split_u16_limbs_to_u8_limbs}; use super::util_air::eval_field_operation; use crate::air::Polynomial; use crate::air::SP1AirBuilder; use crate::utils::ec::field::FieldParameters; use core::borrow::{Borrow, BorrowMut}; -use core::mem::size_of; use num::{BigUint, Zero}; use p3_air::AirBuilder; use p3_field::PrimeField32; -use sp1_derive::AlignedBorrow; +use sp1_derive::AlignedBorrowWithGenerics; use std::fmt::Debug; +use std::usize; #[derive(PartialEq, Copy, Clone, Debug)] pub enum FieldOperation { @@ -24,18 +23,18 @@ pub enum FieldOperation { /// A set of columns to compute `FieldOperation(a, b)` where a, b are field elements. /// Right now the number of limbs is assumed to be a constant, although this could be macro-ed /// or made generic in the future. -#[derive(Debug, Clone, AlignedBorrow)] +#[derive(Debug, Clone, AlignedBorrowWithGenerics)] #[repr(C)] -pub struct FieldOpCols { +pub struct FieldOpCols { /// The result of `a op b`, where a, b are field elements - pub result: Limbs, - pub(crate) carry: Limbs, - pub(crate) witness_low: [T; NUM_WITNESS_LIMBS], - pub(crate) witness_high: [T; NUM_WITNESS_LIMBS], + pub result: Limbs, + pub(crate) carry: Limbs, + pub(crate) witness_low: [T; M], + pub(crate) witness_high: [T; M], } -impl FieldOpCols { - pub fn populate( +impl FieldOpCols { + pub fn populate>( &mut self, a: &BigUint, b: &BigUint, @@ -130,11 +129,11 @@ impl FieldOpCols { } } -impl FieldOpCols { +impl FieldOpCols { #[allow(unused_variables)] pub fn eval< AB: SP1AirBuilder, - P: FieldParameters, + P: FieldParameters, A: Into> + Clone, B: Into> + Clone, >( @@ -163,7 +162,7 @@ impl FieldOpCols { let p_vanishing = p_op_minus_result - &(&p_carry * &p_limbs); let p_witness_low = self.witness_low.iter().into(); let p_witness_high = self.witness_high.iter().into(); - eval_field_operation::(builder, &p_vanishing, &p_witness_low, &p_witness_high); + eval_field_operation::(builder, &p_vanishing, &p_witness_low, &p_witness_high); } } @@ -190,23 +189,26 @@ mod tests { use p3_matrix::dense::RowMajorMatrix; use p3_matrix::MatrixRowSlices; use rand::thread_rng; - use sp1_derive::AlignedBorrow; + use sp1_derive::AlignedBorrowWithGenerics; - #[derive(AlignedBorrow, Debug, Clone)] - pub struct TestCols { - pub a: Limbs, - pub b: Limbs, - pub a_op_b: FieldOpCols, + #[derive(AlignedBorrowWithGenerics, Debug, Clone)] + pub struct TestCols { + pub a: Limbs, + pub b: Limbs, + pub a_op_b: FieldOpCols, } - pub const NUM_TEST_COLS: usize = size_of::>(); + const NUM_LIMBS: usize = 32; + const NUM_WITNESS_LIMBS: usize = 2 * NUM_LIMBS - 2; - struct FieldOpChip { + pub const NUM_TEST_COLS: usize = size_of::>(); + + struct FieldOpChip> { pub operation: FieldOperation, pub _phantom: std::marker::PhantomData

, } - impl FieldOpChip

{ + impl> FieldOpChip

{ pub fn new(operation: FieldOperation) -> Self { Self { operation, @@ -215,7 +217,7 @@ mod tests { } } - impl MachineAir for FieldOpChip

{ + impl> MachineAir for FieldOpChip

{ fn name(&self) -> String { format!("FieldOp{:?}", self.operation) } @@ -249,7 +251,8 @@ mod tests { .iter() .map(|(a, b)| { let mut row = [F::zero(); NUM_TEST_COLS]; - let cols: &mut TestCols = row.as_mut_slice().borrow_mut(); + let cols: &mut TestCols = + row.as_mut_slice().borrow_mut(); cols.a = P::to_limbs_field::(a); cols.b = P::to_limbs_field::(b); cols.a_op_b.populate::

(a, b, self.operation); @@ -269,19 +272,20 @@ mod tests { } } - impl BaseAir for FieldOpChip

{ + impl> BaseAir for FieldOpChip

{ fn width(&self) -> usize { NUM_TEST_COLS } } - impl Air for FieldOpChip

+ impl> Air for FieldOpChip

where AB: SP1AirBuilder, { fn eval(&self, builder: &mut AB) { let main = builder.main(); - let local: &TestCols = main.row_slice(0).borrow(); + let local: &TestCols = + main.row_slice(0).borrow(); local .a_op_b .eval::(builder, &local.a, &local.b, self.operation); diff --git a/core/src/operations/field/field_sqrt.rs b/core/src/operations/field/field_sqrt.rs index 21bca7423b..c7dd08efef 100644 --- a/core/src/operations/field/field_sqrt.rs +++ b/core/src/operations/field/field_sqrt.rs @@ -3,29 +3,28 @@ use super::params::Limbs; use crate::air::SP1AirBuilder; use crate::utils::ec::field::FieldParameters; use core::borrow::{Borrow, BorrowMut}; -use core::mem::size_of; use num::BigUint; use p3_field::PrimeField32; -use sp1_derive::AlignedBorrow; +use sp1_derive::AlignedBorrowWithGenerics; use std::fmt::Debug; /// A set of columns to compute the square root in the ed25519 curve. `T` is the field in which each /// limb lives. -#[derive(Debug, Clone, AlignedBorrow)] +#[derive(Debug, Clone, AlignedBorrowWithGenerics)] #[repr(C)] -pub struct FieldSqrtCols { +pub struct FieldSqrtCols { /// The multiplication operation to verify that the sqrt and the input match. /// /// In order to save space, we actually store the sqrt of the input in `multiplication.result` /// since we'll receive the input again in the `eval` function. - pub multiplication: FieldOpCols, + pub multiplication: FieldOpCols, } -impl FieldSqrtCols { +impl FieldSqrtCols { /// Populates the trace. /// /// `P` is the parameter of the field that each limb lives in. - pub fn populate( + pub fn populate>( &mut self, a: &BigUint, sqrt_fn: impl Fn(&BigUint) -> BigUint, @@ -48,12 +47,12 @@ impl FieldSqrtCols { } } -impl FieldSqrtCols { +impl FieldSqrtCols { /// Calculates the square root of `a`. - pub fn eval, P: FieldParameters>( + pub fn eval, P: FieldParameters>( &self, builder: &mut AB, - a: &Limbs, + a: &Limbs, ) where V: Into, { @@ -65,7 +64,7 @@ impl FieldSqrtCols { multiplication.result = *a; // Compute sqrt * sqrt. We pass in P since we want its BaseField to be the mod. - multiplication.eval::, Limbs>( + multiplication.eval::, Limbs>( builder, &sqrt, &sqrt, @@ -97,20 +96,23 @@ mod tests { use p3_matrix::dense::RowMajorMatrix; use p3_matrix::MatrixRowSlices; use rand::thread_rng; - use sp1_derive::AlignedBorrow; - #[derive(AlignedBorrow, Debug, Clone)] - pub struct TestCols { - pub a: Limbs, - pub sqrt: FieldSqrtCols, + use sp1_derive::AlignedBorrowWithGenerics; + #[derive(AlignedBorrowWithGenerics, Debug, Clone)] + pub struct TestCols { + pub a: Limbs, + pub sqrt: FieldSqrtCols, } - pub const NUM_TEST_COLS: usize = size_of::>(); + const NUM_LIMBS: usize = 32; + const NUM_WITNESS_LIMBS: usize = 2 * NUM_LIMBS - 2; - struct EdSqrtChip { + pub const NUM_TEST_COLS: usize = size_of::>(); + + struct EdSqrtChip> { pub _phantom: std::marker::PhantomData

, } - impl EdSqrtChip

{ + impl> EdSqrtChip

{ pub fn new() -> Self { Self { _phantom: std::marker::PhantomData, @@ -118,7 +120,7 @@ mod tests { } } - impl MachineAir for EdSqrtChip

{ + impl> MachineAir for EdSqrtChip

{ fn name(&self) -> String { "EdSqrtChip".to_string() } @@ -147,7 +149,8 @@ mod tests { .iter() .map(|a| { let mut row = [F::zero(); NUM_TEST_COLS]; - let cols: &mut TestCols = row.as_mut_slice().borrow_mut(); + let cols: &mut TestCols = + row.as_mut_slice().borrow_mut(); cols.a = P::to_limbs_field::(a); cols.sqrt.populate::

(a, ed25519_sqrt); row @@ -166,19 +169,20 @@ mod tests { } } - impl BaseAir for EdSqrtChip

{ + impl> BaseAir for EdSqrtChip

{ fn width(&self) -> usize { NUM_TEST_COLS } } - impl Air for EdSqrtChip

+ impl> Air for EdSqrtChip

where AB: SP1AirBuilder, { fn eval(&self, builder: &mut AB) { let main = builder.main(); - let local: &TestCols = main.row_slice(0).borrow(); + let local: &TestCols = + main.row_slice(0).borrow(); // eval verifies that local.sqrt.result is indeed the square root of local.a. local.sqrt.eval::(builder, &local.a); diff --git a/core/src/operations/field/params.rs b/core/src/operations/field/params.rs index 605a9a0869..205dc8c014 100644 --- a/core/src/operations/field/params.rs +++ b/core/src/operations/field/params.rs @@ -2,15 +2,25 @@ use crate::air::Polynomial; use std::fmt::Debug; use std::ops::Index; use std::slice::Iter; +use std::usize; -pub const NUM_LIMBS: usize = 32; +// pub const NUM_LIMBS: usize = 32; pub const NB_BITS_PER_LIMB: usize = 8; -pub const NUM_WITNESS_LIMBS: usize = 2 * NUM_LIMBS - 2; +// pub const NUM_WITNESS_LIMBS: usize = 2 * NUM_LIMBS - 2; -#[derive(Default, Debug, Clone, Copy)] -pub struct Limbs(pub [T; NUM_LIMBS]); +#[derive(Debug, Clone, Copy)] +pub struct Limbs(pub [T; N]); -impl Index for Limbs { +impl Default for Limbs +where + T: Default + Copy, +{ + fn default() -> Self { + Self([T::default(); N]) + } +} + +impl Index for Limbs { type Output = T; fn index(&self, index: usize) -> &Self::Output { @@ -18,17 +28,19 @@ impl Index for Limbs { } } -impl IntoIterator for Limbs { +impl IntoIterator for Limbs { type Item = T; - type IntoIter = std::array::IntoIter; + type IntoIter = std::array::IntoIter; fn into_iter(self) -> Self::IntoIter { self.0.into_iter() } } -impl + Clone, Expr: Clone> From> for Polynomial { - fn from(value: Limbs) -> Self { +impl + Clone, const N: usize, Expr: Clone> From> + for Polynomial +{ + fn from(value: Limbs) -> Self { Polynomial::from_coefficients(&value.0.into_iter().map(|x| x.into()).collect::>()) } } @@ -39,14 +51,14 @@ impl<'a, Var: Into + Clone, Expr: Clone> From> for Polynomia } } -impl From> for Limbs { +impl From> for Limbs { fn from(value: Polynomial) -> Self { let inner = value.as_coefficients().try_into().unwrap(); Self(inner) } } -impl<'a, T: Debug + Default + Clone> From> for Limbs { +impl<'a, T: Debug + Default + Clone, const N: usize> From> for Limbs { fn from(value: Iter<'a, T>) -> Self { let vec: Vec = value.cloned().collect(); let inner = vec.try_into().unwrap(); diff --git a/core/src/operations/field/util_air.rs b/core/src/operations/field/util_air.rs index f4aea7c5bb..d563731363 100644 --- a/core/src/operations/field/util_air.rs +++ b/core/src/operations/field/util_air.rs @@ -3,7 +3,7 @@ use crate::air::SP1AirBuilder; use crate::utils::ec::field::FieldParameters; use p3_field::AbstractField; -pub fn eval_field_operation( +pub fn eval_field_operation>( builder: &mut AB, p_vanishing: &Polynomial, p_witness_low: &Polynomial, diff --git a/core/src/runtime/record.rs b/core/src/runtime/record.rs index 2ab1d70d94..42c9648919 100644 --- a/core/src/runtime/record.rs +++ b/core/src/runtime/record.rs @@ -11,7 +11,7 @@ use crate::field::event::FieldEvent; use crate::runtime::MemoryRecord; use crate::syscall::precompiles::blake3::Blake3CompressInnerEvent; use crate::syscall::precompiles::edwards::EdDecompressEvent; -use crate::syscall::precompiles::k256::K256DecompressEvent; +// use crate::syscall::precompiles::k256::K256DecompressEvent; use crate::syscall::precompiles::keccak256::KeccakPermuteEvent; use crate::syscall::precompiles::sha256::{ShaCompressEvent, ShaExtendEvent}; use crate::syscall::precompiles::{ECAddEvent, ECDoubleEvent}; @@ -73,12 +73,11 @@ pub struct ExecutionRecord { pub ed_decompress_events: Vec, - pub weierstrass_add_events: Vec, + // pub weierstrass_add_events: Vec, - pub weierstrass_double_events: Vec, - - pub k256_decompress_events: Vec, + // pub weierstrass_double_events: Vec, + // pub k256_decompress_events: Vec, pub blake3_compress_inner_events: Vec, /// Information needed for global chips. This shouldn't really be here but for legacy reasons, @@ -148,9 +147,9 @@ pub struct ShardStats { pub nb_keccak_permute_events: usize, pub nb_ed_add_events: usize, pub nb_ed_decompress_events: usize, - pub nb_weierstrass_add_events: usize, - pub nb_weierstrass_double_events: usize, - pub nb_k256_decompress_events: usize, + // pub nb_weierstrass_add_events: usize, + // pub nb_weierstrass_double_events: usize, + // pub nb_k256_decompress_events: usize, } impl ExecutionRecord { @@ -268,27 +267,27 @@ impl ExecutionRecord { shard.keccak_permute_events.extend_from_slice(keccak_chunk); } - // Weierstrass curve add events. - for (weierstrass_add_chunk, shard) in self - .weierstrass_add_events - .chunks(config.weierstrass_add_len) - .zip(shards.iter_mut()) - { - shard - .weierstrass_add_events - .extend_from_slice(weierstrass_add_chunk); - } - - // Weierstrass curve double events. - for (weierstrass_double_chunk, shard) in self - .weierstrass_double_events - .chunks(config.weierstrass_double_len) - .zip(shards.iter_mut()) - { - shard - .weierstrass_double_events - .extend_from_slice(weierstrass_double_chunk); - } + // // Weierstrass curve add events. + // for (weierstrass_add_chunk, shard) in self + // .weierstrass_add_events + // .chunks(config.weierstrass_add_len) + // .zip(shards.iter_mut()) + // { + // shard + // .weierstrass_add_events + // .extend_from_slice(weierstrass_add_chunk); + // } + + // // Weierstrass curve double events. + // for (weierstrass_double_chunk, shard) in self + // .weierstrass_double_events + // .chunks(config.weierstrass_double_len) + // .zip(shards.iter_mut()) + // { + // shard + // .weierstrass_double_events + // .extend_from_slice(weierstrass_double_chunk); + // } // Put the precompile events in the first shard. let first = shards.first_mut().unwrap(); @@ -312,9 +311,9 @@ impl ExecutionRecord { .extend_from_slice(&self.ed_decompress_events); // K256 curve decompress events. - first - .k256_decompress_events - .extend_from_slice(&self.k256_decompress_events); + // first + // .k256_decompress_events + // .extend_from_slice(&self.k256_decompress_events); // Blake3 compress events . first @@ -470,9 +469,9 @@ impl ExecutionRecord { nb_keccak_permute_events: self.keccak_permute_events.len(), nb_ed_add_events: self.ed_add_events.len(), nb_ed_decompress_events: self.ed_decompress_events.len(), - nb_weierstrass_add_events: self.weierstrass_add_events.len(), - nb_weierstrass_double_events: self.weierstrass_double_events.len(), - nb_k256_decompress_events: self.k256_decompress_events.len(), + // nb_weierstrass_add_events: self.weierstrass_add_events.len(), + // nb_weierstrass_double_events: self.weierstrass_double_events.len(), + // nb_k256_decompress_events: self.k256_decompress_events.len(), } } @@ -499,12 +498,12 @@ impl ExecutionRecord { self.ed_add_events.append(&mut other.ed_add_events); self.ed_decompress_events .append(&mut other.ed_decompress_events); - self.weierstrass_add_events - .append(&mut other.weierstrass_add_events); - self.weierstrass_double_events - .append(&mut other.weierstrass_double_events); - self.k256_decompress_events - .append(&mut other.k256_decompress_events); + // self.weierstrass_add_events + // .append(&mut other.weierstrass_add_events); + // self.weierstrass_double_events + // .append(&mut other.weierstrass_double_events); + // self.k256_decompress_events + // .append(&mut other.k256_decompress_events); self.blake3_compress_inner_events .append(&mut other.blake3_compress_inner_events); diff --git a/core/src/runtime/syscall.rs b/core/src/runtime/syscall.rs index b37ce1c537..5111504168 100644 --- a/core/src/runtime/syscall.rs +++ b/core/src/runtime/syscall.rs @@ -5,16 +5,16 @@ use crate::runtime::{Register, Runtime}; use crate::syscall::precompiles::blake3::Blake3CompressInnerChip; use crate::syscall::precompiles::edwards::EdAddAssignChip; use crate::syscall::precompiles::edwards::EdDecompressChip; -use crate::syscall::precompiles::k256::K256DecompressChip; +// use crate::syscall::precompiles::k256::K256DecompressChip; use crate::syscall::precompiles::keccak256::KeccakPermuteChip; use crate::syscall::precompiles::sha256::{ShaCompressChip, ShaExtendChip}; -use crate::syscall::precompiles::weierstrass::WeierstrassAddAssignChip; -use crate::syscall::precompiles::weierstrass::WeierstrassDoubleAssignChip; +// use crate::syscall::precompiles::weierstrass::WeierstrassAddAssignChip; +// use crate::syscall::precompiles::weierstrass::WeierstrassDoubleAssignChip; use crate::syscall::{ SyscallEnterUnconstrained, SyscallExitUnconstrained, SyscallHalt, SyscallLWA, SyscallWrite, }; use crate::utils::ec::edwards::ed25519::{Ed25519, Ed25519Parameters}; -use crate::utils::ec::weierstrass::secp256k1::Secp256k1; +// use crate::utils::ec::weierstrass::secp256k1::Secp256k1; use crate::{cpu::MemoryReadRecord, cpu::MemoryWriteRecord, runtime::ExecutionRecord}; /// A system call is invoked by the the `ecall` instruction with a specific value in register t0. @@ -200,19 +200,19 @@ pub fn default_syscall_map() -> HashMap> { SyscallCode::KECCAK_PERMUTE, Rc::new(KeccakPermuteChip::new()), ); - syscall_map.insert( - SyscallCode::SECP256K1_ADD, - Rc::new(WeierstrassAddAssignChip::::new()), - ); - syscall_map.insert( - SyscallCode::SECP256K1_DOUBLE, - Rc::new(WeierstrassDoubleAssignChip::::new()), - ); + // syscall_map.insert( + // SyscallCode::SECP256K1_ADD, + // Rc::new(WeierstrassAddAssignChip::::new()), + // ); + // syscall_map.insert( + // SyscallCode::SECP256K1_DOUBLE, + // Rc::new(WeierstrassDoubleAssignChip::::new()), + // ); syscall_map.insert(SyscallCode::SHA_COMPRESS, Rc::new(ShaCompressChip::new())); - syscall_map.insert( - SyscallCode::SECP256K1_DECOMPRESS, - Rc::new(K256DecompressChip::new()), - ); + // syscall_map.insert( + // SyscallCode::SECP256K1_DECOMPRESS, + // Rc::new(K256DecompressChip::new()), + // ); syscall_map.insert( SyscallCode::BLAKE3_COMPRESS_INNER, Rc::new(Blake3CompressInnerChip::new()), diff --git a/core/src/stark/air.rs b/core/src/stark/air.rs index a70b1af5fb..014c1ae441 100644 --- a/core/src/stark/air.rs +++ b/core/src/stark/air.rs @@ -23,16 +23,16 @@ pub(crate) mod riscv_chips { pub use crate::syscall::precompiles::blake3::Blake3CompressInnerChip; pub use crate::syscall::precompiles::edwards::EdAddAssignChip; pub use crate::syscall::precompiles::edwards::EdDecompressChip; - pub use crate::syscall::precompiles::k256::K256DecompressChip; + // pub use crate::syscall::precompiles::k256::K256DecompressChip; pub use crate::syscall::precompiles::keccak256::KeccakPermuteChip; pub use crate::syscall::precompiles::sha256::ShaCompressChip; pub use crate::syscall::precompiles::sha256::ShaExtendChip; - pub use crate::syscall::precompiles::weierstrass::WeierstrassAddAssignChip; - pub use crate::syscall::precompiles::weierstrass::WeierstrassDoubleAssignChip; + // pub use crate::syscall::precompiles::weierstrass::WeierstrassAddAssignChip; + // pub use crate::syscall::precompiles::weierstrass::WeierstrassDoubleAssignChip; pub use crate::utils::ec::edwards::ed25519::Ed25519Parameters; pub use crate::utils::ec::edwards::EdwardsCurve; - pub use crate::utils::ec::weierstrass::secp256k1::Secp256k1Parameters; - pub use crate::utils::ec::weierstrass::SwCurve; + // pub use crate::utils::ec::weierstrass::secp256k1::Secp256k1Parameters; + // pub use crate::utils::ec::weierstrass::SwCurve; } /// An AIR for encoding RISC-V execution. @@ -80,12 +80,12 @@ pub enum RiscvAir { Ed25519Add(EdAddAssignChip>), /// A precompile for decompressing a point on the Edwards curve ed25519. Ed25519Decompress(EdDecompressChip), - /// A precompile for decompressing a point on the K256 curve. - K256Decompress(K256DecompressChip), - /// A precompile for addition on the Elliptic curve secp256k1. - Secp256k1Add(WeierstrassAddAssignChip>), - /// A precompile for doubling a point on the Elliptic curve secp256k1. - Secp256k1Double(WeierstrassDoubleAssignChip>), + // /// A precompile for decompressing a point on the K256 curve. + // K256Decompress(K256DecompressChip), + // /// A precompile for addition on the Elliptic curve secp256k1. + // Secp256k1Add(WeierstrassAddAssignChip>), + // /// A precompile for doubling a point on the Elliptic curve secp256k1. + // Secp256k1Double(WeierstrassDoubleAssignChip>), /// A precompile for the Keccak permutation. KeccakP(KeccakPermuteChip), /// A precompile for the Blake3 compression function. @@ -110,14 +110,14 @@ impl RiscvAir { chips.push(RiscvAir::Ed25519Add(ed_add_assign)); let ed_decompress = EdDecompressChip::::default(); chips.push(RiscvAir::Ed25519Decompress(ed_decompress)); - let k256_decompress = K256DecompressChip::default(); - chips.push(RiscvAir::K256Decompress(k256_decompress)); - let weierstrass_add_assign = - WeierstrassAddAssignChip::>::new(); - chips.push(RiscvAir::Secp256k1Add(weierstrass_add_assign)); - let weierstrass_double_assign = - WeierstrassDoubleAssignChip::>::new(); - chips.push(RiscvAir::Secp256k1Double(weierstrass_double_assign)); + // let k256_decompress = K256DecompressChip::default(); + // chips.push(RiscvAir::K256Decompress(k256_decompress)); + // let weierstrass_add_assign = + // WeierstrassAddAssignChip::>::new(); + // chips.push(RiscvAir::Secp256k1Add(weierstrass_add_assign)); + // let weierstrass_double_assign = + // WeierstrassDoubleAssignChip::>::new(); + // chips.push(RiscvAir::Secp256k1Double(weierstrass_double_assign)); let keccak_permute = KeccakPermuteChip::new(); chips.push(RiscvAir::KeccakP(keccak_permute)); let blake3_compress_inner = Blake3CompressInnerChip::new(); @@ -174,9 +174,9 @@ impl RiscvAir { RiscvAir::Sha256Compress(_) => !shard.sha_compress_events.is_empty(), RiscvAir::Ed25519Add(_) => !shard.ed_add_events.is_empty(), RiscvAir::Ed25519Decompress(_) => !shard.ed_decompress_events.is_empty(), - RiscvAir::K256Decompress(_) => !shard.k256_decompress_events.is_empty(), - RiscvAir::Secp256k1Add(_) => !shard.weierstrass_add_events.is_empty(), - RiscvAir::Secp256k1Double(_) => !shard.weierstrass_double_events.is_empty(), + // RiscvAir::K256Decompress(_) => !shard.k256_decompress_events.is_empty(), + // RiscvAir::Secp256k1Add(_) => !shard.weierstrass_add_events.is_empty(), + // RiscvAir::Secp256k1Double(_) => !shard.weierstrass_double_events.is_empty(), RiscvAir::KeccakP(_) => !shard.keccak_permute_events.is_empty(), RiscvAir::Blake3Compress(_) => !shard.blake3_compress_inner_events.is_empty(), } diff --git a/core/src/syscall/precompiles/edwards/ed_add.rs b/core/src/syscall/precompiles/edwards/ed_add.rs index 869dfc148e..4ca3dac766 100644 --- a/core/src/syscall/precompiles/edwards/ed_add.rs +++ b/core/src/syscall/precompiles/edwards/ed_add.rs @@ -9,7 +9,6 @@ use crate::operations::field::field_inner_product::FieldInnerProductCols; use crate::operations::field::field_op::FieldOpCols; use crate::operations::field::field_op::FieldOperation; use crate::operations::field::params::Limbs; -use crate::operations::field::params::NUM_LIMBS; use crate::runtime::ExecutionRecord; use crate::runtime::Syscall; use crate::syscall::precompiles::create_ec_add_event; @@ -18,6 +17,7 @@ use crate::utils::ec::edwards::EdwardsParameters; use crate::utils::ec::field::FieldParameters; use crate::utils::ec::AffinePoint; use crate::utils::ec::EllipticCurve; +use crate::utils::ec::EllipticCurveParameters; use crate::utils::limbs_from_prev_access; use crate::utils::pad_rows; use core::borrow::{Borrow, BorrowMut}; @@ -37,6 +37,8 @@ use std::fmt::Debug; use std::marker::PhantomData; use tracing::instrument; +use super::{NUM_LIMBS, NUM_WITNESS_LIMBS}; + pub const NUM_ED_ADD_COLS: usize = size_of::>(); /// A set of columns to compute `EdAdd` where a, b are field elements. @@ -53,14 +55,14 @@ pub struct EdAddAssignCols { pub q_ptr_access: MemoryReadCols, pub p_access: [MemoryWriteCols; 16], pub q_access: [MemoryReadCols; 16], - pub(crate) x3_numerator: FieldInnerProductCols, - pub(crate) y3_numerator: FieldInnerProductCols, - pub(crate) x1_mul_y1: FieldOpCols, - pub(crate) x2_mul_y2: FieldOpCols, - pub(crate) f: FieldOpCols, - pub(crate) d_mul_f: FieldOpCols, - pub(crate) x3_ins: FieldDenCols, - pub(crate) y3_ins: FieldDenCols, + pub(crate) x3_numerator: FieldInnerProductCols, + pub(crate) y3_numerator: FieldInnerProductCols, + pub(crate) x1_mul_y1: FieldOpCols, + pub(crate) x2_mul_y2: FieldOpCols, + pub(crate) f: FieldOpCols, + pub(crate) d_mul_f: FieldOpCols, + pub(crate) x3_ins: FieldDenCols, + pub(crate) y3_ins: FieldDenCols, } #[derive(Default)] @@ -68,7 +70,7 @@ pub struct EdAddAssignChip { _marker: PhantomData, } -impl EdAddAssignChip { +impl + EdwardsParameters> EdAddAssignChip { pub fn new() -> Self { Self { _marker: PhantomData, @@ -83,33 +85,63 @@ impl EdAddAssignChip { ) { let x3_numerator = cols .x3_numerator - .populate::(&[p_x.clone(), q_x.clone()], &[q_y.clone(), p_y.clone()]); + .populate::<>::BaseField>( + &[p_x.clone(), q_x.clone()], + &[q_y.clone(), p_y.clone()], + ); let y3_numerator = cols .y3_numerator - .populate::(&[p_y.clone(), p_x.clone()], &[q_y.clone(), q_x.clone()]); + .populate::<>::BaseField>( + &[p_y.clone(), p_x.clone()], + &[q_y.clone(), q_x.clone()], + ); let x1_mul_y1 = cols .x1_mul_y1 - .populate::(&p_x, &p_y, FieldOperation::Mul); + .populate::<>::BaseField>( + &p_x, + &p_y, + FieldOperation::Mul, + ); let x2_mul_y2 = cols .x2_mul_y2 - .populate::(&q_x, &q_y, FieldOperation::Mul); + .populate::<>::BaseField>( + &q_x, + &q_y, + FieldOperation::Mul, + ); let f = cols .f - .populate::(&x1_mul_y1, &x2_mul_y2, FieldOperation::Mul); + .populate::<>::BaseField>( + &x1_mul_y1, + &x2_mul_y2, + FieldOperation::Mul, + ); let d = E::d_biguint(); let d_mul_f = cols .d_mul_f - .populate::(&f, &d, FieldOperation::Mul); + .populate::<>::BaseField>( + &f, + &d, + FieldOperation::Mul, + ); cols.x3_ins - .populate::(&x3_numerator, &d_mul_f, true); + .populate::<>::BaseField>( + &x3_numerator, + &d_mul_f, + true, + ); cols.y3_ins - .populate::(&y3_numerator, &d_mul_f, false); + .populate::<>::BaseField>( + &y3_numerator, + &d_mul_f, + false, + ); } } -impl Syscall for EdAddAssignChip { +impl + EdwardsParameters> Syscall for EdAddAssignChip { fn num_extra_cycles(&self) -> u32 { 8 } @@ -121,7 +153,9 @@ impl Syscall for EdAddAssignChip { } } -impl MachineAir for EdAddAssignChip { +impl + EdwardsParameters> MachineAir + for EdAddAssignChip +{ fn name(&self) -> String { "EdAddAssign".to_string() } @@ -143,9 +177,9 @@ impl MachineAir for Ed // Decode affine points. let p = &event.p; let q = &event.q; - let p = AffinePoint::::from_words_le(p); + let p = AffinePoint::::from_words_le(p); let (p_x, p_y) = (p.x, p.y); - let q = AffinePoint::::from_words_le(q); + let q = AffinePoint::::from_words_le(q); let (q_x, q_y) = (q.x, q.y); // Populate basic columns. @@ -192,13 +226,13 @@ impl MachineAir for Ed } } -impl BaseAir for EdAddAssignChip { +impl + EdwardsParameters> BaseAir for EdAddAssignChip { fn width(&self) -> usize { NUM_ED_ADD_COLS } } -impl Air for EdAddAssignChip +impl + EdwardsParameters> Air for EdAddAssignChip where AB: SP1AirBuilder, { @@ -213,40 +247,80 @@ where // x3_numerator = x1 * y2 + x2 * y1. row.x3_numerator - .eval::(builder, &[x1, x2], &[y2, y1]); + .eval::>::BaseField>( + builder, + &[x1, x2], + &[y2, y1], + ); // y3_numerator = y1 * y2 + x1 * x2. row.y3_numerator - .eval::(builder, &[y1, x1], &[y2, x2]); + .eval::>::BaseField>( + builder, + &[y1, x1], + &[y2, x2], + ); // f = x1 * x2 * y1 * y2. row.x1_mul_y1 - .eval::(builder, &x1, &y1, FieldOperation::Mul); + .eval::>::BaseField, _, _>( + builder, + &x1, + &y1, + FieldOperation::Mul, + ); row.x2_mul_y2 - .eval::(builder, &x2, &y2, FieldOperation::Mul); + .eval::>::BaseField, _, _>( + builder, + &x2, + &y2, + FieldOperation::Mul, + ); let x1_mul_y1 = row.x1_mul_y1.result; let x2_mul_y2 = row.x2_mul_y2.result; row.f - .eval::(builder, &x1_mul_y1, &x2_mul_y2, FieldOperation::Mul); + .eval::>::BaseField, _, _>( + builder, + &x1_mul_y1, + &x2_mul_y2, + FieldOperation::Mul, + ); // d * f. let f = row.f.result; let d_biguint = E::d_biguint(); - let d_const = E::BaseField::to_limbs_field::(&d_biguint); - let d_const_expr = Limbs::(d_const.0.map(|x| x.into())); + let d_const = >::BaseField::to_limbs_field::( + &d_biguint, + ); + let d_const_expr = Limbs::(d_const.0.map(|x| x.into())); row.d_mul_f - .eval::(builder, &f, &d_const_expr, FieldOperation::Mul); + .eval::>::BaseField, _, _>( + builder, + &f, + &d_const_expr, + FieldOperation::Mul, + ); let d_mul_f = row.d_mul_f.result; // x3 = x3_numerator / (1 + d * f). row.x3_ins - .eval::(builder, &row.x3_numerator.result, &d_mul_f, true); + .eval::>::BaseField>( + builder, + &row.x3_numerator.result, + &d_mul_f, + true, + ); // y3 = y3_numerator / (1 - d * f). row.y3_ins - .eval::(builder, &row.y3_numerator.result, &d_mul_f, false); + .eval::>::BaseField>( + builder, + &row.y3_numerator.result, + &d_mul_f, + false, + ); // Constraint self.p_access.value = [self.x3_ins.result, self.y3_ins.result] // This is to ensure that p_access is updated with the new value. diff --git a/core/src/syscall/precompiles/edwards/ed_decompress.rs b/core/src/syscall/precompiles/edwards/ed_decompress.rs index 5c5522f9e7..a45930447d 100644 --- a/core/src/syscall/precompiles/edwards/ed_decompress.rs +++ b/core/src/syscall/precompiles/edwards/ed_decompress.rs @@ -9,6 +9,7 @@ use crate::memory::MemoryWriteCols; use crate::operations::field::field_op::FieldOpCols; use crate::operations::field::field_op::FieldOperation; use crate::operations::field::field_sqrt::FieldSqrtCols; +use crate::operations::field::params::Limbs; use crate::runtime::ExecutionRecord; use crate::runtime::Syscall; use crate::syscall::precompiles::SyscallContext; @@ -17,6 +18,7 @@ use crate::utils::ec::edwards::ed25519::decompress; use crate::utils::ec::edwards::ed25519::ed25519_sqrt; use crate::utils::ec::edwards::EdwardsParameters; use crate::utils::ec::field::FieldParameters; +use crate::utils::ec::EllipticCurveParameters; use crate::utils::ec::COMPRESSED_POINT_BYTES; use crate::utils::ec::NUM_BYTES_FIELD_ELEMENT; use crate::utils::ec::NUM_WORDS_FIELD_ELEMENT; @@ -40,6 +42,8 @@ use p3_matrix::dense::RowMajorMatrix; use sp1_derive::AlignedBorrow; use std::fmt::Debug; +use super::{NUM_LIMBS, NUM_WITNESS_LIMBS}; + #[derive(Debug, Clone, Copy)] pub struct EdDecompressEvent { pub shard: u32, @@ -68,17 +72,17 @@ pub struct EdDecompressCols { pub ptr: T, pub x_access: [MemoryWriteCols; NUM_WORDS_FIELD_ELEMENT], pub y_access: [MemoryReadCols; NUM_WORDS_FIELD_ELEMENT], - pub(crate) yy: FieldOpCols, - pub(crate) u: FieldOpCols, - pub(crate) dyy: FieldOpCols, - pub(crate) v: FieldOpCols, - pub(crate) u_div_v: FieldOpCols, - pub(crate) x: FieldSqrtCols, - pub(crate) neg_x: FieldOpCols, + pub(crate) yy: FieldOpCols, + pub(crate) u: FieldOpCols, + pub(crate) dyy: FieldOpCols, + pub(crate) v: FieldOpCols, + pub(crate) u_div_v: FieldOpCols, + pub(crate) x: FieldSqrtCols, + pub(crate) neg_x: FieldOpCols, } impl EdDecompressCols { - pub fn populate( + pub fn populate, E: EdwardsParameters>( &mut self, event: EdDecompressEvent, record: &mut ExecutionRecord, @@ -99,7 +103,10 @@ impl EdDecompressCols { record.add_field_events(&new_field_events); } - fn populate_field_ops(&mut self, y: &BigUint) { + fn populate_field_ops, E: EdwardsParameters>( + &mut self, + y: &BigUint, + ) { let one = BigUint::one(); let yy = self.yy.populate::

(y, y, FieldOperation::Mul); let u = self.u.populate::

(&yy, &one, FieldOperation::Sub); @@ -115,7 +122,7 @@ impl EdDecompressCols { } impl EdDecompressCols { - pub fn eval, P: FieldParameters, E: EdwardsParameters>( + pub fn eval, P: FieldParameters, E: EdwardsParameters>( &self, builder: &mut AB, ) where @@ -126,7 +133,7 @@ impl EdDecompressCols { self.x_access[NUM_WORDS_FIELD_ELEMENT - 1].prev_value[WORD_SIZE - 1].into(); builder.assert_bool(sign.clone()); - let y = limbs_from_prev_access(&self.y_access); + let y: Limbs = limbs_from_prev_access(&self.y_access); self.yy .eval::(builder, &y, &y, FieldOperation::Mul); self.u.eval::( @@ -136,7 +143,9 @@ impl EdDecompressCols { FieldOperation::Sub, ); let d_biguint = E::d_biguint(); - let d_const = E::BaseField::to_limbs_field::(&d_biguint); + let d_const = >::BaseField::to_limbs_field::( + &d_biguint, + ); self.dyy .eval::(builder, &d_const, &self.yy.result, FieldOperation::Mul); self.v.eval::( @@ -178,7 +187,7 @@ impl EdDecompressCols { ); } - let x_limbs = limbs_from_access(&self.x_access); + let x_limbs: Limbs = limbs_from_access(&self.x_access); builder .when(self.is_real) .when(sign.clone()) @@ -287,7 +296,7 @@ impl MachineAir for EdDecompressChip = row.as_mut_slice().borrow_mut(); - cols.populate::(event, output); + cols.populate::<>::BaseField, E>(event, output); rows.push(row); } @@ -296,7 +305,9 @@ impl MachineAir for EdDecompressChip = row.as_mut_slice().borrow_mut(); let zero = BigUint::zero(); - cols.populate_field_ops::(&zero); + cols.populate_field_ops::<>::BaseField, E>( + &zero, + ); row }); @@ -320,7 +331,7 @@ where fn eval(&self, builder: &mut AB) { let main = builder.main(); let row: &EdDecompressCols = main.row_slice(0).borrow(); - row.eval::(builder); + row.eval::>::BaseField, E>(builder); } } diff --git a/core/src/syscall/precompiles/edwards/mod.rs b/core/src/syscall/precompiles/edwards/mod.rs index dadf241f78..4e38345292 100644 --- a/core/src/syscall/precompiles/edwards/mod.rs +++ b/core/src/syscall/precompiles/edwards/mod.rs @@ -3,3 +3,9 @@ mod ed_decompress; pub use ed_add::*; pub use ed_decompress::*; + +// The number of limbs in the field representation. +const NUM_LIMBS: usize = 32; + +/// The number of `u8` witness limbs in the field representation. +const NUM_WITNESS_LIMBS: usize = 2 * NUM_LIMBS - 2; diff --git a/core/src/syscall/precompiles/k256/decompress.rs b/core/src/syscall/precompiles/k256/decompress.rs index df2220bdc0..47180224c1 100644 --- a/core/src/syscall/precompiles/k256/decompress.rs +++ b/core/src/syscall/precompiles/k256/decompress.rs @@ -43,6 +43,8 @@ use p3_matrix::dense::RowMajorMatrix; use sp1_derive::AlignedBorrow; use std::fmt::Debug; +use super::NUM_LIMBS; + #[derive(Debug, Clone, Copy)] pub struct K256DecompressEvent { pub shard: u32, @@ -144,11 +146,11 @@ pub struct K256DecompressCols { pub ptr: T, pub x_access: [MemoryReadCols; NUM_WORDS_FIELD_ELEMENT], pub y_access: [MemoryReadWriteCols; NUM_WORDS_FIELD_ELEMENT], - pub(crate) x_2: FieldOpCols, - pub(crate) x_3: FieldOpCols, - pub(crate) x_3_plus_b: FieldOpCols, - pub(crate) y: FieldSqrtCols, - pub(crate) neg_y: FieldOpCols, + pub(crate) x_2: FieldOpCols, + pub(crate) x_3: FieldOpCols, + pub(crate) x_3_plus_b: FieldOpCols, + pub(crate) y: FieldSqrtCols, + pub(crate) neg_y: FieldOpCols, pub(crate) y_least_bits: [T; 8], } diff --git a/core/src/syscall/precompiles/k256/mod.rs b/core/src/syscall/precompiles/k256/mod.rs index 6557de6e00..2c0c353fc2 100644 --- a/core/src/syscall/precompiles/k256/mod.rs +++ b/core/src/syscall/precompiles/k256/mod.rs @@ -1,3 +1,6 @@ mod decompress; pub use decompress::*; + +// The number of limbs in the field representation. +const NUM_LIMBS: usize = 32; diff --git a/core/src/syscall/precompiles/mod.rs b/core/src/syscall/precompiles/mod.rs index afac749ffc..b920f06c06 100644 --- a/core/src/syscall/precompiles/mod.rs +++ b/core/src/syscall/precompiles/mod.rs @@ -1,9 +1,9 @@ pub mod blake3; pub mod edwards; -pub mod k256; +// pub mod k256; pub mod keccak256; pub mod sha256; -pub mod weierstrass; +// pub mod weierstrass; use num::BigUint; @@ -14,6 +14,9 @@ use crate::utils::ec::field::FieldParameters; use crate::utils::ec::{AffinePoint, EllipticCurve}; use crate::{cpu::MemoryReadRecord, cpu::MemoryWriteRecord}; +/// Number of `u8` limbs in the field representation. +const NUM_LIMBS: usize = 32; + /// Elliptic curve add event. #[derive(Debug, Clone, Copy)] pub struct ECAddEvent { @@ -28,7 +31,7 @@ pub struct ECAddEvent { pub q_memory_records: [MemoryReadRecord; 16], } -pub fn create_ec_add_event(rt: &mut SyscallContext) -> ECAddEvent { +pub fn create_ec_add_event>(rt: &mut SyscallContext) -> ECAddEvent { let a0 = crate::runtime::Register::X10; let a1 = crate::runtime::Register::X11; @@ -52,8 +55,8 @@ pub fn create_ec_add_event(rt: &mut SyscallContext) -> ECAddEv // When we write to p, we want the clk to be incremented. rt.clk += 4; - let p_affine = AffinePoint::::from_words_le(&p); - let q_affine = AffinePoint::::from_words_le(&q); + let p_affine = AffinePoint::::from_words_le(&p); + let q_affine = AffinePoint::::from_words_le(&q); let result_affine = p_affine + q_affine; let result_words = result_affine.to_words_le(); @@ -84,7 +87,9 @@ pub struct ECDoubleEvent { pub p_memory_records: [MemoryWriteRecord; 16], } -pub fn create_ec_double_event(rt: &mut SyscallContext) -> ECDoubleEvent { +pub fn create_ec_double_event>( + rt: &mut SyscallContext, +) -> ECDoubleEvent { let a0 = crate::runtime::Register::X10; let start_clk = rt.clk; @@ -100,7 +105,7 @@ pub fn create_ec_double_event(rt: &mut SyscallContext) -> ECDo // When we write to p, we want the clk to be incremented. rt.clk += 4; - let p_affine = AffinePoint::::from_words_le(&p); + let p_affine = AffinePoint::::from_words_le(&p); let result_affine = E::ec_double(&p_affine); let result_words = result_affine.to_words_le(); @@ -117,10 +122,12 @@ pub fn create_ec_double_event(rt: &mut SyscallContext) -> ECDo } } -pub fn limbs_from_biguint(value: &BigUint) -> Limbs +pub fn limbs_from_biguint>( + value: &BigUint, +) -> Limbs where AB: SP1AirBuilder, { let a_const = F::to_limbs_field::(value); - Limbs::(a_const.0.map(|x| x.into())) + Limbs::(a_const.0.map(|x| x.into())) } diff --git a/core/src/syscall/precompiles/weierstrass/mod.rs b/core/src/syscall/precompiles/weierstrass/mod.rs index 3d397634e5..02257fe555 100644 --- a/core/src/syscall/precompiles/weierstrass/mod.rs +++ b/core/src/syscall/precompiles/weierstrass/mod.rs @@ -3,3 +3,6 @@ mod weierstrass_double; pub use weierstrass_add::*; pub use weierstrass_double::*; + +// The number of `u8` limbs in the field representation. +const NUM_LIMBS: usize = 32; diff --git a/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs b/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs index 732a4c794d..dafef6c4b6 100644 --- a/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs +++ b/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs @@ -5,7 +5,6 @@ use crate::memory::MemoryReadCols; use crate::memory::MemoryWriteCols; use crate::operations::field::field_op::FieldOpCols; use crate::operations::field::field_op::FieldOperation; -use crate::operations::field::params::NUM_LIMBS; use crate::runtime::ExecutionRecord; use crate::runtime::Register; use crate::runtime::Syscall; @@ -32,6 +31,8 @@ use sp1_derive::AlignedBorrow; use std::fmt::Debug; use std::marker::PhantomData; +use super::NUM_LIMBS; + pub const NUM_WEIERSTRASS_ADD_COLS: usize = size_of::>(); /// A set of columns to compute `WeierstrassAdd` that add two points on a Weierstrass curve. @@ -49,15 +50,15 @@ pub struct WeierstrassAddAssignCols { pub q_ptr_access: MemoryReadCols, pub p_access: [MemoryWriteCols; NUM_WORDS_EC_POINT], pub q_access: [MemoryReadCols; NUM_WORDS_EC_POINT], - pub(crate) slope_denominator: FieldOpCols, - pub(crate) slope_numerator: FieldOpCols, - pub(crate) slope: FieldOpCols, - pub(crate) slope_squared: FieldOpCols, - pub(crate) p_x_plus_q_x: FieldOpCols, - pub(crate) x3_ins: FieldOpCols, - pub(crate) p_x_minus_x: FieldOpCols, - pub(crate) y3_ins: FieldOpCols, - pub(crate) slope_times_p_x_minus_x: FieldOpCols, + pub(crate) slope_denominator: FieldOpCols, + pub(crate) slope_numerator: FieldOpCols, + pub(crate) slope: FieldOpCols, + pub(crate) slope_squared: FieldOpCols, + pub(crate) p_x_plus_q_x: FieldOpCols, + pub(crate) x3_ins: FieldOpCols, + pub(crate) p_x_minus_x: FieldOpCols, + pub(crate) y3_ins: FieldOpCols, + pub(crate) slope_times_p_x_minus_x: FieldOpCols, } #[derive(Default)] @@ -65,7 +66,7 @@ pub struct WeierstrassAddAssignChip { _marker: PhantomData, } -impl Syscall for WeierstrassAddAssignChip { +impl> Syscall for WeierstrassAddAssignChip { fn execute(&self, rt: &mut SyscallContext) -> u32 { let event = create_ec_add_event::(rt); rt.record_mut().weierstrass_add_events.push(event); @@ -77,7 +78,7 @@ impl Syscall for WeierstrassAddAssignChip { } } -impl WeierstrassAddAssignChip { +impl> WeierstrassAddAssignChip { pub fn new() -> Self { Self { _marker: PhantomData, @@ -142,7 +143,7 @@ impl WeierstrassAddAssignChip { } } -impl MachineAir +impl + WeierstrassParameters> MachineAir for WeierstrassAddAssignChip { fn name(&self) -> String { @@ -166,9 +167,9 @@ impl MachineAir // Decode affine points. let p = &event.p; let q = &event.q; - let p = AffinePoint::::from_words_le(p); + let p = AffinePoint::::from_words_le(p); let (p_x, p_y) = (p.x, p.y); - let q = AffinePoint::::from_words_le(q); + let q = AffinePoint::::from_words_le(q); let (q_x, q_y) = (q.x, q.y); // Populate basic columns. @@ -210,13 +211,13 @@ impl MachineAir } } -impl BaseAir for WeierstrassAddAssignChip { +impl> BaseAir for WeierstrassAddAssignChip { fn width(&self) -> usize { NUM_WEIERSTRASS_ADD_COLS } } -impl Air for WeierstrassAddAssignChip +impl> Air for WeierstrassAddAssignChip where AB: SP1AirBuilder, { diff --git a/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs b/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs index ced770596d..e24284c1ae 100644 --- a/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs +++ b/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs @@ -4,7 +4,6 @@ use crate::memory::MemoryCols; use crate::memory::MemoryWriteCols; use crate::operations::field::field_op::FieldOpCols; use crate::operations::field::field_op::FieldOperation; -use crate::operations::field::params::NUM_LIMBS; use crate::runtime::ExecutionRecord; use crate::runtime::Syscall; use crate::syscall::precompiles::create_ec_double_event; @@ -31,6 +30,8 @@ use sp1_derive::AlignedBorrow; use std::fmt::Debug; use std::marker::PhantomData; +use super::NUM_LIMBS; + pub const NUM_WEIERSTRASS_DOUBLE_COLS: usize = size_of::>(); /// A set of columns to double a point on a Weierstrass curve. @@ -45,17 +46,17 @@ pub struct WeierstrassDoubleAssignCols { pub clk: T, pub p_ptr: T, pub p_access: [MemoryWriteCols; NUM_WORDS_EC_POINT], - pub(crate) slope_denominator: FieldOpCols, - pub(crate) slope_numerator: FieldOpCols, - pub(crate) slope: FieldOpCols, - pub(crate) p_x_squared: FieldOpCols, - pub(crate) p_x_squared_times_3: FieldOpCols, - pub(crate) slope_squared: FieldOpCols, - pub(crate) p_x_plus_p_x: FieldOpCols, - pub(crate) x3_ins: FieldOpCols, - pub(crate) p_x_minus_x: FieldOpCols, - pub(crate) y3_ins: FieldOpCols, - pub(crate) slope_times_p_x_minus_x: FieldOpCols, + pub(crate) slope_denominator: FieldOpCols, + pub(crate) slope_numerator: FieldOpCols, + pub(crate) slope: FieldOpCols, + pub(crate) p_x_squared: FieldOpCols, + pub(crate) p_x_squared_times_3: FieldOpCols, + pub(crate) slope_squared: FieldOpCols, + pub(crate) p_x_plus_p_x: FieldOpCols, + pub(crate) x3_ins: FieldOpCols, + pub(crate) p_x_minus_x: FieldOpCols, + pub(crate) y3_ins: FieldOpCols, + pub(crate) slope_times_p_x_minus_x: FieldOpCols, } #[derive(Default)] @@ -63,7 +64,9 @@ pub struct WeierstrassDoubleAssignChip { _marker: PhantomData, } -impl Syscall for WeierstrassDoubleAssignChip { +impl + WeierstrassParameters> Syscall + for WeierstrassDoubleAssignChip +{ fn execute(&self, rt: &mut SyscallContext) -> u32 { let event = create_ec_double_event::(rt); rt.record_mut().weierstrass_double_events.push(event); @@ -75,7 +78,9 @@ impl Syscall for WeierstrassDoubleAssi } } -impl WeierstrassDoubleAssignChip { +impl + WeierstrassParameters> + WeierstrassDoubleAssignChip +{ pub fn new() -> Self { Self { _marker: PhantomData, @@ -155,7 +160,7 @@ impl WeierstrassDoubleAssignChip { } } -impl MachineAir +impl + WeierstrassParameters> MachineAir for WeierstrassDoubleAssignChip { fn name(&self) -> String { @@ -178,7 +183,7 @@ impl MachineAir // Decode affine points. let p = &event.p; - let p = AffinePoint::::from_words_le(p); + let p = AffinePoint::::from_words_le(p); let (p_x, p_y) = (p.x, p.y); // Populate basic columns. @@ -214,13 +219,16 @@ impl MachineAir } } -impl BaseAir for WeierstrassDoubleAssignChip { +impl + WeierstrassParameters> BaseAir + for WeierstrassDoubleAssignChip +{ fn width(&self) -> usize { NUM_WEIERSTRASS_DOUBLE_COLS } } -impl Air for WeierstrassDoubleAssignChip +impl + WeierstrassParameters> Air + for WeierstrassDoubleAssignChip where AB: SP1AirBuilder, { diff --git a/core/src/utils/ec/edwards/ed25519.rs b/core/src/utils/ec/edwards/ed25519.rs index 01f99e3b58..b9fa271408 100644 --- a/core/src/utils/ec/edwards/ed25519.rs +++ b/core/src/utils/ec/edwards/ed25519.rs @@ -3,7 +3,8 @@ use num::{BigUint, Num, One}; use serde::{Deserialize, Serialize}; use std::str::FromStr; -use crate::operations::field::params::{NB_BITS_PER_LIMB, NUM_LIMBS}; +use super::NUM_LIMBS; +use crate::operations::field::params::NB_BITS_PER_LIMB; use crate::utils::ec::edwards::{EdwardsCurve, EdwardsParameters}; use crate::utils::ec::field::{FieldParameters, MAX_NB_LIMBS}; use crate::utils::ec::{AffinePoint, EllipticCurveParameters}; @@ -16,7 +17,7 @@ pub struct Ed25519Parameters; #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] pub struct Ed25519BaseField; -impl FieldParameters for Ed25519BaseField { +impl FieldParameters for Ed25519BaseField { const NB_BITS_PER_LIMB: usize = NB_BITS_PER_LIMB; const NB_LIMBS: usize = NUM_LIMBS; const NB_WITNESS_LIMBS: usize = 2 * Self::NB_LIMBS - 2; @@ -31,7 +32,7 @@ impl FieldParameters for Ed25519BaseField { } } -impl EllipticCurveParameters for Ed25519Parameters { +impl EllipticCurveParameters for Ed25519Parameters { type BaseField = Ed25519BaseField; } @@ -105,7 +106,7 @@ pub fn ed25519_sqrt(a: &BigUint) -> BigUint { beta } -pub fn decompress(compressed_point: &CompressedEdwardsY) -> AffinePoint { +pub fn decompress(compressed_point: &CompressedEdwardsY) -> AffinePoint { let mut point_bytes = *compressed_point.as_bytes(); let sign = point_bytes[31] >> 7 == 1; // mask out the sign bit @@ -146,7 +147,7 @@ mod tests { // Get the generator point. let mut point = { let (x, y) = Ed25519Parameters::generator(); - AffinePoint::>::new(x, y) + AffinePoint::, NUM_LIMBS>::new(x, y) }; for _ in 0..NUM_TEST_CASES { // Compress the point. The first 255 bits of a compressed point is the y-coordinate. The diff --git a/core/src/utils/ec/edwards/mod.rs b/core/src/utils/ec/edwards/mod.rs index b608231d3d..5a3f5c94dd 100644 --- a/core/src/utils/ec/edwards/mod.rs +++ b/core/src/utils/ec/edwards/mod.rs @@ -6,7 +6,9 @@ use serde::{Deserialize, Serialize}; use crate::utils::ec::field::{FieldParameters, MAX_NB_LIMBS}; use crate::utils::ec::{AffinePoint, EllipticCurve, EllipticCurveParameters}; -pub trait EdwardsParameters: EllipticCurveParameters { +// The number of `u8` limbs in the base field of Ed25519. +const NUM_LIMBS: usize = 32; +pub trait EdwardsParameters: EllipticCurveParameters { const D: [u16; MAX_NB_LIMBS]; fn generator() -> (BigUint, BigUint); @@ -50,7 +52,7 @@ impl EdwardsParameters for EdwardsCurve { } } -impl EllipticCurveParameters for EdwardsCurve { +impl EllipticCurveParameters for EdwardsCurve { type BaseField = E::BaseField; } @@ -59,42 +61,45 @@ impl EdwardsCurve { E::prime_group_order() } - pub fn neutral() -> AffinePoint { + pub fn neutral() -> AffinePoint { let (x, y) = E::neutral(); AffinePoint::new(x, y) } } -impl EllipticCurve for EdwardsCurve { - fn ec_add(p: &AffinePoint, q: &AffinePoint) -> AffinePoint { +impl EllipticCurve for EdwardsCurve { + fn ec_add( + p: &AffinePoint, + q: &AffinePoint, + ) -> AffinePoint { p.ed_add(q) } - fn ec_double(p: &AffinePoint) -> AffinePoint { + fn ec_double(p: &AffinePoint) -> AffinePoint { p.ed_double() } - fn ec_generator() -> AffinePoint { + fn ec_generator() -> AffinePoint { let (x, y) = E::generator(); AffinePoint::new(x, y) } - fn ec_neutral() -> Option> { + fn ec_neutral() -> Option> { Some(Self::neutral()) } - fn ec_neg(p: &AffinePoint) -> AffinePoint { - let modulus = E::BaseField::modulus(); + fn ec_neg(p: &AffinePoint) -> AffinePoint { + let modulus = >::BaseField::modulus(); AffinePoint::new(&modulus - &p.x, p.y.clone()) } } -impl AffinePoint> { +impl AffinePoint, NUM_LIMBS> { pub(crate) fn ed_add( &self, - other: &AffinePoint>, - ) -> AffinePoint> { - let p = E::BaseField::modulus(); + other: &AffinePoint, NUM_LIMBS>, + ) -> AffinePoint, NUM_LIMBS> { + let p = >::BaseField::modulus(); let x_3n = (&self.x * &other.y + &self.y * &other.x) % &p; let y_3n = (&self.y * &other.y + &self.x * &other.x) % &p; @@ -110,7 +115,7 @@ impl AffinePoint> { AffinePoint::new(x_3, y_3) } - pub(crate) fn ed_double(&self) -> AffinePoint> { + pub(crate) fn ed_double(&self) -> AffinePoint, NUM_LIMBS> { self.ed_add(self) } } @@ -143,7 +148,7 @@ mod tests { let base = E::ec_generator(); let d = Ed25519Parameters::d_biguint(); - let p = ::BaseField::modulus(); + let p = >::BaseField::modulus(); assert_eq!((d * 121666u32) % &p, (&p - 121665u32) % &p); let mut rng = thread_rng(); diff --git a/core/src/utils/ec/field.rs b/core/src/utils/ec/field.rs index 2cff8134b9..bfbf16d828 100644 --- a/core/src/utils/ec/field.rs +++ b/core/src/utils/ec/field.rs @@ -1,7 +1,6 @@ use super::utils::biguint_from_limbs; use crate::operations::field::params::Limbs; use crate::operations::field::params::NB_BITS_PER_LIMB; -use crate::operations::field::params::NUM_LIMBS; use num::BigUint; use p3_field::Field; use serde::{de::DeserializeOwned, Serialize}; @@ -9,7 +8,7 @@ use std::fmt::Debug; pub const MAX_NB_LIMBS: usize = 32; -pub trait FieldParameters: +pub trait FieldParameters: Send + Sync + Copy + 'static + Debug + Serialize + DeserializeOwned { const NB_BITS_PER_LIMB: usize = NB_BITS_PER_LIMB; @@ -33,7 +32,7 @@ pub trait FieldParameters: .take(Self::NB_LIMBS) } - fn to_limbs(x: &BigUint) -> Limbs { + fn to_limbs(x: &BigUint) -> Limbs { let mut bytes = x.to_bytes_le(); bytes.resize(NUM_LIMBS, 0u8); let mut limbs = [0u8; NUM_LIMBS]; @@ -41,7 +40,7 @@ pub trait FieldParameters: Limbs(limbs) } - fn to_limbs_field(x: &BigUint) -> Limbs { + fn to_limbs_field(x: &BigUint) -> Limbs { Limbs( Self::to_limbs(x) .0 diff --git a/core/src/utils/ec/mod.rs b/core/src/utils/ec/mod.rs index 55bae646ec..b10cf45070 100644 --- a/core/src/utils/ec/mod.rs +++ b/core/src/utils/ec/mod.rs @@ -2,7 +2,7 @@ pub mod edwards; pub mod field; pub mod scalar_mul; pub mod utils; -pub mod weierstrass; +// pub mod weierstrass; use field::FieldParameters; use num::BigUint; @@ -11,7 +11,6 @@ use std::fmt::Debug; use std::ops::{Add, Neg}; use crate::air::WORD_SIZE; -use crate::operations::field::params::NUM_LIMBS; pub const NUM_WORDS_FIELD_ELEMENT: usize = 8; pub const NUM_BYTES_FIELD_ELEMENT: usize = NUM_WORDS_FIELD_ELEMENT * WORD_SIZE; @@ -22,13 +21,13 @@ pub const COMPRESSED_POINT_BYTES: usize = 32; pub const NUM_WORDS_EC_POINT: usize = 2 * NUM_WORDS_FIELD_ELEMENT; #[derive(Debug, Clone, PartialEq, Eq)] -pub struct AffinePoint { +pub struct AffinePoint { pub x: BigUint, pub y: BigUint, _marker: std::marker::PhantomData, } -impl AffinePoint { +impl AffinePoint { #[allow(dead_code)] pub fn new(x: BigUint, y: BigUint) -> Self { Self { @@ -58,9 +57,9 @@ impl AffinePoint { pub fn to_words_le(&self) -> [u32; 16] { let mut x_bytes = self.x.to_bytes_le(); - x_bytes.resize(NUM_LIMBS, 0u8); + x_bytes.resize(N, 0u8); let mut y_bytes = self.y.to_bytes_le(); - y_bytes.resize(NUM_LIMBS, 0u8); + y_bytes.resize(N, 0u8); let mut words = [0u32; 16]; for i in 0..8 { @@ -81,31 +80,31 @@ impl AffinePoint { } } -pub trait EllipticCurveParameters: +pub trait EllipticCurveParameters: Debug + Send + Sync + Copy + Serialize + DeserializeOwned + 'static { - type BaseField: FieldParameters; + type BaseField: FieldParameters; } /// An interface for elliptic curve groups. -pub trait EllipticCurve: EllipticCurveParameters { +pub trait EllipticCurve: EllipticCurveParameters { /// Adds two different points on the curve. /// /// Warning: This method assumes that the two points are different. - fn ec_add(p: &AffinePoint, q: &AffinePoint) -> AffinePoint; + fn ec_add(p: &AffinePoint, q: &AffinePoint) -> AffinePoint; /// Doubles a point on the curve. - fn ec_double(p: &AffinePoint) -> AffinePoint; + fn ec_double(p: &AffinePoint) -> AffinePoint; /// Returns the generator of the curve group for a curve/subgroup of prime order. - fn ec_generator() -> AffinePoint; + fn ec_generator() -> AffinePoint; /// Returns the neutral element of the curve group, if this element is affine (such as in the /// case of the Edwards curve group). Otherwise, returns `None`. - fn ec_neutral() -> Option>; + fn ec_neutral() -> Option>; /// Returns the negative of a point on the curve. - fn ec_neg(p: &AffinePoint) -> AffinePoint; + fn ec_neg(p: &AffinePoint) -> AffinePoint; /// Returns the number of bits needed to represent a scalar in the group. fn nb_scalar_bits() -> usize { @@ -113,42 +112,42 @@ pub trait EllipticCurve: EllipticCurveParameters { } } -impl Add<&AffinePoint> for &AffinePoint { - type Output = AffinePoint; +impl, const N: usize> Add<&AffinePoint> for &AffinePoint { + type Output = AffinePoint; - fn add(self, other: &AffinePoint) -> AffinePoint { + fn add(self, other: &AffinePoint) -> AffinePoint { E::ec_add(self, other) } } -impl Add> for AffinePoint { - type Output = AffinePoint; +impl, const N: usize> Add> for AffinePoint { + type Output = AffinePoint; - fn add(self, other: AffinePoint) -> AffinePoint { + fn add(self, other: AffinePoint) -> AffinePoint { &self + &other } } -impl Add<&AffinePoint> for AffinePoint { - type Output = AffinePoint; +impl, const N: usize> Add<&AffinePoint> for AffinePoint { + type Output = AffinePoint; - fn add(self, other: &AffinePoint) -> AffinePoint { + fn add(self, other: &AffinePoint) -> AffinePoint { &self + other } } -impl Neg for &AffinePoint { - type Output = AffinePoint; +impl, const N: usize> Neg for &AffinePoint { + type Output = AffinePoint; - fn neg(self) -> AffinePoint { + fn neg(self) -> AffinePoint { E::ec_neg(self) } } -impl Neg for AffinePoint { - type Output = AffinePoint; +impl, const N: usize> Neg for AffinePoint { + type Output = AffinePoint; - fn neg(self) -> AffinePoint { + fn neg(self) -> AffinePoint { -&self } } diff --git a/core/src/utils/ec/scalar_mul.rs b/core/src/utils/ec/scalar_mul.rs index 098b11fc51..53aca8733d 100644 --- a/core/src/utils/ec/scalar_mul.rs +++ b/core/src/utils/ec/scalar_mul.rs @@ -6,7 +6,7 @@ use super::utils::biguint_to_bits_le; use super::AffinePoint; use super::EllipticCurve; -impl AffinePoint { +impl, const N: usize> AffinePoint { pub fn scalar_mul(&self, scalar: &BigUint) -> Self { let power_two_modulus = BigUint::one() << E::nb_scalar_bits(); let scalar = scalar % &power_two_modulus; @@ -23,26 +23,26 @@ impl AffinePoint { } } -impl Mul<&BigUint> for &AffinePoint { - type Output = AffinePoint; +impl, const N: usize> Mul<&BigUint> for &AffinePoint { + type Output = AffinePoint; - fn mul(self, scalar: &BigUint) -> AffinePoint { + fn mul(self, scalar: &BigUint) -> AffinePoint { self.scalar_mul(scalar) } } -impl Mul for &AffinePoint { - type Output = AffinePoint; +impl, const N: usize> Mul for &AffinePoint { + type Output = AffinePoint; - fn mul(self, scalar: BigUint) -> AffinePoint { + fn mul(self, scalar: BigUint) -> AffinePoint { self.scalar_mul(&scalar) } } -impl Mul for AffinePoint { - type Output = AffinePoint; +impl, const N: usize> Mul for AffinePoint { + type Output = AffinePoint; - fn mul(self, scalar: BigUint) -> AffinePoint { + fn mul(self, scalar: BigUint) -> AffinePoint { self.scalar_mul(&scalar) } } diff --git a/core/src/utils/ec/utils.rs b/core/src/utils/ec/utils.rs index 834e112fdb..523fa8b10b 100644 --- a/core/src/utils/ec/utils.rs +++ b/core/src/utils/ec/utils.rs @@ -1,7 +1,5 @@ use num::BigUint; -use crate::operations::field::params::NUM_LIMBS; - pub fn biguint_to_bits_le(integer: &BigUint, num_bits: usize) -> Vec { let byte_vec = integer.to_bytes_le(); let mut bits = Vec::new(); @@ -18,14 +16,11 @@ pub fn biguint_to_bits_le(integer: &BigUint, num_bits: usize) -> Vec { bits } -pub fn biguint_to_limbs(integer: &BigUint) -> [u8; NUM_LIMBS] { +pub fn biguint_to_limbs(integer: &BigUint) -> [u8; N] { let mut bytes = integer.to_bytes_le(); - debug_assert!( - bytes.len() <= NUM_LIMBS, - "Number too large to fit in {NUM_LIMBS} limbs" - ); - bytes.resize(NUM_LIMBS, 0u8); - let mut limbs = [0u8; NUM_LIMBS]; + debug_assert!(bytes.len() <= N, "Number too large to fit in {N} limbs"); + bytes.resize(N, 0u8); + let mut limbs = [0u8; N]; limbs.copy_from_slice(&bytes); limbs } diff --git a/core/src/utils/ec/weierstrass/bn254.rs b/core/src/utils/ec/weierstrass/bn254.rs index a84c172672..6c66a9e1a1 100644 --- a/core/src/utils/ec/weierstrass/bn254.rs +++ b/core/src/utils/ec/weierstrass/bn254.rs @@ -5,24 +5,26 @@ use super::{SwCurve, WeierstrassParameters}; use crate::utils::ec::field::{FieldParameters, MAX_NB_LIMBS}; use crate::utils::ec::EllipticCurveParameters; +const NUM_LIMBS: usize = 16; + #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] /// Bn254 curve parameter pub struct Bn254Parameters; -pub type Bn254 = SwCurve; +pub type Bn254 = SwCurve; #[derive(Debug, Default, Clone, Copy, PartialEq, Serialize, Deserialize)] /// Bn254 base field parameter pub struct Bn254BaseField; -impl FieldParameters for Bn254BaseField { +impl FieldParameters for Bn254BaseField { const NB_BITS_PER_LIMB: usize = 16; - const NB_LIMBS: usize = 16; + const NB_LIMBS: usize = NUM_LIMBS; const NB_WITNESS_LIMBS: usize = 2 * Self::NB_LIMBS - 2; - const MODULUS: [u8; MAX_NB_LIMBS] = [ + const MODULUS: [u8; 16] = [ 71, 253, 124, 216, 22, 140, 32, 60, 141, 202, 113, 104, 145, 106, 129, 151, 93, 88, 129, 129, 182, 69, 80, 184, 41, 160, 49, 225, 114, 78, 100, 48, ]; @@ -38,11 +40,11 @@ impl FieldParameters for Bn254BaseField { } } -impl EllipticCurveParameters for Bn254Parameters { +impl EllipticCurveParameters for Bn254Parameters { type BaseField = Bn254BaseField; } -impl WeierstrassParameters for Bn254Parameters { +impl WeierstrassParameters for Bn254Parameters { const A: [u16; MAX_NB_LIMBS] = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, diff --git a/core/src/utils/ec/weierstrass/mod.rs b/core/src/utils/ec/weierstrass/mod.rs index 17f2a97ed4..d8a9b8fcdb 100644 --- a/core/src/utils/ec/weierstrass/mod.rs +++ b/core/src/utils/ec/weierstrass/mod.rs @@ -9,7 +9,7 @@ pub mod bn254; pub mod secp256k1; /// Parameters that specify a short Weierstrass curve : y^2 = x^3 + ax + b. -pub trait WeierstrassParameters: EllipticCurveParameters { +pub trait WeierstrassParameters: EllipticCurveParameters { const A: [u16; MAX_NB_LIMBS]; const B: [u16; MAX_NB_LIMBS]; @@ -39,9 +39,9 @@ pub trait WeierstrassParameters: EllipticCurveParameters { } #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] -pub struct SwCurve(pub E); +pub struct SwCurve(pub E); -impl WeierstrassParameters for SwCurve { +impl, const N: usize> WeierstrassParameters for SwCurve { const A: [u16; MAX_NB_LIMBS] = E::A; const B: [u16; MAX_NB_LIMBS] = E::B; @@ -66,36 +66,36 @@ impl WeierstrassParameters for SwCurve { } } -impl EllipticCurveParameters for SwCurve { +impl, const N: usize> EllipticCurveParameters for SwCurve { type BaseField = E::BaseField; } -impl EllipticCurve for SwCurve { - fn ec_add(p: &AffinePoint, q: &AffinePoint) -> AffinePoint { +impl, const N: usize> EllipticCurve for SwCurve { + fn ec_add(p: &AffinePoint, q: &AffinePoint) -> AffinePoint { p.sw_add(q) } - fn ec_double(p: &AffinePoint) -> AffinePoint { + fn ec_double(p: &AffinePoint) -> AffinePoint { p.sw_double() } - fn ec_generator() -> AffinePoint { + fn ec_generator() -> AffinePoint { let (x, y) = E::generator(); AffinePoint::new(x, y) } - fn ec_neutral() -> Option> { + fn ec_neutral() -> Option> { None } - fn ec_neg(p: &AffinePoint) -> AffinePoint { + fn ec_neg(p: &AffinePoint) -> AffinePoint { let modulus = E::BaseField::modulus(); AffinePoint::new(p.x.clone(), modulus - &p.y) } } -impl SwCurve { - pub fn generator() -> AffinePoint> { +impl, const N: usize> SwCurve { + pub fn generator() -> AffinePoint, N> { let (x, y) = E::generator(); AffinePoint::new(x, y) @@ -110,7 +110,7 @@ impl SwCurve { } } -impl AffinePoint> { +impl, const N: usize> AffinePoint, N> { pub fn sw_scalar_mul(&self, scalar: &BigUint) -> Self { let mut result: Option>> = None; let mut temp = self.clone(); @@ -125,8 +125,8 @@ impl AffinePoint> { } } -impl AffinePoint> { - pub fn sw_add(&self, other: &AffinePoint>) -> AffinePoint> { +impl, const N: usize> AffinePoint, N> { + pub fn sw_add(&self, other: &AffinePoint, N>) -> AffinePoint, N> { if self.x == other.x && self.y == other.y { panic!("Error: Points are the same. Use sw_double instead."); } @@ -142,7 +142,7 @@ impl AffinePoint> { AffinePoint::new(x_3n, y_3n) } - pub fn sw_double(&self) -> AffinePoint> { + pub fn sw_double(&self) -> AffinePoint, N> { let p = E::BaseField::modulus(); let a = E::a_int(); let slope_numerator = (&a + &(&self.x * &self.x) * 3u32) % &p; diff --git a/core/src/utils/ec/weierstrass/secp256k1.rs b/core/src/utils/ec/weierstrass/secp256k1.rs index 4ebcc49719..2c8ada81a0 100644 --- a/core/src/utils/ec/weierstrass/secp256k1.rs +++ b/core/src/utils/ec/weierstrass/secp256k1.rs @@ -7,24 +7,27 @@ use num::{BigUint, Zero}; use serde::{Deserialize, Serialize}; use super::{SwCurve, WeierstrassParameters}; -use crate::operations::field::params::{NB_BITS_PER_LIMB, NUM_LIMBS}; +use crate::operations::field::params::NB_BITS_PER_LIMB; use crate::utils::ec::field::{FieldParameters, MAX_NB_LIMBS}; use crate::utils::ec::EllipticCurveParameters; use k256::FieldElement; use num::traits::FromBytes; use num::traits::ToBytes; +/// Number of `u8` limbs in the base field of Secp256k1. +const NUM_LIMBS: usize = 32; + #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] /// Secp256k1 curve parameter pub struct Secp256k1Parameters; -pub type Secp256k1 = SwCurve; +pub type Secp256k1 = SwCurve; #[derive(Debug, Default, Clone, Copy, PartialEq, Serialize, Deserialize)] /// Secp256k1 base field parameter pub struct Secp256k1BaseField; -impl FieldParameters for Secp256k1BaseField { +impl FieldParameters for Secp256k1BaseField { const NB_BITS_PER_LIMB: usize = NB_BITS_PER_LIMB; const NB_LIMBS: usize = NUM_LIMBS; @@ -45,11 +48,11 @@ impl FieldParameters for Secp256k1BaseField { } } -impl EllipticCurveParameters for Secp256k1Parameters { +impl EllipticCurveParameters for Secp256k1Parameters { type BaseField = Secp256k1BaseField; } -impl WeierstrassParameters for Secp256k1Parameters { +impl WeierstrassParameters for Secp256k1Parameters { const A: [u16; MAX_NB_LIMBS] = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, diff --git a/core/src/utils/mod.rs b/core/src/utils/mod.rs index 3efd0cba4d..8581c3b33d 100644 --- a/core/src/utils/mod.rs +++ b/core/src/utils/mod.rs @@ -36,7 +36,9 @@ pub fn pad_to_power_of_two(values: &mut Vec< values.resize(n_real_rows.next_power_of_two() * N, T::default()); } -pub fn limbs_from_prev_access>(cols: &[M]) -> Limbs { +pub fn limbs_from_prev_access>( + cols: &[M], +) -> Limbs { let vec = cols .iter() .flat_map(|access| access.prev_value().0) @@ -48,7 +50,7 @@ pub fn limbs_from_prev_access>(cols: &[M]) -> Limbs Limbs(sized) } -pub fn limbs_from_access>(cols: &[M]) -> Limbs { +pub fn limbs_from_access>(cols: &[M]) -> Limbs { let vec = cols .iter() .flat_map(|access| access.value().0) diff --git a/derive/src/lib.rs b/derive/src/lib.rs index 8c15dcac6b..59f50a373c 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -57,6 +57,39 @@ pub fn aligned_borrow_derive(input: TokenStream) -> TokenStream { } } }; + + methods.into() +} + +#[proc_macro_derive(AlignedBorrowWithGenerics)] +pub fn aligned_borrow_derive_with_generics(input: TokenStream) -> TokenStream { + let ast: syn::DeriveInput = syn::parse(input).unwrap(); + + // Get struct name from ast + let name = &ast.ident; + + let methods = quote! { + impl Borrow<#name> for [T] { + fn borrow(&self) -> &#name { + debug_assert_eq!(self.len(), std::mem::size_of::<#name>()); + let (prefix, shorts, _suffix) = unsafe { self.align_to::<#name>() }; + debug_assert!(prefix.is_empty(), "Alignment should match"); + debug_assert_eq!(shorts.len(), 1); + &shorts[0] + } + } + + impl BorrowMut<#name> for [T] { + fn borrow_mut(&mut self) -> &mut #name { + debug_assert_eq!(self.len(), std::mem::size_of::<#name>()); + let (prefix, shorts, _suffix) = unsafe { self.align_to_mut::<#name>() }; + debug_assert!(prefix.is_empty(), "Alignment should match"); + debug_assert_eq!(shorts.len(), 1); + &mut shorts[0] + } + } + }; + methods.into() } diff --git a/examples/fibonacci-io/program/elf/riscv32im-succinct-zkvm-elf b/examples/fibonacci-io/program/elf/riscv32im-succinct-zkvm-elf index 85564becf2a7f9b9f04d592ef72ed89849a20488..165c337f15cd3e611d7985d4dcd3a5d366186566 100755 GIT binary patch literal 117804 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%0D1Rw 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 literal 102912 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 QjlbMz{Krr988zSk0vdcuP5=M^ diff --git a/tests/ed-add/Cargo.lock b/tests/ed-add/Cargo.lock index 7c8fe2381e..8a404b5ace 100644 --- a/tests/ed-add/Cargo.lock +++ b/tests/ed-add/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "anyhow" -version = "1.0.79" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" +checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" [[package]] name = "autocfg" @@ -270,28 +270,27 @@ dependencies = [ [[package]] name = "num-complex" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214" +checksum = "23c6602fda94a57c990fe0df199a035d83576b496aa29f4e634a8ac6004e68a6" dependencies = [ "num-traits", ] [[package]] name = "num-integer" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "autocfg", "num-traits", ] [[package]] name = "num-iter" -version = "0.1.43" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9" dependencies = [ "autocfg", "num-integer", @@ -311,9 +310,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.17" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" dependencies = [ "autocfg", ] @@ -420,18 +419,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.196" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.196" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", @@ -504,9 +503,9 @@ checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] name = "syn" -version = "2.0.48" +version = "2.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" dependencies = [ "proc-macro2", "quote", diff --git a/tests/ed-add/elf/riscv32im-succinct-zkvm-elf b/tests/ed-add/elf/riscv32im-succinct-zkvm-elf index 183f4caa0c5c2d21ba3dffbad40871f48df1e759..11e7f5a2253220e487a6181d1784cefbd1a2e52f 100755 GIT binary patch literal 101672 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 O6NG$>w$_i1_x}OKK6Rr2 literal 85932 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 z�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 diff --git a/tests/ed-decompress/Cargo.lock b/tests/ed-decompress/Cargo.lock index 67939b434c..c24b3ca3e3 100644 --- a/tests/ed-decompress/Cargo.lock +++ b/tests/ed-decompress/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "anyhow" -version = "1.0.79" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" +checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" [[package]] name = "base16ct" @@ -350,18 +350,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.196" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.196" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", @@ -434,9 +434,9 @@ checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] name = "syn" -version = "2.0.48" +version = "2.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" dependencies = [ "proc-macro2", "quote", diff --git a/tests/ed-decompress/elf/riscv32im-succinct-zkvm-elf b/tests/ed-decompress/elf/riscv32im-succinct-zkvm-elf index 2b7f66b1375e232bacbf890cfc0b31db0359f94f..303bfe038557b99270931539e47977a9bd4c70c5 100755 GIT binary patch literal 101600 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ℑ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 From eff54d60098ec0b51ed7798bc1a46ffdea595f49 Mon Sep 17 00:00:00 2001 From: 0xkanekiken <100861945+0xKanekiKen@users.noreply.github.com> Date: Mon, 11 Mar 2024 18:26:22 +0000 Subject: [PATCH 02/18] refactor(derive): add support for extra const generics in AlignedBorrow Signed-off-by: 0xkanekiken <100861945+0xKanekiKen@users.noreply.github.com> --- core/src/air/word.rs | 2 +- core/src/memory/columns.rs | 1 - core/src/operations/add.rs | 1 - core/src/operations/add4.rs | 1 - core/src/operations/add5.rs | 1 - core/src/operations/and.rs | 1 - core/src/operations/field/field_den.rs | 10 +- .../operations/field/field_inner_product.rs | 10 +- core/src/operations/field/field_op.rs | 10 +- core/src/operations/field/field_sqrt.rs | 10 +- core/src/operations/fixed_rotate_right.rs | 1 - core/src/operations/fixed_shift_right.rs | 1 - core/src/operations/is_equal_word.rs | 1 - core/src/operations/is_zero.rs | 1 - core/src/operations/is_zero_word.rs | 1 - core/src/operations/not.rs | 1 - core/src/operations/or.rs | 1 - core/src/operations/xor.rs | 1 - core/src/runtime/record.rs | 2 +- .../syscall/precompiles/blake3/compress/g.rs | 1 - derive/src/lib.rs | 116 ++++++++++-------- 21 files changed, 90 insertions(+), 84 deletions(-) diff --git a/core/src/air/word.rs b/core/src/air/word.rs index 76c37d6ea1..067e2e6be5 100644 --- a/core/src/air/word.rs +++ b/core/src/air/word.rs @@ -1,5 +1,5 @@ use std::array::IntoIter; -use std::mem::size_of; + use std::ops::{Index, IndexMut}; use core::borrow::{Borrow, BorrowMut}; diff --git a/core/src/memory/columns.rs b/core/src/memory/columns.rs index 9b9b6130ef..8010f5cbba 100644 --- a/core/src/memory/columns.rs +++ b/core/src/memory/columns.rs @@ -1,6 +1,5 @@ use core::borrow::{Borrow, BorrowMut}; use sp1_derive::AlignedBorrow; -use std::mem::size_of; use crate::air::Word; diff --git a/core/src/operations/add.rs b/core/src/operations/add.rs index fc41f094fc..8c23a9cd4b 100644 --- a/core/src/operations/add.rs +++ b/core/src/operations/add.rs @@ -3,7 +3,6 @@ use core::borrow::BorrowMut; use p3_air::AirBuilder; use p3_field::Field; use sp1_derive::AlignedBorrow; -use std::mem::size_of; use crate::air::SP1AirBuilder; use crate::air::Word; diff --git a/core/src/operations/add4.rs b/core/src/operations/add4.rs index 75bd4d5505..8dcd616264 100644 --- a/core/src/operations/add4.rs +++ b/core/src/operations/add4.rs @@ -5,7 +5,6 @@ use p3_air::AirBuilder; use p3_field::AbstractField; use p3_field::Field; use sp1_derive::AlignedBorrow; -use std::mem::size_of; use crate::air::SP1AirBuilder; use crate::air::Word; diff --git a/core/src/operations/add5.rs b/core/src/operations/add5.rs index e6b6e93d8a..6c4ccbbe6b 100644 --- a/core/src/operations/add5.rs +++ b/core/src/operations/add5.rs @@ -3,7 +3,6 @@ use core::borrow::BorrowMut; use p3_air::AirBuilder; use p3_field::Field; use sp1_derive::AlignedBorrow; -use std::mem::size_of; use crate::air::SP1AirBuilder; use crate::air::Word; diff --git a/core/src/operations/and.rs b/core/src/operations/and.rs index f1f52b892d..3a64cc785a 100644 --- a/core/src/operations/and.rs +++ b/core/src/operations/and.rs @@ -3,7 +3,6 @@ use core::borrow::BorrowMut; use p3_field::AbstractField; use p3_field::Field; use sp1_derive::AlignedBorrow; -use std::mem::size_of; use crate::air::SP1AirBuilder; use crate::air::Word; diff --git a/core/src/operations/field/field_den.rs b/core/src/operations/field/field_den.rs index eec6f123af..d16d904ce1 100644 --- a/core/src/operations/field/field_den.rs +++ b/core/src/operations/field/field_den.rs @@ -4,10 +4,10 @@ use super::util_air::eval_field_operation; use crate::air::Polynomial; use crate::air::SP1AirBuilder; use crate::utils::ec::field::FieldParameters; -use core::borrow::{Borrow, BorrowMut}; +use core::borrow::Borrow; use num::BigUint; use p3_field::PrimeField32; -use sp1_derive::AlignedBorrowWithGenerics; +use sp1_derive::AlignedBorrow; use std::fmt::Debug; /// A set of columns to compute `FieldDen(a, b)` where `a`, `b` are field elements. @@ -17,7 +17,7 @@ use std::fmt::Debug; /// /// Right now the number of limbs is assumed to be a constant, although this could be macro-ed /// or made generic in the future. -#[derive(Debug, Clone, AlignedBorrowWithGenerics)] +#[derive(Debug, Clone, AlignedBorrow)] #[repr(C)] pub struct FieldDenCols { /// The result of `a den b`, where a, b are field elements @@ -145,9 +145,9 @@ mod tests { use p3_matrix::dense::RowMajorMatrix; use p3_matrix::MatrixRowSlices; use rand::thread_rng; - use sp1_derive::AlignedBorrowWithGenerics; + use sp1_derive::AlignedBorrow; - #[derive(Debug, Clone, AlignedBorrowWithGenerics)] + #[derive(Debug, Clone, AlignedBorrow)] pub struct TestCols { pub a: Limbs, pub b: Limbs, diff --git a/core/src/operations/field/field_inner_product.rs b/core/src/operations/field/field_inner_product.rs index 202a781031..28307a278e 100644 --- a/core/src/operations/field/field_inner_product.rs +++ b/core/src/operations/field/field_inner_product.rs @@ -4,17 +4,17 @@ use super::util_air::eval_field_operation; use crate::air::Polynomial; use crate::air::SP1AirBuilder; use crate::utils::ec::field::FieldParameters; -use core::borrow::{Borrow, BorrowMut}; +use core::borrow::Borrow; use num::BigUint; use num::Zero; use p3_field::{AbstractField, PrimeField32}; -use sp1_derive::AlignedBorrowWithGenerics; +use sp1_derive::AlignedBorrow; use std::fmt::Debug; /// A set of columns to compute `FieldInnerProduct(Vec, Vec)` where a, b are field elements. /// Right now the number of limbs is assumed to be a constant, although this could be macro-ed /// or made generic in the future. -#[derive(Debug, Clone, AlignedBorrowWithGenerics)] +#[derive(Debug, Clone, AlignedBorrow)] #[repr(C)] pub struct FieldInnerProductCols { /// The result of `a inner product b`, where a, b are field elements @@ -133,9 +133,9 @@ mod tests { use p3_matrix::dense::RowMajorMatrix; use p3_matrix::MatrixRowSlices; use rand::thread_rng; - use sp1_derive::AlignedBorrowWithGenerics; + use sp1_derive::AlignedBorrow; - #[derive(AlignedBorrowWithGenerics, Debug, Clone)] + #[derive(AlignedBorrow, Debug, Clone)] pub struct TestCols { pub a: [Limbs; 1], pub b: [Limbs; 1], diff --git a/core/src/operations/field/field_op.rs b/core/src/operations/field/field_op.rs index fc31c4d9d4..7008c117d0 100644 --- a/core/src/operations/field/field_op.rs +++ b/core/src/operations/field/field_op.rs @@ -4,11 +4,11 @@ use super::util_air::eval_field_operation; use crate::air::Polynomial; use crate::air::SP1AirBuilder; use crate::utils::ec::field::FieldParameters; -use core::borrow::{Borrow, BorrowMut}; +use core::borrow::Borrow; use num::{BigUint, Zero}; use p3_air::AirBuilder; use p3_field::PrimeField32; -use sp1_derive::AlignedBorrowWithGenerics; +use sp1_derive::AlignedBorrow; use std::fmt::Debug; use std::usize; @@ -23,7 +23,7 @@ pub enum FieldOperation { /// A set of columns to compute `FieldOperation(a, b)` where a, b are field elements. /// Right now the number of limbs is assumed to be a constant, although this could be macro-ed /// or made generic in the future. -#[derive(Debug, Clone, AlignedBorrowWithGenerics)] +#[derive(Debug, Clone, AlignedBorrow)] #[repr(C)] pub struct FieldOpCols { /// The result of `a op b`, where a, b are field elements @@ -189,9 +189,9 @@ mod tests { use p3_matrix::dense::RowMajorMatrix; use p3_matrix::MatrixRowSlices; use rand::thread_rng; - use sp1_derive::AlignedBorrowWithGenerics; + use sp1_derive::AlignedBorrow; - #[derive(AlignedBorrowWithGenerics, Debug, Clone)] + #[derive(AlignedBorrow, Debug, Clone)] pub struct TestCols { pub a: Limbs, pub b: Limbs, diff --git a/core/src/operations/field/field_sqrt.rs b/core/src/operations/field/field_sqrt.rs index c7dd08efef..76949d4ed5 100644 --- a/core/src/operations/field/field_sqrt.rs +++ b/core/src/operations/field/field_sqrt.rs @@ -2,15 +2,15 @@ use super::field_op::FieldOpCols; use super::params::Limbs; use crate::air::SP1AirBuilder; use crate::utils::ec::field::FieldParameters; -use core::borrow::{Borrow, BorrowMut}; +use core::borrow::Borrow; use num::BigUint; use p3_field::PrimeField32; -use sp1_derive::AlignedBorrowWithGenerics; +use sp1_derive::AlignedBorrow; use std::fmt::Debug; /// A set of columns to compute the square root in the ed25519 curve. `T` is the field in which each /// limb lives. -#[derive(Debug, Clone, AlignedBorrowWithGenerics)] +#[derive(Debug, Clone, AlignedBorrow)] #[repr(C)] pub struct FieldSqrtCols { /// The multiplication operation to verify that the sqrt and the input match. @@ -96,8 +96,8 @@ mod tests { use p3_matrix::dense::RowMajorMatrix; use p3_matrix::MatrixRowSlices; use rand::thread_rng; - use sp1_derive::AlignedBorrowWithGenerics; - #[derive(AlignedBorrowWithGenerics, Debug, Clone)] + use sp1_derive::AlignedBorrow; + #[derive(AlignedBorrow, Debug, Clone)] pub struct TestCols { pub a: Limbs, pub sqrt: FieldSqrtCols, diff --git a/core/src/operations/fixed_rotate_right.rs b/core/src/operations/fixed_rotate_right.rs index fec38d10c0..9be4440460 100644 --- a/core/src/operations/fixed_rotate_right.rs +++ b/core/src/operations/fixed_rotate_right.rs @@ -2,7 +2,6 @@ use core::borrow::Borrow; use core::borrow::BorrowMut; use p3_field::Field; use sp1_derive::AlignedBorrow; -use std::mem::size_of; use crate::air::SP1AirBuilder; use crate::air::Word; diff --git a/core/src/operations/fixed_shift_right.rs b/core/src/operations/fixed_shift_right.rs index 30bdbadb2a..2da7c1179f 100644 --- a/core/src/operations/fixed_shift_right.rs +++ b/core/src/operations/fixed_shift_right.rs @@ -2,7 +2,6 @@ use core::borrow::Borrow; use core::borrow::BorrowMut; use p3_field::Field; use sp1_derive::AlignedBorrow; -use std::mem::size_of; use crate::air::SP1AirBuilder; use crate::air::Word; diff --git a/core/src/operations/is_equal_word.rs b/core/src/operations/is_equal_word.rs index a1126965d6..7b7d8bdfa0 100644 --- a/core/src/operations/is_equal_word.rs +++ b/core/src/operations/is_equal_word.rs @@ -2,7 +2,6 @@ use core::borrow::Borrow; use core::borrow::BorrowMut; use p3_field::Field; use sp1_derive::AlignedBorrow; -use std::mem::size_of; use crate::air::SP1AirBuilder; use crate::air::Word; diff --git a/core/src/operations/is_zero.rs b/core/src/operations/is_zero.rs index 908d9f24a8..8efbc3d91a 100644 --- a/core/src/operations/is_zero.rs +++ b/core/src/operations/is_zero.rs @@ -10,7 +10,6 @@ use p3_air::AirBuilder; use p3_field::AbstractField; use p3_field::Field; use sp1_derive::AlignedBorrow; -use std::mem::size_of; use crate::air::SP1AirBuilder; diff --git a/core/src/operations/is_zero_word.rs b/core/src/operations/is_zero_word.rs index 06a45cf1fa..47a6c56f2e 100644 --- a/core/src/operations/is_zero_word.rs +++ b/core/src/operations/is_zero_word.rs @@ -7,7 +7,6 @@ use core::borrow::BorrowMut; use p3_air::AirBuilder; use p3_field::Field; use sp1_derive::AlignedBorrow; -use std::mem::size_of; use crate::air::SP1AirBuilder; use crate::air::Word; diff --git a/core/src/operations/not.rs b/core/src/operations/not.rs index 657b059b11..34959bd9cd 100644 --- a/core/src/operations/not.rs +++ b/core/src/operations/not.rs @@ -3,7 +3,6 @@ use core::borrow::BorrowMut; use p3_air::AirBuilder; use p3_field::Field; use sp1_derive::AlignedBorrow; -use std::mem::size_of; use crate::air::SP1AirBuilder; use crate::air::Word; diff --git a/core/src/operations/or.rs b/core/src/operations/or.rs index cb7440c8b0..90c20659ca 100644 --- a/core/src/operations/or.rs +++ b/core/src/operations/or.rs @@ -3,7 +3,6 @@ use core::borrow::BorrowMut; use p3_field::AbstractField; use p3_field::Field; use sp1_derive::AlignedBorrow; -use std::mem::size_of; use crate::air::SP1AirBuilder; use crate::air::Word; diff --git a/core/src/operations/xor.rs b/core/src/operations/xor.rs index 1a1d433f5c..7fc85a2b35 100644 --- a/core/src/operations/xor.rs +++ b/core/src/operations/xor.rs @@ -3,7 +3,6 @@ use core::borrow::BorrowMut; use p3_field::AbstractField; use p3_field::Field; use sp1_derive::AlignedBorrow; -use std::mem::size_of; use crate::air::SP1AirBuilder; use crate::air::Word; diff --git a/core/src/runtime/record.rs b/core/src/runtime/record.rs index 42c9648919..4483399773 100644 --- a/core/src/runtime/record.rs +++ b/core/src/runtime/record.rs @@ -14,7 +14,7 @@ use crate::syscall::precompiles::edwards::EdDecompressEvent; // use crate::syscall::precompiles::k256::K256DecompressEvent; use crate::syscall::precompiles::keccak256::KeccakPermuteEvent; use crate::syscall::precompiles::sha256::{ShaCompressEvent, ShaExtendEvent}; -use crate::syscall::precompiles::{ECAddEvent, ECDoubleEvent}; +use crate::syscall::precompiles::ECAddEvent; use crate::utils::env; /// A record of the execution of a program. Contains event data for everything that happened during diff --git a/core/src/syscall/precompiles/blake3/compress/g.rs b/core/src/syscall/precompiles/blake3/compress/g.rs index 176d47c2dc..7b48e68909 100644 --- a/core/src/syscall/precompiles/blake3/compress/g.rs +++ b/core/src/syscall/precompiles/blake3/compress/g.rs @@ -3,7 +3,6 @@ use core::borrow::BorrowMut; use p3_field::Field; use sp1_derive::AlignedBorrow; -use std::mem::size_of; use crate::air::SP1AirBuilder; use crate::air::Word; diff --git a/derive/src/lib.rs b/derive/src/lib.rs index 59f50a373c..082a78c2b6 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -28,69 +28,89 @@ use proc_macro::TokenStream; use quote::quote; use syn::parse_macro_input; use syn::Data; +use syn::DeriveInput; +use syn::GenericParam; use syn::ItemFn; #[proc_macro_derive(AlignedBorrow)] pub fn aligned_borrow_derive(input: TokenStream) -> TokenStream { - let ast: syn::DeriveInput = syn::parse(input).unwrap(); - - // Get struct name from ast + let ast = parse_macro_input!(input as DeriveInput); let name = &ast.ident; - let methods = quote! { - impl Borrow<#name> for [T] { - fn borrow(&self) -> &#name { - debug_assert_eq!(self.len(), size_of::<#name>()); - let (prefix, shorts, _suffix) = unsafe { self.align_to::<#name>() }; - debug_assert!(prefix.is_empty(), "Alignment should match"); - debug_assert_eq!(shorts.len(), 1); - &shorts[0] - } - } - impl BorrowMut<#name> for [T] { - fn borrow_mut(&mut self) -> &mut #name { - debug_assert_eq!(self.len(), size_of::<#name>()); - let (prefix, shorts, _suffix) = unsafe { self.align_to_mut::<#name>() }; - debug_assert!(prefix.is_empty(), "Alignment should match"); - debug_assert_eq!(shorts.len(), 1); - &mut shorts[0] + // Separate type generics and const generics + let type_generic = ast + .generics + .params + .iter() + .find_map(|param| { + if let GenericParam::Type(type_param) = param { + Some(&type_param.ident) + } else { + None + } + }) + .expect("Expected at least one type generic"); + + let const_generics = ast + .generics + .params + .iter() + .filter_map(|param| { + if let GenericParam::Const(const_param) = param { + Some(&const_param.ident) + } else { + None + } + }) + .collect::>(); + + let methods = if const_generics.is_empty() { + quote! { + impl<#type_generic> Borrow<#name<#type_generic>> for [#type_generic] { + fn borrow(&self) -> &#name<#type_generic> { + debug_assert_eq!(self.len(), std::mem::size_of::<#name>()); + let (prefix, shorts, _suffix) = unsafe { self.align_to::<#name<#type_generic>>() }; + debug_assert!(prefix.is_empty(), "Alignment should match"); + debug_assert_eq!(shorts.len(), 1); + &shorts[0] + } } - } - }; - - methods.into() -} - -#[proc_macro_derive(AlignedBorrowWithGenerics)] -pub fn aligned_borrow_derive_with_generics(input: TokenStream) -> TokenStream { - let ast: syn::DeriveInput = syn::parse(input).unwrap(); - - // Get struct name from ast - let name = &ast.ident; - let methods = quote! { - impl Borrow<#name> for [T] { - fn borrow(&self) -> &#name { - debug_assert_eq!(self.len(), std::mem::size_of::<#name>()); - let (prefix, shorts, _suffix) = unsafe { self.align_to::<#name>() }; - debug_assert!(prefix.is_empty(), "Alignment should match"); - debug_assert_eq!(shorts.len(), 1); - &shorts[0] + impl<#type_generic> BorrowMut<#name<#type_generic>> for [#type_generic] { + fn borrow_mut(&mut self) -> &mut #name<#type_generic> { + debug_assert_eq!(self.len(), std::mem::size_of::<#name>()); + let (prefix, shorts, _suffix) = unsafe { self.align_to_mut::<#name<#type_generic>>() }; + debug_assert!(prefix.is_empty(), "Alignment should match"); + debug_assert_eq!(shorts.len(), 1); + &mut shorts[0] + } } } + } else { + quote! { + impl<#type_generic #(, const #const_generics: usize)*> Borrow<#name<#type_generic #(, #const_generics)*>> for [#type_generic] { + fn borrow(&self) -> &#name<#type_generic #(, #const_generics)*> { + debug_assert_eq!(self.len(), std::mem::size_of::<#name>()); + let (prefix, shorts, _suffix) = unsafe { self.align_to::<#name<#type_generic #(, #const_generics)*>>() }; + debug_assert!(prefix.is_empty(), "Alignment should match"); + debug_assert_eq!(shorts.len(), 1); + &shorts[0] + } + } - impl BorrowMut<#name> for [T] { - fn borrow_mut(&mut self) -> &mut #name { - debug_assert_eq!(self.len(), std::mem::size_of::<#name>()); - let (prefix, shorts, _suffix) = unsafe { self.align_to_mut::<#name>() }; - debug_assert!(prefix.is_empty(), "Alignment should match"); - debug_assert_eq!(shorts.len(), 1); - &mut shorts[0] + impl<#type_generic #(, const #const_generics: usize)*> std::borrow::BorrowMut<#name<#type_generic #(, #const_generics)*>> for [#type_generic] { + fn borrow_mut(&mut self) -> &mut #name<#type_generic #(, #const_generics)*> { + debug_assert_eq!(self.len(), std::mem::size_of::<#name>()); + let (prefix, shorts, _suffix) = unsafe { self.align_to_mut::<#name<#type_generic #(, #const_generics)*>>() }; + debug_assert!(prefix.is_empty(), "Alignment should match"); + debug_assert_eq!(shorts.len(), 1); + &mut shorts[0] + } } } }; - methods.into() + TokenStream::from(methods) } #[proc_macro_derive(MachineAir)] From 653a2ab451e618084bb7152ac646be9dc13a70a0 Mon Sep 17 00:00:00 2001 From: 0xkanekiken <100861945+0xKanekiKen@users.noreply.github.com> Date: Mon, 11 Mar 2024 21:46:39 +0000 Subject: [PATCH 03/18] refactor: apply the generic changes to weierstrass curves Signed-off-by: 0xkanekiken <100861945+0xKanekiKen@users.noreply.github.com> --- core/src/operations/field/field_den.rs | 33 +++--- .../operations/field/field_inner_product.rs | 41 ++++--- core/src/operations/field/field_op.rs | 38 +++--- core/src/operations/field/field_sqrt.rs | 22 ++-- core/src/operations/field/params.rs | 2 +- core/src/operations/field/util_air.rs | 2 +- core/src/runtime/record.rs | 83 ++++++------- core/src/runtime/syscall.rs | 32 ++--- core/src/stark/air.rs | 44 +++---- .../src/syscall/precompiles/edwards/ed_add.rs | 110 +++++------------- .../precompiles/edwards/ed_decompress.rs | 24 ++-- .../syscall/precompiles/k256/decompress.rs | 18 +-- core/src/syscall/precompiles/k256/mod.rs | 3 + core/src/syscall/precompiles/mod.rs | 30 ++--- .../syscall/precompiles/weierstrass/mod.rs | 3 + .../weierstrass/weierstrass_add.rs | 46 ++++---- .../weierstrass/weierstrass_double.rs | 52 ++++----- core/src/utils/ec/edwards/ed25519.rs | 11 +- core/src/utils/ec/edwards/mod.rs | 35 +++--- core/src/utils/ec/field.rs | 48 ++++---- core/src/utils/ec/mod.rs | 57 ++++----- core/src/utils/ec/scalar_mul.rs | 20 ++-- core/src/utils/ec/weierstrass/bn254.rs | 12 +- core/src/utils/ec/weierstrass/mod.rs | 35 +++--- core/src/utils/ec/weierstrass/secp256k1.rs | 14 +-- tests/secp256k1-add/Cargo.lock | 33 +++--- .../elf/riscv32im-succinct-zkvm-elf | Bin 85956 -> 101748 bytes 27 files changed, 409 insertions(+), 439 deletions(-) diff --git a/core/src/operations/field/field_den.rs b/core/src/operations/field/field_den.rs index d16d904ce1..99db6e3ee3 100644 --- a/core/src/operations/field/field_den.rs +++ b/core/src/operations/field/field_den.rs @@ -3,7 +3,7 @@ use super::util::{compute_root_quotient_and_shift, split_u16_limbs_to_u8_limbs}; use super::util_air::eval_field_operation; use crate::air::Polynomial; use crate::air::SP1AirBuilder; -use crate::utils::ec::field::FieldParameters; +use crate::utils::ec::field::{limbs_from_vec, FieldParameters}; use core::borrow::Borrow; use num::BigUint; use p3_field::PrimeField32; @@ -28,7 +28,7 @@ pub struct FieldDenCols { } impl FieldDenCols { - pub fn populate>( + pub fn populate( &mut self, a: &BigUint, b: &BigUint, @@ -53,11 +53,12 @@ impl FieldDenCols { debug_assert!(carry < p); debug_assert_eq!(&carry * &p, &equation_lhs - &equation_rhs); - let p_a: Polynomial = P::to_limbs_field::(a).into(); - let p_b: Polynomial = P::to_limbs_field::(b).into(); - let p_p: Polynomial = P::to_limbs_field::(&p).into(); - let p_result: Polynomial = P::to_limbs_field::(&result).into(); - let p_carry: Polynomial = P::to_limbs_field::(&carry).into(); + let p_a: Polynomial = limbs_from_vec::(P::to_limbs_field::(a)).into(); + let p_b: Polynomial = limbs_from_vec::(P::to_limbs_field::(b)).into(); + let p_p: Polynomial = limbs_from_vec::(P::to_limbs_field::(&p)).into(); + let p_result: Polynomial = + limbs_from_vec::(P::to_limbs_field::(&result)).into(); + let p_carry: Polynomial = limbs_from_vec::(P::to_limbs_field::(&carry)).into(); // Compute the vanishing polynomial. let vanishing_poly = if sign { @@ -85,7 +86,7 @@ impl FieldDenCols { impl FieldDenCols { #[allow(unused_variables)] - pub fn eval, P: FieldParameters>( + pub fn eval, P: FieldParameters>( &self, builder: &mut AB, a: &Limbs, @@ -133,7 +134,7 @@ mod tests { use crate::air::MachineAir; use crate::utils::ec::edwards::ed25519::Ed25519BaseField; - use crate::utils::ec::field::FieldParameters; + use crate::utils::ec::field::{limbs_from_vec, FieldParameters}; use crate::utils::{uni_stark_prove as prove, uni_stark_verify as verify}; use crate::utils::{BabyBearPoseidon2, StarkUtils}; use crate::{air::SP1AirBuilder, runtime::ExecutionRecord}; @@ -159,12 +160,12 @@ mod tests { pub const NUM_TEST_COLS: usize = size_of::>(); - struct FieldDenChip> { + struct FieldDenChip { pub sign: bool, pub _phantom: std::marker::PhantomData

, } - impl> FieldDenChip

{ + impl FieldDenChip

{ pub fn new(sign: bool) -> Self { Self { sign, @@ -173,7 +174,7 @@ mod tests { } } - impl> MachineAir for FieldDenChip

{ + impl MachineAir for FieldDenChip

{ fn name(&self) -> String { "FieldDen".to_string() } @@ -209,8 +210,8 @@ mod tests { let mut row = [F::zero(); NUM_TEST_COLS]; let cols: &mut TestCols = row.as_mut_slice().borrow_mut(); - cols.a = P::to_limbs_field::(a); - cols.b = P::to_limbs_field::(b); + cols.a = limbs_from_vec::(P::to_limbs_field::(a)); + cols.b = limbs_from_vec::(P::to_limbs_field::(b)); cols.a_den_b.populate::

(a, b, self.sign); row }) @@ -226,13 +227,13 @@ mod tests { } } - impl> BaseAir for FieldDenChip

{ + impl BaseAir for FieldDenChip

{ fn width(&self) -> usize { NUM_TEST_COLS } } - impl> Air for FieldDenChip

+ impl Air for FieldDenChip

where AB: SP1AirBuilder, { diff --git a/core/src/operations/field/field_inner_product.rs b/core/src/operations/field/field_inner_product.rs index 28307a278e..8f8ac339bf 100644 --- a/core/src/operations/field/field_inner_product.rs +++ b/core/src/operations/field/field_inner_product.rs @@ -3,7 +3,7 @@ use super::util::{compute_root_quotient_and_shift, split_u16_limbs_to_u8_limbs}; use super::util_air::eval_field_operation; use crate::air::Polynomial; use crate::air::SP1AirBuilder; -use crate::utils::ec::field::FieldParameters; +use crate::utils::ec::field::{limbs_from_vec, FieldParameters}; use core::borrow::Borrow; use num::BigUint; use num::Zero; @@ -25,11 +25,15 @@ pub struct FieldInnerProductCols { } impl FieldInnerProductCols { - pub fn populate>(&mut self, a: &[BigUint], b: &[BigUint]) -> BigUint { - let p_a_vec: Vec> = - a.iter().map(|x| P::to_limbs_field::(x).into()).collect(); - let p_b_vec: Vec> = - b.iter().map(|x| P::to_limbs_field::(x).into()).collect(); + pub fn populate(&mut self, a: &[BigUint], b: &[BigUint]) -> BigUint { + let p_a_vec: Vec> = a + .iter() + .map(|x| limbs_from_vec::(P::to_limbs_field::(x)).into()) + .collect(); + let p_b_vec: Vec> = b + .iter() + .map(|x| limbs_from_vec::(P::to_limbs_field::(x)).into()) + .collect(); let modulus = &P::modulus(); let inner_product = a @@ -43,9 +47,10 @@ impl FieldInnerProductCols = P::to_limbs_field::(modulus).into(); - let p_result: Polynomial = P::to_limbs_field::(result).into(); - let p_carry: Polynomial = P::to_limbs_field::(carry).into(); + let p_modulus: Polynomial = + limbs_from_vec::(P::to_limbs_field::(modulus)).into(); + let p_result: Polynomial = limbs_from_vec::(P::to_limbs_field::(result)).into(); + let p_carry: Polynomial = limbs_from_vec::(P::to_limbs_field::(carry)).into(); // Compute the vanishing polynomial. let p_inner_product = p_a_vec @@ -75,7 +80,7 @@ impl FieldInnerProductCols FieldInnerProductCols { #[allow(unused_variables)] - pub fn eval, P: FieldParameters>( + pub fn eval, P: FieldParameters>( &self, builder: &mut AB, a: &[Limbs], @@ -121,7 +126,7 @@ mod tests { use crate::air::MachineAir; use crate::utils::ec::edwards::ed25519::Ed25519BaseField; - use crate::utils::ec::field::FieldParameters; + use crate::utils::ec::field::{limbs_from_vec, FieldParameters}; use crate::utils::{pad_to_power_of_two, BabyBearPoseidon2, StarkUtils}; use crate::utils::{uni_stark_prove as prove, uni_stark_verify as verify}; use crate::{air::SP1AirBuilder, runtime::ExecutionRecord}; @@ -147,11 +152,11 @@ mod tests { pub const NUM_TEST_COLS: usize = size_of::>(); - struct FieldIpChip> { + struct FieldIpChip { pub _phantom: std::marker::PhantomData

, } - impl> FieldIpChip

{ + impl FieldIpChip

{ pub fn new() -> Self { Self { _phantom: std::marker::PhantomData, @@ -159,7 +164,7 @@ mod tests { } } - impl> MachineAir for FieldIpChip

{ + impl MachineAir for FieldIpChip

{ fn name(&self) -> String { "FieldInnerProduct".to_string() } @@ -191,8 +196,8 @@ mod tests { let mut row = [F::zero(); NUM_TEST_COLS]; let cols: &mut TestCols = row.as_mut_slice().borrow_mut(); - cols.a[0] = P::to_limbs_field::(&a[0]); - cols.b[0] = P::to_limbs_field::(&b[0]); + cols.a[0] = limbs_from_vec::(P::to_limbs_field::(&a[0])); + cols.b[0] = limbs_from_vec::(P::to_limbs_field::(&b[0])); cols.a_ip_b.populate::

(a, b); row }) @@ -210,13 +215,13 @@ mod tests { } } - impl> BaseAir for FieldIpChip

{ + impl BaseAir for FieldIpChip

{ fn width(&self) -> usize { NUM_TEST_COLS } } - impl> Air for FieldIpChip

+ impl Air for FieldIpChip

where AB: SP1AirBuilder, { diff --git a/core/src/operations/field/field_op.rs b/core/src/operations/field/field_op.rs index 7008c117d0..663016f5db 100644 --- a/core/src/operations/field/field_op.rs +++ b/core/src/operations/field/field_op.rs @@ -3,7 +3,7 @@ use super::util::{compute_root_quotient_and_shift, split_u16_limbs_to_u8_limbs}; use super::util_air::eval_field_operation; use crate::air::Polynomial; use crate::air::SP1AirBuilder; -use crate::utils::ec::field::FieldParameters; +use crate::utils::ec::field::{limbs_from_vec, FieldParameters}; use core::borrow::Borrow; use num::{BigUint, Zero}; use p3_air::AirBuilder; @@ -34,7 +34,7 @@ pub struct FieldOpCols { } impl FieldOpCols { - pub fn populate>( + pub fn populate( &mut self, a: &BigUint, b: &BigUint, @@ -60,7 +60,7 @@ impl FieldOpCols { // Note that this reversal means we have to flip result, a correspondingly in // the `eval` function. self.populate::

(&result, b, FieldOperation::Add); - self.result = P::to_limbs_field::(&result); + self.result = limbs_from_vec::(P::to_limbs_field::(&result)); return result; } @@ -77,12 +77,12 @@ impl FieldOpCols { // Note that this reversal means we have to flip result, a correspondingly in the `eval` // function. self.populate::

(&result, b, FieldOperation::Mul); - self.result = P::to_limbs_field::(&result); + self.result = limbs_from_vec::(P::to_limbs_field::(&result)); return result; } - let p_a: Polynomial = P::to_limbs_field::(a).into(); - let p_b: Polynomial = P::to_limbs_field::(b).into(); + let p_a: Polynomial = limbs_from_vec::(P::to_limbs_field::(a)).into(); + let p_b: Polynomial = limbs_from_vec::(P::to_limbs_field::(b)).into(); // Compute field addition in the integers. let modulus = &P::modulus(); @@ -100,9 +100,11 @@ impl FieldOpCols { } // Make little endian polynomial limbs. - let p_modulus: Polynomial = P::to_limbs_field::(modulus).into(); - let p_result: Polynomial = P::to_limbs_field::(&result).into(); - let p_carry: Polynomial = P::to_limbs_field::(&carry).into(); + let p_modulus: Polynomial = + limbs_from_vec::(P::to_limbs_field::(modulus)).into(); + let p_result: Polynomial = + limbs_from_vec::(P::to_limbs_field::(&result)).into(); + let p_carry: Polynomial = limbs_from_vec::(P::to_limbs_field::(&carry)).into(); // Compute the vanishing polynomial. let p_op = match op { @@ -133,7 +135,7 @@ impl FieldOpCols { #[allow(unused_variables)] pub fn eval< AB: SP1AirBuilder, - P: FieldParameters, + P: FieldParameters, A: Into> + Clone, B: Into> + Clone, >( @@ -177,7 +179,7 @@ mod tests { use crate::air::MachineAir; use crate::utils::ec::edwards::ed25519::Ed25519BaseField; - use crate::utils::ec::field::FieldParameters; + use crate::utils::ec::field::{limbs_from_vec, FieldParameters}; use crate::utils::{pad_to_power_of_two, BabyBearPoseidon2, StarkUtils}; use crate::utils::{uni_stark_prove as prove, uni_stark_verify as verify}; use crate::{air::SP1AirBuilder, runtime::ExecutionRecord}; @@ -203,12 +205,12 @@ mod tests { pub const NUM_TEST_COLS: usize = size_of::>(); - struct FieldOpChip> { + struct FieldOpChip { pub operation: FieldOperation, pub _phantom: std::marker::PhantomData

, } - impl> FieldOpChip

{ + impl FieldOpChip

{ pub fn new(operation: FieldOperation) -> Self { Self { operation, @@ -217,7 +219,7 @@ mod tests { } } - impl> MachineAir for FieldOpChip

{ + impl MachineAir for FieldOpChip

{ fn name(&self) -> String { format!("FieldOp{:?}", self.operation) } @@ -253,8 +255,8 @@ mod tests { let mut row = [F::zero(); NUM_TEST_COLS]; let cols: &mut TestCols = row.as_mut_slice().borrow_mut(); - cols.a = P::to_limbs_field::(a); - cols.b = P::to_limbs_field::(b); + cols.a = limbs_from_vec::(P::to_limbs_field::(a)); + cols.b = limbs_from_vec::(P::to_limbs_field::(b)); cols.a_op_b.populate::

(a, b, self.operation); row }) @@ -272,13 +274,13 @@ mod tests { } } - impl> BaseAir for FieldOpChip

{ + impl BaseAir for FieldOpChip

{ fn width(&self) -> usize { NUM_TEST_COLS } } - impl> Air for FieldOpChip

+ impl Air for FieldOpChip

where AB: SP1AirBuilder, { diff --git a/core/src/operations/field/field_sqrt.rs b/core/src/operations/field/field_sqrt.rs index 76949d4ed5..dcec13b700 100644 --- a/core/src/operations/field/field_sqrt.rs +++ b/core/src/operations/field/field_sqrt.rs @@ -1,7 +1,7 @@ use super::field_op::FieldOpCols; use super::params::Limbs; use crate::air::SP1AirBuilder; -use crate::utils::ec::field::FieldParameters; +use crate::utils::ec::field::{limbs_from_vec, FieldParameters}; use core::borrow::Borrow; use num::BigUint; use p3_field::PrimeField32; @@ -24,7 +24,7 @@ impl FieldSqrtCols { /// Populates the trace. /// /// `P` is the parameter of the field that each limb lives in. - pub fn populate>( + pub fn populate( &mut self, a: &BigUint, sqrt_fn: impl Fn(&BigUint) -> BigUint, @@ -41,7 +41,7 @@ impl FieldSqrtCols { // This is a hack to save a column in FieldSqrtCols. We will receive the value a again in the // eval function, so we'll overwrite it with the sqrt. - self.multiplication.result = P::to_limbs_field::(&sqrt); + self.multiplication.result = limbs_from_vec::(P::to_limbs_field::(&sqrt)); sqrt } @@ -49,7 +49,7 @@ impl FieldSqrtCols { impl FieldSqrtCols { /// Calculates the square root of `a`. - pub fn eval, P: FieldParameters>( + pub fn eval, P: FieldParameters>( &self, builder: &mut AB, a: &Limbs, @@ -84,7 +84,7 @@ mod tests { use crate::air::MachineAir; use crate::utils::ec::edwards::ed25519::{ed25519_sqrt, Ed25519BaseField}; - use crate::utils::ec::field::FieldParameters; + use crate::utils::ec::field::{limbs_from_vec, FieldParameters}; use crate::utils::{pad_to_power_of_two, BabyBearPoseidon2, StarkUtils}; use crate::utils::{uni_stark_prove as prove, uni_stark_verify as verify}; use crate::{air::SP1AirBuilder, runtime::ExecutionRecord}; @@ -108,11 +108,11 @@ mod tests { pub const NUM_TEST_COLS: usize = size_of::>(); - struct EdSqrtChip> { + struct EdSqrtChip { pub _phantom: std::marker::PhantomData

, } - impl> EdSqrtChip

{ + impl EdSqrtChip

{ pub fn new() -> Self { Self { _phantom: std::marker::PhantomData, @@ -120,7 +120,7 @@ mod tests { } } - impl> MachineAir for EdSqrtChip

{ + impl MachineAir for EdSqrtChip

{ fn name(&self) -> String { "EdSqrtChip".to_string() } @@ -151,7 +151,7 @@ mod tests { let mut row = [F::zero(); NUM_TEST_COLS]; let cols: &mut TestCols = row.as_mut_slice().borrow_mut(); - cols.a = P::to_limbs_field::(a); + cols.a = limbs_from_vec::(P::to_limbs_field::(a)); cols.sqrt.populate::

(a, ed25519_sqrt); row }) @@ -169,13 +169,13 @@ mod tests { } } - impl> BaseAir for EdSqrtChip

{ + impl BaseAir for EdSqrtChip

{ fn width(&self) -> usize { NUM_TEST_COLS } } - impl> Air for EdSqrtChip

+ impl Air for EdSqrtChip

where AB: SP1AirBuilder, { diff --git a/core/src/operations/field/params.rs b/core/src/operations/field/params.rs index 205dc8c014..bf7bd9f762 100644 --- a/core/src/operations/field/params.rs +++ b/core/src/operations/field/params.rs @@ -75,7 +75,7 @@ mod tests { #[test] fn test_modulus() { // Convert the MODULUS array to BigUint - let array_modulus = BigUint::from_bytes_le(&Ed25519BaseField::MODULUS); + let array_modulus = BigUint::from_bytes_le(Ed25519BaseField::MODULUS); // Get the modulus from the function let func_modulus = Ed25519BaseField::modulus(); diff --git a/core/src/operations/field/util_air.rs b/core/src/operations/field/util_air.rs index d563731363..1965ba1ac0 100644 --- a/core/src/operations/field/util_air.rs +++ b/core/src/operations/field/util_air.rs @@ -3,7 +3,7 @@ use crate::air::SP1AirBuilder; use crate::utils::ec::field::FieldParameters; use p3_field::AbstractField; -pub fn eval_field_operation>( +pub fn eval_field_operation( builder: &mut AB, p_vanishing: &Polynomial, p_witness_low: &Polynomial, diff --git a/core/src/runtime/record.rs b/core/src/runtime/record.rs index 4483399773..2ab1d70d94 100644 --- a/core/src/runtime/record.rs +++ b/core/src/runtime/record.rs @@ -11,10 +11,10 @@ use crate::field::event::FieldEvent; use crate::runtime::MemoryRecord; use crate::syscall::precompiles::blake3::Blake3CompressInnerEvent; use crate::syscall::precompiles::edwards::EdDecompressEvent; -// use crate::syscall::precompiles::k256::K256DecompressEvent; +use crate::syscall::precompiles::k256::K256DecompressEvent; use crate::syscall::precompiles::keccak256::KeccakPermuteEvent; use crate::syscall::precompiles::sha256::{ShaCompressEvent, ShaExtendEvent}; -use crate::syscall::precompiles::ECAddEvent; +use crate::syscall::precompiles::{ECAddEvent, ECDoubleEvent}; use crate::utils::env; /// A record of the execution of a program. Contains event data for everything that happened during @@ -73,11 +73,12 @@ pub struct ExecutionRecord { pub ed_decompress_events: Vec, - // pub weierstrass_add_events: Vec, + pub weierstrass_add_events: Vec, - // pub weierstrass_double_events: Vec, + pub weierstrass_double_events: Vec, + + pub k256_decompress_events: Vec, - // pub k256_decompress_events: Vec, pub blake3_compress_inner_events: Vec, /// Information needed for global chips. This shouldn't really be here but for legacy reasons, @@ -147,9 +148,9 @@ pub struct ShardStats { pub nb_keccak_permute_events: usize, pub nb_ed_add_events: usize, pub nb_ed_decompress_events: usize, - // pub nb_weierstrass_add_events: usize, - // pub nb_weierstrass_double_events: usize, - // pub nb_k256_decompress_events: usize, + pub nb_weierstrass_add_events: usize, + pub nb_weierstrass_double_events: usize, + pub nb_k256_decompress_events: usize, } impl ExecutionRecord { @@ -267,27 +268,27 @@ impl ExecutionRecord { shard.keccak_permute_events.extend_from_slice(keccak_chunk); } - // // Weierstrass curve add events. - // for (weierstrass_add_chunk, shard) in self - // .weierstrass_add_events - // .chunks(config.weierstrass_add_len) - // .zip(shards.iter_mut()) - // { - // shard - // .weierstrass_add_events - // .extend_from_slice(weierstrass_add_chunk); - // } - - // // Weierstrass curve double events. - // for (weierstrass_double_chunk, shard) in self - // .weierstrass_double_events - // .chunks(config.weierstrass_double_len) - // .zip(shards.iter_mut()) - // { - // shard - // .weierstrass_double_events - // .extend_from_slice(weierstrass_double_chunk); - // } + // Weierstrass curve add events. + for (weierstrass_add_chunk, shard) in self + .weierstrass_add_events + .chunks(config.weierstrass_add_len) + .zip(shards.iter_mut()) + { + shard + .weierstrass_add_events + .extend_from_slice(weierstrass_add_chunk); + } + + // Weierstrass curve double events. + for (weierstrass_double_chunk, shard) in self + .weierstrass_double_events + .chunks(config.weierstrass_double_len) + .zip(shards.iter_mut()) + { + shard + .weierstrass_double_events + .extend_from_slice(weierstrass_double_chunk); + } // Put the precompile events in the first shard. let first = shards.first_mut().unwrap(); @@ -311,9 +312,9 @@ impl ExecutionRecord { .extend_from_slice(&self.ed_decompress_events); // K256 curve decompress events. - // first - // .k256_decompress_events - // .extend_from_slice(&self.k256_decompress_events); + first + .k256_decompress_events + .extend_from_slice(&self.k256_decompress_events); // Blake3 compress events . first @@ -469,9 +470,9 @@ impl ExecutionRecord { nb_keccak_permute_events: self.keccak_permute_events.len(), nb_ed_add_events: self.ed_add_events.len(), nb_ed_decompress_events: self.ed_decompress_events.len(), - // nb_weierstrass_add_events: self.weierstrass_add_events.len(), - // nb_weierstrass_double_events: self.weierstrass_double_events.len(), - // nb_k256_decompress_events: self.k256_decompress_events.len(), + nb_weierstrass_add_events: self.weierstrass_add_events.len(), + nb_weierstrass_double_events: self.weierstrass_double_events.len(), + nb_k256_decompress_events: self.k256_decompress_events.len(), } } @@ -498,12 +499,12 @@ impl ExecutionRecord { self.ed_add_events.append(&mut other.ed_add_events); self.ed_decompress_events .append(&mut other.ed_decompress_events); - // self.weierstrass_add_events - // .append(&mut other.weierstrass_add_events); - // self.weierstrass_double_events - // .append(&mut other.weierstrass_double_events); - // self.k256_decompress_events - // .append(&mut other.k256_decompress_events); + self.weierstrass_add_events + .append(&mut other.weierstrass_add_events); + self.weierstrass_double_events + .append(&mut other.weierstrass_double_events); + self.k256_decompress_events + .append(&mut other.k256_decompress_events); self.blake3_compress_inner_events .append(&mut other.blake3_compress_inner_events); diff --git a/core/src/runtime/syscall.rs b/core/src/runtime/syscall.rs index 5111504168..b37ce1c537 100644 --- a/core/src/runtime/syscall.rs +++ b/core/src/runtime/syscall.rs @@ -5,16 +5,16 @@ use crate::runtime::{Register, Runtime}; use crate::syscall::precompiles::blake3::Blake3CompressInnerChip; use crate::syscall::precompiles::edwards::EdAddAssignChip; use crate::syscall::precompiles::edwards::EdDecompressChip; -// use crate::syscall::precompiles::k256::K256DecompressChip; +use crate::syscall::precompiles::k256::K256DecompressChip; use crate::syscall::precompiles::keccak256::KeccakPermuteChip; use crate::syscall::precompiles::sha256::{ShaCompressChip, ShaExtendChip}; -// use crate::syscall::precompiles::weierstrass::WeierstrassAddAssignChip; -// use crate::syscall::precompiles::weierstrass::WeierstrassDoubleAssignChip; +use crate::syscall::precompiles::weierstrass::WeierstrassAddAssignChip; +use crate::syscall::precompiles::weierstrass::WeierstrassDoubleAssignChip; use crate::syscall::{ SyscallEnterUnconstrained, SyscallExitUnconstrained, SyscallHalt, SyscallLWA, SyscallWrite, }; use crate::utils::ec::edwards::ed25519::{Ed25519, Ed25519Parameters}; -// use crate::utils::ec::weierstrass::secp256k1::Secp256k1; +use crate::utils::ec::weierstrass::secp256k1::Secp256k1; use crate::{cpu::MemoryReadRecord, cpu::MemoryWriteRecord, runtime::ExecutionRecord}; /// A system call is invoked by the the `ecall` instruction with a specific value in register t0. @@ -200,19 +200,19 @@ pub fn default_syscall_map() -> HashMap> { SyscallCode::KECCAK_PERMUTE, Rc::new(KeccakPermuteChip::new()), ); - // syscall_map.insert( - // SyscallCode::SECP256K1_ADD, - // Rc::new(WeierstrassAddAssignChip::::new()), - // ); - // syscall_map.insert( - // SyscallCode::SECP256K1_DOUBLE, - // Rc::new(WeierstrassDoubleAssignChip::::new()), - // ); + syscall_map.insert( + SyscallCode::SECP256K1_ADD, + Rc::new(WeierstrassAddAssignChip::::new()), + ); + syscall_map.insert( + SyscallCode::SECP256K1_DOUBLE, + Rc::new(WeierstrassDoubleAssignChip::::new()), + ); syscall_map.insert(SyscallCode::SHA_COMPRESS, Rc::new(ShaCompressChip::new())); - // syscall_map.insert( - // SyscallCode::SECP256K1_DECOMPRESS, - // Rc::new(K256DecompressChip::new()), - // ); + syscall_map.insert( + SyscallCode::SECP256K1_DECOMPRESS, + Rc::new(K256DecompressChip::new()), + ); syscall_map.insert( SyscallCode::BLAKE3_COMPRESS_INNER, Rc::new(Blake3CompressInnerChip::new()), diff --git a/core/src/stark/air.rs b/core/src/stark/air.rs index 014c1ae441..a70b1af5fb 100644 --- a/core/src/stark/air.rs +++ b/core/src/stark/air.rs @@ -23,16 +23,16 @@ pub(crate) mod riscv_chips { pub use crate::syscall::precompiles::blake3::Blake3CompressInnerChip; pub use crate::syscall::precompiles::edwards::EdAddAssignChip; pub use crate::syscall::precompiles::edwards::EdDecompressChip; - // pub use crate::syscall::precompiles::k256::K256DecompressChip; + pub use crate::syscall::precompiles::k256::K256DecompressChip; pub use crate::syscall::precompiles::keccak256::KeccakPermuteChip; pub use crate::syscall::precompiles::sha256::ShaCompressChip; pub use crate::syscall::precompiles::sha256::ShaExtendChip; - // pub use crate::syscall::precompiles::weierstrass::WeierstrassAddAssignChip; - // pub use crate::syscall::precompiles::weierstrass::WeierstrassDoubleAssignChip; + pub use crate::syscall::precompiles::weierstrass::WeierstrassAddAssignChip; + pub use crate::syscall::precompiles::weierstrass::WeierstrassDoubleAssignChip; pub use crate::utils::ec::edwards::ed25519::Ed25519Parameters; pub use crate::utils::ec::edwards::EdwardsCurve; - // pub use crate::utils::ec::weierstrass::secp256k1::Secp256k1Parameters; - // pub use crate::utils::ec::weierstrass::SwCurve; + pub use crate::utils::ec::weierstrass::secp256k1::Secp256k1Parameters; + pub use crate::utils::ec::weierstrass::SwCurve; } /// An AIR for encoding RISC-V execution. @@ -80,12 +80,12 @@ pub enum RiscvAir { Ed25519Add(EdAddAssignChip>), /// A precompile for decompressing a point on the Edwards curve ed25519. Ed25519Decompress(EdDecompressChip), - // /// A precompile for decompressing a point on the K256 curve. - // K256Decompress(K256DecompressChip), - // /// A precompile for addition on the Elliptic curve secp256k1. - // Secp256k1Add(WeierstrassAddAssignChip>), - // /// A precompile for doubling a point on the Elliptic curve secp256k1. - // Secp256k1Double(WeierstrassDoubleAssignChip>), + /// A precompile for decompressing a point on the K256 curve. + K256Decompress(K256DecompressChip), + /// A precompile for addition on the Elliptic curve secp256k1. + Secp256k1Add(WeierstrassAddAssignChip>), + /// A precompile for doubling a point on the Elliptic curve secp256k1. + Secp256k1Double(WeierstrassDoubleAssignChip>), /// A precompile for the Keccak permutation. KeccakP(KeccakPermuteChip), /// A precompile for the Blake3 compression function. @@ -110,14 +110,14 @@ impl RiscvAir { chips.push(RiscvAir::Ed25519Add(ed_add_assign)); let ed_decompress = EdDecompressChip::::default(); chips.push(RiscvAir::Ed25519Decompress(ed_decompress)); - // let k256_decompress = K256DecompressChip::default(); - // chips.push(RiscvAir::K256Decompress(k256_decompress)); - // let weierstrass_add_assign = - // WeierstrassAddAssignChip::>::new(); - // chips.push(RiscvAir::Secp256k1Add(weierstrass_add_assign)); - // let weierstrass_double_assign = - // WeierstrassDoubleAssignChip::>::new(); - // chips.push(RiscvAir::Secp256k1Double(weierstrass_double_assign)); + let k256_decompress = K256DecompressChip::default(); + chips.push(RiscvAir::K256Decompress(k256_decompress)); + let weierstrass_add_assign = + WeierstrassAddAssignChip::>::new(); + chips.push(RiscvAir::Secp256k1Add(weierstrass_add_assign)); + let weierstrass_double_assign = + WeierstrassDoubleAssignChip::>::new(); + chips.push(RiscvAir::Secp256k1Double(weierstrass_double_assign)); let keccak_permute = KeccakPermuteChip::new(); chips.push(RiscvAir::KeccakP(keccak_permute)); let blake3_compress_inner = Blake3CompressInnerChip::new(); @@ -174,9 +174,9 @@ impl RiscvAir { RiscvAir::Sha256Compress(_) => !shard.sha_compress_events.is_empty(), RiscvAir::Ed25519Add(_) => !shard.ed_add_events.is_empty(), RiscvAir::Ed25519Decompress(_) => !shard.ed_decompress_events.is_empty(), - // RiscvAir::K256Decompress(_) => !shard.k256_decompress_events.is_empty(), - // RiscvAir::Secp256k1Add(_) => !shard.weierstrass_add_events.is_empty(), - // RiscvAir::Secp256k1Double(_) => !shard.weierstrass_double_events.is_empty(), + RiscvAir::K256Decompress(_) => !shard.k256_decompress_events.is_empty(), + RiscvAir::Secp256k1Add(_) => !shard.weierstrass_add_events.is_empty(), + RiscvAir::Secp256k1Double(_) => !shard.weierstrass_double_events.is_empty(), RiscvAir::KeccakP(_) => !shard.keccak_permute_events.is_empty(), RiscvAir::Blake3Compress(_) => !shard.blake3_compress_inner_events.is_empty(), } diff --git a/core/src/syscall/precompiles/edwards/ed_add.rs b/core/src/syscall/precompiles/edwards/ed_add.rs index 4ca3dac766..2a7d9a7022 100644 --- a/core/src/syscall/precompiles/edwards/ed_add.rs +++ b/core/src/syscall/precompiles/edwards/ed_add.rs @@ -14,6 +14,7 @@ use crate::runtime::Syscall; use crate::syscall::precompiles::create_ec_add_event; use crate::syscall::precompiles::SyscallContext; use crate::utils::ec::edwards::EdwardsParameters; +use crate::utils::ec::field::limbs_from_vec; use crate::utils::ec::field::FieldParameters; use crate::utils::ec::AffinePoint; use crate::utils::ec::EllipticCurve; @@ -70,7 +71,7 @@ pub struct EdAddAssignChip { _marker: PhantomData, } -impl + EdwardsParameters> EdAddAssignChip { +impl EdAddAssignChip { pub fn new() -> Self { Self { _marker: PhantomData, @@ -85,63 +86,33 @@ impl + EdwardsParameters> EdAddAssignChip { ) { let x3_numerator = cols .x3_numerator - .populate::<>::BaseField>( - &[p_x.clone(), q_x.clone()], - &[q_y.clone(), p_y.clone()], - ); + .populate::(&[p_x.clone(), q_x.clone()], &[q_y.clone(), p_y.clone()]); let y3_numerator = cols .y3_numerator - .populate::<>::BaseField>( - &[p_y.clone(), p_x.clone()], - &[q_y.clone(), q_x.clone()], - ); + .populate::(&[p_y.clone(), p_x.clone()], &[q_y.clone(), q_x.clone()]); let x1_mul_y1 = cols .x1_mul_y1 - .populate::<>::BaseField>( - &p_x, - &p_y, - FieldOperation::Mul, - ); + .populate::(&p_x, &p_y, FieldOperation::Mul); let x2_mul_y2 = cols .x2_mul_y2 - .populate::<>::BaseField>( - &q_x, - &q_y, - FieldOperation::Mul, - ); + .populate::(&q_x, &q_y, FieldOperation::Mul); let f = cols .f - .populate::<>::BaseField>( - &x1_mul_y1, - &x2_mul_y2, - FieldOperation::Mul, - ); + .populate::(&x1_mul_y1, &x2_mul_y2, FieldOperation::Mul); let d = E::d_biguint(); let d_mul_f = cols .d_mul_f - .populate::<>::BaseField>( - &f, - &d, - FieldOperation::Mul, - ); + .populate::(&f, &d, FieldOperation::Mul); cols.x3_ins - .populate::<>::BaseField>( - &x3_numerator, - &d_mul_f, - true, - ); + .populate::(&x3_numerator, &d_mul_f, true); cols.y3_ins - .populate::<>::BaseField>( - &y3_numerator, - &d_mul_f, - false, - ); + .populate::(&y3_numerator, &d_mul_f, false); } } -impl + EdwardsParameters> Syscall for EdAddAssignChip { +impl Syscall for EdAddAssignChip { fn num_extra_cycles(&self) -> u32 { 8 } @@ -153,9 +124,7 @@ impl + EdwardsParameters> Syscall for EdAddAssignChi } } -impl + EdwardsParameters> MachineAir - for EdAddAssignChip -{ +impl MachineAir for EdAddAssignChip { fn name(&self) -> String { "EdAddAssign".to_string() } @@ -177,9 +146,9 @@ impl + EdwardsParameters> MachineAi // Decode affine points. let p = &event.p; let q = &event.q; - let p = AffinePoint::::from_words_le(p); + let p = AffinePoint::::from_words_le(p); let (p_x, p_y) = (p.x, p.y); - let q = AffinePoint::::from_words_le(q); + let q = AffinePoint::::from_words_le(q); let (q_x, q_y) = (q.x, q.y); // Populate basic columns. @@ -226,13 +195,13 @@ impl + EdwardsParameters> MachineAi } } -impl + EdwardsParameters> BaseAir for EdAddAssignChip { +impl BaseAir for EdAddAssignChip { fn width(&self) -> usize { NUM_ED_ADD_COLS } } -impl + EdwardsParameters> Air for EdAddAssignChip +impl Air for EdAddAssignChip where AB: SP1AirBuilder, { @@ -247,55 +216,34 @@ where // x3_numerator = x1 * y2 + x2 * y1. row.x3_numerator - .eval::>::BaseField>( - builder, - &[x1, x2], - &[y2, y1], - ); + .eval::(builder, &[x1, x2], &[y2, y1]); // y3_numerator = y1 * y2 + x1 * x2. row.y3_numerator - .eval::>::BaseField>( - builder, - &[y1, x1], - &[y2, x2], - ); + .eval::(builder, &[y1, x1], &[y2, x2]); // f = x1 * x2 * y1 * y2. row.x1_mul_y1 - .eval::>::BaseField, _, _>( - builder, - &x1, - &y1, - FieldOperation::Mul, - ); + .eval::(builder, &x1, &y1, FieldOperation::Mul); row.x2_mul_y2 - .eval::>::BaseField, _, _>( - builder, - &x2, - &y2, - FieldOperation::Mul, - ); + .eval::(builder, &x2, &y2, FieldOperation::Mul); let x1_mul_y1 = row.x1_mul_y1.result; let x2_mul_y2 = row.x2_mul_y2.result; row.f - .eval::>::BaseField, _, _>( - builder, - &x1_mul_y1, - &x2_mul_y2, - FieldOperation::Mul, - ); + .eval::(builder, &x1_mul_y1, &x2_mul_y2, FieldOperation::Mul); // d * f. let f = row.f.result; let d_biguint = E::d_biguint(); - let d_const = >::BaseField::to_limbs_field::( - &d_biguint, + let d_const = E::BaseField::to_limbs_field::(&d_biguint); + let d_const_expr = Limbs::( + limbs_from_vec::(d_const) + .0 + .map(|x| x.into()), ); - let d_const_expr = Limbs::(d_const.0.map(|x| x.into())); row.d_mul_f - .eval::>::BaseField, _, _>( + .eval::::BaseField, _, _>( builder, &f, &d_const_expr, @@ -306,7 +254,7 @@ where // x3 = x3_numerator / (1 + d * f). row.x3_ins - .eval::>::BaseField>( + .eval::::BaseField>( builder, &row.x3_numerator.result, &d_mul_f, @@ -315,7 +263,7 @@ where // y3 = y3_numerator / (1 - d * f). row.y3_ins - .eval::>::BaseField>( + .eval::::BaseField>( builder, &row.y3_numerator.result, &d_mul_f, diff --git a/core/src/syscall/precompiles/edwards/ed_decompress.rs b/core/src/syscall/precompiles/edwards/ed_decompress.rs index a45930447d..5ddd434e13 100644 --- a/core/src/syscall/precompiles/edwards/ed_decompress.rs +++ b/core/src/syscall/precompiles/edwards/ed_decompress.rs @@ -17,8 +17,8 @@ use crate::utils::bytes_to_words_le; use crate::utils::ec::edwards::ed25519::decompress; use crate::utils::ec::edwards::ed25519::ed25519_sqrt; use crate::utils::ec::edwards::EdwardsParameters; +use crate::utils::ec::field::limbs_from_vec; use crate::utils::ec::field::FieldParameters; -use crate::utils::ec::EllipticCurveParameters; use crate::utils::ec::COMPRESSED_POINT_BYTES; use crate::utils::ec::NUM_BYTES_FIELD_ELEMENT; use crate::utils::ec::NUM_WORDS_FIELD_ELEMENT; @@ -82,7 +82,7 @@ pub struct EdDecompressCols { } impl EdDecompressCols { - pub fn populate, E: EdwardsParameters>( + pub fn populate( &mut self, event: EdDecompressEvent, record: &mut ExecutionRecord, @@ -103,10 +103,7 @@ impl EdDecompressCols { record.add_field_events(&new_field_events); } - fn populate_field_ops, E: EdwardsParameters>( - &mut self, - y: &BigUint, - ) { + fn populate_field_ops(&mut self, y: &BigUint) { let one = BigUint::one(); let yy = self.yy.populate::

(y, y, FieldOperation::Mul); let u = self.u.populate::

(&yy, &one, FieldOperation::Sub); @@ -122,7 +119,7 @@ impl EdDecompressCols { } impl EdDecompressCols { - pub fn eval, P: FieldParameters, E: EdwardsParameters>( + pub fn eval, P: FieldParameters, E: EdwardsParameters>( &self, builder: &mut AB, ) where @@ -143,9 +140,8 @@ impl EdDecompressCols { FieldOperation::Sub, ); let d_biguint = E::d_biguint(); - let d_const = >::BaseField::to_limbs_field::( - &d_biguint, - ); + let d_const = E::BaseField::to_limbs_field::(&d_biguint); + let d_const = limbs_from_vec::(d_const); self.dyy .eval::(builder, &d_const, &self.yy.result, FieldOperation::Mul); self.v.eval::( @@ -296,7 +292,7 @@ impl MachineAir for EdDecompressChip = row.as_mut_slice().borrow_mut(); - cols.populate::<>::BaseField, E>(event, output); + cols.populate::(event, output); rows.push(row); } @@ -305,9 +301,7 @@ impl MachineAir for EdDecompressChip = row.as_mut_slice().borrow_mut(); let zero = BigUint::zero(); - cols.populate_field_ops::<>::BaseField, E>( - &zero, - ); + cols.populate_field_ops::(&zero); row }); @@ -331,7 +325,7 @@ where fn eval(&self, builder: &mut AB) { let main = builder.main(); let row: &EdDecompressCols = main.row_slice(0).borrow(); - row.eval::>::BaseField, E>(builder); + row.eval::(builder); } } diff --git a/core/src/syscall/precompiles/k256/decompress.rs b/core/src/syscall/precompiles/k256/decompress.rs index 47180224c1..31e38d9a7b 100644 --- a/core/src/syscall/precompiles/k256/decompress.rs +++ b/core/src/syscall/precompiles/k256/decompress.rs @@ -9,10 +9,12 @@ use crate::memory::MemoryReadWriteCols; use crate::operations::field::field_op::FieldOpCols; use crate::operations::field::field_op::FieldOperation; use crate::operations::field::field_sqrt::FieldSqrtCols; +use crate::operations::field::params::Limbs; use crate::runtime::ExecutionRecord; use crate::runtime::Syscall; use crate::syscall::precompiles::SyscallContext; use crate::utils::bytes_to_words_le; +use crate::utils::ec::field::limbs_from_vec; use crate::utils::ec::field::FieldParameters; use crate::utils::ec::weierstrass::secp256k1::secp256k1_sqrt; use crate::utils::ec::weierstrass::secp256k1::Secp256k1BaseField; @@ -44,6 +46,7 @@ use sp1_derive::AlignedBorrow; use std::fmt::Debug; use super::NUM_LIMBS; +use super::NUM_WITNESS_LIMBS; #[derive(Debug, Clone, Copy)] pub struct K256DecompressEvent { @@ -146,11 +149,11 @@ pub struct K256DecompressCols { pub ptr: T, pub x_access: [MemoryReadCols; NUM_WORDS_FIELD_ELEMENT], pub y_access: [MemoryReadWriteCols; NUM_WORDS_FIELD_ELEMENT], - pub(crate) x_2: FieldOpCols, - pub(crate) x_3: FieldOpCols, - pub(crate) x_3_plus_b: FieldOpCols, - pub(crate) y: FieldSqrtCols, - pub(crate) neg_y: FieldOpCols, + pub(crate) x_2: FieldOpCols, + pub(crate) x_3: FieldOpCols, + pub(crate) x_3_plus_b: FieldOpCols, + pub(crate) y: FieldSqrtCols, + pub(crate) neg_y: FieldOpCols, pub(crate) y_least_bits: [T; 8], } @@ -208,7 +211,7 @@ impl K256DecompressCols { let should_be_odd: AB::Expr = self.y_access[0].prev_value[0].into(); builder.assert_bool(should_be_odd.clone()); - let x = limbs_from_prev_access(&self.x_access); + let x: Limbs = limbs_from_prev_access(&self.x_access); self.x_2 .eval::(builder, &x, &x, FieldOperation::Mul); self.x_3.eval::( @@ -219,6 +222,7 @@ impl K256DecompressCols { ); let b = Secp256k1Parameters::b_int(); let b_const = Secp256k1BaseField::to_limbs_field::(&b); + let b_const = limbs_from_vec::(b_const); self.x_3_plus_b.eval::( builder, &self.x_3.result, @@ -255,7 +259,7 @@ impl K256DecompressCols { // When y_is_odd == should_be_odd, result is y // Equivalent: y_is_odd != !should_be_odd - let y_limbs = limbs_from_access(&self.y_access); + let y_limbs: Limbs = limbs_from_access(&self.y_access); builder .when(self.is_real) .when_ne(y_is_odd.into(), AB::Expr::one() - should_be_odd.clone()) diff --git a/core/src/syscall/precompiles/k256/mod.rs b/core/src/syscall/precompiles/k256/mod.rs index 2c0c353fc2..c65a9f3448 100644 --- a/core/src/syscall/precompiles/k256/mod.rs +++ b/core/src/syscall/precompiles/k256/mod.rs @@ -4,3 +4,6 @@ pub use decompress::*; // The number of limbs in the field representation. const NUM_LIMBS: usize = 32; + +/// The number of `u8` witness limbs in the field representation. +const NUM_WITNESS_LIMBS: usize = 2 * NUM_LIMBS - 2; diff --git a/core/src/syscall/precompiles/mod.rs b/core/src/syscall/precompiles/mod.rs index b920f06c06..07e1f5047a 100644 --- a/core/src/syscall/precompiles/mod.rs +++ b/core/src/syscall/precompiles/mod.rs @@ -1,9 +1,9 @@ pub mod blake3; pub mod edwards; -// pub mod k256; +pub mod k256; pub mod keccak256; pub mod sha256; -// pub mod weierstrass; +pub mod weierstrass; use num::BigUint; @@ -13,6 +13,7 @@ use crate::runtime::SyscallContext; use crate::utils::ec::field::FieldParameters; use crate::utils::ec::{AffinePoint, EllipticCurve}; use crate::{cpu::MemoryReadRecord, cpu::MemoryWriteRecord}; +use p3_field::AbstractField; /// Number of `u8` limbs in the field representation. const NUM_LIMBS: usize = 32; @@ -31,7 +32,7 @@ pub struct ECAddEvent { pub q_memory_records: [MemoryReadRecord; 16], } -pub fn create_ec_add_event>(rt: &mut SyscallContext) -> ECAddEvent { +pub fn create_ec_add_event(rt: &mut SyscallContext) -> ECAddEvent { let a0 = crate::runtime::Register::X10; let a1 = crate::runtime::Register::X11; @@ -55,10 +56,10 @@ pub fn create_ec_add_event>(rt: &mut SyscallContext) // When we write to p, we want the clk to be incremented. rt.clk += 4; - let p_affine = AffinePoint::::from_words_le(&p); - let q_affine = AffinePoint::::from_words_le(&q); + let p_affine = AffinePoint::::from_words_le(&p); + let q_affine = AffinePoint::::from_words_le(&q); let result_affine = p_affine + q_affine; - let result_words = result_affine.to_words_le(); + let result_words = result_affine.to_words_le::(); let p_memory_records = rt.mw_slice(p_ptr, &result_words).try_into().unwrap(); @@ -87,9 +88,7 @@ pub struct ECDoubleEvent { pub p_memory_records: [MemoryWriteRecord; 16], } -pub fn create_ec_double_event>( - rt: &mut SyscallContext, -) -> ECDoubleEvent { +pub fn create_ec_double_event(rt: &mut SyscallContext) -> ECDoubleEvent { let a0 = crate::runtime::Register::X10; let start_clk = rt.clk; @@ -105,9 +104,9 @@ pub fn create_ec_double_event>( // When we write to p, we want the clk to be incremented. rt.clk += 4; - let p_affine = AffinePoint::::from_words_le(&p); + let p_affine = AffinePoint::::from_words_le(&p); let result_affine = E::ec_double(&p_affine); - let result_words = result_affine.to_words_le(); + let result_words = result_affine.to_words_le::(); let p_memory_records = rt.mw_slice(p_ptr, &result_words).try_into().unwrap(); @@ -122,12 +121,13 @@ pub fn create_ec_double_event>( } } -pub fn limbs_from_biguint>( - value: &BigUint, -) -> Limbs +pub fn limbs_from_biguint(value: &BigUint) -> Limbs where AB: SP1AirBuilder, { let a_const = F::to_limbs_field::(value); - Limbs::(a_const.0.map(|x| x.into())) + debug_assert_eq!(a_const.len(), NUM_LIMBS); + let mut a = [AB::F::zero(); NUM_LIMBS]; + a[..NUM_LIMBS].copy_from_slice(&a_const[..NUM_LIMBS]); + Limbs::(a.map(|x| x.into())) } diff --git a/core/src/syscall/precompiles/weierstrass/mod.rs b/core/src/syscall/precompiles/weierstrass/mod.rs index 02257fe555..3f02fedc72 100644 --- a/core/src/syscall/precompiles/weierstrass/mod.rs +++ b/core/src/syscall/precompiles/weierstrass/mod.rs @@ -6,3 +6,6 @@ pub use weierstrass_double::*; // The number of `u8` limbs in the field representation. const NUM_LIMBS: usize = 32; + +/// The number of `u8` witness limbs in the field representation. +const NUM_WITNESS_LIMBS: usize = 2 * NUM_LIMBS - 2; diff --git a/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs b/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs index dafef6c4b6..e0c34cc27e 100644 --- a/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs +++ b/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs @@ -5,6 +5,7 @@ use crate::memory::MemoryReadCols; use crate::memory::MemoryWriteCols; use crate::operations::field::field_op::FieldOpCols; use crate::operations::field::field_op::FieldOperation; +use crate::operations::field::params::Limbs; use crate::runtime::ExecutionRecord; use crate::runtime::Register; use crate::runtime::Syscall; @@ -32,6 +33,7 @@ use std::fmt::Debug; use std::marker::PhantomData; use super::NUM_LIMBS; +use super::NUM_WITNESS_LIMBS; pub const NUM_WEIERSTRASS_ADD_COLS: usize = size_of::>(); @@ -50,15 +52,15 @@ pub struct WeierstrassAddAssignCols { pub q_ptr_access: MemoryReadCols, pub p_access: [MemoryWriteCols; NUM_WORDS_EC_POINT], pub q_access: [MemoryReadCols; NUM_WORDS_EC_POINT], - pub(crate) slope_denominator: FieldOpCols, - pub(crate) slope_numerator: FieldOpCols, - pub(crate) slope: FieldOpCols, - pub(crate) slope_squared: FieldOpCols, - pub(crate) p_x_plus_q_x: FieldOpCols, - pub(crate) x3_ins: FieldOpCols, - pub(crate) p_x_minus_x: FieldOpCols, - pub(crate) y3_ins: FieldOpCols, - pub(crate) slope_times_p_x_minus_x: FieldOpCols, + pub(crate) slope_denominator: FieldOpCols, + pub(crate) slope_numerator: FieldOpCols, + pub(crate) slope: FieldOpCols, + pub(crate) slope_squared: FieldOpCols, + pub(crate) p_x_plus_q_x: FieldOpCols, + pub(crate) x3_ins: FieldOpCols, + pub(crate) p_x_minus_x: FieldOpCols, + pub(crate) y3_ins: FieldOpCols, + pub(crate) slope_times_p_x_minus_x: FieldOpCols, } #[derive(Default)] @@ -66,7 +68,7 @@ pub struct WeierstrassAddAssignChip { _marker: PhantomData, } -impl> Syscall for WeierstrassAddAssignChip { +impl Syscall for WeierstrassAddAssignChip { fn execute(&self, rt: &mut SyscallContext) -> u32 { let event = create_ec_add_event::(rt); rt.record_mut().weierstrass_add_events.push(event); @@ -78,7 +80,7 @@ impl> Syscall for WeierstrassAddAssignChip { } } -impl> WeierstrassAddAssignChip { +impl WeierstrassAddAssignChip { pub fn new() -> Self { Self { _marker: PhantomData, @@ -143,7 +145,7 @@ impl> WeierstrassAddAssignChip { } } -impl + WeierstrassParameters> MachineAir +impl MachineAir for WeierstrassAddAssignChip { fn name(&self) -> String { @@ -167,9 +169,9 @@ impl + WeierstrassParameters::from_words_le(p); + let p = AffinePoint::::from_words_le(p); let (p_x, p_y) = (p.x, p.y); - let q = AffinePoint::::from_words_le(q); + let q = AffinePoint::::from_words_le(q); let (q_x, q_y) = (q.x, q.y); // Populate basic columns. @@ -211,13 +213,13 @@ impl + WeierstrassParameters> BaseAir for WeierstrassAddAssignChip { +impl BaseAir for WeierstrassAddAssignChip { fn width(&self) -> usize { NUM_WEIERSTRASS_ADD_COLS } } -impl> Air for WeierstrassAddAssignChip +impl Air for WeierstrassAddAssignChip where AB: SP1AirBuilder, { @@ -225,11 +227,15 @@ where let main = builder.main(); let row: &WeierstrassAddAssignCols = main.row_slice(0).borrow(); - let p_x = limbs_from_prev_access(&row.p_access[0..NUM_WORDS_FIELD_ELEMENT]); - let p_y = limbs_from_prev_access(&row.p_access[NUM_WORDS_FIELD_ELEMENT..]); + let p_x: Limbs<::Var, NUM_LIMBS> = + limbs_from_prev_access(&row.p_access[0..NUM_WORDS_FIELD_ELEMENT]); + let p_y: Limbs<::Var, NUM_LIMBS> = + limbs_from_prev_access(&row.p_access[NUM_WORDS_FIELD_ELEMENT..]); - let q_x = limbs_from_prev_access(&row.q_access[0..NUM_WORDS_FIELD_ELEMENT]); - let q_y = limbs_from_prev_access(&row.q_access[NUM_WORDS_FIELD_ELEMENT..]); + let q_x: Limbs<::Var, NUM_LIMBS> = + limbs_from_prev_access(&row.q_access[0..NUM_WORDS_FIELD_ELEMENT]); + let q_y: Limbs<::Var, NUM_LIMBS> = + limbs_from_prev_access(&row.q_access[NUM_WORDS_FIELD_ELEMENT..]); // slope = (q.y - p.y) / (q.x - p.x). let slope = { diff --git a/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs b/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs index e24284c1ae..d4589ab317 100644 --- a/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs +++ b/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs @@ -4,6 +4,7 @@ use crate::memory::MemoryCols; use crate::memory::MemoryWriteCols; use crate::operations::field::field_op::FieldOpCols; use crate::operations::field::field_op::FieldOperation; +use crate::operations::field::params::Limbs; use crate::runtime::ExecutionRecord; use crate::runtime::Syscall; use crate::syscall::precompiles::create_ec_double_event; @@ -31,6 +32,7 @@ use std::fmt::Debug; use std::marker::PhantomData; use super::NUM_LIMBS; +use super::NUM_WITNESS_LIMBS; pub const NUM_WEIERSTRASS_DOUBLE_COLS: usize = size_of::>(); @@ -46,17 +48,17 @@ pub struct WeierstrassDoubleAssignCols { pub clk: T, pub p_ptr: T, pub p_access: [MemoryWriteCols; NUM_WORDS_EC_POINT], - pub(crate) slope_denominator: FieldOpCols, - pub(crate) slope_numerator: FieldOpCols, - pub(crate) slope: FieldOpCols, - pub(crate) p_x_squared: FieldOpCols, - pub(crate) p_x_squared_times_3: FieldOpCols, - pub(crate) slope_squared: FieldOpCols, - pub(crate) p_x_plus_p_x: FieldOpCols, - pub(crate) x3_ins: FieldOpCols, - pub(crate) p_x_minus_x: FieldOpCols, - pub(crate) y3_ins: FieldOpCols, - pub(crate) slope_times_p_x_minus_x: FieldOpCols, + pub(crate) slope_denominator: FieldOpCols, + pub(crate) slope_numerator: FieldOpCols, + pub(crate) slope: FieldOpCols, + pub(crate) p_x_squared: FieldOpCols, + pub(crate) p_x_squared_times_3: FieldOpCols, + pub(crate) slope_squared: FieldOpCols, + pub(crate) p_x_plus_p_x: FieldOpCols, + pub(crate) x3_ins: FieldOpCols, + pub(crate) p_x_minus_x: FieldOpCols, + pub(crate) y3_ins: FieldOpCols, + pub(crate) slope_times_p_x_minus_x: FieldOpCols, } #[derive(Default)] @@ -64,9 +66,7 @@ pub struct WeierstrassDoubleAssignChip { _marker: PhantomData, } -impl + WeierstrassParameters> Syscall - for WeierstrassDoubleAssignChip -{ +impl Syscall for WeierstrassDoubleAssignChip { fn execute(&self, rt: &mut SyscallContext) -> u32 { let event = create_ec_double_event::(rt); rt.record_mut().weierstrass_double_events.push(event); @@ -78,9 +78,7 @@ impl + WeierstrassParameters> Syscall } } -impl + WeierstrassParameters> - WeierstrassDoubleAssignChip -{ +impl WeierstrassDoubleAssignChip { pub fn new() -> Self { Self { _marker: PhantomData, @@ -160,7 +158,7 @@ impl + WeierstrassParameters> } } -impl + WeierstrassParameters> MachineAir +impl MachineAir for WeierstrassDoubleAssignChip { fn name(&self) -> String { @@ -183,7 +181,7 @@ impl + WeierstrassParameters::from_words_le(p); + let p = AffinePoint::::from_words_le(p); let (p_x, p_y) = (p.x, p.y); // Populate basic columns. @@ -219,16 +217,13 @@ impl + WeierstrassParameters + WeierstrassParameters> BaseAir - for WeierstrassDoubleAssignChip -{ +impl BaseAir for WeierstrassDoubleAssignChip { fn width(&self) -> usize { NUM_WEIERSTRASS_DOUBLE_COLS } } -impl + WeierstrassParameters> Air - for WeierstrassDoubleAssignChip +impl Air for WeierstrassDoubleAssignChip where AB: SP1AirBuilder, { @@ -236,11 +231,14 @@ where let main = builder.main(); let row: &WeierstrassDoubleAssignCols = main.row_slice(0).borrow(); - let p_x = limbs_from_prev_access(&row.p_access[0..NUM_WORDS_FIELD_ELEMENT]); - let p_y = limbs_from_prev_access(&row.p_access[NUM_WORDS_FIELD_ELEMENT..]); + let p_x: Limbs<::Var, NUM_LIMBS> = + limbs_from_prev_access(&row.p_access[0..NUM_WORDS_FIELD_ELEMENT]); + let p_y: Limbs<::Var, NUM_LIMBS> = + limbs_from_prev_access(&row.p_access[NUM_WORDS_FIELD_ELEMENT..]); // a in the Weierstrass form: y^2 = x^3 + a * x + b. - let a = limbs_from_biguint::(&E::a_int()); + let a: Limbs<::Expr, NUM_LIMBS> = + limbs_from_biguint::(&E::a_int()); // slope = slope_numerator / slope_denominator. let slope = { diff --git a/core/src/utils/ec/edwards/ed25519.rs b/core/src/utils/ec/edwards/ed25519.rs index b9fa271408..a13c2b64aa 100644 --- a/core/src/utils/ec/edwards/ed25519.rs +++ b/core/src/utils/ec/edwards/ed25519.rs @@ -17,14 +17,15 @@ pub struct Ed25519Parameters; #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] pub struct Ed25519BaseField; -impl FieldParameters for Ed25519BaseField { +impl FieldParameters for Ed25519BaseField { const NB_BITS_PER_LIMB: usize = NB_BITS_PER_LIMB; const NB_LIMBS: usize = NUM_LIMBS; const NB_WITNESS_LIMBS: usize = 2 * Self::NB_LIMBS - 2; - const MODULUS: [u8; NUM_LIMBS] = [ + const MODULUS: &'static [u8] = &[ 237, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127, ]; + const WITNESS_OFFSET: usize = 1usize << 13; fn modulus() -> BigUint { @@ -32,7 +33,7 @@ impl FieldParameters for Ed25519BaseField { } } -impl EllipticCurveParameters for Ed25519Parameters { +impl EllipticCurveParameters for Ed25519Parameters { type BaseField = Ed25519BaseField; } @@ -106,7 +107,7 @@ pub fn ed25519_sqrt(a: &BigUint) -> BigUint { beta } -pub fn decompress(compressed_point: &CompressedEdwardsY) -> AffinePoint { +pub fn decompress(compressed_point: &CompressedEdwardsY) -> AffinePoint { let mut point_bytes = *compressed_point.as_bytes(); let sign = point_bytes[31] >> 7 == 1; // mask out the sign bit @@ -147,7 +148,7 @@ mod tests { // Get the generator point. let mut point = { let (x, y) = Ed25519Parameters::generator(); - AffinePoint::, NUM_LIMBS>::new(x, y) + AffinePoint::>::new(x, y) }; for _ in 0..NUM_TEST_CASES { // Compress the point. The first 255 bits of a compressed point is the y-coordinate. The diff --git a/core/src/utils/ec/edwards/mod.rs b/core/src/utils/ec/edwards/mod.rs index 5a3f5c94dd..6f39778085 100644 --- a/core/src/utils/ec/edwards/mod.rs +++ b/core/src/utils/ec/edwards/mod.rs @@ -8,7 +8,7 @@ use crate::utils::ec::{AffinePoint, EllipticCurve, EllipticCurveParameters}; // The number of `u8` limbs in the base field of Ed25519. const NUM_LIMBS: usize = 32; -pub trait EdwardsParameters: EllipticCurveParameters { +pub trait EdwardsParameters: EllipticCurveParameters { const D: [u16; MAX_NB_LIMBS]; fn generator() -> (BigUint, BigUint); @@ -52,7 +52,7 @@ impl EdwardsParameters for EdwardsCurve { } } -impl EllipticCurveParameters for EdwardsCurve { +impl EllipticCurveParameters for EdwardsCurve { type BaseField = E::BaseField; } @@ -61,45 +61,42 @@ impl EdwardsCurve { E::prime_group_order() } - pub fn neutral() -> AffinePoint { + pub fn neutral() -> AffinePoint { let (x, y) = E::neutral(); AffinePoint::new(x, y) } } -impl EllipticCurve for EdwardsCurve { - fn ec_add( - p: &AffinePoint, - q: &AffinePoint, - ) -> AffinePoint { +impl EllipticCurve for EdwardsCurve { + fn ec_add(p: &AffinePoint, q: &AffinePoint) -> AffinePoint { p.ed_add(q) } - fn ec_double(p: &AffinePoint) -> AffinePoint { + fn ec_double(p: &AffinePoint) -> AffinePoint { p.ed_double() } - fn ec_generator() -> AffinePoint { + fn ec_generator() -> AffinePoint { let (x, y) = E::generator(); AffinePoint::new(x, y) } - fn ec_neutral() -> Option> { + fn ec_neutral() -> Option> { Some(Self::neutral()) } - fn ec_neg(p: &AffinePoint) -> AffinePoint { - let modulus = >::BaseField::modulus(); + fn ec_neg(p: &AffinePoint) -> AffinePoint { + let modulus = E::BaseField::modulus(); AffinePoint::new(&modulus - &p.x, p.y.clone()) } } -impl AffinePoint, NUM_LIMBS> { +impl AffinePoint> { pub(crate) fn ed_add( &self, - other: &AffinePoint, NUM_LIMBS>, - ) -> AffinePoint, NUM_LIMBS> { - let p = >::BaseField::modulus(); + other: &AffinePoint>, + ) -> AffinePoint> { + let p = ::BaseField::modulus(); let x_3n = (&self.x * &other.y + &self.y * &other.x) % &p; let y_3n = (&self.y * &other.y + &self.x * &other.x) % &p; @@ -115,7 +112,7 @@ impl AffinePoint, NUM_LIMBS> { AffinePoint::new(x_3, y_3) } - pub(crate) fn ed_double(&self) -> AffinePoint, NUM_LIMBS> { + pub(crate) fn ed_double(&self) -> AffinePoint> { self.ed_add(self) } } @@ -148,7 +145,7 @@ mod tests { let base = E::ec_generator(); let d = Ed25519Parameters::d_biguint(); - let p = >::BaseField::modulus(); + let p = ::BaseField::modulus(); assert_eq!((d * 121666u32) % &p, (&p - 121665u32) % &p); let mut rng = thread_rng(); diff --git a/core/src/utils/ec/field.rs b/core/src/utils/ec/field.rs index bfbf16d828..bf7d0986cf 100644 --- a/core/src/utils/ec/field.rs +++ b/core/src/utils/ec/field.rs @@ -1,6 +1,5 @@ use super::utils::biguint_from_limbs; -use crate::operations::field::params::Limbs; -use crate::operations::field::params::NB_BITS_PER_LIMB; +use crate::operations::field::params::{Limbs, NB_BITS_PER_LIMB}; use num::BigUint; use p3_field::Field; use serde::{de::DeserializeOwned, Serialize}; @@ -8,17 +7,17 @@ use std::fmt::Debug; pub const MAX_NB_LIMBS: usize = 32; -pub trait FieldParameters: +pub trait FieldParameters: Send + Sync + Copy + 'static + Debug + Serialize + DeserializeOwned { const NB_BITS_PER_LIMB: usize = NB_BITS_PER_LIMB; - const NB_LIMBS: usize = NUM_LIMBS; + const NB_LIMBS: usize; const NB_WITNESS_LIMBS: usize = 2 * Self::NB_LIMBS - 2; const WITNESS_OFFSET: usize = 1usize << 13; - const MODULUS: [u8; NUM_LIMBS]; + const MODULUS: &'static [u8]; fn modulus() -> BigUint { - biguint_from_limbs(&Self::MODULUS) + biguint_from_limbs(Self::MODULUS) } fn nb_bits() -> usize { @@ -27,28 +26,31 @@ pub trait FieldParameters: fn modulus_field_iter() -> impl Iterator { Self::MODULUS - .into_iter() - .map(|x| F::from_canonical_u8(x)) + .iter() + .map(|x| F::from_canonical_u8(*x)) .take(Self::NB_LIMBS) } - fn to_limbs(x: &BigUint) -> Limbs { + fn to_limbs(x: &BigUint) -> Vec { let mut bytes = x.to_bytes_le(); - bytes.resize(NUM_LIMBS, 0u8); - let mut limbs = [0u8; NUM_LIMBS]; - limbs.copy_from_slice(&bytes); - Limbs(limbs) + bytes.resize(Self::NB_LIMBS, 0u8); + bytes } - fn to_limbs_field(x: &BigUint) -> Limbs { - Limbs( - Self::to_limbs(x) - .0 - .into_iter() - .map(|x| F::from_canonical_u8(x)) - .collect::>() - .try_into() - .unwrap(), - ) + fn to_limbs_field(x: &BigUint) -> Vec { + Self::to_limbs(x) + .into_iter() + .map(|x| F::from_canonical_u8(x)) + .collect() + } +} + +/// Convert a vec of u8 limbs to a Limbs of NUM_LIMBS. +pub fn limbs_from_vec(limbs: Vec) -> Limbs { + debug_assert_eq!(limbs.len(), N); + let mut result = [F::zero(); N]; + for (i, limb) in limbs.into_iter().enumerate() { + result[i] = limb; } + Limbs(result) } diff --git a/core/src/utils/ec/mod.rs b/core/src/utils/ec/mod.rs index b10cf45070..f42a442853 100644 --- a/core/src/utils/ec/mod.rs +++ b/core/src/utils/ec/mod.rs @@ -2,7 +2,7 @@ pub mod edwards; pub mod field; pub mod scalar_mul; pub mod utils; -// pub mod weierstrass; +pub mod weierstrass; use field::FieldParameters; use num::BigUint; @@ -21,13 +21,13 @@ pub const COMPRESSED_POINT_BYTES: usize = 32; pub const NUM_WORDS_EC_POINT: usize = 2 * NUM_WORDS_FIELD_ELEMENT; #[derive(Debug, Clone, PartialEq, Eq)] -pub struct AffinePoint { +pub struct AffinePoint { pub x: BigUint, pub y: BigUint, _marker: std::marker::PhantomData, } -impl AffinePoint { +impl AffinePoint { #[allow(dead_code)] pub fn new(x: BigUint, y: BigUint) -> Self { Self { @@ -55,7 +55,7 @@ impl AffinePoint { } } - pub fn to_words_le(&self) -> [u32; 16] { + pub fn to_words_le(&self) -> [u32; 16] { let mut x_bytes = self.x.to_bytes_le(); x_bytes.resize(N, 0u8); let mut y_bytes = self.y.to_bytes_le(); @@ -80,31 +80,34 @@ impl AffinePoint { } } -pub trait EllipticCurveParameters: +pub trait EllipticCurveParameters: Debug + Send + Sync + Copy + Serialize + DeserializeOwned + 'static { - type BaseField: FieldParameters; + type BaseField: FieldParameters; } /// An interface for elliptic curve groups. -pub trait EllipticCurve: EllipticCurveParameters { +pub trait EllipticCurve: EllipticCurveParameters { + const NB_LIMBS: usize = Self::BaseField::NB_LIMBS; + + const NB_WITNESS_LIMBS: usize = Self::BaseField::NB_WITNESS_LIMBS; /// Adds two different points on the curve. /// /// Warning: This method assumes that the two points are different. - fn ec_add(p: &AffinePoint, q: &AffinePoint) -> AffinePoint; + fn ec_add(p: &AffinePoint, q: &AffinePoint) -> AffinePoint; /// Doubles a point on the curve. - fn ec_double(p: &AffinePoint) -> AffinePoint; + fn ec_double(p: &AffinePoint) -> AffinePoint; /// Returns the generator of the curve group for a curve/subgroup of prime order. - fn ec_generator() -> AffinePoint; + fn ec_generator() -> AffinePoint; /// Returns the neutral element of the curve group, if this element is affine (such as in the /// case of the Edwards curve group). Otherwise, returns `None`. - fn ec_neutral() -> Option>; + fn ec_neutral() -> Option>; /// Returns the negative of a point on the curve. - fn ec_neg(p: &AffinePoint) -> AffinePoint; + fn ec_neg(p: &AffinePoint) -> AffinePoint; /// Returns the number of bits needed to represent a scalar in the group. fn nb_scalar_bits() -> usize { @@ -112,42 +115,42 @@ pub trait EllipticCurve: EllipticCurveParameters { } } -impl, const N: usize> Add<&AffinePoint> for &AffinePoint { - type Output = AffinePoint; +impl Add<&AffinePoint> for &AffinePoint { + type Output = AffinePoint; - fn add(self, other: &AffinePoint) -> AffinePoint { + fn add(self, other: &AffinePoint) -> AffinePoint { E::ec_add(self, other) } } -impl, const N: usize> Add> for AffinePoint { - type Output = AffinePoint; +impl Add> for AffinePoint { + type Output = AffinePoint; - fn add(self, other: AffinePoint) -> AffinePoint { + fn add(self, other: AffinePoint) -> AffinePoint { &self + &other } } -impl, const N: usize> Add<&AffinePoint> for AffinePoint { - type Output = AffinePoint; +impl Add<&AffinePoint> for AffinePoint { + type Output = AffinePoint; - fn add(self, other: &AffinePoint) -> AffinePoint { + fn add(self, other: &AffinePoint) -> AffinePoint { &self + other } } -impl, const N: usize> Neg for &AffinePoint { - type Output = AffinePoint; +impl Neg for &AffinePoint { + type Output = AffinePoint; - fn neg(self) -> AffinePoint { + fn neg(self) -> AffinePoint { E::ec_neg(self) } } -impl, const N: usize> Neg for AffinePoint { - type Output = AffinePoint; +impl Neg for AffinePoint { + type Output = AffinePoint; - fn neg(self) -> AffinePoint { + fn neg(self) -> AffinePoint { -&self } } diff --git a/core/src/utils/ec/scalar_mul.rs b/core/src/utils/ec/scalar_mul.rs index 53aca8733d..098b11fc51 100644 --- a/core/src/utils/ec/scalar_mul.rs +++ b/core/src/utils/ec/scalar_mul.rs @@ -6,7 +6,7 @@ use super::utils::biguint_to_bits_le; use super::AffinePoint; use super::EllipticCurve; -impl, const N: usize> AffinePoint { +impl AffinePoint { pub fn scalar_mul(&self, scalar: &BigUint) -> Self { let power_two_modulus = BigUint::one() << E::nb_scalar_bits(); let scalar = scalar % &power_two_modulus; @@ -23,26 +23,26 @@ impl, const N: usize> AffinePoint { } } -impl, const N: usize> Mul<&BigUint> for &AffinePoint { - type Output = AffinePoint; +impl Mul<&BigUint> for &AffinePoint { + type Output = AffinePoint; - fn mul(self, scalar: &BigUint) -> AffinePoint { + fn mul(self, scalar: &BigUint) -> AffinePoint { self.scalar_mul(scalar) } } -impl, const N: usize> Mul for &AffinePoint { - type Output = AffinePoint; +impl Mul for &AffinePoint { + type Output = AffinePoint; - fn mul(self, scalar: BigUint) -> AffinePoint { + fn mul(self, scalar: BigUint) -> AffinePoint { self.scalar_mul(&scalar) } } -impl, const N: usize> Mul for AffinePoint { - type Output = AffinePoint; +impl Mul for AffinePoint { + type Output = AffinePoint; - fn mul(self, scalar: BigUint) -> AffinePoint { + fn mul(self, scalar: BigUint) -> AffinePoint { self.scalar_mul(&scalar) } } diff --git a/core/src/utils/ec/weierstrass/bn254.rs b/core/src/utils/ec/weierstrass/bn254.rs index 6c66a9e1a1..688c3c2c04 100644 --- a/core/src/utils/ec/weierstrass/bn254.rs +++ b/core/src/utils/ec/weierstrass/bn254.rs @@ -11,20 +11,20 @@ const NUM_LIMBS: usize = 16; /// Bn254 curve parameter pub struct Bn254Parameters; -pub type Bn254 = SwCurve; +pub type Bn254 = SwCurve; #[derive(Debug, Default, Clone, Copy, PartialEq, Serialize, Deserialize)] /// Bn254 base field parameter pub struct Bn254BaseField; -impl FieldParameters for Bn254BaseField { +impl FieldParameters for Bn254BaseField { const NB_BITS_PER_LIMB: usize = 16; const NB_LIMBS: usize = NUM_LIMBS; const NB_WITNESS_LIMBS: usize = 2 * Self::NB_LIMBS - 2; - const MODULUS: [u8; 16] = [ + const MODULUS: &'static [u8] = &[ 71, 253, 124, 216, 22, 140, 32, 60, 141, 202, 113, 104, 145, 106, 129, 151, 93, 88, 129, 129, 182, 69, 80, 184, 41, 160, 49, 225, 114, 78, 100, 48, ]; @@ -40,11 +40,11 @@ impl FieldParameters for Bn254BaseField { } } -impl EllipticCurveParameters for Bn254Parameters { +impl EllipticCurveParameters for Bn254Parameters { type BaseField = Bn254BaseField; } -impl WeierstrassParameters for Bn254Parameters { +impl WeierstrassParameters for Bn254Parameters { const A: [u16; MAX_NB_LIMBS] = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -86,7 +86,7 @@ mod tests { #[test] fn test_weierstrass_biguint_scalar_mul() { assert_eq!( - biguint_from_limbs(&Bn254BaseField::MODULUS), + biguint_from_limbs(Bn254BaseField::MODULUS), Bn254BaseField::modulus() ); } diff --git a/core/src/utils/ec/weierstrass/mod.rs b/core/src/utils/ec/weierstrass/mod.rs index d8a9b8fcdb..da0d0e38f2 100644 --- a/core/src/utils/ec/weierstrass/mod.rs +++ b/core/src/utils/ec/weierstrass/mod.rs @@ -9,7 +9,7 @@ pub mod bn254; pub mod secp256k1; /// Parameters that specify a short Weierstrass curve : y^2 = x^3 + ax + b. -pub trait WeierstrassParameters: EllipticCurveParameters { +pub trait WeierstrassParameters: EllipticCurveParameters { const A: [u16; MAX_NB_LIMBS]; const B: [u16; MAX_NB_LIMBS]; @@ -39,9 +39,9 @@ pub trait WeierstrassParameters: EllipticCurveParameters { } #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] -pub struct SwCurve(pub E); +pub struct SwCurve(pub E); -impl, const N: usize> WeierstrassParameters for SwCurve { +impl WeierstrassParameters for SwCurve { const A: [u16; MAX_NB_LIMBS] = E::A; const B: [u16; MAX_NB_LIMBS] = E::B; @@ -66,36 +66,39 @@ impl, const N: usize> WeierstrassParameters for S } } -impl, const N: usize> EllipticCurveParameters for SwCurve { +impl EllipticCurveParameters for SwCurve { type BaseField = E::BaseField; } -impl, const N: usize> EllipticCurve for SwCurve { - fn ec_add(p: &AffinePoint, q: &AffinePoint) -> AffinePoint { +impl EllipticCurve for SwCurve { + const NB_LIMBS: usize = Self::BaseField::NB_LIMBS; + const NB_WITNESS_LIMBS: usize = Self::BaseField::NB_WITNESS_LIMBS; + + fn ec_add(p: &AffinePoint, q: &AffinePoint) -> AffinePoint { p.sw_add(q) } - fn ec_double(p: &AffinePoint) -> AffinePoint { + fn ec_double(p: &AffinePoint) -> AffinePoint { p.sw_double() } - fn ec_generator() -> AffinePoint { + fn ec_generator() -> AffinePoint { let (x, y) = E::generator(); AffinePoint::new(x, y) } - fn ec_neutral() -> Option> { + fn ec_neutral() -> Option> { None } - fn ec_neg(p: &AffinePoint) -> AffinePoint { + fn ec_neg(p: &AffinePoint) -> AffinePoint { let modulus = E::BaseField::modulus(); AffinePoint::new(p.x.clone(), modulus - &p.y) } } -impl, const N: usize> SwCurve { - pub fn generator() -> AffinePoint, N> { +impl SwCurve { + pub fn generator() -> AffinePoint> { let (x, y) = E::generator(); AffinePoint::new(x, y) @@ -110,7 +113,7 @@ impl, const N: usize> SwCurve { } } -impl, const N: usize> AffinePoint, N> { +impl AffinePoint> { pub fn sw_scalar_mul(&self, scalar: &BigUint) -> Self { let mut result: Option>> = None; let mut temp = self.clone(); @@ -125,8 +128,8 @@ impl, const N: usize> AffinePoint, N> } } -impl, const N: usize> AffinePoint, N> { - pub fn sw_add(&self, other: &AffinePoint, N>) -> AffinePoint, N> { +impl AffinePoint> { + pub fn sw_add(&self, other: &AffinePoint>) -> AffinePoint> { if self.x == other.x && self.y == other.y { panic!("Error: Points are the same. Use sw_double instead."); } @@ -142,7 +145,7 @@ impl, const N: usize> AffinePoint, N> AffinePoint::new(x_3n, y_3n) } - pub fn sw_double(&self) -> AffinePoint, N> { + pub fn sw_double(&self) -> AffinePoint> { let p = E::BaseField::modulus(); let a = E::a_int(); let slope_numerator = (&a + &(&self.x * &self.x) * 3u32) % &p; diff --git a/core/src/utils/ec/weierstrass/secp256k1.rs b/core/src/utils/ec/weierstrass/secp256k1.rs index 2c8ada81a0..40ec280c96 100644 --- a/core/src/utils/ec/weierstrass/secp256k1.rs +++ b/core/src/utils/ec/weierstrass/secp256k1.rs @@ -21,20 +21,20 @@ const NUM_LIMBS: usize = 32; /// Secp256k1 curve parameter pub struct Secp256k1Parameters; -pub type Secp256k1 = SwCurve; +pub type Secp256k1 = SwCurve; #[derive(Debug, Default, Clone, Copy, PartialEq, Serialize, Deserialize)] /// Secp256k1 base field parameter pub struct Secp256k1BaseField; -impl FieldParameters for Secp256k1BaseField { +impl FieldParameters for Secp256k1BaseField { const NB_BITS_PER_LIMB: usize = NB_BITS_PER_LIMB; const NB_LIMBS: usize = NUM_LIMBS; const NB_WITNESS_LIMBS: usize = 2 * Self::NB_LIMBS - 2; - const MODULUS: [u8; MAX_NB_LIMBS] = [ + const MODULUS: &'static [u8] = &[ 0x2f, 0xfc, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, @@ -44,15 +44,15 @@ impl FieldParameters for Secp256k1BaseField { const WITNESS_OFFSET: usize = 1usize << 14; fn modulus() -> BigUint { - BigUint::from_bytes_le(&Self::MODULUS) + BigUint::from_bytes_le(Self::MODULUS) } } -impl EllipticCurveParameters for Secp256k1Parameters { +impl EllipticCurveParameters for Secp256k1Parameters { type BaseField = Secp256k1BaseField; } -impl WeierstrassParameters for Secp256k1Parameters { +impl WeierstrassParameters for Secp256k1Parameters { const A: [u16; MAX_NB_LIMBS] = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -110,7 +110,7 @@ mod tests { #[test] fn test_weierstrass_biguint_scalar_mul() { assert_eq!( - biguint_from_limbs(&Secp256k1BaseField::MODULUS), + biguint_from_limbs(Secp256k1BaseField::MODULUS), Secp256k1BaseField::modulus() ); } diff --git a/tests/secp256k1-add/Cargo.lock b/tests/secp256k1-add/Cargo.lock index 2b703f04b5..08d26df412 100644 --- a/tests/secp256k1-add/Cargo.lock +++ b/tests/secp256k1-add/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "anyhow" -version = "1.0.79" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" +checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" [[package]] name = "autocfg" @@ -261,28 +261,27 @@ dependencies = [ [[package]] name = "num-complex" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214" +checksum = "23c6602fda94a57c990fe0df199a035d83576b496aa29f4e634a8ac6004e68a6" dependencies = [ "num-traits", ] [[package]] name = "num-integer" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "autocfg", "num-traits", ] [[package]] name = "num-iter" -version = "0.1.43" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9" dependencies = [ "autocfg", "num-integer", @@ -302,9 +301,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.17" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" dependencies = [ "autocfg", ] @@ -420,18 +419,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.196" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.196" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", @@ -504,9 +503,9 @@ checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] name = "syn" -version = "2.0.48" +version = "2.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" dependencies = [ "proc-macro2", "quote", diff --git a/tests/secp256k1-add/elf/riscv32im-succinct-zkvm-elf b/tests/secp256k1-add/elf/riscv32im-succinct-zkvm-elf index 99d3cb18c56196863785fe9ebab8993135faaabe..89fa1983471188154c69f328a7fc10c22eca940c 100755 GIT binary patch literal 101748 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�^m=)Ho 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 Date: Wed, 20 Mar 2024 18:20:01 -0700 Subject: [PATCH 04/18] wip --- Cargo.lock | 21 ++++-- core/Cargo.toml | 2 + core/src/lib.rs | 1 + core/src/operations/field/field_den.rs | 68 ++++++++++-------- .../operations/field/field_inner_product.rs | 69 ++++++++++-------- core/src/operations/field/field_op.rs | 65 ++++++++--------- core/src/operations/field/field_sqrt.rs | 49 +++++++------ core/src/operations/field/params.rs | 37 +++++++--- core/src/operations/field/util_air.rs | 2 +- .../src/syscall/precompiles/edwards/ed_add.rs | 28 ++++---- .../precompiles/edwards/ed_decompress.rs | 24 +++---- .../syscall/precompiles/k256/decompress.rs | 21 +++--- core/src/syscall/precompiles/mod.rs | 5 +- .../weierstrass/weierstrass_add.rs | 67 +++++++++-------- .../weierstrass/weierstrass_double.rs | 71 +++++++++++-------- core/src/utils/ec/edwards/ed25519.rs | 8 ++- core/src/utils/ec/field.rs | 12 ++-- core/src/utils/ec/weierstrass/bn254.rs | 7 ++ core/src/utils/ec/weierstrass/secp256k1.rs | 8 ++- core/src/utils/mod.rs | 5 +- derive/src/lib.rs | 69 ++++++------------ examples/chess/script/Cargo.lock | 21 ++++-- examples/ed25519/script/Cargo.lock | 21 ++++-- examples/fibonacci-io/script/Cargo.lock | 21 ++++-- examples/fibonacci/script/Cargo.lock | 21 ++++-- examples/io/script/Cargo.lock | 21 ++++-- examples/json/script/Cargo.lock | 21 ++++-- examples/regex/script/Cargo.lock | 21 ++++-- examples/rsa/script/Cargo.lock | 21 ++++-- examples/ssz-withdrawals/script/Cargo.lock | 21 ++++-- examples/tendermint/script/Cargo.lock | 21 ++++-- 31 files changed, 511 insertions(+), 338 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c3278f013b..53cef60dac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -240,7 +240,7 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array", + "generic-array 0.14.7", ] [[package]] @@ -525,7 +525,7 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ - "generic-array", + "generic-array 0.14.7", "rand_core", "subtle", "zeroize", @@ -537,7 +537,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array", + "generic-array 0.14.7", "typenum", ] @@ -708,7 +708,7 @@ dependencies = [ "crypto-bigint", "digest", "ff", - "generic-array", + "generic-array 0.14.7", "group", "pkcs8", "rand_core", @@ -921,6 +921,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "generic-array" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe739944a5406424e080edccb6add95685130b9f160d5407c639c7df0c5836b0" +dependencies = [ + "typenum", +] + [[package]] name = "getrandom" version = "0.2.12" @@ -2206,7 +2215,7 @@ checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ "base16ct", "der", - "generic-array", + "generic-array 0.14.7", "pkcs8", "subtle", "zeroize", @@ -2400,6 +2409,7 @@ dependencies = [ "elf", "elliptic-curve", "flate2", + "generic-array 1.0.0", "hashbrown", "hex", "itertools 0.12.1", @@ -2442,6 +2452,7 @@ dependencies = [ "tracing-forest", "tracing-log", "tracing-subscriber", + "typenum", ] [[package]] diff --git a/core/Cargo.toml b/core/Cargo.toml index 01c6b201ca..48cdb33859 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -58,6 +58,8 @@ num_cpus = "1.16.0" blake3 = "1.5" blake3-zkvm = { git = "https://github.com/sp1-patches/BLAKE3.git", branch = "patch-blake3_zkvm/v.1.0.0" } cfg-if = "1.0.0" +generic-array = { version = "1.0.0", features = ["alloc"] } +typenum = "1.17.0" [dev-dependencies] criterion = "0.5.1" diff --git a/core/src/lib.rs b/core/src/lib.rs index 72b256a235..a1d1fa9d13 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -10,6 +10,7 @@ clippy::default_constructed_unit_structs, clippy::box_default )] +#![feature(generic_const_exprs)] extern crate alloc; diff --git a/core/src/operations/field/field_den.rs b/core/src/operations/field/field_den.rs index 99db6e3ee3..deec12c4a4 100644 --- a/core/src/operations/field/field_den.rs +++ b/core/src/operations/field/field_den.rs @@ -1,4 +1,4 @@ -use super::params::Limbs; +use super::params::{Limbs, NumLimbs}; use super::util::{compute_root_quotient_and_shift, split_u16_limbs_to_u8_limbs}; use super::util_air::eval_field_operation; use crate::air::Polynomial; @@ -19,15 +19,15 @@ use std::fmt::Debug; /// or made generic in the future. #[derive(Debug, Clone, AlignedBorrow)] #[repr(C)] -pub struct FieldDenCols { +pub struct FieldDenCols { /// The result of `a den b`, where a, b are field elements - pub result: Limbs, - pub(crate) carry: Limbs, - pub(crate) witness_low: [T; M], - pub(crate) witness_high: [T; M], + pub result: Limbs, + pub(crate) carry: Limbs, + pub(crate) witness_low: Limbs, + pub(crate) witness_high: Limbs, } -impl FieldDenCols { +impl FieldDenCols { pub fn populate( &mut self, a: &BigUint, @@ -53,12 +53,13 @@ impl FieldDenCols { debug_assert!(carry < p); debug_assert_eq!(&carry * &p, &equation_lhs - &equation_rhs); - let p_a: Polynomial = limbs_from_vec::(P::to_limbs_field::(a)).into(); - let p_b: Polynomial = limbs_from_vec::(P::to_limbs_field::(b)).into(); - let p_p: Polynomial = limbs_from_vec::(P::to_limbs_field::(&p)).into(); + let p_a: Polynomial = limbs_from_vec::(P::to_limbs_field::(a)).into(); + let p_b: Polynomial = limbs_from_vec::(P::to_limbs_field::(b)).into(); + let p_p: Polynomial = limbs_from_vec::(P::to_limbs_field::(&p)).into(); let p_result: Polynomial = - limbs_from_vec::(P::to_limbs_field::(&result)).into(); - let p_carry: Polynomial = limbs_from_vec::(P::to_limbs_field::(&carry)).into(); + limbs_from_vec::(P::to_limbs_field::(&result)).into(); + let p_carry: Polynomial = + limbs_from_vec::(P::to_limbs_field::(&carry)).into(); // Compute the vanishing polynomial. let vanishing_poly = if sign { @@ -77,20 +78,23 @@ impl FieldDenCols { self.result = p_result.into(); self.carry = p_carry.into(); - self.witness_low = p_witness_low.try_into().unwrap(); - self.witness_high = p_witness_high.try_into().unwrap(); + self.witness_low = Limbs(p_witness_low.try_into().unwrap()); + self.witness_high = Limbs(p_witness_high.try_into().unwrap()); result } } -impl FieldDenCols { +impl FieldDenCols +where + Limbs: Copy, +{ #[allow(unused_variables)] pub fn eval, P: FieldParameters>( &self, builder: &mut AB, - a: &Limbs, - b: &Limbs, + a: &Limbs, + b: &Limbs, sign: bool, ) where V: Into, @@ -116,10 +120,10 @@ impl FieldDenCols { let p_vanishing = p_lhs_minus_rhs - &p_carry * &p_limbs; - let p_witness_low = self.witness_low.iter().into(); - let p_witness_high = self.witness_high.iter().into(); + let p_witness_low = self.witness_low.0.iter().into(); + let p_witness_high = self.witness_high.0.iter().into(); - eval_field_operation::(builder, &p_vanishing, &p_witness_low, &p_witness_high); + eval_field_operation::(builder, &p_vanishing, &p_witness_low, &p_witness_high); } } @@ -128,11 +132,13 @@ mod tests { use num::BigUint; use p3_air::BaseAir; use p3_field::{Field, PrimeField32}; + use typenum::U32; use super::{FieldDenCols, Limbs}; use crate::air::MachineAir; + use crate::operations::field::params::NumLimbs32; use crate::utils::ec::edwards::ed25519::Ed25519BaseField; use crate::utils::ec::field::{limbs_from_vec, FieldParameters}; use crate::utils::{uni_stark_prove as prove, uni_stark_verify as verify}; @@ -148,17 +154,19 @@ mod tests { use rand::thread_rng; use sp1_derive::AlignedBorrow; + type Limbs32 = U32; + #[derive(Debug, Clone, AlignedBorrow)] - pub struct TestCols { - pub a: Limbs, - pub b: Limbs, - pub a_den_b: FieldDenCols, + pub struct TestCols { + pub a: Limbs, + pub b: Limbs, + pub a_den_b: FieldDenCols, } const NUM_LIMBS: usize = 32; const NUM_WITNESS_LIMBS: usize = NUM_LIMBS * 2 - 2; - pub const NUM_TEST_COLS: usize = size_of::>(); + pub const NUM_TEST_COLS: usize = size_of::>(); struct FieldDenChip { pub sign: bool, @@ -208,10 +216,9 @@ mod tests { .iter() .map(|(a, b)| { let mut row = [F::zero(); NUM_TEST_COLS]; - let cols: &mut TestCols = - row.as_mut_slice().borrow_mut(); - cols.a = limbs_from_vec::(P::to_limbs_field::(a)); - cols.b = limbs_from_vec::(P::to_limbs_field::(b)); + let cols: &mut TestCols = row.as_mut_slice().borrow_mut(); + cols.a = limbs_from_vec::(P::to_limbs_field::(a)); + cols.b = limbs_from_vec::(P::to_limbs_field::(b)); cols.a_den_b.populate::

(a, b, self.sign); row }) @@ -239,8 +246,7 @@ mod tests { { fn eval(&self, builder: &mut AB) { let main = builder.main(); - let local: &TestCols = - main.row_slice(0).borrow(); + let local: &TestCols = main.row_slice(0).borrow(); local .a_den_b .eval::(builder, &local.a, &local.b, self.sign); diff --git a/core/src/operations/field/field_inner_product.rs b/core/src/operations/field/field_inner_product.rs index 8f8ac339bf..9e4160de7f 100644 --- a/core/src/operations/field/field_inner_product.rs +++ b/core/src/operations/field/field_inner_product.rs @@ -1,4 +1,4 @@ -use super::params::Limbs; +use super::params::{Limbs, NumLimbs}; use super::util::{compute_root_quotient_and_shift, split_u16_limbs_to_u8_limbs}; use super::util_air::eval_field_operation; use crate::air::Polynomial; @@ -16,23 +16,23 @@ use std::fmt::Debug; /// or made generic in the future. #[derive(Debug, Clone, AlignedBorrow)] #[repr(C)] -pub struct FieldInnerProductCols { +pub struct FieldInnerProductCols { /// The result of `a inner product b`, where a, b are field elements - pub result: Limbs, - pub(crate) carry: Limbs, - pub(crate) witness_low: [T; M], - pub(crate) witness_high: [T; M], + pub result: Limbs, + pub(crate) carry: Limbs, + pub(crate) witness_low: Limbs, + pub(crate) witness_high: Limbs, } -impl FieldInnerProductCols { +impl FieldInnerProductCols { pub fn populate(&mut self, a: &[BigUint], b: &[BigUint]) -> BigUint { let p_a_vec: Vec> = a .iter() - .map(|x| limbs_from_vec::(P::to_limbs_field::(x)).into()) + .map(|x| limbs_from_vec::(P::to_limbs_field::(x)).into()) .collect(); let p_b_vec: Vec> = b .iter() - .map(|x| limbs_from_vec::(P::to_limbs_field::(x)).into()) + .map(|x| limbs_from_vec::(P::to_limbs_field::(x)).into()) .collect(); let modulus = &P::modulus(); @@ -48,9 +48,11 @@ impl FieldInnerProductCols = - limbs_from_vec::(P::to_limbs_field::(modulus)).into(); - let p_result: Polynomial = limbs_from_vec::(P::to_limbs_field::(result)).into(); - let p_carry: Polynomial = limbs_from_vec::(P::to_limbs_field::(carry)).into(); + limbs_from_vec::(P::to_limbs_field::(modulus)).into(); + let p_result: Polynomial = + limbs_from_vec::(P::to_limbs_field::(result)).into(); + let p_carry: Polynomial = + limbs_from_vec::(P::to_limbs_field::(carry)).into(); // Compute the vanishing polynomial. let p_inner_product = p_a_vec @@ -71,20 +73,23 @@ impl FieldInnerProductCols FieldInnerProductCols { +impl FieldInnerProductCols +where + Limbs: Copy, +{ #[allow(unused_variables)] pub fn eval, P: FieldParameters>( &self, builder: &mut AB, - a: &[Limbs], - b: &[Limbs], + a: &[Limbs], + b: &[Limbs], ) where V: Into, { @@ -108,10 +113,10 @@ impl FieldInnerProductCols { let p_carry_mul_modulus = &p_carry * &p_limbs; let p_vanishing = &p_inner_product_minus_result - &(&p_carry * &p_limbs); - let p_witness_low = self.witness_low.iter().into(); - let p_witness_high = self.witness_high.iter().into(); + let p_witness_low = self.witness_low.0.iter().into(); + let p_witness_high = self.witness_high.0.iter().into(); - eval_field_operation::(builder, &p_vanishing, &p_witness_low, &p_witness_high); + eval_field_operation::(builder, &p_vanishing, &p_witness_low, &p_witness_high); } } @@ -120,11 +125,13 @@ mod tests { use num::BigUint; use p3_air::BaseAir; use p3_field::{Field, PrimeField32}; + use typenum::U32; use super::{FieldInnerProductCols, Limbs}; use crate::air::MachineAir; + use crate::operations::field::params::{NumLimbs, NumLimbs32}; use crate::utils::ec::edwards::ed25519::Ed25519BaseField; use crate::utils::ec::field::{limbs_from_vec, FieldParameters}; use crate::utils::{pad_to_power_of_two, BabyBearPoseidon2, StarkUtils}; @@ -141,16 +148,18 @@ mod tests { use sp1_derive::AlignedBorrow; #[derive(AlignedBorrow, Debug, Clone)] - pub struct TestCols { - pub a: [Limbs; 1], - pub b: [Limbs; 1], - pub a_ip_b: FieldInnerProductCols, + pub struct TestCols { + pub a: [Limbs; 1], + pub b: [Limbs; 1], + pub a_ip_b: FieldInnerProductCols, } const NUM_LIMBS: usize = 32; const NUM_WITNESS_LIMBS: usize = 2 * NUM_LIMBS - 2; - pub const NUM_TEST_COLS: usize = size_of::>(); + type Limbs32 = U32; + + pub const NUM_TEST_COLS: usize = size_of::>(); struct FieldIpChip { pub _phantom: std::marker::PhantomData

, @@ -194,10 +203,9 @@ mod tests { .iter() .map(|(a, b)| { let mut row = [F::zero(); NUM_TEST_COLS]; - let cols: &mut TestCols = - row.as_mut_slice().borrow_mut(); - cols.a[0] = limbs_from_vec::(P::to_limbs_field::(&a[0])); - cols.b[0] = limbs_from_vec::(P::to_limbs_field::(&b[0])); + let cols: &mut TestCols = row.as_mut_slice().borrow_mut(); + cols.a[0] = limbs_from_vec::(P::to_limbs_field::(&a[0])); + cols.b[0] = limbs_from_vec::(P::to_limbs_field::(&b[0])); cols.a_ip_b.populate::

(a, b); row }) @@ -227,8 +235,7 @@ mod tests { { fn eval(&self, builder: &mut AB) { let main = builder.main(); - let local: &TestCols = - main.row_slice(0).borrow(); + let local: &TestCols = main.row_slice(0).borrow(); local.a_ip_b.eval::(builder, &local.a, &local.b); // A dummy constraint to keep the degree 3. diff --git a/core/src/operations/field/field_op.rs b/core/src/operations/field/field_op.rs index 663016f5db..bb840ffe28 100644 --- a/core/src/operations/field/field_op.rs +++ b/core/src/operations/field/field_op.rs @@ -1,16 +1,16 @@ -use super::params::Limbs; +use super::params::{Limbs, NumLimbs}; use super::util::{compute_root_quotient_and_shift, split_u16_limbs_to_u8_limbs}; use super::util_air::eval_field_operation; use crate::air::Polynomial; use crate::air::SP1AirBuilder; use crate::utils::ec::field::{limbs_from_vec, FieldParameters}; use core::borrow::Borrow; +use generic_array::ArrayLength; use num::{BigUint, Zero}; use p3_air::AirBuilder; use p3_field::PrimeField32; use sp1_derive::AlignedBorrow; use std::fmt::Debug; -use std::usize; #[derive(PartialEq, Copy, Clone, Debug)] pub enum FieldOperation { @@ -25,15 +25,15 @@ pub enum FieldOperation { /// or made generic in the future. #[derive(Debug, Clone, AlignedBorrow)] #[repr(C)] -pub struct FieldOpCols { +pub struct FieldOpCols { /// The result of `a op b`, where a, b are field elements - pub result: Limbs, - pub(crate) carry: Limbs, - pub(crate) witness_low: [T; M], - pub(crate) witness_high: [T; M], + pub result: Limbs, + pub(crate) carry: Limbs, + pub(crate) witness_low: Limbs, + pub(crate) witness_high: Limbs, } -impl FieldOpCols { +impl FieldOpCols { pub fn populate( &mut self, a: &BigUint, @@ -60,7 +60,7 @@ impl FieldOpCols { // Note that this reversal means we have to flip result, a correspondingly in // the `eval` function. self.populate::

(&result, b, FieldOperation::Add); - self.result = limbs_from_vec::(P::to_limbs_field::(&result)); + self.result = limbs_from_vec::(P::to_limbs_field::(&result)); return result; } @@ -77,12 +77,12 @@ impl FieldOpCols { // Note that this reversal means we have to flip result, a correspondingly in the `eval` // function. self.populate::

(&result, b, FieldOperation::Mul); - self.result = limbs_from_vec::(P::to_limbs_field::(&result)); + self.result = limbs_from_vec::(P::to_limbs_field::(&result)); return result; } - let p_a: Polynomial = limbs_from_vec::(P::to_limbs_field::(a)).into(); - let p_b: Polynomial = limbs_from_vec::(P::to_limbs_field::(b)).into(); + let p_a: Polynomial = limbs_from_vec::(P::to_limbs_field::(a)).into(); + let p_b: Polynomial = limbs_from_vec::(P::to_limbs_field::(b)).into(); // Compute field addition in the integers. let modulus = &P::modulus(); @@ -101,10 +101,11 @@ impl FieldOpCols { // Make little endian polynomial limbs. let p_modulus: Polynomial = - limbs_from_vec::(P::to_limbs_field::(modulus)).into(); + limbs_from_vec::(P::to_limbs_field::(modulus)).into(); let p_result: Polynomial = - limbs_from_vec::(P::to_limbs_field::(&result)).into(); - let p_carry: Polynomial = limbs_from_vec::(P::to_limbs_field::(&carry)).into(); + limbs_from_vec::(P::to_limbs_field::(&result)).into(); + let p_carry: Polynomial = + limbs_from_vec::(P::to_limbs_field::(&carry)).into(); // Compute the vanishing polynomial. let p_op = match op { @@ -131,7 +132,7 @@ impl FieldOpCols { } } -impl FieldOpCols { +impl FieldOpCols { #[allow(unused_variables)] pub fn eval< AB: SP1AirBuilder, @@ -146,6 +147,7 @@ impl FieldOpCols { op: FieldOperation, ) where V: Into, + Limbs: Copy, { let p_a_param: Polynomial = (*a).clone().into(); let p_b: Polynomial = (*b).clone().into(); @@ -162,9 +164,9 @@ impl FieldOpCols { let p_op_minus_result: Polynomial = p_op - p_result; let p_limbs = Polynomial::from_iter(P::modulus_field_iter::().map(AB::Expr::from)); let p_vanishing = p_op_minus_result - &(&p_carry * &p_limbs); - let p_witness_low = self.witness_low.iter().into(); - let p_witness_high = self.witness_high.iter().into(); - eval_field_operation::(builder, &p_vanishing, &p_witness_low, &p_witness_high); + let p_witness_low = self.witness_low.0.iter().into(); + let p_witness_high = self.witness_high.0.iter().into(); + eval_field_operation::(builder, &p_vanishing, &p_witness_low, &p_witness_high); } } @@ -173,11 +175,13 @@ mod tests { use num::BigUint; use p3_air::BaseAir; use p3_field::{Field, PrimeField32}; + use typenum::U32; use super::{FieldOpCols, FieldOperation, Limbs}; use crate::air::MachineAir; + use crate::operations::field::params::NumLimbs32; use crate::utils::ec::edwards::ed25519::Ed25519BaseField; use crate::utils::ec::field::{limbs_from_vec, FieldParameters}; use crate::utils::{pad_to_power_of_two, BabyBearPoseidon2, StarkUtils}; @@ -194,16 +198,15 @@ mod tests { use sp1_derive::AlignedBorrow; #[derive(AlignedBorrow, Debug, Clone)] - pub struct TestCols { - pub a: Limbs, - pub b: Limbs, - pub a_op_b: FieldOpCols, + pub struct TestCols { + pub a: Limbs, + pub b: Limbs, + pub a_op_b: FieldOpCols, } - const NUM_LIMBS: usize = 32; - const NUM_WITNESS_LIMBS: usize = 2 * NUM_LIMBS - 2; + type Limbs32 = U32; - pub const NUM_TEST_COLS: usize = size_of::>(); + pub const NUM_TEST_COLS: usize = size_of::>(); struct FieldOpChip { pub operation: FieldOperation, @@ -253,10 +256,9 @@ mod tests { .iter() .map(|(a, b)| { let mut row = [F::zero(); NUM_TEST_COLS]; - let cols: &mut TestCols = - row.as_mut_slice().borrow_mut(); - cols.a = limbs_from_vec::(P::to_limbs_field::(a)); - cols.b = limbs_from_vec::(P::to_limbs_field::(b)); + let cols: &mut TestCols = row.as_mut_slice().borrow_mut(); + cols.a = limbs_from_vec::(P::to_limbs_field::(a)); + cols.b = limbs_from_vec::(P::to_limbs_field::(b)); cols.a_op_b.populate::

(a, b, self.operation); row }) @@ -286,8 +288,7 @@ mod tests { { fn eval(&self, builder: &mut AB) { let main = builder.main(); - let local: &TestCols = - main.row_slice(0).borrow(); + let local: &TestCols = main.row_slice(0).borrow(); local .a_op_b .eval::(builder, &local.a, &local.b, self.operation); diff --git a/core/src/operations/field/field_sqrt.rs b/core/src/operations/field/field_sqrt.rs index dcec13b700..bcd0cc39e2 100644 --- a/core/src/operations/field/field_sqrt.rs +++ b/core/src/operations/field/field_sqrt.rs @@ -1,5 +1,5 @@ use super::field_op::FieldOpCols; -use super::params::Limbs; +use super::params::{Limbs, NumLimbs}; use crate::air::SP1AirBuilder; use crate::utils::ec::field::{limbs_from_vec, FieldParameters}; use core::borrow::Borrow; @@ -12,15 +12,15 @@ use std::fmt::Debug; /// limb lives. #[derive(Debug, Clone, AlignedBorrow)] #[repr(C)] -pub struct FieldSqrtCols { +pub struct FieldSqrtCols { /// The multiplication operation to verify that the sqrt and the input match. /// /// In order to save space, we actually store the sqrt of the input in `multiplication.result` /// since we'll receive the input again in the `eval` function. - pub multiplication: FieldOpCols, + pub multiplication: FieldOpCols, } -impl FieldSqrtCols { +impl FieldSqrtCols { /// Populates the trace. /// /// `P` is the parameter of the field that each limb lives in. @@ -41,33 +41,36 @@ impl FieldSqrtCols { // This is a hack to save a column in FieldSqrtCols. We will receive the value a again in the // eval function, so we'll overwrite it with the sqrt. - self.multiplication.result = limbs_from_vec::(P::to_limbs_field::(&sqrt)); + self.multiplication.result = limbs_from_vec::(P::to_limbs_field::(&sqrt)); sqrt } } -impl FieldSqrtCols { +impl FieldSqrtCols +where + Limbs: Copy, +{ /// Calculates the square root of `a`. pub fn eval, P: FieldParameters>( &self, builder: &mut AB, - a: &Limbs, + a: &Limbs, ) where V: Into, { // As a space-saving hack, we store the sqrt of the input in `self.multiplication.result` // even though it's technically not the result of the multiplication. Now, we should // retrieve that value and overwrite that member variable with a. - let sqrt = self.multiplication.result; + let sqrt = &self.multiplication.result; let mut multiplication = self.multiplication.clone(); multiplication.result = *a; // Compute sqrt * sqrt. We pass in P since we want its BaseField to be the mod. - multiplication.eval::, Limbs>( + multiplication.eval::, Limbs>( builder, - &sqrt, - &sqrt, + sqrt, + sqrt, super::field_op::FieldOperation::Mul, ); } @@ -78,11 +81,13 @@ mod tests { use num::{BigUint, One, Zero}; use p3_air::BaseAir; use p3_field::{Field, PrimeField32}; + use typenum::U32; use super::{FieldSqrtCols, Limbs}; use crate::air::MachineAir; + use crate::operations::field::params::NumLimbs32; use crate::utils::ec::edwards::ed25519::{ed25519_sqrt, Ed25519BaseField}; use crate::utils::ec::field::{limbs_from_vec, FieldParameters}; use crate::utils::{pad_to_power_of_two, BabyBearPoseidon2, StarkUtils}; @@ -97,16 +102,16 @@ mod tests { use p3_matrix::MatrixRowSlices; use rand::thread_rng; use sp1_derive::AlignedBorrow; + + type Limbs32 = U32; + #[derive(AlignedBorrow, Debug, Clone)] - pub struct TestCols { - pub a: Limbs, - pub sqrt: FieldSqrtCols, + pub struct TestCols { + pub a: Limbs, + pub sqrt: FieldSqrtCols, } - const NUM_LIMBS: usize = 32; - const NUM_WITNESS_LIMBS: usize = 2 * NUM_LIMBS - 2; - - pub const NUM_TEST_COLS: usize = size_of::>(); + pub const NUM_TEST_COLS: usize = size_of::>(); struct EdSqrtChip { pub _phantom: std::marker::PhantomData

, @@ -149,9 +154,8 @@ mod tests { .iter() .map(|a| { let mut row = [F::zero(); NUM_TEST_COLS]; - let cols: &mut TestCols = - row.as_mut_slice().borrow_mut(); - cols.a = limbs_from_vec::(P::to_limbs_field::(a)); + let cols: &mut TestCols = row.as_mut_slice().borrow_mut(); + cols.a = limbs_from_vec::(P::to_limbs_field::(a)); cols.sqrt.populate::

(a, ed25519_sqrt); row }) @@ -181,8 +185,7 @@ mod tests { { fn eval(&self, builder: &mut AB) { let main = builder.main(); - let local: &TestCols = - main.row_slice(0).borrow(); + let local: &TestCols = main.row_slice(0).borrow(); // eval verifies that local.sqrt.result is indeed the square root of local.a. local.sqrt.eval::(builder, &local.a); diff --git a/core/src/operations/field/params.rs b/core/src/operations/field/params.rs index bf7bd9f762..4e1bc28548 100644 --- a/core/src/operations/field/params.rs +++ b/core/src/operations/field/params.rs @@ -1,26 +1,43 @@ use crate::air::Polynomial; +use generic_array::{ArrayLength, GenericArray}; use std::fmt::Debug; use std::ops::Index; use std::slice::Iter; use std::usize; +use typenum::{U32, U62}; // pub const NUM_LIMBS: usize = 32; pub const NB_BITS_PER_LIMB: usize = 8; // pub const NUM_WITNESS_LIMBS: usize = 2 * NUM_LIMBS - 2; -#[derive(Debug, Clone, Copy)] -pub struct Limbs(pub [T; N]); +#[derive(Debug, Clone)] +pub struct Limbs(pub GenericArray); -impl Default for Limbs +impl Copy for Limbs where N::ArrayType: Copy {} + +pub trait NumLimbs: Clone + Debug { + type Limbs: ArrayLength + Debug; + type Witness: ArrayLength + Debug; +} + +#[derive(Debug, Clone)] +pub struct NumLimbs32; + +impl NumLimbs for NumLimbs32 { + type Limbs = U32; + type Witness = U62; +} + +impl Default for Limbs where T: Default + Copy, { fn default() -> Self { - Self([T::default(); N]) + Self(GenericArray::default()) } } -impl Index for Limbs { +impl Index for Limbs { type Output = T; fn index(&self, index: usize) -> &Self::Output { @@ -28,16 +45,16 @@ impl Index for Limbs { } } -impl IntoIterator for Limbs { +impl IntoIterator for Limbs { type Item = T; - type IntoIter = std::array::IntoIter; + type IntoIter = as IntoIterator>::IntoIter; fn into_iter(self) -> Self::IntoIter { self.0.into_iter() } } -impl + Clone, const N: usize, Expr: Clone> From> +impl + Clone, N: ArrayLength, Expr: Clone> From> for Polynomial { fn from(value: Limbs) -> Self { @@ -51,14 +68,14 @@ impl<'a, Var: Into + Clone, Expr: Clone> From> for Polynomia } } -impl From> for Limbs { +impl From> for Limbs { fn from(value: Polynomial) -> Self { let inner = value.as_coefficients().try_into().unwrap(); Self(inner) } } -impl<'a, T: Debug + Default + Clone, const N: usize> From> for Limbs { +impl<'a, T: Debug + Default + Clone, N: ArrayLength> From> for Limbs { fn from(value: Iter<'a, T>) -> Self { let vec: Vec = value.cloned().collect(); let inner = vec.try_into().unwrap(); diff --git a/core/src/operations/field/util_air.rs b/core/src/operations/field/util_air.rs index 1965ba1ac0..f4aea7c5bb 100644 --- a/core/src/operations/field/util_air.rs +++ b/core/src/operations/field/util_air.rs @@ -3,7 +3,7 @@ use crate::air::SP1AirBuilder; use crate::utils::ec::field::FieldParameters; use p3_field::AbstractField; -pub fn eval_field_operation( +pub fn eval_field_operation( builder: &mut AB, p_vanishing: &Polynomial, p_witness_low: &Polynomial, diff --git a/core/src/syscall/precompiles/edwards/ed_add.rs b/core/src/syscall/precompiles/edwards/ed_add.rs index 2a7d9a7022..48d02e317e 100644 --- a/core/src/syscall/precompiles/edwards/ed_add.rs +++ b/core/src/syscall/precompiles/edwards/ed_add.rs @@ -9,6 +9,7 @@ use crate::operations::field::field_inner_product::FieldInnerProductCols; use crate::operations::field::field_op::FieldOpCols; use crate::operations::field::field_op::FieldOperation; use crate::operations::field::params::Limbs; +use crate::operations::field::params::NumLimbs32; use crate::runtime::ExecutionRecord; use crate::runtime::Syscall; use crate::syscall::precompiles::create_ec_add_event; @@ -23,6 +24,7 @@ use crate::utils::limbs_from_prev_access; use crate::utils::pad_rows; use core::borrow::{Borrow, BorrowMut}; use core::mem::size_of; +use generic_array::functional::FunctionalSequence; use num::BigUint; use num::Zero; use p3_air::AirBuilder; @@ -37,8 +39,9 @@ use sp1_derive::AlignedBorrow; use std::fmt::Debug; use std::marker::PhantomData; use tracing::instrument; +use typenum::U32; -use super::{NUM_LIMBS, NUM_WITNESS_LIMBS}; +use super::NUM_LIMBS; pub const NUM_ED_ADD_COLS: usize = size_of::>(); @@ -56,14 +59,14 @@ pub struct EdAddAssignCols { pub q_ptr_access: MemoryReadCols, pub p_access: [MemoryWriteCols; 16], pub q_access: [MemoryReadCols; 16], - pub(crate) x3_numerator: FieldInnerProductCols, - pub(crate) y3_numerator: FieldInnerProductCols, - pub(crate) x1_mul_y1: FieldOpCols, - pub(crate) x2_mul_y2: FieldOpCols, - pub(crate) f: FieldOpCols, - pub(crate) d_mul_f: FieldOpCols, - pub(crate) x3_ins: FieldDenCols, - pub(crate) y3_ins: FieldDenCols, + pub(crate) x3_numerator: FieldInnerProductCols, + pub(crate) y3_numerator: FieldInnerProductCols, + pub(crate) x1_mul_y1: FieldOpCols, + pub(crate) x2_mul_y2: FieldOpCols, + pub(crate) f: FieldOpCols, + pub(crate) d_mul_f: FieldOpCols, + pub(crate) x3_ins: FieldDenCols, + pub(crate) y3_ins: FieldDenCols, } #[derive(Default)] @@ -237,11 +240,8 @@ where let f = row.f.result; let d_biguint = E::d_biguint(); let d_const = E::BaseField::to_limbs_field::(&d_biguint); - let d_const_expr = Limbs::( - limbs_from_vec::(d_const) - .0 - .map(|x| x.into()), - ); + let d_const_expr = + Limbs::(limbs_from_vec::(d_const).0.map(|x| x.into())); row.d_mul_f .eval::::BaseField, _, _>( builder, diff --git a/core/src/syscall/precompiles/edwards/ed_decompress.rs b/core/src/syscall/precompiles/edwards/ed_decompress.rs index 5ddd434e13..1a680b4eb5 100644 --- a/core/src/syscall/precompiles/edwards/ed_decompress.rs +++ b/core/src/syscall/precompiles/edwards/ed_decompress.rs @@ -10,6 +10,7 @@ use crate::operations::field::field_op::FieldOpCols; use crate::operations::field::field_op::FieldOperation; use crate::operations::field::field_sqrt::FieldSqrtCols; use crate::operations::field::params::Limbs; +use crate::operations::field::params::NumLimbs32; use crate::runtime::ExecutionRecord; use crate::runtime::Syscall; use crate::syscall::precompiles::SyscallContext; @@ -37,13 +38,12 @@ use p3_field::AbstractField; use p3_field::PrimeField32; use p3_matrix::MatrixRowSlices; use std::marker::PhantomData; +use typenum::U32; use p3_matrix::dense::RowMajorMatrix; use sp1_derive::AlignedBorrow; use std::fmt::Debug; -use super::{NUM_LIMBS, NUM_WITNESS_LIMBS}; - #[derive(Debug, Clone, Copy)] pub struct EdDecompressEvent { pub shard: u32, @@ -72,13 +72,13 @@ pub struct EdDecompressCols { pub ptr: T, pub x_access: [MemoryWriteCols; NUM_WORDS_FIELD_ELEMENT], pub y_access: [MemoryReadCols; NUM_WORDS_FIELD_ELEMENT], - pub(crate) yy: FieldOpCols, - pub(crate) u: FieldOpCols, - pub(crate) dyy: FieldOpCols, - pub(crate) v: FieldOpCols, - pub(crate) u_div_v: FieldOpCols, - pub(crate) x: FieldSqrtCols, - pub(crate) neg_x: FieldOpCols, + pub(crate) yy: FieldOpCols, + pub(crate) u: FieldOpCols, + pub(crate) dyy: FieldOpCols, + pub(crate) v: FieldOpCols, + pub(crate) u_div_v: FieldOpCols, + pub(crate) x: FieldSqrtCols, + pub(crate) neg_x: FieldOpCols, } impl EdDecompressCols { @@ -130,7 +130,7 @@ impl EdDecompressCols { self.x_access[NUM_WORDS_FIELD_ELEMENT - 1].prev_value[WORD_SIZE - 1].into(); builder.assert_bool(sign.clone()); - let y: Limbs = limbs_from_prev_access(&self.y_access); + let y: Limbs = limbs_from_prev_access(&self.y_access); self.yy .eval::(builder, &y, &y, FieldOperation::Mul); self.u.eval::( @@ -141,7 +141,7 @@ impl EdDecompressCols { ); let d_biguint = E::d_biguint(); let d_const = E::BaseField::to_limbs_field::(&d_biguint); - let d_const = limbs_from_vec::(d_const); + let d_const = limbs_from_vec::(d_const); self.dyy .eval::(builder, &d_const, &self.yy.result, FieldOperation::Mul); self.v.eval::( @@ -183,7 +183,7 @@ impl EdDecompressCols { ); } - let x_limbs: Limbs = limbs_from_access(&self.x_access); + let x_limbs: Limbs = limbs_from_access(&self.x_access); builder .when(self.is_real) .when(sign.clone()) diff --git a/core/src/syscall/precompiles/k256/decompress.rs b/core/src/syscall/precompiles/k256/decompress.rs index 31e38d9a7b..0ac5cf5876 100644 --- a/core/src/syscall/precompiles/k256/decompress.rs +++ b/core/src/syscall/precompiles/k256/decompress.rs @@ -10,6 +10,7 @@ use crate::operations::field::field_op::FieldOpCols; use crate::operations::field::field_op::FieldOperation; use crate::operations::field::field_sqrt::FieldSqrtCols; use crate::operations::field::params::Limbs; +use crate::operations::field::params::NumLimbs32; use crate::runtime::ExecutionRecord; use crate::runtime::Syscall; use crate::syscall::precompiles::SyscallContext; @@ -40,14 +41,12 @@ use p3_field::AbstractField; use p3_field::PrimeField32; use p3_matrix::MatrixRowSlices; use std::str::FromStr; +use typenum::U32; use p3_matrix::dense::RowMajorMatrix; use sp1_derive::AlignedBorrow; use std::fmt::Debug; -use super::NUM_LIMBS; -use super::NUM_WITNESS_LIMBS; - #[derive(Debug, Clone, Copy)] pub struct K256DecompressEvent { pub shard: u32, @@ -149,11 +148,11 @@ pub struct K256DecompressCols { pub ptr: T, pub x_access: [MemoryReadCols; NUM_WORDS_FIELD_ELEMENT], pub y_access: [MemoryReadWriteCols; NUM_WORDS_FIELD_ELEMENT], - pub(crate) x_2: FieldOpCols, - pub(crate) x_3: FieldOpCols, - pub(crate) x_3_plus_b: FieldOpCols, - pub(crate) y: FieldSqrtCols, - pub(crate) neg_y: FieldOpCols, + pub(crate) x_2: FieldOpCols, + pub(crate) x_3: FieldOpCols, + pub(crate) x_3_plus_b: FieldOpCols, + pub(crate) y: FieldSqrtCols, + pub(crate) neg_y: FieldOpCols, pub(crate) y_least_bits: [T; 8], } @@ -211,7 +210,7 @@ impl K256DecompressCols { let should_be_odd: AB::Expr = self.y_access[0].prev_value[0].into(); builder.assert_bool(should_be_odd.clone()); - let x: Limbs = limbs_from_prev_access(&self.x_access); + let x: Limbs = limbs_from_prev_access(&self.x_access); self.x_2 .eval::(builder, &x, &x, FieldOperation::Mul); self.x_3.eval::( @@ -222,7 +221,7 @@ impl K256DecompressCols { ); let b = Secp256k1Parameters::b_int(); let b_const = Secp256k1BaseField::to_limbs_field::(&b); - let b_const = limbs_from_vec::(b_const); + let b_const = limbs_from_vec::(b_const); self.x_3_plus_b.eval::( builder, &self.x_3.result, @@ -259,7 +258,7 @@ impl K256DecompressCols { // When y_is_odd == should_be_odd, result is y // Equivalent: y_is_odd != !should_be_odd - let y_limbs: Limbs = limbs_from_access(&self.y_access); + let y_limbs: Limbs = limbs_from_access(&self.y_access); builder .when(self.is_real) .when_ne(y_is_odd.into(), AB::Expr::one() - should_be_odd.clone()) diff --git a/core/src/syscall/precompiles/mod.rs b/core/src/syscall/precompiles/mod.rs index 07e1f5047a..43d695956c 100644 --- a/core/src/syscall/precompiles/mod.rs +++ b/core/src/syscall/precompiles/mod.rs @@ -6,6 +6,7 @@ pub mod sha256; pub mod weierstrass; use num::BigUint; +use typenum::U32; use crate::air::SP1AirBuilder; use crate::operations::field::params::Limbs; @@ -121,7 +122,7 @@ pub fn create_ec_double_event(rt: &mut SyscallContext) -> ECDo } } -pub fn limbs_from_biguint(value: &BigUint) -> Limbs +pub fn limbs_from_biguint(value: &BigUint) -> Limbs where AB: SP1AirBuilder, { @@ -129,5 +130,5 @@ where debug_assert_eq!(a_const.len(), NUM_LIMBS); let mut a = [AB::F::zero(); NUM_LIMBS]; a[..NUM_LIMBS].copy_from_slice(&a_const[..NUM_LIMBS]); - Limbs::(a.map(|x| x.into())) + Limbs(a.map(|x| x.into()).into()) } diff --git a/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs b/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs index e0c34cc27e..4f8848a5ad 100644 --- a/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs +++ b/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs @@ -6,6 +6,7 @@ use crate::memory::MemoryWriteCols; use crate::operations::field::field_op::FieldOpCols; use crate::operations::field::field_op::FieldOperation; use crate::operations::field::params::Limbs; +use crate::operations::field::params::NumLimbs; use crate::runtime::ExecutionRecord; use crate::runtime::Register; use crate::runtime::Syscall; @@ -33,9 +34,10 @@ use std::fmt::Debug; use std::marker::PhantomData; use super::NUM_LIMBS; -use super::NUM_WITNESS_LIMBS; -pub const NUM_WEIERSTRASS_ADD_COLS: usize = size_of::>(); +pub const fn num_weierstrass_add_cols() -> usize { + size_of::>() +} /// A set of columns to compute `WeierstrassAdd` that add two points on a Weierstrass curve. /// @@ -43,7 +45,7 @@ pub const NUM_WEIERSTRASS_ADD_COLS: usize = size_of:: { +pub struct WeierstrassAddAssignCols { pub is_real: T, pub shard: T, pub clk: T, @@ -52,15 +54,15 @@ pub struct WeierstrassAddAssignCols { pub q_ptr_access: MemoryReadCols, pub p_access: [MemoryWriteCols; NUM_WORDS_EC_POINT], pub q_access: [MemoryReadCols; NUM_WORDS_EC_POINT], - pub(crate) slope_denominator: FieldOpCols, - pub(crate) slope_numerator: FieldOpCols, - pub(crate) slope: FieldOpCols, - pub(crate) slope_squared: FieldOpCols, - pub(crate) p_x_plus_q_x: FieldOpCols, - pub(crate) x3_ins: FieldOpCols, - pub(crate) p_x_minus_x: FieldOpCols, - pub(crate) y3_ins: FieldOpCols, - pub(crate) slope_times_p_x_minus_x: FieldOpCols, + pub(crate) slope_denominator: FieldOpCols, + pub(crate) slope_numerator: FieldOpCols, + pub(crate) slope: FieldOpCols, + pub(crate) slope_squared: FieldOpCols, + pub(crate) p_x_plus_q_x: FieldOpCols, + pub(crate) x3_ins: FieldOpCols, + pub(crate) p_x_minus_x: FieldOpCols, + pub(crate) y3_ins: FieldOpCols, + pub(crate) slope_times_p_x_minus_x: FieldOpCols, } #[derive(Default)] @@ -88,7 +90,7 @@ impl WeierstrassAddAssignChip { } fn populate_field_ops( - cols: &mut WeierstrassAddAssignCols, + cols: &mut WeierstrassAddAssignCols, p_x: BigUint, p_y: BigUint, q_x: BigUint, @@ -147,6 +149,8 @@ impl WeierstrassAddAssignChip { impl MachineAir for WeierstrassAddAssignChip +where + [(); num_weierstrass_add_cols::()]:, { fn name(&self) -> String { "WeierstrassAddAssign".to_string() @@ -163,8 +167,9 @@ impl MachineAir for i in 0..input.weierstrass_add_events.len() { let event = input.weierstrass_add_events[i]; - let mut row = [F::zero(); NUM_WEIERSTRASS_ADD_COLS]; - let cols: &mut WeierstrassAddAssignCols = row.as_mut_slice().borrow_mut(); + let mut row = [F::zero(); num_weierstrass_add_cols::()]; + let cols: &mut WeierstrassAddAssignCols = + row.as_mut_slice().borrow_mut(); // Decode affine points. let p = &event.p; @@ -198,8 +203,9 @@ impl MachineAir output.add_field_events(&new_field_events); pad_rows(&mut rows, || { - let mut row = [F::zero(); NUM_WEIERSTRASS_ADD_COLS]; - let cols: &mut WeierstrassAddAssignCols = row.as_mut_slice().borrow_mut(); + let mut row = [F::zero(); num_weierstrass_add_cols::()]; + let cols: &mut WeierstrassAddAssignCols = + row.as_mut_slice().borrow_mut(); let zero = BigUint::zero(); Self::populate_field_ops(cols, zero.clone(), zero.clone(), zero.clone(), zero); row @@ -208,33 +214,34 @@ impl MachineAir // Convert the trace to a row major matrix. RowMajorMatrix::new( rows.into_iter().flatten().collect::>(), - NUM_WEIERSTRASS_ADD_COLS, + num_weierstrass_add_cols::(), ) } } impl BaseAir for WeierstrassAddAssignChip { fn width(&self) -> usize { - NUM_WEIERSTRASS_ADD_COLS + num_weierstrass_add_cols::() } } impl Air for WeierstrassAddAssignChip where AB: SP1AirBuilder, + Limbs::Limbs>: Copy, { fn eval(&self, builder: &mut AB) { let main = builder.main(); - let row: &WeierstrassAddAssignCols = main.row_slice(0).borrow(); + let row: &WeierstrassAddAssignCols = main.row_slice(0).borrow(); - let p_x: Limbs<::Var, NUM_LIMBS> = + let p_x: Limbs<::Var, ::Limbs> = limbs_from_prev_access(&row.p_access[0..NUM_WORDS_FIELD_ELEMENT]); - let p_y: Limbs<::Var, NUM_LIMBS> = + let p_y: Limbs<::Var, ::Limbs> = limbs_from_prev_access(&row.p_access[NUM_WORDS_FIELD_ELEMENT..]); - let q_x: Limbs<::Var, NUM_LIMBS> = + let q_x: Limbs<::Var, ::Limbs> = limbs_from_prev_access(&row.q_access[0..NUM_WORDS_FIELD_ELEMENT]); - let q_y: Limbs<::Var, NUM_LIMBS> = + let q_y: Limbs<::Var, ::Limbs> = limbs_from_prev_access(&row.q_access[NUM_WORDS_FIELD_ELEMENT..]); // slope = (q.y - p.y) / (q.x - p.x). @@ -260,15 +267,15 @@ where FieldOperation::Div, ); - row.slope.result + &row.slope.result }; // x = slope * slope - self.x - other.x. let x = { row.slope_squared.eval::( builder, - &slope, - &slope, + slope, + slope, FieldOperation::Mul, ); @@ -286,17 +293,17 @@ where FieldOperation::Sub, ); - row.x3_ins.result + &row.x3_ins.result }; // y = slope * (p.x - x_3n) - q.y. { row.p_x_minus_x - .eval::(builder, &p_x, &x, FieldOperation::Sub); + .eval::(builder, &p_x, x, FieldOperation::Sub); row.slope_times_p_x_minus_x.eval::( builder, - &slope, + slope, &row.p_x_minus_x.result, FieldOperation::Mul, ); diff --git a/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs b/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs index d4589ab317..72528ef13a 100644 --- a/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs +++ b/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs @@ -5,6 +5,7 @@ use crate::memory::MemoryWriteCols; use crate::operations::field::field_op::FieldOpCols; use crate::operations::field::field_op::FieldOperation; use crate::operations::field::params::Limbs; +use crate::operations::field::params::NumLimbs; use crate::runtime::ExecutionRecord; use crate::runtime::Syscall; use crate::syscall::precompiles::create_ec_double_event; @@ -30,11 +31,13 @@ use p3_matrix::MatrixRowSlices; use sp1_derive::AlignedBorrow; use std::fmt::Debug; use std::marker::PhantomData; +use typenum::U32; use super::NUM_LIMBS; -use super::NUM_WITNESS_LIMBS; -pub const NUM_WEIERSTRASS_DOUBLE_COLS: usize = size_of::>(); +pub const fn num_weierstrass_double_cols() -> usize { + size_of::>() +} /// A set of columns to double a point on a Weierstrass curve. /// @@ -42,23 +45,23 @@ pub const NUM_WEIERSTRASS_DOUBLE_COLS: usize = size_of:: { +pub struct WeierstrassDoubleAssignCols { pub is_real: T, pub shard: T, pub clk: T, pub p_ptr: T, pub p_access: [MemoryWriteCols; NUM_WORDS_EC_POINT], - pub(crate) slope_denominator: FieldOpCols, - pub(crate) slope_numerator: FieldOpCols, - pub(crate) slope: FieldOpCols, - pub(crate) p_x_squared: FieldOpCols, - pub(crate) p_x_squared_times_3: FieldOpCols, - pub(crate) slope_squared: FieldOpCols, - pub(crate) p_x_plus_p_x: FieldOpCols, - pub(crate) x3_ins: FieldOpCols, - pub(crate) p_x_minus_x: FieldOpCols, - pub(crate) y3_ins: FieldOpCols, - pub(crate) slope_times_p_x_minus_x: FieldOpCols, + pub(crate) slope_denominator: FieldOpCols, + pub(crate) slope_numerator: FieldOpCols, + pub(crate) slope: FieldOpCols, + pub(crate) p_x_squared: FieldOpCols, + pub(crate) p_x_squared_times_3: FieldOpCols, + pub(crate) slope_squared: FieldOpCols, + pub(crate) p_x_plus_p_x: FieldOpCols, + pub(crate) x3_ins: FieldOpCols, + pub(crate) p_x_minus_x: FieldOpCols, + pub(crate) y3_ins: FieldOpCols, + pub(crate) slope_times_p_x_minus_x: FieldOpCols, } #[derive(Default)] @@ -86,7 +89,7 @@ impl WeierstrassDoubleAssignChip { } fn populate_field_ops( - cols: &mut WeierstrassDoubleAssignCols, + cols: &mut WeierstrassDoubleAssignCols, p_x: BigUint, p_y: BigUint, ) { @@ -160,6 +163,8 @@ impl WeierstrassDoubleAssignChip { impl MachineAir for WeierstrassDoubleAssignChip +where + [(); num_weierstrass_double_cols::()]:, { fn name(&self) -> String { "WeierstrassDoubleAssign".to_string() @@ -176,8 +181,9 @@ impl MachineAir for i in 0..input.weierstrass_double_events.len() { let event = input.weierstrass_double_events[i]; - let mut row = [F::zero(); NUM_WEIERSTRASS_DOUBLE_COLS]; - let cols: &mut WeierstrassDoubleAssignCols = row.as_mut_slice().borrow_mut(); + let mut row = [F::zero(); num_weierstrass_double_cols::()]; + let cols: &mut WeierstrassDoubleAssignCols = + row.as_mut_slice().borrow_mut(); // Decode affine points. let p = &event.p; @@ -202,8 +208,9 @@ impl MachineAir output.add_field_events(&new_field_events); pad_rows(&mut rows, || { - let mut row = [F::zero(); NUM_WEIERSTRASS_DOUBLE_COLS]; - let cols: &mut WeierstrassDoubleAssignCols = row.as_mut_slice().borrow_mut(); + let mut row = [F::zero(); num_weierstrass_double_cols::()]; + let cols: &mut WeierstrassDoubleAssignCols = + row.as_mut_slice().borrow_mut(); let zero = BigUint::zero(); Self::populate_field_ops(cols, zero.clone(), zero.clone()); row @@ -212,32 +219,34 @@ impl MachineAir // Convert the trace to a row major matrix. RowMajorMatrix::new( rows.into_iter().flatten().collect::>(), - NUM_WEIERSTRASS_DOUBLE_COLS, + num_weierstrass_double_cols::(), ) } } impl BaseAir for WeierstrassDoubleAssignChip { fn width(&self) -> usize { - NUM_WEIERSTRASS_DOUBLE_COLS + num_weierstrass_double_cols::() } } impl Air for WeierstrassDoubleAssignChip where AB: SP1AirBuilder, + Limbs::Limbs>: Copy, { fn eval(&self, builder: &mut AB) { let main = builder.main(); - let row: &WeierstrassDoubleAssignCols = main.row_slice(0).borrow(); + let row: &WeierstrassDoubleAssignCols = main.row_slice(0).borrow(); - let p_x: Limbs<::Var, NUM_LIMBS> = + let p_x: Limbs<::Var, ::Limbs> = limbs_from_prev_access(&row.p_access[0..NUM_WORDS_FIELD_ELEMENT]); - let p_y: Limbs<::Var, NUM_LIMBS> = + let p_y: Limbs<::Var, ::Limbs> = limbs_from_prev_access(&row.p_access[NUM_WORDS_FIELD_ELEMENT..]); // a in the Weierstrass form: y^2 = x^3 + a * x + b. - let a: Limbs<::Expr, NUM_LIMBS> = + // TODO: U32 can't be hardcoded here? + let a: Limbs<::Expr, U32> = limbs_from_biguint::(&E::a_int()); // slope = slope_numerator / slope_denominator. @@ -281,15 +290,15 @@ where FieldOperation::Div, ); - row.slope.result + &row.slope.result }; // x = slope * slope - (p.x + p.x). let x = { row.slope_squared.eval::( builder, - &slope, - &slope, + slope, + slope, FieldOperation::Mul, ); row.p_x_plus_p_x.eval::( @@ -304,16 +313,16 @@ where &row.p_x_plus_p_x.result, FieldOperation::Sub, ); - row.x3_ins.result + &row.x3_ins.result }; // y = slope * (p.x - x) - p.y. { row.p_x_minus_x - .eval::(builder, &p_x, &x, FieldOperation::Sub); + .eval::(builder, &p_x, x, FieldOperation::Sub); row.slope_times_p_x_minus_x.eval::( builder, - &slope, + slope, &row.p_x_minus_x.result, FieldOperation::Mul, ); diff --git a/core/src/utils/ec/edwards/ed25519.rs b/core/src/utils/ec/edwards/ed25519.rs index a13c2b64aa..0c23ca24a6 100644 --- a/core/src/utils/ec/edwards/ed25519.rs +++ b/core/src/utils/ec/edwards/ed25519.rs @@ -2,9 +2,10 @@ use curve25519_dalek::edwards::CompressedEdwardsY; use num::{BigUint, Num, One}; use serde::{Deserialize, Serialize}; use std::str::FromStr; +use typenum::{U32, U62}; use super::NUM_LIMBS; -use crate::operations::field::params::NB_BITS_PER_LIMB; +use crate::operations::field::params::{NumLimbs, NB_BITS_PER_LIMB}; use crate::utils::ec::edwards::{EdwardsCurve, EdwardsParameters}; use crate::utils::ec::field::{FieldParameters, MAX_NB_LIMBS}; use crate::utils::ec::{AffinePoint, EllipticCurveParameters}; @@ -33,6 +34,11 @@ impl FieldParameters for Ed25519BaseField { } } +impl NumLimbs for Ed25519BaseField { + type Limbs = U32; + type Witness = U62; +} + impl EllipticCurveParameters for Ed25519Parameters { type BaseField = Ed25519BaseField; } diff --git a/core/src/utils/ec/field.rs b/core/src/utils/ec/field.rs index bf7d0986cf..af67f6a7ed 100644 --- a/core/src/utils/ec/field.rs +++ b/core/src/utils/ec/field.rs @@ -1,5 +1,7 @@ use super::utils::biguint_from_limbs; -use crate::operations::field::params::{Limbs, NB_BITS_PER_LIMB}; +use crate::operations::field::params::{Limbs, NumLimbs, NB_BITS_PER_LIMB}; +use generic_array::sequence::GenericSequence; +use generic_array::{ArrayLength, GenericArray}; use num::BigUint; use p3_field::Field; use serde::{de::DeserializeOwned, Serialize}; @@ -8,7 +10,7 @@ use std::fmt::Debug; pub const MAX_NB_LIMBS: usize = 32; pub trait FieldParameters: - Send + Sync + Copy + 'static + Debug + Serialize + DeserializeOwned + Send + Sync + Copy + 'static + Debug + Serialize + DeserializeOwned + NumLimbs { const NB_BITS_PER_LIMB: usize = NB_BITS_PER_LIMB; const NB_LIMBS: usize; @@ -46,9 +48,9 @@ pub trait FieldParameters: } /// Convert a vec of u8 limbs to a Limbs of NUM_LIMBS. -pub fn limbs_from_vec(limbs: Vec) -> Limbs { - debug_assert_eq!(limbs.len(), N); - let mut result = [F::zero(); N]; +pub fn limbs_from_vec(limbs: Vec) -> Limbs { + debug_assert_eq!(limbs.len(), N::USIZE); + let mut result = GenericArray::::generate(|i| F::zero()); for (i, limb) in limbs.into_iter().enumerate() { result[i] = limb; } diff --git a/core/src/utils/ec/weierstrass/bn254.rs b/core/src/utils/ec/weierstrass/bn254.rs index 688c3c2c04..32fb691aec 100644 --- a/core/src/utils/ec/weierstrass/bn254.rs +++ b/core/src/utils/ec/weierstrass/bn254.rs @@ -1,7 +1,9 @@ use num::{BigUint, Num, Zero}; use serde::{Deserialize, Serialize}; +use typenum::{U16, U30}; use super::{SwCurve, WeierstrassParameters}; +use crate::operations::field::params::NumLimbs; use crate::utils::ec::field::{FieldParameters, MAX_NB_LIMBS}; use crate::utils::ec::EllipticCurveParameters; @@ -40,6 +42,11 @@ impl FieldParameters for Bn254BaseField { } } +impl NumLimbs for Bn254BaseField { + type Limbs = U16; + type Witness = U30; +} + impl EllipticCurveParameters for Bn254Parameters { type BaseField = Bn254BaseField; } diff --git a/core/src/utils/ec/weierstrass/secp256k1.rs b/core/src/utils/ec/weierstrass/secp256k1.rs index 40ec280c96..e65fca1ad0 100644 --- a/core/src/utils/ec/weierstrass/secp256k1.rs +++ b/core/src/utils/ec/weierstrass/secp256k1.rs @@ -5,9 +5,10 @@ use std::str::FromStr; use num::{BigUint, Zero}; use serde::{Deserialize, Serialize}; +use typenum::{U32, U60}; use super::{SwCurve, WeierstrassParameters}; -use crate::operations::field::params::NB_BITS_PER_LIMB; +use crate::operations::field::params::{NumLimbs, NB_BITS_PER_LIMB}; use crate::utils::ec::field::{FieldParameters, MAX_NB_LIMBS}; use crate::utils::ec::EllipticCurveParameters; use k256::FieldElement; @@ -48,6 +49,11 @@ impl FieldParameters for Secp256k1BaseField { } } +impl NumLimbs for Secp256k1BaseField { + type Limbs = U32; + type Witness = U60; +} + impl EllipticCurveParameters for Secp256k1Parameters { type BaseField = Secp256k1BaseField; } diff --git a/core/src/utils/mod.rs b/core/src/utils/mod.rs index 8581c3b33d..23cd11e6c3 100644 --- a/core/src/utils/mod.rs +++ b/core/src/utils/mod.rs @@ -16,6 +16,7 @@ pub use tracer::*; pub use programs::*; use crate::{memory::MemoryCols, operations::field::params::Limbs}; +use generic_array::ArrayLength; pub const fn indices_arr() -> [usize; N] { let mut indices_arr = [0; N]; @@ -36,7 +37,7 @@ pub fn pad_to_power_of_two(values: &mut Vec< values.resize(n_real_rows.next_power_of_two() * N, T::default()); } -pub fn limbs_from_prev_access>( +pub fn limbs_from_prev_access>( cols: &[M], ) -> Limbs { let vec = cols @@ -50,7 +51,7 @@ pub fn limbs_from_prev_access>( Limbs(sized) } -pub fn limbs_from_access>(cols: &[M]) -> Limbs { +pub fn limbs_from_access>(cols: &[M]) -> Limbs { let vec = cols .iter() .flat_map(|access| access.value().0) diff --git a/derive/src/lib.rs b/derive/src/lib.rs index 082a78c2b6..d631bd4085 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -38,6 +38,7 @@ pub fn aligned_borrow_derive(input: TokenStream) -> TokenStream { let name = &ast.ident; // Separate type generics and const generics + // First generic T let type_generic = ast .generics .params @@ -51,61 +52,37 @@ pub fn aligned_borrow_derive(input: TokenStream) -> TokenStream { }) .expect("Expected at least one type generic"); - let const_generics = ast + let (impl_generics, type_generics, where_clause) = ast.generics.split_for_impl(); + let non_first_generics = ast .generics .params .iter() - .filter_map(|param| { - if let GenericParam::Const(const_param) = param { - Some(&const_param.ident) - } else { - None - } + .skip(1) + .filter_map(|param| match param { + GenericParam::Type(type_param) => Some(&type_param.ident), + GenericParam::Const(const_param) => Some(&const_param.ident), + _ => None, }) .collect::>(); - let methods = if const_generics.is_empty() { - quote! { - impl<#type_generic> Borrow<#name<#type_generic>> for [#type_generic] { - fn borrow(&self) -> &#name<#type_generic> { - debug_assert_eq!(self.len(), std::mem::size_of::<#name>()); - let (prefix, shorts, _suffix) = unsafe { self.align_to::<#name<#type_generic>>() }; - debug_assert!(prefix.is_empty(), "Alignment should match"); - debug_assert_eq!(shorts.len(), 1); - &shorts[0] - } - } - - impl<#type_generic> BorrowMut<#name<#type_generic>> for [#type_generic] { - fn borrow_mut(&mut self) -> &mut #name<#type_generic> { - debug_assert_eq!(self.len(), std::mem::size_of::<#name>()); - let (prefix, shorts, _suffix) = unsafe { self.align_to_mut::<#name<#type_generic>>() }; - debug_assert!(prefix.is_empty(), "Alignment should match"); - debug_assert_eq!(shorts.len(), 1); - &mut shorts[0] - } + let methods = quote! { + impl #impl_generics Borrow<#name #type_generics> for [#type_generic] #where_clause { + fn borrow(&self) -> &#name #type_generics { + debug_assert_eq!(self.len(), std::mem::size_of::<#name>()); + let (prefix, shorts, _suffix) = unsafe { self.align_to::<#name #type_generics>() }; + debug_assert!(prefix.is_empty(), "Alignment should match"); + debug_assert_eq!(shorts.len(), 1); + &shorts[0] } } - } else { - quote! { - impl<#type_generic #(, const #const_generics: usize)*> Borrow<#name<#type_generic #(, #const_generics)*>> for [#type_generic] { - fn borrow(&self) -> &#name<#type_generic #(, #const_generics)*> { - debug_assert_eq!(self.len(), std::mem::size_of::<#name>()); - let (prefix, shorts, _suffix) = unsafe { self.align_to::<#name<#type_generic #(, #const_generics)*>>() }; - debug_assert!(prefix.is_empty(), "Alignment should match"); - debug_assert_eq!(shorts.len(), 1); - &shorts[0] - } - } - impl<#type_generic #(, const #const_generics: usize)*> std::borrow::BorrowMut<#name<#type_generic #(, #const_generics)*>> for [#type_generic] { - fn borrow_mut(&mut self) -> &mut #name<#type_generic #(, #const_generics)*> { - debug_assert_eq!(self.len(), std::mem::size_of::<#name>()); - let (prefix, shorts, _suffix) = unsafe { self.align_to_mut::<#name<#type_generic #(, #const_generics)*>>() }; - debug_assert!(prefix.is_empty(), "Alignment should match"); - debug_assert_eq!(shorts.len(), 1); - &mut shorts[0] - } + impl #impl_generics std::borrow::BorrowMut<#name #type_generics> for [#type_generic] #where_clause { + fn borrow_mut(&mut self) -> &mut #name #type_generics { + debug_assert_eq!(self.len(), std::mem::size_of::<#name>()); + let (prefix, shorts, _suffix) = unsafe { self.align_to_mut::<#name #type_generics>() }; + debug_assert!(prefix.is_empty(), "Alignment should match"); + debug_assert_eq!(shorts.len(), 1); + &mut shorts[0] } } }; diff --git a/examples/chess/script/Cargo.lock b/examples/chess/script/Cargo.lock index 435214976e..f9d68301df 100644 --- a/examples/chess/script/Cargo.lock +++ b/examples/chess/script/Cargo.lock @@ -174,7 +174,7 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array", + "generic-array 0.14.7", ] [[package]] @@ -312,7 +312,7 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ - "generic-array", + "generic-array 0.14.7", "rand_core", "subtle", "zeroize", @@ -324,7 +324,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array", + "generic-array 0.14.7", "typenum", ] @@ -432,7 +432,7 @@ dependencies = [ "crypto-bigint", "digest", "ff", - "generic-array", + "generic-array 0.14.7", "group", "pkcs8", "rand_core", @@ -583,6 +583,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "generic-array" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe739944a5406424e080edccb6add95685130b9f160d5407c639c7df0c5836b0" +dependencies = [ + "typenum", +] + [[package]] name = "getrandom" version = "0.2.12" @@ -1389,7 +1398,7 @@ checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ "base16ct", "der", - "generic-array", + "generic-array 0.14.7", "pkcs8", "subtle", "zeroize", @@ -1522,6 +1531,7 @@ dependencies = [ "elf", "elliptic-curve", "flate2", + "generic-array 1.0.0", "hashbrown", "hex", "itertools", @@ -1563,6 +1573,7 @@ dependencies = [ "tracing-forest", "tracing-log", "tracing-subscriber", + "typenum", ] [[package]] diff --git a/examples/ed25519/script/Cargo.lock b/examples/ed25519/script/Cargo.lock index 83b6f049a0..56116609fb 100644 --- a/examples/ed25519/script/Cargo.lock +++ b/examples/ed25519/script/Cargo.lock @@ -174,7 +174,7 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array", + "generic-array 0.14.7", ] [[package]] @@ -305,7 +305,7 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ - "generic-array", + "generic-array 0.14.7", "rand_core", "subtle", "zeroize", @@ -317,7 +317,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array", + "generic-array 0.14.7", "typenum", ] @@ -432,7 +432,7 @@ dependencies = [ "crypto-bigint", "digest", "ff", - "generic-array", + "generic-array 0.14.7", "group", "pkcs8", "rand_core", @@ -583,6 +583,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "generic-array" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe739944a5406424e080edccb6add95685130b9f160d5407c639c7df0c5836b0" +dependencies = [ + "typenum", +] + [[package]] name = "getrandom" version = "0.2.12" @@ -1389,7 +1398,7 @@ checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ "base16ct", "der", - "generic-array", + "generic-array 0.14.7", "pkcs8", "subtle", "zeroize", @@ -1522,6 +1531,7 @@ dependencies = [ "elf", "elliptic-curve", "flate2", + "generic-array 1.0.0", "hashbrown", "hex", "itertools", @@ -1563,6 +1573,7 @@ dependencies = [ "tracing-forest", "tracing-log", "tracing-subscriber", + "typenum", ] [[package]] diff --git a/examples/fibonacci-io/script/Cargo.lock b/examples/fibonacci-io/script/Cargo.lock index 3a576f8713..0383a16dd5 100644 --- a/examples/fibonacci-io/script/Cargo.lock +++ b/examples/fibonacci-io/script/Cargo.lock @@ -189,7 +189,7 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array", + "generic-array 0.14.7", ] [[package]] @@ -373,7 +373,7 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ - "generic-array", + "generic-array 0.14.7", "rand_core", "subtle", "zeroize", @@ -385,7 +385,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array", + "generic-array 0.14.7", "typenum", ] @@ -493,7 +493,7 @@ dependencies = [ "crypto-bigint", "digest", "ff", - "generic-array", + "generic-array 0.14.7", "group", "pkcs8", "rand_core", @@ -652,6 +652,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "generic-array" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe739944a5406424e080edccb6add95685130b9f160d5407c639c7df0c5836b0" +dependencies = [ + "typenum", +] + [[package]] name = "getrandom" version = "0.2.12" @@ -1490,7 +1499,7 @@ checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ "base16ct", "der", - "generic-array", + "generic-array 0.14.7", "pkcs8", "subtle", "zeroize", @@ -1626,6 +1635,7 @@ dependencies = [ "elf", "elliptic-curve", "flate2", + "generic-array 1.0.0", "hashbrown", "hex", "itertools", @@ -1667,6 +1677,7 @@ dependencies = [ "tracing-forest", "tracing-log", "tracing-subscriber", + "typenum", ] [[package]] diff --git a/examples/fibonacci/script/Cargo.lock b/examples/fibonacci/script/Cargo.lock index e5eee2ffb3..3c48db6fb3 100644 --- a/examples/fibonacci/script/Cargo.lock +++ b/examples/fibonacci/script/Cargo.lock @@ -174,7 +174,7 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array", + "generic-array 0.14.7", ] [[package]] @@ -305,7 +305,7 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ - "generic-array", + "generic-array 0.14.7", "rand_core", "subtle", "zeroize", @@ -317,7 +317,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array", + "generic-array 0.14.7", "typenum", ] @@ -425,7 +425,7 @@ dependencies = [ "crypto-bigint", "digest", "ff", - "generic-array", + "generic-array 0.14.7", "group", "pkcs8", "rand_core", @@ -583,6 +583,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "generic-array" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe739944a5406424e080edccb6add95685130b9f160d5407c639c7df0c5836b0" +dependencies = [ + "typenum", +] + [[package]] name = "getrandom" version = "0.2.12" @@ -1389,7 +1398,7 @@ checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ "base16ct", "der", - "generic-array", + "generic-array 0.14.7", "pkcs8", "subtle", "zeroize", @@ -1522,6 +1531,7 @@ dependencies = [ "elf", "elliptic-curve", "flate2", + "generic-array 1.0.0", "hashbrown", "hex", "itertools", @@ -1563,6 +1573,7 @@ dependencies = [ "tracing-forest", "tracing-log", "tracing-subscriber", + "typenum", ] [[package]] diff --git a/examples/io/script/Cargo.lock b/examples/io/script/Cargo.lock index 7c8f433f12..411b66923d 100644 --- a/examples/io/script/Cargo.lock +++ b/examples/io/script/Cargo.lock @@ -174,7 +174,7 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array", + "generic-array 0.14.7", ] [[package]] @@ -305,7 +305,7 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ - "generic-array", + "generic-array 0.14.7", "rand_core", "subtle", "zeroize", @@ -317,7 +317,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array", + "generic-array 0.14.7", "typenum", ] @@ -425,7 +425,7 @@ dependencies = [ "crypto-bigint", "digest", "ff", - "generic-array", + "generic-array 0.14.7", "group", "pkcs8", "rand_core", @@ -576,6 +576,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "generic-array" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe739944a5406424e080edccb6add95685130b9f160d5407c639c7df0c5836b0" +dependencies = [ + "typenum", +] + [[package]] name = "getrandom" version = "0.2.12" @@ -1390,7 +1399,7 @@ checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ "base16ct", "der", - "generic-array", + "generic-array 0.14.7", "pkcs8", "subtle", "zeroize", @@ -1523,6 +1532,7 @@ dependencies = [ "elf", "elliptic-curve", "flate2", + "generic-array 1.0.0", "hashbrown", "hex", "itertools", @@ -1564,6 +1574,7 @@ dependencies = [ "tracing-forest", "tracing-log", "tracing-subscriber", + "typenum", ] [[package]] diff --git a/examples/json/script/Cargo.lock b/examples/json/script/Cargo.lock index c6225e8a7c..88726cdf41 100644 --- a/examples/json/script/Cargo.lock +++ b/examples/json/script/Cargo.lock @@ -174,7 +174,7 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array", + "generic-array 0.14.7", ] [[package]] @@ -305,7 +305,7 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ - "generic-array", + "generic-array 0.14.7", "rand_core", "subtle", "zeroize", @@ -317,7 +317,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array", + "generic-array 0.14.7", "typenum", ] @@ -425,7 +425,7 @@ dependencies = [ "crypto-bigint", "digest", "ff", - "generic-array", + "generic-array 0.14.7", "group", "pkcs8", "rand_core", @@ -576,6 +576,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "generic-array" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe739944a5406424e080edccb6add95685130b9f160d5407c639c7df0c5836b0" +dependencies = [ + "typenum", +] + [[package]] name = "getrandom" version = "0.2.12" @@ -1399,7 +1408,7 @@ checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ "base16ct", "der", - "generic-array", + "generic-array 0.14.7", "pkcs8", "subtle", "zeroize", @@ -1532,6 +1541,7 @@ dependencies = [ "elf", "elliptic-curve", "flate2", + "generic-array 1.0.0", "hashbrown", "hex", "itertools", @@ -1573,6 +1583,7 @@ dependencies = [ "tracing-forest", "tracing-log", "tracing-subscriber", + "typenum", ] [[package]] diff --git a/examples/regex/script/Cargo.lock b/examples/regex/script/Cargo.lock index 11bdfb027c..f7711a6343 100644 --- a/examples/regex/script/Cargo.lock +++ b/examples/regex/script/Cargo.lock @@ -174,7 +174,7 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array", + "generic-array 0.14.7", ] [[package]] @@ -305,7 +305,7 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ - "generic-array", + "generic-array 0.14.7", "rand_core", "subtle", "zeroize", @@ -317,7 +317,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array", + "generic-array 0.14.7", "typenum", ] @@ -425,7 +425,7 @@ dependencies = [ "crypto-bigint", "digest", "ff", - "generic-array", + "generic-array 0.14.7", "group", "pkcs8", "rand_core", @@ -576,6 +576,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "generic-array" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe739944a5406424e080edccb6add95685130b9f160d5407c639c7df0c5836b0" +dependencies = [ + "typenum", +] + [[package]] name = "getrandom" version = "0.2.12" @@ -1389,7 +1398,7 @@ checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ "base16ct", "der", - "generic-array", + "generic-array 0.14.7", "pkcs8", "subtle", "zeroize", @@ -1522,6 +1531,7 @@ dependencies = [ "elf", "elliptic-curve", "flate2", + "generic-array 1.0.0", "hashbrown", "hex", "itertools", @@ -1563,6 +1573,7 @@ dependencies = [ "tracing-forest", "tracing-log", "tracing-subscriber", + "typenum", ] [[package]] diff --git a/examples/rsa/script/Cargo.lock b/examples/rsa/script/Cargo.lock index 043f8964bd..fdada3c6de 100644 --- a/examples/rsa/script/Cargo.lock +++ b/examples/rsa/script/Cargo.lock @@ -174,7 +174,7 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array", + "generic-array 0.14.7", ] [[package]] @@ -305,7 +305,7 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ - "generic-array", + "generic-array 0.14.7", "rand_core", "subtle", "zeroize", @@ -317,7 +317,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array", + "generic-array 0.14.7", "typenum", ] @@ -425,7 +425,7 @@ dependencies = [ "crypto-bigint", "digest", "ff", - "generic-array", + "generic-array 0.14.7", "group", "pkcs8", "rand_core", @@ -576,6 +576,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "generic-array" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe739944a5406424e080edccb6add95685130b9f160d5407c639c7df0c5836b0" +dependencies = [ + "typenum", +] + [[package]] name = "getrandom" version = "0.2.12" @@ -1389,7 +1398,7 @@ checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ "base16ct", "der", - "generic-array", + "generic-array 0.14.7", "pkcs8", "subtle", "zeroize", @@ -1522,6 +1531,7 @@ dependencies = [ "elf", "elliptic-curve", "flate2", + "generic-array 1.0.0", "hashbrown", "hex", "itertools", @@ -1563,6 +1573,7 @@ dependencies = [ "tracing-forest", "tracing-log", "tracing-subscriber", + "typenum", ] [[package]] diff --git a/examples/ssz-withdrawals/script/Cargo.lock b/examples/ssz-withdrawals/script/Cargo.lock index 0544bc682d..bddb6e7cb0 100644 --- a/examples/ssz-withdrawals/script/Cargo.lock +++ b/examples/ssz-withdrawals/script/Cargo.lock @@ -174,7 +174,7 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array", + "generic-array 0.14.7", ] [[package]] @@ -305,7 +305,7 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ - "generic-array", + "generic-array 0.14.7", "rand_core", "subtle", "zeroize", @@ -317,7 +317,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array", + "generic-array 0.14.7", "typenum", ] @@ -425,7 +425,7 @@ dependencies = [ "crypto-bigint", "digest", "ff", - "generic-array", + "generic-array 0.14.7", "group", "pkcs8", "rand_core", @@ -576,6 +576,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "generic-array" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe739944a5406424e080edccb6add95685130b9f160d5407c639c7df0c5836b0" +dependencies = [ + "typenum", +] + [[package]] name = "getrandom" version = "0.2.12" @@ -1382,7 +1391,7 @@ checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ "base16ct", "der", - "generic-array", + "generic-array 0.14.7", "pkcs8", "subtle", "zeroize", @@ -1515,6 +1524,7 @@ dependencies = [ "elf", "elliptic-curve", "flate2", + "generic-array 1.0.0", "hashbrown", "hex", "itertools", @@ -1556,6 +1566,7 @@ dependencies = [ "tracing-forest", "tracing-log", "tracing-subscriber", + "typenum", ] [[package]] diff --git a/examples/tendermint/script/Cargo.lock b/examples/tendermint/script/Cargo.lock index af253e2872..f6b3a1fd27 100644 --- a/examples/tendermint/script/Cargo.lock +++ b/examples/tendermint/script/Cargo.lock @@ -174,7 +174,7 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array", + "generic-array 0.14.7", ] [[package]] @@ -305,7 +305,7 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ - "generic-array", + "generic-array 0.14.7", "rand_core", "subtle", "zeroize", @@ -317,7 +317,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array", + "generic-array 0.14.7", "typenum", ] @@ -425,7 +425,7 @@ dependencies = [ "crypto-bigint", "digest", "ff", - "generic-array", + "generic-array 0.14.7", "group", "pkcs8", "rand_core", @@ -576,6 +576,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "generic-array" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe739944a5406424e080edccb6add95685130b9f160d5407c639c7df0c5836b0" +dependencies = [ + "typenum", +] + [[package]] name = "getrandom" version = "0.2.12" @@ -1382,7 +1391,7 @@ checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ "base16ct", "der", - "generic-array", + "generic-array 0.14.7", "pkcs8", "subtle", "zeroize", @@ -1515,6 +1524,7 @@ dependencies = [ "elf", "elliptic-curve", "flate2", + "generic-array 1.0.0", "hashbrown", "hex", "itertools", @@ -1556,6 +1566,7 @@ dependencies = [ "tracing-forest", "tracing-log", "tracing-subscriber", + "typenum", ] [[package]] From c275e38bcfbfe8a0a47cbee519398ecb6ae07dc3 Mon Sep 17 00:00:00 2001 From: Chris Tian Date: Wed, 20 Mar 2024 18:30:45 -0700 Subject: [PATCH 05/18] tests pass --- core/src/operations/field/field_op.rs | 7 +++++-- core/src/utils/ec/weierstrass/secp256k1.rs | 4 ++-- .../program/elf/riscv32im-succinct-zkvm-elf | Bin 117804 -> 102980 bytes 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/core/src/operations/field/field_op.rs b/core/src/operations/field/field_op.rs index bb840ffe28..72b9f6083e 100644 --- a/core/src/operations/field/field_op.rs +++ b/core/src/operations/field/field_op.rs @@ -125,8 +125,11 @@ impl FieldOpCols { self.result = p_result.into(); self.carry = p_carry.into(); - self.witness_low = p_witness_low.try_into().unwrap(); - self.witness_high = p_witness_high.try_into().unwrap(); + use typenum::Unsigned; + println!("low len: {}", p_witness_low.len()); + println!("limbs : {}", N::Witness::USIZE); + self.witness_low = Limbs(p_witness_low.try_into().unwrap()); + self.witness_high = Limbs(p_witness_high.try_into().unwrap()); result } diff --git a/core/src/utils/ec/weierstrass/secp256k1.rs b/core/src/utils/ec/weierstrass/secp256k1.rs index e65fca1ad0..7249e57005 100644 --- a/core/src/utils/ec/weierstrass/secp256k1.rs +++ b/core/src/utils/ec/weierstrass/secp256k1.rs @@ -5,7 +5,7 @@ use std::str::FromStr; use num::{BigUint, Zero}; use serde::{Deserialize, Serialize}; -use typenum::{U32, U60}; +use typenum::{U32, U62}; use super::{SwCurve, WeierstrassParameters}; use crate::operations::field::params::{NumLimbs, NB_BITS_PER_LIMB}; @@ -51,7 +51,7 @@ impl FieldParameters for Secp256k1BaseField { impl NumLimbs for Secp256k1BaseField { type Limbs = U32; - type Witness = U60; + type Witness = U62; } impl EllipticCurveParameters for Secp256k1Parameters { diff --git a/examples/fibonacci-io/program/elf/riscv32im-succinct-zkvm-elf b/examples/fibonacci-io/program/elf/riscv32im-succinct-zkvm-elf index 165c337f15cd3e611d7985d4dcd3a5d366186566..eee64d78545ab0a9ad3b9a2168e7daafdafdf16c 100755 GIT binary patch literal 102980 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 S&EI9dBk+CWV_ing_kRIh5OjtB literal 117804 zcmeFa3w%`7xi`G_btV^*z=jZ!;)Y4WMTEc*0#w_HFeugwiot3ke<^z zVKU(&Qgw?`kF{VfprX|?hIrbZ(;%HtJv~-yLEF<)FC*C3<7?w3fQaP%KWpthxo{D* zzwi5f?^pb7_w2pb^;ysTdDhCE!7JxWlEmD9GW(d()0M+bHiPajif=QR$#gb>rL$Dr z8UHo|CF$zKGhM24^|eO7B=!mZPZxb>S@Z_~ymXoT`qO5{=+fxD^Zic`;9Z-^uV?*? z(bd2HJufnL&wD1nCZJjcE*clrzxH5V8T}mmkAENh^6$@ohrr(<@OKFO9Rh!c!2b^+ zFj8S`1)Dp>kfhIj`9o!2ZiDO_cdu-y8uOXYFyAZshut;7p z+W!@^Hfku_fVQ%nHUhUs%ssM#aYS;9WsFN%5k{TK7|WFHyzd7g#X9jGW$@h@%K;;$0Pq)2V(=A2EeEDd?hFmd{k#VuZlXD z|DZYoo}D?o{Fp7QKTMQ~QW7o-;2g=5B!UgWi00>v=|6pwx3i*F6Yrv{I&im}qSbUa z*2P!bT0o-lJ-Cp=a&B!F>-0@<%g0v^EFZ16wWqOml3PAN<%^)78G6@ByGdiVrlB95 z8BIDHX%J2+k9FX?-PEzL{l)H6c?Ws3mBjt-cdPQ zSKaz;R2Hz6fNv7;O#*DC$izKNnS?cwB$;pz_v09&j4{d>ql_^s7^8wQD!y^oDn7GR z@lClMYu_N@y978&L_gMgJ;QFq98xfc4VXh(fX~5B)$X*@vY3%xAlvB$%ot)a;1qDC z6YvZGj;Ss^&9<7YD(LPLLkln;YvFS-G(IO5K|2cQ+h?|b z?yr{sYXz`Y0BZ%XRsd@mu$Ci}ie=?ONse5IwE!F=ld%>TNfKbM(i(8QZ3_Mq(cpvC zG?zdd;UK>Ef^UI8p^tIEA9E~+eIys-jbp8ej`eD09gYJI^vr-G0a|m0aWIU7VH~u^ zlEVwfSvi`j#OI-G0ZU}JA6Fi0#Jm?^9>A3(EEaHBaQ?+%k;Jz#N^2wPinZiCuyr0w ztksUv`#wI`d45&*1xL{DIpG$^tHyzNWv2pXfKPT>fef5tcKT`YY4{oNDJ<~mCV@{( zOSj%>$ryl7fs^p*LxE5Agion`_*75$lp^q{J|&U8@m%pKwLdyu?{NJ6pZxYRya(!rQ~VM!HGMa`!nLc_g}<4^6W_1 zr7PIpWmc-5;bZMArnfP}Q^1;kxch{)^iW1K-uWb4cs4xMta&rummNxP#yi_{5A)G; z#o^SLzAa!JnTh%bnO{E?FjjT-+C4p)MIO+AXJl3^dQkRl+s*vzx*!KTPFTwhdwq}Y zX1*3&lR8eIE$|<_Uw&Bkwc*`PT#w`0g=<{L312R*e3UyfpV{xOll=POfZ=7}WvEl3 zE3u}-7?Be46=Zb+Xt|O|sXG1g&_Ov0i71t={8y&rD{m)zWPb zlda0b<7~jvYU&wgdmx+F_KdPUS=~$=JG6=UbwI?WX_4&zVU zr+q?v#;Vv2U80-OSd|HvvB-pVEHZ8%`ag{RbhMw1HWvf#7^~and-3CTeG{`b1AciP z)V&PlX-zQKrY4kK$L#v~1fy*FPT%aN`FMXB_%0hkec91$4jT?{4hPeP0|OkSL2zJz zgER;Z3~-PJ!GQq|(&^!l4LF3o?z$MSW1P`^)*PnwIOMEHmNO2lRgQPiIJ{U7dC)jy ztOv>sSPw7O!*hmlN3HGm~KlmzR;`kSB;$sqXp3f2wXzziK{_h9h z0zYUderM#p4Dz(0SQ#s^zcR=sM@B!`-P;SfJ=@W38Sz+K4(PRvIea>Px8TLv7F!F; z4+coihgWks@92-VT>TB=?Nmp!6FAPlLuV&=8_u1|Q5kwy)MG++$DgotO}4>mgl^Y3-~?XX%EH^*s@niw>LMt-Bw0>lj-6r*8SgM*X;7KM?S1an`?H;!ym!BV*Qy zvBx*r+M7&_z4JC28y}Yg0}e9}cm;GNV>Ni)vNqNDc0RMg|7>}oZqxgyhtJO!-pTBe zsMOr>9PXOr!`&!}vSz$DyhnTO^_RmQ@gBFl9+~P=J>sP_Z(r_qX4H4}`lD@l2VE9A zw*#+M$WyNG(75`;$z3N`mm*!qfc|Pjmo=imZ%4m(+WFY`DD)Z9`NFX0`sq_>N9sT4 zvum&O$QQMDsy3C}Aapo_CxiZ+v_qqotjRujlzrp202a|xkI$_W;CMD-@LCxSA&oEkhI~r^)LOH|J)N1IYgR#tk-?e7(eSV9f z7eGg1Lu?JaI$6JcoA|Cj>U>WV?M8n>&+fX7!~(Bik;ezNUGih6??=!#+1?&exBZ_D zecPbAd)vgfJbb%{!-m#Ow5zm=Z}A@)`qDx5<~9%PGq_ds*|imAA?F($-MsVH?pSHf zxE|%_V_tp|j?vmR3U~^=zO$Lu&WMt(uAa1RBj-{(if-VWQ-1qdl+QSGdy&;&Jg&e) zU))b*Sl_q;ThF5Ws56gCso}7T(46;fQh;|#-h8IyHwk&;(4(_%@uJX8x!_s<(~)=G zDmxl~hG0(@+2#uDHY*)E1!x*_klP_6Kkn^??`IK}!Te9M!xc_f-5#>Pt%`OzlGliK zU}rzn3VH+l1Kg&3SiGOd{NSfPM!p~73nPI4fg#5JXSv_V8iqC9U&f4(mhRKRn|eM` z@Y~yr-?qx_6_2rBm8?-z?pIVUgO}R^o4%w~a?85)d>*P-Kz*pjmS@2i_fwfnQRf{z z_p8&d4XWq1(ahTj!2T2S@@sj;*3vDil1FpN6FwZWx4GQvyw_1Oi1@D4S!de#Z zn=kno`sRD-ndVDAlGD#QutCiECp2e{S4CuFX~8GCTq1uW&D)e*`)nuqp2)XIZ6xeuY2g@?DZXgPpHJmZ-4vRi8Ol^G$&dW-@#*lde^Yj+iWRnP(UIiHx3+%%@_V z;h*!db-RFj8TJO98L5~va9QXB!6!R37PdF`^!n>d2=Ba+{43<j6eRA&)hC^f9SaF@CQj4YXk9b8D-!fYd~H2Xre0g7M)qCYO*ihN0z2i-;hhY zux2XoM~&nbtMEUlfTsdKhyp)|0+?w;la8O~4YK*6UmbRy|C|`39iw(^z!CQ4F2XGu ziv#0Q8l!JqgX}!#V=fq9B3 zzlGP*djV_q{OMrr!c@tR!=4So9}fFH{Q$GFblrLc^uX~++X+4{!NyV}c~L&MNGo_? z?mWx~_%sfFZLGWSRR^w8avQlnxbGdi%79KyZ2{)b!41Vv(>Et*#Plv3vn8tP8NZzlUcnaVHI6L;%e!^ob zy#@YH>XZDTz(?SaH7riC4)CooaEH?sA4lI9BCoh(pm(S0zpqafc;oiTUOIE1VU!J= zrq8)Ao}$lV@V~3@udCoUs&4{#fBrPhms_mC|E~GWQpkeaAqyHH3+`3GTi~C62G@4@ zN%T>~^9|4g_`PZ0)zfQ7VFUKm!#0MW>cN@t!$GIo>A^aBQ4a4s>w4{V>)`wKoFE#q z-fJ7@-_RDY(o=>TBML#QZKT`7zwn3A@Q(&8mNMK<0lkq-9X%WV{P`?4LgxTJKxYbA%L_A=$FXMVD%$OY9zgmBXhlndJVq=)=pQfm zQ*V-t^iALk^CTCo@N=0Rj9`?=O8EeM2`~YlY61@t@dzD0*>18S zBYAsZN465b(jXVL2-X(7U4vXyAs1E1MHTS@HF6>3B-S|sxvyL#DUpk~?xS2}cT5yyk?Ccld*X95zkKX|#F5&ekL*Do;9+_Fco?1s@GyLH@bQNVVD0iS@h-fX_&B|fDvG#T>&A5jPM5sKT8e!*ob=ar`M|qzZ(*%Ilq0QJ!?q^+ z4qaZyTH*U-e4q3d*7_ChD=?bkui98MTL%oek01CW=yeg{iINZbhqw~?lqs%CF;DX0 zjI_uWoO=jx9Dqm4e87)n>q}i3R<@o^_MUIjc0mVv{13nn$X?TdZTP1GZ%Phu{P$>o zr0>L&ZN&5)`40a=SZ-FHkqMW&BuD?N6xdeDC}x--LU)PHJnx*PU_vm!Vf<3=QBzz%#CAut%NyuYglLF9B;a z3^)e41$o2!Vk^Lphtd43Q3q0$+@L$}-(z0z`7Lzj&9>QkBmZV=m=Eb5p5SX#hUVn- z^Uq?e7!&v9biFRdlpN2GoN_-0KTB1>FMa7QoVOeh{h=+6!=2CYK6KHC4H%2MoxgPM ze*nEecMAdsqR^waJ34#37{3A22GBp<7cv@)E$hYnu4jw2@ah5n>|I`L=u0sd@CN8h z+*cQs-8nxX)`#Q#$#m$fo4~!mL5D}3q%)HZ=|g-R@>a4D&o)3GqFu-n$P|jZ+r-zo ztP1b2N$2pk>zt-F#E5Rn!?;{o#@fhEv++Ez9&54Is;c!X)oZjuPFw+593^`i^~5?~ z&g1>$OK{%{Ir0Y@w{IND&#-K#Ahr%$Hfe|Rx}7CH^M26i49w&Hlk{S;XCY@0ujc%K z+wu-Q{+8M<%G-H0d@JAR&?e;C(fuol7mzvXlQ7e!C~nTyHPs zuW%jDu~VKP_&U1i`Q*c)wv56NG>4=gm*bh%lh1LtDS9E@jdjr}wzgE|`aFkIAdlwK z(L?mCJx=~jjw|3VPR_gL-Pc8aIM~QXAA?@AtD}C$2KYbs5?ttt z4CbK;@-;;!(>KiTwD?7GAo5t0>(H@iVX@)b?cg!iU-qk{!}_&C@EXD$;G4jUS^nrm ztSjWrqq!346OK<>f-aHt(YR}j{`vY6k8$%VgdN!V{fO|@e2OwB*}(8OAjS$Bm~<_2 zJW3^B{_P^qBdn*AKZWc;t_N;G95<~E_&5L5x?kP~z%T{#fbO@nFin}XLFj$RF&Lot z@wo*ik=|!FHiADakgQF03eQ7$9CG>zmC6gfkNge<6Vm%kZqwe*+lB5!VubEt&fDOJ=pjAnE3M<9)2(Cpe0Lqc{2GQ! z#Ts64%qBcw?e17Vh5tzRThH*}vl*5mRoVZ(O54BLGc;VsS2x~1LqzpS7fhh`0Y z75F0fb~uEbqsh?G`n~I17J>hc_#N4PMXPpfF!cF*WAQjE$_I_;O}qTTIP-_vIqk*@ z?_vI)R@fYx+OOU3QX4cb-bVg)tB_yy3~ysOe7kzr|F~`V3%4=5a5(cHL>n3CkLXbeF}?{TlcDQO+9O+y@VNnwK5zRjgZLLCoa}rK zF}QJ&T#UoSHRWCz{61ZYHzLMLa`YL%0(BbUb9qF|p|&9#xu4G1Kz_PB$;#4(+0kD) z@;&$$12R&y9WdSUyxcHtn6FXg{x?IVaYT3d%zM$kI~Mjd^phM~Z=bn^=BFa24%-Xs zufs+p8+ltC`B3`-3rTh4T9%Qop<`ba9SX zO-{Qe+TBX+?vX^h3^ct*iD6A+^{~q^j?GzhI+F;(4I2QL}YPz+c$2-=en2h9#ebZyV;F6YU4<&QHZSPAk(i zF(&pLwS)Pe(MLe~hJv-`e7X@bhVr@cHwc}pkkd{F=7D?|;Q1unC-0Gq`1|N?(1@d# zMgJ=7MDP{IPNX$g9-jxjf4gj_7J$!QtKc1Qh;l&T2gZIGva_t=C1lG&uA$%7etBeg z9$;VLn~-Up|LWRSq|1nR;pddR7kEt4VkJXu*mYJa<*R~U4R42!68HzarGESQ@i(D= zl!2d0ZTCVyO79@L>Wae04jkXqy2}~`e46^z(=7EHYUd~oZFee@3XKoh5Un`wiECS05`yYg}mPh{6DRq zz>p;24;Z9p5KTDzJB8v=0>6R|o@+-ro^v@Ds3x2uUe5araNebzqRx@NI&3AU4e0H@ z{08ts$^(WURp9yq4vr>u3K|RP{orR_1%5l9DPi5P9`JRNKi!5O5NJ z2S>o0$(|%XDdqbT?)WB={{Vapyq)GWAV$Q;9+;-&LAOQDwUUo^bD<}}|3~@P6szNF zk*}gXj2&%(kK-F~h>r(lbLlt9f`E&MKeSSbM>R-FKJ=m7cId$p#u?|fEp*FIedhk8 zo`LmnbP1;o4&(5c|94@+%+tX{z)<^?)*g7qb*1DS2IZTQEF*gpaR33Im&x`Gf8SCy z@PsWcJdXLsL8l$$=OuoftjA#z7(y@+w5T29-zDiNe4n~+GW3>7&|4;q^}rVM_;QOq z;5DA2qmaMjFMrZdk^AB3$~*>!xPoue&Ry2?9@X`K3S10aO7RVW`={frk}h<}z%sr@ zTacqy0$YsuO=Y{oE5H|kk7BIx6NIA}lgNwq5)Y8TL-D;H_!y1e2%M#N(7)izCm$AT zAUt>Ehz6f6UTis-WM18VO3Ivt(J}Xf|@>0ejAe zhAZ&rz^3++{Ioa1mx(d^OvLxPOGcm#^bg%d^pEj6a!L!HAi2f+#25r@INu}r&Yztz zK)-Rvz>Z@KGU!0HHb>Jj2Ek)<+S4(Hv*T|ZR|4PZ&)>kG!N)O|`&+%|)=uYQC9fDd z3Bx>iefaZ=1#Ra6kD=G_m<0Il0C|IN5AtzzUWfXCm*BPHUHDpBf4WGw0`GasM?L`Z z1$ZITUP3-q6na~J`%|!upNdQ*yG@0ik;3~TUj*<1x?Bo!*b&bayznxTK?26w2)-V) z)+BpP$-yVUp37l^DaRw$5#@Nafp{O@L4Sv?Nb8v1z}HdWVe~D+BfjR7=-vQ(4R|#G zj~bM|HSByN5^PXFt9oKnv>P%?Av{9PcQ<^Y3Ur|a&702+d{?2^6yo;iA97vix+THH zjv}VAdlK`nYT~f4(sitXhyx29tJBNrh}z!T`X04?R`O5a$86FK;U_-?80r>Nh5mgq z4kKs!jaN^N-$8EJwLzPXy%_ixtO4e_hvbM{6ry=Y(?}N*YZV_xI*yPD zSSud;mK5%z#@caM!;hU@C&-brUnl7c)+rF@>m+E+>#mcP(+(Or7g&aKUHm5A4m`v< zxwLXF?J&rWJ;0Uzw9?7tnONtr@GlIK6+UyUL^=h@YVvb{cktgf@ZWl~mFx-b*K&C8 zT~v;LJJt%?L-{7sM}inPOC`M-b{}+qdWZVzV_s`a3f89+bs(oX?ywQCx4a||xV@E& z+#ITxgE~>rJ(oG1jXo206=F}^?+^Y!epQnHmKsM}4DBy)-n{^N{#WY1-#9zN?idnT zj~ylZD$-BRDHFlBB`0?1j!npaZcE_XNxq<@u6{ZgfwqJ{jIB96i~^bDC!x5$0vXL= zl+luIjZpz31{!u@)F~r=nnC&)hf#hW;uok#FiQ3luJM^s$NvH>V6M7l!P}1+9vk$fpp+5?J zcdVh2JrB4i#}p`c=atBA`N)C01e-AF?*eQE9=h}8aA)f{j(#P$hf7Zn_s%R1KUK?c z$7iLsWC*zT$IZb1Kz{eZJ@-^_XW!v)Z&X#t6%Kb1Yk^$Z2Dl@io8W3S#pTn(aE}AS z&fy$JSP$a81J~mfX0&HxAHxXvXZC}KLuO?OUw{o?fNvY}g>&LqW4A4qb&B;^=*~AW zss%AkP6wx14+joe+)r2OtVc4gPw_C$CvqWg@-R>Me2EYE%yvP)uw4Z20uA#v!j}*D zPIv_zJuOV4^BkCjlRS*`10ipI$NS{?pKSk9qK*D^ouuhOJWh-|ewO2Amz+HA#xsn& z(WQrO&>D|d^^Lo;>*R5>qH`NJ@ngVyz}!2hyJJK=40sa|ypzK!{L536pL%Y6I%_8Uo z$Zf>C=W%#{v2Mx+_y7jU?Q>`++yc3cF$kCn85w8>UPD)IP=V7t?~Y*N%&!kNr)5R+(Wb6{gY-!%GnhA%{t3PF zDZ&TqH?3S|@ZVYO+!qO3CzbSF_AyX@zY7o@?&mywGrDk}`h;i_8bTT~>&^%{*pgH!=V61I*4|hkaz&ukwH{`44rm zj#U*EcGL33{`ruxGqPFY5$z~^m&e3fLH-Lq^D5@S`7hw-=3$+zH|dybKFu}GeDK3N z>yv66pt*51c2Km=i2XpOLr+*thPhT6&yo~^hketIFThdMaJO?|fiX5ms&??%~ zA%{A-UuBJ7gU`051@Jk8e2tP%8F4GB$K_+7liH^|Ai$6N;J$qRb5}{J?sAtzQFD~1z!;O2YmSQ zI6fE$1OM3{2a`1PmHHS=M{HmJJ}d@4DOKIIdfqOP;fU=MV)to~v(Bf6%kQ?~C~wj@--lAEga`-+vrj&g;Q^ z@>ALR({7I3T<*6Lw$Czm9#n6n$TQjO;*Jmf@%%!}!_b;~jR$5rKKWq2m7!xSkab!V zytAn{v0gnvb~yA)*k9nYz&jpC6Y%26Ll-yieP42-o2?WIy2I$fD4-~%6iZ^E0x;ltrVxi@?soeO9jw$70AI|Dhz&KPu@ z9fEvdzX$somi{m3$neE)+=$%sCY1FcuQ(NX#n|^B#a!NQNf&v=Kf_*&7G`DtA)U@J zNo-XQLswJ$o}a;HM_#dxJmbHdKF^rfc|?UTM640~C5od11AhR273+y{ig5?NA#_OX zV(ybcZW!=L0e&jL&y&t3!P=;VUyi;xjq))a|Jgr~zS;L4I)_R8AaFCi7k$KM!Dawl zVJpGzB7Ic6N4%V3ZrCqF&(PIp8>I7byk;%Q`g*XC=NI#KI~P0p?EoAhoPh5eyzZ;y z5mTI{0WfNioVigBr>q1UPLW3({3gK-KFcqkM=a>zKgb?&d4yOS_9E8(tn!G7H&Oly za&4B=K3&Sqhi&ET*KMk%{m+qn&_3{t*33Dt<1p4UNu!)UG(t8Y56W^SECj&|IKSP$Wv4P3J^2PYTheX>WneadrSBnkWT!+d}K<~Tot zL6i&3BpT>Pw>(A*x=rfgPPthQtt8{_SZmqegtl(oJ#cP!JaBGvBVFR0=GOV=vzuFZ z!r9F&Jjt2c0DR-?1)BJh^7=mIi{}a=ALd7gH1mEo#BA@VRjQN%1~6?)*K9F;i}e4POh7M@PX&qtOkBJG!w% z82M;lm=_opd4bq3Y0Msuxzk=!)cb;5K!4~l?z6Tv__no19$z9o zhWyl|(;%Pjw0wZ{W0&tbbLGAT0sDBwm+Q!`e8?&jvWl-soYn*|70-}ejeT$nxOB&H zQ^2f~`?p-a`{2{up0A+(NUqv?06Z7td}lYu8(UumUfvn-AMV1pre5pT1F~OhWB!@Q zF#%7AHSG?>cH43jJ?%D>te+P%69T+$EI`9r-1@*s(il8;K*)NLgXismErR+U%^UMP9pGcrqnnAR+d9Uj zd0oBYe9)N}<4NIq2aUNYdN;=8b@Yn^&RYE~$BQ`gmmY7{7mW8mPC4EQeekt)f^Vnf zSK68VZQ4in5o^x;SittgA*`7f@I8us5Dt9huLNK13&!ix{XqDBwefxx_#XR$@wU6P z1e_7{+XbA_=l?UsBa7VM`Fo%z65YaoNBU?w(KdMBn|#mC-Od^bc?mgAd=zwzyvRZN zE8(LS{AX8xr8Y=^a^&t&ryZfAf`3pHN^?N8~l|^Gd0YS8(=CPo^*btz_(s@*_q2J&%wsC4P_iiI|rOUcHX% z=HQb$=1XTd%0*jfjvDg)$+s`@c!ziwMNSsac>q5|e#toG3<-F&V(co(KFT@qO@Lg{ zB%BYq9c_}YG@Rzl@e$E)b+X??6P*uunG|XDz*hjcWAC5Rx{rTX+AhOBG7oe*yr(?u zDVXDA%<)T%6YE4VAGIh-bAz0u++99)t$Fa+Z9evAkS|Z;mo%Gr6PJsDKMq)5b34XH zvK8aX=i?IV?7|Q8A^hlrDd0zWCA{D0jxSzs_w1t1-wo*3IggX?PrV_CJycoa4ZT{n zRvnQIPl0aTx+C52Y-84{gTv@7G{f@>?9qL+rizd4AYMM4?7^au9j_Rk2kSe=Lk_L; z++LK!aK6%Wm)YKc-tjzS#@a_W8w&RAC3-YF@^Pkte0zW4K^gvi7R%_7V;O%gHhz*J z8B3;0{>)6pUUC6`XG+GMf4wvI!wZzy<`c#CBV#1{&l!^chi^-<%)LyRm&ugO3s`LP z@1#iM7#4Xc1LuGJRcUVcq3nzNL~dUD2J)1;dK2&M{nXG`@%bdax8oyYq$U|RjF&n_ z(pWn#^LsGY8%9dDC!ojh+pqNmj1eOcpFlaByVkJ}<6pO9vp>26=Y@^nz8u2~ICy`J zvm!lw1>Z{A)rMn7^K+FT?@8{7vlNwtLUvlo;o{hQ$n|Jjz?hFU zTYOmJXJ&!s$tH8oVSJPHE7BMG)qjKJB-$Tf7yAbJPJCwRNoTc!H(?(S#!U7K?c+`Z zY=^*kFewWEA=y7c!e_^3AF&_wfU`Ek*sr|}XKj)##uUG{8?Z$lm=@}#y;(l?IO@UI zl~3@Yd^oh9G6cR2Ez9Wn9A_bG8P*+Tnmq)2)$WGfhqFSg#tj)t5Plcz=TFwv1H66& zxp~wE>Zkjg<`k2!CGo%<K2^a$w1qf2iDBVr+?eZ*aCYq4Bmw{y!5+MAz6XF#F*#L0Uxw; zNA##a+QQpT42ynB@G^#^VIFCCm&y`Z+9$|a>oL+`ulAc`;+_pWS4HTiIJ>zYZYUF_ zFFX%6a?u`IW7S#fGv@qbt@*hC!X^TLpfh)I(Rsl>xlC%7>m(;OdD>iZ#o2R?K1EJ> z3i52>E8xB|?179-RAI|+kRrkBnXxL!bx{L(B*@juBL0TG4LI8(oJHpcCUgJWpu^I) zXmlsV3u#?xT#0P$FttU$o6|}m3sT_2UjW<#Z-v~p>0BDvGLhC7B&8`uj@=|91g9jL+$V!!AdAo5sfdAyLp9 z#%83!m)rf5w~T(i9)Sxb*t0Z`@Blate89OQWCKNlQOWMX8s0-b4abH{&Zz`@xOkkj z&%R533*uWApN~&&0enb4Je{<+(Emv`GW-xHona)#7Nwju>_b(7W1P1P=jTU*H$^7S z6S#(Nc0I=VFnHkZQOpXbav3ggty8hKrs^ldtDcXa^AKHA?NrdKXg@=&&z6Df<1t}> z?F;ZVKsng&se|DQ-hn(s;48j2dy4z;)zQOj?L&^cr^Q$3g5bTf&kKBoKI5D67W66L z>o~$!iR-Dwp$7lC`yDRIw0ex*;Hhw`J)ZVTGL8aufjk=)|b zp1af^U$9Q7JC^VB<4JNS!2YZU}+Xq~WE zEO~x(5@%XD&QLqfnvj0T>z!P-J&9j7d@DZne$XvqTK#Yg^MS0AcwEKdjokKye&ggn z#0Ta-49*Eq!C%~*0G=mtnw$WX>mSc=?pM#JLC1IVANuD6@Hz+kasmdm;e%a}?3=d{ zARgoDn#q`-Gp{cnU+4Td4*w43K=FGKKk5ZeB>jf8#?E;U|LEcY*ERmX499M=?K+e3 zz5#H=e7{tj_>{2he6K$&0lxt`Dg;N$Ei%B%EM0fb*n+MEeTws6q790JL`(J?dO+~g z{08jZ+zvh>v1YIEH5qywd(I)dv|?8_J^T**Ih^D&@m27KL9|KjaM~n3b5fZ;nk2q$gSR;JC@D@3F6PhkZ^=JS^HZAL`RzYI z^8>5~mc@R0zVBWu#M!X%-Wd3=^}&AT$5}ddQIHwWEoR2$IgHM$wwgS!si2>QF*Y5t z4rkcfZTfM$3wQXU=$z8T{n`myYr7ujFL+Q^-6#7!hj8vU;+|fdb>z)q_D-C+{p%d) z`Z$Md-AE}h+;bwPBi9Olp9_9j*;p0t^*43F1`vH1<2}cX%dj7a`tbgR_hDa`$BKwA zdq!jxX}y32&MgQ3rt``C+EMVefMVY_0p|oQX0f#+i|wPcSgbb2j71UV$K9{g;@T@4 zixkPPHDm3(sfkAU6MLOZ<4CvH%kT^0ENJ@u(XTU&t>c(~y)GFFV<>mbUW@rOqwGr` z_Zr{*0kdDVSmdcoS^~RcBM?Rb9xc>-zo(Gy(tYOV9iInyrza~5 z=L7*pJ*wgD{w(J0!P)ERbKQ~N#7#N9*5MA>k9P{z+{Sn7Pu@&lE@&$MLq_(YvHr4M zwr3&MsZ+8Z>7ldNL2vXOXHNba-@TXbf-ghzKNn}Q=YWs5wUSsbF{31lBXiH7{Qs8eO84f*`@Ane29s7!SZYlXlI>%dwyU5=FxjV2e zqIc-Re7`Yo7kjpn?PA{+Z`a-L1O5b^;Th3xfN*deWFh>&t}lW85BUzE6*W-R~T&zPAY+L{k6KuYjIy57z1R zeJY)!Mf#|KQ}j9Evqs;7r^jgyMC*zU9#nrg)4E)Te~988q&tSw67uekU>|;z*tGu` z&6DOR^m+DQR5x-N?ES+%67Xh-edLH@)jX#vm*)Y0S1{v_qY7v)Gxn}Wvfdw|C_(U% z5eFn2xs%2N_+Hw9gm`QfX8{$y(b;C^cW{0?jX3iLqkH^RQxfp`G{49Q7qUdt+xR;OA7xq(^?=W!4(cb~);N9$N(Q892GvKeJ@&J;OF`drd;lY-v>Bx%R!6> zzJTGoPmn*s=s`}elb^-q4(d~1iHAMN+5O3<9Nv0#kFB9?@;7iCW_%xz^R3g+vH!$34eZ^(eHq5n~a8=@Q9Ugb+7t{IZkZyRuH&-L>Fet8bPVG?q;^cM) z#{+U`OlOP_(VU=bIQIG)%y&4~ouFgz*c|W>IW|Yh7fbW^<&Tww?_d9v@9Rdq4!W4-5vCpo-8_6y9!p7h+DMv@%Az(1?Zv@M; zZ0BrXc}JXh!kJ;2gd+>_J=5^hoocRx%N-<7-1r;!hXnY3zf+zI)dt@|D|B5S^4C$% z#(sDM`S)~Q68SjEw_t!?s9ogtJ9iPYgs<+5z5=BshTGW#5$%) z1KWy157|z*=g27SGst`JQ^arj`Tc23zDd*I)0X(&LDH8U93Ic{4d+_eJP!|cDs+z| z&!)EF^GfOzls`ph>CyQc)aQPzi^gNr=(B+LX_L<3#FS3apJ`)1B+VCV&2tTa*GXRh zbauW61ou7jGSk(0x$UUr2PI{^CPl^rFDC7Q zjRt(4@D|qjL(ozbIfkG$)T8r)iRbyo;hTwm!Q;4$5wt2{t?6%xaeEB+WUk7o{BXVr zrO2^_PDnXQI)fgv2Y29>x(9n^RKA9^|C#WVbYx4_L2KNfi1UORAy1Hx`M_f6^tc+c zaV}Vp+2@sz&sehID=UfuXVc>Am3-_or5sfFc9pya(BTWck+v?^=FCy@HWKa1iuNM< z-VPrU{XI5SoCA{oVs9i5u>$-pCemxI`xh(rmO>WO+R2`WeZ3sHNHI%NZLty4}Isi|_};goLZ z-yXn-^2MN!s1ogy6>ypfIN>5VrOZbi@WxSvSlcteW;o0#cAGLHl0tH~Y@u6M!D6P`h^eaJ2U_Wd66vkAKX7PngRL_&WeI*kCx* z5$!p;@8MYb7Wi5rQ)G{5*SyC^1=5eZ`NIcS7nW;Mn^dl)PH4u0*&#mH|& z{1xvXi4U{WIZh6bT!{6XxB%r4Gtw|-oLgsO+{QZe$7wcv0gu(7F9YWwgMO1SMCc&r z6em)AFNl7k(D{Tu^X1wi`JMLy*&c)wO5`fUU}zqb5u=&%7?0ujSh*tRlzxgi1%@Ht z@*{$YodSDj!>7I0#*}m=KOHiF@p?R_qT+9icE8bWW8W{qk!Tp_mBLO!oj*axcKTE% zzJOQ}-lu)mYq2!&rgX`Lr`ry}5NAKUUj+M%$4OEjd+!Y6^J08|iRAxg0K7=2z~3A= zWPpaO^_x`QkBZzhXYG=GX`kTCxPWq+`fpQQmG~UN%E$hd&a`-&&dBzE9Wlo4Hz-as zz+dQd_DytnFm|F1#NBBB2I*=RJB;{O3UrYa;E&FECdFMi{ynT=-=Zoj%~*H(-nZ_O z(rG=5&e*iIOX>+qjIMln=iMRpNZ--OC@n`K@>a%i^J}wy$9T$R+lyH2?PcI0AEg`0e8QPe4J9A8s)hH@ zV|^|-YAE2-_rXS8_FejZ#7aHjB|c;QQCIE5hcjU>W?1hWf*r{+tv3&;%4ONu+ll^H zA5qA+pv*`82jD+Au$vhp_i-PC|J`>HH$ANQm+#}bd>uOYTn6@?!uM!(N0Fg6jGJh23ysw3CnfTcKah>94(4p}+w^ZPtYh#965=#p|cjGtY z?>!UlL4NS_W+6Y4c!<9Zdos=c5i}1yUAb@pcqV8*6*QlE4C{}-?V6tknkO0%G0y~e zhluNiHBR#syVD<2Bl-V#?9X%=V2x->-b24x3yx*c($)8%V@I$c{7G3_8?+8T6>U_YJiL#&CT(+PXN zjK;y~7kw#+-5Mj>k@wQW?I-cvntVn%uFv~&!GE0d#(6)jV7%jji;%5cW`UQGpX^(YTEw-BDGyHNyphMcrN2q6yI-6;nST%2EQ7B~z=r|n$tu_j z2Y4wC+y<-#;3g6M4p^2#yV8 zWA}?W-HWnr%&GYQ@t70l&;NckV8Cr19&ZB-aVC`$TiefLYfjFUE&LPpUo-TDPHxrS zdr|kS@@jm8{@z9;e?Ha$cGHwsfY&;=Q^2vlYoJmi^Hl@DunBpzGLr9^@(d9Rl4+h28``h2yUSGBdGu-54|4kihFkWRWe&>uFK=gnjTqV5xKK_>W zmEfUwjb_%;jx=M-MHokeME*O%E$Gt<(eesLzXKlnZ5_Tb1#)9{Bt9Dc($A4^f-?v7 z?jhD4yEUb2GI+qnuuVc-CdLlNNe*RN@Bil{Wj<(r#D4HI_;CAukNxjfK3{A7lLf|I zSF*$pI*vdGlZ?C2)`$>`t!!tBx{f1;)~Q+dJUPnPIE3>T>-`&XCS%^y+58#V)w-pU@(GiD8{%%E_ z`I~Mmrgi4}VwUzc;S_XNoQn!t-URuJZ;G#h;{fUV&?*0Hl%&It{3PUb0rZF`bnFAu zY~5rDegAO-@eIDFOUr}Z0eI6|YcG2^JV)TXwUS*FgTOnc*!niaYxd)JHR_`rmwRMW z9P6e25mx}8h2GHp#*rfJuZWNCVu=@@IBJclSBlbsFJ$YWTw=_|9?YGeF>JuqdzK+rGzlAVkwdH#2*2t5k_=~!&?I1gHH_d2+tzM^epn}j&peqJ0P*~ z$z#UBukkY(DfVKQ|YzoxH zonno=K5#dZSB!Ubm#8fATw5jMih8W!5b#Y&PJD9Xe*;ECjMO)E!s*2E8~+Q>=|-x_ zaU9?2In5Y>cp>l;`1f1D?sZx}7gsQEj(da?24ZX+XR@__cX@>ZJo(c60X!zLDfOt; zeGIlf;cW@WTddD#*6&)?*t#2vVS6009=<{GM{g*$H-hJTC|7LBVNUCw_}8eOjTj%d zOPgSm3jf@A@>4lw#tbZj7!fZM=4b3v97Wh8LZ1-+a^+(1)^qj`kUvLh0h0URKZ5K6 zj>|?0F5;>ArCe9Au$R!`spn+dVmvCzhHk?3 z4)A-#va*u+zMvlS1#apKS%>=9Uhr~>kB@Y3$Pzov6mlUwo?{~qnDe;}(7}day*Z!T z!`H>ohaf%%+j)PAWR*QG_}uk^&n3L|pZD>&DCcpIS6E+{$4zAZ{f{MioK?03wxZx~ z26AdG=z6yPDgIWI!{4C80Edy6`y-YJJaNn#6H+=-h_^v+L7Bwx*^muk$V8W)AwPFW z0lo`9XAE(98~7aIm@^O1;kn}!Xb`xS+&e?DIxZ6tuS3jTwkcM3Km2$>!e@%pc}X7- zv87k(TmS`p5_mZue30jBZG$|gI2}9v{;TR0`lmVJ(jUx%3vWEM<^FiZ~aTGHme+2!Gz%C-+Dz{6b$bIL3uXXPcz}4}M z<2&|ylg^{yZ$}}Hje8e(0^OUSZ*4~#(8*dg=(Ett^5JW44ML~g19&3_$j2A{A;y=q zqfXstq?^W$e!1RmHx)Aba96Lf8v4(s-O#&s2dpy466onf-z0xy>-MwAKKxC!jqj$~ zO*pqHXFu{Bu#fL3=?%D_I8__OCC23{EceT4}4_1 z>)RPj3(k9Otz@i_#o9PSYXD9^jrD=-d71AmJwe|fgMFe*+$YN1gLOvUATJX*t^{9! z4Yy~IeGI?M-yj#fpM5MTgK`1^2SH22fG6p?ZhL9{L1VA3m5l6c=+bfc@s4If7E1oY zS0(>Tps#O?VgAavWJJ9<&nrWXyaf7xX$0^z4>=-nS`(lc1( zYHAlUE8|3OV(Sl10KYv{KXG6DxW&BQSkxmK2V{xs4qec99&Ez?qIJc_`jO1Kg7hNf zdguoN*7Z7K0-dtOp3@^;$p2e6p8R?qW8^v(TmG6TGas@q2-_K`5`bob!ttFyP{&z&3sAj>Vt% z+D*$h#dJLHUe00%abG-w6|ImUUygLfx(?wze82~HvyPcm_Rt7X_KzE#iITpdZ)+fUD3PHVLYDwvE8C=`!Mhe za7#R_zu&>_rgl8*7sLtyPX~6uWv{GM|CLFcW4?tK);KVV|) zUD#{x#9H(BK#qXkC%l5aq4Z9Y9sN2Nct!CxuD5dC810bU>_9F6{w7J3_yEaJtF)pb zRAw%{E>v4zQ8#B!edX$!(&`Blmzq_TW@)9lG+0x!)Ld0sQ6FNR=_XSd0)@CnXPRtk zNo}a6c4}$a%JRyKs;#N>LbbQmRaH-|t+%Z5N~>;aZS}ON-@9$q%Bj^gA**U-b$Lao zc4}>nHMP8IN=+@x*-8QDTWCSYs%|F=IUFjDnjP6`sK?*HNQvM(I_+WEA)5V>F)&zuo}?c^74v`0o}2AJ56>z z%H-iwokR9BQ+<#lFtX=S-}_D}{OYSvU&l~)4t0CMe`T3X%OsVhS(t7_J8Ft8t> zuWzB7DY)PgVkjJ{sVuE9Lp3#3HFHd~5vl<~)K}JoO08Q;mjNnPRaxk(kK&fniaId{ z^)ZtzK;N|HG={)PlP$#+#)zwusb)m8al|bt9 zvg=D%1S>JY^2!wh+V-Mtr^wt}N^9IQ&Z|qSsw&)91IJX2u{woH>Xy$+7V1ClZPYdt zy#DXXQ14B=cjxx<`6ly@GFb)ggVDO~7OYK~gW7$FydqQ?swo97*H@MUD5fZ8E|@pR zTvlFJTU}~}%+MXTlmb$rvL8PV+YGP|=Tq7ihE^MU1*NEsA^@%EDP0vOl!^3nvhuqc%$XXW=(yixw^dW7I2l4Mb|I6w0Q2f zuD`B$Zt#-j^%WIM&E-`!W~sR5Xus;rm9TOcN1Tyib9ix zXNq;hRsjC4pvYwR;~LyYc~z1Xu^GEeb{@*Zbm8p|E{pL9wmD_W)cVR=7h@f+$=FiV zzXNH>TJ`_5c z7ru!)E-#!g*5ouxIC}k6CVTEOlPz3eGA!uIQY?LqU?R+X(qx$^GXYoD_&%Jz`9hOH zoM8F!kE74UmzZ@m^`YCaPQ+xsh5OZ2l_94dtruOL*O_c(sJ6CrMTocO!un#gcMW)Z z|32=>2hTvC#9L^bTk*T9n&^UL3P~n31Uz)*-ZjbLUit-#HhVY{nGuNn97>Y8hv;>O7N8 zcuK6-r)V=5mpNhCnmXXaJWxnQm315FW`0$DW!d$ZOW8H`bq&)@v zX;^g3W84+o-T4YWa9V1gwiGnDs=TJEl0-Cg2uODlCy=>i<+arnrE9Y6HA zd*UGc%M`N|45N;g2Yo+{zNe$@{_8OT_?4P$rF1!AIDecor?g^qDYyo2VZy}81DayL z2VT&><7jgl?#_5Da9)h2va0eTXjwq@(+q_Lo)+|dnt6~?z_F@-uXmu%h3Kn~mdh*4 z>&i(S@F7nYh-vJZ z5)(Q~l_lsCeVPJa#XPXqC`&Z9689mvyW@9NJYE^&-h}Tt_+A2rK{~~NX0X0)JI|tA z2EGrJOlPYF4enha66u$z|04ST7;O*3_4I;1zPI&ClXYJKdd0o}`%XMRi*hf2%Vfoz zF>&tbfVh;u0f}7C#l3kYfK*{Fs;jC29~2t7Syo>|NJIjaV`o{Y7W~vAmWDB;Uv1+5 zg12nN@4=%N_%)TFUqPDLuQ3OruQtGN6z+q|_m^QuQTD6Iu-w>}lVN43M>5Rq|7>Jf z3+lKsEDLaO`RF@Wf#1%@+FX9J40{K4GSSZjTm(mwLv)cW61pfC1pFJx8M-Dt z?HX8hRrNI%|4r|x#nPG;{5!Oay3opN>#OQYgLhb=P+17Fw{B4=bQ`tc;Msg=Y&VdB zbW^CN${EN!$V2Dng39XpxI3b zcsma)!vZpsQXX7cUAJaIZE^p1eGfNO)mM~VN}QxvD0;y=0G!%OYpQMwRW2;AcKe=J zwYrj2!v&SF5z*@0s>(_ZZ084vqL?^7<|zhS(r4pbUR7Jy@3F52AQ*C6LIc-@mJ<^P zPJoY?So6U&ays3Oh7U`OSR|1e8@*fDqr=e#@hg&FS-6JcBD|w(nDb2dN@eJK8ZNLi z&I{c;eW!Xj_-<;QKb*AHcN%*PXa(a4pAGf@?0WLR=T%GH`iu{T}W1 zK5Md1aQ!b_zr)pq>u0!j;`$Z7KZN^cTzBHCz*UNCF|Gx;zJY5tuF1GkPpPdj_GE{U zBfD@XIxYp>K=>#940FueLJ(!OW_>Lv*BpC^`K{oMOBMyMzJ77>l_>vv)Vm0GcfGmX z;R3X#boG)|Aq%T&mBPjOjA=8b&+yNfF{5zC%o#;9 zX3dygSWq~vaC)J?a7JNa;mpFK!dZp0XBNzyHgoz+|I8UP3un%pSu}Ij%-KZ+MbnC= z7x{~36crZDEGjCRRWy56!K`VsrqA-vnlYDj0@8?Ruu zeaFO%1k3{Upw(qiX-JO|3Jx?G#@=^ym0$g<$!P&bjCD(>cI+jWTyipcES*phT3%Lco8O<1I$`p}-z@FZGj85&vi{Fm<-j>y zM{#{;%9JVpK&q7k0Mg|KXnCaXEnUi9Kwm`vzsH^U$a}ccc$S4$lvkRt*T}4%0D1Rw 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 From ddb7935ebc08c8d27aef7fc2b7762f7099fba1d8 Mon Sep 17 00:00:00 2001 From: Chris Tian Date: Wed, 20 Mar 2024 19:10:41 -0700 Subject: [PATCH 06/18] tests pass again --- core/src/operations/field/field_den.rs | 1 - .../operations/field/field_inner_product.rs | 3 - core/src/operations/field/field_op.rs | 9 +- core/src/operations/field/field_sqrt.rs | 4 - core/src/syscall/precompiles/mod.rs | 11 +- .../weierstrass/weierstrass_add.rs | 2 +- .../weierstrass/weierstrass_double.rs | 4 +- derive/src/lib.rs | 4 +- examples/chess/script/Cargo.lock | 121 ++++++++++-------- .../program/elf/riscv32im-succinct-zkvm-elf | Bin 197188 -> 197196 bytes examples/ed25519/script/Cargo.lock | 21 ++- .../program/elf/riscv32im-succinct-zkvm-elf | Bin 102932 -> 102976 bytes examples/fibonacci-io/script/Cargo.lock | 21 ++- .../program/elf/riscv32im-succinct-zkvm-elf | Bin 83444 -> 83472 bytes examples/fibonacci/script/Cargo.lock | 21 ++- .../program/elf/riscv32im-succinct-zkvm-elf | Bin 167844 -> 167896 bytes examples/io/script/Cargo.lock | 21 ++- examples/json/script/Cargo.lock | 21 ++- examples/regex/script/Cargo.lock | 21 ++- .../program/elf/riscv32im-succinct-zkvm-elf | Bin 315312 -> 315260 bytes examples/rsa/script/Cargo.lock | 21 ++- examples/ssz-withdrawals/script/Cargo.lock | 21 ++- examples/tendermint/script/Cargo.lock | 25 +++- 23 files changed, 230 insertions(+), 122 deletions(-) diff --git a/core/src/operations/field/field_den.rs b/core/src/operations/field/field_den.rs index 59cba9db4b..3a81dfb448 100644 --- a/core/src/operations/field/field_den.rs +++ b/core/src/operations/field/field_den.rs @@ -3,7 +3,6 @@ use super::util::{compute_root_quotient_and_shift, split_u16_limbs_to_u8_limbs}; use super::util_air::eval_field_operation; use crate::air::Polynomial; use crate::air::SP1AirBuilder; -use crate::utils::ec::field::FieldParameters; use crate::utils::ec::field::{limbs_from_vec, FieldParameters}; use core::borrow::Borrow; use num::BigUint; diff --git a/core/src/operations/field/field_inner_product.rs b/core/src/operations/field/field_inner_product.rs index ec19f2c193..8d0b43946f 100644 --- a/core/src/operations/field/field_inner_product.rs +++ b/core/src/operations/field/field_inner_product.rs @@ -3,7 +3,6 @@ use super::util::{compute_root_quotient_and_shift, split_u16_limbs_to_u8_limbs}; use super::util_air::eval_field_operation; use crate::air::Polynomial; use crate::air::SP1AirBuilder; -use crate::utils::ec::field::FieldParameters; use crate::utils::ec::field::{limbs_from_vec, FieldParameters}; use core::borrow::Borrow; use num::BigUint; @@ -135,10 +134,8 @@ mod tests { use crate::operations::field::params::{NumLimbs, NumLimbs32}; use crate::stark::StarkGenericConfig; use crate::utils::ec::edwards::ed25519::Ed25519BaseField; - use crate::utils::ec::field::FieldParameters; use crate::utils::ec::field::{limbs_from_vec, FieldParameters}; use crate::utils::{pad_to_power_of_two, BabyBearPoseidon2}; - use crate::utils::{pad_to_power_of_two, BabyBearPoseidon2, StarkUtils}; use crate::utils::{uni_stark_prove as prove, uni_stark_verify as verify}; use crate::{air::SP1AirBuilder, runtime::ExecutionRecord}; use core::borrow::{Borrow, BorrowMut}; diff --git a/core/src/operations/field/field_op.rs b/core/src/operations/field/field_op.rs index b38eaabe39..84787308fd 100644 --- a/core/src/operations/field/field_op.rs +++ b/core/src/operations/field/field_op.rs @@ -3,10 +3,8 @@ use super::util::{compute_root_quotient_and_shift, split_u16_limbs_to_u8_limbs}; use super::util_air::eval_field_operation; use crate::air::Polynomial; use crate::air::SP1AirBuilder; -use crate::utils::ec::field::FieldParameters; use crate::utils::ec::field::{limbs_from_vec, FieldParameters}; use core::borrow::Borrow; -use generic_array::ArrayLength; use num::{BigUint, Zero}; use p3_air::AirBuilder; use p3_field::PrimeField32; @@ -188,7 +186,11 @@ mod tests { use crate::operations::field::params::NumLimbs32; use crate::stark::StarkGenericConfig; use crate::utils::ec::edwards::ed25519::Ed25519BaseField; - use crate::utils::{pad_to_power_of_two, BabyBearPoseidon2, StarkUtils}; + use crate::utils::ec::field::{limbs_from_vec, FieldParameters}; + use crate::utils::{ + pad_to_power_of_two, uni_stark_prove as prove, uni_stark_verify as verify, + BabyBearPoseidon2, + }; use crate::{air::SP1AirBuilder, runtime::ExecutionRecord}; use core::borrow::{Borrow, BorrowMut}; use num::bigint::RandBigInt; @@ -198,6 +200,7 @@ mod tests { use p3_matrix::MatrixRowSlices; use rand::thread_rng; use sp1_derive::AlignedBorrow; + use std::mem::size_of; #[derive(AlignedBorrow, Debug, Clone)] pub struct TestCols { diff --git a/core/src/operations/field/field_sqrt.rs b/core/src/operations/field/field_sqrt.rs index c549466aab..f7bf264d58 100644 --- a/core/src/operations/field/field_sqrt.rs +++ b/core/src/operations/field/field_sqrt.rs @@ -1,9 +1,7 @@ use super::field_op::FieldOpCols; use super::params::{Limbs, NumLimbs}; use crate::air::SP1AirBuilder; -use crate::utils::ec::field::FieldParameters; use crate::utils::ec::field::{limbs_from_vec, FieldParameters}; -use core::borrow::Borrow; use num::BigUint; use p3_field::PrimeField32; use sp1_derive::AlignedBorrow; @@ -91,10 +89,8 @@ mod tests { use crate::operations::field::params::NumLimbs32; use crate::stark::StarkGenericConfig; use crate::utils::ec::edwards::ed25519::{ed25519_sqrt, Ed25519BaseField}; - use crate::utils::ec::field::FieldParameters; use crate::utils::ec::field::{limbs_from_vec, FieldParameters}; use crate::utils::{pad_to_power_of_two, BabyBearPoseidon2}; - use crate::utils::{pad_to_power_of_two, BabyBearPoseidon2, StarkUtils}; use crate::utils::{uni_stark_prove as prove, uni_stark_verify as verify}; use crate::{air::SP1AirBuilder, runtime::ExecutionRecord}; use core::borrow::{Borrow, BorrowMut}; diff --git a/core/src/syscall/precompiles/mod.rs b/core/src/syscall/precompiles/mod.rs index d3a64432ba..6b460babea 100644 --- a/core/src/syscall/precompiles/mod.rs +++ b/core/src/syscall/precompiles/mod.rs @@ -14,7 +14,6 @@ use crate::operations::field::params::Limbs; use crate::runtime::SyscallContext; use crate::utils::ec::field::FieldParameters; use crate::utils::ec::{AffinePoint, EllipticCurve}; -use crate::{cpu::MemoryReadRecord, cpu::MemoryWriteRecord}; use crate::{runtime::MemoryReadRecord, runtime::MemoryWriteRecord}; use p3_field::AbstractField; @@ -56,7 +55,7 @@ pub fn create_ec_add_event( let p_affine = AffinePoint::::from_words_le(&p); let q_affine = AffinePoint::::from_words_le(&q); let result_affine = p_affine + q_affine; - let result_words = result_affine.to_words_le::(); + let result_words = result_affine.to_words_le::<32>(); // TODO: FIX let p_memory_records = rt.mw_slice(p_ptr, &result_words).try_into().unwrap(); @@ -97,7 +96,7 @@ pub fn create_ec_double_event( let p: [u32; 16] = rt.slice_unsafe(p_ptr, 16).try_into().unwrap(); let p_affine = AffinePoint::::from_words_le(&p); let result_affine = E::ec_double(&p_affine); - let result_words = result_affine.to_words_le::(); + let result_words = result_affine.to_words_le::<32>(); let p_memory_records = rt.mw_slice(p_ptr, &result_words).try_into().unwrap(); ECDoubleEvent { @@ -114,8 +113,8 @@ where AB: SP1AirBuilder, { let a_const = F::to_limbs_field::(value); - debug_assert_eq!(a_const.len(), NUM_LIMBS); - let mut a = [AB::F::zero(); NUM_LIMBS]; - a[..NUM_LIMBS].copy_from_slice(&a_const[..NUM_LIMBS]); + debug_assert_eq!(a_const.len(), 32); + let mut a = [AB::F::zero(); 32]; + a[..32].copy_from_slice(&a_const[..32]); Limbs(a.map(|x| x.into()).into()) } diff --git a/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs b/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs index ba3ffcd809..6b95e6bdea 100644 --- a/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs +++ b/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs @@ -167,7 +167,7 @@ where let mut new_byte_lookup_events = Vec::new(); for i in 0..input.weierstrass_add_events.len() { - let event = input.weierstrass_add_events[i]; + let event = &input.weierstrass_add_events[i]; let mut row = [F::zero(); num_weierstrass_add_cols::()]; let cols: &mut WeierstrassAddAssignCols = row.as_mut_slice().borrow_mut(); diff --git a/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs b/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs index 0276da509f..8145913462 100644 --- a/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs +++ b/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs @@ -200,8 +200,8 @@ where let rows = events .iter() .map(|event| { - let mut row = [F::zero(); NUM_WEIERSTRASS_DOUBLE_COLS]; - let cols: &mut WeierstrassDoubleAssignCols = + let mut row = [F::zero(); num_weierstrass_double_cols::()]; + let cols: &mut WeierstrassDoubleAssignCols = row.as_mut_slice().borrow_mut(); // Decode affine points. diff --git a/derive/src/lib.rs b/derive/src/lib.rs index 80cad2af67..2ba619f79e 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -67,7 +67,7 @@ pub fn aligned_borrow_derive(input: TokenStream) -> TokenStream { .collect::>(); let methods = quote! { - impl #impl_generics Borrow<#name #type_generics> for [#type_generic] #where_clause { + impl #impl_generics core::borrow::Borrow<#name #type_generics> for [#type_generic] #where_clause { fn borrow(&self) -> &#name #type_generics { debug_assert_eq!(self.len(), std::mem::size_of::<#name>()); let (prefix, shorts, _suffix) = unsafe { self.align_to::<#name #type_generics>() }; @@ -77,7 +77,7 @@ pub fn aligned_borrow_derive(input: TokenStream) -> TokenStream { } } - impl #impl_generics std::borrow::BorrowMut<#name #type_generics> for [#type_generic] #where_clause { + impl #impl_generics core::borrow::BorrowMut<#name #type_generics> for [#type_generic] #where_clause { fn borrow_mut(&mut self) -> &mut #name #type_generics { debug_assert_eq!(self.len(), std::mem::size_of::<#name>()); let (prefix, shorts, _suffix) = unsafe { self.align_to_mut::<#name #type_generics>() }; diff --git a/examples/chess/script/Cargo.lock b/examples/chess/script/Cargo.lock index b478c5466c..413158fd22 100644 --- a/examples/chess/script/Cargo.lock +++ b/examples/chess/script/Cargo.lock @@ -207,7 +207,7 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array", + "generic-array 0.14.7", ] [[package]] @@ -403,7 +403,7 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ - "generic-array", + "generic-array 0.14.7", "rand_core", "subtle", "zeroize", @@ -415,7 +415,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array", + "generic-array 0.14.7", "typenum", ] @@ -568,7 +568,7 @@ dependencies = [ "crypto-bigint", "digest", "ff", - "generic-array", + "generic-array 0.14.7", "group", "pkcs8", "rand_core", @@ -733,6 +733,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "generic-array" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe739944a5406424e080edccb6add95685130b9f160d5407c639c7df0c5836b0" +dependencies = [ + "typenum", +] + [[package]] name = "getrandom" version = "0.2.12" @@ -849,6 +858,15 @@ dependencies = [ "serde", ] +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.12.1" @@ -1094,7 +1112,7 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "p3-air" version = "0.1.0" -source = "git+https://github.com/succinctlabs/plonky3.git#7d11ba55fa2c939449b593df298d04d7e15979d5" +source = "git+https://github.com/Plonky3/Plonky3.git?branch=sp1#4809fa7bedd9ba8f6f5d3267b1592618e3776c57" dependencies = [ "p3-field", "p3-matrix", @@ -1103,9 +1121,13 @@ dependencies = [ [[package]] name = "p3-baby-bear" version = "0.1.0" -source = "git+https://github.com/succinctlabs/plonky3.git#7d11ba55fa2c939449b593df298d04d7e15979d5" +source = "git+https://github.com/Plonky3/Plonky3.git?branch=sp1#4809fa7bedd9ba8f6f5d3267b1592618e3776c57" dependencies = [ + "num-bigint", "p3-field", + "p3-mds", + "p3-poseidon2", + "p3-symmetric", "rand", "serde", ] @@ -1113,7 +1135,7 @@ dependencies = [ [[package]] name = "p3-blake3" version = "0.1.0" -source = "git+https://github.com/succinctlabs/plonky3.git#7d11ba55fa2c939449b593df298d04d7e15979d5" +source = "git+https://github.com/Plonky3/Plonky3.git?branch=sp1#4809fa7bedd9ba8f6f5d3267b1592618e3776c57" dependencies = [ "blake3", "p3-symmetric", @@ -1122,7 +1144,7 @@ dependencies = [ [[package]] name = "p3-challenger" version = "0.1.0" -source = "git+https://github.com/succinctlabs/plonky3.git#7d11ba55fa2c939449b593df298d04d7e15979d5" +source = "git+https://github.com/Plonky3/Plonky3.git?branch=sp1#4809fa7bedd9ba8f6f5d3267b1592618e3776c57" dependencies = [ "p3-field", "p3-maybe-rayon", @@ -1134,31 +1156,36 @@ dependencies = [ [[package]] name = "p3-commit" version = "0.1.0" -source = "git+https://github.com/succinctlabs/plonky3.git#7d11ba55fa2c939449b593df298d04d7e15979d5" +source = "git+https://github.com/Plonky3/Plonky3.git?branch=sp1#4809fa7bedd9ba8f6f5d3267b1592618e3776c57" dependencies = [ + "itertools 0.12.1", "p3-challenger", "p3-field", "p3-matrix", + "p3-util", "serde", ] [[package]] name = "p3-dft" version = "0.1.0" -source = "git+https://github.com/succinctlabs/plonky3.git#7d11ba55fa2c939449b593df298d04d7e15979d5" +source = "git+https://github.com/Plonky3/Plonky3.git?branch=sp1#4809fa7bedd9ba8f6f5d3267b1592618e3776c57" dependencies = [ "p3-field", "p3-matrix", "p3-maybe-rayon", "p3-util", + "tracing", ] [[package]] name = "p3-field" version = "0.1.0" -source = "git+https://github.com/succinctlabs/plonky3.git#7d11ba55fa2c939449b593df298d04d7e15979d5" +source = "git+https://github.com/Plonky3/Plonky3.git?branch=sp1#4809fa7bedd9ba8f6f5d3267b1592618e3776c57" dependencies = [ - "itertools", + "itertools 0.12.1", + "num-bigint", + "num-traits", "p3-util", "rand", "serde", @@ -1167,9 +1194,9 @@ dependencies = [ [[package]] name = "p3-fri" version = "0.1.0" -source = "git+https://github.com/succinctlabs/plonky3.git#7d11ba55fa2c939449b593df298d04d7e15979d5" +source = "git+https://github.com/Plonky3/Plonky3.git?branch=sp1#4809fa7bedd9ba8f6f5d3267b1592618e3776c57" dependencies = [ - "itertools", + "itertools 0.12.1", "p3-challenger", "p3-commit", "p3-dft", @@ -1185,9 +1212,14 @@ dependencies = [ [[package]] name = "p3-goldilocks" version = "0.1.0" -source = "git+https://github.com/succinctlabs/plonky3.git#7d11ba55fa2c939449b593df298d04d7e15979d5" +source = "git+https://github.com/Plonky3/Plonky3.git?branch=sp1#4809fa7bedd9ba8f6f5d3267b1592618e3776c57" dependencies = [ + "num-bigint", + "p3-dft", "p3-field", + "p3-mds", + "p3-poseidon2", + "p3-symmetric", "p3-util", "rand", "serde", @@ -1196,7 +1228,7 @@ dependencies = [ [[package]] name = "p3-interpolation" version = "0.1.0" -source = "git+https://github.com/succinctlabs/plonky3.git#7d11ba55fa2c939449b593df298d04d7e15979d5" +source = "git+https://github.com/Plonky3/Plonky3.git?branch=sp1#4809fa7bedd9ba8f6f5d3267b1592618e3776c57" dependencies = [ "p3-field", "p3-matrix", @@ -1206,7 +1238,7 @@ dependencies = [ [[package]] name = "p3-keccak" version = "0.1.0" -source = "git+https://github.com/succinctlabs/plonky3.git#7d11ba55fa2c939449b593df298d04d7e15979d5" +source = "git+https://github.com/Plonky3/Plonky3.git?branch=sp1#4809fa7bedd9ba8f6f5d3267b1592618e3776c57" dependencies = [ "p3-symmetric", "tiny-keccak", @@ -1215,7 +1247,7 @@ dependencies = [ [[package]] name = "p3-keccak-air" version = "0.1.0" -source = "git+https://github.com/succinctlabs/plonky3.git#7d11ba55fa2c939449b593df298d04d7e15979d5" +source = "git+https://github.com/Plonky3/Plonky3.git?branch=sp1#4809fa7bedd9ba8f6f5d3267b1592618e3776c57" dependencies = [ "p3-air", "p3-field", @@ -1227,19 +1259,21 @@ dependencies = [ [[package]] name = "p3-matrix" version = "0.1.0" -source = "git+https://github.com/succinctlabs/plonky3.git#7d11ba55fa2c939449b593df298d04d7e15979d5" +source = "git+https://github.com/Plonky3/Plonky3.git?branch=sp1#4809fa7bedd9ba8f6f5d3267b1592618e3776c57" dependencies = [ + "itertools 0.12.1", "p3-field", "p3-maybe-rayon", "p3-util", "rand", "serde", + "tracing", ] [[package]] name = "p3-maybe-rayon" version = "0.1.0" -source = "git+https://github.com/succinctlabs/plonky3.git#7d11ba55fa2c939449b593df298d04d7e15979d5" +source = "git+https://github.com/Plonky3/Plonky3.git?branch=sp1#4809fa7bedd9ba8f6f5d3267b1592618e3776c57" dependencies = [ "rayon", ] @@ -1247,14 +1281,12 @@ dependencies = [ [[package]] name = "p3-mds" version = "0.1.0" -source = "git+https://github.com/succinctlabs/plonky3.git#7d11ba55fa2c939449b593df298d04d7e15979d5" +source = "git+https://github.com/Plonky3/Plonky3.git?branch=sp1#4809fa7bedd9ba8f6f5d3267b1592618e3776c57" dependencies = [ - "p3-baby-bear", + "itertools 0.11.0", "p3-dft", "p3-field", - "p3-goldilocks", "p3-matrix", - "p3-mersenne-31", "p3-symmetric", "p3-util", "rand", @@ -1263,9 +1295,9 @@ dependencies = [ [[package]] name = "p3-merkle-tree" version = "0.1.0" -source = "git+https://github.com/succinctlabs/plonky3.git#7d11ba55fa2c939449b593df298d04d7e15979d5" +source = "git+https://github.com/Plonky3/Plonky3.git?branch=sp1#4809fa7bedd9ba8f6f5d3267b1592618e3776c57" dependencies = [ - "itertools", + "itertools 0.12.1", "p3-commit", "p3-field", "p3-matrix", @@ -1276,31 +1308,12 @@ dependencies = [ "tracing", ] -[[package]] -name = "p3-mersenne-31" -version = "0.1.0" -source = "git+https://github.com/succinctlabs/plonky3.git#7d11ba55fa2c939449b593df298d04d7e15979d5" -dependencies = [ - "itertools", - "p3-dft", - "p3-field", - "p3-matrix", - "p3-maybe-rayon", - "p3-util", - "rand", - "serde", -] - [[package]] name = "p3-poseidon2" version = "0.1.0" -source = "git+https://github.com/succinctlabs/plonky3.git#7d11ba55fa2c939449b593df298d04d7e15979d5" +source = "git+https://github.com/Plonky3/Plonky3.git?branch=sp1#4809fa7bedd9ba8f6f5d3267b1592618e3776c57" dependencies = [ - "p3-baby-bear", "p3-field", - "p3-goldilocks", - "p3-mds", - "p3-mersenne-31", "p3-symmetric", "rand", ] @@ -1308,9 +1321,9 @@ dependencies = [ [[package]] name = "p3-symmetric" version = "0.1.0" -source = "git+https://github.com/succinctlabs/plonky3.git#7d11ba55fa2c939449b593df298d04d7e15979d5" +source = "git+https://github.com/Plonky3/Plonky3.git?branch=sp1#4809fa7bedd9ba8f6f5d3267b1592618e3776c57" dependencies = [ - "itertools", + "itertools 0.12.1", "p3-field", "serde", ] @@ -1318,9 +1331,9 @@ dependencies = [ [[package]] name = "p3-uni-stark" version = "0.1.0" -source = "git+https://github.com/succinctlabs/plonky3.git#7d11ba55fa2c939449b593df298d04d7e15979d5" +source = "git+https://github.com/Plonky3/Plonky3.git?branch=sp1#4809fa7bedd9ba8f6f5d3267b1592618e3776c57" dependencies = [ - "itertools", + "itertools 0.12.1", "p3-air", "p3-challenger", "p3-commit", @@ -1336,7 +1349,7 @@ dependencies = [ [[package]] name = "p3-util" version = "0.1.0" -source = "git+https://github.com/succinctlabs/plonky3.git#7d11ba55fa2c939449b593df298d04d7e15979d5" +source = "git+https://github.com/Plonky3/Plonky3.git?branch=sp1#4809fa7bedd9ba8f6f5d3267b1592618e3776c57" dependencies = [ "serde", ] @@ -1625,7 +1638,7 @@ checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ "base16ct", "der", - "generic-array", + "generic-array 0.14.7", "pkcs8", "subtle", "zeroize", @@ -1791,9 +1804,10 @@ dependencies = [ "elf", "elliptic-curve", "flate2", + "generic-array 1.0.0", "hashbrown 0.14.3", "hex", - "itertools", + "itertools 0.12.1", "k256", "lazy_static", "log", @@ -1836,6 +1850,7 @@ dependencies = [ "tracing-forest", "tracing-log", "tracing-subscriber", + "typenum", ] [[package]] diff --git a/examples/ed25519/program/elf/riscv32im-succinct-zkvm-elf b/examples/ed25519/program/elf/riscv32im-succinct-zkvm-elf index 71cb9c6a380f1fa89b30a089c7f470e0f6c49bb4..a18b63297b080ce4c9d96476651cd4a992aee8a7 100755 GIT binary patch delta 16455 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 diff --git a/examples/fibonacci-io/script/Cargo.lock b/examples/fibonacci-io/script/Cargo.lock index d12ba8b9a2..9e1ecc19f8 100644 --- a/examples/fibonacci-io/script/Cargo.lock +++ b/examples/fibonacci-io/script/Cargo.lock @@ -207,7 +207,7 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array", + "generic-array 0.14.7", ] [[package]] @@ -392,7 +392,7 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ - "generic-array", + "generic-array 0.14.7", "rand_core", "subtle", "zeroize", @@ -404,7 +404,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array", + "generic-array 0.14.7", "typenum", ] @@ -557,7 +557,7 @@ dependencies = [ "crypto-bigint", "digest", "ff", - "generic-array", + "generic-array 0.14.7", "group", "pkcs8", "rand_core", @@ -730,6 +730,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "generic-array" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe739944a5406424e080edccb6add95685130b9f160d5407c639c7df0c5836b0" +dependencies = [ + "typenum", +] + [[package]] name = "getrandom" version = "0.2.12" @@ -1626,7 +1635,7 @@ checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ "base16ct", "der", - "generic-array", + "generic-array 0.14.7", "pkcs8", "subtle", "zeroize", @@ -1792,6 +1801,7 @@ dependencies = [ "elf", "elliptic-curve", "flate2", + "generic-array 1.0.0", "hashbrown 0.14.3", "hex", "itertools 0.12.1", @@ -1837,6 +1847,7 @@ dependencies = [ "tracing-forest", "tracing-log", "tracing-subscriber", + "typenum", ] [[package]] diff --git a/examples/fibonacci/program/elf/riscv32im-succinct-zkvm-elf b/examples/fibonacci/program/elf/riscv32im-succinct-zkvm-elf index 6ddfa99127a9f1a9ac81b0e65c77e21b7292d4ef..33a33ed26ca48209deca2ea339133502737e78fe 100755 GIT binary patch delta 14857 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 E0nIXTSpWb4 delta 14322 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 diff --git a/examples/fibonacci/script/Cargo.lock b/examples/fibonacci/script/Cargo.lock index 4348f3bffa..16a714ad1c 100644 --- a/examples/fibonacci/script/Cargo.lock +++ b/examples/fibonacci/script/Cargo.lock @@ -207,7 +207,7 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array", + "generic-array 0.14.7", ] [[package]] @@ -395,7 +395,7 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ - "generic-array", + "generic-array 0.14.7", "rand_core", "subtle", "zeroize", @@ -407,7 +407,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array", + "generic-array 0.14.7", "typenum", ] @@ -560,7 +560,7 @@ dependencies = [ "crypto-bigint", "digest", "ff", - "generic-array", + "generic-array 0.14.7", "group", "pkcs8", "rand_core", @@ -733,6 +733,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "generic-array" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe739944a5406424e080edccb6add95685130b9f160d5407c639c7df0c5836b0" +dependencies = [ + "typenum", +] + [[package]] name = "getrandom" version = "0.2.12" @@ -1629,7 +1638,7 @@ checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ "base16ct", "der", - "generic-array", + "generic-array 0.14.7", "pkcs8", "subtle", "zeroize", @@ -1795,6 +1804,7 @@ dependencies = [ "elf", "elliptic-curve", "flate2", + "generic-array 1.0.0", "hashbrown 0.14.3", "hex", "itertools 0.12.1", @@ -1840,6 +1850,7 @@ dependencies = [ "tracing-forest", "tracing-log", "tracing-subscriber", + "typenum", ] [[package]] diff --git a/examples/io/program/elf/riscv32im-succinct-zkvm-elf b/examples/io/program/elf/riscv32im-succinct-zkvm-elf index a5f708378b2f779b4ea5f846f771dd676d589cef..4d4a4f2c230c849e28af37e3093e0eb5291a6d03 100755 GIT binary patch delta 28759 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 R7vdyE?PbDIzUfKP@_%iu&mI5( delta 28872 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 ZPMi1>ICZ*$8_UrXxLN2Q%-ZVb{{b3-(S85` diff --git a/examples/io/script/Cargo.lock b/examples/io/script/Cargo.lock index 08181d95ab..ad815d3d28 100644 --- a/examples/io/script/Cargo.lock +++ b/examples/io/script/Cargo.lock @@ -207,7 +207,7 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array", + "generic-array 0.14.7", ] [[package]] @@ -395,7 +395,7 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ - "generic-array", + "generic-array 0.14.7", "rand_core", "subtle", "zeroize", @@ -407,7 +407,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array", + "generic-array 0.14.7", "typenum", ] @@ -560,7 +560,7 @@ dependencies = [ "crypto-bigint", "digest", "ff", - "generic-array", + "generic-array 0.14.7", "group", "pkcs8", "rand_core", @@ -725,6 +725,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "generic-array" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe739944a5406424e080edccb6add95685130b9f160d5407c639c7df0c5836b0" +dependencies = [ + "typenum", +] + [[package]] name = "getrandom" version = "0.2.12" @@ -1630,7 +1639,7 @@ checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ "base16ct", "der", - "generic-array", + "generic-array 0.14.7", "pkcs8", "subtle", "zeroize", @@ -1796,6 +1805,7 @@ dependencies = [ "elf", "elliptic-curve", "flate2", + "generic-array 1.0.0", "hashbrown 0.14.3", "hex", "itertools 0.12.1", @@ -1841,6 +1851,7 @@ dependencies = [ "tracing-forest", "tracing-log", "tracing-subscriber", + "typenum", ] [[package]] diff --git a/examples/json/script/Cargo.lock b/examples/json/script/Cargo.lock index cf7ab83372..20b80fcf18 100644 --- a/examples/json/script/Cargo.lock +++ b/examples/json/script/Cargo.lock @@ -207,7 +207,7 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array", + "generic-array 0.14.7", ] [[package]] @@ -395,7 +395,7 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ - "generic-array", + "generic-array 0.14.7", "rand_core", "subtle", "zeroize", @@ -407,7 +407,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array", + "generic-array 0.14.7", "typenum", ] @@ -560,7 +560,7 @@ dependencies = [ "crypto-bigint", "digest", "ff", - "generic-array", + "generic-array 0.14.7", "group", "pkcs8", "rand_core", @@ -725,6 +725,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "generic-array" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe739944a5406424e080edccb6add95685130b9f160d5407c639c7df0c5836b0" +dependencies = [ + "typenum", +] + [[package]] name = "getrandom" version = "0.2.12" @@ -1639,7 +1648,7 @@ checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ "base16ct", "der", - "generic-array", + "generic-array 0.14.7", "pkcs8", "subtle", "zeroize", @@ -1805,6 +1814,7 @@ dependencies = [ "elf", "elliptic-curve", "flate2", + "generic-array 1.0.0", "hashbrown 0.14.3", "hex", "itertools 0.12.1", @@ -1850,6 +1860,7 @@ dependencies = [ "tracing-forest", "tracing-log", "tracing-subscriber", + "typenum", ] [[package]] diff --git a/examples/regex/script/Cargo.lock b/examples/regex/script/Cargo.lock index 29bc0cddb3..4b3ca1d638 100644 --- a/examples/regex/script/Cargo.lock +++ b/examples/regex/script/Cargo.lock @@ -207,7 +207,7 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array", + "generic-array 0.14.7", ] [[package]] @@ -395,7 +395,7 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ - "generic-array", + "generic-array 0.14.7", "rand_core", "subtle", "zeroize", @@ -407,7 +407,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array", + "generic-array 0.14.7", "typenum", ] @@ -560,7 +560,7 @@ dependencies = [ "crypto-bigint", "digest", "ff", - "generic-array", + "generic-array 0.14.7", "group", "pkcs8", "rand_core", @@ -725,6 +725,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "generic-array" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe739944a5406424e080edccb6add95685130b9f160d5407c639c7df0c5836b0" +dependencies = [ + "typenum", +] + [[package]] name = "getrandom" version = "0.2.12" @@ -1629,7 +1638,7 @@ checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ "base16ct", "der", - "generic-array", + "generic-array 0.14.7", "pkcs8", "subtle", "zeroize", @@ -1795,6 +1804,7 @@ dependencies = [ "elf", "elliptic-curve", "flate2", + "generic-array 1.0.0", "hashbrown 0.14.3", "hex", "itertools 0.12.1", @@ -1840,6 +1850,7 @@ dependencies = [ "tracing-forest", "tracing-log", "tracing-subscriber", + "typenum", ] [[package]] diff --git a/examples/rsa/program/elf/riscv32im-succinct-zkvm-elf b/examples/rsa/program/elf/riscv32im-succinct-zkvm-elf index 7e65713c6fb2e38fbba239a8364d90fc937b82b1..2023b313d9b5da9da09638fb939c6028e4021d9c 100755 GIT binary patch delta 44713 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 diff --git a/examples/rsa/script/Cargo.lock b/examples/rsa/script/Cargo.lock index 3f5fd0b0fc..03c80c8e36 100644 --- a/examples/rsa/script/Cargo.lock +++ b/examples/rsa/script/Cargo.lock @@ -207,7 +207,7 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array", + "generic-array 0.14.7", ] [[package]] @@ -395,7 +395,7 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ - "generic-array", + "generic-array 0.14.7", "rand_core", "subtle", "zeroize", @@ -407,7 +407,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array", + "generic-array 0.14.7", "typenum", ] @@ -560,7 +560,7 @@ dependencies = [ "crypto-bigint", "digest", "ff", - "generic-array", + "generic-array 0.14.7", "group", "pkcs8", "rand_core", @@ -725,6 +725,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "generic-array" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe739944a5406424e080edccb6add95685130b9f160d5407c639c7df0c5836b0" +dependencies = [ + "typenum", +] + [[package]] name = "getrandom" version = "0.2.12" @@ -1629,7 +1638,7 @@ checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ "base16ct", "der", - "generic-array", + "generic-array 0.14.7", "pkcs8", "subtle", "zeroize", @@ -1795,6 +1804,7 @@ dependencies = [ "elf", "elliptic-curve", "flate2", + "generic-array 1.0.0", "hashbrown 0.14.3", "hex", "itertools 0.12.1", @@ -1840,6 +1850,7 @@ dependencies = [ "tracing-forest", "tracing-log", "tracing-subscriber", + "typenum", ] [[package]] diff --git a/examples/ssz-withdrawals/script/Cargo.lock b/examples/ssz-withdrawals/script/Cargo.lock index 251785f13a..14473b8b36 100644 --- a/examples/ssz-withdrawals/script/Cargo.lock +++ b/examples/ssz-withdrawals/script/Cargo.lock @@ -207,7 +207,7 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array", + "generic-array 0.14.7", ] [[package]] @@ -395,7 +395,7 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ - "generic-array", + "generic-array 0.14.7", "rand_core", "subtle", "zeroize", @@ -407,7 +407,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array", + "generic-array 0.14.7", "typenum", ] @@ -560,7 +560,7 @@ dependencies = [ "crypto-bigint", "digest", "ff", - "generic-array", + "generic-array 0.14.7", "group", "pkcs8", "rand_core", @@ -725,6 +725,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "generic-array" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe739944a5406424e080edccb6add95685130b9f160d5407c639c7df0c5836b0" +dependencies = [ + "typenum", +] + [[package]] name = "getrandom" version = "0.2.12" @@ -1621,7 +1630,7 @@ checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ "base16ct", "der", - "generic-array", + "generic-array 0.14.7", "pkcs8", "subtle", "zeroize", @@ -1787,6 +1796,7 @@ dependencies = [ "elf", "elliptic-curve", "flate2", + "generic-array 1.0.0", "hashbrown 0.14.3", "hex", "itertools 0.12.1", @@ -1832,6 +1842,7 @@ dependencies = [ "tracing-forest", "tracing-log", "tracing-subscriber", + "typenum", ] [[package]] diff --git a/examples/tendermint/script/Cargo.lock b/examples/tendermint/script/Cargo.lock index 8942ac614b..76837ab5e0 100644 --- a/examples/tendermint/script/Cargo.lock +++ b/examples/tendermint/script/Cargo.lock @@ -231,7 +231,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ - "generic-array", + "generic-array 0.14.7", ] [[package]] @@ -240,7 +240,7 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array", + "generic-array 0.14.7", ] [[package]] @@ -450,7 +450,7 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ - "generic-array", + "generic-array 0.14.7", "rand_core", "subtle", "zeroize", @@ -462,7 +462,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array", + "generic-array 0.14.7", "typenum", ] @@ -591,7 +591,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" dependencies = [ - "generic-array", + "generic-array 0.14.7", ] [[package]] @@ -671,7 +671,7 @@ dependencies = [ "crypto-bigint", "digest 0.10.7", "ff", - "generic-array", + "generic-array 0.14.7", "group", "pkcs8", "rand_core", @@ -878,6 +878,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "generic-array" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe739944a5406424e080edccb6add95685130b9f160d5407c639c7df0c5836b0" +dependencies = [ + "typenum", +] + [[package]] name = "getrandom" version = "0.2.12" @@ -2105,7 +2114,7 @@ checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ "base16ct", "der", - "generic-array", + "generic-array 0.14.7", "pkcs8", "subtle", "zeroize", @@ -2368,6 +2377,7 @@ dependencies = [ "elf", "elliptic-curve", "flate2", + "generic-array 1.0.0", "hashbrown 0.14.3", "hex", "itertools 0.12.1", @@ -2413,6 +2423,7 @@ dependencies = [ "tracing-forest", "tracing-log", "tracing-subscriber", + "typenum", ] [[package]] From 5dccbaf7117bf4bdc88bf3cbdd3b143b53796967 Mon Sep 17 00:00:00 2001 From: Chris Tian Date: Wed, 20 Mar 2024 21:15:43 -0700 Subject: [PATCH 07/18] cleanup --- core/src/operations/field/field_den.rs | 7 ++----- .../operations/field/field_inner_product.rs | 4 ++-- core/src/operations/field/field_op.rs | 2 +- core/src/operations/field/field_sqrt.rs | 6 +++--- core/src/operations/field/params.rs | 2 -- .../src/syscall/precompiles/edwards/ed_add.rs | 2 -- core/src/syscall/precompiles/edwards/mod.rs | 6 ------ core/src/syscall/precompiles/k256/mod.rs | 6 ------ core/src/syscall/precompiles/mod.rs | 5 ++--- .../syscall/precompiles/weierstrass/mod.rs | 6 ------ .../weierstrass/weierstrass_add.rs | 2 -- .../weierstrass/weierstrass_double.rs | 2 -- core/src/utils/ec/field.rs | 2 +- core/src/utils/ec/mod.rs | 6 +++--- core/src/utils/ec/weierstrass/bn254.rs | 4 +--- core/src/utils/ec/weierstrass/secp256k1.rs | 5 +---- derive/src/lib.rs | 21 ++++++++++--------- 17 files changed, 27 insertions(+), 61 deletions(-) diff --git a/core/src/operations/field/field_den.rs b/core/src/operations/field/field_den.rs index 3a81dfb448..5d6737b77a 100644 --- a/core/src/operations/field/field_den.rs +++ b/core/src/operations/field/field_den.rs @@ -4,7 +4,7 @@ use super::util_air::eval_field_operation; use crate::air::Polynomial; use crate::air::SP1AirBuilder; use crate::utils::ec::field::{limbs_from_vec, FieldParameters}; -use core::borrow::Borrow; + use num::BigUint; use p3_field::PrimeField32; use sp1_derive::AlignedBorrow; @@ -164,9 +164,6 @@ mod tests { pub a_den_b: FieldDenCols, } - const NUM_LIMBS: usize = 32; - const NUM_WITNESS_LIMBS: usize = NUM_LIMBS * 2 - 2; - pub const NUM_TEST_COLS: usize = size_of::>(); struct FieldDenChip { @@ -275,7 +272,7 @@ mod tests { } #[test] - fn prove_field_den_babybear() { + fn prove_field() { let config = BabyBearPoseidon2::new(); let mut challenger = config.challenger(); diff --git a/core/src/operations/field/field_inner_product.rs b/core/src/operations/field/field_inner_product.rs index 8d0b43946f..6fbc11215d 100644 --- a/core/src/operations/field/field_inner_product.rs +++ b/core/src/operations/field/field_inner_product.rs @@ -4,7 +4,7 @@ use super::util_air::eval_field_operation; use crate::air::Polynomial; use crate::air::SP1AirBuilder; use crate::utils::ec::field::{limbs_from_vec, FieldParameters}; -use core::borrow::Borrow; + use num::BigUint; use num::Zero; use p3_field::{AbstractField, PrimeField32}; @@ -131,7 +131,7 @@ mod tests { use crate::air::MachineAir; - use crate::operations::field::params::{NumLimbs, NumLimbs32}; + use crate::operations::field::params::{NumLimbs32}; use crate::stark::StarkGenericConfig; use crate::utils::ec::edwards::ed25519::Ed25519BaseField; use crate::utils::ec::field::{limbs_from_vec, FieldParameters}; diff --git a/core/src/operations/field/field_op.rs b/core/src/operations/field/field_op.rs index 84787308fd..8de5a7b48b 100644 --- a/core/src/operations/field/field_op.rs +++ b/core/src/operations/field/field_op.rs @@ -4,7 +4,7 @@ use super::util_air::eval_field_operation; use crate::air::Polynomial; use crate::air::SP1AirBuilder; use crate::utils::ec::field::{limbs_from_vec, FieldParameters}; -use core::borrow::Borrow; + use num::{BigUint, Zero}; use p3_air::AirBuilder; use p3_field::PrimeField32; diff --git a/core/src/operations/field/field_sqrt.rs b/core/src/operations/field/field_sqrt.rs index f7bf264d58..3b3692ec28 100644 --- a/core/src/operations/field/field_sqrt.rs +++ b/core/src/operations/field/field_sqrt.rs @@ -61,15 +61,15 @@ where // As a space-saving hack, we store the sqrt of the input in `self.multiplication.result` // even though it's technically not the result of the multiplication. Now, we should // retrieve that value and overwrite that member variable with a. - let sqrt = &self.multiplication.result; + let sqrt = self.multiplication.result; let mut multiplication = self.multiplication.clone(); multiplication.result = *a; // Compute sqrt * sqrt. We pass in P since we want its BaseField to be the mod. multiplication.eval::, Limbs>( builder, - sqrt, - sqrt, + &sqrt, + &sqrt, super::field_op::FieldOperation::Mul, ); } diff --git a/core/src/operations/field/params.rs b/core/src/operations/field/params.rs index 4e1bc28548..b7fed3fad2 100644 --- a/core/src/operations/field/params.rs +++ b/core/src/operations/field/params.rs @@ -6,9 +6,7 @@ use std::slice::Iter; use std::usize; use typenum::{U32, U62}; -// pub const NUM_LIMBS: usize = 32; pub const NB_BITS_PER_LIMB: usize = 8; -// pub const NUM_WITNESS_LIMBS: usize = 2 * NUM_LIMBS - 2; #[derive(Debug, Clone)] pub struct Limbs(pub GenericArray); diff --git a/core/src/syscall/precompiles/edwards/ed_add.rs b/core/src/syscall/precompiles/edwards/ed_add.rs index 2957e19651..ae98b12595 100644 --- a/core/src/syscall/precompiles/edwards/ed_add.rs +++ b/core/src/syscall/precompiles/edwards/ed_add.rs @@ -42,8 +42,6 @@ use std::marker::PhantomData; use tracing::instrument; use typenum::U32; -use super::NUM_LIMBS; - pub const NUM_ED_ADD_COLS: usize = size_of::>(); /// A set of columns to compute `EdAdd` where a, b are field elements. diff --git a/core/src/syscall/precompiles/edwards/mod.rs b/core/src/syscall/precompiles/edwards/mod.rs index 4e38345292..dadf241f78 100644 --- a/core/src/syscall/precompiles/edwards/mod.rs +++ b/core/src/syscall/precompiles/edwards/mod.rs @@ -3,9 +3,3 @@ mod ed_decompress; pub use ed_add::*; pub use ed_decompress::*; - -// The number of limbs in the field representation. -const NUM_LIMBS: usize = 32; - -/// The number of `u8` witness limbs in the field representation. -const NUM_WITNESS_LIMBS: usize = 2 * NUM_LIMBS - 2; diff --git a/core/src/syscall/precompiles/k256/mod.rs b/core/src/syscall/precompiles/k256/mod.rs index c65a9f3448..6557de6e00 100644 --- a/core/src/syscall/precompiles/k256/mod.rs +++ b/core/src/syscall/precompiles/k256/mod.rs @@ -1,9 +1,3 @@ mod decompress; pub use decompress::*; - -// The number of limbs in the field representation. -const NUM_LIMBS: usize = 32; - -/// The number of `u8` witness limbs in the field representation. -const NUM_WITNESS_LIMBS: usize = 2 * NUM_LIMBS - 2; diff --git a/core/src/syscall/precompiles/mod.rs b/core/src/syscall/precompiles/mod.rs index 6b460babea..25273976b6 100644 --- a/core/src/syscall/precompiles/mod.rs +++ b/core/src/syscall/precompiles/mod.rs @@ -55,8 +55,7 @@ pub fn create_ec_add_event( let p_affine = AffinePoint::::from_words_le(&p); let q_affine = AffinePoint::::from_words_le(&q); let result_affine = p_affine + q_affine; - let result_words = result_affine.to_words_le::<32>(); - // TODO: FIX + let result_words = result_affine.to_words_le(); let p_memory_records = rt.mw_slice(p_ptr, &result_words).try_into().unwrap(); @@ -96,7 +95,7 @@ pub fn create_ec_double_event( let p: [u32; 16] = rt.slice_unsafe(p_ptr, 16).try_into().unwrap(); let p_affine = AffinePoint::::from_words_le(&p); let result_affine = E::ec_double(&p_affine); - let result_words = result_affine.to_words_le::<32>(); + let result_words = result_affine.to_words_le(); let p_memory_records = rt.mw_slice(p_ptr, &result_words).try_into().unwrap(); ECDoubleEvent { diff --git a/core/src/syscall/precompiles/weierstrass/mod.rs b/core/src/syscall/precompiles/weierstrass/mod.rs index 3f02fedc72..3d397634e5 100644 --- a/core/src/syscall/precompiles/weierstrass/mod.rs +++ b/core/src/syscall/precompiles/weierstrass/mod.rs @@ -3,9 +3,3 @@ mod weierstrass_double; pub use weierstrass_add::*; pub use weierstrass_double::*; - -// The number of `u8` limbs in the field representation. -const NUM_LIMBS: usize = 32; - -/// The number of `u8` witness limbs in the field representation. -const NUM_WITNESS_LIMBS: usize = 2 * NUM_LIMBS - 2; diff --git a/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs b/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs index 6b95e6bdea..f20b2ef476 100644 --- a/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs +++ b/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs @@ -33,8 +33,6 @@ use sp1_derive::AlignedBorrow; use std::fmt::Debug; use std::marker::PhantomData; -use super::NUM_LIMBS; - pub const fn num_weierstrass_add_cols() -> usize { size_of::>() } diff --git a/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs b/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs index 8145913462..23b53b6b8e 100644 --- a/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs +++ b/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs @@ -38,8 +38,6 @@ use std::marker::PhantomData; use tracing::instrument; use typenum::U32; -use super::NUM_LIMBS; - pub const fn num_weierstrass_double_cols() -> usize { size_of::>() } diff --git a/core/src/utils/ec/field.rs b/core/src/utils/ec/field.rs index af67f6a7ed..36d7a48f72 100644 --- a/core/src/utils/ec/field.rs +++ b/core/src/utils/ec/field.rs @@ -50,7 +50,7 @@ pub trait FieldParameters: /// Convert a vec of u8 limbs to a Limbs of NUM_LIMBS. pub fn limbs_from_vec(limbs: Vec) -> Limbs { debug_assert_eq!(limbs.len(), N::USIZE); - let mut result = GenericArray::::generate(|i| F::zero()); + let mut result = GenericArray::::generate(|_i| F::zero()); for (i, limb) in limbs.into_iter().enumerate() { result[i] = limb; } diff --git a/core/src/utils/ec/mod.rs b/core/src/utils/ec/mod.rs index f42a442853..9601ccc419 100644 --- a/core/src/utils/ec/mod.rs +++ b/core/src/utils/ec/mod.rs @@ -55,11 +55,11 @@ impl AffinePoint { } } - pub fn to_words_le(&self) -> [u32; 16] { + pub fn to_words_le(&self) -> [u32; 16] { let mut x_bytes = self.x.to_bytes_le(); - x_bytes.resize(N, 0u8); + x_bytes.resize(32, 0u8); let mut y_bytes = self.y.to_bytes_le(); - y_bytes.resize(N, 0u8); + y_bytes.resize(32, 0u8); let mut words = [0u32; 16]; for i in 0..8 { diff --git a/core/src/utils/ec/weierstrass/bn254.rs b/core/src/utils/ec/weierstrass/bn254.rs index 32fb691aec..4ab04e4891 100644 --- a/core/src/utils/ec/weierstrass/bn254.rs +++ b/core/src/utils/ec/weierstrass/bn254.rs @@ -7,8 +7,6 @@ use crate::operations::field::params::NumLimbs; use crate::utils::ec::field::{FieldParameters, MAX_NB_LIMBS}; use crate::utils::ec::EllipticCurveParameters; -const NUM_LIMBS: usize = 16; - #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] /// Bn254 curve parameter pub struct Bn254Parameters; @@ -22,7 +20,7 @@ pub struct Bn254BaseField; impl FieldParameters for Bn254BaseField { const NB_BITS_PER_LIMB: usize = 16; - const NB_LIMBS: usize = NUM_LIMBS; + const NB_LIMBS: usize = 16; const NB_WITNESS_LIMBS: usize = 2 * Self::NB_LIMBS - 2; diff --git a/core/src/utils/ec/weierstrass/secp256k1.rs b/core/src/utils/ec/weierstrass/secp256k1.rs index 7249e57005..a70e2b470a 100644 --- a/core/src/utils/ec/weierstrass/secp256k1.rs +++ b/core/src/utils/ec/weierstrass/secp256k1.rs @@ -15,9 +15,6 @@ use k256::FieldElement; use num::traits::FromBytes; use num::traits::ToBytes; -/// Number of `u8` limbs in the base field of Secp256k1. -const NUM_LIMBS: usize = 32; - #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] /// Secp256k1 curve parameter pub struct Secp256k1Parameters; @@ -31,7 +28,7 @@ pub struct Secp256k1BaseField; impl FieldParameters for Secp256k1BaseField { const NB_BITS_PER_LIMB: usize = NB_BITS_PER_LIMB; - const NB_LIMBS: usize = NUM_LIMBS; + const NB_LIMBS: usize = 32; const NB_WITNESS_LIMBS: usize = 2 * Self::NB_LIMBS - 2; diff --git a/derive/src/lib.rs b/derive/src/lib.rs index 2ba619f79e..1920dfffe1 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -38,22 +38,20 @@ pub fn aligned_borrow_derive(input: TokenStream) -> TokenStream { let ast = parse_macro_input!(input as DeriveInput); let name = &ast.ident; - // Separate type generics and const generics - // First generic T + // Get first generic which must be a type (T in ) let type_generic = ast .generics .params .iter() - .find_map(|param| { - if let GenericParam::Type(type_param) = param { - Some(&type_param.ident) - } else { - None - } + .map(|param| match param { + GenericParam::Type(type_param) => &type_param.ident, + _ => panic!("Expected first generic to be a type"), }) - .expect("Expected at least one type generic"); + .next() + .expect("Expected at least one generic"); - let (impl_generics, type_generics, where_clause) = ast.generics.split_for_impl(); + // Get generics after the first (N: NumLimbs, const M: usize in ) + // We need this because when we assert the size, we want to substitute u8 for T. let non_first_generics = ast .generics .params @@ -66,6 +64,9 @@ pub fn aligned_borrow_derive(input: TokenStream) -> TokenStream { }) .collect::>(); + // Get impl generics (), type generics (), where clause (where T: Clone) + let (impl_generics, type_generics, where_clause) = ast.generics.split_for_impl(); + let methods = quote! { impl #impl_generics core::borrow::Borrow<#name #type_generics> for [#type_generic] #where_clause { fn borrow(&self) -> &#name #type_generics { From 5016a8a5c115ee7a409617bae35bb8389deac994 Mon Sep 17 00:00:00 2001 From: Chris Tian Date: Wed, 20 Mar 2024 21:18:53 -0700 Subject: [PATCH 08/18] cleanup comments --- derive/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/derive/src/lib.rs b/derive/src/lib.rs index 1920dfffe1..d3679de47d 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -38,7 +38,7 @@ pub fn aligned_borrow_derive(input: TokenStream) -> TokenStream { let ast = parse_macro_input!(input as DeriveInput); let name = &ast.ident; - // Get first generic which must be a type (T in ) + // Get first generic which must be type (ex. `T`) for input let type_generic = ast .generics .params @@ -50,7 +50,7 @@ pub fn aligned_borrow_derive(input: TokenStream) -> TokenStream { .next() .expect("Expected at least one generic"); - // Get generics after the first (N: NumLimbs, const M: usize in ) + // Get generics after the first (ex. `N: NumLimbs, const M: usize`) // We need this because when we assert the size, we want to substitute u8 for T. let non_first_generics = ast .generics @@ -64,7 +64,7 @@ pub fn aligned_borrow_derive(input: TokenStream) -> TokenStream { }) .collect::>(); - // Get impl generics (), type generics (), where clause (where T: Clone) + // Get impl generics (``), type generics (``), where clause (`where T: Clone`) let (impl_generics, type_generics, where_clause) = ast.generics.split_for_impl(); let methods = quote! { From d5eaa2142291955af6caf3cd173360c1165fd9ac Mon Sep 17 00:00:00 2001 From: Chris Tian Date: Thu, 21 Mar 2024 10:16:42 -0700 Subject: [PATCH 09/18] fixes --- core/src/lib.rs | 3 ++- core/src/operations/field/field_inner_product.rs | 5 +---- core/src/syscall/precompiles/edwards/ed_add.rs | 2 +- core/src/syscall/precompiles/weierstrass/weierstrass_add.rs | 3 ++- .../syscall/precompiles/weierstrass/weierstrass_double.rs | 3 ++- core/src/utils/ec/edwards/mod.rs | 1 + 6 files changed, 9 insertions(+), 8 deletions(-) diff --git a/core/src/lib.rs b/core/src/lib.rs index 9697c34ae3..23ae115f9c 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -8,7 +8,8 @@ clippy::type_complexity, clippy::unnecessary_unwrap, clippy::default_constructed_unit_structs, - clippy::box_default + clippy::box_default, + incomplete_features )] #![feature(generic_const_exprs)] diff --git a/core/src/operations/field/field_inner_product.rs b/core/src/operations/field/field_inner_product.rs index 6fbc11215d..02b6fad57b 100644 --- a/core/src/operations/field/field_inner_product.rs +++ b/core/src/operations/field/field_inner_product.rs @@ -131,7 +131,7 @@ mod tests { use crate::air::MachineAir; - use crate::operations::field::params::{NumLimbs32}; + use crate::operations::field::params::NumLimbs32; use crate::stark::StarkGenericConfig; use crate::utils::ec::edwards::ed25519::Ed25519BaseField; use crate::utils::ec::field::{limbs_from_vec, FieldParameters}; @@ -155,9 +155,6 @@ mod tests { pub a_ip_b: FieldInnerProductCols, } - const NUM_LIMBS: usize = 32; - const NUM_WITNESS_LIMBS: usize = 2 * NUM_LIMBS - 2; - type Limbs32 = U32; pub const NUM_TEST_COLS: usize = size_of::>(); diff --git a/core/src/syscall/precompiles/edwards/ed_add.rs b/core/src/syscall/precompiles/edwards/ed_add.rs index ae98b12595..6249bbce3e 100644 --- a/core/src/syscall/precompiles/edwards/ed_add.rs +++ b/core/src/syscall/precompiles/edwards/ed_add.rs @@ -278,7 +278,7 @@ where // Constraint self.p_access.value = [self.x3_ins.result, self.y3_ins.result] // This is to ensure that p_access is updated with the new value. - for i in 0..NUM_LIMBS { + for i in 0..E::BaseField::NB_LIMBS { builder .when(row.is_real) .assert_eq(row.x3_ins.result[i], row.p_access[i / 4].value()[i % 4]); diff --git a/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs b/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs index f20b2ef476..df9993b9c3 100644 --- a/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs +++ b/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs @@ -12,6 +12,7 @@ use crate::runtime::Syscall; use crate::runtime::SyscallCode; use crate::syscall::precompiles::create_ec_add_event; use crate::syscall::precompiles::SyscallContext; +use crate::utils::ec::field::FieldParameters; use crate::utils::ec::weierstrass::WeierstrassParameters; use crate::utils::ec::AffinePoint; use crate::utils::ec::EllipticCurve; @@ -319,7 +320,7 @@ where // Constraint self.p_access.value = [self.x3_ins.result, self.y3_ins.result]. This is to // ensure that p_access is updated with the new value. - for i in 0..NUM_LIMBS { + for i in 0..E::BaseField::NB_LIMBS { builder .when(row.is_real) .assert_eq(row.x3_ins.result[i], row.p_access[i / 4].value()[i % 4]); diff --git a/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs b/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs index 23b53b6b8e..196dbfd682 100644 --- a/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs +++ b/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs @@ -13,6 +13,7 @@ use crate::stark::MachineRecord; use crate::syscall::precompiles::create_ec_double_event; use crate::syscall::precompiles::limbs_from_biguint; use crate::syscall::precompiles::SyscallContext; +use crate::utils::ec::field::FieldParameters; use crate::utils::ec::weierstrass::WeierstrassParameters; use crate::utils::ec::AffinePoint; use crate::utils::ec::EllipticCurve; @@ -368,7 +369,7 @@ where // Constraint self.p_access.value = [self.x3_ins.result, self.y3_ins.result]. This is to // ensure that p_access is updated with the new value. - for i in 0..NUM_LIMBS { + for i in 0..E::BaseField::NB_LIMBS { builder .when(row.is_real) .assert_eq(row.x3_ins.result[i], row.p_access[i / 4].value()[i % 4]); diff --git a/core/src/utils/ec/edwards/mod.rs b/core/src/utils/ec/edwards/mod.rs index 6f39778085..fd976a5185 100644 --- a/core/src/utils/ec/edwards/mod.rs +++ b/core/src/utils/ec/edwards/mod.rs @@ -8,6 +8,7 @@ use crate::utils::ec::{AffinePoint, EllipticCurve, EllipticCurveParameters}; // The number of `u8` limbs in the base field of Ed25519. const NUM_LIMBS: usize = 32; + pub trait EdwardsParameters: EllipticCurveParameters { const D: [u16; MAX_NB_LIMBS]; From 973aa33656a9ad9fb76600be0fefbf7acda3c4b2 Mon Sep 17 00:00:00 2001 From: Chris Tian Date: Fri, 22 Mar 2024 14:12:15 -0700 Subject: [PATCH 10/18] make field ops generic on FieldParameters --- core/src/operations/field/field_den.rs | 50 +++---- .../operations/field/field_inner_product.rs | 70 +++++---- core/src/operations/field/field_op.rs | 84 +++++------ core/src/operations/field/field_sqrt.rs | 55 ++++--- .../src/syscall/precompiles/edwards/ed_add.rs | 87 ++++------- .../precompiles/edwards/ed_decompress.rs | 55 ++++--- .../syscall/precompiles/k256/decompress.rs | 58 +++----- core/src/syscall/precompiles/mod.rs | 11 -- .../weierstrass/weierstrass_add.rs | 112 ++++++--------- .../weierstrass/weierstrass_double.rs | 136 +++++++----------- core/src/utils/ec/field.rs | 17 ++- 11 files changed, 289 insertions(+), 446 deletions(-) diff --git a/core/src/operations/field/field_den.rs b/core/src/operations/field/field_den.rs index 5d6737b77a..08d034bf4b 100644 --- a/core/src/operations/field/field_den.rs +++ b/core/src/operations/field/field_den.rs @@ -1,4 +1,4 @@ -use super::params::{Limbs, NumLimbs}; +use super::params::Limbs; use super::util::{compute_root_quotient_and_shift, split_u16_limbs_to_u8_limbs}; use super::util_air::eval_field_operation; use crate::air::Polynomial; @@ -19,21 +19,16 @@ use std::fmt::Debug; /// or made generic in the future. #[derive(Debug, Clone, AlignedBorrow)] #[repr(C)] -pub struct FieldDenCols { +pub struct FieldDenCols { /// The result of `a den b`, where a, b are field elements - pub result: Limbs, - pub(crate) carry: Limbs, - pub(crate) witness_low: Limbs, - pub(crate) witness_high: Limbs, + pub result: Limbs, + pub(crate) carry: Limbs, + pub(crate) witness_low: Limbs, + pub(crate) witness_high: Limbs, } -impl FieldDenCols { - pub fn populate( - &mut self, - a: &BigUint, - b: &BigUint, - sign: bool, - ) -> BigUint { +impl FieldDenCols { + pub fn populate(&mut self, a: &BigUint, b: &BigUint, sign: bool) -> BigUint { let p = P::modulus(); let minus_b_int = &p - b; let b_signed = if sign { b.clone() } else { minus_b_int }; @@ -53,13 +48,11 @@ impl FieldDenCols { debug_assert!(carry < p); debug_assert_eq!(&carry * &p, &equation_lhs - &equation_rhs); - let p_a: Polynomial = limbs_from_vec::(P::to_limbs_field::(a)).into(); - let p_b: Polynomial = limbs_from_vec::(P::to_limbs_field::(b)).into(); - let p_p: Polynomial = limbs_from_vec::(P::to_limbs_field::(&p)).into(); - let p_result: Polynomial = - limbs_from_vec::(P::to_limbs_field::(&result)).into(); - let p_carry: Polynomial = - limbs_from_vec::(P::to_limbs_field::(&carry)).into(); + let p_a: Polynomial = P::to_limbs_field::(a).into(); + let p_b: Polynomial = P::to_limbs_field::(b).into(); + let p_p: Polynomial = P::to_limbs_field::(&p).into(); + let p_result: Polynomial = P::to_limbs_field::(&result).into(); + let p_carry: Polynomial = P::to_limbs_field::(&carry).into(); // Compute the vanishing polynomial. let vanishing_poly = if sign { @@ -85,16 +78,16 @@ impl FieldDenCols { } } -impl FieldDenCols +impl FieldDenCols where - Limbs: Copy, + Limbs: Copy, { #[allow(unused_variables)] - pub fn eval, P: FieldParameters>( + pub fn eval>( &self, builder: &mut AB, - a: &Limbs, - b: &Limbs, + a: &Limbs, + b: &Limbs, sign: bool, ) where V: Into, @@ -138,7 +131,6 @@ mod tests { use crate::air::MachineAir; - use crate::operations::field::params::NumLimbs32; use crate::stark::StarkGenericConfig; use crate::utils::ec::edwards::ed25519::Ed25519BaseField; use crate::utils::ec::field::{limbs_from_vec, FieldParameters}; @@ -161,7 +153,7 @@ mod tests { pub struct TestCols { pub a: Limbs, pub b: Limbs, - pub a_den_b: FieldDenCols, + pub a_den_b: FieldDenCols, } pub const NUM_TEST_COLS: usize = size_of::>(); @@ -219,7 +211,7 @@ mod tests { let cols: &mut TestCols = row.as_mut_slice().borrow_mut(); cols.a = limbs_from_vec::(P::to_limbs_field::(a)); cols.b = limbs_from_vec::(P::to_limbs_field::(b)); - cols.a_den_b.populate::

(a, b, self.sign); + cols.a_den_b.populate(a, b, self.sign); row }) .collect::>(); @@ -253,7 +245,7 @@ mod tests { let local: &TestCols = main.row_slice(0).borrow(); local .a_den_b - .eval::(builder, &local.a, &local.b, self.sign); + .eval::(builder, &local.a, &local.b, self.sign); // A dummy constraint to keep the degree 3. builder.assert_zero( diff --git a/core/src/operations/field/field_inner_product.rs b/core/src/operations/field/field_inner_product.rs index 02b6fad57b..14b33eb18e 100644 --- a/core/src/operations/field/field_inner_product.rs +++ b/core/src/operations/field/field_inner_product.rs @@ -1,9 +1,9 @@ -use super::params::{Limbs, NumLimbs}; +use super::params::Limbs; use super::util::{compute_root_quotient_and_shift, split_u16_limbs_to_u8_limbs}; use super::util_air::eval_field_operation; use crate::air::Polynomial; use crate::air::SP1AirBuilder; -use crate::utils::ec::field::{limbs_from_vec, FieldParameters}; +use crate::utils::ec::field::FieldParameters; use num::BigUint; use num::Zero; @@ -16,23 +16,23 @@ use std::fmt::Debug; /// or made generic in the future. #[derive(Debug, Clone, AlignedBorrow)] #[repr(C)] -pub struct FieldInnerProductCols { +pub struct FieldInnerProductCols { /// The result of `a inner product b`, where a, b are field elements - pub result: Limbs, - pub(crate) carry: Limbs, - pub(crate) witness_low: Limbs, - pub(crate) witness_high: Limbs, + pub result: Limbs, + pub(crate) carry: Limbs, + pub(crate) witness_low: Limbs, + pub(crate) witness_high: Limbs, } -impl FieldInnerProductCols { - pub fn populate(&mut self, a: &[BigUint], b: &[BigUint]) -> BigUint { +impl FieldInnerProductCols { + pub fn populate(&mut self, a: &[BigUint], b: &[BigUint]) -> BigUint { let p_a_vec: Vec> = a .iter() - .map(|x| limbs_from_vec::(P::to_limbs_field::(x)).into()) + .map(|x| P::to_limbs_field::(x).into()) .collect(); let p_b_vec: Vec> = b .iter() - .map(|x| limbs_from_vec::(P::to_limbs_field::(x)).into()) + .map(|x| P::to_limbs_field::(x).into()) .collect(); let modulus = &P::modulus(); @@ -47,12 +47,9 @@ impl FieldInnerProductCols { assert!(carry < &(2u32 * modulus)); assert_eq!(carry * modulus, inner_product - result); - let p_modulus: Polynomial = - limbs_from_vec::(P::to_limbs_field::(modulus)).into(); - let p_result: Polynomial = - limbs_from_vec::(P::to_limbs_field::(result)).into(); - let p_carry: Polynomial = - limbs_from_vec::(P::to_limbs_field::(carry)).into(); + let p_modulus: Polynomial = P::to_limbs_field::(modulus).into(); + let p_result: Polynomial = P::to_limbs_field::(result).into(); + let p_carry: Polynomial = P::to_limbs_field::(carry).into(); // Compute the vanishing polynomial. let p_inner_product = p_a_vec @@ -80,16 +77,16 @@ impl FieldInnerProductCols { } } -impl FieldInnerProductCols +impl FieldInnerProductCols where - Limbs: Copy, + Limbs: Copy, { #[allow(unused_variables)] - pub fn eval, P: FieldParameters>( + pub fn eval>( &self, builder: &mut AB, - a: &[Limbs], - b: &[Limbs], + a: &[Limbs], + b: &[Limbs], ) where V: Into, { @@ -125,16 +122,14 @@ mod tests { use num::BigUint; use p3_air::BaseAir; use p3_field::{Field, PrimeField32}; - use typenum::U32; use super::{FieldInnerProductCols, Limbs}; use crate::air::MachineAir; - use crate::operations::field::params::NumLimbs32; use crate::stark::StarkGenericConfig; use crate::utils::ec::edwards::ed25519::Ed25519BaseField; - use crate::utils::ec::field::{limbs_from_vec, FieldParameters}; + use crate::utils::ec::field::FieldParameters; use crate::utils::{pad_to_power_of_two, BabyBearPoseidon2}; use crate::utils::{uni_stark_prove as prove, uni_stark_verify as verify}; use crate::{air::SP1AirBuilder, runtime::ExecutionRecord}; @@ -149,15 +144,13 @@ mod tests { use sp1_derive::AlignedBorrow; #[derive(AlignedBorrow, Debug, Clone)] - pub struct TestCols { - pub a: [Limbs; 1], - pub b: [Limbs; 1], - pub a_ip_b: FieldInnerProductCols, + pub struct TestCols { + pub a: [Limbs; 1], + pub b: [Limbs; 1], + pub a_ip_b: FieldInnerProductCols, } - type Limbs32 = U32; - - pub const NUM_TEST_COLS: usize = size_of::>(); + pub const NUM_TEST_COLS: usize = size_of::>(); struct FieldIpChip { pub _phantom: std::marker::PhantomData

, @@ -203,10 +196,10 @@ mod tests { .iter() .map(|(a, b)| { let mut row = [F::zero(); NUM_TEST_COLS]; - let cols: &mut TestCols = row.as_mut_slice().borrow_mut(); - cols.a[0] = limbs_from_vec::(P::to_limbs_field::(&a[0])); - cols.b[0] = limbs_from_vec::(P::to_limbs_field::(&b[0])); - cols.a_ip_b.populate::

(a, b); + let cols: &mut TestCols = row.as_mut_slice().borrow_mut(); + cols.a[0] = P::to_limbs_field::(&a[0]); + cols.b[0] = P::to_limbs_field::(&b[0]); + cols.a_ip_b.populate(a, b); row }) .collect::>(); @@ -236,11 +229,12 @@ mod tests { impl Air for FieldIpChip

where AB: SP1AirBuilder, + Limbs: Copy, { fn eval(&self, builder: &mut AB) { let main = builder.main(); - let local: &TestCols = main.row_slice(0).borrow(); - local.a_ip_b.eval::(builder, &local.a, &local.b); + let local: &TestCols = main.row_slice(0).borrow(); + local.a_ip_b.eval::(builder, &local.a, &local.b); // A dummy constraint to keep the degree 3. builder.assert_zero( diff --git a/core/src/operations/field/field_op.rs b/core/src/operations/field/field_op.rs index 8de5a7b48b..2ce6047584 100644 --- a/core/src/operations/field/field_op.rs +++ b/core/src/operations/field/field_op.rs @@ -1,9 +1,9 @@ -use super::params::{Limbs, NumLimbs}; +use super::params::Limbs; use super::util::{compute_root_quotient_and_shift, split_u16_limbs_to_u8_limbs}; use super::util_air::eval_field_operation; use crate::air::Polynomial; use crate::air::SP1AirBuilder; -use crate::utils::ec::field::{limbs_from_vec, FieldParameters}; +use crate::utils::ec::field::FieldParameters; use num::{BigUint, Zero}; use p3_air::AirBuilder; @@ -24,21 +24,16 @@ pub enum FieldOperation { /// or made generic in the future. #[derive(Debug, Clone, AlignedBorrow)] #[repr(C)] -pub struct FieldOpCols { +pub struct FieldOpCols { /// The result of `a op b`, where a, b are field elements - pub result: Limbs, - pub(crate) carry: Limbs, - pub(crate) witness_low: Limbs, - pub(crate) witness_high: Limbs, + pub result: Limbs, + pub(crate) carry: Limbs, + pub(crate) witness_low: Limbs, + pub(crate) witness_high: Limbs, } -impl FieldOpCols { - pub fn populate( - &mut self, - a: &BigUint, - b: &BigUint, - op: FieldOperation, - ) -> BigUint { +impl FieldOpCols { + pub fn populate(&mut self, a: &BigUint, b: &BigUint, op: FieldOperation) -> BigUint { if b == &BigUint::zero() && op == FieldOperation::Div { // Division by 0 is allowed only when dividing 0 so that padded rows can be all 0. assert_eq!( @@ -58,8 +53,8 @@ impl FieldOpCols { // to contain the result by the user. // Note that this reversal means we have to flip result, a correspondingly in // the `eval` function. - self.populate::

(&result, b, FieldOperation::Add); - self.result = limbs_from_vec::(P::to_limbs_field::(&result)); + self.populate(&result, b, FieldOperation::Add); + self.result = P::to_limbs_field::(&result); return result; } @@ -75,13 +70,13 @@ impl FieldOpCols { // multiplication because those columns are expected to contain the result by the user. // Note that this reversal means we have to flip result, a correspondingly in the `eval` // function. - self.populate::

(&result, b, FieldOperation::Mul); - self.result = limbs_from_vec::(P::to_limbs_field::(&result)); + self.populate(&result, b, FieldOperation::Mul); + self.result = P::to_limbs_field::(&result); return result; } - let p_a: Polynomial = limbs_from_vec::(P::to_limbs_field::(a)).into(); - let p_b: Polynomial = limbs_from_vec::(P::to_limbs_field::(b)).into(); + let p_a: Polynomial = P::to_limbs_field::(a).into(); + let p_b: Polynomial = P::to_limbs_field::(b).into(); // Compute field addition in the integers. let modulus = &P::modulus(); @@ -99,12 +94,9 @@ impl FieldOpCols { } // Make little endian polynomial limbs. - let p_modulus: Polynomial = - limbs_from_vec::(P::to_limbs_field::(modulus)).into(); - let p_result: Polynomial = - limbs_from_vec::(P::to_limbs_field::(&result)).into(); - let p_carry: Polynomial = - limbs_from_vec::(P::to_limbs_field::(&carry)).into(); + let p_modulus: Polynomial = P::to_limbs_field::(modulus).into(); + let p_result: Polynomial = P::to_limbs_field::(&result).into(); + let p_carry: Polynomial = P::to_limbs_field::(&carry).into(); // Compute the vanishing polynomial. let p_op = match op { @@ -124,9 +116,7 @@ impl FieldOpCols { self.result = p_result.into(); self.carry = p_carry.into(); - use typenum::Unsigned; - println!("low len: {}", p_witness_low.len()); - println!("limbs : {}", N::Witness::USIZE); + self.witness_low = Limbs(p_witness_low.try_into().unwrap()); self.witness_high = Limbs(p_witness_high.try_into().unwrap()); @@ -134,11 +124,10 @@ impl FieldOpCols { } } -impl FieldOpCols { +impl FieldOpCols { #[allow(unused_variables)] pub fn eval< AB: SP1AirBuilder, - P: FieldParameters, A: Into> + Clone, B: Into> + Clone, >( @@ -149,7 +138,7 @@ impl FieldOpCols { op: FieldOperation, ) where V: Into, - Limbs: Copy, + Limbs: Copy, { let p_a_param: Polynomial = (*a).clone().into(); let p_b: Polynomial = (*b).clone().into(); @@ -177,16 +166,15 @@ mod tests { use num::BigUint; use p3_air::BaseAir; use p3_field::{Field, PrimeField32}; - use typenum::U32; use super::{FieldOpCols, FieldOperation, Limbs}; use crate::air::MachineAir; - use crate::operations::field::params::NumLimbs32; use crate::stark::StarkGenericConfig; use crate::utils::ec::edwards::ed25519::Ed25519BaseField; - use crate::utils::ec::field::{limbs_from_vec, FieldParameters}; + use crate::utils::ec::field::FieldParameters; + use crate::utils::ec::weierstrass::secp256k1::Secp256k1BaseField; use crate::utils::{ pad_to_power_of_two, uni_stark_prove as prove, uni_stark_verify as verify, BabyBearPoseidon2, @@ -203,15 +191,13 @@ mod tests { use std::mem::size_of; #[derive(AlignedBorrow, Debug, Clone)] - pub struct TestCols { - pub a: Limbs, - pub b: Limbs, - pub a_op_b: FieldOpCols, + pub struct TestCols { + pub a: Limbs, + pub b: Limbs, + pub a_op_b: FieldOpCols, } - type Limbs32 = U32; - - pub const NUM_TEST_COLS: usize = size_of::>(); + pub const NUM_TEST_COLS: usize = size_of::>(); struct FieldOpChip { pub operation: FieldOperation, @@ -263,10 +249,10 @@ mod tests { .iter() .map(|(a, b)| { let mut row = [F::zero(); NUM_TEST_COLS]; - let cols: &mut TestCols = row.as_mut_slice().borrow_mut(); - cols.a = limbs_from_vec::(P::to_limbs_field::(a)); - cols.b = limbs_from_vec::(P::to_limbs_field::(b)); - cols.a_op_b.populate::

(a, b, self.operation); + let cols: &mut TestCols = row.as_mut_slice().borrow_mut(); + cols.a = P::to_limbs_field::(a); + cols.b = P::to_limbs_field::(b); + cols.a_op_b.populate(a, b, self.operation); row }) .collect::>(); @@ -296,13 +282,14 @@ mod tests { impl Air for FieldOpChip

where AB: SP1AirBuilder, + Limbs: Copy, { fn eval(&self, builder: &mut AB) { let main = builder.main(); - let local: &TestCols = main.row_slice(0).borrow(); + let local: &TestCols = main.row_slice(0).borrow(); local .a_op_b - .eval::(builder, &local.a, &local.b, self.operation); + .eval::(builder, &local.a, &local.b, self.operation); // A dummy constraint to keep the degree 3. builder.assert_zero( @@ -345,6 +332,7 @@ mod tests { let mut challenger = config.challenger(); + // TODO: test with other fields let chip: FieldOpChip = FieldOpChip::new(*op); let shard = ExecutionRecord::default(); let trace: RowMajorMatrix = diff --git a/core/src/operations/field/field_sqrt.rs b/core/src/operations/field/field_sqrt.rs index 3b3692ec28..502e882fc8 100644 --- a/core/src/operations/field/field_sqrt.rs +++ b/core/src/operations/field/field_sqrt.rs @@ -1,7 +1,7 @@ use super::field_op::FieldOpCols; -use super::params::{Limbs, NumLimbs}; +use super::params::Limbs; use crate::air::SP1AirBuilder; -use crate::utils::ec::field::{limbs_from_vec, FieldParameters}; +use crate::utils::ec::field::FieldParameters; use num::BigUint; use p3_field::PrimeField32; use sp1_derive::AlignedBorrow; @@ -11,51 +11,44 @@ use std::fmt::Debug; /// limb lives. #[derive(Debug, Clone, AlignedBorrow)] #[repr(C)] -pub struct FieldSqrtCols { +pub struct FieldSqrtCols { /// The multiplication operation to verify that the sqrt and the input match. /// /// In order to save space, we actually store the sqrt of the input in `multiplication.result` /// since we'll receive the input again in the `eval` function. - pub multiplication: FieldOpCols, + pub multiplication: FieldOpCols, } -impl FieldSqrtCols { +impl FieldSqrtCols { /// Populates the trace. /// /// `P` is the parameter of the field that each limb lives in. - pub fn populate( - &mut self, - a: &BigUint, - sqrt_fn: impl Fn(&BigUint) -> BigUint, - ) -> BigUint { + pub fn populate(&mut self, a: &BigUint, sqrt_fn: impl Fn(&BigUint) -> BigUint) -> BigUint { let sqrt = sqrt_fn(a); // Use FieldOpCols to compute result * result. let sqrt_squared = self.multiplication - .populate::

(&sqrt, &sqrt, super::field_op::FieldOperation::Mul); + .populate(&sqrt, &sqrt, super::field_op::FieldOperation::Mul); // If the result is indeed the square root of a, then result * result = a. assert_eq!(sqrt_squared, a.clone()); // This is a hack to save a column in FieldSqrtCols. We will receive the value a again in the // eval function, so we'll overwrite it with the sqrt. - self.multiplication.result = limbs_from_vec::(P::to_limbs_field::(&sqrt)); + self.multiplication.result = P::to_limbs_field::(&sqrt); sqrt } } -impl FieldSqrtCols +impl FieldSqrtCols where - Limbs: Copy, + Limbs: Copy, { /// Calculates the square root of `a`. - pub fn eval, P: FieldParameters>( - &self, - builder: &mut AB, - a: &Limbs, - ) where + pub fn eval>(&self, builder: &mut AB, a: &Limbs) + where V: Into, { // As a space-saving hack, we store the sqrt of the input in `self.multiplication.result` @@ -66,7 +59,7 @@ where multiplication.result = *a; // Compute sqrt * sqrt. We pass in P since we want its BaseField to be the mod. - multiplication.eval::, Limbs>( + multiplication.eval::, Limbs>( builder, &sqrt, &sqrt, @@ -86,10 +79,9 @@ mod tests { use crate::air::MachineAir; - use crate::operations::field::params::NumLimbs32; use crate::stark::StarkGenericConfig; use crate::utils::ec::edwards::ed25519::{ed25519_sqrt, Ed25519BaseField}; - use crate::utils::ec::field::{limbs_from_vec, FieldParameters}; + use crate::utils::ec::field::FieldParameters; use crate::utils::{pad_to_power_of_two, BabyBearPoseidon2}; use crate::utils::{uni_stark_prove as prove, uni_stark_verify as verify}; use crate::{air::SP1AirBuilder, runtime::ExecutionRecord}; @@ -106,12 +98,12 @@ mod tests { type Limbs32 = U32; #[derive(AlignedBorrow, Debug, Clone)] - pub struct TestCols { - pub a: Limbs, - pub sqrt: FieldSqrtCols, + pub struct TestCols { + pub a: Limbs, + pub sqrt: FieldSqrtCols, } - pub const NUM_TEST_COLS: usize = size_of::>(); + pub const NUM_TEST_COLS: usize = size_of::>(); struct EdSqrtChip { pub _phantom: std::marker::PhantomData

, @@ -156,9 +148,9 @@ mod tests { .iter() .map(|a| { let mut row = [F::zero(); NUM_TEST_COLS]; - let cols: &mut TestCols = row.as_mut_slice().borrow_mut(); - cols.a = limbs_from_vec::(P::to_limbs_field::(a)); - cols.sqrt.populate::

(a, ed25519_sqrt); + let cols: &mut TestCols = row.as_mut_slice().borrow_mut(); + cols.a = P::to_limbs_field::(a); + cols.sqrt.populate(a, ed25519_sqrt); row }) .collect::>(); @@ -188,13 +180,14 @@ mod tests { impl Air for EdSqrtChip

where AB: SP1AirBuilder, + Limbs: Copy, { fn eval(&self, builder: &mut AB) { let main = builder.main(); - let local: &TestCols = main.row_slice(0).borrow(); + let local: &TestCols = main.row_slice(0).borrow(); // eval verifies that local.sqrt.result is indeed the square root of local.a. - local.sqrt.eval::(builder, &local.a); + local.sqrt.eval::(builder, &local.a); // A dummy constraint to keep the degree 3. builder.assert_zero( diff --git a/core/src/syscall/precompiles/edwards/ed_add.rs b/core/src/syscall/precompiles/edwards/ed_add.rs index 6249bbce3e..ce9e882279 100644 --- a/core/src/syscall/precompiles/edwards/ed_add.rs +++ b/core/src/syscall/precompiles/edwards/ed_add.rs @@ -8,24 +8,20 @@ use crate::operations::field::field_den::FieldDenCols; use crate::operations::field::field_inner_product::FieldInnerProductCols; use crate::operations::field::field_op::FieldOpCols; use crate::operations::field::field_op::FieldOperation; -use crate::operations::field::params::Limbs; -use crate::operations::field::params::NumLimbs32; use crate::runtime::ExecutionRecord; use crate::runtime::Syscall; use crate::runtime::SyscallCode; use crate::syscall::precompiles::create_ec_add_event; use crate::syscall::precompiles::SyscallContext; use crate::utils::ec::edwards::EdwardsParameters; -use crate::utils::ec::field::limbs_from_vec; use crate::utils::ec::field::FieldParameters; +use crate::utils::ec::weierstrass::secp256k1::Secp256k1BaseField; use crate::utils::ec::AffinePoint; use crate::utils::ec::EllipticCurve; -use crate::utils::ec::EllipticCurveParameters; use crate::utils::limbs_from_prev_access; use crate::utils::pad_rows; use core::borrow::{Borrow, BorrowMut}; use core::mem::size_of; -use generic_array::functional::FunctionalSequence; use num::BigUint; use num::Zero; use p3_air::AirBuilder; @@ -57,14 +53,14 @@ pub struct EdAddAssignCols { pub q_ptr: T, pub p_access: [MemoryWriteCols; 16], pub q_access: [MemoryReadCols; 16], - pub(crate) x3_numerator: FieldInnerProductCols, - pub(crate) y3_numerator: FieldInnerProductCols, - pub(crate) x1_mul_y1: FieldOpCols, - pub(crate) x2_mul_y2: FieldOpCols, - pub(crate) f: FieldOpCols, - pub(crate) d_mul_f: FieldOpCols, - pub(crate) x3_ins: FieldDenCols, - pub(crate) y3_ins: FieldDenCols, + pub(crate) x3_numerator: FieldInnerProductCols, + pub(crate) y3_numerator: FieldInnerProductCols, + pub(crate) x1_mul_y1: FieldOpCols, + pub(crate) x2_mul_y2: FieldOpCols, + pub(crate) f: FieldOpCols, + pub(crate) d_mul_f: FieldOpCols, + pub(crate) x3_ins: FieldDenCols, + pub(crate) y3_ins: FieldDenCols, } #[derive(Default)] @@ -87,29 +83,19 @@ impl EdAddAssignChip { ) { let x3_numerator = cols .x3_numerator - .populate::(&[p_x.clone(), q_x.clone()], &[q_y.clone(), p_y.clone()]); + .populate(&[p_x.clone(), q_x.clone()], &[q_y.clone(), p_y.clone()]); let y3_numerator = cols .y3_numerator - .populate::(&[p_y.clone(), p_x.clone()], &[q_y.clone(), q_x.clone()]); - let x1_mul_y1 = cols - .x1_mul_y1 - .populate::(&p_x, &p_y, FieldOperation::Mul); - let x2_mul_y2 = cols - .x2_mul_y2 - .populate::(&q_x, &q_y, FieldOperation::Mul); - let f = cols - .f - .populate::(&x1_mul_y1, &x2_mul_y2, FieldOperation::Mul); + .populate(&[p_y.clone(), p_x.clone()], &[q_y.clone(), q_x.clone()]); + let x1_mul_y1 = cols.x1_mul_y1.populate(&p_x, &p_y, FieldOperation::Mul); + let x2_mul_y2 = cols.x2_mul_y2.populate(&q_x, &q_y, FieldOperation::Mul); + let f = cols.f.populate(&x1_mul_y1, &x2_mul_y2, FieldOperation::Mul); let d = E::d_biguint(); - let d_mul_f = cols - .d_mul_f - .populate::(&f, &d, FieldOperation::Mul); - - cols.x3_ins - .populate::(&x3_numerator, &d_mul_f, true); - cols.y3_ins - .populate::(&y3_numerator, &d_mul_f, false); + let d_mul_f = cols.d_mul_f.populate(&f, &d, FieldOperation::Mul); + + cols.x3_ins.populate(&x3_numerator, &d_mul_f, true); + cols.y3_ins.populate(&y3_numerator, &d_mul_f, false); } } @@ -224,57 +210,38 @@ where let y2 = limbs_from_prev_access(&row.q_access[8..16]); // x3_numerator = x1 * y2 + x2 * y1. - row.x3_numerator - .eval::(builder, &[x1, x2], &[y2, y1]); + row.x3_numerator.eval::(builder, &[x1, x2], &[y2, y1]); // y3_numerator = y1 * y2 + x1 * x2. - row.y3_numerator - .eval::(builder, &[y1, x1], &[y2, x2]); + row.y3_numerator.eval::(builder, &[y1, x1], &[y2, x2]); // f = x1 * x2 * y1 * y2. row.x1_mul_y1 - .eval::(builder, &x1, &y1, FieldOperation::Mul); + .eval::(builder, &x1, &y1, FieldOperation::Mul); row.x2_mul_y2 - .eval::(builder, &x2, &y2, FieldOperation::Mul); + .eval::(builder, &x2, &y2, FieldOperation::Mul); let x1_mul_y1 = row.x1_mul_y1.result; let x2_mul_y2 = row.x2_mul_y2.result; row.f - .eval::(builder, &x1_mul_y1, &x2_mul_y2, FieldOperation::Mul); + .eval::(builder, &x1_mul_y1, &x2_mul_y2, FieldOperation::Mul); // d * f. let f = row.f.result; let d_biguint = E::d_biguint(); - let d_const = E::BaseField::to_limbs_field::(&d_biguint); - let d_const_expr = - Limbs::(limbs_from_vec::(d_const).0.map(|x| x.into())); + let d_const = E::BaseField::to_limbs_field::(&d_biguint); row.d_mul_f - .eval::::BaseField, _, _>( - builder, - &f, - &d_const_expr, - FieldOperation::Mul, - ); + .eval::(builder, &f, &d_const, FieldOperation::Mul); let d_mul_f = row.d_mul_f.result; // x3 = x3_numerator / (1 + d * f). row.x3_ins - .eval::::BaseField>( - builder, - &row.x3_numerator.result, - &d_mul_f, - true, - ); + .eval::(builder, &row.x3_numerator.result, &d_mul_f, true); // y3 = y3_numerator / (1 - d * f). row.y3_ins - .eval::::BaseField>( - builder, - &row.y3_numerator.result, - &d_mul_f, - false, - ); + .eval::(builder, &row.y3_numerator.result, &d_mul_f, false); // Constraint self.p_access.value = [self.x3_ins.result, self.y3_ins.result] // This is to ensure that p_access is updated with the new value. diff --git a/core/src/syscall/precompiles/edwards/ed_decompress.rs b/core/src/syscall/precompiles/edwards/ed_decompress.rs index afafc4b38c..1eac233114 100644 --- a/core/src/syscall/precompiles/edwards/ed_decompress.rs +++ b/core/src/syscall/precompiles/edwards/ed_decompress.rs @@ -7,7 +7,6 @@ use crate::operations::field::field_op::FieldOpCols; use crate::operations::field::field_op::FieldOperation; use crate::operations::field::field_sqrt::FieldSqrtCols; use crate::operations::field::params::Limbs; -use crate::operations::field::params::NumLimbs32; use crate::runtime::ExecutionRecord; use crate::runtime::MemoryReadRecord; use crate::runtime::MemoryWriteRecord; @@ -17,6 +16,7 @@ use crate::syscall::precompiles::SyscallContext; use crate::utils::bytes_to_words_le; use crate::utils::ec::edwards::ed25519::decompress; use crate::utils::ec::edwards::ed25519::ed25519_sqrt; +use crate::utils::ec::edwards::ed25519::Ed25519BaseField; use crate::utils::ec::edwards::EdwardsParameters; use crate::utils::ec::field::limbs_from_vec; use crate::utils::ec::field::FieldParameters; @@ -75,13 +75,13 @@ pub struct EdDecompressCols { pub sign: T, pub x_access: [MemoryWriteCols; NUM_WORDS_FIELD_ELEMENT], pub y_access: [MemoryReadCols; NUM_WORDS_FIELD_ELEMENT], - pub(crate) yy: FieldOpCols, - pub(crate) u: FieldOpCols, - pub(crate) dyy: FieldOpCols, - pub(crate) v: FieldOpCols, - pub(crate) u_div_v: FieldOpCols, - pub(crate) x: FieldSqrtCols, - pub(crate) neg_x: FieldOpCols, + pub(crate) yy: FieldOpCols, + pub(crate) u: FieldOpCols, + pub(crate) dyy: FieldOpCols, + pub(crate) v: FieldOpCols, + pub(crate) u_div_v: FieldOpCols, + pub(crate) x: FieldSqrtCols, + pub(crate) neg_x: FieldOpCols, } impl EdDecompressCols { @@ -109,16 +109,14 @@ impl EdDecompressCols { fn populate_field_ops(&mut self, y: &BigUint) { let one = BigUint::one(); - let yy = self.yy.populate::

(y, y, FieldOperation::Mul); - let u = self.u.populate::

(&yy, &one, FieldOperation::Sub); - let dyy = self - .dyy - .populate::

(&E::d_biguint(), &yy, FieldOperation::Mul); - let v = self.v.populate::

(&one, &dyy, FieldOperation::Add); - let u_div_v = self.u_div_v.populate::

(&u, &v, FieldOperation::Div); - let x = self.x.populate::

(&u_div_v, ed25519_sqrt); + let yy = self.yy.populate(y, y, FieldOperation::Mul); + let u = self.u.populate(&yy, &one, FieldOperation::Sub); + let dyy = self.dyy.populate(&E::d_biguint(), &yy, FieldOperation::Mul); + let v = self.v.populate(&one, &dyy, FieldOperation::Add); + let u_div_v = self.u_div_v.populate(&u, &v, FieldOperation::Div); + let x = self.x.populate(&u_div_v, ed25519_sqrt); self.neg_x - .populate::

(&BigUint::zero(), &x, FieldOperation::Sub); + .populate(&BigUint::zero(), &x, FieldOperation::Sub); } } @@ -133,32 +131,27 @@ impl EdDecompressCols { let y: Limbs = limbs_from_prev_access(&self.y_access); self.yy - .eval::(builder, &y, &y, FieldOperation::Mul); - self.u.eval::( + .eval::(builder, &y, &y, FieldOperation::Mul); + self.u.eval::( builder, &self.yy.result, &[AB::Expr::one()].iter(), FieldOperation::Sub, ); let d_biguint = E::d_biguint(); - let d_const = E::BaseField::to_limbs_field::(&d_biguint); - let d_const = limbs_from_vec::(d_const); + let d_const = E::BaseField::to_limbs_field::(&d_biguint); self.dyy - .eval::(builder, &d_const, &self.yy.result, FieldOperation::Mul); - self.v.eval::( + .eval::(builder, &d_const, &self.yy.result, FieldOperation::Mul); + self.v.eval::( builder, &[AB::Expr::one()].iter(), &self.dyy.result, FieldOperation::Add, ); - self.u_div_v.eval::( - builder, - &self.u.result, - &self.v.result, - FieldOperation::Div, - ); - self.x.eval::(builder, &self.u_div_v.result); - self.neg_x.eval::( + self.u_div_v + .eval::(builder, &self.u.result, &self.v.result, FieldOperation::Div); + self.x.eval::(builder, &self.u_div_v.result); + self.neg_x.eval::( builder, &[AB::Expr::zero()].iter(), &self.x.multiplication.result, diff --git a/core/src/syscall/precompiles/k256/decompress.rs b/core/src/syscall/precompiles/k256/decompress.rs index e84e919a71..93e8cde7b5 100644 --- a/core/src/syscall/precompiles/k256/decompress.rs +++ b/core/src/syscall/precompiles/k256/decompress.rs @@ -8,7 +8,6 @@ use crate::operations::field::field_op::FieldOpCols; use crate::operations::field::field_op::FieldOperation; use crate::operations::field::field_sqrt::FieldSqrtCols; use crate::operations::field::params::Limbs; -use crate::operations::field::params::NumLimbs32; use crate::runtime::ExecutionRecord; use crate::runtime::MemoryReadRecord; use crate::runtime::MemoryWriteRecord; @@ -140,11 +139,11 @@ pub struct K256DecompressCols { pub is_odd: T, pub x_access: [MemoryReadCols; NUM_WORDS_FIELD_ELEMENT], pub y_access: [MemoryReadWriteCols; NUM_WORDS_FIELD_ELEMENT], - pub(crate) x_2: FieldOpCols, - pub(crate) x_3: FieldOpCols, - pub(crate) x_3_plus_b: FieldOpCols, - pub(crate) y: FieldSqrtCols, - pub(crate) neg_y: FieldOpCols, + pub(crate) x_2: FieldOpCols, + pub(crate) x_3: FieldOpCols, + pub(crate) x_3_plus_b: FieldOpCols, + pub(crate) y: FieldSqrtCols, + pub(crate) neg_y: FieldOpCols, pub(crate) y_least_bits: [T; 8], } @@ -169,22 +168,15 @@ impl K256DecompressCols { fn populate_field_ops(&mut self, x: &BigUint) { // Y = sqrt(x^3 + b) - let x_2 = - self.x_2 - .populate::(&x.clone(), &x.clone(), FieldOperation::Mul); - let x_3 = self - .x_3 - .populate::(&x_2, x, FieldOperation::Mul); + let x_2 = self + .x_2 + .populate(&x.clone(), &x.clone(), FieldOperation::Mul); + let x_3 = self.x_3.populate(&x_2, x, FieldOperation::Mul); let b = Secp256k1Parameters::b_int(); - let x_3_plus_b = - self.x_3_plus_b - .populate::(&x_3, &b, FieldOperation::Add); - let y = self - .y - .populate::(&x_3_plus_b, secp256k1_sqrt); + let x_3_plus_b = self.x_3_plus_b.populate(&x_3, &b, FieldOperation::Add); + let y = self.y.populate(&x_3_plus_b, secp256k1_sqrt); let zero = BigUint::zero(); - self.neg_y - .populate::(&zero, &y, FieldOperation::Sub); + self.neg_y.populate(&zero, &y, FieldOperation::Sub); // Decompose bits of least significant Y byte let y_bytes = y.to_bytes_le(); let y_lsb = if y_bytes.is_empty() { 0 } else { y_bytes[0] }; @@ -203,25 +195,15 @@ impl K256DecompressCols { let x: Limbs = limbs_from_prev_access(&self.x_access); self.x_2 - .eval::(builder, &x, &x, FieldOperation::Mul); - self.x_3.eval::( - builder, - &self.x_2.result, - &x, - FieldOperation::Mul, - ); + .eval::(builder, &x, &x, FieldOperation::Mul); + self.x_3 + .eval::(builder, &self.x_2.result, &x, FieldOperation::Mul); let b = Secp256k1Parameters::b_int(); - let b_const = Secp256k1BaseField::to_limbs_field::(&b); - let b_const = limbs_from_vec::(b_const); - self.x_3_plus_b.eval::( - builder, - &self.x_3.result, - &b_const, - FieldOperation::Add, - ); - self.y - .eval::(builder, &self.x_3_plus_b.result); - self.neg_y.eval::( + let b_const = Secp256k1BaseField::to_limbs_field::(&b); + self.x_3_plus_b + .eval::(builder, &self.x_3.result, &b_const, FieldOperation::Add); + self.y.eval::(builder, &self.x_3_plus_b.result); + self.neg_y.eval::( builder, &[AB::Expr::zero()].iter(), &self.y.multiplication.result, diff --git a/core/src/syscall/precompiles/mod.rs b/core/src/syscall/precompiles/mod.rs index 25273976b6..99046f74e4 100644 --- a/core/src/syscall/precompiles/mod.rs +++ b/core/src/syscall/precompiles/mod.rs @@ -106,14 +106,3 @@ pub fn create_ec_double_event( p_memory_records, } } - -pub fn limbs_from_biguint(value: &BigUint) -> Limbs -where - AB: SP1AirBuilder, -{ - let a_const = F::to_limbs_field::(value); - debug_assert_eq!(a_const.len(), 32); - let mut a = [AB::F::zero(); 32]; - a[..32].copy_from_slice(&a_const[..32]); - Limbs(a.map(|x| x.into()).into()) -} diff --git a/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs b/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs index df9993b9c3..1fef483454 100644 --- a/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs +++ b/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs @@ -34,8 +34,8 @@ use sp1_derive::AlignedBorrow; use std::fmt::Debug; use std::marker::PhantomData; -pub const fn num_weierstrass_add_cols() -> usize { - size_of::>() +pub const fn num_weierstrass_add_cols() -> usize { + size_of::>() } /// A set of columns to compute `WeierstrassAdd` that add two points on a Weierstrass curve. @@ -44,7 +44,7 @@ pub const fn num_weierstrass_add_cols() -> usize { /// made generic in the future. #[derive(Debug, Clone, AlignedBorrow)] #[repr(C)] -pub struct WeierstrassAddAssignCols { +pub struct WeierstrassAddAssignCols { pub is_real: T, pub shard: T, pub clk: T, @@ -52,15 +52,15 @@ pub struct WeierstrassAddAssignCols { pub q_ptr: T, pub p_access: [MemoryWriteCols; NUM_WORDS_EC_POINT], pub q_access: [MemoryReadCols; NUM_WORDS_EC_POINT], - pub(crate) slope_denominator: FieldOpCols, - pub(crate) slope_numerator: FieldOpCols, - pub(crate) slope: FieldOpCols, - pub(crate) slope_squared: FieldOpCols, - pub(crate) p_x_plus_q_x: FieldOpCols, - pub(crate) x3_ins: FieldOpCols, - pub(crate) p_x_minus_x: FieldOpCols, - pub(crate) y3_ins: FieldOpCols, - pub(crate) slope_times_p_x_minus_x: FieldOpCols, + pub(crate) slope_denominator: FieldOpCols, + pub(crate) slope_numerator: FieldOpCols, + pub(crate) slope: FieldOpCols, + pub(crate) slope_squared: FieldOpCols, + pub(crate) p_x_plus_q_x: FieldOpCols, + pub(crate) x3_ins: FieldOpCols, + pub(crate) p_x_minus_x: FieldOpCols, + pub(crate) y3_ins: FieldOpCols, + pub(crate) slope_times_p_x_minus_x: FieldOpCols, } #[derive(Default)] @@ -99,48 +99,36 @@ impl WeierstrassAddAssignChip { // slope = (q.y - p.y) / (q.x - p.x). let slope = { - let slope_numerator = - cols.slope_numerator - .populate::(&q_y, &p_y, FieldOperation::Sub); + let slope_numerator = cols + .slope_numerator + .populate(&q_y, &p_y, FieldOperation::Sub); let slope_denominator = cols.slope_denominator - .populate::(&q_x, &p_x, FieldOperation::Sub); + .populate(&q_x, &p_x, FieldOperation::Sub); - cols.slope.populate::( - &slope_numerator, - &slope_denominator, - FieldOperation::Div, - ) + cols.slope + .populate(&slope_numerator, &slope_denominator, FieldOperation::Div) }; // x = slope * slope - (p.x + q.x). let x = { - let slope_squared = - cols.slope_squared - .populate::(&slope, &slope, FieldOperation::Mul); - let p_x_plus_q_x = - cols.p_x_plus_q_x - .populate::(&p_x, &q_x, FieldOperation::Add); + let slope_squared = cols + .slope_squared + .populate(&slope, &slope, FieldOperation::Mul); + let p_x_plus_q_x = cols.p_x_plus_q_x.populate(&p_x, &q_x, FieldOperation::Add); cols.x3_ins - .populate::(&slope_squared, &p_x_plus_q_x, FieldOperation::Sub) + .populate(&slope_squared, &p_x_plus_q_x, FieldOperation::Sub) }; // y = slope * (p.x - x_3n) - p.y. { - let p_x_minus_x = - cols.p_x_minus_x - .populate::(&p_x, &x, FieldOperation::Sub); - let slope_times_p_x_minus_x = cols.slope_times_p_x_minus_x.populate::( - &slope, - &p_x_minus_x, - FieldOperation::Mul, - ); - cols.y3_ins.populate::( - &slope_times_p_x_minus_x, - &p_y, - FieldOperation::Sub, - ); + let p_x_minus_x = cols.p_x_minus_x.populate(&p_x, &x, FieldOperation::Sub); + let slope_times_p_x_minus_x = + cols.slope_times_p_x_minus_x + .populate(&slope, &p_x_minus_x, FieldOperation::Mul); + cols.y3_ins + .populate(&slope_times_p_x_minus_x, &p_y, FieldOperation::Sub); } } } @@ -248,21 +236,13 @@ where // slope = (q.y - p.y) / (q.x - p.x). let slope = { - row.slope_numerator.eval::( - builder, - &q_y, - &p_y, - FieldOperation::Sub, - ); + row.slope_numerator + .eval::(builder, &q_y, &p_y, FieldOperation::Sub); - row.slope_denominator.eval::( - builder, - &q_x, - &p_x, - FieldOperation::Sub, - ); + row.slope_denominator + .eval::(builder, &q_x, &p_x, FieldOperation::Sub); - row.slope.eval::( + row.slope.eval::( builder, &row.slope_numerator.result, &row.slope_denominator.result, @@ -274,21 +254,13 @@ where // x = slope * slope - self.x - other.x. let x = { - row.slope_squared.eval::( - builder, - slope, - slope, - FieldOperation::Mul, - ); + row.slope_squared + .eval::(builder, slope, slope, FieldOperation::Mul); - row.p_x_plus_q_x.eval::( - builder, - &p_x, - &q_x, - FieldOperation::Add, - ); + row.p_x_plus_q_x + .eval::(builder, &p_x, &q_x, FieldOperation::Add); - row.x3_ins.eval::( + row.x3_ins.eval::( builder, &row.slope_squared.result, &row.p_x_plus_q_x.result, @@ -301,16 +273,16 @@ where // y = slope * (p.x - x_3n) - q.y. { row.p_x_minus_x - .eval::(builder, &p_x, x, FieldOperation::Sub); + .eval::(builder, &p_x, x, FieldOperation::Sub); - row.slope_times_p_x_minus_x.eval::( + row.slope_times_p_x_minus_x.eval::( builder, slope, &row.p_x_minus_x.result, FieldOperation::Mul, ); - row.y3_ins.eval::( + row.y3_ins.eval::( builder, &row.slope_times_p_x_minus_x.result, &p_y, diff --git a/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs b/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs index 196dbfd682..61fd387b4c 100644 --- a/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs +++ b/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs @@ -11,7 +11,6 @@ use crate::runtime::Syscall; use crate::runtime::SyscallCode; use crate::stark::MachineRecord; use crate::syscall::precompiles::create_ec_double_event; -use crate::syscall::precompiles::limbs_from_biguint; use crate::syscall::precompiles::SyscallContext; use crate::utils::ec::field::FieldParameters; use crate::utils::ec::weierstrass::WeierstrassParameters; @@ -37,10 +36,9 @@ use sp1_derive::AlignedBorrow; use std::fmt::Debug; use std::marker::PhantomData; use tracing::instrument; -use typenum::U32; -pub const fn num_weierstrass_double_cols() -> usize { - size_of::>() +pub const fn num_weierstrass_double_cols() -> usize { + size_of::>() } /// A set of columns to double a point on a Weierstrass curve. @@ -49,23 +47,23 @@ pub const fn num_weierstrass_double_cols() -> usize { /// made generic in the future. #[derive(Debug, Clone, AlignedBorrow)] #[repr(C)] -pub struct WeierstrassDoubleAssignCols { +pub struct WeierstrassDoubleAssignCols { pub is_real: T, pub shard: T, pub clk: T, pub p_ptr: T, pub p_access: [MemoryWriteCols; NUM_WORDS_EC_POINT], - pub(crate) slope_denominator: FieldOpCols, - pub(crate) slope_numerator: FieldOpCols, - pub(crate) slope: FieldOpCols, - pub(crate) p_x_squared: FieldOpCols, - pub(crate) p_x_squared_times_3: FieldOpCols, - pub(crate) slope_squared: FieldOpCols, - pub(crate) p_x_plus_p_x: FieldOpCols, - pub(crate) x3_ins: FieldOpCols, - pub(crate) p_x_minus_x: FieldOpCols, - pub(crate) y3_ins: FieldOpCols, - pub(crate) slope_times_p_x_minus_x: FieldOpCols, + pub(crate) slope_denominator: FieldOpCols, + pub(crate) slope_numerator: FieldOpCols, + pub(crate) slope: FieldOpCols, + pub(crate) p_x_squared: FieldOpCols, + pub(crate) p_x_squared_times_3: FieldOpCols, + pub(crate) slope_squared: FieldOpCols, + pub(crate) p_x_plus_p_x: FieldOpCols, + pub(crate) x3_ins: FieldOpCols, + pub(crate) p_x_minus_x: FieldOpCols, + pub(crate) y3_ins: FieldOpCols, + pub(crate) slope_times_p_x_minus_x: FieldOpCols, } #[derive(Default)] @@ -105,62 +103,43 @@ impl WeierstrassDoubleAssignChip { let slope = { // slope_numerator = a + (p.x * p.x) * 3. let slope_numerator = { - let p_x_squared = - cols.p_x_squared - .populate::(&p_x, &p_x, FieldOperation::Mul); - let p_x_squared_times_3 = cols.p_x_squared_times_3.populate::( + let p_x_squared = cols.p_x_squared.populate(&p_x, &p_x, FieldOperation::Mul); + let p_x_squared_times_3 = cols.p_x_squared_times_3.populate( &p_x_squared, &BigUint::from(3u32), FieldOperation::Mul, ); - cols.slope_numerator.populate::( - &a, - &p_x_squared_times_3, - FieldOperation::Add, - ) + cols.slope_numerator + .populate(&a, &p_x_squared_times_3, FieldOperation::Add) }; // slope_denominator = 2 * y. - let slope_denominator = cols.slope_denominator.populate::( - &BigUint::from(2u32), - &p_y, - FieldOperation::Mul, - ); + let slope_denominator = + cols.slope_denominator + .populate(&BigUint::from(2u32), &p_y, FieldOperation::Mul); - cols.slope.populate::( - &slope_numerator, - &slope_denominator, - FieldOperation::Div, - ) + cols.slope + .populate(&slope_numerator, &slope_denominator, FieldOperation::Div) }; // x = slope * slope - (p.x + p.x). let x = { - let slope_squared = - cols.slope_squared - .populate::(&slope, &slope, FieldOperation::Mul); - let p_x_plus_p_x = - cols.p_x_plus_p_x - .populate::(&p_x, &p_x, FieldOperation::Add); + let slope_squared = cols + .slope_squared + .populate(&slope, &slope, FieldOperation::Mul); + let p_x_plus_p_x = cols.p_x_plus_p_x.populate(&p_x, &p_x, FieldOperation::Add); cols.x3_ins - .populate::(&slope_squared, &p_x_plus_p_x, FieldOperation::Sub) + .populate(&slope_squared, &p_x_plus_p_x, FieldOperation::Sub) }; // y = slope * (p.x - x) - p.y. { - let p_x_minus_x = - cols.p_x_minus_x - .populate::(&p_x, &x, FieldOperation::Sub); - let slope_times_p_x_minus_x = cols.slope_times_p_x_minus_x.populate::( - &slope, - &p_x_minus_x, - FieldOperation::Mul, - ); - cols.y3_ins.populate::( - &slope_times_p_x_minus_x, - &p_y, - FieldOperation::Sub, - ); + let p_x_minus_x = cols.p_x_minus_x.populate(&p_x, &x, FieldOperation::Sub); + let slope_times_p_x_minus_x = + cols.slope_times_p_x_minus_x + .populate(&slope, &p_x_minus_x, FieldOperation::Mul); + cols.y3_ins + .populate(&slope_times_p_x_minus_x, &p_y, FieldOperation::Sub); } } } @@ -279,28 +258,23 @@ where // a in the Weierstrass form: y^2 = x^3 + a * x + b. // TODO: U32 can't be hardcoded here? - let a: Limbs<::Expr, U32> = - limbs_from_biguint::(&E::a_int()); + let a = E::BaseField::to_limbs_field::(&E::a_int()); // slope = slope_numerator / slope_denominator. let slope = { // slope_numerator = a + (p.x * p.x) * 3. { - row.p_x_squared.eval::( - builder, - &p_x, - &p_x, - FieldOperation::Mul, - ); + row.p_x_squared + .eval::(builder, &p_x, &p_x, FieldOperation::Mul); - row.p_x_squared_times_3.eval::( + row.p_x_squared_times_3.eval::( builder, &row.p_x_squared.result, - &limbs_from_biguint::(&BigUint::from(3u32)), + &E::BaseField::to_limbs_field::(&BigUint::from(3u32)), FieldOperation::Mul, ); - row.slope_numerator.eval::( + row.slope_numerator.eval::( builder, &a, &row.p_x_squared_times_3.result, @@ -309,14 +283,14 @@ where }; // slope_denominator = 2 * y. - row.slope_denominator.eval::( + row.slope_denominator.eval::( builder, - &limbs_from_biguint::(&BigUint::from(2u32)), + &E::BaseField::to_limbs_field::(&BigUint::from(2u32)), &p_y, FieldOperation::Mul, ); - row.slope.eval::( + row.slope.eval::( builder, &row.slope_numerator.result, &row.slope_denominator.result, @@ -328,19 +302,11 @@ where // x = slope * slope - (p.x + p.x). let x = { - row.slope_squared.eval::( - builder, - slope, - slope, - FieldOperation::Mul, - ); - row.p_x_plus_p_x.eval::( - builder, - &p_x, - &p_x, - FieldOperation::Add, - ); - row.x3_ins.eval::( + row.slope_squared + .eval::(builder, slope, slope, FieldOperation::Mul); + row.p_x_plus_p_x + .eval::(builder, &p_x, &p_x, FieldOperation::Add); + row.x3_ins.eval::( builder, &row.slope_squared.result, &row.p_x_plus_p_x.result, @@ -352,14 +318,14 @@ where // y = slope * (p.x - x) - p.y. { row.p_x_minus_x - .eval::(builder, &p_x, x, FieldOperation::Sub); - row.slope_times_p_x_minus_x.eval::( + .eval::(builder, &p_x, x, FieldOperation::Sub); + row.slope_times_p_x_minus_x.eval::( builder, slope, &row.p_x_minus_x.result, FieldOperation::Mul, ); - row.y3_ins.eval::( + row.y3_ins.eval::( builder, &row.slope_times_p_x_minus_x.result, &p_y, diff --git a/core/src/utils/ec/field.rs b/core/src/utils/ec/field.rs index 36d7a48f72..b0528f9418 100644 --- a/core/src/utils/ec/field.rs +++ b/core/src/utils/ec/field.rs @@ -33,24 +33,31 @@ pub trait FieldParameters: .take(Self::NB_LIMBS) } + /// Convert a BigUint to a Vec of u8 limbs (with len NB_LIMBS). fn to_limbs(x: &BigUint) -> Vec { let mut bytes = x.to_bytes_le(); bytes.resize(Self::NB_LIMBS, 0u8); bytes } - fn to_limbs_field(x: &BigUint) -> Vec { + /// Convert a BigUint to a Vec of F limbs (with len NB_LIMBS). + fn to_limbs_field_vec, F: Field>(x: &BigUint) -> Vec { Self::to_limbs(x) .into_iter() - .map(|x| F::from_canonical_u8(x)) - .collect() + .map(|x| F::from_canonical_u8(x).into()) + .collect::>() + } + + /// Convert a BigUint to Limbs. + fn to_limbs_field, F: Field>(x: &BigUint) -> Limbs { + limbs_from_vec(Self::to_limbs_field_vec(x)) } } /// Convert a vec of u8 limbs to a Limbs of NUM_LIMBS. -pub fn limbs_from_vec(limbs: Vec) -> Limbs { +pub fn limbs_from_vec, N: ArrayLength, F: Field>(limbs: Vec) -> Limbs { debug_assert_eq!(limbs.len(), N::USIZE); - let mut result = GenericArray::::generate(|_i| F::zero()); + let mut result = GenericArray::::generate(|_i| F::zero().into()); for (i, limb) in limbs.into_iter().enumerate() { result[i] = limb; } From 37113d0be6e39ab7cf158a2ae65a8a464525de5d Mon Sep 17 00:00:00 2001 From: Chris Tian Date: Fri, 22 Mar 2024 14:23:29 -0700 Subject: [PATCH 11/18] clippy --- core/src/operations/field/field_den.rs | 27 +++++++++---------- core/src/operations/field/field_sqrt.rs | 4 +-- .../src/syscall/precompiles/edwards/ed_add.rs | 19 +++++++------ .../precompiles/edwards/ed_decompress.rs | 7 +++-- .../syscall/precompiles/k256/decompress.rs | 2 +- core/src/syscall/precompiles/mod.rs | 12 ++++----- 6 files changed, 33 insertions(+), 38 deletions(-) diff --git a/core/src/operations/field/field_den.rs b/core/src/operations/field/field_den.rs index 08d034bf4b..cafe734835 100644 --- a/core/src/operations/field/field_den.rs +++ b/core/src/operations/field/field_den.rs @@ -3,7 +3,7 @@ use super::util::{compute_root_quotient_and_shift, split_u16_limbs_to_u8_limbs}; use super::util_air::eval_field_operation; use crate::air::Polynomial; use crate::air::SP1AirBuilder; -use crate::utils::ec::field::{limbs_from_vec, FieldParameters}; +use crate::utils::ec::field::FieldParameters; use num::BigUint; use p3_field::PrimeField32; @@ -125,7 +125,7 @@ mod tests { use num::BigUint; use p3_air::BaseAir; use p3_field::{Field, PrimeField32}; - use typenum::U32; + use super::{FieldDenCols, Limbs}; @@ -133,7 +133,7 @@ mod tests { use crate::stark::StarkGenericConfig; use crate::utils::ec::edwards::ed25519::Ed25519BaseField; - use crate::utils::ec::field::{limbs_from_vec, FieldParameters}; + use crate::utils::ec::field::FieldParameters; use crate::utils::BabyBearPoseidon2; use crate::utils::{uni_stark_prove as prove, uni_stark_verify as verify}; use crate::{air::SP1AirBuilder, runtime::ExecutionRecord}; @@ -147,16 +147,14 @@ mod tests { use rand::thread_rng; use sp1_derive::AlignedBorrow; - type Limbs32 = U32; - #[derive(Debug, Clone, AlignedBorrow)] - pub struct TestCols { - pub a: Limbs, - pub b: Limbs, - pub a_den_b: FieldDenCols, + pub struct TestCols { + pub a: Limbs, + pub b: Limbs, + pub a_den_b: FieldDenCols, } - pub const NUM_TEST_COLS: usize = size_of::>(); + pub const NUM_TEST_COLS: usize = size_of::>(); struct FieldDenChip { pub sign: bool, @@ -208,9 +206,9 @@ mod tests { .iter() .map(|(a, b)| { let mut row = [F::zero(); NUM_TEST_COLS]; - let cols: &mut TestCols = row.as_mut_slice().borrow_mut(); - cols.a = limbs_from_vec::(P::to_limbs_field::(a)); - cols.b = limbs_from_vec::(P::to_limbs_field::(b)); + let cols: &mut TestCols = row.as_mut_slice().borrow_mut(); + cols.a = P::to_limbs_field::(a); + cols.b = P::to_limbs_field::(b); cols.a_den_b.populate(a, b, self.sign); row }) @@ -239,10 +237,11 @@ mod tests { impl Air for FieldDenChip

where AB: SP1AirBuilder, + Limbs: Copy, { fn eval(&self, builder: &mut AB) { let main = builder.main(); - let local: &TestCols = main.row_slice(0).borrow(); + let local: &TestCols = main.row_slice(0).borrow(); local .a_den_b .eval::(builder, &local.a, &local.b, self.sign); diff --git a/core/src/operations/field/field_sqrt.rs b/core/src/operations/field/field_sqrt.rs index 502e882fc8..499b8d474b 100644 --- a/core/src/operations/field/field_sqrt.rs +++ b/core/src/operations/field/field_sqrt.rs @@ -73,7 +73,7 @@ mod tests { use num::{BigUint, One, Zero}; use p3_air::BaseAir; use p3_field::{Field, PrimeField32}; - use typenum::U32; + use super::{FieldSqrtCols, Limbs}; @@ -95,8 +95,6 @@ mod tests { use rand::thread_rng; use sp1_derive::AlignedBorrow; - type Limbs32 = U32; - #[derive(AlignedBorrow, Debug, Clone)] pub struct TestCols { pub a: Limbs, diff --git a/core/src/syscall/precompiles/edwards/ed_add.rs b/core/src/syscall/precompiles/edwards/ed_add.rs index ce9e882279..8938ce844f 100644 --- a/core/src/syscall/precompiles/edwards/ed_add.rs +++ b/core/src/syscall/precompiles/edwards/ed_add.rs @@ -13,9 +13,9 @@ use crate::runtime::Syscall; use crate::runtime::SyscallCode; use crate::syscall::precompiles::create_ec_add_event; use crate::syscall::precompiles::SyscallContext; +use crate::utils::ec::edwards::ed25519::Ed25519BaseField; use crate::utils::ec::edwards::EdwardsParameters; use crate::utils::ec::field::FieldParameters; -use crate::utils::ec::weierstrass::secp256k1::Secp256k1BaseField; use crate::utils::ec::AffinePoint; use crate::utils::ec::EllipticCurve; use crate::utils::limbs_from_prev_access; @@ -36,7 +36,6 @@ use sp1_derive::AlignedBorrow; use std::fmt::Debug; use std::marker::PhantomData; use tracing::instrument; -use typenum::U32; pub const NUM_ED_ADD_COLS: usize = size_of::>(); @@ -53,14 +52,14 @@ pub struct EdAddAssignCols { pub q_ptr: T, pub p_access: [MemoryWriteCols; 16], pub q_access: [MemoryReadCols; 16], - pub(crate) x3_numerator: FieldInnerProductCols, - pub(crate) y3_numerator: FieldInnerProductCols, - pub(crate) x1_mul_y1: FieldOpCols, - pub(crate) x2_mul_y2: FieldOpCols, - pub(crate) f: FieldOpCols, - pub(crate) d_mul_f: FieldOpCols, - pub(crate) x3_ins: FieldDenCols, - pub(crate) y3_ins: FieldDenCols, + pub(crate) x3_numerator: FieldInnerProductCols, + pub(crate) y3_numerator: FieldInnerProductCols, + pub(crate) x1_mul_y1: FieldOpCols, + pub(crate) x2_mul_y2: FieldOpCols, + pub(crate) f: FieldOpCols, + pub(crate) d_mul_f: FieldOpCols, + pub(crate) x3_ins: FieldDenCols, + pub(crate) y3_ins: FieldDenCols, } #[derive(Default)] diff --git a/core/src/syscall/precompiles/edwards/ed_decompress.rs b/core/src/syscall/precompiles/edwards/ed_decompress.rs index 1eac233114..6805315b27 100644 --- a/core/src/syscall/precompiles/edwards/ed_decompress.rs +++ b/core/src/syscall/precompiles/edwards/ed_decompress.rs @@ -18,7 +18,6 @@ use crate::utils::ec::edwards::ed25519::decompress; use crate::utils::ec::edwards::ed25519::ed25519_sqrt; use crate::utils::ec::edwards::ed25519::Ed25519BaseField; use crate::utils::ec::edwards::EdwardsParameters; -use crate::utils::ec::field::limbs_from_vec; use crate::utils::ec::field::FieldParameters; use crate::utils::ec::COMPRESSED_POINT_BYTES; use crate::utils::ec::NUM_BYTES_FIELD_ELEMENT; @@ -102,12 +101,12 @@ impl EdDecompressCols { } let y = &BigUint::from_bytes_le(&event.y_bytes); - self.populate_field_ops::(y); + self.populate_field_ops::(y); record.add_byte_lookup_events(new_byte_lookup_events); } - fn populate_field_ops(&mut self, y: &BigUint) { + fn populate_field_ops(&mut self, y: &BigUint) { let one = BigUint::one(); let yy = self.yy.populate(y, y, FieldOperation::Mul); let u = self.u.populate(&yy, &one, FieldOperation::Sub); @@ -296,7 +295,7 @@ impl MachineAir for EdDecompressChip = row.as_mut_slice().borrow_mut(); let zero = BigUint::zero(); - cols.populate_field_ops::(&zero); + cols.populate_field_ops::(&zero); row }); diff --git a/core/src/syscall/precompiles/k256/decompress.rs b/core/src/syscall/precompiles/k256/decompress.rs index 93e8cde7b5..9e8395d3e5 100644 --- a/core/src/syscall/precompiles/k256/decompress.rs +++ b/core/src/syscall/precompiles/k256/decompress.rs @@ -15,7 +15,7 @@ use crate::runtime::Syscall; use crate::runtime::SyscallCode; use crate::syscall::precompiles::SyscallContext; use crate::utils::bytes_to_words_le; -use crate::utils::ec::field::limbs_from_vec; + use crate::utils::ec::field::FieldParameters; use crate::utils::ec::weierstrass::secp256k1::secp256k1_sqrt; use crate::utils::ec::weierstrass::secp256k1::Secp256k1BaseField; diff --git a/core/src/syscall/precompiles/mod.rs b/core/src/syscall/precompiles/mod.rs index 99046f74e4..2c6d843f3a 100644 --- a/core/src/syscall/precompiles/mod.rs +++ b/core/src/syscall/precompiles/mod.rs @@ -5,17 +5,17 @@ pub mod keccak256; pub mod sha256; pub mod weierstrass; -use num::BigUint; + use serde::{Deserialize, Serialize}; -use typenum::U32; -use crate::air::SP1AirBuilder; -use crate::operations::field::params::Limbs; + + + use crate::runtime::SyscallContext; -use crate::utils::ec::field::FieldParameters; + use crate::utils::ec::{AffinePoint, EllipticCurve}; use crate::{runtime::MemoryReadRecord, runtime::MemoryWriteRecord}; -use p3_field::AbstractField; + /// Elliptic curve add event. #[derive(Debug, Clone, Serialize, Deserialize)] From 9bc870ead5dd14fc5b4a9838f91755229856ea11 Mon Sep 17 00:00:00 2001 From: Chris Tian Date: Fri, 22 Mar 2024 16:00:15 -0700 Subject: [PATCH 12/18] NumWords for words per field element/curve point --- core/src/operations/field/params.rs | 30 ++++++++++++++++-- .../weierstrass/weierstrass_add.rs | 31 +++++++++---------- .../weierstrass/weierstrass_double.rs | 18 +++++------ core/src/utils/ec/mod.rs | 3 +- 4 files changed, 54 insertions(+), 28 deletions(-) diff --git a/core/src/operations/field/params.rs b/core/src/operations/field/params.rs index b7fed3fad2..7e13375054 100644 --- a/core/src/operations/field/params.rs +++ b/core/src/operations/field/params.rs @@ -1,23 +1,49 @@ use crate::air::Polynomial; use generic_array::{ArrayLength, GenericArray}; use std::fmt::Debug; -use std::ops::Index; +use std::ops::{Div, Index}; use std::slice::Iter; use std::usize; -use typenum::{U32, U62}; +use typenum::{U2, U32, U4, U62}; pub const NB_BITS_PER_LIMB: usize = 8; #[derive(Debug, Clone)] +/// An array representing N limbs of T. +/// +/// GenericArray allows us to constrain the correct array lengths so we can have # of limbs and # of +/// witness limbs associated in NumLimbs / FieldParameters. +/// See: https://github.com/RustCrypto/traits/issues/1481 pub struct Limbs(pub GenericArray); impl Copy for Limbs where N::ArrayType: Copy {} +/// Trait that holds the typenum values for # of limbs and # of witness limbs. pub trait NumLimbs: Clone + Debug { type Limbs: ArrayLength + Debug; type Witness: ArrayLength + Debug; } +/// Trait that holds word numbers. +pub trait NumWords: Clone + Debug { + /// The number of words needed to represent a field element. + type WordsFieldElement: ArrayLength + Debug; + /// The number of words needed to represent a curve point (two field elements). + type WordsCurvePoint: ArrayLength + Debug; +} + +/// Implement NumWords for NumLimbs where # Limbs is divisible by 4. +impl NumWords for N +where + N::Limbs: Div, + N::Limbs: Div, + >::Output: ArrayLength + Debug, + >::Output: ArrayLength + Debug, +{ + type WordsFieldElement = >::Output; + type WordsCurvePoint = >::Output; +} + #[derive(Debug, Clone)] pub struct NumLimbs32; diff --git a/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs b/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs index 1fef483454..f445e75f8d 100644 --- a/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs +++ b/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs @@ -7,6 +7,7 @@ use crate::operations::field::field_op::FieldOpCols; use crate::operations::field::field_op::FieldOperation; use crate::operations::field::params::Limbs; use crate::operations::field::params::NumLimbs; +use crate::operations::field::params::NumWords; use crate::runtime::ExecutionRecord; use crate::runtime::Syscall; use crate::runtime::SyscallCode; @@ -16,12 +17,11 @@ use crate::utils::ec::field::FieldParameters; use crate::utils::ec::weierstrass::WeierstrassParameters; use crate::utils::ec::AffinePoint; use crate::utils::ec::EllipticCurve; -use crate::utils::ec::NUM_WORDS_EC_POINT; -use crate::utils::ec::NUM_WORDS_FIELD_ELEMENT; use crate::utils::limbs_from_prev_access; use crate::utils::pad_rows; use core::borrow::{Borrow, BorrowMut}; use core::mem::size_of; +use generic_array::GenericArray; use num::BigUint; use num::Zero; use p3_air::AirBuilder; @@ -33,8 +33,9 @@ use p3_matrix::MatrixRowSlices; use sp1_derive::AlignedBorrow; use std::fmt::Debug; use std::marker::PhantomData; +use typenum::Unsigned; -pub const fn num_weierstrass_add_cols() -> usize { +pub const fn num_weierstrass_add_cols() -> usize { size_of::>() } @@ -44,14 +45,14 @@ pub const fn num_weierstrass_add_cols() -> usize { /// made generic in the future. #[derive(Debug, Clone, AlignedBorrow)] #[repr(C)] -pub struct WeierstrassAddAssignCols { +pub struct WeierstrassAddAssignCols { pub is_real: T, pub shard: T, pub clk: T, pub p_ptr: T, pub q_ptr: T, - pub p_access: [MemoryWriteCols; NUM_WORDS_EC_POINT], - pub q_access: [MemoryReadCols; NUM_WORDS_EC_POINT], + pub p_access: GenericArray, P::WordsCurvePoint>, + pub q_access: GenericArray, P::WordsCurvePoint>, pub(crate) slope_denominator: FieldOpCols, pub(crate) slope_numerator: FieldOpCols, pub(crate) slope: FieldOpCols, @@ -177,10 +178,10 @@ where Self::populate_field_ops(cols, p_x, p_y, q_x, q_y); // Populate the memory access columns. - for i in 0..NUM_WORDS_EC_POINT { + for i in 0..cols.q_access.len() { cols.q_access[i].populate(event.q_memory_records[i], &mut new_byte_lookup_events); } - for i in 0..NUM_WORDS_EC_POINT { + for i in 0..cols.p_access.len() { cols.p_access[i].populate(event.p_memory_records[i], &mut new_byte_lookup_events); } @@ -224,15 +225,13 @@ where let main = builder.main(); let row: &WeierstrassAddAssignCols = main.row_slice(0).borrow(); - let p_x: Limbs<::Var, ::Limbs> = - limbs_from_prev_access(&row.p_access[0..NUM_WORDS_FIELD_ELEMENT]); - let p_y: Limbs<::Var, ::Limbs> = - limbs_from_prev_access(&row.p_access[NUM_WORDS_FIELD_ELEMENT..]); + let num_words_field_element = ::Limbs::USIZE / 4; - let q_x: Limbs<::Var, ::Limbs> = - limbs_from_prev_access(&row.q_access[0..NUM_WORDS_FIELD_ELEMENT]); - let q_y: Limbs<::Var, ::Limbs> = - limbs_from_prev_access(&row.q_access[NUM_WORDS_FIELD_ELEMENT..]); + let p_x = limbs_from_prev_access(&row.p_access[0..num_words_field_element]); + let p_y = limbs_from_prev_access(&row.p_access[num_words_field_element..]); + + let q_x = limbs_from_prev_access(&row.q_access[0..num_words_field_element]); + let q_y = limbs_from_prev_access(&row.q_access[num_words_field_element..]); // slope = (q.y - p.y) / (q.x - p.x). let slope = { diff --git a/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs b/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs index 61fd387b4c..1cb090e8de 100644 --- a/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs +++ b/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs @@ -6,6 +6,7 @@ use crate::operations::field::field_op::FieldOpCols; use crate::operations::field::field_op::FieldOperation; use crate::operations::field::params::Limbs; use crate::operations::field::params::NumLimbs; +use crate::operations::field::params::NumWords; use crate::runtime::ExecutionRecord; use crate::runtime::Syscall; use crate::runtime::SyscallCode; @@ -16,12 +17,12 @@ use crate::utils::ec::field::FieldParameters; use crate::utils::ec::weierstrass::WeierstrassParameters; use crate::utils::ec::AffinePoint; use crate::utils::ec::EllipticCurve; -use crate::utils::ec::NUM_WORDS_EC_POINT; use crate::utils::ec::NUM_WORDS_FIELD_ELEMENT; use crate::utils::limbs_from_prev_access; use crate::utils::pad_rows; use core::borrow::{Borrow, BorrowMut}; use core::mem::size_of; +use generic_array::GenericArray; use num::BigUint; use num::Zero; use p3_air::AirBuilder; @@ -37,7 +38,7 @@ use std::fmt::Debug; use std::marker::PhantomData; use tracing::instrument; -pub const fn num_weierstrass_double_cols() -> usize { +pub const fn num_weierstrass_double_cols() -> usize { size_of::>() } @@ -47,12 +48,12 @@ pub const fn num_weierstrass_double_cols() -> usize { /// made generic in the future. #[derive(Debug, Clone, AlignedBorrow)] #[repr(C)] -pub struct WeierstrassDoubleAssignCols { +pub struct WeierstrassDoubleAssignCols { pub is_real: T, pub shard: T, pub clk: T, pub p_ptr: T, - pub p_access: [MemoryWriteCols; NUM_WORDS_EC_POINT], + pub p_access: GenericArray, P::WordsCurvePoint>, pub(crate) slope_denominator: FieldOpCols, pub(crate) slope_numerator: FieldOpCols, pub(crate) slope: FieldOpCols, @@ -196,7 +197,7 @@ where Self::populate_field_ops(cols, p_x, p_y); // Populate the memory access columns. - for i in 0..NUM_WORDS_EC_POINT { + for i in 0..cols.p_access.len() { cols.p_access[i] .populate(event.p_memory_records[i], &mut new_byte_lookup_events); } @@ -251,10 +252,9 @@ where let main = builder.main(); let row: &WeierstrassDoubleAssignCols = main.row_slice(0).borrow(); - let p_x: Limbs<::Var, ::Limbs> = - limbs_from_prev_access(&row.p_access[0..NUM_WORDS_FIELD_ELEMENT]); - let p_y: Limbs<::Var, ::Limbs> = - limbs_from_prev_access(&row.p_access[NUM_WORDS_FIELD_ELEMENT..]); + let num_words_field_element = E::BaseField::NB_LIMBS / 4; + let p_x = limbs_from_prev_access(&row.p_access[0..num_words_field_element]); + let p_y = limbs_from_prev_access(&row.p_access[num_words_field_element..]); // a in the Weierstrass form: y^2 = x^3 + a * x + b. // TODO: U32 can't be hardcoded here? diff --git a/core/src/utils/ec/mod.rs b/core/src/utils/ec/mod.rs index 9601ccc419..d3d360ff26 100644 --- a/core/src/utils/ec/mod.rs +++ b/core/src/utils/ec/mod.rs @@ -11,6 +11,7 @@ use std::fmt::Debug; use std::ops::{Add, Neg}; use crate::air::WORD_SIZE; +use crate::operations::field::params::NumWords; pub const NUM_WORDS_FIELD_ELEMENT: usize = 8; pub const NUM_BYTES_FIELD_ELEMENT: usize = NUM_WORDS_FIELD_ELEMENT * WORD_SIZE; @@ -83,7 +84,7 @@ impl AffinePoint { pub trait EllipticCurveParameters: Debug + Send + Sync + Copy + Serialize + DeserializeOwned + 'static { - type BaseField: FieldParameters; + type BaseField: FieldParameters + NumWords; } /// An interface for elliptic curve groups. From 51e29e21e480020e01361c1ff81c07a0c53092d8 Mon Sep 17 00:00:00 2001 From: Chris Tian Date: Fri, 22 Mar 2024 16:33:14 -0700 Subject: [PATCH 13/18] comments --- core/src/operations/field/params.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/core/src/operations/field/params.rs b/core/src/operations/field/params.rs index 7e13375054..0abab90ad9 100644 --- a/core/src/operations/field/params.rs +++ b/core/src/operations/field/params.rs @@ -24,7 +24,7 @@ pub trait NumLimbs: Clone + Debug { type Witness: ArrayLength + Debug; } -/// Trait that holds word numbers. +/// Trait that holds number of words needed to represent a field element and a curve point. pub trait NumWords: Clone + Debug { /// The number of words needed to represent a field element. type WordsFieldElement: ArrayLength + Debug; @@ -33,6 +33,9 @@ pub trait NumWords: Clone + Debug { } /// Implement NumWords for NumLimbs where # Limbs is divisible by 4. +/// +/// Using typenum we can do N/4 and N/2 in type-level arithmetic. Having it as a separate trait +/// avoids needing the Div where clauses everywhere. impl NumWords for N where N::Limbs: Div, @@ -40,7 +43,9 @@ where >::Output: ArrayLength + Debug, >::Output: ArrayLength + Debug, { + /// Each word has 4 limbs so we divide by 4. type WordsFieldElement = >::Output; + /// Curve point has 2 field elements so we divide by 2. type WordsCurvePoint = >::Output; } From a2641ea8b59b7b7af0b64e165aeaf9ac54c8d333 Mon Sep 17 00:00:00 2001 From: Chris Tian Date: Fri, 22 Mar 2024 16:33:51 -0700 Subject: [PATCH 14/18] fmt --- core/src/operations/field/field_den.rs | 1 - core/src/operations/field/field_sqrt.rs | 1 - core/src/syscall/precompiles/mod.rs | 5 ----- 3 files changed, 7 deletions(-) diff --git a/core/src/operations/field/field_den.rs b/core/src/operations/field/field_den.rs index cafe734835..6d48de4275 100644 --- a/core/src/operations/field/field_den.rs +++ b/core/src/operations/field/field_den.rs @@ -125,7 +125,6 @@ mod tests { use num::BigUint; use p3_air::BaseAir; use p3_field::{Field, PrimeField32}; - use super::{FieldDenCols, Limbs}; diff --git a/core/src/operations/field/field_sqrt.rs b/core/src/operations/field/field_sqrt.rs index 499b8d474b..2442f078a5 100644 --- a/core/src/operations/field/field_sqrt.rs +++ b/core/src/operations/field/field_sqrt.rs @@ -73,7 +73,6 @@ mod tests { use num::{BigUint, One, Zero}; use p3_air::BaseAir; use p3_field::{Field, PrimeField32}; - use super::{FieldSqrtCols, Limbs}; diff --git a/core/src/syscall/precompiles/mod.rs b/core/src/syscall/precompiles/mod.rs index 2c6d843f3a..bc2cbca9c1 100644 --- a/core/src/syscall/precompiles/mod.rs +++ b/core/src/syscall/precompiles/mod.rs @@ -5,18 +5,13 @@ pub mod keccak256; pub mod sha256; pub mod weierstrass; - use serde::{Deserialize, Serialize}; - - - use crate::runtime::SyscallContext; use crate::utils::ec::{AffinePoint, EllipticCurve}; use crate::{runtime::MemoryReadRecord, runtime::MemoryWriteRecord}; - /// Elliptic curve add event. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ECAddEvent { From fb8e9dacd16b14cd6900341fb624de814888fc53 Mon Sep 17 00:00:00 2001 From: Chris Tian Date: Fri, 22 Mar 2024 16:42:17 -0700 Subject: [PATCH 15/18] move numlimbs to utils/ec --- core/src/operations/field/params.rs | 42 +------------------ .../weierstrass/weierstrass_add.rs | 4 +- .../weierstrass/weierstrass_double.rs | 4 +- core/src/utils/ec/edwards/ed25519.rs | 3 +- core/src/utils/ec/field.rs | 35 +++++++++++++++- core/src/utils/ec/mod.rs | 3 +- core/src/utils/ec/weierstrass/bn254.rs | 2 +- core/src/utils/ec/weierstrass/secp256k1.rs | 3 +- 8 files changed, 46 insertions(+), 50 deletions(-) diff --git a/core/src/operations/field/params.rs b/core/src/operations/field/params.rs index 0abab90ad9..020e42f26b 100644 --- a/core/src/operations/field/params.rs +++ b/core/src/operations/field/params.rs @@ -1,10 +1,9 @@ use crate::air::Polynomial; use generic_array::{ArrayLength, GenericArray}; use std::fmt::Debug; -use std::ops::{Div, Index}; +use std::ops::Index; use std::slice::Iter; use std::usize; -use typenum::{U2, U32, U4, U62}; pub const NB_BITS_PER_LIMB: usize = 8; @@ -18,45 +17,6 @@ pub struct Limbs(pub GenericArray); impl Copy for Limbs where N::ArrayType: Copy {} -/// Trait that holds the typenum values for # of limbs and # of witness limbs. -pub trait NumLimbs: Clone + Debug { - type Limbs: ArrayLength + Debug; - type Witness: ArrayLength + Debug; -} - -/// Trait that holds number of words needed to represent a field element and a curve point. -pub trait NumWords: Clone + Debug { - /// The number of words needed to represent a field element. - type WordsFieldElement: ArrayLength + Debug; - /// The number of words needed to represent a curve point (two field elements). - type WordsCurvePoint: ArrayLength + Debug; -} - -/// Implement NumWords for NumLimbs where # Limbs is divisible by 4. -/// -/// Using typenum we can do N/4 and N/2 in type-level arithmetic. Having it as a separate trait -/// avoids needing the Div where clauses everywhere. -impl NumWords for N -where - N::Limbs: Div, - N::Limbs: Div, - >::Output: ArrayLength + Debug, - >::Output: ArrayLength + Debug, -{ - /// Each word has 4 limbs so we divide by 4. - type WordsFieldElement = >::Output; - /// Curve point has 2 field elements so we divide by 2. - type WordsCurvePoint = >::Output; -} - -#[derive(Debug, Clone)] -pub struct NumLimbs32; - -impl NumLimbs for NumLimbs32 { - type Limbs = U32; - type Witness = U62; -} - impl Default for Limbs where T: Default + Copy, diff --git a/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs b/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs index f445e75f8d..76dda57c32 100644 --- a/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs +++ b/core/src/syscall/precompiles/weierstrass/weierstrass_add.rs @@ -6,14 +6,14 @@ use crate::memory::MemoryWriteCols; use crate::operations::field::field_op::FieldOpCols; use crate::operations::field::field_op::FieldOperation; use crate::operations::field::params::Limbs; -use crate::operations::field::params::NumLimbs; -use crate::operations::field::params::NumWords; use crate::runtime::ExecutionRecord; use crate::runtime::Syscall; use crate::runtime::SyscallCode; use crate::syscall::precompiles::create_ec_add_event; use crate::syscall::precompiles::SyscallContext; use crate::utils::ec::field::FieldParameters; +use crate::utils::ec::field::NumLimbs; +use crate::utils::ec::field::NumWords; use crate::utils::ec::weierstrass::WeierstrassParameters; use crate::utils::ec::AffinePoint; use crate::utils::ec::EllipticCurve; diff --git a/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs b/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs index 1cb090e8de..9281dfa76f 100644 --- a/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs +++ b/core/src/syscall/precompiles/weierstrass/weierstrass_double.rs @@ -5,8 +5,6 @@ use crate::memory::MemoryWriteCols; use crate::operations::field::field_op::FieldOpCols; use crate::operations::field::field_op::FieldOperation; use crate::operations::field::params::Limbs; -use crate::operations::field::params::NumLimbs; -use crate::operations::field::params::NumWords; use crate::runtime::ExecutionRecord; use crate::runtime::Syscall; use crate::runtime::SyscallCode; @@ -14,6 +12,8 @@ use crate::stark::MachineRecord; use crate::syscall::precompiles::create_ec_double_event; use crate::syscall::precompiles::SyscallContext; use crate::utils::ec::field::FieldParameters; +use crate::utils::ec::field::NumLimbs; +use crate::utils::ec::field::NumWords; use crate::utils::ec::weierstrass::WeierstrassParameters; use crate::utils::ec::AffinePoint; use crate::utils::ec::EllipticCurve; diff --git a/core/src/utils/ec/edwards/ed25519.rs b/core/src/utils/ec/edwards/ed25519.rs index 0c23ca24a6..08159e0fba 100644 --- a/core/src/utils/ec/edwards/ed25519.rs +++ b/core/src/utils/ec/edwards/ed25519.rs @@ -5,8 +5,9 @@ use std::str::FromStr; use typenum::{U32, U62}; use super::NUM_LIMBS; -use crate::operations::field::params::{NumLimbs, NB_BITS_PER_LIMB}; +use crate::operations::field::params::NB_BITS_PER_LIMB; use crate::utils::ec::edwards::{EdwardsCurve, EdwardsParameters}; +use crate::utils::ec::field::NumLimbs; use crate::utils::ec::field::{FieldParameters, MAX_NB_LIMBS}; use crate::utils::ec::{AffinePoint, EllipticCurveParameters}; diff --git a/core/src/utils/ec/field.rs b/core/src/utils/ec/field.rs index b0528f9418..e7979db762 100644 --- a/core/src/utils/ec/field.rs +++ b/core/src/utils/ec/field.rs @@ -1,11 +1,13 @@ use super::utils::biguint_from_limbs; -use crate::operations::field::params::{Limbs, NumLimbs, NB_BITS_PER_LIMB}; +use crate::operations::field::params::{Limbs, NB_BITS_PER_LIMB}; use generic_array::sequence::GenericSequence; use generic_array::{ArrayLength, GenericArray}; use num::BigUint; use p3_field::Field; use serde::{de::DeserializeOwned, Serialize}; use std::fmt::Debug; +use std::ops::Div; +use typenum::{U2, U4}; pub const MAX_NB_LIMBS: usize = 32; @@ -63,3 +65,34 @@ pub fn limbs_from_vec, N: ArrayLength, F: Field>(limbs: Vec) -> Li } Limbs(result) } + +/// Trait that holds the typenum values for # of limbs and # of witness limbs. +pub trait NumLimbs: Clone + Debug { + type Limbs: ArrayLength + Debug; + type Witness: ArrayLength + Debug; +} + +/// Trait that holds number of words needed to represent a field element and a curve point. +pub trait NumWords: Clone + Debug { + /// The number of words needed to represent a field element. + type WordsFieldElement: ArrayLength + Debug; + /// The number of words needed to represent a curve point (two field elements). + type WordsCurvePoint: ArrayLength + Debug; +} + +/// Implement NumWords for NumLimbs where # Limbs is divisible by 4. +/// +/// Using typenum we can do N/4 and N/2 in type-level arithmetic. Having it as a separate trait +/// avoids needing the Div where clauses everywhere. +impl NumWords for N +where + N::Limbs: Div, + N::Limbs: Div, + >::Output: ArrayLength + Debug, + >::Output: ArrayLength + Debug, +{ + /// Each word has 4 limbs so we divide by 4. + type WordsFieldElement = >::Output; + /// Curve point has 2 field elements so we divide by 2. + type WordsCurvePoint = >::Output; +} diff --git a/core/src/utils/ec/mod.rs b/core/src/utils/ec/mod.rs index d3d360ff26..a6449393ce 100644 --- a/core/src/utils/ec/mod.rs +++ b/core/src/utils/ec/mod.rs @@ -11,7 +11,8 @@ use std::fmt::Debug; use std::ops::{Add, Neg}; use crate::air::WORD_SIZE; -use crate::operations::field::params::NumWords; + +use self::field::NumWords; pub const NUM_WORDS_FIELD_ELEMENT: usize = 8; pub const NUM_BYTES_FIELD_ELEMENT: usize = NUM_WORDS_FIELD_ELEMENT * WORD_SIZE; diff --git a/core/src/utils/ec/weierstrass/bn254.rs b/core/src/utils/ec/weierstrass/bn254.rs index 4ab04e4891..4246fac275 100644 --- a/core/src/utils/ec/weierstrass/bn254.rs +++ b/core/src/utils/ec/weierstrass/bn254.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; use typenum::{U16, U30}; use super::{SwCurve, WeierstrassParameters}; -use crate::operations::field::params::NumLimbs; +use crate::utils::ec::field::NumLimbs; use crate::utils::ec::field::{FieldParameters, MAX_NB_LIMBS}; use crate::utils::ec::EllipticCurveParameters; diff --git a/core/src/utils/ec/weierstrass/secp256k1.rs b/core/src/utils/ec/weierstrass/secp256k1.rs index a70e2b470a..a7263c277f 100644 --- a/core/src/utils/ec/weierstrass/secp256k1.rs +++ b/core/src/utils/ec/weierstrass/secp256k1.rs @@ -8,7 +8,8 @@ use serde::{Deserialize, Serialize}; use typenum::{U32, U62}; use super::{SwCurve, WeierstrassParameters}; -use crate::operations::field::params::{NumLimbs, NB_BITS_PER_LIMB}; +use crate::operations::field::params::NB_BITS_PER_LIMB; +use crate::utils::ec::field::NumLimbs; use crate::utils::ec::field::{FieldParameters, MAX_NB_LIMBS}; use crate::utils::ec::EllipticCurveParameters; use k256::FieldElement; From 97db87fc7d1034e1b5b67e5ecce8aeab0374879d Mon Sep 17 00:00:00 2001 From: Chris Tian Date: Fri, 22 Mar 2024 17:05:11 -0700 Subject: [PATCH 16/18] remove MAX_NB_LIMBS --- core/src/utils/ec/edwards/ed25519.rs | 11 ++++++----- core/src/utils/ec/edwards/mod.rs | 11 +++++++---- core/src/utils/ec/field.rs | 2 -- core/src/utils/ec/weierstrass/bn254.rs | 17 +++++++++-------- core/src/utils/ec/weierstrass/mod.rs | 13 ++++++++----- core/src/utils/ec/weierstrass/secp256k1.rs | 11 ++++++----- 6 files changed, 36 insertions(+), 29 deletions(-) diff --git a/core/src/utils/ec/edwards/ed25519.rs b/core/src/utils/ec/edwards/ed25519.rs index 08159e0fba..9af9a6dc9d 100644 --- a/core/src/utils/ec/edwards/ed25519.rs +++ b/core/src/utils/ec/edwards/ed25519.rs @@ -1,4 +1,5 @@ use curve25519_dalek::edwards::CompressedEdwardsY; +use generic_array::GenericArray; use num::{BigUint, Num, One}; use serde::{Deserialize, Serialize}; use std::str::FromStr; @@ -7,8 +8,8 @@ use typenum::{U32, U62}; use super::NUM_LIMBS; use crate::operations::field::params::NB_BITS_PER_LIMB; use crate::utils::ec::edwards::{EdwardsCurve, EdwardsParameters}; +use crate::utils::ec::field::FieldParameters; use crate::utils::ec::field::NumLimbs; -use crate::utils::ec::field::{FieldParameters, MAX_NB_LIMBS}; use crate::utils::ec::{AffinePoint, EllipticCurveParameters}; pub type Ed25519 = EdwardsCurve; @@ -45,10 +46,10 @@ impl EllipticCurveParameters for Ed25519Parameters { } impl EdwardsParameters for Ed25519Parameters { - const D: [u16; MAX_NB_LIMBS] = [ - 30883, 4953, 19914, 30187, 55467, 16705, 2637, 112, 59544, 30585, 16505, 36039, 65139, - 11119, 27886, 20995, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ]; + const D: GenericArray = GenericArray::from_array([ + 163, 120, 89, 19, 202, 77, 235, 117, 171, 216, 65, 65, 77, 10, 112, 0, 152, 232, 121, 119, + 121, 64, 199, 140, 115, 254, 111, 43, 238, 108, 3, 82, + ]); fn prime_group_order() -> BigUint { BigUint::from(2u32).pow(252) + BigUint::from(27742317777372353535851937790883648493u128) diff --git a/core/src/utils/ec/edwards/mod.rs b/core/src/utils/ec/edwards/mod.rs index fd976a5185..f8def043fb 100644 --- a/core/src/utils/ec/edwards/mod.rs +++ b/core/src/utils/ec/edwards/mod.rs @@ -1,16 +1,19 @@ pub mod ed25519; +use generic_array::GenericArray; use num::{BigUint, Zero}; use serde::{Deserialize, Serialize}; -use crate::utils::ec::field::{FieldParameters, MAX_NB_LIMBS}; +use crate::utils::ec::field::FieldParameters; use crate::utils::ec::{AffinePoint, EllipticCurve, EllipticCurveParameters}; +use super::field::NumLimbs; + // The number of `u8` limbs in the base field of Ed25519. const NUM_LIMBS: usize = 32; pub trait EdwardsParameters: EllipticCurveParameters { - const D: [u16; MAX_NB_LIMBS]; + const D: GenericArray::Limbs>; fn generator() -> (BigUint, BigUint); @@ -19,7 +22,7 @@ pub trait EdwardsParameters: EllipticCurveParameters { fn d_biguint() -> BigUint { let mut modulus = BigUint::zero(); for (i, limb) in Self::D.iter().enumerate() { - modulus += BigUint::from(*limb) << (16 * i); + modulus += BigUint::from(*limb) << (8 * i); } modulus } @@ -34,7 +37,7 @@ pub trait EdwardsParameters: EllipticCurveParameters { pub struct EdwardsCurve(pub E); impl EdwardsParameters for EdwardsCurve { - const D: [u16; MAX_NB_LIMBS] = E::D; + const D: GenericArray::Limbs> = E::D; fn generator() -> (BigUint, BigUint) { E::generator() diff --git a/core/src/utils/ec/field.rs b/core/src/utils/ec/field.rs index e7979db762..187f4e18cf 100644 --- a/core/src/utils/ec/field.rs +++ b/core/src/utils/ec/field.rs @@ -9,8 +9,6 @@ use std::fmt::Debug; use std::ops::Div; use typenum::{U2, U4}; -pub const MAX_NB_LIMBS: usize = 32; - pub trait FieldParameters: Send + Sync + Copy + 'static + Debug + Serialize + DeserializeOwned + NumLimbs { diff --git a/core/src/utils/ec/weierstrass/bn254.rs b/core/src/utils/ec/weierstrass/bn254.rs index 4246fac275..1a0ca2d4ba 100644 --- a/core/src/utils/ec/weierstrass/bn254.rs +++ b/core/src/utils/ec/weierstrass/bn254.rs @@ -1,10 +1,11 @@ +use generic_array::GenericArray; use num::{BigUint, Num, Zero}; use serde::{Deserialize, Serialize}; -use typenum::{U16, U30}; +use typenum::{U32, U62}; use super::{SwCurve, WeierstrassParameters}; +use crate::utils::ec::field::FieldParameters; use crate::utils::ec::field::NumLimbs; -use crate::utils::ec::field::{FieldParameters, MAX_NB_LIMBS}; use crate::utils::ec::EllipticCurveParameters; #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] @@ -41,8 +42,8 @@ impl FieldParameters for Bn254BaseField { } impl NumLimbs for Bn254BaseField { - type Limbs = U16; - type Witness = U30; + type Limbs = U32; + type Witness = U62; } impl EllipticCurveParameters for Bn254Parameters { @@ -50,15 +51,15 @@ impl EllipticCurveParameters for Bn254Parameters { } impl WeierstrassParameters for Bn254Parameters { - const A: [u16; MAX_NB_LIMBS] = [ + const A: GenericArray = GenericArray::from_array([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ]; + ]); - const B: [u16; MAX_NB_LIMBS] = [ + const B: GenericArray = GenericArray::from_array([ 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ]; + ]); fn generator() -> (BigUint, BigUint) { let x = BigUint::from(1u32); let y = BigUint::from(2u32); diff --git a/core/src/utils/ec/weierstrass/mod.rs b/core/src/utils/ec/weierstrass/mod.rs index da0d0e38f2..bfe954ae31 100644 --- a/core/src/utils/ec/weierstrass/mod.rs +++ b/core/src/utils/ec/weierstrass/mod.rs @@ -1,17 +1,20 @@ +use generic_array::GenericArray; use num::{BigUint, Zero}; use serde::{Deserialize, Serialize}; -use crate::utils::ec::field::{FieldParameters, MAX_NB_LIMBS}; +use crate::utils::ec::field::FieldParameters; use crate::utils::ec::utils::biguint_to_bits_le; use crate::utils::ec::{AffinePoint, EllipticCurve, EllipticCurveParameters}; +use super::field::NumLimbs; + pub mod bn254; pub mod secp256k1; /// Parameters that specify a short Weierstrass curve : y^2 = x^3 + ax + b. pub trait WeierstrassParameters: EllipticCurveParameters { - const A: [u16; MAX_NB_LIMBS]; - const B: [u16; MAX_NB_LIMBS]; + const A: GenericArray::Limbs>; + const B: GenericArray::Limbs>; fn generator() -> (BigUint, BigUint); @@ -42,8 +45,8 @@ pub trait WeierstrassParameters: EllipticCurveParameters { pub struct SwCurve(pub E); impl WeierstrassParameters for SwCurve { - const A: [u16; MAX_NB_LIMBS] = E::A; - const B: [u16; MAX_NB_LIMBS] = E::B; + const A: GenericArray::Limbs> = E::A; + const B: GenericArray::Limbs> = E::B; fn a_int() -> BigUint { E::a_int() diff --git a/core/src/utils/ec/weierstrass/secp256k1.rs b/core/src/utils/ec/weierstrass/secp256k1.rs index a7263c277f..95ef084d19 100644 --- a/core/src/utils/ec/weierstrass/secp256k1.rs +++ b/core/src/utils/ec/weierstrass/secp256k1.rs @@ -3,14 +3,15 @@ use std::str::FromStr; +use generic_array::GenericArray; use num::{BigUint, Zero}; use serde::{Deserialize, Serialize}; use typenum::{U32, U62}; use super::{SwCurve, WeierstrassParameters}; use crate::operations::field::params::NB_BITS_PER_LIMB; +use crate::utils::ec::field::FieldParameters; use crate::utils::ec::field::NumLimbs; -use crate::utils::ec::field::{FieldParameters, MAX_NB_LIMBS}; use crate::utils::ec::EllipticCurveParameters; use k256::FieldElement; use num::traits::FromBytes; @@ -57,15 +58,15 @@ impl EllipticCurveParameters for Secp256k1Parameters { } impl WeierstrassParameters for Secp256k1Parameters { - const A: [u16; MAX_NB_LIMBS] = [ + const A: GenericArray = GenericArray::from_array([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ]; + ]); - const B: [u16; MAX_NB_LIMBS] = [ + const B: GenericArray = GenericArray::from_array([ 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ]; + ]); fn generator() -> (BigUint, BigUint) { let x = BigUint::from_str( "55066263022277343669578718895168534326250603453777594175500187360389116729240", From 3c1c5dc5f2a145df83eb1b984c98df96014ba354 Mon Sep 17 00:00:00 2001 From: Chris Tian Date: Fri, 22 Mar 2024 17:09:44 -0700 Subject: [PATCH 17/18] cleanup --- core/src/utils/ec/edwards/ed25519.rs | 5 ----- core/src/utils/ec/edwards/mod.rs | 3 --- core/src/utils/ec/field.rs | 5 +++-- core/src/utils/ec/weierstrass/bn254.rs | 6 ------ core/src/utils/ec/weierstrass/mod.rs | 4 ++-- core/src/utils/ec/weierstrass/secp256k1.rs | 7 ------- 6 files changed, 5 insertions(+), 25 deletions(-) diff --git a/core/src/utils/ec/edwards/ed25519.rs b/core/src/utils/ec/edwards/ed25519.rs index 9af9a6dc9d..0a794304bd 100644 --- a/core/src/utils/ec/edwards/ed25519.rs +++ b/core/src/utils/ec/edwards/ed25519.rs @@ -5,8 +5,6 @@ use serde::{Deserialize, Serialize}; use std::str::FromStr; use typenum::{U32, U62}; -use super::NUM_LIMBS; -use crate::operations::field::params::NB_BITS_PER_LIMB; use crate::utils::ec::edwards::{EdwardsCurve, EdwardsParameters}; use crate::utils::ec::field::FieldParameters; use crate::utils::ec::field::NumLimbs; @@ -21,9 +19,6 @@ pub struct Ed25519Parameters; pub struct Ed25519BaseField; impl FieldParameters for Ed25519BaseField { - const NB_BITS_PER_LIMB: usize = NB_BITS_PER_LIMB; - const NB_LIMBS: usize = NUM_LIMBS; - const NB_WITNESS_LIMBS: usize = 2 * Self::NB_LIMBS - 2; const MODULUS: &'static [u8] = &[ 237, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127, diff --git a/core/src/utils/ec/edwards/mod.rs b/core/src/utils/ec/edwards/mod.rs index f8def043fb..391b0f07db 100644 --- a/core/src/utils/ec/edwards/mod.rs +++ b/core/src/utils/ec/edwards/mod.rs @@ -9,9 +9,6 @@ use crate::utils::ec::{AffinePoint, EllipticCurve, EllipticCurveParameters}; use super::field::NumLimbs; -// The number of `u8` limbs in the base field of Ed25519. -const NUM_LIMBS: usize = 32; - pub trait EdwardsParameters: EllipticCurveParameters { const D: GenericArray::Limbs>; diff --git a/core/src/utils/ec/field.rs b/core/src/utils/ec/field.rs index 187f4e18cf..f1920cbcba 100644 --- a/core/src/utils/ec/field.rs +++ b/core/src/utils/ec/field.rs @@ -7,13 +7,14 @@ use p3_field::Field; use serde::{de::DeserializeOwned, Serialize}; use std::fmt::Debug; use std::ops::Div; +use typenum::Unsigned; use typenum::{U2, U4}; pub trait FieldParameters: Send + Sync + Copy + 'static + Debug + Serialize + DeserializeOwned + NumLimbs { const NB_BITS_PER_LIMB: usize = NB_BITS_PER_LIMB; - const NB_LIMBS: usize; + const NB_LIMBS: usize = Self::Limbs::USIZE; const NB_WITNESS_LIMBS: usize = 2 * Self::NB_LIMBS - 2; const WITNESS_OFFSET: usize = 1usize << 13; const MODULUS: &'static [u8]; @@ -54,7 +55,7 @@ pub trait FieldParameters: } } -/// Convert a vec of u8 limbs to a Limbs of NUM_LIMBS. +/// Convert a vec of u8 limbs to a Limbs of N length. pub fn limbs_from_vec, N: ArrayLength, F: Field>(limbs: Vec) -> Limbs { debug_assert_eq!(limbs.len(), N::USIZE); let mut result = GenericArray::::generate(|_i| F::zero().into()); diff --git a/core/src/utils/ec/weierstrass/bn254.rs b/core/src/utils/ec/weierstrass/bn254.rs index 1a0ca2d4ba..4ab5ac5756 100644 --- a/core/src/utils/ec/weierstrass/bn254.rs +++ b/core/src/utils/ec/weierstrass/bn254.rs @@ -19,12 +19,6 @@ pub type Bn254 = SwCurve; pub struct Bn254BaseField; impl FieldParameters for Bn254BaseField { - const NB_BITS_PER_LIMB: usize = 16; - - const NB_LIMBS: usize = 16; - - const NB_WITNESS_LIMBS: usize = 2 * Self::NB_LIMBS - 2; - const MODULUS: &'static [u8] = &[ 71, 253, 124, 216, 22, 140, 32, 60, 141, 202, 113, 104, 145, 106, 129, 151, 93, 88, 129, 129, 182, 69, 80, 184, 41, 160, 49, 225, 114, 78, 100, 48, diff --git a/core/src/utils/ec/weierstrass/mod.rs b/core/src/utils/ec/weierstrass/mod.rs index bfe954ae31..84ebe130d2 100644 --- a/core/src/utils/ec/weierstrass/mod.rs +++ b/core/src/utils/ec/weierstrass/mod.rs @@ -23,7 +23,7 @@ pub trait WeierstrassParameters: EllipticCurveParameters { fn a_int() -> BigUint { let mut modulus = BigUint::zero(); for (i, limb) in Self::A.iter().enumerate() { - modulus += BigUint::from(*limb) << (16 * i); + modulus += BigUint::from(*limb) << (8 * i); } modulus } @@ -31,7 +31,7 @@ pub trait WeierstrassParameters: EllipticCurveParameters { fn b_int() -> BigUint { let mut modulus = BigUint::zero(); for (i, limb) in Self::B.iter().enumerate() { - modulus += BigUint::from(*limb) << (16 * i); + modulus += BigUint::from(*limb) << (8 * i); } modulus } diff --git a/core/src/utils/ec/weierstrass/secp256k1.rs b/core/src/utils/ec/weierstrass/secp256k1.rs index 95ef084d19..2f61b8e908 100644 --- a/core/src/utils/ec/weierstrass/secp256k1.rs +++ b/core/src/utils/ec/weierstrass/secp256k1.rs @@ -9,7 +9,6 @@ use serde::{Deserialize, Serialize}; use typenum::{U32, U62}; use super::{SwCurve, WeierstrassParameters}; -use crate::operations::field::params::NB_BITS_PER_LIMB; use crate::utils::ec::field::FieldParameters; use crate::utils::ec::field::NumLimbs; use crate::utils::ec::EllipticCurveParameters; @@ -28,12 +27,6 @@ pub type Secp256k1 = SwCurve; pub struct Secp256k1BaseField; impl FieldParameters for Secp256k1BaseField { - const NB_BITS_PER_LIMB: usize = NB_BITS_PER_LIMB; - - const NB_LIMBS: usize = 32; - - const NB_WITNESS_LIMBS: usize = 2 * Self::NB_LIMBS - 2; - const MODULUS: &'static [u8] = &[ 0x2f, 0xfc, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, From 4b5257293552888b26dd4cd5d0da73eb9afed803 Mon Sep 17 00:00:00 2001 From: Chris Tian Date: Fri, 22 Mar 2024 17:32:00 -0700 Subject: [PATCH 18/18] ed generics --- core/src/syscall/precompiles/edwards/ed_add.rs | 4 ++-- .../syscall/precompiles/edwards/ed_decompress.rs | 15 +++++++++++---- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/core/src/syscall/precompiles/edwards/ed_add.rs b/core/src/syscall/precompiles/edwards/ed_add.rs index 8938ce844f..8bd76b0bfe 100644 --- a/core/src/syscall/precompiles/edwards/ed_add.rs +++ b/core/src/syscall/precompiles/edwards/ed_add.rs @@ -50,8 +50,8 @@ pub struct EdAddAssignCols { pub clk: T, pub p_ptr: T, pub q_ptr: T, - pub p_access: [MemoryWriteCols; 16], - pub q_access: [MemoryReadCols; 16], + pub p_access: [MemoryWriteCols; Ed25519BaseField::NB_LIMBS], + pub q_access: [MemoryReadCols; Ed25519BaseField::NB_LIMBS], pub(crate) x3_numerator: FieldInnerProductCols, pub(crate) y3_numerator: FieldInnerProductCols, pub(crate) x1_mul_y1: FieldOpCols, diff --git a/core/src/syscall/precompiles/edwards/ed_decompress.rs b/core/src/syscall/precompiles/edwards/ed_decompress.rs index 6805315b27..c4da5fccbf 100644 --- a/core/src/syscall/precompiles/edwards/ed_decompress.rs +++ b/core/src/syscall/precompiles/edwards/ed_decompress.rs @@ -19,6 +19,7 @@ use crate::utils::ec::edwards::ed25519::ed25519_sqrt; use crate::utils::ec::edwards::ed25519::Ed25519BaseField; use crate::utils::ec::edwards::EdwardsParameters; use crate::utils::ec::field::FieldParameters; +use crate::utils::ec::field::NumWords; use crate::utils::ec::COMPRESSED_POINT_BYTES; use crate::utils::ec::NUM_BYTES_FIELD_ELEMENT; use crate::utils::ec::NUM_WORDS_FIELD_ELEMENT; @@ -29,6 +30,7 @@ use crate::utils::words_to_bytes_le; use core::borrow::{Borrow, BorrowMut}; use core::mem::size_of; use curve25519_dalek::edwards::CompressedEdwardsY; +use generic_array::GenericArray; use num::BigUint; use num::One; use num::Zero; @@ -39,6 +41,7 @@ use p3_matrix::MatrixRowSlices; use serde::Deserialize; use serde::Serialize; use std::marker::PhantomData; +use typenum::Unsigned; use typenum::U32; use p3_matrix::dense::RowMajorMatrix; @@ -53,8 +56,10 @@ pub struct EdDecompressEvent { pub sign: bool, pub y_bytes: [u8; COMPRESSED_POINT_BYTES], pub decompressed_x_bytes: [u8; NUM_BYTES_FIELD_ELEMENT], - pub x_memory_records: [MemoryWriteRecord; NUM_WORDS_FIELD_ELEMENT], - pub y_memory_records: [MemoryReadRecord; NUM_WORDS_FIELD_ELEMENT], + pub x_memory_records: + [MemoryWriteRecord; <::WordsFieldElement as Unsigned>::USIZE], + pub y_memory_records: + [MemoryReadRecord; <::WordsFieldElement as Unsigned>::USIZE], } pub const NUM_ED_DECOMPRESS_COLS: usize = size_of::>(); @@ -72,8 +77,10 @@ pub struct EdDecompressCols { pub clk: T, pub ptr: T, pub sign: T, - pub x_access: [MemoryWriteCols; NUM_WORDS_FIELD_ELEMENT], - pub y_access: [MemoryReadCols; NUM_WORDS_FIELD_ELEMENT], + pub x_access: + GenericArray, ::WordsFieldElement>, + pub y_access: + GenericArray, ::WordsFieldElement>, pub(crate) yy: FieldOpCols, pub(crate) u: FieldOpCols, pub(crate) dyy: FieldOpCols,