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