@atlasauth/pca-abe 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/abe.d.ts +117 -0
- package/dist/abe.js +262 -0
- package/dist/abe.js.map +1 -0
- package/dist/aead.d.ts +12 -0
- package/dist/aead.js +42 -0
- package/dist/aead.js.map +1 -0
- package/dist/attributes.d.ts +30 -0
- package/dist/attributes.js +72 -0
- package/dist/attributes.js.map +1 -0
- package/dist/bls.d.ts +52 -0
- package/dist/bls.js +146 -0
- package/dist/bls.js.map +1 -0
- package/dist/ibe.d.ts +24 -0
- package/dist/ibe.js +71 -0
- package/dist/ibe.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +33 -0
- package/dist/index.js.map +1 -0
- package/dist/pca.d.ts +50 -0
- package/dist/pca.js +29 -0
- package/dist/pca.js.map +1 -0
- package/dist/policy.d.ts +55 -0
- package/dist/policy.js +94 -0
- package/dist/policy.js.map +1 -0
- package/dist/sss.d.ts +29 -0
- package/dist/sss.js +74 -0
- package/dist/sss.js.map +1 -0
- package/dist/wire.d.ts +14 -0
- package/dist/wire.js +53 -0
- package/dist/wire.js.map +1 -0
- package/package.json +32 -3
- package/README.md +0 -3
package/dist/abe.d.ts
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { type Capability } from '@atlasauth/pca';
|
|
2
|
+
import { type Policy } from './policy';
|
|
3
|
+
/**
|
|
4
|
+
* Proof-carrying encryption: Ciphertext-Policy attribute/policy-based encryption built from a
|
|
5
|
+
* Boneh-Franklin IBE KEM on BLS12-381, composed over a monotone access structure by Shamir
|
|
6
|
+
* secret-sharing (an LSSS), sealing the payload with AES-256-GCM.
|
|
7
|
+
*
|
|
8
|
+
* CONSTRUCTION
|
|
9
|
+
* setup() -> master key pair (s, P_pub = s*g2).
|
|
10
|
+
* keygen(attrs) -> one BF decryption key d_A = s*H1(A) per attribute A the holder owns.
|
|
11
|
+
* encrypt(policy, m) -> pick a random root secret S; share it down the policy's threshold tree with
|
|
12
|
+
* Shamir (AND = n-of-n, OR = 1-of-n, threshold = k-of-n); at each leaf attribute
|
|
13
|
+
* A, BF-encapsulate a fresh KEM key and XOR-mask that leaf's assigned share.
|
|
14
|
+
* The content-encryption key is HKDF(S); the payload is AES-256-GCM sealed with
|
|
15
|
+
* the whole KEM header as AAD.
|
|
16
|
+
* decrypt(key, ct) -> at every leaf the key owns, decapsulate -> unmask that share; interpolate each
|
|
17
|
+
* gate once >= t shares are recovered; recover S iff the key's attribute set
|
|
18
|
+
* satisfies the policy; derive the CEK and open the AEAD. Else fail (null).
|
|
19
|
+
*
|
|
20
|
+
* SECURITY PROPERTY (honest)
|
|
21
|
+
* Confidentiality holds under the Bilinear Diffie-Hellman assumption on BLS12-381 in the random-oracle
|
|
22
|
+
* model (standard BF-IBE), and the Shamir sharing is information-theoretic (fewer than `t` shares of a
|
|
23
|
+
* gate reveal nothing about its secret). A holder whose attribute set does NOT satisfy the policy
|
|
24
|
+
* cannot recover enough shares to reconstruct S and therefore cannot derive the CEK. Payload and header
|
|
25
|
+
* integrity are guaranteed by AES-256-GCM.
|
|
26
|
+
*
|
|
27
|
+
* This is NOT a proof-of-knowledge / NIZK: it binds confidentiality to POSSESSION of capability-derived
|
|
28
|
+
* attribute keys, not to a verified proof. Like any IBE-KEM-composed access structure (as opposed to a
|
|
29
|
+
* single monolithic CP-ABE with per-key randomisation), it is collusion-resistant only within a single
|
|
30
|
+
* issued key: two SEPARATELY issued keys under the same master, each holding part of the required
|
|
31
|
+
* attributes, could in principle pool their attribute keys. Atlas issues exactly one key per capability
|
|
32
|
+
* (`keygenForCapability`), and decryption is evaluated against that one key's attribute set — so the
|
|
33
|
+
* enforced statement is precisely "this capability's authority satisfies the policy".
|
|
34
|
+
*/
|
|
35
|
+
export declare const ABE_ALG = "bf-ibe-bls12381/lsss/aes-256-gcm";
|
|
36
|
+
export interface MasterPublicKey {
|
|
37
|
+
v: 1;
|
|
38
|
+
curve: 'bls12-381';
|
|
39
|
+
/** b64u compressed G2 point `P_pub = s * g2`. */
|
|
40
|
+
pPub: string;
|
|
41
|
+
}
|
|
42
|
+
export interface MasterSecretKey {
|
|
43
|
+
v: 1;
|
|
44
|
+
curve: 'bls12-381';
|
|
45
|
+
/** b64u 32-byte master secret scalar `s`. */
|
|
46
|
+
s: string;
|
|
47
|
+
}
|
|
48
|
+
export interface DecryptionKey {
|
|
49
|
+
v: 1;
|
|
50
|
+
curve: 'bls12-381';
|
|
51
|
+
/** The capability's bound holder key, when issued from a capability (informational). */
|
|
52
|
+
holder?: string;
|
|
53
|
+
/** attribute token -> b64u compressed G1 decryption key `d_A = s * H1(A)`. */
|
|
54
|
+
attrs: Record<string, string>;
|
|
55
|
+
}
|
|
56
|
+
/** The KEM header: the access structure realised as a tree of per-leaf encapsulations. */
|
|
57
|
+
export type KemTree = {
|
|
58
|
+
kind: 'leaf';
|
|
59
|
+
attr: string;
|
|
60
|
+
U: string;
|
|
61
|
+
wrap: string;
|
|
62
|
+
} | {
|
|
63
|
+
kind: 'gate';
|
|
64
|
+
t: number;
|
|
65
|
+
of: {
|
|
66
|
+
i: number;
|
|
67
|
+
sub: KemTree;
|
|
68
|
+
}[];
|
|
69
|
+
};
|
|
70
|
+
export interface AbeCiphertext {
|
|
71
|
+
v: 1;
|
|
72
|
+
alg: typeof ABE_ALG;
|
|
73
|
+
/** b64u HKDF salt (16 bytes) bound into every derived key and the CEK. */
|
|
74
|
+
salt: string;
|
|
75
|
+
/** The share-distribution tree (also the authenticated access structure). */
|
|
76
|
+
kem: KemTree;
|
|
77
|
+
/** b64u AES-256-GCM IV (12 bytes). */
|
|
78
|
+
iv: string;
|
|
79
|
+
/** b64u AES-256-GCM ciphertext. */
|
|
80
|
+
ct: string;
|
|
81
|
+
/** b64u AES-256-GCM tag (16 bytes). */
|
|
82
|
+
tag: string;
|
|
83
|
+
}
|
|
84
|
+
export declare class PcaEncryptionError extends Error {
|
|
85
|
+
constructor(message: string);
|
|
86
|
+
}
|
|
87
|
+
/** Generate a fresh master key pair. */
|
|
88
|
+
export declare function setup(): {
|
|
89
|
+
mpk: MasterPublicKey;
|
|
90
|
+
msk: MasterSecretKey;
|
|
91
|
+
};
|
|
92
|
+
/** Issue a decryption key for an explicit set of attribute tokens. */
|
|
93
|
+
export declare function keygenForAttributes(msk: MasterSecretKey, attrs: Iterable<string>): DecryptionKey;
|
|
94
|
+
/**
|
|
95
|
+
* Issue a decryption key BOUND to a PCA capability: its attributes are exactly those the (signed)
|
|
96
|
+
* capability carries — holder, and the verbs/resources/scopes of its policy envelope — optionally
|
|
97
|
+
* extended with explicit extra tokens. The key can decrypt only ciphertexts whose policy is satisfied
|
|
98
|
+
* by this capability's authority.
|
|
99
|
+
*/
|
|
100
|
+
export declare function keygenForCapability(msk: MasterSecretKey, capability: Capability, extraAttributes?: Iterable<string>): DecryptionKey;
|
|
101
|
+
/**
|
|
102
|
+
* Encrypt `plaintext` so that it decrypts only for a holder whose attribute set satisfies `policy`.
|
|
103
|
+
* Throws {@link PcaEncryptionError} on an invalid policy or master public key.
|
|
104
|
+
*/
|
|
105
|
+
export declare function encryptForPolicy(mpk: MasterPublicKey, policy: Policy, plaintext: Uint8Array | string): {
|
|
106
|
+
ciphertext: AbeCiphertext;
|
|
107
|
+
};
|
|
108
|
+
/** Validate an untrusted value as an {@link AbeCiphertext}; null (fail-closed) on any deviation. */
|
|
109
|
+
export declare function parseCiphertext(x: unknown): AbeCiphertext | null;
|
|
110
|
+
/**
|
|
111
|
+
* Decrypt. Returns the plaintext iff the key's attribute set satisfies the ciphertext's policy AND the
|
|
112
|
+
* AEAD authenticates; otherwise returns null (never throws). A key missing a required attribute cannot
|
|
113
|
+
* recover the root secret and therefore cannot derive the content-encryption key.
|
|
114
|
+
*/
|
|
115
|
+
export declare function decrypt(key: DecryptionKey, ciphertext: unknown): Uint8Array | null;
|
|
116
|
+
/** Like {@link decrypt} but returns the plaintext decoded as UTF-8 text, or null. */
|
|
117
|
+
export declare function decryptText(key: DecryptionKey, ciphertext: unknown): string | null;
|
package/dist/abe.js
ADDED
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PcaEncryptionError = exports.ABE_ALG = void 0;
|
|
4
|
+
exports.setup = setup;
|
|
5
|
+
exports.keygenForAttributes = keygenForAttributes;
|
|
6
|
+
exports.keygenForCapability = keygenForCapability;
|
|
7
|
+
exports.encryptForPolicy = encryptForPolicy;
|
|
8
|
+
exports.parseCiphertext = parseCiphertext;
|
|
9
|
+
exports.decrypt = decrypt;
|
|
10
|
+
exports.decryptText = decryptText;
|
|
11
|
+
const pca_1 = require("@atlasauth/pca");
|
|
12
|
+
const bls_1 = require("./bls");
|
|
13
|
+
const ibe_1 = require("./ibe");
|
|
14
|
+
const aead_1 = require("./aead");
|
|
15
|
+
const sss_1 = require("./sss");
|
|
16
|
+
const attributes_1 = require("./attributes");
|
|
17
|
+
const policy_1 = require("./policy");
|
|
18
|
+
const wire_1 = require("./wire");
|
|
19
|
+
const utils_1 = require("@noble/hashes/utils");
|
|
20
|
+
/**
|
|
21
|
+
* Proof-carrying encryption: Ciphertext-Policy attribute/policy-based encryption built from a
|
|
22
|
+
* Boneh-Franklin IBE KEM on BLS12-381, composed over a monotone access structure by Shamir
|
|
23
|
+
* secret-sharing (an LSSS), sealing the payload with AES-256-GCM.
|
|
24
|
+
*
|
|
25
|
+
* CONSTRUCTION
|
|
26
|
+
* setup() -> master key pair (s, P_pub = s*g2).
|
|
27
|
+
* keygen(attrs) -> one BF decryption key d_A = s*H1(A) per attribute A the holder owns.
|
|
28
|
+
* encrypt(policy, m) -> pick a random root secret S; share it down the policy's threshold tree with
|
|
29
|
+
* Shamir (AND = n-of-n, OR = 1-of-n, threshold = k-of-n); at each leaf attribute
|
|
30
|
+
* A, BF-encapsulate a fresh KEM key and XOR-mask that leaf's assigned share.
|
|
31
|
+
* The content-encryption key is HKDF(S); the payload is AES-256-GCM sealed with
|
|
32
|
+
* the whole KEM header as AAD.
|
|
33
|
+
* decrypt(key, ct) -> at every leaf the key owns, decapsulate -> unmask that share; interpolate each
|
|
34
|
+
* gate once >= t shares are recovered; recover S iff the key's attribute set
|
|
35
|
+
* satisfies the policy; derive the CEK and open the AEAD. Else fail (null).
|
|
36
|
+
*
|
|
37
|
+
* SECURITY PROPERTY (honest)
|
|
38
|
+
* Confidentiality holds under the Bilinear Diffie-Hellman assumption on BLS12-381 in the random-oracle
|
|
39
|
+
* model (standard BF-IBE), and the Shamir sharing is information-theoretic (fewer than `t` shares of a
|
|
40
|
+
* gate reveal nothing about its secret). A holder whose attribute set does NOT satisfy the policy
|
|
41
|
+
* cannot recover enough shares to reconstruct S and therefore cannot derive the CEK. Payload and header
|
|
42
|
+
* integrity are guaranteed by AES-256-GCM.
|
|
43
|
+
*
|
|
44
|
+
* This is NOT a proof-of-knowledge / NIZK: it binds confidentiality to POSSESSION of capability-derived
|
|
45
|
+
* attribute keys, not to a verified proof. Like any IBE-KEM-composed access structure (as opposed to a
|
|
46
|
+
* single monolithic CP-ABE with per-key randomisation), it is collusion-resistant only within a single
|
|
47
|
+
* issued key: two SEPARATELY issued keys under the same master, each holding part of the required
|
|
48
|
+
* attributes, could in principle pool their attribute keys. Atlas issues exactly one key per capability
|
|
49
|
+
* (`keygenForCapability`), and decryption is evaluated against that one key's attribute set — so the
|
|
50
|
+
* enforced statement is precisely "this capability's authority satisfies the policy".
|
|
51
|
+
*/
|
|
52
|
+
exports.ABE_ALG = 'bf-ibe-bls12381/lsss/aes-256-gcm';
|
|
53
|
+
const CEK_INFO = 'atlas-pca-abe/cek/v1';
|
|
54
|
+
const SALT_LEN = 16;
|
|
55
|
+
class PcaEncryptionError extends Error {
|
|
56
|
+
constructor(message) {
|
|
57
|
+
super(message);
|
|
58
|
+
this.name = 'PcaEncryptionError';
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
exports.PcaEncryptionError = PcaEncryptionError;
|
|
62
|
+
// ---- setup / keygen ---------------------------------------------------------------------------
|
|
63
|
+
/** Generate a fresh master key pair. */
|
|
64
|
+
function setup() {
|
|
65
|
+
const { scalar, bytes } = (0, sss_1.randomSecret)();
|
|
66
|
+
return {
|
|
67
|
+
msk: { v: 1, curve: 'bls12-381', s: (0, wire_1.b64u)(bytes) },
|
|
68
|
+
mpk: { v: 1, curve: 'bls12-381', pPub: (0, wire_1.b64u)((0, ibe_1.masterPublic)(scalar)) },
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function mskScalar(msk) {
|
|
72
|
+
const bytes = (0, wire_1.unb64u)(msk?.s);
|
|
73
|
+
const s = bytes === null ? null : (0, bls_1.bytesToScalar)(bytes);
|
|
74
|
+
if (s === null || s === 0n)
|
|
75
|
+
throw new PcaEncryptionError('invalid master secret key');
|
|
76
|
+
return s;
|
|
77
|
+
}
|
|
78
|
+
/** Issue a decryption key for an explicit set of attribute tokens. */
|
|
79
|
+
function keygenForAttributes(msk, attrs) {
|
|
80
|
+
const s = mskScalar(msk);
|
|
81
|
+
const out = {};
|
|
82
|
+
for (const a of attrs) {
|
|
83
|
+
if (typeof a === 'string' && a.length > 0)
|
|
84
|
+
out[a] = (0, wire_1.b64u)((0, ibe_1.keygenAttr)(s, a));
|
|
85
|
+
}
|
|
86
|
+
return { v: 1, curve: 'bls12-381', attrs: out };
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Issue a decryption key BOUND to a PCA capability: its attributes are exactly those the (signed)
|
|
90
|
+
* capability carries — holder, and the verbs/resources/scopes of its policy envelope — optionally
|
|
91
|
+
* extended with explicit extra tokens. The key can decrypt only ciphertexts whose policy is satisfied
|
|
92
|
+
* by this capability's authority.
|
|
93
|
+
*/
|
|
94
|
+
function keygenForCapability(msk, capability, extraAttributes = []) {
|
|
95
|
+
const attrs = (0, attributes_1.capabilityAttributes)(capability);
|
|
96
|
+
for (const a of extraAttributes)
|
|
97
|
+
if (typeof a === 'string' && a.length > 0)
|
|
98
|
+
attrs.add(a);
|
|
99
|
+
const key = keygenForAttributes(msk, attrs);
|
|
100
|
+
if (typeof capability.holder === 'string')
|
|
101
|
+
key.holder = capability.holder;
|
|
102
|
+
return key;
|
|
103
|
+
}
|
|
104
|
+
// ---- encrypt ----------------------------------------------------------------------------------
|
|
105
|
+
function distribute(mpkPub, node, nodeSecret, salt) {
|
|
106
|
+
if (node.kind === 'leaf') {
|
|
107
|
+
const enc = (0, ibe_1.encapsulate)(mpkPub, node.attr, salt);
|
|
108
|
+
if (enc === null)
|
|
109
|
+
throw new PcaEncryptionError('invalid master public key');
|
|
110
|
+
const wrap = (0, wire_1.xorBytes)((0, bls_1.scalarToBytes)(nodeSecret), enc.key);
|
|
111
|
+
if (wrap === null)
|
|
112
|
+
throw new PcaEncryptionError('internal: wrap length mismatch');
|
|
113
|
+
return { kind: 'leaf', attr: node.attr, U: (0, wire_1.b64u)(enc.U), wrap: (0, wire_1.b64u)(wrap) };
|
|
114
|
+
}
|
|
115
|
+
const shares = (0, sss_1.splitSecret)(nodeSecret, node.t, node.of.length);
|
|
116
|
+
const of = [];
|
|
117
|
+
for (let idx = 0; idx < node.of.length; idx++) {
|
|
118
|
+
const child = node.of[idx];
|
|
119
|
+
const share = shares[idx];
|
|
120
|
+
if (child === undefined || share === undefined)
|
|
121
|
+
throw new PcaEncryptionError('internal: share/child mismatch');
|
|
122
|
+
of.push({ i: Number(share.x), sub: distribute(mpkPub, child, share.y, salt) });
|
|
123
|
+
}
|
|
124
|
+
return { kind: 'gate', t: node.t, of };
|
|
125
|
+
}
|
|
126
|
+
function aad(c) {
|
|
127
|
+
return (0, pca_1.canonicalBytes)({ v: c.v, alg: c.alg, salt: c.salt, kem: c.kem });
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Encrypt `plaintext` so that it decrypts only for a holder whose attribute set satisfies `policy`.
|
|
131
|
+
* Throws {@link PcaEncryptionError} on an invalid policy or master public key.
|
|
132
|
+
*/
|
|
133
|
+
function encryptForPolicy(mpk, policy, plaintext) {
|
|
134
|
+
const norm = (0, policy_1.normalizePolicy)(policy);
|
|
135
|
+
if (!norm.ok)
|
|
136
|
+
throw new PcaEncryptionError(`invalid policy: ${norm.reason}`);
|
|
137
|
+
const mpkPub = (0, wire_1.unb64u)(mpk?.pPub);
|
|
138
|
+
if (mpkPub === null)
|
|
139
|
+
throw new PcaEncryptionError('invalid master public key');
|
|
140
|
+
const salt = new Uint8Array((0, utils_1.randomBytes)(SALT_LEN));
|
|
141
|
+
const { scalar: rootSecret, bytes: rootBytes } = (0, sss_1.randomSecret)();
|
|
142
|
+
const kem = distribute(mpkPub, norm.tree, rootSecret, salt);
|
|
143
|
+
const header = { v: 1, alg: exports.ABE_ALG, salt: (0, wire_1.b64u)(salt), kem };
|
|
144
|
+
const cek = (0, bls_1.kdf32)(rootBytes, salt, CEK_INFO);
|
|
145
|
+
const pt = typeof plaintext === 'string' ? new TextEncoder().encode(plaintext) : plaintext;
|
|
146
|
+
const sealed = (0, aead_1.seal)(cek, pt, aad(header));
|
|
147
|
+
return {
|
|
148
|
+
ciphertext: { ...header, iv: (0, wire_1.b64u)(sealed.iv), ct: (0, wire_1.b64u)(sealed.ct), tag: (0, wire_1.b64u)(sealed.tag) },
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
// ---- decrypt ----------------------------------------------------------------------------------
|
|
152
|
+
function parseKemTree(x, depth) {
|
|
153
|
+
if (depth > 64 || !(0, wire_1.isObject)(x))
|
|
154
|
+
return null;
|
|
155
|
+
if (x.kind === 'leaf') {
|
|
156
|
+
if (!(0, wire_1.isString)(x.attr) || !(0, wire_1.isString)(x.U) || !(0, wire_1.isString)(x.wrap))
|
|
157
|
+
return null;
|
|
158
|
+
if ((0, wire_1.unb64u)(x.U) === null || (0, wire_1.unb64u)(x.wrap) === null)
|
|
159
|
+
return null;
|
|
160
|
+
return { kind: 'leaf', attr: x.attr, U: x.U, wrap: x.wrap };
|
|
161
|
+
}
|
|
162
|
+
if (x.kind === 'gate') {
|
|
163
|
+
if (!(0, wire_1.isPosInt)(x.t) || !Array.isArray(x.of) || x.of.length === 0)
|
|
164
|
+
return null;
|
|
165
|
+
if (x.t > x.of.length)
|
|
166
|
+
return null;
|
|
167
|
+
const of = [];
|
|
168
|
+
for (const branch of x.of) {
|
|
169
|
+
if (!(0, wire_1.isObject)(branch) || !(0, wire_1.isPosInt)(branch.i))
|
|
170
|
+
return null;
|
|
171
|
+
const sub = parseKemTree(branch.sub, depth + 1);
|
|
172
|
+
if (sub === null)
|
|
173
|
+
return null;
|
|
174
|
+
of.push({ i: branch.i, sub });
|
|
175
|
+
}
|
|
176
|
+
return { kind: 'gate', t: x.t, of };
|
|
177
|
+
}
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
/** Validate an untrusted value as an {@link AbeCiphertext}; null (fail-closed) on any deviation. */
|
|
181
|
+
function parseCiphertext(x) {
|
|
182
|
+
if (!(0, wire_1.isObject)(x) || x.v !== 1 || x.alg !== exports.ABE_ALG)
|
|
183
|
+
return null;
|
|
184
|
+
if (!(0, wire_1.isString)(x.salt) || !(0, wire_1.isString)(x.iv) || !(0, wire_1.isString)(x.ct) || !(0, wire_1.isString)(x.tag))
|
|
185
|
+
return null;
|
|
186
|
+
if ((0, wire_1.unb64u)(x.salt) === null || (0, wire_1.unb64u)(x.iv) === null || (0, wire_1.unb64u)(x.ct) === null || (0, wire_1.unb64u)(x.tag) === null)
|
|
187
|
+
return null;
|
|
188
|
+
const kem = parseKemTree(x.kem, 0);
|
|
189
|
+
if (kem === null)
|
|
190
|
+
return null;
|
|
191
|
+
return { v: 1, alg: exports.ABE_ALG, salt: x.salt, kem, iv: x.iv, ct: x.ct, tag: x.tag };
|
|
192
|
+
}
|
|
193
|
+
function recover(node, keys, salt) {
|
|
194
|
+
if (node.kind === 'leaf') {
|
|
195
|
+
const dA = keys.get(node.attr);
|
|
196
|
+
if (dA === undefined)
|
|
197
|
+
return null; // the key does not own this attribute: nothing to recover here.
|
|
198
|
+
const uBytes = (0, wire_1.unb64u)(node.U);
|
|
199
|
+
const wrapBytes = (0, wire_1.unb64u)(node.wrap);
|
|
200
|
+
if (uBytes === null || wrapBytes === null)
|
|
201
|
+
return null;
|
|
202
|
+
const kemKey = (0, ibe_1.decapsulate)(dA, node.attr, uBytes, salt);
|
|
203
|
+
if (kemKey === null)
|
|
204
|
+
return null;
|
|
205
|
+
const shareBytes = (0, wire_1.xorBytes)(wrapBytes, kemKey);
|
|
206
|
+
if (shareBytes === null)
|
|
207
|
+
return null;
|
|
208
|
+
return (0, bls_1.bytesToScalar)(shareBytes);
|
|
209
|
+
}
|
|
210
|
+
const shares = [];
|
|
211
|
+
for (const branch of node.of) {
|
|
212
|
+
const y = recover(branch.sub, keys, salt);
|
|
213
|
+
if (y !== null)
|
|
214
|
+
shares.push({ x: BigInt(branch.i), y });
|
|
215
|
+
if (shares.length >= node.t)
|
|
216
|
+
break; // enough branches recovered; no need to decrypt more.
|
|
217
|
+
}
|
|
218
|
+
if (shares.length < node.t)
|
|
219
|
+
return null;
|
|
220
|
+
return (0, sss_1.recoverSecret)(shares);
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Decrypt. Returns the plaintext iff the key's attribute set satisfies the ciphertext's policy AND the
|
|
224
|
+
* AEAD authenticates; otherwise returns null (never throws). A key missing a required attribute cannot
|
|
225
|
+
* recover the root secret and therefore cannot derive the content-encryption key.
|
|
226
|
+
*/
|
|
227
|
+
function decrypt(key, ciphertext) {
|
|
228
|
+
const ct = parseCiphertext(ciphertext);
|
|
229
|
+
if (ct === null)
|
|
230
|
+
return null;
|
|
231
|
+
if (!(0, wire_1.isObject)(key) || !(0, wire_1.isObject)(key.attrs))
|
|
232
|
+
return null;
|
|
233
|
+
const salt = (0, wire_1.unb64u)(ct.salt);
|
|
234
|
+
const iv = (0, wire_1.unb64u)(ct.iv);
|
|
235
|
+
const body = (0, wire_1.unb64u)(ct.ct);
|
|
236
|
+
const tag = (0, wire_1.unb64u)(ct.tag);
|
|
237
|
+
if (salt === null || iv === null || body === null || tag === null)
|
|
238
|
+
return null;
|
|
239
|
+
// Decode the attribute decryption keys we hold (skip any malformed point: fail-closed per attribute).
|
|
240
|
+
const keys = new Map();
|
|
241
|
+
for (const [attr, enc] of Object.entries(key.attrs)) {
|
|
242
|
+
const bytes = (0, wire_1.unb64u)(enc);
|
|
243
|
+
if (bytes === null)
|
|
244
|
+
continue;
|
|
245
|
+
const pt = (0, bls_1.g1FromBytes)(bytes);
|
|
246
|
+
if (pt !== null)
|
|
247
|
+
keys.set(attr, pt);
|
|
248
|
+
}
|
|
249
|
+
const rootSecret = recover(ct.kem, keys, salt);
|
|
250
|
+
if (rootSecret === null)
|
|
251
|
+
return null; // attribute set does not satisfy the policy.
|
|
252
|
+
const cek = (0, bls_1.kdf32)((0, bls_1.scalarToBytes)(rootSecret), salt, CEK_INFO);
|
|
253
|
+
// The AEAD is the final integrity gate: a wrong reconstructed secret (cross-master key / tamper) or a
|
|
254
|
+
// tampered payload/header yields a null here.
|
|
255
|
+
return (0, aead_1.open)(cek, { iv, ct: body, tag }, aad(ct));
|
|
256
|
+
}
|
|
257
|
+
/** Like {@link decrypt} but returns the plaintext decoded as UTF-8 text, or null. */
|
|
258
|
+
function decryptText(key, ciphertext) {
|
|
259
|
+
const pt = decrypt(key, ciphertext);
|
|
260
|
+
return pt === null ? null : new TextDecoder().decode(pt);
|
|
261
|
+
}
|
|
262
|
+
//# sourceMappingURL=abe.js.map
|
package/dist/abe.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"abe.js","sourceRoot":"","sources":["../src/abe.ts"],"names":[],"mappings":"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"}
|
package/dist/aead.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface Sealed {
|
|
2
|
+
iv: Uint8Array;
|
|
3
|
+
ct: Uint8Array;
|
|
4
|
+
tag: Uint8Array;
|
|
5
|
+
}
|
|
6
|
+
/** AES-256-GCM seal. `key` must be 32 bytes. A fresh random 96-bit IV is used per call. */
|
|
7
|
+
export declare function seal(key: Uint8Array, plaintext: Uint8Array, aad: Uint8Array): Sealed;
|
|
8
|
+
/**
|
|
9
|
+
* AES-256-GCM open. Returns the plaintext, or null (never throws) if the key is wrong, the tag/AAD does
|
|
10
|
+
* not authenticate, or any field is malformed.
|
|
11
|
+
*/
|
|
12
|
+
export declare function open(key: Uint8Array, sealed: Sealed, aad: Uint8Array): Uint8Array | null;
|
package/dist/aead.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.seal = seal;
|
|
4
|
+
exports.open = open;
|
|
5
|
+
const node_crypto_1 = require("node:crypto");
|
|
6
|
+
/**
|
|
7
|
+
* Authenticated symmetric encryption: AES-256-GCM (via `node:crypto`). The content-encryption key is
|
|
8
|
+
* derived from the ABE/KEM layer; this module only turns a 32-byte key into a sealed payload and back.
|
|
9
|
+
* The ABE header is passed as Additional Authenticated Data so any tampering with the policy or the KEM
|
|
10
|
+
* ciphertext — not just the payload — fails the GCM tag.
|
|
11
|
+
*/
|
|
12
|
+
const IV_LEN = 12;
|
|
13
|
+
const TAG_LEN = 16;
|
|
14
|
+
/** AES-256-GCM seal. `key` must be 32 bytes. A fresh random 96-bit IV is used per call. */
|
|
15
|
+
function seal(key, plaintext, aad) {
|
|
16
|
+
if (key.length !== 32)
|
|
17
|
+
throw new RangeError('aead.seal: key must be 32 bytes');
|
|
18
|
+
const iv = new Uint8Array((0, node_crypto_1.randomBytes)(IV_LEN));
|
|
19
|
+
const cipher = (0, node_crypto_1.createCipheriv)('aes-256-gcm', key, iv);
|
|
20
|
+
cipher.setAAD(aad);
|
|
21
|
+
const ct = new Uint8Array(Buffer.concat([cipher.update(plaintext), cipher.final()]));
|
|
22
|
+
const tag = new Uint8Array(cipher.getAuthTag());
|
|
23
|
+
return { iv, ct, tag };
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* AES-256-GCM open. Returns the plaintext, or null (never throws) if the key is wrong, the tag/AAD does
|
|
27
|
+
* not authenticate, or any field is malformed.
|
|
28
|
+
*/
|
|
29
|
+
function open(key, sealed, aad) {
|
|
30
|
+
if (key.length !== 32 || sealed.iv.length !== IV_LEN || sealed.tag.length !== TAG_LEN)
|
|
31
|
+
return null;
|
|
32
|
+
try {
|
|
33
|
+
const decipher = (0, node_crypto_1.createDecipheriv)('aes-256-gcm', key, sealed.iv);
|
|
34
|
+
decipher.setAAD(aad);
|
|
35
|
+
decipher.setAuthTag(sealed.tag);
|
|
36
|
+
return new Uint8Array(Buffer.concat([decipher.update(sealed.ct), decipher.final()]));
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=aead.js.map
|
package/dist/aead.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aead.js","sourceRoot":"","sources":["../src/aead.ts"],"names":[],"mappings":";;AAmBA,oBAQC;AAMD,oBAUC;AA3CD,6CAA4E;AAE5E;;;;;GAKG;AAEH,MAAM,MAAM,GAAG,EAAE,CAAC;AAClB,MAAM,OAAO,GAAG,EAAE,CAAC;AAQnB,2FAA2F;AAC3F,SAAgB,IAAI,CAAC,GAAe,EAAE,SAAqB,EAAE,GAAe;IAC1E,IAAI,GAAG,CAAC,MAAM,KAAK,EAAE;QAAE,MAAM,IAAI,UAAU,CAAC,iCAAiC,CAAC,CAAC;IAC/E,MAAM,EAAE,GAAG,IAAI,UAAU,CAAC,IAAA,yBAAW,EAAC,MAAM,CAAC,CAAC,CAAC;IAC/C,MAAM,MAAM,GAAG,IAAA,4BAAc,EAAC,aAAa,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;IACtD,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACnB,MAAM,EAAE,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;IACrF,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;IAChD,OAAO,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC;AACzB,CAAC;AAED;;;GAGG;AACH,SAAgB,IAAI,CAAC,GAAe,EAAE,MAAc,EAAE,GAAe;IACnE,IAAI,GAAG,CAAC,MAAM,KAAK,EAAE,IAAI,MAAM,CAAC,EAAE,CAAC,MAAM,KAAK,MAAM,IAAI,MAAM,CAAC,GAAG,CAAC,MAAM,KAAK,OAAO;QAAE,OAAO,IAAI,CAAC;IACnG,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,IAAA,8BAAgB,EAAC,aAAa,EAAE,GAAG,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;QACjE,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACrB,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAChC,OAAO,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;IACvF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type Capability } from '@atlasauth/pca';
|
|
2
|
+
/**
|
|
3
|
+
* Canonical attribute strings derived from a real PCA capability (see `@atlasauth/pca`'s `Capability`
|
|
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 BF-IBE decryption
|
|
6
|
+
* key per token the capability carries.
|
|
7
|
+
*
|
|
8
|
+
* Four kinds are derived, matching the capability's authority surface (verb / resource / scopes /
|
|
9
|
+
* holder):
|
|
10
|
+
* - `holder:<b64u key>` the key the capability is bound to (`capability.holder`),
|
|
11
|
+
* - `verb:<v>` every literal verb named in the signed envelope's predicates,
|
|
12
|
+
* - `resource:<r>` every resource matcher named in those predicates,
|
|
13
|
+
* - `scope:<s>` every scope carried in a `{ type:'scope', value }` or
|
|
14
|
+
* `{ type:'scopes', values:[...] }` caveat.
|
|
15
|
+
*
|
|
16
|
+
* Because the envelope and caveats are SIGNED into the capability (and attenuation is append-only), the
|
|
17
|
+
* attribute set a capability yields cannot be widened by a holder — it is exactly what the principal
|
|
18
|
+
* authorised.
|
|
19
|
+
*/
|
|
20
|
+
export declare const Attr: {
|
|
21
|
+
readonly holder: (key: string) => string;
|
|
22
|
+
readonly verb: (v: string) => string;
|
|
23
|
+
readonly resource: (r: string) => string;
|
|
24
|
+
readonly scope: (s: string) => string;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Derive the canonical attribute set a capability possesses. Deterministic and total (never throws): a
|
|
28
|
+
* capability with no signed envelope still yields its `holder:` attribute (plus any scope caveats).
|
|
29
|
+
*/
|
|
30
|
+
export declare function capabilityAttributes(cap: Capability): Set<string>;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Attr = void 0;
|
|
4
|
+
exports.capabilityAttributes = capabilityAttributes;
|
|
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
|
+
exports.Attr = {
|
|
25
|
+
holder: (key) => `holder:${key}`,
|
|
26
|
+
verb: (v) => `verb:${v}`,
|
|
27
|
+
resource: (r) => `resource:${r}`,
|
|
28
|
+
scope: (s) => `scope:${s}`,
|
|
29
|
+
};
|
|
30
|
+
function addVerb(out, verb) {
|
|
31
|
+
if (typeof verb === 'string')
|
|
32
|
+
out.add(exports.Attr.verb(verb));
|
|
33
|
+
else if (Array.isArray(verb))
|
|
34
|
+
for (const v of verb)
|
|
35
|
+
if (typeof v === 'string')
|
|
36
|
+
out.add(exports.Attr.verb(v));
|
|
37
|
+
}
|
|
38
|
+
function addScopes(out, caveats) {
|
|
39
|
+
for (const cv of caveats) {
|
|
40
|
+
if (cv.type === 'scope' && typeof cv.value === 'string')
|
|
41
|
+
out.add(exports.Attr.scope(cv.value));
|
|
42
|
+
if (cv.type === 'scopes' && Array.isArray(cv.values)) {
|
|
43
|
+
for (const s of cv.values)
|
|
44
|
+
if (typeof s === 'string')
|
|
45
|
+
out.add(exports.Attr.scope(s));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Derive the canonical attribute set a capability possesses. Deterministic and total (never throws): a
|
|
51
|
+
* capability with no signed envelope still yields its `holder:` attribute (plus any scope caveats).
|
|
52
|
+
*/
|
|
53
|
+
function capabilityAttributes(cap) {
|
|
54
|
+
const out = new Set();
|
|
55
|
+
if (typeof cap.holder === 'string' && cap.holder.length > 0)
|
|
56
|
+
out.add(exports.Attr.holder(cap.holder));
|
|
57
|
+
if (Array.isArray(cap.caveats))
|
|
58
|
+
addScopes(out, cap.caveats);
|
|
59
|
+
const env = (0, pca_1.readEnvelope)(cap);
|
|
60
|
+
if (env !== null && Array.isArray(env.predicates)) {
|
|
61
|
+
for (const p of env.predicates) {
|
|
62
|
+
if (p === null || typeof p !== 'object')
|
|
63
|
+
continue;
|
|
64
|
+
addVerb(out, p.verb);
|
|
65
|
+
const r = p.resource;
|
|
66
|
+
if (typeof r === 'string')
|
|
67
|
+
out.add(exports.Attr.resource(r));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return out;
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=attributes.js.map
|
|
@@ -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;
|