Uniform Resources (URs) allow for the encoding of self-describing, structured binary data in text strings that can are optimized for transmission in QR Codes. The types of data that Blockchain Commons has specified for URs appear in Registry of UR Types and include a variety of key material including seeds, keys, and BIP-39 mnemonics. (SSKR shards can also be encoded as URs.)

Key material is the most valuable data in a cryptography system because private keys and the seeds from which they are derived control cryptocurrency, verify identity, and serve other crucial purposes. For this reason it should be carefully secured — if possible with airgapping, where the material is held in some non-networked place. That’s where URs come in. They allow key material to be encoded as URs, converted into QRs, and then transmitted across an airgap in a way that’s safe and secure, minimizing its vulnerability at the time when it’s the most vulnerable.

The above image, drawn from an interoperability demo for LetheKit and Gordian Cosigner shows how an xpub and an xprv can be transmitted between airgapped devices using standardized, typed URs.

The following major categories of key material are available as URs: seeds, HD keys, and BIP 39 words.

Why Use URs for Key Material?

Why use URs for your key material when you could pass bare seeds, the mnemonic words themselves, or xprvs and xpubs for HD keys?

The biggest reason is interoperability. URs are all self-identifying, so you always know exactly what you’re getting. They’re also built to be encoded into QRs, which is a great way to transfer data across airgaps. The result is an easy, safe way to transfer key material and to expect that it will be understood by products produced by a variety of other manufacturers.

This is particularly important for key material because, as noted earlier, it is both the core of controlling cryptocurrency (and other digital assets) and uniquely vulnerable to theft or loss.

  1. By using a system that integrates well with airgaps, you can maximize the safety of key material without potentially falling prey to man-in-the-middle attacks and you can simultaneously maintain the security of airgapped devices.
  2. By using a self-describing, interoperable method to store key material, you can ensure that it will remain well-understood and thus usable far into the future, not becoming muddled with the huge variety of standards for key material that could otherwise result in it becoming effectively unsuable if a user has no idea what it is.

Key Material: crypto-seed

A seed is the basis of a Bitcoin account. It’s typically generated by a wallet, or alternatively a seed generator such as Blockchain Commons’ LetheKit or seedtool.

A Simple Seed

The example uses Blockchain Commons’ default 128-bit seed, YINMN BLUE.

HEX: 59f2293a5bce7d4de59e71b4207ac5d2
BIP-39 WORDS: fly mule excess resource treat plunge nose soda reflect adult ramp planet
BYTEWORDS: hawk whiz diet fact help taco kiwi gift view noon jugs quiz crux kiln silk tied omit keno lung jade
GORDIAN ENVELOPE: See QR code, above
SEGWIT UR OUTPUT DESCRIPTOR: ur:output-descriptor/oeadisktjojeisdefzdydtaolytantjloxaxhdclaxvlcprfttldjobkredtlnhsidwybaeyjtswyandlgjnehtkdsidbkqzsrkphyfhsaaahdcxhnfgnepefxgdytryckticelyotsstoknfntavevaskiddmolsarntykbrybtjpksamtantjooeadlncsghykaeykaeykaocyhngrmuwzaycyzssajpsndifmkohy
SEGWIT TEXT OUTPUT DESCRIPTOR: wpkh([604b93f2/84'/0'/0']xpub6DVfq9VduocgjGeR69Nyr8CCi9w5gywnU7wXMYGswpHjffjcbLYNzz6G6555VDcSZLDwZPzJHJQabVWWgkpvYntpunL3UjHGrkCJ6VndbQf)#ncwysjuk

:warning: Do not use this seed to hold real monies; they could disappear immediately!

A simple, unadorned seed looks like this:

59F2293A5BCE7D4DE59E71B4207AC5D2

As discussed in the UR Overview, this seed can be converted to the CBOR A1015059F2293A5BCE7D4DE59E71B4207AC5D2 and then a ur:crypto-seed:

ur:crypto-seed/oyadgdhkwzdtfthptokigtvwnnjsqzcxknsktdhpyljeda

Decoding a Simple Seed

The Bytewords and CBOR apps demonstrate how this seed can then be broken down into its constituent parts.

The bytewords CLI can be used to convert the Bytewords minimal encoding used in URs to CBOR:

$ bytewords -i minimal -o hex OYADGDHKWZDTFTHPTOKIGTVWNNJSQZCXKNSKTDHPYLJEDA
a1015059f2293a5bce7d4de59e71b4207ac5d2

The CBOR CLI can then be used to decode the result, revealing a map with just one item, which is the seed itself:

$ cbor2diag -x a1015059f2293a5bce7d4de59e71b4207ac5d2
{1: h'59f2293a5bce7d4de59e71b4207ac5d2'}

UR was built to support clean and efficient conversion into QR codes. That same seed can be encoded into a QR code as following:

If you read this with a QR reader you’ll get:

UR:CRYPTO-SEED/OYADGDHKWZDTFTHPTOKIGTVWNNJSQZCXKNSKTDHPYLJEDA

A Seed with Metadata

More complex examples of ur:crypto-seed may incorporate a creation date (map element #2, tagged 100), a name (map element #3), and/or a note (map element #4) as detailed in the crypto-seed CDDL.

The CBOR for a ur:crypto-seed containing all of these elements could look like the following:

a4015059f2293a5bce7d4de59e71b4207ac5d202D8641A6092DC07036541636F726E046C436F66666565206D6F6E6579

This is a CBOR map containing four elements.

It breaks apart as shown:

A4                                     # map(4)
   01                                  # element #1
   50                                  # 16 bytes in length
      59F2293A5BCE7D4DE59E71B4207AC5D2 # SEED
   02                                  # element #2
   D8 64                               # tag(100) (date)
      1A 6092DC07                      # CREATION DATE (1620237319)
   03                                  # element #3
   65                                  # 5-character text
      41636F726E                       # NAME ("Acorn")
   04                                  # element #4
   6C                                  # 12-character text
      436F66666565206D6F6E6579         # NOTE("Coffee money")

The CBOR-CLI can similarly be used to decode this information:

$ cbor2diag -x a4015059f2293a5bce7d4de59e71b4207ac5d202D8641A6092DC07036541636F726E046C436F66666565206D6F6E6579
{
    1: h'59f2293a5bce7d4de59e71b4207ac5d2',
    2: 100(1620237319),
    3: "Acorn",
    4: "Coffee money"
}

Using the Bytewords CLI you can convert the CBOR to minimal Bytewords:

$ bytewords -i hex -o minimal a4015059f2293a5bce7d4de59e71b4207ac5d202D8641A6092DC07036541636F726E046C436F66666565206D6F6E6579
oxadgdhkwzdtfthptokigtvwnnjsqzcxknsktdaotpiecyhnmouoataxihfpiajljpjtaajzfxjliyiyihihcxjnjljtihkkpseernwl

And you have a crypto-seed:

UR:CRYPTO-SEED/OXADGDHKWZDTFTHPTOKIGTVWNNJSQZCXKNSKTDAOTPIECYHNMOUOATAXIHFPIAJLJPJTAAJZFXJLIYIYIHIHCXJNJLJTIHKKPSEERNWL

Mnemonic Words: crypto-bip39

BIP39 details how mnemonic words can be used to define a master seed. These words can also be encoded for transportation using URs, as defined in the CDDL for BIP39.

The encoding is simple, requiring a map with an array of words and a language.

The test vector A2018C66736869656C646567726F75706565726F6465656177616B65646C6F636B6773617573616765646361736865676C6172656477617665646372657765666C616D6565676C6F76650262656E demonstrates the usage:

cbor2diag -x A2018C66736869656C646567726F75706565726F6465656177616B65646C6F636B6773617573616765646361736865676C6172656477617665646372657765666C616D6565676C6F76650262656E
{
 1:
    [
     "shield",
     "group",
     "erode",
     "awake",
     "lock",
     "sausage",
     "cash",
     "glare",
     "wave",
     "crew",
     "flame",
     "glove"
    ],
 2: "en"
}

Converting this to minimal bytewords results in:

ur:crypto-bip39/oeadlkiyjkisinihjzieihiojpjlkpjoihihjpjlieihihhskthsjeihiejzjliajeiojkhskpjkhsioihieiahsjkisihiojzhsjpihiekthskoihieiajpihktihiyjzhsjnihihiojzjlkoihaoidihjtrkkndede

Key Material: crypto-hdkey

HD Keys allow for a hierarchy of keys. Both master keys and derived keys can be encoded using URs, as described in the CDDL for hdkeys.

A Master Key

The following master HD key is derived from the seed 59F2293A5BCE7D4DE59E71B4207AC5D2:

xprv9s21ZrQH143K4Mnjc7E8rpSMf8JB1XWmojYf7Ndk6zcNSbUYBsvTqJcdzTok1XwYcgytn5CRxtwhHu93NNXNQwGUbBqL3AHHZZrtKpEvmww

That Base58 xprv decodes to hex as follows:

0488ade4000000000000000000b40359eb975b5e662298db589f75ed694b17755abbd0a230c24ffb8ac2be66fd0046f8a7a92fc3ca4fd4cbf3cb5bacde4356ce790e2cd6bc206ea2574ef8991318fe6a22e3

BIP32 reveals that this information is partitioned as follows:

  • 04 ; version 4
  • 88ade4 ; xprv
  • 00 ; depth 0 == master key
  • 00000000 ; parent fingerprint
  • 00000000 ; child number
  • b40359eb975b5e662298db589f75ed694b17755abbd0a230c24ffb8ac2be66fd ; chain code
  • 0046f8a7a92fc3ca4fd4cbf3cb5bacde4356ce790e2cd6bc206ea2574ef8991318 ; key data
  • fe6a22e3 ; base58 checksum

Per the CDDL, creating the CBOR for this master key requires creating a map with 3 to 4 elements, which:

  1. identify the hdkey as a master key in map element #1;
  2. optionally mark it as private in map element #2; and
  3. encode the key data and chain code in map elements #3 and #4.

The resulting CBOR is:

A401F502F50358210046F8A7A92FC3CA4FD4CBF3CB5BACDE4356CE790E2CD6BC206EA2574EF8991318045820B40359EB975B5E662298DB589F75ED694B17755ABBD0A230C24FFB8AC2BE66FD

This decodes as follows:

$ cbor2diag -x A401F502F50358210046F8A7A92FC3CA4FD4CBF3CB5BACDE4356CE790E2CD6BC206EA2574EF8991318045820B40359EB975B5E662298DB589F75ED694B17755ABBD0A230C24FFB8AC2BE66FD
{
    1: true,
    2: true,
    3: h'0046f8a7a92fc3ca4fd4cbf3cb5bacde4356ce790e2cd6bc206ea2574ef8991318',
    4: h'b40359eb975b5e662298db589f75ed694b17755abbd0a230c24ffb8ac2be66fd'

}

As usual, converting to Bytewords then allows creation of the UR:

$ bytewords -i hex -o minimal A401F502F50358210046F8A7A92FC3CA4FD4CBF3CB5BACDE4356CE790E2CD6BC206EA2574EF8991318045820B40359EB975B5E662298DB589F75ED694B17755ABBD0A230C24FFB8AC2BE66FD
oxadykaoykaxhdclaefgyaosptdlsrsggwtysbwfsbhppsuefxhftokkbadwtbrfcxjtoehgglyanlbwcsaahdcxqzaxhkwmmshphyiycpmkuyhdnekpweingrchkphtrktioedysagwzolesarniyzcrhdntkbb

The result is:

ur:crypto-hdkey/oxadykaoykaxhdclaefgyaosptdlsrsggwtysbwfsbhppsuefxhftokkbadwtbrfcxjtoehgglyanlbwcsaahdcxqzaxhkwmmshphyiycpmkuyhdnekpweingrchkphtrktioedysagwzolesarniyzcrhdntkbb

A Derived Key

A derived key will similarly include the key data and chain code, but also tends to include a derivation path (map element #6) and a parent fingerprint (map element #8) as described in the CDDL for hdkeys. The following test vector demonstrates these elements as well as coininfo (map element #5) to denote the key as testnet. Note that both the coininfo and the derivation paths are defined with tags (305 and 304 respectively).

The following CBOR:

A5035821026FE2355745BB2DB3630BBC80EF5D58951C963C841F54170BA6E5C12BE7FC12A6045820CED155C72456255881793514EDC5BD9447E7F74ABB88C6D6B6480FD016EE8C8505D90131A1020106D90130A1018A182CF501F501F500F401F4081AE9181CF3

Breaks down as follows:

cbor2diag -x A5035821026FE2355745BB2DB3630BBC80EF5D58951C963C841F54170BA6E5C12BE7FC12A6045820CED155C72456255881793514EDC5BD9447E7F74ABB88C6D6B6480FD016EE8C8505D90131A1020106D90130A1018A182CF501F501F500F401F4081AE9181CF3
{
    3: h'026fe2355745bb2db3630bbc80ef5d58951c963c841f54170ba6e5c12be7fc12a6',
    4: h'ced155c72456255881793514edc5bd9447e7f74abb88c6d6b6480fd016ee8c85',
    5: 305({2: 1}),
    6: 304({1: [44, true, 1, true, 1, true, 0, false, 1, false]}),
    8: 3910671603
}

The coininfo element (#5) demonstrates use of the coininfo CDDL. Here, the network is set to testnet.

The key derivation element (#6) demonstrates use of the keypath CDDL. Here, the derivation path is set to m/44'/1'/1'/0/1.

The parent-fingerprint element (#8) is simply set to 3910671603 (or in hex: 1AE9181CF3).

The resulting crypto-hdkey after conversion to minimal Bytewords is:

ur:crypto-hdkey/onaxhdclaojlvoechgferkdpqdiabdrflawshlhdmdcemtfnlrctghchbdolvwsednvdztbgolaahdcxtottgostdkhfdahdlykkecbbweskrymwflvdylgerkloswtbrpfdbsticmwylklpahtaadehoyaoadamtaaddyoyadlecsdwykadykadykaewkadwkaycywlcscewfihbdaehn

A few other URs are related to key material:

  • SSKR allows for the transmission of shares that are recombined to reconstruct key material.
  • Envelope can store key material.

Each is covered in their own document.

Testing Key Material URs with Blockchain Commons’ Reference Tools

Blockchain Commons reference tools allow for experimentation with the UR format. The following examples use our seedtool, keytool, and the bytewords CLIs, as well as the CBOR cli.

The Seed

A seed can be generated with seedtool:

$ seedtool
9c49536666b3f5cdbbe8d6da01aa6a66
$ seed=9c49536666b3f5cdbbe8d6da01aa6a66

Rather than outputting hex, seedtool can also output a UR for the crypto-seed:

$ seedtool -i hex $seed -u
ur:crypto-seed/oyadgdnsgaguiyiyqdyksnrkvstbtnadpkimiybzrycyck

bytewords can decode this output:

$ bytewords -i minimal -o hex oyadgdnsgaguiyiyqdyksnrkvstbtnadpkimiybzrycyck
a101509c49536666b3f5cdbbe8d6da01aa6a66

cbor2diag then reveals the original seed within the CBOR encoding:

$ cbor2diag -x a101509c49536666b3f5cdbbe8d6da01aa6a66
{1: h'9c49536666b3f5cdbbe8d6da01aa6a66'}

The BIP39

seedtool can also generate BIP39 words, in either mnemonic or UR format:

$ seedtool -i hex $seed -o bip39
ordinary enhance sunset sniff dismiss traffic use bracket sure ask once slot

$ seedtool -i hex $seed -o bip39 -u
ur:crypto-bip39/oyadlkisjljpieinjthsjpkkioihjtishsjtiaihiyjkkpjtjkihjyihjkjtiniyiyioieinjkjninjkjkiojyjphsiyiyiniaiakpjkihioidjphsiajeihjyiejkkpjpihiahsjkjeiejljtiaihiejkjzjljybyckylhl

Again, bytewords and cbor2diag can decode the UR:

$ bytewords -i minimal -o hex oyadlkisjljpieinjthsjpkkioihjtishsjtiaihiyjkkpjtjkihjyihjkjtiniyiyioieinjkjninjkjkiojyjphsiyiyiniaiakpjkihioidjphsiajeihjyiejkkpjpihiahsjkjeiejljtiaihiejkjzjljybyckylhl
a1018c686f7264696e61727967656e68616e63656673756e73657465736e696666676469736d69737367747261666669636375736567627261636b657464737572656361736b646f6e636564736c6f74

$ cbor2diag -x a1018c686f7264696e61727967656e68616e63656673756e73657465736e696666676469736d69737367747261666669636375736567627261636b657464737572656361736b646f6e636564736c6f74
{1:
    ["ordinary",
     "enhance",
     "sunset",
     "sniff",
     "dismiss",
     "traffic",
     "use",
     "bracket",
     "sure",
     "ask",
     "once",
     "slot"]
}

The Master Key

keytool supports key and address derivation. For example, it can produce a master xprv from a seed:

$ keytool --seed $seed master-key-base58
xprv9s21ZrQH143K3zAmshnnUZcq8YF2GPBnf5C7DhH5Y3EEBbSQCoPTsG6kFCQDKm4qSopjFQnMWhPuytDxezCYir9hdwAWGmJfSxKdaZZPHxj

keytool also can produce URs:

$ keytool --seed $seed master-key
ur:crypto-hdkey/oxadykaoykaxhdclaeswcspsndaezohttlpmfxdlqdcsaxfhuygwoteheylenbmolflninmsehmnhybdstaahdcxseoylrlbjkwmsfctzmetbyollbencftprprkswvwsrguesssnscxnbcftivsrlclbykiflbs

Again, you can decode that with bytewords and cbor2diag:

$ bytewords -i minimal -o hex oxadykaoykaxhdclaeswcspsndaezohttlpmfxdlqdcsaxfhuygwoteheylenbmolflninmsehmnhybdstaahdcxseoylrlbjkwmsfctzmetbyollbencftprprkswvwsrguesssnscxnbcftivsrlclbykiflbs
a401f502f503582100c618ac9b00fb5ad5ad432fb318033fdb4fa331328aa09282866997318e5e0bc7045820c1a1847f73ebcc1fff3811a67f3619d8b6bbc6e5c35339c49c20a019d0e8b721

$ cbor2diag -x a401f502f503582100c618ac9b00fb5ad5ad432fb318033fdb4fa331328aa09282866997318e5e0bc7045820c1a1847f73ebcc1fff3811a67f3619d8b6bbc6e5c35339c49c20a019d0e8b721
{
    1: true,
    2: true,
    3: h'00c618ac9b00fb5ad5ad432fb318033fdb4fa331328aa09282866997318e5e0bc7',
    4: h'c1a1847f73ebcc1fff3811a67f3619d8b6bbc6e5c35339c49c20a019d0e8b721'
}

A Derived Key

keytool can also create derived keys. The following example produced an xprv and a UR for the 44’/1’/1’/0/1 keypath:

$ /usr/local/bin/keytool --master-key xprv9s21ZrQH143K3zAmshnnUZcq8YF2GPBnf5C7DhH5Y3EEBbSQCoPTsG6kFCQDKm4qSopjFQnMWhPuytDxezCYir9hdwAWGmJfSxKdaZZPHxj --full-address-derivation-path m/44h/1h/1h/0/1 address-key-base58 address-key

xprvA3px5eB5pEbMi5bApo1CcoLeXHMubgFJ8hedudWE3gdMeHP6FQYXNJpPxcuznwE4PBHRcEodyp7ykLKvvpCrDK6zTLMBG899dnHTzJ3aKty

ur:crypto-hdkey/onaoykaxhdclaeknidehqdwsatwppfcfdklatdmkuyknckurlgnssrihsgdytniscntkwpcxsrmsnlaahdcxsazshllbztynlufnskreoefgdsztchihttnsahlkamlbcningefhnsjekoutyllkamoeadlecsdwykadykadykaewkadwkaocyahhfespfaycyrnnneooebkadltsn

The following shows the same for the xpub:

$ /usr/local/bin/keytool --master-key xprv9s21ZrQH143K3zAmshnnUZcq8YF2GPBnf5C7DhH5Y3EEBbSQCoPTsG6kFCQDKm4qSopjFQnMWhPuytDxezCYir9hdwAWGmJfSxKdaZZPHxj --full-address-derivation-path m/44h/1h/1h/0/1 address-pub-key-base58 address-pub-key

xpub6GpJV9hyec9evZfdvpYCywHP5KCQ18y9VvaEi1uqc2ALX5iEnwrmv78sotc3ZhwnSw1mvu437TsZ31mCwxMenzVpXsjtsB5UUaKMsYxexnG

ur:crypto-hdkey/oxaxhdclaottglktmoaoaerhonbygygejzzmhphfwnvaprjsfwfhdwsfvytpcxfxvavthkdiplaahdcxsazshllbztynlufnskreoefgdsztchihttnsahlkamlbcningefhnsjekoutyllkamoeadlecsdwykadykadykaewkadwkaocyahhfespfaycyrnnneooetldprhne

Here’s the decoding of that xprv:

$ bytewords -i minimal -o hex onaoykaxhdclaeknidehqdwsatwppfcfdklatdmkuyknckurlgnssrihsgdytniscntkwpcxsrmsnlaahdcxsazshllbztynlufnskreoefgdsztchihttnsahlkamlbcningefhnsjekoutyllkamoeadlecsdwykadykadykaewkadwkaocyahhfespfaycyrnnneooebkadltsn
a502f5035821007a6231b3ef07ecb0192480d298db7a1edf8d9cc365ca30da6823cfec20c39799045820c2fa5d7ffcf68b3cc5b5a24626fc1765d19c058c067f23694a3f9c6b76ddf78c06a2018a182cf501f501f500f401f4021a055639b0081abe9e33a2

$ cbor2diag -x a502f5035821007a6231b3ef07ecb0192480d298db7a1edf8d9cc365ca30da6823cfec20c39799045820c2fa5d7ffcf68b3cc5b5a24626fc1765d19c058c067f23694a3f9c6b76ddf78c06a2018a182cf501f501f500f401f4021a055639b0081abe9e33a2
{
    2: true,
    3: h'007a6231b3ef07ecb0192480d298db7a1edf8d9cc365ca30da6823cfec20c39799',
    4: h'c2fa5d7ffcf68b3cc5b5a24626fc1765d19c058c067f23694a3f9c6b76ddf78c',
    6: {1: [44, true, 1, true, 1, true, 0, false, 1, false], 2: 89536944},
    8: 3198038946
}

Similarly, here’s the decoded xpub:

{
    3: h'02d14e77920200b9a511514a6cff5b56f1e6b271423f2ccce1d82043e6e05927ae',
    4: h'c2fa5d7ffcf68b3cc5b5a24626fc1765d19c058c067f23694a3f9c6b76ddf78c',
    6: {1: [44, true, 1, true, 1, true, 0, false, 1, false], 2: 89536944},
    8: 3198038946
}

Integrating Key Material URs Into Your Code

You can incorporate URs into your own code using bc-ur for C++ or through conversions of that library to other languages such as Java and Swift.

bc-ur provides access to objects such as UREncoder, URDecoder, and Bytewords, which support many of the same functions as described here for the command line. They can also be used with other Blockchain Commons Crypto Commons Reference Libraries which support a variety of cryptography functions.

UR Libraries

Language Repo Contributor Status
C++ bc-ur Blockchain Commons  
Java bc-ur-java Bitmark  
Java Hummingbird Craig Raw  
Python foundation-ur-py Foundation  
Rust bc-ur-rust Blockchain Commons  
Rust ur-rust Dominik Spicher  
Swift URKit + URUI Blockchain Commons  
TypeScript bc-ur for TS xardass  

Conclusion

Key material can be transferred using ur:crypto-seed, ur:crypto-bip39, and ur:crypto-hdkey. Doing so allows you to use airgaps, which increase the safety of these vulnerable operations; and also increases your interoperability, so that other software can work with you, and so that your key material remains usable far into the future.