@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/README.md +57 -107
- package/dist/cbor.d.ts +87 -0
- package/dist/cbor.d.ts.map +1 -0
- package/dist/cbor.js +326 -0
- package/dist/cbor.js.map +1 -0
- package/dist/clauses.d.ts +70 -0
- package/dist/clauses.d.ts.map +1 -1
- package/dist/clauses.js +77 -0
- package/dist/clauses.js.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/quorum.d.ts +245 -0
- package/dist/quorum.d.ts.map +1 -0
- package/dist/quorum.js +566 -0
- package/dist/quorum.js.map +1 -0
- package/dist/sig.d.ts +57 -0
- package/dist/sig.d.ts.map +1 -0
- package/dist/sig.js +127 -0
- package/dist/sig.js.map +1 -0
- package/dist/testkeys.d.ts +33 -0
- package/dist/testkeys.d.ts.map +1 -1
- package/dist/testkeys.js +100 -0
- package/dist/testkeys.js.map +1 -1
- package/dist/verify.d.ts +44 -20
- package/dist/verify.d.ts.map +1 -1
- package/dist/verify.js +55 -146
- package/dist/verify.js.map +1 -1
- package/dist/webauthn.d.ts +148 -0
- package/dist/webauthn.d.ts.map +1 -0
- package/dist/webauthn.js +414 -0
- package/dist/webauthn.js.map +1 -0
- package/dist/wire.d.ts +44 -0
- package/dist/wire.d.ts.map +1 -0
- package/dist/wire.js +90 -0
- package/dist/wire.js.map +1 -0
- package/package.json +12 -9
package/README.md
CHANGED
|
@@ -1,121 +1,71 @@
|
|
|
1
1
|
# @ziffer-io/verify
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
(`crates/acp-decision`, the production decision path). This package lives in ziffer
|
|
7
|
-
**only because the engine repository is publicly frozen and ziffer CI cannot reach new
|
|
8
|
-
engine commits**; the mirrored corpus in `fixtures/` plus `tools/check-verify-mirror.py`
|
|
9
|
-
is what keeps three copies of one rule honest. Engine-home for this package is revisited
|
|
10
|
-
if the freeze lifts.
|
|
3
|
+
Verify a ZIFFER decision receipt in your own process, against a key you configured yourself.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
11
6
|
|
|
12
7
|
```bash
|
|
13
8
|
npm install @ziffer-io/verify
|
|
14
9
|
```
|
|
15
10
|
|
|
16
|
-
|
|
17
|
-
`verifyReceipt`, so
|
|
18
|
-
disagree. Install it on its own when you verify receipts and never call the API.
|
|
11
|
+
Node 22 or later. If you also call the ZIFFER API, install `@ziffer-io/client` instead. It
|
|
12
|
+
depends on this package and re-exports `verifyReceipt`, so one verifier is in your tree.
|
|
19
13
|
|
|
20
|
-
##
|
|
14
|
+
## Quickstart
|
|
21
15
|
|
|
22
16
|
```ts
|
|
23
|
-
import {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
17
|
+
import { readFileSync } from 'node:fs';
|
|
18
|
+
import { verifyReceipt, type TrustAnchor } from '@ziffer-io/verify';
|
|
19
|
+
|
|
20
|
+
const keys = JSON.parse(readFileSync(process.env.ZIFFER_TRUST_ANCHOR, 'utf8'));
|
|
21
|
+
const anchor: TrustAnchor = {
|
|
22
|
+
classical: Buffer.from(keys.ed25519_pk_hex, 'hex'),
|
|
23
|
+
pq: Buffer.from(keys.mldsa65_pk_hex, 'hex'),
|
|
24
|
+
minSuite: process.env.ZIFFER_SUITE_FLOOR,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const proposalBytes = new TextEncoder().encode(JSON.stringify(proposal));
|
|
28
|
+
const verified = verifyReceipt(receipt, proposalBytes, anchor);
|
|
29
|
+
// It returned, so the receipt holds. verified.proposalHash is this verifier's own hash.
|
|
30
|
+
await bank.transfer(amount, toAccount); // your line, unchanged
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
`
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
## Strict Ed25519, written out
|
|
67
|
-
|
|
68
|
-
`@noble/curves`' `verify` with `{ zip215: false }` enforces canonical encodings but —
|
|
69
|
-
like OpenSSL — does **not** refuse small-order points. The ACP-106 rule (a small-order
|
|
70
|
-
public key or a small-order `R` makes the verification equation stop mentioning the
|
|
71
|
-
message) is therefore written out in `src/ed25519.ts`, exactly as the Python reference
|
|
72
|
-
writes it in `verify_prim` and Rust gets from `verify_strict`. The mirrored
|
|
73
|
-
`fixtures/refused_ed25519.json` is the executable statement: every vector is accepted by
|
|
74
|
-
RFC 8032 as OpenSSL implements it and refused by all three implementations. Deleting the
|
|
75
|
-
guard here was observed to accept the corpus's `r_is_the_identity_point` vector.
|
|
76
|
-
|
|
77
|
-
## Canonicalization, proven not transcribed
|
|
78
|
-
|
|
79
|
-
`src/canon.ts` reproduces the engine canon (sorted keys at every depth by **code
|
|
80
|
-
point** — not JS's UTF-16 unit order — no whitespace, raw UTF-8). The proof is a
|
|
81
|
-
triangle: `fixtures/canon_vectors.json` was generated by importing and executing the
|
|
82
|
-
engine's own `acp_executor.canon` (`fixtures/gen_canon_vectors.py`), the TS tests assert
|
|
83
|
-
byte-identity with the fixture on every case, and `tools/check-verify-mirror.py`
|
|
84
|
-
re-derives every case against the engine at the pin.
|
|
85
|
-
|
|
86
|
-
**Disclosed divergence (fail-closed):** the engine accepts a float *nested* in a signed
|
|
87
|
-
structure (the ACP-75 bug-for-bug agreement between Python and Rust). This
|
|
88
|
-
implementation refuses any non-integer number at any depth under `AT-8a`, because
|
|
89
|
-
`JSON.parse` collapses `1000.0` and `1000` into one value and reproducing the engine's
|
|
90
|
-
bytes would be a guess about bytes it never saw. Integers beyond `2^53−1` are refused
|
|
91
|
-
for the same reason (the ACP-54 integer-domain family reached from the JS side). No
|
|
92
|
-
conforming wire receipt carries either — every temporal field is an RFC 3339 string
|
|
93
|
-
since v1.3.28 (ACP-167). Both refusals are pinned by tests so the divergence cannot
|
|
94
|
-
vanish silently.
|
|
95
|
-
|
|
96
|
-
## Fixtures
|
|
97
|
-
|
|
98
|
-
Byte-identical mirrors of engine files, each with a `.provenance.json` sidecar (source
|
|
99
|
-
path, rev, sha256 — a header *inside* the JSON would change the bytes the identity claim
|
|
100
|
-
is about): `refused_ed25519.json`, `python_signatures.json` (the reference's signatures,
|
|
101
|
-
which this side must accept — the TS leg of `tests/python_interop.rs`' claim; its seeds
|
|
102
|
-
also pin the test-key derivation mirror in `src/testkeys.ts`), and
|
|
103
|
-
`instant-type-vectors.json` (this package is the shared instant corpus's fourth
|
|
104
|
-
consumer). Plus the derived `canon_vectors.json` above. Re-mirror at a pin bump;
|
|
105
|
-
`tools/check-verify-mirror.py` refuses a mirror whose provenance rev is not the
|
|
106
|
-
workspace pin.
|
|
107
|
-
|
|
108
|
-
## Running
|
|
109
|
-
|
|
110
|
-
```sh
|
|
111
|
-
pnpm --filter @ziffer-io/verify test # tsc -b && node --test (27 tests)
|
|
112
|
-
python3 tools/check-verify-mirror.py # from the repo root; needs ACP_REPO_PATH at the pin
|
|
113
|
-
```
|
|
33
|
+
It reaches no network and trusts nothing it was not handed. The keys and the suite floor are
|
|
34
|
+
arguments you pass in. The proposal hash is recomputed from your bytes, never read from the
|
|
35
|
+
receipt.
|
|
36
|
+
Key order and spacing do not matter, because the verifier canonicalises your bytes itself.
|
|
37
|
+
|
|
38
|
+
`verifyReceipt` checks the answer. Your own `if` is what stops the action.
|
|
39
|
+
|
|
40
|
+
## Configuration
|
|
41
|
+
|
|
42
|
+
| Variable | What it is | Where the value comes from |
|
|
43
|
+
| --- | --- | --- |
|
|
44
|
+
| `ZIFFER_TRUST_ANCHOR` | Path to the public key file your receipts are signed under. | We give you the file. Take it from us, never from the API you are checking. |
|
|
45
|
+
| `ZIFFER_SUITE_FLOOR` | The weakest signature suite you will accept. | You choose it. There is no default. |
|
|
46
|
+
|
|
47
|
+
## When a request is refused
|
|
48
|
+
|
|
49
|
+
Every refusal is a thrown `Refusal` whose `clause` names the rule that fired; the table of every
|
|
50
|
+
clause, what it means and what to do is at https://ziffer.io/docs/refusals. Narrow with
|
|
51
|
+
`instanceof Refusal`, record the clause, and do not retry it.
|
|
52
|
+
|
|
53
|
+
## Documentation
|
|
54
|
+
|
|
55
|
+
- Quickstart: https://ziffer.io/docs/quickstart
|
|
56
|
+
- Integrating the SDK: https://ziffer.io/docs/developers/sdk
|
|
57
|
+
- Every refusal: https://ziffer.io/docs/refusals
|
|
58
|
+
- The specification: https://ziffer.io/docs/specification
|
|
59
|
+
- Glossary: https://ziffer.io/docs/glossary
|
|
60
|
+
|
|
61
|
+
## Support
|
|
62
|
+
|
|
63
|
+
Write to hello@ziffer.io. Your trust anchor file and your suite floor come from us. So does an
|
|
64
|
+
answer about a refusal you cannot explain.
|
|
114
65
|
|
|
115
|
-
##
|
|
66
|
+
## License
|
|
116
67
|
|
|
117
|
-
Proprietary. Copyright (c) 2026 code75 SASU, Paris, France. ZIFFER is a registered trademark of
|
|
118
|
-
SASU. This package is
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
their own licences.
|
|
68
|
+
Proprietary. Copyright (c) 2026 code75 SASU, Paris, France. ZIFFER is a registered trademark of
|
|
69
|
+
code75 SASU. This package is not open source. Its use is governed by your agreement with code75
|
|
70
|
+
and by `LICENSE` beside this file. The open-source components it redistributes are listed in
|
|
71
|
+
`THIRD-PARTY-NOTICES`, under their own licences.
|
package/dist/cbor.d.ts
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AT-8a canonical CBOR (RFC 8949 §4.2) -- the ONE primitive this package did
|
|
3
|
+
* not already have, added for §8.6c and for nothing else.
|
|
4
|
+
*
|
|
5
|
+
* # Why a new module rather than a reused one
|
|
6
|
+
*
|
|
7
|
+
* `canon.ts` is the canonical JSON encoding, and it is the right preimage for
|
|
8
|
+
* every hash this verifier takes: the engine's `attestation_id` and AB-1 entry
|
|
9
|
+
* digest are `sha256:` over `acp_executor.canon` / `receipt.rs::canon`, both
|
|
10
|
+
* JSON, and this package reproduces those bytes. What CBOR is needed for is
|
|
11
|
+
* narrower and unavoidable: HM-3 says a human attester's assertion is canonical
|
|
12
|
+
* CBOR of `{authenticator_data, client_data_json, signature}`, and HM-1 says the
|
|
13
|
+
* credential's `public_key` is a COSE_Key, which is CBOR by RFC 9052. Those two
|
|
14
|
+
* byte strings arrive from the wire and must be DECODED; no JSON encoder can
|
|
15
|
+
* read them. So this is a decoder for two fixed shapes, not a general codec.
|
|
16
|
+
*
|
|
17
|
+
* The engine's twins are `crates/acp-crypto/src/cbor.rs` and
|
|
18
|
+
* `reference/src/acp_crypto.py`'s `_enc` / `_dec` / `decode_canonical`, and the
|
|
19
|
+
* rule this file takes from them verbatim is the last one:
|
|
20
|
+
*
|
|
21
|
+
* # Canonicity is proved by RE-ENCODING, not by a list of sub-rules
|
|
22
|
+
*
|
|
23
|
+
* {@link decodeCanonical} parses, re-encodes what it parsed, and refuses the
|
|
24
|
+
* input unless the two byte strings are identical. That single comparison
|
|
25
|
+
* carries every §4.2 requirement at once -- shortest-form arguments, definite
|
|
26
|
+
* lengths, map keys sorted by their ENCODED bytes, no duplicate keys -- and it
|
|
27
|
+
* cannot drift from the encoder the way a hand-written checklist of those rules
|
|
28
|
+
* can. The decoder still refuses the coarse violations itself (indefinite
|
|
29
|
+
* lengths, non-shortest arguments, reserved additional information) because a
|
|
30
|
+
* decoder that accepted them would have to invent a canonical form to compare
|
|
31
|
+
* against, and inventing one is normalising.
|
|
32
|
+
*
|
|
33
|
+
* Refused, never normalised (AT-8a): the AB-1 entry digest is taken over the
|
|
34
|
+
* bytes that arrived, so a second encoding of one assertion is a second digest
|
|
35
|
+
* for one human decision, and accepting both would put two receipt identities
|
|
36
|
+
* behind one approval -- the Z4 encoding split, reached through the assertion.
|
|
37
|
+
*
|
|
38
|
+
* # Floats and tags are absent on purpose
|
|
39
|
+
*
|
|
40
|
+
* Neither is encodable, so neither is decodable: a float has several
|
|
41
|
+
* representations of one value and no deterministic ordering story (WE-1), and
|
|
42
|
+
* a tag is a type this verifier has no shape for. They refuse as
|
|
43
|
+
* {@link CborError} rather than being skipped, because a decoder that silently
|
|
44
|
+
* ignores what it does not understand is a parser an attacker can steer.
|
|
45
|
+
*/
|
|
46
|
+
/** The input is not canonical CBOR, or is not CBOR at all. */
|
|
47
|
+
export declare class CborError extends Error {
|
|
48
|
+
constructor(message: string);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* What this decoder can produce. Deliberately NOT a general CBOR value type:
|
|
52
|
+
* a map key is an integer (COSE labels, RFC 9052 §7) or text (HM-3's three
|
|
53
|
+
* fields), and nothing here needs more.
|
|
54
|
+
*/
|
|
55
|
+
export type Cbor = boolean | null | bigint | Uint8Array | string | Cbor[] | CborMap;
|
|
56
|
+
/**
|
|
57
|
+
* A CBOR map, kept as ordered entries rather than a JS object.
|
|
58
|
+
*
|
|
59
|
+
* An object would key everything by string and collapse the integer label `1`
|
|
60
|
+
* and the text key `"1"` into one entry -- two distinct CBOR values, and in
|
|
61
|
+
* COSE_Key the integer form is the only legal one. The order is the order the
|
|
62
|
+
* bytes carried, which the re-encode check has already proved canonical.
|
|
63
|
+
*/
|
|
64
|
+
export interface CborMap {
|
|
65
|
+
readonly entries: readonly (readonly [Cbor, Cbor])[];
|
|
66
|
+
}
|
|
67
|
+
/** Whether a decoded value is a map -- the narrowing the callers need. */
|
|
68
|
+
export declare function cborIsMap(v: Cbor): v is CborMap;
|
|
69
|
+
/** A map's keys, in the (canonical) order the bytes carried. */
|
|
70
|
+
export declare function cborKeys(m: CborMap): Cbor[];
|
|
71
|
+
/** The value at an integer label, or undefined. COSE_Key's accessor. */
|
|
72
|
+
export declare function cborGetInt(m: CborMap, label: bigint): Cbor | undefined;
|
|
73
|
+
/** The value at a text key, or undefined. The assertion map's accessor. */
|
|
74
|
+
export declare function cborGetText(m: CborMap, key: string): Cbor | undefined;
|
|
75
|
+
/** A decoded value as bytes, or null if it is not a byte string. */
|
|
76
|
+
export declare function cborAsBytes(v: Cbor | undefined): Uint8Array | null;
|
|
77
|
+
/** The canonical CBOR bytes of a value. Used by {@link decodeCanonical}'s proof. */
|
|
78
|
+
export declare function cborEncode(value: Cbor): Uint8Array;
|
|
79
|
+
/**
|
|
80
|
+
* AT-8a: parse AND prove canonicity. Any input that is not byte-identical to
|
|
81
|
+
* the canonical encoding of what it decodes to is REFUSED, never normalised.
|
|
82
|
+
*
|
|
83
|
+
* The engine's `decode_canonical` in one sentence, and the same sentence is the
|
|
84
|
+
* whole specification of this function.
|
|
85
|
+
*/
|
|
86
|
+
export declare function decodeCanonical(buf: Uint8Array): Cbor;
|
|
87
|
+
//# sourceMappingURL=cbor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cbor.d.ts","sourceRoot":"","sources":["../src/cbor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAEH,8DAA8D;AAC9D,qBAAa,SAAU,SAAQ,KAAK;gBACtB,OAAO,EAAE,MAAM;CAI5B;AAED;;;;GAIG;AACH,MAAM,MAAM,IAAI,GAAG,OAAO,GAAG,IAAI,GAAG,MAAM,GAAG,UAAU,GAAG,MAAM,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;AAEpF;;;;;;;GAOG;AACH,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC;CACtD;AAMD,0EAA0E;AAC1E,wBAAgB,SAAS,CAAC,CAAC,EAAE,IAAI,GAAG,CAAC,IAAI,OAAO,CAE/C;AAED,gEAAgE;AAChE,wBAAgB,QAAQ,CAAC,CAAC,EAAE,OAAO,GAAG,IAAI,EAAE,CAE3C;AAED,wEAAwE;AACxE,wBAAgB,UAAU,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAGtE;AAED,2EAA2E;AAC3E,wBAAgB,WAAW,CAAC,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAGrE;AAED,oEAAoE;AACpE,wBAAgB,WAAW,CAAC,CAAC,EAAE,IAAI,GAAG,SAAS,GAAG,UAAU,GAAG,IAAI,CAElE;AAsHD,oFAAoF;AACpF,wBAAgB,UAAU,CAAC,KAAK,EAAE,IAAI,GAAG,UAAU,CAIlD;AA0FD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,UAAU,GAAG,IAAI,CAQrD"}
|
package/dist/cbor.js
ADDED
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AT-8a canonical CBOR (RFC 8949 §4.2) -- the ONE primitive this package did
|
|
3
|
+
* not already have, added for §8.6c and for nothing else.
|
|
4
|
+
*
|
|
5
|
+
* # Why a new module rather than a reused one
|
|
6
|
+
*
|
|
7
|
+
* `canon.ts` is the canonical JSON encoding, and it is the right preimage for
|
|
8
|
+
* every hash this verifier takes: the engine's `attestation_id` and AB-1 entry
|
|
9
|
+
* digest are `sha256:` over `acp_executor.canon` / `receipt.rs::canon`, both
|
|
10
|
+
* JSON, and this package reproduces those bytes. What CBOR is needed for is
|
|
11
|
+
* narrower and unavoidable: HM-3 says a human attester's assertion is canonical
|
|
12
|
+
* CBOR of `{authenticator_data, client_data_json, signature}`, and HM-1 says the
|
|
13
|
+
* credential's `public_key` is a COSE_Key, which is CBOR by RFC 9052. Those two
|
|
14
|
+
* byte strings arrive from the wire and must be DECODED; no JSON encoder can
|
|
15
|
+
* read them. So this is a decoder for two fixed shapes, not a general codec.
|
|
16
|
+
*
|
|
17
|
+
* The engine's twins are `crates/acp-crypto/src/cbor.rs` and
|
|
18
|
+
* `reference/src/acp_crypto.py`'s `_enc` / `_dec` / `decode_canonical`, and the
|
|
19
|
+
* rule this file takes from them verbatim is the last one:
|
|
20
|
+
*
|
|
21
|
+
* # Canonicity is proved by RE-ENCODING, not by a list of sub-rules
|
|
22
|
+
*
|
|
23
|
+
* {@link decodeCanonical} parses, re-encodes what it parsed, and refuses the
|
|
24
|
+
* input unless the two byte strings are identical. That single comparison
|
|
25
|
+
* carries every §4.2 requirement at once -- shortest-form arguments, definite
|
|
26
|
+
* lengths, map keys sorted by their ENCODED bytes, no duplicate keys -- and it
|
|
27
|
+
* cannot drift from the encoder the way a hand-written checklist of those rules
|
|
28
|
+
* can. The decoder still refuses the coarse violations itself (indefinite
|
|
29
|
+
* lengths, non-shortest arguments, reserved additional information) because a
|
|
30
|
+
* decoder that accepted them would have to invent a canonical form to compare
|
|
31
|
+
* against, and inventing one is normalising.
|
|
32
|
+
*
|
|
33
|
+
* Refused, never normalised (AT-8a): the AB-1 entry digest is taken over the
|
|
34
|
+
* bytes that arrived, so a second encoding of one assertion is a second digest
|
|
35
|
+
* for one human decision, and accepting both would put two receipt identities
|
|
36
|
+
* behind one approval -- the Z4 encoding split, reached through the assertion.
|
|
37
|
+
*
|
|
38
|
+
* # Floats and tags are absent on purpose
|
|
39
|
+
*
|
|
40
|
+
* Neither is encodable, so neither is decodable: a float has several
|
|
41
|
+
* representations of one value and no deterministic ordering story (WE-1), and
|
|
42
|
+
* a tag is a type this verifier has no shape for. They refuse as
|
|
43
|
+
* {@link CborError} rather than being skipped, because a decoder that silently
|
|
44
|
+
* ignores what it does not understand is a parser an attacker can steer.
|
|
45
|
+
*/
|
|
46
|
+
/** The input is not canonical CBOR, or is not CBOR at all. */
|
|
47
|
+
export class CborError extends Error {
|
|
48
|
+
constructor(message) {
|
|
49
|
+
super(message);
|
|
50
|
+
this.name = 'CborError';
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function isCborMap(v) {
|
|
54
|
+
return typeof v === 'object' && v !== null && !Array.isArray(v) && !(v instanceof Uint8Array);
|
|
55
|
+
}
|
|
56
|
+
/** Whether a decoded value is a map -- the narrowing the callers need. */
|
|
57
|
+
export function cborIsMap(v) {
|
|
58
|
+
return isCborMap(v);
|
|
59
|
+
}
|
|
60
|
+
/** A map's keys, in the (canonical) order the bytes carried. */
|
|
61
|
+
export function cborKeys(m) {
|
|
62
|
+
return m.entries.map(([k]) => k);
|
|
63
|
+
}
|
|
64
|
+
/** The value at an integer label, or undefined. COSE_Key's accessor. */
|
|
65
|
+
export function cborGetInt(m, label) {
|
|
66
|
+
for (const [k, v] of m.entries)
|
|
67
|
+
if (typeof k === 'bigint' && k === label)
|
|
68
|
+
return v;
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
/** The value at a text key, or undefined. The assertion map's accessor. */
|
|
72
|
+
export function cborGetText(m, key) {
|
|
73
|
+
for (const [k, v] of m.entries)
|
|
74
|
+
if (typeof k === 'string' && k === key)
|
|
75
|
+
return v;
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
/** A decoded value as bytes, or null if it is not a byte string. */
|
|
79
|
+
export function cborAsBytes(v) {
|
|
80
|
+
return v instanceof Uint8Array ? v : null;
|
|
81
|
+
}
|
|
82
|
+
const MAJOR_UINT = 0;
|
|
83
|
+
const MAJOR_NINT = 1;
|
|
84
|
+
const MAJOR_BYTES = 2;
|
|
85
|
+
const MAJOR_TEXT = 3;
|
|
86
|
+
const MAJOR_ARRAY = 4;
|
|
87
|
+
const MAJOR_MAP = 5;
|
|
88
|
+
const MAJOR_SIMPLE = 7;
|
|
89
|
+
/**
|
|
90
|
+
* RFC 8949 §4.2.1: the argument MUST use the shortest form that holds it.
|
|
91
|
+
*
|
|
92
|
+
* `bigint` throughout rather than `number`, because a CBOR argument is a full
|
|
93
|
+
* 64-bit unsigned integer and `number` loses digits past 2^53-1 -- the same
|
|
94
|
+
* defect `canon.ts` refuses on the JSON side, and here it would mean re-encoding
|
|
95
|
+
* a length to different bytes than arrived and calling the input non-canonical
|
|
96
|
+
* for the decoder's own reason.
|
|
97
|
+
*/
|
|
98
|
+
function encodeHead(major, value, out) {
|
|
99
|
+
const head = major << 5;
|
|
100
|
+
if (value < 24n) {
|
|
101
|
+
out.push(head | Number(value));
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
let width;
|
|
105
|
+
if (value < 0x100n) {
|
|
106
|
+
out.push(head | 24);
|
|
107
|
+
width = 1;
|
|
108
|
+
}
|
|
109
|
+
else if (value < 0x10000n) {
|
|
110
|
+
out.push(head | 25);
|
|
111
|
+
width = 2;
|
|
112
|
+
}
|
|
113
|
+
else if (value < 0x100000000n) {
|
|
114
|
+
out.push(head | 26);
|
|
115
|
+
width = 4;
|
|
116
|
+
}
|
|
117
|
+
else if (value < 0x10000000000000000n) {
|
|
118
|
+
out.push(head | 27);
|
|
119
|
+
width = 8;
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
throw new CborError('integer exceeds the 64-bit CBOR argument');
|
|
123
|
+
}
|
|
124
|
+
for (let i = width - 1; i >= 0; i -= 1) {
|
|
125
|
+
out.push(Number((value >> BigInt(i * 8)) & 0xffn));
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
function encodeInto(value, out) {
|
|
129
|
+
if (value === true) {
|
|
130
|
+
out.push(0xf5);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
if (value === false) {
|
|
134
|
+
out.push(0xf4);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if (value === null) {
|
|
138
|
+
out.push(0xf6);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
if (typeof value === 'bigint') {
|
|
142
|
+
if (value >= 0n)
|
|
143
|
+
encodeHead(MAJOR_UINT, value, out);
|
|
144
|
+
else
|
|
145
|
+
encodeHead(MAJOR_NINT, -value - 1n, out);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
if (value instanceof Uint8Array) {
|
|
149
|
+
encodeHead(MAJOR_BYTES, BigInt(value.length), out);
|
|
150
|
+
for (const b of value)
|
|
151
|
+
out.push(b);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
if (typeof value === 'string') {
|
|
155
|
+
const bytes = new TextEncoder().encode(value);
|
|
156
|
+
encodeHead(MAJOR_TEXT, BigInt(bytes.length), out);
|
|
157
|
+
for (const b of bytes)
|
|
158
|
+
out.push(b);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
if (Array.isArray(value)) {
|
|
162
|
+
encodeHead(MAJOR_ARRAY, BigInt(value.length), out);
|
|
163
|
+
for (const item of value)
|
|
164
|
+
encodeInto(item, out);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
if (isCborMap(value)) {
|
|
168
|
+
// §4.2.1: keys sorted by their ENCODED bytes, bytewise lexicographic.
|
|
169
|
+
// Sorting by the decoded value would put the integer label -2 and the text
|
|
170
|
+
// key "x" in an order that depends on the comparison chosen rather than on
|
|
171
|
+
// the bytes, and the encoded order is the one the rule names.
|
|
172
|
+
const keyed = value.entries.map(([k, v]) => {
|
|
173
|
+
const kb = [];
|
|
174
|
+
encodeInto(k, kb);
|
|
175
|
+
return { kb, v };
|
|
176
|
+
});
|
|
177
|
+
keyed.sort((a, b) => compareBytes(a.kb, b.kb));
|
|
178
|
+
for (let i = 1; i < keyed.length; i += 1) {
|
|
179
|
+
const prev = keyed[i - 1];
|
|
180
|
+
const cur = keyed[i];
|
|
181
|
+
if (prev === undefined || cur === undefined)
|
|
182
|
+
continue; // unreachable; index in range
|
|
183
|
+
if (compareBytes(prev.kb, cur.kb) === 0)
|
|
184
|
+
throw new CborError('duplicate map key');
|
|
185
|
+
}
|
|
186
|
+
encodeHead(MAJOR_MAP, BigInt(keyed.length), out);
|
|
187
|
+
for (const { kb, v } of keyed) {
|
|
188
|
+
for (const b of kb)
|
|
189
|
+
out.push(b);
|
|
190
|
+
encodeInto(v, out);
|
|
191
|
+
}
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
throw new CborError('value is not canonically encodable');
|
|
195
|
+
}
|
|
196
|
+
function compareBytes(a, b) {
|
|
197
|
+
const n = Math.min(a.length, b.length);
|
|
198
|
+
for (let i = 0; i < n; i += 1) {
|
|
199
|
+
const x = a[i];
|
|
200
|
+
const y = b[i];
|
|
201
|
+
if (x === undefined || y === undefined)
|
|
202
|
+
continue; // unreachable; index in range
|
|
203
|
+
if (x !== y)
|
|
204
|
+
return x - y;
|
|
205
|
+
}
|
|
206
|
+
return a.length - b.length;
|
|
207
|
+
}
|
|
208
|
+
/** The canonical CBOR bytes of a value. Used by {@link decodeCanonical}'s proof. */
|
|
209
|
+
export function cborEncode(value) {
|
|
210
|
+
const out = [];
|
|
211
|
+
encodeInto(value, out);
|
|
212
|
+
return Uint8Array.from(out);
|
|
213
|
+
}
|
|
214
|
+
function decodeAt(buf, start) {
|
|
215
|
+
if (start >= buf.length)
|
|
216
|
+
throw new CborError('truncated');
|
|
217
|
+
const ib = buf[start];
|
|
218
|
+
if (ib === undefined)
|
|
219
|
+
throw new CborError('truncated'); // unreachable; bound checked
|
|
220
|
+
const major = ib >> 5;
|
|
221
|
+
const ai = ib & 0x1f;
|
|
222
|
+
let i = start + 1;
|
|
223
|
+
let value;
|
|
224
|
+
if (ai < 24) {
|
|
225
|
+
value = BigInt(ai);
|
|
226
|
+
}
|
|
227
|
+
else if (ai <= 27) {
|
|
228
|
+
const width = 1 << (ai - 24);
|
|
229
|
+
if (i + width > buf.length)
|
|
230
|
+
throw new CborError('truncated argument');
|
|
231
|
+
value = 0n;
|
|
232
|
+
for (let k = 0; k < width; k += 1) {
|
|
233
|
+
const b = buf[i + k];
|
|
234
|
+
if (b === undefined)
|
|
235
|
+
throw new CborError('truncated argument'); // unreachable
|
|
236
|
+
value = (value << 8n) | BigInt(b);
|
|
237
|
+
}
|
|
238
|
+
i += width;
|
|
239
|
+
// Shortest form (§4.2.1). Refused here as well as by the re-encode proof,
|
|
240
|
+
// because the value that re-encodes shorter would otherwise be decoded
|
|
241
|
+
// first and any shape check above would run on attacker-chosen bytes.
|
|
242
|
+
const floor = ai === 24 ? 24n : 1n << BigInt((width / 2) * 8);
|
|
243
|
+
if (value < floor)
|
|
244
|
+
throw new CborError('non-shortest argument');
|
|
245
|
+
}
|
|
246
|
+
else if (ai === 31) {
|
|
247
|
+
throw new CborError('indefinite length forbidden in canonical CBOR');
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
throw new CborError(`reserved additional information ${ai}`);
|
|
251
|
+
}
|
|
252
|
+
switch (major) {
|
|
253
|
+
case MAJOR_UINT:
|
|
254
|
+
return { value, next: i };
|
|
255
|
+
case MAJOR_NINT:
|
|
256
|
+
return { value: -value - 1n, next: i };
|
|
257
|
+
case MAJOR_BYTES:
|
|
258
|
+
case MAJOR_TEXT: {
|
|
259
|
+
const len = Number(value);
|
|
260
|
+
if (!Number.isSafeInteger(len) || i + len > buf.length) {
|
|
261
|
+
throw new CborError('truncated string');
|
|
262
|
+
}
|
|
263
|
+
const slice = buf.subarray(i, i + len);
|
|
264
|
+
if (major === MAJOR_BYTES)
|
|
265
|
+
return { value: Uint8Array.from(slice), next: i + len };
|
|
266
|
+
// fatal: true -- invalid UTF-8 is a refusal, not a run of U+FFFD. A
|
|
267
|
+
// replacement character would make two distinct byte strings decode to
|
|
268
|
+
// one text value, which the re-encode proof would then report as
|
|
269
|
+
// non-canonical for the wrong reason.
|
|
270
|
+
return { value: new TextDecoder('utf-8', { fatal: true }).decode(slice), next: i + len };
|
|
271
|
+
}
|
|
272
|
+
case MAJOR_ARRAY: {
|
|
273
|
+
const n = Number(value);
|
|
274
|
+
if (!Number.isSafeInteger(n) || n > buf.length - i)
|
|
275
|
+
throw new CborError('truncated array');
|
|
276
|
+
const items = [];
|
|
277
|
+
for (let k = 0; k < n; k += 1) {
|
|
278
|
+
const d = decodeAt(buf, i);
|
|
279
|
+
items.push(d.value);
|
|
280
|
+
i = d.next;
|
|
281
|
+
}
|
|
282
|
+
return { value: items, next: i };
|
|
283
|
+
}
|
|
284
|
+
case MAJOR_MAP: {
|
|
285
|
+
const n = Number(value);
|
|
286
|
+
if (!Number.isSafeInteger(n) || n > buf.length - i)
|
|
287
|
+
throw new CborError('truncated map');
|
|
288
|
+
const entries = [];
|
|
289
|
+
for (let k = 0; k < n; k += 1) {
|
|
290
|
+
const key = decodeAt(buf, i);
|
|
291
|
+
const val = decodeAt(buf, key.next);
|
|
292
|
+
entries.push([key.value, val.value]);
|
|
293
|
+
i = val.next;
|
|
294
|
+
}
|
|
295
|
+
return { value: { entries }, next: i };
|
|
296
|
+
}
|
|
297
|
+
case MAJOR_SIMPLE:
|
|
298
|
+
if (value === 20n)
|
|
299
|
+
return { value: false, next: i };
|
|
300
|
+
if (value === 21n)
|
|
301
|
+
return { value: true, next: i };
|
|
302
|
+
if (value === 22n)
|
|
303
|
+
return { value: null, next: i };
|
|
304
|
+
throw new CborError('float or unsupported simple value');
|
|
305
|
+
default:
|
|
306
|
+
throw new CborError(`unsupported major type ${major}`);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* AT-8a: parse AND prove canonicity. Any input that is not byte-identical to
|
|
311
|
+
* the canonical encoding of what it decodes to is REFUSED, never normalised.
|
|
312
|
+
*
|
|
313
|
+
* The engine's `decode_canonical` in one sentence, and the same sentence is the
|
|
314
|
+
* whole specification of this function.
|
|
315
|
+
*/
|
|
316
|
+
export function decodeCanonical(buf) {
|
|
317
|
+
const { value, next } = decodeAt(buf, 0);
|
|
318
|
+
if (next !== buf.length)
|
|
319
|
+
throw new CborError('trailing bytes');
|
|
320
|
+
const re = cborEncode(value);
|
|
321
|
+
if (re.length !== buf.length || !re.every((b, i) => b === buf[i])) {
|
|
322
|
+
throw new CborError('input is not the canonical encoding of its value');
|
|
323
|
+
}
|
|
324
|
+
return value;
|
|
325
|
+
}
|
|
326
|
+
//# sourceMappingURL=cbor.js.map
|
package/dist/cbor.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cbor.js","sourceRoot":"","sources":["../src/cbor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAEH,8DAA8D;AAC9D,MAAM,OAAO,SAAU,SAAQ,KAAK;IAClC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;IAC1B,CAAC;CACF;AAqBD,SAAS,SAAS,CAAC,CAAO;IACxB,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,UAAU,CAAC,CAAC;AAChG,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,SAAS,CAAC,CAAO;IAC/B,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC;AACtB,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,QAAQ,CAAC,CAAU;IACjC,OAAO,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;AACnC,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,UAAU,CAAC,CAAU,EAAE,KAAa;IAClD,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO;QAAE,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,KAAK;YAAE,OAAO,CAAC,CAAC;IACnF,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,WAAW,CAAC,CAAU,EAAE,GAAW;IACjD,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO;QAAE,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,GAAG;YAAE,OAAO,CAAC,CAAC;IACjF,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,WAAW,CAAC,CAAmB;IAC7C,OAAO,CAAC,YAAY,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,GAAG,CAAC,CAAC;AACrB,MAAM,UAAU,GAAG,CAAC,CAAC;AACrB,MAAM,WAAW,GAAG,CAAC,CAAC;AACtB,MAAM,UAAU,GAAG,CAAC,CAAC;AACrB,MAAM,WAAW,GAAG,CAAC,CAAC;AACtB,MAAM,SAAS,GAAG,CAAC,CAAC;AACpB,MAAM,YAAY,GAAG,CAAC,CAAC;AAEvB;;;;;;;;GAQG;AACH,SAAS,UAAU,CAAC,KAAa,EAAE,KAAa,EAAE,GAAa;IAC7D,MAAM,IAAI,GAAG,KAAK,IAAI,CAAC,CAAC;IACxB,IAAI,KAAK,GAAG,GAAG,EAAE,CAAC;QAChB,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAC/B,OAAO;IACT,CAAC;IACD,IAAI,KAAa,CAAC;IAClB,IAAI,KAAK,GAAG,MAAM,EAAE,CAAC;QACnB,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC;QACpB,KAAK,GAAG,CAAC,CAAC;IACZ,CAAC;SAAM,IAAI,KAAK,GAAG,QAAQ,EAAE,CAAC;QAC5B,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC;QACpB,KAAK,GAAG,CAAC,CAAC;IACZ,CAAC;SAAM,IAAI,KAAK,GAAG,YAAY,EAAE,CAAC;QAChC,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC;QACpB,KAAK,GAAG,CAAC,CAAC;IACZ,CAAC;SAAM,IAAI,KAAK,GAAG,oBAAoB,EAAE,CAAC;QACxC,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC;QACpB,KAAK,GAAG,CAAC,CAAC;IACZ,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,SAAS,CAAC,0CAA0C,CAAC,CAAC;IAClE,CAAC;IACD,KAAK,IAAI,CAAC,GAAG,KAAK,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACvC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,IAAI,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC;IACrD,CAAC;AACH,CAAC;AAED,SAAS,UAAU,CAAC,KAAW,EAAE,GAAa;IAC5C,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACnB,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACf,OAAO;IACT,CAAC;IACD,IAAI,KAAK,KAAK,KAAK,EAAE,CAAC;QACpB,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACf,OAAO;IACT,CAAC;IACD,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACnB,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACf,OAAO;IACT,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,IAAI,KAAK,IAAI,EAAE;YAAE,UAAU,CAAC,UAAU,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;;YAC/C,UAAU,CAAC,UAAU,EAAE,CAAC,KAAK,GAAG,EAAE,EAAE,GAAG,CAAC,CAAC;QAC9C,OAAO;IACT,CAAC;IACD,IAAI,KAAK,YAAY,UAAU,EAAE,CAAC;QAChC,UAAU,CAAC,WAAW,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,CAAC;QACnD,KAAK,MAAM,CAAC,IAAI,KAAK;YAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACnC,OAAO;IACT,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,KAAK,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC9C,UAAU,CAAC,UAAU,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,CAAC;QAClD,KAAK,MAAM,CAAC,IAAI,KAAK;YAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACnC,OAAO;IACT,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,UAAU,CAAC,WAAW,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,CAAC;QACnD,KAAK,MAAM,IAAI,IAAI,KAAK;YAAE,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAChD,OAAO;IACT,CAAC;IACD,IAAI,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;QACrB,sEAAsE;QACtE,2EAA2E;QAC3E,2EAA2E;QAC3E,8DAA8D;QAC9D,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE;YACzC,MAAM,EAAE,GAAa,EAAE,CAAC;YACxB,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAClB,OAAO,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC;QACnB,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC/C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YACzC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC1B,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YACrB,IAAI,IAAI,KAAK,SAAS,IAAI,GAAG,KAAK,SAAS;gBAAE,SAAS,CAAC,8BAA8B;YACrF,IAAI,YAAY,CAAC,IAAI,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC;gBAAE,MAAM,IAAI,SAAS,CAAC,mBAAmB,CAAC,CAAC;QACpF,CAAC;QACD,UAAU,CAAC,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,CAAC;QACjD,KAAK,MAAM,EAAE,EAAE,EAAE,CAAC,EAAE,IAAI,KAAK,EAAE,CAAC;YAC9B,KAAK,MAAM,CAAC,IAAI,EAAE;gBAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAChC,UAAU,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QACrB,CAAC;QACD,OAAO;IACT,CAAC;IACD,MAAM,IAAI,SAAS,CAAC,oCAAoC,CAAC,CAAC;AAC5D,CAAC;AAED,SAAS,YAAY,CAAC,CAAoB,EAAE,CAAoB;IAC9D,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;IACvC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9B,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACf,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACf,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,SAAS;YAAE,SAAS,CAAC,8BAA8B;QAChF,IAAI,CAAC,KAAK,CAAC;YAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IAC5B,CAAC;IACD,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;AAC7B,CAAC;AAED,oFAAoF;AACpF,MAAM,UAAU,UAAU,CAAC,KAAW;IACpC,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,UAAU,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACvB,OAAO,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC9B,CAAC;AAOD,SAAS,QAAQ,CAAC,GAAe,EAAE,KAAa;IAC9C,IAAI,KAAK,IAAI,GAAG,CAAC,MAAM;QAAE,MAAM,IAAI,SAAS,CAAC,WAAW,CAAC,CAAC;IAC1D,MAAM,EAAE,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC;IACtB,IAAI,EAAE,KAAK,SAAS;QAAE,MAAM,IAAI,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,6BAA6B;IACrF,MAAM,KAAK,GAAG,EAAE,IAAI,CAAC,CAAC;IACtB,MAAM,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IACrB,IAAI,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC;IAClB,IAAI,KAAa,CAAC;IAClB,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC;QACZ,KAAK,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC;IACrB,CAAC;SAAM,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC;QACpB,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QAC7B,IAAI,CAAC,GAAG,KAAK,GAAG,GAAG,CAAC,MAAM;YAAE,MAAM,IAAI,SAAS,CAAC,oBAAoB,CAAC,CAAC;QACtE,KAAK,GAAG,EAAE,CAAC;QACX,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YAClC,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACrB,IAAI,CAAC,KAAK,SAAS;gBAAE,MAAM,IAAI,SAAS,CAAC,oBAAoB,CAAC,CAAC,CAAC,cAAc;YAC9E,KAAK,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACpC,CAAC;QACD,CAAC,IAAI,KAAK,CAAC;QACX,0EAA0E;QAC1E,uEAAuE;QACvE,sEAAsE;QACtE,MAAM,KAAK,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,MAAM,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAC9D,IAAI,KAAK,GAAG,KAAK;YAAE,MAAM,IAAI,SAAS,CAAC,uBAAuB,CAAC,CAAC;IAClE,CAAC;SAAM,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QACrB,MAAM,IAAI,SAAS,CAAC,+CAA+C,CAAC,CAAC;IACvE,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,SAAS,CAAC,mCAAmC,EAAE,EAAE,CAAC,CAAC;IAC/D,CAAC;IAED,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,UAAU;YACb,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QAC5B,KAAK,UAAU;YACb,OAAO,EAAE,KAAK,EAAE,CAAC,KAAK,GAAG,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QACzC,KAAK,WAAW,CAAC;QACjB,KAAK,UAAU,CAAC,CAAC,CAAC;YAChB,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;YAC1B,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC;gBACvD,MAAM,IAAI,SAAS,CAAC,kBAAkB,CAAC,CAAC;YAC1C,CAAC;YACD,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC;YACvC,IAAI,KAAK,KAAK,WAAW;gBAAE,OAAO,EAAE,KAAK,EAAE,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC;YACnF,oEAAoE;YACpE,uEAAuE;YACvE,iEAAiE;YACjE,sCAAsC;YACtC,OAAO,EAAE,KAAK,EAAE,IAAI,WAAW,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC;QAC3F,CAAC;QACD,KAAK,WAAW,CAAC,CAAC,CAAC;YACjB,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;YACxB,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC;gBAAE,MAAM,IAAI,SAAS,CAAC,iBAAiB,CAAC,CAAC;YAC3F,MAAM,KAAK,GAAW,EAAE,CAAC;YACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC9B,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;gBAC3B,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;gBACpB,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YACb,CAAC;YACD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QACnC,CAAC;QACD,KAAK,SAAS,CAAC,CAAC,CAAC;YACf,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;YACxB,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC;gBAAE,MAAM,IAAI,SAAS,CAAC,eAAe,CAAC,CAAC;YACzF,MAAM,OAAO,GAA8B,EAAE,CAAC;YAC9C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC9B,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;gBAC7B,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;gBACpC,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;gBACrC,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC;YACf,CAAC;YACD,OAAO,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QACzC,CAAC;QACD,KAAK,YAAY;YACf,IAAI,KAAK,KAAK,GAAG;gBAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;YACpD,IAAI,KAAK,KAAK,GAAG;gBAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;YACnD,IAAI,KAAK,KAAK,GAAG;gBAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;YACnD,MAAM,IAAI,SAAS,CAAC,mCAAmC,CAAC,CAAC;QAC3D;YACE,MAAM,IAAI,SAAS,CAAC,0BAA0B,KAAK,EAAE,CAAC,CAAC;IAC3D,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,GAAe;IAC7C,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IACzC,IAAI,IAAI,KAAK,GAAG,CAAC,MAAM;QAAE,MAAM,IAAI,SAAS,CAAC,gBAAgB,CAAC,CAAC;IAC/D,MAAM,EAAE,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IAC7B,IAAI,EAAE,CAAC,MAAM,KAAK,GAAG,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAClE,MAAM,IAAI,SAAS,CAAC,kDAAkD,CAAC,CAAC;IAC1E,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|