Sorry for the repeated replies, but I would like to make one more remark regarding the 1 character "quick check".

Because the 1 character "quick check" state is so small, the procedure becomes simplified to just using a single table.  You start with the specified initial state, which would be the bech32 character '9', and then you have a lookup mapping (<current state>, <next input character>) -> <next state>.  You go through the table for each character after the prefix, updating the state as you go along. ('9','2') -> '0', then ('0','N') -> '4', and so on until you reach the final state which should be '5'.  If you like volvelles, one could be designed to implement this lookup table.

However, I do want to note that an adjustment could be made to the codex32 generator so that this 1 character "quick check" table would become identical to the Bech32 addition table.  In other words the 1 character quick check would become the same as adding up all the characters and checking that you get the required final constant.

If this change were free to make, I would probably make it.  However such an adjustment would come at a cost.  The current generator was chosen to have three identical coefficients in a row (you can find the generator in the appendix of the draft BIP).  This special property slightly eases the computation needed when creating checksums by hand (no compromise to the quality of the checksum itself).  If we made the above adjustment to the codex32 generator, we would lose this property of having three identical coefficients in a row.

Therefore, I am pretty hesitant to make this adjustment.  Firstly the 1 character quick check is simply too small to be safely used.  While it does guarantee to detect single character errors, it has a 1 in 32 chance of failing to detect more errors.  I think a 3% failure rate is pretty bad, and would definitely recommend people performing quick checks use a minimum size of 2 (which has a 0.1% failure rate).  Secondly the difference between using the addition table/volvelle versus a specific table/volvelle for the purpose of performing 1 character quick checks (which you ought not to be doing anyways) is pretty minimal.  The addition table is possibly slightly less error prone to use because it is symmetric, but other than that the amount of work to do is pretty much the same either way.

My conclusion is that it isn't worth compromising the ease of hand computation for the sake of possibly making a too-low-quality-checksum-that-no-one-should-be-using slightly more convenient, but I thought I should mention it at least.


On Wed, Feb 22, 2023 at 10:30 PM Russell O'Connor <roconnor@blockstream.com> wrote:
After some consultation, I now see that generators for all degree 2 BCH codes, such as ours, are smooth and factor into quadratic and linear components.

Anyhow the upshot of all this is that you can perform a "quickcheck" verification of the codex32 strings for whatever size of verification you want to do, 1 character, 2 characters, 3 characters, upto the full 13 characters.  Each of these partial verifications will have BCH properties.  A 1 character quickchecksum will guarantee to detect any 1 character error.  A 3 character quickchecksum will guarantee to detect any 2 character error, etc.  There remains a 1 in 32^n chance of failing to detect larger numbers of errors where n is the size of your quickcheck.

To illustrate, let's consider a quickcheck of size 2.  This can detect any 1 character error and will only have a 1/1024 chance of failing to detect other random errors.  Let's take the second test vector as our example: "MS12NAMEA320ZYXWVUTSRQPNMLKJHGFEDCAXRPP870HKKQRM"

You start in a specified initial state with a pair of bech32 characters.  For MS1 strings and a size 2 quickcheck it would be the pair of Bech32 characters 'AS'.

Next we "add" the first character after the prefix, which is '2' by using the addition volvelle or lookup table.  "Adding" '2' to 'S' yields '6' and our state becomes 'A6'.

Next we have to look up 'A6' in a lookup table.  This table is too big to fit in the margin of this email, so I will have to omit it.  But it would have an entry mapping 'A6' -> 'QM'.  Our state becomes 'QM'

From this point we have an even number of remaining characters in the input string and we can work 2 characters at a time. We "add" the next two data characters from our string, which are 'NA'.  Again, using the volvelle or lookup table we get that adding 'N' to 'Q' yields 'N', and adding 'A' to 'M' yields 'X'.  So our state is now 'NX'

Next we look up 'NX' in this table I haven't given you and we will find an entry mapping 'NX' -> 'DX', making 'DX' our new state.

We keep repeating this process alternating between adding pairs of characters and using this unstated lookup table all the way until the end where we will reach a final state which will be 'H9'.

If you follow this procedure with any string (upto 400 bit master seeds) you will always end up in the state 'H9'.

A specialized worksheet would help guide the process making the process easier to follow.


This process is somewhat close to Peter Todd's suggestion of using a lookup table on "words", which in this case would be pairs of bech32 characters, and adding values together.  The catch is that the addition is done with Bech32 addition rather than calculator addition, which I accept is a moderately large catch.

Anyhow, the point is that you can do this sort of partial verification by hand to whatever degree you like, if you are in a rush and are willing to accept larger chances of failing to catch random errors.


On Wed, Feb 22, 2023 at 2:01 PM Russell O'Connor <roconnor@blockstream.com> wrote:
After some poking around at the math, I do see that the 13 character generator (for regular sized shares) is reasonably "smooth", having roots at T{11}, S{16}, and C{24}.

This means we could build a "quick check" worksheet to evaluate the string modulo (x - T) to verify a 5 bit checksum, whose operation would be similar to the existing checksum worksheet in structure but significantly less work.

Perhaps 5 bits is too short, and it is more reasonable working modulo (x - T)*(x - S) to get a 10 bit checksum.  A worksheet for a 15 bit checksum is also an option, and possibly others well depending on the size of the other factors.  I think this process is would be about as simple as any other comparable hand operated checksum over the bech32 alphabet would be.

I haven't looked into the smoothness of the long generator for seeds that are greater than 400 bits.  If it isn't smooth and smoother options are available, perhaps it should be changed.

On Wed, Feb 22, 2023 at 11:29 AM Peter Todd via bitcoin-dev <bitcoin-dev@lists.linuxfoundation.org> wrote:
On Sun, Feb 19, 2023 at 10:12:51PM +0000, Andrew Poelstra via bitcoin-dev wrote:
> > What really did catch my attention, but which was kind of buried in the
> > project documentation, is the ability to verify the integrity of each
> > share independently without using a computer.  For example, if I store a
> > share with some relative who lives thousands of kilometers away, I'll be
> > able to take that share out of its tamper-evident bag on my annual
> > holiday visit, verify that I can still read it accurately by validating
> > its checksum, and put it into a new bag for another year.  For this
> > procedure, I don't need to bring copies of any of my other shares,
> > allowing them (and my seed) to stay safe.
> >
>
> This is good feedback. I strongly agree that this is the big selling
> point for this -- that you can vet shares/seeds which *aren't* being
> actively used, without exposing them to the sorts of threats associated
> with active use.
>
> We should make this more prominent in the BIP motivation.

I don't think that use-case is a good selling point. The checksum that Codex32
uses is much more complex than necessary if you are simply verifying a share by
itself.

A *much* simpler approach would be to use a simple mod N = 0 checksum, either
by creating the seed such that each share passes, or by just storing an
additional word/symbol with the seed in such a way that sum(words) mod N = 0
passes. This approach is not only possible to compute by hand with a
word/symbol->number lookup table, and pen and paper or a calculator. It's so
simple they could probably *remember* how to do it themselves.


Secondly, if all shares have mod N checksums, it may be sufficient for everyone
to write down the checksums of the *other* shares, to verify they are the
correct ones and a different (otherwise correct) share hasn't accidentally been
substituted.

Indeed, with some brute forcing and small checksums, I'd expect it to be
mathematically possible to generate Shamir's secret sharing shards such that
every shard can share the *same* checksum. In which case the share verification
procedure would be to simply ask every share holder to verify the checksum
manually using the mod N procedure, and then verify that each share holder has
the same checksum. This would be less error prone in terms of leaking
information accidentally if the checksum was obviously *not* part of the share:
eg by encoding the share with words, and the checksum with a number.

Obviously, small checksums aren't fool proof. But we're probably better off
creating a relatively easy procedure with a 1-in-1000 chance of an error going
undetected than a complex procedure that people don't actually do at all.

--
https://petertodd.org 'peter'[:-1]@petertodd.org
_______________________________________________
bitcoin-dev mailing list
bitcoin-dev@lists.linuxfoundation.org
https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev