@fide.work/fcp 0.0.1-alpha.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/README.md +18 -0
- package/dist/attestation/create.d.ts +173 -0
- package/dist/attestation/create.js +179 -0
- package/dist/attestation/index.d.ts +7 -0
- package/dist/attestation/index.js +7 -0
- package/dist/attestation/verify.d.ts +56 -0
- package/dist/attestation/verify.js +94 -0
- package/dist/broadcasting/config.d.ts +27 -0
- package/dist/broadcasting/config.js +22 -0
- package/dist/broadcasting/index.d.ts +7 -0
- package/dist/broadcasting/index.js +7 -0
- package/dist/broadcasting/registry.d.ts +111 -0
- package/dist/broadcasting/registry.js +99 -0
- package/dist/experimental/attestation/create.d.ts +173 -0
- package/dist/experimental/attestation/create.js +188 -0
- package/dist/experimental/attestation/index.d.ts +7 -0
- package/dist/experimental/attestation/index.js +7 -0
- package/dist/experimental/attestation/verify.d.ts +56 -0
- package/dist/experimental/attestation/verify.js +94 -0
- package/dist/experimental/broadcasting/config.d.ts +27 -0
- package/dist/experimental/broadcasting/config.js +22 -0
- package/dist/experimental/broadcasting/index.d.ts +7 -0
- package/dist/experimental/broadcasting/index.js +7 -0
- package/dist/experimental/broadcasting/registry.d.ts +111 -0
- package/dist/experimental/broadcasting/registry.js +99 -0
- package/dist/experimental/index.d.ts +9 -0
- package/dist/experimental/index.js +13 -0
- package/dist/experimental/merkle/index.d.ts +6 -0
- package/dist/experimental/merkle/index.js +6 -0
- package/dist/experimental/merkle/tree.d.ts +72 -0
- package/dist/experimental/merkle/tree.js +154 -0
- package/dist/experimental/signing/ed25519.d.ts +116 -0
- package/dist/experimental/signing/ed25519.js +161 -0
- package/dist/experimental/signing/eip191.d.ts +50 -0
- package/dist/experimental/signing/eip191.js +96 -0
- package/dist/experimental/signing/eip712.d.ts +112 -0
- package/dist/experimental/signing/eip712.js +187 -0
- package/dist/experimental/signing/index.d.ts +8 -0
- package/dist/experimental/signing/index.js +11 -0
- package/dist/fide-id/calculateFideId.d.ts +21 -0
- package/dist/fide-id/calculateFideId.js +53 -0
- package/dist/fide-id/calculateStatementFideId.d.ts +21 -0
- package/dist/fide-id/calculateStatementFideId.js +38 -0
- package/dist/fide-id/constants.d.ts +43 -0
- package/dist/fide-id/constants.js +55 -0
- package/dist/fide-id/index.d.ts +10 -0
- package/dist/fide-id/index.js +12 -0
- package/dist/fide-id/types.d.ts +52 -0
- package/dist/fide-id/types.js +5 -0
- package/dist/fide-id/utils.d.ts +30 -0
- package/dist/fide-id/utils.js +65 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +19 -0
- package/dist/merkle/index.d.ts +6 -0
- package/dist/merkle/index.js +6 -0
- package/dist/merkle/tree.d.ts +72 -0
- package/dist/merkle/tree.js +154 -0
- package/dist/schema/evaluations.d.ts +31 -0
- package/dist/schema/evaluations.js +31 -0
- package/dist/schema/index.d.ts +6 -0
- package/dist/schema/index.js +6 -0
- package/dist/schema/predicates.d.ts +110 -0
- package/dist/schema/predicates.js +122 -0
- package/dist/signing/ed25519.d.ts +116 -0
- package/dist/signing/ed25519.js +161 -0
- package/dist/signing/eip191.d.ts +50 -0
- package/dist/signing/eip191.js +96 -0
- package/dist/signing/eip712.d.ts +112 -0
- package/dist/signing/eip712.js +187 -0
- package/dist/signing/index.d.ts +8 -0
- package/dist/signing/index.js +11 -0
- package/dist/statement/build.d.ts +99 -0
- package/dist/statement/build.js +71 -0
- package/dist/statement/index.d.ts +6 -0
- package/dist/statement/index.js +6 -0
- package/dist/statement/policy.d.ts +33 -0
- package/dist/statement/policy.js +183 -0
- package/package.json +64 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FCP SDK Broadcasting Utilities
|
|
3
|
+
*
|
|
4
|
+
* Helpers for formatting attestations for JSONL registry files.
|
|
5
|
+
*
|
|
6
|
+
* Note: This module provides formatting helpers. Actual Git operations
|
|
7
|
+
* (commit, push) should be handled by your application using libraries
|
|
8
|
+
* like `simple-git` or `isomorphic-git`.
|
|
9
|
+
*/
|
|
10
|
+
import type { AttestationResult } from "../attestation/index.js";
|
|
11
|
+
import type { Statement } from "../statement/build.js";
|
|
12
|
+
/**
|
|
13
|
+
* Statement object in lean JSONL format
|
|
14
|
+
* Uses short keys for efficiency: s/sr, p/pr, o/or
|
|
15
|
+
*/
|
|
16
|
+
export interface JSONLStatement {
|
|
17
|
+
/** Subject Fide ID (full did:fide:0x... format) */
|
|
18
|
+
s: string;
|
|
19
|
+
/** Subject raw identifier */
|
|
20
|
+
sr: string;
|
|
21
|
+
/** Predicate Fide ID (full did:fide:0x... format) */
|
|
22
|
+
p: string;
|
|
23
|
+
/** Predicate raw identifier */
|
|
24
|
+
pr: string;
|
|
25
|
+
/** Object Fide ID (full did:fide:0x... format) */
|
|
26
|
+
o: string;
|
|
27
|
+
/** Object raw identifier */
|
|
28
|
+
or: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Lean attestation format for JSONL registry files
|
|
32
|
+
*
|
|
33
|
+
* Optimized for indexers: minimal verbosity, all data needed for verification
|
|
34
|
+
* and materialization. Each line is one attestation batch.
|
|
35
|
+
*
|
|
36
|
+
* Format matches canonical attestation data structure: {m, r, s, u}
|
|
37
|
+
* Indexer derives attestation Fide ID from these fields.
|
|
38
|
+
*/
|
|
39
|
+
export interface JSONLAttestation {
|
|
40
|
+
/** Method: Signing method (e.g., "ed25519", "eip712", "eip191") */
|
|
41
|
+
m: string;
|
|
42
|
+
/** User: CAIP-10 signer identifier */
|
|
43
|
+
u: string;
|
|
44
|
+
/** Root: Merkle root commitment */
|
|
45
|
+
r: string;
|
|
46
|
+
/** Signature: Cryptographic signature */
|
|
47
|
+
s: string;
|
|
48
|
+
/** Timestamp: ISO 8601 UTC timestamp */
|
|
49
|
+
t: string;
|
|
50
|
+
/** Data: Array of statements in this batch */
|
|
51
|
+
d: JSONLStatement[];
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Format an attestation result for JSONL output
|
|
55
|
+
*
|
|
56
|
+
* Converts an AttestationResult into the lean JSONL format optimized for indexers.
|
|
57
|
+
* Each line in the JSONL file should be one attestation batch (one signature covering
|
|
58
|
+
* multiple statements via Merkle root).
|
|
59
|
+
*
|
|
60
|
+
* Format uses short keys (m, u, r, s, t, d) matching the canonical attestation
|
|
61
|
+
* data structure. Indexer derives attestation Fide ID from {m, r, s, u}.
|
|
62
|
+
*
|
|
63
|
+
* @param attestationResult - The result from createAttestation
|
|
64
|
+
* @param statements - The original statements that were attested (must match statementFideIds order)
|
|
65
|
+
* @param signedAt - ISO timestamp when the attestation was signed (defaults to current time)
|
|
66
|
+
* @returns Formatted attestation ready for JSONL output
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```ts
|
|
70
|
+
* const statements = await buildStatementBatch([...]);
|
|
71
|
+
* const attestation = await createAttestation(statementFideIds, options);
|
|
72
|
+
* const jsonlAttestation = formatAttestationForJSONL(attestation, statements);
|
|
73
|
+
*
|
|
74
|
+
* // Write to JSONL file (one line per batch)
|
|
75
|
+
* fs.appendFileSync('attestation.jsonl', JSON.stringify(jsonlAttestation) + '\n');
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
export declare function formatAttestationForJSONL(attestationResult: AttestationResult, statements: Statement[], signedAt?: string): JSONLAttestation;
|
|
79
|
+
/**
|
|
80
|
+
* Generate the registry directory path for a given date
|
|
81
|
+
*
|
|
82
|
+
* Follows the YYYY/MM/DD structure required for Fide attestation registries.
|
|
83
|
+
* Uses UTC timezone for consistency across timezones.
|
|
84
|
+
*
|
|
85
|
+
* @param date - Date object (defaults to current UTC date)
|
|
86
|
+
* @returns Directory path (e.g., "2024/01/15")
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```ts
|
|
90
|
+
* const path = generateRegistryPath(new Date('2024-01-15T00:00:00Z'));
|
|
91
|
+
* // Result: "2024/01/15"
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
export declare function generateRegistryPath(date?: Date): string;
|
|
95
|
+
/**
|
|
96
|
+
* Generate a JSONL filename following the registry convention
|
|
97
|
+
*
|
|
98
|
+
* Format: YYYY-MM-DD-{HHmm}-{sequence}.jsonl
|
|
99
|
+
* Uses UTC timezone for consistency across timezones.
|
|
100
|
+
*
|
|
101
|
+
* @param date - Date object (defaults to current UTC date)
|
|
102
|
+
* @param sequence - Sequence number (defaults to 1)
|
|
103
|
+
* @returns Filename (e.g., "2024-01-15-1400-1.jsonl")
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* ```ts
|
|
107
|
+
* const filename = generateJSONLFilename(new Date('2024-01-15T14:00:00Z'), 1);
|
|
108
|
+
* // Result: "2024-01-15-1400-1.jsonl"
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
export declare function generateJSONLFilename(date?: Date, sequence?: number): string;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FCP SDK Broadcasting Utilities
|
|
3
|
+
*
|
|
4
|
+
* Helpers for formatting attestations for JSONL registry files.
|
|
5
|
+
*
|
|
6
|
+
* Note: This module provides formatting helpers. Actual Git operations
|
|
7
|
+
* (commit, push) should be handled by your application using libraries
|
|
8
|
+
* like `simple-git` or `isomorphic-git`.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Format an attestation result for JSONL output
|
|
12
|
+
*
|
|
13
|
+
* Converts an AttestationResult into the lean JSONL format optimized for indexers.
|
|
14
|
+
* Each line in the JSONL file should be one attestation batch (one signature covering
|
|
15
|
+
* multiple statements via Merkle root).
|
|
16
|
+
*
|
|
17
|
+
* Format uses short keys (m, u, r, s, t, d) matching the canonical attestation
|
|
18
|
+
* data structure. Indexer derives attestation Fide ID from {m, r, s, u}.
|
|
19
|
+
*
|
|
20
|
+
* @param attestationResult - The result from createAttestation
|
|
21
|
+
* @param statements - The original statements that were attested (must match statementFideIds order)
|
|
22
|
+
* @param signedAt - ISO timestamp when the attestation was signed (defaults to current time)
|
|
23
|
+
* @returns Formatted attestation ready for JSONL output
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```ts
|
|
27
|
+
* const statements = await buildStatementBatch([...]);
|
|
28
|
+
* const attestation = await createAttestation(statementFideIds, options);
|
|
29
|
+
* const jsonlAttestation = formatAttestationForJSONL(attestation, statements);
|
|
30
|
+
*
|
|
31
|
+
* // Write to JSONL file (one line per batch)
|
|
32
|
+
* fs.appendFileSync('attestation.jsonl', JSON.stringify(jsonlAttestation) + '\n');
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export function formatAttestationForJSONL(attestationResult, statements, signedAt = new Date().toISOString()) {
|
|
36
|
+
// Convert statements to lean JSONL format with short keys
|
|
37
|
+
const jsonlStatements = statements.map(stmt => ({
|
|
38
|
+
s: stmt.subjectFideId,
|
|
39
|
+
sr: stmt.subjectRawIdentifier,
|
|
40
|
+
p: stmt.predicateFideId,
|
|
41
|
+
pr: stmt.predicateRawIdentifier,
|
|
42
|
+
o: stmt.objectFideId,
|
|
43
|
+
or: stmt.objectRawIdentifier
|
|
44
|
+
}));
|
|
45
|
+
return {
|
|
46
|
+
m: attestationResult.attestationData.m,
|
|
47
|
+
u: attestationResult.attestationData.u,
|
|
48
|
+
r: attestationResult.merkleRoot,
|
|
49
|
+
s: attestationResult.attestationData.s,
|
|
50
|
+
t: signedAt,
|
|
51
|
+
d: jsonlStatements
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Generate the registry directory path for a given date
|
|
56
|
+
*
|
|
57
|
+
* Follows the YYYY/MM/DD structure required for Fide attestation registries.
|
|
58
|
+
* Uses UTC timezone for consistency across timezones.
|
|
59
|
+
*
|
|
60
|
+
* @param date - Date object (defaults to current UTC date)
|
|
61
|
+
* @returns Directory path (e.g., "2024/01/15")
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```ts
|
|
65
|
+
* const path = generateRegistryPath(new Date('2024-01-15T00:00:00Z'));
|
|
66
|
+
* // Result: "2024/01/15"
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
export function generateRegistryPath(date = new Date()) {
|
|
70
|
+
const year = date.getUTCFullYear();
|
|
71
|
+
const month = String(date.getUTCMonth() + 1).padStart(2, '0');
|
|
72
|
+
const day = String(date.getUTCDate()).padStart(2, '0');
|
|
73
|
+
return `${year}/${month}/${day}`;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Generate a JSONL filename following the registry convention
|
|
77
|
+
*
|
|
78
|
+
* Format: YYYY-MM-DD-{HHmm}-{sequence}.jsonl
|
|
79
|
+
* Uses UTC timezone for consistency across timezones.
|
|
80
|
+
*
|
|
81
|
+
* @param date - Date object (defaults to current UTC date)
|
|
82
|
+
* @param sequence - Sequence number (defaults to 1)
|
|
83
|
+
* @returns Filename (e.g., "2024-01-15-1400-1.jsonl")
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```ts
|
|
87
|
+
* const filename = generateJSONLFilename(new Date('2024-01-15T14:00:00Z'), 1);
|
|
88
|
+
* // Result: "2024-01-15-1400-1.jsonl"
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
export function generateJSONLFilename(date = new Date(), sequence = 1) {
|
|
92
|
+
const year = date.getUTCFullYear();
|
|
93
|
+
const month = String(date.getUTCMonth() + 1).padStart(2, '0');
|
|
94
|
+
const day = String(date.getUTCDate()).padStart(2, '0');
|
|
95
|
+
const hours = String(date.getUTCHours()).padStart(2, '0');
|
|
96
|
+
const minutes = String(date.getUTCMinutes()).padStart(2, '0');
|
|
97
|
+
const timeWindow = `${hours}${minutes}`;
|
|
98
|
+
return `${year}-${month}-${day}-${timeWindow}-${sequence}.jsonl`;
|
|
99
|
+
}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FCP SDK Attestation Utilities
|
|
3
|
+
*
|
|
4
|
+
* High-level helpers for creating and verifying attestations.
|
|
5
|
+
* Combines Fide ID calculation, Merkle trees, and signing.
|
|
6
|
+
*/
|
|
7
|
+
import type { FideId } from "../../fide-id/types.js";
|
|
8
|
+
import { type MerkleProof } from "../merkle/index.js";
|
|
9
|
+
/**
|
|
10
|
+
* Signing method identifier
|
|
11
|
+
*
|
|
12
|
+
* `ed25519` has no external dependency.
|
|
13
|
+
* `eip712` and `eip191` require the optional `viem` peer dependency.
|
|
14
|
+
*/
|
|
15
|
+
export type SigningMethod = 'ed25519' | 'eip712' | 'eip191';
|
|
16
|
+
/**
|
|
17
|
+
* Attestation data structure (baked into Fide ID)
|
|
18
|
+
* Uses short keys to match protocol: m, u, r, s
|
|
19
|
+
*/
|
|
20
|
+
export interface AttestationData {
|
|
21
|
+
/** Method: Signing standard used */
|
|
22
|
+
m: SigningMethod;
|
|
23
|
+
/** User: CAIP-10 signer identifier */
|
|
24
|
+
u: string;
|
|
25
|
+
/** Root: Merkle tree commitment */
|
|
26
|
+
r: string;
|
|
27
|
+
/** Signature: Cryptographic proof */
|
|
28
|
+
s: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Full attestation result
|
|
32
|
+
*/
|
|
33
|
+
export interface AttestationResult {
|
|
34
|
+
/** The Attestation Fide ID */
|
|
35
|
+
attestationFideId: FideId;
|
|
36
|
+
/** The raw attestation data */
|
|
37
|
+
attestationData: AttestationData;
|
|
38
|
+
/** The normalized JSON string (raw identifier) */
|
|
39
|
+
rawIdentifier: string;
|
|
40
|
+
/** The Merkle root */
|
|
41
|
+
merkleRoot: string;
|
|
42
|
+
/** Proofs for each statement, keyed by statement Fide ID */
|
|
43
|
+
proofs: Map<string, MerkleProof>;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Options for creating an attestation
|
|
47
|
+
*/
|
|
48
|
+
export interface CreateAttestationOptions {
|
|
49
|
+
/** The signing method to use (`eip712`/`eip191` require `viem` to be installed). */
|
|
50
|
+
method: SigningMethod;
|
|
51
|
+
/** CAIP-10 identifier for the signer (e.g., "eip155:1:0x...") */
|
|
52
|
+
caip10User: string;
|
|
53
|
+
/** Signing function - takes merkle root string, returns signature hex string */
|
|
54
|
+
sign: (merkleRoot: string) => Promise<string>;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Provenance statement linking a statement to its attestation
|
|
58
|
+
*/
|
|
59
|
+
export interface ProvenanceStatement {
|
|
60
|
+
subjectFideId: string;
|
|
61
|
+
predicateFideId: string;
|
|
62
|
+
objectFideId: string;
|
|
63
|
+
predicateRawIdentifier: string;
|
|
64
|
+
objectRawIdentifier: string;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Create an attestation for a batch of statement Fide IDs
|
|
68
|
+
*
|
|
69
|
+
* This function:
|
|
70
|
+
* 1. Builds a Merkle tree from the statement Fide IDs
|
|
71
|
+
* 2. Signs the Merkle root using the provided signing function
|
|
72
|
+
* 3. Creates the attestation data structure
|
|
73
|
+
* 4. Derives the Attestation Fide ID
|
|
74
|
+
*
|
|
75
|
+
* @param statementFideIds - Array of statement Fide IDs.
|
|
76
|
+
* @param options - Configuration options for operation.
|
|
77
|
+
* @paramDefault statementFideIds ["did:fide:0x10...", "did:fide:0x10..."]
|
|
78
|
+
* @paramDefault options {"method":"ed25519","caip10User":"ed25519:123...","sign":"async (root) => 'signature'"}
|
|
79
|
+
* @returns Full attestation result including ID, data, and proofs
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```ts
|
|
83
|
+
* import { createAttestation, signEd25519 } from '@fide.work/fcp';
|
|
84
|
+
*
|
|
85
|
+
* const result = await createAttestation(
|
|
86
|
+
* [statement1FideId, statement2FideId],
|
|
87
|
+
* {
|
|
88
|
+
* method: 'ed25519',
|
|
89
|
+
* caip10User: 'ed25519::abc123...',
|
|
90
|
+
* sign: (root) => signEd25519(root, privateKey)
|
|
91
|
+
* }
|
|
92
|
+
* );
|
|
93
|
+
*
|
|
94
|
+
* console.log('Attestation ID:', result.attestationFideId);
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
export declare function createAttestation(statementFideIds: string[], options: CreateAttestationOptions): Promise<AttestationResult>;
|
|
98
|
+
/**
|
|
99
|
+
* Create provenance statements linking each statement to the attestation
|
|
100
|
+
*
|
|
101
|
+
* These are the "Statement → prov:wasGeneratedBy → Attestation" triples
|
|
102
|
+
* that connect content statements to their attestation.
|
|
103
|
+
*
|
|
104
|
+
* @param statementFideIds - Array of statement Fide IDs to include in attestation
|
|
105
|
+
* @param attestationResult - The attestation data structure
|
|
106
|
+
* @returns Array of provenance statements to publish
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```ts
|
|
110
|
+
* const provenance = await createProvenanceStatements(
|
|
111
|
+
* statementFideIds,
|
|
112
|
+
* attestationResult
|
|
113
|
+
* );
|
|
114
|
+
* // Each provenance statement links a content statement to the attestation
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
export declare function createProvenanceStatements(statementFideIds: string[], attestationResult: AttestationResult): Promise<ProvenanceStatement[]>;
|
|
118
|
+
/**
|
|
119
|
+
* Verify that a statement is part of an attestation
|
|
120
|
+
*
|
|
121
|
+
* This verifies the Merkle proof but does NOT verify the signature.
|
|
122
|
+
* Signature verification depends on the signing method and should
|
|
123
|
+
* be done separately using verifyEd25519 or verifyEip712.
|
|
124
|
+
*
|
|
125
|
+
* @param statementFideId - The leaf value to verify.
|
|
126
|
+
* @param proof - The Merkle proof path.
|
|
127
|
+
* @param attestationData - The attestation data.
|
|
128
|
+
* @paramDefault statementFideId did:fide:0x10...
|
|
129
|
+
* @paramDefault proof ["hash1", "hash2"]
|
|
130
|
+
* @paramDefault attestationData {"r":"root-hash"}
|
|
131
|
+
* @returns True if the statement is in the attestation
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* ```ts
|
|
135
|
+
* const isInBatch = await verifyStatementInAttestation(
|
|
136
|
+
* statementFideId,
|
|
137
|
+
* proof,
|
|
138
|
+
* attestationData
|
|
139
|
+
* );
|
|
140
|
+
* ```
|
|
141
|
+
*/
|
|
142
|
+
export declare function verifyStatementInAttestation(statementFideId: string, proof: MerkleProof, attestationData: AttestationData | {
|
|
143
|
+
r: string;
|
|
144
|
+
}): Promise<boolean>;
|
|
145
|
+
/**
|
|
146
|
+
* Parse attestation data from a raw identifier string
|
|
147
|
+
*
|
|
148
|
+
* @param rawIdentifier - The JSON string from objectRawIdentifier
|
|
149
|
+
* @returns Parsed attestation data
|
|
150
|
+
* @throws Error if JSON is invalid
|
|
151
|
+
*
|
|
152
|
+
* @example
|
|
153
|
+
* ```ts
|
|
154
|
+
* const attestationData = parseAttestationData(provenanceStatement.objectRawIdentifier);
|
|
155
|
+
* ```
|
|
156
|
+
*/
|
|
157
|
+
export declare function parseAttestationData(rawIdentifier: string): AttestationData;
|
|
158
|
+
/**
|
|
159
|
+
* Verify that an attestation's Fide ID is correctly derived
|
|
160
|
+
*
|
|
161
|
+
* @param attestationFideId - The claimed attestation Fide ID
|
|
162
|
+
* @param rawIdentifier - The raw identifier JSON string
|
|
163
|
+
* @returns True if the Fide ID is correctly derived
|
|
164
|
+
*
|
|
165
|
+
* @example
|
|
166
|
+
* ```ts
|
|
167
|
+
* const isValidId = await verifyAttestationFideId(
|
|
168
|
+
* provenanceStatement.objectFideId,
|
|
169
|
+
* provenanceStatement.objectRawIdentifier
|
|
170
|
+
* );
|
|
171
|
+
* ```
|
|
172
|
+
*/
|
|
173
|
+
export declare function verifyAttestationFideId(attestationFideId: string, rawIdentifier: string): Promise<boolean>;
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FCP SDK Attestation Utilities
|
|
3
|
+
*
|
|
4
|
+
* High-level helpers for creating and verifying attestations.
|
|
5
|
+
* Combines Fide ID calculation, Merkle trees, and signing.
|
|
6
|
+
*/
|
|
7
|
+
import { calculateFideId } from "../../fide-id/index.js";
|
|
8
|
+
import { buildMerkleTree, verifyMerkleProof } from "../merkle/index.js";
|
|
9
|
+
// ============================================================================
|
|
10
|
+
// ATTESTATION CREATION
|
|
11
|
+
// ============================================================================
|
|
12
|
+
/**
|
|
13
|
+
* Create an attestation for a batch of statement Fide IDs
|
|
14
|
+
*
|
|
15
|
+
* This function:
|
|
16
|
+
* 1. Builds a Merkle tree from the statement Fide IDs
|
|
17
|
+
* 2. Signs the Merkle root using the provided signing function
|
|
18
|
+
* 3. Creates the attestation data structure
|
|
19
|
+
* 4. Derives the Attestation Fide ID
|
|
20
|
+
*
|
|
21
|
+
* @param statementFideIds - Array of statement Fide IDs.
|
|
22
|
+
* @param options - Configuration options for operation.
|
|
23
|
+
* @paramDefault statementFideIds ["did:fide:0x10...", "did:fide:0x10..."]
|
|
24
|
+
* @paramDefault options {"method":"ed25519","caip10User":"ed25519:123...","sign":"async (root) => 'signature'"}
|
|
25
|
+
* @returns Full attestation result including ID, data, and proofs
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* import { createAttestation, signEd25519 } from '@fide.work/fcp';
|
|
30
|
+
*
|
|
31
|
+
* const result = await createAttestation(
|
|
32
|
+
* [statement1FideId, statement2FideId],
|
|
33
|
+
* {
|
|
34
|
+
* method: 'ed25519',
|
|
35
|
+
* caip10User: 'ed25519::abc123...',
|
|
36
|
+
* sign: (root) => signEd25519(root, privateKey)
|
|
37
|
+
* }
|
|
38
|
+
* );
|
|
39
|
+
*
|
|
40
|
+
* console.log('Attestation ID:', result.attestationFideId);
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export async function createAttestation(statementFideIds, options) {
|
|
44
|
+
if (statementFideIds.length === 0) {
|
|
45
|
+
throw new Error('Cannot create attestation from empty statement list');
|
|
46
|
+
}
|
|
47
|
+
// 1. Build Merkle tree
|
|
48
|
+
const merkleResult = await buildMerkleTree(statementFideIds);
|
|
49
|
+
const merkleRoot = merkleResult.root;
|
|
50
|
+
// 2. Sign the Merkle root
|
|
51
|
+
const signature = await options.sign(merkleRoot);
|
|
52
|
+
// 3. Create attestation data (with short keys, alphabetically ordered)
|
|
53
|
+
const attestationData = {
|
|
54
|
+
m: options.method,
|
|
55
|
+
r: merkleRoot,
|
|
56
|
+
s: signature,
|
|
57
|
+
u: options.caip10User
|
|
58
|
+
};
|
|
59
|
+
// 4. Create normalized JSON string (alphabetically ordered for determinism)
|
|
60
|
+
// IMPORTANT: Keys MUST be in alphabetical order (m, r, s, u) for deterministic hashing
|
|
61
|
+
const rawIdentifier = JSON.stringify({
|
|
62
|
+
m: attestationData.m,
|
|
63
|
+
r: attestationData.r,
|
|
64
|
+
s: attestationData.s,
|
|
65
|
+
u: attestationData.u
|
|
66
|
+
});
|
|
67
|
+
// 5. Derive attestation-like ID with fixed 0xaa prefix.
|
|
68
|
+
const attestationFideId = await calculateAaPrefixedId(rawIdentifier);
|
|
69
|
+
return {
|
|
70
|
+
attestationFideId,
|
|
71
|
+
attestationData,
|
|
72
|
+
rawIdentifier,
|
|
73
|
+
merkleRoot,
|
|
74
|
+
proofs: merkleResult.proofs
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Create provenance statements linking each statement to the attestation
|
|
79
|
+
*
|
|
80
|
+
* These are the "Statement → prov:wasGeneratedBy → Attestation" triples
|
|
81
|
+
* that connect content statements to their attestation.
|
|
82
|
+
*
|
|
83
|
+
* @param statementFideIds - Array of statement Fide IDs to include in attestation
|
|
84
|
+
* @param attestationResult - The attestation data structure
|
|
85
|
+
* @returns Array of provenance statements to publish
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```ts
|
|
89
|
+
* const provenance = await createProvenanceStatements(
|
|
90
|
+
* statementFideIds,
|
|
91
|
+
* attestationResult
|
|
92
|
+
* );
|
|
93
|
+
* // Each provenance statement links a content statement to the attestation
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
export async function createProvenanceStatements(statementFideIds, attestationResult) {
|
|
97
|
+
// Get the prov:wasGeneratedBy predicate ID
|
|
98
|
+
const wasGeneratedByPredicateId = await calculateFideId('CreativeWork', 'CreativeWork', 'prov:wasGeneratedBy');
|
|
99
|
+
return statementFideIds.map(statementFideId => ({
|
|
100
|
+
subjectFideId: statementFideId,
|
|
101
|
+
predicateFideId: wasGeneratedByPredicateId,
|
|
102
|
+
objectFideId: attestationResult.attestationFideId,
|
|
103
|
+
predicateRawIdentifier: 'prov:wasGeneratedBy',
|
|
104
|
+
objectRawIdentifier: attestationResult.rawIdentifier
|
|
105
|
+
}));
|
|
106
|
+
}
|
|
107
|
+
// ============================================================================
|
|
108
|
+
// ATTESTATION VERIFICATION
|
|
109
|
+
// ============================================================================
|
|
110
|
+
/**
|
|
111
|
+
* Verify that a statement is part of an attestation
|
|
112
|
+
*
|
|
113
|
+
* This verifies the Merkle proof but does NOT verify the signature.
|
|
114
|
+
* Signature verification depends on the signing method and should
|
|
115
|
+
* be done separately using verifyEd25519 or verifyEip712.
|
|
116
|
+
*
|
|
117
|
+
* @param statementFideId - The leaf value to verify.
|
|
118
|
+
* @param proof - The Merkle proof path.
|
|
119
|
+
* @param attestationData - The attestation data.
|
|
120
|
+
* @paramDefault statementFideId did:fide:0x10...
|
|
121
|
+
* @paramDefault proof ["hash1", "hash2"]
|
|
122
|
+
* @paramDefault attestationData {"r":"root-hash"}
|
|
123
|
+
* @returns True if the statement is in the attestation
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* ```ts
|
|
127
|
+
* const isInBatch = await verifyStatementInAttestation(
|
|
128
|
+
* statementFideId,
|
|
129
|
+
* proof,
|
|
130
|
+
* attestationData
|
|
131
|
+
* );
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
134
|
+
export async function verifyStatementInAttestation(statementFideId, proof, attestationData) {
|
|
135
|
+
return await verifyMerkleProof(statementFideId, proof, attestationData.r);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Parse attestation data from a raw identifier string
|
|
139
|
+
*
|
|
140
|
+
* @param rawIdentifier - The JSON string from objectRawIdentifier
|
|
141
|
+
* @returns Parsed attestation data
|
|
142
|
+
* @throws Error if JSON is invalid
|
|
143
|
+
*
|
|
144
|
+
* @example
|
|
145
|
+
* ```ts
|
|
146
|
+
* const attestationData = parseAttestationData(provenanceStatement.objectRawIdentifier);
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
149
|
+
export function parseAttestationData(rawIdentifier) {
|
|
150
|
+
const parsed = JSON.parse(rawIdentifier);
|
|
151
|
+
if (!parsed.m || !parsed.u || !parsed.r || !parsed.s) {
|
|
152
|
+
throw new Error('Invalid attestation data: missing required fields (m, u, r, s)');
|
|
153
|
+
}
|
|
154
|
+
return {
|
|
155
|
+
m: parsed.m,
|
|
156
|
+
u: parsed.u,
|
|
157
|
+
r: parsed.r,
|
|
158
|
+
s: parsed.s
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Verify that an attestation's Fide ID is correctly derived
|
|
163
|
+
*
|
|
164
|
+
* @param attestationFideId - The claimed attestation Fide ID
|
|
165
|
+
* @param rawIdentifier - The raw identifier JSON string
|
|
166
|
+
* @returns True if the Fide ID is correctly derived
|
|
167
|
+
*
|
|
168
|
+
* @example
|
|
169
|
+
* ```ts
|
|
170
|
+
* const isValidId = await verifyAttestationFideId(
|
|
171
|
+
* provenanceStatement.objectFideId,
|
|
172
|
+
* provenanceStatement.objectRawIdentifier
|
|
173
|
+
* );
|
|
174
|
+
* ```
|
|
175
|
+
*/
|
|
176
|
+
export async function verifyAttestationFideId(attestationFideId, rawIdentifier) {
|
|
177
|
+
const expectedId = await calculateAaPrefixedId(rawIdentifier);
|
|
178
|
+
return attestationFideId.toLowerCase() === expectedId.toLowerCase();
|
|
179
|
+
}
|
|
180
|
+
async function calculateAaPrefixedId(rawIdentifier) {
|
|
181
|
+
const bytes = new TextEncoder().encode(rawIdentifier);
|
|
182
|
+
const subtle = globalThis.crypto?.subtle ?? (await import("node:crypto")).webcrypto.subtle;
|
|
183
|
+
const digest = await subtle.digest("SHA-256", bytes);
|
|
184
|
+
const hashHex = Array.from(new Uint8Array(digest))
|
|
185
|
+
.map((byte) => byte.toString(16).padStart(2, "0"))
|
|
186
|
+
.join("");
|
|
187
|
+
return `did:fide:0xaa${hashHex.slice(-38)}`;
|
|
188
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FCP SDK - Attestation Module
|
|
3
|
+
*
|
|
4
|
+
* Re-exports all attestation utilities.
|
|
5
|
+
*/
|
|
6
|
+
export { createAttestation, createProvenanceStatements, verifyStatementInAttestation, parseAttestationData, verifyAttestationFideId, type SigningMethod, type AttestationData, type AttestationResult, type CreateAttestationOptions, type ProvenanceStatement } from "./create.js";
|
|
7
|
+
export { verifyAttestation, type VerifyAttestationOptions } from "./verify.js";
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FCP SDK - Attestation Module
|
|
3
|
+
*
|
|
4
|
+
* Re-exports all attestation utilities.
|
|
5
|
+
*/
|
|
6
|
+
export { createAttestation, createProvenanceStatements, verifyStatementInAttestation, parseAttestationData, verifyAttestationFideId } from "./create.js";
|
|
7
|
+
export { verifyAttestation } from "./verify.js";
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FCP SDK Attestation Verification Utilities
|
|
3
|
+
*
|
|
4
|
+
* Full verification functions that combine Merkle proof and signature verification.
|
|
5
|
+
*/
|
|
6
|
+
import { type AttestationData } from "./create.js";
|
|
7
|
+
import type { MerkleProof } from "../merkle/index.js";
|
|
8
|
+
import type { SigningMethod } from "./create.js";
|
|
9
|
+
/**
|
|
10
|
+
* Options for verifying an attestation
|
|
11
|
+
*/
|
|
12
|
+
export interface VerifyAttestationOptions {
|
|
13
|
+
/** The signing method used (`eip712`/`eip191` require `viem` to be installed). */
|
|
14
|
+
method: SigningMethod;
|
|
15
|
+
/** Public key or address for signature verification */
|
|
16
|
+
publicKeyOrAddress: CryptoKey | `0x${string}`;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Verify a complete attestation (both Merkle proof and signature)
|
|
20
|
+
*
|
|
21
|
+
* This function performs full verification:
|
|
22
|
+
* 1. Verifies the Merkle proof (statement is in the batch)
|
|
23
|
+
* 2. Verifies the signature (signer authorized the batch)
|
|
24
|
+
*
|
|
25
|
+
* @param statementFideId - The leaf value to verify in Merkle tree
|
|
26
|
+
* @param proof - The Merkle proof path (array of hashes from leaf to root)
|
|
27
|
+
* @param attestationData - The attestation data structure
|
|
28
|
+
* @param options - Configuration options for operation (method, public key/address, etc.)
|
|
29
|
+
* @returns True if both Merkle proof and signature are valid
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```ts
|
|
33
|
+
* // With Ed25519
|
|
34
|
+
* const isValid = await verifyAttestation(
|
|
35
|
+
* statementFideId,
|
|
36
|
+
* proof,
|
|
37
|
+
* attestationData,
|
|
38
|
+
* {
|
|
39
|
+
* method: 'ed25519',
|
|
40
|
+
* publicKeyOrAddress: publicKey
|
|
41
|
+
* }
|
|
42
|
+
* );
|
|
43
|
+
*
|
|
44
|
+
* // With EIP-712
|
|
45
|
+
* const isValid = await verifyAttestation(
|
|
46
|
+
* statementFideId,
|
|
47
|
+
* proof,
|
|
48
|
+
* attestationData,
|
|
49
|
+
* {
|
|
50
|
+
* method: 'eip712',
|
|
51
|
+
* publicKeyOrAddress: address
|
|
52
|
+
* }
|
|
53
|
+
* );
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export declare function verifyAttestation(statementFideId: string, proof: MerkleProof, attestationData: AttestationData | string, options: VerifyAttestationOptions): Promise<boolean>;
|