From cd62064f2303c14ac8e373f57848732ade8c0d5b Mon Sep 17 00:00:00 2001 From: Matt Whitlock Date: Sat, 2 Mar 2024 07:56:53 -0500 Subject: [PATCH] README.md: add more examples --- README.md | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 107 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index e51b190..eee9702 100644 --- a/README.md +++ b/README.md @@ -3,11 +3,22 @@ This simple C library has two primary functions, **`base58check_encode`** and **`base58check_decode`**. Please refer to the auto-generated [Doxygen documentation](https://whitslack.github.io/libbase58check/base58check_8h.html) for usage details. +The library comes with a command-line utility for Base58Check encoding/decoding from `stdin` to `stdout`. + There are also overloaded C++ convenience functions if you are writing in C++. -### Usage examples +## Usage examples + +### Encoding +Here's an example of generating a 256-bit private key and encoding it as Base58Check in Bitcoin's Wallet Import Format (WIF). + +#### Shell +```bash +$ { printf '\x80' ; head -c32 /dev/urandom ; printf '\x01' ; } | base58check +KxmBZwPrX3u2dukBawC9u88BKAXuRRHmPwuLzLo8skAgBQoGnC6c +``` -Here's an example of generating a 256-bit private key and encoding it as Base58Check in Bitcoin's Wallet Import Format (WIF): +#### C++ ```cpp #include @@ -27,7 +38,7 @@ int main() { // wrap the key between a 0x80 type byte and a 0x01 flag byte std::array bytes; bytes[0] = std::byte { 0x80 }; - std::ranges::copy(std::as_bytes(std::span(key)), bytes.begin() + 1); + std::ranges::copy(as_bytes(std::span(key)), bytes.begin() + 1); bytes[33] = std::byte { 0x01 }; // Base58Check encode the wrapped key and print it out @@ -36,7 +47,60 @@ int main() { } ``` -And here's an example of decoding a Base58Check encoding from standard input: +#### C +```c +#include + +#include +#include +#include +#include +#include + +int main() { + struct { + uint8_t type; + uint8_t key[32]; + uint8_t flag; + } buf; + int ret = 0; + + // fill a 32-byte key using getrandom() + if (getrandom(buf.key, sizeof buf.key, 0) < sizeof buf.key) + err(EX_OSERR, "getrandom"); + + // wrap the key between a 0x80 type byte and a 0x01 flag byte + buf.type = 0x80, buf.flag = 0x01; + + // Base58Check encode the wrapped key + char *out = NULL; + size_t n_out = 1; // 1 excess char for null terminator + if (base58check_encode(&out, &n_out, (unsigned char *) &buf, sizeof buf, 0) < 0) + errx(EX_UNAVAILABLE, "base58check_encode failed"); + out[n_out] = '\0'; + + // print it out + if (puts(out) < 0 || fflush(stdout) < 0) + err(EX_IOERR, "stdout"); + + // be tidy + base58check_free(out); + return EX_OK; +} +``` + +### Decoding +And here's an example of decoding a Base58Check encoding from standard input. + +#### Shell +```bash +$ echo 1BitcoinEaterAddressDontSendf59kuE | base58check -d | hexdump -C +00000000 00 75 9d 66 77 09 1e 97 3b 9e 9d 99 f1 9c 68 fb |.u.fw...;.....h.| +00000010 f4 3e 3f 05 f9 |.>?..| +00000015 +``` + +#### C++ ```cpp #include @@ -57,12 +121,49 @@ int main() { auto bytes = base58check::decode(str); std::cout.write(reinterpret_cast(bytes.data()), bytes.size()) << std::flush; - return 0; } ``` -### Building +#### C +```c +#include + +#include +#include +#include +#include +#include + +int main() { + // read a line from stdin + char *in = NULL; + ssize_t n_in = 0; + if ((n_in = getline(&in, (size_t *) &n_in, stdin)) < 0 && ferror(stdin)) + err(EX_IOERR, "stdin"); + + // chop off any trailing newline character + if (n_in && in[n_in - 1] == '\n') + in[--n_in] = '\0'; + + // decode the Base58Check + unsigned char *out = NULL; + size_t n_out = 0; + if (base58check_decode(&out, &n_out, in, n_in, 0) < 0) + errx(EX_DATAERR, "base58check_decode failed"); + + // output the raw bytes + if (fwrite(out, 1, n_out, stdout) < n_out || fflush(stdout) < 0) + err(EX_IOERR, "stdout"); + + // be tidy + base58check_free(out); + free(in); + return EX_OK; +} +``` + +## Building 1. Install the prerequisites — most/all of which you probably already have: