ed25519:   Pure-Racket Ed25519 Signatures
1 Quick Start
2 Keys
ed25519-keypair
generate-keypair
keypair-public
keypair-secret
secret->public
3 Signing and Verification
sign
verify
4 Constants
public-key-length
secret-key-length
signature-length
5 Security Considerations
9.3

ed25519: Pure-Racket Ed25519 Signatures🔗ℹ

 (require ed25519) package: ed25519

This package implements Ed25519 signatures exactly as specified in RFC 8032 using only pure Racket: no FFI, no shared libraries, no external tools. It exists as the last-resort fallback of a provider chain: if no native provider (such as OpenSSL 3 via crypto-lib, libsodium, or Nettle) is available, Ed25519 signing and verification still work in any Racket environment.

  • Signatures are deterministic: the same message and secret seed always produce the same 64-byte signature.

  • The implementation matches RFC 8032 and is validated against all RFC 8032 section 7.1 test vectors plus byte-for-byte cross-validation against OpenSSL 3.

  • It is not constant time. Verification of public data is safe anywhere; production key holders should prefer a native provider (see Security Considerations).

1 Quick Start🔗ℹ

> "(require ed25519)"

"(require ed25519)"

> "\n"

"\n"

> "\n"

"\n"

> "(define kp (generate-keypair))"

"(define kp (generate-keypair))"

> "\n"

"\n"

> "(define message #\"update manifest 2026-11-04\")"

"(define message #\"update manifest 2026-11-04\")"

> "\n"

"\n"

> "(define sig (sign message (keypair-secret kp)))"

"(define sig (sign message (keypair-secret kp)))"

> "\n"

"\n"

> "(verify message sig (keypair-public kp))"

"(verify message sig (keypair-public kp))"

A key pair carries the public key and the secret seed, both as 32-byte byte strings. The secret seed is the RFC 8032 seed: 32 bytes of entropy, not the 64-byte expanded form.

> "(require ed25519)"

"(require ed25519)"

> "\n"

"\n"

> "\n"

"\n"

> "(define seed (crypto-random-bytes 32))   ; caller-provided seed"

"(define seed (crypto-random-bytes 32))   ; caller-provided seed"

> "\n"

"\n"

> "(secret->public seed)                    ; derive the public key"

"(secret->public seed)                    ; derive the public key"

2 Keys🔗ℹ

struct

(struct ed25519-keypair (public secret))

  public : bytes?
  secret : bytes?
A public/secret key pair. public is exactly 32 bytes; the secret field is the 32-byte RFC 8032 seed. The structure is transparent: treat the secret field with the same care as any private key material.

Generates a fresh key pair from 32 bytes of OS entropy (crypto-random-bytes); no deterministic or time-based generation is involved.

procedure

(keypair-public kp) → bytes?

  kp : ed25519-keypair?
Returns the 32-byte public key of kp.

procedure

(keypair-secret kp) → bytes?

  kp : ed25519-keypair?
Returns the 32-byte secret seed of kp.

procedure

(secret->public secret) → bytes?

  secret : bytes?
Derives the 32-byte public key for the 32-byte secret seed secret. Use this when a seed already exists (for example, persisted key material). Raises exn:fail:contract unless secret is a byte string of exactly 32 bytes.

3 Signing and Verification🔗ℹ

procedure

(sign message secret) → bytes?

  message : bytes?
  secret : bytes?
Signs message with the 32-byte secret seed secret and returns the 64-byte signature. Deterministic: identical inputs yield identical signatures. Keys and messages are raw bytes only; callers encode strings themselves (UTF-8 is the recommended encoding). Raises exn:fail:contract for non-byte or wrong-length arguments.

procedure

(verify message signature public) → boolean?

  message : bytes?
  signature : bytes?
  public : bytes?
Verifies signature over message against the 32-byte public key public, returning #t or #f.

All cryptographic failures return #f and never raise: tampered messages or signatures, wrong keys, non-canonical point encodings, non-canonical scalars (S at or above the group order), and small-order public keys are all rejected. Length or type violations raise exn:fail:contract.

4 Constants🔗ℹ

value

public-key-length : 32

Length in bytes of a public key.

value

secret-key-length : 32

Length in bytes of a secret seed.

value

signature-length : 64

Length in bytes of a signature.

5 Security Considerations🔗ℹ

  • Not constant time. Racket bignum arithmetic leaks timing information. Verification of public data (update manifests, license proofs, signed attestations) is the intended use. Production issuers should sign with a native provider and use this implementation only as a fallback in controlled environments.

  • No third-party audit. The implementation follows RFC 8032 and ref10’s decompression technique, is validated against all RFC 8032 vectors, and is cross-checked byte-for-byte against OpenSSL 3, but it has not undergone an independent cryptographic audit.

  • This package signs, it does not encrypt. Ed25519 is a signature scheme; it provides no confidentiality and no key agreement.

  • Secrets are ordinary byte strings. Transparent structures can print secret seeds; keep them out of logs and error messages.

Provenance. The algorithm follows RFC 8032 section 5.1 directly, with the decompression technique from the public-domain ref10 reference implementation (D. J. Bernstein et al.) and SHA-512 per FIPS 180-4. See the package NOTICE file for full attribution.