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