Skip to content

Commit 35f2a17

Browse files
committed
vk generation
1 parent e3560af commit 35f2a17

File tree

8 files changed

+5139
-5504
lines changed

8 files changed

+5139
-5504
lines changed

.pnp.cjs

Lines changed: 2583 additions & 2838 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ethereum/oracles/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
},
2424
"license": "MIT",
2525
"dependencies": {
26+
"@aztec/bb.js": "3.0.0-nightly.20260102",
2627
"@ethereumjs/trie": "^6.2.0",
2728
"@iarna/toml": "^2.2.5",
2829
"@noir-lang/noir_js": "1.0.0-beta.18",

ethereum/oracles/src/noir/circuit/README.md

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,24 +19,28 @@ Unfortunately `nargo` does not generate any of the recursion artifacts. Noir tea
1919
- Compiled artifact - `target/${name}.json`
2020
- generated from code using `nargo compile --package ${name}`
2121
- It's a JSON that contains [`base64`](https://en.wikipedia.org/wiki/Base64) encoded bytecode under the `.bytecode` key
22-
- Acir bytecode
23-
- generated from **compiled artifact** by taking the bytecode and decoding it as `base64`, as **bb** expects it in plain binary form. We use a temp file for it as it's fast to generate and we only use it during **VK** generation
22+
- The bytecode is gzip-compressed before base64 encoding
23+
- Circuit artifact for bb
24+
- the **compiled artifact** is written as-is (as JSON) to a temp file
25+
- **bb** expects circuit JSON format (not raw bytecode) when the file has a `.json` extension
26+
- **bb** handles decompression of the gzipped bytecode field internally
2427
- VK - `target/${name}.vk.bin`
2528
- verification key is generated from **acir bytecode** by running:
2629
- `./bb write_vk -b ${acirPath} -o ${vkPath}`
2730
- We cache it in a file as it's slow to generate
2831
- VK.json - `target/${name}.vk.json`
29-
- generated from VK by running:
30-
- `./bb vk_as_fields -k ${vkPath} -o ${vkJsonPath}`
32+
- generated from VK binary files using the official @aztec/bb.js API
33+
- the `vk_as_fields` CLI command was removed in newer bb versions (moved to msgpack API)
34+
- we use `Barretenberg.vkAsFields()` from @aztec/bb.js to convert VK to field elements
3135
- JSON array that contains `vkHash` as the first element and `vkAsFields` after it
3236

3337
## Usage
3438

3539
```TS
3640
// Read circuit compilation artifact
3741
const circuit = await MonorepoCircuit.create('../../', 'get_header');
38-
// Generate VK - slow.
39-
await generateVk(circuit);
42+
// Generate VK - slow. Pass the full artifact, not just bytecode.
43+
await generateVk(circuit.artefact, circuit.vkPath(), circuit.vkAsFieldsPath());
4044
// Read generated VK
41-
const vk = await VerificationKey.create(circuit);
45+
const vk = await VerificationKey.create(circuit.vkAsFieldsPath());
4246
```

ethereum/oracles/src/noir/circuit/barretenberg.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@ export class Barretenberg {
1111
public async writeVK(acirPath: string, vkPath: string) {
1212
await $`${this.binaryPath} write_vk -b ${acirPath} -o ${vkPath}`;
1313
}
14-
public async vkAsFields(vkPath: string, vkAsFieldsPath: string) {
15-
await $`${this.binaryPath} vk_as_fields -k ${vkPath} -o ${vkAsFieldsPath}`;
16-
}
14+
15+
// Note: vk_as_fields CLI command was removed in newer bb versions
16+
// VK conversion to fields is now handled in TypeScript (see vk.ts)
17+
1718
public async proofAsFields(vkPath: string, proofWithInputsPath: string, proofAsFieldsPath: string) {
1819
await $`${this.binaryPath} proof_as_fields -k ${vkPath} -p ${proofWithInputsPath} -o ${proofAsFieldsPath}`;
1920
}

ethereum/oracles/src/noir/circuit/vk.ts

Lines changed: 67 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,76 @@
1-
import { readObject, withTempFile } from '../../util/file.js';
2-
import { writeFile } from 'fs/promises';
1+
import { readObject, withTempFile, writeObject } from '../../util/file.js';
2+
import { writeFile, readFile } from 'fs/promises';
33
import { Barretenberg } from './barretenberg.js';
4+
import { Barretenberg as BarretenbergAPI } from '@aztec/bb.js';
5+
import { CompiledCircuit } from '@noir-lang/noir_js';
6+
import path from 'path';
47

5-
export async function generateVk(bytecode: string, vkPath: string, vkAsFieldsPath: string): Promise<void> {
8+
/**
9+
* Converts binary VK files to field representation for recursive verification.
10+
* Uses the official @aztec/bb.js API to convert verification keys to field elements.
11+
*/
12+
async function convertVkBinaryToFields(vkDirPath: string, vkAsFieldsPath: string): Promise<void> {
13+
const vkPath = path.join(vkDirPath, 'vk');
14+
const vkHashPath = path.join(vkDirPath, 'vk_hash');
15+
16+
// Read binary files
17+
const vkBinary = await readFile(vkPath);
18+
const vkHashBinary = await readFile(vkHashPath);
19+
20+
// Use official bb.js API to convert VK to fields
21+
const api = await BarretenbergAPI.new({ threads: 1 });
22+
try {
23+
const result = await api.vkAsFields({ verificationKey: vkBinary });
24+
25+
// Convert Fr objects (Uint8Array) to hex strings
26+
const vkAsFields = result.fields.map((field) => '0x' + Buffer.from(field).toString('hex'));
27+
28+
// Convert hash to hex string
29+
const vkHash = '0x' + vkHashBinary.toString('hex');
30+
31+
// Write as JSON: [vkHash, ...vkAsFields]
32+
await writeObject([vkHash, ...vkAsFields], vkAsFieldsPath);
33+
} finally {
34+
await api.destroy();
35+
}
36+
}
37+
38+
export async function generateVk(bytecode: string, vkPath: string, vkAsFieldsPath: string): Promise<void>;
39+
export async function generateVk(artifact: CompiledCircuit, vkPath: string, vkAsFieldsPath: string): Promise<void>;
40+
export async function generateVk(
41+
bytecodeOrArtifact: string | CompiledCircuit,
42+
vkPath: string,
43+
vkAsFieldsPath: string
44+
): Promise<void> {
645
return await withTempFile(async (acirPath) => {
7-
await writeFile(acirPath, Buffer.from(bytecode, 'base64'));
46+
let artifact: CompiledCircuit;
47+
48+
if (typeof bytecodeOrArtifact === 'string') {
49+
// Legacy: just bytecode string - create minimal artifact
50+
// bb expects circuit JSON (not raw bytecode) when file has .json extension
51+
artifact = {
52+
noir_version: '1.0.0',
53+
hash: 0,
54+
abi: { parameters: [], return_type: null, error_types: {} },
55+
bytecode: bytecodeOrArtifact, // Keep compressed - bb handles decompression
56+
} as any;
57+
} else {
58+
// New: full artifact - use as-is
59+
// bb expects bytecode to remain compressed (gzipped + base64)
60+
artifact = bytecodeOrArtifact;
61+
}
62+
63+
// Write circuit JSON to temp file
64+
// bb reads .json files as JSON format and decompresses bytecode internally
65+
await writeFile(acirPath, JSON.stringify(artifact));
866

967
const barretenberg = await Barretenberg.create();
68+
// write_vk creates a directory with 'vk' and 'vk_hash' files
1069
await barretenberg.writeVK(acirPath, vkPath);
11-
await barretenberg.vkAsFields(vkPath, vkAsFieldsPath);
70+
71+
// Convert binary VK files to field representation
72+
// vk_as_fields CLI command was removed in newer bb, so we do it in TypeScript
73+
await convertVkBinaryToFields(vkPath, vkAsFieldsPath);
1274
});
1375
}
1476

ethereum/oracles/src/script/generateGetStorageVK.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { MonorepoCircuit } from '../noir/circuit/circuit.js';
22
import { VerificationKey, generateVk } from '../noir/circuit/vk.js';
33

44
const circuit = await MonorepoCircuit.create('../../', 'get_storage_recursive');
5-
await generateVk(circuit.artefact.bytecode, circuit.vkPath(), circuit.vkAsFieldsPath());
5+
await generateVk(circuit.artefact, circuit.vkPath(), circuit.vkAsFieldsPath());
66
const vk = await VerificationKey.create(circuit.vkAsFieldsPath());
77
// eslint-disable-next-line no-console
88
console.log(vk);

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,8 @@
2828
},
2929
"dependencies": {
3030
"@changesets/cli": "^2.27.2"
31+
},
32+
"resolutions": {
33+
"@noir-lang/noirc_abi": "1.0.0-beta.18"
3134
}
3235
}

0 commit comments

Comments
 (0)