Module: XRBP::Crypto

Defined in:
lib/xrbp/crypto.rb,
lib/xrbp/crypto/key.rb,
lib/xrbp/crypto/node.rb,
lib/xrbp/crypto/seed.rb,
lib/xrbp/crypto/account.rb,
lib/xrbp/crypto/validator.rb

Overview

The Crypto module defines methods to create XRPL compliant keys and subsequent entities (accounts, nodes, validators).

Defined Under Namespace

Modules: Key

Class Method Summary collapse

Class Method Details

.account(key = nil) ⇒ Hash

Generate a new XRPL account.

Parameters:

  • key (Symbol, Hash) (defaults to: nil)

    key type to generate or key itself (optional)

Returns:

  • (Hash)

    account details containing id and pub/priv key pair



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/xrbp/crypto/account.rb', line 9

def self.(key=nil)
  pub = nil
   = nil
  if key == :secp256k1 || key.nil?
    key = Key::secp256k1
    pub = key[:public]

  elsif key == :ed25519
    key = Key::ed25519
    pub = "\xED" + key[:public]

  elsif key.is_a?(Hash)
    if key[:account_id]
       = key[:account_id]
    elsif key[:public]
      pub = key[:public]
    end

  else
    pub = key
    key = {:public => pub}
  end

  raise "must specify pub or account_id" unless pub || 

      sha256 = OpenSSL::Digest::SHA256.new
   ripemd160 = OpenSSL::Digest::RIPEMD160.new
   = [Key::TOKEN_TYPES[:account_id]].pack("C") + ripemd160.digest(sha256.digest([pub].pack("H*"))) unless 
      chksum = sha256.digest(sha256.digest())[0..3]

  { :account => Base58.binary_to_base58(  + chksum, :ripple) }.merge(key)
end

.account?(account) ⇒ Boolean

Return boolean indicating if the specified account is valid

Returns:

  • (Boolean)


85
86
87
# File 'lib/xrbp/crypto/account.rb', line 85

def self.account?()
  () != nil
end

.account_id(account) ⇒ Object

Return the account id for the specified XRP account. This is a simpler version of parse_account that just returns the binary account, skipping the token and checksum verifications.



56
57
58
# File 'lib/xrbp/crypto/account.rb', line 56

def self.()
  Base58.base58_to_binary(, :ripple)[1..-5]
end

.no_accountObject



48
49
50
# File 'lib/xrbp/crypto/account.rb', line 48

def self.
  @no_account ||= (:account_id => ([0] * 20 + [1]).pack("C*"))[:account]
end

.node(key = nil) ⇒ Hash

Generate a new XRPL node.

Parameters:

  • key (Symbol, Hash) (defaults to: nil)

    key type to generate or key itself (optional)

Returns:

  • (Hash)

    node details containing id and pub/priv key pair



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/xrbp/crypto/node.rb', line 9

def self.node(key=nil)
  pub = nil
  if key == :secp256k1 || key.nil?
    key = Key::secp256k1
    pub = key[:public]

  elsif key.is_a?(Hash)
    key = Key::secp256k1(key[:seed]) if key[:seed]
    pub = key[:public]

  else
    pub = key
    key = {:public => pub}
  end

   sha256 = OpenSSL::Digest::SHA256.new
  node_id = [Key::TOKEN_TYPES[:node_public]].pack("C") + [pub].pack("H*")
   chksum = sha256.digest(sha256.digest(node_id))[0..3]

  { :node => Base58.binary_to_base58(node_id + chksum, :ripple) }.merge(key)
end

.node?(node) ⇒ Boolean

Return boolean indicating if the specified node is valid

Returns:

  • (Boolean)


56
57
58
# File 'lib/xrbp/crypto/node.rb', line 56

def self.node?(node)
  parse_node(node) != nil
end

.parse_account(account) ⇒ String?

Extract Account ID from Address.

Parameters:

  • account (String)

    Base58 encoded account address

Returns:

  • (String, nil)

    unique account id or nil if input if not an account



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/xrbp/crypto/account.rb', line 65

def self.()
  begin
    bin = Base58.base58_to_binary(, :ripple)
  rescue ArgumentError
    return nil
  end

  typ = bin[0]
  chk = bin[-4..-1]
  bin = bin[1...-4]

  return nil unless typ.unpack("C*").first == Key::TOKEN_TYPES[:account_id]

  sha256 = OpenSSL::Digest::SHA256.new
  return nil unless sha256.digest(sha256.digest(typ + bin))[0..3] == chk

  return bin
end

.parse_node(node) ⇒ String?

Extract Node ID from Address.

Parameters:

  • node (String)

    Base58 encoded node address

Returns:

  • (String, nil)

    unique node id or nil if input if not an node



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/xrbp/crypto/node.rb', line 36

def self.parse_node(node)
  begin
    bin = Base58.base58_to_binary(node, :ripple)
  rescue ArgumentError
    return nil
  end

  typ = bin[0]
  chk = bin[-4..-1]
  bin = bin[1...-4]

  return nil unless typ.unpack("C*").first == Key::TOKEN_TYPES[:node_public]

  sha256 = OpenSSL::Digest::SHA256.new
  return nil unless sha256.digest(sha256.digest(typ + bin))[0..3] == chk

  return bin
end

.parse_seed(seed) ⇒ String?

Extract Seed ID from Encoding.

Parameters:

  • seed (String)

    Base58 encoded seed

Returns:

  • (String, nil)

    extracted seed or nil if not valid



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/xrbp/crypto/seed.rb', line 36

def self.parse_seed(seed)
  bin = Base58.base58_to_binary(seed, :ripple)
  typ = bin[0]
  chk = bin[-4..-1]
  bin = bin[1...-4]

  # TODO also permit ED25519 prefix (?)
  return nil unless typ.unpack("C*").first == Key::TOKEN_TYPES[:family_seed]

  sha256 = OpenSSL::Digest::SHA256.new
  return nil unless sha256.digest(sha256.digest(typ + bin))[0..3] == chk

  return nil unless bin.size == 16

  return bin
end

.parse_validator(validator) ⇒ Object

Extract Validator ID from Address. Takes same params as parse_node



10
11
12
# File 'lib/xrbp/crypto/validator.rb', line 10

def self.parse_validator(validator)
  return parse_node(validator)
end

.seed(key = nil) ⇒ Hash

Generate a new XRPL seed.

Parameters:

  • key (Symbol) (defaults to: nil)

    key type to generate (optional)

Returns:

  • (Hash)

    seed details containing encoded seed and key type



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/xrbp/crypto/seed.rb', line 10

def self.seed(key=nil)
  prefix = nil
  if key == :secp256k1 || key.nil?
    prefix = [Key::TOKEN_TYPES[:family_seed]]
    key = { :type => :secp256k1 }

  elsif key == :ed25519
    prefix = [0x01, 0xE1, 0x4B]
    key = { :type => :ed25519 }

  else
    raise ArgumentError, key
  end

  sha256 = OpenSSL::Digest::SHA256.new
  base = SecureRandom.random_bytes(16)
  pref = (prefix + base.bytes).pack("C*")
  chk = sha256.digest(sha256.digest(pref))[0..3]
  { :seed => Base58.binary_to_base58(pref + chk, :ripple) }.merge(key)
end

.seed?(seed) ⇒ Boolean

Return boolean indicating if the specified seed is valid

Returns:

  • (Boolean)


54
55
56
# File 'lib/xrbp/crypto/seed.rb', line 54

def self.seed?(seed)
  parse_seed(seed) != nil
end

.validator(key = nil) ⇒ Object

Generate a new XRPL validator. Takes same params as node



4
5
6
# File 'lib/xrbp/crypto/validator.rb', line 4

def self.validator(key=nil)
  return node(key)
end

.validator?(validator) ⇒ Boolean

Return bool indicating if Validator is valid. Takes same params as node?

Returns:

  • (Boolean)


16
17
18
# File 'lib/xrbp/crypto/validator.rb', line 16

def self.validator?(validator)
  return node?(validator)
end

.xrp_accountObject



43
44
45
# File 'lib/xrbp/crypto/account.rb', line 43

def self.
  @xrp_account ||= (:account_id => ([0] * 21).pack("C*"))[:account]
end