ecdsa_ext 0.3.2 → 0.4.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: 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