@verbeth/sdk 0.1.4 → 0.1.6
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 +20 -168
- package/dist/esm/src/addresses.d.ts +20 -0
- package/dist/esm/src/addresses.d.ts.map +1 -0
- package/dist/esm/src/addresses.js +33 -0
- package/dist/esm/src/client/HsrTagIndex.d.ts +77 -0
- package/dist/esm/src/client/HsrTagIndex.d.ts.map +1 -0
- package/dist/esm/src/client/HsrTagIndex.js +157 -0
- package/dist/esm/src/client/PendingManager.d.ts +65 -0
- package/dist/esm/src/client/PendingManager.d.ts.map +1 -0
- package/dist/esm/src/client/PendingManager.js +84 -0
- package/dist/esm/src/client/SessionManager.d.ts +65 -0
- package/dist/esm/src/client/SessionManager.d.ts.map +1 -0
- package/dist/esm/src/client/SessionManager.js +146 -0
- package/dist/esm/src/client/VerbethClient.d.ts +153 -99
- package/dist/esm/src/client/VerbethClient.d.ts.map +1 -1
- package/dist/esm/src/client/VerbethClient.js +429 -123
- package/dist/esm/src/client/VerbethClientBuilder.d.ts +105 -0
- package/dist/esm/src/client/VerbethClientBuilder.d.ts.map +1 -0
- package/dist/esm/src/client/VerbethClientBuilder.js +146 -0
- package/dist/esm/src/client/hsrMatcher.d.ts +22 -0
- package/dist/esm/src/client/hsrMatcher.d.ts.map +1 -0
- package/dist/esm/src/client/hsrMatcher.js +31 -0
- package/dist/esm/src/client/index.d.ts +6 -1
- package/dist/esm/src/client/index.d.ts.map +1 -1
- package/dist/esm/src/client/index.js +2 -0
- package/dist/esm/src/client/types.d.ts +151 -10
- package/dist/esm/src/client/types.d.ts.map +1 -1
- package/dist/esm/src/crypto(old).d.ts +46 -0
- package/dist/esm/src/crypto(old).d.ts.map +1 -0
- package/dist/esm/src/crypto(old).js +137 -0
- package/dist/esm/src/crypto.d.ts +7 -29
- package/dist/esm/src/crypto.d.ts.map +1 -1
- package/dist/esm/src/crypto.js +36 -72
- package/dist/esm/src/executor.d.ts +17 -18
- package/dist/esm/src/executor.d.ts.map +1 -1
- package/dist/esm/src/executor.js +54 -70
- package/dist/esm/src/handshake.d.ts +51 -0
- package/dist/esm/src/handshake.d.ts.map +1 -0
- package/dist/esm/src/handshake.js +105 -0
- package/dist/esm/src/identity.d.ts +24 -18
- package/dist/esm/src/identity.d.ts.map +1 -1
- package/dist/esm/src/identity.js +126 -31
- package/dist/esm/src/index.d.ts +11 -7
- package/dist/esm/src/index.d.ts.map +1 -1
- package/dist/esm/src/index.js +10 -7
- package/dist/esm/src/payload.d.ts +3 -30
- package/dist/esm/src/payload.d.ts.map +1 -1
- package/dist/esm/src/payload.js +3 -77
- package/dist/esm/src/pq/kem.d.ts +33 -0
- package/dist/esm/src/pq/kem.d.ts.map +1 -0
- package/dist/esm/src/pq/kem.js +40 -0
- package/dist/esm/src/ratchet/auth.d.ts +34 -0
- package/dist/esm/src/ratchet/auth.d.ts.map +1 -0
- package/dist/esm/src/ratchet/auth.js +88 -0
- package/dist/esm/src/ratchet/codec.d.ts +52 -0
- package/dist/esm/src/ratchet/codec.d.ts.map +1 -0
- package/dist/esm/src/ratchet/codec.js +127 -0
- package/dist/esm/src/ratchet/decrypt.d.ts +28 -0
- package/dist/esm/src/ratchet/decrypt.d.ts.map +1 -0
- package/dist/esm/src/ratchet/decrypt.js +255 -0
- package/dist/esm/src/ratchet/encrypt.d.ts +17 -0
- package/dist/esm/src/ratchet/encrypt.d.ts.map +1 -0
- package/dist/esm/src/ratchet/encrypt.js +78 -0
- package/dist/esm/src/ratchet/index.d.ts +8 -0
- package/dist/esm/src/ratchet/index.d.ts.map +1 -0
- package/dist/esm/src/ratchet/index.js +8 -0
- package/dist/esm/src/ratchet/kdf.d.ts +60 -0
- package/dist/esm/src/ratchet/kdf.d.ts.map +1 -0
- package/dist/esm/src/ratchet/kdf.js +91 -0
- package/dist/esm/src/ratchet/session.d.ts +43 -0
- package/dist/esm/src/ratchet/session.d.ts.map +1 -0
- package/dist/esm/src/ratchet/session.js +139 -0
- package/dist/esm/src/ratchet/types.d.ts +168 -0
- package/dist/esm/src/ratchet/types.d.ts.map +1 -0
- package/dist/esm/src/ratchet/types.js +27 -0
- package/dist/esm/src/safeSessionSigner.d.ts +35 -0
- package/dist/esm/src/safeSessionSigner.d.ts.map +1 -0
- package/dist/esm/src/safeSessionSigner.js +59 -0
- package/dist/esm/src/send.d.ts +32 -24
- package/dist/esm/src/send.d.ts.map +1 -1
- package/dist/esm/src/send.js +84 -39
- package/dist/esm/src/types.d.ts +8 -13
- package/dist/esm/src/types.d.ts.map +1 -1
- package/dist/esm/src/utils/safeSessionSigner.d.ts +23 -0
- package/dist/esm/src/utils/safeSessionSigner.d.ts.map +1 -0
- package/dist/esm/src/utils/safeSessionSigner.js +59 -0
- package/dist/esm/src/utils/txQueue.d.ts +12 -0
- package/dist/esm/src/utils/txQueue.d.ts.map +1 -0
- package/dist/esm/src/utils/txQueue.js +25 -0
- package/dist/esm/src/utils.d.ts +2 -3
- package/dist/esm/src/utils.d.ts.map +1 -1
- package/dist/esm/src/utils.js +5 -5
- package/dist/esm/src/verify.d.ts +9 -25
- package/dist/esm/src/verify.d.ts.map +1 -1
- package/dist/esm/src/verify.js +49 -50
- package/dist/src/addresses.d.ts +20 -0
- package/dist/src/addresses.d.ts.map +1 -0
- package/dist/src/addresses.js +33 -0
- package/dist/src/client/HsrTagIndex.d.ts +77 -0
- package/dist/src/client/HsrTagIndex.d.ts.map +1 -0
- package/dist/src/client/HsrTagIndex.js +157 -0
- package/dist/src/client/PendingManager.d.ts +65 -0
- package/dist/src/client/PendingManager.d.ts.map +1 -0
- package/dist/src/client/PendingManager.js +84 -0
- package/dist/src/client/SessionManager.d.ts +65 -0
- package/dist/src/client/SessionManager.d.ts.map +1 -0
- package/dist/src/client/SessionManager.js +146 -0
- package/dist/src/client/VerbethClient.d.ts +153 -99
- package/dist/src/client/VerbethClient.d.ts.map +1 -1
- package/dist/src/client/VerbethClient.js +429 -123
- package/dist/src/client/VerbethClientBuilder.d.ts +105 -0
- package/dist/src/client/VerbethClientBuilder.d.ts.map +1 -0
- package/dist/src/client/VerbethClientBuilder.js +146 -0
- package/dist/src/client/hsrMatcher.d.ts +22 -0
- package/dist/src/client/hsrMatcher.d.ts.map +1 -0
- package/dist/src/client/hsrMatcher.js +31 -0
- package/dist/src/client/index.d.ts +6 -1
- package/dist/src/client/index.d.ts.map +1 -1
- package/dist/src/client/index.js +2 -0
- package/dist/src/client/types.d.ts +151 -10
- package/dist/src/client/types.d.ts.map +1 -1
- package/dist/src/crypto(old).d.ts +46 -0
- package/dist/src/crypto(old).d.ts.map +1 -0
- package/dist/src/crypto(old).js +137 -0
- package/dist/src/crypto.d.ts +7 -29
- package/dist/src/crypto.d.ts.map +1 -1
- package/dist/src/crypto.js +36 -72
- package/dist/src/executor.d.ts +17 -18
- package/dist/src/executor.d.ts.map +1 -1
- package/dist/src/executor.js +54 -70
- package/dist/src/handshake.d.ts +51 -0
- package/dist/src/handshake.d.ts.map +1 -0
- package/dist/src/handshake.js +105 -0
- package/dist/src/identity.d.ts +24 -18
- package/dist/src/identity.d.ts.map +1 -1
- package/dist/src/identity.js +126 -31
- package/dist/src/index.d.ts +11 -7
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +10 -7
- package/dist/src/payload.d.ts +3 -30
- package/dist/src/payload.d.ts.map +1 -1
- package/dist/src/payload.js +3 -77
- package/dist/src/pq/kem.d.ts +33 -0
- package/dist/src/pq/kem.d.ts.map +1 -0
- package/dist/src/pq/kem.js +40 -0
- package/dist/src/ratchet/auth.d.ts +34 -0
- package/dist/src/ratchet/auth.d.ts.map +1 -0
- package/dist/src/ratchet/auth.js +88 -0
- package/dist/src/ratchet/codec.d.ts +52 -0
- package/dist/src/ratchet/codec.d.ts.map +1 -0
- package/dist/src/ratchet/codec.js +127 -0
- package/dist/src/ratchet/decrypt.d.ts +28 -0
- package/dist/src/ratchet/decrypt.d.ts.map +1 -0
- package/dist/src/ratchet/decrypt.js +255 -0
- package/dist/src/ratchet/encrypt.d.ts +17 -0
- package/dist/src/ratchet/encrypt.d.ts.map +1 -0
- package/dist/src/ratchet/encrypt.js +78 -0
- package/dist/src/ratchet/index.d.ts +8 -0
- package/dist/src/ratchet/index.d.ts.map +1 -0
- package/dist/src/ratchet/index.js +8 -0
- package/dist/src/ratchet/kdf.d.ts +60 -0
- package/dist/src/ratchet/kdf.d.ts.map +1 -0
- package/dist/src/ratchet/kdf.js +91 -0
- package/dist/src/ratchet/session.d.ts +43 -0
- package/dist/src/ratchet/session.d.ts.map +1 -0
- package/dist/src/ratchet/session.js +139 -0
- package/dist/src/ratchet/types.d.ts +168 -0
- package/dist/src/ratchet/types.d.ts.map +1 -0
- package/dist/src/ratchet/types.js +27 -0
- package/dist/src/safeSessionSigner.d.ts +35 -0
- package/dist/src/safeSessionSigner.d.ts.map +1 -0
- package/dist/src/safeSessionSigner.js +59 -0
- package/dist/src/send.d.ts +32 -24
- package/dist/src/send.d.ts.map +1 -1
- package/dist/src/send.js +84 -39
- package/dist/src/types.d.ts +8 -13
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/utils/safeSessionSigner.d.ts +23 -0
- package/dist/src/utils/safeSessionSigner.d.ts.map +1 -0
- package/dist/src/utils/safeSessionSigner.js +59 -0
- package/dist/src/utils/txQueue.d.ts +12 -0
- package/dist/src/utils/txQueue.d.ts.map +1 -0
- package/dist/src/utils/txQueue.js +25 -0
- package/dist/src/utils.d.ts +2 -3
- package/dist/src/utils.d.ts.map +1 -1
- package/dist/src/utils.js +5 -5
- package/dist/src/verify.d.ts +9 -25
- package/dist/src/verify.d.ts.map +1 -1
- package/dist/src/verify.js +49 -50
- package/package.json +2 -1
package/dist/src/identity.js
CHANGED
|
@@ -1,22 +1,87 @@
|
|
|
1
|
+
// packages/sdk/src/utils/identity.ts
|
|
1
2
|
import { sha256 } from "@noble/hashes/sha2";
|
|
2
3
|
import { hkdf } from "@noble/hashes/hkdf";
|
|
3
|
-
import { concat, hexlify } from "ethers";
|
|
4
|
+
import { Wallet, concat, hexlify, getBytes } from "ethers";
|
|
4
5
|
import nacl from "tweetnacl";
|
|
5
6
|
import { encodeUnifiedPubKeys } from "./payload.js";
|
|
7
|
+
const SECP256K1_N = BigInt("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141");
|
|
8
|
+
const SECP256K1_HALF_N = SECP256K1_N >> 1n;
|
|
9
|
+
function bytesToBigIntBE(bytes) {
|
|
10
|
+
let hex = "";
|
|
11
|
+
for (const b of bytes)
|
|
12
|
+
hex += b.toString(16).padStart(2, "0");
|
|
13
|
+
return hex.length ? BigInt("0x" + hex) : 0n;
|
|
14
|
+
}
|
|
15
|
+
function bigIntTo32BytesBE(x) {
|
|
16
|
+
let hex = x.toString(16);
|
|
17
|
+
if (hex.length > 64)
|
|
18
|
+
hex = hex.slice(hex.length - 64);
|
|
19
|
+
hex = hex.padStart(64, "0");
|
|
20
|
+
const out = new Uint8Array(32);
|
|
21
|
+
for (let i = 0; i < 32; i++) {
|
|
22
|
+
out[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
23
|
+
}
|
|
24
|
+
return out;
|
|
25
|
+
}
|
|
6
26
|
/**
|
|
7
|
-
*
|
|
8
|
-
* Returns a proof binding the derived keypair to the wallet address.
|
|
27
|
+
* Canonicalize an Ethereum ECDSA signature (65 bytes) to low-s form (only used as KDF input)
|
|
9
28
|
*/
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
29
|
+
function canonicalizeEcdsaSig65(sig) {
|
|
30
|
+
if (sig.length !== 65)
|
|
31
|
+
return sig;
|
|
32
|
+
const r = sig.slice(0, 32);
|
|
33
|
+
const s = sig.slice(32, 64);
|
|
34
|
+
const v = sig[64];
|
|
35
|
+
const sBig = bytesToBigIntBE(s);
|
|
36
|
+
if (sBig <= SECP256K1_HALF_N)
|
|
37
|
+
return sig;
|
|
38
|
+
const sLow = SECP256K1_N - sBig;
|
|
39
|
+
const out = new Uint8Array(65);
|
|
40
|
+
out.set(r, 0);
|
|
41
|
+
out.set(bigIntTo32BytesBE(sLow), 32);
|
|
42
|
+
out[64] = v;
|
|
43
|
+
return out;
|
|
44
|
+
}
|
|
45
|
+
function buildSeedMessage(addrLower) {
|
|
46
|
+
const lines = [
|
|
47
|
+
"VerbEth Identity Seed v1",
|
|
48
|
+
`Address: ${addrLower}`,
|
|
49
|
+
"Context: verbeth",
|
|
50
|
+
];
|
|
51
|
+
return lines.join("\n");
|
|
52
|
+
}
|
|
53
|
+
function buildBindingMessage(addrLower, pkEd25519Hex, pkX25519Hex, executorSafeAddress, ctx) {
|
|
54
|
+
const lines = [
|
|
55
|
+
"VerbEth Key Binding v1",
|
|
56
|
+
`Address: ${addrLower}`,
|
|
57
|
+
`PkEd25519: ${pkEd25519Hex}`,
|
|
58
|
+
`PkX25519: ${pkX25519Hex}`,
|
|
59
|
+
`ExecutorSafeAddress: ${executorSafeAddress ?? ""}`,
|
|
60
|
+
];
|
|
61
|
+
if (typeof ctx?.chainId === "number")
|
|
62
|
+
lines.push(`ChainId: ${ctx.chainId}`);
|
|
63
|
+
if (ctx?.rpId)
|
|
64
|
+
lines.push(`RpId: ${ctx.rpId}`);
|
|
65
|
+
return lines.join("\n");
|
|
66
|
+
}
|
|
67
|
+
// ============================================================================
|
|
68
|
+
// Derive all keys from seed signature
|
|
69
|
+
// ============================================================================
|
|
70
|
+
/**
|
|
71
|
+
* Derive all identity keys and session key from a single seed signature.
|
|
72
|
+
*/
|
|
73
|
+
export async function deriveIdentityKeys(signer, address) {
|
|
13
74
|
const enc = new TextEncoder();
|
|
14
75
|
const addrLower = address.toLowerCase();
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const
|
|
76
|
+
const seedMessage = buildSeedMessage(addrLower);
|
|
77
|
+
let seedSignature = await signer.signMessage(seedMessage);
|
|
78
|
+
const seedSigBytes = canonicalizeEcdsaSig65(getBytes(seedSignature));
|
|
79
|
+
seedSignature = "";
|
|
80
|
+
// IKM = HKDF( canonicalSig || H(seedMessage) || "verbeth/addr:" || address_lower )
|
|
81
|
+
const seedSalt = enc.encode("verbeth/seed-sig-v1");
|
|
18
82
|
const seedInfo = enc.encode("verbeth/ikm");
|
|
19
|
-
const
|
|
83
|
+
const seedMsgHash = sha256(enc.encode(seedMessage));
|
|
84
|
+
const ikmInput = getBytes(concat([seedSigBytes, seedMsgHash, enc.encode("verbeth/addr:" + addrLower)]));
|
|
20
85
|
const ikm = hkdf(sha256, ikmInput, seedSalt, seedInfo, 32);
|
|
21
86
|
// Derive X25519 (encryption)
|
|
22
87
|
const info_x25519 = enc.encode("verbeth-x25519-v1");
|
|
@@ -26,6 +91,22 @@ export async function deriveIdentityKeyPairWithProof(signer, address) {
|
|
|
26
91
|
const info_ed25519 = enc.encode("verbeth-ed25519-v1");
|
|
27
92
|
const ed25519_seed = hkdf(sha256, ikm, new Uint8Array(0), info_ed25519, 32);
|
|
28
93
|
const signKeyPair = nacl.sign.keyPair.fromSeed(ed25519_seed);
|
|
94
|
+
// Derive secp256k1 session key for txs via Safe module
|
|
95
|
+
const info_session = enc.encode("verbeth-session-secp256k1-v1");
|
|
96
|
+
const sessionSeed = hkdf(sha256, ikm, new Uint8Array(0), info_session, 32);
|
|
97
|
+
const sessionPrivateKey = hexlify(sessionSeed);
|
|
98
|
+
const sessionWallet = new Wallet(sessionPrivateKey);
|
|
99
|
+
const sessionAddress = sessionWallet.address;
|
|
100
|
+
try {
|
|
101
|
+
seedSigBytes.fill(0);
|
|
102
|
+
seedMsgHash.fill(0);
|
|
103
|
+
ikmInput.fill(0);
|
|
104
|
+
ikm.fill(0);
|
|
105
|
+
ed25519_seed.fill(0);
|
|
106
|
+
x25519_sk.fill(0);
|
|
107
|
+
sessionSeed.fill(0);
|
|
108
|
+
}
|
|
109
|
+
catch { }
|
|
29
110
|
const pkX25519Hex = hexlify(boxKeyPair.publicKey);
|
|
30
111
|
const pkEd25519Hex = hexlify(signKeyPair.publicKey);
|
|
31
112
|
const keyPair = {
|
|
@@ -34,37 +115,51 @@ export async function deriveIdentityKeyPairWithProof(signer, address) {
|
|
|
34
115
|
signingPublicKey: signKeyPair.publicKey,
|
|
35
116
|
signingSecretKey: signKeyPair.secretKey,
|
|
36
117
|
};
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
118
|
+
return {
|
|
119
|
+
keyPair,
|
|
120
|
+
sessionPrivateKey,
|
|
121
|
+
sessionAddress,
|
|
122
|
+
pkX25519Hex,
|
|
123
|
+
pkEd25519Hex,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
// ============================================================================
|
|
127
|
+
// Create binding proof with Safe address
|
|
128
|
+
// ============================================================================
|
|
129
|
+
/**
|
|
130
|
+
* Create the binding proof that ties the derived keys to the Safe address.
|
|
131
|
+
*/
|
|
132
|
+
export async function createBindingProof(signer, address, derivedKeys, executorSafeAddress, ctx) {
|
|
133
|
+
const addrLower = address.toLowerCase();
|
|
134
|
+
const executorSafeAddressLower = executorSafeAddress.toLowerCase();
|
|
135
|
+
const message = buildBindingMessage(addrLower, derivedKeys.pkEd25519Hex, derivedKeys.pkX25519Hex, executorSafeAddressLower, ctx);
|
|
47
136
|
const signature = await signer.signMessage(message);
|
|
48
137
|
const messageRawHex = ("0x" +
|
|
49
138
|
Buffer.from(message, "utf-8").toString("hex"));
|
|
50
139
|
return {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
140
|
+
message,
|
|
141
|
+
signature,
|
|
142
|
+
messageRawHex,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
// this is when the Safe address is known upfront
|
|
146
|
+
export async function deriveIdentityKeyPairWithProof(signer, address, executorSafeAddress, ctx) {
|
|
147
|
+
const derivedKeys = await deriveIdentityKeys(signer, address);
|
|
148
|
+
const identityProof = await createBindingProof(signer, address, derivedKeys, executorSafeAddress ?? "", ctx);
|
|
149
|
+
return {
|
|
150
|
+
...derivedKeys,
|
|
151
|
+
identityProof,
|
|
57
152
|
};
|
|
58
153
|
}
|
|
59
|
-
export async function deriveIdentityWithUnifiedKeys(signer, address) {
|
|
60
|
-
const result = await deriveIdentityKeyPairWithProof(signer, address);
|
|
61
|
-
const unifiedPubKeys = encodeUnifiedPubKeys(result.keyPair.publicKey,
|
|
62
|
-
result.keyPair.signingPublicKey // Ed25519
|
|
63
|
-
);
|
|
154
|
+
export async function deriveIdentityWithUnifiedKeys(signer, address, executorSafeAddress, ctx) {
|
|
155
|
+
const result = await deriveIdentityKeyPairWithProof(signer, address, executorSafeAddress, ctx);
|
|
156
|
+
const unifiedPubKeys = encodeUnifiedPubKeys(result.keyPair.publicKey, result.keyPair.signingPublicKey);
|
|
64
157
|
return {
|
|
65
158
|
identityProof: result.identityProof,
|
|
66
159
|
identityPubKey: result.keyPair.publicKey,
|
|
67
160
|
signingPubKey: result.keyPair.signingPublicKey,
|
|
68
161
|
unifiedPubKeys,
|
|
162
|
+
sessionPrivateKey: result.sessionPrivateKey,
|
|
163
|
+
sessionAddress: result.sessionAddress,
|
|
69
164
|
};
|
|
70
165
|
}
|
package/dist/src/index.d.ts
CHANGED
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
export * from './crypto.js';
|
|
2
2
|
export * from './payload.js';
|
|
3
|
-
export * from './
|
|
3
|
+
export * from './handshake.js';
|
|
4
4
|
export * from './verify.js';
|
|
5
5
|
export * from './types.js';
|
|
6
6
|
export * from './utils.js';
|
|
7
7
|
export * from './identity.js';
|
|
8
8
|
export * from './executor.js';
|
|
9
|
-
export {
|
|
10
|
-
export {
|
|
11
|
-
export { encodeUnifiedPubKeys, decodeUnifiedPubKeys, createHandshakePayload, createHandshakeResponseContent, extractKeysFromHandshakePayload, extractKeysFromHandshakeResponse, parseHandshakeKeys } from './payload.js';
|
|
12
|
-
export { decryptAndExtractHandshakeKeys, decryptMessage, decryptHandshakeResponse } from './crypto.js';
|
|
9
|
+
export { encodeUnifiedPubKeys, decodeUnifiedPubKeys, createHandshakeResponseContent, extractKeysFromHandshakeResponse, parseHandshakeKeys } from './payload.js';
|
|
10
|
+
export { decryptAndExtractHandshakeKeys, decryptHandshakeResponse } from './crypto.js';
|
|
13
11
|
export { verifyIdentityProof, verifyAndExtractHandshakeKeys, verifyAndExtractHandshakeResponseKeys } from './verify.js';
|
|
14
12
|
export { deriveIdentityKeyPairWithProof, deriveIdentityWithUnifiedKeys } from './identity.js';
|
|
15
13
|
export { IExecutor, EOAExecutor, UserOpExecutor, DirectEntryPointExecutor, ExecutorFactory } from './executor.js';
|
|
16
|
-
export {
|
|
17
|
-
export type {
|
|
14
|
+
export { SafeSessionSigner } from "./utils/safeSessionSigner.js";
|
|
15
|
+
export type { SafeSessionSignerOptions } from "./utils/safeSessionSigner.js";
|
|
16
|
+
export { VerbethClient, VerbethClientBuilder, createVerbethClient, matchHsrToContact, } from './client/index.js';
|
|
17
|
+
export type { VerbethClientConfig, VerbethClientCallbacks, TopicRatchetEvent, MessageDecryptedEvent, HandshakeResult, HandshakeResponseResult, SessionStore, PendingStore, PreparedMessage, DecryptedMessage, PendingMessage, PendingStatus, SendResult, ConfirmResult, SerializedSessionInfo, HsrEventData, CreateInitiatorSessionFromHsrParams, CreateVerbethClientOptions, PendingContactEntry, } from './client/index.js';
|
|
18
|
+
export * from './ratchet/index.js';
|
|
19
|
+
export { dh, deriveTopic, hybridInitialSecret } from './ratchet/kdf.js';
|
|
20
|
+
export { kem } from './pq/kem.js';
|
|
21
|
+
export * from './addresses.js';
|
|
18
22
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/src/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAEA,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAE9B,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,8BAA8B,EAC9B,gCAAgC,EAChC,kBAAkB,EACnB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,8BAA8B,EAC9B,wBAAwB,EACzB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,mBAAmB,EACnB,6BAA6B,EAC7B,qCAAqC,EACtC,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,8BAA8B,EAC9B,6BAA6B,EAC9B,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,SAAS,EACT,WAAW,EACX,cAAc,EACd,wBAAwB,EACxB,eAAe,EAChB,MAAM,eAAe,CAAC;AAGvB,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,YAAY,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AAE7E,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAE3B,YAAY,EACV,mBAAmB,EACnB,sBAAsB,EACtB,iBAAiB,EACjB,qBAAqB,EACrB,eAAe,EACf,uBAAuB,EAEvB,YAAY,EACZ,YAAY,EAEZ,eAAe,EACf,gBAAgB,EAChB,cAAc,EACd,aAAa,EAEb,UAAU,EACV,aAAa,EAEb,qBAAqB,EACrB,YAAY,EACZ,mCAAmC,EACnC,0BAA0B,EAC1B,mBAAmB,GACpB,MAAM,mBAAmB,CAAC;AAE3B,cAAc,oBAAoB,CAAC;AACnC,OAAO,EAAE,EAAE,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAExE,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAElC,cAAc,gBAAgB,CAAC"}
|
package/dist/src/index.js
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
|
+
// packages/sdk/src/index.ts
|
|
1
2
|
export * from './crypto.js';
|
|
2
3
|
export * from './payload.js';
|
|
3
|
-
export * from './
|
|
4
|
+
export * from './handshake.js';
|
|
4
5
|
export * from './verify.js';
|
|
5
6
|
export * from './types.js';
|
|
6
7
|
export * from './utils.js';
|
|
7
8
|
export * from './identity.js';
|
|
8
9
|
export * from './executor.js';
|
|
9
|
-
export {
|
|
10
|
-
export {
|
|
11
|
-
export { encodeUnifiedPubKeys, decodeUnifiedPubKeys, createHandshakePayload, createHandshakeResponseContent, extractKeysFromHandshakePayload, extractKeysFromHandshakeResponse, parseHandshakeKeys } from './payload.js';
|
|
12
|
-
export { decryptAndExtractHandshakeKeys, decryptMessage, decryptHandshakeResponse } from './crypto.js';
|
|
10
|
+
export { encodeUnifiedPubKeys, decodeUnifiedPubKeys, createHandshakeResponseContent, extractKeysFromHandshakeResponse, parseHandshakeKeys } from './payload.js';
|
|
11
|
+
export { decryptAndExtractHandshakeKeys, decryptHandshakeResponse } from './crypto.js';
|
|
13
12
|
export { verifyIdentityProof, verifyAndExtractHandshakeKeys, verifyAndExtractHandshakeResponseKeys } from './verify.js';
|
|
14
13
|
export { deriveIdentityKeyPairWithProof, deriveIdentityWithUnifiedKeys } from './identity.js';
|
|
15
14
|
export { EOAExecutor, UserOpExecutor, DirectEntryPointExecutor, ExecutorFactory } from './executor.js';
|
|
16
|
-
|
|
17
|
-
export { VerbethClient } from './client/index.js';
|
|
15
|
+
export { SafeSessionSigner } from "./utils/safeSessionSigner.js";
|
|
16
|
+
export { VerbethClient, VerbethClientBuilder, createVerbethClient, matchHsrToContact, } from './client/index.js';
|
|
17
|
+
export * from './ratchet/index.js';
|
|
18
|
+
export { dh, deriveTopic, hybridInitialSecret } from './ratchet/kdf.js';
|
|
19
|
+
export { kem } from './pq/kem.js';
|
|
20
|
+
export * from './addresses.js';
|
package/dist/src/payload.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IdentityProof
|
|
1
|
+
import { IdentityProof } from './types.js';
|
|
2
2
|
export interface EncryptedPayload {
|
|
3
3
|
v: number;
|
|
4
4
|
epk: string;
|
|
@@ -6,14 +6,6 @@ export interface EncryptedPayload {
|
|
|
6
6
|
ct: string;
|
|
7
7
|
sig?: string;
|
|
8
8
|
}
|
|
9
|
-
export interface MessagePayload {
|
|
10
|
-
content: string;
|
|
11
|
-
timestamp?: number;
|
|
12
|
-
messageType?: 'text' | 'file' | 'media';
|
|
13
|
-
metadata?: Record<string, any>;
|
|
14
|
-
}
|
|
15
|
-
export interface HandshakeResponsePayload extends EncryptedPayload {
|
|
16
|
-
}
|
|
17
9
|
export interface HandshakeContent {
|
|
18
10
|
plaintextPayload: string;
|
|
19
11
|
identityProof: IdentityProof;
|
|
@@ -50,30 +42,11 @@ export interface HandshakePayload {
|
|
|
50
42
|
export interface HandshakeResponseContent {
|
|
51
43
|
unifiedPubKeys: Uint8Array;
|
|
52
44
|
ephemeralPubKey: Uint8Array;
|
|
45
|
+
kemCiphertext?: Uint8Array;
|
|
53
46
|
note?: string;
|
|
54
47
|
identityProof: IdentityProof;
|
|
55
|
-
topicInfo?: TopicInfoWire;
|
|
56
48
|
}
|
|
57
|
-
export declare function
|
|
58
|
-
export declare function decodeHandshakePayload(encoded: Uint8Array): HandshakePayload;
|
|
59
|
-
export declare function encodeHandshakeResponseContent(content: HandshakeResponseContent): Uint8Array;
|
|
60
|
-
export declare function decodeHandshakeResponseContent(encoded: Uint8Array): HandshakeResponseContent;
|
|
61
|
-
/**
|
|
62
|
-
* Creates HandshakePayload from separate identity keys
|
|
63
|
-
*/
|
|
64
|
-
export declare function createHandshakePayload(identityPubKey: Uint8Array, signingPubKey: Uint8Array, ephemeralPubKey: Uint8Array, plaintextPayload: string): HandshakePayload;
|
|
65
|
-
/**
|
|
66
|
-
* Creates HandshakeResponseContent from separate identity keys
|
|
67
|
-
*/
|
|
68
|
-
export declare function createHandshakeResponseContent(identityPubKey: Uint8Array, signingPubKey: Uint8Array, ephemeralPubKey: Uint8Array, note?: string, identityProof?: IdentityProof, topicInfo?: TopicInfoWire): HandshakeResponseContent;
|
|
69
|
-
/**
|
|
70
|
-
* Extracts individual keys from HandshakePayload
|
|
71
|
-
*/
|
|
72
|
-
export declare function extractKeysFromHandshakePayload(payload: HandshakePayload): {
|
|
73
|
-
identityPubKey: Uint8Array;
|
|
74
|
-
signingPubKey: Uint8Array;
|
|
75
|
-
ephemeralPubKey: Uint8Array;
|
|
76
|
-
} | null;
|
|
49
|
+
export declare function createHandshakeResponseContent(identityPubKey: Uint8Array, signingPubKey: Uint8Array, ephemeralPubKey: Uint8Array, note?: string, identityProof?: IdentityProof, kemCiphertext?: Uint8Array): HandshakeResponseContent;
|
|
77
50
|
/**
|
|
78
51
|
* Extracts individual keys from HandshakeResponseContent
|
|
79
52
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"payload.d.ts","sourceRoot":"","sources":["../../src/payload.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"payload.d.ts","sourceRoot":"","sources":["../../src/payload.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,WAAW,gBAAgB;IAC/B,CAAC,EAAE,MAAM,CAAC;IACV,GAAG,EAAE,MAAM,CAAC;IACZ,CAAC,EAAE,MAAM,CAAC;IACV,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,gBAAgB;IAC/B,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,aAAa,CAAC;CAC9B;AAED,wBAAgB,qBAAqB,CAAC,gBAAgB,EAAE,MAAM,GAAG,gBAAgB,CAUhF;AAED,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,gBAAgB,GAAG,MAAM,CAE3E;AAED,wBAAgB,aAAa,CAAC,eAAe,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,GAAG,CAAC,EAAE,UAAU,GAAG,MAAM,CAS9H;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG;IAC3C,GAAG,EAAE,UAAU,CAAC;IAChB,KAAK,EAAE,UAAU,CAAC;IAClB,UAAU,EAAE,UAAU,CAAC;IACvB,GAAG,CAAC,EAAE,UAAU,CAAA;CACjB,CAyBA;AAID,wBAAgB,uBAAuB,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,GAAG,UAAU,CAQjE;AAGD,wBAAgB,uBAAuB,CAAC,CAAC,EACvC,OAAO,EAAE,UAAU,EACnB,SAAS,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,GACzB,CAAC,CAGH;AAID;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,cAAc,EAAE,UAAU,EAAG,oBAAoB;AACjD,aAAa,EAAE,UAAU,GACxB,UAAU,CAOZ;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,UAAU,GAAG;IACzD,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,UAAU,CAAC;IAC3B,aAAa,EAAE,UAAU,CAAC;CAC3B,GAAG,IAAI,CAkBP;AAED,MAAM,WAAW,gBAAgB;IAC/B,cAAc,EAAE,UAAU,CAAC;IAC3B,eAAe,EAAE,UAAU,CAAC;IAC5B,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,wBAAwB;IACvC,cAAc,EAAE,UAAU,CAAC;IAC3B,eAAe,EAAE,UAAU,CAAC;IAC5B,aAAa,CAAC,EAAE,UAAU,CAAC;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,aAAa,CAAC;CAC9B;AAED,wBAAgB,8BAA8B,CAC5C,cAAc,EAAE,UAAU,EAC1B,aAAa,EAAE,UAAU,EACzB,eAAe,EAAE,UAAU,EAC3B,IAAI,CAAC,EAAE,MAAM,EACb,aAAa,CAAC,EAAE,aAAa,EAC7B,aAAa,CAAC,EAAE,UAAU,GACzB,wBAAwB,CAY1B;AAED;;GAEG;AACH,wBAAgB,gCAAgC,CAAC,OAAO,EAAE,wBAAwB,GAAG;IACnF,cAAc,EAAE,UAAU,CAAC;IAC3B,aAAa,EAAE,UAAU,CAAC;IAC1B,eAAe,EAAE,UAAU,CAAC;CAC7B,GAAG,IAAI,CASP;AAGD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG;IAC9D,cAAc,EAAE,UAAU,CAAC;IAC3B,aAAa,EAAE,UAAU,CAAC;CAC3B,GAAG,IAAI,CAkBP"}
|
package/dist/src/payload.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// packages/sdk/src/payload.ts
|
|
1
2
|
export function parseHandshakePayload(plaintextPayload) {
|
|
2
3
|
try {
|
|
3
4
|
const parsed = JSON.parse(plaintextPayload);
|
|
@@ -80,7 +81,6 @@ signingPubKey // Ed25519 - 32 bytes
|
|
|
80
81
|
*/
|
|
81
82
|
export function decodeUnifiedPubKeys(pubKeys) {
|
|
82
83
|
if (pubKeys.length === 64) {
|
|
83
|
-
// Legacy
|
|
84
84
|
return {
|
|
85
85
|
version: 0,
|
|
86
86
|
identityPubKey: pubKeys.slice(0, 32),
|
|
@@ -88,7 +88,6 @@ export function decodeUnifiedPubKeys(pubKeys) {
|
|
|
88
88
|
};
|
|
89
89
|
}
|
|
90
90
|
if (pubKeys.length === 65 && pubKeys[0] === 0x01) {
|
|
91
|
-
// V1: with versioning
|
|
92
91
|
return {
|
|
93
92
|
version: 1,
|
|
94
93
|
identityPubKey: pubKeys.slice(1, 33),
|
|
@@ -97,89 +96,16 @@ export function decodeUnifiedPubKeys(pubKeys) {
|
|
|
97
96
|
}
|
|
98
97
|
return null;
|
|
99
98
|
}
|
|
100
|
-
export function
|
|
101
|
-
return new TextEncoder().encode(JSON.stringify({
|
|
102
|
-
unifiedPubKeys: Buffer.from(payload.unifiedPubKeys).toString('base64'),
|
|
103
|
-
ephemeralPubKey: Buffer.from(payload.ephemeralPubKey).toString('base64'),
|
|
104
|
-
plaintextPayload: payload.plaintextPayload
|
|
105
|
-
}));
|
|
106
|
-
}
|
|
107
|
-
export function decodeHandshakePayload(encoded) {
|
|
108
|
-
const json = new TextDecoder().decode(encoded);
|
|
109
|
-
const parsed = JSON.parse(json);
|
|
110
|
-
return {
|
|
111
|
-
unifiedPubKeys: Uint8Array.from(Buffer.from(parsed.unifiedPubKeys, 'base64')),
|
|
112
|
-
ephemeralPubKey: Uint8Array.from(Buffer.from(parsed.ephemeralPubKey, 'base64')),
|
|
113
|
-
plaintextPayload: parsed.plaintextPayload
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
export function encodeHandshakeResponseContent(content) {
|
|
117
|
-
return new TextEncoder().encode(JSON.stringify({
|
|
118
|
-
unifiedPubKeys: Buffer.from(content.unifiedPubKeys).toString('base64'),
|
|
119
|
-
ephemeralPubKey: Buffer.from(content.ephemeralPubKey).toString('base64'),
|
|
120
|
-
note: content.note,
|
|
121
|
-
identityProof: content.identityProof,
|
|
122
|
-
topicInfo: content.topicInfo ? {
|
|
123
|
-
out: content.topicInfo.out,
|
|
124
|
-
in: content.topicInfo.in,
|
|
125
|
-
chk: content.topicInfo.chk
|
|
126
|
-
} : undefined
|
|
127
|
-
}));
|
|
128
|
-
}
|
|
129
|
-
export function decodeHandshakeResponseContent(encoded) {
|
|
130
|
-
const json = new TextDecoder().decode(encoded);
|
|
131
|
-
const obj = JSON.parse(json);
|
|
132
|
-
if (!obj.identityProof) {
|
|
133
|
-
throw new Error("Invalid handshake response: missing identityProof");
|
|
134
|
-
}
|
|
135
|
-
return {
|
|
136
|
-
unifiedPubKeys: Uint8Array.from(Buffer.from(obj.unifiedPubKeys, 'base64')),
|
|
137
|
-
ephemeralPubKey: Uint8Array.from(Buffer.from(obj.ephemeralPubKey, 'base64')),
|
|
138
|
-
note: obj.note,
|
|
139
|
-
identityProof: obj.identityProof,
|
|
140
|
-
topicInfo: obj.topicInfo ? {
|
|
141
|
-
out: obj.topicInfo.out,
|
|
142
|
-
in: obj.topicInfo.in,
|
|
143
|
-
chk: obj.topicInfo.chk
|
|
144
|
-
} : undefined
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
/**
|
|
148
|
-
* Creates HandshakePayload from separate identity keys
|
|
149
|
-
*/
|
|
150
|
-
export function createHandshakePayload(identityPubKey, signingPubKey, ephemeralPubKey, plaintextPayload) {
|
|
151
|
-
return {
|
|
152
|
-
unifiedPubKeys: encodeUnifiedPubKeys(identityPubKey, signingPubKey),
|
|
153
|
-
ephemeralPubKey,
|
|
154
|
-
plaintextPayload
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
/**
|
|
158
|
-
* Creates HandshakeResponseContent from separate identity keys
|
|
159
|
-
*/
|
|
160
|
-
export function createHandshakeResponseContent(identityPubKey, signingPubKey, ephemeralPubKey, note, identityProof, topicInfo) {
|
|
99
|
+
export function createHandshakeResponseContent(identityPubKey, signingPubKey, ephemeralPubKey, note, identityProof, kemCiphertext) {
|
|
161
100
|
if (!identityProof) {
|
|
162
101
|
throw new Error("Identity proof is now mandatory for handshake responses");
|
|
163
102
|
}
|
|
164
103
|
return {
|
|
165
104
|
unifiedPubKeys: encodeUnifiedPubKeys(identityPubKey, signingPubKey),
|
|
166
105
|
ephemeralPubKey,
|
|
106
|
+
...(kemCiphertext && { kemCiphertext }),
|
|
167
107
|
note,
|
|
168
108
|
identityProof,
|
|
169
|
-
topicInfo
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
/**
|
|
173
|
-
* Extracts individual keys from HandshakePayload
|
|
174
|
-
*/
|
|
175
|
-
export function extractKeysFromHandshakePayload(payload) {
|
|
176
|
-
const decoded = decodeUnifiedPubKeys(payload.unifiedPubKeys);
|
|
177
|
-
if (!decoded)
|
|
178
|
-
return null;
|
|
179
|
-
return {
|
|
180
|
-
identityPubKey: decoded.identityPubKey,
|
|
181
|
-
signingPubKey: decoded.signingPubKey,
|
|
182
|
-
ephemeralPubKey: payload.ephemeralPubKey
|
|
183
109
|
};
|
|
184
110
|
}
|
|
185
111
|
/**
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export declare const kem: {
|
|
2
|
+
publicKeyBytes: number;
|
|
3
|
+
ciphertextBytes: number;
|
|
4
|
+
sharedSecretBytes: number;
|
|
5
|
+
/**
|
|
6
|
+
* Generate a new ML-KEM-768 keypair.
|
|
7
|
+
*
|
|
8
|
+
* @returns Object containing publicKey and secretKey
|
|
9
|
+
*/
|
|
10
|
+
generateKeyPair(): {
|
|
11
|
+
publicKey: Uint8Array;
|
|
12
|
+
secretKey: Uint8Array;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Encapsulate a shared secret using the recipient's public key.
|
|
16
|
+
*
|
|
17
|
+
* @param publicKey - Recipient's ML-KEM-768 public key
|
|
18
|
+
* @returns Object containing ciphertext and sharedSecret
|
|
19
|
+
*/
|
|
20
|
+
encapsulate(publicKey: Uint8Array): {
|
|
21
|
+
ciphertext: Uint8Array;
|
|
22
|
+
sharedSecret: Uint8Array;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Decapsulate a ciphertext using the secret key to recover the shared secret.
|
|
26
|
+
*
|
|
27
|
+
* @param ciphertext - KEM ciphertext
|
|
28
|
+
* @param secretKey - Recipient's ML-KEM-768 secret key
|
|
29
|
+
* @returns Shared secret
|
|
30
|
+
*/
|
|
31
|
+
decapsulate(ciphertext: Uint8Array, secretKey: Uint8Array): Uint8Array;
|
|
32
|
+
};
|
|
33
|
+
//# sourceMappingURL=kem.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kem.d.ts","sourceRoot":"","sources":["../../../src/pq/kem.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,GAAG;;;;IAKd;;;;OAIG;uBACgB;QAAE,SAAS,EAAE,UAAU,CAAC;QAAC,SAAS,EAAE,UAAU,CAAA;KAAE;IAInE;;;;;OAKG;2BACoB,UAAU,GAAG;QAAE,UAAU,EAAE,UAAU,CAAC;QAAC,YAAY,EAAE,UAAU,CAAA;KAAE;IAKxF;;;;;;OAMG;4BACqB,UAAU,aAAa,UAAU,GAAG,UAAU;CAGvE,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// packages/sdk/src/pq/kem.ts
|
|
2
|
+
/**
|
|
3
|
+
* ML-KEM-768 Key Encapsulation Mechanism wrapper.
|
|
4
|
+
*
|
|
5
|
+
* Provides post-quantum key encapsulation for hybrid handshakes.
|
|
6
|
+
*/
|
|
7
|
+
import { ml_kem768 } from '@noble/post-quantum/ml-kem.js';
|
|
8
|
+
export const kem = {
|
|
9
|
+
publicKeyBytes: 1184, // in bytes
|
|
10
|
+
ciphertextBytes: 1088,
|
|
11
|
+
sharedSecretBytes: 32,
|
|
12
|
+
/**
|
|
13
|
+
* Generate a new ML-KEM-768 keypair.
|
|
14
|
+
*
|
|
15
|
+
* @returns Object containing publicKey and secretKey
|
|
16
|
+
*/
|
|
17
|
+
generateKeyPair() {
|
|
18
|
+
return ml_kem768.keygen();
|
|
19
|
+
},
|
|
20
|
+
/**
|
|
21
|
+
* Encapsulate a shared secret using the recipient's public key.
|
|
22
|
+
*
|
|
23
|
+
* @param publicKey - Recipient's ML-KEM-768 public key
|
|
24
|
+
* @returns Object containing ciphertext and sharedSecret
|
|
25
|
+
*/
|
|
26
|
+
encapsulate(publicKey) {
|
|
27
|
+
const result = ml_kem768.encapsulate(publicKey);
|
|
28
|
+
return { ciphertext: result.cipherText, sharedSecret: result.sharedSecret };
|
|
29
|
+
},
|
|
30
|
+
/**
|
|
31
|
+
* Decapsulate a ciphertext using the secret key to recover the shared secret.
|
|
32
|
+
*
|
|
33
|
+
* @param ciphertext - KEM ciphertext
|
|
34
|
+
* @param secretKey - Recipient's ML-KEM-768 secret key
|
|
35
|
+
* @returns Shared secret
|
|
36
|
+
*/
|
|
37
|
+
decapsulate(ciphertext, secretKey) {
|
|
38
|
+
return ml_kem768.decapsulate(ciphertext, secretKey);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { MessageHeader } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Verify message signature before any ratchet operations.
|
|
4
|
+
* This is the primary DoS protection layer.
|
|
5
|
+
*
|
|
6
|
+
* The signature covers (header || ciphertext), where header is the 40-byte
|
|
7
|
+
* binary encoding of (dh, pn, n).
|
|
8
|
+
*
|
|
9
|
+
* @param signature - Ed25519 signature (64 bytes)
|
|
10
|
+
* @param header - Message header
|
|
11
|
+
* @param ciphertext - Encrypted payload
|
|
12
|
+
* @param signingPublicKey - Contact's Ed25519 public key (32 bytes)
|
|
13
|
+
* @returns true if signature is valid
|
|
14
|
+
*/
|
|
15
|
+
export declare function verifyMessageSignature(signature: Uint8Array, header: MessageHeader, ciphertext: Uint8Array, signingPublicKey: Uint8Array): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Create Ed25519 signature for a message.
|
|
18
|
+
*
|
|
19
|
+
* @param header - Message header
|
|
20
|
+
* @param ciphertext - Encrypted payload
|
|
21
|
+
* @param signingSecretKey - Ed25519 secret key (64 bytes)
|
|
22
|
+
* @returns Ed25519 signature (64 bytes)
|
|
23
|
+
*/
|
|
24
|
+
export declare function signMessage(header: MessageHeader, ciphertext: Uint8Array, signingSecretKey: Uint8Array): Uint8Array;
|
|
25
|
+
/**
|
|
26
|
+
* Validate that a parsed payload has a well-formed signature and header.
|
|
27
|
+
* Does NOT verify the signature - just checks lengths and format.
|
|
28
|
+
*
|
|
29
|
+
* @param signature - Signature bytes
|
|
30
|
+
* @param header - Parsed header
|
|
31
|
+
* @returns true if format is valid
|
|
32
|
+
*/
|
|
33
|
+
export declare function isValidPayloadFormat(signature: Uint8Array, header: MessageHeader): boolean;
|
|
34
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/ratchet/auth.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAM3C;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,UAAU,EACrB,MAAM,EAAE,aAAa,EACrB,UAAU,EAAE,UAAU,EACtB,gBAAgB,EAAE,UAAU,GAC3B,OAAO,CAmBT;AAkBD;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,aAAa,EACrB,UAAU,EAAE,UAAU,EACtB,gBAAgB,EAAE,UAAU,GAC3B,UAAU,CAOZ;AAMD;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,UAAU,EACrB,MAAM,EAAE,aAAa,GACpB,OAAO,CAST"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// packages/sdk/src/ratchet/auth.ts
|
|
2
|
+
/**
|
|
3
|
+
* Message Authentication for Ratchet Protocol.
|
|
4
|
+
*/
|
|
5
|
+
import nacl from 'tweetnacl';
|
|
6
|
+
// =============================================================================
|
|
7
|
+
// Signature Verification
|
|
8
|
+
// =============================================================================
|
|
9
|
+
/**
|
|
10
|
+
* Verify message signature before any ratchet operations.
|
|
11
|
+
* This is the primary DoS protection layer.
|
|
12
|
+
*
|
|
13
|
+
* The signature covers (header || ciphertext), where header is the 40-byte
|
|
14
|
+
* binary encoding of (dh, pn, n).
|
|
15
|
+
*
|
|
16
|
+
* @param signature - Ed25519 signature (64 bytes)
|
|
17
|
+
* @param header - Message header
|
|
18
|
+
* @param ciphertext - Encrypted payload
|
|
19
|
+
* @param signingPublicKey - Contact's Ed25519 public key (32 bytes)
|
|
20
|
+
* @returns true if signature is valid
|
|
21
|
+
*/
|
|
22
|
+
export function verifyMessageSignature(signature, header, ciphertext, signingPublicKey) {
|
|
23
|
+
if (signature.length !== 64) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
if (signingPublicKey.length !== 32) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
// Reconstruct signed data: header || ciphertext
|
|
30
|
+
const headerBytes = encodeHeaderForSigning(header);
|
|
31
|
+
const dataToVerify = new Uint8Array(headerBytes.length + ciphertext.length);
|
|
32
|
+
dataToVerify.set(headerBytes, 0);
|
|
33
|
+
dataToVerify.set(ciphertext, headerBytes.length);
|
|
34
|
+
try {
|
|
35
|
+
return nacl.sign.detached.verify(dataToVerify, signature, signingPublicKey);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Encode header as 40 bytes for signature verification.
|
|
43
|
+
* Format: dh (32) + pn (4, BE) + n (4, BE)
|
|
44
|
+
*/
|
|
45
|
+
function encodeHeaderForSigning(header) {
|
|
46
|
+
const buf = new Uint8Array(40);
|
|
47
|
+
buf.set(header.dh, 0);
|
|
48
|
+
new DataView(buf.buffer).setUint32(32, header.pn, false); // big-endian
|
|
49
|
+
new DataView(buf.buffer).setUint32(36, header.n, false);
|
|
50
|
+
return buf;
|
|
51
|
+
}
|
|
52
|
+
// =============================================================================
|
|
53
|
+
// Signature Creation
|
|
54
|
+
// =============================================================================
|
|
55
|
+
/**
|
|
56
|
+
* Create Ed25519 signature for a message.
|
|
57
|
+
*
|
|
58
|
+
* @param header - Message header
|
|
59
|
+
* @param ciphertext - Encrypted payload
|
|
60
|
+
* @param signingSecretKey - Ed25519 secret key (64 bytes)
|
|
61
|
+
* @returns Ed25519 signature (64 bytes)
|
|
62
|
+
*/
|
|
63
|
+
export function signMessage(header, ciphertext, signingSecretKey) {
|
|
64
|
+
const headerBytes = encodeHeaderForSigning(header);
|
|
65
|
+
const dataToSign = new Uint8Array(headerBytes.length + ciphertext.length);
|
|
66
|
+
dataToSign.set(headerBytes, 0);
|
|
67
|
+
dataToSign.set(ciphertext, headerBytes.length);
|
|
68
|
+
return nacl.sign.detached(dataToSign, signingSecretKey);
|
|
69
|
+
}
|
|
70
|
+
// =============================================================================
|
|
71
|
+
// Validation Helpers
|
|
72
|
+
// =============================================================================
|
|
73
|
+
/**
|
|
74
|
+
* Validate that a parsed payload has a well-formed signature and header.
|
|
75
|
+
* Does NOT verify the signature - just checks lengths and format.
|
|
76
|
+
*
|
|
77
|
+
* @param signature - Signature bytes
|
|
78
|
+
* @param header - Parsed header
|
|
79
|
+
* @returns true if format is valid
|
|
80
|
+
*/
|
|
81
|
+
export function isValidPayloadFormat(signature, header) {
|
|
82
|
+
return (signature.length === 64 &&
|
|
83
|
+
header.dh.length === 32 &&
|
|
84
|
+
header.pn >= 0 &&
|
|
85
|
+
header.n >= 0 &&
|
|
86
|
+
Number.isInteger(header.pn) &&
|
|
87
|
+
Number.isInteger(header.n));
|
|
88
|
+
}
|