From bbcc58dca3094ecb838075f3302a170758a45558 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Mon, 8 Jul 2019 16:07:40 +1000 Subject: [PATCH] Start building new bitfield struct --- eth2/utils/ssz_types/Cargo.toml | 2 - eth2/utils/ssz_types/src/bit_list.rs | 39 +- eth2/utils/ssz_types/src/bit_vector.rs | 17 +- eth2/utils/ssz_types/src/bitfield.rs | 520 ++++++++++++++++++ eth2/utils/ssz_types/src/impl_bitfield_fns.rs | 291 ---------- eth2/utils/ssz_types/src/lib.rs | 4 +- 6 files changed, 540 insertions(+), 333 deletions(-) create mode 100644 eth2/utils/ssz_types/src/bitfield.rs delete mode 100644 eth2/utils/ssz_types/src/impl_bitfield_fns.rs diff --git a/eth2/utils/ssz_types/Cargo.toml b/eth2/utils/ssz_types/Cargo.toml index f5680ecb1..2e4cbc899 100644 --- a/eth2/utils/ssz_types/Cargo.toml +++ b/eth2/utils/ssz_types/Cargo.toml @@ -5,8 +5,6 @@ authors = ["Paul Hauner "] edition = "2018" [dependencies] -bit_reverse = "0.1" -bit-vec = "0.5.0" cached_tree_hash = { path = "../cached_tree_hash" } tree_hash = { path = "../tree_hash" } serde = "1.0" diff --git a/eth2/utils/ssz_types/src/bit_list.rs b/eth2/utils/ssz_types/src/bit_list.rs index bbe4a653b..83fa6a0bd 100644 --- a/eth2/utils/ssz_types/src/bit_list.rs +++ b/eth2/utils/ssz_types/src/bit_list.rs @@ -1,6 +1,5 @@ use super::*; -use crate::{impl_bitfield_fns, reverse_bit_order, Error}; -use bit_vec::BitVec as Bitfield; +use crate::{bitfield::Bitfield, impl_bitfield_fns, Error}; use serde::de::{Deserialize, Deserializer}; use serde::ser::{Serialize, Serializer}; use serde_hex::{encode, PrefixedHexVisitor}; @@ -53,7 +52,7 @@ impl BitList { /// Create a new, empty BitList. pub fn new() -> Self { Self { - bitfield: Bitfield::default(), + bitfield: Bitfield::with_capacity(Self::max_len()), _phantom: PhantomData, } } @@ -75,18 +74,20 @@ impl BitList { pub fn max_len() -> usize { N::to_usize() } - - /// Create a new bitfield using the supplied `bytes` as input - pub fn from_bytes(bytes: &[u8]) -> Result { - Self::validate_length(bytes.len().saturating_mul(8))?; - - Ok(Self { - bitfield: Bitfield::from_bytes(&reverse_bit_order(bytes.to_vec())), - _phantom: PhantomData, - }) - } } +/* +fn encode_bitfield(bitfield: Bitfield) -> Vec { + // Set the next bit of the bitfield to true. + // + // SSZ spec: + // + // An additional leading 1 bit is added so that the length in bits will also be known. + bitfield.set(bitfield.len(), true); + let bytes = bitfield.to_bytes(); +} +*/ + impl BitList { /// Compute the intersection (binary-and) of this bitfield with another /// @@ -106,7 +107,7 @@ impl BitList { /// /// If `self` and `other` have different lengths. pub fn intersection_inplace(&mut self, other: &Self) { - self.bitfield.intersect(&other.bitfield); + self.bitfield.intersection(&other.bitfield); } /// Compute the union (binary-or) of this bitfield with another. Lengths must match. @@ -154,14 +155,7 @@ impl BitList { } } -impl default::Default for BitList { - /// Default provides the "empty" bitfield - /// Note: the empty bitfield is set to the `0` byte. - fn default() -> Self { - Self::from_elem(0, false).expect("Zero cannot be larger than the maximum length") - } -} - +/* #[cfg(test)] mod test { use super::*; @@ -451,3 +445,4 @@ mod test { assert!(a.difference(&a).is_zero()); } } +*/ diff --git a/eth2/utils/ssz_types/src/bit_vector.rs b/eth2/utils/ssz_types/src/bit_vector.rs index ea5fcf978..ba63281cf 100644 --- a/eth2/utils/ssz_types/src/bit_vector.rs +++ b/eth2/utils/ssz_types/src/bit_vector.rs @@ -1,6 +1,5 @@ use super::*; -use crate::{impl_bitfield_fns, reverse_bit_order, Error}; -use bit_vec::BitVec as Bitfield; +use crate::{bitfield::Bitfield, impl_bitfield_fns, Error}; use serde::de::{Deserialize, Deserializer}; use serde::ser::{Serialize, Serializer}; use serde_hex::{encode, PrefixedHexVisitor}; @@ -54,18 +53,6 @@ impl BitVector { N::to_usize() } - /// Create a new bitfield using the supplied `bytes` as input - pub fn from_bytes(bytes: &[u8]) -> Result { - if Self::capacity() >= 8 && bytes.len() != 1 { - Self::validate_length(bytes.len().saturating_mul(8))?; - } - - Ok(Self { - bitfield: Bitfield::from_bytes(&reverse_bit_order(bytes.to_vec())), - _phantom: PhantomData, - }) - } - fn validate_length(len: usize) -> Result<(), Error> { let fixed_len = N::to_usize(); @@ -113,6 +100,7 @@ mod test { } */ + /* #[test] fn new_bitfield() { let mut field = BitVector1024::new(); @@ -145,7 +133,6 @@ mod test { assert!(bitvec.get(4).is_err()); } - /* #[test] fn from_bytes_bytes_too_long() { let bytes = &[0, 0]; diff --git a/eth2/utils/ssz_types/src/bitfield.rs b/eth2/utils/ssz_types/src/bitfield.rs new file mode 100644 index 000000000..a64615bd7 --- /dev/null +++ b/eth2/utils/ssz_types/src/bitfield.rs @@ -0,0 +1,520 @@ +/// A heap-allocated, ordered, fixed-length, collection of `bool` values. +/// +/// The length of the Bitfield is set at instantiation (i.e., runtime, not compile time). +/// +/// The internal representation of the bitfield is the same as that required by SSZ - the highest +/// byte (by `Vec` index) stores the lowest bit-indices and the right-most bit stores the lowest +/// bit-index. E.g., `vec![0b0000_0010, 0b0000_0001]` has bits `1, 9` set. +#[derive(Clone, Debug, PartialEq)] +pub struct Bitfield { + bytes: Vec, + len: usize, +} + +impl Bitfield { + pub fn with_capacity(num_bits: usize) -> Self { + Self { + bytes: vec![0; Self::bytes_for_bit_len(num_bits)], + len: num_bits, + } + } + + pub fn set(&mut self, i: usize, value: bool) -> Option<()> { + if i < self.len { + let byte = { + let num_bytes = self.bytes.len(); + let offset = i / 8; + self.bytes + .get_mut(num_bytes - offset - 1) + .expect("Cannot be OOB if less than self.len") + }; + + if value { + *byte |= 1 << (i % 8) + } else { + *byte &= !(1 << (i % 8)) + } + + Some(()) + } else { + None + } + } + + pub fn get(&self, i: usize) -> Option { + if i < self.len { + let byte = { + let num_bytes = self.bytes.len(); + let offset = i / 8; + self.bytes + .get(num_bytes - offset - 1) + .expect("Cannot be OOB if less than self.len") + }; + + Some(*byte & 1 << (i % 8) > 0) + } else { + None + } + } + + pub fn len(&self) -> usize { + self.len + } + + pub fn is_empty(&self) -> bool { + self.len == 0 + } + + fn bytes_for_bit_len(bit_len: usize) -> usize { + (bit_len + 7) / 8 + } + + /// Verify that the given `bytes` faithfully represent a bitfield of length `bit_len`. + /// + /// The only valid `bytes` for `bit_len == 0` is `&[0]`. + fn verify_bitfield_bytes(bytes: &[u8], bit_len: usize) -> bool { + if bytes.len() == 1 && bit_len == 0 && bytes == &[0] { + true // A bitfield with `bit_len` 0 can only be represented by a single zero byte. + } else if bytes.len() != Bitfield::bytes_for_bit_len(bit_len) || bytes.is_empty() { + false // The number of bytes must be the minimum required to represent `bit_len`. + } else { + // Ensure there are no bits higher than `bit_len` that are set to true. + let (mask, _) = u8::max_value().overflowing_shr(bit_len as u32 % 8); + (bytes.last().expect("Bytes cannot be empty") & !mask) == 0 + } + } + + pub fn to_bytes(self) -> Vec { + self.bytes + } + + pub fn as_slice(&self) -> &[u8] { + &self.bytes + } + + pub fn from_bytes(bytes: Vec, bit_len: usize) -> Option { + if bytes.len() == 1 && bit_len == 0 && bytes == &[0] { + // A bitfield with `bit_len` 0 can only be represented by a single zero byte. + Some(Self { bytes, len: 0 }) + } else if bytes.len() != Bitfield::bytes_for_bit_len(bit_len) || bytes.is_empty() { + // The number of bytes must be the minimum required to represent `bit_len`. + None + } else { + // Ensure there are no bits higher than `bit_len` that are set to true. + let (mask, _) = u8::max_value().overflowing_shr(8 - (bit_len as u32 % 8)); + + if (bytes.first().expect("Bytes cannot be empty") & !mask) == 0 { + Some(Self { + bytes, + len: bit_len, + }) + } else { + None + } + } + } + + pub fn iter(&self) -> BitIter<'_> { + BitIter { + bitfield: self, + i: 0, + } + } + + pub fn is_zero(&self) -> bool { + !self.bytes.iter().any(|byte| (*byte & u8::max_value()) > 0) + } + + pub fn intersection(&self, other: &Self) -> Option { + if self.is_comparable(other) { + let mut res = self.clone(); + res.intersection_inplace(other); + Some(res) + } else { + None + } + } + + pub fn intersection_inplace(&mut self, other: &Self) -> Option<()> { + if self.is_comparable(other) { + for i in 0..self.bytes.len() { + self.bytes[i] = self.bytes[i] & other.bytes[i]; + } + Some(()) + } else { + None + } + } + + pub fn union(&self, other: &Self) -> Option { + if self.is_comparable(other) { + let mut res = self.clone(); + res.union_inplace(other); + Some(res) + } else { + None + } + } + + pub fn union_inplace(&mut self, other: &Self) -> Option<()> { + if self.is_comparable(other) { + for i in 0..self.bytes.len() { + self.bytes[i] = self.bytes[i] | other.bytes[i]; + } + Some(()) + } else { + None + } + } + + pub fn difference(&self, other: &Self) -> Option { + if self.is_comparable(other) { + let mut res = self.clone(); + res.difference_inplace(other); + Some(res) + } else { + None + } + } + + pub fn difference_inplace(&mut self, other: &Self) -> Option<()> { + if self.is_comparable(other) { + for i in 0..self.bytes.len() { + self.bytes[i] = self.bytes[i] & !other.bytes[i]; + } + Some(()) + } else { + None + } + } + + pub fn is_comparable(&self, other: &Self) -> bool { + (self.len() == other.len()) && (self.bytes.len() == other.bytes.len()) + } +} + +pub struct BitIter<'a> { + bitfield: &'a Bitfield, + i: usize, +} + +impl<'a> Iterator for BitIter<'a> { + type Item = bool; + + fn next(&mut self) -> Option { + let res = self.bitfield.get(self.i); + self.i += 1; + res + } +} + +/// Provides a common `impl` for structs that wrap a `$name`. +#[macro_export] +macro_rules! impl_bitfield_fns { + ($name: ident) => { + impl $name { + pub fn with_capacity(initial_len: usize) -> Result { + Self::validate_length(initial_len)?; + + Self::with_capacity(initial_len) + } + + pub fn get(&self, i: usize) -> Result { + if i < N::to_usize() { + match self.bitfield.get(i) { + Some(value) => Ok(value), + None => Err(Error::OutOfBounds { + i, + len: self.bitfield.len(), + }), + } + } else { + Err(Error::InvalidLength { + i, + len: N::to_usize(), + }) + } + } + + pub fn set(&mut self, i: usize, value: bool) -> Option<()> { + self.bitfield.set(i, value) + } + + /// Returns the number of bits in this bitfield. + pub fn len(&self) -> usize { + self.bitfield.len() + } + + /// Returns true if `self.len() == 0` + pub fn is_empty(&self) -> bool { + self.bitfield.is_empty() + } + + /// Returns true if all bits are set to 0. + pub fn is_zero(&self) -> bool { + self.bitfield.is_zero() + } + + /// Returns the number of bytes presently used to store the bitfield. + pub fn num_bytes(&self) -> usize { + self.bitfield.as_slice().len() + } + + /// Returns the number of `1` bits in the bitfield + pub fn num_set_bits(&self) -> usize { + self.bitfield.iter().filter(|&bit| bit).count() + } + } + + /* + impl Encode for $name { + fn is_ssz_fixed_len() -> bool { + false + } + + fn ssz_append(&self, buf: &mut Vec) { + buf.append(&mut self.bitfield.to_bytes()) + } + } + + impl Decode for $name { + fn is_ssz_fixed_len() -> bool { + false + } + + fn from_ssz_bytes(bytes: &[u8]) -> Result { + let bitfield = + Bitfield::from_bytes(bytes.to_vec(), bytes.len() * 8).expect("Cannot fail"); + Ok(Self { + bitfield, + _phantom: PhantomData, + }) + /* + $name::from_bytes(bytes) + .map_err(|e| ssz::DecodeError::BytesInvalid(format!("Bitfield {:?}", e))) + */ + } + } + + impl Serialize for $name { + /// Serde serialization is compliant with the Ethereum YAML test format. + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(&encode(self.bitfield.to_bytes())) + } + } + + impl<'de, N: Unsigned> Deserialize<'de> for $name { + /// Serde serialization is compliant with the Ethereum YAML test format. + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + // We reverse the bit-order so that the BitVec library can read its 0th + // bit from the end of the hex string, e.g. + // "0xef01" => [0xef, 0x01] => [0b1000_0000, 0b1111_1110] + let bytes = deserializer.deserialize_str(PrefixedHexVisitor)?; + $name::from_bytes(&bytes) + .map_err(|e| serde::de::Error::custom(format!("Bitfield {:?}", e))) + } + } + + impl tree_hash::TreeHash for $name { + fn tree_hash_type() -> tree_hash::TreeHashType { + tree_hash::TreeHashType::List + } + + fn tree_hash_packed_encoding(&self) -> Vec { + unreachable!("List should never be packed.") + } + + fn tree_hash_packing_factor() -> usize { + unreachable!("List should never be packed.") + } + + fn tree_hash_root(&self) -> Vec { + self.to_bytes().tree_hash_root() + } + } + */ + }; +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn from_bytes() { + assert!(Bitfield::from_bytes(vec![0b0000_0000], 0).is_some()); + assert!(Bitfield::from_bytes(vec![0b0000_0001], 1).is_some()); + assert!(Bitfield::from_bytes(vec![0b0000_0011], 2).is_some()); + assert!(Bitfield::from_bytes(vec![0b0000_0111], 3).is_some()); + assert!(Bitfield::from_bytes(vec![0b0000_1111], 4).is_some()); + assert!(Bitfield::from_bytes(vec![0b0001_1111], 5).is_some()); + assert!(Bitfield::from_bytes(vec![0b0011_1111], 6).is_some()); + assert!(Bitfield::from_bytes(vec![0b0111_1111], 7).is_some()); + assert!(Bitfield::from_bytes(vec![0b1111_1111], 8).is_some()); + + assert!(Bitfield::from_bytes(vec![0b0000_0001, 0b1111_1111], 9).is_some()); + assert!(Bitfield::from_bytes(vec![0b0000_0011, 0b1111_1111], 10).is_some()); + assert!(Bitfield::from_bytes(vec![0b0000_0111, 0b1111_1111], 11).is_some()); + assert!(Bitfield::from_bytes(vec![0b0000_1111, 0b1111_1111], 12).is_some()); + assert!(Bitfield::from_bytes(vec![0b0001_1111, 0b1111_1111], 13).is_some()); + assert!(Bitfield::from_bytes(vec![0b0011_1111, 0b1111_1111], 14).is_some()); + assert!(Bitfield::from_bytes(vec![0b0111_1111, 0b1111_1111], 15).is_some()); + assert!(Bitfield::from_bytes(vec![0b1111_1111, 0b1111_1111], 16).is_some()); + + for i in 0..8 { + assert!(Bitfield::from_bytes(vec![], i).is_none()); + assert!(Bitfield::from_bytes(vec![0b1111_1111], i).is_none()); + assert!(Bitfield::from_bytes(vec![0b1111_1110, 0b0000_0000], i).is_none()); + } + + assert!(Bitfield::from_bytes(vec![0b0000_0001], 0).is_none()); + + assert!(Bitfield::from_bytes(vec![0b0000_0001], 0).is_none()); + assert!(Bitfield::from_bytes(vec![0b0000_0011], 1).is_none()); + assert!(Bitfield::from_bytes(vec![0b0000_0111], 2).is_none()); + assert!(Bitfield::from_bytes(vec![0b0000_1111], 3).is_none()); + assert!(Bitfield::from_bytes(vec![0b0001_1111], 4).is_none()); + assert!(Bitfield::from_bytes(vec![0b0011_1111], 5).is_none()); + assert!(Bitfield::from_bytes(vec![0b0111_1111], 6).is_none()); + assert!(Bitfield::from_bytes(vec![0b1111_1111], 7).is_none()); + + assert!(Bitfield::from_bytes(vec![0b0000_0001, 0b1111_1111], 8).is_none()); + assert!(Bitfield::from_bytes(vec![0b0000_0011, 0b1111_1111], 9).is_none()); + assert!(Bitfield::from_bytes(vec![0b0000_0111, 0b1111_1111], 10).is_none()); + assert!(Bitfield::from_bytes(vec![0b0000_1111, 0b1111_1111], 11).is_none()); + assert!(Bitfield::from_bytes(vec![0b0001_1111, 0b1111_1111], 12).is_none()); + assert!(Bitfield::from_bytes(vec![0b0011_1111, 0b1111_1111], 13).is_none()); + assert!(Bitfield::from_bytes(vec![0b0111_1111, 0b1111_1111], 14).is_none()); + assert!(Bitfield::from_bytes(vec![0b1111_1111, 0b1111_1111], 15).is_none()); + } + + fn test_set_unset(num_bits: usize) { + let mut bitfield = Bitfield::with_capacity(num_bits); + + for i in 0..num_bits + 1 { + dbg!(i); + if i < num_bits { + // Starts as false + assert_eq!(bitfield.get(i), Some(false)); + // Can be set true. + assert!(bitfield.set(i, true).is_some()); + assert_eq!(bitfield.get(i), Some(true)); + // Can be set false + assert!(bitfield.set(i, false).is_some()); + assert_eq!(bitfield.get(i), Some(false)); + } else { + assert_eq!(bitfield.get(i), None); + assert!(bitfield.set(i, true).is_none()); + assert_eq!(bitfield.get(i), None); + } + } + } + + fn test_bytes_round_trip(num_bits: usize) { + dbg!(num_bits); + for i in 0..num_bits { + dbg!(i); + let mut bitfield = Bitfield::with_capacity(num_bits); + bitfield.set(i, true).unwrap(); + + let bytes = bitfield.clone().to_bytes(); + dbg!(&bytes); + assert_eq!(bitfield, Bitfield::from_bytes(bytes, num_bits).unwrap()); + } + } + + #[test] + fn set_unset() { + for i in 0..8 * 5 { + test_set_unset(i) + } + } + + #[test] + fn bytes_round_trip() { + for i in 0..8 * 5 { + test_bytes_round_trip(i) + } + } + + #[test] + fn to_bytes() { + let mut bitfield = Bitfield::with_capacity(9); + bitfield.set(0, true); + assert_eq!(bitfield.clone().to_bytes(), vec![0b0000_0000, 0b0000_0001]); + bitfield.set(1, true); + assert_eq!(bitfield.clone().to_bytes(), vec![0b0000_0000, 0b0000_0011]); + bitfield.set(2, true); + assert_eq!(bitfield.clone().to_bytes(), vec![0b0000_0000, 0b0000_0111]); + bitfield.set(3, true); + assert_eq!(bitfield.clone().to_bytes(), vec![0b0000_0000, 0b0000_1111]); + bitfield.set(4, true); + assert_eq!(bitfield.clone().to_bytes(), vec![0b0000_0000, 0b0001_1111]); + bitfield.set(5, true); + assert_eq!(bitfield.clone().to_bytes(), vec![0b0000_0000, 0b0011_1111]); + bitfield.set(6, true); + assert_eq!(bitfield.clone().to_bytes(), vec![0b0000_0000, 0b0111_1111]); + bitfield.set(7, true); + assert_eq!(bitfield.clone().to_bytes(), vec![0b0000_0000, 0b1111_1111]); + bitfield.set(8, true); + assert_eq!(bitfield.clone().to_bytes(), vec![0b0000_0001, 0b1111_1111]); + } + + #[test] + fn intersection() { + let a = Bitfield::from_bytes(vec![0b1100, 0b0001], 16).unwrap(); + let b = Bitfield::from_bytes(vec![0b1011, 0b1001], 16).unwrap(); + let c = Bitfield::from_bytes(vec![0b1000, 0b0001], 16).unwrap(); + + assert_eq!(a.intersection(&b).unwrap(), c); + assert_eq!(b.intersection(&a).unwrap(), c); + assert_eq!(a.intersection(&c).unwrap(), c); + assert_eq!(b.intersection(&c).unwrap(), c); + assert_eq!(a.intersection(&a).unwrap(), a); + assert_eq!(b.intersection(&b).unwrap(), b); + assert_eq!(c.intersection(&c).unwrap(), c); + } + + #[test] + fn union() { + let a = Bitfield::from_bytes(vec![0b1100, 0b0001], 16).unwrap(); + let b = Bitfield::from_bytes(vec![0b1011, 0b1001], 16).unwrap(); + let c = Bitfield::from_bytes(vec![0b1111, 0b1001], 16).unwrap(); + + assert_eq!(a.union(&b).unwrap(), c); + assert_eq!(b.union(&a).unwrap(), c); + assert_eq!(a.union(&a).unwrap(), a); + assert_eq!(b.union(&b).unwrap(), b); + assert_eq!(c.union(&c).unwrap(), c); + } + + #[test] + fn difference() { + let a = Bitfield::from_bytes(vec![0b1100, 0b0001], 16).unwrap(); + let b = Bitfield::from_bytes(vec![0b1011, 0b1001], 16).unwrap(); + let a_b = Bitfield::from_bytes(vec![0b0100, 0b0000], 16).unwrap(); + let b_a = Bitfield::from_bytes(vec![0b0011, 0b1000], 16).unwrap(); + + assert_eq!(a.difference(&b).unwrap(), a_b); + assert_eq!(b.difference(&a).unwrap(), b_a); + assert!(a.difference(&a).unwrap().is_zero()); + } + + #[test] + fn iter() { + let mut bitfield = Bitfield::with_capacity(9); + bitfield.set(2, true); + bitfield.set(8, true); + + assert_eq!( + bitfield.iter().collect::>(), + vec![false, false, true, false, false, false, false, false, true] + ); + } +} diff --git a/eth2/utils/ssz_types/src/impl_bitfield_fns.rs b/eth2/utils/ssz_types/src/impl_bitfield_fns.rs deleted file mode 100644 index dd11f4f30..000000000 --- a/eth2/utils/ssz_types/src/impl_bitfield_fns.rs +++ /dev/null @@ -1,291 +0,0 @@ -use bit_reverse::LookupReverse; - -/// Provides a common `impl` for structs that wrap a `$name`. -#[macro_export] -macro_rules! impl_bitfield_fns { - ($name: ident) => { - impl $name { - /// Create a new BitList list with `initial_len` bits all set to `false`. - pub fn with_capacity(initial_len: usize) -> Result { - Self::from_elem(initial_len, false) - } - - /// Create a new bitfield with the given length `initial_len` and all values set to `bit`. - /// - /// Note: if `initial_len` is not a multiple of 8, the remaining bits will be set to `false` - /// regardless of `bit`. - pub fn from_elem(initial_len: usize, bit: bool) -> Result { - // BitVec can panic if we don't set the len to be a multiple of 8. - let full_len = ((initial_len + 7) / 8) * 8; - - Self::validate_length(full_len)?; - - let mut bitfield = Bitfield::from_elem(full_len, false); - - if bit { - for i in 0..initial_len { - bitfield.set(i, true); - } - } - - Ok(Self { - bitfield, - _phantom: PhantomData, - }) - } - - /// Returns a vector of bytes representing the bitfield - pub fn to_bytes(&self) -> Vec { - if self.bitfield.is_empty() { - vec![0] // Empty bitfield should be represented as a zero byte. - } else { - reverse_bit_order(self.bitfield.to_bytes().to_vec()) - } - } - - /// Read the value of a bit. - /// - /// If the index is in bounds, then result is Ok(value) where value is `true` if the - /// bit is 1 and `false` if the bit is 0. If the index is out of bounds, we return an - /// error to that extent. - pub fn get(&self, i: usize) -> Result { - if i < N::to_usize() { - match self.bitfield.get(i) { - Some(value) => Ok(value), - None => Err(Error::OutOfBounds { - i, - len: self.bitfield.len(), - }), - } - } else { - Err(Error::InvalidLength { - i, - len: N::to_usize(), - }) - } - } - - /// Set the value of a bit. - /// - /// If the index is out of bounds, we expand the size of the underlying set to include - /// the new index. Returns the previous value if there was one. - pub fn set(&mut self, i: usize, value: bool) -> Result<(), Error> { - match self.get(i) { - Ok(previous) => Some(previous), - Err(Error::OutOfBounds { len, .. }) => { - let new_len = i - len + 1; - self.bitfield.grow(new_len, false); - None - } - Err(e) => return Err(e), - }; - - self.bitfield.set(i, value); - - Ok(()) - } - - /// Returns the number of bits in this bitfield. - pub fn len(&self) -> usize { - self.bitfield.len() - } - - /// Returns true if `self.len() == 0` - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - - /// Returns true if all bits are set to 0. - pub fn is_zero(&self) -> bool { - self.bitfield.none() - } - - /// Returns the number of bytes required to represent this bitfield. - pub fn num_bytes(&self) -> usize { - self.to_bytes().len() - } - - /// Returns the number of `1` bits in the bitfield - pub fn num_set_bits(&self) -> usize { - self.bitfield.iter().filter(|&bit| bit).count() - } - } - - impl cmp::PartialEq for $name { - /// Determines equality by comparing the `ssz` encoding of the two candidates. This - /// method ensures that the presence of high-order (empty) bits in the highest byte do - /// not exclude equality when they are in fact representing the same information. - fn eq(&self, other: &Self) -> bool { - ssz::ssz_encode(self) == ssz::ssz_encode(other) - } - } - - /// Create a new bitfield that is a union of two other bitfields. - /// - /// For example `union(0101, 1000) == 1101` - // TODO: length-independent intersection for BitAnd - impl std::ops::BitOr for $name { - type Output = Self; - - fn bitor(self, other: Self) -> Self { - let (biggest, smallest) = if self.len() > other.len() { - (&self, &other) - } else { - (&other, &self) - }; - let mut new = (*biggest).clone(); - for i in 0..smallest.len() { - if let Ok(true) = smallest.get(i) { - new.set(i, true) - .expect("Cannot produce bitfield larger than smallest of two given"); - } - } - new - } - } - - impl Encode for $name { - fn is_ssz_fixed_len() -> bool { - false - } - - fn ssz_append(&self, buf: &mut Vec) { - buf.append(&mut self.to_bytes()) - } - } - - impl Decode for $name { - fn is_ssz_fixed_len() -> bool { - false - } - - fn from_ssz_bytes(bytes: &[u8]) -> Result { - $name::from_bytes(bytes) - .map_err(|e| ssz::DecodeError::BytesInvalid(format!("Bitfield {:?}", e))) - } - } - - impl Serialize for $name { - /// Serde serialization is compliant with the Ethereum YAML test format. - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_str(&encode(self.to_bytes())) - } - } - - impl<'de, N: Unsigned> Deserialize<'de> for $name { - /// Serde serialization is compliant with the Ethereum YAML test format. - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - // We reverse the bit-order so that the BitVec library can read its 0th - // bit from the end of the hex string, e.g. - // "0xef01" => [0xef, 0x01] => [0b1000_0000, 0b1111_1110] - let bytes = deserializer.deserialize_str(PrefixedHexVisitor)?; - $name::from_bytes(&bytes) - .map_err(|e| serde::de::Error::custom(format!("Bitfield {:?}", e))) - } - } - - impl tree_hash::TreeHash for $name { - fn tree_hash_type() -> tree_hash::TreeHashType { - tree_hash::TreeHashType::List - } - - fn tree_hash_packed_encoding(&self) -> Vec { - unreachable!("List should never be packed.") - } - - fn tree_hash_packing_factor() -> usize { - unreachable!("List should never be packed.") - } - - fn tree_hash_root(&self) -> Vec { - self.to_bytes().tree_hash_root() - } - } - }; -} - -// Reverse the bit order of a whole byte vec, so that the ith bit -// of the input vec is placed in the (N - i)th bit of the output vec. -// This function is necessary for converting bitfields to and from YAML, -// as the BitVec library and the hex-parser use opposing bit orders. -pub fn reverse_bit_order(mut bytes: Vec) -> Vec { - bytes.reverse(); - bytes.into_iter().map(LookupReverse::swap_bits).collect() -} - -/* -/// Verify that the given `bytes` faithfully represent a bitfield of length `bit_len`. -/// -/// The only valid `bytes` for `bit_len == 0` is `&[0]`. -pub fn verify_bitfield_bytes(bytes: &[u8], bit_len: usize) -> bool { - if bytes.len() == 1 && bit_len == 0 && bytes == &[0] { - true // A bitfield with `bit_len` 0 can only be represented by a single zero byte. - } else if bytes.len() != ((bit_len + 7) / 8) || bytes.is_empty() { - false // The number of bytes must be the minimum required to represent `bit_len`. - } else { - // Ensure there are no bits higher than `bit_len` that are set to true. - let (mask, _) = u8::max_value().overflowing_shl(8 - (bit_len as u32 % 8)); - (bytes.last().expect("Bytes cannot be empty") & !mask) == 0 - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn bitfield_bytes_length() { - assert!(verify_bitfield_bytes(&[0b0000_0000], 0)); - assert!(verify_bitfield_bytes(&[0b1000_0000], 1)); - assert!(verify_bitfield_bytes(&[0b1100_0000], 2)); - assert!(verify_bitfield_bytes(&[0b1110_0000], 3)); - assert!(verify_bitfield_bytes(&[0b1111_0000], 4)); - assert!(verify_bitfield_bytes(&[0b1111_1000], 5)); - assert!(verify_bitfield_bytes(&[0b1111_1100], 6)); - assert!(verify_bitfield_bytes(&[0b1111_1110], 7)); - assert!(verify_bitfield_bytes(&[0b1111_1111], 8)); - - assert!(verify_bitfield_bytes(&[0b1111_1111, 0b0000_0000], 9)); - assert!(verify_bitfield_bytes(&[0b1111_1111, 0b1000_0000], 9)); - assert!(verify_bitfield_bytes(&[0b1111_1111, 0b1100_0000], 10)); - assert!(verify_bitfield_bytes(&[0b1111_1111, 0b1110_0000], 11)); - assert!(verify_bitfield_bytes(&[0b1111_1111, 0b1111_0000], 12)); - assert!(verify_bitfield_bytes(&[0b1111_1111, 0b1111_1000], 13)); - assert!(verify_bitfield_bytes(&[0b1111_1111, 0b1111_1100], 14)); - assert!(verify_bitfield_bytes(&[0b1111_1111, 0b1111_1110], 15)); - - for i in 0..8 { - assert!(!verify_bitfield_bytes(&[], i)); - assert!(!verify_bitfield_bytes(&[0b1111_1111], i)); - assert!(!verify_bitfield_bytes(&[0b1111_1110, 0b0000_0000], i)); - } - - assert!(!verify_bitfield_bytes(&[0b1000_0000], 0)); - - assert!(!verify_bitfield_bytes(&[0b1000_0000], 0)); - assert!(!verify_bitfield_bytes(&[0b1100_0000], 1)); - assert!(!verify_bitfield_bytes(&[0b1110_0000], 2)); - assert!(!verify_bitfield_bytes(&[0b1111_0000], 3)); - assert!(!verify_bitfield_bytes(&[0b1111_1000], 4)); - assert!(!verify_bitfield_bytes(&[0b1111_1100], 5)); - assert!(!verify_bitfield_bytes(&[0b1111_1110], 6)); - assert!(!verify_bitfield_bytes(&[0b1111_1111], 7)); - - assert!(!verify_bitfield_bytes(&[0b1111_1111, 0b1000_0000], 8)); - assert!(!verify_bitfield_bytes(&[0b1111_1111, 0b1100_0000], 9)); - assert!(!verify_bitfield_bytes(&[0b1111_1111, 0b1110_0000], 10)); - assert!(!verify_bitfield_bytes(&[0b1111_1111, 0b1111_0000], 11)); - assert!(!verify_bitfield_bytes(&[0b1111_1111, 0b1111_1000], 12)); - assert!(!verify_bitfield_bytes(&[0b1111_1111, 0b1111_1100], 13)); - assert!(!verify_bitfield_bytes(&[0b1111_1111, 0b1111_1110], 14)); - - assert!(!verify_bitfield_bytes(&[0b1111_1110], 6)); - } -} -*/ diff --git a/eth2/utils/ssz_types/src/lib.rs b/eth2/utils/ssz_types/src/lib.rs index 1e49c6edd..9d76b2280 100644 --- a/eth2/utils/ssz_types/src/lib.rs +++ b/eth2/utils/ssz_types/src/lib.rs @@ -1,12 +1,10 @@ #[macro_use] -mod impl_bitfield_fns; +mod bitfield; mod bit_list; mod bit_vector; mod fixed_vector; mod variable_list; -use impl_bitfield_fns::reverse_bit_order; - pub use bit_list::BitList; pub use bit_vector::BitVector; pub use fixed_vector::FixedVector;