@@ -0,0 +1,87 @@ | |||||
F = GF(2^255-19) | |||||
dM = F(-121665) | |||||
d = F(-121665/121666) | |||||
ii = sqrt(F(-1)) | |||||
def lobit(x): return int(x) & 1 | |||||
def hibit(x): return lobit(2*x) | |||||
magic = sqrt(F(-121666)) | |||||
if lobit(magic): magic = -magic | |||||
def eddsa_to_decaf(x,y): | |||||
""" | |||||
Converts an EdDSA point to a Decaf representation, in a manner compatible | |||||
with libdecaf. | |||||
The input point must be even. | |||||
Note well! Decaf does not represent the cofactor information of a point. | |||||
So e2d(d2e(s)) = s, but d2e(e2d(x,y)) might not be (x,y). | |||||
""" | |||||
if x*y == 0: return 0 # This will happen anyway with straightforward square root trick | |||||
if not is_square((1-y)/(1+y)): raise Exception("Unimplemented: odd point in eddsa_to_decaf") | |||||
if hibit(magic/(x*y)): (x,y) = (ii*y,ii*x) | |||||
if hibit(2*magic/x): y = -y | |||||
s = sqrt((1-y)/(1+y)) | |||||
if hibit(s): s = -s | |||||
return s | |||||
def isqrt_trick(to_isr,to_inv): | |||||
to_sqrt = to_isr*to_inv^2 | |||||
if to_sqrt == 0: return 0,0 # This happens automatically in C; just to avoid problems in SAGE | |||||
if not is_square(to_sqrt): raise Exception("Not square in isqrt_trick!") | |||||
tmp = 1/sqrt(to_sqrt) | |||||
isr = tmp * to_inv | |||||
inv = tmp * isr * to_isr | |||||
assert isr^2 == 1/to_isr | |||||
assert inv == 1/to_inv | |||||
return isr, inv | |||||
def eddsa_to_decaf_opt(x,y,z=None): | |||||
""" | |||||
Optimized version of eddsa_to_decaf. | |||||
Uses only one isqrt. | |||||
""" | |||||
if z is None: | |||||
# Pretend that we're in projective | |||||
z = F.random_element() | |||||
x *= z | |||||
y *= z | |||||
isr,inv = isqrt_trick(z^2-y^2,x*y) | |||||
inv *= magic | |||||
rotate = hibit(inv*z^2) | |||||
if rotate: | |||||
isr *= (z^2-y^2)*inv | |||||
y = ii*x | |||||
if hibit(2*inv*y*z) != rotate: y = -y | |||||
s = (z-y) * isr | |||||
if hibit(s): s = -s | |||||
return s | |||||
print [eddsa_to_decaf_opt(x,y) == eddsa_to_decaf(x,y) for _,_,_,_,y1,y2 in points for x,y in [decode(y1,y2)]] | |||||
def decaf_to_eddsa(s): | |||||
""" | |||||
Convert a Decaf representation to an EdDSA point, in a manner compatible | |||||
with libdecaf. | |||||
Note well! The Decaf representation of a point is canonical, but the EdDSA one | |||||
is not, in that | |||||
""" | |||||
if s == 0: return (0,1) | |||||
if hibit(s): raise Exception("invalid: s has high bit") | |||||
if not is_square(s^4 + (2-4*dM)*s^2 + 1): raise Exception("invalid: not on curve") | |||||
t = sqrt(s^4 + (2-4*dM)*s^2 + 1)/s | |||||
if hibit(t): t = -t | |||||
y = (1-s^2)/(1+s^2) | |||||
x = 2*magic/t | |||||
if y == 0 or lobit(t/y): raise Exception("invalid: t/y has high bit") | |||||
assert y^2 - x^2 == 1+d*x^2*y^2 | |||||
return (x,y) |
@@ -57,9 +57,13 @@ const uint8_t decaf_x25519_base_point[DECAF_X25519_PUBLIC_BYTES] = { 0x09 }; | |||||
/* End of template stuff */ | /* End of template stuff */ | ||||
/* Sanity */ | /* Sanity */ | ||||
#if (COFACTOR == 8) && !IMAGINE_TWIST | |||||
#if (COFACTOR == 8) && !IMAGINE_TWIST && !UNSAFE_CURVE_HAS_POINTS_AT_INFINITY | |||||
/* FUTURE MAGIC: Curve41417 doesn't have these properties. */ | /* FUTURE MAGIC: Curve41417 doesn't have these properties. */ | ||||
#error "Currently require IMAGINE_TWIST (and thus p=5 mod 8) for cofactor 8" | |||||
#error "Currently require IMAGINE_TWIST (and thus p=5 mod 8) for cofactor 8" | |||||
/* OK, but why? | |||||
* Two reasons: #1: There are bugs when COFACTOR == && IMAGINE_TWIST | |||||
# #2: | |||||
*/ | |||||
#endif | #endif | ||||
#if IMAGINE_TWIST && (P_MOD_8 != 5) | #if IMAGINE_TWIST && (P_MOD_8 != 5) | ||||
@@ -115,15 +119,6 @@ static mask_t gf_lobit(const gf x) { | |||||
/** identity = (0,1) */ | /** identity = (0,1) */ | ||||
const point_t API_NS(point_identity) = {{{{{0}}},{{{1}}},{{{1}}},{{{0}}}}}; | const point_t API_NS(point_identity) = {{{{{0}}},{{{1}}},{{{1}}},{{{0}}}}}; | ||||
void API_NS(deisogenize) ( | |||||
gf_s *__restrict__ s, | |||||
gf_s *__restrict__ minus_t_over_s, | |||||
const point_t p, | |||||
mask_t toggle_hibit_s, | |||||
mask_t toggle_hibit_t_over_s, | |||||
mask_t toggle_rotation | |||||
); | |||||
void API_NS(deisogenize) ( | void API_NS(deisogenize) ( | ||||
gf_s *__restrict__ s, | gf_s *__restrict__ s, | ||||
gf_s *__restrict__ minus_t_over_s, | gf_s *__restrict__ minus_t_over_s, | ||||
@@ -163,7 +158,7 @@ void API_NS(deisogenize) ( | |||||
#else | #else | ||||
/* More complicated because of rotation */ | /* More complicated because of rotation */ | ||||
/* MAGIC This code is wrong for certain non-Curve25519 curves; | /* MAGIC This code is wrong for certain non-Curve25519 curves; | ||||
* check if it's because of Cofactor==8 or IMAGINE_ROTATION */ | |||||
* check if it's because of Cofactor==8 or IMAGINE_TWIST */ | |||||
gf c, d; | gf c, d; | ||||
gf_s *b = s, *a = minus_t_over_s; | gf_s *b = s, *a = minus_t_over_s; | ||||
@@ -177,11 +172,11 @@ void API_NS(deisogenize) ( | |||||
gf_mul ( c, a, b ); /* "zx" = Z^2 - aX^2 = Z^2 - X^2 */ | gf_mul ( c, a, b ); /* "zx" = Z^2 - aX^2 = Z^2 - X^2 */ | ||||
#else | #else | ||||
const gf_s *x = p->x, *t = p->t; | const gf_s *x = p->x, *t = p->t; | ||||
/* Won't hit the gf_cond_sel below because COFACTOR==8 requires IMAGINE_TWIST for now. */ | |||||
gf_sqr ( a, p->z ); | gf_sqr ( a, p->z ); | ||||
gf_sqr ( b, p->x ); | gf_sqr ( b, p->x ); | ||||
gf_add ( c, a, b ); /* "zx" = Z^2 - aX^2 = Z^2 + X^2 */ | gf_add ( c, a, b ); /* "zx" = Z^2 - aX^2 = Z^2 + X^2 */ | ||||
#endif | #endif | ||||
/* Here: c = "zx" in the SAGE code = Z^2 - aX^2 */ | |||||
gf_mul ( a, p->z, t ); /* "tz" = T*Z */ | gf_mul ( a, p->z, t ); /* "tz" = T*Z */ | ||||
gf_sqr ( b, a ); | gf_sqr ( b, a ); | ||||
@@ -201,8 +196,9 @@ void API_NS(deisogenize) ( | |||||
/* Curve25519: cond select between zx * 1/tz or sqrt(1-d); y=-x */ | /* Curve25519: cond select between zx * 1/tz or sqrt(1-d); y=-x */ | ||||
gf_mul ( a, b, c ); | gf_mul ( a, b, c ); | ||||
gf_cond_sel ( a, a, SQRT_ONE_MINUS_D, rotate ); | gf_cond_sel ( a, a, SQRT_ONE_MINUS_D, rotate ); | ||||
gf_cond_sel ( x, p->y, x, rotate ); | |||||
gf_cond_sel ( e, p->y, x, rotate ); | |||||
#else | #else | ||||
const gf_s *e = x; | |||||
(void)toggle_rotation; | (void)toggle_rotation; | ||||
rotate = 0; | rotate = 0; | ||||
#endif | #endif | ||||
@@ -216,7 +212,7 @@ void API_NS(deisogenize) ( | |||||
gf_cond_neg ( minus_t_over_s, tg ); | gf_cond_neg ( minus_t_over_s, tg ); | ||||
gf_cond_neg ( c, rotate ^ tg ); | gf_cond_neg ( c, rotate ^ tg ); | ||||
gf_add ( d, d, c ); | gf_add ( d, d, c ); | ||||
gf_mul ( s, d, x ); /* here "x" = y unless rotate */ | |||||
gf_mul ( s, d, e ); /* here "x" = y unless rotate */ | |||||
gf_cond_neg ( s, toggle_hibit_s ^ gf_hibit(s) ); | gf_cond_neg ( s, toggle_hibit_s ^ gf_hibit(s) ); | ||||
#endif | #endif | ||||
} | } | ||||
@@ -236,24 +232,24 @@ decaf_error_t API_NS(point_decode) ( | |||||
mask_t succ = gf_deserialize(s, ser, 0); | mask_t succ = gf_deserialize(s, ser, 0); | ||||
mask_t zero = gf_eq(s, ZERO); | mask_t zero = gf_eq(s, ZERO); | ||||
succ &= bool_to_mask(allow_identity) | ~zero; | succ &= bool_to_mask(allow_identity) | ~zero; | ||||
gf_sqr ( a, s ); | |||||
gf_sqr ( a, s ); /* s^2 */ | |||||
#if IMAGINE_TWIST | #if IMAGINE_TWIST | ||||
gf_sub ( f, ONE, a ); /* f = 1-as^2 = 1-s^2*/ | gf_sub ( f, ONE, a ); /* f = 1-as^2 = 1-s^2*/ | ||||
#else | #else | ||||
gf_add ( f, ONE, a ); /* f = 1-as^2 = 1+s^2 */ | gf_add ( f, ONE, a ); /* f = 1-as^2 = 1+s^2 */ | ||||
#endif | #endif | ||||
succ &= ~ gf_eq( f, ZERO ); | succ &= ~ gf_eq( f, ZERO ); | ||||
gf_sqr ( b, f ); | |||||
gf_sqr ( b, f ); /* (1-as^2)^2 = 1 - 2as^2 + a^2 s^4 */ | |||||
gf_mulw ( c, a, 4*IMAGINE_TWIST-4*EDWARDS_D ); | gf_mulw ( c, a, 4*IMAGINE_TWIST-4*EDWARDS_D ); | ||||
gf_add ( c, c, b ); /* t^2 */ | |||||
gf_mul ( d, f, s ); /* s(1-as^2) for denoms */ | |||||
gf_sqr ( e, d ); | |||||
gf_mul ( b, c, e ); | |||||
gf_add ( c, c, b ); /* t^2 = 1 + (2a-4d) s^2 + s^4 */ | |||||
gf_mul ( d, f, s ); /* s * (1-as^2) for denoms */ | |||||
gf_sqr ( e, d ); /* s^2 * (1-as^2)^2 */ | |||||
gf_mul ( b, c, e ); /* t^2 * s^2 * (1-as^2)^2 */ | |||||
succ &= gf_isr(e,b) | gf_eq(b,ZERO); /* e = 1/(t s (1-as^2)) */ | succ &= gf_isr(e,b) | gf_eq(b,ZERO); /* e = 1/(t s (1-as^2)) */ | ||||
gf_mul ( b, e, d ); /* 1/t */ | |||||
gf_mul ( d, e, c ); /* d = t / (s(1-as^2)) */ | |||||
gf_mul ( e, d, f ); /* t/s */ | |||||
gf_mul ( b, e, d ); /* 1 / t */ | |||||
gf_mul ( d, e, c ); /* t / (s(1-as^2)) */ | |||||
gf_mul ( e, d, f ); /* t / s */ | |||||
mask_t negtos = gf_hibit(e); | mask_t negtos = gf_hibit(e); | ||||
gf_cond_neg(b, negtos); | gf_cond_neg(b, negtos); | ||||
gf_cond_neg(d, negtos); | gf_cond_neg(d, negtos); | ||||
@@ -279,8 +275,23 @@ decaf_error_t API_NS(point_decode) ( | |||||
#endif | #endif | ||||
gf_mul ( p->t, p->x, a ); /* T = 2s (1-as^2)/t */ | gf_mul ( p->t, p->x, a ); /* T = 2s (1-as^2)/t */ | ||||
p->y->limb[0] -= zero; | |||||
#if UNSAFE_CURVE_HAS_POINTS_AT_INFINITY | |||||
/* This can't happen for any of the supported configurations. | |||||
* | |||||
* If it can happen (because s=1), it's because the curve has points | |||||
* at infinity, which means that there may be critical security bugs | |||||
* elsewhere in the library. In that case, it's better that you hit | |||||
* the assertion in point_valid, which will happen in the test suite | |||||
* since it tests s=1. | |||||
* | |||||
* This debugging option is to allow testing of IMAGINE_TWIST = 0 on | |||||
* Ed25519, without hitting that assertion. Don't use it in | |||||
* production. | |||||
*/ | |||||
succ &= ~gf_eq(p->z,ZERO); | |||||
#endif | |||||
p->y->limb[0] -= zero; | |||||
assert(API_NS(point_valid)(p) | ~succ); | assert(API_NS(point_valid)(p) | ~succ); | ||||
return decaf_succeed_if(mask_to_bool(succ)); | return decaf_succeed_if(mask_to_bool(succ)); | ||||
@@ -822,7 +833,7 @@ void API_NS(point_debugging_torque) ( | |||||
point_t q, | point_t q, | ||||
const point_t p | const point_t p | ||||
) { | ) { | ||||
#if COFACTOR == 8 | |||||
#if COFACTOR == 8 && IMAGINE_TWIST | |||||
gf tmp; | gf tmp; | ||||
gf_mul(tmp,p->x,SQRT_MINUS_ONE); | gf_mul(tmp,p->x,SQRT_MINUS_ONE); | ||||
gf_mul(q->x,p->y,SQRT_MINUS_ONE); | gf_mul(q->x,p->y,SQRT_MINUS_ONE); | ||||
@@ -61,7 +61,7 @@ void API_NS(point_from_hash_nonuniform) ( | |||||
/* s@a = +-|N.e| */ | /* s@a = +-|N.e| */ | ||||
gf_mul(a,N,e); | gf_mul(a,N,e); | ||||
gf_cond_neg(a,gf_hibit(a)^square); /* NB this is - what is listen in the paper */ | |||||
gf_cond_neg(a,gf_hibit(a)^square); /* NB this is - what is listed in the paper */ | |||||
/* t@b = -+ cN(r-1)((a-2d)e)^2 - 1 */ | /* t@b = -+ cN(r-1)((a-2d)e)^2 - 1 */ | ||||
gf_mulw(c,e,1-2*EDWARDS_D); /* (a-2d)e */ | gf_mulw(c,e,1-2*EDWARDS_D); /* (a-2d)e */ | ||||
@@ -57,9 +57,13 @@ const uint8_t decaf_x448_base_point[DECAF_X448_PUBLIC_BYTES] = { 0x05 }; | |||||
/* End of template stuff */ | /* End of template stuff */ | ||||
/* Sanity */ | /* Sanity */ | ||||
#if (COFACTOR == 8) && !IMAGINE_TWIST | |||||
#if (COFACTOR == 8) && !IMAGINE_TWIST && !UNSAFE_CURVE_HAS_POINTS_AT_INFINITY | |||||
/* FUTURE MAGIC: Curve41417 doesn't have these properties. */ | /* FUTURE MAGIC: Curve41417 doesn't have these properties. */ | ||||
#error "Currently require IMAGINE_TWIST (and thus p=5 mod 8) for cofactor 8" | |||||
#error "Currently require IMAGINE_TWIST (and thus p=5 mod 8) for cofactor 8" | |||||
/* OK, but why? | |||||
* Two reasons: #1: There are bugs when COFACTOR == && IMAGINE_TWIST | |||||
# #2: | |||||
*/ | |||||
#endif | #endif | ||||
#if IMAGINE_TWIST && (P_MOD_8 != 5) | #if IMAGINE_TWIST && (P_MOD_8 != 5) | ||||
@@ -115,15 +119,6 @@ static mask_t gf_lobit(const gf x) { | |||||
/** identity = (0,1) */ | /** identity = (0,1) */ | ||||
const point_t API_NS(point_identity) = {{{{{0}}},{{{1}}},{{{1}}},{{{0}}}}}; | const point_t API_NS(point_identity) = {{{{{0}}},{{{1}}},{{{1}}},{{{0}}}}}; | ||||
void API_NS(deisogenize) ( | |||||
gf_s *__restrict__ s, | |||||
gf_s *__restrict__ minus_t_over_s, | |||||
const point_t p, | |||||
mask_t toggle_hibit_s, | |||||
mask_t toggle_hibit_t_over_s, | |||||
mask_t toggle_rotation | |||||
); | |||||
void API_NS(deisogenize) ( | void API_NS(deisogenize) ( | ||||
gf_s *__restrict__ s, | gf_s *__restrict__ s, | ||||
gf_s *__restrict__ minus_t_over_s, | gf_s *__restrict__ minus_t_over_s, | ||||
@@ -163,7 +158,7 @@ void API_NS(deisogenize) ( | |||||
#else | #else | ||||
/* More complicated because of rotation */ | /* More complicated because of rotation */ | ||||
/* MAGIC This code is wrong for certain non-Curve25519 curves; | /* MAGIC This code is wrong for certain non-Curve25519 curves; | ||||
* check if it's because of Cofactor==8 or IMAGINE_ROTATION */ | |||||
* check if it's because of Cofactor==8 or IMAGINE_TWIST */ | |||||
gf c, d; | gf c, d; | ||||
gf_s *b = s, *a = minus_t_over_s; | gf_s *b = s, *a = minus_t_over_s; | ||||
@@ -177,11 +172,11 @@ void API_NS(deisogenize) ( | |||||
gf_mul ( c, a, b ); /* "zx" = Z^2 - aX^2 = Z^2 - X^2 */ | gf_mul ( c, a, b ); /* "zx" = Z^2 - aX^2 = Z^2 - X^2 */ | ||||
#else | #else | ||||
const gf_s *x = p->x, *t = p->t; | const gf_s *x = p->x, *t = p->t; | ||||
/* Won't hit the gf_cond_sel below because COFACTOR==8 requires IMAGINE_TWIST for now. */ | |||||
gf_sqr ( a, p->z ); | gf_sqr ( a, p->z ); | ||||
gf_sqr ( b, p->x ); | gf_sqr ( b, p->x ); | ||||
gf_add ( c, a, b ); /* "zx" = Z^2 - aX^2 = Z^2 + X^2 */ | gf_add ( c, a, b ); /* "zx" = Z^2 - aX^2 = Z^2 + X^2 */ | ||||
#endif | #endif | ||||
/* Here: c = "zx" in the SAGE code = Z^2 - aX^2 */ | |||||
gf_mul ( a, p->z, t ); /* "tz" = T*Z */ | gf_mul ( a, p->z, t ); /* "tz" = T*Z */ | ||||
gf_sqr ( b, a ); | gf_sqr ( b, a ); | ||||
@@ -201,8 +196,9 @@ void API_NS(deisogenize) ( | |||||
/* Curve25519: cond select between zx * 1/tz or sqrt(1-d); y=-x */ | /* Curve25519: cond select between zx * 1/tz or sqrt(1-d); y=-x */ | ||||
gf_mul ( a, b, c ); | gf_mul ( a, b, c ); | ||||
gf_cond_sel ( a, a, SQRT_ONE_MINUS_D, rotate ); | gf_cond_sel ( a, a, SQRT_ONE_MINUS_D, rotate ); | ||||
gf_cond_sel ( x, p->y, x, rotate ); | |||||
gf_cond_sel ( e, p->y, x, rotate ); | |||||
#else | #else | ||||
const gf_s *e = x; | |||||
(void)toggle_rotation; | (void)toggle_rotation; | ||||
rotate = 0; | rotate = 0; | ||||
#endif | #endif | ||||
@@ -216,7 +212,7 @@ void API_NS(deisogenize) ( | |||||
gf_cond_neg ( minus_t_over_s, tg ); | gf_cond_neg ( minus_t_over_s, tg ); | ||||
gf_cond_neg ( c, rotate ^ tg ); | gf_cond_neg ( c, rotate ^ tg ); | ||||
gf_add ( d, d, c ); | gf_add ( d, d, c ); | ||||
gf_mul ( s, d, x ); /* here "x" = y unless rotate */ | |||||
gf_mul ( s, d, e ); /* here "x" = y unless rotate */ | |||||
gf_cond_neg ( s, toggle_hibit_s ^ gf_hibit(s) ); | gf_cond_neg ( s, toggle_hibit_s ^ gf_hibit(s) ); | ||||
#endif | #endif | ||||
} | } | ||||
@@ -236,24 +232,24 @@ decaf_error_t API_NS(point_decode) ( | |||||
mask_t succ = gf_deserialize(s, ser, 0); | mask_t succ = gf_deserialize(s, ser, 0); | ||||
mask_t zero = gf_eq(s, ZERO); | mask_t zero = gf_eq(s, ZERO); | ||||
succ &= bool_to_mask(allow_identity) | ~zero; | succ &= bool_to_mask(allow_identity) | ~zero; | ||||
gf_sqr ( a, s ); | |||||
gf_sqr ( a, s ); /* s^2 */ | |||||
#if IMAGINE_TWIST | #if IMAGINE_TWIST | ||||
gf_sub ( f, ONE, a ); /* f = 1-as^2 = 1-s^2*/ | gf_sub ( f, ONE, a ); /* f = 1-as^2 = 1-s^2*/ | ||||
#else | #else | ||||
gf_add ( f, ONE, a ); /* f = 1-as^2 = 1+s^2 */ | gf_add ( f, ONE, a ); /* f = 1-as^2 = 1+s^2 */ | ||||
#endif | #endif | ||||
succ &= ~ gf_eq( f, ZERO ); | succ &= ~ gf_eq( f, ZERO ); | ||||
gf_sqr ( b, f ); | |||||
gf_sqr ( b, f ); /* (1-as^2)^2 = 1 - 2as^2 + a^2 s^4 */ | |||||
gf_mulw ( c, a, 4*IMAGINE_TWIST-4*EDWARDS_D ); | gf_mulw ( c, a, 4*IMAGINE_TWIST-4*EDWARDS_D ); | ||||
gf_add ( c, c, b ); /* t^2 */ | |||||
gf_mul ( d, f, s ); /* s(1-as^2) for denoms */ | |||||
gf_sqr ( e, d ); | |||||
gf_mul ( b, c, e ); | |||||
gf_add ( c, c, b ); /* t^2 = 1 + (2a-4d) s^2 + s^4 */ | |||||
gf_mul ( d, f, s ); /* s * (1-as^2) for denoms */ | |||||
gf_sqr ( e, d ); /* s^2 * (1-as^2)^2 */ | |||||
gf_mul ( b, c, e ); /* t^2 * s^2 * (1-as^2)^2 */ | |||||
succ &= gf_isr(e,b) | gf_eq(b,ZERO); /* e = 1/(t s (1-as^2)) */ | succ &= gf_isr(e,b) | gf_eq(b,ZERO); /* e = 1/(t s (1-as^2)) */ | ||||
gf_mul ( b, e, d ); /* 1/t */ | |||||
gf_mul ( d, e, c ); /* d = t / (s(1-as^2)) */ | |||||
gf_mul ( e, d, f ); /* t/s */ | |||||
gf_mul ( b, e, d ); /* 1 / t */ | |||||
gf_mul ( d, e, c ); /* t / (s(1-as^2)) */ | |||||
gf_mul ( e, d, f ); /* t / s */ | |||||
mask_t negtos = gf_hibit(e); | mask_t negtos = gf_hibit(e); | ||||
gf_cond_neg(b, negtos); | gf_cond_neg(b, negtos); | ||||
gf_cond_neg(d, negtos); | gf_cond_neg(d, negtos); | ||||
@@ -279,8 +275,23 @@ decaf_error_t API_NS(point_decode) ( | |||||
#endif | #endif | ||||
gf_mul ( p->t, p->x, a ); /* T = 2s (1-as^2)/t */ | gf_mul ( p->t, p->x, a ); /* T = 2s (1-as^2)/t */ | ||||
p->y->limb[0] -= zero; | |||||
#if UNSAFE_CURVE_HAS_POINTS_AT_INFINITY | |||||
/* This can't happen for any of the supported configurations. | |||||
* | |||||
* If it can happen (because s=1), it's because the curve has points | |||||
* at infinity, which means that there may be critical security bugs | |||||
* elsewhere in the library. In that case, it's better that you hit | |||||
* the assertion in point_valid, which will happen in the test suite | |||||
* since it tests s=1. | |||||
* | |||||
* This debugging option is to allow testing of IMAGINE_TWIST = 0 on | |||||
* Ed25519, without hitting that assertion. Don't use it in | |||||
* production. | |||||
*/ | |||||
succ &= ~gf_eq(p->z,ZERO); | |||||
#endif | |||||
p->y->limb[0] -= zero; | |||||
assert(API_NS(point_valid)(p) | ~succ); | assert(API_NS(point_valid)(p) | ~succ); | ||||
return decaf_succeed_if(mask_to_bool(succ)); | return decaf_succeed_if(mask_to_bool(succ)); | ||||
@@ -822,7 +833,7 @@ void API_NS(point_debugging_torque) ( | |||||
point_t q, | point_t q, | ||||
const point_t p | const point_t p | ||||
) { | ) { | ||||
#if COFACTOR == 8 | |||||
#if COFACTOR == 8 && IMAGINE_TWIST | |||||
gf tmp; | gf tmp; | ||||
gf_mul(tmp,p->x,SQRT_MINUS_ONE); | gf_mul(tmp,p->x,SQRT_MINUS_ONE); | ||||
gf_mul(q->x,p->y,SQRT_MINUS_ONE); | gf_mul(q->x,p->y,SQRT_MINUS_ONE); | ||||
@@ -61,7 +61,7 @@ void API_NS(point_from_hash_nonuniform) ( | |||||
/* s@a = +-|N.e| */ | /* s@a = +-|N.e| */ | ||||
gf_mul(a,N,e); | gf_mul(a,N,e); | ||||
gf_cond_neg(a,gf_hibit(a)^square); /* NB this is - what is listen in the paper */ | |||||
gf_cond_neg(a,gf_hibit(a)^square); /* NB this is - what is listed in the paper */ | |||||
/* t@b = -+ cN(r-1)((a-2d)e)^2 - 1 */ | /* t@b = -+ cN(r-1)((a-2d)e)^2 - 1 */ | ||||
gf_mulw(c,e,1-2*EDWARDS_D); /* (a-2d)e */ | gf_mulw(c,e,1-2*EDWARDS_D); /* (a-2d)e */ | ||||
@@ -122,8 +122,14 @@ for curve,data in curve_data.items(): | |||||
data["eddsa_sigma_iso"] = 0 | data["eddsa_sigma_iso"] = 0 | ||||
if "imagine_twist" not in data: | if "imagine_twist" not in data: | ||||
# This is a HACK. The real problem is that iso-Ed25519 | |||||
# has points at infinity unless you IMAGINE_TWIST. | |||||
# | |||||
# Also there are lots of bugs when cofactor=8 && !IMAGINE_TWIST. | |||||
# (FIXME, eventually) | |||||
if data["modulus"]%4 == 3: data["imagine_twist"] = 0 | if data["modulus"]%4 == 3: data["imagine_twist"] = 0 | ||||
else: data["imagine_twist"] = 1 | else: data["imagine_twist"] = 1 | ||||
# data["imagine_twist"] = 0 | |||||
data["q"] = (data["modulus"]+1-data["trace"]) // data["cofactor"] | data["q"] = (data["modulus"]+1-data["trace"]) // data["cofactor"] | ||||
data["bits"] = ceil_log2(data["modulus"]) | data["bits"] = ceil_log2(data["modulus"]) | ||||
@@ -46,9 +46,13 @@ const uint8_t decaf_x$(gf_shortname)_base_point[DECAF_X$(gf_shortname)_PUBLIC_BY | |||||
/* End of template stuff */ | /* End of template stuff */ | ||||
/* Sanity */ | /* Sanity */ | ||||
#if (COFACTOR == 8) && !IMAGINE_TWIST | |||||
#if (COFACTOR == 8) && !IMAGINE_TWIST && !UNSAFE_CURVE_HAS_POINTS_AT_INFINITY | |||||
/* FUTURE MAGIC: Curve41417 doesn't have these properties. */ | /* FUTURE MAGIC: Curve41417 doesn't have these properties. */ | ||||
#error "Currently require IMAGINE_TWIST (and thus p=5 mod 8) for cofactor 8" | |||||
#error "Currently require IMAGINE_TWIST (and thus p=5 mod 8) for cofactor 8" | |||||
/* OK, but why? | |||||
* Two reasons: #1: There are bugs when COFACTOR == && IMAGINE_TWIST | |||||
# #2: | |||||
*/ | |||||
#endif | #endif | ||||
#if IMAGINE_TWIST && (P_MOD_8 != 5) | #if IMAGINE_TWIST && (P_MOD_8 != 5) | ||||
@@ -104,15 +108,6 @@ static mask_t gf_lobit(const gf x) { | |||||
/** identity = (0,1) */ | /** identity = (0,1) */ | ||||
const point_t API_NS(point_identity) = {{{{{0}}},{{{1}}},{{{1}}},{{{0}}}}}; | const point_t API_NS(point_identity) = {{{{{0}}},{{{1}}},{{{1}}},{{{0}}}}}; | ||||
void API_NS(deisogenize) ( | |||||
gf_s *__restrict__ s, | |||||
gf_s *__restrict__ minus_t_over_s, | |||||
const point_t p, | |||||
mask_t toggle_hibit_s, | |||||
mask_t toggle_hibit_t_over_s, | |||||
mask_t toggle_rotation | |||||
); | |||||
void API_NS(deisogenize) ( | void API_NS(deisogenize) ( | ||||
gf_s *__restrict__ s, | gf_s *__restrict__ s, | ||||
gf_s *__restrict__ minus_t_over_s, | gf_s *__restrict__ minus_t_over_s, | ||||
@@ -152,7 +147,7 @@ void API_NS(deisogenize) ( | |||||
#else | #else | ||||
/* More complicated because of rotation */ | /* More complicated because of rotation */ | ||||
/* MAGIC This code is wrong for certain non-Curve25519 curves; | /* MAGIC This code is wrong for certain non-Curve25519 curves; | ||||
* check if it's because of Cofactor==8 or IMAGINE_ROTATION */ | |||||
* check if it's because of Cofactor==8 or IMAGINE_TWIST */ | |||||
gf c, d; | gf c, d; | ||||
gf_s *b = s, *a = minus_t_over_s; | gf_s *b = s, *a = minus_t_over_s; | ||||
@@ -166,11 +161,11 @@ void API_NS(deisogenize) ( | |||||
gf_mul ( c, a, b ); /* "zx" = Z^2 - aX^2 = Z^2 - X^2 */ | gf_mul ( c, a, b ); /* "zx" = Z^2 - aX^2 = Z^2 - X^2 */ | ||||
#else | #else | ||||
const gf_s *x = p->x, *t = p->t; | const gf_s *x = p->x, *t = p->t; | ||||
/* Won't hit the gf_cond_sel below because COFACTOR==8 requires IMAGINE_TWIST for now. */ | |||||
gf_sqr ( a, p->z ); | gf_sqr ( a, p->z ); | ||||
gf_sqr ( b, p->x ); | gf_sqr ( b, p->x ); | ||||
gf_add ( c, a, b ); /* "zx" = Z^2 - aX^2 = Z^2 + X^2 */ | gf_add ( c, a, b ); /* "zx" = Z^2 - aX^2 = Z^2 + X^2 */ | ||||
#endif | #endif | ||||
/* Here: c = "zx" in the SAGE code = Z^2 - aX^2 */ | |||||
gf_mul ( a, p->z, t ); /* "tz" = T*Z */ | gf_mul ( a, p->z, t ); /* "tz" = T*Z */ | ||||
gf_sqr ( b, a ); | gf_sqr ( b, a ); | ||||
@@ -190,8 +185,9 @@ void API_NS(deisogenize) ( | |||||
/* Curve25519: cond select between zx * 1/tz or sqrt(1-d); y=-x */ | /* Curve25519: cond select between zx * 1/tz or sqrt(1-d); y=-x */ | ||||
gf_mul ( a, b, c ); | gf_mul ( a, b, c ); | ||||
gf_cond_sel ( a, a, SQRT_ONE_MINUS_D, rotate ); | gf_cond_sel ( a, a, SQRT_ONE_MINUS_D, rotate ); | ||||
gf_cond_sel ( x, p->y, x, rotate ); | |||||
gf_cond_sel ( e, p->y, x, rotate ); | |||||
#else | #else | ||||
const gf_s *e = x; | |||||
(void)toggle_rotation; | (void)toggle_rotation; | ||||
rotate = 0; | rotate = 0; | ||||
#endif | #endif | ||||
@@ -205,7 +201,7 @@ void API_NS(deisogenize) ( | |||||
gf_cond_neg ( minus_t_over_s, tg ); | gf_cond_neg ( minus_t_over_s, tg ); | ||||
gf_cond_neg ( c, rotate ^ tg ); | gf_cond_neg ( c, rotate ^ tg ); | ||||
gf_add ( d, d, c ); | gf_add ( d, d, c ); | ||||
gf_mul ( s, d, x ); /* here "x" = y unless rotate */ | |||||
gf_mul ( s, d, e ); /* here "x" = y unless rotate */ | |||||
gf_cond_neg ( s, toggle_hibit_s ^ gf_hibit(s) ); | gf_cond_neg ( s, toggle_hibit_s ^ gf_hibit(s) ); | ||||
#endif | #endif | ||||
} | } | ||||
@@ -225,24 +221,24 @@ decaf_error_t API_NS(point_decode) ( | |||||
mask_t succ = gf_deserialize(s, ser, 0); | mask_t succ = gf_deserialize(s, ser, 0); | ||||
mask_t zero = gf_eq(s, ZERO); | mask_t zero = gf_eq(s, ZERO); | ||||
succ &= bool_to_mask(allow_identity) | ~zero; | succ &= bool_to_mask(allow_identity) | ~zero; | ||||
gf_sqr ( a, s ); | |||||
gf_sqr ( a, s ); /* s^2 */ | |||||
#if IMAGINE_TWIST | #if IMAGINE_TWIST | ||||
gf_sub ( f, ONE, a ); /* f = 1-as^2 = 1-s^2*/ | gf_sub ( f, ONE, a ); /* f = 1-as^2 = 1-s^2*/ | ||||
#else | #else | ||||
gf_add ( f, ONE, a ); /* f = 1-as^2 = 1+s^2 */ | gf_add ( f, ONE, a ); /* f = 1-as^2 = 1+s^2 */ | ||||
#endif | #endif | ||||
succ &= ~ gf_eq( f, ZERO ); | succ &= ~ gf_eq( f, ZERO ); | ||||
gf_sqr ( b, f ); | |||||
gf_sqr ( b, f ); /* (1-as^2)^2 = 1 - 2as^2 + a^2 s^4 */ | |||||
gf_mulw ( c, a, 4*IMAGINE_TWIST-4*EDWARDS_D ); | gf_mulw ( c, a, 4*IMAGINE_TWIST-4*EDWARDS_D ); | ||||
gf_add ( c, c, b ); /* t^2 */ | |||||
gf_mul ( d, f, s ); /* s(1-as^2) for denoms */ | |||||
gf_sqr ( e, d ); | |||||
gf_mul ( b, c, e ); | |||||
gf_add ( c, c, b ); /* t^2 = 1 + (2a-4d) s^2 + s^4 */ | |||||
gf_mul ( d, f, s ); /* s * (1-as^2) for denoms */ | |||||
gf_sqr ( e, d ); /* s^2 * (1-as^2)^2 */ | |||||
gf_mul ( b, c, e ); /* t^2 * s^2 * (1-as^2)^2 */ | |||||
succ &= gf_isr(e,b) | gf_eq(b,ZERO); /* e = 1/(t s (1-as^2)) */ | succ &= gf_isr(e,b) | gf_eq(b,ZERO); /* e = 1/(t s (1-as^2)) */ | ||||
gf_mul ( b, e, d ); /* 1/t */ | |||||
gf_mul ( d, e, c ); /* d = t / (s(1-as^2)) */ | |||||
gf_mul ( e, d, f ); /* t/s */ | |||||
gf_mul ( b, e, d ); /* 1 / t */ | |||||
gf_mul ( d, e, c ); /* t / (s(1-as^2)) */ | |||||
gf_mul ( e, d, f ); /* t / s */ | |||||
mask_t negtos = gf_hibit(e); | mask_t negtos = gf_hibit(e); | ||||
gf_cond_neg(b, negtos); | gf_cond_neg(b, negtos); | ||||
gf_cond_neg(d, negtos); | gf_cond_neg(d, negtos); | ||||
@@ -268,8 +264,23 @@ decaf_error_t API_NS(point_decode) ( | |||||
#endif | #endif | ||||
gf_mul ( p->t, p->x, a ); /* T = 2s (1-as^2)/t */ | gf_mul ( p->t, p->x, a ); /* T = 2s (1-as^2)/t */ | ||||
p->y->limb[0] -= zero; | |||||
#if UNSAFE_CURVE_HAS_POINTS_AT_INFINITY | |||||
/* This can't happen for any of the supported configurations. | |||||
* | |||||
* If it can happen (because s=1), it's because the curve has points | |||||
* at infinity, which means that there may be critical security bugs | |||||
* elsewhere in the library. In that case, it's better that you hit | |||||
* the assertion in point_valid, which will happen in the test suite | |||||
* since it tests s=1. | |||||
* | |||||
* This debugging option is to allow testing of IMAGINE_TWIST = 0 on | |||||
* Ed25519, without hitting that assertion. Don't use it in | |||||
* production. | |||||
*/ | |||||
succ &= ~gf_eq(p->z,ZERO); | |||||
#endif | |||||
p->y->limb[0] -= zero; | |||||
assert(API_NS(point_valid)(p) | ~succ); | assert(API_NS(point_valid)(p) | ~succ); | ||||
return decaf_succeed_if(mask_to_bool(succ)); | return decaf_succeed_if(mask_to_bool(succ)); | ||||
@@ -811,7 +822,7 @@ void API_NS(point_debugging_torque) ( | |||||
point_t q, | point_t q, | ||||
const point_t p | const point_t p | ||||
) { | ) { | ||||
#if COFACTOR == 8 | |||||
#if COFACTOR == 8 && IMAGINE_TWIST | |||||
gf tmp; | gf tmp; | ||||
gf_mul(tmp,p->x,SQRT_MINUS_ONE); | gf_mul(tmp,p->x,SQRT_MINUS_ONE); | ||||
gf_mul(q->x,p->y,SQRT_MINUS_ONE); | gf_mul(q->x,p->y,SQRT_MINUS_ONE); | ||||
@@ -1389,7 +1400,13 @@ void decaf_x$(gf_shortname)_derive_public_key ( | |||||
point_t p; | point_t p; | ||||
API_NS(precomputed_scalarmul)(p,API_NS(precomputed_base),the_scalar); | API_NS(precomputed_scalarmul)(p,API_NS(precomputed_base),the_scalar); | ||||
/* Isogenize to Montgomery curve */ | |||||
/* Isogenize to Montgomery curve. | |||||
* | |||||
* Why isn't this just a separate function, eg decaf_encode_like_x$(gf_shortname)? | |||||
* Basically because in general it does the wrong thing if there is a cofactor | |||||
* component in the input. In this function though, there isn't a cofactor | |||||
* component in the input. | |||||
*/ | |||||
gf_invert(p->t,p->x); /* 1/x */ | gf_invert(p->t,p->x); /* 1/x */ | ||||
gf_mul(p->z,p->t,p->y); /* y/x */ | gf_mul(p->z,p->t,p->y); /* y/x */ | ||||
gf_sqr(p->y,p->z); /* (y/x)^2 */ | gf_sqr(p->y,p->z); /* (y/x)^2 */ | ||||
@@ -50,7 +50,7 @@ void API_NS(point_from_hash_nonuniform) ( | |||||
/* s@a = +-|N.e| */ | /* s@a = +-|N.e| */ | ||||
gf_mul(a,N,e); | gf_mul(a,N,e); | ||||
gf_cond_neg(a,gf_hibit(a)^square); /* NB this is - what is listen in the paper */ | |||||
gf_cond_neg(a,gf_hibit(a)^square); /* NB this is - what is listed in the paper */ | |||||
/* t@b = -+ cN(r-1)((a-2d)e)^2 - 1 */ | /* t@b = -+ cN(r-1)((a-2d)e)^2 - 1 */ | ||||
gf_mulw(c,e,1-2*EDWARDS_D); /* (a-2d)e */ | gf_mulw(c,e,1-2*EDWARDS_D); /* (a-2d)e */ | ||||
@@ -353,7 +353,12 @@ static void test_ec() { | |||||
rng.read(buffer); | rng.read(buffer); | ||||
Point r = Point::from_hash(buffer); | Point r = Point::from_hash(buffer); | ||||
point_check(test,p,q,r,0,0,p,Point(p.serialize()),"round-trip"); | |||||
try { | |||||
point_check(test,p,q,r,0,0,p,Point(p.serialize()),"round-trip"); | |||||
} catch (CryptoException) { | |||||
test.fail(); | |||||
printf(" Round-trip raised CryptoException!\n"); | |||||
} | |||||
Point pp = p.debugging_torque().debugging_pscale(rng); | Point pp = p.debugging_torque().debugging_pscale(rng); | ||||
if (!memeq(pp.serialize(),p.serialize())) { | if (!memeq(pp.serialize(),p.serialize())) { | ||||
test.fail(); | test.fail(); | ||||
@@ -390,8 +395,13 @@ static void test_ec() { | |||||
+ Point::from_hash(Buffer(buffer).slice(Point::HASH_BYTES,Point::HASH_BYTES)), | + Point::from_hash(Buffer(buffer).slice(Point::HASH_BYTES,Point::HASH_BYTES)), | ||||
"unih = hash+add" | "unih = hash+add" | ||||
); | ); | ||||
point_check(test,p,q,r,x,0,Point(x.direct_scalarmul(p.serialize())),x*p,"direct mul"); | |||||
try { | |||||
point_check(test,p,q,r,x,0,Point(x.direct_scalarmul(p.serialize())),x*p,"direct mul"); | |||||
} catch (CryptoException) { | |||||
printf(" Direct mul raised CryptoException!\n"); | |||||
test.fail(); | |||||
} | |||||
q=p; | q=p; | ||||
for (int j=1; j<Group::REMOVED_COFACTOR; j<<=1) q = q.times_two(); | for (int j=1; j<Group::REMOVED_COFACTOR; j<<=1) q = q.times_two(); | ||||
@@ -531,7 +541,6 @@ static void test_eddsa() { | |||||
printf(" Signature validation failed on sig %d\n", i); | printf(" Signature validation failed on sig %d\n", i); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
/* Thanks Johan Pascal */ | /* Thanks Johan Pascal */ | ||||