The bdk library aims to be the core building block for Bitcoin wallets of any kind.
The bdk-reserves library provides an implementation of proof-of-reserves for bdk.
The bdk-reserves-web is a web app to validate the proofs.
- It validates proofs in the form of PSBT's.
- The implementation was inspired by BIP-0127 and BIP-0322.
Verification runs entirely in the browser, compiled to WebAssembly. There is no
backend: dist/ is a folder of static files that any web server, CDN or
GitHub Pages site can host. The PSBT you paste in is never uploaded anywhere.
The only network traffic is UTXO lookups against an Esplora server, which default to Blockstream's public instances. You can point the app at your own Esplora instead, and should if you do not want to tell a third party which addresses you are checking.
The proof itself is checked by bdk-reserves, unchanged from the server version.
Script signatures are validated by bitcoinconsensus, which is Bitcoin Core's
own script interpreter, so a signature accepted here is one the network would
accept. Amounts are taken from the transactions that created each UTXO, and each
transaction is checked against the txid that was requested, so an Esplora server
cannot inflate the reported total by misreporting a value.
What you still trust the Esplora server for is which outputs are unspent. A server that hides a UTXO makes a valid proof fail, which is the safe direction.
Needs a Rust toolchain, curl and node (for the end to end test). Everything
else is fetched into .tools/ on first build. The fetched toolchain is the
Linux x86_64 build, so that is currently the only host build.sh supports.
make build # produces dist/
make serve # builds, then serves dist/ on http://localhost:8087
make test # verification logic on the host, plus the built module end to endmake serve runs python3 -m http.server over dist/, which is all a dev
build needs. To publish it elsewhere, copy dist/ anywhere that serves static
files: S3, a CDN, or any web server. The .wasm file should be served as
application/wasm, which most of them do already.
bitcoinconsensus compiles Bitcoin Core's script interpreter, which is C++, so
building for wasm needs a C++ standard library for that target. build.sh
fetches the wasi-sdk and uses its
clang and libc++.
It deliberately does not link wasi-libc, because that would put a second
allocator in the module next to Rust's and add WASI imports the browser would
have to fill in. src/csupport.rs supplies the dozen or so C symbols libc++
actually needs instead, with malloc and free forwarding to Rust's allocator.
The module that comes out imports nothing but its own JS glue.
Set WASI_SDK_PATH to reuse an SDK you already have.
Every push to master publishes to
aminabank.github.io/bdk-reserves-web
via .github/workflows/pages.yml. The workflow runs the full test suite first,
so a broken verifier does not reach the published site.
This needs Settings > Pages > Build and deployment > Source set to GitHub Actions, once. Until that is done the deploy step fails.
Pages serves the app from a subdirectory rather than a domain root, which is why
everything in web/ refers to its assets relatively.
The implementation of bdk-reserves-web was sponsored by AMINA Bank.
Licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

