Skip to content
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: consensus on successful DKG prior to rotate-keys submission #1285

Merged
merged 57 commits into from
Feb 6, 2025

Conversation

cylewitruk
Copy link
Member

@cylewitruk cylewitruk commented Jan 30, 2025

Description

During DKG it is possible in certain situations, particularly when Bitcoin flash blocks occur while DKG is running, that DKG may succeed as observed by a majority of the signers, but actually fail for a subset. This can result in a coordinator in a such situation proceeding to rotate keys, which will succeed as long as threshold signers sign with their Stacks private key.

Part of: #1300

⚠️ This PR targets #1287 and is targeted by #1301, which needs to merge into this branch before this branch merges into #1287's branch.

This builds on-top of @xoloki 's #1265 with feat/frost-coordinator merged in (though now I have downgraded to WSTS 10) and proposes running a FROST signing round prior to signing and submitting a rotate-keys contract call. In short, it's basically exploiting FROST's requirement of 100% participation to act as a consensus mechanism for a preceding DKG round and provides a solid guarantee that a rotate-keys transaction can never be signed/submitted even in the event of multiple byzantine or faulty coordinators and/or signers.

  1. After a DKG round has completed successfully (at least in the eyes of the coordinator), the coordinator initiates a FROST signing round on some random data using the newly generated DKG keys.
  2. Each signer instantiates their own FROST coordinator state machine in addition to the regular Signer state machine. This state machine id is keyed on the new aggregate key + the current chain tip.
  3. All signing-related messages are passed to both state machines, however only the Signer state machine publishes any messages to the other signers. In effect, each signer is acting as a "passive" coordinator. As FROST requires 100% participation, this gives us the side-effect that all signers must observe that all other signers have successfully participated in the signing round using the new key shares, and that we have generated a valid signature.
  4. Upon completion of the signing round, each signer caches the signing result from its FROST coordinator.
  5. Given success, the sBTC coordinator for the tenure will proceed to attempt to create, sign and submit the corresponding rotate-keys transaction.
  6. When the Stacks signing request is received by the other signers, the signers will check the cached result of the preceding FROST signing round, and refuse to sign if it was not successful, didn't complete or was never run.

P.S. I'm not in love with a lot of the naming/messages, but in favor of getting this done I opted to not spend much time thinking on it -- it's easy to change later. But if you've got some awesome names, plz do suggest :)

Changes

Will update this later, have some cleaning up to do and will probably split some stuff out into separate PRs.

Testing Information

All existing tests pass and devenv works like a dream.

Checklist:

  • I have performed a self-review of my code
  • My changes generate no new warnings
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

@cylewitruk cylewitruk added the key rotation The functionality to rotate a private key for a signer in sBTC-v1. label Jan 30, 2025
@cylewitruk cylewitruk added this to the sBTC: Deposits milestone Jan 30, 2025
@cylewitruk cylewitruk self-assigned this Jan 30, 2025
@cylewitruk cylewitruk requested a review from aldur January 30, 2025 02:37
signer/src/transaction_coordinator.rs Show resolved Hide resolved
signer/src/transaction_coordinator.rs Show resolved Hide resolved
signer/src/transaction_coordinator.rs Show resolved Hide resolved
signer/src/transaction_signer.rs Outdated Show resolved Hide resolved
signer/src/transaction_signer.rs Outdated Show resolved Hide resolved
signer/src/transaction_signer.rs Outdated Show resolved Hide resolved
signer/src/transaction_signer.rs Outdated Show resolved Hide resolved
signer/src/transaction_signer.rs Show resolved Hide resolved
signer/src/transaction_signer.rs Outdated Show resolved Hide resolved
signer/src/transaction_signer.rs Outdated Show resolved Hide resolved
Copy link
Collaborator

@xoloki xoloki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, module a couple of quibbles

signer/src/transaction_coordinator.rs Show resolved Hide resolved
signer/src/transaction_signer.rs Outdated Show resolved Hide resolved
signer/src/transaction_signer.rs Outdated Show resolved Hide resolved
signer/src/transaction_signer.rs Show resolved Hide resolved
@cylewitruk cylewitruk changed the base branch from refactor/wsts-cleanup to main February 5, 2025 21:36
Copy link
Collaborator

@matteojug matteojug left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, new comments can be addressed directly in #1301 (if still relevant)

signer/src/transaction_signer.rs Show resolved Hide resolved
signer/src/transaction_signer.rs Show resolved Hide resolved
signer/src/transaction_signer.rs Show resolved Hide resolved
@cylewitruk cylewitruk merged commit 2168f58 into main Feb 6, 2025
8 checks passed
cylewitruk added a commit that referenced this pull request Feb 7, 2025
commit 2168f58
Author: Cyle Witruk <[email protected]>
Date:   Thu Feb 6 16:08:22 2025 +0100

    feat: consensus on successful DKG prior to rotate-keys submission (#1285)

    * update for wsts 11

    * use wsts 11.0.0 from crates

    * fix rebase

    * use wsts-12.0.0 from crates

    * add FrostCoordinator to wsts_state_machine so we can run signing rounds where all signers must participate

    * wip

    * run a dkg signing before deploying contracts

    * new wsts commit

    * wip

    * seems to work

    * working version

    * remove dead code

    * minor wsts logging tweaks

    * rename wstsmessageid variant

    * it works, now need to clean up

    * downgrade wsts

    * proto backwards compatability fixes

    * some wsts cleanup/refactor

    * think that's it

    * add message support for a specific dkg wstsmessageid

    * add a dkg wstsmessageid variant

    * use block hash instead of random data

    * fmt

    * remove 100% requirement for stacks signing of rotate keys

    * bump p256k1 to 7.2.2

    * fix merge artifacts

    * tracing fields

    * storage mut

    * lovely cascading changes

    * remove wstsmessage.txid infavor of id

    * remove save and prefer trait default impls

    * remove unused trait methods

    * logging stuff

    * rename message ids

    * use tracing constants

    * remove stale comment

    * remove box from some types

    * missed dkg_begin_pause

    * leftover dbg!()

    * refactor some validation

    * various pr comments

    * mut thing

    * remove unneeded allow(deprecated)

    * confused merge tool

    ---------

    Co-authored-by: Joey Yandle <[email protected]>
cylewitruk added a commit that referenced this pull request Feb 7, 2025
* update for wsts 11

* use wsts 11.0.0 from crates

* fix rebase

* use wsts-12.0.0 from crates

* add FrostCoordinator to wsts_state_machine so we can run signing rounds where all signers must participate

* wip

* run a dkg signing before deploying contracts

* new wsts commit

* wip

* seems to work

* working version

* remove dead code

* minor wsts logging tweaks

* rename wstsmessageid variant

* it works, now need to clean up

* downgrade wsts

* proto backwards compatability fixes

* some wsts cleanup/refactor

* think that's it

* add message support for a specific dkg wstsmessageid

* add a dkg wstsmessageid variant

* use block hash instead of random data

* fmt

* remove 100% requirement for stacks signing of rotate keys

* bump p256k1 to 7.2.2

* pop stash

* wip

* working verifications

* saving

* fixing tests

* seems to work

* remove const generic, use 0 amount and add test for random keypair

* vet bitcoinconsensus

* working on cleaning up

* fix merge artifacts

* tracing fields

* migration needs to update block hash/height

* storage mut

* lovely cascading changes

* remove wstsmessage.txid infavor of id

* remove save and prefer trait default impls

* remove unused trait methods

* logging stuff

* rename message ids

* use tracing constants

* remove stale comment

* remove box from some types

* missed dkg_begin_pause

* leftover dbg!()

* refactor some validation

* various pr comments

* mut thing

* remove unneeded allow(deprecated)

* import some changes manually from parent branch to help a confused merge tool

* more diff-reducing imports

* confused merge tool

* reduce diff

* add validation for nonceresponse + signatureshareresponse

* newline

* pr comments

* pr comments utxo

* utxo comments

* remove error conversion method

* Squashed commit of the following:

commit 2168f58
Author: Cyle Witruk <[email protected]>
Date:   Thu Feb 6 16:08:22 2025 +0100

    feat: consensus on successful DKG prior to rotate-keys submission (#1285)

    * update for wsts 11

    * use wsts 11.0.0 from crates

    * fix rebase

    * use wsts-12.0.0 from crates

    * add FrostCoordinator to wsts_state_machine so we can run signing rounds where all signers must participate

    * wip

    * run a dkg signing before deploying contracts

    * new wsts commit

    * wip

    * seems to work

    * working version

    * remove dead code

    * minor wsts logging tweaks

    * rename wstsmessageid variant

    * it works, now need to clean up

    * downgrade wsts

    * proto backwards compatability fixes

    * some wsts cleanup/refactor

    * think that's it

    * add message support for a specific dkg wstsmessageid

    * add a dkg wstsmessageid variant

    * use block hash instead of random data

    * fmt

    * remove 100% requirement for stacks signing of rotate keys

    * bump p256k1 to 7.2.2

    * fix merge artifacts

    * tracing fields

    * storage mut

    * lovely cascading changes

    * remove wstsmessage.txid infavor of id

    * remove save and prefer trait default impls

    * remove unused trait methods

    * logging stuff

    * rename message ids

    * use tracing constants

    * remove stale comment

    * remove box from some types

    * missed dkg_begin_pause

    * leftover dbg!()

    * refactor some validation

    * various pr comments

    * mut thing

    * remove unneeded allow(deprecated)

    * confused merge tool

    ---------

    Co-authored-by: Joey Yandle <[email protected]>

* Change the DKG shares status type.
Lots of small follow-up modifications

* Update the migration query

* Fix up remaining queries

* Oops forgot this one

* Forgot this rename

* Rename the new status field to
match the new column

* Fix up the tests and add a new one

* Change the return value of some of the
queries and simplify the validation check. Also add a test.

* Change it back

* Update the tests

* Clean up the comments in the shares enum

* rename the rotate keys error variant

* Use a better error variant when extracting
the started_at from the state machine Id

* Remove some of our unused error variants

* Match the behavior in the in memory store
with the postgres implementation

* We do not need these errors anymore either

* address nits

---------

Co-authored-by: Joey Yandle <[email protected]>
Co-authored-by: djordon <[email protected]>
Co-authored-by: Francesco Leacche <[email protected]>
cylewitruk added a commit that referenced this pull request Feb 10, 2025
…fication (#1324)

* update for wsts 11

* use wsts 11.0.0 from crates

* fix rebase

* use wsts-12.0.0 from crates

* add FrostCoordinator to wsts_state_machine so we can run signing rounds where all signers must participate

* wip

* run a dkg signing before deploying contracts

* new wsts commit

* wip

* seems to work

* working version

* remove dead code

* minor wsts logging tweaks

* rename wstsmessageid variant

* it works, now need to clean up

* downgrade wsts

* proto backwards compatability fixes

* some wsts cleanup/refactor

* think that's it

* add message support for a specific dkg wstsmessageid

* add a dkg wstsmessageid variant

* use block hash instead of random data

* fmt

* remove 100% requirement for stacks signing of rotate keys

* bump p256k1 to 7.2.2

* pop stash

* wip

* working verifications

* saving

* fixing tests

* seems to work

* remove const generic, use 0 amount and add test for random keypair

* vet bitcoinconsensus

* working on cleaning up

* fix merge artifacts

* tracing fields

* migration needs to update block hash/height

* storage mut

* lovely cascading changes

* remove wstsmessage.txid infavor of id

* remove save and prefer trait default impls

* remove unused trait methods

* logging stuff

* rename message ids

* use tracing constants

* remove stale comment

* remove box from some types

* missed dkg_begin_pause

* leftover dbg!()

* refactor some validation

* various pr comments

* mut thing

* remove unneeded allow(deprecated)

* import some changes manually from parent branch to help a confused merge tool

* more diff-reducing imports

* confused merge tool

* reduce diff

* add validation for nonceresponse + signatureshareresponse

* newline

* pr comments

* pr comments utxo

* utxo comments

* remove error conversion method

* Squashed commit of the following:

commit 2168f58
Author: Cyle Witruk <[email protected]>
Date:   Thu Feb 6 16:08:22 2025 +0100

    feat: consensus on successful DKG prior to rotate-keys submission (#1285)

    * update for wsts 11

    * use wsts 11.0.0 from crates

    * fix rebase

    * use wsts-12.0.0 from crates

    * add FrostCoordinator to wsts_state_machine so we can run signing rounds where all signers must participate

    * wip

    * run a dkg signing before deploying contracts

    * new wsts commit

    * wip

    * seems to work

    * working version

    * remove dead code

    * minor wsts logging tweaks

    * rename wstsmessageid variant

    * it works, now need to clean up

    * downgrade wsts

    * proto backwards compatability fixes

    * some wsts cleanup/refactor

    * think that's it

    * add message support for a specific dkg wstsmessageid

    * add a dkg wstsmessageid variant

    * use block hash instead of random data

    * fmt

    * remove 100% requirement for stacks signing of rotate keys

    * bump p256k1 to 7.2.2

    * fix merge artifacts

    * tracing fields

    * storage mut

    * lovely cascading changes

    * remove wstsmessage.txid infavor of id

    * remove save and prefer trait default impls

    * remove unused trait methods

    * logging stuff

    * rename message ids

    * use tracing constants

    * remove stale comment

    * remove box from some types

    * missed dkg_begin_pause

    * leftover dbg!()

    * refactor some validation

    * various pr comments

    * mut thing

    * remove unneeded allow(deprecated)

    * confused merge tool

    ---------

    Co-authored-by: Joey Yandle <[email protected]>

* Change the DKG shares status type.
Lots of small follow-up modifications

* Update the migration query

* Fix up remaining queries

* Oops forgot this one

* Forgot this rename

* Rename the new status field to
match the new column

* Fix up the tests and add a new one

* Change the return value of some of the
queries and simplify the validation check. Also add a test.

* Change it back

* Update the tests

* Clean up the comments in the shares enum

* rename the rotate keys error variant

* Use a better error variant when extracting
the started_at from the state machine Id

* Remove some of our unused error variants

* Match the behavior in the in memory store
with the postgres implementation

* We do not need these errors anymore either

* wip

* seems to be a working version

* integrated into signer

* fmt

* remove unused errors

* another unused error

* cleanup

* don't cache the mock transaction, for now

* change cache structure

* address nits

* comments

* comments and dead code

* comment

* missed some stuff

* comment

* comments

* comment

* pr comments

* test stuff

* attribute and move mark_processed

* rename unwrap_one to single

* remove error generic

* remove unused error variant

* rename display variant

* fix mod comment

* comments

* use bool to simplify processing loop

* some refactoring and fix issue with multiple messages

* more validation, test improvements and a little cleanup

* move validate_sender in relay_message

* import mock tx verify/revoke match statement from main

* re-add block hash (well, block ref)

* add break-early-on-coordinator-state-change

* allow unlimited timeout (a'la None)

* some final cleanup

* pr comments

* remove testing.rs comment leftovers

* remove unused error variant

* remove unneeded sleep

* log state on error/expired

* statemachineid display impl

---------

Co-authored-by: Joey Yandle <[email protected]>
Co-authored-by: djordon <[email protected]>
Co-authored-by: Francesco Leacche <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking-protocol Breaking protocol changes key rotation The functionality to rotate a private key for a signer in sBTC-v1.
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

5 participants