Factor serde to utils

This commit is contained in:
Remco Bloemen 2022-03-17 15:39:06 -07:00
parent 0a17226a4c
commit 347c6bcaf9
3 changed files with 113 additions and 147 deletions

View File

@ -1,19 +1,11 @@
use crate::util::{keccak256, trim_hex_prefix};
use crate::util::{bytes_from_hex, deserialize_bytes, keccak256, serialize_bytes};
use ark_bn254::Fr as ArkField;
use ark_ff::{BigInteger as _, PrimeField as _};
use core::{
fmt::{Formatter, Result as FmtResult},
str,
str::FromStr,
};
use core::{str, str::FromStr};
use ff::{PrimeField as _, PrimeFieldRepr as _};
use hex::encode_to_slice;
use num_bigint::{BigInt, Sign};
use poseidon_rs::Fr as PosField;
use serde::{
de::{Error as DeError, Visitor},
Deserialize, Serialize, Serializer,
};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
/// An element of the BN254 scalar field Fr.
///
@ -77,36 +69,28 @@ impl From<Field> for BigInt {
}
}
/// Serialize a field element.
///
/// For human readable formats a `0x` prefixed lower case hex string is used.
/// For binary formats a byte array is used.
impl Serialize for Field {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
if serializer.is_human_readable() {
// Write as a 0x prefixed lower-case hex string
let mut buffer = [0u8; 66];
buffer[0] = b'0';
buffer[1] = b'x';
encode_to_slice(&self.0, &mut buffer[2..]).expect("the buffer is correctly sized");
let string = str::from_utf8(&buffer).expect("the buffer is valid UTF-8");
serializer.serialize_str(string)
} else {
// Write as bytes directly
serializer.serialize_bytes(&self.0)
}
serialize_bytes::<32, 66, S>(serializer, &self.0)
}
}
/// Parse Hash from hex string.
///
/// Hex strings can be upper/lower/mixed case and have an optional `0x` prefix
/// but they must always be exactly 32 bytes.
///
/// Too large values are reduced modulo the field prime.
impl FromStr for Field {
type Err = hex::FromHexError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let str = trim_hex_prefix(s);
let mut out = [0_u8; 32];
hex::decode_to_slice(str, &mut out)?;
// TODO: Reduce
Ok(Self(out))
let bytes = bytes_from_hex::<32>(s)?;
Ok(Self::from_be_bytes_mod_order(&bytes[..]))
}
}
@ -114,47 +98,9 @@ impl FromStr for Field {
/// Hex strings can be upper/lower/mixed case and have an optional `0x` prefix
/// but they must always be exactly 32 bytes.
impl<'de> Deserialize<'de> for Field {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
if deserializer.is_human_readable() {
deserializer.deserialize_str(StrVisitor)
} else {
// TODO: Reduce
<[u8; 32]>::deserialize(deserializer).map(Field)
}
}
}
struct StrVisitor;
impl<'de> Visitor<'de> for StrVisitor {
type Value = Field;
fn expecting(&self, formatter: &mut Formatter) -> FmtResult {
formatter.write_str("a 32 byte hex string")
}
fn visit_borrowed_str<E>(self, value: &'de str) -> Result<Self::Value, E>
where
E: DeError,
{
Field::from_str(value).map_err(|e| E::custom(format!("Error in hex: {}", e)))
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: DeError,
{
Field::from_str(value).map_err(|e| E::custom(format!("Error in hex: {}", e)))
}
fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
where
E: DeError,
{
Field::from_str(&value).map_err(|e| E::custom(format!("Error in hex: {}", e)))
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let bytes = deserialize_bytes::<32, _>(deserializer)?;
Ok(Self::from_be_bytes_mod_order(&bytes))
}
}

View File

@ -1,13 +1,10 @@
use crate::util::{bytes_from_hex, deserialize_bytes, serialize_bytes};
use ethers_core::types::U256;
use num_bigint::{BigInt, Sign};
use serde::{
de::{Error as DeError, Visitor},
ser::Error as _,
Deserialize, Serialize,
};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::{
fmt::{Debug, Display, Formatter, Result as FmtResult},
str::{from_utf8, FromStr},
str::FromStr,
};
/// Container for 256-bit hash values.
@ -85,30 +82,15 @@ impl FromStr for Hash {
type Err = hex::FromHexError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let str = trim_hex_prefix(s);
let mut out = [0_u8; 32];
hex::decode_to_slice(str, &mut out)?;
Ok(Self(out))
bytes_from_hex::<32>(s).map(Self)
}
}
/// Serialize hashes into human readable hex strings or byte arrays.
/// Hex strings are lower case without prefix and always 32 bytes.
impl Serialize for Hash {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
if serializer.is_human_readable() {
let mut hex_ascii = [0_u8; 64];
hex::encode_to_slice(self.0, &mut hex_ascii)
.map_err(|e| S::Error::custom(format!("Error hex encoding: {}", e)))?;
from_utf8(&hex_ascii)
.map_err(|e| S::Error::custom(format!("Invalid hex encoding: {}", e)))?
.serialize(serializer)
} else {
self.0.serialize(serializer)
}
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serialize_bytes::<32, 66, S>(serializer, &self.0)
}
}
@ -116,55 +98,9 @@ impl Serialize for Hash {
/// Hex strings can be upper/lower/mixed case and have an optional `0x` prefix
/// but they must always be exactly 32 bytes.
impl<'de> Deserialize<'de> for Hash {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
if deserializer.is_human_readable() {
deserializer.deserialize_str(HashStrVisitor)
} else {
<[u8; 32]>::deserialize(deserializer).map(Hash)
}
}
}
struct HashStrVisitor;
impl<'de> Visitor<'de> for HashStrVisitor {
type Value = Hash;
fn expecting(&self, formatter: &mut Formatter) -> FmtResult {
formatter.write_str("a 32 byte hex string")
}
fn visit_borrowed_str<E>(self, value: &'de str) -> Result<Self::Value, E>
where
E: DeError,
{
Hash::from_str(value).map_err(|e| E::custom(format!("Error in hex: {}", e)))
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: DeError,
{
Hash::from_str(value).map_err(|e| E::custom(format!("Error in hex: {}", e)))
}
fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
where
E: DeError,
{
Hash::from_str(&value).map_err(|e| E::custom(format!("Error in hex: {}", e)))
}
}
/// Helper function to optionally remove `0x` prefix from hex strings.
fn trim_hex_prefix(str: &str) -> &str {
if str.len() >= 2 && (&str[..2] == "0x" || &str[..2] == "0X") {
&str[2..]
} else {
str
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let bytes = deserialize_bytes::<32, _>(deserializer)?;
Ok(Self(bytes))
}
}
@ -179,14 +115,14 @@ pub mod test {
let hash = Hash([0; 32]);
assert_eq!(
to_string(&hash).unwrap(),
"\"0000000000000000000000000000000000000000000000000000000000000000\""
"\"0x0000000000000000000000000000000000000000000000000000000000000000\""
);
let hash = Hash(hex!(
"1c4823575d154474ee3e5ac838d002456a815181437afd14f126da58a9912bbe"
));
assert_eq!(
to_string(&hash).unwrap(),
"\"1c4823575d154474ee3e5ac838d002456a815181437afd14f126da58a9912bbe\""
"\"0x1c4823575d154474ee3e5ac838d002456a815181437afd14f126da58a9912bbe\""
);
}

View File

@ -1,3 +1,11 @@
use core::{
fmt::{Formatter, Result as FmtResult},
str,
};
use serde::{
de::{Error as DeError, Visitor},
Deserializer, Serializer,
};
use tiny_keccak::{Hasher as _, Keccak};
pub(crate) fn keccak256(bytes: &[u8]) -> [u8; 32] {
@ -8,11 +16,87 @@ pub(crate) fn keccak256(bytes: &[u8]) -> [u8; 32] {
output
}
/// Helper function to optionally remove `0x` prefix from hex strings.
pub(crate) fn trim_hex_prefix(str: &str) -> &str {
/// Helper to serialize byte arrays
pub(crate) fn serialize_bytes<const N: usize, const M: usize, S: Serializer>(
serializer: S,
bytes: &[u8; N],
) -> Result<S::Ok, S::Error> {
// TODO: Replace `M` with a const expression once it's stable.
debug_assert_eq!(M, 2 * N + 2);
if serializer.is_human_readable() {
// Write as a 0x prefixed lower-case hex string
let mut buffer = [0u8; M];
buffer[0] = b'0';
buffer[1] = b'x';
hex::encode_to_slice(&bytes[..], &mut buffer[2..]).expect("the buffer is correctly sized");
let string = str::from_utf8(&buffer).expect("the buffer is valid UTF-8");
serializer.serialize_str(string)
} else {
// Write as bytes directly
serializer.serialize_bytes(&bytes[..])
}
}
/// Helper to deserialize byte arrays from hex strings
///
/// TODO: How does it handle strings that are to short?
pub(crate) fn bytes_from_hex<const N: usize>(s: &str) -> Result<[u8; N], hex::FromHexError> {
let str = trim_hex_prefix(s);
let mut result = [0_u8; N];
hex::decode_to_slice(str, &mut result)?;
Ok(result)
}
/// Helper function to remove optionally `0x` prefix from hex strings.
fn trim_hex_prefix(str: &str) -> &str {
if str.len() >= 2 && (&str[..2] == "0x" || &str[..2] == "0X") {
&str[2..]
} else {
str
}
}
pub(crate) fn deserialize_bytes<'de, const N: usize, D: Deserializer<'de>>(
deserializer: D,
) -> Result<[u8; N], D::Error> {
if deserializer.is_human_readable() {
struct StrVisitor<const N: usize>;
impl<'de, const N: usize> Visitor<'de> for StrVisitor<N> {
type Value = [u8; N];
fn expecting(&self, formatter: &mut Formatter) -> FmtResult {
write!(formatter, "a {N} byte hex string")
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: DeError,
{
bytes_from_hex(value).map_err(|e| E::custom(format!("Error in hex: {}", e)))
}
}
deserializer.deserialize_str(StrVisitor)
} else {
struct ByteVisitor<const N: usize>;
impl<'de, const N: usize> Visitor<'de> for ByteVisitor<N> {
type Value = [u8; N];
fn expecting(&self, formatter: &mut Formatter) -> FmtResult {
write!(formatter, "{N} bytes of binary data")
}
fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E>
where
E: DeError,
{
if value.len() != N {
return Err(E::invalid_length(value.len(), &self));
}
let mut result = [0_u8; N];
result.copy_from_slice(value);
Ok(result)
}
}
deserializer.deserialize_bytes(ByteVisitor)
}
}