74 lines
2.9 KiB
Swift
74 lines
2.9 KiB
Swift
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)
|
|
}
|
|
}
|