| @@ -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: "); | |||