From a53f9876f502ee1185d4029e9cf18d602fb351ef Mon Sep 17 00:00:00 2001 From: Michael Hamburg Date: Tue, 23 Jun 2015 19:00:59 -0700 Subject: [PATCH] OK, most tests are now passing. Remaining known problems: 1) Elligator inversion fails on 0. Also there may be corner cases here which ought to be probed but are a pain, such as sqrt(id/(1-d)) and similar. 2) Elligator doesn't return the right hint, because I haven't coded the rotation hints. Probable solution: make Elligator not return a hint, because there's no realistic scenario where it's useful anyway. Alternative possible solution: can compute the right hint, but why bother? 3) Elligator inversion doesn't set the high bit of the buffer at random, because 2^255-19 isn't close to 2^256. Possible solution: preserve the high bit(s) of the buffer? 4) Elligator doesn't map [1] to the identity, I think. 5) Not enough corner case testing. 6) Probably some other non-Elligator problems --- include/shake.hxx | 2 +- src/decaf_fast.c | 12 +++---- test/test_decaf.cxx | 82 ++++++++++++++++++++++++++++++++++++++------- 3 files changed, 77 insertions(+), 19 deletions(-) diff --git a/include/shake.hxx b/include/shake.hxx index aa92a22..613442c 100644 --- a/include/shake.hxx +++ b/include/shake.hxx @@ -208,7 +208,7 @@ inline SecureBuffer Ed255::Point::steg_encode(SpongeRng &rng) const NOEXCEPT { bool done; do { rng.read(out.slice(HASH_BYTES-1,STEG_BYTES-HASH_BYTES+1)); - done = invert_elligator(out, out[HASH_BYTES-1] & 7); /* FIXME 7 is kind of MAGIC */ + done = invert_elligator(out, out[HASH_BYTES-1]); } while (!done); return out; } diff --git a/src/decaf_fast.c b/src/decaf_fast.c index d1b6a01..e9b0618 100644 --- a/src/decaf_fast.c +++ b/src/decaf_fast.c @@ -509,15 +509,14 @@ static void deisogenize ( gf e; gf_sqr(e, t); gf_mul(a, e, b); - rotate = hibit(a); + rotate = hibit(a) ^ toggle_rotation; /* * Curve25519: cond select between zx * 1/tz or sqrt(1-d); y=-x * Pink bike shed: frob = zx * 1/tz */ gf_mul ( a, b, c ); /* this is the case for PinkBikeShed */ - cond_sel ( a, a, SQRT_ONE_MINUS_D, rotate^toggle_rotation ); - gf_sub ( e, ZERO, x ); - cond_sel ( x, p->y, e, rotate ); + cond_sel ( a, a, SQRT_ONE_MINUS_D, rotate ); + cond_sel ( x, p->y, x, rotate ); } @@ -526,7 +525,7 @@ static void deisogenize ( gf_add ( a, a, a ); // 2 * "osx" * Z decaf_bool_t tg1 = rotate ^ toggle_hibit_t_over_s ^~ hibit(a); cond_neg ( c, tg1 ); - cond_neg ( a, tg1 ); + cond_neg ( a, rotate ^ tg1 ); gf_mul ( d, b, p->z ); gf_add ( d, d, c ); gf_mul ( b, d, x ); /* here "x" = y unless rotate */ @@ -1173,8 +1172,9 @@ decaf_bool_t API_NS(invert_elligator_nonuniform) ( unsigned char recovered_hash[DECAF_255_SER_BYTES], const point_t p, - uint16_t hint + uint16_t hint_ ) { + uint64_t hint = hint_; decaf_bool_t sgn_s = -(hint & 1), sgn_t_over_s = -(hint>>1 & 1), sgn_r0 = -(hint>>2 & 1), diff --git a/test/test_decaf.cxx b/test/test_decaf.cxx index 6ad23e8..7fdb33a 100644 --- a/test/test_decaf.cxx +++ b/test/test_decaf.cxx @@ -57,6 +57,14 @@ static void print(const char *name, const Scalar &x) { printf("\n"); } +static void hexprint(const char *name, const decaf::SecureBuffer &buffer) { + printf(" %s = 0x", name); + for (int i=buffer.size()-1; i>=0; i--) { + printf("%02x", buffer[i]); + } + printf("\n"); +} + static void print(const char *name, const Point &x) { unsigned char buffer[Point::SER_BYTES]; x.encode(buffer); @@ -156,6 +164,7 @@ static void test_elligator() { decaf::SpongeRng rng(decaf::Block("test_elligator")); Test test("Elligator"); + /* for (int i=0; i<32; i++) { decaf::SecureBuffer b1(Point::HASH_BYTES); Point p = Point::identity(); @@ -171,26 +180,74 @@ static void test_elligator() { b1[0], b1[1]); } } + */ + + const int NHINTS = 1<<4; + decaf::SecureBuffer *alts[NHINTS]; + bool successes[NHINTS]; - for (int i=0; i Point::HASH_BYTES) - memcpy(&b2[Point::HASH_BYTES], &b1[Point::HASH_BYTES], len-Point::HASH_BYTES); - Point s; - unsigned char hint = s.set_to_hash(b1); + if (len >= Point::HASH_BYTES) b1[Point::HASH_BYTES-1] &= 0x7F; // FIXME MAGIC + Point s = Point::from_hash(b1); for (int j=0; j<(i&3); j++) s.debugging_torque_in_place(); - bool succ = s.invert_elligator(b2,hint); - if (!succ || memcmp(b1,b2,len)) { + + bool good = false; + for (int j=0; j Point::HASH_BYTES) + memcpy(&(*alts[j])[Point::HASH_BYTES], &b1[Point::HASH_BYTES], len-Point::HASH_BYTES); + + successes[j] = s.invert_elligator(*alts[j],j); + + if (successes[j]) { + good = good || (b1 == *alts[j]); + for (int k=0; k