@@ -305,9 +305,8 @@ class Decaf_1_1_Point(QuotientEdwardsPoint): | |||
return cls(x,y) | |||
@optimized_version_of("encodeSpec") | |||
def encode(self): | |||
"""Encode, optimized version""" | |||
def toJacobiQuartic(self,toggle_rotation=False,toggle_altx=False,toggle_s=False): | |||
"Return s,t on jacobi curve" | |||
a,d = self.a,self.d | |||
x,y,z,t = self.xyzt() | |||
@@ -327,50 +326,88 @@ class Decaf_1_1_Point(QuotientEdwardsPoint): | |||
iden = isr * den * self.isoMagic | |||
inum = isr * num | |||
if negative(iden*inum*self.i*t^2*(d-a)): | |||
if negative(iden*inum*self.i*t^2*(d-a)) != toggle_rotation: | |||
iden,inum = inum,iden | |||
fac = x*sqrt(a) | |||
toggle = (-a==1) | |||
toggle=(a==-1) | |||
else: | |||
fac = y | |||
toggle = False | |||
toggle=False | |||
imi = self.isoMagic * self.i | |||
altx = inum*t*imi | |||
if negative(altx) != toggle: inum =- inum | |||
s = fac*iden*(inum*z + 1)*imi | |||
neg_altx = negative(altx) != toggle_altx | |||
if neg_altx != toggle: inum =- inum | |||
tmp = fac*(inum*z + 1) | |||
s = iden*tmp*imi | |||
# Version without the above IMAGINE_TWIST hack | |||
# num = (z+y)*(z-y) | |||
# den = x*y | |||
# isr = isqrt(num*(a-d)*den^2) | |||
# | |||
# imi = self.isoMagic * self.i | |||
# iden = isr * den * imi | |||
# inum = isr * num | |||
# if isr: assert iden*inum == 1/imi/den | |||
# | |||
# if negative(iden*inum*self.i*t^2*(d-a)): | |||
# iden,inum = inum,iden | |||
# fac = x*sqrt(a) | |||
# toggle = (a==1) | |||
# else: | |||
# fac = y | |||
# toggle = False | |||
# | |||
# altx = inum*t*self.isoMagic | |||
# if negative(altx) != toggle: inum =- inum | |||
# s = fac*iden*imi*(inum*z - 1) | |||
negm1 = (negative(s) != toggle_s) != neg_altx | |||
if negm1: m1 = a*fac + z | |||
else: m1 = a*fac - z | |||
swap = toggle_s | |||
else: | |||
# Much simpler cofactor 4 version | |||
num = (x+t)*(x-t) | |||
isr = isqrt(num*(a-d)*x^2) | |||
ratio = isr*num | |||
if negative(ratio*self.isoMagic): ratio=-ratio | |||
s = (a-d)*isr*x*(ratio*z - t) | |||
altx = ratio*self.isoMagic | |||
neg_altx = negative(altx) != toggle_altx | |||
if neg_altx: ratio =- ratio | |||
tmp = ratio*z - t | |||
s = (a-d)*isr*x*tmp | |||
negx = (negative(s) != toggle_s) != neg_altx | |||
if negx: m1 = -a*t + x | |||
else: m1 = -a*t - x | |||
swap = toggle_s | |||
if negative(s): s = -s | |||
return self.gfToBytes(s,mustBePositive=True) | |||
return s,m1,a*tmp,swap | |||
def invertElligator(self,toggle_r=False,*args,**kwargs): | |||
"Produce preimage of self under elligator, or None" | |||
a,d = self.a,self.d | |||
rets = [] | |||
tr = [False,True] if self.cofactor == 8 else [False] | |||
for toggle_rotation in tr: | |||
for toggle_altx in [False,True]: | |||
for toggle_s in [False,True]: | |||
for toggle_r in [False,True]: | |||
s,m1,m12,swap = self.toJacobiQuartic(toggle_rotation,toggle_altx,toggle_s) | |||
if self == self.__class__(): | |||
# Hacks for identity! | |||
if toggle_altx: m12 = 1 | |||
elif toggle_s: m1 = 1 | |||
elif toggle_r: continue | |||
## BOTH??? | |||
rnum = (d*a*m12-m1) | |||
rden = ((d*a-1)*m12+m1) | |||
if swap: rnum,rden = rden,rnum | |||
ok,sr = isqrt_i(rnum*rden*self.qnr) | |||
if not ok: continue | |||
sr *= rnum | |||
if negative(sr) != toggle_r: sr = -sr | |||
ret = self.gfToBytes(sr) | |||
assert self.elligator(ret) == self or self.elligator(ret) == -self | |||
if self.elligator(ret) == -self and self != -self: print "Negated!",[toggle_rotation,toggle_altx,toggle_s,toggle_r] | |||
rets.append(bytes(ret)) | |||
return rets | |||
@optimized_version_of("encodeSpec") | |||
def encode(self): | |||
"""Encode, optimized version""" | |||
return self.gfToBytes(self.toJacobiQuartic()[0]) | |||
@classmethod | |||
@optimized_version_of("decodeSpec") | |||
@@ -404,9 +441,10 @@ class Decaf_1_1_Point(QuotientEdwardsPoint): | |||
return cls(x,sgn*y) | |||
@classmethod | |||
def elligatorSpec(cls,r0): | |||
def elligatorSpec(cls,r0,fromR=False): | |||
a,d = cls.a,cls.d | |||
r = cls.qnr * cls.bytesToGf(r0)^2 | |||
if fromR: r = r0 | |||
else: r = cls.qnr * cls.bytesToGf(r0)^2 | |||
den = (d*r-(d-a))*((d-a)*r-d) | |||
if den == 0: return cls() | |||
@@ -608,9 +646,27 @@ test(Ed448GoldilocksPoint,100) | |||
def testElligator(cls,n): | |||
print "Testing elligator on %s" % cls.__name__ | |||
for i in xrange(n): | |||
cls.elligator(randombytes(cls.encLen)) | |||
r = randombytes(cls.encLen) | |||
P = cls.elligator(r) | |||
if hasattr(P,"invertElligator"): | |||
iv = P.invertElligator() | |||
modr = bytes(cls.gfToBytes(cls.bytesToGf(r))) | |||
iv2 = P.torque().invertElligator() | |||
if modr not in iv: print "Failed to invert Elligator!" | |||
if len(iv) != len(set(iv)): | |||
print "Elligator inverses not unique!", len(set(iv)), len(iv) | |||
if iv != iv2: | |||
print "Elligator is untorqueable!" | |||
#print [binascii.hexlify(j) for j in iv] | |||
#print [binascii.hexlify(j) for j in iv2] | |||
#break | |||
else: | |||
pass # TODO | |||
testElligator(Ed25519Point,100) | |||
testElligator(NegEd25519Point,100) | |||
testElligator(IsoEd25519Point,100) | |||
testElligator(IsoEd448Point,100) | |||
testElligator(Ed448GoldilocksPoint,100) | |||
testElligator(TwistedEd448GoldilocksPoint,100) | |||
@@ -131,27 +131,30 @@ gf_invert(gf y, const gf x, int assert_nonzero) { | |||
const point_t API_NS(point_identity) = {{{{{0}}},{{{1}}},{{{1}}},{{{0}}}}}; | |||
/* Predeclare because not static: called by elligator */ | |||
void API_NS(deisogenize) ( | |||
mask_t API_NS(deisogenize) ( | |||
gf_s *__restrict__ s, | |||
gf_s *__restrict__ altx, | |||
gf_s *__restrict__ inv_el_sum, | |||
gf_s *__restrict__ inv_el_m1, | |||
const point_t p, | |||
mask_t toggle_hibit_s, | |||
mask_t toggle_s, | |||
mask_t toggle_altx, | |||
mask_t toggle_rotation | |||
); | |||
void API_NS(deisogenize) ( | |||
mask_t API_NS(deisogenize) ( | |||
gf_s *__restrict__ s, | |||
gf_s *__restrict__ altx, | |||
gf_s *__restrict__ inv_el_sum, | |||
gf_s *__restrict__ inv_el_m1, | |||
const point_t p, | |||
mask_t toggle_hibit_s, | |||
mask_t toggle_s, | |||
mask_t toggle_altx, | |||
mask_t toggle_rotation | |||
) { | |||
#if COFACTOR == 4 | |||
#if COFACTOR == 4 && !IMAGINE_TWIST | |||
(void)toggle_rotation; /* Only applies to cofactor 8 */ | |||
gf t1,t2,t3; | |||
gf t1; | |||
gf_s *t2 = s, *t3=inv_el_sum, *t4=inv_el_m1; | |||
gf_add(t1,p->x,p->t); | |||
gf_sub(t2,p->x,p->t); | |||
@@ -161,20 +164,27 @@ void API_NS(deisogenize) ( | |||
gf_mulw(t2,t1,-1-TWISTED_D); /* -x^2 * (a-d) * num */ | |||
gf_isr(t1,t2); /* t1 = isr */ | |||
gf_mul(t2,t1,t3); /* t2 = ratio */ | |||
gf_mul(altx,t2,RISTRETTO_ISOMAGIC); | |||
mask_t negx = gf_lobit(altx) ^ toggle_altx; | |||
gf_mul(t4,t2,RISTRETTO_ISOMAGIC); | |||
mask_t negx = gf_lobit(t4) ^ toggle_altx; | |||
gf_cond_neg(t2, negx); | |||
gf_cond_neg(altx, negx); | |||
gf_mul(t3,t2,p->z); | |||
gf_sub(t3,t3,p->t); | |||
gf_mul(t2,t3,p->x); | |||
gf_mulw(t3,t2,-1-TWISTED_D); | |||
gf_mul(s,t3,t1); | |||
gf_cond_neg(s,gf_lobit(s)^toggle_hibit_s); | |||
gf_mulw(t4,t2,-1-TWISTED_D); | |||
gf_mul(s,t4,t1); | |||
mask_t lobs = gf_lobit(s); | |||
gf_cond_neg(s,lobs); | |||
gf_copy(inv_el_m1,p->x); | |||
gf_cond_neg(inv_el_m1,~lobs^negx^toggle_s); | |||
gf_add(inv_el_m1,inv_el_m1,p->t); | |||
return toggle_s; | |||
#elif COFACTOR == 8 && IMAGINE_TWIST | |||
gf_s *altx = inv_el_sum; // TODO | |||
(void)inv_el_m1; | |||
#elif COFACTOR == 8 | |||
/* More complicated because of rotation */ | |||
gf t1,t2,t3,t4; | |||
gf t1,t2,t3,t4,t5; | |||
gf_add(t1,p->z,p->y); | |||
gf_sub(t2,p->z,p->y); | |||
gf_mul(t3,t1,t2); /* t3 = num */ | |||
@@ -196,27 +206,34 @@ void API_NS(deisogenize) ( | |||
mask_t rotate = toggle_rotation ^ gf_lobit(t3); | |||
gf_cond_swap(t1,t2,rotate); | |||
gf_cond_sel(t4,p->y,t4,rotate); /* ix if rotate, else y */ | |||
gf_cond_sel(t4,p->y,t4,rotate); /* "fac" = ix if rotate, else y */ | |||
gf_mul(t3,t2,t4); /* "fac*iden" */ | |||
gf_mul_qnr(t2,RISTRETTO_ISOMAGIC); | |||
gf_mul(t4,t2,t3); /* "fac*iden*imi" */ | |||
gf_mul(t3,t2,p->t); | |||
gf_mul(altx,t3,t1); | |||
mask_t negx = rotate ^ gf_lobit(altx) ^ toggle_altx; | |||
gf_cond_neg(altx,negx); | |||
gf_cond_neg(t1,negx); | |||
gf_mul(t5,t2,p->t); | |||
gf_mul(altx,t5,t1); | |||
mask_t negx = gf_lobit(altx) ^ toggle_altx; | |||
gf_cond_neg(t1,negx^rotate); | |||
gf_mul(t2,t1,p->z); | |||
gf_add(t2,t2,ONE); | |||
gf_mul(s,t2,t4); | |||
gf_cond_neg(s,gf_lobit(s)^toggle_hibit_s); | |||
mask_t negs = gf_lobit(s); | |||
gf_cond_neg(s,negs); | |||
mask_t negz = ~negs ^ toggle_s ^ negx; | |||
gf_copy(inv_el_m1,p->z); | |||
gf_cond_neg(inv_el_m1,negz); | |||
gf_sub(inv_el_m1,inv_el_m1,t3); | |||
return toggle_s; | |||
#else | |||
#error "Cofactor must be 4 or 8" | |||
#error "Cofactor must be 4 (with no IMAGINE_TWIST) or 8 (with IMAGINE_TWIST)" | |||
#endif | |||
} | |||
void API_NS(point_encode)( unsigned char ser[SER_BYTES], const point_t p ) { | |||
gf s, mtos; | |||
API_NS(deisogenize)(s,mtos,p,0,0,0); | |||
gf s,ie1,ie2; | |||
(void)API_NS(deisogenize)(s,ie1,ie2,p,0,0,0); | |||
gf_serialize(ser,s,1); | |||
} | |||
@@ -23,9 +23,10 @@ | |||
static const int EDWARDS_D = -121665; | |||
/* End of template stuff */ | |||
extern void API_NS(deisogenize) ( | |||
extern mask_t API_NS(deisogenize) ( | |||
gf_s *__restrict__ s, | |||
gf_s *__restrict__ altx, | |||
gf_s *__restrict__ inv_el_sum, | |||
gf_s *__restrict__ inv_el_m1, | |||
const point_t p, | |||
mask_t toggle_hibit_s, | |||
mask_t toggle_altx, | |||
@@ -131,48 +132,48 @@ API_NS(invert_elligator_nonuniform) ( | |||
const point_t p, | |||
uint32_t hint_ | |||
) { | |||
/* TODO: test that this can produce sqrt((d-a)/ud) etc. */ | |||
mask_t hint = hint_; | |||
mask_t sgn_s = -(hint & 1), | |||
sgn_t_over_s = -(hint>>1 & 1), | |||
sgn_altx = -(hint>>1 & 1), | |||
sgn_r0 = -(hint>>2 & 1), | |||
/* FUTURE MAGIC: eventually if there's a curve which needs sgn_ed_T but not sgn_r0, | |||
* change this mask extraction. | |||
*/ | |||
sgn_ed_T = -(hint>>3 & 1); | |||
gf a, b, c, d; | |||
API_NS(deisogenize)(a,c,p,sgn_s,sgn_t_over_s,sgn_ed_T); | |||
gf a,b,c; | |||
mask_t swap = API_NS(deisogenize)(a,b,c,p,sgn_s,sgn_altx,sgn_ed_T); | |||
mask_t is_identity = gf_eq(p->t,ZERO); | |||
(void)is_identity; | |||
gf_cond_sel(b,b,ONE,is_identity & sgn_altx); | |||
gf_cond_sel(c,c,ONE,is_identity & sgn_s &~ sgn_altx); | |||
#if IMAGINE_TWIST | |||
gf_mulw(a,b,EDWARDS_D); | |||
gf_sub(b,a,b); | |||
#else | |||
gf_mulw(a,b,EDWARDS_D-1); | |||
gf_add(b,a,b); | |||
#endif | |||
gf_sub(a,a,c); | |||
gf_add(b,b,c); | |||
gf_cond_swap(a,b,swap); | |||
gf_mul_qnr(c,b); | |||
gf_mul(b,c,a); | |||
mask_t succ = gf_isr(c,b); | |||
succ |= gf_eq(b,ZERO); | |||
gf_mul(b,c,a); | |||
#if 255 == 8*SER_BYTES + 1 /* p521. */ | |||
sgn_r0 = 0; | |||
#endif | |||
/* ok, a = s; c = -t/s */ | |||
gf_mul(b,c,a); | |||
gf_sub(b,ONE,b); /* t+1 */ | |||
gf_sqr(c,a); /* s^2 */ | |||
mask_t is_identity = gf_eq(p->t,ZERO); | |||
/* identity adjustments */ | |||
/* in case of identity, currently c=0, t=0, b=1, will encode to 1 */ | |||
/* if hint is 0, -> 0 */ | |||
/* if hint is to neg t/s, then go to infinity, effectively set s to 1 */ | |||
gf_cond_sel(c,c,ONE,is_identity & sgn_t_over_s); | |||
gf_cond_sel(b,b,ZERO,is_identity & ~sgn_t_over_s & ~sgn_s); | |||
gf_mulw(d,c,2*EDWARDS_D-1); /* $d = (2d-a)s^2 */ | |||
gf_add(a,b,d); /* num? */ | |||
gf_sub(d,d,b); /* den? */ | |||
gf_mul(b,a,d); /* n*d */ | |||
gf_cond_sel(a,d,a,sgn_s); | |||
gf_mul_qnr(d,b); | |||
mask_t succ = gf_isr(c,d)|gf_eq(d,ZERO); | |||
gf_mul(b,a,c); | |||
gf_cond_neg(b, sgn_r0^gf_hibit(b)); | |||
succ &= ~(gf_eq(b,ZERO) & sgn_r0); | |||
#if COFACTOR == 8 | |||
succ &= ~(is_identity & sgn_ed_T); /* NB: there are no preimages of rotated identity. */ | |||
#endif | |||
// #if COFACTOR == 8 | |||
// succ &= ~(is_identity & sgn_ed_T); /* NB: there are no preimages of rotated identity. */ | |||
// #endif | |||
#if 255 == 8*SER_BYTES + 1 /* p521 */ | |||
gf_serialize(recovered_hash,b,0); | |||
@@ -131,27 +131,30 @@ gf_invert(gf y, const gf x, int assert_nonzero) { | |||
const point_t API_NS(point_identity) = {{{{{0}}},{{{1}}},{{{1}}},{{{0}}}}}; | |||
/* Predeclare because not static: called by elligator */ | |||
void API_NS(deisogenize) ( | |||
mask_t API_NS(deisogenize) ( | |||
gf_s *__restrict__ s, | |||
gf_s *__restrict__ altx, | |||
gf_s *__restrict__ inv_el_sum, | |||
gf_s *__restrict__ inv_el_m1, | |||
const point_t p, | |||
mask_t toggle_hibit_s, | |||
mask_t toggle_s, | |||
mask_t toggle_altx, | |||
mask_t toggle_rotation | |||
); | |||
void API_NS(deisogenize) ( | |||
mask_t API_NS(deisogenize) ( | |||
gf_s *__restrict__ s, | |||
gf_s *__restrict__ altx, | |||
gf_s *__restrict__ inv_el_sum, | |||
gf_s *__restrict__ inv_el_m1, | |||
const point_t p, | |||
mask_t toggle_hibit_s, | |||
mask_t toggle_s, | |||
mask_t toggle_altx, | |||
mask_t toggle_rotation | |||
) { | |||
#if COFACTOR == 4 | |||
#if COFACTOR == 4 && !IMAGINE_TWIST | |||
(void)toggle_rotation; /* Only applies to cofactor 8 */ | |||
gf t1,t2,t3; | |||
gf t1; | |||
gf_s *t2 = s, *t3=inv_el_sum, *t4=inv_el_m1; | |||
gf_add(t1,p->x,p->t); | |||
gf_sub(t2,p->x,p->t); | |||
@@ -161,20 +164,27 @@ void API_NS(deisogenize) ( | |||
gf_mulw(t2,t1,-1-TWISTED_D); /* -x^2 * (a-d) * num */ | |||
gf_isr(t1,t2); /* t1 = isr */ | |||
gf_mul(t2,t1,t3); /* t2 = ratio */ | |||
gf_mul(altx,t2,RISTRETTO_ISOMAGIC); | |||
mask_t negx = gf_lobit(altx) ^ toggle_altx; | |||
gf_mul(t4,t2,RISTRETTO_ISOMAGIC); | |||
mask_t negx = gf_lobit(t4) ^ toggle_altx; | |||
gf_cond_neg(t2, negx); | |||
gf_cond_neg(altx, negx); | |||
gf_mul(t3,t2,p->z); | |||
gf_sub(t3,t3,p->t); | |||
gf_mul(t2,t3,p->x); | |||
gf_mulw(t3,t2,-1-TWISTED_D); | |||
gf_mul(s,t3,t1); | |||
gf_cond_neg(s,gf_lobit(s)^toggle_hibit_s); | |||
gf_mulw(t4,t2,-1-TWISTED_D); | |||
gf_mul(s,t4,t1); | |||
mask_t lobs = gf_lobit(s); | |||
gf_cond_neg(s,lobs); | |||
gf_copy(inv_el_m1,p->x); | |||
gf_cond_neg(inv_el_m1,~lobs^negx^toggle_s); | |||
gf_add(inv_el_m1,inv_el_m1,p->t); | |||
return toggle_s; | |||
#elif COFACTOR == 8 && IMAGINE_TWIST | |||
gf_s *altx = inv_el_sum; // TODO | |||
(void)inv_el_m1; | |||
#elif COFACTOR == 8 | |||
/* More complicated because of rotation */ | |||
gf t1,t2,t3,t4; | |||
gf t1,t2,t3,t4,t5; | |||
gf_add(t1,p->z,p->y); | |||
gf_sub(t2,p->z,p->y); | |||
gf_mul(t3,t1,t2); /* t3 = num */ | |||
@@ -196,27 +206,34 @@ void API_NS(deisogenize) ( | |||
mask_t rotate = toggle_rotation ^ gf_lobit(t3); | |||
gf_cond_swap(t1,t2,rotate); | |||
gf_cond_sel(t4,p->y,t4,rotate); /* ix if rotate, else y */ | |||
gf_cond_sel(t4,p->y,t4,rotate); /* "fac" = ix if rotate, else y */ | |||
gf_mul(t3,t2,t4); /* "fac*iden" */ | |||
gf_mul_qnr(t2,RISTRETTO_ISOMAGIC); | |||
gf_mul(t4,t2,t3); /* "fac*iden*imi" */ | |||
gf_mul(t3,t2,p->t); | |||
gf_mul(altx,t3,t1); | |||
mask_t negx = rotate ^ gf_lobit(altx) ^ toggle_altx; | |||
gf_cond_neg(altx,negx); | |||
gf_cond_neg(t1,negx); | |||
gf_mul(t5,t2,p->t); | |||
gf_mul(altx,t5,t1); | |||
mask_t negx = gf_lobit(altx) ^ toggle_altx; | |||
gf_cond_neg(t1,negx^rotate); | |||
gf_mul(t2,t1,p->z); | |||
gf_add(t2,t2,ONE); | |||
gf_mul(s,t2,t4); | |||
gf_cond_neg(s,gf_lobit(s)^toggle_hibit_s); | |||
mask_t negs = gf_lobit(s); | |||
gf_cond_neg(s,negs); | |||
mask_t negz = ~negs ^ toggle_s ^ negx; | |||
gf_copy(inv_el_m1,p->z); | |||
gf_cond_neg(inv_el_m1,negz); | |||
gf_sub(inv_el_m1,inv_el_m1,t3); | |||
return toggle_s; | |||
#else | |||
#error "Cofactor must be 4 or 8" | |||
#error "Cofactor must be 4 (with no IMAGINE_TWIST) or 8 (with IMAGINE_TWIST)" | |||
#endif | |||
} | |||
void API_NS(point_encode)( unsigned char ser[SER_BYTES], const point_t p ) { | |||
gf s, mtos; | |||
API_NS(deisogenize)(s,mtos,p,0,0,0); | |||
gf s,ie1,ie2; | |||
(void)API_NS(deisogenize)(s,ie1,ie2,p,0,0,0); | |||
gf_serialize(ser,s,1); | |||
} | |||
@@ -23,9 +23,10 @@ | |||
static const int EDWARDS_D = -39081; | |||
/* End of template stuff */ | |||
extern void API_NS(deisogenize) ( | |||
extern mask_t API_NS(deisogenize) ( | |||
gf_s *__restrict__ s, | |||
gf_s *__restrict__ altx, | |||
gf_s *__restrict__ inv_el_sum, | |||
gf_s *__restrict__ inv_el_m1, | |||
const point_t p, | |||
mask_t toggle_hibit_s, | |||
mask_t toggle_altx, | |||
@@ -131,48 +132,48 @@ API_NS(invert_elligator_nonuniform) ( | |||
const point_t p, | |||
uint32_t hint_ | |||
) { | |||
/* TODO: test that this can produce sqrt((d-a)/ud) etc. */ | |||
mask_t hint = hint_; | |||
mask_t sgn_s = -(hint & 1), | |||
sgn_t_over_s = -(hint>>1 & 1), | |||
sgn_altx = -(hint>>1 & 1), | |||
sgn_r0 = -(hint>>2 & 1), | |||
/* FUTURE MAGIC: eventually if there's a curve which needs sgn_ed_T but not sgn_r0, | |||
* change this mask extraction. | |||
*/ | |||
sgn_ed_T = -(hint>>3 & 1); | |||
gf a, b, c, d; | |||
API_NS(deisogenize)(a,c,p,sgn_s,sgn_t_over_s,sgn_ed_T); | |||
gf a,b,c; | |||
mask_t swap = API_NS(deisogenize)(a,b,c,p,sgn_s,sgn_altx,sgn_ed_T); | |||
mask_t is_identity = gf_eq(p->t,ZERO); | |||
(void)is_identity; | |||
gf_cond_sel(b,b,ONE,is_identity & sgn_altx); | |||
gf_cond_sel(c,c,ONE,is_identity & sgn_s &~ sgn_altx); | |||
#if IMAGINE_TWIST | |||
gf_mulw(a,b,EDWARDS_D); | |||
gf_sub(b,a,b); | |||
#else | |||
gf_mulw(a,b,EDWARDS_D-1); | |||
gf_add(b,a,b); | |||
#endif | |||
gf_sub(a,a,c); | |||
gf_add(b,b,c); | |||
gf_cond_swap(a,b,swap); | |||
gf_mul_qnr(c,b); | |||
gf_mul(b,c,a); | |||
mask_t succ = gf_isr(c,b); | |||
succ |= gf_eq(b,ZERO); | |||
gf_mul(b,c,a); | |||
#if 448 == 8*SER_BYTES + 1 /* p521. */ | |||
sgn_r0 = 0; | |||
#endif | |||
/* ok, a = s; c = -t/s */ | |||
gf_mul(b,c,a); | |||
gf_sub(b,ONE,b); /* t+1 */ | |||
gf_sqr(c,a); /* s^2 */ | |||
mask_t is_identity = gf_eq(p->t,ZERO); | |||
/* identity adjustments */ | |||
/* in case of identity, currently c=0, t=0, b=1, will encode to 1 */ | |||
/* if hint is 0, -> 0 */ | |||
/* if hint is to neg t/s, then go to infinity, effectively set s to 1 */ | |||
gf_cond_sel(c,c,ONE,is_identity & sgn_t_over_s); | |||
gf_cond_sel(b,b,ZERO,is_identity & ~sgn_t_over_s & ~sgn_s); | |||
gf_mulw(d,c,2*EDWARDS_D-1); /* $d = (2d-a)s^2 */ | |||
gf_add(a,b,d); /* num? */ | |||
gf_sub(d,d,b); /* den? */ | |||
gf_mul(b,a,d); /* n*d */ | |||
gf_cond_sel(a,d,a,sgn_s); | |||
gf_mul_qnr(d,b); | |||
mask_t succ = gf_isr(c,d)|gf_eq(d,ZERO); | |||
gf_mul(b,a,c); | |||
gf_cond_neg(b, sgn_r0^gf_hibit(b)); | |||
succ &= ~(gf_eq(b,ZERO) & sgn_r0); | |||
#if COFACTOR == 8 | |||
succ &= ~(is_identity & sgn_ed_T); /* NB: there are no preimages of rotated identity. */ | |||
#endif | |||
// #if COFACTOR == 8 | |||
// succ &= ~(is_identity & sgn_ed_T); /* NB: there are no preimages of rotated identity. */ | |||
// #endif | |||
#if 448 == 8*SER_BYTES + 1 /* p521 */ | |||
gf_serialize(recovered_hash,b,0); | |||
@@ -120,27 +120,30 @@ gf_invert(gf y, const gf x, int assert_nonzero) { | |||
const point_t API_NS(point_identity) = {{{{{0}}},{{{1}}},{{{1}}},{{{0}}}}}; | |||
/* Predeclare because not static: called by elligator */ | |||
void API_NS(deisogenize) ( | |||
mask_t API_NS(deisogenize) ( | |||
gf_s *__restrict__ s, | |||
gf_s *__restrict__ altx, | |||
gf_s *__restrict__ inv_el_sum, | |||
gf_s *__restrict__ inv_el_m1, | |||
const point_t p, | |||
mask_t toggle_hibit_s, | |||
mask_t toggle_s, | |||
mask_t toggle_altx, | |||
mask_t toggle_rotation | |||
); | |||
void API_NS(deisogenize) ( | |||
mask_t API_NS(deisogenize) ( | |||
gf_s *__restrict__ s, | |||
gf_s *__restrict__ altx, | |||
gf_s *__restrict__ inv_el_sum, | |||
gf_s *__restrict__ inv_el_m1, | |||
const point_t p, | |||
mask_t toggle_hibit_s, | |||
mask_t toggle_s, | |||
mask_t toggle_altx, | |||
mask_t toggle_rotation | |||
) { | |||
#if COFACTOR == 4 | |||
#if COFACTOR == 4 && !IMAGINE_TWIST | |||
(void)toggle_rotation; /* Only applies to cofactor 8 */ | |||
gf t1,t2,t3; | |||
gf t1; | |||
gf_s *t2 = s, *t3=inv_el_sum, *t4=inv_el_m1; | |||
gf_add(t1,p->x,p->t); | |||
gf_sub(t2,p->x,p->t); | |||
@@ -150,20 +153,27 @@ void API_NS(deisogenize) ( | |||
gf_mulw(t2,t1,-1-TWISTED_D); /* -x^2 * (a-d) * num */ | |||
gf_isr(t1,t2); /* t1 = isr */ | |||
gf_mul(t2,t1,t3); /* t2 = ratio */ | |||
gf_mul(altx,t2,RISTRETTO_ISOMAGIC); | |||
mask_t negx = gf_lobit(altx) ^ toggle_altx; | |||
gf_mul(t4,t2,RISTRETTO_ISOMAGIC); | |||
mask_t negx = gf_lobit(t4) ^ toggle_altx; | |||
gf_cond_neg(t2, negx); | |||
gf_cond_neg(altx, negx); | |||
gf_mul(t3,t2,p->z); | |||
gf_sub(t3,t3,p->t); | |||
gf_mul(t2,t3,p->x); | |||
gf_mulw(t3,t2,-1-TWISTED_D); | |||
gf_mul(s,t3,t1); | |||
gf_cond_neg(s,gf_lobit(s)^toggle_hibit_s); | |||
gf_mulw(t4,t2,-1-TWISTED_D); | |||
gf_mul(s,t4,t1); | |||
mask_t lobs = gf_lobit(s); | |||
gf_cond_neg(s,lobs); | |||
gf_copy(inv_el_m1,p->x); | |||
gf_cond_neg(inv_el_m1,~lobs^negx^toggle_s); | |||
gf_add(inv_el_m1,inv_el_m1,p->t); | |||
return toggle_s; | |||
#elif COFACTOR == 8 && IMAGINE_TWIST | |||
gf_s *altx = inv_el_sum; // TODO | |||
(void)inv_el_m1; | |||
#elif COFACTOR == 8 | |||
/* More complicated because of rotation */ | |||
gf t1,t2,t3,t4; | |||
gf t1,t2,t3,t4,t5; | |||
gf_add(t1,p->z,p->y); | |||
gf_sub(t2,p->z,p->y); | |||
gf_mul(t3,t1,t2); /* t3 = num */ | |||
@@ -185,27 +195,34 @@ void API_NS(deisogenize) ( | |||
mask_t rotate = toggle_rotation ^ gf_lobit(t3); | |||
gf_cond_swap(t1,t2,rotate); | |||
gf_cond_sel(t4,p->y,t4,rotate); /* ix if rotate, else y */ | |||
gf_cond_sel(t4,p->y,t4,rotate); /* "fac" = ix if rotate, else y */ | |||
gf_mul(t3,t2,t4); /* "fac*iden" */ | |||
gf_mul_qnr(t2,RISTRETTO_ISOMAGIC); | |||
gf_mul(t4,t2,t3); /* "fac*iden*imi" */ | |||
gf_mul(t3,t2,p->t); | |||
gf_mul(altx,t3,t1); | |||
mask_t negx = rotate ^ gf_lobit(altx) ^ toggle_altx; | |||
gf_cond_neg(altx,negx); | |||
gf_cond_neg(t1,negx); | |||
gf_mul(t5,t2,p->t); | |||
gf_mul(altx,t5,t1); | |||
mask_t negx = gf_lobit(altx) ^ toggle_altx; | |||
gf_cond_neg(t1,negx^rotate); | |||
gf_mul(t2,t1,p->z); | |||
gf_add(t2,t2,ONE); | |||
gf_mul(s,t2,t4); | |||
gf_cond_neg(s,gf_lobit(s)^toggle_hibit_s); | |||
mask_t negs = gf_lobit(s); | |||
gf_cond_neg(s,negs); | |||
mask_t negz = ~negs ^ toggle_s ^ negx; | |||
gf_copy(inv_el_m1,p->z); | |||
gf_cond_neg(inv_el_m1,negz); | |||
gf_sub(inv_el_m1,inv_el_m1,t3); | |||
return toggle_s; | |||
#else | |||
#error "Cofactor must be 4 or 8" | |||
#error "Cofactor must be 4 (with no IMAGINE_TWIST) or 8 (with IMAGINE_TWIST)" | |||
#endif | |||
} | |||
void API_NS(point_encode)( unsigned char ser[SER_BYTES], const point_t p ) { | |||
gf s, mtos; | |||
API_NS(deisogenize)(s,mtos,p,0,0,0); | |||
gf s,ie1,ie2; | |||
(void)API_NS(deisogenize)(s,ie1,ie2,p,0,0,0); | |||
gf_serialize(ser,s,1); | |||
} | |||
@@ -12,9 +12,10 @@ | |||
static const int EDWARDS_D = $(d); | |||
/* End of template stuff */ | |||
extern void API_NS(deisogenize) ( | |||
extern mask_t API_NS(deisogenize) ( | |||
gf_s *__restrict__ s, | |||
gf_s *__restrict__ altx, | |||
gf_s *__restrict__ inv_el_sum, | |||
gf_s *__restrict__ inv_el_m1, | |||
const point_t p, | |||
mask_t toggle_hibit_s, | |||
mask_t toggle_altx, | |||
@@ -120,48 +121,48 @@ API_NS(invert_elligator_nonuniform) ( | |||
const point_t p, | |||
uint32_t hint_ | |||
) { | |||
/* TODO: test that this can produce sqrt((d-a)/ud) etc. */ | |||
mask_t hint = hint_; | |||
mask_t sgn_s = -(hint & 1), | |||
sgn_t_over_s = -(hint>>1 & 1), | |||
sgn_altx = -(hint>>1 & 1), | |||
sgn_r0 = -(hint>>2 & 1), | |||
/* FUTURE MAGIC: eventually if there's a curve which needs sgn_ed_T but not sgn_r0, | |||
* change this mask extraction. | |||
*/ | |||
sgn_ed_T = -(hint>>3 & 1); | |||
gf a, b, c, d; | |||
API_NS(deisogenize)(a,c,p,sgn_s,sgn_t_over_s,sgn_ed_T); | |||
gf a,b,c; | |||
mask_t swap = API_NS(deisogenize)(a,b,c,p,sgn_s,sgn_altx,sgn_ed_T); | |||
mask_t is_identity = gf_eq(p->t,ZERO); | |||
(void)is_identity; | |||
gf_cond_sel(b,b,ONE,is_identity & sgn_altx); | |||
gf_cond_sel(c,c,ONE,is_identity & sgn_s &~ sgn_altx); | |||
#if IMAGINE_TWIST | |||
gf_mulw(a,b,EDWARDS_D); | |||
gf_sub(b,a,b); | |||
#else | |||
gf_mulw(a,b,EDWARDS_D-1); | |||
gf_add(b,a,b); | |||
#endif | |||
gf_sub(a,a,c); | |||
gf_add(b,b,c); | |||
gf_cond_swap(a,b,swap); | |||
gf_mul_qnr(c,b); | |||
gf_mul(b,c,a); | |||
mask_t succ = gf_isr(c,b); | |||
succ |= gf_eq(b,ZERO); | |||
gf_mul(b,c,a); | |||
#if $(gf_bits) == 8*SER_BYTES + 1 /* p521. */ | |||
sgn_r0 = 0; | |||
#endif | |||
/* ok, a = s; c = -t/s */ | |||
gf_mul(b,c,a); | |||
gf_sub(b,ONE,b); /* t+1 */ | |||
gf_sqr(c,a); /* s^2 */ | |||
mask_t is_identity = gf_eq(p->t,ZERO); | |||
/* identity adjustments */ | |||
/* in case of identity, currently c=0, t=0, b=1, will encode to 1 */ | |||
/* if hint is 0, -> 0 */ | |||
/* if hint is to neg t/s, then go to infinity, effectively set s to 1 */ | |||
gf_cond_sel(c,c,ONE,is_identity & sgn_t_over_s); | |||
gf_cond_sel(b,b,ZERO,is_identity & ~sgn_t_over_s & ~sgn_s); | |||
gf_mulw(d,c,2*EDWARDS_D-1); /* $d = (2d-a)s^2 */ | |||
gf_add(a,b,d); /* num? */ | |||
gf_sub(d,d,b); /* den? */ | |||
gf_mul(b,a,d); /* n*d */ | |||
gf_cond_sel(a,d,a,sgn_s); | |||
gf_mul_qnr(d,b); | |||
mask_t succ = gf_isr(c,d)|gf_eq(d,ZERO); | |||
gf_mul(b,a,c); | |||
gf_cond_neg(b, sgn_r0^gf_hibit(b)); | |||
succ &= ~(gf_eq(b,ZERO) & sgn_r0); | |||
#if COFACTOR == 8 | |||
succ &= ~(is_identity & sgn_ed_T); /* NB: there are no preimages of rotated identity. */ | |||
#endif | |||
// #if COFACTOR == 8 | |||
// succ &= ~(is_identity & sgn_ed_T); /* NB: there are no preimages of rotated identity. */ | |||
// #endif | |||
#if $(gf_bits) == 8*SER_BYTES + 1 /* p521 */ | |||
gf_serialize(recovered_hash,b,0); | |||
@@ -75,7 +75,7 @@ void usage() { | |||
fprintf(stderr," Operations:\n"); | |||
fprintf(stderr," -n [point]: negative of point\n"); | |||
fprintf(stderr," -s [scalar] * [point]: Hash to curve using elligator\n"); | |||
fprintf(stderr," [point] + [point]: Add two poitns\n"); | |||
fprintf(stderr," [point] + [point]: Add two points\n"); | |||
fprintf(stderr,"\n"); | |||
fprintf(stderr," NB: this is a debugging widget. It doesn't yet have order of operations.\n"); | |||
fprintf(stderr," *** DON'T USE THIS UTILITY FOR ACTUAL CRYPTO! ***\n"); | |||
@@ -483,7 +483,7 @@ static void test_cfrg_vectors() { | |||
SecureBuffer eddsa_pk2 = priv.pub().serialize(); | |||
if (!memeq(SecureBuffer(eddsa_pk[t]), eddsa_pk2)) { | |||
test.fail(); | |||
printf(" EdDSA PK vectors disagree."); | |||
printf(" EdDSA PK vectors #%d disagree.", t); | |||
printf("\n Correct: "); | |||
for (unsigned i=0; i<eddsa_pk[t].size(); i++) printf("%02x", eddsa_pk[t][i]); | |||
printf("\n Incorrect: "); | |||