@atlasauth/pca-abe 0.0.0-stage → 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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attributes.js","sourceRoot":"","sources":["../src/attributes.ts"],"names":[],"mappings":";;;AA8CA,oDAcC;AA5DD,wCAA+D;AAE/D;;;;;;;;;;;;;;;;;GAiBG;AAEU,QAAA,IAAI,GAAG;IAClB,MAAM,EAAE,CAAC,GAAW,EAAU,EAAE,CAAC,UAAU,GAAG,EAAE;IAChD,IAAI,EAAE,CAAC,CAAS,EAAU,EAAE,CAAC,QAAQ,CAAC,EAAE;IACxC,QAAQ,EAAE,CAAC,CAAS,EAAU,EAAE,CAAC,YAAY,CAAC,EAAE;IAChD,KAAK,EAAE,CAAC,CAAS,EAAU,EAAE,CAAC,SAAS,CAAC,EAAE;CAClC,CAAC;AAEX,SAAS,OAAO,CAAC,GAAgB,EAAE,IAAa;IAC9C,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,GAAG,CAAC,GAAG,CAAC,YAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;SAClD,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,KAAK,MAAM,CAAC,IAAI,IAAI;YAAE,IAAI,OAAO,CAAC,KAAK,QAAQ;gBAAE,GAAG,CAAC,GAAG,CAAC,YAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AACvG,CAAC;AAED,SAAS,SAAS,CAAC,GAAgB,EAAE,OAA0D;IAC7F,KAAK,MAAM,EAAE,IAAI,OAAO,EAAE,CAAC;QACzB,IAAI,EAAE,CAAC,IAAI,KAAK,OAAO,IAAI,OAAO,EAAE,CAAC,KAAK,KAAK,QAAQ;YAAE,GAAG,CAAC,GAAG,CAAC,YAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;QACvF,IAAI,EAAE,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC;YACrD,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM;gBAAE,IAAI,OAAO,CAAC,KAAK,QAAQ;oBAAE,GAAG,CAAC,GAAG,CAAC,YAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/E,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAgB,oBAAoB,CAAC,GAAe;IAClD,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAC;IAC9B,IAAI,OAAO,GAAG,CAAC,MAAM,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC;QAAE,GAAG,CAAC,GAAG,CAAC,YAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;IAC9F,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC;QAAE,SAAS,CAAC,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IAC5D,MAAM,GAAG,GAAG,IAAA,kBAAY,EAAC,GAAG,CAAC,CAAC;IAC9B,IAAI,GAAG,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;QAClD,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC;YAC/B,IAAI,CAAC,KAAK,IAAI,IAAI,OAAO,CAAC,KAAK,QAAQ;gBAAE,SAAS;YAClD,OAAO,CAAC,GAAG,EAAG,CAAwB,CAAC,IAAI,CAAC,CAAC;YAC7C,MAAM,CAAC,GAAI,CAA4B,CAAC,QAAQ,CAAC;YACjD,IAAI,OAAO,CAAC,KAAK,QAAQ;gBAAE,GAAG,CAAC,GAAG,CAAC,YAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
package/dist/bls.d.ts ADDED
@@ -0,0 +1,52 @@
1
+ import { bls12_381 } from '@noble/curves/bls12-381';
2
+ /**
3
+ * Low-level BLS12-381 helpers for the ABE scheme. All group/field work goes through `@noble/curves`'s
4
+ * audited `bls12_381` implementation (G1/G2/GT, the ate pairing, RFC 9380 hash-to-curve); nothing here
5
+ * re-implements field or point arithmetic.
6
+ *
7
+ * Group placement (type-3 / asymmetric pairing `e: G1 x G2 -> GT`):
8
+ * - attribute identity points `Q_attr = H1(attr)` live in G1 (hash-to-curve),
9
+ * - the master public `P_pub = s * g2` and ephemerals `U = x * g2` live in G2,
10
+ * - decryption keys `d_attr = s * Q_attr` live in G1,
11
+ * - KEM secrets live in GT.
12
+ */
13
+ /** Curve subgroup (scalar field) order r — a 255-bit prime, so every scalar fits in 32 bytes. */
14
+ export declare const R: bigint;
15
+ /** The fixed G2 generator the whole system is parameterised over. */
16
+ export declare const G2_BASE: import("@noble/curves/abstract/weierstrass").ProjPointType<import("@noble/curves/abstract/tower").Fp2>;
17
+ export type G1Point = ReturnType<typeof bls12_381.G1.ProjectivePoint.fromAffine>;
18
+ export type G2Point = ReturnType<typeof bls12_381.G2.ProjectivePoint.fromAffine>;
19
+ /** Reduce a bigint into the canonical scalar field Z_r. */
20
+ export declare function frCreate(n: bigint): bigint;
21
+ export declare function frAdd(a: bigint, b: bigint): bigint;
22
+ export declare function frSub(a: bigint, b: bigint): bigint;
23
+ export declare function frMul(a: bigint, b: bigint): bigint;
24
+ export declare function frInv(a: bigint): bigint;
25
+ /** A uniformly random NON-ZERO scalar in Z_r (48 bytes of entropy reduced mod r — negligible bias). */
26
+ export declare function randomScalar(): bigint;
27
+ /** Fixed 32-byte big-endian encoding of a scalar (r < 2^255, so 32 bytes always suffice). */
28
+ export declare function scalarToBytes(v: bigint): Uint8Array;
29
+ /** Decode a 32-byte big-endian scalar back into Z_r. Returns null if not exactly 32 bytes. */
30
+ export declare function bytesToScalar(bytes: Uint8Array): bigint | null;
31
+ /** Hash an attribute string to its identity point `Q_attr` in G1 (prime-order subgroup, RO model). */
32
+ export declare function hashAttrToG1(attr: string): G1Point;
33
+ /** Scalar-multiply a G1 point. */
34
+ export declare function g1Mul(p: G1Point, k: bigint): G1Point;
35
+ /** Scalar-multiply a G2 point. */
36
+ export declare function g2Mul(p: G2Point, k: bigint): G2Point;
37
+ /** Serialise a G1 point (compressed, 48 bytes). */
38
+ export declare function g1ToBytes(p: G1Point): Uint8Array;
39
+ /** Serialise a G2 point (compressed, 96 bytes). */
40
+ export declare function g2ToBytes(p: G2Point): Uint8Array;
41
+ /** Parse a compressed G1 point; null (never throws) on any malformed / off-curve / wrong-subgroup input. */
42
+ export declare function g1FromBytes(bytes: Uint8Array): G1Point | null;
43
+ /** Parse a compressed G2 point; null (never throws) on any malformed / off-curve / wrong-subgroup input. */
44
+ export declare function g2FromBytes(bytes: Uint8Array): G2Point | null;
45
+ /** The (final-exponentiated) ate pairing `e(P, Q)` in GT. */
46
+ export declare function pairing(p: G1Point, q: G2Point): ReturnType<typeof bls12_381.pairing>;
47
+ /** Raise a GT element to a scalar power. */
48
+ export declare function gtPow(gt: ReturnType<typeof bls12_381.pairing>, k: bigint): ReturnType<typeof bls12_381.pairing>;
49
+ /** Canonical byte serialisation of a GT element (576 bytes) — the KEM secret material fed into the KDF. */
50
+ export declare function gtToBytes(gt: ReturnType<typeof bls12_381.pairing>): Uint8Array;
51
+ /** HKDF-SHA256 to exactly 32 bytes, with explicit salt + info domain separation. */
52
+ export declare function kdf32(ikm: Uint8Array, salt: Uint8Array, info: string): Uint8Array;
package/dist/bls.js ADDED
@@ -0,0 +1,146 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.G2_BASE = exports.R = void 0;
4
+ exports.frCreate = frCreate;
5
+ exports.frAdd = frAdd;
6
+ exports.frSub = frSub;
7
+ exports.frMul = frMul;
8
+ exports.frInv = frInv;
9
+ exports.randomScalar = randomScalar;
10
+ exports.scalarToBytes = scalarToBytes;
11
+ exports.bytesToScalar = bytesToScalar;
12
+ exports.hashAttrToG1 = hashAttrToG1;
13
+ exports.g1Mul = g1Mul;
14
+ exports.g2Mul = g2Mul;
15
+ exports.g1ToBytes = g1ToBytes;
16
+ exports.g2ToBytes = g2ToBytes;
17
+ exports.g1FromBytes = g1FromBytes;
18
+ exports.g2FromBytes = g2FromBytes;
19
+ exports.pairing = pairing;
20
+ exports.gtPow = gtPow;
21
+ exports.gtToBytes = gtToBytes;
22
+ exports.kdf32 = kdf32;
23
+ const bls12_381_1 = require("@noble/curves/bls12-381");
24
+ const utils_1 = require("@noble/curves/abstract/utils");
25
+ const hkdf_1 = require("@noble/hashes/hkdf");
26
+ const sha256_1 = require("@noble/hashes/sha256");
27
+ const utils_2 = require("@noble/hashes/utils");
28
+ /**
29
+ * Low-level BLS12-381 helpers for the ABE scheme. All group/field work goes through `@noble/curves`'s
30
+ * audited `bls12_381` implementation (G1/G2/GT, the ate pairing, RFC 9380 hash-to-curve); nothing here
31
+ * re-implements field or point arithmetic.
32
+ *
33
+ * Group placement (type-3 / asymmetric pairing `e: G1 x G2 -> GT`):
34
+ * - attribute identity points `Q_attr = H1(attr)` live in G1 (hash-to-curve),
35
+ * - the master public `P_pub = s * g2` and ephemerals `U = x * g2` live in G2,
36
+ * - decryption keys `d_attr = s * Q_attr` live in G1,
37
+ * - KEM secrets live in GT.
38
+ */
39
+ /** Curve subgroup (scalar field) order r — a 255-bit prime, so every scalar fits in 32 bytes. */
40
+ exports.R = bls12_381_1.bls12_381.params.r;
41
+ const Fr = bls12_381_1.bls12_381.fields.Fr;
42
+ const Fp12 = bls12_381_1.bls12_381.fields.Fp12;
43
+ /** Domain-separation tag for hashing an attribute string to a point in G1 (RFC 9380 SSWU_RO). */
44
+ const ATTR_DST = 'ATLAS-PCA-ABE:BF-IBE:G1:SHA256-SSWU-RO:v1';
45
+ /** The fixed G2 generator the whole system is parameterised over. */
46
+ exports.G2_BASE = bls12_381_1.bls12_381.G2.ProjectivePoint.BASE;
47
+ // ---- field scalars (Z_r) --------------------------------------------------------------------
48
+ /** Reduce a bigint into the canonical scalar field Z_r. */
49
+ function frCreate(n) {
50
+ return Fr.create(n);
51
+ }
52
+ function frAdd(a, b) {
53
+ return Fr.add(a, b);
54
+ }
55
+ function frSub(a, b) {
56
+ return Fr.sub(a, b);
57
+ }
58
+ function frMul(a, b) {
59
+ return Fr.mul(a, b);
60
+ }
61
+ function frInv(a) {
62
+ return Fr.inv(a);
63
+ }
64
+ /** A uniformly random NON-ZERO scalar in Z_r (48 bytes of entropy reduced mod r — negligible bias). */
65
+ function randomScalar() {
66
+ for (;;) {
67
+ const v = Fr.create((0, utils_1.bytesToNumberBE)((0, utils_2.randomBytes)(48)));
68
+ if (v !== 0n)
69
+ return v;
70
+ }
71
+ }
72
+ /** Fixed 32-byte big-endian encoding of a scalar (r < 2^255, so 32 bytes always suffice). */
73
+ function scalarToBytes(v) {
74
+ return (0, utils_1.numberToBytesBE)(Fr.create(v), 32);
75
+ }
76
+ /** Decode a 32-byte big-endian scalar back into Z_r. Returns null if not exactly 32 bytes. */
77
+ function bytesToScalar(bytes) {
78
+ if (bytes.length !== 32)
79
+ return null;
80
+ return Fr.create((0, utils_1.bytesToNumberBE)(bytes));
81
+ }
82
+ // ---- points ---------------------------------------------------------------------------------
83
+ /** Hash an attribute string to its identity point `Q_attr` in G1 (prime-order subgroup, RO model). */
84
+ function hashAttrToG1(attr) {
85
+ const msg = new TextEncoder().encode(attr);
86
+ const h = bls12_381_1.bls12_381.G1.hashToCurve(msg, { DST: ATTR_DST });
87
+ // Normalise the hash-to-curve result into a ProjectivePoint so the full (de)serialisation API is available.
88
+ return bls12_381_1.bls12_381.G1.ProjectivePoint.fromAffine(h.toAffine());
89
+ }
90
+ /** Scalar-multiply a G1 point. */
91
+ function g1Mul(p, k) {
92
+ return p.multiply(Fr.create(k));
93
+ }
94
+ /** Scalar-multiply a G2 point. */
95
+ function g2Mul(p, k) {
96
+ return p.multiply(Fr.create(k));
97
+ }
98
+ /** Serialise a G1 point (compressed, 48 bytes). */
99
+ function g1ToBytes(p) {
100
+ return p.toRawBytes(true);
101
+ }
102
+ /** Serialise a G2 point (compressed, 96 bytes). */
103
+ function g2ToBytes(p) {
104
+ return p.toRawBytes(true);
105
+ }
106
+ /** Parse a compressed G1 point; null (never throws) on any malformed / off-curve / wrong-subgroup input. */
107
+ function g1FromBytes(bytes) {
108
+ try {
109
+ const p = bls12_381_1.bls12_381.G1.ProjectivePoint.fromHex(bytes);
110
+ p.assertValidity();
111
+ return p;
112
+ }
113
+ catch {
114
+ return null;
115
+ }
116
+ }
117
+ /** Parse a compressed G2 point; null (never throws) on any malformed / off-curve / wrong-subgroup input. */
118
+ function g2FromBytes(bytes) {
119
+ try {
120
+ const p = bls12_381_1.bls12_381.G2.ProjectivePoint.fromHex(bytes);
121
+ p.assertValidity();
122
+ return p;
123
+ }
124
+ catch {
125
+ return null;
126
+ }
127
+ }
128
+ // ---- pairing / GT ---------------------------------------------------------------------------
129
+ /** The (final-exponentiated) ate pairing `e(P, Q)` in GT. */
130
+ function pairing(p, q) {
131
+ return bls12_381_1.bls12_381.pairing(p, q, true);
132
+ }
133
+ /** Raise a GT element to a scalar power. */
134
+ function gtPow(gt, k) {
135
+ return Fp12.pow(gt, Fr.create(k));
136
+ }
137
+ /** Canonical byte serialisation of a GT element (576 bytes) — the KEM secret material fed into the KDF. */
138
+ function gtToBytes(gt) {
139
+ return Fp12.toBytes(gt);
140
+ }
141
+ // ---- symmetric KDF --------------------------------------------------------------------------
142
+ /** HKDF-SHA256 to exactly 32 bytes, with explicit salt + info domain separation. */
143
+ function kdf32(ikm, salt, info) {
144
+ return (0, hkdf_1.hkdf)(sha256_1.sha256, ikm, salt, new TextEncoder().encode(info), 32);
145
+ }
146
+ //# sourceMappingURL=bls.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bls.js","sourceRoot":"","sources":["../src/bls.ts"],"names":[],"mappings":";;;AAoCA,4BAEC;AAED,sBAEC;AAED,sBAEC;AAED,sBAEC;AAED,sBAEC;AAGD,oCAKC;AAGD,sCAEC;AAGD,sCAGC;AAKD,oCAKC;AAGD,sBAEC;AAGD,sBAEC;AAGD,8BAEC;AAGD,8BAEC;AAGD,kCAQC;AAGD,kCAQC;AAKD,0BAEC;AAGD,sBAEC;AAGD,8BAEC;AAKD,sBAEC;AArJD,uDAAoD;AACpD,wDAAgF;AAChF,6CAA0C;AAC1C,iDAA8C;AAC9C,+CAAkD;AAElD;;;;;;;;;;GAUG;AAEH,iGAAiG;AACpF,QAAA,CAAC,GAAW,qBAAS,CAAC,MAAM,CAAC,CAAC,CAAC;AAE5C,MAAM,EAAE,GAAG,qBAAS,CAAC,MAAM,CAAC,EAAE,CAAC;AAC/B,MAAM,IAAI,GAAG,qBAAS,CAAC,MAAM,CAAC,IAAI,CAAC;AAEnC,iGAAiG;AACjG,MAAM,QAAQ,GAAG,2CAA2C,CAAC;AAE7D,qEAAqE;AACxD,QAAA,OAAO,GAAG,qBAAS,CAAC,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC;AAKzD,gGAAgG;AAEhG,2DAA2D;AAC3D,SAAgB,QAAQ,CAAC,CAAS;IAChC,OAAO,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACtB,CAAC;AAED,SAAgB,KAAK,CAAC,CAAS,EAAE,CAAS;IACxC,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACtB,CAAC;AAED,SAAgB,KAAK,CAAC,CAAS,EAAE,CAAS;IACxC,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACtB,CAAC;AAED,SAAgB,KAAK,CAAC,CAAS,EAAE,CAAS;IACxC,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACtB,CAAC;AAED,SAAgB,KAAK,CAAC,CAAS;IAC7B,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACnB,CAAC;AAED,uGAAuG;AACvG,SAAgB,YAAY;IAC1B,SAAS,CAAC;QACR,MAAM,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAA,uBAAe,EAAC,IAAA,mBAAW,EAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACtD,IAAI,CAAC,KAAK,EAAE;YAAE,OAAO,CAAC,CAAC;IACzB,CAAC;AACH,CAAC;AAED,6FAA6F;AAC7F,SAAgB,aAAa,CAAC,CAAS;IACrC,OAAO,IAAA,uBAAe,EAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAC3C,CAAC;AAED,8FAA8F;AAC9F,SAAgB,aAAa,CAAC,KAAiB;IAC7C,IAAI,KAAK,CAAC,MAAM,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC;IACrC,OAAO,EAAE,CAAC,MAAM,CAAC,IAAA,uBAAe,EAAC,KAAK,CAAC,CAAC,CAAC;AAC3C,CAAC;AAED,gGAAgG;AAEhG,sGAAsG;AACtG,SAAgB,YAAY,CAAC,IAAY;IACvC,MAAM,GAAG,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC3C,MAAM,CAAC,GAAG,qBAAS,CAAC,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC3D,4GAA4G;IAC5G,OAAO,qBAAS,CAAC,EAAE,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC/D,CAAC;AAED,kCAAkC;AAClC,SAAgB,KAAK,CAAC,CAAU,EAAE,CAAS;IACzC,OAAO,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAClC,CAAC;AAED,kCAAkC;AAClC,SAAgB,KAAK,CAAC,CAAU,EAAE,CAAS;IACzC,OAAO,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAClC,CAAC;AAED,mDAAmD;AACnD,SAAgB,SAAS,CAAC,CAAU;IAClC,OAAO,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;AAC5B,CAAC;AAED,mDAAmD;AACnD,SAAgB,SAAS,CAAC,CAAU;IAClC,OAAO,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;AAC5B,CAAC;AAED,4GAA4G;AAC5G,SAAgB,WAAW,CAAC,KAAiB;IAC3C,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,qBAAS,CAAC,EAAE,CAAC,eAAe,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACtD,CAAC,CAAC,cAAc,EAAE,CAAC;QACnB,OAAO,CAAC,CAAC;IACX,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,4GAA4G;AAC5G,SAAgB,WAAW,CAAC,KAAiB;IAC3C,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,qBAAS,CAAC,EAAE,CAAC,eAAe,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACtD,CAAC,CAAC,cAAc,EAAE,CAAC;QACnB,OAAO,CAAC,CAAC;IACX,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,gGAAgG;AAEhG,6DAA6D;AAC7D,SAAgB,OAAO,CAAC,CAAU,EAAE,CAAU;IAC5C,OAAO,qBAAS,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;AACvC,CAAC;AAED,4CAA4C;AAC5C,SAAgB,KAAK,CAAC,EAAwC,EAAE,CAAS;IACvE,OAAO,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AACpC,CAAC;AAED,2GAA2G;AAC3G,SAAgB,SAAS,CAAC,EAAwC;IAChE,OAAO,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;AAC1B,CAAC;AAED,gGAAgG;AAEhG,oFAAoF;AACpF,SAAgB,KAAK,CAAC,GAAe,EAAE,IAAgB,EAAE,IAAY;IACnE,OAAO,IAAA,WAAI,EAAC,eAAM,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;AACrE,CAAC"}
package/dist/ibe.d.ts ADDED
@@ -0,0 +1,24 @@
1
+ import { type G1Point } from './bls';
2
+ /** A per-leaf encapsulation: the ephemeral `U` (G2, compressed) that pins the derived KEM key. */
3
+ export interface Encapsulation {
4
+ /** Compressed G2 ephemeral `U = x * g2`. */
5
+ U: Uint8Array;
6
+ /** 32-byte symmetric key derived from the GT secret (encryptor side). */
7
+ key: Uint8Array;
8
+ }
9
+ /** Compute `P_pub = s * g2` (the master public element) for master secret `s`. */
10
+ export declare function masterPublic(s: bigint): Uint8Array;
11
+ /** Issue the BF decryption key `d_A = s * H1(A)` (G1, compressed) for attribute `A`. */
12
+ export declare function keygenAttr(s: bigint, attr: string): Uint8Array;
13
+ /**
14
+ * Encapsulate to attribute `A` under master public `pPubBytes`. Returns the ephemeral `U` and the
15
+ * 32-byte KEM key. `salt` is the ciphertext-wide HKDF salt (bound into every derived key). Returns null
16
+ * only if `pPubBytes` is not a valid G2 point.
17
+ */
18
+ export declare function encapsulate(pPubBytes: Uint8Array, attr: string, salt: Uint8Array): Encapsulation | null;
19
+ /**
20
+ * Decapsulate: recover the 32-byte KEM key from decryption key `dA` (G1) and ephemeral `uBytes` (G2).
21
+ * Returns null (fail-closed) if either point is malformed. The attribute string must match the one used
22
+ * at encapsulation (it is bound into the KDF).
23
+ */
24
+ export declare function decapsulate(dA: G1Point, attr: string, uBytes: Uint8Array, salt: Uint8Array): Uint8Array | null;
package/dist/ibe.js ADDED
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.masterPublic = masterPublic;
4
+ exports.keygenAttr = keygenAttr;
5
+ exports.encapsulate = encapsulate;
6
+ exports.decapsulate = decapsulate;
7
+ const bls_1 = require("./bls");
8
+ /**
9
+ * Boneh-Franklin Identity-Based Encryption as a Key-Encapsulation Mechanism (BF-IBE KEM) on BLS12-381.
10
+ *
11
+ * Treat each ATTRIBUTE string as a BF "identity". For master secret `s` and public `P_pub = s * g2`:
12
+ * - the decryption key for attribute `A` is `d_A = s * H1(A)` in G1 (issued by `keygen`),
13
+ * - encapsulation to `A` picks a fresh ephemeral `x`, publishes `U = x * g2` in G2, and derives the
14
+ * shared GT secret `K_GT = e(H1(A), P_pub)^x = e(H1(A), g2)^{s*x}`,
15
+ * - decapsulation with `d_A` recomputes `K_GT = e(d_A, U) = e(s*H1(A), x*g2) = e(H1(A), g2)^{s*x}`.
16
+ *
17
+ * The two sides agree, and a holder WITHOUT `d_A` cannot compute `K_GT` without solving Bilinear
18
+ * Diffie-Hellman. The GT secret is run through HKDF-SHA256 (modelled as a random oracle) to a 32-byte
19
+ * symmetric key that masks the payload share.
20
+ *
21
+ * SECURITY: confidentiality holds under the Bilinear Diffie-Hellman assumption in the random-oracle
22
+ * model (standard BF-IBE). This is NOT a proof of knowledge / NIZK: it binds confidentiality to
23
+ * possession of attribute keys, not to an interactive or non-interactive proof.
24
+ */
25
+ const KEM_KDF_INFO = 'atlas-pca-abe/kem/v1';
26
+ /** Compute `P_pub = s * g2` (the master public element) for master secret `s`. */
27
+ function masterPublic(s) {
28
+ return (0, bls_1.g2ToBytes)((0, bls_1.g2Mul)(bls_1.G2_BASE, s));
29
+ }
30
+ /** Issue the BF decryption key `d_A = s * H1(A)` (G1, compressed) for attribute `A`. */
31
+ function keygenAttr(s, attr) {
32
+ const qA = (0, bls_1.hashAttrToG1)(attr);
33
+ return (0, bls_1.g1ToBytes)(qA.multiply(s));
34
+ }
35
+ function kemKey(gtBytes, salt, attr, uBytes) {
36
+ // Bind the derived key to BOTH the attribute and the specific ephemeral so a key cannot be replayed
37
+ // across attributes or ciphertexts even if (hypothetically) a GT value repeated.
38
+ const info = `${KEM_KDF_INFO}|${attr}|${Buffer.from(uBytes).toString('base64url')}`;
39
+ return (0, bls_1.kdf32)(gtBytes, salt, info);
40
+ }
41
+ /**
42
+ * Encapsulate to attribute `A` under master public `pPubBytes`. Returns the ephemeral `U` and the
43
+ * 32-byte KEM key. `salt` is the ciphertext-wide HKDF salt (bound into every derived key). Returns null
44
+ * only if `pPubBytes` is not a valid G2 point.
45
+ */
46
+ function encapsulate(pPubBytes, attr, salt) {
47
+ const pPub = (0, bls_1.g2FromBytes)(pPubBytes);
48
+ if (pPub === null)
49
+ return null;
50
+ const qA = (0, bls_1.hashAttrToG1)(attr);
51
+ const x = (0, bls_1.randomScalar)();
52
+ const uBytes = (0, bls_1.g2ToBytes)((0, bls_1.g2Mul)(bls_1.G2_BASE, x));
53
+ // K_GT = e(Q_A, P_pub)^x
54
+ const kGt = (0, bls_1.gtPow)((0, bls_1.pairing)(qA, pPub), x);
55
+ const key = kemKey((0, bls_1.gtToBytes)(kGt), salt, attr, uBytes);
56
+ return { U: uBytes, key };
57
+ }
58
+ /**
59
+ * Decapsulate: recover the 32-byte KEM key from decryption key `dA` (G1) and ephemeral `uBytes` (G2).
60
+ * Returns null (fail-closed) if either point is malformed. The attribute string must match the one used
61
+ * at encapsulation (it is bound into the KDF).
62
+ */
63
+ function decapsulate(dA, attr, uBytes, salt) {
64
+ const U = (0, bls_1.g2FromBytes)(uBytes);
65
+ if (U === null)
66
+ return null;
67
+ // K_GT = e(d_A, U)
68
+ const kGt = (0, bls_1.pairing)(dA, U);
69
+ return kemKey((0, bls_1.gtToBytes)(kGt), salt, attr, uBytes);
70
+ }
71
+ //# sourceMappingURL=ibe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ibe.js","sourceRoot":"","sources":["../src/ibe.ts"],"names":[],"mappings":";;AA4CA,oCAEC;AAGD,gCAGC;AAcD,kCAUC;AAOD,kCAMC;AAzFD,+BAae;AAEf;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,YAAY,GAAG,sBAAsB,CAAC;AAU5C,kFAAkF;AAClF,SAAgB,YAAY,CAAC,CAAS;IACpC,OAAO,IAAA,eAAS,EAAC,IAAA,WAAK,EAAC,aAAO,EAAE,CAAC,CAAC,CAAC,CAAC;AACtC,CAAC;AAED,wFAAwF;AACxF,SAAgB,UAAU,CAAC,CAAS,EAAE,IAAY;IAChD,MAAM,EAAE,GAAG,IAAA,kBAAY,EAAC,IAAI,CAAC,CAAC;IAC9B,OAAO,IAAA,eAAS,EAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AACnC,CAAC;AAED,SAAS,MAAM,CAAC,OAAmB,EAAE,IAAgB,EAAE,IAAY,EAAE,MAAkB;IACrF,oGAAoG;IACpG,iFAAiF;IACjF,MAAM,IAAI,GAAG,GAAG,YAAY,IAAI,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;IACpF,OAAO,IAAA,WAAK,EAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AACpC,CAAC;AAED;;;;GAIG;AACH,SAAgB,WAAW,CAAC,SAAqB,EAAE,IAAY,EAAE,IAAgB;IAC/E,MAAM,IAAI,GAAG,IAAA,iBAAW,EAAC,SAAS,CAAC,CAAC;IACpC,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC/B,MAAM,EAAE,GAAG,IAAA,kBAAY,EAAC,IAAI,CAAC,CAAC;IAC9B,MAAM,CAAC,GAAG,IAAA,kBAAY,GAAE,CAAC;IACzB,MAAM,MAAM,GAAG,IAAA,eAAS,EAAC,IAAA,WAAK,EAAC,aAAO,EAAE,CAAC,CAAC,CAAC,CAAC;IAC5C,yBAAyB;IACzB,MAAM,GAAG,GAAG,IAAA,WAAK,EAAC,IAAA,aAAO,EAAC,EAAE,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IACxC,MAAM,GAAG,GAAG,MAAM,CAAC,IAAA,eAAS,EAAC,GAAG,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IACvD,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;AAC5B,CAAC;AAED;;;;GAIG;AACH,SAAgB,WAAW,CAAC,EAAW,EAAE,IAAY,EAAE,MAAkB,EAAE,IAAgB;IACzF,MAAM,CAAC,GAAG,IAAA,iBAAW,EAAC,MAAM,CAAC,CAAC;IAC9B,IAAI,CAAC,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC5B,mBAAmB;IACnB,MAAM,GAAG,GAAG,IAAA,aAAO,EAAC,EAAE,EAAE,CAAC,CAAC,CAAC;IAC3B,OAAO,MAAM,CAAC,IAAA,eAAS,EAAC,GAAG,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;AACpD,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @atlasauth/pca-abe — proof-carrying encryption.
3
+ *
4
+ * Ciphertext-policy attribute/policy-based encryption on BLS12-381 (a Boneh-Franklin IBE KEM composed
5
+ * over a monotone access structure by Shamir secret sharing, sealed with AES-256-GCM) so a tool payload
6
+ * or result decrypts ONLY for a holder whose PCA capability satisfies the policy. See `abe.ts` for the
7
+ * full construction and security property.
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';
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';
package/dist/index.js ADDED
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ /**
3
+ * @atlasauth/pca-abe — proof-carrying encryption.
4
+ *
5
+ * Ciphertext-policy attribute/policy-based encryption on BLS12-381 (a Boneh-Franklin IBE KEM composed
6
+ * over a monotone access structure by Shamir secret sharing, sealed with AES-256-GCM) so a tool payload
7
+ * or result decrypts ONLY for a holder whose PCA capability satisfies the policy. See `abe.ts` for the
8
+ * full construction and security property.
9
+ */
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;
12
+ var abe_1 = require("./abe");
13
+ Object.defineProperty(exports, "ABE_ALG", { enumerable: true, get: function () { return abe_1.ABE_ALG; } });
14
+ Object.defineProperty(exports, "PcaEncryptionError", { enumerable: true, get: function () { return abe_1.PcaEncryptionError; } });
15
+ Object.defineProperty(exports, "setup", { enumerable: true, get: function () { return abe_1.setup; } });
16
+ Object.defineProperty(exports, "keygenForAttributes", { enumerable: true, get: function () { return abe_1.keygenForAttributes; } });
17
+ Object.defineProperty(exports, "keygenForCapability", { enumerable: true, get: function () { return abe_1.keygenForCapability; } });
18
+ Object.defineProperty(exports, "encryptForPolicy", { enumerable: true, get: function () { return abe_1.encryptForPolicy; } });
19
+ Object.defineProperty(exports, "decrypt", { enumerable: true, get: function () { return abe_1.decrypt; } });
20
+ Object.defineProperty(exports, "decryptText", { enumerable: true, get: function () { return abe_1.decryptText; } });
21
+ Object.defineProperty(exports, "parseCiphertext", { enumerable: true, get: function () { return abe_1.parseCiphertext; } });
22
+ var pca_1 = require("./pca");
23
+ Object.defineProperty(exports, "encryptToolPayload", { enumerable: true, get: function () { return pca_1.encryptToolPayload; } });
24
+ Object.defineProperty(exports, "decryptWithCapability", { enumerable: true, get: function () { return pca_1.decryptWithCapability; } });
25
+ var policy_1 = require("./policy");
26
+ Object.defineProperty(exports, "normalizePolicy", { enumerable: true, get: function () { return policy_1.normalizePolicy; } });
27
+ Object.defineProperty(exports, "satisfies", { enumerable: true, get: function () { return policy_1.satisfies; } });
28
+ Object.defineProperty(exports, "policyAttributes", { enumerable: true, get: function () { return policy_1.policyAttributes; } });
29
+ Object.defineProperty(exports, "MAX_POLICY_NODES", { enumerable: true, get: function () { return policy_1.MAX_POLICY_NODES; } });
30
+ var attributes_1 = require("./attributes");
31
+ Object.defineProperty(exports, "Attr", { enumerable: true, get: function () { return attributes_1.Attr; } });
32
+ Object.defineProperty(exports, "capabilityAttributes", { enumerable: true, get: function () { return attributes_1.capabilityAttributes; } });
33
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;AAEH,6BAee;AAdb,8FAAA,OAAO,OAAA;AACP,yGAAA,kBAAkB,OAAA;AAClB,4FAAA,KAAK,OAAA;AACL,0GAAA,mBAAmB,OAAA;AACnB,0GAAA,mBAAmB,OAAA;AACnB,uGAAA,gBAAgB,OAAA;AAChB,8FAAA,OAAO,OAAA;AACP,kGAAA,WAAW,OAAA;AACX,sGAAA,eAAe,OAAA;AAQjB,6BAAyF;AAAhF,yGAAA,kBAAkB,OAAA;AAAE,4GAAA,qBAAqB,OAAA;AAElD,mCAQkB;AAPhB,yGAAA,eAAe,OAAA;AACf,mGAAA,SAAS,OAAA;AACT,0GAAA,gBAAgB,OAAA;AAChB,0GAAA,gBAAgB,OAAA;AAMlB,2CAA0D;AAAjD,kGAAA,IAAI,OAAA;AAAE,kHAAA,oBAAoB,OAAA"}
package/dist/pca.d.ts ADDED
@@ -0,0 +1,50 @@
1
+ import { type AbeCiphertext, type DecryptionKey, type MasterPublicKey } from './abe';
2
+ import type { Policy } from './policy';
3
+ /**
4
+ * PCA integration: proof-carrying encryption for tool payloads and results.
5
+ *
6
+ * A tool result is sealed under an ACCESS STRUCTURE over the SAME canonical attributes a PCA capability
7
+ * carries (verb / resource / scope / holder — see `attributes.ts`). Only an agent holding a decryption
8
+ * key issued (via `keygenForCapability`) for a capability whose authority SATISFIES that structure can
9
+ * read the payload. Confidentiality is thus bound to proven authority, not merely to a bearer key.
10
+ *
11
+ * HOW THIS COMPOSES WITH A PCActn
12
+ * A PCActn proves, to a resource server, that the agent's capability chain authorises a specific
13
+ * action (verb/resource under the signed policy envelope). The ABE decryption key handed to that agent
14
+ * is derived from the very SAME capability (`keygenForCapability(msk, capability)`). So:
15
+ *
16
+ * 1. The principal mints a capability (grant/attenuation) bounding the agent's authority.
17
+ * 2. The issuer derives an ABE key from that capability and gives it to the agent.
18
+ * 3. A tool/result is encrypted with `encryptToolPayload(mpk, policy, payload)`, where `policy`
19
+ * restates the authority required to read it (e.g. "holder X AND verb:read on this resource").
20
+ * 4. The agent proves the action with a PCActn (the server verifies the chain + predicates), AND can
21
+ * decrypt the payload ONLY because its capability-derived key satisfies the same policy.
22
+ *
23
+ * The decrypt gate and the PCActn admission gate are therefore keyed to ONE authority: an agent that
24
+ * cannot prove the action also cannot have been issued a key that decrypts its payload, because both
25
+ * derive from the same signed capability. Encryption adds CONFIDENTIALITY (a passive observer, or a
26
+ * holder of a different/weaker capability, learns nothing) on top of the PCActn's AUTHORISATION.
27
+ *
28
+ * SECURITY: as in `abe.ts` — confidentiality under Bilinear Diffie-Hellman (ROM), integrity under
29
+ * AES-256-GCM. Not a NIZK; collusion resistance is within a single issued key (one key per capability).
30
+ */
31
+ /** 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
+ export type DecryptedPayload = {
33
+ ok: true;
34
+ payload: unknown;
35
+ } | {
36
+ ok: false;
37
+ reason: string;
38
+ };
39
+ /**
40
+ * Encrypt a JSON-serialisable tool payload/result under `requiredCapabilityPolicy` — an access
41
+ * structure over capability attributes. Only a capability-derived key satisfying the policy can decrypt.
42
+ */
43
+ export declare function encryptToolPayload(mpk: MasterPublicKey, requiredCapabilityPolicy: Policy, payload: unknown): {
44
+ ciphertext: AbeCiphertext;
45
+ };
46
+ /**
47
+ * Decrypt a tool payload with a capability-derived key. Returns the parsed payload iff the key's
48
+ * authority satisfies the policy and the AEAD authenticates; otherwise a typed failure.
49
+ */
50
+ export declare function decryptWithCapability(key: DecryptionKey, ciphertext: unknown): DecryptedPayload;
package/dist/pca.js ADDED
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.encryptToolPayload = encryptToolPayload;
4
+ exports.decryptWithCapability = decryptWithCapability;
5
+ const abe_1 = require("./abe");
6
+ /**
7
+ * Encrypt a JSON-serialisable tool payload/result under `requiredCapabilityPolicy` — an access
8
+ * structure over capability attributes. Only a capability-derived key satisfying the policy can decrypt.
9
+ */
10
+ function encryptToolPayload(mpk, requiredCapabilityPolicy, payload) {
11
+ const json = JSON.stringify(payload ?? null);
12
+ return (0, abe_1.encryptForPolicy)(mpk, requiredCapabilityPolicy, json);
13
+ }
14
+ /**
15
+ * Decrypt a tool payload with a capability-derived key. Returns the parsed payload iff the key's
16
+ * authority satisfies the policy and the AEAD authenticates; otherwise a typed failure.
17
+ */
18
+ function decryptWithCapability(key, ciphertext) {
19
+ const pt = (0, abe_1.decrypt)(key, ciphertext);
20
+ if (pt === null)
21
+ return { ok: false, reason: 'capability does not satisfy the policy, or ciphertext is invalid' };
22
+ try {
23
+ return { ok: true, payload: JSON.parse(new TextDecoder().decode(pt)) };
24
+ }
25
+ catch {
26
+ return { ok: false, reason: 'decrypted payload is not valid JSON' };
27
+ }
28
+ }
29
+ //# sourceMappingURL=pca.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pca.js","sourceRoot":"","sources":["../src/pca.ts"],"names":[],"mappings":";;AA6CA,gDAOC;AAMD,sDAQC;AAlED,+BAMe;AAmCf;;;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"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Access structure over attributes — a MONOTONE boolean formula expressed as a threshold tree.
3
+ *
4
+ * - `{ attr }` leaf: the holder must own the decryption key for this attribute.
5
+ * - `{ allOf: [...] }` AND (n-of-n): every child subtree must be satisfied.
6
+ * - `{ anyOf: [...] }` OR (1-of-n): at least one child subtree.
7
+ * - `{ threshold: k, of: [...] }` k-of-n: at least k of the n child subtrees.
8
+ *
9
+ * Trees nest arbitrarily, so any monotone access structure (any AND/OR/threshold combination of
10
+ * attributes) is expressible. Negation is intentionally NOT supported: ABE access structures are
11
+ * monotone (you cannot grant decryption by LACKING an attribute).
12
+ */
13
+ export type Policy = {
14
+ attr: string;
15
+ } | {
16
+ allOf: Policy[];
17
+ } | {
18
+ anyOf: Policy[];
19
+ } | {
20
+ threshold: number;
21
+ of: Policy[];
22
+ };
23
+ /** Normalised internal form: every interior node is an explicit `t`-of-`n` threshold gate. */
24
+ export type ThresholdTree = {
25
+ kind: 'leaf';
26
+ attr: string;
27
+ } | {
28
+ kind: 'gate';
29
+ t: number;
30
+ of: ThresholdTree[];
31
+ };
32
+ export interface PolicyError {
33
+ ok: false;
34
+ reason: string;
35
+ }
36
+ export interface PolicyOk {
37
+ ok: true;
38
+ tree: ThresholdTree;
39
+ }
40
+ export type PolicyResult = PolicyOk | PolicyError;
41
+ /** Upper bound on total nodes in a policy tree (bounds work on untrusted input). */
42
+ export declare const MAX_POLICY_NODES = 1024;
43
+ /**
44
+ * Validate and normalise an access structure into a threshold tree. Fails closed (returns a reason)
45
+ * on any malformed node, empty gate, out-of-range threshold, or oversized tree.
46
+ */
47
+ export declare function normalizePolicy(policy: unknown): PolicyResult;
48
+ /**
49
+ * Pure, non-cryptographic satisfaction check: does the attribute SET satisfy the access structure?
50
+ * This is a convenience / test oracle. The real enforcement is cryptographic (a key lacking an
51
+ * attribute cannot recover that leaf's share); this just predicts the outcome.
52
+ */
53
+ export declare function satisfies(tree: ThresholdTree, attrs: ReadonlySet<string>): boolean;
54
+ /** Collect every attribute referenced anywhere in the tree (for diagnostics / key provisioning). */
55
+ export declare function policyAttributes(tree: ThresholdTree, into?: Set<string>): Set<string>;
package/dist/policy.js ADDED
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MAX_POLICY_NODES = void 0;
4
+ exports.normalizePolicy = normalizePolicy;
5
+ exports.satisfies = satisfies;
6
+ exports.policyAttributes = policyAttributes;
7
+ const wire_1 = require("./wire");
8
+ /** Upper bound on total nodes in a policy tree (bounds work on untrusted input). */
9
+ exports.MAX_POLICY_NODES = 1024;
10
+ /**
11
+ * Validate and normalise an access structure into a threshold tree. Fails closed (returns a reason)
12
+ * on any malformed node, empty gate, out-of-range threshold, or oversized tree.
13
+ */
14
+ function normalizePolicy(policy) {
15
+ let nodes = 0;
16
+ function walk(p, path) {
17
+ if (++nodes > exports.MAX_POLICY_NODES)
18
+ return { ok: false, reason: `policy too large (> ${exports.MAX_POLICY_NODES} nodes)` };
19
+ if (!(0, wire_1.isObject)(p))
20
+ return { ok: false, reason: `${path}: not an object` };
21
+ if ('attr' in p) {
22
+ if (!(0, wire_1.isString)(p.attr) || p.attr.length === 0)
23
+ return { ok: false, reason: `${path}: 'attr' must be a non-empty string` };
24
+ if ('allOf' in p || 'anyOf' in p || 'threshold' in p || 'of' in p) {
25
+ return { ok: false, reason: `${path}: a leaf must not mix 'attr' with a gate` };
26
+ }
27
+ return { kind: 'leaf', attr: p.attr };
28
+ }
29
+ const parseChildren = (raw, key) => {
30
+ if (!Array.isArray(raw) || raw.length === 0)
31
+ return { ok: false, reason: `${path}: '${key}' must be a non-empty array` };
32
+ const out = [];
33
+ for (let i = 0; i < raw.length; i++) {
34
+ const child = walk(raw[i], `${path}.${key}[${i}]`);
35
+ if ('ok' in child)
36
+ return child;
37
+ out.push(child);
38
+ }
39
+ return out;
40
+ };
41
+ if ('allOf' in p) {
42
+ const kids = parseChildren(p.allOf, 'allOf');
43
+ if ('ok' in kids)
44
+ return kids;
45
+ return { kind: 'gate', t: kids.length, of: kids };
46
+ }
47
+ if ('anyOf' in p) {
48
+ const kids = parseChildren(p.anyOf, 'anyOf');
49
+ if ('ok' in kids)
50
+ return kids;
51
+ return { kind: 'gate', t: 1, of: kids };
52
+ }
53
+ if ('threshold' in p) {
54
+ if (!(0, wire_1.isPosInt)(p.threshold))
55
+ return { ok: false, reason: `${path}: 'threshold' must be a positive integer` };
56
+ const kids = parseChildren(p.of, 'of');
57
+ if ('ok' in kids)
58
+ return kids;
59
+ if (p.threshold > kids.length) {
60
+ return { ok: false, reason: `${path}: threshold ${p.threshold} exceeds the number of branches (${kids.length})` };
61
+ }
62
+ return { kind: 'gate', t: p.threshold, of: kids };
63
+ }
64
+ return { ok: false, reason: `${path}: unknown policy node (expected attr/allOf/anyOf/threshold)` };
65
+ }
66
+ const tree = walk(policy, 'policy');
67
+ if ('ok' in tree)
68
+ return tree;
69
+ return { ok: true, tree };
70
+ }
71
+ /**
72
+ * Pure, non-cryptographic satisfaction check: does the attribute SET satisfy the access structure?
73
+ * This is a convenience / test oracle. The real enforcement is cryptographic (a key lacking an
74
+ * attribute cannot recover that leaf's share); this just predicts the outcome.
75
+ */
76
+ function satisfies(tree, attrs) {
77
+ if (tree.kind === 'leaf')
78
+ return attrs.has(tree.attr);
79
+ let met = 0;
80
+ for (const child of tree.of)
81
+ if (satisfies(child, attrs))
82
+ met++;
83
+ return met >= tree.t;
84
+ }
85
+ /** Collect every attribute referenced anywhere in the tree (for diagnostics / key provisioning). */
86
+ function policyAttributes(tree, into = new Set()) {
87
+ if (tree.kind === 'leaf')
88
+ into.add(tree.attr);
89
+ else
90
+ for (const child of tree.of)
91
+ policyAttributes(child, into);
92
+ return into;
93
+ }
94
+ //# sourceMappingURL=policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.js","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"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"}
package/dist/sss.d.ts ADDED
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Shamir secret sharing over the scalar field Z_r (prime r = the BLS12-381 subgroup order). This is the
3
+ * Linear Secret-Sharing Scheme (LSSS) that realises the monotone access structure: a `t`-of-`n` gate
4
+ * shares its secret along a degree `t-1` polynomial `f` with `f(0)` = the secret, handing child `i` the
5
+ * evaluation `f(i)`. Fewer than `t` shares leave the secret information-theoretically undetermined; any
6
+ * `t` (or more, consistent) shares reconstruct it by Lagrange interpolation at 0.
7
+ */
8
+ export interface Share {
9
+ /** Evaluation point (1-based branch index); never 0. */
10
+ x: bigint;
11
+ /** f(x) in Z_r. */
12
+ y: bigint;
13
+ }
14
+ /**
15
+ * Split `secret` into `n` shares with reconstruction threshold `t` (1 <= t <= n). Share `i` (1-based)
16
+ * is `f(i)` for a random degree `t-1` polynomial with `f(0) = secret`.
17
+ */
18
+ export declare function splitSecret(secret: bigint, t: number, n: number): Share[];
19
+ /**
20
+ * Reconstruct `f(0)` by Lagrange interpolation at 0 over Z_r. Requires at least one share and distinct,
21
+ * non-zero `x` coordinates. Given `>= t` consistent shares of a degree `t-1` sharing, this returns the
22
+ * original secret; with duplicate x's it returns null (fail-closed).
23
+ */
24
+ export declare function recoverSecret(shares: Share[]): bigint | null;
25
+ /** Convenience: a fresh random secret scalar together with its 32-byte big-endian encoding. */
26
+ export declare function randomSecret(): {
27
+ scalar: bigint;
28
+ bytes: Uint8Array;
29
+ };