Commit 42e410bf authored by Niels Möller's avatar Niels Möller

Update eddsa internals to support ed448.

parent bbc64730
...@@ -2,6 +2,21 @@ ...@@ -2,6 +2,21 @@
* eddsa-internal.h (struct ecc_eddsa): Add magic "dom" string, * eddsa-internal.h (struct ecc_eddsa): Add magic "dom" string,
needed for ed448. needed for ed448.
* ed25519-sha512.c (_nettle_ed25519_sha512): Empty dom string.
* ed448-shake256.c (_nettle_ed448_shake256): New file and
parameter struct.
* eddsa-hash.c (_eddsa_hash): Add digest_size as input argument.
Handle ed448 digests with two extra bytes. Update callers.
* eddsa-verify.c (_eddsa_verify): Hash dom string.
* eddsa-sign.c (_eddsa_sign_itch): Assert that
_eddsa_compress_itch isn't too large.
(_eddsa_sign): New argument k1, with the hash prefix. Add hashing
of this prefix and the dom string. Update callers. Fix final
reduction, it's different for ed25519, with q slightly larger than
a power of two, and ed448, with q slightly smaller.
* eddsa-pubkey.c (_eddsa_public_key_itch): Assert that
_eddsa_compress_itch isn't too large.
2020-01-01 Niels Möller <nisse@lysator.liu.se> 2020-01-01 Niels Möller <nisse@lysator.liu.se>
......
...@@ -52,14 +52,13 @@ ed25519_sha512_sign (const uint8_t *pub, ...@@ -52,14 +52,13 @@ ed25519_sha512_sign (const uint8_t *pub,
#define scratch_out (scratch + ecc->q.size) #define scratch_out (scratch + ecc->q.size)
struct sha512_ctx ctx; struct sha512_ctx ctx;
uint8_t digest[SHA512_DIGEST_SIZE]; uint8_t digest[SHA512_DIGEST_SIZE];
#define k1 (digest + ED25519_KEY_SIZE)
sha512_init (&ctx); sha512_init (&ctx);
_eddsa_expand_key (ecc, &_nettle_ed25519_sha512, &ctx, priv, digest, k2); _eddsa_expand_key (ecc, &_nettle_ed25519_sha512, &ctx, priv, digest, k2);
sha512_update (&ctx, ED25519_KEY_SIZE, k1); _eddsa_sign (ecc, &_nettle_ed25519_sha512, &ctx,
_eddsa_sign (ecc, &_nettle_ed25519_sha512, pub, pub, digest + ED25519_KEY_SIZE, k2,
&ctx, length, msg, signature, scratch_out);
k2, length, msg, signature, scratch_out);
gmp_free_limbs (scratch, itch); gmp_free_limbs (scratch, itch);
#undef k1 #undef k1
......
/* eddsa-hash.c /* eddsa-hash.c
Copyright (C) 2014 Niels Möller Copyright (C) 2014, 2019 Niels Möller
Copyright (C) 2017 Daiki Ueno
Copyright (C) 2017 Red Hat, Inc.
This file is part of GNU Nettle. This file is part of GNU Nettle.
...@@ -42,11 +44,35 @@ ...@@ -42,11 +44,35 @@
#include "ecc-internal.h" #include "ecc-internal.h"
#include "nettle-internal.h" #include "nettle-internal.h"
/* Convert hash digest to integer, and reduce modulo q, to m->size
limbs. Needs space for 2*m->size + 1 at rp. */
void void
_eddsa_hash (const struct ecc_modulo *m, _eddsa_hash (const struct ecc_modulo *m,
mp_limb_t *rp, const uint8_t *digest) mp_limb_t *rp, size_t digest_size, const uint8_t *digest)
{ {
size_t nbytes = 1 + m->bit_size / 8; mp_size_t nlimbs = (8*digest_size + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS;
mpn_set_base256_le (rp, 2*m->size, digest, 2*nbytes);
mpn_set_base256_le (rp, nlimbs, digest, digest_size);
if (nlimbs > 2*m->size)
{
/* Special case for Ed448: reduce rp to 2*m->size limbs.
After decoding rp from a hash of size 2*rn:
rp = r2 || r1 || r0
where r0 and r1 have m->size limbs. Reduce this to:
rp = r1' || r0
where r1' has m->size limbs. */
mp_limb_t hi = rp[2*m->size];
assert (nlimbs == 2*m->size + 1);
hi = mpn_addmul_1 (rp + m->size, m->B, m->size, hi);
assert (hi <= 1);
hi = cnd_add_n (hi, rp + m->size, m->B, m->size);
assert (hi == 0);
}
m->mod (m, rp); m->mod (m, rp);
} }
...@@ -82,7 +82,7 @@ _eddsa_decompress (const struct ecc_curve *ecc, mp_limb_t *p, ...@@ -82,7 +82,7 @@ _eddsa_decompress (const struct ecc_curve *ecc, mp_limb_t *p,
void void
_eddsa_hash (const struct ecc_modulo *m, _eddsa_hash (const struct ecc_modulo *m,
mp_limb_t *rp, const uint8_t *digest); mp_limb_t *rp, size_t digest_size, const uint8_t *digest);
mp_size_t mp_size_t
_eddsa_sign_itch (const struct ecc_curve *ecc); _eddsa_sign_itch (const struct ecc_curve *ecc);
...@@ -90,8 +90,9 @@ _eddsa_sign_itch (const struct ecc_curve *ecc); ...@@ -90,8 +90,9 @@ _eddsa_sign_itch (const struct ecc_curve *ecc);
void void
_eddsa_sign (const struct ecc_curve *ecc, _eddsa_sign (const struct ecc_curve *ecc,
const struct ecc_eddsa *eddsa, const struct ecc_eddsa *eddsa,
const uint8_t *pub,
void *ctx, void *ctx,
const uint8_t *pub,
const uint8_t *k1,
const mp_limb_t *k2, const mp_limb_t *k2,
size_t length, size_t length,
const uint8_t *msg, const uint8_t *msg,
......
...@@ -33,6 +33,8 @@ ...@@ -33,6 +33,8 @@
# include "config.h" # include "config.h"
#endif #endif
#include <assert.h>
#include "eddsa.h" #include "eddsa.h"
#include "eddsa-internal.h" #include "eddsa-internal.h"
...@@ -41,6 +43,7 @@ ...@@ -41,6 +43,7 @@
mp_size_t mp_size_t
_eddsa_public_key_itch (const struct ecc_curve *ecc) _eddsa_public_key_itch (const struct ecc_curve *ecc)
{ {
assert (_eddsa_compress_itch (ecc) <= ecc->mul_g_itch);
return 3*ecc->p.size + ecc->mul_g_itch; return 3*ecc->p.size + ecc->mul_g_itch;
} }
......
...@@ -45,14 +45,16 @@ ...@@ -45,14 +45,16 @@
mp_size_t mp_size_t
_eddsa_sign_itch (const struct ecc_curve *ecc) _eddsa_sign_itch (const struct ecc_curve *ecc)
{ {
assert (_eddsa_compress_itch (ecc) <= ecc->mul_g_itch);
return 5*ecc->p.size + ecc->mul_g_itch; return 5*ecc->p.size + ecc->mul_g_itch;
} }
void void
_eddsa_sign (const struct ecc_curve *ecc, _eddsa_sign (const struct ecc_curve *ecc,
const struct ecc_eddsa *eddsa, const struct ecc_eddsa *eddsa,
const uint8_t *pub,
void *ctx, void *ctx,
const uint8_t *pub,
const uint8_t *k1,
const mp_limb_t *k2, const mp_limb_t *k2,
size_t length, size_t length,
const uint8_t *msg, const uint8_t *msg,
...@@ -61,6 +63,8 @@ _eddsa_sign (const struct ecc_curve *ecc, ...@@ -61,6 +63,8 @@ _eddsa_sign (const struct ecc_curve *ecc,
{ {
mp_size_t size; mp_size_t size;
size_t nbytes; size_t nbytes;
mp_limb_t q, cy;
#define rp scratch #define rp scratch
#define hp (scratch + size) #define hp (scratch + size)
#define P (scratch + 2*size) #define P (scratch + 2*size)
...@@ -71,32 +75,51 @@ _eddsa_sign (const struct ecc_curve *ecc, ...@@ -71,32 +75,51 @@ _eddsa_sign (const struct ecc_curve *ecc,
size = ecc->p.size; size = ecc->p.size;
nbytes = 1 + ecc->p.bit_size / 8; nbytes = 1 + ecc->p.bit_size / 8;
eddsa->update (ctx, eddsa->dom_size, eddsa->dom);
eddsa->update (ctx, nbytes, k1);
eddsa->update (ctx, length, msg); eddsa->update (ctx, length, msg);
eddsa->digest (ctx, 2*nbytes, hash); eddsa->digest (ctx, 2*nbytes, hash);
_eddsa_hash (&ecc->q, rp, hash); _eddsa_hash (&ecc->q, rp, 2*nbytes, hash);
ecc->mul_g (ecc, P, rp, scratch_out); ecc->mul_g (ecc, P, rp, scratch_out);
_eddsa_compress (ecc, signature, P, scratch_out); _eddsa_compress (ecc, signature, P, scratch_out);
eddsa->update (ctx, eddsa->dom_size, eddsa->dom);
eddsa->update (ctx, nbytes, signature); eddsa->update (ctx, nbytes, signature);
eddsa->update (ctx, nbytes, pub); eddsa->update (ctx, nbytes, pub);
eddsa->update (ctx, length, msg); eddsa->update (ctx, length, msg);
eddsa->digest (ctx, 2*nbytes, hash); eddsa->digest (ctx, 2*nbytes, hash);
_eddsa_hash (&ecc->q, hp, hash); _eddsa_hash (&ecc->q, hp, 2*nbytes, hash);
ecc_modq_mul (ecc, sp, hp, k2); ecc_modq_mul (ecc, sp, hp, k2);
ecc_modq_add (ecc, sp, sp, rp); /* FIXME: Can be plain add */ ecc_modq_add (ecc, sp, sp, rp); /* FIXME: Can be plain add */
/* FIXME: Special code duplicated in ecc_25519_modq and ecc_eh_to_a. if (ecc->p.bit_size == 255)
Define a suitable method? */ {
{ /* FIXME: Special code duplicated in ecc_25519_modq
unsigned shift; Define a suitable method for canonical reduction? */
mp_limb_t cy;
assert (ecc->p.bit_size == 255); /* q is slightly larger than 2^252, underflow from below
shift = ecc->q.bit_size - 1 - GMP_NUMB_BITS * (ecc->p.size - 1); mpn_submul_1 is unlikely. */
cy = mpn_submul_1 (sp, ecc->q.m, ecc->p.size, unsigned shift = 252 - GMP_NUMB_BITS * (ecc->p.size - 1);
sp[ecc->p.size-1] >> shift); q = sp[ecc->p.size-1] >> shift;
assert (cy < 2); }
cnd_add_n (cy, sp, ecc->q.m, ecc->p.size); else
} {
unsigned shift;
assert (ecc->p.bit_size == 448);
/* q is slightly smaller than 2^446 */
shift = 446 - GMP_NUMB_BITS * (ecc->p.size - 1);
/* Add one, then it's possible but unlikely that below
mpn_submul_1 does *not* underflow. */
q = (sp[ecc->p.size-1] >> shift) + 1;
}
cy = mpn_submul_1 (sp, ecc->q.m, ecc->p.size, q);
assert (cy < 2);
cy -= cnd_add_n (cy, sp, ecc->q.m, ecc->p.size);
assert (cy == 0);
mpn_get_base256_le (signature + nbytes, nbytes, sp, ecc->q.size); mpn_get_base256_le (signature + nbytes, nbytes, sp, ecc->q.size);
#undef rp #undef rp
#undef hp #undef hp
......
...@@ -106,11 +106,12 @@ _eddsa_verify (const struct ecc_curve *ecc, ...@@ -106,11 +106,12 @@ _eddsa_verify (const struct ecc_curve *ecc,
if (mpn_cmp (sp, ecc->q.m, ecc->q.size) >= 0) if (mpn_cmp (sp, ecc->q.m, ecc->q.size) >= 0)
return 0; return 0;
eddsa->update (ctx, eddsa->dom_size, eddsa->dom);
eddsa->update (ctx, nbytes, signature); eddsa->update (ctx, nbytes, signature);
eddsa->update (ctx, nbytes, pub); eddsa->update (ctx, nbytes, pub);
eddsa->update (ctx, length, msg); eddsa->update (ctx, length, msg);
eddsa->digest (ctx, 2*nbytes, hash); eddsa->digest (ctx, 2*nbytes, hash);
_eddsa_hash (&ecc->q, hp, hash); _eddsa_hash (&ecc->q, hp, 2*nbytes, hash);
/* Compute h A + R - s G, which should be the neutral point */ /* Compute h A + R - s G, which should be the neutral point */
ecc->mul (ecc, P, hp, A, scratch_out); ecc->mul (ecc, P, hp, A, scratch_out);
......
...@@ -69,9 +69,8 @@ test_eddsa_sign (const struct ecc_curve *ecc, ...@@ -69,9 +69,8 @@ test_eddsa_sign (const struct ecc_curve *ecc,
fprintf (stderr, "\n"); fprintf (stderr, "\n");
abort (); abort ();
} }
eddsa->update (ctx, nbytes, k1); _eddsa_sign (ecc, eddsa, ctx,
public->data, k1, k2,
_eddsa_sign (ecc, eddsa, public->data, ctx, k2,
msg->length, msg->data, signature, scratch); msg->length, msg->data, signature, scratch);
if (!MEMEQ (2*nbytes, signature, ref->data)) if (!MEMEQ (2*nbytes, signature, ref->data))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment