Skip to content

Add pczt frost-sign#137

Open
conradoplg wants to merge 1 commit into
zcash:mainfrom
conradoplg:frost-sign
Open

Add pczt frost-sign#137
conradoplg wants to merge 1 commit into
zcash:mainfrom
conradoplg:frost-sign

Conversation

@conradoplg

@conradoplg conradoplg commented Dec 22, 2025

Copy link
Copy Markdown

This is just a proof of concept to gather feedback. The code is ugly; I'm looking for feedback on (1) is the API something acceptable? and (2) is this something that could be possibly merged after cleaning up?

I documented how to run it here: https://frost.zfnd.org/zcash/devtool-demo.html

Regarding the API, currently it is supposed to work along the frost-client CLI for the participants (and the frost-server in the same repo to handle comms), but if we want to go ahead it might make sense to add a new command for participants (pczt frost-sign does the coordinator logic) so that using frost-client is not required.

Regarding what is currently missing:

  • Handling multiple inputs
  • Sending the PCZT for the participants to validate (critical!)
  • Deciding how to handle FROST key material (currently uses the frost-client config file which stores everything in cleartext)
  • Incorporating ZIP-312 when that is done

@conradoplg
conradoplg marked this pull request as ready for review January 21, 2026 20:40
@conradoplg conradoplg changed the title WIP: Add pczt frost-sign Add pczt frost-sign Jan 21, 2026
@nuttycom nuttycom mentioned this pull request Jan 30, 2026
@nuttycom

Copy link
Copy Markdown
Collaborator

In starting to review this, I'm surprised that FROST signing is the first thing that was implemented, because in order to perform signing we need to have keys in the wallet database, and in order to have those keys we need the DKG process implemented. Is the DKG on your agenda for implementation in the devtool?

@conradoplg

Copy link
Copy Markdown
Author

In starting to review this, I'm surprised that FROST signing is the first thing that was implemented, because in order to perform signing we need to have keys in the wallet database, and in order to have those keys we need the DKG process implemented. Is the DKG on your agenda for implementation in the devtool?

As it stands, the keys need to be generated with frost-client (BTW I documented how to run it the ZF FROST Book). I think the easiest approach would simply incorporate all the functionality of frost-client into zcash-devtool, the tricky part is deciding how to store the key data in the devtool wallet file (instead of a separate file managed by frost-client which is what this PR does).

The goal of this PR is mostly to do a proof of concept and gather feedback on the overall idea and the API. I agree that if we go forward it would be better to move to the DKG first. If you also have any feedback on the key data storage, that would be helpful.

@nuttycom

Copy link
Copy Markdown
Collaborator

As it stands, the keys need to be generated with frost-client (BTW I documented how to run it the ZF FROST Book). I think the easiest approach would simply incorporate all the functionality of frost-client into zcash-devtool, the tricky part is deciding how to store the key data in the devtool wallet file (instead of a separate file managed by frost-client which is what this PR does).

The overall approach that we will want is:

In the wallet backend (in the WalletWrite trait) add a method that creates an account that will be associated with the signing set. That creation step should result in inputs to the FROST DKG, and then the account storage should be updated with the results of that DKG process. I'd be happy to pair with you to get you oriented with the things that will need to be added when you have time. The process is basically: design the API in terms of a set of semantically relevant types, then implement that API in terms of storing the relevant bits of information in the SQLite database (adding columns/tables as necessary via a migration) and then ensure that the WalletRead API exposes enough information to be able to perform signing ceremonies.

Then, the signing process should be integrated with the transaction proposal -> PCZT -> transaction finalization workflow.

@zmanian

zmanian commented Feb 8, 2026

Copy link
Copy Markdown

I've opened #150 which supersedes this PR with a complete FROST implementation, integration tests, and documentation.

Implementation (behind the frost feature flag):

  • wallet frost-dkg -- Full interactive DKG ceremony (3 rounds) producing FROST key shares and importing the Orchard UFVK as a view-only wallet account. Key material encrypted at rest with age.
  • pczt frost-sign -- Coordinator-side signing: extracts sighash/alphas from PCZT, orchestrates 2-round ceremony, aggregates shares into orchard_redpallas::Signature<SpendAuth>, applies to PCZT.
  • pczt frost-participate -- Participant-side signing: loads encrypted key package, generates commitments and signature shares with rerandomization.
  • frost_config.rs -- FROST config (frost.toml) management with age encryption.
  • frost_serde.rs -- Hex-encoded JSON serialization for all FROST protocol messages.

Tests (17 tests in frost_serde.rs and frost_config.rs):

  • Full 2-of-3 DKG ceremony with JSON serde round-trips on every message
  • Full signing ceremony with rerandomization and JSON round-trips
  • Round-trip tests for all serde types (KeyPackageStore, PublicKeyPackageStore, DkgRound1PackageStore, DkgRound2PackageStore, SigningCommitmentsStore, SigningPackageStore)
  • Error-path tests for malformed inputs
  • DKG-to-Orchard FVK bridge test (group key to FullViewingKey to UnifiedFullViewingKey with address derivation and ak sign bit handling)
  • FROST signature to orchard_redpallas::Signature<SpendAuth> conversion test (the exact bridge used before apply_orchard_signature())
  • FrostConfig TOML round-trip and age encrypt/decrypt tests

Documentation (doc/frost-walkthrough.md):

  • Key architecture, DKG ceremony walkthrough, signing ceremony with message flow diagram, file layout, security considerations, full test suite reference, and troubleshooting.

This addresses the DKG gap noted in the review -- all functionality from frost-client is now incorporated directly into zcash-devtool.

@nullcopy nullcopy left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hi @conradoplg I've weighed in my thoughts w.r.t. the API. Overall, I think this would be useful and valuable. I left a few minor questions/suggestions below

but if we want to go ahead it might make sense to add a new command for participants (pczt frost-sign does the coordinator logic) so that using frost-client is not required.

I agree with this


let signature: [u8; 64] = signature.serialize()?.try_into().unwrap();
let signature = redpallas::Signature::<SpendAuth>::from(signature);
signatures.push((alphas[0].0, signature));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Curious why you only push alphas[0]. Don't we need one for each non-dummy output?

/// The server URL to use. If not specified, it will use the server URL
/// for the specified group, if any.
#[arg(short, long)]
pub server_url: Option<String>,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm new to the frost signing flow, but is it possible to coordinate signatures from offline signers? Or is a connection to a coordinator server strictly necessary?

Pardon my ignorance 😅


let mut comms = frost_client::coordinator::comms::http::HTTPComms::new(&pargs, &args)
.map_err(|e| anyhow!(e.to_string()))?;
let signature = frost_client::coordinator::cli::coordinator(&mut comms, pargs)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm curious how timeouts/retries work here. If one signer becomes unavailable or fails to contribute in time, is it possible to resume a signing round or do all parties need to start over?

})
.collect::<Result<Vec<_>, _>>()?,
};
let args = frost_client::coordinator::comms::http::Args {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

There's lots of manual struct assembling in this PoC. I would prefer to have constructors where possible

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants