Skip to content

Commit

Permalink
Added serde feature
Browse files Browse the repository at this point in the history
  • Loading branch information
d-sonuga committed Dec 11, 2024
1 parent 40e9c78 commit 6dc2c2a
Show file tree
Hide file tree
Showing 5 changed files with 198 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .github/workflows/dusk_ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
name: Nightly tests std
uses: dusk-network/.github/.github/workflows/run-tests.yml@main
with:
test_flags: --features=zeroize
test_flags: --features=zeroize,serde

test_nightly_no_std:
name: Nightly tests no_std
Expand Down
13 changes: 13 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,18 @@ default-features = false
version = "1"
optional = true
default-features = false

[dependencies.serde]
version = "1.0"
optional = true

[dependencies.serde_json]
version = "1.0"
optional = true

[dependencies.hex]
version = "0.4"
optional = true
# End Dusk dependendencies

[dev-dependencies]
Expand All @@ -86,6 +98,7 @@ default = ["alloc", "bits"]
alloc = ["ff/alloc", "group/alloc"]
bits = ["ff/bits"]
rkyv-impl = ["bytecheck", "dusk-bls12_381/rkyv-impl", "rkyv"]
serde = ["dep:serde", "serde_json", "hex"]

[[bench]]
name = "fq_bench"
Expand Down
3 changes: 3 additions & 0 deletions src/dusk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
#[cfg(feature = "alloc")]
extern crate alloc;

#[cfg(feature = "serde")]
mod serde_support;

use core::ops::Mul;
use ff::Field;
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
Expand Down
115 changes: 115 additions & 0 deletions src/dusk/serde_support.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
extern crate alloc;

use alloc::string::String;

use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer};

use crate::{AffinePoint, ExtendedPoint};

impl Serialize for AffinePoint {
fn serialize<S: Serializer>(
&self,
serializer: S,
) -> Result<S::Ok, S::Error> {
let s = hex::encode(self.to_bytes());
serializer.serialize_str(&s)
}
}

impl<'de> Deserialize<'de> for AffinePoint {
fn deserialize<D: Deserializer<'de>>(
deserializer: D,
) -> Result<Self, D::Error> {
let s = String::deserialize(deserializer)?;
let decoded = hex::decode(&s).map_err(Error::custom)?;
let decoded_len = decoded.len();
let bytes: [u8; 32] = decoded
.try_into()
.map_err(|_| Error::invalid_length(decoded_len, &"32"))?;
AffinePoint::from_bytes(bytes)
.into_option()
.ok_or(Error::custom(
"Failed to deserialize AffinePoint: invalid AffinePoint",
))
}
}

impl Serialize for ExtendedPoint {
fn serialize<S: Serializer>(
&self,
serializer: S,
) -> Result<S::Ok, S::Error> {
AffinePoint::from(self).serialize(serializer)
}
}

impl<'de> Deserialize<'de> for ExtendedPoint {
fn deserialize<D: Deserializer<'de>>(
deserializer: D,
) -> Result<Self, D::Error> {
AffinePoint::deserialize(deserializer).map(Into::into)
}
}

#[cfg(test)]
mod tests {
use group::Group;

use crate::{AffinePoint, ExtendedPoint};

#[test]
fn affine_point() {
let point = AffinePoint::identity();
let ser = serde_json::to_string(&point).unwrap();
let deser = serde_json::from_str(&ser).unwrap();
assert_eq!(point, deser);
}

#[test]
fn extended_point() {
let mut rng = rand_core::OsRng;
let point = ExtendedPoint::random(&mut rng);
let ser = serde_json::to_string(&point).unwrap();
let deser = serde_json::from_str(&ser).unwrap();
assert_eq!(point, deser);
}

#[test]
fn wrong_encoded() {
let wrong_encoded = "wrong-encoded";

let affine_point: Result<AffinePoint, _> =
serde_json::from_str(&wrong_encoded);
assert!(affine_point.is_err());

let extended_point: Result<ExtendedPoint, _> =
serde_json::from_str(&wrong_encoded);
assert!(extended_point.is_err());
}

#[test]
fn too_long_encoded() {
let length_33_enc = "\"e4ab9de40283a85d6ea0cd0120500697d8b01c71b7b4b520292252d20937000631\"";

let affine_point: Result<AffinePoint, _> =
serde_json::from_str(&length_33_enc);
assert!(affine_point.is_err());

let extended_point: Result<ExtendedPoint, _> =
serde_json::from_str(&length_33_enc);
assert!(extended_point.is_err());
}

#[test]
fn too_short_encoded() {
let length_31_enc = "\"1751c37a1dca7aa4c048fcc6177194243edc3637bae042e167e4285945e046\"";

let affine_point: Result<AffinePoint, _> =
serde_json::from_str(&length_31_enc);
assert!(affine_point.is_err());

let extended_point: Result<ExtendedPoint, _> =
serde_json::from_str(&length_31_enc);
assert!(extended_point.is_err());
}
}
66 changes: 66 additions & 0 deletions src/fr/dusk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,44 @@ impl Serializable<32> for Fr {
}
}

#[cfg(feature = "serde")]
mod serde_support {
extern crate alloc;

use alloc::string::String;

use serde::de::Error;
use serde::{Deserialize, Deserializer, Serialize, Serializer};

use super::Fr;

impl Serialize for Fr {
fn serialize<S: Serializer>(
&self,
serializer: S,
) -> Result<S::Ok, S::Error> {
let s = hex::encode(self.to_bytes());
serializer.serialize_str(&s)
}
}

impl<'de> Deserialize<'de> for Fr {
fn deserialize<D: Deserializer<'de>>(
deserializer: D,
) -> Result<Self, D::Error> {
let s = String::deserialize(deserializer)?;
let decoded = hex::decode(s).map_err(Error::custom)?;
let decoded_len = decoded.len();
let bytes: [u8; 32] = decoded
.try_into()
.map_err(|_| Error::invalid_length(decoded_len, &"32"))?;
Fr::from_bytes(&bytes)
.into_option()
.ok_or(Error::custom("Failed to deserialize Fr: invalid Fr"))
}
}
}

#[test]
fn w_naf_3() {
let scalar = Fr::from(1122334455u64);
Expand Down Expand Up @@ -366,3 +404,31 @@ fn test_zeroize() {
scalar.zeroize();
assert_eq!(scalar, Fr::zero());
}

#[cfg(feature = "serde")]
#[test]
fn serde_fr() {
use ff::Field;

let mut rng = rand_core::OsRng;
let fr = Fr::random(&mut rng);
let ser = serde_json::to_string(&fr).unwrap();
let deser = serde_json::from_str(&ser).unwrap();
assert_eq!(fr, deser);

// Should error when the encoding is wrong
let wrong_encoded = "wrong-encoded";
let fr: Result<Fr, _> = serde_json::from_str(&wrong_encoded);
assert!(fr.is_err());

// Should error when the input is too long
let length_33_enc = "\"e4ab9de40283a85d6ea0cd0120500697d8b01c71b7b4b520292252d20937000631\"";
let fr: Result<Fr, _> = serde_json::from_str(&length_33_enc);
assert!(fr.is_err());

// Should error when the input is too short
let length_31_enc =
"\"1751c37a1dca7aa4c048fcc6177194243edc3637bae042e167e4285945e046\"";
let fr: Result<Fr, _> = serde_json::from_str(&length_31_enc);
assert!(fr.is_err());
}

0 comments on commit 6dc2c2a

Please sign in to comment.