digibyte-cigs 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|