NoirWallet: FROST Multi-Device Signing Design

Link: Noir | Privacy first Wallet 🦓🦓🦓 ⓩ on X: "Ledger has confirmed an unauthorized hardware implant in a device sold via a Southeast Asian reseller. Analysts estimate $80M+ lost. The underlying risk: one device with full spend power is one point of failure. This trigger us to build "NoirWallet S… / X

TL;DR

  • What: NoirWallet Secure Vault, an optional 2-of-3 FROST threshold signing setup for Zcash shielded funds.
  • Devices: Chrome Extension + Mobile Wallet for everyday spending, plus an Offline Backup Signer.
  • Key property: no single device ever holds the full spend key, so one compromised device can’t move your funds.
  • On-chain: spends use Re-Randomized FROST and look like any ordinary Zcash shielded spend.
  • Before release: transaction verification, recovery testing and an independent security audit.

Why multi-device signing?

Ledger has confirmed that an affected hardware wallet sold through a third-party reseller contained an unauthorized hardware implant. All confirmed fund-loss cases involve devices from that reseller, and the incident has renewed attention on wallet security.

When all signing authority sits on one device, compromising that device or its key can cost a user all of their funds. With distributed key management, no single device can control a user’s assets on its own.

One compromised device should never be enough to steal your funds.

What is FROST on Zcash?

FROST (Flexible Round-Optimized Schnorr Threshold signatures, RFC 9591) lets a group of devices share control of one signing key. Each device holds only a share of the key, and any threshold of them, such as two out of three, can produce a single valid signature. The full key is never assembled in one place.

Zcash shielded spends use a signature that is re-randomized for every transaction, so spends can’t be linked to each other. Re-Randomized FROST, implemented in the Zcash Foundation’s FROST library and described in draft ZIP-312, adds that step to FROST. This means:

  • The result is one ordinary Zcash spend-authorization signature, checked by the network like any other.
  • Nothing on-chain shows that several devices signed, or how many.

Secure Vault: 2-of-3 threshold signing

How it works

  • Setup: the devices generate their key shares through DKG, with no trusted dealer. The full private key never exists on any single device.
  • Every day: the extension and the phone sign. The offline signer is not needed for normal spending.
  • Backup and recovery: each device backs up only its own key share with its own recovery phrase. If a device is lost, the remaining two can jointly move funds to a new Vault.
  • Key safety: devices never send raw key shares to each other, and NoirWallet’s servers never hold key shares.

Signing flow

Bluetooth support in Chrome extensions is limited, so we’re testing it early. The QR option doesn’t depend on it.

  1. Start a payment. The user sets up a shielded payment in the extension. Each signing device prepares a fresh, one-time commitment.
  2. Build the transaction. The extension builds a PCZT (ZIP-374). Re-Randomized FROST ties the signature’s randomizer to those commitments, so they can’t be mismatched.
  3. Independent verification. The extension sends the full PCZT to the signers, and the phone checks the real transaction itself:
    • Every recipient and amount against the transaction data, plus the fee.
    • That change returns to the user’s own address (the phone holds the full viewing key for this).
    • The SIGHASH, computed on its own.
  4. Joint signing. After the user approves, the required devices run FROST signing, each with fresh single-use nonces.
  5. Broadcast. The extension aggregates the partial signatures into a standard spend authorization signature and broadcasts. If a device declines, verification fails, or too few valid shares arrive, the transaction can’t be authorized.

Signing devices never blind-sign a hash supplied by the extension. Otherwise a hacked extension could show one amount and get a signature for another.

Security architecture

Recovery

For a 2-of-3 setup:

  • With a recovery phrase: import it on a new device to restore the lost share and re-pair.
  • Without a recovery phrase: the remaining two devices jointly move funds to a new Vault.
  • Limit: if fewer than two shares remain available or recoverable, the funds can’t be recovered.

After losing a device, migrate funds to a new Vault promptly so the lost share stops being valid. A cleared or reinstalled browser profile counts as a lost device. Store each recovery phrase separately, because any two shares control the Vault.

For Zcash’s Ironwood pool, recovery follows ZIP-2005 and protects the key material it requires, including nk, rivk and qsk.

Threat model: what this does and doesn’t protect

  • Protects: theft of funds through compromise of a single device.
  • Does not hide: wallet activity from a compromised device. Every signer holds viewing data, so a compromised device can’t spend but may see funds.
  • Shielded funds only: transparent funds aren’t covered, so NoirWallet plans to shield them automatically.
  • Quantum recovery: every device holds the qsk material ZIP-2005 uses for recovery. This does not make Zcash quantum-secure.

How Secure Vault fits into NoirWallet

Secure Vault is optional and offered as a new wallet setup flow. Users who don’t want multi-device signing keep using NoirWallet exactly as today. Before release, we’ll complete transaction verification, recovery testing and an independent security audit.

We’d love your feedback

We’re especially interested in input on:

  • The 2-of-3 device split and the offline backup signer role.
  • Bluetooth LE with Noise vs. animated QR as signing channels.
  • The recovery model, including migrating to a new Vault after a device loss.
  • Anything we’ve missed in the threat model.

Reply below with questions, concerns or suggestions.

Really like this idea. After the Ledger reseller incident, knowing one hacked device can’t drain my wallet is reassuring.

A couple of things from a regular user’s side. Keeping three separate recovery phrases safe feels like a lot, so some simple guidance during setup would help. Also, a lot of people clear their browser data without thinking, so a clear warning that this counts as losing a device would save some headaches.

I’d also vote for QR as the default. It just feels easier than dealing with Bluetooth pairing.

Looking forward to trying it once the audit is done.

As long as all the code is open sourced, Im all for it

2 Likes

Hi Noir team, great to see this, and good call putting the design out for review before building it.

I’ve been working on the same idea for OpenPGP Wallet and posted my design here on October 12: FROST 2-of-3 between a user's own devices for shielded ZEC (Ironwood)
Our two designs line up almost step by step (2-of-3, the phone as an independent checker, DKG, PCZT, sweep to a new vault after a loss). I read that as a good sign: the ZIPs and the ZF crates lead everyone to the same architecture.

Feedback on what you asked:

QR vs BLE. I’d make animated QR the default. It’s a real air gap with a tiny attack surface, it works between any two devices, and it needs no OS pairing state. BLE stacks have a long history of remote bugs, and in an MV3 extension you’d be fighting the platform. ZIP 312 wants the randomizer on a confidential, authenticated channel, so I encrypt the QR payloads with a key agreed at pairing (ephemeral keys plus a short code compared on both screens).

Round order. rk is part of the sighash and ZIP 312 derives each randomizer from the signers’ commitments, so the phone’s commitments have to exist before the PCZT is built (zcash/orchard#571). That means three QR scans rather than two.

Nonces in an extension. MV3 service workers get killed when idle, which makes it tempting to persist session state. Nonces should never land in chrome.storage.local or sync: a restored or synced nonce can leak a share. If the worker dies mid-session, restart the session.

Recovery. Restoring a lost share from its phrase keeps that same share valid on the lost device, so I’d make “sweep to a new vault” the default after any loss, not only the fallback. And as the first reply says, three phrases is a lot, and each one is a share at rest. I went with no phrase at all: the backup share is a file encrypted under its own key and passphrase, written to removable media and decrypted back before setup completes.

Two threat-model questions.

  1. How do you derive nk, rivk and qsk for the group today? As far as I can tell zcash/zips#895 isn’t merged, and zcash-sign uses a fork-only constructor that gives up quantum recoverability. Related: if every device holds qsk, can a single device spend on its own once quantum recovery is enabled? Worth stating either way.
  2. The update channel. If the extension and the phone app come from the same publisher, one compromised release pipeline or store account can push a malicious update to both signers at once, which is 2 of 3. That’s the software version of the reseller incident that started this. Reproducible builds and signed releases help, but the strongest fix is letting users pick co-signers from different vendors.

Which leads to a proposal. With Zkool, NoirWallet and OpenPGP Wallet all doing FROST for shielded ZEC, we’re heading for three signing protocols and three backup formats that don’t talk to each other. Would you be open to a common open spec for the coordinator-to-signer messages and the share backup format? A Noir phone could then co-sign for another wallet and the other way round, which also closes the single-vendor gap above. I’m happy to do the drafting and the test vectors.

Sure, a common format would be good. However, each app may store additional information needed for their particular implementation. For instance, ZKOOL uses standard Ironwood memos for transport and keeps each participant mailbox address.

1 Like

Thanks Hanh, agreed. I’d keep the common part small and leave room for app-specific data like your mailbox addresses, which other apps would just carry along. And if the messages don’t depend on the transport, Zkool can keep using memos while others use QR.

Would you mind if I start from what Zkool stores today? More details are in my grant thread, and I’d really appreciate your thoughts on it: Interoperable FROST co-signing for shielded ZEC: open specs and a reference implementation

It will be open source

1 Like