hbs_lms/lib.rs
1#![forbid(unsafe_code)]
2#![cfg_attr(not(feature = "std"), no_std)]
3
4//! This library implements the Leighton-Micali-Signature scheme, as defined in the
5//! [RFC 8554](<https://datatracker.ietf.org/doc/html/rfc8554>).
6//!
7//! It is a post-quantum secure algorithm that can be used to
8//! generate digital signatures. NIST has published recommendations for this algorithm in:
9//! [NIST Recommendations for Stateful Hash-Based Signatures](https://doi.org/10.6028/NIST.SP.800-208)
10//!
11//! This crate can be used together with the [`signature::SignerMut`] and [`signature::Verifier`] traits.
12//!
13//! # Example
14//! ```
15//! use rand::{rngs::OsRng, RngCore};
16//! use tinyvec::ArrayVec;
17//! use hbs_lms::{keygen, HssParameter, LmotsAlgorithm, LmsAlgorithm,
18//! Signature, signature::{SignerMut, Verifier},
19//! Sha256_256, HashChain, Seed,
20//! };
21//!
22//! let message: [u8; 7] = [42, 84, 34, 12, 64, 34, 32];
23//!
24//! // Generate keys for a 2-level HSS system (RootTree W1/H5, ChildTree W2/H5)
25//! let hss_parameter = [
26//! HssParameter::<Sha256_256>::new(LmotsAlgorithm::LmotsW1, LmsAlgorithm::LmsH5),
27//! HssParameter::<Sha256_256>::new(LmotsAlgorithm::LmotsW2, LmsAlgorithm::LmsH5),
28//! ];
29//!
30//! let mut seed = Seed::default();
31//! OsRng.fill_bytes(seed.as_mut_slice());
32//! let aux_data = None;
33//!
34//! let (mut signing_key, verifying_key) =
35//! hbs_lms::keygen::<Sha256_256>(&hss_parameter, &seed, aux_data).unwrap();
36//!
37//! let signature = signing_key.try_sign(&message).unwrap();
38//!
39//! let valid_signature = verifying_key.verify(&message, &signature);
40//!
41//! assert_eq!(valid_signature.is_ok(), true);
42//! ```
43//!
44//! # Environment Variables
45//!
46//! To adapt the internals of the crate, the user can set the following environment variables:
47//!
48//! ## Adapting the crate in general
49//!
50//! These three environment variables listed below, adapt the internals of the crate and can be used
51//! to reduce the required stack size. The values are used to set the maximum size of the arrays
52//! used for computation and storing intermediate values.
53//!
54//! Any change limits the functionality of this crate, as no longer all possible parameters are
55//! supported! (For example setting `HBS_LMS_MAX_ALLOWED_HSS_LEVELS` to 1 allows only for a single
56//! tree.)
57//!
58//! The length of the tree height and the winternitz parameter arrays must match the value of the
59//! HSS levels.
60//!
61//! | Name | Default | Range of Values | Description |
62//! |--------------------------------|---------|--------------------|-------------------------|
63//! | HBS_LMS_MAX_ALLOWED_HSS_LEVELS | 8 | 1..8 | Max. tree count for HSS |
64//! | HBS_LMS_TREE_HEIGHTS | [25; 8] | [`LmsAlgorithm`] | Max. Tree Height for each tree|
65//! | HBS_LMS_WINTERNITZ_PARAMETERS | [1; 8] | [`LmotsAlgorithm`] | Min. Winternitz Parameter for each tree |
66//!
67//! Reducing the HSS levels or the values of the tree heights lead to a reduced stack usage. For the
68//! values of the Winternitz parameter the inverse must be applied, as higher Winternitz parameters
69//! reduce the stack usage.
70//!
71//! ## Adapting wrt the 'fast_verify' feature
72//!
73//! The 'fast_verify' features enables this crate to sign fast verifiable signatures. The drawback
74//! is more computative effort on the side of the signer. With the these two environment variables
75//! listed below, the user can adapt effect.
76//!
77//! | Name | Default | Description |
78//! |--------------------------------|---------|----------------------------------|
79//! | HBS_LMS_MAX_HASH_OPTIMIZATIONS | 10_000 | Try count to optimize the hash |
80//! | HBS_LMS_THREADS | 1 | Thread count to split the effort |
81//!
82//! If the crate is compiled with the std library, the effort of the generation of fast verifiable
83//! signatures can be split to multiple threads using the `HBS_LMS_THREADS`.
84
85extern crate core;
86
87mod constants;
88mod hasher;
89mod hss;
90mod lm_ots;
91mod lms;
92mod util;
93
94// Re-export the `signature` crate
95pub use signature::{self};
96
97#[doc(hidden)]
98pub use crate::constants::MAX_HASH_SIZE;
99#[doc(hidden)]
100pub use crate::hss::reference_impl_private_key::Seed;
101
102pub use crate::hasher::{
103 sha256::{Sha256_128, Sha256_192, Sha256_256},
104 shake256::{Shake256_128, Shake256_192, Shake256_256},
105 HashChain, HashChainData,
106};
107
108pub use crate::hss::parameter::HssParameter;
109pub use crate::lm_ots::parameters::LmotsAlgorithm;
110pub use crate::lms::parameters::LmsAlgorithm;
111
112pub use crate::hss::hss_keygen as keygen;
113pub use crate::hss::hss_sign as sign;
114#[cfg(feature = "fast_verify")]
115pub use crate::hss::hss_sign_mut as sign_mut;
116pub use crate::hss::hss_verify as verify;
117pub use crate::hss::{SigningKey, VerifyingKey};
118
119use core::convert::TryFrom;
120use signature::Error;
121use tinyvec::ArrayVec;
122
123use constants::MAX_HSS_SIGNATURE_LENGTH;
124
125/**
126 * Implementation of [`signature::Signature`].
127 */
128#[derive(Debug)]
129pub struct Signature {
130 bytes: ArrayVec<[u8; MAX_HSS_SIGNATURE_LENGTH]>,
131 #[cfg(feature = "verbose")]
132 pub hash_iterations: u32,
133}
134
135impl Signature {
136 pub(crate) fn from_bytes_verbose(bytes: &[u8], _hash_iterations: u32) -> Result<Self, Error> {
137 let bytes = ArrayVec::try_from(bytes).map_err(|_| Error::new())?;
138
139 Ok(Self {
140 bytes,
141 #[cfg(feature = "verbose")]
142 hash_iterations: _hash_iterations,
143 })
144 }
145}
146
147impl AsRef<[u8]> for Signature {
148 fn as_ref(&self) -> &[u8] {
149 self.bytes.as_ref()
150 }
151}
152
153impl signature::Signature for Signature {
154 fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
155 Signature::from_bytes_verbose(bytes, 0)
156 }
157}
158
159/**
160 * No-copy friendly alternative to [`Signature`] by using a reference to a slice of bytes (for
161 * verification only!).
162 */
163#[derive(Debug)]
164pub struct VerifierSignature<'a> {
165 bytes: &'a [u8],
166}
167
168#[allow(dead_code)]
169impl<'a> VerifierSignature<'a> {
170 pub fn from_ref(bytes: &'a [u8]) -> Result<Self, Error> {
171 Ok(Self { bytes })
172 }
173}
174
175impl<'a> AsRef<[u8]> for VerifierSignature<'a> {
176 fn as_ref(&self) -> &'a [u8] {
177 self.bytes
178 }
179}
180
181impl<'a> signature::Signature for VerifierSignature<'a> {
182 fn from_bytes(_bytes: &[u8]) -> Result<Self, Error> {
183 Err(Error::new())
184 }
185}
186
187#[cfg(test)]
188mod tests {
189 use crate::{keygen, HssParameter, LmotsAlgorithm, LmsAlgorithm, Sha256_256};
190 use crate::{
191 signature::{SignerMut, Verifier},
192 SigningKey, VerifierSignature, VerifyingKey,
193 };
194
195 use crate::util::helper::test_helper::gen_random_seed;
196
197 #[test]
198 fn get_signing_and_verifying_key() {
199 type H = Sha256_256;
200 let seed = gen_random_seed::<H>();
201
202 let (signing_key, verifying_key) = keygen::<H>(
203 &[HssParameter::new(
204 LmotsAlgorithm::LmotsW2,
205 LmsAlgorithm::LmsH5,
206 )],
207 &seed,
208 None,
209 )
210 .unwrap();
211
212 let _: SigningKey<H> = signing_key;
213 let _: VerifyingKey<H> = verifying_key;
214 }
215
216 #[test]
217 fn signature_trait() {
218 let message = [
219 32u8, 48, 2, 1, 48, 58, 20, 57, 9, 83, 99, 255, 0, 34, 2, 1, 0,
220 ];
221 type H = Sha256_256;
222 let seed = gen_random_seed::<H>();
223
224 let (mut signing_key, verifying_key) = keygen::<H>(
225 &[
226 HssParameter::new(LmotsAlgorithm::LmotsW2, LmsAlgorithm::LmsH5),
227 HssParameter::new(LmotsAlgorithm::LmotsW2, LmsAlgorithm::LmsH5),
228 ],
229 &seed,
230 None,
231 )
232 .unwrap();
233
234 let signature = signing_key.try_sign(&message).unwrap();
235
236 assert!(verifying_key.verify(&message, &signature).is_ok());
237
238 let ref_signature = VerifierSignature::from_ref(signature.as_ref()).unwrap();
239
240 assert!(verifying_key.verify(&message, &ref_signature).is_ok());
241 }
242}