@antseed/antseed-verifier 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.
Files changed (83) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +86 -0
  3. package/dist/adapters/aci.d.ts +4 -0
  4. package/dist/adapters/aci.d.ts.map +1 -0
  5. package/dist/adapters/aci.js +42 -0
  6. package/dist/adapters/aci.js.map +1 -0
  7. package/dist/adapters/chutes.d.ts +4 -0
  8. package/dist/adapters/chutes.d.ts.map +1 -0
  9. package/dist/adapters/chutes.js +72 -0
  10. package/dist/adapters/chutes.js.map +1 -0
  11. package/dist/adapters/index.d.ts +26 -0
  12. package/dist/adapters/index.d.ts.map +1 -0
  13. package/dist/adapters/index.js +19 -0
  14. package/dist/adapters/index.js.map +1 -0
  15. package/dist/antseed-node-types.d.ts +55 -0
  16. package/dist/antseed-node-types.d.ts.map +1 -0
  17. package/dist/antseed-node-types.js +8 -0
  18. package/dist/antseed-node-types.js.map +1 -0
  19. package/dist/capability.d.ts +50 -0
  20. package/dist/capability.d.ts.map +1 -0
  21. package/dist/capability.js +15 -0
  22. package/dist/capability.js.map +1 -0
  23. package/dist/caps/gpu-nvidia.d.ts +66 -0
  24. package/dist/caps/gpu-nvidia.d.ts.map +1 -0
  25. package/dist/caps/gpu-nvidia.js +142 -0
  26. package/dist/caps/gpu-nvidia.js.map +1 -0
  27. package/dist/caps/index.d.ts +7 -0
  28. package/dist/caps/index.d.ts.map +1 -0
  29. package/dist/caps/index.js +21 -0
  30. package/dist/caps/index.js.map +1 -0
  31. package/dist/caps/measured-image.d.ts +14 -0
  32. package/dist/caps/measured-image.d.ts.map +1 -0
  33. package/dist/caps/measured-image.js +46 -0
  34. package/dist/caps/measured-image.js.map +1 -0
  35. package/dist/caps/provider-claims.d.ts +52 -0
  36. package/dist/caps/provider-claims.d.ts.map +1 -0
  37. package/dist/caps/provider-claims.js +195 -0
  38. package/dist/caps/provider-claims.js.map +1 -0
  39. package/dist/caps/seller-bound.d.ts +9 -0
  40. package/dist/caps/seller-bound.d.ts.map +1 -0
  41. package/dist/caps/seller-bound.js +104 -0
  42. package/dist/caps/seller-bound.js.map +1 -0
  43. package/dist/caps/tee-tdx.d.ts +107 -0
  44. package/dist/caps/tee-tdx.d.ts.map +1 -0
  45. package/dist/caps/tee-tdx.js +210 -0
  46. package/dist/caps/tee-tdx.js.map +1 -0
  47. package/dist/collect/configfs.d.ts +6 -0
  48. package/dist/collect/configfs.d.ts.map +1 -0
  49. package/dist/collect/configfs.js +38 -0
  50. package/dist/collect/configfs.js.map +1 -0
  51. package/dist/collect/dstack.d.ts +8 -0
  52. package/dist/collect/dstack.d.ts.map +1 -0
  53. package/dist/collect/dstack.js +79 -0
  54. package/dist/collect/dstack.js.map +1 -0
  55. package/dist/collect/http.d.ts +25 -0
  56. package/dist/collect/http.d.ts.map +1 -0
  57. package/dist/collect/http.js +83 -0
  58. package/dist/collect/http.js.map +1 -0
  59. package/dist/index.d.ts +33 -0
  60. package/dist/index.d.ts.map +1 -0
  61. package/dist/index.js +40 -0
  62. package/dist/index.js.map +1 -0
  63. package/dist/nras.d.ts +81 -0
  64. package/dist/nras.d.ts.map +1 -0
  65. package/dist/nras.js +190 -0
  66. package/dist/nras.js.map +1 -0
  67. package/dist/prover.d.ts +5 -0
  68. package/dist/prover.d.ts.map +1 -0
  69. package/dist/prover.js +204 -0
  70. package/dist/prover.js.map +1 -0
  71. package/dist/report-data.d.ts +47 -0
  72. package/dist/report-data.d.ts.map +1 -0
  73. package/dist/report-data.js +111 -0
  74. package/dist/report-data.js.map +1 -0
  75. package/dist/shared.d.ts +89 -0
  76. package/dist/shared.d.ts.map +1 -0
  77. package/dist/shared.js +158 -0
  78. package/dist/shared.js.map +1 -0
  79. package/dist/verifier.d.ts +21 -0
  80. package/dist/verifier.d.ts.map +1 -0
  81. package/dist/verifier.js +149 -0
  82. package/dist/verifier.js.map +1 -0
  83. package/package.json +42 -0
@@ -0,0 +1,142 @@
1
+ import { claimId } from '../shared.js';
2
+ import { collectJsonFieldViaHttp } from '../collect/http.js';
3
+ import { decodeTeeTdxEvidence, PROVIDER_TEE_CAP_ID } from './tee-tdx.js';
4
+ import { getReportDataScheme } from '../report-data.js';
5
+ import { NRAS_GPU_ATTEST_URL_DEFAULT, NRAS_JWKS_URL_DEFAULT, buildNrasRequest, defaultNrasSubmit, verifyEar, } from '../nras.js';
6
+ /**
7
+ * Capability 'seller-provider-gpu-cc': proves the inference provider's GPUs run NVIDIA
8
+ * Confidential Computing, via NVIDIA's Remote Attestation Service (NRAS). The buyer submits
9
+ * the provider's per-GPU CC evidence and the buyer's nonce to NRAS, then verifies the returned
10
+ * EAR (signed JWT): the signature is valid against NVIDIA's JWKS, the overall result is success,
11
+ * the CC mode is on, and the nonce binds this round.
12
+ *
13
+ * Informational, not required: a CPU-only seller (no GPUs) must still verify, so this cap is
14
+ * never in the buyer's required set. The seller offers it only when it configures a provider
15
+ * evidence route and a GPU evidence field; otherwise it omits the cap. The buyer-side check goes
16
+ * through an injectable GpuVerifyFn (see below) so an offline verifier can replace it.
17
+ */
18
+ export const GPU_CAP_ID = 'seller-provider-gpu-cc';
19
+ /** Mode switch: 'nras' (default, verify via NRAS) or 'local' (offline; not implemented). */
20
+ const GPU_MODE_ENV = 'ANTSEED_VERIFIER_GPU_MODE';
21
+ /** Env overrides for NVIDIA's endpoints (defaults point at NRAS; useful for tests and staging). */
22
+ const NRAS_URL_ENV = 'ANTSEED_VERIFIER_NRAS_URL';
23
+ const NRAS_JWKS_ENV = 'ANTSEED_VERIFIER_NRAS_JWKS_URL';
24
+ /** Decode the provider's GPU evidence bytes (JSON: { arch, evidence_list }). */
25
+ function decodeGpuEvidence(bytes) {
26
+ return JSON.parse(new TextDecoder().decode(bytes));
27
+ }
28
+ /**
29
+ * Build a NRAS-backed GpuVerifyFn. It submits the provider evidence and nonce to NRAS and
30
+ * verifies the EAR. Network or service errors are marked transient (retryable). Anything else
31
+ * (malformed evidence, bad signature, failed claim, nonce mismatch) fails closed as a real
32
+ * verdict. jose is imported lazily (only here) so the seller half and CPU-only buyers never load it.
33
+ */
34
+ export function makeNrasGpuVerify(opts = {}) {
35
+ return async (evidenceBytes, nonce) => {
36
+ const nrasUrl = opts.nrasUrl ?? process.env[NRAS_URL_ENV]?.trim() ?? NRAS_GPU_ATTEST_URL_DEFAULT;
37
+ let request;
38
+ try {
39
+ request = buildNrasRequest(decodeGpuEvidence(evidenceBytes), nonce);
40
+ }
41
+ catch (err) {
42
+ return { ok: false, detail: `invalid GPU evidence: ${msg(err)}` };
43
+ }
44
+ let response;
45
+ try {
46
+ response = await (opts.submit ?? defaultNrasSubmit)(nrasUrl, request);
47
+ }
48
+ catch (err) {
49
+ // NRAS unreachable or 5xx — transient, not an attestation verdict.
50
+ return { ok: false, transient: true, detail: `NRAS request failed: ${msg(err)}` };
51
+ }
52
+ let getKey = opts.getKey;
53
+ if (!getKey) {
54
+ const jwksUrl = opts.jwksUrl ?? process.env[NRAS_JWKS_ENV]?.trim() ?? NRAS_JWKS_URL_DEFAULT;
55
+ const jose = await import('jose');
56
+ getKey = jose.createRemoteJWKSet(new URL(jwksUrl));
57
+ }
58
+ const r = await verifyEar(response, nonce, getKey);
59
+ return { ok: r.ok, detail: r.reason };
60
+ };
61
+ }
62
+ /** Default NRAS verifier (production). */
63
+ export const nrasGpuVerify = makeNrasGpuVerify();
64
+ /**
65
+ * Offline GPU verifier — reserved for the nvtrust-style local path (report + device cert chain
66
+ * + RIM, no external service). Not implemented: it returns a clear, non-transient error so an
67
+ * operator who sets ANTSEED_VERIFIER_GPU_MODE=local gets an explicit "not implemented", not silence.
68
+ */
69
+ export const localGpuVerify = async () => ({
70
+ ok: false,
71
+ detail: 'offline GPU verification not yet implemented (ANTSEED_VERIFIER_GPU_MODE=local)',
72
+ });
73
+ /** Dispatch on ANTSEED_VERIFIER_GPU_MODE: 'nras' or 'local'. An unknown mode fails closed. */
74
+ export const defaultGpuVerify = (evidence, nonce) => {
75
+ const mode = (process.env[GPU_MODE_ENV]?.trim() || 'nras').toLowerCase();
76
+ if (mode === 'local')
77
+ return localGpuVerify(evidence, nonce);
78
+ if (mode === 'nras')
79
+ return nrasGpuVerify(evidence, nonce);
80
+ return Promise.resolve({ ok: false, detail: `unknown ${GPU_MODE_ENV} "${mode}" (expected "nras" or "local")` });
81
+ };
82
+ /** Config-key convention for this cap's collector settings (mirrors tee-tdx's tdxConfigKey). */
83
+ export function gpuConfigKey(key) {
84
+ return `${GPU_CAP_ID}.${key}`;
85
+ }
86
+ function msg(err) {
87
+ return err instanceof Error ? err.message : String(err);
88
+ }
89
+ /**
90
+ * The nonce to submit to NRAS this round. A provider that binds its TDX quote with a report_data
91
+ * scheme (e.g. Chutes' nonce-pubkey-sha256-v1) also binds its GPU evidence to that scheme's derived
92
+ * nonce, not the raw round nonce — so the code asks the declared scheme for it. With no scheme, it
93
+ * uses the raw nonce. It reads the provider quote from the bundle; any decode issue falls back to
94
+ * the raw nonce (fail-open is safe here — verifyEar still enforces the eat_nonce match).
95
+ */
96
+ function nrasNonceFor(nonce, bundle) {
97
+ const providerEvidence = bundle?.[PROVIDER_TEE_CAP_ID];
98
+ if (!providerEvidence)
99
+ return nonce;
100
+ try {
101
+ const { binding } = decodeTeeTdxEvidence(providerEvidence);
102
+ if (!binding)
103
+ return nonce;
104
+ const scheme = getReportDataScheme(binding.scheme);
105
+ return scheme ? scheme.gpuNonce(nonce, binding.ingredients) : nonce;
106
+ }
107
+ catch {
108
+ return nonce;
109
+ }
110
+ }
111
+ /**
112
+ * Mint the GPU-CC capability. `gpuVerify` is the injected buyer-side check (default: NRAS);
113
+ * tests pass a stub. collect fetches the provider's GPU evidence from the same provider
114
+ * evidence route as the TDX quote (config-supplied url and field). It throws when either is
115
+ * absent, so the cap is omitted.
116
+ */
117
+ export function makeGpuNvidiaCap(gpuVerify = defaultGpuVerify) {
118
+ return {
119
+ id: GPU_CAP_ID,
120
+ async verify(input) {
121
+ const claim = claimId(GPU_CAP_ID);
122
+ // Fail-closed: no evidence means the GPUs cannot be attested.
123
+ if (!input.evidence)
124
+ return { claim, ok: false, detail: 'seller returned no GPU CC evidence' };
125
+ const r = await gpuVerify(input.evidence, nrasNonceFor(input.nonce, input.evidenceBundle));
126
+ // ClaimResult has no transient field; show retryability in the human-readable detail.
127
+ const detail = r.transient ? `[transient] ${r.detail}` : r.detail;
128
+ return { claim, ok: r.ok, detail };
129
+ },
130
+ async collect(input) {
131
+ const url = input.config[gpuConfigKey('url')];
132
+ const field = input.config[gpuConfigKey('field')];
133
+ if (!url || !field)
134
+ throw new Error('seller-provider-gpu-cc requires a provider url + gpu field; not offered');
135
+ // The GPU evidence is a structured JSON object ({ arch, evidence_list }), not a lone
136
+ // base64 blob — collect it as JSON bytes so its shape survives to the NRAS submit.
137
+ return collectJsonFieldViaHttp(url, input.nonce, field);
138
+ },
139
+ };
140
+ }
141
+ export const gpuNvidiaCapability = makeGpuNvidiaCap();
142
+ //# sourceMappingURL=gpu-nvidia.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gpu-nvidia.js","sourceRoot":"","sources":["../../src/caps/gpu-nvidia.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { nodeTeeCapability, providerTeeCapability } from './tee-tdx.js';
2
+ import { sellerBoundCapability } from './seller-bound.js';
3
+ import { measuredImageCapability } from './measured-image.js';
4
+ import { gpuNvidiaCapability } from './gpu-nvidia.js';
5
+ import { providerClaimsCapability } from './provider-claims.js';
6
+ export { nodeTeeCapability, providerTeeCapability, sellerBoundCapability, measuredImageCapability, gpuNvidiaCapability, providerClaimsCapability };
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/caps/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AACvE,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAA;AACzD,OAAO,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAA;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AACrD,OAAO,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAA;AAgB/D,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,CAAA"}
@@ -0,0 +1,21 @@
1
+ import { registerCapability } from '../capability.js';
2
+ import { nodeTeeCapability, providerTeeCapability } from './tee-tdx.js';
3
+ import { sellerBoundCapability } from './seller-bound.js';
4
+ import { measuredImageCapability } from './measured-image.js';
5
+ import { gpuNvidiaCapability } from './gpu-nvidia.js';
6
+ import { providerClaimsCapability } from './provider-claims.js';
7
+ /**
8
+ * Registration order defines both the advertised menu order and the seller's collect order.
9
+ * Invariant: seller-bound signs over the whole bundle, so every evidence-producing cap (the
10
+ * TDX caps, gpu-cc and provider-claims) must be registered before seller-bound. They are then
11
+ * already collected when it builds the digest it signs. measured-image derives from the
12
+ * provider quote (no own evidence), so its position does not matter.
13
+ */
14
+ registerCapability(nodeTeeCapability);
15
+ registerCapability(providerTeeCapability);
16
+ registerCapability(gpuNvidiaCapability);
17
+ registerCapability(providerClaimsCapability);
18
+ registerCapability(sellerBoundCapability);
19
+ registerCapability(measuredImageCapability);
20
+ export { nodeTeeCapability, providerTeeCapability, sellerBoundCapability, measuredImageCapability, gpuNvidiaCapability, providerClaimsCapability };
21
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/caps/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AACrD,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AACvE,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAA;AACzD,OAAO,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAA;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AACrD,OAAO,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAA;AAE/D;;;;;;GAMG;AACH,kBAAkB,CAAC,iBAAiB,CAAC,CAAA;AACrC,kBAAkB,CAAC,qBAAqB,CAAC,CAAA;AACzC,kBAAkB,CAAC,mBAAmB,CAAC,CAAA;AACvC,kBAAkB,CAAC,wBAAwB,CAAC,CAAA;AAC5C,kBAAkB,CAAC,qBAAqB,CAAC,CAAA;AACzC,kBAAkB,CAAC,uBAAuB,CAAC,CAAA;AAE3C,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,CAAA"}
@@ -0,0 +1,14 @@
1
+ import type { Capability } from '../capability.js';
2
+ /** One approved image fingerprint. Hex strings (no 0x); rtmrN optional (checked when present). */
3
+ export interface ApprovedMeasurement {
4
+ mrtd: string;
5
+ rtmr0?: string;
6
+ rtmr1?: string;
7
+ rtmr2?: string;
8
+ rtmr3?: string;
9
+ }
10
+ export interface MeasuredImagePolicy {
11
+ approvedMeasurements?: ApprovedMeasurement[];
12
+ }
13
+ export declare const measuredImageCapability: Capability;
14
+ //# sourceMappingURL=measured-image.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"measured-image.d.ts","sourceRoot":"","sources":["../../src/caps/measured-image.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAyB,MAAM,kBAAkB,CAAA;AAezE,kGAAkG;AAClG,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,mBAAmB;IAClC,oBAAoB,CAAC,EAAE,mBAAmB,EAAE,CAAA;CAC7C;AAoBD,eAAO,MAAM,uBAAuB,EAAE,UAoBrC,CAAA"}
@@ -0,0 +1,46 @@
1
+ import { claimId } from '../shared.js';
2
+ /**
3
+ * Capability 'seller-provider-measured-image': proves the inference provider booted a
4
+ * specific, approved software image. It compares the provider TDX quote's authenticated
5
+ * measurements (MRTD + RTMR0-3) to a buyer-supplied allow-list. The approved measurements
6
+ * are pure data passed in via policy — never fetched, never hardcoded — so the SDK stays
7
+ * provider-agnostic. With no policy it returns ok:false; it never passes by default. It
8
+ * derives from the provider quote, so it has no own evidence.
9
+ */
10
+ const CAP_ID = 'seller-provider-measured-image';
11
+ function hex(b) {
12
+ return Buffer.from(b).toString('hex');
13
+ }
14
+ /** A measurement matches only if every field it specifies equals the quote's value. */
15
+ function matches(m, td) {
16
+ if (!td)
17
+ return false;
18
+ const eq = (expected, actual) => expected === undefined || expected.toLowerCase() === hex(actual);
19
+ return (m.mrtd.toLowerCase() === hex(td.mrTd) &&
20
+ eq(m.rtmr0, td.rtMr0) &&
21
+ eq(m.rtmr1, td.rtMr1) &&
22
+ eq(m.rtmr2, td.rtMr2) &&
23
+ eq(m.rtmr3, td.rtMr3));
24
+ }
25
+ export const measuredImageCapability = {
26
+ id: CAP_ID,
27
+ verify(input) {
28
+ const claim = claimId(CAP_ID);
29
+ const p = input.parsedQuote;
30
+ if (!p || !p.td)
31
+ return { claim, ok: false, detail: 'no TDX measurements available (a verified tee-tdx quote is required)' };
32
+ const policy = input.policy;
33
+ const approved = policy?.approvedMeasurements;
34
+ if (!approved || approved.length === 0) {
35
+ return { claim, ok: false, detail: 'no approved measurement set configured' };
36
+ }
37
+ if (!approved.some((m) => matches(m, p.td))) {
38
+ return { claim, ok: false, detail: `MRTD ${hex(p.td.mrTd).slice(0, 16)}… matches no approved measurement` };
39
+ }
40
+ // A matching measurement alone says nothing about freshness. Without a report_data scheme
41
+ // that binds this quote to the round, it could be a genuine but replayed or borrowed quote.
42
+ const caveat = p.binding ? '' : ' (freshness/instance binding NOT verified — no report_data scheme declared)';
43
+ return { claim, ok: true, detail: `measurements match an approved image (MRTD ${hex(p.td.mrTd).slice(0, 16)}…)${caveat}` };
44
+ },
45
+ };
46
+ //# sourceMappingURL=measured-image.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"measured-image.js","sourceRoot":"","sources":["../../src/caps/measured-image.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAEtC;;;;;;;GAOG;AAEH,MAAM,MAAM,GAAG,gCAAgC,CAAA;AAe/C,SAAS,GAAG,CAAC,CAAa;IACxB,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;AACvC,CAAC;AAED,uFAAuF;AACvF,SAAS,OAAO,CAAC,CAAsB,EAAE,EAAwB;IAC/D,IAAI,CAAC,EAAE;QAAE,OAAO,KAAK,CAAA;IACrB,MAAM,EAAE,GAAG,CAAC,QAA4B,EAAE,MAAkB,EAAW,EAAE,CACvE,QAAQ,KAAK,SAAS,IAAI,QAAQ,CAAC,WAAW,EAAE,KAAK,GAAG,CAAC,MAAM,CAAC,CAAA;IAClE,OAAO,CACL,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC;QACrC,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC;QACrB,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC;QACrB,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC;QACrB,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,CACtB,CAAA;AACH,CAAC;AAED,MAAM,CAAC,MAAM,uBAAuB,GAAe;IACjD,EAAE,EAAE,MAAM;IAEV,MAAM,CAAC,KAA4B;QACjC,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;QAC7B,MAAM,CAAC,GAAG,KAAK,CAAC,WAAyC,CAAA;QACzD,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;YAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,sEAAsE,EAAE,CAAA;QAC5H,MAAM,MAAM,GAAG,KAAK,CAAC,MAAyC,CAAA;QAC9D,MAAM,QAAQ,GAAG,MAAM,EAAE,oBAAoB,CAAA;QAC7C,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvC,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,wCAAwC,EAAE,CAAA;QAC/E,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;YAC5C,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,mCAAmC,EAAE,CAAA;QAC7G,CAAC;QACD,0FAA0F;QAC1F,4FAA4F;QAC5F,MAAM,MAAM,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,6EAA6E,CAAA;QAC7G,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,8CAA8C,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,MAAM,EAAE,EAAE,CAAA;IAC5H,CAAC;CACF,CAAA"}
@@ -0,0 +1,52 @@
1
+ import type { Capability } from '../capability.js';
2
+ /**
3
+ * Capability 'seller-provider-claims': carries the inference provider's claims into the
4
+ * protocol with per-claim granularity — one ClaimResult per claim, namespaced
5
+ * '<verifier>:seller-provider-claims/<name>'. The claims menu is frozen in the SDK
6
+ * (PROVIDER_CLAIMS_MENU below), never supplied by the seller or provider; the provider's
7
+ * document supplies values only ({ "<name>": <value> }).
8
+ *
9
+ * Frozen proof levels:
10
+ * 'asserted' the claim may pass on bundle integrity alone: the document rides in the
11
+ * evidence bundle that seller-bound signs (freshness + seller identity).
12
+ * 'tdx-quote' the claim passes only when the provider's TDX quote (verified this round
13
+ * with DCAP as seller-provider-tee-genuine) commits to this exact document
14
+ * and nonce in its report_data (see claimsReportData). The provider's TEE
15
+ * then attests the claim; it is not merely asserted.
16
+ * When the quote binding holds, asserted-level claims are reported TEE-attested too.
17
+ *
18
+ * The document is provider-authored bytes carried verbatim (base64 field on the same
19
+ * config-driven evidence route as the provider quote). The binding hashes the exact
20
+ * bytes, so no re-encoding is allowed anywhere. No provider specifics live here.
21
+ */
22
+ export declare const PROVIDER_CLAIMS_CAP_ID = "seller-provider-claims";
23
+ /** Config-key convention for this cap's collector; mirrors tdxConfigKey. */
24
+ export declare function claimsConfigKey(key: string): string;
25
+ /**
26
+ * Provider quote report_data layout for TEE-attested claims:
27
+ *
28
+ * report_data[ 0:32] = SHA-256( DOMAIN ‖ nonce(32) ‖ SHA-256(claimsDocBytes) )
29
+ * report_data[32:64] = reserved // gpu-cc binds the GPU via the NRAS nonce, not this half
30
+ *
31
+ * `claimsReportData` returns the 32-byte [0:32] commitment; the verifier compares it against
32
+ * the provider quote's first half.
33
+ */
34
+ export declare const PROVIDER_REPORT_DATA_DOMAIN = "antseed-provider-report-data-v1";
35
+ export declare function claimsReportData(nonce: Uint8Array, docBytes: Uint8Array): Uint8Array;
36
+ /** One frozen menu entry: what the claim means, how its value must look, what proves it. */
37
+ export interface ProviderClaimDefinition {
38
+ /** Human meaning of the claim, frozen with its verification semantics. */
39
+ description: string;
40
+ /** Minimum proof required to pass: 'asserted' (bundle-bound) or 'tdx-quote' (TEE-bound). */
41
+ proof: 'asserted' | 'tdx-quote';
42
+ /** Frozen value check; returns a failure reason, or null when the value is acceptable. */
43
+ validate(value: unknown): string | null;
44
+ }
45
+ /**
46
+ * The frozen claims menu for this SDK version. Buyers verify only against these
47
+ * definitions; a document name outside this menu can never pass. Add entries only with
48
+ * an SDK version bump (the CLI trust registry pins the exact version network-wide).
49
+ */
50
+ export declare const PROVIDER_CLAIMS_MENU: Record<string, ProviderClaimDefinition>;
51
+ export declare const providerClaimsCapability: Capability;
52
+ //# sourceMappingURL=provider-claims.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider-claims.d.ts","sourceRoot":"","sources":["../../src/caps/provider-claims.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAiD,MAAM,kBAAkB,CAAA;AAKjG;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,eAAO,MAAM,sBAAsB,2BAA2B,CAAA;AAE9D,4EAA4E;AAC5E,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,2BAA2B,oCAAoC,CAAA;AAE5E,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,GAAG,UAAU,CAOpF;AAED,4FAA4F;AAC5F,MAAM,WAAW,uBAAuB;IACtC,0EAA0E;IAC1E,WAAW,EAAE,MAAM,CAAA;IACnB,4FAA4F;IAC5F,KAAK,EAAE,UAAU,GAAG,WAAW,CAAA;IAC/B,0FAA0F;IAC1F,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAAA;CACxC;AAED;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,uBAAuB,CAiBxE,CAAA;AAwED,eAAO,MAAM,wBAAwB,EAAE,UA0DtC,CAAA"}
@@ -0,0 +1,195 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { claimId } from '../shared.js';
3
+ import { collectViaHttp } from '../collect/http.js';
4
+ import { isTcbAcceptable } from './tee-tdx.js';
5
+ /**
6
+ * Capability 'seller-provider-claims': carries the inference provider's claims into the
7
+ * protocol with per-claim granularity — one ClaimResult per claim, namespaced
8
+ * '<verifier>:seller-provider-claims/<name>'. The claims menu is frozen in the SDK
9
+ * (PROVIDER_CLAIMS_MENU below), never supplied by the seller or provider; the provider's
10
+ * document supplies values only ({ "<name>": <value> }).
11
+ *
12
+ * Frozen proof levels:
13
+ * 'asserted' the claim may pass on bundle integrity alone: the document rides in the
14
+ * evidence bundle that seller-bound signs (freshness + seller identity).
15
+ * 'tdx-quote' the claim passes only when the provider's TDX quote (verified this round
16
+ * with DCAP as seller-provider-tee-genuine) commits to this exact document
17
+ * and nonce in its report_data (see claimsReportData). The provider's TEE
18
+ * then attests the claim; it is not merely asserted.
19
+ * When the quote binding holds, asserted-level claims are reported TEE-attested too.
20
+ *
21
+ * The document is provider-authored bytes carried verbatim (base64 field on the same
22
+ * config-driven evidence route as the provider quote). The binding hashes the exact
23
+ * bytes, so no re-encoding is allowed anywhere. No provider specifics live here.
24
+ */
25
+ export const PROVIDER_CLAIMS_CAP_ID = 'seller-provider-claims';
26
+ /** Config-key convention for this cap's collector; mirrors tdxConfigKey. */
27
+ export function claimsConfigKey(key) {
28
+ return `${PROVIDER_CLAIMS_CAP_ID}.${key}`;
29
+ }
30
+ /**
31
+ * Provider quote report_data layout for TEE-attested claims:
32
+ *
33
+ * report_data[ 0:32] = SHA-256( DOMAIN ‖ nonce(32) ‖ SHA-256(claimsDocBytes) )
34
+ * report_data[32:64] = reserved // gpu-cc binds the GPU via the NRAS nonce, not this half
35
+ *
36
+ * `claimsReportData` returns the 32-byte [0:32] commitment; the verifier compares it against
37
+ * the provider quote's first half.
38
+ */
39
+ export const PROVIDER_REPORT_DATA_DOMAIN = 'antseed-provider-report-data-v1';
40
+ export function claimsReportData(nonce, docBytes) {
41
+ const docHash = createHash('sha256').update(Buffer.from(docBytes)).digest();
42
+ const h = createHash('sha256');
43
+ h.update(Buffer.from(PROVIDER_REPORT_DATA_DOMAIN, 'utf8'));
44
+ h.update(Buffer.from(nonce));
45
+ h.update(docHash);
46
+ return new Uint8Array(h.digest());
47
+ }
48
+ /**
49
+ * The frozen claims menu for this SDK version. Buyers verify only against these
50
+ * definitions; a document name outside this menu can never pass. Add entries only with
51
+ * an SDK version bump (the CLI trust registry pins the exact version network-wide).
52
+ */
53
+ export const PROVIDER_CLAIMS_MENU = {
54
+ 'model-id': {
55
+ description: 'the model identifier this provider serves for the routed requests',
56
+ proof: 'asserted',
57
+ validate: (v) => typeof v === 'string' && v.length > 0 && v.length <= 200
58
+ ? null
59
+ : 'expected a non-empty string (max 200 chars)',
60
+ },
61
+ 'serving-image-digest': {
62
+ description: 'digest of the serving-stack image handling requests inside the provider TEE',
63
+ proof: 'tdx-quote',
64
+ validate: (v) => typeof v === 'string' && /^sha256:[0-9a-f]{64}$/.test(v)
65
+ ? null
66
+ : 'expected "sha256:<64 lowercase hex>"',
67
+ },
68
+ };
69
+ /** Claim names become protocol claim-id path segments; keep them id-safe and bounded. */
70
+ const CLAIM_NAME_RE = /^[a-z0-9][a-z0-9.-]{0,63}$/;
71
+ /** Hard bound on claims per document, so a provider cannot flood the buyer's report. */
72
+ const MAX_CLAIMS = 64;
73
+ /** Hard bound on the claims document size before JSON.parse (a hostile seller must not force an unbounded parse). */
74
+ const MAX_DOC_BYTES = 64 * 1024;
75
+ /** Parse + validate a claims document envelope. Throws with a doc-level reason. */
76
+ function parseClaimsDoc(bytes) {
77
+ if (bytes.length > MAX_DOC_BYTES) {
78
+ throw new Error(`claims document exceeds ${MAX_DOC_BYTES} bytes (${bytes.length})`);
79
+ }
80
+ let root;
81
+ try {
82
+ root = JSON.parse(new TextDecoder().decode(bytes));
83
+ }
84
+ catch (err) {
85
+ throw new Error(`malformed claims document: ${err instanceof Error ? err.message : String(err)}`);
86
+ }
87
+ if (root === null || typeof root !== 'object' || Array.isArray(root)) {
88
+ throw new Error('malformed claims document: not a JSON object');
89
+ }
90
+ const { version, claims } = root;
91
+ if (version !== undefined && version !== 1) {
92
+ throw new Error(`unsupported claims document version ${JSON.stringify(version)} (expected 1)`);
93
+ }
94
+ if (claims === null || typeof claims !== 'object' || Array.isArray(claims)) {
95
+ throw new Error('malformed claims document: "claims" is not an object');
96
+ }
97
+ const entries = Object.entries(claims);
98
+ if (entries.length === 0)
99
+ throw new Error('claims document declares no claims');
100
+ if (entries.length > MAX_CLAIMS) {
101
+ throw new Error(`claims document has too many claims (${entries.length} > ${MAX_CLAIMS})`);
102
+ }
103
+ for (const [name] of entries) {
104
+ if (!CLAIM_NAME_RE.test(name)) {
105
+ throw new Error(`invalid claim name "${name}": use lowercase letters, digits, hyphen or dot (max 64 chars)`);
106
+ }
107
+ }
108
+ return new Map(entries);
109
+ }
110
+ /** Compact human summary of a claim's value for ClaimResult.detail. */
111
+ function summarize(value) {
112
+ const s = JSON.stringify(value) ?? 'undefined';
113
+ return s.length > 80 ? `${s.slice(0, 77)}…` : s;
114
+ }
115
+ /**
116
+ * One binding verdict per document: is the provider quote genuine and committed to these
117
+ * exact document bytes? Every claim in the document shares it.
118
+ */
119
+ function quoteBinding(p, nonce, docBytes) {
120
+ if (!p)
121
+ return 'no verified provider TDX quote in this round (this claim requires seller-provider-tee-genuine evidence)';
122
+ if (p.error)
123
+ return p.error;
124
+ if (!isTcbAcceptable(p.status))
125
+ return `provider TCB status not acceptable: ${p.status || 'unknown'}`;
126
+ if (!p.td)
127
+ return 'provider quote is not an Intel TDX quote';
128
+ if (p.td.debug === true)
129
+ return 'provider TDX debug mode is enabled';
130
+ // Compare the canonical [0:32] commitment; [32:64] is reserved (gpu-cc binds via NRAS).
131
+ const expected = claimsReportData(nonce, docBytes);
132
+ const rd = p.td.reportData;
133
+ if (rd.length < 32 || !Buffer.from(rd.subarray(0, 32)).equals(Buffer.from(expected))) {
134
+ return 'provider quote report_data does not commit to this claims document';
135
+ }
136
+ return null;
137
+ }
138
+ export const providerClaimsCapability = {
139
+ id: PROVIDER_CLAIMS_CAP_ID,
140
+ verify(input) {
141
+ const parent = claimId(PROVIDER_CLAIMS_CAP_ID);
142
+ if (!input.evidence) {
143
+ return [{ claim: parent, ok: false, detail: 'seller returned no claims document' }];
144
+ }
145
+ let values;
146
+ try {
147
+ values = parseClaimsDoc(input.evidence);
148
+ }
149
+ catch (err) {
150
+ return [{ claim: parent, ok: false, detail: err instanceof Error ? err.message : String(err) }];
151
+ }
152
+ // Bind once per document; every claim shares the verdict.
153
+ const p = input.parsedQuote;
154
+ const bindingFailure = quoteBinding(p, input.nonce, input.evidence);
155
+ const results = [];
156
+ for (const [name, value] of values) {
157
+ const claim = `${parent}/${name}`;
158
+ const def = PROVIDER_CLAIMS_MENU[name];
159
+ if (!def) {
160
+ results.push({ claim, ok: false, detail: `unknown claim "${name}": not in this SDK version's frozen claims menu` });
161
+ continue;
162
+ }
163
+ const invalid = def.validate(value);
164
+ if (invalid) {
165
+ results.push({ claim, ok: false, detail: `invalid value: ${invalid}` });
166
+ continue;
167
+ }
168
+ if (def.proof === 'tdx-quote' && bindingFailure) {
169
+ results.push({ claim, ok: false, detail: bindingFailure });
170
+ continue;
171
+ }
172
+ // An asserted-level pass is a signed self-assertion, not an independent measurement.
173
+ // Label it so buyer UIs and policy cannot render it as "verified".
174
+ results.push({
175
+ claim,
176
+ ok: true,
177
+ detail: bindingFailure
178
+ ? `provider-asserted only, NOT independently verified: ${summarize(value)}`
179
+ : `attested by provider TEE (report_data-bound TDX quote): ${summarize(value)}`,
180
+ });
181
+ }
182
+ return results;
183
+ },
184
+ async collect(input) {
185
+ const url = input.config[claimsConfigKey('url')];
186
+ const field = input.config[claimsConfigKey('field')];
187
+ if (!url || !field) {
188
+ throw new Error(`${PROVIDER_CLAIMS_CAP_ID} requires an evidence url and a claims field; not offered`);
189
+ }
190
+ // collectViaHttp base64-decodes the field — the document bytes arrive verbatim, which
191
+ // the tdx-quote binding depends on (report_data hashes the exact bytes).
192
+ return collectViaHttp(url, input.nonce, field);
193
+ },
194
+ };
195
+ //# sourceMappingURL=provider-claims.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider-claims.js","sourceRoot":"","sources":["../../src/caps/provider-claims.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { Capability } from '../capability.js';
2
+ /** Recover the 40-hex (lowercase, no 0x) EVM address that produced an r‖s‖v signature. */
3
+ export declare function recoverEvmAddress(digest: Uint8Array, sig: Uint8Array): string;
4
+ /** Build a signer over 32-byte digests from a hex private key; it emits r‖s‖v (v = 27/28). */
5
+ export declare function signerFromPrivateKey(privHex: string): (msg: Uint8Array) => Promise<Uint8Array>;
6
+ /** The 40-hex EVM address a private key corresponds to (for seller-side consistency checks). */
7
+ export declare function evmAddressFromPrivateKey(privHex: string): string;
8
+ export declare const sellerBoundCapability: Capability;
9
+ //# sourceMappingURL=seller-bound.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seller-bound.d.ts","sourceRoot":"","sources":["../../src/caps/seller-bound.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAiD,MAAM,kBAAkB,CAAA;AAejG,0FAA0F;AAC1F,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,UAAU,GAAG,MAAM,CAW7E;AAED,8FAA8F;AAC9F,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,CAAC,GAAG,EAAE,UAAU,KAAK,OAAO,CAAC,UAAU,CAAC,CAW9F;AAED,gGAAgG;AAChG,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAIhE;AAED,eAAO,MAAM,qBAAqB,EAAE,UA+CnC,CAAA"}