Skip to content

Commit acdd2c8

Browse files
slontist8m
authored andcommitted
Add SLH-DSA design document
Reviewed-by: Paul Dale <[email protected]> Reviewed-by: Viktor Dukhovni <[email protected]> Reviewed-by: Tim Hudson <[email protected]> (Merged from openssl#25882)
1 parent 6de4119 commit acdd2c8

File tree

2 files changed

+100
-1
lines changed

2 files changed

+100
-1
lines changed

CHANGES.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ OpenSSL 3.5
3939

4040
*Neil Horman*
4141

42-
* Add SLH-DSA as specified by FIPS 205.
42+
* Add SLH-DSA as specified in FIPS 205.
4343

4444
*Shane Lontis*
4545

doc/designs/slh-dsa.md

+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
SLH-DSA Design
2+
==============
3+
4+
This document covers OpenSSL specific SLH-DSA implementation details.
5+
FIPS 205 clearly states most of the requirements of SLH-DSA and has comprehensive
6+
pseudo code for all its algorithms.
7+
8+
SLH_DSA Parameters & Functions
9+
------------------------------
10+
11+
There are 12 different parameter sets in FIPS 205. (See Section 11)
12+
There are constants related to these, as well as there being a group of functions
13+
associated with each set.
14+
15+
The constants include things like hash sizes and tree heights.
16+
17+
OpenSSL will have 12 different key managers and 12 corresponding signature functions.
18+
The names used are of the form "SLH-DSA-SHA2-128s" and "SLH-DSA-SHAKE-128f".
19+
20+
There are 7 hash functions used. The algorithms using SHAKE have a much simpler
21+
set of 7 functions as they just use SHAKE-256 XOF (Even for the SHAKE-128 names).
22+
The SHA2 algorithms are much more complex and require HMAC, MGF1, and well as digests.
23+
There are 2 sets of functions for the SHA2 case.
24+
25+
Some of the hash functions use an ADRS object. This is 32 bytes for SHAKE algorithms
26+
and 22 bytes for SHA2. Because SHA2 used a compressed format the ADRS functions are
27+
different.
28+
29+
There are many functions required to implement the sign and verify paths, which include
30+
Merkle trees and WOTS+. The different functions normally call one of 2 of the
31+
7 hash functions, as well as calling ADRS functions to pass to the HASH functions.
32+
33+
Rather that duplicating this code 12 times for every function, instead a
34+
SLH_DSA_CTX object is created.
35+
This contains the HASH functions, the ADRS functions, and the parameter constants.
36+
It also contains pre fetched algorithms.
37+
38+
This SLH_DSA_CTX is then passed to all functions. This context is allocated in the
39+
providers SLH_DSA signature context.
40+
41+
SLH-DSA keys
42+
------------
43+
44+
SLH-DSA keys have 2 elements of size n for both the public and private keys.
45+
Since different algorithms have different key sizes, buffers of the maximum size
46+
will be used to hold the keys (since the keys are only a maximum of 64 bytes each)
47+
48+
struct slh_dsa_key_st {
49+
/* The public key consists of a SEED and ROOT values each of size |n| */
50+
uint8_t pub[SLH_DSA_MAX_KEYLEN];
51+
/* The private key consists of a SEED and PRF values of size |n| */
52+
uint8_t priv[SLH_DSA_MAX_KEYLEN];
53+
size_t key_len; /* This value is set to 2 * n if there is a public key */
54+
/* contains the algorithm name and constants such as |n| */
55+
const SLH_DSA_PARAMS *params;
56+
int has_priv; /* Set to 1 if there is a private key component */
57+
};
58+
59+
The fields 'key_len' and 'has_priv' are used to determine if a key has loaded
60+
the public and private key elements.
61+
The 'params' field is the parameter set which is resolved via the algorithm name.
62+
63+
The FIPS 205 the SLH_DSA private key contains the public key.
64+
In OpenSSL these components are stored separately, so there must always be a
65+
public key in order for the key to be valid.
66+
67+
The key generation process creates a private key and half of the public key
68+
using DRBG's. The public key root component is then computed based on these
69+
values. For ACVP testing these values are supplied as an ENTROPY parameter.
70+
It is assumed that from data will not deal with a partial public key, and if this
71+
is required the user should use the key generation operation.
72+
73+
Pure vs Pre Hashed Signature Generation
74+
----------------------------------------
75+
76+
The normal signing process (called Pure SLH-DSA Signature Generation)
77+
encodes the message internally as 0x00 || len(ctx) || ctx || message.
78+
where B<ctx> is some optional value of size 0x00..0xFF.
79+
80+
ACVP Testing requires the ability for the message to not be encoded also. This
81+
will be controlled by settable parameters.
82+
83+
Pre Hash SLH-DSA Signature Generation encode the message as
84+
0x01 || len(ctx) || ctx || digest_OID || H(message).
85+
The scenario that is stated that this is useful for is when this encoded message
86+
is supplied from an external source.
87+
88+
Currently I do not support the Pre Hash variant as this does not sit well with the
89+
OpenSSL API's. The user could do the encoding themselves and then set the settable
90+
to not encode the passed in message.
91+
92+
Buffers
93+
-------
94+
95+
Many functions need to pass around key elements and return signature buffers of
96+
various sizes which are often updated in loops in parts, all of these sizes
97+
are known quantities. Currently there is no attempt to use wpacket to pass
98+
around these sizes. asserts are currently done by the child functions to check
99+
that the expected size does not exceed the size passed in by the parent.

0 commit comments

Comments
 (0)