@reallyme/crypto 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.
Files changed (75) hide show
  1. package/README.md +140 -0
  2. package/dist/aead.d.ts +9 -0
  3. package/dist/aead.js +62 -0
  4. package/dist/aesKw.d.ts +10 -0
  5. package/dist/aesKw.js +45 -0
  6. package/dist/algorithms.d.ts +18 -0
  7. package/dist/algorithms.js +64 -0
  8. package/dist/argon2id.d.ts +8 -0
  9. package/dist/argon2id.js +40 -0
  10. package/dist/bip340Schnorr.d.ts +26 -0
  11. package/dist/bip340Schnorr.js +72 -0
  12. package/dist/codecs.d.ts +35 -0
  13. package/dist/codecs.js +216 -0
  14. package/dist/cryptoFacade.d.ts +51 -0
  15. package/dist/cryptoFacade.js +329 -0
  16. package/dist/digest.d.ts +14 -0
  17. package/dist/digest.js +33 -0
  18. package/dist/ed25519.d.ts +34 -0
  19. package/dist/ed25519.js +78 -0
  20. package/dist/encodeEcdsaDer.d.ts +2 -0
  21. package/dist/encodeEcdsaDer.js +141 -0
  22. package/dist/errors.d.ts +10 -0
  23. package/dist/errors.js +11 -0
  24. package/dist/hkdf.d.ts +7 -0
  25. package/dist/hkdf.js +27 -0
  26. package/dist/hmac.d.ts +9 -0
  27. package/dist/hmac.js +50 -0
  28. package/dist/hpke.d.ts +15 -0
  29. package/dist/hpke.js +59 -0
  30. package/dist/index.d.ts +41 -0
  31. package/dist/index.js +31 -0
  32. package/dist/jwk.d.ts +42 -0
  33. package/dist/jwk.js +289 -0
  34. package/dist/mlDsa.d.ts +18 -0
  35. package/dist/mlDsa.js +85 -0
  36. package/dist/mlKem.d.ts +25 -0
  37. package/dist/mlKem.js +95 -0
  38. package/dist/p256Ecdh.d.ts +22 -0
  39. package/dist/p256Ecdh.js +53 -0
  40. package/dist/p256Ecdsa.d.ts +25 -0
  41. package/dist/p256Ecdsa.js +85 -0
  42. package/dist/p384Ecdsa.d.ts +23 -0
  43. package/dist/p384Ecdsa.js +83 -0
  44. package/dist/p521Ecdsa.d.ts +23 -0
  45. package/dist/p521Ecdsa.js +83 -0
  46. package/dist/pbkdf2.d.ts +28 -0
  47. package/dist/pbkdf2.js +57 -0
  48. package/dist/proto/generated/reallyme/crypto/v1/crypto_pb.d.ts +618 -0
  49. package/dist/proto/generated/reallyme/crypto/v1/crypto_pb.js +523 -0
  50. package/dist/proto.d.ts +25 -0
  51. package/dist/proto.js +342 -0
  52. package/dist/providerCatalog.d.ts +9 -0
  53. package/dist/providerCatalog.js +15 -0
  54. package/dist/rsa.d.ts +13 -0
  55. package/dist/rsa.js +102 -0
  56. package/dist/secp256k1.d.ts +47 -0
  57. package/dist/secp256k1.js +106 -0
  58. package/dist/slhDsa.d.ts +15 -0
  59. package/dist/slhDsa.js +54 -0
  60. package/dist/validateBytes.d.ts +2 -0
  61. package/dist/validateBytes.js +20 -0
  62. package/dist/verifySignature.d.ts +1 -0
  63. package/dist/verifySignature.js +9 -0
  64. package/dist/wasm/LICENSE +201 -0
  65. package/dist/wasm/reallyme_crypto_wasm.js +1319 -0
  66. package/dist/wasm/reallyme_crypto_wasm_bg.wasm +0 -0
  67. package/dist/wasmModuleTypes.d.ts +72 -0
  68. package/dist/wasmModuleTypes.js +4 -0
  69. package/dist/wasmProvider.d.ts +94 -0
  70. package/dist/wasmProvider.js +173 -0
  71. package/dist/x25519.d.ts +28 -0
  72. package/dist/x25519.js +66 -0
  73. package/dist/xWing.d.ts +23 -0
  74. package/dist/xWing.js +86 -0
  75. package/package.json +48 -0
@@ -0,0 +1,85 @@
1
+ // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
+ //
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ import { p256 } from "@noble/curves/nist.js";
5
+ import { sha256 } from "@noble/hashes/sha2.js";
6
+ import { decodeEcdsaDerSignature, encodeEcdsaDerSignature, } from "./encodeEcdsaDer.js";
7
+ import { ReallyMeCryptoError } from "./errors.js";
8
+ export const P256_ECDSA_SECRET_KEY_LENGTH = 32;
9
+ export const P256_ECDSA_COMPRESSED_PUBLIC_KEY_LENGTH = 33;
10
+ export const P256_ECDSA_COMPACT_SIGNATURE_LENGTH = 64;
11
+ export const P256_ECDSA_DER_SIGNATURE_MAX_LENGTH = 72;
12
+ /**
13
+ * P-256 ECDSA backed by @noble/curves.
14
+ *
15
+ * The workspace contract signs SHA-256(message) exactly once and uses DER
16
+ * encoding for signatures because that is what X.509, JOSE, and the Rust
17
+ * P-256 lane expose. We intentionally preserve the Rust vector bytes instead
18
+ * of applying a TypeScript-only low-S normalization policy.
19
+ */
20
+ export const ReallyMeP256Ecdsa = {
21
+ generateKeyPair() {
22
+ const secretKey = p256.utils.randomSecretKey();
23
+ return {
24
+ publicKey: p256.getPublicKey(secretKey, true),
25
+ secretKey,
26
+ };
27
+ },
28
+ deriveKeyPair(secretKey) {
29
+ return {
30
+ publicKey: this.derivePublicKey(secretKey),
31
+ secretKey: secretKey.slice(),
32
+ };
33
+ },
34
+ derivePublicKey(secretKey) {
35
+ if (secretKey.length !== P256_ECDSA_SECRET_KEY_LENGTH) {
36
+ throw new ReallyMeCryptoError("invalid-input");
37
+ }
38
+ try {
39
+ return p256.getPublicKey(secretKey, true);
40
+ }
41
+ catch {
42
+ throw new ReallyMeCryptoError("invalid-input");
43
+ }
44
+ },
45
+ sign(message, secretKey) {
46
+ if (secretKey.length !== P256_ECDSA_SECRET_KEY_LENGTH) {
47
+ throw new ReallyMeCryptoError("invalid-input");
48
+ }
49
+ try {
50
+ const compactSignature = p256.sign(sha256(message), secretKey, {
51
+ lowS: false,
52
+ prehash: false,
53
+ });
54
+ return encodeEcdsaDerSignature(compactSignature, P256_ECDSA_SECRET_KEY_LENGTH);
55
+ }
56
+ catch {
57
+ throw new ReallyMeCryptoError("invalid-input");
58
+ }
59
+ },
60
+ verify(signature, message, publicKey) {
61
+ if (publicKey.length !== P256_ECDSA_COMPRESSED_PUBLIC_KEY_LENGTH) {
62
+ throw new ReallyMeCryptoError("invalid-input");
63
+ }
64
+ let compactSignature;
65
+ try {
66
+ p256.Point.fromBytes(publicKey);
67
+ compactSignature = decodeEcdsaDerSignature(signature, P256_ECDSA_SECRET_KEY_LENGTH, P256_ECDSA_DER_SIGNATURE_MAX_LENGTH);
68
+ }
69
+ catch {
70
+ throw new ReallyMeCryptoError("invalid-input");
71
+ }
72
+ try {
73
+ const valid = p256.verify(compactSignature, sha256(message), publicKey, {
74
+ lowS: false,
75
+ prehash: false,
76
+ });
77
+ if (!valid) {
78
+ throw new ReallyMeCryptoError("invalid-signature");
79
+ }
80
+ }
81
+ catch {
82
+ throw new ReallyMeCryptoError("invalid-signature");
83
+ }
84
+ },
85
+ };
@@ -0,0 +1,23 @@
1
+ export declare const P384_ECDSA_SECRET_KEY_LENGTH = 48;
2
+ export declare const P384_ECDSA_COMPRESSED_PUBLIC_KEY_LENGTH = 49;
3
+ export declare const P384_ECDSA_COMPACT_SIGNATURE_LENGTH = 96;
4
+ export declare const P384_ECDSA_DER_SIGNATURE_MAX_LENGTH = 104;
5
+ /**
6
+ * P-384 ECDSA backed by @noble/curves.
7
+ *
8
+ * The package signs SHA-384(message) exactly once and preserves DER signatures
9
+ * byte-for-byte with the Rust/Swift vector contract.
10
+ */
11
+ export declare const ReallyMeP384Ecdsa: {
12
+ readonly generateKeyPair: () => {
13
+ publicKey: Uint8Array;
14
+ secretKey: Uint8Array;
15
+ };
16
+ readonly deriveKeyPair: (secretKey: Uint8Array) => {
17
+ publicKey: Uint8Array;
18
+ secretKey: Uint8Array;
19
+ };
20
+ readonly derivePublicKey: (secretKey: Uint8Array) => Uint8Array;
21
+ readonly sign: (message: Uint8Array, secretKey: Uint8Array) => Uint8Array;
22
+ readonly verify: (signature: Uint8Array, message: Uint8Array, publicKey: Uint8Array) => void;
23
+ };
@@ -0,0 +1,83 @@
1
+ // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
+ //
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ import { p384 } from "@noble/curves/nist.js";
5
+ import { sha384 } from "@noble/hashes/sha2.js";
6
+ import { decodeEcdsaDerSignature, encodeEcdsaDerSignature, } from "./encodeEcdsaDer.js";
7
+ import { ReallyMeCryptoError } from "./errors.js";
8
+ export const P384_ECDSA_SECRET_KEY_LENGTH = 48;
9
+ export const P384_ECDSA_COMPRESSED_PUBLIC_KEY_LENGTH = 49;
10
+ export const P384_ECDSA_COMPACT_SIGNATURE_LENGTH = 96;
11
+ export const P384_ECDSA_DER_SIGNATURE_MAX_LENGTH = 104;
12
+ /**
13
+ * P-384 ECDSA backed by @noble/curves.
14
+ *
15
+ * The package signs SHA-384(message) exactly once and preserves DER signatures
16
+ * byte-for-byte with the Rust/Swift vector contract.
17
+ */
18
+ export const ReallyMeP384Ecdsa = {
19
+ generateKeyPair() {
20
+ const secretKey = p384.utils.randomSecretKey();
21
+ return {
22
+ publicKey: p384.getPublicKey(secretKey, true),
23
+ secretKey,
24
+ };
25
+ },
26
+ deriveKeyPair(secretKey) {
27
+ return {
28
+ publicKey: this.derivePublicKey(secretKey),
29
+ secretKey: secretKey.slice(),
30
+ };
31
+ },
32
+ derivePublicKey(secretKey) {
33
+ if (secretKey.length !== P384_ECDSA_SECRET_KEY_LENGTH) {
34
+ throw new ReallyMeCryptoError("invalid-input");
35
+ }
36
+ try {
37
+ return p384.getPublicKey(secretKey, true);
38
+ }
39
+ catch {
40
+ throw new ReallyMeCryptoError("invalid-input");
41
+ }
42
+ },
43
+ sign(message, secretKey) {
44
+ if (secretKey.length !== P384_ECDSA_SECRET_KEY_LENGTH) {
45
+ throw new ReallyMeCryptoError("invalid-input");
46
+ }
47
+ try {
48
+ const compactSignature = p384.sign(sha384(message), secretKey, {
49
+ lowS: false,
50
+ prehash: false,
51
+ });
52
+ return encodeEcdsaDerSignature(compactSignature, P384_ECDSA_SECRET_KEY_LENGTH);
53
+ }
54
+ catch {
55
+ throw new ReallyMeCryptoError("invalid-input");
56
+ }
57
+ },
58
+ verify(signature, message, publicKey) {
59
+ if (publicKey.length !== P384_ECDSA_COMPRESSED_PUBLIC_KEY_LENGTH) {
60
+ throw new ReallyMeCryptoError("invalid-input");
61
+ }
62
+ let compactSignature;
63
+ try {
64
+ p384.Point.fromBytes(publicKey);
65
+ compactSignature = decodeEcdsaDerSignature(signature, P384_ECDSA_SECRET_KEY_LENGTH, P384_ECDSA_DER_SIGNATURE_MAX_LENGTH);
66
+ }
67
+ catch {
68
+ throw new ReallyMeCryptoError("invalid-input");
69
+ }
70
+ try {
71
+ const valid = p384.verify(compactSignature, sha384(message), publicKey, {
72
+ lowS: false,
73
+ prehash: false,
74
+ });
75
+ if (!valid) {
76
+ throw new ReallyMeCryptoError("invalid-signature");
77
+ }
78
+ }
79
+ catch {
80
+ throw new ReallyMeCryptoError("invalid-signature");
81
+ }
82
+ },
83
+ };
@@ -0,0 +1,23 @@
1
+ export declare const P521_ECDSA_SECRET_KEY_LENGTH = 66;
2
+ export declare const P521_ECDSA_COMPRESSED_PUBLIC_KEY_LENGTH = 67;
3
+ export declare const P521_ECDSA_COMPACT_SIGNATURE_LENGTH = 132;
4
+ export declare const P521_ECDSA_DER_SIGNATURE_MAX_LENGTH = 139;
5
+ /**
6
+ * P-521 ECDSA backed by @noble/curves.
7
+ *
8
+ * P-521 DER signatures can require long-form sequence lengths; the shared DER
9
+ * helper enforces canonical positive INTEGER encoding before verification.
10
+ */
11
+ export declare const ReallyMeP521Ecdsa: {
12
+ readonly generateKeyPair: () => {
13
+ publicKey: Uint8Array;
14
+ secretKey: Uint8Array;
15
+ };
16
+ readonly deriveKeyPair: (secretKey: Uint8Array) => {
17
+ publicKey: Uint8Array;
18
+ secretKey: Uint8Array;
19
+ };
20
+ readonly derivePublicKey: (secretKey: Uint8Array) => Uint8Array;
21
+ readonly sign: (message: Uint8Array, secretKey: Uint8Array) => Uint8Array;
22
+ readonly verify: (signature: Uint8Array, message: Uint8Array, publicKey: Uint8Array) => void;
23
+ };
@@ -0,0 +1,83 @@
1
+ // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
+ //
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ import { p521 } from "@noble/curves/nist.js";
5
+ import { sha512 } from "@noble/hashes/sha2.js";
6
+ import { decodeEcdsaDerSignature, encodeEcdsaDerSignature, } from "./encodeEcdsaDer.js";
7
+ import { ReallyMeCryptoError } from "./errors.js";
8
+ export const P521_ECDSA_SECRET_KEY_LENGTH = 66;
9
+ export const P521_ECDSA_COMPRESSED_PUBLIC_KEY_LENGTH = 67;
10
+ export const P521_ECDSA_COMPACT_SIGNATURE_LENGTH = 132;
11
+ export const P521_ECDSA_DER_SIGNATURE_MAX_LENGTH = 139;
12
+ /**
13
+ * P-521 ECDSA backed by @noble/curves.
14
+ *
15
+ * P-521 DER signatures can require long-form sequence lengths; the shared DER
16
+ * helper enforces canonical positive INTEGER encoding before verification.
17
+ */
18
+ export const ReallyMeP521Ecdsa = {
19
+ generateKeyPair() {
20
+ const secretKey = p521.utils.randomSecretKey();
21
+ return {
22
+ publicKey: p521.getPublicKey(secretKey, true),
23
+ secretKey,
24
+ };
25
+ },
26
+ deriveKeyPair(secretKey) {
27
+ return {
28
+ publicKey: this.derivePublicKey(secretKey),
29
+ secretKey: secretKey.slice(),
30
+ };
31
+ },
32
+ derivePublicKey(secretKey) {
33
+ if (secretKey.length !== P521_ECDSA_SECRET_KEY_LENGTH) {
34
+ throw new ReallyMeCryptoError("invalid-input");
35
+ }
36
+ try {
37
+ return p521.getPublicKey(secretKey, true);
38
+ }
39
+ catch {
40
+ throw new ReallyMeCryptoError("invalid-input");
41
+ }
42
+ },
43
+ sign(message, secretKey) {
44
+ if (secretKey.length !== P521_ECDSA_SECRET_KEY_LENGTH) {
45
+ throw new ReallyMeCryptoError("invalid-input");
46
+ }
47
+ try {
48
+ const compactSignature = p521.sign(sha512(message), secretKey, {
49
+ lowS: false,
50
+ prehash: false,
51
+ });
52
+ return encodeEcdsaDerSignature(compactSignature, P521_ECDSA_SECRET_KEY_LENGTH);
53
+ }
54
+ catch {
55
+ throw new ReallyMeCryptoError("invalid-input");
56
+ }
57
+ },
58
+ verify(signature, message, publicKey) {
59
+ if (publicKey.length !== P521_ECDSA_COMPRESSED_PUBLIC_KEY_LENGTH) {
60
+ throw new ReallyMeCryptoError("invalid-input");
61
+ }
62
+ let compactSignature;
63
+ try {
64
+ p521.Point.fromBytes(publicKey);
65
+ compactSignature = decodeEcdsaDerSignature(signature, P521_ECDSA_SECRET_KEY_LENGTH, P521_ECDSA_DER_SIGNATURE_MAX_LENGTH);
66
+ }
67
+ catch {
68
+ throw new ReallyMeCryptoError("invalid-input");
69
+ }
70
+ try {
71
+ const valid = p521.verify(compactSignature, sha512(message), publicKey, {
72
+ lowS: false,
73
+ prehash: false,
74
+ });
75
+ if (!valid) {
76
+ throw new ReallyMeCryptoError("invalid-signature");
77
+ }
78
+ }
79
+ catch {
80
+ throw new ReallyMeCryptoError("invalid-signature");
81
+ }
82
+ },
83
+ };
@@ -0,0 +1,28 @@
1
+ export declare const PBKDF2_MIN_INPUT_LENGTH = 1;
2
+ export declare const PBKDF2_MAX_INPUT_LENGTH = 4096;
3
+ export declare const PBKDF2_MIN_ITERATIONS = 1;
4
+ export declare const PBKDF2_MIN_OUTPUT_LENGTH = 1;
5
+ export declare const PBKDF2_MAX_OUTPUT_LENGTH = 4096;
6
+ /**
7
+ * OWASP Password Storage Cheat Sheet minimum iteration counts for deriving a
8
+ * *new* password key.
9
+ * The primitive does not enforce these (it must remain able to verify
10
+ * externally created hashes), so callers creating new key material SHOULD
11
+ * pass at least the value for their PRF.
12
+ */
13
+ export declare const PBKDF2_RECOMMENDED_MIN_ITERATIONS_SHA256 = 600000;
14
+ export declare const PBKDF2_RECOMMENDED_MIN_ITERATIONS_SHA512 = 220000;
15
+ export declare const ReallyMePbkdf2: {
16
+ /**
17
+ * PBKDF2-HMAC-SHA-256. For a new password key pass at least
18
+ * {@link PBKDF2_RECOMMENDED_MIN_ITERATIONS_SHA256} iterations; lower counts
19
+ * are accepted only to verify hashes created elsewhere.
20
+ */
21
+ readonly deriveHmacSha256: (password: Uint8Array, salt: Uint8Array, iterations: number, outputLength: number) => Uint8Array;
22
+ /**
23
+ * PBKDF2-HMAC-SHA-512. For a new password key pass at least
24
+ * {@link PBKDF2_RECOMMENDED_MIN_ITERATIONS_SHA512} iterations; lower counts
25
+ * are accepted only to verify hashes created elsewhere.
26
+ */
27
+ readonly deriveHmacSha512: (password: Uint8Array, salt: Uint8Array, iterations: number, outputLength: number) => Uint8Array;
28
+ };
package/dist/pbkdf2.js ADDED
@@ -0,0 +1,57 @@
1
+ // SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2
+ //
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ import { pbkdf2 } from "@noble/hashes/pbkdf2.js";
5
+ import { sha256, sha512 } from "@noble/hashes/sha2.js";
6
+ import { ReallyMeCryptoError } from "./errors.js";
7
+ export const PBKDF2_MIN_INPUT_LENGTH = 1;
8
+ export const PBKDF2_MAX_INPUT_LENGTH = 4096;
9
+ // The primitive accepts any count >= 1 so it can verify PBKDF2 hashes created
10
+ // elsewhere at their stored iteration count (a required interop use), matching
11
+ // the Rust lane. It is NOT a security floor; see the recommended minimums
12
+ // below for deriving *new* password keys.
13
+ export const PBKDF2_MIN_ITERATIONS = 1;
14
+ export const PBKDF2_MIN_OUTPUT_LENGTH = 1;
15
+ export const PBKDF2_MAX_OUTPUT_LENGTH = 4096;
16
+ /**
17
+ * OWASP Password Storage Cheat Sheet minimum iteration counts for deriving a
18
+ * *new* password key.
19
+ * The primitive does not enforce these (it must remain able to verify
20
+ * externally created hashes), so callers creating new key material SHOULD
21
+ * pass at least the value for their PRF.
22
+ */
23
+ export const PBKDF2_RECOMMENDED_MIN_ITERATIONS_SHA256 = 600_000;
24
+ export const PBKDF2_RECOMMENDED_MIN_ITERATIONS_SHA512 = 220_000;
25
+ export const ReallyMePbkdf2 = {
26
+ /**
27
+ * PBKDF2-HMAC-SHA-256. For a new password key pass at least
28
+ * {@link PBKDF2_RECOMMENDED_MIN_ITERATIONS_SHA256} iterations; lower counts
29
+ * are accepted only to verify hashes created elsewhere.
30
+ */
31
+ deriveHmacSha256(password, salt, iterations, outputLength) {
32
+ validate(password, salt, iterations, outputLength);
33
+ return pbkdf2(sha256, password, salt, { c: iterations, dkLen: outputLength });
34
+ },
35
+ /**
36
+ * PBKDF2-HMAC-SHA-512. For a new password key pass at least
37
+ * {@link PBKDF2_RECOMMENDED_MIN_ITERATIONS_SHA512} iterations; lower counts
38
+ * are accepted only to verify hashes created elsewhere.
39
+ */
40
+ deriveHmacSha512(password, salt, iterations, outputLength) {
41
+ validate(password, salt, iterations, outputLength);
42
+ return pbkdf2(sha512, password, salt, { c: iterations, dkLen: outputLength });
43
+ },
44
+ };
45
+ function validate(password, salt, iterations, outputLength) {
46
+ if (password.length < PBKDF2_MIN_INPUT_LENGTH ||
47
+ password.length > PBKDF2_MAX_INPUT_LENGTH ||
48
+ salt.length < PBKDF2_MIN_INPUT_LENGTH ||
49
+ salt.length > PBKDF2_MAX_INPUT_LENGTH ||
50
+ !Number.isInteger(iterations) ||
51
+ iterations < PBKDF2_MIN_ITERATIONS ||
52
+ !Number.isInteger(outputLength) ||
53
+ outputLength < PBKDF2_MIN_OUTPUT_LENGTH ||
54
+ outputLength > PBKDF2_MAX_OUTPUT_LENGTH) {
55
+ throw new ReallyMeCryptoError("invalid-input");
56
+ }
57
+ }