From 6aaa08266cc0a172af1bff8e0e8f6c16bfeddf89 Mon Sep 17 00:00:00 2001 From: Federica Date: Tue, 27 Jun 2023 12:21:47 -0300 Subject: [PATCH 01/60] 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 5a4fedcb..68a00330 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 52e2a0d1..6cb71273 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/60] 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 6cb71273..3f5e914c 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/60] 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 3f5e914c..65bc8122 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/60] 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 65bc8122..a7e233e4 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/60] 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 a7e233e4..e24d4cda 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/60] 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 e24d4cda..49a95bf9 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/60] 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 49a95bf9..6f8511d5 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/60] 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 6f8511d5..c667b237 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/60] 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 c667b237..2c752069 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/60] 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 2c752069..e7e6a521 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/60] 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 e7e6a521..5df3a24a 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/60] 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 5df3a24a..57df3dff 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/60] 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 57df3dff..3b49ec04 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/60] 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 3b49ec04..2f6c0360 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/60] 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 2f6c0360..22effaf4 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/60] 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 22effaf4..6c78a127 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/60] 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 6c78a127..08262f64 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/60] 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 08262f64..146ef986 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/60] 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 146ef986..49ace094 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/60] 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 49ace094..ca5a6242 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/60] 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 ca5a6242..4e65ad02 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/60] 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 4e65ad02..b216b063 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/60] 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 b216b063..8a64d569 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/60] 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 8a64d569..07946746 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/60] 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 07946746..5f9e06cd 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/60] 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 5f9e06cd..eea1fb1e 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/60] 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 eea1fb1e..0acd1abb 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/60] 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 0acd1abb..d68b3ba8 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/60] 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 d68b3ba8..f865fa88 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/60] 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 f865fa88..9be52939 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/60] 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 9be52939..07f29209 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/60] 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 07f29209..f28ab2eb 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/60] 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 f28ab2eb..8c77f673 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/60] 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 8c77f673..f1092d57 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/60] 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 f1092d57..439c90ff 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/60] 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 439c90ff..a75747dd 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/60] 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 a75747dd..7ed5ebc4 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/60] 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 7ed5ebc4..0f4482f4 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/60] 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 0f4482f4..df620551 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/60] 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 df620551..a7cb51a5 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/60] 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 a7cb51a5..44fa6cbd 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/60] 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 44fa6cbd..ccee1222 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/60] 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 ccee1222..193a36a6 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/60] 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 193a36a6..5d3c96dc 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/60] 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 5d3c96dc..c873b960 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/60] 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 c873b960..20946591 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/60] 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 20946591..bf97d153 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/60] 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 bf97d153..0f8e2fad 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/60] 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 0f8e2fad..f85f5ca1 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/60] 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 f85f5ca1..38a047af 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/60] 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 38a047af..c6a6cb49 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/60] 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 c6a6cb49..aa65892a 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/60] 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 aa65892a..5e8ac763 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/60] 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 5e8ac763..daa250b4 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/60] 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 daa250b4..8f9598ef 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/60] 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 68a00330..57b75fe7 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/60] 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 00000000..893331c9 --- /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/60] 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 8f9598ef..4c8ebb6b 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/60] 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 893331c9..456cec13 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/60] 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 35f21d02..7d227b2b 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 57b75fe7..a2fdfbd9 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"