@atlasauth/pca-abe 0.3.0 → 0.4.1
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 +19 -4
- package/dist/abe.d.ts +83 -42
- package/dist/abe.js +290 -117
- package/dist/abe.js.map +1 -1
- package/dist/aead.js +1 -1
- package/dist/aead.js.map +1 -1
- package/dist/attributes.d.ts +28 -7
- package/dist/attributes.js +48 -27
- package/dist/attributes.js.map +1 -1
- package/dist/bls.d.ts +35 -12
- package/dist/bls.js +81 -11
- package/dist/bls.js.map +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.js +6 -4
- package/dist/index.js.map +1 -1
- package/dist/pca.d.ts +3 -2
- package/dist/pca.js.map +1 -1
- package/dist/policy.d.ts +7 -0
- package/dist/policy.js +21 -4
- package/dist/policy.js.map +1 -1
- package/dist/sss.d.ts +6 -0
- package/dist/sss.js +33 -19
- package/dist/sss.js.map +1 -1
- package/dist/wire.d.ts +0 -2
- package/dist/wire.js +0 -10
- package/dist/wire.js.map +1 -1
- package/package.json +3 -2
- package/dist/ibe.d.ts +0 -24
- package/dist/ibe.js +0 -71
- package/dist/ibe.js.map +0 -1
package/dist/attributes.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { type Capability } from '@atlasauth/pca';
|
|
1
|
+
import { type Capability, type CapabilityChain } from '@atlasauth/pca';
|
|
2
2
|
/**
|
|
3
3
|
* Canonical attribute strings derived from a real PCA capability (see `@atlasauth/pca`'s `Capability`
|
|
4
4
|
* and the signed policy `Envelope`). An "attribute" is a lowercase `kind:value` token; a policy
|
|
5
|
-
* references attributes by exactly these tokens, and `keygenForCapability` issues one
|
|
6
|
-
* key per
|
|
5
|
+
* references attributes by exactly these tokens, and `keygenForCapability` issues one per-attribute
|
|
6
|
+
* decryption key (the collusion-resistant per-holder-randomised scheme in `index.ts`, not plain
|
|
7
|
+
* Boneh-Franklin IBE) per token the capability carries.
|
|
7
8
|
*
|
|
8
9
|
* Four kinds are derived, matching the capability's authority surface (verb / resource / scopes /
|
|
9
10
|
* holder):
|
|
@@ -13,18 +14,38 @@ import { type Capability } from '@atlasauth/pca';
|
|
|
13
14
|
* - `scope:<s>` every scope carried in a `{ type:'scope', value }` or
|
|
14
15
|
* `{ type:'scopes', values:[...] }` caveat.
|
|
15
16
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
17
|
+
* - `act:["<v>","<r>"]` a BOUND (verb, resource) pair, one per verb x resource of each predicate.
|
|
18
|
+
*
|
|
19
|
+
* With a single predicate the flat `verb:` / `resource:` tokens are exact and are also emitted. With
|
|
20
|
+
* two or more predicates only the pair tokens (plus holder/scope) are emitted, so the pairing cannot
|
|
21
|
+
* be recombined (RT-08, breaking). Predicate `where` conditions and non-predicate caveats are NOT
|
|
22
|
+
* reflected in any token: a policy that depends on them must also require a `scope:` or `holder:`.
|
|
23
|
+
*
|
|
24
|
+
* `scope:` tokens, and (R3-09) the envelope predicates behind `act:`/`verb:`/`resource:`, come ONLY from the ROOT capability (R2-07). Attenuation may append ANY caveat, so a
|
|
25
|
+
* delegated hop's own `scope` caveats are restrictions, never grants: reading them as positive attributes would let a
|
|
26
|
+
* delegatee append `scope:admin` and obtain a key for it. A delegated capability (one with a `parent`) therefore yields
|
|
27
|
+
* `scope:`/`act:`/`verb:`/`resource:` tokens only when the verified `chain` (root first, ending in that capability) is supplied, and then from
|
|
28
|
+
* `chain[0]` alone. Without a chain a delegated capability gets no `scope:` tokens; a supplied chain that fails
|
|
29
|
+
* verification yields NO attributes (fail closed).
|
|
19
30
|
*/
|
|
31
|
+
export interface CapabilityAttributeOpts {
|
|
32
|
+
/** The capability chain, root first, whose last element is the capability. Required for `scope:` tokens on a delegated hop. */
|
|
33
|
+
chain?: CapabilityChain;
|
|
34
|
+
/** The principal key the root must be issued by (recommended: pin it; defaults to the chain's own root issuer). */
|
|
35
|
+
principal?: string;
|
|
36
|
+
/** verifier-side PQ pins by Ed25519 identity (R3-01). A pure-PQ / hybrid ROOT is accepted only if the root issuer has a pin equal to its `pq_pk` (a signed binding from `pqPinFor`, or your own registry); without one it is refused. */
|
|
37
|
+
pqPins?: Readonly<Record<string, string>>;
|
|
38
|
+
}
|
|
20
39
|
export declare const Attr: {
|
|
21
40
|
readonly holder: (key: string) => string;
|
|
22
41
|
readonly verb: (v: string) => string;
|
|
23
42
|
readonly resource: (r: string) => string;
|
|
24
43
|
readonly scope: (s: string) => string;
|
|
44
|
+
/** A bound (verb, resource) pair: only a predicate that grants exactly this verb ON exactly this resource yields it. */
|
|
45
|
+
readonly act: (verb: string, resource: string) => string;
|
|
25
46
|
};
|
|
26
47
|
/**
|
|
27
48
|
* Derive the canonical attribute set a capability possesses. Deterministic and total (never throws): a
|
|
28
49
|
* capability with no signed envelope still yields its `holder:` attribute (plus any scope caveats).
|
|
29
50
|
*/
|
|
30
|
-
export declare function capabilityAttributes(cap: Capability): Set<string>;
|
|
51
|
+
export declare function capabilityAttributes(cap: Capability, opts?: CapabilityAttributeOpts): Set<string>;
|
package/dist/attributes.js
CHANGED
|
@@ -3,29 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.Attr = void 0;
|
|
4
4
|
exports.capabilityAttributes = capabilityAttributes;
|
|
5
5
|
const pca_1 = require("@atlasauth/pca");
|
|
6
|
-
/**
|
|
7
|
-
* Canonical attribute strings derived from a real PCA capability (see `@atlasauth/pca`'s `Capability`
|
|
8
|
-
* and the signed policy `Envelope`). An "attribute" is a lowercase `kind:value` token; a policy
|
|
9
|
-
* references attributes by exactly these tokens, and `keygenForCapability` issues one BF-IBE decryption
|
|
10
|
-
* key per token the capability carries.
|
|
11
|
-
*
|
|
12
|
-
* Four kinds are derived, matching the capability's authority surface (verb / resource / scopes /
|
|
13
|
-
* holder):
|
|
14
|
-
* - `holder:<b64u key>` the key the capability is bound to (`capability.holder`),
|
|
15
|
-
* - `verb:<v>` every literal verb named in the signed envelope's predicates,
|
|
16
|
-
* - `resource:<r>` every resource matcher named in those predicates,
|
|
17
|
-
* - `scope:<s>` every scope carried in a `{ type:'scope', value }` or
|
|
18
|
-
* `{ type:'scopes', values:[...] }` caveat.
|
|
19
|
-
*
|
|
20
|
-
* Because the envelope and caveats are SIGNED into the capability (and attenuation is append-only), the
|
|
21
|
-
* attribute set a capability yields cannot be widened by a holder — it is exactly what the principal
|
|
22
|
-
* authorised.
|
|
23
|
-
*/
|
|
24
6
|
exports.Attr = {
|
|
25
7
|
holder: (key) => `holder:${key}`,
|
|
26
8
|
verb: (v) => `verb:${v}`,
|
|
27
9
|
resource: (r) => `resource:${r}`,
|
|
28
10
|
scope: (s) => `scope:${s}`,
|
|
11
|
+
/** A bound (verb, resource) pair: only a predicate that grants exactly this verb ON exactly this resource yields it. */
|
|
12
|
+
act: (verb, resource) => `act:${JSON.stringify([verb, resource])}`,
|
|
29
13
|
};
|
|
30
14
|
function addVerb(out, verb) {
|
|
31
15
|
if (typeof verb === 'string')
|
|
@@ -35,6 +19,13 @@ function addVerb(out, verb) {
|
|
|
35
19
|
if (typeof v === 'string')
|
|
36
20
|
out.add(exports.Attr.verb(v));
|
|
37
21
|
}
|
|
22
|
+
function verbsOf(verb) {
|
|
23
|
+
if (typeof verb === 'string')
|
|
24
|
+
return [verb];
|
|
25
|
+
if (Array.isArray(verb))
|
|
26
|
+
return verb.filter((v) => typeof v === 'string');
|
|
27
|
+
return [];
|
|
28
|
+
}
|
|
38
29
|
function addScopes(out, caveats) {
|
|
39
30
|
for (const cv of caveats) {
|
|
40
31
|
if (cv.type === 'scope' && typeof cv.value === 'string')
|
|
@@ -50,21 +41,51 @@ function addScopes(out, caveats) {
|
|
|
50
41
|
* Derive the canonical attribute set a capability possesses. Deterministic and total (never throws): a
|
|
51
42
|
* capability with no signed envelope still yields its `holder:` attribute (plus any scope caveats).
|
|
52
43
|
*/
|
|
53
|
-
function capabilityAttributes(cap) {
|
|
44
|
+
function capabilityAttributes(cap, opts = {}) {
|
|
54
45
|
const out = new Set();
|
|
46
|
+
let scopeSource;
|
|
47
|
+
// R3-09: the envelope (act/verb/resource tokens) is read from the ROOT only, like scopes: a delegatee may append
|
|
48
|
+
// its own envelope caveat, which is a restriction, never a grant.
|
|
49
|
+
let envSource;
|
|
50
|
+
if (opts.chain !== undefined) {
|
|
51
|
+
const chain = opts.chain;
|
|
52
|
+
const root = chain[0];
|
|
53
|
+
if (!Array.isArray(chain) || chain.length === 0 || chain[chain.length - 1]?.id !== cap.id || root === undefined)
|
|
54
|
+
return out;
|
|
55
|
+
const v = (0, pca_1.verifyChain)(chain, opts.principal ?? root.issuer, { pqPins: opts.pqPins });
|
|
56
|
+
if (!v.ok)
|
|
57
|
+
return out;
|
|
58
|
+
scopeSource = root.caveats;
|
|
59
|
+
envSource = root;
|
|
60
|
+
}
|
|
61
|
+
else if (cap.parent === undefined) {
|
|
62
|
+
scopeSource = cap.caveats; // a root capability
|
|
63
|
+
envSource = cap;
|
|
64
|
+
}
|
|
55
65
|
if (typeof cap.holder === 'string' && cap.holder.length > 0)
|
|
56
66
|
out.add(exports.Attr.holder(cap.holder));
|
|
57
|
-
if (Array.isArray(
|
|
58
|
-
addScopes(out,
|
|
59
|
-
const env = (0, pca_1.readEnvelope)(
|
|
67
|
+
if (Array.isArray(scopeSource))
|
|
68
|
+
addScopes(out, scopeSource);
|
|
69
|
+
const env = envSource === undefined ? null : (0, pca_1.readEnvelope)(envSource);
|
|
60
70
|
if (env !== null && Array.isArray(env.predicates)) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
71
|
+
const preds = env.predicates.filter((p) => p !== null && typeof p === 'object');
|
|
72
|
+
// Paired tokens: one per (verb, resource) of each predicate. These are the ONLY tokens that
|
|
73
|
+
// carry authority when the envelope holds more than one predicate (RT-08).
|
|
74
|
+
for (const p of preds) {
|
|
75
|
+
const verbs = verbsOf(p.verb);
|
|
65
76
|
const r = p.resource;
|
|
66
77
|
if (typeof r === 'string')
|
|
67
|
-
|
|
78
|
+
for (const v of verbs)
|
|
79
|
+
out.add(exports.Attr.act(v, r));
|
|
80
|
+
}
|
|
81
|
+
// Flat verb:/resource: tokens are exact only for a single predicate (verbs x ONE resource), so
|
|
82
|
+
// they are emitted only then; with several predicates they would cross-pair (read of A + write
|
|
83
|
+
// of B would also open "read B").
|
|
84
|
+
if (preds.length === 1) {
|
|
85
|
+
const p = preds[0];
|
|
86
|
+
addVerb(out, p.verb);
|
|
87
|
+
if (typeof p.resource === 'string')
|
|
88
|
+
out.add(exports.Attr.resource(p.resource));
|
|
68
89
|
}
|
|
69
90
|
}
|
|
70
91
|
return out;
|
package/dist/attributes.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attributes.js","sourceRoot":"","sources":["../src/attributes.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"attributes.js","sourceRoot":"","sources":["../src/attributes.ts"],"names":[],"mappings":"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"}
|
package/dist/bls.d.ts
CHANGED
|
@@ -4,17 +4,20 @@ import { bls12_381 } from '@noble/curves/bls12-381';
|
|
|
4
4
|
* audited `bls12_381` implementation (G1/G2/GT, the ate pairing, RFC 9380 hash-to-curve); nothing here
|
|
5
5
|
* re-implements field or point arithmetic.
|
|
6
6
|
*
|
|
7
|
-
* Group placement (type-3 / asymmetric pairing `e: G1 x G2 -> GT`):
|
|
8
|
-
* - attribute
|
|
9
|
-
* -
|
|
10
|
-
* -
|
|
11
|
-
* -
|
|
7
|
+
* Group placement (type-3 / asymmetric pairing `e: G1 x G2 -> GT`), see `abe.ts` for the scheme:
|
|
8
|
+
* - the attribute hash `H(attr)` lives in G1 (hash-to-curve),
|
|
9
|
+
* - user-key components D, D_j live in G1 and D'_j in G2,
|
|
10
|
+
* - ciphertext components C_0 and C_x live in G2 and C'_x in G1,
|
|
11
|
+
* - the blinding value e(g1,g2)^alpha and every recovered quantity live in GT.
|
|
12
12
|
*/
|
|
13
13
|
/** Curve subgroup (scalar field) order r — a 255-bit prime, so every scalar fits in 32 bytes. */
|
|
14
14
|
export declare const R: bigint;
|
|
15
|
+
/** The fixed G1 generator the whole system is parameterised over. */
|
|
16
|
+
export declare const G1_BASE: import("@noble/curves/abstract/weierstrass").ProjPointType<bigint>;
|
|
15
17
|
/** The fixed G2 generator the whole system is parameterised over. */
|
|
16
18
|
export declare const G2_BASE: import("@noble/curves/abstract/weierstrass").ProjPointType<import("@noble/curves/abstract/tower").Fp2>;
|
|
17
19
|
export type G1Point = ReturnType<typeof bls12_381.G1.ProjectivePoint.fromAffine>;
|
|
20
|
+
export type GtElement = ReturnType<typeof bls12_381.pairing>;
|
|
18
21
|
export type G2Point = ReturnType<typeof bls12_381.G2.ProjectivePoint.fromAffine>;
|
|
19
22
|
/** Reduce a bigint into the canonical scalar field Z_r. */
|
|
20
23
|
export declare function frCreate(n: bigint): bigint;
|
|
@@ -28,7 +31,13 @@ export declare function randomScalar(): bigint;
|
|
|
28
31
|
export declare function scalarToBytes(v: bigint): Uint8Array;
|
|
29
32
|
/** Decode a 32-byte big-endian scalar back into Z_r. Returns null if not exactly 32 bytes. */
|
|
30
33
|
export declare function bytesToScalar(bytes: Uint8Array): bigint | null;
|
|
31
|
-
/**
|
|
34
|
+
/** True iff `s` contains an unpaired UTF-16 surrogate (such strings alias each other once UTF-8 encoded). */
|
|
35
|
+
export declare function isIllFormedUtf16(s: string): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Hash an attribute string to its identity point `Q_attr` in G1 (prime-order subgroup, RO model).
|
|
38
|
+
* Throws on ill-formed UTF-16: `TextEncoder` maps every lone surrogate to U+FFFD, so two different JS strings
|
|
39
|
+
* would otherwise hash to the SAME identity and a key issued for one would open ciphertexts for the other.
|
|
40
|
+
*/
|
|
32
41
|
export declare function hashAttrToG1(attr: string): G1Point;
|
|
33
42
|
/** Scalar-multiply a G1 point. */
|
|
34
43
|
export declare function g1Mul(p: G1Point, k: bigint): G1Point;
|
|
@@ -38,15 +47,29 @@ export declare function g2Mul(p: G2Point, k: bigint): G2Point;
|
|
|
38
47
|
export declare function g1ToBytes(p: G1Point): Uint8Array;
|
|
39
48
|
/** Serialise a G2 point (compressed, 96 bytes). */
|
|
40
49
|
export declare function g2ToBytes(p: G2Point): Uint8Array;
|
|
41
|
-
/**
|
|
50
|
+
/**
|
|
51
|
+
* Parse a G1 point; null (never throws) on any malformed / off-curve / wrong-subgroup input AND on the point at
|
|
52
|
+
* infinity (no honest key, ephemeral or public element is ever the identity, and pairing with it is undefined).
|
|
53
|
+
*/
|
|
42
54
|
export declare function g1FromBytes(bytes: Uint8Array): G1Point | null;
|
|
43
|
-
/** Parse a
|
|
55
|
+
/** Parse a G2 point; null (never throws) on any malformed / off-curve / wrong-subgroup / identity input. */
|
|
44
56
|
export declare function g2FromBytes(bytes: Uint8Array): G2Point | null;
|
|
45
57
|
/** The (final-exponentiated) ate pairing `e(P, Q)` in GT. */
|
|
46
|
-
export declare function pairing(p: G1Point, q: G2Point):
|
|
58
|
+
export declare function pairing(p: G1Point, q: G2Point): GtElement;
|
|
47
59
|
/** Raise a GT element to a scalar power. */
|
|
48
|
-
export declare function gtPow(gt:
|
|
49
|
-
/**
|
|
50
|
-
export declare function
|
|
60
|
+
export declare function gtPow(gt: GtElement, k: bigint): GtElement;
|
|
61
|
+
/** Product of pairings `prod e(P_i, Q_i)` with ONE shared final exponentiation (a multi-Miller loop). Throws on an identity point. */
|
|
62
|
+
export declare function pairingProduct(pairs: readonly {
|
|
63
|
+
g1: G1Point;
|
|
64
|
+
g2: G2Point;
|
|
65
|
+
}[]): GtElement;
|
|
66
|
+
export declare function gtEql(a: GtElement, b: GtElement): boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Parse a GT element (576 bytes). Null unless the bytes are the canonical encoding of an element of the
|
|
69
|
+
* prime-order subgroup GT (x^r = 1) other than the identity.
|
|
70
|
+
*/
|
|
71
|
+
export declare function gtFromBytes(bytes: Uint8Array): GtElement | null;
|
|
72
|
+
/** Canonical byte serialisation of a GT element (576 bytes) — the secret material fed into the KDF. */
|
|
73
|
+
export declare function gtToBytes(gt: GtElement): Uint8Array;
|
|
51
74
|
/** HKDF-SHA256 to exactly 32 bytes, with explicit salt + info domain separation. */
|
|
52
75
|
export declare function kdf32(ikm: Uint8Array, salt: Uint8Array, info: string): Uint8Array;
|
package/dist/bls.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.G2_BASE = exports.R = void 0;
|
|
3
|
+
exports.G2_BASE = exports.G1_BASE = exports.R = void 0;
|
|
4
4
|
exports.frCreate = frCreate;
|
|
5
5
|
exports.frAdd = frAdd;
|
|
6
6
|
exports.frSub = frSub;
|
|
@@ -9,6 +9,7 @@ exports.frInv = frInv;
|
|
|
9
9
|
exports.randomScalar = randomScalar;
|
|
10
10
|
exports.scalarToBytes = scalarToBytes;
|
|
11
11
|
exports.bytesToScalar = bytesToScalar;
|
|
12
|
+
exports.isIllFormedUtf16 = isIllFormedUtf16;
|
|
12
13
|
exports.hashAttrToG1 = hashAttrToG1;
|
|
13
14
|
exports.g1Mul = g1Mul;
|
|
14
15
|
exports.g2Mul = g2Mul;
|
|
@@ -18,6 +19,9 @@ exports.g1FromBytes = g1FromBytes;
|
|
|
18
19
|
exports.g2FromBytes = g2FromBytes;
|
|
19
20
|
exports.pairing = pairing;
|
|
20
21
|
exports.gtPow = gtPow;
|
|
22
|
+
exports.pairingProduct = pairingProduct;
|
|
23
|
+
exports.gtEql = gtEql;
|
|
24
|
+
exports.gtFromBytes = gtFromBytes;
|
|
21
25
|
exports.gtToBytes = gtToBytes;
|
|
22
26
|
exports.kdf32 = kdf32;
|
|
23
27
|
const bls12_381_1 = require("@noble/curves/bls12-381");
|
|
@@ -30,18 +34,21 @@ const utils_2 = require("@noble/hashes/utils");
|
|
|
30
34
|
* audited `bls12_381` implementation (G1/G2/GT, the ate pairing, RFC 9380 hash-to-curve); nothing here
|
|
31
35
|
* re-implements field or point arithmetic.
|
|
32
36
|
*
|
|
33
|
-
* Group placement (type-3 / asymmetric pairing `e: G1 x G2 -> GT`):
|
|
34
|
-
* - attribute
|
|
35
|
-
* -
|
|
36
|
-
* -
|
|
37
|
-
* -
|
|
37
|
+
* Group placement (type-3 / asymmetric pairing `e: G1 x G2 -> GT`), see `abe.ts` for the scheme:
|
|
38
|
+
* - the attribute hash `H(attr)` lives in G1 (hash-to-curve),
|
|
39
|
+
* - user-key components D, D_j live in G1 and D'_j in G2,
|
|
40
|
+
* - ciphertext components C_0 and C_x live in G2 and C'_x in G1,
|
|
41
|
+
* - the blinding value e(g1,g2)^alpha and every recovered quantity live in GT.
|
|
38
42
|
*/
|
|
39
43
|
/** Curve subgroup (scalar field) order r — a 255-bit prime, so every scalar fits in 32 bytes. */
|
|
40
44
|
exports.R = bls12_381_1.bls12_381.params.r;
|
|
41
45
|
const Fr = bls12_381_1.bls12_381.fields.Fr;
|
|
46
|
+
const Fp = bls12_381_1.bls12_381.fields.Fp;
|
|
42
47
|
const Fp12 = bls12_381_1.bls12_381.fields.Fp12;
|
|
43
48
|
/** Domain-separation tag for hashing an attribute string to a point in G1 (RFC 9380 SSWU_RO). */
|
|
44
|
-
const ATTR_DST = 'ATLAS-PCA-ABE:
|
|
49
|
+
const ATTR_DST = 'ATLAS-PCA-ABE:BSW07:H-G1:SHA256-SSWU-RO:v2';
|
|
50
|
+
/** The fixed G1 generator the whole system is parameterised over. */
|
|
51
|
+
exports.G1_BASE = bls12_381_1.bls12_381.G1.ProjectivePoint.BASE;
|
|
45
52
|
/** The fixed G2 generator the whole system is parameterised over. */
|
|
46
53
|
exports.G2_BASE = bls12_381_1.bls12_381.G2.ProjectivePoint.BASE;
|
|
47
54
|
// ---- field scalars (Z_r) --------------------------------------------------------------------
|
|
@@ -80,8 +87,18 @@ function bytesToScalar(bytes) {
|
|
|
80
87
|
return Fr.create((0, utils_1.bytesToNumberBE)(bytes));
|
|
81
88
|
}
|
|
82
89
|
// ---- points ---------------------------------------------------------------------------------
|
|
83
|
-
/**
|
|
90
|
+
/** True iff `s` contains an unpaired UTF-16 surrogate (such strings alias each other once UTF-8 encoded). */
|
|
91
|
+
function isIllFormedUtf16(s) {
|
|
92
|
+
return /[\ud800-\udbff](?![\udc00-\udfff])|(?<![\ud800-\udbff])[\udc00-\udfff]/.test(s);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Hash an attribute string to its identity point `Q_attr` in G1 (prime-order subgroup, RO model).
|
|
96
|
+
* Throws on ill-formed UTF-16: `TextEncoder` maps every lone surrogate to U+FFFD, so two different JS strings
|
|
97
|
+
* would otherwise hash to the SAME identity and a key issued for one would open ciphertexts for the other.
|
|
98
|
+
*/
|
|
84
99
|
function hashAttrToG1(attr) {
|
|
100
|
+
if (isIllFormedUtf16(attr))
|
|
101
|
+
throw new RangeError('attribute is not well-formed UTF-16');
|
|
85
102
|
const msg = new TextEncoder().encode(attr);
|
|
86
103
|
const h = bls12_381_1.bls12_381.G1.hashToCurve(msg, { DST: ATTR_DST });
|
|
87
104
|
// Normalise the hash-to-curve result into a ProjectivePoint so the full (de)serialisation API is available.
|
|
@@ -103,22 +120,41 @@ function g1ToBytes(p) {
|
|
|
103
120
|
function g2ToBytes(p) {
|
|
104
121
|
return p.toRawBytes(true);
|
|
105
122
|
}
|
|
106
|
-
|
|
123
|
+
function bytesEqual(a, b) {
|
|
124
|
+
if (a.length !== b.length)
|
|
125
|
+
return false;
|
|
126
|
+
let d = 0;
|
|
127
|
+
for (let i = 0; i < a.length; i++)
|
|
128
|
+
d |= (a[i] ?? 0) ^ (b[i] ?? 0);
|
|
129
|
+
return d === 0;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Parse a G1 point; null (never throws) on any malformed / off-curve / wrong-subgroup input AND on the point at
|
|
133
|
+
* infinity (no honest key, ephemeral or public element is ever the identity, and pairing with it is undefined).
|
|
134
|
+
*/
|
|
107
135
|
function g1FromBytes(bytes) {
|
|
108
136
|
try {
|
|
109
137
|
const p = bls12_381_1.bls12_381.G1.ProjectivePoint.fromHex(bytes);
|
|
110
138
|
p.assertValidity();
|
|
139
|
+
if (p.equals(bls12_381_1.bls12_381.G1.ProjectivePoint.ZERO))
|
|
140
|
+
return null;
|
|
141
|
+
if (!bytesEqual(p.toRawBytes(true), bytes))
|
|
142
|
+
return null; // strict: only the canonical compressed encoding
|
|
111
143
|
return p;
|
|
112
144
|
}
|
|
113
145
|
catch {
|
|
114
146
|
return null;
|
|
115
147
|
}
|
|
116
148
|
}
|
|
117
|
-
/** Parse a
|
|
149
|
+
/** Parse a G2 point; null (never throws) on any malformed / off-curve / wrong-subgroup / identity input. */
|
|
118
150
|
function g2FromBytes(bytes) {
|
|
119
151
|
try {
|
|
120
152
|
const p = bls12_381_1.bls12_381.G2.ProjectivePoint.fromHex(bytes);
|
|
121
153
|
p.assertValidity();
|
|
154
|
+
if (p.equals(bls12_381_1.bls12_381.G2.ProjectivePoint.ZERO))
|
|
155
|
+
return null;
|
|
156
|
+
if (!bytesEqual(p.toRawBytes(true), bytes))
|
|
157
|
+
return null; // strict: only the canonical compressed encoding
|
|
122
158
|
return p;
|
|
123
159
|
}
|
|
124
160
|
catch {
|
|
@@ -134,7 +170,41 @@ function pairing(p, q) {
|
|
|
134
170
|
function gtPow(gt, k) {
|
|
135
171
|
return Fp12.pow(gt, Fr.create(k));
|
|
136
172
|
}
|
|
137
|
-
/**
|
|
173
|
+
/** Product of pairings `prod e(P_i, Q_i)` with ONE shared final exponentiation (a multi-Miller loop). Throws on an identity point. */
|
|
174
|
+
function pairingProduct(pairs) {
|
|
175
|
+
return bls12_381_1.bls12_381.pairingBatch([...pairs], true);
|
|
176
|
+
}
|
|
177
|
+
function gtEql(a, b) {
|
|
178
|
+
return Fp12.eql(a, b);
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Parse a GT element (576 bytes). Null unless the bytes are the canonical encoding of an element of the
|
|
182
|
+
* prime-order subgroup GT (x^r = 1) other than the identity.
|
|
183
|
+
*/
|
|
184
|
+
function gtFromBytes(bytes) {
|
|
185
|
+
if (bytes.length !== 576)
|
|
186
|
+
return null;
|
|
187
|
+
// @noble's Fp12.fromBytes does NOT reduce coordinates: a coordinate c + p parses as a distinct, structurally
|
|
188
|
+
// unequal value that still behaves as c in arithmetic (so 1 + p would slip past the identity test below) and
|
|
189
|
+
// re-serialises to the same unreduced bytes (so the round-trip check cannot see it). Require every Fp coordinate < p.
|
|
190
|
+
for (let off = 0; off < 576; off += 48)
|
|
191
|
+
if ((0, utils_1.bytesToNumberBE)(bytes.subarray(off, off + 48)) >= Fp.ORDER)
|
|
192
|
+
return null;
|
|
193
|
+
try {
|
|
194
|
+
const x = Fp12.fromBytes(bytes);
|
|
195
|
+
if (Fp12.eql(x, Fp12.ONE))
|
|
196
|
+
return null;
|
|
197
|
+
if (!Fp12.eql(Fp12.pow(x, exports.R), Fp12.ONE))
|
|
198
|
+
return null;
|
|
199
|
+
if (!bytesEqual(Fp12.toBytes(x), bytes))
|
|
200
|
+
return null;
|
|
201
|
+
return x;
|
|
202
|
+
}
|
|
203
|
+
catch {
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
/** Canonical byte serialisation of a GT element (576 bytes) — the secret material fed into the KDF. */
|
|
138
208
|
function gtToBytes(gt) {
|
|
139
209
|
return Fp12.toBytes(gt);
|
|
140
210
|
}
|
package/dist/bls.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bls.js","sourceRoot":"","sources":["../src/bls.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"bls.js","sourceRoot":"","sources":["../src/bls.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @atlasauth/pca-abe — proof-carrying encryption.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* or result decrypts ONLY for a holder whose PCA capability satisfies the policy. See `abe.ts` for the
|
|
4
|
+
* Collusion-resistant ciphertext-policy attribute-based encryption on BLS12-381 (Bethencourt-Sahai-Waters
|
|
5
|
+
* CP-ABE with a per-user key randomiser, type-3 pairing adaptation, Shamir access tree, AES-256-GCM) so a
|
|
6
|
+
* tool payload or result decrypts ONLY for a holder whose PCA capability satisfies the policy. See `abe.ts` for the
|
|
7
7
|
* full construction and security property.
|
|
8
8
|
*/
|
|
9
|
-
export { ABE_ALG, PcaEncryptionError, setup, keygenForAttributes, keygenForCapability, encryptForPolicy, decrypt, decryptText, parseCiphertext, type MasterPublicKey, type MasterSecretKey, type DecryptionKey, type AbeCiphertext, type KemTree, } from './abe';
|
|
9
|
+
export { ABE_ALG, PcaEncryptionError, setup, keygenForAttributes, keygenForCapability, rerandomizeKey, encryptForPolicy, decrypt, decryptText, parseCiphertext, type MasterPublicKey, type MasterSecretKey, type DecryptionKey, type AbeCiphertext, type AttributeKey, type KemTree, } from './abe';
|
|
10
10
|
export { encryptToolPayload, decryptWithCapability, type DecryptedPayload } from './pca';
|
|
11
|
-
export { normalizePolicy, satisfies, policyAttributes, MAX_POLICY_NODES, type Policy, type ThresholdTree, type PolicyResult, } from './policy';
|
|
12
|
-
export { Attr, capabilityAttributes } from './attributes';
|
|
11
|
+
export { normalizePolicy, satisfies, policyAttributes, MAX_POLICY_NODES, MAX_POLICY_DEPTH, type Policy, type ThresholdTree, type PolicyResult, } from './policy';
|
|
12
|
+
export { Attr, capabilityAttributes, type CapabilityAttributeOpts } from './attributes';
|
package/dist/index.js
CHANGED
|
@@ -2,19 +2,20 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* @atlasauth/pca-abe — proof-carrying encryption.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* or result decrypts ONLY for a holder whose PCA capability satisfies the policy. See `abe.ts` for the
|
|
5
|
+
* Collusion-resistant ciphertext-policy attribute-based encryption on BLS12-381 (Bethencourt-Sahai-Waters
|
|
6
|
+
* CP-ABE with a per-user key randomiser, type-3 pairing adaptation, Shamir access tree, AES-256-GCM) so a
|
|
7
|
+
* tool payload or result decrypts ONLY for a holder whose PCA capability satisfies the policy. See `abe.ts` for the
|
|
8
8
|
* full construction and security property.
|
|
9
9
|
*/
|
|
10
10
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
-
exports.capabilityAttributes = exports.Attr = exports.MAX_POLICY_NODES = exports.policyAttributes = exports.satisfies = exports.normalizePolicy = exports.decryptWithCapability = exports.encryptToolPayload = exports.parseCiphertext = exports.decryptText = exports.decrypt = exports.encryptForPolicy = exports.keygenForCapability = exports.keygenForAttributes = exports.setup = exports.PcaEncryptionError = exports.ABE_ALG = void 0;
|
|
11
|
+
exports.capabilityAttributes = exports.Attr = exports.MAX_POLICY_DEPTH = exports.MAX_POLICY_NODES = exports.policyAttributes = exports.satisfies = exports.normalizePolicy = exports.decryptWithCapability = exports.encryptToolPayload = exports.parseCiphertext = exports.decryptText = exports.decrypt = exports.encryptForPolicy = exports.rerandomizeKey = exports.keygenForCapability = exports.keygenForAttributes = exports.setup = exports.PcaEncryptionError = exports.ABE_ALG = void 0;
|
|
12
12
|
var abe_1 = require("./abe");
|
|
13
13
|
Object.defineProperty(exports, "ABE_ALG", { enumerable: true, get: function () { return abe_1.ABE_ALG; } });
|
|
14
14
|
Object.defineProperty(exports, "PcaEncryptionError", { enumerable: true, get: function () { return abe_1.PcaEncryptionError; } });
|
|
15
15
|
Object.defineProperty(exports, "setup", { enumerable: true, get: function () { return abe_1.setup; } });
|
|
16
16
|
Object.defineProperty(exports, "keygenForAttributes", { enumerable: true, get: function () { return abe_1.keygenForAttributes; } });
|
|
17
17
|
Object.defineProperty(exports, "keygenForCapability", { enumerable: true, get: function () { return abe_1.keygenForCapability; } });
|
|
18
|
+
Object.defineProperty(exports, "rerandomizeKey", { enumerable: true, get: function () { return abe_1.rerandomizeKey; } });
|
|
18
19
|
Object.defineProperty(exports, "encryptForPolicy", { enumerable: true, get: function () { return abe_1.encryptForPolicy; } });
|
|
19
20
|
Object.defineProperty(exports, "decrypt", { enumerable: true, get: function () { return abe_1.decrypt; } });
|
|
20
21
|
Object.defineProperty(exports, "decryptText", { enumerable: true, get: function () { return abe_1.decryptText; } });
|
|
@@ -27,6 +28,7 @@ Object.defineProperty(exports, "normalizePolicy", { enumerable: true, get: funct
|
|
|
27
28
|
Object.defineProperty(exports, "satisfies", { enumerable: true, get: function () { return policy_1.satisfies; } });
|
|
28
29
|
Object.defineProperty(exports, "policyAttributes", { enumerable: true, get: function () { return policy_1.policyAttributes; } });
|
|
29
30
|
Object.defineProperty(exports, "MAX_POLICY_NODES", { enumerable: true, get: function () { return policy_1.MAX_POLICY_NODES; } });
|
|
31
|
+
Object.defineProperty(exports, "MAX_POLICY_DEPTH", { enumerable: true, get: function () { return policy_1.MAX_POLICY_DEPTH; } });
|
|
30
32
|
var attributes_1 = require("./attributes");
|
|
31
33
|
Object.defineProperty(exports, "Attr", { enumerable: true, get: function () { return attributes_1.Attr; } });
|
|
32
34
|
Object.defineProperty(exports, "capabilityAttributes", { enumerable: true, get: function () { return attributes_1.capabilityAttributes; } });
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;AAEH,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;AAEH,6BAiBe;AAhBb,8FAAA,OAAO,OAAA;AACP,yGAAA,kBAAkB,OAAA;AAClB,4FAAA,KAAK,OAAA;AACL,0GAAA,mBAAmB,OAAA;AACnB,0GAAA,mBAAmB,OAAA;AACnB,qGAAA,cAAc,OAAA;AACd,uGAAA,gBAAgB,OAAA;AAChB,8FAAA,OAAO,OAAA;AACP,kGAAA,WAAW,OAAA;AACX,sGAAA,eAAe,OAAA;AASjB,6BAAyF;AAAhF,yGAAA,kBAAkB,OAAA;AAAE,4GAAA,qBAAqB,OAAA;AAElD,mCASkB;AARhB,yGAAA,eAAe,OAAA;AACf,mGAAA,SAAS,OAAA;AACT,0GAAA,gBAAgB,OAAA;AAChB,0GAAA,gBAAgB,OAAA;AAChB,0GAAA,gBAAgB,OAAA;AAMlB,2CAAwF;AAA/E,kGAAA,IAAI,OAAA;AAAE,kHAAA,oBAAoB,OAAA"}
|
package/dist/pca.d.ts
CHANGED
|
@@ -25,8 +25,9 @@ import type { Policy } from './policy';
|
|
|
25
25
|
* derive from the same signed capability. Encryption adds CONFIDENTIALITY (a passive observer, or a
|
|
26
26
|
* holder of a different/weaker capability, learns nothing) on top of the PCActn's AUTHORISATION.
|
|
27
27
|
*
|
|
28
|
-
* SECURITY: as in `abe.ts` —
|
|
29
|
-
* AES-256-GCM. Not a NIZK
|
|
28
|
+
* SECURITY: as in `abe.ts` — BSW07 CP-ABE (selective security in the paper's generic-group model, not
|
|
29
|
+
* re-proved for this type-3 adaptation), integrity under AES-256-GCM. Not a NIZK. Keys carry a per-key
|
|
30
|
+
* randomiser, so keys issued to different agents cannot be pooled to satisfy a policy neither satisfies.
|
|
30
31
|
*/
|
|
31
32
|
/** Result of a payload decryption attempt. `ok:false` means the key's authority did not satisfy the policy (or the ciphertext was tampered/malformed). */
|
|
32
33
|
export type DecryptedPayload = {
|
package/dist/pca.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pca.js","sourceRoot":"","sources":["../src/pca.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"pca.js","sourceRoot":"","sources":["../src/pca.ts"],"names":[],"mappings":";;AA8CA,gDAOC;AAMD,sDAQC;AAnED,+BAMe;AAoCf;;;GAGG;AACH,SAAgB,kBAAkB,CAChC,GAAoB,EACpB,wBAAgC,EAChC,OAAgB;IAEhB,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,IAAI,IAAI,CAAC,CAAC;IAC7C,OAAO,IAAA,sBAAgB,EAAC,GAAG,EAAE,wBAAwB,EAAE,IAAI,CAAC,CAAC;AAC/D,CAAC;AAED;;;GAGG;AACH,SAAgB,qBAAqB,CAAC,GAAkB,EAAE,UAAmB;IAC3E,MAAM,EAAE,GAAG,IAAA,aAAO,EAAC,GAAG,EAAE,UAAU,CAAC,CAAC;IACpC,IAAI,EAAE,KAAK,IAAI;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,kEAAkE,EAAE,CAAC;IAClH,IAAI,CAAC;QACH,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,CAAY,EAAE,CAAC;IACpF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,qCAAqC,EAAE,CAAC;IACtE,CAAC;AACH,CAAC"}
|
package/dist/policy.d.ts
CHANGED
|
@@ -40,6 +40,13 @@ export interface PolicyOk {
|
|
|
40
40
|
export type PolicyResult = PolicyOk | PolicyError;
|
|
41
41
|
/** Upper bound on total nodes in a policy tree (bounds work on untrusted input). */
|
|
42
42
|
export declare const MAX_POLICY_NODES = 1024;
|
|
43
|
+
/**
|
|
44
|
+
* Upper bound on gate nesting along any root-to-leaf path. The ciphertext header is authenticated as canonical
|
|
45
|
+
* JSON, whose nesting is capped at 32 by the PCA canonicalizer; every gate level costs three JSON levels
|
|
46
|
+
* (gate object, `of` array, branch object) and the root sits at level 2, so 10 gate levels is the most that can
|
|
47
|
+
* ever be authenticated. Enforcing it here makes "encryptable" imply "decryptable".
|
|
48
|
+
*/
|
|
49
|
+
export declare const MAX_POLICY_DEPTH = 10;
|
|
43
50
|
/**
|
|
44
51
|
* Validate and normalise an access structure into a threshold tree. Fails closed (returns a reason)
|
|
45
52
|
* on any malformed node, empty gate, out-of-range threshold, or oversized tree.
|
package/dist/policy.js
CHANGED
|
@@ -1,19 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.MAX_POLICY_NODES = void 0;
|
|
3
|
+
exports.MAX_POLICY_DEPTH = exports.MAX_POLICY_NODES = void 0;
|
|
4
4
|
exports.normalizePolicy = normalizePolicy;
|
|
5
5
|
exports.satisfies = satisfies;
|
|
6
6
|
exports.policyAttributes = policyAttributes;
|
|
7
|
+
const bls_1 = require("./bls");
|
|
7
8
|
const wire_1 = require("./wire");
|
|
8
9
|
/** Upper bound on total nodes in a policy tree (bounds work on untrusted input). */
|
|
9
10
|
exports.MAX_POLICY_NODES = 1024;
|
|
11
|
+
/**
|
|
12
|
+
* Upper bound on gate nesting along any root-to-leaf path. The ciphertext header is authenticated as canonical
|
|
13
|
+
* JSON, whose nesting is capped at 32 by the PCA canonicalizer; every gate level costs three JSON levels
|
|
14
|
+
* (gate object, `of` array, branch object) and the root sits at level 2, so 10 gate levels is the most that can
|
|
15
|
+
* ever be authenticated. Enforcing it here makes "encryptable" imply "decryptable".
|
|
16
|
+
*/
|
|
17
|
+
exports.MAX_POLICY_DEPTH = 10;
|
|
10
18
|
/**
|
|
11
19
|
* Validate and normalise an access structure into a threshold tree. Fails closed (returns a reason)
|
|
12
20
|
* on any malformed node, empty gate, out-of-range threshold, or oversized tree.
|
|
13
21
|
*/
|
|
14
22
|
function normalizePolicy(policy) {
|
|
15
23
|
let nodes = 0;
|
|
16
|
-
function walk(p, path) {
|
|
24
|
+
function walk(p, path, gates) {
|
|
17
25
|
if (++nodes > exports.MAX_POLICY_NODES)
|
|
18
26
|
return { ok: false, reason: `policy too large (> ${exports.MAX_POLICY_NODES} nodes)` };
|
|
19
27
|
if (!(0, wire_1.isObject)(p))
|
|
@@ -21,17 +29,26 @@ function normalizePolicy(policy) {
|
|
|
21
29
|
if ('attr' in p) {
|
|
22
30
|
if (!(0, wire_1.isString)(p.attr) || p.attr.length === 0)
|
|
23
31
|
return { ok: false, reason: `${path}: 'attr' must be a non-empty string` };
|
|
32
|
+
if ((0, bls_1.isIllFormedUtf16)(p.attr))
|
|
33
|
+
return { ok: false, reason: `${path}: 'attr' is not well-formed UTF-16` };
|
|
24
34
|
if ('allOf' in p || 'anyOf' in p || 'threshold' in p || 'of' in p) {
|
|
25
35
|
return { ok: false, reason: `${path}: a leaf must not mix 'attr' with a gate` };
|
|
26
36
|
}
|
|
27
37
|
return { kind: 'leaf', attr: p.attr };
|
|
28
38
|
}
|
|
39
|
+
const gateKeys = ['allOf', 'anyOf', 'threshold', 'of'].filter((k) => k in p).filter((k) => k !== 'of' || !('threshold' in p));
|
|
40
|
+
if (gateKeys.length > 1) {
|
|
41
|
+
return { ok: false, reason: `${path}: ambiguous node (${gateKeys.join(', ')}); a gate must use exactly one of allOf/anyOf/threshold` };
|
|
42
|
+
}
|
|
43
|
+
if (gateKeys.length === 1 && gates + 1 > exports.MAX_POLICY_DEPTH) {
|
|
44
|
+
return { ok: false, reason: `${path}: policy nested deeper than ${exports.MAX_POLICY_DEPTH} gates` };
|
|
45
|
+
}
|
|
29
46
|
const parseChildren = (raw, key) => {
|
|
30
47
|
if (!Array.isArray(raw) || raw.length === 0)
|
|
31
48
|
return { ok: false, reason: `${path}: '${key}' must be a non-empty array` };
|
|
32
49
|
const out = [];
|
|
33
50
|
for (let i = 0; i < raw.length; i++) {
|
|
34
|
-
const child = walk(raw[i], `${path}.${key}[${i}]
|
|
51
|
+
const child = walk(raw[i], `${path}.${key}[${i}]`, gates + 1);
|
|
35
52
|
if ('ok' in child)
|
|
36
53
|
return child;
|
|
37
54
|
out.push(child);
|
|
@@ -63,7 +80,7 @@ function normalizePolicy(policy) {
|
|
|
63
80
|
}
|
|
64
81
|
return { ok: false, reason: `${path}: unknown policy node (expected attr/allOf/anyOf/threshold)` };
|
|
65
82
|
}
|
|
66
|
-
const tree = walk(policy, 'policy');
|
|
83
|
+
const tree = walk(policy, 'policy', 0);
|
|
67
84
|
if ('ok' in tree)
|
|
68
85
|
return tree;
|
|
69
86
|
return { ok: true, tree };
|