Skip to content

What is the recommended approach for verifying TLSNotary proofs on-chain (EVM / Solidity)? #257

@looikaizhi

Description

@looikaizhi

Background

I have successfully used tlsn-extension to generate a TLSNotary proof for a Wise transfer transaction. The proof only discloses minimal necessary information.

The goal is to prove that:

  • A user transferred funds
  • To a specific Wise account
  • Within a specific time window

Next, I would like to submit the proof to a Solidity smart contract so that the contract can verify that the payment actually occurred and then continue executing DeFi logic.

Proposed Approach

My current idea is to adapt TLSN so the proof can be efficiently verified on-chain.

1. Replace hash algorithm with keccak256

In: tlsn/crates/core/src/transcript/commit.rs

impl<'a> TranscriptCommitConfigBuilder<'a> {
    /// Creates a new commit config builder.
    pub fn new(transcript: &'a Transcript) -> Self {
        Self {
            transcript,
            default_kind: TranscriptCommitmentKind::Hash {
                alg: HashAlgId::BLAKE3, // change to keccak256
            },
            commits: HashSet::default(),
        }
    }

TranscriptCommitConfigBuilder currently uses its default hash algorithm. I plan to replace it with keccak256, because:

  • Solidity natively supports keccak256
  • It reduces gas cost for hashing inside smart contracts
  • It avoids the need to implement another hash function in Solidity

2. Add verifier signature using secp256k1 (EVM-compatible)

Currently the tlsn-extension verifier does not produce a signature. My idea is:

  • Export the transcript_commitments field from VerifierOutput
  • Sign it using a private key
  • Use secp256k1 (Ethereum compatible)

I noticed the signing infrastructure here: tlsn/crates/attestation/src/signing.rs

impl SignatureAlgId {
    /// secp256k1 signature algorithm with SHA-256 hashing.
    pub const SECP256K1: Self = Self(1);
    /// secp256r1 signature algorithm with SHA-256 hashing.
    pub const SECP256R1: Self = Self(2);
    /// Ethereum-compatible signature algorithm.
    ///
    /// Uses secp256k1 with Keccak-256 hashing. The signature is a concatenation
    /// of `r || s || v` as defined in Solidity's ecrecover().
    pub const SECP256K1ETH: Self = Self(3);  // use this

So my plan is:

  • Sign transcript_commitments
  • Use secp256k1 Ethereum signature
  • Verify it in Solidity via ecrecover

This should make verification significantly cheaper on-chain.

3. Off-chain verification using verify_with_provider

I noticed a function called: verify_with_provider

In my understanding, is that this allows any party to verify the TLS proof off-chain, before the signed commitment is submitted on-chain.

So the flow could be:

  • TLSN proof generated
  • Anyone can verify proof off-chain

Questions

1. Keccak compatibility

If I replace the transcript commitment hash with keccak256, would the resulting commitment be safely verifiable inside Solidity?

Or does TLSN depend on a specific hash function that should not be modified?

2. Attestation signing after Notary removal

I noticed that TLSN is moving away from the Notary architecture.

If the verifier needs to sign the transcript commitment:

Is it still valid to use the attestation signing module? (tlsn/crates/attestation/src/signing.rs)

Could this conflict with the current TLSN design?

3. Rebuilding wasm after modifying TLSN

If I modify the TLSN Rust codebase (for example changing the hash algorithm or exporting new fields):

What is the recommended way to rebuild the wasm bindings so that I can call the new functions from TypeScript?

Is there a documented workflow for this?


Is there already a recommended architecture for on-chain TLS proof verification (especially for EVM chains)?

If there is a better design than the approach above, I would greatly appreciate guidance from the team.

Thank you very much for your time and for building TLSN.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions