@rougechain/sdk 0.8.4 → 0.9.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 +37 -31
- package/dist/index.cjs +115 -138
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +115 -139
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -337,7 +337,7 @@ const batch = await rc.getRollupBatch(1);
|
|
|
337
337
|
|
|
338
338
|
## Mail (`rc.mail`)
|
|
339
339
|
|
|
340
|
-
On-chain encrypted email with `@rouge.quant` / `@qwalla.mail` addresses.
|
|
340
|
+
On-chain encrypted email with `@rouge.quant` / `@qwalla.mail` addresses. All write operations require a `wallet` parameter for ML-DSA-65 request signing — requests are authenticated via `/api/v2/` endpoints with anti-replay nonce protection.
|
|
341
341
|
|
|
342
342
|
### Name Registry
|
|
343
343
|
|
|
@@ -345,17 +345,17 @@ Register a mail name so other users can send you encrypted email. Third-party ap
|
|
|
345
345
|
|
|
346
346
|
```typescript
|
|
347
347
|
// Step 1: Register wallet on the node (required for encryption keys)
|
|
348
|
-
await rc.messenger.registerWallet({
|
|
348
|
+
await rc.messenger.registerWallet(wallet, {
|
|
349
349
|
id: wallet.publicKey,
|
|
350
350
|
displayName: "Alice",
|
|
351
351
|
signingPublicKey: wallet.publicKey,
|
|
352
352
|
encryptionPublicKey: encPubKey,
|
|
353
353
|
});
|
|
354
354
|
|
|
355
|
-
// Step 2: Register a mail name
|
|
356
|
-
await rc.mail.registerName("alice", wallet.publicKey);
|
|
355
|
+
// Step 2: Register a mail name (signed request)
|
|
356
|
+
await rc.mail.registerName(wallet, "alice", wallet.publicKey);
|
|
357
357
|
|
|
358
|
-
// Resolve a name → wallet info (includes encryption key)
|
|
358
|
+
// Resolve a name → wallet info (includes encryption key, public data only)
|
|
359
359
|
const resolved = await rc.mail.resolveName("alice");
|
|
360
360
|
// { entry: { name, wallet_id }, wallet: { id, signing_public_key, encryption_public_key } }
|
|
361
361
|
|
|
@@ -363,15 +363,15 @@ const resolved = await rc.mail.resolveName("alice");
|
|
|
363
363
|
const name = await rc.mail.reverseLookup(wallet.publicKey);
|
|
364
364
|
// "alice"
|
|
365
365
|
|
|
366
|
-
// Release a name
|
|
367
|
-
await rc.mail.releaseName("alice", wallet.publicKey);
|
|
366
|
+
// Release a name (signed request)
|
|
367
|
+
await rc.mail.releaseName(wallet, "alice", wallet.publicKey);
|
|
368
368
|
```
|
|
369
369
|
|
|
370
370
|
### Sending & Reading Mail
|
|
371
371
|
|
|
372
372
|
```typescript
|
|
373
|
-
// Send an encrypted email
|
|
374
|
-
await rc.mail.send({
|
|
373
|
+
// Send an encrypted email (signed, multi-recipient CEK encryption)
|
|
374
|
+
await rc.mail.send(wallet, {
|
|
375
375
|
from: wallet.publicKey,
|
|
376
376
|
to: recipientPubKey,
|
|
377
377
|
subject: "Hello",
|
|
@@ -380,52 +380,55 @@ await rc.mail.send({
|
|
|
380
380
|
encrypted_body: encryptedBody,
|
|
381
381
|
});
|
|
382
382
|
|
|
383
|
-
// Read inbox
|
|
384
|
-
const inbox = await rc.mail.getInbox(wallet
|
|
383
|
+
// Read inbox (signed request)
|
|
384
|
+
const inbox = await rc.mail.getInbox(wallet);
|
|
385
385
|
|
|
386
|
-
// Move to trash
|
|
387
|
-
await rc.mail.move(messageId, "trash");
|
|
386
|
+
// Move to trash (signed request)
|
|
387
|
+
await rc.mail.move(wallet, messageId, "trash");
|
|
388
388
|
|
|
389
|
-
// Mark as read
|
|
390
|
-
await rc.mail.markRead(messageId);
|
|
389
|
+
// Mark as read (signed request)
|
|
390
|
+
await rc.mail.markRead(wallet, messageId);
|
|
391
|
+
|
|
392
|
+
// Delete (signed request)
|
|
393
|
+
await rc.mail.delete(wallet, messageId);
|
|
391
394
|
```
|
|
392
395
|
|
|
393
396
|
## Messenger (`rc.messenger`)
|
|
394
397
|
|
|
395
|
-
End-to-end encrypted messaging with media and self-destruct support.
|
|
398
|
+
End-to-end encrypted messaging with media and self-destruct support. All operations use ML-DSA-65 signed requests via `/api/v2/` endpoints with nonce-based anti-replay protection.
|
|
396
399
|
|
|
397
400
|
```typescript
|
|
398
|
-
// Register wallet for messaging
|
|
399
|
-
await rc.messenger.registerWallet({
|
|
401
|
+
// Register wallet for messaging (signed request)
|
|
402
|
+
await rc.messenger.registerWallet(wallet, {
|
|
400
403
|
id: wallet.publicKey,
|
|
401
404
|
displayName: "Alice",
|
|
402
405
|
signingPublicKey: wallet.publicKey,
|
|
403
406
|
encryptionPublicKey: encPubKey,
|
|
404
407
|
});
|
|
405
408
|
|
|
406
|
-
// Create a conversation
|
|
407
|
-
const result = await rc.messenger.createConversation([
|
|
409
|
+
// Create a conversation (signed request)
|
|
410
|
+
const result = await rc.messenger.createConversation(wallet, [
|
|
408
411
|
wallet.publicKey,
|
|
409
412
|
recipientPubKey,
|
|
410
413
|
]);
|
|
411
414
|
|
|
412
|
-
// Fetch conversations (
|
|
413
|
-
const convos = await rc.messenger.getConversations(wallet
|
|
414
|
-
signingPublicKey: wallet.publicKey,
|
|
415
|
-
encryptionPublicKey: encPubKey,
|
|
416
|
-
});
|
|
415
|
+
// Fetch conversations (signed request)
|
|
416
|
+
const convos = await rc.messenger.getConversations(wallet);
|
|
417
417
|
|
|
418
|
-
// Send an encrypted message (with optional self-destruct)
|
|
419
|
-
await rc.messenger.sendMessage(
|
|
418
|
+
// Send an encrypted message (signed, with optional self-destruct)
|
|
419
|
+
await rc.messenger.sendMessage(wallet, conversationId, encryptedContent, {
|
|
420
420
|
selfDestruct: true,
|
|
421
421
|
destructAfterSeconds: 30,
|
|
422
422
|
});
|
|
423
423
|
|
|
424
|
-
// Read messages
|
|
425
|
-
const messages = await rc.messenger.getMessages(conversationId);
|
|
424
|
+
// Read messages (signed request)
|
|
425
|
+
const messages = await rc.messenger.getMessages(wallet, conversationId);
|
|
426
|
+
|
|
427
|
+
// Delete a message (signed request)
|
|
428
|
+
await rc.messenger.deleteMessage(wallet, messageId);
|
|
426
429
|
|
|
427
|
-
// Delete a
|
|
428
|
-
await rc.messenger.
|
|
430
|
+
// Delete a conversation (signed request)
|
|
431
|
+
await rc.messenger.deleteConversation(wallet, conversationId);
|
|
429
432
|
```
|
|
430
433
|
|
|
431
434
|
## Shielded Transactions (`rc.shielded`)
|
|
@@ -553,6 +556,9 @@ import type {
|
|
|
553
556
|
- **Post-quantum cryptography** — All signatures use ML-DSA-65 (CRYSTALS-Dilithium), resistant to quantum computer attacks
|
|
554
557
|
- **Client-side signing** — Private keys never leave your application
|
|
555
558
|
- **No key storage** — The SDK does not store or transmit keys
|
|
559
|
+
- **Signed API requests** — All mail, messenger, and name registry operations use ML-DSA-65 signed requests with timestamp validation and nonce-based anti-replay protection
|
|
560
|
+
- **Multi-recipient CEK encryption** — Mail content is encrypted once with a random AES-256 key, KEM-wrapped individually per recipient via ML-KEM-768
|
|
561
|
+
- **TOFU key verification** — Public key fingerprints (SHA-256) are tracked for key change detection
|
|
556
562
|
|
|
557
563
|
## Links
|
|
558
564
|
|
package/dist/index.cjs
CHANGED
|
@@ -286,6 +286,9 @@ function createSignedPushUnregister(wallet) {
|
|
|
286
286
|
type: "push_unregister"
|
|
287
287
|
});
|
|
288
288
|
}
|
|
289
|
+
function signRequest(wallet, payload) {
|
|
290
|
+
return buildAndSign(wallet, payload);
|
|
291
|
+
}
|
|
289
292
|
var COMMITMENT_DOMAIN = new TextEncoder().encode("ROUGECHAIN_COMMITMENT_V1");
|
|
290
293
|
var NULLIFIER_DOMAIN = new TextEncoder().encode("ROUGECHAIN_NULLIFIER_V1");
|
|
291
294
|
function generateRandomness() {
|
|
@@ -959,17 +962,10 @@ var MailClient = class {
|
|
|
959
962
|
constructor(rc) {
|
|
960
963
|
this.rc = rc;
|
|
961
964
|
}
|
|
962
|
-
// --- Name Registry ---
|
|
963
|
-
async registerName(name, walletId) {
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
name,
|
|
967
|
-
walletId
|
|
968
|
-
});
|
|
969
|
-
return { success: data.success === true, error: data.error, data };
|
|
970
|
-
} catch (e) {
|
|
971
|
-
return { success: false, error: e instanceof Error ? e.message : String(e) };
|
|
972
|
-
}
|
|
965
|
+
// --- Name Registry (signed) ---
|
|
966
|
+
async registerName(wallet, name, walletId) {
|
|
967
|
+
const signed = signRequest(wallet, { name, walletId });
|
|
968
|
+
return this.rc.submitTx("/v2/names/register", signed);
|
|
973
969
|
}
|
|
974
970
|
async resolveName(name) {
|
|
975
971
|
try {
|
|
@@ -992,85 +988,71 @@ var MailClient = class {
|
|
|
992
988
|
return null;
|
|
993
989
|
}
|
|
994
990
|
}
|
|
995
|
-
async releaseName(
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
}
|
|
991
|
+
async releaseName(wallet, name) {
|
|
992
|
+
const signed = signRequest(wallet, { name });
|
|
993
|
+
return this.rc.submitTx("/v2/names/release", signed);
|
|
994
|
+
}
|
|
995
|
+
// --- Mail (signed) ---
|
|
996
|
+
async send(wallet, params) {
|
|
997
|
+
const signed = signRequest(wallet, {
|
|
998
|
+
fromWalletId: params.from,
|
|
999
|
+
toWalletIds: [params.to],
|
|
1000
|
+
subjectEncrypted: params.encrypted_subject,
|
|
1001
|
+
bodyEncrypted: params.encrypted_body,
|
|
1002
|
+
contentSignature: params.body,
|
|
1003
|
+
replyToId: params.reply_to_id,
|
|
1004
|
+
hasAttachment: false
|
|
1005
|
+
});
|
|
1006
|
+
return this.rc.submitTx("/v2/mail/send", signed);
|
|
1010
1007
|
}
|
|
1011
|
-
|
|
1012
|
-
|
|
1008
|
+
async getInbox(wallet) {
|
|
1009
|
+
const signed = signRequest(wallet, { folder: "inbox" });
|
|
1013
1010
|
try {
|
|
1014
|
-
const data = await this.rc.post("/mail/
|
|
1015
|
-
return
|
|
1016
|
-
} catch
|
|
1017
|
-
return
|
|
1011
|
+
const data = await this.rc.post("/v2/mail/folder", signed);
|
|
1012
|
+
return data.messages ?? [];
|
|
1013
|
+
} catch {
|
|
1014
|
+
return [];
|
|
1018
1015
|
}
|
|
1019
1016
|
}
|
|
1020
|
-
async
|
|
1021
|
-
const
|
|
1022
|
-
`/mail/inbox?walletId=${encodeURIComponent(walletId)}`
|
|
1023
|
-
);
|
|
1024
|
-
return data.messages ?? [];
|
|
1025
|
-
}
|
|
1026
|
-
async getSent(walletId) {
|
|
1027
|
-
const data = await this.rc.get(
|
|
1028
|
-
`/mail/sent?walletId=${encodeURIComponent(walletId)}`
|
|
1029
|
-
);
|
|
1030
|
-
return data.messages ?? [];
|
|
1031
|
-
}
|
|
1032
|
-
async getTrash(walletId) {
|
|
1033
|
-
const data = await this.rc.get(
|
|
1034
|
-
`/mail/trash?walletId=${encodeURIComponent(walletId)}`
|
|
1035
|
-
);
|
|
1036
|
-
return data.messages ?? [];
|
|
1037
|
-
}
|
|
1038
|
-
async getMessage(id) {
|
|
1039
|
-
return this.rc.get(`/mail/message/${encodeURIComponent(id)}`);
|
|
1040
|
-
}
|
|
1041
|
-
async move(messageId, folder) {
|
|
1017
|
+
async getSent(wallet) {
|
|
1018
|
+
const signed = signRequest(wallet, { folder: "sent" });
|
|
1042
1019
|
try {
|
|
1043
|
-
const data = await this.rc.post("/mail/
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
return { success: data.success === true, error: data.error };
|
|
1048
|
-
} catch (e) {
|
|
1049
|
-
return { success: false, error: e instanceof Error ? e.message : String(e) };
|
|
1020
|
+
const data = await this.rc.post("/v2/mail/folder", signed);
|
|
1021
|
+
return data.messages ?? [];
|
|
1022
|
+
} catch {
|
|
1023
|
+
return [];
|
|
1050
1024
|
}
|
|
1051
1025
|
}
|
|
1052
|
-
async
|
|
1026
|
+
async getTrash(wallet) {
|
|
1027
|
+
const signed = signRequest(wallet, { folder: "trash" });
|
|
1053
1028
|
try {
|
|
1054
|
-
const data = await this.rc.post("/mail/
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
return
|
|
1058
|
-
} catch (e) {
|
|
1059
|
-
return { success: false, error: e instanceof Error ? e.message : String(e) };
|
|
1029
|
+
const data = await this.rc.post("/v2/mail/folder", signed);
|
|
1030
|
+
return data.messages ?? [];
|
|
1031
|
+
} catch {
|
|
1032
|
+
return [];
|
|
1060
1033
|
}
|
|
1061
1034
|
}
|
|
1062
|
-
async
|
|
1035
|
+
async getMessage(wallet, messageId) {
|
|
1036
|
+
const signed = signRequest(wallet, { messageId });
|
|
1063
1037
|
try {
|
|
1064
|
-
const
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
const data = await res.json();
|
|
1069
|
-
return { success: data.success === true, error: data.error };
|
|
1070
|
-
} catch (e) {
|
|
1071
|
-
return { success: false, error: e instanceof Error ? e.message : String(e) };
|
|
1038
|
+
const data = await this.rc.post("/v2/mail/message", signed);
|
|
1039
|
+
return data.message ?? null;
|
|
1040
|
+
} catch {
|
|
1041
|
+
return null;
|
|
1072
1042
|
}
|
|
1073
1043
|
}
|
|
1044
|
+
async move(wallet, messageId, folder) {
|
|
1045
|
+
const signed = signRequest(wallet, { messageId, folder });
|
|
1046
|
+
return this.rc.submitTx("/v2/mail/move", signed);
|
|
1047
|
+
}
|
|
1048
|
+
async markRead(wallet, messageId) {
|
|
1049
|
+
const signed = signRequest(wallet, { messageId });
|
|
1050
|
+
return this.rc.submitTx("/v2/mail/read", signed);
|
|
1051
|
+
}
|
|
1052
|
+
async delete(wallet, messageId) {
|
|
1053
|
+
const signed = signRequest(wallet, { messageId });
|
|
1054
|
+
return this.rc.submitTx("/v2/mail/delete", signed);
|
|
1055
|
+
}
|
|
1074
1056
|
};
|
|
1075
1057
|
var MessengerClient = class {
|
|
1076
1058
|
constructor(rc) {
|
|
@@ -1080,77 +1062,71 @@ var MessengerClient = class {
|
|
|
1080
1062
|
const data = await this.rc.get("/messenger/wallets");
|
|
1081
1063
|
return data.wallets ?? [];
|
|
1082
1064
|
}
|
|
1083
|
-
async registerWallet(opts) {
|
|
1065
|
+
async registerWallet(wallet, opts) {
|
|
1066
|
+
const signed = signRequest(wallet, {
|
|
1067
|
+
id: opts.id,
|
|
1068
|
+
displayName: opts.displayName,
|
|
1069
|
+
signingPublicKey: opts.signingPublicKey,
|
|
1070
|
+
encryptionPublicKey: opts.encryptionPublicKey,
|
|
1071
|
+
discoverable: opts.discoverable ?? true
|
|
1072
|
+
});
|
|
1073
|
+
return this.rc.submitTx("/v2/messenger/wallets/register", signed);
|
|
1074
|
+
}
|
|
1075
|
+
async getConversations(wallet) {
|
|
1076
|
+
const signed = signRequest(wallet, {});
|
|
1084
1077
|
try {
|
|
1085
|
-
const data = await this.rc.post(
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1078
|
+
const data = await this.rc.post(
|
|
1079
|
+
"/v2/messenger/conversations/list",
|
|
1080
|
+
signed
|
|
1081
|
+
);
|
|
1082
|
+
return data.conversations ?? [];
|
|
1083
|
+
} catch {
|
|
1084
|
+
return [];
|
|
1089
1085
|
}
|
|
1090
1086
|
}
|
|
1091
|
-
async
|
|
1092
|
-
const
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
);
|
|
1098
|
-
return data.conversations ?? [];
|
|
1087
|
+
async createConversation(wallet, participantIds, opts = {}) {
|
|
1088
|
+
const signed = signRequest(wallet, {
|
|
1089
|
+
participantIds,
|
|
1090
|
+
name: opts.name,
|
|
1091
|
+
isGroup: opts.isGroup ?? false
|
|
1092
|
+
});
|
|
1093
|
+
return this.rc.submitTx("/v2/messenger/conversations", signed);
|
|
1099
1094
|
}
|
|
1100
|
-
async
|
|
1095
|
+
async getMessages(wallet, conversationId) {
|
|
1096
|
+
const signed = signRequest(wallet, { conversationId });
|
|
1101
1097
|
try {
|
|
1102
|
-
const data = await this.rc.post(
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1098
|
+
const data = await this.rc.post(
|
|
1099
|
+
"/v2/messenger/messages/list",
|
|
1100
|
+
signed
|
|
1101
|
+
);
|
|
1102
|
+
return data.messages ?? [];
|
|
1103
|
+
} catch {
|
|
1104
|
+
return [];
|
|
1108
1105
|
}
|
|
1109
1106
|
}
|
|
1110
|
-
async
|
|
1111
|
-
const
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1107
|
+
async sendMessage(wallet, conversationId, encryptedContent, opts = {}) {
|
|
1108
|
+
const signed = signRequest(wallet, {
|
|
1109
|
+
conversationId,
|
|
1110
|
+
encryptedContent,
|
|
1111
|
+
contentSignature: opts.contentSignature ?? "",
|
|
1112
|
+
messageType: opts.messageType ?? "text",
|
|
1113
|
+
selfDestruct: opts.selfDestruct ?? false,
|
|
1114
|
+
destructAfterSeconds: opts.destructAfterSeconds,
|
|
1115
|
+
spoiler: opts.spoiler ?? false
|
|
1116
|
+
});
|
|
1117
|
+
return this.rc.submitTx("/v2/messenger/messages", signed);
|
|
1115
1118
|
}
|
|
1116
|
-
async
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
conversationId,
|
|
1120
|
-
senderWalletId,
|
|
1121
|
-
encryptedContent,
|
|
1122
|
-
signature: opts.signature ?? "",
|
|
1123
|
-
messageType: opts.messageType ?? "text",
|
|
1124
|
-
selfDestruct: opts.selfDestruct ?? false,
|
|
1125
|
-
destructAfterSeconds: opts.destructAfterSeconds,
|
|
1126
|
-
spoiler: opts.spoiler ?? false
|
|
1127
|
-
});
|
|
1128
|
-
return { success: data.success === true, error: data.error, data };
|
|
1129
|
-
} catch (e) {
|
|
1130
|
-
return { success: false, error: e instanceof Error ? e.message : String(e) };
|
|
1131
|
-
}
|
|
1119
|
+
async deleteMessage(wallet, messageId, conversationId) {
|
|
1120
|
+
const signed = signRequest(wallet, { messageId, conversationId });
|
|
1121
|
+
return this.rc.submitTx("/v2/messenger/messages/delete", signed);
|
|
1132
1122
|
}
|
|
1133
|
-
async
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
`${this.rc.baseUrl}/messenger/messages/${encodeURIComponent(messageId)}`,
|
|
1137
|
-
{ method: "DELETE", headers: this.rc.headers }
|
|
1138
|
-
);
|
|
1139
|
-
const data = await res.json();
|
|
1140
|
-
return { success: data.success === true, error: data.error };
|
|
1141
|
-
} catch (e) {
|
|
1142
|
-
return { success: false, error: e instanceof Error ? e.message : String(e) };
|
|
1143
|
-
}
|
|
1123
|
+
async deleteConversation(wallet, conversationId) {
|
|
1124
|
+
const signed = signRequest(wallet, { conversationId });
|
|
1125
|
+
return this.rc.submitTx("/v2/messenger/conversations/delete", signed);
|
|
1144
1126
|
}
|
|
1145
|
-
async markRead(messageId) {
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
messageId
|
|
1149
|
-
});
|
|
1150
|
-
return { success: data.success === true, error: data.error };
|
|
1151
|
-
} catch (e) {
|
|
1152
|
-
return { success: false, error: e instanceof Error ? e.message : String(e) };
|
|
1153
|
-
}
|
|
1127
|
+
async markRead(wallet, messageId, conversationId) {
|
|
1128
|
+
const signed = signRequest(wallet, { messageId, conversationId });
|
|
1129
|
+
return this.rc.submitTx("/v2/messenger/messages/read", signed);
|
|
1154
1130
|
}
|
|
1155
1131
|
};
|
|
1156
1132
|
var ShieldedClient = class {
|
|
@@ -1486,6 +1462,7 @@ exports.keypairFromMnemonic = keypairFromMnemonic;
|
|
|
1486
1462
|
exports.mnemonicToMLDSASeed = mnemonicToMLDSASeed;
|
|
1487
1463
|
exports.pubkeyToAddress = pubkeyToAddress;
|
|
1488
1464
|
exports.serializePayload = serializePayload;
|
|
1465
|
+
exports.signRequest = signRequest;
|
|
1489
1466
|
exports.signTransaction = signTransaction;
|
|
1490
1467
|
exports.validateMnemonic = validateMnemonic;
|
|
1491
1468
|
exports.verifyTransaction = verifyTransaction;
|