diff options
Diffstat (limited to 'eddsa-verify.c')
-rw-r--r-- | eddsa-verify.c | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/eddsa-verify.c b/eddsa-verify.c new file mode 100644 index 00000000..85b751e9 --- /dev/null +++ b/eddsa-verify.c @@ -0,0 +1,120 @@ +/* eddsa-verify.c + + Copyright (C) 2014 Niels Möller + + This file is part of GNU Nettle. + + GNU Nettle is free software: you can redistribute it and/or + modify it under the terms of either: + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your + option) any later version. + + or both in parallel, as here. + + GNU Nettle is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see http://www.gnu.org/licenses/. +*/ + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include <assert.h> + +#include "eddsa.h" + +#include "ecc.h" +#include "ecc-internal.h" +#include "nettle-meta.h" + +/* FIXME: Use mpn_zero_p. Also duplicated in ecc-ecdsa-verify.c. */ +static int +zero_p (const mp_limb_t *xp, mp_size_t n) +{ + while (n > 0) + if (xp[--n] > 0) + return 0; + return 1; +} + +mp_size_t +_eddsa_verify_itch (const struct ecc_curve *ecc) +{ + return 8*ecc->p.size + ecc->mul_itch; +} + +int +_eddsa_verify (const struct ecc_curve *ecc, + const struct nettle_hash *H, + const uint8_t *pub, + void *ctx, + const mp_limb_t *A, + size_t length, + const uint8_t *msg, + const uint8_t *signature, + mp_limb_t *scratch) +{ + size_t nbytes; +#define R scratch +#define sp (scratch + 2*ecc->p.size) +#define hp (scratch + 3*ecc->p.size) +#define P (scratch + 5*ecc->p.size) +#define scratch_out (scratch + 8*ecc->p.size) +#define S R +#define hash ((uint8_t *) P) + + nbytes = 1 + ecc->p.bit_size / 8; + + /* Could maybe save some storage by delaying the R and S operations, + but it makes sense to check them for validity up front. */ + if (!_eddsa_decompress (ecc, R, signature, R+2*ecc->p.size)) + return 0; + + mpn_set_base256_le (sp, ecc->q.size, signature + nbytes, nbytes); + /* Check that s < q */ + if (mpn_cmp (sp, ecc->q.m, ecc->q.size) >= 0) + return 0; + + H->init (ctx); + H->update (ctx, nbytes, signature); + H->update (ctx, nbytes, pub); + H->update (ctx, length, msg); + H->digest (ctx, 2*nbytes, hash); + _eddsa_hash (&ecc->q, hp, hash); + + /* Compute h A + R - s G, which should be the neutral point */ + ecc->mul (ecc, P, hp, A, scratch_out); + /* FIXME: Introduce an ecc->add method? */ + ecc_add_eh (ecc, P, P, R, scratch_out); + /* Produces s in the range 1 <= s <= q, with no carry. */ + mpn_sub_n (hp, ecc->q.m, sp, ecc->q.size); + ecc->mul_g (ecc, S, hp, scratch_out); + ecc_add_ehh (ecc, P, P, S, scratch_out); + + /* Zero point iff x == 0 (mod p) iff (x == 0 or x == p) */ + /* FIXME: Needs to differentiate between (0,1) and (0,-1). Implement + point compare instead of the above ecc_add_ehh? + /* FIXME: Introduce zero_p method? */ + return (zero_p (P, ecc->p.size) + || mpn_cmp (P, ecc->p.m, ecc->p.size) == 0); + +#undef R +#undef sp +#undef hp +#undef P +#undef S +} |