ecdsa_ext 0.2.1 → 0.3.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: d034afcff3fe0f7bcdd0a201387242296617c4115c8a5e5c17be9c55727aa7b5
4
- data.tar.gz: 94ca9bd31bd199527df5e77d82bfad340d81a869675ecaec0dec2f41c63a4ae7
3
+ metadata.gz: fa41cad7e597e74cfabf27c0dd026aa60b47f64419d8c17e56653fe68d863e4c
4
+ data.tar.gz: 35754ec99989184df9f3ceabdf2d6c946ed55d810e0753b34b3a9779aa04eb1b
5
5
  SHA512:
6
- metadata.gz: 57ce381df7da79e9e4853c1e0f9e7a67157a49c7e6701db9076eec31f41b6e87e6e03350280c833d9b5d91c125ca3619364c96b9e621688b5f5b0ea09456f7d5
7
- data.tar.gz: 75ecb95e6e18a751dea27a435555b6ae4dc583c93c5dda206a7a9bfd24fbda045d6a09a715f4d962060165aad0c961366977d4092743f3755e0cc04080731e20
6
+ metadata.gz: c0f9f06b62b6ca56b4c374d665f600d3750204b9b3a91651069f4416a08869c58148158c53cc9b981c3508703c3451b93541c4dbbe72f43cda4364c03ffbd507
7
+ data.tar.gz: 26f3e2e7313ff913d4b03b91ac3bcc0daa17ca3d8c2f1b3f43a049140f7fd9ba367ccad84913882decdbacc2a06304e40ae3a3add342b86103e980d5df341257
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
+ 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.0"
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.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-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