agent-passport-system 3.0.0 → 3.2.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 +7 -4
- package/dist/src/adapters/governance-hook.d.ts.map +1 -1
- package/dist/src/adapters/ibac-cedar.d.ts.map +1 -1
- package/dist/src/adapters/ibac-cedar.js +22 -4
- package/dist/src/adapters/ibac-cedar.js.map +1 -1
- package/dist/src/adapters/langchain.d.ts +1 -1
- package/dist/src/adapters/langchain.d.ts.map +1 -1
- package/dist/src/adapters/mcp.d.ts.map +1 -1
- package/dist/src/adapters/oauth-id-jag/index.js.map +1 -1
- package/dist/src/adapters/oauth-id-jag/types.d.ts.map +1 -1
- package/dist/src/adapters/oauth-id-jag/types.js.map +1 -1
- package/dist/src/adapters/oauth-rfc8693/types.d.ts +7 -7
- package/dist/src/adapters/oauth-rfc8693/types.d.ts.map +1 -1
- package/dist/src/adapters/remote-signer/handle-signer.d.ts.map +1 -1
- package/dist/src/adapters/remote-signer/local-signer.d.ts.map +1 -1
- package/dist/src/adapters/remote-signer/types.d.ts.map +1 -1
- package/dist/src/cli/index.js +12 -5
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/core/anchor-state.js.map +1 -1
- package/dist/src/core/aps-txt.js.map +1 -1
- package/dist/src/core/attestation.js.map +1 -1
- package/dist/src/core/canonical-jcs.js.map +1 -1
- package/dist/src/core/commerce.d.ts +1 -1
- package/dist/src/core/commerce.d.ts.map +1 -1
- package/dist/src/core/context.d.ts.map +1 -1
- package/dist/src/core/cross-chain.js.map +1 -1
- package/dist/src/core/data-enforcement.d.ts.map +1 -1
- package/dist/src/core/data-gateway.d.ts.map +1 -1
- package/dist/src/core/data-lifecycle.js.map +1 -1
- package/dist/src/core/data-source-attribution.js.map +1 -1
- package/dist/src/core/did-interop.d.ts.map +1 -1
- package/dist/src/core/did-interop.js +63 -0
- package/dist/src/core/did-interop.js.map +1 -1
- package/dist/src/core/execution-attestation.js.map +1 -1
- package/dist/src/core/gateway.d.ts.map +1 -1
- package/dist/src/core/governance.js.map +1 -1
- package/dist/src/core/obligations.js.map +1 -1
- package/dist/src/core/passport.js.map +1 -1
- package/dist/src/core/policy.d.ts.map +1 -1
- package/dist/src/core/principal.js.map +1 -1
- package/dist/src/core/reputation-authority.js.map +1 -1
- package/dist/src/core/time.js.map +1 -1
- package/dist/src/core/values.js.map +1 -1
- package/dist/src/crypto/key-storage.d.ts.map +1 -1
- package/dist/src/crypto/keys.js +1 -1
- package/dist/src/crypto/keys.js.map +1 -1
- package/dist/src/decisionReceipt.d.ts +3 -3
- package/dist/src/errors/identity-composition-error.d.ts.map +1 -1
- package/dist/src/errors/identity-composition-error.js.map +1 -1
- package/dist/src/interop/qntm-bridge.d.ts.map +1 -1
- package/dist/src/interop/qntm-bridge.js +36 -4
- package/dist/src/interop/qntm-bridge.js.map +1 -1
- package/dist/src/storage/volatile-backend.d.ts.map +1 -1
- package/dist/src/v2/accountability/__tests__/bundle.test.js.map +1 -1
- package/dist/src/v2/accountability/__tests__/contestability.test.js.map +1 -1
- package/dist/src/v2/accountability/__tests__/custody.test.js.map +1 -1
- package/dist/src/v2/accountability/__tests__/fixtures.test.js.map +1 -1
- package/dist/src/v2/assurance/descriptor.js.map +1 -1
- package/dist/src/v2/attribution-primitive/canonical.js.map +1 -1
- package/dist/src/v2/attribution-primitive/merkle.js.map +1 -1
- package/dist/src/v2/attribution-primitive/residual.js.map +1 -1
- package/dist/src/v2/attribution-weights/compute-axis.js.map +1 -1
- package/dist/src/v2/audience-binding/types.d.ts +1 -1
- package/dist/src/v2/bridge.js.map +1 -1
- package/dist/src/v2/claim-evidence-types.d.ts +5 -5
- package/dist/src/v2/claim-evidence-types.d.ts.map +1 -1
- package/dist/src/v2/composition-check/types.d.ts +2 -2
- package/dist/src/v2/context-provenance/__tests__/cross-lang-parity.test.js.map +1 -1
- package/dist/src/v2/context-provenance/vectors/generate-vectors.js.map +1 -1
- package/dist/src/v2/cross_issuer_attestation/__tests__/cross_issuer_attestation.test.js.map +1 -1
- package/dist/src/v2/delegation-v2.js.map +1 -1
- package/dist/src/v2/feasibility/__tests__/feasibility.test.js.map +1 -1
- package/dist/src/v2/feasibility/compiler.js.map +1 -1
- package/dist/src/v2/hash-pointer/profile.js.map +1 -1
- package/dist/src/v2/hash-pointer/types.d.ts +1 -1
- package/dist/src/v2/human-escalation.js.map +1 -1
- package/dist/src/v2/instruction-provenance/canonicalize.d.ts.map +1 -1
- package/dist/src/v2/instruction-provenance/canonicalize.js.map +1 -1
- package/dist/src/v2/instruction-provenance/envelope.d.ts.map +1 -1
- package/dist/src/v2/instruction-provenance/envelope.js.map +1 -1
- package/dist/src/v2/key-resolution/resolver.d.ts.map +1 -1
- package/dist/src/v2/key-resolution/resolver.js.map +1 -1
- package/dist/src/v2/memory_provenance/__tests__/memory_provenance.test.js.map +1 -1
- package/dist/src/v2/mutual-auth/certificate.js.map +1 -1
- package/dist/src/v2/offline-verifier/middleware.js.map +1 -1
- package/dist/src/v2/offline-verifier/verify.js.map +1 -1
- package/dist/src/v2/outcome-v2.js.map +1 -1
- package/dist/src/v2/payment-rails/acp/index.js.map +1 -1
- package/dist/src/v2/payment-rails/acp/types.d.ts +1 -1
- package/dist/src/v2/payment-rails/ap2/fixtures/_generate.js.map +1 -1
- package/dist/src/v2/payment-rails/ap2/index.js.map +1 -1
- package/dist/src/v2/payment-rails/conformance/binding-harness.js.map +1 -1
- package/dist/src/v2/payment-rails/conformance/fixtures/_generate.js.map +1 -1
- package/dist/src/v2/payment-rails/conformance/harness.js.map +1 -1
- package/dist/src/v2/payment-rails/cycles/evidence-resolution.js.map +1 -1
- package/dist/src/v2/payment-rails/cycles/index.js.map +1 -1
- package/dist/src/v2/payment-rails/cycles/types.d.ts +5 -5
- package/dist/src/v2/payment-rails/fixtures/_generate.js.map +1 -1
- package/dist/src/v2/payment-rails/hooks.js.map +1 -1
- package/dist/src/v2/payment-rails/mpp/index.js.map +1 -1
- package/dist/src/v2/payment-rails/mpp/types.d.ts +1 -1
- package/dist/src/v2/payment-rails/nano.d.ts.map +1 -1
- package/dist/src/v2/payment-rails/scope-resolution.js.map +1 -1
- package/dist/src/v2/payment-rails/stripe-issuing/fixtures/_generate-cross-rail.js.map +1 -1
- package/dist/src/v2/payment-rails/stripe-issuing/fixtures/_generate.js.map +1 -1
- package/dist/src/v2/payment-rails/stripe-issuing/primitives.js.map +1 -1
- package/dist/src/v2/payment-rails/x402/fixtures/_generate.js.map +1 -1
- package/dist/src/v2/payment-rails/x402/index.d.ts.map +1 -1
- package/dist/src/v2/policy-bundle/bundle.js.map +1 -1
- package/dist/src/v2/provisional-statement/promote.js.map +1 -1
- package/dist/src/v2/read_fidelity_receipt/__tests__/read_fidelity_receipt.test.d.ts +2 -0
- package/dist/src/v2/read_fidelity_receipt/__tests__/read_fidelity_receipt.test.d.ts.map +1 -0
- package/dist/src/v2/read_fidelity_receipt/__tests__/read_fidelity_receipt.test.js +392 -0
- package/dist/src/v2/read_fidelity_receipt/__tests__/read_fidelity_receipt.test.js.map +1 -0
- package/dist/src/v2/read_fidelity_receipt/index.d.ts +4 -0
- package/dist/src/v2/read_fidelity_receipt/index.d.ts.map +1 -0
- package/dist/src/v2/read_fidelity_receipt/index.js +16 -0
- package/dist/src/v2/read_fidelity_receipt/index.js.map +1 -0
- package/dist/src/v2/read_fidelity_receipt/receipt.d.ts +45 -0
- package/dist/src/v2/read_fidelity_receipt/receipt.d.ts.map +1 -0
- package/dist/src/v2/read_fidelity_receipt/receipt.js +283 -0
- package/dist/src/v2/read_fidelity_receipt/receipt.js.map +1 -0
- package/dist/src/v2/read_fidelity_receipt/sampler.d.ts +35 -0
- package/dist/src/v2/read_fidelity_receipt/sampler.d.ts.map +1 -0
- package/dist/src/v2/read_fidelity_receipt/sampler.js +110 -0
- package/dist/src/v2/read_fidelity_receipt/sampler.js.map +1 -0
- package/dist/src/v2/read_fidelity_receipt/types.d.ts +139 -0
- package/dist/src/v2/read_fidelity_receipt/types.d.ts.map +1 -0
- package/dist/src/v2/read_fidelity_receipt/types.js +17 -0
- package/dist/src/v2/read_fidelity_receipt/types.js.map +1 -0
- package/dist/src/v2/read_fidelity_receipt/vectors/generate.d.ts +2 -0
- package/dist/src/v2/read_fidelity_receipt/vectors/generate.d.ts.map +1 -0
- package/dist/src/v2/read_fidelity_receipt/vectors/generate.js +261 -0
- package/dist/src/v2/read_fidelity_receipt/vectors/generate.js.map +1 -0
- package/dist/src/v2/regulated-action/types.d.ts +7 -7
- package/dist/src/v2/regulated-action/types.d.ts.map +1 -1
- package/dist/src/v2/scope-registry/registry.js.map +1 -1
- package/dist/src/v2/semantic-scoping.js.map +1 -1
- package/dist/src/v2/transport/rfc9421/profile.d.ts +1 -1
- package/dist/src/v2/transport/rfc9421/profile.d.ts.map +1 -1
- package/dist/src/v2/transport/rfc9421/signature-base.js.map +1 -1
- package/dist/src/v2/trust-policy/types.d.ts +1 -1
- package/dist/src/v2/trust-policy/well-known.d.ts +2 -2
- package/dist/src/v2/verifier-hardening/index.d.ts.map +1 -1
- package/dist/src/v2/word_handles/__tests__/word_handles.test.d.ts +2 -0
- package/dist/src/v2/word_handles/__tests__/word_handles.test.d.ts.map +1 -0
- package/dist/src/v2/word_handles/__tests__/word_handles.test.js +312 -0
- package/dist/src/v2/word_handles/__tests__/word_handles.test.js.map +1 -0
- package/dist/src/v2/word_handles/codec.d.ts +54 -0
- package/dist/src/v2/word_handles/codec.d.ts.map +1 -0
- package/dist/src/v2/word_handles/codec.js +334 -0
- package/dist/src/v2/word_handles/codec.js.map +1 -0
- package/dist/src/v2/word_handles/index.d.ts +4 -0
- package/dist/src/v2/word_handles/index.d.ts.map +1 -0
- package/dist/src/v2/word_handles/index.js +13 -0
- package/dist/src/v2/word_handles/index.js.map +1 -0
- package/dist/src/v2/word_handles/lexicon.d.ts +7 -0
- package/dist/src/v2/word_handles/lexicon.d.ts.map +1 -0
- package/dist/src/v2/word_handles/lexicon.js +276 -0
- package/dist/src/v2/word_handles/lexicon.js.map +1 -0
- package/dist/src/v2/word_handles/types.d.ts +58 -0
- package/dist/src/v2/word_handles/types.d.ts.map +1 -0
- package/dist/src/v2/word_handles/types.js +13 -0
- package/dist/src/v2/word_handles/types.js.map +1 -0
- package/dist/src/verification/verify.d.ts.map +1 -1
- package/dist/src/verification/verify.js +6 -1
- package/dist/src/verification/verify.js.map +1 -1
- package/package.json +11 -12
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
// Copyright 2024-2026 Tymofii Pidlisnyi. Apache-2.0 license. See LICENSE.
|
|
2
|
+
// ══════════════════════════════════════════════════════════════════
|
|
3
|
+
// read_fidelity_receipt (v2): create and verify
|
|
4
|
+
// ══════════════════════════════════════════════════════════════════
|
|
5
|
+
// Signature convention: sig is EXCLUDED from the signing preimage.
|
|
6
|
+
// The preimage is canonicalizeJCS(record with the sig key removed
|
|
7
|
+
// entirely). Verification order: shape checks and n consistency,
|
|
8
|
+
// then the Ed25519 signature against the embedded attester, then the
|
|
9
|
+
// seed derivation. A record tampered after signing fails on the
|
|
10
|
+
// signature; a record re-signed after a nonce or presentation swap
|
|
11
|
+
// carries a valid signature and fails on the seed derivation, which
|
|
12
|
+
// is the replay binding doing its job.
|
|
13
|
+
// ══════════════════════════════════════════════════════════════════
|
|
14
|
+
import { createHash } from 'node:crypto';
|
|
15
|
+
import { canonicalizeJCS } from '../../core/canonical-jcs.js';
|
|
16
|
+
import { sign, verify as edVerify, publicKeyFromPrivate } from '../../crypto/keys.js';
|
|
17
|
+
import { commitSpans, deriveSeed, sampleSpans, scoreResponses } from './sampler.js';
|
|
18
|
+
const DIGEST_RE = /^sha256:[0-9a-f]{64}$/;
|
|
19
|
+
const HEX64_RE = /^[0-9a-f]{64}$/;
|
|
20
|
+
const HEX128_RE = /^[0-9a-f]{128}$/;
|
|
21
|
+
const ISO_8601_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,9})?(?:Z|[+-]\d{2}:\d{2})$/;
|
|
22
|
+
function sha256hex(input) {
|
|
23
|
+
return createHash('sha256').update(input, 'utf8').digest('hex');
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Canonical signing preimage: RFC 8785 JCS of the record with the
|
|
27
|
+
* `sig` key removed entirely. Accepts a signed record (sig dropped)
|
|
28
|
+
* or an unsigned draft (no sig key present).
|
|
29
|
+
*/
|
|
30
|
+
export function canonicalNoSig(record) {
|
|
31
|
+
const { sig: _sig, ...rest } = record;
|
|
32
|
+
return canonicalizeJCS(rest);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Structural checks shared by verifyReadFidelityReceipt and
|
|
36
|
+
* verifyAgainstSource. Returns the first failing reason, or null when
|
|
37
|
+
* the value is structurally a ReadFidelityReceipt. Does NOT check the
|
|
38
|
+
* signature or the seed derivation.
|
|
39
|
+
*/
|
|
40
|
+
function shapeReason(value) {
|
|
41
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
42
|
+
return 'INVALID_TYPE';
|
|
43
|
+
}
|
|
44
|
+
const r = value;
|
|
45
|
+
if (r.type !== 'read_fidelity_receipt')
|
|
46
|
+
return 'INVALID_TYPE';
|
|
47
|
+
if (typeof r.content_digest !== 'string' || !DIGEST_RE.test(r.content_digest)) {
|
|
48
|
+
return 'INVALID_CONTENT_DIGEST';
|
|
49
|
+
}
|
|
50
|
+
if (r.presentation_digest !== null &&
|
|
51
|
+
(typeof r.presentation_digest !== 'string' ||
|
|
52
|
+
!DIGEST_RE.test(r.presentation_digest))) {
|
|
53
|
+
return 'INVALID_PRESENTATION_DIGEST';
|
|
54
|
+
}
|
|
55
|
+
const challengeReason = challengeShapeReason(r.challenge);
|
|
56
|
+
if (challengeReason !== null)
|
|
57
|
+
return challengeReason;
|
|
58
|
+
const c = r.challenge;
|
|
59
|
+
const commitments = c.span_commitments;
|
|
60
|
+
if (typeof r.n !== 'number' || !Number.isInteger(r.n) || r.n < 1) {
|
|
61
|
+
return 'INVALID_N';
|
|
62
|
+
}
|
|
63
|
+
if (r.n !== commitments.length)
|
|
64
|
+
return 'N_MISMATCH';
|
|
65
|
+
if (typeof r.k !== 'number' ||
|
|
66
|
+
!Number.isInteger(r.k) ||
|
|
67
|
+
r.k < 0 ||
|
|
68
|
+
r.k > r.n) {
|
|
69
|
+
return 'INVALID_K';
|
|
70
|
+
}
|
|
71
|
+
if (typeof r.response_digest !== 'string' || !DIGEST_RE.test(r.response_digest)) {
|
|
72
|
+
return 'INVALID_RESPONSE_DIGEST';
|
|
73
|
+
}
|
|
74
|
+
if (r.scoring_method !== 'exact_match_v1')
|
|
75
|
+
return 'INVALID_SCORING_METHOD';
|
|
76
|
+
if (typeof r.attester !== 'string' || !HEX64_RE.test(r.attester)) {
|
|
77
|
+
return 'INVALID_ATTESTER';
|
|
78
|
+
}
|
|
79
|
+
if (typeof r.model_claim !== 'string' || typeof r.runtime_claim !== 'string') {
|
|
80
|
+
return 'INVALID_CLAIMS';
|
|
81
|
+
}
|
|
82
|
+
if (r.verification_method !== 'asserted' &&
|
|
83
|
+
r.verification_method !== 'provider_attestation') {
|
|
84
|
+
return 'INVALID_VERIFICATION_METHOD';
|
|
85
|
+
}
|
|
86
|
+
for (const field of [
|
|
87
|
+
'challenge_issued_at',
|
|
88
|
+
'response_observed_at',
|
|
89
|
+
'receipt_issued_at',
|
|
90
|
+
]) {
|
|
91
|
+
const t = r[field];
|
|
92
|
+
if (typeof t !== 'string' || !ISO_8601_RE.test(t))
|
|
93
|
+
return 'INVALID_TIMESTAMP';
|
|
94
|
+
}
|
|
95
|
+
if ('lexicon_id' in r || 'lexicon_profile' in r) {
|
|
96
|
+
if (typeof r.lexicon_id !== 'string' || !DIGEST_RE.test(r.lexicon_id)) {
|
|
97
|
+
return 'INVALID_LEXICON_FIELDS';
|
|
98
|
+
}
|
|
99
|
+
if ('lexicon_profile' in r &&
|
|
100
|
+
(typeof r.lexicon_profile !== 'string' || r.lexicon_profile.length === 0)) {
|
|
101
|
+
return 'INVALID_LEXICON_FIELDS';
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (typeof r.sig !== 'string' || !HEX128_RE.test(r.sig)) {
|
|
105
|
+
return 'INVALID_SIG_FORMAT';
|
|
106
|
+
}
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
function challengeShapeReason(value) {
|
|
110
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
111
|
+
return 'INVALID_CHALLENGE';
|
|
112
|
+
}
|
|
113
|
+
const c = value;
|
|
114
|
+
if (typeof c.nonce !== 'string' || c.nonce.length === 0)
|
|
115
|
+
return 'INVALID_CHALLENGE';
|
|
116
|
+
if (typeof c.seed !== 'string' || !HEX64_RE.test(c.seed))
|
|
117
|
+
return 'INVALID_CHALLENGE';
|
|
118
|
+
if (c.algorithm !== 'span_sample_v1')
|
|
119
|
+
return 'INVALID_CHALLENGE';
|
|
120
|
+
if (c.version !== '1')
|
|
121
|
+
return 'INVALID_CHALLENGE';
|
|
122
|
+
if (typeof c.span_len !== 'number' ||
|
|
123
|
+
!Number.isInteger(c.span_len) ||
|
|
124
|
+
c.span_len < 1) {
|
|
125
|
+
return 'INVALID_CHALLENGE';
|
|
126
|
+
}
|
|
127
|
+
if (!Array.isArray(c.span_commitments) || c.span_commitments.length === 0) {
|
|
128
|
+
return 'INVALID_CHALLENGE';
|
|
129
|
+
}
|
|
130
|
+
for (const s of c.span_commitments) {
|
|
131
|
+
if (typeof s !== 'string' || !DIGEST_RE.test(s))
|
|
132
|
+
return 'INVALID_CHALLENGE';
|
|
133
|
+
}
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
function seedMatches(record) {
|
|
137
|
+
return (record.challenge.seed ===
|
|
138
|
+
deriveSeed(record.content_digest, record.presentation_digest, record.challenge.nonce, record.challenge.version));
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Build and sign a read fidelity receipt. Validates the input
|
|
142
|
+
* (n MUST equal challenge.span_commitments.length, challenge.seed MUST
|
|
143
|
+
* equal the seed derivation, every digest MUST be
|
|
144
|
+
* "sha256:<64 lowercase hex>", timestamps MUST be ISO 8601), sets
|
|
145
|
+
* `attester` from the private key, and signs the JCS canonical form of
|
|
146
|
+
* the record with the sig key excluded. Throws on any validation
|
|
147
|
+
* failure; nothing is signed unless the record is internally
|
|
148
|
+
* consistent.
|
|
149
|
+
*/
|
|
150
|
+
export function createReadFidelityReceipt(fields, privateKeyHex) {
|
|
151
|
+
const attester = publicKeyFromPrivate(privateKeyHex);
|
|
152
|
+
const draft = {
|
|
153
|
+
type: 'read_fidelity_receipt',
|
|
154
|
+
content_digest: fields.content_digest,
|
|
155
|
+
presentation_digest: fields.presentation_digest,
|
|
156
|
+
challenge: {
|
|
157
|
+
nonce: fields.challenge.nonce,
|
|
158
|
+
seed: fields.challenge.seed,
|
|
159
|
+
algorithm: fields.challenge.algorithm,
|
|
160
|
+
version: fields.challenge.version,
|
|
161
|
+
span_len: fields.challenge.span_len,
|
|
162
|
+
span_commitments: [...fields.challenge.span_commitments],
|
|
163
|
+
},
|
|
164
|
+
response_digest: fields.response_digest,
|
|
165
|
+
k: fields.k,
|
|
166
|
+
n: fields.n,
|
|
167
|
+
scoring_method: fields.scoring_method,
|
|
168
|
+
attester,
|
|
169
|
+
model_claim: fields.model_claim,
|
|
170
|
+
runtime_claim: fields.runtime_claim,
|
|
171
|
+
verification_method: fields.verification_method,
|
|
172
|
+
challenge_issued_at: fields.challenge_issued_at,
|
|
173
|
+
response_observed_at: fields.response_observed_at,
|
|
174
|
+
receipt_issued_at: fields.receipt_issued_at,
|
|
175
|
+
...(fields.lexicon_id !== undefined ? { lexicon_id: fields.lexicon_id } : {}),
|
|
176
|
+
...(fields.lexicon_profile !== undefined
|
|
177
|
+
? { lexicon_profile: fields.lexicon_profile }
|
|
178
|
+
: {}),
|
|
179
|
+
};
|
|
180
|
+
if (fields.n !== fields.challenge.span_commitments.length) {
|
|
181
|
+
throw new Error(`n (${fields.n}) must equal challenge.span_commitments.length ` +
|
|
182
|
+
`(${fields.challenge.span_commitments.length})`);
|
|
183
|
+
}
|
|
184
|
+
// Full structural validation on the draft plus a placeholder sig so
|
|
185
|
+
// create and verify enforce the identical shape rules.
|
|
186
|
+
const reason = shapeReason({ ...draft, sig: '0'.repeat(128) });
|
|
187
|
+
if (reason !== null) {
|
|
188
|
+
throw new Error(`invalid read fidelity receipt input: ${reason}`);
|
|
189
|
+
}
|
|
190
|
+
const expectedSeed = deriveSeed(fields.content_digest, fields.presentation_digest, fields.challenge.nonce, fields.challenge.version);
|
|
191
|
+
if (fields.challenge.seed !== expectedSeed) {
|
|
192
|
+
throw new Error('challenge.seed does not match the seed derivation over ' +
|
|
193
|
+
'content_digest, presentation_digest, nonce, and version');
|
|
194
|
+
}
|
|
195
|
+
const sig = sign(canonicalNoSig(draft), privateKeyHex);
|
|
196
|
+
return { ...draft, sig };
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Verify a read fidelity receipt: shape checks, n consistency against
|
|
200
|
+
* challenge.span_commitments, Ed25519 signature against the embedded
|
|
201
|
+
* attester, and the seed derivation recompute. Accepts unknown and
|
|
202
|
+
* never throws on malformed input; failures carry a reason code.
|
|
203
|
+
*/
|
|
204
|
+
export function verifyReadFidelityReceipt(record) {
|
|
205
|
+
const reason = shapeReason(record);
|
|
206
|
+
if (reason !== null)
|
|
207
|
+
return { valid: false, reason };
|
|
208
|
+
const r = record;
|
|
209
|
+
if (!edVerify(canonicalNoSig(r), r.sig, r.attester)) {
|
|
210
|
+
return { valid: false, reason: 'SIGNATURE_INVALID' };
|
|
211
|
+
}
|
|
212
|
+
if (!seedMatches(r)) {
|
|
213
|
+
return { valid: false, reason: 'SEED_MISMATCH' };
|
|
214
|
+
}
|
|
215
|
+
return { valid: true };
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Verify a receipt against the source text it claims to sample:
|
|
219
|
+
* everything verifyReadFidelityReceipt checks, plus a recompute of the
|
|
220
|
+
* spans from challenge.seed / n / span_len over `sourceText`, a sha256
|
|
221
|
+
* commitment of each recomputed span, and a positionwise comparison
|
|
222
|
+
* against challenge.span_commitments. ALL commitments must match.
|
|
223
|
+
* `signature_valid` and `seed_valid` are reported independently.
|
|
224
|
+
*/
|
|
225
|
+
export function verifyAgainstSource(record, sourceText) {
|
|
226
|
+
const reason = shapeReason(record);
|
|
227
|
+
if (reason !== null) {
|
|
228
|
+
return {
|
|
229
|
+
valid: false,
|
|
230
|
+
reason,
|
|
231
|
+
commitment_matches: [],
|
|
232
|
+
signature_valid: false,
|
|
233
|
+
seed_valid: false,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
const r = record;
|
|
237
|
+
const signature_valid = edVerify(canonicalNoSig(r), r.sig, r.attester);
|
|
238
|
+
const seed_valid = seedMatches(r);
|
|
239
|
+
let commitment_matches = [];
|
|
240
|
+
let spanReason = null;
|
|
241
|
+
try {
|
|
242
|
+
const spans = sampleSpans(sourceText, r.challenge.seed, r.n, r.challenge.span_len);
|
|
243
|
+
const recomputed = commitSpans(spans.map((s) => s.text));
|
|
244
|
+
commitment_matches = recomputed.map((c, i) => c === r.challenge.span_commitments[i]);
|
|
245
|
+
}
|
|
246
|
+
catch {
|
|
247
|
+
spanReason = 'SPAN_RECOMPUTE_FAILED';
|
|
248
|
+
}
|
|
249
|
+
const allMatch = spanReason === null && commitment_matches.every((m) => m === true);
|
|
250
|
+
const valid = signature_valid && seed_valid && allMatch;
|
|
251
|
+
let failure;
|
|
252
|
+
if (!signature_valid)
|
|
253
|
+
failure = 'SIGNATURE_INVALID';
|
|
254
|
+
else if (!seed_valid)
|
|
255
|
+
failure = 'SEED_MISMATCH';
|
|
256
|
+
else if (spanReason !== null)
|
|
257
|
+
failure = spanReason;
|
|
258
|
+
else if (!allMatch)
|
|
259
|
+
failure = 'COMMITMENT_MISMATCH';
|
|
260
|
+
return valid
|
|
261
|
+
? { valid, commitment_matches, signature_valid, seed_valid }
|
|
262
|
+
: { valid, reason: failure, commitment_matches, signature_valid, seed_valid };
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Recompute k for a set of readback responses against the source text:
|
|
266
|
+
* resample the spans the record commits to, score `responses` under
|
|
267
|
+
* exact_match_v1, and compare the recomputed k with the recorded k and
|
|
268
|
+
* the responses JCS digest with the recorded response_digest. Throws
|
|
269
|
+
* when the source cannot produce the spans (wrong length) or when
|
|
270
|
+
* `responses` has the wrong length; use verifyAgainstSource first to
|
|
271
|
+
* establish that the record matches the source at all.
|
|
272
|
+
*/
|
|
273
|
+
export function verifyResponses(record, sourceText, responses) {
|
|
274
|
+
const spans = sampleSpans(sourceText, record.challenge.seed, record.n, record.challenge.span_len);
|
|
275
|
+
const { k } = scoreResponses(spans.map((s) => s.text), responses);
|
|
276
|
+
const digest = `sha256:${sha256hex(canonicalizeJCS(responses))}`;
|
|
277
|
+
return {
|
|
278
|
+
k_recomputed: k,
|
|
279
|
+
matches_claimed_k: k === record.k,
|
|
280
|
+
response_digest_ok: digest === record.response_digest,
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
//# sourceMappingURL=receipt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"receipt.js","sourceRoot":"","sources":["../../../../src/v2/read_fidelity_receipt/receipt.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { SampledSpan, ScoreResponsesResult } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Derive the challenge seed. The preimage is the RFC 8785 JCS
|
|
4
|
+
* canonicalization of an object carrying the four bound fields, so the
|
|
5
|
+
* component boundaries are unambiguous: presentation_digest is a
|
|
6
|
+
* distinct JSON member (null when absent), never foldable into the
|
|
7
|
+
* nonce. An earlier concatenation preimage let a null-presentation
|
|
8
|
+
* record with nonce = P || N derive the same seed as a P-presentation
|
|
9
|
+
* record with nonce N; the structured preimage closes that.
|
|
10
|
+
*/
|
|
11
|
+
export declare function deriveSeed(contentDigest: string, presentationDigestOrNull: string | null, nonce: string, version: string): string;
|
|
12
|
+
/**
|
|
13
|
+
* Sample `n` spans of `spanLen` code points from `sourceText` at
|
|
14
|
+
* distinct positions determined by `seed` (algorithm span_sample_v1).
|
|
15
|
+
*
|
|
16
|
+
* The source is split into code points via Array.from, so astral
|
|
17
|
+
* characters (emoji) count as one position each and spans never split
|
|
18
|
+
* a surrogate pair. With L code points the position range is
|
|
19
|
+
* L - spanLen + 1. Throws when spanLen or n is not a positive integer,
|
|
20
|
+
* when the source is shorter than spanLen code points, or when n
|
|
21
|
+
* exceeds the position range.
|
|
22
|
+
*/
|
|
23
|
+
export declare function sampleSpans(sourceText: string, seed: string, n: number, spanLen: number): SampledSpan[];
|
|
24
|
+
/**
|
|
25
|
+
* Commit to span texts: "sha256:" + sha256hex(UTF-8 of each span
|
|
26
|
+
* text), in the given (sampling) order.
|
|
27
|
+
*/
|
|
28
|
+
export declare function commitSpans(spanTexts: readonly string[]): string[];
|
|
29
|
+
/**
|
|
30
|
+
* Score responses against span texts under exact_match_v1: exact
|
|
31
|
+
* string equality per index. Throws when the arrays differ in length;
|
|
32
|
+
* a missing response is a protocol error, not a miss.
|
|
33
|
+
*/
|
|
34
|
+
export declare function scoreResponses(spanTexts: readonly string[], responses: readonly string[]): ScoreResponsesResult;
|
|
35
|
+
//# sourceMappingURL=sampler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sampler.d.ts","sourceRoot":"","sources":["../../../../src/v2/read_fidelity_receipt/sampler.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAMnE;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CACxB,aAAa,EAAE,MAAM,EACrB,wBAAwB,EAAE,MAAM,GAAG,IAAI,EACvC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,GACd,MAAM,CASR;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CACzB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,CAAC,EAAE,MAAM,EACT,OAAO,EAAE,MAAM,GACd,WAAW,EAAE,CAqCf;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,CAElE;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,SAAS,EAAE,SAAS,MAAM,EAAE,EAC5B,SAAS,EAAE,SAAS,MAAM,EAAE,GAC3B,oBAAoB,CAYtB"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
// Copyright 2024-2026 Tymofii Pidlisnyi. Apache-2.0 license. See LICENSE.
|
|
2
|
+
// ══════════════════════════════════════════════════════════════════
|
|
3
|
+
// read_fidelity_receipt (v2): seed derivation, span sampler, scoring
|
|
4
|
+
// ══════════════════════════════════════════════════════════════════
|
|
5
|
+
// Deterministic, pure functions: no I/O, no clock, no randomness.
|
|
6
|
+
// Bit-exact across languages:
|
|
7
|
+
// seed = sha256hex(utf8( canonicalizeJCS({
|
|
8
|
+
// content_digest, presentation_digest (null when absent),
|
|
9
|
+
// nonce, version }) )) (RFC 8785 JCS preimage)
|
|
10
|
+
// position i, attempt j:
|
|
11
|
+
// h = sha256(utf8(seed + ":" + i + ":" + j))
|
|
12
|
+
// pos = BE-uint64(first 8 bytes of h) mod range
|
|
13
|
+
// bump j on repeat until the position is unused
|
|
14
|
+
// span text = code points [pos, pos + spanLen), Array.from slicing.
|
|
15
|
+
// ══════════════════════════════════════════════════════════════════
|
|
16
|
+
import { createHash } from 'node:crypto';
|
|
17
|
+
import { canonicalizeJCS } from '../../core/canonical-jcs.js';
|
|
18
|
+
function sha256hex(input) {
|
|
19
|
+
return createHash('sha256').update(input, 'utf8').digest('hex');
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Derive the challenge seed. The preimage is the RFC 8785 JCS
|
|
23
|
+
* canonicalization of an object carrying the four bound fields, so the
|
|
24
|
+
* component boundaries are unambiguous: presentation_digest is a
|
|
25
|
+
* distinct JSON member (null when absent), never foldable into the
|
|
26
|
+
* nonce. An earlier concatenation preimage let a null-presentation
|
|
27
|
+
* record with nonce = P || N derive the same seed as a P-presentation
|
|
28
|
+
* record with nonce N; the structured preimage closes that.
|
|
29
|
+
*/
|
|
30
|
+
export function deriveSeed(contentDigest, presentationDigestOrNull, nonce, version) {
|
|
31
|
+
return sha256hex(canonicalizeJCS({
|
|
32
|
+
content_digest: contentDigest,
|
|
33
|
+
presentation_digest: presentationDigestOrNull,
|
|
34
|
+
nonce,
|
|
35
|
+
version,
|
|
36
|
+
}));
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Sample `n` spans of `spanLen` code points from `sourceText` at
|
|
40
|
+
* distinct positions determined by `seed` (algorithm span_sample_v1).
|
|
41
|
+
*
|
|
42
|
+
* The source is split into code points via Array.from, so astral
|
|
43
|
+
* characters (emoji) count as one position each and spans never split
|
|
44
|
+
* a surrogate pair. With L code points the position range is
|
|
45
|
+
* L - spanLen + 1. Throws when spanLen or n is not a positive integer,
|
|
46
|
+
* when the source is shorter than spanLen code points, or when n
|
|
47
|
+
* exceeds the position range.
|
|
48
|
+
*/
|
|
49
|
+
export function sampleSpans(sourceText, seed, n, spanLen) {
|
|
50
|
+
if (!Number.isInteger(spanLen) || spanLen < 1) {
|
|
51
|
+
throw new Error(`spanLen must be a positive integer, got ${spanLen}`);
|
|
52
|
+
}
|
|
53
|
+
if (!Number.isInteger(n) || n < 1) {
|
|
54
|
+
throw new Error(`n must be a positive integer, got ${n}`);
|
|
55
|
+
}
|
|
56
|
+
const cps = Array.from(sourceText);
|
|
57
|
+
const L = cps.length;
|
|
58
|
+
if (L < spanLen) {
|
|
59
|
+
throw new Error(`source has ${L} code points, need at least spanLen ${spanLen}`);
|
|
60
|
+
}
|
|
61
|
+
const range = L - spanLen + 1;
|
|
62
|
+
if (n > range) {
|
|
63
|
+
throw new Error(`n ${n} exceeds the position range ${range}`);
|
|
64
|
+
}
|
|
65
|
+
const used = new Set();
|
|
66
|
+
const spans = [];
|
|
67
|
+
for (let i = 0; i < n; i++) {
|
|
68
|
+
for (let j = 0;; j++) {
|
|
69
|
+
const h = createHash('sha256')
|
|
70
|
+
.update(`${seed}:${i}:${j}`, 'utf8')
|
|
71
|
+
.digest();
|
|
72
|
+
const pos = Number(h.readBigUInt64BE(0) % BigInt(range));
|
|
73
|
+
if (used.has(pos))
|
|
74
|
+
continue;
|
|
75
|
+
used.add(pos);
|
|
76
|
+
spans.push({
|
|
77
|
+
pos,
|
|
78
|
+
len: spanLen,
|
|
79
|
+
text: cps.slice(pos, pos + spanLen).join(''),
|
|
80
|
+
});
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return spans;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Commit to span texts: "sha256:" + sha256hex(UTF-8 of each span
|
|
88
|
+
* text), in the given (sampling) order.
|
|
89
|
+
*/
|
|
90
|
+
export function commitSpans(spanTexts) {
|
|
91
|
+
return spanTexts.map((t) => `sha256:${sha256hex(t)}`);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Score responses against span texts under exact_match_v1: exact
|
|
95
|
+
* string equality per index. Throws when the arrays differ in length;
|
|
96
|
+
* a missing response is a protocol error, not a miss.
|
|
97
|
+
*/
|
|
98
|
+
export function scoreResponses(spanTexts, responses) {
|
|
99
|
+
if (spanTexts.length !== responses.length) {
|
|
100
|
+
throw new Error(`responses length ${responses.length} does not match span count ${spanTexts.length}`);
|
|
101
|
+
}
|
|
102
|
+
const results = spanTexts.map((t, i) => responses[i] === t);
|
|
103
|
+
let k = 0;
|
|
104
|
+
for (const r of results) {
|
|
105
|
+
if (r)
|
|
106
|
+
k++;
|
|
107
|
+
}
|
|
108
|
+
return { k, results };
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=sampler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sampler.js","sourceRoot":"","sources":["../../../../src/v2/read_fidelity_receipt/sampler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/** Literal tag for record discrimination at the wire level. */
|
|
2
|
+
export type ReadFidelityReceiptType = 'read_fidelity_receipt';
|
|
3
|
+
/** The v1 sampling algorithm identifier. */
|
|
4
|
+
export type ReadFidelitySamplingAlgorithm = 'span_sample_v1';
|
|
5
|
+
/** The v1 scoring method identifier: exact string equality per span. */
|
|
6
|
+
export type ReadFidelityScoringMethod = 'exact_match_v1';
|
|
7
|
+
/**
|
|
8
|
+
* How the executor claims were checked. `asserted` means the attester
|
|
9
|
+
* simply asserts model_claim and runtime_claim; `provider_attestation`
|
|
10
|
+
* means a provider-level attestation backs them.
|
|
11
|
+
*/
|
|
12
|
+
export type ReadFidelityVerificationMethod = 'asserted' | 'provider_attestation';
|
|
13
|
+
/**
|
|
14
|
+
* The challenge block. The nonce is verifier-supplied and never
|
|
15
|
+
* derivable from the document alone. The seed MUST equal
|
|
16
|
+
* sha256hex(utf8( canonicalizeJCS({
|
|
17
|
+
* content_digest, presentation_digest, nonce, version }) ))
|
|
18
|
+
* the RFC 8785 JCS preimage of those four fields (presentation_digest
|
|
19
|
+
* null when absent); verifiers recompute and reject on mismatch, which
|
|
20
|
+
* is the replay binding: reusing commitments under a different nonce,
|
|
21
|
+
* content, or presentation breaks the derivation.
|
|
22
|
+
*/
|
|
23
|
+
export interface ReadFidelityChallenge {
|
|
24
|
+
/** Verifier-supplied; never derivable from the document alone. */
|
|
25
|
+
readonly nonce: string;
|
|
26
|
+
/** MUST equal the seed derivation over content, presentation, nonce, version. */
|
|
27
|
+
readonly seed: string;
|
|
28
|
+
readonly algorithm: ReadFidelitySamplingAlgorithm;
|
|
29
|
+
readonly version: '1';
|
|
30
|
+
/** Span length in code points; required to recompute spans. */
|
|
31
|
+
readonly span_len: number;
|
|
32
|
+
/**
|
|
33
|
+
* sha256 of the UTF-8 bytes of each span text, in sampling order,
|
|
34
|
+
* each as "sha256:<64 lowercase hex>". Raw span texts are NOT in
|
|
35
|
+
* the record.
|
|
36
|
+
*/
|
|
37
|
+
readonly span_commitments: readonly string[];
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* A read fidelity receipt proves sampled readback fidelity at the stated n under the declared sampling
|
|
41
|
+
* assumptions. It does not prove every byte was read correctly, does not prove perception or comprehension,
|
|
42
|
+
* does not prove which channel was used, and carries no normative pass threshold: the consumer judges k of n.
|
|
43
|
+
*/
|
|
44
|
+
export interface ReadFidelityReceipt {
|
|
45
|
+
readonly type: ReadFidelityReceiptType;
|
|
46
|
+
/** Digest of the canonical content bytes, "sha256:<64 lowercase hex>". */
|
|
47
|
+
readonly content_digest: string;
|
|
48
|
+
/** Digest of the rendered presentation as served, or null. */
|
|
49
|
+
readonly presentation_digest: string | null;
|
|
50
|
+
readonly challenge: ReadFidelityChallenge;
|
|
51
|
+
/**
|
|
52
|
+
* "sha256:" + sha256hex(canonicalizeJCS(responses)) where responses
|
|
53
|
+
* is the ordered array of readback strings.
|
|
54
|
+
*/
|
|
55
|
+
readonly response_digest: string;
|
|
56
|
+
/** Count of responses that exactly matched their span text. */
|
|
57
|
+
readonly k: number;
|
|
58
|
+
/** Sample count; MUST equal challenge.span_commitments.length. */
|
|
59
|
+
readonly n: number;
|
|
60
|
+
readonly scoring_method: ReadFidelityScoringMethod;
|
|
61
|
+
/**
|
|
62
|
+
* Ed25519 public key hex of the SIGNING identity. May differ from
|
|
63
|
+
* the executing model; model_claim and runtime_claim are claims
|
|
64
|
+
* about the executor, not proofs.
|
|
65
|
+
*/
|
|
66
|
+
readonly attester: string;
|
|
67
|
+
readonly model_claim: string;
|
|
68
|
+
readonly runtime_claim: string;
|
|
69
|
+
readonly verification_method: ReadFidelityVerificationMethod;
|
|
70
|
+
/** ISO 8601, caller-provided; the library never reads a wall clock. */
|
|
71
|
+
readonly challenge_issued_at: string;
|
|
72
|
+
/** ISO 8601, caller-provided; the library never reads a wall clock. */
|
|
73
|
+
readonly response_observed_at: string;
|
|
74
|
+
/** ISO 8601, caller-provided; the library never reads a wall clock. */
|
|
75
|
+
readonly receipt_issued_at: string;
|
|
76
|
+
/** Optional; present when word_digest_handles appear in the flow. */
|
|
77
|
+
readonly lexicon_id?: string;
|
|
78
|
+
/** Optional; "single-list-v1", alongside lexicon_id. */
|
|
79
|
+
readonly lexicon_profile?: string;
|
|
80
|
+
/** 128 hex chars, Ed25519 over canonicalizeJCS(record with sig excluded). */
|
|
81
|
+
readonly sig: string;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Input to createReadFidelityReceipt: the record minus the fields the
|
|
85
|
+
* library sets itself (`type` is the literal, `attester` is derived
|
|
86
|
+
* from the private key, `sig` is computed).
|
|
87
|
+
*/
|
|
88
|
+
export type CreateReadFidelityReceiptInput = Omit<ReadFidelityReceipt, 'type' | 'attester' | 'sig'>;
|
|
89
|
+
/** One sampled span: code-point position, length, and text. */
|
|
90
|
+
export interface SampledSpan {
|
|
91
|
+
/** Start position in code points (Array.from indexing). */
|
|
92
|
+
readonly pos: number;
|
|
93
|
+
/** Span length in code points; equals the requested spanLen. */
|
|
94
|
+
readonly len: number;
|
|
95
|
+
readonly text: string;
|
|
96
|
+
}
|
|
97
|
+
/** Result of scoreResponses: per-span exact-match flags and their count. */
|
|
98
|
+
export interface ScoreResponsesResult {
|
|
99
|
+
readonly k: number;
|
|
100
|
+
readonly results: readonly boolean[];
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Failure reasons for verifyReadFidelityReceipt and verifyAgainstSource.
|
|
104
|
+
* Check order in verifyReadFidelityReceipt: shape (INVALID_* and
|
|
105
|
+
* N_MISMATCH), then SIGNATURE_INVALID, then SEED_MISMATCH. A record
|
|
106
|
+
* tampered after signing therefore fails on the signature; a record
|
|
107
|
+
* re-signed after a nonce or presentation swap carries a valid
|
|
108
|
+
* signature and fails on the seed derivation instead.
|
|
109
|
+
*/
|
|
110
|
+
export type ReadFidelityVerifyReason = 'INVALID_TYPE' | 'INVALID_CONTENT_DIGEST' | 'INVALID_PRESENTATION_DIGEST' | 'INVALID_CHALLENGE' | 'INVALID_N' | 'N_MISMATCH' | 'INVALID_K' | 'INVALID_RESPONSE_DIGEST' | 'INVALID_SCORING_METHOD' | 'INVALID_ATTESTER' | 'INVALID_CLAIMS' | 'INVALID_VERIFICATION_METHOD' | 'INVALID_TIMESTAMP' | 'INVALID_LEXICON_FIELDS' | 'INVALID_SIG_FORMAT' | 'SIGNATURE_INVALID' | 'SEED_MISMATCH' | 'SPAN_RECOMPUTE_FAILED' | 'COMMITMENT_MISMATCH';
|
|
111
|
+
/** Result of verifyReadFidelityReceipt. */
|
|
112
|
+
export interface ReadFidelityVerifyResult {
|
|
113
|
+
readonly valid: boolean;
|
|
114
|
+
readonly reason?: ReadFidelityVerifyReason;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Result of verifyAgainstSource. `commitment_matches[i]` compares the
|
|
118
|
+
* recomputed commitment of span i against challenge.span_commitments[i];
|
|
119
|
+
* ALL must match for validity. `signature_valid` and `seed_valid` are
|
|
120
|
+
* reported independently so a caller can see which binding broke.
|
|
121
|
+
*/
|
|
122
|
+
export interface VerifyAgainstSourceResult {
|
|
123
|
+
readonly valid: boolean;
|
|
124
|
+
readonly reason?: ReadFidelityVerifyReason;
|
|
125
|
+
readonly commitment_matches: readonly boolean[];
|
|
126
|
+
readonly signature_valid: boolean;
|
|
127
|
+
readonly seed_valid: boolean;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Result of verifyResponses: the recomputed k over the supplied
|
|
131
|
+
* responses, whether it equals the recorded k, and whether the
|
|
132
|
+
* responses JCS-hash to the recorded response_digest.
|
|
133
|
+
*/
|
|
134
|
+
export interface VerifyResponsesResult {
|
|
135
|
+
readonly k_recomputed: number;
|
|
136
|
+
readonly matches_claimed_k: boolean;
|
|
137
|
+
readonly response_digest_ok: boolean;
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/v2/read_fidelity_receipt/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Copyright 2024-2026 Tymofii Pidlisnyi. Apache-2.0 license. See LICENSE.
|
|
2
|
+
// ══════════════════════════════════════════════════════════════════
|
|
3
|
+
// read_fidelity_receipt (v2): TypeScript types
|
|
4
|
+
// ══════════════════════════════════════════════════════════════════
|
|
5
|
+
// A signed record of a sampled readback challenge: a verifier supplies
|
|
6
|
+
// a nonce, the seed binds that nonce to the exact content digest and
|
|
7
|
+
// presentation digest, spans are sampled deterministically from the
|
|
8
|
+
// seed, and the record commits to the span hashes and the scored
|
|
9
|
+
// readback result (k of n). The raw span texts and responses are NOT
|
|
10
|
+
// in the record; only their commitments and digests are.
|
|
11
|
+
//
|
|
12
|
+
// Signature convention: `sig` is EXCLUDED from the signing preimage.
|
|
13
|
+
// The preimage is canonicalizeJCS(record with the sig key removed
|
|
14
|
+
// entirely), NOT a record with sig set to an empty string.
|
|
15
|
+
// ══════════════════════════════════════════════════════════════════
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/v2/read_fidelity_receipt/types.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,qEAAqE;AACrE,+CAA+C;AAC/C,qEAAqE;AACrE,uEAAuE;AACvE,qEAAqE;AACrE,oEAAoE;AACpE,iEAAiE;AACjE,qEAAqE;AACrE,yDAAyD;AACzD,EAAE;AACF,qEAAqE;AACrE,kEAAkE;AAClE,2DAA2D;AAC3D,qEAAqE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../../../../src/v2/read_fidelity_receipt/vectors/generate.ts"],"names":[],"mappings":""}
|