-
Notifications
You must be signed in to change notification settings - Fork 667
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feat: Signature order-independence fix for multisig tx #3710
Feat: Signature order-independence fix for multisig tx #3710
Conversation
I just added a second draft to the PR using an additional field in the MultisigSpendingCondition struct, it doesn't remove the rolling hash but adds a correct order vector which helps to verify the multisig tx |
This is nowhere close to being ready. First, adding a new mode of transaction authorization requires a hard fork, with gating logic to ensure that any transaction with this new struct will be unparseable until after the hard fork takes place. It will also require rigorous tests of this gating. Neither is present in this PR. Second, the issues linked calls for order-independent transaction signing and verifying. As in, if Alice, Bob, and Charlie participate in a 2-of-3 multisig, then the order in which any two or more of them sign ought to result in not only the same multisig address, but also the same signatures (and same intermediate sighashes). This requirement is not satisfied with this code. Third, there is zero test coverage for the feature. Even a basic test such as the one above would have demonstrated that this code does not address the problem at hand. |
Hey @jcnelson, thanks a lot for your feedback! And you're right that it's far from being ready, since I have different ways to solve the problem I'm trying to propose potential solutions and start the discussion to select the way before moving forward with autotests with the gating logic which undoubtedly should be present, but before that, we need to figure out the approach to select. |
Stacks multisig addresses are calculated the exact same way the are in Bitcoin (see Suppose Alice, Bob, and Charlie create a 2-of-3 multisig address, with their public keys given in that order. Suppose Alice and Charlie sign. When Alice signs, her signature (but not her public key) is appended to the Now, if you look at What needs to happen is that Charlie's signature must not commit to Alice's signature, but instead to just the initial transaction sighash. While Alice's and Charlie's signatures and Bob's public keys need to be inserted in to the auth structure in the same order in order for |
@jcnelson Oh thanks a lot for the explanation! |
Your code allows Also, I disagree with the approach. There's no need for |
@jcnelson Yeah I understood that, I don't like this approach either that's why it's the second draft |
Hey, I'm sorry for being snippy earlier. I'm glad you have taken the initiative to implement this feature. It's not the most straightforward thing to do, either, so kudos to you for taking this on :) What made me grumpy earlier was all the emails you sent to me and my colleagues to review the PR, despite it being in draft status (i.e. not ready for review). Please don't do that. We're all subscribed to the repository already; we already get emails when PRs come in and get commented on. It sounded like you really, really wanted an assessment despite it not being ready for review. Now to get to your questions:
The rolling hash approach is still required, because it provides linear-time signing and verification. For example, contrast this to Bitcoin's signing and verifying algorithm, which before segwit was quadratic-time. However, the contents of the rolling hash can be different in order to accommodate new signing protocols. In particular, you'd make it so that sighash does not contain the previous signers' signatures and public keys. Insofar as implementation, you'll notice that we have a few different enum variants for spending conditions. An order-independent multisig spending condition would be its own enum variant, with its own ID byte. This way, the block validation logic (which is epoch-gated) can be updated to reject blocks with this new spending condition structure before the hard fork in which this feature will ship takes effect. Within Once you're confident with the new Again, thank you for PR. If you have any questions or concerns in making progress on the above, please drop a comment here :) |
Hey @jcnelson! First of all, thanks so much for your comment, now it's very much clear where to proceed, that's exactly what I was looking for! |
b7facac
to
4852d64
Compare
Hey @jcnelson, @jbencin! Implemented the new logic based on your comments above, supported the recent SIP, added Now For that, I added the
Gating logic added and tested (both sponsored and standard multisig transactions), used Epoch21 for now as a stub, will change it later to the target activation epoch I'm planning to add:
If you have any questions let me know, looking forward to your feedback! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a couple comments, more to come...
@jcnelson can you explain how a rolling hash is required for linear-time signing and verification? I would think whether you use a rolling hash or not, if you have n participants, you will have to produce and validate n signatures, making it an |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks pretty good to me. Definitely make those epoch changes Jude suggested. Also maybe add tests for some different thresholds, like 2-of-9, 5-of-5, or something
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## next #3710 +/- ##
==========================================
- Coverage 83.15% 77.31% -5.85%
==========================================
Files 470 470
Lines 332698 335231 +2533
Branches 317 317
==========================================
- Hits 276663 259171 -17492
- Misses 56027 76052 +20025
Partials 8 8
... and 167 files with indirect coverage changes Continue to review full report in Codecov by Sentry.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well done seeing this through to the end @fess-v!
Let's get that rider SIP added to SIP-021 so this activates in the next hard fork :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This LGTM. Just two minor comments.
Co-authored-by: Brice Dobry <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
578a24f
Description
UPD v2 - removed rolling hash, gating logic implemented for being ready with the Nakamoto release (3.0 epoch)
UPD - check discussion below, decided to leave the rolling hash functionality and remove signatures & public keys from hash creation, add new multisig transaction hash modes following this SIP.
This comment explains this pull request.
OLD:
After the discussion on the SIP call from May 5th, we decided to make a PR with our ideas for fixing the signing ordering issue for multisig transactions.
Forum post with the initial discussion - https://forum.stacks.org/t/implementing-a-fully-functioning-multisig-wallet-on-stacks/14889
SIP PR - stacksgov/sips#139
This PR implements one possible solution for this problem - removing the rolling hash functionality from signing and verification procedures. This seems to be a redundant security measure that adds a lot of restrictions on the signing flow.
It is still a draft though so return types for verification and signing methods as well as test cases should be revised.
If it's required anyway, there's also another solution that we can think of - to unbind the relation of transaction fields to
StacksAddress::from_public_keys
. It can be done for instance via an additional public keys input array (in the multisig address creation order) or a separate index variable in each signing field.An example, where the last parameter in the Signature option is the index in the initial address creation public key array:
In the second scenario, there will still be one restriction on the signing order - other users will have to get the previous signer's signature to continue the signing process. But it won't be critical anymore and will allow to create multisig wallets on Stacks.
Applicable issues
Additional info (benefits, drawbacks, caveats)
It is a consensus-critical change, therefore should be probably included in the next big release/fork of the network.
Solving this issue will open the multisig functionality to a wide range of use cases.
Checklist - TODO
docs/rpc/openapi.yaml
andrpc-endpoints.md
for v2 endpoints,event-dispatcher.md
for new events)clarity-benchmarking
repobitcoin-tests.yml