import Foundation import CryptoKit /// Ed25519 signing operations — Identity Key management enum Ed25519Crypto { // MARK: - Key Generation /// Generate Ed25519 keypair static func generateKeypair() -> (privateKey: Curve25519.Signing.PrivateKey, publicKey: Curve25519.Signing.PublicKey) { let privateKey = Curve25519.Signing.PrivateKey() return (privateKey, privateKey.publicKey) } // MARK: - Serialization /// Serialize Ed25519 private key. With password: raw 32B → ECP1. Without: raw 32B. /// Matches Python: serialize_ed25519_private(key, password=None) static func serializePrivate(_ key: Curve25519.Signing.PrivateKey, password: Data? = nil) throws -> Data { let raw = key.rawData // 32 bytes if let password = password { return try KeyEncryption.encrypt(raw, password: password) } return raw } /// Serialize Ed25519 public key to 32 raw bytes. /// Matches Python: serialize_ed25519_public(key) static func serializePublic(_ key: Curve25519.Signing.PublicKey) -> Data { key.rawData // 32 bytes } // MARK: - Loading /// Load Ed25519 private key. Auto-detects ECP1 / raw 32B. /// Matches Python: load_ed25519_private(data, password=None) static func loadPrivate(_ data: Data, password: Data? = nil) throws -> Curve25519.Signing.PrivateKey { if KeyEncryption.isECP1Format(data) { guard let pwd = password else { throw CryptoError.invalidKeyData("ECP1 key requires password") } let raw = try KeyEncryption.decrypt(data, password: pwd) return try Curve25519.Signing.PrivateKey(rawRepresentation: raw) } if data.count == 32 { return try Curve25519.Signing.PrivateKey(rawRepresentation: data) } throw CryptoError.invalidKeyData("Cannot parse Ed25519 private key (\(data.count) bytes)") } /// Load Ed25519 public key from 32 raw bytes. /// Matches Python: load_ed25519_public(data) static func loadPublic(_ data: Data) throws -> Curve25519.Signing.PublicKey { guard data.count == 32 else { throw CryptoError.invalidKeyData("Ed25519 public key must be 32 bytes, got \(data.count)") } return try Curve25519.Signing.PublicKey(rawRepresentation: data) } // MARK: - Sign / Verify /// Sign data with Ed25519. Returns 64-byte signature. /// Matches Python: ed25519_sign(private_key, data) static func sign(_ privateKey: Curve25519.Signing.PrivateKey, data: Data) throws -> Data { Data(try privateKey.signature(for: data)) } /// Verify Ed25519 signature. /// Matches Python: ed25519_verify(public_key, signature, data) static func verify(_ publicKey: Curve25519.Signing.PublicKey, signature: Data, data: Data) -> Bool { publicKey.isValidSignature(signature, for: data) } }