On Wed, Jun 26, 2019 at 08:08:01PM -0400, Russell O'Connor via bitcoin-dev 
wrote:
> I have a comment about the 'input_index' of the transaction digest for taproot
> signatures.  It is currently listed as 2 bytes.  I think it would be better to
> expand that to 4 bytes.

FWIW, I think this would be essentially free, at least for the current
sighash modes, as (I think) all the non-ANYONECANPAY modes have at least
4 bytes of sha256 padding at present.

In addition to (or, perhaps, as a special case of) the reasons Russell
gives, I think this change would also better support proof-of-reserves
via taproot signatures (cf [0] or BIP 127), as it would allow the proof
tx to include more than 65k utxos with each utxo being signed with a
signature that commits to all inputs including the invalid placeholder.

[0] 
https://blockstream.com/2019/02/04/en-standardizing-bitcoin-proof-of-reserves/

If you didn't have this, but wanted to do proof-of-reserves over >65k
taproot UTXOs, you could use ANYONECANPAY signatures, and use the output
amounts to ensure the signatures can't be abused, something like:

   inputs:
     0: spend from txid 0000..0000 vout 0, no witness data
     1: utxo1, signed with ANYONECANPAY|ALL
     2: utxo2, signed with ANYONECANPAY|ALL
     3: utxo3, signed with ANYONECANPAY|ALL
     [etc]

   outputs:
     0: sum(utxo1..utxoN), pay to self
     1: 2099999997690001-sum(utxo1..utxo3), payable to whatever

The total output value is therefore one satoshi more bitcoin than there
could ever have been, so none of the utxoK signatures can be reused on the
blockchain (unless there's severe inflation due to bugs or hardforks),
but the values (and sums) all remain less than 21M BTC so it also won't
fail the current "amount too big" sanity checks.

That seems a bit more fragile/complicated than using SIGHASH_ALL for
everything, though it means your cold wallet doesn't have to serialize
your >65k transactions to verify it's signing what it thinks it is.

> [1]The var-integer field for the number of inputs (and the number of outputs)
> in a transaction looks like it should allow upto 2^64-1 inputs; however this 
> is
> an illusion.  The P2P rules dictate that these values are immediately taken
> modulo 2^32 after decoding.  For example, if the number of inputs is a
> var-integer encoding of 0x0100000001, it is actually just a non-canonical way
> of encoding that there is 1 input.  Try this at home!

Hmm? If I'm following what you mean, that's not the P2P rules, it's the
Unserialize code, in particular:

  compat/assumptions.h:52:static_assert(sizeof(int) == 4, "32-bit int assumed");

  serialize.h:289:uint64_t ReadCompactSize(Stream& is)

  serialize.h-679-template<typename Stream, unsigned int N, typename T, 
typename V>
  serialize.h-680-void Unserialize_impl(Stream& is, prevector<N, T>& v, const 
V&)
  serialize.h-681-{
  serialize.h-682-    v.clear();
  serialize.h:683:    unsigned int nSize = ReadCompactSize(is);

  (and other Unserialize_impl implementations)

However, ReadCompactSize throws "size too large" if the return value is
greater than MAX_SIZE == 0x02000000 =~ 33.5M, which prior to the implicit
cast to 32 bits in Unserialize_impl. And it looks like that check's been
there since Satoshi...

So as far as I can see, that encoding's just unsupported/invalid, rather
than equivalent/non-canonical?

Cheers,
aj

_______________________________________________
bitcoin-dev mailing list
bitcoin-dev@lists.linuxfoundation.org
https://lists.linuxfoundation.org/mailman/listinfo/bitcoin-dev

Reply via email to