@ziffer-io/verify 0.1.0 → 0.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/dist/clauses.d.ts CHANGED
@@ -50,4 +50,74 @@ export declare const CLAUSE_WIRE_TYPE = "WE-4";
50
50
  * refusal carries the field's (ACP-88/ACP-89).
51
51
  */
52
52
  export declare const CLAUSE_RECEIPT_NONCE_SIZE = "L-17";
53
+ /** Rust `quorum::CLAUSE_NO_ATTESTATIONS` -- INV-1-HIGH, a receipt commits to
54
+ * attestations and none arrived. */
55
+ export declare const CLAUSE_NO_ATTESTATIONS = "INV-1-HIGH";
56
+ /** Rust `quorum::CLAUSE_NO_OBJECT` -- AT-8, an entry carrying no Attestation
57
+ * Object (the pre-v1.3.3 form, where only the id travelled). */
58
+ export declare const CLAUSE_NO_OBJECT = "AT-8";
59
+ /** Rust `quorum::CLAUSE_OBJECT_SCHEMA` -- AT-8b, the object's field set is not
60
+ * exactly AT-1's. CLOSED: an unknown field is refused, a missing one never
61
+ * defaulted (Z4). */
62
+ export declare const CLAUSE_OBJECT_SCHEMA = "AT-8b";
63
+ /** Rust `quorum::CLAUSE_NONCE_SIZE` -- AT-1, `att_nonce` is well-formed but is
64
+ * not 128-bit. The ATTESTATION nonce's own size clause, never L-17 (which sizes
65
+ * the receipt's): one number, two clauses, and the refusal carries the field's. */
66
+ export declare const CLAUSE_ATT_NONCE_SIZE = "AT-1";
67
+ /** Rust `quorum::CLAUSE_ATTESTATION_SUITE` -- CR-4. An UNKNOWN suite refuses
68
+ * here under CR-4 and not CR-1, matching `Bundle.suite_ok`, which returns False
69
+ * for a name it does not know; the receipt path spells the same condition CR-1
70
+ * and the differential compares names, so the reference wins. */
71
+ export declare const CLAUSE_ATTESTATION_SUITE = "CR-4";
72
+ /** Rust `quorum::CLAUSE_ATTESTER_SIG` -- §9.3 step 7b(i). */
73
+ export declare const CLAUSE_ATTESTER_SIG = "9.3-7b-i";
74
+ /** Rust `quorum::CLAUSE_BINDING` -- §9.3 step 7b(ii), the object binds a
75
+ * DIFFERENT proposal. This is Y1: a genuine quorum raised for P1 attached to a
76
+ * receipt for P2. */
77
+ export declare const CLAUSE_BINDING = "9.3-7b-ii";
78
+ /** Rust `quorum::CLAUSE_POLICY_BASIS` -- §9.3 step 7b(iii), policy basis or
79
+ * object freshness. */
80
+ export declare const CLAUSE_POLICY_BASIS = "9.3-7b-iii";
81
+ /** Rust `quorum::CLAUSE_OPERATOR_DISAGREE` -- §9.3 step 7b(iii-a), the objects
82
+ * disagree on who the operator is (Y4). */
83
+ export declare const CLAUSE_OPERATOR_DISAGREE = "9.3-7b-iii-a";
84
+ /** Rust `quorum::CLAUSE_CONSENT` -- AT-9's SECOND requirement: an attester
85
+ * signed for a quorum other than the bundle's. A CONSENT check, not a threshold
86
+ * one; deleting it cannot lower a quorum. */
87
+ export declare const CLAUSE_CONSENT = "AT-9";
88
+ /** Rust `quorum::CLAUSE_DERIVED_ID` -- Y1b, a transmitted `attestation_id`
89
+ * differing from the derived one. */
90
+ export declare const CLAUSE_DERIVED_ID = "Y1b";
91
+ /** Rust `quorum::CLAUSE_MEMBERSHIP` -- AB-1, the entry digest binding: entry
92
+ * schema, digest-list type, or membership. */
93
+ export declare const CLAUSE_MEMBERSHIP = "AB-1";
94
+ /** Rust `quorum::CLAUSE_DIGEST_ORDER` -- AB-2, `attestation_digests` is not in
95
+ * the one canonical ordering. */
96
+ export declare const CLAUSE_DIGEST_ORDER = "AB-2";
97
+ /** Rust `quorum::CLAUSE_DIGEST_DUP` -- AB-3, a repeated digest. */
98
+ export declare const CLAUSE_DIGEST_DUP = "AB-3";
99
+ /** Rust `quorum::CLAUSE_CARDINALITY` -- AB-4, entry count and signed digest
100
+ * count disagree. Fewer is withholding, more is injection. */
101
+ export declare const CLAUSE_CARDINALITY = "AB-4";
102
+ /** Rust `quorum::CLAUSE_ASSURANCE` -- AT-10, an identity enrolled below the
103
+ * registry's assurance floor. */
104
+ export declare const CLAUSE_ASSURANCE = "AT-10";
105
+ /** Rust `quorum::CLAUSE_QUORUM` -- AT-3, fewer distinct approvals than the
106
+ * threshold recomputed from the bundle. */
107
+ export declare const CLAUSE_QUORUM = "AT-3";
108
+ /** Rust `quorum::CLAUSE_OPERATOR_SELF` -- AT-2, the operator counted toward
109
+ * their own quorum. */
110
+ export declare const CLAUSE_OPERATOR_SELF = "AT-2";
111
+ /** Rust `quorum::CLAUSE_WEBAUTHN_ALG` -- HM-3. The object's declared `alg` and
112
+ * the registry's disagree about what KIND of key this identity holds. Either
113
+ * side alone decides nothing; the DISAGREEMENT is the refusal, raised before a
114
+ * byte of the assertion is parsed. */
115
+ export declare const CLAUSE_WEBAUTHN_ALG = "WebauthnAlgMismatch";
116
+ /** Rust `quorum::CLAUSE_WEBAUTHN_COUNTER` -- HM-4 (f). A regression is a CLONED
117
+ * AUTHENTICATOR, not a retry. */
118
+ export declare const CLAUSE_WEBAUTHN_COUNTER = "WebauthnCounter";
119
+ /** Rust `quorum::CLAUSE_MALFORMED` -- the entry's `sig`, the assertion or the
120
+ * credential is not the shape §8.6c declares. Not a statement about a
121
+ * signature. */
122
+ export declare const CLAUSE_MALFORMED = "Malformed";
53
123
  //# sourceMappingURL=clauses.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"clauses.d.ts","sourceRoot":"","sources":["../src/clauses.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,sFAAsF;AACtF,eAAO,MAAM,cAAc,SAAS,CAAC;AACrC,8FAA8F;AAC9F,eAAO,MAAM,gBAAgB,SAAS,CAAC;AACvC,gGAAgG;AAChG,eAAO,MAAM,oBAAoB,SAAS,CAAC;AAC3C,oGAAoG;AACpG,eAAO,MAAM,kBAAkB,SAAS,CAAC;AACzC,6FAA6F;AAC7F,eAAO,MAAM,gBAAgB,UAAU,CAAC;AACxC,oGAAoG;AACpG,eAAO,MAAM,gBAAgB,UAAU,CAAC;AACxC,4EAA4E;AAC5E,eAAO,MAAM,eAAe,UAAU,CAAC;AACvC;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,UAAU,CAAC;AAC/C,qGAAqG;AACrG,eAAO,MAAM,eAAe,UAAU,CAAC;AACvC;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,SAAS,CAAC;AAC7C,6FAA6F;AAC7F,eAAO,MAAM,gBAAgB,SAAS,CAAC;AACvC;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,SAAS,CAAC"}
1
+ {"version":3,"file":"clauses.d.ts","sourceRoot":"","sources":["../src/clauses.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,sFAAsF;AACtF,eAAO,MAAM,cAAc,SAAS,CAAC;AACrC,8FAA8F;AAC9F,eAAO,MAAM,gBAAgB,SAAS,CAAC;AACvC,gGAAgG;AAChG,eAAO,MAAM,oBAAoB,SAAS,CAAC;AAC3C,oGAAoG;AACpG,eAAO,MAAM,kBAAkB,SAAS,CAAC;AACzC,6FAA6F;AAC7F,eAAO,MAAM,gBAAgB,UAAU,CAAC;AACxC,oGAAoG;AACpG,eAAO,MAAM,gBAAgB,UAAU,CAAC;AACxC,4EAA4E;AAC5E,eAAO,MAAM,eAAe,UAAU,CAAC;AACvC;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,UAAU,CAAC;AAC/C,qGAAqG;AACrG,eAAO,MAAM,eAAe,UAAU,CAAC;AACvC;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,SAAS,CAAC;AAC7C,6FAA6F;AAC7F,eAAO,MAAM,gBAAgB,SAAS,CAAC;AACvC;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,SAAS,CAAC;AAUhD;oCACoC;AACpC,eAAO,MAAM,sBAAsB,eAAe,CAAC;AACnD;gEACgE;AAChE,eAAO,MAAM,gBAAgB,SAAS,CAAC;AACvC;;qBAEqB;AACrB,eAAO,MAAM,oBAAoB,UAAU,CAAC;AAC5C;;mFAEmF;AACnF,eAAO,MAAM,qBAAqB,SAAS,CAAC;AAC5C;;;iEAGiE;AACjE,eAAO,MAAM,wBAAwB,SAAS,CAAC;AAC/C,6DAA6D;AAC7D,eAAO,MAAM,mBAAmB,aAAa,CAAC;AAC9C;;qBAEqB;AACrB,eAAO,MAAM,cAAc,cAAc,CAAC;AAC1C;uBACuB;AACvB,eAAO,MAAM,mBAAmB,eAAe,CAAC;AAChD;2CAC2C;AAC3C,eAAO,MAAM,wBAAwB,iBAAiB,CAAC;AACvD;;6CAE6C;AAC7C,eAAO,MAAM,cAAc,SAAS,CAAC;AACrC;qCACqC;AACrC,eAAO,MAAM,iBAAiB,QAAQ,CAAC;AACvC;8CAC8C;AAC9C,eAAO,MAAM,iBAAiB,SAAS,CAAC;AACxC;iCACiC;AACjC,eAAO,MAAM,mBAAmB,SAAS,CAAC;AAC1C,mEAAmE;AACnE,eAAO,MAAM,iBAAiB,SAAS,CAAC;AACxC;8DAC8D;AAC9D,eAAO,MAAM,kBAAkB,SAAS,CAAC;AACzC;iCACiC;AACjC,eAAO,MAAM,gBAAgB,UAAU,CAAC;AACxC;2CAC2C;AAC3C,eAAO,MAAM,aAAa,SAAS,CAAC;AACpC;uBACuB;AACvB,eAAO,MAAM,oBAAoB,SAAS,CAAC;AAC3C;;;sCAGsC;AACtC,eAAO,MAAM,mBAAmB,wBAAwB,CAAC;AACzD;iCACiC;AACjC,eAAO,MAAM,uBAAuB,oBAAoB,CAAC;AACzD;;gBAEgB;AAChB,eAAO,MAAM,gBAAgB,cAAc,CAAC"}
package/dist/clauses.js CHANGED
@@ -50,4 +50,81 @@ export const CLAUSE_WIRE_TYPE = 'WE-4';
50
50
  * refusal carries the field's (ACP-88/ACP-89).
51
51
  */
52
52
  export const CLAUSE_RECEIPT_NONCE_SIZE = 'L-17';
53
+ // ------------------------------------------------------------------ step 7b
54
+ //
55
+ // The AT-* quorum and §8.6b's AB-*, spelled as `crates/acp-decision/src/quorum.rs`
56
+ // and `reference/src/acp_executor.py` spell them. Several are literals at the
57
+ // refusal site in Rust and named here; the VALUE is the contract either way, and
58
+ // the Rust constant name is kept beside each one so a reader diffing the two
59
+ // files sees one table rather than two vocabularies.
60
+ /** Rust `quorum::CLAUSE_NO_ATTESTATIONS` -- INV-1-HIGH, a receipt commits to
61
+ * attestations and none arrived. */
62
+ export const CLAUSE_NO_ATTESTATIONS = 'INV-1-HIGH';
63
+ /** Rust `quorum::CLAUSE_NO_OBJECT` -- AT-8, an entry carrying no Attestation
64
+ * Object (the pre-v1.3.3 form, where only the id travelled). */
65
+ export const CLAUSE_NO_OBJECT = 'AT-8';
66
+ /** Rust `quorum::CLAUSE_OBJECT_SCHEMA` -- AT-8b, the object's field set is not
67
+ * exactly AT-1's. CLOSED: an unknown field is refused, a missing one never
68
+ * defaulted (Z4). */
69
+ export const CLAUSE_OBJECT_SCHEMA = 'AT-8b';
70
+ /** Rust `quorum::CLAUSE_NONCE_SIZE` -- AT-1, `att_nonce` is well-formed but is
71
+ * not 128-bit. The ATTESTATION nonce's own size clause, never L-17 (which sizes
72
+ * the receipt's): one number, two clauses, and the refusal carries the field's. */
73
+ export const CLAUSE_ATT_NONCE_SIZE = 'AT-1';
74
+ /** Rust `quorum::CLAUSE_ATTESTATION_SUITE` -- CR-4. An UNKNOWN suite refuses
75
+ * here under CR-4 and not CR-1, matching `Bundle.suite_ok`, which returns False
76
+ * for a name it does not know; the receipt path spells the same condition CR-1
77
+ * and the differential compares names, so the reference wins. */
78
+ export const CLAUSE_ATTESTATION_SUITE = 'CR-4';
79
+ /** Rust `quorum::CLAUSE_ATTESTER_SIG` -- §9.3 step 7b(i). */
80
+ export const CLAUSE_ATTESTER_SIG = '9.3-7b-i';
81
+ /** Rust `quorum::CLAUSE_BINDING` -- §9.3 step 7b(ii), the object binds a
82
+ * DIFFERENT proposal. This is Y1: a genuine quorum raised for P1 attached to a
83
+ * receipt for P2. */
84
+ export const CLAUSE_BINDING = '9.3-7b-ii';
85
+ /** Rust `quorum::CLAUSE_POLICY_BASIS` -- §9.3 step 7b(iii), policy basis or
86
+ * object freshness. */
87
+ export const CLAUSE_POLICY_BASIS = '9.3-7b-iii';
88
+ /** Rust `quorum::CLAUSE_OPERATOR_DISAGREE` -- §9.3 step 7b(iii-a), the objects
89
+ * disagree on who the operator is (Y4). */
90
+ export const CLAUSE_OPERATOR_DISAGREE = '9.3-7b-iii-a';
91
+ /** Rust `quorum::CLAUSE_CONSENT` -- AT-9's SECOND requirement: an attester
92
+ * signed for a quorum other than the bundle's. A CONSENT check, not a threshold
93
+ * one; deleting it cannot lower a quorum. */
94
+ export const CLAUSE_CONSENT = 'AT-9';
95
+ /** Rust `quorum::CLAUSE_DERIVED_ID` -- Y1b, a transmitted `attestation_id`
96
+ * differing from the derived one. */
97
+ export const CLAUSE_DERIVED_ID = 'Y1b';
98
+ /** Rust `quorum::CLAUSE_MEMBERSHIP` -- AB-1, the entry digest binding: entry
99
+ * schema, digest-list type, or membership. */
100
+ export const CLAUSE_MEMBERSHIP = 'AB-1';
101
+ /** Rust `quorum::CLAUSE_DIGEST_ORDER` -- AB-2, `attestation_digests` is not in
102
+ * the one canonical ordering. */
103
+ export const CLAUSE_DIGEST_ORDER = 'AB-2';
104
+ /** Rust `quorum::CLAUSE_DIGEST_DUP` -- AB-3, a repeated digest. */
105
+ export const CLAUSE_DIGEST_DUP = 'AB-3';
106
+ /** Rust `quorum::CLAUSE_CARDINALITY` -- AB-4, entry count and signed digest
107
+ * count disagree. Fewer is withholding, more is injection. */
108
+ export const CLAUSE_CARDINALITY = 'AB-4';
109
+ /** Rust `quorum::CLAUSE_ASSURANCE` -- AT-10, an identity enrolled below the
110
+ * registry's assurance floor. */
111
+ export const CLAUSE_ASSURANCE = 'AT-10';
112
+ /** Rust `quorum::CLAUSE_QUORUM` -- AT-3, fewer distinct approvals than the
113
+ * threshold recomputed from the bundle. */
114
+ export const CLAUSE_QUORUM = 'AT-3';
115
+ /** Rust `quorum::CLAUSE_OPERATOR_SELF` -- AT-2, the operator counted toward
116
+ * their own quorum. */
117
+ export const CLAUSE_OPERATOR_SELF = 'AT-2';
118
+ /** Rust `quorum::CLAUSE_WEBAUTHN_ALG` -- HM-3. The object's declared `alg` and
119
+ * the registry's disagree about what KIND of key this identity holds. Either
120
+ * side alone decides nothing; the DISAGREEMENT is the refusal, raised before a
121
+ * byte of the assertion is parsed. */
122
+ export const CLAUSE_WEBAUTHN_ALG = 'WebauthnAlgMismatch';
123
+ /** Rust `quorum::CLAUSE_WEBAUTHN_COUNTER` -- HM-4 (f). A regression is a CLONED
124
+ * AUTHENTICATOR, not a retry. */
125
+ export const CLAUSE_WEBAUTHN_COUNTER = 'WebauthnCounter';
126
+ /** Rust `quorum::CLAUSE_MALFORMED` -- the entry's `sig`, the assertion or the
127
+ * credential is not the shape §8.6c declares. Not a statement about a
128
+ * signature. */
129
+ export const CLAUSE_MALFORMED = 'Malformed';
53
130
  //# sourceMappingURL=clauses.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"clauses.js","sourceRoot":"","sources":["../src/clauses.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,sFAAsF;AACtF,MAAM,CAAC,MAAM,cAAc,GAAG,MAAM,CAAC;AACrC,8FAA8F;AAC9F,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC;AACvC,gGAAgG;AAChG,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAC;AAC3C,oGAAoG;AACpG,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC;AACzC,6FAA6F;AAC7F,MAAM,CAAC,MAAM,gBAAgB,GAAG,OAAO,CAAC;AACxC,oGAAoG;AACpG,MAAM,CAAC,MAAM,gBAAgB,GAAG,OAAO,CAAC;AACxC,4EAA4E;AAC5E,MAAM,CAAC,MAAM,eAAe,GAAG,OAAO,CAAC;AACvC;;;;GAIG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,OAAO,CAAC;AAC/C,qGAAqG;AACrG,MAAM,CAAC,MAAM,eAAe,GAAG,OAAO,CAAC;AACvC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,MAAM,CAAC;AAC7C,6FAA6F;AAC7F,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC;AACvC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,MAAM,CAAC"}
1
+ {"version":3,"file":"clauses.js","sourceRoot":"","sources":["../src/clauses.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,sFAAsF;AACtF,MAAM,CAAC,MAAM,cAAc,GAAG,MAAM,CAAC;AACrC,8FAA8F;AAC9F,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC;AACvC,gGAAgG;AAChG,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAC;AAC3C,oGAAoG;AACpG,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC;AACzC,6FAA6F;AAC7F,MAAM,CAAC,MAAM,gBAAgB,GAAG,OAAO,CAAC;AACxC,oGAAoG;AACpG,MAAM,CAAC,MAAM,gBAAgB,GAAG,OAAO,CAAC;AACxC,4EAA4E;AAC5E,MAAM,CAAC,MAAM,eAAe,GAAG,OAAO,CAAC;AACvC;;;;GAIG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,OAAO,CAAC;AAC/C,qGAAqG;AACrG,MAAM,CAAC,MAAM,eAAe,GAAG,OAAO,CAAC;AACvC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,MAAM,CAAC;AAC7C,6FAA6F;AAC7F,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC;AACvC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,MAAM,CAAC;AAEhD,6EAA6E;AAC7E,EAAE;AACF,mFAAmF;AACnF,8EAA8E;AAC9E,iFAAiF;AACjF,6EAA6E;AAC7E,qDAAqD;AAErD;oCACoC;AACpC,MAAM,CAAC,MAAM,sBAAsB,GAAG,YAAY,CAAC;AACnD;gEACgE;AAChE,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC;AACvC;;qBAEqB;AACrB,MAAM,CAAC,MAAM,oBAAoB,GAAG,OAAO,CAAC;AAC5C;;mFAEmF;AACnF,MAAM,CAAC,MAAM,qBAAqB,GAAG,MAAM,CAAC;AAC5C;;;iEAGiE;AACjE,MAAM,CAAC,MAAM,wBAAwB,GAAG,MAAM,CAAC;AAC/C,6DAA6D;AAC7D,MAAM,CAAC,MAAM,mBAAmB,GAAG,UAAU,CAAC;AAC9C;;qBAEqB;AACrB,MAAM,CAAC,MAAM,cAAc,GAAG,WAAW,CAAC;AAC1C;uBACuB;AACvB,MAAM,CAAC,MAAM,mBAAmB,GAAG,YAAY,CAAC;AAChD;2CAC2C;AAC3C,MAAM,CAAC,MAAM,wBAAwB,GAAG,cAAc,CAAC;AACvD;;6CAE6C;AAC7C,MAAM,CAAC,MAAM,cAAc,GAAG,MAAM,CAAC;AACrC;qCACqC;AACrC,MAAM,CAAC,MAAM,iBAAiB,GAAG,KAAK,CAAC;AACvC;8CAC8C;AAC9C,MAAM,CAAC,MAAM,iBAAiB,GAAG,MAAM,CAAC;AACxC;iCACiC;AACjC,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC;AAC1C,mEAAmE;AACnE,MAAM,CAAC,MAAM,iBAAiB,GAAG,MAAM,CAAC;AACxC;8DAC8D;AAC9D,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC;AACzC;iCACiC;AACjC,MAAM,CAAC,MAAM,gBAAgB,GAAG,OAAO,CAAC;AACxC;2CAC2C;AAC3C,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC;AACpC;uBACuB;AACvB,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAC;AAC3C;;;sCAGsC;AACtC,MAAM,CAAC,MAAM,mBAAmB,GAAG,qBAAqB,CAAC;AACzD;iCACiC;AACjC,MAAM,CAAC,MAAM,uBAAuB,GAAG,iBAAiB,CAAC;AACzD;;gBAEgB;AAChB,MAAM,CAAC,MAAM,gBAAgB,GAAG,WAAW,CAAC"}
package/dist/index.d.ts CHANGED
@@ -6,6 +6,11 @@
6
6
  * client adds no verification logic of its own -- one home per rule).
7
7
  */
8
8
  export { canon, compareCodePoints, type Json } from './canon.js';
9
+ export { CborError, cborAsBytes, cborEncode, cborGetInt, cborGetText, cborIsMap, cborKeys, decodeCanonical, type Cbor, type CborMap, } from './cbor.js';
10
+ export { CLAUSE_ASSURANCE, CLAUSE_ATTESTATION_SUITE, CLAUSE_ATTESTER_SIG, CLAUSE_ATT_NONCE_SIZE, CLAUSE_BINDING, CLAUSE_CARDINALITY, CLAUSE_CONSENT, CLAUSE_DERIVED_ID, CLAUSE_DIGEST_DUP, CLAUSE_DIGEST_ORDER, CLAUSE_MALFORMED, CLAUSE_MEMBERSHIP, CLAUSE_NO_ATTESTATIONS, CLAUSE_NO_OBJECT, CLAUSE_OBJECT_SCHEMA, CLAUSE_OPERATOR_DISAGREE, CLAUSE_OPERATOR_SELF, CLAUSE_POLICY_BASIS, CLAUSE_QUORUM, CLAUSE_WEBAUTHN_ALG, CLAUSE_WEBAUTHN_COUNTER, } from './clauses.js';
11
+ export { AT1_FIELDS, attestationId, entryDigest, verifyQuorum, type AttesterCredential, type DecisionBasis, type HybridAttester, type QuorumOutcome, type QuorumPolicy, type WebauthnAttester, } from './quorum.js';
12
+ export { ASSERTION_FIELDS, MALFORMED, REGISTRY_KEY_WEAK, WEBAUTHN_ALGS, WEBAUTHN_AUTHENTICATOR_DATA, WEBAUTHN_CHALLENGE, WEBAUTHN_ORIGIN, WEBAUTHN_PRIMITIVE, WEBAUTHN_SIGNATURE, WEBAUTHN_TYPE, WebauthnRefusal, coseKeyParse, decodeAssertion, verifyWebauthn, webauthnChallenge, type Assertion, type CredentialKey, } from './webauthn.js';
13
+ export { b64Decode } from './wire.js';
9
14
  export { CLAUSE_BODY_SIZE, CLAUSE_CANONICAL, CLAUSE_DECISION, CLAUSE_PROPOSAL_BINDING, CLAUSE_RECEIPT_NONCE_SIZE, CLAUSE_SIGNATURE, CLAUSE_SUITE_FLOOR, CLAUSE_TEMPORAL, CLAUSE_UNKNOWN_SUITE, CLAUSE_VALIDITY_WINDOW, CLAUSE_VERSION, CLAUSE_WIRE_TYPE, } from './clauses.js';
10
15
  export { ED25519_PK_LEN, ED25519_SIG_LEN, ed25519IsSmallOrder, verifyEd25519Strict, } from './ed25519.js';
11
16
  export { parseInstant } from './instant.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,KAAK,EAAE,iBAAiB,EAAE,KAAK,IAAI,EAAE,MAAM,YAAY,CAAC;AACjE,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,uBAAuB,EACvB,yBAAyB,EACzB,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,EACf,oBAAoB,EACpB,sBAAsB,EACtB,cAAc,EACd,gBAAgB,GACjB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,cAAc,EACd,eAAe,EACf,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EACL,UAAU,EACV,cAAc,EACd,eAAe,EACf,YAAY,EACZ,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,gBAAgB,EACrB,KAAK,KAAK,GACX,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,eAAe,EACf,wBAAwB,EACxB,cAAc,EACd,eAAe,EACf,cAAc,EACd,YAAY,EACZ,wBAAwB,EACxB,eAAe,EACf,cAAc,EACd,QAAQ,EACR,aAAa,EACb,KAAK,WAAW,EAChB,KAAK,QAAQ,EACb,KAAK,aAAa,GACnB,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,KAAK,EAAE,iBAAiB,EAAE,KAAK,IAAI,EAAE,MAAM,YAAY,CAAC;AACjE,OAAO,EACL,SAAS,EACT,WAAW,EACX,UAAU,EACV,UAAU,EACV,WAAW,EACX,SAAS,EACT,QAAQ,EACR,eAAe,EACf,KAAK,IAAI,EACT,KAAK,OAAO,GACb,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,gBAAgB,EAChB,wBAAwB,EACxB,mBAAmB,EACnB,qBAAqB,EACrB,cAAc,EACd,kBAAkB,EAClB,cAAc,EACd,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,EACjB,sBAAsB,EACtB,gBAAgB,EAChB,oBAAoB,EACpB,wBAAwB,EACxB,oBAAoB,EACpB,mBAAmB,EACnB,aAAa,EACb,mBAAmB,EACnB,uBAAuB,GACxB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,UAAU,EACV,aAAa,EACb,WAAW,EACX,YAAY,EACZ,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,gBAAgB,GACtB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,gBAAgB,EAChB,SAAS,EACT,iBAAiB,EACjB,aAAa,EACb,2BAA2B,EAC3B,kBAAkB,EAClB,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAClB,aAAa,EACb,eAAe,EACf,YAAY,EACZ,eAAe,EACf,cAAc,EACd,iBAAiB,EACjB,KAAK,SAAS,EACd,KAAK,aAAa,GACnB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,uBAAuB,EACvB,yBAAyB,EACzB,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,EACf,oBAAoB,EACpB,sBAAsB,EACtB,cAAc,EACd,gBAAgB,GACjB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,cAAc,EACd,eAAe,EACf,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EACL,UAAU,EACV,cAAc,EACd,eAAe,EACf,YAAY,EACZ,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,gBAAgB,EACrB,KAAK,KAAK,GACX,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,eAAe,EACf,wBAAwB,EACxB,cAAc,EACd,eAAe,EACf,cAAc,EACd,YAAY,EACZ,wBAAwB,EACxB,eAAe,EACf,cAAc,EACd,QAAQ,EACR,aAAa,EACb,KAAK,WAAW,EAChB,KAAK,QAAQ,EACb,KAAK,aAAa,GACnB,MAAM,aAAa,CAAC"}
package/dist/index.js CHANGED
@@ -6,6 +6,11 @@
6
6
  * client adds no verification logic of its own -- one home per rule).
7
7
  */
8
8
  export { canon, compareCodePoints } from './canon.js';
9
+ export { CborError, cborAsBytes, cborEncode, cborGetInt, cborGetText, cborIsMap, cborKeys, decodeCanonical, } from './cbor.js';
10
+ export { CLAUSE_ASSURANCE, CLAUSE_ATTESTATION_SUITE, CLAUSE_ATTESTER_SIG, CLAUSE_ATT_NONCE_SIZE, CLAUSE_BINDING, CLAUSE_CARDINALITY, CLAUSE_CONSENT, CLAUSE_DERIVED_ID, CLAUSE_DIGEST_DUP, CLAUSE_DIGEST_ORDER, CLAUSE_MALFORMED, CLAUSE_MEMBERSHIP, CLAUSE_NO_ATTESTATIONS, CLAUSE_NO_OBJECT, CLAUSE_OBJECT_SCHEMA, CLAUSE_OPERATOR_DISAGREE, CLAUSE_OPERATOR_SELF, CLAUSE_POLICY_BASIS, CLAUSE_QUORUM, CLAUSE_WEBAUTHN_ALG, CLAUSE_WEBAUTHN_COUNTER, } from './clauses.js';
11
+ export { AT1_FIELDS, attestationId, entryDigest, verifyQuorum, } from './quorum.js';
12
+ export { ASSERTION_FIELDS, MALFORMED, REGISTRY_KEY_WEAK, WEBAUTHN_ALGS, WEBAUTHN_AUTHENTICATOR_DATA, WEBAUTHN_CHALLENGE, WEBAUTHN_ORIGIN, WEBAUTHN_PRIMITIVE, WEBAUTHN_SIGNATURE, WEBAUTHN_TYPE, WebauthnRefusal, coseKeyParse, decodeAssertion, verifyWebauthn, webauthnChallenge, } from './webauthn.js';
13
+ export { b64Decode } from './wire.js';
9
14
  export { CLAUSE_BODY_SIZE, CLAUSE_CANONICAL, CLAUSE_DECISION, CLAUSE_PROPOSAL_BINDING, CLAUSE_RECEIPT_NONCE_SIZE, CLAUSE_SIGNATURE, CLAUSE_SUITE_FLOOR, CLAUSE_TEMPORAL, CLAUSE_UNKNOWN_SUITE, CLAUSE_VALIDITY_WINDOW, CLAUSE_VERSION, CLAUSE_WIRE_TYPE, } from './clauses.js';
10
15
  export { ED25519_PK_LEN, ED25519_SIG_LEN, ed25519IsSmallOrder, verifyEd25519Strict, } from './ed25519.js';
11
16
  export { parseInstant } from './instant.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,KAAK,EAAE,iBAAiB,EAAa,MAAM,YAAY,CAAC;AACjE,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,uBAAuB,EACvB,yBAAyB,EACzB,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,EACf,oBAAoB,EACpB,sBAAsB,EACtB,cAAc,EACd,gBAAgB,GACjB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,cAAc,EACd,eAAe,EACf,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EACL,UAAU,EACV,cAAc,EACd,eAAe,EACf,YAAY,GAKb,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,eAAe,EACf,wBAAwB,EACxB,cAAc,EACd,eAAe,EACf,cAAc,EACd,YAAY,EACZ,wBAAwB,EACxB,eAAe,EACf,cAAc,EACd,QAAQ,EACR,aAAa,GAId,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,KAAK,EAAE,iBAAiB,EAAa,MAAM,YAAY,CAAC;AACjE,OAAO,EACL,SAAS,EACT,WAAW,EACX,UAAU,EACV,UAAU,EACV,WAAW,EACX,SAAS,EACT,QAAQ,EACR,eAAe,GAGhB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,gBAAgB,EAChB,wBAAwB,EACxB,mBAAmB,EACnB,qBAAqB,EACrB,cAAc,EACd,kBAAkB,EAClB,cAAc,EACd,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,EACjB,sBAAsB,EACtB,gBAAgB,EAChB,oBAAoB,EACpB,wBAAwB,EACxB,oBAAoB,EACpB,mBAAmB,EACnB,aAAa,EACb,mBAAmB,EACnB,uBAAuB,GACxB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,UAAU,EACV,aAAa,EACb,WAAW,EACX,YAAY,GAOb,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,gBAAgB,EAChB,SAAS,EACT,iBAAiB,EACjB,aAAa,EACb,2BAA2B,EAC3B,kBAAkB,EAClB,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAClB,aAAa,EACb,eAAe,EACf,YAAY,EACZ,eAAe,EACf,cAAc,EACd,iBAAiB,GAGlB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,uBAAuB,EACvB,yBAAyB,EACzB,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,EACf,oBAAoB,EACpB,sBAAsB,EACtB,cAAc,EACd,gBAAgB,GACjB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,cAAc,EACd,eAAe,EACf,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EACL,UAAU,EACV,cAAc,EACd,eAAe,EACf,YAAY,GAKb,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,eAAe,EACf,wBAAwB,EACxB,cAAc,EACd,eAAe,EACf,cAAc,EACd,YAAY,EACZ,wBAAwB,EACxB,eAAe,EACf,cAAc,EACd,QAAQ,EACR,aAAa,GAId,MAAM,aAAa,CAAC"}
@@ -0,0 +1,245 @@
1
+ /**
2
+ * §9.3 step 7b -- the AT-* quorum and §8.6b's AB-*, run in the CUSTOMER's own
3
+ * process against the CUSTOMER's own signed bundle.
4
+ *
5
+ * # Why this exists (ACP-406 gap 1)
6
+ *
7
+ * Until this module, a customer verifying a ZIFFER receipt checked the
8
+ * signature and the bindings and **trusted us for the approvals**: the header
9
+ * table in `verify.ts` said "7b -- NO, needs the attester registry". A
10
+ * compromised receipt-signing substrate could therefore emit a floor-HIGH
11
+ * receipt carrying fabricated `attestation_digests`, and every customer-side
12
+ * verifier would accept it. The registry is in the customer's OWN signed
13
+ * bundle -- the tree they already load for `policy_bundle_hash` -- so nothing
14
+ * about that trust was necessary. This is the third implementation of the
15
+ * step, after `reference/src/acp_executor.py::_verify_quorum` and
16
+ * `crates/acp-decision/src/quorum.rs`, and the clause names are theirs.
17
+ *
18
+ * # AT-9 is TWO requirements and they fail closed on disjoint inputs
19
+ *
20
+ * 1. The threshold is **recomputed** from the signed bundle's `quorum_k`
21
+ * (PB-6) and never read from an attestation. Through v1.3.14 the reference
22
+ * read `entries[0].required_count` -- asking the party under verification
23
+ * how many signatures to demand -- and one compromised attester key signing
24
+ * one object carrying `required_count: 1` executed a floor-HIGH action.
25
+ * 2. **Every** entry's `required_count` must equal `quorum_k`. That is a
26
+ * CONSENT check (AT-3), not a threshold one: two humans approving while both
27
+ * objects say `3` means they approved believing a third reviewer existed.
28
+ *
29
+ * Deleting (2) cannot lower a quorum; deleting (1) cannot detect an attester
30
+ * who signed under a different stated threshold. Keeping only (1) satisfies
31
+ * INV-1-HIGH while silently executing actions no attester agreed to.
32
+ *
33
+ * # What this CANNOT check customer-side, and why -- read before trusting a pass
34
+ *
35
+ * These are absences, not agreements. Each one is a step of §9.3 this package
36
+ * does not run, and each is disclosed here rather than approximated:
37
+ *
38
+ * - **Whether a quorum was required at all.** §9.3 step 7 recomputes the
39
+ * floor-only risk from the bundle's `floors.json` and `risk_functions.json`;
40
+ * this package does not grade, so it cannot know that a receipt carrying an
41
+ * EMPTY attestation list should have carried a quorum. A receipt with no
42
+ * attestations passes 7b vacuously (AB-1's own note covers the legitimate
43
+ * LOW/MEDIUM case) and {@link verifyQuorum} returns `null` so the caller can
44
+ * see that nothing was verified. **Reading `risk_level_floor_only` off the
45
+ * receipt instead would be X1 -- the defect where a compromised issuer
46
+ * asserting `LOW` suppressed attestation entirely** -- so it is not read.
47
+ * - **`obj.floor_only_risk` against the recomputed grade** (7b(iii), TR-8), for
48
+ * the same reason: there is no recomputed grade here to compare against.
49
+ * - **Single-use of the recomputed `attestation_id`** (7b(v), CL-3). That needs
50
+ * a linearizable Consumption Ledger and this package holds none. Replay
51
+ * protection that forgets is not replay protection, so it is named rather
52
+ * than half-built.
53
+ * - **HM-4 (f)'s stored signature counter** is `T` at this boundary: the caller
54
+ * hands in what it stored and MUST persist what {@link QuorumOutcome}
55
+ * returns. A caller passing an empty map every time has switched (f) off for
56
+ * a credential that has signed before.
57
+ *
58
+ * # One deliberate NARROWING beyond both engine implementations
59
+ *
60
+ * AT-1 says role membership "is resolved against the attester registry", and
61
+ * neither engine implementation resolves it: `quorum.rs` records that
62
+ * `AttesterRole` is generated and read by nothing, and the Python reference has
63
+ * no role field at all. This one does, because the customer's registry carries
64
+ * `role` and their bundle is the authority on who may approve: an entry counts
65
+ * toward the quorum only if its attester's REGISTRY role is named in the
66
+ * object's `required_roles`. An empty list means the rule demanded a quorum and
67
+ * named no role, so any enrolled attester satisfies it (AT-1 as amended in
68
+ * v1.3.32, ACP-308) -- which is byte-for-byte the engine's behaviour, and is the
69
+ * case every ZIFFER deployment is in today except where the policy engine sets
70
+ * `["approver"]`.
71
+ *
72
+ * This is a NARROWER acceptance, never a wider one, and it is stated because a
73
+ * third implementation that refuses what the other two accept is a divergence
74
+ * even when it is the safer side. Its strength is bounded and that is disclosed
75
+ * too: `required_roles` is read from the OBJECT (class **B** -- signed by the
76
+ * attester, evidence of what they were shown), because the bundle names no
77
+ * per-rule role list for it to be recomputed from. A compromised issuer that
78
+ * writes an empty list degrades this check to the engine's behaviour and no
79
+ * further.
80
+ *
81
+ * # Suite 12 classification -- R / B / T for every control input read here
82
+ *
83
+ * | input | class | why |
84
+ * | --- | :---: | --- |
85
+ * | `quorumK` | **R** | from the signed bundle, never an attestation (AT-9) |
86
+ * | attester keys and credentials | **R** | read out of the signed registry after the bundle's own signature checked; `rpId` above all, because HM-4 (c) compares the assertion's origin against THIS and an origin taken from the assertion would compare a value with itself |
87
+ * | `floor` | **R** | the signed manifest's `min_suite` (CR-4) |
88
+ * | `policyBundleHash`, `bundleEpoch` | **R** | the bundle the caller trusts; the object's copies are compared against them (7b(iii)) |
89
+ * | the eleven AT-1 fields | **B** | the attester signature covers the derived id, which covers the whole object |
90
+ * | `obj.proposal_hash` | **B** | and compared against the hash this verifier recomputed from the caller's own proposal bytes (Y1) |
91
+ * | `obj.required_count` | **B** | and compared against `quorumK` (AT-9's consent half) |
92
+ * | `obj.required_roles` | **B** | signed, and resolved against the registry; see the narrowing above for what it does NOT prove |
93
+ * | `entry.attester` | **B** | a name SELECTS a key; the signature establishes identity (ACK-4) |
94
+ * | `entry.attestation_id` | **R** | derived; a transmitted value is compared, never used (Y1b) |
95
+ * | `attestation_digests` | **B** | inside the signed receipt body (AB-5), and each entry's digest is recomputed from the received bytes (AB-1) |
96
+ * | `entry.kind` | **B** | bound by the entry digest under the receipt signature (AB-1). **NARROWED RESIDUAL, not closed**: the attester does not sign `kind`, so the ISSUER still chooses per entry whose signature counts as an approval |
97
+ * | `webauthnCounters` | **T** | the caller's stored counters; this package holds no ledger and says so above |
98
+ */
99
+ import { type Suite } from './suite.js';
100
+ /**
101
+ * AT-8b: the Attestation Object schema is CLOSED. Exactly this field set, no
102
+ * more and no less.
103
+ *
104
+ * An unknown field is refused rather than ignored and a missing one is never
105
+ * defaulted (Z4). Normalising either would let an issuer add a field a future
106
+ * verifier reads, or drop one this verifier checks, without invalidating a
107
+ * signature that covers only what is present.
108
+ */
109
+ export declare const AT1_FIELDS: readonly string[];
110
+ /** A machine attester's hybrid pair, decoded from the signed registry. */
111
+ export interface HybridAttester {
112
+ readonly kind: 'hybrid';
113
+ /** Ed25519 verification key, 32 raw bytes. */
114
+ readonly classical: Uint8Array;
115
+ /** ML-DSA-65 verification key, 1,952 raw bytes. */
116
+ readonly pq: Uint8Array;
117
+ /** The registry's `role`, or null where the entry declares none. */
118
+ readonly role: string | null;
119
+ }
120
+ /**
121
+ * HM-1 -- a human attester's enrolled credential, as the SIGNED registry
122
+ * carries it.
123
+ *
124
+ * No private key is reachable from here: `publicKey` is the COSE_Key the
125
+ * authenticator returned at registration and the private half is on the
126
+ * person's phone or security key. That is the strongest custody statement in
127
+ * this package, and the one a software key file could never make.
128
+ */
129
+ export interface WebauthnAttester {
130
+ readonly kind: 'webauthn';
131
+ /** The approval origin's host. Signed policy (HM-4 (c), (d)). */
132
+ readonly rpId: string;
133
+ /** What the Consumption Ledger keys the signature counter by (HM-4 (f)). */
134
+ readonly credentialId: string;
135
+ /** The COSE_Key bytes, base64-decoded by the caller's bundle loader. */
136
+ readonly publicKey: Uint8Array;
137
+ /** `webauthn-es256` or `webauthn-ed25519` (HM-1). */
138
+ readonly alg: string;
139
+ /** The registry's `role`, or null where the entry declares none. */
140
+ readonly role: string | null;
141
+ }
142
+ /**
143
+ * One registry identity: a machine's hybrid pair or a person's WebAuthn
144
+ * credential.
145
+ *
146
+ * A TAGGED union here because it is a tagged union in the signed document
147
+ * (`attesters.schema.json`, v1.3.30). A kind guessed from which fields are
148
+ * present is how a machine entry that lost its `pq` leg reads as a human.
149
+ */
150
+ export type AttesterCredential = HybridAttester | WebauthnAttester;
151
+ /**
152
+ * The quorum policy. **Every field comes from the customer's SIGNED bundle**,
153
+ * and nothing here may be sourced from the receipt or from an Attestation
154
+ * Object -- that is AT-9 for `quorumK`, PB-KEY for `attesters`, CR-4 for the
155
+ * floor (taken from the {@link import('./verify.js').TrustAnchor}'s `minSuite`,
156
+ * so the package has one definition of the floor and not two).
157
+ */
158
+ export interface QuorumPolicy {
159
+ /** PB-6. The number of DISTINCT approvals a floor-HIGH action requires. */
160
+ readonly quorumK: number;
161
+ /**
162
+ * The attester registry: identity -> credential. PB-7 distinctness over the
163
+ * keys is the BUNDLE LOADER's obligation and is assumed to have run; a second
164
+ * copy here would be two definitions of one rule, so this module depends on
165
+ * that check rather than restating it.
166
+ */
167
+ readonly attesters: ReadonlyMap<string, AttesterCredential>;
168
+ /** AT-10: per-identity enrolled assurance, from the signed registry. */
169
+ readonly assurances: ReadonlyMap<string, string>;
170
+ /** AT-10: the registry's floor (`min_attester_assurance`). */
171
+ readonly minAssurance: string;
172
+ /** Step 4's trusted bundle hash, compared against each object's (7b(iii)). */
173
+ readonly policyBundleHash: string;
174
+ /** Step 4's trusted bundle epoch, compared against each object's (7b(iii)). */
175
+ readonly bundleEpoch: number;
176
+ /**
177
+ * HM-4 (f): the signature counter this verifier has STORED per
178
+ * `credential_id`. **T at this package's boundary** -- see the module header.
179
+ * A credential absent from the map reads as 0, which is what a credential
180
+ * that has never been seen has.
181
+ */
182
+ readonly webauthnCounters?: ReadonlyMap<string, number>;
183
+ }
184
+ /** What {@link verifyQuorum} concluded. */
185
+ export interface QuorumOutcome {
186
+ /** The operator, from the VERIFIED objects (Y4) -- never the receipt body. */
187
+ readonly operator: string;
188
+ /** The distinct attesters whose approvals were counted, sorted. */
189
+ readonly approvals: readonly string[];
190
+ /**
191
+ * HM-4 (f): the counter each credential's assertion carried, by
192
+ * `credential_id`. **The caller MUST persist these**; a verifier that accepts
193
+ * an assertion and does not advance the stored counter has accepted the same
194
+ * assertion twice.
195
+ */
196
+ readonly webauthnCounters: ReadonlyMap<string, number>;
197
+ }
198
+ /** The values every attestation is checked against, established by the caller. */
199
+ export interface DecisionBasis {
200
+ /** The hash this verifier recomputed from the caller's own proposal bytes. */
201
+ readonly proposalHash: string;
202
+ /** The receipt's `issued_at`, already parsed at step 5, epoch seconds. */
203
+ readonly receiptIssuedAt: number;
204
+ /** The CR-4 floor from the signed manifest, as a parsed suite. */
205
+ readonly floor: Suite;
206
+ }
207
+ /**
208
+ * AT-8a -- derive an Attestation Object's id from its canonical bytes.
209
+ * **Derived, never read**: the id names a binding, and a transmitted name for a
210
+ * binding is not evidence of one (Y1b).
211
+ */
212
+ export declare function attestationId(obj: unknown): string;
213
+ /**
214
+ * AB-1 -- the receipt's commitment to ONE attestation entry.
215
+ *
216
+ * ENTRY-SCOPED, NEVER OBJECT-SCOPED, and this is the whole trap.
217
+ * {@link attestationId} already exists and is `h(obj)` -- reusing it here is the
218
+ * obvious move and it is wrong. {@link AT1_FIELDS} is closed over the OBJECT: it
219
+ * contains no `kind`, no `attester` and no `sig`. Quorum composition reads
220
+ * `kind` and `attester` from the ENTRY and the attester signs neither, so an
221
+ * object-scoped digest lets an attacker on the transport path flip `kind` from
222
+ * `confirmation` to `approval` while every digest still matches.
223
+ *
224
+ * The two identifiers MUST NOT be merged: `attestation_id` is what a ledger
225
+ * consumes for single-use under CL-3, because the same object replayed inside a
226
+ * different entry is still a replay. This digest is what the receipt authorised,
227
+ * byte for byte.
228
+ */
229
+ export declare function entryDigest(entry: unknown): string;
230
+ /**
231
+ * §9.3 step 7b over the attestations travelling beside one receipt.
232
+ *
233
+ * @param policy the customer's own signed-bundle quorum policy.
234
+ * @param basis the values recomputed by `verifyReceipt` before this runs.
235
+ * @param entries `receipt.attestations`, as parsed JSON.
236
+ * @param digests `receipt.attestation_digests`, as parsed JSON.
237
+ * @returns the outcome, or `null` when no attestations travelled and none were
238
+ * committed to -- the vacuous LOW/MEDIUM case of AB-1's own note.
239
+ * `null` means "nothing was verified", never "a quorum held": see the
240
+ * module header on why this package cannot tell that a quorum was
241
+ * REQUIRED.
242
+ * @throws {@link Refusal} with the engine's clause names.
243
+ */
244
+ export declare function verifyQuorum(policy: QuorumPolicy, basis: DecisionBasis, entries: unknown, digests: unknown): QuorumOutcome | null;
245
+ //# sourceMappingURL=quorum.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quorum.d.ts","sourceRoot":"","sources":["../src/quorum.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiGG;AAgCH,OAAO,EAA8B,KAAK,KAAK,EAAE,MAAM,YAAY,CAAC;AAcpE;;;;;;;;GAQG;AACH,eAAO,MAAM,UAAU,EAAE,SAAS,MAAM,EAYvC,CAAC;AASF,0EAA0E;AAC1E,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,8CAA8C;IAC9C,QAAQ,CAAC,SAAS,EAAE,UAAU,CAAC;IAC/B,mDAAmD;IACnD,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAC;IACxB,oEAAoE;IACpE,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,iEAAiE;IACjE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,4EAA4E;IAC5E,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,wEAAwE;IACxE,QAAQ,CAAC,SAAS,EAAE,UAAU,CAAC;IAC/B,qDAAqD;IACrD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,oEAAoE;IACpE,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,kBAAkB,GAAG,cAAc,GAAG,gBAAgB,CAAC;AAEnE;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B,2EAA2E;IAC3E,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAC5D,wEAAwE;IACxE,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjD,8DAA8D;IAC9D,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,8EAA8E;IAC9E,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,+EAA+E;IAC/E,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B;;;;;OAKG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACzD;AAED,2CAA2C;AAC3C,MAAM,WAAW,aAAa;IAC5B,8EAA8E;IAC9E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,mEAAmE;IACnE,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC;;;;;OAKG;IACH,QAAQ,CAAC,gBAAgB,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACxD;AAED,kFAAkF;AAClF,MAAM,WAAW,aAAa;IAC5B,8EAA8E;IAC9E,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,0EAA0E;IAC1E,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,kEAAkE;IAClE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;CACvB;AAgBD;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAElD;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAclD;AAuGD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,YAAY,EACpB,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,OAAO,GACf,aAAa,GAAG,IAAI,CAkVtB"}