Skip to content

Commit

Permalink
Uint: const fn encoders (#453)
Browse files Browse the repository at this point in the history
Adds `const fn` encoders which can serialize to big or little endian
byte arrays.
  • Loading branch information
tarcieri authored Dec 17, 2023
1 parent 2f70cb7 commit 8f46be0
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 8 deletions.
59 changes: 58 additions & 1 deletion src/uint/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ mod der;
mod rlp;

use super::Uint;
use crate::{Encoding, Limb, Word};
use crate::{Limb, Word};

#[cfg(feature = "generic-array")]
use crate::Encoding;

impl<const LIMBS: usize> Uint<LIMBS> {
/// Create a new [`Uint`] from the provided big endian bytes.
Expand Down Expand Up @@ -124,6 +127,7 @@ impl<const LIMBS: usize> Uint<LIMBS> {

/// Serialize this [`Uint`] as big-endian, writing it into the provided
/// byte slice.
#[cfg(feature = "generic-array")]
#[inline]
pub(crate) fn write_be_bytes(&self, out: &mut [u8]) {
debug_assert_eq!(out.len(), Limb::BYTES * LIMBS);
Expand All @@ -141,6 +145,7 @@ impl<const LIMBS: usize> Uint<LIMBS> {

/// Serialize this [`Uint`] as little-endian, writing it into the provided
/// byte slice.
#[cfg(feature = "generic-array")]
#[inline]
pub(crate) fn write_le_bytes(&self, out: &mut [u8]) {
debug_assert_eq!(out.len(), Limb::BYTES * LIMBS);
Expand All @@ -156,6 +161,58 @@ impl<const LIMBS: usize> Uint<LIMBS> {
}
}

/// Encode a [`Uint`] to a big endian byte array of the given size.
pub(crate) const fn uint_to_be_bytes<const LIMBS: usize, const BYTES: usize>(
uint: &Uint<LIMBS>,
) -> [u8; BYTES] {
if BYTES != LIMBS * Limb::BYTES {
panic!("BYTES != LIMBS * Limb::BYTES");
}

let mut ret = [0u8; BYTES];
let mut i = 0;

while i < LIMBS {
let limb_bytes = uint.limbs[LIMBS - i - 1].0.to_be_bytes();
let mut j = 0;

while j < Limb::BYTES {
ret[i * Limb::BYTES + j] = limb_bytes[j];
j += 1;
}

i += 1;
}

ret
}

/// Encode a [`Uint`] to a little endian byte array of the given size.
pub(crate) const fn uint_to_le_bytes<const LIMBS: usize, const BYTES: usize>(
uint: &Uint<LIMBS>,
) -> [u8; BYTES] {
if BYTES != LIMBS * Limb::BYTES {
panic!("BYTES != LIMBS * Limb::BYTES");
}

let mut ret = [0u8; BYTES];
let mut i = 0;

while i < LIMBS {
let limb_bytes = uint.limbs[i].0.to_le_bytes();
let mut j = 0;

while j < Limb::BYTES {
ret[i * Limb::BYTES + j] = limb_bytes[j];
j += 1;
}

i += 1;
}

ret
}

/// Decode a single nibble of upper or lower hex
#[inline(always)]
const fn decode_nibble(src: u8) -> u16 {
Expand Down
17 changes: 10 additions & 7 deletions src/uint/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,14 @@ macro_rules! impl_uint_aliases {
$(
#[doc = $doc]
#[doc="unsigned big integer."]
pub type $name = Uint<{nlimbs!($bits)}>;
pub type $name = Uint<{ nlimbs!($bits) }>;

impl $name {
/// Serialize as big endian bytes.
pub const fn to_be_bytes(&self) -> [u8; $bits / 8] {
encoding::uint_to_be_bytes::<{ nlimbs!($bits) }, { $bits / 8 }>(self)
}
}

impl Encoding for $name {
type Repr = [u8; $bits / 8];
Expand All @@ -51,16 +58,12 @@ macro_rules! impl_uint_aliases {

#[inline]
fn to_be_bytes(&self) -> Self::Repr {
let mut result = [0u8; $bits / 8];
self.write_be_bytes(&mut result);
result
encoding::uint_to_be_bytes(self)
}

#[inline]
fn to_le_bytes(&self) -> Self::Repr {
let mut result = [0u8; $bits / 8];
self.write_le_bytes(&mut result);
result
encoding::uint_to_le_bytes(self)
}
}

Expand Down

0 comments on commit 8f46be0

Please sign in to comment.