Skip to content

Commit 8f46be0

Browse files
authored
Uint: const fn encoders (#453)
Adds `const fn` encoders which can serialize to big or little endian byte arrays.
1 parent 2f70cb7 commit 8f46be0

File tree

2 files changed

+68
-8
lines changed

2 files changed

+68
-8
lines changed

src/uint/encoding.rs

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ mod der;
77
mod rlp;
88

99
use super::Uint;
10-
use crate::{Encoding, Limb, Word};
10+
use crate::{Limb, Word};
11+
12+
#[cfg(feature = "generic-array")]
13+
use crate::Encoding;
1114

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

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

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

164+
/// Encode a [`Uint`] to a big endian byte array of the given size.
165+
pub(crate) const fn uint_to_be_bytes<const LIMBS: usize, const BYTES: usize>(
166+
uint: &Uint<LIMBS>,
167+
) -> [u8; BYTES] {
168+
if BYTES != LIMBS * Limb::BYTES {
169+
panic!("BYTES != LIMBS * Limb::BYTES");
170+
}
171+
172+
let mut ret = [0u8; BYTES];
173+
let mut i = 0;
174+
175+
while i < LIMBS {
176+
let limb_bytes = uint.limbs[LIMBS - i - 1].0.to_be_bytes();
177+
let mut j = 0;
178+
179+
while j < Limb::BYTES {
180+
ret[i * Limb::BYTES + j] = limb_bytes[j];
181+
j += 1;
182+
}
183+
184+
i += 1;
185+
}
186+
187+
ret
188+
}
189+
190+
/// Encode a [`Uint`] to a little endian byte array of the given size.
191+
pub(crate) const fn uint_to_le_bytes<const LIMBS: usize, const BYTES: usize>(
192+
uint: &Uint<LIMBS>,
193+
) -> [u8; BYTES] {
194+
if BYTES != LIMBS * Limb::BYTES {
195+
panic!("BYTES != LIMBS * Limb::BYTES");
196+
}
197+
198+
let mut ret = [0u8; BYTES];
199+
let mut i = 0;
200+
201+
while i < LIMBS {
202+
let limb_bytes = uint.limbs[i].0.to_le_bytes();
203+
let mut j = 0;
204+
205+
while j < Limb::BYTES {
206+
ret[i * Limb::BYTES + j] = limb_bytes[j];
207+
j += 1;
208+
}
209+
210+
i += 1;
211+
}
212+
213+
ret
214+
}
215+
159216
/// Decode a single nibble of upper or lower hex
160217
#[inline(always)]
161218
const fn decode_nibble(src: u8) -> u16 {

src/uint/macros.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,14 @@ macro_rules! impl_uint_aliases {
3434
$(
3535
#[doc = $doc]
3636
#[doc="unsigned big integer."]
37-
pub type $name = Uint<{nlimbs!($bits)}>;
37+
pub type $name = Uint<{ nlimbs!($bits) }>;
38+
39+
impl $name {
40+
/// Serialize as big endian bytes.
41+
pub const fn to_be_bytes(&self) -> [u8; $bits / 8] {
42+
encoding::uint_to_be_bytes::<{ nlimbs!($bits) }, { $bits / 8 }>(self)
43+
}
44+
}
3845

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

5259
#[inline]
5360
fn to_be_bytes(&self) -> Self::Repr {
54-
let mut result = [0u8; $bits / 8];
55-
self.write_be_bytes(&mut result);
56-
result
61+
encoding::uint_to_be_bytes(self)
5762
}
5863

5964
#[inline]
6065
fn to_le_bytes(&self) -> Self::Repr {
61-
let mut result = [0u8; $bits / 8];
62-
self.write_le_bytes(&mut result);
63-
result
66+
encoding::uint_to_le_bytes(self)
6467
}
6568
}
6669

0 commit comments

Comments
 (0)