Factor serde to utils
This commit is contained in:
parent
0a17226a4c
commit
347c6bcaf9
86
src/field.rs
86
src/field.rs
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
86
src/hash.rs
86
src/hash.rs
|
@ -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\""
|
||||
);
|
||||
}
|
||||
|
||||
|
|
88
src/util.rs
88
src/util.rs
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue