Skip to content

Commit 7e92f59

Browse files
committed
Correctly decode multi-share SLIP-39 URs.
* Fixed bug where multi-share URs like SLIP-39 were not decoded correctly due to support for multi-part URs being added. Seedtool now supports *either* decoding a multi-part UR or a multi-share UR where the shares are encoded as URs, but not both simultaneously. * Added example to MANUAL of decoding URs containing SLIP-39 shares.
1 parent c079370 commit 7e92f59

File tree

9 files changed

+108
-37
lines changed

9 files changed

+108
-37
lines changed

.vscode/launch.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"type": "lldb",
88
"request": "launch",
99
"program": "${workspaceFolder}/src/seedtool",
10-
"args": [ "--in", "ur" ],
10+
"args": [ ],
1111
"cwd": "${workspaceFolder}/src",
1212
"preLaunchTask": "Build"
1313
}

MANUAL.md

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# 🌱 Seedtool
22

3-
**Version 0.7.0**<br/>**August 12, 2020**
3+
**Version 0.7.1**<br/>**August 21, 2020**
44

55
*Copyright © 2020 by Blockchain Commons, LLC*<br/>*Licensed under the "BSD-2-Clause Plus Patent License"*
66

@@ -933,8 +933,27 @@ ur:crypto-slip39/18-9/ltbgascfadrkcyrkfmesjlhdeyihiajlkoihjpiojkjyhsieinkpjniojo
933933
9d347f841a4e2ce6bc886e1aee74d824
934934
```
935935

936+
The example above uses a multi-part UR to encode all the shares of a SLIP-39 seed. Each of the parts of a multi-part UR are *not* equivalent to a share of a multi-share recovery tool like SLIP-39. Seedtool can also decode a SLIP-39 seed from one or more single-part URs that each represent one share of a SLIP-39.
937+
938+
```
939+
#
940+
# Recover a SLIP-39 seed using 2 of 3 shares. Each UR is one share.
941+
#
942+
943+
$ seedtool --in ur
944+
ur:crypto-slip39/oyadlymwihkojliniaihishsiahsieihjniniaishsiahsieihjniniaiehsiainieiohsjtksinihjykkihiojpinjzjzieiyhsktjtiohskpiajyinjljtiokoihjpieiniajyiyjyihjnjojzihieisjlkpjpiojzinidjphsjpkkihiokpihjkjyiejohsjohsiyjpiskkjyisjnihjkhskoihjpiejlkoihjtihjphsjkjokkisihksiaishsjtioihiyjyjphsiajejkbnvsckem
945+
ur:crypto-slip39/oyadlymwihkojliniaihishsiahsieihjniniaishsiahsieihjniniaiyhsioihjtiakkiyhsiyjphsinieiyiahsjtkkjljtisjkkkjnjohsjyiskkiyiajpihieinjyiojpihkoihjtkpihihiejpjlkoihiohsiekohsjtiaihiojzhsktjkkpinjyihiahsjpiojlisidinjpjyisiehskkieieihjtkkiyjphsiainjkjnihhsjohsjpjyiyjkhsiyhsjpiniojyjphsiyiyiniaiyihjphsjkihjptytpolwy
946+
^D
947+
e3b0c44298fc1c149afbf4c8996fb924
948+
```
949+
936950
## Version History
937951

952+
### 0.7.1, 8/21/2020
953+
954+
* Fixed bug where multi-share URs like SLIP-39 were not decoded correctly due to support for multi-part URs being added. Seedtool now supports *either* decoding a multi-part UR or a multi-share UR where the shares are encoded as URs, but not both simultaneously.
955+
* Added example to MANUAL of decoding URs containing SLIP-39 shares.
956+
938957
### 0.7.0, 8/12/2020
939958

940959
* Now using bc-ur for UR encoding/decoding. Support multi-part fountain encoding/decoding.

configure

Lines changed: 9 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.7.0.
3+
# Generated by GNU Autoconf 2.69 for bc-seedtool-cli 0.7.1.
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.7.0'
581-
PACKAGE_STRING='bc-seedtool-cli 0.7.0'
580+
PACKAGE_VERSION='0.7.1'
581+
PACKAGE_STRING='bc-seedtool-cli 0.7.1'
582582
PACKAGE_BUGREPORT=''
583583
PACKAGE_URL=''
584584

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

12941294
if test -n "$ac_init_help"; then
12951295
case $ac_init_help in
1296-
short | recursive ) echo "Configuration of bc-seedtool-cli 0.7.0:";;
1296+
short | recursive ) echo "Configuration of bc-seedtool-cli 0.7.1:";;
12971297
esac
12981298
cat <<\_ACEOF
12991299
@@ -1375,7 +1375,7 @@ fi
13751375
test -n "$ac_init_help" && exit $ac_status
13761376
if $ac_init_version; then
13771377
cat <<\_ACEOF
1378-
bc-seedtool-cli configure 0.7.0
1378+
bc-seedtool-cli configure 0.7.1
13791379
generated by GNU Autoconf 2.69
13801380
13811381
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -1962,7 +1962,7 @@ cat >config.log <<_ACEOF
19621962
This file contains any messages produced by compilers while
19631963
running configure, to aid debugging if configure makes a mistake.
19641964
1965-
It was created by bc-seedtool-cli $as_me 0.7.0, which was
1965+
It was created by bc-seedtool-cli $as_me 0.7.1, which was
19661966
generated by GNU Autoconf 2.69. Invocation command line was
19671967
19681968
$ $0 $@
@@ -5048,7 +5048,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
50485048
# report actual input values of CONFIG_FILES etc. instead of their
50495049
# values after options handling.
50505050
ac_log="
5051-
This file was extended by bc-seedtool-cli $as_me 0.7.0, which was
5051+
This file was extended by bc-seedtool-cli $as_me 0.7.1, which was
50525052
generated by GNU Autoconf 2.69. Invocation command line was
50535053
50545054
CONFIG_FILES = $CONFIG_FILES
@@ -5110,7 +5110,7 @@ _ACEOF
51105110
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
51115111
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
51125112
ac_cs_version="\\
5113-
bc-seedtool-cli config.status 0.7.0
5113+
bc-seedtool-cli config.status 0.7.1
51145114
configured by $0, generated by GNU Autoconf 2.69,
51155115
with options \\"\$ac_cs_config\\"
51165116

configure.ac

Lines changed: 1 addition & 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.7.0])
5+
AC_INIT([bc-seedtool-cli], [0.7.1])
66
AC_CONFIG_SRCDIR([src/seedtool.cpp])
77
AC_CONFIG_HEADERS([src/config.h])
88

src/format-bip39.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ void FormatBIP39::process_input(Params* p) {
2929
string input;
3030

3131
if(p->is_ur_in) {
32-
auto& ur = *(p->ur);
32+
auto& ur = p->ur_shares.front();
3333
auto pos = ur.cbor().begin();
3434
const auto end = ur.cbor().end();
3535

src/format-hex.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ void FormatHex::process_input(Params* p) {
2525
// ONLY in "raw entropy" mode.
2626

2727
if(p->is_ur_in) {
28-
auto& ur = *p->ur;
28+
auto& ur = p->ur_shares.front();
2929
auto pos = ur.cbor().begin();
3030
const auto end = ur.cbor().end();
3131

src/format-slip39.cpp

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -69,18 +69,19 @@ static byte_vector combine(string_vector shares) {
6969

7070
void FormatSLIP39::process_input(Params* p) {
7171
if(p->is_ur_in) {
72-
auto& ur = *p->ur;
73-
auto pos = ur.cbor().begin();
74-
const auto end = ur.cbor().end();
75-
76-
vector<string_vector> array_of_string_arrays;
77-
typedef ur::ByteVector::const_iterator Iter;
78-
auto f = [&array_of_string_arrays](Iter& pos, Iter end) {
79-
decode_array_of_string_arrays(pos, end, array_of_string_arrays);
80-
};
81-
decode_dict_with_birthdate(pos, end, f);
82-
for(auto a: array_of_string_arrays) {
83-
p->shares.push_back(join(a, " "));
72+
for(auto& ur: p->ur_shares) {
73+
auto pos = ur.cbor().begin();
74+
const auto end = ur.cbor().end();
75+
76+
vector<string_vector> array_of_string_arrays;
77+
typedef ur::ByteVector::const_iterator Iter;
78+
auto f = [&array_of_string_arrays](Iter& pos, Iter end) {
79+
decode_array_of_string_arrays(pos, end, array_of_string_arrays);
80+
};
81+
decode_dict_with_birthdate(pos, end, f);
82+
for(auto a: array_of_string_arrays) {
83+
p->shares.push_back(join(a, " "));
84+
}
8485
}
8586
} else {
8687
p->shares = p->get_multiple_arguments();

src/params.cpp

Lines changed: 61 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -252,22 +252,73 @@ void Params::validate_input() {
252252
argp_error(state, "No input provided.");
253253
}
254254

255+
// We have to handle the cases of multi-part URs and multi-share URs, like SLIP39.
256+
// It's also possible that SLIP39 UR shares might themselves be multi-part.
255257
if(is_ur_in) {
256-
auto decoder = ur::URDecoder();
257-
for(auto part: input) {
258-
decoder.receive_part(part);
258+
auto i = input.begin();
259+
ur::URDecoder* decoder = NULL;
260+
261+
enum decoding_state {
262+
starting,
263+
decoding_multi_part,
264+
decoding_multi_share
265+
};
266+
267+
decoding_state ur_state = starting;
268+
269+
while(i != input.end()) {
270+
auto part = *i;
271+
//cout << part << endl;
272+
273+
if(decoder == NULL) {
274+
decoder = new ur::URDecoder();
275+
}
276+
277+
decoder->receive_part(part);
278+
279+
if(decoder->is_failure()) {
280+
argp_error(state, "%s", decoder->result_error().what());
281+
}
282+
283+
if(ur_state == starting) {
284+
if(decoder->is_success()) {
285+
ur_state = decoding_multi_share;
286+
} else {
287+
ur_state = decoding_multi_part;
288+
}
289+
}
290+
291+
if(decoder->is_success()) {
292+
ur_shares.push_back(decoder->result_ur());
293+
}
294+
295+
if(ur_state == decoding_multi_share) {
296+
if(decoder->is_success()) {
297+
delete decoder;
298+
decoder = NULL;
299+
} else {
300+
argp_error(state, "Multi-part UR encountered while decoding multi-share.");
301+
}
302+
} else if(ur_state == decoding_multi_part) {
303+
if(decoder->is_success()) {
304+
delete decoder;
305+
decoder = NULL;
306+
break;
307+
}
308+
}
309+
310+
i++;
259311
}
260-
if(!decoder.is_complete()) {
312+
313+
if(decoder != NULL) {
261314
argp_error(state, "Incomplete UR parts.");
262-
} else if(decoder.is_failure()) {
263-
argp_error(state, "%s", decoder.result_error().what());
264315
} else {
265-
ur = decoder.result_ur();
266-
if(ur->type() == "crypto-seed") {
316+
auto type = ur_shares.front().type();
317+
if(type == "crypto-seed") {
267318
input_format = new FormatHex();
268-
} else if(ur->type() == "crypto-bip39") {
319+
} else if(type == "crypto-bip39") {
269320
input_format = new FormatBIP39();
270-
} else if(ur->type() == "crypto-slip39") {
321+
} else if(type == "crypto-slip39") {
271322
input_format = new FormatSLIP39();
272323
} else {
273324
argp_error(state, "Unknown UR type.");

src/params.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ class Params {
5555

5656
bool is_ur_out = false;
5757
bool is_ur_in = false;
58-
std::optional<ur::UR> ur;
58+
std::vector<ur::UR> ur_shares;
5959
size_t max_fragment_length = 0;
6060
std::optional<size_t> fountain_parts;
6161

0 commit comments

Comments
 (0)