Skip to content

Commit b16d264

Browse files
authored
Merge pull request #7 from wolfmcnally/develop
Bech32 format support
2 parents e6934b7 + 0eb9755 commit b16d264

File tree

13 files changed

+220
-21
lines changed

13 files changed

+220
-21
lines changed

.vscode/launch.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@
1212
"preLaunchTask": "Build"
1313
}
1414
]
15-
}
15+
}

MANUAL.md

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,25 @@ $ seedtool --in random --out hex
4444
06799f71d16fad08ec5407d32d670147
4545
```
4646

47-
An output format `--out` and count `--count` may be specified. Count may be in [1-64] and the default `count` is 16. For the `hex` output format, the count is the number of bytes generated. For other output formats, `count` is the number of "output units" (e.g., bits, cards, die rolls, etc.)
47+
The `bech32` format can be used in place of `hex`. Bech32 is recognizable by the first 5 characters being `seed1`. Unlike hex, where every possible input is a seed, Bech32 includes error detection.
48+
49+
```
50+
#
51+
# Generate a 16-byte random seed and display it as Bech32.
52+
#
53+
54+
$ seedtool --out bech32
55+
seed1ee2mukxh95k4tyjv875aka5xwqc59ge0
56+
57+
#
58+
# Convert the Bech32-encoded seed to hex.
59+
#
60+
61+
$ seedtool --in bech32 seed1ee2mukxh95k4tyjv875aka5xwqc59ge0
62+
ce55be58d72d2d55924c3fa9db768670
63+
```
64+
65+
An output format `--out` and count `--count` may be specified. Count may be in [1-64] and the default `count` is 16. For the `hex` and `bech32` output formats, the count is the number of bytes generated. For other output formats, `count` is the number of "output units" (e.g., bits, cards, die rolls, etc.)
4866

4967
```
5068
#
@@ -200,7 +218,7 @@ crucial enlarge ceramic method custody maximum campus earth ordinary twice adequ
200218

201219
When the `--in` option is used, seedtool takes one or more arguments and uses them to construct the seed. If no arguments are given on the command line, it reads input from stdin and uses what it reads to construct the seed. In the examples below, the end of input to stdin is marked by `^D` on its own line.
202220

203-
When the input format is `hex`, the construction is the identity function (passthrough.)
221+
When the input format is `hex` or `bech32`, the construction is the identity function (passthrough.)
204222

205223
```
206224
#
@@ -211,6 +229,15 @@ $ seedtool --in hex
211229
3d1d142cd016cf8a393a1b477891c5e594fb7c9479b175a0db653067d6de0b17
212230
^D
213231
3d1d142cd016cf8a393a1b477891c5e594fb7c9479b175a0db653067d6de0b17
232+
233+
#
234+
# Input a Bech32 seed via stdin, receive the same seed back in hex.
235+
#
236+
237+
$ seedtool --in bech32
238+
seed1gv0pq3wv5733vyzs6de2tjn7vc677gcm
239+
^D
240+
431e1045cca7a3161050d372a5ca7e66
214241
```
215242

216243
For the other input formats, each "unit" of the input (bit, digit, card, etc.) is converted to a byte and placed in an array. The SHA256 is then taken of the resulting array, yielding a deterministic seed. This seed is then used to generate a cryptographic seed of `count` bytes.
@@ -343,7 +370,7 @@ $ seedtool --in cards --count 20 6c2c3hthacts6d4hkhtd2d7c6c3sqs6h
343370
731e0a4c76189b2b55f4c705ccbb0105d3ee72c0
344371
```
345372

346-
`bip39` and `slip39` output formats can be combined with the `random` (default) input format. If the `--count N` option is used with the `hex` input format, it results in a seed of `N` bytes being generated and used.
373+
`bip39` and `slip39` output formats can be combined with the `random` (default) input format. If the `--count N` option is used with the `hex` or `bech32` input formats, it results in a seed of `N` bytes being generated and used.
347374

348375
```
349376
#
@@ -362,7 +389,7 @@ $ seedtool --in random --out slip39 --count 32
362389
pumps guest academic academic analysis election admit harvest very webcam acquire answer primary viral venture declare have short bucket pickup pistol squeeze script racism western alarm depend depart lilac zero capacity capture warn
363390
```
364391

365-
`bip39` and `slip39` output formats can be combined with the `hex` input format. The `--count` option is not allowed and the whole hex seed is used. For `bip39` the seed must be 12-32 bytes and even. For `slip39` the seed must be 16-32 bytes and even.
392+
`bip39` and `slip39` output formats can be combined with the `hex` or `bech32` input formats. The `--count` option is not allowed and the whole hex seed is used. For `bip39` the seed must be 12-32 bytes and even. For `slip39` the seed must be 16-32 bytes and even.
366393

367394
```
368395
#
@@ -379,6 +406,20 @@ $ seedtool --out hex
379406
$ seedtool --in hex --out bip39 8a3796240f6a9606a577c887f2e5c83a
380407
mechanic royal math burst practice addict noise weekend margin now improve invest
381408
409+
#
410+
# Convert the seed above to Bech32.
411+
#
412+
413+
$ seedtool --in hex --out bech32 8a3796240f6a9606a577c887f2e5c83a
414+
seed13gmevfq0d2tqdfthezrl9ewg8g4fq0wc
415+
416+
#
417+
# Display the Bech32-encoded seed as BIP39.
418+
#
419+
420+
$ seedtool --in bech32 --out bip39 seed13gmevfq0d2tqdfthezrl9ewg8g4fq0wc
421+
mechanic royal math burst practice addict noise weekend margin now improve invest
422+
382423
#
383424
# The --count option is not available when providing the
384425
# seed yourself.
@@ -387,6 +428,9 @@ mechanic royal math burst practice addict noise weekend margin now improve inves
387428
$ seedtool --count 12 --in hex --out bip39 8a3796240f6a9606a577c887f2e5c83a
388429
seedtool: The --count option is not available for hex input.
389430
431+
$ seedtool --count 5 --in bech32 seed1gv0pq3wv5733vyzs6de2tjn7vc677gcm
432+
seedtool: The --count option is not available for bech32 input.
433+
390434
#
391435
# The seed you provide must conform to the output format constraints.
392436
#
@@ -423,6 +467,16 @@ $ seedtool --in bip39
423467
mechanic royal math burst practice addict noise weekend margin now improve invest
424468
^D
425469
8a3796240f6a9606a577c887f2e5c83a
470+
471+
#
472+
# Recover from the same BIP39 mnemonic sequence, providing all
473+
# the words via stdin, and displaying the result as Bech32.
474+
#
475+
476+
$ seedtool --in bip39 --out bech32
477+
mechanic royal math burst practice addict noise weekend margin now improve invest
478+
^D
479+
seed13gmevfq0d2tqdfthezrl9ewg8g4fq0wc
426480
```
427481

428482
`slip39` can be used as an input format, in which case the original seed is recovered. The SLIP39 shares may be passed on the command line or entered via stdin. If passed on the command line, the shares must each be a single argument (i.e., quoted). If passed via stdin, each share must appear by itself on one line.
@@ -624,6 +678,10 @@ mirror reject rookie talk pudding throw happy era myth already payment owner
624678

625679
## Version History
626680

681+
### 0.2.0, 4/22/2020
682+
683+
* Added "bech32" input and output formats.
684+
627685
### 0.1.1, 4/8/2020
628686

629687
* Added compatibility with Ian Coleman's BIP39 tool for several input formats:

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ If any of the following prerequisites are not installed, the `configure` step be
1010
* [`bc-shamir`](https://github.com/blockchaincommons/bc-shamir)
1111
* [`bc-slip39`](https://github.com/blockchaincommons/bc-slip39)
1212
* [`bc-bip39`](https://github.com/blockchaincommons/bc-bip39)
13+
* [`bc-bech32`](https://github.com/blockchaincommons/bc-bech32)
1314
* [`GNU argp`](https://www.gnu.org/software/libc/manual/html_node/Argp.html) This may be installed via `brew install argp-standalone`.
1415

1516
## Installation

configure

Lines changed: 59 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#! /bin/sh
22
# Guess values for system-dependent variables and create Makefiles.
3-
# Generated by GNU Autoconf 2.69 for bc-seedtool-cli 0.1.1.
3+
# Generated by GNU Autoconf 2.69 for bc-seedtool-cli 0.2.0.
44
#
55
#
66
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@@ -577,8 +577,8 @@ MAKEFLAGS=
577577
# Identity of this package.
578578
PACKAGE_NAME='bc-seedtool-cli'
579579
PACKAGE_TARNAME='bc-seedtool-cli'
580-
PACKAGE_VERSION='0.1.1'
581-
PACKAGE_STRING='bc-seedtool-cli 0.1.1'
580+
PACKAGE_VERSION='0.2.0'
581+
PACKAGE_STRING='bc-seedtool-cli 0.2.0'
582582
PACKAGE_BUGREPORT=''
583583
PACKAGE_URL=''
584584

@@ -1231,7 +1231,7 @@ if test "$ac_init_help" = "long"; then
12311231
# Omit some internal or obsolete options to make the list less imposing.
12321232
# This message is too long to be a string in the A/UX 3.1 sh.
12331233
cat <<_ACEOF
1234-
\`configure' configures bc-seedtool-cli 0.1.1 to adapt to many kinds of systems.
1234+
\`configure' configures bc-seedtool-cli 0.2.0 to adapt to many kinds of systems.
12351235
12361236
Usage: $0 [OPTION]... [VAR=VALUE]...
12371237
@@ -1292,7 +1292,7 @@ fi
12921292

12931293
if test -n "$ac_init_help"; then
12941294
case $ac_init_help in
1295-
short | recursive ) echo "Configuration of bc-seedtool-cli 0.1.1:";;
1295+
short | recursive ) echo "Configuration of bc-seedtool-cli 0.2.0:";;
12961296
esac
12971297
cat <<\_ACEOF
12981298
@@ -1374,7 +1374,7 @@ fi
13741374
test -n "$ac_init_help" && exit $ac_status
13751375
if $ac_init_version; then
13761376
cat <<\_ACEOF
1377-
bc-seedtool-cli configure 0.1.1
1377+
bc-seedtool-cli configure 0.2.0
13781378
generated by GNU Autoconf 2.69
13791379
13801380
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -1885,7 +1885,7 @@ cat >config.log <<_ACEOF
18851885
This file contains any messages produced by compilers while
18861886
running configure, to aid debugging if configure makes a mistake.
18871887
1888-
It was created by bc-seedtool-cli $as_me 0.1.1, which was
1888+
It was created by bc-seedtool-cli $as_me 0.2.0, which was
18891889
generated by GNU Autoconf 2.69. Invocation command line was
18901890
18911891
$ $0 $@
@@ -3609,6 +3609,56 @@ else
36093609

36103610
fi
36113611

3612+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for bech32_seed_encode in -lbc-bech32" >&5
3613+
$as_echo_n "checking for bech32_seed_encode in -lbc-bech32... " >&6; }
3614+
if ${ac_cv_lib_bc_bech32_bech32_seed_encode+:} false; then :
3615+
$as_echo_n "(cached) " >&6
3616+
else
3617+
ac_check_lib_save_LIBS=$LIBS
3618+
LIBS="-lbc-bech32 $LIBS"
3619+
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
3620+
/* end confdefs.h. */
3621+
3622+
/* Override any GCC internal prototype to avoid an error.
3623+
Use char because int might match the return type of a GCC
3624+
builtin and then its argument prototype would still apply. */
3625+
#ifdef __cplusplus
3626+
extern "C"
3627+
#endif
3628+
char bech32_seed_encode ();
3629+
int
3630+
main ()
3631+
{
3632+
return bech32_seed_encode ();
3633+
;
3634+
return 0;
3635+
}
3636+
_ACEOF
3637+
if ac_fn_c_try_link "$LINENO"; then :
3638+
ac_cv_lib_bc_bech32_bech32_seed_encode=yes
3639+
else
3640+
ac_cv_lib_bc_bech32_bech32_seed_encode=no
3641+
fi
3642+
rm -f core conftest.err conftest.$ac_objext \
3643+
conftest$ac_exeext conftest.$ac_ext
3644+
LIBS=$ac_check_lib_save_LIBS
3645+
fi
3646+
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bc_bech32_bech32_seed_encode" >&5
3647+
$as_echo "$ac_cv_lib_bc_bech32_bech32_seed_encode" >&6; }
3648+
if test "x$ac_cv_lib_bc_bech32_bech32_seed_encode" = xyes; then :
3649+
cat >>confdefs.h <<_ACEOF
3650+
#define HAVE_LIBBC_BECH32 1
3651+
_ACEOF
3652+
3653+
LIBS="-lbc-bech32 $LIBS"
3654+
3655+
else
3656+
3657+
echo "### Error! libbc-bech32 must be installed first."
3658+
exit -1
3659+
3660+
fi
3661+
36123662
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for argp_parse in -largp" >&5
36133663
$as_echo_n "checking for argp_parse in -largp... " >&6; }
36143664
if ${ac_cv_lib_argp_argp_parse+:} false; then :
@@ -4868,7 +4918,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
48684918
# report actual input values of CONFIG_FILES etc. instead of their
48694919
# values after options handling.
48704920
ac_log="
4871-
This file was extended by bc-seedtool-cli $as_me 0.1.1, which was
4921+
This file was extended by bc-seedtool-cli $as_me 0.2.0, which was
48724922
generated by GNU Autoconf 2.69. Invocation command line was
48734923
48744924
CONFIG_FILES = $CONFIG_FILES
@@ -4930,7 +4980,7 @@ _ACEOF
49304980
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
49314981
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
49324982
ac_cs_version="\\
4933-
bc-seedtool-cli config.status 0.1.1
4983+
bc-seedtool-cli config.status 0.2.0
49344984
configured by $0, generated by GNU Autoconf 2.69,
49354985
with options \\"\$ac_cs_config\\"
49364986

configure.ac

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# Process this file with autoconf to produce a configure script.
33

44
AC_PREREQ([2.69])
5-
AC_INIT([bc-seedtool-cli], [0.1.1])
5+
AC_INIT([bc-seedtool-cli], [0.2.0])
66
AC_CONFIG_SRCDIR([src/seedtool.cpp])
77
AC_CONFIG_HEADERS([src/config.h])
88

@@ -28,6 +28,10 @@ AC_CHECK_LIB([bc-bip39], [bip39_mnemonic_from_word], [], [
2828
echo "### Error! libbc-bip39 must be installed first."
2929
exit -1
3030
])
31+
AC_CHECK_LIB([bc-bech32], [bech32_seed_encode], [], [
32+
echo "### Error! libbc-bech32 must be installed first."
33+
exit -1
34+
])
3135
AC_CHECK_LIB([argp], [argp_parse], [], [
3236
echo "### Error! argp must be installed first. Try 'brew install argp-standalone'."
3337
exit -1

src/Makefile.in

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,11 @@ OBJS = \
5151
format-ints.o \
5252
format-random.o \
5353
format-slip39.o \
54+
format-bech32.o \
5455
randombytes.o \
5556
hkdf.o
5657

57-
LDFLAGS = -lstdc++ -lbc-crypto-base -lbc-shamir -lbc-slip39 -lbc-bip39 -largp
58+
LDFLAGS = -lstdc++ -lbc-crypto-base -lbc-shamir -lbc-slip39 -lbc-bip39 -lbc-bech32 -largp
5859

5960
$(toolname): $(OBJS)
6061

@@ -65,7 +66,7 @@ random.o: random.hpp randombytes.h hkdf.h utils.hpp
6566
randombytes.o: randombytes.h
6667
hkdf.o: hkdf.h
6768
format.o: format.hpp utils.hpp
68-
formats-all.hpp: format-base6.hpp format-base10.hpp format-bip39.hpp format-bits.hpp format-cards.hpp format-dice.hpp format-hex.hpp format-ints.hpp format-random.hpp format-slip39.hpp
69+
formats-all.hpp: format-base6.hpp format-base10.hpp format-bip39.hpp format-bits.hpp format-cards.hpp format-dice.hpp format-hex.hpp format-ints.hpp format-random.hpp format-slip39.hpp format-bech32.hpp
6970
format-base6.o: format-base6.hpp format.hpp params.hpp random.hpp
7071
format-base10.o: format-base10.hpp format.hpp params.hpp random.hpp
7172
format-bip39.o: format-bip39.hpp format.hpp params.hpp random.hpp
@@ -76,6 +77,7 @@ format-hex.o: format-hex.hpp format.hpp params.hpp random.hpp
7677
format-ints.o: format-ints.hpp format.hpp params.hpp random.hpp
7778
format-random.o: format-random.hpp format.hpp params.hpp random.hpp
7879
format-slip39.o: format-slip39.hpp format.hpp params.hpp random.hpp
80+
format-bech32.o: format-bech32.hpp format.hpp params.hpp random.hpp
7981

8082
bindir = $(DESTDIR)/$(prefix)/bin
8183

src/config.h.in

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
/* Define to 1 if you have the `argp' library (-largp). */
1010
#undef HAVE_LIBARGP
1111

12+
/* Define to 1 if you have the `bc-bech32' library (-lbc-bech32). */
13+
#undef HAVE_LIBBC_BECH32
14+
1215
/* Define to 1 if you have the `bc-bip39' library (-lbc-bip39). */
1316
#undef HAVE_LIBBC_BIP39
1417

src/format-bech32.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//
2+
// format-bech32.cpp
3+
//
4+
// Copyright © 2020 by Blockchain Commons, LLC
5+
// Licensed under the "BSD-2-Clause Plus Patent License"
6+
//
7+
8+
#include "format-bech32.hpp"
9+
10+
#include <stdexcept>
11+
#include <bc-bech32/bc-bech32.h>
12+
13+
#include "params.hpp"
14+
15+
using namespace std;
16+
17+
bool FormatBech32::is_seed_length_valid(size_t seed_len) {
18+
if(!(1 <= seed_len && seed_len <= 64)) { return false; }
19+
return true;
20+
}
21+
22+
void FormatBech32::process_input(Params* p) {
23+
auto input = p->get_one_argument();
24+
vector<uint8_t> seed;
25+
seed.resize(300);
26+
size_t seed_len = 0;
27+
if(bech32_seed_decode(&seed[0], &seed_len, input.c_str()) == 0) {
28+
throw runtime_error("Invalid bech32 seed.");
29+
}
30+
seed.resize(seed_len);
31+
p->seed = seed;
32+
}
33+
34+
void FormatBech32::process_output(Params* p) {
35+
auto data_len = p->seed.size();
36+
char output[200];
37+
auto data = &p->seed[0];
38+
if(bech32_seed_encode(output, data, data_len) == 0) {
39+
throw runtime_error("Bech32 seed encoding failed.");
40+
}
41+
p->output = output;
42+
}

src/format-bech32.hpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//
2+
// format-bech32.hpp
3+
//
4+
// Copyright © 2020 by Blockchain Commons, LLC
5+
// Licensed under the "BSD-2-Clause Plus Patent License"
6+
//
7+
8+
#pragma once
9+
10+
#include "format.hpp"
11+
12+
class FormatBech32 : public Format {
13+
public:
14+
FormatBech32() : Format(Format::Key::bech32, "bech32") {}
15+
16+
virtual void process_input(Params* p) override;
17+
virtual void process_output(Params* p) override;
18+
19+
static bool is_seed_length_valid(size_t seed_len);
20+
};

0 commit comments

Comments
 (0)