Merge pull request #48 from filecoin-project/impl-serde

Implement Serde for fields and curves
This commit is contained in:
str4d 2022-11-19 12:02:52 +00:00 committed by GitHub
commit f8ba48de4e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 334 additions and 0 deletions

View File

@ -20,8 +20,10 @@ all-features = true
rustdoc-args = ["--cfg", "docsrs", "--html-in-header", "katex-header.html"]
[dev-dependencies]
bincode = "1.3"
criterion = "0.3"
rand_xorshift = "0.3"
serde_json = "1.0"
[[bench]]
name = "hashtocurve"
@ -57,6 +59,10 @@ lazy_static = { version = "1.4.0", optional = true }
# gpu dependencies
ec-gpu = { version = "0.2.0", optional = true }
# serde dependencies
serde_crate = { version = "1.0.16", optional = true, default-features = false, features = ["alloc"], package = "serde" }
hex = { version = "0.4", optional = true, default-features = false, features = ["alloc", "serde"] }
[features]
default = ["bits", "sqrt-table"]
alloc = ["group/alloc", "blake2b_simd"]
@ -65,3 +71,4 @@ gpu = ["alloc", "ec-gpu"]
sqrt-table = ["alloc", "lazy_static"]
repr-c = []
uninline-portable = []
serde = ["hex", "serde_crate"]

View File

@ -28,6 +28,9 @@ pub mod vesta;
#[cfg(feature = "alloc")]
mod hashtocurve;
#[cfg(feature = "serde")]
mod serde_impl;
pub use curves::*;
pub use fields::*;

324
src/serde_impl.rs Normal file
View File

@ -0,0 +1,324 @@
use ff::PrimeField;
use group::GroupEncoding;
use serde_crate::{
de::Error as DeserializeError, Deserialize, Deserializer, Serialize, Serializer,
};
use crate::{
curves::{EpAffine, EqAffine},
fields::{Fp, Fq},
};
/// Serializes bytes to human readable or compact representation.
///
/// Depending on whether the serializer is a human readable one or not, the bytes are either
/// encoded as a hex string or a list of bytes.
fn serialize_bytes<S: Serializer>(bytes: [u8; 32], s: S) -> Result<S::Ok, S::Error> {
if s.is_human_readable() {
hex::serde::serialize(bytes, s)
} else {
bytes.serialize(s)
}
}
/// Deserialize bytes from human readable or compact representation.
///
/// Depending on whether the deserializer is a human readable one or not, the bytes are either
/// decoded from a hex string or a list of bytes.
fn deserialize_bytes<'de, D: Deserializer<'de>>(d: D) -> Result<[u8; 32], D::Error> {
if d.is_human_readable() {
hex::serde::deserialize(d)
} else {
<[u8; 32]>::deserialize(d)
}
}
impl Serialize for Fp {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
serialize_bytes(self.to_repr(), s)
}
}
impl<'de> Deserialize<'de> for Fp {
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
let bytes = deserialize_bytes(d)?;
match Fp::from_repr(bytes).into() {
Some(fq) => Ok(fq),
None => Err(D::Error::custom(
"deserialized bytes don't encode a Pallas field element",
)),
}
}
}
impl Serialize for Fq {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
serialize_bytes(self.to_repr(), s)
}
}
impl<'de> Deserialize<'de> for Fq {
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
let bytes = deserialize_bytes(d)?;
match Fq::from_repr(bytes).into() {
Some(fq) => Ok(fq),
None => Err(D::Error::custom(
"deserialized bytes don't encode a Vesta field element",
)),
}
}
}
impl Serialize for EpAffine {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
serialize_bytes(self.to_bytes(), s)
}
}
impl<'de> Deserialize<'de> for EpAffine {
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
let bytes = deserialize_bytes(d)?;
match EpAffine::from_bytes(&bytes).into() {
Some(ep_affine) => Ok(ep_affine),
None => Err(D::Error::custom(
"deserialized bytes don't encode a Pallas curve point",
)),
}
}
}
impl Serialize for EqAffine {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
serialize_bytes(self.to_bytes(), s)
}
}
impl<'de> Deserialize<'de> for EqAffine {
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
let bytes = deserialize_bytes(d)?;
match EqAffine::from_bytes(&bytes).into() {
Some(eq_affine) => Ok(eq_affine),
None => Err(D::Error::custom(
"deserialized bytes don't encode a Vesta curve point",
)),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use core::fmt::Debug;
use ff::Field;
use group::{prime::PrimeCurveAffine, Curve, Group};
use rand::SeedableRng;
use rand_xorshift::XorShiftRng;
use crate::curves::{Ep, Eq};
fn test_roundtrip<T: Serialize + for<'a> Deserialize<'a> + Debug + PartialEq>(t: &T) {
let serialized_json = serde_json::to_vec(t).unwrap();
assert_eq!(*t, serde_json::from_slice(&serialized_json).unwrap());
let serialized_bincode = bincode::serialize(t).unwrap();
assert_eq!(*t, bincode::deserialize(&serialized_bincode).unwrap());
}
#[test]
fn serde_fp() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
for _ in 0..100 {
let f = Fp::random(&mut rng);
test_roundtrip(&f);
}
let f = Fp::zero();
test_roundtrip(&f);
assert_eq!(
serde_json::from_slice::<Fp>(
br#""0000000000000000000000000000000000000000000000000000000000000000""#
)
.unwrap(),
f
);
assert_eq!(
bincode::deserialize::<Fp>(&[
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0
])
.unwrap(),
f
);
let f = Fp::one();
test_roundtrip(&f);
assert_eq!(
serde_json::from_slice::<Fp>(
br#""0100000000000000000000000000000000000000000000000000000000000000""#
)
.unwrap(),
f
);
assert_eq!(
bincode::deserialize::<Fp>(&[
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0
])
.unwrap(),
f
);
}
#[test]
fn serde_fq() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
for _ in 0..100 {
let f = Fq::random(&mut rng);
test_roundtrip(&f);
}
let f = Fq::zero();
test_roundtrip(&f);
assert_eq!(
serde_json::from_slice::<Fq>(
br#""0000000000000000000000000000000000000000000000000000000000000000""#
)
.unwrap(),
f
);
assert_eq!(
bincode::deserialize::<Fq>(&[
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0
])
.unwrap(),
f
);
let f = Fq::one();
test_roundtrip(&f);
assert_eq!(
serde_json::from_slice::<Fq>(
br#""0100000000000000000000000000000000000000000000000000000000000000""#
)
.unwrap(),
f
);
assert_eq!(
bincode::deserialize::<Fq>(&[
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0
])
.unwrap(),
f
);
}
#[test]
fn serde_ep_affine() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
for _ in 0..100 {
let f = Ep::random(&mut rng);
test_roundtrip(&f.to_affine());
}
let f = EpAffine::identity();
test_roundtrip(&f);
assert_eq!(
serde_json::from_slice::<EpAffine>(
br#""0000000000000000000000000000000000000000000000000000000000000000""#
)
.unwrap(),
f
);
assert_eq!(
bincode::deserialize::<EpAffine>(&[
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0
])
.unwrap(),
f
);
let f = EpAffine::generator();
test_roundtrip(&f);
assert_eq!(
serde_json::from_slice::<EpAffine>(
br#""00000000ed302d991bf94c09fc98462200000000000000000000000000000040""#
)
.unwrap(),
f
);
assert_eq!(
bincode::deserialize::<EpAffine>(&[
0, 0, 0, 0, 237, 48, 45, 153, 27, 249, 76, 9, 252, 152, 70, 34, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 64
])
.unwrap(),
f
);
}
#[test]
fn serde_eq_affine() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
for _ in 0..100 {
let f = Eq::random(&mut rng);
test_roundtrip(&f.to_affine());
}
let f = EqAffine::identity();
test_roundtrip(&f);
assert_eq!(
serde_json::from_slice::<EqAffine>(
br#""0000000000000000000000000000000000000000000000000000000000000000""#
)
.unwrap(),
f
);
assert_eq!(
bincode::deserialize::<EqAffine>(&[
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0
])
.unwrap(),
f
);
let f = EqAffine::generator();
test_roundtrip(&f);
assert_eq!(
serde_json::from_slice::<EqAffine>(
br#""0000000021eb468cdda89409fc98462200000000000000000000000000000040""#
)
.unwrap(),
f
);
assert_eq!(
bincode::deserialize::<EqAffine>(&[
0, 0, 0, 0, 33, 235, 70, 140, 221, 168, 148, 9, 252, 152, 70, 34, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 64
])
.unwrap(),
f
);
}
}