defmodule BitcoinLib.Signing.Psbt.GenericProperties.Bip32Derivation do defstruct [:pub_key, :master_key_fingerprint, :derivation_path] @compressed_pub_key_size 33 @uncompressed_pub_key_size 65 alias BitcoinLib.Signing.Psbt.Keypair alias BitcoinLib.Signing.Psbt.Keypair.{Key, Value} alias BitcoinLib.Signing.Psbt.GenericProperties.Bip32Derivation alias BitcoinLib.Key.PublicKey alias BitcoinLib.Key.HD.DerivationPath # TODO: document def parse(%Keypair{key: %Key{data: binary_pub_key}, value: %Value{data: remaining}}) do {master_key_fingerprint, remaining} = extract_master_key_fingerprint(remaining) {derivation_path, _remaining} = extract_derivation_path(remaining, []) %Bip32Derivation{ pub_key: %PublicKey{key: binary_pub_key}, master_key_fingerprint: master_key_fingerprint, derivation_path: DerivationPath.from_list(["m" | derivation_path]) } |> validate_pub_key() end defp extract_master_key_fingerprint(<>) do {fingerprint, remaining} end defp extract_derivation_path(<<>> = remaining, path) do {Enum.reverse(path), remaining} end defp extract_derivation_path(<>, path) do extract_derivation_path(remaining, [level | path]) end defp validate_pub_key(%Bip32Derivation{pub_key: pub_key} = bip32_derivation) do case byte_size(pub_key.key) do @compressed_pub_key_size -> bip32_derivation @uncompressed_pub_key_size -> bip32_derivation wrong_size -> bip32_derivation |> Map.put(:error, "wrong pub key size, which is #{wrong_size} in hex format") end end end defimpl Inspect, for: BitcoinLib.Signing.Psbt.GenericProperties.Bip32Derivation do alias BitcoinLib.Signing.Psbt.GenericProperties.Bip32Derivation alias BitcoinLib.Formatting.HexBinary def inspect(%Bip32Derivation{} = bip32_derivation, opts) do %{ bip32_derivation | master_key_fingerprint: %HexBinary{data: bip32_derivation.master_key_fingerprint} } |> Inspect.Any.inspect(opts) end end