PageSourceSearch

https://noir-lang.org/docs/assets/js/b095fc37.39a6592c.js

js noir-lang.org collected 2026-10-03 22:55:10 UTC 16,338 bytes, 1 lines download raw bytes

1"use strict";(globalThis.webpackChunkdocs=globalThis.webpackChunkdocs||[]).push([[4e3],{5953(e,n,r){r.r(n),r.d(n,{assets:()=>l,contentTitle:()=>a,default:()=>h,frontMatter:()=>i,metadata:()=>s,toc:()=>c});const s=JSON.parse('{"id":"guides/how_to_use_oracles","title":"How to use Oracles","description":"Learn how to use oracles in your Noir program with examples in both Nargo and NoirJS. This guide also covers writing a JSON RPC server and providing custom foreign call handlers for NoirJS.","source":"@site/processed-docs/guides/how_to_use_oracles.md","sourceDirName":"guides","slug":"/guides/how_to_use_oracles","permalink":"/docs/dev/guides/how_to_use_oracles","draft":false,"unlisted":false,"editUrl":"https://github.com/noir-lang/noir/edit/master/docs/docs/guides/how_to_use_oracles.md","tags":[],"version":"current","frontMatter":{"title":"How to use Oracles","description":"Learn how to use oracles in your Noir program with examples in both Nargo and NoirJS. This guide also covers writing a JSON RPC server and providing custom foreign call handlers for NoirJS.","keywords":["Noir Programming","Oracles","Nargo","NoirJS","JSON RPC Server","Foreign Call Handlers"]}
1,"sidebar":"sidebar","previous":{"title":"Noir Codegen for TypeScript","permalink":"/docs/dev/tooling/noir_codegen"},"next":{"title":"Using the VS Code Debugger","permalink":"/docs/dev/guides/debugging/debugging_with_vs_code"}}');var o=r(74848),t=r(28453);const i={title:"How to use Oracles",description:"Learn how to use oracles in your Noir program with examples in both Nargo and NoirJS. This guide also covers writing a JSON RPC server and providing custom foreign call handlers for NoirJS.",keywords:["Noir Programming","Oracles","Nargo","NoirJS","JSON RPC Server","Foreign Call Handlers"]},a=void 0,l={},c=[{value:"Rundown",id:"rundown",level:2},{value:"Step 1 - Modify your Noir program",id:"step-1---modify-your-noir-program",level:2},{value:"Step 2 - Write an RPC server",id:"step-2---write-an-rpc-server",level:2},{value:"Step 3 - Usage with Nargo",id:"step-3---usage-with-nargo",level:2},{value:"Step 4 - Usage with NoirJS",id:"step-4---usage-with-noirjs",level:2},{value:"Conclusion",id:"conclusion",level:2}];function d(e){const n={a:"a",admonition:"admonition",code:"code",em:"em",h2:"h2",li:"li",ol:"ol",p:"p",pre:"pre",ul:"ul",...(0,t.R)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.p,{children:"This guide shows you how to use oracles in your Noir program. For the sake of clarity, it assumes that:"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:["You have read the ",(0,o.jsx)(n.a,{href:"/docs/dev/guides/oracles",children:"explainer on Oracles"})," and are comfortable with the concept."]}),"\n",(0,o.jsxs)(n.li,{children:["You have a Noir program to add oracles to. You can create one using one of the starters in ",(0,o.jsx)(n.a,{href:"https://github.com/noir-lang/awesome-noir?tab=readme-ov-file#boilerplates",children:"awesome-noir"}),"."]}),"\n",(0,o.jsxs)(n.li,{children:["You understand the concept of a JSON-RPC server. Visit the ",(0,o.jsx)(n.a,{href:"https://www.jsonrpc.org/",children:"JSON-RPC website"})," if you need a refresher."]}),"\n",(0,o.jsx)(n.li,{children:"You are comfortable with server-side JavaScript (e.g. Node.js, managing packages, etc.)."}),"\n"]}),"\n",(0,o.jsx)(n.h2,{id:"rundown",children:"Rundown"}),"\n",(0,o.jsx)(n.p,{children:"This guide has 3 major steps:"}),"\n",(0,o.jsxs)(n.ol,{children:["\n",(0,o.jsx)(n.li,{children:"How to modify our Noir program to make use of oracle calls as unconstrained functions"}),"\n",(0,o.jsx)(n.li,{children:"How to write a JSON RPC Server to resolve these oracle calls with Nargo"}),"\n",(0,o.jsx)(n.li,{children:"How to use them in Nargo and how to provide a custom resolver in NoirJS"}),"\n"]}),"\n",(0,o.jsx)(n.h2,{id:"step-1---modify-your-noir-program",children:"Step 1 - Modify your Noir program"}),"\n",(0,o.jsx)(n.p,{children:"An oracle is defined in a Noir program by defining two methods:"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:["An unconstrained method - This tells the compiler that it is executing an ",(0,o.jsx)(n.a,{href:"/docs/dev/language/unconstrained",children:"unconstrained function"}),"."]}),"\n",(0,o.jsx)(n.li,{children:"A decorated oracle method - This tells the compiler that this method is an RPC call."}),"\n"]}),"\n",(0,o.jsxs)(n.p,{children:["An example of an oracle that returns a ",(0,o.jsx)(n.code,{children:"Field"})," would be:"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-rust",children:"#[oracle(getSqrt)]\nunconstrained fn sqrt(number: Field) -> Field { }\n\nunconstrained fn get_sqrt(number: Field) -> Field {\n    sqrt(number)\n}\n"})}),"\n",(0,o.jsxs)(n.p,{children:["In this example, we're wrapping our oracle function in an unconstrained method, and decorating it with ",(0,o.jsx)(n.code,{children:"oracle(getSqrt)"}),". We can then call the unconstrained function as we would call any other function:"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-rust",children:"fn main(input: Field) {\n    let sqrt = get_sqrt(input);\n}\n"})}),"\n",(0,o.jsxs)(n.p,{children:["In the next section, we will make this ",(0,o.jsx)(n.code,{children:"getSqrt"})," (defined on the ",(0,o.jsx)(n.code,{children:"sqrt"})," decorator) be a method of the RPC server Noir will use."]}),"\n",(0,o.jsxs)(n.admonition,{type:"danger",children:[(0,o.jsxs)(n.p,{children:["As explained in the ",(0,o.jsx)(n.a,{href:"/docs/dev/guides/oracles",children:"Oracle Explainer"}),", this ",(0,o.jsx)(n.code,{children:"main"})," function is unsafe unless you constrain its return value. For example:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-rust",children:"fn main(input: Field) {\
1n    let sqrt = get_sqrt(input);\n    assert(sqrt.pow_32(2) as u64 == input as u64); // <---- constrain the return of an oracle!\n}\n"})})]}),"\n",(0,o.jsxs)(n.admonition,{type:"info",children:[(0,o.jsx)(n.p,{children:"Currently, oracles only work with single params or array params. For example:"}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-rust",children:"#[oracle(getSqrt)]\nunconstrained fn sqrt([Field; 2]) -> [Field; 2] { }\n"})})]}),"\n",(0,o.jsx)(n.h2,{id:"step-2---write-an-rpc-server",children:"Step 2 - Write an RPC server"}),"\n",(0,o.jsxs)(n.p,{children:["Brillig will call ",(0,o.jsx)(n.em,{children:"one"})," RPC server. Most likely you will have to write your own, and you can do it in whatever language you prefer. In this guide, we will do it in Javascript."]}),"\n",(0,o.jsxs)(n.p,{children:["Let's use the above example of an oracle that consumes an array with two ",(0,o.jsx)(n.code,{children:"Field"})," and returns their square roots:"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-rust",children:"#[oracle(getSqrt)]\nunconstrained fn sqrt(input: [Field; 2]) -> [Field; 2] { }\n\nunconstrained fn get_sqrt(input: [Field; 2]) -> [Field; 2] {\n    sqrt(input)\n}\n\nfn main(input: [Field; 2]) {\n    let sqrt = get_sqrt(input);\n    assert(sqrt[0].pow_32(2) as u64 == input[0] as u64);\n    assert(sqrt[1].pow_32(2) as u64 == input[1] as u64);\n}\n\n#[test]\nfn test() {\n    let input = [4, 16];\n    main(input);\n}\n"})}),"\n",(0,o.jsxs)(n.admonition,{type:"info",children:[(0,o.jsx)(n.p,{children:"Why square root?"}),(0,o.jsx)(n.p,{children:"In general, computing square roots is computationally more expensive than multiplications, which takes a toll when speaking about ZK applications. In this case, instead of calculating the square root in Noir, we are using our oracle to offload that computation to be made in plain. In our circuit we can simply multiply the two values."})]}),"\n",(0,o.jsxs)(n.p,{children:["Now, we should write the correspondent RPC server, starting with the ",(0,o.jsx)(n.a,{href:"https://www.npmjs.com/package/json-rpc-2.0#example",children:"default JSON-RPC 2.0 boilerplate"}),":"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-js",children:'import { JSONRPCServer } from "json-rpc-2.0";\nimport express from "express";\nimport bodyParser from "body-parser";\n\nconst app = express();\napp.use(bodyParser.json());\n\nconst server = new JSONRPCServer();\napp.post("/", (req, res) => {\n const jsonRPCRequest = req.body;\n server.receive(jsonRPCRequest).then((jsonRPCResponse) => {\n  if (jsonRPCResponse) {\n   res.json(jsonRPCResponse);\n  } else {\n   res.sendStatus(204);\n  }\n });\n});\n\napp.listen(5555);\n'})}),"\n",(0,o.jsxs)(n.p,{children:["Now, we will add our ",(0,o.jsx)(n.code,{children:"getSqrt"})," method, as expected by the ",(0,o.jsx)(n.code,{children:"#[oracle(getSqrt)]"})," decorator in our Noir code. It maps through the params array and returns their square roots:"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-js",children:'server.addMethod("resolve_foreign_call", async (params) => {\n    if (params[0].function !== "getSqrt") {\n        throw Error("Unexpected foreign call")\n    };\n    const values = params[0].inputs[0].map((field) => {\n        return `${Math.sqrt(parseInt(field, 16))}`;\n    });\n    return { values: [values] };\n});\n'})}),"\n",(0,o.jsx)(n.p,{children:"If you're using Typescript, the following types may be helpful in understanding the expected return value and making sure they're easy to follow:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-js",children:"export type ForeignCallSingle = string;\n\nexport type ForeignCallArray = string[];\n\nexport type ForeignCallResult = {\n  values: (ForeignCallSingle | ForeignCallArray)[];\n};\n"})}),"\n",(0,o.jsx)(n.admonition,{title:"Multidimensional Arrays",type:"info",children:(0,o.jsxs)(n.p,{children:["If the Oracle function is returning an array containing other arrays, such as ",(0,o.jsx)(n.code,{children:"[['1','2],['3','4']]"}),", you need to provide the values in JSON as flattened values. In the previous example, it would be ",(0,o.jsx)(n.code,{children:"['1', '2', '3', '4']"}),". In the Noir program, the Oracle signature can use a nested type, the flattened values will be automatically converted to the nested type."]})}),"\n",(0,o.jsx)(n.h2,{id:"step-3---usage-with-nargo",children:"Step 3 - Usage with Nargo"}),"\n",(0,o.jsxs)(n.p,{children:["Using Nargo, you can use oracles in the ",(0,o.jsx)(n.code,{children:"nargo test"})," and ",(0,o.jsx)(n.code,{children:"nargo execute"})," commands by passing a value to ",(0,o.jsx)(n.code,{children:"--oracle-resolver"}),". For example:"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"nargo test --oracle-resolver http://localhost:5555\n"})}),"\n",(0,o.jsxs)(n.p,{children:["This tells ",(0,o.jsx)(n.code,{children:"nargo"})," to use your RPC Server URL whenever it finds an oracle decorator."]}),"\n",(0,o.jsx)(n.h2,{id:"step-4---usage-with-noirjs",children:"Step 4 - Usage with NoirJS"}
1),"\n",(0,o.jsx)(n.p,{children:"In a JS environment, an RPC server is not strictly necessary, as you may want to resolve your oracles without needing any JSON call at all. NoirJS simply expects that you pass a callback function when you generate proofs, and that callback function can be anything."}),"\n",(0,o.jsxs)(n.p,{children:["For example, if your Noir program expects the host machine to provide CPU pseudo-randomness, you could simply pass it as the ",(0,o.jsx)(n.code,{children:"foreignCallHandler"}),". You don't strictly need to create an RPC server to serve pseudo-randomness, as you may as well get it directly in your app:"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-js",children:"const foreignCallHandler = (name, inputs) => crypto.randomBytes(16) // etc\n\nawait noir.execute(inputs, foreignCallHandler)\n"})}),"\n",(0,o.jsxs)(n.p,{children:["As one can see, in NoirJS, the ",(0,o.jsx)(n.code,{children:"foreignCallHandler"}),' function simply means "a callback function that returns a value of type ',(0,o.jsx)(n.code,{children:"ForeignCallOutput"}),". It doesn't have to be an RPC call like in the case for Nargo."]}),"\n",(0,o.jsxs)(n.admonition,{type:"tip",children:[(0,o.jsxs)(n.p,{children:["Does this mean you don't have to write an RPC server like in ",(0,o.jsx)(n.a,{href:"#step-2---write-an-rpc-server",children:"Step #2"}),"?"]}),(0,o.jsxs)(n.p,{children:["You don't technically have to, but then how would you run ",(0,o.jsx)(n.code,{children:"nargo test"}),"? To use both Nargo and NoirJS in your development flow, you will have to write a JSON RPC server."]})]}),"\n",(0,o.jsxs)(n.p,{children:["In this case, let's make ",(0,o.jsx)(n.code,{children:"foreignCallHandler"})," call the JSON RPC Server we created in ",(0,o.jsx)(n.a,{href:"#step-2---write-an-rpc-server",children:"Step #2"}),", by making it a JSON RPC Client."]}),"\n",(0,o.jsxs)(n.p,{children:["For example, using the same ",(0,o.jsx)(n.code,{children:"getSqrt"})," program in ",(0,o.jsx)(n.a,{href:"#step-1---modify-your-noir-program",children:"Step #1"})," (comments in the code):"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-js",children:'import { JSONRPCClient } from "json-rpc-2.0";\n\n// declaring the JSONRPCClient\nconst client = new JSONRPCClient((jsonRPCRequest) => {\n// hitting the same JSON RPC Server we coded above\n return fetch("http://localhost:5555", {\n  method: "POST",\n  headers: {\n   "content-type": "application/json",\n  },\n  body: JSON.stringify(jsonRPCRequest),\n }).then((response) => {\n  if (response.status === 200) {\n   return response\n    .json()\n    .then((jsonRPCResponse) => client.receive(jsonRPCResponse));\n  } else if (jsonRPCRequest.id !== undefined) {\n   return Promise.reject(new Error(response.statusText));\n  }\n });\n});\n\n// declaring a function that takes the name of the foreign call (getSqrt) and the inputs\nconst foreignCallHandler = async (name, input) => {\n  const inputs = input[0].map((i) => i.toString("hex"))\n  // notice that the "inputs" parameter contains *all* the inputs\n  // in this case we to make the RPC request with the first parameter "numbers", which would be input[0]\n  const oracleReturn = await client.request("resolve_foreign_call", [\n    {\n      function: name,\n      inputs: [inputs]\n    },\n  ]);\n  return [oracleReturn.values[0]];\n};\n\n// the rest of your NoirJS code\nconst input = { input: [4, 16] };\nconst { witness } = await noir.execute(input, foreignCallHandler);\n'})}),"\n",(0,o.jsxs)(n.admonition,{type:"tip",children:[(0,o.jsxs)(n.p,{children:["If you're in a NoirJS environment running your RPC server together with a frontend app, you'll probably hit a familiar problem in full-stack development: requests being blocked by ",(0,o.jsx)(n.a,{href:"https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS",children:"CORS"})," policy. For development only, you can simply install and use the ",(0,o.jsxs)(n.a,{href:"https://www.npmjs.com/package/cors",children:[(0,o.jsx)(n.code,{children:"cors"})," npm package"]})," to get around the problem:"]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"yarn add cors\n"})}),(0,o.jsx)(n.p,{children:"and use it as a middleware:"}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-js",children:'import 
1cors from "cors";\n\nconst app = express();\napp.use(cors())\n'})})]}),"\n",(0,o.jsx)(n.h2,{id:"conclusion",children:"Conclusion"}),"\n",(0,o.jsx)(n.p,{children:"Hopefully by the end of this guide, you should be able to:"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:"Write your own logic around Oracles and how to write a JSON RPC server to make them work with your Nargo commands."}),"\n",(0,o.jsx)(n.li,{children:"Provide custom foreign call handlers for NoirJS."}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,t.R)(),...e.components};return n?(0,o.jsx)(n,{...e,children:(0,o.jsx)(d,{...e})}):d(e)}},28453(e,n,r){r.d(n,{R:()=>i,x:()=>a});var s=r(96540);const o={},t=s.createContext(o);function i(e){const n=s.useContext(t);return s.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(o):e.components||o:i(e.components),s.createElement(t.Provider,{value:n},e.children)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.