bivvydocs
Developers / Security & recovery
BIVVY DOCS

Under the canopy.

Clear boundaries. Your keys. An honest look at the foundations.

Passkey-derived, from the start

Bivvy evaluates WebAuthn’s PRF extension with a fixed, versioned input. HKDF-SHA256 turns the secret into 256-bit BIP39 entropy. The resulting 24 words initialize the Spark wallet and derive the Nostr key. Registration and login require user verification. There is no password, email, social login, or random-seed fallback.

Wallet format v1
PRF input = UTF8("bivvy.me/passkey/v1")
root entropy = HKDF-SHA256(PRF, PRF input,
  UTF8("bivvy.me/bip39/root/v1"), 32)
root mnemonic = BIP39(root entropy)
Nostr key = BIP32(BIP39-seed(root mnemonic), "m/44'/1237'/0'/0/0")

Origin isolation

The embed script has no key derivation code. A Bivvy iframe validates the parent window, exact message origin, channel, method, and request ID. Spending allowances are bound to that origin. Top-level Bivvy popups display sensitive requests outside the embedding page.

The popup passes an approved secret only to its same-origin Bivvy iframe opener. The iframe returns only the requested operation result to the host. No SDK method exports a mnemonic or private key.

What is stored?

  • On your device: a public credential ID as a login hint. The root mnemonic is held in memory while unlocked.
  • In your passkey provider: the passkey, with syncing and recovery controlled by that provider.
  • On Bivvy’s server: public username mappings, signed permission records, and payment allowance reservations. No user seed or private key.

Self custody and the trust model

Bivvy is self custodial. It is not accurate to call a hosted JavaScript wallet absolutely trustless. Users trust the browser, authenticator, passkey sync provider, the code delivered by bivvy.me, and the dependencies it runs. A compromised Bivvy deployment could access an unlocked wallet.

Spark adds its own signing-operator, service-provider, availability, and exit assumptions. Payment allowance accounting relies on Bivvy’s database. Read Spark’s documentation before choosing it for your use case.

Back up a way out

Passkeys are bound to their relying-party domain. If bivvy.me becomes unavailable, a passkey alone cannot be used from a different domain. In your wallet, open permissions → view recovery words and save them privately. Those words restore your Spark wallet and standard NIP-06 Nostr identity.

Creating another passkey creates another wallet. Synced access depends on your passkey provider supporting both sync and PRF. Test recovery on your second device before relying on it.

Browser support

Bivvy requires a browser and authenticator that support WebAuthn PRF, discoverable passkeys, and required user verification. Browser names alone do not guarantee support; support also depends on the chosen authenticator. Bivvy fails closed when PRF is unavailable. Use a normal browser with popups enabled for embedded flows.

Security tests

The repository contains the security test plan. The implementation is in active development; it has not received an independent security audit. Unit, integration, and browser isolation results are recorded alongside the source.

Reporting an issue

Use the repository’s security reporting guidance. Never include your passkey, recovery words, or private keys in an issue.

Made to be understood. Built to be yours.View the source