# Adding BIP-340 Schnorr Support to `frost-zcash-demo`
The `frost-zcash-demo` tools already support multiple elliptic‐curve ciphersuites. As documented, the demo supports **Ed25519** and **RedPallas**; users can switch curves at runtime via the `--curve` (or `-C`) option [[1]](https://github.com/ZcashFoundation/frost-zcash-demo#:~:text=Currently%20the%20demo%20supports%20curve,be%20used%20to%20sign%20Zcash). In practice, the CLI parses a curve argument (e.g. `"ed25519"` or `"redpallas"`) and **dispatches** to the corresponding FROST implementation. For example, the code likely does something akin to:
* If `--curve ed25519`, use the `frost-ed25519` crate (Ed25519 ciphersuite).
* If `--curve redpallas`, use the `reddsa::frost::redpallas` crate (Zcash’s RedPallas Schnorr ciphersuite).
This dispatch is implemented in each binary’s argument-handling code (e.g. in `frost-client/src/args.rs` or similar). The existing code often uses a feature flag or enum to select the crate. (For example, older versions used `#[cfg(feature = "redpallas")]` to import the RedPallas FROST, otherwise defaulting to Ed25519.)
Thus, curve selection is dynamic at runtime via CLI flags, and internally the code invokes the appropriate FROST types depending on that flag.
# Integration of `frost-secp256k1-tr`
Adding support for the BIP-340 (Taproot) ciphersuite means enabling the **secp256k1 (Taproot) FROST** implementation. The ZF FROST libraries already include a `frost-secp256k1-tr` ciphersuite crate [[2]](https://github.com/ZcashFoundation/frost-zcash-demo#:~:text=Currently%20the%20demo%20supports%20curve,be%20used%20to%20sign%20Zcash). This crate provides the Schnorr/GR8x86 group over secp256k1 with SHA-256 (tagged for BIP-340), along with all FROST operations (nonce gen, hashing, signing, etc.). To integrate this into the demo CLI tools, we need to make the following changes:
* **Add dependency:** In each CLI’s `Cargo.toml` (for both `frost-client` and `frost-participant`), add the `frost-secp256k1-tr` (or `frost-secp256k1-tr-unofficial`) crate. Ensure its version is compatible with the existing `frost-core` version (the latest FROST release uses 2.x series).
* **Update CLI argument handling:** Extend the `--curve` option to accept `"secp256k1-tr"` (or a shorthand like `"secp256k1"` with Taproot implied). For example, if using Clap for argument parsing, add `"secp256k1-tr"` as a valid enum variant.
* **Dispatch logic:** In the code where curves are handled (e.g. in `match args.curve { … }` or similar), add a branch for secp256k1. For instance, if using generics, one might do:
```rust
// Pseudo-code illustrating dispatch by curve
match curve_arg {
Curve::Ed25519 => frost = frost_ed25519::FROST::<...>,
Curve::RedPallas => frost = reddsa::frost::redpallas::FROST::<...>,
Curve::Secp256k1TR => frost = frost_secp256k1_tr::Secp256K1Sha256TR,
}
```
In practice, one imports the correct FROST types. For secp256k1, the ciphersuite type is typically named `Secp256K1Sha256TR` (as per the crate code) [[3]](https://docs.rs/crate/frost-secp256k1-tr-unofficial/2.2.0/source/src/lib.rs#:~:text=impl%20Ciphersuite%20for%20Secp256K1Sha256TR%20,ID%3A%20%26%27static%20str%20%3D%20CONTEXT_STRING). Replace or augment any existing conditional imports (e.g. `use frost_ed25519 as frost;` or `use reddsa::frost::redpallas as frost;`) to include the secp256k1 option. If the code uses feature flags, you can introduce a new feature (e.g. `secp256k1-tr`) or remove compile-time gating and use runtime selection instead.
* **Curve-specific subprotocols:** Note that RedPallas enables *Rerandomized FROST* (two-round signing) automatically. The secp256k1-TR FROST implementation uses the standard FROST flow with BIP-340 hashing and nonce derivation, so no additional “rerandomized” step is needed for Taproot keys. Ensure that wherever the code checks or enables rerandomization (usually only for RedPallas), the secp256k1 path uses the normal (non-rerandomized) FROST.
# Architectural Considerations
The FROST demo tools are architected for **curve-agnostic** operation: all protocol logic (keygen, DKG, commit, sign) is generic over a trait (the `Ciphersuite` trait in `frost-core`). This means nearly all signing and communication code is identical regardless of curve; only the underlying curve operations and hash functions differ. In practice, this is implemented by selecting a concrete ciphersuite at runtime and invoking the generic algorithms on that suite.
Integrating secp256k1-TR thus mainly involves plugging in the new ciphersuite implementation rather than rewriting protocol logic. The key architectural modules – e.g. the FROST key-gen (trusted or DKG), signing protocol, and JSON/HTTP comms – should **automatically work** once the new ciphersuite types are provided.
However, there are some modular points to watch:
* **Feature flags vs dynamic code:** If the existing code uses Cargo features (as older code did) to toggle curve crates, you may need to adjust the project’s feature setup. For example, you might add a `secp256k1-tr` feature to conditionally include the secp crate. Alternatively, remove curve-related feature gating and always compile all curve crates, then select at runtime.
* **Server/Coordinator support:** If the demo’s server or coordinator components currently assume only Ed25519/RedPallas, you should similarly add secp256k1-TR support there. In practice, the Coordinator’s logic mostly just forwards JSON to participants; it would only need secp support if it ever verifies or formats curve-specific data. Focus on the CLI tools as asked, but be aware of cross-component consistency.
# Code Reuse
Because Ed25519 and RedPallas support are implemented via the same generic FROST infrastructure, adding secp256k1-TR will largely reuse the same code paths. For example:
* **Key generation and sharing:** The trusted-dealer or DKG commands output identical JSON fields (participant ID, secret share, public key, commitment commitments), just with different underlying math. The code that formats these structs in Serde does not need curve-specific code beyond serialization.
* **Signing rounds:** Each FROST round (Round 1 broadcast commitments, Round 2 shares, etc.) is the same structure. The only difference is how the nonces and challenges are computed (handled by the ciphersuite implementation). Thus, the existing implementation of the CLI subcommands (`participant`, `coordinator`, etc.) can remain unchanged except for wiring in the new types.
In summary, we expect **high code reuse**: most of the logic in `frost-client` and `frost-participant` will stay the same, and only the parts that instantiate or operate on a specific curve’s `KeyPackage`, `Signature`, etc. will change curve type.
# Data Formats and Serialization
Some care is needed for key and signature serialization:
* **Public keys and group commitments:** Ed25519 public keys are 32 bytes, RedPallas are 32-byte compressed points (with cofactor 8 considerations), and secp256k1-TR public keys are 32-byte *x-only* encodings (BIP-340). The existing code likely encodes keys as byte arrays or hex/base64 strings in JSON. You should ensure the serialization code correctly handles 32-byte keys from the secp curve. If the code uses a generic `encode_bytes(PublicKey)` approach, it will work as long as the byte length is 32. (Alternatively, if any code assumed Ed25519’s encoding or used a Zcash-specific prefix, that must be updated for secp256k1.)
* **Signature format:** Ed25519 and schnorr (both RedPallas and secp256k1 TR) use 64-byte signatures. The FROST ciphersuite trait uses `SignatureSerialization = [u8;64]` for secp256k1-TR (as shown in its impl) [[4]](https://docs.rs/crate/frost-secp256k1-tr-unofficial/2.2.0/source/src/lib.rs#:~:text=type%20SignatureSerialization%20%3D%20). As long as the code serializes signatures in a fixed 64-byte format (e.g. 32 + 32), no change is needed. Verify any signature hashing or verification routines use SHA-256 (Taproot) for secp and SHA-512 (Ed25519) or SHA-256-BIP0340 (RedPallas) as appropriate, but this is abstracted by the ciphersuite.
* **Key-package JSON:** The participant’s key-package JSON (used by `frost-client init`) contains the participant’s secret share and public verification share. We must ensure the format can carry secp256k1 keys. Likely this is already a byte array or hex string, so it will work. If the code uses different JSON labels or types for RedPallas vs Ed25519 (unlikely), standardize to a common format.
* **Bech32 or other encoding:** The search results hinted at a `bech32` dependency. If the demo encodes keys or addresses using bech32 (e.g. a Zcash-specific HRP like `uk` or similar), you may need to define a new HRP for secp256k1 keys to avoid confusion. For example, if Ed25519 keys were bech32-encoded with prefix `zp` and RedPallas with `zr`, then choose something like `zk` for secp256k1. Update any functions like `serialize_keypackage` to handle the new curve. If the code currently *only* supports Ed25519/RedPallas bech32 prefixes, add the secp256k1 case.
# Implementation Effort and Blockers
Overall, the effort is moderate. Most of the heavy work (elliptic-curve math, hashing) is already in the `frost-secp256k1-tr` crate. The main tasks are wiring it into the existing CLI framework:
* **Straightforward tasks:** Adding the crate dependency, updating CLI enums and `match` statements, and adding any necessary `#[cfg]` flags are all routine code changes. Because the demo code is small, this will likely be a few dozen lines of changes across the two binaries.
* **Technical Risks:**
* **Crate compatibility:** Ensure the `frost-secp256k1-tr` crate version is compatible with the `frost-core` version used by the demo. If the demo still uses an older `frost-core`, you may need to update the FROST library dependency as well.
* **Feature flags:** If the code uses compile-time features for curve selection, introducing a new feature may require reorganizing the build (e.g. updating `Cargo.toml` \[features] section). Alternatively, removing the feature model in favor of runtime selection may be nontrivial.
* **Key format differences:** If the demo’s config format is assumed to be Ed25519-based (e.g. in example YAML/JSON), testers will need to adapt their workflow for secp keys (for example, generating a bech32 prefix for secp public keys, or verifying signatures with SHA-256).
* **Testing and validation:** Finally, thorough testing is needed. The FROST protocol involves many message exchanges; make sure the secp256k1 path actually interoperates between participants and produces a valid Schnorr signature. Mismatches in hash tags or bit order could be subtle.
In summary, extending `frost-client` and `frost-participant` to support `frost-secp256k1-tr` is mostly a matter of **adding the new ciphersuite crate and updating the curve-selection logic**. With the generic FROST framework, nearly all protocol code can be reused, and only curve-specific details (imports, serialization formats) require attention.