Coverage Report

Created: 2026-02-14 07:20

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
23
#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
23
{
27
23
    EVP_MD_CTX *hashctx = EVP_MD_CTX_new();
28
23
    EVP_MD *shake256 = NULL;
29
23
    c448_error_t ret = C448_FAILURE;
30
31
23
    if (hashctx == NULL)
32
0
        return C448_FAILURE;
33
34
23
    shake256 = EVP_MD_fetch(ctx, "SHAKE256", propq);
35
23
    if (shake256 == NULL)
36
0
        goto err;
37
38
23
    if (!EVP_DigestInit_ex(hashctx, shake256, NULL)
39
23
        || !EVP_DigestUpdate(hashctx, in, inlen)
40
23
        || !EVP_DigestFinalXOF(hashctx, out, outlen))
41
0
        goto err;
42
43
23
    ret = C448_SUCCESS;
44
23
err:
45
23
    EVP_MD_CTX_free(hashctx);
46
23
    EVP_MD_free(shake256);
47
23
    return ret;
48
23
}
49
50
static void clamp(uint8_t secret_scalar_ser[EDDSA_448_PRIVATE_BYTES])
51
23
{
52
23
    secret_scalar_ser[0] &= -COFACTOR;
53
23
    secret_scalar_ser[EDDSA_448_PRIVATE_BYTES - 1] = 0;
54
23
    secret_scalar_ser[EDDSA_448_PRIVATE_BYTES - 2] |= 0x80;
55
23
}
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
45
{
64
#ifdef CHARSET_EBCDIC
65
    const char dom_s[] = { 0x53, 0x69, 0x67, 0x45,
66
        0x64, 0x34, 0x34, 0x38, 0x00 };
67
#else
68
45
    const char dom_s[] = "SigEd448";
69
45
#endif
70
45
    uint8_t dom[2];
71
45
    EVP_MD *shake256 = NULL;
72
73
45
    if (context_len > UINT8_MAX)
74
0
        return C448_FAILURE;
75
76
45
    dom[0] = (uint8_t)(2 - (prehashed == 0 ? 1 : 0)
77
45
        - (for_prehash == 0 ? 1 : 0));
78
45
    dom[1] = (uint8_t)context_len;
79
80
45
    shake256 = EVP_MD_fetch(ctx, "SHAKE256", propq);
81
45
    if (shake256 == NULL)
82
0
        return C448_FAILURE;
83
84
45
    if (!EVP_DigestInit_ex(hashctx, shake256, NULL)
85
45
        || !EVP_DigestUpdate(hashctx, dom_s, strlen(dom_s))
86
45
        || !EVP_DigestUpdate(hashctx, dom, sizeof(dom))
87
45
        || !EVP_DigestUpdate(hashctx, context, context_len)) {
88
0
        EVP_MD_free(shake256);
89
0
        return C448_FAILURE;
90
0
    }
91
92
45
    EVP_MD_free(shake256);
93
45
    return C448_SUCCESS;
94
45
}
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
23
{
117
    /* only this much used for keygen */
118
23
    uint8_t secret_scalar_ser[EDDSA_448_PRIVATE_BYTES];
119
23
    curve448_scalar_t secret_scalar;
120
23
    unsigned int c;
121
23
    curve448_point_t p;
122
123
23
    if (!oneshot_hash(ctx, secret_scalar_ser, sizeof(secret_scalar_ser),
124
23
            privkey,
125
23
            EDDSA_448_PRIVATE_BYTES,
126
23
            propq))
127
0
        return C448_FAILURE;
128
129
23
    clamp(secret_scalar_ser);
130
131
23
    ossl_curve448_scalar_decode_long(secret_scalar, secret_scalar_ser,
132
23
        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
69
    for (c = 1; c < C448_EDDSA_ENCODE_RATIO; c <<= 1)
143
46
        ossl_curve448_scalar_halve(secret_scalar, secret_scalar);
144
145
23
    ossl_curve448_precomputed_scalarmul(p, ossl_curve448_precomputed_base,
146
23
        secret_scalar);
147
148
23
    ossl_curve448_point_mul_by_ratio_and_encode_like_eddsa(pubkey, p);
149
150
    /* Cleanup */
151
23
    ossl_curve448_scalar_destroy(secret_scalar);
152
23
    ossl_curve448_point_destroy(p);
153
23
    OPENSSL_cleanse(secret_scalar_ser, sizeof(secret_scalar_ser));
154
155
23
    return C448_SUCCESS;
156
23
}
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
64
{
288
64
    curve448_point_t pk_point, r_point;
289
64
    c448_error_t error;
290
64
    curve448_scalar_t challenge_scalar;
291
64
    curve448_scalar_t response_scalar;
292
    /* Order in little endian format */
293
64
    static const uint8_t order[] = {
294
64
        0xF3, 0x44, 0x58, 0xAB, 0x92, 0xC2, 0x78, 0x23, 0x55, 0x8F, 0xC5, 0x8D,
295
64
        0x72, 0xC2, 0x6C, 0x21, 0x90, 0x36, 0xD6, 0xAE, 0x49, 0xDB, 0x4E, 0xC4,
296
64
        0xE9, 0x23, 0xCA, 0x7C, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
297
64
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
298
64
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00
299
64
    };
300
64
    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
184
    for (i = EDDSA_448_PUBLIC_BYTES - 1; i >= 0; i--) {
309
184
        if (signature[i + EDDSA_448_PUBLIC_BYTES] > order[i])
310
7
            return C448_FAILURE;
311
177
        if (signature[i + EDDSA_448_PUBLIC_BYTES] < order[i])
312
57
            break;
313
177
    }
314
57
    if (i < 0)
315
0
        return C448_FAILURE;
316
317
57
    error = ossl_curve448_point_decode_like_eddsa_and_mul_by_ratio(pk_point, pubkey);
318
319
57
    if (C448_SUCCESS != error)
320
8
        return error;
321
322
49
    error = ossl_curve448_point_decode_like_eddsa_and_mul_by_ratio(r_point, signature);
323
49
    if (C448_SUCCESS != error)
324
4
        return error;
325
326
45
    {
327
        /* Compute the challenge */
328
45
        EVP_MD_CTX *hashctx = EVP_MD_CTX_new();
329
45
        uint8_t challenge[2 * EDDSA_448_PRIVATE_BYTES];
330
331
45
        if (hashctx == NULL
332
45
            || !hash_init_with_dom(ctx, hashctx, prehashed, 0, context,
333
45
                context_len, propq)
334
45
            || !EVP_DigestUpdate(hashctx, signature, EDDSA_448_PUBLIC_BYTES)
335
45
            || !EVP_DigestUpdate(hashctx, pubkey, EDDSA_448_PUBLIC_BYTES)
336
45
            || !EVP_DigestUpdate(hashctx, message, message_len)
337
45
            || !EVP_DigestFinalXOF(hashctx, challenge, sizeof(challenge))) {
338
0
            EVP_MD_CTX_free(hashctx);
339
0
            return C448_FAILURE;
340
0
        }
341
342
45
        EVP_MD_CTX_free(hashctx);
343
45
        ossl_curve448_scalar_decode_long(challenge_scalar, challenge,
344
45
            sizeof(challenge));
345
45
        OPENSSL_cleanse(challenge, sizeof(challenge));
346
45
    }
347
0
    ossl_curve448_scalar_sub(challenge_scalar, ossl_curve448_scalar_zero,
348
45
        challenge_scalar);
349
350
45
    ossl_curve448_scalar_decode_long(response_scalar,
351
45
        &signature[EDDSA_448_PUBLIC_BYTES],
352
45
        EDDSA_448_PRIVATE_BYTES);
353
354
    /* pk_point = -c(x(P)) + (cx + k)G = kG */
355
45
    ossl_curve448_base_double_scalarmul_non_secret(pk_point,
356
45
        response_scalar,
357
45
        pk_point, challenge_scalar);
358
45
    return c448_succeed_if(ossl_curve448_point_eq(pk_point, r_point));
359
45
}
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
64
{
388
64
    return ossl_c448_ed448_verify(ctx, signature, public_key, message,
389
64
               message_len, 0, context, (uint8_t)context_len,
390
64
               propq)
391
64
        == C448_SUCCESS;
392
64
}
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
23
{
418
23
    return ossl_c448_ed448_derive_public_key(ctx, out_public_key, private_key,
419
23
               propq)
420
23
        == C448_SUCCESS;
421
23
}