Reproducing the SEV-SNP MEASUREMENT
Independently verify that weikeng2.bitcoinpir.org's
attestation report — signed by the AMD chip — actually corresponds
to the source code published in this repo. No need to trust the
operator's claimed MEASUREMENT.
The non-collusion argument
The two-server PIR security model needs two
non-colluding servers to keep query content
private. weikeng1.bitcoinpir.org and
weikeng2.bitcoinpir.org run on different
physical machines — Hetzner i7-8700 and VPSBG AMD EPYC
respectively — but they share one operator.
So the deployment doesn't literally satisfy
non-collusion at the trust-boundary level.
SEV-SNP attestation closes that gap. The two hosts deliberately play asymmetric roles:
-
pir1 (Hetzner, no SEV) serves the
HarmonyPIR hint phase (offline
preprocessing) plus DPF server-0 and OnionPIR
queries. Its binary hash is pinned at build time
(see
PIR1_PIN) but there's no hardware-backed proof that the running code matches. -
pir2 (VPSBG, SEV-SNP, Tier 3 UKI)
serves the HarmonyPIR query phase plus
DPF server-1. It boots in a measured-boot UKI
environment; AMD's PSP signs a
MEASUREMENTover the loaded image and the client's pre-negotiated channel pubkey (REPORT_DATA binding viapir_core::attest::build_report_data).
Wire-level enforcement: each server explicitly opts in
to its role via --serve-hints /
--serve-queries CLI flags
(runtime/src/bin/unified_server.rs).
A client mistakenly asking pir2 for
hints gets a clean wire-level rejection
("server not configured to serve hints")
rather than a silent fall-through to whichever box
the cloudflared tunnel happens to point at.
Combined: a malicious operator can't silently route
pir2 traffic through pir1
(or any other unattested box) without either
flipping the pinned MEASUREMENT the
client checks against the chip's signed report, or
flipping the SEV STATUS from
reportDataMatch to something else. Both
are observable in the browser's attestation badge,
and both are version-controlled in
web/src/attest-pin.ts. The rest of this
page documents how to reproduce the pinned value
yourself from the published source.
Why this matters
When a client connects to pir2, the server returns
an SEV-SNP attestation report. AMD's PSP signs a
MEASUREMENT field that's a hash over the host's
launch context (firmware + kernel + initramfs + cmdline). The
client matches that signed value against a hardcoded pin
(web/src/attest-pin.ts::PIR2_TIER3_PIN)
— if they don't match, the encrypted channel won't come up.
That alone establishes "the chip is running what the operator pinned." But how do you know the pinned value corresponds to the source you can read on GitHub? You compute it yourself from the published artifacts, and check against what the chip signs.
The trust chain
Each step has a published, verifiable input. If your computed value matches the chip-signed value, the entire chain is trustworthy down to the AMD ARK.
Currently pinned values v11 — 2026-05-05
| MEASUREMENT | 0662adca3ef25ead88ae763684b6a7261e6d71e75e0a197f26c2439a3b6511c86019968bbd4a44c049ea8e6eb636c346 |
| UKI sha256 | bd243f817d463114dea187630fa8b0911ccd99cb7b37d39177b9f22e27cc7330 |
| binary sha256 | f9daecb103104c58c40440738557785febdfe2c9724de5b3506bca22a5265c9c |
| OVMF sha256 | e4ac90be71f3b455922ebc7106c5630536bf67027de585e34319b0a42fcd716e |
| AMD ARK fingerprint | 1f084161a44bb6d93778a904877d4819cafa5d05ef4193b2ded9dd9c73dd3f6a |
Verify via published artifacts
The fast path: download the UKI bytes the operator published,
download the OVMF VPSBG provided, run
sev-snp-measure, compare the result to the chip's
signed value via bpir-admin attest.
-
Get the OVMF
VPSBG's custom EDK2 build, used when "Measured Boot" is enabled in the portal. Same binary across all VPSBG SEV-SNP customers; sha-pinned.
OVMF_SEV_MEASUREDBOOT_4M.fd -
Get the UKI
The operator-built unified kernel image — kernel + initramfs (with
bpir-tier3-v11.efiunified_serverbaked in) + cmdline, packaged as a single PE/EFI file. -
Predict the MEASUREMENT
Install
sev-snp-measure(pipx install sev-snp-measure), then:sev-snp-measure \ --mode snp \ --vcpus 2 \ --vcpu-sig 0x00B10F10 \ --ovmf OVMF_SEV_MEASUREDBOOT_4M.fd \ --kernel bpir-tier3-v11.efi \ --guest-features 0x1Output should be the same hex as the
MEASUREMENTin the pinned-values table above. The launch parameters (vcpus=2,vcpu-sig=0x00B10F10for AMD Turin,guest-features=0x1) come from VPSBG's confirmed Proxmox QEMU command line. -
Verify against the live chip
Build
bpir-admin(in this repo) and askpir2for a fresh attestation report. The chip's signedLaunch MEASUREMENTfield should equal what you computed in step 3:cargo build --release --bin bpir-admin -p bpir-admin ./target/release/bpir-admin attest wss://weikeng2.bitcoinpir.org \ --expect-measurement 0662adca3ef25ead88ae763684b6a7261e6d71e75e0a197f26c2439a3b6511c86019968bbd4a44c049ea8e6eb636c346 \ --expect-binary f9daecb103104c58c40440738557785febdfe2c9724de5b3506bca22a5265c9cThree checkmarks:
SEV-SNP REPORT_DATA binding verified,binary_sha256 matches expected,Launch MEASUREMENT matches expected.
pir1 verification (Hetzner, no SEV)
weikeng1.bitcoinpir.org runs the same
unified_server binary as pir2, on a Hetzner i7-8700
(Intel, no SEV-SNP). Without a hardware root of trust, the
client verifies the server's self-reported binary_sha256
against a pinned value. This detects accidental drift between
what the operator claims is deployed and what's actually running.
The binary pin is in
web/src/attest-pin.ts::PIR1_PIN:
| binary sha256 | f9daecb103104c58c40440738557785febdfe2c9724de5b3506bca22a5265c9c |
Verify with:
cargo build --release --bin bpir-admin -p bpir-admin
./target/release/bpir-admin attest wss://weikeng1.bitcoinpir.org \
--expect-binary f9daecb103104c58c40440738557785febdfe2c9724de5b3506bca22a5265c9c
Or directly: sha256sum /home/pir/BitcoinPIR/target/release/unified_server
on the Hetzner host should return the same hash.
What this proves
- The same
unified_serverbinary serves both pir1 and pir2 — built once from the same source commit on the Hetzner build host, with identical hash on both machines. - For pir2: the bytes loaded into the confidential VM are exactly
the bytes you can rebuild from the source git commit. The AMD
chip signs over those bytes, with a key chained to
AMD's ARK — pinned at
1f084161…3dd3f6aand independently verifiable at AMD KDS. - For pir1: the binary hash is cross-checked against the same pinned value, ensuring the same code runs on both servers.
- The web client refuses to upgrade to the encrypted channel if the pinned values don't match what the server reports — so a tampered server is silent, not silently-trusted.
Out of scope
- The custom OVMF binary itself is binary-pinned, not built from EDK2 source by us. PHASE3_SLICE3_REPRO_PLAN.md documents this gap.
- Cross-path determinism (operators building from different
repo-clone paths get different binaries) is closed only
with the
/home/pir/BitcoinPIRpath convention; full closure is sub-task 5 (hermetic env). - AMD's signing keys themselves are trust roots (we can't verify "AMD didn't sign this maliciously"). Mitigated by pinning the ARK fingerprint locally.