module HDetEc::ECManipulation

Public Instance Methods

CKD(extended_key, index)
CKDh(extended_key, index)
CKDpriv(extended_key, index)
CKDpub(extended_key, index)
child_key_derivation(extended_key, index) click to toggle source

@abstract Generic derivation method for non-hardened keys

Alogrithm to derive public and private key if it not hardened key. That means no {#index} above 2^31 - 1 are allowed.

# File lib/hdet-ec-key/ec_manipulation.rb, line 57
def child_key_derivation(extended_key, index)
  k, c = extended_key
  key = c
  data = serp(k) + ser32(index)
  OpenSSL::HMAC.digest('SHA512', key, data)
end
Also aliased as: CKD
child_key_derivation_hardened(extended_key, index) click to toggle source

@abstract Generic derivation method for hardened keys

Alogrithm to derive only hardened private key. That means no {#index} below 2^31 are allowed.

# File lib/hdet-ec-key/ec_manipulation.rb, line 44
def child_key_derivation_hardened(extended_key, index)
  k, c = extended_key
  key = c
  data = "\x00" + k + ser32(index)
  OpenSSL::HMAC.digest('SHA512', key, data)
end
Also aliased as: CKDh
child_key_derivation_private(extended_key, index) click to toggle source

@abstract Derive a public key according to BIP32 specifications

Public parent key → public child key.

@param extended_key [Array] extended_key @param index [Integer]

@note

https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#private-parent-key--private-child-key
# File lib/hdet-ec-key/ec_manipulation.rb, line 75
def child_key_derivation_private(extended_key, index)
  k, c = extended_key

  if index >= 2**31
    inter = child_key_derivation_hardened(extended_key, index)
  else
    inter = child_key_derivation([point(k), c], index)
  end

  iL, iR = split_hash(inter)

  bn = parse256(iL) + parse256(k)
  k_child = OpenSSL::BN.new(bn) % group.order

  [k_child.to_s(2), iR]
end
Also aliased as: CKDpriv
child_key_derivation_public(extended_key, index) click to toggle source

@abstract Derive a public key according to BIP32 specifications

Public parent key → public child key.

@param extended_key [Array] extended_key @param index [Integer]

@note

https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#public-parent-key--public-child-key
# File lib/hdet-ec-key/ec_manipulation.rb, line 104
def child_key_derivation_public(extended_key, index)
  k, c = extended_key
  if index >= 2**31
    raise "No hardened public key derivation possible"
  end

  inter = child_key_derivation(extended_key, index)

  iL, iR = split_hash(inter)

  bn = OpenSSL::BN.new(iL, 2)
  pub_key = OpenSSL::PKey::EC::Point.new(group, k).mul(1, bn)
  [pub_key.to_octet_string(:compressed), iR]
end
Also aliased as: CKDpub
generate_public_key_from_private(private_key) click to toggle source

@abstract Generate public key from the private one

The input parameter {#private_key} a binary string representation of the private key

@return [String] The output is a binary representation of the public key

in the compressed form.
# File lib/hdet-ec-key/ec_manipulation.rb, line 31
def generate_public_key_from_private(private_key)
  bn_private_key = OpenSSL::BN.new private_key, 2

  public_key = group.generator.mul(bn_private_key)
  public_key.to_bn.to_s(2)
end
Also aliased as: point
group() click to toggle source
# File lib/hdet-ec-key/ec_manipulation.rb, line 18
def group
  @@group ||= OpenSSL::PKey::EC.new("secp256k1").group
  @@group.point_conversion_form = :compressed
  @@group
end
group=(openssl_group) click to toggle source

The default group is the same as used by Bitcoin network, “secp256k1”. But it can be change, just provide the a OpenSSL group string.

example:

HDetEc::Key.group = "secp256r1"
# File lib/hdet-ec-key/ec_manipulation.rb, line 12
def group=(openssl_group)
  @@group = OpenSSL::PKey::EC.new(openssl_group).group
  @@group.point_conversion_form = :compressed
  @@group
end
point(private_key)
serp(kp) click to toggle source

Serializes the coordinate pair P = (x,y) as a byte sequence using SEC1's compressed form: (0x02 or 0x03) || ser256(x), where the header byte depends on the parity of the omitted y coordinate. input kp: public key

# File lib/hdet-ec-key/ec_manipulation.rb, line 125
def serp(kp)
  # ensure kp is in compressed form
  point = OpenSSL::PKey::EC::Point.new(group, kp)
  point.to_octet_string(:compressed)
end