Skip to main content

bouncycastle_rng/
hash_drbg80090a.rs

1//! Implements Hash_DRBG (Deterministic Random Bit Generator) from NIST SP 800-90Ar1.
2
3// This is here cause HashDRBG80090AParams is private on purpose so that people can't instantiate new parameter sets other than the ones prescribed by NIST.
4#![allow(private_bounds)]
5
6use crate::Sp80090ADrbg;
7
8use bouncycastle_core::errors::{KeyMaterialError, RNGError};
9use bouncycastle_core::key_material::{
10    KeyMaterial512, KeyMaterialTrait, KeyType, do_hazardous_operations,
11};
12use bouncycastle_core::traits::{Hash, HashAlgParams, RNG, SecurityStrength};
13use bouncycastle_sha2::{SHA256, SHA512};
14use bouncycastle_utils::{min, secret::Secret};
15
16use std::fmt::{Display, Formatter};
17
18enum SupportedHash {
19    SHA256,
20    SHA512,
21}
22
23// By not making this pub, nobody else should be able to impl it;
24// ie the structs defined below will be the only allowed ones.
25trait HashDRBG80090AParams {
26    const HASH: SupportedHash;
27    // const OUT_LEN: usize;
28    const MAX_SECURITY_STRENGTH: SecurityStrength;
29    // const SEED_LEN: usize;
30    const MAX_LENGTH: u64;
31    const MAX_PERSONALIZATION_STRING_LENGTH: u64;
32    const MAX_ADDITIONAL_INPUT_LENGTH: u64;
33    const MAX_NUMBER_OF_BITS_PER_REQUEST: u64;
34    const RESEED_INTERVAL: u64;
35}
36
37/// The parameters for HashDRBG with SHA256.
38#[allow(non_camel_case_types)]
39pub struct HashDRBG80090AParams_SHA256 {}
40
41impl HashDRBG80090AParams for HashDRBG80090AParams_SHA256 {
42    const HASH: SupportedHash = SupportedHash::SHA256;
43    const MAX_SECURITY_STRENGTH: SecurityStrength = SecurityStrength::_128bit;
44    const MAX_LENGTH: u64 = (1u64 << 35) / 8; // 2^35 bits
45    const MAX_PERSONALIZATION_STRING_LENGTH: u64 = (1u64 << 35) / 8; // 2^35 bits
46    const MAX_ADDITIONAL_INPUT_LENGTH: u64 = (1u64 << 35) / 8; // 2^35 bits
47    const MAX_NUMBER_OF_BITS_PER_REQUEST: u64 = (1u64 << 19) / 8; // 2^19 bits
48    const RESEED_INTERVAL: u64 = 1u64 << 48; // 2^48 requests
49}
50
51/// The parameters for HashDRBG with SHA256.
52#[allow(non_camel_case_types)]
53pub struct HashDRBG80090AParams_SHA512 {}
54impl HashDRBG80090AParams for HashDRBG80090AParams_SHA512 {
55    const HASH: SupportedHash = SupportedHash::SHA512;
56    const MAX_SECURITY_STRENGTH: SecurityStrength = SecurityStrength::_256bit;
57    const MAX_LENGTH: u64 = (1u64 << 35) / 8; // 2^35 bits
58    const MAX_PERSONALIZATION_STRING_LENGTH: u64 = (1u64 << 35) / 8; // 2^35 bits
59    const MAX_ADDITIONAL_INPUT_LENGTH: u64 = (1u64 << 35) / 8; // 2^35 bits
60    const MAX_NUMBER_OF_BITS_PER_REQUEST: u64 = (1u64 << 19) / 8; // 2^19 bits
61    const RESEED_INTERVAL: u64 = 1u64 << 48; // 2^48 requests
62}
63
64// TODO: replace / simplify this once the generic_const_exprs feature lands in the stable rust compiler.
65const LARGEST_HASHER_OUTPUT_LEN: usize = 64;
66
67#[allow(private_bounds)]
68/// Implementation of the Hash_DRBG algorithm as specified in NIST SP 800-90Ar1.
69pub struct HashDRBG80090A<H: HashDRBG80090AParams> {
70    _phantom: core::marker::PhantomData<H>,
71    // TODO: replace / simplify this once the generic_const_exprs feature lands in the stable rust compiler.
72    //  state: WorkingState<H::SEED_LEN>,
73    state: WorkingState<LARGEST_HASHER_OUTPUT_LEN>,
74    admin_info: AdministrativeInfo,
75}
76
77struct WorkingState<const SEED_LEN: usize> {
78    v: Secret<[u8; SEED_LEN]>,
79    c: Secret<[u8; SEED_LEN]>,
80
81    /// s 8.3: "A count of the number of requests produced since the instantiation was seeded or reseeded."
82    reseed_counter: Secret<u64>,
83}
84
85struct AdministrativeInfo {
86    strength: SecurityStrength,
87    prediction_resistance: bool,
88    instantiated: bool,
89}
90
91/// Explicit implementation of Display that prevents auto-generated ones from accidentally leaking secrets.
92impl<const SEED_LEN: usize> Display for WorkingState<SEED_LEN> {
93    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
94        write!(f, "HashDRBG80090A::WorkingState::<{}>", SEED_LEN)
95    }
96}
97
98#[test]
99/// impl Display to not print the state data.
100fn test_working_state_display() {
101    let ws =
102        WorkingState::<32> { v: Secret::new(), c: Secret::new(), reseed_counter: Secret::new() };
103    assert_eq!(format!("{}", ws), "HashDRBG80090A::WorkingState::<32>");
104}
105
106impl<H: HashDRBG80090AParams> HashDRBG80090A<H> {
107    /// Creates a new instance using the local OS RNG as a source of seed entropy.
108    /// Alias for [`HashDRBG80090A::new_from_os`].
109    pub fn new() -> Self {
110        Self::new_from_os()
111    }
112
113    /// Creates a new, uninstantiated instance. After creating it, you must call instantiate() to seed it.
114    ///
115    /// **WARNING: Dangerous! This constructor does not initialize the DRBG from any entropy source,
116    /// and relies on you to provide a strong seed.**
117    pub fn new_unititialized() -> Self {
118        Self {
119            _phantom: core::marker::PhantomData,
120            state: WorkingState::<LARGEST_HASHER_OUTPUT_LEN> {
121                v: Secret::<[u8; LARGEST_HASHER_OUTPUT_LEN]>::new(),
122                c: Secret::<[u8; LARGEST_HASHER_OUTPUT_LEN]>::new(),
123                reseed_counter: Secret::new(),
124            },
125            admin_info: AdministrativeInfo {
126                strength: H::MAX_SECURITY_STRENGTH,
127                prediction_resistance: false,
128                instantiated: false,
129            },
130        }
131    }
132
133    /// Creates a new instance using the local OS RNG as a source of seed entropy.
134    pub fn new_from_os() -> Self {
135        let mut seed = KeyMaterial512::new();
136        do_hazardous_operations(&mut seed, |seed| {
137            seed.set_key_type(KeyType::Seed).unwrap();
138            match H::HASH {
139                SupportedHash::SHA256 => {
140                    getrandom::fill(&mut seed.ref_to_bytes_mut().unwrap()[..32]).unwrap();
141                    seed.set_key_len(32).unwrap();
142                    seed.set_security_strength(SecurityStrength::_128bit).unwrap();
143                }
144                SupportedHash::SHA512 => {
145                    getrandom::fill(&mut seed.ref_to_bytes_mut().unwrap()).unwrap();
146                    seed.set_key_len(64).unwrap();
147                    seed.set_security_strength(SecurityStrength::_256bit).unwrap();
148                }
149            }
150            Ok(())
151        })
152        .unwrap();
153
154        let mut rng = Self::new_unititialized();
155        let ss = seed.security_strength().clone();
156        rng.instantiate(false, seed, &KeyMaterial512::new(), "new_from_os".as_bytes(), ss).unwrap();
157        rng
158    }
159}
160
161impl<H: HashDRBG80090AParams> Default for HashDRBG80090A<H> {
162    /// Creates a new instance using the local OS RNG as a source of seed entropy.
163    /// Alias for [`HashDRBG80090A::new_from_os`].
164    fn default() -> Self {
165        Self::new_from_os()
166    }
167}
168
169impl<H: HashDRBG80090AParams> Sp80090ADrbg for HashDRBG80090A<H> {
170    /// Output:
171    /// 1. initial_working_state: The initial values for V, C, and reseed_counter (see Section 10.1.1.1).
172    fn instantiate(
173        &mut self,
174        prediction_resistance: bool,
175        seed: impl KeyMaterialTrait,
176        nonce: &impl KeyMaterialTrait,
177        personalization_string: &[u8],
178        security_strength: SecurityStrength,
179    ) -> Result<(), RNGError> {
180        // Hash_DRBG Instantiate Process:
181        // 1. seed_material = entropy_input || nonce || personalization_string.
182        // 2. seed = Hash_df (seed_material, seedlen).
183        // 3. V = seed.
184        // 4. C = Hash_df ((0x00 || V), seedlen). Comment: Precede V with a byte of zeros.
185        // 5. reseed_counter = 1.
186        // 6. Return (V, C, reseed_counter).
187
188        if self.admin_info.instantiated {
189            return Err(RNGError::GenericError(
190                "This DRBG instance has already been instantiated.",
191            ));
192        }
193
194        // TODO: take this out once supported
195        if prediction_resistance {
196            todo!("Prediction resistance is not yet supported by Hash_DRBG80090A.")
197        }
198
199        if personalization_string.len() as u64 > H::MAX_PERSONALIZATION_STRING_LENGTH {
200            return Err(RNGError::GenericError(
201                "Personalization string exceeds the maximum length allowed by the DRBG instance",
202            ));
203        }
204
205        if seed.key_type() != KeyType::Seed {
206            return Err(KeyMaterialError::InvalidKeyType("RNG seed must be KeyType::Seed"))?;
207        }
208
209        if (seed.key_len() as u32) < security_strength.as_int() / 8 {
210            return Err(KeyMaterialError::SecurityStrength(
211                "Provided seed must have a length that matches or exceeds the DRBG security strength.",
212            ))?;
213        }
214        if (seed.key_len() as u64) > H::MAX_LENGTH {
215            return Err(KeyMaterialError::SecurityStrength(
216                "Provided seed exceeds the maximum seed length.",
217            ))?;
218        }
219        // On purpose not checking the SecurityStrength field of the seed, 
220        // because we assume it's pure entropy and hasn't been touched by any actual algoritms yet.
221        if security_strength > H::MAX_SECURITY_STRENGTH {
222            return Err(KeyMaterialError::SecurityStrength(
223                "Requested security strength exceeds the maximum strength that this DRBG instance can provide.",
224            ))?;
225        }
226
227        // 1. seed_material = entropy_input || nonce || personalization_string.
228        // 2. seed = Hash_df (seed_material, seedlen).
229        // 3. V = seed.
230        match H::HASH {
231            SupportedHash::SHA256 => hash_df::<SHA256>(
232                seed.ref_to_bytes(),
233                nonce.ref_to_bytes(),
234                personalization_string,
235                &[0u8; 0],
236                &mut *self.state.v,
237            ),
238            SupportedHash::SHA512 => hash_df::<SHA512>(
239                seed.ref_to_bytes(),
240                nonce.ref_to_bytes(),
241                personalization_string,
242                &[0u8; 0],
243                &mut *self.state.v,
244            ),
245        }
246
247        // 4. C = Hash_df ((0x00 || V), seedlen). Comment: Precede V with a byte of zeros.
248        match H::HASH {
249            SupportedHash::SHA256 => {
250                hash_df::<SHA256>(&[0u8], &*self.state.v, &[0u8; 0], &[0u8; 0], &mut *self.state.c)
251            }
252            SupportedHash::SHA512 => {
253                hash_df::<SHA512>(&[0u8], &*self.state.v, &[0u8; 0], &[0u8; 0], &mut *self.state.c)
254            }
255        }
256
257        // 5. reseed_counter = 1.
258        *self.state.reseed_counter = 1;
259        self.admin_info.strength = min(&security_strength, &H::MAX_SECURITY_STRENGTH).clone();
260        self.admin_info.prediction_resistance = prediction_resistance;
261        self.admin_info.instantiated = true;
262
263        // 6. Return (V, C, reseed_counter).
264        Ok(())
265    }
266
267    fn reseed<K: KeyMaterialTrait + ?Sized>(
268        &mut self,
269        seed: &K,
270        additional_input: &[u8],
271    ) -> Result<(), RNGError> {
272        // Hash_DRBG Reseed Process:
273        // 1. seed_material = 0x01 || V || entropy_input || additional_input.
274        // 2. seed = Hash_df (seed_material, seedlen).
275        // 3. V = seed.
276        // 4. C = Hash_df ((0x00 || V), seedlen). Comment: Preceed with a byte of all zeros.
277        // 5. reseed_counter = 1.
278        // 6. Return (V, C, and reseed_counter).
279
280        if !self.admin_info.instantiated {
281            return Err(RNGError::Uninitialized);
282        }
283
284        if additional_input.len() as u64 > H::MAX_ADDITIONAL_INPUT_LENGTH {
285            return Err(RNGError::GenericError(
286                "Additional input exceeds the maximum length allowed by the DRBG instance",
287            ));
288        }
289
290        if seed.key_type() != KeyType::Seed {
291            return Err(KeyMaterialError::InvalidKeyType("RNG seed must be KeyType::Seed"))?;
292        }
293
294        // On purpose not checking the SecurityStrength field of the seed, because we assume it's pure entropy and hasn't been touched by any actual algoritms yet.
295
296        if (seed.key_len() as u32) < self.admin_info.strength.as_int() / 8 {
297            return Err(KeyMaterialError::SecurityStrength(
298                "Provided seed must have a length that matches or exceeds the DRBG security strength.",
299            ))?;
300        }
301        if (seed.key_len() as u64) > H::MAX_LENGTH {
302            return Err(KeyMaterialError::SecurityStrength(
303                "Provided seed exceeds the maximum seed length.",
304            ))?;
305        }
306
307        // 1. seed_material = 0x01 || V || entropy_input || additional_input.
308        // 2. seed = Hash_df (seed_material, seedlen).
309        // 3. V = seed.
310        match H::HASH {
311            SupportedHash::SHA256 => hash_df::<SHA256>(
312                &[0x01],
313                &*self.state.v.clone(),
314                seed.ref_to_bytes(),
315                additional_input,
316                &mut *self.state.v,
317            ),
318            SupportedHash::SHA512 => hash_df::<SHA512>(
319                &[0x01],
320                &*self.state.v.clone(),
321                seed.ref_to_bytes(),
322                additional_input,
323                &mut *self.state.v,
324            ),
325        }
326
327        // 4. C = Hash_df ((0x00 || V), seedlen). Comment: Preceed with a byte of all zeros.
328        match H::HASH {
329            SupportedHash::SHA256 => {
330                hash_df::<SHA256>(&[0u8], &*self.state.v, &[0u8; 0], &[0u8; 0], &mut *self.state.c)
331            }
332            SupportedHash::SHA512 => {
333                hash_df::<SHA512>(&[0u8], &*self.state.v, &[0u8; 0], &[0u8; 0], &mut *self.state.c)
334            }
335        }
336
337        // 5. reseed_counter = 1.
338        *self.state.reseed_counter = 1;
339
340        // 6. Return (V, C, and reseed_counter).
341        Ok(())
342    }
343
344    fn generate(&mut self, additional_input: &[u8], len: usize) -> Result<Vec<u8>, RNGError> {
345        let mut out = vec![0u8; len];
346        self.generate_out(additional_input, &mut out)?;
347        Ok(out)
348    }
349
350    fn generate_out(&mut self, additional_input: &[u8], out: &mut [u8]) -> Result<usize, RNGError> {
351        // Hash_DRBG_Generate Process:
352        // 1. If reseed_counter > reseed_interval, then return an indication that a reseed is required.
353        // 2. If (additional_input ≠ Null), then do
354        //   2.1 w = Hash (0x02 || V || additional_input).
355        //   2.2 V = (V + w) mod 2^seedlen.
356        // 3. (returned_bits) = Hashgen (requested_number_of_bits, V).
357        // 4. H = Hash (0x03 || V).
358        // 5. V = (V + H + C + reseed_counter) mod 2^seedlen.
359        // 6. reseed_counter = reseed_counter + 1.
360        // 7. Return (SUCCESS, returned_bits, V, C, reseed_counter).
361
362        if !self.admin_info.instantiated {
363            return Err(RNGError::Uninitialized);
364        }
365        if out.len() as u64 > H::MAX_NUMBER_OF_BITS_PER_REQUEST {
366            return Err(RNGError::GenericError(
367                "Requested number of bits exceeds the maximum number of bits per request allowed by the DRBG instance",
368            ));
369        }
370        if additional_input.len() as u64 > H::MAX_ADDITIONAL_INPUT_LENGTH {
371            return Err(RNGError::GenericError(
372                "Additional input exceeds the maximum length allowed by the DRBG instance",
373            ));
374        }
375
376        // 1. If reseed_counter > reseed_interval, then return an indication that a reseed is required.
377        if *self.state.reseed_counter > H::RESEED_INTERVAL {
378            return Err(RNGError::ReseedRequired);
379        }
380
381        out.fill(0);
382
383        // 2. If (additional_input ≠ Null), then do
384        //   2.1 w = Hash (0x02 || V || additional_input).
385        //   2.2 V = (V + w) mod 2^seedlen.
386        if additional_input.len() > 0 {
387            match H::HASH {
388                SupportedHash::SHA256 => {
389                    let mut h = SHA256::new();
390                    h.do_update(&[0x02]);
391                    h.do_update(&*self.state.v);
392                    h.do_update(additional_input);
393
394                    let mut w = [0u8; SHA256::OUTPUT_LEN];
395                    h.do_final_out(&mut w);
396                    add_to_array(&mut *self.state.v, &w);
397                }
398                SupportedHash::SHA512 => {
399                    let mut h = SHA512::new();
400                    h.do_update(&[0x02]);
401                    h.do_update(&*self.state.v);
402                    h.do_update(additional_input);
403
404                    let mut w = [0u8; SHA512::OUTPUT_LEN];
405                    h.do_final_out(&mut w);
406                    add_to_array(&mut *self.state.v, &w);
407                }
408            }
409        }
410
411        // 3. (returned_bits) = Hashgen (requested_number_of_bits, V).
412        if out.len() > 0 {
413            // If zero bytes of output is requested, we can skip the hashgen step because this step
414            // is purely producing output and has no side-effect on the state.
415            // But we do want to continue below to roll the state and increment the request counter.
416            match H::HASH {
417                SupportedHash::SHA256 => {
418                    hashgen::<SHA256>(&*self.state.v, out);
419                }
420                SupportedHash::SHA512 => {
421                    hashgen::<SHA512>(&*self.state.v, out);
422                }
423            }
424        }
425
426        // 4. H = Hash (0x03 || V).
427        // let mut h = [0u8; H::OUT_LEN];
428        let mut h = [0u8; 64];
429        match H::HASH {
430            SupportedHash::SHA256 => {
431                let mut sha = SHA256::default();
432                sha.do_update(&[0x03]);
433                sha.do_update(&*self.state.v);
434                sha.do_final_out(&mut h);
435            }
436            SupportedHash::SHA512 => {
437                let mut sha = SHA512::default();
438                sha.do_update(&[0x03]);
439                sha.do_update(&*self.state.v);
440                sha.do_final_out(&mut h);
441            }
442        };
443
444        // 5. V = (V + H + C + reseed_counter) mod 2^seedlen.
445        add_to_array(&mut *self.state.v, &h);
446        add_to_array(&mut *self.state.v, &*self.state.c);
447        add_to_array(&mut *self.state.v, &self.state.reseed_counter.to_le_bytes());
448
449        // 6. reseed_counter = reseed_counter + 1.
450        *self.state.reseed_counter += 1;
451
452        // 7. Return (SUCCESS, returned_bits, V, C, reseed_counter).
453        Ok(out.len())
454    }
455
456    fn generate_keymaterial_out<K: KeyMaterialTrait + ?Sized>(
457        &mut self,
458        additional_input: &[u8],
459        out: &mut K,
460    ) -> Result<usize, RNGError> {
461        let mut ret: Result<usize, RNGError> = Ok(0);
462        do_hazardous_operations(out, |out| {
463            let out_ref = out.ref_to_bytes_mut()?;
464            ret = self.generate_out(additional_input, out_ref);
465            Ok(())
466        })?;
467
468        let bytes_written = match ret {
469            Err(e) => return Err(e),
470            Ok(bytes_written) => bytes_written,
471        };
472
473        do_hazardous_operations(out, |out| {
474            out.set_key_len(bytes_written)?;
475            out.set_key_type(KeyType::CryptographicRandom)?;
476            let new_security_strength =
477                min(&self.admin_info.strength, &SecurityStrength::from_bits(bytes_written * 8))
478                    .clone();
479            out.set_security_strength(new_security_strength)?;
480            Ok(())
481        })?;
482        Ok(bytes_written)
483    }
484}
485
486impl<H: HashDRBG80090AParams> RNG for HashDRBG80090A<H> {
487    // TODO: add this back once we figure out how to handle a streaming-style reseed.
488    // fn add_seed_bytes(&mut self, additional_seed: &[u8]) -> Result<(), RNGError> {
489    //     if !self.admin_info.instantiated { return Err(RNGError::Uninitialized) }
490    //
491    //     todo!()
492    // }
493
494    fn add_seed_keymaterial(
495        &mut self,
496        additional_seed: &dyn KeyMaterialTrait,
497    ) -> Result<(), RNGError> {
498        self.reseed(additional_seed, "add_seed_keymaterial".as_bytes())
499    }
500
501    fn next_int(&mut self) -> Result<u32, RNGError> {
502        let mut out = [0u8; 4];
503        self.generate_out("next_int".as_bytes(), &mut out)?;
504        Ok(u32::from_le_bytes(out))
505    }
506
507    fn next_bytes(&mut self, len: usize) -> Result<Vec<u8>, RNGError> {
508        self.generate("next_bytes".as_bytes(), len)
509    }
510
511    fn next_bytes_out(&mut self, out: &mut [u8]) -> Result<usize, RNGError> {
512        out.fill(0);
513
514        self.generate_out("next_bytes_out".as_bytes(), out)
515    }
516
517    fn fill_keymaterial_out(&mut self, out: &mut dyn KeyMaterialTrait) -> Result<usize, RNGError> {
518        self.generate_keymaterial_out("fill_keymaterial".as_bytes(), out)
519    }
520
521    fn security_strength(&self) -> SecurityStrength {
522        self.admin_info.strength.clone()
523    }
524}
525
526/*** Internal Helper Functions ***/
527
528/// the hash_df function as defined in SP 800-90Ar1 section 10.3.1.
529/// no_of_bits_to_return is the length of the provided output buffer.
530/// Because array concatenation is not available in a no_std / no_alloc build, this takes many input parameters. 
531// To leave a parameter unused, simply provide an empty array &[0u8;0]
532fn hash_df<H: Hash + HashAlgParams + Default>(
533    in1: &[u8],
534    in2: &[u8],
535    in3: &[u8],
536    in4: &[u8],
537    out: &mut [u8],
538) {
539    // Note: all lengths here are in bytes, whereas the spec uses bits.
540
541    // The implementation panic! here because this is private and shouldn't get into weird inputs.
542    if out.len() > 255 * H::OUTPUT_LEN {
543        panic!("hash_df can't produce that much output!")
544    }
545
546    out.fill(0);
547
548    // out is "temp" in SP 800-90Ar1
549    let no_of_bits_to_return: u32 = (out.len() * 8) as u32;
550    let len = u32::div_ceil(out.len() as u32, H::OUTPUT_LEN as u32);
551    let mut counter: u8 = 0x01;
552
553    // note: this could probably be performance optimized a tiny bit by pulling no_of_bits_to_return.to_le_bytes() 
554    // out of the loop and by merging i and counter into the same variable.
555    for i in 1..len {
556        let mut h = H::default();
557        h.do_update(&counter.to_le_bytes());
558        h.do_update(&no_of_bits_to_return.to_le_bytes());
559        h.do_update(in1);
560        h.do_update(in2);
561        h.do_update(in3);
562        h.do_update(in4);
563        h.do_final_out(&mut out[((i - 1) as usize) * H::OUTPUT_LEN..(i as usize) * H::OUTPUT_LEN]);
564
565        counter += 1;
566    }
567
568    // Handle the last block separately since not all of it will fit in the output buffer.
569    // TODO: Check whether it is necessary to do a last block, 
570    // or was the requested number of bits already a multiple of the output length
571    let bytes_written = (len - 1) as usize * H::OUTPUT_LEN;
572    let remainder = out.len() - bytes_written;
573    if remainder != 0 {
574        let mut h = H::default();
575        h.do_update(&counter.to_le_bytes());
576        h.do_update(&no_of_bits_to_return.to_le_bytes());
577        h.do_update(in1);
578        h.do_update(in2);
579        h.do_update(in3);
580        h.do_update(in4);
581
582        // let mut temp = [0u8; H::OUTPUT_LEN];
583        let mut temp = [0u8; 64];
584        h.do_final_out(&mut temp);
585
586        // Copy only what we need from the last block.
587        out[bytes_written..].copy_from_slice(&temp[..remainder]);
588    }
589}
590
591#[test]
592fn test_hash_df() {
593    // success case
594    let mut out = [0u8; 100];
595    hash_df::<SHA256>(&[0x01, 0x02, 0x03], &[0x04, 0x05], &[0x06, 0x07], &[0x08, 0x09], &mut out);
596    assert_ne!(out, [0u8; 100]);
597    // repeatability test
598    // println!("out: {:?}", out);
599    assert_eq!(
600        out,
601        [
602            150u8, 177u8, 87u8, 145u8, 138u8, 4u8, 164u8, 14u8, 162u8, 43u8, 159u8, 152u8, 121u8,
603            117u8, 6u8, 18u8, 253u8, 84u8, 41u8, 64u8, 40u8, 209u8, 16u8, 176u8, 106u8, 115u8,
604            172u8, 193u8, 246u8, 228u8, 208u8, 79u8, 37u8, 31u8, 134u8, 141u8, 200u8, 7u8, 42u8,
605            199u8, 229u8, 236u8, 236u8, 186u8, 28u8, 87u8, 200u8, 14u8, 127u8, 36u8, 132u8, 23u8,
606            36u8, 150u8, 23u8, 215u8, 247u8, 121u8, 175u8, 82u8, 99u8, 187u8, 235u8, 25u8, 213u8,
607            18u8, 106u8, 22u8, 4u8, 99u8, 1u8, 184u8, 211u8, 160u8, 177u8, 67u8, 78u8, 181u8, 69u8,
608            51u8, 117u8, 2u8, 72u8, 36u8, 134u8, 72u8, 2u8, 9u8, 105u8, 149u8, 136u8, 35u8, 81u8,
609            114u8, 142u8, 80u8, 94u8, 42u8, 85u8, 155
610        ]
611    );
612
613    // Test success with out.len() at the maximum allowed for SHA256 (255 * 32 = 8160)
614    let mut out_max_sha256 = vec![0u8; 255 * 32];
615    hash_df::<SHA256>(&[0x01], &[0x02], &[0x03], &[0x04], &mut out_max_sha256);
616    assert_ne!(out_max_sha256, vec![0u8; 255 * 32]);
617
618    // Test panic with out.len() exceeding the maximum for SHA256
619    let mut out_too_large_sha256 = vec![0u8; 255 * 32 + 1];
620    let result_sha256 = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
621        hash_df::<SHA256>(&[0x01], &[0x02], &[0x03], &[0x04], &mut out_too_large_sha256);
622    }));
623    assert!(result_sha256.is_err());
624
625    // Test success with out.len() at the maximum allowed for SHA512 (255 * 64 = 16320)
626    let mut out_max_sha512 = vec![0u8; 255 * 64];
627    hash_df::<SHA512>(&[0x01], &[0x02], &[0x03], &[0x04], &mut out_max_sha512);
628    assert_ne!(out_max_sha512, vec![0u8; 255 * 64]);
629    // make sure the last block got written to
630    assert_ne!(out_max_sha512[254 * 64..], [0u8; 64]);
631
632    // Test panic with out.len() exceeding the maximum for SHA512
633    let mut out_too_large_sha512 = vec![0u8; 255 * 64 + 1];
634    let result_sha512 = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
635        hash_df::<SHA512>(&[0x01], &[0x02], &[0x03], &[0x04], &mut out_too_large_sha512);
636    }));
637    assert!(result_sha512.is_err());
638}
639
640fn hashgen<H: Hash + HashAlgParams + Default>(v: &[u8], out: &mut [u8]) {
641    // Hashgen Process:
642    // 1. m = ceil(requested_no_of_bits / outlen)
643    // 2. data = V.
644    // 3. W = the Null string.
645    // 4. For i = 1 to m
646    //   4.1 w = Hash (data).
647    //   4.2 W = W || w.
648    //   4.3 data = (data + 1) mod 2^seedlen.
649    // 5. returned_bits = leftmost (W, requested_no_of_bits).
650    // 6. Return (returned_bits).
651
652    // 1. m = ceil(requested_no_of_bits / outlen)
653    out.fill(0);
654
655    let m = u32::div_ceil(out.len() as u32, H::OUTPUT_LEN as u32);
656
657    // requested_no_of_bits = out.len()
658    // let mut data= [0u8; H::OUTPUT_LEN];
659    let mut data = [0u8; 64];
660    data.copy_from_slice(v);
661    // W = out
662
663    // 4. For i = 1 to m
664    //   4.1 w = Hash (data).
665    //   4.2 W = W || w.
666    //   4.3 data = (data + 1) mod 2^seedlen.
667    for i in 1..m {
668        H::default().hash_out(
669            &data,
670            &mut out[((i - 1) as usize) * H::OUTPUT_LEN..(i as usize) * H::OUTPUT_LEN],
671        );
672        add_to_array(&mut data, &[0x01]);
673    }
674
675    // Handle the last block separately since not all of it will fit in the output buffer.
676    // TODO: Check whether it is necessary to do a last block, 
677    // or was the requested number of bits already a multiple of the output length
678    let bytes_written = (m - 1) as usize * H::OUTPUT_LEN;
679    let remainder = out.len() - bytes_written;
680    if remainder != 0 {
681        // let mut temp = [0u8; H::OUTPUT_LEN];
682        let mut temp = [0u8; 64];
683        H::default().hash_out(&data, &mut temp);
684
685        // Copy only what we need from the last block.
686        out[bytes_written..].copy_from_slice(&temp[..remainder as usize]);
687    }
688}
689
690/// This will always add the shorter length byte array mathematically to the
691/// longer length byte array.
692/// Mathematically, this is
693///   longer + shorter (mod longer.len())
694/// Be careful....
695fn add_to_array(longer: &mut [u8], shorter: &[u8]) {
696    if shorter.len() > longer.len() {
697        panic!("add_to_array: shorter array is longer than longer array!")
698    }
699
700    let mut carry: u8 = 0;
701
702    // Add the overlapping portion
703    for i in 1..=shorter.len() {
704        let res = (longer[longer.len() - i] as u16)
705            + (shorter[shorter.len() - i] as u16)
706            + (carry as u16);
707        carry = if res > 0xFF { 1 } else { 0 };
708        longer[longer.len() - i] = res as u8;
709    }
710
711    // Propagate carry through the remaining bytes
712    for i in (shorter.len() + 1)..=longer.len() {
713        let res = (longer[longer.len() - i] as u16) + (carry as u16);
714        carry = if res > 0xFF { 1 } else { 0 };
715        longer[longer.len() - i] = res as u8;
716    }
717}
718
719#[test]
720fn test_add_to_array() {
721    let mut longer = [0x0F, 0xFF, 0xFF, 0xFF];
722    let shorter = [0x01];
723    add_to_array(&mut longer, &shorter);
724    assert_eq!(longer, [0x10, 0x00, 0x00, 0x00]);
725
726    let mut longer = [0x0F, 0xFF, 0xFE, 0xFE];
727    let shorter = [0x01];
728    add_to_array(&mut longer, &shorter);
729    assert_eq!(longer, [0x0F, 0xFF, 0xFE, 0xFF]);
730
731    let mut longer = [0x0F, 0xFF, 0xFE, 0xFF];
732    let shorter = [0x01];
733    add_to_array(&mut longer, &shorter);
734    assert_eq!(longer, [0x0F, 0xFF, 0xFF, 0x00]);
735
736    let mut longer = [0x1F, 0xFF, 0xFF, 0xFF];
737    let shorter = [0xE0, 0x00, 0x00, 0x02];
738    add_to_array(&mut longer, &shorter);
739    assert_eq!(longer, [0x00, 0x00, 0x00, 0x01]);
740
741    let mut longer = [0xFF];
742    let shorter = [0x01];
743    add_to_array(&mut longer, &shorter);
744    assert_eq!(longer, [0x00]);
745
746    let mut longer = [0x00, 0x01];
747    let shorter = [0xFF];
748    add_to_array(&mut longer, &shorter);
749    assert_eq!(longer, [0x01, 0x00]);
750
751    let mut longer = [0x00, 0x00, 0xFF];
752    let shorter = [0x00, 0x01];
753    add_to_array(&mut longer, &shorter);
754    assert_eq!(longer, [0x00, 0x01, 0x00]);
755
756    let mut longer = [0x00, 0x00, 0xFF];
757    let shorter = [0x0C, 0x01];
758    add_to_array(&mut longer, &shorter);
759    assert_eq!(longer, [0x00, 0x0D, 0x00]);
760
761    let mut longer = [0x00, 0xFF];
762    let shorter = [0x00, 0x01];
763    add_to_array(&mut longer, &shorter);
764    assert_eq!(longer, [0x01, 0x00]);
765
766    let mut longer = [0x00, 0x00, 0xFF];
767    let shorter = [0x00, 0x0C, 0x01];
768    add_to_array(&mut longer, &shorter);
769    assert_eq!(longer, [0x00, 0x0D, 0x00]);
770
771    let mut longer = [0x00, 0x00, 0xFF];
772    let shorter = [0x00, 0x0F, 0x01];
773    add_to_array(&mut longer, &shorter);
774    assert_eq!(longer, [0x00, 0x10, 0x00]);
775
776    let mut longer = [0x00, 0x00, 0xFC];
777    let shorter = [0x00, 0x0F, 0x01];
778    add_to_array(&mut longer, &shorter);
779    assert_eq!(longer, [0x00, 0x0F, 0xFD]);
780
781    let mut longer = [0x00, 0x0F, 0xFC];
782    let shorter = [0x00, 0x1F, 0x01];
783    add_to_array(&mut longer, &shorter);
784    assert_eq!(longer, [0x00, 0x2E, 0xFD]);
785}