Fun with CSFS I

In this blog series, I’ll write up some fun uses for CSFS I’m aware of.

The purpose is to document things that others might not know about.

Did I invent these? Maybe. Maybe not. Citations to prior work welcome!

Irreplacable Irreusable Addresses

You create a taproot that is a NUMS keypath (the NUMS keypath and single tapleaf is so that you learn all the spending info always), and a tapleaf that says either a <PK> CHECKSIG, or a proof that there were >1 signatures produced by that key of any data that are distinct from one another and then either:

This means that as soon as you see a signature of a txn with this address, you know that there is no other txn that can be issued without harming the sender by making their funds burnable.

for extra fun:

The “equivocation bond” can be also in a different output, different address, to secure addresses with fresh collateral, even retroactively.

Function Lookup Table Precompiles

Suppose we want to add an opcode to Bitcoin that evaluates f(x).

let X = musig(big one time setup federation).

let CSFS(key, sig, data) = ...

Recall key laddering… make a script with the following logic, via laddering:

CSFS(X, sig_x, sig_arg)
CSFS(Tweaked(X, arg), sig_arg, arg)
CSFS(Tweaked(X, arg), sig_f, f(arg)))
sig_f != sig_arg

now run (in signing committee) f(arg) over all values of arg.

you now get a lookup table that can be used in any script for an arbitrary sized tree for a constant cost of 3 sigs and 2 keys ==> 256 bytes, which is cheaper than using taproot pre-generated trees in many cases.

This technique can be modified to also work for multiple arguments, as long as the result can be precomputed. That rules out “big output spaces” like OP_CAT, but rules in lookup tables like e.g. merkle trees.

And for use cases where, e.g., a merkle tree would be signed by a key anyways, this is trust wise equivalent. E.g., a tree of user balances can be done in this fashion, and any user can “look up” their balance from the signature set.

For “standard library” type uses, big federations can be used for a one-time-trusted-setup.

SIGHASH Flag Detection

Presently, bitcoin scripts cannot restrict which sighash flags are used. CSFS enables a limited version of this in Taproot outoputs. Here’s how:

You can use CSFS to get the tx digest onto the stack from a signature.

without op_cat, this is of limited use…

however, we have the following formula:

^ What is the output length of SigMsg()? The total length of SigMsg() can be computed using the following formula: 174 - is_anyonecanpay * 49 - is_none * 32 + has_annex * 32

which is at most 206 bytes (when has_annex is set).

N.B. This number ends up being + 1 byte sighash epoch, + 64 bytes for the tag in taggedhash.

this means that using CSFS, you can restrict a signature to use some particular sighash flags, by using OP_SIZE.

is_anyonecanpay=0, is_none=0, has_annex=0, size=174+65 is_anyonecanpay=0, is_none=0, has_annex=1, size=206+65 is_anyonecanpay=0, is_none=1, has_annex=0, size=142+65 is_anyonecanpay=0, is_none=1, has_annex=1, size=174+65 is_anyonecanpay=1, is_none=0, has_annex=0, size=125+65 is_anyonecanpay=1, is_none=0, has_annex=1, size=157+65 is_anyonecanpay=1, is_none=1, has_annex=0, size=93+65 is_anyonecanpay=1, is_none=1, has_annex=1, size=125+65

this means you can use CSFS to differentiate flag combos with anyonecanpay and none and annex, except for when is_none + has_annex are both set or unset.

alas, this means you should probably only be interested in the following ability:

is_anyonecanpay=0, is_none=1, has_annex=0, size=142+65 is_anyonecanpay=1, is_none=1, has_annex=0, size=93+65

and less interested but still interested in these, given the annex isn’t standard:

is_anyonecanpay=0, is_none=0, has_annex=1, size=206+65 is_anyonecanpay=1, is_none=0, has_annex=1, size=157+65

note: the other flags can still be set given these ones!

to continue the conversation...

© 2011-2021 Jeremy Rubin. All rights reserved.