Coverage Report

Created: 2026-04-09 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openssl30/crypto/ec/curve448/eddsa.c
Line
Count
Source
1
/*
2
 * Copyright 2017-2021 The OpenSSL Project Authors. All Rights Reserved.
3
 * Copyright 2015-2016 Cryptography Research, Inc.
4
 *
5
 * Licensed under the Apache License 2.0 (the "License").  You may not use
6
 * this file except in compliance with the License.  You can obtain a copy
7
 * in the file LICENSE in the source distribution or at
8
 * https://www.openssl.org/source/license.html
9
 *
10
 * Originally written by Mike Hamburg
11
 */
12
#include <string.h>
13
#include <openssl/crypto.h>
14
#include <openssl/evp.h>
15
#include "crypto/ecx.h"
16
#include "curve448_local.h"
17
#include "word.h"
18
#include "ed448.h"
19
#include "internal/numbers.h"
20
21
22
#define COFACTOR 4
22
23
static c448_error_t oneshot_hash(OSSL_LIB_CTX *ctx, uint8_t *out, size_t outlen,
24
    const uint8_t *in, size_t inlen,
25
    const char *propq)
26
22
{
27
22
    EVP_MD_CTX *hashctx = EVP_MD_CTX_new();
28
22
    EVP_MD *shake256 = NULL;
29
22
    c448_error_t ret = C448_FAILURE;
30
31
22
    if (hashctx == NULL)
32
0
        return C448_FAILURE;
33
34
22
    shake256 = EVP_MD_fetch(ctx, "SHAKE256", propq);
35
22
    if (shake256 == NULL)
36
0
        goto err;
37
38
22
    if (!EVP_DigestInit_ex(hashctx, shake256, NULL)
39
22
        || !EVP_DigestUpdate(hashctx, in, inlen)
40
22
        || !EVP_DigestFinalXOF(hashctx, out, outlen))
41
0
        goto err;
42
43
22
    ret = C448_SUCCESS;
44
22
err:
45
22
    EVP_MD_CTX_free(hashctx);
46
22
    EVP_MD_free(shake256);
47
22
    return ret;
48
22
}
49
50
static void clamp(uint8_t secret_scalar_ser[EDDSA_448_PRIVATE_BYTES])
51
22
{
52
22
    secret_scalar_ser[0] &= -COFACTOR;
53
22
    secret_scalar_ser[EDDSA_448_PRIVATE_BYTES - 1] = 0;
54
22
    secret_scalar_ser[EDDSA_448_PRIVATE_BYTES - 2] |= 0x80;
55
22
}
56
57
static c448_error_t hash_init_with_dom(OSSL_LIB_CTX *ctx, EVP_MD_CTX *hashctx,
58
    uint8_t prehashed,
59
    uint8_t for_prehash,
60
    const uint8_t *context,
61
    size_t context_len,
62
    const char *propq)
63
43
{
64
#ifdef CHARSET_EBCDIC
65
    const char dom_s[] = { 0x53, 0x69, 0x67, 0x45,
66
        0x64, 0x34, 0x34, 0x38, 0x00 };
67
#else
68
43
    const char dom_s[] = "SigEd448";
69
43
#endif
70
43
    uint8_t dom[2];
71
43
    EVP_MD *shake256 = NULL;
72
73
43
    if (context_len > UINT8_MAX)
74
0
        return C448_FAILURE;
75
76
43
    dom[0] = (uint8_t)(2 - (prehashed == 0 ? 1 : 0)
77
43
        - (for_prehash == 0 ? 1 : 0));
78
43
    dom[1] = (uint8_t)context_len;
79
80
43
    shake256 = EVP_MD_fetch(ctx, "SHAKE256", propq);
81
43
    if (shake256 == NULL)
82
0
        return C448_FAILURE;
83
84
43
    if (!EVP_DigestInit_ex(hashctx, shake256, NULL)
85
43
        || !EVP_DigestUpdate(hashctx, dom_s, strlen(dom_s))
86
43
        || !EVP_DigestUpdate(hashctx, dom, sizeof(dom))
87
43
        || !EVP_DigestUpdate(hashctx, context, context_len)) {
88
0
        EVP_MD_free(shake256);
89
0
        return C448_FAILURE;
90
0
    }
91
92
43
    EVP_MD_free(shake256);
93
43
    return C448_SUCCESS;
94
43
}
95
96
/* In this file because it uses the hash */
97
c448_error_t
98
ossl_c448_ed448_convert_private_key_to_x448(
99
    OSSL_LIB_CTX *ctx,
100
    uint8_t x[X448_PRIVATE_BYTES],
101
    const uint8_t ed[EDDSA_448_PRIVATE_BYTES],
102
    const char *propq)
103
0
{
104
    /* pass the private key through oneshot_hash function */
105
    /* and keep the first X448_PRIVATE_BYTES bytes */
106
0
    return oneshot_hash(ctx, x, X448_PRIVATE_BYTES, ed,
107
0
        EDDSA_448_PRIVATE_BYTES, propq);
108
0
}
109
110
c448_error_t
111
ossl_c448_ed448_derive_public_key(
112
    OSSL_LIB_CTX *ctx,
113
    uint8_t pubkey[EDDSA_448_PUBLIC_BYTES],
114
    const uint8_t privkey[EDDSA_448_PRIVATE_BYTES],
115
    const char *propq)
116
22
{
117
    /* only this much used for keygen */
118
22
    uint8_t secret_scalar_ser[EDDSA_448_PRIVATE_BYTES];
119
22
    curve448_scalar_t secret_scalar;
120
22
    unsigned int c;
121
22
    curve448_point_t p;
122
123
22
    if (!oneshot_hash(ctx, secret_scalar_ser, sizeof(secret_scalar_ser),
124
22
            privkey,
125
22
            EDDSA_448_PRIVATE_BYTES,
126
22
            propq))
127
0
        return C448_FAILURE;
128
129
22
    clamp(secret_scalar_ser);
130
131
22
    ossl_curve448_scalar_decode_long(secret_scalar, secret_scalar_ser,
132
22
        sizeof(secret_scalar_ser));
133
134
    /*
135
     * Since we are going to mul_by_cofactor during encoding, divide by it
136
     * here. However, the EdDSA base point is not the same as the decaf base
137
     * point if the sigma isogeny is in use: the EdDSA base point is on
138
     * Etwist_d/(1-d) and the decaf base point is on Etwist_d, and when
139
     * converted it effectively picks up a factor of 2 from the isogenies.  So
140
     * we might start at 2 instead of 1.
141
     */
142
66
    for (c = 1; c < C448_EDDSA_ENCODE_RATIO; c <<= 1)
143
44
        ossl_curve448_scalar_halve(secret_scalar, secret_scalar);
144
145
22
    ossl_curve448_precomputed_scalarmul(p, ossl_curve448_precomputed_base,
146
22
        secret_scalar);
147
148
22
    ossl_curve448_point_mul_by_ratio_and_encode_like_eddsa(pubkey, p);
149
150
    /* Cleanup */
151
22
    ossl_curve448_scalar_destroy(secret_scalar);
152
22
    ossl_curve448_point_destroy(p);
153
22
    OPENSSL_cleanse(secret_scalar_ser, sizeof(secret_scalar_ser));
154
155
22
    return C448_SUCCESS;
156
22
}
157
158
c448_error_t
159
ossl_c448_ed448_sign(OSSL_LIB_CTX *ctx,
160
    uint8_t signature[EDDSA_448_SIGNATURE_BYTES],
161
    const uint8_t privkey[EDDSA_448_PRIVATE_BYTES],
162
    const uint8_t pubkey[EDDSA_448_PUBLIC_BYTES],
163
    const uint8_t *message, size_t message_len,
164
    uint8_t prehashed, const uint8_t *context,
165
    size_t context_len, const char *propq)
166
0
{
167
0
    curve448_scalar_t secret_scalar;
168
0
    EVP_MD_CTX *hashctx = EVP_MD_CTX_new();
169
0
    c448_error_t ret = C448_FAILURE;
170
0
    curve448_scalar_t nonce_scalar;
171
0
    uint8_t nonce_point[EDDSA_448_PUBLIC_BYTES] = { 0 };
172
0
    unsigned int c;
173
0
    curve448_scalar_t challenge_scalar;
174
175
0
    if (hashctx == NULL)
176
0
        return C448_FAILURE;
177
178
0
    {
179
        /*
180
         * Schedule the secret key, First EDDSA_448_PRIVATE_BYTES is serialized
181
         * secret scalar,next EDDSA_448_PRIVATE_BYTES bytes is the seed.
182
         */
183
0
        uint8_t expanded[EDDSA_448_PRIVATE_BYTES * 2];
184
185
0
        if (!oneshot_hash(ctx, expanded, sizeof(expanded), privkey,
186
0
                EDDSA_448_PRIVATE_BYTES, propq))
187
0
            goto err;
188
0
        clamp(expanded);
189
0
        ossl_curve448_scalar_decode_long(secret_scalar, expanded,
190
0
            EDDSA_448_PRIVATE_BYTES);
191
192
        /* Hash to create the nonce */
193
0
        if (!hash_init_with_dom(ctx, hashctx, prehashed, 0, context,
194
0
                context_len, propq)
195
0
            || !EVP_DigestUpdate(hashctx,
196
0
                expanded + EDDSA_448_PRIVATE_BYTES,
197
0
                EDDSA_448_PRIVATE_BYTES)
198
0
            || !EVP_DigestUpdate(hashctx, message, message_len)) {
199
0
            OPENSSL_cleanse(expanded, sizeof(expanded));
200
0
            goto err;
201
0
        }
202
0
        OPENSSL_cleanse(expanded, sizeof(expanded));
203
0
    }
204
205
    /* Decode the nonce */
206
0
    {
207
0
        uint8_t nonce[2 * EDDSA_448_PRIVATE_BYTES];
208
209
0
        if (!EVP_DigestFinalXOF(hashctx, nonce, sizeof(nonce)))
210
0
            goto err;
211
0
        ossl_curve448_scalar_decode_long(nonce_scalar, nonce, sizeof(nonce));
212
0
        OPENSSL_cleanse(nonce, sizeof(nonce));
213
0
    }
214
215
0
    {
216
        /* Scalarmul to create the nonce-point */
217
0
        curve448_scalar_t nonce_scalar_2;
218
0
        curve448_point_t p;
219
220
0
        ossl_curve448_scalar_halve(nonce_scalar_2, nonce_scalar);
221
0
        for (c = 2; c < C448_EDDSA_ENCODE_RATIO; c <<= 1)
222
0
            ossl_curve448_scalar_halve(nonce_scalar_2, nonce_scalar_2);
223
224
0
        ossl_curve448_precomputed_scalarmul(p, ossl_curve448_precomputed_base,
225
0
            nonce_scalar_2);
226
0
        ossl_curve448_point_mul_by_ratio_and_encode_like_eddsa(nonce_point, p);
227
0
        ossl_curve448_point_destroy(p);
228
0
        ossl_curve448_scalar_destroy(nonce_scalar_2);
229
0
    }
230
231
0
    {
232
0
        uint8_t challenge[2 * EDDSA_448_PRIVATE_BYTES];
233
234
        /* Compute the challenge */
235
0
        if (!hash_init_with_dom(ctx, hashctx, prehashed, 0, context, context_len,
236
0
                propq)
237
0
            || !EVP_DigestUpdate(hashctx, nonce_point, sizeof(nonce_point))
238
0
            || !EVP_DigestUpdate(hashctx, pubkey, EDDSA_448_PUBLIC_BYTES)
239
0
            || !EVP_DigestUpdate(hashctx, message, message_len)
240
0
            || !EVP_DigestFinalXOF(hashctx, challenge, sizeof(challenge)))
241
0
            goto err;
242
243
0
        ossl_curve448_scalar_decode_long(challenge_scalar, challenge,
244
0
            sizeof(challenge));
245
0
        OPENSSL_cleanse(challenge, sizeof(challenge));
246
0
    }
247
248
0
    ossl_curve448_scalar_mul(challenge_scalar, challenge_scalar, secret_scalar);
249
0
    ossl_curve448_scalar_add(challenge_scalar, challenge_scalar, nonce_scalar);
250
251
0
    OPENSSL_cleanse(signature, EDDSA_448_SIGNATURE_BYTES);
252
0
    memcpy(signature, nonce_point, sizeof(nonce_point));
253
0
    ossl_curve448_scalar_encode(&signature[EDDSA_448_PUBLIC_BYTES],
254
0
        challenge_scalar);
255
256
0
    ossl_curve448_scalar_destroy(secret_scalar);
257
0
    ossl_curve448_scalar_destroy(nonce_scalar);
258
0
    ossl_curve448_scalar_destroy(challenge_scalar);
259
260
0
    ret = C448_SUCCESS;
261
0
err:
262
0
    EVP_MD_CTX_free(hashctx);
263
0
    return ret;
264
0
}
265
266
c448_error_t
267
ossl_c448_ed448_sign_prehash(
268
    OSSL_LIB_CTX *ctx,
269
    uint8_t signature[EDDSA_448_SIGNATURE_BYTES],
270
    const uint8_t privkey[EDDSA_448_PRIVATE_BYTES],
271
    const uint8_t pubkey[EDDSA_448_PUBLIC_BYTES],
272
    const uint8_t hash[64], const uint8_t *context,
273
    size_t context_len, const char *propq)
274
0
{
275
0
    return ossl_c448_ed448_sign(ctx, signature, privkey, pubkey, hash, 64, 1,
276
0
        context, context_len, propq);
277
0
}
278
279
c448_error_t
280
ossl_c448_ed448_verify(
281
    OSSL_LIB_CTX *ctx,
282
    const uint8_t signature[EDDSA_448_SIGNATURE_BYTES],
283
    const uint8_t pubkey[EDDSA_448_PUBLIC_BYTES],
284
    const uint8_t *message, size_t message_len,
285
    uint8_t prehashed, const uint8_t *context,
286
    uint8_t context_len, const char *propq)
287
49
{
288
49
    curve448_point_t pk_point, r_point;
289
49
    c448_error_t error;
290
49
    curve448_scalar_t challenge_scalar;
291
49
    curve448_scalar_t response_scalar;
292
    /* Order in little endian format */
293
49
    static const uint8_t order[] = {
294
49
        0xF3, 0x44, 0x58, 0xAB, 0x92, 0xC2, 0x78, 0x23, 0x55, 0x8F, 0xC5, 0x8D,
295
49
        0x72, 0xC2, 0x6C, 0x21, 0x90, 0x36, 0xD6, 0xAE, 0x49, 0xDB, 0x4E, 0xC4,
296
49
        0xE9, 0x23, 0xCA, 0x7C, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
297
49
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
298
49
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00
299
49
    };
300
49
    int i;
301
302
    /*
303
     * Check that s (second 57 bytes of the sig) is less than the order. Both
304
     * s and the order are in little-endian format. This can be done in
305
     * variable time, since if this is not the case the signature if publicly
306
     * invalid.
307
     */
308
161
    for (i = EDDSA_448_PUBLIC_BYTES - 1; i >= 0; i--) {
309
161
        if (signature[i + EDDSA_448_PUBLIC_BYTES] > order[i])
310
1
            return C448_FAILURE;
311
160
        if (signature[i + EDDSA_448_PUBLIC_BYTES] < order[i])
312
48
            break;
313
160
    }
314
48
    if (i < 0)
315
0
        return C448_FAILURE;
316
317
48
    error = ossl_curve448_point_decode_like_eddsa_and_mul_by_ratio(pk_point, pubkey);
318
319
48
    if (C448_SUCCESS != error)
320
3
        return error;
321
322
45
    error = ossl_curve448_point_decode_like_eddsa_and_mul_by_ratio(r_point, signature);
323
45
    if (C448_SUCCESS != error)
324
2
        return error;
325
326
43
    {
327
        /* Compute the challenge */
328
43
        EVP_MD_CTX *hashctx = EVP_MD_CTX_new();
329
43
        uint8_t challenge[2 * EDDSA_448_PRIVATE_BYTES];
330
331
43
        if (hashctx == NULL
332
43
            || !hash_init_with_dom(ctx, hashctx, prehashed, 0, context,
333
43
                context_len, propq)
334
43
            || !EVP_DigestUpdate(hashctx, signature, EDDSA_448_PUBLIC_BYTES)
335
43
            || !EVP_DigestUpdate(hashctx, pubkey, EDDSA_448_PUBLIC_BYTES)
336
43
            || !EVP_DigestUpdate(hashctx, message, message_len)
337
43
            || !EVP_DigestFinalXOF(hashctx, challenge, sizeof(challenge))) {
338
0
            EVP_MD_CTX_free(hashctx);
339
0
            return C448_FAILURE;
340
0
        }
341
342
43
        EVP_MD_CTX_free(hashctx);
343
43
        ossl_curve448_scalar_decode_long(challenge_scalar, challenge,
344
43
            sizeof(challenge));
345
43
        OPENSSL_cleanse(challenge, sizeof(challenge));
346
43
    }
347
0
    ossl_curve448_scalar_sub(challenge_scalar, ossl_curve448_scalar_zero,
348
43
        challenge_scalar);
349
350
43
    ossl_curve448_scalar_decode_long(response_scalar,
351
43
        &signature[EDDSA_448_PUBLIC_BYTES],
352
43
        EDDSA_448_PRIVATE_BYTES);
353
354
    /* pk_point = -c(x(P)) + (cx + k)G = kG */
355
43
    ossl_curve448_base_double_scalarmul_non_secret(pk_point,
356
43
        response_scalar,
357
43
        pk_point, challenge_scalar);
358
43
    return c448_succeed_if(ossl_curve448_point_eq(pk_point, r_point));
359
43
}
360
361
c448_error_t
362
ossl_c448_ed448_verify_prehash(
363
    OSSL_LIB_CTX *ctx,
364
    const uint8_t signature[EDDSA_448_SIGNATURE_BYTES],
365
    const uint8_t pubkey[EDDSA_448_PUBLIC_BYTES],
366
    const uint8_t hash[64], const uint8_t *context,
367
    uint8_t context_len, const char *propq)
368
0
{
369
0
    return ossl_c448_ed448_verify(ctx, signature, pubkey, hash, 64, 1, context,
370
0
        context_len, propq);
371
0
}
372
373
int ossl_ed448_sign(OSSL_LIB_CTX *ctx, uint8_t *out_sig, const uint8_t *message,
374
    size_t message_len, const uint8_t public_key[57],
375
    const uint8_t private_key[57], const uint8_t *context,
376
    size_t context_len, const char *propq)
377
0
{
378
0
    return ossl_c448_ed448_sign(ctx, out_sig, private_key, public_key, message,
379
0
               message_len, 0, context, context_len,
380
0
               propq)
381
0
        == C448_SUCCESS;
382
0
}
383
384
int ossl_ed448_verify(OSSL_LIB_CTX *ctx, const uint8_t *message, size_t message_len,
385
    const uint8_t signature[114], const uint8_t public_key[57],
386
    const uint8_t *context, size_t context_len, const char *propq)
387
49
{
388
49
    return ossl_c448_ed448_verify(ctx, signature, public_key, message,
389
49
               message_len, 0, context, (uint8_t)context_len,
390
49
               propq)
391
49
        == C448_SUCCESS;
392
49
}
393
394
int ossl_ed448ph_sign(OSSL_LIB_CTX *ctx, uint8_t *out_sig, const uint8_t hash[64],
395
    const uint8_t public_key[57], const uint8_t private_key[57],
396
    const uint8_t *context, size_t context_len, const char *propq)
397
0
{
398
0
    return ossl_c448_ed448_sign_prehash(ctx, out_sig, private_key, public_key,
399
0
               hash, context, context_len,
400
0
               propq)
401
0
        == C448_SUCCESS;
402
0
}
403
404
int ossl_ed448ph_verify(OSSL_LIB_CTX *ctx, const uint8_t hash[64],
405
    const uint8_t signature[114], const uint8_t public_key[57],
406
    const uint8_t *context, size_t context_len,
407
    const char *propq)
408
0
{
409
0
    return ossl_c448_ed448_verify_prehash(ctx, signature, public_key, hash,
410
0
               context, (uint8_t)context_len,
411
0
               propq)
412
0
        == C448_SUCCESS;
413
0
}
414
415
int ossl_ed448_public_from_private(OSSL_LIB_CTX *ctx, uint8_t out_public_key[57],
416
    const uint8_t private_key[57], const char *propq)
417
22
{
418
22
    return ossl_c448_ed448_derive_public_key(ctx, out_public_key, private_key,
419
22
               propq)
420
22
        == C448_SUCCESS;
421
22
}