zkTLS: An Alternative to Native HTTPS Outcalls for Private or Big Data

Hello all :waving_hand:,

I’m Ryan from Usher Labs, where we focus on zero-knowledge cryptography to help Web3 businesses keep their data safe. I want to share in a post how you can get data from the outside world into the Internet Computer (IC). This comes after the recent updates to HTTPS Outcalls, like IPv4 support and non-replicated calls. While great steps forward, there’s another way that tackles some key challenges: zkTLS.

zkTLS is a tech that uses cryptography to prove data comes from a trusted source without revealing secrets. Our platform, Verity, makes it easy to build secure data pipelines with zkTLS. I’ve created a videos to

  1. :backhand_index_pointing_right: explain why zkTLS > native
  2. walkthrough a code demo – check it out below. The code demo forks the ICP Ninja starter for non-replicated requests.

It’s all about making data fetching safer, cheaper, and better for building protocols on any chain, using IC as a data verification hub.

How Native HTTPS Outcalls Work Today

The IC has built-in tools to pull data from APIs. That’s handy! In a subnet (a group of nodes that work together), each node – say 13 or 34 of them – makes its own request to the API. They then agree on the result through consensus. For example, if you’re grabbing crypto prices from CoinGecko, all nodes check the same data at the same time.

This works well for public data, but it has limits:

  • Consensus needs matching results: If the API gives slightly different answers to each node (due to timing or small changes), it might fail.

  • Security risks with non-replicated calls: The new feature lets one node fetch data and share it without repeats. This saves resources but opens doors to tampering if that single node is compromised.

  • High costs for frequent fetches: Repeating requests across all nodes uses a lot of cycles (IC’s compute units), especially if you’re pulling data often. While this functions like Chainlink, zkTLS opts to work with a single request but adds cryptographic proofs for extra trust.

zkTLS as a Strong Alternative

zkTLS lets you fetch data off-chain with proofs that the IC can verify. This means:

  • Access to private data: Get info behind logins or API keys without exposing secrets. Perfect for sensitive stuff like user details or financial records.

  • Lower costs and faster speeds: Instead of every node repeating the fetch, one proof covers it all. Our tests show big drops in cycle use – up to dramatic reductions for high-frequency data.

  • Strong security: Cryptographic guarantees ensure data hasn’t been changed. Even if you’re handling millions in assets, it’s tamper-proof.

  • Build on-chain databases: Index real-world data like credit scores, reserves, or derivatives into IC canisters. Recent IC tools for SQL databases pair well with this.

For sending data out (like to Ethereum), non-replicated calls shine – no need to repeat sends. But for fetching in, zkTLS keeps things efficient while adding that proof layer.

How Verity Makes zkTLS Easy

Verity is our open-source toolkit for zkTLS. It works like this:

  • Prover: Fetches data and creates a TLS proof off-chain.

  • Verifier (Canister): Validates the TLS proof on-chain

  • IC Canister or zkVM for Data Processing: Handles transformations in a verifiable way, like using zero-knowledge virtual machines (zkVMs).

We visited the DFINITY team in Switzerland earlier this year to share our research. The results? zkTLS cuts cycle costs hugely compared to native repeats, especially for frequent updates. There’s a trade-off – running proof infrastructure has a base cost – but for anything more than a few requests per hour, it’s worth it.

Think of the IC as a hub for verified world data. Feed it into DeFi protocols across crypto, or use it for new ideas like micro-loans based on credit scores.

Code Demo + Walkthrough

Code Repository: GitHub - rsoury/ic-verity-demo: Demo of using Verity zkTLS to fetch data on Internet Computer

Walkthrough Video: Verity zkTLS to the IC - Code Log | Loom

Let’s Chat

What do you think? Have you run into issues with HTTPS Outcalls? How could zkTLS fit your projects? Join the discussion, or reach out to us at Usher Labs via Discord or our site. We’re here to help support adoption of the IC!

Cheers,
Ryan Soury
Usher Labs

10 Likes

Hey Ryan :waving_hand:

thanks for sharing the demo and the walkthrough :slight_smile:

Quick feedback on this:

  • can you make sure to update the README so that the “Open in ICP Ninja” button uses the correct repo?

I just deployed this via ninja and got following error when calling canister_http:

(variant {Err="Failed to parse JSON response: expected value at line 1 column 1"})

@fxgst WDYT about adding this example also to ninja once it is in a good shape?

UPDATE

  • alright I just realized I was to quick without looking into the demo thoroughly and that this requires an additional setup
  • not sure if this fits into a ninja example :thinking:
    • might be better to remove the “Open in ICP Ninja” button in the readme then
4 Likes

Hi @marc0olo ,

You are correct, there are dependencies on components outside the scope of the IC.

I’ve improved the README to describe operating these components and invoking them through the new non-replicated HTTPS Outcalls.

The demo aims to make a single HTTPS Outcalls request verifiable through cryptography.


I believe I’ve also surfaced a potential bug in attempting to allow our Managed TLS Verifier Canister to load via dfx deps deploy

I spent as much time as I could aiming to improve dfx configuration inside of our dependency Canister. I had to use the EVM RPC Canister as a reference to do this.

I’ve included this report inside of the README: GitHub - rsoury/ic-verity-demo: Demo of using Verity zkTLS to fetch data on Internet Computer

It seems Canister ID on mainnet and Local Node via dfx start cannot share the same Principle.


As an alternative to dfx deps deploy, I’ve included guide to simple local deployment of third-party Canister: GitHub - rsoury/ic-verity-demo: Demo of using Verity zkTLS to fetch data on Internet Computer

1 Like

Hey @ryanusher,

zkTLS is great! I love to see the wider ‘web3 science’ space come back into the ICP ecosystem :slight_smile:

But the “ZK” in zkTLS - is often not ZK.

You’re right that zkTLS is promising, but in practice, the ‘zero-knowledge component’ is often minimal or absent entirely. Most production systems lean heavily on MPC rather than true zero-knowledge cryptography. I’ve seen implementations that rely more on EigenLayer restaking and social consensus mechanisms than cryptographic proofs. Systems like Pluto (pluto.xyz) and Opacity (docs.opacity.network) illustrate this; there are likely a dozen more.

Opacity:
MPC with garbled circuits and oblivious transfer.

Pluto:
TEE with zkAttestation of the TEE. zkDCAP.

Core Trust Model Challenge

If I understand correctly, the fundamental issue remains: someone must act as a trusted proxy to verify API data authenticity. Your system uses:

  • Prover: Fetches data off-chain and generates TLS proofs

  • Verifier: IC canister that validates proofs on-chain

This introduces a critical trust bottleneck. While zkTLS provides cryptographic proof that data came from a legitimate TLS session, it doesn’t solve the core trust problem:

Two Scenarios, Both Problematic:

  1. Public inputs: If the API data is public anyway, why not just provide direct API access rather than adding this complexity?

  2. Private inputs: If the data is sensitive (your main value prop), how do we ensure the prover isn’t inputting completely fabricated data? Running verifiable computation over a program doesn’t guarantee the prover used authentic inputs.

    You have a single point of failure. The prover. Correct me if I am wrong?

The Collusion Problem

A malicious prover could potentially:

  • Collude with API providers to prove incorrect values

  • Selectively choose which data points to prove (cherry-picking)

  • Manipulate timing to capture favorable data points

While compromising an API’s TLS infrastructure is much harder than corrupting individual nodes, the single point of failure remains concerning, especially for high-value applications.

MPC Alternative

MPC-based systems distribute this trust across multiple parties - requiring broad collusion to compromise the system rather than a single prover + API compromise.

What’s your take on these trust model trade-offs? How does Verity address the prover reliability problem beyond the cryptographic guarantees?

___

Which zkVM do you plan to use? You will need many machines to make STARK compression work with ETH, or pay lots of gas cost. I can provide a few pointers on this. But your efficiency hit would be here from the naive case you mention as a benchmark.

  • Could take minutes or hours for complex TLS sessions.
  • GBs of RAM for proof generation. 128GB++
  • Representing TLS hash functions in arithmetic circuits is massive.

__

”For sending data out (like to Ethereum), non-replicated calls shine – no need to repeat sends.”

Would need some feedback from the Dfinity team on how http outcalls function.. but if they are WASM based with repeat sends for consensus while avoiding collusion.. you could just make proofs for each of those and aggregate them to be sent to verify on ETH as one succinct proof.

Hello @apotheosis ,

I appreciate your attempt to breakdown security risks within our architecture.

To clarify, Verity zkTLS stack involves a fork of TLSNotary.

Use cases | TLSNotary - See us here.

At the API request, it follows an an MPC architecture.

Therefore, the same security model are shared between Opacity, vLayer, and us.

Let me address your concerns one by one:

why not just provide direct API access rather than adding this complexity?

Because it’s cost efficient to adopt this model at a certain frequency of data requests / second.

You have a single point of failure. The prover. Correct me if I am wrong?

The Prover can be self-hosted to mitigate risks involved in sharing data. A Prover cannot fabricate data if engaging a Notary with integrity over MPC-TLS protocol to co-sign a given TLS handshake.

However, as with real-world application of any software, some users do not mind sharing data with only 1 party to mitigate overheads in tech operation. eg. using AWS instead running your own hardware. Therefore, we do offer our Prover Proxy as a managed instance.

Collusion Problem

The collusion problem ONLY occurs if the Prover and the Notary in an MPC-TLS collude to fabricate the results of a Server (API).

Beyond this, your dot points about collusion need evidence. From research, they’re incorrect.

eg. Anyone can collude with an API provider to request/prove incorrect values. This is why zkTLS only really works with Trusted Data. Learn more on what is Trusted Data here.

Our answer to the collusion risk is to isolate aspects of the Notary involved in key management and proof integrity checks, and operate these functions inside of TEE enclaves.

This approach is not new (eg. feat: intel sgx attestation by maceip · Pull Request #630 · tlsnotary/tlsn · GitHub ), Opacity also adopts this model. However, where we will differ is in enforcing operation of a Notary in an TEE through a protocol on the Internet Computer.

In essence, the ICP will serve as a coordination layer to determine whether a Notary is “verified“, and therefore where the extended MPC-TLS proofs can be valid.

Work by ICPanda team is quite inspiring: GitHub - ldclabs/ic-tee: 🔐 Make Trusted Execution Environments (TEEs) work with the Internet Computer.

You can read more on our approach here: Architecture - Usher Labs' Verity Documentation

Alternative approaches involve using many Notaries for a single API request.

What’s your take on these trust model trade-offs?
Which zkVM do you plan to use?

The MPC approach to TLS proofs is the most secure model as the proof itself is a correlation (in the form of a Merkle Tree) between sent/recv data and the associated TLS cert_chain.

However, the complexity of the proof introduces what Verity zkTLS actually does.

API → Ethereum is a data flow enabled with Verity zkTLS, powered by the Internet Computer and optionally RiscZero zkVM (for private data processing).

Representing TLS hash functions in arithmetic circuits is massive.

We agree.

In Verity zkTLS - ICP is used as a decentralised verification hub for both public-only facets in the MPC-TLS proofs, and then for direct zkSTARK verification.

In our case, we split the TLS Proof into sub-proofs that verify on zkVM and ICP, and then marry the results, into a single tECDSA of outcome.

It’s the best model available in my opinion.

See an example with zkVM here: verity-dp/examples/zktls at dev · usherlabs/verity-dp · GitHub


The only solid alternative is the pure TLS Proxy model, which involves traffic routed through an Attestor. It offers better latency outcomes at the cost of assuming trust specifically in Attestor’s observation of the data and TLS handshake.

Great!

In your diagram above you did not mention MPC. Only Orchestrator and zkVM.
This is where my entire argument was coming from. Was able to read your docs a bit more.

So now that you do use MPC (to avoid collusion) w/ TLSNotary; so the '“ZK” portion is not super significant… I expect that you will be using multiple machines for Multi-Party-Computation. This means more overhead. Moreover, you need a way to randomize selection or slash bad actors; you can use the IC for this.

”In essence, the ICP will serve as a coordination layer to determine whether a Notary is “verified“, and therefore where the extended MPC-TLS proofs can be valid.”

So essentially Opacity but rather than AVS on Eigen you have it on ICP.

zkVM choice

Risc0 is technically not ZK (as in not private)… they do something weird with obfuscation and claim privacy by wrapping the final proofs with Groth16. If you needed to do the same wrapping you would need many machines with lots of memory.

As an FYI — technically no STARK is privacy preserving at the moment. Also STARKs would be terribly heavy for this use case — a lot of memory and minutes to prove.

Access to private data” - this is not possible in your setup unless you use zkTLS with TEE and then rely on the TEE hardware as the privacy preserving portion. For this you would need to do what pluto does and attest to the TEE - with zkDCAP where you use ZK to compress the TEE attestations.

”In Verity zkTLS - ICP is used as a decentralised verification hub for both public-only facets in the MPC-TLS proofs, and then for direct zkSTARK verification.”

So you are going through ICP consensus.

Lower costs and faster speeds” - this is completely unclear.

”For sending data out (like to Ethereum), non-replicated calls shine – no need to repeat sends.”

You need Groth16 or to pay high gas costs for large STARK proofs. Neither is great.

”n our case, we split the TLS Proof into sub-proofs that verify on zkVM and ICP, and then marry the results, into a single tECDSA of outcome.”

tECDSA is a better choice!

Ok.. so now that I read the docs and understand the system. We need to discuss this graph.

I am super excited about a zkTLS solution running on ICP. Just trying to help you out with value-prop so you can get PMF easier.

  1. The chart is only the final verifier cost and efficiency. This excludes any cost of ZKP generation, MPC, MPC node selection (needs to be random to prevent collusion or have some slashing), ICP verifiers meeting consensus?

  2. If using Risc0, for zkDCAP for your TEE? The cost of the TEE needs to be added. The cost of using Risc0 as well. If you do use Bonsai there is overhead there.. if not you will need a powerful machine to do the ZKP portion. Also this is not privacy preserving if not using the TEE. STARKs are not ZK, they wrap STARK proofs in Groth16 for ZK; at much cost.

  3. If you do not do 2 and decide to verify the TEE proofs directly on the IC, what is the cost?
    At the end of this process you will need HTTP outcalls or tECDSA - so the cost would be the base cost of using ICP directly + the overhead cost of everything above.

Component Missing Costs
ZKP Generation RISC0: $X per proof
TEE Operations TDX premium: +20-50% compute
MPC Coordination Node selection + slashing: $Y
ICP Consensus Verification cycles: Z ICP
Cross-chain Output Ethereum gas: 100k-500k gas. millions if using STARK and not Groth16. If using tECDSA you have the same base cost as default HTTP outcalls + overhead of the system.

The value prop is not the cost of your system vs HTTP outcalls. It would be the relative performance and trust trade-offs vs the competition like Opacity and Pluto. Any advantage here — would be a good product. Since Opacity uses Eigen for node selection.. this is where I would dive in. Also if tECDSA is much cheaper for triggering cross chain zkTLS transactions - which I suspect it is. You have hardware based ‘privacy’ with the TEE; ZKP is not really needed unless you want to wrap those TEE proofs to make them more succinct, with the IC you do not need to - the costs should be lower than ETH for directly verifying them.

Last non-technical business note — by finding your true value prop you also get a larger potential user-base. ICP devs < People who need zkTLS (ETH, SOL, Web2, +ICP).

Let me continue to address your concerns 1 by 1:

The chart is only the final verifier cost and efficiency

Incorrect, it factors in the base cost of operating a single Prover and Notary on a VPS. Hence the tradeoff based on request frequency.

This chart does not include use of zkVM. zkVM is only necessary when processing private data. Developers can choose whether data redactions can suffice, meaning omitting data from proofs that is private. However, redacted data can no longer be processed.

eg. Imagine we want to associate a CEX account to a wallet signature. API key credentials are essentially distinct identifiers relative to the CEX account, and therefore zkVM can enforce that correlation.

ICP verifiers meeting consensus

This is inherent in the Internet Computer, as it is a replicated state machine.

MPC node selection

Node Selection requires trivial cycle requirements. However, well noted that this is not considered in the graph.

As a matter of fact, the cycles in this process will be primarily paid by Notaries primarily on participation verifying their secure operation in TEE enabled VM. On verification of TLS proofs, of sub-proofs, there is cross-references to the list of “verified“ Notaries.

needs to be random to prevent collusion or have some slashing

Not necessarily. TEE should suffice. As a matter of fact, geographic distance between Prover and Notary also plays a role in uptime.

The cost of the TEE needs to be added.

Ask ICP team, who are now using TEE, the difference is trivial.

for zkDCAP for your TEE

Attestations and essentially all non-private compute occurs on the ICP.

Notaries pay to “participate” in the protocol, and maintain “verified” status.

Also this is not privacy preserving if not using the TEE.

Incorrect. Privacy is a condition: eg. have my API keys been leaks to ICP node operators?

The tools alone do not determine privacy, it’s how they’re used for that particular function.

In our case, it’s to move data from A to B.

The entire stack can be operated in house in a server in your basement - achieving full data privacy. But in the real world, with real businesses, this is not viable and some credential sharing is necessary. Refer back to AWS example.

STARKs are not ZK, they wrap STARK proofs in Groth16 for ZK; at much cost.

Incorrect.

Groth16 proof generation is an aggregated verification of a STARK to consolidate proof size.

At the end of this process you will need HTTP outcalls or tECDSA

Incorrect.

tECDSA is only necessary for generating a proof to use in external systems.

eg. tECDSA = Proof of ICP out.

The graph compares approaches to data ingestion exclusively into ICP.

Opacity uses Eigen

Eigen is literally just ICP if it decouples consensus and compute.

PMF

zkTLS is not our PMF. It’s a public utility. The aim is to empower protocols with more data that people care about.


Final note, I appreciate your comments and your concerns about why this viable or valid, and “how we can achieve PMF”, however, your cost considerations are not grounded on what the graph is actually presenting a comparison on.

The graph compares approaches to data ingestion exclusively into ICP.


PS. Anyone is welcome to take the benchmarks for a spin: https://github.com/usherlabs/ic-adc/tree/main/example_caller#benchmarking-workflow

@ryanusher STARK (as in hash based ZKP systems) are not privacy preserving this is a well known fact. The reason why Risc0 and other zkVM use Groth16 is for two reasons: make it fit onto ETH, and make the final thing ‘privacy preserving’.

’Costs’ should include all costs to your service for you running the service.
This is the baseline. Right now you ignore almost all costs by pushing them off-chain. Someone still needs to pay for these; at best it would cost equal to using ICP directly.

Just some disclaimers showing the fact.. but there is actually a lot of research papers and videos as well. The Risc0 system claims privacy but is not technically.. unless you wrap the proof with Groth16.

I would spend time making this beat other zkTLS services such as Opacity and Pluto.

ckTLS leverages the Verity Network and Data Processor Framework to generate MPC-TLS proofs, and verify them within the IC Canister.

What is the true total cost? This benchmark is just the verifier right?
The cost of running MPC + TEE or any other component required for your protocol.

Those numbers would be very helpful.

’Costs’ should include all costs to your service for you running the service.

The purpose of the graph is to compare costs for executing the same function: Unprocessed (optionally redacted) API data into ICP.

It uses nominated Notary in current model, similar to Reclaim or vLayer.

This is a total true cost.

The graph also considers cost of off-chain components - hence the tradeoff.

For TEE driven collusion resistance, I advise adding a generous 10% buffer. As mentioned costs will be paid by Notary on participation.

Nonetheless, of course, we’ll have more numbers as we progress this model.

’Costs’ should include all costs to your service for you running the service.

^ The graph would not make sense.

STARK (as in hash based ZKP systems) are not privacy preserving this is a well known fact.

As for your assessment of zkSTARKs, simplified research: https://grok.com/share/bGVnYWN5_b5c8a3b6-b558-4b93-86f7-31bbd6ff4183

If you’ve identified a flaw in their code, or system, I would definitely advise reviewing the R0 Whitepaper, and then surfacing the error to the RiscZero team. I’m sure they’ll reward your findings :folded_hands:

Please pay attention to this 20 seconds - I marked the specific spot for you with a timestamp.

No STARKS have attainted the zero knowledge property. What Risc0 does is different and is not true ZK. They want you to upgrade to Bonsai to wrap in Groth16 which would be ZK.

Here is what my PhD team member says:

”I remember talking with the Risc0 team at the time when they claimed to have privacy but not zk (the explanation was very messy and purely based on engineering details but in short they added some randomisation that made it “hard” to retrieve private data). I think this recent zk puzzle (https://zkhack.dev/zkhackV/puzzleV1.html) showed that being “hard” doesn’t make it zk. Once again they wrote a post on the puzzle https://nmohnblatt.github.io/chosen-instance-attack/

If you don’t understand that or don’t believe it watch the short clip from Ulrich Habock the current leader in STARK academics and production systems — on why NO STARK has achieved the zero-knowledge property (they are not privacy preserving).

*Grok is obviously not an academic :slight_smile:

With the components that you mentioned needing — MCP + TEE + optional ZKP (10,000x the computation cost) + if you want to interact with ETH you need tECDSA (the base-cost).

The code you share as your benchmark is simply the adc_caller. Not the full cost of running the protocol.

From the RiscZero docs (our intern looked this up in a few minutes):

”Proofs generated by the RISC-V Prover that haven’t been passed through the Recursion Prover leak information about the length of execution. Passing proofs through the Recursion Prover resolves this warning: recursion proofs leak no information about execution length.”

The recursive prover is the Groth16 portion.. this is what they want you to pay for on Bonsai if not its huge compute cost that you will need to run.

”We urge those with critical privacy requirements to take caution until the necessary changes have been implemented.”

So now we know without a doubt .. that in theory and in implementations no STARK has ever achieved zero-knowledge and should not be used for privacy :wink:.

Interesting,

Thank you for shedding light on this.

recursive prover is the Groth16 portion

The Recursion Prover is distinct from the STARK → SNARK (Groth16) Prover.

We use proof post-Recursion.

Nonetheless, I’ve shared this post with R0 team.


Side note: I did more research

  1. Ulrich mentions “I’m not saying they’re insecure because they are in production“
  2. The talk seems more a cautionary tale, not a condemnation. Ulrich argues that Perfect ZK is not achieved, which is true. However, Statistical ZK is still achieved - which is susceptible to the same brute force (highly unlikely because computationally expensive) attacks that other cryptography algos face.
    1. The chances of successfully brute forcing data extraction from a RISC Zero proof are negligible, on the order of 1 in 2^{100}
  3. The probability of meaningful data leakage is exponentially small
  4. Further Perfect vs Statistical offers trade-offs.
    1. The former is less efficient overhead rises 10-15%
    2. The statistical approach prioritises efficiency.

Therefore, it seems R0 is aware of this, and their approach is with purpose.

However, we’ll keep an eye on this. Could be worth revisiting in the Post-Quantum world.

1 Like

Glad we can dive into more research on it!
I am deep into the zkWorld and research. Just happy if your portocol beats best of class in zkTLS.

1 Like

Think this is the wrong take-away. You should not use STARK for any privacy app that has any funds involved. Likely, it is not private! It has nothing to do with quantum computers. This has to do with math. If you want privacy you should use a ZKP system that has the zero-knowledge property.

**”We urge those with critical privacy requirements to take caution until the necessary changes have been implemented.” - Risc Zero docs.
**
Your “1 in 2^100” confidence is misplaced because the real vulnerabilities aren’t just brute force attacks - they’re implementation gaps that can leak information through normal protocol execution.

It’s like saying “bank vaults are secure because they’re rated for explosives” while ignoring that the door is left wide open. The 2^100 security is meaningless if information leaks through implementation flaws during normal operation as noted in Ulrich’s talk.

Here is the paper form of Ulrich’s talk.