1# coding: utf-8
2#
3# Elliptic Curve Equation
4#
5# y^2 = x^3 + A*x + B (mod P)
6#
7from .math import Math
8from .point import Point
9
10
11class CurveFp:
12
13 def __init__(self, A, B, P, N, Gx, Gy, name, oid, nistName=None, glvParams=None):
14 self.A = A
15 self.B = B
16 self.P = P
17 self.N = N
18 self.nBitLength = N.bit_length()
19 self.G = Point(Gx, Gy)
20 self.name = name
21 self.nistName = nistName
22 self.oid = oid # ASN.1 Object Identifier
23 # GLV endomorphism parameters (only for curves that support one,
24 # e.g. secp256k1). None means no endomorphism; fall back to Shamir+JSF.
25 self.glvParams = glvParams
26
27 def contains(self, p):
28 """
29 Verify if the point `p` is on the curve
30
31 :param p: Point p = Point(x, y)
32 :return: boolean
33 """
34 if not 0 <= p.x <= self.P - 1:
35 return False
36 if not 0 <= p.y <= self.P - 1:
37 return False
38 if (p.y**2 - (p.x**3 + self.A * p.x + self.B)) % self.P != 0:
39 return False
40 return True
41
42 def length(self):
43 return (1 + len("%x" % self.N)) // 2
44
45 def y(self, x, isEven):
46 ySquared = (pow(x, 3, self.P) + self.A * x + self.B) % self.P
47 y = Math.modularSquareRoot(ySquared, self.P)
48 if isEven != (y % 2 == 0):
49 y = self.P - y
50 return y
51
52
53_curvesByOid = {tuple(curve.oid): curve for curve in []}
54
55
56def add(curve):
57 _curvesByOid[tuple(curve.oid)] = curve
58
59
60def getByOid(oid):
61 if oid not in _curvesByOid:
62 raise Exception("Unknown curve with oid {oid}; The following are registered: {names}".format(
63 oid=".".join([str(number) for number in oid]),
64 names=", ".join([curve.name for curve in _curvesByOid.values()]),
65 ))
66 return _curvesByOid[oid]
67
68
69secp256k1 = CurveFp(
70 name="secp256k1",
71 A=0x0000000000000000000000000000000000000000000000000000000000000000,
72 B=0x0000000000000000000000000000000000000000000000000000000000000007,
73 P=0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f,
74 N=0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141,
75 Gx=0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,
76 Gy=0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8,
77 oid=[1, 3, 132, 0, 10],
78 # GLV endomorphism φ((x,y)) = (β·x, y), equivalent to λ·P.
79 # Basis vectors from Gauss reduction; used to split a 256-bit scalar k
80 # into two ~128-bit scalars (k1, k2) with k ≡ k1 + k2·λ (mod N).
81 glvParams={
82 "beta": 0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee,
83 "lambda": 0x5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72,
84 "a1": 0x3086d221a7d46bcde86c90e49284eb15,
85 "b1": -0xe4437ed6010e88286f547fa90abfe4c3,
86 "a2": 0x114ca50f7a8e2f3f657c1108d9d44cfd8,
87 "b2": 0x3086d221a7d46bcde86c90e49284eb15,
88 },
89)
90
91prime256v1 = CurveFp(
92 name="prime256v1",
93 nistName="P-256",
94 A=0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc,
95 B=0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b,
96 P=0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff,
97 N=0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551,
98 Gx=0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296,
99 Gy=0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5,
100 oid=[1, 2, 840, 10045, 3, 1, 7],
101)
102
103p256 = prime256v1
104
105add(secp256k1)
106add(prime256v1)