Files
skills/docs/security-stack/crypto/crypto-sodium/src/engines/sodium-sign-engine/sodium-sign-engine.md
2026-05-29 08:20:56 +01:00

3.8 KiB

engines/sodium-sign-engine

(no submodules)

Purpose

sodiumSignEngine implements the SignEngine interface from @suaveplan/crypto using libsodium's Ed25519 signing primitives. Ed25519 is a deterministic signature scheme based on the Edwards-curve digital signature algorithm — it provides strong security guarantees, fast verification, and small key and signature sizes.

This engine replaces the noble-curves default in performance-sensitive or server-side scenarios where the libsodium WASM path is preferred for its maturity and NIST/IETF certification heritage.

Features

  • Ed25519 keypair generation via crypto_sign_keypair — uses libsodium's internal secure entropy.
  • Detached signature creation via crypto_sign_detached — signature is separate from the message.
  • Detached signature verification via crypto_sign_verify_detached — returns boolean, never throws on invalid signatures.
  • 32-byte public keys, 64-byte secret keys (includes seed), 64-byte signatures.
  • Conforms to SignEngine from @suaveplan/crypto/engines — drop-in for the noble default.

Usage: Basic Example

import { sodiumReady } from "@suaveplan/crypto-sodium/init";
import { sodiumSignEngine } from "@suaveplan/crypto-sodium/engines/sign";

await sodiumReady();

const kp = sodiumSignEngine.generateKeypair();
const msg = new TextEncoder().encode("sign this");
const sig = sodiumSignEngine.sign(kp.secretKey, msg);
const valid = sodiumSignEngine.verify(kp.publicKey, sig, msg);
console.log(valid); // true

Usage: Advanced Example

Using sodiumSignEngine as a pluggable engine with @suaveplan/crypto:

import { sodiumReady } from "@suaveplan/crypto-sodium/init";
import { sodiumSignEngine } from "@suaveplan/crypto-sodium/engines/sign";
import type { SignEngine } from "@suaveplan/crypto/engines";

await sodiumReady();

function signDocument(
  engine: SignEngine,
  secretKey: Uint8Array,
  document: Uint8Array
): Uint8Array {
  return engine.sign(secretKey, document);
}

const kp = sodiumSignEngine.generateKeypair();
const doc = new TextEncoder().encode("legal document text");
const sig = signDocument(sodiumSignEngine, kp.secretKey, doc);

// Verify on the receiving side:
const ok = sodiumSignEngine.verify(kp.publicKey, sig, doc);

API Reference

sodiumSignEngine: SignEngine

Singleton engine object.

generateKeypair(byteSource?: ByteSource): SignKeypair

Generates a fresh Ed25519 keypair. The byteSource parameter is accepted for interface compatibility but ignored — libsodium manages its own CSPRNG.

Returns: { publicKey: Uint8Array (32 bytes), secretKey: Uint8Array (64 bytes) }

sign(secretKey: Uint8Array, message: Uint8Array): Uint8Array

Produces a 64-byte detached Ed25519 signature over message.

verify(publicKey: Uint8Array, signature: Uint8Array, message: Uint8Array): boolean

Verifies a detached signature. Returns false rather than throwing on any verification failure (wrong key, tampered sig, wrong message). Exceptions from libsodium are caught and mapped to false.

Implementation Notes

libsodium's crypto_sign_keypair() returns { publicKey, privateKey } — note the property is named privateKey in the TS bindings despite being the full 64-byte secret key (seed + public key concatenated). The engine remaps this to secretKey to match the SignKeypair interface.

The byteSource parameter is not forwarded to libsodium because libsodium's WASM module manages entropy internally. Callers cannot substitute an alternative random source for key generation via this engine.

verify wraps crypto_sign_verify_detached in a try/catch because libsodium throws for structurally malformed inputs (e.g., a signature buffer that is not 64 bytes), mapping those to false for consistency with the SignEngine contract.