Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
f70e550
bindings: mimick format of wasm side on napi conversion core
querolita Jan 21, 2026
cb5b8e5
bindings: use conversion bundle for napi and wasm rust interfaces
querolita Jan 21, 2026
1c10038
bindings: add napi ffi helpers to reduce use of any and unknown
querolita Jan 21, 2026
bd42ffd
bindings: remove old log
querolita Jan 21, 2026
80b2500
bindings: switch plonk_wasm for kimchi_wasm
querolita Jan 27, 2026
5fe55c6
bindings: switch plonk_napi for kimchi_napi
querolita Jan 27, 2026
585b1c8
bindings: rename backend guards
querolita Jan 29, 2026
f1639e6
napi: improve types of conversion layer
querolita Jan 29, 2026
cd6fa0b
bindings: improve types of proof conversion
querolita Jan 29, 2026
370d5c4
bindings: reduce use of any in verifier index
querolita Jan 29, 2026
16d3a9c
submodule: update proof-systems
querolita Jan 29, 2026
b510238
submodule: update mina
querolita Feb 3, 2026
28d9a1c
napi: move types to their own file and remove snake/camel dupes
querolita Feb 3, 2026
c56c018
submodule: update mina
querolita Feb 3, 2026
0758f89
conversion: prefix types with Napi, unify types in wrappers, remove s…
querolita Feb 4, 2026
17c5963
napi: simplify accessing elements of point evaluations removing and …
querolita Feb 4, 2026
9d74a02
conversion: remove error handling and unify return syntax
querolita Feb 4, 2026
536c01f
bindings: unify backend to be 'native'
querolita Feb 5, 2026
1ab7d91
remove not needed typ<e class
Trivo25 Feb 9, 2026
a500ba3
refactor to use shared functionaity
Trivo25 Feb 9, 2026
3f074f3
dont need to free napi values (tbd)
Trivo25 Feb 9, 2026
5d5c143
get rid of some as types (wip)
Trivo25 Feb 9, 2026
4df7c9c
try to free
Trivo25 Feb 9, 2026
7c17f51
get rid of debug log
Trivo25 Feb 9, 2026
1c5ae01
duplicated range check property
Trivo25 Feb 9, 2026
217b920
cleanup arrayFrom
Trivo25 Feb 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions README-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,11 +156,11 @@ against the Wasm backend.

For the Wasm build, the output files are:

- `plonk_wasm_bg.wasm`: The compiled WebAssembly binary.
- `plonk_wasm_bg.wasm.d.ts`: TypeScript definition files describing the types of
- `kimchi_wasm_bg.wasm`: The compiled WebAssembly binary.
- `kimchi_wasm_bg.wasm.d.ts`: TypeScript definition files describing the types of
.wasm or .js files.
- `plonk_wasm.js`: JavaScript file that wraps the Wasm code for use in Node.js.
- `plonk_wasm.d.ts`: TypeScript definition file for plonk_wasm.js.
- `kimchi_wasm.js`: JavaScript file that wraps the Wasm code for use in Node.js.
- `kimchi_wasm.d.ts`: TypeScript definition file for kimchi_wasm.js.

### Generated Constant Types

Expand Down
4 changes: 2 additions & 2 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -260,8 +260,8 @@
];
});
inherit (inputs.mina.devShells."${system}".default)
PLONK_WASM_NODEJS
PLONK_WASM_WEB
KIMCHI_WASM_NODEJS
KIMCHI_WASM_WEB
KIMCHI_STUBS
KIMCHI_STUBS_STATIC_LIB
;
Expand Down
2 changes: 1 addition & 1 deletion scripts/build/jsoo/build-node.sh
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ run_cmd mv -f $BINDINGS_PATH/o1js_node.bc.js $BINDINGS_PATH/o1js_node.bc.cjs
ok "Node.js bindings copied"

info "Updating WASM references in bindings..."
run_cmd sed -i 's/plonk_wasm.js/plonk_wasm.cjs/' $BINDINGS_PATH/o1js_node.bc.cjs
run_cmd sed -i 's/kimchi_wasm.js/kimchi_wasm.cjs/' $BINDINGS_PATH/o1js_node.bc.cjs
ok "WASM references updated"

info "fixing JS bindings for better error handling..."
Expand Down
8 changes: 4 additions & 4 deletions scripts/build/native/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ cat > $BINDINGS_PATH/package.json <<EOF
}
},
"files": [
"plonk_napi.node",
"kimchi_napi.node",
"index.d.ts",
"index.js"
],
Expand All @@ -61,11 +61,11 @@ To use this package, please refer to [o1js](https://www.npmjs.com/package/o1js)

EOF

echo "module.exports = require('./plonk_napi.node')" > $BINDINGS_PATH/index.js
echo "module.exports = require('./kimchi_napi.node')" > $BINDINGS_PATH/index.js

info "copying artifacts into the right place..."
cp $BUILT_PATH/plonk_napi.node $BINDINGS_PATH/plonk_napi.node
chmod 660 $BINDINGS_PATH/plonk_napi.node
cp $BUILT_PATH/kimchi_napi.node $BINDINGS_PATH/kimchi_napi.node
chmod 660 $BINDINGS_PATH/kimchi_napi.node
cp $BUILT_PATH/index.d.ts $BINDINGS_PATH/index.d.ts
chmod 660 $BINDINGS_PATH/index.d.ts

Expand Down
14 changes: 7 additions & 7 deletions scripts/build/wasm/build-node.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ mkdir -p $BINDINGS_PATH
info "building Kimchi bindings for node..."

TARGETS=(\
plonk_wasm_bg.wasm \
plonk_wasm_bg.wasm.d.ts \
plonk_wasm.js \
plonk_wasm.d.ts \
kimchi_wasm_bg.wasm \
kimchi_wasm_bg.wasm.d.ts \
kimchi_wasm.js \
kimchi_wasm.d.ts \
)
dune build ${TARGETS[@]/#/$KIMCHI_PATH/}

Expand All @@ -32,10 +32,10 @@ done

info "moving some files to CommonJS format..."

mv $BINDINGS_PATH/plonk_wasm.js $BINDINGS_PATH/plonk_wasm.cjs
mv $BINDINGS_PATH/plonk_wasm.d.ts $BINDINGS_PATH/plonk_wasm.d.cts
mv $BINDINGS_PATH/kimchi_wasm.js $BINDINGS_PATH/kimchi_wasm.cjs
mv $BINDINGS_PATH/kimchi_wasm.d.ts $BINDINGS_PATH/kimchi_wasm.d.cts

info "autofixing wasm bindings for Node.JS..."
run_cmd node src/build/fix-wasm-bindings-node.js $BINDINGS_PATH/plonk_wasm.cjs
run_cmd node src/build/fix-wasm-bindings-node.js $BINDINGS_PATH/kimchi_wasm.cjs

success "WASM node build success!"
14 changes: 7 additions & 7 deletions scripts/build/wasm/build-web.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ mkdir -p $BINDINGS_PATH
info "building Kimchi bindings for web..."

TARGETS=(\
plonk_wasm_bg.wasm \
plonk_wasm_bg.wasm.d.ts \
plonk_wasm.js \
plonk_wasm.d.ts\
kimchi_wasm_bg.wasm \
kimchi_wasm_bg.wasm.d.ts \
kimchi_wasm.js \
kimchi_wasm.d.ts\
)
dune build ${TARGETS[@]/#/$KIMCHI_PATH/}

Expand All @@ -40,9 +40,9 @@ run_cmd wasm-opt \
--detect-features \
--enable-mutable-globals \
-O4 \
-o $BINDINGS_PATH/plonk_wasm_bg.wasm.opt \
$BINDINGS_PATH/plonk_wasm_bg.wasm
run_cmd mv $BINDINGS_PATH/plonk_wasm_bg.wasm.opt $BINDINGS_PATH/plonk_wasm_bg.wasm
-o $BINDINGS_PATH/kimchi_wasm_bg.wasm.opt \
$BINDINGS_PATH/kimchi_wasm_bg.wasm
run_cmd mv $BINDINGS_PATH/kimchi_wasm_bg.wasm.opt $BINDINGS_PATH/kimchi_wasm_bg.wasm

ok "wasm optimized"

Expand Down
4 changes: 2 additions & 2 deletions src/bindings.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ import type {
import type {
WasmFpSrs,
WasmFqSrs,
} from './bindings/compiled/node_bindings/plonk_wasm.cjs';
import * as wasm from './bindings/compiled/node_bindings/plonk_wasm.cjs';
} from './bindings/compiled/node_bindings/kimchi_wasm.cjs';
import * as wasm from './bindings/compiled/node_bindings/kimchi_wasm.cjs';
import type { KimchiGateType } from './lib/provable/gates.ts';
import type { MlConstraintSystem } from './lib/provable/core/provable-context.ts';
import type { FieldVector } from './bindings/crypto/bindings/vector.ts';
Expand Down
159 changes: 54 additions & 105 deletions src/bindings/crypto/bindings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,28 @@
* It is exposed to JSOO by populating a global variable with an object.
* It gets imported as the first thing in ../../bindings.js so that the global variable is ready by the time JSOO code gets executed.
*/
import type * as napiNamespace from '../compiled/node_bindings/plonk_wasm.cjs';
import type * as wasmNamespace from '../compiled/node_bindings/plonk_wasm.cjs';
import type * as rustNamespace from '../compiled/node_bindings/kimchi_wasm.cjs';
import { prefixHashes, prefixHashesLegacy } from '../crypto/constants.js';
import { Bigint256Bindings } from './bindings/bigint256.js';
import { fieldsFromRustFlat, fieldsToRustFlat } from './bindings/conversion-base.js';
import { conversionCore } from './bindings/conversion-core.js';
import { oraclesConversion } from './bindings/conversion-oracles.js';
import { proofConversion } from './bindings/conversion-proof.js';
import { verifierIndexConversion } from './bindings/conversion-verifier-index.js';
import { conversionCore as wasmConversionCore } from './bindings/conversion-core.js';
import { oraclesConversion as wasmOraclesConversion } from './bindings/conversion-oracles.js';
import { proofConversion as wasmProofConversion } from './bindings/conversion-proof.js';
import { verifierIndexConversion as wasmVerifierIndexConversion } from './bindings/conversion-verifier-index.js';
import { PallasBindings, VestaBindings } from './bindings/curve.js';
import { jsEnvironment } from './bindings/env.js';
import { FpBindings, FqBindings } from './bindings/field.js';
import { FpVectorBindings, FqVectorBindings } from './bindings/vector.js';
import { srs } from './bindings/srs.js';
import { srs as napiSrs } from './napi-srs.js';
import { napiConversionCore } from './napi-conversion-core.js';
import { napiProofConversion } from './napi-conversion-proof.js';
import { napiVerifierIndexConversion } from './napi-conversion-verifier-index.js';
import { napiOraclesConversion } from './napi-conversion-oracles.js';
import { srs as wasmSrs } from './bindings/srs.js';
import { srs as napiSrs } from './native/napi-srs.js';
import { napiConversionCore } from './native/napi-conversion-core.js';
import { napiProofConversion } from './native/napi-conversion-proof.js';
import { napiVerifierIndexConversion } from './native/napi-conversion-verifier-index.js';
import { napiOraclesConversion } from './native/napi-conversion-oracles.js';

export { Napi, RustConversion, Wasm, createNativeRustConversion, getRustConversion };
export { Napi, Wasm, RustConversion, getRustConversion };

/* TODO: Uncomment in phase 2 of conversion layer
import { conversionCore as conversionCoreNative } from './native/conversion-core.js';
import { fieldsFromRustFlat as fieldsFromRustFlatNative, fieldsToRustFlat as fieldsToRustFlatNative } from './native/conversion-base.js';
import { proofConversion as proofConversionNative } from './native/conversion-proof.js';
import { verifierIndexConversion as verifierIndexConversionNative } from './native/conversion-verifier-index.js';
import { oraclesConversion as oraclesConversionNative } from './native/conversion-oracles.js';

export { getRustConversion, type RustConversion, type NativeConversion, type Wasm };*/

const tsBindings = {
jsEnvironment,
Expand All @@ -45,38 +37,42 @@ const tsBindings = {
...PallasBindings,
...FpVectorBindings,
...FqVectorBindings,
rustConversion: createRustConversion,
nativeRustConversion: createNativeRustConversion,
/* TODO: Uncomment in phase 2 of conversion layer
srs: (wasm: Wasm) => {
const bundle = getConversionBundle(wasm);
return bundle.srsFactory(wasm, bundle.conversion);
},*/
srs: (wasm: Wasm) => srs(wasm, getRustConversion(wasm)),
srsNative: (napi: Napi) => napiSrs(napi, createNativeRustConversion(napi) as any),
rustConversion: (rust: Rust) => getConversionBundle(rust).conversion,
srs: (rust: Rust) => getConversionBundle(rust).srs,
};

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

type Wasm = typeof wasmNamespace;
type Napi = typeof napiNamespace;
type Rust = typeof rustNamespace;
type Wasm = Rust;
type Napi = Rust;
type BackendKind = 'wasm' | 'native';

type RustConversion = ReturnType<typeof buildWasmConversion>;

function getRustConversion(wasm: Wasm): RustConversion {
return createRustConversion(wasm);
// Whether or not native backend is in use
function getKimchiBackend(rust: Rust): BackendKind {
const backend = (rust as any).__kimchi_backend ?? (globalThis as any)?.__kimchi_backend;
return backend === 'native' ? 'native' : 'wasm';
}

function createRustConversion(wasm: Wasm) {
return buildWasmConversion(wasm);
type WasmConversion = ReturnType<typeof buildWasmRustConversion>;
type NapiConversion = ReturnType<typeof buildNapiRustConversion>;

type RustConversion<B extends BackendKind = BackendKind> = B extends 'wasm'
? WasmConversion
: NapiConversion;

function getRustConversion(rust: Rust): RustConversion {
return getKimchiBackend(rust) === 'wasm'
? buildWasmRustConversion(rust)
: buildNapiRustConversion(rust);
}

function buildWasmConversion(wasm: Wasm) {
let core = conversionCore(wasm);
let verifierIndex = verifierIndexConversion(wasm, core);
let oracles = oraclesConversion(wasm);
let proof = proofConversion(wasm, core);
function buildWasmRustConversion(wasm: Rust) {
let core = wasmConversionCore(wasm);
let proof = wasmProofConversion(wasm, core);
let oracles = wasmOraclesConversion(wasm);
let verifierIndex = wasmVerifierIndexConversion(wasm, core);

return {
fp: { ...core.fp, ...verifierIndex.fp, ...oracles.fp, ...proof.fp },
Expand All @@ -88,81 +84,34 @@ function buildWasmConversion(wasm: Wasm) {
};
}

function createNativeRustConversion(napi: any) {
function buildNapiRustConversion(napi: Rust) {
let core = napiConversionCore(napi);
let proof = napiProofConversion(napi, core);
let verif = napiVerifierIndexConversion(napi, core);
let oracles = napiOraclesConversion(napi);
return {
fp: { ...core.fp, ...proof.fp, ...verif.fp, ...oracles.fp },
fq: { ...core.fq, ...proof.fq, ...verif.fq, ...oracles.fq },
mapMlArrayToRustVector<TMl, TRust>(
[, ...array]: [0, ...TMl[]],
map: (x: TMl) => TRust
): TRust[] {
return array.map(map);
},
};
}
let verifierIndex = napiVerifierIndexConversion(napi, core);

/* TODO: Uncomment in phase 2 of conversion layer

function shouldUseNativeConversion(wasm: Wasm): boolean {
const marker = (wasm as any).__kimchi_use_native;
const globalMarker =
typeof globalThis !== 'undefined' &&
(globalThis as any).__kimchi_use_native;
return Boolean(marker || globalMarker);
}

function createRustConversion(wasm: Wasm): RustConversion {
return shouldUseNativeConversion(wasm)
? createNativeConversion(wasm)
: createWasmConversion(wasm);
}

function createWasmConversion(wasm: Wasm) {
const core = conversionCore(wasm);
const verifierIndex = verifierIndexConversion(wasm, core);
const oracles = oraclesConversion(wasm);
const proof = proofConversion(wasm, core);

return {
fp: { ...core.fp, ...verifierIndex.fp, ...oracles.fp, ...proof.fp },
fq: { ...core.fq, ...verifierIndex.fq, ...oracles.fq, ...proof.fq },
fp: { ...core.fp, ...proof.fp, ...verifierIndex.fp, ...oracles.fp },
fq: { ...core.fq, ...proof.fq, ...verifierIndex.fq, ...oracles.fq },
fieldsToRustFlat,
fieldsFromRustFlat,
wireToRust: core.wireToRust,
mapMlArrayToRustVector: core.mapMlArrayToRustVector,
};
}

type RustConversion = ReturnType<typeof buildConversion>;

function createNativeConversion(wasm: Wasm) {
const core = conversionCoreNative(wasm);
const verifierIndex = verifierIndexConversionNative(wasm, core);
const oracles = oraclesConversionNative(wasm);
const proof = proofConversionNative(wasm, core);

return {
fp: { ...core.fp, ...verifierIndex.fp, ...oracles.fp, ...proof.fp },
fq: { ...core.fq, ...verifierIndex.fq, ...oracles.fq, ...proof.fq },
fieldsToRustFlatNative,
fieldsFromRustFlatNative,
wireToRust: core.wireToRust,
mapMlArrayToRustVector: core.mapMlArrayToRustVector,
};
}

type ConversionBundle =
| { conversion: WasmConversion; srsFactory: typeof srs }
| { conversion: NativeConversion; srsFactory: typeof srsNative };
type ConversionBundle<B extends BackendKind> = {
kind: B;
rust: Rust;
conversion: RustConversion<B>;
srs: B extends 'wasm' ? ReturnType<typeof wasmSrs> : ReturnType<typeof napiSrs>;
};

function getConversionBundle(wasm: Wasm): ConversionBundle {
if (shouldUseNativeConversion(wasm)) {
return { conversion: createNativeConversion(wasm), srsFactory: srsNative };
function getConversionBundle(rust: Rust): ConversionBundle<BackendKind> {
if (getKimchiBackend(rust) === 'wasm') {
const conversion = buildWasmRustConversion(rust);
return { kind: 'wasm', rust, conversion, srs: wasmSrs(rust, conversion) };
}
return { conversion: createWasmConversion(wasm), srsFactory: srs };
const conversion = buildNapiRustConversion(rust);
return { kind: 'native', rust, conversion, srs: napiSrs(rust, conversion) };
}
*/
2 changes: 1 addition & 1 deletion src/bindings/crypto/bindings/bindings.unit-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import {
WasmGVesta,
WasmPallasGProjective,
WasmVestaGProjective,
} from '../../compiled/node_bindings/plonk_wasm.cjs';
} from '../../compiled/node_bindings/kimchi_wasm.cjs';
import { FiniteField, Fp, Fq } from '../finite-field.js';

let number: ToSpec<number, number> = { back: id };
Expand Down
10 changes: 3 additions & 7 deletions src/bindings/crypto/bindings/conversion-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type {
WasmGVesta,
WasmPallasGProjective,
WasmVestaGProjective,
} from '../../compiled/node_bindings/plonk_wasm.cjs';
} from '../../compiled/node_bindings/kimchi_wasm.cjs';
import { bigintToBytes32, bytesToBigint32 } from '../bigint-helpers.js';
import { Infinity, OrInfinity } from './curve.js';
import { Field } from './field.js';
Expand Down Expand Up @@ -87,18 +87,14 @@ function affineFromRust<A extends WasmAffine>(pt: A): OrInfinity {
}
}

const tmpBytes = new Uint8Array(32);

function affineToRust<A extends WasmAffine>(pt: OrInfinity, makeAffine: () => A) {
let res = makeAffine();
if (pt === Infinity) {
res.infinity = true;
} else {
let [, [, x, y]] = pt;
// we can use the same bytes here every time,
// because x and y setters copy the bytes into wasm memory
res.x = fieldToRust(x, tmpBytes);
res.y = fieldToRust(y, tmpBytes);
res.x = fieldToRust(x);
res.y = fieldToRust(y);
}
return res;
}
Expand Down
Loading
Loading