@useaccord/sdk 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/README.md +126 -0
- package/dist/accord.d.ts +43 -0
- package/dist/accord.d.ts.map +1 -0
- package/dist/adapter.d.ts +39 -0
- package/dist/adapter.d.ts.map +1 -0
- package/dist/chunk-7QVYU63E.js +7 -0
- package/dist/chunk-7QVYU63E.js.map +1 -0
- package/dist/constants.d.ts +83 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/domain.d.ts +73 -0
- package/dist/domain.d.ts.map +1 -0
- package/dist/errors.d.ts +64 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/evidence/crypto.d.ts +12 -0
- package/dist/evidence/crypto.d.ts.map +1 -0
- package/dist/evidence/ecies.d.ts +45 -0
- package/dist/evidence/ecies.d.ts.map +1 -0
- package/dist/evidence/fetch.d.ts +20 -0
- package/dist/evidence/fetch.d.ts.map +1 -0
- package/dist/evidence/index.d.ts +27 -0
- package/dist/evidence/index.d.ts.map +1 -0
- package/dist/evidence/index.js +392 -0
- package/dist/evidence/index.js.map +1 -0
- package/dist/evidence/keys.d.ts +33 -0
- package/dist/evidence/keys.d.ts.map +1 -0
- package/dist/evidence/manifest.d.ts +47 -0
- package/dist/evidence/manifest.d.ts.map +1 -0
- package/dist/evidence/options.d.ts +14 -0
- package/dist/evidence/options.d.ts.map +1 -0
- package/dist/evidence/parse.d.ts +39 -0
- package/dist/evidence/parse.d.ts.map +1 -0
- package/dist/evidence/publish.d.ts +45 -0
- package/dist/evidence/publish.d.ts.map +1 -0
- package/dist/fetch.d.ts +24 -0
- package/dist/fetch.d.ts.map +1 -0
- package/dist/generated/accounts/accordState.d.ts +58 -0
- package/dist/generated/accounts/accordState.d.ts.map +1 -0
- package/dist/generated/accounts/appealBond.d.ts +61 -0
- package/dist/generated/accounts/appealBond.d.ts.map +1 -0
- package/dist/generated/accounts/dispute.d.ts +213 -0
- package/dist/generated/accounts/dispute.d.ts.map +1 -0
- package/dist/generated/accounts/index.d.ts +15 -0
- package/dist/generated/accounts/index.d.ts.map +1 -0
- package/dist/generated/accounts/jurorStake.d.ts +137 -0
- package/dist/generated/accounts/jurorStake.d.ts.map +1 -0
- package/dist/generated/accounts/pendingUpdate.d.ts +43 -0
- package/dist/generated/accounts/pendingUpdate.d.ts.map +1 -0
- package/dist/generated/accounts/round.d.ts +143 -0
- package/dist/generated/accounts/round.d.ts.map +1 -0
- package/dist/generated/accounts/subaccord.d.ts +300 -0
- package/dist/generated/accounts/subaccord.d.ts.map +1 -0
- package/dist/generated/errors/accord.d.ts +160 -0
- package/dist/generated/errors/accord.d.ts.map +1 -0
- package/dist/generated/errors/index.d.ts +9 -0
- package/dist/generated/errors/index.d.ts.map +1 -0
- package/dist/generated/index.d.ts +14 -0
- package/dist/generated/index.d.ts.map +1 -0
- package/dist/generated/instructions/appeal.d.ts +107 -0
- package/dist/generated/instructions/appeal.d.ts.map +1 -0
- package/dist/generated/instructions/cancelDispute.d.ts +73 -0
- package/dist/generated/instructions/cancelDispute.d.ts.map +1 -0
- package/dist/generated/instructions/claimAppealRefund.d.ts +91 -0
- package/dist/generated/instructions/claimAppealRefund.d.ts.map +1 -0
- package/dist/generated/instructions/commit.d.ts +50 -0
- package/dist/generated/instructions/commit.d.ts.map +1 -0
- package/dist/generated/instructions/commitVrfCallback.d.ts +47 -0
- package/dist/generated/instructions/commitVrfCallback.d.ts.map +1 -0
- package/dist/generated/instructions/createDispute.d.ts +136 -0
- package/dist/generated/instructions/createDispute.d.ts.map +1 -0
- package/dist/generated/instructions/createSubaccord.d.ts +196 -0
- package/dist/generated/instructions/createSubaccord.d.ts.map +1 -0
- package/dist/generated/instructions/drawSeat.d.ts +74 -0
- package/dist/generated/instructions/drawSeat.d.ts.map +1 -0
- package/dist/generated/instructions/executeSubaccordUpdate.d.ts +43 -0
- package/dist/generated/instructions/executeSubaccordUpdate.d.ts.map +1 -0
- package/dist/generated/instructions/executeUnpause.d.ts +59 -0
- package/dist/generated/instructions/executeUnpause.d.ts.map +1 -0
- package/dist/generated/instructions/finalizeDispute.d.ts +46 -0
- package/dist/generated/instructions/finalizeDispute.d.ts.map +1 -0
- package/dist/generated/instructions/finalizeRound.d.ts +46 -0
- package/dist/generated/instructions/finalizeRound.d.ts.map +1 -0
- package/dist/generated/instructions/getRuling.d.ts +42 -0
- package/dist/generated/instructions/getRuling.d.ts.map +1 -0
- package/dist/generated/instructions/health.d.ts +37 -0
- package/dist/generated/instructions/health.d.ts.map +1 -0
- package/dist/generated/instructions/index.d.ts +37 -0
- package/dist/generated/instructions/index.d.ts.map +1 -0
- package/dist/generated/instructions/initializePause.d.ts +51 -0
- package/dist/generated/instructions/initializePause.d.ts.map +1 -0
- package/dist/generated/instructions/pause.d.ts +47 -0
- package/dist/generated/instructions/pause.d.ts.map +1 -0
- package/dist/generated/instructions/proposeSubaccordUpdate.d.ts +90 -0
- package/dist/generated/instructions/proposeSubaccordUpdate.d.ts.map +1 -0
- package/dist/generated/instructions/proposeUnpause.d.ts +47 -0
- package/dist/generated/instructions/proposeUnpause.d.ts.map +1 -0
- package/dist/generated/instructions/pruneJuror.d.ts +68 -0
- package/dist/generated/instructions/pruneJuror.d.ts.map +1 -0
- package/dist/generated/instructions/reclaimSlot.d.ts +48 -0
- package/dist/generated/instructions/reclaimSlot.d.ts.map +1 -0
- package/dist/generated/instructions/reconcileStake.d.ts +48 -0
- package/dist/generated/instructions/reconcileStake.d.ts.map +1 -0
- package/dist/generated/instructions/redraw.d.ts +86 -0
- package/dist/generated/instructions/redraw.d.ts.map +1 -0
- package/dist/generated/instructions/requestVrf.d.ts +71 -0
- package/dist/generated/instructions/requestVrf.d.ts.map +1 -0
- package/dist/generated/instructions/requestWithdraw.d.ts +61 -0
- package/dist/generated/instructions/requestWithdraw.d.ts.map +1 -0
- package/dist/generated/instructions/reveal.d.ts +53 -0
- package/dist/generated/instructions/reveal.d.ts.map +1 -0
- package/dist/generated/instructions/settleRound.d.ts +60 -0
- package/dist/generated/instructions/settleRound.d.ts.map +1 -0
- package/dist/generated/instructions/stake.d.ts +98 -0
- package/dist/generated/instructions/stake.d.ts.map +1 -0
- package/dist/generated/instructions/withdraw.d.ts +67 -0
- package/dist/generated/instructions/withdraw.d.ts.map +1 -0
- package/dist/generated/instructions/withdrawFees.d.ts +67 -0
- package/dist/generated/instructions/withdrawFees.d.ts.map +1 -0
- package/dist/generated/pdas/accordState.d.ts +12 -0
- package/dist/generated/pdas/accordState.d.ts.map +1 -0
- package/dist/generated/pdas/appealBond.d.ts +16 -0
- package/dist/generated/pdas/appealBond.d.ts.map +1 -0
- package/dist/generated/pdas/dispute.d.ts +16 -0
- package/dist/generated/pdas/dispute.d.ts.map +1 -0
- package/dist/generated/pdas/index.d.ts +16 -0
- package/dist/generated/pdas/index.d.ts.map +1 -0
- package/dist/generated/pdas/jurorStake.d.ts +16 -0
- package/dist/generated/pdas/jurorStake.d.ts.map +1 -0
- package/dist/generated/pdas/pendingUpdate.d.ts +16 -0
- package/dist/generated/pdas/pendingUpdate.d.ts.map +1 -0
- package/dist/generated/pdas/programIdentity.d.ts +12 -0
- package/dist/generated/pdas/programIdentity.d.ts.map +1 -0
- package/dist/generated/pdas/round.d.ts +16 -0
- package/dist/generated/pdas/round.d.ts.map +1 -0
- package/dist/generated/pdas/subaccord.d.ts +16 -0
- package/dist/generated/pdas/subaccord.d.ts.map +1 -0
- package/dist/generated/programs/accord.d.ts +182 -0
- package/dist/generated/programs/accord.d.ts.map +1 -0
- package/dist/generated/programs/index.d.ts +9 -0
- package/dist/generated/programs/index.d.ts.map +1 -0
- package/dist/generated/types/aggregation.d.ts +25 -0
- package/dist/generated/types/aggregation.d.ts.map +1 -0
- package/dist/generated/types/caseTerms.d.ts +87 -0
- package/dist/generated/types/caseTerms.d.ts.map +1 -0
- package/dist/generated/types/disputeState.d.ts +34 -0
- package/dist/generated/types/disputeState.d.ts.map +1 -0
- package/dist/generated/types/index.d.ts +15 -0
- package/dist/generated/types/index.d.ts.map +1 -0
- package/dist/generated/types/leafClaim.d.ts +27 -0
- package/dist/generated/types/leafClaim.d.ts.map +1 -0
- package/dist/generated/types/mSTNode.d.ts +26 -0
- package/dist/generated/types/mSTNode.d.ts.map +1 -0
- package/dist/generated/types/shortfallPolicy.d.ts +23 -0
- package/dist/generated/types/shortfallPolicy.d.ts.map +1 -0
- package/dist/generated/types/updatePayload.d.ts +107 -0
- package/dist/generated/types/updatePayload.d.ts.map +1 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8714 -0
- package/dist/index.js.map +1 -0
- package/dist/methods/appeal.d.ts +131 -0
- package/dist/methods/appeal.d.ts.map +1 -0
- package/dist/methods/dispute.d.ts +177 -0
- package/dist/methods/dispute.d.ts.map +1 -0
- package/dist/methods/disputePhase.d.ts +34 -0
- package/dist/methods/disputePhase.d.ts.map +1 -0
- package/dist/methods/lifecycle.d.ts +228 -0
- package/dist/methods/lifecycle.d.ts.map +1 -0
- package/dist/methods/mst.d.ts +100 -0
- package/dist/methods/mst.d.ts.map +1 -0
- package/dist/methods/settlement.d.ts +69 -0
- package/dist/methods/settlement.d.ts.map +1 -0
- package/dist/methods/stakeFlow.d.ts +65 -0
- package/dist/methods/stakeFlow.d.ts.map +1 -0
- package/dist/methods/staking.d.ts +220 -0
- package/dist/methods/staking.d.ts.map +1 -0
- package/dist/methods/voting.d.ts +227 -0
- package/dist/methods/voting.d.ts.map +1 -0
- package/dist/methods/vrf.d.ts +143 -0
- package/dist/methods/vrf.d.ts.map +1 -0
- package/dist/methods.d.ts +79 -0
- package/dist/methods.d.ts.map +1 -0
- package/dist/pda.d.ts +37 -0
- package/dist/pda.d.ts.map +1 -0
- package/dist/queries.d.ts +27 -0
- package/dist/queries.d.ts.map +1 -0
- package/dist/query.d.ts +30 -0
- package/dist/query.d.ts.map +1 -0
- package/dist/token.d.ts +24 -0
- package/dist/token.d.ts.map +1 -0
- package/dist/types.d.ts +19 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/wallet.d.ts +30 -0
- package/dist/wallet.d.ts.map +1 -0
- package/package.json +45 -0
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__name
|
|
3
|
+
} from "../chunk-7QVYU63E.js";
|
|
4
|
+
|
|
5
|
+
// src/evidence/crypto.ts
|
|
6
|
+
import { gcm } from "@noble/ciphers/aes";
|
|
7
|
+
import { hkdf } from "@noble/hashes/hkdf";
|
|
8
|
+
import { sha256 as nobleSha256 } from "@noble/hashes/sha256";
|
|
9
|
+
import { randomBytes } from "@noble/hashes/utils";
|
|
10
|
+
var AES_NONCE_BYTES = 12;
|
|
11
|
+
var AES_TAG_BYTES = 16;
|
|
12
|
+
async function sha256(data) {
|
|
13
|
+
return nobleSha256(data);
|
|
14
|
+
}
|
|
15
|
+
__name(sha256, "sha256");
|
|
16
|
+
async function hkdfSha256(ikm, info, length = 32) {
|
|
17
|
+
return hkdf(nobleSha256, ikm, new Uint8Array(0), info, length);
|
|
18
|
+
}
|
|
19
|
+
__name(hkdfSha256, "hkdfSha256");
|
|
20
|
+
async function aesGcmEncrypt(key, plaintext) {
|
|
21
|
+
requireKey(key);
|
|
22
|
+
const nonce = randomBytes(AES_NONCE_BYTES);
|
|
23
|
+
const ct = gcm(key, nonce).encrypt(plaintext);
|
|
24
|
+
const out = new Uint8Array(AES_NONCE_BYTES + ct.length);
|
|
25
|
+
out.set(nonce, 0);
|
|
26
|
+
out.set(ct, AES_NONCE_BYTES);
|
|
27
|
+
return out;
|
|
28
|
+
}
|
|
29
|
+
__name(aesGcmEncrypt, "aesGcmEncrypt");
|
|
30
|
+
async function aesGcmDecrypt(key, blob) {
|
|
31
|
+
requireKey(key);
|
|
32
|
+
if (blob.length < AES_NONCE_BYTES + AES_TAG_BYTES) {
|
|
33
|
+
throw new Error("AES-GCM blob too short (missing nonce/tag)");
|
|
34
|
+
}
|
|
35
|
+
const nonce = blob.subarray(0, AES_NONCE_BYTES);
|
|
36
|
+
const ct = blob.subarray(AES_NONCE_BYTES);
|
|
37
|
+
return gcm(key, nonce).decrypt(ct);
|
|
38
|
+
}
|
|
39
|
+
__name(aesGcmDecrypt, "aesGcmDecrypt");
|
|
40
|
+
function requireKey(key) {
|
|
41
|
+
if (key.length !== 32) {
|
|
42
|
+
throw new Error(`AES-256 key must be 32 bytes, got ${key.length}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
__name(requireKey, "requireKey");
|
|
46
|
+
|
|
47
|
+
// src/evidence/keys.ts
|
|
48
|
+
import {
|
|
49
|
+
ed25519,
|
|
50
|
+
edwardsToMontgomeryPriv,
|
|
51
|
+
edwardsToMontgomeryPub,
|
|
52
|
+
x25519
|
|
53
|
+
} from "@noble/curves/ed25519";
|
|
54
|
+
function ed25519ToX25519PublicKey(ed25519Pubkey) {
|
|
55
|
+
requireLen(ed25519Pubkey, 32, "Ed25519 public key");
|
|
56
|
+
if (ed25519Pubkey.every((b) => b === 0)) {
|
|
57
|
+
throw new Error(
|
|
58
|
+
"Ed25519 public key is all zeros (Solana Pubkey::default \u2014 unset evidence_operator on-chain); refusing X25519 conversion"
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
return edwardsToMontgomeryPub(ed25519Pubkey);
|
|
62
|
+
}
|
|
63
|
+
__name(ed25519ToX25519PublicKey, "ed25519ToX25519PublicKey");
|
|
64
|
+
function ed25519SecretToX25519(ed25519SecretSeed) {
|
|
65
|
+
requireLen(ed25519SecretSeed, 32, "Ed25519 secret seed");
|
|
66
|
+
return edwardsToMontgomeryPriv(ed25519SecretSeed);
|
|
67
|
+
}
|
|
68
|
+
__name(ed25519SecretToX25519, "ed25519SecretToX25519");
|
|
69
|
+
function x25519SharedSecret(mySecret, theirPublic) {
|
|
70
|
+
return x25519.getSharedSecret(mySecret, theirPublic);
|
|
71
|
+
}
|
|
72
|
+
__name(x25519SharedSecret, "x25519SharedSecret");
|
|
73
|
+
function newX25519KeyPair() {
|
|
74
|
+
const secret = x25519.utils.randomPrivateKey();
|
|
75
|
+
return { secret, publicKey: x25519.getPublicKey(secret) };
|
|
76
|
+
}
|
|
77
|
+
__name(newX25519KeyPair, "newX25519KeyPair");
|
|
78
|
+
function ed25519PublicKeyFromSeed(seed) {
|
|
79
|
+
requireLen(seed, 32, "Ed25519 secret seed");
|
|
80
|
+
return ed25519.getPublicKey(seed);
|
|
81
|
+
}
|
|
82
|
+
__name(ed25519PublicKeyFromSeed, "ed25519PublicKeyFromSeed");
|
|
83
|
+
function requireLen(b, n, what) {
|
|
84
|
+
if (b.length !== n) {
|
|
85
|
+
throw new Error(`${what} must be ${n} bytes, got ${b.length}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
__name(requireLen, "requireLen");
|
|
89
|
+
|
|
90
|
+
// src/evidence/ecies.ts
|
|
91
|
+
import { randomBytes as randomBytes2 } from "@noble/hashes/utils";
|
|
92
|
+
var INGEST_INFO = "accord-ingest-v1";
|
|
93
|
+
var DELIVER_INFO = "accord-deliver-v1";
|
|
94
|
+
var te = new TextEncoder();
|
|
95
|
+
async function claimantEncrypt(plaintext, operatorEd25519Pub) {
|
|
96
|
+
const dek = randomBytes2(32);
|
|
97
|
+
const ct = await aesGcmEncrypt(dek, plaintext);
|
|
98
|
+
const ephem = newX25519KeyPair();
|
|
99
|
+
const opX25519Pub = ed25519ToX25519PublicKey(operatorEd25519Pub);
|
|
100
|
+
const shared = x25519SharedSecret(ephem.secret, opX25519Pub);
|
|
101
|
+
const kIn = await hkdfSha256(shared, te.encode(INGEST_INFO));
|
|
102
|
+
const wrapped = await aesGcmEncrypt(kIn, dek);
|
|
103
|
+
return {
|
|
104
|
+
ct,
|
|
105
|
+
claimant_ephem_pub: ephem.publicKey,
|
|
106
|
+
wrapped,
|
|
107
|
+
plaintext_hash: await sha256(plaintext)
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
__name(claimantEncrypt, "claimantEncrypt");
|
|
111
|
+
async function operatorDecrypt(bundle, operatorEd25519SecretSeed) {
|
|
112
|
+
const opX25519Sk = ed25519SecretToX25519(operatorEd25519SecretSeed);
|
|
113
|
+
const shared = x25519SharedSecret(opX25519Sk, bundle.claimant_ephem_pub);
|
|
114
|
+
const kIn = await hkdfSha256(shared, te.encode(INGEST_INFO));
|
|
115
|
+
const dek = await aesGcmDecrypt(kIn, bundle.wrapped);
|
|
116
|
+
return aesGcmDecrypt(dek, bundle.ct);
|
|
117
|
+
}
|
|
118
|
+
__name(operatorDecrypt, "operatorDecrypt");
|
|
119
|
+
async function deliverToJuror(plaintext, jurorEd25519Pub) {
|
|
120
|
+
const ephem = newX25519KeyPair();
|
|
121
|
+
const jurorX25519Pub = ed25519ToX25519PublicKey(jurorEd25519Pub);
|
|
122
|
+
const shared = x25519SharedSecret(ephem.secret, jurorX25519Pub);
|
|
123
|
+
const kOut = await hkdfSha256(shared, te.encode(DELIVER_INFO));
|
|
124
|
+
const out = await aesGcmEncrypt(kOut, plaintext);
|
|
125
|
+
return { out, operator_ephem_pub: ephem.publicKey };
|
|
126
|
+
}
|
|
127
|
+
__name(deliverToJuror, "deliverToJuror");
|
|
128
|
+
async function jurorDecrypt(delivered, jurorEd25519SecretSeed) {
|
|
129
|
+
const jurorX25519Sk = ed25519SecretToX25519(jurorEd25519SecretSeed);
|
|
130
|
+
const shared = x25519SharedSecret(jurorX25519Sk, delivered.operator_ephem_pub);
|
|
131
|
+
const kOut = await hkdfSha256(shared, te.encode(DELIVER_INFO));
|
|
132
|
+
return aesGcmDecrypt(kOut, delivered.out);
|
|
133
|
+
}
|
|
134
|
+
__name(jurorDecrypt, "jurorDecrypt");
|
|
135
|
+
async function verifyIntegrity(plaintext, evidenceHash) {
|
|
136
|
+
const h = await sha256(plaintext);
|
|
137
|
+
if (h.length !== evidenceHash.length) {
|
|
138
|
+
throw new Error("integrity gate failed: sha256(plaintext) != evidence_hash");
|
|
139
|
+
}
|
|
140
|
+
for (let i = 0; i < h.length; i++) {
|
|
141
|
+
if (h[i] !== evidenceHash[i]) {
|
|
142
|
+
throw new Error("integrity gate failed: sha256(plaintext) != evidence_hash");
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
__name(verifyIntegrity, "verifyIntegrity");
|
|
147
|
+
|
|
148
|
+
// src/evidence/manifest.ts
|
|
149
|
+
var SHA256_ZERO = new Uint8Array(32);
|
|
150
|
+
function hex(bytes) {
|
|
151
|
+
return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
152
|
+
}
|
|
153
|
+
__name(hex, "hex");
|
|
154
|
+
function yamlQuote(s) {
|
|
155
|
+
return `"${s.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
156
|
+
}
|
|
157
|
+
__name(yamlQuote, "yamlQuote");
|
|
158
|
+
function buildManifest(input, ctx) {
|
|
159
|
+
const lines = [
|
|
160
|
+
"schema: accord-evidence/v1",
|
|
161
|
+
`dispute: ${ctx.dispute}`,
|
|
162
|
+
`subaccord: ${ctx.subaccord}`,
|
|
163
|
+
`filer: ${ctx.filer}`,
|
|
164
|
+
`filed_at: ${ctx.filedAt}`,
|
|
165
|
+
"language: en",
|
|
166
|
+
`title: ${yamlQuote(input.title)}`,
|
|
167
|
+
// description is optional; omitted when absent/empty → backward-compatible
|
|
168
|
+
// bytes (sha256 stable). JSON-escaped so multi-line markdown stays on one
|
|
169
|
+
// logical line (no YAML block-scalar parsing needed).
|
|
170
|
+
...input.description ? [`description: ${JSON.stringify(input.description)}`] : [],
|
|
171
|
+
"",
|
|
172
|
+
`option_salt: ${hex(input.salt)}`,
|
|
173
|
+
"options:",
|
|
174
|
+
...input.labels.map(
|
|
175
|
+
(label, index) => ` - { index: ${index}, label: ${yamlQuote(label)} }`
|
|
176
|
+
),
|
|
177
|
+
"",
|
|
178
|
+
"entries:",
|
|
179
|
+
...input.entries.map(
|
|
180
|
+
(e) => ` - { path: ${yamlQuote(e.path)}, sha256: "${hex(e.sha256 ?? SHA256_ZERO)}" }`
|
|
181
|
+
)
|
|
182
|
+
];
|
|
183
|
+
return new TextEncoder().encode(lines.join("\n") + "\n");
|
|
184
|
+
}
|
|
185
|
+
__name(buildManifest, "buildManifest");
|
|
186
|
+
|
|
187
|
+
// src/evidence/options.ts
|
|
188
|
+
function generateSalt() {
|
|
189
|
+
return crypto.getRandomValues(new Uint8Array(32));
|
|
190
|
+
}
|
|
191
|
+
__name(generateSalt, "generateSalt");
|
|
192
|
+
function concat(a, b) {
|
|
193
|
+
const out = new Uint8Array(a.length + b.length);
|
|
194
|
+
out.set(a);
|
|
195
|
+
out.set(b, a.length);
|
|
196
|
+
return out;
|
|
197
|
+
}
|
|
198
|
+
__name(concat, "concat");
|
|
199
|
+
var te2 = new TextEncoder();
|
|
200
|
+
async function deriveOptionHashes(salt, labels) {
|
|
201
|
+
if (salt.length !== 32) {
|
|
202
|
+
throw new Error(`InvalidOptionSalt: expected 32 bytes, got ${salt.length}`);
|
|
203
|
+
}
|
|
204
|
+
return Promise.all(
|
|
205
|
+
labels.map((label) => sha256(concat(salt, te2.encode(label))))
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
__name(deriveOptionHashes, "deriveOptionHashes");
|
|
209
|
+
function equalBytes(a, b) {
|
|
210
|
+
if (a.length !== b.length) return false;
|
|
211
|
+
return a.every((v, i) => v === b[i]);
|
|
212
|
+
}
|
|
213
|
+
__name(equalBytes, "equalBytes");
|
|
214
|
+
async function verifyOptionHashes(salt, labels, hashes) {
|
|
215
|
+
if (labels.length !== hashes.length) {
|
|
216
|
+
throw new Error(
|
|
217
|
+
`OptionHashMismatch: ${labels.length} labels vs ${hashes.length} hashes`
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
const derived = await deriveOptionHashes(salt, labels);
|
|
221
|
+
for (let i = 0; i < derived.length; i++) {
|
|
222
|
+
if (!equalBytes(derived[i], hashes[i])) {
|
|
223
|
+
throw new Error(`option-hash mismatch at index ${i}`);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
__name(verifyOptionHashes, "verifyOptionHashes");
|
|
228
|
+
|
|
229
|
+
// src/evidence/parse.ts
|
|
230
|
+
function parseManifest(text) {
|
|
231
|
+
const lines = text.split("\n");
|
|
232
|
+
const getField = /* @__PURE__ */ __name((key) => lines.find((l) => l.startsWith(`${key}: `))?.slice(`${key}: `.length).replace(/^"(.*)"$/, "$1"), "getField");
|
|
233
|
+
const options = [];
|
|
234
|
+
const entries = [];
|
|
235
|
+
let section = null;
|
|
236
|
+
for (const line of lines) {
|
|
237
|
+
if (line === "options:") {
|
|
238
|
+
section = "options";
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
if (line === "entries:") {
|
|
242
|
+
section = "entries";
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
if (!line.startsWith(" - {")) continue;
|
|
246
|
+
const item = line.slice(" - ".length);
|
|
247
|
+
if (section === "options") {
|
|
248
|
+
const index = Number(item.match(/index:\s*(\d+)/)?.[1] ?? -1);
|
|
249
|
+
const label = item.match(/label:\s*"([^"]*)"/)?.[1] ?? "";
|
|
250
|
+
options.push({ index, label });
|
|
251
|
+
} else if (section === "entries") {
|
|
252
|
+
const path = item.match(/path:\s*"([^"]*)"/)?.[1] ?? "";
|
|
253
|
+
const sha2562 = item.match(/sha256:\s*"([^"]*)"/)?.[1] ?? "";
|
|
254
|
+
entries.push({ path, sha256: sha2562 });
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
const descriptionRaw = getField("description");
|
|
258
|
+
const description = descriptionRaw ? JSON.parse(`"${descriptionRaw}"`) : "";
|
|
259
|
+
return {
|
|
260
|
+
title: getField("title") ?? "Untitled dispute",
|
|
261
|
+
description,
|
|
262
|
+
filedAt: getField("filed_at") ?? "\u2014",
|
|
263
|
+
filer: getField("filer") ?? "\u2014",
|
|
264
|
+
subaccord: getField("subaccord") ?? "\u2014",
|
|
265
|
+
dispute: getField("dispute") ?? "\u2014",
|
|
266
|
+
optionSalt: getField("option_salt") ?? "\u2014",
|
|
267
|
+
options,
|
|
268
|
+
entries
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
__name(parseManifest, "parseManifest");
|
|
272
|
+
function optionLabels(manifest) {
|
|
273
|
+
if (manifest == null) return [];
|
|
274
|
+
const parsed = typeof manifest === "string" ? parseManifest(manifest) : parseManifest(JSON.stringify(manifest));
|
|
275
|
+
const byIndex = /* @__PURE__ */ new Map();
|
|
276
|
+
for (const o of parsed.options) {
|
|
277
|
+
if (o.index >= 0) byIndex.set(o.index, o.label);
|
|
278
|
+
}
|
|
279
|
+
const labels = [];
|
|
280
|
+
for (let i = 0; i < parsed.options.length; i++) {
|
|
281
|
+
const label = byIndex.get(i);
|
|
282
|
+
if (typeof label === "string" && label.trim()) {
|
|
283
|
+
labels.push(label);
|
|
284
|
+
} else {
|
|
285
|
+
break;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
return labels;
|
|
289
|
+
}
|
|
290
|
+
__name(optionLabels, "optionLabels");
|
|
291
|
+
|
|
292
|
+
// src/evidence/publish.ts
|
|
293
|
+
function toBase64(bytes) {
|
|
294
|
+
let binary = "";
|
|
295
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
296
|
+
binary += String.fromCharCode(bytes[i]);
|
|
297
|
+
}
|
|
298
|
+
return btoa(binary);
|
|
299
|
+
}
|
|
300
|
+
__name(toBase64, "toBase64");
|
|
301
|
+
function equalBytes2(a, b) {
|
|
302
|
+
if (a.length !== b.length) return false;
|
|
303
|
+
return a.every((v, i) => v === b[i]);
|
|
304
|
+
}
|
|
305
|
+
__name(equalBytes2, "equalBytes");
|
|
306
|
+
async function postBundle(url, manifest, operatorPub) {
|
|
307
|
+
const bundle = await claimantEncrypt(manifest, operatorPub);
|
|
308
|
+
const res = await fetch(url, {
|
|
309
|
+
method: "POST",
|
|
310
|
+
headers: { "content-type": "application/json" },
|
|
311
|
+
body: JSON.stringify({
|
|
312
|
+
ct: toBase64(bundle.ct),
|
|
313
|
+
claimant_ephem_pub: toBase64(bundle.claimant_ephem_pub),
|
|
314
|
+
wrapped: toBase64(bundle.wrapped),
|
|
315
|
+
plaintext_hash: toBase64(bundle.plaintext_hash)
|
|
316
|
+
})
|
|
317
|
+
});
|
|
318
|
+
if (res.status !== 201) {
|
|
319
|
+
const body = await res.text().catch(() => "");
|
|
320
|
+
throw new Error(`evidence publish failed: ${res.status} ${body}`);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
__name(postBundle, "postBundle");
|
|
324
|
+
async function publishEvidence(params) {
|
|
325
|
+
const { endpoint, subaccord, dispute, manifest, operatorPub } = params;
|
|
326
|
+
await postBundle(
|
|
327
|
+
`${endpoint}/evidence/${subaccord}/${dispute}`,
|
|
328
|
+
manifest,
|
|
329
|
+
operatorPub
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
__name(publishEvidence, "publishEvidence");
|
|
333
|
+
async function publishSynodEvidence(params) {
|
|
334
|
+
const { endpoint, casePda, slot, manifest, operatorPub } = params;
|
|
335
|
+
await postBundle(
|
|
336
|
+
`${endpoint}/evidence/synod/${casePda}/${slot}`,
|
|
337
|
+
manifest,
|
|
338
|
+
operatorPub
|
|
339
|
+
);
|
|
340
|
+
}
|
|
341
|
+
__name(publishSynodEvidence, "publishSynodEvidence");
|
|
342
|
+
async function verifyManifestHash(manifest, evidenceHash) {
|
|
343
|
+
const hash = await sha256(manifest);
|
|
344
|
+
if (!equalBytes2(hash, evidenceHash)) {
|
|
345
|
+
throw new Error(
|
|
346
|
+
"manifest hash mismatch \u2014 upload does not match on-chain evidence_hash"
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
__name(verifyManifestHash, "verifyManifestHash");
|
|
351
|
+
|
|
352
|
+
// src/evidence/fetch.ts
|
|
353
|
+
async function fetchManifest(params) {
|
|
354
|
+
const { endpoint, subaccord, dispute, round } = params;
|
|
355
|
+
const res = await fetch(
|
|
356
|
+
`${endpoint}/evidence/${subaccord}/${dispute}/${round}`
|
|
357
|
+
);
|
|
358
|
+
if (res.status === 404) return null;
|
|
359
|
+
if (!res.ok) throw new Error(`evidence daemon returned ${res.status}`);
|
|
360
|
+
return res.json();
|
|
361
|
+
}
|
|
362
|
+
__name(fetchManifest, "fetchManifest");
|
|
363
|
+
export {
|
|
364
|
+
DELIVER_INFO,
|
|
365
|
+
INGEST_INFO,
|
|
366
|
+
SHA256_ZERO,
|
|
367
|
+
aesGcmDecrypt,
|
|
368
|
+
aesGcmEncrypt,
|
|
369
|
+
buildManifest,
|
|
370
|
+
claimantEncrypt,
|
|
371
|
+
deliverToJuror,
|
|
372
|
+
deriveOptionHashes,
|
|
373
|
+
ed25519PublicKeyFromSeed,
|
|
374
|
+
ed25519SecretToX25519,
|
|
375
|
+
ed25519ToX25519PublicKey,
|
|
376
|
+
fetchManifest,
|
|
377
|
+
generateSalt,
|
|
378
|
+
hkdfSha256,
|
|
379
|
+
jurorDecrypt,
|
|
380
|
+
newX25519KeyPair,
|
|
381
|
+
operatorDecrypt,
|
|
382
|
+
optionLabels,
|
|
383
|
+
parseManifest,
|
|
384
|
+
publishEvidence,
|
|
385
|
+
publishSynodEvidence,
|
|
386
|
+
sha256,
|
|
387
|
+
verifyIntegrity,
|
|
388
|
+
verifyManifestHash,
|
|
389
|
+
verifyOptionHashes,
|
|
390
|
+
x25519SharedSecret
|
|
391
|
+
};
|
|
392
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/evidence/crypto.ts","../../src/evidence/keys.ts","../../src/evidence/ecies.ts","../../src/evidence/manifest.ts","../../src/evidence/options.ts","../../src/evidence/parse.ts","../../src/evidence/publish.ts","../../src/evidence/fetch.ts"],"sourcesContent":["/**\n * evidence/crypto.ts — symmetric primitive spine for the Accord evidence\n * protocol (ADR-0006).\n *\n * Every primitive delegates to the audited `@noble` suite (`@noble/ciphers`,\n * `@noble/hashes`). Nothing here is hand-rolled: this module only fixes the two\n * protocol policies the claimant/operator/juror must share byte-for-byte —\n *\n * - AES-256-GCM wire blob = `nonce(12) ‖ ciphertext ‖ tag(16)`\n * - HKDF-SHA256 with an empty salt and a role-pinning `info` label\n *\n * — exactly as {@link ../methods/mst.ts} fixes a node layout over a library\n * hash. Functions are `async` to match the SPEC's stated crypto model and keep\n * callers (the daemon's injected ports, SDK consumers) await-shaped.\n *\n * Authority: apps/evidence-daemon/SPEC.md §Crypto model; ADR-0006.\n */\nimport { gcm } from \"@noble/ciphers/aes\";\nimport { hkdf } from \"@noble/hashes/hkdf\";\nimport { sha256 as nobleSha256 } from \"@noble/hashes/sha256\";\nimport { randomBytes } from \"@noble/hashes/utils\";\n\nconst AES_NONCE_BYTES = 12;\nconst AES_TAG_BYTES = 16;\n\n/** SHA-256 digest (32 bytes). */\nexport async function sha256(data: Uint8Array): Promise<Uint8Array> {\n return nobleSha256(data);\n}\n\n/**\n * HKDF-SHA256 with an empty salt (per SPEC §Crypto model) and a protocol `info`\n * label that pins the derived key to its role (ingest vs deliver).\n */\nexport async function hkdfSha256(\n ikm: Uint8Array,\n info: Uint8Array,\n length = 32,\n): Promise<Uint8Array> {\n return hkdf(nobleSha256, ikm, new Uint8Array(0), info, length);\n}\n\n/** AES-256-GCM encrypt → `nonce(12) ‖ ciphertext ‖ tag(16)` (SPEC wire format). */\nexport async function aesGcmEncrypt(\n key: Uint8Array,\n plaintext: Uint8Array,\n): Promise<Uint8Array> {\n requireKey(key);\n const nonce = randomBytes(AES_NONCE_BYTES);\n const ct = gcm(key, nonce).encrypt(plaintext); // ciphertext ‖ tag(16)\n const out = new Uint8Array(AES_NONCE_BYTES + ct.length);\n out.set(nonce, 0);\n out.set(ct, AES_NONCE_BYTES);\n return out;\n}\n\n/** AES-256-GCM decrypt of a `nonce(12) ‖ ciphertext ‖ tag(16)` blob. Throws on auth failure. */\nexport async function aesGcmDecrypt(\n key: Uint8Array,\n blob: Uint8Array,\n): Promise<Uint8Array> {\n requireKey(key);\n if (blob.length < AES_NONCE_BYTES + AES_TAG_BYTES) {\n throw new Error(\"AES-GCM blob too short (missing nonce/tag)\");\n }\n const nonce = blob.subarray(0, AES_NONCE_BYTES);\n const ct = blob.subarray(AES_NONCE_BYTES);\n return gcm(key, nonce).decrypt(ct);\n}\n\nfunction requireKey(key: Uint8Array): void {\n if (key.length !== 32) {\n throw new Error(`AES-256 key must be 32 bytes, got ${key.length}`);\n }\n}\n","/**\n * evidence/keys.ts — Ed25519/X25519 key material + the operator keyring\n * contract for the evidence protocol (ADR-0006 / ADR-0011).\n *\n * Solana identities are Ed25519; the protocol encrypts to the on-chain\n * `evidence_operator` and `Round.jurors[]` Ed25519 pubkeys by dual-using each\n * key: signing on-chain (Ed25519) + encryption off-chain via its Montgomery\n * (X25519) form — a libsodium-style `crypto_sign_ed25519_{pk,sk}_to_curve25519`\n * `@noble/curves`; the wrappers only add length + zero-key validation at the\n * public seam.\n */\nimport {\n ed25519,\n edwardsToMontgomeryPriv,\n edwardsToMontgomeryPub,\n x25519,\n} from \"@noble/curves/ed25519\";\n\n/** Ed25519 keypair material held by the operator. The secret never leaves the keyring. */\nexport interface Ed25519Keypair {\n /** 32-byte Ed25519 public key (matches the on-chain `evidence_operator` field). */\n publicKey: Uint8Array;\n /** 32-byte Ed25519 secret seed. */\n secretKey: Uint8Array;\n}\n\n/**\n * Per-Subaccord operator keyring contract. Resolves the Ed25519 secret whose\n * pubkey matches a Subaccord's on-chain `evidence_operator`, or null when this\n * operator does not operate that Subaccord (the caller maps null → 404). The\n * on-chain field is the binding: no key↔subaccord mapping is held out-of-band.\n *\n * The daemon supplies the env-backed implementation; a file/KMS source can\n * satisfy this without touching callers (ADR-0011).\n */\nexport interface Keyring {\n forOperator(operatorPubkey: Uint8Array): Promise<Ed25519Keypair | null>;\n}\n\n// --- Ed25519 <-> X25519 (libsodium-style; backed by @noble/curves) ---------\n\n/** Convert an Ed25519 public key (32 bytes) to its X25519 (Montgomery) form. */\nexport function ed25519ToX25519PublicKey(ed25519Pubkey: Uint8Array): Uint8Array {\n requireLen(ed25519Pubkey, 32, \"Ed25519 public key\");\n // Pubkey::default() converts to Montgomery u=1 (order-2) — the X25519 shared\n // secret would be all zeros and noble throws a cryptic error downstream.\n // Canon's create_list CPI still sets evidence_operator = Pubkey::default().\n if (ed25519Pubkey.every((b) => b === 0)) {\n throw new Error(\n \"Ed25519 public key is all zeros (Solana Pubkey::default — unset evidence_operator on-chain); refusing X25519 conversion\",\n );\n }\n return edwardsToMontgomeryPub(ed25519Pubkey);\n}\n\n/** Convert an Ed25519 secret seed (32 bytes) to its X25519 (Montgomery) secret. */\nexport function ed25519SecretToX25519(ed25519SecretSeed: Uint8Array): Uint8Array {\n requireLen(ed25519SecretSeed, 32, \"Ed25519 secret seed\");\n return edwardsToMontgomeryPriv(ed25519SecretSeed);\n}\n\n/** X25519 ECDH: shared secret from a Montgomery secret + a Montgomery public key. */\nexport function x25519SharedSecret(\n mySecret: Uint8Array,\n theirPublic: Uint8Array,\n): Uint8Array {\n return x25519.getSharedSecret(mySecret, theirPublic);\n}\n\n/** Fresh ephemeral X25519 keypair for one ECIES operation. */\nexport function newX25519KeyPair(): { secret: Uint8Array; publicKey: Uint8Array } {\n const secret = x25519.utils.randomPrivateKey();\n return { secret, publicKey: x25519.getPublicKey(secret) };\n}\n\n/** Derive the Ed25519 public key from a 32-byte secret seed (keyring indexing). */\nexport function ed25519PublicKeyFromSeed(seed: Uint8Array): Uint8Array {\n requireLen(seed, 32, \"Ed25519 secret seed\");\n return ed25519.getPublicKey(seed);\n}\n\nfunction requireLen(b: Uint8Array, n: number, what: string): void {\n if (b.length !== n) {\n throw new Error(`${what} must be ${n} bytes, got ${b.length}`);\n }\n}\n","/**\n * evidence/ecies.ts — the Accord evidence encryption protocol (ADR-0006).\n *\n * One ECIES-style envelope, two roles:\n *\n * Ingest (claimant → operator): the claimant encrypts plaintext to the\n * operator's Ed25519→X25519 key and posts the bundle; the operator decrypts.\n *\n * Deliver (operator → drawn juror): the operator re-encrypts plaintext to the\n * juror's Ed25519→X25519 key; only that juror's key decrypts.\n *\n * This is the single byte-exact implementation all three parties import — the\n * claimant and juror run it off-daemon (they are SDK consumers), so the protocol\n * cannot drift between participants. Composition only: every primitive\n * (ECDH, HKDF, AES-GCM, Montgomery conversion) comes from {@link ./crypto} /\n * {@link ./keys}; the only thing owned here is the construction order and the\n * HKDF `info` role labels.\n *\n * Plaintext exists only ephemerally between decrypt and re-encrypt on the\n * operator side; nothing persisted is ever plaintext (SPEC §Encrypted-at-rest).\n *\n * Authority: apps/evidence-daemon/SPEC.md §Crypto model; ADR-0006.\n */\nimport { randomBytes } from \"@noble/hashes/utils\";\nimport { aesGcmDecrypt, aesGcmEncrypt, hkdfSha256, sha256 } from \"./crypto.js\";\nimport {\n ed25519SecretToX25519,\n ed25519ToX25519PublicKey,\n newX25519KeyPair,\n x25519SharedSecret,\n} from \"./keys.js\";\n\n/** HKDF `info` labels pin the derivation to its protocol role. */\nexport const INGEST_INFO = \"accord-ingest-v1\";\nexport const DELIVER_INFO = \"accord-deliver-v1\";\n\nconst te = new TextEncoder();\n\n/** Stored ciphertext bundle (ciphertext only — no plaintext field). */\nexport interface IngestBundle {\n /** AES-GCM(dek, plaintext) — nonce(12) prepended. */\n ct: Uint8Array;\n /** Claimant's ephemeral X25519 public key (32 bytes). */\n claimant_ephem_pub: Uint8Array;\n /** AES-GCM(k_in, dek) — nonce(12) prepended. */\n wrapped: Uint8Array;\n /** sha256(plaintext); matches the dispute's on-chain `evidence_hash`. */\n plaintext_hash: Uint8Array;\n}\n\n/** A bundle re-encrypted to a single drawn juror. */\nexport interface JurorBundle {\n /** AES-GCM(k_out, plaintext) — nonce(12) prepended. */\n out: Uint8Array;\n /** Operator's ephemeral X25519 public key for this delivery (32 bytes). */\n operator_ephem_pub: Uint8Array;\n}\n\n/**\n * Claimant-side ingest encryption. Produces the bundle posted to the operator.\n * Claimants run this off-daemon; the operator never calls it in production (it\n * is exposed so claimant SDK clients share one implementation, and for\n * round-trips / test vectors).\n */\nexport async function claimantEncrypt(\n plaintext: Uint8Array,\n operatorEd25519Pub: Uint8Array,\n): Promise<IngestBundle> {\n const dek = randomBytes(32);\n const ct = await aesGcmEncrypt(dek, plaintext);\n\n const ephem = newX25519KeyPair();\n const opX25519Pub = ed25519ToX25519PublicKey(operatorEd25519Pub);\n const shared = x25519SharedSecret(ephem.secret, opX25519Pub);\n const kIn = await hkdfSha256(shared, te.encode(INGEST_INFO));\n const wrapped = await aesGcmEncrypt(kIn, dek);\n\n // dek wiped implicitly (local ref dropped); plaintext_hash is metadata, not secret.\n return {\n ct,\n claimant_ephem_pub: ephem.publicKey,\n wrapped,\n plaintext_hash: await sha256(plaintext),\n };\n}\n\n/**\n * Operator-side decrypt of a stored bundle → plaintext (in-memory only).\n * Callers MUST run {@link verifyIntegrity} next.\n */\nexport async function operatorDecrypt(\n bundle: IngestBundle,\n operatorEd25519SecretSeed: Uint8Array,\n): Promise<Uint8Array> {\n const opX25519Sk = ed25519SecretToX25519(operatorEd25519SecretSeed);\n const shared = x25519SharedSecret(opX25519Sk, bundle.claimant_ephem_pub);\n const kIn = await hkdfSha256(shared, te.encode(INGEST_INFO));\n const dek = await aesGcmDecrypt(kIn, bundle.wrapped); // throws on auth failure\n return aesGcmDecrypt(dek, bundle.ct);\n}\n\n/** Operator re-encrypts plaintext to a drawn juror's Ed25519 pubkey. */\nexport async function deliverToJuror(\n plaintext: Uint8Array,\n jurorEd25519Pub: Uint8Array,\n): Promise<JurorBundle> {\n const ephem = newX25519KeyPair();\n const jurorX25519Pub = ed25519ToX25519PublicKey(jurorEd25519Pub);\n const shared = x25519SharedSecret(ephem.secret, jurorX25519Pub);\n const kOut = await hkdfSha256(shared, te.encode(DELIVER_INFO));\n const out = await aesGcmEncrypt(kOut, plaintext);\n return { out, operator_ephem_pub: ephem.publicKey };\n}\n\n/** Juror-side decrypt of a delivered bundle → plaintext. */\nexport async function jurorDecrypt(\n delivered: JurorBundle,\n jurorEd25519SecretSeed: Uint8Array,\n): Promise<Uint8Array> {\n const jurorX25519Sk = ed25519SecretToX25519(jurorEd25519SecretSeed);\n const shared = x25519SharedSecret(jurorX25519Sk, delivered.operator_ephem_pub);\n const kOut = await hkdfSha256(shared, te.encode(DELIVER_INFO));\n return aesGcmDecrypt(kOut, delivered.out);\n}\n\n/**\n * Mandatory integrity gate (SPEC §3, §Failure modes): `sha256(plaintext)` MUST\n * equal the dispute's on-chain `evidence_hash`. Both operands are public hashes,\n * so a plain compare suffices (no constant-time requirement). Throws on mismatch\n * — at ingest this rejects a bad upload, at delivery it refuses + alerts.\n */\nexport async function verifyIntegrity(\n plaintext: Uint8Array,\n evidenceHash: Uint8Array,\n): Promise<void> {\n const h = await sha256(plaintext);\n if (h.length !== evidenceHash.length) {\n throw new Error(\"integrity gate failed: sha256(plaintext) != evidence_hash\");\n }\n for (let i = 0; i < h.length; i++) {\n if (h[i] !== evidenceHash[i]) {\n throw new Error(\"integrity gate failed: sha256(plaintext) != evidence_hash\");\n }\n }\n}\n","/**\n * manifest.ts — serialize the `accord-evidence/v1` manifest into a single\n * deterministic Uint8Array buffer. That one buffer feeds the YAML preview,\n * `sha256`→`evidence_hash`, and `claimantEncrypt`→POST. Never re-serialize.\n *\n * Authority: EVIDENCE-FORMAT.md §2 (no canonicalization needed — manifest\n * delivered verbatim), milestone accord-ebel §3 (single-buffer invariant).\n */\nimport type { Address } from \"@solana/kit\";\n\n/** All-zero `[u8;32]` sentinel — juror skips leaf verification (root gate still applies). */\nexport const SHA256_ZERO = new Uint8Array(32);\n\nexport interface ManifestEntryInput {\n /** URL or relative POSIX path to the evidence resource. */\n path: string;\n /** Leaf sha256 (32 bytes). Defaults to {@link SHA256_ZERO} when unknown. */\n sha256?: Uint8Array;\n}\n\nexport interface ManifestInput {\n /** Per-dispute 32-byte random salt (app-generated). */\n salt: Uint8Array;\n title: string;\n /**\n * Optional markdown claim body (the challenger's argument). Serialized as a\n * single JSON-escaped line so the manifest stays single-line-per-field and\n * the targeted parser needs no block-scalar handling. Omitted entirely when\n * absent/empty → byte-identical to a pre-`description` manifest (sha256\n * stable). Rendering is display-only; committed bytes are never altered.\n */\n description?: string;\n /** Ordered option labels; `Dispute.options[i] = sha256(salt ‖ utf8(label_i))`. */\n labels: string[];\n entries: ManifestEntryInput[];\n}\n\nexport interface ManifestCtx {\n dispute: Address;\n subaccord: Address;\n filer: Address;\n /** ISO-8601 UTC timestamp string. */\n filedAt: string;\n}\n\nfunction hex(bytes: Uint8Array): string {\n return Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n}\n\n/** Minimal YAML double-quote escaping for a string value. */\nfunction yamlQuote(s: string): string {\n return `\"${s.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"')}\"`;\n}\n\n/**\n * Serialize manifest input + ctx into a single `Uint8Array` (UTF-8 YAML).\n * Hand-serialized — the manifest is a flat object with two list fields; no YAML\n * library needed (EVIDENCE-FORMAT.md §2: no canonicalization, delivered verbatim).\n */\nexport function buildManifest(\n input: ManifestInput,\n ctx: ManifestCtx,\n): Uint8Array {\n const lines: string[] = [\n \"schema: accord-evidence/v1\",\n `dispute: ${ctx.dispute}`,\n `subaccord: ${ctx.subaccord}`,\n `filer: ${ctx.filer}`,\n `filed_at: ${ctx.filedAt}`,\n \"language: en\",\n `title: ${yamlQuote(input.title)}`,\n // description is optional; omitted when absent/empty → backward-compatible\n // bytes (sha256 stable). JSON-escaped so multi-line markdown stays on one\n // logical line (no YAML block-scalar parsing needed).\n ...(input.description\n ? [`description: ${JSON.stringify(input.description)}`]\n : []),\n \"\",\n `option_salt: ${hex(input.salt)}`,\n \"options:\",\n ...input.labels.map(\n (label, index) => ` - { index: ${index}, label: ${yamlQuote(label)} }`,\n ),\n \"\",\n \"entries:\",\n ...input.entries.map(\n (e) =>\n ` - { path: ${yamlQuote(e.path)}, sha256: \"${hex(e.sha256 ?? SHA256_ZERO)}\" }`,\n ),\n ];\n return new TextEncoder().encode(lines.join(\"\\n\") + \"\\n\");\n}\n","/**\n * evidence/options.ts — option-salt derivation + self-verify.\n *\n * `Dispute.options[i] = sha256(option_salt ‖ utf8(label_i))` (EVIDENCE-FORMAT.md §4).\n * The salt is app-generated, per-dispute, and lives only in the manifest.\n * `verifyOptionHashes` runs pre-submit — nothing on-chain enforces this today\n * (ADR-0017 open; D2 trustlessly closed when it lands).\n */\nimport { sha256 } from \"./crypto.js\";\n\n/** Generate a 32-byte random salt via the Web Crypto API. */\nexport function generateSalt(): Uint8Array {\n return crypto.getRandomValues(new Uint8Array(32));\n}\n\nfunction concat(a: Uint8Array, b: Uint8Array): Uint8Array {\n const out = new Uint8Array(a.length + b.length);\n out.set(a);\n out.set(b, a.length);\n return out;\n}\n\nconst te = new TextEncoder();\n\n/**\n * Derive `Dispute.options[i] = sha256(option_salt ‖ utf8(label_i))` for each label.\n * Returns 32-byte digests in label order. Throws if salt is not 32 bytes — a\n * wrong-length salt produces silently-wrong hashes (correctness footgun).\n */\nexport async function deriveOptionHashes(\n salt: Uint8Array,\n labels: string[],\n): Promise<Uint8Array[]> {\n if (salt.length !== 32) {\n throw new Error(`InvalidOptionSalt: expected 32 bytes, got ${salt.length}`);\n }\n return Promise.all(\n labels.map((label) => sha256(concat(salt, te.encode(label)))),\n );\n}\n\nfunction equalBytes(a: Uint8Array, b: Uint8Array): boolean {\n if (a.length !== b.length) return false;\n return a.every((v, i) => v === b[i]);\n}\n\n/**\n * Verify that `hashes[i] == sha256(salt ‖ utf8(labels[i]))` for all i.\n * Throws on mismatch — fails closed (D2 self-verify, app-side).\n */\nexport async function verifyOptionHashes(\n salt: Uint8Array,\n labels: string[],\n hashes: Uint8Array[],\n): Promise<void> {\n if (labels.length !== hashes.length) {\n throw new Error(\n `OptionHashMismatch: ${labels.length} labels vs ${hashes.length} hashes`,\n );\n }\n const derived = await deriveOptionHashes(salt, labels);\n for (let i = 0; i < derived.length; i++) {\n if (!equalBytes(derived[i]!, hashes[i]!)) {\n throw new Error(`option-hash mismatch at index ${i}`);\n }\n }\n}\n","/**\n * parse.ts — parse the `accord-evidence/v1` manifest returned by the evidence\n * daemon (`useManifest`). Shared by `EvidenceManifest` (full render) and any\n * feature that needs a slice of the manifest (e.g. option labels for voting).\n *\n * The manifest is YAML (produced by `buildManifest`); the daemon may return it\n * as a raw UTF-8 string or as a parsed JSON object. This targeted parser needs\n * no YAML dependency.\n */\n\nexport interface ParsedManifest {\n title: string;\n /** Markdown claim body; \"\" when absent (pre-`description` manifests). */\n description: string;\n filedAt: string;\n filer: string;\n subaccord: string;\n dispute: string;\n optionSalt: string;\n options: { index: number; label: string }[];\n entries: { path: string; sha256: string }[];\n}\n\n/** Parse the `accord-evidence/v1` YAML format (produced by `buildManifest`). */\nexport function parseManifest(text: string): ParsedManifest {\n const lines = text.split(\"\\n\");\n const getField = (key: string): string | undefined =>\n lines\n .find((l) => l.startsWith(`${key}: `))\n ?.slice(`${key}: `.length)\n .replace(/^\"(.*)\"$/, \"$1\");\n\n const options: { index: number; label: string }[] = [];\n const entries: { path: string; sha256: string }[] = [];\n let section: \"options\" | \"entries\" | null = null;\n\n for (const line of lines) {\n if (line === \"options:\") {\n section = \"options\";\n continue;\n }\n if (line === \"entries:\") {\n section = \"entries\";\n continue;\n }\n if (!line.startsWith(\" - {\")) continue;\n\n const item = line.slice(\" - \".length);\n if (section === \"options\") {\n const index = Number(item.match(/index:\\s*(\\d+)/)?.[1] ?? -1);\n const label = item.match(/label:\\s*\"([^\"]*)\"/)?.[1] ?? \"\";\n options.push({ index, label });\n } else if (section === \"entries\") {\n const path = item.match(/path:\\s*\"([^\"]*)\"/)?.[1] ?? \"\";\n const sha256 = item.match(/sha256:\\s*\"([^\"]*)\"/)?.[1] ?? \"\";\n entries.push({ path, sha256 });\n }\n }\n\n // description is JSON-escaped on a single line (see buildManifest); getField\n // strips the outer quotes, so re-quote + JSON.parse to unescape markdown.\n const descriptionRaw = getField(\"description\");\n const description = descriptionRaw\n ? (JSON.parse(`\"${descriptionRaw}\"`) as string)\n : \"\";\n\n return {\n title: getField(\"title\") ?? \"Untitled dispute\",\n description,\n filedAt: getField(\"filed_at\") ?? \"—\",\n filer: getField(\"filer\") ?? \"—\",\n subaccord: getField(\"subaccord\") ?? \"—\",\n dispute: getField(\"dispute\") ?? \"—\",\n optionSalt: getField(\"option_salt\") ?? \"—\",\n options,\n entries,\n };\n}\n\n/**\n * Ordered option labels from a manifest fetched via `useManifest` (a YAML\n * string for the `accord-evidence/v1` format, or a parsed JSON object).\n *\n * Returns labels in index order, contiguously from 0 up to the first missing\n * or blank entry. Callers fall back to the on-chain option hash for any index\n * not covered. Returns `[]` when the manifest is absent (no bundle stored).\n */\nexport function optionLabels(manifest: unknown): string[] {\n if (manifest == null) return [];\n const parsed =\n typeof manifest === \"string\"\n ? parseManifest(manifest)\n : parseManifest(JSON.stringify(manifest));\n\n const byIndex = new Map<number, string>();\n for (const o of parsed.options) {\n if (o.index >= 0) byIndex.set(o.index, o.label);\n }\n\n const labels: string[] = [];\n for (let i = 0; i < parsed.options.length; i++) {\n const label = byIndex.get(i);\n if (typeof label === \"string\" && label.trim()) {\n labels.push(label);\n } else {\n break;\n }\n }\n return labels;\n}\n","/**\n * publish.ts — claimant-side encrypt + POST to the evidence daemon, and\n * manifest-hash verification for the recovery upload path.\n *\n * The daemon base URL is deployment-specific (Vite env on the app side) and is\n * NOT held here — `publishEvidence` takes `endpoint` as a parameter. App\n * consumers keep their own `EVIDENCE_DAEMON_URL` config (ADR-0011).\n *\n * Authority: ADR-0011 (daemon transport), EVIDENCE-FORMAT.md §2 (root hash),\n * milestone accord-ebel §1 (happy path step 7, recovery).\n */\nimport { claimantEncrypt } from \"./ecies.js\";\nimport { sha256 } from \"./crypto.js\";\n\nfunction toBase64(bytes: Uint8Array): string {\n let binary = \"\";\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]!);\n }\n return btoa(binary);\n}\n\nfunction equalBytes(a: Uint8Array, b: Uint8Array): boolean {\n if (a.length !== b.length) return false;\n return a.every((v, i) => v === b[i]);\n}\n\nexport interface PublishParams {\n /** Daemon base URL (app-side `EVIDENCE_DAEMON_URL`). */\n endpoint: string;\n subaccord: string;\n dispute: string;\n /** The single manifest buffer (same bytes that produced `evidence_hash`). */\n manifest: Uint8Array;\n /** Evidence operator's raw Ed25519 public key (32 bytes, decoded from address). */\n operatorPub: Uint8Array;\n}\n\n/** Encrypt the manifest to the operator and POST the wire bundle to `url`. */\nasync function postBundle(url: string, manifest: Uint8Array, operatorPub: Uint8Array): Promise<void> {\n const bundle = await claimantEncrypt(manifest, operatorPub);\n const res = await fetch(url, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({\n ct: toBase64(bundle.ct),\n claimant_ephem_pub: toBase64(bundle.claimant_ephem_pub),\n wrapped: toBase64(bundle.wrapped),\n plaintext_hash: toBase64(bundle.plaintext_hash),\n }),\n });\n if (res.status !== 201) {\n const body = await res.text().catch(() => \"\");\n throw new Error(`evidence publish failed: ${res.status} ${body}`);\n }\n}\n\n/**\n * Encrypt the manifest to the operator and POST it to the daemon.\n * Daemon ingest is idempotent on `(dispute, round, plaintext_hash)` — same\n * manifest → 201 no-op, first POST wins. Safe to retry without re-creating\n * the dispute.\n */\nexport async function publishEvidence(params: PublishParams): Promise<void> {\n const { endpoint, subaccord, dispute, manifest, operatorPub } = params;\n await postBundle(\n `${endpoint}/evidence/${subaccord}/${dispute}`,\n manifest,\n operatorPub,\n );\n}\n\nexport interface PublishSynodParams {\n /** Daemon base URL (app-side `EVIDENCE_DAEMON_URL`). */\n endpoint: string;\n /** The SynodCase PDA — the pre-dispute grouping key. */\n casePda: string;\n /** Roster slot of the joining party (0–6). */\n slot: number;\n /** The party's manifest buffer (same bytes that produced the join hash). */\n manifest: Uint8Array;\n /** Evidence operator's raw Ed25519 public key (32 bytes, decoded from address). */\n operatorPub: Uint8Array;\n}\n\n/**\n * Encrypt the party's manifest to the operator and POST it to the daemon's\n * synod pre-dispute grouping route (`POST /evidence/synod/{case}/{slot}`,\n * milestone accord-daq8). Unauthenticated by design: the on-chain\n * `SynodCase.evidence[slot]` hash committed at `join` IS the commit; pushes\n * are gated chain-side (case exists, slot live, dispute unbound). Same-bundle\n * re-pushes are 201-idempotent server-side; a different hash for a filled\n * slot is a 409.\n */\nexport async function publishSynodEvidence(\n params: PublishSynodParams,\n): Promise<void> {\n const { endpoint, casePda, slot, manifest, operatorPub } = params;\n await postBundle(\n `${endpoint}/evidence/synod/${casePda}/${slot}`,\n manifest,\n operatorPub,\n );\n}\n\n/**\n * Verify `sha256(manifest) == evidenceHash`. Throws on mismatch — the recovery\n * upload is rejected if the manifest doesn't match what was committed on-chain.\n */\nexport async function verifyManifestHash(\n manifest: Uint8Array,\n evidenceHash: Uint8Array,\n): Promise<void> {\n const hash = await sha256(manifest);\n if (!equalBytes(hash, evidenceHash)) {\n throw new Error(\n \"manifest hash mismatch — upload does not match on-chain evidence_hash\",\n );\n }\n}\n","/**\n * evidence/fetch.ts — framework-agnostic manifest fetch from the evidence daemon.\n *\n * GET {endpoint}/evidence/{subaccord}/{dispute}/{round}\n *\n * Returns the decrypted manifest (a YAML string for the `accord-evidence/v1`\n * format, or a parsed JSON object if the plaintext was JSON). `null` when no\n * bundle is stored for the round (404).\n *\n * This is the pure fetch — React apps wrap it in a `useQuery` hook\n * (see apps/app and apps/canon `useManifest.ts`).\n */\nexport interface FetchManifestParams {\n endpoint: string;\n subaccord: string;\n dispute: string;\n round: number;\n}\n\nexport async function fetchManifest(\n params: FetchManifestParams,\n): Promise<unknown> {\n const { endpoint, subaccord, dispute, round } = params;\n const res = await fetch(\n `${endpoint}/evidence/${subaccord}/${dispute}/${round}`,\n );\n if (res.status === 404) return null;\n if (!res.ok) throw new Error(`evidence daemon returned ${res.status}`);\n return res.json();\n}\n"],"mappings":"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","names":["randomBytes","randomBytes","te","sha256","equalBytes"]}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/** Ed25519 keypair material held by the operator. The secret never leaves the keyring. */
|
|
2
|
+
export interface Ed25519Keypair {
|
|
3
|
+
/** 32-byte Ed25519 public key (matches the on-chain `evidence_operator` field). */
|
|
4
|
+
publicKey: Uint8Array;
|
|
5
|
+
/** 32-byte Ed25519 secret seed. */
|
|
6
|
+
secretKey: Uint8Array;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Per-Subaccord operator keyring contract. Resolves the Ed25519 secret whose
|
|
10
|
+
* pubkey matches a Subaccord's on-chain `evidence_operator`, or null when this
|
|
11
|
+
* operator does not operate that Subaccord (the caller maps null → 404). The
|
|
12
|
+
* on-chain field is the binding: no key↔subaccord mapping is held out-of-band.
|
|
13
|
+
*
|
|
14
|
+
* The daemon supplies the env-backed implementation; a file/KMS source can
|
|
15
|
+
* satisfy this without touching callers (ADR-0011).
|
|
16
|
+
*/
|
|
17
|
+
export interface Keyring {
|
|
18
|
+
forOperator(operatorPubkey: Uint8Array): Promise<Ed25519Keypair | null>;
|
|
19
|
+
}
|
|
20
|
+
/** Convert an Ed25519 public key (32 bytes) to its X25519 (Montgomery) form. */
|
|
21
|
+
export declare function ed25519ToX25519PublicKey(ed25519Pubkey: Uint8Array): Uint8Array;
|
|
22
|
+
/** Convert an Ed25519 secret seed (32 bytes) to its X25519 (Montgomery) secret. */
|
|
23
|
+
export declare function ed25519SecretToX25519(ed25519SecretSeed: Uint8Array): Uint8Array;
|
|
24
|
+
/** X25519 ECDH: shared secret from a Montgomery secret + a Montgomery public key. */
|
|
25
|
+
export declare function x25519SharedSecret(mySecret: Uint8Array, theirPublic: Uint8Array): Uint8Array;
|
|
26
|
+
/** Fresh ephemeral X25519 keypair for one ECIES operation. */
|
|
27
|
+
export declare function newX25519KeyPair(): {
|
|
28
|
+
secret: Uint8Array;
|
|
29
|
+
publicKey: Uint8Array;
|
|
30
|
+
};
|
|
31
|
+
/** Derive the Ed25519 public key from a 32-byte secret seed (keyring indexing). */
|
|
32
|
+
export declare function ed25519PublicKeyFromSeed(seed: Uint8Array): Uint8Array;
|
|
33
|
+
//# sourceMappingURL=keys.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../../src/evidence/keys.ts"],"names":[],"mappings":"AAkBA,0FAA0F;AAC1F,MAAM,WAAW,cAAc;IAC7B,mFAAmF;IACnF,SAAS,EAAE,UAAU,CAAC;IACtB,mCAAmC;IACnC,SAAS,EAAE,UAAU,CAAC;CACvB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,OAAO;IACtB,WAAW,CAAC,cAAc,EAAE,UAAU,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;CACzE;AAID,gFAAgF;AAChF,wBAAgB,wBAAwB,CAAC,aAAa,EAAE,UAAU,GAAG,UAAU,CAW9E;AAED,mFAAmF;AACnF,wBAAgB,qBAAqB,CAAC,iBAAiB,EAAE,UAAU,GAAG,UAAU,CAG/E;AAED,qFAAqF;AACrF,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,UAAU,EACpB,WAAW,EAAE,UAAU,GACtB,UAAU,CAEZ;AAED,8DAA8D;AAC9D,wBAAgB,gBAAgB,IAAI;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,SAAS,EAAE,UAAU,CAAA;CAAE,CAGhF;AAED,mFAAmF;AACnF,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,UAAU,GAAG,UAAU,CAGrE"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* manifest.ts — serialize the `accord-evidence/v1` manifest into a single
|
|
3
|
+
* deterministic Uint8Array buffer. That one buffer feeds the YAML preview,
|
|
4
|
+
* `sha256`→`evidence_hash`, and `claimantEncrypt`→POST. Never re-serialize.
|
|
5
|
+
*
|
|
6
|
+
* Authority: EVIDENCE-FORMAT.md §2 (no canonicalization needed — manifest
|
|
7
|
+
* delivered verbatim), milestone accord-ebel §3 (single-buffer invariant).
|
|
8
|
+
*/
|
|
9
|
+
import type { Address } from "@solana/kit";
|
|
10
|
+
/** All-zero `[u8;32]` sentinel — juror skips leaf verification (root gate still applies). */
|
|
11
|
+
export declare const SHA256_ZERO: Uint8Array<ArrayBuffer>;
|
|
12
|
+
export interface ManifestEntryInput {
|
|
13
|
+
/** URL or relative POSIX path to the evidence resource. */
|
|
14
|
+
path: string;
|
|
15
|
+
/** Leaf sha256 (32 bytes). Defaults to {@link SHA256_ZERO} when unknown. */
|
|
16
|
+
sha256?: Uint8Array;
|
|
17
|
+
}
|
|
18
|
+
export interface ManifestInput {
|
|
19
|
+
/** Per-dispute 32-byte random salt (app-generated). */
|
|
20
|
+
salt: Uint8Array;
|
|
21
|
+
title: string;
|
|
22
|
+
/**
|
|
23
|
+
* Optional markdown claim body (the challenger's argument). Serialized as a
|
|
24
|
+
* single JSON-escaped line so the manifest stays single-line-per-field and
|
|
25
|
+
* the targeted parser needs no block-scalar handling. Omitted entirely when
|
|
26
|
+
* absent/empty → byte-identical to a pre-`description` manifest (sha256
|
|
27
|
+
* stable). Rendering is display-only; committed bytes are never altered.
|
|
28
|
+
*/
|
|
29
|
+
description?: string;
|
|
30
|
+
/** Ordered option labels; `Dispute.options[i] = sha256(salt ‖ utf8(label_i))`. */
|
|
31
|
+
labels: string[];
|
|
32
|
+
entries: ManifestEntryInput[];
|
|
33
|
+
}
|
|
34
|
+
export interface ManifestCtx {
|
|
35
|
+
dispute: Address;
|
|
36
|
+
subaccord: Address;
|
|
37
|
+
filer: Address;
|
|
38
|
+
/** ISO-8601 UTC timestamp string. */
|
|
39
|
+
filedAt: string;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Serialize manifest input + ctx into a single `Uint8Array` (UTF-8 YAML).
|
|
43
|
+
* Hand-serialized — the manifest is a flat object with two list fields; no YAML
|
|
44
|
+
* library needed (EVIDENCE-FORMAT.md §2: no canonicalization, delivered verbatim).
|
|
45
|
+
*/
|
|
46
|
+
export declare function buildManifest(input: ManifestInput, ctx: ManifestCtx): Uint8Array;
|
|
47
|
+
//# sourceMappingURL=manifest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/evidence/manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C,6FAA6F;AAC7F,eAAO,MAAM,WAAW,yBAAqB,CAAC;AAE9C,MAAM,WAAW,kBAAkB;IACjC,2DAA2D;IAC3D,IAAI,EAAE,MAAM,CAAC;IACb,4EAA4E;IAC5E,MAAM,CAAC,EAAE,UAAU,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,uDAAuD;IACvD,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kFAAkF;IAClF,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,kBAAkB,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,OAAO,CAAC;IACf,qCAAqC;IACrC,OAAO,EAAE,MAAM,CAAC;CACjB;AAaD;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,aAAa,EACpB,GAAG,EAAE,WAAW,GACf,UAAU,CA6BZ"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** Generate a 32-byte random salt via the Web Crypto API. */
|
|
2
|
+
export declare function generateSalt(): Uint8Array;
|
|
3
|
+
/**
|
|
4
|
+
* Derive `Dispute.options[i] = sha256(option_salt ‖ utf8(label_i))` for each label.
|
|
5
|
+
* Returns 32-byte digests in label order. Throws if salt is not 32 bytes — a
|
|
6
|
+
* wrong-length salt produces silently-wrong hashes (correctness footgun).
|
|
7
|
+
*/
|
|
8
|
+
export declare function deriveOptionHashes(salt: Uint8Array, labels: string[]): Promise<Uint8Array[]>;
|
|
9
|
+
/**
|
|
10
|
+
* Verify that `hashes[i] == sha256(salt ‖ utf8(labels[i]))` for all i.
|
|
11
|
+
* Throws on mismatch — fails closed (D2 self-verify, app-side).
|
|
12
|
+
*/
|
|
13
|
+
export declare function verifyOptionHashes(salt: Uint8Array, labels: string[], hashes: Uint8Array[]): Promise<void>;
|
|
14
|
+
//# sourceMappingURL=options.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../../src/evidence/options.ts"],"names":[],"mappings":"AAUA,6DAA6D;AAC7D,wBAAgB,YAAY,IAAI,UAAU,CAEzC;AAWD;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,UAAU,EAChB,MAAM,EAAE,MAAM,EAAE,GACf,OAAO,CAAC,UAAU,EAAE,CAAC,CAOvB;AAOD;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,UAAU,EAChB,MAAM,EAAE,MAAM,EAAE,EAChB,MAAM,EAAE,UAAU,EAAE,GACnB,OAAO,CAAC,IAAI,CAAC,CAYf"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* parse.ts — parse the `accord-evidence/v1` manifest returned by the evidence
|
|
3
|
+
* daemon (`useManifest`). Shared by `EvidenceManifest` (full render) and any
|
|
4
|
+
* feature that needs a slice of the manifest (e.g. option labels for voting).
|
|
5
|
+
*
|
|
6
|
+
* The manifest is YAML (produced by `buildManifest`); the daemon may return it
|
|
7
|
+
* as a raw UTF-8 string or as a parsed JSON object. This targeted parser needs
|
|
8
|
+
* no YAML dependency.
|
|
9
|
+
*/
|
|
10
|
+
export interface ParsedManifest {
|
|
11
|
+
title: string;
|
|
12
|
+
/** Markdown claim body; "" when absent (pre-`description` manifests). */
|
|
13
|
+
description: string;
|
|
14
|
+
filedAt: string;
|
|
15
|
+
filer: string;
|
|
16
|
+
subaccord: string;
|
|
17
|
+
dispute: string;
|
|
18
|
+
optionSalt: string;
|
|
19
|
+
options: {
|
|
20
|
+
index: number;
|
|
21
|
+
label: string;
|
|
22
|
+
}[];
|
|
23
|
+
entries: {
|
|
24
|
+
path: string;
|
|
25
|
+
sha256: string;
|
|
26
|
+
}[];
|
|
27
|
+
}
|
|
28
|
+
/** Parse the `accord-evidence/v1` YAML format (produced by `buildManifest`). */
|
|
29
|
+
export declare function parseManifest(text: string): ParsedManifest;
|
|
30
|
+
/**
|
|
31
|
+
* Ordered option labels from a manifest fetched via `useManifest` (a YAML
|
|
32
|
+
* string for the `accord-evidence/v1` format, or a parsed JSON object).
|
|
33
|
+
*
|
|
34
|
+
* Returns labels in index order, contiguously from 0 up to the first missing
|
|
35
|
+
* or blank entry. Callers fall back to the on-chain option hash for any index
|
|
36
|
+
* not covered. Returns `[]` when the manifest is absent (no bundle stored).
|
|
37
|
+
*/
|
|
38
|
+
export declare function optionLabels(manifest: unknown): string[];
|
|
39
|
+
//# sourceMappingURL=parse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../src/evidence/parse.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,yEAAyE;IACzE,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC5C,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC7C;AAED,gFAAgF;AAChF,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAqD1D;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,OAAO,GAAG,MAAM,EAAE,CAsBxD"}
|