├── .gitignore ├── .vscode ├── settings.json └── spellright.dict ├── CLA.md ├── CODEOWNERS ├── CONTRIBUTING.md ├── Investigation ├── Files.md ├── Formats.md ├── Passwords.md ├── X_0_Expanding_Bitcoin_Transactions_with_Schnorr.md └── X_1_Understanding Schnorr Signatures.md ├── LICENSE ├── README.md ├── images └── logos │ ├── README.md │ ├── bcc-research-screen.jpg │ ├── bcc-research-screen.png │ └── bcc-research-screen.psd ├── papers ├── bcr-2020-001-entropy-to-seed.md ├── bcr-2020-002-bech32-seed-format.md ├── bcr-2020-003-uri-binary-compatibility.md ├── bcr-2020-003 │ ├── 1.png │ ├── 10.png │ ├── 11.png │ ├── 12.png │ ├── 2.png │ ├── 3.png │ ├── 4.png │ ├── 5.png │ ├── 6.png │ ├── 7.png │ ├── 8.png │ ├── 9.png │ └── AlphabetCollisionAnalysis.nb ├── bcr-2020-004-bc32.md ├── bcr-2020-004 │ ├── BC32.nb │ └── Binary-to-Text Efficiency.nb ├── bcr-2020-005-ur.md ├── bcr-2020-005 │ ├── 1.png │ └── UR.nb ├── bcr-2020-006-urtypes.md ├── bcr-2020-006 │ ├── 1.png │ ├── 2.png │ └── 6.png ├── bcr-2020-007-hdkey.md ├── bcr-2020-007 │ ├── 1.png │ └── 2.png ├── bcr-2020-008-eckey.md ├── bcr-2020-009-address.md ├── bcr-2020-009 │ ├── 1.png │ └── 2.png ├── bcr-2020-010-output-desc.md ├── bcr-2020-011-sskr.md ├── bcr-2020-012-bytewords.md ├── bcr-2020-012 │ └── Bytewords.nb ├── bcr-2020-013-crc32-cbor-tag.md ├── bcr-2020-014-urs-on-epaper.md ├── bcr-2020-015-account.md ├── bcr-2021-001-request.md ├── bcr-2021-002-digest.md ├── bcr-2021-002 │ ├── 0.png │ ├── blockchain-commons.png │ ├── oib-1.png │ ├── oib-2.png │ ├── oib-3.png │ ├── oib-4.png │ ├── oib-5.png │ ├── oib-6.png │ ├── sskr-coupons.jpg │ └── wolf.png ├── bcr-2022-001-encrypted-message.md ├── bcr-2022-002-arid.md ├── bcr-2023-001-compressed-message.md ├── bcr-2023-002-known-value.md ├── bcr-2023-003-envelope-known-value.md ├── bcr-2023-004-envelope-symmetric-encryption.md ├── bcr-2023-005-envelope-compression.md ├── bcr-2023-006-envelope-attachment.md ├── bcr-2023-007-envelope-output-desc.md ├── bcr-2023-008-dcbor-date.md ├── bcr-2023-009-envelope-seed.md ├── bcr-2023-010-output-descriptor.md ├── bcr-2023-011-public-key-crypto.md ├── bcr-2023-012-envelope-expression.md ├── bcr-2023-013-envelope-crypto.md ├── bcr-2023-014-gstp.md ├── bcr-2023-015-nonce.md ├── bcr-2023-016-password.md ├── bcr-2023-017-salt.md ├── bcr-2023-018-depo-api.md ├── bcr-2023-019-account-descriptor.md ├── bcr-2024-001-multipart-ur.md ├── bcr-2024-002-dcbor.md ├── bcr-2024-003-envelope.md ├── bcr-2024-004-request.md ├── bcr-2024-005-key-encodings.md ├── bcr-2024-006-envelope-graph.md ├── bcr-2024-007-envelope-decorrelation.md ├── bcr-2024-008-bytemoji.md ├── bcr-2024-009-signature-metadata.md ├── bcr-2024-010-xid.md ├── bcr-2024-010 │ └── lifehash.png ├── bcr-2024-011-reference.md ├── bcr-2025-001-provenance-mark.md ├── bcr-2025-001 │ ├── hash-chain.png │ ├── lifehash.png │ ├── link-qr-code.png │ ├── provenance-mark-symbol-white.svg │ └── ur-qr-code.png ├── bcr-2025-002-negative-zero.md ├── bcr-2025-003-post-quantum.md ├── bcr-2025-004-permit.md └── bcr-2025-005-domain-separation.md └── signed-cla ├── CLA.gorazdko.41F0EA1699A74C1E2FA41B538CF96BC3FF9DBBCE.asc ├── CLA.mcelrath.D4274A20A7A006DDF1B904A2CF18D8489BE58C4E.asc ├── CLA.wolfmcnally.943652EE38441760C3DC35364B6C2FCF894780AE.asc └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.gitignore.io/api/macos 2 | 3 | ### macOS ### 4 | # General 5 | .DS_Store 6 | .AppleDouble 7 | .LSOverride 8 | 9 | # Icon must end with two \r 10 | Icon 11 | 12 | # Thumbnails 13 | ._* 14 | 15 | # Files that might appear in the root of a volume 16 | .DocumentRevisions-V100 17 | .fseventsd 18 | .Spotlight-V100 19 | .TemporaryItems 20 | .Trashes 21 | .VolumeIcon.icns 22 | .com.apple.timemachine.donotpresent 23 | 24 | # Directories potentially created on remote AFP share 25 | .AppleDB 26 | .AppleDesktop 27 | Network Trash Folder 28 | Temporary Items 29 | .apdisk 30 | 31 | # End of https://www.gitignore.io/api/macos 32 | 33 | # Created by https://www.gitignore.io/api/c 34 | 35 | ### C ### 36 | # Prerequisites 37 | *.d 38 | 39 | # Object files 40 | *.o 41 | *.ko 42 | *.obj 43 | *.elf 44 | 45 | # Linker output 46 | *.ilk 47 | *.map 48 | *.exp 49 | 50 | # Precompiled Headers 51 | *.gch 52 | *.pch 53 | 54 | # Libraries 55 | *.lib 56 | *.a 57 | *.la 58 | *.lo 59 | 60 | # Shared objects (inc. Windows DLLs) 61 | *.dll 62 | *.so 63 | *.so.* 64 | *.dylib 65 | 66 | # Executables 67 | *.exe 68 | *.out 69 | *.app 70 | *.i*86 71 | *.x86_64 72 | *.hex 73 | 74 | # Debug files 75 | *.dSYM/ 76 | *.su 77 | *.idb 78 | *.pdb 79 | 80 | # Kernel Module Compile Results 81 | *.mod* 82 | *.cmd 83 | .tmp_versions/ 84 | modules.order 85 | Module.symvers 86 | Mkfile.old 87 | dkms.conf 88 | 89 | # End of https://www.gitignore.io/api/c 90 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.words": [ 3 | "Adkxj", 4 | "ALHY", 5 | "Applecline", 6 | "arity", 7 | "ATSAMD", 8 | "birthdate", 9 | "bitfields", 10 | "BMSE", 11 | "BUHQVHQ", 12 | "bybg", 13 | "canonicalization", 14 | "chacha", 15 | "checknum", 16 | "checksummed", 17 | "checksumming", 18 | "codepoint", 19 | "codepoints", 20 | "coininfo", 21 | "coinswap", 22 | "cointype", 23 | "correlatability", 24 | "Correlatability", 25 | "Ctig", 26 | "cvsj", 27 | "Damerau", 28 | "datasheet", 29 | "Dilithium", 30 | "dnducr", 31 | "doublesha", 32 | "Dpjw", 33 | "dzgq", 34 | "Dznezpb", 35 | "dzthz", 36 | "eagzwgf", 37 | "eckey", 38 | "ecparam", 39 | "ECPARMS", 40 | "Ecygo", 41 | "ehqydjmwktac", 42 | "Epot", 43 | "evaluatable", 44 | "Ewjg", 45 | "Ewpk", 46 | "FDFE", 47 | "fffffffe", 48 | "Flatbuffers", 49 | "FLTX", 50 | "fpjkcmr", 51 | "Gavu", 52 | "gdaebycpeofygoiyktlonlpkrksfutwyzmwmfyeozs", 53 | "gogrrsbyadadbnluotnykpaootdaweatrotlmsttrobsghbnurrh", 54 | "gogrrsbyadaefmnlbnctaaecvoqdfnjpbzecstfgaxtifpsskbfw", 55 | "gogrrsbyadaohtrygabavahphnlrlpmkghwyiojkjtkpmdkncfjp", 56 | "gogrrsbybgaaiaeenbuyksetonswsstduoprvwrphkbytlfzlyca", 57 | "gogrrsbybgadjlzocwbnskpyfdhehtiobwjzladnswkgtscfhfvt", 58 | "gogrrsbybgaefywsfefhiymofseyihfremkivwsogrespmclwepd", 59 | "gogrrsbybgaootkoehgoztzcreloknrfvawyinssrksnmedtfmks", 60 | "gogrrsbybgaxloidjliyhessrtvwfevtsazmbndsenmywmbylpdy", 61 | "gorli", 62 | "Gqsef", 63 | "Gqxd", 64 | "grrs", 65 | "GSTP", 66 | "Gtcq", 67 | "Gudu", 68 | "hdcxvwskgscmfsrsroluaettbboxsnjnfptbonsstktnrnbasgbyjypaaybnjzfrfyisecmwbzrk", 69 | "hdosjojkidjyzmadaenyaoaeaeaeaohdvsknclrejnpebncnrnmnjojofejzeojlkerdonspkpkkdkykfelokgprpyutkpaeaeaeaeaezmzmzmzmlslgaaditiwpihbkispkfgrkbdaslewdfycprtjsprsgksecdratkkhktikewdcaadaeaeaeaezmzmzmzmaojopkwtayaeaeaeaecmaebbtphhdnjstiambdassoloimwmlyhygdnlcatnbggtaevyykahaeaeaeaecmaebbaeplptoevwwtyakoonlourgofgvsjydpcaltaemyaeaeaeaeaeaeaeaeaebkgdcarh", 70 | "hkfah", 71 | "HMAC", 72 | "Hnxo", 73 | "homoiconic", 74 | "hrss", 75 | "Hvoed", 76 | "iaeenbuyksetonswsstduoprvwrphkby", 77 | "idoc", 78 | "ietfchacha", 79 | "inout", 80 | "inspecific", 81 | "Ints", 82 | "involutory", 83 | "isogenies", 84 | "Isogeny", 85 | "isomorphically", 86 | "JFLJTH", 87 | "Jird", 88 | "Jppvct", 89 | "jzfdihjzjzjldwcxktjljpjzieatjpgele", 90 | "Jzuv", 91 | "keccak", 92 | "keypath", 93 | "keypaths", 94 | "khvwfdcr", 95 | "koxb", 96 | "lethekit", 97 | "Lgpey", 98 | "LHRV", 99 | "lnlltj", 100 | "lpadbtcfadndcysawfmslghdcxoeadhkadmhjtdrswhlnnktwlprtkaeploejyoxlkytzevoidgstennskdkkoeopkinjelpwe", 101 | "lrhdjptecylgeeiemnhnuykglnperfguwskbsaoxpmwegydtjtayzeptvoreosenwyidtbfsrnoxhylkptiobglfzszointnmojplucyjsuebknnambddtahtbonrpkbsnfrenmoutrylbdpktlulkmkaxplvldeascwhdzsqddkvezstbkpmwgolplalufdehtsrffhwkuewtmngrknntvwkotdihlntoswgrhscmgsataeaeaefzfpfwfxfyfefgflgdcyvybdhkgwasvoimkbmhdmsbtihnammegsgdgygmgurtsesasrssskswstcfnbpdct", 102 | "Luby", 103 | "Mathematica", 104 | "Mcet", 105 | "mesage", 106 | "millis", 107 | "Mkhgbm", 108 | "MRNNU", 109 | "MSEB", 110 | "Mskt", 111 | "multikey", 112 | "multipath", 113 | "Multisignature", 114 | "mxzp", 115 | "nistp", 116 | "Nnnsrjh", 117 | "Nqtwyb", 118 | "NTRU", 119 | "oeadcyemrewytyaolttaadeetaadmutaaddloxaxhdclaxwmfmdeiamecsdsemgtvsjzcncygrkowtrontzschgezokstswkkscfmklrtauteyaahdcxiehfonurdppfyntapejpproypegrdawkgmaewejlsfdtsrfybdehcaflmtrlbdhpamtaaddyoeadlncsdwykaeykaeykaocyemrewytyaycynlytsnyltaadeetaadmhtaadmwtaaddloxaxhdclaostvelfemdyynwydwyaievosrgmambklovabdgypdglldvespsthysadamhpmjeinaahdcxntdllnaaeykoytdacygegwhgjsiyonpywmcmrpwphsvodsrerozsbyaxluzcoxdpamtaaddyoeadlncsehykaeykaeykaocyemrewytyaycypdbskeuytaadeetaadmwtaaddloxaxhdclaxzcfxeegdrpmogrgwkbzctlttweadkiengrwlhtprremouoluutqdpfbncedkynfhaahdcxjpwevdeogthttkmeswzcolcpsaahcfnshkhtehytclmnteatmoteadtlwynnftloamtaaddyoeadlncsghykaeykaeykaocyemrewytyaycybthlvytstaadeetaadmhtaadnytaaddloxaxhdclaxhhsnhdrpftdwuocntilydibehnecmovdfekpjkclcslasbhkpawsaddmcmmnahnyaahdcxlotedtndfymyltclhlmtpfsadscnhtztaolbnnkistaedegwfmmedreetnwmcycnamtaaddyoeadlfcsdpykaocyemrewytyaycyemrewytytaadeetaadmhtaadmetaadnytaaddloxaxhdclaxdwkswmztpytnswtsecnblfbayajkdldeclqzzolrsnhljedsgminetytbnahatbyaahdcxkkguwsvyimjkvwteytwztyswvendtpmncpasfrrylprnhtkblndrgrmkoyjtbkrpamtaaddyoeadlocsdyykaeykaeykadykaocyemrewytyaycyhkrpnddrtaadeetaadmetaadnytaaddloxaxhdclaohnhffmvsbndslrfgclpfjejyatbdpebacnzokotofxntaoemvskpaowmryfnotfgaahdcxdlnbvecentssfsssgylnhkrstoytecrdlyadrekirfaybglahltalsrfcaeerobwamtaaddyoeadlocsdyykaeykaeykaoykaocyemrewytyaycyhkrpnddrtaadeetaadnltaaddloxaxhdclaorkrhkeytwsoykorletwstbwycagtbsotmeptjkesgwrfcmveskvdmngujzttgtdpaahdcxgrfgmuvyylmwcxjtttechplslgoegagaptdniatidmhdmebdwfryfsnsdkcplyvaamtaaddyoeadlncshfykaeykaeykaocyemrewytyaycytostatbngmdavolk", 120 | "oeadgdstaslplabghydrpfmkbggufgludprfgmaotpiecffltnlpqdenos", 121 | "oeadtaadehoeadcsfnaoadaxghlyrlvtmyihryykielnamspnlmkptsflyieeskofllosfeecf", 122 | "oeadtpdagdfrghbbemhyftfebdmyvydacerfdnfhreaotaaddwoeadgdstaslplabghydrpfmkbggufgludprfgmaotpiecffltnvezsamyn", 123 | "oeadtpdagdfrghbbemhyftfebdmyvydacerfdnfhreaotaadwkoyadtaaohdhdcxvsdkfgkepezepefrrffmbnnbmdvahnptrdtpbtuyimmemweootjshsmhlunyeslnkiledlmo", 124 | "oeaoykaxhdcxlkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypkrphsmyid", 125 | "onaxhdclaojlvoechgferkdpqdiabdrflawshlhdmdcemtfnlrctghchbdolvwsednvdztbgolaahdcxtottgostdkhfdahdlykkecbbweskrymwflvdylgerkloswtbrpfdbsticmwylklpahtaadehoyaoadamtaaddyoyadlecsdwykadykadykaewkadwkaycywlcscewfihbdaehn", 126 | "Optech", 127 | "otadykaxhdclaevswfdmjpfswpwkahcywspsmndwmusoskprbbehetchsnpfcybbmwrhchspfxjeecaahdcxltfszmlyrtdlgmhfcnzcctvwcmkbpsftgonbgauefsehgrqzdmvodizmweemtlaybakiylat", 128 | "oyaxghktrswzbnhnvwcpurpkeogdsrndaxbkhlaegllsnyolrsemgu", 129 | "oyaxhdclaxrnskcmfswzhlltaxbzbnftcsaawdsttbbzrkcldnkesotszmmuknpdrycegagrlbemdevtlp", 130 | "pgwgjc", 131 | "Pieter", 132 | "Pqji", 133 | "println", 134 | "probs", 135 | "proto", 136 | "protoc", 137 | "prvkey", 138 | "psbt", 139 | "PSBT", 140 | "pubkey", 141 | "Qedj", 142 | "Qkiv", 143 | "qrencode", 144 | "QTDL", 145 | "QTPH", 146 | "qyhesn", 147 | "rateless", 148 | "Rdap", 149 | "rescoping", 150 | "Rfvrn", 151 | "Rgmmd", 152 | "Rkrg", 153 | "Ruap", 154 | "Rupje", 155 | "Rydo", 156 | "Satoshi", 157 | "Schwarz", 158 | "secp", 159 | "segwit", 160 | "seqlen", 161 | "shjm", 162 | "sortedmulti", 163 | "specifes", 164 | "staslplabghydrpfmkbggufgludprfgmzepsbtwd", 165 | "strikethrough", 166 | "Supersingular", 167 | "sxcqn", 168 | "SXXQUM", 169 | "taaddwoeadgdstaslplabghydrpfmkbggufgludprfgmaotpiecffltntddwgmrp", 170 | "taadmetaadmtoeadadaolftaaddloxaxhdclaxsbsgptsolkltkndsmskiaelfhhmdimcnmnlgutzotecpsfveylgrbdhptbpsveosaahdcxhnganelacwldjnlschnyfxjyplrllfdrplpswdnbuyctlpwyfmmhgsgtwsrymtldamtaaddyoeadlaaxaeattaaddyoyadlnadwkaewklawktaaddloxaxhdclaoztnnhtwtpslgndfnwpzedrlomnclchrdfsayntlplplojznslfjejecpptlgbgwdaahdcxwtmhnyzmpkkbvdpyvwutglbeahmktyuogusnjonththhdwpsfzvdfpdlcndlkensamtaaddyoeadlfaewkaocyrycmrnvwattaaddyoyadlnaewkaewklawktdbsfttn", 171 | "taadmhtaadmtoeadaoaolftaadeyoyaxhdclaodladvwvyhhsgeccapewflrfhrlbsfndlbkcwutahvwpeloleioksglwfvybkdradtaadeyoyaxhdclaxpstylrvowtstynguaspmchlenegonyryvtmsmtmsgshgvdbbsrhebybtztdisfrnpfadremh", 172 | "taadmhtaadmwtaadeyoyaxhdclaxzmytkgtlkphywyoxcxfeftbbecgmectelfynfldllpisoyludlahknbbhndtkphfhlehmust", 173 | "taadmutaaddlonaxhdclaotdqdinaeesjzmolfzsbbidlpiyhddlcximhltirfsptlvsmohscsamsgzoaxadwtaahdcxiaksataxbtgotictnybnqdoslsmdbztsmtryatjoialnolweuramsfdtolhtbadtamtaaddyotadlncsdwykaeykaeykaocytegtqdfhaxaaattaaddyoyadlradwklawkaycyksfpdmftkiiozsfd", 174 | "taadmutaadeyoyaxhdclaoswaalbmwfpwekijndyfefzjtmdrtketphhktmngrlkwsfnospypsasrhhhjonnvwtsqzwljy", 175 | "Tatx", 176 | "Tcxd", 177 | "tefu", 178 | "Tezos", 179 | "tlfzlyca", 180 | "Tmca", 181 | "tnhkrcpg", 182 | "tpub", 183 | "twofish", 184 | "typealias", 185 | "uawcg", 186 | "uistate", 187 | "Umsmo", 188 | "unmix", 189 | "unvvsh", 190 | "URTYPES", 191 | "Uwgc", 192 | "veyzpwk", 193 | "Vose", 194 | "Vuko", 195 | "Vvoe", 196 | "wcpv", 197 | "Wetq", 198 | "Wgjj", 199 | "wjrpfauutvwkcawd", 200 | "wordlist", 201 | "wordlists", 202 | "wphk", 203 | "wpkh", 204 | "Wuille", 205 | "Wzmp", 206 | "XFPs", 207 | "xpar", 208 | "xprv", 209 | "xpub", 210 | "xpubs", 211 | "Xvgj", 212 | "ypmk", 213 | "Ysgtki", 214 | "Ysrm", 215 | "Yyarv", 216 | "zstream", 217 | "zutwflk" 218 | ], 219 | "cSpell.enabled": true, 220 | "spellright.language": [ 221 | "en" 222 | ], 223 | "spellright.documentTypes": [ 224 | "rust", 225 | "json", 226 | "latex", 227 | "markdown" 228 | ] 229 | } 230 | -------------------------------------------------------------------------------- /.vscode/spellright.dict: -------------------------------------------------------------------------------- 1 | doublesha 2 | pubkeys 3 | prvkey 4 | keypair 5 | Kyber 6 | bcr 7 | md 8 | aad 9 | Gorazd 10 | Kovacic 11 | Scrypt 12 | Appelcline 13 | Bytemoji 14 | spdx 15 | codepoints 16 | Codepoint 17 | datestamp 18 | pseudograph 19 | hypergraph 20 | hyperedge 21 | rs 22 | Xoshiro256 23 | preimage 24 | auditability 25 | seqLen 26 | trunc 27 | seq 28 | non-repudiable 29 | byteword 30 | -------------------------------------------------------------------------------- /CLA.md: -------------------------------------------------------------------------------- 1 | # Contributor License Agreement 2 | 3 | Version 1.0 4 | 5 | Name: `$name` 6 | 7 | E-Mail: `$email` 8 | 9 | Legal Jurisdiction: Wyoming, United States of America 10 | 11 | Project: https://github.com/BlockchainCommons/bc-lethe-kit 12 | 13 | Date: `$date` 14 | 15 | ## Purpose 16 | 17 | This agreement gives Blockchain Commons, LLC the permission it needs in order to accept my contributions into its open software project and to manage the intellectual property in that project over time. 18 | 19 | ## License 20 | 21 | I hereby license Blockchain Commons, LLC to: 22 | 23 | 1. do anything with my contributions that would otherwise infringe my copyright in them 24 | 25 | 2. do anything with my contributions that would otherwise infringe patents that I can or become able to license 26 | 27 | 3. sublicense these rights to others on any terms they like 28 | 29 | ## Reliability 30 | 31 | I understand that Blockchain Commons will rely on this license. I may not revoke this license. 32 | 33 | ## Awareness 34 | 35 | I promise that I am familiar with legal rules, like ["work made for hire" rules](http://worksmadeforhire.com), that can give employers and clients ownership of intellectual property in work that I do. I am also aware that legal agreements I might sign, like confidential information and invention assignment agreements, will usually give ownership of intellectual property in my work to employers, clients, and companies that I found. If someone else owns intellectual property in my work, I need their permission to license it. 36 | 37 | ## Copyright Guarantee 38 | 39 | I promise not to offer contributions to the project that contain copyrighted work that I do not have legally binding permission to contribute under these terms. When I offer a contribution with permission, I promise to document in the contribution who owns copyright in what work, and how they gave permission to contribute it. If I later become aware that one of my contributions may have copyrighted work of others that I did not have permission to contribute, I will notify Blockchain Commons, in confidence, immediately. 40 | 41 | ## Patent Guarantee 42 | 43 | I promise not to offer contributions to the project that I know infringe patents of others that I do not have permission to contribute under these terms. 44 | 45 | ## Open Source Guarantee 46 | 47 | I promise not to offer contributions that contain or depend on the work of others, unless that work is available under a license that [Blue Oak Council rates bronze or better](https://blueoakconcil.org/list), such as the MIT License, two- or three-clause BSD License, the Apache License Version 2.0, or the Blue Oak Model License 1.0.0. When I offer a contribution containing or depending on others' work, I promise to document in the contribution who licenses that work, along with copies of their license terms. 48 | 49 | ## Disclaimers 50 | 51 | ***As far as the law allows, my contributions come as is, without any warranty or condition. Other than under [Copyright Guarantee](#copyright-guarantee), [Patent Guarantee](#patent-guarantee), or [Open Source Guarantee](#open-source-guarantee), I will not be liable to anyone for any damages related to my contributions or this contributor license agreement, under any kind of legal claim.*** 52 | 53 | --- 54 | 55 | To sign this Contributor License Agreement, fill in `$name`, `$email`, and `$date` above. Then sign using GPG using the following command `gpg --armor --clearsign --output ./signed-cla/CLA.YOURGITHUBNAME.YOURGPGFINGERPRINT.asc CLA.md`, then either submit your signed Contributor License Agreement to this repo as a GPG signed Pull Request or email it to [ChristopherA@BlockchainCommons.com](mailto:ChristopherA@BlockchainCommons.com). 56 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # These owners will be the default owners for everything in this repo. 2 | 3 | * @ChristopherA 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | We love your input! We want to make contributing to this project as easy and transparent as possible, whether it's: 4 | 5 | - Reporting a bug 6 | - Discussing the current state of the code 7 | - Submitting a fix 8 | - Proposing new features 9 | - Becoming a maintainer 10 | 11 | ## We Develop with Github 12 | We use GitHub to host code, to track issues and feature requests, and to accept Pull Requests. 13 | 14 | ## Report Bugs using Github's Issues Tracker 15 | 16 | If you find bugs, mistakes, or inconsistencies in this project's code or documents, please let us know by [opening a new issue](./issues), but consider searching through existing issues first to check and see if the problem has already been reported. If it has, it never hurts to add a quick "+1" or "I have this problem too". This helps prioritize the most common problems and requests. 17 | 18 | ### Write Bug Reports with Detail, Background, and Sample Code 19 | 20 | [This is an example](http://stackoverflow.com/q/12488905/180626) of a good bug report by @briandk. Here's [another example from craig.hockenberry](http://www.openradar.me/11905408). 21 | 22 | **Great Bug Reports** tend to have: 23 | 24 | - A quick summary and/or background 25 | - Steps to reproduce 26 | - Be specific! 27 | - Give sample code if you can. [The stackoverflow bug report](http://stackoverflow.com/q/12488905/180626) includes sample code that *anyone* with a base R setup can run to reproduce what I was seeing 28 | - What you expected would happen 29 | - What actually happens 30 | - Notes (possibly including why you think this might be happening, or stuff you tried that didn't work) 31 | 32 | People *love* thorough bug reports. I'm not even kidding. 33 | 34 | ## Submit Code Changes through Pull Requests 35 | 36 | Simple Pull Requests to fix typos, to document, or to fix small bugs are always welcome. 37 | 38 | We ask that more significant improvements to the project be first proposed before anybody starts to code as an [issue](./issues) or as a [draft Pull Request](./pulls), which is a [nice new feature](https://github.blog/2019-02-14-introducing-draft-pull-requests/) that gives other contributors a chance to point you in the right direction, give feedback on the design, and maybe discuss if related work is already under way. 39 | 40 | ### Use a Consistent Coding Style 41 | 42 | * We indent using two spaces (soft tabs) 43 | * We ALWAYS put spaces after list items and method parameters ([1, 2, 3], not [1,2,3]), around operators (x += 1, not x+=1), and around hash arrows. 44 | * This is open-source software. Consider the people who will read your code, and make it look nice for them. It's sort of like driving a car: Perhaps you love doing donuts when you're alone, but with passengers the goal is to make the ride as smooth as possible. 45 | 46 | ### Use [Github Flow](https://guides.github.com/introduction/flow/index.html) for Pull Requests 47 | 48 | We use [Github Flow](https://guides.github.com/introduction/flow/index.html). When you submit Pull Requests, please: 49 | 50 | 1. Fork the repo and create your branch from `master`. 51 | 2. If you've added code that should be tested, add tests. 52 | 3. If you've changed APIs, update the documentation. 53 | 4. Ensure the test suite passes. 54 | 5. Make sure your code lints. 55 | 6. Issue that Pull Request! 56 | 57 | ### Submit Under the BSD-2-Clause Plus Patent License 58 | 59 | In short, when you submit code changes, your submissions are understood to be available under the same [BSD-2-Clause Plus Patent License](./LICENSE.md) that covers the project. We also ask all code contributors to GPG sign the [Contributor License Agreement (CLA.md)](./CLA.md) to protect future users of this project. Feel free to contact the maintainers if that's a concern. 60 | 61 | ## References 62 | 63 | Portions of this CONTRIBUTING.md document were adopted from best practices of a number of open source projects, including: 64 | * [Facebook's Draft](https://github.com/facebook/draft-js/blob/a9316a723f9e918afde44dea68b5f9f39b7d9b00/CONTRIBUTING.md) 65 | * [IPFS Contributing](https://github.com/ipfs/community/blob/master/CONTRIBUTING.md) 66 | -------------------------------------------------------------------------------- /Investigation/Formats.md: -------------------------------------------------------------------------------- 1 | # Formats 2 | 3 | This is a catalog of various formats for blockchain-related things that we might want to publish or even specify in the future or for compatibility in projects like Gordian Seed Tool. 4 | 5 | ## Seed Formats 6 | 7 | * QR Code of Recovery Words 8 | * See https://github.com/BlockchainCommons/GordianSeedTool-iOS/issues/66 9 | * Numbered lists of words and bare words have both been used 10 | * QR Code, Encrypting Recovery Words 11 | * See https://github.com/BlockchainCommons/GordianSeedTool-iOS/issues/67#issuecomment-1055827481 12 | * See https://anderson-arlen.github.io/cryptoseed/ 13 | * "Your recovery seed is encrypted with the Cipher Block Chaining (CBC) mode of the Advanced Encryption Standard with a 256 bit key length. Your key is generated using a password of your choice and a random salt, hashed 1 million times with pbkdf2 (sha512). Encrypting the same data with the same key will yield a different result every time." 14 | * 7zip of Backup 15 | * See https://github.com/BlockchainCommons/GordianSeedTool-iOS/issues/138#issuecomment-1048477394 16 | * For Foundation Devices, Backup is Encrypted with 6 Bytewords separated by spaces 17 | * ColdCard uses a similar methodology 18 | -------------------------------------------------------------------------------- /Investigation/Passwords.md: -------------------------------------------------------------------------------- 1 | # Password Best Practices 2 | 3 | What are the best practices for generating encryption keys from passwords? 4 | 5 | Current best practices are to make key-derivation processes costly. Some algorithms such as PBKDF2 do so via [key stretching](https://en.wikipedia.org/wiki/Key_stretching), to dramatically increase the CPU resources required to generate a key from a password, making it more difficult to brute-force the key. Generally, this means: combine a password with both a fixed salt (for the site) and a unique salt and then either use a slow hasing algorithm or hash thousands of times. 6 | 7 | Some algorithms such as Bcrypt and [Scrypt](https://datatracker.ietf.org/doc/html/rfc7914) instead require high memory resources, to sidestep GPU attacks. 8 | 9 | * PHP still uses bcrypt as default for password hashing, but has support for Argon2. 10 | * 7zip uses [SHA-256 executed 218 (262144) times](https://en.wikipedia.org/wiki/7z#Encryption) for the encryption of its data. 11 | * This [overview](https://medium.com/analytics-vidhya/password-hashing-pbkdf2-scrypt-bcrypt-and-argon2-e25aaf41598e) suggests Argon2 or else Scrypt as the most robust current options. 12 | * OWASP [suggests] Argon2id, then bcrypt. 13 | 14 | * There's also discussion that long pass phrases are more secure than increasing key-derivation time, as per [this article](https://blog.benpri.me/blog/2019/01/13/why-you-shouldnt-be-using-bcrypt-and-scrypt/). 15 | -------------------------------------------------------------------------------- /Investigation/X_0_Expanding_Bitcoin_Transactions_with_Schnorr.md: -------------------------------------------------------------------------------- 1 | # Chapter X: Expanding Bitcoin Transactions with Schnorr 2 | The traditionally used ECDSA signatures in Bitcoin for authenticating transactions are standardized but have a number of downsides like non-linearity, signature malleability, to name a few. 3 | These issues do not exist in the case of Schnorr signatures. Schnorr, being inherently non-malleable and linear, allows usage of various cryptographic tools in Bitcoin like MuSig, Adopter Signature and Cross-Input signature aggregation. This section aims to develop an understanding of Schnorr Signatures and their usage in Bitcoin transactions. 4 | ## Objectives for This Section 5 | After working through this chapter, a developer will be able to: 6 | * Understand the Math of Schnorr and it's advantages 7 | * Sign, Add and Read a Schnorr Signature 8 | 9 | 10 | Supporting objectives include the ability to: 11 | * Use Schnorr with Taproot 12 | * Understand the Use of Adapter Signatures 13 | * Support MuSig with Schnorr 14 | ## Table of Contents 15 | 16 | * [Section One: Understanding Schnorr Signatures]() 17 | * [Section Two: Using Schnorr Signatures]() 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Unless otherwise noted (either in /README.md or in the file's header comments) the contents of this repository are released under the following license: 2 | 3 | BSD-2-Clause Plus Patent License 4 | 5 | SPDX-License-Identifier: [BSD-2-Clause-Patent](https://spdx.org/licenses/BSD-2-Clause-Patent.html) 6 | 7 | Copyright © 2019 Blockchain Commons, LLC 8 | 9 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 10 | 11 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 12 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 13 | Subject to the terms and conditions of this license, each copyright holder and contributor hereby grants to those receiving rights under this license a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except for failure to satisfy the conditions of this license) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer this software, where such license applies only to those patent claims, already acquired or hereafter acquired, licensable by such copyright holder or contributor that are necessarily infringed by: 14 | 15 | (a) their Contribution(s) (the licensed copyrights of copyright holders and non-copyrightable additions of contributors, in source or binary form) alone; or 16 | (b) combination of their Contribution(s) with the work of authorship to which such Contribution(s) was added by such copyright holder or contributor, if, at the time the Contribution is added, such addition causes such combination to be necessarily infringed. The patent license shall not apply to any other combinations which include the Contribution. 17 | Except as expressly stated above, no rights or licenses from any copyright holder or contributor is granted under this license, whether expressly, by implication, estoppel or otherwise. 18 | 19 | DISCLAIMER 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | -------------------------------------------------------------------------------- /images/logos/README.md: -------------------------------------------------------------------------------- 1 | Logo files for Blockchain Commons Research. 2 | -------------------------------------------------------------------------------- /images/logos/bcc-research-screen.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockchainCommons/Research/f48872e3f858e9b86957f16f39149f3e1c47b24f/images/logos/bcc-research-screen.jpg -------------------------------------------------------------------------------- /images/logos/bcc-research-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockchainCommons/Research/f48872e3f858e9b86957f16f39149f3e1c47b24f/images/logos/bcc-research-screen.png -------------------------------------------------------------------------------- /images/logos/bcc-research-screen.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockchainCommons/Research/f48872e3f858e9b86957f16f39149f3e1c47b24f/images/logos/bcc-research-screen.psd -------------------------------------------------------------------------------- /papers/bcr-2020-001-entropy-to-seed.md: -------------------------------------------------------------------------------- 1 | # Uniformly Translating Entropy into Cryptographic Seeds 2 | ## BCR-2020-001 3 | 4 | **© 2020 Blockchain Commons** 5 | 6 | Authors: Wolf McNally, Christopher Allen
7 | Date: April 8, 2020
8 | Revised: June 25, 2020 9 | 10 | --- 11 | 12 | A simple scheme for uniformly translating human-provided entropy into a cryptographic seed is proposed. The goal is to suggest an approach that is easy to understand and to code in various programming languages, in order to maximize compatibility between implementations over time. 13 | 14 | Existing third-party tools do *not* use this proposed system and instead use a variety of idiosyncratic approaches. It would be helpful if implementers standardized on a single approach. 15 | 16 | **NOTE**: The strength of the resulting seed is still only as strong as the number of bits of entropy provided, and the method used to generate it. This proposal does not address this possible weakness one way or the other. 17 | 18 | Any human-generated or entered entropy can be represented as an array of bytes. Entropy is generated and then entered in *input form units*: 19 | 20 | * Binary digits (coin tosses) 21 | * Decimal digits 22 | * Die rolls 23 | * Playing cards drawn from a shuffled deck 24 | * Arbitrary integers in the range [0-255]. 25 | 26 | After each input form unit is syntax-checked, it is transformed into a binary representation in an array: 27 | 28 | * Bits "011010" would translate to the byte array {0x00, 0x01, 0x01, 0x00, 0x01, 0x00}. 29 | * Die rolls "123456" would translate to the byte array {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}. 30 | * The integers "36 24 51 58 71 47" would translate to the byte array {0x24, 0x18, 0x33, 0x3a, 0x47, 0x2f}. 31 | * Playing cards use a simple function to convert the letter representation to an integer in [0-51]: 32 | * Suits are most-significant and have values: {"c": 0, "d": 1, "h": 2, "s": 3} 33 | * Ranks are least-significant and have values: {"a": 0, "2": 1, "3": 2, "4": 3, "5": 4, "6": 5, "7": 6, "8": 7, "9": 8, "t": 9, "j": 10, "q": 11, "k": 12} 34 | * So the binary representation of a card is `suit * 13 + rank`. So for example 5♥ would be: 2 * 13 + 4 = 30. 35 | * Card values are case-insensitive and can be entered or displayed in any case. If they are stored as text, canonically they are stored in lower case. 36 | 37 | Once you have the byte array, perform SHA256 on it and use the resulting digest as a seed for a HKDF_SHA256-based RNG. Arbitrary amounts of random numbers can then be generated and used as seeds for other purposes like HD key derivation. 38 | 39 | **⚠️ Warning:** The authors note that the seed used as input to this RNG algorithm should be used only once. 40 | 41 | Benefits: 42 | 43 | * The entire 8-bit range can be used for the entropy. 44 | * There is no complex math or bit packing to do. 45 | * Although entropy should be randomly generated, any UTF-8 string could be used if desired 46 | * Bits("011010"), Base10("011010") and Ints("0 1 1 0 1 0") all represent the same entropy, simplifying the human interpretation of the syntax of an entropy string. 47 | -------------------------------------------------------------------------------- /papers/bcr-2020-002-bech32-seed-format.md: -------------------------------------------------------------------------------- 1 | # Bech32 Encoding for Cryptographic Seeds 2 | ## BCR-2020-002 3 | 4 | **© 2020 Blockchain Commons** 5 | 6 | Author: Wolf McNally
7 | Date: April 22, 2020 8 | 9 | ### DEPRECATED 10 | 11 | The content below is now deprecated and of historical interest only. 12 | 13 | --- 14 | 15 | ### Introduction 16 | 17 | [BIP173] "Bech32" is a checksummed base32 format, and a standard for native segregated witness output addresses. 18 | 19 | A scheme for using Bech32 encoding for generalized cryptographic seeds is proposed. [BIP173] defines not only the syntactical format, but also a segwit version byte that is unnecessary for encoding a simple string of pseudorandom data. 20 | 21 | ### Specification 22 | 23 | For cryptographic seeds, the "human readable part" (HRP) of the Bech32 encoding shall be `seed`. This means that bech32-encoded cryptographic seeds will be recognizable by starting with the characters `seed1` (The HRP + the mandatory numeral `1` divider.) 24 | 25 | The payload of the seed shall be a minimum of 1 byte and a maximum of 64 bytes. 26 | 27 | The payload of the seed shall be encoded as per [BIP173], leaving out the segwit version byte. 28 | 29 | The checksum of the seed shall be calculated as per [Bech32bis]. 30 | 31 | ### Test Vectors 32 | 33 | | Length | Hex/Bech32 | 34 | |--------|------------| 35 | | 1 | `ee`
`seed1acu7gj09` | 36 | | 16 | `012f984d5b30831d4a256cdbcc0d5029`
`seed1qyhesn2mxzp36j39dnducr2s9y5fu50r` | 37 | | 32 | `80c35bd93dbbf67cdc046cb6eb2fb8f0fefe4aaefd71b23fe9aa337a5b537e19`
`seed1srp4hkfah0m8ehqydjmwktac7rl0uj4wl4cmy0lf4geh5k6n0cvsj4f3dy` | 38 | | 64 | `a2e77b0f0147801c3cc34c6341716e4fed12005e664820bacf0f6b5eabb1fcfff5ca2bdd1a25dc4f7354df3a430a7bce2d8eb63ae69e7e90a8f689002cae156a`
`seed15tnhkrcpg7qpc0xrf335zutwflk3yqz7veyzpwk0pa44a2a3lnlltj3tm5dzthz0wd2d7wjrpfauutvwkcawd8n7jz50dzgq9jhp26sxcqn82` | 39 | 40 | ### References 41 | 42 | * [BIP173] Pieter Wuille et al, [Base32 address format for native v0-16 witness outputs 43 | ](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki) 44 | * [Bech32bis] Pieter Wuille, [Analysis of insertion in Bech32 strings](https://gist.github.com/sipa/a9845b37c1b298a7301c33a04090b2eb) 45 | -------------------------------------------------------------------------------- /papers/bcr-2020-003-uri-binary-compatibility.md: -------------------------------------------------------------------------------- 1 | # Encoding Binary Compatibly with URI Reserved Characters 2 | ## BCR-2020-003 3 | 4 | **© 2020 Blockchain Commons** 5 | 6 | Author: Wolf McNally
7 | Date: April 23, 2020
8 | Revised: June 25, 2020 9 | 10 | --- 11 | 12 | ### Introduction 13 | 14 | The goal of this paper is to identify a method for encoding arbitrary binary blobs to text that is also suitable for embedding within a well-formed URI string. 15 | 16 | ### URI Reserved and Unreserved Characters 17 | 18 | [RFC3986] defines a subset of printable ASCII as "reserved characters" whose purpose is to "provide a set of delimiting characters that are distinguishable from other data within a URI." Characters in the reserved set are protected from normalization and are therefore safe to be used by scheme-specific and producer-specific algorithms for delimiting data sub-components within a URI: 19 | 20 | ``` 21 | :/?#[]@!$&'()*+,;= 22 | ``` 23 | 24 | In addition, the "%" character is use to introduce escape sequences allowing other characters to be encoded. This produces the URI reserved subset: 25 | 26 | ![](bcr-2020-003/1.png) 27 | 28 | [RFC3986] also defines another subset of printable ASCII as "unreserved characters" that are allowed in a URI but do not have a reserved purpose: 29 | 30 | ``` 31 | ALPHA DIGIT -._~ 32 | ``` 33 | 34 | ![](bcr-2020-003/2.png) 35 | 36 | The remaining printable ASCII codepoints are neither "reserved" nor "unreserved" by [RFC3986] and the implication is that these codepoints should be avoided in URIs because they are often used in operating system commands and scripts. 37 | 38 | ``` 39 | SP "<>\^`{|} 40 | ``` 41 | 42 | ![](bcr-2020-003/3.png) 43 | 44 | The union of all the reserved or to-be-avoided codepoints with the unreserved codepoints shows that every printable codepoint in the ASCII space is disposed. 45 | 46 | ![](bcr-2020-003/4.png) 47 | 48 | ### Base64 Characters 49 | 50 | [RFC4648] defines the Base64 encoding standard. The character set of Base64 collides with the URI reserved character set in three places: 51 | 52 | ``` 53 | +/= 54 | ``` 55 | 56 | ![](bcr-2020-003/5.png) 57 | 58 | To allow binary data to be efficiently encoded in URIs, [RFC4648] also defines the Base64URL variant, which moves the "+" codepoint to "-", moves the "/" codepoint to "_", and drops the use of padding with "=". This removes all the collisions with the URI reserved subset. 59 | 60 | ![](bcr-2020-003/6.png) 61 | 62 | ### Hexadecimal 63 | 64 | Encoding binary payloads in hexadecimal is compatible with URIs, but only results in 50% efficiency as opposed to Base64URL, which achieves 75%, as described in [BinaryToText]. 65 | 66 | ![](bcr-2020-003/11.png) 67 | 68 | ### Base58 69 | 70 | [Base58] is similar to Base64 but has been modified to avoid both non-alphanumeric characters and letters which might look ambiguous when printed. Base58 achieves 73% efficiency. 71 | 72 | Base58Check is a Base58 encoding format that unambiguously encodes the type of data in the first few characters and includes an error detection code in the last few characters. Base58Check also includes a leading metadata byte that is 0 for Bitcoin addresses. 73 | 74 | ![](bcr-2020-003/12.png) 75 | 76 | ### Bech32 77 | 78 | The [Bech32] encoding standard encodes its payload using 32 alphanumeric characters omitting: 79 | 80 | ``` 81 | 1bio 82 | ``` 83 | 84 | ![](bcr-2020-003/7.png) 85 | 86 | [Bech32] also defines "1" as the separator between the human-readable part (HRP) and the payload. 87 | 88 | ![](bcr-2020-003/8.png) 89 | 90 | So far, all of the characters that Bech32 use come from the "unreserved" subset of URI characters. Unfortunately, [Bech32] defines the HRP as consisting of 1-83 characters in the ASCII range 33-126, which heavily collides with the URI reserved subset. 91 | 92 | ![](bcr-2020-003/9.png) 93 | 94 | ### QR Code Alphanumeric Encoding 95 | 96 | The QR Code Alphanumeric Encoding Mode listed at [QRCodeAlphaNum] defines 45 codepoints that if used exclusively result in a lower-density QR code. Unfortunately these codepoints collide significantly with the URI reserved subset. 97 | 98 | ![](bcr-2020-003/10.png) 99 | 100 | ### BC32 101 | 102 | The [BC32] encoding method uses the same character set as Bech32 and uses the same checksum, but drops the human readable part. This makes the BC32 encoding method compatible with both QR code alphanumeric encoding (when translated to upper case letters) and the URI non-reserved character set. 103 | 104 | ### Bytewords 105 | 106 | The Bytewords [BYTEWORDS] encoding method uses only ASCII letters, is not case sensitive, and encodes each byte as either a four-letter English word, or minimally as the first and last letters of that word. It also appends a 32-bit (4 byte, 4 word) CRC32 checksum. Setting aside the checksum, from an efficiency perspective this it is the same as hexadecimal, using two ASCII characters to encode each byte. Unlike hexadecimal, where any pair of hexadecimal digits represents a valid byte, only 256 specific pairings of English letters represent valid bytes, making catching transcription errors more likely. Bytewords also specifies two encoding modes: "normal" and "brutal." In normal mode the encoded data must be a self-describing CBOR structure and in brutal mode it can be any string of bytes. Both modes include the four-word checksum at the end. 107 | 108 | ### Comparison 109 | 110 | | Method | Bits/char | URI-Friendly | QR-Friendly | Human-Friendly | Self-Describing | Checksum (bits) | Multi-Part | 111 | |-|-|-|-|-|-|--|--| 112 | | Base64 | 6 113 | | Base64URL | 6 |🟢 114 | | Base58 | 5.86 |🟢|🟢||🟢 115 | | Base58Check | 5.86 |🟢|🟢||🟢| 32 116 | | Bech32 | 5 ||||🟢| 30 117 | | BC32 | 5 |🟢|🟢||| 30 118 | | UR-BC32 | 5 |🟢|🟢||🟢| 30 |🟢 119 | | Hexadecimal | 4 |🟢|🟢 120 | | Bytewords | 4 |🟢|🟢|🟢|🟢| 32 121 | | Bytewords-brutal | 4 |🟢|🟢|🟢|| 32 122 | | UR-Bytewords | 4 |🟢|🟢|🟢|🟢| 32 |🟢 + Fountain Codes 123 | 124 | * **Method**: The name of the encoding method. 125 | * **Bits/char**: The number of bits encoded per encoding output character, without considering other structural elements. 126 | * **URI-Friendly**: Does this method output characters only in the URI unreserved character set? 127 | * **QR-Friendly**: Does this method output characters only in the QR Code alphanumeric encoding character set or translatable to that set via capitalization? 128 | * **Human-Friendly**: Does this method output English words or mnemonics that can be easily remembered or transcribed onto permanent media such as metal tags? 129 | * **Self-Describing**: Does this method include structural elements to allow a decoder to determine type or other structural aspects of the encoded data? 130 | * **Checksum**: How many bits of checksum are included in the encoded output? 131 | * **Multi-Part**: Does this method provide for the breaking of large amounts of data (too much to fit into a single QR code) into smaller parts? 132 | 133 | ### References 134 | 135 | * [RFC3986] [Uniform Resource Identifier (URI): Generic Syntax](https://tools.ietf.org/html/rfc3986) 136 | * [RFC4648] [The Base16, Base32, and Base64 Data Encodings](https://tools.ietf.org/html/rfc4648) 137 | * [CBOR] [Concise Binary Object Representation (CBOR)](https://tools.ietf.org/html/rfc7049) 138 | * [Bech32] [BIP-173: Base32 address format for native v0-16 witness outputs](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki) 139 | * [QRCodeAlphaNum] [Table of Alphanumeric Values](https://www.thonky.com/qr-code-tutorial/alphanumeric-table) 140 | * [BinaryToText] [Binary-to-text Encoding](https://en.wikipedia.org/wiki/Binary-to-text_encoding) 141 | * [Base58] [Base58](https://en.wikipedia.org/wiki/Base58) 142 | * [BC32] [BCR-2020-004: The BC32 Data Encoding Format](bcr-2020-004-bc32.md) 143 | * [UR] [BCR-2020-005: Uniform Resources (UR)](bcr-2020-005-ur.md) 144 | * [BYTEWORDS] [BCR-2020-012: Bytewords: Encoding binary data as English words](bcr-2020-012-bytewords.md) 145 | -------------------------------------------------------------------------------- /papers/bcr-2020-003/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockchainCommons/Research/f48872e3f858e9b86957f16f39149f3e1c47b24f/papers/bcr-2020-003/1.png -------------------------------------------------------------------------------- /papers/bcr-2020-003/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockchainCommons/Research/f48872e3f858e9b86957f16f39149f3e1c47b24f/papers/bcr-2020-003/10.png -------------------------------------------------------------------------------- /papers/bcr-2020-003/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockchainCommons/Research/f48872e3f858e9b86957f16f39149f3e1c47b24f/papers/bcr-2020-003/11.png -------------------------------------------------------------------------------- /papers/bcr-2020-003/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockchainCommons/Research/f48872e3f858e9b86957f16f39149f3e1c47b24f/papers/bcr-2020-003/12.png -------------------------------------------------------------------------------- /papers/bcr-2020-003/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockchainCommons/Research/f48872e3f858e9b86957f16f39149f3e1c47b24f/papers/bcr-2020-003/2.png -------------------------------------------------------------------------------- /papers/bcr-2020-003/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockchainCommons/Research/f48872e3f858e9b86957f16f39149f3e1c47b24f/papers/bcr-2020-003/3.png -------------------------------------------------------------------------------- /papers/bcr-2020-003/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockchainCommons/Research/f48872e3f858e9b86957f16f39149f3e1c47b24f/papers/bcr-2020-003/4.png -------------------------------------------------------------------------------- /papers/bcr-2020-003/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockchainCommons/Research/f48872e3f858e9b86957f16f39149f3e1c47b24f/papers/bcr-2020-003/5.png -------------------------------------------------------------------------------- /papers/bcr-2020-003/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockchainCommons/Research/f48872e3f858e9b86957f16f39149f3e1c47b24f/papers/bcr-2020-003/6.png -------------------------------------------------------------------------------- /papers/bcr-2020-003/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockchainCommons/Research/f48872e3f858e9b86957f16f39149f3e1c47b24f/papers/bcr-2020-003/7.png -------------------------------------------------------------------------------- /papers/bcr-2020-003/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockchainCommons/Research/f48872e3f858e9b86957f16f39149f3e1c47b24f/papers/bcr-2020-003/8.png -------------------------------------------------------------------------------- /papers/bcr-2020-003/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockchainCommons/Research/f48872e3f858e9b86957f16f39149f3e1c47b24f/papers/bcr-2020-003/9.png -------------------------------------------------------------------------------- /papers/bcr-2020-004-bc32.md: -------------------------------------------------------------------------------- 1 | # The BC32 Data Encoding Format 2 | ## BCR-2020-004 3 | 4 | **© 2020 Blockchain Commons** 5 | 6 | Authors: Wolf McNally, Christopher Allen
7 | Date: May 5, 2020 8 | 9 | ### DEPRECATED 10 | 11 | The content below is now deprecated and of historical interest only. 12 | 13 | --- 14 | 15 | ### Introduction 16 | 17 | The [Bech32] checksummed base32 format was introduced to transport segregated witness signatures for Bitcoin. It has several desirable qualities: 18 | 19 | * The payload and checksum data use a limited character set compatible with both URI syntax and QR code alphanumeric encoding mode. 20 | * The character set uses the letters A-Z in a case-modal fashion (i.e., one can use all upper case or all lower case but the algorithm rejects mixed-case.) 21 | * The character set is chosen to minimize ambiguity, and the ordering is chosen to minimize the number of pairs of similar characters. 22 | * Built-in error detection and optional error location for payloads <80 characters. 23 | * Because the character set used are all "word characters", most text editors will select the entire sequence of characters when it is double-clicked. 24 | 25 | However, it also has a major drawback when considered for general data encoding: 26 | 27 | * The characters allowed for the human readable part ("HRP") conflict with both URI syntax and QR code alphanumeric encoding mode. 28 | * The HRP is not useful to identify a wide variety of general structured data types. 29 | 30 | ### Proposal 31 | 32 | This document proposes a new, more general data encoding format *BC32* that is based on Bech32 but makes the following modifications: 33 | 34 | * The HRP and numeral `1` divider are no longer included. 35 | * **TODO:** Checksum parameters are defined to handle error correction and identification for larger payloads. 36 | 37 | ### Relative Efficiency 38 | 39 | The following table compares the relative efficiency of various binary-to-text encoding methods. base32 encoding (and BC32 excluding the checksum) is 12.5% less efficient than base64, but also 12.5% more efficient than hexadecimal. The benefit gained by using only 32 characters is seamless compatibility with both QR code alphanumeric encoding and URI syntax. 40 | 41 | | Format | Number of characters | Number of bits per character | Efficiency compared to raw binary | 42 | |---|---|---|---| 43 | | raw binary | 256 | 8.0 | 100% | 44 | | base64 | 64 | 6.0 | 75% | 45 | | base45 (QR Code alphanumeric) | 45 | 5.49185 | 68.65% | 46 | | base32, bech32, BC32 (not including checksum) | 32 | 5.0 | 62.5% | 47 | | hexadecimal | 16 | 4.0 | 50% | 48 | 49 | **✳️ Note:** Although it would appear that base32 is always less efficient than base64, this is not the case when encoding a payload for transport in QR codes. Because BC32 uses a character set optimized for the more efficient QR code alphanumeric mode, a payload of 1000 random bytes results in a QR code 13% less dense when the payload is encoded with BC32, compared to the same payload encoded as Base64. 50 | 51 | ### Implementations 52 | 53 | Current implementations: 54 | 55 | * Implemented by `bc32_seed_encode()` and `bc32_seed_decode()` in the Blockchain Commons [bc-bech32](https://github.com/blockchaincommons/bc-bech32) library. 56 | * Implemented as a [Wolfram Language (Mathematica) module accompanying this document](bcr-2020-004/BC32.nb). 57 | * Implemented as [bc-bech32](https://github.com/CoboVault/cobo-vault-blockchain-base/tree/master/packages/bc-bech32) on Typescript/javascript 58 | 59 | ### Test Vectors 60 | 61 | | Input | BC32 Encoded | 62 | |---|---| 63 | | "Hello world" (UTF-8) == 48656c6c6f20776f726c64 | fpjkcmr0ypmk7unvvsh4ra4j | 64 | | d934063e82001eec0585ee41ab5d8e4b703a4be1f73aec21e143912c56 | my6qv05zqq0wcpv9aeq6khvwfdcr5jlp7uawcg0pgwgjc4shjm6xu | 65 | 66 | ### References 67 | 68 | * [Bech32] [BIP-173: Base32 address format for native v0-16 witness outputs](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki) 69 | 70 | ### Unused References 71 | -------------------------------------------------------------------------------- /papers/bcr-2020-005/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockchainCommons/Research/f48872e3f858e9b86957f16f39149f3e1c47b24f/papers/bcr-2020-005/1.png -------------------------------------------------------------------------------- /papers/bcr-2020-006/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockchainCommons/Research/f48872e3f858e9b86957f16f39149f3e1c47b24f/papers/bcr-2020-006/1.png -------------------------------------------------------------------------------- /papers/bcr-2020-006/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockchainCommons/Research/f48872e3f858e9b86957f16f39149f3e1c47b24f/papers/bcr-2020-006/2.png -------------------------------------------------------------------------------- /papers/bcr-2020-006/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockchainCommons/Research/f48872e3f858e9b86957f16f39149f3e1c47b24f/papers/bcr-2020-006/6.png -------------------------------------------------------------------------------- /papers/bcr-2020-007/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockchainCommons/Research/f48872e3f858e9b86957f16f39149f3e1c47b24f/papers/bcr-2020-007/1.png -------------------------------------------------------------------------------- /papers/bcr-2020-007/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockchainCommons/Research/f48872e3f858e9b86957f16f39149f3e1c47b24f/papers/bcr-2020-007/2.png -------------------------------------------------------------------------------- /papers/bcr-2020-008-eckey.md: -------------------------------------------------------------------------------- 1 | # UR Type Definition for Elliptic Curve (EC) Keys 2 | 3 | ## BCR-2020-008 4 | 5 | **© 2020 Blockchain Commons** 6 | 7 | Authors: Wolf McNally, Christopher Allen
8 | Date: June 5, 2020
9 | Revised: November 25, 2023 10 | 11 | --- 12 | 13 | ### Introduction 14 | 15 | Elliptical Curve Keys (ECKeys) have numerous uses in cryptocurrencies and elsewhere [EC-Crypto](https://en.wikipedia.org/wiki/Elliptic-curve_cryptography). Like other forms of public key cryptography, EC keys come in two flavors: private and public. Public EC keys come in two flavors, compressed and uncompressed, with compressed being preferred. 16 | 17 | The only other variable that needs to be determined to create an EC key is the elliptic curve parameters, with the parameters known as "secp256k1" being the most popular and the ones that Bitcoin is based on. 18 | 19 | ## UR Types and CBOR Tags 20 | 21 | This document defines the following UR types along with their corresponding CBOR tags: 22 | 23 | | UR type | CBOR Tag | 24 | | :----------- | :------- | 25 | | ur:eckey | #6.40306 | 26 | 27 | These tags have been registered in the [IANA Registry of CBOR Tags](https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml). 28 | 29 | This specification defines a UR type `eckey` (CBOR tag #6.40306) for encoding and transmitting EC private and public keys. 30 | 31 | **Note:** This specification describes version 2 `eckey` (#6.40306), which differs from version 1 `crypto-eckey` (#6.306) only in the UR type and CBOR tag it uses. Version 1 `crypto-eckey` is deprecated, but may still be supported for backwards compatibility. 32 | 33 | ### EC Curve Selector 34 | 35 | [SEC2-ECPARMS](http://www.secg.org/sec2-v2.pdf) lists 20 sets of parameters for elliptic curve cryptography, and a current invocation of `openssl ecparam -list_curves | wc -l` shows that OpenSSL currently supports 87. The `curve` field below selects which curve is used by the represented key. However, the only value specified in the current version of this document is `0` which represents the curve `secp256k1`. 36 | 37 | ### Key Data 38 | 39 | The required `data` field carries the key data. The length of this field will depend on the curve, whether it is a public or private key, and if it is a public key, whether or not it is represented in compressed format. 40 | 41 | For the `secp256k1` curve, the `data` field MUST contain exactly 32 bytes for a private key, or 64 bytes for an uncompressed public key, or 33 bytes (including the 1-byte prefix) for a compressed public key. 42 | 43 | The `curve` and `is-private` fields allow a decoder to determine the nature of the key and whether it is supported by the encoder, without having to parse the contents of the `data` field. 44 | 45 | ### CDDL 46 | 47 | The following specification is written in Concise Data Definition Language [CDDL](https://tools.ietf.org/html/rfc8610). 48 | 49 | ``` 50 | tagged-eckey = #6.40306(eckey) 51 | 52 | eckey = { 53 | ? curve: uint .default 0, 54 | ? is-private: bool .default false, 55 | data: bytes 56 | } 57 | 58 | curve = 1 59 | is-private = 2 60 | data = 3 61 | ``` 62 | 63 | ### Example/Test Vector 1 64 | 65 | * An EC private key: 66 | 67 | ``` 68 | $ seedtool --count 32 69 | 8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa 70 | ``` 71 | 72 | * In the CBOR diagnostic notation: 73 | 74 | ``` 75 | { 76 | ; `curve` is implied to be 0 (secp256k1) 77 | 2: true, ; is-private 78 | 3: h'8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa' ; data 79 | } 80 | ``` 81 | 82 | * Encoded as binary using [CBOR-PLAYGROUND](http://cbor.me): 83 | 84 | ``` 85 | a2 # map(2) 86 | 02 # unsigned(2) is-private 87 | f5 # primitive(21) true 88 | 03 # unsigned(3) data 89 | 58 20 # bytes(32) 90 | 8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa 91 | ``` 92 | 93 | * As a hex string: 94 | 95 | ``` 96 | a202f50358208c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa 97 | ``` 98 | 99 | * As a UR: 100 | 101 | ``` 102 | ur:eckey/oeaoykaxhdcxlkahssqzwfvslofzoxwkrewngotktbmwjkwdcmnefsaaehrlolkskncnktlbaypkrphsmyid 103 | ``` 104 | 105 | * UR as QR Code: 106 | 107 | ![](bcr-2020-008/1.png) 108 | 109 | ### Example/Test Vector 2 110 | 111 | * Convert the private key above into a public key: 112 | 113 | ``` 114 | $ bx ec-to-public 115 | 8c05c4b4f3e88840a4f4b5f155cfd69473ea169f3d0431b7a6787a23777f08aa 116 | ^D 117 | 03bec5163df25d8703150c3a1804eac7d615bb212b7cc9d7ff937aa8bd1c494b7f 118 | ``` 119 | 120 | * In the CBOR diagnostic notation: 121 | 122 | ``` 123 | { 124 | 3: h'03bec5163df25d8703150c3a1804eac7d615bb212b7cc9d7ff937aa8bd1c494b7f' ; data 125 | } 126 | ``` 127 | 128 | * Encoded as binary using [CBOR-PLAYGROUND](http://cbor.me): 129 | 130 | ``` 131 | a1 # map(1) 132 | 03 # unsigned(3) data 133 | 58 21 # bytes(33) 134 | 03bec5163df25d8703150c3a1804eac7d615bb212b7cc9d7ff937aa8bd1c494b7f 135 | ``` 136 | 137 | * As a hex string: 138 | 139 | ``` 140 | a103582103bec5163df25d8703150c3a1804eac7d615bb212b7cc9d7ff937aa8bd1c494b7f 141 | ``` 142 | 143 | * As a UR: 144 | 145 | ``` 146 | ur:eckey/oyaxhdclaxrnskcmfswzhlltaxbzbnftcsaawdsttbbzrkcldnkesotszmmuknpdrycegagrlbemdevtlp 147 | ``` 148 | 149 | * UR as QR Code: 150 | 151 | ![](bcr-2020-008/2.png) 152 | -------------------------------------------------------------------------------- /papers/bcr-2020-009-address.md: -------------------------------------------------------------------------------- 1 | # UR Type Definition for Cryptocurrency Addresses 2 | 3 | ## BCR-2020-009 4 | 5 | **© 2020 Blockchain Commons** 6 | 7 | Authors: Wolf McNally, Christopher Allen
8 | Date: June 6, 2020
9 | Revised: November 25, 2023 10 | 11 | --- 12 | 13 | ### Introduction 14 | 15 | Bitcoin, Ethereum, and other cryptocurrencies use [addresses](https://en.bitcoin.it/wiki/Address) as destinations for funds. Addresses are generated from public keys, which were in turn generated from private keys. Ultimately an address is just a string of bytes, but to facilitate recognition and handling by humans they are encoded as base58 (Bitcoin), bech32 (Bitcoin) or base16 (Ethereum). Encodings such as Bitcoin's include one or more tag characters at the front to help identify the string as an address, e.g., `1` for a Bitcoin P2PKH address or `m` for a Bitcoin testnet address, or `bc1` for a Bitcoin Bech32-encoded address. 16 | 17 | ## UR Types and CBOR Tags 18 | 19 | This document defines the following UR types along with their corresponding CBOR tags: 20 | 21 | | UR type | CBOR Tag | 22 | | :--------- | :------- | 23 | | ur:address | #6.40307 | 24 | 25 | These tags have been registered in the [IANA Registry of CBOR Tags](https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml). 26 | 27 | This specification defines a UR type `address` (CBOR tag #6.40307) for encoding and transmitting cryptocurrency addresses. 28 | 29 | The `info` field of the CBOR type defined herein references the `coininfo` type defined in [BCR-2020-007](bcr-2020-007-hdkey.md). This structure encodes both the type of coin and the network (main or test) the address is to be used with. If the optional `info` field is omitted, its defaults (mainnet Bitcoin address) are assumed. 30 | 31 | The `data` field encodes the raw byte string comprising the address. 32 | 33 | **Note:** This specification describes version 2 `address` (#6.40307), which differs from version 1 `crypto-address` (#6.307) only in the UR type and CBOR tag it uses. Version 1 `crypto-address` is deprecated, but may still be supported for backwards compatibility. 34 | 35 | ### CDDL 36 | 37 | The following specification is written in Concise Data Definition Language [CDDL](https://tools.ietf.org/html/rfc8610). 38 | 39 | When used embedded in another CBOR structure, this structure should be tagged #6.40307. 40 | 41 | ``` 42 | tagged-address = #6.40307(address) 43 | 44 | address = { 45 | ? info: tagged-coininfo, 46 | ? type: address-type, 47 | data: bytes 48 | } 49 | 50 | info = 1 51 | type = 2 52 | data = 3 53 | 54 | address-type = p2pkh / p2sh / p2wpkh 55 | p2pkh = 0 56 | p2sh = 1 57 | p2wpkh = 2 58 | 59 | ; The `type` field MAY be included for Bitcoin (and similar cryptocurrency) addresses, and MUST be omitted for non-applicable types. 60 | 61 | ; `data` contains: 62 | ; For addresses of type `p2pkh`, the hash160 of the public key (20 bytes). 63 | ; For addresses of type `p2sh`, the hash160 of the script bytes (20 bytes). 64 | ; For addresses of type `p2wphk`, the sha256 of the script bytes (32 bytes). 65 | ; For ethereum addresses, the last 20 bytes of the keccak256 hash of the public key (20 bytes). 66 | ``` 67 | 68 | ### Example/Test Vector 1 69 | 70 | * A mainnet Bitcoin address. 71 | 72 | ``` 73 | 1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2 74 | ``` 75 | 76 | * Decoded 77 | 78 | ``` 79 | $ bx address-decode 1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2 80 | wrapper 81 | { 82 | checksum 1802900980 83 | payload 77bff20c60e522dfaa3350c39b030a5d004e839a 84 | version 0 85 | } 86 | ``` 87 | 88 | * In the CBOR diagnostic notation: 89 | 90 | ``` 91 | { 92 | 3: h'77bff20c60e522dfaa3350c39b030a5d004e839a' ; data 93 | } 94 | ``` 95 | 96 | * Encoded as binary using [CBOR-PLAYGROUND]: 97 | 98 | ``` 99 | a1 # map(1) 100 | 03 # unsigned(3) ; data 101 | 54 # bytes(20) 102 | 77bff20c60e522dfaa3350c39b030a5d004e839a 103 | ``` 104 | 105 | * As a hex string: 106 | 107 | ``` 108 | a1035477bff20c60e522dfaa3350c39b030a5d004e839a 109 | ``` 110 | 111 | * As a UR: 112 | 113 | ``` 114 | ur:address/oyaxghktrswzbnhnvwcpurpkeogdsrndaxbkhlaegllsnyolrsemgu 115 | ``` 116 | 117 | * UR as QR Code: 118 | 119 | ![](bcr-2020-009/1.png) 120 | 121 | ### Example/Test Vector 2 122 | 123 | * A testnet Ethereum address. 124 | 125 | ``` 126 | 0x81b7E08F65Bdf5648606c89998A9CC8164397647 127 | ``` 128 | 129 | * In the CBOR diagnostic notation: 130 | 131 | ``` 132 | { 133 | 1: 40305({ / info: coininfo [BCR-2020-007] / 134 | 1: 60, / type: coin-type-eth (0x3c) [BCR-2020-007] / 135 | 2: 1 / network: testnet-eth-ropsten [BCR-2020-007] / 136 | }), 137 | 3: h'81b7e08f65bdf5648606c89998a9cc8164397647' / data / 138 | } 139 | ``` 140 | 141 | * Encoded as binary using [CBOR-PLAYGROUND]: 142 | 143 | ``` 144 | a2 # map(2) 145 | 01 # unsigned(1) info 146 | d9 9d71 # tag(40305) coininfo 147 | a2 # map(2) 148 | 01 # unsigned(1) type 149 | 18 3c # unsigned(60) coin-type-eth 150 | 02 # unsigned(2) network 151 | 01 # unsigned(1) testnet-eth-ropsten 152 | 03 # unsigned(3) data 153 | 54 # bytes(20) 154 | 81b7e08f65bdf5648606c89998a9cc8164397647 155 | ``` 156 | 157 | * As a hex string: 158 | 159 | ``` 160 | a201d99d71a201183c0201035481b7e08f65bdf5648606c89998a9cc8164397647 161 | ``` 162 | 163 | * As a UR: 164 | 165 | ``` 166 | ur:address/oeadtantjsoeadcsfnaoadaxghlyrlvtmyihryykielnamspnlmkptsflyieeskoflkovdfdlb 167 | ``` 168 | 169 | * UR as QR Code: 170 | 171 | ![](bcr-2020-009/2.png) 172 | -------------------------------------------------------------------------------- /papers/bcr-2020-009/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockchainCommons/Research/f48872e3f858e9b86957f16f39149f3e1c47b24f/papers/bcr-2020-009/1.png -------------------------------------------------------------------------------- /papers/bcr-2020-009/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockchainCommons/Research/f48872e3f858e9b86957f16f39149f3e1c47b24f/papers/bcr-2020-009/2.png -------------------------------------------------------------------------------- /papers/bcr-2020-012-bytewords.md: -------------------------------------------------------------------------------- 1 | # Bytewords: Encoding binary data as English words 2 | 3 | ## BCR-2020-012 4 | 5 | **© 2020 Blockchain Commons** 6 | 7 | Authors: Wolf McNally, Christopher Allen
8 | Date: June 20, 2020
9 | Revised: October 4, 2020 10 | 11 | ### Introduction 12 | 13 | Schemes like [BIP39] and [SLIP39] (see Appendix) encode a binary string as a series of human-readable words. This proposal specifies a scheme "Bytewords" with similar ends but: 14 | 15 | * Encodes a [CBOR] structure tagged with the data type [URTYPES], and is therefore self-describing. 16 | * Uses a dictionary of exactly 256 English words with a uniform word size of 4 letters. 17 | * Only two letters of each word (the first and last) are required to uniquely identify each byte value, making a minimal Bytewords encoding as efficient as hexadecimal (2 characters per byte) and yet less error prone. 18 | * Additionally, words can be uniquely identified by their first three letters or last three letters. 19 | * Representing each byte as a single word simplifies encoder and decoder architecture. 20 | * Minimizing the number of letters for each word simplifies transfer to permanent media such as stamped metal. 21 | * Using only ASCII letters (and a separator character, either space or hyphen) preserves compatibility with URI and QR code character sets. 22 | * Provides a four-word sequence at the end as a checksum of the entire sequence. 23 | 24 | ### Word selection criteria 25 | 26 | * All words are English. 27 | * All words are exactly 4 ASCII letters. 28 | * No proper names. 29 | * Prefer words in common usage. 30 | * Avoid homophones and near homophones. 31 | * Prefer two-syllable words. 32 | * Each word's first three letters must be a unique sequence (XXX-). 33 | * Each word's last three letters must be a unique sequence (-XXX). 34 | * Each word's first and last letters must be a unique sequence (X--X). 35 | * The Damerau-Levenshtein distance between any two words is at least 2. 36 | * Prefer words with positive connotations. 37 | * Prefer words which are "interesting" (strong emotional valence) even if connotation is neutral or slightly negative. 38 | * Avoid words with strong negative connotations. 39 | * Represent initial letters somewhat equally when possible. 40 | * Word list is sorted alphabetically. 41 | 42 | ### Word List 43 | 44 | ``` 45 | 0x00: able acid also apex aqua arch atom aunt 46 | 0x08: away axis back bald barn belt beta bias 47 | 0x10: blue body brag brew bulb buzz calm cash 48 | 0x18: cats chef city claw code cola cook cost 49 | 0x20: crux curl cusp cyan dark data days deli 50 | 0x28: dice diet door down draw drop drum dull 51 | 0x30: duty each easy echo edge epic even exam 52 | 0x38: exit eyes fact fair fern figs film fish 53 | 0x40: fizz flap flew flux foxy free frog fuel 54 | 0x48: fund gala game gear gems gift girl glow 55 | 0x50: good gray grim guru gush gyro half hang 56 | 0x58: hard hawk heat help high hill holy hope 57 | 0x60: horn huts iced idea idle inch inky into 58 | 0x68: iris iron item jade jazz join jolt jowl 59 | 0x70: judo jugs jump junk jury keep keno kept 60 | 0x78: keys kick kiln king kite kiwi knob lamb 61 | 0x80: lava lazy leaf legs liar limp lion list 62 | 0x88: logo loud love luau luck lung main many 63 | 0x90: math maze memo menu meow mild mint miss 64 | 0x98: monk nail navy need news next noon note 65 | 0xa0: numb obey oboe omit onyx open oval owls 66 | 0xa8: paid part peck play plus poem pool pose 67 | 0xb0: puff puma purr quad quiz race ramp real 68 | 0xb8: redo rich road rock roof ruby ruin runs 69 | 0xc0: rust safe saga scar sets silk skew slot 70 | 0xc8: soap solo song stub surf swan taco task 71 | 0xd0: taxi tent tied time tiny toil tomb toys 72 | 0xd8: trip tuna twin ugly undo unit urge user 73 | 0xe0: vast very veto vial vibe view visa void 74 | 0xe8: vows wall wand warm wasp wave waxy webs 75 | 0xf0: what when whiz wolf work yank yawn yell 76 | 0xf8: yoga yurt zaps zero zest zinc zone zoom 77 | ``` 78 | 79 | #### Distribution of initial letters 80 | 81 | | letter | count | 82 | |--------|-------| 83 | | a | 10 | 84 | | b | 12 | 85 | | c | 14 | 86 | | d | 13 | 87 | | e | 9 | 88 | | f | 15 | 89 | | g | 13 | 90 | | h | 12 | 91 | | i | 9 | 92 | | j | 10 | 93 | | k | 10 | 94 | | l | 15 | 95 | | m | 11 | 96 | | n | 8 | 97 | | o | 7 | 98 | | p | 11 | 99 | | q | 2 | 100 | | r | 12 | 101 | | s | 13 | 102 | | t | 13 | 103 | | u | 5 | 104 | | v | 9 | 105 | | w | 12 | 106 | | x | 0 | 107 | | y | 5 | 108 | | z | 6 | 109 | 110 | ### Checksum 111 | 112 | The CBOR body of an encoded Bytewords sequence is followed by a four-word (four byte, 32 bit) CRC32 checksum in network order (big-endian). 113 | 114 | The choice to use a CRC32 hash of a Bytewords body is open for comment. This issue is being tracked [here](https://github.com/BlockchainCommons/Research/issues/23). 115 | 116 | ### Example/Test Vector 117 | 118 | * A 16 byte (128-bit) cryptographic seed (`seed`) (tag #6.40300) [URTYPES] generated on May 13, 2020, in the CBOR diagnostic notation: 119 | 120 | ``` 121 | 40300({ 122 | 1: h'c7098580125e2ab0981253468b2dbc52', / payload / 123 | 2: 1(18394) / birthdate / 124 | }) 125 | ``` 126 | 127 | * Encoded as binary using [CBOR-PLAYGROUND]: 128 | 129 | ``` 130 | D9 9D6C # tag(40300) seed 131 | A2 # map(2) 132 | 01 # unsigned(1) payload: 133 | 50 # bytes(16) 134 | C7098580125E2AB0981253468B2DBC52 135 | 02 # unsigned(2) birthdate: 136 | C1 # tag(1) [CBOR-DATE] 137 | 19 47DA # unsigned(18394) 138 | ``` 139 | 140 | * Body as a hex string: 141 | 142 | ``` 143 | d99d6ca20150c7098580125e2ab0981253468b2dbc5202c11947da 144 | ``` 145 | 146 | * CRC32 Checksum: 147 | 148 | ``` 149 | c904f40b 150 | ``` 151 | 152 | * Body with checksum appended: 153 | 154 | ``` 155 | d99d6ca20150c7098580125e2ab0981253468b2dbc5202c11947dac904f40b 156 | ``` 157 | 158 | * Bytewords: 159 | 160 | ``` 161 | tuna next jazz oboe acid good slot axis limp lava 162 | brag holy door puff monk brag guru frog luau drop 163 | roof grim also safe chef fuel twin solo aqua work 164 | bald 165 | ``` 166 | 167 | * Bytewords (URI compatible): 168 | 169 | ``` 170 | tuna-next-jazz-oboe-acid-good-slot-axis-limp-lava- 171 | brag-holy-door-puff-monk-brag-guru-frog-luau-drop- 172 | roof-grim-also-safe-chef-fuel-twin-solo-aqua-work- 173 | bald 174 | ``` 175 | 176 | * Bytewords (minimal encoding, only first and last letters of each word): 177 | 178 | ``` 179 | tantjzoeadgdstaslplabghydrpfmkbggufgludprfgmaosecffltnsoaawkbd 180 | ``` 181 | 182 | ### Brutal Encoding 183 | 184 | Unlike the "standard" encoding described above, where the encoded message is CBOR and is therefore self-describing, Bytewords can also be used to encode arbitrary byte sequences with no defined internal structure except for the last four words being the checksum. The advantage of this "brutal" encoding is brevity. The disadvantage is that it is up to the user to keep track of the type of information encoded and ensure that it is interpreted correctly. 185 | 186 | For example, the seed payload used in the example above: 187 | 188 | ``` 189 | c7098580125e2ab0981253468b2dbc52 190 | ``` 191 | 192 | can be concatenated with the four-byte checksum of the payload as described above: 193 | 194 | ``` 195 | feac0dea 196 | ``` 197 | 198 | to yield: 199 | 200 | ``` 201 | c7098580125e2ab0981253468b2dbc52feac0dea 202 | ``` 203 | 204 | And then encoded as Bytewords: 205 | 206 | ``` 207 | slot axis limp lava brag holy door puff monk brag 208 | guru frog luau drop roof grim zone plus belt wand 209 | ``` 210 | 211 | Or encoded as minimal Bytewords: 212 | 213 | ``` 214 | staslplabghydrpfmkbggufgludprfgmzepsbtwd 215 | ``` 216 | 217 | It is recommended that if Bytewords is used in the brutal encoding mode, that some other metadata, such as a URI scheme, be present to guide in interpreting the payload, e.g.: 218 | 219 | ``` 220 | my-seed:slot-axis-limp-lava-brag-holy-door-puff-monk-brag-guru-frog-luau-drop-roof-grim-zone-plus-belt-wand 221 | ``` 222 | 223 | or 224 | 225 | ``` 226 | my-seed:staslplabghydrpfmkbggufgludprfgmzepsbtwd 227 | ``` 228 | 229 | ### References 230 | 231 | * [URTYPES] [BCR-0006: Registry of Uniform Resource (UR) Types 232 | ](bcr-0006-urtypes.md) 233 | * [BC32] [BCR-2020-004: The BC32 Data Encoding Format](bcr-2020-004-bc32.md) 234 | * [BIP39] [BIP-0039: Mnemonic code for generating deterministic keys](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) 235 | * [BIP39WORDS] [BIP-0039 Multilingual Word Lists](https://github.com/bitcoin/bips/blob/master/bip-0039/bip-0039-wordlists.md) 236 | * [CBOR] [Concise Binary Object Representation (CBOR)](https://tools.ietf.org/html/rfc7049) 237 | * [CBOR-DATE] [Concise Binary Object Representation (CBOR) Tags for Date](https://datatracker.ietf.org/doc/draft-ietf-cbor-date-tag/) 238 | * [CBOR-PLAYGROUND] [CBOR Playground](http://cbor.me) 239 | * [CRC32] [MSDN: 32-Bit CRC Algorithm](https://docs.microsoft.com/en-us/openspecs/office_protocols/ms-abs/06966aa2-70da-4bf9-8448-3355f277cd77) 240 | * [SLIP39] [SLIP-0039: Shamir's Secret-Sharing for Mnemonic Codes](https://github.com/satoshilabs/slips/blob/master/slip-0039.md) 241 | * [SLIP39WORDS] [SLIP-0039: Word List](https://github.com/satoshilabs/slips/blob/master/slip-0039/wordlist.txt) 242 | 243 | ## Appendix 244 | 245 | ### Analysis of BIP-39 246 | 247 | In the case of BIP-39, the binary string is broken up into 11-bit words and encoded using a 2,048-word dictionary. The words are according the following criteria: 248 | 249 | > An ideal wordlist has the following characteristics: 250 | > 251 | > a) smart selection of words 252 | > 253 | > - the wordlist is created in such way that it's enough to type the first four letters to unambiguously identify the word 254 | > 255 | > b) similar words avoided 256 | > 257 | > - word pairs like "build" and "built", "woman" and "women", or "quick" and "quickly" not only make remembering the sentence difficult, but are also more error prone and more difficult to guess 258 | > 259 | > c) sorted wordlists 260 | > 261 | > - the wordlist is sorted which allows for more efficient lookup of the code words (i.e. implementations can use binary search instead of linear search) 262 | > - this also allows trie (a prefix tree) to be used, e.g. for better compression 263 | 264 | In addition, BIP-39 word lists are available in several other languages, each of which was constructed by rules described in [BIP39WORDS]. 265 | 266 | ### Analysis of SLIP-39 267 | 268 | In the case of SLIP-39, the binary string is broken up into 10-bit words and encoded using a 1,024-word dictionary [SLIP39WORDS]. The words are according the following criteria: 269 | 270 | > * The wordlist is alphabetically sorted. 271 | > * No word is shorter than 4 letters. 272 | > * No word is longer than 8 letters. 273 | > * All words begin with a unique 4-letter prefix. 274 | > * The wordlist contains only common English words (+ the word "satoshi"). 275 | > * The minimum Damerau-Levenshtein distance between any two words is at least 2. 276 | > * The similarity between the pronunciation of any two words has been minimized. 277 | 278 | ### Analysis of BC32 279 | 280 | In the case of [BC32], the binary string is broken up into 5-bit letters and encoded using a limited 32-character subset of ASCII that is compatible both with QR Code alphanumeric mode and URI unreserved characters. Six characters (30 bits) of checksum are added at the end. 281 | 282 | ## Version History 283 | 284 | ### October 4, 2020: 285 | 286 | * Fix for [https://github.com/BlockchainCommons/Research/issues/45](wordlist alphabetization error). 287 | -------------------------------------------------------------------------------- /papers/bcr-2020-013-crc32-cbor-tag.md: -------------------------------------------------------------------------------- 1 | # CRC-32 Checksums in CBOR 2 | 3 | ## BCR-2020-013 4 | 5 | **© 2020 Blockchain Commons** 6 | 7 | Authors: Wolf McNally, Christopher Allen
8 | Date: July 3, 2020 9 | 10 | ### DEPRECATED 11 | 12 | The content below is now deprecated and of historical interest only. 13 | 14 | ### Introduction 15 | 16 | This document registers a tag for serializing CRC-32 checksums in Concise Binary Object Representation (CBOR). 17 | 18 | ``` 19 | Tag: 19 20 | Data item: unsigned integer in [0...2^32) 21 | Semantics: CRC-32 checksum in network byte order (big-endian) 22 | Created: 2020-07-03 23 | ``` 24 | 25 | ### Introduction 26 | 27 | [CRC-32](https://en.wikipedia.org/wiki/Cyclic_redundancy_check#CRC-32_algorithm) is a common method for checksumming a block of data for later error detection. A CRC-32 checksum is an integer in the range [0...2^32). 28 | 29 | ### Semantics 30 | 31 | A CRC-32 checksum is represented in the machine as an unsigned 32-bit integer. Memory layout may be little-endian or big-endian depending on the processor, so the checksum must be translated to network byte order (big-endian) before being encoded as CBOR. In CBOR, a CRC-32 checksum has tag 19 and is encoded as an unsigned integer (major type 0). 32 | 33 | ### Example 34 | 35 | The CRC-32 checksum for the UTF-8 string "Hello, world!" is 0xebe6c6e6 in network byte order. 36 | 37 | The integer checksum is then stored with tag 19: 38 | 39 | ``` 40 | D3 # tag(19) 41 | 1A EBE6C6E6 # unsigned(3957769958) 42 | ``` 43 | -------------------------------------------------------------------------------- /papers/bcr-2020-014-urs-on-epaper.md: -------------------------------------------------------------------------------- 1 | # URs on E-Paper Display 2 | 3 | ## BCR-2020-014 4 | 5 | **© 2020 Blockchain Commons** 6 | 7 | Authors: Gorazd Kovacic, Christopher Allen
8 | Date: October 1, 2020 9 | 10 | 11 | ## Abstract 12 | 13 | This paper investigates running QR animations standardized in [bcr-2020-005-ur](https://github.com/BlockchainCommons/Research/blob/master/papers/bcr-2020-005-ur.md) and [bc-ur](https://github.com/BlockchainCommons/bc-ur/) on ATSAMD51J20 ([bc-lethekit](https://github.com/BlockchainCommons/bc-lethekit)) on an e-paper display [1.54inch-e-Paper-Module Rev. 2.1](https://www.waveshare.net/w/upload/e/e5/1.54inch_e-paper_V2_Datasheet.pdf) (200x200). 14 | 15 | The results suggest we can animate 1 QR code per second or up to 2 if the QR parts are very small. 16 | Another finding is that *UREncoder* gets very slow (4 seconds) for messages of size around 5kB and 100 byte QR parts. 17 | 18 | ## Introduction 19 | 20 | The advantage of e-paper displays is they use very little power or no power at all when displaying a static image. This comes at a cost of a display's refresh rate capabilities. 21 | Most e-paper displays need a couple of seconds to do a full refresh cycle and some of them are able to do a partial refresh cycle which are faster but less clean. That is you can still 22 | see some small remnants of a previous image which is good enough for many applications, including animation of QR codes. 23 | 24 | ![img](https://i.ibb.co/g4pmJbr/epaper.jpg) 25 | 26 | ### Libraries used 27 | 28 | * The bc-ur library has been ported to work with Arduino (bc-ur-arduino) and can be found in [bc-lethekit/deps](https://github.com/BlockchainCommons/bc-lethekit/tree/master/deps). 29 | * The display library used in lethekit is [GxEPD2_154_D67](https://github.com/ZinggJM/GxEPD2) and suggests that the screen has a partial refresh time of 500 ms: 30 | 31 | ```bash 32 | $ git grep partial_refresh_time 33 | src/epd/GxEPD2_1248.cpp: _waitWhileAnyBusy("_Update_Part", partial_refresh_time); 34 | src/epd/GxEPD2_1248.h: static const uint16_t partial_refresh_time = 1600; // ms, e.g. 1525001us 35 | src/epd/GxEPD2_154.cpp: _waitWhileBusy("_Update_Part", partial_refresh_time); 36 | src/epd/GxEPD2_154.h: static const uint16_t partial_refresh_time = 300; // ms, e.g. 290867us 37 | src/epd/GxEPD2_154_D67.cpp: _waitWhileBusy("_Update_Part", partial_refresh_time); 38 | src/epd/GxEPD2_154_D67.h: static const uint16_t partial_refresh_time = 500; // ms, e.g. 457282us 39 | ``` 40 | 41 | *Note:* there is also GxEPD2_154 screen which works with lethekit and has a refresh time of 300 ms. This screen is discontinued, hence no measurements were conducted with it. 42 | 43 | ## Measurements 44 | 45 | In this section the code is introduced used to measure the rate of QR animations with different parameters. 46 | We are conveying a message (*message_size*) split into qr parts (*CHUNK_SIZE*) by the *UR encoder*. The QR code can fully fit 47 | onto screen (*scale* = 200) or we can make it smaller. 48 | 49 | *Note:* scale is not a reliable parameter. Scale of 200 means display the QR code over the whole screen if possible. The actually depicted code may 50 | be smaller. 51 | 52 | 53 | *displayQR* is a function which generates the QR "pixels" and sends them over to the display's RAM one by one rather than as a whole. This is usually 54 | how it's done on devices with low RAM resources. 55 | 56 | 57 | ```cpp 58 | void ur_demo(void) { 59 | 60 | uint32_t dt; 61 | uint32_t dt0; 62 | const size_t CHUNK_SIZE = 100; // bytes 63 | 64 | dt = millis(); 65 | auto ur = make_message_ur(5000); 66 | dt = millis() - dt; 67 | Serial.println("Make mesage: " + String(dt)); 68 | 69 | dt = millis(); 70 | auto encoder = UREncoder(ur, CHUNK_SIZE); 71 | dt = millis() - dt; 72 | Serial.println("UREncoder: " + String(dt)); 73 | 74 | while (true) { 75 | 76 | // measure refresh rate 77 | dt0 = millis(); 78 | 79 | dt = millis(); 80 | string _part = encoder.next_part(); 81 | dt = millis() - dt; 82 | Serial.println("Encoder.next_part: " + String(dt)); 83 | 84 | const char * part_tmp = _part.c_str(); 85 | String part_Str = part_tmp; 86 | part_Str.toUpperCase(); 87 | 88 | g_display->firstPage(); 89 | do 90 | { 91 | g_display->setPartialWindow(0, 0, 200, 200); 92 | g_display->fillScreen(GxEPD_WHITE); 93 | g_display->setTextColor(GxEPD_BLACK); 94 | 95 | // measure QR generation/transfer to screen RAM 96 | dt = millis(); 97 | displayQR((char *)part_Str.c_str(), 200); 98 | // Delta time 99 | dt = millis() - dt; 100 | Serial.println("QR Code generated: " + String(dt)); 101 | } 102 | while (g_display->nextPage()); 103 | 104 | // Delta time 105 | dt0 = millis() - dt0; 106 | Serial.println("QR updated: " + String(dt0)); 107 | 108 | char key; 109 | key = g_keypad.getKey(); 110 | 111 | switch (key) { 112 | case NO_KEY: 113 | break; 114 | default: 115 | // return on any key 116 | g_uistate = SEEDLESS_MENU; 117 | return; 118 | } 119 | } 120 | } 121 | ``` 122 | 123 | 124 | 125 | ## Results 126 | 127 | Scale: 200 128 | 129 | Chunk size [byte] | Refresh rate [ms]| QR generation [ms] 130 | --- | --- | --- 131 | 50 | 717 | 155 132 | 100 | 758 | 197 133 | 200 | 861 | 296 134 | 135 | ------ 136 | 137 | Scale: 100 138 | 139 | Chunk size [byte] | Refresh rate [ms]| QR generation [ms] 140 | --- | --- | --- 141 | 50 | 680 | 120 142 | 100 | 723 | 161 143 | 200 | 836 | 272 144 | 145 | ----- 146 | 147 | Chunk size: 100 148 | 149 | Msg size [byte]| make_message_ur() [ms]| UREncoder() [ms] 150 | --- | --- | --- 151 | 100 | 1 | 0 152 | 500 | 8 | 8 153 | 1000 | 23 | 42 154 | 2000 | 72 | 278 155 | 5000 | 384 | 3869 156 | 157 | 158 | *Note:* printing strings over serial (`Serial.println`) is negligible (<1ms) whereas `encoder.next_part()` takes 2-3ms 159 | 160 | We can see that the difference between refresh rate and QR generation is about **560 ms** which is close (delta=60ms) to what the refresh rate 161 | specified for this display is. 162 | 163 | The refresh rate of QR parts is slowing down with their size. That is because the *displayQR* function has more "pixels" to generate and send to the 164 | display controller. 165 | 166 | 167 | ## Video 168 | 169 | [![Urs on lethekit](https://i.ibb.co/b35PPvs/epaperdisp.png)](https://lbry.tv/URs-on-LetheKit:d "URs on lethekit") 170 | 171 | ## References 172 | 173 | * [bcr-2020-005-ur](https://github.com/BlockchainCommons/Research/blob/master/papers/bcr-2020-005-ur.md) 174 | * [bc-lethekit](https://github.com/BlockchainCommons/bc-lethekit) 175 | * [GxEPD2 Arduino library](https://github.com/ZinggJM/GxEPD2) 176 | * [datasheet_1.54V2](https://www.waveshare.net/w/upload/e/e5/1.54inch_e-paper_V2_Datasheet.pdf) 177 | -------------------------------------------------------------------------------- /papers/bcr-2021-002/0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockchainCommons/Research/f48872e3f858e9b86957f16f39149f3e1c47b24f/papers/bcr-2021-002/0.png -------------------------------------------------------------------------------- /papers/bcr-2021-002/blockchain-commons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockchainCommons/Research/f48872e3f858e9b86957f16f39149f3e1c47b24f/papers/bcr-2021-002/blockchain-commons.png -------------------------------------------------------------------------------- /papers/bcr-2021-002/oib-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockchainCommons/Research/f48872e3f858e9b86957f16f39149f3e1c47b24f/papers/bcr-2021-002/oib-1.png -------------------------------------------------------------------------------- /papers/bcr-2021-002/oib-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockchainCommons/Research/f48872e3f858e9b86957f16f39149f3e1c47b24f/papers/bcr-2021-002/oib-2.png -------------------------------------------------------------------------------- /papers/bcr-2021-002/oib-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockchainCommons/Research/f48872e3f858e9b86957f16f39149f3e1c47b24f/papers/bcr-2021-002/oib-3.png -------------------------------------------------------------------------------- /papers/bcr-2021-002/oib-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockchainCommons/Research/f48872e3f858e9b86957f16f39149f3e1c47b24f/papers/bcr-2021-002/oib-4.png -------------------------------------------------------------------------------- /papers/bcr-2021-002/oib-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockchainCommons/Research/f48872e3f858e9b86957f16f39149f3e1c47b24f/papers/bcr-2021-002/oib-5.png -------------------------------------------------------------------------------- /papers/bcr-2021-002/oib-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockchainCommons/Research/f48872e3f858e9b86957f16f39149f3e1c47b24f/papers/bcr-2021-002/oib-6.png -------------------------------------------------------------------------------- /papers/bcr-2021-002/sskr-coupons.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockchainCommons/Research/f48872e3f858e9b86957f16f39149f3e1c47b24f/papers/bcr-2021-002/sskr-coupons.jpg -------------------------------------------------------------------------------- /papers/bcr-2021-002/wolf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockchainCommons/Research/f48872e3f858e9b86957f16f39149f3e1c47b24f/papers/bcr-2021-002/wolf.png -------------------------------------------------------------------------------- /papers/bcr-2022-001-encrypted-message.md: -------------------------------------------------------------------------------- 1 | # UR Type Definition for Encrypted Messages 2 | 3 | ## BCR-2022-001 4 | 5 | **© 2022 Blockchain Commons** 6 | 7 | Authors: Wolf McNally, Christopher Allen
8 | Date: Mar 15, 2022
9 | Revised: Aug 12, 2023 10 | 11 | --- 12 | 13 | ## Introduction 14 | 15 | This paper addresses the need for a way to encrypt messages using best practices and encode them using [CBOR](https://cbor.io/) and [URs](https://github.com/BlockchainCommons/Research/blob/master/papers/bcr-2020-005-ur.md). It specifies a general "encrypted message" structure and a specific encoding based on ChaCha20-Poly1305 Authenticated Encryption as specified in [RFC-8439](https://datatracker.ietf.org/doc/html/rfc8439). 16 | 17 | ## UR Types and CBOR Tags 18 | 19 | This document defines the following UR types along with their corresponding CBOR tags: 20 | 21 | | UR type | CBOR Tag | 22 | | :--------------- | :------- | 23 | | ur:encrypted | #6.40002 | 24 | | ur:crypto-key | #6.40023 | 25 | | ur:encrypted-key | #6.40027 | 26 | 27 | These tags have been registered in the [IANA Registry of CBOR Tags](https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml). 28 | 29 | ### Related Work 30 | 31 | The [COSE specification](https://datatracker.ietf.org/doc/draft-ietf-cose-rfc8152bis-struct/) specifies a highly general structure for the encryption and signing of messages in CBOR. There is also a need for an alternative that is simpler, more specific, more compact, and more opinionated about best practices, while still allowing for extensibility and able to serve as a component of larger structures. 32 | 33 | ## The ChaCha20-Poly1305-IETF Cipher 34 | 35 | The [IETF variant of the ChaCha20-Poly1305](https://datatracker.ietf.org/doc/html/rfc8439) construction can encrypt a practically unlimited number of messages, but individual messages cannot exceed 64*(2^32)-64 bytes (approximately 256 GiB). 36 | 37 | To encrypt a message, the sender provides a 32-byte symmetric key and a 12-byte nonce. The nonce is sent as part of the message, but the key is kept secret between the sender and recipient. The ChaCha20 stream cipher is used for encryption and decryption, and as part of the construction, a 16-byte authentication tag is generated using Poly1305, and is used to verify message integrity. An "additional authenticated data" field can also be provided, which is not encrypted, but it is included in the message authentication step. This field is often used to send metadata about the encrypted portion of the message. In all, the fields used and the names this document refers to them by are: 38 | 39 | * `plaintext`: [Any length] The unencrypted message. 40 | * `ciphertext`: [Same length as `plaintext`] The encrypted message. 41 | * `aad`: [Any length] Additional Authenticated Data 42 | * `key`: [32 bytes] The symmetric key. 43 | * `nonce` [12 bytes] The nonce, which must not be repeated for the same key. 44 | * `auth` [16 bytes] The authentication tag. 45 | 46 | ## CDDL for Encrypted Message 47 | 48 | The following specification is written in [Concise Data Definition Language (CDDL)](https://tools.ietf.org/html/rfc8610). 49 | 50 | When used embedded in another CBOR structure, this structure MUST be tagged `#6.40002`. When used as the top-level object of a UR, it MUST NOT be tagged. 51 | 52 | The general format for a Encrypted Message is a CBOR array with either 3 or 4 elements. The `aad` element is optional, but if it is present it MUST NOT be empty. 53 | 54 | ``` 55 | encrypted = [ ciphertext, nonce, auth, ? aad ]; 56 | 57 | ciphertext = bytes 58 | nonce = bytes .size 12 59 | auth = bytes .size 16 60 | aad = bytes 61 | ``` 62 | 63 | ### Example/Test Vector 64 | 65 | * Test Vector from [Section 2.8.2 of RFC-8439](https://datatracker.ietf.org/doc/html/rfc8439#section-2.8.2): 66 | 67 | plaintext: `4c616469657320616e642047656e746c656d656e206f662074686520636c617373206f66202739393a204966204920636f756c64206f6666657220796f75206f6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73637265656e20776f756c642062652069742e` 68 | 69 | plaintext as UTF-8: `Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it.` 70 | 71 | aad: `50515253c0c1c2c3c4c5c6c7` 72 | 73 | key: `808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f` 74 | 75 | nonce: `070000004041424344454647` 76 | 77 | ciphertext: `d31a8d34648e60db7b86afbc53ef7ec2a4aded51296e08fea9e2b5a736ee62d63dbea45e8ca9671282fafb69da92728b1a71de0a9e060b2905d6a5b67ecd3b3692ddbd7f2d778b8c9803aee328091b58fab324e4fad675945585808b4831d7bc3ff4def08e4b7a9de576d26586cec64b6116` 78 | 79 | * In the CBOR diagnostic notation, with `#6.40002` tag: 80 | 81 | ``` 82 | 40002( / encrypted / 83 | [ 84 | h'd31a8d34648e60db7b86afbc53ef7ec2a4aded51296e08fea9e2b5a736ee62d6 85 | 3dbea45e8ca9671282fafb69da92728b1a71de0a9e060b2905d6a5b67ecd3b36 86 | 92ddbd7f2d778b8c9803aee328091b58fab324e4fad675945585808b4831d7bc 87 | 3ff4def08e4b7a9de576d26586cec64b6116', / ciphertext / 88 | h'070000004041424344454647', / nonce / 89 | h'1ae10b594f09e26a7e902ecbd0600691', / auth / 90 | h'50515253c0c1c2c3c4c5c6c7' / aad / 91 | ] 92 | ) 93 | ``` 94 | 95 | * Encoded as binary using [CBOR Playground](https://cbor.me): 96 | 97 | ``` 98 | d9 9c42 # tag(40002) encrypted 99 | 84 # array(4) 100 | 58 72 # bytes(114) ciphertext 101 | d31a8d34648e60db7b86afbc53ef7ec2a4aded51296e08fea9e2b5a736ee62d63dbea45e8ca9671282fafb69da92728b1a71de0a9e060b2905d6a5b67ecd3b3692ddbd7f2d778b8c9803aee328091b58fab324e4fad675945585808b4831d7bc3ff4def08e4b7a9de576d26586cec64b6116 102 | 4c # bytes(12) 103 | 070000004041424344454647 # "....@ABCDEFG" 104 | 50 # bytes(16) auth 105 | 1ae10b594f09e26a7e902ecbd0600691 106 | 4c # bytes(12) aad 107 | 50515253c0c1c2c3c4c5c6c7 # 108 | ``` 109 | 110 | * As a hex string: 111 | 112 | ``` 113 | d99c42845872d31a8d34648e60db7b86afbc53ef7ec2a4aded51296e08fea9e2b5a736ee62d63dbea45e8ca9671282fafb69da92728b1a71de0a9e060b2905d6a5b67ecd3b3692ddbd7f2d778b8c9803aee328091b58fab324e4fad675945585808b4831d7bc3ff4def08e4b7a9de576d26586cec64b61164c070000004041424344454647501ae10b594f09e26a7e902ecbd06006914c50515253c0c1c2c3c4c5c6c7 114 | ``` 115 | 116 | * The structure above, as a UR: 117 | 118 | NOTE: URs do not use CBOR tags for the top-level object. The type of the object is provided by the type field of the UR schema, in this case `encrypted`: 119 | 120 | ``` 121 | ur:encrypted/lrhdjptecylgeeiemnhnuykglnperfguwskbsaoxpmwegydtjtayzeptvoreosenwyidtbfsrnoxhylkptiobglfzszointnmojplucyjsuebknnambddtahtbonrpkbsnfrenmoutrylbdpktlulkmkaxplvldeascwhdzsqddkvezstbkpmwgolplalufdehtsrffhwkuewtmngrknntvwkotdihlntoswgrhscmgsataeaeaefzfpfwfxfyfefgflgdcyvybdhkgwasvoimkbmhdmsbtihnammegsgdgygmgurtsesasrssskswstcfnbpdct 122 | ``` 123 | 124 | ### Security Considerations 125 | 126 | The security considerations for this type are the same as that for the cryptographic construction defined in [RFC-8439](https://datatracker.ietf.org/doc/html/rfc8439). 127 | 128 | ## Future Proofing 129 | 130 | The `#6.40002` tag is intended to be extensible to other symmetric encryption constructs, if and when the need arises. The only requirement is that later constructs are distinguishable from the one defined herein, for example by inserting a distinguishing integer as the first element of the array. 131 | 132 | ## Symmetric Encryption Key 133 | 134 | The `#6.40023` tag is used to represent a symmetric encryption key. It is a byte string of 32 bytes, which is the size of the key used in the ChaCha20-Poly1305-IETF cipher. 135 | 136 | ```cddl 137 | crypto-key = bytes .size 32 138 | ``` 139 | 140 | ## Encrypted Key 141 | 142 | The `#6.40027` tag is used to represent a key that has been encrypted using a derivation function. It is a profile of `EncryptedMessage` which MUST contain the CBOR serialization of a `KeyDerivation` structure in the message's Additional Authenticated Data (AAD) field: 143 | 144 | ```cddl 145 | EncryptedKey = #6.40027(EncryptedMessage) ; TAG_ENCRYPTED_KEY 146 | 147 | EncryptedMessage = 148 | #6.40002([ ; TAG_ENCRYPTED 149 | ciphertext: bstr, 150 | nonce: bstr, 151 | auth: bstr, 152 | aad: bstr .cbor KeyDerivation ; This MUST be present in an `EncryptedKey` 153 | ]) 154 | ``` 155 | 156 | So the full serialization will have two nested tags: the outer one representing `EncryptedKey` and the inner one representing `EncryptedMessage`: 157 | 158 | ```cddl 159 | #6.40027( #6.40002( ... ) ) 160 | ``` 161 | 162 | Currently four key derivation methods are supported: 163 | 164 | ```cddl 165 | KeyDerivationMethod = HKDF / PBKDF2 / Scrypt / Argon2id 166 | 167 | HKDF = 0 168 | PBKDF2 = 1 169 | Scrypt = 2 170 | Argon2id = 3 171 | ``` 172 | 173 | The above constants are used to identify the key derivation method in the `KeyDerivation` structure, which is an array of the form: 174 | 175 | ```cddl 176 | [, Salt, ] 177 | ``` 178 | 179 | The actual parameter arrays being: 180 | 181 | ```cddl 182 | KeyDerivation = HKDFParams / PBKDF2Params / ScryptParams / Argon2idParams 183 | 184 | HKDFParams = [HKDF, Salt, HashType] 185 | PBKDF2Params = [PBKDF2, Salt, iterations: uint, HashType] 186 | ScryptParams = [Scrypt, Salt, log_n: uint, r: uint, p: uint] 187 | Argon2idParams = [Argon2id, Salt] 188 | 189 | HashType = SHA256 / SHA512 190 | 191 | SHA256 = 0 192 | SHA512 = 1 193 | ``` 194 | 195 | The `Salt` type is defined in [BCR-2023-017](bcr-2023-017-salt.md). 196 | 197 | ### IANA Considerations 198 | 199 | This document requests that [IANA](https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml) reserve the following tag: 200 | 201 | | Tag | Data Item | Semantics | 202 | | :---- | :----------- | :----------------------------------------------------------------- | 203 | | 40002 | array | ur:encrypted, IETF ChaCha20-Poly1305 (RFC8439) encrypted message | 204 | | 40023 | byte string | ur:crypto-key, Cryptographic key used for symmetric encryption | 205 | | 40027 | tagged array | ur:encrypted-key, Content key encrypted with a derivation function | 206 | -------------------------------------------------------------------------------- /papers/bcr-2022-002-arid.md: -------------------------------------------------------------------------------- 1 | # ARID: Apparently Random Identifier 2 | 3 | ## BCR-2022-002 4 | 5 | **© 2022 Blockchain Commons** 6 | 7 | Authors: Wolf McNally, Christopher Allen, Shannon Applecline
8 | Date: Aug 10, 2022
9 | Updated: Sep 3, 2023 10 | 11 | --- 12 | 13 | ## Introduction 14 | 15 | Information systems use many kinds of identifiers for many purposes. The main purpose of an identifier is to uniquely point to an object, or *referent*, within a given domain. An identifier that is *universally* unique can be associated to any object or concept in all of existence and be relied on to be unique because it contains sufficient entropy (randomness) to ensure that it will, for every conceivable practical purpose, *never* collide with another such identifier. 16 | 17 | ## Survey 18 | 19 | Universally unique identifiers have precedent in (for example) [UUIDs](https://en.wikipedia.org/wiki/Universally_unique_identifier), [URIs](https://en.wikipedia.org/wiki/Uniform_Resource_Identifier), and cryptographic digests. 20 | 21 | ### UUIDs 22 | 23 | UUIDs are 128 bits in length and come in several different versions. Each version specifies several bitfields and their semantics. Version 4 is specified to be random, but is still not completely random because it does not specify that cryptographically strong randomness is always be used, and it reserves a 7 bits to identify it *as* a version 4 UUID, leaving 121 bits of actual randomness. 24 | 25 | ### URIs 26 | 27 | URIs are (more or less) human readable text. The specification of URIs usually focuses on human-understandable semantics and are frequently hierarchical, starting with the `scheme` field, which describes a namespace within which the remainder of the URI is considered to point to a referent. 28 | 29 | ### Digests 30 | 31 | A cryptographic hash algorithm such as SHA-256 or BLAKE3 maps a block of data of arbitrary size to a fixed-length "digest." This digest reveals nothing about the source image by itself, but can only be computed by applying the same algorithm to the same image. A digest can thereby be considered a "pointer" to a particular binary referent. 32 | 33 | ## Introducing the ARID 34 | 35 | We propose herein a standard for a cryptographically strong, universally unique identifier known as an Apparently Random Identifier, or ARID. 36 | 37 | The goals for this form of identifier are: 38 | 39 | * Non-correlatability 40 | * Neutral semantics 41 | * Open generation 42 | * Minimum strength 43 | * Cryptographic suitability 44 | 45 | ## Non-Correlatability 46 | 47 | To be an ARID, the sequence of bits that comprise it MUST NOT be correlatable with its referent, nor any other ARID. Therefore, it MUST NOT be a hash or digest of another object. 48 | 49 | The sequence of bits in an ARID MUST be statistically indistinguishable from pure entropy. Therefore one method of generating an ARID is to use a cryptographically strong random number generator. 50 | 51 | However, the source of entropy for an ARID does not itself have to actually be random; it simply has to be indistinguishable from randomness without additional hidden information. One example would be when a sequence of ARIDs are generated from a ratcheting key generation algorithm. Knowing the current state of the ratchet and correct ARID would give one the ability to ratchet the key to the next state and generate the next ARID in the sequence. A third-party observer would be unable to correlate the next ARID with the previous ARID without access to the secret ratchet state. 52 | 53 | ## Neutral Semantics 54 | 55 | Existing identifiers frequently contain inherent type information (UUID version 4 identifies itself as such) and frequently specify the type of referent (URIs specify the `scheme` and often specify a referent type such as `.jpg` in their path.) 56 | 57 | ARIDs contain no type information. Statistically, they are uniformly random sequences of bits. If you merely encoded an ARID as a sequence of binary or hexadecimal digits, it would appear to be a random sequence. 58 | 59 | Type information can be added at higher levels. When encoded as [CBOR](https://cbor.io/), an ARID is tagged with #6.40012. Tagged this way, the receiver of an ARID can still only determine that it *is* an ARID, and nothing about the type or nature of its referent. 60 | 61 | In particular, this construct provides no information about the lifetime of the referent. The referent could exist persistently for all time, such as in a blockchain, or it could exist for milliseconds, as in a distributed function call. 62 | 63 | This construct also provides no information as to the source of its bit sequence. Since the sequence is statistically random, it could have been generated by a cryptographic random number generator or a sequence of ratcheting keys, and either case would be indistinguishable to a third-party observer. 64 | 65 | Higher level semantics are provided by how an ARID is further tagged, or by how it is positioned in a larger structure, or both. For instance, a distributed function call could have a header that includes the construct `request(ARID(XXX))` where `request` is a CBOR tag indicating that the remainder of the structure specifies which function to call and with what parameters, and `ARID` specifies its tagged contents as conforming to the other requirements of this document. Positional information would include, for example the position of the ARID within a header, or which field an ARID populates, such as `person: ARID(XXX)`. In this example, being the value of the `person` field is sufficient to use the ARID as a "person identifier" *unless* there is more than one distinct kind of "person", in which case another tag would be needed to disambiguate this. 66 | 67 | ### Open Generation 68 | 69 | As mentioned above, *any* method of generating an ARID is allowed as long as it fulfills the other requirements of this document, chiefly: 70 | 71 | 1. statistically random bits, and 72 | 2. universal uniqueness. 73 | 74 | ### Minimum Strength 75 | 76 | ARIDs must be a minimum of 256 bits (32 bytes) in length. At this time, there is no perceived need for ARIDs to be longer, and thus conformant processes that receive ARIDs MAY reject ARIDs that are longer or shorter than 256 bits, while processes that generate ARIDs SHOULD only generate ARIDs that are exactly 256 bits in length. 77 | 78 | ### Cryptographic suitability 79 | 80 | The foregoing notwithstanding, ARIDs MAY be used as inputs to cryptographic constructs such as a ratcheting key algorithms, or used as additional entropy for random number generators, or salt for hashing algorithms, as long as the output of such algorithms is necessarily related to the ARID's referent. 81 | 82 | For example in the distributed call scenario, a caller might transmit a structure including `request(ARID(A))`, where A is an ARID generated from an iteration of a ratcheting key algorithm. The receiver compares `A` to its own internal state, rejecting the call if it does not match, and advancing the state of its ratchet if it does. The receiver computes the result of the call and returns a structure including `response(ARID(B))`, where B is generated from the new state of the ratchet. The caller receives the response and uses the algorithm to correlate `B` in the response to its call `A`, and if further exchanges are needed, uses the ratchet to produce the next expected transaction ID, `C`. Third parties viewing the exchange cannot correlate `A`, `B`, or `C`, and in particular, they cannot correlate a specific response to its call. 83 | 84 | ## Not to be Confused With 85 | 86 | ARIDs MUST NOT be confused with any other sort of identifier or sequence of random or pseudorandom numbers. 87 | 88 | * ARIDs MUST NOT be cast to or from other identifier types such as UUIDs, nor should they be considered isomorphic to any other type. 89 | * ARIDs MUST NOT be cast from digests (hashes) or similar structures. 90 | * ARIDs are not [nonces](https://en.wikipedia.org/wiki/Cryptographic_nonce). Unlike nonces, ARIDs always have a referent. ARIDs MUST NOT be used as nonces, and MUST NOT be created by casting from a nonce used anywhere else. 91 | * ARIDs are not keys and MUST NOT be used as keys. 92 | * ARIDs are not cryptographic seeds. They are generally not considered secret, and MUST NOT be used as secret key material from which keys or other secret constructs are derived. 93 | 94 | ## UR Types and CBOR Tags 95 | 96 | This document defines the following UR types along with their corresponding CBOR tags: 97 | 98 | | UR type | CBOR Tag | 99 | | :-------- | :------- | 100 | | ur:arid | #6.40012 | 101 | 102 | These tags have been registered in the [IANA Registry of CBOR Tags](https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml). 103 | 104 | ## CDDL 105 | 106 | ``` 107 | arid = #6.40012(arid-data) 108 | arid-data = bytes .size 32 109 | ``` 110 | 111 | ## Q&A 112 | 113 | ### What advantage do ARIDs have over simply using hashes? 114 | 115 | Hashes identify a fixed, immutable state of data. If the data changes, the hash changes. ARIDs, on the other hand, can serve as a stable identifier for mutable data structures. They provide universal uniqueness without tying them to a specific data snapshot, making them more versatile for identifying evolving or mutable referents. 116 | 117 | ### Why can't ARIDs be cast to or from other identifier types? 118 | 119 | Casting ARIDs to or from other identifier types compromises their neutral semantics and could introduce correlation with their referent or with other ARIDs. It undermines the fundamental aim of being universally unique while remaining completely opaque regarding their origin or the data they reference. 120 | 121 | ### Why can't ARIDs be cast from digests? 122 | 123 | Hashes like SHA-256 are deterministic and directly tied to the data they represent. This compromises the non-correlatability requirement of ARIDs. If you use a hash, anyone with the same input data could generate the same ARID, making it possible to correlate the identifier with its referent. This runs counter to the primary goals of ARIDs, which aim for complete opacity regarding their generation method and the data they are linked to. 124 | 125 | ### Why can't ARIDs be used as nonces? 126 | 127 | ARIDs are designed to be universally unique identifiers tied to a referent, whereas nonces are often ephemeral and context-dependent. Using an ARID as a nonce could mislead into thinking it's meant to be associated with a specific object or event long-term. This discrepancy in purpose could cause semantic confusion and potential security risks. 128 | 129 | ### Why must ARIDs be exactly 256 bits in length? 130 | 131 | ARIDs are set at 256 bits to meet a minimum threshold for cryptographic strength and universal uniqueness. Shorter lengths compromise these properties. Longer lengths don't offer proportionate benefits but increase computational and storage costs. Therefore, the 256-bit length is both sufficient and efficient. 132 | 133 | ### Why are ARIDs not considered secret key material? 134 | 135 | ARIDs are not designed to be secret; their primary role is to serve as identifiers that are uncorrelated with their referents. Using them as secret key material would be a misuse of the structure and could compromise the security of cryptographic systems where actual secret keys are needed. 136 | 137 | ### How is universal uniqueness guaranteed for ARIDs when multiple generation methods are allowed? 138 | 139 | The "universal uniqueness" of ARIDs comes from adhering to stringent entropy requirements. Regardless of the generation method—be it a cryptographically secure random number generator or a ratcheting key algorithm—the resulting ARID must be statistically indistinguishable from pure entropy and at least 256 bits long. The sheer scale of the entropy space for a 256-bit identifier effectively guarantees that the chance of collision, even when using multiple methods, is astronomically low. Therefore, as long as the entropy requirements are rigorously met, the "universal uniqueness" is practically assured. 140 | 141 | ### Why is it OK to use ARIDs as inputs to cryptographic constructs? 142 | 143 | Using ARIDs as inputs to cryptographic constructs doesn't violate their non-correlatability or neutral semantics. It doesn't reveal information about the ARID or its referent, maintaining their core attributes. It simply utilizes their high-entropy nature for cryptographic operations. 144 | -------------------------------------------------------------------------------- /papers/bcr-2023-001-compressed-message.md: -------------------------------------------------------------------------------- 1 | # UR Type Definition for Compressed Messages 2 | 3 | ## BCR-2023-001 4 | 5 | **© 2023 Blockchain Commons** 6 | 7 | Authors: Wolf McNally, Christopher Allen
8 | Date: Aug 13, 2022
9 | Revised: Aug 13, 2023 10 | 11 | --- 12 | 13 | ## Introduction 14 | 15 | This paper addresses the need for a way to compress messages using best practices and encode them using [CBOR](https://cbor.io/) and [URs](https://github.com/BlockchainCommons/Research/blob/master/papers/bcr-2020-005-ur.md). It specifies a general "compressed message" structure and a specific encoding based on the DEFLATE algorithm as specified in [RFC 1951](https://datatracker.ietf.org/doc/html/rfc1951). 16 | 17 | This specification defines a UR type `compressed` (CBOR tag `#6.40003`). 18 | 19 | ⚠️ WARNING: As of the date of this publication the tag `#6.40003` is unallocated in the [IANA Registry of CBOR Tags](https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml). Blockchain Commons is applying for this number to be assigned to the CBOR specification herein, but because it is in a range that is open to other applications, it may change. So for now, the `#6.40003` tag MUST be understood as provisional and subject to change by all implementors. 20 | 21 | ## The DEFLATE algorithm 22 | 23 | The [DEFLATE algorithm](https://datatracker.ietf.org/doc/html/rfc1951) is a lossless compression algorithm that can compress a practically unlimited number of messages, but individual messages cannot exceed 2^32 bytes (approximately 4 GiB). 24 | 25 | The following line of code using the ZLIB API obtains the recommended default configuration of the encoder: 26 | 27 | ``` 28 | deflateInit2(zstream,5,Z_DEFLATED,-15,8,Z_DEFAULT_STRATEGY) 29 | ``` 30 | 31 | The configuration of the encoder may be adjusted by the user, but the decoder MUST be able to decode any valid DEFLATE stream. 32 | 33 | ## CDDL for Compressed Message 34 | 35 | The following specification is written in [Concise Data Definition Language (CDDL)](https://tools.ietf.org/html/rfc8610). 36 | 37 | When used embedded in another CBOR structure, this structure MUST be tagged `#6.40003`. When used as the top-level object of a UR, it MUST NOT be tagged. 38 | 39 | `tagged-digest` is defined in [BCR-2021-002](bcr-2021-002-digest.md). 40 | 41 | ``` 42 | tagged-compressed = #6.40003(compressed) 43 | 44 | compressed = [ 45 | checksum, ; CRC-32 checksum of the uncompressed data 46 | uncompressed-size, 47 | compressed-data, 48 | ? tagged-digest ; Optional user-defined SHA-256 digest 49 | ] 50 | 51 | checksum = crc32 52 | uncompressed-size = uint 53 | compressed-data = bytes 54 | 55 | crc32 = uint 56 | ``` 57 | 58 | The `checksum` field is a standard feature of most DEFLATE implementations, and MUST be validated by the decoder. The `digest` field is optional and is not validated by the decoder, but may be used by the application to validate the integrity of the uncompressed data in ways that are beyond the scope of this specification. It's format is as defined in "Digests for Digital Objects" [BCR-2021-002](bcr-2021-002-digest.md). 59 | 60 | If the payload is too small to compress using DEFLATE, the uncompressed payload MUST be placed in the `compressedData` field and the length of that field MUST be the same as the `uncompressedSize` field. 61 | 62 | Due to fixed overhead, the compressed form of very small messages may be somewhat larger than their uncompressed form. 63 | 64 | ## Future Proofing 65 | 66 | The `#6.40003` tag is intended to be extensible to other compression constructs, if and when the need arises. The only requirement is that later constructs are distinguishable from the one defined herein, for example by inserting a distinguishing integer as the first element of the array. 67 | 68 | ## IANA Considerations 69 | 70 | When a digest of another object is encoded as tagged CBOR, it is tagged #6.40001. This document requests registration of the following CBOR tag: 71 | 72 | * Tag: 6.40003 73 | * Data Item: array 74 | * Semantics: Compressed Message 75 | -------------------------------------------------------------------------------- /papers/bcr-2023-003-envelope-known-value.md: -------------------------------------------------------------------------------- 1 | # Gordian Envelope Extension: Known Values 2 | 3 | ## BCR-2023-003 4 | 5 | **© 2023 Blockchain Commons** 6 | 7 | Authors: Wolf McNally, Christopher Allen
8 | Date: Aug 15, 2022
9 | Revised: Aug 15, 2023 10 | 11 | ## Abstract 12 | 13 | Known Values are a namespace of unsigned integers used to represent stand-alone ontological concepts. This document extends the Gordian Envelope Base Specification to add the `known-value` case arm. 14 | 15 | ## Introduction 16 | 17 | [BCR-2023-002](bcr-2023-002-known-value.md) defines Known Values as a uniform way to represent ontological concepts as unique 64-bit unsigned integers. 18 | 19 | Within an Envelope, any Envelope may be used as a predicate in an assertion. Ontology vocabularies such as [OWL](https://www.w3.org/OWL/) and [RDF](https://www.w3.org/2001/sw/wiki/RDF) use URIs for this purpose, and Envelope support this. But URIs are verbose and subject to manipulation that may break determinism, an essential property of Gordian Envelopes. 20 | 21 | In addition, many predicates are commonly used, e.g., `isA` for type declarations (analogous to the URI [http://www.w3.org/1999/02/22-rdf-syntax-ns#type](http://www.w3.org/1999/02/22-rdf-syntax-ns#type)). It is desirable to keep common predicates both short and deterministically encoded. Known Values offer a solution to this problem within Gordian Envelope. 22 | 23 | This document extends the [Gordian Envelope Base Specification](https://datatracker.ietf.org/doc/draft-mcnally-envelope/) to add the `known-value` case used to represent a Known Value. 24 | 25 | ## Format Specification 26 | 27 | This section is normative, and specifies an additional case arm for the `envelope` type: `known-value`. The formal language used is the [Concise Data Definition Language (CDDL)](https://datatracker.ietf.org/doc/html/rfc8610). The top-level specification of Gordian Envelope with this extension added is: 28 | 29 | ``` 30 | envelope = #6.200(envelope-content) 31 | envelope-content = ( 32 | leaf / elided / node / assertion / wrapped / 33 | known-value 34 | ) 35 | ``` 36 | 37 | As defined in [BCR-2023-002](bcr-2023-002-known-value.md): 38 | 39 | ``` 40 | known-value = uint 41 | 42 | tagged-known-value = #6.40000(known-value) 43 | ``` 44 | 45 | Within the context of an Envelope, `known-value` is represented as an untagged unsigned integer, and is distinguished from other case arms as the *only* one represented as such. So a Gordian Envelope containing only the Known Value for `isA` in CBOR diagnostic notation would be: 46 | 47 | ``` 48 | 200(1) 49 | ``` 50 | 51 | ## Computing the Digest 52 | 53 | This section is normative. 54 | 55 | The Envelope digest image of a Known Value is the CBOR serialization of its `tagged-known-value` representation. See the [Gordian Envelope Base Specification](https://datatracker.ietf.org/doc/draft-mcnally-envelope/) for the definition of the `digest` function. 56 | 57 | ``` 58 | digest(#6.40000(known-value)) 59 | ``` 60 | 61 | **Example** 62 | 63 | The `tagged-known-value` for `isA` in CBOR diagnostic notation is `40000(1)`, which in hex is `d99c4001`. The SHA-256 sum of this sequence is: 64 | 65 | ```bash 66 | $ echo "d99c4001" | xxd -r -p | shasum --binary --algorithm 256 | \ 67 | awk '{ print $1 }' 68 | 2be2d79b306a21ff8e3e6bd3d1c2c6c74ff4a693b1e7ba3a0f40cdfb9ea493f8 69 | ``` 70 | 71 | Using the [envelope command line tool](https://github.com/BlockchainCommons/envelope-cli-swift), we create an Envelope with this known value as the subject and display the Envelope's digest. The digest below matches the one above. 72 | 73 | ```bash 74 | $ envelope subject --known isA | envelope digest --hex 75 | 2be2d79b306a21ff8e3e6bd3d1c2c6c74ff4a693b1e7ba3a0f40cdfb9ea493f8 76 | ``` 77 | 78 | ## Reference Implementations 79 | 80 | This section is informative. 81 | 82 | Both the [Swift Gordian Envelope Reference Implementation](https://github.com/BlockchainCommons/BCSwiftEnvelope) and the [Rust Gordian Envelope Reference Implementation](https://github.com/BlockchainCommons/bc-envelope-rust) support this extension. 83 | 84 | ## Security Considerations 85 | 86 | *Work in progress* 87 | 88 | ## IANA Considerations 89 | 90 | This document makes no requests of IANA. 91 | -------------------------------------------------------------------------------- /papers/bcr-2023-004-envelope-symmetric-encryption.md: -------------------------------------------------------------------------------- 1 | # Gordian Envelope Extension: Symmetric Encryption 2 | 3 | ## BCR-2023-004 4 | 5 | **© 2023 Blockchain Commons** 6 | 7 | Authors: Wolf McNally, Christopher Allen
8 | Date: Aug 15, 2022
9 | Revised: Aug 15, 2023 10 | 11 | ## Abstract 12 | 13 | This document extends the Gordian Envelope Base Specification to add the `encrypted` case arm, which supports symmetric encryption. 14 | 15 | ## Introduction 16 | 17 | This document extends the [Gordian Envelope Base Specification](https://datatracker.ietf.org/doc/draft-mcnally-envelope/) to add the `encrypted` case arm used to represent an Envelope that has been encrypted using a symmetric key. The scheme defined herein supports [IETF-ChaCha20-Poly1305](https://datatracker.ietf.org/doc/html/rfc7539). 18 | 19 | Like elision, which is supported by the Envelope Base Specification, encryption is a reversible transformation of an Envelope that does not alter its unique digest. And since Envelope is a recursively nested structure of Envelopes in a Merkle-like digest tree, any of these nested envelopes can be elided or encrypted without disturbing the tree, hence preserving constructs like signatures. 20 | 21 | This basic encryption can be further extended to support public key encryption (including encryption to multiple recipients) and social backup and recovery using [Sharded Secret Key Reconstruction (SSKR)](bcr-2020-011-sskr.md). 22 | 23 | ## Format Specification 24 | 25 | This section is normative, and specifies an additional case arm for the `envelope` type: `encrypted`. It also specifies that assertions may be encrypted by adding the `encrypted-assertion` case to Envelope's `assertion-element` type. 26 | 27 | The formal language used is the [Concise Data Definition Language (CDDL)](https://datatracker.ietf.org/doc/html/rfc8610). The top-level specification of Gordian Envelope with this extension added is: 28 | 29 | ``` 30 | envelope = #6.200(envelope-content) 31 | envelope-content = ( 32 | leaf / elided / node / assertion / wrapped / 33 | encrypted 34 | ) 35 | 36 | assertion-element = ( 37 | assertion / elided-assertion / 38 | encrypted-assertion 39 | ) 40 | 41 | encrypted-assertion = encrypted ; MUST represent an assertion 42 | ``` 43 | 44 | The format for `encrypted` is defined by [UR Type Definition for Encrypted Messages](bcr-2022-001-encrypted-message.md), including the CBOR tag `#6.40002`. In this specification, the optional fourth array element `aad` is REQUIRED, and MUST contain the CBOR-encoded tagged digest of the envelope. `tagged-digest` is defined in [BCR-2021-002](bcr-2021-002-digest.md). 45 | 46 | ``` 47 | encrypted = #6.40002([ ciphertext, nonce, auth, aad ]) 48 | 49 | ciphertext = bytes 50 | nonce = bytes .size 12 51 | auth = bytes .size 16 52 | 53 | aad = tagged-digest 54 | ``` 55 | 56 | The `encrypted` case can be discriminated from other Envelope case arms by the fact that it is the only one that is tagged using `#6.40002`. 57 | 58 | ## Declaring the Digest 59 | 60 | This section is normative. 61 | 62 | The `encrypted` case directly declares the encrypted envelope's digest as the fourth element of its array, `aad`. The `tagged-digest` encoded therein MUST match the actual digest of the Envelope that has been encrypted. Decrypting an envelope MUST be validated by matching the decrypted Envelope's actual computed digest to the one declared, and the decryption operation MUST reject the result if the digests do not match. 63 | 64 | **Example** 65 | 66 | ``` 67 | $ KEY=`envelope generate key` 68 | $ ENVELOPE=`envelope subject "Hello"` 69 | 70 | $ envelope format --diag $ENVELOPE 71 | 72 | 200( / envelope / 73 | 24("Hello") / leaf / 74 | ) 75 | 76 | $ envelope digest --hex $ENVELOPE 77 | 78 | 4d303dac9eed63573f6190e9c4191be619e03a7b3c21e9bb3d27ac1a55971e6b 79 | 80 | $ ENCRYPTED_ENVELOPE=`envelope encrypt --key $KEY $ENVELOPE` 81 | $ envelope format --diag $ENCRYPTED_ENVELOPE 82 | 83 | 200( / envelope / 84 | 40002( / encrypted / 85 | [ 86 | h'dadeecba53db714445c0', 87 | h'3cda0648bcb07f0f8b4da2be', 88 | h'912a35829bab21219c0e7974f6f8b2cc', 89 | h'd99c4158204d303dac9eed63573f6190e9c4191be619e03a7b3c21e9bb3d27ac1a55971e6b' 90 | ] 91 | ) 92 | ) 93 | 94 | $ envelope digest --hex $ENCRYPTED_ENVELOPE 95 | 96 | 4d303dac9eed63573f6190e9c4191be619e03a7b3c21e9bb3d27ac1a55971e6b 97 | ``` 98 | 99 | Notice that the digest of the unencrypted and encrypted Envelopes both match. This is because the fourth array element of the encrypted Envelope is the encoded CBOR for `tagged-digest`: 100 | 101 | ``` 102 | 40001(h'4d303dac9eed63573f6190e9c4191be619e03a7b3c21e9bb3d27ac1a55971e6b') 103 | ``` 104 | 105 | ## Reference Implementations 106 | 107 | This section is informative. 108 | 109 | Both the [Swift Gordian Envelope Reference Implementation](https://github.com/BlockchainCommons/BCSwiftEnvelope) and the [Rust Gordian Envelope Reference Implementation](https://github.com/BlockchainCommons/bc-envelope-rust) support this extension. 110 | 111 | ## Future Proofing 112 | 113 | To support this extension, future extensions to the encrypted message used herein and defined in [UR Type Definition for Encrypted Messages](bcr-2022-001-encrypted-message.md) may support other encryption constructs. To work with this specification, they MUST support an equivalent of the `aad` field afforded by the original IETF-ChaCha20-Poly1305 construct so that the digest of the encrypted Envelope can be declared. 114 | 115 | ## Security Considerations 116 | 117 | Generally, this document inherits the security considerations of the cryptographic construct it uses: [IETF-ChaCha20-Poly1305](https://datatracker.ietf.org/doc/html/rfc7539). 118 | 119 | ## IANA Considerations 120 | 121 | This document makes no requests of IANA. 122 | -------------------------------------------------------------------------------- /papers/bcr-2023-005-envelope-compression.md: -------------------------------------------------------------------------------- 1 | # Gordian Envelope Extension: Compression 2 | 3 | ## BCR-2023-005 4 | 5 | **© 2023 Blockchain Commons** 6 | 7 | Authors: Wolf McNally, Christopher Allen
8 | Date: Aug 15, 2022
9 | Revised: Aug 15, 2023 10 | 11 | ## Abstract 12 | 13 | This document extends the Gordian Envelope Base Specification to add the `compressed` case arm, which supports the general purpose compression of any Envelope. 14 | 15 | ## Introduction 16 | 17 | This document extends the [Gordian Envelope Base Specification](https://datatracker.ietf.org/doc/draft-mcnally-envelope/) to add the `compressed` case arm used to represent an Envelope that has been compressed. The scheme defined herein supports the [DEFLATE](https://datatracker.ietf.org/doc/html/rfc1951) algorithm. 18 | 19 | Like elision, which is supported by the Envelope Base Specification, compression is a reversible transformation of an Envelope that does not alter its unique digest. And since Envelope is a recursively nested structure of Envelopes in a Merkle-like digest tree, any of these nested envelopes can be elided or compressed without disturbing the tree, hence preserving constructs like signatures. 20 | 21 | ## Format Specification 22 | 23 | This section is normative, and specifies an additional case arm for the `envelope` type: `compressed`. It also specifies that assertions may be compressed by adding the `compressed-assertion` case to Envelope's `assertion-element` type. 24 | 25 | The formal language used is the [Concise Data Definition Language (CDDL)](https://datatracker.ietf.org/doc/html/rfc8610). The top-level specification of Gordian Envelope with this extension added is: 26 | 27 | ``` 28 | envelope = #6.200(envelope-content) 29 | envelope-content = ( 30 | leaf / elided / node / assertion / wrapped / 31 | compressed 32 | ) 33 | 34 | assertion-element = ( 35 | assertion / elided-assertion / 36 | compressed-assertion 37 | ) 38 | 39 | compressed-assertion = compressed ; MUST represent an assertion 40 | ``` 41 | 42 | The format for `compressed` corresponds to `tagged-compressed` as defined in [UR Type Definition for Compressed Messages](bcr-2023-001-compressed-message.md), including the CBOR tag `#6.40003`. In this specification, the optional fourth array element `tagged-digest` (defined in [BCR-2021-002](bcr-2021-002-digest.md)) is REQUIRED, and MUST contain the CBOR-encoded tagged digest of the envelope: 43 | 44 | ``` 45 | compressed = #6.40003([checksum, uncompressed-size, compressed-data, tagged-digest]) 46 | 47 | checksum = crc32 48 | crc32 = uint 49 | 50 | uncompressed-size = uint 51 | compressed-data = bytes 52 | ``` 53 | 54 | The `compressed` case can be discriminated from other Envelope case arms by the fact that it is the only one that is tagged using `#6.40003`. 55 | 56 | ## Declaring the Digest 57 | 58 | This section is normative. 59 | 60 | The `compressed` case directly declares the compressed envelope's digest as the fourth element of its array, `digest`. The `tagged-digest` encoded therein MUST match the actual digest of the Envelope that has been compressed. Decompressing an envelope MUST be validated by matching the uncompressed Envelope's actual computed digest to the one declared, and the decompression operation MUST reject the result if the digests do not match. 61 | 62 | **Example** 63 | 64 | In the following example, the test envelope is too small for effective compression by DEFLATE, so the uncompressed payload is used where the compressed payload would normally be. This is as is specified in [UR Type Definition for Compressed Messages](bcr-2023-001-compressed-message.md) and is only for example purposes. 65 | 66 | ``` 67 | $ ENVELOPE=`envelope subject "Hello"` 68 | 69 | $ envelope format --diag $ENVELOPE 70 | 71 | 200( / envelope / 72 | 24("Hello") / leaf / 73 | ) 74 | 75 | $ envelope digest --hex $ENVELOPE 76 | 77 | 4d303dac9eed63573f6190e9c4191be619e03a7b3c21e9bb3d27ac1a55971e6b 78 | 79 | $ COMPRESSED_ENVELOPE=`envelope compress $ENVELOPE` 80 | $ envelope format --diag $COMPRESSED_ENVELOPE 81 | 82 | 200( / envelope / 83 | 40003( / compressed / 84 | [ 85 | 1146116589, 86 | 10, 87 | h'd8c8d8186548656c6c6f', 88 | 40001( / digest / 89 | h'4d303dac9eed63573f6190e9c4191be619e03a7b3c21e9bb3d27ac1a55971e6b' 90 | ) 91 | ] 92 | ) 93 | ) 94 | 95 | $ envelope digest --hex $COMPRESSED_ENVELOPE 96 | 97 | 4d303dac9eed63573f6190e9c4191be619e03a7b3c21e9bb3d27ac1a55971e6b 98 | ``` 99 | 100 | Notice that the digest of the unencrypted and encrypted Envelopes both match. This is because the fourth array element of the encrypted Envelope declares the uncompressed envelope's digest. 101 | 102 | ## Reference Implementations 103 | 104 | This section is informative. 105 | 106 | Both the [Swift Gordian Envelope Reference Implementation](https://github.com/BlockchainCommons/BCSwiftEnvelope) and the [Rust Gordian Envelope Reference Implementation](https://github.com/BlockchainCommons/bc-envelope-rust) support this extension. 107 | 108 | ## Future Proofing 109 | 110 | To support this extension, future extensions to the compressed message used herein and defined in [UR Type Definition for Compressed Messages](bcr-2023-001-compressed-message.md) may support other compression constructs. To work with this specification, they MUST support an equivalent of the `digest` field so that the digest of the encrypted Envelope can be declared. 111 | 112 | ## Security Considerations 113 | 114 | In general, this specification inherits any security considerations of the DEFLATE algorithm. 115 | 116 | ## IANA Considerations 117 | 118 | This document makes no requests of IANA. 119 | -------------------------------------------------------------------------------- /papers/bcr-2023-006-envelope-attachment.md: -------------------------------------------------------------------------------- 1 | # Gordian Envelope: Attachments 2 | 3 | ## BCR-2023-006 4 | 5 | **© 2023 Blockchain Commons** 6 | 7 | Authors: Wolf McNally, Christopher Allen
8 | Date: Aug 23, 2022
9 | Revised: Mar 6, 2024 10 | 11 | ## Abstract 12 | 13 | This document defines a method for adding vendor-specific information ("attachments") to a Gordian Envelope. 14 | 15 | ## Introduction 16 | 17 | This document defines a protocol for specifying vendor-specific additional data ("attachments") to a Gordian Envelope. 18 | 19 | ## Known Values 20 | 21 | This document uses the following [Known Values](bcr-2023-002-known-value.md): 22 | 23 | | Codepoint | Canonical Name | Type | Description | URI 24 | |--|--|--|--|--| 25 | | 50 | `attachment` | property | Declares that the object is a vendor-defined attachment to the envelope. | [BCR-2023-006](bcr-2023-006-envelope-attachment.md) 26 | | 51 | `vendor` | property | Declares the vendor of the subject. | [BCR-2023-006](bcr-2023-006-envelope-attachment.md) 27 | | 52 | `conformsTo` | property | An established standard to which the subject conforms. | http://purl.org/dc/terms/conformsTo 28 | 29 | ## Format Specification 30 | 31 | A Gordian Envelope is specified by the format of its subject and the assertions it MUST or MAY include. For security, Envelope definitions SHOULD reject as invalid any unexpected assertions that are not defined for the Envelope type. 32 | 33 | As an example, an Envelope containing a cryptographic seed has a subject that is a byte string containing the seed. It MUST include an `'isA': Seed` assertion to declare its type. A Seed Envelope MAY also include an optional `'name'` assertion, an optional `'note'` assertion, and an optional `'date'` assertion: 34 | 35 | ``` 36 | Bytes(16) [ 37 | 'isA': Seed 38 | 'name': "Dark Purple Aqua Love" 39 | 'note': "This is the note." 40 | ] 41 | ``` 42 | 43 | If an Envelope specification allows attachments, they are added by using one or more `attachment` assertions. For example: 44 | 45 | ``` 46 | Bytes(16) [ 47 | 'isA': Seed 48 | 'attachment': { 49 | "Attachment Data" 50 | } [ 51 | 'conformsTo': "https://example.com/seed-envelope-attachment/v1" 52 | 'vendor': "com.example" 53 | ] 54 | 'name': "Dark Purple Aqua Love" 55 | 'note': "This is the note." 56 | ] 57 | ``` 58 | 59 | The object-subject of the `'attachment'` assertion is its "payload", which in the above example is the string `"Attachment Data"`. The payload may be an Envelope of arbitrary complexity. The contents of the payload are defined by the vendor. 60 | 61 | The payload is wrapped, and to this wrapped envelope is added one REQUIRED assertion: `'vendor'`, and optionally one RECOMMENDED assertion: `'conformsTo'`. No other assertions are permitted. 62 | 63 | * The `'vendor'` assertion is REQUIRED and MUST be a string that uniquely identifies the entity that added the attachment data. It is RECOMMENDED that it be a reverse domain name. It MAY NOT be an empty string. It MAY NOT be any other data type have additional assertions. 64 | * The `'conformsTo'` assertion is RECOMMENDED and MUST be a string that identifies the format of the attachment data. It is RECOMMENDED that it be a URL that points to a document that defines the format of the attachment data including version number. It MAY NOT be any other data type or have additional assertions. 65 | * The source of the `'conformsTo'` URI does not have to be from the same vendor as the `'vendor'` assertion. In other words, the `'conformsTo'` URI MAY be from a third party that defines a standard format for the attachment data. 66 | 67 | Multiple attachments MAY be added to an Envelope that accepts them. For example: 68 | 69 | ``` 70 | Bytes(16) [ 71 | 'isA': Seed 72 | 'attachment': { 73 | "Attachment Data Version 1" 74 | } [ 75 | 'conformsTo': "https://example.com/seed-envelope-attachment/v1" 76 | 'vendor': "com.example" 77 | ] 78 | 'attachment': { 79 | "Attachment Data Version 2" 80 | } [ 81 | 'conformsTo': "https://example.com/seed-envelope-attachment/v2" 82 | 'vendor': "com.example" 83 | ] 84 | 'name': "Dark Purple Aqua Love" 85 | 'note': "This is the note." 86 | ] 87 | ``` 88 | 89 | Applications that process Envelopes in which attachments are supported: 90 | 91 | * MAY implement support for attachments they understand. 92 | * MAY reject Envelopes with attachments that they do not understand. 93 | * May ignore Envelopes with attachments that they do not understand (but note that ignored attachments still contribute to the digest of the Envelope) 94 | * MAY store the Envelope's attachments for later retrieval. 95 | * MAY transfer an Envelope's attachments to another Envelope when it makes sense to do so, such as when a new Envelope is created as a variant of an existing Envelope. 96 | * MAY notify the user that the Envelope contains attachments, or provide affordances for the user to view or edit the attachments. 97 | -------------------------------------------------------------------------------- /papers/bcr-2023-007-envelope-output-desc.md: -------------------------------------------------------------------------------- 1 | # Gordian Envelope: Bitcoin Output Descriptors (Version 2) 2 | 3 | ## BCR-2023-007 4 | 5 | **© 2023 Blockchain Commons** 6 | 7 | Authors: Wolf McNally, Christopher Allen
8 | Date: Aug 30, 2022
9 | Revised: Aug 30, 2023 10 | 11 | ### DEPRECATED: Superseded by Version 3 Output Descriptors 12 | 13 | This document has been superseded by [Bitcoin Output Descriptors (Version 3)](bcr-2023-010-output-descriptor.md). 14 | 15 | The content below is now deprecated and of historical interest only. It is not deployed anywhere of which we are aware. 16 | 17 | ## Abstract 18 | 19 | This document defines a format for enclosing typed Bitcoin output descriptors in Gordian Envelopes. 20 | 21 | ## Introduction 22 | 23 | The primary definition for Bitcoin output descriptors is text-based and defined in [BIP-174](https://github.com/bitcoin/bitcoin/blob/master/doc/descriptors.md). 24 | 25 | This document defines a method for enclosing Bitcoin output descriptors in Gordian Envelopes, leveraging the existing text-based format and adding an assertion to declare the data type. 26 | 27 | ## Known Values 28 | 29 | The two Known Values this protocol uses are defined in the [Known Values Registry](bcr-2023-002-known-value.md#appendix-a-registry): 30 | 31 | * `OutputDescriptor` (class) 32 | * `outputDescriptor` (property) 33 | * `name` (property) 34 | * `note` (property) 35 | 36 | Note the difference in case of the two known values: `OutputDescriptor` is a type (class), and `outputDescriptor`, is a predicate (property). 37 | 38 | ## Format Specification 39 | 40 | The subject of a Bitcoin Output Descriptor Envelope is a text string containing a Bitcoin output descriptor. 41 | 42 | * It MUST include an `isA: OutputDescriptor` assertion to declare its type conforming to this document. 43 | * It MAY include a `name` assertion, where the object MUST be a non-empty string. 44 | * It MAY include a `note` assertion, where the object MUST be a non-empty string. 45 | 46 | **Example:** 47 | 48 | ``` 49 | "wpkh([37b5eed4/84'/0'/0']xpub6BkU445MSEBXbPjD3g2c2ch6mn8yy1SXXQUM7EwjgYiq6Wt1NDwDZ45npqWcV8uQC5oi2gHuVukoCoZZyT4HKq8EpotPMqGqxdZRuapCQ23/<0;1>/*)" [ 50 | 'isA': OutputDescriptor 51 | 'name': "Example" 52 | 'note': "This is the note." 53 | ] 54 | ``` 55 | 56 | ### In an Assertion 57 | 58 | A Bitcoin Output Descriptor Envelope MAY be used as the object of an assertion with the `outputDescriptor` predicate. 59 | 60 | **Example:** 61 | 62 | ``` 63 | "Example" [ 64 | 'outputDescriptor': "wpkh([37b5eed4/84'/0'/0']xpub6BkU445MSEBXbPjD3g2c2ch6mn8yy1SXXQUM7EwjgYiq6Wt1NDwDZ45npqWcV8uQC5oi2gHuVukoCoZZyT4HKq8EpotPMqGqxdZRuapCQ23/<0;1>/*)" [ 65 | 'isA': OutputDescriptor 66 | 'name': "Example" 67 | 'note': "This is the note." 68 | ] 69 | ] 70 | ``` 71 | -------------------------------------------------------------------------------- /papers/bcr-2023-008-dcbor-date.md: -------------------------------------------------------------------------------- 1 | # dCBOR: Preferred Encoding of Dates 2 | 3 | ## BCR-2023-008 4 | 5 | **© 2023 Blockchain Commons** 6 | 7 | Authors: Wolf McNally, Christopher Allen
8 | Date: Sep 2, 2022
9 | Revised: Sep 4, 2023 10 | 11 | ## Abstract 12 | 13 | This document defines a preferred format for dates in Gordian Deterministic CBOR (dCBOR). 14 | 15 | ## Format Specification 16 | 17 | CBOR already has a well-defined date format using the tag #6.1 defined in [RFC 8949 §3.4.2 Epoch-Based Date Type](https://www.rfc-editor.org/rfc/rfc8949.html#section-3.4.2). 18 | 19 | This document specifies this method, which MUST include its tag-based type declaration, as the preferred format to specify dates when using [Gordian dCBOR](https://datatracker.ietf.org/doc/draft-mcnally-deterministic-cbor/). 20 | 21 | RFC 8949 says the tagged value may be either an integer or a float, but dCBOR's numeric reduction rules apply and MUST be used to determine the encoded numeric type. 22 | 23 | ## CDDL 24 | 25 | ``` 26 | tagged-date = #6.1(date) 27 | date = int / float 28 | ``` 29 | -------------------------------------------------------------------------------- /papers/bcr-2023-009-envelope-seed.md: -------------------------------------------------------------------------------- 1 | # Gordian Envelope: Cryptographic Seeds 2 | 3 | ## BCR-2023-007 4 | 5 | **© 2023 Blockchain Commons** 6 | 7 | Authors: Wolf McNally, Christopher Allen
8 | Date: Sep 4, 2022 9 | 10 | ## Abstract 11 | 12 | This document defines a format for enclosing cryptographic seeds in Gordian Envelopes 13 | 14 | ## Introduction 15 | 16 | Crypto seeds are large random numbers used to generate cryptographic keys. 17 | 18 | ## Known Values 19 | 20 | The Known Values this protocol uses are defined in the [Known Values Registry](bcr-2023-002-known-value.md#appendix-a-registry): 21 | 22 | * `Seed` (class) 23 | * `isA` (property) 24 | * `name` (property) 25 | * `note` (property) 26 | * `date` (property) 27 | * `outputDescriptor` (property) 28 | * `attachment` (property) 29 | 30 | ## Format Specification 31 | 32 | An Envelope containing a cryptographic seed has a subject that is a byte string containing the seed. 33 | 34 | * It MUST include an `isA: Seed` assertion to declare its type conforming to this document. 35 | * It MAY include a single `name` assertion, where the object MUST be a non-empty string, which MAY have been elided. 36 | * It MAY include a single `note` assertion, where the object MUST be a non-empty string, which MAY have been elided. 37 | * It MAY include a single `date` assertion, where the object MUST be a date conforming to [BCR-2023-008](bcr-2023-008-dcbor-date.md). 38 | * It MAY include a single `outputDescriptor` assertion, where the object MUST be a Bitcoin output descriptor conforming to [BCR-2023-007](bcr-2023-007-envelope-output-desc.md). 39 | * It MAY include one or more `attachment` assertions conforming to [BCR-2023-006](bcr-2023-006-envelope-attachment.md). 40 | 41 | **Example:** 42 | 43 | ``` 44 | Bytes(16) [ 45 | 'isA': Seed 46 | 'attachment': { 47 | "Attachment Data" 48 | } [ 49 | 'conformsTo': "https://example.com/seed-envelope-attachment/v1" 50 | 'vendor': "com.example" 51 | ] 52 | 'date': 2021-02-24T09:19:01Z 53 | 'name': "Dark Purple Aqua Love" 54 | 'note': "This is the note." 55 | 'outputDescriptor': "wpkh([37b5eed4/84'/0'/0']xpub6BkU445MSEBXbPjD3g2c2ch6mn8yy1SXXQUM7EwjgYiq6Wt1NDwDZ45npqWcV8uQC5oi2gHuVukoCoZZyT4HKq8EpotPMqGqxdZRuapCQ23/<0;1>/*)" [ 56 | 'isA': OutputDescriptor 57 | 'name': "Example Descriptor" 58 | 'note': "This is the descriptor's note." 59 | ] 60 | ] 61 | ``` 62 | -------------------------------------------------------------------------------- /papers/bcr-2023-011-public-key-crypto.md: -------------------------------------------------------------------------------- 1 | # UR Type Definitions for Public Key Cryptography 2 | 3 | ## BCR-2023-011 4 | 5 | **© 2023 Blockchain Commons** 6 | 7 | Authors: Wolf McNally, Christopher Allen
8 | Date: December 9, 2023
9 | Revised: December 9, 2023 10 | 11 | ## Introduction 12 | 13 | Public key cryptography is a fundamental building block of secure systems. This document defines a set of UR types for encrypting and signing data using public key cryptography. 14 | 15 | The encryption primitives are based on [X25519 key agreement](https://datatracker.ietf.org/doc/html/rfc7748), and the signature primitives are based on [BIP-340 Schnorr](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki) and [ECDSA-25519-doublesha256](https://en.bitcoin.it/wiki/BIP_0137). 16 | 17 | ## UR Types and CBOR Tags 18 | 19 | This document defines the following UR types along with their corresponding CBOR tags: 20 | 21 | | UR type | CBOR Tag | 22 | | :----------------------- | :------- | 23 | | ur:agreement-private-key | #6.40010 | 24 | | ur:agreement-public-key | #6.40011 | 25 | | ur:crypto-prvkeys | #6.40013 | 26 | | ur:crypto-prvkey-base | #6.40016 | 27 | | ur:crypto-pubkeys | #6.40017 | 28 | | ur:crypto-sealed | #6.40019 | 29 | | ur:signature | #6.40020 | 30 | | ur:signing-private-key | #6.40021 | 31 | | ur:signing-public-key | #6.40022 | 32 | 33 | These tags have been registered in the [IANA Registry of CBOR Tags](https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml). 34 | 35 | ## Agreement Private Key `ur:agreement-private-key` 36 | 37 | A Curve25519 private key used for [X25519 key agreement](https://datatracker.ietf.org/doc/html/rfc7748). See `private-key-base` for how to derive agreement keys from the base key material. 38 | 39 | ### CDDL 40 | 41 | ``` 42 | agreement-private-key = #6.40010(bytes .size 32) 43 | ``` 44 | 45 | ## Agreement Public Key `ur:agreement-public-key` 46 | 47 | A Curve25519 public key used for [X25519 key agreement](https://datatracker.ietf.org/doc/html/rfc7748). 48 | 49 | ### CDDL 50 | 51 | ``` 52 | agreement-public-key = #6.40011(bytes .size 32) 53 | ``` 54 | 55 | ## Private Key Base `ur:crypto-prvkey-base` 56 | 57 | Holds cryptographic key material that may be of any length, but it is RECOMMENDED that it be at least 32 bytes in length. It can produce all the private and public keys needed to use this suite. It is usually only serialized for purposes of backup. 58 | 59 | ### CDDL 60 | 61 | ``` 62 | crypto-prvkey-base = #6.40016(key-material) 63 | key-material = bytes 64 | ``` 65 | 66 | ### Derivations 67 | 68 | * `signing-private-key`: [HKDF](https://www.rfc-editor.org/rfc/rfc6234) with salt: `signing`. 69 | * `agreement-private-key`: [HKDF](https://www.rfc-editor.org/rfc/rfc6234) with salt: `agreement`. 70 | * `signing-private-key`: [RFC-7748 X25519](https://datatracker.ietf.org/doc/html/rfc7748). 71 | * `signing-public-key`: 72 | * [BIP-340 Schnorr](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki) x-only public key, or 73 | * [ECDSA-25519-doublesha256](https://en.bitcoin.it/wiki/BIP_0137) public key. 74 | 75 | ## PublicKeys `ur:crypto-pubkeys` 76 | 77 | Holds the public keys of an identifiable entity, and can be made public. It is not simply called a "public key" because it holds at least _two_ public keys: one for signing and another for encryption. The `signing-public-key` may specifically be for verifying Schnorr or ECDSA signatures. 78 | 79 | ### CDDL 80 | 81 | A `crypto-pubkeys` is a two-element array with the first element being the `signing-public-key` and the second being the `agreement-public-key`. 82 | 83 | ``` 84 | crypto-pubkeys = #6.40017([signing-public-key, agreement-public-key]) 85 | ``` 86 | 87 | ## Sealed Message `ur:crypto-sealed` 88 | 89 | A message that has been one-way encrypted to a particular `agreement-public-key`, and may be used to implement anonymous-sender and multi-recipient public key encryption. 90 | 91 | An ephemeral sender agreement key pair generated at encryption time, and the ephemeral sender's public key is included, enabling the recipient to decrypt the message without identifying the real sender. The ephemeral private key is discarded. 92 | 93 | The `encrypted` type is defined in [BCR-2022-001](bcr-2022-001-encrypted-message.md). 94 | 95 | ### SealedMessage: CDDL 96 | 97 | ``` 98 | crypto-sealed = #6.40019([encrypted, ephemeral-public-key]) 99 | ephemeral-public-key = agreement-public-key 100 | ``` 101 | 102 | ## Signature 103 | 104 | A cryptographic signature. It has two variants: 105 | 106 | * A [BIP-340 Schnorr](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki) signature. 107 | * An [ECDSA-25519-doublesha256](https://en.bitcoin.it/wiki/BIP_0137) signature. 108 | 109 | ### CDDL 110 | 111 | A `signature` has two variants. The Schnorr variant is preferred. Schnorr signatures may include tag data of arbitrary length. 112 | 113 | If the `signature-variant-schnorr` is selected and has no tag, it will appear directly as a byte string of length 64. If it includes tag data, it will appear as a two-element array where the first element is the signature and the second element is the tag. The second form MUST NOT be used if the tag data is empty. 114 | 115 | If the `signature-variant-ecdsa` is selected, it will appear as a two-element array where the first element is `1` and the second element is a byte string of length 64. 116 | 117 | ``` 118 | signature = #6.40020(signature-variant-schnorr / signature-variant-ecdsa) 119 | 120 | signature-variant-schnorr = signature-schnorr / signature-schnorr-tagged 121 | signature-schnorr = bytes .size 64 122 | signature-schnorr-tagged = [signature-schnorr, schnorr-tag] 123 | schnorr-tag = bytes .size ne 0 124 | 125 | signature-variant-ecdsa = [ 1, signature-ecdsa ] 126 | signature-ecdsa = bytes .size 64 127 | ``` 128 | 129 | ## SigningPrivateKey 130 | 131 | A private key for creating [BIP-340 Schnorr](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki) or [ECDSA-25519-doublesha256](https://en.bitcoin.it/wiki/BIP_0137) signatures. See `private-key-base` for how to derive signing keys from the base key material. 132 | 133 | ### CDDL 134 | 135 | ``` 136 | private-signing-key = #6.40021(bytes .size 32) 137 | ``` 138 | 139 | ## SigningPublicKey 140 | 141 | A public key for verifying signatures. It has two variants: 142 | 143 | * An x-only public key for verifying [BIP-340 Schnorr](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki) signatures. 144 | * An ECDSA public key [ECDSA-25519-doublesha256](https://en.bitcoin.it/wiki/BIP_0137) signatures. 145 | 146 | ### SigningPublicKey: CDDL 147 | 148 | A signing public key has two variants: Schnorr or ECDSA. The Schnorr variant is preferred, so it appears as a byte string of length 32. If ECDSA is selected, it appears as a 2-element array where the first element is `1` and the second element is the compressed ECDSA key as a byte string of length 33. 149 | 150 | ``` 151 | signing-public-key = #6.40022(key-variant-schnorr / key-variant-ecdsa) 152 | 153 | key-variant-schnorr = key-schnorr 154 | key-schnorr = bytes .size 32 155 | 156 | key-variant-ecdsa = [1, key-ecdsa] 157 | key-ecdsa = bytes .size 33 158 | ``` 159 | -------------------------------------------------------------------------------- /papers/bcr-2023-013-envelope-crypto.md: -------------------------------------------------------------------------------- 1 | # Gordian Envelope Cryptography 2 | 3 | ## BCR-2023-013 4 | 5 | **© 2023 Blockchain Commons** 6 | 7 | Authors: Wolf McNally, Christopher Allen
8 | Date: December 9, 2023
9 | Revised: December 9, 2023 10 | 11 | ## Overview 12 | 13 | Gordian Envelope can be used to encrypt and sign data. For encryption, Envelope supports both symmetric and public key encryption. Envelope also supports sharding using [SSKR](bcr-2020-011-sskr.md). 14 | 15 | ## Symmetric Encryption 16 | 17 | Gordian Envelope supports industry standard IETF-ChaCha20-Poly1305 symmetric encryption as described in [BCR-2023-004](bcr-2023-004-envelope-symmetric-encryption.md). Using a symmetric `crypto-key` defined in [BCR-2020-001](bcr-2022-001-encrypted-message.md), the Envelope API specifically encrypts the subject of the envelope, transforming it into an instance of `encrypted` (ibid.) and, leaving its assertions unencrypted. For example: 18 | 19 | ``` 20 | "Secret" [ 21 | "assertion1": "value1" 22 | "assertion2": "value2" 23 | ] 24 | ``` 25 | 26 | becomes: 27 | 28 | ``` 29 | ENCRYPTED [ 30 | "assertion1": "value1" 31 | "assertion2": "value2" 32 | ] 33 | ``` 34 | 35 | If the entire contents of an envelope are to be encrypted, it must first be wrapped, so all of its assertions are included: 36 | 37 | ``` 38 | { 39 | "Secret" [ 40 | "assertion1": "value1" 41 | "assertion2": "value2" 42 | ] 43 | } 44 | ``` 45 | 46 | Now the entire contents of the envelope are encrypted: 47 | 48 | ``` 49 | ENCRYPTED 50 | ``` 51 | 52 | Note that in both cases, the digest associated with the envelope does not change, as the `encrypted` message declares the digest of the unencrypted envelope as described in [BCR-2023-004](bcr-2023-004-envelope-symmetric-encryption.md). 53 | 54 | Symmetric key encryption is a building block of both the public key encryption and the sharding using SSKR described below. 55 | 56 | ## Public Key Encryption 57 | 58 | A "sealed message" (`crypto-sealed`) as described in [BCR-2023-011](bcr-2023-011-public-key-crypto.md) is a message that has been encrypted to a specific recipient using their public key (`crypto-pubkeys`) (ibid.) in such a way that only the recipient and not even the sender can decrypt it later. Creating a sealed message involves several steps: 59 | 60 | 1. **Create a Unique Symmetric Key:** A unique symmetric key (the content key) is generated for encrypting the payload. 61 | 62 | 2. **Ephemeral Sender Key Pair and Encryption:** An ephemeral sender public-private key pair is created. The symmetric key is then encrypted using the recipient's public key through this ephemeral key pair. 63 | 64 | 3. **Discard the Ephemeral Private Key:** The ephemeral private key is discarded after its one-time use, enhancing security by ensuring that even the sender cannot decrypt the message once it's sent. 65 | 66 | Gordian Envelope supports multi-recipient public key encryption by adding one or more `hasRecipient: SealedMessage` assertions to the envelope. Only a single content key is used, but that key is separately encrypted to each recipient's `PublicKeys`, one per recipient. For example, a message encrypted to two recipients would look like this: 67 | 68 | ``` 69 | ENCRYPTED [ 70 | 'hasRecipient': SealedMessage 71 | 'hasRecipient': SealedMessage 72 | ] 73 | ``` 74 | 75 | As the sealed message gives no indicator of which recipient it is for, a recipient must try to decrypt each sealed message in turn until one succeeds. Once it has the content key, it can decrypt the envelope's subject. 76 | 77 | ## Signing 78 | 79 | A signature (`signature`) (ibid.) supports either [BIP-340 Schnorr](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki) (preferred) or [ECDSA-25519-doublesha256](https://en.bitcoin.it/wiki/BIP_0137). The signature is generated by signing the digest of the subject envelope. The signature is then added to the envelope as a `signed` assertion. Multiple signers can be supported by adding multiple `signed` assertions: 80 | 81 | ``` 82 | ENCRYPTED [ 83 | 'signed': Signature 84 | 'signed': Signature 85 | ] 86 | ``` 87 | 88 | The above is an example of encrypt-then-sign. Sign-then-encrypt is also supported, by first adding the `signed` assertion before encrypting the envelope: 89 | 90 | ``` 91 | "Payload" [ 92 | 'signed': Signature 93 | ] 94 | ``` 95 | 96 | then wrapping the entire envelope: 97 | 98 | ``` 99 | { 100 | "Payload" [ 101 | 'signed': Signature 102 | ] 103 | } 104 | ``` 105 | 106 | and finally encrypting the entire envelope: 107 | 108 | ``` 109 | ENCRYPTED 110 | ``` 111 | 112 | ## Sharding using SSKR 113 | 114 | Sharding is a technique for splitting a secret into multiple shares, such that a minimum number of shares are required to reconstruct the secret. SSKR is a standard for sharding secrets, defined in [BCR-2020-011](bcr-2020-011-sskr.md). As with public key encryption, an ephemeral content key can be used to encrypt the payload, and then the content key can be sharded using SSKR. A set of envelopes can each be generated and distributed, each containing a unique `sskrAssertion` containing a share of the content key: 115 | 116 | ``` 117 | ENCRYPTED [ 118 | 'sskrShare': SSKRShare 119 | ] 120 | ``` 121 | 122 | A minimum number of shares can be used to reconstruct the content key, which can then be used to decrypt the envelope subject. 123 | 124 | ## Combinations 125 | 126 | All of the above techniques can be combined. For example, a message can be signed: 127 | 128 | ``` 129 | "Payload" [ 130 | 'signed': Signature 131 | ] 132 | ``` 133 | 134 | then wrapped: 135 | 136 | ``` 137 | { 138 | "Payload" [ 139 | 'signed': Signature 140 | ] 141 | } 142 | ``` 143 | 144 | then encrypted: 145 | 146 | ``` 147 | ENCRYPTED 148 | ``` 149 | 150 | then a content key generated which is used to add a `hasRecipient` assertion: 151 | 152 | ``` 153 | ENCRYPTED [ 154 | 'hasRecipient': SealedMessage 155 | ] 156 | ``` 157 | 158 | then the content key sharded using SSKR: 159 | 160 | ``` 161 | ENCRYPTED [ 162 | 'hasRecipient': SealedMessage 163 | 'sskrShare': SSKRShare 164 | ] 165 | ``` 166 | 167 | This results in a set of envelopes, the payload of which can be decrypted by a specific holder of the recipient's private key, or by collecting a quorum of SSKR shares. 168 | -------------------------------------------------------------------------------- /papers/bcr-2023-014-gstp.md: -------------------------------------------------------------------------------- 1 | # Gordian Sealed Transaction Protocol (GSTP) 2 | 3 | ## BCR-2023-014 4 | 5 | **© 2023 Blockchain Commons** 6 | 7 | Authors: Wolf McNally, Christopher Allen
8 | Date: December 8, 2023
9 | Revised: December 8, 2023 10 | 11 | ## Overview 12 | 13 | Gordian Sealed Transaction Protocol (GSTP) supports secure communication between two or more parties, and is built on the Gordian Envelope specification. 14 | 15 | GSTP is specifically designed to be transport-agnostic: usable over HTTP, raw TCP/IP, airgapped protocols using QR codes, NFC cards, etc. As such it specifies its own secure encryption and signing protocol. 16 | 17 | It is also designed to be usable with various protocol architectures, including client-server and peer-to-peer. 18 | 19 | GSTP builds on the Envelope Expression format defined in [BCR-2023-012](bcr-2023-011-envelope-expression.md). As such it uses a function-calling or remote procedure call (RPC) syntax, and gains the flexibility of the Envelope Expression syntax. 20 | 21 | GSTP also builds on the encryption and signing techniques defined in [BCR-2023-013](bcr-2023-013-envelope-crypto.md). 22 | 23 | ## UR Types and CBOR Tags 24 | 25 | This document defines the following UR types along with their corresponding CBOR tags: 26 | 27 | | UR type | CBOR Tag | 28 | | :--------------- | :--------- | 29 | | ur:request | #6.40004 | 30 | | ur:response | #6.40005 | 31 | | ur:event | #6.40026 | 32 | 33 | These tags have been registered in the [IANA Registry of CBOR Tags](https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml). 34 | 35 | ## Known Values 36 | 37 | This document uses the following [Known Values](bcr-2023-002-known-value.md): 38 | 39 | | Codepoint | Canonical Name | Type | Description | URI 40 | |--|--|--|--|--| 41 | | 17 | Unknown | value | Placeholder for an unknown value. | https://en.wikipedia.org/wiki/Blank_node 42 | | 100 | body | property | Property declaring that the object is the body (parameters of) a distributed request identified by the subject. 43 | | 101 | result | property | Property declaring that the object is the success result of the request identified by the subject. 44 | | 102 | error | property | Property declaring that the object is the failure result of the request identified by the subject. 45 | | 103 | OK | value | Instance providing the success result of a request that has no other return value. 46 | | 104 | Processing | value | Instance providing the "in processing" result of a request. 47 | 48 | ## Encrypting and Signing GSTP Messages 49 | 50 | GSTP messages are Gordian Envelopes that are encrypted to a receiver. Beyond that, they do not expose whether they are a request or a response, or anything else about their contents. The receiver must decrypt the message to learn more: 51 | 52 | ``` 53 | ENCRYPTED [ 54 | 'hasRecipient': SealedMessage 55 | ] 56 | ``` 57 | 58 | The decrypted envelope is a wrapped envelope with a signature: 59 | 60 | ``` 61 | { 62 | *omitted* 63 | } [ 64 | 'signed': Signature 65 | ] 66 | ``` 67 | 68 | The receiver MUST verify the signature before acting on the contents of the wrapped envelope. Multi-signature schemes may also be implemented if necessary. 69 | 70 | In the case of client-server communications, the client already has the server's public key (it had to use it to encrypt the message to the server), and uses that to verify the signature. 71 | 72 | On the other side, the server must learn the client's public key somehow so it can encrypt its responses back to the sender: 73 | 74 | * In the case of Trust on First Use (TOFU), the client's request can include the the sender's public key, and the server can store that key for future use. 75 | * Other more traditional account creation techniques can also be used. 76 | * In the case of peer-to-peer communications, the peers must exchange public keys before communicating. They can do this by first agreeing on a symmetric key using a Diffie-Hellman key exchange, and then using that key to encrypt their public keys to each other. Alternatively they can use a Public Key Infrastructure (PKI) to exchange their public keys. 77 | 78 | ## Requests and Responses 79 | 80 | Once unwrapped, the subject of the inner envelope is either a request (CBOR tag #6.40004) or a response (CBOR tag #6.40005). The tagged value is an ARID (see [BCR-2022-002](bcr-2022-002-arid.md)) that uniquely identifies a request and matches it to its response. 81 | 82 | ``` 83 | request(ARID(abcdef01)) [ 84 | *omitted* 85 | ] 86 | ``` 87 | 88 | ``` 89 | response(ARID(abcdef01)) [ 90 | *omitted* 91 | ] 92 | ``` 93 | 94 | Any party to a request/response may use the ARID as a way of discarding duplicates, avoiding replays, or as input to a cryptographic algorithm. See the [ARID specification](https://github.com/BlockchainCommons/Research/blob/master/papers/bcr-2022-002-ARID-common-identifier.md) for more information. 95 | 96 | A request will have an assertion with its predicate being the known value `'body'`, and the object being an Envelope Expression as defined in [BCR-2023-012](bcr-2023-012-envelope-expression.md). For example, a request to add two numbers might look like this: 97 | 98 | ``` 99 | request(ARID(abcdef01)) [ 100 | 'body': «add» [ 101 | ❰lhs❱: 2 102 | ❰rhs❱: 3 103 | ] 104 | ] 105 | ``` 106 | 107 | The body expression is: 108 | 109 | ``` 110 | «add» [ 111 | ❰lhs❱: 2 112 | ❰rhs❱: 3 113 | ] 114 | ``` 115 | 116 | A successful response will have an assertion with its predicate being the known value `'result'`, and the object being the result of the evaluation of the expression in the request. Following the same example above, a successful response might look like this: 117 | 118 | ``` 119 | response(ARID(abcdef01)) [ 120 | 'result': 5 121 | ] 122 | ``` 123 | 124 | An unsuccessful response will have an assertion with its predicate being the known value `'error'`, and the object being a string containing a human-readable error message. The error message MAY have additional assertions providing diagnostic information. 125 | 126 | ``` 127 | response(ARID(abcdef01)) [ 128 | 'error': "Internal server error" [ 129 | "errorCode": 500 130 | ] 131 | ] 132 | ``` 133 | 134 | In the event that a request is malformed, a generic error may be returned, its `response` tag will contain the known value `'unknown'`, and the response will have an assertion with its predicate being the known value `'error'`, and the object being a string containing a human-readable message. The error message MAY have additional assertions providing diagnostic information. 135 | 136 | This message MAY be signed by the server, but generally will not be encrypted as the sender's public key is not known. 137 | 138 | ``` 139 | response('Unknown') [ 140 | 'error': "Decryption failure" 141 | ] 142 | ``` 143 | 144 | Here is a more realistic example of a signed request from the [Gordian Depository API](bcr-2023-018-depo-api.md). Notice that one of the parameters `❰"key"❱` to the `«"storeShare"»` function is a public key. This is the public key of the sender, and is used by the server to verify the signature, set up an account if necessary using Trust on First Use (TOFU) and encrypt its response back to the client. 145 | 146 | ``` 147 | { 148 | request(ARID(8712dfac)) [ 149 | 'body': «"storeShare"» [ 150 | ❰"data"❱: Bytes(327) 151 | ❰"key"❱: PublicKeys 152 | ] 153 | ] 154 | } [ 155 | 'signed': Signature 156 | ] 157 | ``` 158 | -------------------------------------------------------------------------------- /papers/bcr-2023-015-nonce.md: -------------------------------------------------------------------------------- 1 | # UR Type Definition for Cryptographic Nonce 2 | 3 | ## BCR-2023-015 4 | 5 | **© 2023 Blockchain Commons** 6 | 7 | Authors: Wolf McNally, Christopher Allen
8 | Date: December 9, 2023
9 | Revised: December 9, 2023 10 | 11 | ## Overview 12 | 13 | A `Nonce` is a cryptographically strong random "number used once" and is frequently used in algorithms where a random value is needed that should never be reused. This document defines a fixed-length 12-byte nonces. 14 | 15 | ## CDDL 16 | 17 | ``` 18 | nonce = #6.40014(bytes .size 12) 19 | ``` 20 | -------------------------------------------------------------------------------- /papers/bcr-2023-016-password.md: -------------------------------------------------------------------------------- 1 | # UR Type Definition for Scrypt-Hashed Password 2 | 3 | ## BCR-2023-016 4 | 5 | **© 2023 Blockchain Commons** 6 | 7 | Authors: Wolf McNally, Christopher Allen
8 | Date: December 9, 2023
9 | Revised: December 9, 2023 10 | 11 | ## Overview 12 | 13 | [Scrypt](https://datatracker.ietf.org/doc/html/rfc7914) is a password-based key derivation function that is designed to be computationally intensive and memory-hard. It is designed to make brute-force attacks difficult to perform. This document defines a UR type for storing a password that has been salted and hashed using scrypt. 14 | 15 | `password` is a password that has been salted and hashed using Scrypt, and is therefore suitable for storage and use for authenticating users via password. To validate an entered password, the same hashing algorithm using the same parameters and salt must be performed again, and the hashes compared to determine validity. This way the authenticator never needs to store the password. The processor and memory intensive design of the scrypt algorithm makes such hashes resistant to brute-force attacks. 16 | 17 | ### CDDL 18 | 19 | ``` 20 | password = #6.40015([n, r, p, salt, hashed-password]) 21 | 22 | n = uint ; iterations 23 | r = uint ; block size 24 | p = uint ; parallelism factor 25 | salt = bytes ; random salt (16 bytes recommended) 26 | hashed-password = bytes ; 32 bytes recommended 27 | ``` 28 | -------------------------------------------------------------------------------- /papers/bcr-2023-017-salt.md: -------------------------------------------------------------------------------- 1 | # UR Type Definition for Random Salt 2 | 3 | ## BCR-2023-017 4 | 5 | **© 2023 Blockchain Commons** 6 | 7 | Authors: Wolf McNally, Christopher Allen
8 | Date: December 9, 2023
9 | Revised: December 9, 2023 10 | 11 | ## Overview 12 | 13 | A `salt` is random data frequently used as an additional input to one-way algorithms (e.g., password hashing) where similar inputs (the same password) should not yield the same outputs (the hashed password.) This is known as "decorrelation". Salts are not usually secret. 14 | 15 | ## CDDL 16 | 17 | ``` 18 | salt = #6.40018(bytes) 19 | ``` 20 | -------------------------------------------------------------------------------- /papers/bcr-2023-018-depo-api.md: -------------------------------------------------------------------------------- 1 | # Gordian Depository API 2 | 3 | ## BCR-2023-018 4 | 5 | **© 2023 Blockchain Commons** 6 | 7 | Authors: Wolf McNally, Christopher Allen
8 | Date: December 13, 2023
9 | Revised: December 13, 2023 10 | 11 | ## Overview 12 | 13 | The Gordian Depository API is a protocol for securely and anonymously storing and retrieving data from a remote server. 14 | 15 | **⚠️ Forthcoming:** This document is a work in progress and is not yet complete. 16 | -------------------------------------------------------------------------------- /papers/bcr-2024-002-dcbor.md: -------------------------------------------------------------------------------- 1 | # dCBOR: A Deterministic CBOR Application Profile 2 | 3 | ## BCR-2024-002 4 | 5 | **© 2024 Blockchain Commons** 6 | 7 | Authors: Wolf McNally, Christopher Allen
8 | Date: January 9, 2024 9 | 10 | --- 11 | 12 | This document is a pointer to the [dCBOR IETF Internet Draft](https://datatracker.ietf.org/doc/draft-mcnally-deterministic-cbor/). 13 | 14 | As this specification now has several implementations by third parties and has been extensively discussed in the IETF CBOR working group, we now consider it to be on track to becoming a standard. 15 | 16 | ## Abstract 17 | 18 | The purpose of determinism is to ensure that semantically equivalent data items are encoded into identical byte streams. CBOR (RFC 8949) defines "Deterministically Encoded CBOR" in its Section 4.2, but leaves some important choices up to the application developer. The CBOR Common Deterministic Encoding (CDE) Internet Draft builds on this by specifying a baseline for application profiles that wish to implement deterministic encoding with CBOR. The present document provides an application profile "dCBOR" that can be used to help achieve interoperable deterministic encoding based on CDE for a variety of applications wishing an even narrower and clearly defined set of choices. 19 | -------------------------------------------------------------------------------- /papers/bcr-2024-003-envelope.md: -------------------------------------------------------------------------------- 1 | # The Gordian Envelope Structured Data Format 2 | 3 | ## BCR-2024-003 4 | 5 | **© 2024 Blockchain Commons** 6 | 7 | Authors: Wolf McNally, Christopher Allen
8 | Date: January 9, 2024 9 | 10 | --- 11 | 12 | This document is a pointer to the [Gordian Envelope IETF Internet Draft](https://datatracker.ietf.org/doc/draft-mcnally-envelope/). 13 | 14 | ## Abstract 15 | 16 | Gordian Envelope specifies a structured format for hierarchical binary data focused on the ability to transmit it in a privacy-focused way, offering support for privacy as described in RFC 6973 and human rights as described in RFC 8280. Envelopes are designed to facilitate "smart documents" and have a number of unique features including: easy representation of a variety of semantic structures, a built-in Merkle-like digest tree, deterministic representation using CBOR, and the ability for the holder of a document to selectively elide specific parts of a document without invalidating the digest tree structure. This document specifies the base Envelope format, which is designed to be extensible. 17 | -------------------------------------------------------------------------------- /papers/bcr-2024-008-bytemoji.md: -------------------------------------------------------------------------------- 1 | # Bytemoji: Easy and quick digital object recognition using emojis 2 | 3 | ## BCR-2024-008 4 | 5 | **© 2024 Blockchain Commons** 6 | 7 | Authors: Wolf McNally, Christopher Allen
8 | Date: December 7, 2024 9 | 10 | ### Introduction 11 | 12 | Bytemoji is a curated set of 256 emojis that are chosen to be easily recognized and distinguished from each other, especially when used in combination. Bytemoji are intended to be used as a simple and quick way to visually identify objects in digital systems, for example, by converting a 32-bit hash (e.g., CRC-32 or truncated SHA-256) to its four corresponding Bytemojis. 13 | 14 | Other ways to visually identify digital object include [ByteWords](bcr-2020-012-Bytewords.md), and [LifeHash](http://lifehash.info). Bytemoji combine the value of cryptographic hash visualization with easy display and handling as text. 15 | 16 | Unlike ByteWords, Bytemoji are not intended to "round-trip" data between text and binary format, although this is technically possible. 17 | 18 | ### Example 19 | 20 | Each line below represents a combination of four bytes, represented as Bytemojis. 21 | 22 | 💛 🚩 🐥 🫠
23 | 🧵 💀 🎂 🛟
24 | 💫 🤠 👆 😂
25 | 🪐 👔 👚 👻
26 | 🧸 🥚 🧀 🙀
27 | 👃 👄 🐬 🧄
28 | 🧦 🌽 🏠 🦆
29 | 🌐 🌭 🥺 🛑
30 | 🥁 🦞 🌹 🐢
31 | 😽 😐 🐺 🌀
32 | 33 | #### Clustering 34 | 35 | Although Bytemoji are chosen partly for their visual distinctness, they are not intended to be individually identifiable. Bytemoji should never be displayed in isolation: they should always displayed in clusters of four or more to represent cryptographic hashes. In addition, they should be clustered with other indicators of the digital object's unique identity, such as hex codes, ByteWords, or a LifeHash. 36 | 37 | This clustering ensures sufficient visual distinction and reduces the risk of ambiguity, even if individual emojis may share some similar features. In this example, the Bytemojis, the ByteWords, and the raw hex representation are shown together, under the user's chosen name of the object: 38 | 39 | ``` 40 | **My First Cryptographic Seed** 41 | 42 | 🌊 😹 🌽 🐞 43 | JUGS DELI GIFT WHEN 44 | 71 27 4d f1 45 | ``` 46 | 47 | This mix of modalities further increases the likelihood of accurate recognition and decreases the risk of confusion. It is also useful for accessibility, as it provides multiple ways to present the information via assistive technologies. 48 | 49 | See our previous work on the [Object Identity Block (OIB)](bcr-2021-002-digest.md#object-identity-block) for more information on identifying digital objects. 50 | 51 | ### Selection Criteria 52 | 53 | The byte sequences that encode emojis can become quite long and complex: 54 | 55 | - Some emojis that render as a single glyph use several combining forms. For example, *“I am a witness”* takes 17 UTF-8 bytes! 56 | 57 | 👁️‍🗨️ 58 | 59 | - Some emojis are rendered as sequences of multiple glyphs, for example *"family: man, woman, girl, boy with various skin tones"* takes 28 UTF-8 bytes. Note that this is a *single* emoji! 60 | 61 | 👨🏿‍👩🏾‍👧🏽‍👦🏼 62 | 63 | So to keep things simple while still providing a wide range of visual objects, we selected a set of 256 emojis that: 64 | 65 | - All render as single glyphs. 66 | - All have code points that serialize as 3 or 4 UTF-8 bytes. 67 | 68 | In addition, we used these other selection criteria: 69 | 70 | - All emojis are visually distinct, with maximally unique shapes and designs. 71 | - All emojis must render on a wide range of platforms. 72 | - Avoid emojis that are highly similar or could be easily confused. 73 | - Avoid emojis that depend solely on color differences to be distinguished. 74 | - Prefer emojis that read well at smaller sizes. 75 | - Ensure that contrast is good when displayed on light or dark backgrounds. 76 | - Exclude combining forms, skin tone modifiers, and gender modifiers. 77 | - Ensure the set covers a wide range of themes and concepts. 78 | - Prefer emojis with positive or neutral connotations. 79 | - Avoid national, ideological, and controversial symbols. 80 | 81 | ### Bytemoji Table 82 | 83 | | | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F | 84 | |---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---| 85 | | 0 | 😀 | 😂 | 😆 | 😉 | 🙄 | 😋 | 😎 | 😍 | 😘 | 😭 | 🫠 | 🥱 | 🤩 | 😶 | 🤨 | 🫥 | 86 | | 1 | 🥵 | 🥶 | 😳 | 🤪 | 😵 | 😡 | 🤢 | 😇 | 🤠 | 🤡 | 🥳 | 🥺 | 😬 | 🤑 | 🙃 | 🤯 | 87 | | 2 | 😈 | 👹 | 👺 | 💀 | 👻 | 👽 | 😺 | 😹 | 😻 | 😽 | 🙀 | 😿 | 🫶 | 🤲 | 🙌 | 🤝 | 88 | | 3 | 👍 | 👎 | 👈 | 👆 | 💪 | 👄 | 🦷 | 👂 | 👃 | 🧠 | 👀 | 🤚 | 🦶 | 🍎 | 🍊 | 🍋 | 89 | | 4 | 🍌 | 🍉 | 🍇 | 🍓 | 🫐 | 🍒 | 🍑 | 🍍 | 🥝 | 🍆 | 🥑 | 🥦 | 🍅 | 🌽 | 🥕 | 🫒 | 90 | | 5 | 🧄 | 🥐 | 🥯 | 🍞 | 🧀 | 🥚 | 🍗 | 🌭 | 🍔 | 🍟 | 🍕 | 🌮 | 🥙 | 🍱 | 🍜 | 🍤 | 91 | | 6 | 🍚 | 🥠 | 🍨 | 🍦 | 🎂 | 🪴 | 🌵 | 🌱 | 💐 | 🍁 | 🍄 | 🌹 | 🌺 | 🌼 | 🌻 | 🌸 | 92 | | 7 | 💨 | 🌊 | 💧 | 💦 | 🌀 | 🌈 | 🌞 | 🌝 | 🌛 | 🌜 | 🌙 | 🌎 | 💫 | ⭐ | 🪐 | 🌐 | 93 | | 8 | 💛 | 💔 | 💘 | 💖 | 💕 | 🏁 | 🚩 | 💬 | 💯 | 🚫 | 🔴 | 🔷 | 🟩 | 🛑 | 🔺 | 🚗 | 94 | | 9 | 🚑 | 🚒 | 🚜 | 🛵 | 🚨 | 🚀 | 🚁 | 🛟 | 🚦 | 🏰 | 🎡 | 🎢 | 🎠 | 🏠 | 🔔 | 🔑 | 95 | | A | 🚪 | 🪑 | 🎈 | 💌 | 📦 | 📫 | 📖 | 📚 | 📌 | 🧮 | 🔒 | 💎 | 📷 | ⏰ | ⏳ | 📡 | 96 | | B | 💡 | 💰 | 🧲 | 🧸 | 🎁 | 🎀 | 🎉 | 🪭 | 👑 | 🫖 | 🔭 | 🛁 | 🏆 | 🥁 | 🎷 | 🎺 | 97 | | C | 🏀 | 🏈 | 🎾 | 🏓 | ✨ | 🔥 | 💥 | 👕 | 👚 | 👖 | 🩳 | 👗 | 👔 | 🧢 | 👓 | 🧶 | 98 | | D | 🧵 | 💍 | 👠 | 👟 | 🧦 | 🧤 | 👒 | 👜 | 🐱 | 🐶 | 🐭 | 🐹 | 🐰 | 🦊 | 🐻 | 🐼 | 99 | | E | 🐨 | 🐯 | 🦁 | 🐮 | 🐷 | 🐸 | 🐵 | 🐔 | 🐥 | 🦆 | 🦉 | 🐴 | 🦄 | 🐝 | 🐛 | 🦋 | 100 | | F | 🐌 | 🐞 | 🐢 | 🐺 | 🐍 | 🪽 | 🐙 | 🦑 | 🪼 | 🦞 | 🦀 | 🐚 | 🦭 | 🐟 | 🐬 | 🐳 | 101 | 102 | ### Reference Implementation 103 | 104 | The current reference implementation is in the `bc-ur` Rust crate. The `bc-ur` crate is available on [crates.io](https://crates.io/crates/bc-ur) and [GitHub](https://github.com/blockchaincommons/bc-ur-rust/). 105 | 106 | ### Reference String 107 | 108 | The following line contains all 256 Bytemojis in order, which may be used for testing and in further implementations: 109 | 110 | ``` 111 | 😀😂😆😉🙄😋😎😍😘😭🫠🥱🤩😶🤨🫥🥵🥶😳🤪😵😡🤢😇🤠🤡🥳🥺😬🤑🙃🤯😈👹👺💀👻👽😺😹😻😽🙀😿🫶🤲🙌🤝👍👎👈👆💪👄🦷👂👃🧠👀🤚🦶🍎🍊🍋🍌🍉🍇🍓🫐🍒🍑🍍🥝🍆🥑🥦🍅🌽🥕🫒🧄🥐🥯🍞🧀🥚🍗🌭🍔🍟🍕🌮🥙🍱🍜🍤🍚🥠🍨🍦🎂🪴🌵🌱💐🍁🍄🌹🌺🌼🌻🌸💨🌊💧💦🌀🌈🌞🌝🌛🌜🌙🌎💫⭐🪐🌐💛💔💘💖💕🏁🚩💬💯🚫🔴🔷🟩🛑🔺🚗🚑🚒🚜🛵🚨🚀🚁🛟🚦🏰🎡🎢🎠🏠🔔🔑🚪🪑🎈💌📦📫📖📚📌🧮🔒💎📷⏰⏳📡💡💰🧲🧸🎁🎀🎉🪭👑🫖🔭🛁🏆🥁🎷🎺🏀🏈🎾🏓✨🔥💥👕👚👖🩳👗👔🧢👓🧶🧵💍👠👟🧦🧤👒👜🐱🐶🐭🐹🐰🦊🐻🐼🐨🐯🦁🐮🐷🐸🐵🐔🐥🦆🦉🐴🦄🐝🐛🦋🐌🐞🐢🐺🐍🪽🐙🦑🪼🦞🦀🐚🦭🐟🐬🐳 112 | ``` 113 | 114 | ### Note on Emoji Rendering 115 | 116 | The rendering of emojis can vary significantly between platforms. The Bytemoji set was chosen to be as platform-independent as possible and the entire set should be universally supported where emojis are supported, but some variation in appearance is to be expected. 117 | -------------------------------------------------------------------------------- /papers/bcr-2024-009-signature-metadata.md: -------------------------------------------------------------------------------- 1 | # Signatures with Metadata in Gordian Envelope 2 | 3 | ## BCR-2024-009 4 | 5 | **© 2024 Blockchain Commons** 6 | 7 | Authors: Wolf McNally, Christopher Allen
8 | Date: December 7, 2024 9 | 10 | ### Introduction 11 | 12 | In this document, we extend that concept to include metadata in the signature. This allows the signer to include additional information about the signed subject, such as the signer's identity, the date of the signature, and the purpose of the signature. 13 | 14 | ### Signing the Envelope Subject 15 | 16 | In [BCR-2023-013](bcr-2023-013-envelope-crypto.md), we explained how to digitally sign the subject of a [Gordian Envelope](bcr-2024-003-envelope.md). 17 | 18 | This involves signing the hash of the subject envelope, then adding an assertion to it, like this: 19 | 20 | ``` 21 | "Subject" [ 22 | 'signed': Signature 23 | ] 24 | ``` 25 | 26 | It's important to note that if the subject has assertions that also need signing: 27 | 28 | ``` 29 | "Subject" [ 30 | "assertion1": "value1" 31 | "assertion2": "value2" 32 | ] 33 | ``` 34 | 35 | Then adding a signature assertion to the subject envelope is not sufficient, because the subject *only* is signed. 36 | 37 | ``` 38 | "Subject" [ // This is signed 39 | "assertion1": "value1" // This is not signed 40 | "assertion2": "value2" // This is not signed 41 | 'signed': Signature 42 | ] 43 | ``` 44 | 45 | To cover the other assertions, the entire envelope must be signed by wrapping it first, making the entire envelope, including its assertions, the subject: 46 | 47 | ``` 48 | { 49 | "Subject" [ 50 | "assertion1": "value1" 51 | "assertion2": "value2" 52 | ] 53 | } [ 54 | 'signed': Signature 55 | ] 56 | ``` 57 | 58 | ### Signature Metadata 59 | 60 | Now that we can sign a payload envelope, the question arises as to where to put additional metadata about the signature, such as the signer's identity, the date of the signature, and the purpose of the signature. 61 | 62 | We could add these to the payload envelope as assertions before we wrap it to be signed: 63 | 64 | ``` 65 | { 66 | "Subject" [ 67 | "assertion1": "value1" 68 | "assertion2": "value2" 69 | "signer": "Alice" 70 | "date": 2024-12-07 71 | "purpose": "Proof of Identity" 72 | ] 73 | } [ 74 | 'signed': Signature 75 | ] 76 | ``` 77 | 78 | But this would violate a preferred separation of concerns where the payload envelope is only about the payload, and the signature metadata is separate. Failing to separate these concerns becomes critical when an envelope may have multiple signatures, each with its own metadata. 79 | 80 | Alternatively, we could add our metadata after signing the envelope: 81 | 82 | ``` 83 | { 84 | "Subject" [ 85 | "assertion1": "value1" 86 | "assertion2": "value2" 87 | ] 88 | } [ 89 | 'signed': Signature 90 | "signer": "Alice" 91 | "date": 2024-12-07 92 | "purpose": "Proof of Identity" 93 | ] 94 | ``` 95 | 96 | But then we're back to having assertions that are not signed, leaving them *mutable*. This is a problem because the metadata could be changed after the signature is applied, leaving the signature valid, but the metadata incorrect. 97 | 98 | ### Signature with Metadata 99 | 100 | To solve this, we introduce a standard for adding signatures with metadata. This solution leverages the recursive nature of Gordian Envelope to create a signature envelope that includes the metadata, and then signs *that* envelope with the same private key used to sign the payload. 101 | 102 | ### Step 1 103 | 104 | Wrap the payload envelope and produce a `Signature` object as usual, but don't yet add it as an assertion: 105 | 106 | ``` 107 | { 108 | "Subject" [ 109 | "assertion1": "value1" 110 | "assertion2": "value2" 111 | ] 112 | } 113 | ``` 114 | 115 | ``` 116 | Signature 117 | ``` 118 | 119 | ### Step 2 120 | 121 | Create an envelope with the payload `Signature` as its subject, and add the metadata as assertions on this subject: 122 | 123 | ``` 124 | Signature [ 125 | "signer": "Alice" 126 | "date": 2024-12-07 127 | "purpose": "Proof of Identity" 128 | ] 129 | ``` 130 | 131 | ### Step 3 132 | 133 | Wrap this signature metadata envelope and then sign *it* with the *same* private key used to sign the payload: 134 | 135 | ``` 136 | { 137 | Signature [ 138 | "signer": "Alice" 139 | "date": 2024-12-07 140 | "purpose": "Proof of Identity" 141 | ] 142 | } [ 143 | 'signed': Signature 144 | ] 145 | ``` 146 | 147 | ### Step 4: 148 | 149 | Use this signed signature metadata envelope as the object of the `'signed'` assertion on the wrapped payload envelope, in the same position as a `Signature` object that includes no metadata: 150 | 151 | ``` 152 | { 153 | "Subject" [ 154 | "assertion1": "value1" 155 | "assertion2": "value2" 156 | ] 157 | } [ 158 | 'signed': { 159 | Signature [ 160 | "signer": "Alice" 161 | "date": 2024-12-07 162 | "purpose": "Proof of Identity" 163 | ] 164 | } [ 165 | 'signed': Signature 166 | ] 167 | ] 168 | ``` 169 | 170 | Signing the metadata and the payload signature with the same private key that signed the payload ensures that the metadata is immutable with the same level of security as the payload itself. 171 | 172 | ## Verification 173 | 174 | To verify the signature, the verifier MUST verify both signatures against the sender's public key. The outer signature verifies the metadata envelope, and the inner signature verifies the payload envelope. Both signatures MUST be valid against the same public key for the overall signature to be considered valid. In addition, the outer signature MUST be the only assertion on the signature metadata envelope, and MUST NOT have additional assertions itself. (Note that the metadata assertions themselves may be arbirarily complex.) 175 | 176 | The basic Envelope API for verifying signatures does not need to change at all: whether or not a signature carries metadata is transparent to the verifier who does not need the metadata. 177 | 178 | Th extended Envelope API for verifying signatures provides affordances for verifying the envelope and returning the metadata, if desired. This metadata is returned as the `Signature` with metadata envelope, which may be inspected further: 179 | 180 | ``` 181 | Signature [ 182 | "signer": "Alice" 183 | "date": 2024-12-07 184 | "purpose": "Proof of Identity" 185 | ] 186 | ``` 187 | 188 | ## Multiple Signatures 189 | 190 | Because of the cleanly separated concerns, it is easy to add multiple signatures with metadata to an envelope. Each signature with metadata stands alone, and the payload envelope is signed by each of them. 191 | 192 | ### Without Metadata 193 | 194 | ``` 195 | { 196 | "Subject" [ 197 | "assertion1": "value1" 198 | "assertion2": "value2" 199 | ] 200 | } [ 201 | 'signed': Signature 202 | 'signed': Signature 203 | ] 204 | ``` 205 | 206 | ### With Metadata 207 | 208 | ``` 209 | { 210 | "Subject" [ 211 | "assertion1": "value1" 212 | "assertion2": "value2" 213 | ] 214 | } [ 215 | 'signed': { 216 | Signature [ 217 | "signer": "Alice" 218 | "date": 2024-12-07 219 | "purpose": "Proof of Identity" 220 | ] 221 | } [ 222 | 'signed': Signature 223 | ] 224 | 'signed': { 225 | Signature [ 226 | "signer": "Bob" 227 | "date": 2024-12-08 228 | "purpose": "Witness" 229 | ] 230 | } [ 231 | 'signed': Signature 232 | ] 233 | ] 234 | ``` 235 | 236 | ## Reference Implementation 237 | 238 | The reference implementation for signatures with metadata is in the [`bc-envelope` Rust crate](https://crates.io/crates/bc-envelope), or on GitHub at [BlockchainCommons/bc-envelope-rust](https://github.com/blockchaincommons/bc-envelope-rust/). 239 | 240 | The basic signing and verification API remains unchanged, while the extended signing API provides affordances for working with the metadata. 241 | 242 | The unit tests in the reference implementation demonstrate how to sign with metadata, and verify signatures returning metadata if any. 243 | 244 | ## Future Work 245 | 246 | This paper lays out the format for adding metadata to signatures in Gordian Envelopes. However, the metadata examples given in this paper are intended to be illustrative, not normative. While there is no intent to limit what developers may add as metadata using this technique, future work will include developing standards for interoperable metadata, including dates, signer identity, and signing purpose. 247 | -------------------------------------------------------------------------------- /papers/bcr-2024-010/lifehash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockchainCommons/Research/f48872e3f858e9b86957f16f39149f3e1c47b24f/papers/bcr-2024-010/lifehash.png -------------------------------------------------------------------------------- /papers/bcr-2024-011-reference.md: -------------------------------------------------------------------------------- 1 | # Digital Object References 2 | 3 | ## BCR-2024-011 4 | 5 | **© 2024 Blockchain Commons** 6 | 7 | Authors: Wolf McNally, Christopher Allen
8 | Date: December 22, 2024 9 | 10 | ### Introduction 11 | 12 | Many objects have some form of globally unique identifier that takes the form of a 32-byte (256 bit) value. Sometimes it is desirable to refer to an object by such an identifier. 13 | 14 | Any globally unique object or identifier can be converted to a 32-byte identifier by, for example, taking its SHA-256 digest. This can work with 16-byte (128 bit) UUIDs, or tagged CBOR serializations of globally unique objects like public keys. 15 | 16 | This document introduces a new CBOR tag, `#6.40025`, for representing globally unique references, simply called `Reference` herein. `Reference`s are used to indicate a globally unique object (the "referent"). 17 | 18 | For each type for which a `Reference` can be provied, the the object type documentation must publish a way to generate a globally unique identifier for it. 19 | 20 | ### Example: XIDs 21 | 22 | A [XID](bcr-2024-010-xid.md) is a 32-byte identifier created by hashing the tagged CBOR encoding of a `SigningPublicKey`. The CBOR representation of a BIP-340 Schnorr `SigningPublicKey` in CBOR diagnostic notation would be: 23 | 24 | ``` 25 | 40022( 26 | h'e8251dc3a17e0f2c07865ed191139ecbcddcbdd070ec1ff65df5148c7ef4005a' 27 | ) 28 | ``` 29 | 30 | Serialized to hex: 31 | 32 | ``` 33 | d9 9c56 # tag(40022) signing-public-key 34 | 5820 # bytes(32) 35 | e8251dc3a17e0f2c07865ed191139ecbcddcbdd070ec1ff65df5148c7ef4005a 36 | 37 | => 38 | 39 | d99c565820e8251dc3a17e0f2c07865ed191139ecbcddcbdd070ec1ff65df5148c7ef4005a 40 | ``` 41 | 42 | Taking the SHA-256 hash this encoding gives a globally unique identifier for this `PublicSigningKey`: 43 | 44 | ``` 45 | d40e0602674df1b732f5e025d04c45f2e74ed1652c5ae1740f6a5502dbbdcd47 46 | ``` 47 | 48 | When wrapped in the CBOR tag for XIDs, `#6.40024`, this becomes a `XID`: 49 | 50 | ``` 51 | 40024( 52 | h'd40e0602674df1b732f5e025d04c45f2e74ed1652c5ae1740f6a5502dbbdcd47' 53 | ) 54 | ``` 55 | 56 | This XID can in turn be the subject of a Gordian Envelope that contains much more information: the XID document. XID documents can be quite long and may be retrieved using the XID itself as a key. 57 | 58 | In the case of XIDs, the hashed CBOR encoding of a specific `PublicSigningKey` (the "inception key") is used as the `Reference` for the `XID` object, so this would be wrapped in the `Reference` tag: 59 | 60 | ``` 61 | 40025( 62 | h'd40e0602674df1b732f5e025d04c45f2e74ed1652c5ae1740f6a5502dbbdcd47' 63 | ) 64 | ``` 65 | 66 | Note that references do not include the type of object they refer to: they are used in contexts where the reference can be resolved to the full object, which could be done locally within a document, or globally by looking up the reference in a registry or index. 67 | 68 | ## User-Facing Description 69 | 70 | The first four bytes of a `Reference`'s data are in most cases sufficiently unique for humans to identify the object referred to. For an object of a known type, like a XID, this can be displayed as a human-readable prefix: 71 | 72 | ``` 73 | XID(d40e0602) 74 | ``` 75 | 76 | while a `Reference` to that same XID would be displayed as: 77 | 78 | ``` 79 | Reference(d40e0602) 80 | ``` 81 | 82 | These four bytes can also be translated to [ByteWords](bcr-2020-012-bytewords.md) or [Bytemojis](bcr-2024-008-bytemoji.md) for a more human-friendly representation: 83 | 84 | ``` 85 | Reference(d40e0602) 86 | TINY BETA ATOM ALSO 87 | 🧦 🤨 😎 😆 88 | ``` 89 | 90 | Similarly, if the display form of a `PublicKeys` is: 91 | 92 | ``` 93 | PublicKeys(c9ede672) 94 | ``` 95 | 96 | then a `Reference` to that `PublicKeys` would be: 97 | 98 | ``` 99 | Reference(c9ede672) 100 | ``` 101 | 102 | This correspondence between the identifier of object instances and references to them is machine-comparable (all 32 bytes are compared), and their shortened forms can be useful for end-user identification, debugging, and other contexts where human-readable identifiers are desired. 103 | 104 | ## UR Types and CBOR Tags 105 | 106 | This document defines the following UR types along with their corresponding CBOR tags: 107 | 108 | | UR type | CBOR Tag | 109 | | :----------- | :------- | 110 | | ur:reference | #6.40025 | 111 | 112 | ## IANA Considerations 113 | 114 | This document requests the assignment of a new CBOR tag for References: #6.40025. 115 | -------------------------------------------------------------------------------- /papers/bcr-2025-001/hash-chain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockchainCommons/Research/f48872e3f858e9b86957f16f39149f3e1c47b24f/papers/bcr-2025-001/hash-chain.png -------------------------------------------------------------------------------- /papers/bcr-2025-001/lifehash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockchainCommons/Research/f48872e3f858e9b86957f16f39149f3e1c47b24f/papers/bcr-2025-001/lifehash.png -------------------------------------------------------------------------------- /papers/bcr-2025-001/link-qr-code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockchainCommons/Research/f48872e3f858e9b86957f16f39149f3e1c47b24f/papers/bcr-2025-001/link-qr-code.png -------------------------------------------------------------------------------- /papers/bcr-2025-001/provenance-mark-symbol-white.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /papers/bcr-2025-001/ur-qr-code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockchainCommons/Research/f48872e3f858e9b86957f16f39149f3e1c47b24f/papers/bcr-2025-001/ur-qr-code.png -------------------------------------------------------------------------------- /papers/bcr-2025-002-negative-zero.md: -------------------------------------------------------------------------------- 1 | # Negative Zero: An Unstable Phantom Across System Boundaries 2 | 3 | ## BCR-2025-002 4 | 5 | **© 2025 Blockchain Commons** 6 | 7 | Author: Wolf McNally\ 8 | Date: April 25, 2024 9 | 10 | ## Introduction 11 | 12 | IEEE-754 floating point computations allow for the result *negative zero*, `-0.0`. In these environments, the expression `-1 / Infinity` typically results in negative zero. 13 | 14 | However, all these environments treat zero and negative zero as identical for the purposes of numeric comparison, i.e., `0.0 == -0.0`. The value of negative zero is therefore an artifact of no common use (similar to IEEE-754 NaN payloads). If you’re a numerical purist, please refer to Endnote 1. 15 | 16 | dCBOR abstracts away the value `-0.0` in numeric reduction, serializing it as `0x00`. Some have proposed that this is inconsistent behavior. In fact, the opposite is true: allowing `-0.0` to survive encoding across the serialization and language barriers I describe below is what *breaks* consistency. As I’ll show below, treating all forms of zero as `0` is the only path to deterministic, interoperable numeric representations. 17 | 18 | An existence proof for my argument would be to find common systems that: 19 | 20 | - Do not have a concept of “negative zero” or always treat zero as uniquely *unsigned*, 21 | - May produce negative zero internally, but normalize it in such a way that code cannot recover it, 22 | - Treat negative zero *inconsistently* so that its behavior cannot be relied upon as deterministic. 23 | 24 | Below is the result of my survey. It confirms that systems that do *not* normalize `-0.0` to `0` may break determinism in applications that require it. 25 | 26 | Many common languages like C, C++, Rust, Java, Go, etc. are IEEE-754 environments, and all provide a way to detect the sign bit. When formatting and printing floating point values as text, they may not all format `-0.0` as negative by default. So even though they may exhibit inconsistent *display* behavior, they still provide a clear internal distinction between zero and negative zero. As such, I won’t be dealing with them further here. 27 | 28 | ## JavaScript/JSON interoperability 29 | 30 | While JavaScript can *produce* `-0`, and `JSON.parse()` will *decode* `-0`, `JSON.stringify()` will not *encode* `-0`. This is inconsistent behavior, and cannot be relied upon for deterministic behavior unless extra steps are taken. 31 | 32 | This silent flattening by `JSON.stringify()`—combined with JavaScript’s internal ability to produce `-0`—means `-0` is an unstable phantom: visible in memory, erased on the wire. No application depending on it can behave predictably across serialization boundaries. 33 | 34 | ``` 35 | : -1 / Infinity 36 | -0 37 | 38 | : JSON.parse("-0.0"); 39 | -0 40 | 41 | : JSON.stringify(-1 / Infinity) 42 | '0' 43 | 44 | : JSON.stringify(0.0); 45 | '0' 46 | 47 | : JSON.stringify(-0.0); 48 | '0' 49 | 50 | : JSON.parse(JSON.stringify(-1 / Infinity)); 51 | 0 52 | 53 | : JSON.parse(JSON.stringify(-0.0)) 54 | 0 55 | ``` 56 | 57 | ## Mathematica 58 | 59 | Mathematica treats zero as a unique, unsigned value. 60 | 61 | ``` 62 | In[1]:= -1 / Infinity 63 | Out[1]= 0 64 | 65 | In[2]:= -0.0 66 | Out[2]= 0. 67 | 68 | In[3]:= N[-0.0] 69 | Out[3]= 0. 70 | 71 | In[4]:= Sign[-0.0] 72 | Out[4]= 0 73 | 74 | In[5]:= Sign[0.0] 75 | Out[5]= 0 76 | 77 | In[6]:= Sign[-1.0] 78 | Out[6]= -1 79 | 80 | In[7]:= Sign[-1/Infinity] 81 | Out[7]= 0 82 | 83 | In[8]:= Sign[N[-0.0]] 84 | Out[8]= 0 85 | ``` 86 | 87 | ## MATLAB/Octave 88 | 89 | MATLAB and Octave (an open source MATLAB-like environment) use IEEE-754 internally, but normalize all presentations of zero *except hex* to present as unsigned. So the environment *hides* the sign bit of negative zero, requiring a *backdoor* way such as bit manipulation to distinguish between the negative and positive zeros. Nonetheless, as these two representations of zero have different binary values, they break determinism. 90 | 91 | ``` 92 | x = -1 / Inf; 93 | disp(x); 94 | 0 95 | disp(sign(x)); 96 | 0 97 | format hex 98 | disp(x); 99 | 8000000000000000 100 | u = typecast(x, 'uint64'); 101 | signBit = bitget(u, 64); 102 | format default 103 | disp(signBit); 104 | 1 105 | ``` 106 | 107 | ## R 108 | 109 | Like Mathematica, R treats zero as a unique, unsigned value. 110 | 111 | ``` 112 | x <- -1 / Inf 113 | print(x) # 0 114 | print(identical(x, -0.0)) # TRUE 115 | print(identical(x, 0.0)) # TRUE 116 | print(sign(x)) # 0 117 | print(identical(0.0, -0.0)) # TRUE 118 | ``` 119 | 120 | ## SQL 121 | 122 | All implementations of SQL, even if they use IEEE-754 internally, normalize negative zero to zero: 123 | 124 | ``` 125 | MariaDB [(none)]> SELECT 0.0, SIGN(0.0), -0.0, SIGN(-0.0); 126 | +-----+-----------+------+------------+ 127 | | 0.0 | SIGN(0.0) | -0.0 | SIGN(-0.0) | 128 | +-----+-----------+------+------------+ 129 | | 0.0 | 0 | 0.0 | 0 | 130 | +-----+-----------+------+------------+ 131 | 1 row in set (0.000 sec) 132 | ``` 133 | 134 | ## Conclusion 135 | 136 | The only form of zero that survives cleanly across serialization, inter-language calls, and memory models is `0`. Any system that permits `-0.0` to be encoded introduces a trapdoor of non-determinism. 137 | 138 | Therefore, dCBOR is correct to normalize `-0.0` to `0x00`: Determinism demands it. 139 | 140 | ## Endnote 1 141 | 142 | While the sign bit in the IEEE-754 floating-point representation of zero can technically encode information potentially useful in certain niche numerical analysis contexts (e.g., indicating limit directionality or handling branch cuts in complex functions), its practical necessity and consistent implementation across diverse systems are questionable. Notably, highly sophisticated mathematical environments such as Mathematica and R, designed for complex computations, deliberately treat zero as a unique, unsigned value, lacking any concept of negative zero. Their ability to perform advanced mathematics without preserving or relying on a distinct `-0.0` strongly suggests that this artifact is neither universally required nor fundamental, even in demanding computational fields. Furthermore, as demonstrated in the main text, the handling of `-0.0` is inconsistent across system boundaries, particularly during serialization (e.g., `JSON.stringify()` behavior). Attempting to maintain the `-0.0` distinction in a generalized, interoperable format thus introduces a fragile dependency and a clear risk of non-determinism. Consequently, for robust formats like dCBOR that prioritize deterministic and canonical representations essential for interoperability and verification, normalizing `-0.0` to the single, unambiguous value of `0` is the necessary approach to ensure predictable behavior and avoid reliance on this non-universally supported and inconsistently handled artifact. 143 | 144 | --- 145 | 146 | I am the author of this paper. Thoughts? 147 | -------------------------------------------------------------------------------- /papers/bcr-2025-003-post-quantum.md: -------------------------------------------------------------------------------- 1 | # UR Type Definition for Post-Quantum Cryptographic Structures 2 | 3 | ## BCR-2025-003 4 | 5 | **© 2025 Blockchain Commons** 6 | 7 | Author: Wolf McNally\ 8 | Date: April 25, 2025 9 | 10 | ## Introduction 11 | 12 | This document defines a set of CBOR tags and [Uniform Resource (UR) types](./bcr-2020-005-ur.md) for post-quantum cryptographic structures implementing ML-KEM and ML-DSA. These tags and types are intended to be used in conjunction with the Concise Binary Object Representation (CBOR) format, which is a data serialization format designed for small code size and small message size. 13 | 14 | ## About ML-KEM and ML-DSA 15 | 16 | ML‑KEM (“Module‑Lattice Key‑Encapsulation Mechanism”) and ML‑DSA (“Module‑Lattice Digital Signature Algorithm”) are NIST’s post‑quantum standards for key exchange and signatures. Both descend from the CRYSTALS competition winners—Kyber and Dilithium respectively—but they are *not drop‑in replacements* for those schemes. 17 | 18 | ## UR Types and CBOR Tags 19 | 20 | This document defines the following [UR types](./bcr-2020-006-urtypes.md) along with their corresponding CBOR tags, which have been assigned in the [IANA Concise Binary Object Representation (CBOR) Tags registry](https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml). 21 | 22 | | UR type | CBOR Tag | 23 | | :--------------------- | :--------- | 24 | | `ur:mlkem-private-key` | `#6.40100` | 25 | | `ur:mlkem-public-key` | `#6.40101` | 26 | | `ur:mlkem-ciphertext` | `#6.40102` | 27 | | `ur:mldsa-private-key` | `#6.40103` | 28 | | `ur:mldsa-public-key` | `#6.40104` | 29 | | `ur:mldsa-signature` | `#6.40105` | 30 | 31 | ## CDDL Definitions 32 | 33 | This section provides the [CDDL](https://datatracker.ietf.org/doc/html/rfc8610) definitions for the CBOR tags defined above. 34 | 35 | Our reference for the key sizes and other parameters is the [`pqcrypto-mlkem`](https://crates.io/crates/pqcrypto-mlkem) and [`pqcrypto-mldsa`](https://crates.io/crates/pqcrypto-mldsa) crates, which are part of the [PQClean](https://github.com/pqclean/pqclean/) project. 36 | 37 | Our general architecture is for the CBOR tag to identify the type of object, and then the first element of the tuple to identify the level of security. The second element of the tuple is a binary string of a fixed size, which contains the actual key, ciphertext, or signature. 38 | 39 | The [bc-components](https://crates.io/crates/bc-components) crate contains reference implementations of these schemas. 40 | 41 | ```cddl 42 | mlkem-level = 512 / 768 / 1024 43 | 44 | mlkem-tuple<$L, $S> = ( 45 | $L .within mlkem-level, 46 | bstr .size $S 47 | ) 48 | 49 | mlkem-private-key = #6.40100([ 50 | mlkem-tuple<512, 1632> // 51 | mlkem-tuple<768, 2400> // 52 | mlkem-tuple<1024, 3168> 53 | ]) 54 | 55 | mlkem-public-key = #6.40101([ 56 | mlkem-tuple<512, 800> // 57 | mlkem-tuple<768, 1184> // 58 | mlkem-tuple<1024, 1568> 59 | ]) 60 | 61 | mlkem-ciphertext = #6.40102([ 62 | mlkem-tuple<512, 768> // 63 | mlkem-tuple<768, 1088> // 64 | mlkem-tuple<1024, 1568> 65 | ]) 66 | 67 | mldsa-level = 2 / 3 / 5 68 | 69 | mldsa-tuple<$L, $S> = ( 70 | $L .within mldsa-level, 71 | bstr .size $S 72 | ) 73 | 74 | mldsa-private-key = #6.40103([ 75 | mldsa-tuple<2, 2560> // 76 | mldsa-tuple<3, 4032> // 77 | mldsa-tuple<5, 4896> 78 | ]) 79 | 80 | mldsa-public-key = #6.40104([ 81 | mldsa-tuple<2, 1312> // 82 | mldsa-tuple<3, 1952> // 83 | mldsa-tuple<5, 2592> 84 | ]) 85 | 86 | mldsa-signature = #6.40105([ 87 | mldsa-tuple<2, 2420> // 88 | mldsa-tuple<3, 3309> // 89 | mldsa-tuple<5, 4627> 90 | ]) 91 | ``` 92 | -------------------------------------------------------------------------------- /papers/bcr-2025-004-permit.md: -------------------------------------------------------------------------------- 1 | # Permits in Gordian Envelope 2 | 3 | ## BCR-2025-004 4 | 5 | **© 2025 Blockchain Commons** 6 | 7 | Authors: Wolf McNally\ 8 | Date: May 13, 2025 9 | 10 | ## Introduction 11 | 12 | Gordian Envelope supports both symmetric and public key encryption. More generally, it bases its public key encryption system on its symmetric encryption system. This is quite a flexible architecture, because by encrypting a single symmetric key multiple ways, you can create envelopes that can be transmitted securely, then: 13 | 14 | - Opened by multiple parties, 15 | - Encrypted using strong passwords, 16 | - "Sharded" into a number of pieces for social key recovery 17 | 18 | In fact, you can use any of these "permits" in any combination on the same envelope. This document describes the permit system in detail. 19 | 20 | ## Walkthrough 21 | 22 | This example shows how to create a Gordian Envelope, encrypt it, and then assign multiple permits to it. 23 | 24 | ### Composing the Payload Envelope 25 | 26 | Alice composes a poem: 27 | 28 | ```rust 29 | let poem_text = "At midnight, the clocks sang lullabies to the wandering teacups."; 30 | ``` 31 | 32 | She creates a new envelope and assigns the text as the envelope's subject. She also adds some metadata assertions to the envelope, including that the subject of the envelope is a poem, its title, the (pseudonymous) author, and the date. 33 | 34 | ```rust 35 | use bc_envelope::prelude::*; 36 | 37 | let original_envelope = Envelope::new(poem_text) 38 | .add_type("poem") 39 | .add_assertion("title", "A Song of Ice Cream") 40 | .add_assertion("author", "Plonkus the Iridescent") 41 | .add_assertion(known_values::DATE, Date::from_ymd(2025, 5, 15)); 42 | ``` 43 | 44 | Right now, if `original_envelope` were printed using `format()`, it would look like this, with the subject being the poem text, and four assertions on it: 45 | 46 | ``` 47 | "At midnight, the clocks sang lullabies to the wandering teacups." [ 48 | 'isA': "poem" 49 | "author": "Plonkus the Iridescent" 50 | "title": "A Song of Ice Cream" 51 | 'date': 2025-05-15 52 | ] 53 | ``` 54 | 55 | Alice signs the envelope with her private key by generating a keypair, and then using the `sign()` method with her private key. The `sign()` method wraps the envelope so the subject and all its assertions are signed, and adds a `'signed'` assertion to the wrapped envelope: 56 | 57 | ```rust 58 | let (alice_private_keys, alice_public_keys) = keypair(); 59 | let signed_envelope = original_envelope.sign(&alice_private_keys); 60 | ``` 61 | 62 | The `format()` method will now show the wrapped and signed envelope: 63 | 64 | ``` 65 | { 66 | "At midnight, the clocks sang lullabies to the wandering teacups." [ 67 | 'isA': "poem" 68 | "author": "Plonkus the Iridescent" 69 | "title": "A Song of Ice Cream" 70 | 'date': 2025-05-15 71 | ] 72 | } [ 73 | 'signed': Signature 74 | ] 75 | ``` 76 | 77 | ### Symmetric Encryption with a Content Key 78 | 79 | Alice picks a random symmetric "content key" and uses it to encrypt the signed envelope. Even though the content key is not saved in the envelope in its unencrypted form, it is still considered a *permit* because it can be used to decrypt the envelope. 80 | 81 | ```rust 82 | let content_key = SymmetricKey::new(); 83 | let encrypted_envelope = signed_envelope.encrypt(&content_key); 84 | ``` 85 | 86 | When printed, the encrypted envelope looks very... cryptic: 87 | 88 | ``` 89 | ENCRYPTED 90 | ``` 91 | 92 | Alice will provide several different methods ("permits") that can be used to unlock it. Each permit encrypts the same content key using a different method. 93 | 94 | ### Adding a Password Permit 95 | 96 | First, Alice wants to be able to recover the envelope later using a password she can remember, so she adds the first permit to the envelope using the `add_secret()` method, providing a derivation method `Argon2id`, her password, and the content key. The `add_secret()` method encrypts the content key with a new key derived from her password, and adds it to the envelope as a `'hasSecret'` assertion: 97 | 98 | ```rust 99 | let password = b"unicorns_dance_on_mars_while_eating_pizza"; 100 | let locked_envelope = encrypted_envelope.add_secret( 101 | KeyDerivationMethod::Argon2id, 102 | &password, 103 | &content_key 104 | ); 105 | ``` 106 | 107 | The encrypted envelope now has one permit: 108 | 109 | ``` 110 | ENCRYPTED [ 111 | 'hasSecret': EncryptedKey(Argon2id) 112 | ] 113 | ``` 114 | 115 | ### Adding Public Key Recipient Permits 116 | 117 | Next, Alice wants to be able to decrypt her envelope using her private key, and she also wants Bob to be able to decrypt it using his private key. To do this, she uses the `add_recipient()` with her own public key, and then Bob's public key. The `add_recipient()` method encrypts the content key with the recipient's public key, and adds it to the envelope as a `'hasRecipient'` assertion: 118 | 119 | ```rust 120 | let (bob_private_keys, bob_public_keys) = keypair(); 121 | 122 | let locked_envelope = locked_envelope 123 | .add_recipient(&alice_public_keys, &content_key) 124 | .add_recipient(&bob_public_keys, &content_key); 125 | ``` 126 | 127 | The encrypted envelope now has three permits: 128 | 129 | ``` 130 | ENCRYPTED [ 131 | 'hasRecipient': SealedMessage 132 | 'hasRecipient': SealedMessage 133 | 'hasSecret': EncryptedKey(Argon2id) 134 | ] 135 | ``` 136 | 137 | ### Adding Social Key Recovery Permits 138 | 139 | An SSKR share is a kind of permit defined by the characteristic that one share by itself is not enough to decrypt the envelope: some *quorum* or *threshold* of shares is required. 140 | 141 | Alice wants to back up her poem using a social recovery scheme, so even if she forgets her password and loses her private key, she can still recover the envelope by finding two of the three friends she entrusted with the shares. 142 | 143 | Alice creates a 2-of-3 SSKR group and "shards" the envelope into three envelopes, each containing a unique SSKR share. 144 | 145 | ```rust 146 | let sskr_group = SSKRGroupSpec::new(2, 3)?; 147 | let spec = SSKRSpec::new(1, vec![sskr_group])?; 148 | let sharded_envelopes = locked_envelope.sskr_split_flattened(&spec, &content_key)?; 149 | ``` 150 | 151 | Every envelope looks the same including the previous permits Alice added, but each one contains a different SSKR share, so we only show one of them here. There are now four permits, where each of the three envelopes has a different SSKR share: 152 | 153 | ``` 154 | ENCRYPTED [ 155 | 'hasRecipient': SealedMessage 156 | 'hasRecipient': SealedMessage 157 | 'hasSecret': EncryptedKey(Argon2id) 158 | 'sskrShare': SSKRShare 159 | ] 160 | ``` 161 | 162 | Now there are three envelopes, each having four permits, and *five* different ways to recover the original envelope: 163 | 164 | 1. Using the original content key (could be stored in a safe place) 165 | 2. Using Alice's password 166 | 3. Using Alice's private key 167 | 4. Using Bob's private key 168 | 5. Using any two of the three SSKR shares 169 | 170 | Alice will now: 171 | 172 | - Keep one envelope for herself 173 | - Give one envelope to Bob 174 | - Give the three sharded envelopes to three other friends who don't know each other 175 | - Use a password manager to store her password and private key 176 | - Put the content key in a safe place (optional, not usually recommended as Alice's private key is sufficient) 177 | 178 | ### Decrypting the Envelope 179 | 180 | Let's demonstrate using each of these permits to decrypt the envelope: 181 | 182 | ```rust 183 | // 184 | // Grab the first envelope from the SSKR shares. 185 | // 186 | 187 | let received_envelope = &sharded_envelopes[0]; 188 | 189 | // 190 | // Decrypt using the content key. 191 | // 192 | 193 | let unlocked_envelope = received_envelope.decrypt(&content_key)?; 194 | assert_eq!(unlocked_envelope, signed_envelope); 195 | 196 | // 197 | // Decrypt using the password. 198 | // 199 | 200 | let unlocked_envelope = received_envelope.unlock(&password)?; 201 | assert_eq!(unlocked_envelope, signed_envelope); 202 | 203 | // 204 | // Decrypt using Alice's private key. 205 | // 206 | 207 | let unlocked_envelope = received_envelope.decrypt_to_recipient(&alice_private_keys)?; 208 | assert_eq!(unlocked_envelope, signed_envelope); 209 | 210 | // 211 | // Decrypt using Bob's private key. 212 | // 213 | 214 | let unlocked_envelope = received_envelope.decrypt_to_recipient(&bob_private_keys)?; 215 | assert_eq!(unlocked_envelope, signed_envelope); 216 | 217 | // 218 | // Decrypt using any two of the three SSKR shares. 219 | // 220 | 221 | let unlocked_envelope = Envelope::sskr_join(&[ 222 | &sharded_envelopes[0], 223 | &sharded_envelopes[2] 224 | ])?.unwrap_envelope()?; 225 | assert_eq!(unlocked_envelope, signed_envelope); 226 | 227 | // 228 | // And of course, Alice's signature still verifies. 229 | // 230 | 231 | unlocked_envelope.verify(&alice_public_keys)?; 232 | ``` 233 | -------------------------------------------------------------------------------- /papers/bcr-2025-005-domain-separation.md: -------------------------------------------------------------------------------- 1 | # Domain Separation in Derived Keys 2 | 3 | ## BCR-2025-005 4 | 5 | **© 2025 Blockchain Commons** 6 | 7 | Authors: Wolf McNally\ 8 | Date: June 3, 2025 9 | 10 | ## Introduction 11 | 12 | _Domain separation_ is the practice of tagging cryptographic primitives (like hashes or derived keys) with unique, purpose-specific inputs, frequently called "salts" or "info" strings that ensure outputs for different uses don't overlap. This separation: 13 | 14 | - Prevents keys or hashes created for one purpose from being misused for another, 15 | - Blocks attacks that try to mix protocols, 16 | - Maintains security guarantees, and 17 | - Allows different systems to safely use the same algorithms without information leaking between them. 18 | 19 | Many applications require private-public key pairs used for both signing and public key encryption. For some key types, these can be derived from the same source key material. While a single derived key pair could in theory be used for both signing and key agreement, this is a bad idea. In the Blockchain Commons stack, wherever both a "signing" key and an "agreement" key are needed, and where these can both be derived from the same key material, we use distinct salts to derive them. 20 | 21 | This document shows where domain separation is applied in the Blockchain Commons software stack: particularly in the [`bc-components`](https://crates.io/crates/bc-components) ("Secure Components") Rust crate. 22 | 23 | ## `PrivateKeyBase` 24 | 25 | The [`PrivateKeyBase`](https://github.com/BlockchainCommons/bc-components-rust/blob/master/src/private_key_base.rs) structure simply holds an array of bytes representing _not_ a private key, but the raw key material from which a private key can be derived: 26 | 27 | ```rust 28 | pub struct PrivateKeyBase(Vec); 29 | ``` 30 | 31 | Just using the `new` method, you can create a new `PrivateKeyBase` using a cryptographically secure random number generator: 32 | 33 | ```rust 34 | let private_key_base = PrivateKeyBase::new(); 35 | ``` 36 | 37 | Or you can create a `PrivateKeyBase` from an existing byte array: 38 | 39 | ```rust 40 | let private_key_base = PrivateKeyBase::from_data(&[0x01, 0x02, 0x03, 0x04]); 41 | ``` 42 | 43 | Using such a simple sequence of bytes should never be done in production code as it is a critical security risk. However it is useful for testing and debugging purposes, as the keys derived from it will be deterministic and predictable. 44 | 45 | `PrivateKeyBase` also provides a number of convenience methods for deriving keys, such as `x25519_private_key()`. X25519 is used for key agreement, upon which Blockchain Commons builds its public key encryption structures. 46 | 47 | If we drill down into its implementation, we eventually arrive at the `derive_agreement_private_key()` function in the `bc-crypto`, which is used to derive the X25519 private key from the key material using HKDF (HMAC-based Key Derivation Function) with a specific salt for agreement keys: 48 | 49 | ```rust 50 | impl PrivateKeyBase { 51 | pub fn x25519_private_key(&self) -> X25519PrivateKey { 52 | X25519PrivateKey::derive_from_key_material(&self.0) 53 | } 54 | } 55 | 56 | impl X25519PrivateKey { 57 | pub fn derive_from_key_material(key_material: impl AsRef<[u8]>) -> Self { 58 | Self::from_data(bc_crypto::derive_agreement_private_key(key_material)) 59 | } 60 | } 61 | 62 | pub fn derive_agreement_private_key( 63 | key_material: impl AsRef<[u8]> 64 | ) -> [u8; GENERIC_PRIVATE_KEY_SIZE] { 65 | hkdf_hmac_sha256(key_material, "agreement".as_bytes(), GENERIC_PRIVATE_KEY_SIZE) 66 | .try_into() 67 | .unwrap() 68 | } 69 | ``` 70 | 71 | The string `"agreement"` is the salt used for deriving agreement keys, ensuring that the derived key is distinct from any signing keys that might be derived from the same key material. 72 | 73 | Next to the above function, we also have a `derive_signing_private_key()` primitive function that derives signing keys from the same key material, but with a different salt: 74 | 75 | ```rust 76 | pub fn derive_signing_private_key(key_material: impl AsRef<[u8]>) -> [u8; GENERIC_PUBLIC_KEY_SIZE] { 77 | hkdf_hmac_sha256(key_material, "signing".as_bytes(), GENERIC_PUBLIC_KEY_SIZE) 78 | .try_into() 79 | .unwrap() 80 | } 81 | ``` 82 | 83 | For all the key types that support deterministic key derivation, we ultimately uses these primitives to derive the keys, ensuring that agreement and signing keys are always derived into separate domains. 84 | 85 | ## `PrivateKeys` 86 | 87 | Because many applications require both signing and agreement keys, `PrivateKeyBase` also provides ways to derive an agreement key and and a signing key in a single step. For example: 88 | 89 | ```rust 90 | let private_keys: PrivateKeys = my_private_key_base.schnorr_private_keys(); 91 | ``` 92 | 93 | The `schnorr_private_keys()` method derives a BIP-340 Schnorr private key for signing and a X25519 private key for agreement from the `PrivateKeyBase`. The keys are derived using distinct salts, and packaged in a single [`PrivateKeys`](https://github.com/BlockchainCommons/bc-components-rust/blob/master/src/private_keys.rs) structure for convenience: 94 | 95 | ```rust 96 | pub struct PrivateKeys { 97 | signing_private_key: SigningPrivateKey, 98 | encapsulation_private_key: EncapsulationPrivateKey, 99 | } 100 | ``` 101 | 102 | Because the `PrivateKeys` structure implements the `Signer` and `Decrypter` traits, it can be used directly for signing messages and decrypting messages, both of which require private keys. In each case the key derived from the `PrivateKeyBase` with the appropriate salt is used. 103 | 104 | ## Non-Deterministic Key Generation and Best Practices 105 | 106 | The Blockchain Commons stack also supports key types where both keys are derived randomly and independently, such as the post-quantum algorithms like "ML-KEM" and "ML-DSA". In these cases, the production of these keys is never deterministic, so no domain separation is needed, and there is no separate step to derive the public keys. Instead, the `keypair()` or `keypair_opt()` methods can be used to generate all the keys at once. This is the recommended method for generating keys in production code, and works for all the signature and encapsulation schemes supported by the Blockchain Commons stack: 107 | 108 | ```rust 109 | // Generates the keys using the default signature and encapsulation schemes. 110 | let (private_keys: PrivateKeys, public_keys: PublicKeys) = 111 | keypair(); 112 | 113 | // Generates the keys using the specified signature and encapsulation schemes. 114 | let (private_keys: PrivateKeys, public_keys: PublicKeys) = 115 | keypair_opt(SignatureScheme::MLDSA44, EncapsulationScheme::MLKEM512); 116 | ``` 117 | -------------------------------------------------------------------------------- /signed-cla/CLA.gorazdko.41F0EA1699A74C1E2FA41B538CF96BC3FF9DBBCE.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNED MESSAGE----- 2 | Hash: SHA512 3 | 4 | # Contributor License Agreement 5 | 6 | Version 1.0 7 | 8 | Name: Gorazd Kovacic 9 | 10 | E-Mail: gorazdko@gmail.com 11 | 12 | Legal Jurisdiction: Wyoming, United States of America 13 | 14 | Project: https://github.com/BlockchainCommons/bc-lethe-kit 15 | 16 | Date: 10-01-2020 17 | 18 | ## Purpose 19 | 20 | This agreement gives Blockchain Commons, LLC the permission it needs in order to accept my contributions into its open software project and to manage the intellectual property in that project over time. 21 | 22 | ## License 23 | 24 | I hereby license Blockchain Commons, LLC to: 25 | 26 | 1. do anything with my contributions that would otherwise infringe my copyright in them 27 | 28 | 2. do anything with my contributions that would otherwise infringe patents that I can or become able to license 29 | 30 | 3. sublicense these rights to others on any terms they like 31 | 32 | ## Reliability 33 | 34 | I understand that Blockchain Commons will rely on this license. I may not revoke this license. 35 | 36 | ## Awareness 37 | 38 | I promise that I am familiar with legal rules, like ["work made for hire" rules](http://worksmadeforhire.com), that can give employers and clients ownership of intellectual property in work that I do. I am also aware that legal agreements I might sign, like confidential information and invention assignment agreements, will usually give ownership of intellectual property in my work to employers, clients, and companies that I found. If someone else owns intellectual property in my work, I need their permission to license it. 39 | 40 | ## Copyright Guarantee 41 | 42 | I promise not to offer contributions to the project that contain copyrighted work that I do not have legally binding permission to contribute under these terms. When I offer a contribution with permission, I promise to document in the contribution who owns copyright in what work, and how they gave permission to contribute it. If I later become aware that one of my contributions may have copyrighted work of others that I did not have permission to contribute, I will notify Blockchain Commons, in confidence, immediately. 43 | 44 | ## Patent Guarantee 45 | 46 | I promise not to offer contributions to the project that I know infringe patents of others that I do not have permission to contribute under these terms. 47 | 48 | ## Open Source Guarantee 49 | 50 | I promise not to offer contributions that contain or depend on the work of others, unless that work is available under a license that [Blue Oak Council rates bronze or better](https://blueoakconcil.org/list), such as the MIT License, two- or three-clause BSD License, the Apache License Version 2.0, or the Blue Oak Model License 1.0.0. When I offer a contribution containing or depending on others' work, I promise to document in the contribution who licenses that work, along with copies of their license terms. 51 | 52 | ## Disclaimers 53 | 54 | ***As far as the law allows, my contributions come as is, without any warranty or condition. Other than under [Copyright Guarantee](#copyright-guarantee), [Patent Guarantee](#patent-guarantee), or [Open Source Guarantee](#open-source-guarantee), I will not be liable to anyone for any damages related to my contributions or this contributor license agreement, under any kind of legal claim.*** 55 | 56 | - --- 57 | 58 | To sign this Contributor License Agreement, fill in `$name`, `$email`, and `$date` above. Then sign using GPG using the following command `gpg --armor --clearsign --output ./signed-cla/CLA.YOURGITHUBNAME.YOURGPGFINGERPRINT.asc CLA.md`, then either submit your signed Contributor License Agreement to this repo as a GPG signed Pull Request or email it to [ChristopherA@BlockchainCommons.com](mailto:ChristopherA@BlockchainCommons.com). 59 | -----BEGIN PGP SIGNATURE----- 60 | 61 | iQIzBAEBCgAdFiEEQfDqFpmnTB4vpBtTjPlrw/+du84FAl91DjUACgkQjPlrw/+d 62 | u84dbg//VO8bjxzebkGFQNyz29edHTnkq9aMdnHUd6NC61gRIWJ4sSBlscWeNFOb 63 | QpLb4WO8/X9V5ITqQG52M6VnM09DocQXQBZG30HoeTuFIYbrC5zfTQZYPAeabV7c 64 | dzGjWeZVr/IVkWc1BoLhJntzB3rdlsqQbnf5QRvLtLY7PJ7Z+lN5KF+S2wMQrEaA 65 | 9M3X9BzgfqjZ+I8FC4aEs0jwj+aPKOetnPRTDDsqO8poPRa7t6Bd/HDV75meAue0 66 | H9hpF6GSrDez8/nczCo2C4qadI3LwBrUzTwXrXFoltCokzm6A7affwWaBItH5yQC 67 | DkOSj7+MDoUTHP71zsGV8fUSuxppPqOz58pVTec+JnOu0PDWwDsXlQS9OoHTD8uR 68 | ybaDLu5zXXN0m+y7IMhYogO7NxdjMuAOKBTp1VAOgqWKgEVejIhZxoI15dL7IBYI 69 | fgcP5GjyycGeOhrhrvzSxWao4LrLKRnaBd83ptZhruY8qKNb4u5hl19vkkvCEQYY 70 | C4LiTFAbagfsEfp5ekqkcfbhCwSQO7m6oqw5tP1rZbvW/V2QeKdJ8JQbdBvhQS8y 71 | eFHSF/Hv0kVheBqs/H3fRazFZsxBhmTlOaFp1qJF+yg6VZJVsBaRVdKTOJMafINv 72 | KDECoSy9WWN6XPuD+Lt/Ce2ZPC6OmbWewqFEKWKg7N7SN5Ok49Y= 73 | =vpt3 74 | -----END PGP SIGNATURE----- 75 | -------------------------------------------------------------------------------- /signed-cla/CLA.mcelrath.D4274A20A7A006DDF1B904A2CF18D8489BE58C4E.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNED MESSAGE----- 2 | Hash: SHA256 3 | 4 | # Contributor License Agreement 5 | 6 | Version 1.0 7 | 8 | Name: `Bob McElrath` 9 | 10 | E-Mail: `bob.mcelrath@gmail.com` 11 | 12 | Legal Jurisdiction: Wyoming, United States of America 13 | 14 | Project: https://github.com/BlockchainCommons/bc-lethe-kit 15 | 16 | Date: `Thu 14 May 2020 09:35:00 AM EDT` 17 | 18 | ## Purpose 19 | 20 | This agreement gives Blockchain Commons, LLC the permission it needs in order to accept my contributions into its open software project and to manage the intellectual property in that project over time. 21 | 22 | ## License 23 | 24 | I hereby license Blockchain Commons, LLC to: 25 | 26 | 1. do anything with my contributions that would otherwise infringe my copyright in them 27 | 28 | 2. do anything with my contributions that would otherwise infringe patents that I can or become able to license 29 | 30 | 3. sublicense these rights to others on any terms they like 31 | 32 | ## Reliability 33 | 34 | I understand that Blockchain Commons will rely on this license. I may not revoke this license. 35 | 36 | ## Awareness 37 | 38 | I promise that I am familiar with legal rules, like ["work made for hire" rules](http://worksmadeforhire.com), that can give employers and clients ownership of intellectual property in work that I do. I am also aware that legal agreements I might sign, like confidential information and invention assignment agreements, will usually give ownership of intellectual property in my work to employers, clients, and companies that I found. If someone else owns intellectual property in my work, I need their permission to license it. 39 | 40 | ## Copyright Guarantee 41 | 42 | I promise not to offer contributions to the project that contain copyrighted work that I do not have legally binding permission to contribute under these terms. When I offer a contribution with permission, I promise to document in the contribution who owns copyright in what work, and how they gave permission to contribute it. If I later become aware that one of my contributions may have copyrighted work of others that I did not have permission to contribute, I will notify Blockchain Commons, in confidence, immediately. 43 | 44 | ## Patent Guarantee 45 | 46 | I promise not to offer contributions to the project that I know infringe patents of others that I do not have permission to contribute under these terms. 47 | 48 | ## Open Source Guarantee 49 | 50 | I promise not to offer contributions that contain or depend on the work of others, unless that work is available under a license that [Blue Oak Council rates bronze or better](https://blueoakconcil.org/list), such as the MIT License, two- or three-clause BSD License, the Apache License Version 2.0, or the Blue Oak Model License 1.0.0. When I offer a contribution containing or depending on others' work, I promise to document in the contribution who licenses that work, along with copies of their license terms. 51 | 52 | ## Disclaimers 53 | 54 | ***As far as the law allows, my contributions come as is, without any warranty or condition. Other than under [Copyright Guarantee](#copyright-guarantee), [Patent Guarantee](#patent-guarantee), or [Open Source Guarantee](#open-source-guarantee), I will not be liable to anyone for any damages related to my contributions or this contributor license agreement, under any kind of legal claim.*** 55 | 56 | - --- 57 | 58 | To sign this Contributor License Agreement, fill in `$name`, `$email`, and `$date` above. Then sign using GPG using the following command `gpg --armor --clearsign --output ./signed-cla/CLA.YOURGITHUBNAME.YOURGPGFINGERPRINT.asc CLA.md`, then either submit your signed Contributor License Agreement to this repo as a GPG signed Pull Request or email it to [ChristopherA@BlockchainCommons.com](mailto:ChristopherA@BlockchainCommons.com). 59 | -----BEGIN PGP SIGNATURE----- 60 | 61 | iQGzBAEBCAAdFiEE1CdKIKegBt3xuQSizxjYSJvljE4FAl69Sa0ACgkQzxjYSJvl 62 | jE5J5AwAlh/ztitoKfjVbb+c5B9LXEzqAtExdKjLl1HqHFn6wql+JIOr8nTR6yTg 63 | Q4aedMVqiXnpsJd7Jacd80YrAGcnwPwbDssHv+54I2WfDcEiWc2A7IIE5kv7m4Tt 64 | x0trpl1wsypWbSXSL8fv83TcArhlMPQZzrz8WRK1ScnhxApVt80P/tDhvKV9OUDp 65 | Cg15qZrQhIEYCdazD5O8W4/9lDeavXw/jZEavRdw/09Dx/xOvaAEz1bRogTa/2ks 66 | oj2PO/GtcEmO38oqxs5pjHSL7xtznFC+DilK7riJi+F+7Czj11DkPelHAbYH2UW+ 67 | PcSQIiFDPOYbTo+QIWqugxT/8yPqc6i47bSOOecqd/CSx73xr2VtKUWhe7e2cp9h 68 | Ent9fX2IdYV0PHn1WPAgrEOdMGOtLNWmTShAy03GQsL6yURPH1SJFgIIvfaLvnX3 69 | WLYYO2lBpOqUKR0hNFob9BFI6tKNvqNSESYYDCVXfYNXyEH3qaheuLY5bLuN771U 70 | aIg92L7a 71 | =0/UL 72 | -----END PGP SIGNATURE----- 73 | -------------------------------------------------------------------------------- /signed-cla/CLA.wolfmcnally.943652EE38441760C3DC35364B6C2FCF894780AE.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNED MESSAGE----- 2 | Hash: SHA512 3 | 4 | # Contributor License Agreement 5 | 6 | Version 1.0 7 | 8 | Name: Wolf McNally 9 | 10 | E-Mail: wolf@wolfmcnally.com 11 | 12 | Legal Jurisdiction: Wyoming, United States of America 13 | 14 | Project: https://github.com/BlockchainCommons/bc-lethe-kit 15 | 16 | Date: April 20, 2020 17 | 18 | ## Purpose 19 | 20 | This agreement gives Blockchain Commons, LLC the permission it needs in order to accept my contributions into its open software project and to manage the intellectual property in that project over time. 21 | 22 | ## License 23 | 24 | I hereby license Blockchain Commons, LLC to: 25 | 26 | 1. do anything with my contributions that would otherwise infringe my copyright in them 27 | 28 | 2. do anything with my contributions that would otherwise infringe patents that I can or become able to license 29 | 30 | 3. sublicense these rights to others on any terms they like 31 | 32 | ## Reliability 33 | 34 | I understand that Blockchain Commons will rely on this license. I may not revoke this license. 35 | 36 | ## Awareness 37 | 38 | I promise that I am familiar with legal rules, like ["work made for hire" rules](http://worksmadeforhire.com), that can give employers and clients ownership of intellectual property in work that I do. I am also aware that legal agreements I might sign, like confidential information and invention assignment agreements, will usually give ownership of intellectual property in my work to employers, clients, and companies that I found. If someone else owns intellectual property in my work, I need their permission to license it. 39 | 40 | ## Copyright Guarantee 41 | 42 | I promise not to offer contributions to the project that contain copyrighted work that I do not have legally binding permission to contribute under these terms. When I offer a contribution with permission, I promise to document in the contribution who owns copyright in what work, and how they gave permission to contribute it. If I later become aware that one of my contributions may have copyrighted work of others that I did not have permission to contribute, I will notify Blockchain Commons, in confidence, immediately. 43 | 44 | ## Patent Guarantee 45 | 46 | I promise not to offer contributions to the project that I know infringe patents of others that I do not have permission to contribute under these terms. 47 | 48 | ## Open Source Guarantee 49 | 50 | I promise not to offer contributions that contain or depend on the work of others, unless that work is available under a license that [Blue Oak Council rates bronze or better](https://blueoakconcil.org/list), such as the MIT License, two- or three-clause BSD License, the Apache License Version 2.0, or the Blue Oak Model License 1.0.0. When I offer a contribution containing or depending on others' work, I promise to document in the contribution who licenses that work, along with copies of their license terms. 51 | 52 | ## Disclaimers 53 | 54 | ***As far as the law allows, my contributions come as is, without any warranty or condition. Other than under [Copyright Guarantee](#copyright-guarantee), [Patent Guarantee](#patent-guarantee), or [Open Source Guarantee](#open-source-guarantee), I will not be liable to anyone for any damages related to my contributions or this contributor license agreement, under any kind of legal claim.*** 55 | 56 | - --- 57 | 58 | To sign this Contributor License Agreement, fill in `$name`, `$email`, and `$date` above. Then sign using GPG using the following command `gpg --armor --clearsign --output ./signed-cla/CLA.YOURGITHUBNAME.YOURGPGFINGERPRINT.asc CLA.md`, then either submit your signed Contributor License Agreement to this repo as a GPG signed Pull Request or email it to [ChristopherA@BlockchainCommons.com](mailto:ChristopherA@BlockchainCommons.com). 59 | 60 | -----BEGIN PGP SIGNATURE----- 61 | Comment: GPGTools - https://gpgtools.org 62 | 63 | iQIzBAEBCgAdFiEElDZS7jhEF2DD3DU2S2wvz4lHgK4FAl6eDFMACgkQS2wvz4lH 64 | gK7p0RAAuSvcZvSSOR3ELwEqjVhn9SgG3Ye8XlQXY0AM8tRT4zs8BuotzjD+HzE3 65 | bELHDou3sOc1eQpBg+iLiSLLg7q7xRkuZTz2CShxgCpfwrOtxojjmmXH1eJOz5KO 66 | RpPcU1SZLE8r7oWGanP72VuK6VcTshV4YAReeQildsYiYjsHqvSAxN9L/Fuctp6p 67 | 8Lphpgdi/CvYlV6IXaauonCornuxUXZVZkpXJ8GhIoPIKxXfmLThfcTDfdYDBzRX 68 | tS7NjmzF7+dkTmBybUpEHBTnS63MzIpYXD0PrdsOGeRL2gtK1DXMfYZ5XNhsvvDG 69 | m44rYIk7cy42GRBCfJ26QviuWbpoAmXj0Kdna7dRp8aCEflOne9R2/jpXOzI2kLg 70 | qwc05CVwjkPN3oOHQyJnJoc5dvBGenT7CmlK9dek+I0dZWtLHnnuD9jjILhT32aB 71 | KxhcaxqbkB+tq9EV0FTUU8k460JBPQK291KH+zUFTcSDUOW8umfTCyX0focIIHj6 72 | vF5S6UQ9Jf3vgmQ9MZRLq6Wla194vEdUjDjfitUylIp7sBn37vzfycx5TznrDocE 73 | Z7RRKrKjxRaM7AefuHAjcN9cNj4u4nCeYpqf4ctDNJ3H5VVpCciEBrwJor3Zx4Gh 74 | yxh+zKD6KorCqMJv4ofYd4Xg1yInOR8Yp+ZGQ9Jn674mSxNbQhQ= 75 | =cTFx 76 | -----END PGP SIGNATURE----- 77 | -------------------------------------------------------------------------------- /signed-cla/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlockchainCommons/Research/f48872e3f858e9b86957f16f39149f3e1c47b24f/signed-cla/README.md --------------------------------------------------------------------------------