Module: TezosClient::Crypto

Included in:
TezosClient, OperationMgr, RpcInterface
Defined in:
lib/tezos_client/crypto.rb

Constant Summary collapse

PREFIXES =
{
  tz1:    [6, 161, 159],
  tz2:    [6, 161, 161],
  tz3:    [6, 161, 164],
  KT:     [2, 90, 121],
  expr:   [13, 44, 64, 27],
  edpk:   [13, 15, 37, 217],
  edsk2:  [13, 15, 58, 7],
  spsk:   [17, 162, 224, 201],
  p2sk:   [16, 81, 238, 189],
  sppk:   [3, 254, 226, 86],
  p2pk:   [3, 178, 139, 127],
  edsk:   [43, 246, 78, 7],
  edsig:  [9, 245, 205, 134, 18],
  spsig1: [13, 115, 101, 19, 63],
  p2sig:  [54, 240, 44, 52],
  sig:    [4, 130, 43],
  Net:    [87, 82, 0],
  nce:    [69, 220, 169],
  b:      [1, 52],
  o:      [5, 116],
  Lo:     [133, 233],
  LLo:    [29, 159, 109],
  P:      [2, 170],
  Co:     [79, 179],
  id:     [153, 103]
}.freeze
WATERMARK =
{
  block: "01",
  endorsement: "02",
  generic: "03"
}.freeze

Instance Method Summary collapse

Instance Method Details

#checksum(hex) ⇒ Object



61
62
63
64
# File 'lib/tezos_client/crypto.rb', line 61

def checksum(hex)
  b = hex.to_bin
  Digest::SHA256.hexdigest(Digest::SHA256.digest(b))[0...8]
end

#decode_account_wallet(wallet) ⇒ Object



191
192
193
194
195
196
197
198
# File 'lib/tezos_client/crypto.rb', line 191

def (wallet)
  wallet_config = JSON.load(wallet).with_indifferent_access

  mnemonic = wallet_config[:mnemonic].join(" ")
  password = "#{wallet_config[:email]}#{wallet_config[:password]}"
  key = generate_key(mnemonic: mnemonic, password: password)
  key.merge(activation_secret: wallet_config[:secret])
end

#decode_base58(base58_val) ⇒ Object



51
52
53
54
# File 'lib/tezos_client/crypto.rb', line 51

def decode_base58(base58_val)
  bin_val = Base58.base58_to_binary(base58_val, :bitcoin)
  bin_val.to_hex
end

#decode_tz(str) {|prefix, payload| ... } ⇒ Object

Yields:

  • (prefix, payload)


74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/tezos_client/crypto.rb', line 74

def decode_tz(str)
  decoded = decode_base58 str

  unless checksum(decoded[0...-8]) != decoded[0...-8]
    raise "invalid checksum for #{str}"
  end

  prefix, payload = get_prefix_and_payload(decoded[0...-8])

  yield(prefix, payload) if block_given?

  payload
end

#edsk2_to_edsk(edsk2key) ⇒ Object



128
129
130
131
132
# File 'lib/tezos_client/crypto.rb', line 128

def edsk2_to_edsk(edsk2key)
  signing_key = signing_key(edsk2key)
  keypair_hex = signing_key.keypair_bytes.to_hex
  encode_tz(:edsk, keypair_hex)
end

#encode_base58(hex_val) ⇒ Object



56
57
58
59
# File 'lib/tezos_client/crypto.rb', line 56

def encode_base58(hex_val)
  bin_val = hex_val.to_bin
  Base58.binary_to_base58(bin_val, :bitcoin)
end

#encode_script_expr(data:, type:) ⇒ Object



200
201
202
203
204
# File 'lib/tezos_client/crypto.rb', line 200

def encode_script_expr(data:, type:)
  packed_key = pack_data(data: data, type: type)
  raw_expr_key = RbNaCl::Hash::Blake2b.digest(packed_key["packed"].to_bin, digest_size: 32).to_hex
  encode_tz(:expr, raw_expr_key)
end

#encode_tz(prefix, str) ⇒ Object



88
89
90
91
92
93
# File 'lib/tezos_client/crypto.rb', line 88

def encode_tz(prefix, str)
  prefixed = hex_prefix(prefix) + str
  checksum = checksum(prefixed)

  encode_base58(prefixed + checksum)
end

#generate_key(mnemonic: nil, password: nil, wallet_seed: nil, path: nil) ⇒ Object



113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/tezos_client/crypto.rb', line 113

def generate_key(mnemonic: nil, password: nil, wallet_seed: nil, path: nil)
  signing_key = generate_signing_key(mnemonic: mnemonic, password: password, wallet_seed: wallet_seed, path: path).to_bytes.to_hex

  secret_key = encode_tz(:edsk2, signing_key)
  public_key = secret_key_to_public_key(secret_key)
  address = public_key_to_address(public_key)

  {
    secret_key: secret_key,
    public_key: public_key,
    address: address,
    path: path
  }
end

#generate_mnemonicObject



134
135
136
# File 'lib/tezos_client/crypto.rb', line 134

def generate_mnemonic
  BipMnemonic.to_mnemonic(nil)
end

#get_prefix_and_payload(str) ⇒ Object



66
67
68
69
70
71
72
# File 'lib/tezos_client/crypto.rb', line 66

def get_prefix_and_payload(str)
  PREFIXES.keys.each do |prefix|
    if str.start_with? hex_prefix(prefix)
      return prefix, str[(hex_prefix(prefix).size) .. -1]
    end
  end
end

#hex_prefix(type) ⇒ Object



47
48
49
# File 'lib/tezos_client/crypto.rb', line 47

def hex_prefix(type)
  PREFIXES[type].pack("C*").to_hex
end

#operation_id(signed_operation_hex) ⇒ Object



168
169
170
171
172
173
174
# File 'lib/tezos_client/crypto.rb', line 168

def operation_id(signed_operation_hex)
  hash = RbNaCl::Hash::Blake2b.digest(
    signed_operation_hex.to_bin,
    digest_size: 32
  )
  encode_tz(:o, hash.to_hex)
end

#public_key_to_address(public_key) ⇒ Object



102
103
104
105
106
107
108
109
110
111
# File 'lib/tezos_client/crypto.rb', line 102

def public_key_to_address(public_key)
  hex_public_key = decode_tz(public_key) do |type, _key|
    raise "invalid public key: #{public_key} " unless type == :edpk
  end

  hash = RbNaCl::Hash::Blake2b.digest(hex_public_key.to_bin, digest_size: 20)
  hex_hash = hash.to_hex

  encode_tz(:tz1, hex_hash)
end

#secret_key_to_public_key(secret_key) ⇒ Object



95
96
97
98
99
100
# File 'lib/tezos_client/crypto.rb', line 95

def secret_key_to_public_key(secret_key)
  signing_key = signing_key(secret_key)
  verify_key = signing_key.verify_key
  hex_pubkey = verify_key.to_s.to_hex
  encode_tz(:edpk, hex_pubkey)
end

#sign_bytes(secret_key:, data:, watermark: nil) ⇒ Object



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/tezos_client/crypto.rb', line 146

def sign_bytes(secret_key:, data:, watermark: nil)
  watermarked_data = if watermark.nil?
    data
  else
    WATERMARK[watermark] + data
  end

  hash = RbNaCl::Hash::Blake2b.digest(watermarked_data.to_bin, digest_size: 32)

  signing_key = signing_key(secret_key)
  bin_signature = signing_key.sign(hash)

  edsig = encode_tz(:edsig, bin_signature.to_hex)
  signed_data = data + bin_signature.to_hex

  if block_given?
    yield(edsig, signed_data)
  else
    edsig
  end
end

#sign_operation(secret_key:, operation_hex:) ⇒ Object



177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/tezos_client/crypto.rb', line 177

def sign_operation(secret_key:, operation_hex:)
  sign_bytes(secret_key: secret_key,
             data: operation_hex,
             watermark: :generic) do |edsig, signed_data|
    op_id = operation_id(signed_data)

    if block_given?
      yield(edsig, signed_data, op_id)
    else
      edsig
    end
  end
end

#signing_key(secret_key) ⇒ Object



138
139
140
141
142
143
144
# File 'lib/tezos_client/crypto.rb', line 138

def signing_key(secret_key)
  secret_key = decode_tz(secret_key) do |type, _key|
    raise "invalid secret key: #{secret_key} " unless [:edsk, :edsk2].include? type
  end

  RbNaCl::SigningKey.new(secret_key.to_bin[0..31])
end