Skip to main content
Cascade, the permanent storage service of Lumera Protocol, stores files publicly by default. Any wallet can download a file if it knows the action ID. For private data, encrypt files client-side before you upload them. This guide implements wallet-based encryption with libsodium, so users only need their wallet and never a separate password. You need a browser app with a connected Cascade client and a signer that supports signArbitrary (ADR-036). Follow Build a browser app first if you are starting fresh. The Research Archive uses this exact pattern for encrypted drafts with secure collaboration.

How it works

The scheme uses two keys. The wallet key is re-derived from a wallet signature whenever needed. A random document key encrypts the file itself. A wallet signature over a fixed ADR-036 message is hashed with BLAKE2b into a wallet key that is never stored. The wallet key encrypts a random per-file document key, the document key encrypts the file bytes, and the result is packaged into a manifest JSON and uploaded to Cascade, where it is public but unreadable without the keys.

Implement the pattern

1

Install libsodium

If you use Vite, exclude libsodium from dependency optimization.
vite.config.ts
2

Derive a key from the wallet

Instead of asking users to manage separate encryption passwords, derive a deterministic key from a wallet signature.
src/crypto.ts
Why ADR-036? Signing a fixed message means the same wallet always produces the same signature, which derives the same encryption key. The key is never stored. It is re-derived on demand, so users only need their wallet to decrypt.
3

Add encrypt and decrypt helpers

The helpers wrap libsodium’s crypto_secretbox authenticated encryption.
src/crypto.ts
4

Upload encrypted files

Each file gets its own random document key. The document key encrypts the file. The wallet key encrypts the document key so the owner can recover it later. Everything travels inside one JSON manifest.
src/encrypted-cascade.ts
Files are uploaded as isPublic: true even when encrypted. The isPublic flag controls access at the SuperNode API level, but client-side encryption is the real confidentiality mechanism. This keeps the encrypted blob available to any collaborator you share the key with.
5

Download and decrypt

Download the manifest, recover the document key with the wallet key, then decrypt the file.
src/encrypted-cascade.ts
6

Share with collaborators

To share an encrypted file, re-encrypt the document key under the collaborator’s wallet-derived key.
The collaborator downloads the invitation, decrypts the document key with their wallet, and uses it to decrypt the file.For a complete implementation of this pattern, see the Research Archive example.

Next steps

Research Archive example

See this encryption pattern inside a full application.

Upload lifecycle

Follow an upload from registration to completion.

JavaScript SDK reference

Look up the uploadFile and download options.