bip_mnemonic 0.0.2 → 0.0.3
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 +5 -5
- data/lib/bip_mnemonic.rb +44 -29
- metadata +7 -8
- data/lib/pbkdf2.rb +0 -118
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 866130921b342eab2a72f02b33e659e1a644b6a832d13e31af08bcbcd209f9ea
|
4
|
+
data.tar.gz: 8d2581038cc68b6ac8588b7274f425966bcb3d7078ee63638a1bc7a29893c3f1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9e3416ed270b6c5679bf406cbaae6c67f29e30991a15adcd129e6d07ca9e0234b8d0f5c776d26d5e5114d7e3a76a9abfe70d934cf6ee7176c570e3ef0168e2b7
|
7
|
+
data.tar.gz: c8ea91e39855b9604d49ecbbb285c6916f2db3bd8135bd1ac4860010e1cdd84c619ea5b7e88c9454fe87da83275176a5e06613e4ac5dba298436bb19228bd985
|
data/lib/bip_mnemonic.rb
CHANGED
@@ -1,51 +1,66 @@
|
|
1
|
-
require '
|
2
|
-
|
1
|
+
require 'openssl'
|
3
2
|
class BipMnemonic
|
4
|
-
VERSION =
|
3
|
+
VERSION = '0.0.3'.freeze
|
4
|
+
|
5
5
|
def self.to_mnemonic(options)
|
6
6
|
options ||= {}
|
7
7
|
bits = options[:bits] || 128
|
8
|
-
|
9
|
-
|
10
|
-
entropy_bytes = [options[:entropy]].pack("H*")
|
8
|
+
if options[:entropy].nil?
|
9
|
+
entropy_bytes = OpenSSL::Random.random_bytes(bits / 8)
|
11
10
|
else
|
12
|
-
|
11
|
+
raise ArgumentError, 'Entropy is empty' if options[:entropy].empty?
|
12
|
+
entropy_bytes = [options[:entropy]].pack('H*')
|
13
13
|
end
|
14
|
-
entropy_binary = entropy_bytes.unpack(
|
14
|
+
entropy_binary = entropy_bytes.unpack('B*').first
|
15
15
|
seed_binary = entropy_binary + checksum(entropy_binary)
|
16
|
-
words_array = File.readlines(
|
17
|
-
|
16
|
+
words_array = File.readlines(
|
17
|
+
File.join(
|
18
|
+
File.dirname(File.expand_path(__FILE__)), '../words/english.txt'
|
19
|
+
)
|
20
|
+
).map(&:strip)
|
21
|
+
seed_binary.chars
|
22
|
+
.each_slice(11)
|
23
|
+
.map(&:join)
|
24
|
+
.map { |item| item.to_i(2) }
|
25
|
+
.map { |i| words_array[i] }
|
26
|
+
.join(' ')
|
18
27
|
end
|
19
28
|
|
20
29
|
def self.to_entropy(options)
|
21
30
|
options ||= {}
|
22
|
-
raise ArgumentError,
|
23
|
-
raise ArgumentError,
|
24
|
-
words_array = File.readlines(
|
25
|
-
|
31
|
+
raise ArgumentError, 'Mnemonic not set' if options[:mnemonic].nil?
|
32
|
+
raise ArgumentError, 'Mnemonic is empty' if options[:mnemonic].empty?
|
33
|
+
words_array = File.readlines(
|
34
|
+
File.join(
|
35
|
+
File.dirname(File.expand_path(__FILE__)), '../words/english.txt'
|
36
|
+
)
|
37
|
+
).map(&:strip)
|
38
|
+
mnemonic_array = options[:mnemonic].split(' ').map do |word|
|
26
39
|
word_index = words_array.index(word)
|
27
|
-
raise IndexError,
|
28
|
-
word_index.to_s(2).rjust(11,
|
40
|
+
raise IndexError, 'Word not found in words list' if word_index.nil?
|
41
|
+
word_index.to_s(2).rjust(11, '0')
|
29
42
|
end
|
30
43
|
mnemonic_binary_with_checksum = mnemonic_array.join.to_s
|
31
|
-
entropy_binary =
|
32
|
-
checksum_bits = mnemonic_binary_with_checksum.slice(-(entropy_binary.length/32),(entropy_binary.length/32))
|
33
|
-
|
34
|
-
|
35
|
-
else
|
36
|
-
raise SecurityError, "Checksum mismatch, invalid mnemonic"
|
37
|
-
end
|
44
|
+
entropy_binary =mnemonic_binary_with_checksum.slice(0, mnemonic_binary_with_checksum.length * 32 / 33)
|
45
|
+
checksum_bits = mnemonic_binary_with_checksum.slice(-(entropy_binary.length / 32), (entropy_binary.length / 32))
|
46
|
+
raise SecurityError, 'Checksum mismatch, invalid mnemonic' unless checksum(entropy_binary) == checksum_bits
|
47
|
+
[entropy_binary].pack('B*').unpack('H*').first
|
38
48
|
end
|
39
49
|
|
40
50
|
def self.checksum(entropy_binary)
|
41
|
-
sha256hash = OpenSSL::Digest::SHA256.hexdigest([entropy_binary].pack(
|
42
|
-
sha256hash_binary = [sha256hash].pack(
|
43
|
-
|
51
|
+
sha256hash = OpenSSL::Digest::SHA256.hexdigest([entropy_binary].pack('B*'))
|
52
|
+
sha256hash_binary = [sha256hash].pack('H*').unpack('B*').first
|
53
|
+
sha256hash_binary.slice(0, (entropy_binary.length / 32))
|
44
54
|
end
|
45
55
|
|
46
56
|
def self.to_seed(options)
|
47
|
-
raise ArgumentError,
|
48
|
-
|
57
|
+
raise ArgumentError, 'Mnemonic not set' if options[:mnemonic].nil?
|
58
|
+
OpenSSL::PKCS5.pbkdf2_hmac(
|
59
|
+
options[:mnemonic],
|
60
|
+
"mnemonic#{options[:password]}",
|
61
|
+
2048,
|
62
|
+
64,
|
63
|
+
OpenSSL::Digest::SHA512.new
|
64
|
+
).unpack('H*')[0]
|
49
65
|
end
|
50
|
-
|
51
66
|
end
|
metadata
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bip_mnemonic
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sreekanth GS
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-06-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: rdoc
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
@@ -25,7 +25,7 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: rspec
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
@@ -47,10 +47,10 @@ extensions: []
|
|
47
47
|
extra_rdoc_files: []
|
48
48
|
files:
|
49
49
|
- lib/bip_mnemonic.rb
|
50
|
-
- lib/pbkdf2.rb
|
51
50
|
- words/english.txt
|
52
51
|
homepage: http://github.com/sreekanthgs/mnemonic
|
53
|
-
licenses:
|
52
|
+
licenses:
|
53
|
+
- MIT
|
54
54
|
metadata: {}
|
55
55
|
post_install_message:
|
56
56
|
rdoc_options: []
|
@@ -67,8 +67,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
69
|
requirements: []
|
70
|
-
|
71
|
-
rubygems_version: 2.4.6
|
70
|
+
rubygems_version: 3.0.3
|
72
71
|
signing_key:
|
73
72
|
specification_version: 4
|
74
73
|
summary: BipMnemonic words and seed generator based on BIP-39
|
data/lib/pbkdf2.rb
DELETED
@@ -1,118 +0,0 @@
|
|
1
|
-
# THIS IS A MINIMALLY MODIFIED IMPLEMENTATION OF PBKDF2, ORIGINALLY IMPLEMENTED BY
|
2
|
-
# Sam Quigley. ORIGINAL IMPLEMENTATION AVAILABLE AT:
|
3
|
-
# https://github.com/emerose/pbkdf2-ruby
|
4
|
-
#
|
5
|
-
# Copyright (c) 2008 Sam Quigley <quigley@emerose.com>
|
6
|
-
#
|
7
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
8
|
-
# of this software and associated documentation files (the "Software"), to deal
|
9
|
-
# in the Software without restriction, including without limitation the rights
|
10
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11
|
-
# copies of the Software, and to permit persons to whom the Software is
|
12
|
-
# furnished to do so, subject to the following conditions:
|
13
|
-
#
|
14
|
-
# The above copyright notice and this permission notice shall be included in
|
15
|
-
# all copies or substantial portions of the Software.
|
16
|
-
#
|
17
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23
|
-
# THE SOFTWARE.
|
24
|
-
#
|
25
|
-
# This license is sometimes referred to as "The MIT License"
|
26
|
-
|
27
|
-
require 'openssl'
|
28
|
-
|
29
|
-
class PBKDF2
|
30
|
-
VERSION = "0.0.1"
|
31
|
-
def self.hex_string(options = {})
|
32
|
-
|
33
|
-
yield self if block_given?
|
34
|
-
|
35
|
-
# Raise errors for unset options, all are mandatory
|
36
|
-
raise ArgumentError, ":password is not set" if options[:password].nil?
|
37
|
-
raise ArgumentError, ":salt is not set" if options[:salt].nil?
|
38
|
-
raise ArgumentError, ":iterations is not set" if options[:iterations].nil?
|
39
|
-
raise ArgumentError, ":key_length is not set" if options[:key_length].nil?
|
40
|
-
raise ArgumentError, ":hash_function is not set" if options[:hash_function].nil?
|
41
|
-
|
42
|
-
options[:hash_function] = options[:hash_function].new
|
43
|
-
validate(options)
|
44
|
-
options[:key_length] = options[:key_length]/8
|
45
|
-
|
46
|
-
calculate!(options)
|
47
|
-
end
|
48
|
-
|
49
|
-
def self.validate(options)
|
50
|
-
raise ArgumentError, "Key is too short (< 1)" if options[:key_length] < 1
|
51
|
-
raise ArgumentError, "key is too long for hash function" if options[:key_length]/8 > ((2**32 - 1) * options[:hash_function].size)
|
52
|
-
raise ArgumentError, "iterations can't be less than 1" if options[:iterations] < 1
|
53
|
-
end
|
54
|
-
|
55
|
-
def self.prf(options, data)
|
56
|
-
OpenSSL::HMAC.digest(options[:hash_function], options[:password], data)
|
57
|
-
end
|
58
|
-
|
59
|
-
# this is a translation of the helper function "F" defined in the spec
|
60
|
-
def self.calculate_block(options, block_num)
|
61
|
-
# u_1:
|
62
|
-
u = prf(options, options[:salt]+[block_num].pack("N"))
|
63
|
-
ret = u
|
64
|
-
# u_2 through u_c:
|
65
|
-
2.upto(options[:iterations]) do
|
66
|
-
# calculate u_n
|
67
|
-
u = prf(options, u)
|
68
|
-
# xor it with the previous results
|
69
|
-
ret = ret^u
|
70
|
-
end
|
71
|
-
ret
|
72
|
-
end
|
73
|
-
|
74
|
-
# the bit that actually does the calculating
|
75
|
-
def self.calculate!(options)
|
76
|
-
# how many blocks we'll need to calculate (the last may be truncated)
|
77
|
-
blocks_needed = (options[:key_length].to_f / options[:hash_function].size).ceil
|
78
|
-
# reset
|
79
|
-
value = ""
|
80
|
-
# main block-calculating loop:
|
81
|
-
1.upto(blocks_needed) do |block_num|
|
82
|
-
value << calculate_block(options,block_num)
|
83
|
-
end
|
84
|
-
# truncate to desired length:
|
85
|
-
value = value.slice(0,options[:key_length]).unpack("H*").first
|
86
|
-
value
|
87
|
-
end
|
88
|
-
|
89
|
-
end
|
90
|
-
|
91
|
-
class String
|
92
|
-
if RUBY_VERSION >= "1.9"
|
93
|
-
def xor_impl(other)
|
94
|
-
result = "".encode("ASCII-8BIT")
|
95
|
-
o_bytes = other.bytes.to_a
|
96
|
-
bytes.each_with_index do |c, i|
|
97
|
-
result << (c ^ o_bytes[i])
|
98
|
-
end
|
99
|
-
result
|
100
|
-
end
|
101
|
-
else
|
102
|
-
def xor_impl(other)
|
103
|
-
result = (0..length-1).collect { |i| self[i] ^ other[i] }
|
104
|
-
result.pack("C*")
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
private :xor_impl
|
109
|
-
|
110
|
-
def ^(other)
|
111
|
-
raise ArgumentError, "Can't bitwise-XOR a String with a non-String" \
|
112
|
-
unless other.kind_of? String
|
113
|
-
raise ArgumentError, "Can't bitwise-XOR strings of different length" \
|
114
|
-
unless length == other.length
|
115
|
-
|
116
|
-
xor_impl(other)
|
117
|
-
end
|
118
|
-
end
|