digibyte-cigs 0.0.1
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/.gitignore +46 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +29 -0
- data/LICENSE.txt +21 -0
- data/README.md +85 -0
- data/Rakefile +7 -0
- data/bin/digibyte-cigs +52 -0
- data/digibyte-cigs.gemspec +23 -0
- data/lib/digibyte-cigs.rb +1 -0
- data/lib/digibyte_cigs.rb +278 -0
- data/lib/digibyte_cigs/base_58.rb +42 -0
- data/lib/digibyte_cigs/compact_int.rb +33 -0
- data/lib/digibyte_cigs/crypto_helper.rb +67 -0
- data/lib/digibyte_cigs/curve_fp.rb +15 -0
- data/lib/digibyte_cigs/ec_key.rb +13 -0
- data/lib/digibyte_cigs/error.rb +4 -0
- data/lib/digibyte_cigs/point.rb +91 -0
- data/lib/digibyte_cigs/private_key.rb +28 -0
- data/lib/digibyte_cigs/public_key.rb +57 -0
- data/lib/digibyte_cigs/signature.rb +16 -0
- data/lib/digibyte_cigs/version.rb +3 -0
- data/misc/bitaddress.org.html +6487 -0
- data/misc/jasvet.py +632 -0
- data/spec/digibyte_cigs/base_58_spec.rb +28 -0
- data/spec/digibyte_cigs/compact_int_spec.rb +25 -0
- data/spec/digibyte_cigs_spec.rb +254 -0
- data/spec/spec_helper.rb +6 -0
- metadata +103 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: df993226b86b93297a57ad07fa01304a1d6702f5
|
4
|
+
data.tar.gz: 752c471cbcd1c6af8ebd8466284415ad480c101d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8632c3d2e520af4e00d5c384eac7ef90b0f8ad7ef378ecefd248b4e4e06f10f81fa03cb6c86498808e7038f467fdae5af7e03b790c3b8c0bf2ef02507e042c8d
|
7
|
+
data.tar.gz: 062e367f0e1211e9ad2ec181025aaf1f672c5327f6723fd63277fa87109cb95ddf491d4c46652785de8a536905b7903e019325f3312c55405a33e7955f35820e
|
data/.gitignore
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
# rcov generated
|
2
|
+
coverage
|
3
|
+
|
4
|
+
# rdoc generated
|
5
|
+
rdoc
|
6
|
+
|
7
|
+
# yard generated
|
8
|
+
doc
|
9
|
+
.yardoc
|
10
|
+
|
11
|
+
# bundler
|
12
|
+
.bundle
|
13
|
+
*.gem
|
14
|
+
|
15
|
+
# jeweler generated
|
16
|
+
pkg
|
17
|
+
|
18
|
+
# Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore:
|
19
|
+
#
|
20
|
+
# * Create a file at ~/.gitignore
|
21
|
+
# * Include files you want ignored
|
22
|
+
# * Run: git config --global core.excludesfile ~/.gitignore
|
23
|
+
#
|
24
|
+
# After doing this, these files will be ignored in all your git projects,
|
25
|
+
# saving you from having to 'pollute' every project you touch with them
|
26
|
+
#
|
27
|
+
# Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line)
|
28
|
+
#
|
29
|
+
# For MacOS:
|
30
|
+
|
31
|
+
.DS_Store
|
32
|
+
|
33
|
+
# For TextMate
|
34
|
+
*.tmproj
|
35
|
+
tmtags
|
36
|
+
.tmtags
|
37
|
+
|
38
|
+
# For emacs:
|
39
|
+
*~
|
40
|
+
\#*
|
41
|
+
.\#*
|
42
|
+
|
43
|
+
# For vim:
|
44
|
+
*.swp
|
45
|
+
|
46
|
+
.rvmrc
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
digibyte-cigs (0.0.1)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: http://rubygems.org/
|
8
|
+
specs:
|
9
|
+
diff-lcs (1.2.4)
|
10
|
+
rake (10.0.4)
|
11
|
+
rspec (2.13.0)
|
12
|
+
rspec-core (~> 2.13.0)
|
13
|
+
rspec-expectations (~> 2.13.0)
|
14
|
+
rspec-mocks (~> 2.13.0)
|
15
|
+
rspec-core (2.13.1)
|
16
|
+
rspec-expectations (2.13.0)
|
17
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
18
|
+
rspec-mocks (2.13.1)
|
19
|
+
|
20
|
+
PLATFORMS
|
21
|
+
ruby
|
22
|
+
|
23
|
+
DEPENDENCIES
|
24
|
+
digibyte-cigs!
|
25
|
+
rake (~> 10.0.4)
|
26
|
+
rspec (~> 2.13.0)
|
27
|
+
|
28
|
+
BUNDLED WITH
|
29
|
+
1.16.1
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2013 Michael Pearce
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
# DigiByte Cigs - Smokin' Hot DigiByte Signatures
|
2
|
+
|
3
|
+
## Installation
|
4
|
+
|
5
|
+
```sh
|
6
|
+
~$ gem install digibyte-cigs
|
7
|
+
```
|
8
|
+
|
9
|
+
## Command Line
|
10
|
+
|
11
|
+
Usage:
|
12
|
+
```sh
|
13
|
+
~$ digibyte-cigs
|
14
|
+
Usage: digibyte-cigs command [arguments ...] [options ...]
|
15
|
+
|
16
|
+
Commands
|
17
|
+
verify digibyte-address signature [message-file]
|
18
|
+
sign private-key [message-file]
|
19
|
+
|
20
|
+
Options
|
21
|
+
-m, --message MESSAGE Message can also be read from STDIN
|
22
|
+
-S, --no-strip Do not strip leading and trailing whitespace from message (stripped by default)
|
23
|
+
```
|
24
|
+
|
25
|
+
Examples:
|
26
|
+
```sh
|
27
|
+
~$ # Sign with -m message parameter
|
28
|
+
~$ digibyte-cigs sign 5JFZuDkLgbEXK4CUEiXyyz4fUqzAsQ5QUqufdJy8MoLA9S1RdNX -m 'this is a message'
|
29
|
+
HIBYi2g3yFimzD/YSD9j+PYwtsdCuHR2xwIQ6n0AN6RPUVDGttgOmlnsiwx90ZSjmaWrH1/HwrINJbaP7eMA6V4=
|
30
|
+
~$
|
31
|
+
~$ # Verify with message from STDIN
|
32
|
+
~$ echo 'this is a message' | digibyte-cigs verify 11o51X3ciSjoLWFN3sbg3yzCM8RSuD2q9 HIBYi2g3yFimzD/YSD9j+PYwtsdCuHR2xwIQ6n0AN6RPUVDGttgOmlnsiwx90ZSjmaWrH1/HwrINJbaP7eMA6V4=
|
33
|
+
~$
|
34
|
+
~$ # Verify with message from file
|
35
|
+
~$ echo 'this is a message' > message.txt
|
36
|
+
~$ digibyte-cigs verify 11o51X3ciSjoLWFN3sbg3yzCM8RSuD2q9 HIBYi2g3yFimzD/YSD9j+PYwtsdCuHR2xwIQ6n0AN6RPUVDGttgOmlnsiwx90ZSjmaWrH1/HwrINJbaP7eMA6V4= message.txt
|
37
|
+
~$
|
38
|
+
```
|
39
|
+
|
40
|
+
## Ruby API
|
41
|
+
|
42
|
+
Sign a message:
|
43
|
+
```ruby
|
44
|
+
require 'rubygems'
|
45
|
+
require 'digibyte-cigs'
|
46
|
+
|
47
|
+
# Support for Wallet Import Format, Compressed WIF, Mini Format, Hex and Base64 wallets
|
48
|
+
wallet_key = "5JFZuDkLgbEXK4CUEiXyyz4fUqzAsQ5QUqufdJy8MoLA9S1RdNX"
|
49
|
+
message = "this is a message"
|
50
|
+
|
51
|
+
puts "The signature is: #{DigiByteCigs.sign_message!(wallet_key, message)}"
|
52
|
+
```
|
53
|
+
|
54
|
+
Verify a message signature:
|
55
|
+
```ruby
|
56
|
+
require 'rubygems'
|
57
|
+
require 'digibyte-cigs'
|
58
|
+
|
59
|
+
address = "11o51X3ciSjoLWFN3sbg3yzCM8RSuD2q9"
|
60
|
+
signature = "HIBYi2g3yFimzD/YSD9j+PYwtsdCuHR2xwIQ6n0AN6RPUVDGttgOmlnsiwx90ZSjmaWrH1/HwrINJbaP7eMA6V4="
|
61
|
+
message = "this is a message"
|
62
|
+
|
63
|
+
if DigiByteCigs.verify_message(address, signature, message)
|
64
|
+
puts "It looks like you own address #{address}!"
|
65
|
+
end
|
66
|
+
```
|
67
|
+
|
68
|
+
# Credits
|
69
|
+
|
70
|
+
Thanks to jackjack for pointing me to Armory's implementation of message signatures:
|
71
|
+
https://github.com/jackjack-jj/jasvet
|
72
|
+
|
73
|
+
[DigiByte Cigs](https://github.com/michaelgpearce/digibyte-cigs) is maintained by [Michael Pearce](https://github.com/michaelgpearce).
|
74
|
+
|
75
|
+
# Donation
|
76
|
+
|
77
|
+
If you find this software useful and wish to donate, you can do so here:
|
78
|
+
```
|
79
|
+
1Cyd1wG4hCXK5aRCJQu3KnnhSrrfgs7NeM
|
80
|
+
```
|
81
|
+
|
82
|
+
# Copyright
|
83
|
+
|
84
|
+
Copyright (c) 2013 Michael Pearce. See LICENSE.txt for further details.
|
85
|
+
|
data/Rakefile
ADDED
data/bin/digibyte-cigs
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
require 'digibyte-cigs'
|
5
|
+
|
6
|
+
@options = {}
|
7
|
+
|
8
|
+
opt_parser = OptionParser.new do |opt|
|
9
|
+
opt.banner = "Usage: digibyte-cigs command [arguments ...] [options ...]"
|
10
|
+
opt.separator ""
|
11
|
+
opt.separator "Commands"
|
12
|
+
opt.separator " verify digibyte-address signature [message-file]"
|
13
|
+
opt.separator " sign private-key [message-file]"
|
14
|
+
opt.separator ""
|
15
|
+
opt.separator "Options"
|
16
|
+
opt.on("-m", "--message MESSAGE", "Message can also be read from STDIN") do |message|
|
17
|
+
@options[:message] = message
|
18
|
+
end
|
19
|
+
opt.on("-S", "--no-strip", "Do not strip leading and trailing whitespace from message (stripped by default)") do
|
20
|
+
@options[:no_strip] = true
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
opt_parser.parse!
|
25
|
+
|
26
|
+
def message
|
27
|
+
message = @options[:message] || ARGF.read
|
28
|
+
message.strip! unless @options[:no_strip]
|
29
|
+
|
30
|
+
message
|
31
|
+
end
|
32
|
+
|
33
|
+
begin
|
34
|
+
case ARGV.shift
|
35
|
+
when "verify"
|
36
|
+
address = ARGV.shift or raise ArgumentError
|
37
|
+
signature = ARGV.shift or raise ArgumentError
|
38
|
+
::DigiByteCigs.verify_message!(address, signature, message)
|
39
|
+
when "sign"
|
40
|
+
private_key = ARGV.shift or raise ArgumentError
|
41
|
+
puts ::DigiByteCigs.sign_message!(private_key, message)
|
42
|
+
else
|
43
|
+
raise ArgumentError
|
44
|
+
end
|
45
|
+
exit 0
|
46
|
+
rescue ::DigiByteCigs::Error => e
|
47
|
+
puts "Error: #{e}"
|
48
|
+
exit 2
|
49
|
+
rescue ArgumentError
|
50
|
+
puts opt_parser
|
51
|
+
exit 1
|
52
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
|
4
|
+
require "digibyte_cigs/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "digibyte-cigs"
|
8
|
+
spec.version = DigiByteCigs::VERSION
|
9
|
+
spec.authors = ["Vertbase"]
|
10
|
+
spec.email = ["dev@vertbase.com"]
|
11
|
+
spec.summary = "Create and Verify DigiByte Signatures"
|
12
|
+
spec.homepage = "https://github.com/vertbase/digibyte-cigs"
|
13
|
+
|
14
|
+
spec.rubyforge_project = "digibyte-cigs"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split("\n")
|
17
|
+
spec.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
spec.executables = ['digibyte-cigs']
|
20
|
+
|
21
|
+
spec.add_development_dependency 'rspec', '~> 2.13.0'
|
22
|
+
spec.add_development_dependency 'rake', '~> 10.0.4'
|
23
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'digibyte_cigs.rb')
|
@@ -0,0 +1,278 @@
|
|
1
|
+
%w(error crypto_helper compact_int base_58 curve_fp point public_key private_key signature ec_key).each do |f|
|
2
|
+
require File.join(File.dirname(__FILE__), 'digibyte_cigs', f)
|
3
|
+
end
|
4
|
+
|
5
|
+
module DigiByteCigs
|
6
|
+
PRIVATE_KEY_PREFIX = {
|
7
|
+
:mainnet => 0x80,
|
8
|
+
:testnet => 0xEF
|
9
|
+
}
|
10
|
+
NETWORK_VERSION = {
|
11
|
+
:mainnet => 0x00,
|
12
|
+
:testnet => 0x6F
|
13
|
+
}
|
14
|
+
|
15
|
+
P = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F
|
16
|
+
R = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
|
17
|
+
B = 0x0000000000000000000000000000000000000000000000000000000000000007
|
18
|
+
A = 0x0000000000000000000000000000000000000000000000000000000000000000
|
19
|
+
Gx = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798
|
20
|
+
Gy = 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8
|
21
|
+
|
22
|
+
CURVE_SECP256K1 = ::DigiByteCigs::CurveFp.new(P, A, B)
|
23
|
+
GENERATOR_SECP256K1 = ::DigiByteCigs::Point.new(CURVE_SECP256K1, Gx, Gy, R)
|
24
|
+
|
25
|
+
class << self
|
26
|
+
include ::DigiByteCigs::CryptoHelper
|
27
|
+
|
28
|
+
def verify_message(address, signature, message, options = {:network => :mainnet})
|
29
|
+
begin
|
30
|
+
verify_message!(address, signature, message, options)
|
31
|
+
true
|
32
|
+
rescue ::DigiByteCigs::Error
|
33
|
+
false
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def verify_message!(address, signature, message, options = {:network => :mainnet})
|
38
|
+
|
39
|
+
decoded_address = decode58(address)
|
40
|
+
raise ::DigiByteCigs::Error.new("Incorrect address or message for signature.") if decoded_address.nil?
|
41
|
+
# network_version = str_to_num(decoded_address) >> (8 * 24)
|
42
|
+
|
43
|
+
addr = get_signature_address!(signature, message, options)
|
44
|
+
|
45
|
+
raise ::DigiByteCigs::Error.new("Incorrect address or message for signature.") if address != addr
|
46
|
+
|
47
|
+
nil
|
48
|
+
end
|
49
|
+
|
50
|
+
def get_signature_address(signature, message, options = {:network => :mainnet})
|
51
|
+
begin
|
52
|
+
get_signature_address!(signature, message, options)
|
53
|
+
rescue ::DigiByteCigs::Error
|
54
|
+
false
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def get_signature_address!(signature, message, options = {:network => :mainnet})
|
59
|
+
|
60
|
+
message = calculate_hash(format_message_to_sign(message))
|
61
|
+
|
62
|
+
curve = CURVE_SECP256K1
|
63
|
+
g = GENERATOR_SECP256K1
|
64
|
+
a, b, p = curve.a, curve.b, curve.p
|
65
|
+
|
66
|
+
order = g.order
|
67
|
+
|
68
|
+
sig = decode64(signature)
|
69
|
+
raise ::DigiByteCigs::Error.new("Bad signature length") if sig.size != 65
|
70
|
+
raise ::DigiByteCigs::Error.new("Bad characters in signature") if signature != encode64(sig)
|
71
|
+
|
72
|
+
hb = sig[0].ord
|
73
|
+
r, s = [sig[1...33], sig[33...65]].collect { |s| str_to_num(s) }
|
74
|
+
|
75
|
+
|
76
|
+
raise ::DigiByteCigs::Error.new("Bad signature first byte") if hb < 27 || hb >= 35
|
77
|
+
|
78
|
+
compressed = false
|
79
|
+
if hb >= 31
|
80
|
+
compressed = true
|
81
|
+
hb -= 4
|
82
|
+
end
|
83
|
+
|
84
|
+
recid = hb - 27
|
85
|
+
x = (r + (recid / 2) * order) % p
|
86
|
+
y2 = ((x ** 3 % p) + a * x + b) % p
|
87
|
+
yomy = sqrt_mod(y2, p)
|
88
|
+
if (yomy - recid) % 2 == 0
|
89
|
+
y = yomy
|
90
|
+
else
|
91
|
+
y = p - yomy
|
92
|
+
end
|
93
|
+
|
94
|
+
r_point = ::DigiByteCigs::Point.new(curve, x, y, order)
|
95
|
+
e = str_to_num(message)
|
96
|
+
minus_e = -e % order
|
97
|
+
|
98
|
+
inv_r = inverse_mod(r, order)
|
99
|
+
q = (r_point * s + g * minus_e) * inv_r
|
100
|
+
|
101
|
+
|
102
|
+
public_key = ::DigiByteCigs::PublicKey.new(g, q, compressed)
|
103
|
+
|
104
|
+
public_key_to_bc_address(public_key.ser(), NETWORK_VERSION[options[:network]])
|
105
|
+
end
|
106
|
+
|
107
|
+
def sign_message(wallet_key, message, options = {:network => :mainnet})
|
108
|
+
begin
|
109
|
+
sign_message!(wallet_key, message, options)
|
110
|
+
rescue ::DigiByteCigs::Error
|
111
|
+
nil
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def sign_message!(wallet_key, message, options = {:network => :mainnet})
|
116
|
+
private_key = convert_wallet_format_to_bytes!(wallet_key, options[:network])
|
117
|
+
|
118
|
+
msg_hash = sha256(sha256(format_message_to_sign(message)))
|
119
|
+
|
120
|
+
ec_key = ::DigiByteCigs::EcKey.new(str_to_num(private_key))
|
121
|
+
private_key = ec_key.private_key
|
122
|
+
public_key = ec_key.public_key
|
123
|
+
addr = public_key_to_bc_address(get_pub_key(ec_key, ec_key.public_key.compressed), NETWORK_VERSION[options[:network]])
|
124
|
+
|
125
|
+
sig = private_key.sign(msg_hash, random_k)
|
126
|
+
raise ::DigiByteCigs::Error.new("Unable to sign message") unless public_key.verify(msg_hash, sig)
|
127
|
+
|
128
|
+
4.times do |i|
|
129
|
+
hb = 27 + i
|
130
|
+
|
131
|
+
sign = "#{hb.chr}#{sig.ser}"
|
132
|
+
sign_64 = encode64(sign)
|
133
|
+
|
134
|
+
begin
|
135
|
+
verify_message!(addr, sign_64, message, options)
|
136
|
+
return sign_64
|
137
|
+
rescue ::DigiByteCigs::Error
|
138
|
+
next
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
raise ::DigiByteCigs::Error, "Unable to construct recoverable key"
|
143
|
+
end
|
144
|
+
|
145
|
+
def convert_wallet_format_to_bytes!(input, network)
|
146
|
+
bytes = if is_wallet_import_format?(input, network)
|
147
|
+
decode_wallet_import_format(input, network)
|
148
|
+
elsif is_compressed_wallet_import_format?(input, network)
|
149
|
+
decode_compressed_wallet_import_format(input, network)
|
150
|
+
elsif is_mini_format?(input)
|
151
|
+
sha256(input)
|
152
|
+
elsif is_hex_format?(input)
|
153
|
+
decode_hex(input)
|
154
|
+
elsif is_base_64_format?(input)
|
155
|
+
decode64(input)
|
156
|
+
else
|
157
|
+
raise ::DigiByteCigs::Error.new("Unknown Wallet Format")
|
158
|
+
end
|
159
|
+
|
160
|
+
bytes
|
161
|
+
end
|
162
|
+
|
163
|
+
private
|
164
|
+
|
165
|
+
def format_message_to_sign(message)
|
166
|
+
"\x18DigiByte Signed Message:\n#{::DigiByteCigs::CompactInt.new(message.size).encode}#{message}"
|
167
|
+
end
|
168
|
+
|
169
|
+
def random_k
|
170
|
+
k = 0
|
171
|
+
8.times do |i|
|
172
|
+
k |= (rand * 0xffffffff).to_i << (32 * i)
|
173
|
+
end
|
174
|
+
|
175
|
+
k
|
176
|
+
end
|
177
|
+
|
178
|
+
def get_pub_key(public_key, compressed)
|
179
|
+
i2o_ec_public_key(public_key, compressed)
|
180
|
+
end
|
181
|
+
|
182
|
+
def i2o_ec_public_key(public_key, compressed)
|
183
|
+
key = if compressed
|
184
|
+
"#{public_key.public_key.point.y & 1 > 0 ? '03' : '02'}%064x" % public_key.public_key.point.x
|
185
|
+
else
|
186
|
+
"04%064x%064x" % [public_key.public_key.point.x, public_key.public_key.point.y]
|
187
|
+
end
|
188
|
+
|
189
|
+
decode_hex(key)
|
190
|
+
end
|
191
|
+
|
192
|
+
def decode_wallet_import_format(input, network)
|
193
|
+
bytes = decode58(input)#[1..-1]
|
194
|
+
#puts "ASDF #{bytes.unpack('H*')}"
|
195
|
+
#puts bytes.bytes.collect {|e| e.to_i}.join(" ")
|
196
|
+
hash = bytes[0..32]
|
197
|
+
|
198
|
+
checksum = sha256(sha256(hash))
|
199
|
+
raise ::DigiByteCigs::Error.new("Wallet checksum invalid") if bytes[33..37] != checksum[0..3]
|
200
|
+
|
201
|
+
version, hash = hash[0], hash[1..-1]
|
202
|
+
raise ::DigiByteCigs::Error.new("Wallet Version #{version} not supported") if version.ord != PRIVATE_KEY_PREFIX[network]
|
203
|
+
|
204
|
+
hash
|
205
|
+
end
|
206
|
+
|
207
|
+
def decode_compressed_wallet_import_format(input, network)
|
208
|
+
bytes = decode58(input)
|
209
|
+
hash = bytes[0...34]
|
210
|
+
|
211
|
+
checksum = sha256(sha256(hash))
|
212
|
+
raise ::DigiByteCigs::Error.new("Wallet checksum invalid") if bytes[34..37] != checksum[0..3]
|
213
|
+
|
214
|
+
version, hash = hash[0], hash[1..32]
|
215
|
+
raise ::DigiByteCigs::Error.new("Wallet Version #{version} not supported") if version.ord != PRIVATE_KEY_PREFIX[network]
|
216
|
+
|
217
|
+
hash
|
218
|
+
end
|
219
|
+
|
220
|
+
# 64 characters [0-9A-F]
|
221
|
+
def is_hex_format?(key)
|
222
|
+
/^[A-Fa-f0-9]{64}$/ =~ key
|
223
|
+
end
|
224
|
+
|
225
|
+
# 51 characters base58 starting with 5
|
226
|
+
def is_wallet_import_format?(key, network)
|
227
|
+
/^#{network == :mainnet ? '5' : '9'}[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{50}$/ =~ key
|
228
|
+
end
|
229
|
+
|
230
|
+
# 52 characters base58 starting with L or K
|
231
|
+
def is_compressed_wallet_import_format?(key, network)
|
232
|
+
/^[network == :mainnet ? 'LK' : 'c'][123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{51}$/ =~ key
|
233
|
+
end
|
234
|
+
|
235
|
+
# 44 characters
|
236
|
+
def is_base_64_format?(key)
|
237
|
+
/^[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789=+\/]{44}$/ =~ key
|
238
|
+
end
|
239
|
+
|
240
|
+
# 22, 26 or 30 characters, always starts with an 'S'
|
241
|
+
def is_mini_format?(key)
|
242
|
+
validChars22 = /^S[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{21}$/ =~ key
|
243
|
+
validChars26 = /^S[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{25}$/ =~ key
|
244
|
+
validChars30 = /^S[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{29}$/ =~ key
|
245
|
+
|
246
|
+
bytes = sha256("#{key}?")
|
247
|
+
|
248
|
+
(bytes[0].ord === 0x00 || bytes[0].ord === 0x01) && (validChars22 || validChars26 || validChars30)
|
249
|
+
end
|
250
|
+
|
251
|
+
def debug_bytes(s)
|
252
|
+
s.chars.collect(&:ord).join(', ')
|
253
|
+
end
|
254
|
+
|
255
|
+
def calculate_hash(d)
|
256
|
+
sha256(sha256(d))
|
257
|
+
end
|
258
|
+
|
259
|
+
def public_key_to_bc_address(public_key, network_version)
|
260
|
+
h160 = hash_160(public_key)
|
261
|
+
|
262
|
+
hash_160_to_bc_address(h160, network_version)
|
263
|
+
end
|
264
|
+
|
265
|
+
def hash_160_to_bc_address(h160, address_type)
|
266
|
+
vh160 = address_type.chr + h160
|
267
|
+
h = calculate_hash(vh160)
|
268
|
+
addr = vh160 + h[0...4]
|
269
|
+
|
270
|
+
encode58(addr)
|
271
|
+
end
|
272
|
+
|
273
|
+
def hash_160(public_key)
|
274
|
+
ripemd160(sha256(public_key))
|
275
|
+
end
|
276
|
+
|
277
|
+
end
|
278
|
+
end
|