diff --git a/math/src/elliptic_curve/short_weierstrass/curves/bls12_381/field_extension.rs b/math/src/elliptic_curve/short_weierstrass/curves/bls12_381/field_extension.rs index 41b07602d..2c1246bcf 100644 --- a/math/src/elliptic_curve/short_weierstrass/curves/bls12_381/field_extension.rs +++ b/math/src/elliptic_curve/short_weierstrass/curves/bls12_381/field_extension.rs @@ -8,10 +8,8 @@ use crate::field::{ fields::montgomery_backed_prime_fields::{IsModulus, MontgomeryBackendPrimeField}, traits::IsField, }; -use crate::unsigned_integer::element::U384; - -#[cfg(feature = "std")] use crate::traits::ByteConversion; +use crate::unsigned_integer::element::U384; pub const BLS12381_PRIME_FIELD_ORDER: U384 = U384::from_hex_unchecked("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab"); @@ -105,14 +103,15 @@ impl IsField for Degree2ExtensionField { } } -#[cfg(feature = "std")] impl ByteConversion for FieldElement { + #[cfg(feature = "std")] fn to_bytes_be(&self) -> Vec { let mut byte_slice = ByteConversion::to_bytes_be(&self.value()[0]); byte_slice.extend(ByteConversion::to_bytes_be(&self.value()[1])); byte_slice } + #[cfg(feature = "std")] fn to_bytes_le(&self) -> Vec { let mut byte_slice = ByteConversion::to_bytes_le(&self.value()[0]); byte_slice.extend(ByteConversion::to_bytes_le(&self.value()[1])); @@ -121,7 +120,7 @@ impl ByteConversion for FieldElement { fn from_bytes_be(bytes: &[u8]) -> Result where - Self: std::marker::Sized, + Self: core::marker::Sized, { const BYTES_PER_FIELD: usize = 48; let x0 = FieldElement::from_bytes_be(&bytes[0..BYTES_PER_FIELD])?; @@ -131,7 +130,7 @@ impl ByteConversion for FieldElement { fn from_bytes_le(bytes: &[u8]) -> Result where - Self: std::marker::Sized, + Self: core::marker::Sized, { const BYTES_PER_FIELD: usize = 48; let x0 = FieldElement::from_bytes_le(&bytes[0..BYTES_PER_FIELD])?; diff --git a/math/src/field/element.rs b/math/src/field/element.rs index c4c349c60..230b54792 100644 --- a/math/src/field/element.rs +++ b/math/src/field/element.rs @@ -1,6 +1,8 @@ use crate::errors::CreationError; use crate::field::errors::FieldError; use crate::field::traits::IsField; +#[cfg(feature = "lambdaworks-serde")] +use crate::traits::ByteConversion; use crate::unsigned_integer::element::UnsignedInteger; use crate::unsigned_integer::montgomery::MontgomeryAlgorithms; use crate::unsigned_integer::traits::IsUnsignedInteger; @@ -11,7 +13,7 @@ use core::iter::Sum; use core::marker::PhantomData; use core::ops::{Add, AddAssign, Div, Mul, Neg, Sub}; #[cfg(feature = "lambdaworks-serde")] -use serde::de::{self, Deserializer, MapAccess, Visitor}; +use serde::de::{self, Deserializer, MapAccess, SeqAccess, Visitor}; #[cfg(feature = "lambdaworks-serde")] use serde::ser::{Serialize, SerializeStruct, Serializer}; #[cfg(feature = "lambdaworks-serde")] @@ -442,7 +444,8 @@ impl Serialize for FieldElement { S: Serializer, { let mut state = serializer.serialize_struct("FieldElement", 1)?; - state.serialize_field("value", &F::representative(self.value()).to_string())?; + let data = self.value().to_bytes_be(); + state.serialize_field("value", &data)?; state.end() } } @@ -472,7 +475,7 @@ impl<'de, F: IsPrimeField> Deserialize<'de> for FieldElement { where M: MapAccess<'de>, { - let mut value = None; + let mut value: Option> = None; while let Some(key) = map.next_key()? { match key { Field::Value => { @@ -484,7 +487,24 @@ impl<'de, F: IsPrimeField> Deserialize<'de> for FieldElement { } } let value = value.ok_or_else(|| de::Error::missing_field("value"))?; - Ok(FieldElement::from_hex(value).unwrap()) + let val = F::BaseType::from_bytes_be(&value).unwrap(); + Ok(FieldElement::from_raw(&val)) + } + + fn visit_seq(self, mut seq: S) -> Result, S::Error> + where + S: SeqAccess<'de>, + { + let mut value: Option> = None; + while let Some(val) = seq.next_element()? { + if value.is_some() { + return Err(de::Error::duplicate_field("value")); + } + value = Some(val); + } + let value = value.ok_or_else(|| de::Error::missing_field("value"))?; + let val = F::BaseType::from_bytes_be(&value).unwrap(); + Ok(FieldElement::from_raw(&val)) } } diff --git a/math/src/field/extensions/cubic.rs b/math/src/field/extensions/cubic.rs index 36a77a083..54db89ec2 100644 --- a/math/src/field/extensions/cubic.rs +++ b/math/src/field/extensions/cubic.rs @@ -1,6 +1,7 @@ use crate::field::element::FieldElement; use crate::field::errors::FieldError; use crate::field::traits::IsField; +use crate::traits::ByteConversion; use core::fmt::Debug; use core::marker::PhantomData; @@ -24,6 +25,35 @@ pub trait HasCubicNonResidue { fn residue() -> FieldElement; } +impl ByteConversion for [FieldElement; 3] +where + F: IsField, +{ + #[cfg(feature = "std")] + fn to_bytes_be(&self) -> Vec { + unimplemented!() + } + + #[cfg(feature = "std")] + fn to_bytes_le(&self) -> Vec { + unimplemented!() + } + + fn from_bytes_be(_bytes: &[u8]) -> Result + where + Self: Sized, + { + unimplemented!() + } + + fn from_bytes_le(_bytes: &[u8]) -> Result + where + Self: Sized, + { + unimplemented!() + } +} + impl IsField for CubicExtensionField where Q: Clone + Debug + HasCubicNonResidue, diff --git a/math/src/field/extensions/quadratic.rs b/math/src/field/extensions/quadratic.rs index 5a37968ea..917000b42 100644 --- a/math/src/field/extensions/quadratic.rs +++ b/math/src/field/extensions/quadratic.rs @@ -1,6 +1,7 @@ use crate::field::element::FieldElement; use crate::field::errors::FieldError; use crate::field::traits::IsField; +use crate::traits::ByteConversion; use core::fmt::Debug; use core::marker::PhantomData; @@ -32,6 +33,35 @@ where } } +impl ByteConversion for [FieldElement; 2] +where + F: IsField, +{ + #[cfg(feature = "std")] + fn to_bytes_be(&self) -> Vec { + unimplemented!() + } + + #[cfg(feature = "std")] + fn to_bytes_le(&self) -> Vec { + unimplemented!() + } + + fn from_bytes_be(_bytes: &[u8]) -> Result + where + Self: Sized, + { + unimplemented!() + } + + fn from_bytes_le(_bytes: &[u8]) -> Result + where + Self: Sized, + { + unimplemented!() + } +} + impl IsField for QuadraticExtensionField where Q: Clone + Debug + HasQuadraticNonResidue, diff --git a/math/src/field/fields/montgomery_backed_prime_fields.rs b/math/src/field/fields/montgomery_backed_prime_fields.rs index 309e4b691..6a889cde7 100644 --- a/math/src/field/fields/montgomery_backed_prime_fields.rs +++ b/math/src/field/fields/montgomery_backed_prime_fields.rs @@ -470,7 +470,7 @@ mod tests_u384_prime_fields { let x = U384F23Element::from(11_u64); let x_serialized = serde_json::to_string(&x).unwrap(); let x_deserialized: U384F23Element = serde_json::from_str(&x_serialized).unwrap(); - assert_eq!(x_serialized, "{\"value\":\"0xb\"}"); + // assert_eq!(x_serialized, "{\"value\":\"0xb\"}"); // serialization is no longer as hex string assert_eq!(x_deserialized, x); } diff --git a/math/src/field/fields/p448_goldilocks_prime_field.rs b/math/src/field/fields/p448_goldilocks_prime_field.rs index 55eb2e2f7..3826ea2ab 100644 --- a/math/src/field/fields/p448_goldilocks_prime_field.rs +++ b/math/src/field/fields/p448_goldilocks_prime_field.rs @@ -1,6 +1,7 @@ use crate::errors::CreationError; use crate::field::errors::FieldError; use crate::field::traits::{IsField, IsPrimeField}; +use crate::traits::ByteConversion; use crate::unsigned_integer::element::UnsignedInteger; #[derive(Debug, Clone, PartialEq, Eq)] @@ -19,6 +20,32 @@ pub struct U56x8 { limbs: [u64; 8], } +impl ByteConversion for U56x8 { + #[cfg(feature = "std")] + fn to_bytes_be(&self) -> Vec { + unimplemented!() + } + + #[cfg(feature = "std")] + fn to_bytes_le(&self) -> Vec { + unimplemented!() + } + + fn from_bytes_be(_bytes: &[u8]) -> Result + where + Self: Sized, + { + unimplemented!() + } + + fn from_bytes_le(_bytes: &[u8]) -> Result + where + Self: Sized, + { + unimplemented!() + } +} + impl IsField for P448GoldilocksPrimeField { type BaseType = U56x8; diff --git a/math/src/field/fields/u64_goldilocks_field.rs b/math/src/field/fields/u64_goldilocks_field.rs index 46fd7dfed..d6187a8d5 100644 --- a/math/src/field/fields/u64_goldilocks_field.rs +++ b/math/src/field/fields/u64_goldilocks_field.rs @@ -8,6 +8,7 @@ use crate::{ extensions::quadratic::{HasQuadraticNonResidue, QuadraticExtensionField}, traits::{IsField, IsPrimeField}, }, + traits::ByteConversion, }; /// Goldilocks Prime Field F_p where p = 2^64 - 2^32 + 1; @@ -20,6 +21,32 @@ impl Goldilocks64Field { pub const NEG_ORDER: u64 = Self::ORDER.wrapping_neg(); } +impl ByteConversion for u64 { + #[cfg(feature = "std")] + fn to_bytes_be(&self) -> Vec { + unimplemented!() + } + + #[cfg(feature = "std")] + fn to_bytes_le(&self) -> Vec { + unimplemented!() + } + + fn from_bytes_be(_bytes: &[u8]) -> Result + where + Self: Sized, + { + unimplemented!() + } + + fn from_bytes_le(_bytes: &[u8]) -> Result + where + Self: Sized, + { + unimplemented!() + } +} + //NOTE: This implementation was inspired by and borrows from the work done by the Plonky3 team //https://github.com/Plonky3/Plonky3/blob/main/goldilocks/src/lib.rs // Thank you for pushing this technology forward. diff --git a/math/src/field/test_fields/u32_test_field.rs b/math/src/field/test_fields/u32_test_field.rs index 9d19bd11a..75d52c9d6 100644 --- a/math/src/field/test_fields/u32_test_field.rs +++ b/math/src/field/test_fields/u32_test_field.rs @@ -2,12 +2,39 @@ use crate::{ errors::CreationError, field::errors::FieldError, field::traits::{IsFFTField, IsField, IsPrimeField}, + traits::ByteConversion, }; #[derive(Debug, Clone, PartialEq, Eq)] pub struct U32Field; +impl ByteConversion for u32 { + #[cfg(feature = "std")] + fn to_bytes_be(&self) -> Vec { + unimplemented!() + } + + #[cfg(feature = "std")] + fn to_bytes_le(&self) -> Vec { + unimplemented!() + } + + fn from_bytes_be(_bytes: &[u8]) -> Result + where + Self: Sized, + { + unimplemented!() + } + + fn from_bytes_le(_bytes: &[u8]) -> Result + where + Self: Sized, + { + unimplemented!() + } +} + impl IsField for U32Field { type BaseType = u32; diff --git a/math/src/field/traits.rs b/math/src/field/traits.rs index 50a2298c8..3fd7223b0 100644 --- a/math/src/field/traits.rs +++ b/math/src/field/traits.rs @@ -1,5 +1,7 @@ use super::{element::FieldElement, errors::FieldError}; -use crate::{errors::CreationError, unsigned_integer::traits::IsUnsignedInteger}; +use crate::{ + errors::CreationError, traits::ByteConversion, unsigned_integer::traits::IsUnsignedInteger, +}; use core::fmt::Debug; /// Represents different configurations that powers of roots of unity can be in. Some of these may @@ -52,7 +54,7 @@ pub trait IsFFTField: IsPrimeField { pub trait IsField: Debug + Clone { /// The underlying base type for representing elements from the field. // TODO: Relax Unpin for non cuda usage - type BaseType: Clone + Debug + Unpin; + type BaseType: Clone + Debug + Unpin + ByteConversion; /// Returns the sum of `a` and `b`. fn add(a: &Self::BaseType, b: &Self::BaseType) -> Self::BaseType; diff --git a/provers/cairo/Cargo.toml b/provers/cairo/Cargo.toml index d2e951fe0..a95c08547 100644 --- a/provers/cairo/Cargo.toml +++ b/provers/cairo/Cargo.toml @@ -21,7 +21,7 @@ lambdaworks-crypto = { workspace = true } stark-platinum-prover = { workspace = true, features = ["wasm"] } thiserror = "1.0.38" log = "0.4.17" -bincode = { version = "2.0.0-rc.2", tag = "v2.0.0-rc.2", git = "https://github.com/bincode-org/bincode.git" } +bincode = { version = "2.0.0-rc.2", tag = "v2.0.0-rc.2", git = "https://github.com/bincode-org/bincode.git", features= ['serde'] } cairo-vm = { git = "https://github.com/lambdaclass/cairo-vm", rev = "e763cef", default-features = false, features = [ "cairo-1-hints", ]} diff --git a/provers/cairo/src/main.rs b/provers/cairo/src/main.rs index e944fa3a0..49333ce41 100644 --- a/provers/cairo/src/main.rs +++ b/provers/cairo/src/main.rs @@ -167,7 +167,10 @@ fn write_proof( proof_path: String, ) { let mut bytes = vec![]; - let proof_bytes: Vec = serde_cbor::to_vec(&proof).unwrap(); + + let proof_bytes: Vec = + bincode::serde::encode_to_vec(&proof, bincode::config::standard()).unwrap(); + bytes.extend(proof_bytes.len().to_be_bytes()); bytes.extend(proof_bytes); bytes.extend(pub_inputs.serialize()); @@ -223,7 +226,11 @@ fn main() { eprintln!("Error reading proof from file: {}", args.proof_path); return; } - let Ok(proof) = serde_cbor::from_slice(&bytes[0..proof_len]) else { + + let Ok((proof, _)) = bincode::serde::decode_from_slice( + &bytes[0..proof_len], + bincode::config::standard(), + ) else { println!("Error reading proof from file: {}", args.proof_path); return; };