ecdsa_ext 0.3.2 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f677f4ad2748b8deece8f2372fc76ffcbcf0f2e951914ea621a97b7654cf847b
4
- data.tar.gz: fd05c8a9404150adb80d34ac25ded983509739c6cdb8e96abc59305c18873629
3
+ metadata.gz: 84f032825c120367ced4c69a3faf2f25c519b0591a6fe2e6a9ebe21e1456a66b
4
+ data.tar.gz: af328ff04a086fabaf93652cab94400c95a1dfba85daff6667defca0c112b2a1
5
5
  SHA512:
6
- metadata.gz: 0b2f252817dbb9f94a6fd0f23dffc2d6351450bf8a7c1a324c8e200e9b7aa573be30af9b2b20c5d2ac9d3ca407a50d3988d74a6f6bebeecf2f622a3577e44f7e
7
- data.tar.gz: ef7b1b7db62bc607729cbee51114a6096cc715062d31680ec28af61165f6b95f03a126627c4a69a3ef520520bd0518426cc916f6dc45d633740223d10effb619
6
+ metadata.gz: c1c83beba1a26a89ba958f0b1f3f75ea48ad4777f252c1430294997cf44385c205559876354fe62d728f714fc162606af4975535c813a18595623d8ed6944d09
7
+ data.tar.gz: e32b28574ec1c21cc336039e9a66a780784a7a5d3ea2a1fa20796799c2077f24b6db0dcb8853d0b7067bba4b6b41d7196214df10b7175037ab118828a74934ba
data/README.md CHANGED
@@ -82,4 +82,13 @@ affine_point = projective_point4.to_affine
82
82
  Jacobian coordinates have been supported since 0.3.0.
83
83
 
84
84
  When using Jacobian coordinates, use `ECDSA::Ext::JacobianPoint` instead of `ECDSA::Ext::ProjectivePoint`.
85
- In addition, `ECDSA::Point` now has a `to_jacobian` method that convert affine coordinates to jacobian coordinates.
85
+ In addition, `ECDSA::Point` now has a `to_jacobian` method that convert affine coordinates to jacobian coordinates.
86
+
87
+ ### Apply jacobian coordinates to existing ECDSA sign/verify
88
+
89
+ If you want the existing ECDSA gem to generate and verify signatures in Jacobian coordinates,
90
+ add the following code. This code is a monkey patch to do the existing process in Jacobian coordinates.
91
+
92
+ ```ruby
93
+ require 'ecdsa/ext/sign_verify'
94
+ ```
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ECDSA
4
+ module Ext
5
+ # Abstract class of point
6
+ class AbstractPoint
7
+ attr_reader :group, :x, :y, :z, :infinity
8
+
9
+ # Create new instance.
10
+ # @param [ECDSA::Group] group
11
+ # @param [Array] args [x, y, z]
12
+ # @return [ECDSA::Ext::AbstractPoint]
13
+ def initialize(group, *args)
14
+ @group = group
15
+ if args == [:infinity]
16
+ @infinity = true
17
+ else
18
+ @infinity = false
19
+ @x, @y, @z = args
20
+ raise ArgumentError, "Invalid x: #{x.inspect}" unless x.is_a?(Integer)
21
+ raise ArgumentError, "Invalid y: #{y.inspect}" unless y.is_a?(Integer)
22
+ raise ArgumentError, "Invalid z: #{z.inspect}" unless z.is_a?(Integer)
23
+ end
24
+ end
25
+
26
+ # Get filed of this group.
27
+ # @return [ECDSA::PrimeField]
28
+ def field
29
+ group.field
30
+ end
31
+
32
+ # Convert coordinates from affine.
33
+ # @param [ECDSA::Point] point
34
+ # @return [ECDSA::Ext::AbstractPoint]
35
+ def self.from_affine(point)
36
+ if point.infinity?
37
+ infinity_point(point.group)
38
+ else
39
+ new(point.group, point.x, point.y, 1)
40
+ end
41
+ end
42
+
43
+ # Create infinity point
44
+ # @return [ECDSA::Ext::AbstractPoint]
45
+ def self.infinity_point(group)
46
+ new(group, :infinity)
47
+ end
48
+
49
+ # Check whether infinity point or not.
50
+ # @return [Boolean]
51
+ def infinity?
52
+ @infinity
53
+ end
54
+
55
+ # Return additive inverse of the point.
56
+ # @return [ECDSA::Ext::AbstractPoint]
57
+ def negate
58
+ return self if infinity?
59
+ self.class.new(group, x, field.mod(-y), z)
60
+ end
61
+
62
+ # Return coordinates.
63
+ # @return [Array] (x, y , z)
64
+ def coords
65
+ [x, y, z]
66
+ end
67
+
68
+ # Return the point multiplied by a non-negative integer.
69
+ # @param [Integer] x
70
+ # @return [ECDSA::Ext::ProjectivePoint]
71
+ def multiply_by_scalar(x)
72
+ raise ArgumentError, "Scalar is not an integer." unless x.is_a?(Integer)
73
+ raise ArgumentError, "Scalar is negative." if x.negative?
74
+
75
+ q = self.class.infinity_point(group)
76
+ v = self
77
+ i = x
78
+ while i.positive?
79
+ q = q.add_to_point(v) if i.odd?
80
+ v = v.double
81
+ i >>= 1
82
+ end
83
+ q
84
+ end
85
+ alias * multiply_by_scalar
86
+
87
+ def add_to_point(other)
88
+ raise NotImplementedError
89
+ end
90
+
91
+ def double
92
+ raise NotImplementedError
93
+ end
94
+
95
+ def to_affine
96
+ raise NotImplementedError
97
+ end
98
+
99
+ def ==(other)
100
+ raise NotImplementedError
101
+ end
102
+ end
103
+ end
104
+ end
@@ -3,53 +3,9 @@
3
3
  module ECDSA
4
4
  module Ext
5
5
  # Point of Jacobian coordinates
6
- class JacobianPoint
6
+ class JacobianPoint < AbstractPoint
7
7
  include JacobianArithmetic
8
8
 
9
- attr_reader :group, :x, :y, :z
10
-
11
- # Create new instance of jacobian
12
- # @param [ECDSA::Group] group
13
- # @param [Array] args [x, y, z]
14
- # @return [ECDSA::Ext::ProjectivePoint]
15
- def initialize(group, *args)
16
- @group = group
17
- @x, @y, @z = args
18
- raise ArgumentError, "Invalid x: #{x.inspect}" unless x.is_a?(Integer)
19
- raise ArgumentError, "Invalid y: #{y.inspect}" unless y.is_a?(Integer)
20
- raise ArgumentError, "Invalid z: #{z.inspect}" unless z.is_a?(Integer)
21
- end
22
-
23
- # Get filed of this group.
24
- # @return [ECDSA::PrimeField]
25
- def field
26
- group.field
27
- end
28
-
29
- # Convert coordinates from affine to jacobian.
30
- # @param [ECDSA::Point] point
31
- # @return [ECDSA::Ext::JacobianPoint]
32
- def self.from_affine(point)
33
- if point.infinity?
34
- JacobianPoint.infinity(point.group)
35
- else
36
- new(point.group, point.x, point.y, 1)
37
- end
38
- end
39
-
40
- # Create infinity point
41
- # @return [ECDSA::Ext::JacobianPoint]
42
- def self.infinity(group)
43
- # new(group, :infinity)
44
- new(group, 0, 1, 0)
45
- end
46
-
47
- # Check whether infinity point or not.
48
- # @return [Boolean]
49
- def infinity?
50
- x.zero? && y == 1 && z.zero?
51
- end
52
-
53
9
  # Add this point to another point on the same curve.
54
10
  # @param [ECDSA::Ext::JacobianPoint] other
55
11
  # @return [ECDSA::Ext::JacobianPoint]
@@ -65,7 +21,7 @@ module ECDSA
65
21
  return self if other.infinity?
66
22
 
67
23
  if x == other.x && y == field.mod(-other.y) && z == other.z
68
- return JacobianPoint.infinity(group)
24
+ return JacobianPoint.infinity_point(group)
69
25
  end
70
26
 
71
27
  return other if y.zero? || z.zero?
@@ -106,25 +62,6 @@ module ECDSA
106
62
  JacobianPoint.new(group, t, y3, z3)
107
63
  end
108
64
 
109
- # Return the point multiplied by a non-negative integer.
110
- # @param [Integer] x
111
- # @return [ECDSA::Ext::JacobianPoint]
112
- def multiply_by_scalar(x)
113
- raise ArgumentError, "Scalar is not an integer." unless x.is_a?(Integer)
114
- raise ArgumentError, "Scalar is negative." if x.negative?
115
-
116
- q = JacobianPoint.infinity(group)
117
- v = self
118
- i = x
119
- while i.positive?
120
- q = q.add_to_point(v) if i.odd?
121
- v = v.double
122
- i >>= 1
123
- end
124
- q
125
- end
126
- alias * multiply_by_scalar
127
-
128
65
  # Convert this coordinates to affine coordinates.
129
66
  # @return [ECDSA::Point]
130
67
  def to_affine
@@ -139,19 +76,6 @@ module ECDSA
139
76
  end
140
77
  end
141
78
 
142
- # Return additive inverse of the point.
143
- # @return [ECDSA::Ext::JacobianPoint]
144
- def negate
145
- return self if infinity?
146
- JacobianPoint.new(group, x, field.mod(-y), z)
147
- end
148
-
149
- # Return coordinates.
150
- # @return [Array] (x, y , z)
151
- def coords
152
- [x, y, z]
153
- end
154
-
155
79
  # Check whether same jacobian point or not.
156
80
  # @param [ECDSA::Ext::JacobianPoint] other
157
81
  # @return [Boolean]
@@ -3,53 +3,9 @@
3
3
  module ECDSA
4
4
  module Ext
5
5
  # Representing a point on elliptic curves using projective coordinates.
6
- class ProjectivePoint
6
+ class ProjectivePoint < AbstractPoint
7
7
  include ProjectiveArithmetic
8
8
 
9
- attr_reader :group, :x, :y, :z
10
-
11
- # Create new instance of projective
12
- # @param [ECDSA::Group] group
13
- # @param [Array] args [x, y, z]
14
- # @return [ECDSA::Ext::ProjectivePoint]
15
- def initialize(group, *args)
16
- @group = group
17
- @x, @y, @z = args
18
- raise ArgumentError, "Invalid x: #{x.inspect}" unless x.is_a?(Integer)
19
- raise ArgumentError, "Invalid y: #{y.inspect}" unless y.is_a?(Integer)
20
- raise ArgumentError, "Invalid z: #{z.inspect}" unless z.is_a?(Integer)
21
- end
22
-
23
- # Get filed of this group.
24
- # @return [ECDSA::PrimeField]
25
- def field
26
- group.field
27
- end
28
-
29
- # Convert coordinates from affine to projective.
30
- # @param [ECDSA::Point] point
31
- # @return [ECDSA::Ext::ProjectivePoint]
32
- def self.from_affine(point)
33
- if point.infinity?
34
- ProjectivePoint.infinity(point.group)
35
- else
36
- new(point.group, point.x, point.y, 1)
37
- end
38
- end
39
-
40
- # Create infinity
41
- # @return [ECDSA::Ext::ProjectivePoint]
42
- def self.infinity(group)
43
- # new(group, :infinity)
44
- new(group, 0, 1, 0)
45
- end
46
-
47
- # Check whether infinity point or not.
48
- # @return [Boolean]
49
- def infinity?
50
- x.zero? && y == 1 && z.zero?
51
- end
52
-
53
9
  # Add this point to another point on the same curve.
54
10
  # @param [ECDSA::Ext::ProjectivePoint] other
55
11
  # @return [ECDSA::Ext::ProjectivePoint]
@@ -65,7 +21,7 @@ module ECDSA
65
21
  return self if other.infinity?
66
22
 
67
23
  if x == other.x && y == field.mod(-other.y) && z == other.z
68
- return ProjectivePoint.infinity(group)
24
+ return ProjectivePoint.infinity_point(group)
69
25
  end
70
26
 
71
27
  unless x == other.x
@@ -108,38 +64,6 @@ module ECDSA
108
64
  end
109
65
  end
110
66
 
111
- # Return the point multiplied by a non-negative integer.
112
- # @param [Integer] x
113
- # @return [ECDSA::Ext::ProjectivePoint]
114
- def multiply_by_scalar(x)
115
- raise ArgumentError, "Scalar is not an integer." unless x.is_a?(Integer)
116
- raise ArgumentError, "Scalar is negative." if x.negative?
117
-
118
- q = ProjectivePoint.infinity(group)
119
- v = self
120
- i = x
121
- while i.positive?
122
- q = q.add_to_point(v) if i.odd?
123
- v = v.double
124
- i >>= 1
125
- end
126
- q
127
- end
128
- alias * multiply_by_scalar
129
-
130
- # Return additive inverse of the point.
131
- # @return [ECDSA::Ext::ProjectivePoint]
132
- def negate
133
- return self if infinity?
134
- ProjectivePoint.new(group, x, field.mod(-y), z)
135
- end
136
-
137
- # Return coordinates.
138
- # @return [Array] (x, y , z)
139
- def coords
140
- [x, y, z]
141
- end
142
-
143
67
  def ==(other)
144
68
  return false unless other.is_a?(ProjectivePoint)
145
69
  return true if infinity? && other.infinity?
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ # A monkey patch to allow signature generation and verification of existing ECDSA with Jacobian coordinates.
4
+ module ECDSA
5
+ def self.sign(group, private_key, digest, temporary_key)
6
+ # Second part of step 1: Select ephemeral elliptic curve key pair
7
+ # temporary_key was already selected for us by the caller
8
+ r_point = (group.generator.to_jacobian * temporary_key).to_affine
9
+
10
+ # Steps 2 and 3
11
+ point_field = PrimeField.new(group.order)
12
+ r = point_field.mod(r_point.x)
13
+ return nil if r.zero?
14
+
15
+ # Step 4, calculating the hash, was already performed by the caller.
16
+
17
+ # Step 5
18
+ e = normalize_digest(digest, group.bit_length)
19
+
20
+ # Step 6
21
+ s =
22
+ point_field.mod(
23
+ point_field.inverse(temporary_key) * (e + r * private_key)
24
+ )
25
+ return nil if s.zero?
26
+
27
+ Signature.new r, s
28
+ end
29
+
30
+ def self.check_signature!(public_key, digest, signature)
31
+ group = public_key.group
32
+ field = group.field
33
+
34
+ # Step 1: r and s must be in the field and non-zero
35
+ unless field.include?(signature.r)
36
+ raise InvalidSignatureError, "Invalid signature: r is not in the field."
37
+ end
38
+ unless field.include?(signature.s)
39
+ raise InvalidSignatureError, "Invalid signature: s is not in the field."
40
+ end
41
+ if signature.r.zero?
42
+ raise InvalidSignatureError, "Invalid signature: r is zero."
43
+ end
44
+ if signature.s.zero?
45
+ raise InvalidSignatureError, "Invalid signature: s is zero."
46
+ end
47
+
48
+ # Step 2 was already performed when the digest of the message was computed.
49
+
50
+ # Step 3: Convert octet string to number and take leftmost bits.
51
+ e = normalize_digest(digest, group.bit_length)
52
+
53
+ # Step 4
54
+ point_field = PrimeField.new(group.order)
55
+ s_inverted = point_field.inverse(signature.s)
56
+ u1 = point_field.mod(e * s_inverted)
57
+ u2 = point_field.mod(signature.r * s_inverted)
58
+
59
+ # Step 5
60
+ r =
61
+ (group.generator.to_jacobian * u1 + public_key.to_jacobian * u2).to_affine
62
+ if r.infinity?
63
+ raise InvalidSignatureError, "Invalid signature: r is infinity in step 5."
64
+ end
65
+
66
+ # Steps 6 and 7
67
+ v = point_field.mod r.x
68
+
69
+ # Step 8
70
+ if v != signature.r
71
+ raise InvalidSignatureError, "Invalid signature: v does not equal r."
72
+ end
73
+
74
+ true
75
+ end
76
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module ECDSA
4
4
  module Ext
5
- VERSION = "0.3.2"
5
+ VERSION = "0.4.0"
6
6
  end
7
7
  end
data/lib/ecdsa/ext.rb CHANGED
@@ -4,6 +4,7 @@ require_relative "ext/point"
4
4
  module ECDSA
5
5
  # Extension for ecdsa gem.
6
6
  module Ext
7
+ autoload :AbstractPoint, "ecdsa/ext/abstract_point"
7
8
  autoload :ProjectiveArithmetic, "ecdsa/ext/projective_arithmetic"
8
9
  autoload :ProjectivePoint, "ecdsa/ext/projective_point"
9
10
  autoload :JacobianArithmetic, "ecdsa/ext/jacobian_arithmetic"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ecdsa_ext
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - azuchi
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-03-06 00:00:00.000000000 Z
11
+ date: 2023-03-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ecdsa
@@ -46,11 +46,13 @@ files:
46
46
  - bin/setup
47
47
  - ecdsa_ext.gemspec
48
48
  - lib/ecdsa/ext.rb
49
+ - lib/ecdsa/ext/abstract_point.rb
49
50
  - lib/ecdsa/ext/jacobian_arithmetic.rb
50
51
  - lib/ecdsa/ext/jacobian_point.rb
51
52
  - lib/ecdsa/ext/point.rb
52
53
  - lib/ecdsa/ext/projective_arithmetic.rb
53
54
  - lib/ecdsa/ext/projective_point.rb
55
+ - lib/ecdsa/ext/sign_verify.rb
54
56
  - lib/ecdsa/ext/version.rb
55
57
  - lib/ecdsa_ext.rb
56
58
  - sig/ecdsa_ext.rbs