npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@norionsoft/w2qr-shamir

v1.0.0

Published

Secure multi-share wallet backup using Shamir Secret Sharing, password-protected QR payloads, and BIP39 mnemonic support

Readme

@norionsoft/w2qr-shamir

Secure multi-share wallet backup using Shamir Secret Sharing, password-protected QR payloads, and BIP39 mnemonic support.

Security Warning: This package has not been independently audited. Use at your own risk for production wallet protection. Always test restore after creation. Never upload shares to untrusted servers.

Installation

npm install @norionsoft/w2qr-shamir

How it works

mnemonic/entropy → Shamir split → each share encrypted with password → each encrypted share encoded as QR code

QR payloads + passwords → decrypted shares → threshold validation → mnemonic recovery

Usage

Create a 3-of-5 backup

import { createMultishareWallet } from '@norionsoft/w2qr-shamir'

const backup = await createMultishareWallet({
  threshold: 3,
  totalShares: 5,
  passwords: ['p1', 'p2', 'p3', 'p4', 'p5'],
  qr: { format: 'svg' }
})

console.log('Mnemonic:', backup.mnemonic)
console.log('Wallet ID:', backup.walletId)

for (const share of backup.shares) {
  console.log(`Share ${share.index}:`, share.qrPayload)
  // share.qrSvg contains SVG markup
}

Restore from 3 shares

import { restoreMultishareWallet } from '@norionsoft/w2qr-shamir'

const restored = await restoreMultishareWallet({
  shares: [
    { qrPayload: backup.shares[0].qrPayload, password: 'p1' },
    { qrPayload: backup.shares[2].qrPayload, password: 'p3' },
    { qrPayload: backup.shares[4].qrPayload, password: 'p5' }
  ]
})

if (restored.success) {
  console.log('Recovered mnemonic:', restored.mnemonic)
}

Backup an existing mnemonic

const backup = await createMultishareWallet({
  mnemonic: 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about',
  threshold: 2,
  totalShares: 3,
  passwords: ['password-a', 'password-b', 'password-c']
})

Supported Schemes

| Scheme | Description | |--------|-------------| | 2-of-2 | Both shares required | | 2-of-3 | Any 2 of 3 shares | | 3-of-3 | All 3 shares required | | 3-of-4 | Any 3 of 4 shares | | 3-of-5 | Any 3 of 5 shares | | 4-of-5 | Any 4 of 5 shares |

Generic: threshold >= 2, totalShares >= threshold, totalShares <= 10

API Reference

createMultishareWallet(options)

Creates a multi-share wallet backup.

Options:

  • mnemonic? — Existing BIP39 mnemonic to split
  • entropy? — Raw entropy bytes
  • strength? — Entropy strength: 128, 160, 192, 224, or 256 (default: 256)
  • threshold — Minimum shares needed to restore
  • totalShares — Total number of shares to create
  • passwords — Array of passwords, one per share
  • wordlist? — Custom BIP39 wordlist
  • kdf? — KDF options ({ iterations?: number })
  • qr? — QR options ({ format?: 'svg' | 'dataUrl' | 'both' })

Returns: MultishareWalletResult with walletId, fingerprint, mnemonic, and shares[]

restoreMultishareWallet(options)

Restores a wallet from share payloads and passwords.

Options:

  • shares — Array of { qrPayload: string, password: string }
  • wordlist? — Custom BIP39 wordlist

Returns: RestoreMultishareWalletResult — discriminated union with success: true (includes mnemonic, entropy) or success: false (includes reason, optional decoyMnemonic)

generateMnemonic(strength?, wordlist?)

Generates a new BIP39 mnemonic phrase.

validateSharePayload(payload)

Returns true if the payload string is a valid w2qr-shamir share.

inspectShare(payload)

Returns public metadata from a share payload without decryption.

encodeSharePayload(data) / decodeSharePayload(payload)

Low-level payload encoding/decoding.

estimateQrSize(payloadLength)

Estimates QR code version needed for a payload.

Payload Format

Each share is encoded as: w2qrs1:<base64url-encoded-json>

Public metadata (visible without password):

{
  "v": 1,
  "t": "w2qr-s",
  "wid": "<walletId>",
  "i": 2,
  "th": 3,
  "n": 5,
  "fp": "<fingerprint>",
  "enc": {
    "alg": "AES-256-GCM",
    "kdf": "PBKDF2-SHA256",
    "iter": 600000,
    "salt": "<base64url>",
    "nonce": "<base64url>",
    "ct": "<base64url>"
  }
}

Browser / Node Compatibility

  • Node.js >= 18 (uses crypto.subtle for AES-GCM)
  • Modern browsers with WebCrypto API support
  • ESM-only (no CommonJS)

Honey Mode

v1 implements basic honey mode: wrong passwords do not throw raw cryptographic errors. Instead, failed decryption returns a plausible decoy mnemonic derived from the password and share salt.

Limitation: v1 honey mode is plausibility/decoy behavior, not formal distribution-transforming honey encryption. Future versions may add full honey-wallet reconstruction where wrong passwords produce valid decoy wallets.

QR Size Notes

Typical share payloads for a 24-word (256-bit) mnemonic with AES-256-GCM are ~800-1200 bytes encoded. This fits comfortably in QR version 15-25 (error correction level M). For 12-word mnemonics, payloads are smaller.

Security Recommendations

  • Use strong, unique passwords for each share
  • Store shares in separate physical locations
  • Always test restore after creation
  • Do not upload shares to untrusted servers
  • Print or store QR codes on durable media
  • Consider laminating printed QR codes
  • Entropy is split (not the mnemonic text) to avoid leaking word boundaries

Cryptographic Details

  • Secret Sharing: Shamir over GF(256) — each byte of entropy is split independently
  • Encryption: AES-256-GCM via WebCrypto API (authenticated encryption)
  • KDF: PBKDF2-SHA256 with 600,000 iterations (configurable)
  • Random: crypto.getRandomValues (CSPRNG)
  • Checksums: SHA-256 with domain separation
  • Independent salt and nonce per share

Roadmap

  • [ ] Formal honey encryption (distribution-transforming)
  • [ ] SLIP-0039 compatibility
  • [ ] Web Worker KDF offloading
  • [ ] CLI tool
  • [ ] Independent security audit
  • [ ] Argon2id KDF support

License

MIT