elliptic-lite 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/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: []
|