@pulse-compute/crypto 0.0.0 → 1.0.0-beta.2

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,273 @@
1
+ import { CRYPTO_RESOURCE_LIMITS, CRYPTO_VERIFICATION_STATUSES, } from '../contracts.js';
2
+ import { copyBytes, exactDataProperties, isOrdinaryObject, ownDataProperty, } from './data.js';
3
+ const REQUEST_KEYS = new Set(['algorithm', 'key', 'data', 'tag']);
4
+ const KEY_KEYS = new Set(['type', 'bytes']);
5
+ const SIGNATURE_REQUEST_KEYS = new Set(['algorithm', 'key', 'data', 'signature']);
6
+ const P256_KEY_KEYS = new Set(['type', 'bytes']);
7
+ const JOSE_REQUEST_KEYS = new Set(['key', 'data', 'signature']);
8
+ const JOSE_KEY_KEYS = new Set(['x', 'y']);
9
+ const BASE64URL = /^[A-Za-z0-9_-]+$/;
10
+ const P256_ORDER = Uint8Array.from([
11
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
12
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
13
+ 0xbc, 0xe6, 0xfa, 0xad, 0xa7, 0x17, 0x9e, 0x84,
14
+ 0xf3, 0xb9, 0xca, 0xc2, 0xfc, 0x63, 0x25, 0x51,
15
+ ]);
16
+ const RESULTS = Object.freeze(Object.fromEntries(CRYPTO_VERIFICATION_STATUSES.map((status) => [
17
+ status,
18
+ Object.freeze({ status }),
19
+ ])));
20
+ export function verificationResult(status) {
21
+ return RESULTS[status];
22
+ }
23
+ function invalidInput() {
24
+ return Object.freeze({
25
+ ok: false,
26
+ result: verificationResult('invalid-input'),
27
+ });
28
+ }
29
+ function invalidKey() {
30
+ return Object.freeze({
31
+ ok: false,
32
+ result: verificationResult('invalid-key'),
33
+ });
34
+ }
35
+ function invalidSignatureInput() {
36
+ return Object.freeze({
37
+ ok: false,
38
+ result: verificationResult('invalid-input'),
39
+ });
40
+ }
41
+ function invalidSignatureKey() {
42
+ return Object.freeze({
43
+ ok: false,
44
+ result: verificationResult('invalid-key'),
45
+ });
46
+ }
47
+ function compareBigEndian(left, right) {
48
+ for (let index = 0; index < left.byteLength; index += 1) {
49
+ if (left[index] < right[index])
50
+ return -1;
51
+ if (left[index] > right[index])
52
+ return 1;
53
+ }
54
+ return 0;
55
+ }
56
+ function validP256Scalar(value) {
57
+ let nonZero = false;
58
+ for (const byte of value)
59
+ nonZero ||= byte !== 0;
60
+ return nonZero && compareBigEndian(value, P256_ORDER) < 0;
61
+ }
62
+ function validEs256Signature(signature) {
63
+ return signature.byteLength === CRYPTO_RESOURCE_LIMITS.es256SignatureBytes
64
+ && validP256Scalar(signature.subarray(0, 32))
65
+ && validP256Scalar(signature.subarray(32, 64));
66
+ }
67
+ function decodeCanonicalBase64url(value, expectedBytes) {
68
+ if (typeof value !== 'string'
69
+ || value.length === 0
70
+ || value.includes('=')
71
+ || !BASE64URL.test(value)
72
+ || value.length % 4 === 1)
73
+ return undefined;
74
+ const padded = value.replace(/-/g, '+').replace(/_/g, '/')
75
+ + '='.repeat((4 - value.length % 4) % 4);
76
+ let binary;
77
+ try {
78
+ binary = atob(padded);
79
+ }
80
+ catch {
81
+ return undefined;
82
+ }
83
+ const bytes = Uint8Array.from(binary, (character) => character.charCodeAt(0));
84
+ if (bytes.byteLength !== expectedBytes)
85
+ return undefined;
86
+ let canonical = '';
87
+ for (const byte of bytes)
88
+ canonical += String.fromCharCode(byte);
89
+ canonical = btoa(canonical)
90
+ .replace(/\+/g, '-')
91
+ .replace(/\//g, '_')
92
+ .replace(/=+$/u, '');
93
+ return canonical === value ? bytes : undefined;
94
+ }
95
+ export function normalizeMacVerifyRequest(value) {
96
+ if (!isOrdinaryObject(value) || !exactDataProperties(value, REQUEST_KEYS)) {
97
+ return invalidInput();
98
+ }
99
+ const algorithm = ownDataProperty(value, 'algorithm').value;
100
+ if (algorithm !== 'HS256')
101
+ return invalidInput();
102
+ const keyValue = ownDataProperty(value, 'key').value;
103
+ if (!isOrdinaryObject(keyValue) || !exactDataProperties(keyValue, KEY_KEYS)) {
104
+ return invalidKey();
105
+ }
106
+ if (ownDataProperty(keyValue, 'type').value !== 'hmac-key-bytes') {
107
+ return invalidKey();
108
+ }
109
+ const keyBytes = copyBytes(ownDataProperty(keyValue, 'bytes').value);
110
+ if (!keyBytes
111
+ || keyBytes.byteLength < CRYPTO_RESOURCE_LIMITS.hmacKeyBytesMinimum
112
+ || keyBytes.byteLength > CRYPTO_RESOURCE_LIMITS.hmacKeyBytesMaximum) {
113
+ return invalidKey();
114
+ }
115
+ const data = copyBytes(ownDataProperty(value, 'data').value);
116
+ const tag = copyBytes(ownDataProperty(value, 'tag').value);
117
+ if (!data
118
+ || data.byteLength > CRYPTO_RESOURCE_LIMITS.macDataBytesMaximum
119
+ || !tag
120
+ || tag.byteLength !== CRYPTO_RESOURCE_LIMITS.hs256TagBytes) {
121
+ return invalidInput();
122
+ }
123
+ return Object.freeze({
124
+ ok: true,
125
+ request: Object.freeze({
126
+ algorithm,
127
+ key: Object.freeze({
128
+ type: 'hmac-key-bytes',
129
+ bytes: keyBytes,
130
+ }),
131
+ data,
132
+ tag,
133
+ }),
134
+ });
135
+ }
136
+ export function normalizeSignatureVerifyRequest(value) {
137
+ if (!isOrdinaryObject(value)
138
+ || !exactDataProperties(value, SIGNATURE_REQUEST_KEYS))
139
+ return invalidSignatureInput();
140
+ if (ownDataProperty(value, 'algorithm').value !== 'ES256') {
141
+ return invalidSignatureInput();
142
+ }
143
+ const keyValue = ownDataProperty(value, 'key').value;
144
+ if (!isOrdinaryObject(keyValue)
145
+ || !exactDataProperties(keyValue, P256_KEY_KEYS)
146
+ || ownDataProperty(keyValue, 'type').value !== 'p256-public-key-bytes')
147
+ return invalidSignatureKey();
148
+ const keyBytes = copyBytes(ownDataProperty(keyValue, 'bytes').value);
149
+ if (!keyBytes
150
+ || keyBytes.byteLength !== CRYPTO_RESOURCE_LIMITS.es256PublicKeyBytes)
151
+ return invalidSignatureKey();
152
+ const data = copyBytes(ownDataProperty(value, 'data').value);
153
+ const signature = copyBytes(ownDataProperty(value, 'signature').value);
154
+ if (!data
155
+ || data.byteLength > CRYPTO_RESOURCE_LIMITS.es256SigningInputBytesMaximum
156
+ || !signature
157
+ || !validEs256Signature(signature)) {
158
+ keyBytes.fill(0);
159
+ return invalidSignatureInput();
160
+ }
161
+ return Object.freeze({
162
+ ok: true,
163
+ request: Object.freeze({
164
+ algorithm: 'ES256',
165
+ key: Object.freeze({
166
+ type: 'p256-public-key-bytes',
167
+ bytes: keyBytes,
168
+ }),
169
+ data,
170
+ signature,
171
+ }),
172
+ });
173
+ }
174
+ export function normalizeEs256JoseVerifyRequest(value) {
175
+ if (!isOrdinaryObject(value) || !exactDataProperties(value, JOSE_REQUEST_KEYS)) {
176
+ return invalidSignatureInput();
177
+ }
178
+ const keyValue = ownDataProperty(value, 'key').value;
179
+ if (!isOrdinaryObject(keyValue) || !exactDataProperties(keyValue, JOSE_KEY_KEYS)) {
180
+ return invalidSignatureKey();
181
+ }
182
+ const normalizedKey = normalizeP256PublicKeyCoordinates(keyValue);
183
+ if (!normalizedKey.ok)
184
+ return normalizedKey;
185
+ const signature = decodeCanonicalBase64url(ownDataProperty(value, 'signature').value, CRYPTO_RESOURCE_LIMITS.es256SignatureBytes);
186
+ if (!signature || !validEs256Signature(signature)) {
187
+ normalizedKey.key.bytes.fill(0);
188
+ return invalidSignatureInput();
189
+ }
190
+ const data = copyBytes(ownDataProperty(value, 'data').value);
191
+ if (!data
192
+ || data.byteLength > CRYPTO_RESOURCE_LIMITS.es256SigningInputBytesMaximum) {
193
+ normalizedKey.key.bytes.fill(0);
194
+ return invalidSignatureInput();
195
+ }
196
+ return Object.freeze({
197
+ ok: true,
198
+ request: Object.freeze({
199
+ algorithm: 'ES256',
200
+ key: normalizedKey.key,
201
+ data,
202
+ signature,
203
+ }),
204
+ });
205
+ }
206
+ export function normalizeP256PublicKeyCoordinates(value) {
207
+ if (!isOrdinaryObject(value) || !exactDataProperties(value, JOSE_KEY_KEYS)) {
208
+ return Object.freeze({
209
+ ok: false,
210
+ result: verificationResult('invalid-key'),
211
+ });
212
+ }
213
+ const x = decodeCanonicalBase64url(ownDataProperty(value, 'x').value, 32);
214
+ const y = decodeCanonicalBase64url(ownDataProperty(value, 'y').value, 32);
215
+ if (!x || !y) {
216
+ if (x)
217
+ x.fill(0);
218
+ if (y)
219
+ y.fill(0);
220
+ return Object.freeze({
221
+ ok: false,
222
+ result: verificationResult('invalid-key'),
223
+ });
224
+ }
225
+ const keyBytes = new Uint8Array(CRYPTO_RESOURCE_LIMITS.es256PublicKeyBytes);
226
+ keyBytes.set(x, 0);
227
+ keyBytes.set(y, 32);
228
+ x.fill(0);
229
+ y.fill(0);
230
+ return Object.freeze({
231
+ ok: true,
232
+ key: Object.freeze({
233
+ type: 'p256-public-key-bytes',
234
+ bytes: keyBytes,
235
+ }),
236
+ });
237
+ }
238
+ export function normalizeVerificationResult(value) {
239
+ if (!isOrdinaryObject(value) || !exactDataProperties(value, new Set(['status']))) {
240
+ return verificationResult('realization-failure');
241
+ }
242
+ const status = ownDataProperty(value, 'status').value;
243
+ if (typeof status !== 'string'
244
+ || !CRYPTO_VERIFICATION_STATUSES.includes(status)) {
245
+ return verificationResult('realization-failure');
246
+ }
247
+ return verificationResult(status);
248
+ }
249
+ export function redactMacVerifyRequest(request) {
250
+ return Object.freeze({
251
+ algorithm: request.algorithm,
252
+ key: Object.freeze({
253
+ type: 'hmac-key-bytes',
254
+ compatibleAlgorithms: Object.freeze(['HS256']),
255
+ identity: '[redacted]',
256
+ }),
257
+ data: '[redacted]',
258
+ tag: '[redacted]',
259
+ });
260
+ }
261
+ export function redactSignatureVerifyRequest(request) {
262
+ return Object.freeze({
263
+ algorithm: request.algorithm,
264
+ key: Object.freeze({
265
+ type: 'p256-public-key-bytes',
266
+ compatibleAlgorithms: Object.freeze(['ES256']),
267
+ identity: '[redacted]',
268
+ }),
269
+ data: '[redacted]',
270
+ signature: '[redacted]',
271
+ });
272
+ }
273
+ //# sourceMappingURL=verification.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verification.js","sourceRoot":"","sources":["../../src/internal/verification.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,4BAA4B,GAO7B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,SAAS,EACT,mBAAmB,EACnB,gBAAgB,EAChB,eAAe,GAChB,MAAM,WAAW,CAAC;AAEnB,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;AAClE,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAC5C,MAAM,sBAAsB,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;AAClF,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AACjD,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;AAChE,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;AAC1C,MAAM,SAAS,GAAG,kBAAkB,CAAC;AACrC,MAAM,UAAU,GAAG,UAAU,CAAC,IAAI,CAAC;IACjC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;IAC9C,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;IAC9C,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;IAC9C,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;CAC/C,CAAC,CAAC;AAEH,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,WAAW,CAC9C,4BAA4B,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;IAC3C,MAAM;IACN,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B,CAAC,CACH,CAAyE,CAAC;AAoD3E,MAAM,UAAU,kBAAkB,CAChC,MAAgC;IAEhC,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC;AACzB,CAAC;AAED,SAAS,YAAY;IACnB,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,EAAE,EAAE,KAAK;QACT,MAAM,EAAE,kBAAkB,CAAC,eAAe,CAAC;KAC5C,CAAC,CAAC;AACL,CAAC;AAED,SAAS,UAAU;IACjB,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,EAAE,EAAE,KAAK;QACT,MAAM,EAAE,kBAAkB,CAAC,aAAa,CAAC;KAC1C,CAAC,CAAC;AACL,CAAC;AAED,SAAS,qBAAqB;IAC5B,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,EAAE,EAAE,KAAK;QACT,MAAM,EAAE,kBAAkB,CAAC,eAAe,CAAC;KAC5C,CAAC,CAAC;AACL,CAAC;AAED,SAAS,mBAAmB;IAC1B,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,EAAE,EAAE,KAAK;QACT,MAAM,EAAE,kBAAkB,CAAC,aAAa,CAAC;KAC1C,CAAC,CAAC;AACL,CAAC;AAED,SAAS,gBAAgB,CAAC,IAAgB,EAAE,KAAiB;IAC3D,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC,UAAU,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACxD,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC;YAAE,OAAO,CAAC,CAAC,CAAC;QAC1C,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC;YAAE,OAAO,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,SAAS,eAAe,CAAC,KAAiB;IACxC,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,KAAK,MAAM,IAAI,IAAI,KAAK;QAAE,OAAO,KAAK,IAAI,KAAK,CAAC,CAAC;IACjD,OAAO,OAAO,IAAI,gBAAgB,CAAC,KAAK,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC;AAC5D,CAAC;AAED,SAAS,mBAAmB,CAAC,SAAqB;IAChD,OAAO,SAAS,CAAC,UAAU,KAAK,sBAAsB,CAAC,mBAAmB;WACrE,eAAe,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;WAC1C,eAAe,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;AACnD,CAAC;AAED,SAAS,wBAAwB,CAC/B,KAAc,EACd,aAAqB;IAErB,IACE,OAAO,KAAK,KAAK,QAAQ;WACtB,KAAK,CAAC,MAAM,KAAK,CAAC;WAClB,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC;WACnB,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC;WACtB,KAAK,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC;QACzB,OAAO,SAAS,CAAC;IACnB,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC;UACtD,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC3C,IAAI,MAAc,CAAC;IACnB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAC3B,MAAM,EACN,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,CACvC,CAAC;IACF,IAAI,KAAK,CAAC,UAAU,KAAK,aAAa;QAAE,OAAO,SAAS,CAAC;IACzD,IAAI,SAAS,GAAG,EAAE,CAAC;IACnB,KAAK,MAAM,IAAI,IAAI,KAAK;QAAE,SAAS,IAAI,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IACjE,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;SACxB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACvB,OAAO,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,yBAAyB,CACvC,KAAc;IAEd,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,KAAK,EAAE,YAAY,CAAC,EAAE,CAAC;QAC1E,OAAO,YAAY,EAAE,CAAC;IACxB,CAAC;IAED,MAAM,SAAS,GAAG,eAAe,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC;IAC5D,IAAI,SAAS,KAAK,OAAO;QAAE,OAAO,YAAY,EAAE,CAAC;IAEjD,MAAM,QAAQ,GAAG,eAAe,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,KAAK,CAAC;IACrD,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,IAAI,CAAC,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE,CAAC;QAC5E,OAAO,UAAU,EAAE,CAAC;IACtB,CAAC;IACD,IAAI,eAAe,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,KAAK,KAAK,gBAAgB,EAAE,CAAC;QACjE,OAAO,UAAU,EAAE,CAAC;IACtB,CAAC;IAED,MAAM,QAAQ,GAAG,SAAS,CAAC,eAAe,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC;IACrE,IACE,CAAC,QAAQ;WACN,QAAQ,CAAC,UAAU,GAAG,sBAAsB,CAAC,mBAAmB;WAChE,QAAQ,CAAC,UAAU,GAAG,sBAAsB,CAAC,mBAAmB,EACnE,CAAC;QACD,OAAO,UAAU,EAAE,CAAC;IACtB,CAAC;IAED,MAAM,IAAI,GAAG,SAAS,CAAC,eAAe,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC;IAC7D,MAAM,GAAG,GAAG,SAAS,CAAC,eAAe,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC;IAC3D,IACE,CAAC,IAAI;WACF,IAAI,CAAC,UAAU,GAAG,sBAAsB,CAAC,mBAAmB;WAC5D,CAAC,GAAG;WACJ,GAAG,CAAC,UAAU,KAAK,sBAAsB,CAAC,aAAa,EAC1D,CAAC;QACD,OAAO,YAAY,EAAE,CAAC;IACxB,CAAC;IAED,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,EAAE,EAAE,IAAI;QACR,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC;YACrB,SAAS;YACT,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC;gBACjB,IAAI,EAAE,gBAAgB;gBACtB,KAAK,EAAE,QAAQ;aAChB,CAAC;YACF,IAAI;YACJ,GAAG;SACJ,CAAC;KACH,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,+BAA+B,CAC7C,KAAc;IAEd,IACE,CAAC,gBAAgB,CAAC,KAAK,CAAC;WACrB,CAAC,mBAAmB,CAAC,KAAK,EAAE,sBAAsB,CAAC;QACtD,OAAO,qBAAqB,EAAE,CAAC;IACjC,IAAI,eAAe,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,KAAK,KAAK,OAAO,EAAE,CAAC;QAC1D,OAAO,qBAAqB,EAAE,CAAC;IACjC,CAAC;IAED,MAAM,QAAQ,GAAG,eAAe,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,KAAK,CAAC;IACrD,IACE,CAAC,gBAAgB,CAAC,QAAQ,CAAC;WACxB,CAAC,mBAAmB,CAAC,QAAQ,EAAE,aAAa,CAAC;WAC7C,eAAe,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,KAAK,KAAK,uBAAuB;QACtE,OAAO,mBAAmB,EAAE,CAAC;IAC/B,MAAM,QAAQ,GAAG,SAAS,CAAC,eAAe,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC;IACrE,IACE,CAAC,QAAQ;WACN,QAAQ,CAAC,UAAU,KAAK,sBAAsB,CAAC,mBAAmB;QACrE,OAAO,mBAAmB,EAAE,CAAC;IAE/B,MAAM,IAAI,GAAG,SAAS,CAAC,eAAe,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC;IAC7D,MAAM,SAAS,GAAG,SAAS,CAAC,eAAe,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC,CAAC;IACvE,IACE,CAAC,IAAI;WACF,IAAI,CAAC,UAAU,GAAG,sBAAsB,CAAC,6BAA6B;WACtE,CAAC,SAAS;WACV,CAAC,mBAAmB,CAAC,SAAS,CAAC,EAClC,CAAC;QACD,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjB,OAAO,qBAAqB,EAAE,CAAC;IACjC,CAAC;IAED,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,EAAE,EAAE,IAAI;QACR,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC;YACrB,SAAS,EAAE,OAAO;YAClB,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC;gBACjB,IAAI,EAAE,uBAAuB;gBAC7B,KAAK,EAAE,QAAQ;aAChB,CAAC;YACF,IAAI;YACJ,SAAS;SACV,CAAC;KACH,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,+BAA+B,CAC7C,KAA2B;IAE3B,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,KAAK,EAAE,iBAAiB,CAAC,EAAE,CAAC;QAC/E,OAAO,qBAAqB,EAAE,CAAC;IACjC,CAAC;IACD,MAAM,QAAQ,GAAG,eAAe,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,KAAK,CAAC;IACrD,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,IAAI,CAAC,mBAAmB,CAAC,QAAQ,EAAE,aAAa,CAAC,EAAE,CAAC;QACjF,OAAO,mBAAmB,EAAE,CAAC;IAC/B,CAAC;IACD,MAAM,aAAa,GAAG,iCAAiC,CACrD,QAA+C,CAChD,CAAC;IACF,IAAI,CAAC,aAAa,CAAC,EAAE;QAAE,OAAO,aAAa,CAAC;IAC5C,MAAM,SAAS,GAAG,wBAAwB,CACxC,eAAe,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,KAAK,EACzC,sBAAsB,CAAC,mBAAmB,CAC3C,CAAC;IACF,IAAI,CAAC,SAAS,IAAI,CAAC,mBAAmB,CAAC,SAAS,CAAC,EAAE,CAAC;QAClD,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAChC,OAAO,qBAAqB,EAAE,CAAC;IACjC,CAAC;IACD,MAAM,IAAI,GAAG,SAAS,CAAC,eAAe,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC;IAC7D,IACE,CAAC,IAAI;WACF,IAAI,CAAC,UAAU,GAAG,sBAAsB,CAAC,6BAA6B,EACzE,CAAC;QACD,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAChC,OAAO,qBAAqB,EAAE,CAAC;IACjC,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,EAAE,EAAE,IAAI;QACR,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC;YACrB,SAAS,EAAE,OAAO;YAClB,GAAG,EAAE,aAAa,CAAC,GAAG;YACtB,IAAI;YACJ,SAAS;SACV,CAAC;KACH,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,iCAAiC,CAC/C,KAA+B;IAE/B,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,KAAK,EAAE,aAAa,CAAC,EAAE,CAAC;QAC3E,OAAO,MAAM,CAAC,MAAM,CAAC;YACnB,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,kBAAkB,CAAC,aAAa,CAAC;SAC1C,CAAC,CAAC;IACL,CAAC;IACD,MAAM,CAAC,GAAG,wBAAwB,CAChC,eAAe,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,KAAK,EACjC,EAAE,CACH,CAAC;IACF,MAAM,CAAC,GAAG,wBAAwB,CAChC,eAAe,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,KAAK,EACjC,EAAE,CACH,CAAC;IACF,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;QACb,IAAI,CAAC;YAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjB,IAAI,CAAC;YAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjB,OAAO,MAAM,CAAC,MAAM,CAAC;YACnB,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,kBAAkB,CAAC,aAAa,CAAC;SAC1C,CAAC,CAAC;IACL,CAAC;IACD,MAAM,QAAQ,GAAG,IAAI,UAAU,CAAC,sBAAsB,CAAC,mBAAmB,CAAC,CAAC;IAC5E,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACnB,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACpB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACV,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACV,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,EAAE,EAAE,IAAI;QACR,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC;YACjB,IAAI,EAAE,uBAAuB;YAC7B,KAAK,EAAE,QAAQ;SAChB,CAAC;KACH,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,2BAA2B,CACzC,KAAc;IAEd,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,KAAK,EAAE,IAAI,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;QACjF,OAAO,kBAAkB,CAAC,qBAAqB,CAAC,CAAC;IACnD,CAAC;IACD,MAAM,MAAM,GAAG,eAAe,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,KAAK,CAAC;IACtD,IACE,OAAO,MAAM,KAAK,QAAQ;WACvB,CAAE,4BAAkD,CAAC,QAAQ,CAAC,MAAM,CAAC,EACxE,CAAC;QACD,OAAO,kBAAkB,CAAC,qBAAqB,CAAC,CAAC;IACnD,CAAC;IACD,OAAO,kBAAkB,CAAC,MAAkC,CAAC,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,sBAAsB,CACpC,OAAsD;IAWtD,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC;YACjB,IAAI,EAAE,gBAAgB;YACtB,oBAAoB,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAU,CAAC;YACvD,QAAQ,EAAE,YAAY;SACvB,CAAC;QACF,IAAI,EAAE,YAAY;QAClB,GAAG,EAAE,YAAY;KAClB,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,4BAA4B,CAC1C,OAAkE;IAWlE,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC;YACjB,IAAI,EAAE,uBAAuB;YAC7B,oBAAoB,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAU,CAAC;YACvD,QAAQ,EAAE,YAAY;SACvB,CAAC;QACF,IAAI,EAAE,YAAY;QAClB,SAAS,EAAE,YAAY;KACxB,CAAC,CAAC;AACL,CAAC"}
package/package.json CHANGED
@@ -1,16 +1,48 @@
1
1
  {
2
2
  "name": "@pulse-compute/crypto",
3
- "version": "0.0.0",
4
- "description": "Inert bootstrap placeholder for @pulse-compute/crypto.",
3
+ "version": "1.0.0-beta.2",
5
4
  "license": "Apache-2.0",
5
+ "engines": {
6
+ "node": "^22.14.0 || ^24.0.0"
7
+ },
8
+ "description": "Provider-neutral cryptographic verification contracts for Pulse.",
9
+ "type": "module",
10
+ "sideEffects": false,
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js",
15
+ "default": "./dist/index.js"
16
+ },
17
+ "./pulsewasm-native": "./pulsewasm.native.cjs",
18
+ "./provider": "./src/provider.cjs"
19
+ },
6
20
  "files": [
21
+ "as",
22
+ "dist",
23
+ "pulsewasm.native.cjs",
7
24
  "README.md",
25
+ "src/provider.cjs",
8
26
  "LICENSE",
9
27
  "NOTICE"
10
28
  ],
11
29
  "publishConfig": {
12
- "access": "public",
13
- "registry": "https://registry.npmjs.org/",
14
- "tag": "bootstrap"
30
+ "access": "public"
31
+ },
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "git+https://github.com/pulse-compute/pulse.git",
35
+ "directory": "packages/crypto"
36
+ },
37
+ "bugs": {
38
+ "url": "https://github.com/pulse-compute/pulse/issues"
39
+ },
40
+ "homepage": "https://pulsecompute.io/v1.0.0-beta.2/packages/crypto/",
41
+ "main": "./dist/index.js",
42
+ "types": "./dist/index.d.ts",
43
+ "scripts": {
44
+ "build": "tsc -b",
45
+ "test": "corepack pnpm --dir ../.. exec vitest run packages/crypto/test",
46
+ "test:types": "tsc -p tsconfig.types.json --noEmit"
15
47
  }
16
- }
48
+ }
@@ -0,0 +1,127 @@
1
+ 'use strict';
2
+
3
+ const crypto = require('node:crypto');
4
+ const fs = require('node:fs');
5
+ const path = require('node:path');
6
+ const packageManifest = require('./package.json');
7
+
8
+ const CRYPTO_GUEST_SOURCE_CONTRACT_VERSION = 'pulse.crypto-guest-source.v1';
9
+ const GUEST_UNIT_CONTRIBUTION_VERSION = 'pulse.guest-unit-contribution.v1';
10
+ const sourceRelativeFile = 'as/pulse-hmac-as.ts';
11
+ const sourceFile = path.join(__dirname, sourceRelativeFile);
12
+
13
+ function sha256(value) {
14
+ return crypto.createHash('sha256').update(value).digest('hex');
15
+ }
16
+
17
+ function pulseHmacAssemblyScriptSource(algorithm = 'HS256') {
18
+ if (!['HS256', 'SHA-256', 'HMAC-SHA256'].includes(algorithm)) throw new TypeError('Unsupported Crypto guest-source algorithm.');
19
+ const source = fs.readFileSync(sourceFile, 'utf8');
20
+ return Object.freeze({
21
+ version: CRYPTO_GUEST_SOURCE_CONTRACT_VERSION,
22
+ id: 'pulse-hmac-as',
23
+ owner: '@pulse-compute/crypto',
24
+ packageVersion: packageManifest.version,
25
+ realization: 'guest-source:pulse-hmac-as',
26
+ kind: 'guest-source',
27
+ backend: 'pulse-hmac-as',
28
+ backendVersion: 'pulse-hmac-as.v1',
29
+ algorithm,
30
+ language: 'assemblyscript',
31
+ license: 'Apache-2.0',
32
+ origin: 'package-source',
33
+ sourceIncluded: true,
34
+ provenance: Object.freeze([
35
+ 'NIST FIPS 180-4',
36
+ 'RFC 2104',
37
+ 'RFC 4231'
38
+ ]),
39
+ sourceFile: sourceRelativeFile,
40
+ source,
41
+ sourceBytes: Buffer.byteLength(source),
42
+ sourceSha256: sha256(source),
43
+ imports: Object.freeze([]),
44
+ exports: Object.freeze([
45
+ 'pulse_crypto_hs256_verify',
46
+ 'pulse_crypto_sha256_digest',
47
+ 'pulse_crypto_bytes_frame_v1',
48
+ 'pulse_crypto_sha256_bytes_v1',
49
+ 'pulse_crypto_hmac_sha256_bytes_v1'
50
+ ]),
51
+ resourceLimits: Object.freeze({
52
+ hmacKeyBytesMinimum: 32,
53
+ hmacKeyBytesMaximum: 4 * 1024,
54
+ macDataBytesMaximum: 1024 * 1024,
55
+ hs256TagBytes: 32,
56
+ byteOperationKeyBytesMaximum: 8192,
57
+ byteOperationDataBytesMaximum: 32768,
58
+ byteOperationOutputBytes: 32,
59
+ byteOperationFrameBytes: 40992
60
+ }),
61
+ resultCodes: Object.freeze({
62
+ valid: 1,
63
+ invalidAuthenticator: 0,
64
+ invalidKey: -1,
65
+ invalidInput: -2,
66
+ realizationFailure: -3
67
+ }),
68
+ comparison: Object.freeze({
69
+ mode: 'constant-time-full-tag-scan',
70
+ bytes: 32,
71
+ earlyMismatchReturn: false
72
+ }),
73
+ automaticFallback: false
74
+ });
75
+ }
76
+
77
+ function bindNativeDigestMac(moduleExports) {
78
+ const memory = moduleExports && moduleExports.memory;
79
+ const names = ['pulse_crypto_bytes_frame_v1', 'pulse_crypto_sha256_bytes_v1', 'pulse_crypto_hmac_sha256_bytes_v1'];
80
+ if (!(memory instanceof WebAssembly.Memory) || names.some((name) => typeof moduleExports[name] !== 'function')) {
81
+ throw new TypeError('Native Crypto digest/MAC exports are unavailable.');
82
+ }
83
+ const frameBytes = 8192 + 32768 + 32;
84
+ function run(data, key) {
85
+ if (!(data instanceof Uint8Array) || data.length > 32768
86
+ || (key !== undefined && (!(key instanceof Uint8Array) || key.length > 8192))) {
87
+ throw new TypeError('Native Crypto digest/MAC input exceeds its byte contract.');
88
+ }
89
+ const pointer = moduleExports.pulse_crypto_bytes_frame_v1() >>> 0;
90
+ if (pointer + frameBytes > memory.buffer.byteLength) throw new TypeError('Native Crypto frame is outside memory.');
91
+ const dataPointer = pointer + 8192;
92
+ const outputPointer = dataPointer + 32768;
93
+ try {
94
+ const view = new Uint8Array(memory.buffer);
95
+ view.set(data, dataPointer);
96
+ if (key !== undefined) view.set(key, pointer);
97
+ const code = key === undefined
98
+ ? moduleExports.pulse_crypto_sha256_bytes_v1(dataPointer, data.length, outputPointer, 32)
99
+ : moduleExports.pulse_crypto_hmac_sha256_bytes_v1(pointer, key.length, dataPointer, data.length, outputPointer, 32);
100
+ if (code !== 1) throw new TypeError('Native Crypto digest/MAC realization failed.');
101
+ return new Uint8Array(memory.buffer, outputPointer, 32).slice();
102
+ } finally {
103
+ // The Wasm allocator can grow memory while hashing: acquire a fresh view.
104
+ new Uint8Array(memory.buffer, pointer, frameBytes).fill(0);
105
+ }
106
+ }
107
+ return Object.freeze({ sha256: (data) => run(data), hmacSha256: (key, data) => run(data, key) });
108
+ }
109
+
110
+ function pulseEs256GuestUnit() {
111
+ return Object.freeze({
112
+ version: GUEST_UNIT_CONTRIBUTION_VERSION,
113
+ id: 'pulse.crypto.es256.rustcrypto-p256.v1',
114
+ manifest: './guests/es256-rustcrypto/pulse.guest-unit.json',
115
+ owner: packageManifest.name,
116
+ packageVersion: packageManifest.version,
117
+ origin: 'package-prebuilt'
118
+ });
119
+ }
120
+
121
+ module.exports = Object.freeze({
122
+ CRYPTO_GUEST_SOURCE_CONTRACT_VERSION,
123
+ GUEST_UNIT_CONTRIBUTION_VERSION,
124
+ pulseHmacAssemblyScriptSource,
125
+ bindNativeDigestMac,
126
+ pulseEs256GuestUnit
127
+ });
@@ -0,0 +1,43 @@
1
+ 'use strict';
2
+
3
+ // Trusted provider byte-output seam. JWT verification keeps its own key limits.
4
+ const IMPLEMENTATIONS = Object.freeze({
5
+ 'SHA-256': 'webcrypto.subtle.sha-256-bytes.v1',
6
+ 'HMAC-SHA256': 'webcrypto.subtle.hmac-sha-256-bytes.v1'
7
+ });
8
+ function snapshot(value, maximum) {
9
+ if (!(value instanceof Uint8Array) || value.byteLength > maximum) throw new TypeError('Crypto byte input is outside its bound.');
10
+ return new Uint8Array(value);
11
+ }
12
+ function result(value) {
13
+ if (!(value instanceof ArrayBuffer) || value.byteLength !== 32) throw new TypeError('Crypto byte output is invalid.');
14
+ return new Uint8Array(value);
15
+ }
16
+ function bindJavascriptDigestMac(algorithms, subtle = globalThis.crypto && globalThis.crypto.subtle) {
17
+ if (!Array.isArray(algorithms) || new Set(algorithms).size !== algorithms.length || algorithms.some((name) => !Object.hasOwn(IMPLEMENTATIONS, name))) throw new TypeError('Crypto requires explicit supported byte algorithms.');
18
+ if (!subtle || algorithms.includes('SHA-256') && typeof subtle.digest !== 'function'
19
+ || algorithms.includes('HMAC-SHA256') && (typeof subtle.sign !== 'function' || typeof subtle.importKey !== 'function')) throw new TypeError('Selected Web Crypto byte realization is unavailable.');
20
+ const bytes = {};
21
+ if (algorithms.includes('SHA-256')) bytes.sha256 = async (input) => {
22
+ const data = snapshot(input, 32768);
23
+ try { return result(await subtle.digest({ name: 'SHA-256' }, data)); }
24
+ finally { data.fill(0); }
25
+ };
26
+ if (algorithms.includes('HMAC-SHA256')) bytes.hmacSha256 = async (keyInput, input) => {
27
+ let key = snapshot(keyInput, 8192);
28
+ let data;
29
+ try {
30
+ data = snapshot(input, 32768);
31
+ // HMAC pads an empty key to a zero block (RFC 2104). Web Crypto rejects
32
+ // a zero-length import; the equivalent padded block retains Native parity.
33
+ if (key.length === 0) key = new Uint8Array(64);
34
+ const imported = await subtle.importKey('raw', key, { name: 'HMAC', hash: 'SHA-256', length: key.length * 8 }, false, ['sign']);
35
+ return result(await subtle.sign({ name: 'HMAC' }, imported, data));
36
+ } finally { key.fill(0); if (data) data.fill(0); }
37
+ };
38
+ return Object.freeze({ bytes: Object.freeze(bytes), realization: Object.freeze({
39
+ target: 'javascript', automaticFallback: false,
40
+ algorithms: Object.freeze(algorithms.map((algorithm) => Object.freeze({ algorithm, realization: 'runtime-builtin', implementation: IMPLEMENTATIONS[algorithm], available: true, automaticFallback: false })))
41
+ }) });
42
+ }
43
+ module.exports = Object.freeze({ IMPLEMENTATIONS, bindJavascriptDigestMac });