Coverage Report

Created: 2026-03-31 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/blst/src/keygen.c
Line
Count
Source
1
/*
2
 * Copyright Supranational LLC
3
 * Licensed under the Apache License, Version 2.0, see LICENSE for details.
4
 * SPDX-License-Identifier: Apache-2.0
5
 */
6
7
#include "consts.h"
8
#include "bytes.h"
9
#include "sha256.h"
10
11
typedef struct {
12
    SHA256_CTX ctx;
13
    unsigned int h_ipad[8];
14
    unsigned int h_opad[8];
15
    union { limb_t l[64/sizeof(limb_t)]; unsigned char c[64]; } tail;
16
} HMAC_SHA256_CTX;
17
18
static void HMAC_init(HMAC_SHA256_CTX *ctx, const void *K, size_t K_len)
19
0
{
20
0
    size_t i;
21
22
0
    if (K == NULL) {            /* reuse h_ipad and h_opad */
23
0
        sha256_hcopy(ctx->ctx.h, ctx->h_ipad);
24
0
        ctx->ctx.N = 64;
25
0
        vec_zero(ctx->ctx.buf, sizeof(ctx->ctx.buf));
26
0
        ctx->ctx.off = 0;
27
28
0
        return;
29
0
    }
30
31
0
    vec_zero(ctx->tail.c, sizeof(ctx->tail));
32
0
    if (K_len > 64) {
33
0
        sha256_init(&ctx->ctx);
34
0
        sha256_update(&ctx->ctx, K, K_len);
35
0
        sha256_final(ctx->tail.c, &ctx->ctx);
36
0
    } else {
37
0
        sha256_bcopy(ctx->tail.c, K, K_len);
38
0
    }
39
40
0
    for (i = 0; i < 64/sizeof(limb_t); i++)
41
0
        ctx->tail.l[i] ^= (limb_t)0x3636363636363636;
42
43
0
    sha256_init(&ctx->ctx);
44
0
    sha256_update(&ctx->ctx, ctx->tail.c, 64);
45
0
    sha256_hcopy(ctx->h_ipad, ctx->ctx.h);
46
47
0
    for (i = 0; i < 64/sizeof(limb_t); i++)
48
0
        ctx->tail.l[i] ^= (limb_t)(0x3636363636363636 ^ 0x5c5c5c5c5c5c5c5c);
49
50
0
    sha256_init_h(ctx->h_opad);
51
0
    sha256_block_data_order(ctx->h_opad, ctx->tail.c, 1);
52
53
0
    vec_zero(ctx->tail.c, sizeof(ctx->tail));
54
0
    ctx->tail.c[32] = 0x80;
55
0
    ctx->tail.c[62] = 3;        /* (64+32)*8 in big endian */
56
0
    ctx->tail.c[63] = 0;
57
0
}
58
59
static void HMAC_update(HMAC_SHA256_CTX *ctx, const unsigned char *inp,
60
                                              size_t len)
61
0
{   sha256_update(&ctx->ctx, inp, len);   }
62
63
static void HMAC_final(unsigned char md[32], HMAC_SHA256_CTX *ctx)
64
0
{
65
0
    sha256_final(ctx->tail.c, &ctx->ctx);
66
0
    sha256_hcopy(ctx->ctx.h, ctx->h_opad);
67
0
    sha256_block_data_order(ctx->ctx.h, ctx->tail.c, 1);
68
0
    sha256_emit(md, ctx->ctx.h);
69
0
}
70
71
static void HKDF_Extract(unsigned char PRK[32],
72
                         const void *salt, size_t salt_len,
73
                         const void *IKM,  size_t IKM_len,
74
#ifndef __BLST_HKDF_TESTMODE__
75
                         int IKM_fixup,
76
#endif
77
                         HMAC_SHA256_CTX *ctx)
78
0
{
79
0
    unsigned char zero[1] = { 0 };
80
81
0
    HMAC_init(ctx, salt != NULL ? salt : zero, salt_len);
82
0
    HMAC_update(ctx, IKM, IKM_len);
83
0
#ifndef __BLST_HKDF_TESTMODE__
84
0
    if (IKM_fixup) {
85
        /* Section 2.3 KeyGen in BLS-signature draft */
86
0
        HMAC_update(ctx, zero, 1);
87
0
    }
88
0
#endif
89
0
    HMAC_final(PRK, ctx);
90
0
}
91
92
static void HKDF_Expand(unsigned char *OKM, size_t L,
93
                        const unsigned char PRK[32],
94
                        const void *info, size_t info_len,
95
#ifndef __BLST_HKDF_TESTMODE__
96
                        int info_fixup,
97
#endif
98
                        HMAC_SHA256_CTX *ctx)
99
0
{
100
#if !defined(__STDC_VERSION__) || __STDC_VERSION__<199901 \
101
                               || defined(__STDC_NO_VLA__)
102
    unsigned char *info_prime = alloca(info_len + 2 + 1);
103
#else
104
0
    unsigned char info_prime[info_len + 2 + 1];
105
0
#endif
106
107
0
    HMAC_init(ctx, PRK, 32);
108
109
0
    if (info_len != 0)
110
0
        sha256_bcopy(info_prime, info, info_len);
111
0
#ifndef __BLST_HKDF_TESTMODE__
112
0
    if (info_fixup) {
113
        /* Section 2.3 KeyGen in BLS-signature draft */
114
0
        info_prime[info_len + 0] = (unsigned char)(L >> 8);
115
0
        info_prime[info_len + 1] = (unsigned char)(L);
116
0
        info_len += 2;
117
0
    }
118
0
#endif
119
0
    info_prime[info_len] = 1;   /* counter */
120
0
    HMAC_update(ctx, info_prime, info_len + 1);
121
0
    HMAC_final(ctx->tail.c, ctx);
122
0
    while (L > 32) {
123
0
        sha256_hcopy((unsigned int *)OKM, (const unsigned int *)ctx->tail.c);
124
0
        OKM += 32; L -= 32;
125
0
        ++info_prime[info_len]; /* counter */
126
0
        HMAC_init(ctx, NULL, 0);
127
0
        HMAC_update(ctx, ctx->tail.c, 32);
128
0
        HMAC_update(ctx, info_prime, info_len + 1);
129
0
        HMAC_final(ctx->tail.c, ctx);
130
0
    }
131
0
    sha256_bcopy(OKM, ctx->tail.c, L);
132
0
}
133
134
#ifndef __BLST_HKDF_TESTMODE__
135
static void keygen(pow256 SK, const void *IKM, size_t IKM_len,
136
                              const void *salt, size_t salt_len,
137
                              const void *info, size_t info_len,
138
                              int version)
139
0
{
140
0
    struct {
141
0
        HMAC_SHA256_CTX ctx;
142
0
        unsigned char PRK[32], OKM[48];
143
0
        vec512 key;
144
0
    } scratch;
145
0
    unsigned char salt_prime[32] = "BLS-SIG-KEYGEN-SALT-";
146
147
0
    if (IKM_len < 32 || (version > 4 && salt == NULL)) {
148
0
        vec_zero(SK, sizeof(pow256));
149
0
        return;
150
0
    }
151
152
    /*
153
     * Vet |info| since some callers were caught to be sloppy, e.g.
154
     * SWIG-4.0-generated Python wrapper...
155
     */
156
0
    info_len = info==NULL ? 0 : info_len;
157
158
0
    if (salt == NULL) {
159
0
        salt = salt_prime;
160
0
        salt_len = 20;
161
0
    }
162
163
0
    if (version == 4) {
164
        /* salt = H(salt) */
165
0
        sha256_init(&scratch.ctx.ctx);
166
0
        sha256_update(&scratch.ctx.ctx, salt, salt_len);
167
0
        sha256_final(salt_prime, &scratch.ctx.ctx);
168
0
        salt = salt_prime;
169
0
        salt_len = sizeof(salt_prime);
170
0
    }
171
172
0
    while (1) {
173
        /* PRK = HKDF-Extract(salt, IKM || I2OSP(0, 1)) */
174
0
        HKDF_Extract(scratch.PRK, salt, salt_len,
175
0
                                  IKM, IKM_len, 1, &scratch.ctx);
176
177
        /* OKM = HKDF-Expand(PRK, key_info || I2OSP(L, 2), L) */
178
0
        HKDF_Expand(scratch.OKM, sizeof(scratch.OKM), scratch.PRK,
179
0
                    info, info_len, 1, &scratch.ctx);
180
181
        /* SK = OS2IP(OKM) mod r */
182
0
        vec_zero(scratch.key, sizeof(scratch.key));
183
0
        limbs_from_be_bytes(scratch.key, scratch.OKM, sizeof(scratch.OKM));
184
0
        redc_mont_256(scratch.key, scratch.key, BLS12_381_r, r0);
185
        /*
186
         * Given that mul_mont_sparse_256 has special boundary conditions
187
         * it's appropriate to mention that redc_mont_256 output is fully
188
         * reduced at this point. Because we started with 384-bit input,
189
         * one with most significant half smaller than the modulus.
190
         */
191
0
        mul_mont_sparse_256(scratch.key, scratch.key, BLS12_381_rRR,
192
0
                            BLS12_381_r, r0);
193
194
0
        if (version < 4 || !vec_is_zero(scratch.key, sizeof(vec256)))
195
0
            break;
196
197
        /* salt = H(salt) */
198
0
        sha256_init(&scratch.ctx.ctx);
199
0
        sha256_update(&scratch.ctx.ctx, salt, salt_len);
200
0
        sha256_final(salt_prime, &scratch.ctx.ctx);
201
0
        salt = salt_prime;
202
0
        salt_len = sizeof(salt_prime);
203
0
    }
204
205
0
    le_bytes_from_limbs(SK, scratch.key, sizeof(pow256));
206
207
    /*
208
     * scrub the stack just in case next callee inadvertently flashes
209
     * a fragment across application boundary...
210
     */
211
0
    vec_zero(&scratch, sizeof(scratch));
212
0
}
213
214
void blst_keygen(pow256 SK, const void *IKM, size_t IKM_len,
215
                            const void *info, size_t info_len)
216
0
{   keygen(SK, IKM, IKM_len, NULL, 0, info, info_len, 4);   }
217
218
void blst_keygen_v3(pow256 SK, const void *IKM, size_t IKM_len,
219
                               const void *info, size_t info_len)
220
0
{   keygen(SK, IKM, IKM_len, NULL, 0, info, info_len, 3);   }
221
222
void blst_keygen_v4_5(pow256 SK, const void *IKM, size_t IKM_len,
223
                                 const void *salt, size_t salt_len,
224
                                 const void *info, size_t info_len)
225
0
{   keygen(SK, IKM, IKM_len, salt, salt_len, info, info_len, 4);   }
226
227
void blst_keygen_v5(pow256 SK, const void *IKM, size_t IKM_len,
228
                               const void *salt, size_t salt_len,
229
                               const void *info, size_t info_len)
230
0
{   keygen(SK, IKM, IKM_len, salt, salt_len, info, info_len, 5);   }
231
232
/*
233
 * https://eips.ethereum.org/EIPS/eip-2333
234
 */
235
void blst_derive_master_eip2333(pow256 SK, const void *seed, size_t seed_len)
236
0
{   keygen(SK, seed, seed_len, NULL, 0, NULL, 0, 4);   }
237
238
static void parent_SK_to_lamport_PK(pow256 PK, const pow256 parent_SK,
239
                                    unsigned int index)
240
0
{
241
0
    size_t i;
242
0
    struct {
243
0
        HMAC_SHA256_CTX ctx;
244
0
        SHA256_CTX ret;
245
0
        unsigned char PRK[32], IKM[32];
246
0
        unsigned char lamport[255][32];
247
0
    } scratch;
248
249
    /* salt = I2OSP(index, 4) */
250
0
    unsigned char salt[4] = { (unsigned char)(index>>24),
251
0
                              (unsigned char)(index>>16),
252
0
                              (unsigned char)(index>>8),
253
0
                              (unsigned char)(index) };
254
255
    /* IKM = I2OSP(parent_SK, 32) */
256
0
    for (i = 0; i < 32; i++)
257
0
        scratch.IKM[i] = parent_SK[31-i];
258
259
    /* lamport_0 = IKM_to_lamport_SK(IKM, salt) */
260
0
    HKDF_Extract(scratch.PRK, salt, sizeof(salt), scratch.IKM, 32, 0,
261
0
                 &scratch.ctx);
262
0
    HKDF_Expand(scratch.lamport[0], sizeof(scratch.lamport),
263
0
                scratch.PRK, NULL, 0, 0, &scratch.ctx);
264
265
0
    vec_zero(scratch.ctx.ctx.buf, sizeof(scratch.ctx.ctx.buf));
266
0
    scratch.ctx.ctx.buf[32] = 0x80;
267
0
    scratch.ctx.ctx.buf[62] = 1;    /* 32*8 in big endian */
268
0
    scratch.ctx.ctx.buf[63] = 0;
269
0
    for (i = 0; i < 255; i++) {
270
        /* lamport_PK = lamport_PK | SHA256(lamport_0[i]) */
271
0
        sha256_init_h(scratch.ctx.ctx.h);
272
0
        sha256_bcopy(scratch.ctx.ctx.buf, scratch.lamport[i], 32);
273
0
        sha256_block_data_order(scratch.ctx.ctx.h, scratch.ctx.ctx.buf, 1);
274
0
        sha256_emit(scratch.lamport[i], scratch.ctx.ctx.h);
275
0
    }
276
277
    /* compressed_lamport_PK = SHA256(lamport_PK) */
278
0
    sha256_init(&scratch.ret);
279
0
    sha256_update(&scratch.ret, scratch.lamport, sizeof(scratch.lamport));
280
281
    /* not_IKM = flip_bits(IKM) */
282
0
    for (i = 0; i< 32; i++)
283
0
        scratch.IKM[i] = ~scratch.IKM[i];
284
285
    /* lamport_1 = IKM_to_lamport_SK(not_IKM, salt) */
286
0
    HKDF_Extract(scratch.PRK, salt, sizeof(salt), scratch.IKM, 32, 0,
287
0
                 &scratch.ctx);
288
0
    HKDF_Expand(scratch.lamport[0], sizeof(scratch.lamport),
289
0
                scratch.PRK, NULL, 0, 0, &scratch.ctx);
290
291
0
    vec_zero(scratch.ctx.ctx.buf, sizeof(scratch.ctx.ctx.buf));
292
0
    scratch.ctx.ctx.buf[32] = 0x80;
293
0
    scratch.ctx.ctx.buf[62] = 1;
294
0
    for (i = 0; i < 255; i++) {
295
        /* lamport_PK = lamport_PK | SHA256(lamport_1[i]) */
296
0
        sha256_init_h(scratch.ctx.ctx.h);
297
0
        sha256_bcopy(scratch.ctx.ctx.buf, scratch.lamport[i], 32);
298
0
        sha256_block_data_order(scratch.ctx.ctx.h, scratch.ctx.ctx.buf, 1);
299
0
        sha256_emit(scratch.lamport[i], scratch.ctx.ctx.h);
300
0
    }
301
302
    /* compressed_lamport_PK = SHA256(lamport_PK) */
303
0
    sha256_update(&scratch.ret, scratch.lamport, sizeof(scratch.lamport));
304
0
    sha256_final(PK, &scratch.ret);
305
306
    /*
307
     * scrub the stack just in case next callee inadvertently flashes
308
     * a fragment across application boundary...
309
     */
310
0
    vec_zero(&scratch, sizeof(scratch));
311
0
}
312
313
void blst_derive_child_eip2333(pow256 SK, const pow256 parent_SK,
314
                               unsigned int child_index)
315
0
{
316
0
    parent_SK_to_lamport_PK(SK, parent_SK, child_index);
317
0
    keygen(SK, SK, sizeof(pow256), NULL, 0, NULL, 0, 4);
318
0
}
319
#endif