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_bn254::Fr as ArkField;
|
||||||
use ark_ff::{BigInteger as _, PrimeField as _};
|
use ark_ff::{BigInteger as _, PrimeField as _};
|
||||||
use core::{
|
use core::{str, str::FromStr};
|
||||||
fmt::{Formatter, Result as FmtResult},
|
|
||||||
str,
|
|
||||||
str::FromStr,
|
|
||||||
};
|
|
||||||
use ff::{PrimeField as _, PrimeFieldRepr as _};
|
use ff::{PrimeField as _, PrimeFieldRepr as _};
|
||||||
use hex::encode_to_slice;
|
|
||||||
use num_bigint::{BigInt, Sign};
|
use num_bigint::{BigInt, Sign};
|
||||||
use poseidon_rs::Fr as PosField;
|
use poseidon_rs::Fr as PosField;
|
||||||
use serde::{
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
de::{Error as DeError, Visitor},
|
|
||||||
Deserialize, Serialize, Serializer,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// An element of the BN254 scalar field Fr.
|
/// 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 {
|
impl Serialize for Field {
|
||||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||||
if serializer.is_human_readable() {
|
serialize_bytes::<32, 66, S>(serializer, &self.0)
|
||||||
// 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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse Hash from hex string.
|
/// Parse Hash from hex string.
|
||||||
|
///
|
||||||
/// Hex strings can be upper/lower/mixed case and have an optional `0x` prefix
|
/// Hex strings can be upper/lower/mixed case and have an optional `0x` prefix
|
||||||
/// but they must always be exactly 32 bytes.
|
/// but they must always be exactly 32 bytes.
|
||||||
|
///
|
||||||
|
/// Too large values are reduced modulo the field prime.
|
||||||
impl FromStr for Field {
|
impl FromStr for Field {
|
||||||
type Err = hex::FromHexError;
|
type Err = hex::FromHexError;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
let str = trim_hex_prefix(s);
|
let bytes = bytes_from_hex::<32>(s)?;
|
||||||
let mut out = [0_u8; 32];
|
Ok(Self::from_be_bytes_mod_order(&bytes[..]))
|
||||||
hex::decode_to_slice(str, &mut out)?;
|
|
||||||
|
|
||||||
// TODO: Reduce
|
|
||||||
Ok(Self(out))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,47 +98,9 @@ impl FromStr for Field {
|
||||||
/// Hex strings can be upper/lower/mixed case and have an optional `0x` prefix
|
/// Hex strings can be upper/lower/mixed case and have an optional `0x` prefix
|
||||||
/// but they must always be exactly 32 bytes.
|
/// but they must always be exactly 32 bytes.
|
||||||
impl<'de> Deserialize<'de> for Field {
|
impl<'de> Deserialize<'de> for Field {
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
|
||||||
where
|
let bytes = deserialize_bytes::<32, _>(deserializer)?;
|
||||||
D: serde::Deserializer<'de>,
|
Ok(Self::from_be_bytes_mod_order(&bytes))
|
||||||
{
|
|
||||||
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)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
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 ethers_core::types::U256;
|
||||||
use num_bigint::{BigInt, Sign};
|
use num_bigint::{BigInt, Sign};
|
||||||
use serde::{
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
de::{Error as DeError, Visitor},
|
|
||||||
ser::Error as _,
|
|
||||||
Deserialize, Serialize,
|
|
||||||
};
|
|
||||||
use std::{
|
use std::{
|
||||||
fmt::{Debug, Display, Formatter, Result as FmtResult},
|
fmt::{Debug, Display, Formatter, Result as FmtResult},
|
||||||
str::{from_utf8, FromStr},
|
str::FromStr,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Container for 256-bit hash values.
|
/// Container for 256-bit hash values.
|
||||||
|
@ -85,30 +82,15 @@ impl FromStr for Hash {
|
||||||
type Err = hex::FromHexError;
|
type Err = hex::FromHexError;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
let str = trim_hex_prefix(s);
|
bytes_from_hex::<32>(s).map(Self)
|
||||||
let mut out = [0_u8; 32];
|
|
||||||
hex::decode_to_slice(str, &mut out)?;
|
|
||||||
Ok(Self(out))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Serialize hashes into human readable hex strings or byte arrays.
|
/// Serialize hashes into human readable hex strings or byte arrays.
|
||||||
/// Hex strings are lower case without prefix and always 32 bytes.
|
/// Hex strings are lower case without prefix and always 32 bytes.
|
||||||
impl Serialize for Hash {
|
impl Serialize for Hash {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||||
where
|
serialize_bytes::<32, 66, S>(serializer, &self.0)
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,55 +98,9 @@ impl Serialize for Hash {
|
||||||
/// Hex strings can be upper/lower/mixed case and have an optional `0x` prefix
|
/// Hex strings can be upper/lower/mixed case and have an optional `0x` prefix
|
||||||
/// but they must always be exactly 32 bytes.
|
/// but they must always be exactly 32 bytes.
|
||||||
impl<'de> Deserialize<'de> for Hash {
|
impl<'de> Deserialize<'de> for Hash {
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
|
||||||
where
|
let bytes = deserialize_bytes::<32, _>(deserializer)?;
|
||||||
D: serde::Deserializer<'de>,
|
Ok(Self(bytes))
|
||||||
{
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,14 +115,14 @@ pub mod test {
|
||||||
let hash = Hash([0; 32]);
|
let hash = Hash([0; 32]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
to_string(&hash).unwrap(),
|
to_string(&hash).unwrap(),
|
||||||
"\"0000000000000000000000000000000000000000000000000000000000000000\""
|
"\"0x0000000000000000000000000000000000000000000000000000000000000000\""
|
||||||
);
|
);
|
||||||
let hash = Hash(hex!(
|
let hash = Hash(hex!(
|
||||||
"1c4823575d154474ee3e5ac838d002456a815181437afd14f126da58a9912bbe"
|
"1c4823575d154474ee3e5ac838d002456a815181437afd14f126da58a9912bbe"
|
||||||
));
|
));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
to_string(&hash).unwrap(),
|
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};
|
use tiny_keccak::{Hasher as _, Keccak};
|
||||||
|
|
||||||
pub(crate) fn keccak256(bytes: &[u8]) -> [u8; 32] {
|
pub(crate) fn keccak256(bytes: &[u8]) -> [u8; 32] {
|
||||||
|
@ -8,11 +16,87 @@ pub(crate) fn keccak256(bytes: &[u8]) -> [u8; 32] {
|
||||||
output
|
output
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper function to optionally remove `0x` prefix from hex strings.
|
/// Helper to serialize byte arrays
|
||||||
pub(crate) fn trim_hex_prefix(str: &str) -> &str {
|
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") {
|
if str.len() >= 2 && (&str[..2] == "0x" || &str[..2] == "0X") {
|
||||||
&str[2..]
|
&str[2..]
|
||||||
} else {
|
} else {
|
||||||
str
|
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