Skip to content

Commit

Permalink
PackedFe32: introduce ability to re-pack elements
Browse files Browse the repository at this point in the history
Adds a couple elements to the API. Note that this *is* a breaking change
because we are adding a method to the `PackedFe32` trait, which is not
sealed, so any downstream implementors will be broken.
  • Loading branch information
apoelstra committed Mar 27, 2024
1 parent 0dc47b4 commit fa8b70f
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 0 deletions.
5 changes: 5 additions & 0 deletions api/all-features.txt
Original file line number Diff line number Diff line change
Expand Up @@ -857,12 +857,14 @@ pub fn bech32::primitives::checksum::HrpFe32Iter<'hrp>::new(hrp: &'hrp bech32::p
pub fn bech32::primitives::checksum::HrpFe32Iter<'hrp>::next(&mut self) -> core::option::Option<bech32::primitives::gf32::Fe32>
pub fn bech32::primitives::checksum::HrpFe32Iter<'hrp>::size_hint(&self) -> (usize, core::option::Option<usize>)
pub fn bech32::primitives::checksum::PackedFe32::mul_by_x_then_add(&mut self, degree: usize, add: u8) -> u8
pub fn bech32::primitives::checksum::PackedFe32::pack<I: core::iter::traits::iterator::Iterator<Item = u8>>(iter: I) -> Self
pub fn bech32::primitives::checksum::PackedFe32::unpack(&self, n: usize) -> u8
pub fn bech32::primitives::checksum::PackedNull::bitxor(self, bech32::primitives::checksum::PackedNull) -> bech32::primitives::checksum::PackedNull
pub fn bech32::primitives::checksum::PackedNull::clone(&self) -> bech32::primitives::checksum::PackedNull
pub fn bech32::primitives::checksum::PackedNull::eq(&self, other: &bech32::primitives::checksum::PackedNull) -> bool
pub fn bech32::primitives::checksum::PackedNull::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
pub fn bech32::primitives::checksum::PackedNull::mul_by_x_then_add(&mut self, usize, u8) -> u8
pub fn bech32::primitives::checksum::PackedNull::pack<I: core::iter::traits::iterator::Iterator<Item = u8>>(iter: I) -> Self
pub fn bech32::primitives::checksum::PackedNull::unpack(&self, usize) -> u8
pub fn bech32::primitives::decode::AsciiToFe32Iter<'s>::len(&self) -> usize
pub fn bech32::primitives::decode::AsciiToFe32Iter<'s>::next(&mut self) -> core::option::Option<bech32::primitives::gf32::Fe32>
Expand Down Expand Up @@ -1131,10 +1133,13 @@ pub fn bech32::segwit::encode_v0(hrp: bech32::primitives::hrp::Hrp, witness_prog
pub fn bech32::segwit::encode_v1(hrp: bech32::primitives::hrp::Hrp, witness_program: &[u8]) -> core::result::Result<alloc::string::String, bech32::segwit::EncodeError>
pub fn bech32::segwit::encoded_length(hrp: bech32::primitives::hrp::Hrp, _witness_version: bech32::primitives::gf32::Fe32, witness_program: &[u8]) -> core::result::Result<usize, bech32::primitives::decode::SegwitCodeLengthError>
pub fn u128::mul_by_x_then_add(&mut self, degree: usize, add: u8) -> u8
pub fn u128::pack<I: core::iter::traits::iterator::Iterator<Item = u8>>(iter: I) -> Self
pub fn u128::unpack(&self, n: usize) -> u8
pub fn u32::mul_by_x_then_add(&mut self, degree: usize, add: u8) -> u8
pub fn u32::pack<I: core::iter::traits::iterator::Iterator<Item = u8>>(iter: I) -> Self
pub fn u32::unpack(&self, n: usize) -> u8
pub fn u64::mul_by_x_then_add(&mut self, degree: usize, add: u8) -> u8
pub fn u64::pack<I: core::iter::traits::iterator::Iterator<Item = u8>>(iter: I) -> Self
pub fn u64::unpack(&self, n: usize) -> u8
pub fn u8::from(v: bech32::primitives::gf32::Fe32) -> u8
pub mod bech32
Expand Down
5 changes: 5 additions & 0 deletions api/alloc-only.txt
Original file line number Diff line number Diff line change
Expand Up @@ -817,12 +817,14 @@ pub fn bech32::primitives::checksum::HrpFe32Iter<'hrp>::new(hrp: &'hrp bech32::p
pub fn bech32::primitives::checksum::HrpFe32Iter<'hrp>::next(&mut self) -> core::option::Option<bech32::primitives::gf32::Fe32>
pub fn bech32::primitives::checksum::HrpFe32Iter<'hrp>::size_hint(&self) -> (usize, core::option::Option<usize>)
pub fn bech32::primitives::checksum::PackedFe32::mul_by_x_then_add(&mut self, degree: usize, add: u8) -> u8
pub fn bech32::primitives::checksum::PackedFe32::pack<I: core::iter::traits::iterator::Iterator<Item = u8>>(iter: I) -> Self
pub fn bech32::primitives::checksum::PackedFe32::unpack(&self, n: usize) -> u8
pub fn bech32::primitives::checksum::PackedNull::bitxor(self, bech32::primitives::checksum::PackedNull) -> bech32::primitives::checksum::PackedNull
pub fn bech32::primitives::checksum::PackedNull::clone(&self) -> bech32::primitives::checksum::PackedNull
pub fn bech32::primitives::checksum::PackedNull::eq(&self, other: &bech32::primitives::checksum::PackedNull) -> bool
pub fn bech32::primitives::checksum::PackedNull::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
pub fn bech32::primitives::checksum::PackedNull::mul_by_x_then_add(&mut self, usize, u8) -> u8
pub fn bech32::primitives::checksum::PackedNull::pack<I: core::iter::traits::iterator::Iterator<Item = u8>>(iter: I) -> Self
pub fn bech32::primitives::checksum::PackedNull::unpack(&self, usize) -> u8
pub fn bech32::primitives::decode::AsciiToFe32Iter<'s>::len(&self) -> usize
pub fn bech32::primitives::decode::AsciiToFe32Iter<'s>::next(&mut self) -> core::option::Option<bech32::primitives::gf32::Fe32>
Expand Down Expand Up @@ -1073,10 +1075,13 @@ pub fn bech32::segwit::encode_v0(hrp: bech32::primitives::hrp::Hrp, witness_prog
pub fn bech32::segwit::encode_v1(hrp: bech32::primitives::hrp::Hrp, witness_program: &[u8]) -> core::result::Result<alloc::string::String, bech32::segwit::EncodeError>
pub fn bech32::segwit::encoded_length(hrp: bech32::primitives::hrp::Hrp, _witness_version: bech32::primitives::gf32::Fe32, witness_program: &[u8]) -> core::result::Result<usize, bech32::primitives::decode::SegwitCodeLengthError>
pub fn u128::mul_by_x_then_add(&mut self, degree: usize, add: u8) -> u8
pub fn u128::pack<I: core::iter::traits::iterator::Iterator<Item = u8>>(iter: I) -> Self
pub fn u128::unpack(&self, n: usize) -> u8
pub fn u32::mul_by_x_then_add(&mut self, degree: usize, add: u8) -> u8
pub fn u32::pack<I: core::iter::traits::iterator::Iterator<Item = u8>>(iter: I) -> Self
pub fn u32::unpack(&self, n: usize) -> u8
pub fn u64::mul_by_x_then_add(&mut self, degree: usize, add: u8) -> u8
pub fn u64::pack<I: core::iter::traits::iterator::Iterator<Item = u8>>(iter: I) -> Self
pub fn u64::unpack(&self, n: usize) -> u8
pub fn u8::from(v: bech32::primitives::gf32::Fe32) -> u8
pub mod bech32
Expand Down
5 changes: 5 additions & 0 deletions api/no-features.txt
Original file line number Diff line number Diff line change
Expand Up @@ -758,12 +758,14 @@ pub fn bech32::primitives::checksum::HrpFe32Iter<'hrp>::new(hrp: &'hrp bech32::p
pub fn bech32::primitives::checksum::HrpFe32Iter<'hrp>::next(&mut self) -> core::option::Option<bech32::primitives::gf32::Fe32>
pub fn bech32::primitives::checksum::HrpFe32Iter<'hrp>::size_hint(&self) -> (usize, core::option::Option<usize>)
pub fn bech32::primitives::checksum::PackedFe32::mul_by_x_then_add(&mut self, degree: usize, add: u8) -> u8
pub fn bech32::primitives::checksum::PackedFe32::pack<I: core::iter::traits::iterator::Iterator<Item = u8>>(iter: I) -> Self
pub fn bech32::primitives::checksum::PackedFe32::unpack(&self, n: usize) -> u8
pub fn bech32::primitives::checksum::PackedNull::bitxor(self, bech32::primitives::checksum::PackedNull) -> bech32::primitives::checksum::PackedNull
pub fn bech32::primitives::checksum::PackedNull::clone(&self) -> bech32::primitives::checksum::PackedNull
pub fn bech32::primitives::checksum::PackedNull::eq(&self, other: &bech32::primitives::checksum::PackedNull) -> bool
pub fn bech32::primitives::checksum::PackedNull::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
pub fn bech32::primitives::checksum::PackedNull::mul_by_x_then_add(&mut self, usize, u8) -> u8
pub fn bech32::primitives::checksum::PackedNull::pack<I: core::iter::traits::iterator::Iterator<Item = u8>>(iter: I) -> Self
pub fn bech32::primitives::checksum::PackedNull::unpack(&self, usize) -> u8
pub fn bech32::primitives::decode::AsciiToFe32Iter<'s>::len(&self) -> usize
pub fn bech32::primitives::decode::AsciiToFe32Iter<'s>::next(&mut self) -> core::option::Option<bech32::primitives::gf32::Fe32>
Expand Down Expand Up @@ -998,10 +1000,13 @@ pub fn bech32::segwit::encode_to_fmt_unchecked<W: core::fmt::Write>(fmt: &mut W,
pub fn bech32::segwit::encode_upper_to_fmt_unchecked<W: core::fmt::Write>(fmt: &mut W, hrp: bech32::primitives::hrp::Hrp, witness_version: bech32::primitives::gf32::Fe32, witness_program: &[u8]) -> core::fmt::Result
pub fn bech32::segwit::encoded_length(hrp: bech32::primitives::hrp::Hrp, _witness_version: bech32::primitives::gf32::Fe32, witness_program: &[u8]) -> core::result::Result<usize, bech32::primitives::decode::SegwitCodeLengthError>
pub fn u128::mul_by_x_then_add(&mut self, degree: usize, add: u8) -> u8
pub fn u128::pack<I: core::iter::traits::iterator::Iterator<Item = u8>>(iter: I) -> Self
pub fn u128::unpack(&self, n: usize) -> u8
pub fn u32::mul_by_x_then_add(&mut self, degree: usize, add: u8) -> u8
pub fn u32::pack<I: core::iter::traits::iterator::Iterator<Item = u8>>(iter: I) -> Self
pub fn u32::unpack(&self, n: usize) -> u8
pub fn u64::mul_by_x_then_add(&mut self, degree: usize, add: u8) -> u8
pub fn u64::pack<I: core::iter::traits::iterator::Iterator<Item = u8>>(iter: I) -> Self
pub fn u64::unpack(&self, n: usize) -> u8
pub fn u8::from(v: bech32::primitives::gf32::Fe32) -> u8
pub mod bech32
Expand Down
52 changes: 52 additions & 0 deletions src/primitives/checksum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,18 @@ pub trait PackedFe32: Copy + PartialEq + Eq + ops::BitXor<Self, Output = Self> {
/// The number of fe32s that can fit into the type; computed as floor(bitwidth / 5).
const WIDTH: usize = mem::size_of::<Self>() * 8 / 5;

/// Takes an iterator of `u8`s (or [`Fe32`]s converted to `u8`s) and packs
/// them into a [`Self`].
///
/// For sequences representing polynomials, the iterator should yield the
/// coefficients in little-endian order, i.e. the 0th coefficien first.
///
/// # Panics
///
/// May panic if the iterator yields more items than can fit into the bit-packed
/// type.
fn pack<I: Iterator<Item = u8>>(iter: I) -> Self;

/// Extracts the coefficient of the x^n from the packed polynomial.
fn unpack(&self, n: usize) -> u8;

Expand Down Expand Up @@ -183,6 +195,14 @@ impl PackedFe32 for PackedNull {
fn unpack(&self, _: usize) -> u8 { 0 }
#[inline]
fn mul_by_x_then_add(&mut self, _: usize, _: u8) -> u8 { 0 }

#[inline]
fn pack<I: Iterator<Item = u8>>(mut iter: I) -> Self {
if iter.next().is_some() {
panic!("Cannot pack anything into a PackedNull");
}
Self
}
}

macro_rules! impl_packed_fe32 {
Expand All @@ -207,6 +227,18 @@ macro_rules! impl_packed_fe32 {
*self |= Self::from(add);
ret
}

#[inline]
fn pack<I: Iterator<Item = u8>>(iter: I) -> Self {
let mut ret: Self = 0;
for (n, elem) in iter.enumerate() {
debug_assert!(elem < 32);
debug_assert!(n < Self::WIDTH);
ret <<= 5;
ret |= Self::from(elem);
}
ret
}
}
};
}
Expand Down Expand Up @@ -276,3 +308,23 @@ impl<'hrp> Iterator for HrpFe32Iter<'hrp> {
(min, max)
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn pack_unpack() {
let packed = u128::pack([0, 0, 0, 1].iter().copied());
assert_eq!(packed, 1);
assert_eq!(packed.unpack(0), 1);
assert_eq!(packed.unpack(3), 0);

let packed = u128::pack([1, 2, 3, 4].iter().copied());
assert_eq!(packed, 0b00001_00010_00011_00100);
assert_eq!(packed.unpack(0), 4);
assert_eq!(packed.unpack(1), 3);
assert_eq!(packed.unpack(2), 2);
assert_eq!(packed.unpack(3), 1);
}
}

0 comments on commit fa8b70f

Please sign in to comment.