Coverage Report

Created: 2025-11-16 06:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openssl35/crypto/slh_dsa/slh_xmss.c
Line
Count
Source
1
/*
2
 * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved.
3
 *
4
 * Licensed under the Apache License 2.0 (the "License").  You may not use
5
 * this file except in compliance with the License.  You can obtain a copy
6
 * in the file LICENSE in the source distribution or at
7
 * https://www.openssl.org/source/license.html
8
 */
9
10
#include <string.h>
11
#include "slh_dsa_local.h"
12
#include "slh_dsa_key.h"
13
14
/**
15
 * @brief Compute the root Public key of a XMSS tree.
16
 * See FIPS 205 Section 6.1 Algorithm 9.
17
 * This is a recursive function that starts at an leaf index, that calculates
18
 * the hash of each parent using 2 child nodes.
19
 *
20
 * @param ctx Contains SLH_DSA algorithm functions and constants.
21
 * @param sk_seed A SLH-DSA private key seed of size |n|
22
 * @param nodeid The index of the target node being computed
23
 *               (which must be < 2^(hm - height)
24
 * @param h The height within the tree of the node being computed.
25
 *          (which must be <= hm) (hm is one of 3, 4, 8 or 9)
26
 *          At height=0 There are 2^hm leaf nodes,
27
 *          and the root node is at height = hm)
28
 * @param pk_seed A SLH-DSA public key seed of size |n|
29
 * @param adrs An ADRS object containing the layer address and tree address set
30
 *             to the XMSS tree within which the XMSS tree is being computed.
31
 * @param pk_out The generated public key of size |n|
32
 * @param pk_out_len The maximum size of |pk_out|
33
 * @returns 1 on success, or 0 on error.
34
 */
35
int ossl_slh_xmss_node(SLH_DSA_HASH_CTX *ctx, const uint8_t *sk_seed,
36
                       uint32_t node_id, uint32_t h,
37
                       const uint8_t *pk_seed, uint8_t *adrs,
38
                       uint8_t *pk_out, size_t pk_out_len)
39
1.39M
{
40
1.39M
    const SLH_DSA_KEY *key = ctx->key;
41
1.39M
    SLH_ADRS_FUNC_DECLARE(key, adrsf);
42
43
1.39M
    if (h == 0) {
44
        /* For leaf nodes generate the public key */
45
716k
        adrsf->set_type_and_clear(adrs, SLH_ADRS_TYPE_WOTS_HASH);
46
716k
        adrsf->set_keypair_address(adrs, node_id);
47
716k
        if (!ossl_slh_wots_pk_gen(ctx, sk_seed, pk_seed, adrs,
48
716k
                                  pk_out, pk_out_len))
49
0
            return 0;
50
716k
    } else {
51
675k
        uint8_t lnode[SLH_MAX_N], rnode[SLH_MAX_N];
52
53
675k
        if (!ossl_slh_xmss_node(ctx, sk_seed, 2 * node_id, h - 1, pk_seed, adrs,
54
675k
                                lnode, sizeof(lnode))
55
675k
                || !ossl_slh_xmss_node(ctx, sk_seed, 2 * node_id + 1, h - 1,
56
675k
                                       pk_seed, adrs, rnode, sizeof(rnode)))
57
0
            return 0;
58
675k
        adrsf->set_type_and_clear(adrs, SLH_ADRS_TYPE_TREE);
59
675k
        adrsf->set_tree_height(adrs, h);
60
675k
        adrsf->set_tree_index(adrs, node_id);
61
675k
        if (!key->hash_func->H(ctx, pk_seed, adrs, lnode, rnode, pk_out, pk_out_len))
62
0
            return 0;
63
675k
    }
64
1.39M
    return 1;
65
1.39M
}
66
67
/**
68
 * @brief Generate an XMSS signature using a message and key.
69
 * See FIPS 205 Section 6.2 Algorithm 10
70
 *
71
 * The generated signature consists of:
72
 *  - A WOTS+ signature of size (2 * n + 3) * n
73
 *  - An array of authentication paths of size (XMSS tree_height) * n.
74
 *
75
 * @param ctx Contains SLH_DSA algorithm functions and constants.
76
 * @param msg A message of size |n| bytes to sign
77
 * @param sk_seed A private key seed of size |n|
78
 * @param node_id The index of a WOTS+ key within the XMSS tree to use for signing.
79
 * @param pk_seed A public key seed f size |n|
80
 * @param adrs An ADRS object containing the layer address and tree address set
81
 *              to the XMSS key being used to sign the message.
82
 * @param sig_wpkt A WPACKET object to write the generated XMSS signature to.
83
 * @returns 1 on success, or 0 on error.
84
 */
85
int ossl_slh_xmss_sign(SLH_DSA_HASH_CTX *ctx, const uint8_t *msg,
86
                       const uint8_t *sk_seed, uint32_t node_id,
87
                       const uint8_t *pk_seed, uint8_t *adrs, WPACKET *sig_wpkt)
88
10.5k
{
89
10.5k
    const SLH_DSA_KEY *key = ctx->key;
90
10.5k
    SLH_ADRS_FUNC_DECLARE(key, adrsf);
91
10.5k
    SLH_ADRS_DECLARE(tmp_adrs);
92
10.5k
    size_t n = key->params->n;
93
10.5k
    uint32_t h, hm = key->params->hm;
94
10.5k
    uint32_t id = node_id;
95
10.5k
    uint8_t *auth_path; /* Pointer to a buffer offset inside |sig_wpkt| */
96
10.5k
    size_t auth_path_len = n;
97
98
    /*
99
     * This code reverses the order of the FIPS 205 code so that it does the
100
     * sign first. This simplifies the WPACKET writing.
101
     */
102
10.5k
    adrsf->copy(tmp_adrs, adrs);
103
10.5k
    adrsf->set_type_and_clear(adrs, SLH_ADRS_TYPE_WOTS_HASH);
104
10.5k
    adrsf->set_keypair_address(adrs, node_id);
105
10.5k
    if (!ossl_slh_wots_sign(ctx, msg, sk_seed, pk_seed, adrs, sig_wpkt))
106
0
        return 0;
107
108
10.5k
    adrsf->copy(adrs, tmp_adrs);
109
50.2k
    for (h = 0; h < hm; ++h) {
110
39.7k
        if (!WPACKET_allocate_bytes(sig_wpkt, auth_path_len, &auth_path)
111
39.7k
                || !ossl_slh_xmss_node(ctx, sk_seed, id ^ 1, h, pk_seed, adrs,
112
39.7k
                                       auth_path, auth_path_len))
113
0
            return 0;
114
39.7k
        id >>= 1;
115
39.7k
    }
116
10.5k
    return 1;
117
10.5k
}
118
119
/**
120
 * @brief Compute a candidate XMSS public key from a message and XMSS signature
121
 * See FIPS 205 Section 6.3 Algorithm 11
122
 *
123
 * * The signature consists of:
124
 *  - A WOTS+ signature of size (2 * n + 3) * n
125
 *  - An array of authentication paths of size (XMSS tree height) * n.
126
 *
127
 * @param ctx Contains SLH_DSA algorithm functions and constants.
128
 * @param node_id Must be set to the |node_id| used in xmss_sign().
129
 * @param sig_rpkt A Packet to read a XMSS signature from.
130
 * @param msg A message of size |n| bytes
131
 * @param sk_seed A private key seed of size |n|
132
 * @param pk_seed A public key seed of size |n|
133
 * @param adrs An ADRS object containing a layer address and tree address of an
134
 *             XMSS key used for signing the message.
135
 * @param pk_out The returned candidate XMSS public key of size |n|.
136
 * @param pk_out_len The maximum size of |pk_out|.
137
 * @returns 1 on success, or 0 on error.
138
 */
139
int ossl_slh_xmss_pk_from_sig(SLH_DSA_HASH_CTX *ctx, uint32_t node_id,
140
                              PACKET *sig_rpkt, const uint8_t *msg,
141
                              const uint8_t *pk_seed, uint8_t *adrs,
142
                              uint8_t *pk_out, size_t pk_out_len)
143
20.4k
{
144
20.4k
    const SLH_DSA_KEY *key = ctx->key;
145
20.4k
    SLH_HASH_FUNC_DECLARE(key, hashf);
146
20.4k
    SLH_ADRS_FUNC_DECLARE(key, adrsf);
147
20.4k
    SLH_HASH_FN_DECLARE(hashf, H);
148
20.4k
    SLH_ADRS_FN_DECLARE(adrsf, set_tree_index);
149
20.4k
    SLH_ADRS_FN_DECLARE(adrsf, set_tree_height);
150
20.4k
    uint32_t k;
151
20.4k
    size_t n = key->params->n;
152
20.4k
    uint32_t hm = key->params->hm;
153
20.4k
    uint8_t *node = pk_out;
154
20.4k
    const uint8_t *auth_path; /* Pointer to buffer offset in |pkt_sig| */
155
156
20.4k
    adrsf->set_type_and_clear(adrs, SLH_ADRS_TYPE_WOTS_HASH);
157
20.4k
    adrsf->set_keypair_address(adrs, node_id);
158
20.4k
    if (!ossl_slh_wots_pk_from_sig(ctx, sig_rpkt, msg, pk_seed, adrs,
159
20.4k
                                   node, pk_out_len))
160
0
        return 0;
161
162
20.4k
    adrsf->set_type_and_clear(adrs, SLH_ADRS_TYPE_TREE);
163
164
97.0k
    for (k = 0; k < hm; ++k) {
165
76.6k
        if (!PACKET_get_bytes(sig_rpkt, &auth_path, n))
166
0
            return 0;
167
76.6k
        set_tree_height(adrs, k + 1);
168
76.6k
        if ((node_id & 1) == 0) { /* even */
169
38.1k
            node_id >>= 1;
170
38.1k
            set_tree_index(adrs, node_id);
171
38.1k
            if (!H(ctx, pk_seed, adrs, node, auth_path, node, pk_out_len))
172
0
                return 0;
173
38.4k
        } else { /* odd */
174
38.4k
            node_id = (node_id - 1) >> 1;
175
38.4k
            set_tree_index(adrs, node_id);
176
38.4k
            if (!H(ctx, pk_seed, adrs, auth_path, node, node, pk_out_len))
177
0
                return 0;
178
38.4k
        }
179
76.6k
    }
180
20.4k
    return 1;
181
20.4k
}