@reallyme/crypto 0.3.6 → 0.3.7

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/LICENSE CHANGED
@@ -1,3 +1,29 @@
1
+ ReallyMe Crypto is licensed, at your option, under either the MIT License or
2
+ the Apache License, Version 2.0. The full text of both licenses follows.
3
+ Third-party components retain their own licenses and notices.
4
+
5
+ MIT License
6
+
7
+ Copyright © 2026 ReallyMe LLC.
8
+
9
+ Permission is hereby granted, free of charge, to any person obtaining a copy
10
+ of this software and associated documentation files (the "Software"), to deal
11
+ in the Software without restriction, including without limitation the rights
12
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
+ copies of the Software, and to permit persons to whom the Software is
14
+ furnished to do so, subject to the following conditions:
15
+
16
+ The above copyright notice and this permission notice shall be included in all
17
+ copies or substantial portions of the Software.
18
+
19
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25
+ SOFTWARE.
26
+
1
27
  Apache License
2
28
  Version 2.0, January 2004
3
29
  http://www.apache.org/licenses/
package/README.md CHANGED
@@ -1,13 +1,11 @@
1
1
  <!--
2
2
  SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
3
-
4
- SPDX-License-Identifier: Apache-2.0
5
3
  -->
6
4
 
7
5
  # @reallyme/crypto
8
6
 
9
7
  [![npm](https://img.shields.io/npm/v/@reallyme/crypto?label=npm&color=2563eb)](https://www.npmjs.com/package/@reallyme/crypto)
10
- [![License](https://img.shields.io/badge/license-Apache--2.0-blue)](https://github.com/reallyme/crypto/blob/main/LICENSE)
8
+ [![License](https://img.shields.io/badge/license-MIT%20OR%20Apache--2.0-blue)](https://github.com/reallyme/crypto/blob/main/LICENSE)
11
9
 
12
10
  `@reallyme/crypto` is the TypeScript SDK for ReallyMe Crypto. It provides typed,
13
11
  synchronous APIs for Node.js and browsers, with explicit JavaScript and
@@ -17,16 +15,6 @@ The package shares algorithm identifiers, byte formats, typed failures, and
17
15
  conformance vectors with the Rust, Swift, Kotlin, and Android SDKs. Availability
18
16
  is provider-specific; unsupported routes fail closed.
19
17
 
20
- ## Why
21
-
22
- Modern cryptography APIs differ across platforms. Algorithms are exposed
23
- differently, key formats vary, providers have different capabilities, and error
24
- behavior is inconsistent.
25
-
26
- ReallyMe Crypto makes platform differences explicit while preserving a stable
27
- contract for every supported route. Applications can share protocol logic
28
- without silently changing cryptographic providers.
29
-
30
18
  ## Installation
31
19
 
32
20
  ```sh
@@ -187,18 +175,6 @@ created.
187
175
  Do not move private keys, passwords, plaintext, shared secrets, or derived keys
188
176
  through strings or JSON paths.
189
177
 
190
- ## Features
191
-
192
- - Platform-agnostic cryptography APIs.
193
- - Consistent key formats and protocol identifiers.
194
- - Shared conformance vectors across Rust, Swift, Kotlin, and TypeScript.
195
- - Native providers where available, WASM-backed implementations where needed.
196
- - Typed errors and fail-closed verification behavior.
197
- - Generated protobuf operations, algorithm identifiers, and typed wire errors
198
- via `@reallyme/crypto/proto`.
199
- - JWK, multikey, multicodec, HPKE, ML-KEM, ML-DSA, Ed25519, secp256k1, X25519,
200
- AES-GCM, ChaCha20-Poly1305, and more.
201
-
202
178
  ## Protobuf Process Boundary
203
179
 
204
180
  `processOperationResponse(request)` accepts one generated binary
@@ -220,3 +196,9 @@ The complete documentation, provider matrix, protocol contracts, and conformance
220
196
  specifications are available in the main repository:
221
197
 
222
198
  https://github.com/reallyme/crypto
199
+
200
+ ## License
201
+
202
+ Licensed under either the MIT License or the Apache License, Version 2.0,
203
+ at your option. See [LICENSE](https://github.com/reallyme/crypto/blob/main/LICENSE). Third-party components retain
204
+ their own licenses and notices.
package/dist/aead.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
2
  //
3
- // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-License-Identifier: MIT OR Apache-2.0
4
4
  import { ReallyMeCryptoError } from "./errors.js";
5
5
  import { ensureByteArrayAtMost, ensureBytes, ensureIndependentByteArray, MAX_CRYPTO_INPUT_LENGTH, } from "./validateBytes.js";
6
6
  import { requireReallyMeWasmProvider } from "./wasmProvider.js";
package/dist/aesKw.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
2
  //
3
- // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-License-Identifier: MIT OR Apache-2.0
4
4
  import { ReallyMeCryptoError } from "./errors.js";
5
5
  import { ensureByteArray, ensureBytes, ensureIndependentByteArray, } from "./validateBytes.js";
6
6
  import { requireReallyMeWasmProvider } from "./wasmProvider.js";
@@ -1,6 +1,6 @@
1
1
  // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
2
  //
3
- // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-License-Identifier: MIT OR Apache-2.0
4
4
  export const REALLYME_SIGNATURE_ALGORITHMS = [
5
5
  "Ed25519",
6
6
  "ECDSA-P256-SHA256",
package/dist/argon2id.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
2
  //
3
- // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-License-Identifier: MIT OR Apache-2.0
4
4
  import { ReallyMeCryptoError } from "./errors.js";
5
5
  import { ensureByteArrayAtMost, ensureIndependentByteArray, } from "./validateBytes.js";
6
6
  import { requireReallyMeWasmProvider } from "./wasmProvider.js";
@@ -1,8 +1,9 @@
1
1
  // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
2
  //
3
- // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-License-Identifier: MIT OR Apache-2.0
4
4
  import { schnorr, secp256k1 } from "@noble/curves/secp256k1.js";
5
5
  import { ReallyMeCryptoError } from "./errors.js";
6
+ import { ensureByteArray } from "./validateBytes.js";
6
7
  export const BIP340_SCHNORR_SECRET_KEY_LENGTH = 32;
7
8
  export const BIP340_SCHNORR_PUBLIC_KEY_LENGTH = 32;
8
9
  export const BIP340_SCHNORR_MESSAGE_LENGTH = 32;
@@ -27,10 +28,12 @@ export const ReallyMeBip340Schnorr = {
27
28
  deriveKeyPair(secretKey) {
28
29
  return {
29
30
  publicKey: this.derivePublicKey(secretKey),
30
- secretKey: secretKey.slice(),
31
+ // Buffer.slice() aliases its input; the returned key must own its bytes.
32
+ secretKey: new Uint8Array(secretKey),
31
33
  };
32
34
  },
33
35
  derivePublicKey(secretKey) {
36
+ ensureByteArray(secretKey);
34
37
  if (secretKey.length !== BIP340_SCHNORR_SECRET_KEY_LENGTH) {
35
38
  throw new ReallyMeCryptoError("invalid-input");
36
39
  }
@@ -42,6 +45,9 @@ export const ReallyMeBip340Schnorr = {
42
45
  }
43
46
  },
44
47
  sign(message32, secretKey, auxRand32) {
48
+ ensureByteArray(message32);
49
+ ensureByteArray(secretKey);
50
+ ensureByteArray(auxRand32);
45
51
  if (message32.length !== BIP340_SCHNORR_MESSAGE_LENGTH ||
46
52
  secretKey.length !== BIP340_SCHNORR_SECRET_KEY_LENGTH ||
47
53
  auxRand32.length !== BIP340_SCHNORR_AUX_RAND_LENGTH) {
@@ -55,6 +61,9 @@ export const ReallyMeBip340Schnorr = {
55
61
  }
56
62
  },
57
63
  verify(signature, message32, publicKey) {
64
+ ensureByteArray(signature);
65
+ ensureByteArray(message32);
66
+ ensureByteArray(publicKey);
58
67
  if (signature.length !== BIP340_SCHNORR_SIGNATURE_LENGTH ||
59
68
  message32.length !== BIP340_SCHNORR_MESSAGE_LENGTH ||
60
69
  publicKey.length !== BIP340_SCHNORR_PUBLIC_KEY_LENGTH) {
@@ -1,6 +1,6 @@
1
1
  // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
2
  //
3
- // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-License-Identifier: MIT OR Apache-2.0
4
4
  import { ReallyMeAead } from "./aead.js";
5
5
  import { ReallyMeAesKw } from "./aesKw.js";
6
6
  import { ReallyMeArgon2id } from "./argon2id.js";
package/dist/digest.js CHANGED
@@ -1,8 +1,9 @@
1
1
  // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
2
  //
3
- // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-License-Identifier: MIT OR Apache-2.0
4
4
  import { sha256 as nobleSha256, sha384 as nobleSha384, sha512 as nobleSha512 } from "@noble/hashes/sha2.js";
5
5
  import { sha3_224 as nobleSha3_224, sha3_256 as nobleSha3_256, sha3_384 as nobleSha3_384, sha3_512 as nobleSha3_512, } from "@noble/hashes/sha3.js";
6
+ import { ensureByteArray } from "./validateBytes.js";
6
7
  /**
7
8
  * Small digest surface used by package tests and as the first package API
8
9
  * slice while algorithm wrappers are added one at a time. Mirrors the Swift
@@ -10,24 +11,31 @@ import { sha3_224 as nobleSha3_224, sha3_256 as nobleSha3_256, sha3_384 as noble
10
11
  */
11
12
  export const ReallyMeDigest = {
12
13
  sha256(bytes) {
14
+ ensureByteArray(bytes);
13
15
  return nobleSha256(bytes);
14
16
  },
15
17
  sha384(bytes) {
18
+ ensureByteArray(bytes);
16
19
  return nobleSha384(bytes);
17
20
  },
18
21
  sha512(bytes) {
22
+ ensureByteArray(bytes);
19
23
  return nobleSha512(bytes);
20
24
  },
21
25
  sha3_224(bytes) {
26
+ ensureByteArray(bytes);
22
27
  return nobleSha3_224(bytes);
23
28
  },
24
29
  sha3_256(bytes) {
30
+ ensureByteArray(bytes);
25
31
  return nobleSha3_256(bytes);
26
32
  },
27
33
  sha3_384(bytes) {
34
+ ensureByteArray(bytes);
28
35
  return nobleSha3_384(bytes);
29
36
  },
30
37
  sha3_512(bytes) {
38
+ ensureByteArray(bytes);
31
39
  return nobleSha3_512(bytes);
32
40
  },
33
41
  };
package/dist/ed25519.js CHANGED
@@ -1,8 +1,9 @@
1
1
  // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
2
  //
3
- // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-License-Identifier: MIT OR Apache-2.0
4
4
  import { ed25519 } from "@noble/curves/ed25519.js";
5
5
  import { ReallyMeCryptoError } from "./errors.js";
6
+ import { ensureByteArray } from "./validateBytes.js";
6
7
  /**
7
8
  * Ed25519 signatures backed by @noble/curves — the same pinned implementation
8
9
  * the TypeScript conformance lane proves vectors against.
@@ -33,11 +34,13 @@ export const ReallyMeEd25519 = {
33
34
  deriveKeyPair(secretKey) {
34
35
  return {
35
36
  publicKey: this.derivePublicKey(secretKey),
36
- secretKey: secretKey.slice(),
37
+ // Buffer.slice() aliases its input; the returned key must own its bytes.
38
+ secretKey: new Uint8Array(secretKey),
37
39
  };
38
40
  },
39
41
  /** Derives the 32-byte Ed25519 public key from a 32-byte seed. */
40
42
  derivePublicKey(secretKey) {
43
+ ensureByteArray(secretKey);
41
44
  if (secretKey.length !== ED25519_SECRET_KEY_LENGTH) {
42
45
  throw new ReallyMeCryptoError("invalid-input");
43
46
  }
@@ -50,6 +53,8 @@ export const ReallyMeEd25519 = {
50
53
  },
51
54
  /** Signs the full message using plain deterministic Ed25519. */
52
55
  sign(message, secretKey) {
56
+ ensureByteArray(message);
57
+ ensureByteArray(secretKey);
53
58
  if (secretKey.length !== ED25519_SECRET_KEY_LENGTH) {
54
59
  throw new ReallyMeCryptoError("invalid-input");
55
60
  }
@@ -66,6 +71,9 @@ export const ReallyMeEd25519 = {
66
71
  * Throws on malformed input shape, undecodable keys, or invalid signatures.
67
72
  */
68
73
  verify(signature, message, publicKey) {
74
+ ensureByteArray(signature);
75
+ ensureByteArray(message);
76
+ ensureByteArray(publicKey);
69
77
  if (signature.length !== ED25519_SIGNATURE_LENGTH ||
70
78
  publicKey.length !== ED25519_PUBLIC_KEY_LENGTH) {
71
79
  throw new ReallyMeCryptoError("invalid-input");
@@ -1,6 +1,6 @@
1
1
  // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
2
  //
3
- // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-License-Identifier: MIT OR Apache-2.0
4
4
  import { ReallyMeCryptoError } from "./errors.js";
5
5
  const DER_SEQUENCE_TAG = 0x30;
6
6
  const DER_INTEGER_TAG = 0x02;
package/dist/errors.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
2
  //
3
- // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-License-Identifier: MIT OR Apache-2.0
4
4
  export class ReallyMeCryptoError extends Error {
5
5
  code;
6
6
  constructor(code) {
package/dist/hkdf.js CHANGED
@@ -1,9 +1,10 @@
1
1
  // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
2
  //
3
- // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-License-Identifier: MIT OR Apache-2.0
4
4
  import { hkdf } from "@noble/hashes/hkdf.js";
5
5
  import { sha256, sha384 } from "@noble/hashes/sha2.js";
6
6
  import { ReallyMeCryptoError } from "./errors.js";
7
+ import { ensureByteArray } from "./validateBytes.js";
7
8
  export const HKDF_MIN_INPUT_KEY_MATERIAL_LENGTH = 1;
8
9
  export const HKDF_MAX_INPUT_LENGTH = 4096;
9
10
  export const HKDF_MIN_OUTPUT_LENGTH = 1;
@@ -19,6 +20,9 @@ export const ReallyMeHkdf = {
19
20
  },
20
21
  };
21
22
  function validate(inputKeyMaterial, salt, info, outputLength) {
23
+ ensureByteArray(inputKeyMaterial);
24
+ ensureByteArray(salt);
25
+ ensureByteArray(info);
22
26
  if (inputKeyMaterial.length < HKDF_MIN_INPUT_KEY_MATERIAL_LENGTH ||
23
27
  inputKeyMaterial.length > HKDF_MAX_INPUT_LENGTH ||
24
28
  salt.length > HKDF_MAX_INPUT_LENGTH ||
package/dist/hmac.js CHANGED
@@ -1,9 +1,10 @@
1
1
  // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
2
  //
3
- // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-License-Identifier: MIT OR Apache-2.0
4
4
  import { hmac } from "@noble/hashes/hmac.js";
5
5
  import { sha256, sha384, sha512 } from "@noble/hashes/sha2.js";
6
6
  import { ReallyMeCryptoError } from "./errors.js";
7
+ import { ensureByteArray } from "./validateBytes.js";
7
8
  export const HMAC_MAX_KEY_LENGTH = 4096;
8
9
  export const HMAC_SHA256_TAG_LENGTH = 32;
9
10
  export const HMAC_SHA384_TAG_LENGTH = 48;
@@ -11,29 +12,35 @@ export const HMAC_SHA512_TAG_LENGTH = 64;
11
12
  export const ReallyMeHmac = {
12
13
  authenticateSha256(key, message) {
13
14
  validateKey(key);
15
+ ensureByteArray(message);
14
16
  return hmac(sha256, key, message);
15
17
  },
16
18
  authenticateSha384(key, message) {
17
19
  validateKey(key);
20
+ ensureByteArray(message);
18
21
  return hmac(sha384, key, message);
19
22
  },
20
23
  authenticateSha512(key, message) {
21
24
  validateKey(key);
25
+ ensureByteArray(message);
22
26
  return hmac(sha512, key, message);
23
27
  },
24
28
  verifySha256(tag, key, message) {
29
+ ensureByteArray(tag);
25
30
  if (tag.length !== HMAC_SHA256_TAG_LENGTH) {
26
31
  throw new ReallyMeCryptoError("invalid-input");
27
32
  }
28
33
  return verifyAndClearExpectedTag(tag, ReallyMeHmac.authenticateSha256(key, message));
29
34
  },
30
35
  verifySha384(tag, key, message) {
36
+ ensureByteArray(tag);
31
37
  if (tag.length !== HMAC_SHA384_TAG_LENGTH) {
32
38
  throw new ReallyMeCryptoError("invalid-input");
33
39
  }
34
40
  return verifyAndClearExpectedTag(tag, ReallyMeHmac.authenticateSha384(key, message));
35
41
  },
36
42
  verifySha512(tag, key, message) {
43
+ ensureByteArray(tag);
37
44
  if (tag.length !== HMAC_SHA512_TAG_LENGTH) {
38
45
  throw new ReallyMeCryptoError("invalid-input");
39
46
  }
@@ -41,6 +48,7 @@ export const ReallyMeHmac = {
41
48
  },
42
49
  };
43
50
  function validateKey(key) {
51
+ ensureByteArray(key);
44
52
  if (key.length === 0 || key.length > HMAC_MAX_KEY_LENGTH) {
45
53
  throw new ReallyMeCryptoError("invalid-input");
46
54
  }
@@ -50,9 +58,10 @@ function constantTimeEquals(left, right) {
50
58
  return false;
51
59
  }
52
60
  let difference = 0;
53
- for (const [index, leftByte] of left.entries()) {
61
+ for (let index = 0; index < left.length; index += 1) {
62
+ const leftByte = left[index];
54
63
  const rightByte = right[index];
55
- if (rightByte === undefined) {
64
+ if (leftByte === undefined || rightByte === undefined) {
56
65
  return false;
57
66
  }
58
67
  difference |= leftByte ^ rightByte;
package/dist/hpke.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
2
  //
3
- // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-License-Identifier: MIT OR Apache-2.0
4
4
  import { ReallyMeCryptoError } from "./errors.js";
5
5
  import { ensureByteArrayAtMost, ensureBytes, ensureIndependentByteArray, MAX_CRYPTO_INPUT_LENGTH, readIndependentByteArrayProperty, } from "./validateBytes.js";
6
6
  import { requireReallyMeWasmProvider } from "./wasmProvider.js";
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
2
  //
3
- // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-License-Identifier: MIT OR Apache-2.0
4
4
  export { ReallyMeCryptoError } from "./errors.js";
5
5
  export { REALLYME_AEAD_ALGORITHMS, REALLYME_HASH_ALGORITHMS, REALLYME_HPKE_SUITES, REALLYME_KDF_ALGORITHMS, REALLYME_KEM_ALGORITHMS, REALLYME_KEY_AGREEMENT_ALGORITHMS, REALLYME_KEY_WRAP_ALGORITHMS, REALLYME_MAC_ALGORITHMS, REALLYME_SIGNATURE_ALGORITHMS, } from "./algorithms.js";
6
6
  export { AEAD_KEY_LENGTH, AEAD_NONCE_LENGTH, AEAD_TAG_LENGTH, AES_128_GCM_KEY_LENGTH, AES_192_GCM_KEY_LENGTH, AES_256_GCM_KEY_LENGTH, CHACHA20_POLY1305_KEY_LENGTH, ReallyMeAead, XCHACHA20_POLY1305_NONCE_LENGTH, } from "./aead.js";
@@ -1,8 +1,9 @@
1
1
  // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
2
  //
3
- // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-License-Identifier: MIT OR Apache-2.0
4
4
  import { sha256 } from "@noble/hashes/sha2.js";
5
5
  import { ReallyMeCryptoError } from "./errors.js";
6
+ import { ensureByteArray } from "./validateBytes.js";
6
7
  import { bestEffortClear } from "./memory.js";
7
8
  export const JWA_CONCAT_KDF_SHA256_DIGEST_LENGTH = 32;
8
9
  export const JWA_CONCAT_KDF_MAX_SHARED_SECRET_LENGTH = 4096;
@@ -32,6 +33,10 @@ export const ReallyMeJwaConcatKdf = {
32
33
  },
33
34
  };
34
35
  function validate(sharedSecret, algorithmId, partyUInfo, partyVInfo, outputLength) {
36
+ ensureByteArray(sharedSecret);
37
+ ensureByteArray(algorithmId);
38
+ ensureByteArray(partyUInfo);
39
+ ensureByteArray(partyVInfo);
35
40
  if (sharedSecret.length === 0 ||
36
41
  sharedSecret.length > JWA_CONCAT_KDF_MAX_SHARED_SECRET_LENGTH ||
37
42
  algorithmId.length === 0 ||
package/dist/jwk.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
2
  //
3
- // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-License-Identifier: MIT OR Apache-2.0
4
4
  import { p256 } from "@noble/curves/nist.js";
5
5
  import { secp256k1 } from "@noble/curves/secp256k1.js";
6
6
  import { base64urlDecode as codecBase64urlDecodeValue, base64urlEncode as codecBase64urlEncodeValue, canonicalizeJson as codecCanonicalizeJson, ReallyMeCodecError, } from "@reallyme/codec";
package/dist/kmac.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
2
  //
3
- // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-License-Identifier: MIT OR Apache-2.0
4
4
  import { ReallyMeCryptoError } from "./errors.js";
5
5
  import { ensureByteArray, ensureIndependentByteArray, } from "./validateBytes.js";
6
6
  import { requireReallyMeWasmProvider } from "./wasmProvider.js";
package/dist/memory.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
2
  //
3
- // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-License-Identifier: MIT OR Apache-2.0
4
4
  /**
5
5
  * Best-effort cleanup for caller-owned managed-runtime byte arrays.
6
6
  *
package/dist/mlDsa.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
2
  //
3
- // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-License-Identifier: MIT OR Apache-2.0
4
4
  import { ReallyMeCryptoError } from "./errors.js";
5
5
  import { ensureByteArrayAtMost, ensureBytes, ensureIndependentByteArray, MAX_CRYPTO_INPUT_LENGTH, readIndependentByteArrayProperty, } from "./validateBytes.js";
6
6
  import { requireReallyMeWasmProvider } from "./wasmProvider.js";
package/dist/mlKem.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
2
  //
3
- // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-License-Identifier: MIT OR Apache-2.0
4
4
  import { ReallyMeCryptoError } from "./errors.js";
5
5
  import { ensureBytes, readIndependentByteArrayProperty, readIndependentProviderBytes, } from "./validateBytes.js";
6
6
  import { requireReallyMeWasmProvider } from "./wasmProvider.js";
@@ -1,6 +1,6 @@
1
1
  // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
2
  //
3
- // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-License-Identifier: MIT OR Apache-2.0
4
4
  import { ReallyMeCryptoError } from "./errors.js";
5
5
  import { ensureByteArray, ensureIndependentByteArray, } from "./validateBytes.js";
6
6
  import { requireReallyMeWasmProvider } from "./wasmProvider.js";
package/dist/p256Ecdh.js CHANGED
@@ -1,8 +1,9 @@
1
1
  // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
2
  //
3
- // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-License-Identifier: MIT OR Apache-2.0
4
4
  import { p256 } from "@noble/curves/nist.js";
5
5
  import { ReallyMeCryptoError } from "./errors.js";
6
+ import { ensureByteArray } from "./validateBytes.js";
6
7
  import { bestEffortClear } from "./memory.js";
7
8
  /**
8
9
  * P-256 ECDH backed by @noble/curves.
@@ -25,10 +26,12 @@ export const ReallyMeP256Ecdh = {
25
26
  deriveKeyPair(secretKey) {
26
27
  return {
27
28
  publicKey: this.derivePublicKey(secretKey),
28
- secretKey: secretKey.slice(),
29
+ // Buffer.slice() aliases its input; the returned key must own its bytes.
30
+ secretKey: new Uint8Array(secretKey),
29
31
  };
30
32
  },
31
33
  derivePublicKey(secretKey) {
34
+ ensureByteArray(secretKey);
32
35
  if (secretKey.length !== P256_ECDH_SECRET_KEY_LENGTH) {
33
36
  throw new ReallyMeCryptoError("invalid-input");
34
37
  }
@@ -40,6 +43,8 @@ export const ReallyMeP256Ecdh = {
40
43
  }
41
44
  },
42
45
  deriveSharedSecret(publicKey, secretKey) {
46
+ ensureByteArray(publicKey);
47
+ ensureByteArray(secretKey);
43
48
  if (publicKey.length !== P256_ECDH_COMPRESSED_PUBLIC_KEY_LENGTH ||
44
49
  secretKey.length !== P256_ECDH_SECRET_KEY_LENGTH) {
45
50
  throw new ReallyMeCryptoError("invalid-input");
package/dist/p256Ecdsa.js CHANGED
@@ -1,10 +1,11 @@
1
1
  // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
2
  //
3
- // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-License-Identifier: MIT OR Apache-2.0
4
4
  import { p256 } from "@noble/curves/nist.js";
5
5
  import { sha256 } from "@noble/hashes/sha2.js";
6
6
  import { decodeEcdsaDerSignature, encodeEcdsaDerSignature, } from "./encodeEcdsaDer.js";
7
7
  import { ReallyMeCryptoError } from "./errors.js";
8
+ import { ensureByteArray } from "./validateBytes.js";
8
9
  export const P256_ECDSA_SECRET_KEY_LENGTH = 32;
9
10
  export const P256_ECDSA_COMPRESSED_PUBLIC_KEY_LENGTH = 33;
10
11
  export const P256_ECDSA_COMPACT_SIGNATURE_LENGTH = 64;
@@ -28,10 +29,12 @@ export const ReallyMeP256Ecdsa = {
28
29
  deriveKeyPair(secretKey) {
29
30
  return {
30
31
  publicKey: this.derivePublicKey(secretKey),
31
- secretKey: secretKey.slice(),
32
+ // Buffer.slice() aliases its input; the returned key must own its bytes.
33
+ secretKey: new Uint8Array(secretKey),
32
34
  };
33
35
  },
34
36
  derivePublicKey(secretKey) {
37
+ ensureByteArray(secretKey);
35
38
  if (secretKey.length !== P256_ECDSA_SECRET_KEY_LENGTH) {
36
39
  throw new ReallyMeCryptoError("invalid-input");
37
40
  }
@@ -43,6 +46,8 @@ export const ReallyMeP256Ecdsa = {
43
46
  }
44
47
  },
45
48
  sign(message, secretKey) {
49
+ ensureByteArray(message);
50
+ ensureByteArray(secretKey);
46
51
  if (secretKey.length !== P256_ECDSA_SECRET_KEY_LENGTH) {
47
52
  throw new ReallyMeCryptoError("invalid-input");
48
53
  }
@@ -58,6 +63,9 @@ export const ReallyMeP256Ecdsa = {
58
63
  }
59
64
  },
60
65
  verify(signature, message, publicKey) {
66
+ ensureByteArray(signature);
67
+ ensureByteArray(message);
68
+ ensureByteArray(publicKey);
61
69
  if (publicKey.length !== P256_ECDSA_COMPRESSED_PUBLIC_KEY_LENGTH) {
62
70
  throw new ReallyMeCryptoError("invalid-input");
63
71
  }
package/dist/p384Ecdh.js CHANGED
@@ -1,8 +1,9 @@
1
1
  // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
2
  //
3
- // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-License-Identifier: MIT OR Apache-2.0
4
4
  import { p384 } from "@noble/curves/nist.js";
5
5
  import { ReallyMeCryptoError } from "./errors.js";
6
+ import { ensureByteArray } from "./validateBytes.js";
6
7
  import { bestEffortClear } from "./memory.js";
7
8
  /**
8
9
  * P-384 ECDH backed by @noble/curves.
@@ -25,10 +26,12 @@ export const ReallyMeP384Ecdh = {
25
26
  deriveKeyPair(secretKey) {
26
27
  return {
27
28
  publicKey: this.derivePublicKey(secretKey),
28
- secretKey: secretKey.slice(),
29
+ // Buffer.slice() aliases its input; the returned key must own its bytes.
30
+ secretKey: new Uint8Array(secretKey),
29
31
  };
30
32
  },
31
33
  derivePublicKey(secretKey) {
34
+ ensureByteArray(secretKey);
32
35
  if (secretKey.length !== P384_ECDH_SECRET_KEY_LENGTH) {
33
36
  throw new ReallyMeCryptoError("invalid-input");
34
37
  }
@@ -40,6 +43,8 @@ export const ReallyMeP384Ecdh = {
40
43
  }
41
44
  },
42
45
  deriveSharedSecret(publicKey, secretKey) {
46
+ ensureByteArray(publicKey);
47
+ ensureByteArray(secretKey);
43
48
  if (publicKey.length !== P384_ECDH_COMPRESSED_PUBLIC_KEY_LENGTH ||
44
49
  secretKey.length !== P384_ECDH_SECRET_KEY_LENGTH) {
45
50
  throw new ReallyMeCryptoError("invalid-input");
package/dist/p384Ecdsa.js CHANGED
@@ -1,10 +1,11 @@
1
1
  // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
2
  //
3
- // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-License-Identifier: MIT OR Apache-2.0
4
4
  import { p384 } from "@noble/curves/nist.js";
5
5
  import { sha384 } from "@noble/hashes/sha2.js";
6
6
  import { decodeEcdsaDerSignature, encodeEcdsaDerSignature, } from "./encodeEcdsaDer.js";
7
7
  import { ReallyMeCryptoError } from "./errors.js";
8
+ import { ensureByteArray } from "./validateBytes.js";
8
9
  export const P384_ECDSA_SECRET_KEY_LENGTH = 48;
9
10
  export const P384_ECDSA_COMPRESSED_PUBLIC_KEY_LENGTH = 49;
10
11
  export const P384_ECDSA_COMPACT_SIGNATURE_LENGTH = 96;
@@ -26,10 +27,12 @@ export const ReallyMeP384Ecdsa = {
26
27
  deriveKeyPair(secretKey) {
27
28
  return {
28
29
  publicKey: this.derivePublicKey(secretKey),
29
- secretKey: secretKey.slice(),
30
+ // Buffer.slice() aliases its input; the returned key must own its bytes.
31
+ secretKey: new Uint8Array(secretKey),
30
32
  };
31
33
  },
32
34
  derivePublicKey(secretKey) {
35
+ ensureByteArray(secretKey);
33
36
  if (secretKey.length !== P384_ECDSA_SECRET_KEY_LENGTH) {
34
37
  throw new ReallyMeCryptoError("invalid-input");
35
38
  }
@@ -41,6 +44,8 @@ export const ReallyMeP384Ecdsa = {
41
44
  }
42
45
  },
43
46
  sign(message, secretKey) {
47
+ ensureByteArray(message);
48
+ ensureByteArray(secretKey);
44
49
  if (secretKey.length !== P384_ECDSA_SECRET_KEY_LENGTH) {
45
50
  throw new ReallyMeCryptoError("invalid-input");
46
51
  }
@@ -56,6 +61,9 @@ export const ReallyMeP384Ecdsa = {
56
61
  }
57
62
  },
58
63
  verify(signature, message, publicKey) {
64
+ ensureByteArray(signature);
65
+ ensureByteArray(message);
66
+ ensureByteArray(publicKey);
59
67
  if (publicKey.length !== P384_ECDSA_COMPRESSED_PUBLIC_KEY_LENGTH) {
60
68
  throw new ReallyMeCryptoError("invalid-input");
61
69
  }
package/dist/p521Ecdh.js CHANGED
@@ -1,8 +1,9 @@
1
1
  // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
2
  //
3
- // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-License-Identifier: MIT OR Apache-2.0
4
4
  import { p521 } from "@noble/curves/nist.js";
5
5
  import { ReallyMeCryptoError } from "./errors.js";
6
+ import { ensureByteArray } from "./validateBytes.js";
6
7
  import { bestEffortClear } from "./memory.js";
7
8
  /**
8
9
  * P-521 ECDH backed by @noble/curves.
@@ -25,10 +26,12 @@ export const ReallyMeP521Ecdh = {
25
26
  deriveKeyPair(secretKey) {
26
27
  return {
27
28
  publicKey: this.derivePublicKey(secretKey),
28
- secretKey: secretKey.slice(),
29
+ // Buffer.slice() aliases its input; the returned key must own its bytes.
30
+ secretKey: new Uint8Array(secretKey),
29
31
  };
30
32
  },
31
33
  derivePublicKey(secretKey) {
34
+ ensureByteArray(secretKey);
32
35
  if (secretKey.length !== P521_ECDH_SECRET_KEY_LENGTH) {
33
36
  throw new ReallyMeCryptoError("invalid-input");
34
37
  }
@@ -40,6 +43,8 @@ export const ReallyMeP521Ecdh = {
40
43
  }
41
44
  },
42
45
  deriveSharedSecret(publicKey, secretKey) {
46
+ ensureByteArray(publicKey);
47
+ ensureByteArray(secretKey);
43
48
  if (publicKey.length !== P521_ECDH_COMPRESSED_PUBLIC_KEY_LENGTH ||
44
49
  secretKey.length !== P521_ECDH_SECRET_KEY_LENGTH) {
45
50
  throw new ReallyMeCryptoError("invalid-input");
package/dist/p521Ecdsa.js CHANGED
@@ -1,10 +1,11 @@
1
1
  // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
2
  //
3
- // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-License-Identifier: MIT OR Apache-2.0
4
4
  import { p521 } from "@noble/curves/nist.js";
5
5
  import { sha512 } from "@noble/hashes/sha2.js";
6
6
  import { decodeEcdsaDerSignature, encodeEcdsaDerSignature, } from "./encodeEcdsaDer.js";
7
7
  import { ReallyMeCryptoError } from "./errors.js";
8
+ import { ensureByteArray } from "./validateBytes.js";
8
9
  export const P521_ECDSA_SECRET_KEY_LENGTH = 66;
9
10
  export const P521_ECDSA_COMPRESSED_PUBLIC_KEY_LENGTH = 67;
10
11
  export const P521_ECDSA_COMPACT_SIGNATURE_LENGTH = 132;
@@ -26,10 +27,12 @@ export const ReallyMeP521Ecdsa = {
26
27
  deriveKeyPair(secretKey) {
27
28
  return {
28
29
  publicKey: this.derivePublicKey(secretKey),
29
- secretKey: secretKey.slice(),
30
+ // Buffer.slice() aliases its input; the returned key must own its bytes.
31
+ secretKey: new Uint8Array(secretKey),
30
32
  };
31
33
  },
32
34
  derivePublicKey(secretKey) {
35
+ ensureByteArray(secretKey);
33
36
  if (secretKey.length !== P521_ECDSA_SECRET_KEY_LENGTH) {
34
37
  throw new ReallyMeCryptoError("invalid-input");
35
38
  }
@@ -41,6 +44,8 @@ export const ReallyMeP521Ecdsa = {
41
44
  }
42
45
  },
43
46
  sign(message, secretKey) {
47
+ ensureByteArray(message);
48
+ ensureByteArray(secretKey);
44
49
  if (secretKey.length !== P521_ECDSA_SECRET_KEY_LENGTH) {
45
50
  throw new ReallyMeCryptoError("invalid-input");
46
51
  }
@@ -56,6 +61,9 @@ export const ReallyMeP521Ecdsa = {
56
61
  }
57
62
  },
58
63
  verify(signature, message, publicKey) {
64
+ ensureByteArray(signature);
65
+ ensureByteArray(message);
66
+ ensureByteArray(publicKey);
59
67
  if (publicKey.length !== P521_ECDSA_COMPRESSED_PUBLIC_KEY_LENGTH) {
60
68
  throw new ReallyMeCryptoError("invalid-input");
61
69
  }
package/dist/pbkdf2.js CHANGED
@@ -1,9 +1,10 @@
1
1
  // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
2
  //
3
- // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-License-Identifier: MIT OR Apache-2.0
4
4
  import { pbkdf2 } from "@noble/hashes/pbkdf2.js";
5
5
  import { sha256, sha512 } from "@noble/hashes/sha2.js";
6
6
  import { ReallyMeCryptoError } from "./errors.js";
7
+ import { ensureByteArray } from "./validateBytes.js";
7
8
  export const PBKDF2_MIN_INPUT_LENGTH = 1;
8
9
  export const PBKDF2_MAX_INPUT_LENGTH = 4096;
9
10
  // Public derivation routes enforce a modern baseline. Historical hashes with a
@@ -42,6 +43,8 @@ export const ReallyMePbkdf2 = {
42
43
  },
43
44
  };
44
45
  function validate(password, salt, iterations, outputLength) {
46
+ ensureByteArray(password);
47
+ ensureByteArray(salt);
45
48
  if (password.length < PBKDF2_MIN_INPUT_LENGTH ||
46
49
  password.length > PBKDF2_MAX_INPUT_LENGTH ||
47
50
  salt.length < PBKDF2_MIN_INPUT_LENGTH ||
@@ -1,6 +1,6 @@
1
1
  // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
2
  //
3
- // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-License-Identifier: MIT OR Apache-2.0
4
4
  import { enumDesc, fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv2";
5
5
  /**
6
6
  * Describes the file reallyme/crypto/v1/crypto.proto.
package/dist/proto.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
2
  //
3
- // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-License-Identifier: MIT OR Apache-2.0
4
4
  import { create, fromBinary, toBinary } from "@bufbuild/protobuf";
5
5
  import { ReallyMeCryptoError } from "./errors.js";
6
6
  import { MAX_JWKS_KEYS, ReallyMeJwk } from "./jwk.js";
@@ -1,6 +1,6 @@
1
1
  // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
2
  //
3
- // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-License-Identifier: MIT OR Apache-2.0
4
4
  /** Providers compiled into the TypeScript package. */
5
5
  export const REALLYME_CRYPTO_PROVIDERS = [
6
6
  "@noble/curves",
package/dist/rsa.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
2
  //
3
- // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-License-Identifier: MIT OR Apache-2.0
4
4
  import { ReallyMeCryptoError } from "./errors.js";
5
5
  import { ensureByteArray, ensureByteArrayAtMost, MAX_CRYPTO_INPUT_LENGTH, } from "./validateBytes.js";
6
6
  import { requireReallyMeWasmProvider } from "./wasmProvider.js";
package/dist/secp256k1.js CHANGED
@@ -1,9 +1,10 @@
1
1
  // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
2
  //
3
- // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-License-Identifier: MIT OR Apache-2.0
4
4
  import { secp256k1 } from "@noble/curves/secp256k1.js";
5
5
  import { sha256 } from "@noble/hashes/sha2.js";
6
6
  import { ReallyMeCryptoError } from "./errors.js";
7
+ import { ensureByteArray } from "./validateBytes.js";
7
8
  /**
8
9
  * secp256k1 ECDSA backed by @noble/curves — the same pinned implementation
9
10
  * the TypeScript conformance lane proves vectors against.
@@ -36,11 +37,13 @@ export const ReallyMeSecp256k1 = {
36
37
  deriveKeyPair(secretKey) {
37
38
  return {
38
39
  publicKey: this.derivePublicKey(secretKey),
39
- secretKey: secretKey.slice(),
40
+ // Buffer.slice() aliases its input; the returned key must own its bytes.
41
+ secretKey: new Uint8Array(secretKey),
40
42
  };
41
43
  },
42
44
  /** Derives the 33-byte compressed SEC1 public key for a 32-byte secret. */
43
45
  derivePublicKey(secretKey) {
46
+ ensureByteArray(secretKey);
44
47
  if (secretKey.length !== SECP256K1_SECRET_KEY_LENGTH) {
45
48
  throw new ReallyMeCryptoError("invalid-input");
46
49
  }
@@ -56,6 +59,8 @@ export const ReallyMeSecp256k1 = {
56
59
  * SHA-256(message), returning the 64-byte compact low-S signature.
57
60
  */
58
61
  sign(message, secretKey) {
62
+ ensureByteArray(message);
63
+ ensureByteArray(secretKey);
59
64
  if (secretKey.length !== SECP256K1_SECRET_KEY_LENGTH) {
60
65
  throw new ReallyMeCryptoError("invalid-input");
61
66
  }
@@ -80,6 +85,9 @@ export const ReallyMeSecp256k1 = {
80
85
  * high-S twin (BIP 0062), which every workspace lane rejects.
81
86
  */
82
87
  verify(signature, message, publicKey) {
88
+ ensureByteArray(signature);
89
+ ensureByteArray(message);
90
+ ensureByteArray(publicKey);
83
91
  if (signature.length !== SECP256K1_SIGNATURE_LENGTH ||
84
92
  publicKey.length !== SECP256K1_COMPRESSED_PUBLIC_KEY_LENGTH) {
85
93
  throw new ReallyMeCryptoError("invalid-input");
package/dist/slhDsa.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
2
  //
3
- // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-License-Identifier: MIT OR Apache-2.0
4
4
  import { ReallyMeCryptoError } from "./errors.js";
5
5
  import { ensureByteArrayAtMost, ensureBytes, ensureIndependentByteArray, MAX_CRYPTO_INPUT_LENGTH, readIndependentByteArrayProperty, } from "./validateBytes.js";
6
6
  import { requireReallyMeWasmProvider } from "./wasmProvider.js";
@@ -1,5 +1,5 @@
1
1
  export declare const MAX_CRYPTO_INPUT_LENGTH = 1048576;
2
- export declare const ensureByteArray: (value: Uint8Array) => void;
2
+ export declare function ensureByteArray(value: unknown): asserts value is Uint8Array;
3
3
  export declare const ensureByteArrayAtMost: (value: Uint8Array, maximumLength: number) => void;
4
4
  export declare const ensureBytes: (value: Uint8Array, expectedLength: number) => void;
5
5
  export declare const byteArraysOverlap: (left: Uint8Array, right: Uint8Array) => boolean;
@@ -1,15 +1,31 @@
1
1
  // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
2
  //
3
- // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-License-Identifier: MIT OR Apache-2.0
4
4
  import { ReallyMeCryptoError } from "./errors.js";
5
5
  // Match the structured operation boundary so direct primitive facades cannot
6
6
  // ask a provider to copy or allocate an attacker-controlled unbounded buffer.
7
7
  export const MAX_CRYPTO_INPUT_LENGTH = 1_048_576;
8
- export const ensureByteArray = (value) => {
9
- if (!(value instanceof Uint8Array)) {
8
+ // The intrinsic getter reads the typed-array element kind from internal slots.
9
+ // instanceof rejects legitimate arrays from other realms, while an object's
10
+ // constructor name or own toStringTag can be spoofed.
11
+ const typedArrayTagGetter = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(Uint8Array.prototype), Symbol.toStringTag)?.get;
12
+ export function ensureByteArray(value) {
13
+ if (!ArrayBuffer.isView(value) || typedArrayTagGetter === undefined) {
10
14
  throw new ReallyMeCryptoError("invalid-input");
11
15
  }
12
- };
16
+ try {
17
+ const elementKind = Reflect.apply(typedArrayTagGetter, value, []);
18
+ if (elementKind !== "Uint8Array") {
19
+ throw new ReallyMeCryptoError("invalid-input");
20
+ }
21
+ // Detached views report zero length; validate the backing store before a
22
+ // provider can confuse them with an intentionally empty message.
23
+ Uint8Array.prototype.values.call(value);
24
+ }
25
+ catch {
26
+ throw new ReallyMeCryptoError("invalid-input");
27
+ }
28
+ }
13
29
  export const ensureByteArrayAtMost = (value, maximumLength) => {
14
30
  ensureByteArray(value);
15
31
  if (value.length > maximumLength) {
package/dist/wasm/LICENSE CHANGED
@@ -1,3 +1,29 @@
1
+ ReallyMe Crypto is licensed, at your option, under either the MIT License or
2
+ the Apache License, Version 2.0. The full text of both licenses follows.
3
+ Third-party components retain their own licenses and notices.
4
+
5
+ MIT License
6
+
7
+ Copyright © 2026 ReallyMe LLC.
8
+
9
+ Permission is hereby granted, free of charge, to any person obtaining a copy
10
+ of this software and associated documentation files (the "Software"), to deal
11
+ in the Software without restriction, including without limitation the rights
12
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
+ copies of the Software, and to permit persons to whom the Software is
14
+ furnished to do so, subject to the following conditions:
15
+
16
+ The above copyright notice and this permission notice shall be included in all
17
+ copies or substantial portions of the Software.
18
+
19
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25
+ SOFTWARE.
26
+
1
27
  Apache License
2
28
  Version 2.0, January 2004
3
29
  http://www.apache.org/licenses/
@@ -1,4 +1,4 @@
1
1
  // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
2
  //
3
- // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-License-Identifier: MIT OR Apache-2.0
4
4
  export {};
@@ -1,6 +1,6 @@
1
1
  // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
2
  //
3
- // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-License-Identifier: MIT OR Apache-2.0
4
4
  import { ReallyMeCryptoError } from "./errors.js";
5
5
  let installedProvider;
6
6
  const requireObject = (module) => {
package/dist/x25519.js CHANGED
@@ -1,8 +1,9 @@
1
1
  // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
2
  //
3
- // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-License-Identifier: MIT OR Apache-2.0
4
4
  import { x25519 } from "@noble/curves/ed25519.js";
5
5
  import { ReallyMeCryptoError } from "./errors.js";
6
+ import { ensureByteArray } from "./validateBytes.js";
6
7
  /**
7
8
  * X25519 key agreement backed by @noble/curves — the same pinned
8
9
  * implementation the TypeScript conformance lane proves vectors against.
@@ -28,11 +29,13 @@ export const ReallyMeX25519 = {
28
29
  deriveKeyPair(secretKey) {
29
30
  return {
30
31
  publicKey: this.derivePublicKey(secretKey),
31
- secretKey: secretKey.slice(),
32
+ // Buffer.slice() aliases its input; the returned key must own its bytes.
33
+ secretKey: new Uint8Array(secretKey),
32
34
  };
33
35
  },
34
36
  /** Derives the 32-byte X25519 public key from a 32-byte secret. */
35
37
  derivePublicKey(secretKey) {
38
+ ensureByteArray(secretKey);
36
39
  if (secretKey.length !== X25519_SECRET_KEY_LENGTH) {
37
40
  throw new ReallyMeCryptoError("invalid-input");
38
41
  }
@@ -45,6 +48,8 @@ export const ReallyMeX25519 = {
45
48
  },
46
49
  /** Derives the raw 32-byte X25519 shared secret. */
47
50
  deriveSharedSecret(publicKey, secretKey) {
51
+ ensureByteArray(publicKey);
52
+ ensureByteArray(secretKey);
48
53
  if (publicKey.length !== X25519_PUBLIC_KEY_LENGTH ||
49
54
  secretKey.length !== X25519_SECRET_KEY_LENGTH) {
50
55
  throw new ReallyMeCryptoError("invalid-input");
package/dist/xWing.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
2
  //
3
- // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-License-Identifier: MIT OR Apache-2.0
4
4
  import { ReallyMeCryptoError } from "./errors.js";
5
5
  import { ensureBytes, readIndependentByteArrayProperty, readIndependentProviderBytes, } from "./validateBytes.js";
6
6
  import { requireReallyMeWasmProvider } from "./wasmProvider.js";
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@reallyme/crypto",
3
- "version": "0.3.6",
3
+ "version": "0.3.7",
4
4
  "description": "ReallyMe crypto SDK for TypeScript/JavaScript with an explicit, pinned provider set.",
5
- "license": "Apache-2.0",
5
+ "license": "MIT OR Apache-2.0",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "git+https://github.com/reallyme/crypto.git",
@@ -55,7 +55,7 @@
55
55
  "@bufbuild/protobuf": "2.14.1",
56
56
  "@noble/curves": "2.4.0",
57
57
  "@noble/hashes": "2.4.0",
58
- "@reallyme/codec": "0.2.2"
58
+ "@reallyme/codec": "0.2.3"
59
59
  },
60
60
  "devDependencies": {
61
61
  "typescript": "7.0.2"