diff --git a/src/cryptonum/builder.rs b/src/cryptonum/builder.rs index 30d7891..8351890 100644 --- a/src/cryptonum/builder.rs +++ b/src/cryptonum/builder.rs @@ -230,6 +230,42 @@ macro_rules! construct_unsigned { generic_div(&self.contents, &a.contents, &mut q.contents, &mut r.contents); } + + fn to_bytes(&self) -> Vec { + let mut res = Vec::with_capacity($count * 8); + for x in self.contents.iter() { + res.push( (x >> 56) as u8 ); + res.push( (x >> 48) as u8 ); + res.push( (x >> 40) as u8 ); + res.push( (x >> 32) as u8 ); + res.push( (x >> 24) as u8 ); + res.push( (x >> 16) as u8 ); + res.push( (x >> 8) as u8 ); + res.push( (x >> 0) as u8 ); + } + res + } + + fn from_bytes(x: &[u8]) -> $type { + let mut res = $type::zero(); + let mut i = 0; + + assert!(x.len() >= ($count * 8)); + for chunk in x.chunks(8) { + assert!(chunk.len() == 8); + res.contents[i] = ((chunk[0] as u64) << 56) | + ((chunk[1] as u64) << 48) | + ((chunk[2] as u64) << 40) | + ((chunk[3] as u64) << 32) | + ((chunk[4] as u64) << 24) | + ((chunk[5] as u64) << 16) | + ((chunk[6] as u64) << 8) | + ((chunk[7] as u64) << 0); + i += 1; + } + assert!(i == $count); + res + } } #[cfg(test)] @@ -638,6 +674,13 @@ macro_rules! construct_unsigned { } } + quickcheck! { + fn serialization_inverts(a: $type) -> bool { + let bytes = a.to_bytes(); + let b = $type::from_bytes(&bytes); + a == b + } + } } }; } diff --git a/src/cryptonum/traits.rs b/src/cryptonum/traits.rs index 7b1f35e..9a12600 100644 --- a/src/cryptonum/traits.rs +++ b/src/cryptonum/traits.rs @@ -1,5 +1,12 @@ - pub trait CryptoNum { + /// Simultaneously compute the quotient and remainder of this number and + /// the given divisor. fn divmod(&self, a: &Self, q: &mut Self, r: &mut Self); + /// Convert a number to a series of bytes, in standard order (most to + /// least significant) + fn to_bytes(&self) -> Vec; + /// Convert a series of bytes into the number. The size of the given slice + /// must be greater than or equal to the size of the number, and must be + /// a multiple of 8 bytes long. Unused bytes should be ignored. + fn from_bytes(&[u8]) -> Self; } -