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

Make uint types (un)serializable #511

Merged
merged 7 commits into from Feb 5, 2021
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Expand Up @@ -34,5 +34,6 @@ serde = { version = "1", features = [ "derive" ], optional = true }
serde_json = "<1.0.45"
serde_test = "1"
secp256k1 = { version = "0.20.0", features = [ "recovery", "rand-std" ] }
bincode = "1.3.1"
# We need to pin ryu (transitive dep from serde_json) to stay compatible with Rust 1.22.0
ryu = "<1.0.5"
1 change: 1 addition & 0 deletions src/lib.rs
Expand Up @@ -47,6 +47,7 @@ pub extern crate bech32;
#[cfg(feature = "serde")] #[macro_use] extern crate serde;
#[cfg(all(test, feature = "serde"))] extern crate serde_json;
#[cfg(all(test, feature = "serde"))] extern crate serde_test;
#[cfg(all(test, feature = "serde"))] extern crate bincode;
#[cfg(all(test, feature = "unstable"))] extern crate test;

#[cfg(target_pointer_width = "16")]
Expand Down
1 change: 1 addition & 0 deletions src/util/endian.rs
Expand Up @@ -54,6 +54,7 @@ macro_rules! define_le_to_array {
define_slice_to_be!(slice_to_u32_be, u32);
define_slice_to_be!(slice_to_u64_be, u64);
define_be_to_array!(u32_to_array_be, u32, 4);
define_be_to_array!(u64_to_array_be, u64, 8);
define_slice_to_le!(slice_to_u16_le, u16);
define_slice_to_le!(slice_to_u32_le, u32);
define_slice_to_le!(slice_to_u64_le, u64);
Expand Down
151 changes: 150 additions & 1 deletion src/util/uint.rs
Expand Up @@ -90,9 +90,23 @@ macro_rules! construct_uint {
}
}

/// Creates big integer value from a byte slice array using
/// Creates big integer value from a byte array using
/// big-endian encoding
pub fn from_be_bytes(bytes: [u8; $n_words * 8]) -> $name {
Self::_from_be_slice(&bytes)
}

/// Creates big integer value from a byte slice using
/// big-endian encoding
pub fn from_be_slice(bytes: &[u8]) -> Result<$name, ParseLengthError> {
if bytes.len() != $n_words * 8 {
Err(ParseLengthError { actual: bytes.len(), expected: $n_words*8 })
} else {
Ok(Self::_from_be_slice(bytes))
}
}

fn _from_be_slice(bytes: &[u8]) -> $name {
use super::endian::slice_to_u64_be;
let mut slice = [0u64; $n_words];
slice.iter_mut()
Expand All @@ -102,6 +116,17 @@ macro_rules! construct_uint {
$name(slice)
}

/// Convert a big integer into a byte array using big-endian encoding
pub fn to_be_bytes(&self) -> [u8; $n_words * 8] {
use super::endian::u64_to_array_be;
let mut res = [0; $n_words * 8];
for i in 0..$n_words {
let start = i * 8;
res[start..start+8].copy_from_slice(&u64_to_array_be(self.0[$n_words - (i+1)]));
}
res
}

// divmod like operation, returns (quotient, remainder)
#[inline]
fn div_rem(self, other: Self) -> (Self, Self) {
Expand Down Expand Up @@ -403,12 +428,87 @@ macro_rules! construct_uint {
Ok($name(ret))
}
}

#[cfg(feature = "serde")]
impl $crate::serde::Serialize for $name {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: $crate::serde::Serializer,
{
use $crate::hashes::hex::ToHex;
let bytes = self.to_be_bytes();
if serializer.is_human_readable() {
serializer.serialize_str(&bytes.to_hex())
} else {
serializer.serialize_bytes(&bytes)
}
}
}

#[cfg(feature = "serde")]
impl<'de> $crate::serde::Deserialize<'de> for $name {
fn deserialize<D: $crate::serde::Deserializer<'de>>(
deserializer: D,
) -> Result<Self, D::Error> {
use ::std::fmt;
use $crate::hashes::hex::FromHex;
use $crate::serde::de;
struct Visitor;
impl<'de> de::Visitor<'de> for Visitor {
type Value = $name;

fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} bytes or a hex string with {} characters", $n_words * 8, $n_words * 8 * 2)
}

fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
let bytes = Vec::from_hex(s)
.map_err(|_| de::Error::invalid_value(de::Unexpected::Str(s), &self))?;
$name::from_be_slice(&bytes)
.map_err(|_| de::Error::invalid_length(bytes.len() * 2, &self))
}

fn visit_bytes<E>(self, bytes: &[u8]) -> Result<Self::Value, E>
where
E: de::Error,
{
$name::from_be_slice(bytes)
.map_err(|_| de::Error::invalid_length(bytes.len(), &self))
}
}

if deserializer.is_human_readable() {
deserializer.deserialize_str(Visitor)
} else {
deserializer.deserialize_bytes(Visitor)
}
}
}
);
}

construct_uint!(Uint256, 4);
construct_uint!(Uint128, 2);

/// Invalid slice length
#[derive(Debug, PartialEq, PartialOrd, Clone, Copy, Hash)]
shesek marked this conversation as resolved.
Show resolved Hide resolved
/// Invalid slice length
pub struct ParseLengthError {
/// The length of the slice de-facto
pub actual: usize,
/// The required length of the slice
pub expected: usize,
}

impl ::std::fmt::Display for ParseLengthError {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(f, "Invalid length: got {}, expected {}", self.actual, self.expected)
}
}

shesek marked this conversation as resolved.
Show resolved Hide resolved
impl Uint256 {
/// Increment by 1
#[inline]
Expand Down Expand Up @@ -505,6 +605,16 @@ mod tests {
Uint256([0x11fed2bad1c0ffe0, 0xbaadf00ddefaceda, 0xdeafbabe2bedfeed, 0x1badcafedeadbeef]));
}

#[test]
pub fn uint_to_be_bytes() {
assert_eq!(Uint128([0xdeafbabe2bedfeed, 0x1badcafedeadbeef]).to_be_bytes(),
[0x1b, 0xad, 0xca, 0xfe, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xaf, 0xba, 0xbe, 0x2b, 0xed, 0xfe, 0xed]);

assert_eq!(Uint256([0x11fed2bad1c0ffe0, 0xbaadf00ddefaceda, 0xdeafbabe2bedfeed, 0x1badcafedeadbeef]).to_be_bytes(),
[0x1b, 0xad, 0xca, 0xfe, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xaf, 0xba, 0xbe, 0x2b, 0xed, 0xfe, 0xed,
0xba, 0xad, 0xf0, 0x0d, 0xde, 0xfa, 0xce, 0xda, 0x11, 0xfe, 0xd2, 0xba, 0xd1, 0xc0, 0xff, 0xe0]);
}

#[test]
pub fn uint256_arithmetic_test() {
let init = Uint256::from_u64(0xDEADBEEFDEADBEEF).unwrap();
Expand Down Expand Up @@ -612,4 +722,43 @@ mod tests {
assert_eq!(end1.ok(), Some(start1));
assert_eq!(end2.ok(), Some(start2));
}

#[cfg(feature = "serde")]
#[test]
pub fn uint256_serde_test() {
let check = |uint, hex| {
let json = format!("\"{}\"", hex);
assert_eq!(::serde_json::to_string(&uint).unwrap(), json);
assert_eq!(::serde_json::from_str::<Uint256>(&json).unwrap(), uint);

let bin_encoded = ::bincode::serialize(&uint).unwrap();
let bin_decoded: Uint256 = ::bincode::deserialize(&bin_encoded).unwrap();
assert_eq!(bin_decoded, uint);
};

check(
Uint256::from_u64(0).unwrap(),
"0000000000000000000000000000000000000000000000000000000000000000",
);
check(
Uint256::from_u64(0xDEADBEEF).unwrap(),
"00000000000000000000000000000000000000000000000000000000deadbeef",
);
check(
Uint256([0xaa11, 0xbb22, 0xcc33, 0xdd44]),
"000000000000dd44000000000000cc33000000000000bb22000000000000aa11",
);
check(
Uint256([u64::max_value(), u64::max_value(), u64::max_value(), u64::max_value()]),
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
);
check(
Uint256([ 0xA69B4555DEADBEEF, 0xA69B455CD41BB662, 0xD41BB662A69B4550, 0xDEADBEEAA69B455C ]),
"deadbeeaa69b455cd41bb662a69b4550a69b455cd41bb662a69b4555deadbeef",
);

assert!(::serde_json::from_str::<Uint256>("\"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffg\"").is_err()); // invalid char
assert!(::serde_json::from_str::<Uint256>("\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\"").is_err()); // invalid length
assert!(::serde_json::from_str::<Uint256>("\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\"").is_err()); // invalid length
}
}