Coverage Report

Created: 2025-12-31 06:58

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