elliptic-lite 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/CHANGELOG.md +3 -0
- data/Manifest.txt +16 -0
- data/README.md +399 -0
- data/Rakefile +29 -0
- data/lib/elliptic-lite.rb +9 -0
- data/lib/elliptic-lite/base.rb +76 -0
- data/lib/elliptic-lite/field.rb +151 -0
- data/lib/elliptic-lite/point.rb +179 -0
- data/lib/elliptic-lite/secp256k1.rb +31 -0
- data/lib/elliptic-lite/signature.rb +62 -0
- data/lib/elliptic-lite/version.rb +20 -0
- data/lib/elliptic/lite.rb +2 -0
- data/test/helper.rb +12 -0
- data/test/test_field.rb +142 -0
- data/test/test_point.rb +83 -0
- data/test/test_signature.rb +61 -0
- metadata +103 -0
@@ -0,0 +1,62 @@
|
|
1
|
+
###########
|
2
|
+
# Elliptic Curve Digital Signature Algorithm (ECDSA)
|
3
|
+
|
4
|
+
module ECC
|
5
|
+
|
6
|
+
|
7
|
+
class Signature
|
8
|
+
attr_reader :r, :s
|
9
|
+
def initialize( r, s )
|
10
|
+
@r, @s = r, s
|
11
|
+
end
|
12
|
+
end # class Signature
|
13
|
+
|
14
|
+
|
15
|
+
class PublicKey
|
16
|
+
attr_reader :point
|
17
|
+
|
18
|
+
def initialize( *args, group: SECP256K1 )
|
19
|
+
@group = group
|
20
|
+
|
21
|
+
if args.size == 1 ## assume it's a point already -- todo/fix: check class via group - why? why not?
|
22
|
+
@point = args[0]
|
23
|
+
elsif args.size == 2 ## assume it's an x/y coord pair -- todo/fix: check must be Integer class/type - why? why not?
|
24
|
+
@point = @group.point( *args )
|
25
|
+
else
|
26
|
+
raise ArgumentError, "expected point or x/y coords for point; got: #{args.inspect}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def verify?( z, sig )
|
31
|
+
s_inv = sig.s.pow( @group.n-2, @group.n )
|
32
|
+
u = z * s_inv % @group.n
|
33
|
+
v = sig.r * s_inv % @group.n
|
34
|
+
|
35
|
+
total = u*@group.g + v*@point
|
36
|
+
total.x == sig.r
|
37
|
+
end
|
38
|
+
end # class PublicKey
|
39
|
+
|
40
|
+
|
41
|
+
class PrivateKey
|
42
|
+
def initialize( secret, group: SECP256K1 )
|
43
|
+
@secret = secret
|
44
|
+
@group = group
|
45
|
+
end
|
46
|
+
|
47
|
+
def public_key
|
48
|
+
@pubkey ||= PublicKey.new( @secret * @group.g, group: @group )
|
49
|
+
end
|
50
|
+
alias_method :pubkey, :public_key
|
51
|
+
|
52
|
+
def sign( z )
|
53
|
+
k = 1 + SecureRandom.random_number( @group.n - 1)
|
54
|
+
# k = 1234567890
|
55
|
+
r = (k*@group.g).x
|
56
|
+
k_inv = k.pow( @group.n-2, @group.n )
|
57
|
+
s = (z+r*@secret) * k_inv % @group.n
|
58
|
+
s = @group.n - s if s > @group.n/2
|
59
|
+
Signature.new( r, s )
|
60
|
+
end
|
61
|
+
end # class PrivateKey
|
62
|
+
end # module ECC
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module ECCLite
|
2
|
+
|
3
|
+
MAJOR = 0
|
4
|
+
MINOR = 1
|
5
|
+
PATCH = 0
|
6
|
+
VERSION = [MAJOR,MINOR,PATCH].join('.')
|
7
|
+
|
8
|
+
def self.version
|
9
|
+
VERSION
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.banner
|
13
|
+
"elliptic-lite/#{VERSION} on Ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}] in (#{root})"
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.root
|
17
|
+
File.expand_path( File.dirname(File.dirname(File.dirname(__FILE__))) )
|
18
|
+
end
|
19
|
+
|
20
|
+
end # module ECCLite
|
data/test/helper.rb
ADDED
data/test/test_field.rb
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
###
|
2
|
+
# to run use
|
3
|
+
# ruby -I ./lib -I ./test test/test_field.rb
|
4
|
+
|
5
|
+
|
6
|
+
require 'helper'
|
7
|
+
|
8
|
+
class TestField < MiniTest::Test
|
9
|
+
|
10
|
+
## same as F13 = FiniteField.new(13) - use shortcut - why? why not?
|
11
|
+
class F₁₃ < ECC::FiniteField::Element
|
12
|
+
def self.prime() 13; end
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
def test_f13
|
17
|
+
pp F₁₃
|
18
|
+
pp F₁₃.prime
|
19
|
+
assert_equal 13, F₁₃.prime
|
20
|
+
|
21
|
+
assert F₁₃.include?( 0 )
|
22
|
+
assert F₁₃.include?( 12 )
|
23
|
+
assert_equal false, F₁₃.include?( 13 )
|
24
|
+
|
25
|
+
|
26
|
+
pp F₁₃.new(7)
|
27
|
+
pp F₁₃.new(6)
|
28
|
+
|
29
|
+
a = F₁₃[7]
|
30
|
+
b = F₁₃[6]
|
31
|
+
|
32
|
+
assert_equal false, a == b
|
33
|
+
assert_equal false, F₁₃[7] == F₁₃[6]
|
34
|
+
|
35
|
+
assert a == a
|
36
|
+
assert F₁₃[7] == F₁₃[7]
|
37
|
+
|
38
|
+
|
39
|
+
|
40
|
+
a = F₁₃[7]
|
41
|
+
b = F₁₃[12]
|
42
|
+
c = F₁₃[6]
|
43
|
+
|
44
|
+
assert_equal c, a+b
|
45
|
+
assert_equal 6, F₁₃.add( 7, 12 )
|
46
|
+
|
47
|
+
c = F₁₃[8]
|
48
|
+
assert_equal c, a-b
|
49
|
+
assert_equal F₁₃[8], a-b
|
50
|
+
assert_equal 8, F₁₃.sub( 7, 12 )
|
51
|
+
|
52
|
+
a = F₁₃[3]
|
53
|
+
b = F₁₃[12]
|
54
|
+
c = F₁₃[10]
|
55
|
+
|
56
|
+
assert_equal c, a*b
|
57
|
+
assert_equal F₁₃[10], F₁₃[3]*F₁₃[12]
|
58
|
+
assert_equal 10, F₁₃.mul( 3, 12 )
|
59
|
+
|
60
|
+
|
61
|
+
a = F₁₃[3]
|
62
|
+
b = F₁₃[1]
|
63
|
+
assert_equal b, a**3
|
64
|
+
assert_equal b, a*a*a
|
65
|
+
assert_equal a**3, a*a*a
|
66
|
+
assert_equal 1, F₁₃.pow( 3, 3 )
|
67
|
+
|
68
|
+
a = F₁₃[7]
|
69
|
+
b = F₁₃[8]
|
70
|
+
|
71
|
+
pp a**-3
|
72
|
+
assert_equal b, a**-3
|
73
|
+
assert_equal 8, F₁₃.pow( 7, -3 )
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
|
78
|
+
class F₁₇ < ECC::FiniteField::Element
|
79
|
+
def self.prime() 17; end
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_f17
|
83
|
+
pp F₁₇.new(7)
|
84
|
+
assert F₁₇.new(7) == F₁₇[7]
|
85
|
+
assert F₁₇.new(7) == F₁₇.new(7)
|
86
|
+
assert F₁₇[7] == F₁₇[7]
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
F₁₉ = ECC::FiniteField.new(19)
|
91
|
+
|
92
|
+
def test_f19
|
93
|
+
a = F₁₉[2]
|
94
|
+
b = F₁₉[7]
|
95
|
+
c = a / b
|
96
|
+
|
97
|
+
assert_equal F₁₉[3], c
|
98
|
+
|
99
|
+
assert_equal F₁₉[9], F₁₉[7] / F₁₉[5]
|
100
|
+
assert_equal 9, F₁₉.div( 7, 5 )
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
def test_examples
|
105
|
+
a = F₁₃[7]
|
106
|
+
b = F₁₃[12]
|
107
|
+
c = F₁₃[6]
|
108
|
+
assert_equal c, a+b
|
109
|
+
|
110
|
+
c = F₁₃[8]
|
111
|
+
assert_equal c, a-b
|
112
|
+
|
113
|
+
a = F₁₃[3]
|
114
|
+
b = F₁₃[12]
|
115
|
+
c = F₁₃[10]
|
116
|
+
assert_equal c, a*b
|
117
|
+
|
118
|
+
a = F₁₃[3]
|
119
|
+
b = F₁₃[1]
|
120
|
+
assert_equal b, a**3
|
121
|
+
assert_equal b, a*a*a
|
122
|
+
assert_equal a**3, a*a*a
|
123
|
+
|
124
|
+
a = F₁₉[2]
|
125
|
+
b = F₁₉[7]
|
126
|
+
c = F₁₉[3]
|
127
|
+
assert_equal c, a/b
|
128
|
+
|
129
|
+
|
130
|
+
assert_equal F₁₃[6], F₁₃[7] + F₁₃[12]
|
131
|
+
assert_equal F₁₃[8], F₁₃[7] - F₁₃[12]
|
132
|
+
assert_equal F₁₃[10], F₁₃[3] * F₁₃[12]
|
133
|
+
assert_equal F₁₃[1], F₁₃[3] ** 3
|
134
|
+
assert_equal F₁₃[1], F₁₃[3] * F₁₃[3] * F₁₃[3]
|
135
|
+
assert_equal F₁₃[3] * F₁₃[3] * F₁₃[3], F₁₃[3] ** 3
|
136
|
+
|
137
|
+
assert_equal F₁₉[3], F₁₉[2] / F₁₉[7]
|
138
|
+
end
|
139
|
+
|
140
|
+
end # class TestField
|
141
|
+
|
142
|
+
|
data/test/test_point.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
###
|
2
|
+
# to run use
|
3
|
+
# ruby -I ./lib -I ./test test/test_point.rb
|
4
|
+
|
5
|
+
|
6
|
+
require 'helper'
|
7
|
+
|
8
|
+
class TestPoint < MiniTest::Test
|
9
|
+
|
10
|
+
class Point_5_7 < ECC::Point
|
11
|
+
def self.curve() @curve ||= ECC::Curve.new( a: 5, b: 7 ); end
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_point_5_7
|
15
|
+
p1 = Point_5_7.new( -1, -1 ) # point with x/y coords: -1/-1
|
16
|
+
## p2 = Point_5_7.new( -1, -2 ) # raise ArgumentError!! point NOT on curve
|
17
|
+
|
18
|
+
assert Point_5_7.on_curve?( -1, -1 ) #=> true
|
19
|
+
assert_equal false, Point_5_7.on_curve?( -1, -2 ) #=> false
|
20
|
+
|
21
|
+
inf = Point_5_7[ :infinity ]
|
22
|
+
assert inf.infinity? #=> true
|
23
|
+
|
24
|
+
p1 = Point_5_7[-1, -1]
|
25
|
+
p2 = Point_5_7[-1, 1]
|
26
|
+
inf = Point_5_7[ :infinity ]
|
27
|
+
|
28
|
+
assert Point_5_7[-1,-1], p1 + inf
|
29
|
+
assert Point_5_7[-1,1], inf + p2
|
30
|
+
assert Point_5_7[:infinity], p1 + p2
|
31
|
+
|
32
|
+
p1 = Point_5_7[ 2, 5]
|
33
|
+
p2 = Point_5_7[-1,-1]
|
34
|
+
assert Point_5_7[3,-7], p1 + p2
|
35
|
+
|
36
|
+
p1 = Point_5_7[-1,-1]
|
37
|
+
assert Point_5_7[18,77], p1 + p1
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
|
42
|
+
class F₂₂₃ < ECC::FiniteField::Element
|
43
|
+
def self.prime() 223; end
|
44
|
+
end
|
45
|
+
|
46
|
+
class Point_F₂₂₃0_7 < ECC::Point
|
47
|
+
def self.curve() @curve ||= ECC::Curve.new( a: 0, b: 7, f: F₂₂₃ ); end
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
def test_point_f₂₂₃0_7
|
52
|
+
p1 = Point_F₂₂₃0_7[ 192, 105 ]
|
53
|
+
p2 = Point_F₂₂₃0_7[ 17, 56 ]
|
54
|
+
assert Point_F₂₂₃0_7[170,142], p1 + p2
|
55
|
+
|
56
|
+
p1 = Point_F₂₂₃0_7[ 170, 142 ]
|
57
|
+
p2 = Point_F₂₂₃0_7[ 60, 139 ]
|
58
|
+
assert Point_F₂₂₃0_7[220,181], p1 + p2
|
59
|
+
|
60
|
+
p1 = Point_F₂₂₃0_7[ 47, 71 ]
|
61
|
+
p2 = Point_F₂₂₃0_7[ 17, 56 ]
|
62
|
+
assert Point_F₂₂₃0_7[215,68], p1 + p2
|
63
|
+
|
64
|
+
|
65
|
+
p = Point_F₂₂₃0_7[ 192, 105 ]
|
66
|
+
assert Point_F₂₂₃0_7[49,71], p+p
|
67
|
+
|
68
|
+
p = Point_F₂₂₃0_7[ 143, 98 ]
|
69
|
+
assert Point_F₂₂₃0_7[64,168], p+p
|
70
|
+
|
71
|
+
p = Point_F₂₂₃0_7[ 47, 71 ]
|
72
|
+
assert Point_F₂₂₃0_7[36,111], p+p
|
73
|
+
assert Point_F₂₂₃0_7[194,51], p+p+p+p
|
74
|
+
assert Point_F₂₂₃0_7[116,55], p+p+p+p+p+p+p+p
|
75
|
+
assert Point_F₂₂₃0_7[:infinity], p+p+p+p+p+p+p+p+p+p+p+p+p+p+p+p+p+p+p+p+p
|
76
|
+
|
77
|
+
assert 2*p, p+p
|
78
|
+
assert 4*p, p+p+p+p
|
79
|
+
assert 8*p, p+p+p+p+p+p+p+p
|
80
|
+
assert 21*p, p+p+p+p+p+p+p+p+p+p+p+p+p+p+p+p+p+p+p+p+p
|
81
|
+
end
|
82
|
+
end # class TestPoint
|
83
|
+
|
@@ -0,0 +1,61 @@
|
|
1
|
+
###
|
2
|
+
# to run use
|
3
|
+
# ruby -I ./lib -I ./test test/test_signature.rb
|
4
|
+
|
5
|
+
|
6
|
+
require 'helper'
|
7
|
+
|
8
|
+
class TestSignature < MiniTest::Test
|
9
|
+
|
10
|
+
def test_verify
|
11
|
+
puts "test_verify:"
|
12
|
+
pubkey = ECC::PublicKey.new(
|
13
|
+
0x887387e452b8eacc4acfde10d9aaf7f6d9a0f975aabb10d006e4da568744d06c,
|
14
|
+
0x61de6d95231cd89026e286df3b6ae4a894a3378e393e93a0f45b666329a0ae34 )
|
15
|
+
pp pubkey
|
16
|
+
|
17
|
+
z = 0xec208baa0fc1c19f708a9ca96fdeff3ac3f230bb4a7ba4aede4942ad003c0f60
|
18
|
+
sig = ECC::Signature.new(
|
19
|
+
0xac8d1c87e51d0d441be8b3dd5b05c8795b48875dffe00b7ffcfac23010d3a395,
|
20
|
+
0x68342ceff8935ededd102dd876ffd6ba72d6a427a3edb13d26eb0781cb423c4)
|
21
|
+
|
22
|
+
assert pubkey.verify?( z, sig )
|
23
|
+
|
24
|
+
|
25
|
+
z = 0x7c076ff316692a3d7eb3c3bb0f8b1488cf72e1afcd929e29307032997a838a3d
|
26
|
+
sig = ECC::Signature.new(
|
27
|
+
0xeff69ef2b1bd93a66ed5219add4fb51e11a840f404876325a1e8ffe0529a2c,
|
28
|
+
0xc7207fee197d27c618aea621406f6bf5ef6fca38681d82b2f06fddbdce6feab6)
|
29
|
+
|
30
|
+
assert pubkey.verify?( z, sig )
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_sign
|
34
|
+
puts "test_sign:"
|
35
|
+
e = 12345
|
36
|
+
key = ECC::PrivateKey.new( e )
|
37
|
+
|
38
|
+
pp z_hex = Digest::SHA256.hexdigest( 'Programming Elliptic Curve Cryptography!' )
|
39
|
+
pp z = z_hex.to_i( 16 )
|
40
|
+
|
41
|
+
sig = key.sign( z )
|
42
|
+
pp sig
|
43
|
+
|
44
|
+
|
45
|
+
pp pubkey = key.pubkey
|
46
|
+
|
47
|
+
assert pubkey.verify?( z, sig )
|
48
|
+
|
49
|
+
# -or-
|
50
|
+
pubkey = ECC::PublicKey.new(
|
51
|
+
0xf01d6b9018ab421dd410404cb869072065522bf85734008f105cf385a023a80f,
|
52
|
+
0x0eba29d0f0c5408ed681984dc525982abefccd9f7ff01dd26da4999cf3f6a295 )
|
53
|
+
|
54
|
+
sig = ECC::Signature.new(
|
55
|
+
35839919642726191515862186078164267963984698217861116280002507416364797996230,
|
56
|
+
34481949470477153440646085306694123309931748956488082604284303792820502002529 )
|
57
|
+
|
58
|
+
assert pubkey.verify?( z, sig )
|
59
|
+
end
|
60
|
+
end # class TestSignature
|
61
|
+
|
metadata
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: elliptic-lite
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Gerald Bauer
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-06-06 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rdoc
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4.0'
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '7'
|
23
|
+
type: :development
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '4.0'
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '7'
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: hoe
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '3.22'
|
40
|
+
type: :development
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '3.22'
|
47
|
+
description: elliptic-lite - elliptic curve cryptography from scratch / zero - start
|
48
|
+
with finite fields, add elliptic curve points and point addition and scalar multiplications,
|
49
|
+
add the elliptic curve digital signature algorithm (ECDSA) using the secp256k1 curve
|
50
|
+
/ group to sign and verify messages and more
|
51
|
+
email: wwwmake@googlegroups.com
|
52
|
+
executables: []
|
53
|
+
extensions: []
|
54
|
+
extra_rdoc_files:
|
55
|
+
- CHANGELOG.md
|
56
|
+
- Manifest.txt
|
57
|
+
- README.md
|
58
|
+
files:
|
59
|
+
- CHANGELOG.md
|
60
|
+
- Manifest.txt
|
61
|
+
- README.md
|
62
|
+
- Rakefile
|
63
|
+
- lib/elliptic-lite.rb
|
64
|
+
- lib/elliptic-lite/base.rb
|
65
|
+
- lib/elliptic-lite/field.rb
|
66
|
+
- lib/elliptic-lite/point.rb
|
67
|
+
- lib/elliptic-lite/secp256k1.rb
|
68
|
+
- lib/elliptic-lite/signature.rb
|
69
|
+
- lib/elliptic-lite/version.rb
|
70
|
+
- lib/elliptic/lite.rb
|
71
|
+
- test/helper.rb
|
72
|
+
- test/test_field.rb
|
73
|
+
- test/test_point.rb
|
74
|
+
- test/test_signature.rb
|
75
|
+
homepage: https://github.com/rubycoco/blockchain
|
76
|
+
licenses:
|
77
|
+
- Public Domain
|
78
|
+
metadata: {}
|
79
|
+
post_install_message:
|
80
|
+
rdoc_options:
|
81
|
+
- "--main"
|
82
|
+
- README.md
|
83
|
+
require_paths:
|
84
|
+
- lib
|
85
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '2.3'
|
90
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
requirements: []
|
96
|
+
rubygems_version: 3.1.4
|
97
|
+
signing_key:
|
98
|
+
specification_version: 4
|
99
|
+
summary: elliptic-lite - elliptic curve cryptography from scratch / zero - start with
|
100
|
+
finite fields, add elliptic curve points and point addition and scalar multiplications,
|
101
|
+
add the elliptic curve digital signature algorithm (ECDSA) using the secp256k1 curve
|
102
|
+
/ group to sign and verify messages and more
|
103
|
+
test_files: []
|