Pro Yearly is on sale from $80 to $50! »

Get Paid in Bitcoin

Get Paid in Bitcoin

A presentation about using Elixir to generate a Bitcoin Address from a private key, with the help of external Python and C++ Bitcoin libraries.

Presented at the Elixir Sydney meetup on 7 Feb 2018.

Presentation slide deck markdown and speaker notes (useable in Deckset):
https://github.com/paulfioravanti/presentations/tree/master/get_paid_in_bitcoin

Abda861707b1e78e0fce47ced55f84ee?s=128

Paul Fioravanti

February 07, 2018
Tweet

Transcript

  1. Get P id in @paulfioravanti 1/149

  2. None
  3. None
  4. None
  5. None
  6. None
  7. None
  8. @paulfioravanti 8/149

  9. ExCrypto https://github.com/ntrepid8/ex_crypto @paulfioravanti 9/149

  10. ExCrypto https://github.com/ntrepid8/ex_crypto RSA Ex https://github.com/anoskov/rsa-ex @paulfioravanti 10/149

  11. @paulfioravanti 11/149

  12. ut

  13. Generate Bitcoin Address @paulfioravanti 13/149

  14. We need: A private key @paulfioravanti 14/149

  15. We need: Bitcoin public key (from private key) @paulfioravanti 15/149

  16. We need: Bitcoin address (from Bitcoin public key) @paulfioravanti 16/149

  17. Checklist - Private Key - Bitcoin Public Key - Bitcoin

    Address @paulfioravanti 17/149
  18. None
  19. Checklist - Private Key ✅ - Bitcoin Public Key -

    Bitcoin Address @paulfioravanti 19/149
  20. Bitcoin Public Key @paulfioravanti 20/149

  21. Elliptic Curve Digital Signature Algorithm @paulfioravanti 21/149

  22. Elliptic Curve Digital Signature Algorithm @paulfioravanti 22/149

  23. ECDSA secp256k1 @paulfioravanti

  24. ECDSA secp256k1 {x,y} coordinate on the Elliptic Curve @paulfioravanti

  25. Anyway... @paulfioravanti 25/149

  26. @paulfioravanti 26/149

  27. bitcoin-elixir — h!ps://github.com/comboy/bitcoin-elixir @paulfioravanti 27/149

  28. bitcoin-elixir — h!ps://github.com/comboy/bitcoin-elixir Bitcoin-Ex — h!ps://github.com/justinlynn/bitcoin-ex @paulfioravanti 28/149

  29. ut

  30. Checklist - Private Key ✅ - Bitcoin Public Key -

    Bitcoin Address @paulfioravanti 30/149
  31. NOW WHAT? @paulfioravanti 31/149

  32. NOPE! @paulfioravanti 32/149

  33. ut

  34. @paulfioravanti 34/149

  35. 35/149

  36. @paulfioravanti 36/149

  37. @paulfioravanti 37/149

  38. @paulfioravanti 38/149

  39. New project! $ mix new bitcoin_address $ cd bitcoin_address $

    mix deps.get @paulfioravanti 39/149
  40. Pybitcointools — h!ps://github.com/vbuterin/pybitcointools $ pip install bitcoin @paulfioravanti 40/149

  41. Python Code priv/bitcoin_address.py @paulfioravanti 41/149

  42. bitcoin_address.py import bitcoin def create_bitcoin_public_key(private_key): decoded_private_key = bitcoin.decode_privkey(private_key, "hex") public_key

    = bitcoin.fast_multiply(bitcoin.G, decoded_private_key) (public_key_x, public_key_y) = public_key compressed_prefix = "02" if (public_key_y % 2) == 0 else "03" return compressed_prefix + bitcoin.encode(public_key_x, 16, 64) @paulfioravanti 42/149
  43. bitcoin_address.py import bitcoin def create_bitcoin_public_key(private_key): decoded_private_key = bitcoin.decode_privkey(private_key, "hex") public_key

    = bitcoin.fast_multiply(bitcoin.G, decoded_private_key) (public_key_x, public_key_y) = public_key compressed_prefix = "02" if (public_key_y % 2) == 0 else "03" return compressed_prefix + bitcoin.encode(public_key_x, 16, 64) @paulfioravanti 43/149
  44. bitcoin_address.py import bitcoin def create_bitcoin_public_key(private_key): decoded_private_key = bitcoin.decode_privkey(private_key, "hex") public_key

    = bitcoin.fast_multiply(bitcoin.G, decoded_private_key) (public_key_x, public_key_y) = public_key compressed_prefix = "02" if (public_key_y % 2) == 0 else "03" return compressed_prefix + bitcoin.encode(public_key_x, 16, 64) @paulfioravanti 44/149
  45. bitcoin_address.py import bitcoin def create_bitcoin_public_key(private_key): decoded_private_key = bitcoin.decode_privkey(private_key, "hex") public_key

    = bitcoin.fast_multiply(bitcoin.G, decoded_private_key) (public_key_x, public_key_y) = public_key compressed_prefix = "02" if (public_key_y % 2) == 0 else "03" return compressed_prefix + bitcoin.encode(public_key_x, 16, 64) @paulfioravanti 45/149
  46. bitcoin_address.py import bitcoin def create_bitcoin_public_key(private_key): decoded_private_key = bitcoin.decode_privkey(private_key, "hex") public_key

    = bitcoin.fast_multiply(bitcoin.G, decoded_private_key) (public_key_x, public_key_y) = public_key compressed_prefix = "02" if (public_key_y % 2) == 0 else "03" return compressed_prefix + bitcoin.encode(public_key_x, 16, 64) @paulfioravanti 46/149
  47. bitcoin_address.py import bitcoin def create_bitcoin_public_key(private_key): decoded_private_key = bitcoin.decode_privkey(private_key, "hex") public_key

    = bitcoin.fast_multiply(bitcoin.G, decoded_private_key) (public_key_x, public_key_y) = public_key compressed_prefix = "02" if (public_key_y % 2) == 0 else "03" return compressed_prefix + bitcoin.encode(public_key_x, 16, 64) @paulfioravanti 47/149
  48. bitcoin_address.py import bitcoin def create_bitcoin_public_key(private_key): decoded_private_key = bitcoin.decode_privkey(private_key, "hex") public_key

    = bitcoin.fast_multiply(bitcoin.G, decoded_private_key) (public_key_x, public_key_y) = public_key compressed_prefix = "02" if (public_key_y % 2) == 0 else "03" return compressed_prefix + bitcoin.encode(public_key_x, 16, 64) @paulfioravanti 48/149
  49. Export — h!ps://github.com/fazibear/ export @paulfioravanti 49/149

  50. Erlport — h!ps://github.com/hdima/ erlport @paulfioravanti 50/149

  51. @paulfioravanti 51/149

  52. Install defp deps do [ # Erlport wrapper for Elixir

    to interface with Python code {:export, "~> 0.1.0"} ] end @paulfioravanti 52/149
  53. defmodule BitcoinAddress.Python do use Export.Python @python_path :bitcoin_address |> :code.priv_dir() |>

    Path.basename() @python_file "bitcoin_address" def generate(private_key) do with {:ok, pid} <- Python.start(python_path: @python_path), bitcoin_public_key <- create_bitcoin_public_key(pid, private_key) do IO.puts("Private key: #{inspect(private_key)}") IO.puts("Public key: #{inspect(bitcoin_public_key)}") Python.stop(pid) end end defp create_bitcoin_public_key(pid, private_key) do pid |> Python.call(@python_file, "create_bitcoin_public_key", [private_key]) |> to_string() end end @paulfioravanti 53/149
  54. defmodule BitcoinAddress.Python do use Export.Python @python_path :bitcoin_address |> :code.priv_dir() |>

    Path.basename() @python_file "bitcoin_address" # ... end @paulfioravanti 54/149
  55. defmodule BitcoinAddress.Python do use Export.Python @python_path :bitcoin_address |> :code.priv_dir() |>

    Path.basename() @python_file "bitcoin_address" # ... end @paulfioravanti 55/149
  56. defmodule BitcoinAddress.Python do use Export.Python @python_path :bitcoin_address |> :code.priv_dir() |>

    Path.basename() @python_file "bitcoin_address" # ... end @paulfioravanti 56/149
  57. defmodule BitcoinAddress.Python do # ... def generate(private_key) do with {:ok,

    pid} <- Python.start(python_path: @python_path), bitcoin_public_key <- create_bitcoin_public_key(pid, private_key) do # ... Python.stop(pid) end end # ... end @paulfioravanti 57/149
  58. defmodule BitcoinAddress.Python do # ... def generate(private_key) do with {:ok,

    pid} <- Python.start(python_path: @python_path), bitcoin_public_key <- create_bitcoin_public_key(pid, private_key) do # ... Python.stop(pid) end end # ... end @paulfioravanti 58/149
  59. defmodule BitcoinAddress.Python do # ... def generate(private_key) do with {:ok,

    pid} <- Python.start(python_path: @python_path), bitcoin_public_key <- create_bitcoin_public_key(pid, private_key) do # ... Python.stop(pid) end end # ... end @paulfioravanti 59/149
  60. defmodule BitcoinAddress.Python do # ... def generate(private_key) do with {:ok,

    pid} <- Python.start(python_path: @python_path), bitcoin_public_key <- create_bitcoin_public_key(pid, private_key) do # ... Python.stop(pid) end end defp create_bitcoin_public_key(pid, priv_key) do pid |> Python.call(@python_file, "create_bitcoin_public_key", [priv_key]) |> to_string() end end @paulfioravanti 60/149
  61. defmodule BitcoinAddress.Python do # ... def generate(private_key) do with {:ok,

    pid} <- Python.start(python_path: @python_path), bitcoin_public_key <- create_bitcoin_public_key(pid, private_key) do IO.puts("Private key: #{inspect(private_key)}") IO.puts("Public key: #{inspect(bitcoin_public_key)}") Python.stop(pid) end end defp create_bitcoin_public_key(pid, priv_key) do # ... end end @paulfioravanti 61/149
  62. defmodule BitcoinAddress.Python do use Export.Python @python_path :bitcoin_address |> :code.priv_dir() |>

    Path.basename() @python_file "bitcoin_address" def generate(private_key) do with {:ok, pid} <- Python.start(python_path: @python_path), bitcoin_public_key <- create_bitcoin_public_key(pid, private_key) do IO.puts("Private key: #{inspect(private_key)}") IO.puts("Public key: #{inspect(bitcoin_public_key)}") Python.stop(pid) end end defp create_bitcoin_public_key(pid, priv_key) do pid |> Python.call(@python_file, "create_bitcoin_public_key", [priv_key]) |> to_string() end end @paulfioravanti 62/149
  63. Checklist - Private Key ✅ - Bitcoin Public Key -

    Bitcoin Address @paulfioravanti 63/149
  64. bitcoin.pubkey_to_address @paulfioravanti 64/149

  65. defmodule BitcoinAddress.Python do # ... def generate(private_key) do with {:ok,

    pid} <- Python.start(python_path: @python_path), bitcoin_public_key <- create_bitcoin_public_key(pid, private_key), bitcoin_address <- create_bitcoin_address(pid, bitcoin_public_key) do # ... end end defp create_bitcoin_address(pid, pub_key) do pid |> Python.call(@python_file, "bitcoin.pubkey_to_address", [pub_key]) |> to_string() end end @paulfioravanti 65/149
  66. defmodule BitcoinAddress.Python do # ... def generate(private_key) do with {:ok,

    pid} <- Python.start(python_path: @python_path), bitcoin_public_key <- create_bitcoin_public_key(pid, private_key), bitcoin_address <- create_bitcoin_address(pid, bitcoin_public_key) do # ... end end defp create_bitcoin_address(pid, pub_key) do pid |> Python.call(@python_file, "bitcoin.pubkey_to_address", [pub_key]) |> to_string() end end @paulfioravanti 66/149
  67. defp create_bitcoin_public_key(pid, priv_key) do pid |> Python.call(@python_file, "create_bitcoin_public_key", [priv_key]) |>

    to_string() end defp create_bitcoin_address(pid, pub_key) do pid |> Python.call(@python_file, "bitcoin.pubkey_to_address", [pub_key]) |> to_string() end @paulfioravanti 67/149
  68. defp create_bitcoin_public_key(pid, priv_key) do pid |> Python.call(@python_file, "create_bitcoin_public_key", [priv_key]) |>

    to_string() end defp create_bitcoin_address(pid, pub_key) do pid |> Python.call(@python_file, "bitcoin.pubkey_to_address", [pub_key]) |> to_string() end @paulfioravanti 68/149
  69. defmodule BitcoinAddress.Python do # ... def generate(private_key) do with {:ok,

    pid} <- Python.start(python_path: @python_path), bitcoin_public_key <- create_bitcoin_public_key(pid, private_key), bitcoin_address <- create_bitcoin_address(pid, bitcoin_public_key) do IO.puts("Private key: #{inspect(private_key)}") IO.puts("Public key: #{inspect(bitcoin_public_key)}") IO.puts("Bitcoin address: #{inspect(bitcoin_address)}") Python.stop(pid) end end defp create_bitcoin_address(pid, pub_key) do pid |> Python.call(@python_file, "bitcoin.pubkey_to_address", [pub_key]) |> to_string() end end @paulfioravanti 69/149
  70. defmodule BitcoinAddress.Python do use Export.Python @python_path :bitcoin_address |> :code.priv_dir() |>

    Path.basename() @python_file "bitcoin_address" def generate(private_key) do with {:ok, pid} <- Python.start(python_path: @python_path), bitcoin_public_key <- create_bitcoin_public_key(pid, private_key), bitcoin_address <- create_bitcoin_address(pid, bitcoin_public_key) do IO.puts("Private key: #{inspect(private_key)}") IO.puts("Public key: #{inspect(bitcoin_public_key)}") IO.puts("Bitcoin address: #{inspect(bitcoin_address)}") Python.stop(pid) end end defp create_bitcoin_public_key(pid, priv_key) do call_python(pid, "create_bitcoin_public_key", [priv_key]) end defp create_bitcoin_address(pid, pub_key) do call_python(pid, "bitcoin.pubkey_to_address", [pub_key]) end defp call_python(pid, function, args) do pid |> Python.call(@python_file, function, args) |> to_string() end end @paulfioravanti 70/149
  71. Checklist - Private Key ✅ - Bitcoin Public Key -

    Bitcoin Address @paulfioravanti 71/149
  72. None
  73. None
  74. 74/149

  75. None
  76. @paulfioravanti 76/149

  77. Cure — h!ps://github.com/luc-tielen/ Cure @paulfioravanti 77/149

  78. $ brew install libbitcoin @paulfioravanti 78/149

  79. Install defp deps do [ # Interface C-code with Erlang/Elixir

    using Ports {:cure, "~> 0.4.0"}, ] end @paulfioravanti 79/149
  80. $ mix cure.bootstrap @paulfioravanti 80/149

  81. Cure Bootstrap c_src ᵓᴷ Makefile ᵓᴷ main.c ᵋᴷ main.h @paulfioravanti

    81/149
  82. Cure Bootstrap c_src ᵓᴷ Makefile ᵓᴷ main.c ᵋᴷ main.h @paulfioravanti

    82/149
  83. Cure Bootstrap c_src ᵓᴷ Makefile ᵓᴷ main.c ᵋᴷ main.h @paulfioravanti

    83/149
  84. Cure Bootstrap c_src ᵓᴷ Makefile ᵓᴷ main.c ᵋᴷ main.h @paulfioravanti

    84/149
  85. main.c #include "main.h" int main(void) { int bytes_read; byte buffer[MAX_BUFFER_SIZE];

    while((bytes_read = read_msg(buffer)) > 0) { // TODO put C-code here, right now it only echos data back // to Elixir. send_msg(buffer, bytes_read); } return 0; } @paulfioravanti 85/149
  86. main.c #include "main.h" int main(void) { int bytes_read; byte buffer[MAX_BUFFER_SIZE];

    while((bytes_read = read_msg(buffer)) > 0) { // TODO put C-code here, right now it only echos data back // to Elixir. send_msg(buffer, bytes_read); } return 0; } @paulfioravanti 86/149
  87. main.c #include "main.h" int main(void) { int bytes_read; byte buffer[MAX_BUFFER_SIZE];

    while((bytes_read = read_msg(buffer)) > 0) { // TODO put C-code here, right now it only echos data back // to Elixir. send_msg(buffer, bytes_read); } return 0; } @paulfioravanti 87/149
  88. main.c #include "main.h" int main(void) { int bytes_read; byte buffer[MAX_BUFFER_SIZE];

    while((bytes_read = read_msg(buffer)) > 0) { // TODO put C-code here, right now it only echos data back // to Elixir. send_msg(buffer, bytes_read); } return 0; } @paulfioravanti 88/149
  89. Rename Files $ mv c_src/main.h c_src/bitcoin_address.h $ mv c_src/main.c c_src/bitcoin_address.cpp

    @paulfioravanti 89/149
  90. bitcoin_address.h #ifndef BITCOIN_ADDRESS_H #define BITCOIN_ADDRESS_H #include <elixir_comm.h> std::string create_bitcoin_public_key(std::string priv_key);

    #endif @paulfioravanti 90/149
  91. bitcoin_address.cpp #include <string> #include "bitcoin_address.h" int main(void) { ... }

    std::string create_bitcoin_public_key(std::string priv_key) { bc::ec_secret decoded; bc::decode_base16(decoded, priv_key); bc::wallet::ec_private secret(decoded, bc::wallet::ec_private::mainnet_p2kh); bc::wallet::ec_public public_key(secret); return public_key.encoded(); } @paulfioravanti 91/149
  92. bitcoin_address.cpp std::string create_bitcoin_public_key(std::string priv_key) { bc::ec_secret decoded; bc::decode_base16(decoded, priv_key); bc::wallet::ec_private

    secret(decoded, bc::wallet::ec_private::mainnet_p2kh); bc::wallet::ec_public public_key(secret); return public_key.encoded(); } @paulfioravanti 92/149
  93. bitcoin_address.cpp std::string create_bitcoin_public_key(std::string priv_key) { bc::ec_secret decoded; bc::decode_base16(decoded, priv_key); bc::wallet::ec_private

    secret(decoded, bc::wallet::ec_private::mainnet_p2kh); bc::wallet::ec_public public_key(secret); return public_key.encoded(); } @paulfioravanti 93/149
  94. bitcoin_address.cpp std::string create_bitcoin_public_key(std::string priv_key) { bc::ec_secret decoded; bc::decode_base16(decoded, priv_key); bc::wallet::ec_private

    secret(decoded, bc::wallet::ec_private::mainnet_p2kh); bc::wallet::ec_public public_key(secret); return public_key.encoded(); } @paulfioravanti 94/149
  95. bitcoin_address.cpp std::string create_bitcoin_public_key(std::string priv_key) { bc::ec_secret decoded; bc::decode_base16(decoded, priv_key); bc::wallet::ec_private

    secret(decoded, bc::wallet::ec_private::mainnet_p2kh); bc::wallet::ec_public public_key(secret); return public_key.encoded(); } @paulfioravanti 95/149
  96. bitcoin_address.cpp std::string create_bitcoin_public_key(std::string priv_key) { bc::ec_secret decoded; bc::decode_base16(decoded, priv_key); bc::wallet::ec_private

    secret(decoded, bc::wallet::ec_private::mainnet_p2kh); bc::wallet::ec_public public_key(secret); return public_key.encoded(); } @paulfioravanti 96/149
  97. bitcoin_address.cpp #include <string> #include "bitcoin_address.h" int main(void) { ... }

    std::string create_bitcoin_public_key(std::string priv_key) { bc::ec_secret decoded; bc::decode_base16(decoded, priv_key); bc::wallet::ec_private secret(decoded, bc::wallet::ec_private::mainnet_p2kh); bc::wallet::ec_public public_key(secret); return public_key.encoded(); } @paulfioravanti 97/149
  98. bitcoin_address.cpp int main(void) { int bytes_read; byte buffer[MAX_BUFFER_SIZE]; while((bytes_read =

    read_msg(buffer)) > 0) { // TODO put C-code here, right now it only echos data back // to Elixir. send_msg(buffer, bytes_read); } return 0; } @paulfioravanti 98/149
  99. Just send function name & private key? @paulfioravanti 99/149

  100. Just send function name & private key? @paulfioravanti 100/149

  101. Send Flag ! @paulfioravanti 101/149

  102. Send Flag ! const int CREATE_BITCOIN_PUBLIC_KEY = 1; @paulfioravanti 102/149

  103. bitcoin_address.cpp const int CREATE_BITCOIN_PUBLIC_KEY = 1; int main(void) { int

    bytes_read; byte buffer[MAX_BUFFER_SIZE]; while((bytes_read = read_msg(buffer)) > 0) { process_command(buffer, bytes_read); } return 0; } @paulfioravanti 103/149
  104. bitcoin_address.cpp const int CREATE_BITCOIN_PUBLIC_KEY = 1; int main(void) { int

    bytes_read; byte buffer[MAX_BUFFER_SIZE]; while((bytes_read = read_msg(buffer)) > 0) { process_command(buffer, bytes_read); } return 0; } @paulfioravanti 104/149
  105. bitcoin_address.cpp void process_command(byte* buffer, int bytes_read) { int function =

    buffer[0]; std::string arg = (char*) &buffer[1]; std::string result; switch (function) { case CREATE_BITCOIN_PUBLIC_KEY: result = create_bitcoin_public_key(arg); break; } memcpy(buffer, result.data(), result.length()); send_msg(buffer, result.size()); } @paulfioravanti 105/149
  106. bitcoin_address.cpp void process_command(byte* buffer, int bytes_read) { int function =

    buffer[0]; std::string arg = (char*) &buffer[1]; std::string result; switch (function) { case CREATE_BITCOIN_PUBLIC_KEY: result = create_bitcoin_public_key(arg); break; } memcpy(buffer, result.data(), result.length()); send_msg(buffer, result.size()); } @paulfioravanti 106/149
  107. bitcoin_address.cpp void process_command(byte* buffer, int bytes_read) { int function =

    buffer[0]; std::string arg = (char*) &buffer[1]; std::string result; switch (function) { case CREATE_BITCOIN_PUBLIC_KEY: result = create_bitcoin_public_key(arg); break; } memcpy(buffer, result.data(), result.length()); send_msg(buffer, result.size()); } @paulfioravanti 107/149
  108. bitcoin_address.cpp void process_command(byte* buffer, int bytes_read) { int function =

    buffer[0]; std::string arg = (char*) &buffer[1]; std::string result; switch (function) { case CREATE_BITCOIN_PUBLIC_KEY: result = create_bitcoin_public_key(arg); break; } memcpy(buffer, result.data(), result.length()); send_msg(buffer, result.size()); } @paulfioravanti 108/149
  109. bitcoin_address.cpp void process_command(byte* buffer, int bytes_read) { int function =

    buffer[0]; std::string arg = (char*) &buffer[1]; std::string result; switch (function) { case CREATE_BITCOIN_PUBLIC_KEY: result = create_bitcoin_public_key(arg); break; } memcpy(buffer, result.data(), result.length()); send_msg(buffer, result.size()); } @paulfioravanti 109/149
  110. bitcoin_address.cpp void process_command(byte* buffer, int bytes_read) { int function =

    buffer[0]; std::string arg = (char*) &buffer[1]; std::string result; switch (function) { case CREATE_BITCOIN_PUBLIC_KEY: result = create_bitcoin_public_key(arg); break; } memcpy(buffer, result.data(), result.length()); send_msg(buffer, result.size()); } @paulfioravanti 110/149
  111. bitcoin_address.cpp void process_command(byte* buffer, int bytes_read) { int function =

    buffer[0]; std::string arg = (char*) &buffer[1]; std::string result; switch (function) { case CREATE_BITCOIN_PUBLIC_KEY: result = create_bitcoin_public_key(arg); break; } memcpy(buffer, result.data(), result.length()); send_msg(buffer, result.size()); } @paulfioravanti 111/149
  112. bitcoin_address.cpp void process_command(byte* buffer, int bytes_read) { int function =

    buffer[0]; std::string arg = (char*) &buffer[1]; std::string result; switch (function) { case CREATE_BITCOIN_PUBLIC_KEY: result = create_bitcoin_public_key(arg); break; } memcpy(buffer, result.data(), result.length()); send_msg(buffer, result.size()); } @paulfioravanti 112/149
  113. @paulfioravanti 113/149

  114. defmodule BitcoinAddress.CPlusPlus do alias Cure.Server, as: Cure @cpp_executable "priv/bitcoin_address" #

    Integers representing C++ methods @create_bitcoin_public_key 1 def generate(private_key) do with {:ok, pid} <- Cure.start_link(@cpp_executable), bitcoin_public_key <- create_bitcoin_public_key(pid, private_key) do IO.puts("Private key: #{inspect(private_key)}") IO.puts("Bitcoin public key: #{inspect(bitcoin_public_key)}") :ok = Cure.stop(pid) end end defp create_bitcoin_public_key(pid, private_key) do Cure.send_data(pid, <<@create_bitcoin_public_key, private_key::binary>>, :once) receive do {:cure_data, response} -> response end end end @paulfioravanti 114/149
  115. defmodule BitcoinAddress.CPlusPlus do alias Cure.Server, as: Cure @cpp_executable "priv/bitcoin_address" #

    Integers representing C++ methods @create_bitcoin_public_key 1 # ... end @paulfioravanti 115/149
  116. defmodule BitcoinAddress.CPlusPlus do alias Cure.Server, as: Cure @cpp_executable "priv/bitcoin_address" #

    Integers representing C++ methods @create_bitcoin_public_key 1 # ... end @paulfioravanti 116/149
  117. defmodule BitcoinAddress.CPlusPlus do alias Cure.Server, as: Cure @cpp_executable "priv/bitcoin_address" #

    Integers representing C++ methods @create_bitcoin_public_key 1 # ... end @paulfioravanti 117/149
  118. defmodule BitcoinAddress.CPlusPlus do # ... def generate(private_key) do with {:ok,

    pid} <- Cure.start_link(@cpp_executable), bitcoin_public_key <- create_bitcoin_public_key(pid, private_key) do # ... :ok = Cure.stop(pid) end end # ... end @paulfioravanti 118/149
  119. defmodule BitcoinAddress.CPlusPlus do # ... def generate(private_key) do with {:ok,

    pid} <- Cure.start_link(@cpp_executable), bitcoin_public_key <- create_bitcoin_public_key(pid, private_key) do # ... :ok = Cure.stop(pid) end end # ... end @paulfioravanti 119/149
  120. defmodule BitcoinAddress.CPlusPlus do # ... def generate(private_key) do with {:ok,

    pid} <- Cure.start_link(@cpp_executable), bitcoin_public_key <- create_bitcoin_public_key(pid, private_key) do # ... :ok = Cure.stop(pid) end end # ... end @paulfioravanti 120/149
  121. defmodule BitcoinAddress.CPlusPlus do # ... def generate(private_key) do with {:ok,

    pid} <- Cure.start_link(@cpp_executable), bitcoin_public_key <- create_bitcoin_public_key(pid, private_key) do # ... :ok = Cure.stop(pid) end end defp create_bitcoin_public_key(pid, priv_key) do Cure.send_data(pid, <<@create_bitcoin_public_key, priv_key::binary>>, :once) receive do {:cure_data, response} -> response end end end @paulfioravanti 121/149
  122. defmodule BitcoinAddress.CPlusPlus do alias Cure.Server, as: Cure @cpp_executable "priv/bitcoin_address" #

    Integers representing C++ methods @create_bitcoin_public_key 1 def generate(private_key) do with {:ok, pid} <- Cure.start_link(@cpp_executable), bitcoin_public_key <- create_bitcoin_public_key(pid, private_key) do IO.puts("Private key: #{inspect(private_key)}") IO.puts("Bitcoin public key: #{inspect(bitcoin_public_key)}") :ok = Cure.stop(pid) end end defp create_bitcoin_public_key(pid, private_key) do Cure.send_data(pid, <<@create_bitcoin_public_key, priv_key::binary>>, :once) receive do {:cure_data, response} -> response end end end @paulfioravanti 122/149
  123. Checklist - Private Key ✅ - Bitcoin Public Key -

    Bitcoin Address @paulfioravanti 123/149
  124. bitcoin_address.cpp std::string create_bitcoin_address(std::string pub_key) { bc::wallet::ec_public public_key = bc::wallet::ec_public::ec_public(pub_key); bc::data_chunk

    public_key_data; public_key.to_data(public_key_data); const auto hash = bc::bitcoin_short_hash(public_key_data); bc::data_chunk unencoded_address; unencoded_address.reserve(25); unencoded_address.push_back(0); bc::extend_data(unencoded_address, hash); bc::append_checksum(unencoded_address); const std::string address = bc::encode_base58(unencoded_address); return address; } @paulfioravanti 124/149
  125. const int CREATE_BITCOIN_PUBLIC_KEY = 1; const int CREATE_BITCOIN_ADDRESS = 2;

    int main(void) { ... } void process_command(byte* buffer, int bytes_read) { int function = buffer[0]; std::string arg = (char*) &buffer[1]; std::string result; switch (function) { case CREATE_BITCOIN_PUBLIC_KEY: result = create_bitcoin_public_key(arg); break; case CREATE_BITCOIN_ADDRESS: result = create_bitcoin_address(arg); break; } memcpy(buffer, result.data(), result.length()); send_msg(buffer, result.size()); } @paulfioravanti 125/149
  126. const int CREATE_BITCOIN_PUBLIC_KEY = 1; const int CREATE_BITCOIN_ADDRESS = 2;

    int main(void) { ... } void process_command(byte* buffer, int bytes_read) { int function = buffer[0]; std::string arg = (char*) &buffer[1]; std::string result; switch (function) { case CREATE_BITCOIN_PUBLIC_KEY: result = create_bitcoin_public_key(arg); break; case CREATE_BITCOIN_ADDRESS: result = create_bitcoin_address(arg); break; } memcpy(buffer, result.data(), result.length()); send_msg(buffer, result.size()); } @paulfioravanti 126/149
  127. defmodule BitcoinAddress.CPlusPlus do @create_bitcoin_public_key 1 @create_bitcoin_address 2 def generate(private_key) do

    with {:ok, pid} <- Cure.start_link(@cpp_executable), bitcoin_public_key <- create_bitcoin_public_key(pid, private_key), bitcoin_address <- create_bitcoin_address(pid, public_key) do # ... end end defp create_bitcoin_address(pid, pub_key) do Cure.send_data(pid, <<@create_bitcoin_address, pub_key::binary>>, :once) receive do {:cure_data, response} -> response end end end @paulfioravanti 127/149
  128. defmodule BitcoinAddress.CPlusPlus do @create_bitcoin_public_key 1 @create_bitcoin_address 2 def generate(private_key) do

    with {:ok, pid} <- Cure.start_link(@cpp_executable), bitcoin_public_key <- create_bitcoin_public_key(pid, private_key), bitcoin_address <- create_bitcoin_address(pid, public_key) do # ... end end defp create_bitcoin_address(pid, pub_key) do Cure.send_data(pid, <<@create_bitcoin_address, pub_key::binary>>, :once) receive do {:cure_data, response} -> response end end end @paulfioravanti 128/149
  129. defmodule BitcoinAddress.CPlusPlus do @create_bitcoin_public_key 1 @create_bitcoin_address 2 def generate(private_key) do

    with {:ok, pid} <- Cure.start_link(@cpp_executable), bitcoin_public_key <- create_bitcoin_public_key(pid, private_key), bitcoin_address <- create_bitcoin_address(pid, public_key) do # ... end end defp create_bitcoin_address(pid, pub_key) do Cure.send_data(pid, <<@create_bitcoin_address, pub_key::binary>>, :once) receive do {:cure_data, response} -> response end end end @paulfioravanti 129/149
  130. defmodule BitcoinAddress.CPlusPlus do alias Cure.Server, as: Cure @cpp_executable "priv/bitcoin_address" #

    Integers representing C++ methods @create_bitcoin_public_key 1 @create_bitcoin_address 2 def generate(private_key) do with {:ok, pid} <- Cure.start_link(@cpp_executable), bitcoin_public_key <- create_bitcoin_public_key(pid, private_key), bitcoin_address <- create_bitcoin_address(pid, bitcoin_public_key) do IO.puts("Private key: #{inspect(private_key)}") IO.puts("Public key: #{inspect(bitcoin_public_key)}") IO.puts("Bitcoin address: #{inspect(bitcoin_address)}") :ok = Cure.stop(pid) end end defp create_bitcoin_public_key(pid, priv_key) do call_cpp(pid, <<@create_bitcoin_public_key, priv_key::binary>>) end defp create_bitcoin_address(pid, pub_key) do call_cpp(pid, <<@create_bitcoin_address, pub_key::binary>>) end defp call_cpp(pid, data) do Cure.send_data(pid, data, :once) receive do {:cure_data, response} -> response end end end @paulfioravanti 130/149
  131. Checklist - Private Key ✅ - Bitcoin Public Key -

    Bitcoin Address @paulfioravanti 131/149
  132. ut

  133. Makefile @paulfioravanti 133/149

  134. Makefile ! CC = g++ -std=c++11 APP_DIR = $(shell dirname

    $(shell pwd)) CURE_DEPS_DIR = $(APP_DIR)/deps/cure/c_src CURE_DEPS = -I$(CURE_DEPS_DIR) -L$(CURE_DEPS_DIR) ELIXIR_COMM_C = -x c++ $(CURE_DEPS_DIR)/elixir_comm.c LIBBITCOIN_DEPS = $(shell pkg-config --cflags --libs libbitcoin) C_FLAGS = $(CURE_DEPS) $(ELIXIR_COMM_C) $(LIBBITCOIN_DEPS) -O3 PRIV_DIR = $(APP_DIR)/priv C_SRC_DIR = $(APP_DIR)/c_src EXECUTABLES = bitcoin_address all: $(EXECUTABLES) # * $< - prerequisite file # * $@ - executable file $(EXECUTABLES): %: %.cpp $(CC) $(C_FLAGS) $(C_SRC_DIR)/$< -o $(PRIV_DIR)/$@ @paulfioravanti 134/149
  135. Compile from c_src/ to priv/ all: $(EXECUTABLES) # * $<

    - prerequisite file # * $@ - executable file $(EXECUTABLES): %: %.cpp $(CC) $(C_FLAGS) $(C_SRC_DIR)/$< -o $(PRIV_DIR)/$@ @paulfioravanti 135/149
  136. Compile C++ with Elixir defmodule BitcoinAddress.Mixfile do use Mix.Project def

    project do [ # ... compilers: Mix.compilers ++ [:cure, :"cure.deps"] ] end # ... end @paulfioravanti 136/149
  137. Compile during TDD if Mix.env() == :dev do config :mix_test_watch,

    clear: true, tasks: [ "compile.cure", "format", "test", "credo --strict" ] end @paulfioravanti 137/149
  138. Anyway... @paulfioravanti 138/149

  139. None
  140. None
  141. None
  142. @paulfioravanti 142/149

  143. Self-Promotion — h!ps://paulfioravanti.com/blog/2017/12/04/using- pythons-bitcoin-libraries-in-elixir/ — h!ps://paulfioravanti.com/blog/2017/12/13/using-c- plus-plus-bitcoin-libraries-in-elixir/ @paulfioravanti 143/149

  144. Github Repos — h!ps://github.com/paulfioravanti/bitcoin_address — h!ps://github.com/paulfioravanti/mastering_bitcoin @paulfioravanti 144/149

  145. Ironically enough... @paulfioravanti 145/149

  146. None
  147. @paulfioravanti 147/149

  148. None
  149. Thanks! @paulfioravanti