kyber-sdk-ios/Sources/KyberSDK/KyberKEM.swift
2026-05-06 22:28:00 +08:00

174 行
6.5 KiB
Swift

此文件含有模棱两可的 Unicode 字符

此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。

import Foundation
import CKyber
// MARK: - KyberKEM
/**
* Kyber KEMSwift
*
* ##
* CRYSTALS-KyberML-KEMNIST FIPS 203Module-LWE
* NIST 2024
* RSA / ECDH
*
* ## 使
* ```swift
* //
* let keyPair = try KyberKEM.generateKeyPair(variant: .kyber768)
*
* //
* let result = try KyberKEM.encapsulate(variant: .kyber768, publicKey: keyPair.publicKey)
* // result.ciphertext
* // result.sharedSecret 使 AES-GCM
*
* //
* let sharedSecret = try KyberKEM.decapsulate(
* variant: .kyber768,
* ciphertext: result.ciphertext,
* secretKey: keyPair.secretKey
* )
* // result.sharedSecret == sharedSecret
* ```
*
* ##
* - C `crypto_kem_keypair`
* `keypair_derand` `randombytes()`
*
* - 0 `sharedSecret`
* IND-CCA2
*
* ## 线
*
*/
public enum KyberKEM {
// MARK: -
/**
* Kyber
*
* 使 `arc4random_buf` 64 coinsiOS/macOS CSPRNG
* `keypair_derand`
*
* - Parameter variant: ``KyberVariant``
* - Returns: ``KyberKeyPair``
* - Throws: ``KyberError/keyGenerationFailed(code:)``
*/
public static func generateKeyPair(variant: KyberVariant) throws -> KyberKeyPair {
var pk = [UInt8](repeating: 0, count: variant.publicKeyBytes)
var sk = [UInt8](repeating: 0, count: variant.secretKeyBytes)
// 64 coins 32 IND-CPA 32 z
var coins = [UInt8](repeating: 0, count: 64)
randombytes(&coins, 64)
let ret: Int32
switch variant {
case .kyber512:
ret = pqcrystals_kyber512_ref_keypair_derand(&pk, &sk, coins)
case .kyber768:
ret = pqcrystals_kyber768_ref_keypair_derand(&pk, &sk, coins)
case .kyber1024:
ret = pqcrystals_kyber1024_ref_keypair_derand(&pk, &sk, coins)
}
guard ret == 0 else { throw KyberError.keyGenerationFailed(code: ret) }
return KyberKeyPair(publicKey: Data(pk), secretKey: Data(sk))
}
// MARK: -
/**
* 使
*
* 32 coins `enc_derand`
* `ciphertext`
* `sharedSecret`
*
* - Parameters:
* - variant: 使
* - publicKey:
* - Returns: ``KyberEncapsulationResult``
* - Throws: ``KyberError/invalidPublicKeySize(expected:got:)``
* ``KyberError/encapsulationFailed(code:)``
*/
public static func encapsulate(
variant: KyberVariant,
publicKey: Data
) throws -> KyberEncapsulationResult {
guard publicKey.count == variant.publicKeyBytes else {
throw KyberError.invalidPublicKeySize(
expected: variant.publicKeyBytes, got: publicKey.count)
}
var ct = [UInt8](repeating: 0, count: variant.ciphertextBytes)
var ss = [UInt8](repeating: 0, count: variant.sharedSecretBytes)
// 32 coins
var coins = [UInt8](repeating: 0, count: 32)
randombytes(&coins, 32)
let pk = Array(publicKey)
let ret: Int32
switch variant {
case .kyber512:
ret = pqcrystals_kyber512_ref_enc_derand(&ct, &ss, pk, coins)
case .kyber768:
ret = pqcrystals_kyber768_ref_enc_derand(&ct, &ss, pk, coins)
case .kyber1024:
ret = pqcrystals_kyber1024_ref_enc_derand(&ct, &ss, pk, coins)
}
guard ret == 0 else { throw KyberError.encapsulationFailed(code: ret) }
return KyberEncapsulationResult(ciphertext: Data(ct), sharedSecret: Data(ss))
}
// MARK: -
/**
* 使
*
* IND-CCA2
*
*
* - Parameters:
* - variant:
* - ciphertext:
* - secretKey:
* - Returns: 32
* - Throws: ``KyberError/invalidCiphertextSize(expected:got:)``
* ``KyberError/invalidSecretKeySize(expected:got:)``
* ``KyberError/decapsulationFailed(code:)``
*/
public static func decapsulate(
variant: KyberVariant,
ciphertext: Data,
secretKey: Data
) throws -> Data {
guard ciphertext.count == variant.ciphertextBytes else {
throw KyberError.invalidCiphertextSize(
expected: variant.ciphertextBytes, got: ciphertext.count)
}
guard secretKey.count == variant.secretKeyBytes else {
throw KyberError.invalidSecretKeySize(
expected: variant.secretKeyBytes, got: secretKey.count)
}
var ss = [UInt8](repeating: 0, count: variant.sharedSecretBytes)
let ct = Array(ciphertext)
let sk = Array(secretKey)
let ret: Int32
switch variant {
case .kyber512:
ret = pqcrystals_kyber512_ref_dec(&ss, ct, sk)
case .kyber768:
ret = pqcrystals_kyber768_ref_dec(&ss, ct, sk)
case .kyber1024:
ret = pqcrystals_kyber1024_ref_dec(&ss, ct, sk)
}
guard ret == 0 else { throw KyberError.decapsulationFailed(code: ret) }
return Data(ss)
}
}