@tinyhumansai/tinyplace 0.1.0 → 0.1.1

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 (60) hide show
  1. package/package.json +2 -1
  2. package/src/api/a2a.ts +0 -50
  3. package/src/api/admin.ts +0 -95
  4. package/src/api/broadcasts.ts +0 -110
  5. package/src/api/channels.ts +0 -110
  6. package/src/api/directory.ts +0 -45
  7. package/src/api/escrow.ts +0 -163
  8. package/src/api/events.ts +0 -133
  9. package/src/api/explorer.ts +0 -48
  10. package/src/api/groups.ts +0 -64
  11. package/src/api/inbox.ts +0 -71
  12. package/src/api/keys.ts +0 -18
  13. package/src/api/ledger.ts +0 -28
  14. package/src/api/marketplace.ts +0 -165
  15. package/src/api/messages.ts +0 -23
  16. package/src/api/moderation.ts +0 -71
  17. package/src/api/payments.ts +0 -47
  18. package/src/api/pricing.ts +0 -122
  19. package/src/api/profiles.ts +0 -43
  20. package/src/api/registry.ts +0 -143
  21. package/src/api/reputation.ts +0 -60
  22. package/src/api/search.ts +0 -59
  23. package/src/api/stats.ts +0 -32
  24. package/src/auth.ts +0 -75
  25. package/src/client.ts +0 -120
  26. package/src/crypto.ts +0 -74
  27. package/src/http.ts +0 -147
  28. package/src/index.ts +0 -72
  29. package/src/local-signer.ts +0 -78
  30. package/src/signal/crypto.ts +0 -229
  31. package/src/signal/index.ts +0 -28
  32. package/src/signal/keys.ts +0 -54
  33. package/src/signal/memory-store.ts +0 -66
  34. package/src/signal/ratchet.ts +0 -162
  35. package/src/signal/session.ts +0 -189
  36. package/src/signal/store.ts +0 -49
  37. package/src/signal/x3dh.ts +0 -130
  38. package/src/signer.ts +0 -21
  39. package/src/types/broadcasts.ts +0 -81
  40. package/src/types/commerce.ts +0 -206
  41. package/src/types/directory.ts +0 -98
  42. package/src/types/escrow.ts +0 -163
  43. package/src/types/events.ts +0 -155
  44. package/src/types/explorer.ts +0 -152
  45. package/src/types/groups.ts +0 -62
  46. package/src/types/identity.ts +0 -113
  47. package/src/types/index.ts +0 -16
  48. package/src/types/ledger.ts +0 -78
  49. package/src/types/marketplace.ts +0 -166
  50. package/src/types/messaging.ts +0 -77
  51. package/src/types/payments.ts +0 -103
  52. package/src/types/profile.ts +0 -55
  53. package/src/types/reputation.ts +0 -98
  54. package/src/types/search.ts +0 -61
  55. package/src/types/social.ts +0 -186
  56. package/src/websocket.ts +0 -112
  57. package/tests/signal.test.ts +0 -353
  58. package/tests/staging.test.ts +0 -650
  59. package/tsconfig.json +0 -15
  60. package/vitest.config.ts +0 -7
@@ -1,66 +0,0 @@
1
- import type { X25519KeyPair } from "./crypto.js";
2
- import type { SessionStore, SessionState, PreKeyPair, SignedPreKeyPair } from "./store.js";
3
-
4
- export class MemorySessionStore implements SessionStore {
5
- private readonly identityKeyPair: X25519KeyPair;
6
- private readonly signedPreKeys = new Map<string, SignedPreKeyPair>();
7
- private readonly preKeys = new Map<string, PreKeyPair>();
8
- private readonly sessions = new Map<string, SessionState>();
9
- private activeSignedPreKeyId: string | null = null;
10
-
11
- constructor(identityKeyPair: X25519KeyPair) {
12
- this.identityKeyPair = identityKeyPair;
13
- }
14
-
15
- async getIdentityX25519KeyPair(): Promise<X25519KeyPair> {
16
- return this.identityKeyPair;
17
- }
18
-
19
- async getSignedPreKey(keyId: string): Promise<SignedPreKeyPair | null> {
20
- return this.signedPreKeys.get(keyId) ?? null;
21
- }
22
-
23
- async getActiveSignedPreKey(): Promise<SignedPreKeyPair> {
24
- if (!this.activeSignedPreKeyId) {
25
- throw new Error("No active signed pre-key");
26
- }
27
- const key = this.signedPreKeys.get(this.activeSignedPreKeyId);
28
- if (!key) {
29
- throw new Error("Active signed pre-key not found");
30
- }
31
- return key;
32
- }
33
-
34
- async storeSignedPreKey(preKey: SignedPreKeyPair): Promise<void> {
35
- this.signedPreKeys.set(preKey.keyId, preKey);
36
- this.activeSignedPreKeyId = preKey.keyId;
37
- }
38
-
39
- async getPreKey(keyId: string): Promise<PreKeyPair | null> {
40
- return this.preKeys.get(keyId) ?? null;
41
- }
42
-
43
- async removePreKey(keyId: string): Promise<void> {
44
- this.preKeys.delete(keyId);
45
- }
46
-
47
- async storePreKey(preKey: PreKeyPair): Promise<void> {
48
- this.preKeys.set(preKey.keyId, preKey);
49
- }
50
-
51
- async getAllPreKeys(): Promise<Array<PreKeyPair>> {
52
- return Array.from(this.preKeys.values());
53
- }
54
-
55
- async getSession(address: string): Promise<SessionState | null> {
56
- return this.sessions.get(address) ?? null;
57
- }
58
-
59
- async storeSession(address: string, session: SessionState): Promise<void> {
60
- this.sessions.set(address, session);
61
- }
62
-
63
- async removeSession(address: string): Promise<void> {
64
- this.sessions.delete(address);
65
- }
66
- }
@@ -1,162 +0,0 @@
1
- import {
2
- generateX25519KeyPair,
3
- x25519SharedSecret,
4
- kdfRootKey,
5
- kdfChainKey,
6
- encrypt,
7
- decrypt,
8
- } from "./crypto.js";
9
- import { skippedKeyId } from "./store.js";
10
- import type { SessionState } from "./store.js";
11
-
12
- const MAX_SKIP = 1000;
13
-
14
- export interface RatchetHeader {
15
- publicKey: Uint8Array;
16
- previousChainLength: number;
17
- messageNumber: number;
18
- }
19
-
20
- export interface RatchetMessage {
21
- header: RatchetHeader;
22
- ciphertext: Uint8Array;
23
- }
24
-
25
- export async function ratchetEncrypt(
26
- state: SessionState,
27
- plaintext: Uint8Array,
28
- associatedData: Uint8Array,
29
- ): Promise<RatchetMessage> {
30
- if (!state.sendChainKey) {
31
- dhRatchetStep(state);
32
- }
33
- const { chainKey, messageKey } = kdfChainKey(state.sendChainKey!);
34
- state.sendChainKey = chainKey;
35
-
36
- const header: RatchetHeader = {
37
- publicKey: state.dhSendKeyPair.publicKey,
38
- previousChainLength: state.previousChainLength,
39
- messageNumber: state.sendMessageNumber,
40
- };
41
- state.sendMessageNumber++;
42
-
43
- const headerBytes = encodeHeader(header);
44
- const ad = concat(associatedData, headerBytes);
45
- const ciphertext = await encrypt(messageKey, plaintext, ad);
46
-
47
- return { header, ciphertext };
48
- }
49
-
50
- export async function ratchetDecrypt(
51
- state: SessionState,
52
- message: RatchetMessage,
53
- associatedData: Uint8Array,
54
- ): Promise<Uint8Array> {
55
- const skId = skippedKeyId(message.header.publicKey, message.header.messageNumber);
56
- const skippedMk = state.skippedKeys.get(skId);
57
- if (skippedMk) {
58
- state.skippedKeys.delete(skId);
59
- const headerBytes = encodeHeader(message.header);
60
- const ad = concat(associatedData, headerBytes);
61
- return decrypt(skippedMk, message.ciphertext, ad);
62
- }
63
-
64
- const headerKeyChanged =
65
- !state.dhRecvPublicKey ||
66
- !uint8ArrayEqual(state.dhRecvPublicKey, message.header.publicKey);
67
-
68
- if (headerKeyChanged) {
69
- if (state.recvChainKey) {
70
- skipMessageKeys(state, message.header.previousChainLength);
71
- }
72
- dhRatchetStepWithRecv(state, message.header.publicKey);
73
- }
74
-
75
- skipMessageKeys(state, message.header.messageNumber);
76
-
77
- const { chainKey, messageKey } = kdfChainKey(state.recvChainKey!);
78
- state.recvChainKey = chainKey;
79
- state.recvMessageNumber++;
80
-
81
- const headerBytes = encodeHeader(message.header);
82
- const ad = concat(associatedData, headerBytes);
83
- return decrypt(messageKey, message.ciphertext, ad);
84
- }
85
-
86
- function dhRatchetStep(state: SessionState): void {
87
- if (!state.dhRecvPublicKey) {
88
- throw new Error("Cannot perform DH ratchet without recipient public key");
89
- }
90
- const dhOutput = x25519SharedSecret(
91
- state.dhSendKeyPair.privateKey,
92
- state.dhRecvPublicKey,
93
- );
94
- const { rootKey, chainKey } = kdfRootKey(state.rootKey, dhOutput);
95
- state.rootKey = rootKey;
96
- state.sendChainKey = chainKey;
97
- }
98
-
99
- function dhRatchetStepWithRecv(
100
- state: SessionState,
101
- newRecvPublicKey: Uint8Array,
102
- ): void {
103
- state.previousChainLength = state.sendMessageNumber;
104
- state.sendMessageNumber = 0;
105
- state.recvMessageNumber = 0;
106
- state.dhRecvPublicKey = newRecvPublicKey;
107
-
108
- const dhRecv = x25519SharedSecret(
109
- state.dhSendKeyPair.privateKey,
110
- state.dhRecvPublicKey,
111
- );
112
- const recvResult = kdfRootKey(state.rootKey, dhRecv);
113
- state.rootKey = recvResult.rootKey;
114
- state.recvChainKey = recvResult.chainKey;
115
-
116
- state.dhSendKeyPair = generateX25519KeyPair();
117
- const dhSend = x25519SharedSecret(
118
- state.dhSendKeyPair.privateKey,
119
- state.dhRecvPublicKey,
120
- );
121
- const sendResult = kdfRootKey(state.rootKey, dhSend);
122
- state.rootKey = sendResult.rootKey;
123
- state.sendChainKey = sendResult.chainKey;
124
- }
125
-
126
- function skipMessageKeys(state: SessionState, until: number): void {
127
- if (!state.recvChainKey) return;
128
- if (until - state.recvMessageNumber > MAX_SKIP) {
129
- throw new Error("Too many skipped messages");
130
- }
131
- while (state.recvMessageNumber < until) {
132
- const { chainKey, messageKey } = kdfChainKey(state.recvChainKey);
133
- state.recvChainKey = chainKey;
134
- const skId = skippedKeyId(state.dhRecvPublicKey!, state.recvMessageNumber);
135
- state.skippedKeys.set(skId, messageKey);
136
- state.recvMessageNumber++;
137
- }
138
- }
139
-
140
- function encodeHeader(header: RatchetHeader): Uint8Array {
141
- const result = new Uint8Array(32 + 4 + 4);
142
- result.set(header.publicKey);
143
- const view = new DataView(result.buffer);
144
- view.setUint32(32, header.previousChainLength, false);
145
- view.setUint32(36, header.messageNumber, false);
146
- return result;
147
- }
148
-
149
- function concat(a: Uint8Array, b: Uint8Array): Uint8Array {
150
- const result = new Uint8Array(a.length + b.length);
151
- result.set(a);
152
- result.set(b, a.length);
153
- return result;
154
- }
155
-
156
- function uint8ArrayEqual(a: Uint8Array, b: Uint8Array): boolean {
157
- if (a.length !== b.length) return false;
158
- for (let i = 0; i < a.length; i++) {
159
- if (a[i] !== b[i]) return false;
160
- }
161
- return true;
162
- }
@@ -1,189 +0,0 @@
1
- import { toBase64, fromBase64 } from "./crypto.js";
2
- import type { X25519KeyPair } from "./crypto.js";
3
- import { x3dhInitiate, x3dhRespond, buildAssociatedData } from "./x3dh.js";
4
- import type { X3DHBundle } from "./x3dh.js";
5
- import { ratchetEncrypt, ratchetDecrypt } from "./ratchet.js";
6
- import type { RatchetMessage, RatchetHeader } from "./ratchet.js";
7
- import type { SessionStore, SessionState } from "./store.js";
8
- import type { KeyBundle, MessageEnvelope, SignalMetadata } from "../types/index.js";
9
-
10
- export interface EncryptedMessage {
11
- body: string;
12
- type: "CIPHERTEXT" | "PREKEY_BUNDLE";
13
- signal?: SignalMetadata;
14
- }
15
-
16
- export class SignalSession {
17
- private readonly store: SessionStore;
18
- private readonly ourIdentityPublicKey: Uint8Array;
19
-
20
- constructor(store: SessionStore, ourIdentityPublicKey: Uint8Array) {
21
- this.store = store;
22
- this.ourIdentityPublicKey = ourIdentityPublicKey;
23
- }
24
-
25
- async encrypt(
26
- recipientAddress: string,
27
- recipientIdentityKey: Uint8Array,
28
- plaintext: Uint8Array,
29
- recipientBundle?: KeyBundle,
30
- ): Promise<EncryptedMessage> {
31
- let session = await this.store.getSession(recipientAddress);
32
- let isPreKeyMessage = false;
33
- let ephemeralPublicKey: Uint8Array | undefined;
34
- let signedPreKeyId: string | undefined;
35
- let oneTimePreKeyId: string | undefined;
36
-
37
- if (!session && recipientBundle) {
38
- const bundle = parseKeyBundle(recipientBundle, recipientIdentityKey);
39
- const identityKeyPair = await this.store.getIdentityX25519KeyPair();
40
- const result = x3dhInitiate(identityKeyPair, bundle);
41
- session = result.session;
42
- ephemeralPublicKey = result.ephemeralPublicKey;
43
- signedPreKeyId = result.signedPreKeyId;
44
- oneTimePreKeyId = result.oneTimePreKeyId;
45
- isPreKeyMessage = true;
46
- }
47
-
48
- if (!session) {
49
- throw new Error(
50
- `No session for ${recipientAddress}. Provide a key bundle for initial message.`,
51
- );
52
- }
53
-
54
- const associatedData = buildAssociatedData(
55
- this.ourIdentityPublicKey,
56
- recipientIdentityKey,
57
- );
58
- const message = await ratchetEncrypt(session, plaintext, associatedData);
59
- await this.store.storeSession(recipientAddress, session);
60
-
61
- const signal = buildSignalMetadata(message.header, ephemeralPublicKey, signedPreKeyId, oneTimePreKeyId);
62
-
63
- return {
64
- body: toBase64(message.ciphertext),
65
- type: isPreKeyMessage ? "PREKEY_BUNDLE" : "CIPHERTEXT",
66
- signal,
67
- };
68
- }
69
-
70
- async decrypt(
71
- senderAddress: string,
72
- senderIdentityKey: Uint8Array,
73
- envelope: MessageEnvelope,
74
- ): Promise<Uint8Array> {
75
- let session = await this.store.getSession(senderAddress);
76
- const ciphertext = fromBase64(envelope.body);
77
-
78
- if (envelope.type === "PREKEY_BUNDLE" && envelope.signal) {
79
- session = await this.processPreKeyMessage(
80
- senderIdentityKey,
81
- envelope.signal,
82
- );
83
- }
84
-
85
- if (!session) {
86
- throw new Error(`No session for ${senderAddress}`);
87
- }
88
-
89
- const header = parseSignalHeader(envelope.signal);
90
- const associatedData = buildAssociatedData(
91
- senderIdentityKey,
92
- this.ourIdentityPublicKey,
93
- );
94
- const ratchetMessage: RatchetMessage = { header, ciphertext };
95
- const plaintext = await ratchetDecrypt(session, ratchetMessage, associatedData);
96
- await this.store.storeSession(senderAddress, session);
97
-
98
- return plaintext;
99
- }
100
-
101
- private async processPreKeyMessage(
102
- senderIdentityKey: Uint8Array,
103
- signal: SignalMetadata,
104
- ): Promise<SessionState> {
105
- const identityKeyPair = await this.store.getIdentityX25519KeyPair();
106
- const signedPreKey = await this.store.getSignedPreKey(signal.signedPreKeyId!);
107
- if (!signedPreKey) {
108
- throw new Error(`Signed pre-key ${signal.signedPreKeyId} not found`);
109
- }
110
-
111
- let oneTimePreKeyPair: X25519KeyPair | undefined;
112
- if (signal.oneTimePreKeyId) {
113
- const oneTimePreKey = await this.store.getPreKey(signal.oneTimePreKeyId);
114
- if (oneTimePreKey) {
115
- oneTimePreKeyPair = oneTimePreKey.keyPair;
116
- await this.store.removePreKey(signal.oneTimePreKeyId);
117
- }
118
- }
119
-
120
- const ephemeralKey = fromBase64(signal.ephemeralKey!);
121
-
122
- return x3dhRespond(
123
- identityKeyPair,
124
- signedPreKey.keyPair,
125
- senderIdentityKey,
126
- ephemeralKey,
127
- oneTimePreKeyPair,
128
- );
129
- }
130
-
131
- async hasSession(address: string): Promise<boolean> {
132
- const session = await this.store.getSession(address);
133
- return session !== null;
134
- }
135
-
136
- async removeSession(address: string): Promise<void> {
137
- await this.store.removeSession(address);
138
- }
139
- }
140
-
141
- function parseKeyBundle(
142
- bundle: KeyBundle,
143
- recipientX25519IdentityKey: Uint8Array,
144
- ): X3DHBundle {
145
- const result: X3DHBundle = {
146
- identityKey: recipientX25519IdentityKey,
147
- signedPreKeyId: bundle.signedPreKey.keyId,
148
- signedPreKey: fromBase64(bundle.signedPreKey.publicKey),
149
- };
150
- if (bundle.oneTimePreKey) {
151
- result.oneTimePreKeyId = bundle.oneTimePreKey.keyId;
152
- result.oneTimePreKey = fromBase64(bundle.oneTimePreKey.publicKey);
153
- }
154
- return result;
155
- }
156
-
157
- function buildSignalMetadata(
158
- header: RatchetHeader,
159
- ephemeralPublicKey?: Uint8Array,
160
- signedPreKeyId?: string,
161
- oneTimePreKeyId?: string,
162
- ): SignalMetadata {
163
- const signal: SignalMetadata = {
164
- ratchetKey: toBase64(header.publicKey),
165
- messageNumber: header.messageNumber,
166
- previousChainLength: header.previousChainLength,
167
- };
168
- if (ephemeralPublicKey) {
169
- signal.ephemeralKey = toBase64(ephemeralPublicKey);
170
- }
171
- if (signedPreKeyId) {
172
- signal.signedPreKeyId = signedPreKeyId;
173
- }
174
- if (oneTimePreKeyId) {
175
- signal.oneTimePreKeyId = oneTimePreKeyId;
176
- }
177
- return signal;
178
- }
179
-
180
- function parseSignalHeader(signal?: SignalMetadata): RatchetHeader {
181
- if (!signal?.ratchetKey) {
182
- throw new Error("Missing ratchet key in signal metadata");
183
- }
184
- return {
185
- publicKey: fromBase64(signal.ratchetKey),
186
- previousChainLength: signal.previousChainLength ?? 0,
187
- messageNumber: signal.messageNumber ?? 0,
188
- };
189
- }
@@ -1,49 +0,0 @@
1
- import type { X25519KeyPair } from "./crypto.js";
2
-
3
- export interface SessionState {
4
- dhSendKeyPair: X25519KeyPair;
5
- dhRecvPublicKey: Uint8Array | null;
6
- rootKey: Uint8Array;
7
- sendChainKey: Uint8Array | null;
8
- recvChainKey: Uint8Array | null;
9
- sendMessageNumber: number;
10
- recvMessageNumber: number;
11
- previousChainLength: number;
12
- skippedKeys: Map<string, Uint8Array>;
13
- }
14
-
15
- export interface PreKeyPair {
16
- keyId: string;
17
- keyPair: X25519KeyPair;
18
- signature: Uint8Array;
19
- }
20
-
21
- export interface SignedPreKeyPair {
22
- keyId: string;
23
- keyPair: X25519KeyPair;
24
- signature: Uint8Array;
25
- }
26
-
27
- export interface SessionStore {
28
- getIdentityX25519KeyPair(): Promise<X25519KeyPair>;
29
- getSignedPreKey(keyId: string): Promise<SignedPreKeyPair | null>;
30
- getActiveSignedPreKey(): Promise<SignedPreKeyPair>;
31
- storeSignedPreKey(preKey: SignedPreKeyPair): Promise<void>;
32
- getPreKey(keyId: string): Promise<PreKeyPair | null>;
33
- removePreKey(keyId: string): Promise<void>;
34
- storePreKey(preKey: PreKeyPair): Promise<void>;
35
- getAllPreKeys(): Promise<Array<PreKeyPair>>;
36
- getSession(address: string): Promise<SessionState | null>;
37
- storeSession(address: string, session: SessionState): Promise<void>;
38
- removeSession(address: string): Promise<void>;
39
- }
40
-
41
- export function skippedKeyId(
42
- ratchetPublicKey: Uint8Array,
43
- messageNumber: number,
44
- ): string {
45
- const hex = Array.from(ratchetPublicKey)
46
- .map((b) => b.toString(16).padStart(2, "0"))
47
- .join("");
48
- return `${hex}:${messageNumber}`;
49
- }
@@ -1,130 +0,0 @@
1
- import { hkdf } from "@noble/hashes/hkdf.js";
2
- import { sha256 } from "@noble/hashes/sha2.js";
3
- import {
4
- generateX25519KeyPair,
5
- x25519SharedSecret,
6
- toBase64,
7
- } from "./crypto.js";
8
- import type { X25519KeyPair } from "./crypto.js";
9
- import type { SessionState } from "./store.js";
10
-
11
- const X3DH_INFO = new TextEncoder().encode("WhisperText");
12
- const PADDING = new Uint8Array(32).fill(0xff);
13
-
14
- export interface X3DHBundle {
15
- identityKey: Uint8Array;
16
- signedPreKeyId: string;
17
- signedPreKey: Uint8Array;
18
- oneTimePreKeyId?: string;
19
- oneTimePreKey?: Uint8Array;
20
- }
21
-
22
- export interface X3DHInitResult {
23
- session: SessionState;
24
- ephemeralPublicKey: Uint8Array;
25
- signedPreKeyId: string;
26
- oneTimePreKeyId?: string;
27
- }
28
-
29
- export function x3dhInitiate(
30
- ourIdentityKeyPair: X25519KeyPair,
31
- theirBundle: X3DHBundle,
32
- ): X3DHInitResult {
33
- const ephemeral = generateX25519KeyPair();
34
-
35
- // DH1: our identity <-> their signed pre-key
36
- const dh1 = x25519SharedSecret(ourIdentityKeyPair.privateKey, theirBundle.signedPreKey);
37
- // DH2: our ephemeral <-> their identity
38
- const dh2 = x25519SharedSecret(ephemeral.privateKey, theirBundle.identityKey);
39
- // DH3: our ephemeral <-> their signed pre-key
40
- const dh3 = x25519SharedSecret(ephemeral.privateKey, theirBundle.signedPreKey);
41
-
42
- let dhConcat: Uint8Array;
43
- if (theirBundle.oneTimePreKey) {
44
- // DH4: our ephemeral <-> their one-time pre-key
45
- const dh4 = x25519SharedSecret(ephemeral.privateKey, theirBundle.oneTimePreKey);
46
- dhConcat = concat(PADDING, dh1, dh2, dh3, dh4);
47
- } else {
48
- dhConcat = concat(PADDING, dh1, dh2, dh3);
49
- }
50
-
51
- const sharedSecret = hkdf(sha256, dhConcat, new Uint8Array(32), X3DH_INFO, 32);
52
-
53
- const sendKeyPair = generateX25519KeyPair();
54
- const session: SessionState = {
55
- dhSendKeyPair: sendKeyPair,
56
- dhRecvPublicKey: theirBundle.signedPreKey,
57
- rootKey: sharedSecret,
58
- sendChainKey: null,
59
- recvChainKey: null,
60
- sendMessageNumber: 0,
61
- recvMessageNumber: 0,
62
- previousChainLength: 0,
63
- skippedKeys: new Map(),
64
- };
65
-
66
- return {
67
- session,
68
- ephemeralPublicKey: ephemeral.publicKey,
69
- signedPreKeyId: theirBundle.signedPreKeyId,
70
- oneTimePreKeyId: theirBundle.oneTimePreKeyId,
71
- };
72
- }
73
-
74
- export function x3dhRespond(
75
- ourIdentityKeyPair: X25519KeyPair,
76
- ourSignedPreKeyPair: X25519KeyPair,
77
- theirIdentityKey: Uint8Array,
78
- theirEphemeralKey: Uint8Array,
79
- ourOneTimePreKeyPair?: X25519KeyPair,
80
- ): SessionState {
81
- // DH1: their identity <-> our signed pre-key
82
- const dh1 = x25519SharedSecret(ourSignedPreKeyPair.privateKey, theirIdentityKey);
83
- // DH2: their ephemeral <-> our identity
84
- const dh2 = x25519SharedSecret(ourIdentityKeyPair.privateKey, theirEphemeralKey);
85
- // DH3: their ephemeral <-> our signed pre-key
86
- const dh3 = x25519SharedSecret(ourSignedPreKeyPair.privateKey, theirEphemeralKey);
87
-
88
- let dhConcat: Uint8Array;
89
- if (ourOneTimePreKeyPair) {
90
- const dh4 = x25519SharedSecret(ourOneTimePreKeyPair.privateKey, theirEphemeralKey);
91
- dhConcat = concat(PADDING, dh1, dh2, dh3, dh4);
92
- } else {
93
- dhConcat = concat(PADDING, dh1, dh2, dh3);
94
- }
95
-
96
- const sharedSecret = hkdf(sha256, dhConcat, new Uint8Array(32), X3DH_INFO, 32);
97
-
98
- return {
99
- dhSendKeyPair: ourSignedPreKeyPair,
100
- dhRecvPublicKey: null,
101
- rootKey: sharedSecret,
102
- sendChainKey: null,
103
- recvChainKey: null,
104
- sendMessageNumber: 0,
105
- recvMessageNumber: 0,
106
- previousChainLength: 0,
107
- skippedKeys: new Map(),
108
- };
109
- }
110
-
111
- export function buildAssociatedData(
112
- senderIdentityKey: Uint8Array,
113
- recipientIdentityKey: Uint8Array,
114
- ): Uint8Array {
115
- return concat(senderIdentityKey, recipientIdentityKey);
116
- }
117
-
118
- function concat(...arrays: Array<Uint8Array>): Uint8Array {
119
- let totalLength = 0;
120
- for (const array of arrays) {
121
- totalLength += array.length;
122
- }
123
- const result = new Uint8Array(totalLength);
124
- let offset = 0;
125
- for (const array of arrays) {
126
- result.set(array, offset);
127
- offset += array.length;
128
- }
129
- return result;
130
- }
package/src/signer.ts DELETED
@@ -1,21 +0,0 @@
1
- import type { SigningKey } from "./auth.js";
2
- import type { X25519KeyPair } from "./signal/crypto.js";
3
-
4
- /**
5
- * Abstract base for all signing strategies. Subclass this to plug in
6
- * remote wallets (e.g. OpenHuman), HSMs, or any API-based signer.
7
- */
8
- export abstract class Signer implements SigningKey {
9
- abstract readonly agentId: string;
10
- abstract readonly publicKeyBase64: string;
11
-
12
- abstract sign(data: Uint8Array): Promise<Uint8Array> | Uint8Array;
13
-
14
- // Derive X25519 key pair for Signal Protocol key agreement.
15
- // Ed25519 identity keys are converted to X25519 for ECDH.
16
- abstract getX25519KeyPair(): Promise<X25519KeyPair>;
17
-
18
- toSigningKey(): SigningKey {
19
- return this;
20
- }
21
- }
@@ -1,81 +0,0 @@
1
- export type BroadcastVisibility = "public" | "unlisted";
2
- export type BroadcastEncryption = "none" | "envelope";
3
- export type BroadcastPaymentType = "free" | "subscription" | "per-message";
4
-
5
- export interface BroadcastSubscriptionPrice {
6
- amount: string;
7
- asset: string;
8
- network: string;
9
- interval: string;
10
- }
11
-
12
- export interface BroadcastPaymentPolicy {
13
- type: BroadcastPaymentType;
14
- subscription?: BroadcastSubscriptionPrice;
15
- }
16
-
17
- export interface BroadcastChannel {
18
- broadcastId: string;
19
- name: string;
20
- description?: string;
21
- owner: string;
22
- ownerCryptoId?: string;
23
- publishers: Array<string>;
24
- subscriberCount: number;
25
- tags?: Array<string>;
26
- visibility: BroadcastVisibility;
27
- encryption: BroadcastEncryption;
28
- paymentPolicy?: BroadcastPaymentPolicy;
29
- keyVersion?: number;
30
- keyRotatedAt?: string;
31
- createdAt: string;
32
- updatedAt: string;
33
- lastActivityAt?: string;
34
- closedAt?: string;
35
- }
36
-
37
- export interface BroadcastQueryParams {
38
- q?: string;
39
- tag?: string;
40
- tags?: Array<string>;
41
- owner?: string;
42
- visibility?: BroadcastVisibility;
43
- paymentType?: BroadcastPaymentType;
44
- sort?: string;
45
- limit?: number;
46
- }
47
-
48
- export interface BroadcastSubscriber {
49
- broadcastId: string;
50
- agentId: string;
51
- subscribedAt: string;
52
- status: string;
53
- paymentScheme?: string;
54
- paymentNetwork?: string;
55
- paymentAsset?: string;
56
- paymentAmount?: string;
57
- paymentInterval?: string;
58
- paymentExpiresAt?: string;
59
- nextPaymentAt?: string;
60
- }
61
-
62
- export interface BroadcastMessage {
63
- messageId: string;
64
- broadcastId: string;
65
- publisher: string;
66
- timestamp: string;
67
- contentType: string;
68
- body: string;
69
- sequence: number;
70
- deletedAt?: string;
71
- }
72
-
73
- export interface BroadcastCreateRequest {
74
- name: string;
75
- description?: string;
76
- tags?: Array<string>;
77
- visibility?: BroadcastVisibility;
78
- encryption?: BroadcastEncryption;
79
- paymentPolicy?: BroadcastPaymentPolicy;
80
- signature?: string;
81
- }