Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ criterion = { version = "0.3", features = ["html_reports"] }
rand_xorshift = "0.3"
ark-std = { version = "0.3" }
bincode = "1.3.3"
serde_json = "1.0.105"

[dependencies]
subtle = "2.4"
Expand All @@ -30,14 +31,15 @@ num-traits = "0.2"
paste = "1.0.11"
serde = { version = "1.0", default-features = false, optional = true }
serde_arrays = { version = "0.1.0", optional = true }
hex = { version = "0.4", optional = true, default-features = false, features = ["alloc", "serde"] }
blake2b_simd = "1"

[features]
default = ["reexport", "bits"]
asm = []
bits = ["ff/bits"]
bn256-table = []
derive_serde = ["serde/derive", "serde_arrays"]
derive_serde = ["serde/derive", "serde_arrays", "hex"]
prefetch = []
print-trace = ["ark-std/print-trace"]
reexport = []
Expand Down
7 changes: 3 additions & 4 deletions src/bn256/fq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@ use core::ops::{Add, Mul, Neg, Sub};
use rand::RngCore;
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};

#[cfg(feature = "derive_serde")]
use serde::{Deserialize, Serialize};

/// This represents an element of $\mathbb{F}_q$ where
///
/// `p = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47`
Expand All @@ -28,9 +25,11 @@ use serde::{Deserialize, Serialize};
// integers in little-endian order. `Fq` values are always in
// Montgomery form; i.e., Fq(a) = aR mod q, with R = 2^256.
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))]
pub struct Fq(pub(crate) [u64; 4]);

#[cfg(feature = "derive_serde")]
crate::serialize_deserialize_32_byte_primefield!(Fq);

/// Constant representing the modulus
/// q = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47
const MODULUS: Fq = Fq([
Expand Down
7 changes: 3 additions & 4 deletions src/bn256/fr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,6 @@ use core::ops::{Add, Mul, Neg, Sub};
use rand::RngCore;
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};

#[cfg(feature = "derive_serde")]
use serde::{Deserialize, Serialize};

/// This represents an element of $\mathbb{F}_r$ where
///
/// `r = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001`
Expand All @@ -43,9 +40,11 @@ use serde::{Deserialize, Serialize};
// integers in little-endian order. `Fr` values are always in
// Montgomery form; i.e., Fr(a) = aR mod r, with R = 2^256.
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))]
pub struct Fr(pub(crate) [u64; 4]);

#[cfg(feature = "derive_serde")]
crate::serialize_deserialize_32_byte_primefield!(Fr);

/// Constant representing the modulus
/// r = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001
const MODULUS: Fr = Fr([
Expand Down
35 changes: 35 additions & 0 deletions src/derive/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -686,3 +686,38 @@ macro_rules! field_bits {
}
};
}

/// A macro to help define serialization and deserialization for prime field implementations
/// that use 32-byte representations. This assumes the concerned type implements PrimeField
/// (for from_repr, to_repr).
#[macro_export]
macro_rules! serialize_deserialize_32_byte_primefield {
($type:ty) => {
impl ::serde::Serialize for $type {
fn serialize<S: ::serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let bytes = &self.to_repr();
if serializer.is_human_readable() {
hex::serde::serialize(bytes, serializer)
} else {
bytes.serialize(serializer)
}
Comment on lines +699 to +703

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm afraid this if will even make performance worse when it comes to serialization.

On another hand, this never has anything to do with raw serialization (which is usually the used for performance).
Do I understand correctly that we're using serde then as "debugging serialization"??

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Serializers usually just implement is_human_readable as a constant, so this if is as cheap as can be. Examples:

The semantics of is_human_readable, as the doc indicates, is not debugging. It's simply articulating the difference between formats that are meant to be human-readable (JSON, YAML), and those that are not (bincode, CBOR, RLP, ...).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Serializers usually just implement is_human_readable as a constant, so this if is as cheap as can be.

Fair point.

}
}

use ::serde::de::Error as _;
impl<'de> ::serde::Deserialize<'de> for $type {
fn deserialize<D: ::serde::Deserializer<'de>>(
deserializer: D,
) -> Result<Self, D::Error> {
let bytes = if deserializer.is_human_readable() {
::hex::serde::deserialize(deserializer)?
} else {
<[u8; 32]>::deserialize(deserializer)?
};
Option::from(Self::from_repr(bytes)).ok_or_else(|| {
D::Error::custom("deserialized bytes don't encode a valid field element")
})
}
}
};
}
7 changes: 3 additions & 4 deletions src/secp256k1/fp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@ use core::ops::{Add, Mul, Neg, Sub};
use rand::RngCore;
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};

#[cfg(feature = "derive_serde")]
use serde::{Deserialize, Serialize};

/// This represents an element of $\mathbb{F}_p$ where
///
/// `p = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f`
Expand All @@ -23,9 +20,11 @@ use serde::{Deserialize, Serialize};
// integers in little-endian order. `Fp` values are always in
// Montgomery form; i.e., Fp(a) = aR mod p, with R = 2^256.
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))]
pub struct Fp(pub(crate) [u64; 4]);

#[cfg(feature = "derive_serde")]
crate::serialize_deserialize_32_byte_primefield!(Fp);

/// Constant representing the modulus
/// p = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f
const MODULUS: Fp = Fp([
Expand Down
7 changes: 3 additions & 4 deletions src/secp256k1/fq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@ use core::ops::{Add, Mul, Neg, Sub};
use rand::RngCore;
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};

#[cfg(feature = "derive_serde")]
use serde::{Deserialize, Serialize};

/// This represents an element of $\mathbb{F}_q$ where
///
/// `q = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141`
Expand All @@ -23,9 +20,11 @@ use serde::{Deserialize, Serialize};
// integers in little-endian order. `Fq` values are always in
// Montgomery form; i.e., Fq(a) = aR mod q, with R = 2^256.
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))]
pub struct Fq(pub(crate) [u64; 4]);

#[cfg(feature = "derive_serde")]
crate::serialize_deserialize_32_byte_primefield!(Fq);

/// Constant representing the modulus
/// q = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141
const MODULUS: Fq = Fq([
Expand Down
7 changes: 3 additions & 4 deletions src/secp256r1/fp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@ use core::ops::{Add, Mul, Neg, Sub};
use rand::RngCore;
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};

#[cfg(feature = "derive_serde")]
use serde::{Deserialize, Serialize};

/// This represents an element of $\mathbb{F}_p$ where
///
/// `p = 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff
Expand All @@ -23,9 +20,11 @@ use serde::{Deserialize, Serialize};
// integers in little-endian order. `Fp` values are always in
// Montgomery form; i.e., Fp(a) = aR mod p, with R = 2^256.
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))]
pub struct Fp(pub(crate) [u64; 4]);

#[cfg(feature = "derive_serde")]
crate::serialize_deserialize_32_byte_primefield!(Fp);

/// Constant representing the modulus
/// p = 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff
const MODULUS: Fp = Fp([
Expand Down
7 changes: 3 additions & 4 deletions src/secp256r1/fq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@ use core::ops::{Add, Mul, Neg, Sub};
use rand::RngCore;
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};

#[cfg(feature = "derive_serde")]
use serde::{Deserialize, Serialize};

/// This represents an element of $\mathbb{F}_q$ where
///
/// `q = 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551`
Expand All @@ -17,9 +14,11 @@ use serde::{Deserialize, Serialize};
// integers in little-endian order. `Fq` values are always in
// Montgomery form; i.e., Fq(a) = aR mod q, with R = 2^256.
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))]
pub struct Fq(pub(crate) [u64; 4]);

#[cfg(feature = "derive_serde")]
crate::serialize_deserialize_32_byte_primefield!(Fq);

/// Constant representing the modulus
/// q = 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551
const MODULUS: Fq = Fq([
Expand Down
7 changes: 7 additions & 0 deletions src/tests/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -280,11 +280,18 @@ where
let _message = format!("serialization with serde {type_name}");
let start = start_timer!(|| _message);
for _ in 0..1000000 {
// byte serialization
let a = F::random(&mut rng);
let bytes = bincode::serialize(&a).unwrap();
let reader = std::io::Cursor::new(bytes);
let b: F = bincode::deserialize_from(reader).unwrap();
assert_eq!(a, b);

// json serialization
let json = serde_json::to_string(&a).unwrap();
let reader = std::io::Cursor::new(json);
let b: F = serde_json::from_reader(reader).unwrap();
assert_eq!(a, b);
}
end_timer!(start);
}
Expand Down