eddsa.c 13.1 KB
Newer Older
1
/*
2
 * Copyright 2017-2018 The OpenSSL Project Authors. All Rights Reserved.
3
 * Copyright 2015-2016 Cryptography Research, Inc.
M
Matt Caswell 已提交
4
 *
5 6 7 8
 * Licensed under the OpenSSL license (the "License").  You may not use
 * this file except in compliance with the License.  You can obtain a copy
 * in the file LICENSE in the source distribution or at
 * https://www.openssl.org/source/license.html
M
Matt Caswell 已提交
9
 *
10
 * Originally written by Mike Hamburg
M
Matt Caswell 已提交
11
 */
12
#include <openssl/crypto.h>
13
#include <openssl/evp.h>
14

M
Matt Caswell 已提交
15
#include "curve448_lcl.h"
M
Matt Caswell 已提交
16
#include "word.h"
17
#include "ed448.h"
M
Matt Caswell 已提交
18
#include <string.h>
19
#include "internal/numbers.h"
M
Matt Caswell 已提交
20 21 22

#define COFACTOR 4

M
Matt Caswell 已提交
23 24
static c448_error_t oneshot_hash(uint8_t *out, size_t outlen,
                                 const uint8_t *in, size_t inlen)
25 26 27 28
{
    EVP_MD_CTX *hashctx = EVP_MD_CTX_new();

    if (hashctx == NULL)
M
Matt Caswell 已提交
29
        return C448_FAILURE;
30 31

    if (!EVP_DigestInit_ex(hashctx, EVP_shake256(), NULL)
M
Matt Caswell 已提交
32 33
            || !EVP_DigestUpdate(hashctx, in, inlen)
            || !EVP_DigestFinalXOF(hashctx, out, outlen)) {
34
        EVP_MD_CTX_free(hashctx);
M
Matt Caswell 已提交
35
        return C448_FAILURE;
36 37 38
    }

    EVP_MD_CTX_free(hashctx);
M
Matt Caswell 已提交
39
    return C448_SUCCESS;
40 41
}

42
static void clamp(uint8_t secret_scalar_ser[EDDSA_448_PRIVATE_BYTES])
43 44
{
    uint8_t hibit = (1 << 0) >> 1;
M
Matt Caswell 已提交
45

M
Matt Caswell 已提交
46 47 48
    /* Blarg */
    secret_scalar_ser[0] &= -COFACTOR;
    if (hibit == 0) {
49 50
        secret_scalar_ser[EDDSA_448_PRIVATE_BYTES - 1] = 0;
        secret_scalar_ser[EDDSA_448_PRIVATE_BYTES - 2] |= 0x80;
M
Matt Caswell 已提交
51
    } else {
52 53
        secret_scalar_ser[EDDSA_448_PRIVATE_BYTES - 1] &= hibit - 1;
        secret_scalar_ser[EDDSA_448_PRIVATE_BYTES - 1] |= hibit;
M
Matt Caswell 已提交
54 55 56
    }
}

M
Matt Caswell 已提交
57 58 59 60
static c448_error_t hash_init_with_dom(EVP_MD_CTX *hashctx, uint8_t prehashed,
                                       uint8_t for_prehash,
                                       const uint8_t *context,
                                       size_t context_len)
61
{
62
    const char *dom_s = "SigEd448";
M
Matt Caswell 已提交
63 64 65 66
    uint8_t dom[2];

    dom[0] = 2 + word_is_zero(prehashed) + word_is_zero(for_prehash);
    dom[1] = (uint8_t)context_len;
67 68

    if (context_len > UINT8_MAX)
M
Matt Caswell 已提交
69
        return C448_FAILURE;
M
Matt Caswell 已提交
70

71
    if (!EVP_DigestInit_ex(hashctx, EVP_shake256(), NULL)
M
Matt Caswell 已提交
72 73 74
            || !EVP_DigestUpdate(hashctx, dom_s, strlen(dom_s))
            || !EVP_DigestUpdate(hashctx, dom, sizeof(dom))
            || !EVP_DigestUpdate(hashctx, context, context_len))
M
Matt Caswell 已提交
75
        return C448_FAILURE;
76

M
Matt Caswell 已提交
77
    return C448_SUCCESS;
M
Matt Caswell 已提交
78 79 80
}

/* In this file because it uses the hash */
M
Matt Caswell 已提交
81
c448_error_t c448_ed448_convert_private_key_to_x448(
82 83
                            uint8_t x[X448_PRIVATE_BYTES],
                            const uint8_t ed [EDDSA_448_PRIVATE_BYTES])
84
{
85
    /* pass the private key through oneshot_hash function */
86 87 88
    /* and keep the first X448_PRIVATE_BYTES bytes */
    return oneshot_hash(x, X448_PRIVATE_BYTES, ed,
                        EDDSA_448_PRIVATE_BYTES);
M
Matt Caswell 已提交
89
}
90

M
Matt Caswell 已提交
91
c448_error_t c448_ed448_derive_public_key(
92 93
                        uint8_t pubkey[EDDSA_448_PUBLIC_BYTES],
                        const uint8_t privkey[EDDSA_448_PRIVATE_BYTES])
94
{
M
Matt Caswell 已提交
95
    /* only this much used for keygen */
96
    uint8_t secret_scalar_ser[EDDSA_448_PRIVATE_BYTES];
M
Matt Caswell 已提交
97 98 99 100
    curve448_scalar_t secret_scalar;
    unsigned int c;
    curve448_point_t p;

101
    if (!oneshot_hash(secret_scalar_ser, sizeof(secret_scalar_ser), privkey,
102
                      EDDSA_448_PRIVATE_BYTES))
M
Matt Caswell 已提交
103
        return C448_FAILURE;
104

M
Matt Caswell 已提交
105
    clamp(secret_scalar_ser);
M
Matt Caswell 已提交
106

107 108 109 110 111 112 113 114 115 116
    curve448_scalar_decode_long(secret_scalar, secret_scalar_ser,
                                sizeof(secret_scalar_ser));

    /*
     * Since we are going to mul_by_cofactor during encoding, divide by it
     * here. However, the EdDSA base point is not the same as the decaf base
     * point if the sigma isogeny is in use: the EdDSA base point is on
     * Etwist_d/(1-d) and the decaf base point is on Etwist_d, and when
     * converted it effectively picks up a factor of 2 from the isogenies.  So
     * we might start at 2 instead of 1.
M
Matt Caswell 已提交
117
     */
118
    for (c = 1; c < C448_EDDSA_ENCODE_RATIO; c <<= 1)
119 120 121 122
        curve448_scalar_halve(secret_scalar, secret_scalar);

    curve448_precomputed_scalarmul(p, curve448_precomputed_base, secret_scalar);

M
Matt Caswell 已提交
123
    curve448_point_mul_by_ratio_and_encode_like_eddsa(pubkey, p);
124

M
Matt Caswell 已提交
125
    /* Cleanup */
M
Matt Caswell 已提交
126 127
    curve448_scalar_destroy(secret_scalar);
    curve448_point_destroy(p);
128
    OPENSSL_cleanse(secret_scalar_ser, sizeof(secret_scalar_ser));
129

M
Matt Caswell 已提交
130
    return C448_SUCCESS;
M
Matt Caswell 已提交
131 132
}

M
Matt Caswell 已提交
133
c448_error_t c448_ed448_sign(
134 135 136
                        uint8_t signature[EDDSA_448_SIGNATURE_BYTES],
                        const uint8_t privkey[EDDSA_448_PRIVATE_BYTES],
                        const uint8_t pubkey[EDDSA_448_PUBLIC_BYTES],
137 138 139
                        const uint8_t *message, size_t message_len,
                        uint8_t prehashed, const uint8_t *context,
                        size_t context_len)
140
{
M
Matt Caswell 已提交
141
    curve448_scalar_t secret_scalar;
142
    EVP_MD_CTX *hashctx = EVP_MD_CTX_new();
M
Matt Caswell 已提交
143
    c448_error_t ret = C448_FAILURE;
M
Matt Caswell 已提交
144
    curve448_scalar_t nonce_scalar;
145
    uint8_t nonce_point[EDDSA_448_PUBLIC_BYTES] = { 0 };
M
Matt Caswell 已提交
146 147
    unsigned int c;
    curve448_scalar_t challenge_scalar;
148 149

    if (hashctx == NULL)
M
Matt Caswell 已提交
150
        return C448_FAILURE;
151

M
Matt Caswell 已提交
152
    {
153 154 155 156 157
        /*
         * Schedule the secret key, First EDDSA_448_PRIVATE_BYTES is serialised
         * secret scalar,next EDDSA_448_PRIVATE_BYTES bytes is the seed.
         */
        uint8_t expanded[EDDSA_448_PRIVATE_BYTES * 2];
158

159
        if (!oneshot_hash(expanded, sizeof(expanded), privkey,
160
                          EDDSA_448_PRIVATE_BYTES))
161
            goto err;
162 163 164
        clamp(expanded);
        curve448_scalar_decode_long(secret_scalar, expanded,
                                    EDDSA_448_PRIVATE_BYTES);
165

M
Matt Caswell 已提交
166
        /* Hash to create the nonce */
167
        if (!hash_init_with_dom(hashctx, prehashed, 0, context, context_len)
M
Matt Caswell 已提交
168 169 170 171 172
                || !EVP_DigestUpdate(hashctx,
                                     expanded + EDDSA_448_PRIVATE_BYTES,
                                     EDDSA_448_PRIVATE_BYTES)
                || !EVP_DigestUpdate(hashctx, message, message_len)) {
                OPENSSL_cleanse(expanded, sizeof(expanded));
173 174
            goto err;
        }
175
        OPENSSL_cleanse(expanded, sizeof(expanded));
M
Matt Caswell 已提交
176
    }
177

M
Matt Caswell 已提交
178 179
    /* Decode the nonce */
    {
180
        uint8_t nonce[2 * EDDSA_448_PRIVATE_BYTES];
181 182 183

        if (!EVP_DigestFinalXOF(hashctx, nonce, sizeof(nonce)))
            goto err;
M
Matt Caswell 已提交
184
        curve448_scalar_decode_long(nonce_scalar, nonce, sizeof(nonce));
185
        OPENSSL_cleanse(nonce, sizeof(nonce));
M
Matt Caswell 已提交
186
    }
M
Matt Caswell 已提交
187

M
Matt Caswell 已提交
188 189
    {
        /* Scalarmul to create the nonce-point */
M
Matt Caswell 已提交
190
        curve448_scalar_t nonce_scalar_2;
M
Matt Caswell 已提交
191 192
        curve448_point_t p;

193
        curve448_scalar_halve(nonce_scalar_2, nonce_scalar);
194
        for (c = 2; c < C448_EDDSA_ENCODE_RATIO; c <<= 1) {
195
            curve448_scalar_halve(nonce_scalar_2, nonce_scalar_2);
M
Matt Caswell 已提交
196
        }
M
Matt Caswell 已提交
197

198 199
        curve448_precomputed_scalarmul(p, curve448_precomputed_base,
                                       nonce_scalar_2);
M
Matt Caswell 已提交
200 201 202
        curve448_point_mul_by_ratio_and_encode_like_eddsa(nonce_point, p);
        curve448_point_destroy(p);
        curve448_scalar_destroy(nonce_scalar_2);
M
Matt Caswell 已提交
203
    }
M
Matt Caswell 已提交
204

M
Matt Caswell 已提交
205
    {
206
        uint8_t challenge[2 * EDDSA_448_PRIVATE_BYTES];
207 208 209

        /* Compute the challenge */
        if (!hash_init_with_dom(hashctx, prehashed, 0, context, context_len)
210
            || !EVP_DigestUpdate(hashctx, nonce_point, sizeof(nonce_point))
211
            || !EVP_DigestUpdate(hashctx, pubkey, EDDSA_448_PUBLIC_BYTES)
212 213
            || !EVP_DigestUpdate(hashctx, message, message_len)
            || !EVP_DigestFinalXOF(hashctx, challenge, sizeof(challenge)))
214 215
            goto err;

216 217 218
        curve448_scalar_decode_long(challenge_scalar, challenge,
                                    sizeof(challenge));
        OPENSSL_cleanse(challenge, sizeof(challenge));
M
Matt Caswell 已提交
219
    }
220 221 222 223

    curve448_scalar_mul(challenge_scalar, challenge_scalar, secret_scalar);
    curve448_scalar_add(challenge_scalar, challenge_scalar, nonce_scalar);

224
    OPENSSL_cleanse(signature, EDDSA_448_SIGNATURE_BYTES);
225
    memcpy(signature, nonce_point, sizeof(nonce_point));
226
    curve448_scalar_encode(&signature[EDDSA_448_PUBLIC_BYTES],
227 228
                           challenge_scalar);

M
Matt Caswell 已提交
229 230 231
    curve448_scalar_destroy(secret_scalar);
    curve448_scalar_destroy(nonce_scalar);
    curve448_scalar_destroy(challenge_scalar);
232

M
Matt Caswell 已提交
233
    ret = C448_SUCCESS;
234 235 236
 err:
    EVP_MD_CTX_free(hashctx);
    return ret;
M
Matt Caswell 已提交
237 238
}

M
Matt Caswell 已提交
239
c448_error_t c448_ed448_sign_prehash(
240 241 242
                        uint8_t signature[EDDSA_448_SIGNATURE_BYTES],
                        const uint8_t privkey[EDDSA_448_PRIVATE_BYTES],
                        const uint8_t pubkey[EDDSA_448_PUBLIC_BYTES],
M
Matt Caswell 已提交
243 244
                        const uint8_t hash[64], const uint8_t *context,
                        size_t context_len)
245
{
M
Matt Caswell 已提交
246 247
    return c448_ed448_sign(signature, privkey, pubkey, hash, 64, 1, context,
                           context_len);
M
Matt Caswell 已提交
248 249
}

M
Matt Caswell 已提交
250
c448_error_t c448_ed448_verify(
251 252
                    const uint8_t signature[EDDSA_448_SIGNATURE_BYTES],
                    const uint8_t pubkey[EDDSA_448_PUBLIC_BYTES],
M
Matt Caswell 已提交
253 254 255
                    const uint8_t *message, size_t message_len,
                    uint8_t prehashed, const uint8_t *context,
                    uint8_t context_len)
256
{
M
Matt Caswell 已提交
257
    curve448_point_t pk_point, r_point;
M
Matt Caswell 已提交
258
    c448_error_t error =
259
        curve448_point_decode_like_eddsa_and_mul_by_ratio(pk_point, pubkey);
M
Matt Caswell 已提交
260 261 262 263
    curve448_scalar_t challenge_scalar;
    curve448_scalar_t response_scalar;
    unsigned int c;

M
Matt Caswell 已提交
264
    if (C448_SUCCESS != error)
265 266 267 268
        return error;

    error =
        curve448_point_decode_like_eddsa_and_mul_by_ratio(r_point, signature);
M
Matt Caswell 已提交
269
    if (C448_SUCCESS != error)
270 271
        return error;

M
Matt Caswell 已提交
272 273
    {
        /* Compute the challenge */
274
        EVP_MD_CTX *hashctx = EVP_MD_CTX_new();
275
        uint8_t challenge[2 * EDDSA_448_PRIVATE_BYTES];
276 277

        if (hashctx == NULL
278 279 280 281 282 283
                || !hash_init_with_dom(hashctx, prehashed, 0, context,
                                       context_len)
                || !EVP_DigestUpdate(hashctx, signature, EDDSA_448_PUBLIC_BYTES)
                || !EVP_DigestUpdate(hashctx, pubkey, EDDSA_448_PUBLIC_BYTES)
                || !EVP_DigestUpdate(hashctx, message, message_len)
                || !EVP_DigestFinalXOF(hashctx, challenge, sizeof(challenge))) {
284
            EVP_MD_CTX_free(hashctx);
M
Matt Caswell 已提交
285
            return C448_FAILURE;
286 287 288
        }

        EVP_MD_CTX_free(hashctx);
289 290 291
        curve448_scalar_decode_long(challenge_scalar, challenge,
                                    sizeof(challenge));
        OPENSSL_cleanse(challenge, sizeof(challenge));
M
Matt Caswell 已提交
292
    }
293 294 295 296
    curve448_scalar_sub(challenge_scalar, curve448_scalar_zero,
                        challenge_scalar);

    curve448_scalar_decode_long(response_scalar,
297 298
                                &signature[EDDSA_448_PUBLIC_BYTES],
                                EDDSA_448_PRIVATE_BYTES);
299

300
    for (c = 1; c < C448_EDDSA_DECODE_RATIO; c <<= 1)
301 302
        curve448_scalar_add(response_scalar, response_scalar, response_scalar);

M
Matt Caswell 已提交
303
    /* pk_point = -c(x(P)) + (cx + k)G = kG */
304 305 306
    curve448_base_double_scalarmul_non_secret(pk_point,
                                              response_scalar,
                                              pk_point, challenge_scalar);
M
Matt Caswell 已提交
307
    return c448_succeed_if(curve448_point_eq(pk_point, r_point));
M
Matt Caswell 已提交
308 309
}

M
Matt Caswell 已提交
310
c448_error_t c448_ed448_verify_prehash(
311 312
                    const uint8_t signature[EDDSA_448_SIGNATURE_BYTES],
                    const uint8_t pubkey[EDDSA_448_PUBLIC_BYTES],
313 314
                    const uint8_t hash[64], const uint8_t *context,
                    uint8_t context_len)
315
{
M
Matt Caswell 已提交
316
    c448_error_t ret;
317

M
Matt Caswell 已提交
318 319
    ret = c448_ed448_verify(signature, pubkey, hash, 64, 1, context,
                            context_len);
320

M
Matt Caswell 已提交
321 322
    return ret;
}
M
Matt Caswell 已提交
323 324

int ED448_sign(uint8_t *out_sig, const uint8_t *message, size_t message_len,
M
Matt Caswell 已提交
325
               const uint8_t public_key[57], const uint8_t private_key[57],
M
Matt Caswell 已提交
326 327
               const uint8_t *context, size_t context_len)
{
M
Matt Caswell 已提交
328

M
Matt Caswell 已提交
329 330 331
    return c448_ed448_sign(out_sig, private_key, public_key, message,
                           message_len, 0, context, context_len)
        == C448_SUCCESS;
M
Matt Caswell 已提交
332 333 334
}

int ED448_verify(const uint8_t *message, size_t message_len,
M
Matt Caswell 已提交
335
                 const uint8_t signature[114], const uint8_t public_key[57],
M
Matt Caswell 已提交
336 337
                 const uint8_t *context, size_t context_len)
{
M
Matt Caswell 已提交
338
    return c448_ed448_verify(signature, public_key, message, message_len, 0,
M
Matt Caswell 已提交
339
                             context, (uint8_t)context_len) == C448_SUCCESS;
M
Matt Caswell 已提交
340 341
}

M
Matt Caswell 已提交
342
int ED448ph_sign(uint8_t *out_sig, const uint8_t hash[64],
M
Matt Caswell 已提交
343
                 const uint8_t public_key[57], const uint8_t private_key[57],
M
Matt Caswell 已提交
344 345
                 const uint8_t *context, size_t context_len)
{
M
Matt Caswell 已提交
346 347
    return c448_ed448_sign_prehash(out_sig, private_key, public_key, hash,
                                   context, context_len) == C448_SUCCESS;
M
Matt Caswell 已提交
348

M
Matt Caswell 已提交
349
}
M
Matt Caswell 已提交
350

M
Matt Caswell 已提交
351 352
int ED448ph_verify(const uint8_t hash[64], const uint8_t signature[114],
                   const uint8_t public_key[57], const uint8_t *context,
M
Matt Caswell 已提交
353 354
                   size_t context_len)
{
M
Matt Caswell 已提交
355
    return c448_ed448_verify_prehash(signature, public_key, hash, context,
M
Matt Caswell 已提交
356
                                     (uint8_t)context_len) == C448_SUCCESS;
M
Matt Caswell 已提交
357 358
}

M
Matt Caswell 已提交
359
int ED448_public_from_private(uint8_t out_public_key[57],
360
                              const uint8_t private_key[57])
M
Matt Caswell 已提交
361
{
M
Matt Caswell 已提交
362 363
    return c448_ed448_derive_public_key(out_public_key, private_key)
        == C448_SUCCESS;
M
Matt Caswell 已提交
364
}