# KrayWallet Security Architecture

**Version:** 1.2.0
**Last Updated:** January 31, 2026

---

## Executive Summary

KrayWallet is a **self-custodial Bitcoin wallet** that implements **industry-standard security practices** to ensure that **each user has complete control** over their funds. Your mnemonic, private keys, and signatures **never leave your device**.

### Core Security Principles

- **Zero-Trust Architecture** - No server has access to your keys
- **Client-Side Signing** - All cryptographic operations happen locally
- **Local Wallet Generation** - Mnemonic creation and address derivation are fully local (v1.2.0)
- **Open Source** - Fully auditable code
- **Industry Standards** - Follows BIP39, BIP32, BIP86, BIP340 (Schnorr), BIP341
- **No Backdoors** - Your keys, your Bitcoin

---

## How Your Keys Are Protected

### 1. Mnemonic Generation (12 Words)

**Process:**
```
User creates new wallet
  |
  v
Extension calls generateWalletLocal() (v1.2.0)
  |
  v
12 words generated locally using BIP39
  |
  v
Uses browser's crypto.getRandomValues() for entropy
  |
  v
Mnemonic NEVER sent to any server
  |
  v
Stored encrypted with user's password
```

**Technologies:**
- **BIP39** - Standard mnemonic generation
- **Web Crypto API** - Secure random number generation
- **chrome.storage.local** - Encrypted storage in browser

**Security Guarantees:**
- Generated entirely on your device
- Never transmitted over any network
- Cryptographically secure entropy source
- Compatible with other BIP39-compliant wallets

---

### 2. Key Derivation (BIP32/BIP86)

**Process:**
```
Mnemonic (12 words)
  |
  v
Seed derivation (BIP39)
  |
  v
Master key generation (BIP32)
  |
  v
Taproot derivation path: m/86'/0'/0'/0/0 (BIP86)
  |
  v
Taproot address generation (P2TR)
```

As of v1.2.0, address derivation is handled entirely by `getAddressFromMnemonic()` in the local bundle. No backend calls are involved.

**Technologies:**
- **BIP32** - Hierarchical Deterministic key derivation
- **BIP86** - Taproot address derivation standard
- **bitcoinjs-lib** - Industry-standard Bitcoin library

**Security Guarantees:**
- All derivation happens locally in-browser
- Keys are never stored in plaintext
- Compatible with hardware wallets using the same derivation path
- Standard derivation path ensures interoperability

---

### 3. Transaction Signing (Schnorr)

**Process:**
```
User initiates transaction
  |
  v
Backend creates unsigned PSBT (no keys required)
  |
  v
Extension decrypts mnemonic locally (with user password)
  |
  v
Derives keys locally (BIP32/BIP86)
  |
  v
Signs PSBT locally (Schnorr signature - BIP340)
  |
  v
Clears mnemonic and keys from memory immediately
  |
  v
Broadcasts signed transaction only
```

**Technologies:**
- **tiny-secp256k1** - WebAssembly Schnorr signing
- **bitcoinjs-lib** - PSBT handling
- **BIP340** - Schnorr signature standard (Taproot)
- **Webpack Bundle** - Local signing library

**Security Guarantees:**
- Signing happens entirely in your browser
- Private keys are never transmitted
- Memory is cleared after signing
- Only the signed transaction (public data) is broadcast

---

### 4. Encryption at Rest

**Process:**
```
User sets password
  |
  v
Mnemonic encrypted with PBKDF2 + AES-256-GCM
  |
  v
Encrypted blob stored in chrome.storage.local
  |
  v
Decrypted only when user enters password
  |
  v
Never stored in plaintext
```

**Technologies:**
- **PBKDF2** - Key derivation from password (100,000 iterations, SHA-256)
- **AES-256-GCM** - Authenticated encryption
- **Web Crypto API** - Browser's built-in secure crypto primitives

**Security Guarantees:**
- Strong encryption (AES-256-GCM)
- Password is never persisted to disk
- Authenticated encryption prevents tampering
- Key stretching resists brute-force attacks (PBKDF2, 100,000 iterations)

**Session behavior:** After the user unlocks the wallet, a session reference is held in `chrome.storage.session` for the duration of the browser session. This avoids re-prompting for the password on every action. The session reference is automatically cleared when the browser closes or when the auto-lock timer expires (default: 15 minutes of inactivity).

---

## Security Architecture Diagram

```
+-------------------------------------------------------------+
|                    USER'S DEVICE (SECURE)                    |
|                                                              |
|  +--------------------------------------------------------+  |
|  |  KrayWallet Extension (Chrome)                         |  |
|  |                                                        |  |
|  |  1. Mnemonic Generation (BIP39)                        |  |
|  |     -> 12 words generated locally                      |  |
|  |                                                        |  |
|  |  2. Encryption (AES-256-GCM)                           |  |
|  |     -> Encrypted with user password                    |  |
|  |                                                        |  |
|  |  3. Storage (chrome.storage.local)                     |  |
|  |     -> Encrypted blob only                             |  |
|  |                                                        |  |
|  |  4. Key Derivation (BIP32/BIP86)                       |  |
|  |     -> Happens on-demand, in memory                    |  |
|  |                                                        |  |
|  |  5. Transaction Signing (Schnorr - BIP340)             |  |
|  |     -> Signed locally with tiny-secp256k1 (WASM)       |  |
|  |                                                        |  |
|  |  6. Memory Cleanup                                     |  |
|  |     -> Keys cleared after use                          |  |
|  +--------------------------------------------------------+  |
|                                                              |
|              | ONLY signed transaction leaves |               |
|              v                                               |
+-------------------------------------------------------------+
              |
              | HTTPS
              v
+-------------------------------------------------------------+
|                   KRAYWALLET BACKEND                         |
|                    (UNTRUSTED ZONE)                          |
|                                                              |
|  [OK] Creates unsigned PSBTs                                 |
|  [OK] Broadcasts signed transactions                         |
|  [OK] Queries blockchain data                                |
|  [NO] NEVER sees mnemonic                                    |
|  [NO] NEVER sees private keys                                |
|  [NO] CANNOT sign transactions                               |
|                                                              |
+-------------------------------------------------------------+
              |
              | Bitcoin P2P
              v
+-------------------------------------------------------------+
|                    BITCOIN NETWORK                           |
|                                                              |
|  Receives signed transactions                                |
|  Validates signatures                                        |
|  Confirms blocks                                             |
|                                                              |
+-------------------------------------------------------------+
```

---

## Compliance with Industry Standards

### BIP Standards

| BIP | Description | Status |
|-----|-------------|--------|
| **BIP39** | Mnemonic code for generating deterministic keys | Fully compliant |
| **BIP32** | Hierarchical Deterministic Wallets | Fully compliant |
| **BIP44** | Multi-Account Hierarchy (Legacy/SegWit) | Not used (Taproot focus) |
| **BIP86** | Key Derivation for Single Key P2TR Outputs | Fully compliant |
| **BIP340** | Schnorr Signatures for secp256k1 | Fully compliant |
| **BIP341** | Taproot: SegWit version 1 | Fully compliant |
| **BIP174** | Partially Signed Bitcoin Transactions (PSBT) | Fully compliant |

### Comparison with Bitcoin Wallets

| Feature | KrayWallet | Xverse | Unisat | Sparrow | Ledger |
|---------|------------|--------|--------|---------|--------|
| Local Signing | Yes | Yes | Yes | Yes | Hardware |
| Open Source | Yes | Partial | Partial | Yes | Partial |
| Taproot (P2TR) | Yes | Yes | Yes | Yes | Yes |
| Ordinals | Yes | Yes | Yes | Limited | Limited |
| Runes | Yes | Yes | Limited | No | No |
| Self-Custodial | Yes | Yes | Yes | Yes | Yes |
| Chrome Extension | Yes | Yes | Yes | No (Desktop) | No (Hardware) |

---

## Code Verification

### Local Signing Implementation

**Source:** `src/taproot-signer-local.js` (bundled to `background/taproot-signer.bundle.js`)

**Key functions (v1.2.0):**

- `generateWalletLocal(wordCount)` - Creates a new mnemonic and derives the Taproot address entirely in-browser
- `getAddressFromMnemonic(mnemonic)` - Derives a Taproot address from an existing mnemonic without any server calls
- `signPsbtTaprootLocal(mnemonic, psbtBase64)` - Signs a PSBT locally using Schnorr signatures

**Signing flow:**
```javascript
async function signPsbtTaprootLocal(mnemonic, psbtBase64) {
    // 1. Derive seed locally (BIP39)
    const seed = await bip39.mnemonicToSeed(mnemonic);

    // 2. Derive key locally (BIP32/BIP86)
    const root = bip32.BIP32Factory(ecc).fromSeed(seed, network);
    const child = root.derivePath("m/86'/0'/0'/0/0");

    // 3. Apply Taproot tweak (BIP341)
    const xOnly = Buffer.from(child.publicKey.subarray(1, 33));
    const tapTweak = bitcoin.crypto.taggedHash('TapTweak', xOnly);
    let tweakedPriv = ecc.privateAdd(child.privateKey, tapTweak);

    // 4. Ensure even Y coordinate (Taproot requirement)
    const tweakedPub = ecc.pointFromScalar(tweakedPriv);
    if (tweakedPub[0] !== 0x02) {
        tweakedPriv = ecc.privateNegate(tweakedPriv);
    }

    // 5. Create Schnorr signer (BIP340)
    const signer = {
        signSchnorr: (hash) => {
            return ecc.signSchnorr(hash, tweakedPriv, Buffer.alloc(32, 0));
        }
    };

    // 6. Sign PSBT locally
    const psbt = bitcoin.Psbt.fromBase64(psbtBase64);
    for (let i = 0; i < psbt.inputCount; i++) {
        psbt.signInput(i, signer);

        const isValid = psbt.validateSignaturesOfInput(i, signer.signSchnorr);
        if (!isValid) throw new Error('Invalid signature');
    }

    // 7. Finalize and extract transaction
    psbt.finalizeAllInputs();
    const txHex = psbt.extractTransaction().toHex();

    // 8. Clear sensitive data from memory
    mnemonic = null;
    tweakedPriv = null;

    return txHex; // Only the signed transaction
}
```

**Security properties of this implementation:**
- All operations happen locally, no network calls
- Signature validation before broadcast
- Memory cleanup after signing
- Uses standard, widely-audited libraries (bitcoinjs-lib, tiny-secp256k1)

---

## Security Testing

### How to Verify Security

1. **Install the extension:**
   ```bash
   git clone https://github.com/tomkray/kraywallet-extension.git
   cd kraywallet-extension
   ```

2. **Load in Chrome:**
   - Go to `chrome://extensions`
   - Enable "Developer mode"
   - Click "Load unpacked"
   - Select the extension folder

3. **Open DevTools:**
   - Right-click the extension icon and select "Inspect"
   - Go to the Console tab

4. **Create a wallet and test:**
   - Create a new wallet
   - Send a test transaction
   - Observe console output

5. **Expected console output (normal operation):**
   ```
   Local signer loaded! Mnemonic will NEVER leave device!

   [When sending a transaction:]
   SECURE SEND (3-STEP PROCESS)
   Step 1: Creating PSBT structure...
      Mnemonic NOT sent!
   PSBT created

   Step 2: Signing PSBT...
      Using LOCAL signing (mnemonic NEVER leaves device!)
   Signing PSBT 100% LOCALLY...
      Seed derived
      Key derived: m/86'/0'/0'/0/0
      Taproot key ready
      PSBT loaded
      All inputs signed and validated
      Transaction finalized
   PSBT SIGNED 100% LOCALLY!

   Step 3: Broadcasting...
      Only signed TX sent!
   BROADCAST SUCCESS!
   ```

6. **Red flags (should NEVER appear):**
   ```
   Using BACKEND signing (INSECURE - mnemonic sent!)
   Sending mnemonic to server
   Remote signing
   ```

---

## Network Requests Analysis

### What Gets Sent to Backend

#### Safe Requests (No Sensitive Data)

1. **Create PSBT**
   ```json
   POST /api/kraywallet/create-inscription-psbt
   {
     "inscription": {
       "utxo": {
         "txid": "abc123...",
         "vout": 0,
         "value": 555
       }
     },
     "recipientAddress": "bc1p...",
     "senderAddress": "bc1p...",
     "feeRate": 1
   }
   ```
   **Contains:** Public addresses, UTXO references, fee rate
   **Does NOT contain:** Mnemonic, private keys, signatures

2. **Broadcast Transaction**
   ```json
   POST /api/psbt/broadcast
   {
     "hex": "020000000001..."
   }
   ```
   **Contains:** Signed transaction (public data)
   **Does NOT contain:** Mnemonic, private keys

3. **Query Balance/UTXOs**
   ```json
   GET /api/wallet/{address}/utxos
   GET /api/wallet/{address}/balance
   GET /api/wallet/{address}/inscriptions
   ```
   **Contains:** Public address only
   **Does NOT contain:** Any private data

#### What NEVER Gets Sent

- Mnemonic (12 words)
- Private keys
- Seed phrase
- User password
- Unencrypted wallet data

---

## Threat Model & Mitigations

### Threat 1: Malicious Backend

**Risk:** Backend could be compromised.
**Impact:** Attacker could see public addresses and transaction data, but NOT keys.
**Mitigation:**
- Local signing prevents key exposure
- Backend never receives sensitive data
- Users can switch to a different backend without losing funds

### Threat 2: Compromised Device

**Risk:** Malware on user's computer.
**Impact:** Could potentially access extension storage.
**Mitigation:**
- Wallet data encrypted with user password (AES-256-GCM)
- Password not persisted to disk
- Memory cleared after cryptographic operations
- Users should use a strong password
- Consider a hardware wallet for large amounts

### Threat 3: Network Interception

**Risk:** Man-in-the-middle attack.
**Impact:** Could intercept public data, but NOT keys.
**Mitigation:**
- HTTPS for all API calls
- No sensitive data is transmitted
- Signed transactions are inherently public

### Threat 4: Extension Store Compromise

**Risk:** Malicious update pushed via distribution channel.
**Impact:** Could replace extension code.
**Mitigation:**
- Open source: users can verify code before updating
- GitHub releases are tagged
- Users can load directly from source
- Users should verify updates before installing

### Threat 5: Browser Vulnerability

**Risk:** Browser bug could expose extension data.
**Impact:** Could access storage or memory.
**Mitigation:**
- Encryption at rest
- Memory cleanup after operations
- Auto-lock with configurable timeout (default: 15 minutes)
- Users should keep their browser updated

---

## Best Practices for Users

### During Setup

1. **Strong Password**
   - Use at least 12 characters
   - Mix uppercase, lowercase, numbers, and symbols
   - Do not reuse passwords from other services
   - Consider using a password manager

2. **Backup Mnemonic**
   - Write down all 12 words on paper
   - Store in a secure physical location
   - Never take a photo or screenshot
   - Never store in cloud services or digital notes
   - Consider a metal backup for long-term durability

3. **Verify Backup**
   - Test a restore on a different device
   - Verify the derived address matches
   - Send a small test transaction first

### During Usage

1. **Lock Wallet**
   - Auto-lock is enabled by default (15 minutes)
   - Lock manually when not in use
   - Use a shorter timeout on shared computers

2. **Verify Transactions**
   - Check the recipient address carefully
   - Verify the amount and fee rate
   - Double-check all details before signing

3. **Monitor Activity**
   - Review transaction history regularly
   - Watch for unexpected transactions
   - Verify addresses match your expectations

### Security Hygiene

1. **Device Security**
   - Keep your OS updated
   - Use reputable security software
   - Avoid public or untrusted WiFi for transactions
   - Lock your screen when stepping away

2. **Browser Security**
   - Keep Chrome updated
   - Only install extensions from trusted sources
   - Clear cache periodically
   - Use a dedicated browser profile for your wallet

3. **Phishing Protection**
   - Verify URLs before entering information
   - Never share your mnemonic with anyone
   - No legitimate support team will ever ask for your mnemonic
   - Bookmark the official site: [kray.space](https://kray.space)

---

## Encryption Details

### Storage Encryption

**Algorithm:** AES-256-GCM
**Key Derivation:** PBKDF2 (100,000 iterations, SHA-256)
**Salt:** Random 16 bytes per wallet
**IV:** Random 12 bytes per encryption operation

**Encryption Process:**
```
1. User enters password
2. Generate random salt (16 bytes)
3. Derive key: PBKDF2(password, salt, 100000, 'SHA-256')
4. Generate random IV (12 bytes)
5. Encrypt: AES-256-GCM(mnemonic, key, IV)
6. Store: { encrypted, salt, iv }
```

**Decryption Process:**
```
1. User enters password
2. Retrieve { encrypted, salt, iv }
3. Derive key: PBKDF2(password, salt, 100000, 'SHA-256')
4. Decrypt: AES-256-GCM-Decrypt(encrypted, key, iv)
5. Verify authentication tag
6. Return mnemonic (if valid)
```

**Security Properties:**
- Authenticated encryption prevents tampering
- Unique IV per encryption operation
- Strong key derivation (100,000 PBKDF2 iterations)
- Industry-standard algorithm
- Resistant to brute-force attacks

---

## Dependencies & Audit

### Core Dependencies

| Library | Version | Purpose | Audit Status |
|---------|---------|---------|--------------|
| bitcoinjs-lib | 6.1.5 | Bitcoin protocol operations | Widely audited |
| tiny-secp256k1 | 2.2.3 | Schnorr signatures (WebAssembly) | Audited |
| bip32 | 4.0.0 | HD key derivation | Standard library |
| bip39 | 3.1.0 | Mnemonic generation | Standard library |

### Bundle Composition

**Total Size:** ~548 KB (minified)
**WebAssembly:** ~160 KB (secp256k1)
**JavaScript:** ~388 KB (Bitcoin libraries)

**Bundle properties:**
- No telemetry or analytics
- No external network calls from bundle code
- Deterministic build (reproducible with `npm run build`)

### Build Verification

```bash
# Clone repository
git clone https://github.com/tomkray/kraywallet-extension.git
cd kraywallet-extension

# Install dependencies
npm install

# Build bundle
npm run build

# Verify bundle integrity
sha256sum background/taproot-signer.bundle.js
```

---

## Security Roadmap

### Completed (v1.0.0)

- Local mnemonic generation (BIP39)
- Encrypted storage (AES-256-GCM)
- Local key derivation (BIP32/BIP86)
- Local Schnorr signing (BIP340)
- PSBT support (BIP174)
- Taproot addresses (BIP341)
- Memory cleanup after operations
- Auto-lock functionality
- Open source codebase

### Completed (v1.2.0)

- Fully local wallet generation via `generateWalletLocal()`
- Fully local address derivation via `getAddressFromMnemonic()`
- Removed all backend dependencies for key management operations
- Security hardening and dead code removal

### Planned

- Hardware wallet support (Ledger, Trezor)
- Multi-signature support
- Watch-only wallet mode
- Lightning Network integration

---

## OWASP Compliance

KrayWallet's security posture against the **OWASP Top 10 for Browser Extensions:**

| Category | Status | Notes |
|----------|--------|-------|
| Improper Platform Usage | Compliant | Uses Manifest V3, minimal permissions |
| Insecure Data Storage | Compliant | AES-256-GCM encryption at rest |
| Insecure Communication | Compliant | HTTPS only, no sensitive data in transit |
| Insecure Authentication | Compliant | Strong crypto, PBKDF2 key derivation |
| Insufficient Cryptography | Compliant | Industry-standard algorithms throughout |
| Insecure Authorization | Compliant | Local control, no server-side auth |
| Client Code Quality | Compliant | Linted, minimal dependencies |
| Code Tampering | Compliant | Open source, verifiable builds |
| Reverse Engineering | Not applicable | Code is open source |
| Extraneous Functionality | Compliant | Minimal attack surface, no debug endpoints |

---

## Responsible Disclosure

### Found a Security Issue?

**Do NOT open a public GitHub issue for security vulnerabilities.**

Instead, report privately via [GitHub Security Advisories](https://github.com/tomkray/kraywallet-extension/security/advisories/new).

Please include:
- Description of the vulnerability
- Steps to reproduce
- Potential impact assessment
- Suggested fix (if applicable)

We will:
- Acknowledge receipt within 48 hours
- Provide a fix timeline
- Credit the reporter (if desired)
- Coordinate responsible disclosure

---

## License & Legal

**License:** MIT
**Copyright:** 2025-2026 KrayWallet Contributors

### Disclaimer

KrayWallet is provided "as is" without warranty. Users are responsible for:
- Backing up their mnemonic
- Keeping their password secure
- Verifying transactions before signing
- Following appropriate security practices

**Not liable for:**
- User error (lost mnemonic, weak password)
- Device compromise (malware, theft)
- Phishing attacks
- Market volatility or regulatory changes

### No Investment Advice

KrayWallet is a tool for managing Bitcoin. It does not:
- Provide investment advice
- Guarantee returns
- Endorse any assets
- Offer custodial services

---

## Contact & Support

**Website:** [kray.space](https://kray.space)
**GitHub:** [github.com/tomkray/kraywallet-extension](https://github.com/tomkray/kraywallet-extension)

**Support:** Open an issue on [GitHub](https://github.com/tomkray/kraywallet-extension/issues)
**Security:** Report privately via [GitHub Security Advisories](https://github.com/tomkray/kraywallet-extension/security/advisories/new)

---

## Conclusion

KrayWallet implements industry-standard security practices to ensure that:

1. **Your mnemonic never leaves your device**
2. **Your private keys never touch the network**
3. **Your signatures are created locally**
4. **You have complete control of your funds**

Each user who installs KrayWallet has:
- A unique mnemonic generated locally (BIP39)
- Encrypted storage (AES-256-GCM)
- Local signing (Schnorr/Taproot)
- Complete self-custody

KrayWallet follows the same security model used by leading Bitcoin wallets including Xverse, Unisat, Sparrow, and Ledger. Our code is open source, auditable, and follows all relevant Bitcoin Improvement Proposals (BIPs).

**Your keys, your Bitcoin. Always.**

---

**Version:** 1.2.0
**Last Updated:** January 31, 2026

*This document is maintained by the KrayWallet team. For updates or corrections, please open a pull request on [GitHub](https://github.com/tomkray/kraywallet-extension).*
