Verifiable LLM Inference: Using Zero-Knowledge Proofs to Prove Which Model Actually Generated an Answer

    Many teams calling LLM APIs through third-party relay services see the same model name return wildly different quality. The root cause is often not the model but the layer in between: model swapping, silent degradation, and distillation impersonation. This article explains why existing detection approaches fall short, how verifiable inference replaces trust with cryptographic proof through a commit–challenge–prove protocol, the four main engineering obstacles to proving a full transformer forward pass with zero-knowledge proofs, how the lighter-weight alternatives compare, and a practical verification loop most teams can build today. Readers will come away with a clear picture of what zero-knowledge proofs can and cannot assert about model identity, plus reference code for contract hashing and golden-sample regression checks.

    1. Introduction: Same “Flagship Model” Label, Wildly Different Answer Quality

    Many developers who call LLM APIs through third-party relay services have run into the same situation. The API documentation and the model identifier are identical, yet some responses are careful and thorough while others miss the question entirely, or fail outright on any moderately complex coding task. A related pattern shows up inside companies too: platform teams build a unified gateway that wraps several vendors’ model APIs behind a single protocol. If upstream configuration or version management slips, the result is the same — everything is labeled “flagship model,” but actual behavior varies enormously.

    The problem is usually not the model itself, but the fact that the answer you receive may not have been generated by the model you paid for. Throughout this article, the “verifying party” can be an end developer or an internal enterprise gateway or audit system, and “relay service” refers generically to any forwarding or proxy layer sitting between the user and the model provider.

    2. Three Common Substitution Techniques and Their Detection Blind Spots

    What the middle layer does usually falls into three categories.

    2.1 Model substitution

    The caller requests the largest flagship model in a family; the middle layer forwards the request to a lighter, cheaper variant in the same family and returns the result unchanged. The lighter model costs less to run and responds faster, and the price difference becomes the middle layer’s margin.

    2.2 Silent degradation

    The model name stays the same, but the middle layer quietly cuts the inference budget — shortening the context window, lowering the maximum output length, reducing sampling temperature. A subtler variant rewrites the system prompt before the request reaches the model, injecting instructions such as “output only a brief conclusion” or “do not expand your analysis.” None of this touches model weights, which makes it extremely hard to detect after the fact.

    2.3 Distillation impersonation

    The middle layer trains a small model on large volumes of “model input–output” samples so that it imitates the target model’s phrasing style and formatting habits, then serves that impostor as the original model. The industry has no settled position on model distillation itself: using your own weights and your own data to build a smaller deployment is a routine engineering optimization, while harvesting another party’s outputs at scale without authorization to train a competing model can raise terms-of-service and intellectual-property disputes. Some model vendors have already publicly disclosed and pursued distillation behavior, citing mass collection of conversation data through bulk fake accounts and abnormally high call rates. Even so, output samples alone make it very hard to infer a model’s parameter count, training data, or true identity — which is precisely why verification is difficult.

    2.4 Why existing detection approaches fall short

    The most intuitive check is to simply ask the model what it is. But a model’s sense of its own identity depends entirely on its input: if the middle layer writes “you are a certain flagship model” into the system prompt, any model will answer accordingly, and the trick collapses immediately.

    The detection tools commonly used in the community rely on one of a few ideas:

    • Comparing response style, formatting habits, and statistical features;
    • Inspecting field structure in the response;
    • Verifying the completeness or signature of extended-thinking content.

    These approaches answer one question — “was this response produced by some vendor’s API?” — but not the questions that matter here: “which version, which configuration, and through what kind of inference process?” Vendors face a symmetric problem. When a user complains that a model has been quietly degraded, even a provider that never changed its inference configuration struggles to prove its innocence without revealing its weights.

    At bottom, inside the black box of LLM input and output, the authenticity of an answer has long rested on trust — and trust is exactly the thing most easily eroded by financial incentives.

    3. Core Idea: Replace Trust with Proof

    Verifiable inference aims to rewrite that trust relationship as a cryptographically verifiable one. A complete inference lifecycle has four stages:

    1. Request: the input prompt and sampling parameters.
    2. Inference: the model provider loads weights, runs the forward computation, and samples an output.
    3. Transport: the output travels back to the user through gateways and proxies.
    4. Billing: settlement based on token usage.

    Every stage can be tampered with, but a traditional API response only proves that stage 3 happened — that “some text was successfully delivered.” It says nothing about stage 2: that “this text was actually computed by the claimed model.” The goal of verifiable inference is to make stage 2 provable instead of invisible.

    Three technical routes are being explored in the field:

    • End-to-end proofs: generating a proof over the entire forward computation;
    • Component-level proofs: committing to or proving only the key components most likely to be swapped;
    • Confidence scoring: producing a probability of “suspected substitution” from indicators such as response latency and output distribution characteristics.

    The cryptographically strongest of these is end-to-end proving, which builds on zero-knowledge proofs (ZKPs). Intuitively, a zero-knowledge proof lets a prover convince a verifier that “a certain statement is true” without revealing anything beyond the truth of that statement. The classic “Ali Baba’s cave” story illustrates it well:

    • The prover knows the secret phrase that opens the door;
    • The verifier randomly specifies whether the prover must exit from the left or the right passage;
    • Only someone who truly knows the phrase can appear as instructed every time;
    • Someone who does not know the phrase has a 1/2 chance of guessing correctly each round, so after several rounds impersonation becomes practically impossible.

    Applied to model inference, the “statement” can be phrased as: “there exists a set of weights W and a valid sampling procedure such that the model outputs Y on input X, and the commitment to W is C.” The answer Y, the commitment C, and the public parameters needed for verification are visible to everyone, while the weights W themselves never need to be disclosed. This creates an entirely new trust relationship: the user does not need to trust the middle layer, nor take the model vendor’s verbal claims on faith — only cryptographic assumptions and publicly auditable verification code.

    4. Dissecting the Commit–Challenge–Prove Protocol

    Such schemes are often summarized in three steps. In a rigorous engineering implementation they are better broken into four stages — commit, challenge, prove, and verify — with the commitment stage further split into session-level and request-level commitments. Each stage is unpacked below.

    4.1 Step one: Commit — put the cards face down on the table

    Before inference begins, the model provider must lock in everything the inference depends on and publish the cryptographic digests (commitments) of those elements. Typical commitment targets include:

    • Model identity: a version hash of the weight files, or a short verification value derived from a commitment polynomial over the weights. To preserve zero-knowledge, weights are usually not published as plaintext hashes; instead a commitment is generated with the weights as polynomial coefficients, for example a Pedersen commitment based on elliptic-curve operations. Such commitments can verify claims about weight-related computations without exposing the coefficients themselves.
    • Inference configuration: sampling parameters such as temperature, top-p, context length, and maximum output length.
    • Request content: a hash over the full prompt, system prompt included. This is what stops the middle layer from slipping “output only a brief conclusion”–style degradation instructions into the system prompt.

    This “commit first, reveal later” mechanism is known in cryptography as a commitment scheme, and it must satisfy two basic properties:

    • Binding: after committing, the provider cannot later claim it used different weights or parameters;
    • Hiding: without a reveal, no one can infer the committed content from the commitment value.

    Two implementation details deserve attention.

    First, the commitment must be generated before the request is sent. A user can first obtain the vendor’s published commitment for the current model version (for example, a version fingerprint released with an announcement), then include that commitment in the request as the agreement that “this call must use this model version.” Without this step, a provider can simply pick a set of weights on the fly, generate a matching commitment, and still pass verification after the fact.

    Second, guard against “commitment grafting” — the provider forwards some genuine version’s commitment value verbatim while actually computing with different weights. The only defense is binding the commitment to the computation result: the proof system verifies that “there exists a set of weights satisfying commitment C that produces inference result Y,” not that “a string appearing in the response equals C.” The verifying party must therefore check the proof itself, not merely read a commitment field in the response.

    4.2 Step two: Challenge — don’t let the other side cherry-pick its computation

    If the verifying party receives only a single proof, one extreme case remains: the provider computes the same request repeatedly and submits only the “best-looking” result together with its proof — selective disclosure.

    The solution borrows from verifiable random function design: the challenge value is generated on the spot by the verifying party, or produced by a public randomness source no one can manipulate, such as:

    • A publicly auditable randomness beacon;
    • A hash derived from block height;
    • A random number obtained through multi-party commit-reveal.

    For scenarios with very strict consistency requirements — for example, auditing whether repeated calls with the same request return consistent results — a verifiable delay function (VDF) can also be used. It requires a serial computation that cannot be parallelized away and simultaneously produces a proof that is cheap to check, making after-the-fact recomputation infeasible in time. Together, these mechanisms prevent the provider from pre-selecting a computation result favorable to one side.

    4.3 Step three: Prove and verify — deliver the answer together with the proof

    After completing the forward pass and sampling an answer, the provider must produce:

    • The answer Y;
    • A zero-knowledge proof π of the inference process;
    • The weight commitment C and the public verification parameters.

    The verifying party does not need to re-run inference or touch the weights. It only runs the verification algorithm Check(C, X, Y, π) and confirms the result is “accept.” At that point one can be confident of at least this much: there exists a model satisfying commitment C that, on input X, could genuinely produce answer Y through valid inference.

    The boundaries of this mechanism need to be recognized clearly. It proves that “the inference process is self-consistent and consistent with some committed set of weights”; it cannot directly assert that “this set of weights equals a given vendor’s flagship model.” Closing that last gap requires bringing the model release process into the trust system: the provider publishes weight commitments at each version update, and an independent third party or the community performs hash comparison against officially released models as routine, ongoing audits.

    5. How a Zero-Knowledge Proof Proves One Inference: From Circuitization to Quantification

    Turning LLM inference into a provable statement centers on arithmetization: rewriting operations such as matrix multiplication, activation functions, and attention softmax one by one as arithmetic circuits or constraint systems over a finite field. Every operation the inference executes requires the proof system to generate a corresponding constraint. Four major difficulties arise.

    5.1 Difficulty one: floating-point arithmetic resists circuitization

    Zero-knowledge proof systems operate natively over integer finite fields, while model inference runs in floating-point formats such as FP16 and BF16. Handling floating-point numbers directly introduces large numbers of bit-level constraints, and circuit size explodes.

    The common industry workaround is fixed-point conversion: floating-point values are multiplied by a fixed scaling factor and mapped to field elements, and every value during inference is represented as a fixed-point integer. Two consequences follow.

    First, the model is usually quantized to 8 bits or lower, so the object being proved is effectively “the quantized model.”

    Second, the provider can manipulate the quantization scheme. It might compute with an INT8 quantized version and generate a proof for that, while claiming externally that the original FP16 model was used. The quantization scheme — bit width, scaling factor, quantization algorithm — must therefore be part of the committed content and locked together with the weights; the provider should also state publicly whether the “online inference version” and the “verifiable version” are identical.

    5.2 Difficulty two: nonlinear operators are expensive

    Matrix multiplication is fundamentally just addition and multiplication and maps naturally onto circuits. But activation functions (such as GELU and SiLU), the exponentiation inside softmax, and the square-root operations in LayerNorm and RMSNorm are all nonlinear: over a finite field they either cannot be expressed directly or require many constraints to approximate.

    Two families of countermeasures are common:

    • Polynomial approximation or lookup tables: approximate a nonlinear function with a low-degree polynomial, or bucket the input and express the operation as a “table lookup.” The lookup typically requires “select one of many” constraints over the entire table, so cost grows with table size.
    • Switching to finite-field-friendly model architectures: replace operators such as softmax with approximations during training so the model is naturally suited to proof systems, though this approach currently appears mostly in research-stage models.

    5.3 Difficulty three: proving costs far more than the inference itself

    Transformer inference cost scales with parameter count and sequence length, and the attention portion grows quadratically with context length. Once all of that computation becomes constraints, proof generation is often several orders of magnitude slower than the original inference: the academic literature includes successful demonstrations of complete proofs for billion-parameter models, but they typically take minutes or even hours.

    That is nearly unacceptable for a real-time API service. Three mitigation approaches are currently mainstream:

    • Chunking and recursive proofs: split long-sequence inference into blocks, prove each block, then compress multiple proofs into one with a recursive proof. The recursion itself can further reduce per-step cost using techniques such as lookup tables.
    • Incremental verification: bring the KV cache into the commitment as well. In multi-turn conversations, each turn only needs a proof for “new tokens + cache consistency,” avoiding re-proving the entire history every turn.
    • Tiered verification: skip proofs for ordinary requests, generating full proofs only for sampled requests, high-value requests, or post-hoc audit requests.

    It is worth stressing that recursive compression changes only the shape and size of the proof; it does not make the underlying computation cheaper. End-to-end proofs of full LLM inference will remain hard to complete in real time on every single call for the foreseeable future.

    5.4 Difficulty four: who decides sampling randomness

    The concrete content of an answer is determined by sampling. If the random numbers are entirely under the provider’s control, it can sample repeatedly, pick the most flattering answer, and submit that one with its proof.

    Two safer designs exist:

    • Seed commitment: before service begins, the provider publishes a derivation rule such as “random seed = H(provider randomness, public randomness source),” making the sampling result of each call reproducible and checkable;
    • Verifier-controlled randomness: the verifying party supplies the random seed, or a verifiable randomness source of the kind described in section 4.2 is incorporated.

    One more engineering detail matters: common sampling strategies involve truncation. Top-k keeps only the K highest-probability candidates, and temperature sampling rescales the probability distribution. The committed content must therefore cover the complete set of sampling parameters — otherwise a provider may claim a “temperature 0.7” configuration while running inference with more conservative parameters and simply writing the sampling parameters back into the response.

    6. Lighter-Weight Alternative Routes and Where They Fit

    Route Core mechanism What it solves Main limitation
    End-to-end zero-knowledge proof Proof over the complete forward inference Proves the answer is consistent with committed weights and input Extremely high proving cost; quantization scheme needs extra constraints
    Partial component proof Proof over only the first/last layer or a key subgraph Sharply reduces cost; blocks coarse-grained substitution Middle layers can still be tampered with
    Trusted execution environment remote attestation Inference inside a hardware-isolated enclave, with attestation signed by the hardware vendor Inference overhead close to zero Requires trusting the hardware vendor and firmware; side-channel risk; cannot constrain a middle layer for proxied requests
    Output watermarking Biasing specific tokens during decoding according to a key Tracing the source of leaks after the fact; identifying distillation Can be weakened by rewriting, translation, or resampling; cannot prevent substitution
    Output fingerprinting and reproducible sampling Fixed version, fixed seed, fixed prompt; compare output hashes Cheap detection of version drift and configuration changes Depends on sampling coverage; samples must be protected from targeted optimization

    An easily overlooked fact: trusted execution environments and model watermarking can only constrain who runs the inference, whereas the relay problem happens in how a request is forwarded. Even if an upstream vendor deploys hardware-level isolation, the middle layer can still route the user’s request to a different, cheaper model. In other words, preventing a middle layer from swapping models requires the proof to be established between the user and the middle layer — which is exactly where zero-knowledge-proof-based schemes deliver value. These routes are not mutually exclusive; real systems often combine several of them.

    7. Engineering Practice: A Verification Loop You Can Actually Deploy

    For the vast majority of developer teams, a full zero-knowledge proof stack is not yet practical in production. A more realistic approach borrows the commit–challenge idea and starts with a low-cost, sustainable verification loop.

    7.1 Three lines of defense: lock down beforehand, monitor during, spot-check afterward

    • Lock down beforehand: freeze critical configuration such as model version, sampling parameters, and context length into a “calling contract.” Any change must go through approval and leave an audit record.
    • Monitor during: per channel and per version, track metrics such as latency, time to first token, output length, refusal rate, and format compliance, and compute semantic similarity between responses and reference answers over a fixed test set. Trigger alerts automatically when drift appears.
    • Spot-check afterward: periodically run “golden sample” regression with fixed prompts and a fixed random seed. If the provider supports reproducible sampling, results should be identical or very close under the same version and parameters; a mismatch suggests the actual inference configuration may have been changed.

    Note that spot-check samples can be targeted for optimization, so the sample set should stay reasonably private and be rotated regularly. Spot-checking is also statistical detection by nature — it is not the same as a cryptographic proof.

    7.2 Sample code: calling contract and fingerprint comparison

    The code below shows how to engineer these ideas. The contract hash acts as a lightweight “commitment,” and comparing answer fingerprints against golden samples acts as a lightweight “verification.”

    1. import hashlib
    2. import json
    3. import statistics
    4. import time
    5. def _digest(payload: dict) -> str:
    6. """Compute a SHA-256 fingerprint over a canonicalized JSON serialization."""
    7. canonical = json.dumps(payload, sort_keys=True,
    8. ensure_ascii=False, separators=(",", ":"))
    9. return hashlib.sha256(canonical.encode("utf-8")).hexdigest()
    10. # 1) Calling contract: a lightweight stand-in for a "commitment";
    11. # any change must go through approval.
    12. CONTRACT = {
    13. "channel_id": "vendor-a",
    14. "model": "<flagship model identifier>",
    15. "version": "2026-03", # Model version identifier from the vendor announcement; illustrative only
    16. "temperature": 0.7,
    17. "top_p": 0.9,
    18. "max_output_tokens": 4096,
    19. "quantization": "fp16", # The quantization scheme is also committed content that must be locked
    20. }
    21. CONTRACT_HASH = _digest(CONTRACT)
    22. # 2) Golden samples: prompt + reference answer, where the reference is
    23. # generated over the locked version through a direct vendor channel.
    24. GOLDEN_SAMPLES = [
    25. {
    26. "prompt": "In one sentence, explain \"index selectivity\" in a database and why it affects whether the optimizer chooses an index scan.",
    27. "reference": "<reference answer generated via a direct vendor channel>",
    28. },
    29. # ... more samples; rotate them periodically
    30. ]
    31. def call_model(prompt: str) -> str:
    32. """Call the model API; a real implementation needs timeouts, retries, and error handling."""
    33. # client.chat.completions.create(...): illustrative call, per the SDK in use
    34. return "<text returned by the model>"
    35. def answer_fingerprint(answer: str) -> str:
    36. """Answer fingerprint: a real system can swap in rewrite-resistant features such as semantic vectors."""
    37. return hashlib.sha256(answer.strip().encode("utf-8")).hexdigest()
    38. def run_golden_check(similarity_fn) -> dict:
    39. """Run the golden-sample spot check; returns the baseline match rate and similarity statistics."""
    40. scores, exact_matches = [], 0
    41. for i, sample in enumerate(GOLDEN_SAMPLES):
    42. answer = call_model(sample["prompt"])
    43. score = similarity_fn(answer, sample["reference"]) # value in [0, 1]
    44. scores.append(score)
    45. exact_matches += answer_fingerprint(answer) == \
    46. answer_fingerprint(sample["reference"])
    47. matched = len(scores) and exact_matches / len(scores)
    48. return {
    49. "contract_hash": CONTRACT_HASH, # Configuration fingerprint this check corresponds to
    50. "checked_at": time.strftime("%Y-%m-%dT%H:%M:%S"),
    51. "exact_match_rate": matched, # Should approach 1.0 under reproducible sampling
    52. "mean_similarity": statistics.mean(scores),
    53. "min_similarity": min(scores),
    54. }

    Once report results are written to an audit log, three things become possible:

    • Compare fingerprints by channel and by version;
    • Trigger alerts when similarity drops below a threshold;
    • Archive historical reports to object storage for long-term retention.

    Teams that run their own unified gateway can go further and record the contract hash and response fingerprint for every request at the gateway layer, forming a complete audit chain.

    7.3 Cloud deployment: build the monitoring and audit foundation on general-purpose cloud capabilities

    Whether deployed in a self-managed data center or a public cloud, a verification system of this kind depends on a few general capabilities:

    • A container platform to host the inference gateway and spot-check jobs, with versioned images guaranteeing a reproducible verification environment;
    • A log service to collect call logs, contract hashes, and spot-check reports in one place, with retrieval by version;
    • Monitoring and alerting configured with thresholds and tiered notifications for metrics such as latency, similarity, and refusal rate;
    • Object storage to archive golden samples, audit reports, and proof data, with versioning enabled to prevent tampering.

    Taking Baidu AI Cloud as an example, all of these capabilities are covered by general-purpose product categories such as container engines, log services, cloud monitoring, and object storage. That lets developers concentrate their effort on the verification rules themselves rather than reinvesting in infrastructure.

    8. Summary and Outlook

    “Whether a model’s answer is genuine” is a problem that trust has long papered over. Substitution at relay services, silent degradation, and distillation impersonation all exploit the same fact: users see only the output, never the computation.

    Verifiable inference built on zero-knowledge proofs offers a cryptographic answer to this problem. Its value is not limited to “catching bad actors” — it also lets model providers prove their own innocence, turning “was the model degraded?” from a shouting match into a verifiable fact. At the same time, it is worth being realistic: proving a complete LLM inference remains expensive, and details such as quantization schemes and sampling randomness must be pinned down strictly at the protocol level. There is still a long way to go before every single call carries a proof.

    For developers and enterprises, the pragmatic path today has three steps:

    1. First establish calling contracts and an audit log;
    2. Then use golden-sample spot checks and fingerprint comparison to catch anomalies early;
    3. Meanwhile, track progress on zero-knowledge proofs in inference hardware, lookup-table parameters, and recursive proofs, and reserve interfaces for future end-to-end verification.

    After all, “don’t trust, verify” has always held true in the world of cryptography.