Wrappers for built-in Web Workers enabling easy parallel data processing.
Used in micro-zk-proofs.
Browser Web Workers work fine, but have terrible APIs (just like most "web APIs"). Node.js doesn't have workers, while polyfilling them using node APIs breaks bundlers.
How could one pass a code to a worker?
eval. Would break CSP and importsCheck out webpack docs on webworkers.
The library could also be used in single-threaded manner: provide threads option to initBatch.
Then slow functions can be ran outside of main thread, with async API.
npm install micro-wrkr
deno add jsr:@paulmillr/micro-wrkr
main.jsimport { bn254 } from '@noble/curves/bn254.js';
import type {
WeierstrassPointCons, WeierstrassPoint,
} from '@noble/curves/abstract/weierstrass.js';
import { wrkr } from 'micro-wrkr';
import type { Methods } from 'micro-wrkr/utils.js';
import type { Handlers } from './msm-worker.js';
function reducePoint<T>(p: WeierstrassPointCons<T>) {
return (lst: WeierstrassPoint<T>[]): WeierstrassPoint<T> =>
lst.map((i) => new p(i.X, i.Y, i.Z)).reduce((acc, i) => acc.add(i), p.ZERO);
}
export function initMSM(): { methods: Methods<Handlers>; terminate: () => void } {
// Type-safe
// worker should be in same directory as main thread code
const { methods, terminate } = wrkr.initBatch<Handlers>(
() => new Worker(new URL('./msm-worker.js', import.meta.url), { type: 'module' }),
{
// optional reducers
bn254_msmG1: reducePoint(bn254.G1.Point),
bn254_msmG2: reducePoint(bn254.G2.Point),
}
);
// Use `terminate` to stop workers when app is paused or exported from library.
// Otherwise, it won't terminate.
return { methods, terminate };
}
msm-worker.jsimport { bn254 } from '@noble/curves/bn254.js';
import { pippenger } from '@noble/curves/abstract/curve.js';
import { wrkr } from 'micro-wrkr';
import type { Fp2 } from '@noble/curves/abstract/tower.js';
import type {
WeierstrassPointCons,
WeierstrassPoint,
} from '@noble/curves/abstract/weierstrass.js';
type MSMInput<T> = { point: WeierstrassPoint<T>; scalar: bigint };
export type Handlers = {
bn254_msmG1: (lst: MSMInput<bigint>[]) => WeierstrassPoint<bigint>;
bn254_msmG2: (lst: MSMInput<Fp2>[]) => WeierstrassPoint<Fp2>;
};
function buildMSM<T>(point: WeierstrassPointCons<T>) {
return (lst: MSMInput<T>[]): WeierstrassPoint<T> => {
if (!lst.length) return point.ZERO;
const points = lst.map((i) => new point(i.point.X, i.point.Y, i.point.Z));
const scalars = lst.map((i) => i.scalar);
return pippenger(point, points, scalars);
};
}
const handlers: Handlers = {
bn254_msmG1: buildMSM(bn254.G1.Point),
bn254_msmG2: buildMSM(bn254.G2.Point),
};
wrkr.initWorker(handlers);
new Worker(new URL(e.p+e.u(44),e.b),{type:void 0})# when no google chrome, thorium can also be used
export CHROME_BIN='/Applications/Thorium.app/Contents/MacOS/Thorium'
npm run build && npm run test:full
MIT (c) Paul Miller (https://paulmillr.com), see LICENSE file.