Version 0.5.0
March 29, 2021
Copyright © 2020 by Blockchain Commons, LLC
Licensed under the "BSD-2-Clause Plus Patent License"
Keytool is a CLI tool that implements a data flow graph for deriving cryptocurrency keys and addresses, and signing transactions.
As its inputs, Keytool can be supplied with any of the attributes for the nodes, and as its outputs Keytool can be asked for any of the attributes of the existing or derivable nodes. In this way, Keytool can implement a very short derivation such as "Derive a master HD key from a seed," or a long sequence of derivations from a seed all the way to a payment address, also outputting any of the intermediate steps along the way.
These derivations are expressed visually in the graph below. Each node in the graph is a specific attribute that can be supplied directly on the command line, or derived from its predecessors. Two or more arrows entering a node indicate more than one possible set of inputs can be used to derive it. AND junctors indicate that all predecessor attributes must be supplied, unless a predecessor is marked optional
.
Below is a list of the single-step derivations that Keytool can perform, in the form A <- [B, C, ...]
where A
is the derived attributed and [B, C, ...]
are the attributes required to derive it.
If an attribute is listed more than once, then it has more than one derivation path. If the first derivation path cannot be used, the second one will be tried, and so on.
All the attributes except seed
are either derivable from other attributes or have a default value. The default values are suitable for use with Bitcoin mainnet. If these attributes are supplied on the command line, they override the defaults.
account-derivation-path <- [master-key-fingerprint, purpose, coin-type, account-index]
account-index (default: 0)
account-key <- [account-key-base58]
account-key <- [master-key, account-derivation-path]
account-key-base58 <- [account-key]
account-pub-key <- [account-key]
account-pub-key <- [account-pub-key-base58]
account-pub-key-base58 <- [account-pub-key]
address-derivation-path <- [chain-type-int, address-index]
address-ec-key <- [address-ec-key-wif, network]
address-ec-key <- [address-key]
address-ec-key-wif <- [address-ec-key, network]
address-index (default: 0)
address-key <- [account-key, address-derivation-path], is-derivable
address-key <- [address-key-base58]
address-key <- [master-key, full-address-derivation-path, is-derivable]
address-key-base58 <- [address-key]
address-pkh <- [address-pub-ec-key, asset, network]
address-pub-ec-key <- [address-ec-key]
address-pub-ec-key <- [address-pub-key]
address-pub-key <- [account-pub-key, address-derivation-path, is-derivable]
address-pub-key <- [address-key]
address-pub-key <- [address-pub-key-base58]
address-pub-key-base58 <- [address-pub-key]
address-segwit <- [address-pub-key]
address-sh <- [address-pub-ec-key, asset, network]
asset (default: btc)
chain-type (default: external)
chain-type-int <- [chain-type]
coin-type <- [asset, network]
derived-key <- [key-response]
derived-key-base58 <- [derived-key]
full-address-derivation-path <- [account-derivation-path, address-derivation-path]
is-derivable (default: true)
is-derivable <- [source-key]
key-request <- [key-request-derivation-path, key-request-type, key-request-id, key-request-description, asset, network, is-derivable]
key-request-derivation-path <- [full-address-derivation-path]
key-request-derivation-path <- [key-request]
key-request-description (default: empty)
key-request-description <- [key-request]
key-request-id (default: unique)
key-request-id <- [key-request]
key-request-id <- [key-response]
key-request-type (default: private)
key-request-type <- [key-request]
key-response <- [key-request, source-key]
master-key <- [master-key-base58]
master-key <- [seed, asset, network]
master-key-base58 <- [master-key]
master-key-fingerprint <- [master-key]
network (default: mainnet)
output-descriptor <- [output-type, account-derivation-path, address-derivation-path, account-pub-key]
output-type (default: wpkh)
psbt <- [psbt-signature-request]
psbt <- [psbt-signature-response]
psbt-base64 <- [psbt]
psbt-finalized <- [psbt]
psbt-finalized-base64 <- [psbt-finalized]
psbt-finalized-hex <- [psbt-finalized]
psbt-hex <- [psbt]
psbt-signature-request <- [psbt psbt-signature-request-id psbt-signature-request-description]
psbt-signature-request-description (default: empty)
psbt-signature-request-description <- [psbt-signature-request]
psbt-signature-request-id (default: unique)
psbt-signature-request-id <- [psbt-signature-request]
psbt-signature-request-id <- [psbt-signature-response]
psbt-signature-response <- [psbt-signature-request, psbt-signed]
psbt-signed <- [psbt, address-ec-key]
psbt-signed-base64 <- [psbt-signed]
psbt-signed-hex <- [psbt-signed]
purpose <- [output-type]
seed <- [seed-hex, seed-name (optional), seed-note (optional)]
seed <- [seed-response]
seed-digest <- [seed-request]
seed-digest <- [seed]
seed-hex <- [seed]
seed-name <- [seed]
seed-note <- [seed]
seed-request <- [seed-digest seed-request-id seed-request-description]
seed-request-description (default: empty)
seed-request-description <- [seed-request]
seed-request-id (default: unique)
seed-request-id <- [seed-request]
seed-request-id <- [seed-response]
seed-response <- [seed-request, seed]
source-key <- [master-key]
transaction <- [psbt-finalized]
transaction-hex <- [transaction]
Keytool uses particular formats for input and output attributes:
Type | Description |
---|---|
ADDRESS | An address in Base58 check format. |
BASE58 | An HD private key starting with xprv , xpub or similar. |
BASE64 | Data in Base64 format. |
BIP32_PATH | A series of BIP-32 path elements, possibly starting with the source fingerprint as 8 hex digits and followed by integers, which may optionally be followed by h (for hardened derivation). Example: 1a2b3c4d/44h/0h/0h/0/123 . |
BOOLEAN | true or false . |
ECPRV | An elliptic curve private key in hex format. |
ECPUB | A compressed elliptic curve public key in hex format. |
ENUM | A specific, value from a set of enumerated values. For example network can have the value mainnet or testnet . |
HDKEY | A BIP-32 HD key. |
HEX | A string of hexadecimal digits, case-insensitive. |
INDEX | A non-negative integer. |
INDEX_BOUND | An INDEX or the wildcard * . Note that on the Unix command line, you will need to enclose * in single quotes ('*' ) to avoid shell globbing. |
OUTPUT_DESCRIPTOR | A single-signature output descriptor. |
PSBT | A partially-signed Bitcoin transaction (PSBT). |
REQUEST | A request for a seed, derived HD key, or other service. |
RESPONSE | The response to a corresponding request. |
TEXT | A text annotation. |
TRANSACTION | A raw Bitcoin transaction. |
UUID | A Universally Unique Identifier. |
WIF | An elliptic curve private key in Wallet Import Format. |
The Uniform Resource (UR) format is described here.
Nodes that hold the types below accept input in Uniform Resource (UR) format and others as well. They output their contents in UR format, but other nodes may derive from them that provide output in other formats.
Type | Primary type | Other accepted input types | Nodes for output formats |
---|---|---|---|
SEED | ur:crypto-seed | hex | hex |
HDKEY | ur:crypto-hdkey | Base58 | Base58 |
PSBT | ur:crypto-psbt | Hex, Base64 | Hex, Base64 |
REQUEST | ur:crypto-request | ||
RESPONSE | ur:crypto-response | ||
TRANSACTION | ur:crypto-tx | Hex | Hex |
Usage: keytool [-?V] [--account-derivation-path=BIP32_PATH]
[--account-index=INDEX] [--account-key=HDKEY]
[--account-key-base58=BASE58] [--account-pub-key=HDKEY]
[--account-pub-key-base58=BASE58]
[--address-derivation-path=BIP32_PATH] [--address-ec-key=ECPRV]
[--address-ec-key-wif=WIF] [--address-index=INDEX_BOUND]
[--address-key=HDKEY] [--address-key-base58=BASE58]
[--address-pkh=ADDRESS] [--address-pub-ec-key=ECPUB]
[--address-pub-key=HDKEY] [--address-pub-key-base58=BASE58]
[--address-segwit=ADDRESS] [--address-sh=ADDRESS] [--asset=ENUM btc
| eth] [--chain-type=ENUM internal | external | identity]
[--chain-type-int=INDEX] [--coin-type=INDEX] [--derived-key=HDKEY]
[--derived-key-base58=BASE58]
[--full-address-derivation-path=BIP32_PATH]
[--is-derivable=BOOLEAN] [--key-request=REQUEST]
[--key-request-derivation-path=BIP32_PATH]
[--key-request-description=TEXT] [--key-request-id=UUID]
[--key-request-type=ENUM private | public]
[--key-response=RESPONSE] [--master-key=HDKEY]
[--master-key-base58=BASE58] [--master-key-fingerprint=HEX]
[--network=ENUM mainnet | testnet]
[--output-descriptor=OUTPUT_DESCRIPTOR] [--output-type=ENUM wpkh |
pkh | sh-wpkh] [--psbt=PSBT] [--psbt-base64=BASE64]
[--psbt-finalized=PSBT] [--psbt-finalized-base64=BASE64]
[--psbt-finalized-hex=HEX] [--psbt-hex=HEX]
[--psbt-signature-request=REQUEST]
[--psbt-signature-request-description=TEXT]
[--psbt-signature-request-id=UUID]
[--psbt-signature-response=RESPONSE] [--psbt-signed=PSBT]
[--psbt-signed-base64=BASE64] [--psbt-signed-hex=HEX]
[--purpose=INDEX] [--seed=SEED] [--seed-digest=HEX]
[--seed-hex=HEX] [--seed-name=TEXT] [--seed-note=TEXT]
[--seed-request=REQUEST] [--seed-request-description=TEXT]
[--seed-request-id=UUID] [--seed-response=RESPONSE]
[--source-key=HDKEY] [--transaction=TRANSACTION]
[--transaction-hex=HEX] [--help] [--usage] [--version] INPUT
output-attributes...
$ keytool \
--seed 1eb5338edac6fae54cbb172091ae6c1a \
master-key \
master-key-base58
ur:crypto-hdkey/oxadykaoykaxhdclaeqzwzssbnzczmkneccestferochaeryiheycpynwllertqztasseskslkidjofelfaahdcxuynskidktswzeejshsdldsfykbtloeemfhgluttycxvaennykenbghhfuyampddidavsjpze
xprv9s21ZrQH143K4FAunaSG9eYwrAaaChpSYwYF22eJiZJrz5zSBKTg7NJcFqWR2UZc7EhneSMJhHLmPsKx96UDgv9CdoLc6JfQo3AncKhYNSc
$ keytool \
--master-key ur:crypto-hdkey/oxadykaoykaxhdclaeqzwzssbnzczmkneccestferochaeryiheycpynwllertqztasseskslkidjofelfaahdcxuynskidktswzeejshsdldsfykbtloeemfhgluttycxvaennykenbghhfuyampddidavsjpze \
--address-index 1234 \
address-key
ur:crypto-hdkey/onaoykaxhdclaelthegdiskssarfbatlpeenayuofghsoeenvegmqzmstpgtwksbcywspkroleaaztaahdcxmevdctknhdaonyeypllfmezeksnllgieolyabnfnonfdftidndmtbkwefmfpecbsamoeadlecsghykaeykaeykaewkcfaatdwkaocyselpnldsaycyghsbyngdvojzlywm
$ keytool \
--master-key xprv9s21ZrQH143K4FAunaSG9eYwrAaaChpSYwYF22eJiZJrz5zSBKTg7NJcFqWR2UZc7EhneSMJhHLmPsKx96UDgv9CdoLc6JfQo3AncKhYNSc \
--full-address-derivation-path m/99h/1h/2h/3 \
address-key-base58 \
address-pub-key-base58
xprv9zvzy7RBcHUqSY5uPpz5jMgA4f98yCxW21Qrwg5qQu3GcqTSBsAgpRXfTnmE4SqSbLJVHx4NdWFEc1CzwVps15ynZtFPEtpaNh9uDkd3auw
xpub6DvMNcx5Sf38f2ANVrX66VctcgydNfgMPELTk4VSyEaFVdnajQUwNDr9K54VQ2SRM7gmcQmJcMa23xyWEwU2ehdU9tgFBozSUnLaWJAhmBk
- Note: Since
'
is a UNIX command-line quote mark, BIP32 paths given to Keytool useh
to denote hardened derivations.
for (( i=0; i <= 9; ++i ))
do
keytool \
--network testnet \
--seed e48225bd3c8d508f45a86607a8eca277 \
--address-index $i \
address-index \
full-address-derivation-path \
address-segwit
done
0
3aa00dc3/84h/1h/0h/0/0
tb1qtc425u2januzcjk3x39vp24dwkawsqu8v5jn53
1
3aa00dc3/84h/1h/0h/0/1
tb1qynvun8gs4e4xtegfs4jdymzmt4wynph895dk68
2
3aa00dc3/84h/1h/0h/0/2
tb1qhs4j4ytplrynu8kqmk6v40del62dmklu02lxtv
3
3aa00dc3/84h/1h/0h/0/3
tb1qcdnerx0he0tgwfxfqrjs02wu2q9tny7fc2h936
4
3aa00dc3/84h/1h/0h/0/4
tb1qa2jqhu9ywj2r0ghec00xj6nxdndx22fqqtnwdy
5
3aa00dc3/84h/1h/0h/0/5
tb1qmn454fsvqjg7gytw5xyxf2cc48xag2krjps76w
6
3aa00dc3/84h/1h/0h/0/6
tb1q47e96q9jvl4dm3fmy3j6fwjt8u8mlc2l79dpk6
7
3aa00dc3/84h/1h/0h/0/7
tb1qjgcglx4d4snj4r70l8qxruqjfday4fshraqsed
8
3aa00dc3/84h/1h/0h/0/8
tb1q0kfewchxvyvwtrke35mregekx20keqwkglsh5j
9
3aa00dc3/84h/1h/0h/0/9
tb1q06f6uwt8cnr8t5prkkqv2clnnw4x5ftzdlw0pr
Note the following:
- When more than one output is requested, each output is printed in the order requested on a separate line.
- Supplied results, like
address-index
, or intermediate derived results, likefull-address-derivation-path
can also be requested.
Output descriptors are described here and here. Keytool currently supports pkh
, wpkh
, and sh-wpkh
(wpkh
nested within sh
) output descriptor types.
The address-index
node is set to the wildcard *
so the returned output descriptor indicates that all address indexes are valid. The asterisk is single-quoted '*'
to avoid shell globbing.
This example provides a seed, specifies an output descriptor type of wpkh
, and specifies that any address index is usable. It outputs a descriptor containing the type, the fingerprint of the master key derived from the provided seed, the derivation path of the account key, the account public key, and the derivation path that will be used to derive addresses.
$ keytool \
--seed 1b1454fab426f2729ddcec1b2a6fb539aa2ff0a36d078902994e2fde561d6550 \
--address-index '*' \
output-descriptor
wpkh([01577231/84h/0h/0h]xpub6CaE5t6vuSJpRZ4mUb8SX27bmZcinKzUfpn2ZFMYTK81vvrrA9XJZyT8bypiz7gMsjPnpdAJDaQDwvsErnAYi9ZFbDSSSxKR7PtM8msR29D/0/*)
When providing inputs to Keytool, any input values provided as an empty string are then expected via STDIN:
CLI: $ keytool --seed '' master-key-base58
STDIN: 8935a8068526d84da555cdb741a3b8a8
STDOUT: xprv9s21ZrQH143K3rJgfaUmUCueBxbDT1bbksxayh7ik1nZN41zAy2kQNop8REXEAAwqwes1E8rxk1313tyzsNmMq69h4vDyyrXkmjDZ2Nf3pN
You can of course use shell argument replacement with Seedtool to generate a seed, and from that a master key in one line:
$ keytool --seed `seedtool` master-key
ur:crypto-hdkey/oxadykaoykaxhdclaedynbntlglkzctoueutbenynnwyhhcnfxjotnosbwcpstbdveehiolplstbaxdnesaahdcxhncnjevwcaltahcsamlakptlehattipejswksnrfhfleadcmamhkndmndkledttpjtfpbbme
Because you can provide inputs on STDIN, you can also use the shell to pipe the result of Seedtool to Keytool:
$ seedtool | keytool --seed '' master-key
ur:crypto-hdkey/oxadykaoykaxhdclaeplrliolfpldipdkkatttmslfmswfrftpnljzftrhyndrylknlahfgwwkcnkiayuraahdcxbawegrdtdldmtlfxytkbdkvyfxehztvokowypdlfayuyctchzosamdmtptdpteuroxfrpdyk
You can use Keytool to print out both the seed generated by Seedtool and the master key:
$ seedtool | keytool --seed '' seed master-key
ur:crypto-seed/oyadgdeeaefdttoejnsptegmmwflcscxtpuoswgslycpin
ur:crypto-hdkey/oxadykaoykaxhdclaemeptlffhinplayjocwkokbnemozsfmselunlmhioqdhhrlfzjypmcywzfdzmleghaahdcxayjkasgtdlpasroeotltpreohyiejkkpwdldcecnterftpurcphkgodrhhcmdagyknfydidy
Other scripts can provide all the necessary inputs to keytool:
$ { seedtool && echo 'testnet'; } | keytool --seed '' --network '' master-key
ur:crypto-hdkey/onadykaoykaxhdclaepehscecabainlaytsffhtddsktonvytdrsynytsbtpoyoxpsytmnieonrtcwkogtaahdcxlsvtswoewpghwebgadldrspynepmnytybtprylpkwdvyzmuebtlfsnjeynmupyskahoyaoadehiakklf
Keytool can add a signature to a partially-signed Bitcoin transaction (PSBT).
keytool \
--network testnet \
--psbt "cHNidP8BAMMCAAAAA0DcshmpIS/ZW94f7roto1MhBNhk6Rz/ZaetRRfcedh9AAAAAAD9////wm+mbFIbTYiPlNNhB8P1/vBcwKG/ZryOHMKkL7dSqTYAAAAAAP3///+CmZgUyFrdKNCZUoqfgBhCAFORPdiP/qr0OOt4I5n+CgAAAAAA/f///wJAQg8AAAAAABYAFCBk78yn2RApIqWfuXigrti3WcQRncYQAAAAAAAWABSMyh/Y85oXJKUZQJT+IeAZJk/MeAAAAAAAAQD9PgECAAAABnPYBYJW735g7YMuaFrrK2ZgQj2XELyHukIJmdvOUB4sAAAAAAD+////bmU42jLXSFq3iLHmsyOR/OrF/x0ZQ2lAbecy8CeanlsAAAAAAP7///87WWkGf++EI4Um41R9YUGj00Z0+wvW0fmPYJ+81lWZOAEAAAAA/v///++syYWL4jBkYbhPlOrxJkozfdkL/XJWnhl2nVzVxa2OAAAAAAD+////UAL64CRRErlwBwQM+X5opqpiI0JmpsKs2a1MzGtZh8QAAAAAAP7///8chEjupyVpNkPdCyBE1wpPrS8MGI9EjEGpj7CTgZAXtgAAAAAA/v///wKghgEAAAAAABYAFMzoxnRhxnGxMSMykm4rhwto1dz6vkMPAAAAAAAWABTzi7rfXv1coXc7HvFo2QoeYq4U1E54HAABAR+ghgEAAAAAABYAFMzoxnRhxnGxMSMykm4rhwto1dz6IgYCtKMsZPEI+kb9daMTFeF/+8io6poDvTx+cinpPo9y1EQYDwVpQ1QAAIABAACAAAAAgAAAAAAQAAAAAAEAUgIAAAABbEc0zoXZ/16+PtvwSQ43BytcwpYvO6gGU11xDcaGH7YAAAAAAAEAAAABgEEPAAAAAAAWABQMEbJbdDyzQi5GH1/cPH4QeuPCiwAAAAABAR+AQQ8AAAAAABYAFAwRslt0PLNCLkYfX9w8fhB648KLIgYDcV7jKmCV/4gwmyIZjcVj1LXh1/M4er/DpkPbYiUikt8YDwVpQ1QAAIABAACAAAAAgAAAAACIAAAAAAEAUgIAAAABtvIk4LNoWJem4tfDI5qeVZKR954vLCVJBiqv3pSFR8AAAAAAAAEAAAAB0kEPAAAAAAAWABT93jySCCHYPSeMHxs0jj9i+0UtmAAAAAABAR/SQQ8AAAAAABYAFP3ePJIIIdg9J4wfGzSOP2L7RS2YIgYDhA94BGdguQJPUq61nFoMNrVM4VUaSEJwM7lZcPGyFPUYDwVpQ1QAAIABAACAAAAAgAAAAACGAAAAACICAgFa3FuEwDkszXFDVxN6KU6pVUV/f6d1JSWZ1RsD4CNtGA8FaUNUAACAAQAAgAAAAIAAAAAAiQAAAAAiAgJZ8CLw/Bdus5hyuOPx7cnFfkBkRoTavnS6BRAHi5GOLBgPBWlDVAAAgAEAAIAAAACAAQAAAFIAAAAA" \
--address-ec-key-wif "cSyLgU8rSvYNU1j6XR2vo5ebSQqza7PR9iFNtkkYrFMwyB5or5gH" \
psbt-signed
ur:crypto-psbt/hkaarfjojkidjyzmadaesraoaeaeaeaxfzuoprcfptcldltahpuectwyrddpotguclaatpiewlcezmihospmfechuokktpkiaeaeaeaeaezczmzmzmsajloljzgmcwgtlomymwtehsatsrykzewthhrtoyrsiyrfmncesaoxdlrlgmptenaeaeaeaeaezczmzmzmlfnlmkbbsphtutdetinlgmlenelacsfwaegumefstpmyzepkwketwmkscnnlzebkaeaeaeaeaezczmzmzmaofzfwbsaeaeaeaeaecmaebbcxiewssfostabedtcponnerhksnbpltprlhkssbyntswbeaeaeaeaeaecmaebblksgcttpwfnychdkoncffzmwzeclvtcfdsgwsfksaeaeaeaeaeadaezcfmadaoaeaeaeamjktpahlfhfwskbhnwelsdmishtwmdniyhnfwfsmsberfltrdfwasnluytogdckdwaeaeaeaeaezezmzmzmjtihettneytsfdhtrllopavaqdcnmeztwdskzmcacffxinfzjnvdeywtdinynnhpaeaeaeaeaezezmzmzmfrhkinamlbwslrcnlpdsvlghkihsfpottefgjyzobdtbttytmyhnnerftbgonletadaeaeaeaezezmzmzmwspssolpluvodyiehsrogwmwwdwndsgeeokitabdzcjphfnncfkonthhtlskpmmnaeaeaeaeaezezmzmzmgdaozsvtdkgybgrhjoataabnytkbisolpkidcnfwiyolsapstapmgssfjehkltssaeaeaeaeaezezmzmzmcelrfdwyosdainenfxutbdcxfytsbkgwpmdlbncsmyfylkfpptmypfmulymhchrpaeaeaeaeaezezmzmzmaonblnadaeaeaeaeaecmaebbsfvsswjyhsswjspaehcneymojtdnltbdistluozsrnfxbsaeaeaeaeaecmaebbwflurdurhyzchhoyktfrckwnistabkckidplbbtyglksceaeadadctnblnadaeaeaeaeaecmaebbsfvsswjyhsswjspaehcneymojtdnltbdistluozscpaoaoqzotdwiewnayzsfgzckpotbwbzvylbzosppdwdnyaxryfnkbjpdtwlfmmyjptyfyfddyfeaoclaevendbaiazmrdjtisgwinjsfxjeetosrocerdhglazcpfksgesnbgsefedafemhhnaocxdebkoniypyoxrfksmecyenjppfsbrecsadldfgbntastdeutbyptylbymwttpsjzadcpamaoqzotdwiewnayzsfgzckpotbwbzvylbzosppdwdnyaxryfnkbjpdtwlfmmyjptyfycsbsahinfxghaeaelaadaeaelaaeaeaelaaeaeaeaebeaeaeaeaeadaegmaoaeaeaeadjzfleetolptazmhyrnfmuywtgabaematdnhhsamtdlfrpdamguhljsbtswlnctrpaeaeaeaeaeadaeaeaeadlafpbsaeaeaeaeaecmaebbbnbyprhpjyfnqdfwdmfgctheuofnkbbeknvlsaluaeaeaeaeadadctlafpbsaeaeaeaeaecmaebbbnbyprhpjyfnqdfwdmfgctheuofnkbbeknvlsalucpamaxjshyvldrhnmdzmlodyndcpcflgskiatyrevytswfetknrssrolfxuyiddacpmourcsbsahinfxghaeaelaadaeaelaaeaeaelaaeaeaeaeloaeaeaeaeadaegmaoaeaeaeadrpwzdkvtqdishdmsolvotssrcnnynngomomeylnndldwdagaamdrpeuemwlpflrtaeaeaeaeaeadaeaeaeadtdfpbsaeaeaeaeaecmaebbzcuefnmoaycltpfsdilkctcweemnfhidzofedpmkaeaeaeaeadadcttdfpbsaeaeaeaeaecmaebbzcuefnmoaycltpfsdilkctcweemnfhidzofedpmkcpamaxlrbsksaaiohnrhaogwgmplrenshtbnenregsvygocyfdfwjoeorhhkjownprbbykcsbsahinfxghaeaelaadaeaelaaeaeaelaaeaeaeaelnaeaeaeaecpaoaoadhtuohplrrtesdwsnjsfxhgbwkndtglptgofelblboskpdadanltlcwaxvtcnjncsbsahinfxghaeaelaadaeaelaaeaeaelaaeaeaeaeldaeaeaeaecpaoaohkwtcpwtztchjtqdmkjprovlwnwesoskkbfziefglrtnrnjyrdahbeatlumemndwcsbsahinfxghaeaelaadaeaelaaeaeaelaadaeaeaegmaeaeaeaerdinonfp
Once a transaction is fully signed, Keytool can extract the raw Bitcoin transaction, ready to be placed on the network.
keytool \
--psbt "cHNidP8BAMMCAAAAA0DcshmpIS/ZW94f7roto1MhBNhk6Rz/ZaetRRfcedh9AAAAAAD9////wm+mbFIbTYiPlNNhB8P1/vBcwKG/ZryOHMKkL7dSqTYAAAAAAP3///+CmZgUyFrdKNCZUoqfgBhCAFORPdiP/qr0OOt4I5n+CgAAAAAA/f///wJAQg8AAAAAABYAFCBk78yn2RApIqWfuXigrti3WcQRncYQAAAAAAAWABSMyh/Y85oXJKUZQJT+IeAZJk/MeAAAAAAAAQD9PgECAAAABnPYBYJW735g7YMuaFrrK2ZgQj2XELyHukIJmdvOUB4sAAAAAAD+////bmU42jLXSFq3iLHmsyOR/OrF/x0ZQ2lAbecy8CeanlsAAAAAAP7///87WWkGf++EI4Um41R9YUGj00Z0+wvW0fmPYJ+81lWZOAEAAAAA/v///++syYWL4jBkYbhPlOrxJkozfdkL/XJWnhl2nVzVxa2OAAAAAAD+////UAL64CRRErlwBwQM+X5opqpiI0JmpsKs2a1MzGtZh8QAAAAAAP7///8chEjupyVpNkPdCyBE1wpPrS8MGI9EjEGpj7CTgZAXtgAAAAAA/v///wKghgEAAAAAABYAFMzoxnRhxnGxMSMykm4rhwto1dz6vkMPAAAAAAAWABTzi7rfXv1coXc7HvFo2QoeYq4U1E54HAABAR+ghgEAAAAAABYAFMzoxnRhxnGxMSMykm4rhwto1dz6IgICtKMsZPEI+kb9daMTFeF/+8io6poDvTx+cinpPo9y1ERIMEUCIQDkmw5j/7puaE9pcUNrOKe4HLpXgP2weErNEsFFJUWQYAIgKAqlZqukvHiRGjZysMu1GAGJRgzZxyjdEan3EZTRrGwBIgYCtKMsZPEI+kb9daMTFeF/+8io6poDvTx+cinpPo9y1EQYDwVpQ1QAAIABAACAAAAAgAAAAAAQAAAAAAEAUgIAAAABbEc0zoXZ/16+PtvwSQ43BytcwpYvO6gGU11xDcaGH7YAAAAAAAEAAAABgEEPAAAAAAAWABQMEbJbdDyzQi5GH1/cPH4QeuPCiwAAAAABAR+AQQ8AAAAAABYAFAwRslt0PLNCLkYfX9w8fhB648KLIgIDcV7jKmCV/4gwmyIZjcVj1LXh1/M4er/DpkPbYiUikt9IMEUCIQDeFzLuE1DRcQEvwJevA+kf8m8Ay9LJbnoP4qarthudHQIgYyk2ZQEIbvXSFDh37tTG9u2T247SbCfzYNsbLFW4AVYBIgYDcV7jKmCV/4gwmyIZjcVj1LXh1/M4er/DpkPbYiUikt8YDwVpQ1QAAIABAACAAAAAgAAAAACIAAAAAAEAUgIAAAABtvIk4LNoWJem4tfDI5qeVZKR954vLCVJBiqv3pSFR8AAAAAAAAEAAAAB0kEPAAAAAAAWABT93jySCCHYPSeMHxs0jj9i+0UtmAAAAAABAR/SQQ8AAAAAABYAFP3ePJIIIdg9J4wfGzSOP2L7RS2YIgIDhA94BGdguQJPUq61nFoMNrVM4VUaSEJwM7lZcPGyFPVHMEQCIFALHbiTldYsUElBStxS550LVScYBmmsgRrWGWPVfr7EAiAA1kGB/iscnQrbJnKtBhLEDE4MsCfiLjQNNakjB+9MjgEiBgOED3gEZ2C5Ak9SrrWcWgw2tUzhVRpIQnAzuVlw8bIU9RgPBWlDVAAAgAEAAIAAAACAAAAAAIYAAAAAIgICAVrcW4TAOSzNcUNXE3opTqlVRX9/p3UlJZnVGwPgI20YDwVpQ1QAAIABAACAAAAAgAAAAACJAAAAACICAlnwIvD8F26zmHK44/HtycV+QGRGhNq+dLoFEAeLkY4sGA8FaUNUAACAAQAAgAAAAIABAAAAUgAAAAA=" \
transaction \
transaction-hex
ur:crypto-tx/hkaoayaoaeaeaeaeadaxfzuoprcfptcldltahpuectwyrddpotguclaatpiewlcezmihospmfechuokktpkiaeaeaeaeaezczmzmzmsajloljzgmcwgtlomymwtehsatsrykzewthhrtoyrsiyrfmncesaoxdlrlgmptenaeaeaeaeaezczmzmzmlfnlmkbbsphtutdetinlgmlenelacsfwaegumefstpmyzepkwketwmkscnnlzebkaeaeaeaeaezczmzmzmaofzfwbsaeaeaeaeaecmaebbcxiewssfostabedtcponnerhksnbpltprlhkssbyntswbeaeaeaeaeaecmaebblksgcttpwfnychdkoncffzmwzeclvtcfdsgwsfksaofddyfeaoclaevendbaiazmrdjtisgwinjsfxjeetosrocerdhglazcpfksgesnbgsefedafemhhnaocxdebkoniypyoxrfksmecyenjppfsbrecsadldfgbntastdeutbyptylbymwttpsjzadclaoqzotdwiewnayzsfgzckpotbwbzvylbzosppdwdnyaxryfnkbjpdtwlfmmyjptyfyaofddyfeaoclaeuecheywybwgdttjsaddlrtmspeaxwlctwzjlaesbtdsojtknbsvoolpyrpcwntcaaocxiadtenihadayjtyktdbbetktwytyswynwemuuymntdjzdiwfhnuycwdwgoroadhfadclaxjshyvldrhnmdzmlodyndcpcflgskiatyrevytswfetknrssrolfxuyiddacpmouraofldyfyaocxgdbdcaromumdtbdwgdgafpgeuogmvdntbdgodicsaminpslycytbcfiatlkbrnssaocxaetbfplyzedncentbkuydsjppmambgssbnglbnpfdivodmeebtecptcnatwsgsmnadclaxlrbsksaaiohnrhaogwgmplrenshtbnenregsvygocyfdfwjoeorhhkjownprbbykaeaeaeaegyzswkhd
0200000000010340dcb219a9212fd95bde1feeba2da3532104d864e91cff65a7ad4517dc79d87d0000000000fdffffffc26fa66c521b4d888f94d36107c3f5fef05cc0a1bf66bc8e1cc2a42fb752a9360000000000fdffffff82999814c85add28d099528a9f8018420053913dd88ffeaaf438eb782399fe0a0000000000fdffffff0240420f00000000001600142064efcca7d9102922a59fb978a0aed8b759c4119dc61000000000001600148cca1fd8f39a1724a5194094fe21e019264fcc7802483045022100e49b0e63ffba6e684f6971436b38a7b81cba5780fdb0784acd12c145254590600220280aa566aba4bc78911a3672b0cbb5180189460cd9c728dd11a9f71194d1ac6c012102b4a32c64f108fa46fd75a31315e17ffbc8a8ea9a03bd3c7e7229e93e8f72d44402483045022100de1732ee1350d171012fc097af03e91ff26f00cbd2c96e7a0fe2a6abb61b9d1d02206329366501086ef5d2143877eed4c6f6ed93db8ed26c27f360db1b2c55b80156012103715ee32a6095ff88309b22198dc563d4b5e1d7f3387abfc3a643db62252292df024730440220500b1db89395d62c5049414adc52e79d0b5527180669ac811ad61963d57ebec4022000d64181fe2b1c9d0adb2672ad0612c40c4e0cb027e22e340d35a92307ef4c8e012103840f78046760b9024f52aeb59c5a0c36b54ce1551a48427033b95970f1b214f500000000
Keytool can be invoked repeatedly to add multiple signatures to a PSBT and then extract the final transaction, with the progessively-signed PSBT handed from one invocation to the next using the Unix pipe operator (|
)
PSBT_TO_SIGN=cHNidP8BAMMCAAAAA0DcshmpIS/ZW94f7roto1MhBNhk6Rz/ZaetRRfcedh9AAAAAAD9////wm+mbFIbTYiPlNNhB8P1/vBcwKG/ZryOHMKkL7dSqTYAAAAAAP3///+CmZgUyFrdKNCZUoqfgBhCAFORPdiP/qr0OOt4I5n+CgAAAAAA/f///wJAQg8AAAAAABYAFCBk78yn2RApIqWfuXigrti3WcQRncYQAAAAAAAWABSMyh/Y85oXJKUZQJT+IeAZJk/MeAAAAAAAAQD9PgECAAAABnPYBYJW735g7YMuaFrrK2ZgQj2XELyHukIJmdvOUB4sAAAAAAD+////bmU42jLXSFq3iLHmsyOR/OrF/x0ZQ2lAbecy8CeanlsAAAAAAP7///87WWkGf++EI4Um41R9YUGj00Z0+wvW0fmPYJ+81lWZOAEAAAAA/v///++syYWL4jBkYbhPlOrxJkozfdkL/XJWnhl2nVzVxa2OAAAAAAD+////UAL64CRRErlwBwQM+X5opqpiI0JmpsKs2a1MzGtZh8QAAAAAAP7///8chEjupyVpNkPdCyBE1wpPrS8MGI9EjEGpj7CTgZAXtgAAAAAA/v///wKghgEAAAAAABYAFMzoxnRhxnGxMSMykm4rhwto1dz6vkMPAAAAAAAWABTzi7rfXv1coXc7HvFo2QoeYq4U1E54HAABAR+ghgEAAAAAABYAFMzoxnRhxnGxMSMykm4rhwto1dz6IgYCtKMsZPEI+kb9daMTFeF/+8io6poDvTx+cinpPo9y1EQYDwVpQ1QAAIABAACAAAAAgAAAAAAQAAAAAAEAUgIAAAABbEc0zoXZ/16+PtvwSQ43BytcwpYvO6gGU11xDcaGH7YAAAAAAAEAAAABgEEPAAAAAAAWABQMEbJbdDyzQi5GH1/cPH4QeuPCiwAAAAABAR+AQQ8AAAAAABYAFAwRslt0PLNCLkYfX9w8fhB648KLIgYDcV7jKmCV/4gwmyIZjcVj1LXh1/M4er/DpkPbYiUikt8YDwVpQ1QAAIABAACAAAAAgAAAAACIAAAAAAEAUgIAAAABtvIk4LNoWJem4tfDI5qeVZKR954vLCVJBiqv3pSFR8AAAAAAAAEAAAAB0kEPAAAAAAAWABT93jySCCHYPSeMHxs0jj9i+0UtmAAAAAABAR/SQQ8AAAAAABYAFP3ePJIIIdg9J4wfGzSOP2L7RS2YIgYDhA94BGdguQJPUq61nFoMNrVM4VUaSEJwM7lZcPGyFPUYDwVpQ1QAAIABAACAAAAAgAAAAACGAAAAACICAgFa3FuEwDkszXFDVxN6KU6pVUV/f6d1JSWZ1RsD4CNtGA8FaUNUAACAAQAAgAAAAIAAAAAAiQAAAAAiAgJZ8CLw/Bdus5hyuOPx7cnFfkBkRoTavnS6BRAHi5GOLBgPBWlDVAAAgAEAAIAAAACAAQAAAFIAAAAA
KEY_1=cSyLgU8rSvYNU1j6XR2vo5ebSQqza7PR9iFNtkkYrFMwyB5or5gH
KEY_2=cVok3VJ1fGhdT2yAndKHFWvgTbDsdVFXb8xE9rsAcQASuS4JV9HG
KEY_3=cMaqfcb16JjrCdfYTfT2vRKFpGjdAugAucEAxw3VuhN91XgjKqzF
keytool --network testnet --psbt ${PSBT_TO_SIGN} --address-ec-key-wif ${KEY_1} psbt-signed \
| keytool --network testnet --psbt '' --address-ec-key-wif ${KEY_2} psbt-signed \
| keytool --network testnet --psbt '' --address-ec-key-wif ${KEY_3} psbt-signed \
| keytool --psbt '' transaction-hex
0200000000010340dcb219a9212fd95bde1feeba2da3532104d864e91cff65a7ad4517dc79d87d0000000000fdffffffc26fa66c521b4d888f94d36107c3f5fef05cc0a1bf66bc8e1cc2a42fb752a9360000000000fdffffff82999814c85add28d099528a9f8018420053913dd88ffeaaf438eb782399fe0a0000000000fdffffff0240420f00000000001600142064efcca7d9102922a59fb978a0aed8b759c4119dc61000000000001600148cca1fd8f39a1724a5194094fe21e019264fcc7802483045022100e49b0e63ffba6e684f6971436b38a7b81cba5780fdb0784acd12c145254590600220280aa566aba4bc78911a3672b0cbb5180189460cd9c728dd11a9f71194d1ac6c012102b4a32c64f108fa46fd75a31315e17ffbc8a8ea9a03bd3c7e7229e93e8f72d44402483045022100de1732ee1350d171012fc097af03e91ff26f00cbd2c96e7a0fe2a6abb61b9d1d02206329366501086ef5d2143877eed4c6f6ed93db8ed26c27f360db1b2c55b80156012103715ee32a6095ff88309b22198dc563d4b5e1d7f3387abfc3a643db62252292df024730440220500b1db89395d62c5049414adc52e79d0b5527180669ac811ad61963d57ebec4022000d64181fe2b1c9d0adb2672ad0612c40c4e0cb027e22e340d35a92307ef4c8e012103840f78046760b9024f52aeb59c5a0c36b54ce1551a48427033b95970f1b214f500000000
Generate a seed using Seedtool:
seedtool
581fbdbf6b3eeababae7e7b51e3aabea
Generate the digest of the seed:
keytool \
--seed 581fbdbf6b3eeababae7e7b51e3aabea \
seed-digest
faf717696382dff46fe473c75936a7df3990cd56e438aaad9953e94fba7f857f
Generate a request for the seed with the given digest, printing the request and the request ID:
keytool \
--seed-digest faf717696382dff46fe473c75936a7df3990cd56e438aaad9953e94fba7f857f \
seed-request \
seed-request-id
ur:crypto-request/oeadtpdagdvacyoegodnaxfdisqddwtlhdbwoxvejeaotaadwkoyadtaaohdhdcxzsylchinialfurwkjlvejksthkenosuresmhsnhfveetpkpmnlguwlgwrdlblplbvsrnleba
e61aa255-2b03-4868-b32c-d55813a4e46b
Generate a response to the above request, printing the request and the request ID:
keytool \
--seed-request ur:crypto-request/oeadtpdagdvacyoegodnaxfdisqddwtlhdbwoxvejeaotaadwkoyadtaaohdhdcxzsylchinialfurwkjlvejksthkenosuresmhsnhfveetpkpmnlguwlgwrdlblplbvsrnleba \
--seed 581fbdbf6b3eeababae7e7b51e3aabea \
seed-response \
seed-request-id
ur:crypto-response/oeadtpdagdvacyoegodnaxfdisqddwtlhdbwoxvejeaotaaddwoyadgdhdctryrsjefmwdrdrdvdvdreckftpywdwmdstlrs
e61aa255-2b03-4868-b32c-d55813a4e46b
Extract the hex seed from the above response:
keytool \
--seed-response ur:crypto-response/oeadtpdagdvacyoegodnaxfdisqddwtlhdbwoxvejeaotaaddwoyadgdhdctryrsjefmwdrdrdvdvdreckftpywdwmdstlrs \
seed-hex
581fbdbf6b3eeababae7e7b51e3aabea
Generate a master HD key from the above seed:
keytool \
--seed 581fbdbf6b3eeababae7e7b51e3aabea \
master-key
ur:crypto-hdkey/oxadykaoykaxhdclaeaozmfxfpvdvwmulklywyatdahypmknahkoaoiepkwztkidwevosbsoqdhgltnngoaahdcxdeeyoevetdtpehlslyaaoyhfkideiygytetkvdmechvokptnkoltgojzdllpfwpkrpmtjkhy
Get a testnet account derivation path for the master key:
keytool \
--network testnet \
--master-key ur:crypto-hdkey/oxadykaoykaxhdclaeaozmfxfpvdvwmulklywyatdahypmknahkoaoiepkwztkidwevosbsoqdhgltnngoaahdcxdeeyoevetdtpehlslyaaoyhfkideiygytetkvdmechvokptnkoltgojzdllpfwpkrpmtjkhy \
account-derivation-path
0fd09078/84h/1h/0h
Generate a request for a public key derived from the master key, printing the request and the request ID:
keytool \
--key-request-type public \
--key-request-derivation-path 0fd09078/84h/1h/0h \
key-request \
key-request-id
ur:crypto-request/oeadtpdagdhkckiepsgwqzfyoxnnmhgspfhtoerylraotaadykoeadwkaotaaddyoeadlncsghykadykaeykaocybstimhksfwrlosee
591e64ac-4fb4-44a4-9e90-4cb05aa2bd84
Generate a response for the requested derived key.
src/keytool \
--key-request ur:crypto-request/oeadtpdagdhkckiepsgwqzfyoxnnmhgspfhtoerylraotaadykoeadwkaotaaddyoeadlncsghykadykaeykaocybstimhksfwrlosee \
--source-key ur:crypto-hdkey/oxadykaoykaxhdclaeaozmfxfpvdvwmulklywyatdahypmknahkoaoiepkwztkidwevosbsoqdhgltnngoaahdcxdeeyoevetdtpehlslyaaoyhfkideiygytetkvdmechvokptnkoltgojzdllpfwpkrpmtjkhy \
key-response
ur:crypto-response/oeadtpdagdhkckiepsgwqzfyoxnnmhgspfhtoerylraotaaddloxaxhdclaondcfnsctgmqzgmcnpyurahykcfjklkcnjeolcfkimhattbkgglmtjlpddrwpzcktaahdcxrftpgmaoayaefgzmplesjskicmlamktnhgssmucnrytocmcftacxwlcedelneelyamoeadlncsghykadykaeykaocybstimhksaycywtwpeoeylgcnfysp
From the response, extract the key in UR and Base58 formats, and the request ID:
keytool \
--key-response ur:crypto-response/oeadtpdagdhkckiepsgwqzfyoxnnmhgspfhtoerylraotaaddloxaxhdclaondcfnsctgmqzgmcnpyurahykcfjklkcnjeolcfkimhattbkgglmtjlpddrwpzcktaahdcxrftpgmaoayaefgzmplesjskicmlamktnhgssmucnrytocmcftacxwlcedelneelyamoeadlncsghykadykaeykaocybstimhksaycywtwpeoeylgcnfysp \
derived-key \
derived-key-base58 \
key-request-id
ur:crypto-hdkey/oxaxhdclaondcfnsctgmqzgmcnpyurahykcfjklkcnjeolcfkimhattbkgglmtjlpddrwpzcktaahdcxrftpgmaoayaefgzmplesjskicmlamktnhgssmucnrytocmcftacxwlcedelneelyamoeadlncsghykadykaeykaocybstimhksaycywtwpeoeyjohkterk
xpub6DRUbxFn5yqrAkKgnsUNjPcbw5NtFjQnRNK4ytXwCxMKv3rks66xPKWK5YBUy9sDddCpta7FexygbmKUp7shSKeMRk1cWeDQSXvGyvX9s1i
591e64ac-4fb4-44a4-9e90-4cb05aa2bd84
This example produces the same finished transaction as the signing example above, but uses ur:crypto-request
and ur:crypto-response
in the same manner that airgapped devices would use them.
Each of the three phases of the example repeats these three steps, one for each signing key:
- Generate a
ur:crypto-request
that requests signing of the unfinished PSBT, - Respond to the request by generating a
ur:crypto-response
containing the PSBT with one or more outputs signed by the provided key, and - Extract a
ur:crypto-psbt
from the response, ready to be put into another signature request or extracted to a finalized transaction.
PSBT_TO_SIGN=cHNidP8BAMMCAAAAA0DcshmpIS/ZW94f7roto1MhBNhk6Rz/ZaetRRfcedh9AAAAAAD9////wm+mbFIbTYiPlNNhB8P1/vBcwKG/ZryOHMKkL7dSqTYAAAAAAP3///+CmZgUyFrdKNCZUoqfgBhCAFORPdiP/qr0OOt4I5n+CgAAAAAA/f///wJAQg8AAAAAABYAFCBk78yn2RApIqWfuXigrti3WcQRncYQAAAAAAAWABSMyh/Y85oXJKUZQJT+IeAZJk/MeAAAAAAAAQD9PgECAAAABnPYBYJW735g7YMuaFrrK2ZgQj2XELyHukIJmdvOUB4sAAAAAAD+////bmU42jLXSFq3iLHmsyOR/OrF/x0ZQ2lAbecy8CeanlsAAAAAAP7///87WWkGf++EI4Um41R9YUGj00Z0+wvW0fmPYJ+81lWZOAEAAAAA/v///++syYWL4jBkYbhPlOrxJkozfdkL/XJWnhl2nVzVxa2OAAAAAAD+////UAL64CRRErlwBwQM+X5opqpiI0JmpsKs2a1MzGtZh8QAAAAAAP7///8chEjupyVpNkPdCyBE1wpPrS8MGI9EjEGpj7CTgZAXtgAAAAAA/v///wKghgEAAAAAABYAFMzoxnRhxnGxMSMykm4rhwto1dz6vkMPAAAAAAAWABTzi7rfXv1coXc7HvFo2QoeYq4U1E54HAABAR+ghgEAAAAAABYAFMzoxnRhxnGxMSMykm4rhwto1dz6IgYCtKMsZPEI+kb9daMTFeF/+8io6poDvTx+cinpPo9y1EQYDwVpQ1QAAIABAACAAAAAgAAAAAAQAAAAAAEAUgIAAAABbEc0zoXZ/16+PtvwSQ43BytcwpYvO6gGU11xDcaGH7YAAAAAAAEAAAABgEEPAAAAAAAWABQMEbJbdDyzQi5GH1/cPH4QeuPCiwAAAAABAR+AQQ8AAAAAABYAFAwRslt0PLNCLkYfX9w8fhB648KLIgYDcV7jKmCV/4gwmyIZjcVj1LXh1/M4er/DpkPbYiUikt8YDwVpQ1QAAIABAACAAAAAgAAAAACIAAAAAAEAUgIAAAABtvIk4LNoWJem4tfDI5qeVZKR954vLCVJBiqv3pSFR8AAAAAAAAEAAAAB0kEPAAAAAAAWABT93jySCCHYPSeMHxs0jj9i+0UtmAAAAAABAR/SQQ8AAAAAABYAFP3ePJIIIdg9J4wfGzSOP2L7RS2YIgYDhA94BGdguQJPUq61nFoMNrVM4VUaSEJwM7lZcPGyFPUYDwVpQ1QAAIABAACAAAAAgAAAAACGAAAAACICAgFa3FuEwDkszXFDVxN6KU6pVUV/f6d1JSWZ1RsD4CNtGA8FaUNUAACAAQAAgAAAAIAAAAAAiQAAAAAiAgJZ8CLw/Bdus5hyuOPx7cnFfkBkRoTavnS6BRAHi5GOLBgPBWlDVAAAgAEAAIAAAACAAQAAAFIAAAAA
KEY_1=cSyLgU8rSvYNU1j6XR2vo5ebSQqza7PR9iFNtkkYrFMwyB5or5gH
KEY_2=cVok3VJ1fGhdT2yAndKHFWvgTbDsdVFXb8xE9rsAcQASuS4JV9HG
KEY_3=cMaqfcb16JjrCdfYTfT2vRKFpGjdAugAucEAxw3VuhN91XgjKqzF
REQUEST_1=`keytool --psbt "${PSBT_TO_SIGN}" psbt-signature-request`
RESPONSE_1=`keytool --network testnet --address-ec-key-wif ${KEY_1} --psbt-signature-request ${REQUEST_1} psbt-signature-response`
PSBT_1=`keytool --psbt-signature-response ${RESPONSE_1} psbt`
REQUEST_2=`keytool --psbt ${PSBT_1} psbt-signature-request`
RESPONSE_2=`keytool --network testnet --address-ec-key-wif ${KEY_2} --psbt-signature-request ${REQUEST_2} psbt-signature-response`
PSBT_2=`keytool --psbt-signature-response ${RESPONSE_2} psbt`
REQUEST_3=`keytool --psbt ${PSBT_2} psbt-signature-request`
RESPONSE_3=`keytool --network testnet --address-ec-key-wif ${KEY_3} --psbt-signature-request ${REQUEST_3} psbt-signature-response`
PSBT_3=`keytool --psbt-signature-response ${RESPONSE_3} psbt`
keytool --psbt ${PSBT_3} transaction-hex
0200000000010340dcb219a9212fd95bde1feeba2da3532104d864e91cff65a7ad4517dc79d87d0000000000fdffffffc26fa66c521b4d888f94d36107c3f5fef05cc0a1bf66bc8e1cc2a42fb752a9360000000000fdffffff82999814c85add28d099528a9f8018420053913dd88ffeaaf438eb782399fe0a0000000000fdffffff0240420f00000000001600142064efcca7d9102922a59fb978a0aed8b759c4119dc61000000000001600148cca1fd8f39a1724a5194094fe21e019264fcc7802483045022100e49b0e63ffba6e684f6971436b38a7b81cba5780fdb0784acd12c145254590600220280aa566aba4bc78911a3672b0cbb5180189460cd9c728dd11a9f71194d1ac6c012102b4a32c64f108fa46fd75a31315e17ffbc8a8ea9a03bd3c7e7229e93e8f72d44402483045022100de1732ee1350d171012fc097af03e91ff26f00cbd2c96e7a0fe2a6abb61b9d1d02206329366501086ef5d2143877eed4c6f6ed93db8ed26c27f360db1b2c55b80156012103715ee32a6095ff88309b22198dc563d4b5e1d7f3387abfc3a643db62252292df024730440220500b1db89395d62c5049414adc52e79d0b5527180669ac811ad61963d57ebec4022000d64181fe2b1c9d0adb2672ad0612c40c4e0cb027e22e340d35a92307ef4c8e012103840f78046760b9024f52aeb59c5a0c36b54ce1551a48427033b95970f1b214f500000000
Hierarchical Deterministic (HD) keys contain a field called the "chain code" that enables a key to be used to derive further keys. If the chain code is omitted, the key can still be used to produce Elliptic Curve (EC) keys used to verify transactions (or sign them if it is private key), but no further HD keys can be derived from it. The ur:crypto-hdkey
format supports such "non-derivable" keys, and Keytool enables generating and using such keys via the is-derivable
node. The is-derivable
node contains a boolean value that, if set to false
, causes keys derived from the address-key
or derived-key
nodes to be non-derivable. In addition, setting is-derivable
to false
causes generated ur:crypto-requests
for keys to become requests for non-derivable keys, and causes generated ur:crypto-response
s to produce non-derivable keys.
The Base58 format for HD keys only supports derivable keys, so Keytool will produce an error if asked to produce a Base58 key from a non-derivable HD key.
Generate derivable and non-derivable versions of a key:
keytool \
--seed 581fbdbf6b3eeababae7e7b51e3aabea \
address-key
ur:crypto-hdkey/onaoykaxhdclaebkmdcfjtdmaacybbesmskbolvdvalbdkgachhtlefpcmotltoezsynjlehidmokeaahdcxjsvdzechamzcosfhsrksyasnurgturdposknjsteaomulkfswnrfaenbclhtzcwnamoeadlecsghykaeykaeykaewkaewkaocybstimhksaycytssgtkwkksskatmk
keytool \
--seed 581fbdbf6b3eeababae7e7b51e3aabea \
--is-derivable false \
address-key
ur:crypto-hdkey/oxaoykaxhdclaebkmdcfjtdmaacybbesmskbolvdvalbdkgachhtlefpcmotltoezsynjlehidmokeamoeadlecsghykaeykaeykaewkaewkaocybstimhksaycytssgtkwkvatnuylf
Have Keytool report whether the keys generated above are or are not derivable:
keytool \
--source-key ur:crypto-hdkey/onaoykaxhdclaebkmdcfjtdmaacybbesmskbolvdvalbdkgachhtlefpcmotltoezsynjlehidmokeaahdcxjsvdzechamzcosfhsrksyasnurgturdposknjsteaomulkfswnrfaenbclhtzcwnamoeadlecsghykaeykaeykaewkaewkaocybstimhksaycytssgtkwkksskatmk \
is-derivable
true
keytool \
--source-key ur:crypto-hdkey/oxaoykaxhdclaebkmdcfjtdmaacybbesmskbolvdvalbdkgachhtlefpcmotltoezsynjlehidmokeamoeadlecsghykaeykaeykaewkaewkaocybstimhksaycytssgtkwkvatnuylf \
is-derivable
false
Attempt to derive a key from the derivable and non-derivable keys generated above:
keytool \
--source-key ur:crypto-hdkey/onaoykaxhdclaebkmdcfjtdmaacybbesmskbolvdvalbdkgachhtlefpcmotltoezsynjlehidmokeaahdcxjsvdzechamzcosfhsrksyasnurgturdposknjsteaomulkfswnrfaenbclhtzcwnamoeadlecsghykaeykaeykaewkaewkaocybstimhksaycytssgtkwkksskatmk \
--key-request-derivation-path 0 \
derived-key
ur:crypto-hdkey/onaoykaxhdclaebzgybzdkvdctayyknntdsrgdpfurgmpyjthlkpzeynzthdislaetutdicsjtneuoaahdcxresaftkttytazthfticfjloychchmyjpotmybzrocwaofnotenvomtsnmovwqztdamoeadlkcsghykaeykaeykaewkaewkaewkaocybstimhksaycytacyrypfoswszcrh
keytool \
--source-key ur:crypto-hdkey/oxaoykaxhdclaebkmdcfjtdmaacybbesmskbolvdvalbdkgachhtlefpcmotltoezsynjlehidmokeamoeadlecsghykaeykaeykaewkaewkaocybstimhksaycytssgtkwkvatnuylf \
--key-request-derivation-path 0 \
derived-key
keytool: Cannot derive from a non-derivable key.
Produce a request and the corresponding response for the non-derivable key above, and also print the key itself.
keytool \
--seed 581fbdbf6b3eeababae7e7b51e3aabea \
--is-derivable false \
key-request \
key-response \
derived-key
ur:crypto-request/oeadtpdagdpratsratkisffymontntdmbsbnlramsnaotaadykotadykaotaaddyoeadlecsghykaeykaeykaewkaewkaocybstimhksaawkwzsogalt
ur:crypto-response/oeadtpdagdpratsratkisffymontntdmbsbnlramsnaotaaddloxaoykaxhdclaebkmdcfjtdmaacybbesmskbolvdvalbdkgachhtlefpcmotltoezsynjlehidmokeamoeadlecsghykaeykaeykaewkaewkaocybstimhksaycytssgtkwkjpqddidk
ur:crypto-hdkey/oxaoykaxhdclaebkmdcfjtdmaacybbesmskbolvdvalbdkgachhtlefpcmotltoezsynjlehidmokeamoeadlecsghykaeykaeykaewkaewkaocybstimhksaycytssgtkwkvatnuylf
Transform the derivable key above into a non-derivable key:
keytool \
--source-key ur:crypto-hdkey/onaoykaxhdclaebkmdcfjtdmaacybbesmskbolvdvalbdkgachhtlefpcmotltoezsynjlehidmokeaahdcxjsvdzechamzcosfhsrksyasnurgturdposknjsteaomulkfswnrfaenbclhtzcwnamoeadlecsghykaeykaeykaewkaewkaocybstimhksaycytssgtkwkksskatmk \
--key-request-derivation-path 'm' \
--is-derivable false \
derived-key
ur:crypto-hdkey/oxaoykaxhdclaebkmdcfjtdmaacybbesmskbolvdvalbdkgachhtlefpcmotltoezsynjlehidmokeamoeadlecsghykaeykaeykaewkaewkaocybstimhksaycytssgtkwkvatnuylf
- Updated libwally
- Added suite of nodes for requesting and responding to requests for signing PSBTs.
- Fixed bug in generated format of seed request; now conforms to specs.
- Added shunit2 as submodule instead of external dependency.
- Support for non-derivable keys via the
is-derivable
node.
- UR is now the primary format for types that support it, e.g.
master-key
. Such nodes can still take other forms of input (for example HD Key nodes can take UR or Base58) but output in Base58 is now done via separate nodes (e.g.,master-key-base58
). network
is no longer derived fromasset
; they are separate. The two supported assets are currently Bitcoinbtc
and Ethereumeth
. To use Bitcoin Testnet, use assetbtc
(the default) and networktestnet
.- Support for UR:CRYPTO-REQUEST and UR:CRYPTO-RESPONSE types for requesting and returning seeds and derived keys.
- Added ability to input PSBTs in hex and ur:crypto-psbt formats as well as Base-64, and output PSBTs in all three formats as well.
- Added ability to input transactions in ur:crypto-tx format as well as hex, and output transactions in both formats as well.
- Added nodes for deriving segwit addresses, signing PSBTs, and extracting raw transactions from PSBTs.
- Renamed
output-descriptor-type
tooutput-type
. - Made
purpose
dependent onoutput-type
. - Changed default
output-type
towpkh
.
- Support for
output-descriptor
.
- First testing release.