From 6aaa08266cc0a172af1bff8e0e8f6c16bfeddf89 Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 27 Jun 2023 12:21:47 -0300 Subject: [PATCH 01/97] Set lambdaworks felt as Felt --- crates/stark-felt/Cargo.toml | 1 + crates/stark-felt/src/lib.rs | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/crates/stark-felt/Cargo.toml b/crates/stark-felt/Cargo.toml index 5a4fedc..68a0033 100644 --- a/crates/stark-felt/Cargo.toml +++ b/crates/stark-felt/Cargo.toml @@ -13,6 +13,7 @@ readme = "README.md" [dependencies] bitvec = { version = "1.0.1", default-features = false } serde = { version = "1.0.163", optional = true, default-features = false } +lambdaworks-math = { version = "0.1.1", default-features = false } [features] default = ["std", "serde"] diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 52e2a0d..6cb7127 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -8,9 +8,16 @@ pub type BitArrayStore = [u64; 4]; #[cfg(not(target_pointer_width = "64"))] pub type BitArrayStore = [u32; 8]; +use lambdaworks_math::{ + field::{ + element::FieldElement, fields::fft_friendly::stark_252_prime_field::Stark252PrimeField, + }, + unsigned_integer::element::UnsignedInteger, +}; + /// Definition of the Field Element type. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub struct Felt {} +pub struct Felt(FieldElement); /// A non-zero [Felt]. pub struct NonZeroFelt {} From 1bfd3606e9ef462f53909d9931e2b958ad1b4a72 Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 27 Jun 2023 13:09:16 -0300 Subject: [PATCH 02/97] Temporarily remove `Copy` derive trait + implement `Eq` & `PartialEq` manually --- crates/stark-felt/src/lib.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 6cb7127..3f5e914 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -16,9 +16,23 @@ use lambdaworks_math::{ }; /// Definition of the Field Element type. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +// TODO: Derive/Implement Copy +// TODO: See if we can move PartialOrd & Ord to lambdaworks crate +#[derive(Debug, Clone, PartialEq, Eq)] pub struct Felt(FieldElement); +impl PartialOrd for Felt { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for Felt { + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + self.0.representative().cmp(&other.0.representative()) + } +} + /// A non-zero [Felt]. pub struct NonZeroFelt {} From e1cbb869f87cff55547bf4e48ac5d3a312d5e760 Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 27 Jun 2023 13:43:24 -0300 Subject: [PATCH 03/97] Temporarily remove const + implement some fns --- crates/stark-felt/src/lib.rs | 48 +++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 3f5e914..65bc812 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -12,7 +12,7 @@ use lambdaworks_math::{ field::{ element::FieldElement, fields::fft_friendly::stark_252_prime_field::Stark252PrimeField, }, - unsigned_integer::element::UnsignedInteger, + traits::ByteConversion, }; /// Definition of the Field Element type. @@ -46,39 +46,47 @@ pub struct FromStrError; pub struct FromBytesError; impl Felt { - /// [Felt] constant that's equal to 0. - pub const ZERO: Self = Self {}; + // TODO: check if its ok to use lazy_static here + // /// [Felt] constant that's equal to 0. + // pub const ZERO: Self = Self(FieldElement::::zero()); - /// [Felt] constant that's equal to 1. - pub const ONE: Self = Self {}; + // /// [Felt] constant that's equal to 1. + // pub const ONE: Self = Self(FieldElement::::one()); - /// [Felt] constant that's equal to 2. - pub const TWO: Self = Self {}; + // /// [Felt] constant that's equal to 2. + // pub const TWO: Self = Self(FieldElement::::from(2)); - /// [Felt] constant that's equal to 3. - pub const THREE: Self = Self {}; + // /// [Felt] constant that's equal to 3. + // pub const THREE: Self = Self(FieldElement::::from(3)); - /// Maximum value of [Felt]. Equals to 2^251 + 17 * 2^192. - pub const MAX: Self = Self {}; + // /// Maximum value of [Felt]. Equals to 2^251 + 17 * 2^192. + // pub const MAX: Self = Self(FieldElement::::zero() - FieldElement::::one()); + // TODO: const was removed from all methods, check if this is ok/ if we can make these const in lambdaworks /// Creates a new [Felt] from its big-endian representation in a [u8] slice. - pub const fn from_bytes_be(_bytes: &[u8]) -> Result { - todo!() + pub fn from_bytes_be(bytes: &[u8]) -> Result { + FieldElement::from_bytes_be(bytes) + .map(|x| Self(x)) + .map_err(|_| FromBytesError) } /// Creates a new [Felt] from its little-endian representation in a [u8] slice. - pub const fn from_bytes_le(_bytes: &[u8]) -> Result { - todo!() + pub fn from_bytes_le(bytes: &[u8]) -> Result { + FieldElement::from_bytes_le(bytes) + .map(|x| Self(x)) + .map_err(|_| FromBytesError) } /// Converts to big-endian byte representation in a [u8] array. - pub const fn to_bytes_be(&self) -> [u8; 32] { + pub fn to_bytes_be(&self) -> [u8; 32] { + // TODO: implement a no-std version in lambdaworks crate (like to_bytes_le) + //self.0.to_bytes_be() todo!() } /// Converts to little-endian byte representation in a [u8] array. - pub const fn to_bytes_le(&self) -> [u8; 32] { - todo!() + pub fn to_bytes_le(&self) -> [u8; 32] { + self.0.to_bytes_le() } /// Converts to big-endian bit representation. @@ -92,8 +100,8 @@ impl Felt { } /// Checks if `self` is equal to [Felt::Zero]. - pub const fn is_zero(&self) -> bool { - todo!() + pub fn is_zero(&self) -> bool { + self.0 == FieldElement::from_raw(&Stark252PrimeField::ZERO) } /// Finite field division. From 0e2413b34608229e1418a2bd0daf5d471056f340 Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 27 Jun 2023 14:23:11 -0300 Subject: [PATCH 04/97] Impelemnt more methods --- crates/stark-felt/src/lib.rs | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 65bc812..a7e233e 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -34,7 +34,7 @@ impl Ord for Felt { } /// A non-zero [Felt]. -pub struct NonZeroFelt {} +pub struct NonZeroFelt(FieldElement); #[derive(Debug)] pub struct FeltIsZeroError; @@ -104,29 +104,32 @@ impl Felt { self.0 == FieldElement::from_raw(&Stark252PrimeField::ZERO) } + // Question: What is the difference between field_div & floor_div? /// Finite field division. - pub const fn field_div(&self, _rhs: &NonZeroFelt) -> Self { - todo!() + pub fn field_div(&self, rhs: &NonZeroFelt) -> Self { + Self(&self.0 / &rhs.0) } /// Floor division. - pub const fn floor_div(&self, _rhs: &NonZeroFelt) -> Self { - todo!() + pub fn floor_div(&self, rhs: &NonZeroFelt) -> Self { + Self(&self.0 / &rhs.0) } /// Multiplicative inverse. - pub const fn inverse(&self) -> Option { - todo!() + pub fn inverse(&self) -> Option { + Some(Self(self.0.inv())) } /// Finds the square root. There may be 2 roots for each square, and the lower one is returned. - pub const fn sqrt(&self) -> Option { - todo!() + pub fn sqrt(&self) -> Option { + let (root_1, root_2) = self.0.sqrt()?; + let value = FieldElement::new(root_1.representative().min(root_2.representative())); + Some(Self(value)) } /// Raises `self` to the power of 2. - pub const fn square(&self) -> Self { - todo!() + pub fn square(&self) -> Self { + Self(self.0.square()) } /// Raises `self` to the power of `exponent`. From 94571bf0106b828a0927a010c313b6a1cb15050f Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 27 Jun 2023 14:24:25 -0300 Subject: [PATCH 05/97] Derive Copy --- crates/stark-felt/src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index a7e233e..e24d4cd 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -16,9 +16,8 @@ use lambdaworks_math::{ }; /// Definition of the Field Element type. -// TODO: Derive/Implement Copy // TODO: See if we can move PartialOrd & Ord to lambdaworks crate -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct Felt(FieldElement); impl PartialOrd for Felt { From 6ae2304c69eef41d8c72f6a815df10661c22db26 Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 27 Jun 2023 14:33:35 -0300 Subject: [PATCH 06/97] Implement methods + add questions in comment --- crates/stark-felt/src/lib.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index e24d4cd..49a95bf 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -1,5 +1,7 @@ #![cfg_attr(not(feature = "std"), no_std)] +use core::ops::Mul; + use bitvec::array::BitArray; #[cfg(target_pointer_width = "64")] @@ -132,13 +134,18 @@ impl Felt { } /// Raises `self` to the power of `exponent`. - pub const fn pow(&self, _exponent: u128) -> Self { - todo!() + pub fn pow(&self, exponent: u128) -> Self { + Self(self.0.pow(exponent)) } + // Question: Is mul_mod necessary in this crate? + // Isn't multiplication mod CAIRO_PRIME more useful? + // Possible bug: If one wanted to do multiplication modulo CAIRO_PRIME this method would be useless as Felt(CAIRO_PRIME) = 0 + // CHANGE: removed p argument from mul_mod -> doing modulo cairo prime is more useful for the crate + // Suggestion: leave only mul for multiplication operation within the field and then discuss if mul_mod a different prime is needed and if implementing mod would't be a better solution in that case /// Modular multiplication. - pub const fn mul_mod(&self, _rhs: &Self, _p: &Self) -> Self { - todo!() + pub fn mul_mod(&self, rhs: &Self) -> Self { + Self(self.0.mul(rhs.0)) } /// Modular multiplicative inverse. From 8a7a08b6fae55190ab262eb82c59230b5c38ece1 Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 27 Jun 2023 14:37:53 -0300 Subject: [PATCH 07/97] Add questions in comment --- crates/stark-felt/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 49a95bf..6f8511d 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -148,6 +148,7 @@ impl Felt { Self(self.0.mul(rhs.0)) } + // Question: Why is this method needed? /// Modular multiplicative inverse. pub const fn inverse_mod(&self, _p: &Self) -> Self { todo!() From e635d881725e4e73f9da965b07a72ce95e1de2cd Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 27 Jun 2023 14:45:33 -0300 Subject: [PATCH 08/97] Implement basic traits --- crates/stark-felt/src/lib.rs | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 6f8511d..c667b23 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -158,47 +158,55 @@ impl Felt { /// Defaults to [Felt::ZERO]. impl Default for Felt { fn default() -> Self { - todo!() + Self(FieldElement::::zero()) } } impl AsRef for Felt { fn as_ref(&self) -> &Felt { - todo!() + &self } } impl From for Felt { - fn from(_value: NonZeroFelt) -> Self { - todo!() + fn from(value: NonZeroFelt) -> Self { + Self(value.0) } } impl From<&NonZeroFelt> for Felt { - fn from(_value: &NonZeroFelt) -> Self { - todo!() + fn from(value: &NonZeroFelt) -> Self { + Self(value.0) } } impl AsRef for NonZeroFelt { fn as_ref(&self) -> &NonZeroFelt { - todo!() + &self } } impl TryFrom for NonZeroFelt { - type Error = NonZeroFelt; + type Error = FeltIsZeroError; - fn try_from(_value: Felt) -> Result { - todo!() + fn try_from(value: Felt) -> Result { + if value.is_zero() { + Ok(Self(value.0)) + } else { + Err(FeltIsZeroError) + } } } impl TryFrom<&Felt> for NonZeroFelt { - type Error = NonZeroFelt; + type Error = FeltIsZeroError; - fn try_from(_value: &Felt) -> Result { - todo!() + fn try_from(value: &Felt) -> Result { + if value.is_zero() { + Ok(Self(value.0)) + } else { + Err(FeltIsZeroError) + } } } From 7cf2ac7e92c9db38620f95a27982545f50ccae3c Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 27 Jun 2023 14:49:04 -0300 Subject: [PATCH 09/97] Implement addition --- crates/stark-felt/src/lib.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index c667b23..2c75206 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -217,15 +217,15 @@ mod arithmetic { /// Field addition. Never overflows/underflows. impl ops::AddAssign for Felt { - fn add_assign(&mut self, _rhs: Felt) { - todo!() + fn add_assign(&mut self, rhs: Felt) { + self.0 += rhs.0 } } /// Field addition. Never overflows/underflows. impl ops::AddAssign<&Felt> for Felt { - fn add_assign(&mut self, _rhs: &Felt) { - todo!() + fn add_assign(&mut self, rhs: &Felt) { + self.0 += rhs.0 } } @@ -233,8 +233,8 @@ mod arithmetic { impl ops::Add for Felt { type Output = Felt; - fn add(self, _rhs: Felt) -> Self::Output { - todo!() + fn add(self, rhs: Felt) -> Self::Output { + Self(self.0 + rhs.0) } } @@ -242,8 +242,8 @@ mod arithmetic { impl ops::Add<&Felt> for Felt { type Output = Felt; - fn add(self, _rhs: &Felt) -> Self::Output { - todo!() + fn add(self, rhs: &Felt) -> Self::Output { + Self(self.0 + rhs.0) } } @@ -251,8 +251,8 @@ mod arithmetic { impl ops::Add for &Felt { type Output = Felt; - fn add(self, _rhs: Felt) -> Self::Output { - todo!() + fn add(self, rhs: Felt) -> Self::Output { + Felt(self.0 + rhs.0) } } @@ -260,8 +260,8 @@ mod arithmetic { impl ops::Add<&Felt> for &Felt { type Output = Felt; - fn add(self, _rhs: &Felt) -> Self::Output { - todo!() + fn add(self, rhs: &Felt) -> Self::Output { + Felt(self.0 + rhs.0) } } From 6b719cee7efcf4cae75c8f66ea76475885178519 Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 27 Jun 2023 14:53:33 -0300 Subject: [PATCH 10/97] Implement sub + mul --- crates/stark-felt/src/lib.rs | 48 ++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 2c75206..e7e6a52 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -267,15 +267,15 @@ mod arithmetic { /// Field subtraction. Never overflows/underflows. impl ops::SubAssign for Felt { - fn sub_assign(&mut self, _rhs: Felt) { - todo!() + fn sub_assign(&mut self, rhs: Felt) { + self.0 = self.0 - rhs.0 } } /// Field subtraction. Never overflows/underflows. impl ops::SubAssign<&Felt> for Felt { - fn sub_assign(&mut self, _rhs: &Felt) { - todo!() + fn sub_assign(&mut self, rhs: &Felt) { + self.0 = self.0 - rhs.0 } } @@ -283,8 +283,8 @@ mod arithmetic { impl ops::Sub for Felt { type Output = Felt; - fn sub(self, _rhs: Felt) -> Self::Output { - todo!() + fn sub(self, rhs: Felt) -> Self::Output { + Self(self.0 - rhs.0) } } @@ -292,8 +292,8 @@ mod arithmetic { impl ops::Sub<&Felt> for Felt { type Output = Felt; - fn sub(self, _rhs: &Felt) -> Self::Output { - todo!() + fn sub(self, rhs: &Felt) -> Self::Output { + Self(self.0 - rhs.0) } } @@ -301,8 +301,8 @@ mod arithmetic { impl ops::Sub for &Felt { type Output = Felt; - fn sub(self, _rhs: Felt) -> Self::Output { - todo!() + fn sub(self, rhs: Felt) -> Self::Output { + Felt(self.0 - rhs.0) } } @@ -310,22 +310,22 @@ mod arithmetic { impl ops::Sub<&Felt> for &Felt { type Output = Felt; - fn sub(self, _rhs: &Felt) -> Self::Output { - todo!() + fn sub(self, rhs: &Felt) -> Self::Output { + Felt(self.0 - rhs.0) } } /// Field multiplication. Never overflows/underflows. impl ops::MulAssign for Felt { - fn mul_assign(&mut self, _rhs: Felt) { - todo!() + fn mul_assign(&mut self, rhs: Felt) { + self.0 = self.0 * rhs.0 } } /// Field multiplication. Never overflows/underflows. impl ops::MulAssign<&Felt> for Felt { - fn mul_assign(&mut self, _rhs: &Felt) { - todo!() + fn mul_assign(&mut self, rhs: &Felt) { + self.0 = self.0 * rhs.0 } } @@ -333,8 +333,8 @@ mod arithmetic { impl ops::Mul for Felt { type Output = Felt; - fn mul(self, _rhs: Felt) -> Self::Output { - todo!() + fn mul(self, rhs: Felt) -> Self::Output { + Self(self.0 * rhs.0) } } @@ -342,8 +342,8 @@ mod arithmetic { impl ops::Mul<&Felt> for Felt { type Output = Felt; - fn mul(self, _rhs: &Felt) -> Self::Output { - todo!() + fn mul(self, rhs: &Felt) -> Self::Output { + Self(self.0 * rhs.0) } } @@ -351,8 +351,8 @@ mod arithmetic { impl ops::Mul for &Felt { type Output = Felt; - fn mul(self, _rhs: Felt) -> Self::Output { - todo!() + fn mul(self, rhs: Felt) -> Self::Output { + Felt(self.0 * rhs.0) } } @@ -360,8 +360,8 @@ mod arithmetic { impl ops::Mul<&Felt> for &Felt { type Output = Felt; - fn mul(self, _rhs: &Felt) -> Self::Output { - todo!() + fn mul(self, rhs: &Felt) -> Self::Output { + Felt(self.0 * rhs.0) } } From 2d38c768a7b28c275e1ee2106ddb00a2341ebccc Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 27 Jun 2023 15:06:26 -0300 Subject: [PATCH 11/97] Implement some traits --- crates/stark-felt/src/lib.rs | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index e7e6a52..5df3a24 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -372,7 +372,7 @@ mod arithmetic { type Output = Felt; fn neg(self) -> Self::Output { - todo!() + Self(self.0.neg()) } } @@ -380,35 +380,41 @@ mod arithmetic { type Output = Felt; fn neg(self) -> Self::Output { - todo!() + Felt(self.0.neg()) } } + // Are these two impls needed? + impl iter::Sum for Felt { - fn sum>(_iter: I) -> Self { - todo!() + fn sum>(iter: I) -> Self { + iter.sum() } } impl<'a> iter::Sum<&'a Felt> for Felt { - fn sum>(_iter: I) -> Self { - todo!() + fn sum>(iter: I) -> Self { + iter.sum() } } } +// Serialization & Deserialization differs between projects and objectives +// For example: In cairo 0 programs, instructions are Felts in hexadecimal format, but constants are Felts in decimal value +// It doesn't make much sense to have a universal serialization #[cfg(feature = "serde")] mod serde { use ::serde::{Deserialize, Serialize}; use super::*; + // Serialization to decimal value impl Serialize for Felt { - fn serialize(&self, _serializer: S) -> Result + fn serialize(&self, serializer: S) -> Result where S: ::serde::Serializer, { - todo!() + serializer.serialize_str(&self.to_string()) } } @@ -429,8 +435,8 @@ mod formatting { /// Represents [Felt] in decimal by default. impl fmt::Display for Felt { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - todo!() + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) } } From d8aaff384754b0cf0bd1a483167ecd37c9efefc1 Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 27 Jun 2023 16:44:32 -0300 Subject: [PATCH 12/97] Add to_be_bytes impl --- crates/stark-felt/src/lib.rs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 5df3a24..57df3df 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -80,9 +80,7 @@ impl Felt { /// Converts to big-endian byte representation in a [u8] array. pub fn to_bytes_be(&self) -> [u8; 32] { - // TODO: implement a no-std version in lambdaworks crate (like to_bytes_le) - //self.0.to_bytes_be() - todo!() + self.0.to_bytes_be() } /// Converts to little-endian byte representation in a [u8] array. @@ -436,21 +434,21 @@ mod formatting { /// Represents [Felt] in decimal by default. impl fmt::Display for Felt { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) + fmt::Display::fmt(&self, f) } } /// Represents [Felt] in lowercase hexadecimal format. impl fmt::LowerHex for Felt { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - todo!() + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::LowerHex::fmt(&self, f) } } /// Represents [Felt] in uppercase hexadecimal format. impl fmt::UpperHex for Felt { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - todo!() + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::UpperHex::fmt(&self, f) } } } @@ -464,8 +462,8 @@ mod errors { impl std::error::Error for FeltIsZeroError {} impl fmt::Display for FeltIsZeroError { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - todo!() + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + "Tried to create NonZeroFelt from 0".fmt(f) } } From 0bed61f1f589e551bda7cf648a98f4933021fcf1 Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 27 Jun 2023 16:50:51 -0300 Subject: [PATCH 13/97] Move implementation of PartialEq & Eq to lambdaworks --- crates/stark-felt/src/lib.rs | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 57df3df..3b49ec0 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -19,21 +19,9 @@ use lambdaworks_math::{ /// Definition of the Field Element type. // TODO: See if we can move PartialOrd & Ord to lambdaworks crate -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct Felt(FieldElement); -impl PartialOrd for Felt { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for Felt { - fn cmp(&self, other: &Self) -> core::cmp::Ordering { - self.0.representative().cmp(&other.0.representative()) - } -} - /// A non-zero [Felt]. pub struct NonZeroFelt(FieldElement); From 304fe5685c2c73b2440d4a3b64233888b031ce98 Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 27 Jun 2023 16:57:50 -0300 Subject: [PATCH 14/97] Implement `Display` for errors --- crates/stark-felt/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 3b49ec0..2f6c036 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -459,8 +459,8 @@ mod errors { impl std::error::Error for FromStrError {} impl fmt::Display for FromStrError { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - todo!() + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + "Failed to create Felt from string".fmt(f) } } @@ -468,8 +468,8 @@ mod errors { impl std::error::Error for FromBytesError {} impl fmt::Display for FromBytesError { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - todo!() + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + "Failed to create Felt from bytes".fmt(f) } } } From 8aa11b4722e002fe95262e8235405e6cfe04badd Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 27 Jun 2023 17:25:13 -0300 Subject: [PATCH 15/97] Implement constants --- crates/stark-felt/src/lib.rs | 40 ++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 2f6c036..22effaf 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -15,6 +15,7 @@ use lambdaworks_math::{ element::FieldElement, fields::fft_friendly::stark_252_prime_field::Stark252PrimeField, }, traits::ByteConversion, + unsigned_integer::element::UnsignedInteger, }; /// Definition of the Field Element type. @@ -35,21 +36,30 @@ pub struct FromStrError; pub struct FromBytesError; impl Felt { - // TODO: check if its ok to use lazy_static here - // /// [Felt] constant that's equal to 0. - // pub const ZERO: Self = Self(FieldElement::::zero()); - - // /// [Felt] constant that's equal to 1. - // pub const ONE: Self = Self(FieldElement::::one()); - - // /// [Felt] constant that's equal to 2. - // pub const TWO: Self = Self(FieldElement::::from(2)); - - // /// [Felt] constant that's equal to 3. - // pub const THREE: Self = Self(FieldElement::::from(3)); - - // /// Maximum value of [Felt]. Equals to 2^251 + 17 * 2^192. - // pub const MAX: Self = Self(FieldElement::::zero() - FieldElement::::one()); + /// [Felt] constant that's equal to 0. + pub const ZERO: Self = Self(FieldElement::::const_from_raw( + UnsignedInteger::from_u64(0), + )); + + /// [Felt] constant that's equal to 1. + pub const ONE: Self = Self(FieldElement::::const_from_raw( + UnsignedInteger::from_u64(1), + )); + + /// [Felt] constant that's equal to 2. + pub const TWO: Self = Self(FieldElement::::const_from_raw( + UnsignedInteger::from_u64(2), + )); + + /// [Felt] constant that's equal to 3. + pub const THREE: Self = Self(FieldElement::::const_from_raw( + UnsignedInteger::from_u64(3), + )); + + /// Maximum value of [Felt]. Equals to 2^251 + 17 * 2^192. + pub const MAX: Self = Self(FieldElement::::const_from_raw( + UnsignedInteger::from_limbs([544, 0, 0, 32]), + )); // TODO: const was removed from all methods, check if this is ok/ if we can make these const in lambdaworks /// Creates a new [Felt] from its big-endian representation in a [u8] slice. From 89152536b1cf82d825f811ded448a6b74528d6c5 Mon Sep 17 00:00:00 2001 From: Federica Date: Thu, 29 Jun 2023 11:39:16 -0300 Subject: [PATCH 16/97] Remove Todo --- crates/stark-felt/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 22effaf..6c78a12 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -19,7 +19,6 @@ use lambdaworks_math::{ }; /// Definition of the Field Element type. -// TODO: See if we can move PartialOrd & Ord to lambdaworks crate #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct Felt(FieldElement); From 2fb2bfa467adcc5df922609c68a046fce3b086a4 Mon Sep 17 00:00:00 2001 From: Federica Date: Thu, 29 Jun 2023 12:41:38 -0300 Subject: [PATCH 17/97] Implement to_bits_le --- crates/stark-felt/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 6c78a12..08262f6 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -91,8 +91,8 @@ impl Felt { } /// Converts to little-endian bit representation. - pub const fn to_bits_le(&self) -> BitArray { - todo!() + pub fn to_bits_le(&self) -> BitArray { + BitArray::new(self.0.representative().limbs) } /// Checks if `self` is equal to [Felt::Zero]. From 91261e5787e2a00b4740e3ea1bcba66b28e8b932 Mon Sep 17 00:00:00 2001 From: Federica Date: Thu, 29 Jun 2023 12:49:56 -0300 Subject: [PATCH 18/97] Implement to_bits_be --- crates/stark-felt/src/lib.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 08262f6..146ef98 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -86,8 +86,10 @@ impl Felt { } /// Converts to big-endian bit representation. - pub const fn to_bits_be(&self) -> BitArray { - todo!() + pub fn to_bits_be(&self) -> BitArray { + let mut limbs = self.0.representative().limbs; + limbs.reverse(); + BitArray::new(limbs) } /// Converts to little-endian bit representation. From d441085344171ab29d7171d762b65e40304167dc Mon Sep 17 00:00:00 2001 From: Federica Date: Thu, 29 Jun 2023 12:52:03 -0300 Subject: [PATCH 19/97] Clippy --- crates/stark-felt/src/lib.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 146ef98..49ace09 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -64,14 +64,14 @@ impl Felt { /// Creates a new [Felt] from its big-endian representation in a [u8] slice. pub fn from_bytes_be(bytes: &[u8]) -> Result { FieldElement::from_bytes_be(bytes) - .map(|x| Self(x)) + .map(Self) .map_err(|_| FromBytesError) } /// Creates a new [Felt] from its little-endian representation in a [u8] slice. pub fn from_bytes_le(bytes: &[u8]) -> Result { FieldElement::from_bytes_le(bytes) - .map(|x| Self(x)) + .map(Self) .map_err(|_| FromBytesError) } @@ -105,12 +105,12 @@ impl Felt { // Question: What is the difference between field_div & floor_div? /// Finite field division. pub fn field_div(&self, rhs: &NonZeroFelt) -> Self { - Self(&self.0 / &rhs.0) + Self(self.0 / rhs.0) } /// Floor division. pub fn floor_div(&self, rhs: &NonZeroFelt) -> Self { - Self(&self.0 / &rhs.0) + Self(self.0 / rhs.0) } /// Multiplicative inverse. @@ -161,7 +161,7 @@ impl Default for Felt { impl AsRef for Felt { fn as_ref(&self) -> &Felt { - &self + self } } @@ -179,7 +179,7 @@ impl From<&NonZeroFelt> for Felt { impl AsRef for NonZeroFelt { fn as_ref(&self) -> &NonZeroFelt { - &self + self } } From 34c11c79c3764c422f01eab578bc67120960f4a0 Mon Sep 17 00:00:00 2001 From: Federica Date: Thu, 29 Jun 2023 13:01:37 -0300 Subject: [PATCH 20/97] Simplify sqrt --- crates/stark-felt/src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 49ace09..ca5a624 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -121,8 +121,7 @@ impl Felt { /// Finds the square root. There may be 2 roots for each square, and the lower one is returned. pub fn sqrt(&self) -> Option { let (root_1, root_2) = self.0.sqrt()?; - let value = FieldElement::new(root_1.representative().min(root_2.representative())); - Some(Self(value)) + Some(Self(if root_1 < root_2 { root_1 } else { root_2 })) } /// Raises `self` to the power of 2. From 5020bb8539d31910ff1e546decde1058fb6193d8 Mon Sep 17 00:00:00 2001 From: Federica Date: Thu, 29 Jun 2023 13:02:56 -0300 Subject: [PATCH 21/97] Remove comment --- crates/stark-felt/src/lib.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index ca5a624..4e65ad0 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -135,12 +135,8 @@ impl Felt { } // Question: Is mul_mod necessary in this crate? - // Isn't multiplication mod CAIRO_PRIME more useful? - // Possible bug: If one wanted to do multiplication modulo CAIRO_PRIME this method would be useless as Felt(CAIRO_PRIME) = 0 - // CHANGE: removed p argument from mul_mod -> doing modulo cairo prime is more useful for the crate - // Suggestion: leave only mul for multiplication operation within the field and then discuss if mul_mod a different prime is needed and if implementing mod would't be a better solution in that case /// Modular multiplication. - pub fn mul_mod(&self, rhs: &Self) -> Self { + pub fn mul_mod(&self, rhs: &Self, _p: &Self) -> Self { Self(self.0.mul(rhs.0)) } From 25a35dfaa9e399034810adedb8b95a2748c001b8 Mon Sep 17 00:00:00 2001 From: Federica Date: Thu, 29 Jun 2023 13:04:27 -0300 Subject: [PATCH 22/97] Simplify is_zero --- crates/stark-felt/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 4e65ad0..b216b06 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -99,7 +99,7 @@ impl Felt { /// Checks if `self` is equal to [Felt::Zero]. pub fn is_zero(&self) -> bool { - self.0 == FieldElement::from_raw(&Stark252PrimeField::ZERO) + self.0 == FieldElement::::zero() } // Question: What is the difference between field_div & floor_div? From 3419d8bcbc0937538164fda5aae3909d0095ba28 Mon Sep 17 00:00:00 2001 From: Federica Date: Thu, 29 Jun 2023 13:58:21 -0300 Subject: [PATCH 23/97] Add split for not(target_pointer_width = "64") --- crates/stark-felt/src/lib.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index b216b06..8a64d56 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -89,12 +89,21 @@ impl Felt { pub fn to_bits_be(&self) -> BitArray { let mut limbs = self.0.representative().limbs; limbs.reverse(); + + #[cfg(not(target_pointer_width = "64"))] + let limbs = limbs.iter().map(|n| [n >> 32 as u32, n as u32]).collect(); + BitArray::new(limbs) } /// Converts to little-endian bit representation. pub fn to_bits_le(&self) -> BitArray { - BitArray::new(self.0.representative().limbs) + let limbs = self.0.representative().limbs; + + #[cfg(not(target_pointer_width = "64"))] + let limbs = limbs.iter().map(|n| [n as u32, n >> 32 as u32]).collect(); + + BitArray::new(limbs) } /// Checks if `self` is equal to [Felt::Zero]. From 74fbbb630b88e37f1894f912b5eea3d1dd939f8b Mon Sep 17 00:00:00 2001 From: Federica Date: Thu, 29 Jun 2023 14:17:45 -0300 Subject: [PATCH 24/97] Fix array handling --- crates/stark-felt/src/lib.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 8a64d56..0794674 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -91,7 +91,13 @@ impl Felt { limbs.reverse(); #[cfg(not(target_pointer_width = "64"))] - let limbs = limbs.iter().map(|n| [n >> 32 as u32, n as u32]).collect(); + let limbs: [u32; 8] = limbs + .map(|n| [(n >> 32) as u32, n as u32]) + .into_iter() + .flatten() + .collect::>() + .try_into() + .unwrap(); BitArray::new(limbs) } @@ -101,7 +107,13 @@ impl Felt { let limbs = self.0.representative().limbs; #[cfg(not(target_pointer_width = "64"))] - let limbs = limbs.iter().map(|n| [n as u32, n >> 32 as u32]).collect(); + let limbs: [u32; 8] = limbs + .map(|n| [n as u32, n >> 32 as u32]) + .into_iter() + .flatten() + .collect::>() + .try_into() + .unwrap(); BitArray::new(limbs) } From b669c3a532ebf13b5175ed4cf5d2574774312d65 Mon Sep 17 00:00:00 2001 From: Federica Date: Thu, 29 Jun 2023 16:00:13 -0300 Subject: [PATCH 25/97] Remove comment & wrong impl --- crates/stark-felt/src/lib.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 0794674..5f9e06c 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -122,16 +122,14 @@ impl Felt { pub fn is_zero(&self) -> bool { self.0 == FieldElement::::zero() } - - // Question: What is the difference between field_div & floor_div? /// Finite field division. pub fn field_div(&self, rhs: &NonZeroFelt) -> Self { Self(self.0 / rhs.0) } /// Floor division. - pub fn floor_div(&self, rhs: &NonZeroFelt) -> Self { - Self(self.0 / rhs.0) + pub fn floor_div(&self, _rhs: &NonZeroFelt) -> Self { + todo!() } /// Multiplicative inverse. From a1a7c6278edd9b559f7fde10874e8237c8a06d23 Mon Sep 17 00:00:00 2001 From: Federica Date: Thu, 29 Jun 2023 16:07:06 -0300 Subject: [PATCH 26/97] Fix wrong impl --- crates/stark-felt/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 5f9e06c..eea1fb1 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -202,9 +202,9 @@ impl TryFrom for NonZeroFelt { fn try_from(value: Felt) -> Result { if value.is_zero() { - Ok(Self(value.0)) - } else { Err(FeltIsZeroError) + } else { + Ok(Self(value.0)) } } } @@ -214,9 +214,9 @@ impl TryFrom<&Felt> for NonZeroFelt { fn try_from(value: &Felt) -> Result { if value.is_zero() { - Ok(Self(value.0)) - } else { Err(FeltIsZeroError) + } else { + Ok(Self(value.0)) } } } From 6149f1239f8753cd158c2b53beac6b575d024981 Mon Sep 17 00:00:00 2001 From: Federica Date: Thu, 29 Jun 2023 16:30:26 -0300 Subject: [PATCH 27/97] Remove wrong impls --- crates/stark-felt/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index eea1fb1..0acd1ab 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -446,22 +446,22 @@ mod formatting { /// Represents [Felt] in decimal by default. impl fmt::Display for Felt { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(&self, f) + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + todo!() } } /// Represents [Felt] in lowercase hexadecimal format. impl fmt::LowerHex for Felt { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::LowerHex::fmt(&self, f) + fmt::Display::fmt(&self.0, f) } } /// Represents [Felt] in uppercase hexadecimal format. impl fmt::UpperHex for Felt { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::UpperHex::fmt(&self, f) + todo!() } } } From cd961ad3b9a4134888fd077bede8deed571a55dd Mon Sep 17 00:00:00 2001 From: Federica Date: Thu, 29 Jun 2023 16:41:47 -0300 Subject: [PATCH 28/97] Add deserialization from hex string --- crates/stark-felt/src/lib.rs | 38 ++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 0acd1ab..d68b3ba 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -410,16 +410,14 @@ mod arithmetic { } } -// Serialization & Deserialization differs between projects and objectives -// For example: In cairo 0 programs, instructions are Felts in hexadecimal format, but constants are Felts in decimal value -// It doesn't make much sense to have a universal serialization #[cfg(feature = "serde")] mod serde { - use ::serde::{Deserialize, Serialize}; + use core::fmt; + + use ::serde::{de, Deserialize, Serialize}; use super::*; - // Serialization to decimal value impl Serialize for Felt { fn serialize(&self, serializer: S) -> Result where @@ -430,11 +428,35 @@ mod serde { } impl<'de> Deserialize<'de> for Felt { - fn deserialize(_deserializer: D) -> Result + fn deserialize(deserializer: D) -> Result where D: ::serde::Deserializer<'de>, { - todo!() + deserializer.deserialize_str(FeltVisitor) + } + } + + struct FeltVisitor; + + impl<'de> de::Visitor<'de> for FeltVisitor { + type Value = Felt; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Failed to deserialize hexadecimal string") + } + + fn visit_str(self, value: &str) -> Result + where + E: de::Error, + { + // Strip the '0x' prefix from the encoded hex string + if let Some(no_prefix_hex) = value.strip_prefix("0x") { + Ok(Felt(FieldElement::::const_from_raw( + UnsignedInteger::from(no_prefix_hex), + ))) + } else { + Err(String::from("Extected hex string to be prefixed by '0x'")).map_err(de::Error::custom) + } } } } @@ -460,7 +482,7 @@ mod formatting { /// Represents [Felt] in uppercase hexadecimal format. impl fmt::UpperHex for Felt { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { todo!() } } From f6c116b01228d3a6e45d0caba15ccfcff798eb54 Mon Sep 17 00:00:00 2001 From: Federica Date: Thu, 29 Jun 2023 16:54:14 -0300 Subject: [PATCH 29/97] Implement UpperHex fmt --- crates/stark-felt/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index d68b3ba..f865fa8 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -482,8 +482,8 @@ mod formatting { /// Represents [Felt] in uppercase hexadecimal format. impl fmt::UpperHex for Felt { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - todo!() + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0.to_string().to_uppercase()) } } } From 537f483d542c57e5baef3ff204e51095c5b2b3ab Mon Sep 17 00:00:00 2001 From: Federica Date: Fri, 30 Jun 2023 10:56:16 -0300 Subject: [PATCH 30/97] Remove comments --- crates/stark-felt/src/lib.rs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index f865fa8..9be5293 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -1,7 +1,5 @@ #![cfg_attr(not(feature = "std"), no_std)] -use core::ops::Mul; - use bitvec::array::BitArray; #[cfg(target_pointer_width = "64")] @@ -60,7 +58,6 @@ impl Felt { UnsignedInteger::from_limbs([544, 0, 0, 32]), )); - // TODO: const was removed from all methods, check if this is ok/ if we can make these const in lambdaworks /// Creates a new [Felt] from its big-endian representation in a [u8] slice. pub fn from_bytes_be(bytes: &[u8]) -> Result { FieldElement::from_bytes_be(bytes) @@ -153,13 +150,11 @@ impl Felt { Self(self.0.pow(exponent)) } - // Question: Is mul_mod necessary in this crate? /// Modular multiplication. - pub fn mul_mod(&self, rhs: &Self, _p: &Self) -> Self { - Self(self.0.mul(rhs.0)) + pub fn mul_mod(&self, _rhs: &Self, _p: &Self) -> Self { + todo!() } - // Question: Why is this method needed? /// Modular multiplicative inverse. pub const fn inverse_mod(&self, _p: &Self) -> Self { todo!() @@ -395,8 +390,6 @@ mod arithmetic { } } - // Are these two impls needed? - impl iter::Sum for Felt { fn sum>(iter: I) -> Self { iter.sum() @@ -455,7 +448,8 @@ mod serde { UnsignedInteger::from(no_prefix_hex), ))) } else { - Err(String::from("Extected hex string to be prefixed by '0x'")).map_err(de::Error::custom) + Err(String::from("Extected hex string to be prefixed by '0x'")) + .map_err(de::Error::custom) } } } From d48cbb19596fa5866ec78b677dca0daefd3c446d Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 3 Jul 2023 10:40:46 -0300 Subject: [PATCH 31/97] Implement `mul_mod` & `inverse_mod` --- crates/stark-felt/src/lib.rs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 9be5293..07f2920 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -151,13 +151,24 @@ impl Felt { } /// Modular multiplication. - pub fn mul_mod(&self, _rhs: &Self, _p: &Self) -> Self { - todo!() + pub fn mul_mod(&self, rhs: &Self, p: &Self) -> Self { + Self(FieldElement::const_from_raw( + (self.0 * rhs.0) + .representative() + .div_rem(&p.0.representative()) + .1, + )) } /// Modular multiplicative inverse. - pub const fn inverse_mod(&self, _p: &Self) -> Self { - todo!() + pub fn inverse_mod(&self, p: &Self) -> Self { + Self(FieldElement::const_from_raw( + self.0 + .inv() + .representative() + .div_rem(&p.0.representative()) + .1, + )) } } From 2695f68e2627514136d86d3a42465bedeeeb06a0 Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 3 Jul 2023 10:44:31 -0300 Subject: [PATCH 32/97] Implement floor_div --- crates/stark-felt/src/lib.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 07f2920..f28ab2e 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -125,8 +125,10 @@ impl Felt { } /// Floor division. - pub fn floor_div(&self, _rhs: &NonZeroFelt) -> Self { - todo!() + pub fn floor_div(&self, rhs: &NonZeroFelt) -> Self { + Self(FieldElement::const_from_raw( + (self.0.representative().div_rem(&rhs.0.representative())).0, + )) } /// Multiplicative inverse. From 63a63479f1feb8cddf7c06dfe7bf7e1f8347ec0e Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 3 Jul 2023 16:02:38 -0300 Subject: [PATCH 33/97] Fix constants --- crates/stark-felt/src/lib.rs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index f28ab2e..8c77f67 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -39,19 +39,13 @@ impl Felt { )); /// [Felt] constant that's equal to 1. - pub const ONE: Self = Self(FieldElement::::const_from_raw( - UnsignedInteger::from_u64(1), - )); + pub const ONE: Self = Self(FieldElement::::from_hex_unchecked("1")); /// [Felt] constant that's equal to 2. - pub const TWO: Self = Self(FieldElement::::const_from_raw( - UnsignedInteger::from_u64(2), - )); + pub const TWO: Self = Self(FieldElement::::from_hex_unchecked("2")); /// [Felt] constant that's equal to 3. - pub const THREE: Self = Self(FieldElement::::const_from_raw( - UnsignedInteger::from_u64(3), - )); + pub const THREE: Self = Self(FieldElement::::from_hex_unchecked("3")); /// Maximum value of [Felt]. Equals to 2^251 + 17 * 2^192. pub const MAX: Self = Self(FieldElement::::const_from_raw( From 0a3a0b7fe2dfbd1d5d96f563bb57394797d5857e Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 3 Jul 2023 16:35:06 -0300 Subject: [PATCH 34/97] Add proptests --- crates/stark-felt/src/lib.rs | 54 ++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 8c77f67..f1092d5 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -2,6 +2,9 @@ use bitvec::array::BitArray; +#[cfg(test)] +mod arbitrary; + #[cfg(target_pointer_width = "64")] pub type BitArrayStore = [u64; 4]; @@ -521,3 +524,54 @@ mod errors { } } } + +#[cfg(test)] +mod test { + use super::*; + + use proptest::prelude::*; + + proptest! { + #[test] + // Property-based test that ensures, for 100 felt values that are randomly generated + // each time tests are run, that a new felt doesn't fall outside the range [0, p]. + // In this and some of the following tests, The value of {x} can be either [0] or a + // very large number, in order to try to overflow the value of {p} and thus ensure the + // modular arithmetic is working correctly. + fn new_in_range(ref x in any::<[u8; 40]>()) { + let x = Felt::from_bytes_be(x).unwrap(); + prop_assert!(x < Felt::MAX); + } + + #[test] + fn to_be_bytes(ref x in any::()) { + let bytes = x.to_bytes_be(); + let y = &Felt::from_bytes_be(&bytes).unwrap(); + prop_assert_eq!(x, y); + } + + #[test] + fn to_le_bytes(ref x in any::()) { + let bytes = x.to_bytes_le(); + let y = &Felt::from_bytes_le(&bytes).unwrap(); + prop_assert_eq!(x, y); + } + + #[test] + fn to_bits_be(ref x in any::()) { + let bits: Vec = x.to_bits_be().into_iter().rev().collect(); + let mut res = [0;32]; + let mut acc: u8 = 0; + for (i, bits64) in bits.chunks(8).enumerate() { + for bit in bits64.iter() { + acc <<= 1; + acc += *bit as u8; + } + res[i] = acc; + acc = 0; + } + let y = &Felt::from_bytes_be(&res).unwrap(); + prop_assert_eq!(x, y); + } + } +} From 2a2a6536e67c3d8aaa1eaa664db8353a0acd2ff3 Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 3 Jul 2023 17:28:00 -0300 Subject: [PATCH 35/97] Add proptest --- crates/stark-felt/src/lib.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index f1092d5..439c90f 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -573,5 +573,29 @@ mod test { let y = &Felt::from_bytes_be(&res).unwrap(); prop_assert_eq!(x, y); } + + #[test] + fn to_bits_le(ref x in any::()) { + let bits: Vec = x.to_bits_le().into_iter().collect(); + let mut res = [0;4]; + let mut acc: u64 = 0; + for (i, bits64) in bits.chunks(64).enumerate() { + for bit in bits64.iter().rev() { + acc <<= 1; + acc += *bit as u64; + } + res[i] = acc; + acc = 0; + } + let mut bytes = [0u8; 32]; + for i in (0..4).rev() { + let limb_bytes = res[i].to_le_bytes(); + for j in 0..8 { + bytes[(3 - i) * 8 + j] = limb_bytes[j] + } + } + let y = &Felt::from_bytes_le(&bytes).unwrap(); + prop_assert_eq!(x, y); + } } } From 7f2bd3aa34c9f3477dda7e28d1bb07a3e0bc189c Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 3 Jul 2023 18:25:35 -0300 Subject: [PATCH 36/97] Remove wrong usage of from_raw --- crates/stark-felt/src/lib.rs | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 439c90f..a75747d 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -83,7 +83,6 @@ impl Felt { pub fn to_bits_be(&self) -> BitArray { let mut limbs = self.0.representative().limbs; limbs.reverse(); - #[cfg(not(target_pointer_width = "64"))] let limbs: [u32; 8] = limbs .map(|n| [(n >> 32) as u32, n as u32]) @@ -123,9 +122,12 @@ impl Felt { /// Floor division. pub fn floor_div(&self, rhs: &NonZeroFelt) -> Self { - Self(FieldElement::const_from_raw( - (self.0.representative().div_rem(&rhs.0.representative())).0, - )) + Self::from_bytes_be( + &(self.0.representative().div_rem(&rhs.0.representative())) + .0 + .to_bytes_be(), + ) + .unwrap_or_default() } /// Multiplicative inverse. @@ -151,23 +153,28 @@ impl Felt { /// Modular multiplication. pub fn mul_mod(&self, rhs: &Self, p: &Self) -> Self { - Self(FieldElement::const_from_raw( - (self.0 * rhs.0) + Self::from_bytes_be( + &(self.0 * rhs.0) .representative() .div_rem(&p.0.representative()) - .1, - )) + .1 + .to_bytes_be(), + ) + .unwrap_or_default() } /// Modular multiplicative inverse. pub fn inverse_mod(&self, p: &Self) -> Self { - Self(FieldElement::const_from_raw( - self.0 + Self::from_bytes_be( + &self + .0 .inv() .representative() .div_rem(&p.0.representative()) - .1, - )) + .1 + .to_bytes_be(), + ) + .unwrap_or_default() } } From ec76d879a875c91cd86fb5f6685f4d94669c8b07 Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 3 Jul 2023 18:53:26 -0300 Subject: [PATCH 37/97] Add proptest --- crates/stark-felt/src/lib.rs | 126 +++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index a75747d..7ed5ebc 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -534,6 +534,8 @@ mod errors { #[cfg(test)] mod test { + use crate::arbitrary::nonzero_felt; + use super::*; use proptest::prelude::*; @@ -604,5 +606,129 @@ mod test { let y = &Felt::from_bytes_le(&bytes).unwrap(); prop_assert_eq!(x, y); } + + #[test] + // Property-based test that ensures, for 100 felt values that are randomly + // generated each time tests are run, that a felt created using Felt252::from_bytes_be doesn't + // fall outside the range [0, p]. + // In this and some of the following tests, The value of {x} can be either [0] or a very large number, + // in order to try to overflow the value of {p} and thus ensure the modular arithmetic is working correctly. + fn from_bytes_be_in_range(ref x in any::<[u8; 40]>()) { + let x = Felt::from_bytes_be(x).unwrap(); + prop_assert!(x <= Felt::MAX); + } + + #[test] + // Property-based test that ensures, for 100 felt values that are randomly generated each time + // tests are run, that the negative of a felt doesn't fall outside the range [0, p]. + fn neg_in_range(x in any::()) { + prop_assert!(-x <= Felt::MAX); + } + + #[test] + // Property-based test that ensures, for 100 {x} and {y} values that are randomly generated + // each time tests are run, that a subtraction between two felts {x} and {y} and doesn't fall + // outside the range [0, p]. The values of {x} and {y} can be either [0] or a very large number. + fn sub(ref x in any::(), ref y in any::()) { + // x - y + prop_assert!(x - y <= Felt::MAX); + prop_assert_eq!(Felt::MAX + x - y + Felt::ONE, x - y); + // y - x + prop_assert!(y - x <= Felt::MAX); + prop_assert_eq!(Felt::MAX + y - x + Felt::ONE, y - x); + } + + #[test] + // Property-based test that ensures, for 100 {x} and {y} values that are randomly generated + // each time tests are run, that a subtraction with assignment between two felts {x} and {y} + // and doesn't fall outside the range [0, p]. The values of {x} and {y} can be either [0] or a very large number. + fn sub_assign_in_range(mut x in any::(), y in any::()) { + x -= y; + prop_assert!(x <= Felt::MAX); + // test reference variant + x -= &y; + prop_assert!(x <= Felt::MAX); + } + + #[test] + // Property-based test that ensures, for 100 {x} and {y} values that are randomly + // generated each time tests are run, that a multiplication between two felts {x} + // and {y} and doesn't fall outside the range [0, p]. The values of {x} and {y} + // can be either [0] or a very large number. + fn mul(ref x in any::(), ref y in any::()) { + prop_assert_eq!(x * y, y * x); + prop_assert!(x * y <= Felt::MAX); + } + + #[test] + // Property-based test that ensures, for 100 pairs of {x} and {y} values that + // are randomly generated each time tests are run, that a multiplication with + // assignment between two felts {x} and {y} and doesn't fall outside the range [0, p]. + // The values of {x} and {y} can be either [0] or a very large number. + fn mul_assign_in_range(mut x in any::(), y in any::()) { + x *= y; + prop_assert!(x <= Felt::MAX); + // test reference variant + x *= &y; + prop_assert!(x <= Felt::MAX); + } + + #[test] + // Property-based test that ensures, for 100 pairs of {x} and {y} values that are + // randomly generated each time tests are run, that the result of the division of + // {x} by {y} is the inverse multiplicative of {x} --that is, multiplying the result + // by {y} returns the original number {x}. The values of {x} and {y} can be either + // [0] or a very large number. + fn field_div_is_mul_inv(x in any::(), y in nonzero_felt()) { + let q = x.field_div(&NonZeroFelt(y.0)); + prop_assert!(q <= Felt::MAX); + prop_assert_eq!(q * y, x); + } + + #[test] + // Property-based test that ensures, for 100 values {x} that are randomly + // generated each time tests are run, that raising {x} to the {y}th power + // returns a result that is inside of the range [0, p]. + fn pow_in_range(base in any::(), exp in 0..u128::MAX){ + prop_assert!(base.pow(exp) <= Felt::MAX); + } + + #[test] + // Property based test that ensures, for 100 pairs of values {x} and {y} + // generated at random each time tests are run, that performing an Add operation + // between them returns a result that is inside of the range [0, p]. + fn add_in_range(x in any::(), y in any::()){ + prop_assert!(x + y <= Felt::MAX); + } + + /// Tests the additive identity of the implementation of Zero trait for felts + /// + /// ```{.text} + /// x + 0 = x ∀ x + /// 0 + x = x ∀ x + /// ``` + #[test] + fn zero_additive_identity(x in any::()) { + prop_assert_eq!(x, x + Felt::ZERO); + prop_assert_eq!(x, Felt::ZERO + x); + } + + /// Tests the multiplicative identity of the implementation of One trait for felts + /// + /// ```{.text} + /// x * 1 = x ∀ x + /// 1 * x = x ∀ x + /// ``` + #[test] + fn one_multiplicative_identity(x in any::()) { + prop_assert_eq!(x, x * Felt::ONE); + prop_assert_eq!(x, Felt::ONE * x); + } + + #[test] + fn sqrt_in_range(x in any::()) { + // we use x = x' * x' so x has a square root + prop_assert!((x * x).sqrt().unwrap() <= Felt::MAX); + } } } From 59c18379b56c866aff5d470482a4826a0c8bcd0e Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 3 Jul 2023 18:59:24 -0300 Subject: [PATCH 38/97] Add proptest --- crates/stark-felt/src/lib.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 7ed5ebc..0f4482f 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -730,5 +730,28 @@ mod test { // we use x = x' * x' so x has a square root prop_assert!((x * x).sqrt().unwrap() <= Felt::MAX); } + + #[test] + fn sqrt_is_inv_square(x in any::()) { + // we use x = x' * x' so x has a square root + let sqrt = (x * x).sqrt().unwrap(); + prop_assert!( sqrt == x || -sqrt == x) + } + + #[test] + fn square_in_range(x in any::()) { + prop_assert!(x.square() <= Felt::MAX); + } + + #[test] + fn square_x_is_x_mul_x(x in any::()) { + prop_assert_eq!(x.square(), x * x); + } + + #[test] + fn square_is_inv_sqrt(x in any::()) { + let sqrt = x.square().sqrt().unwrap(); + prop_assert!( sqrt == x || -sqrt == x) + } } } From 7c0a77acac72eb1ac9c90c2c6b724e7f76192e67 Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 4 Jul 2023 10:23:27 -0300 Subject: [PATCH 39/97] Fix deserialization --- crates/stark-felt/src/lib.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 0f4482f..df62055 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -460,14 +460,12 @@ mod serde { E: de::Error, { // Strip the '0x' prefix from the encoded hex string - if let Some(no_prefix_hex) = value.strip_prefix("0x") { - Ok(Felt(FieldElement::::const_from_raw( - UnsignedInteger::from(no_prefix_hex), - ))) - } else { - Err(String::from("Extected hex string to be prefixed by '0x'")) - .map_err(de::Error::custom) - } + value + .strip_prefix("0x") + .and_then(|v| FieldElement::::from_hex(v).ok()) + .map(Felt) + .ok_or(String::from("Extected hex string to be prefixed by '0x'")) + .map_err(de::Error::custom) } } } From d9c51f53c5b5fc5f51c8517ec200dd4066ed721c Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 4 Jul 2023 10:43:01 -0300 Subject: [PATCH 40/97] Add tests for basic constants --- crates/stark-felt/src/lib.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index df62055..a7cb51a 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -752,4 +752,25 @@ mod test { prop_assert!( sqrt == x || -sqrt == x) } } + + #[test] + fn constant_one() { + let mut one_bytes = 1_u64.to_le_bytes().to_vec(); + one_bytes.extend_from_slice(&[0; 24]); + assert_eq!(Felt::ONE.to_bytes_le().to_vec(), one_bytes); + } + + #[test] + fn constant_two() { + let mut two_bytes = 2_u64.to_le_bytes().to_vec(); + two_bytes.extend_from_slice(&[0; 24]); + assert_eq!(Felt::TWO.to_bytes_le().to_vec(), two_bytes); + } + + #[test] + fn constant_three() { + let mut three_bytes = 3_u64.to_le_bytes().to_vec(); + three_bytes.extend_from_slice(&[0; 24]); + assert_eq!(Felt::THREE.to_bytes_le().to_vec(), three_bytes); + } } From d81c0ae60cb9051ed32512d6ad6150284c7a22cc Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 4 Jul 2023 10:51:12 -0300 Subject: [PATCH 41/97] Add test for max constant --- crates/stark-felt/src/lib.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index a7cb51a..44fa6cb 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -773,4 +773,10 @@ mod test { three_bytes.extend_from_slice(&[0; 24]); assert_eq!(Felt::THREE.to_bytes_le().to_vec(), three_bytes); } + + #[test] + fn constant_max() { + let max_bytes = [8, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; //3618502788666131213697322783095070105623107215331596699973092056135872020481 + assert_eq!(Felt::MAX.to_bytes_be(), max_bytes); + } } From 8188168079945b41699f1ad76a979143027f88c6 Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 4 Jul 2023 10:52:08 -0300 Subject: [PATCH 42/97] Add test for zero constant --- crates/stark-felt/src/lib.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 44fa6cb..ccee122 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -753,6 +753,13 @@ mod test { } } + #[test] + fn constant_zero() { + let mut zero_bytes = 0_u64.to_le_bytes().to_vec(); + zero_bytes.extend_from_slice(&[0; 24]); + assert_eq!(Felt::ZERO.to_bytes_le().to_vec(), zero_bytes); + } + #[test] fn constant_one() { let mut one_bytes = 1_u64.to_le_bytes().to_vec(); From d192fff52cf70dc6b30c9d43abd33159c6ba987e Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 4 Jul 2023 10:58:09 -0300 Subject: [PATCH 43/97] Test is_zero --- crates/stark-felt/src/lib.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index ccee122..193a36a 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -113,7 +113,7 @@ impl Felt { /// Checks if `self` is equal to [Felt::Zero]. pub fn is_zero(&self) -> bool { - self.0 == FieldElement::::zero() + *self == Felt::ZERO } /// Finite field division. pub fn field_div(&self, rhs: &NonZeroFelt) -> Self { @@ -546,8 +546,10 @@ mod test { // very large number, in order to try to overflow the value of {p} and thus ensure the // modular arithmetic is working correctly. fn new_in_range(ref x in any::<[u8; 40]>()) { - let x = Felt::from_bytes_be(x).unwrap(); - prop_assert!(x < Felt::MAX); + let x_be = Felt::from_bytes_be(x).unwrap(); + prop_assert!(x_be < Felt::MAX); + let x_le = Felt::from_bytes_le(x).unwrap(); + prop_assert!(x_le < Felt::MAX); } #[test] @@ -751,6 +753,11 @@ mod test { let sqrt = x.square().sqrt().unwrap(); prop_assert!( sqrt == x || -sqrt == x) } + + #[test] + fn non_zero_is_not_zero(x in nonzero_felt()) { + prop_assert!(!x.is_zero()) + } } #[test] @@ -786,4 +793,9 @@ mod test { let max_bytes = [8, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; //3618502788666131213697322783095070105623107215331596699973092056135872020481 assert_eq!(Felt::MAX.to_bytes_be(), max_bytes); } + + #[test] + fn zero_is_zero() { + assert!(Felt::ZERO.is_zero()); + } } From c4f4790b11ce2e03088cdce855a858443a5de68f Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 4 Jul 2023 11:07:32 -0300 Subject: [PATCH 44/97] Add more proptests --- crates/stark-felt/src/lib.rs | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 193a36a..5d3c96d 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -758,6 +758,23 @@ mod test { fn non_zero_is_not_zero(x in nonzero_felt()) { prop_assert!(!x.is_zero()) } + + #[test] + fn multiplying_by_inverse_yields_multiplicative_neutral(x in nonzero_felt()) { + prop_assert_eq!(x * x.inverse().unwrap(), Felt::ONE ) + } + + #[test] + fn inverse_mod_in_range(x in any::(), p in any::()) { + prop_assert!(x.inverse_mod(&p) <= Felt::MAX); + prop_assert!(x.inverse_mod(&p) < p); + } + + #[test] + fn mul_mod_in_range(x in any::(), y in any::(), p in any::()) { + prop_assert!(x.mul_mod(&y, &p) <= Felt::MAX); + prop_assert!(x.mul_mod(&y, &p) < p); + } } #[test] @@ -790,7 +807,10 @@ mod test { #[test] fn constant_max() { - let max_bytes = [8, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; //3618502788666131213697322783095070105623107215331596699973092056135872020481 + let max_bytes = [ + 8, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, + ]; assert_eq!(Felt::MAX.to_bytes_be(), max_bytes); } From 02242f47f078224b1709d5a9b277020d3ffc8cc9 Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 4 Jul 2023 14:38:08 -0300 Subject: [PATCH 45/97] Fix serialization & deserialization --- crates/stark-felt/src/lib.rs | 58 +++++++++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 4 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 5d3c96d..c873b96 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -83,6 +83,7 @@ impl Felt { pub fn to_bits_be(&self) -> BitArray { let mut limbs = self.0.representative().limbs; limbs.reverse(); + #[cfg(not(target_pointer_width = "64"))] let limbs: [u32; 8] = limbs .map(|n| [(n >> 32) as u32, n as u32]) @@ -409,13 +410,13 @@ mod arithmetic { impl iter::Sum for Felt { fn sum>(iter: I) -> Self { - iter.sum() + iter.fold(Self::ZERO, |augend, addend| augend + addend) } } impl<'a> iter::Sum<&'a Felt> for Felt { fn sum>(iter: I) -> Self { - iter.sum() + iter.fold(Self::ZERO, |augend, addend| augend + addend) } } } @@ -433,7 +434,7 @@ mod serde { where S: ::serde::Serializer, { - serializer.serialize_str(&self.to_string()) + serializer.serialize_str(&format!("{:x}", self)) } } @@ -464,7 +465,7 @@ mod serde { .strip_prefix("0x") .and_then(|v| FieldElement::::from_hex(v).ok()) .map(Felt) - .ok_or(String::from("Extected hex string to be prefixed by '0x'")) + .ok_or(String::from("Expected hex string to be prefixed by '0x'")) .map_err(de::Error::custom) } } @@ -537,6 +538,7 @@ mod test { use super::*; use proptest::prelude::*; + use serde_test::{assert_de_tokens, assert_ser_tokens, Token}; proptest! { #[test] @@ -775,6 +777,18 @@ mod test { prop_assert!(x.mul_mod(&y, &p) <= Felt::MAX); prop_assert!(x.mul_mod(&y, &p) < p); } + + #[test] + fn non_zero_felt_new_is_ok_when_not_zero(x in nonzero_felt()) { + prop_assert!(NonZeroFelt::try_from(x).is_ok()); + prop_assert_eq!(NonZeroFelt::try_from(x).unwrap().0, x.0); + } + + #[test] + fn iter_sum(a in any::(), b in any::(), c in any::()) { + prop_assert_eq!([a, b, c].iter().sum::(), a + b + c); + prop_assert_eq!([a, b, c].iter().map(Clone::clone).sum::(), a + b + c); + } } #[test] @@ -818,4 +832,40 @@ mod test { fn zero_is_zero() { assert!(Felt::ZERO.is_zero()); } + + #[test] + fn non_zero_felt_from_zero_should_fail() { + assert!(NonZeroFelt::try_from(Felt::ZERO).is_err()); + } + + #[test] + fn default_is_zero() { + assert!(Felt::default().is_zero()); + } + + #[test] + fn deserialize() { + assert_de_tokens(&Felt::ZERO, &[Token::String("0x0")]); + assert_de_tokens(&Felt::TWO, &[Token::String("0x2")]); + assert_de_tokens(&Felt::THREE, &[Token::String("0x3")]); + assert_de_tokens( + &Felt::MAX, + &[Token::String( + "0x800000000000011000000000000000000000000000000000000000000000000", + )], + ); + } + + #[test] + fn serialize() { + assert_ser_tokens(&Felt::ZERO, &[Token::String("0x0")]); + assert_ser_tokens(&Felt::TWO, &[Token::String("0x2")]); + assert_ser_tokens(&Felt::THREE, &[Token::String("0x3")]); + assert_ser_tokens( + &Felt::MAX, + &[Token::String( + "0x800000000000011000000000000000000000000000000000000000000000000", + )], + ); + } } From 9ee8b6f68aca7c82e7faa6a733bc1ab8bc3faada Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 4 Jul 2023 15:03:03 -0300 Subject: [PATCH 46/97] Test hexadecimal display --- crates/stark-felt/src/lib.rs | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index c873b96..2094659 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -493,7 +493,15 @@ mod formatting { /// Represents [Felt] in uppercase hexadecimal format. impl fmt::UpperHex for Felt { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.0.to_string().to_uppercase()) + write!( + f, + "0x{}", + self.0 + .to_string() + .strip_prefix("0x") + .unwrap() + .to_uppercase() + ) } } } @@ -868,4 +876,26 @@ mod test { )], ); } + + #[test] + fn display_lower_hex() { + assert_eq!(format!("{:#x}", Felt::ZERO), format!("{:#x}", 0_u64)); + assert_eq!(format!("{:#x}", Felt::TWO), format!("{:#x}", 2_u64)); + assert_eq!(format!("{:#x}", Felt::THREE), format!("{:#x}", 3_u64)); + assert_eq!( + format!("{:#x}", Felt::MAX), + String::from("0x800000000000011000000000000000000000000000000000000000000000000") + ); + } + + #[test] + fn display_upper_hex() { + assert_eq!(format!("{:#X}", Felt::ZERO), format!("{:#x}", 0_u64)); + assert_eq!(format!("{:#X}", Felt::TWO), format!("{:#x}", 2_u64)); + assert_eq!(format!("{:#X}", Felt::THREE), format!("{:#x}", 3_u64)); + assert_eq!( + format!("{:#X}", Felt::MAX), + String::from("0x800000000000011000000000000000000000000000000000000000000000000") + ); + } } From a863f4e6c156d81c58b176cd0803fca02ecc0225 Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 4 Jul 2023 15:06:01 -0300 Subject: [PATCH 47/97] Improve tests --- crates/stark-felt/src/lib.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 2094659..bf97d15 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -882,6 +882,7 @@ mod test { assert_eq!(format!("{:#x}", Felt::ZERO), format!("{:#x}", 0_u64)); assert_eq!(format!("{:#x}", Felt::TWO), format!("{:#x}", 2_u64)); assert_eq!(format!("{:#x}", Felt::THREE), format!("{:#x}", 3_u64)); + assert_eq!(format!("{:#x}", Felt(FieldElement::from(200))), format!("{:#x}", 200_u64)); assert_eq!( format!("{:#x}", Felt::MAX), String::from("0x800000000000011000000000000000000000000000000000000000000000000") @@ -890,9 +891,10 @@ mod test { #[test] fn display_upper_hex() { - assert_eq!(format!("{:#X}", Felt::ZERO), format!("{:#x}", 0_u64)); - assert_eq!(format!("{:#X}", Felt::TWO), format!("{:#x}", 2_u64)); - assert_eq!(format!("{:#X}", Felt::THREE), format!("{:#x}", 3_u64)); + assert_eq!(format!("{:#X}", Felt::ZERO), format!("{:#X}", 0_u64)); + assert_eq!(format!("{:#X}", Felt::TWO), format!("{:#X}", 2_u64)); + assert_eq!(format!("{:#X}", Felt::THREE), format!("{:#X}", 3_u64)); + assert_eq!(format!("{:#X}", Felt(FieldElement::from(200))), format!("{:#X}", 200_u64)); assert_eq!( format!("{:#X}", Felt::MAX), String::from("0x800000000000011000000000000000000000000000000000000000000000000") From 2f47fe38987c0e88a0545472350999e88ea58553 Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 4 Jul 2023 15:25:12 -0300 Subject: [PATCH 48/97] Implement Display --- crates/stark-felt/src/lib.rs | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index bf97d15..0f8e2fa 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -478,8 +478,33 @@ mod formatting { /// Represents [Felt] in decimal by default. impl fmt::Display for Felt { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - todo!() + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if self.is_zero() { + return write!(f, "0"); + } + + let mut buf = [0u8; 4 * 20]; + let mut i = buf.len() - 1; + let mut current = self.0.representative(); + let ten = UnsignedInteger::from(10_u16); + + loop { + let digit = if current < ten { + current.limbs[0] as u8 + } else { + (current.div_rem(&ten).1).limbs[0] as u8 + }; + buf[i] = digit + b'0'; + current = current.div_rem(&ten).0; + if current == UnsignedInteger::from(0_u16) { + break; + } + i -= 1; + } + + // sequence of `'0'..'9'` chars is guaranteed to be a valid UTF8 string + let s = std::str::from_utf8(&buf[i..]).unwrap(); + fmt::Display::fmt(s, f) } } @@ -882,7 +907,10 @@ mod test { assert_eq!(format!("{:#x}", Felt::ZERO), format!("{:#x}", 0_u64)); assert_eq!(format!("{:#x}", Felt::TWO), format!("{:#x}", 2_u64)); assert_eq!(format!("{:#x}", Felt::THREE), format!("{:#x}", 3_u64)); - assert_eq!(format!("{:#x}", Felt(FieldElement::from(200))), format!("{:#x}", 200_u64)); + assert_eq!( + format!("{:#x}", Felt(FieldElement::from(200))), + format!("{:#x}", 200_u64) + ); assert_eq!( format!("{:#x}", Felt::MAX), String::from("0x800000000000011000000000000000000000000000000000000000000000000") From 63acbf5fd24ebd66b53e0c58c73465a3ef8d2edc Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 4 Jul 2023 15:32:32 -0300 Subject: [PATCH 49/97] Fix Display + add tests --- crates/stark-felt/src/lib.rs | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 0f8e2fa..f85f5ca 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -490,9 +490,9 @@ mod formatting { loop { let digit = if current < ten { - current.limbs[0] as u8 + current.limbs[3] as u8 } else { - (current.div_rem(&ten).1).limbs[0] as u8 + (current.div_rem(&ten).1).limbs[3] as u8 }; buf[i] = digit + b'0'; current = current.div_rem(&ten).0; @@ -922,10 +922,28 @@ mod test { assert_eq!(format!("{:#X}", Felt::ZERO), format!("{:#X}", 0_u64)); assert_eq!(format!("{:#X}", Felt::TWO), format!("{:#X}", 2_u64)); assert_eq!(format!("{:#X}", Felt::THREE), format!("{:#X}", 3_u64)); - assert_eq!(format!("{:#X}", Felt(FieldElement::from(200))), format!("{:#X}", 200_u64)); + assert_eq!( + format!("{:#X}", Felt(FieldElement::from(200))), + format!("{:#X}", 200_u64) + ); assert_eq!( format!("{:#X}", Felt::MAX), String::from("0x800000000000011000000000000000000000000000000000000000000000000") ); } + + #[test] + fn display_decimal() { + assert_eq!(format!("{}", Felt::ZERO), format!("{}", 0_u64)); + assert_eq!(format!("{}", Felt::TWO), format!("{}", 2_u64)); + assert_eq!(format!("{}", Felt::THREE), format!("{}", 3_u64)); + assert_eq!( + format!("{}", Felt(FieldElement::from(200))), + format!("{}", 200_u64) + ); + assert_eq!( + format!("{}", Felt::MAX), + String::from("3618502788666131213697322783095070105623107215331596699973092056135872020480") + ); + } } From 2eb99bda988823a502c3fe45c3a93f7314aa7cd2 Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 4 Jul 2023 15:32:53 -0300 Subject: [PATCH 50/97] fmt --- crates/stark-felt/src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index f85f5ca..38a047a 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -943,7 +943,9 @@ mod test { ); assert_eq!( format!("{}", Felt::MAX), - String::from("3618502788666131213697322783095070105623107215331596699973092056135872020480") + String::from( + "3618502788666131213697322783095070105623107215331596699973092056135872020480" + ) ); } } From 6ee595044a4236470f5944c5fb9ecd6cbdb09c15 Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 4 Jul 2023 15:53:10 -0300 Subject: [PATCH 51/97] Simplify methods --- crates/stark-felt/src/lib.rs | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 38a047a..c6a6cb4 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -123,12 +123,9 @@ impl Felt { /// Floor division. pub fn floor_div(&self, rhs: &NonZeroFelt) -> Self { - Self::from_bytes_be( - &(self.0.representative().div_rem(&rhs.0.representative())) - .0 - .to_bytes_be(), - ) - .unwrap_or_default() + Self(FieldElement::from( + &(self.0.representative().div_rem(&rhs.0.representative())).0, + )) } /// Multiplicative inverse. @@ -154,28 +151,24 @@ impl Felt { /// Modular multiplication. pub fn mul_mod(&self, rhs: &Self, p: &Self) -> Self { - Self::from_bytes_be( + Self(FieldElement::from( &(self.0 * rhs.0) .representative() .div_rem(&p.0.representative()) .1 - .to_bytes_be(), - ) - .unwrap_or_default() + )) } /// Modular multiplicative inverse. pub fn inverse_mod(&self, p: &Self) -> Self { - Self::from_bytes_be( + Self(FieldElement::from( &self .0 .inv() .representative() .div_rem(&p.0.representative()) .1 - .to_bytes_be(), - ) - .unwrap_or_default() + )) } } From 1bf28f78d7eef0147a1f037836c31ea932053da0 Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 4 Jul 2023 15:57:06 -0300 Subject: [PATCH 52/97] Remove doc comments from tests --- crates/stark-felt/src/lib.rs | 53 ++---------------------------------- 1 file changed, 2 insertions(+), 51 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index c6a6cb4..aa65892 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -155,7 +155,7 @@ impl Felt { &(self.0 * rhs.0) .representative() .div_rem(&p.0.representative()) - .1 + .1, )) } @@ -167,7 +167,7 @@ impl Felt { .inv() .representative() .div_rem(&p.0.representative()) - .1 + .1, )) } } @@ -568,11 +568,6 @@ mod test { proptest! { #[test] - // Property-based test that ensures, for 100 felt values that are randomly generated - // each time tests are run, that a new felt doesn't fall outside the range [0, p]. - // In this and some of the following tests, The value of {x} can be either [0] or a - // very large number, in order to try to overflow the value of {p} and thus ensure the - // modular arithmetic is working correctly. fn new_in_range(ref x in any::<[u8; 40]>()) { let x_be = Felt::from_bytes_be(x).unwrap(); prop_assert!(x_be < Felt::MAX); @@ -636,27 +631,17 @@ mod test { } #[test] - // Property-based test that ensures, for 100 felt values that are randomly - // generated each time tests are run, that a felt created using Felt252::from_bytes_be doesn't - // fall outside the range [0, p]. - // In this and some of the following tests, The value of {x} can be either [0] or a very large number, - // in order to try to overflow the value of {p} and thus ensure the modular arithmetic is working correctly. fn from_bytes_be_in_range(ref x in any::<[u8; 40]>()) { let x = Felt::from_bytes_be(x).unwrap(); prop_assert!(x <= Felt::MAX); } #[test] - // Property-based test that ensures, for 100 felt values that are randomly generated each time - // tests are run, that the negative of a felt doesn't fall outside the range [0, p]. fn neg_in_range(x in any::()) { prop_assert!(-x <= Felt::MAX); } #[test] - // Property-based test that ensures, for 100 {x} and {y} values that are randomly generated - // each time tests are run, that a subtraction between two felts {x} and {y} and doesn't fall - // outside the range [0, p]. The values of {x} and {y} can be either [0] or a very large number. fn sub(ref x in any::(), ref y in any::()) { // x - y prop_assert!(x - y <= Felt::MAX); @@ -667,9 +652,6 @@ mod test { } #[test] - // Property-based test that ensures, for 100 {x} and {y} values that are randomly generated - // each time tests are run, that a subtraction with assignment between two felts {x} and {y} - // and doesn't fall outside the range [0, p]. The values of {x} and {y} can be either [0] or a very large number. fn sub_assign_in_range(mut x in any::(), y in any::()) { x -= y; prop_assert!(x <= Felt::MAX); @@ -679,20 +661,12 @@ mod test { } #[test] - // Property-based test that ensures, for 100 {x} and {y} values that are randomly - // generated each time tests are run, that a multiplication between two felts {x} - // and {y} and doesn't fall outside the range [0, p]. The values of {x} and {y} - // can be either [0] or a very large number. fn mul(ref x in any::(), ref y in any::()) { prop_assert_eq!(x * y, y * x); prop_assert!(x * y <= Felt::MAX); } #[test] - // Property-based test that ensures, for 100 pairs of {x} and {y} values that - // are randomly generated each time tests are run, that a multiplication with - // assignment between two felts {x} and {y} and doesn't fall outside the range [0, p]. - // The values of {x} and {y} can be either [0] or a very large number. fn mul_assign_in_range(mut x in any::(), y in any::()) { x *= y; prop_assert!(x <= Felt::MAX); @@ -702,11 +676,6 @@ mod test { } #[test] - // Property-based test that ensures, for 100 pairs of {x} and {y} values that are - // randomly generated each time tests are run, that the result of the division of - // {x} by {y} is the inverse multiplicative of {x} --that is, multiplying the result - // by {y} returns the original number {x}. The values of {x} and {y} can be either - // [0] or a very large number. fn field_div_is_mul_inv(x in any::(), y in nonzero_felt()) { let q = x.field_div(&NonZeroFelt(y.0)); prop_assert!(q <= Felt::MAX); @@ -714,39 +683,21 @@ mod test { } #[test] - // Property-based test that ensures, for 100 values {x} that are randomly - // generated each time tests are run, that raising {x} to the {y}th power - // returns a result that is inside of the range [0, p]. fn pow_in_range(base in any::(), exp in 0..u128::MAX){ prop_assert!(base.pow(exp) <= Felt::MAX); } #[test] - // Property based test that ensures, for 100 pairs of values {x} and {y} - // generated at random each time tests are run, that performing an Add operation - // between them returns a result that is inside of the range [0, p]. fn add_in_range(x in any::(), y in any::()){ prop_assert!(x + y <= Felt::MAX); } - /// Tests the additive identity of the implementation of Zero trait for felts - /// - /// ```{.text} - /// x + 0 = x ∀ x - /// 0 + x = x ∀ x - /// ``` #[test] fn zero_additive_identity(x in any::()) { prop_assert_eq!(x, x + Felt::ZERO); prop_assert_eq!(x, Felt::ZERO + x); } - /// Tests the multiplicative identity of the implementation of One trait for felts - /// - /// ```{.text} - /// x * 1 = x ∀ x - /// 1 * x = x ∀ x - /// ``` #[test] fn one_multiplicative_identity(x in any::()) { prop_assert_eq!(x, x * Felt::ONE); From 9523238fd53855d5477ce96833d72b50b7556653 Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 4 Jul 2023 16:00:47 -0300 Subject: [PATCH 53/97] Add proptest for floor_div --- crates/stark-felt/src/lib.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index aa65892..5e8ac76 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -559,6 +559,8 @@ mod errors { #[cfg(test)] mod test { + use core::ops::Shl; + use crate::arbitrary::nonzero_felt; use super::*; @@ -682,6 +684,15 @@ mod test { prop_assert_eq!(q * y, x); } + #[test] + fn floor_div_is_mul_inv(x in any::(), y in nonzero_felt()) { + let x = Felt(FieldElement::from(&x.0.representative().shl(127))); + let y = Felt(FieldElement::from(&y.0.representative().shl(127))); + let q = x.field_div(&NonZeroFelt(y.0)); + prop_assert!(q <= Felt::MAX); + prop_assert_eq!(q * y, x); + } + #[test] fn pow_in_range(base in any::(), exp in 0..u128::MAX){ prop_assert!(base.pow(exp) <= Felt::MAX); From 51b0fd53ba6f6bc9ec5a4f6d440be3e47e93ef5f Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 4 Jul 2023 16:13:55 -0300 Subject: [PATCH 54/97] Add tests for basic operations --- crates/stark-felt/src/lib.rs | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 5e8ac76..daa250b 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -831,6 +831,39 @@ mod test { assert!(Felt::default().is_zero()); } + #[test] + fn mul_operations() { + assert_eq!(Felt::ONE * Felt::THREE, Felt::THREE); + assert_eq!(Felt::ZERO * Felt::MAX, Felt::ZERO); + assert_eq!( + Felt(FieldElement::from(200)) * Felt::THREE, + Felt(FieldElement::from(600)) + ); + assert_eq!(Felt::MAX * Felt::TWO, Felt::MAX - Felt::ONE); + } + + #[test] + fn add_operations() { + assert_eq!(Felt::ONE + Felt::TWO, Felt::THREE); + assert_eq!(Felt::ZERO + Felt::MAX, Felt::MAX); + assert_eq!( + Felt(FieldElement::from(200)) + Felt::THREE, + Felt(FieldElement::from(203)) + ); + assert_eq!(Felt::MAX + Felt::TWO, Felt::ONE); + } + + #[test] + fn sub_operations() { + assert_eq!(Felt::TWO - Felt::ONE, Felt::ONE); + assert_eq!(Felt::MAX - Felt::ZERO, Felt::MAX); + assert_eq!( + Felt(FieldElement::from(200)) - Felt::THREE, + Felt(FieldElement::from(197)) + ); + assert_eq!(Felt::ZERO - Felt::ONE, Felt::MAX); + } + #[test] fn deserialize() { assert_de_tokens(&Felt::ZERO, &[Token::String("0x0")]); From b8b91e557141146dd6bf2f94dee786bf84c93501 Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 4 Jul 2023 16:22:03 -0300 Subject: [PATCH 55/97] Add pow operations test --- crates/stark-felt/src/lib.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index daa250b..8f9598e 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -864,6 +864,18 @@ mod test { assert_eq!(Felt::ZERO - Felt::ONE, Felt::MAX); } + #[test] + fn pow_operations() { + assert_eq!(Felt::ONE.pow(5), Felt::ONE); + assert_eq!(Felt::ZERO.pow(5), Felt::ZERO); + assert_eq!(Felt::THREE.pow(0), Felt::ONE); + assert_eq!( + Felt(FieldElement::from(200)).pow(4), + Felt(FieldElement::from(1600000000)) + ); + assert_eq!(Felt::MAX.pow(9), Felt::MAX); + } + #[test] fn deserialize() { assert_de_tokens(&Felt::ZERO, &[Token::String("0x0")]); From 834a952dc47d43ff7fa6119dedf25f83595c6663 Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 4 Jul 2023 16:26:57 -0300 Subject: [PATCH 56/97] Update toml --- crates/stark-felt/Cargo.toml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/crates/stark-felt/Cargo.toml b/crates/stark-felt/Cargo.toml index 68a0033..57b75fe 100644 --- a/crates/stark-felt/Cargo.toml +++ b/crates/stark-felt/Cargo.toml @@ -13,9 +13,14 @@ readme = "README.md" [dependencies] bitvec = { version = "1.0.1", default-features = false } serde = { version = "1.0.163", optional = true, default-features = false } -lambdaworks-math = { version = "0.1.1", default-features = false } - +# TODO: use version once published +# lambdaworks-math = { version = "0.1.1", default-features = false } +lambdaworks-math = { git = "https://github.com/lambdaclass/lambdaworks.git", rev = "bfd91d4e8116ab8b0bf25f75a9f1e8bb61d355d9", default_features = false} [features] default = ["std", "serde"] std = [] alloc = ["serde?/alloc"] + +[dev-dependencies] +proptest = "1.1.0" +serde_test = "1.0.1" From 39be089bcb721c2cda0b2a3c2e85e0b1fce8e6b9 Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 4 Jul 2023 16:27:41 -0300 Subject: [PATCH 57/97] Add arbitrary.rs --- crates/stark-felt/src/arbitrary.rs | 48 ++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 crates/stark-felt/src/arbitrary.rs diff --git a/crates/stark-felt/src/arbitrary.rs b/crates/stark-felt/src/arbitrary.rs new file mode 100644 index 0000000..893331c --- /dev/null +++ b/crates/stark-felt/src/arbitrary.rs @@ -0,0 +1,48 @@ +use lambdaworks_math::{field::element::FieldElement, unsigned_integer::element::UnsignedInteger}; +use proptest::prelude::*; + +use crate::Felt; +const FIELD_HIGH: u128 = (1 << 123) + (17 << 64); // this is equal to 10633823966279327296825105735305134080 +const FIELD_LOW: u128 = 1; + +/// Returns a [`Strategy`] that generates any valid Felt +fn any_felt() -> impl Strategy { + (0..=FIELD_HIGH) + // turn range into `impl Strategy` + .prop_map(|x| x) + // choose second 128-bit limb capped by first one + .prop_flat_map(|high| { + let low = if high == FIELD_HIGH { + (0..FIELD_LOW).prop_map(|x| x).sboxed() + } else { + any::().sboxed() + }; + (Just(high), low) + }) + // turn (u128, u128) into limbs array and then into Felt + .prop_map(|(high, low)| { + let limbs = [ + (high >> 64) as u64, + (high & ((1 << 64) - 1)) as u64, + (low >> 64) as u64, + (low & ((1 << 64) - 1)) as u64, + ]; + FieldElement::new(UnsignedInteger::from_limbs(limbs)) + }) + .prop_map(|value| Felt(value)) +} + +/// Returns a [`Strategy`] that generates any nonzero Felt +pub fn nonzero_felt() -> impl Strategy { + any_felt().prop_filter("is zero", |x| !x.is_zero()) +} + +impl Arbitrary for Felt { + type Parameters = (); + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + any_felt().sboxed() + } + + type Strategy = SBoxedStrategy; +} From f5e0cc874835771942838a35d150d2996f8dff90 Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 4 Jul 2023 16:29:52 -0300 Subject: [PATCH 58/97] Remove std import --- crates/stark-felt/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 8f9598e..4c8ebb6 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -496,7 +496,7 @@ mod formatting { } // sequence of `'0'..'9'` chars is guaranteed to be a valid UTF8 string - let s = std::str::from_utf8(&buf[i..]).unwrap(); + let s = core::str::from_utf8(&buf[i..]).unwrap(); fmt::Display::fmt(s, f) } } From 7c09e6d99e10cc0f1d733af848abd797b82f63eb Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 4 Jul 2023 16:30:55 -0300 Subject: [PATCH 59/97] Clippy --- crates/stark-felt/src/arbitrary.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/stark-felt/src/arbitrary.rs b/crates/stark-felt/src/arbitrary.rs index 893331c..456cec1 100644 --- a/crates/stark-felt/src/arbitrary.rs +++ b/crates/stark-felt/src/arbitrary.rs @@ -29,7 +29,7 @@ fn any_felt() -> impl Strategy { ]; FieldElement::new(UnsignedInteger::from_limbs(limbs)) }) - .prop_map(|value| Felt(value)) + .prop_map(Felt) } /// Returns a [`Strategy`] that generates any nonzero Felt From 1b6aaaa6072144fa7c83bfbe3041690e239166f4 Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 4 Jul 2023 17:11:37 -0300 Subject: [PATCH 60/97] Bump version --- README.md | 2 +- crates/stark-felt/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 35f21d0..7d227b2 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ As a crates.io dependency: ```toml [dependencies] -stark-felt = "0.0.2" +stark-felt = "0.0.3" ``` As a git dependency: diff --git a/crates/stark-felt/Cargo.toml b/crates/stark-felt/Cargo.toml index 57b75fe..a2fdfbd 100644 --- a/crates/stark-felt/Cargo.toml +++ b/crates/stark-felt/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "stark-felt" -version = "0.0.2" +version = "0.0.3" edition = "2021" license = "MIT" homepage = "https://github.com/starknet-io/types-rs" From 7290d2ce150d0e12ac14fc90fc570f76529e185b Mon Sep 17 00:00:00 2001 From: Federica Date: Wed, 5 Jul 2023 14:02:31 -0300 Subject: [PATCH 61/97] Add methods `to_usize` & `to_u64` --- crates/stark-felt/src/lib.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 4c8ebb6..c340d1e 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -170,6 +170,17 @@ impl Felt { .1, )) } + + pub fn to_u64(&self) -> Option { + match self.0.representative().limbs { + [0, 0, 0, val] => Some(val), + _ => None, + } + } + + pub fn to_usize(&self) -> Option { + self.to_u64()?.try_into().ok() + } } /// Defaults to [Felt::ZERO]. From 0b4721510404a6c7a865a92ae45d4d5dc899f5f9 Mon Sep 17 00:00:00 2001 From: Federica Date: Wed, 5 Jul 2023 14:21:30 -0300 Subject: [PATCH 62/97] Derive `Hash` for Felt --- crates/stark-felt/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index c340d1e..5ce1fd0 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -20,7 +20,7 @@ use lambdaworks_math::{ }; /// Definition of the Field Element type. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Felt(FieldElement); /// A non-zero [Felt]. From 6f350daa908d4a2a981432318084f95ad6c34aff Mon Sep 17 00:00:00 2001 From: Federica Date: Wed, 5 Jul 2023 14:35:01 -0300 Subject: [PATCH 63/97] Implement From + From for Felt --- crates/stark-felt/src/lib.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 5ce1fd0..0457e60 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -237,6 +237,17 @@ impl TryFrom<&Felt> for NonZeroFelt { } } } +impl From for Felt { + fn from(value: u64) -> Self { + Self(FieldElement::from(value)) + } +} + +impl From for Felt { + fn from(value: u128) -> Self { + Self(FieldElement::from(&UnsignedInteger::from(value))) + } +} mod arithmetic { use core::{iter, ops}; From 92acbfb2350d0ab5d6112b01f8d79f79f6063339 Mon Sep 17 00:00:00 2001 From: Federica Date: Wed, 5 Jul 2023 15:12:04 -0300 Subject: [PATCH 64/97] Implement more ops --- crates/stark-felt/src/lib.rs | 85 +++++++++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 0457e60..dbb5251 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -249,8 +249,21 @@ impl From for Felt { } } +impl From for Felt { + fn from(value: i128) -> Self { + if value.is_negative() { + Self::ZERO - Self(FieldElement::from(&UnsignedInteger::from(value as u128))) + } else { + Self(FieldElement::from(&UnsignedInteger::from(value as u128))) + } + } +} + mod arithmetic { - use core::{iter, ops}; + use core::{ + iter, + ops::{self, Neg}, + }; use super::*; @@ -304,6 +317,42 @@ mod arithmetic { } } + /// Field addition. Never overflows/underflows. + impl ops::Add for Felt { + type Output = Felt; + + fn add(self, rhs: u64) -> Self::Output { + self + Felt::from(rhs) + } + } + + /// Field addition. Never overflows/underflows. + impl ops::Add for &Felt { + type Output = Felt; + + fn add(self, rhs: u64) -> Self::Output { + self + Felt::from(rhs) + } + } + + /// Field addition. Never overflows/underflows. + impl ops::Add for Felt { + type Output = Felt; + + fn add(self, rhs: usize) -> Self::Output { + self + rhs as u64 + } + } + + /// Field addition. Never overflows/underflows. + impl ops::Add for &Felt { + type Output = Felt; + + fn add(self, rhs: usize) -> Self::Output { + self + rhs as u64 + } + } + /// Field subtraction. Never overflows/underflows. impl ops::SubAssign for Felt { fn sub_assign(&mut self, rhs: Felt) { @@ -354,6 +403,40 @@ mod arithmetic { } } + /// Field subtraction. Never overflows/underflows. + #[allow(clippy::suspicious_arithmetic_impl)] + impl ops::Sub for u64 { + type Output = Felt; + fn sub(self, rhs: Felt) -> Self::Output { + rhs.neg() + self + } + } + + /// Field subtraction. Never overflows/underflows. + #[allow(clippy::suspicious_arithmetic_impl)] + impl ops::Sub<&Felt> for u64 { + type Output = Felt; + fn sub(self, rhs: &Felt) -> Self::Output { + rhs.neg() + self + } + } + + /// Field subtraction. Never overflows/underflows. + impl ops::Sub for usize { + type Output = Felt; + fn sub(self, rhs: Felt) -> Self::Output { + self as u64 - rhs + } + } + + /// Field subtraction. Never overflows/underflows. + impl ops::Sub<&Felt> for usize { + type Output = Felt; + fn sub(self, rhs: &Felt) -> Self::Output { + self as u64 - rhs + } + } + /// Field multiplication. Never overflows/underflows. impl ops::MulAssign for Felt { fn mul_assign(&mut self, rhs: Felt) { From 23418742de7e6715207390f43e3a099fa5a88f02 Mon Sep 17 00:00:00 2001 From: Federica Date: Wed, 5 Jul 2023 16:54:23 -0300 Subject: [PATCH 65/97] Implement more ops --- crates/stark-felt/src/lib.rs | 90 +++++++++++++++++++++++++++++++++++- 1 file changed, 89 insertions(+), 1 deletion(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index dbb5251..77d98d1 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -171,6 +171,10 @@ impl Felt { )) } + pub fn to_u32(&self) -> Option { + self.to_u64().and_then(|n| n.try_into().ok()) + } + pub fn to_u64(&self) -> Option { match self.0.representative().limbs { [0, 0, 0, val] => Some(val), @@ -181,6 +185,16 @@ impl Felt { pub fn to_usize(&self) -> Option { self.to_u64()?.try_into().ok() } + + pub fn from_hex(hex_string: &str) -> Result { + FieldElement::from_hex(hex_string).map(Self).map_err(|_| FromStrError) + } + + pub fn to_le_digits(&self) -> [u64; 4] { + let mut limbs = self.0.representative().limbs; + limbs.reverse(); + limbs + } } /// Defaults to [Felt::ZERO]. @@ -237,6 +251,19 @@ impl TryFrom<&Felt> for NonZeroFelt { } } } + +impl From for Felt { + fn from(value: usize) -> Self { + Self::from(value as u64) + } +} + +impl From for Felt { + fn from(value: u32) -> Self { + Self::from(value as u64) + } +} + impl From for Felt { fn from(value: u64) -> Self { Self(FieldElement::from(value)) @@ -249,10 +276,26 @@ impl From for Felt { } } +impl From for Felt { + fn from(value: i32) -> Self { + Self::from(value as i64) + } +} + +impl From for Felt { + fn from(value: i64) -> Self { + if value.is_negative() { + Self::ZERO - Self(FieldElement::from(&UnsignedInteger::from(value.abs() as u64))) + } else { + Self(FieldElement::from(&UnsignedInteger::from(value as u64))) + } + } +} + impl From for Felt { fn from(value: i128) -> Self { if value.is_negative() { - Self::ZERO - Self(FieldElement::from(&UnsignedInteger::from(value as u128))) + Self::ZERO - Self(FieldElement::from(&UnsignedInteger::from(value.abs() as u128))) } else { Self(FieldElement::from(&UnsignedInteger::from(value as u128))) } @@ -506,6 +549,51 @@ mod arithmetic { } } + impl ops::Shl for Felt { + type Output = Felt; + fn shl(self, rhs: usize) -> Self::Output { + Self(FieldElement::from(&self.0.representative().shl(rhs))) + } + } + + impl ops::Shl for &Felt { + type Output = Felt; + + fn shl(self, rhs: usize) -> Self::Output { + Felt(FieldElement::from(&self.0.representative().shl(rhs))) + } + } + + impl ops::Shr for Felt { + type Output = Felt; + fn shr(self, rhs: usize) -> Self::Output { + Self(FieldElement::from(&self.0.representative().shr(rhs))) + } + } + + impl ops::Shr for &Felt { + type Output = Felt; + + fn shr(self, rhs: usize) -> Self::Output { + Felt(FieldElement::from(&self.0.representative().shr(rhs))) + } + } + + impl ops::BitAnd for Felt { + type Output = Felt; + fn bitand(self, rhs: Felt) -> Self::Output { + Self(FieldElement::from(&self.0.representative().bitand(rhs.0.representative()))) + } + } + + impl ops::BitAnd for &Felt { + type Output = Felt; + + fn bitand(self, rhs: Felt) -> Self::Output { + Felt(FieldElement::from(&self.0.representative().bitand(rhs.0.representative()))) + } + } + impl iter::Sum for Felt { fn sum>(iter: I) -> Self { iter.fold(Self::ZERO, |augend, addend| augend + addend) From 0ecdba4cc153299f30a237f857aeb15541ae12cc Mon Sep 17 00:00:00 2001 From: Federica Date: Wed, 5 Jul 2023 18:14:15 -0300 Subject: [PATCH 66/97] Implement more ops --- crates/stark-felt/src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 77d98d1..63cb99f 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -195,6 +195,10 @@ impl Felt { limbs.reverse(); limbs } + + pub fn bits(&self) -> u32 { + self.0.representative().bits() + } } /// Defaults to [Felt::ZERO]. From 63b514237cba836ea398db24ba1bc0bc6c96c369 Mon Sep 17 00:00:00 2001 From: Federica Date: Wed, 5 Jul 2023 18:53:33 -0300 Subject: [PATCH 67/97] Add bitwise operations --- crates/stark-felt/src/lib.rs | 117 +++++++++++++++++++++++++++++++++-- 1 file changed, 112 insertions(+), 5 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 63cb99f..6ff370d 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -187,7 +187,9 @@ impl Felt { } pub fn from_hex(hex_string: &str) -> Result { - FieldElement::from_hex(hex_string).map(Self).map_err(|_| FromStrError) + FieldElement::from_hex(hex_string) + .map(Self) + .map_err(|_| FromStrError) } pub fn to_le_digits(&self) -> [u64; 4] { @@ -289,7 +291,10 @@ impl From for Felt { impl From for Felt { fn from(value: i64) -> Self { if value.is_negative() { - Self::ZERO - Self(FieldElement::from(&UnsignedInteger::from(value.abs() as u64))) + Self::ZERO + - Self(FieldElement::from(&UnsignedInteger::from( + value.abs() as u64 + ))) } else { Self(FieldElement::from(&UnsignedInteger::from(value as u64))) } @@ -299,7 +304,10 @@ impl From for Felt { impl From for Felt { fn from(value: i128) -> Self { if value.is_negative() { - Self::ZERO - Self(FieldElement::from(&UnsignedInteger::from(value.abs() as u128))) + Self::ZERO + - Self(FieldElement::from(&UnsignedInteger::from( + value.abs() as u128 + ))) } else { Self(FieldElement::from(&UnsignedInteger::from(value as u128))) } @@ -586,7 +594,9 @@ mod arithmetic { impl ops::BitAnd for Felt { type Output = Felt; fn bitand(self, rhs: Felt) -> Self::Output { - Self(FieldElement::from(&self.0.representative().bitand(rhs.0.representative()))) + Self(FieldElement::from( + &self.0.representative().bitand(rhs.0.representative()), + )) } } @@ -594,7 +604,104 @@ mod arithmetic { type Output = Felt; fn bitand(self, rhs: Felt) -> Self::Output { - Felt(FieldElement::from(&self.0.representative().bitand(rhs.0.representative()))) + Felt(FieldElement::from( + &self.0.representative().bitand(rhs.0.representative()), + )) + } + } + + impl ops::BitAnd<&Felt> for Felt { + type Output = Felt; + fn bitand(self, rhs: &Felt) -> Self::Output { + Self(FieldElement::from( + &self.0.representative().bitand(rhs.0.representative()), + )) + } + } + + impl ops::BitAnd<&Felt> for &Felt { + type Output = Felt; + + fn bitand(self, rhs: &Felt) -> Self::Output { + Felt(FieldElement::from( + &self.0.representative().bitand(rhs.0.representative()), + )) + } + } + + impl ops::BitOr for Felt { + type Output = Felt; + fn bitor(self, rhs: Felt) -> Self::Output { + Self(FieldElement::from( + &self.0.representative().bitor(rhs.0.representative()), + )) + } + } + + impl ops::BitOr for &Felt { + type Output = Felt; + + fn bitor(self, rhs: Felt) -> Self::Output { + Felt(FieldElement::from( + &self.0.representative().bitor(rhs.0.representative()), + )) + } + } + + impl ops::BitOr<&Felt> for Felt { + type Output = Felt; + fn bitor(self, rhs: &Felt) -> Self::Output { + Self(FieldElement::from( + &self.0.representative().bitor(rhs.0.representative()), + )) + } + } + + impl ops::BitOr<&Felt> for &Felt { + type Output = Felt; + + fn bitor(self, rhs: &Felt) -> Self::Output { + Felt(FieldElement::from( + &self.0.representative().bitor(rhs.0.representative()), + )) + } + } + + impl ops::BitXor for Felt { + type Output = Felt; + fn bitxor(self, rhs: Felt) -> Self::Output { + Self(FieldElement::from( + &self.0.representative().bitxor(rhs.0.representative()), + )) + } + } + + impl ops::BitXor for &Felt { + type Output = Felt; + + fn bitxor(self, rhs: Felt) -> Self::Output { + Felt(FieldElement::from( + &self.0.representative().bitxor(rhs.0.representative()), + )) + } + } + + impl ops::BitXor<&Felt> for Felt { + type Output = Felt; + fn bitxor(self, rhs: &Felt) -> Self::Output { + Self(FieldElement::from( + &self.0.representative().bitxor(rhs.0.representative()), + )) + } + } + + impl ops::BitXor<&Felt> for &Felt { + type Output = Felt; + + fn bitxor(self, rhs: &Felt) -> Self::Output { + Felt(FieldElement::from( + &self.0.representative().bitxor(rhs.0.representative()), + )) } } From 142e946eea9300050a4af942a155cbdf3b160810 Mon Sep 17 00:00:00 2001 From: Federica Date: Mon, 10 Jul 2023 11:07:47 -0300 Subject: [PATCH 68/97] Add more methods --- crates/stark-felt/Cargo.toml | 2 +- crates/stark-felt/src/lib.rs | 39 ++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/crates/stark-felt/Cargo.toml b/crates/stark-felt/Cargo.toml index a2fdfbd..0742d58 100644 --- a/crates/stark-felt/Cargo.toml +++ b/crates/stark-felt/Cargo.toml @@ -15,7 +15,7 @@ bitvec = { version = "1.0.1", default-features = false } serde = { version = "1.0.163", optional = true, default-features = false } # TODO: use version once published # lambdaworks-math = { version = "0.1.1", default-features = false } -lambdaworks-math = { git = "https://github.com/lambdaclass/lambdaworks.git", rev = "bfd91d4e8116ab8b0bf25f75a9f1e8bb61d355d9", default_features = false} +lambdaworks-math = { git = "https://github.com/lambdaclass/lambdaworks.git", rev = "60ba0fdb76496995b062d4e9943d7bb96d94ee37", default_features = false} [features] default = ["std", "serde"] std = [] diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 6ff370d..b89b2ce 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -128,6 +128,11 @@ impl Felt { )) } + pub fn div_rem(&self, rhs: &NonZeroFelt) -> (Self, Self) { + let (q, r) = self.0.representative().div_rem(&rhs.0.representative()); + (Self(FieldElement::from(&q)), Self(FieldElement::from(&r))) + } + /// Multiplicative inverse. pub fn inverse(&self) -> Option { Some(Self(self.0.inv())) @@ -171,6 +176,12 @@ impl Felt { )) } + pub fn mod_floor(&self, p: &Self) -> Self { + Self(FieldElement::from( + &self.0.representative().div_rem(&p.0.representative()).1, + )) + } + pub fn to_u32(&self) -> Option { self.to_u64().and_then(|n| n.try_into().ok()) } @@ -192,6 +203,12 @@ impl Felt { .map_err(|_| FromStrError) } + pub fn from_dec_str(dec_string: &str) -> Result { + UnsignedInteger::from_dec_str(dec_string) + .map(|x| Self(FieldElement::from(&x))) + .map_err(|_| FromStrError) + } + pub fn to_le_digits(&self) -> [u64; 4] { let mut limbs = self.0.representative().limbs; limbs.reverse(); @@ -264,6 +281,12 @@ impl From for Felt { } } +impl From for Felt { + fn from(value: u8) -> Self { + Self::from(value as u64) + } +} + impl From for Felt { fn from(value: u32) -> Self { Self::from(value as u64) @@ -492,6 +515,22 @@ mod arithmetic { } } + /// Field subtraction. Never overflows/underflows. + impl ops::Sub for Felt { + type Output = Felt; + fn sub(self, rhs: u64) -> Self::Output { + self - Self::from(rhs) + } + } + + /// Field subtraction. Never overflows/underflows. + impl ops::Sub for &Felt { + type Output = Felt; + fn sub(self, rhs: u64) -> Self::Output { + self - Felt::from(rhs) + } + } + /// Field multiplication. Never overflows/underflows. impl ops::MulAssign for Felt { fn mul_assign(&mut self, rhs: Felt) { From e53ccbb2fa35fd845664cf7d538bca2178f96216 Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 11 Jul 2023 11:05:09 -0300 Subject: [PATCH 69/97] Use `bits_le` in bits method --- crates/stark-felt/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index b89b2ce..79c9073 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -216,7 +216,7 @@ impl Felt { } pub fn bits(&self) -> u32 { - self.0.representative().bits() + self.0.representative().bits_le() as u32 } } From 8e1051a03405947d43180235e39ec64fb60c3ff4 Mon Sep 17 00:00:00 2001 From: Federica Date: Sat, 15 Jul 2023 10:47:05 -0300 Subject: [PATCH 70/97] Handle negative numbers in `Felt::from_dec_string` --- crates/stark-felt/src/lib.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 79c9073..569d792 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -1,5 +1,7 @@ #![cfg_attr(not(feature = "std"), no_std)] +use core::ops::Neg; + use bitvec::array::BitArray; #[cfg(test)] @@ -204,9 +206,15 @@ impl Felt { } pub fn from_dec_str(dec_string: &str) -> Result { - UnsignedInteger::from_dec_str(dec_string) - .map(|x| Self(FieldElement::from(&x))) - .map_err(|_| FromStrError) + if dec_string.starts_with('-') { + UnsignedInteger::from_dec_str(dec_string) + .map(|x| Self(FieldElement::from(&x))) + .map_err(|_| FromStrError) + } else { + UnsignedInteger::from_dec_str(dec_string.strip_prefix('-').unwrap()) + .map(|x| Self(FieldElement::from(&x)).neg()) + .map_err(|_| FromStrError) + } } pub fn to_le_digits(&self) -> [u64; 4] { From f0352146393cdd909948000c71e8300085459b2f Mon Sep 17 00:00:00 2001 From: Federica Date: Sat, 15 Jul 2023 10:53:05 -0300 Subject: [PATCH 71/97] Fix --- crates/stark-felt/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 569d792..4d0364f 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -207,13 +207,13 @@ impl Felt { pub fn from_dec_str(dec_string: &str) -> Result { if dec_string.starts_with('-') { - UnsignedInteger::from_dec_str(dec_string) - .map(|x| Self(FieldElement::from(&x))) - .map_err(|_| FromStrError) - } else { UnsignedInteger::from_dec_str(dec_string.strip_prefix('-').unwrap()) .map(|x| Self(FieldElement::from(&x)).neg()) .map_err(|_| FromStrError) + } else { + UnsignedInteger::from_dec_str(dec_string) + .map(|x| Self(FieldElement::from(&x))) + .map_err(|_| FromStrError) } } From ff2a141cb04156694c8a1deabb20e350576eecc8 Mon Sep 17 00:00:00 2001 From: Pedro Fontana Date: Wed, 23 Aug 2023 12:47:52 -0300 Subject: [PATCH 72/97] Add pow_felt --- crates/stark-felt/src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index b81f617..7d06b9c 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -169,6 +169,10 @@ impl Felt { Self(self.0.pow(exponent)) } + pub fn pow_felt(&self, exponent: &Felt) -> Self { + Self(self.0.pow(exponent.0.representative())) + } + /// Modular multiplication. pub fn mul_mod(&self, rhs: &Self, p: &Self) -> Self { Self(FieldElement::from( From c5707410460b4e3f194b64a0d3a94ad5ad4fe7ad Mon Sep 17 00:00:00 2001 From: Pedro Fontana Date: Fri, 25 Aug 2023 17:22:18 -0300 Subject: [PATCH 73/97] Update lambdaworks commit --- crates/stark-felt/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/stark-felt/Cargo.toml b/crates/stark-felt/Cargo.toml index 02e8c40..4d9dfdf 100644 --- a/crates/stark-felt/Cargo.toml +++ b/crates/stark-felt/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" [dependencies] bitvec = { version = "1.0.1", default-features = false } serde = { version = "1.0.163", optional = true, default-features = false } -lambdaworks-math = { git = "https://github.com/lambdaclass/lambdaworks.git", rev = "4c73e8578fc69b8a548b9a3d9657afe97e089811", default_features = false} +lambdaworks-math = { git = "https://github.com/lambdaclass/lambdaworks.git", rev = "4964ccf29e3cfac97e4ca1a97e500cde6fed143c", default_features = false} [features] default = ["std", "serde"] From cf61a68c254d4e732edc8f84e622007abf7157e7 Mon Sep 17 00:00:00 2001 From: Pedro Fontana Date: Fri, 25 Aug 2023 19:02:59 -0300 Subject: [PATCH 74/97] impl Add<&Felt> for u64 && to_be_digits --- crates/stark-felt/src/lib.rs | 50 +++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 7d06b9c..2595c95 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -1,6 +1,6 @@ #![cfg_attr(not(feature = "std"), no_std)] -use core::ops::Neg; +use core::ops::{Add, Neg}; use bitvec::array::BitArray; @@ -240,6 +240,10 @@ impl Felt { limbs } + pub fn to_be_digits(&self) -> [u64; 4] { + self.0.representative().limbs + } + pub fn bits(&self) -> u32 { self.0.representative().bits_le() as u32 } @@ -362,6 +366,50 @@ impl From for Felt { } } +impl Add<&Felt> for u64 { + type Output = Option; + + fn add(self, rhs: &Felt) -> Option { + const PRIME_DIGITS_BE_HI: [u64; 3] = + [0x0800000000000011, 0x0000000000000000, 0x0000000000000000]; + const PRIME_MINUS_U64_MAX_DIGITS_BE_HI: [u64; 3] = + [0x0800000000000010, 0xffffffffffffffff, 0xffffffffffffffff]; + + // Match with the 64 bits digits in big-endian order to + // characterize how the sum will behave. + match rhs.to_be_digits() { + // All digits are `0`, so the sum is simply `self`. + [0, 0, 0, 0] => Some(self), + // A single digit means this is effectively the sum of two `u64` numbers. + [0, 0, 0, low] => self.checked_add(low), + // Now we need to compare the 3 most significant digits. + // There are two relevant cases from now on, either `rhs` behaves like a + // substraction of a `u64` or the result of the sum falls out of range. + + // The 3 MSB only match the prime for Felt::max_value(), which is -1 + // in the signed field, so this is equivalent to substracting 1 to `self`. + [hi @ .., _] if hi == PRIME_DIGITS_BE_HI => self.checked_sub(1), + + // For the remaining values between `[-u64::MAX..0]` (where `{0, -1}` have + // already been covered) the MSB matches that of `PRIME - u64::MAX`. + // Because we're in the negative number case, we count down. Because `0` + // and `-1` correspond to different MSBs, `0` and `1` in the LSB are less + // than `-u64::MAX`, the smallest value we can add to (read, substract its + // magnitude from) a `u64` number, meaning we exclude them from the valid + // case. + // For the remaining range, we take the absolute value module-2 while + // correcting by substracting `1` (note we actually substract `2` because + // the absolute value itself requires substracting `1`. + [hi @ .., low] if hi == PRIME_MINUS_U64_MAX_DIGITS_BE_HI && low >= 2 => { + (self).checked_sub(u64::MAX - (low - 2)) + } + // Any other case will result in an addition that is out of bounds, so + // the addition fails, returning `None`. + _ => None, + } + } +} + mod arithmetic { use core::{ iter, From 8d5ad211146442dc8c2c3f4a35c5e4fb413fe7d8 Mon Sep 17 00:00:00 2001 From: Pedro Fontana Date: Fri, 1 Sep 2023 11:49:11 -0300 Subject: [PATCH 75/97] Update lambdaworks commit --- crates/stark-felt/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/stark-felt/Cargo.toml b/crates/stark-felt/Cargo.toml index 4d9dfdf..5d93f27 100644 --- a/crates/stark-felt/Cargo.toml +++ b/crates/stark-felt/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" [dependencies] bitvec = { version = "1.0.1", default-features = false } serde = { version = "1.0.163", optional = true, default-features = false } -lambdaworks-math = { git = "https://github.com/lambdaclass/lambdaworks.git", rev = "4964ccf29e3cfac97e4ca1a97e500cde6fed143c", default_features = false} +lambdaworks-math = { git = "https://github.com/lambdaclass/lambdaworks.git", rev = "731e27c2c8ed3de66bceacd15e2b6595a2acdc83", default_features = false} [features] default = ["std", "serde"] From 105250cbf8bad757c9dd5ad09faaa30bc025256a Mon Sep 17 00:00:00 2001 From: "juan.mv" Date: Fri, 1 Sep 2023 12:50:52 -0300 Subject: [PATCH 76/97] Add arbitrary feature --- crates/stark-felt/Cargo.toml | 2 ++ .../{arbitrary.rs => arbitrary_proptest.rs} | 0 crates/stark-felt/src/lib.rs | 20 ++++++++++++++++++- 3 files changed, 21 insertions(+), 1 deletion(-) rename crates/stark-felt/src/{arbitrary.rs => arbitrary_proptest.rs} (100%) diff --git a/crates/stark-felt/Cargo.toml b/crates/stark-felt/Cargo.toml index 5d93f27..3b342bd 100644 --- a/crates/stark-felt/Cargo.toml +++ b/crates/stark-felt/Cargo.toml @@ -14,11 +14,13 @@ readme = "README.md" bitvec = { version = "1.0.1", default-features = false } serde = { version = "1.0.163", optional = true, default-features = false } lambdaworks-math = { git = "https://github.com/lambdaclass/lambdaworks.git", rev = "731e27c2c8ed3de66bceacd15e2b6595a2acdc83", default_features = false} +arbitrary = { version = "1.3.0", optional = true, default-features = false } [features] default = ["std", "serde"] std = [] alloc = ["serde?/alloc"] +arbitrary = ["std", "dep:arbitrary"] [dev-dependencies] proptest = "1.1.0" diff --git a/crates/stark-felt/src/arbitrary.rs b/crates/stark-felt/src/arbitrary_proptest.rs similarity index 100% rename from crates/stark-felt/src/arbitrary.rs rename to crates/stark-felt/src/arbitrary_proptest.rs diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 2595c95..ca04994 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -5,7 +5,7 @@ use core::ops::{Add, Neg}; use bitvec::array::BitArray; #[cfg(test)] -mod arbitrary; +mod arbitrary_proptest; #[cfg(target_pointer_width = "64")] pub type BitArrayStore = [u64; 4]; @@ -28,6 +28,9 @@ use lambdaworks_math::{ unsigned_integer::element::UnsignedInteger, }; +#[cfg(feature = "arbitrary")] +use arbitrary::{self, Arbitrary, Unstructured}; + /// Definition of the Field Element type. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Felt(FieldElement); @@ -249,6 +252,21 @@ impl Felt { } } +#[cfg(feature = "arbitrary")] +impl<'a> Arbitrary<'a> for Felt { + fn arbitrary(u: &mut Unstructured) -> arbitrary::Result { + let hex_chars = [ + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", + ]; + let mut hex_string = String::new(); + for _ in 0..63 { + hex_string.push_str(u.choose(&hex_chars)?); + } + let felt = FieldElement::::from_hex_unchecked(&hex_string); + Ok(Felt(felt)) + } +} + /// Defaults to [Felt::ZERO]. impl Default for Felt { fn default() -> Self { From 2ffab31dd369151b469ceea43a83ffec572fbcc9 Mon Sep 17 00:00:00 2001 From: Pedro Fontana Date: Fri, 1 Sep 2023 16:17:02 -0300 Subject: [PATCH 77/97] cargo clippy --- crates/stark-felt/src/lib.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index ca04994..c841a7e 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -363,7 +363,7 @@ impl From for Felt { if value.is_negative() { Self::ZERO - Self(FieldElement::from(&UnsignedInteger::from( - value.abs() as u64 + value.unsigned_abs(), ))) } else { Self(FieldElement::from(&UnsignedInteger::from(value as u64))) @@ -376,7 +376,7 @@ impl From for Felt { if value.is_negative() { Self::ZERO - Self(FieldElement::from(&UnsignedInteger::from( - value.abs() as u128 + value.unsigned_abs(), ))) } else { Self(FieldElement::from(&UnsignedInteger::from(value as u128))) @@ -1004,9 +1004,8 @@ mod errors { mod test { use core::ops::Shl; - use crate::arbitrary::nonzero_felt; - use super::*; + use crate::arbitrary_proptest::nonzero_felt; use proptest::prelude::*; use serde_test::{assert_de_tokens, assert_ser_tokens, Configure, Token}; From 192551b364d5b2a39c0cbcb9c58274be6a28a109 Mon Sep 17 00:00:00 2001 From: "juan.mv" Date: Fri, 1 Sep 2023 17:43:02 -0300 Subject: [PATCH 78/97] Fix imports; run linter --- crates/stark-felt/src/lib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 8ad2f95..a365967 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -1002,7 +1002,10 @@ mod errors { #[cfg(test)] mod test { - use super::alloc::{format, string::String, vec::Vec}; + use super::{ + alloc::{format, string::String, vec::Vec}, + Felt, FieldElement, NonZeroFelt, + }; use crate::arbitrary_proptest::nonzero_felt; use core::ops::Shl; use proptest::prelude::*; From 9fd1992641d1613dca4629bed19175e26a5ac8b1 Mon Sep 17 00:00:00 2001 From: Mario Rugiero Date: Wed, 20 Sep 2023 10:57:02 -0300 Subject: [PATCH 79/97] Pin lambdaworks version --- crates/stark-felt/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/stark-felt/Cargo.toml b/crates/stark-felt/Cargo.toml index 3b342bd..619f924 100644 --- a/crates/stark-felt/Cargo.toml +++ b/crates/stark-felt/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" [dependencies] bitvec = { version = "1.0.1", default-features = false } serde = { version = "1.0.163", optional = true, default-features = false } -lambdaworks-math = { git = "https://github.com/lambdaclass/lambdaworks.git", rev = "731e27c2c8ed3de66bceacd15e2b6595a2acdc83", default_features = false} +lambdaworks-math = { version = "0.1.4", default_features = false} arbitrary = { version = "1.3.0", optional = true, default-features = false } [features] From a8cfbadab598e12d1e988d0f50f0e51488a15f30 Mon Sep 17 00:00:00 2001 From: Mario Rugiero Date: Thu, 21 Sep 2023 17:16:34 -0300 Subject: [PATCH 80/97] Fixes to new APIs --- crates/stark-felt/src/lib.rs | 53 ++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 29 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index a365967..cba1536 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -152,7 +152,7 @@ impl Felt { /// Multiplicative inverse. pub fn inverse(&self) -> Option { - Some(Self(self.0.inv())) + self.0.inv().map(Self).ok() } /// Finds the square root. There may be 2 roots for each square, and the lower one is returned. @@ -176,31 +176,17 @@ impl Felt { } /// Modular multiplication. - pub fn mul_mod(&self, rhs: &Self, p: &Self) -> Self { - Self(FieldElement::from( - &(self.0 * rhs.0) - .representative() - .div_rem(&p.0.representative()) - .1, - )) + pub fn mul_mod(&self, rhs: &Self, p: &NonZeroFelt) -> Self { + (self * rhs).div_rem(p).1 } /// Modular multiplicative inverse. - pub fn inverse_mod(&self, p: &Self) -> Self { - Self(FieldElement::from( - &self - .0 - .inv() - .representative() - .div_rem(&p.0.representative()) - .1, - )) + pub fn inverse_mod(&self, p: &NonZeroFelt) -> Option { + self.inverse().map(|x| x.div_rem(p).1) } - pub fn mod_floor(&self, n: &Self) -> Self { - Self(FieldElement::from( - &(self.0).representative().div_rem(&n.0.representative()).1, - )) + pub fn mod_floor(&self, n: &NonZeroFelt) -> Self { + self.div_rem(n).1 } pub fn to_u32(&self) -> Option { @@ -1123,8 +1109,9 @@ mod test { } #[test] - fn mod_floor_in_range(x in any::(), n in any::()) { - let x_mod_n = x.mod_floor(&n); + fn mod_floor_in_range(x in any::(), n in nonzero_felt()) { + let nzn = NonZeroFelt(n.0); + let x_mod_n = x.mod_floor(&nzn); prop_assert!(x_mod_n <= Felt::MAX); prop_assert!(x_mod_n < n); } @@ -1207,15 +1194,23 @@ mod test { } #[test] - fn inverse_mod_in_range(x in any::(), p in any::()) { - prop_assert!(x.inverse_mod(&p) <= Felt::MAX); - prop_assert!(x.inverse_mod(&p) < p); + fn inverse_mod_of_zero_is_none(p in nonzero_felt()) { + let nzp = NonZeroFelt(p.0); + prop_assert!(Felt::ZERO.inverse_mod(&nzp).is_none()); + } + + #[test] + fn inverse_mod_in_range(x in nonzero_felt(), p in nonzero_felt()) { + let nzp = NonZeroFelt(p.0); + prop_assert!(x.inverse_mod(&nzp) <= Some(Felt::MAX)); + prop_assert!(x.inverse_mod(&nzp) < Some(p)); } #[test] - fn mul_mod_in_range(x in any::(), y in any::(), p in any::()) { - prop_assert!(x.mul_mod(&y, &p) <= Felt::MAX); - prop_assert!(x.mul_mod(&y, &p) < p); + fn mul_mod_in_range(x in any::(), y in any::(), p in nonzero_felt()) { + let nzp = NonZeroFelt(p.0); + prop_assert!(x.mul_mod(&y, &nzp) <= Felt::MAX); + prop_assert!(x.mul_mod(&y, &nzp) < p); } #[test] From 77132a34b2e0ce8eda8606838561cdf3a0d77648 Mon Sep 17 00:00:00 2001 From: Mario Rugiero Date: Fri, 22 Sep 2023 11:27:28 -0300 Subject: [PATCH 81/97] whitespace --- crates/stark-felt/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/stark-felt/Cargo.toml b/crates/stark-felt/Cargo.toml index 619f924..deef2a7 100644 --- a/crates/stark-felt/Cargo.toml +++ b/crates/stark-felt/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" [dependencies] bitvec = { version = "1.0.1", default-features = false } serde = { version = "1.0.163", optional = true, default-features = false } -lambdaworks-math = { version = "0.1.4", default_features = false} +lambdaworks-math = { version = "0.1.4", default_features = false } arbitrary = { version = "1.3.0", optional = true, default-features = false } [features] From 54e3ba593e844c8abaad5684a7afea2a40fd7492 Mon Sep 17 00:00:00 2001 From: Mario Rugiero Date: Thu, 28 Sep 2023 15:56:28 -0300 Subject: [PATCH 82/97] Bump lambdaworks version --- crates/stark-felt/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/stark-felt/Cargo.toml b/crates/stark-felt/Cargo.toml index deef2a7..b9dbf30 100644 --- a/crates/stark-felt/Cargo.toml +++ b/crates/stark-felt/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" [dependencies] bitvec = { version = "1.0.1", default-features = false } serde = { version = "1.0.163", optional = true, default-features = false } -lambdaworks-math = { version = "0.1.4", default_features = false } +lambdaworks-math = { version = "0.2.0", default_features = false } arbitrary = { version = "1.3.0", optional = true, default-features = false } [features] From 4fb89b3c082d48518e8e5968980d6af9022a8949 Mon Sep 17 00:00:00 2001 From: Mario Rugiero Date: Thu, 28 Sep 2023 19:05:46 -0300 Subject: [PATCH 83/97] Implement `FromPrimitive` and `From` with primitive T --- crates/stark-felt/Cargo.toml | 1 + crates/stark-felt/src/lib.rs | 85 +++++++++++++++++------------------- 2 files changed, 41 insertions(+), 45 deletions(-) diff --git a/crates/stark-felt/Cargo.toml b/crates/stark-felt/Cargo.toml index b9dbf30..d2968dc 100644 --- a/crates/stark-felt/Cargo.toml +++ b/crates/stark-felt/Cargo.toml @@ -15,6 +15,7 @@ bitvec = { version = "1.0.1", default-features = false } serde = { version = "1.0.163", optional = true, default-features = false } lambdaworks-math = { version = "0.2.0", default_features = false } arbitrary = { version = "1.3.0", optional = true, default-features = false } +num-traits = { version = "0.2.16", default-features = false } [features] default = ["std", "serde"] diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index cba1536..e489cf3 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -3,6 +3,7 @@ use core::ops::{Add, Neg}; use bitvec::array::BitArray; +use num_traits::FromPrimitive; #[cfg(test)] mod arbitrary_proptest; @@ -307,68 +308,62 @@ impl TryFrom<&Felt> for NonZeroFelt { } } -impl From for Felt { - fn from(value: usize) -> Self { - Self::from(value as u64) +impl FromPrimitive for Felt { + fn from_i64(value: i64) -> Option { + Self::from_i128(value as i128) } -} -impl From for Felt { - fn from(value: u8) -> Self { - Self::from(value as u64) + fn from_u64(value: u64) -> Option { + Self::from_u128(value as u128) } -} - -impl From for Felt { - fn from(value: u32) -> Self { - Self::from(value as u64) - } -} -impl From for Felt { - fn from(value: u64) -> Self { - Self(FieldElement::from(value)) - } -} - -impl From for Felt { - fn from(value: u128) -> Self { - Self(FieldElement::from(&UnsignedInteger::from(value))) + fn from_i128(value: i128) -> Option { + let mut res = Self(FieldElement::from(&UnsignedInteger::from(value.unsigned_abs()))); + if value.is_negative() { + res = -res; + } + Some(res) } -} -impl From for Felt { - fn from(value: i32) -> Self { - Self::from(value as i64) + fn from_u128(value: u128) -> Option { + Some(Self(FieldElement::from(&UnsignedInteger::from(value)))) } } -impl From for Felt { - fn from(value: i64) -> Self { - if value.is_negative() { - Self::ZERO - - Self(FieldElement::from(&UnsignedInteger::from( - value.unsigned_abs(), - ))) - } else { - Self(FieldElement::from(&UnsignedInteger::from(value as u64))) +macro_rules! impl_from_u128 { + ($type:ty) => { + impl From<$type> for Felt { + fn from(value: $type) -> Self { + Self::from_u128(value as u128).expect("conversion from primitive is infallible") + } } } } -impl From for Felt { - fn from(value: i128) -> Self { - if value.is_negative() { - Self::ZERO - - Self(FieldElement::from(&UnsignedInteger::from( - value.unsigned_abs(), - ))) - } else { - Self(FieldElement::from(&UnsignedInteger::from(value as u128))) +impl_from_u128!(u8); +impl_from_u128!(u16); +impl_from_u128!(u32); +impl_from_u128!(u64); +impl_from_u128!(u128); +impl_from_u128!(usize); + +macro_rules! impl_from_i128 { + ($type:ty) => { + impl From<$type> for Felt { + fn from(value: $type) -> Self { + Self::from_i128(value as i128).expect("conversion from primitive is infallible") + } } } } +impl_from_i128!(i8); +impl_from_i128!(i16); +impl_from_i128!(i32); +impl_from_i128!(i64); +impl_from_i128!(i128); +impl_from_i128!(isize); + impl Add<&Felt> for u64 { type Output = Option; From f1c17d1df63e54d7708c9c19ff0653a93432f1b1 Mon Sep 17 00:00:00 2001 From: Mario Rugiero Date: Fri, 29 Sep 2023 12:27:34 -0300 Subject: [PATCH 84/97] Add docs --- crates/stark-felt/src/lib.rs | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index e489cf3..3c609de 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -130,7 +130,7 @@ impl Felt { BitArray::new(limbs) } - /// Checks if `self` is equal to [Felt::Zero]. + /// Checks if `self` is equal to [Felt::ZERO]. pub fn is_zero(&self) -> bool { *self == Felt::ZERO } @@ -139,19 +139,20 @@ impl Felt { Self(self.0 / rhs.0) } - /// Floor division. + /// Truncated quotient between `self` and `rhs`. pub fn floor_div(&self, rhs: &NonZeroFelt) -> Self { Self(FieldElement::from( &(self.0.representative().div_rem(&rhs.0.representative())).0, )) } + /// Quotient and remainder between `self` and `rhs`. pub fn div_rem(&self, rhs: &NonZeroFelt) -> (Self, Self) { let (q, r) = self.0.representative().div_rem(&rhs.0.representative()); (Self(FieldElement::from(&q)), Self(FieldElement::from(&r))) } - /// Multiplicative inverse. + /// Multiplicative inverse inside field. pub fn inverse(&self) -> Option { self.0.inv().map(Self).ok() } @@ -172,28 +173,32 @@ impl Felt { Self(self.0.pow(exponent)) } + /// Raises `self` to the power of `exponent`. pub fn pow_felt(&self, exponent: &Felt) -> Self { Self(self.0.pow(exponent.0.representative())) } - /// Modular multiplication. + /// Modular multiplication between `self` and `rhs` modulo `p`. pub fn mul_mod(&self, rhs: &Self, p: &NonZeroFelt) -> Self { (self * rhs).div_rem(p).1 } - /// Modular multiplicative inverse. + /// Modular inverse of `self` modulo `p`. pub fn inverse_mod(&self, p: &NonZeroFelt) -> Option { self.inverse().map(|x| x.div_rem(p).1) } + /// Remainder of dividing `self` by `n` as integers. pub fn mod_floor(&self, n: &NonZeroFelt) -> Self { self.div_rem(n).1 } + /// Checked cast `self` to `u32`. pub fn to_u32(&self) -> Option { self.to_u64().and_then(|n| n.try_into().ok()) } + /// Checked cast `self` to `u64`. pub fn to_u64(&self) -> Option { match self.0.representative().limbs { [0, 0, 0, val] => Some(val), @@ -201,16 +206,19 @@ impl Felt { } } + /// Checked cast `self` to `usize`. pub fn to_usize(&self) -> Option { self.to_u64()?.try_into().ok() } + /// Parse a hex-encoded number into `Felt`. pub fn from_hex(hex_string: &str) -> Result { FieldElement::from_hex(hex_string) .map(Self) .map_err(|_| FromStrError) } + /// Parse a decimal-encoded number into `Felt`. pub fn from_dec_str(dec_string: &str) -> Result { if dec_string.starts_with('-') { UnsignedInteger::from_dec_str(dec_string.strip_prefix('-').unwrap()) @@ -223,16 +231,21 @@ impl Felt { } } + /// Convert `self`'s representative into an array of `u64` digits, + /// least significant digits first. pub fn to_le_digits(&self) -> [u64; 4] { let mut limbs = self.0.representative().limbs; limbs.reverse(); limbs } + /// Convert `self`'s representative into an array of `u64` digits, + /// most significant digits first. pub fn to_be_digits(&self) -> [u64; 4] { self.0.representative().limbs } + /// Count the minimum number of bits needed to express `self`'s representative. pub fn bits(&self) -> u32 { self.0.representative().bits_le() as u32 } From c2945cfde8fe12744e934e60a2366abbd6250524 Mon Sep 17 00:00:00 2001 From: Mario Rugiero Date: Fri, 29 Sep 2023 12:47:11 -0300 Subject: [PATCH 85/97] Implement ToPrimitive --- crates/stark-felt/src/lib.rs | 43 ++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 3c609de..35c699a 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -3,7 +3,7 @@ use core::ops::{Add, Neg}; use bitvec::array::BitArray; -use num_traits::FromPrimitive; +use num_traits::{FromPrimitive, ToPrimitive}; #[cfg(test)] mod arbitrary_proptest; @@ -193,24 +193,6 @@ impl Felt { self.div_rem(n).1 } - /// Checked cast `self` to `u32`. - pub fn to_u32(&self) -> Option { - self.to_u64().and_then(|n| n.try_into().ok()) - } - - /// Checked cast `self` to `u64`. - pub fn to_u64(&self) -> Option { - match self.0.representative().limbs { - [0, 0, 0, val] => Some(val), - _ => None, - } - } - - /// Checked cast `self` to `usize`. - pub fn to_usize(&self) -> Option { - self.to_u64()?.try_into().ok() - } - /// Parse a hex-encoded number into `Felt`. pub fn from_hex(hex_string: &str) -> Result { FieldElement::from_hex(hex_string) @@ -343,6 +325,29 @@ impl FromPrimitive for Felt { } } +// TODO: we need to decide whether we want conversions to signed primitives +// will support converting the high end of the field to negative. +impl ToPrimitive for Felt { + fn to_u64(&self) -> Option { + self.to_u128().and_then(|x| u64::try_from(x).ok()) + } + + fn to_i64(&self) -> Option { + self.to_u128().and_then(|x| i64::try_from(x).ok()) + } + + fn to_u128(&self) -> Option { + match self.0.representative().limbs { + [0, 0, hi, lo] => Some((lo as u128) | ((hi as u128) << 64)), + _ => None, + } + } + + fn to_i128(&self) -> Option { + self.to_u128().and_then(|x| i128::try_from(x).ok()) + } +} + macro_rules! impl_from_u128 { ($type:ty) => { impl From<$type> for Felt { From 1840022e0f02780a5bfd39b26eb5a1793f70d058 Mon Sep 17 00:00:00 2001 From: Mario Rugiero Date: Mon, 2 Oct 2023 11:42:31 -0300 Subject: [PATCH 86/97] cargo fmt --- crates/stark-felt/src/lib.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 35c699a..5b2c28e 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -313,7 +313,9 @@ impl FromPrimitive for Felt { } fn from_i128(value: i128) -> Option { - let mut res = Self(FieldElement::from(&UnsignedInteger::from(value.unsigned_abs()))); + let mut res = Self(FieldElement::from(&UnsignedInteger::from( + value.unsigned_abs(), + ))); if value.is_negative() { res = -res; } @@ -355,7 +357,7 @@ macro_rules! impl_from_u128 { Self::from_u128(value as u128).expect("conversion from primitive is infallible") } } - } + }; } impl_from_u128!(u8); @@ -372,7 +374,7 @@ macro_rules! impl_from_i128 { Self::from_i128(value as i128).expect("conversion from primitive is infallible") } } - } + }; } impl_from_i128!(i8); From b32c7dadd2a989b4258f7045d89e0746d62f7337 Mon Sep 17 00:00:00 2001 From: Mario Rugiero Date: Tue, 3 Oct 2023 15:16:02 -0300 Subject: [PATCH 87/97] From first, FromPrimitive later --- crates/stark-felt/src/lib.rs | 87 ++++++++++++++++++------------------ 1 file changed, 43 insertions(+), 44 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 5b2c28e..cf199de 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -303,27 +303,60 @@ impl TryFrom<&Felt> for NonZeroFelt { } } -impl FromPrimitive for Felt { - fn from_i64(value: i64) -> Option { - Self::from_i128(value as i128) - } - - fn from_u64(value: u64) -> Option { - Self::from_u128(value as u128) +impl From for Felt { + fn from(value: u128) -> Felt { + Self(FieldElement::from(&UnsignedInteger::from(value))) } +} - fn from_i128(value: i128) -> Option { +impl From for Felt { + fn from(value: i128) -> Felt { let mut res = Self(FieldElement::from(&UnsignedInteger::from( value.unsigned_abs(), ))); if value.is_negative() { res = -res; } - Some(res) + res + } +} + +macro_rules! impl_from { + ($from:ty, $with:ty) => { + impl From<$from> for Felt { + fn from(value: $from) -> Self { + (value as $with).into() + } + } + }; +} + +impl_from!(u8, u128); +impl_from!(u16, u128); +impl_from!(u32, u128); +impl_from!(u64, u128); +impl_from!(usize, u128); +impl_from!(i8, i128); +impl_from!(i16, i128); +impl_from!(i32, i128); +impl_from!(i64, i128); +impl_from!(isize, i128); + +impl FromPrimitive for Felt { + fn from_i64(value: i64) -> Option { + Some(value.into()) + } + + fn from_u64(value: u64) -> Option { + Some(value.into()) + } + + fn from_i128(value: i128) -> Option { + Some(value.into()) } fn from_u128(value: u128) -> Option { - Some(Self(FieldElement::from(&UnsignedInteger::from(value)))) + Some(value.into()) } } @@ -350,40 +383,6 @@ impl ToPrimitive for Felt { } } -macro_rules! impl_from_u128 { - ($type:ty) => { - impl From<$type> for Felt { - fn from(value: $type) -> Self { - Self::from_u128(value as u128).expect("conversion from primitive is infallible") - } - } - }; -} - -impl_from_u128!(u8); -impl_from_u128!(u16); -impl_from_u128!(u32); -impl_from_u128!(u64); -impl_from_u128!(u128); -impl_from_u128!(usize); - -macro_rules! impl_from_i128 { - ($type:ty) => { - impl From<$type> for Felt { - fn from(value: $type) -> Self { - Self::from_i128(value as i128).expect("conversion from primitive is infallible") - } - } - }; -} - -impl_from_i128!(i8); -impl_from_i128!(i16); -impl_from_i128!(i32); -impl_from_i128!(i64); -impl_from_i128!(i128); -impl_from_i128!(isize); - impl Add<&Felt> for u64 { type Output = Option; From 13fab09b3fa16896b882ff52986c0da8741748c4 Mon Sep 17 00:00:00 2001 From: Mario Rugiero Date: Wed, 4 Oct 2023 14:38:04 -0300 Subject: [PATCH 88/97] Remove bitwise operators --- crates/stark-felt/src/lib.rs | 144 ----------------------------------- 1 file changed, 144 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index cf199de..b5cb609 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -690,150 +690,6 @@ mod arithmetic { } } - impl ops::Shl for Felt { - type Output = Felt; - fn shl(self, rhs: usize) -> Self::Output { - Self(FieldElement::from(&self.0.representative().shl(rhs))) - } - } - - impl ops::Shl for &Felt { - type Output = Felt; - - fn shl(self, rhs: usize) -> Self::Output { - Felt(FieldElement::from(&self.0.representative().shl(rhs))) - } - } - - impl ops::Shr for Felt { - type Output = Felt; - fn shr(self, rhs: usize) -> Self::Output { - Self(FieldElement::from(&self.0.representative().shr(rhs))) - } - } - - impl ops::Shr for &Felt { - type Output = Felt; - - fn shr(self, rhs: usize) -> Self::Output { - Felt(FieldElement::from(&self.0.representative().shr(rhs))) - } - } - - impl ops::BitAnd for Felt { - type Output = Felt; - fn bitand(self, rhs: Felt) -> Self::Output { - Self(FieldElement::from( - &self.0.representative().bitand(rhs.0.representative()), - )) - } - } - - impl ops::BitAnd for &Felt { - type Output = Felt; - - fn bitand(self, rhs: Felt) -> Self::Output { - Felt(FieldElement::from( - &self.0.representative().bitand(rhs.0.representative()), - )) - } - } - - impl ops::BitAnd<&Felt> for Felt { - type Output = Felt; - fn bitand(self, rhs: &Felt) -> Self::Output { - Self(FieldElement::from( - &self.0.representative().bitand(rhs.0.representative()), - )) - } - } - - impl ops::BitAnd<&Felt> for &Felt { - type Output = Felt; - - fn bitand(self, rhs: &Felt) -> Self::Output { - Felt(FieldElement::from( - &self.0.representative().bitand(rhs.0.representative()), - )) - } - } - - impl ops::BitOr for Felt { - type Output = Felt; - fn bitor(self, rhs: Felt) -> Self::Output { - Self(FieldElement::from( - &self.0.representative().bitor(rhs.0.representative()), - )) - } - } - - impl ops::BitOr for &Felt { - type Output = Felt; - - fn bitor(self, rhs: Felt) -> Self::Output { - Felt(FieldElement::from( - &self.0.representative().bitor(rhs.0.representative()), - )) - } - } - - impl ops::BitOr<&Felt> for Felt { - type Output = Felt; - fn bitor(self, rhs: &Felt) -> Self::Output { - Self(FieldElement::from( - &self.0.representative().bitor(rhs.0.representative()), - )) - } - } - - impl ops::BitOr<&Felt> for &Felt { - type Output = Felt; - - fn bitor(self, rhs: &Felt) -> Self::Output { - Felt(FieldElement::from( - &self.0.representative().bitor(rhs.0.representative()), - )) - } - } - - impl ops::BitXor for Felt { - type Output = Felt; - fn bitxor(self, rhs: Felt) -> Self::Output { - Self(FieldElement::from( - &self.0.representative().bitxor(rhs.0.representative()), - )) - } - } - - impl ops::BitXor for &Felt { - type Output = Felt; - - fn bitxor(self, rhs: Felt) -> Self::Output { - Felt(FieldElement::from( - &self.0.representative().bitxor(rhs.0.representative()), - )) - } - } - - impl ops::BitXor<&Felt> for Felt { - type Output = Felt; - fn bitxor(self, rhs: &Felt) -> Self::Output { - Self(FieldElement::from( - &self.0.representative().bitxor(rhs.0.representative()), - )) - } - } - - impl ops::BitXor<&Felt> for &Felt { - type Output = Felt; - - fn bitxor(self, rhs: &Felt) -> Self::Output { - Felt(FieldElement::from( - &self.0.representative().bitxor(rhs.0.representative()), - )) - } - } - impl iter::Sum for Felt { fn sum>(iter: I) -> Self { let mut base = Self::ZERO; From 0befb5378b1364872c23271483fa2b53c1fb7145 Mon Sep 17 00:00:00 2001 From: Mario Rugiero Date: Wed, 4 Oct 2023 14:39:37 -0300 Subject: [PATCH 89/97] Remove operations with usize, expect fixed width operands --- crates/stark-felt/src/lib.rs | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index b5cb609..0093636 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -503,24 +503,6 @@ mod arithmetic { } } - /// Field addition. Never overflows/underflows. - impl ops::Add for Felt { - type Output = Felt; - - fn add(self, rhs: usize) -> Self::Output { - self + rhs as u64 - } - } - - /// Field addition. Never overflows/underflows. - impl ops::Add for &Felt { - type Output = Felt; - - fn add(self, rhs: usize) -> Self::Output { - self + rhs as u64 - } - } - /// Field subtraction. Never overflows/underflows. impl ops::SubAssign for Felt { fn sub_assign(&mut self, rhs: Felt) { @@ -589,22 +571,6 @@ mod arithmetic { } } - /// Field subtraction. Never overflows/underflows. - impl ops::Sub for usize { - type Output = Felt; - fn sub(self, rhs: Felt) -> Self::Output { - self as u64 - rhs - } - } - - /// Field subtraction. Never overflows/underflows. - impl ops::Sub<&Felt> for usize { - type Output = Felt; - fn sub(self, rhs: &Felt) -> Self::Output { - self as u64 - rhs - } - } - /// Field subtraction. Never overflows/underflows. impl ops::Sub for Felt { type Output = Felt; From 2db8cfd67d3177fddfa75c0b8024158fa699b33d Mon Sep 17 00:00:00 2001 From: Mario Rugiero Date: Wed, 4 Oct 2023 14:45:00 -0300 Subject: [PATCH 90/97] Return Option for u64 - Felt --- crates/stark-felt/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 0093636..43ee8ae 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -556,18 +556,18 @@ mod arithmetic { /// Field subtraction. Never overflows/underflows. #[allow(clippy::suspicious_arithmetic_impl)] impl ops::Sub for u64 { - type Output = Felt; + type Output = Option; fn sub(self, rhs: Felt) -> Self::Output { - rhs.neg() + self + self + &rhs.neg() } } /// Field subtraction. Never overflows/underflows. #[allow(clippy::suspicious_arithmetic_impl)] impl ops::Sub<&Felt> for u64 { - type Output = Felt; + type Output = Option; fn sub(self, rhs: &Felt) -> Self::Output { - rhs.neg() + self + self + &rhs.neg() } } From 00673e995ea9f141e1afcb35f143cfb03d4b217c Mon Sep 17 00:00:00 2001 From: Mario Rugiero Date: Wed, 4 Oct 2023 15:06:58 -0300 Subject: [PATCH 91/97] Simplify and explain arbitrary --- crates/stark-felt/src/lib.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 43ee8ae..5e0a4fd 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -235,15 +235,13 @@ impl Felt { #[cfg(feature = "arbitrary")] impl<'a> Arbitrary<'a> for Felt { + // Creates an arbitrary `Felt` from unstructured input for fuzzing. + // It uses the default implementation to create the internal limbs and then + // uses the usual constructors from `lambdaworks-math`. fn arbitrary(u: &mut Unstructured) -> arbitrary::Result { - let hex_chars = [ - "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", - ]; - let mut hex_string = String::new(); - for _ in 0..63 { - hex_string.push_str(u.choose(&hex_chars)?); - } - let felt = FieldElement::::from_hex_unchecked(&hex_string); + let limbs = <[u64; 4]>::arbitrary(u); + let uint = UnsignedInteger::from_limbs(limbs); + let felt = FieldElement::from(uint); Ok(Felt(felt)) } } From 8d703875b9571f7797e39a4f0f12f0c95f4ccd0e Mon Sep 17 00:00:00 2001 From: Mario Rugiero Date: Wed, 4 Oct 2023 18:17:50 -0300 Subject: [PATCH 92/97] Fix arbitrary (and test with the feature enabled!) --- crates/stark-felt/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 5e0a4fd..2bff8bc 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -239,9 +239,9 @@ impl<'a> Arbitrary<'a> for Felt { // It uses the default implementation to create the internal limbs and then // uses the usual constructors from `lambdaworks-math`. fn arbitrary(u: &mut Unstructured) -> arbitrary::Result { - let limbs = <[u64; 4]>::arbitrary(u); + let limbs = <[u64; 4]>::arbitrary(u)?; let uint = UnsignedInteger::from_limbs(limbs); - let felt = FieldElement::from(uint); + let felt = FieldElement::new(uint); Ok(Felt(felt)) } } From af3320c7f7dc5a048d42135886393679ba61f6d0 Mon Sep 17 00:00:00 2001 From: Mario Rugiero Date: Thu, 5 Oct 2023 11:27:27 -0300 Subject: [PATCH 93/97] Impl Zero --- crates/stark-felt/src/arbitrary_proptest.rs | 1 + crates/stark-felt/src/lib.rs | 21 ++++++++++++--------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/crates/stark-felt/src/arbitrary_proptest.rs b/crates/stark-felt/src/arbitrary_proptest.rs index 28ae9e5..49ea020 100644 --- a/crates/stark-felt/src/arbitrary_proptest.rs +++ b/crates/stark-felt/src/arbitrary_proptest.rs @@ -1,4 +1,5 @@ use lambdaworks_math::{field::element::FieldElement, unsigned_integer::element::UnsignedInteger}; +use num_traits::Zero; use proptest::prelude::*; use crate::Felt; diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 2bff8bc..e321ec1 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -3,7 +3,7 @@ use core::ops::{Add, Neg}; use bitvec::array::BitArray; -use num_traits::{FromPrimitive, ToPrimitive}; +use num_traits::{FromPrimitive, ToPrimitive, Zero}; #[cfg(test)] mod arbitrary_proptest; @@ -130,10 +130,6 @@ impl Felt { BitArray::new(limbs) } - /// Checks if `self` is equal to [Felt::ZERO]. - pub fn is_zero(&self) -> bool { - *self == Felt::ZERO - } /// Finite field division. pub fn field_div(&self, rhs: &NonZeroFelt) -> Self { Self(self.0 / rhs.0) @@ -381,6 +377,16 @@ impl ToPrimitive for Felt { } } +impl Zero for Felt { + fn is_zero(&self) -> bool { + *self == Felt::ZERO + } + + fn zero() -> Felt { + Felt::ZERO + } +} + impl Add<&Felt> for u64 { type Output = Option; @@ -822,10 +828,7 @@ mod errors { #[cfg(test)] mod test { - use super::{ - alloc::{format, string::String, vec::Vec}, - Felt, FieldElement, NonZeroFelt, - }; + use super::*; use crate::arbitrary_proptest::nonzero_felt; use core::ops::Shl; use proptest::prelude::*; From 95b90ca932d69a5c4189435c1e359170a2b8e88a Mon Sep 17 00:00:00 2001 From: Mario Rugiero Date: Thu, 5 Oct 2023 11:28:37 -0300 Subject: [PATCH 94/97] bits -> usize --- crates/stark-felt/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index e321ec1..92d162c 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -224,8 +224,8 @@ impl Felt { } /// Count the minimum number of bits needed to express `self`'s representative. - pub fn bits(&self) -> u32 { - self.0.representative().bits_le() as u32 + pub fn bits(&self) -> usize { + self.0.representative().bits_le() } } From b154e7e5f2aeb11fbd3c24d27f8f0d3dfd079886 Mon Sep 17 00:00:00 2001 From: Mario Rugiero Date: Fri, 6 Oct 2023 15:55:20 -0300 Subject: [PATCH 95/97] Define pow of Into --- crates/stark-felt/src/lib.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index 92d162c..beb35ae 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -165,8 +165,8 @@ impl Felt { } /// Raises `self` to the power of `exponent`. - pub fn pow(&self, exponent: u128) -> Self { - Self(self.0.pow(exponent)) + pub fn pow(&self, exponent: impl Into) -> Self { + Self(self.0.pow(exponent.into())) } /// Raises `self` to the power of `exponent`. @@ -1150,14 +1150,14 @@ mod test { #[test] fn pow_operations() { - assert_eq!(Felt::ONE.pow(5), Felt::ONE); - assert_eq!(Felt::ZERO.pow(5), Felt::ZERO); - assert_eq!(Felt::THREE.pow(0), Felt::ONE); + assert_eq!(Felt::ONE.pow(5u32), Felt::ONE); + assert_eq!(Felt::ZERO.pow(5u32), Felt::ZERO); + assert_eq!(Felt::THREE.pow(0u32), Felt::ONE); assert_eq!( - Felt(FieldElement::from(200)).pow(4), + Felt(FieldElement::from(200)).pow(4u32), Felt(FieldElement::from(1600000000)) ); - assert_eq!(Felt::MAX.pow(9), Felt::MAX); + assert_eq!(Felt::MAX.pow(9u32), Felt::MAX); } #[test] From e5037925d9c5a6267e7da6721ec31f59626c3bc1 Mon Sep 17 00:00:00 2001 From: Mario Rugiero Date: Tue, 10 Oct 2023 12:00:11 -0300 Subject: [PATCH 96/97] Fix alloc --- crates/stark-felt/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index beb35ae..b34ec7d 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -829,6 +829,7 @@ mod errors { #[cfg(test)] mod test { use super::*; + use super::alloc::{format, string::String, vec::Vec}; use crate::arbitrary_proptest::nonzero_felt; use core::ops::Shl; use proptest::prelude::*; From cc95ba2a32655cd2c222797055fd18c83e0a657f Mon Sep 17 00:00:00 2001 From: Mario Rugiero Date: Tue, 10 Oct 2023 12:01:34 -0300 Subject: [PATCH 97/97] cargo fmt --- crates/stark-felt/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/stark-felt/src/lib.rs b/crates/stark-felt/src/lib.rs index b34ec7d..12c0328 100644 --- a/crates/stark-felt/src/lib.rs +++ b/crates/stark-felt/src/lib.rs @@ -828,8 +828,8 @@ mod errors { #[cfg(test)] mod test { - use super::*; use super::alloc::{format, string::String, vec::Vec}; + use super::*; use crate::arbitrary_proptest::nonzero_felt; use core::ops::Shl; use proptest::prelude::*;