@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.
- package/README.md +140 -0
- package/dist/aead.d.ts +9 -0
- package/dist/aead.js +62 -0
- package/dist/aesKw.d.ts +10 -0
- package/dist/aesKw.js +45 -0
- package/dist/algorithms.d.ts +18 -0
- package/dist/algorithms.js +64 -0
- package/dist/argon2id.d.ts +8 -0
- package/dist/argon2id.js +40 -0
- package/dist/bip340Schnorr.d.ts +26 -0
- package/dist/bip340Schnorr.js +72 -0
- package/dist/codecs.d.ts +35 -0
- package/dist/codecs.js +216 -0
- package/dist/cryptoFacade.d.ts +51 -0
- package/dist/cryptoFacade.js +329 -0
- package/dist/digest.d.ts +14 -0
- package/dist/digest.js +33 -0
- package/dist/ed25519.d.ts +34 -0
- package/dist/ed25519.js +78 -0
- package/dist/encodeEcdsaDer.d.ts +2 -0
- package/dist/encodeEcdsaDer.js +141 -0
- package/dist/errors.d.ts +10 -0
- package/dist/errors.js +11 -0
- package/dist/hkdf.d.ts +7 -0
- package/dist/hkdf.js +27 -0
- package/dist/hmac.d.ts +9 -0
- package/dist/hmac.js +50 -0
- package/dist/hpke.d.ts +15 -0
- package/dist/hpke.js +59 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.js +31 -0
- package/dist/jwk.d.ts +42 -0
- package/dist/jwk.js +289 -0
- package/dist/mlDsa.d.ts +18 -0
- package/dist/mlDsa.js +85 -0
- package/dist/mlKem.d.ts +25 -0
- package/dist/mlKem.js +95 -0
- package/dist/p256Ecdh.d.ts +22 -0
- package/dist/p256Ecdh.js +53 -0
- package/dist/p256Ecdsa.d.ts +25 -0
- package/dist/p256Ecdsa.js +85 -0
- package/dist/p384Ecdsa.d.ts +23 -0
- package/dist/p384Ecdsa.js +83 -0
- package/dist/p521Ecdsa.d.ts +23 -0
- package/dist/p521Ecdsa.js +83 -0
- package/dist/pbkdf2.d.ts +28 -0
- package/dist/pbkdf2.js +57 -0
- package/dist/proto/generated/reallyme/crypto/v1/crypto_pb.d.ts +618 -0
- package/dist/proto/generated/reallyme/crypto/v1/crypto_pb.js +523 -0
- package/dist/proto.d.ts +25 -0
- package/dist/proto.js +342 -0
- package/dist/providerCatalog.d.ts +9 -0
- package/dist/providerCatalog.js +15 -0
- package/dist/rsa.d.ts +13 -0
- package/dist/rsa.js +102 -0
- package/dist/secp256k1.d.ts +47 -0
- package/dist/secp256k1.js +106 -0
- package/dist/slhDsa.d.ts +15 -0
- package/dist/slhDsa.js +54 -0
- package/dist/validateBytes.d.ts +2 -0
- package/dist/validateBytes.js +20 -0
- package/dist/verifySignature.d.ts +1 -0
- package/dist/verifySignature.js +9 -0
- package/dist/wasm/LICENSE +201 -0
- package/dist/wasm/reallyme_crypto_wasm.js +1319 -0
- package/dist/wasm/reallyme_crypto_wasm_bg.wasm +0 -0
- package/dist/wasmModuleTypes.d.ts +72 -0
- package/dist/wasmModuleTypes.js +4 -0
- package/dist/wasmProvider.d.ts +94 -0
- package/dist/wasmProvider.js +173 -0
- package/dist/x25519.d.ts +28 -0
- package/dist/x25519.js +66 -0
- package/dist/xWing.d.ts +23 -0
- package/dist/xWing.js +86 -0
- package/package.json +48 -0
package/README.md
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
|
|
3
|
+
|
|
4
|
+
SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
-->
|
|
6
|
+
|
|
7
|
+
# ReallyMeCrypto TypeScript
|
|
8
|
+
|
|
9
|
+
`@reallyme/crypto` is the TypeScript package for the ReallyMe Crypto workspace.
|
|
10
|
+
It gives Node and browser applications the same algorithm identifiers, byte
|
|
11
|
+
formats, provider policy, and fail-closed verification behavior used by the
|
|
12
|
+
Rust, Swift, and Kotlin packages.
|
|
13
|
+
|
|
14
|
+
The npm API is synchronous. WebCrypto is intentionally not part of this facade:
|
|
15
|
+
adding an async-only provider would change every call site. Primitives that
|
|
16
|
+
should stay shared with Rust are provided by the generated WASM module.
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
npm install @reallyme/crypto
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Quick Start
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
import { ReallyMeCrypto } from "@reallyme/crypto";
|
|
28
|
+
|
|
29
|
+
const digest = ReallyMeCrypto.hash(
|
|
30
|
+
"SHA2-256",
|
|
31
|
+
new TextEncoder().encode("abc"),
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
const tag = ReallyMeCrypto.authenticate(
|
|
35
|
+
"HMAC-SHA-256",
|
|
36
|
+
key,
|
|
37
|
+
new TextEncoder().encode("message"),
|
|
38
|
+
);
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Signature verification throws `ReallyMeCryptoError` on invalid signatures. It
|
|
42
|
+
does not return a boolean that can be accidentally ignored.
|
|
43
|
+
|
|
44
|
+
## Provider Model
|
|
45
|
+
|
|
46
|
+
Provider selection is explicit:
|
|
47
|
+
|
|
48
|
+
- `@noble/curves` and `@noble/hashes`, pinned to the versions exercised by the
|
|
49
|
+
TypeScript conformance lane, for JavaScript-native classical primitives.
|
|
50
|
+
- The ReallyMe Rust WASM lane for primitives that should stay shared with Rust,
|
|
51
|
+
including ML-KEM, ML-DSA, SLH-DSA, X-Wing, Argon2id, AES-GCM-SIV, XChaCha,
|
|
52
|
+
AES-KW, HPKE, RSA verify, and codecs.
|
|
53
|
+
|
|
54
|
+
The public API has two layers:
|
|
55
|
+
|
|
56
|
+
- algorithm-specific objects, such as `ReallyMeEd25519`, `ReallyMeX25519`,
|
|
57
|
+
`ReallyMeP256Ecdh`, `ReallyMeSecp256k1`, and `ReallyMeCodecs`;
|
|
58
|
+
- `ReallyMeCrypto`, a typed facade keyed by repository-wide algorithm string
|
|
59
|
+
unions.
|
|
60
|
+
|
|
61
|
+
Reserved identifiers, future contract entries, and unsupported overload shapes
|
|
62
|
+
throw `ReallyMeCryptoError` with code `unsupported-algorithm`. The npm package
|
|
63
|
+
does not silently fall back to a different provider. The complete TypeScript
|
|
64
|
+
lane is tracked in [PROVIDER_POLICY.md](../../PROVIDER_POLICY.md).
|
|
65
|
+
|
|
66
|
+
## Protobuf
|
|
67
|
+
|
|
68
|
+
The package exports generated protobuf identifiers and boundary adapters from
|
|
69
|
+
`@reallyme/crypto/proto`.
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
import {
|
|
73
|
+
HashAlgorithm,
|
|
74
|
+
hashAlgorithmFromProto,
|
|
75
|
+
hashAlgorithmToProto,
|
|
76
|
+
} from "@reallyme/crypto/proto";
|
|
77
|
+
|
|
78
|
+
const facadeAlgorithm = hashAlgorithmFromProto(HashAlgorithm.SHA2_256);
|
|
79
|
+
const protoAlgorithm = hashAlgorithmToProto(facadeAlgorithm);
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
`UNSPECIFIED`, unrecognized values, and private multicodec identifiers throw
|
|
83
|
+
`ReallyMeCryptoError` with code `unsupported-algorithm`.
|
|
84
|
+
|
|
85
|
+
## WASM Providers
|
|
86
|
+
|
|
87
|
+
WASM-backed operations require the generated module to be initialized and
|
|
88
|
+
installed before use. If the provider is missing, those operations fail closed
|
|
89
|
+
with `provider-failure`.
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
import { readFileSync } from "node:fs";
|
|
93
|
+
import { installReallyMeWasmProvider } from "@reallyme/crypto";
|
|
94
|
+
import * as wasmProvider from "@reallyme/crypto/wasm/reallyme_crypto_wasm.js";
|
|
95
|
+
|
|
96
|
+
wasmProvider.initSync({
|
|
97
|
+
module: readFileSync("reallyme_crypto_wasm_bg.wasm"),
|
|
98
|
+
});
|
|
99
|
+
installReallyMeWasmProvider(wasmProvider);
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
After installation, the facade routes WASM-backed algorithms through that
|
|
103
|
+
provider:
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
import { ReallyMeCrypto } from "@reallyme/crypto";
|
|
107
|
+
|
|
108
|
+
const keyPair = ReallyMeCrypto.generateKemKeyPair("X-Wing-768");
|
|
109
|
+
const encapsulation = ReallyMeCrypto.encapsulate("X-Wing-768", keyPair.publicKey);
|
|
110
|
+
const sharedSecret = ReallyMeCrypto.decapsulate(
|
|
111
|
+
"X-Wing-768",
|
|
112
|
+
encapsulation.ciphertext,
|
|
113
|
+
keyPair.secretKey,
|
|
114
|
+
);
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Building the WASM artifact requires `wasm-pack` `0.15.0` or newer and
|
|
118
|
+
`wasm-bindgen-cli` `0.2.126` or newer.
|
|
119
|
+
|
|
120
|
+
```sh
|
|
121
|
+
cargo install wasm-pack --version 0.15.0 --locked
|
|
122
|
+
cargo install wasm-bindgen-cli --version 0.2.126 --locked
|
|
123
|
+
npm --prefix packages/ts test
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Test
|
|
127
|
+
|
|
128
|
+
```sh
|
|
129
|
+
cd packages/ts
|
|
130
|
+
npm ci
|
|
131
|
+
npm test
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Publish
|
|
135
|
+
|
|
136
|
+
The npm package name is `@reallyme/crypto`. Release builds publish from
|
|
137
|
+
`packages/ts` with the generated WASM artifact included.
|
|
138
|
+
|
|
139
|
+
This package is the SDK API. The conformance verifiers under
|
|
140
|
+
`crates/conformance/vectors` remain test harnesses.
|
package/dist/aead.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ReallyMeAeadAlgorithm } from "./algorithms.js";
|
|
2
|
+
export declare const AEAD_KEY_LENGTH = 32;
|
|
3
|
+
export declare const AEAD_NONCE_LENGTH = 12;
|
|
4
|
+
export declare const XCHACHA20_POLY1305_NONCE_LENGTH = 24;
|
|
5
|
+
export declare const AEAD_TAG_LENGTH = 16;
|
|
6
|
+
export declare const ReallyMeAead: {
|
|
7
|
+
readonly seal: (algorithm: ReallyMeAeadAlgorithm, key: Uint8Array, nonce: Uint8Array, aad: Uint8Array, plaintext: Uint8Array) => Uint8Array;
|
|
8
|
+
readonly open: (algorithm: ReallyMeAeadAlgorithm, key: Uint8Array, nonce: Uint8Array, aad: Uint8Array, ciphertextWithTag: Uint8Array) => Uint8Array;
|
|
9
|
+
};
|
package/dist/aead.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
|
|
2
|
+
//
|
|
3
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
import { ReallyMeCryptoError } from "./errors.js";
|
|
5
|
+
import { ensureBytes } from "./validateBytes.js";
|
|
6
|
+
import { requireReallyMeWasmProvider } from "./wasmProvider.js";
|
|
7
|
+
export const AEAD_KEY_LENGTH = 32;
|
|
8
|
+
export const AEAD_NONCE_LENGTH = 12;
|
|
9
|
+
export const XCHACHA20_POLY1305_NONCE_LENGTH = 24;
|
|
10
|
+
export const AEAD_TAG_LENGTH = 16;
|
|
11
|
+
const aeadSuite = (algorithm) => {
|
|
12
|
+
const provider = requireReallyMeWasmProvider();
|
|
13
|
+
switch (algorithm) {
|
|
14
|
+
case "AES-256-GCM":
|
|
15
|
+
return {
|
|
16
|
+
nonceLength: AEAD_NONCE_LENGTH,
|
|
17
|
+
seal: provider.aes256GcmSeal,
|
|
18
|
+
open: provider.aes256GcmOpen,
|
|
19
|
+
};
|
|
20
|
+
case "AES-256-GCM-SIV":
|
|
21
|
+
return {
|
|
22
|
+
nonceLength: AEAD_NONCE_LENGTH,
|
|
23
|
+
seal: provider.aes256GcmSivSeal,
|
|
24
|
+
open: provider.aes256GcmSivOpen,
|
|
25
|
+
};
|
|
26
|
+
case "ChaCha20-Poly1305":
|
|
27
|
+
return {
|
|
28
|
+
nonceLength: AEAD_NONCE_LENGTH,
|
|
29
|
+
seal: provider.chacha20Poly1305Seal,
|
|
30
|
+
open: provider.chacha20Poly1305Open,
|
|
31
|
+
};
|
|
32
|
+
case "XChaCha20-Poly1305":
|
|
33
|
+
return {
|
|
34
|
+
nonceLength: XCHACHA20_POLY1305_NONCE_LENGTH,
|
|
35
|
+
seal: provider.xchacha20Poly1305Seal,
|
|
36
|
+
open: provider.xchacha20Poly1305Open,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
const requireBytesOutput = (value) => {
|
|
41
|
+
if (!(value instanceof Uint8Array)) {
|
|
42
|
+
throw new ReallyMeCryptoError("provider-failure");
|
|
43
|
+
}
|
|
44
|
+
return value;
|
|
45
|
+
};
|
|
46
|
+
export const ReallyMeAead = {
|
|
47
|
+
seal(algorithm, key, nonce, aad, plaintext) {
|
|
48
|
+
const suite = aeadSuite(algorithm);
|
|
49
|
+
ensureBytes(key, AEAD_KEY_LENGTH);
|
|
50
|
+
ensureBytes(nonce, suite.nonceLength);
|
|
51
|
+
return requireBytesOutput(suite.seal(key, nonce, aad, plaintext));
|
|
52
|
+
},
|
|
53
|
+
open(algorithm, key, nonce, aad, ciphertextWithTag) {
|
|
54
|
+
const suite = aeadSuite(algorithm);
|
|
55
|
+
ensureBytes(key, AEAD_KEY_LENGTH);
|
|
56
|
+
ensureBytes(nonce, suite.nonceLength);
|
|
57
|
+
if (ciphertextWithTag.length < AEAD_TAG_LENGTH) {
|
|
58
|
+
throw new ReallyMeCryptoError("invalid-input");
|
|
59
|
+
}
|
|
60
|
+
return requireBytesOutput(suite.open(key, nonce, aad, ciphertextWithTag));
|
|
61
|
+
},
|
|
62
|
+
};
|
package/dist/aesKw.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const AES_256_KW_KEK_LENGTH = 32;
|
|
2
|
+
export declare const AES_KW_BLOCK_LENGTH = 8;
|
|
3
|
+
export declare const AES_KW_INTEGRITY_CHECK_LENGTH = 8;
|
|
4
|
+
export declare const AES_KW_MIN_KEY_DATA_LENGTH = 16;
|
|
5
|
+
export declare const AES_KW_MIN_WRAPPED_KEY_LENGTH: number;
|
|
6
|
+
export declare const AES_KW_MAX_KEY_DATA_LENGTH = 4096;
|
|
7
|
+
export declare const ReallyMeAesKw: {
|
|
8
|
+
readonly wrapKey: (wrappingKey: Uint8Array, keyToWrap: Uint8Array) => Uint8Array;
|
|
9
|
+
readonly unwrapKey: (wrappingKey: Uint8Array, wrappedKey: Uint8Array) => Uint8Array;
|
|
10
|
+
};
|
package/dist/aesKw.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
|
|
2
|
+
//
|
|
3
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
import { ReallyMeCryptoError } from "./errors.js";
|
|
5
|
+
import { ensureBytes } from "./validateBytes.js";
|
|
6
|
+
import { requireReallyMeWasmProvider } from "./wasmProvider.js";
|
|
7
|
+
export const AES_256_KW_KEK_LENGTH = 32;
|
|
8
|
+
export const AES_KW_BLOCK_LENGTH = 8;
|
|
9
|
+
export const AES_KW_INTEGRITY_CHECK_LENGTH = 8;
|
|
10
|
+
export const AES_KW_MIN_KEY_DATA_LENGTH = 16;
|
|
11
|
+
export const AES_KW_MIN_WRAPPED_KEY_LENGTH = AES_KW_MIN_KEY_DATA_LENGTH + AES_KW_INTEGRITY_CHECK_LENGTH;
|
|
12
|
+
export const AES_KW_MAX_KEY_DATA_LENGTH = 4_096;
|
|
13
|
+
const validateKeyDataLength = (length) => {
|
|
14
|
+
if (length < AES_KW_MIN_KEY_DATA_LENGTH ||
|
|
15
|
+
length > AES_KW_MAX_KEY_DATA_LENGTH ||
|
|
16
|
+
length % AES_KW_BLOCK_LENGTH !== 0) {
|
|
17
|
+
throw new ReallyMeCryptoError("invalid-input");
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
const validateWrappedKeyLength = (length) => {
|
|
21
|
+
const maxWrappedLength = AES_KW_MAX_KEY_DATA_LENGTH + AES_KW_INTEGRITY_CHECK_LENGTH;
|
|
22
|
+
if (length < AES_KW_MIN_WRAPPED_KEY_LENGTH ||
|
|
23
|
+
length > maxWrappedLength ||
|
|
24
|
+
length % AES_KW_BLOCK_LENGTH !== 0) {
|
|
25
|
+
throw new ReallyMeCryptoError("invalid-input");
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
const requireBytesOutput = (value) => {
|
|
29
|
+
if (!(value instanceof Uint8Array)) {
|
|
30
|
+
throw new ReallyMeCryptoError("provider-failure");
|
|
31
|
+
}
|
|
32
|
+
return value;
|
|
33
|
+
};
|
|
34
|
+
export const ReallyMeAesKw = {
|
|
35
|
+
wrapKey(wrappingKey, keyToWrap) {
|
|
36
|
+
ensureBytes(wrappingKey, AES_256_KW_KEK_LENGTH);
|
|
37
|
+
validateKeyDataLength(keyToWrap.length);
|
|
38
|
+
return requireBytesOutput(requireReallyMeWasmProvider().aes256KwWrapKey(wrappingKey, keyToWrap));
|
|
39
|
+
},
|
|
40
|
+
unwrapKey(wrappingKey, wrappedKey) {
|
|
41
|
+
ensureBytes(wrappingKey, AES_256_KW_KEK_LENGTH);
|
|
42
|
+
validateWrappedKeyLength(wrappedKey.length);
|
|
43
|
+
return requireBytesOutput(requireReallyMeWasmProvider().aes256KwUnwrapKey(wrappingKey, wrappedKey));
|
|
44
|
+
},
|
|
45
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare const REALLYME_SIGNATURE_ALGORITHMS: readonly ["Ed25519", "ECDSA-P256-SHA256", "ECDSA-P384-SHA384", "ECDSA-P521-SHA512", "ECDSA-secp256k1-SHA256", "BIP340-Schnorr-secp256k1-SHA256", "RSA-PKCS1v15-SHA1", "RSA-PKCS1v15-SHA256", "RSA-PKCS1v15-SHA384", "RSA-PKCS1v15-SHA512", "RSA-PSS-SHA1-MGF1-SHA1", "RSA-PSS-SHA256-MGF1-SHA256", "RSA-PSS-SHA384-MGF1-SHA384", "RSA-PSS-SHA512-MGF1-SHA512", "ML-DSA-44", "ML-DSA-65", "ML-DSA-87", "SLH-DSA-SHA2-128s"];
|
|
2
|
+
export type ReallyMeSignatureAlgorithm = (typeof REALLYME_SIGNATURE_ALGORITHMS)[number];
|
|
3
|
+
export declare const REALLYME_HASH_ALGORITHMS: readonly ["SHA2-256", "SHA2-384", "SHA2-512", "SHA3-224", "SHA3-256", "SHA3-384", "SHA3-512"];
|
|
4
|
+
export type ReallyMeHashAlgorithm = (typeof REALLYME_HASH_ALGORITHMS)[number];
|
|
5
|
+
export declare const REALLYME_AEAD_ALGORITHMS: readonly ["AES-256-GCM", "AES-256-GCM-SIV", "ChaCha20-Poly1305", "XChaCha20-Poly1305"];
|
|
6
|
+
export type ReallyMeAeadAlgorithm = (typeof REALLYME_AEAD_ALGORITHMS)[number];
|
|
7
|
+
export declare const REALLYME_KEM_ALGORITHMS: readonly ["ML-KEM-512", "ML-KEM-768", "ML-KEM-1024", "X-Wing-768", "X-Wing-1024"];
|
|
8
|
+
export type ReallyMeKemAlgorithm = (typeof REALLYME_KEM_ALGORITHMS)[number];
|
|
9
|
+
export declare const REALLYME_KEY_AGREEMENT_ALGORITHMS: readonly ["X25519", "P-256-ECDH"];
|
|
10
|
+
export type ReallyMeKeyAgreementAlgorithm = (typeof REALLYME_KEY_AGREEMENT_ALGORITHMS)[number];
|
|
11
|
+
export declare const REALLYME_MAC_ALGORITHMS: readonly ["HMAC-SHA-256", "HMAC-SHA-512"];
|
|
12
|
+
export type ReallyMeMacAlgorithm = (typeof REALLYME_MAC_ALGORITHMS)[number];
|
|
13
|
+
export declare const REALLYME_KDF_ALGORITHMS: readonly ["HKDF-SHA256", "Argon2id", "PBKDF2-HMAC-SHA-256", "PBKDF2-HMAC-SHA-512"];
|
|
14
|
+
export type ReallyMeKdfAlgorithm = (typeof REALLYME_KDF_ALGORITHMS)[number];
|
|
15
|
+
export declare const REALLYME_KEY_WRAP_ALGORITHMS: readonly ["AES-256-KW"];
|
|
16
|
+
export type ReallyMeKeyWrapAlgorithm = (typeof REALLYME_KEY_WRAP_ALGORITHMS)[number];
|
|
17
|
+
export declare const REALLYME_HPKE_SUITES: readonly ["DHKEM-P256-HKDF-SHA256-HKDF-SHA256-AES-256-GCM", "DHKEM-X25519-HKDF-SHA256-HKDF-SHA256-CHACHA20-POLY1305"];
|
|
18
|
+
export type ReallyMeHpkeSuite = (typeof REALLYME_HPKE_SUITES)[number];
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
|
|
2
|
+
//
|
|
3
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
export const REALLYME_SIGNATURE_ALGORITHMS = [
|
|
5
|
+
"Ed25519",
|
|
6
|
+
"ECDSA-P256-SHA256",
|
|
7
|
+
"ECDSA-P384-SHA384",
|
|
8
|
+
"ECDSA-P521-SHA512",
|
|
9
|
+
"ECDSA-secp256k1-SHA256",
|
|
10
|
+
"BIP340-Schnorr-secp256k1-SHA256",
|
|
11
|
+
"RSA-PKCS1v15-SHA1",
|
|
12
|
+
"RSA-PKCS1v15-SHA256",
|
|
13
|
+
"RSA-PKCS1v15-SHA384",
|
|
14
|
+
"RSA-PKCS1v15-SHA512",
|
|
15
|
+
"RSA-PSS-SHA1-MGF1-SHA1",
|
|
16
|
+
"RSA-PSS-SHA256-MGF1-SHA256",
|
|
17
|
+
"RSA-PSS-SHA384-MGF1-SHA384",
|
|
18
|
+
"RSA-PSS-SHA512-MGF1-SHA512",
|
|
19
|
+
"ML-DSA-44",
|
|
20
|
+
"ML-DSA-65",
|
|
21
|
+
"ML-DSA-87",
|
|
22
|
+
"SLH-DSA-SHA2-128s",
|
|
23
|
+
];
|
|
24
|
+
export const REALLYME_HASH_ALGORITHMS = [
|
|
25
|
+
"SHA2-256",
|
|
26
|
+
"SHA2-384",
|
|
27
|
+
"SHA2-512",
|
|
28
|
+
"SHA3-224",
|
|
29
|
+
"SHA3-256",
|
|
30
|
+
"SHA3-384",
|
|
31
|
+
"SHA3-512",
|
|
32
|
+
];
|
|
33
|
+
export const REALLYME_AEAD_ALGORITHMS = [
|
|
34
|
+
"AES-256-GCM",
|
|
35
|
+
"AES-256-GCM-SIV",
|
|
36
|
+
"ChaCha20-Poly1305",
|
|
37
|
+
"XChaCha20-Poly1305",
|
|
38
|
+
];
|
|
39
|
+
export const REALLYME_KEM_ALGORITHMS = [
|
|
40
|
+
"ML-KEM-512",
|
|
41
|
+
"ML-KEM-768",
|
|
42
|
+
"ML-KEM-1024",
|
|
43
|
+
"X-Wing-768",
|
|
44
|
+
"X-Wing-1024",
|
|
45
|
+
];
|
|
46
|
+
export const REALLYME_KEY_AGREEMENT_ALGORITHMS = [
|
|
47
|
+
"X25519",
|
|
48
|
+
"P-256-ECDH",
|
|
49
|
+
];
|
|
50
|
+
export const REALLYME_MAC_ALGORITHMS = [
|
|
51
|
+
"HMAC-SHA-256",
|
|
52
|
+
"HMAC-SHA-512",
|
|
53
|
+
];
|
|
54
|
+
export const REALLYME_KDF_ALGORITHMS = [
|
|
55
|
+
"HKDF-SHA256",
|
|
56
|
+
"Argon2id",
|
|
57
|
+
"PBKDF2-HMAC-SHA-256",
|
|
58
|
+
"PBKDF2-HMAC-SHA-512",
|
|
59
|
+
];
|
|
60
|
+
export const REALLYME_KEY_WRAP_ALGORITHMS = ["AES-256-KW"];
|
|
61
|
+
export const REALLYME_HPKE_SUITES = [
|
|
62
|
+
"DHKEM-P256-HKDF-SHA256-HKDF-SHA256-AES-256-GCM",
|
|
63
|
+
"DHKEM-X25519-HKDF-SHA256-HKDF-SHA256-CHACHA20-POLY1305",
|
|
64
|
+
];
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const ARGON2ID_DERIVED_KEY_LENGTH = 32;
|
|
2
|
+
export declare const ARGON2ID_SALT_MIN_LENGTH = 16;
|
|
3
|
+
export declare const ARGON2ID_SALT_MAX_LENGTH = 32;
|
|
4
|
+
export declare const ARGON2ID_V1 = 1;
|
|
5
|
+
export declare const ARGON2ID_V2 = 2;
|
|
6
|
+
export declare const ReallyMeArgon2id: {
|
|
7
|
+
readonly deriveKey: (kdfVersion: number, secret: Uint8Array, salt: Uint8Array) => Uint8Array;
|
|
8
|
+
};
|
package/dist/argon2id.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
|
|
2
|
+
//
|
|
3
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
import { ReallyMeCryptoError } from "./errors.js";
|
|
5
|
+
import { requireReallyMeWasmProvider } from "./wasmProvider.js";
|
|
6
|
+
export const ARGON2ID_DERIVED_KEY_LENGTH = 32;
|
|
7
|
+
export const ARGON2ID_SALT_MIN_LENGTH = 16;
|
|
8
|
+
export const ARGON2ID_SALT_MAX_LENGTH = 32;
|
|
9
|
+
export const ARGON2ID_V1 = 1;
|
|
10
|
+
export const ARGON2ID_V2 = 2;
|
|
11
|
+
const validateVersion = (kdfVersion) => {
|
|
12
|
+
if (!Number.isInteger(kdfVersion) ||
|
|
13
|
+
(kdfVersion !== ARGON2ID_V1 && kdfVersion !== ARGON2ID_V2)) {
|
|
14
|
+
throw new ReallyMeCryptoError("invalid-input");
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
const validateSecret = (secret) => {
|
|
18
|
+
if (secret.length === 0) {
|
|
19
|
+
throw new ReallyMeCryptoError("invalid-input");
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
const validateSalt = (salt) => {
|
|
23
|
+
if (salt.length < ARGON2ID_SALT_MIN_LENGTH || salt.length > ARGON2ID_SALT_MAX_LENGTH) {
|
|
24
|
+
throw new ReallyMeCryptoError("invalid-input");
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
const requireDerivedKey = (value) => {
|
|
28
|
+
if (!(value instanceof Uint8Array) || value.length !== ARGON2ID_DERIVED_KEY_LENGTH) {
|
|
29
|
+
throw new ReallyMeCryptoError("provider-failure");
|
|
30
|
+
}
|
|
31
|
+
return value;
|
|
32
|
+
};
|
|
33
|
+
export const ReallyMeArgon2id = {
|
|
34
|
+
deriveKey(kdfVersion, secret, salt) {
|
|
35
|
+
validateVersion(kdfVersion);
|
|
36
|
+
validateSecret(secret);
|
|
37
|
+
validateSalt(salt);
|
|
38
|
+
return requireDerivedKey(requireReallyMeWasmProvider().argon2idDeriveKey(kdfVersion, secret, salt));
|
|
39
|
+
},
|
|
40
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export declare const BIP340_SCHNORR_SECRET_KEY_LENGTH = 32;
|
|
2
|
+
export declare const BIP340_SCHNORR_PUBLIC_KEY_LENGTH = 32;
|
|
3
|
+
export declare const BIP340_SCHNORR_MESSAGE_LENGTH = 32;
|
|
4
|
+
export declare const BIP340_SCHNORR_AUX_RAND_LENGTH = 32;
|
|
5
|
+
export declare const BIP340_SCHNORR_SIGNATURE_LENGTH = 64;
|
|
6
|
+
/**
|
|
7
|
+
* BIP-340 Schnorr over secp256k1 backed by @noble/curves.
|
|
8
|
+
*
|
|
9
|
+
* BIP-340 signs a 32-byte message representative and requires 32 bytes of
|
|
10
|
+
* auxiliary randomness. Keeping `auxRand32` explicit matches the Rust, Swift,
|
|
11
|
+
* and Kotlin lanes and avoids a hidden provider-specific randomness policy at
|
|
12
|
+
* the generic facade boundary.
|
|
13
|
+
*/
|
|
14
|
+
export declare const ReallyMeBip340Schnorr: {
|
|
15
|
+
readonly generateKeyPair: () => {
|
|
16
|
+
publicKey: Uint8Array;
|
|
17
|
+
secretKey: Uint8Array;
|
|
18
|
+
};
|
|
19
|
+
readonly deriveKeyPair: (secretKey: Uint8Array) => {
|
|
20
|
+
publicKey: Uint8Array;
|
|
21
|
+
secretKey: Uint8Array;
|
|
22
|
+
};
|
|
23
|
+
readonly derivePublicKey: (secretKey: Uint8Array) => Uint8Array;
|
|
24
|
+
readonly sign: (message32: Uint8Array, secretKey: Uint8Array, auxRand32: Uint8Array) => Uint8Array;
|
|
25
|
+
readonly verify: (signature: Uint8Array, message32: Uint8Array, publicKey: Uint8Array) => void;
|
|
26
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
|
|
2
|
+
//
|
|
3
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
import { schnorr, secp256k1 } from "@noble/curves/secp256k1.js";
|
|
5
|
+
import { ReallyMeCryptoError } from "./errors.js";
|
|
6
|
+
export const BIP340_SCHNORR_SECRET_KEY_LENGTH = 32;
|
|
7
|
+
export const BIP340_SCHNORR_PUBLIC_KEY_LENGTH = 32;
|
|
8
|
+
export const BIP340_SCHNORR_MESSAGE_LENGTH = 32;
|
|
9
|
+
export const BIP340_SCHNORR_AUX_RAND_LENGTH = 32;
|
|
10
|
+
export const BIP340_SCHNORR_SIGNATURE_LENGTH = 64;
|
|
11
|
+
/**
|
|
12
|
+
* BIP-340 Schnorr over secp256k1 backed by @noble/curves.
|
|
13
|
+
*
|
|
14
|
+
* BIP-340 signs a 32-byte message representative and requires 32 bytes of
|
|
15
|
+
* auxiliary randomness. Keeping `auxRand32` explicit matches the Rust, Swift,
|
|
16
|
+
* and Kotlin lanes and avoids a hidden provider-specific randomness policy at
|
|
17
|
+
* the generic facade boundary.
|
|
18
|
+
*/
|
|
19
|
+
export const ReallyMeBip340Schnorr = {
|
|
20
|
+
generateKeyPair() {
|
|
21
|
+
const secretKey = secp256k1.utils.randomSecretKey();
|
|
22
|
+
return {
|
|
23
|
+
publicKey: schnorr.getPublicKey(secretKey),
|
|
24
|
+
secretKey,
|
|
25
|
+
};
|
|
26
|
+
},
|
|
27
|
+
deriveKeyPair(secretKey) {
|
|
28
|
+
return {
|
|
29
|
+
publicKey: this.derivePublicKey(secretKey),
|
|
30
|
+
secretKey: secretKey.slice(),
|
|
31
|
+
};
|
|
32
|
+
},
|
|
33
|
+
derivePublicKey(secretKey) {
|
|
34
|
+
if (secretKey.length !== BIP340_SCHNORR_SECRET_KEY_LENGTH) {
|
|
35
|
+
throw new ReallyMeCryptoError("invalid-input");
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
return schnorr.getPublicKey(secretKey);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
throw new ReallyMeCryptoError("invalid-input");
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
sign(message32, secretKey, auxRand32) {
|
|
45
|
+
if (message32.length !== BIP340_SCHNORR_MESSAGE_LENGTH ||
|
|
46
|
+
secretKey.length !== BIP340_SCHNORR_SECRET_KEY_LENGTH ||
|
|
47
|
+
auxRand32.length !== BIP340_SCHNORR_AUX_RAND_LENGTH) {
|
|
48
|
+
throw new ReallyMeCryptoError("invalid-input");
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
return schnorr.sign(message32, secretKey, auxRand32);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
throw new ReallyMeCryptoError("invalid-input");
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
verify(signature, message32, publicKey) {
|
|
58
|
+
if (signature.length !== BIP340_SCHNORR_SIGNATURE_LENGTH ||
|
|
59
|
+
message32.length !== BIP340_SCHNORR_MESSAGE_LENGTH ||
|
|
60
|
+
publicKey.length !== BIP340_SCHNORR_PUBLIC_KEY_LENGTH) {
|
|
61
|
+
throw new ReallyMeCryptoError("invalid-input");
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
if (!schnorr.verify(signature, message32, publicKey)) {
|
|
65
|
+
throw new ReallyMeCryptoError("invalid-signature");
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
throw new ReallyMeCryptoError("invalid-signature");
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
};
|
package/dist/codecs.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export type ReallyMeMulticodecTag = "encryption" | "hash" | "key" | "multihash" | "multikey";
|
|
2
|
+
export type ReallyMeKeyMaterialKind = "not-key" | "public-key" | "private-key" | "symmetric-key";
|
|
3
|
+
export type ReallyMeMulticodecMetadata = Readonly<{
|
|
4
|
+
name: string;
|
|
5
|
+
alg: string;
|
|
6
|
+
tag: ReallyMeMulticodecTag;
|
|
7
|
+
keyMaterial: ReallyMeKeyMaterialKind;
|
|
8
|
+
prefix: Uint8Array;
|
|
9
|
+
expectedKeyLength?: number;
|
|
10
|
+
}>;
|
|
11
|
+
export type ReallyMeParsedMultikey = Readonly<{
|
|
12
|
+
codecName: string;
|
|
13
|
+
algorithmName: string;
|
|
14
|
+
publicKey: Uint8Array;
|
|
15
|
+
expectedPublicKeyLength?: number;
|
|
16
|
+
}>;
|
|
17
|
+
export type ReallyMeDagCborCidVerification = Readonly<{
|
|
18
|
+
valid: boolean;
|
|
19
|
+
expectedCid: string;
|
|
20
|
+
actualCid: string;
|
|
21
|
+
}>;
|
|
22
|
+
export declare const ReallyMeCodecs: {
|
|
23
|
+
readonly base64urlEncode: (bytes: Uint8Array) => string;
|
|
24
|
+
readonly base64urlDecode: (encoded: string) => Uint8Array;
|
|
25
|
+
readonly base64urlDecodeBytes: (encoded: Uint8Array) => Uint8Array;
|
|
26
|
+
readonly multibaseBase64urlEncode: (bytes: Uint8Array) => string;
|
|
27
|
+
readonly multibaseBase58btcEncode: (bytes: Uint8Array) => string;
|
|
28
|
+
readonly multibaseDecode: (encoded: string) => Uint8Array;
|
|
29
|
+
readonly multicodecPrefixForName: (codecName: string) => ReallyMeMulticodecMetadata;
|
|
30
|
+
readonly multicodecLookupPrefix: (bytes: Uint8Array) => ReallyMeMulticodecMetadata;
|
|
31
|
+
readonly multikeyEncode: (codecName: string, publicKey: Uint8Array) => string;
|
|
32
|
+
readonly multikeyParse: (multikey: string) => ReallyMeParsedMultikey;
|
|
33
|
+
readonly dagCborComputeCid: (bytes: Uint8Array) => string;
|
|
34
|
+
readonly dagCborVerifyCid: (cid: string, bytes: Uint8Array) => ReallyMeDagCborCidVerification;
|
|
35
|
+
};
|