From 5fc32bf1e9af9836fb1a01a23c52ff93f4922c0a Mon Sep 17 00:00:00 2001 From: Michael Hamburg Date: Thu, 5 Oct 2017 19:11:31 -0700 Subject: [PATCH] elligator apparently(?) working for ed448 --- aux/ristretto/ristretto.sage | 126 ++++++++++++++------ src/GENERATED/c/curve25519/decaf.c | 69 +++++++---- src/GENERATED/c/curve25519/elligator.c | 61 +++++----- src/GENERATED/c/ed448goldilocks/decaf.c | 69 +++++++---- src/GENERATED/c/ed448goldilocks/elligator.c | 61 +++++----- src/per_curve/decaf.tmpl.c | 69 +++++++---- src/per_curve/elligator.tmpl.c | 61 +++++----- test/ristretto.cxx | 2 +- test/test_decaf.cxx | 2 +- 9 files changed, 315 insertions(+), 205 deletions(-) diff --git a/aux/ristretto/ristretto.sage b/aux/ristretto/ristretto.sage index 8dfee08..3f442d5 100644 --- a/aux/ristretto/ristretto.sage +++ b/aux/ristretto/ristretto.sage @@ -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) diff --git a/src/GENERATED/c/curve25519/decaf.c b/src/GENERATED/c/curve25519/decaf.c index 4e6aa34..36ca9ec 100644 --- a/src/GENERATED/c/curve25519/decaf.c +++ b/src/GENERATED/c/curve25519/decaf.c @@ -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); } diff --git a/src/GENERATED/c/curve25519/elligator.c b/src/GENERATED/c/curve25519/elligator.c index 1eaa8d7..0511d23 100644 --- a/src/GENERATED/c/curve25519/elligator.c +++ b/src/GENERATED/c/curve25519/elligator.c @@ -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); diff --git a/src/GENERATED/c/ed448goldilocks/decaf.c b/src/GENERATED/c/ed448goldilocks/decaf.c index ce569a9..e3c46b2 100644 --- a/src/GENERATED/c/ed448goldilocks/decaf.c +++ b/src/GENERATED/c/ed448goldilocks/decaf.c @@ -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); } diff --git a/src/GENERATED/c/ed448goldilocks/elligator.c b/src/GENERATED/c/ed448goldilocks/elligator.c index 3b4e162..feb3bb1 100644 --- a/src/GENERATED/c/ed448goldilocks/elligator.c +++ b/src/GENERATED/c/ed448goldilocks/elligator.c @@ -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); diff --git a/src/per_curve/decaf.tmpl.c b/src/per_curve/decaf.tmpl.c index b38977a..6da0bfa 100644 --- a/src/per_curve/decaf.tmpl.c +++ b/src/per_curve/decaf.tmpl.c @@ -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); } diff --git a/src/per_curve/elligator.tmpl.c b/src/per_curve/elligator.tmpl.c index 95848f0..747f361 100644 --- a/src/per_curve/elligator.tmpl.c +++ b/src/per_curve/elligator.tmpl.c @@ -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); diff --git a/test/ristretto.cxx b/test/ristretto.cxx index 5e6bc42..1b6597b 100644 --- a/test/ristretto.cxx +++ b/test/ristretto.cxx @@ -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"); diff --git a/test/test_decaf.cxx b/test/test_decaf.cxx index 00405ec..b72269b 100644 --- a/test/test_decaf.cxx +++ b/test/test_decaf.cxx @@ -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