@pinionengineering/prover-client 0.1.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/dist/types.js ADDED
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Wire format types for the pinion-prover service.
3
+ *
4
+ * All byte fields (G1/G2 curve points, scalars, seeds) are transmitted as
5
+ * standard base64 strings inside JSON objects. The Go service uses encoding/json
6
+ * which encodes []byte as base64 automatically.
7
+ */
8
+ export {};
9
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * SW-Pub proof verification.
3
+ *
4
+ * Implements the public-key verification equation from §3.3 of
5
+ * Shacham & Waters, "Compact Proofs of Retrievability", ASIACRYPT 2008:
6
+ *
7
+ * e(σ, G₂) == e(Σₜ νₜ·H(λ‖idᵢₜ) + Σⱼ μⱼ·uⱼ, v)
8
+ *
9
+ * where:
10
+ * σ proof accumulator G1 point (from server)
11
+ * G₂ generator of G2
12
+ * νₜ, iₜ blinding coefficients and block indices (re-derived from seed)
13
+ * H(λ‖id) SHA-256(λ‖id) mod q · G₁ (ROM hash-to-G1)
14
+ * μⱼ per-sector Z_q scalars (from server)
15
+ * uⱼ public key G1 elements (from client_setup)
16
+ * v V = α·G₂, public key G2 point (from client_setup)
17
+ *
18
+ * Correctness: any honest server response satisfies this equation because:
19
+ * σ = Σₜ νₜ·σᵢₜ and σᵢ = α·(H(λ‖idᵢ) + Σⱼ fᵢⱼ·uⱼ)
20
+ * Substituting and using bilinearity of e gives the identity.
21
+ *
22
+ * Security: under the computational Diffie-Hellman assumption, a server
23
+ * cannot forge a passing response without holding the tagged blocks.
24
+ *
25
+ * Ports verifyPubCore() in storage-proofs/por/sw/pub.go.
26
+ */
27
+ import type { WireClientSetup } from './types.js';
28
+ export interface VerifyParams {
29
+ /**
30
+ * The parsed WireClientSetup from the client_setup blob.
31
+ * Obtain via parseClientSetup() or directly from ParsedSetup.clientSetup.
32
+ */
33
+ clientSetup: WireClientSetup;
34
+ /**
35
+ * Block IDs (CID.Bytes()) in TagList order, concatenated across all challenged
36
+ * roots in the same order as the roots array in the ProveRequest.
37
+ * These are the same byte slices stored in ParsedRoot.blockIds.
38
+ */
39
+ blockIds: Uint8Array[];
40
+ /**
41
+ * The challenge string that was sent to POST /prove.
42
+ * This is buildChallenge()'s return value: base64(JSON(WireChallenge)).
43
+ */
44
+ challenge: string;
45
+ /**
46
+ * Raw bytes from the POST /prove response body.
47
+ * Despite Content-Type: application/octet-stream, the body is JSON (WireProof).
48
+ */
49
+ proofBytes: Uint8Array;
50
+ }
51
+ /**
52
+ * Cryptographically verify a storage proof returned by pinion-prover.
53
+ *
54
+ * Returns true if and only if the pairing equation holds. A false result means
55
+ * the server either does not hold the data or returned a malformed proof.
56
+ *
57
+ * This is what the website's StorageHealthContext should call instead of
58
+ * checking resp.ok alone — HTTP 200 only proves the server responded, not that
59
+ * it holds the data.
60
+ */
61
+ export declare function verifyProof(params: VerifyParams): boolean;
62
+ /**
63
+ * Decode a base64 client_setup blob into a WireClientSetup.
64
+ * The blob is base64(JSON(WireClientSetup)) — there are two layers of encoding.
65
+ */
66
+ export declare function parseClientSetup(clientSetupBase64: string): WireClientSetup;
67
+ //# sourceMappingURL=verify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAcH,OAAO,KAAK,EAAE,eAAe,EAA4B,MAAM,YAAY,CAAC;AAE5E,MAAM,WAAW,YAAY;IAC3B;;;OAGG;IACH,WAAW,EAAE,eAAe,CAAC;IAC7B;;;;OAIG;IACH,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB;;;OAGG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,UAAU,EAAE,UAAU,CAAC;CACxB;AAED;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAMzD;AAoDD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,iBAAiB,EAAE,MAAM,GAAG,eAAe,CAE3E"}
package/dist/verify.js ADDED
@@ -0,0 +1,94 @@
1
+ /**
2
+ * SW-Pub proof verification.
3
+ *
4
+ * Implements the public-key verification equation from §3.3 of
5
+ * Shacham & Waters, "Compact Proofs of Retrievability", ASIACRYPT 2008:
6
+ *
7
+ * e(σ, G₂) == e(Σₜ νₜ·H(λ‖idᵢₜ) + Σⱼ μⱼ·uⱼ, v)
8
+ *
9
+ * where:
10
+ * σ proof accumulator G1 point (from server)
11
+ * G₂ generator of G2
12
+ * νₜ, iₜ blinding coefficients and block indices (re-derived from seed)
13
+ * H(λ‖id) SHA-256(λ‖id) mod q · G₁ (ROM hash-to-G1)
14
+ * μⱼ per-sector Z_q scalars (from server)
15
+ * uⱼ public key G1 elements (from client_setup)
16
+ * v V = α·G₂, public key G2 point (from client_setup)
17
+ *
18
+ * Correctness: any honest server response satisfies this equation because:
19
+ * σ = Σₜ νₜ·σᵢₜ and σᵢ = α·(H(λ‖idᵢ) + Σⱼ fᵢⱼ·uⱼ)
20
+ * Substituting and using bilinearity of e gives the identity.
21
+ *
22
+ * Security: under the computational Diffie-Hellman assumption, a server
23
+ * cannot forge a passing response without holding the tagged blocks.
24
+ *
25
+ * Ports verifyPubCore() in storage-proofs/por/sw/pub.go.
26
+ */
27
+ import { atePairing, fp12Equal, g1Add, g1FromBytes, g1ScalarMult, g2FromBytes, bytesToBigInt, G2_BASE, } from './bn254.js';
28
+ import { base64ToBytes, blockHashG1, deriveIndicesAndCoeffs } from './challenge.js';
29
+ /**
30
+ * Cryptographically verify a storage proof returned by pinion-prover.
31
+ *
32
+ * Returns true if and only if the pairing equation holds. A false result means
33
+ * the server either does not hold the data or returned a malformed proof.
34
+ *
35
+ * This is what the website's StorageHealthContext should call instead of
36
+ * checking resp.ok alone — HTTP 200 only proves the server responded, not that
37
+ * it holds the data.
38
+ */
39
+ export function verifyProof(params) {
40
+ try {
41
+ return _verifyProof(params);
42
+ }
43
+ catch {
44
+ return false;
45
+ }
46
+ }
47
+ function _verifyProof(params) {
48
+ const { clientSetup, blockIds, challenge, proofBytes } = params;
49
+ // 1. Decode the challenge to recover the seed used for derivation.
50
+ const wireChal = JSON.parse(new TextDecoder().decode(base64ToBytes(challenge)));
51
+ const seed = base64ToBytes(wireChal.seed);
52
+ // 2. Re-derive indices and coefficients deterministically.
53
+ // Both sides (browser + server) run this on the same (seed, ids) to agree
54
+ // on which blocks were sampled without communicating the full index list.
55
+ const { indices, coeffs } = deriveIndicesAndCoeffs(seed, blockIds, wireChal.c);
56
+ // 3. Decode the proof (JSON despite the octet-stream content-type).
57
+ const wireProof = JSON.parse(new TextDecoder().decode(proofBytes));
58
+ const sigma = g1FromBytes(base64ToBytes(wireProof.sigma));
59
+ const mu = wireProof.mu.map((m) => bytesToBigInt(base64ToBytes(m)));
60
+ // 4. Decode the public key from client_setup.
61
+ const name = base64ToBytes(clientSetup.name);
62
+ const V = g2FromBytes(base64ToBytes(clientSetup.v));
63
+ const U = clientSetup.u.map((u) => g1FromBytes(base64ToBytes(u)));
64
+ // 5. Compute A = Σₜ νₜ·H(λ‖ids[iₜ]) + Σⱼ μⱼ·uⱼ ∈ G₁
65
+ let A = null;
66
+ for (let t = 0; t < indices.length; t++) {
67
+ const idx = indices[t] ?? 0;
68
+ const nu = coeffs[t] ?? 0n;
69
+ const term = g1ScalarMult(blockHashG1(name, blockIds[idx] ?? new Uint8Array()), nu);
70
+ A = A === null ? term : g1Add(A, term);
71
+ }
72
+ for (let j = 0; j < U.length; j++) {
73
+ const uj = U[j];
74
+ const muj = mu[j];
75
+ if (uj === undefined || muj === undefined)
76
+ continue;
77
+ const term = g1ScalarMult(uj, muj);
78
+ A = A === null ? term : g1Add(A, term);
79
+ }
80
+ if (A === null)
81
+ return false;
82
+ // 6. Check e(σ, G₂) == e(A, v)
83
+ const lhs = atePairing(sigma, G2_BASE);
84
+ const rhs = atePairing(A, V);
85
+ return fp12Equal(lhs, rhs);
86
+ }
87
+ /**
88
+ * Decode a base64 client_setup blob into a WireClientSetup.
89
+ * The blob is base64(JSON(WireClientSetup)) — there are two layers of encoding.
90
+ */
91
+ export function parseClientSetup(clientSetupBase64) {
92
+ return JSON.parse(new TextDecoder().decode(base64ToBytes(clientSetupBase64)));
93
+ }
94
+ //# sourceMappingURL=verify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.js","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@pinionengineering/prover-client",
3
+ "version": "0.1.0",
4
+ "description": "JavaScript/TypeScript client for the pinion-prover storage-proof service. Builds SW-Pub challenges and cryptographically verifies proofs using BN254 pairings.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "default": "./dist/index.js",
12
+ "types": "./dist/index.d.ts"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "scripts": {
19
+ "build": "tsc",
20
+ "prepare": "npm run build",
21
+ "build:watch": "tsc --watch",
22
+ "typecheck": "tsc --noEmit",
23
+ "test": "npm run build && node test/verify.test.mjs",
24
+ "test:gen": "cd testdata/gen && go run . > ../vectors.json"
25
+ },
26
+ "dependencies": {
27
+ "@noble/curves": "^1.4.0",
28
+ "@noble/hashes": "^1.4.0"
29
+ },
30
+ "devDependencies": {
31
+ "@types/node": "^20.0.0",
32
+ "typescript": "^5.4.0"
33
+ },
34
+ "engines": {
35
+ "node": ">=18"
36
+ },
37
+ "keywords": [
38
+ "pinion",
39
+ "ipfs",
40
+ "storage-proof",
41
+ "por",
42
+ "bn254",
43
+ "alt-bn128",
44
+ "shacham-waters"
45
+ ]
46
+ }