@javakha77/circomlibjs-hinkal-fork 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.
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @type import('hardhat/config').HardhatUserConfig
3
+ */
4
+ module.exports = {
5
+ solidity: "0.7.3",
6
+ };
package/main.js ADDED
@@ -0,0 +1,5 @@
1
+ export { default as buildBabyjub } from "./src/babyjub.js";
2
+
3
+ export { default as buildEddsa } from "./src/eddsa.js";
4
+
5
+ export { buildPoseidon, buildPoseidonWasm } from "./src/poseidon_wasm.js";
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@javakha77/circomlibjs-hinkal-fork",
3
+ "version": "0.0.11",
4
+ "description": "Javascript library to work with circomlib",
5
+ "keywords": [
6
+ "circom",
7
+ "circomlib",
8
+ "iden3",
9
+ "snarkjs",
10
+ "snark",
11
+ "zero",
12
+ "knowledge"
13
+ ],
14
+ "homepage": "https://github.com/Hinkal-Protocol/circomlibjs#readme",
15
+ "bugs": {
16
+ "url": "https://github.com/Hinkal-Protocol/circomlibjs/issues"
17
+ },
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/Hinkal-Protocol/circomlibjs.git"
21
+ },
22
+ "license": "GPL-3.0",
23
+ "author": "javakha77",
24
+ "type": "module",
25
+ "exports": {
26
+ "import": "./main.js",
27
+ "require": "./build/main.cjs"
28
+ },
29
+ "main": "./build/main.cjs",
30
+ "directories": {
31
+ "test": "test"
32
+ },
33
+ "scripts": {
34
+ "test": "mocha",
35
+ "poseidonOptimizeConstants": "node tools/poseidon_optimize_constants.js",
36
+ "build": "rollup -c rollup.cjs.config.js"
37
+ },
38
+ "dependencies": {
39
+ "@noble/hashes": "^2.2.0",
40
+ "ffjavascript": "^0.3.0",
41
+ "poseidon-lite": "^0.3.0"
42
+ },
43
+ "devDependencies": {
44
+ "chai": "^4.3.4",
45
+ "ganache": "^7.3.0",
46
+ "mocha": "^9.1.3",
47
+ "rollup": "^4.60.4"
48
+ },
49
+ "module": "./main.js"
50
+ }
@@ -0,0 +1,16 @@
1
+ import fs from "fs";
2
+ import { builtinModules as builtin } from "module";
3
+
4
+ const pkg = JSON.parse(fs.readFileSync("./package.json"));
5
+
6
+ export default {
7
+ input: "./main.js",
8
+ output: {
9
+ file: "build/main.cjs",
10
+ format: "cjs",
11
+ },
12
+ external: [
13
+ ...Object.keys(pkg.dependencies),
14
+ ...builtin,
15
+ ]
16
+ };
package/src/EddsaRN.js ADDED
@@ -0,0 +1,77 @@
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 { BabyJubRN } from './babyjubRN.js';
5
+ import { PoseidonRN } 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
+ await PoseidonRN.init();
76
+ return new EddsaRN(new BabyJubRN(), PoseidonRN.getPoseidon());
77
+ };
@@ -0,0 +1,155 @@
1
+ import { safeJsonStringify } from './serialize.utils.js';
2
+
3
+ /**
4
+ * @typedef {string | number | boolean | bigint | { toBigInt: () => bigint }} BigIntable
5
+ */
6
+
7
+ export const calculateSum = (arr) => arr.reduce((prev, item) => prev + item, 0);
8
+
9
+ export const beepsToPercentage = (beeps) => beeps / 100;
10
+ export const calculateAmountUsingBeeps = (beep, amount) => (amount * beep) / 10000n;
11
+
12
+ export function toBigInt(value) {
13
+ if (typeof value === 'object' && 'toBigInt' in value) {
14
+ return value.toBigInt();
15
+ }
16
+ return BigInt(value);
17
+ }
18
+
19
+ export const advancedToBigInt = (value) => {
20
+ if (Array.isArray(value) && value.length === 32) {
21
+ // Convert big-endian byte array to BigInt
22
+ let result = 0n;
23
+ for (let i = 0; i < 32; i += 1) {
24
+ // eslint-disable-next-line no-bitwise
25
+ result = (result << 8n) | BigInt(value[i]);
26
+ }
27
+
28
+ return result;
29
+ }
30
+
31
+ if (typeof value === 'string' || typeof value === 'number') {
32
+ return BigInt(value);
33
+ }
34
+
35
+ if (typeof value === 'bigint') {
36
+ return value;
37
+ }
38
+
39
+ throw new Error(`Cannot convert value to BigInt: ${typeof value}, value: ${safeJsonStringify(value)}`);
40
+ };
41
+
42
+ /** Converts the value to a BigInt or returns undefined if can't */
43
+ export const toBigIntOrUndefined = (value) => {
44
+ try {
45
+ return BigInt(value);
46
+ } catch {
47
+ return undefined;
48
+ }
49
+ };
50
+
51
+ /** Converts the value to a number or returns undefined if can't */
52
+ export const toNumberOrUndefined = (value) => {
53
+ const num = Number(value);
54
+ return Number.isNaN(num) ? undefined : num;
55
+ };
56
+
57
+ export const toInt = (param, defaultValue) =>
58
+ param ? parseInt(param, 10) : defaultValue;
59
+
60
+ export function bigintMax(...values) {
61
+ return values.reduce((max, value) => (value > max ? value : max));
62
+ }
63
+
64
+ // here + before Number convers string to number and cuts unused 0s at the end
65
+ export function fixDecimalsAmount(n, decimals) {
66
+ if (n === 0) {
67
+ return 0;
68
+ }
69
+ return n < 0.00000099999 ? ' < 0.000001' : +Number(n).toFixed(decimals ?? 6);
70
+ }
71
+
72
+ export const getValueFirstNDigit = (num, numberOfDigits) => {
73
+ const numStr = num.toFixed(20); // if num = 0.03232e-17 -> it will transform to 0.00...03232
74
+
75
+ const indexOfDecimal = numStr.indexOf('.');
76
+ // If there's no decimal point, return the original number (or handle this case as you need)
77
+ if (indexOfDecimal === -1) return numStr;
78
+
79
+ // Determine the end position for substring, which is start position + n digits after decimal
80
+ const endPosition = indexOfDecimal + numberOfDigits + 1;
81
+
82
+ // Get the string from the start to the specified end position
83
+ const resultStr = numStr.substring(0, endPosition);
84
+
85
+ return resultStr;
86
+ };
87
+
88
+ export const trimLeadingZeros = (numberString) => {
89
+ // String of repeating 0's (e.g. '0000000') should be replaced with '0', not empty string
90
+ if (/^0+$/.test(numberString)) {
91
+ return '0';
92
+ }
93
+ // One leading zero before decimal point is valid
94
+ if (/^0\.\d+$/.test(numberString)) {
95
+ return numberString;
96
+ }
97
+ const trimmed = numberString.replace(/^0+/, '');
98
+ return trimmed.startsWith('.') ? `0${trimmed}` : trimmed;
99
+ };
100
+
101
+ export const toCommaSeparatedNumberString = (numberString) => {
102
+ const parts = numberString.split('.');
103
+ const integerPart = parts[0];
104
+ // Only add the . and decimal part if exist
105
+ const decimalPart = parts.length > 1 ? `.${parts[1]}` : '';
106
+
107
+ // Use a regular expression to format the integer part with commas
108
+ const formattedIntegerPart = trimLeadingZeros(integerPart).replace(/\B(?=(\d{3})+(?!\d))/g, ',');
109
+
110
+ return `${formattedIntegerPart}${decimalPart}`;
111
+ };
112
+
113
+ export const truncateToDecimalPlaces = (numStr, decimalPlaces = 18) => {
114
+ const match = numStr.match(/^(\d+)(\.(\d+))?$/);
115
+ if (match) {
116
+ const integerPart = match[1];
117
+ const decimalPart = match[3]?.slice(0, decimalPlaces) || '';
118
+ return decimalPart ? `${integerPart}.${decimalPart}` : integerPart;
119
+ }
120
+ return numStr;
121
+ };
122
+
123
+ export const formatAmountInput = (
124
+ valueStr,
125
+ decimals,
126
+ inputEl,
127
+ ) => {
128
+ if (!/^[0-9]*[.]?[0-9]*$/.test(valueStr)) return null;
129
+
130
+ const formatted = truncateToDecimalPlaces(trimLeadingZeros(valueStr), decimals);
131
+
132
+ if (inputEl && formatted !== valueStr) {
133
+ const oldPos = inputEl.selectionStart ?? 0;
134
+ const leadingZerosLength = valueStr.match(/^0+(?=\d)/)?.[0]?.length ?? 0;
135
+ const newCursorPos = Math.max(oldPos - leadingZerosLength, 1);
136
+
137
+ requestAnimationFrame(() => {
138
+ inputEl.setSelectionRange(newCursorPos, newCursorPos);
139
+ });
140
+ }
141
+
142
+ return formatted;
143
+ };
144
+
145
+ /** Return absolute value of BigInt */
146
+ export const absBigInt = (n) => (n < 0n ? -n : n);
147
+
148
+ /** Return the smallest values of the 2 or 3 values provided */
149
+ export const minBigInt = (a, b, c) => {
150
+ const minOne = a < b ? a : b;
151
+ if (!c) return minOne;
152
+ return minOne < c ? minOne : c;
153
+ };
154
+
155
+ export const maxBigInt = (a, b) => (a > b ? a : b);
package/src/babyjub.js ADDED
@@ -0,0 +1,139 @@
1
+ import { getCurveFromName, Scalar } from "ffjavascript";
2
+
3
+ export default async function buildBabyJub() {
4
+ const bn128 = await getCurveFromName("bn128", true);
5
+ return new BabyJub(bn128.Fr);
6
+ }
7
+
8
+ class BabyJub {
9
+ constructor(F) {
10
+ this.F = F;
11
+ this.p = Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617");
12
+ this.pm1d2 = Scalar.div(Scalar.sub(this.p, Scalar.e(1)), Scalar.e(2));
13
+
14
+ this.Generator = [
15
+ F.e("995203441582195749578291179787384436505546430278305826713579947235728471134"),
16
+ F.e("5472060717959818805561601436314318772137091100104008585924551046643952123905")
17
+ ];
18
+ this.Base8 = [
19
+ F.e("5299619240641551281634865583518297030282874472190772894086521144482721001553"),
20
+ F.e("16950150798460657717958625567821834550301663161624707787222815936182638968203")
21
+ ];
22
+ this.order = Scalar.fromString("21888242871839275222246405745257275088614511777268538073601725287587578984328");
23
+ this.subOrder = Scalar.shiftRight(this.order, 3);
24
+ this.A = F.e("168700");
25
+ this.D = F.e("168696");
26
+ }
27
+
28
+
29
+ addPoint(a,b) {
30
+ const F = this.F;
31
+
32
+ const res = [];
33
+
34
+ /* does the equivalent of:
35
+ res[0] = bigInt((a[0]*b[1] + b[0]*a[1]) * bigInt(bigInt("1") + d*a[0]*b[0]*a[1]*b[1]).inverse(q)).affine(q);
36
+ res[1] = bigInt((a[1]*b[1] - cta*a[0]*b[0]) * bigInt(bigInt("1") - d*a[0]*b[0]*a[1]*b[1]).inverse(q)).affine(q);
37
+ */
38
+
39
+ const beta = F.mul(a[0],b[1]);
40
+ const gamma = F.mul(a[1],b[0]);
41
+ const delta = F.mul(
42
+ F.sub(a[1], F.mul(this.A, a[0])),
43
+ F.add(b[0], b[1])
44
+ );
45
+ const tau = F.mul(beta, gamma);
46
+ const dtau = F.mul(this.D, tau);
47
+
48
+ res[0] = F.div(
49
+ F.add(beta, gamma),
50
+ F.add(F.one, dtau)
51
+ );
52
+
53
+ res[1] = F.div(
54
+ F.add(delta, F.sub(F.mul(this.A,beta), gamma)),
55
+ F.sub(F.one, dtau)
56
+ );
57
+
58
+ return res;
59
+ }
60
+
61
+ mulPointEscalar(base, e) {
62
+ const F = this.F;
63
+ let res = [F.e("0"),F.e("1")];
64
+ let rem = e;
65
+ let exp = base;
66
+
67
+ while (! Scalar.isZero(rem)) {
68
+ if (Scalar.isOdd(rem)) {
69
+ res = this.addPoint(res, exp);
70
+ }
71
+ exp = this.addPoint(exp, exp);
72
+ rem = Scalar.shiftRight(rem, 1);
73
+ }
74
+
75
+ return res;
76
+ }
77
+
78
+ inSubgroup(P) {
79
+ const F = this.F;
80
+ if (!this.inCurve(P)) return false;
81
+ const res= this.mulPointEscalar(P, this.subOrder);
82
+ return (F.isZero(res[0]) && F.eq(res[1], F.one));
83
+ }
84
+
85
+ inCurve(P) {
86
+ const F = this.F;
87
+ const x2 = F.square(P[0]);
88
+ const y2 = F.square(P[1]);
89
+
90
+ if (!F.eq(
91
+ F.add(F.mul(this.A, x2), y2),
92
+ F.add(F.one, F.mul(F.mul(x2, y2), this.D)))) return false;
93
+
94
+ return true;
95
+ }
96
+
97
+ packPoint(P) {
98
+ const F = this.F;
99
+ const buff = new Uint8Array(32);
100
+ F.toRprLE(buff, 0, P[1]);
101
+ const n = F.toObject(P[0]);
102
+ if (Scalar.gt(n, this.pm1d2)) {
103
+ buff[31] = buff[31] | 0x80;
104
+ }
105
+ return buff;
106
+ }
107
+
108
+ unpackPoint(buff) {
109
+ const F = this.F;
110
+ let sign = false;
111
+ const P = new Array(2);
112
+ if (buff[31] & 0x80) {
113
+ sign = true;
114
+ buff[31] = buff[31] & 0x7F;
115
+ }
116
+ P[1] = F.fromRprLE(buff, 0);
117
+ if (Scalar.gt(F.toObject(P[1]), this.p)) return null;
118
+
119
+ const y2 = F.square(P[1]);
120
+
121
+ const x2 = F.div(
122
+ F.sub(F.one, y2),
123
+ F.sub(this.A, F.mul(this.D, y2))
124
+ );
125
+
126
+ const x2h = F.exp(x2, F.half);
127
+ if (! F.eq(F.one, x2h)) return null;
128
+
129
+ let x = F.sqrt(x2);
130
+
131
+ if (x == null) return null;
132
+
133
+ if (sign) x = F.neg(x);
134
+
135
+ P[0] = x;
136
+
137
+ return P;
138
+ }
139
+ }
@@ -0,0 +1,118 @@
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('5299619240641551281634865583518297030282874472190772894086521144482721001553'),
96
+ F.e('16950150798460657717958625567821834550301663161624707787222815936182638968203'),
97
+ ];
98
+
99
+ // Add two affine curve points.
100
+ addPoint(a, b) {
101
+ return toAffine(addExtended(toExtended(a), toExtended(b)));
102
+ }
103
+
104
+ // Scalar multiplication: returns e * base (double-and-add in extended coords).
105
+ mulPointEscalar(base, e) {
106
+ let res = IDENTITY;
107
+ let exp = toExtended(base);
108
+ let rem = BigInt(e);
109
+
110
+ while (rem !== 0n) {
111
+ if (rem % 2n === 1n) res = addExtended(res, exp);
112
+ exp = doubleExtended(exp);
113
+ rem /= 2n;
114
+ }
115
+
116
+ return toAffine(res);
117
+ }
118
+ }
@@ -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
+ };
package/src/eddsa.js ADDED
@@ -0,0 +1,101 @@
1
+ import { Scalar, utils } from "ffjavascript";
2
+ import buildBabyJub from "./babyjub.js";
3
+ import { buildPoseidon } from "./poseidon_wasm.js";
4
+ import { blake512 } from "@noble/hashes/blake1.js";
5
+
6
+ export default async function buildEddsa() {
7
+ const babyJub = await buildBabyJub("bn128");
8
+ const poseidon = await buildPoseidon();
9
+ return new Eddsa(babyJub, poseidon);
10
+ }
11
+
12
+ class Eddsa {
13
+ constructor(babyJub, poseidon) {
14
+ this.babyJub = babyJub;
15
+ this.poseidon = poseidon;
16
+ this.F = babyJub.F;
17
+ }
18
+
19
+ pruneBuffer(buff) {
20
+ buff[0] = buff[0] & 0xf8;
21
+ buff[31] = buff[31] & 0x7f;
22
+ buff[31] = buff[31] | 0x40;
23
+ return buff;
24
+ }
25
+
26
+ prv2pub(prv) {
27
+ const sBuff = this.pruneBuffer(blake512(prv).slice(0, 32));
28
+ let s = utils.leBuff2int(sBuff);
29
+ const A = this.babyJub.mulPointEscalar(
30
+ this.babyJub.Base8,
31
+ Scalar.shr(s, 3),
32
+ );
33
+ return A;
34
+ }
35
+
36
+ signPoseidon(prv, msg) {
37
+ const F = this.babyJub.F;
38
+ const sBuff = this.pruneBuffer(blake512(prv));
39
+ const s = Scalar.fromRprLE(sBuff, 0, 32);
40
+ const A = this.babyJub.mulPointEscalar(
41
+ this.babyJub.Base8,
42
+ Scalar.shr(s, 3),
43
+ );
44
+
45
+ const composeBuff = new Uint8Array(32 + msg.length);
46
+ composeBuff.set(sBuff.slice(32), 0);
47
+ F.toRprLE(composeBuff, 32, msg);
48
+ const rBuff = blake512(composeBuff);
49
+ let r = Scalar.mod(Scalar.fromRprLE(rBuff, 0, 64), this.babyJub.subOrder);
50
+ const R8 = this.babyJub.mulPointEscalar(this.babyJub.Base8, r);
51
+
52
+ const hm = this.poseidon([R8[0], R8[1], A[0], A[1], msg]);
53
+ const hms = Scalar.e(this.babyJub.F.toObject(hm));
54
+ const S = Scalar.mod(
55
+ Scalar.add(r, Scalar.mul(hms, s)),
56
+ this.babyJub.subOrder,
57
+ );
58
+ return {
59
+ R8: R8,
60
+ S: S,
61
+ };
62
+ }
63
+
64
+ verifyPoseidon(msg, sig, A) {
65
+ // Check parameters
66
+ if (typeof sig != "object") return false;
67
+ if (!Array.isArray(sig.R8)) return false;
68
+ if (sig.R8.length != 2) return false;
69
+ if (!this.babyJub.inCurve(sig.R8)) return false;
70
+ if (!Array.isArray(A)) return false;
71
+ if (A.length != 2) return false;
72
+ if (!this.babyJub.inCurve(A)) return false;
73
+ if (sig.S >= this.babyJub.subOrder) return false;
74
+
75
+ const hm = this.poseidon([sig.R8[0], sig.R8[1], A[0], A[1], msg]);
76
+ const hms = Scalar.e(this.babyJub.F.toObject(hm));
77
+
78
+ const Pleft = this.babyJub.mulPointEscalar(this.babyJub.Base8, sig.S);
79
+ let Pright = this.babyJub.mulPointEscalar(A, Scalar.mul(hms, 8));
80
+ Pright = this.babyJub.addPoint(sig.R8, Pright);
81
+
82
+ if (!this.babyJub.F.eq(Pleft[0], Pright[0])) return false;
83
+ if (!this.babyJub.F.eq(Pleft[1], Pright[1])) return false;
84
+ return true;
85
+ }
86
+
87
+ packSignature(sig) {
88
+ const buff = new Uint8Array(64);
89
+ const R8p = this.babyJub.packPoint(sig.R8);
90
+ buff.set(R8p, 0);
91
+ const Sp = Scalar.toRprLE(buff, 32, sig.S, 32);
92
+ return buff;
93
+ }
94
+
95
+ unpackSignature(sigBuff) {
96
+ return {
97
+ R8: this.babyJub.unpackPoint(sigBuff.slice(0, 32)),
98
+ S: Scalar.fromRprLE(sigBuff, 32, 32),
99
+ };
100
+ }
101
+ }