ecdsa 0.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 +7 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/lib/ecdsa.rb +59 -0
- data/lib/ecdsa/format.rb +5 -0
- data/lib/ecdsa/format/decode_error.rb +11 -0
- data/lib/ecdsa/format/field_element_octet_string.rb +27 -0
- data/lib/ecdsa/format/integer_octet_string.rb +28 -0
- data/lib/ecdsa/format/point_octet_string.rb +87 -0
- data/lib/ecdsa/format/signature_der_string.rb +22 -0
- data/lib/ecdsa/group.rb +126 -0
- data/lib/ecdsa/group/nistp192.rb +16 -0
- data/lib/ecdsa/group/nistp224.rb +16 -0
- data/lib/ecdsa/group/nistp256.rb +16 -0
- data/lib/ecdsa/group/nistp384.rb +17 -0
- data/lib/ecdsa/group/nistp521.rb +16 -0
- data/lib/ecdsa/group/secp112r1.rb +16 -0
- data/lib/ecdsa/group/secp112r2.rb +16 -0
- data/lib/ecdsa/group/secp128r1.rb +16 -0
- data/lib/ecdsa/group/secp128r2.rb +16 -0
- data/lib/ecdsa/group/secp160k1.rb +16 -0
- data/lib/ecdsa/group/secp160r1.rb +16 -0
- data/lib/ecdsa/group/secp160r2.rb +16 -0
- data/lib/ecdsa/group/secp192k1.rb +16 -0
- data/lib/ecdsa/group/secp192r1.rb +16 -0
- data/lib/ecdsa/group/secp224k1.rb +16 -0
- data/lib/ecdsa/group/secp224r1.rb +16 -0
- data/lib/ecdsa/group/secp256k1.rb +18 -0
- data/lib/ecdsa/group/secp256r1.rb +16 -0
- data/lib/ecdsa/group/secp384r1.rb +16 -0
- data/lib/ecdsa/group/secp521r1.rb +16 -0
- data/lib/ecdsa/point.rb +113 -0
- data/lib/ecdsa/prime_field.rb +81 -0
- data/lib/ecdsa/sign.rb +37 -0
- data/lib/ecdsa/signature.rb +16 -0
- data/lib/ecdsa/verify.rb +48 -0
- data/lib/ecdsa/version.rb +3 -0
- metadata +82 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d725d0e513f16f2ec4b24170b5d2f85c26472d79
|
4
|
+
data.tar.gz: 866b36f01ad0f3e0cf3f32b2ec01881252e564b7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d00fa2b23d9fc9225b6bbe7ae9e1b84254b3e31a5163974179f3ce8bbd3cde4c7d48012de2ba54a238d76cc068f9d0f0310eff985ebdb296191036fbba9f6c07
|
7
|
+
data.tar.gz: 84610f1b18e5e8e3b633e932fc58eb950d37a4b193a87ea49e9a16bfd454a1c961278276f0bad1c49d26c7d19cf8c4f3ee4b3690e29cc13ca1c9a79b3ba5c070
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 David Grayson.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person
|
4
|
+
obtaining a copy of this software and associated documentation
|
5
|
+
files (the "Software"), to deal in the Software without
|
6
|
+
restriction, including without limitation the rights to use,
|
7
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
copies of the Software, and to permit persons to whom the
|
9
|
+
Software is furnished to do so, subject to the following
|
10
|
+
conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
17
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
19
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
20
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# ECDSA gem for Ruby
|
2
|
+
|
3
|
+
This gem implements the Elliptic Curve Digital Signature Algorithm (ECDSA) almost entirely in pure Ruby.
|
4
|
+
It aims to be easier to use and easier to understand than Ruby's [OpenSSL EC support](http://www.ruby-doc.org/stdlib/libdoc/openssl/rdoc/OpenSSL/PKey/EC.html).
|
5
|
+
This gem does use OpenSSL but it only uses it to decode and encode ASN1 strings for ECDSA signatures.
|
6
|
+
All cryptographic calculations are done in pure Ruby.
|
7
|
+
|
8
|
+
The main classes of this gem are `ECDSA::Group`, `ECDSA::Point`, and `ECDSA::Signature`.
|
9
|
+
These classes operate on Ruby integers and do not deal at all with binary formatting.
|
10
|
+
Encoding and decoding of binary formats is solely handled by classes under the `ECDSA::Format` module.
|
11
|
+
|
12
|
+
You can enter your own curve parameters by instantiating a new `ECDSA::Group` object or you can
|
13
|
+
use a pre-existing group object such as `ECDSA::Group::Secp256k1`.
|
14
|
+
The pre-existing groups can be seen in the `lib/ecdsa/group` folder, and include all the curves
|
15
|
+
defined in [SEC2](http://www.secg.org/collateral/sec2_final.pdf) and [NIST's Recommended Elliptic Curves for Federal Government Use](http://csrc.nist.gov/groups/ST/toolkit/documents/dss/NISTReCur.pdf).
|
16
|
+
|
17
|
+
This gem is hosted at the [DavidEGrayson/ruby_ecdsa github repository](https://github.com/DavidEGrayson/ruby_ecdsa).
|
18
|
+
|
19
|
+
## Current limitations
|
20
|
+
|
21
|
+
- This gem only supports fields of integers modulo a prime number (_F<sub>p</sub>_).
|
22
|
+
ECDSA's characteristic 2 fields are not supported.
|
23
|
+
- This gem can only compute square roots in prime fields over a prime _p_
|
24
|
+
that is one less than a multiple of 4.
|
25
|
+
Computing a square root is required for parsing public keys stored in compressed form.
|
26
|
+
- There is no documentation. If you know ECDSA and know how to read Ruby source code,
|
27
|
+
you can probably figure it out though.
|
28
|
+
- The algorithms have not been optimized for speed, and will probably never be, because that
|
29
|
+
would hinder the goal of helping people understand ECDSA.
|
data/lib/ecdsa.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require_relative 'ecdsa/group'
|
2
|
+
require_relative 'ecdsa/signature'
|
3
|
+
require_relative 'ecdsa/verify'
|
4
|
+
require_relative 'ecdsa/sign'
|
5
|
+
require_relative 'ecdsa/format'
|
6
|
+
require_relative 'ecdsa/version'
|
7
|
+
|
8
|
+
module ECDSA
|
9
|
+
def self.byte_length(integer)
|
10
|
+
length = 0
|
11
|
+
while integer > 0
|
12
|
+
length += 1
|
13
|
+
integer >>= 8
|
14
|
+
end
|
15
|
+
length
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.bit_length(integer)
|
19
|
+
length = 0
|
20
|
+
while integer > 0
|
21
|
+
length += 1
|
22
|
+
integer >>= 1
|
23
|
+
end
|
24
|
+
length
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.convert_digest_to_integer(digest)
|
28
|
+
case digest
|
29
|
+
when Integer then digest
|
30
|
+
when String then convert_octet_string_to_bit_string(digest)
|
31
|
+
else raise "Invalid digest: #{digest.inspect}"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.leftmost_bits(n, bit_length)
|
36
|
+
if n >= (1 << (8 * bit_length))
|
37
|
+
raise 'Have not yet written code to handle this case'
|
38
|
+
else
|
39
|
+
n
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.normalize_digest(digest, bit_length)
|
44
|
+
digest_num = convert_digest_to_integer(digest)
|
45
|
+
leftmost_bits(digest_num, bit_length)
|
46
|
+
end
|
47
|
+
|
48
|
+
# SEC1, Section 2.3.2.
|
49
|
+
# My interpretation of that section is that we treat the octet string as BIG endian.
|
50
|
+
def self.convert_octet_string_to_bit_string(string)
|
51
|
+
string.bytes.reduce { |n, b| (n << 8) + b }
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class String
|
56
|
+
def hex_inspect
|
57
|
+
'"' + each_byte.map { |b| '\x%02x' % b }.join + '"'
|
58
|
+
end
|
59
|
+
end
|
data/lib/ecdsa/format.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
module ECDSA
|
2
|
+
module Format
|
3
|
+
# Raising instance of this class as an exception indicates that
|
4
|
+
# the data being decoded was invalid, but does not necessarily
|
5
|
+
# indicate a bug in the program, unlike most other exceptions
|
6
|
+
# because it is possible the data being decoded is coming from
|
7
|
+
# an untrusted source.
|
8
|
+
class DecodeError < StandardError
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# Defined in http://www.secg.org/collateral/sec1_final.pdf
|
2
|
+
# section 2.3.5: FieldElement-to-OctetString Conversion
|
3
|
+
|
4
|
+
module ECDSA
|
5
|
+
module Format
|
6
|
+
module FieldElementOctetString
|
7
|
+
# @param integer (Integer) The integer to encode
|
8
|
+
# @param length (Integer) The number of bytes desired in the output string.
|
9
|
+
def self.encode(element, field)
|
10
|
+
raise ArgumentError, 'Given element is not an element of the field.' if !field.include?(element)
|
11
|
+
length = ECDSA.byte_length(field.prime)
|
12
|
+
IntegerOctetString.encode(element, length)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.decode(string, field)
|
16
|
+
int = IntegerOctetString.decode(string)
|
17
|
+
|
18
|
+
if !field.include?(int)
|
19
|
+
# The integer has to be non-negative, so it must be too big.
|
20
|
+
raise DecodeError, 'Decoded integer is too large for field: 0x%x >= 0x%x.' % [int, field.prime]
|
21
|
+
end
|
22
|
+
|
23
|
+
int
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# Defined in http://www.secg.org/collateral/sec1_final.pdf :
|
2
|
+
# Section 2.3.7: Integer-to-OctetString Conversion
|
3
|
+
# Section 2.3.8: OctetString-to-Integer Conversion
|
4
|
+
|
5
|
+
module ECDSA
|
6
|
+
module Format
|
7
|
+
module IntegerOctetString
|
8
|
+
# @param integer (Integer) The integer to encode
|
9
|
+
# @param length (Integer) The number of bytes desired in the output string.
|
10
|
+
def self.encode(integer, length)
|
11
|
+
raise ArgumentError, 'Integer to encode is negative.' if integer < 0
|
12
|
+
raise ArgumentError, 'Integer to encode is too large.' if integer >= (1 << (8 * length))
|
13
|
+
|
14
|
+
length.pred.downto(0).map do |i|
|
15
|
+
integer >> (8 * i)
|
16
|
+
end.pack('C*')
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.decode(string)
|
20
|
+
integer = 0
|
21
|
+
string.each_byte do |b|
|
22
|
+
integer = (integer << 8) + b.ord
|
23
|
+
end
|
24
|
+
integer
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# encoding: US-ASCII
|
2
|
+
|
3
|
+
# The point octet string format is defined in http://www.secg.org/collateral/sec1_final.pdf .
|
4
|
+
# Section 2.3.3: EllipticCurvePoint-to-OctetString Conversion
|
5
|
+
# Section 2.3.4: OctetString-to-EllipticCurvePoint Conversion
|
6
|
+
|
7
|
+
require_relative '../point'
|
8
|
+
|
9
|
+
module ECDSA
|
10
|
+
module Format
|
11
|
+
module PointOctetString
|
12
|
+
def self.encode(point, opts = {})
|
13
|
+
return "\x00" if point.infinity?
|
14
|
+
|
15
|
+
if opts[:compression]
|
16
|
+
start_byte = point.y.even? ? "\x02" : "\x03"
|
17
|
+
start_byte + FieldElementOctetString.encode(point.x, point.group.field)
|
18
|
+
else
|
19
|
+
"\x04" +
|
20
|
+
FieldElementOctetString.encode(point.x, point.group.field) +
|
21
|
+
FieldElementOctetString.encode(point.y, point.group.field)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# This is equivalent to ec_GFp_simple_oct2point in OpenSSL:
|
26
|
+
# https://github.com/openssl/openssl/blob/a898936218bc279b5d7cdf76d58a25e7a2d419cb/crypto/ec/ecp_oct.c
|
27
|
+
def self.decode(string, group)
|
28
|
+
raise DecodeError, 'Point octet string is empty.' if string.empty?
|
29
|
+
|
30
|
+
case string[0].ord
|
31
|
+
when 0
|
32
|
+
check_length string, 1
|
33
|
+
return group.infinity_point
|
34
|
+
when 2
|
35
|
+
decode_compressed string, group, 0
|
36
|
+
when 3
|
37
|
+
decode_compressed string, group, 1
|
38
|
+
when 4
|
39
|
+
decode_uncompressed string, group
|
40
|
+
else
|
41
|
+
raise DecodeError, 'Unrecognized start byte for point octet string: 0x%x' % string[0].ord
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def self.decode_compressed(string, group, y_lsb)
|
48
|
+
expected_length = 1 + group.byte_length
|
49
|
+
check_length string, expected_length
|
50
|
+
|
51
|
+
x_string = string[1, group.byte_length]
|
52
|
+
x = ECDSA::Format::FieldElementOctetString.decode x_string, group.field
|
53
|
+
|
54
|
+
possible_ys = group.solve_for_y(x)
|
55
|
+
y = possible_ys.find { |py| (py % 2) == y_lsb }
|
56
|
+
|
57
|
+
finish_decode x, y, group
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.decode_uncompressed(string, group)
|
61
|
+
expected_length = 1 + 2 * group.byte_length
|
62
|
+
check_length string, expected_length
|
63
|
+
|
64
|
+
x_string = string[1, group.byte_length]
|
65
|
+
y_string = string[1 + group.byte_length, group.byte_length]
|
66
|
+
x = ECDSA::Format::FieldElementOctetString.decode x_string, group.field
|
67
|
+
y = ECDSA::Format::FieldElementOctetString.decode y_string, group.field
|
68
|
+
|
69
|
+
finish_decode x, y, group
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.finish_decode(x, y, group)
|
73
|
+
point = group.new_point [x, y]
|
74
|
+
if !group.include? point
|
75
|
+
raise DecodeError, "Decoded point does not satisfy curve equation: #{point.inspect}."
|
76
|
+
end
|
77
|
+
point
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.check_length(string, expected_length)
|
81
|
+
if string.length != expected_length
|
82
|
+
raise DecodeError, "Expected point octet string to be length #{expected_length} but it was #{string.length}."
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
require_relative '../signature'
|
3
|
+
|
4
|
+
module ECDSA
|
5
|
+
module Format
|
6
|
+
module SignatureDerString
|
7
|
+
def self.decode(der_string)
|
8
|
+
asn1 = OpenSSL::ASN1.decode(der_string)
|
9
|
+
r = asn1.value[0].value.to_i
|
10
|
+
s = asn1.value[1].value.to_i
|
11
|
+
Signature.new(r, s)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.encode(signature)
|
15
|
+
ra = OpenSSL::ASN1::Integer.new signature.r
|
16
|
+
sa = OpenSSL::ASN1::Integer.new signature.s
|
17
|
+
asn1 = OpenSSL::ASN1::Sequence.new [ra, sa]
|
18
|
+
asn1.to_der
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/ecdsa/group.rb
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
require_relative 'prime_field'
|
2
|
+
require_relative 'point'
|
3
|
+
|
4
|
+
module ECDSA
|
5
|
+
class Group
|
6
|
+
attr_reader :name
|
7
|
+
|
8
|
+
attr_reader :generator
|
9
|
+
|
10
|
+
attr_reader :order
|
11
|
+
|
12
|
+
attr_reader :param_a
|
13
|
+
|
14
|
+
attr_reader :param_b
|
15
|
+
|
16
|
+
attr_reader :field
|
17
|
+
|
18
|
+
# These parameters are defined in http://www.secg.org/collateral/sec2_final.pdf
|
19
|
+
#
|
20
|
+
# - +p+: A prime number that defines the field used. The field will be F_p.
|
21
|
+
# - +a+: The a parameter in the curve equation (y^2 = x^3 + ax + b).
|
22
|
+
# - +b+: The b parameter in the curve equation.
|
23
|
+
# - +g+: The base point as an octet string.
|
24
|
+
# - +n+: The order of g.
|
25
|
+
# - +h+: The cofactor.
|
26
|
+
def initialize(opts)
|
27
|
+
@opts = opts
|
28
|
+
|
29
|
+
@name = opts.fetch(:name) { '%#x' % object_id }
|
30
|
+
@field = PrimeField.new(opts[:p])
|
31
|
+
@param_a = opts[:a]
|
32
|
+
@param_b = opts[:b]
|
33
|
+
@generator = new_point(@opts[:g])
|
34
|
+
@order = opts[:n]
|
35
|
+
@cofactor = opts[:h]
|
36
|
+
|
37
|
+
@param_a.is_a?(Integer) or raise ArgumentError, 'Invalid a.'
|
38
|
+
@param_b.is_a?(Integer) or raise ArgumentError, 'Invalid b.'
|
39
|
+
|
40
|
+
@param_a = field.mod @param_a
|
41
|
+
@param_b = field.mod @param_b
|
42
|
+
end
|
43
|
+
|
44
|
+
def new_point(p)
|
45
|
+
case p
|
46
|
+
when :infinity
|
47
|
+
infinity_point
|
48
|
+
when Array
|
49
|
+
x, y = p
|
50
|
+
Point.new(self, x, y)
|
51
|
+
when Integer
|
52
|
+
generator.multiply_by_scalar(p)
|
53
|
+
else
|
54
|
+
raise ArgumentError, "Invalid point specifier #{p.inspect}."
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def infinity_point
|
59
|
+
@infinity_point ||= Point.new(self, :infinity)
|
60
|
+
end
|
61
|
+
|
62
|
+
# The number of bits that it takes to represent a member of the field.
|
63
|
+
# Log base 2 of the prime p, rounded up.
|
64
|
+
def bit_length
|
65
|
+
@bit_length ||= ECDSA.bit_length(field.prime)
|
66
|
+
end
|
67
|
+
|
68
|
+
def byte_length
|
69
|
+
@byte_length ||= ECDSA.byte_length(field.prime)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Verify that the point is a solution to the curve's defining equation.
|
73
|
+
def include?(point)
|
74
|
+
raise 'Group mismatch.' if point.group != self
|
75
|
+
point.infinity? or point_satisfies_equation?(point)
|
76
|
+
end
|
77
|
+
|
78
|
+
# You should probably use include? instead of this.
|
79
|
+
def point_satisfies_equation?(point)
|
80
|
+
field.mod(point.y * point.y) == equation_right_hand_side(point.x)
|
81
|
+
end
|
82
|
+
|
83
|
+
def equation_right_hand_side(x)
|
84
|
+
field.mod(x * x * x + param_a * x + param_b)
|
85
|
+
end
|
86
|
+
|
87
|
+
def solve_for_y(x)
|
88
|
+
field.square_roots equation_right_hand_side x
|
89
|
+
end
|
90
|
+
|
91
|
+
def inspect
|
92
|
+
"#<#{self.class}:#{name}>"
|
93
|
+
end
|
94
|
+
|
95
|
+
def to_s
|
96
|
+
inspect
|
97
|
+
end
|
98
|
+
|
99
|
+
NAMES = %w(
|
100
|
+
Secp112r1
|
101
|
+
Secp112r2
|
102
|
+
Secp128r1
|
103
|
+
Secp128r2
|
104
|
+
Secp160k1
|
105
|
+
Secp160r1
|
106
|
+
Secp160r2
|
107
|
+
Secp192k1
|
108
|
+
Secp192r1
|
109
|
+
Secp224k1
|
110
|
+
Secp224r1
|
111
|
+
Secp256k1
|
112
|
+
Secp256r1
|
113
|
+
Secp384r1
|
114
|
+
Secp521r1
|
115
|
+
Nistp192
|
116
|
+
Nistp224
|
117
|
+
Nistp256
|
118
|
+
Nistp384
|
119
|
+
Nistp521
|
120
|
+
)
|
121
|
+
|
122
|
+
NAMES.each do |name|
|
123
|
+
autoload name, 'ecdsa/group/' + name.downcase
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Source: http://csrc.nist.gov/groups/ST/toolkit/documents/dss/NISTReCur.pdf
|
2
|
+
|
3
|
+
module ECDSA
|
4
|
+
class Group
|
5
|
+
Nistp192 = new(
|
6
|
+
name: 'nistp192',
|
7
|
+
p: 62771017353866807638357894232076664160839087_00390324961279,
|
8
|
+
a: -3,
|
9
|
+
b: 0x64210519_e59c80e7_0fa7e9ab_72243049_feb8deec_c146b9b1,
|
10
|
+
g: [0x188da80e_b03090f6_7cbf20eb_43a18800_f4ff0afd_82ff1012,
|
11
|
+
0x07192b95_ffc8da78_631011ed_6b24cdd5_73f977a1_1e794811],
|
12
|
+
n: 62771017353866807638357894231760590137671947_73182842284081,
|
13
|
+
h: nil, # cofactor not given in NIST document
|
14
|
+
)
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Source: http://csrc.nist.gov/groups/ST/toolkit/documents/dss/NISTReCur.pdf
|
2
|
+
|
3
|
+
module ECDSA
|
4
|
+
class Group
|
5
|
+
Nistp224 = new(
|
6
|
+
name: 'nistp224',
|
7
|
+
p: 26959946667150639794667015087019630673557916_260026308143510066298881,
|
8
|
+
a: -3,
|
9
|
+
b: 0xb4050a85_0c04b3ab_f5413256_5044b0b7_d7bfd8ba_270b3943_2355ffb4,
|
10
|
+
g: [0xb70e0cbd_6bb4bf7f_321390b9_4a03c1d3_56c21122_343280d6_115c1d21,
|
11
|
+
0xbd376388_b5f723fb_4c22dfe6_cd4375a0_5a074764_44d58199_85007e34],
|
12
|
+
n: 26959946667150639794667015087019625940457807_714424391721682722368061,
|
13
|
+
h: nil, # cofactor not given in NIST document
|
14
|
+
)
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Source: http://csrc.nist.gov/groups/ST/toolkit/documents/dss/NISTReCur.pdf
|
2
|
+
|
3
|
+
module ECDSA
|
4
|
+
class Group
|
5
|
+
Nistp256 = new(
|
6
|
+
name: 'nistp256',
|
7
|
+
p: 11579208921035624876269744694940757353008614_3415290314195533631308867097853951,
|
8
|
+
a: -3,
|
9
|
+
b: 0x5ac635d8_aa3a93e7_b3ebbd55_769886bc_651d06b0_cc53b0f6_3bce3c3e_27d2604b,
|
10
|
+
g: [0x6b17d1f2_e12c4247_f8bce6e5_63a440f2_77037d81_2deb33a0_f4a13945_d898c296,
|
11
|
+
0x4fe342e2_fe1a7f9b_8ee7eb4a_7c0f9e16_2bce3357_6b315ece_cbb64068_37bf51f5],
|
12
|
+
n: 11579208921035624876269744694940757352999695_5224135760342422259061068512044369,
|
13
|
+
h: nil, # cofactor not given in NIST document
|
14
|
+
)
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# Source: http://csrc.nist.gov/groups/ST/toolkit/documents/dss/NISTReCur.pdf
|
2
|
+
|
3
|
+
module ECDSA
|
4
|
+
class Group
|
5
|
+
Nistp384 = new(
|
6
|
+
name: 'nistp384',
|
7
|
+
p: 39402006196394479212279040100143613805079739_27046544666794829340424572177149687032904726_6088258938001861606973112319,
|
8
|
+
a: -3,
|
9
|
+
b: 0xb3312fa7_e23ee7e4_988e056b_e3f82d19_181d9c6e_fe814112_0314088f_5013875a_c656398d_8a2ed19d_2a85c8ed_d3ec2aef,
|
10
|
+
g: [0xaa87ca22_be8b0537_8eb1c71e_f320ad74_6e1d3b62_8ba79b98_59f741e0_82542a38_5502f25d_bf55296c_3a545e38_72760ab7,
|
11
|
+
0x3617de4a_96262c6f_5d9e98bf_9292dc29_f8f41dbd_289a147c_e9da3113_b5f0b8c0_0a60b1ce_1d7e819d_7a431d7c_90ea0e5f,
|
12
|
+
],
|
13
|
+
n: 39402006196394479212279040100143613805079739_27046544666794690527962765939911326356939895_6308152294913554433653942643,
|
14
|
+
h: nil, # cofactor not given in NIST document
|
15
|
+
)
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Source: "Curve P-256" from http://csrc.nist.gov/groups/ST/toolkit/documents/dss/NISTReCur.doc
|
2
|
+
|
3
|
+
module ECDSA
|
4
|
+
class Group
|
5
|
+
Nistp521 = new(
|
6
|
+
name: 'nistp521',
|
7
|
+
p: 68647976601306097149819007990813932172694353_00143305409394463459185543183397656052122559_64066145455497729631139148085803712198799971_6643812574028291115057151,
|
8
|
+
a: -3,
|
9
|
+
b: 0x051_953eb961_8e1c9a1f_929a21a0_b68540ee_a2da725b_99b315f3_b8b48991_8ef109e1_56193951_ec7e937b_1652c0bd_3bb1bf07_3573df88_3d2c34f1_ef451fd4_6b503f00,
|
10
|
+
g: [0x00c6_858e06b7_0404e9cd_9e3ecb66_2395b442_9c648139_053fb521_f828af60_6b4d3dba_a14b5e77_efe75928_fe1dc127_a2ffa8de_3348b3c1_856a429b_f97e7e31_c2e5bd66,
|
11
|
+
0x0118_39296a78_9a3bc004_5c8a5fb4_2c7d1bd9_98f54449_579b4468_17afbd17_273e662c_97ee7299_5ef42640_c550b901_3fad0761_353c7086_a272c240_88be9476_9fd16650],
|
12
|
+
n: 68647976601306097149819007990813932172694353_00143305409394463459185543183397655394245057_74633321719753296399637136332111386476861244_0380340372808892707005449,
|
13
|
+
h: nil, # cofactor not given in NIST document
|
14
|
+
)
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Source: http://www.secg.org/collateral/sec2_final.pdf
|
2
|
+
|
3
|
+
module ECDSA
|
4
|
+
class Group
|
5
|
+
Secp112r1 = new(
|
6
|
+
name: 'secp112r1',
|
7
|
+
p: 0xDB7C_2ABF62E3_5E668076_BEAD208B,
|
8
|
+
a: 0xDB7C_2ABF62E3_5E668076_BEAD2088,
|
9
|
+
b: 0x659E_F8BA0439_16EEDE89_11702B22,
|
10
|
+
g: [0x0948_7239995A_5EE76B55_F9C2F098,
|
11
|
+
0xA89C_E5AF8724_C0A23E0E_0FF77500],
|
12
|
+
n: 0xDB7C_2ABF62E3_5E7628DF_AC6561C5,
|
13
|
+
h: 1,
|
14
|
+
)
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Source: http://www.secg.org/collateral/sec2_final.pdf
|
2
|
+
|
3
|
+
module ECDSA
|
4
|
+
class Group
|
5
|
+
Secp112r2 = new(
|
6
|
+
name: 'secp112r2',
|
7
|
+
p: 0xDB7C_2ABF62E3_5E668076_BEAD208B,
|
8
|
+
a: 0x6127_C24C05F3_8A0AAAF6_5C0EF02C,
|
9
|
+
b: 0x51DE_F1815DB5_ED74FCC3_4C85D709,
|
10
|
+
g: [0x4BA3_0AB5E892_B4E1649D_D0928643,
|
11
|
+
0xADCD_46F5882E_3747DEF3_6E956E97],
|
12
|
+
n: 0x36DF_0AAFD8B8_D7597CA1_0520D04B,
|
13
|
+
h: 4,
|
14
|
+
)
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Source: http://www.secg.org/collateral/sec2_final.pdf
|
2
|
+
|
3
|
+
module ECDSA
|
4
|
+
class Group
|
5
|
+
Secp128r1 = new(
|
6
|
+
name: 'secp128r1',
|
7
|
+
p: 0xFFFFFFFD_FFFFFFFF_FFFFFFFF_FFFFFFFF,
|
8
|
+
a: 0xFFFFFFFD_FFFFFFFF_FFFFFFFF_FFFFFFFC,
|
9
|
+
b: 0xE87579C1_1079F43D_D824993C_2CEE5ED3,
|
10
|
+
g: [0x161FF752_8B899B2D_0C28607C_A52C5B86,
|
11
|
+
0xCF5AC839_5BAFEB13_C02DA292_DDED7A83],
|
12
|
+
n: 0xFFFFFFFE_00000000_75A30D1B_9038A115,
|
13
|
+
h: 1,
|
14
|
+
)
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Source: http://www.secg.org/collateral/sec2_final.pdf
|
2
|
+
|
3
|
+
module ECDSA
|
4
|
+
class Group
|
5
|
+
Secp128r2 = new(
|
6
|
+
name: 'secp128r2',
|
7
|
+
p: 0xFFFFFFFD_FFFFFFFF_FFFFFFFF_FFFFFFFF,
|
8
|
+
a: 0xD6031998_D1B3BBFE_BF59CC9B_BFF9AEE1,
|
9
|
+
b: 0x5EEEFCA3_80D02919_DC2C6558_BB6D8A5D,
|
10
|
+
g: [0x7B6AA5D8_5E572983_E6FB32A7_CDEBC140,
|
11
|
+
0x27B6916A_894D3AEE_7106FE80_5FC34B44],
|
12
|
+
n: 0x3FFFFFFF_7FFFFFFF_BE002472_0613B5A3,
|
13
|
+
h: 4,
|
14
|
+
)
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Source: http://www.secg.org/collateral/sec2_final.pdf
|
2
|
+
|
3
|
+
module ECDSA
|
4
|
+
class Group
|
5
|
+
Secp160k1 = new(
|
6
|
+
name: 'secp160k1',
|
7
|
+
p: 0xFFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFE_FFFFAC73,
|
8
|
+
a: 0,
|
9
|
+
b: 7,
|
10
|
+
g: [0x3B4C382C_E37AA192_A4019E76_3036F4F5_DD4D7EBB,
|
11
|
+
0x938CF935_318FDCED_6BC28286_531733C3_F03C4FEE],
|
12
|
+
n: 0x01_00000000_00000000_0001B8FA_16DFAB9A_CA16B6B3,
|
13
|
+
h: 1,
|
14
|
+
)
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Source: http://www.secg.org/collateral/sec2_final.pdf
|
2
|
+
|
3
|
+
module ECDSA
|
4
|
+
class Group
|
5
|
+
Secp160r1 = new(
|
6
|
+
name: 'secp160r1',
|
7
|
+
p: 0xFFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_7FFFFFFF,
|
8
|
+
a: 0xFFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_7FFFFFFC,
|
9
|
+
b: 0x1C97BEFC_54BD7A8B_65ACF89F_81D4D4AD_C565FA45,
|
10
|
+
g: [0x4A96B568_8EF57328_46646989_68C38BB9_13CBFC82,
|
11
|
+
0x23A62855_3168947D_59DCC912_04235137_7AC5FB32],
|
12
|
+
n: 0x01_00000000_00000000_0001F4C8_F927AED3_CA752257,
|
13
|
+
h: 1,
|
14
|
+
)
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Source: http://www.secg.org/collateral/sec2_final.pdf
|
2
|
+
|
3
|
+
module ECDSA
|
4
|
+
class Group
|
5
|
+
Secp160r2 = new(
|
6
|
+
name: 'secp160r2',
|
7
|
+
p: 0xFFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFE_FFFFAC73,
|
8
|
+
a: 0xFFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFE_FFFFAC70,
|
9
|
+
b: 0xB4E134D3_FB59EB8B_AB572749_04664D5A_F50388BA,
|
10
|
+
g: [0x52DCB034_293A117E_1F4FF11B_30F7199D_3144CE6D,
|
11
|
+
0xFEAFFEF2_E331F296_E071FA0D_F9982CFE_A7D43F2E],
|
12
|
+
n: 0x01_00000000_00000000_0000351E_E786A818_F3A1A16B,
|
13
|
+
h: 1,
|
14
|
+
)
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Source: http://www.secg.org/collateral/sec2_final.pdf
|
2
|
+
|
3
|
+
module ECDSA
|
4
|
+
class Group
|
5
|
+
Secp192k1 = new(
|
6
|
+
name: 'secp192k1',
|
7
|
+
p: 0xFFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFE_FFFFEE37,
|
8
|
+
a: 0,
|
9
|
+
b: 3,
|
10
|
+
g: [0xDB4FF10E_C057E9AE_26B07D02_80B7F434_1DA5D1B1_EAE06C7D,
|
11
|
+
0x9B2F2F6D_9C5628A7_844163D0_15BE8634_4082AA88_D95E2F9D],
|
12
|
+
n: 0xFFFFFFFF_FFFFFFFF_FFFFFFFE_26F2FC17_0F69466A_74DEFD8D,
|
13
|
+
h: 1,
|
14
|
+
)
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Source: http://www.secg.org/collateral/sec2_final.pdf
|
2
|
+
|
3
|
+
module ECDSA
|
4
|
+
class Group
|
5
|
+
Secp192r1 = new(
|
6
|
+
name: 'secp192r1',
|
7
|
+
p: 0xFFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFE_FFFFFFFF_FFFFFFFF,
|
8
|
+
a: 0xFFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFE_FFFFFFFF_FFFFFFFC,
|
9
|
+
b: 0x64210519_E59C80E7_0FA7E9AB_72243049_FEB8DEEC_C146B9B1,
|
10
|
+
g: [0x188DA80E_B03090F6_7CBF20EB_43A18800_F4FF0AFD_82FF1012,
|
11
|
+
0x07192B95_FFC8DA78_631011ED_6B24CDD5_73F977A1_1E794811],
|
12
|
+
n: 0xFFFFFFFF_FFFFFFFF_FFFFFFFF_99DEF836_146BC9B1_B4D22831,
|
13
|
+
h: 1,
|
14
|
+
)
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Source: http://www.secg.org/collateral/sec2_final.pdf
|
2
|
+
|
3
|
+
module ECDSA
|
4
|
+
class Group
|
5
|
+
Secp224k1 = new(
|
6
|
+
name: 'secp224k1',
|
7
|
+
p: 0xFFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFE_FFFFE56D,
|
8
|
+
a: 0,
|
9
|
+
b: 5,
|
10
|
+
g: [0xA1455B33_4DF099DF_30FC28A1_69A467E9_E47075A9_0F7E650E_B6B7A45C,
|
11
|
+
0x7E089FED_7FBA3442_82CAFBD6_F7E319F7_C0B0BD59_E2CA4BDB_556D61A5],
|
12
|
+
n: 0x01_00000000_00000000_00000000_0001DCE8_D2EC6184_CAF0A971_769FB1F7,
|
13
|
+
h: 1,
|
14
|
+
)
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Source: http://www.secg.org/collateral/sec2_final.pdf
|
2
|
+
|
3
|
+
module ECDSA
|
4
|
+
class Group
|
5
|
+
Secp224r1 = new(
|
6
|
+
name: 'secp224r1',
|
7
|
+
p: 0xFFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_00000000_00000000_00000001,
|
8
|
+
a: 0xFFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFE_FFFFFFFF_FFFFFFFF_FFFFFFFE,
|
9
|
+
b: 0xB4050A85_0C04B3AB_F5413256_5044B0B7_D7BFD8BA_270B3943_2355FFB4,
|
10
|
+
g: [0xB70E0CBD_6BB4BF7F_321390B9_4A03C1D3_56C21122_343280D6_115C1D21,
|
11
|
+
0xBD376388_B5F723FB_4C22DFE6_CD4375A0_5A074764_44D58199_85007E34],
|
12
|
+
n: 0xFFFFFFFF_FFFFFFFF_FFFFFFFF_FFFF16A2_E0B8F03E_13DD2945_5C5C2A3D,
|
13
|
+
h: 1,
|
14
|
+
)
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# Source: http://www.secg.org/collateral/sec2_final.pdf
|
2
|
+
|
3
|
+
module ECDSA
|
4
|
+
class Group
|
5
|
+
Secp256k1 = new(
|
6
|
+
name: 'secp256k1',
|
7
|
+
p: 0xFFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFE_FFFFFC2F,
|
8
|
+
a: 0,
|
9
|
+
b: 7,
|
10
|
+
g: [0x79BE667E_F9DCBBAC_55A06295_CE870B07_029BFCDB_2DCE28D9_59F2815B_16F81798,
|
11
|
+
0x483ADA77_26A3C465_5DA4FBFC_0E1108A8_FD17B448_A6855419_9C47D08F_FB10D4B8],
|
12
|
+
n: 0xFFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFE_BAAEDCE6_AF48A03B_BFD25E8C_D0364141,
|
13
|
+
h: 1,
|
14
|
+
)
|
15
|
+
|
16
|
+
# compressed G: "\x02\x79\xBE\x66\x7E\xF9\xDC\xBB\xAC\x55\xA0\x62\x95\xCE\x87\x0B\x07\x02\x9B\xFC\xDB\x2D\xCE\x28\xD9\x59\xF2\x81\x5B\x16\xF8\x17\x98",
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Source: http://www.secg.org/collateral/sec2_final.pdf
|
2
|
+
|
3
|
+
module ECDSA
|
4
|
+
class Group
|
5
|
+
Secp256r1 = new(
|
6
|
+
name: 'secp256r1',
|
7
|
+
p: 0xFFFFFFFF_00000001_00000000_00000000_00000000_FFFFFFFF_FFFFFFFF_FFFFFFFF,
|
8
|
+
a: 0xFFFFFFFF_00000001_00000000_00000000_00000000_FFFFFFFF_FFFFFFFF_FFFFFFFC,
|
9
|
+
b: 0x5AC635D8_AA3A93E7_B3EBBD55_769886BC_651D06B0_CC53B0F6_3BCE3C3E_27D2604B,
|
10
|
+
g: [0x6B17D1F2_E12C4247_F8BCE6E5_63A440F2_77037D81_2DEB33A0_F4A13945_D898C296,
|
11
|
+
0x4FE342E2_FE1A7F9B_8EE7EB4A_7C0F9E16_2BCE3357_6B315ECE_CBB64068_37BF51F5],
|
12
|
+
n: 0xFFFFFFFF_00000000_FFFFFFFF_FFFFFFFF_BCE6FAAD_A7179E84_F3B9CAC2_FC632551,
|
13
|
+
h: 1,
|
14
|
+
)
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Source: http://www.secg.org/collateral/sec2_final.pdf
|
2
|
+
|
3
|
+
module ECDSA
|
4
|
+
class Group
|
5
|
+
Secp384r1 = new(
|
6
|
+
name: 'secp384r1',
|
7
|
+
p: 0xFFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFE_FFFFFFFF_00000000_00000000_FFFFFFFF,
|
8
|
+
a: 0xFFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFE_FFFFFFFF_00000000_00000000_FFFFFFFC,
|
9
|
+
b: 0xB3312FA7_E23EE7E4_988E056B_E3F82D19_181D9C6E_FE814112_0314088F_5013875A_C656398D_8A2ED19D_2A85C8ED_D3EC2AEF,
|
10
|
+
g: [0xAA87CA22_BE8B0537_8EB1C71E_F320AD74_6E1D3B62_8BA79B98_59F741E0_82542A38_5502F25D_BF55296C_3A545E38_72760AB7,
|
11
|
+
0x3617DE4A_96262C6F_5D9E98BF_9292DC29_F8F41DBD_289A147C_E9DA3113_B5F0B8C0_0A60B1CE_1D7E819D_7A431D7C_90EA0E5F],
|
12
|
+
n: 0xFFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_C7634D81_F4372DDF_581A0DB2_48B0A77A_ECEC196A_CCC52973,
|
13
|
+
h: 1,
|
14
|
+
)
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Source: http://www.secg.org/collateral/sec2_final.pdf
|
2
|
+
|
3
|
+
module ECDSA
|
4
|
+
class Group
|
5
|
+
Secp521r1 = new(
|
6
|
+
name: 'secp521r1',
|
7
|
+
p: 0x01FF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF,
|
8
|
+
a: 0x01FF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFC,
|
9
|
+
b: 0x0051_953EB961_8E1C9A1F_929A21A0_B68540EE_A2DA725B_99B315F3_B8B48991_8EF109E1_56193951_EC7E937B_1652C0BD_3BB1BF07_3573DF88_3D2C34F1_EF451FD4_6B503F00,
|
10
|
+
g: [0x00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66,
|
11
|
+
0x011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650],
|
12
|
+
n: 0x01FF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFA_51868783_BF2F966B_7FCC0148_F709A5D0_3BB5C9B8_899C47AE_BB6FB71E_91386409,
|
13
|
+
h: 1,
|
14
|
+
)
|
15
|
+
end
|
16
|
+
end
|
data/lib/ecdsa/point.rb
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
# http://www.secg.org/collateral/sec1_final.pdf
|
2
|
+
|
3
|
+
module ECDSA
|
4
|
+
class Point
|
5
|
+
attr_reader :group
|
6
|
+
|
7
|
+
attr_reader :x
|
8
|
+
|
9
|
+
attr_reader :y
|
10
|
+
|
11
|
+
def initialize(group, *args)
|
12
|
+
@group = group
|
13
|
+
|
14
|
+
if args == [:infinity]
|
15
|
+
@infinity = true
|
16
|
+
# leave @x and @y nil
|
17
|
+
else
|
18
|
+
x, y = args
|
19
|
+
raise ArgumentError, "Invalid x: #{x.inspect}" if !x.is_a? Integer
|
20
|
+
raise ArgumentError, "Invalid y: #{y.inspect}" if !y.is_a? Integer
|
21
|
+
|
22
|
+
@x = x
|
23
|
+
@y = y
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def coords
|
28
|
+
[x, y]
|
29
|
+
end
|
30
|
+
|
31
|
+
def add_to_point(point)
|
32
|
+
check_group! point
|
33
|
+
|
34
|
+
# Assertions:
|
35
|
+
# raise "point given (#{point.inspect}) does not belong to #{group.name}" if !group.include?(point)
|
36
|
+
# raise "point (#{inspect}) does not belong to #{group.name}" if !group.include?(self)
|
37
|
+
|
38
|
+
# SEC1, section 2.2.1, rules 1 and 2
|
39
|
+
return point if infinity?
|
40
|
+
return self if point.infinity?
|
41
|
+
|
42
|
+
# SEC1, section 2.2.1, rule 3
|
43
|
+
return group.infinity_point if x == point.x && y == field.mod(-point.y)
|
44
|
+
|
45
|
+
# SEC1, section 2.2.1, rule 4
|
46
|
+
if x != point.x
|
47
|
+
gamma = field.mod((point.y - y) * field.inverse(point.x - x))
|
48
|
+
sum_x = field.mod(gamma * gamma - x - point.x)
|
49
|
+
sum_y = field.mod(gamma * (x - sum_x) - y)
|
50
|
+
return self.class.new(group, sum_x, sum_y)
|
51
|
+
end
|
52
|
+
|
53
|
+
# SEC2, section 2.2.1, rule 5
|
54
|
+
return double if self == point
|
55
|
+
|
56
|
+
raise "Failed to add #{inspect} to #{point.inspect}: No addition rules matched."
|
57
|
+
end
|
58
|
+
|
59
|
+
def negate
|
60
|
+
return self if infinity?
|
61
|
+
self.class.new(group, x, field.mod(-y))
|
62
|
+
end
|
63
|
+
|
64
|
+
def double
|
65
|
+
gamma = field.mod((3 * x * x + @group.param_a) * field.inverse(2 * y))
|
66
|
+
new_x = field.mod(gamma * gamma - 2 * x)
|
67
|
+
new_y = field.mod(gamma * (x - new_x) - y)
|
68
|
+
self.class.new(group, new_x, new_y)
|
69
|
+
end
|
70
|
+
|
71
|
+
def multiply_by_scalar(i)
|
72
|
+
result = group.infinity_point
|
73
|
+
v = self
|
74
|
+
while i > 0
|
75
|
+
result = result.add_to_point(v) if i.odd?
|
76
|
+
v = v.double
|
77
|
+
i >>= 1
|
78
|
+
end
|
79
|
+
result
|
80
|
+
end
|
81
|
+
|
82
|
+
def eql?(other)
|
83
|
+
return false if !other.is_a?(Point) || other.group != group
|
84
|
+
x == other.x && y == other.y
|
85
|
+
end
|
86
|
+
|
87
|
+
def ==(other)
|
88
|
+
eql?(other)
|
89
|
+
end
|
90
|
+
|
91
|
+
def infinity?
|
92
|
+
@infinity == true
|
93
|
+
end
|
94
|
+
|
95
|
+
def inspect
|
96
|
+
if infinity?
|
97
|
+
'#<%s: %s, infinity>' % [self.class, group.name]
|
98
|
+
else
|
99
|
+
'#<%s: %s, 0x%x, 0x%x>' % [self.class, group.name, x, y]
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
def check_group!(point)
|
106
|
+
raise 'Mismatched groups.' if point.group != group
|
107
|
+
end
|
108
|
+
|
109
|
+
def field
|
110
|
+
group.field
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module ECDSA
|
2
|
+
class PrimeField
|
3
|
+
attr_reader :prime
|
4
|
+
|
5
|
+
def initialize(prime)
|
6
|
+
raise ArgumentError, "Invalid prime #{prime.inspect}" if !prime.is_a?(Integer)
|
7
|
+
@prime = prime
|
8
|
+
end
|
9
|
+
|
10
|
+
def include?(e)
|
11
|
+
e.is_a?(Integer) && e >= 0 && e < prime
|
12
|
+
end
|
13
|
+
|
14
|
+
def mod(num)
|
15
|
+
num % prime
|
16
|
+
end
|
17
|
+
|
18
|
+
# http://en.wikipedia.org/wiki/Extended_Euclidean_algorithm
|
19
|
+
def inverse(num)
|
20
|
+
raise ArgumentError, '0 has no multiplicative inverse.' if num.zero?
|
21
|
+
|
22
|
+
# For every i, we make sure that num * s[i] + prime * t[i] = r[i].
|
23
|
+
# Eventually r[i] will equal 1 because gcd(num, prime) is always 1.
|
24
|
+
# At that point, s[i] is the multiplicative inverse of num in the field.
|
25
|
+
|
26
|
+
remainders = [num, prime]
|
27
|
+
s = [1, 0]
|
28
|
+
t = [0, 1]
|
29
|
+
arrays = [remainders, s, t]
|
30
|
+
while remainders.last > 0
|
31
|
+
quotient = remainders[-2] / remainders[-1]
|
32
|
+
arrays.each do |array|
|
33
|
+
array << array[-2] - quotient * array[-1]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
raise 'Inversion bug: remainder is not than 1.' if remainders[-2] != 1
|
38
|
+
mod s[-2]
|
39
|
+
end
|
40
|
+
|
41
|
+
# Computes n raised to the power m.
|
42
|
+
# This algorithm uses the same idea as Point#multiply_by_scalar.
|
43
|
+
def power(n, m)
|
44
|
+
result = 1
|
45
|
+
v = n
|
46
|
+
while m > 0
|
47
|
+
result = mod result * v if m.odd?
|
48
|
+
v = square v
|
49
|
+
m >>= 1
|
50
|
+
end
|
51
|
+
result
|
52
|
+
end
|
53
|
+
|
54
|
+
# Computes n^2.
|
55
|
+
def square(n)
|
56
|
+
mod n * n
|
57
|
+
end
|
58
|
+
|
59
|
+
def square_roots(n)
|
60
|
+
raise ArgumentError, "Not a member of the field: #{n}." if !include?(n)
|
61
|
+
if (prime % 4) == 3
|
62
|
+
square_roots_for_p_3_mod_4(n)
|
63
|
+
else
|
64
|
+
raise NotImplementedError, 'Square root is only implemented in fields where the prime is equal to 3 mod 4.'
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
# This is Algorithm 1 from http://math.stanford.edu/~jbooher/expos/sqr_qnr.pdf
|
71
|
+
# The algorithm assumes that its input actually does have a square root.
|
72
|
+
# To get around that, we double check the answer after running the algorithm to make
|
73
|
+
# sure it works.
|
74
|
+
def square_roots_for_p_3_mod_4(n)
|
75
|
+
candidate = power n, (prime + 1) / 4
|
76
|
+
return [] if square(candidate) != n
|
77
|
+
return [candidate] if candidate.zero?
|
78
|
+
[candidate, mod(-candidate)].sort
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
data/lib/ecdsa/sign.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
module ECDSA
|
2
|
+
class SZeroError < StandardError
|
3
|
+
end
|
4
|
+
|
5
|
+
# From http://www.secg.org/collateral/sec1_final.pdf section 4.1.3
|
6
|
+
# Warning: Never use the same k value twice for two different messages
|
7
|
+
# or else it will be trivial for someone to calculate your private key.
|
8
|
+
# k should be generated with a secure random number generator.
|
9
|
+
def self.sign(group, private_key, digest, k)
|
10
|
+
# Second part of step 1: Select ephemeral elliptic curve key pair
|
11
|
+
# k was already selected for us by the caller
|
12
|
+
r_point = group.new_point k
|
13
|
+
|
14
|
+
# Step 2
|
15
|
+
xr = r_point.x
|
16
|
+
|
17
|
+
# Step 3
|
18
|
+
point_field = PrimeField.new(group.order)
|
19
|
+
r = point_field.mod(xr)
|
20
|
+
|
21
|
+
# Step 4, calculating the hash, was already performed by the caller.
|
22
|
+
|
23
|
+
# Step 5
|
24
|
+
e = normalize_digest(digest, group.bit_length)
|
25
|
+
|
26
|
+
# Step 6
|
27
|
+
s = point_field.mod(point_field.inverse(k) * (e + r * private_key))
|
28
|
+
|
29
|
+
if s.zero?
|
30
|
+
# We need to go back to step 1, so the caller should generate another
|
31
|
+
# random number k and try again.
|
32
|
+
return nil
|
33
|
+
end
|
34
|
+
|
35
|
+
Signature.new r, s
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module ECDSA
|
2
|
+
class Signature
|
3
|
+
attr_reader :r
|
4
|
+
attr_reader :s
|
5
|
+
|
6
|
+
def initialize(r, s)
|
7
|
+
@r, @s = r, s
|
8
|
+
r.is_a?(Integer) or raise ArgumentError, 'r is not an integer.'
|
9
|
+
s.is_a?(Integer) or raise ArgumentError, 's is not an integer.'
|
10
|
+
end
|
11
|
+
|
12
|
+
def components
|
13
|
+
[r, s]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/ecdsa/verify.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
module ECDSA
|
2
|
+
class InvalidSignatureError < StandardError
|
3
|
+
end
|
4
|
+
|
5
|
+
# Algorithm taken from http://www.secg.org/collateral/sec1_final.pdf Section 4.1.4.
|
6
|
+
def self.valid_signature?(public_key, digest, signature)
|
7
|
+
check_signature! public_key, digest, signature
|
8
|
+
rescue InvalidSignatureError
|
9
|
+
false
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.check_signature!(public_key, digest, signature)
|
13
|
+
group = public_key.group
|
14
|
+
field = group.field
|
15
|
+
|
16
|
+
# Step 1: r and s must be in the field and non-zero
|
17
|
+
raise InvalidSignatureError, 'r value is not the field.' if !field.include?(signature.r)
|
18
|
+
raise InvalidSignatureError, 's value is not the field.' if !field.include?(signature.s)
|
19
|
+
raise InvalidSignatureError, 'r is zero.' if signature.r.zero?
|
20
|
+
raise InvalidSignatureError, 's is zero.' if signature.s.zero?
|
21
|
+
|
22
|
+
# Step 2 was already performed when the digest of the message was computed.
|
23
|
+
|
24
|
+
# Step 3: Convert octet string to number and take leftmost bits.
|
25
|
+
e = normalize_digest(digest, group.bit_length)
|
26
|
+
|
27
|
+
# Step 4
|
28
|
+
point_field = PrimeField.new(group.order)
|
29
|
+
s_inverted = point_field.inverse(signature.s)
|
30
|
+
u1 = point_field.mod(e * s_inverted)
|
31
|
+
u2 = point_field.mod(signature.r * s_inverted)
|
32
|
+
|
33
|
+
# Step 5
|
34
|
+
r = group.generator.multiply_by_scalar(u1).add_to_point public_key.multiply_by_scalar(u2)
|
35
|
+
raise InvalidSignatureError, 'R is infinity in step 5.' if r.infinity?
|
36
|
+
|
37
|
+
# Step 6
|
38
|
+
xr = r.x
|
39
|
+
|
40
|
+
# Step 7
|
41
|
+
v = point_field.mod xr
|
42
|
+
|
43
|
+
# Step 8
|
44
|
+
raise InvalidSignatureError, 'v does not equal r.' if v != signature.r
|
45
|
+
|
46
|
+
true
|
47
|
+
end
|
48
|
+
end
|
metadata
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ecdsa
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- David Grayson
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-03-18 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description:
|
14
|
+
email: davidegrayson@gmail.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- lib/ecdsa/format/decode_error.rb
|
20
|
+
- lib/ecdsa/format/field_element_octet_string.rb
|
21
|
+
- lib/ecdsa/format/integer_octet_string.rb
|
22
|
+
- lib/ecdsa/format/point_octet_string.rb
|
23
|
+
- lib/ecdsa/format/signature_der_string.rb
|
24
|
+
- lib/ecdsa/format.rb
|
25
|
+
- lib/ecdsa/group/nistp192.rb
|
26
|
+
- lib/ecdsa/group/nistp224.rb
|
27
|
+
- lib/ecdsa/group/nistp256.rb
|
28
|
+
- lib/ecdsa/group/nistp384.rb
|
29
|
+
- lib/ecdsa/group/nistp521.rb
|
30
|
+
- lib/ecdsa/group/secp112r1.rb
|
31
|
+
- lib/ecdsa/group/secp112r2.rb
|
32
|
+
- lib/ecdsa/group/secp128r1.rb
|
33
|
+
- lib/ecdsa/group/secp128r2.rb
|
34
|
+
- lib/ecdsa/group/secp160k1.rb
|
35
|
+
- lib/ecdsa/group/secp160r1.rb
|
36
|
+
- lib/ecdsa/group/secp160r2.rb
|
37
|
+
- lib/ecdsa/group/secp192k1.rb
|
38
|
+
- lib/ecdsa/group/secp192r1.rb
|
39
|
+
- lib/ecdsa/group/secp224k1.rb
|
40
|
+
- lib/ecdsa/group/secp224r1.rb
|
41
|
+
- lib/ecdsa/group/secp256k1.rb
|
42
|
+
- lib/ecdsa/group/secp256r1.rb
|
43
|
+
- lib/ecdsa/group/secp384r1.rb
|
44
|
+
- lib/ecdsa/group/secp521r1.rb
|
45
|
+
- lib/ecdsa/group.rb
|
46
|
+
- lib/ecdsa/point.rb
|
47
|
+
- lib/ecdsa/prime_field.rb
|
48
|
+
- lib/ecdsa/sign.rb
|
49
|
+
- lib/ecdsa/signature.rb
|
50
|
+
- lib/ecdsa/verify.rb
|
51
|
+
- lib/ecdsa/version.rb
|
52
|
+
- lib/ecdsa.rb
|
53
|
+
- Gemfile
|
54
|
+
- README.md
|
55
|
+
- LICENSE.txt
|
56
|
+
homepage: https://github.com/pololu/rpicsim
|
57
|
+
licenses:
|
58
|
+
- MIT
|
59
|
+
metadata: {}
|
60
|
+
post_install_message:
|
61
|
+
rdoc_options: []
|
62
|
+
require_paths:
|
63
|
+
- lib
|
64
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - '>='
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '2'
|
74
|
+
requirements: []
|
75
|
+
rubyforge_project:
|
76
|
+
rubygems_version: 2.0.0
|
77
|
+
signing_key:
|
78
|
+
specification_version: 4
|
79
|
+
summary: This gem implements the Ellipctic Curve Digital Signature Algorithm (ECDSA)
|
80
|
+
almost entirely in pure Ruby.
|
81
|
+
test_files: []
|
82
|
+
has_rdoc:
|