Work in Progress. Document written by Opus 4.5

Technical Design Document


Executive Summary

Nuri Wallet is a next-generation Bitcoin wallet that combines MuSig2 Schnorr signatures, stateless key derivation via WebAuthn PRF, NFC hardware wallet integration, and server-assisted two-factor authentication into a unified security architecture. The design prioritizes both security and recoverability through a decaying multisig mechanism that ensures users can always recover their funds, even if one or more signing components become unavailable.


Table of Contents

  1. Introduction
  2. Architecture Overview
  3. Key Components
  4. MuSig2 Protocol Integration
  5. Wallet Configurations
  6. Decaying Multisig with CSV Timelocks
  7. Security Analysis
  8. Recovery Scenarios
  9. Comparison with Existing Solutions
  10. Implementation Considerations

Introduction

Traditional Bitcoin wallets face a fundamental tension between security and usability. Single-signature wallets are vulnerable to key theft, while multisig wallets can lock users out of their funds if keys are lost. Nuri Wallet resolves this tension through an innovative combination of:

  • Stateless key derivation: No persistent key storage means no keys to steal from rest
  • MuSig2 aggregated signatures: Multiple parties contribute to a single Schnorr signature, maintaining privacy and reducing transaction fees
  • Decaying timelocks: Graduated recovery options that balance security against lockout risk
  • Hardware wallet integration: Optional cold storage for maximum security

Architecture Overview

┌─────────────────────────────────────────────────────────────────────────────┐
│                           NURI WALLET ARCHITECTURE                          │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ┌──────────────────┐  ┌──────────────────┐  ┌──────────────────┐          │
│  │   PASSKEY KEY    │  │  HARDWARE KEY    │  │   SERVER KEY     │          │
│  │   (Stateless)    │  │  (NFC Satochip)  │  │   (Stateless)    │          │
│  ├──────────────────┤  ├──────────────────┤  ├──────────────────┤          │
│  │ WebAuthn PRF     │  │ Secure Element   │  │ HSM/Secure       │          │
│  │ Extension        │  │ on NFC Card      │  │ Element          │          │
│  │                  │  │                  │  │                  │          │
│  │ key = PRF(salt)  │  │ Private key      │  │ key = f(user_id, │          │
│  │                  │  │ never leaves     │  │        entropy)  │          │
│  │ No key storage   │  │ the chip         │  │                  │          │
│  └────────┬─────────┘  └────────┬─────────┘  └────────┬─────────┘          │
│           │                     │                     │                     │
│           │    MuSig2 Partial   │    MuSig2 Partial   │                     │
│           │    Signature        │    Signature        │                     │
│           │                     │                     │                     │
│           └──────────┬──────────┴──────────┬──────────┘                     │
│                      │                     │                                │
│                      ▼                     ▼                                │
│           ┌─────────────────────────────────────────┐                       │
│           │         MuSig2 SIGNATURE AGGREGATION    │                       │
│           │                                         │                       │
│           │  2-of-2: Passkey + Server               │                       │
│           │  2-of-3: Any 2 of {Passkey, HW, Server} │                       │
│           └─────────────────────────────────────────┘                       │
│                                                                             │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │                    DECAYING TIMELOCK STRUCTURE                       │   │
│  │                                                                      │   │
│  │   T=0                    T=10,000 blocks              T=52,560       │   │
│  │    │                          │                       blocks         │   │
│  │    ▼                          ▼                          ▼           │   │
│  │  ┌────────────────────┬───────────────────────┬─────────────────┐   │   │
│  │  │  NORMAL OPERATION  │  RECOVERY MODE        │  EMERGENCY EXIT │   │   │
│  │  │  2-of-2 or 2-of-3  │  Passkey + HW         │  Passkey only   │   │
│  │  │  (Server active)   │  (Server unavailable) │  (CSV expired)  │   │
│  │  └────────────────────┴───────────────────────┴─────────────────┘   │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

Key Components

Stateless Passkey Wallet

The passkey-based key is the cornerstone of Nuri’s user experience. It leverages the WebAuthn PRF (Pseudo-Random Function) extension to derive cryptographic keys without ever storing them.

How It Works

┌─────────────────────────────────────────────────────────────────┐
│                    PASSKEY KEY DERIVATION                       │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   User authenticates with passkey (biometric/PIN)               │
│                          │                                      │
│                          ▼                                      │
│   ┌─────────────────────────────────────────┐                  │
│   │         WebAuthn Authenticator          │                  │
│   │    (Platform or Roaming Authenticator)  │                  │
│   └─────────────────────────────────────────┘                  │
│                          │                                      │
│                          ▼                                      │
│   ┌─────────────────────────────────────────┐                  │
│   │           PRF Extension                 │                  │
│   │                                         │                  │
│   │   secret = HMAC-SHA256(device_secret,   │                  │
│   │                        salt || rpId)    │                  │
│   └─────────────────────────────────────────┘                  │
│                          │                                      │
│                          ▼                                      │
│   ┌─────────────────────────────────────────┐                  │
│   │      Bitcoin Key Derivation             │                  │
│   │                                         │                  │
│   │   private_key = HKDF(secret,            │                  │
│   │                      "nuri-bitcoin",    │                  │
│   │                      derivation_path)   │                  │
│   └─────────────────────────────────────────┘                  │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Security Properties

PropertyDescription
StatelessNo private keys stored on device; derived on-demand
Phishing ResistantWebAuthn binds credentials to origin
Hardware-BackedPRF secret stored in device secure element
Biometric ProtectedUser presence verified via fingerprint/face

Key Derivation Formula

Given:

  • $s$ = device master secret (in secure element)
  • $\text{salt}$ = application-specific salt
  • $\text{rpId}$ = relying party identifier

The PRF output is:

$$\text{prf_output} = \text{HMAC-SHA256}(s, \text{salt} | \text{rpId})$$

The Bitcoin private key is then derived as:

$$k_{\text{passkey}} = \text{HKDF-SHA256}(\text{prf_output}, \text{“nuri-btc-v1”}, \text{path})$$


Hardware Wallet (NFC Satochip Signing Device)

The hardware wallet component uses an NFC-based secure element card (similar to Satochip or SatSigner) that performs MuSig2 partial signing without ever exposing its private key.

Capabilities

┌─────────────────────────────────────────────────────────────────┐
│                  NFC HARDWARE WALLET                            │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   ┌─────────────────────┐                                      │
│   │   Secure Element    │                                      │
│   │   (JavaCard/etc)    │                                      │
│   ├─────────────────────┤                                      │
│   │ • Private key       │  ◄── Never leaves the chip           │
│   │   generation        │                                      │
│   │ • MuSig2 nonce      │                                      │
│   │   generation        │                                      │
│   │ • Partial signature │                                      │
│   │   creation          │                                      │
│   │ • Public key export │                                      │
│   └─────────────────────┘                                      │
│            ▲                                                    │
│            │ NFC                                                │
│            ▼                                                    │
│   ┌─────────────────────┐                                      │
│   │   Mobile Device     │                                      │
│   │   (Nuri App)        │                                      │
│   └─────────────────────┘                                      │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

MuSig2 Signing Flow

  1. Nonce Commitment Round: Card generates random nonce $R_{\text{hw}}$ and provides commitment
  2. Nonce Exchange: All parties exchange nonce commitments, then reveal nonces
  3. Partial Signing: Card computes partial signature without revealing private key
  4. Aggregation: Partial signatures combined into final Schnorr signature

Stateless Server

The server acts as a 2FA-protected co-signer that adds entropy and provides an additional security layer without introducing custody risk.

Design Principles

┌─────────────────────────────────────────────────────────────────┐
│                    STATELESS SERVER                             │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   ┌─────────────────────────────────────────┐                  │
│   │         Hardware Security Module        │                  │
│   │              (HSM)                       │                  │
│   ├─────────────────────────────────────────┤                  │
│   │ • Master seed (never exported)          │                  │
│   │ • Deterministic key derivation          │                  │
│   │ • Rate limiting                         │                  │
│   │ • Audit logging                         │                  │
│   └─────────────────────────────────────────┘                  │
│                          │                                      │
│                          ▼                                      │
│   ┌─────────────────────────────────────────┐                  │
│   │      Key Derivation Function            │                  │
│   │                                         │                  │
│   │   k_server = KDF(master_seed,           │                  │
│   │                  user_id,               │                  │
│   │                  wallet_id,             │                  │
│   │                  key_index)             │                  │
│   └─────────────────────────────────────────┘                  │
│                                                                 │
│   Properties:                                                   │
│   • No private keys stored in database                         │
│   • Keys derived on-demand from HSM                            │
│   • 2FA required before signing                                │
│   • Server breach doesn't compromise keys                      │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Server Key Derivation

The server derives user-specific keys deterministically:

$$k_{\text{server}} = \text{HKDF}(k_{\text{master}}, \text{user_id} | \text{wallet_id} | \text{index})$$

Where $k_{\text{master}}$ is stored in the HSM and never exported.


MuSig2 Protocol Integration

MuSig2 is a multi-signature scheme that produces a single aggregated Schnorr signature indistinguishable from a regular signature. This provides both privacy (observers can’t tell it’s multisig) and efficiency (smaller transactions, lower fees).

MuSig2 Overview

┌─────────────────────────────────────────────────────────────────┐
│                     MuSig2 PROTOCOL                             │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   SETUP PHASE (one-time)                                        │
│   ──────────────────────                                        │
│                                                                 │
│   Each party i has:                                             │
│   • Private key: xᵢ                                             │
│   • Public key:  Pᵢ = xᵢ · G                                    │
│                                                                 │
│   Aggregated public key:                                        │
│   P = Σᵢ (aᵢ · Pᵢ)                                              │
│   where aᵢ = H(L, Pᵢ) and L = {P₁, P₂, ...}                     │
│                                                                 │
│   SIGNING PHASE (per transaction)                               │
│   ───────────────────────────────                               │
│                                                                 │
│   Round 1: Nonce Generation                                     │
│   ┌─────────┐  ┌─────────┐  ┌─────────┐                        │
│   │ Party 1 │  │ Party 2 │  │ Party 3 │                        │
│   │ r₁ → R₁ │  │ r₂ → R₂ │  │ r₃ → R₃ │                        │
│   └────┬────┘  └────┬────┘  └────┬────┘                        │
│        │            │            │                              │
│        └────────────┼────────────┘                              │
│                     ▼                                           │
│              Exchange Rᵢ values                                 │
│                     │                                           │
│                     ▼                                           │
│   Round 2: Partial Signatures                                   │
│                                                                 │
│   R = Σᵢ Rᵢ  (aggregated nonce)                                 │
│   c = H(R, P, m)  (challenge)                                   │
│                                                                 │
│   Each party computes:                                          │
│   sᵢ = rᵢ + c · aᵢ · xᵢ                                         │
│                                                                 │
│   Final signature:                                              │
│   s = Σᵢ sᵢ                                                     │
│   σ = (R, s)                                                    │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Why MuSig2 for Nuri?

BenefitDescription
PrivacyAggregated signature looks like single-sig on-chain
EfficiencyOne signature regardless of number of signers
Taproot NativeDesigned for Bitcoin’s Schnorr/Taproot upgrade
Non-InteractiveOnly 2 rounds of communication needed

Wallet Configurations

2-of-2 Configuration

The basic configuration requires both the passkey and server to sign transactions.

┌─────────────────────────────────────────────────────────────────┐
│                    2-of-2 CONFIGURATION                         │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   NORMAL OPERATION                                              │
│   ────────────────                                              │
│                                                                 │
│   ┌───────────┐         ┌───────────┐                          │
│   │  Passkey  │────────▶│  Server   │                          │
│   │   Key     │  2FA    │   Key     │                          │
│   └─────┬─────┘ verify  └─────┬─────┘                          │
│         │                     │                                 │
│         │    MuSig2          │                                 │
│         └──────────┬─────────┘                                 │
│                    ▼                                            │
│              ┌──────────┐                                       │
│              │ Combined │                                       │
│              │Signature │                                       │
│              └──────────┘                                       │
│                                                                 │
│   RECOVERY (Server Unavailable)                                 │
│   ─────────────────────────────                                 │
│                                                                 │
│   After CSV timelock expires (~1 year):                         │
│                                                                 │
│   ┌───────────┐                                                │
│   │  Passkey  │──────────────▶ Spend with single signature     │
│   │   Key     │                (CSV exit path)                 │
│   └───────────┘                                                │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Transaction Structure (Taproot)

Output Script (P2TR):
┌─────────────────────────────────────────────────────────────────┐
│  OP_1 <aggregated_pubkey>                                       │
└─────────────────────────────────────────────────────────────────┘

Taproot Tree:
┌─────────────────────────────────────────────────────────────────┐
│                         Internal Key                            │
│                    (MuSig2: Passkey + Server)                   │
│                              │                                  │
│              ┌───────────────┴───────────────┐                  │
│              │                               │                  │
│        ┌─────▼─────┐                  ┌──────▼──────┐           │
│        │  Leaf 1   │                  │   Leaf 2    │           │
│        │  (empty)  │                  │  CSV Exit   │           │
│        │           │                  │ <pk_passkey>│           │
│        │           │                  │ CHECKSIG    │           │
│        │           │                  │ <52560>     │           │
│        │           │                  │ CSV         │           │
│        └───────────┘                  └─────────────┘           │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

2-of-3 Configuration

The enhanced configuration adds a hardware wallet for additional security and recovery options.

┌─────────────────────────────────────────────────────────────────┐
│                    2-of-3 CONFIGURATION                         │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   THREE SIGNING KEYS                                            │
│   ──────────────────                                            │
│                                                                 │
│   ┌───────────┐    ┌───────────┐    ┌───────────┐              │
│   │  Passkey  │    │ Hardware  │    │  Server   │              │
│   │   (Hot)   │    │  Wallet   │    │  (2FA)    │              │
│   │           │    │  (Cold)   │    │           │              │
│   └─────┬─────┘    └─────┬─────┘    └─────┬─────┘              │
│         │                │                │                     │
│         └────────┬───────┴───────┬────────┘                     │
│                  │               │                              │
│                  ▼               ▼                              │
│         ┌──────────────────────────────┐                        │
│         │   ANY 2-of-3 can sign        │                        │
│         │                              │                        │
│         │   • Passkey + Server (daily) │                        │
│         │   • Passkey + HW (recovery)  │                        │
│         │   • Server + HW (if needed)  │                        │
│         └──────────────────────────────┘                        │
│                                                                 │
│   SIGNING SCENARIOS                                             │
│   ─────────────────                                             │
│                                                                 │
│   Scenario 1: Normal (Passkey + Server)                         │
│   ┌─────────┐  2FA  ┌─────────┐                                │
│   │ Passkey ├──────▶│ Server  │────▶ ✓ Transaction             │
│   └─────────┘       └─────────┘                                │
│                                                                 │
│   Scenario 2: Server Down (Passkey + Hardware)                  │
│   ┌─────────┐  NFC  ┌─────────┐                                │
│   │ Passkey ├──────▶│   HW    │────▶ ✓ Transaction             │
│   └─────────┘       └─────────┘      (No waiting!)             │
│                                                                 │
│   Scenario 3: Passkey Lost (Hardware + Server)                  │
│   ┌─────────┐       ┌─────────┐                                │
│   │   HW    ├──────▶│ Server  │────▶ ✓ Transaction             │
│   └─────────┘       └─────────┘                                │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Taproot Structure for 2-of-3

Taproot Tree (2-of-3):
┌─────────────────────────────────────────────────────────────────┐
│                         Internal Key                            │
│              (MuSig2: Passkey + Server - default path)          │
│                              │                                  │
│      ┌───────────────────────┼───────────────────────┐          │
│      │                       │                       │          │
│ ┌────▼────┐           ┌──────▼──────┐         ┌──────▼──────┐   │
│ │ Leaf 1  │           │   Leaf 2    │         │   Leaf 3    │   │
│ │Passkey+ │           │ Passkey+    │         │  CSV Exit   │   │
│ │  HW     │           │  Server     │         │<pk_passkey> │   │
│ │(MuSig2) │           │ (redundant) │         │ CHECKSIG    │   │
│ │         │           │             │         │ <52560> CSV │   │
│ └─────────┘           └─────────────┘         └─────────────┘   │
│                                                                 │
│ Note: Server+HW combination handled via Leaf 2 alternative      │
│       or additional leaf as needed                              │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Decaying Multisig with CSV Timelocks

The decaying multisig pattern ensures that users can always recover their funds, with security guarantees that gracefully degrade over time.

How CSV (CheckSequenceVerify) Works

CSV enforces a relative timelock measured in blocks since the UTXO was created:

$$\text{spendable_height} = \text{confirmation_height} + \text{csv_blocks}$$

For Nuri Wallet:

  • Normal operation: 2-of-2 or 2-of-3 MuSig2 required
  • After ~70 days (10,000 blocks): Alternative recovery paths activate
  • After ~1 year (52,560 blocks): Single-key emergency exit available

Timelock Visualization

┌─────────────────────────────────────────────────────────────────┐
│                    DECAYING SECURITY MODEL                      │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  Security                                                       │
│  Level                                                          │
│    ▲                                                            │
│    │                                                            │
│  3 ┤ ████████████████████┐                                      │
│    │                     │                                      │
│  2 ┤                     └───────────────────┐   2-of-3 config  │
│    │                                         │   (HW available) │
│    │                                         │                  │
│  1 ┤                                         └─────────────     │
│    │                                                            │
│    └────────────────────────────────────────────────────▶       │
│         T=0            T=10,000         T=52,560      Time      │
│         │              blocks           blocks        (blocks)  │
│         │              (~70 days)       (~1 year)               │
│         │                 │                │                    │
│         ▼                 ▼                ▼                    │
│   ┌──────────┐     ┌──────────────┐  ┌──────────────┐          │
│   │ Maximum  │     │ HW Recovery  │  │  Emergency   │          │
│   │ Security │     │  Available   │  │    Exit      │          │
│   │  2FA +   │     │ No server    │  │  Passkey     │          │
│   │ Passkey  │     │   needed     │  │    only      │          │
│   └──────────┘     └──────────────┘  └──────────────┘          │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Script Structure

CSV Exit Script (simplified):

OP_IF
    // Normal spending path: requires aggregated MuSig2 signature
    <aggregated_pubkey>
    OP_CHECKSIG
OP_ELSE
    // Emergency exit: after timelock, passkey alone can spend
    <52560>           // ~1 year in blocks
    OP_CHECKSEQUENCEVERIFY
    OP_DROP
    <passkey_pubkey>
    OP_CHECKSIG
OP_ENDIF

Re-locking Mechanism

To maintain maximum security, users should periodically “refresh” their UTXOs:

┌─────────────────────────────────────────────────────────────────┐
│                    UTXO REFRESH CYCLE                           │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   Initial Deposit          After 11 months         Re-deposit  │
│        │                        │                       │       │
│        ▼                        ▼                       ▼       │
│   ┌─────────┐              ┌─────────┐             ┌─────────┐ │
│   │  UTXO   │   Time       │  UTXO   │   Self-    │  UTXO   │ │
│   │  CSV=0  │  ─────▶      │CSV=47520│   send     │  CSV=0  │ │
│   │         │              │ (aging) │  ─────▶    │ (fresh) │ │
│   └─────────┘              └─────────┘             └─────────┘ │
│                                                                 │
│   Security: MAX            Security: Degrading    Security: MAX│
│                                                                 │
│   Wallet prompts user when UTXOs approach timelock expiry      │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Security Analysis

Threat Model

ThreatMitigation
Device theftPasskey protected by biometrics; key derived on-demand
Server compromiseServer keys in HSM; stateless derivation;
server alone cannot spend
PhishingWebAuthn origin binding prevents credential theft
Man-in-the-middleMuSig2 nonce protocol prevents signature forgery
Server disappearanceCSV timelock enables recovery; HW wallet
provides immediate alternative
Hardware wallet loss2-of-3 allows recovery with passkey + server
Passkey loss2-of-3 allows recovery with HW + server

Security Levels by Configuration

┌─────────────────────────────────────────────────────────────────┐
│                SECURITY COMPARISON                              │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│                    2-of-2           2-of-3                      │
│                    ──────           ──────                      │
│                                                                 │
│   Keys Required      2                2                         │
│   to Spend                                                      │
│                                                                 │
│   Single Point       Passkey         None                       │
│   of Failure         (for CSV exit)  (any 2 keys work)          │
│                                                                 │
│   Server Down        Wait ~1 year    Use Passkey + HW           │
│   Recovery                           (immediate)                │
│                                                                 │
│   Passkey Lost       Funds locked    Use Server + HW            │
│   Recovery           (CSV doesn't    (immediate)                │
│                      help here!)                                │
│                                                                 │
│   Best For           Simplicity,     Maximum security,          │
│                      casual users    significant holdings       │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Attack Scenarios

Scenario 1: Attacker Compromises Server

Attacker obtains: Server signing capability
Attacker needs:   Passkey authentication OR Hardware wallet

Result: ❌ Cannot steal funds (missing second key)
        ⚠️  Can potentially DoS by refusing to sign
        ✅ User recovers via CSV exit or HW wallet

Scenario 2: Attacker Steals Phone

Attacker obtains: Physical device
Attacker needs:   Biometric/PIN to unlock passkey
                  PLUS 2FA to authorize server signing

Result: ❌ Cannot steal funds (passkey protected by biometrics)
        ✅ Keys never stored on device (stateless)

Scenario 3: Attacker Compromises Both Passkey AND Server

Attacker obtains: Passkey credential + Server access
Result: ⚠️  Can steal funds in 2-of-2 config
        ✅ 2-of-3 config: HW wallet still required

Recovery Scenarios

Complete Recovery Matrix

Scenario2-of-2 Config2-of-3 Config
Lost phone (passkey)Wait for CSV (~1 year), then… ❌ still
can’t spend!Server + HW ✅
Server goes offlineWait for CSV (~1 year) ✅Passkey + HW ✅
(immediate)
Lost hardware walletN/A (not in config)Passkey + Server ✅
Lost phone + server down❌ Funds lostHW can spend after
CSV? (design decision)
Lost HW + server downWait for CSV ✅Wait for CSV ✅

Recovery Flow: Server Unavailable (2-of-3)

┌─────────────────────────────────────────────────────────────────┐
│          RECOVERY: SERVER UNAVAILABLE (2-of-3)                  │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   Step 1: Detect server unavailability                          │
│   ┌─────────────────────────────────────────┐                  │
│   │ App: "Server unreachable. Use hardware  │                  │
│   │       wallet for recovery signing?"     │                  │
│   └─────────────────────────────────────────┘                  │
│                                                                 │
│   Step 2: Authenticate with passkey                             │
│   ┌─────────────────────────────────────────┐                  │
│   │ User: [Biometric authentication]        │                  │
│   │ App:  Derives passkey private key       │                  │
│   └─────────────────────────────────────────┘                  │
│                                                                 │
│   Step 3: Tap NFC hardware wallet                               │
│   ┌─────────────────────────────────────────┐                  │
│   │ App: "Tap your Nuri Card to sign"       │                  │
│   │                                         │                  │
│   │        ┌───────────┐                    │                  │
│   │        │  📱 ←→ 💳 │  NFC               │                  │
│   │        └───────────┘                    │                  │
│   └─────────────────────────────────────────┘                  │
│                                                                 │
│   Step 4: MuSig2 signing between Passkey + HW                   │
│   ┌─────────────────────────────────────────┐                  │
│   │ Passkey partial sig + HW partial sig    │                  │
│   │              ↓                          │                  │
│   │    Aggregated Schnorr signature         │                  │
│   └─────────────────────────────────────────┘                  │
│                                                                 │
│   Step 5: Broadcast transaction                                 │
│   ┌─────────────────────────────────────────┐                  │
│   │ Transaction broadcast to Bitcoin network│                  │
│   │ ✅ Funds recovered without server       │                  │
│   └─────────────────────────────────────────┘                  │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Recovery Flow: CSV Emergency Exit (2-of-2)

┌─────────────────────────────────────────────────────────────────┐
│              RECOVERY: CSV EMERGENCY EXIT                       │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   Prerequisites:                                                │
│   • Server has been unavailable for extended period             │
│   • UTXO age > 52,560 blocks (~1 year)                          │
│   • User still has passkey access                               │
│                                                                 │
│   Step 1: Check UTXO eligibility                                │
│   ┌─────────────────────────────────────────┐                  │
│   │ App scans UTXOs for CSV-eligible funds  │                  │
│   │                                         │                  │
│   │ UTXO 1: 0.5 BTC  - Age: 55,000 blocks ✅│                  │
│   │ UTXO 2: 0.3 BTC  - Age: 40,000 blocks ❌│                  │
│   └─────────────────────────────────────────┘                  │
│                                                                 │
│   Step 2: Construct CSV spending transaction                    │
│   ┌─────────────────────────────────────────┐                  │
│   │ Input: UTXO with nSequence = 52,560     │                  │
│   │ Witness: <passkey_signature> <csv_script>│                  │
│   │ Output: New address controlled by user  │                  │
│   └─────────────────────────────────────────┘                  │
│                                                                 │
│   Step 3: Sign with passkey only                                │
│   ┌─────────────────────────────────────────┐                  │
│   │ No server needed - single signature     │                  │
│   │ sufficient for CSV exit path            │                  │
│   └─────────────────────────────────────────┘                  │
│                                                                 │
│   Step 4: Broadcast and confirm                                 │
│   ┌─────────────────────────────────────────┐                  │
│   │ Transaction valid because:              │                  │
│   │ • CSV timelock satisfied                │                  │
│   │ • Valid passkey signature provided      │                  │
│   │ ✅ Funds recovered!                     │                  │
│   └─────────────────────────────────────────┘                  │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Comparison with Existing Solutions

Nuri vs. Blockstream Green

FeatureBlockstream GreenNuri Wallet
Signature SchemeECDSA multisigMuSig2 Schnorr
On-chain FootprintVisible multisigSingle-sig appearance
Client Key StorageEncrypted on deviceStateless (PRF-derived)
Server Key StorageTraditional HSMStateless HSM derivation
Recovery (2-of-2)CSV timelockCSV timelock
Recovery (2-of-3)Backup key phraseHardware wallet
Taproot SupportLimitedNative

Nuri vs. Traditional Hardware Wallets

FeatureLedger/TrezorNuri Wallet
Form FactorDedicated devicePasskey + NFC card
Daily TransactionsDevice requiredPasskey only (server 2FA)
High-Value TransactionsSame as dailyCan require HW card
Loss RecoverySeed phraseMultiple paths (CSV, 2-of-3)
Theft RiskSeed phrase exposureNo seed phrase needed

Nuri vs. Custodial Solutions

FeatureCustodial ExchangeNuri Wallet
Key ControlExchange holds keysUser holds all keys
Counterparty RiskHighNone
Regulatory RiskSubject to seizureSelf-sovereign
RecoveryAccount recoveryCSV + multisig
PrivacyKYC requiredNo KYC for self-custody

Implementation Considerations

WebAuthn PRF Browser Support

┌─────────────────────────────────────────────────────────────────┐
│                 WEBAUTHN PRF SUPPORT STATUS                     │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   Browser/Platform          PRF Support    Notes                │
│   ────────────────          ───────────    ─────                │
│   Chrome (Desktop)          ✅ Yes         Windows Hello, etc.  │
│   Chrome (Android)          ✅ Yes         Fingerprint/PIN      │
│   Safari (macOS)            ✅ Yes         Touch ID             │
│   Safari (iOS)              ✅ Yes         Face ID/Touch ID     │
│   Firefox                   ⚠️ Partial     Platform dependent   │
│   Security Keys             ⚠️ Varies      FIDO2 Level 2 req.   │
│                                                                 │
│   Fallback Strategy:                                            │
│   • Detect PRF support at registration                          │
│   • Fall back to encrypted key storage if unavailable           │
│   • Clearly communicate security implications to user           │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

MuSig2 Implementation Notes

Key Aggregation:

// Simplified MuSig2 key aggregation
function aggregateKeys(pubkeys: Uint8Array[]): Uint8Array {
  // Sort pubkeys lexicographically for determinism
  const sortedKeys = [...pubkeys].sort(compareBytes);

  // Compute key aggregation coefficients
  const L = hashKeys(sortedKeys);

  // Aggregate with coefficients
  let aggregated = Point.ZERO;
  for (const pk of sortedKeys) {
    const P = Point.fromBytes(pk);
    const a = computeCoefficient(L, pk);
    aggregated = aggregated.add(P.multiply(a));
  }

  return aggregated.toBytes();
}

Nonce Generation (Critical for Security):

// MuSig2 requires fresh, unpredictable nonces
function generateNonce(
  secretKey: Uint8Array,
  publicKey: Uint8Array,
  message: Uint8Array,
  extraRand: Uint8Array
): { secretNonce: Uint8Array; publicNonce: Uint8Array } {
  // MUST use fresh randomness for each signing session
  const rand = crypto.getRandomValues(new Uint8Array(32));

  // Derive nonce deterministically from inputs + randomness
  const k = taggedHash(
    "MuSig2/nonce",
    concat(secretKey, publicKey, message, rand, extraRand)
  );

  return {
    secretNonce: k,
    publicNonce: Point.BASE.multiply(k).toBytes()
  };
}

NFC Hardware Wallet Protocol

┌─────────────────────────────────────────────────────────────────┐
│              NFC SIGNING PROTOCOL (APDU)                        │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   Command                    Response                           │
│   ───────                    ────────                           │
│                                                                 │
│   SELECT APPLET              OK + Version                       │
│   ┌────────────────┐         ┌────────────────┐                │
│   │ CLA: 00        │   ──▶   │ SW: 9000       │                │
│   │ INS: A4        │         │ Version: 1.0   │                │
│   │ AID: Nuri...   │         │                │                │
│   └────────────────┘         └────────────────┘                │
│                                                                 │
│   GET PUBLIC KEY             Public Key                         │
│   ┌────────────────┐         ┌────────────────┐                │
│   │ CLA: E0        │   ──▶   │ SW: 9000       │                │
│   │ INS: 40        │         │ PubKey: 33B    │                │
│   │ Path: m/86'/...│         │                │                │
│   └────────────────┘         └────────────────┘                │
│                                                                 │
│   MUSIG2 NONCE               Nonce Commitment                   │
│   ┌────────────────┐         ┌────────────────┐                │
│   │ CLA: E0        │   ──▶   │ SW: 9000       │                │
│   │ INS: 50        │         │ R: 33B         │                │
│   │ SessionID      │         │                │                │
│   └────────────────┘         └────────────────┘                │
│                                                                 │
│   MUSIG2 SIGN                Partial Signature                  │
│   ┌────────────────┐         ┌────────────────┐                │
│   │ CLA: E0        │   ──▶   │ SW: 9000       │                │
│   │ INS: 52        │         │ s: 32B         │                │
│   │ Message hash   │         │                │                │
│   │ Agg nonce      │         │                │                │
│   │ Agg pubkey     │         │                │                │
│   └────────────────┘         └────────────────┘                │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Conclusion

Nuri Wallet represents a significant advancement in Bitcoin self-custody, combining:

  1. Stateless Security: No persistent key storage reduces attack surface
  2. Multi-Party Signing: MuSig2 provides privacy and efficiency
  3. Graceful Degradation: Decaying timelocks ensure recovery is always possible
  4. Flexible Security: 2-of-2 and 2-of-3 configurations for different needs

The architecture ensures that users maintain full sovereignty over their Bitcoin while benefiting from the security of multi-signature protection and the convenience of modern authentication methods.


Appendix A: Glossary

TermDefinition
CSVCheckSequenceVerify; Bitcoin opcode for relative timelocks
HSMHardware Security Module; tamper-resistant key storage
MuSig2Multi-signature scheme for Schnorr signatures
PRFPseudo-Random Function; WebAuthn extension for key derivation
TaprootBitcoin upgrade enabling Schnorr signatures and MAST
UTXOUnspent Transaction Output; Bitcoin’s accounting model
WebAuthnWeb Authentication standard for passwordless auth

Appendix B: References

  1. BIP-340: Schnorr Signatures for secp256k1
  2. BIP-341: Taproot
  3. BIP-327: MuSig2
  4. WebAuthn PRF Extension
  5. Blockstream Green Security Model

Post created via email from emin@nuri.com