Beersy
BRC-39

User Wallet Data Format Encryption Extension

A file containing everything about your wallet is not something to leave lying around unprotected. This defines the encrypted wrapper around such an export, so a backup can be stored safely and restored with a password.

Ty Everettchanged 1 May 20267 min read
wdat headerbrc39 encryptibrc38 json

Summary

Why
Wallet data needs to leave a wallet as one downloadable file that is safely encrypted, self-describing, and openable by any conforming wallet, not just the one that made it.
What
BRC-39 is a binary, password-encrypted file format for exporting and importing a wallet's full BRC-38 data as a single portable file, conventionally named wallet.brc39.
How
An exporter serializes the wallet's BRC-38 data as canonical JSON, derives a key from the user's password with Argon2id, encrypts the JSON with AES-256-GCM, and writes it into a versioned binary header plus salt, nonce, and ciphertext.

What this lets you do

  • Export a full BRC-38 wallet document as one encrypted binary file
  • Protect the export with a user-chosen password run through Argon2id
  • Detect tampering or wrong passwords via AES-256-GCM authentication
  • Reject malformed or non-conforming files before decryption completes
  • Move a wallet's data between different wallet implementations

Written by claude-sonnet-5 from the specification text. Where the two differ, the original is correct.

Reference for an AI

Everything an assistant needs to answer questions about BRC-39 accurately, including what it depends on.

The specification

Abstract

This specification defines the canonical encrypted wrapper for BRC-38 user wallet data exports.

It standardizes a downloadable binary file format, conventionally named wallet.brc39, for password-protected wallet export and import. The design is intended for strong user data portability, backups, archival export, GDPR-style data access, and migration between wallet implementations and storage providers.

BRC-39 uses:

  • the BRC-38 payload as its canonical plaintext inner document
  • the AES-256-GCM symmetric encryption primitive used by BRC-2
  • a portable, versioned binary envelope in the spirit of BRC-78
  • Argon2id as the mandatory password key-derivation function for new exports

Motivation

BRC-38 defines what wallet data must be portable. It does not define how that data should be safely delivered to a user as a single downloadable file.

For real-world portability, the default export artifact must be:

  • encrypted
  • password protected
  • self-describing
  • suitable for offline storage
  • stable enough to move between implementations

This document defines that artifact.

Specification

1. Scope

This specification defines:

  • the canonical encrypted file format for a single-user BRC-38 export
  • password normalization rules
  • key derivation rules
  • authenticated encryption rules
  • file parsing, validation, export, and import behavior

It does not define:

  • secret-sharing or recovery-key workflows
  • multi-file backup sets
  • multi-user containers
  • wallet-runtime key snapshots unrelated to BRC-38

2. Conformance

An implementation conforms to BRC-39 if it can:

  1. serialize a valid BRC-38 payload
  2. encrypt that payload into a valid BRC-39 file
  3. decrypt and validate a valid BRC-39 file
  4. recover the original BRC-38 payload without loss

3. Canonical Export Artifact

The canonical encrypted export artifact:

  • MUST be a binary file
  • SHOULD be named wallet.brc39
  • SHOULD use media type application/vnd.brc39.wallet

The inner plaintext payload MUST be a complete BRC-38 document serialized as canonical UTF-8 JSON.

4. Cryptographic Profile

4.1 Plaintext

The plaintext to be encrypted is:

  • the exact UTF-8 byte sequence of a valid canonical BRC-38 JSON document

4.2 Password Encoding

Before key derivation, the user password MUST be:

  1. interpreted as a Unicode string
  2. normalized to NFC
  3. encoded as UTF-8 bytes

No additional trimming, case folding, or whitespace normalization is permitted.

4.3 Key Derivation

New BRC-39 exports MUST use Argon2id.

The canonical derived-key length is:

  • 32 bytes

The canonical default Argon2id parameters are:

  • iterations: 7
  • memoryKiB: 131072
  • parallelism: 1
  • hashLength: 32
  • saltLength: 32

These defaults align with the Argon2id defaults this specification is intended to standardize.

Implementations MAY use stronger Argon2id parameters, but they MUST encode the exact parameters used in the file header.

4.4 Authenticated Encryption

The content-encryption algorithm is AES-256-GCM.

The content-encryption key is the 32-byte Argon2id-derived key.

The file nonce length is:

  • 32 bytes

The nonce MUST be generated randomly for each export.

The GCM authentication tag length MUST be 16 bytes.

4.5 Header Validation

Header fields are validated before decryption as specified below. BRC-39 encrypts only the BRC-38 plaintext payload.

5. File Layout

All integers in the binary file MUST be unsigned and encoded in big-endian byte order.

The canonical BRC-39 file layout is:

FieldLengthDescription
Magic4 bytesASCII WDAT
Format Version1 byteCurrently 0x01
Protector Type1 byteCurrently 0x01 for password-protected export
Inner Format1 byteCurrently 0x26 (decimal 38) for BRC-38
KDF Type1 byteCurrently 0x01 = Argon2id
Flags1 byteCurrently 0x00; all bits reserved and MUST be zero
Salt Length1 byteCurrently 0x20 (32)
Nonce Length1 byteCurrently 0x20 (32)
Argon2id Iterations4 bytesWork factor
Argon2id Memory KiB4 bytesMemory cost
Argon2id Parallelism1 byteParallelism
Argon2id Hash Length1 byteDerived key length; currently 32
Reserved12 bytesMUST be all zero
SaltvariableSalt Length bytes
NoncevariableNonce Length bytes
CiphertextAndTagvariableAES-256-GCM ciphertext followed by 16-byte tag

6. Header Field Requirements

6.1 Magic

The file MUST begin with the ASCII bytes:

57 44 41 54

which spell WDAT.

6.2 Format Version

The current format version is 1.

Files with unsupported versions MUST be rejected.

6.3 Protector Type

The following protector types are defined:

  • 0x01: password-based encryption

The following values are reserved for future extension:

  • 0x02 to 0xff

This version of BRC-39 standardizes only password-based encryption.

6.4 Inner Format

The Inner Format field identifies the plaintext payload.

For BRC-39 wallet exports:

  • Inner Format MUST be 38

Meaning the decrypted plaintext MUST be a valid BRC-38 document.

6.5 KDF Type

The following KDF type is defined:

  • 0x01: Argon2id

All other KDF type values are reserved for future specifications. This version of BRC-39 defines no alternate KDF import mode.

6.6 Flags

All flag bits are reserved for future specifications.

For this specification:

  • Flags MUST be 0x00

6.7 Reserved Bytes

All reserved bytes MUST be zero on export and MUST be ignored only if zero on import. Non-zero reserved bytes MUST cause rejection.

7. Export Procedure

To create a BRC-39 file, an exporter MUST:

  1. construct a valid BRC-38 document
  2. serialize it as canonical UTF-8 JSON
  3. normalize the user password to NFC and encode it as UTF-8
  4. generate a random 32-byte salt
  5. derive a 32-byte key using Argon2id and the encoded password
  6. generate a random 32-byte nonce
  7. construct the BRC-39 header
  8. encrypt the BRC-38 plaintext using AES-256-GCM with:
    • key = derived key
    • nonce = header nonce
  9. append CiphertextAndTag
  10. emit the resulting bytes as wallet.brc39

8. Import Procedure

To import a BRC-39 file, an importer MUST:

  1. parse and validate the binary header
  2. verify Magic, Format Version, Protector Type, Inner Format, KDF Type, Flags, and reserved bytes
  3. obtain the user password
  4. normalize the password to NFC and encode it as UTF-8
  5. derive the decryption key using the encoded KDF parameters from the file
  6. decrypt CiphertextAndTag with AES-256-GCM using:
    • key = derived key
    • nonce = header nonce
  7. reject the file if GCM authentication fails
  8. parse the plaintext as UTF-8 JSON
  9. validate that the plaintext is a valid BRC-38 document

Only after successful BRC-38 validation may the importer proceed to import wallet data into local storage.

9. KDF Compatibility

BRC-39 standardizes only Argon2id for password-based wallet export encryption.

Implementations MUST reject files whose KDF Type is not 0x01. Compatibility with pre-standard password-derived wallet internals is outside the BRC-39 file format.

10. Relationship to BRC-2 and BRC-78

10.1 BRC-2

BRC-39 uses the same symmetric encryption primitive family as BRC-2:

  • AES-256-GCM

Unlike BRC-2 application messages, BRC-39 stores the nonce explicitly in the binary file header instead of prepending it to a message payload.

10.2 BRC-78

BRC-39 follows the same general design philosophy as BRC-78:

  • binary, versioned, self-describing encrypted envelopes

BRC-78 is oriented toward portable encrypted inter-party messages using BRC-2/BRC-42/BRC-43 derivation. BRC-39 instead targets password-protected at-rest wallet export. This version does not standardize recipient-encrypted wallet exports, but future protector types MAY define such a mode.

11. Validation Rules

A BRC-39 file MUST be rejected if:

  • Magic is not WDAT
  • Format Version is unsupported
  • Protector Type is unsupported
  • Inner Format is not 38
  • KDF Type is not 0x01
  • Flags is not 0x00
  • Salt Length is zero
  • Nonce Length is zero
  • reserved bytes are non-zero
  • any Argon2id parameter is invalid, including:
    • iterations is zero
    • memoryKiB is zero
    • parallelism is zero
    • hashLength is not 32
  • AES-GCM authentication fails
  • the decrypted payload is not valid UTF-8 JSON
  • the decrypted payload is not a valid BRC-38 document

12. Privacy and Operational Requirements

BRC-39 files contain the complete user wallet export, protected only by the chosen password and KDF parameters.

Wallet implementations:

  • MUST warn users that weak passwords materially weaken the file
  • SHOULD encourage long passwords or passphrases
  • SHOULD avoid embedding password hints in the file
  • SHOULD default to Argon2id parameters at least as strong as the canonical defaults

13. Canonical Example Header Semantics

An example canonical new-export header therefore means:

  • file type: wallet.brc39
  • payload type: BRC-38
  • protection mode: password
  • KDF: Argon2id
  • salt: 32 random bytes
  • nonce: 32 random bytes
  • plaintext: canonical UTF-8 BRC-38 JSON

Implementation

An implementation based on Wallet Toolbox can produce a BRC-39 file by:

  1. exporting a full BRC-38 payload for the selected user
  2. deriving a password key with Argon2id using the standardized Toolbox-compatible default parameters
  3. encrypting the payload with AES-256-GCM
  4. writing the standardized binary envelope described above

References

Was this helpful?

Search Beersy

Search standards by number, title, author or topic