starkbank-ecdsa 0.0.5 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 552ac4aee46c31ad3dcc11dac2022b7a458925d718fc22ac31c5349a580e441d
4
- data.tar.gz: 94d725e7728047557a4c032d5f27c9174b0ace61e76e54bdff481d28fc55ccf3
3
+ metadata.gz: 9b661f1bd378387d7c6466e9271adba268c3e85e7cc3a65ed71bb4e26a6e26d5
4
+ data.tar.gz: 9f815e7c6c4a95f302b12a0458eb6ab24596ff0df5a8cfcb51a608f463ee1b42
5
5
  SHA512:
6
- metadata.gz: 657954155c41471d9ecf3799d705c7183cb0beb888de65f9e609f7bad729e6188cd0fdd9f67ee7193ffb2807b679fa9ee1f3f08687b0a0ba9ff32dede7cd3476
7
- data.tar.gz: bb5e12f6c6f9413050f74f7acb6a204a75a0af1710689bca44a3af78783d6dec19315a623923c0c370bf23d4eded548d89e187b937cce1c8c04d63c0623e9d5a
6
+ metadata.gz: 62071d28e66c906ee70a2a3fe8bc5de2c4174cee49e0d90eb1f19b76014573462ad14035941717f162486dc33780b14e8fbddefff415249d70ba8a16fe79e75a
7
+ data.tar.gz: c1c599e3c8d5bb1f998fe91fdebf54f8b5efd43fb9644fac8425e5f9a20f3dab29b5a430763777b40800e27c7eba106d20c47195caa0ba27520bb5549a2ea3ea
data/lib/curve.rb ADDED
@@ -0,0 +1,112 @@
1
+ module EllipticCurve
2
+ #
3
+ # Elliptic Curve Equation
4
+ #
5
+ # y^2 = x^3 + A*x + B (mod P)
6
+ #
7
+ module Curve
8
+ class CurveFp
9
+ attr_accessor :a, :b, :p, :n, :g, :name, :oid, :nistName, :nBitLength, :glvParams
10
+ attr_accessor :_generatorPowersTable
11
+
12
+ def initialize(a, b, p, n, gx, gy, name, oid, nistName=nil, glvParams=nil)
13
+ @a = a
14
+ @b = b
15
+ @p = p
16
+ @n = n
17
+ @nBitLength = n.bit_length
18
+ @g = Point.new(gx, gy)
19
+ @name = name
20
+ @oid = oid
21
+ @nistName = nistName
22
+ # GLV endomorphism parameters (only for curves that support one,
23
+ # e.g. secp256k1). nil means no endomorphism; fall back to Shamir+JSF.
24
+ @glvParams = glvParams
25
+ @_generatorPowersTable = nil
26
+ end
27
+
28
+ def contains(p)
29
+ # Verify if the point `p` is on the curve
30
+ # :param p: point p = Point(x, y)
31
+ # :return: boolean
32
+ if not (0 <= p.x and p.x <= @p - 1)
33
+ return false
34
+ end
35
+ if not (0 <= p.y and p.y <= @p - 1)
36
+ return false
37
+ end
38
+ if (p.y ** 2 - (p.x ** 3 + @a * p.x + @b)) % @p != 0
39
+ return false
40
+ end
41
+ return true
42
+ end
43
+
44
+ def length
45
+ return (1 + ("%x" % @n).length).div(2)
46
+ end
47
+
48
+ def y(x, isEven)
49
+ ySquared = (x.pow(3, @p) + @a * x + @b) % @p
50
+ y = Math::modularSquareRoot(ySquared, @p)
51
+ if isEven != (y % 2 == 0)
52
+ y = @p - y
53
+ end
54
+ return y
55
+ end
56
+
57
+ end
58
+
59
+ @_curvesByOid = { }
60
+
61
+ def self.add(curve)
62
+ @_curvesByOid[curve.oid] = curve
63
+ end
64
+
65
+ def self.getbyOid(oid)
66
+ if not @_curvesByOid.include?(oid)
67
+ raise Exception.new("Unknown curve oid: #{oid}; The following are registered: #{@_curvesByOid.map{|k,v| v.name}}")
68
+ end
69
+ return @_curvesByOid[oid]
70
+ end
71
+
72
+ SECP256K1 = CurveFp.new(
73
+ 0x0000000000000000000000000000000000000000000000000000000000000000,
74
+ 0x0000000000000000000000000000000000000000000000000000000000000007,
75
+ 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f,
76
+ 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141,
77
+ 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,
78
+ 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8,
79
+ "secp256k1",
80
+ [1, 3, 132, 0, 10],
81
+ nil,
82
+ # GLV endomorphism phi((x,y)) = (beta*x, y), equivalent to lambda*P.
83
+ # Basis vectors from Gauss reduction; used to split a 256-bit scalar k
84
+ # into two ~128-bit scalars (k1, k2) with k == k1 + k2*lambda (mod N).
85
+ {
86
+ :beta => 0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee,
87
+ :lambda => 0x5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72,
88
+ :a1 => 0x3086d221a7d46bcde86c90e49284eb15,
89
+ :b1 => -0xe4437ed6010e88286f547fa90abfe4c3,
90
+ :a2 => 0x114ca50f7a8e2f3f657c1108d9d44cfd8,
91
+ :b2 => 0x3086d221a7d46bcde86c90e49284eb15,
92
+ }
93
+ )
94
+
95
+ PRIME256V1 = CurveFp.new(
96
+ 0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc,
97
+ 0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b,
98
+ 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff,
99
+ 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551,
100
+ 0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296,
101
+ 0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5,
102
+ "prime256v1",
103
+ [1, 2, 840, 10045, 3, 1, 7],
104
+ "p-256",
105
+ )
106
+
107
+ P256 = PRIME256V1
108
+
109
+ self.add(PRIME256V1)
110
+ self.add(SECP256K1)
111
+ end
112
+ end
data/lib/ecdsa.rb CHANGED
@@ -1,32 +1,62 @@
1
1
  require 'digest'
2
- require 'openssl'
3
- require_relative './signature'
4
2
 
5
3
 
6
4
  module EllipticCurve
7
-
8
5
  module Ecdsa
9
-
10
6
  def self.sign(message, privateKey, hashfunc=nil)
11
- if hashfunc.nil?
12
- message = Digest::SHA256.digest(message)
13
- else
14
- message = hashfunc(message)
7
+ if hashfunc.nil? then hashfunc = lambda{ |x| Digest::SHA256.digest(x) } end
8
+ curve = privateKey.curve
9
+ byteMessage = hashfunc.call(message)
10
+ numberMessage = Utils::Binary.numberFromByteString(byteMessage, curve.nBitLength)
11
+
12
+ r, s, randSignPoint = 0, 0, nil
13
+ kIterator = Utils::RandomInteger.rfc6979(byteMessage, privateKey.secret, curve, hashfunc)
14
+ while r == 0 or s == 0
15
+ randNum = kIterator.next
16
+ randSignPoint = Math.multiplyGenerator(curve, randNum)
17
+ r = randSignPoint.x % curve.n
18
+ s = ((numberMessage + r * privateKey.secret) * (Math.inv(randNum, curve.n))) % curve.n
19
+ end
20
+ recoveryId = randSignPoint.y & 1
21
+ if randSignPoint.y > curve.n
22
+ recoveryId += 2
23
+ end
24
+ if s > curve.n / 2
25
+ s = curve.n - s
26
+ recoveryId ^= 1
15
27
  end
16
28
 
17
- signature = privateKey.openSslPrivateKey.dsa_sign_asn1(message)
18
- return Signature.new(signature)
29
+ return Signature.new(r, s, recoveryId)
19
30
  end
20
31
 
21
32
  def self.verify(message, signature, publicKey, hashfunc=nil)
22
- if hashfunc.nil?
23
- message = Digest::SHA256.digest(message)
24
- else
25
- message = hashfunc(message)
33
+ if hashfunc.nil? then hashfunc = lambda{ |x| Digest::SHA256.digest(x) } end
34
+ curve = publicKey.curve
35
+ byteMessage = hashfunc.call(message)
36
+ numberMessage = Utils::Binary.numberFromByteString(byteMessage, curve.nBitLength)
37
+
38
+ r = signature.r
39
+ s = signature.s
40
+
41
+ if not (1 <= r and r <= curve.n - 1)
42
+ return false
26
43
  end
27
- return publicKey.openSslPublicKey.dsa_verify_asn1(message, signature.toDer())
44
+ if not (1 <= s and s <= curve.n - 1)
45
+ return false
46
+ end
47
+ if not curve.contains(publicKey.point)
48
+ return false
49
+ end
50
+ inv = Math.inv(s, curve.n)
51
+ v = Math.multiplyAndAdd(
52
+ curve.g, (numberMessage * inv) % curve.n,
53
+ publicKey.point, (r * inv) % curve.n,
54
+ curve.n, curve.a, curve.p, curve,
55
+ )
56
+ if v.isAtInfinity
57
+ return false
58
+ end
59
+ return v.x % curve.n == r
28
60
  end
29
-
30
61
  end
31
-
32
- end
62
+ end