1#![allow(private_bounds)]
5
6use crate::Sp80090ADrbg;
7
8use bouncycastle_core_interface::errors::{KeyMaterialError, RNGError};
9use bouncycastle_core_interface::key_material::{KeyMaterial512, KeyType};
10use bouncycastle_core_interface::traits::{Hash, HashAlgParams, KeyMaterial, RNG, SecurityStrength};
11use bouncycastle_sha2::{SHA256, SHA512};
12use bouncycastle_utils::min;
13
14use std::fmt::{Display, Formatter};
15
16enum SupportedHash {
17 SHA256,
18 SHA512,
19}
20
21trait HashDRBG80090AParams {
24 const HASH: SupportedHash;
25 const MAX_SECURITY_STRENGTH: SecurityStrength;
27 const MAX_LENGTH: u64;
29 const MAX_PERSONALIZATION_STRING_LENGTH: u64;
30 const MAX_ADDITIONAL_INPUT_LENGTH: u64;
31 const MAX_NUMBER_OF_BITS_PER_REQUEST: u64;
32 const RESEED_INTERVAL: u64;
33}
34
35#[allow(non_camel_case_types)]
36pub struct HashDRBG80090AParams_SHA256 {}
37
38impl HashDRBG80090AParams for HashDRBG80090AParams_SHA256 {
39 const HASH: SupportedHash = SupportedHash::SHA256;
40 const MAX_SECURITY_STRENGTH: SecurityStrength = SecurityStrength::_128bit;
42 const MAX_LENGTH: u64 = (1u64 << 35) / 8; const MAX_PERSONALIZATION_STRING_LENGTH: u64 = (1u64 << 35) / 8; const MAX_ADDITIONAL_INPUT_LENGTH: u64 = (1u64 << 35) / 8; const MAX_NUMBER_OF_BITS_PER_REQUEST: u64 = (1u64 << 19) / 8; const RESEED_INTERVAL: u64 = 1u64 << 48; }
49
50#[allow(non_camel_case_types)]
51pub struct HashDRBG80090AParams_SHA512 {}
52impl HashDRBG80090AParams for HashDRBG80090AParams_SHA512 {
53 const HASH: SupportedHash = SupportedHash::SHA512;
54 const MAX_SECURITY_STRENGTH: SecurityStrength = SecurityStrength::_256bit;
56 const MAX_LENGTH: u64 = (1u64 << 35) / 8; const MAX_PERSONALIZATION_STRING_LENGTH: u64 = (1u64 << 35) / 8; const MAX_ADDITIONAL_INPUT_LENGTH: u64 = (1u64 << 35) / 8; const MAX_NUMBER_OF_BITS_PER_REQUEST: u64 = (1u64 << 19) / 8; const RESEED_INTERVAL: u64 = 1u64 << 48; }
63
64const LARGEST_HASHER_OUTPUT_LEN: usize = 64;
66
67#[allow(private_bounds)]
68pub struct HashDRBG80090A<H: HashDRBG80090AParams> {
70 state: WorkingState<LARGEST_HASHER_OUTPUT_LEN>,
73 admin_info: AdministrativeInfo,
74}
75
76struct WorkingState<const SEED_LEN: usize> {
77 v: [u8; SEED_LEN],
78 c: [u8; SEED_LEN],
79
80 reseed_counter: u64,
82}
83
84struct AdministrativeInfo {
85 strength: SecurityStrength,
86 prediction_resistance: bool,
87 instantiated: bool,
88}
89
90impl<const SEED_LEN: usize> Drop for WorkingState<SEED_LEN> {
91 fn drop(&mut self) {
92 self.v.fill(0u8);
94 self.c.fill(0u8);
95 self.reseed_counter = 0;
96 }
97}
98
99impl<const SEED_LEN: usize> Display for WorkingState<SEED_LEN> {
101 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
102 write!(f, "HashDRBG80090A::WorkingState::<{}>", SEED_LEN)
103 }
104}
105
106#[test]
107fn test_working_state_display() {
109 let ws = WorkingState::<32> { v: [0u8; 32], c: [0u8; 32], reseed_counter: 0 };
110 assert_eq!(format!("{}", ws), "HashDRBG80090A::WorkingState::<32>");
111}
112
113impl<H: HashDRBG80090AParams> HashDRBG80090A<H> {
114 pub fn new() -> Self {
117 Self::new_from_os()
118 }
119
120 pub fn new_unititialized() -> Self {
125 Self {
126 state: WorkingState::<LARGEST_HASHER_OUTPUT_LEN> {
127 v: [0u8; LARGEST_HASHER_OUTPUT_LEN],
128 c: [0u8; LARGEST_HASHER_OUTPUT_LEN],
129 reseed_counter: 0,
130 },
131 admin_info: AdministrativeInfo {
132 strength: H::MAX_SECURITY_STRENGTH,
133 prediction_resistance: false,
134 instantiated: false,
135 },
136 }
137 }
138
139 pub fn new_from_os() -> Self {
141 let mut seed = KeyMaterial512::new();
142 seed.allow_hazardous_operations();
143 seed.set_key_type(KeyType::Seed).unwrap();
144 match H::HASH {
145 SupportedHash::SHA256 => {
146 getrandom::fill(&mut seed.mut_ref_to_bytes().unwrap()[..32]).unwrap();
147 seed.set_key_len(32).unwrap();
148 seed.set_security_strength(SecurityStrength::_128bit).unwrap();
149 }
150 SupportedHash::SHA512 => {
151 getrandom::fill(&mut seed.mut_ref_to_bytes().unwrap()).unwrap();
152 seed.set_key_len(64).unwrap();
153 seed.set_security_strength(SecurityStrength::_256bit).unwrap();
154 }
155 }
156
157 let mut rng = Self::new_unititialized();
158 let ss = seed.security_strength().clone();
159 rng.instantiate(false, seed, &KeyMaterial512::new(), "new_from_os".as_bytes(), ss).unwrap();
160 rng
161 }
162}
163
164impl<H: HashDRBG80090AParams> Default for HashDRBG80090A<H> {
165 fn default() -> Self {
168 Self::new_from_os()
169 }
170}
171
172impl<H: HashDRBG80090AParams> Sp80090ADrbg for HashDRBG80090A<H> {
173 fn instantiate(
176 &mut self,
177 prediction_resistance: bool,
178 seed: impl KeyMaterial,
179 nonce: &impl KeyMaterial,
180 personalization_string: &[u8],
181 security_strength: SecurityStrength,
182 ) -> Result<(), RNGError> {
183 if self.admin_info.instantiated {
192 return Err(RNGError::GenericError(
193 "This DRBG instance has already been instantiated.",
194 ));
195 }
196
197 if prediction_resistance {
199 todo!("Prediction resistance is not yet supported by Hash_DRBG80090A.")
200 }
201
202 if personalization_string.len() as u64 > H::MAX_PERSONALIZATION_STRING_LENGTH {
203 return Err(RNGError::GenericError(
204 "Personalization string exceeds the maximum length allowed by the DRBG instance",
205 ));
206 }
207
208 if seed.key_type() != KeyType::Seed {
209 return Err(KeyMaterialError::InvalidKeyType("RNG seed must be KeyType::Seed"))?;
210 }
211
212 if (seed.key_len() as u32) < security_strength.as_int() / 8 {
213 return Err(KeyMaterialError::SecurityStrength(
214 "Provided seed must have a length that matches or exceeds the DRBG security strength.",
215 ))?;
216 }
217 if (seed.key_len() as u64) > H::MAX_LENGTH {
218 return Err(KeyMaterialError::SecurityStrength(
219 "Provided seed exceeds the maximum seed length.",
220 ))?;
221 }
222 if security_strength > H::MAX_SECURITY_STRENGTH {
224 return Err(KeyMaterialError::SecurityStrength(
225 "Requested security strength exceeds the maximum strength that this DRBG instance can provide.",
226 ))?;
227 }
228
229 match H::HASH {
233 SupportedHash::SHA256 => hash_df::<SHA256>(
234 seed.ref_to_bytes(),
235 nonce.ref_to_bytes(),
236 personalization_string,
237 &[0u8; 0],
238 &mut self.state.v,
239 ),
240 SupportedHash::SHA512 => hash_df::<SHA512>(
241 seed.ref_to_bytes(),
242 nonce.ref_to_bytes(),
243 personalization_string,
244 &[0u8; 0],
245 &mut self.state.v,
246 ),
247 }
248
249 match H::HASH {
251 SupportedHash::SHA256 => {
252 hash_df::<SHA256>(&[0u8], &self.state.v, &[0u8; 0], &[0u8; 0], &mut self.state.c)
253 }
254 SupportedHash::SHA512 => {
255 hash_df::<SHA512>(&[0u8], &self.state.v, &[0u8; 0], &[0u8; 0], &mut self.state.c)
256 }
257 }
258
259 self.state.reseed_counter = 1;
261 self.admin_info.strength = min(&security_strength, &H::MAX_SECURITY_STRENGTH).clone();
262 self.admin_info.prediction_resistance = prediction_resistance;
263 self.admin_info.instantiated = true;
264
265 Ok(())
267 }
268
269 fn reseed(&mut self, seed: &impl KeyMaterial, additional_input: &[u8]) -> Result<(), RNGError> {
270 if !self.admin_info.instantiated {
279 return Err(RNGError::Uninitialized);
280 }
281
282 if additional_input.len() as u64 > H::MAX_ADDITIONAL_INPUT_LENGTH {
283 return Err(RNGError::GenericError(
284 "Additional input exceeds the maximum length allowed by the DRBG instance",
285 ));
286 }
287
288 if seed.key_type() != KeyType::Seed {
289 return Err(KeyMaterialError::InvalidKeyType("RNG seed must be KeyType::Seed"))?;
290 }
291
292 if (seed.key_len() as u32) < self.admin_info.strength.as_int() / 8 {
295 return Err(KeyMaterialError::SecurityStrength(
296 "Provided seed must have a length that matches or exceeds the DRBG security strength.",
297 ))?;
298 }
299 if (seed.key_len() as u64) > H::MAX_LENGTH {
300 return Err(KeyMaterialError::SecurityStrength(
301 "Provided seed exceeds the maximum seed length.",
302 ))?;
303 }
304
305 match H::HASH {
309 SupportedHash::SHA256 => hash_df::<SHA256>(
310 &[0x01],
311 &self.state.v.clone(),
312 seed.ref_to_bytes(),
313 additional_input,
314 &mut self.state.v,
315 ),
316 SupportedHash::SHA512 => hash_df::<SHA512>(
317 &[0x01],
318 &self.state.v.clone(),
319 seed.ref_to_bytes(),
320 additional_input,
321 &mut self.state.v,
322 ),
323 }
324
325 match H::HASH {
327 SupportedHash::SHA256 => {
328 hash_df::<SHA256>(&[0u8], &self.state.v, &[0u8; 0], &[0u8; 0], &mut self.state.c)
329 }
330 SupportedHash::SHA512 => {
331 hash_df::<SHA512>(&[0u8], &self.state.v, &[0u8; 0], &[0u8; 0], &mut self.state.c)
332 }
333 }
334
335 self.state.reseed_counter = 1;
337
338 Ok(())
340 }
341
342 fn generate(&mut self, additional_input: &[u8], len: usize) -> Result<Vec<u8>, RNGError> {
343 let mut out = vec![0u8; len];
344 self.generate_out(additional_input, &mut out)?;
345 Ok(out)
346 }
347
348 fn generate_out(&mut self, additional_input: &[u8], out: &mut [u8]) -> Result<usize, RNGError> {
349 if !self.admin_info.instantiated {
361 return Err(RNGError::Uninitialized);
362 }
363 if out.len() as u64 > H::MAX_NUMBER_OF_BITS_PER_REQUEST {
364 return Err(RNGError::GenericError(
365 "Requested number of bits exceeds the maximum number of bits per request allowed by the DRBG instance",
366 ));
367 }
368 if additional_input.len() as u64 > H::MAX_ADDITIONAL_INPUT_LENGTH {
369 return Err(RNGError::GenericError(
370 "Additional input exceeds the maximum length allowed by the DRBG instance",
371 ));
372 }
373
374 if self.state.reseed_counter > H::RESEED_INTERVAL {
376 return Err(RNGError::ReseedRequired);
377 }
378
379 if additional_input.len() > 0 {
383 match H::HASH {
384 SupportedHash::SHA256 => {
385 let mut h = SHA256::new();
386 h.do_update(&[0x02]);
387 h.do_update(&self.state.v);
388 h.do_update(additional_input);
389
390 let mut w = [0u8; SHA256::OUTPUT_LEN];
391 h.do_final_out(&mut w);
392 add_to_array(&mut self.state.v, &w);
393 }
394 SupportedHash::SHA512 => {
395 let mut h = SHA512::new();
396 h.do_update(&[0x02]);
397 h.do_update(&self.state.v);
398 h.do_update(additional_input);
399
400 let mut w = [0u8; SHA512::OUTPUT_LEN];
401 h.do_final_out(&mut w);
402 add_to_array(&mut self.state.v, &w);
403 }
404 }
405 }
406
407 if out.len() > 0 {
409 match H::HASH {
413 SupportedHash::SHA256 => {
414 hashgen::<SHA256>(&self.state.v, out);
415 }
416 SupportedHash::SHA512 => {
417 hashgen::<SHA512>(&self.state.v, out);
418 }
419 }
420 }
421
422 let mut h = [0u8; 64];
425 match H::HASH {
426 SupportedHash::SHA256 => {
427 let mut sha = SHA256::default();
428 sha.do_update(&[0x03]);
429 sha.do_update(&self.state.v);
430 sha.do_final_out(&mut h);
431 }
432 SupportedHash::SHA512 => {
433 let mut sha = SHA512::default();
434 sha.do_update(&[0x03]);
435 sha.do_update(&self.state.v);
436 sha.do_final_out(&mut h);
437 }
438 };
439
440 add_to_array(&mut self.state.v, &h);
442 add_to_array(&mut self.state.v, &self.state.c);
443 add_to_array(&mut self.state.v, &self.state.reseed_counter.to_le_bytes());
444
445 self.state.reseed_counter += 1;
447
448 Ok(out.len())
450 }
451
452 fn generate_keymaterial_out(
453 &mut self,
454 additional_input: &[u8],
455 out: &mut impl KeyMaterial,
456 ) -> Result<usize, RNGError> {
457 out.allow_hazardous_operations();
458 let bytes_written = self.generate_out(additional_input, out.mut_ref_to_bytes().unwrap())?;
459
460 out.set_key_len(bytes_written)?;
461 out.set_key_type(KeyType::BytesFullEntropy)?;
462 let new_security_strength =
463 min(&self.admin_info.strength, &SecurityStrength::from_bits(bytes_written * 8)).clone();
464 out.set_security_strength(new_security_strength)?;
465 out.drop_hazardous_operations();
466 Ok(bytes_written)
467 }
468}
469
470impl<H: HashDRBG80090AParams> RNG for HashDRBG80090A<H> {
471 fn add_seed_keymaterial(&mut self, additional_seed: impl KeyMaterial) -> Result<(), RNGError> {
479 self.reseed(&additional_seed, "add_seed_keymaterial".as_bytes())
480 }
481
482 fn next_int(&mut self) -> Result<u32, RNGError> {
483 let mut out = [0u8; 4];
484 self.generate_out("next_int".as_bytes(), &mut out)?;
485 Ok(u32::from_le_bytes(out))
486 }
487
488 fn next_bytes(&mut self, len: usize) -> Result<Vec<u8>, RNGError> {
489 self.generate("next_bytes".as_bytes(), len)
490 }
491
492 fn next_bytes_out(&mut self, out: &mut [u8]) -> Result<usize, RNGError> {
493 self.generate_out("next_bytes_out".as_bytes(), out)
494 }
495
496 fn fill_keymaterial_out(&mut self, out: &mut impl KeyMaterial) -> Result<usize, RNGError> {
497 self.generate_keymaterial_out("fill_keymaterial".as_bytes(), out)
498 }
499
500 fn security_strength(&self) -> SecurityStrength {
501 self.admin_info.strength.clone()
502 }
503}
504
505fn hash_df<H: Hash + HashAlgParams + Default>(
511 in1: &[u8],
512 in2: &[u8],
513 in3: &[u8],
514 in4: &[u8],
515 out: &mut [u8],
516) {
517 if out.len() > 255 * H::OUTPUT_LEN {
521 panic!("hash_df can't produce that much output!")
522 }
523
524 let no_of_bits_to_return: u32 = (out.len() * 8) as u32;
526 let len = u32::div_ceil(out.len() as u32, H::OUTPUT_LEN as u32);
527 let mut counter: u8 = 0x01;
528
529 for i in 1..len {
532 let mut h = H::default();
533 h.do_update(&counter.to_le_bytes());
534 h.do_update(&no_of_bits_to_return.to_le_bytes());
535 h.do_update(in1);
536 h.do_update(in2);
537 h.do_update(in3);
538 h.do_update(in4);
539 h.do_final_out(&mut out[((i - 1) as usize) * H::OUTPUT_LEN..(i as usize) * H::OUTPUT_LEN]);
540
541 counter += 1;
542 }
543
544 let bytes_written = (len - 1) as usize * H::OUTPUT_LEN;
547 let remainder = out.len() - bytes_written;
548 if remainder != 0 {
549 let mut h = H::default();
550 h.do_update(&counter.to_le_bytes());
551 h.do_update(&no_of_bits_to_return.to_le_bytes());
552 h.do_update(in1);
553 h.do_update(in2);
554 h.do_update(in3);
555 h.do_update(in4);
556
557 let mut temp = [0u8; 64];
560 h.do_final_out(&mut temp);
561
562 out[bytes_written..].copy_from_slice(&temp[..remainder]);
564 }
565}
566
567#[test]
568fn test_hash_df() {
569 let mut out = [0u8; 100];
571 hash_df::<SHA256>(&[0x01, 0x02, 0x03], &[0x04, 0x05], &[0x06, 0x07], &[0x08, 0x09], &mut out);
572 assert_ne!(out, [0u8; 100]);
573 assert_eq!(out, [150u8, 177u8, 87u8, 145u8, 138u8, 4u8, 164u8, 14u8, 162u8, 43u8, 159u8, 152u8, 121u8, 117u8, 6u8, 18u8, 253u8, 84u8, 41u8, 64u8, 40u8, 209u8, 16u8, 176u8, 106u8, 115u8, 172u8, 193u8, 246u8, 228u8, 208u8, 79u8, 37u8, 31u8, 134u8, 141u8, 200u8, 7u8, 42u8, 199u8, 229u8, 236u8, 236u8, 186u8, 28u8, 87u8, 200u8, 14u8, 127u8, 36u8, 132u8, 23u8, 36u8, 150u8, 23u8, 215u8, 247u8, 121u8, 175u8, 82u8, 99u8, 187u8, 235u8, 25u8, 213u8, 18u8, 106u8, 22u8, 4u8, 99u8, 1u8, 184u8, 211u8, 160u8, 177u8, 67u8, 78u8, 181u8, 69u8, 51u8, 117u8, 2u8, 72u8, 36u8, 134u8, 72u8, 2u8, 9u8, 105u8, 149u8, 136u8, 35u8, 81u8, 114u8, 142u8, 80u8, 94u8, 42u8, 85u8, 155]);
576
577 let mut out_max_sha256 = vec![0u8; 255 * 32];
579 hash_df::<SHA256>(&[0x01], &[0x02], &[0x03], &[0x04], &mut out_max_sha256);
580 assert_ne!(out_max_sha256, vec![0u8; 255 * 32]);
581
582 let mut out_too_large_sha256 = vec![0u8; 255 * 32 + 1];
584 let result_sha256 = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
585 hash_df::<SHA256>(&[0x01], &[0x02], &[0x03], &[0x04], &mut out_too_large_sha256);
586 }));
587 assert!(result_sha256.is_err());
588
589 let mut out_max_sha512 = vec![0u8; 255 * 64];
591 hash_df::<SHA512>(&[0x01], &[0x02], &[0x03], &[0x04], &mut out_max_sha512);
592 assert_ne!(out_max_sha512, vec![0u8; 255 * 64]);
593 assert_ne!(out_max_sha512[254 * 64..], [0u8; 64]);
595
596 let mut out_too_large_sha512 = vec![0u8; 255 * 64 + 1];
598 let result_sha512 = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
599 hash_df::<SHA512>(&[0x01], &[0x02], &[0x03], &[0x04], &mut out_too_large_sha512);
600 }));
601 assert!(result_sha512.is_err());
602}
603
604fn hashgen<H: Hash + HashAlgParams + Default>(v: &[u8], out: &mut [u8]) {
605 let m = u32::div_ceil(out.len() as u32, H::OUTPUT_LEN as u32);
618
619 let mut data = [0u8; 64];
622 data.copy_from_slice(v);
623 for i in 1..m {
630 H::default().hash_out(
631 &data,
632 &mut out[((i - 1) as usize) * H::OUTPUT_LEN..(i as usize) * H::OUTPUT_LEN],
633 );
634 add_to_array(&mut data, &[0x01]);
635 }
636
637 let bytes_written = (m - 1) as usize * H::OUTPUT_LEN;
640 let remainder = out.len() - bytes_written;
641 if remainder != 0 {
642 let mut temp = [0u8; 64];
645 H::default().hash_out(&data, &mut temp);
646
647 out[bytes_written..].copy_from_slice(&temp[..remainder as usize]);
649 }
650}
651
652fn add_to_array(longer: &mut [u8], shorter: &[u8]) {
658 if shorter.len() > longer.len() {
659 panic!("add_to_array: shorter array is longer than longer array!")
660 }
661
662 let mut carry: u8 = 0;
663
664 for i in 1..=shorter.len() {
666 let res = (longer[longer.len() - i] as u16)
667 + (shorter[shorter.len() - i] as u16)
668 + (carry as u16);
669 carry = if res > 0xFF { 1 } else { 0 };
670 longer[longer.len() - i] = res as u8;
671 }
672
673 for i in (shorter.len() + 1)..=longer.len() {
675 let res = (longer[longer.len() - i] as u16) + (carry as u16);
676 carry = if res > 0xFF { 1 } else { 0 };
677 longer[longer.len() - i] = res as u8;
678 }
679}
680
681#[test]
682fn test_add_to_array() {
683 let mut longer = [0x0F, 0xFF, 0xFF, 0xFF];
684 let shorter = [0x01];
685 add_to_array(&mut longer, &shorter);
686 assert_eq!(longer, [0x10, 0x00, 0x00, 0x00]);
687
688 let mut longer = [0x0F, 0xFF, 0xFE, 0xFE];
689 let shorter = [0x01];
690 add_to_array(&mut longer, &shorter);
691 assert_eq!(longer, [0x0F, 0xFF, 0xFE, 0xFF]);
692
693 let mut longer = [0x0F, 0xFF, 0xFE, 0xFF];
694 let shorter = [0x01];
695 add_to_array(&mut longer, &shorter);
696 assert_eq!(longer, [0x0F, 0xFF, 0xFF, 0x00]);
697
698 let mut longer = [0x1F, 0xFF, 0xFF, 0xFF];
699 let shorter = [0xE0, 0x00, 0x00, 0x02];
700 add_to_array(&mut longer, &shorter);
701 assert_eq!(longer, [0x00, 0x00, 0x00, 0x01]);
702
703 let mut longer = [0xFF];
704 let shorter = [0x01];
705 add_to_array(&mut longer, &shorter);
706 assert_eq!(longer, [0x00]);
707
708 let mut longer = [0x00, 0x01];
709 let shorter = [0xFF];
710 add_to_array(&mut longer, &shorter);
711 assert_eq!(longer, [0x01, 0x00]);
712
713 let mut longer = [0x00, 0x00, 0xFF];
714 let shorter = [0x00, 0x01];
715 add_to_array(&mut longer, &shorter);
716 assert_eq!(longer, [0x00, 0x01, 0x00]);
717
718 let mut longer = [0x00, 0x00, 0xFF];
719 let shorter = [0x0C, 0x01];
720 add_to_array(&mut longer, &shorter);
721 assert_eq!(longer, [0x00, 0x0D, 0x00]);
722
723 let mut longer = [0x00, 0xFF];
724 let shorter = [0x00, 0x01];
725 add_to_array(&mut longer, &shorter);
726 assert_eq!(longer, [0x01, 0x00]);
727
728 let mut longer = [0x00, 0x00, 0xFF];
729 let shorter = [0x00, 0x0C, 0x01];
730 add_to_array(&mut longer, &shorter);
731 assert_eq!(longer, [0x00, 0x0D, 0x00]);
732
733 let mut longer = [0x00, 0x00, 0xFF];
734 let shorter = [0x00, 0x0F, 0x01];
735 add_to_array(&mut longer, &shorter);
736 assert_eq!(longer, [0x00, 0x10, 0x00]);
737
738 let mut longer = [0x00, 0x00, 0xFC];
739 let shorter = [0x00, 0x0F, 0x01];
740 add_to_array(&mut longer, &shorter);
741 assert_eq!(longer, [0x00, 0x0F, 0xFD]);
742
743 let mut longer = [0x00, 0x0F, 0xFC];
744 let shorter = [0x00, 0x1F, 0x01];
745 add_to_array(&mut longer, &shorter);
746 assert_eq!(longer, [0x00, 0x2E, 0xFD]);
747}