@decentnetwork/peer 0.1.46 → 0.1.47

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.
@@ -1 +1,12 @@
1
- export declare function signDetached(_payload: Uint8Array): Promise<never>;
1
+ export declare const SIGNATURE_LENGTH = 64;
2
+ /**
3
+ * Produce a detached XEdDSA signature over `message` using a 32-byte X25519
4
+ * secret key (a Carrier identity secret key). Returns a 64-byte signature.
5
+ */
6
+ export declare function signDetached(secretKey: Uint8Array, message: Uint8Array): Uint8Array;
7
+ /**
8
+ * Verify a detached XEdDSA signature against a 32-byte X25519 public key
9
+ * (decode the userid to get it). Returns false on any malformed input rather
10
+ * than throwing, so callers can treat it as a plain predicate.
11
+ */
12
+ export declare function verifyDetached(publicKey: Uint8Array, message: Uint8Array, signature: Uint8Array): boolean;
@@ -1,3 +1,44 @@
1
- export async function signDetached(_payload) {
2
- throw new Error("Legacy-compatible signing is not implemented yet");
1
+ // Detached signatures over a Carrier identity's key.
2
+ //
3
+ // A Carrier/toxcore identity key is an X25519 (Curve25519) key pair — the
4
+ // same key used for crypto_box, and the public half IS the userid (base58).
5
+ // X25519 keys can't be fed to Ed25519 (nacl.sign) directly, so we use XEdDSA
6
+ // (Signal's scheme): sign with the Montgomery/X25519 private key, and verify
7
+ // against the X25519 public key. A relying party (e.g. a website doing
8
+ // "Sign in with Decent") decodes the userid → 32-byte X25519 public key and
9
+ // verifies with the same primitive — no separate signing key, no new key
10
+ // derivation path, the signature is bound to the identity itself.
11
+ //
12
+ // curve25519-js implements XEdDSA sign/verify; randomization (64 bytes) makes
13
+ // signatures non-deterministic per the spec. Verification is independent of
14
+ // the random used.
15
+ import { sign as xeddsaSign, verify as xeddsaVerify } from "curve25519-js";
16
+ import nacl from "tweetnacl";
17
+ export const SIGNATURE_LENGTH = 64;
18
+ /**
19
+ * Produce a detached XEdDSA signature over `message` using a 32-byte X25519
20
+ * secret key (a Carrier identity secret key). Returns a 64-byte signature.
21
+ */
22
+ export function signDetached(secretKey, message) {
23
+ if (secretKey.length !== nacl.box.secretKeyLength) {
24
+ throw new Error(`secretKey must be ${nacl.box.secretKeyLength} bytes`);
25
+ }
26
+ const random = nacl.randomBytes(64);
27
+ return xeddsaSign(secretKey, message, random);
28
+ }
29
+ /**
30
+ * Verify a detached XEdDSA signature against a 32-byte X25519 public key
31
+ * (decode the userid to get it). Returns false on any malformed input rather
32
+ * than throwing, so callers can treat it as a plain predicate.
33
+ */
34
+ export function verifyDetached(publicKey, message, signature) {
35
+ if (publicKey.length !== nacl.box.publicKeyLength || signature.length !== SIGNATURE_LENGTH) {
36
+ return false;
37
+ }
38
+ try {
39
+ return xeddsaVerify(publicKey, message, signature);
40
+ }
41
+ catch {
42
+ return false;
43
+ }
3
44
  }
package/dist/index.d.ts CHANGED
@@ -3,6 +3,8 @@ export { CARRIER_ADDRESS_SIZE, CARRIER_PUBLIC_KEY_SIZE, carrierAddressFromPublic
3
3
  export { PACKET_TYPE_FRIEND_REQUEST, PACKET_TYPE_MESSAGE, decodeCarrierPacket, encodeFriendMessagePacket, encodeFriendRequestPacket } from "./compat/packet.js";
4
4
  export { CRYPTO_PACKET_DHTPK, CRYPTO_PACKET_FRIEND_REQ, CRYPTO_PACKET_NAT_PING, NET_PACKET_CRYPTO, createToxDhtCryptoRequest, openToxDhtCryptoRequest } from "./compat/tox-dht-crypto.js";
5
5
  export { NET_PACKET_ONION_ANNOUNCE_REQUEST, NET_PACKET_ONION_ANNOUNCE_RESPONSE, NET_PACKET_ONION_DATA_REQUEST, NET_PACKET_ONION_DATA_RESPONSE, ONION_FRIEND_REQUEST_ID } from "./compat/tox-onion.js";
6
+ export { signDetached, verifyDetached, SIGNATURE_LENGTH } from "./crypto/sign.js";
7
+ export { base58ToBytes, bytesToBase58 } from "./utils/base58.js";
6
8
  export { LegacyProtocolNotImplementedError } from "./runtime/errors.js";
7
9
  export type { CarrierPacket, FriendMessagePacket, FriendRequestPacket } from "./compat/packet.js";
8
10
  export type { ToxDhtCryptoRequest } from "./compat/tox-dht-crypto.js";
package/dist/index.js CHANGED
@@ -3,4 +3,6 @@ export { CARRIER_ADDRESS_SIZE, CARRIER_PUBLIC_KEY_SIZE, carrierAddressFromPublic
3
3
  export { PACKET_TYPE_FRIEND_REQUEST, PACKET_TYPE_MESSAGE, decodeCarrierPacket, encodeFriendMessagePacket, encodeFriendRequestPacket } from "./compat/packet.js";
4
4
  export { CRYPTO_PACKET_DHTPK, CRYPTO_PACKET_FRIEND_REQ, CRYPTO_PACKET_NAT_PING, NET_PACKET_CRYPTO, createToxDhtCryptoRequest, openToxDhtCryptoRequest } from "./compat/tox-dht-crypto.js";
5
5
  export { NET_PACKET_ONION_ANNOUNCE_REQUEST, NET_PACKET_ONION_ANNOUNCE_RESPONSE, NET_PACKET_ONION_DATA_REQUEST, NET_PACKET_ONION_DATA_RESPONSE, ONION_FRIEND_REQUEST_ID } from "./compat/tox-onion.js";
6
+ export { signDetached, verifyDetached, SIGNATURE_LENGTH } from "./crypto/sign.js";
7
+ export { base58ToBytes, bytesToBase58 } from "./utils/base58.js";
6
8
  export { LegacyProtocolNotImplementedError } from "./runtime/errors.js";
package/dist/peer.d.ts CHANGED
@@ -9,6 +9,14 @@ export declare class Peer {
9
9
  stop(): Promise<void>;
10
10
  pubkey(): string;
11
11
  userid(): string;
12
+ /**
13
+ * Sign `message` with this identity's private key (XEdDSA over the X25519
14
+ * key). The signature verifies against the userid — `verifyDetached(
15
+ * base58Decode(userid), message, sig)` — so a relying party that knows only
16
+ * the userid can prove the signer holds the matching key. Used by "Sign in
17
+ * with Decent". Returns a detached 64-byte signature.
18
+ */
19
+ sign(message: Uint8Array): Uint8Array;
12
20
  address(): string;
13
21
  joinNetwork(): Promise<BootstrapResult>;
14
22
  lookup(pubkey: string): Promise<LookupResult>;
package/dist/peer.js CHANGED
@@ -15,6 +15,7 @@ import { LegacyExpressClient } from "./compat/express.js";
15
15
  import { TcpRelayPool } from "./compat/tcp-relay-pool.js";
16
16
  import { LegacyDhtClient } from "./compat/dht.js";
17
17
  import { loadOrCreateKeyPair } from "./crypto/keypair.js";
18
+ import { signDetached } from "./crypto/sign.js";
18
19
  import { base58ToBytes } from "./utils/base58.js";
19
20
  import { UdpTransport } from "./transport/udp.js";
20
21
  import { bytesToHex, concatBytes, randomBytes } from "./utils/bytes.js";
@@ -481,6 +482,19 @@ export class Peer {
481
482
  }
482
483
  return carrierIdFromPublicKey(this.#keyPair.publicKey);
483
484
  }
485
+ /**
486
+ * Sign `message` with this identity's private key (XEdDSA over the X25519
487
+ * key). The signature verifies against the userid — `verifyDetached(
488
+ * base58Decode(userid), message, sig)` — so a relying party that knows only
489
+ * the userid can prove the signer holds the matching key. Used by "Sign in
490
+ * with Decent". Returns a detached 64-byte signature.
491
+ */
492
+ sign(message) {
493
+ if (!this.#keyPair) {
494
+ throw new Error("Peer is not started");
495
+ }
496
+ return signDetached(this.#keyPair.secretKey, message);
497
+ }
484
498
  address() {
485
499
  if (!this.#keyPair) {
486
500
  throw new Error("Peer is not started");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decentnetwork/peer",
3
- "version": "0.1.46",
3
+ "version": "0.1.47",
4
4
  "description": "Pure TypeScript port of Elastos Carrier (toxcore-derived) P2P messaging. DHT, onion routing, TCP relay, FlatBuffers app payloads, Express offline relay. Wire-compatible with iOS Beagle and the Carrier C SDK.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -72,6 +72,7 @@
72
72
  },
73
73
  "dependencies": {
74
74
  "flatbuffers": "^25.9.23",
75
- "tweetnacl": "^1.0.3"
75
+ "tweetnacl": "^1.0.3",
76
+ "curve25519-js": "^0.0.4"
76
77
  }
77
78
  }