Skip to content

Commit facb107

Browse files
authored
Merge pull request #2632 from o1-labs/querolita/napi-proof
[WIP] (`o1js`) Native Prover with Napi - Proof
2 parents 188aa22 + 1793999 commit facb107

15 files changed

+1124
-86
lines changed

src/bindings/crypto/bindings.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* It is exposed to JSOO by populating a global variable with an object.
44
* It gets imported as the first thing in ../../bindings.js so that the global variable is ready by the time JSOO code gets executed.
55
*/
6+
import type * as napiNamespace from '../compiled/node_bindings/plonk_wasm.cjs';
67
import type * as wasmNamespace from '../compiled/node_bindings/plonk_wasm.cjs';
78
import { prefixHashes, prefixHashesLegacy } from '../crypto/constants.js';
89
import { Bigint256Bindings } from './bindings/bigint256.js';
@@ -14,12 +15,15 @@ import { verifierIndexConversion } from './bindings/conversion-verifier-index.js
1415
import { PallasBindings, VestaBindings } from './bindings/curve.js';
1516
import { jsEnvironment } from './bindings/env.js';
1617
import { FpBindings, FqBindings } from './bindings/field.js';
17-
import { srs } from './bindings/srs.js';
1818
import { FpVectorBindings, FqVectorBindings } from './bindings/vector.js';
19+
import { srs } from './bindings/srs.js';
20+
import { srs as napiSrs } from './napi-srs.js';
1921
import { napiConversionCore } from './napi-conversion-core.js';
2022
import { napiProofConversion } from './napi-conversion-proof.js';
23+
import { napiVerifierIndexConversion } from './napi-conversion-verifier-index.js';
24+
import { napiOraclesConversion } from './bindings/napi-conversion-oracles.js';
2125

22-
export { RustConversion, Wasm, createNativeRustConversion, getRustConversion };
26+
export { Napi, RustConversion, Wasm, createNativeRustConversion, getRustConversion };
2327

2428
/* TODO: Uncomment in phase 2 of conversion layer
2529
import { conversionCore as conversionCoreNative } from './native/conversion-core.js';
@@ -49,13 +53,14 @@ const tsBindings = {
4953
return bundle.srsFactory(wasm, bundle.conversion);
5054
},*/
5155
srs: (wasm: Wasm) => srs(wasm, getRustConversion(wasm)),
52-
srsNative: (napi: Wasm) => srs(napi, createNativeRustConversion(napi) as any),
56+
srsNative: (napi: Napi) => napiSrs(napi, createNativeRustConversion(napi) as any),
5357
};
5458

5559
// this is put in a global variable so that mina/src/lib/crypto/kimchi_bindings/js/bindings.js finds it
5660
(globalThis as any).__snarkyTsBindings = tsBindings;
5761

5862
type Wasm = typeof wasmNamespace;
63+
type Napi = typeof napiNamespace;
5964

6065
type RustConversion = ReturnType<typeof buildWasmConversion>;
6166

@@ -86,9 +91,11 @@ function buildWasmConversion(wasm: Wasm) {
8691
function createNativeRustConversion(napi: any) {
8792
let core = napiConversionCore(napi);
8893
let proof = napiProofConversion(napi, core);
94+
let verif = napiVerifierIndexConversion(napi, core);
95+
let oracles = napiOraclesConversion(napi);
8996
return {
90-
fp: { ...core.fp, ...proof.fp },
91-
fq: { ...core.fq, ...proof.fq },
97+
fp: { ...core.fp, ...proof.fp, ...verif.fp, ...oracles.fp },
98+
fq: { ...core.fq, ...proof.fq, ...verif.fq, ...oracles.fq },
9299
};
93100
}
94101

src/bindings/crypto/bindings/conversion-base.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
1-
import { Field } from './field.js';
2-
import { bigintToBytes32, bytesToBigint32 } from '../bigint-helpers.js';
1+
import type { MlArray } from '../../../lib/ml/base.js';
32
import type {
43
WasmGPallas,
54
WasmGVesta,
65
WasmPallasGProjective,
76
WasmVestaGProjective,
87
} from '../../compiled/node_bindings/plonk_wasm.cjs';
9-
import type { MlArray } from '../../../lib/ml/base.js';
10-
import { OrInfinity, Infinity } from './curve.js';
8+
import { bigintToBytes32, bytesToBigint32 } from '../bigint-helpers.js';
9+
import { Infinity, OrInfinity } from './curve.js';
10+
import { Field } from './field.js';
1111

1212
export {
13-
fieldToRust,
13+
WasmAffine,
14+
WasmProjective,
15+
affineFromRust,
16+
affineToRust,
1417
fieldFromRust,
15-
fieldsToRustFlat,
18+
fieldToRust,
1619
fieldsFromRustFlat,
20+
fieldsToRustFlat,
1721
maybeFieldToRust,
18-
affineToRust,
19-
affineFromRust,
20-
WasmAffine,
21-
WasmProjective,
2222
};
2323

2424
// TODO: Hardcoding this is a little brittle

src/bindings/crypto/bindings/conversion-core.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,9 @@ function conversionCorePerField(
116116
return new PolyComm(rustUnshifted, rustShifted);
117117
},
118118
polyCommFromRust(polyComm: WasmPolyComm): PolyComm {
119-
console.log('polyComm', polyComm);
119+
console.log('polyComm old', polyComm);
120120
let rustUnshifted = polyComm.unshifted;
121-
console.log('polyCommFromRust', rustUnshifted);
121+
console.log('rustUnshifted', rustUnshifted);
122122
let mlUnshifted = mapFromUintArray(rustUnshifted, (ptr) => {
123123
return affineFromRust(wrap(ptr, CommitmentCurve));
124124
});

src/bindings/crypto/bindings/conversion-proof.ts

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,46 @@
1+
import { MlArray, MlOption, MlTuple } from '../../../lib/ml/base.js';
2+
import type * as wasmNamespace from '../../compiled/node_bindings/plonk_wasm.cjs';
13
import type {
24
WasmFpLookupCommitments,
3-
WasmPastaFpLookupTable,
45
WasmFpOpeningProof,
56
WasmFpProverCommitments,
67
WasmFpProverProof,
78
WasmFpRuntimeTable,
8-
WasmPastaFpRuntimeTableCfg,
99
WasmFqLookupCommitments,
1010
WasmFqOpeningProof,
1111
WasmFqProverCommitments,
12-
WasmPastaFqLookupTable,
1312
WasmFqProverProof,
1413
WasmFqRuntimeTable,
14+
WasmPastaFpLookupTable,
15+
WasmPastaFpRuntimeTableCfg,
16+
WasmPastaFqLookupTable,
1517
WasmPastaFqRuntimeTableCfg,
1618
WasmVecVecFp,
1719
WasmVecVecFq,
1820
} from '../../compiled/node_bindings/plonk_wasm.cjs';
19-
import type * as wasmNamespace from '../../compiled/node_bindings/plonk_wasm.cjs';
21+
import {
22+
fieldFromRust,
23+
fieldToRust,
24+
fieldsFromRustFlat,
25+
fieldsToRustFlat,
26+
} from './conversion-base.js';
27+
import { ConversionCore, ConversionCores, mapToUint32Array, unwrap } from './conversion-core.js';
2028
import type {
29+
Field,
30+
LookupCommitments,
31+
LookupTable,
32+
OpeningProof,
2133
OrInfinity,
2234
PointEvaluations,
2335
PolyComm,
24-
ProverProof,
25-
ProofWithPublic,
2636
ProofEvaluations,
37+
ProofWithPublic,
2738
ProverCommitments,
28-
OpeningProof,
39+
ProverProof,
2940
RecursionChallenge,
30-
LookupCommitments,
3141
RuntimeTable,
3242
RuntimeTableCfg,
33-
LookupTable,
34-
Field,
3543
} from './kimchi-types.js';
36-
import { MlArray, MlOption, MlTuple } from '../../../lib/ml/base.js';
37-
import {
38-
fieldToRust,
39-
fieldFromRust,
40-
fieldsToRustFlat,
41-
fieldsFromRustFlat,
42-
} from './conversion-base.js';
43-
import { ConversionCore, ConversionCores, mapToUint32Array, unwrap } from './conversion-core.js';
4444

4545
export { proofConversion };
4646

@@ -178,6 +178,7 @@ function proofConversionPerField(
178178
}
179179

180180
function runtimeTableToRust([, id, data]: RuntimeTable): WasmRuntimeTable {
181+
console.log('old runtime table to rust!');
181182
return new RuntimeTable(id, core.vectorToRust(data));
182183
}
183184

src/bindings/crypto/bindings/conversion-verifier-index.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,6 @@ function verifierIndexConversionPerField(
117117
);
118118
}
119119
function verificationEvalsFromRust(evals: WasmVerificationEvals): VerificationEvals {
120-
console.log('evals', evals.coefficients_comm);
121-
122120
let mlEvals: VerificationEvals = [
123121
0,
124122
core.polyCommsFromRust(evals.sigma_comm),

src/bindings/crypto/bindings/gate-vector-napi.unit-test.ts

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@ import type { Field, Gate, Wire } from './kimchi-types.js';
66
const require = createRequire(import.meta.url);
77

88
function loadNative() {
9+
const slug = `${process.platform}-${process.arch}`;
910
const candidates = [
10-
'../../compiled/_node_bindings/plonk_napi.node',
11+
`../../../../../native/${slug}/plonk_napi.node`,
1112
'../../compiled/node_bindings/plonk_napi.node',
13+
'../../compiled/_node_bindings/plonk_napi.node',
1214
];
1315
for (const path of candidates) {
1416
try {
@@ -23,6 +25,21 @@ function loadNative() {
2325

2426
const native: any = loadNative();
2527

28+
const gateVectorCreate =
29+
native.caml_pasta_fp_plonk_gate_vector_create ?? native.camlPastaFpPlonkGateVectorCreate;
30+
const gateVectorLen =
31+
native.caml_pasta_fp_plonk_gate_vector_len ?? native.camlPastaFpPlonkGateVectorLen;
32+
const gateVectorAdd =
33+
native.caml_pasta_fp_plonk_gate_vector_add ?? native.camlPastaFpPlonkGateVectorAdd;
34+
const gateVectorGet =
35+
native.caml_pasta_fp_plonk_gate_vector_get ?? native.camlPastaFpPlonkGateVectorGet;
36+
const gateVectorWrap =
37+
native.caml_pasta_fp_plonk_gate_vector_wrap ?? native.camlPastaFpPlonkGateVectorWrap;
38+
const gateVectorDigest =
39+
native.caml_pasta_fp_plonk_gate_vector_digest ?? native.camlPastaFpPlonkGateVectorDigest;
40+
const circuitSerialize =
41+
native.caml_pasta_fp_plonk_circuit_serialize ?? native.camlPastaFpPlonkCircuitSerialize;
42+
2643
const { fp } = napiConversionCore(native);
2744

2845
const zeroField: Field = [0, 0n];
@@ -44,24 +61,24 @@ const sampleGate: Gate = [
4461
[0, zeroField, zeroField, zeroField, zeroField, zeroField, zeroField, zeroField],
4562
];
4663

47-
const vector = native.camlPastaFpPlonkGateVectorCreate();
48-
expect(native.camlPastaFpPlonkGateVectorLen(vector)).toBe(0);
64+
const vector = gateVectorCreate();
65+
expect(gateVectorLen(vector)).toBe(0);
4966

50-
native.camlPastaFpPlonkGateVectorAdd(vector, fp.gateToRust(sampleGate));
51-
expect(native.camlPastaFpPlonkGateVectorLen(vector)).toBe(1);
67+
gateVectorAdd(vector, fp.gateToRust(sampleGate));
68+
expect(gateVectorLen(vector)).toBe(1);
5269

53-
const gate0 = native.camlPastaFpPlonkGateVectorGet(vector, 0);
70+
const gate0 = gateVectorGet(vector, 0);
5471
expect(gate0.typ).toBe(sampleGate[1]);
5572

5673
const rustTarget = fp.wireToRust(mlWire(0, 0));
5774
const rustHead = fp.wireToRust(mlWire(1, 2));
58-
native.camlPastaFpPlonkGateVectorWrap(vector, rustTarget, rustHead);
59-
const wrapped = native.camlPastaFpPlonkGateVectorGet(vector, 0);
75+
gateVectorWrap(vector, rustTarget, rustHead);
76+
const wrapped = gateVectorGet(vector, 0);
6077
expect(wrapped.wires.w0).toEqual({ row: 1, col: 2 });
6178

62-
native.camlPastaFpPlonkGateVectorDigest(0, vector);
63-
native.camlPastaFpPlonkCircuitSerialize(0, vector);
79+
gateVectorDigest(0, vector);
80+
circuitSerialize(0, vector);
6481

65-
console.log('{}', native.camlPastaFpPlonkGateVectorDigest(0, vector));
82+
console.log('{}', gateVectorDigest(0, vector));
6683

6784
console.log('gate vector napi bindings (fp) are working ✔️');
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
import { MlOption } from '../../../lib/ml/base.js';
2+
import type * as napiNamespace from '../../compiled/node_bindings/plonk_wasm.cjs';
3+
import type {
4+
WasmFpOracles,
5+
WasmFpRandomOracles,
6+
WasmFqOracles,
7+
WasmFqRandomOracles,
8+
} from '../../compiled/node_bindings/plonk_wasm.cjs';
9+
import {
10+
fieldFromRust,
11+
fieldToRust,
12+
fieldsFromRustFlat,
13+
fieldsToRustFlat,
14+
maybeFieldToRust,
15+
} from './conversion-base.js';
16+
import { Field, Oracles, RandomOracles, ScalarChallenge } from './kimchi-types.js';
17+
18+
export { napiOraclesConversion };
19+
20+
type napi = typeof napiNamespace;
21+
22+
type NapiRandomOracles = WasmFpRandomOracles | WasmFqRandomOracles;
23+
type NapiOracles = WasmFpOracles | WasmFqOracles;
24+
25+
type NapiClasses = {
26+
RandomOracles: typeof WasmFpRandomOracles | typeof WasmFqRandomOracles;
27+
Oracles: typeof WasmFpOracles | typeof WasmFqOracles;
28+
};
29+
30+
function napiOraclesConversion(napi: napi) {
31+
return {
32+
fp: oraclesConversionPerField({
33+
RandomOracles: napi.WasmFpRandomOracles,
34+
Oracles: napi.WasmFpOracles,
35+
}),
36+
fq: oraclesConversionPerField({
37+
RandomOracles: napi.WasmFqRandomOracles,
38+
Oracles: napi.WasmFqOracles,
39+
}),
40+
};
41+
}
42+
43+
function oraclesConversionPerField({ RandomOracles, Oracles }: NapiClasses) {
44+
function randomOraclesToRust(ro: RandomOracles): NapiRandomOracles {
45+
let jointCombinerMl = MlOption.from(ro[1]);
46+
let jointCombinerChal = maybeFieldToRust(jointCombinerMl?.[1][1]);
47+
let jointCombiner = maybeFieldToRust(jointCombinerMl?.[2]);
48+
let beta = fieldToRust(ro[2]);
49+
let gamma = fieldToRust(ro[3]);
50+
let alphaChal = fieldToRust(ro[4][1]);
51+
let alpha = fieldToRust(ro[5]);
52+
let zeta = fieldToRust(ro[6]);
53+
let v = fieldToRust(ro[7]);
54+
let u = fieldToRust(ro[8]);
55+
let zetaChal = fieldToRust(ro[9][1]);
56+
let vChal = fieldToRust(ro[10][1]);
57+
let uChal = fieldToRust(ro[11][1]);
58+
return new RandomOracles(
59+
jointCombinerChal,
60+
jointCombiner,
61+
beta,
62+
gamma,
63+
alphaChal,
64+
alpha,
65+
zeta,
66+
v,
67+
u,
68+
zetaChal,
69+
vChal,
70+
uChal
71+
);
72+
}
73+
function randomOraclesFromRust(ro: NapiRandomOracles): RandomOracles {
74+
let jointCombinerChal = ro.joint_combiner_chal;
75+
let jointCombiner = ro.joint_combiner;
76+
let jointCombinerOption = MlOption<[0, ScalarChallenge, Field]>(
77+
jointCombinerChal &&
78+
jointCombiner && [0, [0, fieldFromRust(jointCombinerChal)], fieldFromRust(jointCombiner)]
79+
);
80+
let mlRo: RandomOracles = [
81+
0,
82+
jointCombinerOption,
83+
fieldFromRust(ro.beta),
84+
fieldFromRust(ro.gamma),
85+
[0, fieldFromRust(ro.alpha_chal)],
86+
fieldFromRust(ro.alpha),
87+
fieldFromRust(ro.zeta),
88+
fieldFromRust(ro.v),
89+
fieldFromRust(ro.u),
90+
[0, fieldFromRust(ro.zeta_chal)],
91+
[0, fieldFromRust(ro.v_chal)],
92+
[0, fieldFromRust(ro.u_chal)],
93+
];
94+
// TODO: do we not want to free?
95+
// ro.free();
96+
return mlRo;
97+
}
98+
99+
return {
100+
oraclesToRust(oracles: Oracles): NapiOracles {
101+
let [, o, pEval, openingPrechallenges, digestBeforeEvaluations] = oracles;
102+
return new Oracles(
103+
randomOraclesToRust(o),
104+
fieldToRust(pEval[1]),
105+
fieldToRust(pEval[2]),
106+
fieldsToRustFlat(openingPrechallenges),
107+
fieldToRust(digestBeforeEvaluations)
108+
);
109+
},
110+
oraclesFromRust(oracles: NapiOracles): Oracles {
111+
let mlOracles: Oracles = [
112+
0,
113+
randomOraclesFromRust(oracles.o),
114+
[0, fieldFromRust(oracles.p_eval0), fieldFromRust(oracles.p_eval1)],
115+
fieldsFromRustFlat(oracles.opening_prechallenges),
116+
fieldFromRust(oracles.digest_before_evaluations),
117+
];
118+
// TODO: do we not want to free?
119+
// oracles.free();
120+
return mlOracles;
121+
},
122+
};
123+
}

src/bindings/crypto/bindings/srs.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ function srsPerField(f: 'fp' | 'fq', wasm: Wasm, conversion: RustConversion) {
104104
let maybeLagrangeCommitment = (srs: WasmSrs, domain_size: number, i: number) => {
105105
try {
106106
console.log(3);
107-
console.log('srs', srs);
107+
console.log('srs wasm', srs);
108108
let bytes = (wasm as any)[`caml_${f}_srs_to_bytes_external`](srs);
109109
console.log('bytes', bytes);
110110
let wasmSrs = undefined;

0 commit comments

Comments
 (0)