Skip to main content
Version: dev

Oracles

A Noir program is usually self-contained. You can pass certain inputs to it, and it will generate a deterministic output for those inputs. But what if you wanted to defer some calculation to an outside process or source?

Oracles let you do exactly that: they allow a Noir program to use the result of a calculation performed outside of it.

Use cases

An example usage for Oracles is proving something on-chain. For example, proving that the ETH-USDC quote was below a certain target at a certain block time. Or even making more complex proofs like proving the ownership of an NFT as an anonymous login method.

Another interesting use case is to defer expensive calculations to be made outside of the Noir program, and then constraining the result; similar to the use of unconstrained functions.

In short, anything that can be constrained in a Noir program but needs to be fetched from an external source is a great candidate to be used in oracles.

Constraining oracles

Oracles are powerful, but using one in a Noir program does not make its output true. The value an oracle returns is only as trustworthy as its source, so any claim that depends on external data still relies on potentially untrusted information.

To give a concrete example, Alice wants to login to the NounsDAO forum with her username "noir_nouner" by proving she owns a noun without revealing her ethereum address. Her Noir program could have an oracle call like this:

#[oracle(getNoun)]
unconstrained fn get_noun(address: Field) -> Field

This oracle could naively resolve with the number of Nouns she possesses. However, it is useless as a trusted source, as the oracle could resolve to anything Alice wants. In order to make this oracle call actually useful, Alice would need to constrain the response from the oracle, by proving her address and the noun count belongs to the state tree of the contract.

In short, Oracles don't prove anything. Your Noir program does.

danger

If you don't constrain the return of your oracle, you could be clearly opening an attack vector on your Noir program. Make double-triple sure that the return of an oracle call is constrained!

Return Type

Oracles cannot return references (e.g., &Field, &mut T) because oracle functions represent external computations that execute outside the Noir program's memory space. Since oracles bridge between the Noir runtime and external environments, any values they return must be copied into the caller's context rather than referenced. Attempting to return a reference from an oracle would be meaningless, as there is no shared memory space between the oracle's execution environment and the Noir program.

This restriction applies to any type containing references, including:

  • Direct references: &Field, &mut u32
  • Tuples with references: (Field, &u32)
  • Structs with reference fields
  • Enums with reference variants

The compiler will produce an error if an oracle function's return type contains any references.

How to use Oracles

On CLI, Nargo resolves oracles by making JSON RPC calls, which means it would require an RPC node to be running.

In JavaScript, NoirJS accepts and resolves arbitrary call handlers (that is, not limited to JSON) as long as they match the expected types the developer defines.

If you want to build using oracles, follow through to the oracle guide for a simple example on how to do that.