Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ed448: Ed448 Implementation #727

Merged
merged 11 commits into from
Oct 15, 2023
Prev Previous commit
Next Next commit
ed448: support serde
  • Loading branch information
ashWhiteHat committed Jul 1, 2023
commit 0e30df9162a37f6020f6f4ade6782f757bb46a59
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions ed448/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,16 @@ keywords = ["crypto", "curve448", "ecc", "signature", "signing"]

[dependencies]
signature = { version = "2", default-features = false }

# optional dependencies
serde = { version = "1", optional = true, default-features = false }
serde_bytes = { version = "0.11", optional = true }

[dev-dependencies]
hex-literal = "0.4"
bincode = "1"

[features]
default = ["std"]
serde_bytes = ["serde", "dep:serde_bytes"]
std = ["signature/std"]
3 changes: 3 additions & 0 deletions ed448/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@

mod hex;

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

pub use signature::{self, Error, SignatureEncoding};

use core::fmt;
Expand Down
121 changes: 121 additions & 0 deletions ed448/src/serde.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
//! `serde` support.

use crate::{Signature, SignatureBytes};
use ::serde::{de, ser, Deserialize, Serialize};
use core::fmt;

impl Serialize for Signature {
fn serialize<S: ser::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
use ser::SerializeTuple;

let mut seq = serializer.serialize_tuple(Signature::BYTE_SIZE)?;

for byte in self.to_bytes() {
seq.serialize_element(&byte)?;
}

seq.end()
}
}

impl<'de> Deserialize<'de> for Signature {
fn deserialize<D: de::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
struct ByteArrayVisitor;

impl<'de> de::Visitor<'de> for ByteArrayVisitor {
type Value = [u8; Signature::BYTE_SIZE];

fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("bytestring of length 64")
}

fn visit_seq<A>(self, mut seq: A) -> Result<[u8; Signature::BYTE_SIZE], A::Error>
where
A: de::SeqAccess<'de>,
{
use de::Error;
let mut arr = [0u8; Signature::BYTE_SIZE];

for (i, byte) in arr.iter_mut().enumerate() {
*byte = seq
.next_element()?
.ok_or_else(|| Error::invalid_length(i, &self))?;
}

Ok(arr)
}
}

deserializer
.deserialize_tuple(Signature::BYTE_SIZE, ByteArrayVisitor)
.map(Into::into)
}
}

#[cfg(feature = "serde_bytes")]
impl serde_bytes::Serialize for Signature {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_bytes(&self.to_bytes())
}
}

#[cfg(feature = "serde_bytes")]
impl<'de> serde_bytes::Deserialize<'de> for Signature {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
struct ByteArrayVisitor;

impl<'de> de::Visitor<'de> for ByteArrayVisitor {
type Value = SignatureBytes;

fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("bytestring of length 64")
}

fn visit_bytes<E>(self, bytes: &[u8]) -> Result<Self::Value, E>
where
E: de::Error,
{
use de::Error;

bytes
.try_into()
.map_err(|_| Error::invalid_length(bytes.len(), &self))
}
}

deserializer
.deserialize_bytes(ByteArrayVisitor)
.map(Into::into)
}
}

#[cfg(test)]
mod tests {
use crate::{Signature, SignatureBytes};
use hex_literal::hex;

const SIGNATURE_BYTES: SignatureBytes = hex!(
"533a37f6bbe457251f023c0d88f976ae
2dfb504a843e34d2074fd823d41a591f
2b233f034f628281f2fd7a22ddd47d78
28c59bd0a21bfd3980ff0d2028d4b18a
9df63e006c5d1c2d345b925d8dc00b41
04852db99ac5c7cdda8530a113a0f4db
b61149f05a7363268c71d95808ff2e65
2600"
);

#[test]
fn round_trip() {
let signature = Signature::from_bytes(&SIGNATURE_BYTES);
let serialized = bincode::serialize(&signature).unwrap();
let deserialized = bincode::deserialize(&serialized).unwrap();
assert_eq!(signature, deserialized);
}
}
24 changes: 24 additions & 0 deletions ed448/tests/serde.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//! Tests for serde serializers/deserializers

#![cfg(feature = "serde")]

use ed448::{Signature, SignatureBytes};
use hex_literal::hex;

const EXAMPLE_SIGNATURE: SignatureBytes = hex!(
"3f3e3d3c3b3a393837363534333231302f2e2d2c2b2a292827262524232221201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807"
"1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0efeeedecebeae9e8e7"
);

#[test]
fn test_serialize() {
let signature = Signature::try_from(&EXAMPLE_SIGNATURE[..]).unwrap();
let encoded_signature: Vec<u8> = bincode::serialize(&signature).unwrap();
assert_eq!(&EXAMPLE_SIGNATURE[..], &encoded_signature[..]);
}

#[test]
fn test_deserialize() {
let signature = bincode::deserialize::<Signature>(&EXAMPLE_SIGNATURE).unwrap();
assert_eq!(EXAMPLE_SIGNATURE, signature.to_bytes());
}