Coverage Report

Created: 2026-04-01 06:39

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
42
{
64
#ifdef CHARSET_EBCDIC
65
    const char dom_s[] = { 0x53, 0x69, 0x67, 0x45,
66
        0x64, 0x34, 0x34, 0x38, 0x00 };
67
#else
68
42
    const char dom_s[] = "SigEd448";
69
42
#endif
70
42
    uint8_t dom[2];
71
42
    EVP_MD *shake256 = NULL;
72
73
42
    if (context_len > UINT8_MAX)
74
0
        return C448_FAILURE;
75
76
42
    dom[0] = (uint8_t)(2 - (prehashed == 0 ? 1 : 0)
77
42
        - (for_prehash == 0 ? 1 : 0));
78
42
    dom[1] = (uint8_t)context_len;
79
80
42
    shake256 = EVP_MD_fetch(ctx, "SHAKE256", propq);
81
42
    if (shake256 == NULL)
82
0
        return C448_FAILURE;
83
84
42
    if (!EVP_DigestInit_ex(hashctx, shake256, NULL)
85
42
        || !EVP_DigestUpdate(hashctx, dom_s, strlen(dom_s))
86
42
        || !EVP_DigestUpdate(hashctx, dom, sizeof(dom))
87
42
        || !EVP_DigestUpdate(hashctx, context, context_len)) {
88
0
        EVP_MD_free(shake256);
89
0
        return C448_FAILURE;
90
0
    }
91
92
42
    EVP_MD_free(shake256);
93
42
    return C448_SUCCESS;
94
42
}
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
51
{
288
51
    curve448_point_t pk_point, r_point;
289
51
    c448_error_t error;
290
51
    curve448_scalar_t challenge_scalar;
291
51
    curve448_scalar_t response_scalar;
292
    /* Order in little endian format */
293
51
    static const uint8_t order[] = {
294
51
        0xF3, 0x44, 0x58, 0xAB, 0x92, 0xC2, 0x78, 0x23, 0x55, 0x8F, 0xC5, 0x8D,
295
51
        0x72, 0xC2, 0x6C, 0x21, 0x90, 0x36, 0xD6, 0xAE, 0x49, 0xDB, 0x4E, 0xC4,
296
51
        0xE9, 0x23, 0xCA, 0x7C, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
297
51
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
298
51
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00
299
51
    };
300
51
    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
208
    for (i = EDDSA_448_PUBLIC_BYTES - 1; i >= 0; i--) {
309
208
        if (signature[i + EDDSA_448_PUBLIC_BYTES] > order[i])
310
1
            return C448_FAILURE;
311
207
        if (signature[i + EDDSA_448_PUBLIC_BYTES] < order[i])
312
50
            break;
313
207
    }
314
50
    if (i < 0)
315
0
        return C448_FAILURE;
316
317
50
    error = ossl_curve448_point_decode_like_eddsa_and_mul_by_ratio(pk_point, pubkey);
318
319
50
    if (C448_SUCCESS != error)
320
3
        return error;
321
322
47
    error = ossl_curve448_point_decode_like_eddsa_and_mul_by_ratio(r_point, signature);
323
47
    if (C448_SUCCESS != error)
324
5
        return error;
325
326
42
    {
327
        /* Compute the challenge */
328
42
        EVP_MD_CTX *hashctx = EVP_MD_CTX_new();
329
42
        uint8_t challenge[2 * EDDSA_448_PRIVATE_BYTES];
330
331
42
        if (hashctx == NULL
332
42
            || !hash_init_with_dom(ctx, hashctx, prehashed, 0, context,
333
42
                context_len, propq)
334
42
            || !EVP_DigestUpdate(hashctx, signature, EDDSA_448_PUBLIC_BYTES)
335
42
            || !EVP_DigestUpdate(hashctx, pubkey, EDDSA_448_PUBLIC_BYTES)
336
42
            || !EVP_DigestUpdate(hashctx, message, message_len)
337
42
            || !EVP_DigestFinalXOF(hashctx, challenge, sizeof(challenge))) {
338
0
            EVP_MD_CTX_free(hashctx);
339
0
            return C448_FAILURE;
340
0
        }
341
342
42
        EVP_MD_CTX_free(hashctx);
343
42
        ossl_curve448_scalar_decode_long(challenge_scalar, challenge,
344
42
            sizeof(challenge));
345
42
        OPENSSL_cleanse(challenge, sizeof(challenge));
346
42
    }
347
0
    ossl_curve448_scalar_sub(challenge_scalar, ossl_curve448_scalar_zero,
348
42
        challenge_scalar);
349
350
42
    ossl_curve448_scalar_decode_long(response_scalar,
351
42
        &signature[EDDSA_448_PUBLIC_BYTES],
352
42
        EDDSA_448_PRIVATE_BYTES);
353
354
    /* pk_point = -c(x(P)) + (cx + k)G = kG */
355
42
    ossl_curve448_base_double_scalarmul_non_secret(pk_point,
356
42
        response_scalar,
357
42
        pk_point, challenge_scalar);
358
42
    return c448_succeed_if(ossl_curve448_point_eq(pk_point, r_point));
359
42
}
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
51
{
388
51
    return ossl_c448_ed448_verify(ctx, signature, public_key, message,
389
51
               message_len, 0, context, (uint8_t)context_len,
390
51
               propq)
391
51
        == C448_SUCCESS;
392
51
}
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
}