Skip to content

feat(tlsn): a proxy-mode prover, for callers that cannot dial the platform - #18

Closed
SupremaLex wants to merge 1 commit into
mainfrom
feat/proxy-mode-prover
Closed

SupremaLex wants to merge 1 commit into
mainfrom
feat/proxy-mode-prover

Conversation

@SupremaLex

Copy link
Copy Markdown
Member

Why

prover_generic runs one commitment protocol: MPC-TLS, where the prover opens the connection to the server and the notary takes part in encrypting it. tlsn has a second, Proxy-TLS, where the notary opens that connection and the prover reaches it through the session mux. Nothing in libid-tlsn exposed it.

The OAuth Bridge needs it. Its contract (oauth-bridge.md, §GitHub token endpoint) has the notary address arrive in the request and the Bridge derive wss://{notaryAddress}/notarize-proxy from it — and /notarize-proxy is the notary's Proxy-TLS endpoint. Without a proxy prover the Bridge can only dial a configured address over the wire port, which is the "notary mapping or override" its contract says it must not maintain. See libid-org/libID-server-rs#8, the notaryAddress thread.

What

prover_proxy, with the same arguments and the same ProverResult as prover_generic. A caller states its transport by choosing a function rather than passing a value.

The two transports differ in exactly one place, and the change is shaped to keep it that way:

  • Prover::commit is already generic over the protocol config (MpcTlsConfig / ProxyTlsConfig);
  • a connected prover's future resolves to Prover<state::Committed> whichever way the connection was made.

So the branch covers the commit config and the connect call — MPC passes a socket it opened, Proxy passes none — and everything downstream is written once: the HTTP exchange, the disclosure the prover chooses through select_layout, the commitments as the complement of the reveals, the attested record. Those are the parts a verifier reads, and two copies of them would be two copies that can disagree about what a session proves.

prover_generic keeps its signature and its behaviour. Both callers (the Bridge, the JWKS keeper) are unaffected.

Verification

  • cargo test --all — green (all existing suites)
  • cargo clippy --all-targets --all-features -- -D warnings — clean
  • cargo +nightly fmt --all -- --check — clean

Not exercised end to end here, on purpose. The proxy verifier lives in the notary service, and this repository's tests deliberately open no TLS (ceremony_end_to_end.rs: "It is not a network test"). The place for that test is notary's proxy_protocol_returns_attestation_on_the_reclaimed_websocket, which already drives this protocol from the client side with tlsn-server-fixture as the target.

🤖 Generated with Claude Code

https://claude.ai/code/session_01F9MSaibJ5zbBEBigjNjvca

…tform

`prover_generic` runs one commitment protocol: MPC-TLS, where this side opens
the connection to the server and the notary takes part in encrypting it. tlsn
has a second, Proxy-TLS, where the notary opens that connection and the prover
reaches it through the session mux -- and nothing here exposed it, so a caller
that cannot egress to the platform, or must not, had no way to notarize at all.

The OAuth Bridge is that caller. Its contract has the notary address arrive in
the request and the Bridge derive `wss://{notaryAddress}/notarize-proxy` from
it, which is this protocol; the notary already serves it. Without this the
Bridge can only dial a configured address over the wire port, which is the
thing its contract says it must not maintain.

The two transports differ in exactly one place, and this change is shaped to
keep it that way. `commit` is already generic over the protocol config, and a
connected prover's future resolves to `Prover<state::Committed>` whichever way
the connection was made -- so the branch covers the commit config and the
`connect` call, and everything downstream is written once: the HTTP exchange,
the disclosure the prover chooses through `select_layout`, the commitments as
the complement of the reveals, and the attested record. Those are the parts a
verifier reads, and two copies of them would be two copies that can disagree
about what a session proves.

`prover_generic` keeps its signature and its behaviour; `prover_proxy` takes
the same arguments and returns the same `ProverResult`. A caller states its
transport by choosing a function rather than by passing a value, so there is no
parameter to thread through three layers and arrive wrong.

Not exercised end to end here: the proxy verifier lives in the notary service,
and this repository's tests deliberately open no TLS. `notary`'s
`proxy_protocol_returns_attestation_on_the_reclaimed_websocket` is where that
belongs, and it already drives this protocol from the client side.

Assisted-by: Claude Opus 5
Signed-off-by: SupremaLex <georglutsenko@gmail.com>
@SupremaLex
SupremaLex requested a review from xgreenx September 10, 2026 15:29
@SupremaLex SupremaLex closed this Sep 10, 2026
@SupremaLex
SupremaLex deleted the feat/proxy-mode-prover branch September 10, 2026 16:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant