Skip to content

Commit

Permalink
Improve (de)serialization (#159)
Browse files Browse the repository at this point in the history
* Add more tests covering different ways values can be represented

* Support deserialization of points/scalars represented as a sequence

* Support serialization/deserialization in human readable format
  • Loading branch information
Denis Varlakov authored Dec 28, 2021
1 parent 2817893 commit 44537a7
Show file tree
Hide file tree
Showing 3 changed files with 250 additions and 53 deletions.
50 changes: 30 additions & 20 deletions src/arithmetic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,38 +41,48 @@ pub use traits::*;

#[cfg(test)]
mod test {
use std::{fmt, iter, ops::*};
use std::{fmt, ops::*};

use proptest_derive::Arbitrary;

use super::*;

#[test]
fn serde() {
use serde_test::{assert_tokens, Token::*};
fn serializes_deserializes() {
use serde_test::{assert_tokens, Configure, Token::*};
for bigint in [BigInt::zero(), BigInt::sample(1024)] {
let bytes = bigint.to_bytes();
let tokens = vec![Bytes(bytes.leak())];
assert_tokens(&bigint, &tokens)
let tokens = [Bytes(bytes.leak())];
assert_tokens(&bigint.compact(), &tokens)
}
}

#[test]
fn deserialize_from_seq() {
use serde_test::{
assert_de_tokens,
Token::{Seq, SeqEnd, U8},
};
for bigint in [BigInt::zero(), BigInt::sample(1024)] {
let bytes = bigint.to_bytes();
let tokens = iter::once(Seq {
len: Some(bytes.len()),
})
.chain(bytes.into_iter().map(U8))
.chain(iter::once(SeqEnd))
.collect::<Vec<_>>();
assert_de_tokens(&bigint, &tokens)
}
fn deserializes_bigint_represented_as_seq() {
use serde_test::{assert_de_tokens, Configure, Token::*};

let number = BigInt::sample(1024);
let bytes = number.to_bytes();

let mut tokens = vec![Seq {
len: Option::Some(bytes.len()),
}];
tokens.extend(bytes.into_iter().map(U8));
tokens.push(SeqEnd);

assert_de_tokens(&number.compact(), &tokens);
}

#[test]
fn serializes_deserializes_in_human_readable_format() {
use serde_test::{assert_tokens, Configure, Token::*};

let number = BigInt::sample(1024);
let tokens = [Str(Box::leak(
hex::encode(number.to_bytes()).into_boxed_str(),
))];

assert_tokens(&number.readable(), &tokens);
}

#[test]
Expand Down
22 changes: 19 additions & 3 deletions src/arithmetic/serde_support.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::fmt;

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

use super::traits::Converter;
Expand All @@ -12,7 +12,11 @@ impl Serialize for BigInt {
S: Serializer,
{
let bytes = self.to_bytes();
serializer.serialize_bytes(&bytes)
if !serializer.is_human_readable() {
serializer.serialize_bytes(&bytes)
} else {
serializer.serialize_str(&hex::encode(bytes))
}
}
}

Expand Down Expand Up @@ -47,8 +51,20 @@ impl<'de> Deserialize<'de> for BigInt {
}
Ok(BigInt::from_bytes(&bytes))
}

fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: Error,
{
let bytes = hex::decode(v).map_err(|_| E::custom("malformed hex encoding"))?;
Ok(BigInt::from_bytes(&bytes))
}
}

deserializer.deserialize_bytes(BigintVisitor)
if !deserializer.is_human_readable() {
deserializer.deserialize_bytes(BigintVisitor)
} else {
deserializer.deserialize_str(BigintVisitor)
}
}
}
Loading

0 comments on commit 44537a7

Please sign in to comment.