Module: MoneroWalletGen

Defined in:
lib/monero_wallet_gen/ed25519.rb,
lib/monero_wallet_gen.rb,
lib/monero_wallet_gen/base58.rb,
lib/monero_wallet_gen/version.rb

Overview

This is a port of the pure-python implementation of Ed25519 ed25519.cr.yp.to/software.html

Defined Under Namespace

Modules: Base58, Ed25519

Constant Summary collapse

NETBYTE_STANDARD =
'12'
NETBYTE_TESTNET =
'35'
VERSION =
"0.1.0"

Class Method Summary collapse

Class Method Details

.cn_fast_hash(hex) ⇒ Object



117
118
119
120
# File 'lib/monero_wallet_gen.rb', line 117

def self.cn_fast_hash(hex)
  bin = hex_to_bin(hex)
  Digest::SHA3.hexdigest(bin, 256)
end

.generate(testnet: false) ⇒ Object



12
13
14
15
# File 'lib/monero_wallet_gen.rb', line 12

def self.generate(testnet: false)
  hex = sc_reduce32(mn_random)
  generate_from_private_key(hex, testnet: testnet)
end

.generate_from_private_key(hex, testnet: false) ⇒ Object



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/monero_wallet_gen.rb', line 17

def self.generate_from_private_key(hex, testnet: false)
  mn = mn_encode(hex)
  priv_spend_key = hex
  priv_view_key = sc_reduce32(cn_fast_hash(hex))
  pub_spend_key = priv_key_to_pub(priv_spend_key)
  pub_view_key = priv_key_to_pub(priv_view_key)
  netbyte = testnet ? NETBYTE_TESTNET : NETBYTE_STANDARD
  address = get_public_address(netbyte, pub_spend_key, pub_view_key)

  {
    priv_spend_key: priv_spend_key,
    priv_view_key: priv_view_key,
    pub_spend_key: pub_spend_key,
    pub_view_key: pub_view_key,
    address: address,
    mnemonic: mn
  }
end

.get_public_address(netbyte, pub_spend_key, pub_view_key, pid = '') ⇒ Object



127
128
129
130
131
132
# File 'lib/monero_wallet_gen.rb', line 127

def self.get_public_address(netbyte, pub_spend_key, pub_view_key, pid = '')
  pre_address = netbyte + pub_spend_key + pub_view_key
  hashed = cn_fast_hash(pre_address)
  hex_address = pre_address + hashed[0..7]
  Base58::encode(hex_address)
end

.hex_to_bin(hex) ⇒ Object



108
109
110
111
112
113
114
115
# File 'lib/monero_wallet_gen.rb', line 108

def self.hex_to_bin(hex)
  output = []
  (0..hex.length-1).step(2) do |i|
    substr = hex[i..i+1]
    output << substr.to_i(16)
  end
  output.pack('C*')
end

.hex_to_int(hex) ⇒ Object



45
46
47
48
# File 'lib/monero_wallet_gen.rb', line 45

def self.hex_to_int(hex)
  le_hex = little_endian(hex)
  le_hex.to_i(16)
end

.int_to_hex(n) ⇒ Object



50
51
52
53
# File 'lib/monero_wallet_gen.rb', line 50

def self.int_to_hex(n)
  be_hex = n.to_s(16).rjust(64, '0')
  little_endian(be_hex)
end

.little_endian(str) ⇒ Object



36
37
38
39
40
41
42
43
# File 'lib/monero_wallet_gen.rb', line 36

def self.little_endian(str)
  output = []
  (0..str.length).step(2) do |i|
    substr = str[i..i+1]
    output << substr
  end
  output.reverse.join
end

.mn_encode(message) ⇒ Object



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/monero_wallet_gen.rb', line 78

def self.mn_encode(message)
  n = WORDS.length

  (0..message.length-1).step(8) do |i|
    if i == 0
      message = little_endian(message[i..i+7]) + message[i+8..-1]
    else
      message = message[0..i-1] + little_endian(message[i..i+7]) + message[i+8..-1]
    end
  end

  words = []
  limit = message.length / 8 - 1
  (0..limit).to_a.each do |i|
    word = message[8*i..8*i+7]
    x = word.to_i(16)
    w1 = (x % n)
    w2 = ((x / n).to_i + w1) % n
    w3 = (((x / n) / n).to_i + w2) % n

    words += [ WORDS[w1], WORDS[w2], WORDS[w3] ]
  end

  trimmed_words = words.map { |word| word[0..2] }.join
  checksum = Zlib.crc32(trimmed_words)
  checkword = words[checksum % words.length]
  words << checkword
  words.join(' ')
end

.mn_randomObject



68
69
70
71
72
73
74
75
76
# File 'lib/monero_wallet_gen.rb', line 68

def self.mn_random
  # Generate array of random integers
  array = 8.times.map { random_integer_digits(10) }

  # Convert to 8-bit hex
  array.map do |n|
    ('0000000' + n.to_s(16))[-8..-1]
  end.join
end

.priv_key_to_pub(hex) ⇒ Object



122
123
124
125
# File 'lib/monero_wallet_gen.rb', line 122

def self.priv_key_to_pub(hex)
  point = Ed25519::scalarmultbase(hex_to_int(hex))
  Ed25519::encode_point(point).unpack('H*').first.to_s
end

.random_integer_digits(digits) ⇒ Object



64
65
66
# File 'lib/monero_wallet_gen.rb', line 64

def self.random_integer_digits(digits)
  digits.times.map{ rand(10) }.join.to_i
end

.sc_reduce32(hex) ⇒ Object

Takes a 32-byte integer and outputs the integer modulo q. Same code as above, except skipping the 64→32 byte step.



57
58
59
60
61
62
# File 'lib/monero_wallet_gen.rb', line 57

def self.sc_reduce32(hex)
  l = 2**252 + 27742317777372353535851937790883648493
  n = hex_to_int(hex)
  reduced = (n % l)
  int_to_hex(reduced)
end