circomlibjs-hinkal-fork 0.0.10 → 0.0.11
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.
- package/.yarn/install-state.gz +0 -0
- package/.yarnrc.yml +1 -0
- package/build/main.cjs +302 -3
- package/main.js +6 -0
- package/package.json +3 -2
- package/src/EddsaRN.js +76 -0
- package/src/babyjubRN.js +124 -0
- package/src/bigint-math.utils.js +29 -0
- package/src/poseidonRN.js +51 -0
- package/src/protocol.constants.js +2 -0
|
Binary file
|
package/.yarnrc.yml
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
nodeLinker: node-modules
|
package/build/main.cjs
CHANGED
|
@@ -2,6 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
var ffjavascript = require('ffjavascript');
|
|
4
4
|
var blake1_js = require('@noble/hashes/blake1.js');
|
|
5
|
+
var poseidonLite = require('poseidon-lite');
|
|
6
|
+
|
|
7
|
+
function _interopNamespaceDefault(e) {
|
|
8
|
+
var n = Object.create(null);
|
|
9
|
+
if (e) {
|
|
10
|
+
Object.keys(e).forEach(function (k) {
|
|
11
|
+
if (k !== 'default') {
|
|
12
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
13
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
14
|
+
enumerable: true,
|
|
15
|
+
get: function () { return e[k]; }
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
n.default = e;
|
|
21
|
+
return Object.freeze(n);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
var poseidonLite__namespace = /*#__PURE__*/_interopNamespaceDefault(poseidonLite);
|
|
5
25
|
|
|
6
26
|
async function buildBabyJub() {
|
|
7
27
|
const bn128 = await ffjavascript.getCurveFromName("bn128", true);
|
|
@@ -24948,7 +24968,7 @@ var poseidonConstants = {
|
|
|
24948
24968
|
]
|
|
24949
24969
|
};
|
|
24950
24970
|
|
|
24951
|
-
async function buildPoseidon() {
|
|
24971
|
+
async function buildPoseidon$1() {
|
|
24952
24972
|
const bn128 = await ffjavascript.getCurveFromName("bn128", true, buildPoseidonWasm);
|
|
24953
24973
|
|
|
24954
24974
|
const F = bn128.Fr;
|
|
@@ -25379,7 +25399,7 @@ function buildPoseidonWasm(module) {
|
|
|
25379
25399
|
|
|
25380
25400
|
async function buildEddsa() {
|
|
25381
25401
|
const babyJub = await buildBabyJub();
|
|
25382
|
-
const poseidon = await buildPoseidon();
|
|
25402
|
+
const poseidon = await buildPoseidon$1();
|
|
25383
25403
|
return new Eddsa(babyJub, poseidon);
|
|
25384
25404
|
}
|
|
25385
25405
|
|
|
@@ -25474,7 +25494,286 @@ class Eddsa {
|
|
|
25474
25494
|
}
|
|
25475
25495
|
}
|
|
25476
25496
|
|
|
25497
|
+
const CIRCOM_P =
|
|
25498
|
+
21888242871839275222246405745257275088548364400416034343698204186575808495617n;
|
|
25499
|
+
|
|
25500
|
+
// Reduce value into [0, m); handles negative inputs.
|
|
25501
|
+
const mod = (value, m = CIRCOM_P) => {
|
|
25502
|
+
const result = value % m;
|
|
25503
|
+
return result >= 0n ? result : result + m;
|
|
25504
|
+
};
|
|
25505
|
+
|
|
25506
|
+
// Modular inverse via extended Euclidean algorithm (a^-1 mod m).
|
|
25507
|
+
const modInverse = (value, m = CIRCOM_P) => {
|
|
25508
|
+
let lm = 1n;
|
|
25509
|
+
let hm = 0n;
|
|
25510
|
+
let low = mod(value, m);
|
|
25511
|
+
let high = m;
|
|
25512
|
+
|
|
25513
|
+
if (low === 0n) throw new Error("Division by zero");
|
|
25514
|
+
|
|
25515
|
+
while (low > 1n) {
|
|
25516
|
+
const remainder = high % low;
|
|
25517
|
+
const quotient = high / low;
|
|
25518
|
+
high = low;
|
|
25519
|
+
low = remainder;
|
|
25520
|
+
const nm = hm - lm * quotient;
|
|
25521
|
+
hm = lm;
|
|
25522
|
+
lm = nm;
|
|
25523
|
+
}
|
|
25524
|
+
|
|
25525
|
+
return lm < 0n ? lm + m : lm;
|
|
25526
|
+
};
|
|
25527
|
+
|
|
25528
|
+
const P = CIRCOM_P;
|
|
25529
|
+
|
|
25530
|
+
// BabyJub base-field arithmetic over CIRCOM_P (same semantics as circomlibjs F).
|
|
25531
|
+
const F = {
|
|
25532
|
+
p: P,
|
|
25533
|
+
zero: 0n,
|
|
25534
|
+
one: 1n,
|
|
25535
|
+
e: (v) => mod(BigInt(v)),
|
|
25536
|
+
add: (a, b) => mod(a + b),
|
|
25537
|
+
sub: (a, b) => mod(a - b),
|
|
25538
|
+
mul: (a, b) => mod(a * b),
|
|
25539
|
+
div: (a, b) => {
|
|
25540
|
+
if (b === 0n) throw new Error("Division by zero in BabyJub field");
|
|
25541
|
+
return mod(a * modInverse(b));
|
|
25542
|
+
},
|
|
25543
|
+
toString: (a) => mod(a).toString(),
|
|
25544
|
+
};
|
|
25545
|
+
|
|
25546
|
+
/**
|
|
25547
|
+
* @typedef {{ X: bigint, Y: bigint, Z: bigint, T: bigint }} ExtPoint
|
|
25548
|
+
*/
|
|
25549
|
+
|
|
25550
|
+
// Neutral element in extended coordinates (affine identity 0, 1).
|
|
25551
|
+
const IDENTITY = { X: F.zero, Y: F.one, Z: F.one, T: F.zero };
|
|
25552
|
+
|
|
25553
|
+
// Embed an affine (x, y) point into extended twisted Edwards form.
|
|
25554
|
+
const toExtended = (affine) => {
|
|
25555
|
+
const x = F.e(affine[0]);
|
|
25556
|
+
const y = F.e(affine[1]);
|
|
25557
|
+
return { X: x, Y: y, Z: F.one, T: F.mul(x, y) };
|
|
25558
|
+
};
|
|
25559
|
+
|
|
25560
|
+
// Project an extended point back to affine (x, y) coordinates.
|
|
25561
|
+
const toAffine = (point) => {
|
|
25562
|
+
const zInv = modInverse(point.Z);
|
|
25563
|
+
return [F.mul(point.X, zInv), F.mul(point.Y, zInv)];
|
|
25564
|
+
};
|
|
25565
|
+
|
|
25566
|
+
const A = F.e("168700");
|
|
25567
|
+
const D = F.e("168696");
|
|
25568
|
+
|
|
25569
|
+
// Add two extended points (add-2008-hwcd; no per-step field inversions).
|
|
25570
|
+
const addExtended = (p1, p2) => {
|
|
25571
|
+
const a = F.mul(p1.X, p2.X);
|
|
25572
|
+
const b = F.mul(p1.Y, p2.Y);
|
|
25573
|
+
const c = F.mul(F.mul(p1.T, p2.T), D);
|
|
25574
|
+
const d = F.mul(p1.Z, p2.Z);
|
|
25575
|
+
const e = F.sub(F.mul(F.add(p1.X, p1.Y), F.add(p2.X, p2.Y)), F.add(a, b));
|
|
25576
|
+
const f = F.sub(d, c);
|
|
25577
|
+
const g = F.add(d, c);
|
|
25578
|
+
const h = F.sub(b, F.mul(A, a));
|
|
25579
|
+
return {
|
|
25580
|
+
X: F.mul(e, f),
|
|
25581
|
+
Y: F.mul(g, h),
|
|
25582
|
+
T: F.mul(e, h),
|
|
25583
|
+
Z: F.mul(f, g),
|
|
25584
|
+
};
|
|
25585
|
+
};
|
|
25586
|
+
|
|
25587
|
+
// Double an extended point (dbl-2008-hwcd; no per-step field inversions).
|
|
25588
|
+
const doubleExtended = (p) => {
|
|
25589
|
+
const a = F.mul(p.X, p.X);
|
|
25590
|
+
const b = F.mul(p.Y, p.Y);
|
|
25591
|
+
const c = F.mul(F.mul(p.Z, p.Z), 2n);
|
|
25592
|
+
const d = F.mul(A, a);
|
|
25593
|
+
const e = F.sub(F.mul(F.add(p.X, p.Y), F.add(p.X, p.Y)), F.add(a, b));
|
|
25594
|
+
const g = F.add(d, b);
|
|
25595
|
+
const f = F.sub(g, c);
|
|
25596
|
+
const h = F.sub(d, b);
|
|
25597
|
+
return {
|
|
25598
|
+
X: F.mul(e, f),
|
|
25599
|
+
Y: F.mul(g, h),
|
|
25600
|
+
T: F.mul(e, h),
|
|
25601
|
+
Z: F.mul(f, g),
|
|
25602
|
+
};
|
|
25603
|
+
};
|
|
25604
|
+
|
|
25605
|
+
// Pure-JS BabyJub curve used on React Native (circomlibjs uses WASM instead).
|
|
25606
|
+
class BabyJubRN {
|
|
25607
|
+
static A = A;
|
|
25608
|
+
|
|
25609
|
+
static D = D;
|
|
25610
|
+
|
|
25611
|
+
F = F;
|
|
25612
|
+
|
|
25613
|
+
A = A;
|
|
25614
|
+
|
|
25615
|
+
D = D;
|
|
25616
|
+
|
|
25617
|
+
// Standard BabyJub generator used by EdDSA (matches circomlibjs Base8).
|
|
25618
|
+
Base8 = [
|
|
25619
|
+
F.e(
|
|
25620
|
+
"5299619240641551281634865583518297030282874472190772894086521144482721001553",
|
|
25621
|
+
),
|
|
25622
|
+
F.e(
|
|
25623
|
+
"16950150798460657717958625567821834550301663161624707787222815936182638968203",
|
|
25624
|
+
),
|
|
25625
|
+
];
|
|
25626
|
+
|
|
25627
|
+
// Add two affine curve points.
|
|
25628
|
+
addPoint(a, b) {
|
|
25629
|
+
return toAffine(addExtended(toExtended(a), toExtended(b)));
|
|
25630
|
+
}
|
|
25631
|
+
|
|
25632
|
+
// Scalar multiplication: returns e * base (double-and-add in extended coords).
|
|
25633
|
+
mulPointEscalar(base, e) {
|
|
25634
|
+
let res = IDENTITY;
|
|
25635
|
+
let exp = toExtended(base);
|
|
25636
|
+
let rem = BigInt(e);
|
|
25637
|
+
|
|
25638
|
+
while (rem !== 0n) {
|
|
25639
|
+
if (rem % 2n === 1n) res = addExtended(res, exp);
|
|
25640
|
+
exp = doubleExtended(exp);
|
|
25641
|
+
rem /= 2n;
|
|
25642
|
+
}
|
|
25643
|
+
|
|
25644
|
+
return toAffine(res);
|
|
25645
|
+
}
|
|
25646
|
+
}
|
|
25647
|
+
|
|
25648
|
+
const buildBabyJubRN = () => new BabyJubRN();
|
|
25649
|
+
|
|
25650
|
+
const toBigInt = (v) => {
|
|
25651
|
+
switch (typeof v) {
|
|
25652
|
+
case "bigint":
|
|
25653
|
+
return v;
|
|
25654
|
+
case "boolean":
|
|
25655
|
+
return v ? 1n : 0n;
|
|
25656
|
+
case "number":
|
|
25657
|
+
if (!Number.isInteger(v))
|
|
25658
|
+
throw new TypeError(`Poseidon: non-integer Number ${v}`);
|
|
25659
|
+
return BigInt(v);
|
|
25660
|
+
case "string": {
|
|
25661
|
+
try {
|
|
25662
|
+
return BigInt(v.trim());
|
|
25663
|
+
} catch {
|
|
25664
|
+
throw new TypeError(
|
|
25665
|
+
`Poseidon: cannot parse string "${v}" as an integer`,
|
|
25666
|
+
);
|
|
25667
|
+
}
|
|
25668
|
+
}
|
|
25669
|
+
default:
|
|
25670
|
+
throw new TypeError(`Poseidon.F: unsupported value of type ${typeof v}`);
|
|
25671
|
+
}
|
|
25672
|
+
};
|
|
25673
|
+
|
|
25674
|
+
// poseidon-lite exposes `poseidon1`..`poseidon16`; wrap them in a `buildPoseidon`-shaped
|
|
25675
|
+
// factory (matching the WASM reference) so callers — and the existing
|
|
25676
|
+
// `poseidon.F.toString(...)` pattern — keep working on RN.
|
|
25677
|
+
const buildPoseidon = () => {
|
|
25678
|
+
const poseidon = (inputs, initState = 0, nOut = 1) => {
|
|
25679
|
+
const fn = poseidonLite__namespace[`poseidon${inputs.length}`];
|
|
25680
|
+
if (!fn)
|
|
25681
|
+
throw new Error(`Poseidon: arity ${inputs.length} not supported (1..16)`);
|
|
25682
|
+
const formattedInputs = inputs.map((v) => toBigInt(v));
|
|
25683
|
+
|
|
25684
|
+
if (nOut > 1) {
|
|
25685
|
+
const results = fn(formattedInputs, nOut);
|
|
25686
|
+
return results.map((v) => BigInt(v));
|
|
25687
|
+
}
|
|
25688
|
+
|
|
25689
|
+
const res = fn(formattedInputs);
|
|
25690
|
+
return BigInt(res);
|
|
25691
|
+
};
|
|
25692
|
+
poseidon.F = {
|
|
25693
|
+
toString: (v) => toBigInt(v).toString(),
|
|
25694
|
+
e: (v) => toBigInt(v),
|
|
25695
|
+
eq: (a, b) => toBigInt(a) === toBigInt(b),
|
|
25696
|
+
};
|
|
25697
|
+
return poseidon;
|
|
25698
|
+
};
|
|
25699
|
+
|
|
25700
|
+
/* eslint-disable no-bitwise */
|
|
25701
|
+
// React Native port of circomlibjs-hinkal-fork/src/eddsa.js (Poseidon EdDSA over BabyJubJub).
|
|
25702
|
+
|
|
25703
|
+
const BABYJUB_ORDER = 21888242871839275222246405745257275088614511777268538073601725287587578984328n;
|
|
25704
|
+
const SUB_ORDER = BABYJUB_ORDER / 8n;
|
|
25705
|
+
|
|
25706
|
+
const leBuff2int = (buff, offset = 0, length = buff.length - offset) => {
|
|
25707
|
+
let result = 0n;
|
|
25708
|
+
for (let i = length - 1; i >= 0; i -= 1) {
|
|
25709
|
+
result = (result << 8n) + BigInt(buff[offset + i]);
|
|
25710
|
+
}
|
|
25711
|
+
return result;
|
|
25712
|
+
};
|
|
25713
|
+
|
|
25714
|
+
const toRprLE = (buff, offset, value, length) => {
|
|
25715
|
+
let v = mod(value);
|
|
25716
|
+
for (let i = 0; i < length; i += 1) {
|
|
25717
|
+
buff[offset + i] = Number(v & 0xffn);
|
|
25718
|
+
v >>= 8n;
|
|
25719
|
+
}
|
|
25720
|
+
};
|
|
25721
|
+
|
|
25722
|
+
const modSubOrder = (value) => mod(value, SUB_ORDER);
|
|
25723
|
+
|
|
25724
|
+
const pruneBuffer = (buff) => {
|
|
25725
|
+
const out = new Uint8Array(buff);
|
|
25726
|
+
out[0] = out[0] & 0xf8;
|
|
25727
|
+
out[31] = out[31] & 0x7f;
|
|
25728
|
+
out[31] = out[31] | 0x40;
|
|
25729
|
+
return out;
|
|
25730
|
+
};
|
|
25731
|
+
|
|
25732
|
+
/**
|
|
25733
|
+
* @typedef {((inputs: bigint[]) => bigint) & { F: { toString: (v: bigint | number | string) => string } }} PoseidonFn
|
|
25734
|
+
*/
|
|
25735
|
+
|
|
25736
|
+
class EddsaRN {
|
|
25737
|
+
constructor(babyJub, poseidon) {
|
|
25738
|
+
this.babyJub = babyJub;
|
|
25739
|
+
this.poseidon = poseidon;
|
|
25740
|
+
}
|
|
25741
|
+
|
|
25742
|
+
prv2pub(prv) {
|
|
25743
|
+
const sBuff = pruneBuffer(blake1_js.blake512(prv).slice(0, 32));
|
|
25744
|
+
const s = leBuff2int(sBuff, 0, 32);
|
|
25745
|
+
return this.babyJub.mulPointEscalar(this.babyJub.Base8, s / 8n);
|
|
25746
|
+
}
|
|
25747
|
+
|
|
25748
|
+
signPoseidon(prv, msg) {
|
|
25749
|
+
const sBuff = pruneBuffer(blake1_js.blake512(prv));
|
|
25750
|
+
const s = leBuff2int(sBuff, 0, 32);
|
|
25751
|
+
const A = this.babyJub.mulPointEscalar(this.babyJub.Base8, s / 8n);
|
|
25752
|
+
|
|
25753
|
+
const composeBuff = new Uint8Array(64);
|
|
25754
|
+
composeBuff.set(sBuff.slice(32), 0);
|
|
25755
|
+
toRprLE(composeBuff, 32, msg, 32);
|
|
25756
|
+
|
|
25757
|
+
const rBuff = blake1_js.blake512(composeBuff);
|
|
25758
|
+
const r = modSubOrder(leBuff2int(rBuff, 0, 64));
|
|
25759
|
+
const R8 = this.babyJub.mulPointEscalar(this.babyJub.Base8, r);
|
|
25760
|
+
|
|
25761
|
+
const hm = this.poseidon([R8[0], R8[1], A[0], A[1], msg]);
|
|
25762
|
+
const hms = mod(BigInt(this.poseidon.F.toString(hm)));
|
|
25763
|
+
const S = modSubOrder(r + modSubOrder(hms * s));
|
|
25764
|
+
|
|
25765
|
+
return { R8, S };
|
|
25766
|
+
}
|
|
25767
|
+
}
|
|
25768
|
+
|
|
25769
|
+
const buildEddsaRN = async () => {
|
|
25770
|
+
return new EddsaRN(buildBabyJubRN(), buildPoseidon());
|
|
25771
|
+
};
|
|
25772
|
+
|
|
25773
|
+
exports.buildBabyJubRN = buildBabyJubRN;
|
|
25477
25774
|
exports.buildBabyjub = buildBabyJub;
|
|
25478
25775
|
exports.buildEddsa = buildEddsa;
|
|
25479
|
-
exports.
|
|
25776
|
+
exports.buildEddsaRN = buildEddsaRN;
|
|
25777
|
+
exports.buildPoseidon = buildPoseidon$1;
|
|
25778
|
+
exports.buildPoseidonRN = buildPoseidon;
|
|
25480
25779
|
exports.buildPoseidonWasm = buildPoseidonWasm;
|
package/main.js
CHANGED
|
@@ -3,3 +3,9 @@ export { default as buildBabyjub } from "./src/babyjub.js";
|
|
|
3
3
|
export { default as buildEddsa } from "./src/eddsa.js";
|
|
4
4
|
|
|
5
5
|
export { buildPoseidon, buildPoseidonWasm } from "./src/poseidon_wasm.js";
|
|
6
|
+
|
|
7
|
+
export { buildEddsaRN } from "./src/EddsaRN.js";
|
|
8
|
+
|
|
9
|
+
export { buildBabyJubRN } from "./src/babyjubRN.js";
|
|
10
|
+
|
|
11
|
+
export { buildPoseidon as buildPoseidonRN } from "./src/poseidonRN.js";
|
package/package.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"import": "./main.js",
|
|
8
8
|
"require": "./build/main.cjs"
|
|
9
9
|
},
|
|
10
|
-
"version": "0.0.
|
|
10
|
+
"version": "0.0.11",
|
|
11
11
|
"description": "Javascript library to work with circomlib",
|
|
12
12
|
"scripts": {
|
|
13
13
|
"test": "mocha",
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@noble/hashes": "^2.2.0",
|
|
35
|
-
"ffjavascript": "^0.3.0"
|
|
35
|
+
"ffjavascript": "^0.3.0",
|
|
36
|
+
"poseidon-lite": "^0.3.0"
|
|
36
37
|
}
|
|
37
38
|
}
|
package/src/EddsaRN.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/* eslint-disable no-bitwise */
|
|
2
|
+
// React Native port of circomlibjs-hinkal-fork/src/eddsa.js (Poseidon EdDSA over BabyJubJub).
|
|
3
|
+
import { blake512 } from '@noble/hashes/blake1.js';
|
|
4
|
+
import { buildBabyJubRN } from './babyjubRN.js';
|
|
5
|
+
import { buildPoseidon as buildPoseidonRN } from './poseidonRN.js';
|
|
6
|
+
import { mod } from './bigint-math.utils.js';
|
|
7
|
+
|
|
8
|
+
const BABYJUB_ORDER = 21888242871839275222246405745257275088614511777268538073601725287587578984328n;
|
|
9
|
+
const SUB_ORDER = BABYJUB_ORDER / 8n;
|
|
10
|
+
|
|
11
|
+
const leBuff2int = (buff, offset = 0, length = buff.length - offset) => {
|
|
12
|
+
let result = 0n;
|
|
13
|
+
for (let i = length - 1; i >= 0; i -= 1) {
|
|
14
|
+
result = (result << 8n) + BigInt(buff[offset + i]);
|
|
15
|
+
}
|
|
16
|
+
return result;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const toRprLE = (buff, offset, value, length) => {
|
|
20
|
+
let v = mod(value);
|
|
21
|
+
for (let i = 0; i < length; i += 1) {
|
|
22
|
+
buff[offset + i] = Number(v & 0xffn);
|
|
23
|
+
v >>= 8n;
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const modSubOrder = (value) => mod(value, SUB_ORDER);
|
|
28
|
+
|
|
29
|
+
const pruneBuffer = (buff) => {
|
|
30
|
+
const out = new Uint8Array(buff);
|
|
31
|
+
out[0] = out[0] & 0xf8;
|
|
32
|
+
out[31] = out[31] & 0x7f;
|
|
33
|
+
out[31] = out[31] | 0x40;
|
|
34
|
+
return out;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @typedef {((inputs: bigint[]) => bigint) & { F: { toString: (v: bigint | number | string) => string } }} PoseidonFn
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
export class EddsaRN {
|
|
42
|
+
constructor(babyJub, poseidon) {
|
|
43
|
+
this.babyJub = babyJub;
|
|
44
|
+
this.poseidon = poseidon;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
prv2pub(prv) {
|
|
48
|
+
const sBuff = pruneBuffer(blake512(prv).slice(0, 32));
|
|
49
|
+
const s = leBuff2int(sBuff, 0, 32);
|
|
50
|
+
return this.babyJub.mulPointEscalar(this.babyJub.Base8, s / 8n);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
signPoseidon(prv, msg) {
|
|
54
|
+
const sBuff = pruneBuffer(blake512(prv));
|
|
55
|
+
const s = leBuff2int(sBuff, 0, 32);
|
|
56
|
+
const A = this.babyJub.mulPointEscalar(this.babyJub.Base8, s / 8n);
|
|
57
|
+
|
|
58
|
+
const composeBuff = new Uint8Array(64);
|
|
59
|
+
composeBuff.set(sBuff.slice(32), 0);
|
|
60
|
+
toRprLE(composeBuff, 32, msg, 32);
|
|
61
|
+
|
|
62
|
+
const rBuff = blake512(composeBuff);
|
|
63
|
+
const r = modSubOrder(leBuff2int(rBuff, 0, 64));
|
|
64
|
+
const R8 = this.babyJub.mulPointEscalar(this.babyJub.Base8, r);
|
|
65
|
+
|
|
66
|
+
const hm = this.poseidon([R8[0], R8[1], A[0], A[1], msg]);
|
|
67
|
+
const hms = mod(BigInt(this.poseidon.F.toString(hm)));
|
|
68
|
+
const S = modSubOrder(r + modSubOrder(hms * s));
|
|
69
|
+
|
|
70
|
+
return { R8, S };
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export const buildEddsaRN = async () => {
|
|
75
|
+
return new EddsaRN(buildBabyJubRN(), buildPoseidonRN());
|
|
76
|
+
};
|
package/src/babyjubRN.js
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { CIRCOM_P } from "./protocol.constants.js";
|
|
2
|
+
import { mod, modInverse } from "./bigint-math.utils.js";
|
|
3
|
+
|
|
4
|
+
const P = CIRCOM_P;
|
|
5
|
+
|
|
6
|
+
// BabyJub base-field arithmetic over CIRCOM_P (same semantics as circomlibjs F).
|
|
7
|
+
const F = {
|
|
8
|
+
p: P,
|
|
9
|
+
zero: 0n,
|
|
10
|
+
one: 1n,
|
|
11
|
+
e: (v) => mod(BigInt(v)),
|
|
12
|
+
add: (a, b) => mod(a + b),
|
|
13
|
+
sub: (a, b) => mod(a - b),
|
|
14
|
+
mul: (a, b) => mod(a * b),
|
|
15
|
+
div: (a, b) => {
|
|
16
|
+
if (b === 0n) throw new Error("Division by zero in BabyJub field");
|
|
17
|
+
return mod(a * modInverse(b));
|
|
18
|
+
},
|
|
19
|
+
toString: (a) => mod(a).toString(),
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @typedef {{ X: bigint, Y: bigint, Z: bigint, T: bigint }} ExtPoint
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
// Neutral element in extended coordinates (affine identity 0, 1).
|
|
27
|
+
const IDENTITY = { X: F.zero, Y: F.one, Z: F.one, T: F.zero };
|
|
28
|
+
|
|
29
|
+
// Embed an affine (x, y) point into extended twisted Edwards form.
|
|
30
|
+
const toExtended = (affine) => {
|
|
31
|
+
const x = F.e(affine[0]);
|
|
32
|
+
const y = F.e(affine[1]);
|
|
33
|
+
return { X: x, Y: y, Z: F.one, T: F.mul(x, y) };
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
// Project an extended point back to affine (x, y) coordinates.
|
|
37
|
+
const toAffine = (point) => {
|
|
38
|
+
const zInv = modInverse(point.Z);
|
|
39
|
+
return [F.mul(point.X, zInv), F.mul(point.Y, zInv)];
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const A = F.e("168700");
|
|
43
|
+
const D = F.e("168696");
|
|
44
|
+
|
|
45
|
+
// Add two extended points (add-2008-hwcd; no per-step field inversions).
|
|
46
|
+
const addExtended = (p1, p2) => {
|
|
47
|
+
const a = F.mul(p1.X, p2.X);
|
|
48
|
+
const b = F.mul(p1.Y, p2.Y);
|
|
49
|
+
const c = F.mul(F.mul(p1.T, p2.T), D);
|
|
50
|
+
const d = F.mul(p1.Z, p2.Z);
|
|
51
|
+
const e = F.sub(F.mul(F.add(p1.X, p1.Y), F.add(p2.X, p2.Y)), F.add(a, b));
|
|
52
|
+
const f = F.sub(d, c);
|
|
53
|
+
const g = F.add(d, c);
|
|
54
|
+
const h = F.sub(b, F.mul(A, a));
|
|
55
|
+
return {
|
|
56
|
+
X: F.mul(e, f),
|
|
57
|
+
Y: F.mul(g, h),
|
|
58
|
+
T: F.mul(e, h),
|
|
59
|
+
Z: F.mul(f, g),
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
// Double an extended point (dbl-2008-hwcd; no per-step field inversions).
|
|
64
|
+
const doubleExtended = (p) => {
|
|
65
|
+
const a = F.mul(p.X, p.X);
|
|
66
|
+
const b = F.mul(p.Y, p.Y);
|
|
67
|
+
const c = F.mul(F.mul(p.Z, p.Z), 2n);
|
|
68
|
+
const d = F.mul(A, a);
|
|
69
|
+
const e = F.sub(F.mul(F.add(p.X, p.Y), F.add(p.X, p.Y)), F.add(a, b));
|
|
70
|
+
const g = F.add(d, b);
|
|
71
|
+
const f = F.sub(g, c);
|
|
72
|
+
const h = F.sub(d, b);
|
|
73
|
+
return {
|
|
74
|
+
X: F.mul(e, f),
|
|
75
|
+
Y: F.mul(g, h),
|
|
76
|
+
T: F.mul(e, h),
|
|
77
|
+
Z: F.mul(f, g),
|
|
78
|
+
};
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// Pure-JS BabyJub curve used on React Native (circomlibjs uses WASM instead).
|
|
82
|
+
export class BabyJubRN {
|
|
83
|
+
static A = A;
|
|
84
|
+
|
|
85
|
+
static D = D;
|
|
86
|
+
|
|
87
|
+
F = F;
|
|
88
|
+
|
|
89
|
+
A = A;
|
|
90
|
+
|
|
91
|
+
D = D;
|
|
92
|
+
|
|
93
|
+
// Standard BabyJub generator used by EdDSA (matches circomlibjs Base8).
|
|
94
|
+
Base8 = [
|
|
95
|
+
F.e(
|
|
96
|
+
"5299619240641551281634865583518297030282874472190772894086521144482721001553",
|
|
97
|
+
),
|
|
98
|
+
F.e(
|
|
99
|
+
"16950150798460657717958625567821834550301663161624707787222815936182638968203",
|
|
100
|
+
),
|
|
101
|
+
];
|
|
102
|
+
|
|
103
|
+
// Add two affine curve points.
|
|
104
|
+
addPoint(a, b) {
|
|
105
|
+
return toAffine(addExtended(toExtended(a), toExtended(b)));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Scalar multiplication: returns e * base (double-and-add in extended coords).
|
|
109
|
+
mulPointEscalar(base, e) {
|
|
110
|
+
let res = IDENTITY;
|
|
111
|
+
let exp = toExtended(base);
|
|
112
|
+
let rem = BigInt(e);
|
|
113
|
+
|
|
114
|
+
while (rem !== 0n) {
|
|
115
|
+
if (rem % 2n === 1n) res = addExtended(res, exp);
|
|
116
|
+
exp = doubleExtended(exp);
|
|
117
|
+
rem /= 2n;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return toAffine(res);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export const buildBabyJubRN = () => new BabyJubRN();
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { CIRCOM_P } from "./protocol.constants.js";
|
|
2
|
+
|
|
3
|
+
// Reduce value into [0, m); handles negative inputs.
|
|
4
|
+
export const mod = (value, m = CIRCOM_P) => {
|
|
5
|
+
const result = value % m;
|
|
6
|
+
return result >= 0n ? result : result + m;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
// Modular inverse via extended Euclidean algorithm (a^-1 mod m).
|
|
10
|
+
export const modInverse = (value, m = CIRCOM_P) => {
|
|
11
|
+
let lm = 1n;
|
|
12
|
+
let hm = 0n;
|
|
13
|
+
let low = mod(value, m);
|
|
14
|
+
let high = m;
|
|
15
|
+
|
|
16
|
+
if (low === 0n) throw new Error("Division by zero");
|
|
17
|
+
|
|
18
|
+
while (low > 1n) {
|
|
19
|
+
const remainder = high % low;
|
|
20
|
+
const quotient = high / low;
|
|
21
|
+
high = low;
|
|
22
|
+
low = remainder;
|
|
23
|
+
const nm = hm - lm * quotient;
|
|
24
|
+
hm = lm;
|
|
25
|
+
lm = nm;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return lm < 0n ? lm + m : lm;
|
|
29
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import * as poseidonLite from "poseidon-lite";
|
|
2
|
+
|
|
3
|
+
const toBigInt = (v) => {
|
|
4
|
+
switch (typeof v) {
|
|
5
|
+
case "bigint":
|
|
6
|
+
return v;
|
|
7
|
+
case "boolean":
|
|
8
|
+
return v ? 1n : 0n;
|
|
9
|
+
case "number":
|
|
10
|
+
if (!Number.isInteger(v))
|
|
11
|
+
throw new TypeError(`Poseidon: non-integer Number ${v}`);
|
|
12
|
+
return BigInt(v);
|
|
13
|
+
case "string": {
|
|
14
|
+
try {
|
|
15
|
+
return BigInt(v.trim());
|
|
16
|
+
} catch {
|
|
17
|
+
throw new TypeError(
|
|
18
|
+
`Poseidon: cannot parse string "${v}" as an integer`,
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
default:
|
|
23
|
+
throw new TypeError(`Poseidon.F: unsupported value of type ${typeof v}`);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// poseidon-lite exposes `poseidon1`..`poseidon16`; wrap them in a `buildPoseidon`-shaped
|
|
28
|
+
// factory (matching the WASM reference) so callers — and the existing
|
|
29
|
+
// `poseidon.F.toString(...)` pattern — keep working on RN.
|
|
30
|
+
export const buildPoseidon = () => {
|
|
31
|
+
const poseidon = (inputs, initState = 0, nOut = 1) => {
|
|
32
|
+
const fn = poseidonLite[`poseidon${inputs.length}`];
|
|
33
|
+
if (!fn)
|
|
34
|
+
throw new Error(`Poseidon: arity ${inputs.length} not supported (1..16)`);
|
|
35
|
+
const formattedInputs = inputs.map((v) => toBigInt(v));
|
|
36
|
+
|
|
37
|
+
if (nOut > 1) {
|
|
38
|
+
const results = fn(formattedInputs, nOut);
|
|
39
|
+
return results.map((v) => BigInt(v));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const res = fn(formattedInputs);
|
|
43
|
+
return BigInt(res);
|
|
44
|
+
};
|
|
45
|
+
poseidon.F = {
|
|
46
|
+
toString: (v) => toBigInt(v).toString(),
|
|
47
|
+
e: (v) => toBigInt(v),
|
|
48
|
+
eq: (a, b) => toBigInt(a) === toBigInt(b),
|
|
49
|
+
};
|
|
50
|
+
return poseidon;
|
|
51
|
+
};
|