monacoin-ruby 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/bitcoin.rb +933 -0
- data/lib/bitcoin/bloom_filter.rb +125 -0
- data/lib/bitcoin/builder.rb +494 -0
- data/lib/bitcoin/connection.rb +130 -0
- data/lib/bitcoin/contracthash.rb +76 -0
- data/lib/bitcoin/dogecoin.rb +97 -0
- data/lib/bitcoin/electrum/mnemonic.rb +162 -0
- data/lib/bitcoin/ext_key.rb +191 -0
- data/lib/bitcoin/ffi/bitcoinconsensus.rb +75 -0
- data/lib/bitcoin/ffi/openssl.rb +388 -0
- data/lib/bitcoin/ffi/secp256k1.rb +266 -0
- data/lib/bitcoin/key.rb +280 -0
- data/lib/bitcoin/litecoin.rb +83 -0
- data/lib/bitcoin/logger.rb +86 -0
- data/lib/bitcoin/protocol.rb +189 -0
- data/lib/bitcoin/protocol/address.rb +50 -0
- data/lib/bitcoin/protocol/alert.rb +46 -0
- data/lib/bitcoin/protocol/aux_pow.rb +123 -0
- data/lib/bitcoin/protocol/block.rb +285 -0
- data/lib/bitcoin/protocol/handler.rb +43 -0
- data/lib/bitcoin/protocol/parser.rb +194 -0
- data/lib/bitcoin/protocol/partial_merkle_tree.rb +61 -0
- data/lib/bitcoin/protocol/reject.rb +38 -0
- data/lib/bitcoin/protocol/script_witness.rb +31 -0
- data/lib/bitcoin/protocol/tx.rb +587 -0
- data/lib/bitcoin/protocol/txin.rb +142 -0
- data/lib/bitcoin/protocol/txout.rb +95 -0
- data/lib/bitcoin/protocol/version.rb +88 -0
- data/lib/bitcoin/script.rb +1656 -0
- data/lib/bitcoin/trezor/mnemonic.rb +130 -0
- data/lib/bitcoin/version.rb +3 -0
- metadata +32 -1
@@ -0,0 +1,130 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
|
3
|
+
require 'socket'
|
4
|
+
require 'eventmachine'
|
5
|
+
require 'bitcoin'
|
6
|
+
require 'resolv'
|
7
|
+
|
8
|
+
module Bitcoin
|
9
|
+
|
10
|
+
module ConnectionHandler
|
11
|
+
def on_inv_transaction(hash)
|
12
|
+
p ['inv transaction', hash.hth]
|
13
|
+
pkt = Protocol.getdata_pkt(:tx, [hash])
|
14
|
+
send_data(pkt)
|
15
|
+
end
|
16
|
+
|
17
|
+
def on_inv_block(hash)
|
18
|
+
p ['inv block', hash.hth]
|
19
|
+
pkt = Protocol.getdata_pkt(:block, [hash])
|
20
|
+
send_data(pkt)
|
21
|
+
end
|
22
|
+
|
23
|
+
def on_get_transaction(hash)
|
24
|
+
p ['get transaction', hash.hth]
|
25
|
+
end
|
26
|
+
|
27
|
+
def on_get_block(hash)
|
28
|
+
p ['get block', hash.hth]
|
29
|
+
end
|
30
|
+
|
31
|
+
def on_addr(addr)
|
32
|
+
p ['addr', addr, addr.alive?]
|
33
|
+
end
|
34
|
+
|
35
|
+
def on_tx(tx)
|
36
|
+
p ['tx', tx.hash]
|
37
|
+
end
|
38
|
+
|
39
|
+
def on_block(block)
|
40
|
+
p ['block', block.hash]
|
41
|
+
#p block.payload.each_byte.map{|i| "%02x" % [i] }.join(" ")
|
42
|
+
#puts block.to_json
|
43
|
+
end
|
44
|
+
|
45
|
+
def on_version(version)
|
46
|
+
p [@sockaddr, 'version', version, version.time - Time.now.to_i]
|
47
|
+
send_data( Protocol.verack_pkt )
|
48
|
+
end
|
49
|
+
|
50
|
+
def on_verack
|
51
|
+
on_handshake_complete
|
52
|
+
end
|
53
|
+
|
54
|
+
def on_handshake_complete
|
55
|
+
p [@sockaddr, 'handshake complete']
|
56
|
+
@connected = true
|
57
|
+
|
58
|
+
query_blocks
|
59
|
+
end
|
60
|
+
|
61
|
+
def query_blocks
|
62
|
+
start = ("\x00"*32)
|
63
|
+
stop = ("\x00"*32)
|
64
|
+
pkt = Protocol.pkt("getblocks", "\x00" + start + stop )
|
65
|
+
send_data(pkt)
|
66
|
+
end
|
67
|
+
|
68
|
+
def on_handshake_begin
|
69
|
+
block = 127953
|
70
|
+
from = "127.0.0.1:8333"
|
71
|
+
from_id = Bitcoin::Protocol::Uniq
|
72
|
+
to = @sockaddr.reverse.join(":")
|
73
|
+
# p "==", from_id, from, to, block
|
74
|
+
pkt = Protocol.version_pkt(from_id, from, to, block)
|
75
|
+
p ['sending version pkt', pkt]
|
76
|
+
send_data(pkt)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
class Connection < EM::Connection
|
82
|
+
include ConnectionHandler
|
83
|
+
|
84
|
+
def initialize(host, port, connections)
|
85
|
+
@sockaddr = [port, host]
|
86
|
+
@connections = connections
|
87
|
+
@parser = Bitcoin::Protocol::Parser.new( self )
|
88
|
+
end
|
89
|
+
|
90
|
+
def post_init
|
91
|
+
p ['connected', @sockaddr]
|
92
|
+
EM.schedule{ on_handshake_begin }
|
93
|
+
end
|
94
|
+
|
95
|
+
def receive_data(data)
|
96
|
+
@parser.parse(data)
|
97
|
+
end
|
98
|
+
|
99
|
+
def unbind
|
100
|
+
p ['disconnected', @sockaddr]
|
101
|
+
self.class.connect_random_from_dns(@connections)
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.connect(host, port, connections)
|
105
|
+
EM.connect(host, port, self, host, port, connections)
|
106
|
+
end
|
107
|
+
|
108
|
+
def self.connect_random_from_dns(connections)
|
109
|
+
seeds = Bitcoin.network[:dns_seeds]
|
110
|
+
if seeds.any?
|
111
|
+
host = Resolv::DNS.new.getaddresses(seeds.sample).map {|a| a.to_s}.sample
|
112
|
+
connect(host, Bitcoin::network[:default_port], connections)
|
113
|
+
else
|
114
|
+
raise "No DNS seeds available. Provide IP, configure seeds, or use different network."
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
if $0 == __FILE__
|
122
|
+
EM.run do
|
123
|
+
|
124
|
+
connections = []
|
125
|
+
#Bitcoin::Connection.connect('127.0.0.1', 8333, connections)
|
126
|
+
#Bitcoin::Connection.connect('217.157.1.202', 8333, connections)
|
127
|
+
Bitcoin::Connection.connect_random_from_dns(connections)
|
128
|
+
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
#
|
2
|
+
# Ruby port of https://github.com/Blockstream/contracthashtool
|
3
|
+
#
|
4
|
+
|
5
|
+
module Bitcoin
|
6
|
+
module ContractHash
|
7
|
+
|
8
|
+
HMAC_DIGEST = OpenSSL::Digest.new("SHA256")
|
9
|
+
EC_GROUP = OpenSSL::PKey::EC::Group.new("secp256k1")
|
10
|
+
|
11
|
+
def self.hmac(pubkey, data)
|
12
|
+
OpenSSL::HMAC.hexdigest(HMAC_DIGEST, pubkey, data)
|
13
|
+
end
|
14
|
+
|
15
|
+
# generate a contract address
|
16
|
+
def self.generate(redeem_script_hex, payee_address_or_ascii, nonce_hex=nil)
|
17
|
+
redeem_script = Bitcoin::Script.new([redeem_script_hex].pack("H*"))
|
18
|
+
raise "only multisig redeem scripts are currently supported" unless redeem_script.is_multisig?
|
19
|
+
nonce_hex, data = compute_data(payee_address_or_ascii, nonce_hex)
|
20
|
+
|
21
|
+
derived_keys = []
|
22
|
+
redeem_script.get_multisig_pubkeys.each do |pubkey|
|
23
|
+
tweak = hmac(pubkey, data).to_i(16)
|
24
|
+
raise "order exceeded, pick a new nonce" if tweak >= EC_GROUP.order.to_i
|
25
|
+
tweak = OpenSSL::BN.new(tweak.to_s)
|
26
|
+
|
27
|
+
key = Bitcoin::Key.new(nil, pubkey.unpack("H*")[0])
|
28
|
+
key = key.instance_variable_get(:@key)
|
29
|
+
point = EC_GROUP.generator.mul(tweak).ec_add(key.public_key).to_bn.to_i
|
30
|
+
raise "infinity" if point == 1/0.0
|
31
|
+
|
32
|
+
key = Bitcoin::Key.new(nil, point.to_s(16))
|
33
|
+
key.instance_eval{ @pubkey_compressed = true }
|
34
|
+
derived_keys << key.pub
|
35
|
+
end
|
36
|
+
|
37
|
+
m = redeem_script.get_signatures_required
|
38
|
+
p2sh_script, redeem_script = Bitcoin::Script.to_p2sh_multisig_script(m, *derived_keys)
|
39
|
+
|
40
|
+
[ nonce_hex, redeem_script.unpack("H*")[0], Bitcoin::Script.new(p2sh_script).get_p2sh_address ]
|
41
|
+
end
|
42
|
+
|
43
|
+
# claim a contract
|
44
|
+
def self.claim(private_key_wif, payee_address_or_ascii, nonce_hex)
|
45
|
+
key = Bitcoin::Key.from_base58(private_key_wif)
|
46
|
+
data = compute_data(payee_address_or_ascii, nonce_hex)[1]
|
47
|
+
|
48
|
+
pubkey = [key.pub].pack("H*")
|
49
|
+
tweak = hmac(pubkey, data).to_i(16)
|
50
|
+
raise "order exceeded, verify parameters" if tweak >= EC_GROUP.order.to_i
|
51
|
+
|
52
|
+
derived_key = (tweak + key.priv.to_i(16)) % EC_GROUP.order.to_i
|
53
|
+
raise "zero" if derived_key == 0
|
54
|
+
|
55
|
+
Bitcoin::Key.new(derived_key.to_s(16))
|
56
|
+
end
|
57
|
+
|
58
|
+
# compute HMAC data
|
59
|
+
def self.compute_data(address_or_ascii, nonce_hex)
|
60
|
+
nonce = nonce_hex ? [nonce_hex].pack("H32") : SecureRandom.random_bytes(16)
|
61
|
+
if Bitcoin.valid_address?(address_or_ascii)
|
62
|
+
address_type = case Bitcoin.address_type(address_or_ascii)
|
63
|
+
when :hash160; 'P2PH'
|
64
|
+
when :p2sh; 'P2SH'
|
65
|
+
else
|
66
|
+
raise "unsupported address type #{address_type}"
|
67
|
+
end
|
68
|
+
contract_bytes = [ Bitcoin.hash160_from_address(address_or_ascii) ].pack("H*")
|
69
|
+
else
|
70
|
+
address_type = "TEXT"
|
71
|
+
contract_bytes = address_or_ascii
|
72
|
+
end
|
73
|
+
[ nonce.unpack("H*")[0], address_type + nonce + contract_bytes ]
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
|
3
|
+
# This module includes (almost) everything necessary to add dogecoin support
|
4
|
+
# to bitcoin-ruby. When switching to a :dogecoin network, it will load its
|
5
|
+
# functionality into the Script class.
|
6
|
+
# The only things not included here should be parsing the AuxPow, which is
|
7
|
+
# done in Protocol::Block directly, and passing the txout to #store_doge from
|
8
|
+
# the storage backend.
|
9
|
+
module Bitcoin::Dogecoin
|
10
|
+
|
11
|
+
def self.load
|
12
|
+
Bitcoin::Util.class_eval { include Util }
|
13
|
+
end
|
14
|
+
|
15
|
+
# fixed reward past the 600k block
|
16
|
+
POST_600K_REWARD = 10000 * Bitcoin::COIN
|
17
|
+
|
18
|
+
# Dogecoin-specific Script methods for parsing and creating of dogecoin scripts,
|
19
|
+
# as well as methods to extract address, doge_hash, doge and value.
|
20
|
+
module Util
|
21
|
+
|
22
|
+
def self.included(base)
|
23
|
+
base.constants.each {|c| const_set(c, base.const_get(c)) unless constants.include?(c) }
|
24
|
+
base.class_eval do
|
25
|
+
|
26
|
+
def block_creation_reward(block_height)
|
27
|
+
if block_height < Bitcoin.network[:difficulty_change_block]
|
28
|
+
# Dogecoin early rewards were random, using part of the hash of the
|
29
|
+
# previous block as the seed for the Mersenne Twister algorithm.
|
30
|
+
# Given we don't have previous block hash available, and this value is
|
31
|
+
# functionally a maximum (not exact value), I'm using the maximum the random
|
32
|
+
# reward generator can produce and calling it good enough.
|
33
|
+
Bitcoin.network[:reward_base] / (2 ** (block_height / Bitcoin.network[:reward_halving].to_f).floor) * 2
|
34
|
+
elsif block_height < 600000
|
35
|
+
Bitcoin.network[:reward_base] / (2 ** (block_height / Bitcoin.network[:reward_halving].to_f).floor)
|
36
|
+
else
|
37
|
+
POST_600K_REWARD
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def block_new_target(prev_height, prev_block_time, prev_block_bits, last_retarget_time)
|
42
|
+
new_difficulty_protocol = (prev_height + 1) >= Bitcoin.network[:difficulty_change_block]
|
43
|
+
|
44
|
+
# target interval for block interval in seconds
|
45
|
+
retarget_time = Bitcoin.network[:retarget_time]
|
46
|
+
|
47
|
+
if new_difficulty_protocol
|
48
|
+
# what is the ideal interval between the blocks
|
49
|
+
retarget_time = Bitcoin.network[:retarget_time_new]
|
50
|
+
end
|
51
|
+
|
52
|
+
# actual time elapsed since last retarget
|
53
|
+
actual_time = prev_block_time - last_retarget_time
|
54
|
+
|
55
|
+
if new_difficulty_protocol
|
56
|
+
# DigiShield implementation - thanks to RealSolid & WDC for this code
|
57
|
+
# We round always towards zero to match the C++ version
|
58
|
+
if actual_time < retarget_time
|
59
|
+
actual_time = retarget_time + ((actual_time - retarget_time) / 8.0).ceil
|
60
|
+
else
|
61
|
+
actual_time = retarget_time + ((actual_time - retarget_time) / 8.0).floor
|
62
|
+
end
|
63
|
+
# amplitude filter - thanks to daft27 for this code
|
64
|
+
min = retarget_time - (retarget_time/4)
|
65
|
+
max = retarget_time + (retarget_time/2)
|
66
|
+
elsif prev_height+1 > 10000
|
67
|
+
min = retarget_time / 4
|
68
|
+
max = retarget_time * 4
|
69
|
+
elsif prev_height+1 > 5000
|
70
|
+
min = retarget_time / 8
|
71
|
+
max = retarget_time * 4
|
72
|
+
else
|
73
|
+
min = retarget_time / 16
|
74
|
+
max = retarget_time * 4
|
75
|
+
end
|
76
|
+
|
77
|
+
actual_time = min if actual_time < min
|
78
|
+
actual_time = max if actual_time > max
|
79
|
+
|
80
|
+
# It could be a bit confusing: we are adjusting difficulty of the previous block, while logically
|
81
|
+
# we should use difficulty of the previous 2016th block ("first")
|
82
|
+
|
83
|
+
prev_target = decode_compact_bits(prev_block_bits).to_i(16)
|
84
|
+
|
85
|
+
new_target = prev_target * actual_time / retarget_time
|
86
|
+
if new_target < Bitcoin.decode_compact_bits(Bitcoin.network[:proof_of_work_limit]).to_i(16)
|
87
|
+
encode_compact_bits(new_target.to_s(16))
|
88
|
+
else
|
89
|
+
Bitcoin.network[:proof_of_work_limit]
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
|
3
|
+
class Mnemonic
|
4
|
+
# ruby version of: https://github.com/spesmilo/electrum/blob/master/lib/mnemonic.py
|
5
|
+
|
6
|
+
# list of words from http://en.wiktionary.org/wiki/Wiktionary:Frequency_lists/Contemporary_poetry
|
7
|
+
Words = (<<-TEXT).split
|
8
|
+
like just love know never want time out there make look eye down only think
|
9
|
+
heart back then into about more away still them take thing even through long always
|
10
|
+
world too friend tell try hand thought over here other need smile again much cry
|
11
|
+
been night ever little said end some those around mind people girl leave dream left
|
12
|
+
turn myself give nothing really off before something find walk wish good once place ask
|
13
|
+
stop keep watch seem everything wait got yet made remember start alone run hope maybe
|
14
|
+
believe body hate after close talk stand own each hurt help home god soul new
|
15
|
+
many two inside should true first fear mean better play another gone change use wonder
|
16
|
+
someone hair cold open best any behind happen water dark laugh stay forever name work
|
17
|
+
show sky break came deep door put black together upon happy such great white matter
|
18
|
+
fill past please burn cause enough touch moment soon voice scream anything stare sound red
|
19
|
+
everyone hide kiss truth death beautiful mine blood broken very pass next forget tree wrong
|
20
|
+
air mother understand lip hit wall memory sleep free high realize school might skin sweet
|
21
|
+
perfect blue kill breath dance against fly between grow strong under listen bring sometimes speak
|
22
|
+
pull person become family begin ground real small father sure feet rest young finally land
|
23
|
+
across today different guy line fire reason reach second slowly write eat smell mouth step
|
24
|
+
learn three floor promise breathe darkness push earth guess save song above along both color
|
25
|
+
house almost sorry anymore brother okay dear game fade already apart warm beauty heard notice
|
26
|
+
question shine began piece whole shadow secret street within finger point morning whisper child moon
|
27
|
+
green story glass kid silence since soft yourself empty shall angel answer baby bright dad
|
28
|
+
path worry hour drop follow power war half flow heaven act chance fact least tired
|
29
|
+
children near quite afraid rise sea taste window cover nice trust lot sad cool force
|
30
|
+
peace return blind easy ready roll rose drive held music beneath hang mom paint emotion
|
31
|
+
quiet clear cloud few pretty bird outside paper picture front rock simple anyone meant reality
|
32
|
+
road sense waste bit leaf thank happiness meet men smoke truly decide self age book
|
33
|
+
form alive carry escape damn instead able ice minute throw catch leg ring course goodbye
|
34
|
+
lead poem sick corner desire known problem remind shoulder suppose toward wave drink jump woman
|
35
|
+
pretend sister week human joy crack grey pray surprise dry knee less search bleed caught
|
36
|
+
clean embrace future king son sorrow chest hug remain sat worth blow daddy final parent
|
37
|
+
tight also create lonely safe cross dress evil silent bone fate perhaps anger class scar
|
38
|
+
snow tiny tonight continue control dog edge mirror month suddenly comfort given loud quickly gaze
|
39
|
+
plan rush stone town battle ignore spirit stood stupid yours brown build dust hey kept
|
40
|
+
pay phone twist although ball beyond hidden nose taken fail float pure somehow wash wrap
|
41
|
+
angry cheek creature forgotten heat rip single space special weak whatever yell anyway blame job
|
42
|
+
choose country curse drift echo figure grew laughter neck suffer worse yeah disappear foot forward
|
43
|
+
knife mess somewhere stomach storm beg idea lift offer breeze field five often simply stuck
|
44
|
+
win allow confuse enjoy except flower seek strength calm grin gun heavy hill large ocean
|
45
|
+
shoe sigh straight summer tongue accept crazy everyday exist grass mistake sent shut surround table
|
46
|
+
ache brain destroy heal nature shout sign stain choice doubt glance glow mountain queen stranger
|
47
|
+
throat tomorrow city either fish flame rather shape spin spread ash distance finish image imagine
|
48
|
+
important nobody shatter warmth became feed flesh funny lust shirt trouble yellow attention bare bite
|
49
|
+
money protect amaze appear born choke completely daughter fresh friendship gentle probably six deserve expect
|
50
|
+
grab middle nightmare river thousand weight worst wound barely bottle cream regret relationship stick test
|
51
|
+
crush endless fault itself rule spill art circle join kick mask master passion quick raise
|
52
|
+
smooth unless wander actually broke chair deal favorite gift note number sweat box chill clothes
|
53
|
+
lady mark park poor sadness tie animal belong brush consume dawn forest innocent pen pride
|
54
|
+
stream thick clay complete count draw faith press silver struggle surface taught teach wet bless
|
55
|
+
chase climb enter letter melt metal movie stretch swing vision wife beside crash forgot guide
|
56
|
+
haunt joke knock plant pour prove reveal steal stuff trip wood wrist bother bottom crawl
|
57
|
+
crowd fix forgive frown grace loose lucky party release surely survive teacher gently grip speed
|
58
|
+
suicide travel treat vein written cage chain conversation date enemy however interest million page pink
|
59
|
+
proud sway themselves winter church cruel cup demon experience freedom pair pop purpose respect shoot
|
60
|
+
softly state strange bar birth curl dirt excuse lord lovely monster order pack pants pool
|
61
|
+
scene seven shame slide ugly among blade blonde closet creek deny drug eternity gain grade
|
62
|
+
handle key linger pale prepare swallow swim tremble wheel won cast cigarette claim college direction
|
63
|
+
dirty gather ghost hundred loss lung orange present swear swirl twice wild bitter blanket doctor
|
64
|
+
everywhere flash grown knowledge numb pressure radio repeat ruin spend unknown buy clock devil early
|
65
|
+
false fantasy pound precious refuse sheet teeth welcome add ahead block bury caress content depth
|
66
|
+
despite distant marry purple threw whenever bomb dull easily grasp hospital innocence normal receive reply
|
67
|
+
rhyme shade someday sword toe visit asleep bought center consider flat hero history ink insane
|
68
|
+
muscle mystery pocket reflection shove silently smart soldier spot stress train type view whether bus
|
69
|
+
energy explain holy hunger inch magic mix noise nowhere prayer presence shock snap spider study
|
70
|
+
thunder trail admit agree bag bang bound butterfly cute exactly explode familiar fold further pierce
|
71
|
+
reflect scent selfish sharp sink spring stumble universe weep women wonderful action ancient attempt avoid
|
72
|
+
birthday branch chocolate core depress drunk especially focus fruit honest match palm perfectly pillow pity
|
73
|
+
poison roar shift slightly thump truck tune twenty unable wipe wrote coat constant dinner drove
|
74
|
+
egg eternal flight flood frame freak gasp glad hollow motion peer plastic root screen season
|
75
|
+
sting strike team unlike victim volume warn weird attack await awake built charm crave despair
|
76
|
+
fought grant grief horse limit message ripple sanity scatter serve split string trick annoy blur
|
77
|
+
boat brave clearly cling connect fist forth imagination iron jock judge lesson milk misery nail
|
78
|
+
naked ourselves poet possible princess sail size snake society stroke torture toss trace wise bloom
|
79
|
+
bullet cell check cost darling during footstep fragile hallway hardly horizon invisible journey midnight mud
|
80
|
+
nod pause relax shiver sudden value youth abuse admire blink breast bruise constantly couple creep
|
81
|
+
curve difference dumb emptiness gotta honor plain planet recall rub ship slam soar somebody tightly
|
82
|
+
weather adore approach bond bread burst candle coffee cousin crime desert flutter frozen grand heel
|
83
|
+
hello language level movement pleasure powerful random rhythm settle silly slap sort spoken steel threaten
|
84
|
+
tumble upset aside awkward bee blank board button card carefully complain crap deeply discover drag
|
85
|
+
dread effort entire fairy giant gotten greet illusion jeans leap liquid march mend nervous nine
|
86
|
+
replace rope spine stole terror accident apple balance boom childhood collect demand depression eventually faint
|
87
|
+
glare goal group honey kitchen laid limb machine mere mold murder nerve painful poetry prince
|
88
|
+
rabbit shelter shore shower soothe stair steady sunlight tangle tease treasure uncle begun bliss canvas
|
89
|
+
cheer claw clutch commit crimson crystal delight doll existence express fog football gay goose guard
|
90
|
+
hatred illuminate mass math mourn rich rough skip stir student style support thorn tough yard
|
91
|
+
yearn yesterday advice appreciate autumn bank beam bowl capture carve collapse confusion creation dove feather
|
92
|
+
girlfriend glory government harsh hop inner loser moonlight neighbor neither peach pig praise screw shield
|
93
|
+
shimmer sneak stab subject throughout thrown tower twirl wow army arrive bathroom bump cease cookie
|
94
|
+
couch courage dim guilt howl hum husband insult led lunch mock mostly natural nearly needle
|
95
|
+
nerd peaceful perfection pile price remove roam sanctuary serious shiny shook sob stolen tap vain
|
96
|
+
void warrior wrinkle affection apologize blossom bounce bridge cheap crumble decision descend desperately dig dot
|
97
|
+
flip frighten heartbeat huge lazy lick odd opinion process puzzle quietly retreat score sentence separate
|
98
|
+
situation skill soak square stray taint task tide underneath veil whistle anywhere bedroom bid bloody
|
99
|
+
burden careful compare concern curtain decay defeat describe double dreamer driver dwell evening flare flicker
|
100
|
+
grandma guitar harm horrible hungry indeed lace melody monkey nation object obviously rainbow salt scratch
|
101
|
+
shown shy stage stun third tickle useless weakness worship worthless afternoon beard boyfriend bubble busy
|
102
|
+
certain chin concrete desk diamond doom drawn due felicity freeze frost garden glide harmony hopefully
|
103
|
+
hunt jealous lightning mama mercy peel physical position pulse punch quit rant respond salty sane
|
104
|
+
satisfy savior sheep slept social sport tuck utter valley wolf aim alas alter arrow awaken
|
105
|
+
beaten belief brand ceiling cheese clue confidence connection daily disguise eager erase essence everytime expression
|
106
|
+
fan flag flirt foul fur giggle glorious ignorance law lifeless measure mighty muse north opposite
|
107
|
+
paradise patience patient pencil petal plate ponder possibly practice slice spell stock strife strip suffocate
|
108
|
+
suit tender tool trade velvet verse waist witch aunt bench bold cap certainly click companion
|
109
|
+
creator dart delicate determine dish dragon drama drum dude everybody feast forehead former fright fully
|
110
|
+
gas hook hurl invite juice manage moral possess raw rebel royal scale scary several slight
|
111
|
+
stubborn swell talent tea terrible thread torment trickle usually vast violence weave acid agony ashamed
|
112
|
+
awe belly blend blush character cheat common company coward creak danger deadly defense define depend
|
113
|
+
desperate destination dew duck dusty embarrass engine example explore foe freely frustrate generation glove guilty
|
114
|
+
health hurry idiot impossible inhale jaw kingdom mention mist moan mumble mutter observe ode pathetic
|
115
|
+
pattern pie prefer puff rape rare revenge rude scrape spiral squeeze strain sunset suspend sympathy
|
116
|
+
thigh throne total unseen weapon weary
|
117
|
+
TEXT
|
118
|
+
|
119
|
+
def self.encode(hex, words=Words)
|
120
|
+
n = words.size
|
121
|
+
[hex].pack("H*").unpack("N*").map{|x|
|
122
|
+
w1 = x % n
|
123
|
+
w2 = ((x / n) + w1) % n
|
124
|
+
w3 = ((x / n / n) + w2) % n
|
125
|
+
[ words[w1], words[w2], words[w3] ]
|
126
|
+
}.flatten
|
127
|
+
end
|
128
|
+
|
129
|
+
def self.decode(word_list, words=Words)
|
130
|
+
n = words.size
|
131
|
+
word_list.each_slice(3).map{|three_words|
|
132
|
+
w1, w2, w3 = three_words.map{|word| words.index(word) % n }
|
133
|
+
'%08x' % ( w1 + n*((w2-w1)%n) + n*n*((w3-w2)%n) )
|
134
|
+
}.join
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
|
140
|
+
|
141
|
+
if $0 == __FILE__
|
142
|
+
hex = "4c7d10656aa55383a5d88e3f63300af5e169918f4058bf349d99b20239909b61"
|
143
|
+
expected_words = ['horse', 'love', 'nose', 'speak', 'diamond', 'gaze', 'wash', 'drag', 'glance',
|
144
|
+
'money', 'cease', 'soft', 'complete', 'huge', 'aside', 'confusion', 'touch',
|
145
|
+
'grass', 'pie', 'play', 'bread', 'exactly', 'bubble', 'great']
|
146
|
+
|
147
|
+
# from http://brainwallet.org/#chains
|
148
|
+
hex = "ff64b72c431f75799f0c5ebe438e46dd"
|
149
|
+
expected_words = %w[muscle lot sea got revenge crack wait yeah gas study embrace spend]
|
150
|
+
hex = "18cfaf96961750c7a4e4e39c861d1415"
|
151
|
+
expected_words = %w[example poor twice expect decision master blame rub forward easy jump carve]
|
152
|
+
|
153
|
+
# from https://en.bitcoin.it/wiki/Electrum#Brain_Wallet
|
154
|
+
hex = "431a62f1c86555d3c45e5c4d9e10c8c7"
|
155
|
+
expected_words = %w[constant forest adore false green weave stop guy fur freeze giggle clock]
|
156
|
+
|
157
|
+
#p Mnemonic.encode(hex)
|
158
|
+
p Mnemonic.encode(hex) == expected_words
|
159
|
+
#p Mnemonic.decode(expected_words)
|
160
|
+
p Mnemonic.decode(expected_words) == hex
|
161
|
+
end
|
162
|
+
|