Ed25519 Security-Focused API Documentation

Version: 1.0
Last Updated: 2025-07-05
**Security Classification:
PUBLIC
Author: Phantom (phantom@metamui.id)

Overview

Ed25519 is a high-security digital signature algorithm providing 128-bit security level. This documentation provides security-focused guidance for using the Ed25519 implementation in the MetaMUI cryptographic library.

Security Level: 128 bits
Key Size: 32 bytes (256 bits)
Signature Size: 64 bytes

Security Warnings ⚠️

  1. Private Key Entropy: Private keys MUST have at least 128 bits of entropy
  2. Key Storage: Private keys must be stored encrypted and cleared from memory after use
  3. Deterministic Nonces: Ed25519 uses deterministic nonces - do NOT attempt to provide random nonces
  4. Quantum Vulnerability: Ed25519 is NOT quantum-resistant

API Functions

generate_keypair() -> (PrivateKey, PublicKey)

Security Contract:

Attack Resistance: | Attack Type | Protected | Notes | |————-|———–|——-| | Weak RNG | ✅ | Uses system CSPRNG | | Timing Attack | ✅ | Constant-time scalar multiplication | | Memory Disclosure | ✅ | Secure memory clearing | | Fault Injection | ❌ | No protection against hardware faults |

Secure Usage Example:

# SECURE: Generate keypair with proper entropy
private_key, public_key = ed25519.generate_keypair()
try:
    # Use the keys
    signature = ed25519.sign(message, private_key)
finally:
    # Always clear private key from memory
    secure_clear(private_key)

Common Mistakes:

# INSECURE: Using weak entropy source
import random
random.seed(12345)  # NEVER DO THIS
weak_bytes = bytes([random.randint(0, 255) for _ in range(32)])
private_key = ed25519.from_seed(weak_bytes)  # VULNERABLE!

# INSECURE: Not clearing private key
private_key, public_key = ed25519.generate_keypair()
signature = ed25519.sign(message, private_key)
# private_key remains in memory - SECURITY RISK!

sign(message: bytes, private_key: PrivateKey) -> Signature

Security Contract:

Attack Resistance: | Attack Type | Protected | Notes | |————-|———–|——-| | Timing Attack | ✅ | Constant-time implementation | | Malleability | ✅ | Canonical signature encoding | | Nonce Reuse | ✅ | Deterministic nonces from RFC 8032 | | Power Analysis | ⚠️ | Basic protection, not DPA-resistant | | Fault Injection | ❌ | No protection |

Security Requirements:

Secure Usage Example:

// SECURE: Sign with proper key handling
let private_key = secure_load_private_key()?;
let signature = ed25519::sign(&message, &private_key)?;
secure_zero(&mut private_key);  // Clear immediately after use

// SECURE: Sign multiple messages
let private_key = secure_load_private_key()?;
let signatures: Vec<Signature> = messages
    .iter()
    .map(|msg| ed25519::sign(msg, &private_key))
    .collect::<Result<_, _>>()?;
secure_zero(&mut private_key);

Common Mistakes:

// INSECURE: Reusing nonces (if implementation allowed it)
let nonce = generate_random_nonce();  // NEVER DO THIS
let sig1 = ed25519_sign_with_nonce(msg1, private_key, nonce);
let sig2 = ed25519_sign_with_nonce(msg2, private_key, nonce);  // KEY COMPROMISED!

// INSECURE: Leaving private key in memory
let private_key = load_private_key()?;
let signature = ed25519::sign(&message, &private_key)?;
// private_key not cleared - can be extracted from memory dump

verify(message: bytes, signature: Signature, public_key: PublicKey) -> bool

Security Contract:

Attack Resistance: | Attack Type | Protected | Notes | |————-|———–|——-| | Timing Attack | ✅ | Constant-time verification | | Malleability | ✅ | Rejects non-canonical signatures | | Invalid Curve | ✅ | Validates public key is on curve | | Small Subgroup | ✅ | Cofactor multiplication included |

Security Warnings:

Secure Usage Example:

// SECURE: Verify with proper error handling
const isValid = ed25519.verify(message, signature, publicKey);
if (!isValid) {
    // Log failure but don't reveal details to attacker
    logger.warn('Signature verification failed');
    throw new Error('Invalid signature');
}

// SECURE: Batch verification for performance
const results = ed25519.batchVerify(messages, signatures, publicKeys);
const allValid = results.every(r => r === true);
if (!allValid) {
    // Don't reveal which signatures failed
    throw new Error('Batch verification failed');
}

Common Mistakes:

// INSECURE: Revealing verification details
try {
    ed25519.verify(message, signature, publicKey);
} catch (e) {
    // NEVER DO THIS - reveals information to attacker
    return { error: `Verification failed: ${e.message}` };
}

// INSECURE: Not checking return value
ed25519.verify(message, signature, publicKey);
// Assuming success without checking - SECURITY RISK!
processAuthenticatedMessage(message);

from_seed(seed: bytes) -> PrivateKey

Security Contract:

Attack Resistance: | Attack Type | Protected | Notes | |————-|———–|——-| | Weak Seeds | ❌ | Caller responsible for entropy | | Rainbow Tables | ⚠️ | Only if seed has good entropy | | Timing Attack | ✅ | Constant-time derivation |

Security Requirements:

Secure Usage Example:

// SECURE: Generate high-entropy seed
let seed = try SecureRandom.generateBytes(count: 32)
let privateKey = try Ed25519.fromSeed(seed)
defer { 
    secureZero(&seed)
    secureZero(&privateKey)
}

// SECURE: Derive from password using KDF
let salt = try SecureRandom.generateBytes(count: 32)
let seed = try Argon2.deriveKey(
    password: password,
    salt: salt,
    length: 32,
    iterations: 4,
    memory: 65536,
    parallelism: 1
)
let privateKey = try Ed25519.fromSeed(seed)
defer { secureZero(&seed) }

Common Mistakes:

// INSECURE: Low entropy seed
let timestamp = UInt32(Date().timeIntervalSince1970)
var seed = Data(count: 32)
seed[0..<4] = withUnsafeBytes(of: timestamp) { Data($0) }
let privateKey = Ed25519.fromSeed(seed)  // EASILY BRUTE-FORCED!

// INSECURE: Predictable seed from password
let seed = password.data(using: .utf8)!.sha256()  // NO KDF!
let privateKey = Ed25519.fromSeed(seed)  // VULNERABLE TO DICTIONARY ATTACK!

// INSECURE: Reusing seeds across different contexts
let masterSeed = loadMasterSeed()
let signingKey = Ed25519.fromSeed(masterSeed)
let encryptionKey = X25519.fromSeed(masterSeed)  // KEY REUSE - DANGEROUS!

Security Best Practices

Key Management

  1. Generation: Always use system CSPRNG for key generation
  2. Storage: Encrypt private keys at rest using authenticated encryption
  3. Transport: Never transmit private keys; use secure key agreement
  4. Rotation: Implement regular key rotation policies
  5. Destruction: Clear keys from memory immediately after use

Implementation Security

  1. Constant Time: All operations are constant-time by default
  2. No Branching: Never branch on secret data
  3. Memory Safety: Use secure allocators where available
  4. Stack Clearing: Enable stack clearing in sensitive functions

Common Integration Patterns

Secure Authentication Flow

# 1. Server generates challenge
challenge = secure_random(32)
session['challenge'] = challenge
send_to_client(challenge)

# 2. Client signs challenge
signature = ed25519.sign(challenge + client_id, private_key)
secure_clear(private_key)
send_to_server(signature, client_id, public_key)

# 3. Server verifies
expected_message = session['challenge'] + client_id
if not ed25519.verify(expected_message, signature, public_key):
    raise AuthenticationError()
# Clear challenge to prevent replay
del session['challenge']

Secure Document Signing

// 1. Hash document first (for large files)
let document_hash = sha512::hash(&document);

// 2. Create signature with metadata
let to_sign = format!(
    "Document signature v1.0\n\
     Hash: {}\n\
     Timestamp: {}\n\
     Signer: {}",
    hex::encode(&document_hash),
    timestamp,
    signer_id
);

// 3. Sign with proper key handling
let private_key = secure_key_store.get_signing_key()?;
let signature = ed25519::sign(to_sign.as_bytes(), &private_key)?;
secure_key_store.clear_signing_key();

// 4. Create verifiable signature bundle
let signature_bundle = SignatureBundle {
    signature,
    public_key,
    document_hash,
    timestamp,
    signer_id,
};

Performance Considerations

Operation Time Security Notes
Key Generation ~250 μs Includes secure random generation
Signing ~70 μs Constant time regardless of message
Verification ~180 μs Constant time for both success/failure
Batch Verify (n=100) ~12 ms ~3x faster than individual verification

Platform-Specific Security Notes

Python

Rust

TypeScript/JavaScript

Swift

Kotlin

Compliance and Standards

Security Auditing

Verification Checklist

Logging and Monitoring

# SECURE: Log operations without revealing secrets
logger.info(f"Signature created for document {doc_id}")
logger.info(f"Signature verified for user {user_id}")

# INSECURE: Never log private keys or signatures
logger.debug(f"Private key: {private_key}")  # NEVER!
logger.debug(f"Signature: {signature}")      # NEVER!

Security Analysis

Threat Model: Ed25519 Threat Model

The comprehensive threat analysis covers:

For complete security analysis and risk assessment, see the dedicated threat model documentation.

References

  1. RFC 8032 - EdDSA Signature Algorithms
  2. DJB’s Ed25519 Paper
  3. Security Best Practices

Support

Security Issues: security@metamui.id
Documentation Updates: phantom@metamui.id
Vulnerability Disclosure: See SECURITY.md


Document Version: 1.0
Review Cycle: Quarterly
Next Review: 2025-04-05
Classification: PUBLIC