@aztec-foundation/noir-noir_js 0.0.1-commit.b66364b

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.base64Decode = base64Decode;
4
+ // Since this is a simple function, we can use feature detection to
5
+ // see if we are in the nodeJs environment or the browser environment.
6
+ function base64Decode(input) {
7
+ if (typeof Buffer !== 'undefined') {
8
+ // Node.js environment
9
+ return Buffer.from(input, 'base64');
10
+ }
11
+ else if (typeof atob === 'function') {
12
+ // Browser environment
13
+ return Uint8Array.from(atob(input), (c) => c.charCodeAt(0));
14
+ }
15
+ else {
16
+ throw new Error('No implementation found for base64 decoding.');
17
+ }
18
+ }
@@ -0,0 +1 @@
1
+ export declare function base64Decode(input: string): Uint8Array;
@@ -0,0 +1,15 @@
1
+ // Since this is a simple function, we can use feature detection to
2
+ // see if we are in the nodeJs environment or the browser environment.
3
+ export function base64Decode(input) {
4
+ if (typeof Buffer !== 'undefined') {
5
+ // Node.js environment
6
+ return Buffer.from(input, 'base64');
7
+ }
8
+ else if (typeof atob === 'function') {
9
+ // Browser environment
10
+ return Uint8Array.from(atob(input), (c) => c.charCodeAt(0));
11
+ }
12
+ else {
13
+ throw new Error('No implementation found for base64 decoding.');
14
+ }
15
+ }
package/lib/debug.cjs ADDED
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseDebugSymbols = parseDebugSymbols;
4
+ exports.extractCallStack = extractCallStack;
5
+ const pako_1 = require("pako");
6
+ const base64_decode_1 = require("./base64_decode.cjs");
7
+ function parseDebugSymbols(debugSymbols) {
8
+ return JSON.parse((0, pako_1.inflate)((0, base64_decode_1.base64Decode)(debugSymbols), { toText: true, raw: true })).debug_infos;
9
+ }
10
+ /**
11
+ * Extracts the call stack from an thrown by the acvm.
12
+ * @param error - The error to extract from.
13
+ * @param debug - The debug metadata of the program called.
14
+ * @param files - The files used for compilation of the program.
15
+ * @returns The call stack, if available.
16
+ */
17
+ function extractCallStack(error, debug, files) {
18
+ if (!('callStack' in error) || !error.callStack) {
19
+ return undefined;
20
+ }
21
+ const { callStack, brilligFunctionId } = error;
22
+ if (!debug) {
23
+ return callStack;
24
+ }
25
+ try {
26
+ return resolveOpcodeLocations(callStack, debug, files, brilligFunctionId);
27
+ }
28
+ catch (_err) {
29
+ return callStack;
30
+ }
31
+ }
32
+ /**
33
+ * Resolves the source code locations from an array of opcode locations
34
+ */
35
+ function resolveOpcodeLocations(opcodeLocations, debug, files, brilligFunctionId) {
36
+ let locations = opcodeLocations.flatMap((opcodeLocation) => getSourceCodeLocationsFromOpcodeLocation(opcodeLocation, debug, files, brilligFunctionId));
37
+ // Adds the acir call stack if the last location is a brillig opcode
38
+ if (locations.length > 0) {
39
+ const decomposedOpcodeLocation = opcodeLocations[opcodeLocations.length - 1].split('.');
40
+ if (decomposedOpcodeLocation.length === 2) {
41
+ const acirCallstackId = debug.acir_locations[decomposedOpcodeLocation[0]];
42
+ if (acirCallstackId !== undefined) {
43
+ const callStack = debug.location_tree.locations[acirCallstackId];
44
+ const acirCallstack = getCallStackFromLocationNode(callStack, debug.location_tree.locations, files);
45
+ locations = acirCallstack.concat(locations);
46
+ }
47
+ }
48
+ }
49
+ return locations;
50
+ }
51
+ function getCallStackFromLocationNode(callStack, location_tree, files) {
52
+ const result = [];
53
+ while (callStack.parent !== null) {
54
+ const { file: fileId, span } = callStack.value;
55
+ const { path, source } = files[fileId];
56
+ const locationText = source.substring(span.start, span.end);
57
+ const precedingText = source.substring(0, span.start);
58
+ const previousLines = precedingText.split('\n');
59
+ // Lines and columns in stacks are one indexed.
60
+ const line = previousLines.length;
61
+ const column = previousLines[previousLines.length - 1].length + 1;
62
+ result.push({
63
+ filePath: path,
64
+ line,
65
+ column,
66
+ locationText,
67
+ });
68
+ callStack = location_tree[callStack.parent];
69
+ }
70
+ // Reverse since we explored the child nodes first
71
+ return result.reverse();
72
+ }
73
+ /**
74
+ * Extracts the call stack from the location of a failing opcode and the debug metadata.
75
+ * One opcode can point to multiple calls due to inlining.
76
+ */
77
+ function getSourceCodeLocationsFromOpcodeLocation(opcodeLocation, debug, files, brilligFunctionId) {
78
+ let callstack_id = debug.acir_locations[opcodeLocation];
79
+ const brilligLocation = extractBrilligLocation(opcodeLocation);
80
+ if (brilligFunctionId !== undefined && brilligLocation !== undefined) {
81
+ callstack_id = debug.brillig_locations[brilligFunctionId][brilligLocation];
82
+ if (callstack_id === undefined) {
83
+ return [];
84
+ }
85
+ }
86
+ if (callstack_id === undefined) {
87
+ return [];
88
+ }
89
+ const callStack = debug.location_tree.locations[callstack_id];
90
+ return getCallStackFromLocationNode(callStack, debug.location_tree.locations, files);
91
+ }
92
+ /**
93
+ * Extracts a brillig location from an opcode location.
94
+ */
95
+ function extractBrilligLocation(opcodeLocation) {
96
+ const splitted = opcodeLocation.split('.');
97
+ if (splitted.length === 2) {
98
+ return splitted[1];
99
+ }
100
+ return undefined;
101
+ }
package/lib/debug.d.ts ADDED
@@ -0,0 +1,37 @@
1
+ import { DebugFileMap, DebugInfo, OpcodeLocation } from '@aztec-foundation/noir-types';
2
+ import { ExecutionError } from '@aztec-foundation/noir-acvm_js';
3
+ /**
4
+ * A stack of calls, resolved or not
5
+ */
6
+ type CallStack = SourceCodeLocation[] | OpcodeLocation[];
7
+ /**
8
+ * A resolved pointer to a failing section of the noir source code.
9
+ */
10
+ interface SourceCodeLocation {
11
+ /**
12
+ * The path to the source file.
13
+ */
14
+ filePath: string;
15
+ /**
16
+ * The line number of the location.
17
+ */
18
+ line: number;
19
+ /**
20
+ * The column number of the location.
21
+ */
22
+ column: number;
23
+ /**
24
+ * The source code text of the location.
25
+ */
26
+ locationText: string;
27
+ }
28
+ export declare function parseDebugSymbols(debugSymbols: string): DebugInfo[];
29
+ /**
30
+ * Extracts the call stack from an thrown by the acvm.
31
+ * @param error - The error to extract from.
32
+ * @param debug - The debug metadata of the program called.
33
+ * @param files - The files used for compilation of the program.
34
+ * @returns The call stack, if available.
35
+ */
36
+ export declare function extractCallStack(error: ExecutionError, debug: DebugInfo, files: DebugFileMap): CallStack | undefined;
37
+ export {};
package/lib/debug.mjs ADDED
@@ -0,0 +1,97 @@
1
+ import { inflate } from 'pako';
2
+ import { base64Decode } from "./base64_decode.mjs";
3
+ export function parseDebugSymbols(debugSymbols) {
4
+ return JSON.parse(inflate(base64Decode(debugSymbols), { toText: true, raw: true })).debug_infos;
5
+ }
6
+ /**
7
+ * Extracts the call stack from an thrown by the acvm.
8
+ * @param error - The error to extract from.
9
+ * @param debug - The debug metadata of the program called.
10
+ * @param files - The files used for compilation of the program.
11
+ * @returns The call stack, if available.
12
+ */
13
+ export function extractCallStack(error, debug, files) {
14
+ if (!('callStack' in error) || !error.callStack) {
15
+ return undefined;
16
+ }
17
+ const { callStack, brilligFunctionId } = error;
18
+ if (!debug) {
19
+ return callStack;
20
+ }
21
+ try {
22
+ return resolveOpcodeLocations(callStack, debug, files, brilligFunctionId);
23
+ }
24
+ catch (_err) {
25
+ return callStack;
26
+ }
27
+ }
28
+ /**
29
+ * Resolves the source code locations from an array of opcode locations
30
+ */
31
+ function resolveOpcodeLocations(opcodeLocations, debug, files, brilligFunctionId) {
32
+ let locations = opcodeLocations.flatMap((opcodeLocation) => getSourceCodeLocationsFromOpcodeLocation(opcodeLocation, debug, files, brilligFunctionId));
33
+ // Adds the acir call stack if the last location is a brillig opcode
34
+ if (locations.length > 0) {
35
+ const decomposedOpcodeLocation = opcodeLocations[opcodeLocations.length - 1].split('.');
36
+ if (decomposedOpcodeLocation.length === 2) {
37
+ const acirCallstackId = debug.acir_locations[decomposedOpcodeLocation[0]];
38
+ if (acirCallstackId !== undefined) {
39
+ const callStack = debug.location_tree.locations[acirCallstackId];
40
+ const acirCallstack = getCallStackFromLocationNode(callStack, debug.location_tree.locations, files);
41
+ locations = acirCallstack.concat(locations);
42
+ }
43
+ }
44
+ }
45
+ return locations;
46
+ }
47
+ function getCallStackFromLocationNode(callStack, location_tree, files) {
48
+ const result = [];
49
+ while (callStack.parent !== null) {
50
+ const { file: fileId, span } = callStack.value;
51
+ const { path, source } = files[fileId];
52
+ const locationText = source.substring(span.start, span.end);
53
+ const precedingText = source.substring(0, span.start);
54
+ const previousLines = precedingText.split('\n');
55
+ // Lines and columns in stacks are one indexed.
56
+ const line = previousLines.length;
57
+ const column = previousLines[previousLines.length - 1].length + 1;
58
+ result.push({
59
+ filePath: path,
60
+ line,
61
+ column,
62
+ locationText,
63
+ });
64
+ callStack = location_tree[callStack.parent];
65
+ }
66
+ // Reverse since we explored the child nodes first
67
+ return result.reverse();
68
+ }
69
+ /**
70
+ * Extracts the call stack from the location of a failing opcode and the debug metadata.
71
+ * One opcode can point to multiple calls due to inlining.
72
+ */
73
+ function getSourceCodeLocationsFromOpcodeLocation(opcodeLocation, debug, files, brilligFunctionId) {
74
+ let callstack_id = debug.acir_locations[opcodeLocation];
75
+ const brilligLocation = extractBrilligLocation(opcodeLocation);
76
+ if (brilligFunctionId !== undefined && brilligLocation !== undefined) {
77
+ callstack_id = debug.brillig_locations[brilligFunctionId][brilligLocation];
78
+ if (callstack_id === undefined) {
79
+ return [];
80
+ }
81
+ }
82
+ if (callstack_id === undefined) {
83
+ return [];
84
+ }
85
+ const callStack = debug.location_tree.locations[callstack_id];
86
+ return getCallStackFromLocationNode(callStack, debug.location_tree.locations, files);
87
+ }
88
+ /**
89
+ * Extracts a brillig location from an opcode location.
90
+ */
91
+ function extractBrilligLocation(opcodeLocation) {
92
+ const splitted = opcodeLocation.split('.');
93
+ if (splitted.length === 2) {
94
+ return splitted[1];
95
+ }
96
+ return undefined;
97
+ }
package/lib/index.cjs ADDED
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.abi = exports.acvm = exports.Noir = exports.and = exports.xor = exports.blake2s256 = exports.ecdsa_secp256k1_verify = exports.ecdsa_secp256r1_verify = void 0;
37
+ const acvm = __importStar(require("@aztec-foundation/noir-acvm_js"));
38
+ exports.acvm = acvm;
39
+ const abi = __importStar(require("@aztec-foundation/noir-noirc_abi"));
40
+ exports.abi = abi;
41
+ var acvm_js_1 = require("@aztec-foundation/noir-acvm_js");
42
+ Object.defineProperty(exports, "ecdsa_secp256r1_verify", { enumerable: true, get: function () { return acvm_js_1.ecdsa_secp256r1_verify; } });
43
+ Object.defineProperty(exports, "ecdsa_secp256k1_verify", { enumerable: true, get: function () { return acvm_js_1.ecdsa_secp256k1_verify; } });
44
+ Object.defineProperty(exports, "blake2s256", { enumerable: true, get: function () { return acvm_js_1.blake2s256; } });
45
+ Object.defineProperty(exports, "xor", { enumerable: true, get: function () { return acvm_js_1.xor; } });
46
+ Object.defineProperty(exports, "and", { enumerable: true, get: function () { return acvm_js_1.and; } });
47
+ var program_js_1 = require("./program.cjs");
48
+ Object.defineProperty(exports, "Noir", { enumerable: true, get: function () { return program_js_1.Noir; } });
package/lib/index.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ import * as acvm from '@aztec-foundation/noir-acvm_js';
2
+ import * as abi from '@aztec-foundation/noir-noirc_abi';
3
+ import { CompiledCircuit } from '@aztec-foundation/noir-types';
4
+ export { ecdsa_secp256r1_verify, ecdsa_secp256k1_verify, blake2s256, xor, and } from '@aztec-foundation/noir-acvm_js';
5
+ export { InputMap } from '@aztec-foundation/noir-noirc_abi';
6
+ export { WitnessMap, ForeignCallHandler, ForeignCallInput, ForeignCallOutput } from '@aztec-foundation/noir-acvm_js';
7
+ export { Noir } from './program.js';
8
+ export { ErrorWithPayload } from './witness_generation.js';
9
+ /** @ignore */
10
+ export { acvm, abi };
11
+ export { CompiledCircuit };
package/lib/index.mjs ADDED
@@ -0,0 +1,6 @@
1
+ import * as acvm from '@aztec-foundation/noir-acvm_js';
2
+ import * as abi from '@aztec-foundation/noir-noirc_abi';
3
+ export { ecdsa_secp256r1_verify, ecdsa_secp256k1_verify, blake2s256, xor, and } from '@aztec-foundation/noir-acvm_js';
4
+ export { Noir } from "./program.mjs";
5
+ /** @ignore */
6
+ export { acvm, abi };
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.Noir = void 0;
37
+ const witness_generation_js_1 = require("./witness_generation.cjs");
38
+ const noirc_abi_1 = __importStar(require("@aztec-foundation/noir-noirc_abi"));
39
+ const acvm_js_1 = __importStar(require("@aztec-foundation/noir-acvm_js"));
40
+ class Noir {
41
+ circuit;
42
+ constructor(circuit) {
43
+ this.circuit = circuit;
44
+ }
45
+ /** @ignore */
46
+ async init() {
47
+ // If these are available, then we are in the
48
+ // web environment. For the node environment, this
49
+ // is a no-op.
50
+ if (typeof noirc_abi_1.default === 'function') {
51
+ await Promise.all([(0, noirc_abi_1.default)(), (0, acvm_js_1.default)()]);
52
+ }
53
+ }
54
+ /**
55
+ * @description
56
+ * Allows to execute a circuit to get its witness and return value.
57
+ *
58
+ * @example
59
+ * ```typescript
60
+ * async execute(inputs)
61
+ * ```
62
+ */
63
+ async execute(inputs, foreignCallHandler) {
64
+ await this.init();
65
+ const witness_stack = await (0, witness_generation_js_1.generateWitness)(this.circuit, inputs, foreignCallHandler);
66
+ const main_witness = witness_stack[0].witness;
67
+ const { return_value: returnValue } = (0, noirc_abi_1.abiDecode)(this.circuit.abi, main_witness);
68
+ return { witness: (0, acvm_js_1.compressWitnessStack)(witness_stack), returnValue };
69
+ }
70
+ }
71
+ exports.Noir = Noir;
@@ -0,0 +1,22 @@
1
+ import { CompiledCircuit } from '@aztec-foundation/noir-types';
2
+ import { InputMap, InputValue } from '@aztec-foundation/noir-noirc_abi';
3
+ import { ForeignCallHandler } from '@aztec-foundation/noir-acvm_js';
4
+ export declare class Noir {
5
+ private circuit;
6
+ constructor(circuit: CompiledCircuit);
7
+ /** @ignore */
8
+ init(): Promise<void>;
9
+ /**
10
+ * @description
11
+ * Allows to execute a circuit to get its witness and return value.
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * async execute(inputs)
16
+ * ```
17
+ */
18
+ execute(inputs: InputMap, foreignCallHandler?: ForeignCallHandler): Promise<{
19
+ witness: Uint8Array;
20
+ returnValue: InputValue;
21
+ }>;
22
+ }
@@ -0,0 +1,34 @@
1
+ import { generateWitness } from "./witness_generation.mjs";
2
+ import initAbi, { abiDecode } from '@aztec-foundation/noir-noirc_abi';
3
+ import initACVM, { compressWitnessStack } from '@aztec-foundation/noir-acvm_js';
4
+ export class Noir {
5
+ circuit;
6
+ constructor(circuit) {
7
+ this.circuit = circuit;
8
+ }
9
+ /** @ignore */
10
+ async init() {
11
+ // If these are available, then we are in the
12
+ // web environment. For the node environment, this
13
+ // is a no-op.
14
+ if (typeof initAbi === 'function') {
15
+ await Promise.all([initAbi(), initACVM()]);
16
+ }
17
+ }
18
+ /**
19
+ * @description
20
+ * Allows to execute a circuit to get its witness and return value.
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * async execute(inputs)
25
+ * ```
26
+ */
27
+ async execute(inputs, foreignCallHandler) {
28
+ await this.init();
29
+ const witness_stack = await generateWitness(this.circuit, inputs, foreignCallHandler);
30
+ const main_witness = witness_stack[0].witness;
31
+ const { return_value: returnValue } = abiDecode(this.circuit.abi, main_witness);
32
+ return { witness: compressWitnessStack(witness_stack), returnValue };
33
+ }
34
+ }
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateWitness = generateWitness;
4
+ const noirc_abi_1 = require("@aztec-foundation/noir-noirc_abi");
5
+ const base64_decode_js_1 = require("./base64_decode.cjs");
6
+ const acvm_js_1 = require("@aztec-foundation/noir-acvm_js");
7
+ const debug_js_1 = require("./debug.cjs");
8
+ const defaultForeignCallHandler = async (name, args) => {
9
+ if (name == 'print') {
10
+ // By default we do not print anything for `print` foreign calls due to a need for formatting,
11
+ // however we provide an empty response in order to not halt execution.
12
+ //
13
+ // If a user needs to print values then they should provide a custom foreign call handler.
14
+ return [];
15
+ }
16
+ throw Error(`Unexpected oracle during execution: ${name}(${args.join(', ')})`);
17
+ };
18
+ function enrichExecutionError(artifact, originalError) {
19
+ const enrichedError = originalError;
20
+ if (originalError.rawAssertionPayload) {
21
+ try {
22
+ // Decode the payload
23
+ const decodedPayload = (0, noirc_abi_1.abiDecodeError)(artifact.abi, originalError.rawAssertionPayload);
24
+ if (typeof decodedPayload === 'string') {
25
+ // If it's a string, just add it to the error message
26
+ enrichedError.message = `Circuit execution failed: ${decodedPayload}`;
27
+ }
28
+ else {
29
+ // If not, attach the payload to the original error
30
+ enrichedError.decodedAssertionPayload = decodedPayload;
31
+ }
32
+ }
33
+ catch (_errorDecoding) {
34
+ // Ignore errors decoding the payload
35
+ }
36
+ }
37
+ try {
38
+ // Decode the callstack
39
+ const callStack = (0, debug_js_1.extractCallStack)(originalError, (0, debug_js_1.parseDebugSymbols)(artifact.debug_symbols)[originalError.acirFunctionId], artifact.file_map);
40
+ enrichedError.noirCallStack = callStack?.map((errorLocation) => {
41
+ if (typeof errorLocation === 'string') {
42
+ return `at opcode ${errorLocation}`;
43
+ }
44
+ else {
45
+ return `at ${errorLocation.locationText} (${errorLocation.filePath}:${errorLocation.line}:${errorLocation.column})`;
46
+ }
47
+ });
48
+ }
49
+ catch (_errorResolving) {
50
+ // Ignore errors resolving the callstack
51
+ }
52
+ return enrichedError;
53
+ }
54
+ // Generates the witnesses needed to feed into the chosen proving system
55
+ async function generateWitness(compiledProgram, inputs, foreignCallHandler = defaultForeignCallHandler) {
56
+ // Throws on ABI encoding error
57
+ const witnessMap = (0, noirc_abi_1.abiEncode)(compiledProgram.abi, inputs);
58
+ // Execute the circuit to generate the rest of the witnesses and serialize
59
+ // them into a Uint8Array.
60
+ try {
61
+ const solvedWitness = await (0, acvm_js_1.executeProgram)((0, base64_decode_js_1.base64Decode)(compiledProgram.bytecode), witnessMap, foreignCallHandler);
62
+ return solvedWitness;
63
+ }
64
+ catch (err) {
65
+ // Typescript types caught errors as unknown or any, so we need to narrow its type to check if it has raw assertion payload.
66
+ if (typeof err === 'object' && err !== null && 'rawAssertionPayload' in err) {
67
+ throw enrichExecutionError(compiledProgram, err);
68
+ }
69
+ throw new Error(`Circuit execution failed: ${err}`, { cause: err });
70
+ }
71
+ }
@@ -0,0 +1,8 @@
1
+ import { InputMap } from '@aztec-foundation/noir-noirc_abi';
2
+ import { WitnessStack, ForeignCallHandler, ExecutionError } from '@aztec-foundation/noir-acvm_js';
3
+ import { CompiledCircuit } from '@aztec-foundation/noir-types';
4
+ export type ErrorWithPayload = ExecutionError & {
5
+ decodedAssertionPayload?: any;
6
+ noirCallStack?: string[];
7
+ };
8
+ export declare function generateWitness(compiledProgram: CompiledCircuit, inputs: InputMap, foreignCallHandler?: ForeignCallHandler): Promise<WitnessStack>;
@@ -0,0 +1,68 @@
1
+ import { abiDecodeError, abiEncode } from '@aztec-foundation/noir-noirc_abi';
2
+ import { base64Decode } from "./base64_decode.mjs";
3
+ import { executeProgram } from '@aztec-foundation/noir-acvm_js';
4
+ import { extractCallStack, parseDebugSymbols } from "./debug.mjs";
5
+ const defaultForeignCallHandler = async (name, args) => {
6
+ if (name == 'print') {
7
+ // By default we do not print anything for `print` foreign calls due to a need for formatting,
8
+ // however we provide an empty response in order to not halt execution.
9
+ //
10
+ // If a user needs to print values then they should provide a custom foreign call handler.
11
+ return [];
12
+ }
13
+ throw Error(`Unexpected oracle during execution: ${name}(${args.join(', ')})`);
14
+ };
15
+ function enrichExecutionError(artifact, originalError) {
16
+ const enrichedError = originalError;
17
+ if (originalError.rawAssertionPayload) {
18
+ try {
19
+ // Decode the payload
20
+ const decodedPayload = abiDecodeError(artifact.abi, originalError.rawAssertionPayload);
21
+ if (typeof decodedPayload === 'string') {
22
+ // If it's a string, just add it to the error message
23
+ enrichedError.message = `Circuit execution failed: ${decodedPayload}`;
24
+ }
25
+ else {
26
+ // If not, attach the payload to the original error
27
+ enrichedError.decodedAssertionPayload = decodedPayload;
28
+ }
29
+ }
30
+ catch (_errorDecoding) {
31
+ // Ignore errors decoding the payload
32
+ }
33
+ }
34
+ try {
35
+ // Decode the callstack
36
+ const callStack = extractCallStack(originalError, parseDebugSymbols(artifact.debug_symbols)[originalError.acirFunctionId], artifact.file_map);
37
+ enrichedError.noirCallStack = callStack?.map((errorLocation) => {
38
+ if (typeof errorLocation === 'string') {
39
+ return `at opcode ${errorLocation}`;
40
+ }
41
+ else {
42
+ return `at ${errorLocation.locationText} (${errorLocation.filePath}:${errorLocation.line}:${errorLocation.column})`;
43
+ }
44
+ });
45
+ }
46
+ catch (_errorResolving) {
47
+ // Ignore errors resolving the callstack
48
+ }
49
+ return enrichedError;
50
+ }
51
+ // Generates the witnesses needed to feed into the chosen proving system
52
+ export async function generateWitness(compiledProgram, inputs, foreignCallHandler = defaultForeignCallHandler) {
53
+ // Throws on ABI encoding error
54
+ const witnessMap = abiEncode(compiledProgram.abi, inputs);
55
+ // Execute the circuit to generate the rest of the witnesses and serialize
56
+ // them into a Uint8Array.
57
+ try {
58
+ const solvedWitness = await executeProgram(base64Decode(compiledProgram.bytecode), witnessMap, foreignCallHandler);
59
+ return solvedWitness;
60
+ }
61
+ catch (err) {
62
+ // Typescript types caught errors as unknown or any, so we need to narrow its type to check if it has raw assertion payload.
63
+ if (typeof err === 'object' && err !== null && 'rawAssertionPayload' in err) {
64
+ throw enrichExecutionError(compiledProgram, err);
65
+ }
66
+ throw new Error(`Circuit execution failed: ${err}`, { cause: err });
67
+ }
68
+ }
package/package.json ADDED
@@ -0,0 +1,67 @@
1
+ {
2
+ "name": "@aztec-foundation/noir-noir_js",
3
+ "contributors": [
4
+ "The Noir Team <team@noir-lang.org>"
5
+ ],
6
+ "version": "0.0.1-commit.b66364b",
7
+ "packageManager": "yarn@4.5.2",
8
+ "license": "(MIT OR Apache-2.0)",
9
+ "type": "module",
10
+ "homepage": "https://noir-lang.org/",
11
+ "repository": {
12
+ "url": "https://github.com/noir-lang/noir.git",
13
+ "directory": "tooling/noir_js",
14
+ "type": "git"
15
+ },
16
+ "bugs": {
17
+ "url": "https://github.com/noir-lang/noir/issues"
18
+ },
19
+ "dependencies": {
20
+ "@aztec-foundation/noir-acvm_js": "0.0.1-commit.b66364b",
21
+ "@aztec-foundation/noir-noirc_abi": "0.0.1-commit.b66364b",
22
+ "@aztec-foundation/noir-types": "0.0.1-commit.b66364b",
23
+ "pako": "^3.0.1"
24
+ },
25
+ "files": [
26
+ "lib",
27
+ "package.json"
28
+ ],
29
+ "source": "src/index.ts",
30
+ "main": "lib/index.cjs",
31
+ "module": "lib/index.mjs",
32
+ "exports": {
33
+ "require": "./lib/index.cjs",
34
+ "types": "./lib/index.d.ts",
35
+ "default": "./lib/index.mjs"
36
+ },
37
+ "types": "lib/index.d.ts",
38
+ "scripts": {
39
+ "dev": "tsc-multi --watch",
40
+ "build": "tsc-multi",
41
+ "test": "yarn test:compile_program && yarn test:node:esm && yarn test:node:cjs",
42
+ "test:compile_program": "./scripts/compile_test_programs.sh",
43
+ "test:node:esm": "mocha --timeout 25000 --exit --config ./.mocharc.json",
44
+ "test:node:cjs": "mocha --timeout 25000 --exit --config ./.mocharc.cjs.json",
45
+ "prettier": "prettier 'src/**/*.ts'",
46
+ "prettier:fix": "prettier --write 'src/**/*.ts' 'test/**/*.ts'",
47
+ "lint": "NODE_NO_WARNINGS=1 eslint . --max-warnings 0",
48
+ "nightly:version": "jq --arg new_version \"-$(git rev-parse --short HEAD)$1\" '.version = .version + $new_version' package.json > package-tmp.json && mv package-tmp.json package.json",
49
+ "publish": "echo 📡 publishing `$npm_package_name` && yarn npm publish",
50
+ "clean": "rm -rf ./lib"
51
+ },
52
+ "devDependencies": {
53
+ "@types/chai": "^5",
54
+ "@types/mocha": "^10.0.10",
55
+ "@types/node": "^22.20.1",
56
+ "@types/pako": "^2",
57
+ "@types/prettier": "^3.0.0",
58
+ "chai": "^6.2.2",
59
+ "eslint": "^10.7.0",
60
+ "eslint-plugin-prettier": "^5.5.6",
61
+ "mocha": "^11.7.6",
62
+ "prettier": "3.9.5",
63
+ "tsc-multi": "^1.1.0",
64
+ "tsx": "^4.23.1",
65
+ "typescript": "^6.0.3"
66
+ }
67
+ }