Commit abe22e57 authored by Michael Hamburg's avatar Michael Hamburg
Browse files

iso-ed working for cofactor 8, but maybe not for a=-1 isoed25519

parent 5f12ca45
......@@ -5,6 +5,7 @@ class SpecException(Exception): pass
def lobit(x): return int(x) & 1
def hibit(x): return lobit(2*x)
def negative(x): return lobit(x)
def enc_le(x,n): return bytearray([int(x)>>(8*i) & 0xFF for i in xrange(n)])
def dec_le(x): return sum(b<<(8*i) for i,b in enumerate(x))
def randombytes(n): return bytearray([randint(0,255) for _ in range(n)])
......@@ -36,7 +37,7 @@ def xsqrt(x,exn=InvalidEncodingException("Not on curve")):
"""Return sqrt(x)"""
if not is_square(x): raise exn
s = sqrt(x)
if lobit(s): s=-s
if negative(s): s=-s
return s
def isqrt(x,exn=InvalidEncodingException("Not on curve")):
......@@ -106,7 +107,8 @@ class QuotientEdwardsPoint(object):
def torque(self):
"""Apply cofactor group, except keeping the point even"""
if self.cofactor == 8:
return self.__class__(self.y*self.i, self.x*self.i)
if self.a == -1: return self.__class__(self.y*self.i, self.x*self.i)
if self.a == 1: return self.__class__(-self.y, self.x)
else:
return self.__class__(-self.x, -self.y)
......@@ -120,14 +122,15 @@ class QuotientEdwardsPoint(object):
s = dec_le(bytes)
if mustBeProper and s >= cls.F.modulus():
raise InvalidEncodingException("%d out of range!" % s)
if mustBePositive and lobit(s):
s = cls.F(s)
if mustBePositive and negative(s):
raise InvalidEncodingException("%d is negative!" % s)
return cls.F(s)
return s
@classmethod
def gfToBytes(cls,x,mustBePositive=False):
"""Convert little-endian bytes to field element, sanity check length"""
if lobit(x) and mustBePositive: x = -x
if negative(x) and mustBePositive: x = -x
return enc_le(x,cls.encLen)
class RistrettoPoint(QuotientEdwardsPoint):
......@@ -135,12 +138,10 @@ class RistrettoPoint(QuotientEdwardsPoint):
def encodeSpec(self):
"""Unoptimized specification for encoding"""
x,y = self
if self.cofactor==8 and (lobit(x*y) or y==0):
(x,y) = (self.i*y,self.i*x)
if self.cofactor==8 and (negative(x*y) or y==0): (x,y) = self.torque()
if y == -1: y = 1 # Avoid divide by 0; doesn't affect impl
if lobit(x): x,y = -x,-y
if negative(x): x,y = -x,-y
s = xsqrt(self.a*(y-1)/(y+1),exn=Exception("Unimplemented: point is odd: " + str(self)))
return self.gfToBytes(s)
......@@ -153,7 +154,7 @@ class RistrettoPoint(QuotientEdwardsPoint):
x = xsqrt(4*s^2 / (a*d*(1+a*s^2)^2 - (1-a*s^2)^2))
y = (1+a*s^2) / (1-a*s^2)
if cls.cofactor==8 and (lobit(x*y) or y==0):
if cls.cofactor==8 and (negative(x*y) or y==0):
raise InvalidEncodingException("x*y has high bit")
return cls(x,y)
......@@ -171,13 +172,14 @@ class RistrettoPoint(QuotientEdwardsPoint):
i2 = isr*u2
z_inv = i1*i2*t
if self.cofactor==8 and lobit(t*z_inv):
x,y = y*self.i,x*self.i
if self.cofactor==8 and negative(t*z_inv):
if a==-1: x,y = y*self.i,x*self.i
else: x,y = -y,x # TODO: test
den_inv = self.magic * i1
else:
den_inv = i2
if lobit(x*z_inv): y = -y
if negative(x*z_inv): y = -y
s = (z-y) * den_inv
return self.gfToBytes(s,mustBePositive=True)
......@@ -199,10 +201,10 @@ class RistrettoPoint(QuotientEdwardsPoint):
yden_inv = xden_inv * isr * xden_sqr
x = 2*s*xden_inv
if lobit(x): x = -x
if negative(x): x = -x
y = ynum * yden_inv
if cls.cofactor==8 and (lobit(x*y) or y==0):
if cls.cofactor==8 and (negative(x*y) or y==0):
raise InvalidEncodingException("x*y is invalid: %d, %d" % (x,y))
return cls(x,y)
......@@ -213,7 +215,7 @@ class RistrettoPoint(QuotientEdwardsPoint):
a,d = cls.a,cls.d
assert s^4 - 2*cls.a*(1-2*d/(d-a))*s^2 + 1 == t^2
x = 2*s*cls.magic / t
if lobit(x): x = -x # TODO: doesn't work without resolving x
if negative(x): x = -x # TODO: doesn't work without resolving x
y = (1+a*s^2) / (1-a*s^2)
return cls(sgn*x,y)
......@@ -249,20 +251,26 @@ class RistrettoPoint(QuotientEdwardsPoint):
return cls.fromJacobiQuartic(s,t,sgn)
class Decaf1Point(QuotientEdwardsPoint):
class Decaf_1_1_Point(QuotientEdwardsPoint):
"""Like current decaf but tweaked for simplicity"""
def encodeSpec(self):
"""Unoptimized specification for encoding"""
a,d = self.a,self.d
x,y = self
if x==0: return(self.gfToBytes(0))
if x==0 or y==0: return(self.gfToBytes(0))
if self.cofactor==8 and negative(x*y*self.isoMagic):
x,y = self.torque()
isr2 = isqrt(a*(y^2-1)) / self.magic
sr = xsqrt(1-a*x^2)
assert sr in [isr2*x*y,-isr2*x*y]
altx = 1/isr2*self.isoMagic
if lobit(altx): s = (1+x*y*isr2)/(a*x)
else: s = (1-x*y*isr2)/(a*x)
if negative(altx): s = (1+x*y*isr2)/(a*x)
else: s = (1-x*y*isr2)/(a*x)
# TODO: cofactor 8
return self.gfToBytes(s,mustBePositive=True)
@classmethod
......@@ -274,11 +282,13 @@ class Decaf1Point(QuotientEdwardsPoint):
if s==0: return cls()
isr = isqrt(s^4 + 2*(a-2*d)*s^2 + 1)
altx = 2*s*isr*cls.isoMagic
if lobit(altx): isr = -isr
if negative(altx): isr = -isr
x = 2*s / (1+a*s^2)
y = (1-a*s^2) * isr
# TODO: cofactor 8
if cls.cofactor==8 and (negative(x*y*cls.isoMagic) or y==0):
raise InvalidEncodingException("x*y is invalid: %d, %d" % (x,y))
return cls(x,y)
@optimized_version_of("encodeSpec")
......@@ -325,7 +335,7 @@ class IsoEd448Point(RistrettoPoint):
"00000000000000000000000000000000000000000000000000000000"+
"fdffffffffffffffffffffffffffffffffffffffffffffffffffffff")))
class TwistedEd448GoldilocksPoint(Decaf1Point):
class TwistedEd448GoldilocksPoint(Decaf_1_1_Point):
F = GF(2^448-2^224-1)
d = F(-39082)
a = F(-1)
......@@ -341,7 +351,7 @@ class TwistedEd448GoldilocksPoint(Decaf1Point):
"00000000000000000000000000000000000000000000000000000000"+
"fdffffffffffffffffffffffffffffffffffffffffffffffffffffff")))
class Ed448GoldilocksPoint(Decaf1Point):
class Ed448GoldilocksPoint(Decaf_1_1_Point):
F = GF(2^448-2^224-1)
d = F(-39081)
a = F(1)
......@@ -357,6 +367,24 @@ class Ed448GoldilocksPoint(Decaf1Point):
"00000000000000000000000000000000000000000000000000000000"+
"fdffffffffffffffffffffffffffffffffffffffffffffffffffffff")))
class IsoEd25519Point(Decaf_1_1_Point):
# TODO: twisted iso too!
# TODO: twisted iso might have to IMAGINE_TWIST or whatever
F = GF(2^255-19)
d = F(-121665)
a = F(1)
i = sqrt(F(-1))
qnr = i
magic = isqrt(a*d-1)
cofactor = 8
encLen = 32
isoMagic = Ed25519Point.magic
isoA = Ed25519Point.a
@classmethod
def base(cls):
return cls.decodeSpec(Ed25519Point.base().encode())
class TestFailedException(Exception): pass
def test(cls,n):
......@@ -385,6 +413,7 @@ def test(cls,n):
if Q1 + Q0 != Q2: raise TestFailedException("Scalarmul doesn't work")
Q = Q1
test(Ed25519Point,100)
test(IsoEd25519Point,100)
test(IsoEd448Point,100)
test(TwistedEd448GoldilocksPoint,100)
test(Ed448GoldilocksPoint,100)
......@@ -398,6 +427,7 @@ def gangtest(classes,n):
print c,binascii.hexlify(ret)
print
gangtest([IsoEd448Point,TwistedEd448GoldilocksPoint,Ed448GoldilocksPoint],100)
gangtest([Ed25519Point,IsoEd25519Point],100)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment