Your Compute-Usage Receipt Can Be Cryptographically Signed and Still Be Forged. Here's the One Field That Actually Prevents It, From the Command Line.
Co-authored by Rudrendu Paul and Sourav Nandy.
Repo: github.com/RudrenduPaul/ComputeLedger, Apache-2.0. npm install -g computeledger-cli (Node.js 18+) or pip install computeledger-cli (Python 3.10+), two independently maintained implementations of the same receipt format, both live at 0.1.2 (npm) and 0.1.4 (PyPI) on their respective registries as of this writing; the two implementations now version independently rather than staying in lockstep.
Quick summary: A cryptographic signature on a usage receipt doesn't automatically make that receipt unforgeable. If the signer's public key is passed alongside the signed data instead of inside it, an attacker can swap in a different key, re-sign, and the check still passes. We built ComputeLedger, a provider-agnostic CLI for signing and independently verifying compute-usage receipts, and an internal security audit made us confirm, with a dedicated test, that the one field preventing exactly that gap was actually where it needed to be before we shipped it.
Multi-cloud and multi-provider GPU usage has no standard, portable, independently verifiable record. A provider's billing dashboard tells you what that provider says you used. It doesn't let a third party confirm the number wasn't altered after the fact, and it only covers that one provider's stack. Two actively maintained open-source projects already prove real demand for pieces of this problem: a multi-cloud job orchestrator has 10,463 GitHub stars and shipped a commit the same week this article was written, and a Kubernetes/cloud cost-monitoring project under the CNCF has 6,670 stars and is also under active development (both checked live via the GitHub API, 2026-08-08). Neither one signs a usage claim in a way a stranger, with no account and no trust in either party, can independently check.
Real output: key generation, a recorded receipt, and a ledger-integrity check, run end to end against the actual computeledger binary.
What "cryptographically signed" quietly leaves out
Say a compute job's usage record, GPU-hours, hardware, duration, gets signed with Ed25519, the same signature scheme used in SSH, TLS 1.3, and the Signal protocol (Bernstein et al., High-speed high-security signatures) [1]. A verifier checks the signature against a public key and it passes. Case closed, receipt is real. Except: passes against which public key, and where did that key come from?
If the public key travels next to the signed payload rather than as a hashed part of it, nothing stops someone from taking a receipt, generating their own fresh Ed25519 keypair, re-signing the same claim under their own key, and handing you a receipt that verifies perfectly. The signature math is completely correct. What broke is the binding between the claim and a specific, trusted identity, exactly the failure OWASP's own Top 10 groups under cryptographic failures rather than injection or access control, because the crypto isn't broken; it's applied to the wrong scope (OWASP Top 10:2021, A02:2021-Cryptographic Failures) [2]. A signature proves "this exact byte string was signed by whoever holds this exact private key." It proves nothing about whether that key is the one you meant to trust, unless the thing being signed pins that down itself.
ComputeLedger's fix is one design decision, not a library or a protocol: the public key is a field inside the payload that gets hashed and signed, not metadata bolted on afterward. The source code says this directly, in a comment above the function that builds what gets hashed:
/**
* The hash covers every field an attacker could tamper with, including publicKey
*/
export function hashPayload(payload: ReceiptPayload): string {
return sha256Hex(canonicalizeToBytes(payload));
}
Swap the public key and the hash changes. A different hash means the original signature no longer matches anything, so ledger verify rejects it before signature verification even runs. This isn't a novel cryptographic technique. It's the same "sign what you mean to bind" discipline that shows up wherever a protocol has been burned by leaving an identity field outside the signed scope. What's easy to get wrong is skipping it, because a naive implementation that checks "does this signature verify against this embedded public key" looks completely correct in a code review and in every happy-path test. It only fails the one test that specifically tries to swap the key and re-sign, which is exactly the test our own security audit required before we called this feature done.
The two bugs an internal audit caught before a single user could
The forgery gap above was caught at design time, before code existed to catch. Two smaller, real bugs got caught after code existed, during a security-focused audit of the finished implementation, and both are worth naming because neither is a cryptography mistake. They're the ordinary kind of gap that ships in working software constantly.
First: the ledger reads its history back from a local .jsonl file, one JSON object per line. The original version parsed each line with JSON.parse and no error handling around it. A correctly-formatted-but-tampered line was already caught (a modified entry with a still-valid JSON shape fails the hash-chain check, by design). A line that isn't valid JSON at all, from a half-written disk flush, a manual edit gone wrong, anything, would throw an uncaught exception and crash the whole ledger list or ledger verify command instead of reporting a clean error about which line was bad.
Second: the record command validated --duration-seconds as a finite, non-negative number before doing anything else with it. It didn't apply the same check to --gpu-hours or --flops. Passing a non-numeric value to either one didn't fail cleanly, it threw a raw JavaScript stack trace from deep inside the canonicalization step that hashes the payload, three layers away from where the actual mistake was made.
Neither bug is exotic. Both are the unglamorous kind that a manual code review can miss because the happy path works, and both were live in the codebase at the time of the audit. We checked the current source directly while writing this piece: both are fixed now, readAll() wraps the per-line parse in a try/catch and skips or reports the bad line instead of crashing, and --gpu-hours/--flops get the identical Number.isFinite check --duration-seconds always had, with a clean CLI error message instead of a stack trace. Neither fix is interesting on its own. What's worth taking away is the audit step that found them: reading the actual implementation against a specific checklist of failure classes instead of only running the existing test suite and calling it verified, because the existing tests were all written against inputs that already worked.
What this doesn't prove, and why that distinction matters
A signed, hash-chained receipt proves two specific things: that the receipt hasn't been altered since it was signed, and that whoever holds the private key behind the embedded public key produced it. It proves nothing about whether the numbers inside that receipt were true at the moment of signing. If you run computeledger run --provider on-prem --hardware nvidia-a100 -- python train.py on a machine you fully control, you control every input the tool captures before it signs anything. Tamper-evidence protects the record after signing. It is not a truth oracle for what happened before signing, and a tool that implied otherwise would be overselling what cryptography can actually do here. That's a real limitation, not a caveat to bury in fine print, and it's the same limitation every self-attested signed-record system has, from a Git commit signature to a notarized affidavit: the notarization proves who signed and that it wasn't altered afterward, not that the signer told the truth.
The private signing key itself carries a second, related tradeoff. It's stored as an unencrypted PEM file, protected only by filesystem permissions (mode 600, owner read/write only), no passphrase. That's the same tradeoff an unprotected local SSH key makes: fine for a local tool where the threat model is "don't leak the file," not fine if the threat model includes "an attacker with read access to this machine." A hosted or fleet-wide version of this idea would need a real key-management story; a single-machine CLI signing your own local job history reasonably doesn't, but that's a judgment call worth stating plainly rather than leaving implicit.
What this means if you're accountable for compute spend across providers
If your job is tracking GPU spend, capacity, or usage claims across more than one provider, "cryptographically signed" in a vendor's marketing copy is not, by itself, a claim worth taking at face value. The question worth asking is narrower and checkable: is the identity that a signature is supposed to bind to actually part of what got signed, or is it sitting next to the signature as unauthenticated metadata? The difference between those two designs is invisible in a demo and in a green test suite. It only shows up when someone deliberately tries to swap the key, which is exactly the kind of test a working system has no built-in reason to run against itself.
The Evolving Landscape of Verifiable Compute Usage
A handful of distinct approaches already touch some part of "prove what compute was actually used," and they solve genuinely different problems, not competing versions of the same one.
Multi-cloud job orchestration and cost-visibility platforms focus on running workloads across providers and showing you what they cost, often with real scale and real adoption behind them. Their value is operational: fewer manual steps to launch a job anywhere, one dashboard instead of five billing consoles. None of them, by design, produces a receipt a third party with no account and no API access can independently verify offline; the record lives inside the platform's own system of record, which is a different trust model than a portable, self-contained proof.
A newer category of cryptoeconomic compute networks verifies contributed compute as part of a decentralized training or inference marketplace, often anchored to a blockchain or token mechanism for settlement and reputation. This solves a real problem, verifying work done by untrusted third parties who get paid for it, but it's a heavier commitment than most teams tracking their own already-trusted infrastructure need: adopting a specific chain, a specific settlement mechanism, and a specific network's governance just to get a receipt for a job that ran on hardware you already own or already pay a known cloud provider for directly.
A third category, enterprise attestation platforms increasingly backed by hardware vendors, ties verification to trusted execution environments and hardware-rooted attestation, a genuinely stronger guarantee in the specific sense that it can attest to what actually ran inside a protected enclave, rather than only what a process later claims happened. The tradeoff is dependency: it generally requires specific hardware support and, often, an enterprise relationship with the platform providing the attestation service, which is a real barrier for a team that wants a receipt format they can adopt today on whatever hardware they already have.
A fourth category is the direct precedent this project has to be honest about: a prior open-source attempt at training-compute provenance attestation, binding model weights to a hardware-rooted proof, shipped, got real attention, and then stopped. Its GitHub repository sits at 20 stars with no commits since June 2024 (verified live via the GitHub API, 2026-08-08) and, worth stating precisely rather than loosely, is not formally archived by GitHub itself, it's dormant, not read-only. That's a real data point about how hard this specific narrow niche is to sustain as a standalone open-source project, not a detail to gloss over.
None of these four fully occupies the specific, narrow space of a lightweight, provider-agnostic, offline-verifiable receipt format that doesn't require adopting a chain, a hardware dependency, or a hosted platform, just a CLI command or an MCP tool call and a signature anyone can check with no account. A persistent gap remains between "trust the platform's dashboard" and "commit to a full attestation ecosystem." An emerging, narrower category of small, self-contained receipt formats is starting to fill that specific gap: a signed, hash-chained, cross-language-verifiable claim that travels with the job itself rather than living inside any one provider's or network's system of record.
Honest limitations
ComputeLedger doesn't attest to ground truth, only to what was signed and whether it was altered afterward, a distinction the section above covers in full because it's the single most important thing to understand correctly before using this for anything that matters. It doesn't do multi-cloud orchestration or cost dashboards; SkyPilot and OpenCost solve those problems, actively and at real scale, and ComputeLedger is explicitly not attempting to replace either. Windows CI coverage doesn't exist yet, only Linux is continuously tested upstream, even though both packages install cross-platform. And the honest one with no benchmark number attached to fix it: whether teams actually want a separate, portable receipt format instead of trusting whatever their existing cloud or orchestration platform already reports is a real, unsettled question. An earlier internal validation pass on this exact niche found it already crowded by funded players working adjacent angles, and we built this anyway as a narrower, cheaper bet specifically on the provider-agnostic, no-lock-in framing those players don't occupy. Whether that bet is right isn't proven by shipping the tool.
Try it yourself
computeledger keys generate --local
computeledger record --local --provider aws --hardware nvidia-h100 \
--duration-seconds 3600 --gpu-hours 1 --workload-type training
computeledger ledger verify --local
Or skip the manual record call and wrap a real job directly:
computeledger run --local --provider on-prem --hardware nvidia-a100 -- python train.py
Anyone with the resulting receipt.json can run computeledger verify receipt.json on a completely different machine, with a completely different install (npm or PyPI, either direction) and get the same answer.
We have one open, genuinely undecided question: whether the next release should add a signed, optional witness field (a third party attesting they observed the job run, in addition to the issuer's own signature) or should instead focus on hardening the single-machine key-storage story before adding any new receipt fields at all. Both are real, scoped pieces of work. Which one would actually make you consider wiring this into a compute-tracking pipeline you already run?
If you're building anything that signs a claim and hands it to someone who has to trust it later, a compute receipt, an audit log, an API response, check whether the field that names who's trusted is actually part of what gets hashed, or just sitting next to it. If you maintain a FinOps, MLOps, or compute-governance pipeline and want a portable, independently verifiable usage format as a dependency instead of building one from scratch, a star on the repo helps other people building the same kind of tool find it.
GitHub: github.com/RudrenduPaul/ComputeLedger
MCP Servers:
mcpservers.org/servers/rudrendupaul/computeledger
glama.ai/mcp/servers/RudrenduPaul/ComputeLedger
npm: npmjs.com/package/computeledger-cli
PyPI: pypi.org/project/computeledger-cli
References
- Bernstein, D.J., Duif, N., Lange, T., Schwabe, P., Yang, B.Y., High-speed high-security signatures, Journal of Cryptographic Engineering, 2, 77-89, 2012 (the Ed25519 signature scheme ComputeLedger uses)
- OWASP Top 10:2021 - A02:2021-Cryptographic Failures, OWASP Foundation, 2021
- RFC 8032: Edwards-Curve Digital Signature Algorithm (EdDSA), IETF, 2017
Co-authored by Rudrendu Paul and Sourav Nandy.
Rudrendu Paul and Sourav Nandy build open-source developer tools for the AI agent ecosystem. They are the co-authors of ComputeLedger, a dual-distribution (npm + PyPI) CLI, library, and MCP server for signing and independently verifying compute-usage receipts across any cloud or on-prem provider, and other AI agent infrastructure tools. Find the code at github.com/RudrenduPaul.