fangorn-sdk 0.0.0
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/LICENSE.md +20 -0
- package/README.md +104 -0
- package/lib/_virtual/rolldown_runtime.js +5 -0
- package/lib/circuits/poseiden1_hash/target/poseiden1_hash.js +46 -0
- package/lib/circuits/poseiden1_hash/target/poseiden1_hash.js.map +1 -0
- package/lib/circuits/poseiden2_hash/target/poseiden2_hash.js +50 -0
- package/lib/circuits/poseiden2_hash/target/poseiden2_hash.js.map +1 -0
- package/lib/circuits/preimage/target/preimage.js +160 -0
- package/lib/circuits/preimage/target/preimage.js.map +1 -0
- package/lib/crypto/constants.d.ts +5 -0
- package/lib/crypto/constants.d.ts.map +1 -0
- package/lib/crypto/constants.js +6 -0
- package/lib/crypto/constants.js.map +1 -0
- package/lib/crypto/encryption.d.ts +11 -0
- package/lib/crypto/encryption.d.ts.map +1 -0
- package/lib/crypto/encryption.js +52 -0
- package/lib/crypto/encryption.js.map +1 -0
- package/lib/crypto/merkle.d.ts +15 -0
- package/lib/crypto/merkle.d.ts.map +1 -0
- package/lib/crypto/merkle.js +56 -0
- package/lib/crypto/merkle.js.map +1 -0
- package/lib/crypto/proof.d.ts +12 -0
- package/lib/crypto/proof.d.ts.map +1 -0
- package/lib/crypto/proof.js +69 -0
- package/lib/crypto/proof.js.map +1 -0
- package/lib/crypto/rand.d.ts +6 -0
- package/lib/crypto/rand.d.ts.map +1 -0
- package/lib/crypto/rand.js +17 -0
- package/lib/crypto/rand.js.map +1 -0
- package/lib/deployContract.d.ts +62 -0
- package/lib/deployContract.d.ts.map +1 -0
- package/lib/deployContract.js +230 -0
- package/lib/deployContract.js.map +1 -0
- package/lib/fangorn.d.ts +86 -0
- package/lib/fangorn.d.ts.map +1 -0
- package/lib/fangorn.js +264 -0
- package/lib/fangorn.js.map +1 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +3 -0
- package/lib/interface/index.d.ts +2 -0
- package/lib/interface/index.js +3 -0
- package/lib/interface/manifest.d.ts +8 -0
- package/lib/interface/manifest.d.ts.map +1 -0
- package/lib/interface/manifest.js +11 -0
- package/lib/interface/manifest.js.map +1 -0
- package/lib/interface/zkGate.d.ts +36 -0
- package/lib/interface/zkGate.d.ts.map +1 -0
- package/lib/interface/zkGate.js +375 -0
- package/lib/interface/zkGate.js.map +1 -0
- package/lib/test/index.d.ts +8 -0
- package/lib/test/index.d.ts.map +1 -0
- package/lib/test/index.js +26 -0
- package/lib/test/index.js.map +1 -0
- package/lib/test/testbed.d.ts +18 -0
- package/lib/test/testbed.d.ts.map +1 -0
- package/lib/test/testbed.js +42 -0
- package/lib/test/testbed.js.map +1 -0
- package/lib/types/types.d.ts +51 -0
- package/lib/types/types.d.ts.map +1 -0
- package/lib/types/types.js +1 -0
- package/lib/utils/index.d.ts +13 -0
- package/lib/utils/index.d.ts.map +1 -0
- package/lib/utils/index.js +47 -0
- package/lib/utils/index.js.map +1 -0
- package/package.json +82 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","names":[],"sources":["../../src/crypto/constants.ts"],"sourcesContent":[],"mappings":";cAEa,UAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","names":[],"sources":["../../src/crypto/constants.ts"],"sourcesContent":["// constants\n\nexport const TREE_DEPTH = 8;\n"],"mappings":";AAEA,MAAa,aAAa"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { EncryptedData } from "../types/types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/crypto/encryption.d.ts
|
|
4
|
+
declare function encryptData(data: string | Uint8Array): Promise<{
|
|
5
|
+
encryptedData: EncryptedData;
|
|
6
|
+
keyMaterial: Uint8Array<ArrayBuffer>;
|
|
7
|
+
}>;
|
|
8
|
+
declare function decryptData(encryptedData: EncryptedData, keyMaterial: Uint8Array<ArrayBuffer>): Promise<Uint8Array>;
|
|
9
|
+
//#endregion
|
|
10
|
+
export { decryptData, encryptData };
|
|
11
|
+
//# sourceMappingURL=encryption.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encryption.d.ts","names":[],"sources":["../../src/crypto/encryption.ts"],"sourcesContent":[],"mappings":";;;iBAGsB,WAAA,gBAA2B,aAAa;iBAC9C;EADM,WAAA,EAER,UAFmB,CAER,WAFQ,CAAA;CAAgB,CAAA;AACjC,iBA6CM,WAAA,CA7CN,aAAA,EA8CA,aA9CA,EAAA,WAAA,EA+CF,UA/CE,CA+CS,WA/CT,CAAA,CAAA,EAgDb,OAhDa,CAgDL,UAhDK,CAAA"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { getRandomValues, getSubtleCrypto } from "./rand.js";
|
|
2
|
+
|
|
3
|
+
//#region src/crypto/encryption.ts
|
|
4
|
+
async function encryptData(data) {
|
|
5
|
+
const subtle = getSubtleCrypto();
|
|
6
|
+
const salt = getRandomValues(new Uint8Array(16));
|
|
7
|
+
const iv = getRandomValues(new Uint8Array(12));
|
|
8
|
+
const keyMaterial = getRandomValues(new Uint8Array(32));
|
|
9
|
+
const key = await subtle.importKey("raw", keyMaterial, { name: "AES-GCM" }, false, ["encrypt"]);
|
|
10
|
+
const encodedData = typeof data === "string" ? new TextEncoder().encode(data) : data;
|
|
11
|
+
const encryptedContent = await subtle.encrypt({
|
|
12
|
+
name: "AES-GCM",
|
|
13
|
+
iv,
|
|
14
|
+
tagLength: 128
|
|
15
|
+
}, key, encodedData);
|
|
16
|
+
const ciphertext = encryptedContent.slice(0, encryptedContent.byteLength - 16);
|
|
17
|
+
const authTag = encryptedContent.slice(encryptedContent.byteLength - 16);
|
|
18
|
+
return {
|
|
19
|
+
encryptedData: {
|
|
20
|
+
ciphertext: new Uint8Array(ciphertext),
|
|
21
|
+
iv,
|
|
22
|
+
authTag: new Uint8Array(authTag),
|
|
23
|
+
salt
|
|
24
|
+
},
|
|
25
|
+
keyMaterial
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
async function decryptData(encryptedData, keyMaterial) {
|
|
29
|
+
const subtle = getSubtleCrypto();
|
|
30
|
+
const ciphertext = toUint8Array(encryptedData.ciphertext);
|
|
31
|
+
const iv = toUint8Array(encryptedData.iv);
|
|
32
|
+
const authTag = toUint8Array(encryptedData.authTag);
|
|
33
|
+
const key = await subtle.importKey("raw", keyMaterial, { name: "AES-GCM" }, false, ["decrypt"]);
|
|
34
|
+
const dataWithAuthTag = new Uint8Array(ciphertext.length + authTag.length);
|
|
35
|
+
dataWithAuthTag.set(ciphertext, 0);
|
|
36
|
+
dataWithAuthTag.set(authTag, ciphertext.length);
|
|
37
|
+
const decryptedContent = await subtle.decrypt({
|
|
38
|
+
name: "AES-GCM",
|
|
39
|
+
iv,
|
|
40
|
+
tagLength: 128
|
|
41
|
+
}, key, dataWithAuthTag);
|
|
42
|
+
return new Uint8Array(decryptedContent);
|
|
43
|
+
}
|
|
44
|
+
function toUint8Array(data) {
|
|
45
|
+
if (data instanceof Uint8Array) return data;
|
|
46
|
+
if (Array.isArray(data)) return new Uint8Array(data);
|
|
47
|
+
return new Uint8Array(Object.values(data));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
//#endregion
|
|
51
|
+
export { decryptData, encryptData };
|
|
52
|
+
//# sourceMappingURL=encryption.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encryption.js","names":[],"sources":["../../src/crypto/encryption.ts"],"sourcesContent":["import { EncryptedData } from \"../types/types\";\nimport { getSubtleCrypto, getRandomValues } from \"./rand\";\n\nexport async function encryptData(data: string | Uint8Array): Promise<{\n\tencryptedData: EncryptedData;\n\tkeyMaterial: Uint8Array<ArrayBuffer>;\n}> {\n\tconst subtle = getSubtleCrypto();\n\tconst salt = getRandomValues(new Uint8Array(16));\n\tconst iv = getRandomValues(new Uint8Array(12));\n\tconst keyMaterial = getRandomValues(new Uint8Array(32));\n\tconst key = await subtle.importKey(\n\t\t\"raw\",\n\t\tkeyMaterial,\n\t\t{ name: \"AES-GCM\" },\n\t\tfalse,\n\t\t[\"encrypt\"],\n\t);\n\n\tconst encodedData =\n\t\ttypeof data === \"string\" ? new TextEncoder().encode(data) : data;\n\n\tconst encryptedContent = await subtle.encrypt(\n\t\t{\n\t\t\tname: \"AES-GCM\",\n\t\t\tiv,\n\t\t\ttagLength: 128,\n\t\t},\n\t\tkey,\n\t\tencodedData as Uint8Array<ArrayBuffer>,\n\t);\n\n\tconst ciphertext = encryptedContent.slice(\n\t\t0,\n\t\tencryptedContent.byteLength - 16,\n\t);\n\tconst authTag = encryptedContent.slice(encryptedContent.byteLength - 16);\n\n\treturn {\n\t\tencryptedData: {\n\t\t\tciphertext: new Uint8Array(ciphertext) as Uint8Array<ArrayBuffer>,\n\t\t\tiv,\n\t\t\tauthTag: new Uint8Array(authTag) as Uint8Array<ArrayBuffer>,\n\t\t\tsalt,\n\t\t},\n\t\tkeyMaterial,\n\t};\n}\n\nexport async function decryptData(\n\tencryptedData: EncryptedData,\n\tkeyMaterial: Uint8Array<ArrayBuffer>,\n): Promise<Uint8Array> {\n\tconst subtle = getSubtleCrypto();\n\n\t// Ensure these are proper Uint8Arrays (may have been serialized to JSON)\n\tconst ciphertext = toUint8Array(encryptedData.ciphertext);\n\tconst iv = toUint8Array(encryptedData.iv);\n\tconst authTag = toUint8Array(encryptedData.authTag);\n\n\tconst key = await subtle.importKey(\n\t\t\"raw\",\n\t\tkeyMaterial,\n\t\t{ name: \"AES-GCM\" },\n\t\tfalse,\n\t\t[\"decrypt\"],\n\t);\n\n\tconst dataWithAuthTag = new Uint8Array(ciphertext.length + authTag.length);\n\tdataWithAuthTag.set(ciphertext, 0);\n\tdataWithAuthTag.set(authTag, ciphertext.length);\n\n\tconst decryptedContent = await subtle.decrypt(\n\t\t{ name: \"AES-GCM\", iv, tagLength: 128 },\n\t\tkey,\n\t\tdataWithAuthTag as Uint8Array<ArrayBuffer>,\n\t);\n\n\treturn new Uint8Array(decryptedContent);\n}\n\nfunction toUint8Array(\n\tdata: Uint8Array | Record<string, number> | number[],\n): Uint8Array<ArrayBuffer> {\n\tif (data instanceof Uint8Array) {\n\t\treturn data as Uint8Array<ArrayBuffer>;\n\t}\n\tif (Array.isArray(data)) {\n\t\treturn new Uint8Array(data) as Uint8Array<ArrayBuffer>;\n\t}\n\treturn new Uint8Array(Object.values(data)) as Uint8Array<ArrayBuffer>;\n}\n"],"mappings":";;;AAGA,eAAsB,YAAY,MAG/B;CACF,MAAM,SAAS,iBAAiB;CAChC,MAAM,OAAO,gBAAgB,IAAI,WAAW,GAAG,CAAC;CAChD,MAAM,KAAK,gBAAgB,IAAI,WAAW,GAAG,CAAC;CAC9C,MAAM,cAAc,gBAAgB,IAAI,WAAW,GAAG,CAAC;CACvD,MAAM,MAAM,MAAM,OAAO,UACxB,OACA,aACA,EAAE,MAAM,WAAW,EACnB,OACA,CAAC,UAAU,CACX;CAED,MAAM,cACL,OAAO,SAAS,WAAW,IAAI,aAAa,CAAC,OAAO,KAAK,GAAG;CAE7D,MAAM,mBAAmB,MAAM,OAAO,QACrC;EACC,MAAM;EACN;EACA,WAAW;EACX,EACD,KACA,YACA;CAED,MAAM,aAAa,iBAAiB,MACnC,GACA,iBAAiB,aAAa,GAC9B;CACD,MAAM,UAAU,iBAAiB,MAAM,iBAAiB,aAAa,GAAG;AAExE,QAAO;EACN,eAAe;GACd,YAAY,IAAI,WAAW,WAAW;GACtC;GACA,SAAS,IAAI,WAAW,QAAQ;GAChC;GACA;EACD;EACA;;AAGF,eAAsB,YACrB,eACA,aACsB;CACtB,MAAM,SAAS,iBAAiB;CAGhC,MAAM,aAAa,aAAa,cAAc,WAAW;CACzD,MAAM,KAAK,aAAa,cAAc,GAAG;CACzC,MAAM,UAAU,aAAa,cAAc,QAAQ;CAEnD,MAAM,MAAM,MAAM,OAAO,UACxB,OACA,aACA,EAAE,MAAM,WAAW,EACnB,OACA,CAAC,UAAU,CACX;CAED,MAAM,kBAAkB,IAAI,WAAW,WAAW,SAAS,QAAQ,OAAO;AAC1E,iBAAgB,IAAI,YAAY,EAAE;AAClC,iBAAgB,IAAI,SAAS,WAAW,OAAO;CAE/C,MAAM,mBAAmB,MAAM,OAAO,QACrC;EAAE,MAAM;EAAW;EAAI,WAAW;EAAK,EACvC,KACA,gBACA;AAED,QAAO,IAAI,WAAW,iBAAiB;;AAGxC,SAAS,aACR,MAC0B;AAC1B,KAAI,gBAAgB,WACnB,QAAO;AAER,KAAI,MAAM,QAAQ,KAAK,CACtB,QAAO,IAAI,WAAW,KAAK;AAE5B,QAAO,IAAI,WAAW,OAAO,OAAO,KAAK,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/crypto/merkle.d.ts
|
|
2
|
+
declare function hashCidToField(cid: string): bigint;
|
|
3
|
+
declare function buildTreeFromLeaves(leaves: bigint[]): Promise<{
|
|
4
|
+
root: bigint;
|
|
5
|
+
layers: bigint[][];
|
|
6
|
+
}>;
|
|
7
|
+
declare function getProof(layers: bigint[][], index: number): {
|
|
8
|
+
path: bigint[];
|
|
9
|
+
indices: number[];
|
|
10
|
+
};
|
|
11
|
+
declare function fieldToHex(field: bigint): `0x${string}`;
|
|
12
|
+
declare function hexToField(hex: string): bigint;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { buildTreeFromLeaves, fieldToHex, getProof, hashCidToField, hexToField };
|
|
15
|
+
//# sourceMappingURL=merkle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merkle.d.ts","names":[],"sources":["../../src/crypto/merkle.ts"],"sourcesContent":[],"mappings":";iBAGgB,cAAA;AAAA,iBAUM,mBAAA,CAVQ,MAAA,EAAA,MAAA,EAAA,CAAA,EAU+B,OAV/B,CAAA;EAUR,IAAA,EAAA,MAAA;EA6BN,MAAA,EAAA,MAAQ,EAAA,EAAA;AAkBxB,CAAA,CAAA;AAIgB,iBAtBA,QAAA,CAsBU,MAAA,EAAA,MAAA,EAAA,EAAA,EAAA,KAAA,EAAA,MAAA,CAAA,EAAA;;;;iBAJV,UAAA;iBAIA,UAAA"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { poseidon2Hash } from "../utils/index.js";
|
|
2
|
+
import { TREE_DEPTH } from "./constants.js";
|
|
3
|
+
|
|
4
|
+
//#region src/crypto/merkle.ts
|
|
5
|
+
function hashCidToField(cid) {
|
|
6
|
+
const bytes = new TextEncoder().encode(cid);
|
|
7
|
+
let value = 0n;
|
|
8
|
+
for (let i = 0; i < Math.min(bytes.length, 31); i++) value = value << 8n | BigInt(bytes[i]);
|
|
9
|
+
return value;
|
|
10
|
+
}
|
|
11
|
+
async function buildTreeFromLeaves(leaves) {
|
|
12
|
+
const size = 2 ** TREE_DEPTH;
|
|
13
|
+
const paddedLeaves = [...leaves];
|
|
14
|
+
while (paddedLeaves.length < size) paddedLeaves.push(0n);
|
|
15
|
+
const layers = [paddedLeaves];
|
|
16
|
+
let current = paddedLeaves;
|
|
17
|
+
while (current.length > 1) {
|
|
18
|
+
const next = [];
|
|
19
|
+
for (let i = 0; i < current.length; i += 2) {
|
|
20
|
+
const hash = await poseidon2Hash(current[i], current[i + 1]);
|
|
21
|
+
next.push(hash);
|
|
22
|
+
}
|
|
23
|
+
layers.push(next);
|
|
24
|
+
current = next;
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
root: layers[layers.length - 1][0],
|
|
28
|
+
layers
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function getProof(layers, index) {
|
|
32
|
+
const path = [];
|
|
33
|
+
const indices = [];
|
|
34
|
+
for (let i = 0; i < TREE_DEPTH; i++) {
|
|
35
|
+
const isRight = index % 2 === 1;
|
|
36
|
+
const siblingIndex = isRight ? index - 1 : index + 1;
|
|
37
|
+
path.push(layers[i][siblingIndex] ?? 0n);
|
|
38
|
+
indices.push(isRight ? 1 : 0);
|
|
39
|
+
index = Math.floor(index / 2);
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
path,
|
|
43
|
+
indices
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function fieldToHex(field) {
|
|
47
|
+
return `0x${field.toString(16).padStart(64, "0")}`;
|
|
48
|
+
}
|
|
49
|
+
function hexToField(hex) {
|
|
50
|
+
const cleanHex = hex.startsWith("0x") ? hex : `0x${hex}`;
|
|
51
|
+
return BigInt(cleanHex);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
//#endregion
|
|
55
|
+
export { buildTreeFromLeaves, fieldToHex, getProof, hashCidToField, hexToField };
|
|
56
|
+
//# sourceMappingURL=merkle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merkle.js","names":["layers: bigint[][]","next: bigint[]","path: bigint[]","indices: number[]"],"sources":["../../src/crypto/merkle.ts"],"sourcesContent":["import { poseidon2Hash } from \"../utils/index.js\";\nimport { TREE_DEPTH } from \"./constants.js\";\n\nexport function hashCidToField(cid: string): bigint {\n\t// Convert CID to field element\n\tconst bytes = new TextEncoder().encode(cid);\n\tlet value = 0n;\n\tfor (let i = 0; i < Math.min(bytes.length, 31); i++) {\n\t\tvalue = (value << 8n) | BigInt(bytes[i]);\n\t}\n\treturn value;\n}\n\nexport async function buildTreeFromLeaves(leaves: bigint[]): Promise<{\n\troot: bigint;\n\tlayers: bigint[][];\n}> {\n\tconst size = 2 ** TREE_DEPTH;\n\tconst paddedLeaves = [...leaves];\n\twhile (paddedLeaves.length < size) {\n\t\tpaddedLeaves.push(0n);\n\t}\n\n\tconst layers: bigint[][] = [paddedLeaves];\n\tlet current = paddedLeaves;\n\n\twhile (current.length > 1) {\n\t\tconst next: bigint[] = [];\n\t\tfor (let i = 0; i < current.length; i += 2) {\n\t\t\tconst hash = await poseidon2Hash(current[i], current[i + 1]);\n\t\t\tnext.push(hash);\n\t\t}\n\t\tlayers.push(next);\n\t\tcurrent = next;\n\t}\n\n\treturn {\n\t\troot: layers[layers.length - 1][0],\n\t\tlayers,\n\t};\n}\n\nexport function getProof(\n\tlayers: bigint[][],\n\tindex: number,\n): { path: bigint[]; indices: number[] } {\n\tconst path: bigint[] = [];\n\tconst indices: number[] = [];\n\n\tfor (let i = 0; i < TREE_DEPTH; i++) {\n\t\tconst isRight = index % 2 === 1;\n\t\tconst siblingIndex = isRight ? index - 1 : index + 1;\n\t\tpath.push(layers[i][siblingIndex] ?? 0n);\n\t\tindices.push(isRight ? 1 : 0);\n\t\tindex = Math.floor(index / 2);\n\t}\n\n\treturn { path, indices };\n}\n\nexport function fieldToHex(field: bigint): `0x${string}` {\n\treturn `0x${field.toString(16).padStart(64, \"0\")}` as `0x${string}`;\n}\n\nexport function hexToField(hex: string): bigint {\n\tconst cleanHex = hex.startsWith(\"0x\") ? hex : `0x${hex}`;\n\treturn BigInt(cleanHex);\n}\n"],"mappings":";;;;AAGA,SAAgB,eAAe,KAAqB;CAEnD,MAAM,QAAQ,IAAI,aAAa,CAAC,OAAO,IAAI;CAC3C,IAAI,QAAQ;AACZ,MAAK,IAAI,IAAI,GAAG,IAAI,KAAK,IAAI,MAAM,QAAQ,GAAG,EAAE,IAC/C,SAAS,SAAS,KAAM,OAAO,MAAM,GAAG;AAEzC,QAAO;;AAGR,eAAsB,oBAAoB,QAGvC;CACF,MAAM,OAAO,KAAK;CAClB,MAAM,eAAe,CAAC,GAAG,OAAO;AAChC,QAAO,aAAa,SAAS,KAC5B,cAAa,KAAK,GAAG;CAGtB,MAAMA,SAAqB,CAAC,aAAa;CACzC,IAAI,UAAU;AAEd,QAAO,QAAQ,SAAS,GAAG;EAC1B,MAAMC,OAAiB,EAAE;AACzB,OAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK,GAAG;GAC3C,MAAM,OAAO,MAAM,cAAc,QAAQ,IAAI,QAAQ,IAAI,GAAG;AAC5D,QAAK,KAAK,KAAK;;AAEhB,SAAO,KAAK,KAAK;AACjB,YAAU;;AAGX,QAAO;EACN,MAAM,OAAO,OAAO,SAAS,GAAG;EAChC;EACA;;AAGF,SAAgB,SACf,QACA,OACwC;CACxC,MAAMC,OAAiB,EAAE;CACzB,MAAMC,UAAoB,EAAE;AAE5B,MAAK,IAAI,IAAI,GAAG,IAAI,YAAY,KAAK;EACpC,MAAM,UAAU,QAAQ,MAAM;EAC9B,MAAM,eAAe,UAAU,QAAQ,IAAI,QAAQ;AACnD,OAAK,KAAK,OAAO,GAAG,iBAAiB,GAAG;AACxC,UAAQ,KAAK,UAAU,IAAI,EAAE;AAC7B,UAAQ,KAAK,MAAM,QAAQ,EAAE;;AAG9B,QAAO;EAAE;EAAM;EAAS;;AAGzB,SAAgB,WAAW,OAA8B;AACxD,QAAO,KAAK,MAAM,SAAS,GAAG,CAAC,SAAS,IAAI,IAAI;;AAGjD,SAAgB,WAAW,KAAqB;CAC/C,MAAM,WAAW,IAAI,WAAW,KAAK,GAAG,MAAM,KAAK;AACnD,QAAO,OAAO,SAAS"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { VaultEntry, VaultManifest } from "../types/types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/crypto/proof.d.ts
|
|
4
|
+
declare function buildCircuitInputs(password: string, entry: VaultEntry, userAddress: `0x${string}`, vaultId: `0x${string}`, manifest: VaultManifest): Promise<{
|
|
5
|
+
inputs: Record<string, any>;
|
|
6
|
+
nullifier: `0x${string}`;
|
|
7
|
+
cidCommitment: `0x${string}`;
|
|
8
|
+
}>;
|
|
9
|
+
declare function computeTagCommitment(vaultId: string, tag: string): Promise<bigint>;
|
|
10
|
+
//#endregion
|
|
11
|
+
export { buildCircuitInputs, computeTagCommitment };
|
|
12
|
+
//# sourceMappingURL=proof.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proof.d.ts","names":[],"sources":["../../src/crypto/proof.ts"],"sourcesContent":[],"mappings":";;;iBAQsB,kBAAA,0BAEd,0EAGG,gBACR;UACM;EAPa,SAAA,EAAA,KAAA,MAAkB,EAAA;EAEhC,aAAA,EAAA,KAAA,MAAA,EAAA;CAGG,CAAA;AAEF,iBAmFa,oBAAA,CAnFb,OAAA,EAAA,MAAA,EAAA,GAAA,EAAA,MAAA,CAAA,EAsFN,OAtFM,CAAA,MAAA,CAAA"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { poseidon2Hash } from "../utils/index.js";
|
|
2
|
+
import { TREE_DEPTH } from "./constants.js";
|
|
3
|
+
import { fieldToHex, getProof, hexToField } from "./merkle.js";
|
|
4
|
+
import { keccak256 } from "viem";
|
|
5
|
+
import { blake3 } from "@noble/hashes/blake3.js";
|
|
6
|
+
|
|
7
|
+
//#region src/crypto/proof.ts
|
|
8
|
+
async function buildCircuitInputs(password, entry, userAddress, vaultId, manifest) {
|
|
9
|
+
const { path, indices } = getProof(manifest.tree.map((layer) => layer.map(hexToField)), Number(entry.index));
|
|
10
|
+
const cidCommitment = hexToField(entry.leaf);
|
|
11
|
+
let current = cidCommitment;
|
|
12
|
+
for (let i = 0; i < TREE_DEPTH; i++) {
|
|
13
|
+
const sibling = path[i];
|
|
14
|
+
const [left, right] = indices[i] === 1 ? [sibling, current] : [current, sibling];
|
|
15
|
+
current = await poseidon2Hash(left, right);
|
|
16
|
+
}
|
|
17
|
+
const expectedRoot = hexToField(manifest.poseidon_root);
|
|
18
|
+
if (current !== expectedRoot) throw new Error(`Merkle root mismatch: computed ${current}, expected ${expectedRoot}`);
|
|
19
|
+
const passwordBytes = new Uint8Array(32);
|
|
20
|
+
passwordBytes.set(new TextEncoder().encode(password).slice(0, 32));
|
|
21
|
+
const expectedHash = keccak256(passwordBytes);
|
|
22
|
+
const userAddressBytes = new Uint8Array(32);
|
|
23
|
+
const addrBytes = Buffer.from(userAddress.slice(2), "hex");
|
|
24
|
+
userAddressBytes.set(addrBytes, 32 - addrBytes.length);
|
|
25
|
+
const vaultIdBytes = new Uint8Array(32);
|
|
26
|
+
const vaultBytes = Buffer.from(vaultId.slice(2), "hex");
|
|
27
|
+
vaultIdBytes.set(vaultBytes, 32 - vaultBytes.length);
|
|
28
|
+
const cidBytes = new Uint8Array(32);
|
|
29
|
+
let temp = cidCommitment;
|
|
30
|
+
for (let i = 31; i >= 0; i--) {
|
|
31
|
+
cidBytes[i] = Number(temp & 255n);
|
|
32
|
+
temp = temp >> 8n;
|
|
33
|
+
}
|
|
34
|
+
const nullifierInput = new Uint8Array(128);
|
|
35
|
+
nullifierInput.set(passwordBytes, 0);
|
|
36
|
+
nullifierInput.set(userAddressBytes, 32);
|
|
37
|
+
nullifierInput.set(vaultIdBytes, 64);
|
|
38
|
+
nullifierInput.set(cidBytes, 96);
|
|
39
|
+
const nullifierHash = blake3(nullifierInput);
|
|
40
|
+
const nullifier = `0x${Buffer.from(nullifierHash).toString("hex")}`;
|
|
41
|
+
const expectedHashBytes = Array.from(Buffer.from(expectedHash.slice(2), "hex"));
|
|
42
|
+
const nullifierBytesArr = Array.from(nullifierHash);
|
|
43
|
+
return {
|
|
44
|
+
inputs: {
|
|
45
|
+
password: Array.from(passwordBytes),
|
|
46
|
+
merkle_path: path.map((p) => p.toString()),
|
|
47
|
+
merkle_indices: indices.map((i) => i.toString()),
|
|
48
|
+
expected_hash: expectedHashBytes,
|
|
49
|
+
merkle_root: expectedRoot.toString(),
|
|
50
|
+
user_address: Array.from(userAddressBytes),
|
|
51
|
+
vault_id: Array.from(vaultIdBytes),
|
|
52
|
+
nullifier: nullifierBytesArr,
|
|
53
|
+
cid_commitment: cidCommitment.toString()
|
|
54
|
+
},
|
|
55
|
+
nullifier,
|
|
56
|
+
cidCommitment: fieldToHex(cidCommitment)
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
async function computeTagCommitment(vaultId, tag) {
|
|
60
|
+
const vaultIdBigInt = BigInt(vaultId);
|
|
61
|
+
const tagBytes = new TextEncoder().encode(tag);
|
|
62
|
+
let tagField = 0n;
|
|
63
|
+
for (let i = 0; i < Math.min(tagBytes.length, 31); i++) tagField = tagField << 8n | BigInt(tagBytes[i]);
|
|
64
|
+
return await poseidon2Hash(vaultIdBigInt, tagField);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
//#endregion
|
|
68
|
+
export { buildCircuitInputs, computeTagCommitment };
|
|
69
|
+
//# sourceMappingURL=proof.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proof.js","names":[],"sources":["../../src/crypto/proof.ts"],"sourcesContent":["import { Hex, keccak256, toBytes } from \"viem\";\nimport { VaultEntry, VaultManifest } from \"../types/types.js\";\nimport { blake3 } from \"@noble/hashes/blake3.js\";\n\nimport { poseidon2Hash } from \"../utils/index.js\";\nimport { fieldToHex, getProof, hexToField } from \"./merkle.js\";\nimport { TREE_DEPTH } from \"./constants.js\";\n\nexport async function buildCircuitInputs(\n\tpassword: string,\n\tentry: VaultEntry,\n\tuserAddress: `0x${string}`,\n\tvaultId: `0x${string}`,\n\tmanifest: VaultManifest,\n): Promise<{\n\tinputs: Record<string, any>;\n\tnullifier: `0x${string}`;\n\tcidCommitment: `0x${string}`;\n}> {\n\tconst layers = manifest.tree!.map((layer) => layer.map(hexToField));\n\tconst { path, indices } = getProof(layers, Number(entry.index));\n\n\tconst cidCommitment = hexToField(entry.leaf);\n\n\t// verify merkle root locally\n\tlet current = cidCommitment;\n\tfor (let i = 0; i < TREE_DEPTH; i++) {\n\t\tconst sibling = path[i];\n\t\tconst isRight = indices[i] === 1;\n\t\tconst [left, right] = isRight ? [sibling, current] : [current, sibling];\n\t\tcurrent = await poseidon2Hash(left, right);\n\t}\n\n\tconst expectedRoot = hexToField(manifest.poseidon_root);\n\tif (current !== expectedRoot) {\n\t\tthrow new Error(\n\t\t\t`Merkle root mismatch: computed ${current}, expected ${expectedRoot}`,\n\t\t);\n\t}\n\n\t// Password (padded to 32 bytes)\n\tconst passwordBytes = new Uint8Array(32);\n\tpasswordBytes.set(new TextEncoder().encode(password).slice(0, 32));\n\tconst expectedHash = keccak256(passwordBytes);\n\n\t// User address (left-padded to 32 bytes)\n\tconst userAddressBytes = new Uint8Array(32);\n\tconst addrBytes = Buffer.from(userAddress.slice(2), \"hex\");\n\tuserAddressBytes.set(addrBytes, 32 - addrBytes.length);\n\n\t// Vault ID (32 bytes)\n\tconst vaultIdBytes = new Uint8Array(32);\n\tconst vaultBytes = Buffer.from(vaultId.slice(2), \"hex\");\n\tvaultIdBytes.set(vaultBytes, 32 - vaultBytes.length);\n\n\t// CID commitment as big-endian bytes (for nullifier)\n\tconst cidBytes = new Uint8Array(32);\n\tlet temp = cidCommitment;\n\tfor (let i = 31; i >= 0; i--) {\n\t\tcidBytes[i] = Number(temp & 0xffn);\n\t\ttemp = temp >> 8n;\n\t}\n\n\t// Nullifier = blake3(password || user_address || vault_id || cid_commitment)\n\tconst nullifierInput = new Uint8Array(128);\n\tnullifierInput.set(passwordBytes, 0);\n\tnullifierInput.set(userAddressBytes, 32);\n\tnullifierInput.set(vaultIdBytes, 64);\n\tnullifierInput.set(cidBytes, 96);\n\tconst nullifierHash = blake3(nullifierInput);\n\tconst nullifier =\n\t\t`0x${Buffer.from(nullifierHash).toString(\"hex\")}` as `0x${string}`;\n\n\tconst expectedHashBytes = Array.from(\n\t\tBuffer.from(expectedHash.slice(2), \"hex\"),\n\t);\n\tconst nullifierBytesArr = Array.from(nullifierHash);\n\n\treturn {\n\t\tinputs: {\n\t\t\t// Private\n\t\t\tpassword: Array.from(passwordBytes),\n\t\t\tmerkle_path: path.map((p) => p.toString()),\n\t\t\tmerkle_indices: indices.map((i) => i.toString()),\n\t\t\t// Public\n\t\t\texpected_hash: expectedHashBytes,\n\t\t\tmerkle_root: expectedRoot.toString(),\n\t\t\tuser_address: Array.from(userAddressBytes),\n\t\t\tvault_id: Array.from(vaultIdBytes),\n\t\t\tnullifier: nullifierBytesArr,\n\t\t\tcid_commitment: cidCommitment.toString(),\n\t\t},\n\t\tnullifier,\n\t\tcidCommitment: fieldToHex(cidCommitment),\n\t};\n}\n\n// create a commitment to the (vaultId, tag) combo using poseidon2\nexport async function computeTagCommitment(\n\tvaultId: string,\n\ttag: string,\n): Promise<bigint> {\n\tconst vaultIdBigInt = BigInt(vaultId);\n\n\t// Convert tag to field\n\tconst tagBytes = new TextEncoder().encode(tag);\n\tlet tagField = 0n;\n\tfor (let i = 0; i < Math.min(tagBytes.length, 31); i++) {\n\t\ttagField = (tagField << 8n) | BigInt(tagBytes[i]);\n\t}\n\n\tconst hash = await poseidon2Hash(vaultIdBigInt, tagField);\n\treturn hash;\n}\n"],"mappings":";;;;;;;AAQA,eAAsB,mBACrB,UACA,OACA,aACA,SACA,UAKE;CAEF,MAAM,EAAE,MAAM,YAAY,SADX,SAAS,KAAM,KAAK,UAAU,MAAM,IAAI,WAAW,CAAC,EACxB,OAAO,MAAM,MAAM,CAAC;CAE/D,MAAM,gBAAgB,WAAW,MAAM,KAAK;CAG5C,IAAI,UAAU;AACd,MAAK,IAAI,IAAI,GAAG,IAAI,YAAY,KAAK;EACpC,MAAM,UAAU,KAAK;EAErB,MAAM,CAAC,MAAM,SADG,QAAQ,OAAO,IACC,CAAC,SAAS,QAAQ,GAAG,CAAC,SAAS,QAAQ;AACvE,YAAU,MAAM,cAAc,MAAM,MAAM;;CAG3C,MAAM,eAAe,WAAW,SAAS,cAAc;AACvD,KAAI,YAAY,aACf,OAAM,IAAI,MACT,kCAAkC,QAAQ,aAAa,eACvD;CAIF,MAAM,gBAAgB,IAAI,WAAW,GAAG;AACxC,eAAc,IAAI,IAAI,aAAa,CAAC,OAAO,SAAS,CAAC,MAAM,GAAG,GAAG,CAAC;CAClE,MAAM,eAAe,UAAU,cAAc;CAG7C,MAAM,mBAAmB,IAAI,WAAW,GAAG;CAC3C,MAAM,YAAY,OAAO,KAAK,YAAY,MAAM,EAAE,EAAE,MAAM;AAC1D,kBAAiB,IAAI,WAAW,KAAK,UAAU,OAAO;CAGtD,MAAM,eAAe,IAAI,WAAW,GAAG;CACvC,MAAM,aAAa,OAAO,KAAK,QAAQ,MAAM,EAAE,EAAE,MAAM;AACvD,cAAa,IAAI,YAAY,KAAK,WAAW,OAAO;CAGpD,MAAM,WAAW,IAAI,WAAW,GAAG;CACnC,IAAI,OAAO;AACX,MAAK,IAAI,IAAI,IAAI,KAAK,GAAG,KAAK;AAC7B,WAAS,KAAK,OAAO,OAAO,KAAM;AAClC,SAAO,QAAQ;;CAIhB,MAAM,iBAAiB,IAAI,WAAW,IAAI;AAC1C,gBAAe,IAAI,eAAe,EAAE;AACpC,gBAAe,IAAI,kBAAkB,GAAG;AACxC,gBAAe,IAAI,cAAc,GAAG;AACpC,gBAAe,IAAI,UAAU,GAAG;CAChC,MAAM,gBAAgB,OAAO,eAAe;CAC5C,MAAM,YACL,KAAK,OAAO,KAAK,cAAc,CAAC,SAAS,MAAM;CAEhD,MAAM,oBAAoB,MAAM,KAC/B,OAAO,KAAK,aAAa,MAAM,EAAE,EAAE,MAAM,CACzC;CACD,MAAM,oBAAoB,MAAM,KAAK,cAAc;AAEnD,QAAO;EACN,QAAQ;GAEP,UAAU,MAAM,KAAK,cAAc;GACnC,aAAa,KAAK,KAAK,MAAM,EAAE,UAAU,CAAC;GAC1C,gBAAgB,QAAQ,KAAK,MAAM,EAAE,UAAU,CAAC;GAEhD,eAAe;GACf,aAAa,aAAa,UAAU;GACpC,cAAc,MAAM,KAAK,iBAAiB;GAC1C,UAAU,MAAM,KAAK,aAAa;GAClC,WAAW;GACX,gBAAgB,cAAc,UAAU;GACxC;EACD;EACA,eAAe,WAAW,cAAc;EACxC;;AAIF,eAAsB,qBACrB,SACA,KACkB;CAClB,MAAM,gBAAgB,OAAO,QAAQ;CAGrC,MAAM,WAAW,IAAI,aAAa,CAAC,OAAO,IAAI;CAC9C,IAAI,WAAW;AACf,MAAK,IAAI,IAAI,GAAG,IAAI,KAAK,IAAI,SAAS,QAAQ,GAAG,EAAE,IAClD,YAAY,YAAY,KAAM,OAAO,SAAS,GAAG;AAIlD,QADa,MAAM,cAAc,eAAe,SAAS"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rand.d.ts","names":[],"sources":["../../src/crypto/rand.ts"],"sourcesContent":[],"mappings":";iBAYgB,eAAA,CAAA,GAAmB;AAAnB,iBASA,eAAA,CATmB,KAAA,EASI,UATQ,CAAA,EASK,UATL,CASgB,WAThB,CAAA"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region src/crypto/rand.ts
|
|
2
|
+
function getCrypto() {
|
|
3
|
+
if (typeof globalThis.crypto !== "undefined") return globalThis.crypto;
|
|
4
|
+
throw new Error("No crypto available - are you in Node < 19?");
|
|
5
|
+
}
|
|
6
|
+
function getSubtleCrypto() {
|
|
7
|
+
if (typeof window !== "undefined" && window.crypto) return window.crypto.subtle;
|
|
8
|
+
else return getCrypto().subtle;
|
|
9
|
+
}
|
|
10
|
+
function getRandomValues(array) {
|
|
11
|
+
if (typeof window !== "undefined" && window.crypto) return window.crypto.getRandomValues(array);
|
|
12
|
+
else return getCrypto().getRandomValues(array);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
//#endregion
|
|
16
|
+
export { getRandomValues, getSubtleCrypto };
|
|
17
|
+
//# sourceMappingURL=rand.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rand.js","names":[],"sources":["../../src/crypto/rand.ts"],"sourcesContent":["function getCrypto(): Crypto {\n\tif (typeof globalThis.crypto !== \"undefined\") {\n\t\treturn globalThis.crypto;\n\t}\n\n\t// Node 19+ has globalThis.crypto, but for older versions:\n\tthrow new Error(\"No crypto available - are you in Node < 19?\");\n}\n\n// For Node 15-18, you might need top-level await or lazy init:\nlet cryptoModule: Crypto | null = null;\n\nexport function getSubtleCrypto(): SubtleCrypto {\n\tif (typeof window !== \"undefined\" && window.crypto) {\n\t\treturn window.crypto.subtle;\n\t} else {\n\t\tconst webcrypto = getCrypto();\n\t\treturn webcrypto.subtle as SubtleCrypto;\n\t}\n}\n\nexport function getRandomValues(array: Uint8Array): Uint8Array<ArrayBuffer> {\n\tif (typeof window !== \"undefined\" && window.crypto) {\n\t\treturn window.crypto.getRandomValues(array) as Uint8Array<ArrayBuffer>;\n\t} else {\n\t\tconst webcrypto = getCrypto();\n\t\treturn webcrypto.getRandomValues(array) as Uint8Array<ArrayBuffer>;\n\t}\n}\n"],"mappings":";AAAA,SAAS,YAAoB;AAC5B,KAAI,OAAO,WAAW,WAAW,YAChC,QAAO,WAAW;AAInB,OAAM,IAAI,MAAM,8CAA8C;;AAM/D,SAAgB,kBAAgC;AAC/C,KAAI,OAAO,WAAW,eAAe,OAAO,OAC3C,QAAO,OAAO,OAAO;KAGrB,QADkB,WAAW,CACZ;;AAInB,SAAgB,gBAAgB,OAA4C;AAC3E,KAAI,OAAO,WAAW,eAAe,OAAO,OAC3C,QAAO,OAAO,OAAO,gBAAgB,MAAM;KAG3C,QADkB,WAAW,CACZ,gBAAgB,MAAM"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { Account, Address, Hex } from "viem";
|
|
2
|
+
|
|
3
|
+
//#region src/deployContract.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Deploys HonkVerifier (circuit-specific)
|
|
7
|
+
*/
|
|
8
|
+
declare function deployVerifier({
|
|
9
|
+
account
|
|
10
|
+
}: {
|
|
11
|
+
account: Account;
|
|
12
|
+
}): Promise<{
|
|
13
|
+
verifierAddress: Address;
|
|
14
|
+
verifierAbi: any;
|
|
15
|
+
}>;
|
|
16
|
+
/**
|
|
17
|
+
* Deploys ZKGate (universal, verifier-agnostic)
|
|
18
|
+
*/
|
|
19
|
+
declare function deployZKGate({
|
|
20
|
+
account,
|
|
21
|
+
verifierAddress,
|
|
22
|
+
treasuryAddress,
|
|
23
|
+
vaultCreationFee
|
|
24
|
+
}: {
|
|
25
|
+
account: Account;
|
|
26
|
+
verifierAddress: Address;
|
|
27
|
+
treasuryAddress: Address;
|
|
28
|
+
vaultCreationFee: bigint;
|
|
29
|
+
}): Promise<{
|
|
30
|
+
zkGateAddress: Address;
|
|
31
|
+
zkGateAbi: any;
|
|
32
|
+
}>;
|
|
33
|
+
/**
|
|
34
|
+
* Deploys both contracts
|
|
35
|
+
*/
|
|
36
|
+
declare function deployContracts({
|
|
37
|
+
account
|
|
38
|
+
}: {
|
|
39
|
+
account: Account;
|
|
40
|
+
}): Promise<{
|
|
41
|
+
verifierAddress: Address;
|
|
42
|
+
zkGateAddress: Address;
|
|
43
|
+
verifierAbi: any;
|
|
44
|
+
zkGateAbi: any;
|
|
45
|
+
}>;
|
|
46
|
+
/**
|
|
47
|
+
* Verifies a proof using a deployed verifier contract
|
|
48
|
+
*/
|
|
49
|
+
declare function verifyProof({
|
|
50
|
+
contractAddress,
|
|
51
|
+
abi,
|
|
52
|
+
proof,
|
|
53
|
+
publicInputs
|
|
54
|
+
}: {
|
|
55
|
+
contractAddress: Address;
|
|
56
|
+
abi: any;
|
|
57
|
+
proof: Hex;
|
|
58
|
+
publicInputs: Hex[];
|
|
59
|
+
}): Promise<boolean>;
|
|
60
|
+
//#endregion
|
|
61
|
+
export { deployContracts, deployVerifier, deployZKGate, verifyProof };
|
|
62
|
+
//# sourceMappingURL=deployContract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deployContract.d.ts","names":[],"sources":["../src/deployContract.ts"],"sourcesContent":[],"mappings":";;;;;;AAgJA;AACC,iBADqB,cAAA,CACrB;EAAA;CAAA,EAAA;EAES,OAAA,EAAA,OAAA;CAEQ,CAAA,EADd,OACc,CAAA;EADd,eAAA,EACc,OADd;EAAO,WAAA,EAAA,GAAA;AAyGX,CAAA,CAAA;;;;AAIC,iBAJqB,YAAA,CAIrB;EAAA,OAAA;EAAA,eAAA;EAAA,eAAA;EAAA;CAAA,EAAA;EAES,OAAA,EAAA,OAAA;EACQ,eAAA,EAAA,OAAA;EACA,eAAA,EAAA,OAAA;EAGF,gBAAA,EAAA,MAAA;CADZ,CAAA,EAAA,OAAA,CAAA;EAAO,aAAA,EACK,OADL;EAoDW,SAAA,EAAA,GAAA;CACrB,CAAA;;;;AAGG,iBAJkB,eAAA,CAIlB;EAAA;AA2BJ,CA3BI,EAAA;EAAO,OAAA,EADD,OACC;AA2BX,CAAA,CAAA,EA3BI,OA2BkB,CAAA;EACrB,eAAA,EA3BiB,OA2BjB;EACA,aAAA,EA3Be,OA2Bf;EACA,WAAA,EAAA,GAAA;EACA,SAAA,EAAA,GAAA;CAEiB,CAAA;;;;AAIP,iBAVW,WAAA,CAUX;EAAA,eAAA;EAAA,GAAA;EAAA,KAAA;EAAA;CAAA,EAAA;mBAJO;;SAEV;gBACO;IACX"}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import { require_preimage } from "./circuits/preimage/target/preimage.js";
|
|
2
|
+
import { readFileSync } from "fs";
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
4
|
+
import { dirname, join } from "path";
|
|
5
|
+
import { createPublicClient, createWalletClient, encodeDeployData, http, parseEther } from "viem";
|
|
6
|
+
import solc from "solc";
|
|
7
|
+
import { Barretenberg, UltraHonkBackend } from "@aztec/bb.js";
|
|
8
|
+
import { baseSepolia } from "viem/chains";
|
|
9
|
+
|
|
10
|
+
//#region src/deployContract.ts
|
|
11
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
const circuit = require_preimage();
|
|
13
|
+
const currentChain = baseSepolia;
|
|
14
|
+
/**
|
|
15
|
+
* Compiles verifier from circuit
|
|
16
|
+
*/
|
|
17
|
+
async function compileVerifier() {
|
|
18
|
+
const api = await Barretenberg.new({ threads: 1 });
|
|
19
|
+
const backend = new UltraHonkBackend(circuit.bytecode, api);
|
|
20
|
+
const vk = await backend.getVerificationKey({ verifierTarget: "evm" });
|
|
21
|
+
const verifierSource = await backend.getSolidityVerifier(vk, { verifierTarget: "evm" });
|
|
22
|
+
const input = {
|
|
23
|
+
language: "Solidity",
|
|
24
|
+
sources: { "PreimageVerifier.sol": { content: verifierSource } },
|
|
25
|
+
settings: {
|
|
26
|
+
metadata: {
|
|
27
|
+
appendCBOR: false,
|
|
28
|
+
useLiteralContent: false
|
|
29
|
+
},
|
|
30
|
+
optimizer: {
|
|
31
|
+
enabled: true,
|
|
32
|
+
runs: 1
|
|
33
|
+
},
|
|
34
|
+
outputSelection: { "*": { "*": ["abi", "evm.bytecode"] } }
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
const output = JSON.parse(solc.compile(JSON.stringify(input)));
|
|
38
|
+
if (output.errors?.some((e) => e.severity === "error")) {
|
|
39
|
+
console.error("Compilation errors:", output.errors.filter((e) => e.severity === "error"));
|
|
40
|
+
throw new Error("Verifier compilation failed");
|
|
41
|
+
}
|
|
42
|
+
const contracts = {};
|
|
43
|
+
for (const [name, contract] of Object.entries(output.contracts["PreimageVerifier.sol"])) contracts[name] = {
|
|
44
|
+
abi: contract.abi,
|
|
45
|
+
bytecode: contract.evm.bytecode.object
|
|
46
|
+
};
|
|
47
|
+
return contracts;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Compiles ZKGate
|
|
51
|
+
*/
|
|
52
|
+
function compileZKGate() {
|
|
53
|
+
const zkGateSource = readFileSync(join(__dirname, "..", "./contracts/src", "ZKGate.sol"), "utf-8");
|
|
54
|
+
const input = {
|
|
55
|
+
language: "Solidity",
|
|
56
|
+
sources: { "ZKGate.sol": { content: zkGateSource } },
|
|
57
|
+
settings: {
|
|
58
|
+
metadata: {
|
|
59
|
+
appendCBOR: false,
|
|
60
|
+
useLiteralContent: false
|
|
61
|
+
},
|
|
62
|
+
optimizer: {
|
|
63
|
+
enabled: true,
|
|
64
|
+
runs: 200
|
|
65
|
+
},
|
|
66
|
+
outputSelection: { "*": { "*": ["abi", "evm.bytecode"] } }
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
const output = JSON.parse(solc.compile(JSON.stringify(input)));
|
|
70
|
+
if (output.errors?.some((e) => e.severity === "error")) {
|
|
71
|
+
console.error("Compilation errors:", output.errors.filter((e) => e.severity === "error"));
|
|
72
|
+
throw new Error("ZKGate compilation failed");
|
|
73
|
+
}
|
|
74
|
+
const zkGate = output.contracts["ZKGate.sol"]["ZKGate"];
|
|
75
|
+
return {
|
|
76
|
+
abi: zkGate.abi,
|
|
77
|
+
bytecode: zkGate.evm.bytecode.object
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Links library addresses into bytecode
|
|
82
|
+
*/
|
|
83
|
+
function linkBytecode(bytecode, libraries) {
|
|
84
|
+
let linked = bytecode;
|
|
85
|
+
for (const [, libAddress] of Object.entries(libraries)) linked = linked.replace(/__\$[a-fA-F0-9]{34}\$__/g, libAddress.slice(2).toLowerCase());
|
|
86
|
+
const remaining = linked.match(/__\$[a-fA-F0-9]{34}\$__/);
|
|
87
|
+
if (remaining) throw new Error(`Unlinked library: ${remaining[0]}`);
|
|
88
|
+
return `0x${linked}`;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Deploys HonkVerifier (circuit-specific)
|
|
92
|
+
*/
|
|
93
|
+
async function deployVerifier({ account }) {
|
|
94
|
+
console.log("Compiling verifier...");
|
|
95
|
+
const contracts = await compileVerifier();
|
|
96
|
+
const rpcUrl = process.env.CHAIN_RPC_URL;
|
|
97
|
+
if (!rpcUrl) throw new Error("CHAIN_RPC_URL environment variable is required");
|
|
98
|
+
const publicClient = createPublicClient({ transport: http(rpcUrl) });
|
|
99
|
+
const walletClient = createWalletClient({
|
|
100
|
+
account,
|
|
101
|
+
transport: http(rpcUrl)
|
|
102
|
+
});
|
|
103
|
+
console.log("Deploying ZKTranscriptLib...");
|
|
104
|
+
const libBytecode = contracts["ZKTranscriptLib"]?.bytecode;
|
|
105
|
+
if (!libBytecode) throw new Error("ZKTranscriptLib not found");
|
|
106
|
+
console.log("Estimating gas...");
|
|
107
|
+
const gasEstimate = await publicClient.estimateGas({
|
|
108
|
+
data: `0x${libBytecode}`,
|
|
109
|
+
account: walletClient.account.address
|
|
110
|
+
});
|
|
111
|
+
console.log("Gas estimate:", gasEstimate);
|
|
112
|
+
const gasPrice = await publicClient.getGasPrice();
|
|
113
|
+
await publicClient.getTransactionCount({ address: walletClient.account.address });
|
|
114
|
+
console.log("Sending transaction...");
|
|
115
|
+
const libHash = await walletClient.sendTransaction({
|
|
116
|
+
data: `0x${libBytecode}`,
|
|
117
|
+
gas: gasEstimate + gasEstimate / 10n,
|
|
118
|
+
gasPrice,
|
|
119
|
+
chain: currentChain
|
|
120
|
+
});
|
|
121
|
+
const libAddress = (await publicClient.waitForTransactionReceipt({ hash: libHash })).contractAddress;
|
|
122
|
+
console.log(`ZKTranscriptLib deployed: ${libAddress}`);
|
|
123
|
+
console.log("Deploying HonkVerifier...");
|
|
124
|
+
const verifier = contracts["HonkVerifier"];
|
|
125
|
+
if (!verifier) throw new Error("HonkVerifier not found");
|
|
126
|
+
const linkedBytecode = linkBytecode(verifier.bytecode, { ZKTranscriptLib: libAddress });
|
|
127
|
+
const verifierGasEstimate = await publicClient.estimateGas({
|
|
128
|
+
data: linkedBytecode,
|
|
129
|
+
account: walletClient.account.address
|
|
130
|
+
});
|
|
131
|
+
console.log("Verifier gas estimate:", verifierGasEstimate);
|
|
132
|
+
await publicClient.getTransactionCount({ address: walletClient.account.address });
|
|
133
|
+
console.log("Sending transaction...");
|
|
134
|
+
const verifierHash = await walletClient.sendTransaction({
|
|
135
|
+
data: linkedBytecode,
|
|
136
|
+
gas: verifierGasEstimate + verifierGasEstimate / 10n,
|
|
137
|
+
gasPrice,
|
|
138
|
+
chain: currentChain
|
|
139
|
+
});
|
|
140
|
+
const verifierReceipt = await publicClient.waitForTransactionReceipt({ hash: verifierHash });
|
|
141
|
+
console.log("Receipt status:", verifierReceipt.status);
|
|
142
|
+
console.log("Contract address from receipt:", verifierReceipt.contractAddress);
|
|
143
|
+
const code = await publicClient.getCode({ address: verifierReceipt.contractAddress });
|
|
144
|
+
console.log("Code length:", code?.length);
|
|
145
|
+
console.log("Has code:", code && code !== "0x" && code.length > 2);
|
|
146
|
+
const verifierAddress = verifierReceipt.contractAddress;
|
|
147
|
+
console.log(`HonkVerifier deployed: ${verifierAddress}`);
|
|
148
|
+
return {
|
|
149
|
+
verifierAddress,
|
|
150
|
+
verifierAbi: verifier.abi
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Deploys ZKGate (universal, verifier-agnostic)
|
|
155
|
+
*/
|
|
156
|
+
async function deployZKGate({ account, verifierAddress, treasuryAddress, vaultCreationFee }) {
|
|
157
|
+
console.log("Compiling ZKGate...");
|
|
158
|
+
const zkGate = compileZKGate();
|
|
159
|
+
const rpcUrl = process.env.CHAIN_RPC_URL;
|
|
160
|
+
if (!rpcUrl) throw new Error("CHAIN_RPC_URL environment variable is required");
|
|
161
|
+
const publicClient = createPublicClient({ transport: http(rpcUrl) });
|
|
162
|
+
const walletClient = createWalletClient({
|
|
163
|
+
account,
|
|
164
|
+
transport: http(rpcUrl)
|
|
165
|
+
});
|
|
166
|
+
console.log("Deploying ZKGate...");
|
|
167
|
+
const deployData = encodeDeployData({
|
|
168
|
+
abi: zkGate.abi,
|
|
169
|
+
bytecode: `0x${zkGate.bytecode}`,
|
|
170
|
+
args: [
|
|
171
|
+
verifierAddress,
|
|
172
|
+
treasuryAddress,
|
|
173
|
+
vaultCreationFee
|
|
174
|
+
]
|
|
175
|
+
});
|
|
176
|
+
const gasPrice = await publicClient.getGasPrice();
|
|
177
|
+
const gasEstimate = await publicClient.estimateGas({
|
|
178
|
+
data: deployData,
|
|
179
|
+
account: walletClient.account.address
|
|
180
|
+
});
|
|
181
|
+
const zkGateHash = await walletClient.sendTransaction({
|
|
182
|
+
data: deployData,
|
|
183
|
+
gas: gasEstimate + gasEstimate / 10n,
|
|
184
|
+
gasPrice,
|
|
185
|
+
chain: currentChain
|
|
186
|
+
});
|
|
187
|
+
const zkGateAddress = (await publicClient.waitForTransactionReceipt({ hash: zkGateHash })).contractAddress;
|
|
188
|
+
console.log(`ZKGate deployed: ${zkGateAddress}`);
|
|
189
|
+
return {
|
|
190
|
+
zkGateAddress,
|
|
191
|
+
zkGateAbi: zkGate.abi
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Deploys both contracts
|
|
196
|
+
*/
|
|
197
|
+
async function deployContracts({ account }) {
|
|
198
|
+
const { verifierAddress, verifierAbi } = await deployVerifier({ account });
|
|
199
|
+
const { zkGateAddress, zkGateAbi } = await deployZKGate({
|
|
200
|
+
account,
|
|
201
|
+
verifierAddress,
|
|
202
|
+
treasuryAddress: account.address,
|
|
203
|
+
vaultCreationFee: parseEther("0.001")
|
|
204
|
+
});
|
|
205
|
+
return {
|
|
206
|
+
verifierAddress,
|
|
207
|
+
zkGateAddress,
|
|
208
|
+
verifierAbi,
|
|
209
|
+
zkGateAbi
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Verifies a proof using a deployed verifier contract
|
|
214
|
+
*/
|
|
215
|
+
async function verifyProof({ contractAddress, abi, proof, publicInputs }) {
|
|
216
|
+
const rpcUrl = process.env.CHAIN_RPC_URL;
|
|
217
|
+
if (!rpcUrl) throw new Error("CHAIN_RPC_URL environment variable is required");
|
|
218
|
+
const result = await createPublicClient({ transport: http(rpcUrl) }).readContract({
|
|
219
|
+
address: contractAddress,
|
|
220
|
+
abi,
|
|
221
|
+
functionName: "verify",
|
|
222
|
+
args: [proof, publicInputs]
|
|
223
|
+
});
|
|
224
|
+
console.log(`Verification result: ${result}`);
|
|
225
|
+
return result;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
//#endregion
|
|
229
|
+
export { deployContracts, deployVerifier, deployZKGate, verifyProof };
|
|
230
|
+
//# sourceMappingURL=deployContract.js.map
|