|
|
@@ -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) |