From ffb58e91141a201d4995af006cdc74a81ab00dfb Mon Sep 17 00:00:00 2001 From: Daira Hopwood Date: Thu, 2 Nov 2017 05:52:36 +0000 Subject: [PATCH] Initial commit (including the original verify.sage). Signed-off-by: Daira Hopwood --- README.md | 28 ++++ a | 1 + d | 1 + l | 1 + p | 1 + rigid | 1 + shape | 1 + verify.sage | 378 ++++++++++++++++++++++++++++++++++++++++++++++++++++ x0 | 1 + x1 | 1 + y0 | 1 + y1 | 1 + 12 files changed, 416 insertions(+) create mode 100644 README.md create mode 100644 a create mode 100644 d create mode 100644 l create mode 100644 p create mode 100644 rigid create mode 100644 shape create mode 100644 verify.sage create mode 100644 x0 create mode 100644 x1 create mode 100644 y0 create mode 100644 y1 diff --git a/README.md b/README.md new file mode 100644 index 0000000..371dd50 --- /dev/null +++ b/README.md @@ -0,0 +1,28 @@ +Jubjub supporting evidence +-------------------------- + +This repository contains supporting evidence that the twisted Edwards curve +-x^2 + y^2 = 1 - (10240/10241) of rational points over +GF(52435875175126190479447740508185965837690552500527637822603658699938581184513), +[also called "Jubjub"](https://z.cash/technology/jubjub.html), +satisfies the [SafeCurves criteria](https://safecurves.cr.yp.to/index.html). + +The script ``verify.sage`` is based on +[this script from the SafeCurves site](https://safecurves.cr.yp.to/verify.html), +modified + +* to support twisted Edwards curves; +* to generate a file 'primes' containing the primes needed for primality proofs, + if it is not already present; +* to change the directory in which Pocklington proof files are generated + (``proof/`` rather than ``../../../proof``), and to create that directory + if it does not exist. + +Prerequisites: + +* apt-get install sagemath +* pip install sortedcontainers + +Run ``sage verify.sage .``, or ``./run.sh`` to also print out the results. + +Note that the "rigidity" criterion cannot be checked automatically. diff --git a/a b/a new file mode 100644 index 0000000..3a2e3f4 --- /dev/null +++ b/a @@ -0,0 +1 @@ +-1 diff --git a/d b/d new file mode 100644 index 0000000..767309a --- /dev/null +++ b/d @@ -0,0 +1 @@ +19257038036680949359750312669786877991949435402254120286184196891950884077233 diff --git a/l b/l new file mode 100644 index 0000000..83f92d5 --- /dev/null +++ b/l @@ -0,0 +1 @@ +6554484396890773809930967563523245729705921265872317281365359162392183254199 diff --git a/p b/p new file mode 100644 index 0000000..1dc0557 --- /dev/null +++ b/p @@ -0,0 +1 @@ +52435875175126190479447740508185965837690552500527637822603658699938581184513 diff --git a/rigid b/rigid new file mode 100644 index 0000000..e560e40 --- /dev/null +++ b/rigid @@ -0,0 +1 @@ +fully rigid diff --git a/shape b/shape new file mode 100644 index 0000000..796f74d --- /dev/null +++ b/shape @@ -0,0 +1 @@ +tedwards diff --git a/verify.sage b/verify.sage new file mode 100644 index 0000000..05e6b05 --- /dev/null +++ b/verify.sage @@ -0,0 +1,378 @@ +import os +import sys + +def readfile(fn): + fd = open(fn,'r') + r = fd.read() + fd.close() + return r + +def writefile(fn,s): + fd = open(fn,'w') + fd.write(s) + fd.close() + +def expand2(n): + s = "" + + while n != 0: + j = 16 + while 2**j < abs(n): j += 1 + if 2**j - abs(n) > abs(n) - 2**(j-1): j -= 1 + + if abs(abs(n) - 2**j) > 2**(j - 10): + if n > 0: + if s != "": s += " + " + s += str(n) + else: + s += " - " + str(-n) + n = 0 + elif n > 0: + if s != "": s += " + " + s += "2^" + str(j) + n -= 2**j + else: + s += " - 2^" + str(j) + n += 2**j + + return s + +def requirement(fn,istrue): + writefile(fn,str(istrue) + '\n') + return istrue + +def verify(): + p = Integer(readfile('p')) + k = GF(p) + kz. = k[] + l = Integer(readfile('l')) + x0 = Integer(readfile('x0')) + y0 = Integer(readfile('y0')) + x1 = Integer(readfile('x1')) + y1 = Integer(readfile('y1')) + shape = readfile('shape').strip() + s = readfile('primes') + rigid = readfile('rigid').strip() + + safefield = True + safeeq = True + safebase = True + saferho = True + safetransfer = True + safedisc = True + saferigid = True + safeladder = True + safetwist = True + safecomplete = True + safeind = True + + V = [] # distinct verified primes + for line in s.split(): + n = Integer(line) + if not n.is_prime(): continue + if n == 2: + if not n in V: V += [n] + continue + for trybase in primes(2,10000): + base = Integers(n)(trybase) + if base^(n-1) != 1: continue + proof = 'Primality proof for n = %s:\n' % n + proof += '

Take b = %s.\n' % base + proof += '

b^(n-1) mod n = 1.\n' + f = factor(1) + for v in reversed(V): + if f.prod()^2 <= n: + if n % v == 1: + u = base^((n-1)/v)-1 + if u.is_unit(): + proof += '

%s is prime.\n' % (v,v) + proof += '
b^((n-1)/%s)-1 mod n = %s, which is a unit, inverse %s.\n' % (v,u,1/u) + f *= factor(v)^(n-1).valuation(v) + if f.prod()^2 <= n: continue + if n % f.prod() != 1: continue + proof += '

(%s) divides n-1.\n' % f + proof += '

(%s)^2 > n.\n' % f + proof += "

n is prime by Pocklington's theorem.\n" + proof += '\n' + writefile('../../../proof/%s.html' % n,proof) + if not n in V: V += [n] + break + + writefile('verify-primes',''.join('%s\n' % (v,v) for v in V)) + + pstatus = 'Unverified' + if not p.is_prime(): pstatus = 'False' + if p in V: pstatus = 'True' + if pstatus != 'True': safefield = False + writefile('verify-pisprime',pstatus + '\n') + + pstatus = 'Unverified' + if not l.is_prime(): pstatus = 'False' + if l in V: pstatus = 'True' + if pstatus != 'True': safebase = False + writefile('verify-lisprime',pstatus + '\n') + + writefile('expand2-p','= %s\n' % expand2(p)) + writefile('expand2-l','
= %s\n' % expand2(l)) + + writefile('hex-p',hex(p) + '\n') + writefile('hex-l',hex(l) + '\n') + writefile('hex-x0',hex(x0) + '\n') + writefile('hex-x1',hex(x1) + '\n') + writefile('hex-y0',hex(y0) + '\n') + writefile('hex-y1',hex(y1) + '\n') + + gcdlpis1 = gcd(l,p) == 1 + safetransfer &= requirement('verify-gcdlp1',gcdlpis1) + + writefile('verify-movsafe','Unverified\n') + writefile('verify-embeddingdegree','Unverified\n') + if gcdlpis1 and l.is_prime(): + u = Integers(l)(p) + d = l-1 + for v in V: + while d % v == 0: d /= v + if d == 1: + d = l-1 + for v in V: + while d % v == 0: + if u^(d/v) != 1: break + d /= v + safetransfer &= requirement('verify-movsafe',(l-1)/d <= 100) + writefile('verify-embeddingdegree','%s
= (l-1)/%s\n' % (d,(l-1)/d)) + + t = p+1-l*round((p+1)/l) + if l^2 > 16*p: + writefile('verify-trace','%s\n' % t) + f = factor(1) + d = (p+1-t)/l + for v in V: + while d % v == 0: + d //= v + f *= factor(v) + writefile('verify-cofactor','%s\n' % f) + else: + writefile('verify-trace','Unverified\n') + writefile('verify-cofactor','Unverified\n') + + D = t^2-4*p + for v in V: + while D % v^2 == 0: D /= v^2 + if prod([v for v in V if D % v == 0]) != -D: + writefile('verify-disc','Unverified\n') + writefile('verify-discisbig','Unverified\n') + safedisc = False + else: + f = -prod([factor(v) for v in V if D % v == 0]) + if D % 4 != 1: + D *= 4 + f = factor(4) * f + Dbits = (log(-D)/log(2)).numerical_approx() + writefile('verify-disc','%s
= %s
≈ -2^%.1f\n' % (D,f,Dbits)) + safedisc &= requirement('verify-discisbig',D < -2^100) + + pi4 = 0.78539816339744830961566084581987572105 + rho = log(pi4*l)/log(4) + writefile('verify-rho','%.1f\n' % rho) + saferho &= requirement('verify-rhoabove100',rho.numerical_approx() >= 100) + + twistl = 'Unverified' + d = p+1+t + for v in V: + while d % v == 0: d /= v + if d == 1: + d = p+1+t + for v in V: + if d % v == 0: + if twistl == 'Unverified' or v > twistl: twistl = v + + writefile('verify-twistl','%s\n' % twistl) + writefile('verify-twistembeddingdegree','Unverified\n') + writefile('verify-twistmovsafe','Unverified\n') + if twistl == 'Unverified': + writefile('hex-twistl','Unverified\n') + writefile('expand2-twistl','Unverified\n') + writefile('verify-twistcofactor','Unverified\n') + writefile('verify-gcdtwistlp1','Unverified\n') + writefile('verify-twistrho','Unverified\n') + safetwist = False + else: + writefile('hex-twistl',hex(twistl) + '\n') + writefile('expand2-twistl','
= %s\n' % expand2(twistl)) + f = factor(1) + d = (p+1+t)/twistl + for v in V: + while d % v == 0: + d //= v + f *= factor(v) + writefile('verify-twistcofactor','%s\n' % f) + gcdtwistlpis1 = gcd(twistl,p) == 1 + safetwist &= requirement('verify-gcdtwistlp1',gcdtwistlpis1) + + movsafe = 'Unverified' + embeddingdegree = 'Unverified' + if gcdtwistlpis1 and twistl.is_prime(): + u = Integers(twistl)(p) + d = twistl-1 + for v in V: + while d % v == 0: d /= v + if d == 1: + d = twistl-1 + for v in V: + while d % v == 0: + if u^(d/v) != 1: break + d /= v + safetwist &= requirement('verify-twistmovsafe',(twistl-1)/d <= 100) + writefile('verify-twistembeddingdegree',"%s
= (l'-1)/%s\n" % (d,(twistl-1)/d)) + + rho = log(pi4*twistl)/log(4) + writefile('verify-twistrho','%.1f\n' % rho) + safetwist &= requirement('verify-twistrhoabove100',rho.numerical_approx() >= 100) + + precomp = 0 + joint = l + for v in V: + d1 = p+1-t + d2 = p+1+t + while d1 % v == 0 or d2 % v == 0: + if d1 % v == 0: d1 //= v + if d2 % v == 0: d2 //= v + # best case for attack: cyclic; each power is usable + # also assume that kangaroo is as efficient as rho + if v + sqrt(pi4*joint/v) < sqrt(pi4*joint): + precomp += v + joint /= v + + rho = log(precomp + sqrt(pi4 * joint))/log(2) + writefile('verify-jointrho','%.1f\n' % rho) + safetwist &= requirement('verify-jointrhoabove100',rho.numerical_approx() >= 100) + + + x0 = k(x0) + y0 = k(y0) + x1 = k(x1) + y1 = k(y1) + + if shape == 'edwards': + d = Integer(readfile('d')) + writefile('verify-shape','Edwards\n') + writefile('verify-equation','x^2+y^2 = 1%+dx^2y^2\n' % d) + + d = k(d) + elliptic = d*(1-d) + level0 = x0^2+y0^2-1-d*x0^2*y0^2 + level1 = x1^2+y1^2-1-d*x1^2*y1^2 + + if shape == 'montgomery': + writefile('verify-shape','Montgomery\n') + A = Integer(readfile('A')) + B = Integer(readfile('B')) + equation = '%sy^2 = x^3%+dx^2+x' % (B,A) + if B == 1: + equation = 'y^2 = x^3%+dx^2+x' % A + writefile('verify-equation',equation + '\n') + + A = k(A) + B = k(B) + elliptic = B*(A^2-4) + level0 = B*y0^2-x0^3-A*x0^2-x0 + level1 = B*y1^2-x1^3-A*x1^2-x1 + + if shape == 'shortw': + writefile('verify-shape','short Weierstrass\n') + a = Integer(readfile('a')) + b = Integer(readfile('b')) + writefile('verify-equation','y^2 = x^3%+dx%+d\n' % (a,b)) + + a = k(a) + b = k(b) + elliptic = 4*a^3+27*b^2 + level0 = y0^2-x0^3-a*x0-b + level1 = y1^2-x1^3-a*x1-b + + writefile('verify-elliptic',str(elliptic) + '\n') + safeeq &= requirement('verify-iselliptic',elliptic != 0) + safebase &= requirement('verify-isoncurve0',level0 == 0) + safebase &= requirement('verify-isoncurve1',level1 == 0) + + if shape == 'edwards': + A = 2*(1+d)/(1-d) + B = 4/(1-d) + x0,y0 = (1+y0)/(1-y0),((1+y0)/(1-y0))/x0 + x1,y1 = (1+y1)/(1-y1),((1+y1)/(1-y1))/x1 + shape = 'montgomery' + + if shape == 'montgomery': + a = (3-A^2)/(3*B^2) + b = (2*A^3-9*A)/(27*B^3) + x0,y0 = (x0+A/3)/B,y0/B + x1,y1 = (x1+A/3)/B,y1/B + shape = 'shortw' + + try: + E = EllipticCurve([a,b]) + numorder2 = 0 + numorder4 = 0 + for P in E(0).division_points(4): + if P != 0 and 2*P == 0: + numorder2 += 1 + if 2*P != 0 and 4*P == 0: + numorder4 += 1 + writefile('verify-numorder2',str(numorder2) + '\n') + writefile('verify-numorder4',str(numorder4) + '\n') + completesingle = False + completemulti = False + if numorder4 == 2 and numorder2 == 1: + # complete edwards form, and montgomery with unique point of order 2 + completesingle = True + completemulti = True + # should extend this to allow complete twisted hessian + safecomplete &= requirement('verify-completesingle',completesingle) + safecomplete &= requirement('verify-completemulti',completemulti) + safecomplete &= requirement('verify-ltimesbase1is0',l * E([x1,y1]) == 0) + writefile('verify-ltimesbase1',str(l * E([x1,y1])) + '\n') + writefile('verify-cofactorbase01',str(((p+1-t)//l) * E([x0,y0]) == E([x1,y1])) + '\n') + except: + writefile('verify-numorder2','Unverified\n') + writefile('verify-numorder4','Unverified\n') + writefile('verify-ltimesbase1','Unverified\n') + writefile('verify-cofactorbase01','Unverified\n') + safecomplete = False + + montladder = False + for r,e in (z^3+a*z+b).roots(): + if (3*r^2+a).is_square(): + montladder = True + safeladder &= requirement('verify-montladder',montladder) + + indistinguishability = False + elligator2 = False + if (p+1-t) % 2 == 0: + if b != 0: + indistinguishability = True + elligator2 = True + safeind &= requirement('verify-indistinguishability',indistinguishability) + writefile('verify-ind-notes','Elligator 2: %s.\n' % ['No','Yes'][elligator2]) + + saferigid &= (rigid == 'fully rigid' or rigid == 'somewhat rigid') + + safecurve = True + safecurve &= requirement('verify-safefield',safefield) + safecurve &= requirement('verify-safeeq',safeeq) + safecurve &= requirement('verify-safebase',safebase) + safecurve &= requirement('verify-saferho',saferho) + safecurve &= requirement('verify-safetransfer',safetransfer) + safecurve &= requirement('verify-safedisc',safedisc) + safecurve &= requirement('verify-saferigid',saferigid) + safecurve &= requirement('verify-safeladder',safeladder) + safecurve &= requirement('verify-safetwist',safetwist) + safecurve &= requirement('verify-safecomplete',safecomplete) + safecurve &= requirement('verify-safeind',safeind) + requirement('verify-safecurve',safecurve) + +originaldir = os.open('.',os.O_RDONLY) +for i in range(1,len(sys.argv)): + os.fchdir(originaldir) + os.chdir(sys.argv[i]) + verify() + diff --git a/x0 b/x0 new file mode 100644 index 0000000..3b2097a --- /dev/null +++ b/x0 @@ -0,0 +1 @@ +11076627216317271660298050606127911965867021807910416450833192264015104452986 diff --git a/x1 b/x1 new file mode 100644 index 0000000..c8c8fc3 --- /dev/null +++ b/x1 @@ -0,0 +1 @@ +8076246640662884909881801758704306714034609987455869804520522091855516602923 diff --git a/y0 b/y0 new file mode 100644 index 0000000..b47cd27 --- /dev/null +++ b/y0 @@ -0,0 +1 @@ +44412834903739585386157632289020980010620626017712148233229312325549216099227 diff --git a/y1 b/y1 new file mode 100644 index 0000000..a46479f --- /dev/null +++ b/y1 @@ -0,0 +1 @@ +13262374693698910701929044844600465831413122818447359594527400194675274060458