Implement Serde for fields and curves
Currently Serde is only implemented for `Fp`, `Fq`, `EpAffine` and `EqAffine`. Support can be enabled with the `serde` feature.
This commit is contained in:
parent
db8305723d
commit
52902e6fdf
|
@ -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.1.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"]
|
||||
|
|
|
@ -28,6 +28,9 @@ pub mod vesta;
|
|||
#[cfg(feature = "alloc")]
|
||||
mod hashtocurve;
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
mod serde_impl;
|
||||
|
||||
pub use curves::*;
|
||||
pub use fields::*;
|
||||
|
||||
|
|
|
@ -0,0 +1,318 @@
|
|||
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},
|
||||
};
|
||||
|
||||
const ERR_CODE: &str = "deserialized bytes don't encode a field element";
|
||||
|
||||
/// 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(ERR_CODE)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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(ERR_CODE)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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_unchecked(&bytes).into() {
|
||||
Some(ep_affine) => Ok(ep_affine),
|
||||
None => Err(D::Error::custom(ERR_CODE)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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_unchecked(&bytes).into() {
|
||||
Some(eq_affine) => Ok(eq_affine),
|
||||
None => Err(D::Error::custom(ERR_CODE)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[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
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue