Return-Path: Received: from smtp4.osuosl.org (smtp4.osuosl.org [140.211.166.137]) by lists.linuxfoundation.org (Postfix) with ESMTP id 7C0DBC002B for ; Thu, 16 Feb 2023 11:50:55 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 51A854189D for ; Thu, 16 Feb 2023 11:50:55 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org 51A854189D Authentication-Results: smtp4.osuosl.org; dkim=pass (2048-bit key) header.d=satoshilabs.com header.i=@satoshilabs.com header.a=rsa-sha256 header.s=google header.b=eT/lNaN2 X-Virus-Scanned: amavisd-new at osuosl.org X-Spam-Flag: NO X-Spam-Score: -1.6 X-Spam-Level: X-Spam-Status: No, score=-1.6 tagged_above=-999 required=5 tests=[BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, HTML_MESSAGE=0.001, PDS_BTC_ID=0.499, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001] autolearn=no autolearn_force=no Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id qUdOH6yVCySb for ; Thu, 16 Feb 2023 11:50:51 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.8.0 DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org B8AE34189B Received: from mail-ej1-x636.google.com (mail-ej1-x636.google.com [IPv6:2a00:1450:4864:20::636]) by smtp4.osuosl.org (Postfix) with ESMTPS id B8AE34189B for ; Thu, 16 Feb 2023 11:50:50 +0000 (UTC) Received: by mail-ej1-x636.google.com with SMTP id a3so4544842ejb.3 for ; Thu, 16 Feb 2023 03:50:50 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=satoshilabs.com; s=google; h=to:subject:message-id:date:from:in-reply-to:references:mime-version :from:to:cc:subject:date:message-id:reply-to; bh=N1DScCOWLckpLLK+bUIBmkHNvl4UwUYjM/s/KGGVPp8=; b=eT/lNaN2Zlgt1zkUqyxIBZPJZRwqtHqV28hKvYvjtC/ALLKe1qafUVkPNxnuWqh/yK ND/WmYAgR+OrVEWZDpyJPlIbpY6RZ7fLmzwu/9a6sfWbAJLRdxFP7wESiQK++TRY56t9 4vf9KtSYpSUaeF3qJ7rJ2bjqfh7ts7MUHZSE2zCb3au7EvaPjWfTLpmEJwW7E/eyxbjp ECuTfZweve2SZF/YG22GsmyeFbzt5svksZm0Iw5B6cRxJrwhKKaV+EqfhjoKKNEW/g5o PAQaPBmtGNNc5VucyVMC4WyYU4gTw5VgdTuKyKcbY3iMkdta4w8iaukF1ISsif2lubxZ 0Lrg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=to:subject:message-id:date:from:in-reply-to:references:mime-version :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=N1DScCOWLckpLLK+bUIBmkHNvl4UwUYjM/s/KGGVPp8=; b=hIi8ATbZQPLYh95Tg4O4mf0MX0UmoyO3Q748JJJsU/hRg35x7Ar3q4Qq4S1ao4H1WS ifAyt5y/3anb6j5QXBMUZ7uUM3iO33GeUvz6mSI35SK9q1YSecYWM7IkRu1oUay4lXBK iIbmVlePG/gqz5cg0Po+P2gIXnamGVOIPeBlPvStxoEjLjrt+oazdIo0/XLVojkOpAPi XarWTH/qxetBFVkFdMhOBhyO2samB4V6cvk7l2x6/uRFPHJG7QLzvw+0g5p0epJajXZd 112WIWEEAVhixYE2b9KKXBsZ55DtUmLLE5yNNfXZ+ON/M6kNSAByq0AQbDrnZ5taT+SP EuLg== X-Gm-Message-State: AO0yUKUkpKluJYOITZ+KmVRlgXRyLz5DcUHpHaARve90IHhzzYupT+Zn CA+9XtfSJOB0AglJiyl82rBuBgT4cSleuvqqWmIG9g== X-Google-Smtp-Source: AK7set9i7zg7n6ajfc0Njpx1ec74ssvkLVwVmuD3uDE4jvrrQKJSsEQPpBhNcoWQqSLM5qXiJoKpLu4e9bQc25D5dbA= X-Received: by 2002:a17:906:c315:b0:877:747d:f11f with SMTP id s21-20020a170906c31500b00877747df11fmr2730571ejz.7.1676548248657; Thu, 16 Feb 2023 03:50:48 -0800 (PST) MIME-Version: 1.0 References: In-Reply-To: From: Pavol Rusnak Date: Thu, 16 Feb 2023 12:50:12 +0100 Message-ID: To: "Russell O'Connor" , Bitcoin Protocol Discussion Content-Type: multipart/alternative; boundary="000000000000cf72bd05f4cfce1c" X-Mailman-Approved-At: Thu, 16 Feb 2023 13:24:37 +0000 Subject: Re: [bitcoin-dev] Codex32 X-BeenThere: bitcoin-dev@lists.linuxfoundation.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: Bitcoin Protocol Discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 16 Feb 2023 11:50:55 -0000 --000000000000cf72bd05f4cfce1c Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Hi! The BIP states that its only advantage over SLIP-0039, which has been used in production for nearly three years (in at at least 3 SW/HW wallet implementations), is that it aims to be simple enough for hand computation. However, the BIP also indicates that "details of hand computation are outside the scope of this standard, and implementers do not need to be concerned with this possibility." Therefore, I am curious about how significant this advantage over SLIP-0039 really is. If hand computation is not straightforward and there are no other substantial advantages over SLIP-0039, I cannot help but feel that this BIP is simply a result of not-invented-here syndrome, but please correct me if I am wrong. Keep in mind that the encoded shares in SLIP-0039 consist of exactly 200 or 330 bits, both of which are divisible by 5. This makes it straightforward to encode them as Bech32 strings. On Thu, 16 Feb 2023 at 09:30, Russell O'Connor via bitcoin-dev < bitcoin-dev@lists.linuxfoundation.org> wrote: > I've been asked by Dr. Curr and Professor Snead to forward this message t= o > this mailing list, as it may be of general interest to Bitcoin users. > > Dear Colleague: > > In 1967, during excavation for the construction of a new shopping center > in > Monroeville, Pennsylvania, workers uncovered a vault containing a cache o= f > ancient scrolls[1]. Most were severely damaged, but those that could be > recovered confirmed the existence of a secret society long suspected to > have > been active in the region around the year 200 BC. > > Based on a translation of these documents, we now know that the society, > the > Cult of the Bound Variable, was devoted to the careful study of > computation, > over two millennia before the invention of the digital computer. > > While the Monroeville scrolls make reference to computing machines made o= f > sandstone, most researchers believed this to be a poetic metaphor and tha= t > the > "computers" were in fact the initiates themselves, carrying out the > unimaginably tedious steps of their computations with reed pens on > parchment. > > Within the vault, a collection of sandstone wheels marked in a language > consisting of 32 glyphs was found. After 15 years of study, we have > successfully > completed the translation of what is known as "Codex32," a document that > describes the functions of the wheels. It was discovered that the wheels > operate > a system of cryptographic computations that was used by cult members to > safeguard their most valuable secrets. > > The Codex32 system allows secrets to be carved into multiple tablets and > scattered to the far corners of the earth. When a sufficient number of > tablets are > brought together the stone wheels are manipulated in a manner to recover > the > secrets. This finding may be of particular interest to the Bitcoin > community. > > Below we provide a summary of the cult's secret sharing system, which is > graciously hosted at > < > https://github.com/apoelstra/bips/blob/2023-02--volvelles/bip-0000.mediaw= iki > >. > We are requesting a record assignment in the Bibliography of Immemorial > Philosophy (BIP) repository. > > Thank you for your consideration. > > Dr. Leon O. Curr and Professor Pearlwort Snead > Department of Archaeocryptography > Harry Q. Bovik Institute for the Advancement > > [1] http://www.boundvariable.org/task.shtml > > -----BEGIN BIP----- > >
>   BIP: ????
>   Layer: Applications
>   Title: codex32
>   Author: Leon Olsson Curr and Pearlwort Sneed 
>   Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-????
>   Status: Draft
>   Type: ????
>   Created: 2023-02-13
>   License: BSD-3-Clause
>   Post-History: FIXME
> 
> > =3D=3DIntroduction=3D=3D > > =3D=3D=3DAbstract=3D=3D=3D > > This document describes a standard for backing up and restoring the maste= r > seed of a > [https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki BIP-0032] > hierarchical deterministic wallet, using Shamir's secret sharing. > It includes an encoding format, a BCH error-correcting checksum, and > algorithms for share generation and secret recovery. > Secret data can be split into up to 31 shares. > A minimum threshold of shares, which can be between 1 and 9, is needed to > recover the secret, whereas without sufficient shares, no information abo= ut > the secret is recoverable. > > =3D=3D=3DCopyright=3D=3D=3D > > This document is licensed under the 3-clause BSD license. > > =3D=3D=3DMotivation=3D=3D=3D > > BIP-0032 master seed data is the source entropy used to derive all privat= e > keys in an HD wallet. > Safely storing this secret data is the hardest and most important part of > self-custody. > However, there is a tension between security, which demands limiting the > number of backups, and resilience, which demands widely replicated backup= s. > Encrypting the seed does not change this fundamental tradeoff, since it > leaves essentially the same problem of how to back up the encryption key(= s). > > To allow users freedom to make this tradeoff, we use Shamir's secret > sharing, which guarantees that any number of shares less than the thresho= ld > leaks no information about the secret. > This approach allows increasing safety by widely distributing the > generated shares, while also providing security against the compromise of > one or more shares (as long as fewer than the threshold have been > compromised). > > [https://github.com/satoshilabs/slips/blob/master/slip-0039.md SLIP-0039] > has essentially the same motivations as this standard. > However, unlike SLIP-0039, this standard also aims to be simple enough fo= r > hand computation. > Users who demand a higher level of security for particular secrets, or > have a general distrust in digital electronic devices, have the option of > using hand computation to backup and restore secret data in an > interoperable manner. > Note that hand computation is optional, the particular details of hand > computation are outside the scope of this standard, and implementers do n= ot > need to be concerned with this possibility. > > [https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki BIP-0039] > serves the same purpose as this standard: encoding master seeds for stora= ge > by users. > However, BIP-0039 has no error-correcting ability, cannot sensibly be > extended to support secret sharing, has no support for versioning or othe= r > metadata, and has many technical design decisions that make implementatio= n > and interoperability difficult (for example, the use of SHA-512 to derive > seeds, or the use of 11-bit words). > > =3D=3DSpecification=3D=3D > > =3D=3D=3Dcodex32=3D=3D=3D > > A codex32 string is similar to a Bech32 string defined in [ > https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki BIP-0173]. > It reuses the base32 character set from BIP-0173, and consists of: > > * A human-readable part, which is the string "ms" (or "MS"). > * A separator, which is always "1". > * A data part which is in turn subdivided into: > ** A threshold parameter, which MUST be a single digit between "2" and > "9", or the digit "0". > *** If the threshold parameter is "0" then the share index, defined below= , > MUST have a value of "s" (or "S"). > ** An identifier consisting of 4 Bech32 characters. > ** A share index, which is any Bech32 character. Note that a share index > value of "s" (or "S") is special and denotes the unshared secret (see > section "Unshared Secret"). > ** A payload which is a sequence of up to 74 Bech32 characters. (However, > see '''Long codex32 Strings''' below for an exception to this limit.) > ** A checksum which consists of 13 Bech32 characters as described below. > > As with Bech32 strings, a codex32 string MUST be entirely uppercase or > entirely lowercase. > The lowercase form is used when determining a character's value for > checksum purposes. > For presentation, lowercase is usually preferable, but uppercase SHOULD b= e > used for handwritten codex32 strings. > > =3D=3D=3DChecksum=3D=3D=3D > > The last thirteen characters of the data part form a checksum and contain > no information. > Valid strings MUST pass the criteria for validity specified by the Python= 3 > code snippet below. > The function ms32_verify_checksum must return true when its > argument is the data part as a list of integers representing the characte= rs > converted using the bech32 character table from BIP-0173. > > To construct a valid checksum given the data-part characters (excluding > the checksum), the ms32_create_checksum function can be used= . > > > MS32_CONST =3D 0x10ce0795c2fd1e62a > > def ms32_polymod(values): > GEN =3D [ > 0x19dc500ce73fde210, > 0x1bfae00def77fe529, > 0x1fbd920fffe7bee52, > 0x1739640bdeee3fdad, > 0x07729a039cfc75f5a, > ] > residue =3D 0x23181b3 > for v in values: > b =3D (residue >> 60) > residue =3D (residue & 0x0fffffffffffffff) << 5 ^ v > for i in range(5): > residue ^=3D GEN[i] if ((b >> i) & 1) else 0 > return residue > > def ms32_verify_checksum(data): > if len(data) >=3D 96: # See Long codex32 Strings > return ms32_verify_long_checksum(data) > if len(data) <=3D 93: > return ms32_polymod(data) =3D=3D MS32_CONST > return False > > def ms32_create_checksum(data): > if len(data) > 80: # See Long codex32 Strings > return ms32_create_long_checksum(data) > values =3D data > polymod =3D ms32_polymod(values + [0] * 13) ^ MS32_CONST > return [(polymod >> 5 * (12 - i)) & 31 for i in range(13)] > > > =3D=3D=3DError Correction=3D=3D=3D > > A codex32 string without a valid checksum MUST NOT be used. > The checksum is designed to be an error correcting code that can correct > up to 4 character substitutions, up to 8 unreadable characters (called > erasures), or up to 13 consecutive erasures. > Implementations SHOULD provide the user with a corrected valid codex32 > string if possible. > However, implementations SHOULD NOT automatically proceed with a correcte= d > codex32 string without user confirmation of the corrected string, either = by > prompting the user, or returning a corrected string in an error message a= nd > allowing the user to repeat their action. > We do not specify how an implementation should implement error correction= . > However, we recommend that: > > * Implementations make suggestions to substitute non-bech32 characters > with bech32 characters in some situations, such as replacing "B" with "8"= , > "O" with "0", "I" with "l", etc. > * Implementations interpret "?" as an erasure. > * Implementations optionally interpret other non-bech32 characters, or > characters with incorrect case, as erasures. > * If a string with 8 or fewer erasures can have those erasures filled in > to make a valid codex32 string, then the implementation suggests such a > string as a correction. > * If a string consisting of valid Bech32 characters in the proper case ca= n > be made valid by substituting 4 or fewer characters, then the > implementation suggests such a string as a correction. > > =3D=3D=3DUnshared Secret=3D=3D=3D > > When the share index of a valid codex32 string (converted to lowercase) i= s > the letter "s", we call the string a codex32 secret. > The subsequent data characters in a codex32 secret, excluding the final > checksum of 13 characters, is a direct encoding of a BIP-0032 HD master > seed. > > The master seed is decoded by converting the data to bytes: > > * Translate the characters to 5 bits values using the bech32 character > table from BIP-0173, most significant bit first. > * Re-arrange those bits into groups of 8 bits. Any incomplete group at th= e > end MUST be 4 bits or less, and is discarded. > > Note that unlike the decoding process in BIP-0173, we do NOT require that > the incomplete group be all zeros. > > For an unshared secret, the threshold parameter (the first character of > the data part) is ignored (beyond the fact it must be a digit for the > codex32 string to be valid). > We recommend using the digit "0" for the threshold parameter in this case= . > The 4 character identifier also has no effect beyond aiding users in > distinguishing between multiple different master seeds in cases where the= y > have more than one. > > =3D=3D=3DRecovering Master Seed=3D=3D=3D > > When the share index of a valid codex32 string (converted to lowercase) i= s > not the letter "s", we call the string an codex32 share. > The first character of the data part indicates the threshold of the share= , > and it is required to be a non-"0" digit. > > In order to recover a master seed, one needs a set of valid codex32 share= s > such that: > > * All shares have the same threshold value, the same identifier, and the > same length. > * All of the share index values are distinct. > * The number of codex32 shares is exactly equal to the (common) threshold > value. > > If all the above conditions are satisfied, the ms32_recover > function will return a codex32 secret when its argument is the list of > codex32 shares with each share represented as a list of integers > representing the characters converted using the bech32 character table fr= om > BIP-0173. > > > bech32_inv =3D [ > 0, 1, 20, 24, 10, 8, 12, 29, 5, 11, 4, 9, 6, 28, 26, 31, > 22, 18, 17, 23, 2, 25, 16, 19, 3, 21, 14, 30, 13, 7, 27, 15, > ] > > def bech32_mul(a, b): > res =3D 0 > for i in range(5): > res ^=3D a if ((b >> i) & 1) else 0 > a *=3D 2 > a ^=3D 41 if (32 <=3D a) else 0 > return res > > def bech32_lagrange(l, x): > n =3D 1 > c =3D [] > for i in l: > n =3D bech32_mul(n, i ^ x) > m =3D 1 > for j in l: > m =3D bech32_mul(m, (x if i =3D=3D j else i) ^ j) > c.append(m) > return [bech32_mul(n, bech32_inv[i]) for i in c] > > def ms32_interpolate(l, x): > w =3D bech32_lagrange([s[5] for s in l], x) > res =3D [] > for i in range(len(l[0])): > n =3D 0 > for j in range(len(l)): > n ^=3D bech32_mul(w[j], l[j][i]) > res.append(n) > return res > > def ms32_recover(l): > return ms32_interpolate(l, 16) > > > =3D=3D=3DGenerating Shares=3D=3D=3D > > If we already have ''t'' valid codex32 strings such that: > > * All strings have the same threshold value ''t'', the same identifier, > and the same length > * All of the share index values are distinct > > Then we can derive additional shares with the > ms32_interpolate function by passing it a list of exactly > ''t'' of these codex32 strings, together with a fresh share index distinc= t > from all of the existing share indexes. > The newly derived share will have the provided share index. > > Once a user has generated ''n'' codex32 shares, they may discard the > codex32 secret (if it exists). > The ''n'' shares form a ''t'' of ''n'' Shamir's secret sharing scheme of = a > codex32 secret. > > There are two ways to create an initial set of ''t'' valid codex32 > strings, depending on whether the user already has an existing master see= d > to split. > > =3D=3D=3D=3DFor an existing master seed=3D=3D=3D=3D > > Before generating shares for an existing master seed, it first must be > converted into a codex32 secret, as described above. > The conversion process consists of: > > * Choosing a threshold value ''t'' between 2 and 9, inclusive > * Choosing a 4 bech32 character identifier > ** We do not define how to choose the identifier, beyond noting that it > SHOULD be distinct for every master seed the user may need to disambiguat= e. > * Setting the share index to "s" > * Setting the payload to a Bech32 encoding of the master seed, padded wit= h > arbitrary bits > * Generating a valid checksum in accordance with the Checksum section > > Along with the codex32 secret, the user must generate ''t''-1 other > codex32 shares, each with the same threshold value, the same identifier, > and a distinct share index. > The set of share indexes may be chosen arbitrarily. > The payload of each of these codex32 shares is chosen uniformly at random > such that it has the same length as the payload of the codex32 secret. > For each share, a valid checksum must be generated in accordance with the > Checksum section. > > The codex32 secret and the ''t''-1 codex32 shares form a set of ''t'' > valid codex32 strings from which additional shares can be derived as > described above. > > =3D=3D=3D=3DFor a fresh master seed=3D=3D=3D=3D > > In the case that the user wishes to generate a fresh master seed, the use= r > chooses a threshold value ''t'' and an identifier, then generates ''t'' > random codex32 shares, using the generation procedure from the previous > section. > As before, each share must have the same threshold value ''t'', the same > identifier, and a distinct share index. > > With this set of ''t'' codex32 shares, new shares can be derived as > discussed above. This process generates a fresh master seed, whose value > can be retrieved by running the recovery process on any ''t'' of these > shares. > > =3D=3D=3DLong codex32 Strings=3D=3D=3D > > The 13 character checksum design only supports up to 80 data characters. > Excluding the threshold, identifier and index characters, this limits the > payload to 74 characters or 46 bytes. > While this is enough to support the 32-byte advised size of BIP-0032 > master seeds, BIP-0032 allows seeds to be up to 64 bytes in size. > We define a long codex32 string format to support these longer seeds by > defining an alternative checksum. > > > MS32_LONG_CONST =3D 0x43381e570bf4798ab26 > > def ms32_long_polymod(values): > GEN =3D [ > 0x3d59d273535ea62d897, > 0x7a9becb6361c6c51507, > 0x543f9b7e6c38d8a2a0e, > 0x0c577eaeccf1990d13c, > 0x1887f74f8dc71b10651, > ] > residue =3D 0x23181b3 > for v in values: > b =3D (residue >> 70) > residue =3D (residue & 0x3fffffffffffffffff) << 5 ^ v > for i in range(5): > residue ^=3D GEN[i] if ((b >> i) & 1) else 0 > return residue > > def ms32_verify_long_checksum(data): > return ms32_long_polymod(data) =3D=3D MS32_LONG_CONST > > def ms32_create_long_checksum(data): > values =3D data > polymod =3D ms32_long_polymod(values + [0] * 15) ^ MS32_LONG_CONST > return [(polymod >> 5 * (14 - i)) & 31 for i in range(15)] > > > A long codex32 string follows the same specification as a regular codex32 > string with the following changes. > > * The payload is a sequence of between 75 and 103 Bech32 characters. > * The checksum consists of 15 Bech32 characters as defined above. > > A codex32 string with a data part of 94 or 95 characters is never legal a= s > a regular codex32 string is limited to 93 data characters and a long > codex32 string is at least 96 characters. > > Generation of long shares and recovery of the master seed from long share= s > proceeds in exactly the same way as for regular shares with the > ms32_interpolate function. > > The long checksum is designed to be an error correcting code that can > correct up to 4 character substitutions, up to 8 unreadable characters > (called erasures), or up to 15 consecutive erasures. > As with regular checksums we do not specify how an implementation should > implement error correction, and all our recommendations for error > correction of regular codex32 strings also apply to long codex32 strings. > > =3D=3DRationale=3D=3D > > This scheme is based on the observation that the Lagrange interpolation o= f > valid codewords in a BCH code will always be a valid codeword. > This means that derived shares will always have valid checksum, and a > sufficient threshold of shares with valid checksums will derive a secret > with a valid checksum. > > The header system is also compatible with Lagrange interpolation, meaning > all derived shares will have the same identifier and will have the > appropriate share index. > This fact allows the header data to be covered by the checksum. > > The checksum size and identifier size have been chosen so that the > encoding of 128-bit seeds and shares fit within 48 characters. > This is a standard size for many common seed storage formats, which has > been popularized by the 12 four-letter word format of the BIP-0039 mnemon= ic. > > The 13 character checksum is adequate to correct 4 errors in up to 93 > characters (80 characters of data and 13 characters of the checksum). Thi= s > is somewhat better quality than the checksum used in SLIP-0039. > > For 256-bit seeds and shares our strings are 74 characters, which fits > into the 96 character format of the 24 four-letter word format of the > BIP-0039 mnemonic, with plenty of room to spare. > > A longer checksum is needed to support up to 512-bit seeds, the longest > seed length specified in BIP-0032, as the 13 character checksum isn't > adequate for more than 80 data characters. > While we could use the 15 character checksum for both cases, we prefer to > keep the strings as short as possible for the more common cases of 128-bi= t > and 256-bit master seeds. > We only guarantee to correct 4 characters no matter how long the string i= s. > Longer strings mean more chances for transcription errors, so shorter > strings are better. > > The longest data part using the regular 13 character checksum is 93 > characters and corresponds to a 400-bit secret. > At this length, the prefix MS1 is not covered by the checksu= m. > This is acceptable because the checksum scheme itself requires you to kno= w > that the MS1 prefix is being used in the first place. > If the prefix is damaged and a user is guessing that the data might be > using this scheme, then the user can enter the available data explicitly > using the suspected MS1 prefix. > > =3D=3DBackwards Compatibility=3D=3D > > codex32 is an alternative to BIP-0039 and SLIP-0039. > It is technically possible to derive the BIP32 master seed from seed word= s > encoded in one of these schemes, and then to encode this seed in codex32. > For BIP-0039 this process is irreversible, since it involves hashing the > original words. > Furthermore, the resulting seed will be 512 bits long, which may be too > large to be safely and conveniently handled. > > SLIP-0039 seed words can be reversibly converted to master seeds, so it i= s > possible to interconvert between SLIP-0039 and codex32. > However, SLIP-0039 '''shares''' cannot be converted to codex32 shares > because the two schemes use a different underlying field. > > The authors of this BIP do not recommend interconversion. > Instead, users who wish to switch to codex32 should generate a fresh seed > and sweep their coins. > > =3D=3DReference Implementation=3D=3D > > * [https://secretcodex32.com/docs/2023-02-14--bw.ps Reference PostScript > Implementation] > * FIXME add Python implementation > * FIXME add Rust implementation > > =3D=3DTest Vectors=3D=3D > > =3D=3D=3DTest vector 1=3D=3D=3D > > This example shows the codex32 format, when used without splitting the > secret into any shares. > The data part contains 26 Bech32 characters, which corresponds to 130 > bits. We truncate the last two bits in order to obtain a 128-bit master > seed. > > codex32 secret (Bech32): > ms10testsxxxxxxxxxxxxxxxxxxxxxxxxxx4nzvca9cmczlw > > Master secret (hex): 318c6318c6318c6318c6318c6318c631 > > * human-readable part: ms > * separator: 1 > * k value: 0 (no secret splitting) > * identifier: test > * share index: s (the secret) > * data: xxxxxxxxxxxxxxxxxxxxxxxxxx > * checksum: 4nzvca9cmczlw > > =3D=3D=3DTest vector 2=3D=3D=3D > > This example shows generating a new master seed using "random" codex32 > shares, as well as deriving an additional codex32 share, using ''k''=3D2 = and > an identifier of NAME. > Although codex32 strings are canonically all lowercase, it's also valid t= o > use all uppercase. > > Share with index A: > MS12NAMEA320ZYXWVUTSRQPNMLKJHGFEDCAXRPP870HKKQRM > > Share with index C: > MS12NAMECACDEFGHJKLMNPQRSTUVWXYZ023FTR2GDZMPY6PN > > * Derived share with index D: > MS12NAMEDLL4F8JLH4E5VDVULDLFXU2JHDNLSM97XVENRXEG > * Secret share with index S: > MS12NAMES6XQGUZTTXKEQNJSJZV4JV3NZ5K3KWGSPHUH6EVW > * Master secret (hex): d1808e096b35b209ca12132b264662a5 > > Note that per BIP-0173, the lowercase form is used when determining a > character's value for checksum purposes. > In particular, given an all uppercase codex32 string, we still use > lowercase ms as the human-readable part during checksum > construction. > > =3D=3D=3DTest vector 3=3D=3D=3D > > This example shows splitting an existing 128-bit master seed into "random= " > codex32 shares, using ''k''=3D3 and an identifier of cash. > We appended two zero bits in order to obtain 26 Bech32 characters (130 > bits of data) from the 128-bit master seed. > > Master secret (hex): ffeeddccbbaa99887766554433221100 > > Secret share with index s: > ms13cashsllhdmn9m42vcsamx24zrxgs3qqjzqud4m0d6nln > > Share with index a: > ms13casha320zyxwvutsrqpnmlkjhgfedca2a8d0zehn8a0t > > Share with index c: > ms13cashcacdefghjklmnpqrstuvwxyz023949xq35my48dr > > * Derived share with index d: > ms13cashd0wsedstcdcts64cd7wvy4m90lm28w4ffupqs7rm > * Derived share with index e: > ms13casheekgpemxzshcrmqhaydlp6yhms3ws7320xyxsar9 > * Derived share with index f: > ms13cashf8jh6sdrkpyrsp5ut94pj8ktehhw2hfvyrj48704 > > Any three of the five shares among acdef can be used to > recover the secret. > > Note that the choice to append two zero bits was arbitrary, and any of th= e > following four secret shares would have been valid choices. > However, each choice would have resulted in a different set of derived > shares. > > * ms13cashsllhdmn9m42vcsamx24zrxgs3qqjzqud4m0d6nln > * ms13cashsllhdmn9m42vcsamx24zrxgs3qpte35dvzkjpt0r > * ms13cashsllhdmn9m42vcsamx24zrxgs3qzfatvdwq5692k6 > * ms13cashsllhdmn9m42vcsamx24zrxgs3qrsx6ydhed97jx2 > > =3D=3D=3DTest vector 4=3D=3D=3D > > This example shows converting a 256-bit secret into a codex32 secret, > without splitting the secret into any shares. > We appended four zero bits in order to obtain 52 Bech32 characters (260 > bits of data) from the 256-bit secret. > > 256-bit secret (hex): > ffeeddccbbaa99887766554433221100ffeeddccbbaa99887766554433221100 > > * codex32 secret: > ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqqtum9pg= v99ycma > > Note that the choice to append four zero bits was arbitrary, and any of > the following sixteen codex32 secrets would have been valid: > > * > ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqqtum9pg= v99ycma > * > ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqpj82dp3= 4u6lqtd > * > ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqzsrs4pn= h7jmpj5 > * > ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqrfcpap2= w8dqezy > * > ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqy5tdvph= n6znrf0 > * > ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyq9dsuypw= 2ragmel > * > ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqx05xupv= gp4v6qx > * > ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyq8k0h5p4= 3c2hzsk > * > ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqgum7hpl= mjtr8ks > * > ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqf9q0lpx= zt5clxq > * > ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyq28y48py= qfuu7le > * > ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqt7ly0pa= esr8x0f > * > ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqvrvg7pq= ydv5uyz > * > ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqd6hekpe= a5n0y5j > * > ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqwcnrwpm= lkmt9dt > * > ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyq0pgjxpz= x0ysaam > > =3D=3D=3DTest vector 5=3D=3D=3D > > This example shows generating a new 512-bit master seed using "random" > codex32 characters and appending a checksum. > The payload contains 103 Bech32 characters, which corresponds to 515 bits= . > The last three bits are discarded when converting to a 512-bit master see= d. > > This is an example of a '''Long codex32 String'''. > > * Secret share with index S: > MS100C8VSM32ZXFGUHPCHTLUPZRY9X8GF2TVDW0S3JN54KHCE6MUA7LQPZYGSFJD6AN= 074RXVCEMLH8WU3TK925ACDEFGHJKLMNPQRSTUVWXY06FHPV80UNDVARHRAK > * Master secret (hex): > dc5423251cb87175ff8110c8531d0952d8d73e1194e95b5f19d6f9df7c01111104c= 9baecdfea8cccc677fb9ddc8aec5553b86e528bcadfdcc201c17c638c47e9 > > =3D=3DAppendix=3D=3D > > =3D=3D=3DMathematical Companion=3D=3D=3D > > Below we use the Bech32 character set to denote values in GF[32]. > In Bech32, the letter Q denotes zero and the letter > P denotes one. > The digits 0 and 2 through 9 do > ''not'' denote their numeric values. > They are simply elements of GF[32]. > > The generating polynomial for our BCH code is as follows. > > We extend GF[32] to GF[1024] by adjoining a primitive cube root of unity, > =CE=B6, satisfying =CE=B6^2 =3D =CE=B6 + P. > > We select =CE=B2 :=3D G =CE=B6 which has order 93, and const= ruct the > product (x - =CE=B2^i) for i in {17, 20, = 46, 49, > 52, 77, 78, 79, 80, 81, 82, 83, 84}. > The resulting polynomial is our generating polynomial for our 13 characte= r > checksum: > > x^13 + E x^12 + M x^11 + 3 x^10 + G x^9 + Q x^8 + E x^7 + E x^6 + E > x^5 + L x^4 + M x^3 + C x^2 + S x + S > > For our long checksum, we select =CE=B3 :=3D E + X =CE=B6, w= hich has > order 1023, and construct the product (x - =CE=B3^i) for > i in {32, 64, 96, 895, 927, 959, 991, 1019, 1020, 1021= , > 1022, 1023, 1024, 1025, 1026}. > The resulting polynomial is our generating polynomial for our 15 characte= r > checksum for long strings: > > x^15 + 0 x^14 + 2 x^13 + E x^12 + 6 x^11 + F x^10 + E x^9 + 4 x^8 + X > x^7 + H x^6 + 4 x^5 + X x^4 + 9 x^3 + K x^2 + Y x^1 + H > > (Reminder: the character 0 does ''not'' denote the zero of > the field.) > > -----END BIP----- > _______________________________________________ > bitcoin-dev mailing list > bitcoin-dev@lists.linuxfoundation.org > https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev > --=20 Best Regards / S pozdravom, Pavol "Stick" Rusnak Co-Founder, SatoshiLabs --000000000000cf72bd05f4cfce1c Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Hi!

The BIP states that its only advant= age over SLIP-0039, which has been used in production for nearly three year= s (in at at least 3 SW/HW wallet implementations), is that it aims to be si= mple enough for hand computation. However, the BIP also indicates that &quo= t;details of hand computation are outside = the scope of this standard, and implementers do not need to be concerned wi= th this possibility." Therefore, I am curious about how signifi= cant this advantage over SLIP-0039 really is. If hand computation is not st= raightforward and there are no other substantial advantages over SLIP-0039,= I cannot help but feel that this BIP is simply a result of not-invented-he= re syndrome, but please correct me if I am wrong.

= Keep in mind=C2=A0that the encoded shares in SLIP-0039 consist of exactly 2= 00 or 330 bits, both of which are divisible by 5. This makes it straightfor= ward to encode them as Bech32 strings.

On Thu, 16 Feb 2023 at 09:30, R= ussell O'Connor via bitcoin-dev <bitcoin-dev@lists.linuxfoundation.org> wrote:<= br>
I've been ask= ed by Dr. Curr and Professor Snead to forward this message to=C2=A0<= /div>
this mailin= g list, as it may be of general interest to Bitcoin users.=C2=A0

Dear Colleague:=C2=A0

In 1967, during excavation f= or the construction of a new shopping center in=C2=A0
Monroeville, Pennsylvania= , workers uncovered a vault containing a cache of=C2=A0
ancient scrolls[1].=C2=A0= Most were severely damaged, but those that could be=C2=A0
recovered confirmed t= he existence of a secret society long suspected to have=C2=A0
<= div id=3D"m_6526893476585381914gmail-magicdomid11">been active in the= region around the year 200 BC.=C2=A0

Based on a translation of these documents, we now know = that the society, the=C2=A0
Cult of the Bound Variable, was devoted to the caref= ul study of computation,=C2=A0
over two millennia before the invention of the di= gital computer.=C2=A0

While the Monroeville scrolls make reference to computing machines made= of=C2=A0
<= span>sandstone, most researchers believed this to be a poetic metaphor and = that the=C2=A0
"computers" were in fact the initiates themselves, carr= ying out the=C2=A0
unimaginably tedious steps of their computations with reed pe= ns on parchment.=C2=A0

Within the vault, a collection of sandstone wheels mark= ed in a language=C2=A0
consisting of 32 glyphs was found. After 15 years of stu= dy, we have successfully
completed the translation of what is know= n as "Codex32," a document that<= /div>
describes t= he functions of the wheels. It was discovered that the<= span> wheels operate
a system of cryptographic computations that was used by cult members to
safeguard th= eir most valuable secrets.

The Codex32 system allows secrets to be= carved into multiple tablets and
scattered to the far corners of the earth. Whe= n a sufficient number of tablets are
brought together the stone wheels are mani= pulated in a manner to recover the
secrets. This finding may be of= particular interest to the Bitcoin community.

Below we provide a summary of the cult's s= ecret sharing system, which is
graciously hosted at<= /span>




= -----BEGIN BIP-----

<pre>
=C2=A0 BIP: ????
=C2=A0 Layer: Applications
=C2=A0 Title: codex32
=C2=A0 Author: = Leon Olsson Curr and Pearlwort Sneed <pearlwort@wpsoftware.net>
=C2=A0 Comments-URI= : https://github.com/bit= coin/bips/wiki/Comments:BIP-????
=C2=A0 Status: Draft
=C2=A0 Type: ????
=C2=A0 Created= : 2023-02-13
=C2=A0 License: BSD-3-Clause
=C2=A0 Post-History: FIXME
</pre>

=3D=3DIntroduction=3D=3D=

=
=3D=3D=3DAbstract= =3D=3D=3D
<= br>
This doc= ument describes a standard for backing up and restoring the master seed of = a
[https://github.com= /bitcoin/bips/blob/master/bip-0032.mediawiki BIP-0032] hie= rarchical deterministic wallet, using Shamir's secret sharing.
It includes a= n encoding format, a BCH error-correcting checksum, and algorithms for shar= e generation and secret recovery.
Secret data can be split into up to 31 shares.=
A mi= nimum threshold of shares, which can be between 1 and 9, is needed to recov= er the secret, whereas without sufficient shares, no information about the = secret is recoverable.

<= span>=3D=3D=3DCopyright=3D=3D=3D

This document is licensed under the 3-clause BSD license.

=3D=3D=3DMotivation= =3D=3D=3D
<= br>
BIP-0032= master seed data is the source entropy used to derive all private keys in = an HD wallet.
Safely storing this secret data is the hardest and most important = part of self-custody.
However, there is a tension between security, which demand= s limiting the number of backups, and resilience, which demands widely repl= icated backups.
Encrypting the seed does not change this fundamental tradeoff, s= ince it leaves essentially the same problem of how to back up the encryptio= n key(s).
<= br>
To allow= users freedom to make this tradeoff, we use Shamir's secret sharing, w= hich guarantees that any number of shares less than the threshold leaks no = information about the secret.
This approach allows increasing safety by widely d= istributing the generated shares, while also providing security against the= compromise of one or more shares (as long as fewer than the threshold have= been compromised).

[https://github= .com/satoshilabs/slips/blob/master/slip-0039.md SLIP-0039]= has essentially the same motivations as this standard.
However, unlike SLIP-003= 9, this standard also aims to be simple enough for hand computation.=
Users who d= emand a higher level of security for particular secrets, or have a general = distrust in digital electronic devices, have the option of using hand compu= tation to backup and restore secret data in an interoperable manner.=
Note that h= and computation is optional, the particular details of hand computation are= outside the scope of this standard, and implementers do not need to be con= cerned with this possibility.

[htt= ps://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki BIP-0039] serves the same purpose as this standard: encoding master seeds= for storage by users.
However, BIP-0039 has no error-correcting ability, cannot= sensibly be extended to support secret sharing, has no support for version= ing or other metadata, and has many technical design decisions that make im= plementation and interoperability difficult (for example, the use of SHA-51= 2 to derive seeds, or the use of 11-bit words).

=3D=3DSpecification=3D=3D

=3D=3D=3Dcodex32=3D=3D=3D

A codex32 string is similar t= o a Bech32 string defined in [https://github.com/bitcoin/bips/blob/master/bip-0173.mediawik= i BIP-0173].
It reuses the base32 character set from BIP-0173, = and consists of:

*= A human-readable part, which is the string "ms" (or "MS&quo= t;).
* A separator, which is always "1".
* A data part which is in turn s= ubdivided into:
** A threshold parameter, which MUST be a single digit between = "2" and "9", or the digit "0".
*** If the thresho= ld parameter is "0" then the share index, defined below, MUST hav= e a value of "s" (or "S").
** An identifier consisting of 4= Bech32 characters.
** A share index, which is any Bech32 character. Note that = a share index value of "s" (or "S") is special and deno= tes the unshared secret (see section "Unshared Secret").
** A payload= which is a sequence of up to 74 Bech32 characters. (However, see ''= ;'Long codex32 Strings''' below for an exception to this li= mit.)
** A checksum which consists of 13 Bech32 characters as described below.<= /span>

=
As with Bech32 s= trings, a codex32 string MUST be entirely uppercase or entirely lowercase.<= /span>
The = lowercase form is used when determining a character's value for checksu= m purposes.
For presentation, lowercase is usually preferable, but uppercase SH= OULD be used for handwritten codex32 strings.

=3D=3D=3DChecksum=3D=3D=3D

The last thirteen characters of th= e data part form a checksum and contain no information.
Valid strings MUST pass= the criteria for validity specified by the Python3 code snippet below.
The fun= ction <code>ms32_verify_checksum</code> must return true when i= ts argument is the data part as a list of integers representing the charact= ers converted using the bech32 character table from BIP-0173.
<= div id=3D"m_6526893476585381914gmail-magicdomid118">
To construct a valid checksum= given the data-part characters (excluding the checksum), the <code>m= s32_create_checksum</code> function can be used.

<source lang=3D"python"= ;>
MS32_CONST =3D 0x10ce0795c2fd1e62a

def ms32_polymod(values):
=C2=A0=C2=A0=C2=A0 GEN =3D [
=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 0x19dc500ce73fde210,
=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 0x1bfae00def77fe529,
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0 0x1fbd920fffe7bee52,
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 0x173964= 0bdeee3fdad,
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 0x07729a039cfc75f5a,
=C2=A0= =C2=A0=C2=A0 ]
=C2=A0=C2=A0=C2=A0 residue =3D 0x23181b3
=C2=A0=C2=A0=C2=A0 for v in= values:
<= span>=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 b =3D (residue >> 60)=
=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 residue =3D (residue & 0x0fffff= ffffffffff) << 5 ^ v
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 for i in = range(5):
= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 re= sidue ^=3D GEN[i] if ((b >> i) & 1) else 0
=C2=A0=C2=A0=C2=A0 return = residue
def ms32= _verify_checksum(data):
=C2=A0=C2=A0=C2=A0 if len(data) >=3D 96:=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 # See Long codex32 Strings
=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return ms32_verify_long_checksum(data)
=C2=A0=C2= =A0=C2=A0 if len(data) <=3D 93:
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 r= eturn ms32_polymod(data) =3D=3D MS32_CONST
=C2=A0=C2=A0=C2=A0 return False

def ms32_create_chec= ksum(data):
=C2=A0=C2=A0=C2=A0 if len(data) > 80:=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 # See Long codex32 Strings
=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 return ms32_create_long_checksum(data)
=C2=A0=C2=A0=C2=A0= values =3D data
=C2=A0=C2=A0=C2=A0 polymod =3D ms32_polymod(values + [0] * 13)= ^ MS32_CONST
=C2=A0=C2=A0=C2=A0 return [(polymod >> 5 * (12 - i)) & = 31 for i in range(13)]
</source>

=3D=3D=3DError Correction=3D=3D=3D

A codex32 string without a valid ch= ecksum MUST NOT be used.
The checksum is designed to be an error correcting cod= e that can correct up to 4 character substitutions, up to 8 unreadable char= acters (called erasures), or up to 13 consecutive erasures.
Implementations SHO= ULD provide the user with a corrected valid codex32 string if possible.
However= , implementations SHOULD NOT automatically proceed with a corrected codex32= string without user confirmation of the corrected string, either by prompt= ing the user, or returning a corrected string in an error message and allow= ing the user to repeat their action.
We do not specify how an implementation sh= ould implement error correction. However, we recommend that:

* Implementations make suggest= ions to substitute non-bech32 characters with bech32 characters in some sit= uations, such as replacing "B" with "8", "O" = with "0", "I" with "l", etc.
* Implementations in= terpret "?" as an erasure.
* Implementations optionally interpret oth= er non-bech32 characters, or characters with incorrect case, as erasures.
* If = a string with 8 or fewer erasures can have those erasures filled in to make= a valid codex32 string, then the implementation suggests such a string as = a correction.
* If a string consisting of valid Bech32 characters in the proper= case can be made valid by substituting 4 or fewer characters, then the imp= lementation suggests such a string as a correction.

=3D=3D=3DUnshared Secret=3D=3D=3D

When the share index = of a valid codex32 string (converted to lowercase) is the letter "s&qu= ot;, we call the string a codex32 secret.
The subsequent data characters in a c= odex32 secret, excluding the final checksum of 13 characters, is a direct e= ncoding of a BIP-0032 HD master seed.

The master seed is decoded by converting the data to = bytes:
* Transla= te the characters to 5 bits values using the bech32 character table from BI= P-0173, most significant bit first.
* Re-arrange those bits into groups of 8 bi= ts. Any incomplete group at the end MUST be 4 bits or less, and is discarde= d.

Note that unl= ike the decoding process in BIP-0173, we do NOT require that the incomplete= group be all zeros.

<= span>For an unshared secret, the threshold parameter (the first character o= f the data part) is ignored (beyond the fact it must be a digit for the cod= ex32 string to be valid).
We recommend using the digit "0" for the th= reshold parameter in this case.
The 4 character identifier also has no effect b= eyond aiding users in distinguishing between multiple different master seed= s in cases where they have more than one.

=3D=3D=3DRecovering Master Seed=3D=3D=3D

When the share index of= a valid codex32 string (converted to lowercase) is not the letter "s&= quot;, we call the string an codex32 share.
The first character of the data par= t indicates the threshold of the share, and it is required to be a non-&quo= t;0" digit.

In order to recover a master seed, one needs a set of valid codex32 shares= such that:

* Al= l shares have the same threshold value, the same identifier, and the same l= ength.
* All of the share index values are distinct.
* The number of codex32 shares= is exactly equal to the (common) threshold value.

If all the above conditions are satisfie= d, the <code>ms32_recover</code> function will return a codex32= secret when its argument is the list of codex32 shares with each share rep= resented as a list of integers representing the characters converted using = the bech32 character table from BIP-0173.

<source lang=3D"python">
bech32_inv = =3D [
=C2=A0=C2=A0=C2=A0 0, 1, 20, 24, 10, 8, 12, 29, 5, 11, 4, 9, 6, 28, 26, 3= 1,
= =C2=A0=C2=A0=C2=A0 22, 18, 17, 23, 2, 25, 16, 19, 3, 21, 14, 30, 13, 7, 27,= 15,
]

def bech32_mu= l(a, b):
<= span>=C2=A0=C2=A0=C2=A0 res =3D 0
=C2=A0=C2=A0=C2=A0 for i in range(5):<= /div>
=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 res ^=3D a if ((b >> i) & 1) el= se 0
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 a *=3D 2
=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 a ^=3D 41 if (32 <=3D a) else 0
=C2=A0=C2=A0=C2=A0 retu= rn res
def bech3= 2_lagrange(l, x):
=C2=A0=C2=A0=C2=A0 n =3D 1
=C2=A0=C2=A0=C2=A0 c =3D []
=C2=A0=C2=A0= =C2=A0 for i in l:
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 n =3D bech32_mul(= n, i ^ x)
= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 m =3D 1
=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 for j in l:
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 m =3D bech32_mul(m, (x if i =3D=3D j else i) ^ j)
=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 c.append(m)
=C2=A0=C2=A0=C2=A0 return [bec= h32_mul(n, bech32_inv[i]) for i in c]

def ms32_interpolate(l, x):
=C2=A0=C2=A0=C2=A0 w =3D bech= 32_lagrange([s[5] for s in l], x)
=C2=A0=C2=A0=C2=A0 res =3D []
=C2=A0=C2=A0=C2=A0 = for i in range(len(l[0])):
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 n =3D 0
=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 for j in range(len(l)):
=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 n ^=3D bech32_mul(w[j],= l[j][i])
= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 res.append(n)
=
=C2=A0=C2=A0=C2= =A0 return res

d= ef ms32_recover(l):
=C2=A0=C2=A0=C2=A0 return ms32_interpolate(l, 16)
</source&g= t;

=3D=3D=3DGene= rating Shares=3D=3D=3D

If we already have ''t'' valid codex32 strings such = that:

=
* All stri= ngs have the same threshold value ''t'', the same identifie= r, and the same length
* All of the share index values are distinct

Then we can derive addition= al shares with the <code>ms32_interpolate</code> function by pa= ssing it a list of exactly ''t'' of these codex32 strings, = together with a fresh share index distinct from all of the existing share i= ndexes.
The newly derived share will have the provided share index.

Once a user has generated &= #39;'n'' codex32 shares, they may discard the codex32 secret (i= f it exists).
The ''n'' shares form a ''t'' of = ''n'' Shamir's secret sharing scheme of a codex32 secre= t.

There are two= ways to create an initial set of ''t'' valid codex32 strin= gs, depending on whether the user already has an existing master seed to sp= lit.

<= /div>
=3D=3D=3D= =3DFor an existing master seed=3D=3D=3D=3D

Before generating shares for an existing master = seed, it first must be converted into a codex32 secret, as described above.=
The= conversion process consists of:

* Choosing a threshold value ''t'' between= 2 and 9, inclusive
* Choosing a 4 bech32 character identifier
** We do not define = how to choose the identifier, beyond noting that it SHOULD be distinct for = every master seed the user may need to disambiguate.
* Setting the share index = to "s"
* Setting the payload to a Bech32 encoding of the master seed,= padded with arbitrary bits
* Generating a valid checksum in accordance with th= e Checksum section

Along with the codex32 secret, the user must generate ''t'&#= 39;-1 other codex32 shares, each with the same threshold value, the same id= entifier, and a distinct share index.
The set of share indexes may be chosen ar= bitrarily.
The payload of each of these codex32 shares is chosen uniformly at r= andom such that it has the same length as the payload of the codex32 secret= .
Fo= r each share, a valid checksum must be generated in accordance with the Che= cksum section.

T= he codex32 secret and the ''t''-1 codex32 shares form a set= of ''t'' valid codex32 strings from which additional share= s can be derived as described above.

=3D=3D=3D=3DFor a fresh master seed=3D=3D=3D=3D=

In the case that the u= ser wishes to generate a fresh master seed, the user chooses a threshold va= lue ''t'' and an identifier, then generates ''t'= ;' random codex32 shares, using the generation procedure from the previ= ous section.
As before, each share must have the same threshold value ''= ;t'', the same identifier, and a distinct share index.
=

With this set of ''t= '' codex32 shares, new shares can be derived as discussed above. Th= is process generates a fresh master seed, whose value can be retrieved by r= unning the recovery process on any ''t'' of these shares.

<= div id=3D"m_6526893476585381914gmail-magicdomid278">=3D=3D=3DLong cod= ex32 Strings=3D=3D=3D

= The 13 character checksum design only supports up to 80 data characte= rs.
= Excluding the threshold, identifier and index characters, this limits the p= ayload to 74 characters or 46 bytes.
While this is enough to support the 32-byt= e advised size of BIP-0032 master seeds, BIP-0032 allows seeds to be up to = 64 bytes in size.
We define a long codex32 string format to support these longe= r seeds by defining an alternative checksum.

<source lang=3D"python">
MS32_LONG= _CONST =3D 0x43381e570bf4798ab26

def ms32_long_polymod(values):
=C2=A0=C2=A0=C2=A0 GEN =3D [
=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 0x3d59d273535ea62d897,
=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0 0x7a9becb6361c6c51507,
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0 0x543f9b7e6c38d8a2a0e,
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 = 0x0c577eaeccf1990d13c,
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 0x1887f74f8dc= 71b10651,
= =C2=A0=C2=A0=C2=A0 ]
=C2=A0=C2=A0=C2=A0 residue =3D 0x23181b3
=C2=A0=C2=A0=C2= =A0 for v in values:
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 b =3D (residue = >> 70)
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 residue =3D (residue &a= mp; 0x3fffffffffffffffff) << 5 ^ v
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0 for i in range(5):
=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0 residue ^=3D GEN[i] if ((b >> i) & 1) else 0
=C2=A0= =C2=A0=C2=A0 return residue

def ms32_verify_long_checksum(data):
=C2=A0=C2=A0=C2=A0 return ms32= _long_polymod(data) =3D=3D MS32_LONG_CONST

def ms32_create_long_checksum(data):
=C2=A0=C2=A0=C2= =A0 values =3D data
=C2=A0=C2=A0=C2=A0 polymod =3D ms32_long_polymod(values + [= 0] * 15) ^ MS32_LONG_CONST
=C2=A0=C2=A0=C2=A0 return [(polymod >> 5 * (14= - i)) & 31 for i in range(15)]
</source>

A long codex32 string follows the same spec= ification as a regular codex32 string with the following changes.

* The payload is a sequ= ence of between 75 and 103 Bech32 characters.
* The checksum consists of 15 Bec= h32 characters as defined above.

A codex32 string with a data part of 94 or 95 characters i= s never legal as a regular codex32 string is limited to 93 data characters = and a long codex32 string is at least 96 characters.

Generation of long shares and recovery= of the master seed from long shares proceeds in exactly the same way as fo= r regular shares with the <code>ms32_interpolate</code> functio= n.

The long chec= ksum is designed to be an error correcting code that can correct up to 4 ch= aracter substitutions, up to 8 unreadable characters (called erasures), or = up to 15 consecutive erasures.
As with regular checksums we do not specify how = an implementation should implement error correction, and all our recommenda= tions for error correction of regular codex32 strings also apply to long co= dex32 strings.

= =3D=3DRationale=3D=3D

= This scheme is based on the observation that the Lagrange interpolati= on of valid codewords in a BCH code will always be a valid codeword.=
This means= that derived shares will always have valid checksum, and a sufficient thre= shold of shares with valid checksums will derive a secret with a valid chec= ksum.

=
The header= system is also compatible with Lagrange interpolation, meaning all derived= shares will have the same identifier and will have the appropriate share i= ndex.
This fact allows the header data to be covered by the checksum.

The checksum size and i= dentifier size have been chosen so that the encoding of 128-bit seeds and s= hares fit within 48 characters.
This is a standard size for many common seed st= orage formats, which has been popularized by the 12 four-letter word format= of the BIP-0039 mnemonic.

The 13 character checksum is adequate to correct 4 errors in up = to 93 characters (80 characters of data and 13 characters of the checksum).= This is somewhat better quality than the checksum used in SLIP-0039.

For 256-bit seeds and= shares our strings are 74 characters, which fits into the 96 character for= mat of the 24 four-letter word format of the BIP-0039 mnemonic, with plenty= of room to spare.

A longer checksum is needed to support up to 512-bit seeds, the longest = seed length specified in BIP-0032, as the 13 character checksum isn't a= dequate for more than 80 data characters.
While we could use the 15 character c= hecksum for both cases, we prefer to keep the strings as short as possible = for the more common cases of 128-bit and 256-bit master seeds.
=
We only guarante= e to correct 4 characters no matter how long the string is.
Longer strings mean= more chances for transcription errors, so shorter strings are better.

The longest data par= t using the regular 13 character checksum is 93 characters and corresponds = to a 400-bit secret.
At this length, the prefix <code>MS1</code> is= not covered by the checksum.
This is acceptable because the checksum scheme it= self requires you to know that the <code>MS1</code> prefix is b= eing used in the first place.
If the prefix is damaged and a user is guessing t= hat the data might be using this scheme, then the user can enter the availa= ble data explicitly using the suspected <code>MS1</code> prefix= .

=3D=3DBackward= s Compatibility=3D=3D

= codex32 is an alternative to BIP-0039 and SLIP-0039.
It is technically po= ssible to derive the BIP32 master seed from seed words encoded in one of th= ese schemes, and then to encode this seed in codex32.
For BIP-0039 this proce= ss is irreversible, since it involves hashing the original words.
Furthermore, = the resulting seed will be 512 bits long, which may be too large to be safe= ly and conveniently handled.

SLIP-0039 seed words can be reversibly converted to master see= ds, so it is possible to interconvert between SLIP-0039 and codex32.=
However, S= LIP-0039 '''shares''' cannot be converted to codex3= 2 shares because the two schemes use a different underlying field.

The authors of this BIP= do not recommend interconversion.
Instead, users who wish to switch to codex32= should generate a fresh seed and sweep their coins.

=3D=3DReference Implementation=3D=3D

<= div id=3D"m_6526893476585381914gmail-magicdomid365">* [<= a href=3D"https://secretcodex32.com/docs/2023-02-14--bw.ps" rel=3D"noreferr= er noopener" target=3D"_blank">https://secretcodex32.com/docs/2023-02-14--b= w.ps Reference PostScript Implementation]
* FIXME add Python i= mplementation
* FIXME add Rust implementation

=3D=3DTest Vectors=3D=3D

=3D=3D=3DTest vector 1=3D=3D=3D

This example shows the = codex32 format, when used without splitting the secret into any shares.
The dat= a part contains 26 Bech32 characters, which corresponds to 130 bits. We tru= ncate the last two bits in order to obtain a 128-bit master seed.

codex32 secret (Bech32)= : <code>ms10testsxxxxxxxxxxxxxxxxxxxxxxxxxx4nzvca9cmczlw</code>=

Master secret (= hex): <code>318c6318c6318c6318c6318c6318c631</code>

* human-readable part: <= code>ms</code>
* separator: <code>1</code>
* k value: <code= >0</code> (no secret splitting)
* identifier: <code>test</cod= e>
* share index: <code>s</code> (the secret)
* data: <code>xx= xxxxxxxxxxxxxxxxxxxxxxxx</code>
* checksum: <code>4nzvca9cmczlw<= /code>
=
=3D=3D= =3DTest vector 2=3D=3D=3D

This example shows generating a new master seed using "rando= m" codex32 shares, as well as deriving an additional codex32 share, us= ing ''k''=3D2 and an identifier of <code>NAME</cod= e>.
Although codex32 strings are canonically all lowercase, it's also va= lid to use all uppercase.

Share with index <code>A</code>: <code>MS12NAME= A320ZYXWVUTSRQPNMLKJHGFEDCAXRPP870HKKQRM</code>

Share with index <code>C</= code>: <code>MS12NAMECACDEFGHJKLMNPQRSTUVWXYZ023FTR2GDZMPY6PN</= code>
<= br>
* Deriv= ed share with index <code>D</code>: <code>MS12NAMEDLL4F8J= LH4E5VDVULDLFXU2JHDNLSM97XVENRXEG</code>
* Secret share with index <co= de>S</code>: <code>MS12NAMES6XQGUZTTXKEQNJSJZV4JV3NZ5K3KWGSP= HUH6EVW</code>
* Master secret (hex): <code>d1808e096b35b209ca12132= b264662a5</code>

Note that per BIP-0173, the lowercase form is used when determining = a character's value for checksum purposes.
In particular, given an all uppe= rcase codex32 string, we still use lowercase <code>ms</code> as= the human-readable part during checksum construction.

=3D=3D=3DTest vector 3=3D=3D=3D

This example shows = splitting an existing 128-bit master seed into "random" codex32 s= hares, using ''k''=3D3 and an identifier of <code>cas= h</code>.
We appended two zero bits in order to obtain 26 Bech32 characte= rs (130 bits of data) from the 128-bit master seed.

Master secret (hex): <code>ffeedd= ccbbaa99887766554433221100</code>

Secret share with index <code>s</code>:= <code>ms13cashsllhdmn9m42vcsamx24zrxgs3qqjzqud4m0d6nln</code><= /span>

=
Share with index= <code>a</code>: <code>ms13casha320zyxwvutsrqpnmlkjhgfedc= a2a8d0zehn8a0t</code>

Share with index <code>c</code>: <code>ms13ca= shcacdefghjklmnpqrstuvwxyz023949xq35my48dr</code>

* Derived share with index <code= >d</code>: <code>ms13cashd0wsedstcdcts64cd7wvy4m90lm28w4ffup= qs7rm</code>
* Derived share with index <code>e</code>: <c= ode>ms13casheekgpemxzshcrmqhaydlp6yhms3ws7320xyxsar9</code>=
* Derived = share with index <code>f</code>: <code>ms13cashf8jh6sdrkp= yrsp5ut94pj8ktehhw2hfvyrj48704</code>

Any three of the five shares among <code>= acdef</code> can be used to recover the secret.

Note that the choice to append two = zero bits was arbitrary, and any of the following four secret shares would = have been valid choices.
However, each choice would have resulted in a differen= t set of derived shares.

* <code>ms13cashsllhdmn9m42vcsamx24zrxgs3qqjzqud4m0d6nln<= /code>
= * <code>ms13cashsllhdmn9m42vcsamx24zrxgs3qpte35dvzkjpt0r</co= de>
* <code>ms13cashsllhdmn9m42vcsamx24zrxgs3qzfatvdwq5692k6</code&= gt;
= * <code>ms13cashsllhdmn9m42vcsamx24zrxgs3qrsx6ydhed97jx2</code>=

=3D=3D=3DTest v= ector 4=3D=3D=3D

This example shows converting a 256-bit secret into a codex32 secret, with= out splitting the secret into any shares.
We appended four zero bits in order t= o obtain 52 Bech32 characters (260 bits of data) from the 256-bit secret.

<= div id=3D"m_6526893476585381914gmail-magicdomid436">256-bit secret (h= ex): <code>ffeeddccbbaa99887766554433221100ffeeddccbbaa99887766554433= 221100</code>

* codex32 secret: <code>ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwv= hw4fnzrhve25gvezzyqqtum9pgv99ycma</code>

Note that the choice to append four zero bit= s was arbitrary, and any of the following sixteen codex32 secrets would hav= e been valid:

* = <code>ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqqtu= m9pgv99ycma</code>
* <code>ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahw= vhw4fnzrhve25gvezzyqpj82dp34u6lqtd</code>
* <code>ms10leetsllhdmn9m= 42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqzsrs4pnh7jmpj5</code>
* <co= de>ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqrfcpap2w8= dqezy</code>
* <code>ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fn= zrhve25gvezzyqy5tdvphn6znrf0</code>
* <code>ms10leetsllhdmn9m42vcsa= mx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyq9dsuypw2ragmel</code>
* <code>= ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqx05xupvgp4v6qx&= lt;/code>
* <code>ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve2= 5gvezzyq8k0h5p43c2hzsk</code>
* <code>ms10leetsllhdmn9m42vcsamx24zr= xgs3qrl7ahwvhw4fnzrhve25gvezzyqgum7hplmjtr8ks</code>
* <code>ms10le= etsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqf9q0lpxzt5clxq</co= de>
* <code>ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezz= yq28y48pyqfuu7le</code>
* <code>ms10leetsllhdmn9m42vcsamx24zrxgs3qr= l7ahwvhw4fnzrhve25gvezzyqt7ly0paesr8x0f</code>
* <code>ms10leetsllh= dmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqvrvg7pqydv5uyz</code>=
* &= lt;code>ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyqd6he= kpea5n0y5j</code>
* <code>ms10leetsllhdmn9m42vcsamx24zrxgs3qrl7ahwv= hw4fnzrhve25gvezzyqwcnrwpmlkmt9dt</code>
* <code>ms10leetsllhdmn9m4= 2vcsamx24zrxgs3qrl7ahwvhw4fnzrhve25gvezzyq0pgjxpzx0ysaam</code>

=3D=3D=3DTest vector = 5=3D=3D=3D

This = example shows generating a new 512-bit master seed using "random"= codex32 characters and appending a checksum.
The payload contains 103 Bech32 c= haracters, which corresponds to 515 bits. The last three bits are discarded= when converting to a 512-bit master seed.

This is an example of a '''Long code= x32 String'''.

* Secret share with index <code>S</code>: <code&g= t;MS100C8VSM32ZXFGUHPCHTLUPZRY9X8GF2TVDW0S3JN54KHCE6MUA7LQPZYGSFJD6AN074RXV= CEMLH8WU3TK925ACDEFGHJKLMNPQRSTUVWXY06FHPV80UNDVARHRAK</code><= /div>
* Master se= cret (hex): <code>dc5423251cb87175ff8110c8531d0952d8d73e1194e95b5f19d= 6f9df7c01111104c9baecdfea8cccc677fb9ddc8aec5553b86e528bcadfdcc201c17c638c47= e9</code>

= =3D=3DAppendix=3D=3D

<= span>=3D=3D=3DMathematical Companion=3D=3D=3D

Below we use the Bech32 character set to deno= te values in GF[32].
In Bech32, the letter <code>Q</code> denotes z= ero and the letter <code>P</code> denotes one.
The digits <code&= gt;0</code> and <code>2</code> through <code>9</= code> do ''not'' denote their numeric values.
They are simpl= y elements of GF[32].

= The generating polynomial for our BCH code is as follows.

We extend GF[32] to GF[1024= ] by adjoining a primitive cube root of unity, <code>=CE=B6</code&= gt;, satisfying <code>=CE=B6^2 =3D =CE=B6 + P</code>.

We select <code>= =CE=B2 :=3D G =CE=B6</code> which has order 93, and construct the pro= duct <code>(x - =CE=B2^i)</code> for <code>i</code>= in <code>{17, 20, 46, 49, 52, 77, 78, 79, 80, 81, 82, 83, 84}</co= de>.
The resulting polynomial is our generating polynomial for our 13 charac= ter checksum:

= =C2=A0=C2=A0=C2=A0 x^13 + E x^12 + M x^11 + 3 x^10 + G x^9 + Q x^8 + E x^7 = + E x^6 + E x^5 + L x^4 + M x^3 + C x^2 + S x + S

For our long checksum, we select <code= >=CE=B3 :=3D E + X =CE=B6</code>, which has order 1023, and constr= uct the product <code>(x - =CE=B3^i)</code> for <code>i&l= t;/code> in <code>{32, 64, 96, 895, 927, 959, 991, 1019, 1020, 102= 1, 1022, 1023, 1024, 1025, 1026}</code>.
The resulting polynomial is our = generating polynomial for our 15 character checksum for long strings:

=C2=A0=C2=A0=C2=A0 x^= 15 + 0 x^14 + 2 x^13 + E x^12 + 6 x^11 + F x^10 + E x^9 + 4 x^8 + X x^7 + H= x^6 + 4 x^5 + X x^4 + 9 x^3 + K x^2 + Y x^1 + H

(Reminder: the character <code>0<= /code> does ''not'' denote the zero of the field.)

-----END BIP-----
_______________________________________________
bitcoin-dev mailing list
= bitcoin-dev@lists.linuxfoundation.org
https://lists.linuxfoundation.org/mail= man/listinfo/bitcoin-dev


--
Best Regards / S pozdravom,

Pavol "Sti= ck" Rusnak
Co-Founder, SatoshiLabs
--000000000000cf72bd05f4cfce1c--