slingshot
slingshot copied to clipboard
musig: multi-signer API
Problem
For multi-key/multi-party signing we need an API that handles both individual signatures (for delegate
) and aggregated per-tx signature (signtx
).
For delegate
, ZkVM already expects a signature produced externally, and its signing logic is tied to a specific protocol (e.g. a payment channel), so we don't need to focus on it right now.
For signtx
, ZkVM provides a list of UTXOs to be signed, along with the txid
. And we do not want to keep all secret keys in one machine that composes the transaction, yet we need a way to produce a joint Tx
instance with a complete signature. So we'll focus on that problem.
Prerequisites
- Removing signing secrets from
Predicate::Key
witness: PR #142 - Core MuSig implementation: #92
- Integration of Multikey with Predicate tree: #235
- Nested Multikeys: #236
- Multi-message API: #176
Design ideas
First, the ZkVM on a prover side cannot immediately produce a fully signed Tx
object. Instead, it needs to pause when R1CS proof is done, but signature is not, and returns an UnsignedTx
instance to let the multiple signers produce and aggregate their signatures.
If there's only one signer, there could be a convenience API to signed the UnsignedTx
and produce Tx
with just a single private key.
For multiple signers, there are two ways the signers could proceed:
- They could replay the ZkVM transaction per their own rules. Each will receive some
txid
as a result, and sign the UTXOs that they can spend (have keys for), ignoring additional UTXOs that might be thrown in by other parties (multi-message protocol #176 makes this safe to do). If they all agree on the rules and txid is the same for all signers, their signatures will all agree. This is a use case for various multi-factor hardware wallets: think your desktop and phone both have the same view of your wallet and sign the same high-level "payment request" per identical rules. - Alternatively, signers can receive only a
txid
, theirutxoid
s to sign, and a proof of the specific outputs that they need to verify (merkle path to txid + witness data for commitments). Then, they can avoid replaying the entire tx, and it could have been assembled by someone else entirely. For instance, if the policy is "spend $10 at a time to allowed addresses", the signer could see that they are spending a few utxos with total worth of $30, then they'll need a merkle path to an output with $X≤$10 to an allowed address, and a merkle path to an output to a change address (derived from the same Keytree) with the ($30-$X) as amount. They can then safely ignore the rest of the transaction.
Any top-level MuSig party can complete the UnsignedTx
with an aggregated signature and produce and publish fully-signed Tx
.