ecdsa_ext 0.2.1 → 0.3.1

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: d034afcff3fe0f7bcdd0a201387242296617c4115c8a5e5c17be9c55727aa7b5
4
- data.tar.gz: 94ca9bd31bd199527df5e77d82bfad340d81a869675ecaec0dec2f41c63a4ae7
3
+ metadata.gz: c2a5e0f4a0a8de441e3d2f1374666b345b3b5576c4d3b455b1e138ee9c032c88
4
+ data.tar.gz: 844a766b56bf77ce971788fa414194500f9e9ee25c9549b003cded0437fb2ff4
5
5
  SHA512:
6
- metadata.gz: 57ce381df7da79e9e4853c1e0f9e7a67157a49c7e6701db9076eec31f41b6e87e6e03350280c833d9b5d91c125ca3619364c96b9e621688b5f5b0ea09456f7d5
7
- data.tar.gz: 75ecb95e6e18a751dea27a435555b6ae4dc583c93c5dda206a7a9bfd24fbda045d6a09a715f4d962060165aad0c961366977d4092743f3755e0cc04080731e20
6
+ metadata.gz: 794aaac69e3cad831d943aa488d0b3a5f9169d7660dd3c37edb284332550be3112b39455090af2efc0229ac828d72280ad827c383e6c29300ad2d29febc28bfc
7
+ data.tar.gz: 5ee76f7e334da633becd188573089f00e3c326726217da25ceb7fb3a9e04279e5548a4085f64366bb8e530b986fdd8f691360a88690dfbc889f90333aea45314
data/Gemfile CHANGED
@@ -12,4 +12,6 @@ gem "rspec", "~> 3.0"
12
12
  gem 'prettier'
13
13
 
14
14
  gem 'rubocop-rake'
15
- gem 'rubocop-rspec'
15
+ gem 'rubocop-rspec'
16
+
17
+ gem 'benchmark-ips'
data/README.md CHANGED
@@ -75,4 +75,11 @@ projective_point4_neg = projective_point4.negate
75
75
  require 'ecdsa_ext'
76
76
 
77
77
  affine_point = projective_point4.to_affine
78
- ```
78
+ ```
79
+
80
+ ### Use jacobian coordinates
81
+
82
+ Jacobian coordinates have been supported since 0.3.0.
83
+
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.
data/ecdsa_ext.gemspec CHANGED
@@ -22,7 +22,7 @@ Gem::Specification.new do |spec|
22
22
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
23
23
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
24
24
  `git ls-files -z`.split("\x0").reject do |f|
25
- (f == __FILE__) || f.match(%r{\A(?:(?:test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
25
+ (f == __FILE__) || f.match(%r{\A(?:(?:test|spec|features|bench)/|\.(?:git|travis|circleci)|appveyor)})
26
26
  end
27
27
  end
28
28
  spec.bindir = "exe"
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+ module ECDSA
3
+ module Ext
4
+ # Point arithmetic implementation
5
+ module JacobianArithmetic
6
+ def add_with_z_one(a, b)
7
+ field = a.field
8
+ h = field.mod(b.x - a.x)
9
+ hh = field.square(h)
10
+ i = field.mod(4 * hh)
11
+ j = field.mod(h * i)
12
+ r = field.mod(2 * (b.y - a.y))
13
+ return double_with_z_one(a) if h.zero? && r.zero?
14
+ v = field.mod(a.x * i)
15
+ x3 = field.mod(field.square(r) - j - 2 * v)
16
+ y3 = field.mod(r * (v - x3) - 2 * a.y * j)
17
+ z3 = field.mod(2 * h)
18
+ JacobianPoint.new(a.group, x3, y3, z3)
19
+ end
20
+
21
+ def add_with_z_eq(a, b)
22
+ field = a.field
23
+ a = field.square(field.mod(b.x - a.x))
24
+ b = field.mod(a.x * a)
25
+ c = field.mod(b.x * a)
26
+ d = field.square(field.mod(b.y - a.y))
27
+ return double(a) if a.zero? && d.zero?
28
+ x3 = field.mod(d - b - c)
29
+ y3 = field.mod((b.y - a.y) * (b - x3) - a.y * (c - b))
30
+ z3 = field.mod(a.z * (b.x - a.x))
31
+ JacobianPoint.new(a.group, x3, y3, z3)
32
+ end
33
+
34
+ def add_with_z2_one(a, b)
35
+ field = a.field
36
+ z1z1 = field.square(a.z)
37
+ u2 = field.mod(b.x * z1z1)
38
+ s2 = field.mod(b.y * a.z * z1z1)
39
+ h = field.mod(u2 - a.x)
40
+ hh = field.square(h)
41
+ i = field.mod(4 * hh)
42
+ j = field.mod(h * i)
43
+ r = field.mod(2 * (s2 - a.y))
44
+ return double_with_z_one(b) if r.zero? && h.zero?
45
+ v = field.mod(a.x * i)
46
+ x3 = field.mod(r * r - j - 2 * v)
47
+ y3 = field.mod(r * (v - x3) - 2 * a.y * j)
48
+ z3 = field.mod(field.square(a.z + h) - z1z1 - hh)
49
+ JacobianPoint.new(a.group, x3, y3, z3)
50
+ end
51
+
52
+ def add_with_z_ne(a, b)
53
+ field = a.field
54
+ z1z1 = field.square(a.z)
55
+ z2z2 = field.square(b.z)
56
+ u1 = field.mod(a.x * z2z2)
57
+ u2 = field.mod(b.x * z1z1)
58
+ s1 = field.mod(a.y * b.z * z2z2)
59
+ s2 = field.mod(b.y * a.z * z1z1)
60
+ h = field.mod(u2 - u1)
61
+ i = field.mod(4 * h * h)
62
+ j = field.mod(h * i)
63
+ r = field.mod(2 * (s2 - s1))
64
+ return double(a) if h.zero? && r.zero?
65
+ v = field.mod(u1 * i)
66
+ x3 = field.mod(r * r - j - 2 * v)
67
+ y3 = field.mod(r * (v - x3) - 2 * s1 * j)
68
+ z3 = field.mod((field.square(a.z + b.z) - z1z1 - z2z2) * h)
69
+ JacobianPoint.new(a.group, x3, y3, z3)
70
+ end
71
+
72
+ def double_with_z_one(point)
73
+ field = point.field
74
+ xx = field.square(point.x)
75
+ yy = field.square(point.y)
76
+ yyyy = field.square(yy)
77
+ s = field.mod(2 * (field.square(point.x + yy) - xx - yyyy))
78
+ m = field.mod(3 * xx + point.group.param_a)
79
+ t = field.mod(m * m - 2 * s)
80
+ y3 = field.mod(m * (s - t) - 8 * yyyy)
81
+ z3 = field.mod(2 * point.y)
82
+ JacobianPoint.new(point.group, t, y3, z3)
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,195 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ECDSA
4
+ module Ext
5
+ # Point of Jacobian coordinates
6
+ class JacobianPoint
7
+ include JacobianArithmetic
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 projective.
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
+ # Add this point to another point on the same curve.
54
+ # @param [ECDSA::Ext::JacobianPoint] other
55
+ # @return [ECDSA::Ext::JacobianPoint]
56
+ def add_to_point(other)
57
+ unless other.is_a?(JacobianPoint)
58
+ raise ArgumentError, "other point must be instance of JacobianPoint"
59
+ end
60
+ unless other.group == group
61
+ raise ArgumentError, "other group must be same group of this point"
62
+ end
63
+
64
+ return other if infinity?
65
+ return self if other.infinity?
66
+
67
+ if x == other.x && y == field.mod(-other.y) && z == other.z
68
+ return JacobianPoint.infinity(group)
69
+ end
70
+
71
+ return other if y.zero? || z.zero?
72
+ return self if other.y.zero? || other.z.zero?
73
+
74
+ unless x == other.x
75
+ if z == other.z
76
+ return(
77
+ z == 1 ? add_with_z_one(self, other) : add_with_z_eq(self, other)
78
+ )
79
+ end
80
+ return add_with_z2_one(other, self) if z == 1
81
+ return add_with_z2_one(self, other) if other.z == 1
82
+ return add_with_z_ne(self, other)
83
+ end
84
+
85
+ return double if self == other
86
+ raise "Failed to add #{inspect} to #{other.inspect}: No addition rules matched."
87
+ end
88
+ alias + add_to_point
89
+
90
+ # Return the point added to itself.
91
+ # @return [ECDSA::Ext::JacobianPoint]
92
+ def double
93
+ return self if infinity?
94
+
95
+ return double_with_z_one(self) if z == 1
96
+
97
+ xx = field.square(x)
98
+ yy = field.square(y)
99
+ yyyy = field.square(yy)
100
+ zz = field.square(z)
101
+ s = field.mod(2 * (field.square(x + yy) - xx - yyyy))
102
+ m = field.mod(3 * xx + group.param_a * zz * zz)
103
+ t = field.mod(m * m - 2 * s)
104
+ y3 = field.mod(m * (s - t) - 8 * yyyy)
105
+ z3 = field.mod(field.square(y + z) - yy - zz)
106
+ JacobianPoint.new(group, t, y3, z3)
107
+ end
108
+
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
+ # Convert this coordinates to affine coordinates.
129
+ # @return [ECDSA::Point]
130
+ def to_affine
131
+ if infinity?
132
+ group.infinity
133
+ else
134
+ z_inv = field.inverse(z)
135
+ tmp_z = field.square(z_inv)
136
+ new_x = field.mod(x * tmp_z) # x = x * (1/z)^2
137
+ new_y = field.mod(y * tmp_z * z_inv) # y = y * (1/z)^3
138
+ ECDSA::Point.new(group, new_x, new_y)
139
+ end
140
+ end
141
+
142
+ # Return additive inverse of the point.
143
+ # @return [ECDSA::Ext::ProjectivePoint]
144
+ def negate
145
+ return self if infinity?
146
+ ProjectivePoint.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
+ # Check whether same jacobian point or not.
156
+ # @param [ECDSA::Ext::JacobianPoint] other
157
+ # @return [Boolean]
158
+ def ==(other)
159
+ return false unless other.is_a?(JacobianPoint)
160
+ return true if infinity? && other.infinity?
161
+
162
+ zz = field.square(z)
163
+ other_zz = field.square(other.z)
164
+ lhs_x = field.mod(x * other_zz)
165
+ rhs_x = field.mod(other.x * zz)
166
+ lhs_y = field.mod(y * other_zz * other.z)
167
+ rhs_y = field.mod(other.y * zz * z)
168
+
169
+ lhs_x == rhs_x && lhs_y == rhs_y
170
+ end
171
+
172
+ private
173
+
174
+ def double_non_const
175
+ return self if infinity?
176
+ z == 1 ? double_z1 : double
177
+ end
178
+
179
+ def double_z1
180
+ z3 = field.mod(2 * y)
181
+ a = field.square(x)
182
+ b = field.square(y)
183
+ c = field.square(b)
184
+ b = field.square(x + b)
185
+ d = field.mod(2 * (b - (a + c)))
186
+ e = field.mod(a * 3)
187
+ f = field.square(e)
188
+ x3 = field.mod(f - (2 * d))
189
+ f = field.mod(d - x3)
190
+ y3 = field.mod(e * f - 8 * c)
191
+ JacobianPoint.new(group, x3, y3, z3)
192
+ end
193
+ end
194
+ end
195
+ end
@@ -8,5 +8,11 @@ module ECDSA
8
8
  def to_projective
9
9
  ECDSA::Ext::ProjectivePoint.from_affine(self)
10
10
  end
11
+
12
+ # Convert coordinates to projective point.
13
+ # @return [ECDSA::Ext::JacobianPoint]
14
+ def to_jacobian
15
+ ECDSA::Ext::JacobianPoint.from_affine(self)
16
+ end
11
17
  end
12
18
  end
@@ -2,7 +2,7 @@
2
2
  module ECDSA
3
3
  module Ext
4
4
  # Point arithmetic implementation
5
- module PointArithmetic
5
+ module ProjectiveArithmetic
6
6
  def addition_negative3(a, b)
7
7
  field = a.field
8
8
  xx = field.mod(a.x * b.x)
@@ -76,9 +76,9 @@ module ECDSA
76
76
 
77
77
  def double_negative3(point)
78
78
  field = point.field
79
- xx = field.power(point.x, 2)
80
- yy = field.power(point.y, 2)
81
- zz = field.power(point.z, 2)
79
+ xx = field.square(point.x)
80
+ yy = field.square(point.y)
81
+ zz = field.square(point.z)
82
82
  xy2 = field.mod(point.x * point.y * 2)
83
83
  xz2 = field.mod(point.x * point.z * 2)
84
84
 
@@ -4,13 +4,13 @@ module ECDSA
4
4
  module Ext
5
5
  # Representing a point on elliptic curves using projective coordinates.
6
6
  class ProjectivePoint
7
- include PointArithmetic
7
+ include ProjectiveArithmetic
8
8
 
9
9
  attr_reader :group, :x, :y, :z
10
10
 
11
11
  # Create new instance of projective
12
12
  # @param [ECDSA::Group] group
13
- # @param [Array] args [:infinity] or [x, y, z]
13
+ # @param [Array] args [x, y, z]
14
14
  # @return [ECDSA::Ext::ProjectivePoint]
15
15
  def initialize(group, *args)
16
16
  @group = group
@@ -2,6 +2,6 @@
2
2
 
3
3
  module ECDSA
4
4
  module Ext
5
- VERSION = "0.2.1"
5
+ VERSION = "0.3.1"
6
6
  end
7
7
  end
data/lib/ecdsa/ext.rb CHANGED
@@ -4,7 +4,9 @@ require_relative "ext/point"
4
4
  module ECDSA
5
5
  # Extension for ecdsa gem.
6
6
  module Ext
7
- autoload :PointArithmetic, "ecdsa/ext/point_arithmetic"
7
+ autoload :ProjectiveArithmetic, "ecdsa/ext/projective_arithmetic"
8
8
  autoload :ProjectivePoint, "ecdsa/ext/projective_point"
9
+ autoload :JacobianArithmetic, "ecdsa/ext/jacobian_arithmetic"
10
+ autoload :JacobianPoint, "ecdsa/ext/jacobian_point"
9
11
  end
10
12
  end
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.2.1
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - azuchi
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-02-28 00:00:00.000000000 Z
11
+ date: 2023-03-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ecdsa
@@ -46,8 +46,10 @@ files:
46
46
  - bin/setup
47
47
  - ecdsa_ext.gemspec
48
48
  - lib/ecdsa/ext.rb
49
+ - lib/ecdsa/ext/jacobian_arithmetic.rb
50
+ - lib/ecdsa/ext/jacobian_point.rb
49
51
  - lib/ecdsa/ext/point.rb
50
- - lib/ecdsa/ext/point_arithmetic.rb
52
+ - lib/ecdsa/ext/projective_arithmetic.rb
51
53
  - lib/ecdsa/ext/projective_point.rb
52
54
  - lib/ecdsa/ext/version.rb
53
55
  - lib/ecdsa_ext.rb