hash_based_signatures/signature/winternitz/
d.rs

1use anyhow::{anyhow, Error, Result};
2
3/// Wrapper around the parameter "d" used for `domination_free_function`
4#[derive(Clone, Copy)]
5pub struct D {
6    pub d: u64,
7    log_log_d_plus_1: usize,
8}
9
10impl D {
11    /// Wraps a value for `d`.
12    ///
13    /// # Panics
14    /// Panics if `d` is not of the form 2^(2^x) - 1.
15    /// Consider using `D::try_from()`.
16    pub fn new(d: u64) -> Self {
17        D::try_from(d).unwrap()
18    }
19
20    /// The number of bits that are combined into one integer value
21    pub fn bits_to_combine(&self) -> usize {
22        1 << self.log_log_d_plus_1
23    }
24
25    /// The number of bits of the "checksum" c
26    pub fn bits_c(&self) -> usize {
27        // The maximal value of c is d * n0,
28        // and this is the number of bits of (d + 1) * n0:
29        // log2((d + 1) * n0)
30        // = log2(d + 1) + log2(n0)
31        // = bits_to_combine + log2(256 / bits_to_combine)
32        // = bits_to_combine + 8 + log2_bits_to_combine
33        let bits_c = self.bits_to_combine() + 8 - self.log_log_d_plus_1;
34
35        // Round up to the next factor of bits_to_combine
36        let bits_c = (((bits_c as f32) / (self.bits_to_combine() as f32)).ceil() as usize)
37            * self.bits_to_combine();
38        bits_c
39    }
40
41    /// Size of the resulting Winternitz signature / key
42    pub fn signature_and_key_size(&self) -> usize {
43        (256 + self.bits_c()) / self.bits_to_combine()
44    }
45}
46
47impl TryFrom<u64> for D {
48    type Error = Error;
49
50    fn try_from(d: u64) -> Result<D> {
51        let log_log_d_plus_1 = ((d + 1) as f64).log2().log2() as usize;
52        if d + 1 != (1 << (1 << log_log_d_plus_1)) {
53            Err(anyhow!(
54                "d is not of the form 2^(2^x) - 1! Try one of 1, 3, 15, or 255."
55            ))
56        } else {
57            Ok(D {
58                d,
59                log_log_d_plus_1,
60            })
61        }
62    }
63}