Skip to content

Commit f69cfce

Browse files
committed
bindings: native conversions for affine, points, polycomm
1 parent cb030a4 commit f69cfce

File tree

1 file changed

+115
-50
lines changed

1 file changed

+115
-50
lines changed
Lines changed: 115 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,43 @@
1-
import { fieldsFromRustFlat, fieldsToRustFlat } from './bindings/conversion-base.js';
2-
import { Gate, Wire } from './bindings/kimchi-types.js';
1+
import { Buffer } from 'node:buffer';
2+
import { fieldFromRust, fieldToRust, fieldsFromRustFlat, fieldsToRustFlat } from './bindings/conversion-base.js';
3+
import { Gate, OrInfinity, PolyComm, Wire, Field } from './bindings/kimchi-types.js';
4+
import { MlArray } from '../../lib/ml/base.js';
35
import { mapTuple } from './bindings/util.js';
6+
import type * as napiNamespace from '../compiled/node_bindings/plonk_wasm.cjs';
47

58
export { bindingsNapi };
69

10+
type NapiAffine = napiNamespace.WasmGVesta | napiNamespace.WasmGPallas;
11+
type NapiPolyComm = { unshifted: unknown; shifted?: NapiAffine | undefined };
12+
type PolyCommCtor = new (unshifted: unknown, shifted?: NapiAffine | undefined) => NapiPolyComm;
13+
14+
//const FIELD_BYTE_LENGTH = fieldToRust([0, 0n]).length;
15+
16+
type NapiClasses = {
17+
CommitmentCurve: typeof napiNamespace.WasmGVesta | typeof napiNamespace.WasmGPallas;
18+
makeAffine: () => NapiAffine;
19+
PolyComm: napiNamespace.WasmFpPolyComm | napiNamespace.WasmFqPolyComm;
20+
}
21+
722
function bindingsNapi(napi: any) {
8-
return {
9-
fp: {
10-
vectorToRust: (fields: any) => {
11-
//console.log('values going in ', fields);
12-
let res = fieldsToRustFlat(fields);
13-
//console.log('values going out ', res);
14-
return res;
15-
},
16-
vectorFromRust: fieldsFromRustFlat,
17-
wireToRust([, row, col]: Wire) {
18-
return { row, col };
19-
},
20-
gateToRust(gate: Gate): any {
21-
const [, typ, [, ...wires], coeffs] = gate;
22-
const mapped = mapTuple(wires, (wire) => this.wireToRust(wire));
23-
const nativeWires = {
24-
w0: mapped[0],
25-
w1: mapped[1],
26-
w2: mapped[2],
27-
w3: mapped[3],
28-
w4: mapped[4],
29-
w5: mapped[5],
30-
w6: mapped[6],
31-
} as const;
32-
return {
33-
typ,
34-
wires: nativeWires,
35-
coeffs: Array.from(fieldsToRustFlat(coeffs)),
36-
};
37-
},
23+
const fpCore = conversionCorePerField({
24+
CommitmentCurve: napi.WasmGVesta,
25+
makeAffine: napi.caml_vesta_affine_one,
26+
PolyComm: napi.WasmFpPolyComm,
27+
});
28+
const fqCore = conversionCorePerField({
29+
CommitmentCurve: napi.WasmGPallas,
30+
makeAffine: napi.caml_pallas_affine_one,
31+
PolyComm: napi.WasmFqPolyComm,
32+
});
33+
34+
const shared = {
35+
vectorToRust: (fields: any) => fieldsToRustFlat(fields),
36+
vectorFromRust: fieldsFromRustFlat,
37+
wireToRust([, row, col]: Wire) {
38+
return { row, col };
3839
},
39-
fq: {
40-
vectorToRust: (fields: any) => {
41-
//console.log('values going in ', fields);
42-
let res = fieldsToRustFlat(fields);
43-
//console.log('values going out ', res);
44-
return res;
45-
},
46-
vectorFromRust: (fieldBytes: any) => {
47-
//console.log('values going in ', fieldBytes);
48-
let res = fieldsFromRustFlat(fieldBytes);
49-
//console.log('values going out ', res);
50-
return res;
51-
},
52-
wireToRust([, row, col]: Wire) {
53-
return { row, col };
54-
},
55-
gateToRust(gate: Gate): any {
40+
gateToRust(gate: Gate): any {
5641
const [, typ, [, ...wires], coeffs] = gate;
5742
const mapped = mapTuple(wires, (wire) => this.wireToRust(wire));
5843
const nativeWires = {
@@ -70,6 +55,86 @@ function bindingsNapi(napi: any) {
7055
coeffs: Array.from(fieldsToRustFlat(coeffs)),
7156
};
7257
},
73-
},
7458
};
59+
60+
return {
61+
fp: { ...shared, ...fpCore },
62+
fq: { ...shared, ...fqCore },
63+
};
64+
}
65+
66+
function conversionCorePerField({ makeAffine, PolyComm }: NapiClasses) {
67+
const affineToRust = (pt: OrInfinity): NapiAffine => {
68+
function isFinitePoint(point: OrInfinity): point is [0, [0, Field, Field]] {
69+
return Array.isArray(point);
70+
}
71+
let res = makeAffine();
72+
if (!isFinitePoint(pt)) {
73+
res.infinity = true;
74+
} else {
75+
const tmpBytes = new Uint8Array(32);
76+
const [, pair] = pt;
77+
const [, x, y] = pair;
78+
res.x = fieldToRust(x, tmpBytes);
79+
res.y = fieldToRust(y, tmpBytes);
80+
}
81+
return res;
82+
};
83+
const affineFromRust = (pt: NapiAffine): OrInfinity => {
84+
if (pt.infinity) return 0;
85+
const xField = fieldFromRust(pt.x);
86+
const yField = fieldFromRust(pt.y);
87+
return [0, [0, xField, yField]];
88+
};
89+
90+
const pointToRust = (point: OrInfinity): NapiAffine => affineToRust(point);
91+
const pointFromRust = (point: NapiAffine): OrInfinity => affineFromRust(point);
92+
93+
const pointsToRust = ([, ...points]: MlArray<OrInfinity>): NapiAffine[] => points.map(affineToRust);
94+
const pointsFromRust = (points: NapiAffine[]): MlArray<OrInfinity> => [0, ...points.map(affineFromRust)];
95+
96+
const polyCommToRust = (polyComm: PolyComm): NapiPolyComm => {
97+
const [, camlElems] = polyComm;
98+
const unshifted = pointsToRust(camlElems);
99+
const PolyCommClass = PolyComm as unknown as PolyCommCtor;
100+
return new PolyCommClass(unshifted as unknown, undefined);
101+
};
102+
103+
const polyCommFromRust = (polyComm: NapiPolyComm): PolyComm => {
104+
const rustUnshifted = asArrayLike<NapiAffine>(polyComm.unshifted, 'polyComm.unshifted');
105+
const mlUnshifted = rustUnshifted.map(affineFromRust);
106+
return [0, [0, ...mlUnshifted]];
107+
};
108+
109+
const polyCommsToRust = ([, ...comms]: MlArray<PolyComm>): NapiPolyComm[] =>
110+
comms.map(polyCommToRust);
111+
112+
const polyCommsFromRust = (rustComms: unknown): MlArray<PolyComm> => {
113+
const comms = asArrayLike<NapiPolyComm>(rustComms, 'polyCommsFromRust');
114+
return [0, ...comms.map(polyCommFromRust)];
115+
};
116+
117+
return {
118+
affineToRust,
119+
affineFromRust,
120+
pointToRust,
121+
pointFromRust,
122+
pointsToRust,
123+
pointsFromRust,
124+
polyCommToRust,
125+
polyCommFromRust,
126+
polyCommsToRust,
127+
polyCommsFromRust,
128+
};
129+
}
130+
131+
function asArrayLike<T>(value: unknown, context: string): T[] {
132+
if (value == null) return [];
133+
if (Array.isArray(value)) return value as T[];
134+
if (ArrayBuffer.isView(value)) return Array.from(value as unknown as ArrayLike<T>);
135+
if (typeof value === 'object' && value !== null && 'length' in (value as { length: unknown })) {
136+
const { length } = value as { length: unknown };
137+
if (typeof length === 'number') return Array.from(value as ArrayLike<T>);
138+
}
139+
throw Error(`${context}: expected array-like native values`);
75140
}

0 commit comments

Comments
 (0)