Ed25519 (RFC 8032 / FIPS 186-5 §7.6) — EdDSA pure + ph (preHash) + ctx (context).

Module ed25519 | Source packages/front/fw/src/crypto/pkc/ed25519.js | Deps sha512, bitArray | Worker-safe yes

EdDSA over Curve25519 (cofactor 8). Faster than ECDSA, deterministic by construction (no RNG required to sign). Ed448 explicit reject (FIPS 186-5 §7.7 out of scope).

Resolve

const ed25519 = runtime.resolve('ed25519');
// Returns: { keyPair, sign, verify, signPh, verifyPh, signCtx, verifyCtx, ed448 }

API

Method Signature Returns
keyPair(seed) (Uint8Array(32)) => {publicKey, privateKey} | false Derives the pair from the seed; false if seed absent or ≠ 32 bytes
sign(privateKey, msg) (Uint8Array(64), Uint8Array) => Uint8Array(64) | false Pure Ed25519 signature (privateKey = seed ‖ pubKey, 64 bytes)
verify(publicKey, msg, sig) (Uint8Array(32), Uint8Array, Uint8Array(64)) => boolean Verifies + rejects s≥L constant-time
signPh(privateKey, msg, ctx?) (Uint8Array(64), Uint8Array, Uint8Array?) => Uint8Array(64) | false Ed25519ph — pass the raw message (SHA-512 applied internally)
verifyPh(publicKey, msg, sig, ctx?) — boolean
signCtx(privateKey, msg, ctx) (Uint8Array(64), Uint8Array, Uint8Array(1..255)) => Uint8Array(64) | false Ed25519ctx (context required, 1..255 bytes)
verifyCtx(publicKey, msg, sig, ctx) — boolean
ed448.{keyPair,sign,verify,signPh,verifyPh} () => false NOT-IMPLEMENTED explicit reject

Examples

Pure EdDSA

const { ed25519, random } = fw.runtime.resolveAll(['ed25519', 'random']);
const { privateKey, publicKey } = ed25519.keyPair(random.bytes(32));

const msg = new TextEncoder().encode('Hello, EdDSA!');
const sig = ed25519.sign(privateKey, msg);
const ok  = ed25519.verify(publicKey, msg, sig);   // true

Ed25519ph (prehash + dom2)

// signPh takes the raw message — SHA-512 is applied internally
const sig = ed25519.signPh(privateKey, msg);
const ok  = ed25519.verifyPh(publicKey, msg, sig);

Ed25519ctx (context separation)

const ctx = new TextEncoder().encode('app-v1');   // 1..255 bytes required
const sig = ed25519.signCtx(privateKey, msg, ctx);
const ok  = ed25519.verifyCtx(publicKey, msg, sig, ctx);
const bad = ed25519.verifyCtx(publicKey, msg, sig, otherCtx);   // false

Ed448 rejected

ed25519.ed448.keyPair();   // false + console.warn('NOT-IMPLEMENTED: ed25519: Ed448 ...')

Worker Usage

const worker = fw.createWorker(
    function ({ libs, args }) {
        const sig = libs.ed25519.sign(args[0], args[1]);
        self.postMessage(sig);
    },
    { dependencies: ['ed25519'], args: [privateKey, msg] }
);

Notes

  • Deterministic: sign(sk, msg) does NOT consume any RNG (k derived from sk + msg via SHA-512). Byte-exact reproducible.
  • s < L check: verify rejects signatures where s ≥ L (constant-time, RFC 8032 §5.1.7 step 2) — prevents malleability (s + k·L would otherwise be valid).
  • keyPair(seed) — seed required: keyPair() without argument returns false + warn. Use random.bytes(32) for generation.
  • Ed25519ph: pass the raw message — signPh applies SHA-512 internally. Do not pre-hash before the call.
  • Ed448 not implemented — edwards448 curve + SHAKE-256; create a separate ed448.js module if required for CMVP.

See also