// Copyright © 2023 Rangeproof Pty Ltd. All rights reserved. import Foundation import SessionUtil // MARK: - Randomness public extension Crypto.Generator { static func uuid() -> Crypto.Generator { return Crypto.Generator(id: "uuid") { UUID() } } static func randomBytes(_ count: Int) -> Crypto.Generator { return Crypto.Generator(id: "randomBytes_Data", args: [count]) { () -> Data in Data(bytes: session_random(count), count: count) } } static func randomBytes(_ count: Int) -> Crypto.Generator<[UInt8]> { return Crypto.Generator(id: "randomBytes_[UInt8]", args: [count]) { () -> [UInt8] in Array(Data(bytes: session_random(count), count: count)) } } } // MARK: - Hash public extension Crypto.Generator { static func hash(message: [UInt8], key: [UInt8]? = nil, length: Int = 32) -> Crypto.Generator<[UInt8]> { return Crypto.Generator(id: "hash", args: [message, key]) { var cMessage: [UInt8] = message var cHash: [UInt8] = [UInt8](repeating: 0, count: length) switch key { case .some(let finalKey): var cKey: [UInt8] = finalKey guard session_hash(length, &cMessage, cMessage.count, &cKey, cKey.count, &cHash) else { throw CryptoError.failedToGenerateOutput } case .none: guard session_hash(length, &cMessage, cMessage.count, nil, 0, &cHash) else { throw CryptoError.failedToGenerateOutput } } return cHash } } } // MARK: - curve25519 public extension Crypto.Generator { static func x25519KeyPair() -> Crypto.Generator { return Crypto.Generator(id: "x25519KeyPair") { () -> KeyPair in var pubkey: [UInt8] = [UInt8](repeating: 0, count: 32) var seckey: [UInt8] = [UInt8](repeating: 0, count: 32) guard session_curve25519_key_pair(&pubkey, &seckey) else { throw CryptoError.keyGenerationFailed } return KeyPair(publicKey: pubkey, secretKey: seckey) } } static func x25519( ed25519Pubkey: [UInt8] ) -> Crypto.Generator<[UInt8]> { return Crypto.Generator( id: "ed25519Pubkey_to_x25519Pubkey", args: [ed25519Pubkey] ) { var cEd25519Pubkey: [UInt8] = ed25519Pubkey var pubkey: [UInt8] = [UInt8](repeating: 0, count: 32) guard cEd25519Pubkey.count == 32, session_to_curve25519_pubkey(&cEd25519Pubkey, &pubkey) else { throw CryptoError.keyGenerationFailed } return pubkey } } static func x25519( ed25519Seckey: [UInt8] ) -> Crypto.Generator<[UInt8]> { return Crypto.Generator( id: "ed25519Seckey_to_x25519Seckey", args: [ed25519Seckey] ) { var cEd25519SecretKey: [UInt8] = ed25519Seckey var seckey: [UInt8] = [UInt8](repeating: 0, count: 32) guard cEd25519SecretKey.count == 64, session_to_curve25519_seckey(&cEd25519SecretKey, &seckey) else { throw CryptoError.keyGenerationFailed } return seckey } } } // MARK: - Ed25519 public extension Crypto.Generator { static func ed25519KeyPair() -> Crypto.Generator { return Crypto.Generator(id: "ed25519KeyPair") { var pubkey: [UInt8] = [UInt8](repeating: 0, count: 32) var seckey: [UInt8] = [UInt8](repeating: 0, count: 64) guard session_ed25519_key_pair(&pubkey, &seckey) else { throw CryptoError.keyGenerationFailed } return KeyPair(publicKey: pubkey, secretKey: seckey) } } static func ed25519KeyPair(seed: [UInt8]) -> Crypto.Generator { return Crypto.Generator(id: "ed25519KeyPair_Seed", args: [seed]) { var cSeed: [UInt8] = seed var pubkey: [UInt8] = [UInt8](repeating: 0, count: 32) var seckey: [UInt8] = [UInt8](repeating: 0, count: 64) guard cSeed.count == 32, session_ed25519_key_pair_seed(&cSeed, &pubkey, &seckey) else { throw CryptoError.invalidSeed } return KeyPair(publicKey: pubkey, secretKey: seckey) } } static func ed25519Seed(ed25519SecretKey: [UInt8]) -> Crypto.Generator { return Crypto.Generator(id: "ed25519Seed", args: [ed25519SecretKey]) { var cEd25519SecretKey: [UInt8] = ed25519SecretKey var seed: [UInt8] = [UInt8](repeating: 0, count: 32) guard cEd25519SecretKey.count == 64, session_seed_for_ed_privkey(&cEd25519SecretKey, &seed) else { throw CryptoError.invalidSeed } return Data(seed) } } static func signature(message: [UInt8], ed25519SecretKey: [UInt8]) -> Crypto.Generator<[UInt8]> { return Crypto.Generator(id: "signature", args: [message, ed25519SecretKey]) { var cEd25519SecretKey: [UInt8] = ed25519SecretKey var cMessage: [UInt8] = message var cSignature: [UInt8] = [UInt8](repeating: 0, count: 64) guard cEd25519SecretKey.count == 64, session_ed25519_sign(&cEd25519SecretKey, &cMessage, cMessage.count, &cSignature) else { throw CryptoError.signatureGenerationFailed } return cSignature } } } public extension Crypto.Verification { static func signature(message: [UInt8], publicKey: [UInt8], signature: [UInt8]) -> Crypto.Verification { return Crypto.Verification(id: "signature", args: [message, publicKey, signature]) { var cSignature: [UInt8] = signature var cPublicKey: [UInt8] = publicKey var cMessage: [UInt8] = message return session_ed25519_verify( &cSignature, &cPublicKey, &cMessage, cMessage.count ) } } } // MARK: - Xed25519 public extension Crypto.Generator { static func signatureXed25519(data: [UInt8], curve25519PrivateKey: [UInt8]) -> Crypto.Generator<[UInt8]> { return Crypto.Generator(id: "signatureXed25519", args: [data, curve25519PrivateKey]) { var cSignature: [UInt8] = [UInt8](repeating: 0, count: 64) var cCurve25519PrivateKey: [UInt8] = curve25519PrivateKey var cData: [UInt8] = data guard cCurve25519PrivateKey.count == 32, session_xed25519_sign( &cSignature, &cCurve25519PrivateKey, &cData, cData.count ) else { throw CryptoError.signatureGenerationFailed } return cSignature } } } public extension Crypto.Verification { static func signatureXed25519(_ signature: Data, curve25519PublicKey: [UInt8], data: Data) -> Crypto.Verification { return Crypto.Verification(id: "signatureXed25519", args: [signature, curve25519PublicKey, data]) { var cSignature: [UInt8] = Array(signature) var cCurve25519PublicKey: [UInt8] = curve25519PublicKey var cData: [UInt8] = Array(data) return session_xed25519_verify( &cSignature, &cCurve25519PublicKey, &cData, cData.count ) } } }