1+ import type { UltraHonkBackend , UltraPlonkBackend } from "@aztec/bb.js" ;
12import {
23 TASK_CLEAN ,
34 TASK_COMPILE ,
@@ -7,28 +8,62 @@ import { task } from "hardhat/config";
78import { HardhatPluginError } from "hardhat/plugins" ;
89import { HardhatConfig } from "hardhat/types" ;
910import { NoirCache } from "./cache" ;
10- import { installBb , installNargo } from "./install" ;
11+ import { installNargo } from "./install" ;
1112import { getTarget , ProofFlavor } from "./Noir" ;
1213import { makeRunCommand , PLUGIN_NAME } from "./utils" ;
1314
1415task ( TASK_COMPILE , "Compile and generate circuits and contracts" ) . setAction (
1516 async ( args , { config } , runSuper ) => {
17+ const fs = await import ( "fs" ) ;
18+ const path = await import ( "path" ) ;
19+
1620 const noirDir = config . paths . noir ;
1721 const targetDir = await getTarget ( noirDir ) ;
1822
19- const runCommand = makeRunCommand ( config . paths . noir ) ;
20-
21- const nargoBinary = await installNargo ( config . noir . version ) ;
22- const bbBinary = await installBb ( config . noir . bbVersion ) ;
23-
2423 await checkNargoWorkspace ( config ) ;
2524 await addGitIgnore ( noirDir ) ;
2625
2726 const force = ! ! args . force ;
2827 const cache = await NoirCache . fromConfig ( config ) ;
2928 if ( ( await cache . haveSourceFilesChanged ( ) ) || force ) {
3029 console . log ( "Compiling Noir circuits..." ) ;
31- await runCommand ( `${ nargoBinary } compile` ) ;
30+ const { compile, createFileManager } = await import (
31+ "@noir-lang/noir_wasm"
32+ ) ;
33+ const toml = await import ( "smol-toml" ) ;
34+
35+ // list dirs
36+ const dirs = (
37+ (
38+ toml . parse (
39+ fs . readFileSync ( path . join ( noirDir , "Nargo.toml" ) , "utf-8" ) ,
40+ ) as any
41+ ) . workspace . members as string [ ]
42+ ) . map ( ( dir : string ) => path . join ( noirDir , dir ) ) ;
43+
44+ await Promise . all (
45+ dirs . map ( async ( dir ) => {
46+ const fileManager = createFileManager ( dir ) ;
47+ const compiled = await compile ( fileManager ) ;
48+ const name : unknown = (
49+ toml . parse (
50+ fs . readFileSync ( path . join ( dir , "Nargo.toml" ) , "utf-8" ) ,
51+ ) as any
52+ ) . package ?. name ;
53+ if ( typeof name !== "string" ) {
54+ throw new HardhatPluginError (
55+ PLUGIN_NAME ,
56+ `Nargo.toml must contain a name, but ${ dir } /Nargo.toml does not` ,
57+ ) ;
58+ }
59+ fs . mkdirSync ( targetDir , { recursive : true } ) ;
60+ fs . writeFileSync (
61+ path . join ( targetDir , `${ name } .json` ) ,
62+ JSON . stringify ( compiled . program , null , 2 ) ,
63+ ) ;
64+ } ) ,
65+ ) ;
66+
3267 await cache . saveSourceFilesHash ( ) ;
3368 console . log ( "Compiled Noir circuits" ) ;
3469 }
@@ -45,13 +80,7 @@ task(TASK_COMPILE, "Compile and generate circuits and contracts").setAction(
4580 if ( ! config . noir . flavor . includes ( flavor ) ) {
4681 continue ;
4782 }
48- await generateSolidityVerifier (
49- config ,
50- file ,
51- bbBinary ,
52- targetDir ,
53- flavor ,
54- ) ;
83+ await generateSolidityVerifier ( file , targetDir , flavor ) ;
5584 }
5685 await cache . saveJsonFileHash ( file ) ;
5786 } ) ,
@@ -108,43 +137,44 @@ task(
108137) ;
109138
110139async function generateSolidityVerifier (
111- config : HardhatConfig ,
112140 file : string ,
113- bbBinary : string ,
114141 targetDir : string ,
115142 flavor : ProofFlavor ,
116143) {
117144 const path = await import ( "path" ) ;
145+ const fs = await import ( "fs" ) ;
146+ const { UltraHonkBackend, UltraPlonkBackend } = await import ( "@aztec/bb.js" ) ;
118147
119- const runCommand = makeRunCommand ( config . paths . noir ) ;
120-
121- const name = path . basename ( file , ".json" ) ;
122- console . log ( `Generating Solidity ${ flavor } verifier for ${ name } ...` ) ;
123- let writeVkCmd : string , contractCmd : string ;
148+ let backend : UltraHonkBackend | UltraPlonkBackend ;
149+ const program = JSON . parse ( fs . readFileSync ( file , "utf-8" ) ) ;
124150 switch ( flavor ) {
125151 case "ultra_plonk" : {
126- writeVkCmd = "write_vk" ;
127- contractCmd = "contract" ;
152+ backend = new UltraPlonkBackend ( program . bytecode ) ;
128153 break ;
129154 }
130155 case "ultra_keccak_honk" : {
131- writeVkCmd = "write_vk_ultra_keccak_honk" ;
132- contractCmd = "contract_ultra_honk" ;
156+ backend = new UltraHonkBackend ( program . bytecode ) ;
133157 break ;
134158 }
135159 default : {
136160 flavor satisfies never ;
137- return ;
161+ throw new HardhatPluginError (
162+ PLUGIN_NAME ,
163+ `Unsupported Noir proof flavor: ${ flavor } ` ,
164+ ) ;
138165 }
139166 }
167+ let verifier = await backend . getSolidityVerifier ( ) ;
168+ if ( typeof verifier !== "string" ) {
169+ // bug in bb types
170+ verifier = new TextDecoder ( ) . decode ( verifier ) ;
171+ }
172+
173+ const name = path . basename ( file , ".json" ) ;
174+ console . log ( `Generating Solidity ${ flavor } verifier for ${ name } ...` ) ;
140175 const nameSuffix =
141176 flavor === ProofFlavor . ultra_keccak_honk ? "" : `_${ flavor } ` ;
142- await runCommand (
143- `${ bbBinary } ${ writeVkCmd } -b ${ targetDir } /${ name } .json -o ${ targetDir } /${ name } ${ nameSuffix } _vk` ,
144- ) ;
145- await runCommand (
146- `${ bbBinary } ${ contractCmd } -k ${ targetDir } /${ name } ${ nameSuffix } _vk -o ${ targetDir } /${ name } ${ nameSuffix } .sol` ,
147- ) ;
177+ fs . writeFileSync ( path . join ( targetDir , `${ name } ${ nameSuffix } .sol` ) , verifier ) ;
148178 console . log ( `Generated Solidity ${ flavor } verifier for ${ name } ` ) ;
149179}
150180
0 commit comments