diff --git a/Makefile b/Makefile index bb27775..b19fe3e 100644 --- a/Makefile +++ b/Makefile @@ -20,11 +20,11 @@ BUILD_IBIN = build/obj/bin DOXYGEN ?= doxygen ifeq ($(UNAME),Darwin) -CC = clang -CXX = clang++ +CC ?= clang +CXX ?= clang++ else -CC = gcc -CXX = g++ +CC ?= gcc +CXX ?= g++ endif LD = $(CC) LDXX = $(CXX) diff --git a/_aux/ristretto/ristretto.sage b/_aux/ristretto/ristretto.sage index 4bb08cc..41b0d22 100644 --- a/_aux/ristretto/ristretto.sage +++ b/_aux/ristretto/ristretto.sage @@ -121,6 +121,8 @@ class QuotientEdwardsPoint(object): else: return self.__class__(-self.x, -self.y) + def doubleAndEncodeSpec(self): + return (self+self).encode() # Utility functions @classmethod @@ -203,7 +205,42 @@ class RistrettoPoint(QuotientEdwardsPoint): if negative(isr^2*num*y*t): y = -y s = isr*y*(z-y) - + return self.gfToBytes(s,mustBePositive=True) + + @optimized_version_of("doubleAndEncodeSpec") + def doubleAndEncode(self): + X,Y,Z,T = self.xyzt() + a,d,mneg = self.a,self.d,self.mneg + + if self.cofactor==8: + e = 2*X*Y + f = Z^2+d*T^2 + g = Y^2-a*X^2 + h = Z^2-d*T^2 + + inv1 = inv0(e*f*g*h) + z_inv = inv1*e*g # 1 / (f*h) + t_inv = inv1*f*h + + if negative(e*g*z_inv): + if a==-1: sqrta = self.i + else: sqrta = -1 + e,f,g,h = g,h,-e,f*sqrta + factor = self.i + else: + factor = self.magic + + if negative(h*e*z_inv): g=-g + s = (h-g)*factor*g*t_inv + + else: + foo = Y^2+a*X^2 + bar = X*Y + den = inv0(foo*bar) + if negative(2*bar^2*den): tmp = a*X^2 + else: tmp = Y^2 + s = self.magic*(Z^2-tmp)*foo*den + return self.gfToBytes(s,mustBePositive=True) @classmethod @@ -466,6 +503,54 @@ class Decaf_1_1_Point(QuotientEdwardsPoint): x = 2*s / (1+a*s^2) y = (1-a*s^2) / t return cls(x,sgn*y) + + @optimized_version_of("doubleAndEncodeSpec") + def doubleAndEncode(self): + X,Y,Z,T = self.xyzt() + a,d = self.a,self.d + + if self.cofactor == 8: + # Cofactor 8 version + # Simulate IMAGINE_TWIST because that's how libdecaf does it + X = self.i*X + T = self.i*T + a = -a + d = -d + # TODO: This is only being called for a=-1, so could + # be wrong for a=1 + + e = 2*X*Y + f = Y^2+a*X^2 + g = Y^2-a*X^2 + h = Z^2-d*T^2 + + eim = e*self.isoMagic + inv = inv0(eim*g*f*h) + fh_inv = eim*g*inv*self.i + + if negative(eim*g*fh_inv): + idf = g*self.isoMagic*self.i + bar = f + foo = g + test = eim*f + else: + idf = eim + bar = h + foo = -eim + test = g*h + + if negative(test*fh_inv): bar =- bar + s = idf*(foo+bar)*inv*f*h + + else: + xy = X*Y + h = Z^2-d*T^2 + inv = inv0(xy*h) + if negative(inv*2*xy^2*self.isoMagic): tmp = Y + else: tmp = X + s = tmp^2*h*inv # = X/Y or Y/X, interestingly + + return self.gfToBytes(s,mustBePositive=True) @classmethod def elligatorSpec(cls,r0,fromR=False): @@ -696,7 +781,6 @@ def test(cls,n): if Q1 + Q0 != Q2: raise TestFailedException("Scalarmul doesn't work") Q = Q1 - def testElligator(cls,n): print "Testing elligator on %s" % cls.__name__ for i in xrange(n): @@ -716,9 +800,6 @@ def testElligator(cls,n): #break else: pass # TODO - - - def gangtest(classes,n): print "Gang test",[cls.__name__ for cls in classes] @@ -747,18 +828,37 @@ def gangtest(classes,n): print c,binascii.hexlify(ret) print - -test(Ed25519Point,100) -test(NegEd25519Point,100) -test(IsoEd25519Point,100) -test(IsoEd448Point,100) -test(TwistedEd448GoldilocksPoint,100) -test(Ed448GoldilocksPoint,100) -testElligator(Ed25519Point,100) -testElligator(NegEd25519Point,100) -testElligator(IsoEd25519Point,100) -testElligator(IsoEd448Point,100) -testElligator(Ed448GoldilocksPoint,100) -testElligator(TwistedEd448GoldilocksPoint,100) -gangtest([IsoEd448Point,TwistedEd448GoldilocksPoint,Ed448GoldilocksPoint],100) -gangtest([Ed25519Point,IsoEd25519Point],100) +def testDoubleAndEncode(cls,n): + print "Testing doubleAndEncode on %s" % cls.__name__ + + P = cls() + for i in xrange(cls.cofactor): + Q = P.torque() + assert P.doubleAndEncode() == Q.doubleAndEncode() + P = Q + + for i in xrange(n): + r1 = randombytes(cls.encLen) + r2 = randombytes(cls.encLen) + u = cls.elligator(r1) + cls.elligator(r2) + assert u.doubleAndEncode() == u.torque().doubleAndEncode() + +testDoubleAndEncode(Ed25519Point,100) +testDoubleAndEncode(NegEd25519Point,100) +testDoubleAndEncode(IsoEd25519Point,100) +testDoubleAndEncode(IsoEd448Point,100) +testDoubleAndEncode(TwistedEd448GoldilocksPoint,100) +#test(Ed25519Point,100) +#test(NegEd25519Point,100) +#test(IsoEd25519Point,100) +#test(IsoEd448Point,100) +#test(TwistedEd448GoldilocksPoint,100) +#test(Ed448GoldilocksPoint,100) +#testElligator(Ed25519Point,100) +#testElligator(NegEd25519Point,100) +#testElligator(IsoEd25519Point,100) +#testElligator(IsoEd448Point,100) +#testElligator(Ed448GoldilocksPoint,100) +#testElligator(TwistedEd448GoldilocksPoint,100) +#gangtest([IsoEd448Point,TwistedEd448GoldilocksPoint,Ed448GoldilocksPoint],100) +#gangtest([Ed25519Point,IsoEd25519Point],100) diff --git a/src/generator/curve_data.py b/src/generator/curve_data.py index 8e7e8d9..f1773be 100644 --- a/src/generator/curve_data.py +++ b/src/generator/curve_data.py @@ -133,8 +133,11 @@ for curve,data in curve_data.items(): data["eddsa_sigma_iso"] = 0 if "rist_base_decoded" not in data: + def xord(x): + if isinstance(x,str): return ord(x) + else: return x data["rist_base_decoded"] = sum( - ord(b)<<(8*i) for i,b in enumerate(unhexlify(data["rist_base"])) + xord(b)<<(8*i) for i,b in enumerate(unhexlify(data["rist_base"])) ) if "imagine_twist" not in data: diff --git a/src/per_curve/decaf.tmpl.c b/src/per_curve/decaf.tmpl.c index 833f301..56b9d7f 100644 --- a/src/per_curve/decaf.tmpl.c +++ b/src/per_curve/decaf.tmpl.c @@ -776,7 +776,7 @@ decaf_bool_t API_NS(point_eq) ( const point_t p, const point_t q ) { gf_mul ( b, q->y, p->x ); mask_t succ = gf_eq(a,b); - #if (COFACTOR == 8) && IMAGINE_TWIST + #if (COFACTOR == 8) gf_mul ( a, p->y, q->y ); gf_mul ( b, q->x, p->x ); #if !(IMAGINE_TWIST) diff --git a/src/per_curve/point.tmpl.hxx b/src/per_curve/point.tmpl.hxx index d481777..2e5c11d 100644 --- a/src/per_curve/point.tmpl.hxx +++ b/src/per_curve/point.tmpl.hxx @@ -305,7 +305,7 @@ public: */ inline explicit Point(const FixedBlock &buffer, bool allow_identity=true) /*throw(CryptoException)*/ { - if (DECAF_SUCCESS != decode(buffer,allow_identity ? DECAF_TRUE : DECAF_FALSE)) { + if (DECAF_SUCCESS != decode(buffer,allow_identity)) { throw CryptoException(); } } diff --git a/test/test_decaf.sage b/test/test_decaf.sage index c2e7439..19e0490 100644 --- a/test/test_decaf.sage +++ b/test/test_decaf.sage @@ -10,6 +10,7 @@ p_tor4 = E.lift_x(-1) Tor = [p_tor4 * i for i in xrange(4)] q = 2^446-0x8335dc163bb124b65129c96fde933d8d723a70aadc873d6d54a7bb0d FQ = GF(q) +isoMagic = 1/sqrt(F(39082/39081)-1) passing = True @@ -195,7 +196,16 @@ class DecafScalar(): return True class DecafPoint(): - _UNDER = c_uint64 * int(8*4) + @staticmethod + def _UNDER(): + size = int(8*8*4) + alignment = 32 + buf1 = bytearray(size+alignment-1) + buf2 = (c_char * int(size+alignment-1)).from_buffer(buf1) + raw_addr = addressof(buf2) + offset = (-raw_addr) % alignment + return (c_char*size).from_buffer(buf2,int(offset)) + def __init__(self,cstruct=None,point=None): if cstruct is None: cstruct = DecafPoint._UNDER() @@ -222,12 +232,11 @@ class DecafPoint(): @staticmethod def _sage_deser(str): s = from_le(str) - if s > (F.cardinality()-1)/2: raise Exception("Point didn't decode") + if is_odd(s): raise Exception("Point didn't decode") if (s==0): return E(0) if not E.is_x_coord(s^2): raise Exception("Point didn't decode") P = E.lift_x(s^2) - t = P.xy()[1] / s - if is_odd(int(2*t/s)): P = -P + if is_odd(int(2*s^2*isoMagic/P.xy()[1])): P = -P return P def __eq__(self,other): @@ -318,16 +327,16 @@ class DecafPoint(): x,y = P.xy() s = sqrt(x) if s==0: return to_le(0,56) - if is_odd(int(2*y/s^2)): s = 1/s - if int(s) > (F.cardinality()-1)/2: s = -s + if is_odd(int(2*s^2*isoMagic/y)): s = 1/s + if is_odd(int(s)): s = -s return to_le(s,56) def _check(self): ss = self._sage_ser(self.point) cs = self._c_ser(self.cstruct) if ss != cs: - print ss - print cs + print "SAGE",b64encode(ss) + print "C ",b64encode(cs) raise Exception("Check failed!") return True