ecdsa 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|