crypto_bigint/uint/boxed/
encoding.rs1use super::BoxedUint;
4use crate::{uint::encoding, DecodeError, Limb, Word};
5use alloc::{boxed::Box, string::String, vec::Vec};
6use subtle::{Choice, CtOption};
7
8impl BoxedUint {
9 pub fn from_be_slice(bytes: &[u8], bits_precision: u32) -> Result<Self, DecodeError> {
21 if bytes.is_empty() && bits_precision == 0 {
22 return Ok(Self::zero());
23 }
24
25 if bytes.len() > (bits_precision as usize + 7) / 8 {
26 return Err(DecodeError::InputSize);
27 }
28
29 let mut ret = Self::zero_with_precision(bits_precision);
30
31 for (chunk, limb) in bytes.rchunks(Limb::BYTES).zip(ret.limbs.iter_mut()) {
32 *limb = Limb::from_be_slice(chunk);
33 }
34
35 if bits_precision < ret.bits() {
36 return Err(DecodeError::Precision);
37 }
38
39 Ok(ret)
40 }
41
42 pub fn from_le_slice(bytes: &[u8], bits_precision: u32) -> Result<Self, DecodeError> {
54 if bytes.is_empty() && bits_precision == 0 {
55 return Ok(Self::zero());
56 }
57
58 if bytes.len() > (bits_precision as usize + 7) / 8 {
59 return Err(DecodeError::InputSize);
60 }
61
62 let mut ret = Self::zero_with_precision(bits_precision);
63
64 for (chunk, limb) in bytes.chunks(Limb::BYTES).zip(ret.limbs.iter_mut()) {
65 *limb = Limb::from_le_slice(chunk);
66 }
67
68 if bits_precision < ret.bits() {
69 return Err(DecodeError::Precision);
70 }
71
72 Ok(ret)
73 }
74
75 #[inline]
77 pub fn to_be_bytes(&self) -> Box<[u8]> {
78 let mut out = vec![0u8; self.limbs.len() * Limb::BYTES];
79
80 for (src, dst) in self
81 .limbs
82 .iter()
83 .rev()
84 .cloned()
85 .zip(out.chunks_exact_mut(Limb::BYTES))
86 {
87 dst.copy_from_slice(&src.0.to_be_bytes());
88 }
89
90 out.into()
91 }
92
93 #[inline]
95 pub fn to_le_bytes(&self) -> Box<[u8]> {
96 let mut out = vec![0u8; self.limbs.len() * Limb::BYTES];
97
98 for (src, dst) in self
99 .limbs
100 .iter()
101 .cloned()
102 .zip(out.chunks_exact_mut(Limb::BYTES))
103 {
104 dst.copy_from_slice(&src.0.to_le_bytes());
105 }
106
107 out.into()
108 }
109
110 pub fn from_be_hex(hex: &str, bits_precision: u32) -> CtOption<Self> {
112 let nlimbs = (bits_precision / Limb::BITS) as usize;
113 let bytes = hex.as_bytes();
114
115 assert!(
116 bytes.len() == Limb::BYTES * nlimbs * 2,
117 "hex string is not the expected size"
118 );
119 let mut res = vec![Limb::ZERO; nlimbs];
120 let mut buf = [0u8; Limb::BYTES];
121 let mut i = 0;
122 let mut err = 0;
123
124 while i < nlimbs {
125 let mut j = 0;
126 while j < Limb::BYTES {
127 let offset = (i * Limb::BYTES + j) * 2;
128 let (result, byte_err) =
129 encoding::decode_hex_byte([bytes[offset], bytes[offset + 1]]);
130 err |= byte_err;
131 buf[j] = result;
132 j += 1;
133 }
134 res[nlimbs - i - 1] = Limb(Word::from_be_bytes(buf));
135 i += 1;
136 }
137 CtOption::new(Self { limbs: res.into() }, Choice::from((err == 0) as u8))
138 }
139
140 pub fn from_str_radix_vartime(src: &str, radix: u32) -> Result<Self, DecodeError> {
149 let mut dec = VecDecodeByLimb::default();
150 encoding::radix_decode_str(src, radix, &mut dec)?;
151 Ok(Self {
152 limbs: dec.limbs.into(),
153 })
154 }
155
156 pub fn from_str_radix_with_precision_vartime(
175 src: &str,
176 radix: u32,
177 bits_precision: u32,
178 ) -> Result<Self, DecodeError> {
179 let mut ret = Self::zero_with_precision(bits_precision);
180 encoding::radix_decode_str(
181 src,
182 radix,
183 &mut encoding::SliceDecodeByLimb::new(&mut ret.limbs),
184 )?;
185 if bits_precision < ret.bits() {
186 return Err(DecodeError::Precision);
187 }
188 Ok(ret)
189 }
190
191 pub fn to_string_radix_vartime(&self, radix: u32) -> String {
195 encoding::radix_encode_limbs_to_string(radix, &self.limbs)
196 }
197}
198
199#[derive(Default)]
201struct VecDecodeByLimb {
202 limbs: Vec<Limb>,
203}
204
205impl encoding::DecodeByLimb for VecDecodeByLimb {
206 #[inline]
207 fn limbs_mut(&mut self) -> &mut [Limb] {
208 self.limbs.as_mut_slice()
209 }
210
211 #[inline]
212 fn push_limb(&mut self, limb: Limb) -> bool {
213 self.limbs.push(limb);
214 true
215 }
216}
217
218#[cfg(test)]
219mod tests {
220 use super::{BoxedUint, DecodeError};
221 use crate::Limb;
222 use hex_literal::hex;
223
224 #[test]
225 #[cfg(target_pointer_width = "32")]
226 fn from_be_slice_eq() {
227 let bytes = hex!("0011223344556677");
228 let n = BoxedUint::from_be_slice(&bytes, 64).unwrap();
229 assert_eq!(n.as_limbs(), &[Limb(0x44556677), Limb(0x00112233)]);
230 }
231
232 #[test]
233 #[cfg(target_pointer_width = "64")]
234 fn from_be_slice_eq() {
235 let bytes = hex!("00112233445566778899aabbccddeeff");
236 let n = BoxedUint::from_be_slice(&bytes, 128).unwrap();
237 assert_eq!(
238 n.as_limbs(),
239 &[Limb(0x8899aabbccddeeff), Limb(0x0011223344556677)]
240 );
241 }
242
243 #[test]
244 #[cfg(target_pointer_width = "64")]
245 fn from_be_hex_eq() {
246 let hex = "00112233445566778899aabbccddeeff";
247 let n = BoxedUint::from_be_hex(hex, 128).unwrap();
248 assert_eq!(
249 n.as_limbs(),
250 &[Limb(0x8899aabbccddeeff), Limb(0x0011223344556677)]
251 );
252 }
253
254 #[test]
255 #[cfg(target_pointer_width = "32")]
256 fn from_be_slice_short() {
257 let bytes = hex!("0011223344556677");
258 let n = BoxedUint::from_be_slice(&bytes, 128).unwrap();
259 assert_eq!(
260 n.as_limbs(),
261 &[Limb(0x44556677), Limb(0x00112233), Limb::ZERO, Limb::ZERO]
262 );
263 }
264
265 #[test]
266 #[cfg(target_pointer_width = "64")]
267 fn from_be_slice_short() {
268 let bytes = hex!("00112233445566778899aabbccddeeff");
269 let n = BoxedUint::from_be_slice(&bytes, 256).unwrap();
270 assert_eq!(
271 n.as_limbs(),
272 &[
273 Limb(0x8899aabbccddeeff),
274 Limb(0x0011223344556677),
275 Limb::ZERO,
276 Limb::ZERO
277 ]
278 );
279 }
280
281 #[test]
282 fn from_be_slice_too_long() {
283 let bytes = hex!("00112233445566778899aabbccddeeff");
284 assert_eq!(
285 BoxedUint::from_be_slice(&bytes, 64),
286 Err(DecodeError::InputSize)
287 );
288 }
289
290 #[test]
291 #[cfg(target_pointer_width = "32")]
292 fn from_be_slice_not_word_sized() {
293 let bytes = hex!("112233445566778899aabbccddeeff");
294 let n = BoxedUint::from_be_slice(&bytes, 127).unwrap();
295 assert_eq!(
296 n.as_limbs(),
297 &[
298 Limb(0xccddeeff),
299 Limb(0x8899aabb),
300 Limb(0x44556677),
301 Limb(0x00112233)
302 ]
303 );
304 assert_eq!(n.bits_precision(), 128);
305 }
306
307 #[test]
308 #[cfg(target_pointer_width = "64")]
309 fn from_be_slice_not_word_sized() {
310 let bytes = hex!("112233445566778899aabbccddeeff");
311 let n = BoxedUint::from_be_slice(&bytes, 127).unwrap();
312 assert_eq!(
313 n.as_limbs(),
314 &[Limb(0x8899aabbccddeeff), Limb(0x0011223344556677)]
315 );
316 assert_eq!(n.bits_precision(), 128);
317 }
318
319 #[test]
320 fn from_be_slice_non_multiple_precision() {
321 let bytes = hex!("0f112233445566778899aabbccddeeff");
322 assert_eq!(
323 BoxedUint::from_be_slice(&bytes, 121),
324 Err(DecodeError::Precision)
325 );
326 }
327
328 #[test]
329 #[cfg(target_pointer_width = "32")]
330 fn from_le_slice_eq() {
331 let bytes = hex!("7766554433221100");
332 let n = BoxedUint::from_le_slice(&bytes, 64).unwrap();
333 assert_eq!(n.as_limbs(), &[Limb(0x44556677), Limb(0x00112233)]);
334 }
335
336 #[test]
337 #[cfg(target_pointer_width = "64")]
338 fn from_le_slice_eq() {
339 let bytes = hex!("ffeeddccbbaa99887766554433221100");
340 let n = BoxedUint::from_le_slice(&bytes, 128).unwrap();
341 assert_eq!(
342 n.as_limbs(),
343 &[Limb(0x8899aabbccddeeff), Limb(0x0011223344556677)]
344 );
345 }
346
347 #[test]
348 #[cfg(target_pointer_width = "32")]
349 fn from_le_slice_short() {
350 let bytes = hex!("7766554433221100");
351 let n = BoxedUint::from_le_slice(&bytes, 128).unwrap();
352 assert_eq!(
353 n.as_limbs(),
354 &[Limb(0x44556677), Limb(0x00112233), Limb::ZERO, Limb::ZERO]
355 );
356 }
357
358 #[test]
359 #[cfg(target_pointer_width = "64")]
360 fn from_le_slice_short() {
361 let bytes = hex!("ffeeddccbbaa99887766554433221100");
362 let n = BoxedUint::from_le_slice(&bytes, 256).unwrap();
363 assert_eq!(
364 n.as_limbs(),
365 &[
366 Limb(0x8899aabbccddeeff),
367 Limb(0x0011223344556677),
368 Limb::ZERO,
369 Limb::ZERO
370 ]
371 );
372 }
373
374 #[test]
375 fn from_le_slice_too_long() {
376 let bytes = hex!("ffeeddccbbaa99887766554433221100");
377 assert_eq!(
378 BoxedUint::from_be_slice(&bytes, 64),
379 Err(DecodeError::InputSize)
380 );
381 }
382
383 #[test]
384 #[cfg(target_pointer_width = "32")]
385 fn from_le_slice_not_word_sized() {
386 let bytes = hex!("ffeeddccbbaa998877665544332211");
387 let n = BoxedUint::from_le_slice(&bytes, 127).unwrap();
388 assert_eq!(
389 n.as_limbs(),
390 &[
391 Limb(0xccddeeff),
392 Limb(0x8899aabb),
393 Limb(0x44556677),
394 Limb(0x00112233)
395 ]
396 );
397 assert_eq!(n.bits_precision(), 128);
398 }
399
400 #[test]
401 #[cfg(target_pointer_width = "64")]
402 fn from_le_slice_not_word_sized() {
403 let bytes = hex!("ffeeddccbbaa998877665544332211");
404 let n = BoxedUint::from_le_slice(&bytes, 127).unwrap();
405 assert_eq!(
406 n.as_limbs(),
407 &[Limb(0x8899aabbccddeeff), Limb(0x0011223344556677)]
408 );
409 assert_eq!(n.bits_precision(), 128);
410 }
411
412 #[test]
413 fn from_le_slice_non_multiple_precision() {
414 let bytes = hex!("ffeeddccbbaa998877665544332211f0");
415 assert_eq!(
416 BoxedUint::from_le_slice(&bytes, 121),
417 Err(DecodeError::Precision)
418 );
419 }
420
421 #[test]
422 fn to_be_bytes() {
423 let bytes = hex!("00112233445566778899aabbccddeeff");
424 let n = BoxedUint::from_be_slice(&bytes, 128).unwrap();
425 assert_eq!(bytes.as_slice(), &*n.to_be_bytes());
426 }
427
428 #[test]
429 fn to_le_bytes() {
430 let bytes = hex!("ffeeddccbbaa99887766554433221100");
431 let n = BoxedUint::from_be_slice(&bytes, 128).unwrap();
432 assert_eq!(bytes.as_slice(), &*n.to_be_bytes());
433 }
434
435 #[test]
436 fn from_str_radix_invalid() {
437 assert_eq!(
438 BoxedUint::from_str_radix_vartime("?", 10,),
439 Err(DecodeError::InvalidDigit)
440 );
441 assert_eq!(
442 BoxedUint::from_str_radix_with_precision_vartime(
443 "ffffffffffffffff_ffffffffffffffff_f",
444 16,
445 128
446 ),
447 Err(DecodeError::InputSize)
448 );
449 assert_eq!(
450 BoxedUint::from_str_radix_with_precision_vartime("1111111111111111", 2, 10),
451 Err(DecodeError::Precision)
452 );
453 }
454
455 #[test]
456 fn from_str_radix_10() {
457 let dec = "+340_282_366_920_938_463_463_374_607_431_768_211_455";
458 let res = BoxedUint::from_str_radix_vartime(dec, 10).expect("error decoding");
459 assert_eq!(res, BoxedUint::max(128));
460 }
461
462 #[test]
463 fn from_str_radix_16() {
464 let hex = "fedcba9876543210fedcba9876543210";
465 let res = BoxedUint::from_str_radix_vartime(hex, 16).expect("error decoding");
466 assert_eq!(hex, format!("{res:x}"));
467 }
468
469 #[test]
470 #[cfg(feature = "rand_core")]
471 fn encode_radix_round_trip() {
472 use crate::RandomBits;
473 use rand_core::SeedableRng;
474 let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(1);
475
476 for _ in 0..100 {
477 let uint = BoxedUint::random_bits(&mut rng, 4096);
478 for radix in 2..=36 {
479 let enc = uint.to_string_radix_vartime(radix);
480 let res = BoxedUint::from_str_radix_vartime(&enc, radix).expect("decoding error");
481 assert_eq!(
482 res, uint,
483 "round trip failure: radix {radix} encoded {uint} as {enc}"
484 );
485 }
486 }
487 }
488}