1use super::BoxedUint;
4use crate::{CtEq, CtOption, DecodeError, Encoding, Limb, Word, bitlen, uint::encoding};
5use alloc::{boxed::Box, string::String, vec::Vec};
6
7#[cfg(feature = "serde")]
8mod serde;
9
10impl BoxedUint {
11 pub fn from_be_slice(bytes: &[u8], bits_precision: u32) -> Result<Self, DecodeError> {
25 if bytes.len() > bitlen::to_bytes(bits_precision) {
26 return Err(DecodeError::InputSize);
27 }
28
29 Ok(Self::from_be_slice_truncated(bytes, bits_precision))
30 }
31
32 #[must_use]
36 #[allow(clippy::missing_panics_doc, reason = "should not panic in practice")]
37 pub fn from_be_slice_truncated(bytes: &[u8], bits_precision: u32) -> Self {
38 let mut ret = Self::zero_with_precision(bits_precision);
39 encoding::fill_limbs_from_be_slice_truncated(bytes, &mut ret.limbs, bits_precision)
40 .expect("should fit in requested precision");
41 ret
42 }
43
44 #[must_use]
52 pub fn from_be_slice_vartime(bytes: &[u8]) -> Self {
53 Self::from_be_slice_truncated(bytes, bitlen::from_bytes(bytes.len()))
54 }
55
56 pub fn from_le_slice(bytes: &[u8], bits_precision: u32) -> Result<Self, DecodeError> {
70 if bytes.len() > bitlen::to_bytes(bits_precision) {
71 return Err(DecodeError::InputSize);
72 }
73
74 Ok(Self::from_le_slice_truncated(bytes, bits_precision))
75 }
76
77 #[must_use]
81 #[allow(clippy::missing_panics_doc, reason = "should not panic in practice")]
82 pub fn from_le_slice_truncated(bytes: &[u8], bits_precision: u32) -> Self {
83 let mut ret = Self::zero_with_precision(bits_precision);
84 encoding::fill_limbs_from_le_slice_truncated(bytes, &mut ret.limbs, bits_precision)
85 .expect("should fit in requested precision");
86 ret
87 }
88
89 #[must_use]
97 pub fn from_le_slice_vartime(bytes: &[u8]) -> Self {
98 Self::from_le_slice_truncated(bytes, bitlen::from_bytes(bytes.len()))
99 }
100
101 #[inline]
103 #[must_use]
104 pub fn to_be_bytes(&self) -> Box<[u8]> {
105 let mut out = vec![0u8; self.limbs.len() * Limb::BYTES];
106
107 for (src, dst) in self
108 .limbs
109 .iter()
110 .rev()
111 .cloned()
112 .zip(out.chunks_exact_mut(Limb::BYTES))
113 {
114 dst.copy_from_slice(&src.0.to_be_bytes());
115 }
116
117 out.into()
118 }
119
120 #[inline]
122 #[must_use]
123 #[allow(clippy::integer_division_remainder_used, reason = "vartime")]
124 pub fn to_be_bytes_trimmed_vartime(&self) -> Box<[u8]> {
125 let zeroes = self.leading_zeros() as usize / 8;
126 (&self.to_be_bytes()[zeroes..]).into()
127 }
128
129 #[inline]
131 #[must_use]
132 pub fn to_le_bytes(&self) -> Box<[u8]> {
133 let mut out = vec![0u8; self.limbs.len() * Limb::BYTES];
134
135 for (src, dst) in self
136 .limbs
137 .iter()
138 .cloned()
139 .zip(out.chunks_exact_mut(Limb::BYTES))
140 {
141 dst.copy_from_slice(&src.0.to_le_bytes());
142 }
143
144 out.into()
145 }
146
147 #[inline]
149 #[must_use]
150 #[allow(clippy::integer_division_remainder_used, reason = "vartime")]
151 pub fn to_le_bytes_trimmed_vartime(&self) -> Box<[u8]> {
152 let zeroes = self.leading_zeros() as usize / 8;
153 let bytes = self.to_le_bytes();
154 (&bytes[..bytes.len() - zeroes]).into()
155 }
156
157 #[must_use]
162 pub fn from_be_hex(hex: &str, bits_precision: u32) -> CtOption<Self> {
163 let nlimbs = bitlen::to_limbs(bits_precision);
164 let bytes = hex.as_bytes();
165
166 assert_eq!(
167 bytes.len(),
168 Limb::BYTES * nlimbs * 2,
169 "hex string is not the expected size"
170 );
171
172 let mut res = vec![Limb::ZERO; nlimbs];
173 let mut buf = [0u8; Limb::BYTES];
174 let mut i = 0;
175 let mut err = 0;
176
177 while i < nlimbs {
178 let mut j = 0;
179 while j < Limb::BYTES {
180 let offset = (i * Limb::BYTES + j) * 2;
181 let (result, byte_err) =
182 encoding::decode_hex_byte([bytes[offset], bytes[offset + 1]]);
183 err |= byte_err;
184 buf[j] = result;
185 j += 1;
186 }
187 res[nlimbs - i - 1] = Limb(Word::from_be_bytes(buf));
188 i += 1;
189 }
190
191 CtOption::new(Self { limbs: res.into() }, err.ct_eq(&0))
192 }
193
194 pub fn from_str_radix_vartime(src: &str, radix: u32) -> Result<Self, DecodeError> {
206 let mut dec = VecDecodeByLimb::default();
207 encoding::radix_decode_str(src, radix, &mut dec)?;
208 Ok(Self {
209 limbs: dec.limbs.into(),
210 })
211 }
212
213 pub fn from_str_radix_with_precision_vartime(
236 src: &str,
237 radix: u32,
238 bits_precision: u32,
239 ) -> Result<Self, DecodeError> {
240 let mut ret = Self::zero_with_precision(bits_precision);
241 encoding::radix_decode_str(
242 src,
243 radix,
244 &mut encoding::SliceDecodeByLimb::new(&mut ret.limbs),
245 )?;
246 if bits_precision < ret.bits() {
247 return Err(DecodeError::Precision);
248 }
249 Ok(ret)
250 }
251
252 #[must_use]
257 pub fn to_string_radix_vartime(&self, radix: u32) -> String {
258 encoding::radix_encode_limbs_to_string(radix, &self.limbs)
259 }
260}
261
262impl Encoding for BoxedUint {
263 type Repr = Box<[u8]>;
264
265 fn from_be_bytes(bytes: Self::Repr) -> Self {
266 Self::from_be_slice_vartime(&bytes)
267 }
268
269 fn from_le_bytes(bytes: Self::Repr) -> Self {
270 Self::from_le_slice_vartime(&bytes)
271 }
272
273 fn from_be_slice_truncated(bytes: &[u8], bits_precision: u32) -> Self {
274 Self::from_be_slice_truncated(bytes, bits_precision)
275 }
276
277 fn from_le_slice_truncated(bytes: &[u8], bits_precision: u32) -> Self {
278 Self::from_le_slice_truncated(bytes, bits_precision)
279 }
280
281 fn to_be_bytes(&self) -> Self::Repr {
282 Self::to_be_bytes(self)
283 }
284
285 fn to_le_bytes(&self) -> Self::Repr {
286 Self::to_le_bytes(self)
287 }
288}
289
290#[derive(Default)]
292struct VecDecodeByLimb {
293 limbs: Vec<Limb>,
294}
295
296impl encoding::DecodeByLimb for VecDecodeByLimb {
297 #[inline]
298 fn limbs_mut(&mut self) -> &mut [Limb] {
299 self.limbs.as_mut_slice()
300 }
301
302 #[inline]
303 fn push_limb(&mut self, limb: Limb) -> bool {
304 self.limbs.push(limb);
305 true
306 }
307}
308
309#[cfg(test)]
310mod tests {
311 use super::{BoxedUint, DecodeError};
312 use crate::Limb;
313 use hex_literal::hex;
314
315 cpubits::cpubits! {
316 32 => {
317 #[test]
318 fn from_be_slice_eq() {
319 let bytes = hex!("0011223344556677");
320 let n = BoxedUint::from_be_slice(&bytes, 64).unwrap();
321 assert_eq!(n.as_limbs(), &[Limb(0x44556677), Limb(0x00112233)]);
322 }
323
324 #[test]
325 fn from_be_slice_short() {
326 let bytes = hex!("0011223344556677");
327 let n = BoxedUint::from_be_slice(&bytes, 128).unwrap();
328 assert_eq!(
329 n.as_limbs(),
330 &[Limb(0x44556677), Limb(0x00112233), Limb::ZERO, Limb::ZERO]
331 );
332 }
333
334 #[test]
335 fn from_be_slice_not_word_sized() {
336 let bytes = hex!("112233445566778899aabbccddeeff");
337 let n = BoxedUint::from_be_slice(&bytes, 127).unwrap();
338 assert_eq!(
339 n.as_limbs(),
340 &[
341 Limb(0xccddeeff),
342 Limb(0x8899aabb),
343 Limb(0x44556677),
344 Limb(0x00112233)
345 ]
346 );
347 assert_eq!(n.bits_precision(), 128);
348 }
349
350 #[test]
351 fn from_le_slice_eq() {
352 let bytes = hex!("7766554433221100");
353 let n = BoxedUint::from_le_slice(&bytes, 64).unwrap();
354 assert_eq!(n.as_limbs(), &[Limb(0x44556677), Limb(0x00112233)]);
355 }
356
357 #[test]
358 fn from_le_slice_short() {
359 let bytes = hex!("7766554433221100");
360 let n = BoxedUint::from_le_slice(&bytes, 128).unwrap();
361 assert_eq!(
362 n.as_limbs(),
363 &[Limb(0x44556677), Limb(0x00112233), Limb::ZERO, Limb::ZERO]
364 );
365 }
366
367 #[test]
368 fn from_le_slice_not_word_sized() {
369 let bytes = hex!("ffeeddccbbaa998877665544332211");
370 let n = BoxedUint::from_le_slice(&bytes, 127).unwrap();
371 assert_eq!(
372 n.as_limbs(),
373 &[
374 Limb(0xccddeeff),
375 Limb(0x8899aabb),
376 Limb(0x44556677),
377 Limb(0x00112233)
378 ]
379 );
380 assert_eq!(n.bits_precision(), 128);
381 }
382 }
383 64 => {
384 #[test]
385 #[should_panic]
386 fn from_be_hex_short() {
387 let hex = "00112233445566778899aabbccddee";
388 let _ = BoxedUint::from_be_hex(hex, 128).unwrap();
389 }
390
391 #[test]
392 fn from_be_slice_eq() {
393 let bytes = hex!("00112233445566778899aabbccddeeff");
394 let n = BoxedUint::from_be_slice(&bytes, 128).unwrap();
395 assert_eq!(
396 n.as_limbs(),
397 &[Limb(0x8899aabbccddeeff), Limb(0x0011223344556677)]
398 );
399 }
400
401 #[test]
402 fn from_be_slice_short() {
403 let bytes = hex!("00112233445566778899aabbccddeeff");
404 let n = BoxedUint::from_be_slice(&bytes, 256).unwrap();
405 assert_eq!(
406 n.as_limbs(),
407 &[
408 Limb(0x8899aabbccddeeff),
409 Limb(0x0011223344556677),
410 Limb::ZERO,
411 Limb::ZERO
412 ]
413 );
414 }
415
416 #[test]
417 fn from_be_slice_not_word_sized() {
418 let bytes = hex!("112233445566778899aabbccddeeff");
419 let n = BoxedUint::from_be_slice(&bytes, 127).unwrap();
420 assert_eq!(
421 n.as_limbs(),
422 &[Limb(0x8899aabbccddeeff), Limb(0x0011223344556677)]
423 );
424 assert_eq!(n.bits_precision(), 128);
425 }
426
427 #[test]
428 fn from_le_slice_eq() {
429 let bytes = hex!("ffeeddccbbaa99887766554433221100");
430 let n = BoxedUint::from_le_slice(&bytes, 128).unwrap();
431 assert_eq!(
432 n.as_limbs(),
433 &[Limb(0x8899aabbccddeeff), Limb(0x0011223344556677)]
434 );
435 }
436
437 #[test]
438 fn from_le_slice_short() {
439 let bytes = hex!("ffeeddccbbaa99887766554433221100");
440 let n = BoxedUint::from_le_slice(&bytes, 256).unwrap();
441 assert_eq!(
442 n.as_limbs(),
443 &[
444 Limb(0x8899aabbccddeeff),
445 Limb(0x0011223344556677),
446 Limb::ZERO,
447 Limb::ZERO
448 ]
449 );
450 }
451
452 #[test]
453 fn from_le_slice_not_word_sized() {
454 let bytes = hex!("ffeeddccbbaa998877665544332211");
455 let n = BoxedUint::from_le_slice(&bytes, 127).unwrap();
456 assert_eq!(
457 n.as_limbs(),
458 &[Limb(0x8899aabbccddeeff), Limb(0x0011223344556677)]
459 );
460 assert_eq!(n.bits_precision(), 128);
461 }
462 }
463 }
464
465 #[test]
466 fn from_be_slice_too_long() {
467 let bytes = hex!("00112233445566778899aabbccddeeff");
468 assert_eq!(
469 BoxedUint::from_be_slice(&bytes, 64),
470 Err(DecodeError::InputSize)
471 );
472 }
473
474 #[test]
475 fn from_be_slice_non_multiple_precision() {
476 let bytes = hex!("0f112233445566778899aabbccddeeff");
477 let n = BoxedUint::from_be_slice(&bytes, 121).unwrap();
478 assert_eq!(n.bits(), 121);
479 }
480
481 #[test]
482 fn from_be_slice_rejects_value_exceeding_precision() {
483 assert_eq!(
484 BoxedUint::from_be_slice(&[0x01, 0x00], 8),
485 Err(DecodeError::InputSize)
486 );
487 }
488
489 #[test]
490 fn from_be_slice_truncated_exact_fit() {
491 let bytes = [0u8; 32];
492 let n = BoxedUint::from_be_slice_truncated(&bytes, 256);
493 assert_eq!(&*n.to_be_bytes(), &bytes);
494 }
495
496 #[test]
497 fn from_be_slice_truncated_truncates_to_lsb() {
498 let n = BoxedUint::from_be_slice_truncated(&[0xDE, 0xAD, 0xBE, 0xEF], 16);
499 let out = n.to_be_bytes();
500 assert_eq!(&out[(out.len() - 2)..], &[0xBE, 0xEF]);
501 }
502
503 #[test]
504 fn from_be_slice_truncated_zero_pads_short_input() {
505 let n = BoxedUint::from_be_slice_truncated(&[0x42], 32);
506 assert_eq!(n.to_be_bytes().last(), Some(&0x42));
507 assert!(n.to_be_bytes().iter().rev().skip(1).all(|&b| b == 0));
508 }
509
510 #[test]
511 fn from_be_slice_truncated_top_byte_masked() {
512 let n = BoxedUint::from_be_slice_truncated(&[0xFF, 0xFF], 12);
513 assert!(n.bits() <= 12);
514 }
515
516 #[test]
517 fn from_le_slice_truncated_exact_fit() {
518 let bytes = [0u8; 32];
519 let n = BoxedUint::from_le_slice_truncated(&bytes, 256);
520 assert_eq!(&*n.to_le_bytes(), &bytes);
521 }
522
523 #[test]
524 fn from_le_slice_truncated_truncates_to_lsb() {
525 let n = BoxedUint::from_le_slice_truncated(&[0xEF, 0xBE, 0xAD, 0xDE], 16);
526 assert_eq!(&n.to_le_bytes()[..2], &[0xEF, 0xBE]);
527 }
528
529 #[test]
530 fn from_le_slice_truncated_top_byte_masked() {
531 let n = BoxedUint::from_le_slice_truncated(&[0xFF, 0xFF], 12);
532 assert!(n.bits() <= 12,);
533 }
534
535 #[test]
536 fn from_be_slice_vartime() {
537 let bytes = hex!(
538 "111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111F"
539 );
540 let uint = BoxedUint::from_be_slice_vartime(&bytes);
541 assert_eq!(&*uint.to_be_bytes_trimmed_vartime(), bytes.as_slice());
542 }
543
544 #[test]
545 fn from_le_slice_too_long() {
546 let bytes = hex!("ffeeddccbbaa99887766554433221100");
547 assert_eq!(
548 BoxedUint::from_be_slice(&bytes, 64),
549 Err(DecodeError::InputSize)
550 );
551 }
552
553 #[test]
554 fn from_le_slice_non_multiple_precision() {
555 let bytes = hex!("ffeeddccbbaa998877665544332211ff");
556 let n = BoxedUint::from_le_slice(&bytes, 121).unwrap();
557 assert_eq!(n.bits(), 121);
558 }
559
560 #[test]
561 fn from_le_slice_vartime() {
562 let bytes = hex!(
563 "111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111F"
564 );
565 let uint = BoxedUint::from_le_slice_vartime(&bytes);
566 assert_eq!(&*uint.to_le_bytes_trimmed_vartime(), bytes.as_slice());
567 }
568
569 #[test]
570 fn to_be_bytes() {
571 let bytes = hex!("00112233445566778899aabbccddeeff");
572 let n = BoxedUint::from_be_slice(&bytes, 128).unwrap();
573 assert_eq!(bytes.as_slice(), &*n.to_be_bytes());
574 }
575
576 #[test]
577 fn to_be_bytes_trimmed_vartime() {
578 let bytes = hex!("ff112233445566778899aabbccddeeff");
579 let n = BoxedUint::from_be_slice(&bytes, 128).unwrap();
580 assert_eq!(&bytes, &*n.to_be_bytes_trimmed_vartime());
581
582 let bytes = hex!("00112233445566778899aabbccddeeff");
583 let n = BoxedUint::from_be_slice(&bytes, 128).unwrap();
584 assert_eq!(&bytes.as_slice()[1..], &*n.to_be_bytes_trimmed_vartime());
585
586 let bytes: &[u8] = b"";
587 let n = BoxedUint::from_be_slice(bytes, 128).unwrap();
588 assert_eq!(
589 hex!("00000000000000000000000000000000"),
590 n.to_be_bytes().as_ref()
591 );
592 assert_eq!(bytes, n.to_be_bytes_trimmed_vartime().as_ref());
593
594 let bytes = hex!("00012233445566778899aabbccddeeff");
595 let n = BoxedUint::from_be_slice(&bytes, 128).unwrap();
596 assert_eq!(&bytes.as_slice()[1..], &*n.to_be_bytes_trimmed_vartime());
597
598 let bytes = hex!("00000000000000000000000000000001");
599 let n = BoxedUint::from_be_slice(&bytes, 128).unwrap();
600 assert_eq!(bytes, n.to_be_bytes().as_ref());
601 assert_eq!(&bytes.as_slice()[15..], &*n.to_be_bytes_trimmed_vartime());
602 }
603
604 #[test]
605 fn to_le_bytes() {
606 let bytes = hex!("ffeeddccbbaa99887766554433221100");
607 let n = BoxedUint::from_le_slice(&bytes, 128).unwrap();
608 assert_eq!(bytes.as_slice(), &*n.to_le_bytes());
609 }
610
611 #[test]
612 fn to_le_bytes_trimmed_vartime() {
613 let bytes = hex!("ffeeddccbbaa998877665544332211ff");
614 let n = BoxedUint::from_le_slice(&bytes, 128).unwrap();
615 assert_eq!(bytes.as_slice(), &*n.to_le_bytes_trimmed_vartime());
616
617 let bytes = hex!("ffeeddccbbaa99887766554433221100");
618 let n = BoxedUint::from_le_slice(&bytes, 128).unwrap();
619 assert_eq!(&bytes.as_slice()[..15], &*n.to_le_bytes_trimmed_vartime());
620
621 let bytes = hex!("ff000000000000000000000000000000");
622 let n = BoxedUint::from_le_slice(&bytes, 128).unwrap();
623 assert_eq!(&bytes.as_slice()[..1], &*n.to_le_bytes_trimmed_vartime());
624
625 let bytes = hex!("01000000000000000000000000000000");
626 let n = BoxedUint::from_le_slice(&bytes, 128).unwrap();
627 assert_eq!(&bytes.as_slice()[..1], &*n.to_le_bytes_trimmed_vartime());
628
629 let bytes = hex!("00000000000000000000000000000000");
630 let n = BoxedUint::from_le_slice(&bytes, 128).unwrap();
631 assert_eq!(b"", &*n.to_le_bytes_trimmed_vartime());
632 }
633
634 #[test]
635 fn from_str_radix_invalid() {
636 assert_eq!(
637 BoxedUint::from_str_radix_vartime("?", 10,),
638 Err(DecodeError::InvalidDigit)
639 );
640 assert_eq!(
641 BoxedUint::from_str_radix_with_precision_vartime(
642 "ffffffffffffffff_ffffffffffffffff_f",
643 16,
644 128
645 ),
646 Err(DecodeError::InputSize)
647 );
648 assert_eq!(
649 BoxedUint::from_str_radix_with_precision_vartime("1111111111111111", 2, 10),
650 Err(DecodeError::Precision)
651 );
652 }
653
654 #[test]
655 fn from_str_radix_10() {
656 let dec = "+340_282_366_920_938_463_463_374_607_431_768_211_455";
657 let res = BoxedUint::from_str_radix_vartime(dec, 10).expect("error decoding");
658 assert_eq!(res, BoxedUint::max(128));
659 }
660
661 #[test]
662 fn from_str_radix_16() {
663 let hex = "fedcba9876543210fedcba9876543210";
664 let res = BoxedUint::from_str_radix_vartime(hex, 16).expect("error decoding");
665 assert_eq!(hex, format!("{res:x}"));
666 }
667
668 #[test]
669 #[cfg(feature = "rand_core")]
670 fn encode_radix_round_trip() {
671 use crate::RandomBits;
672 use rand_core::SeedableRng;
673 let mut rng = chacha20::ChaCha8Rng::seed_from_u64(1);
674
675 let rounds = if cfg!(miri) { 10 } else { 100 };
676 let bits = if cfg!(miri) { 256 } else { 4096 };
677 for _ in 0..rounds {
678 let uint = BoxedUint::random_bits(&mut rng, bits);
679 for radix in 2..=36 {
680 let enc = uint.to_string_radix_vartime(radix);
681 let res = BoxedUint::from_str_radix_vartime(&enc, radix).expect("decoding error");
682 assert_eq!(
683 res, uint,
684 "round trip failure: radix {radix} encoded {uint} as {enc}"
685 );
686 }
687 }
688 }
689}