123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- # Prover implementation for Weierstrass curves of the form
- # y^2 = x^3 + A * x + B, specifically with a = 0 and b = 7, with group laws
- # operating on affine and Jacobian coordinates, including the point at infinity
- # represented by a 4th variable in coordinates.
-
- load("group_prover.sage")
-
-
- class affinepoint:
- def __init__(self, x, y, infinity=0):
- self.x = x
- self.y = y
- self.infinity = infinity
- def __str__(self):
- return "affinepoint(x=%s,y=%s,inf=%s)" % (self.x, self.y, self.infinity)
-
-
- class jacobianpoint:
- def __init__(self, x, y, z, infinity=0):
- self.X = x
- self.Y = y
- self.Z = z
- self.Infinity = infinity
- def __str__(self):
- return "jacobianpoint(X=%s,Y=%s,Z=%s,inf=%s)" % (self.X, self.Y, self.Z, self.Infinity)
-
-
- def point_at_infinity():
- return jacobianpoint(1, 1, 1, 1)
-
-
- def negate(p):
- if p.__class__ == affinepoint:
- return affinepoint(p.x, -p.y)
- if p.__class__ == jacobianpoint:
- return jacobianpoint(p.X, -p.Y, p.Z)
- assert(False)
-
-
- def on_weierstrass_curve(A, B, p):
- """Return a set of zero-expressions for an affine point to be on the curve"""
- return constraints(zero={p.x^3 + A*p.x + B - p.y^2: 'on_curve'})
-
-
- def tangential_to_weierstrass_curve(A, B, p12, p3):
- """Return a set of zero-expressions for ((x12,y12),(x3,y3)) to be a line that is tangential to the curve at (x12,y12)"""
- return constraints(zero={
- (p12.y - p3.y) * (p12.y * 2) - (p12.x^2 * 3 + A) * (p12.x - p3.x): 'tangential_to_curve'
- })
-
-
- def colinear(p1, p2, p3):
- """Return a set of zero-expressions for ((x1,y1),(x2,y2),(x3,y3)) to be collinear"""
- return constraints(zero={
- (p1.y - p2.y) * (p1.x - p3.x) - (p1.y - p3.y) * (p1.x - p2.x): 'colinear_1',
- (p2.y - p3.y) * (p2.x - p1.x) - (p2.y - p1.y) * (p2.x - p3.x): 'colinear_2',
- (p3.y - p1.y) * (p3.x - p2.x) - (p3.y - p2.y) * (p3.x - p1.x): 'colinear_3'
- })
-
-
- def good_affine_point(p):
- return constraints(nonzero={p.x : 'nonzero_x', p.y : 'nonzero_y'})
-
-
- def good_jacobian_point(p):
- return constraints(nonzero={p.X : 'nonzero_X', p.Y : 'nonzero_Y', p.Z^6 : 'nonzero_Z'})
-
-
- def good_point(p):
- return constraints(nonzero={p.Z^6 : 'nonzero_X'})
-
-
- def finite(p, *affine_fns):
- con = good_point(p) + constraints(zero={p.Infinity : 'finite_point'})
- if p.Z != 0:
- return con + reduce(lambda a, b: a + b, (f(affinepoint(p.X / p.Z^2, p.Y / p.Z^3)) for f in affine_fns), con)
- else:
- return con
-
- def infinite(p):
- return constraints(nonzero={p.Infinity : 'infinite_point'})
-
-
- def law_jacobian_weierstrass_add(A, B, pa, pb, pA, pB, pC):
- """Check whether the passed set of coordinates is a valid Jacobian add, given assumptions"""
- assumeLaw = (good_affine_point(pa) +
- good_affine_point(pb) +
- good_jacobian_point(pA) +
- good_jacobian_point(pB) +
- on_weierstrass_curve(A, B, pa) +
- on_weierstrass_curve(A, B, pb) +
- finite(pA) +
- finite(pB) +
- constraints(nonzero={pa.x - pb.x : 'different_x'}))
- require = (finite(pC, lambda pc: on_weierstrass_curve(A, B, pc) +
- colinear(pa, pb, negate(pc))))
- return (assumeLaw, require)
-
-
- def law_jacobian_weierstrass_double(A, B, pa, pb, pA, pB, pC):
- """Check whether the passed set of coordinates is a valid Jacobian doubling, given assumptions"""
- assumeLaw = (good_affine_point(pa) +
- good_affine_point(pb) +
- good_jacobian_point(pA) +
- good_jacobian_point(pB) +
- on_weierstrass_curve(A, B, pa) +
- on_weierstrass_curve(A, B, pb) +
- finite(pA) +
- finite(pB) +
- constraints(zero={pa.x - pb.x : 'equal_x', pa.y - pb.y : 'equal_y'}))
- require = (finite(pC, lambda pc: on_weierstrass_curve(A, B, pc) +
- tangential_to_weierstrass_curve(A, B, pa, negate(pc))))
- return (assumeLaw, require)
-
-
- def law_jacobian_weierstrass_add_opposites(A, B, pa, pb, pA, pB, pC):
- assumeLaw = (good_affine_point(pa) +
- good_affine_point(pb) +
- good_jacobian_point(pA) +
- good_jacobian_point(pB) +
- on_weierstrass_curve(A, B, pa) +
- on_weierstrass_curve(A, B, pb) +
- finite(pA) +
- finite(pB) +
- constraints(zero={pa.x - pb.x : 'equal_x', pa.y + pb.y : 'opposite_y'}))
- require = infinite(pC)
- return (assumeLaw, require)
-
-
- def law_jacobian_weierstrass_add_infinite_a(A, B, pa, pb, pA, pB, pC):
- assumeLaw = (good_affine_point(pa) +
- good_affine_point(pb) +
- good_jacobian_point(pA) +
- good_jacobian_point(pB) +
- on_weierstrass_curve(A, B, pb) +
- infinite(pA) +
- finite(pB))
- require = finite(pC, lambda pc: constraints(zero={pc.x - pb.x : 'c.x=b.x', pc.y - pb.y : 'c.y=b.y'}))
- return (assumeLaw, require)
-
-
- def law_jacobian_weierstrass_add_infinite_b(A, B, pa, pb, pA, pB, pC):
- assumeLaw = (good_affine_point(pa) +
- good_affine_point(pb) +
- good_jacobian_point(pA) +
- good_jacobian_point(pB) +
- on_weierstrass_curve(A, B, pa) +
- infinite(pB) +
- finite(pA))
- require = finite(pC, lambda pc: constraints(zero={pc.x - pa.x : 'c.x=a.x', pc.y - pa.y : 'c.y=a.y'}))
- return (assumeLaw, require)
-
-
- def law_jacobian_weierstrass_add_infinite_ab(A, B, pa, pb, pA, pB, pC):
- assumeLaw = (good_affine_point(pa) +
- good_affine_point(pb) +
- good_jacobian_point(pA) +
- good_jacobian_point(pB) +
- infinite(pA) +
- infinite(pB))
- require = infinite(pC)
- return (assumeLaw, require)
-
-
- laws_jacobian_weierstrass = {
- 'add': law_jacobian_weierstrass_add,
- 'double': law_jacobian_weierstrass_double,
- 'add_opposite': law_jacobian_weierstrass_add_opposites,
- 'add_infinite_a': law_jacobian_weierstrass_add_infinite_a,
- 'add_infinite_b': law_jacobian_weierstrass_add_infinite_b,
- 'add_infinite_ab': law_jacobian_weierstrass_add_infinite_ab
- }
-
-
- def check_exhaustive_jacobian_weierstrass(name, A, B, branches, formula, p):
- """Verify an implementation of addition of Jacobian points on a Weierstrass curve, by executing and validating the result for every possible addition in a prime field"""
- F = Integers(p)
- print("Formula %s on Z%i:" % (name, p))
- points = []
- for x in range(0, p):
- for y in range(0, p):
- point = affinepoint(F(x), F(y))
- r, e = concrete_verify(on_weierstrass_curve(A, B, point))
- if r:
- points.append(point)
-
- for za in range(1, p):
- for zb in range(1, p):
- for pa in points:
- for pb in points:
- for ia in range(2):
- for ib in range(2):
- pA = jacobianpoint(pa.x * F(za)^2, pa.y * F(za)^3, F(za), ia)
- pB = jacobianpoint(pb.x * F(zb)^2, pb.y * F(zb)^3, F(zb), ib)
- for branch in range(0, branches):
- assumeAssert, assumeBranch, pC = formula(branch, pA, pB)
- pC.X = F(pC.X)
- pC.Y = F(pC.Y)
- pC.Z = F(pC.Z)
- pC.Infinity = F(pC.Infinity)
- r, e = concrete_verify(assumeAssert + assumeBranch)
- if r:
- match = False
- for key in laws_jacobian_weierstrass:
- assumeLaw, require = laws_jacobian_weierstrass[key](A, B, pa, pb, pA, pB, pC)
- r, e = concrete_verify(assumeLaw)
- if r:
- if match:
- print(" multiple branches for (%s,%s,%s,%s) + (%s,%s,%s,%s)" % (pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity))
- else:
- match = True
- r, e = concrete_verify(require)
- if not r:
- print(" failure in branch %i for (%s,%s,%s,%s) + (%s,%s,%s,%s) = (%s,%s,%s,%s): %s" % (branch, pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity, pC.X, pC.Y, pC.Z, pC.Infinity, e))
- print()
-
-
- def check_symbolic_function(R, assumeAssert, assumeBranch, f, A, B, pa, pb, pA, pB, pC):
- assumeLaw, require = f(A, B, pa, pb, pA, pB, pC)
- return check_symbolic(R, assumeLaw, assumeAssert, assumeBranch, require)
-
- def check_symbolic_jacobian_weierstrass(name, A, B, branches, formula):
- """Verify an implementation of addition of Jacobian points on a Weierstrass curve symbolically"""
- R.<ax,bx,ay,by,Az,Bz,Ai,Bi> = PolynomialRing(QQ,8,order='invlex')
- lift = lambda x: fastfrac(R,x)
- ax = lift(ax)
- ay = lift(ay)
- Az = lift(Az)
- bx = lift(bx)
- by = lift(by)
- Bz = lift(Bz)
- Ai = lift(Ai)
- Bi = lift(Bi)
-
- pa = affinepoint(ax, ay, Ai)
- pb = affinepoint(bx, by, Bi)
- pA = jacobianpoint(ax * Az^2, ay * Az^3, Az, Ai)
- pB = jacobianpoint(bx * Bz^2, by * Bz^3, Bz, Bi)
-
- res = {}
-
- for key in laws_jacobian_weierstrass:
- res[key] = []
-
- print("Formula " + name + ":")
- count = 0
- for branch in range(branches):
- assumeFormula, assumeBranch, pC = formula(branch, pA, pB)
- pC.X = lift(pC.X)
- pC.Y = lift(pC.Y)
- pC.Z = lift(pC.Z)
- pC.Infinity = lift(pC.Infinity)
-
- for key in laws_jacobian_weierstrass:
- res[key].append((check_symbolic_function(R, assumeFormula, assumeBranch, laws_jacobian_weierstrass[key], A, B, pa, pb, pA, pB, pC), branch))
-
- for key in res:
- print(" %s:" % key)
- val = res[key]
- for x in val:
- if x[0] is not None:
- print(" branch %i: %s" % (x[1], x[0]))
-
- print()
|