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_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
21// By not making this pub, nobody else should be able to impl it;
22// ie the structs defined below will be the only allowed ones.
23trait HashDRBG80090AParams {
24    const HASH: SupportedHash;
25    // const OUT_LEN: usize;
26    const MAX_SECURITY_STRENGTH: SecurityStrength;
27    // const SEED_LEN: usize;
28    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 OUT_LEN: usize = 64;
41    const MAX_SECURITY_STRENGTH: SecurityStrength = SecurityStrength::_128bit;
42    // const SEED_LEN: usize = 440 / 8;
43    const MAX_LENGTH: u64 = (1u64 << 35) / 8; // 2^35 bits
44    const MAX_PERSONALIZATION_STRING_LENGTH: u64 = (1u64 << 35) / 8; // 2^35 bits
45    const MAX_ADDITIONAL_INPUT_LENGTH: u64 = (1u64 << 35) / 8; // 2^35 bits
46    const MAX_NUMBER_OF_BITS_PER_REQUEST: u64 = (1u64 << 19) / 8; // 2^19 bits
47    const RESEED_INTERVAL: u64 = 1u64 << 48; // 2^48 requests
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 OUT_LEN: usize = 64;
55    const MAX_SECURITY_STRENGTH: SecurityStrength = SecurityStrength::_256bit;
56    // const SEED_LEN: usize = 888 / 8;
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: is there a rustacious way to extract this from HASH?
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    // Rust is stupid. What's the point of having a generic parameter if we can't use constants inside it?
71    // state: WorkingState<H::SEED_LEN>,
72    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    /// s 8.3: "A count of the number of requests produced since the instantiation was seeded or reseeded."
81    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        // zeroize
93        self.v.fill(0u8);
94        self.c.fill(0u8);
95        self.reseed_counter = 0;
96    }
97}
98
99/// Explicit implementation of Display that prevents auto-generated ones from accidentally leaking secrets.
100impl<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]
107/// impl Display to not print the state data.
108fn 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    /// Creates a new instance using the local OS RNG as a source of seed entropy.
115    /// Alias for [HashDRBG80090A::new_from_os].
116    pub fn new() -> Self {
117        Self::new_from_os()
118    }
119
120    /// Creates a new, uninstantiated instance. After creating it, you must call instantiate() to seed it.
121    ///
122    /// **WARNING: Dangerous! This constructor does not initialize the DRBG from any entropy source,
123    /// and relies on you to provide a strong seed.**
124    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    /// Creates a new instance using the local OS RNG as a source of seed entropy.
140    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    /// Creates a new instance using the local OS RNG as a source of seed entropy.
166    /// Alias for [HashDRBG80090A::new_from_os].
167    fn default() -> Self {
168        Self::new_from_os()
169    }
170}
171
172impl<H: HashDRBG80090AParams> Sp80090ADrbg for HashDRBG80090A<H> {
173    /// Output:
174    /// 1. initial_working_state: The initial values for V, C, and reseed_counter (see Section 10.1.1.1).
175    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        // Hash_DRBG Instantiate Process:
184        // 1. seed_material = entropy_input || nonce || personalization_string.
185        // 2. seed = Hash_df (seed_material, seedlen).
186        // 3. V = seed.
187        // 4. C = Hash_df ((0x00 || V), seedlen). Comment: Precede V with a byte of zeros.
188        // 5. reseed_counter = 1.
189        // 6. Return (V, C, reseed_counter).
190
191        if self.admin_info.instantiated {
192            return Err(RNGError::GenericError(
193                "This DRBG instance has already been instantiated.",
194            ));
195        }
196
197        // todo: take this out once supported
198        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        // 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.
223        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        // 1. seed_material = entropy_input || nonce || personalization_string.
230        // 2. seed = Hash_df (seed_material, seedlen).
231        // 3. V = seed.
232        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        // 4. C = Hash_df ((0x00 || V), seedlen). Comment: Precede V with a byte of zeros.
250        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        // 5. reseed_counter = 1.
260        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        // 6. Return (V, C, reseed_counter).
266        Ok(())
267    }
268
269    fn reseed(&mut self, seed: &impl KeyMaterial, additional_input: &[u8]) -> Result<(), RNGError> {
270        // Hash_DRBG Reseed Process:
271        // 1. seed_material = 0x01 || V || entropy_input || additional_input.
272        // 2. seed = Hash_df (seed_material, seedlen).
273        // 3. V = seed.
274        // 4. C = Hash_df ((0x00 || V), seedlen). Comment: Preceed with a byte of all zeros.
275        // 5. reseed_counter = 1.
276        // 6. Return (V, C, and reseed_counter).
277
278        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        // 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.
293
294        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        // 1. seed_material = 0x01 || V || entropy_input || additional_input.
306        // 2. seed = Hash_df (seed_material, seedlen).
307        // 3. V = seed.
308        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        // 4. C = Hash_df ((0x00 || V), seedlen). Comment: Preceed with a byte of all zeros.
326        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        // 5. reseed_counter = 1.
336        self.state.reseed_counter = 1;
337
338        // 6. Return (V, C, and reseed_counter).
339        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        // Hash_DRBG_Generate Process:
350        // 1. If reseed_counter > reseed_interval, then return an indication that a reseed is required.
351        // 2. If (additional_input ≠ Null), then do
352        //   2.1 w = Hash (0x02 || V || additional_input).
353        //   2.2 V = (V + w) mod 2^seedlen.
354        // 3. (returned_bits) = Hashgen (requested_number_of_bits, V).
355        // 4. H = Hash (0x03 || V).
356        // 5. V = (V + H + C + reseed_counter) mod 2^seedlen.
357        // 6. reseed_counter = reseed_counter + 1.
358        // 7. Return (SUCCESS, returned_bits, V, C, reseed_counter).
359
360        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        // 1. If reseed_counter > reseed_interval, then return an indication that a reseed is required.
375        if self.state.reseed_counter > H::RESEED_INTERVAL {
376            return Err(RNGError::ReseedRequired);
377        }
378
379        // 2. If (additional_input ≠ Null), then do
380        //   2.1 w = Hash (0x02 || V || additional_input).
381        //   2.2 V = (V + w) mod 2^seedlen.
382        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        // 3. (returned_bits) = Hashgen (requested_number_of_bits, V).
408        if out.len() > 0 {
409            // If zero bytes of output is requested, we can skip the hashgen step because this step
410            // is purely producing output and has no side-effect on the state.
411            // But we do want to continue below to roll the state and increment the request counter.
412            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        // 4. H = Hash (0x03 || V).
423        // let mut h = [0u8; H::OUT_LEN];
424        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        // 5. V = (V + H + C + reseed_counter) mod 2^seedlen.
441        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        // 6. reseed_counter = reseed_counter + 1.
446        self.state.reseed_counter += 1;
447
448        // 7. Return (SUCCESS, returned_bits, V, C, reseed_counter).
449        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    // TODO: add this back once we figure out how to handle a streaming-style reseed.
472    // fn add_seed_bytes(&mut self, additional_seed: &[u8]) -> Result<(), RNGError> {
473    //     if !self.admin_info.instantiated { return Err(RNGError::Uninitialized) }
474    //
475    //     todo!()
476    // }
477
478    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
505/*** Internal Helper Functions ***/
506
507/// the hash_df function as defined in SP 800-90Ar1 section 10.3.1.
508/// no_of_bits_to_return is the length of the provided output buffer.
509/// Because array concatenation is not available in a no_std / no_alloc build, this takes many input parameters. To leave a parameter unused, simply provide an empty array &[0u8;0]
510fn hash_df<H: Hash + HashAlgParams + Default>(
511    in1: &[u8],
512    in2: &[u8],
513    in3: &[u8],
514    in4: &[u8],
515    out: &mut [u8],
516) {
517    // Note: all lengths here are in bytes, whereas the spec uses bits.
518
519    // // I'm gonna panic! here because this is private and shouldn't get into weird inputs.
520    if out.len() > 255 * H::OUTPUT_LEN {
521        panic!("hash_df can't produce that much output!")
522    }
523
524    // out is "temp" in SP 800-90Ar1
525    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    // note: this could probably be performance optimized a tiny bit by pulling no_of_bits_to_return.to_le_bytes() out of the loop
530    // and by merging i and counter into the same variable.
531    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    // Handle the last block separately since not all of it will fit in the output buffer.
545    // First, do we even need to do a last block, or was the requested number of bits already a multiple of the output length?
546    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        // I don't understand rust
558        // let mut temp = [0u8; H::OUTPUT_LEN];
559        let mut temp = [0u8; 64];
560        h.do_final_out(&mut temp);
561
562        // Copy only what we need from the last block.
563        out[bytes_written..].copy_from_slice(&temp[..remainder]);
564    }
565}
566
567#[test]
568fn test_hash_df() {
569    // success case
570    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    // repeatability test
574    // println!("out: {:?}", out);
575    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    // Test success with out.len() at the maximum allowed for SHA256 (255 * 32 = 8160)
578    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    // Test panic with out.len() exceeding the maximum for SHA256
583    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    // Test success with out.len() at the maximum allowed for SHA512 (255 * 64 = 16320)
590    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    // make sure the last block got written to
594    assert_ne!(out_max_sha512[254 * 64..], [0u8; 64]);
595
596    // Test panic with out.len() exceeding the maximum for SHA512
597    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    // Hashgen Process:
606    // 1. m = ceil(requested_no_of_bits / outlen)
607    // 2. data = V.
608    // 3. W = the Null string.
609    // 4. For i = 1 to m
610    //   4.1 w = Hash (data).
611    //   4.2 W = W || w.
612    //   4.3 data = (data + 1) mod 2^seedlen.
613    // 5. returned_bits = leftmost (W, requested_no_of_bits).
614    // 6. Return (returned_bits).
615
616    // 1. m = ceil(requested_no_of_bits / outlen)
617    let m = u32::div_ceil(out.len() as u32, H::OUTPUT_LEN as u32);
618
619    // requested_no_of_bits = out.len()
620    // let mut data= [0u8; H::OUTPUT_LEN];
621    let mut data = [0u8; 64];
622    data.copy_from_slice(v);
623    // W = out
624
625    // 4. For i = 1 to m
626    //   4.1 w = Hash (data).
627    //   4.2 W = W || w.
628    //   4.3 data = (data + 1) mod 2^seedlen.
629    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    // Handle the last block separately since not all of it will fit in the output buffer.
638    // First, do we even need to do a last block, or was the requested number of bits already a multiple of the output length?
639    let bytes_written = (m - 1) as usize * H::OUTPUT_LEN;
640    let remainder = out.len() - bytes_written;
641    if remainder != 0 {
642        // I don't understand rust
643        // let mut temp = [0u8; H::OUTPUT_LEN];
644        let mut temp = [0u8; 64];
645        H::default().hash_out(&data, &mut temp);
646
647        // Copy only what we need from the last block.
648        out[bytes_written..].copy_from_slice(&temp[..remainder as usize]);
649    }
650}
651
652/// This will always add the shorter length byte array mathematically to the
653/// longer length byte array.
654/// Mathematically, this is
655///   longer + shorter (mod longer.len())
656/// Be careful....
657fn 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    // Add the overlapping portion
665    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    // Propagate carry through the remaining bytes
674    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}