@brashkie/signalis-core 0.1.0 → 0.3.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/dist/index.d.mts CHANGED
@@ -46,6 +46,12 @@ type PrivateKey = Buffer & {
46
46
  type SharedSecret = Buffer & {
47
47
  readonly __brand?: 'SharedSecret';
48
48
  };
49
+ /**
50
+ * A digital signature (64 bytes) — Ed25519 or XEd25519.
51
+ */
52
+ type Signature = Buffer & {
53
+ readonly __brand?: 'Signature';
54
+ };
49
55
  /**
50
56
  * HKDF pseudorandom key (32 bytes), output of the Extract step.
51
57
  */
@@ -107,6 +113,10 @@ declare function asPrivateKey(buf: Buffer): PrivateKey;
107
113
  * Brand a Buffer as a {@link SharedSecret}.
108
114
  */
109
115
  declare function asSharedSecret(buf: Buffer): SharedSecret;
116
+ /**
117
+ * Brand a Buffer as a {@link Signature} (NEW in v0.2.0).
118
+ */
119
+ declare function asSignature(buf: Buffer): Signature;
110
120
 
111
121
  /**
112
122
  * Core cryptographic wrappers for signalis-core.
@@ -320,6 +330,28 @@ declare const AES_GCM: Readonly<{
320
330
  NONCE_SIZE: 12;
321
331
  /** Tag size in bytes (16). */
322
332
  TAG_SIZE: 16;
333
+ /**
334
+ * Encrypt with AES-256-GCM and Additional Authenticated Data (NEW in v0.2.0).
335
+ *
336
+ * AAD is authenticated but NOT encrypted. Useful for binding metadata
337
+ * (like message headers) to the ciphertext.
338
+ *
339
+ * @param key - 32-byte symmetric key
340
+ * @param nonce - 12-byte unique nonce
341
+ * @param plaintext - Data to encrypt
342
+ * @param aad - Additional authenticated data (any length, can be empty)
343
+ * @returns Ciphertext + auth tag
344
+ * @throws {ValidationError} On invalid sizes.
345
+ */
346
+ encryptWithAad(key: Buffer, nonce: Buffer, plaintext: Buffer, aad: Buffer): Buffer;
347
+ /**
348
+ * Decrypt with AES-256-GCM and AAD (NEW in v0.2.0).
349
+ *
350
+ * The same AAD used during encryption must be provided. Mismatch = failure.
351
+ *
352
+ * @throws {AuthenticationError} If tag verification fails (incl. AAD mismatch).
353
+ */
354
+ decryptWithAad(key: Buffer, nonce: Buffer, ciphertext: Buffer, aad: Buffer): Buffer;
323
355
  }>;
324
356
  /**
325
357
  * AES-256-CBC block cipher (NOT authenticated by itself).
@@ -415,10 +447,197 @@ declare const SHA256: Readonly<{
415
447
  /** Output size in bytes (32). */
416
448
  OUTPUT_SIZE: 32;
417
449
  }>;
450
+ /**
451
+ * Ed25519 digital signatures (RFC 8032).
452
+ *
453
+ * Standard Ed25519 with deterministic signatures. Use when you want clean
454
+ * separation between signing and ECDH keys.
455
+ *
456
+ * @example
457
+ * ```ts
458
+ * import { Ed25519 } from '@brashkie/signalis-core';
459
+ *
460
+ * const keys = Ed25519.generateKeyPair();
461
+ * const sig = Ed25519.sign(keys.privateKey, Buffer.from('Hello'));
462
+ * Ed25519.verify(keys.publicKey, Buffer.from('Hello'), sig);
463
+ * ```
464
+ */
465
+ declare const Ed25519: Readonly<{
466
+ /**
467
+ * Generate a new random Ed25519 keypair.
468
+ */
469
+ generateKeyPair(): KeyPair;
470
+ /**
471
+ * Derive a deterministic Ed25519 keypair from a 32-byte seed.
472
+ */
473
+ keyPairFromSeed(seed: Buffer): KeyPair;
474
+ /**
475
+ * Derive the public key from a private key.
476
+ */
477
+ publicFromPrivate(privateKey: Buffer): Buffer;
478
+ /**
479
+ * Sign a message. Ed25519 signatures are deterministic (RFC 8032).
480
+ */
481
+ sign(privateKey: Buffer, message: Buffer): Signature;
482
+ /**
483
+ * Verify a signature. Throws on failure.
484
+ *
485
+ * @throws {SignatureError} If signature is invalid.
486
+ */
487
+ verify(publicKey: Buffer, message: Buffer, signature: Buffer): void;
488
+ /**
489
+ * Verify a signature. Returns boolean (does not throw).
490
+ */
491
+ verifyBool(publicKey: Buffer, message: Buffer, signature: Buffer): boolean;
492
+ /** Private key size in bytes (32). */
493
+ PRIVATE_KEY_SIZE: 32;
494
+ /** Public key size in bytes (32). */
495
+ PUBLIC_KEY_SIZE: 32;
496
+ /** Signature size in bytes (64). */
497
+ SIGNATURE_SIZE: 64;
498
+ /** Seed size for deterministic keypair derivation (32). */
499
+ SEED_SIZE: 32;
500
+ }>;
501
+ /**
502
+ * XEd25519 — sign messages using the SAME Curve25519 keypair used for ECDH.
503
+ *
504
+ * This is what Signal Protocol uses to maintain a single identity key.
505
+ * Signatures are non-deterministic (each call gives a different valid sig).
506
+ *
507
+ * @example
508
+ * ```ts
509
+ * import { Curve25519, XEd25519 } from '@brashkie/signalis-core';
510
+ *
511
+ * const identity = Curve25519.generateKeyPair();
512
+ *
513
+ * // Use for ECDH:
514
+ * const shared = Curve25519.diffieHellman(identity.privateKey, peerPublic);
515
+ *
516
+ * // SAME key used to sign:
517
+ * const sig = XEd25519.sign(identity.privateKey, message);
518
+ * XEd25519.verify(identity.publicKey, message, sig);
519
+ * ```
520
+ */
521
+ declare const XEd25519: Readonly<{
522
+ /**
523
+ * Sign a message using a Curve25519 private key. Uses OS RNG.
524
+ * Signatures are NOT deterministic (different each call).
525
+ */
526
+ sign(privateKey: Buffer, message: Buffer): Signature;
527
+ /**
528
+ * Sign with explicit 64-byte random nonce (for testing/reproducibility).
529
+ */
530
+ signWithRandom(privateKey: Buffer, message: Buffer, random: Buffer): Signature;
531
+ /**
532
+ * Verify a XEd25519 signature. Throws on failure.
533
+ *
534
+ * @throws {SignatureError} If signature is invalid.
535
+ */
536
+ verify(publicKey: Buffer, message: Buffer, signature: Buffer): void;
537
+ /**
538
+ * Verify a XEd25519 signature. Returns boolean (does not throw).
539
+ */
540
+ verifyBool(publicKey: Buffer, message: Buffer, signature: Buffer): boolean;
541
+ /** Private key size in bytes (32, same as Curve25519). */
542
+ PRIVATE_KEY_SIZE: 32;
543
+ /** Public key size in bytes (32, same as Curve25519). */
544
+ PUBLIC_KEY_SIZE: 32;
545
+ /** Signature size in bytes (64). */
546
+ SIGNATURE_SIZE: 64;
547
+ /** Random nonce size for signing (64). */
548
+ RANDOM_SIZE: 64;
549
+ }>;
418
550
  /**
419
551
  * The version of the underlying Rust crate (from `Cargo.toml`).
420
552
  */
421
553
  declare const nativeVersion: string;
554
+ /** ChaCha20-Poly1305 key size (bytes). */
555
+ declare const CHACHA20_POLY1305_KEY_SIZE = 32;
556
+ /** ChaCha20-Poly1305 nonce size (bytes). */
557
+ declare const CHACHA20_POLY1305_NONCE_SIZE = 12;
558
+ /** Poly1305 authentication tag size (bytes), appended to ciphertext. */
559
+ declare const CHACHA20_POLY1305_TAG_SIZE = 16;
560
+ /**
561
+ * ChaCha20-Poly1305 authenticated encryption with associated data (AEAD).
562
+ *
563
+ * RFC 8439-compliant alternative to AES-GCM. Same security guarantees,
564
+ * but typically 2-3x faster on platforms without AES-NI hardware
565
+ * (Android arm64-v8a without crypto extensions, IoT, older embedded).
566
+ *
567
+ * On servers and modern desktops with AES-NI, AES-GCM is usually faster
568
+ * — pick the cipher based on your deployment target.
569
+ *
570
+ * @example
571
+ * ```ts
572
+ * import { ChaCha20Poly1305, secureRandom } from '@brashkie/signalis-core';
573
+ *
574
+ * const key = secureRandom(32);
575
+ * const nonce = secureRandom(12);
576
+ * const ct = ChaCha20Poly1305.encrypt(key, nonce, Buffer.from('secret'));
577
+ * const pt = ChaCha20Poly1305.decrypt(key, nonce, ct);
578
+ * ```
579
+ */
580
+ declare const ChaCha20Poly1305: Readonly<{
581
+ /**
582
+ * Encrypt + authenticate `plaintext`.
583
+ *
584
+ * @param key 32-byte key
585
+ * @param nonce 12-byte nonce — MUST be unique per (key, plaintext)
586
+ * @param plaintext data to encrypt
587
+ * @returns ciphertext || tag (16 bytes appended)
588
+ */
589
+ encrypt(key: Buffer, nonce: Buffer, plaintext: Buffer): Buffer;
590
+ /**
591
+ * Verify-then-decrypt. Returns plaintext on success, throws on auth failure.
592
+ */
593
+ decrypt(key: Buffer, nonce: Buffer, ciphertext: Buffer): Buffer;
594
+ /**
595
+ * Encrypt + authenticate with Additional Authenticated Data.
596
+ *
597
+ * AAD is NOT encrypted but IS authenticated. Use for plaintext metadata
598
+ * (e.g., message headers) that must not be tampered with.
599
+ */
600
+ encryptWithAad(key: Buffer, nonce: Buffer, plaintext: Buffer, aad: Buffer): Buffer;
601
+ /**
602
+ * Verify (key + nonce + ciphertext + AAD) and decrypt.
603
+ */
604
+ decryptWithAad(key: Buffer, nonce: Buffer, ciphertext: Buffer, aad: Buffer): Buffer;
605
+ /** Key size in bytes (32). */
606
+ KEY_SIZE: 32;
607
+ /** Nonce size in bytes (12). */
608
+ NONCE_SIZE: 12;
609
+ /** Authentication tag size in bytes (16), appended to ciphertext. */
610
+ TAG_SIZE: 16;
611
+ }>;
612
+ /**
613
+ * Compare two buffers in constant time.
614
+ *
615
+ * Returns `true` only if both buffers have identical length AND contents.
616
+ *
617
+ * Use this for any secret comparison (MAC tags, signatures, tokens) where
618
+ * a fast-fail comparison could leak information via timing side-channels.
619
+ *
620
+ * **Wrong:**
621
+ * ```ts
622
+ * if (expectedMac.equals(receivedMac)) { ... } // ← timing-vulnerable
623
+ * ```
624
+ *
625
+ * **Right:**
626
+ * ```ts
627
+ * if (constantTimeEq(expectedMac, receivedMac)) { ... }
628
+ * ```
629
+ */
630
+ declare function constantTimeEq(a: Buffer, b: Buffer): boolean;
631
+ /**
632
+ * Generate `size` cryptographically secure random bytes via the OS RNG
633
+ * (Rust side). Equivalent to {@link secureRandom} but routed through the
634
+ * native bindings — useful when you want to ensure entropy comes from the
635
+ * same source that the rest of the library uses internally.
636
+ *
637
+ * For most code, plain {@link secureRandom} (which uses `node:crypto`)
638
+ * is fine and avoids a NAPI hop.
639
+ */
640
+ declare function nativeSecureRandom(size: number): Buffer;
422
641
 
423
642
  /**
424
643
  * Typed error classes for signalis-core.
@@ -485,6 +704,14 @@ declare class AuthenticationError extends CryptoError {
485
704
  declare class KeyDerivationError extends CryptoError {
486
705
  constructor(message: string);
487
706
  }
707
+ /**
708
+ * Thrown when a digital signature verification fails (NEW in v0.2.0).
709
+ *
710
+ * Used by Ed25519 and XEd25519 verification.
711
+ */
712
+ declare class SignatureError extends CryptoError {
713
+ constructor(message?: string);
714
+ }
488
715
  /**
489
716
  * Thrown when the requested output length is invalid (e.g., HKDF > 8160 bytes).
490
717
  */
@@ -657,6 +884,22 @@ declare const CURVE25519_PRIVATE_KEY_SIZE = 32;
657
884
  declare const CURVE25519_PUBLIC_KEY_SIZE = 32;
658
885
  /** Size of an X25519 ECDH shared secret in bytes. */
659
886
  declare const CURVE25519_SHARED_SECRET_SIZE = 32;
887
+ /** Size of an Ed25519 private key in bytes. */
888
+ declare const ED25519_PRIVATE_KEY_SIZE = 32;
889
+ /** Size of an Ed25519 public key in bytes. */
890
+ declare const ED25519_PUBLIC_KEY_SIZE = 32;
891
+ /** Size of an Ed25519 signature in bytes. */
892
+ declare const ED25519_SIGNATURE_SIZE = 64;
893
+ /** Size of an Ed25519 seed for deterministic key derivation. */
894
+ declare const ED25519_SEED_SIZE = 32;
895
+ /** Size of an XEd25519 private key in bytes (same as Curve25519). */
896
+ declare const XED25519_PRIVATE_KEY_SIZE = 32;
897
+ /** Size of an XEd25519 public key in bytes (same as Curve25519). */
898
+ declare const XED25519_PUBLIC_KEY_SIZE = 32;
899
+ /** Size of an XEd25519 signature in bytes. */
900
+ declare const XED25519_SIGNATURE_SIZE = 64;
901
+ /** Size of XEd25519 random nonce for signing (in bytes). */
902
+ declare const XED25519_RANDOM_SIZE = 64;
660
903
  /** Size of HKDF-SHA256 PRK (pseudorandom key) in bytes. */
661
904
  declare const HKDF_PRK_SIZE = 32;
662
905
  /** Maximum HKDF-SHA256 output length: 255 * HashLen = 255 * 32 = 8160 bytes. */
@@ -695,7 +938,7 @@ declare const AES_GCM_RECOMMENDED_MESSAGES_PER_KEY = 4294967296;
695
938
  *
696
939
  * Bumped on every release.
697
940
  */
698
- declare const VERSION: "0.1.0";
941
+ declare const VERSION: "0.2.0";
699
942
 
700
943
  /**
701
944
  * Default export — provides all primitives and helpers under one namespace.
@@ -717,6 +960,28 @@ declare const SignalisCore: Readonly<{
717
960
  PUBLIC_KEY_SIZE: 32;
718
961
  SHARED_SECRET_SIZE: 32;
719
962
  }>;
963
+ Ed25519: Readonly<{
964
+ generateKeyPair(): KeyPair;
965
+ keyPairFromSeed(seed: Buffer): KeyPair;
966
+ publicFromPrivate(privateKey: Buffer): Buffer;
967
+ sign(privateKey: Buffer, message: Buffer): Signature;
968
+ verify(publicKey: Buffer, message: Buffer, signature: Buffer): void;
969
+ verifyBool(publicKey: Buffer, message: Buffer, signature: Buffer): boolean;
970
+ PRIVATE_KEY_SIZE: 32;
971
+ PUBLIC_KEY_SIZE: 32;
972
+ SIGNATURE_SIZE: 64;
973
+ SEED_SIZE: 32;
974
+ }>;
975
+ XEd25519: Readonly<{
976
+ sign(privateKey: Buffer, message: Buffer): Signature;
977
+ signWithRandom(privateKey: Buffer, message: Buffer, random: Buffer): Signature;
978
+ verify(publicKey: Buffer, message: Buffer, signature: Buffer): void;
979
+ verifyBool(publicKey: Buffer, message: Buffer, signature: Buffer): boolean;
980
+ PRIVATE_KEY_SIZE: 32;
981
+ PUBLIC_KEY_SIZE: 32;
982
+ SIGNATURE_SIZE: 64;
983
+ RANDOM_SIZE: 64;
984
+ }>;
720
985
  HKDF: Readonly<{
721
986
  extract(salt: Buffer, ikm: Buffer): Buffer;
722
987
  expand(prk: Buffer, info: Buffer, length: number): Buffer;
@@ -731,6 +996,8 @@ declare const SignalisCore: Readonly<{
731
996
  KEY_SIZE: 32;
732
997
  NONCE_SIZE: 12;
733
998
  TAG_SIZE: 16;
999
+ encryptWithAad(key: Buffer, nonce: Buffer, plaintext: Buffer, aad: Buffer): Buffer;
1000
+ decryptWithAad(key: Buffer, nonce: Buffer, ciphertext: Buffer, aad: Buffer): Buffer;
734
1001
  }>;
735
1002
  AES_CBC: Readonly<{
736
1003
  encrypt(key: Buffer, iv: Buffer, plaintext: Buffer): Buffer;
@@ -757,8 +1024,8 @@ declare const SignalisCore: Readonly<{
757
1024
  toBase64: typeof toBase64;
758
1025
  fromBase64: typeof fromBase64;
759
1026
  constantTimeEqual: typeof constantTimeEqual;
760
- VERSION: "0.1.0";
1027
+ VERSION: "0.2.0";
761
1028
  nativeVersion: string;
762
1029
  }>;
763
1030
 
764
- export { AES_256_CBC_IV_SIZE, AES_256_GCM_NONCE_SIZE, AES_256_GCM_TAG_SIZE, AES_256_KEY_SIZE, AES_BLOCK_SIZE, AES_CBC, AES_GCM, AES_GCM_MAX_PLAINTEXT_SIZE, AES_GCM_RECOMMENDED_MESSAGES_PER_KEY, type AesCbcParams, type AesGcmParams, AuthenticationError, CURVE25519_PRIVATE_KEY_SIZE, CURVE25519_PUBLIC_KEY_SIZE, CURVE25519_SHARED_SECRET_SIZE, CryptoError, Curve25519, type Encoding, HKDF, HKDF_MAX_OUTPUT_SIZE, HKDF_PRK_SIZE, HMAC, HMAC_SHA256_TAG_SIZE, type HkdfParams, KeyDerivationError, type KeyPair, LengthError, type PrivateKey, type PseudoRandomKey, type PublicKey, SHA256, SHA256_BLOCK_SIZE, SHA256_OUTPUT_SIZE, type SharedSecret, SignalisError, VERSION, ValidationError, asPrivateKey, asPublicKey, asSharedSecret, assertBuffer, assertBufferLength, assertBufferOfSize, assertHkdfLength, assertPositiveInteger, bufferToString, buffersSameLength, concat, constantTimeEqual, SignalisCore as default, fromBase64, fromBase64Url, fromHex, nativeVersion, randomIv, randomKey, randomNonce, secureRandom, stringToBuffer, toBase64, toBase64Url, toHex, xor, zeroize };
1031
+ export { AES_256_CBC_IV_SIZE, AES_256_GCM_NONCE_SIZE, AES_256_GCM_TAG_SIZE, AES_256_KEY_SIZE, AES_BLOCK_SIZE, AES_CBC, AES_GCM, AES_GCM_MAX_PLAINTEXT_SIZE, AES_GCM_RECOMMENDED_MESSAGES_PER_KEY, type AesCbcParams, type AesGcmParams, AuthenticationError, CHACHA20_POLY1305_KEY_SIZE, CHACHA20_POLY1305_NONCE_SIZE, CHACHA20_POLY1305_TAG_SIZE, CURVE25519_PRIVATE_KEY_SIZE, CURVE25519_PUBLIC_KEY_SIZE, CURVE25519_SHARED_SECRET_SIZE, ChaCha20Poly1305, CryptoError, Curve25519, ED25519_PRIVATE_KEY_SIZE, ED25519_PUBLIC_KEY_SIZE, ED25519_SEED_SIZE, ED25519_SIGNATURE_SIZE, Ed25519, type Encoding, HKDF, HKDF_MAX_OUTPUT_SIZE, HKDF_PRK_SIZE, HMAC, HMAC_SHA256_TAG_SIZE, type HkdfParams, KeyDerivationError, type KeyPair, LengthError, type PrivateKey, type PseudoRandomKey, type PublicKey, SHA256, SHA256_BLOCK_SIZE, SHA256_OUTPUT_SIZE, type SharedSecret, SignalisError, type Signature, SignatureError, VERSION, ValidationError, XED25519_PRIVATE_KEY_SIZE, XED25519_PUBLIC_KEY_SIZE, XED25519_RANDOM_SIZE, XED25519_SIGNATURE_SIZE, XEd25519, asPrivateKey, asPublicKey, asSharedSecret, asSignature, assertBuffer, assertBufferLength, assertBufferOfSize, assertHkdfLength, assertPositiveInteger, bufferToString, buffersSameLength, concat, constantTimeEq, constantTimeEqual, SignalisCore as default, fromBase64, fromBase64Url, fromHex, nativeSecureRandom, nativeVersion, randomIv, randomKey, randomNonce, secureRandom, stringToBuffer, toBase64, toBase64Url, toHex, xor, zeroize };
package/dist/index.d.ts CHANGED
@@ -46,6 +46,12 @@ type PrivateKey = Buffer & {
46
46
  type SharedSecret = Buffer & {
47
47
  readonly __brand?: 'SharedSecret';
48
48
  };
49
+ /**
50
+ * A digital signature (64 bytes) — Ed25519 or XEd25519.
51
+ */
52
+ type Signature = Buffer & {
53
+ readonly __brand?: 'Signature';
54
+ };
49
55
  /**
50
56
  * HKDF pseudorandom key (32 bytes), output of the Extract step.
51
57
  */
@@ -107,6 +113,10 @@ declare function asPrivateKey(buf: Buffer): PrivateKey;
107
113
  * Brand a Buffer as a {@link SharedSecret}.
108
114
  */
109
115
  declare function asSharedSecret(buf: Buffer): SharedSecret;
116
+ /**
117
+ * Brand a Buffer as a {@link Signature} (NEW in v0.2.0).
118
+ */
119
+ declare function asSignature(buf: Buffer): Signature;
110
120
 
111
121
  /**
112
122
  * Core cryptographic wrappers for signalis-core.
@@ -320,6 +330,28 @@ declare const AES_GCM: Readonly<{
320
330
  NONCE_SIZE: 12;
321
331
  /** Tag size in bytes (16). */
322
332
  TAG_SIZE: 16;
333
+ /**
334
+ * Encrypt with AES-256-GCM and Additional Authenticated Data (NEW in v0.2.0).
335
+ *
336
+ * AAD is authenticated but NOT encrypted. Useful for binding metadata
337
+ * (like message headers) to the ciphertext.
338
+ *
339
+ * @param key - 32-byte symmetric key
340
+ * @param nonce - 12-byte unique nonce
341
+ * @param plaintext - Data to encrypt
342
+ * @param aad - Additional authenticated data (any length, can be empty)
343
+ * @returns Ciphertext + auth tag
344
+ * @throws {ValidationError} On invalid sizes.
345
+ */
346
+ encryptWithAad(key: Buffer, nonce: Buffer, plaintext: Buffer, aad: Buffer): Buffer;
347
+ /**
348
+ * Decrypt with AES-256-GCM and AAD (NEW in v0.2.0).
349
+ *
350
+ * The same AAD used during encryption must be provided. Mismatch = failure.
351
+ *
352
+ * @throws {AuthenticationError} If tag verification fails (incl. AAD mismatch).
353
+ */
354
+ decryptWithAad(key: Buffer, nonce: Buffer, ciphertext: Buffer, aad: Buffer): Buffer;
323
355
  }>;
324
356
  /**
325
357
  * AES-256-CBC block cipher (NOT authenticated by itself).
@@ -415,10 +447,197 @@ declare const SHA256: Readonly<{
415
447
  /** Output size in bytes (32). */
416
448
  OUTPUT_SIZE: 32;
417
449
  }>;
450
+ /**
451
+ * Ed25519 digital signatures (RFC 8032).
452
+ *
453
+ * Standard Ed25519 with deterministic signatures. Use when you want clean
454
+ * separation between signing and ECDH keys.
455
+ *
456
+ * @example
457
+ * ```ts
458
+ * import { Ed25519 } from '@brashkie/signalis-core';
459
+ *
460
+ * const keys = Ed25519.generateKeyPair();
461
+ * const sig = Ed25519.sign(keys.privateKey, Buffer.from('Hello'));
462
+ * Ed25519.verify(keys.publicKey, Buffer.from('Hello'), sig);
463
+ * ```
464
+ */
465
+ declare const Ed25519: Readonly<{
466
+ /**
467
+ * Generate a new random Ed25519 keypair.
468
+ */
469
+ generateKeyPair(): KeyPair;
470
+ /**
471
+ * Derive a deterministic Ed25519 keypair from a 32-byte seed.
472
+ */
473
+ keyPairFromSeed(seed: Buffer): KeyPair;
474
+ /**
475
+ * Derive the public key from a private key.
476
+ */
477
+ publicFromPrivate(privateKey: Buffer): Buffer;
478
+ /**
479
+ * Sign a message. Ed25519 signatures are deterministic (RFC 8032).
480
+ */
481
+ sign(privateKey: Buffer, message: Buffer): Signature;
482
+ /**
483
+ * Verify a signature. Throws on failure.
484
+ *
485
+ * @throws {SignatureError} If signature is invalid.
486
+ */
487
+ verify(publicKey: Buffer, message: Buffer, signature: Buffer): void;
488
+ /**
489
+ * Verify a signature. Returns boolean (does not throw).
490
+ */
491
+ verifyBool(publicKey: Buffer, message: Buffer, signature: Buffer): boolean;
492
+ /** Private key size in bytes (32). */
493
+ PRIVATE_KEY_SIZE: 32;
494
+ /** Public key size in bytes (32). */
495
+ PUBLIC_KEY_SIZE: 32;
496
+ /** Signature size in bytes (64). */
497
+ SIGNATURE_SIZE: 64;
498
+ /** Seed size for deterministic keypair derivation (32). */
499
+ SEED_SIZE: 32;
500
+ }>;
501
+ /**
502
+ * XEd25519 — sign messages using the SAME Curve25519 keypair used for ECDH.
503
+ *
504
+ * This is what Signal Protocol uses to maintain a single identity key.
505
+ * Signatures are non-deterministic (each call gives a different valid sig).
506
+ *
507
+ * @example
508
+ * ```ts
509
+ * import { Curve25519, XEd25519 } from '@brashkie/signalis-core';
510
+ *
511
+ * const identity = Curve25519.generateKeyPair();
512
+ *
513
+ * // Use for ECDH:
514
+ * const shared = Curve25519.diffieHellman(identity.privateKey, peerPublic);
515
+ *
516
+ * // SAME key used to sign:
517
+ * const sig = XEd25519.sign(identity.privateKey, message);
518
+ * XEd25519.verify(identity.publicKey, message, sig);
519
+ * ```
520
+ */
521
+ declare const XEd25519: Readonly<{
522
+ /**
523
+ * Sign a message using a Curve25519 private key. Uses OS RNG.
524
+ * Signatures are NOT deterministic (different each call).
525
+ */
526
+ sign(privateKey: Buffer, message: Buffer): Signature;
527
+ /**
528
+ * Sign with explicit 64-byte random nonce (for testing/reproducibility).
529
+ */
530
+ signWithRandom(privateKey: Buffer, message: Buffer, random: Buffer): Signature;
531
+ /**
532
+ * Verify a XEd25519 signature. Throws on failure.
533
+ *
534
+ * @throws {SignatureError} If signature is invalid.
535
+ */
536
+ verify(publicKey: Buffer, message: Buffer, signature: Buffer): void;
537
+ /**
538
+ * Verify a XEd25519 signature. Returns boolean (does not throw).
539
+ */
540
+ verifyBool(publicKey: Buffer, message: Buffer, signature: Buffer): boolean;
541
+ /** Private key size in bytes (32, same as Curve25519). */
542
+ PRIVATE_KEY_SIZE: 32;
543
+ /** Public key size in bytes (32, same as Curve25519). */
544
+ PUBLIC_KEY_SIZE: 32;
545
+ /** Signature size in bytes (64). */
546
+ SIGNATURE_SIZE: 64;
547
+ /** Random nonce size for signing (64). */
548
+ RANDOM_SIZE: 64;
549
+ }>;
418
550
  /**
419
551
  * The version of the underlying Rust crate (from `Cargo.toml`).
420
552
  */
421
553
  declare const nativeVersion: string;
554
+ /** ChaCha20-Poly1305 key size (bytes). */
555
+ declare const CHACHA20_POLY1305_KEY_SIZE = 32;
556
+ /** ChaCha20-Poly1305 nonce size (bytes). */
557
+ declare const CHACHA20_POLY1305_NONCE_SIZE = 12;
558
+ /** Poly1305 authentication tag size (bytes), appended to ciphertext. */
559
+ declare const CHACHA20_POLY1305_TAG_SIZE = 16;
560
+ /**
561
+ * ChaCha20-Poly1305 authenticated encryption with associated data (AEAD).
562
+ *
563
+ * RFC 8439-compliant alternative to AES-GCM. Same security guarantees,
564
+ * but typically 2-3x faster on platforms without AES-NI hardware
565
+ * (Android arm64-v8a without crypto extensions, IoT, older embedded).
566
+ *
567
+ * On servers and modern desktops with AES-NI, AES-GCM is usually faster
568
+ * — pick the cipher based on your deployment target.
569
+ *
570
+ * @example
571
+ * ```ts
572
+ * import { ChaCha20Poly1305, secureRandom } from '@brashkie/signalis-core';
573
+ *
574
+ * const key = secureRandom(32);
575
+ * const nonce = secureRandom(12);
576
+ * const ct = ChaCha20Poly1305.encrypt(key, nonce, Buffer.from('secret'));
577
+ * const pt = ChaCha20Poly1305.decrypt(key, nonce, ct);
578
+ * ```
579
+ */
580
+ declare const ChaCha20Poly1305: Readonly<{
581
+ /**
582
+ * Encrypt + authenticate `plaintext`.
583
+ *
584
+ * @param key 32-byte key
585
+ * @param nonce 12-byte nonce — MUST be unique per (key, plaintext)
586
+ * @param plaintext data to encrypt
587
+ * @returns ciphertext || tag (16 bytes appended)
588
+ */
589
+ encrypt(key: Buffer, nonce: Buffer, plaintext: Buffer): Buffer;
590
+ /**
591
+ * Verify-then-decrypt. Returns plaintext on success, throws on auth failure.
592
+ */
593
+ decrypt(key: Buffer, nonce: Buffer, ciphertext: Buffer): Buffer;
594
+ /**
595
+ * Encrypt + authenticate with Additional Authenticated Data.
596
+ *
597
+ * AAD is NOT encrypted but IS authenticated. Use for plaintext metadata
598
+ * (e.g., message headers) that must not be tampered with.
599
+ */
600
+ encryptWithAad(key: Buffer, nonce: Buffer, plaintext: Buffer, aad: Buffer): Buffer;
601
+ /**
602
+ * Verify (key + nonce + ciphertext + AAD) and decrypt.
603
+ */
604
+ decryptWithAad(key: Buffer, nonce: Buffer, ciphertext: Buffer, aad: Buffer): Buffer;
605
+ /** Key size in bytes (32). */
606
+ KEY_SIZE: 32;
607
+ /** Nonce size in bytes (12). */
608
+ NONCE_SIZE: 12;
609
+ /** Authentication tag size in bytes (16), appended to ciphertext. */
610
+ TAG_SIZE: 16;
611
+ }>;
612
+ /**
613
+ * Compare two buffers in constant time.
614
+ *
615
+ * Returns `true` only if both buffers have identical length AND contents.
616
+ *
617
+ * Use this for any secret comparison (MAC tags, signatures, tokens) where
618
+ * a fast-fail comparison could leak information via timing side-channels.
619
+ *
620
+ * **Wrong:**
621
+ * ```ts
622
+ * if (expectedMac.equals(receivedMac)) { ... } // ← timing-vulnerable
623
+ * ```
624
+ *
625
+ * **Right:**
626
+ * ```ts
627
+ * if (constantTimeEq(expectedMac, receivedMac)) { ... }
628
+ * ```
629
+ */
630
+ declare function constantTimeEq(a: Buffer, b: Buffer): boolean;
631
+ /**
632
+ * Generate `size` cryptographically secure random bytes via the OS RNG
633
+ * (Rust side). Equivalent to {@link secureRandom} but routed through the
634
+ * native bindings — useful when you want to ensure entropy comes from the
635
+ * same source that the rest of the library uses internally.
636
+ *
637
+ * For most code, plain {@link secureRandom} (which uses `node:crypto`)
638
+ * is fine and avoids a NAPI hop.
639
+ */
640
+ declare function nativeSecureRandom(size: number): Buffer;
422
641
 
423
642
  /**
424
643
  * Typed error classes for signalis-core.
@@ -485,6 +704,14 @@ declare class AuthenticationError extends CryptoError {
485
704
  declare class KeyDerivationError extends CryptoError {
486
705
  constructor(message: string);
487
706
  }
707
+ /**
708
+ * Thrown when a digital signature verification fails (NEW in v0.2.0).
709
+ *
710
+ * Used by Ed25519 and XEd25519 verification.
711
+ */
712
+ declare class SignatureError extends CryptoError {
713
+ constructor(message?: string);
714
+ }
488
715
  /**
489
716
  * Thrown when the requested output length is invalid (e.g., HKDF > 8160 bytes).
490
717
  */
@@ -657,6 +884,22 @@ declare const CURVE25519_PRIVATE_KEY_SIZE = 32;
657
884
  declare const CURVE25519_PUBLIC_KEY_SIZE = 32;
658
885
  /** Size of an X25519 ECDH shared secret in bytes. */
659
886
  declare const CURVE25519_SHARED_SECRET_SIZE = 32;
887
+ /** Size of an Ed25519 private key in bytes. */
888
+ declare const ED25519_PRIVATE_KEY_SIZE = 32;
889
+ /** Size of an Ed25519 public key in bytes. */
890
+ declare const ED25519_PUBLIC_KEY_SIZE = 32;
891
+ /** Size of an Ed25519 signature in bytes. */
892
+ declare const ED25519_SIGNATURE_SIZE = 64;
893
+ /** Size of an Ed25519 seed for deterministic key derivation. */
894
+ declare const ED25519_SEED_SIZE = 32;
895
+ /** Size of an XEd25519 private key in bytes (same as Curve25519). */
896
+ declare const XED25519_PRIVATE_KEY_SIZE = 32;
897
+ /** Size of an XEd25519 public key in bytes (same as Curve25519). */
898
+ declare const XED25519_PUBLIC_KEY_SIZE = 32;
899
+ /** Size of an XEd25519 signature in bytes. */
900
+ declare const XED25519_SIGNATURE_SIZE = 64;
901
+ /** Size of XEd25519 random nonce for signing (in bytes). */
902
+ declare const XED25519_RANDOM_SIZE = 64;
660
903
  /** Size of HKDF-SHA256 PRK (pseudorandom key) in bytes. */
661
904
  declare const HKDF_PRK_SIZE = 32;
662
905
  /** Maximum HKDF-SHA256 output length: 255 * HashLen = 255 * 32 = 8160 bytes. */
@@ -695,7 +938,7 @@ declare const AES_GCM_RECOMMENDED_MESSAGES_PER_KEY = 4294967296;
695
938
  *
696
939
  * Bumped on every release.
697
940
  */
698
- declare const VERSION: "0.1.0";
941
+ declare const VERSION: "0.2.0";
699
942
 
700
943
  /**
701
944
  * Default export — provides all primitives and helpers under one namespace.
@@ -717,6 +960,28 @@ declare const SignalisCore: Readonly<{
717
960
  PUBLIC_KEY_SIZE: 32;
718
961
  SHARED_SECRET_SIZE: 32;
719
962
  }>;
963
+ Ed25519: Readonly<{
964
+ generateKeyPair(): KeyPair;
965
+ keyPairFromSeed(seed: Buffer): KeyPair;
966
+ publicFromPrivate(privateKey: Buffer): Buffer;
967
+ sign(privateKey: Buffer, message: Buffer): Signature;
968
+ verify(publicKey: Buffer, message: Buffer, signature: Buffer): void;
969
+ verifyBool(publicKey: Buffer, message: Buffer, signature: Buffer): boolean;
970
+ PRIVATE_KEY_SIZE: 32;
971
+ PUBLIC_KEY_SIZE: 32;
972
+ SIGNATURE_SIZE: 64;
973
+ SEED_SIZE: 32;
974
+ }>;
975
+ XEd25519: Readonly<{
976
+ sign(privateKey: Buffer, message: Buffer): Signature;
977
+ signWithRandom(privateKey: Buffer, message: Buffer, random: Buffer): Signature;
978
+ verify(publicKey: Buffer, message: Buffer, signature: Buffer): void;
979
+ verifyBool(publicKey: Buffer, message: Buffer, signature: Buffer): boolean;
980
+ PRIVATE_KEY_SIZE: 32;
981
+ PUBLIC_KEY_SIZE: 32;
982
+ SIGNATURE_SIZE: 64;
983
+ RANDOM_SIZE: 64;
984
+ }>;
720
985
  HKDF: Readonly<{
721
986
  extract(salt: Buffer, ikm: Buffer): Buffer;
722
987
  expand(prk: Buffer, info: Buffer, length: number): Buffer;
@@ -731,6 +996,8 @@ declare const SignalisCore: Readonly<{
731
996
  KEY_SIZE: 32;
732
997
  NONCE_SIZE: 12;
733
998
  TAG_SIZE: 16;
999
+ encryptWithAad(key: Buffer, nonce: Buffer, plaintext: Buffer, aad: Buffer): Buffer;
1000
+ decryptWithAad(key: Buffer, nonce: Buffer, ciphertext: Buffer, aad: Buffer): Buffer;
734
1001
  }>;
735
1002
  AES_CBC: Readonly<{
736
1003
  encrypt(key: Buffer, iv: Buffer, plaintext: Buffer): Buffer;
@@ -757,8 +1024,8 @@ declare const SignalisCore: Readonly<{
757
1024
  toBase64: typeof toBase64;
758
1025
  fromBase64: typeof fromBase64;
759
1026
  constantTimeEqual: typeof constantTimeEqual;
760
- VERSION: "0.1.0";
1027
+ VERSION: "0.2.0";
761
1028
  nativeVersion: string;
762
1029
  }>;
763
1030
 
764
- export { AES_256_CBC_IV_SIZE, AES_256_GCM_NONCE_SIZE, AES_256_GCM_TAG_SIZE, AES_256_KEY_SIZE, AES_BLOCK_SIZE, AES_CBC, AES_GCM, AES_GCM_MAX_PLAINTEXT_SIZE, AES_GCM_RECOMMENDED_MESSAGES_PER_KEY, type AesCbcParams, type AesGcmParams, AuthenticationError, CURVE25519_PRIVATE_KEY_SIZE, CURVE25519_PUBLIC_KEY_SIZE, CURVE25519_SHARED_SECRET_SIZE, CryptoError, Curve25519, type Encoding, HKDF, HKDF_MAX_OUTPUT_SIZE, HKDF_PRK_SIZE, HMAC, HMAC_SHA256_TAG_SIZE, type HkdfParams, KeyDerivationError, type KeyPair, LengthError, type PrivateKey, type PseudoRandomKey, type PublicKey, SHA256, SHA256_BLOCK_SIZE, SHA256_OUTPUT_SIZE, type SharedSecret, SignalisError, VERSION, ValidationError, asPrivateKey, asPublicKey, asSharedSecret, assertBuffer, assertBufferLength, assertBufferOfSize, assertHkdfLength, assertPositiveInteger, bufferToString, buffersSameLength, concat, constantTimeEqual, SignalisCore as default, fromBase64, fromBase64Url, fromHex, nativeVersion, randomIv, randomKey, randomNonce, secureRandom, stringToBuffer, toBase64, toBase64Url, toHex, xor, zeroize };
1031
+ export { AES_256_CBC_IV_SIZE, AES_256_GCM_NONCE_SIZE, AES_256_GCM_TAG_SIZE, AES_256_KEY_SIZE, AES_BLOCK_SIZE, AES_CBC, AES_GCM, AES_GCM_MAX_PLAINTEXT_SIZE, AES_GCM_RECOMMENDED_MESSAGES_PER_KEY, type AesCbcParams, type AesGcmParams, AuthenticationError, CHACHA20_POLY1305_KEY_SIZE, CHACHA20_POLY1305_NONCE_SIZE, CHACHA20_POLY1305_TAG_SIZE, CURVE25519_PRIVATE_KEY_SIZE, CURVE25519_PUBLIC_KEY_SIZE, CURVE25519_SHARED_SECRET_SIZE, ChaCha20Poly1305, CryptoError, Curve25519, ED25519_PRIVATE_KEY_SIZE, ED25519_PUBLIC_KEY_SIZE, ED25519_SEED_SIZE, ED25519_SIGNATURE_SIZE, Ed25519, type Encoding, HKDF, HKDF_MAX_OUTPUT_SIZE, HKDF_PRK_SIZE, HMAC, HMAC_SHA256_TAG_SIZE, type HkdfParams, KeyDerivationError, type KeyPair, LengthError, type PrivateKey, type PseudoRandomKey, type PublicKey, SHA256, SHA256_BLOCK_SIZE, SHA256_OUTPUT_SIZE, type SharedSecret, SignalisError, type Signature, SignatureError, VERSION, ValidationError, XED25519_PRIVATE_KEY_SIZE, XED25519_PUBLIC_KEY_SIZE, XED25519_RANDOM_SIZE, XED25519_SIGNATURE_SIZE, XEd25519, asPrivateKey, asPublicKey, asSharedSecret, asSignature, assertBuffer, assertBufferLength, assertBufferOfSize, assertHkdfLength, assertPositiveInteger, bufferToString, buffersSameLength, concat, constantTimeEq, constantTimeEqual, SignalisCore as default, fromBase64, fromBase64Url, fromHex, nativeSecureRandom, nativeVersion, randomIv, randomKey, randomNonce, secureRandom, stringToBuffer, toBase64, toBase64Url, toHex, xor, zeroize };