initial commit

This commit is contained in:
Filip
2026-03-11 16:06:00 +01:00
parent b3c69053f6
commit 5fd80e6dd6
127 changed files with 39684 additions and 0 deletions

View File

@@ -0,0 +1,73 @@
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)
}
}