-
Notifications
You must be signed in to change notification settings - Fork 90
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(bridge-signer): implement FROST threshold signer node #1960
base: main
Are you sure you want to change the base?
Conversation
To deploy this in a production environment, we need to add a Helm chart to manage the new binary within the cluster. Additionally, updates to our GitHub workflow are required to enforce merge restrictions and streamline the release process. |
## Summary support FROST ed25519 threshold signing in the bridge withdrawer. ## Background improves security of the withdrawer over having one private key used; instead, we can employ an m-of-n threshold signature scheme to sign withdrawals. ## Changes - create `FrostParticipantService` gRPC proto definition, which is to be implemented by a binary which contains a FROST secret key partial that participates in the threshold signing process - update withdrawer config/setup to support single signer (previous behaviour) or threshold signing via the `Signer` trait - create `FrostSigner` which has gRPC clients for the signing participants - `FrostSigner.sign()` performs the signing process by calling each participant for their commitment (part 1) and signature share (part 2) and finally aggregates the shares to create a valid signature. - `FrostSigner.sign()` will fail if it does not receive responses from at least the minimum number of signers required. the min number of signers is determined during key generation, which is done completely separately. ## Testing blackbox tests with mock signer servers have been added. also, this was tested with a 2/2 threshold signer node setup. withdrawal transactions are successfully signed, submitted, and included on the sequencer. see https://www.notion.so/astria-org/bridge-threshold-withdrawer-testing-1936bd31a90c803ab33ccc1221f545a1?pvs=4 use the following testing keys which are for 2/2 threshold and represent astria address `astria1w2lxx9p02u7u934ljl060wannqm40g3y089lmh` put the following keys into their own files. pubkey package: ```bash { "header": { "version": 0, "ciphersuite": "FROST-ED25519-SHA512-v1" }, "verifying_shares": { "0100000000000000000000000000000000000000000000000000000000000000": "bd209bd0c47806fee2db29bde0b705f6a191602f0307e8d959d74f189ae92e9e", "0200000000000000000000000000000000000000000000000000000000000000": "0a677e1c6ad0c1906bf6ac53810b29efcb9ca9e7ab50fe9fca3ae49e613b922f" }, "verifying_key": "ecbe5e2fbaaf23f14ca43f34d71ad733c57afcadeb5782809af48a3da17b9b69" ``` secret key 1: ```bash { "header": { "version": 0, "ciphersuite": "FROST-ED25519-SHA512-v1" }, "identifier": "0100000000000000000000000000000000000000000000000000000000000000", "signing_share": "4b45de055567d7a2027bfc9a2463de4aaa6f2df995180e638dc938013e9bf70e", "verifying_share": "bd209bd0c47806fee2db29bde0b705f6a191602f0307e8d959d74f189ae92e9e", "verifying_key": "ecbe5e2fbaaf23f14ca43f34d71ad733c57afcadeb5782809af48a3da17b9b69", "min_signers": 2 } ``` secret key 2: ```bash { "header": { "version": 0, "ciphersuite": "FROST-ED25519-SHA512-v1" }, "identifier": "0200000000000000000000000000000000000000000000000000000000000000", "signing_share": "29a52cd248df9a7bb2346fb4ed53318f0bff320985c8e49062c68e4fd0012d0f", "verifying_share": "0a677e1c6ad0c1906bf6ac53810b29efcb9ca9e7ab50fe9fca3ae49e613b922f", "verifying_key": "ecbe5e2fbaaf23f14ca43f34d71ad733c57afcadeb5782809af48a3da17b9b69", "min_signers": 2 } ``` checkout `noot/frost-participant` (see #1960) build astria-cli, astria-bridge-withdrawer, astria-bridge-signer and astria-sequencer. run anvil (using this as fake rollup evm node for testing) run astria-sequencer + cometbft as normal transfer funds from funded address to withdrawer address ```bash ./target/debug/astria-cli sequencer transfer --amount 100000000 \ --private-key 2bd806c97f0e00af1a1fc3328fa763a9269723c8db8fac4f93af71db186d6e90 \ --sequencer-url http://localhost:26657 \ --sequencer.chain-id astria astria1w2lxx9p02u7u934ljl060wannqm40g3y089lmh ``` initialize bridge account on astria, with `astria1w2lxx9p02u7u934ljl060wannqm40g3y089lmh` being the withdrawer address ```bash ./target/debug/astria-cli sequencer init-bridge-account \ --private-key 2bd806c97f0e00af1a1fc3328fa763a9269723c8db8fac4f93af71db186d6e90 \ --withdrawer-address astria1w2lxx9p02u7u934ljl060wannqm40g3y089lmh \ --sequencer-url http://localhost:26657 \ --sequencer.chain-id astria \ --rollup-name test ``` result: ```bash sending tx from address: astria1rsxyjrcm255ds9euthjx6yc3vrjt9sxrm9cfgm InitBridgeAccount completed! Included in block: 1252 Rollup name: test Rollup ID: n4bQgYhMfWWaL-qgxVrQFaO_TxsrC4Is0V1sFbDwCgg= ``` deploy contracts to anvil using `astria-bridge-contracts` - set `.env` and `source .env` ```bash PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 RPC_URL="http://localhost:8545" BASE_CHAIN_ASSET_PRECISION=9 BASE_CHAIN_BRIDGE_ADDRESS="astria1rsxyjrcm255ds9euthjx6yc3vrjt9sxrm9cfgm" BASE_CHAIN_ASSET_DENOMINATION="nria" ``` - `forge script script/AstriaWithdrawer.s.sol:AstriaWithdrawerScript --rpc-url $RPC_URL --broadcast --sig "deploy()" -vvvv` - contract deployed at `0x5FbDB2315678afecb367f032d93F642f64180aa3` , update `.env` again run two astria-bridge-signers, one with grpc port `9001` and first secret key package, second with grpc port `9002` and second secret key package. start the bridge withdrawer, configured for 2/2 threshold (make sure to update pubkey package path): ```bash ASTRIA_BRIDGE_WITHDRAWER_FROST_THRESHOLD_SIGNING_ENABLED=true ASTRIA_BRIDGE_WITHDRAWER_FROST_MIN_SIGNERS=2 ASTRIA_BRIDGE_WITHDRAWER_FROST_PUBLIC_KEY_PACKAGE_PATH="pub_bridge.key" ASTRIA_BRIDGE_WITHDRAWER_FROST_PARTICIPANT_ENDPOINTS="http://127.0.0.1:9001,http://127.0.0.1:9002" ASTRIA_BRIDGE_WITHDRAWER_SEQUENCER_BRIDGE_ADDRESS="astria1rsxyjrcm255ds9euthjx6yc3vrjt9sxrm9cfgm" ASTRIA_BRIDGE_WITHDRAWER_ETHEREUM_CONTRACT_ADDRESS="0x5FbDB2315678afecb367f032d93F642f64180aa3" ``` finally, send a withdrawal on the rollup: ```bash forge script script/AstriaWithdrawer.s.sol:AstriaWithdrawerScript \ --rpc-url $RPC_URL --broadcast --sig "withdrawToSequencer()" -vvvv ``` in the withdrawer, should see: ```bash 2025-02-10T17:33:57.417370Z INFO process_batch: astria_bridge_withdrawer::bridge_withdrawer::submitter: withdraw batch successfully executed. sequencer.block=41 sequencer.tx_hash=69E3997A2A67CD4716D1051D9962219FBCEF9F3F7557C276D9F4D414D30166F2 rollup.height=4 batch.value=1000 ``` ## Changelogs Changelogs updated. ## Related Issues closes #1937 --------- Co-authored-by: Richard Janis Goldschmidt <[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.
Can you provide a summary in the PR text on how this service should work? I.e. who is calling it and how? I have a rudimentary understanding of how the threshold signing works, but it would be great to have a summary as to what role this server plays and how (and in which order) its RPCs are called.
I would also ike to see a couple of points to be addressed by this PR listed below. I have to still go through the functionality of the inner service.
- follow the rest of our services in that a singleton
BridgeSigner
is instantiated, rather than everything being done inmain.rs
- this would make it easier to also implement blackbox test - related to this, outlining how a blackbox test would look (together with a followup PR) would be great.
- move changes in
astria-cli
,astria-bridge-withdrawer
, andastria-sequencer
to separate PRs - provide a changelog and entry in codeowners
- add tests to
local.env.example
to prevent it from degrading (similar to the other services) - add the various env vars that are understood by the service but are not part of
Config
(NO_COLOR
and the otherOTEL
related ones; see the other services).
@@ -0,0 +1,30 @@ | |||
# A list of filter directives of the form target[span{field=value}]=level. | |||
ASTRIA_BRIDGE_SIGNER_LOG=astria_bridge_signer=info |
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.
We shouldn't prefix it with the target by default, just make this =info
:
ASTRIA_BRIDGE_SIGNER_LOG=astria_bridge_signer=info | |
ASTRIA_BRIDGE_SIGNER_LOG=info |
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 is standard across our other components. Unsure of the implications here, but happy to change if necessary
/// # Errors | ||
/// | ||
/// Returns an error if the provider cannot be created. | ||
pub fn new(rollup_rpc_endpoint: String) -> eyre::Result<Self> { |
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.
If this is part of the Server, then the server should instantiate it.
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.
f09cad5
to
ac5fcd8
Compare
Summary
implement FROST threshold signer node which implements the
FrostParticipantService
gRPC service defined in #1948. the bridge withdrawer can then collect signature partials from various threshold signer nodes to sign a withdrawal transaction in a more distributed manner.Background
improves security of the withdrawer over having one private key used; instead, we can employ an m-of-n threshold signature scheme to sign withdrawals.
Changes
FrostParticipantService
gRPC serviceTesting
tested with the withdrawer in #1948; see https://www.notion.so/astria-org/bridge-threshold-withdrawer-testing-1936bd31a90c803ab33ccc1221f545a1?pvs=4
Changelogs
Ensure all relevant changelog files are updated as necessary. See
keepachangelog for change
categories. Replace this text with e.g. "Changelogs updated." or "No updates
required." to acknowledge changelogs have been considered.
Related Issues
closes #1937