Bitcoin Forum
April 26, 2024, 10:27:20 PM *
News: Latest Bitcoin Core release: 27.0 [Torrent]
 
   Home   Help Search Login Register More  
Pages: [1]
  Print  
Author Topic: [BIP] Implementing Multisig Using Taproot  (Read 259 times)
NotATether (OP)
Legendary
*
Offline Offline

Activity: 1582
Merit: 6687


bitcoincleanup.com / bitmixlist.org


View Profile WWW
August 20, 2022, 04:36:26 AM
Last edit: August 20, 2022, 10:48:37 AM by NotATether
Merited by Welsh (4), hugeblack (4), ABCbits (1)
 #1

This BIP builds upon the discussions in the BIP 322 draft design and improvement thread. Consequentually, it was generalized from the specific problem of delegation to implementing Multisig using Taproot script paths in general.

The full text converted to mediawiki format is listed below. I haven't sent this to the mailing list yet.

The comments link will not work yet, because I haven't pushed the BIP to Github either.

Use cases:

- BIP 322 (if they decide to implement delegation)
- LN channels, DLCs, other kinds of contracts, etc...

Code:
<pre>
  BIP: notatether-multisigtaproot
  Layer: Applications
  Title: Implementing Multisig Using Taproot
  Author: Ali Sherief <ali@notatether.com>
  Comments-Summary: No comments yet.
  Comments-URI: https://github.com/ZenulAbidin/bips/wiki/Comments:BIP-notatether-multisigtaproot
  Status: Draft
  Type: Informational
  License: BSD-2-Clause
  Created: 2022-08-19
  Requires: 341, 342
</pre>

== Summary ==

This document defines the proper way to construct Multisig outputs and spends that utilize the privacy provided by Taproot script paths.

== Copyright ==

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

== Abstract ==

A Multisignature (also called Multisig) unspent transaction output (UTXO) attached to an address allows two or more parties to restrict the spending of the UTXO inside the address until a specified number of parties sign the output spending it. Multisig UTXOs are extremely useful for creating contracts, and is therefore used in many applications where delegation of funds to a committee is required, such as in Lightning Network channels, in DLCs (Discrete Log Contracts), and in other kinds of contracts.

== Motivation ==

OP_CHECKMULTISIG has the disadvantage of revealing all co-signer public keys involved in a transaction. This compromises the privacy of those signers. Additionally, this construct is not compatible with Taproot because OP_CHECKMULTISIG is disabled in TapScript, thus those applications are unable to make use of Pay-to-Taproot (P2TR) addresses.

Constructing a Multisig output on Taproot is technically possible, but its implementation has not been specified by any existing BIP, to the author's knowledge. Additionally, most developers of Bitcoin applications do not know how to construct Multisig Taproot outputs.

== Design ==

Taproot gives us three different options for implementing Multisig, each with their own advantages and disadvantages<ref>'''Multisig implementation options reference''' The options were originally enumerated in [https://jimmysong.github.io/taproot-multisig Jimmy Song's slideshow] in a more detailed manner.</ref>:
# Single-leaf with a TapScript implementing K-of-N Multisig. This is functionally equivalent to legacy OP_CHECKMULTISIG, and shares all its advantages and disadvantages. In particular, all public keys of signers are revealed in the TapScript embedded in the first element of the witness program, so the privacy advantages of Taproot are compromised.
# Multiple leaves, each with a TapScript implementing K-of-K Multisig.
# Multiple leaves, each with a TapScript implementing MuSig of K keys (i.e. aggregate of K public keys).

This document uses the second option for implementing Multisig, because it only reveals the public keys of those who sign the transaction.<ref>'''Why wasn't MuSig considered?''' Although MuSig provides even more privacy by not revealing any original public keys all together, it is a cumbersome process to create since K parties must be online not only at one point to create the aggregated keys, but also at another point to create a signature. There is the problem of who will be the trustee of the MuSigs themselves, as opposed to just the delegated UTXOs. Also, There is no BIP that implements MuSig, to the author's knowledge.</ref>

== Specification ==

Notations used here are specified in [[bip-0340.mediawiki#design|BIP340]].

''taproot_output_script'' and ''taproot_sign_script'' refers to the Python functions of [[bip-0341.mediawiki|BIP341]] with the same name.

=== Constructing K-of-N Multisig outputs ===

All of the participating TapScripts must be collected together at construction-time. This implies that all signers must know each other beforehand<ref>'''Why should all signers know each other beforehand?''' Knowing all possible signers of a multisignature is required for many instances of delegation, so that an unknown party cannot insert a rogue signature at spending-time.</ref>.

The algorithm takes as inputs:
* An integer value  ''m'', greater than 0
* An array ''scripts'' of ''m'' TapScripts as byte-arrays.
** The scripts must be written in the following format: "[PubKey p<sub>1</sub>] OP_CHECKSIG [PubKey p<sub>2</sub>] OP_CHECKSIGADD ... [PubKey p<sub>K</sub>] OP_CHECKSIGADD OP_[K] OP_NUMEQUAL"<ref>'''1-of-N Multisig TapScripts''', it is possible to save two bytes in each script by dropping "OP_[K] OP_NUMEQUAL" from the end of each script. Since OP_CHECKSIG will return 1 on success and the empty array on failure, and the script interpreter considers a final stack of truthy values such as 1 as the script succeeding, and likewise for falsy values such as the empty array, the additional OP_NUMEQUAL comparison and associated number push is redundant.</ref>
Where the list p<sub>1</sub> ... p<sub>K</sub> represents a unique combination of K public keys from the total set of N public keys. In this way, each TapScript is a K-of-K multisig, requiring the signatures of all parties participating in the TapLeaf.

And returns as the outputs:
* The scriptPubKey, including the hash of the generated withness program and the push bytes.

Algorithm steps:
# Generate a random private key ''p'', in the range ''[0, n-1]''.
# Set the internal key ''internal_pubkey'' to ''lift_x(0x0250929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0) + p*G''<ref>'''Why is an arbitrary public key used for signing and spending?''' All possible combinations of multisignature spends are already enumerated in the script path, so the internal public key is not only redundant, but a security hazard since it must be specified. Values that will make Taproot validation fail cannot be used. BIP341 advises that in such cases, an internal public key with unknown discrete logarithm should be used.</ref>, where ''G'' is the secp256k1 generator point.
# Set ''script_tree'' to the empty list.
# For each script (''i'' in the range ''[0,m-1]'', convert it into a tuple with first element a byte 0xc0 and second element the script itself, and append it to ''script_tree''.
# Return the result of ''taproot_output_script(internal_pubkey, script_tree)''.


=== Spending K-of-N Multisig outputs ===

Only one of the multisignature TapScripts will be spent in a K-of-N Taproot Multisig.

The algorithm takes as inputs:
* An integer value  ''m'', greater than 0
* An array ''scripts'' of ''m'' TapScripts as byte-arrays, in the format taken by the Multisig Construction algorithm
* An integer value ''j'', greater than 0 and less than ''m'', that indicates which multisignature TapScript will be used to spend the output.
* The witness stack ''inputs'' of the script ''scripts[i]'', as an array of byte-arrays.
** The witness stack must be written in the following format: "[Signature s<sub>K</sub>] [Signature s<sub>K-1</sub>] ... [Signature s<sub>0</sub>]"
Where the list s<sub>1</sub> ... s<sub>K</sub> are the Schnorr signatures corresponding to the public keys p<sub>1</sub> ... p<sub>K</sub>. Note that the list of signatures is coded in the reverse order, because the script interpreter will pop the left-most byte-array as the first stack element, the second-left-most byte array as the second stack element, and so on.

And returns as the outputs:
* The witness, that can spend the scriptPubKey returned by the Multisig Construction algorithm.

Algorithm steps:
# Generate a random private key ''p'', in the range ''[0, n-1]''.
# Set the internal key ''internal_pubkey'' to ''lift_x(0x0250929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0) + p*G''<ref>'''Why is an arbitrary public key used for signing and spending?''' All possible combinations of multisignature spends are already enumerated in the TapLeaves, so the internal public key is not only redundant, but a security hazard since it must be specified. Values that will make Taproot validation fail cannot be used. BIP341 advises that in such cases, an internal public key with unknown discrete logarithm should be used.</ref>.
# Set the internal key ''internal_pubkey'' to ''lift_x(0x0250929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0) + p*G'', where ''G'' is the secp256k1 generator point.
# Set ''script_tree'' to the empty list.
# For each script (''i'' in the range ''[0,m-1]'', convert it into a tuple with first element a byte 0xc0 and second element the script itself, and append it to ''script_tree''.
# Return the result of ''taproot_sign_script(internal_pubkey, script_tree, j, inputs)''.

== Notes ==

[[bip342.mediawiki|BIP342]] mentions that a complete TapBranch of ''k-of-k'' multisignature leaves are "only more cost effective for small values of ''k'' (1-of-''n'' for any ''n'', 2-of-''n'' for ''n &ge; 6'', 3-of-''n'' for ''n &ge; 9'', ...)". Since the scripts are all of fixed size, and the number of TapLeaves can similarly be calculated, it is possible to derive a formula for the relative size in (v)bytes of a spent Multisig Taproot output.
* The size of each script is ''33*K + 2''.
* The size of the control block is ''33 + 32 * ceil(log2(nCr(N,K)))'', where ''nCr'' computes the binomial coefficient of ''N'' and ''K''.
* Therefore, the size of the witness inside the output is ''32*ceil(log2(nCr(N,K))) + 33*K + 35''. A table of output sizes is provided for the first few values of N and K.

N,K,Size (vbytes)
1,1,68
2,1,100
2,2,101
3,1,132
3,2,165
3,3,134
4,1,132
4,2,197
4,3,198
4,4,167
5,1,164
5,2,229
5,3,262
5,4,263
5,5,200
6,1,164
6,2,229
6,3,294
6,4,295
6,5,296
6,6,233

The data shows that 1-of-N Multisig TapScripts have the smallest witness output, and K-of-N Multisig Tapscripts with ''K &gt; 1'' and progressively increasing to ''N-1'' have increasingly larger sizes. Where the K-of-N combination has a smaller size than the equivalent N-of-N combination, it is deemed to be cost-efficient. Hence, since 2 cosigners out of a maximum of 6 makes a transaction size smaller than 6-of-6, 2-of-6 multisig is the largest cost-effective combination for ''N = 6''. If the data is extended, it can similary be proven that 3-of-9 multisig is the largest cost-effective combination for ''N = 9''.<ref>'''Cost-effective delegations''' Several delegation schemes such as Lightning Network channels use only a combination of 1-of-N and N-of-N multisig transactions, with small N &gt; 1.</ref>

The following Python 3.8 code an be used to calculate transaction sizes for ''K &gt; 0'', ''N &gt; 0'', and ''N &ge; K'':

<source lang="python">
>>> import math
>>> txsize = lambda n,k : 32*math.ceil(math.log2(math.comb(n, k))) + 33*k + 35
>>> txsize(1,1)
68
# ...
</source>


== Rationale ==

<references />

== Acknowledgements ==

Thanks to garlonicon, vjudeu, and Ali Ashraf for providing feedback about multisignatures while this document was being written.

This thread is not self-moderated, since there's no existing Taproot Multisig BIP and there 'ought to be one specified, so I feel there is no point in having a moderated discussion about that.

.
.BLACKJACK ♠ FUN.
█████████
██████████████
████████████
█████████████████
████████████████▄▄
░█████████████▀░▀▀
██████████████████
░██████████████
████████████████
░██████████████
████████████
███████████████░██
██████████
CRYPTO CASINO &
SPORTS BETTING
▄▄███████▄▄
▄███████████████▄
███████████████████
█████████████████████
███████████████████████
█████████████████████████
█████████████████████████
█████████████████████████
███████████████████████
█████████████████████
███████████████████
▀███████████████▀
█████████
.
1714170440
Hero Member
*
Offline Offline

Posts: 1714170440

View Profile Personal Message (Offline)

Ignore
1714170440
Reply with quote  #2

1714170440
Report to moderator
The Bitcoin network protocol was designed to be extremely flexible. It can be used to create timed transactions, escrow transactions, multi-signature transactions, etc. The current features of the client only hint at what will be possible in the future.
Advertised sites are not endorsed by the Bitcoin Forum. They may be unsafe, untrustworthy, or illegal in your jurisdiction.
gmaxwell
Moderator
Legendary
*
expert
Offline Offline

Activity: 4158
Merit: 8382



View Profile WWW
August 23, 2022, 07:59:39 AM
Last edit: August 23, 2022, 08:18:42 AM by gmaxwell
Merited by LoyceV (8), Welsh (8), ABCbits (4), hugeblack (4), Hueristic (1), DdmrDdmr (1), NotATether (1)
 #2

Musig(1) K of K doesn't require interaction to create the keys, just to spend using them.  Musig(2) K of N requires interaction both to create and spend.

You could add another branch off the tree such that you have a separate subtree of K of K musig1s, which wouldn't need any interaction to create the thresholds (unlike musig2 k of ns).  They'd be more efficient and private to spend assuming that your signers are online and can afford the interaction, but you could still spend using the k of k paths assuming you weren't.

This would provide more incentive to develop the software and processes to use the musig1.   Doing a musig1 is also really attractive because you can store one of them (ideally the one you think you would be most likely or able to use) in the root for a really efficient spend.

Including the separate tree would have a cost assuming you weren't going to use it-- so it might not be justified on that basis, but including at least one k-way musig1 at the top would be entirely free, and wouldn't end up creating a "random private key" that you have to store.  Just take the any K of the N pubkeys keys (maybe the first?), combine them with musig 1 and stick that in the root instead.  No private data, no interaction, and the users gets the option to spend via that path in the future if their software and process supports it.  I don't keep up with bitcoin development, so maybe there is a good reason you haven't proposed this-- but I can't think of one. musig1 is very simple: essentially just hashing all the pubkeys and a counter for each pubkey to get a deterministic per key randomizer, then multiplying the keys by their randomizers and summing the resulting keys.

Having the _option_ of spending existing coins via more anonymous and radically cheaper path is something the users of a scheme like this would really thank you for in the future should Bitcoin have a period of high fees or deanonymization attacks.

Aside, you I see nothing about your point of "unknown" discrete log that could allow someone to verify that it was in fact unknown,  and a such it could be hiding a backdoor as the document is currently written.

I suggest you consider what I wrote above and do that instead but if you must have a point of unknown discrete log you must generate it by hashing a serialization of G and a counter and lift_xing that and documenting the process of generating it that way.  It's possible that you picked a value from elsewhere that was generated that way, but it must be documented clearly since it's a major attack vector. You could also eliminate the randomizer by making your point of unknown DL be lift_x(H(G||list of all the other pubkeys||counter)) and using the first counter that passes the liftx. Use that directly as the taproot base point, but again, I *really* suggest making your basepoint a musig k-of-k, redundant to one of the ones in the leaves, even if you don't initially expect signers to support using it.

Aside, it was my impression a couple years ago that development of musig software has gone slowly mostly because the industrial participants most interested in writing it (e.g. blockstream) is primarily interested in making software for unattended, automated, byzantine fault tolerant systems.  This means they need a K of N scheme that can still efficiently produce valid signatures with up to M out of  K+M of live participants being malicious.  This is vastly harder than just K of K or  K of N  where if any of the K misbehave the signing jams and its up to the humans to figure it out (which is what happens for a checkmultisig if one of the signers is screwing around).  The more complex use case is a valid one, but many people don't need it-- and CMS like signing that people are using instead of musig(1/2) doesn't really provide it either (though it can be easier to figure out WHY a CMS is failing if a signer is producing junk, AFAICT existing tools don't).


Cheers!
NotATether (OP)
Legendary
*
Offline Offline

Activity: 1582
Merit: 6687


bitcoincleanup.com / bitmixlist.org


View Profile WWW
August 23, 2022, 01:50:58 PM
 #3

Using MuSig1 in that manner is a pretty good idea. I'm thinking about converting the BIP to a Standard kind so I can specify this.

Aside, you I see nothing about your point of "unknown" discrete log that could allow someone to verify that it was in fact unknown,  and a such it could be hiding a backdoor as the document is currently written.

I put the detail about disabling the public key root path because I thought it wasn't necessary. But, reading this feedback, I have the following in mind:

- The first K of the N public keys (numbering starts from the top of the stack as if a single-leaf TapScript of K-of-N multisig was ran) are combined with MuSig1 and placed in the root. It will serve as a kind of cache where the keys that are expected to be used the most are placed on the top.
- The script path will then look like this:
-- nCr(N,K) multisig K-of-K's
-- nCr(N,K) Musig1 K-of-K's (except for the one with the first K keys)

Output size for the will almost double, but when that output is subsequently spent, the input size will remain largely the same.

I envision use cases for this that go something like this: Two or more people want to make a connection, similar to an HTTP connection (Taproot Contract Connection*) that is layered on top of TCP/IP (individual Taproot outputs that have multisig and musig1 leaves) for routing - or in bitcoin's case, stateful channels between addresses, similar to LN. They wish to send and receive bitcoins using that connection, and commit the result to the blockchain once the connection is closed.

The opening of the connection is done with a transaction with all the UTXOs to commit, having a single taproot output constructed with script path and root as specified above. Sending and receiving is accomplished by means of standard transaction creation, where there is exactly one Taproot input and one Taproot output.Users can choose whether they would like to utilize the multisig or musig paths depending on whether the respective connection is interactive or non-interactive. Finally, the commitment transaction which closes the transaction has N outputs, each output distributes the final transaction partition between the N users, which could be less if some users don't get anything at all.

I already see major advantages of this scheme over the current way things like Lightning Network handle connections: Nobody can commit fraud, because everybody has to agree on the next connection state, and consequentially spend that output on the blockchain - hence the connection state is reflected in real-time. There is no stale state broadcasting problem like in Lightning network. Timelocks are not even needed here - the conenction can be left open indefinitely if that is desired.

*I choose to name this construct a "Taproot Contract Connection" instead of Taproot Multisig Connection to avoid implying that it only uses Multisig leaves.

<I might have more to say about this later as I process this feedback>

.
.BLACKJACK ♠ FUN.
█████████
██████████████
████████████
█████████████████
████████████████▄▄
░█████████████▀░▀▀
██████████████████
░██████████████
████████████████
░██████████████
████████████
███████████████░██
██████████
CRYPTO CASINO &
SPORTS BETTING
▄▄███████▄▄
▄███████████████▄
███████████████████
█████████████████████
███████████████████████
█████████████████████████
█████████████████████████
█████████████████████████
███████████████████████
█████████████████████
███████████████████
▀███████████████▀
█████████
.
gmaxwell
Moderator
Legendary
*
expert
Offline Offline

Activity: 4158
Merit: 8382



View Profile WWW
August 23, 2022, 11:25:58 PM
Merited by Welsh (6)
 #4

Output size for the will almost double, but when that output is subsequently spent, the input size will remain largely the same.
Hm? having a whole extra tree of nCr(N,K) will add 32 bytes to the signatures if the root musig1 k-of-k isn't used, but the output will always remain 32 bytes.  Or do you just mean the fully expanded tree size (that never gets communicated with anyone explicitly) will double?  The 32 bytes is no big deal if you're talking about a 15 of 20, but it's a bit expensive for a 2 of 3. Tongue That's why I said it's a trade-off to include the sub leaves.

In fact, for a 2 of 3, I think it's never worth it to include the seperate subtree of musig k of k because the extra tree size matches the savings if the k of k is used.

The musig1 top level root k-of-k is free itself-- so it's always a win to have it. My isn't used comment above is because it lets you skip exposing the tree entirely, so if you will be normally using it the average cost of having that extra hash is very low. 

While speaking about the expanded tree size-- One thing that probably deserves special consideration:  with large N it becomes computationally difficult to enumerate the nCr(N,K) branches (unless K is very small or very large).  N larger than 16 or so is probably annoyingly slow with python or JS code, and N larger than 20 is probably visibly slow with native code. A small hardware wallet might be unusable slow with N>12 if it has to enumerate the tree but I think support could be designed there so the host always does that work.  And regardless of speed, you need to use special hashing code to build the tree or otherwise memory usage to build it crosses a gigabyte at around N=28 (with proper hashing code that works incrementally, the memory needed is log(n) so not an issue).

This is why the checksigadd approach still exists-- doing a tree of K of Ks will always be smaller but it would be straight up intractable to do a 50 of 100 that way.

Thought technically a bip doesn't need to describe an optimized implementation if your design is such that implementer will get thrown by them (and maybe even think the whole proposal is worthless) it can be a good idea to at least raise the issue and point out that solutions exist. Smiley
NotATether (OP)
Legendary
*
Offline Offline

Activity: 1582
Merit: 6687


bitcoincleanup.com / bitmixlist.org


View Profile WWW
August 27, 2022, 09:01:49 AM
 #5

Output size for the will almost double, but when that output is subsequently spent, the input size will remain largely the same.
Hm? having a whole extra tree of nCr(N,K) will add 32 bytes to the signatures if the root musig1 k-of-k isn't used, but the output will always remain 32 bytes.  Or do you just mean the fully expanded tree size (that never gets communicated with anyone explicitly) will double?  The 32 bytes is no big deal if you're talking about a 15 of 20, but it's a bit expensive for a 2 of 3. Tongue That's why I said it's a trade-off to include the sub leaves.

My calculations were related to the tree size, which I completely forgot was not placed in any input or output [outputs have a control block whose size is proportional to log2(number of leaves) but this is negligible for large N.]
In fact, for a 2 of 3, I think it's never worth it to include the seperate subtree of musig k of k because the extra tree size matches the savings if the k of k is used.

Quote
The musig1 top level root k-of-k is free itself-- so it's always a win to have it. My isn't used comment above is because it lets you skip exposing the tree entirely, so if you will be normally using it the average cost of having that extra hash is very low.  

While speaking about the expanded tree size-- One thing that probably deserves special consideration:  with large N it becomes computationally difficult to enumerate the nCr(N,K) branches (unless K is very small or very large).  N larger than 16 or so is probably annoyingly slow with python or JS code, and N larger than 20 is probably visibly slow with native code. A small hardware wallet might be unusable slow with N>12 if it has to enumerate the tree but I think support could be designed there so the host always does that work.  And regardless of speed, you need to use special hashing code to build the tree or otherwise memory usage to build it crosses a gigabyte at around N=28 (with proper hashing code that works incrementally, the memory needed is log(n) so not an issue).

I can't think of any practical use cases for K-of-N signatures (multi- or musig) with large N and medium-sized K. But this proposal gave birth to another idea I was formulating a few weeks ago, related to constructing a "Layer 2" on Layer 1 (mainnet).

Existing L2 solutions like Lightning network keep the intermediate transaction state off the blockchain to save on fees, but this allows for a host of nasty scenarios where the immediate state can be broadcasted - so they attempted to solve that by adding equally complex stuff built using things like timelocks to their own protocol.

What if we can do away with all that, and record the immediate state directly on the blockchain? This can be done by:

- Opening a connection: creating a large N-of-N Musig which has some UTXOs transfered to it
- Coin Distribution: the participants of such a scheme can change the distribution of the coins by creating a transaction which spends the N-of-N and constructs two new transactions: another N-of-N Musig, and a small OP_RETURN transaction that has encoded data of the current partitioning of the funds between addresses.
- Close connection: At any time, the N participants of the Musig can sign a transaction that sends the outputs to the last coin distribution.

Notes:
- If one of the N participants disappears, then everyone's funds are lost forever. To mitigate against spammers joining with dust outputs and then leaving, a minimum (large) UTXO size for joining can be established. This and the fact that there is no possibility for funds recovery incentivices people to stay in the connection until it's closed properly.

- In this scheme, collusion to defaud is impossible - Everyone has to sign the signature for it to be broadcasted, so the would-be defrauded particpants can just abstain from signing the signature.
- Similarly, participants cannot "steal" amounts (including their own) in a future distribution which they have allocated to other, outside, addresses in a previous distribution, because the other participants would not sign such a transaction. Effectively, it means there is no concept of RBF here - which is desireable because it encourages peers to behave as would be optimal in game theory, and that is what makes the connections work.
- The N participants are all different addresses/people whose use case for these connections is to minimize their net fee costs by combining their transactions together. As I mentioned above, all these people have different expenses and the game theory-centric rules described above neither allow participants to steal from each other or from some other service they have paid to in a previous coin distribution.
- While I'm on that subject, it can be said that it does require a specialized ruleset deployed on top of the mainnet i.e. a soft-fork, but if fees continue to increase in the future, architectual limits on the maximum number of participants N in a MuSig could be raised via future BIPs.
- You get privacy for free in this scheme because of Musig, and it's provably auditable (unlike LN).
- Funds recovery from the musig via K(<N)-of-N signatures back to some random address is not allowed for, unlike similarly in Lightning Network, because inherently such a feature is vulnerable to fraud (The PayPal refunds to buyers who actually defrauded their sellers attest to this). This disallows all the cases of "Bob swipes the entire balance in the contract between Alice and Bob". No need to worry about penality transactions etc.
- Everyone's going to view this change as canon, because it's part of Bitcoin Core as opposed to some random programs on the internet that just *happen* to use it.

.
.BLACKJACK ♠ FUN.
█████████
██████████████
████████████
█████████████████
████████████████▄▄
░█████████████▀░▀▀
██████████████████
░██████████████
████████████████
░██████████████
████████████
███████████████░██
██████████
CRYPTO CASINO &
SPORTS BETTING
▄▄███████▄▄
▄███████████████▄
███████████████████
█████████████████████
███████████████████████
█████████████████████████
█████████████████████████
█████████████████████████
███████████████████████
█████████████████████
███████████████████
▀███████████████▀
█████████
.
garlonicon
Hero Member
*****
Offline Offline

Activity: 799
Merit: 1932


View Profile
August 27, 2022, 11:29:17 AM
Last edit: August 27, 2022, 11:49:31 AM by garlonicon
 #6

Quote
But this proposal gave birth to another idea I was formulating a few weeks ago, related to constructing a "Layer 2" on Layer 1 (mainnet)
There are better ways to do that. You can read more about Pedersen Commitments.

1) We can use Taproot address as a public key.
2) People open connections by sending coins to some Taproot public key of "rct=xG+aH(G)". They choose their own "x*G", where "x" could be their Taproot private key. "H(G)" can be replaced by a huge N-of-N multisig, so if everyone agrees, it is possible to get those funds directly, but if there is a disagreement, only the public key is known in such case. Also, "a" is the amount of coins in satoshis.
3) People spend coins by producing key-based signature, if they are able to join all keys and reach a valid signature for "rct".
4) People can also get "a" coins to the "x" Taproot address destination by using SIGHASH_SINGLE|SIGHASH_ANYONECANPAY, probably a separate sighash is needed to handle that.

The last point is the only thing, where any consensus change is needed. It can be also done as a no-fork, but then, constructing proper closing transactions is needed, which makes things more complex than they could be, if it would be possible to directly achieve this last point on-chain.

Edit:
Quote
- Coin Distribution: the participants of such a scheme can change the distribution of the coins by creating a transaction which spends the N-of-N and constructs two new transactions: another N-of-N Musig, and a small OP_RETURN transaction that has encoded data of the current partitioning of the funds between addresses.
You don't need OP_RETURN in this case. You can place a commitment in R-value of your signature, then it would be possible to validate it. The partitioning of the funds will be pushed to the chain anyway, probably in some batched form, so by getting transaction data, it is possible to check if the commitment is valid.

Quote
If one of the N participants disappears, then everyone's funds are lost forever.
That's why closing transactions are needed in the Lightning Network. I think they are needed in your scheme as well, exactly for the same reason.

Quote
To mitigate against spammers joining with dust outputs and then leaving, a minimum (large) UTXO size for joining can be established.
There is no need for such things, because if you add closing transactions, then you can accept and reject UTXOs by signing closing transactions, or rejecting to sign them. Nodes can declare their conditions if needed, in a similar way as they for example declare the minimal satoshis per kilobyte for relaying transactions. Imagine travelling N-of-N Taproot multisig as a compressed equivalent of a CoinJoin transaction, that would simplify things, and hide them even deeper, because it would look like one-input-one-output transaction, so SIGHASH_SINGLE|SIGHASH_ANYONECANPAY can be used on that, to mix it with other transactions.

Hold your horses before deploying blockchain-related things. You don't want to deploy SHA-1 collision without deploying hardened SHA-1. Once you reveal some code, and make it Open Source, there is no "undo" button. Once you share some idea, there is no way to erase it from reader's memory.
NotATether (OP)
Legendary
*
Offline Offline

Activity: 1582
Merit: 6687


bitcoincleanup.com / bitmixlist.org


View Profile WWW
August 28, 2022, 09:26:34 AM
 #7

There are better ways to do that. You can read more about Pedersen Commitments.

1) We can use Taproot address as a public key.
2) People open connections by sending coins to some Taproot public key of "rct=xG+aH(G)". They choose their own "x*G", where "x" could be their Taproot private key. "H(G)" can be replaced by a huge N-of-N multisig, so if everyone agrees, it is possible to get those funds directly, but if there is a disagreement, only the public key is known in such case. Also, "a" is the amount of coins in satoshis.
3) People spend coins by producing key-based signature, if they are able to join all keys and reach a valid signature for "rct".
4) People can also get "a" coins to the "x" Taproot address destination by using SIGHASH_SINGLE|SIGHASH_ANYONECANPAY, probably a separate sighash is needed to handle that.

Never heard of Pedersen commitments before. I have to read up on that.

Edit:
Quote
- Coin Distribution: the participants of such a scheme can change the distribution of the coins by creating a transaction which spends the N-of-N and constructs two new transactions: another N-of-N Musig, and a small OP_RETURN transaction that has encoded data of the current partitioning of the funds between addresses.
You don't need OP_RETURN in this case. You can place a commitment in R-value of your signature, then it would be possible to validate it. The partitioning of the funds will be pushed to the chain anyway, probably in some batched form, so by getting transaction data, it is possible to check if the commitment is valid.

I assume this R value is part of the Pedersen commitment? Because you can't do such a thing with ECDSA or Schnorr.

Quote
If one of the N participants disappears, then everyone's funds are lost forever.
That's why closing transactions are needed in the Lightning Network. I think they are needed in your scheme as well, exactly for the same reason.

Quote
To mitigate against spammers joining with dust outputs and then leaving, a minimum (large) UTXO size for joining can be established.
There is no need for such things, because if you add closing transactions, then you can accept and reject UTXOs by signing closing transactions, or rejecting to sign them. Nodes can declare their conditions if needed, in a similar way as they for example declare the minimal satoshis per kilobyte for relaying transactions. Imagine travelling N-of-N Taproot multisig as a compressed equivalent of a CoinJoin transaction, that would simplify things, and hide them even deeper, because it would look like one-input-one-output transaction, so SIGHASH_SINGLE|SIGHASH_ANYONECANPAY can be used on that, to mix it with other transactions.

I'm not sure how SIGHASH_ANYONECANPAY will help here, when there are Musig's involved. That's because there's only one public key and signature (the combination of all others), so assuming a transaction is modifying only one connection's state, I don't see the point of signing only one input - the only input BTW.

Maybe when starting the connection and funding it with UTXOs, participants can sign their own inputs with SIGHASH_ANYONECANPAY, but then again, this scheme is noninteractive, so they should be able to send in their UTXOs whenever they want, hence single-input transactions to the Musig connection address.

.
.BLACKJACK ♠ FUN.
█████████
██████████████
████████████
█████████████████
████████████████▄▄
░█████████████▀░▀▀
██████████████████
░██████████████
████████████████
░██████████████
████████████
███████████████░██
██████████
CRYPTO CASINO &
SPORTS BETTING
▄▄███████▄▄
▄███████████████▄
███████████████████
█████████████████████
███████████████████████
█████████████████████████
█████████████████████████
█████████████████████████
███████████████████████
█████████████████████
███████████████████
▀███████████████▀
█████████
.
garlonicon
Hero Member
*****
Offline Offline

Activity: 799
Merit: 1932


View Profile
August 28, 2022, 10:45:27 AM
 #8

Quote
I assume this R value is part of the Pedersen commitment? Because you can't do such a thing with ECDSA or Schnorr.
You actually can. For example, in a typical ECDSA signature, you have "r=(k*G).x". You should use random k-value every time to play it safe. But: if you have a hash "h" you want to include, then you can tweak it: "r=k+tweak*G", where "tweak=SHA-256(SHA-256(SHA-256("TapTweak")||SHA-256("TapTweak")||bytes(k*G))||SHA-256(h))". Then, you can later write it as "r=(k*G)+(tweak*G)", so "r=oldR+SHA-256(salt256||SHA-256(h))". Also, you can just convert R-value to a Taproot public key, and validate a commitment by checking if a TapBranch of that matches your commitment.

Quote
I don't see the point of signing only one input - the only input BTW.
If you sign only one input and one output, then your transaction is open for modifications. That means, you can do more things:
1) You can save some satoshis on fees.
2) You can combine it with other transactions, so the amount of your output could be bigger than the amount of your input, because that would allow introducing new participant to the multisig, while someone else is leaving.
3) You can make it always as a combination of different sighashes, then one Schnorr signature can sign one-input-one-output, and another Schnorr signature can sign all outputs, protecting the coins of the leaving participants (or there could be even the third one, signing all inputs to protect those who enter the system). By using different sighashes, the whole thing is more flexible. But without SIGHASH_PREVOUT_SOMETHING, it is incomplete, because it cannot form a chain of off-chain transactions, but for a single transaction it would work.

Quote
Maybe when starting the connection and funding it with UTXOs, participants can sign their own inputs with SIGHASH_ANYONECANPAY, but then again, this scheme is noninteractive, so they should be able to send in their UTXOs whenever they want, hence single-input transactions to the Musig connection address.
I also thought about a different model, but it would still require different sighashes. I thought about combining signatures and sighashes at the same time, so if one signature signs only the first input and the first output, and the second signature signs only the second input and the second output, then the combination of those two should give us a signature that signs both inputs and outputs, so it will look in the same way as SIGHASH_ALL on that.

Hold your horses before deploying blockchain-related things. You don't want to deploy SHA-1 collision without deploying hardened SHA-1. Once you reveal some code, and make it Open Source, there is no "undo" button. Once you share some idea, there is no way to erase it from reader's memory.
Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!