crypto_bigint/uint/boxed/
encoding.rs1use super::BoxedUint;
4use crate::{CtEq, CtOption, DecodeError, Encoding, Limb, Word, 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.is_empty() && bits_precision == 0 {
26 return Ok(Self::zero());
27 }
28
29 if bytes.len() > (bits_precision as usize).div_ceil(8) {
30 return Err(DecodeError::InputSize);
31 }
32
33 let mut ret = Self::zero_with_precision(bits_precision);
34
35 for (chunk, limb) in bytes.rchunks(Limb::BYTES).zip(ret.limbs.iter_mut()) {
36 *limb = Limb::from_be_slice(chunk);
37 }
38
39 if bits_precision < ret.bits() {
40 return Err(DecodeError::Precision);
41 }
42
43 Ok(ret)
44 }
45
46 #[must_use]
54 #[allow(clippy::cast_possible_truncation, clippy::missing_panics_doc)]
55 pub fn from_be_slice_vartime(bytes: &[u8]) -> Self {
56 let bits_precision = (bytes.len() as u32).saturating_mul(8);
57
58 Self::from_be_slice(bytes, bits_precision).expect("precision should be large enough")
60 }
61
62 pub fn from_le_slice(bytes: &[u8], bits_precision: u32) -> Result<Self, DecodeError> {
76 if bytes.is_empty() && bits_precision == 0 {
77 return Ok(Self::zero());
78 }
79
80 if bytes.len() > (bits_precision as usize).div_ceil(8) {
81 return Err(DecodeError::InputSize);
82 }
83
84 let mut ret = Self::zero_with_precision(bits_precision);
85
86 for (chunk, limb) in bytes.chunks(Limb::BYTES).zip(ret.limbs.iter_mut()) {
87 *limb = Limb::from_le_slice(chunk);
88 }
89
90 if bits_precision < ret.bits() {
91 return Err(DecodeError::Precision);
92 }
93
94 Ok(ret)
95 }
96
97 #[must_use]
105 #[allow(clippy::cast_possible_truncation, clippy::missing_panics_doc)]
106 pub fn from_le_slice_vartime(bytes: &[u8]) -> Self {
107 let bits_precision = (bytes.len() as u32).saturating_mul(8);
108
109 Self::from_le_slice(bytes, bits_precision).expect("precision should be large enough")
111 }
112
113 #[inline]
115 #[must_use]
116 pub fn to_be_bytes(&self) -> Box<[u8]> {
117 let mut out = vec![0u8; self.limbs.len() * Limb::BYTES];
118
119 for (src, dst) in self
120 .limbs
121 .iter()
122 .rev()
123 .cloned()
124 .zip(out.chunks_exact_mut(Limb::BYTES))
125 {
126 dst.copy_from_slice(&src.0.to_be_bytes());
127 }
128
129 out.into()
130 }
131
132 #[inline]
134 #[must_use]
135 #[allow(clippy::integer_division_remainder_used, reason = "vartime")]
136 pub fn to_be_bytes_trimmed_vartime(&self) -> Box<[u8]> {
137 let zeroes = self.leading_zeros() as usize / 8;
138 (&self.to_be_bytes()[zeroes..]).into()
139 }
140
141 #[inline]
143 #[must_use]
144 pub fn to_le_bytes(&self) -> Box<[u8]> {
145 let mut out = vec![0u8; self.limbs.len() * Limb::BYTES];
146
147 for (src, dst) in self
148 .limbs
149 .iter()
150 .cloned()
151 .zip(out.chunks_exact_mut(Limb::BYTES))
152 {
153 dst.copy_from_slice(&src.0.to_le_bytes());
154 }
155
156 out.into()
157 }
158
159 #[inline]
161 #[must_use]
162 #[allow(clippy::integer_division_remainder_used, reason = "vartime")]
163 pub fn to_le_bytes_trimmed_vartime(&self) -> Box<[u8]> {
164 let zeroes = self.leading_zeros() as usize / 8;
165 let bytes = self.to_le_bytes();
166 (&bytes[..bytes.len() - zeroes]).into()
167 }
168
169 #[must_use]
174 #[allow(clippy::integer_division_remainder_used, reason = "public parameter")]
175 pub fn from_be_hex(hex: &str, bits_precision: u32) -> CtOption<Self> {
176 let nlimbs = (bits_precision / Limb::BITS) as usize;
177 let bytes = hex.as_bytes();
178
179 assert_eq!(
180 bytes.len(),
181 Limb::BYTES * nlimbs * 2,
182 "hex string is not the expected size"
183 );
184 let mut res = vec![Limb::ZERO; nlimbs];
185 let mut buf = [0u8; Limb::BYTES];
186 let mut i = 0;
187 let mut err = 0;
188
189 while i < nlimbs {
190 let mut j = 0;
191 while j < Limb::BYTES {
192 let offset = (i * Limb::BYTES + j) * 2;
193 let (result, byte_err) =
194 encoding::decode_hex_byte([bytes[offset], bytes[offset + 1]]);
195 err |= byte_err;
196 buf[j] = result;
197 j += 1;
198 }
199 res[nlimbs - i - 1] = Limb(Word::from_be_bytes(buf));
200 i += 1;
201 }
202
203 CtOption::new(Self { limbs: res.into() }, err.ct_eq(&0))
204 }
205
206 pub fn from_str_radix_vartime(src: &str, radix: u32) -> Result<Self, DecodeError> {
218 let mut dec = VecDecodeByLimb::default();
219 encoding::radix_decode_str(src, radix, &mut dec)?;
220 Ok(Self {
221 limbs: dec.limbs.into(),
222 })
223 }
224
225 pub fn from_str_radix_with_precision_vartime(
248 src: &str,
249 radix: u32,
250 bits_precision: u32,
251 ) -> Result<Self, DecodeError> {
252 let mut ret = Self::zero_with_precision(bits_precision);
253 encoding::radix_decode_str(
254 src,
255 radix,
256 &mut encoding::SliceDecodeByLimb::new(&mut ret.limbs),
257 )?;
258 if bits_precision < ret.bits() {
259 return Err(DecodeError::Precision);
260 }
261 Ok(ret)
262 }
263
264 #[must_use]
269 pub fn to_string_radix_vartime(&self, radix: u32) -> String {
270 encoding::radix_encode_limbs_to_string(radix, &self.limbs)
271 }
272}
273
274impl Encoding for BoxedUint {
275 type Repr = Box<[u8]>;
276
277 fn to_be_bytes(&self) -> Self::Repr {
278 BoxedUint::to_be_bytes(self)
279 }
280
281 fn to_le_bytes(&self) -> Self::Repr {
282 BoxedUint::to_le_bytes(self)
283 }
284
285 fn from_be_bytes(bytes: Self::Repr) -> Self {
286 BoxedUint::from_be_slice(&bytes, (bytes.len() * 8).try_into().expect("overflow"))
287 .expect("decode error")
288 }
289
290 fn from_le_bytes(bytes: Self::Repr) -> Self {
291 BoxedUint::from_le_slice(&bytes, (bytes.len() * 8).try_into().expect("overflow"))
292 .expect("decode error")
293 }
294}
295
296#[derive(Default)]
298struct VecDecodeByLimb {
299 limbs: Vec<Limb>,
300}
301
302impl encoding::DecodeByLimb for VecDecodeByLimb {
303 #[inline]
304 fn limbs_mut(&mut self) -> &mut [Limb] {
305 self.limbs.as_mut_slice()
306 }
307
308 #[inline]
309 fn push_limb(&mut self, limb: Limb) -> bool {
310 self.limbs.push(limb);
311 true
312 }
313}
314
315#[cfg(test)]
316mod tests {
317 use super::{BoxedUint, DecodeError};
318 use crate::Limb;
319 use hex_literal::hex;
320
321 cpubits::cpubits! {
322 32 => {
323 #[test]
324 fn from_be_slice_eq() {
325 let bytes = hex!("0011223344556677");
326 let n = BoxedUint::from_be_slice(&bytes, 64).unwrap();
327 assert_eq!(n.as_limbs(), &[Limb(0x44556677), Limb(0x00112233)]);
328 }
329
330 #[test]
331 fn from_be_slice_short() {
332 let bytes = hex!("0011223344556677");
333 let n = BoxedUint::from_be_slice(&bytes, 128).unwrap();
334 assert_eq!(
335 n.as_limbs(),
336 &[Limb(0x44556677), Limb(0x00112233), Limb::ZERO, Limb::ZERO]
337 );
338 }
339
340 #[test]
341 fn from_be_slice_not_word_sized() {
342 let bytes = hex!("112233445566778899aabbccddeeff");
343 let n = BoxedUint::from_be_slice(&bytes, 127).unwrap();
344 assert_eq!(
345 n.as_limbs(),
346 &[
347 Limb(0xccddeeff),
348 Limb(0x8899aabb),
349 Limb(0x44556677),
350 Limb(0x00112233)
351 ]
352 );
353 assert_eq!(n.bits_precision(), 128);
354 }
355
356 #[test]
357 fn from_le_slice_eq() {
358 let bytes = hex!("7766554433221100");
359 let n = BoxedUint::from_le_slice(&bytes, 64).unwrap();
360 assert_eq!(n.as_limbs(), &[Limb(0x44556677), Limb(0x00112233)]);
361 }
362
363 #[test]
364 fn from_le_slice_short() {
365 let bytes = hex!("7766554433221100");
366 let n = BoxedUint::from_le_slice(&bytes, 128).unwrap();
367 assert_eq!(
368 n.as_limbs(),
369 &[Limb(0x44556677), Limb(0x00112233), Limb::ZERO, Limb::ZERO]
370 );
371 }
372
373 #[test]
374 fn from_le_slice_not_word_sized() {
375 let bytes = hex!("ffeeddccbbaa998877665544332211");
376 let n = BoxedUint::from_le_slice(&bytes, 127).unwrap();
377 assert_eq!(
378 n.as_limbs(),
379 &[
380 Limb(0xccddeeff),
381 Limb(0x8899aabb),
382 Limb(0x44556677),
383 Limb(0x00112233)
384 ]
385 );
386 assert_eq!(n.bits_precision(), 128);
387 }
388 }
389 64 => {
390 #[test]
391 fn from_be_slice_eq() {
392 let bytes = hex!("00112233445566778899aabbccddeeff");
393 let n = BoxedUint::from_be_slice(&bytes, 128).unwrap();
394 assert_eq!(
395 n.as_limbs(),
396 &[Limb(0x8899aabbccddeeff), Limb(0x0011223344556677)]
397 );
398 }
399
400 #[test]
401 fn from_be_hex_eq() {
402 let hex = "00112233445566778899aabbccddeeff";
403 let n = BoxedUint::from_be_hex(hex, 128).unwrap();
404 assert_eq!(
405 n.as_limbs(),
406 &[Limb(0x8899aabbccddeeff), Limb(0x0011223344556677)]
407 );
408 }
409
410 #[test]
411 fn from_be_slice_short() {
412 let bytes = hex!("00112233445566778899aabbccddeeff");
413 let n = BoxedUint::from_be_slice(&bytes, 256).unwrap();
414 assert_eq!(
415 n.as_limbs(),
416 &[
417 Limb(0x8899aabbccddeeff),
418 Limb(0x0011223344556677),
419 Limb::ZERO,
420 Limb::ZERO
421 ]
422 );
423 }
424
425 #[test]
426 fn from_be_slice_not_word_sized() {
427 let bytes = hex!("112233445566778899aabbccddeeff");
428 let n = BoxedUint::from_be_slice(&bytes, 127).unwrap();
429 assert_eq!(
430 n.as_limbs(),
431 &[Limb(0x8899aabbccddeeff), Limb(0x0011223344556677)]
432 );
433 assert_eq!(n.bits_precision(), 128);
434 }
435
436 #[test]
437 fn from_le_slice_eq() {
438 let bytes = hex!("ffeeddccbbaa99887766554433221100");
439 let n = BoxedUint::from_le_slice(&bytes, 128).unwrap();
440 assert_eq!(
441 n.as_limbs(),
442 &[Limb(0x8899aabbccddeeff), Limb(0x0011223344556677)]
443 );
444 }
445
446 #[test]
447 fn from_le_slice_short() {
448 let bytes = hex!("ffeeddccbbaa99887766554433221100");
449 let n = BoxedUint::from_le_slice(&bytes, 256).unwrap();
450 assert_eq!(
451 n.as_limbs(),
452 &[
453 Limb(0x8899aabbccddeeff),
454 Limb(0x0011223344556677),
455 Limb::ZERO,
456 Limb::ZERO
457 ]
458 );
459 }
460
461 #[test]
462 fn from_le_slice_not_word_sized() {
463 let bytes = hex!("ffeeddccbbaa998877665544332211");
464 let n = BoxedUint::from_le_slice(&bytes, 127).unwrap();
465 assert_eq!(
466 n.as_limbs(),
467 &[Limb(0x8899aabbccddeeff), Limb(0x0011223344556677)]
468 );
469 assert_eq!(n.bits_precision(), 128);
470 }
471 }
472 }
473
474 #[test]
475 fn from_be_slice_too_long() {
476 let bytes = hex!("00112233445566778899aabbccddeeff");
477 assert_eq!(
478 BoxedUint::from_be_slice(&bytes, 64),
479 Err(DecodeError::InputSize)
480 );
481 }
482
483 #[test]
484 fn from_be_slice_non_multiple_precision() {
485 let bytes = hex!("0f112233445566778899aabbccddeeff");
486 assert_eq!(
487 BoxedUint::from_be_slice(&bytes, 121),
488 Err(DecodeError::Precision)
489 );
490 }
491
492 #[test]
493 fn from_be_slice_vartime() {
494 let bytes = hex!(
495 "111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111F"
496 );
497 let uint = BoxedUint::from_be_slice_vartime(&bytes);
498 assert_eq!(&*uint.to_be_bytes_trimmed_vartime(), bytes.as_slice());
499 }
500
501 #[test]
502 fn from_le_slice_too_long() {
503 let bytes = hex!("ffeeddccbbaa99887766554433221100");
504 assert_eq!(
505 BoxedUint::from_be_slice(&bytes, 64),
506 Err(DecodeError::InputSize)
507 );
508 }
509
510 #[test]
511 fn from_le_slice_non_multiple_precision() {
512 let bytes = hex!("ffeeddccbbaa998877665544332211f0");
513 assert_eq!(
514 BoxedUint::from_le_slice(&bytes, 121),
515 Err(DecodeError::Precision)
516 );
517 }
518
519 #[test]
520 fn from_le_slice_vartime() {
521 let bytes = hex!(
522 "111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111F"
523 );
524 let uint = BoxedUint::from_le_slice_vartime(&bytes);
525 assert_eq!(&*uint.to_le_bytes_trimmed_vartime(), bytes.as_slice());
526 }
527
528 #[test]
529 fn to_be_bytes() {
530 let bytes = hex!("00112233445566778899aabbccddeeff");
531 let n = BoxedUint::from_be_slice(&bytes, 128).unwrap();
532 assert_eq!(bytes.as_slice(), &*n.to_be_bytes());
533 }
534
535 #[test]
536 fn to_be_bytes_trimmed_vartime() {
537 let bytes = hex!("ff112233445566778899aabbccddeeff");
538 let n = BoxedUint::from_be_slice(&bytes, 128).unwrap();
539 assert_eq!(&bytes, &*n.to_be_bytes_trimmed_vartime());
540
541 let bytes = hex!("00112233445566778899aabbccddeeff");
542 let n = BoxedUint::from_be_slice(&bytes, 128).unwrap();
543 assert_eq!(&bytes.as_slice()[1..], &*n.to_be_bytes_trimmed_vartime());
544
545 let bytes: &[u8] = b"";
546 let n = BoxedUint::from_be_slice(bytes, 128).unwrap();
547 assert_eq!(
548 hex!("00000000000000000000000000000000"),
549 n.to_be_bytes().as_ref()
550 );
551 assert_eq!(bytes, n.to_be_bytes_trimmed_vartime().as_ref());
552
553 let bytes = hex!("00012233445566778899aabbccddeeff");
554 let n = BoxedUint::from_be_slice(&bytes, 128).unwrap();
555 assert_eq!(&bytes.as_slice()[1..], &*n.to_be_bytes_trimmed_vartime());
556
557 let bytes = hex!("00000000000000000000000000000001");
558 let n = BoxedUint::from_be_slice(&bytes, 128).unwrap();
559 assert_eq!(bytes, n.to_be_bytes().as_ref());
560 assert_eq!(&bytes.as_slice()[15..], &*n.to_be_bytes_trimmed_vartime());
561 }
562
563 #[test]
564 fn to_le_bytes() {
565 let bytes = hex!("ffeeddccbbaa99887766554433221100");
566 let n = BoxedUint::from_le_slice(&bytes, 128).unwrap();
567 assert_eq!(bytes.as_slice(), &*n.to_le_bytes());
568 }
569
570 #[test]
571 fn to_le_bytes_trimmed_vartime() {
572 let bytes = hex!("ffeeddccbbaa998877665544332211ff");
573 let n = BoxedUint::from_le_slice(&bytes, 128).unwrap();
574 assert_eq!(bytes.as_slice(), &*n.to_le_bytes_trimmed_vartime());
575
576 let bytes = hex!("ffeeddccbbaa99887766554433221100");
577 let n = BoxedUint::from_le_slice(&bytes, 128).unwrap();
578 assert_eq!(&bytes.as_slice()[..15], &*n.to_le_bytes_trimmed_vartime());
579
580 let bytes = hex!("ff000000000000000000000000000000");
581 let n = BoxedUint::from_le_slice(&bytes, 128).unwrap();
582 assert_eq!(&bytes.as_slice()[..1], &*n.to_le_bytes_trimmed_vartime());
583
584 let bytes = hex!("01000000000000000000000000000000");
585 let n = BoxedUint::from_le_slice(&bytes, 128).unwrap();
586 assert_eq!(&bytes.as_slice()[..1], &*n.to_le_bytes_trimmed_vartime());
587
588 let bytes = hex!("00000000000000000000000000000000");
589 let n = BoxedUint::from_le_slice(&bytes, 128).unwrap();
590 assert_eq!(b"", &*n.to_le_bytes_trimmed_vartime());
591 }
592
593 #[test]
594 fn from_str_radix_invalid() {
595 assert_eq!(
596 BoxedUint::from_str_radix_vartime("?", 10,),
597 Err(DecodeError::InvalidDigit)
598 );
599 assert_eq!(
600 BoxedUint::from_str_radix_with_precision_vartime(
601 "ffffffffffffffff_ffffffffffffffff_f",
602 16,
603 128
604 ),
605 Err(DecodeError::InputSize)
606 );
607 assert_eq!(
608 BoxedUint::from_str_radix_with_precision_vartime("1111111111111111", 2, 10),
609 Err(DecodeError::Precision)
610 );
611 }
612
613 #[test]
614 fn from_str_radix_10() {
615 let dec = "+340_282_366_920_938_463_463_374_607_431_768_211_455";
616 let res = BoxedUint::from_str_radix_vartime(dec, 10).expect("error decoding");
617 assert_eq!(res, BoxedUint::max(128));
618 }
619
620 #[test]
621 fn from_str_radix_16() {
622 let hex = "fedcba9876543210fedcba9876543210";
623 let res = BoxedUint::from_str_radix_vartime(hex, 16).expect("error decoding");
624 assert_eq!(hex, format!("{res:x}"));
625 }
626
627 #[test]
628 #[cfg(feature = "rand_core")]
629 fn encode_radix_round_trip() {
630 use crate::RandomBits;
631 use rand_core::SeedableRng;
632 let mut rng = chacha20::ChaCha8Rng::seed_from_u64(1);
633
634 let rounds = if cfg!(miri) { 10 } else { 100 };
635 let bits = if cfg!(miri) { 256 } else { 4096 };
636 for _ in 0..rounds {
637 let uint = BoxedUint::random_bits(&mut rng, bits);
638 for radix in 2..=36 {
639 let enc = uint.to_string_radix_vartime(radix);
640 let res = BoxedUint::from_str_radix_vartime(&enc, radix).expect("decoding error");
641 assert_eq!(
642 res, uint,
643 "round trip failure: radix {radix} encoded {uint} as {enc}"
644 );
645 }
646 }
647 }
648}