chore: release KyberSDK 1.0.0
这个提交包含在:
当前提交
a77fcc3a41
1
.sdk-version
普通文件
1
.sdk-version
普通文件
@ -0,0 +1 @@
|
||||
1.0.0
|
||||
61
Package.swift
普通文件
61
Package.swift
普通文件
@ -0,0 +1,61 @@
|
||||
// swift-tools-version: 5.9
|
||||
// KyberSDK — CRYSTALS-Kyber(ML-KEM)后量子密钥封装机制 Swift Package
|
||||
//
|
||||
// 包结构:
|
||||
// CKyber — C 实现层,单 target 内编译 Kyber512 / 768 / 1024 三种变体
|
||||
// KyberSDK — Swift 封装层,提供面向 Swift 的类型安全 API
|
||||
//
|
||||
// 多变体编译方案(".inc 翻译单元技巧"):
|
||||
// kyber512/768/1024.c 各为独立翻译单元,每个文件先 #define KYBER_K,
|
||||
// 再 #include internal/*.inc(原始 .c 文件的内容副本)。
|
||||
// 由此,KYBER_NAMESPACE 宏在三个翻译单元中分别展开为不同符号名,
|
||||
// 实现三种变体共存于同一静态库,链接器对公共符号(fips202)自动去重。
|
||||
//
|
||||
// 支持平台:iOS 14+ / macOS 11+
|
||||
// 支持架构:arm64(真机)/ arm64-simulator(Apple Silicon 模拟器)/ x86_64-simulator
|
||||
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "KyberSDK",
|
||||
platforms: [
|
||||
.iOS(.v14),
|
||||
.macOS(.v11),
|
||||
],
|
||||
products: [
|
||||
// 对外暴露 KyberSDK 库(包含 Swift 封装和 C 实现)
|
||||
.library(name: "KyberSDK", targets: ["KyberSDK"]),
|
||||
],
|
||||
targets: [
|
||||
// ── C 实现目标 ────────────────────────────────────────────────────
|
||||
// internal/ 目录中的 .inc 文件不直接编译(由 kyber512/768/1024.c 包含),
|
||||
// 需通过 exclude 将其排除出自动源码发现范围。
|
||||
.target(
|
||||
name: "CKyber",
|
||||
path: "Sources/CKyber",
|
||||
exclude: ["internal"], // .inc 文件不直接编译
|
||||
publicHeadersPath: "include", // 对外暴露的头文件目录
|
||||
cSettings: [
|
||||
.headerSearchPath("include"), // 使 #include "xxx.h" 能找到 include/ 中的头文件
|
||||
.headerSearchPath("."), // 使同级目录下的文件可相互引用
|
||||
.unsafeFlags(["-O2", "-fomit-frame-pointer"]), // 编译优化
|
||||
]
|
||||
),
|
||||
|
||||
// ── Swift 封装目标 ────────────────────────────────────────────────
|
||||
// 依赖 CKyber,通过 @_silgen_name / 直接调用 C 函数与底层交互
|
||||
.target(
|
||||
name: "KyberSDK",
|
||||
dependencies: ["CKyber"],
|
||||
path: "Sources/KyberSDK"
|
||||
),
|
||||
|
||||
// ── 单元测试目标 ─────────────────────────────────────────────────
|
||||
// 覆盖:三种变体 KEM 全流程、密钥尺寸验证、错误密钥测试、输入校验
|
||||
.testTarget(
|
||||
name: "KyberSDKTests",
|
||||
dependencies: ["KyberSDK"],
|
||||
path: "Tests/KyberSDKTests"
|
||||
),
|
||||
]
|
||||
)
|
||||
173
README.md
普通文件
173
README.md
普通文件
@ -0,0 +1,173 @@
|
||||
# KyberSDK — iOS / macOS Swift Package
|
||||
|
||||
基于 CRYSTALS-Kyber(ML-KEM,NIST FIPS 203)后量子密钥封装机制的 Swift Package,
|
||||
支持 iOS 14+ / macOS 11+ 及全平台架构(arm64 真机、arm64/x86_64 模拟器)。
|
||||
|
||||
---
|
||||
|
||||
## 环境要求
|
||||
|
||||
| 工具 | 最低版本 |
|
||||
|------|---------|
|
||||
| Xcode | 15.0 |
|
||||
| iOS | 14.0 |
|
||||
| macOS | 11.0 |
|
||||
| Swift | 5.9 |
|
||||
|
||||
---
|
||||
|
||||
## 支持的平台与架构
|
||||
|
||||
| 平台 | 架构 |
|
||||
|------|-----|
|
||||
| iOS 真机 | `arm64` |
|
||||
| iOS 模拟器(Intel Mac) | `x86_64` |
|
||||
| iOS 模拟器(Apple Silicon Mac) | `arm64` |
|
||||
| macOS | `arm64`、`x86_64` |
|
||||
|
||||
---
|
||||
|
||||
## 集成方法
|
||||
|
||||
### 方式一:本地 Swift Package(推荐开发阶段)
|
||||
|
||||
1. 在 Xcode 中选择 **File → Add Package Dependencies → Add Local…**
|
||||
2. 选择本仓库中的 `ios/` 目录(包含 `Package.swift`)
|
||||
3. 在弹出框中勾选 **KyberSDK**,选择目标 Target,点击 Add Package
|
||||
|
||||
### 方式二:SPM 依赖声明
|
||||
|
||||
```swift
|
||||
// Package.swift
|
||||
.package(path: "../ios"), // 本地路径
|
||||
// 或使用远程 URL:
|
||||
// .package(url: "https://your-repo/KyberSDK", from: "1.0.0"),
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## API 使用示例
|
||||
|
||||
```swift
|
||||
import KyberSDK
|
||||
|
||||
// ── 接收方:生成密钥对 ────────────────────────────────────────────────
|
||||
let keyPair = try KyberKEM.generateKeyPair(variant: .kyber768)
|
||||
// keyPair.publicKey → 可公开分发(Data)
|
||||
// keyPair.secretKey → 安全存储,建议存入 iOS Keychain
|
||||
|
||||
// ── 发送方:封装共享密钥 ──────────────────────────────────────────────
|
||||
let result = try KyberKEM.encapsulate(variant: .kyber768, publicKey: keyPair.publicKey)
|
||||
// result.ciphertext → 传输给接收方(Data)
|
||||
// result.sharedSecret → 本地保留,用于对称加密(AES-GCM、ChaCha20-Poly1305)
|
||||
|
||||
// ── 接收方:解封装恢复共享密钥 ───────────────────────────────────────
|
||||
let sharedSecret = try KyberKEM.decapsulate(
|
||||
variant: .kyber768,
|
||||
ciphertext: result.ciphertext,
|
||||
secretKey: keyPair.secretKey
|
||||
)
|
||||
// result.sharedSecret == sharedSecret ✓(密文合法时)
|
||||
```
|
||||
|
||||
> **注意**:所有方法均为同步调用,建议在后台队列执行:
|
||||
> ```swift
|
||||
> let kp = try await Task.detached(priority: .userInitiated) {
|
||||
> try KyberKEM.generateKeyPair(variant: .kyber768)
|
||||
> }.value
|
||||
> ```
|
||||
|
||||
---
|
||||
|
||||
## 支持的安全级别
|
||||
|
||||
| 枚举值 | KYBER_K | NIST 级别 | 经典安全性 | 公钥 | 私钥 | 密文 |
|
||||
|--------|---------|----------|----------|-----|-----|-----|
|
||||
| `.kyber512` | 2 | Level 1 | ~AES-128 | 800 B | 1632 B | 768 B |
|
||||
| `.kyber768` | 3 | Level 3 | ~AES-192 | 1184 B | 2400 B | 1088 B |
|
||||
| `.kyber1024` | 4 | Level 5 | ~AES-256 | 1568 B | 3168 B | 1568 B |
|
||||
|
||||
共享密钥固定为 **32 字节**(三种变体相同)。
|
||||
|
||||
---
|
||||
|
||||
## 运行测试
|
||||
|
||||
```bash
|
||||
cd ios
|
||||
swift test
|
||||
# 预期输出:11 项测试全部通过
|
||||
```
|
||||
|
||||
测试覆盖:
|
||||
|
||||
| 测试名称 | 说明 |
|
||||
|---------|------|
|
||||
| `testKyber512/768/1024KeySizes` | 密钥尺寸符合规范 |
|
||||
| `testKyber512/768/1024RoundTrip` | 完整 KEM 流程,共享密钥必须一致 |
|
||||
| `testKyber512WrongKey` | 错误私钥不能恢复正确共享密钥(IND-CCA2) |
|
||||
| `testInvalidPublicKeySize` | 公钥长度不符时抛出错误 |
|
||||
| `testInvalidSecretKeySize` | 私钥长度不符时抛出错误 |
|
||||
| `testInvalidCiphertextSize` | 密文长度不符时抛出错误 |
|
||||
| `testKyber768Performance` | 密钥生成性能基线 |
|
||||
|
||||
---
|
||||
|
||||
## 包结构详解
|
||||
|
||||
```
|
||||
ios/
|
||||
├── Package.swift # SPM 包描述(iOS 14+ / macOS 11+)
|
||||
├── Sources/
|
||||
│ ├── CKyber/ # C 实现层(单 target 包含三种变体)
|
||||
│ │ ├── include/ # 对外暴露的头文件
|
||||
│ │ │ ├── kyber_sdk.h # 伞头文件(包含 api.h 及 randombytes 声明)
|
||||
│ │ │ ├── api.h # 三种变体函数声明
|
||||
│ │ │ └── ...(其余内部头文件)
|
||||
│ │ ├── internal/ # .inc 文件(不直接编译,由变体 .c 文件 #include)
|
||||
│ │ │ ├── kem.inc # kem.c 内容副本
|
||||
│ │ │ ├── indcpa.inc # indcpa.c 内容副本
|
||||
│ │ │ └── ...(poly / ntt / cbd / reduce / verify / symmetric_shake)
|
||||
│ │ ├── kyber512.c # 翻译单元:#define KYBER_K 2
|
||||
│ │ ├── kyber768.c # 翻译单元:#define KYBER_K 3
|
||||
│ │ ├── kyber1024.c # 翻译单元:#define KYBER_K 4
|
||||
│ │ ├── fips202.c # SHA3/SHAKE(与 KYBER_K 无关,编译一次)
|
||||
│ │ └── randombytes_ios.c # arc4random_buf 包装
|
||||
│ └── KyberSDK/ # Swift 封装层
|
||||
│ ├── KyberTypes.swift # KyberVariant / KyberKeyPair / KyberError
|
||||
│ └── KyberKEM.swift # 主 API:generateKeyPair / encapsulate / decapsulate
|
||||
├── Tests/
|
||||
│ └── KyberSDKTests/
|
||||
│ └── KyberSDKTests.swift # 11 项单元测试
|
||||
└── KyberDemo/ # SwiftUI 演示 App 源文件
|
||||
├── KyberDemoApp.swift
|
||||
├── ContentView.swift
|
||||
└── README.md # Demo 集成说明
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 多变体编译原理(.inc 翻译单元技巧)
|
||||
|
||||
Kyber C 实现通过编译时常量 `KYBER_K` 区分变体,同一源文件在不同 `KYBER_K` 下产生不同符号名。
|
||||
为在单一 SPM target 中同时支持三种变体:
|
||||
|
||||
1. 将所有变体相关的 `.c` 文件重命名为 `.inc`(放在 `internal/`),SPM 不直接编译它们。
|
||||
2. 创建三个"驱动"翻译单元(`kyber512/768/1024.c`),各自先 `#define KYBER_K`,再 `#include` 所有 `.inc` 文件。
|
||||
3. `fips202.c` 与 KYBER_K 无关,单独编译一次;链接器对三份对象文件中的相同符号自动去重。
|
||||
|
||||
```
|
||||
kyber512.c (#define KYBER_K 2) → pqcrystals_kyber512_ref_keypair 等
|
||||
kyber768.c (#define KYBER_K 3) → pqcrystals_kyber768_ref_keypair 等
|
||||
kyber1024.c (#define KYBER_K 4) → pqcrystals_kyber1024_ref_keypair 等
|
||||
fips202.c → pqcrystals_kyber_fips202_ref_* (共享,去重)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 安全注意事项
|
||||
|
||||
1. **私钥存储**:私钥应存入 iOS Keychain(`kSecClassKey`),不应明文持久化。
|
||||
2. **共享密钥用途**:建议通过 HKDF 从共享密钥派生实际加密/认证密钥。
|
||||
3. **密文完整性**:解封装不抛出错误不代表密文合法(IND-CCA2 特性),
|
||||
应通过上层协议(TLS / AEAD)保证完整性。
|
||||
774
Sources/CKyber/fips202.c
普通文件
774
Sources/CKyber/fips202.c
普通文件
@ -0,0 +1,774 @@
|
||||
/* Based on the public domain implementation in crypto_hash/keccakc512/simple/ from
|
||||
* http://bench.cr.yp.to/supercop.html by Ronny Van Keer and the public domain "TweetFips202"
|
||||
* implementation from https://twitter.com/tweetfips202 by Gilles Van Assche, Daniel J. Bernstein,
|
||||
* and Peter Schwabe */
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "fips202.h"
|
||||
|
||||
#define NROUNDS 24
|
||||
#define ROL(a, offset) ((a << offset) ^ (a >> (64-offset)))
|
||||
|
||||
/*************************************************
|
||||
* Name: load64
|
||||
*
|
||||
* Description: Load 8 bytes into uint64_t in little-endian order
|
||||
*
|
||||
* Arguments: - const uint8_t *x: pointer to input byte array
|
||||
*
|
||||
* Returns the loaded 64-bit unsigned integer
|
||||
**************************************************/
|
||||
static uint64_t load64(const uint8_t x[8]) {
|
||||
unsigned int i;
|
||||
uint64_t r = 0;
|
||||
|
||||
for(i=0;i<8;i++)
|
||||
r |= (uint64_t)x[i] << 8*i;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: store64
|
||||
*
|
||||
* Description: Store a 64-bit integer to array of 8 bytes in little-endian order
|
||||
*
|
||||
* Arguments: - uint8_t *x: pointer to the output byte array (allocated)
|
||||
* - uint64_t u: input 64-bit unsigned integer
|
||||
**************************************************/
|
||||
static void store64(uint8_t x[8], uint64_t u) {
|
||||
unsigned int i;
|
||||
|
||||
for(i=0;i<8;i++)
|
||||
x[i] = u >> 8*i;
|
||||
}
|
||||
|
||||
/* Keccak round constants */
|
||||
static const uint64_t KeccakF_RoundConstants[NROUNDS] = {
|
||||
(uint64_t)0x0000000000000001ULL,
|
||||
(uint64_t)0x0000000000008082ULL,
|
||||
(uint64_t)0x800000000000808aULL,
|
||||
(uint64_t)0x8000000080008000ULL,
|
||||
(uint64_t)0x000000000000808bULL,
|
||||
(uint64_t)0x0000000080000001ULL,
|
||||
(uint64_t)0x8000000080008081ULL,
|
||||
(uint64_t)0x8000000000008009ULL,
|
||||
(uint64_t)0x000000000000008aULL,
|
||||
(uint64_t)0x0000000000000088ULL,
|
||||
(uint64_t)0x0000000080008009ULL,
|
||||
(uint64_t)0x000000008000000aULL,
|
||||
(uint64_t)0x000000008000808bULL,
|
||||
(uint64_t)0x800000000000008bULL,
|
||||
(uint64_t)0x8000000000008089ULL,
|
||||
(uint64_t)0x8000000000008003ULL,
|
||||
(uint64_t)0x8000000000008002ULL,
|
||||
(uint64_t)0x8000000000000080ULL,
|
||||
(uint64_t)0x000000000000800aULL,
|
||||
(uint64_t)0x800000008000000aULL,
|
||||
(uint64_t)0x8000000080008081ULL,
|
||||
(uint64_t)0x8000000000008080ULL,
|
||||
(uint64_t)0x0000000080000001ULL,
|
||||
(uint64_t)0x8000000080008008ULL
|
||||
};
|
||||
|
||||
/*************************************************
|
||||
* Name: KeccakF1600_StatePermute
|
||||
*
|
||||
* Description: The Keccak F1600 Permutation
|
||||
*
|
||||
* Arguments: - uint64_t *state: pointer to input/output Keccak state
|
||||
**************************************************/
|
||||
static void KeccakF1600_StatePermute(uint64_t state[25])
|
||||
{
|
||||
int round;
|
||||
|
||||
uint64_t Aba, Abe, Abi, Abo, Abu;
|
||||
uint64_t Aga, Age, Agi, Ago, Agu;
|
||||
uint64_t Aka, Ake, Aki, Ako, Aku;
|
||||
uint64_t Ama, Ame, Ami, Amo, Amu;
|
||||
uint64_t Asa, Ase, Asi, Aso, Asu;
|
||||
uint64_t BCa, BCe, BCi, BCo, BCu;
|
||||
uint64_t Da, De, Di, Do, Du;
|
||||
uint64_t Eba, Ebe, Ebi, Ebo, Ebu;
|
||||
uint64_t Ega, Ege, Egi, Ego, Egu;
|
||||
uint64_t Eka, Eke, Eki, Eko, Eku;
|
||||
uint64_t Ema, Eme, Emi, Emo, Emu;
|
||||
uint64_t Esa, Ese, Esi, Eso, Esu;
|
||||
|
||||
//copyFromState(A, state)
|
||||
Aba = state[ 0];
|
||||
Abe = state[ 1];
|
||||
Abi = state[ 2];
|
||||
Abo = state[ 3];
|
||||
Abu = state[ 4];
|
||||
Aga = state[ 5];
|
||||
Age = state[ 6];
|
||||
Agi = state[ 7];
|
||||
Ago = state[ 8];
|
||||
Agu = state[ 9];
|
||||
Aka = state[10];
|
||||
Ake = state[11];
|
||||
Aki = state[12];
|
||||
Ako = state[13];
|
||||
Aku = state[14];
|
||||
Ama = state[15];
|
||||
Ame = state[16];
|
||||
Ami = state[17];
|
||||
Amo = state[18];
|
||||
Amu = state[19];
|
||||
Asa = state[20];
|
||||
Ase = state[21];
|
||||
Asi = state[22];
|
||||
Aso = state[23];
|
||||
Asu = state[24];
|
||||
|
||||
for(round = 0; round < NROUNDS; round += 2) {
|
||||
// prepareTheta
|
||||
BCa = Aba^Aga^Aka^Ama^Asa;
|
||||
BCe = Abe^Age^Ake^Ame^Ase;
|
||||
BCi = Abi^Agi^Aki^Ami^Asi;
|
||||
BCo = Abo^Ago^Ako^Amo^Aso;
|
||||
BCu = Abu^Agu^Aku^Amu^Asu;
|
||||
|
||||
//thetaRhoPiChiIotaPrepareTheta(round, A, E)
|
||||
Da = BCu^ROL(BCe, 1);
|
||||
De = BCa^ROL(BCi, 1);
|
||||
Di = BCe^ROL(BCo, 1);
|
||||
Do = BCi^ROL(BCu, 1);
|
||||
Du = BCo^ROL(BCa, 1);
|
||||
|
||||
Aba ^= Da;
|
||||
BCa = Aba;
|
||||
Age ^= De;
|
||||
BCe = ROL(Age, 44);
|
||||
Aki ^= Di;
|
||||
BCi = ROL(Aki, 43);
|
||||
Amo ^= Do;
|
||||
BCo = ROL(Amo, 21);
|
||||
Asu ^= Du;
|
||||
BCu = ROL(Asu, 14);
|
||||
Eba = BCa ^((~BCe)& BCi );
|
||||
Eba ^= (uint64_t)KeccakF_RoundConstants[round];
|
||||
Ebe = BCe ^((~BCi)& BCo );
|
||||
Ebi = BCi ^((~BCo)& BCu );
|
||||
Ebo = BCo ^((~BCu)& BCa );
|
||||
Ebu = BCu ^((~BCa)& BCe );
|
||||
|
||||
Abo ^= Do;
|
||||
BCa = ROL(Abo, 28);
|
||||
Agu ^= Du;
|
||||
BCe = ROL(Agu, 20);
|
||||
Aka ^= Da;
|
||||
BCi = ROL(Aka, 3);
|
||||
Ame ^= De;
|
||||
BCo = ROL(Ame, 45);
|
||||
Asi ^= Di;
|
||||
BCu = ROL(Asi, 61);
|
||||
Ega = BCa ^((~BCe)& BCi );
|
||||
Ege = BCe ^((~BCi)& BCo );
|
||||
Egi = BCi ^((~BCo)& BCu );
|
||||
Ego = BCo ^((~BCu)& BCa );
|
||||
Egu = BCu ^((~BCa)& BCe );
|
||||
|
||||
Abe ^= De;
|
||||
BCa = ROL(Abe, 1);
|
||||
Agi ^= Di;
|
||||
BCe = ROL(Agi, 6);
|
||||
Ako ^= Do;
|
||||
BCi = ROL(Ako, 25);
|
||||
Amu ^= Du;
|
||||
BCo = ROL(Amu, 8);
|
||||
Asa ^= Da;
|
||||
BCu = ROL(Asa, 18);
|
||||
Eka = BCa ^((~BCe)& BCi );
|
||||
Eke = BCe ^((~BCi)& BCo );
|
||||
Eki = BCi ^((~BCo)& BCu );
|
||||
Eko = BCo ^((~BCu)& BCa );
|
||||
Eku = BCu ^((~BCa)& BCe );
|
||||
|
||||
Abu ^= Du;
|
||||
BCa = ROL(Abu, 27);
|
||||
Aga ^= Da;
|
||||
BCe = ROL(Aga, 36);
|
||||
Ake ^= De;
|
||||
BCi = ROL(Ake, 10);
|
||||
Ami ^= Di;
|
||||
BCo = ROL(Ami, 15);
|
||||
Aso ^= Do;
|
||||
BCu = ROL(Aso, 56);
|
||||
Ema = BCa ^((~BCe)& BCi );
|
||||
Eme = BCe ^((~BCi)& BCo );
|
||||
Emi = BCi ^((~BCo)& BCu );
|
||||
Emo = BCo ^((~BCu)& BCa );
|
||||
Emu = BCu ^((~BCa)& BCe );
|
||||
|
||||
Abi ^= Di;
|
||||
BCa = ROL(Abi, 62);
|
||||
Ago ^= Do;
|
||||
BCe = ROL(Ago, 55);
|
||||
Aku ^= Du;
|
||||
BCi = ROL(Aku, 39);
|
||||
Ama ^= Da;
|
||||
BCo = ROL(Ama, 41);
|
||||
Ase ^= De;
|
||||
BCu = ROL(Ase, 2);
|
||||
Esa = BCa ^((~BCe)& BCi );
|
||||
Ese = BCe ^((~BCi)& BCo );
|
||||
Esi = BCi ^((~BCo)& BCu );
|
||||
Eso = BCo ^((~BCu)& BCa );
|
||||
Esu = BCu ^((~BCa)& BCe );
|
||||
|
||||
// prepareTheta
|
||||
BCa = Eba^Ega^Eka^Ema^Esa;
|
||||
BCe = Ebe^Ege^Eke^Eme^Ese;
|
||||
BCi = Ebi^Egi^Eki^Emi^Esi;
|
||||
BCo = Ebo^Ego^Eko^Emo^Eso;
|
||||
BCu = Ebu^Egu^Eku^Emu^Esu;
|
||||
|
||||
//thetaRhoPiChiIotaPrepareTheta(round+1, E, A)
|
||||
Da = BCu^ROL(BCe, 1);
|
||||
De = BCa^ROL(BCi, 1);
|
||||
Di = BCe^ROL(BCo, 1);
|
||||
Do = BCi^ROL(BCu, 1);
|
||||
Du = BCo^ROL(BCa, 1);
|
||||
|
||||
Eba ^= Da;
|
||||
BCa = Eba;
|
||||
Ege ^= De;
|
||||
BCe = ROL(Ege, 44);
|
||||
Eki ^= Di;
|
||||
BCi = ROL(Eki, 43);
|
||||
Emo ^= Do;
|
||||
BCo = ROL(Emo, 21);
|
||||
Esu ^= Du;
|
||||
BCu = ROL(Esu, 14);
|
||||
Aba = BCa ^((~BCe)& BCi );
|
||||
Aba ^= (uint64_t)KeccakF_RoundConstants[round+1];
|
||||
Abe = BCe ^((~BCi)& BCo );
|
||||
Abi = BCi ^((~BCo)& BCu );
|
||||
Abo = BCo ^((~BCu)& BCa );
|
||||
Abu = BCu ^((~BCa)& BCe );
|
||||
|
||||
Ebo ^= Do;
|
||||
BCa = ROL(Ebo, 28);
|
||||
Egu ^= Du;
|
||||
BCe = ROL(Egu, 20);
|
||||
Eka ^= Da;
|
||||
BCi = ROL(Eka, 3);
|
||||
Eme ^= De;
|
||||
BCo = ROL(Eme, 45);
|
||||
Esi ^= Di;
|
||||
BCu = ROL(Esi, 61);
|
||||
Aga = BCa ^((~BCe)& BCi );
|
||||
Age = BCe ^((~BCi)& BCo );
|
||||
Agi = BCi ^((~BCo)& BCu );
|
||||
Ago = BCo ^((~BCu)& BCa );
|
||||
Agu = BCu ^((~BCa)& BCe );
|
||||
|
||||
Ebe ^= De;
|
||||
BCa = ROL(Ebe, 1);
|
||||
Egi ^= Di;
|
||||
BCe = ROL(Egi, 6);
|
||||
Eko ^= Do;
|
||||
BCi = ROL(Eko, 25);
|
||||
Emu ^= Du;
|
||||
BCo = ROL(Emu, 8);
|
||||
Esa ^= Da;
|
||||
BCu = ROL(Esa, 18);
|
||||
Aka = BCa ^((~BCe)& BCi );
|
||||
Ake = BCe ^((~BCi)& BCo );
|
||||
Aki = BCi ^((~BCo)& BCu );
|
||||
Ako = BCo ^((~BCu)& BCa );
|
||||
Aku = BCu ^((~BCa)& BCe );
|
||||
|
||||
Ebu ^= Du;
|
||||
BCa = ROL(Ebu, 27);
|
||||
Ega ^= Da;
|
||||
BCe = ROL(Ega, 36);
|
||||
Eke ^= De;
|
||||
BCi = ROL(Eke, 10);
|
||||
Emi ^= Di;
|
||||
BCo = ROL(Emi, 15);
|
||||
Eso ^= Do;
|
||||
BCu = ROL(Eso, 56);
|
||||
Ama = BCa ^((~BCe)& BCi );
|
||||
Ame = BCe ^((~BCi)& BCo );
|
||||
Ami = BCi ^((~BCo)& BCu );
|
||||
Amo = BCo ^((~BCu)& BCa );
|
||||
Amu = BCu ^((~BCa)& BCe );
|
||||
|
||||
Ebi ^= Di;
|
||||
BCa = ROL(Ebi, 62);
|
||||
Ego ^= Do;
|
||||
BCe = ROL(Ego, 55);
|
||||
Eku ^= Du;
|
||||
BCi = ROL(Eku, 39);
|
||||
Ema ^= Da;
|
||||
BCo = ROL(Ema, 41);
|
||||
Ese ^= De;
|
||||
BCu = ROL(Ese, 2);
|
||||
Asa = BCa ^((~BCe)& BCi );
|
||||
Ase = BCe ^((~BCi)& BCo );
|
||||
Asi = BCi ^((~BCo)& BCu );
|
||||
Aso = BCo ^((~BCu)& BCa );
|
||||
Asu = BCu ^((~BCa)& BCe );
|
||||
}
|
||||
|
||||
//copyToState(state, A)
|
||||
state[ 0] = Aba;
|
||||
state[ 1] = Abe;
|
||||
state[ 2] = Abi;
|
||||
state[ 3] = Abo;
|
||||
state[ 4] = Abu;
|
||||
state[ 5] = Aga;
|
||||
state[ 6] = Age;
|
||||
state[ 7] = Agi;
|
||||
state[ 8] = Ago;
|
||||
state[ 9] = Agu;
|
||||
state[10] = Aka;
|
||||
state[11] = Ake;
|
||||
state[12] = Aki;
|
||||
state[13] = Ako;
|
||||
state[14] = Aku;
|
||||
state[15] = Ama;
|
||||
state[16] = Ame;
|
||||
state[17] = Ami;
|
||||
state[18] = Amo;
|
||||
state[19] = Amu;
|
||||
state[20] = Asa;
|
||||
state[21] = Ase;
|
||||
state[22] = Asi;
|
||||
state[23] = Aso;
|
||||
state[24] = Asu;
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: keccak_init
|
||||
*
|
||||
* Description: Initializes the Keccak state.
|
||||
*
|
||||
* Arguments: - uint64_t *s: pointer to Keccak state
|
||||
**************************************************/
|
||||
static void keccak_init(uint64_t s[25])
|
||||
{
|
||||
unsigned int i;
|
||||
for(i=0;i<25;i++)
|
||||
s[i] = 0;
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: keccak_absorb
|
||||
*
|
||||
* Description: Absorb step of Keccak; incremental.
|
||||
*
|
||||
* Arguments: - uint64_t *s: pointer to Keccak state
|
||||
* - unsigned int pos: position in current block to be absorbed
|
||||
* - unsigned int r: rate in bytes (e.g., 168 for SHAKE128)
|
||||
* - const uint8_t *in: pointer to input to be absorbed into s
|
||||
* - size_t inlen: length of input in bytes
|
||||
*
|
||||
* Returns new position pos in current block
|
||||
**************************************************/
|
||||
static unsigned int keccak_absorb(uint64_t s[25],
|
||||
unsigned int pos,
|
||||
unsigned int r,
|
||||
const uint8_t *in,
|
||||
size_t inlen)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
while(pos+inlen >= r) {
|
||||
for(i=pos;i<r;i++)
|
||||
s[i/8] ^= (uint64_t)*in++ << 8*(i%8);
|
||||
inlen -= r-pos;
|
||||
KeccakF1600_StatePermute(s);
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
for(i=pos;i<pos+inlen;i++)
|
||||
s[i/8] ^= (uint64_t)*in++ << 8*(i%8);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: keccak_finalize
|
||||
*
|
||||
* Description: Finalize absorb step.
|
||||
*
|
||||
* Arguments: - uint64_t *s: pointer to Keccak state
|
||||
* - unsigned int pos: position in current block to be absorbed
|
||||
* - unsigned int r: rate in bytes (e.g., 168 for SHAKE128)
|
||||
* - uint8_t p: domain separation byte
|
||||
**************************************************/
|
||||
static void keccak_finalize(uint64_t s[25], unsigned int pos, unsigned int r, uint8_t p)
|
||||
{
|
||||
s[pos/8] ^= (uint64_t)p << 8*(pos%8);
|
||||
s[r/8-1] ^= 1ULL << 63;
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: keccak_squeeze
|
||||
*
|
||||
* Description: Squeeze step of Keccak. Squeezes arbitratrily many bytes.
|
||||
* Modifies the state. Can be called multiple times to keep
|
||||
* squeezing, i.e., is incremental.
|
||||
*
|
||||
* Arguments: - uint8_t *out: pointer to output
|
||||
* - size_t outlen: number of bytes to be squeezed (written to out)
|
||||
* - uint64_t *s: pointer to input/output Keccak state
|
||||
* - unsigned int pos: number of bytes in current block already squeezed
|
||||
* - unsigned int r: rate in bytes (e.g., 168 for SHAKE128)
|
||||
*
|
||||
* Returns new position pos in current block
|
||||
**************************************************/
|
||||
static unsigned int keccak_squeeze(uint8_t *out,
|
||||
size_t outlen,
|
||||
uint64_t s[25],
|
||||
unsigned int pos,
|
||||
unsigned int r)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
while(outlen) {
|
||||
if(pos == r) {
|
||||
KeccakF1600_StatePermute(s);
|
||||
pos = 0;
|
||||
}
|
||||
for(i=pos;i < r && i < pos+outlen; i++)
|
||||
*out++ = s[i/8] >> 8*(i%8);
|
||||
outlen -= i-pos;
|
||||
pos = i;
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Name: keccak_absorb_once
|
||||
*
|
||||
* Description: Absorb step of Keccak;
|
||||
* non-incremental, starts by zeroeing the state.
|
||||
*
|
||||
* Arguments: - uint64_t *s: pointer to (uninitialized) output Keccak state
|
||||
* - unsigned int r: rate in bytes (e.g., 168 for SHAKE128)
|
||||
* - const uint8_t *in: pointer to input to be absorbed into s
|
||||
* - size_t inlen: length of input in bytes
|
||||
* - uint8_t p: domain-separation byte for different Keccak-derived functions
|
||||
**************************************************/
|
||||
static void keccak_absorb_once(uint64_t s[25],
|
||||
unsigned int r,
|
||||
const uint8_t *in,
|
||||
size_t inlen,
|
||||
uint8_t p)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for(i=0;i<25;i++)
|
||||
s[i] = 0;
|
||||
|
||||
while(inlen >= r) {
|
||||
for(i=0;i<r/8;i++)
|
||||
s[i] ^= load64(in+8*i);
|
||||
in += r;
|
||||
inlen -= r;
|
||||
KeccakF1600_StatePermute(s);
|
||||
}
|
||||
|
||||
for(i=0;i<inlen;i++)
|
||||
s[i/8] ^= (uint64_t)in[i] << 8*(i%8);
|
||||
|
||||
s[i/8] ^= (uint64_t)p << 8*(i%8);
|
||||
s[(r-1)/8] ^= 1ULL << 63;
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: keccak_squeezeblocks
|
||||
*
|
||||
* Description: Squeeze step of Keccak. Squeezes full blocks of r bytes each.
|
||||
* Modifies the state. Can be called multiple times to keep
|
||||
* squeezing, i.e., is incremental. Assumes zero bytes of current
|
||||
* block have already been squeezed.
|
||||
*
|
||||
* Arguments: - uint8_t *out: pointer to output blocks
|
||||
* - size_t nblocks: number of blocks to be squeezed (written to out)
|
||||
* - uint64_t *s: pointer to input/output Keccak state
|
||||
* - unsigned int r: rate in bytes (e.g., 168 for SHAKE128)
|
||||
**************************************************/
|
||||
static void keccak_squeezeblocks(uint8_t *out,
|
||||
size_t nblocks,
|
||||
uint64_t s[25],
|
||||
unsigned int r)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
while(nblocks) {
|
||||
KeccakF1600_StatePermute(s);
|
||||
for(i=0;i<r/8;i++)
|
||||
store64(out+8*i, s[i]);
|
||||
out += r;
|
||||
nblocks -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: shake128_init
|
||||
*
|
||||
* Description: Initilizes Keccak state for use as SHAKE128 XOF
|
||||
*
|
||||
* Arguments: - keccak_state *state: pointer to (uninitialized) Keccak state
|
||||
**************************************************/
|
||||
void shake128_init(keccak_state *state)
|
||||
{
|
||||
keccak_init(state->s);
|
||||
state->pos = 0;
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: shake128_absorb
|
||||
*
|
||||
* Description: Absorb step of the SHAKE128 XOF; incremental.
|
||||
*
|
||||
* Arguments: - keccak_state *state: pointer to (initialized) output Keccak state
|
||||
* - const uint8_t *in: pointer to input to be absorbed into s
|
||||
* - size_t inlen: length of input in bytes
|
||||
**************************************************/
|
||||
void shake128_absorb(keccak_state *state, const uint8_t *in, size_t inlen)
|
||||
{
|
||||
state->pos = keccak_absorb(state->s, state->pos, SHAKE128_RATE, in, inlen);
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: shake128_finalize
|
||||
*
|
||||
* Description: Finalize absorb step of the SHAKE128 XOF.
|
||||
*
|
||||
* Arguments: - keccak_state *state: pointer to Keccak state
|
||||
**************************************************/
|
||||
void shake128_finalize(keccak_state *state)
|
||||
{
|
||||
keccak_finalize(state->s, state->pos, SHAKE128_RATE, 0x1F);
|
||||
state->pos = SHAKE128_RATE;
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: shake128_squeeze
|
||||
*
|
||||
* Description: Squeeze step of SHAKE128 XOF. Squeezes arbitraily many
|
||||
* bytes. Can be called multiple times to keep squeezing.
|
||||
*
|
||||
* Arguments: - uint8_t *out: pointer to output blocks
|
||||
* - size_t outlen : number of bytes to be squeezed (written to output)
|
||||
* - keccak_state *s: pointer to input/output Keccak state
|
||||
**************************************************/
|
||||
void shake128_squeeze(uint8_t *out, size_t outlen, keccak_state *state)
|
||||
{
|
||||
state->pos = keccak_squeeze(out, outlen, state->s, state->pos, SHAKE128_RATE);
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: shake128_absorb_once
|
||||
*
|
||||
* Description: Initialize, absorb into and finalize SHAKE128 XOF; non-incremental.
|
||||
*
|
||||
* Arguments: - keccak_state *state: pointer to (uninitialized) output Keccak state
|
||||
* - const uint8_t *in: pointer to input to be absorbed into s
|
||||
* - size_t inlen: length of input in bytes
|
||||
**************************************************/
|
||||
void shake128_absorb_once(keccak_state *state, const uint8_t *in, size_t inlen)
|
||||
{
|
||||
keccak_absorb_once(state->s, SHAKE128_RATE, in, inlen, 0x1F);
|
||||
state->pos = SHAKE128_RATE;
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: shake128_squeezeblocks
|
||||
*
|
||||
* Description: Squeeze step of SHAKE128 XOF. Squeezes full blocks of
|
||||
* SHAKE128_RATE bytes each. Can be called multiple times
|
||||
* to keep squeezing. Assumes new block has not yet been
|
||||
* started (state->pos = SHAKE128_RATE).
|
||||
*
|
||||
* Arguments: - uint8_t *out: pointer to output blocks
|
||||
* - size_t nblocks: number of blocks to be squeezed (written to output)
|
||||
* - keccak_state *s: pointer to input/output Keccak state
|
||||
**************************************************/
|
||||
void shake128_squeezeblocks(uint8_t *out, size_t nblocks, keccak_state *state)
|
||||
{
|
||||
keccak_squeezeblocks(out, nblocks, state->s, SHAKE128_RATE);
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: shake256_init
|
||||
*
|
||||
* Description: Initilizes Keccak state for use as SHAKE256 XOF
|
||||
*
|
||||
* Arguments: - keccak_state *state: pointer to (uninitialized) Keccak state
|
||||
**************************************************/
|
||||
void shake256_init(keccak_state *state)
|
||||
{
|
||||
keccak_init(state->s);
|
||||
state->pos = 0;
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: shake256_absorb
|
||||
*
|
||||
* Description: Absorb step of the SHAKE256 XOF; incremental.
|
||||
*
|
||||
* Arguments: - keccak_state *state: pointer to (initialized) output Keccak state
|
||||
* - const uint8_t *in: pointer to input to be absorbed into s
|
||||
* - size_t inlen: length of input in bytes
|
||||
**************************************************/
|
||||
void shake256_absorb(keccak_state *state, const uint8_t *in, size_t inlen)
|
||||
{
|
||||
state->pos = keccak_absorb(state->s, state->pos, SHAKE256_RATE, in, inlen);
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: shake256_finalize
|
||||
*
|
||||
* Description: Finalize absorb step of the SHAKE256 XOF.
|
||||
*
|
||||
* Arguments: - keccak_state *state: pointer to Keccak state
|
||||
**************************************************/
|
||||
void shake256_finalize(keccak_state *state)
|
||||
{
|
||||
keccak_finalize(state->s, state->pos, SHAKE256_RATE, 0x1F);
|
||||
state->pos = SHAKE256_RATE;
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: shake256_squeeze
|
||||
*
|
||||
* Description: Squeeze step of SHAKE256 XOF. Squeezes arbitraily many
|
||||
* bytes. Can be called multiple times to keep squeezing.
|
||||
*
|
||||
* Arguments: - uint8_t *out: pointer to output blocks
|
||||
* - size_t outlen : number of bytes to be squeezed (written to output)
|
||||
* - keccak_state *s: pointer to input/output Keccak state
|
||||
**************************************************/
|
||||
void shake256_squeeze(uint8_t *out, size_t outlen, keccak_state *state)
|
||||
{
|
||||
state->pos = keccak_squeeze(out, outlen, state->s, state->pos, SHAKE256_RATE);
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: shake256_absorb_once
|
||||
*
|
||||
* Description: Initialize, absorb into and finalize SHAKE256 XOF; non-incremental.
|
||||
*
|
||||
* Arguments: - keccak_state *state: pointer to (uninitialized) output Keccak state
|
||||
* - const uint8_t *in: pointer to input to be absorbed into s
|
||||
* - size_t inlen: length of input in bytes
|
||||
**************************************************/
|
||||
void shake256_absorb_once(keccak_state *state, const uint8_t *in, size_t inlen)
|
||||
{
|
||||
keccak_absorb_once(state->s, SHAKE256_RATE, in, inlen, 0x1F);
|
||||
state->pos = SHAKE256_RATE;
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: shake256_squeezeblocks
|
||||
*
|
||||
* Description: Squeeze step of SHAKE256 XOF. Squeezes full blocks of
|
||||
* SHAKE256_RATE bytes each. Can be called multiple times
|
||||
* to keep squeezing. Assumes next block has not yet been
|
||||
* started (state->pos = SHAKE256_RATE).
|
||||
*
|
||||
* Arguments: - uint8_t *out: pointer to output blocks
|
||||
* - size_t nblocks: number of blocks to be squeezed (written to output)
|
||||
* - keccak_state *s: pointer to input/output Keccak state
|
||||
**************************************************/
|
||||
void shake256_squeezeblocks(uint8_t *out, size_t nblocks, keccak_state *state)
|
||||
{
|
||||
keccak_squeezeblocks(out, nblocks, state->s, SHAKE256_RATE);
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: shake128
|
||||
*
|
||||
* Description: SHAKE128 XOF with non-incremental API
|
||||
*
|
||||
* Arguments: - uint8_t *out: pointer to output
|
||||
* - size_t outlen: requested output length in bytes
|
||||
* - const uint8_t *in: pointer to input
|
||||
* - size_t inlen: length of input in bytes
|
||||
**************************************************/
|
||||
void shake128(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen)
|
||||
{
|
||||
size_t nblocks;
|
||||
keccak_state state;
|
||||
|
||||
shake128_absorb_once(&state, in, inlen);
|
||||
nblocks = outlen/SHAKE128_RATE;
|
||||
shake128_squeezeblocks(out, nblocks, &state);
|
||||
outlen -= nblocks*SHAKE128_RATE;
|
||||
out += nblocks*SHAKE128_RATE;
|
||||
shake128_squeeze(out, outlen, &state);
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: shake256
|
||||
*
|
||||
* Description: SHAKE256 XOF with non-incremental API
|
||||
*
|
||||
* Arguments: - uint8_t *out: pointer to output
|
||||
* - size_t outlen: requested output length in bytes
|
||||
* - const uint8_t *in: pointer to input
|
||||
* - size_t inlen: length of input in bytes
|
||||
**************************************************/
|
||||
void shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen)
|
||||
{
|
||||
size_t nblocks;
|
||||
keccak_state state;
|
||||
|
||||
shake256_absorb_once(&state, in, inlen);
|
||||
nblocks = outlen/SHAKE256_RATE;
|
||||
shake256_squeezeblocks(out, nblocks, &state);
|
||||
outlen -= nblocks*SHAKE256_RATE;
|
||||
out += nblocks*SHAKE256_RATE;
|
||||
shake256_squeeze(out, outlen, &state);
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: sha3_256
|
||||
*
|
||||
* Description: SHA3-256 with non-incremental API
|
||||
*
|
||||
* Arguments: - uint8_t *h: pointer to output (32 bytes)
|
||||
* - const uint8_t *in: pointer to input
|
||||
* - size_t inlen: length of input in bytes
|
||||
**************************************************/
|
||||
void sha3_256(uint8_t h[32], const uint8_t *in, size_t inlen)
|
||||
{
|
||||
unsigned int i;
|
||||
uint64_t s[25];
|
||||
|
||||
keccak_absorb_once(s, SHA3_256_RATE, in, inlen, 0x06);
|
||||
KeccakF1600_StatePermute(s);
|
||||
for(i=0;i<4;i++)
|
||||
store64(h+8*i,s[i]);
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: sha3_512
|
||||
*
|
||||
* Description: SHA3-512 with non-incremental API
|
||||
*
|
||||
* Arguments: - uint8_t *h: pointer to output (64 bytes)
|
||||
* - const uint8_t *in: pointer to input
|
||||
* - size_t inlen: length of input in bytes
|
||||
**************************************************/
|
||||
void sha3_512(uint8_t h[64], const uint8_t *in, size_t inlen)
|
||||
{
|
||||
unsigned int i;
|
||||
uint64_t s[25];
|
||||
|
||||
keccak_absorb_once(s, SHA3_512_RATE, in, inlen, 0x06);
|
||||
KeccakF1600_StatePermute(s);
|
||||
for(i=0;i<8;i++)
|
||||
store64(h+8*i,s[i]);
|
||||
}
|
||||
66
Sources/CKyber/include/api.h
普通文件
66
Sources/CKyber/include/api.h
普通文件
@ -0,0 +1,66 @@
|
||||
#ifndef API_H
|
||||
#define API_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define pqcrystals_kyber512_SECRETKEYBYTES 1632
|
||||
#define pqcrystals_kyber512_PUBLICKEYBYTES 800
|
||||
#define pqcrystals_kyber512_CIPHERTEXTBYTES 768
|
||||
#define pqcrystals_kyber512_KEYPAIRCOINBYTES 64
|
||||
#define pqcrystals_kyber512_ENCCOINBYTES 32
|
||||
#define pqcrystals_kyber512_BYTES 32
|
||||
|
||||
#define pqcrystals_kyber512_ref_SECRETKEYBYTES pqcrystals_kyber512_SECRETKEYBYTES
|
||||
#define pqcrystals_kyber512_ref_PUBLICKEYBYTES pqcrystals_kyber512_PUBLICKEYBYTES
|
||||
#define pqcrystals_kyber512_ref_CIPHERTEXTBYTES pqcrystals_kyber512_CIPHERTEXTBYTES
|
||||
#define pqcrystals_kyber512_ref_KEYPAIRCOINBYTES pqcrystals_kyber512_KEYPAIRCOINBYTES
|
||||
#define pqcrystals_kyber512_ref_ENCCOINBYTES pqcrystals_kyber512_ENCCOINBYTES
|
||||
#define pqcrystals_kyber512_ref_BYTES pqcrystals_kyber512_BYTES
|
||||
|
||||
int pqcrystals_kyber512_ref_keypair_derand(uint8_t *pk, uint8_t *sk, const uint8_t *coins);
|
||||
int pqcrystals_kyber512_ref_keypair(uint8_t *pk, uint8_t *sk);
|
||||
int pqcrystals_kyber512_ref_enc_derand(uint8_t *ct, uint8_t *ss, const uint8_t *pk, const uint8_t *coins);
|
||||
int pqcrystals_kyber512_ref_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk);
|
||||
int pqcrystals_kyber512_ref_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk);
|
||||
|
||||
#define pqcrystals_kyber768_SECRETKEYBYTES 2400
|
||||
#define pqcrystals_kyber768_PUBLICKEYBYTES 1184
|
||||
#define pqcrystals_kyber768_CIPHERTEXTBYTES 1088
|
||||
#define pqcrystals_kyber768_KEYPAIRCOINBYTES 64
|
||||
#define pqcrystals_kyber768_ENCCOINBYTES 32
|
||||
#define pqcrystals_kyber768_BYTES 32
|
||||
|
||||
#define pqcrystals_kyber768_ref_SECRETKEYBYTES pqcrystals_kyber768_SECRETKEYBYTES
|
||||
#define pqcrystals_kyber768_ref_PUBLICKEYBYTES pqcrystals_kyber768_PUBLICKEYBYTES
|
||||
#define pqcrystals_kyber768_ref_CIPHERTEXTBYTES pqcrystals_kyber768_CIPHERTEXTBYTES
|
||||
#define pqcrystals_kyber768_ref_KEYPAIRCOINBYTES pqcrystals_kyber768_KEYPAIRCOINBYTES
|
||||
#define pqcrystals_kyber768_ref_ENCCOINBYTES pqcrystals_kyber768_ENCCOINBYTES
|
||||
#define pqcrystals_kyber768_ref_BYTES pqcrystals_kyber768_BYTES
|
||||
|
||||
int pqcrystals_kyber768_ref_keypair_derand(uint8_t *pk, uint8_t *sk, const uint8_t *coins);
|
||||
int pqcrystals_kyber768_ref_keypair(uint8_t *pk, uint8_t *sk);
|
||||
int pqcrystals_kyber768_ref_enc_derand(uint8_t *ct, uint8_t *ss, const uint8_t *pk, const uint8_t *coins);
|
||||
int pqcrystals_kyber768_ref_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk);
|
||||
int pqcrystals_kyber768_ref_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk);
|
||||
|
||||
#define pqcrystals_kyber1024_SECRETKEYBYTES 3168
|
||||
#define pqcrystals_kyber1024_PUBLICKEYBYTES 1568
|
||||
#define pqcrystals_kyber1024_CIPHERTEXTBYTES 1568
|
||||
#define pqcrystals_kyber1024_KEYPAIRCOINBYTES 64
|
||||
#define pqcrystals_kyber1024_ENCCOINBYTES 32
|
||||
#define pqcrystals_kyber1024_BYTES 32
|
||||
|
||||
#define pqcrystals_kyber1024_ref_SECRETKEYBYTES pqcrystals_kyber1024_SECRETKEYBYTES
|
||||
#define pqcrystals_kyber1024_ref_PUBLICKEYBYTES pqcrystals_kyber1024_PUBLICKEYBYTES
|
||||
#define pqcrystals_kyber1024_ref_CIPHERTEXTBYTES pqcrystals_kyber1024_CIPHERTEXTBYTES
|
||||
#define pqcrystals_kyber1024_ref_KEYPAIRCOINBYTES pqcrystals_kyber1024_KEYPAIRCOINBYTES
|
||||
#define pqcrystals_kyber1024_ref_ENCCOINBYTES pqcrystals_kyber1024_ENCCOINBYTES
|
||||
#define pqcrystals_kyber1024_ref_BYTES pqcrystals_kyber1024_BYTES
|
||||
|
||||
int pqcrystals_kyber1024_ref_keypair_derand(uint8_t *pk, uint8_t *sk, const uint8_t *coins);
|
||||
int pqcrystals_kyber1024_ref_keypair(uint8_t *pk, uint8_t *sk);
|
||||
int pqcrystals_kyber1024_ref_enc_derand(uint8_t *ct, uint8_t *ss, const uint8_t *pk, const uint8_t *coins);
|
||||
int pqcrystals_kyber1024_ref_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk);
|
||||
int pqcrystals_kyber1024_ref_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk);
|
||||
|
||||
#endif
|
||||
14
Sources/CKyber/include/cbd.h
普通文件
14
Sources/CKyber/include/cbd.h
普通文件
@ -0,0 +1,14 @@
|
||||
#ifndef CBD_H
|
||||
#define CBD_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "params.h"
|
||||
#include "poly.h"
|
||||
|
||||
#define poly_cbd_eta1 KYBER_NAMESPACE(poly_cbd_eta1)
|
||||
void poly_cbd_eta1(poly *r, const uint8_t buf[KYBER_ETA1*KYBER_N/4]);
|
||||
|
||||
#define poly_cbd_eta2 KYBER_NAMESPACE(poly_cbd_eta2)
|
||||
void poly_cbd_eta2(poly *r, const uint8_t buf[KYBER_ETA2*KYBER_N/4]);
|
||||
|
||||
#endif
|
||||
54
Sources/CKyber/include/fips202.h
普通文件
54
Sources/CKyber/include/fips202.h
普通文件
@ -0,0 +1,54 @@
|
||||
#ifndef FIPS202_H
|
||||
#define FIPS202_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define SHAKE128_RATE 168
|
||||
#define SHAKE256_RATE 136
|
||||
#define SHA3_256_RATE 136
|
||||
#define SHA3_512_RATE 72
|
||||
|
||||
#define FIPS202_NAMESPACE(s) pqcrystals_kyber_fips202_ref_##s
|
||||
|
||||
typedef struct {
|
||||
uint64_t s[25];
|
||||
unsigned int pos;
|
||||
} keccak_state;
|
||||
|
||||
#define shake128_init FIPS202_NAMESPACE(shake128_init)
|
||||
void shake128_init(keccak_state *state);
|
||||
#define shake128_absorb FIPS202_NAMESPACE(shake128_absorb)
|
||||
void shake128_absorb(keccak_state *state, const uint8_t *in, size_t inlen);
|
||||
#define shake128_finalize FIPS202_NAMESPACE(shake128_finalize)
|
||||
void shake128_finalize(keccak_state *state);
|
||||
#define shake128_squeeze FIPS202_NAMESPACE(shake128_squeeze)
|
||||
void shake128_squeeze(uint8_t *out, size_t outlen, keccak_state *state);
|
||||
#define shake128_absorb_once FIPS202_NAMESPACE(shake128_absorb_once)
|
||||
void shake128_absorb_once(keccak_state *state, const uint8_t *in, size_t inlen);
|
||||
#define shake128_squeezeblocks FIPS202_NAMESPACE(shake128_squeezeblocks)
|
||||
void shake128_squeezeblocks(uint8_t *out, size_t nblocks, keccak_state *state);
|
||||
|
||||
#define shake256_init FIPS202_NAMESPACE(shake256_init)
|
||||
void shake256_init(keccak_state *state);
|
||||
#define shake256_absorb FIPS202_NAMESPACE(shake256_absorb)
|
||||
void shake256_absorb(keccak_state *state, const uint8_t *in, size_t inlen);
|
||||
#define shake256_finalize FIPS202_NAMESPACE(shake256_finalize)
|
||||
void shake256_finalize(keccak_state *state);
|
||||
#define shake256_squeeze FIPS202_NAMESPACE(shake256_squeeze)
|
||||
void shake256_squeeze(uint8_t *out, size_t outlen, keccak_state *state);
|
||||
#define shake256_absorb_once FIPS202_NAMESPACE(shake256_absorb_once)
|
||||
void shake256_absorb_once(keccak_state *state, const uint8_t *in, size_t inlen);
|
||||
#define shake256_squeezeblocks FIPS202_NAMESPACE(shake256_squeezeblocks)
|
||||
void shake256_squeezeblocks(uint8_t *out, size_t nblocks, keccak_state *state);
|
||||
|
||||
#define shake128 FIPS202_NAMESPACE(shake128)
|
||||
void shake128(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen);
|
||||
#define shake256 FIPS202_NAMESPACE(shake256)
|
||||
void shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen);
|
||||
#define sha3_256 FIPS202_NAMESPACE(sha3_256)
|
||||
void sha3_256(uint8_t h[32], const uint8_t *in, size_t inlen);
|
||||
#define sha3_512 FIPS202_NAMESPACE(sha3_512)
|
||||
void sha3_512(uint8_t h[64], const uint8_t *in, size_t inlen);
|
||||
|
||||
#endif
|
||||
27
Sources/CKyber/include/indcpa.h
普通文件
27
Sources/CKyber/include/indcpa.h
普通文件
@ -0,0 +1,27 @@
|
||||
#ifndef INDCPA_H
|
||||
#define INDCPA_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "params.h"
|
||||
#include "polyvec.h"
|
||||
|
||||
#define gen_matrix KYBER_NAMESPACE(gen_matrix)
|
||||
void gen_matrix(polyvec *a, const uint8_t seed[KYBER_SYMBYTES], int transposed);
|
||||
|
||||
#define indcpa_keypair_derand KYBER_NAMESPACE(indcpa_keypair_derand)
|
||||
void indcpa_keypair_derand(uint8_t pk[KYBER_INDCPA_PUBLICKEYBYTES],
|
||||
uint8_t sk[KYBER_INDCPA_SECRETKEYBYTES],
|
||||
const uint8_t coins[KYBER_SYMBYTES]);
|
||||
|
||||
#define indcpa_enc KYBER_NAMESPACE(indcpa_enc)
|
||||
void indcpa_enc(uint8_t c[KYBER_INDCPA_BYTES],
|
||||
const uint8_t m[KYBER_INDCPA_MSGBYTES],
|
||||
const uint8_t pk[KYBER_INDCPA_PUBLICKEYBYTES],
|
||||
const uint8_t coins[KYBER_SYMBYTES]);
|
||||
|
||||
#define indcpa_dec KYBER_NAMESPACE(indcpa_dec)
|
||||
void indcpa_dec(uint8_t m[KYBER_INDCPA_MSGBYTES],
|
||||
const uint8_t c[KYBER_INDCPA_BYTES],
|
||||
const uint8_t sk[KYBER_INDCPA_SECRETKEYBYTES]);
|
||||
|
||||
#endif
|
||||
35
Sources/CKyber/include/kem.h
普通文件
35
Sources/CKyber/include/kem.h
普通文件
@ -0,0 +1,35 @@
|
||||
#ifndef KEM_H
|
||||
#define KEM_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "params.h"
|
||||
|
||||
#define CRYPTO_SECRETKEYBYTES KYBER_SECRETKEYBYTES
|
||||
#define CRYPTO_PUBLICKEYBYTES KYBER_PUBLICKEYBYTES
|
||||
#define CRYPTO_CIPHERTEXTBYTES KYBER_CIPHERTEXTBYTES
|
||||
#define CRYPTO_BYTES KYBER_SSBYTES
|
||||
|
||||
#if (KYBER_K == 2)
|
||||
#define CRYPTO_ALGNAME "Kyber512"
|
||||
#elif (KYBER_K == 3)
|
||||
#define CRYPTO_ALGNAME "Kyber768"
|
||||
#elif (KYBER_K == 4)
|
||||
#define CRYPTO_ALGNAME "Kyber1024"
|
||||
#endif
|
||||
|
||||
#define crypto_kem_keypair_derand KYBER_NAMESPACE(keypair_derand)
|
||||
int crypto_kem_keypair_derand(uint8_t *pk, uint8_t *sk, const uint8_t *coins);
|
||||
|
||||
#define crypto_kem_keypair KYBER_NAMESPACE(keypair)
|
||||
int crypto_kem_keypair(uint8_t *pk, uint8_t *sk);
|
||||
|
||||
#define crypto_kem_enc_derand KYBER_NAMESPACE(enc_derand)
|
||||
int crypto_kem_enc_derand(uint8_t *ct, uint8_t *ss, const uint8_t *pk, const uint8_t *coins);
|
||||
|
||||
#define crypto_kem_enc KYBER_NAMESPACE(enc)
|
||||
int crypto_kem_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk);
|
||||
|
||||
#define crypto_kem_dec KYBER_NAMESPACE(dec)
|
||||
int crypto_kem_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk);
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* kyber_sdk.h — CKyber 模块公开头文件(伞头文件)
|
||||
*
|
||||
* 对外暴露以下内容:
|
||||
* 1. Kyber512 / 768 / 1024 三种变体的完整 API(来自 api.h)
|
||||
* 2. randombytes — 密码学安全随机数接口(iOS 侧由 arc4random_buf 实现)
|
||||
*
|
||||
* Swift 层通过 `import CKyber` 访问所有 C 函数。
|
||||
*/
|
||||
#ifndef KYBER_SDK_H
|
||||
#define KYBER_SDK_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "api.h" /* Kyber512 / 768 / 1024 密钥生成 / 封装 / 解封装函数声明 */
|
||||
|
||||
/* 暴露随机数接口,供 Swift 层在调用 keypair_derand / enc_derand 前生成 coins */
|
||||
void randombytes(uint8_t *out, size_t outlen);
|
||||
|
||||
#endif /* KYBER_SDK_H */
|
||||
19
Sources/CKyber/include/ntt.h
普通文件
19
Sources/CKyber/include/ntt.h
普通文件
@ -0,0 +1,19 @@
|
||||
#ifndef NTT_H
|
||||
#define NTT_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "params.h"
|
||||
|
||||
#define zetas KYBER_NAMESPACE(zetas)
|
||||
extern const int16_t zetas[128];
|
||||
|
||||
#define ntt KYBER_NAMESPACE(ntt)
|
||||
void ntt(int16_t poly[256]);
|
||||
|
||||
#define invntt KYBER_NAMESPACE(invntt)
|
||||
void invntt(int16_t poly[256]);
|
||||
|
||||
#define basemul KYBER_NAMESPACE(basemul)
|
||||
void basemul(int16_t r[2], const int16_t a[2], const int16_t b[2], int16_t zeta);
|
||||
|
||||
#endif
|
||||
55
Sources/CKyber/include/params.h
普通文件
55
Sources/CKyber/include/params.h
普通文件
@ -0,0 +1,55 @@
|
||||
#ifndef PARAMS_H
|
||||
#define PARAMS_H
|
||||
|
||||
#ifndef KYBER_K
|
||||
#define KYBER_K 3 /* Change this for different security strengths */
|
||||
#endif
|
||||
|
||||
|
||||
/* Don't change parameters below this line */
|
||||
#if (KYBER_K == 2)
|
||||
#define KYBER_NAMESPACE(s) pqcrystals_kyber512_ref_##s
|
||||
#elif (KYBER_K == 3)
|
||||
#define KYBER_NAMESPACE(s) pqcrystals_kyber768_ref_##s
|
||||
#elif (KYBER_K == 4)
|
||||
#define KYBER_NAMESPACE(s) pqcrystals_kyber1024_ref_##s
|
||||
#else
|
||||
#error "KYBER_K must be in {2,3,4}"
|
||||
#endif
|
||||
|
||||
#define KYBER_N 256
|
||||
#define KYBER_Q 3329
|
||||
|
||||
#define KYBER_SYMBYTES 32 /* size in bytes of hashes, and seeds */
|
||||
#define KYBER_SSBYTES 32 /* size in bytes of shared key */
|
||||
|
||||
#define KYBER_POLYBYTES 384
|
||||
#define KYBER_POLYVECBYTES (KYBER_K * KYBER_POLYBYTES)
|
||||
|
||||
#if KYBER_K == 2
|
||||
#define KYBER_ETA1 3
|
||||
#define KYBER_POLYCOMPRESSEDBYTES 128
|
||||
#define KYBER_POLYVECCOMPRESSEDBYTES (KYBER_K * 320)
|
||||
#elif KYBER_K == 3
|
||||
#define KYBER_ETA1 2
|
||||
#define KYBER_POLYCOMPRESSEDBYTES 128
|
||||
#define KYBER_POLYVECCOMPRESSEDBYTES (KYBER_K * 320)
|
||||
#elif KYBER_K == 4
|
||||
#define KYBER_ETA1 2
|
||||
#define KYBER_POLYCOMPRESSEDBYTES 160
|
||||
#define KYBER_POLYVECCOMPRESSEDBYTES (KYBER_K * 352)
|
||||
#endif
|
||||
|
||||
#define KYBER_ETA2 2
|
||||
|
||||
#define KYBER_INDCPA_MSGBYTES (KYBER_SYMBYTES)
|
||||
#define KYBER_INDCPA_PUBLICKEYBYTES (KYBER_POLYVECBYTES + KYBER_SYMBYTES)
|
||||
#define KYBER_INDCPA_SECRETKEYBYTES (KYBER_POLYVECBYTES)
|
||||
#define KYBER_INDCPA_BYTES (KYBER_POLYVECCOMPRESSEDBYTES + KYBER_POLYCOMPRESSEDBYTES)
|
||||
|
||||
#define KYBER_PUBLICKEYBYTES (KYBER_INDCPA_PUBLICKEYBYTES)
|
||||
/* 32 bytes of additional space to save H(pk) */
|
||||
#define KYBER_SECRETKEYBYTES (KYBER_INDCPA_SECRETKEYBYTES + KYBER_INDCPA_PUBLICKEYBYTES + 2*KYBER_SYMBYTES)
|
||||
#define KYBER_CIPHERTEXTBYTES (KYBER_INDCPA_BYTES)
|
||||
|
||||
#endif
|
||||
53
Sources/CKyber/include/poly.h
普通文件
53
Sources/CKyber/include/poly.h
普通文件
@ -0,0 +1,53 @@
|
||||
#ifndef POLY_H
|
||||
#define POLY_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "params.h"
|
||||
|
||||
/*
|
||||
* Elements of R_q = Z_q[X]/(X^n + 1). Represents polynomial
|
||||
* coeffs[0] + X*coeffs[1] + X^2*coeffs[2] + ... + X^{n-1}*coeffs[n-1]
|
||||
*/
|
||||
typedef struct{
|
||||
int16_t coeffs[KYBER_N];
|
||||
} poly;
|
||||
|
||||
#define poly_compress KYBER_NAMESPACE(poly_compress)
|
||||
void poly_compress(uint8_t r[KYBER_POLYCOMPRESSEDBYTES], const poly *a);
|
||||
#define poly_decompress KYBER_NAMESPACE(poly_decompress)
|
||||
void poly_decompress(poly *r, const uint8_t a[KYBER_POLYCOMPRESSEDBYTES]);
|
||||
|
||||
#define poly_tobytes KYBER_NAMESPACE(poly_tobytes)
|
||||
void poly_tobytes(uint8_t r[KYBER_POLYBYTES], const poly *a);
|
||||
#define poly_frombytes KYBER_NAMESPACE(poly_frombytes)
|
||||
void poly_frombytes(poly *r, const uint8_t a[KYBER_POLYBYTES]);
|
||||
|
||||
#define poly_frommsg KYBER_NAMESPACE(poly_frommsg)
|
||||
void poly_frommsg(poly *r, const uint8_t msg[KYBER_INDCPA_MSGBYTES]);
|
||||
#define poly_tomsg KYBER_NAMESPACE(poly_tomsg)
|
||||
void poly_tomsg(uint8_t msg[KYBER_INDCPA_MSGBYTES], const poly *r);
|
||||
|
||||
#define poly_getnoise_eta1 KYBER_NAMESPACE(poly_getnoise_eta1)
|
||||
void poly_getnoise_eta1(poly *r, const uint8_t seed[KYBER_SYMBYTES], uint8_t nonce);
|
||||
|
||||
#define poly_getnoise_eta2 KYBER_NAMESPACE(poly_getnoise_eta2)
|
||||
void poly_getnoise_eta2(poly *r, const uint8_t seed[KYBER_SYMBYTES], uint8_t nonce);
|
||||
|
||||
#define poly_ntt KYBER_NAMESPACE(poly_ntt)
|
||||
void poly_ntt(poly *r);
|
||||
#define poly_invntt_tomont KYBER_NAMESPACE(poly_invntt_tomont)
|
||||
void poly_invntt_tomont(poly *r);
|
||||
#define poly_basemul_montgomery KYBER_NAMESPACE(poly_basemul_montgomery)
|
||||
void poly_basemul_montgomery(poly *r, const poly *a, const poly *b);
|
||||
#define poly_tomont KYBER_NAMESPACE(poly_tomont)
|
||||
void poly_tomont(poly *r);
|
||||
|
||||
#define poly_reduce KYBER_NAMESPACE(poly_reduce)
|
||||
void poly_reduce(poly *r);
|
||||
|
||||
#define poly_add KYBER_NAMESPACE(poly_add)
|
||||
void poly_add(poly *r, const poly *a, const poly *b);
|
||||
#define poly_sub KYBER_NAMESPACE(poly_sub)
|
||||
void poly_sub(poly *r, const poly *a, const poly *b);
|
||||
|
||||
#endif
|
||||
36
Sources/CKyber/include/polyvec.h
普通文件
36
Sources/CKyber/include/polyvec.h
普通文件
@ -0,0 +1,36 @@
|
||||
#ifndef POLYVEC_H
|
||||
#define POLYVEC_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "params.h"
|
||||
#include "poly.h"
|
||||
|
||||
typedef struct{
|
||||
poly vec[KYBER_K];
|
||||
} polyvec;
|
||||
|
||||
#define polyvec_compress KYBER_NAMESPACE(polyvec_compress)
|
||||
void polyvec_compress(uint8_t r[KYBER_POLYVECCOMPRESSEDBYTES], const polyvec *a);
|
||||
#define polyvec_decompress KYBER_NAMESPACE(polyvec_decompress)
|
||||
void polyvec_decompress(polyvec *r, const uint8_t a[KYBER_POLYVECCOMPRESSEDBYTES]);
|
||||
|
||||
#define polyvec_tobytes KYBER_NAMESPACE(polyvec_tobytes)
|
||||
void polyvec_tobytes(uint8_t r[KYBER_POLYVECBYTES], const polyvec *a);
|
||||
#define polyvec_frombytes KYBER_NAMESPACE(polyvec_frombytes)
|
||||
void polyvec_frombytes(polyvec *r, const uint8_t a[KYBER_POLYVECBYTES]);
|
||||
|
||||
#define polyvec_ntt KYBER_NAMESPACE(polyvec_ntt)
|
||||
void polyvec_ntt(polyvec *r);
|
||||
#define polyvec_invntt_tomont KYBER_NAMESPACE(polyvec_invntt_tomont)
|
||||
void polyvec_invntt_tomont(polyvec *r);
|
||||
|
||||
#define polyvec_basemul_acc_montgomery KYBER_NAMESPACE(polyvec_basemul_acc_montgomery)
|
||||
void polyvec_basemul_acc_montgomery(poly *r, const polyvec *a, const polyvec *b);
|
||||
|
||||
#define polyvec_reduce KYBER_NAMESPACE(polyvec_reduce)
|
||||
void polyvec_reduce(polyvec *r);
|
||||
|
||||
#define polyvec_add KYBER_NAMESPACE(polyvec_add)
|
||||
void polyvec_add(polyvec *r, const polyvec *a, const polyvec *b);
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,9 @@
|
||||
#ifndef RANDOMBYTES_H
|
||||
#define RANDOMBYTES_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void randombytes(uint8_t *out, size_t outlen);
|
||||
|
||||
#endif
|
||||
16
Sources/CKyber/include/reduce.h
普通文件
16
Sources/CKyber/include/reduce.h
普通文件
@ -0,0 +1,16 @@
|
||||
#ifndef REDUCE_H
|
||||
#define REDUCE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "params.h"
|
||||
|
||||
#define MONT -1044 // 2^16 mod q
|
||||
#define QINV -3327 // q^-1 mod 2^16
|
||||
|
||||
#define montgomery_reduce KYBER_NAMESPACE(montgomery_reduce)
|
||||
int16_t montgomery_reduce(int32_t a);
|
||||
|
||||
#define barrett_reduce KYBER_NAMESPACE(barrett_reduce)
|
||||
int16_t barrett_reduce(int16_t a);
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,33 @@
|
||||
#ifndef SYMMETRIC_H
|
||||
#define SYMMETRIC_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "params.h"
|
||||
|
||||
#include "fips202.h"
|
||||
|
||||
typedef keccak_state xof_state;
|
||||
|
||||
#define kyber_shake128_absorb KYBER_NAMESPACE(kyber_shake128_absorb)
|
||||
void kyber_shake128_absorb(keccak_state *s,
|
||||
const uint8_t seed[KYBER_SYMBYTES],
|
||||
uint8_t x,
|
||||
uint8_t y);
|
||||
|
||||
#define kyber_shake256_prf KYBER_NAMESPACE(kyber_shake256_prf)
|
||||
void kyber_shake256_prf(uint8_t *out, size_t outlen, const uint8_t key[KYBER_SYMBYTES], uint8_t nonce);
|
||||
|
||||
#define kyber_shake256_rkprf KYBER_NAMESPACE(kyber_shake256_rkprf)
|
||||
void kyber_shake256_rkprf(uint8_t out[KYBER_SSBYTES], const uint8_t key[KYBER_SYMBYTES], const uint8_t input[KYBER_CIPHERTEXTBYTES]);
|
||||
|
||||
#define XOF_BLOCKBYTES SHAKE128_RATE
|
||||
|
||||
#define hash_h(OUT, IN, INBYTES) sha3_256(OUT, IN, INBYTES)
|
||||
#define hash_g(OUT, IN, INBYTES) sha3_512(OUT, IN, INBYTES)
|
||||
#define xof_absorb(STATE, SEED, X, Y) kyber_shake128_absorb(STATE, SEED, X, Y)
|
||||
#define xof_squeezeblocks(OUT, OUTBLOCKS, STATE) shake128_squeezeblocks(OUT, OUTBLOCKS, STATE)
|
||||
#define prf(OUT, OUTBYTES, KEY, NONCE) kyber_shake256_prf(OUT, OUTBYTES, KEY, NONCE)
|
||||
#define rkprf(OUT, KEY, INPUT) kyber_shake256_rkprf(OUT, KEY, INPUT)
|
||||
|
||||
#endif /* SYMMETRIC_H */
|
||||
17
Sources/CKyber/include/verify.h
普通文件
17
Sources/CKyber/include/verify.h
普通文件
@ -0,0 +1,17 @@
|
||||
#ifndef VERIFY_H
|
||||
#define VERIFY_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "params.h"
|
||||
|
||||
#define verify KYBER_NAMESPACE(verify)
|
||||
int verify(const uint8_t *a, const uint8_t *b, size_t len);
|
||||
|
||||
#define cmov KYBER_NAMESPACE(cmov)
|
||||
void cmov(uint8_t *r, const uint8_t *x, size_t len, uint8_t b);
|
||||
|
||||
#define cmov_int16 KYBER_NAMESPACE(cmov_int16)
|
||||
void cmov_int16(int16_t *r, int16_t v, uint16_t b);
|
||||
|
||||
#endif
|
||||
128
Sources/CKyber/internal/cbd.inc
普通文件
128
Sources/CKyber/internal/cbd.inc
普通文件
@ -0,0 +1,128 @@
|
||||
#include <stdint.h>
|
||||
#include "params.h"
|
||||
#include "cbd.h"
|
||||
|
||||
/*************************************************
|
||||
* Name: load32_littleendian
|
||||
*
|
||||
* Description: load 4 bytes into a 32-bit integer
|
||||
* in little-endian order
|
||||
*
|
||||
* Arguments: - const uint8_t *x: pointer to input byte array
|
||||
*
|
||||
* Returns 32-bit unsigned integer loaded from x
|
||||
**************************************************/
|
||||
static uint32_t load32_littleendian(const uint8_t x[4])
|
||||
{
|
||||
uint32_t r;
|
||||
r = (uint32_t)x[0];
|
||||
r |= (uint32_t)x[1] << 8;
|
||||
r |= (uint32_t)x[2] << 16;
|
||||
r |= (uint32_t)x[3] << 24;
|
||||
return r;
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: load24_littleendian
|
||||
*
|
||||
* Description: load 3 bytes into a 32-bit integer
|
||||
* in little-endian order.
|
||||
* This function is only needed for Kyber-512
|
||||
*
|
||||
* Arguments: - const uint8_t *x: pointer to input byte array
|
||||
*
|
||||
* Returns 32-bit unsigned integer loaded from x (most significant byte is zero)
|
||||
**************************************************/
|
||||
#if KYBER_ETA1 == 3
|
||||
static uint32_t load24_littleendian(const uint8_t x[3])
|
||||
{
|
||||
uint32_t r;
|
||||
r = (uint32_t)x[0];
|
||||
r |= (uint32_t)x[1] << 8;
|
||||
r |= (uint32_t)x[2] << 16;
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Name: cbd2
|
||||
*
|
||||
* Description: Given an array of uniformly random bytes, compute
|
||||
* polynomial with coefficients distributed according to
|
||||
* a centered binomial distribution with parameter eta=2
|
||||
*
|
||||
* Arguments: - poly *r: pointer to output polynomial
|
||||
* - const uint8_t *buf: pointer to input byte array
|
||||
**************************************************/
|
||||
static void cbd2(poly *r, const uint8_t buf[2*KYBER_N/4])
|
||||
{
|
||||
unsigned int i,j;
|
||||
uint32_t t,d;
|
||||
int16_t a,b;
|
||||
|
||||
for(i=0;i<KYBER_N/8;i++) {
|
||||
t = load32_littleendian(buf+4*i);
|
||||
d = t & 0x55555555;
|
||||
d += (t>>1) & 0x55555555;
|
||||
|
||||
for(j=0;j<8;j++) {
|
||||
a = (d >> (4*j+0)) & 0x3;
|
||||
b = (d >> (4*j+2)) & 0x3;
|
||||
r->coeffs[8*i+j] = a - b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: cbd3
|
||||
*
|
||||
* Description: Given an array of uniformly random bytes, compute
|
||||
* polynomial with coefficients distributed according to
|
||||
* a centered binomial distribution with parameter eta=3.
|
||||
* This function is only needed for Kyber-512
|
||||
*
|
||||
* Arguments: - poly *r: pointer to output polynomial
|
||||
* - const uint8_t *buf: pointer to input byte array
|
||||
**************************************************/
|
||||
#if KYBER_ETA1 == 3
|
||||
static void cbd3(poly *r, const uint8_t buf[3*KYBER_N/4])
|
||||
{
|
||||
unsigned int i,j;
|
||||
uint32_t t,d;
|
||||
int16_t a,b;
|
||||
|
||||
for(i=0;i<KYBER_N/4;i++) {
|
||||
t = load24_littleendian(buf+3*i);
|
||||
d = t & 0x00249249;
|
||||
d += (t>>1) & 0x00249249;
|
||||
d += (t>>2) & 0x00249249;
|
||||
|
||||
for(j=0;j<4;j++) {
|
||||
a = (d >> (6*j+0)) & 0x7;
|
||||
b = (d >> (6*j+3)) & 0x7;
|
||||
r->coeffs[4*i+j] = a - b;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void poly_cbd_eta1(poly *r, const uint8_t buf[KYBER_ETA1*KYBER_N/4])
|
||||
{
|
||||
#if KYBER_ETA1 == 2
|
||||
cbd2(r, buf);
|
||||
#elif KYBER_ETA1 == 3
|
||||
cbd3(r, buf);
|
||||
#else
|
||||
#error "This implementation requires eta1 in {2,3}"
|
||||
#endif
|
||||
}
|
||||
|
||||
void poly_cbd_eta2(poly *r, const uint8_t buf[KYBER_ETA2*KYBER_N/4])
|
||||
{
|
||||
#if KYBER_ETA2 == 2
|
||||
cbd2(r, buf);
|
||||
#else
|
||||
#error "This implementation requires eta2 = 2"
|
||||
#endif
|
||||
}
|
||||
332
Sources/CKyber/internal/indcpa.inc
普通文件
332
Sources/CKyber/internal/indcpa.inc
普通文件
@ -0,0 +1,332 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "params.h"
|
||||
#include "indcpa.h"
|
||||
#include "polyvec.h"
|
||||
#include "poly.h"
|
||||
#include "ntt.h"
|
||||
#include "symmetric.h"
|
||||
#include "randombytes.h"
|
||||
|
||||
/*************************************************
|
||||
* Name: pack_pk
|
||||
*
|
||||
* Description: Serialize the public key as concatenation of the
|
||||
* serialized vector of polynomials pk
|
||||
* and the public seed used to generate the matrix A.
|
||||
*
|
||||
* Arguments: uint8_t *r: pointer to the output serialized public key
|
||||
* polyvec *pk: pointer to the input public-key polyvec
|
||||
* const uint8_t *seed: pointer to the input public seed
|
||||
**************************************************/
|
||||
static void pack_pk(uint8_t r[KYBER_INDCPA_PUBLICKEYBYTES],
|
||||
polyvec *pk,
|
||||
const uint8_t seed[KYBER_SYMBYTES])
|
||||
{
|
||||
polyvec_tobytes(r, pk);
|
||||
memcpy(r+KYBER_POLYVECBYTES, seed, KYBER_SYMBYTES);
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: unpack_pk
|
||||
*
|
||||
* Description: De-serialize public key from a byte array;
|
||||
* approximate inverse of pack_pk
|
||||
*
|
||||
* Arguments: - polyvec *pk: pointer to output public-key polynomial vector
|
||||
* - uint8_t *seed: pointer to output seed to generate matrix A
|
||||
* - const uint8_t *packedpk: pointer to input serialized public key
|
||||
**************************************************/
|
||||
static void unpack_pk(polyvec *pk,
|
||||
uint8_t seed[KYBER_SYMBYTES],
|
||||
const uint8_t packedpk[KYBER_INDCPA_PUBLICKEYBYTES])
|
||||
{
|
||||
polyvec_frombytes(pk, packedpk);
|
||||
memcpy(seed, packedpk+KYBER_POLYVECBYTES, KYBER_SYMBYTES);
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: pack_sk
|
||||
*
|
||||
* Description: Serialize the secret key
|
||||
*
|
||||
* Arguments: - uint8_t *r: pointer to output serialized secret key
|
||||
* - polyvec *sk: pointer to input vector of polynomials (secret key)
|
||||
**************************************************/
|
||||
static void pack_sk(uint8_t r[KYBER_INDCPA_SECRETKEYBYTES], polyvec *sk)
|
||||
{
|
||||
polyvec_tobytes(r, sk);
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: unpack_sk
|
||||
*
|
||||
* Description: De-serialize the secret key; inverse of pack_sk
|
||||
*
|
||||
* Arguments: - polyvec *sk: pointer to output vector of polynomials (secret key)
|
||||
* - const uint8_t *packedsk: pointer to input serialized secret key
|
||||
**************************************************/
|
||||
static void unpack_sk(polyvec *sk, const uint8_t packedsk[KYBER_INDCPA_SECRETKEYBYTES])
|
||||
{
|
||||
polyvec_frombytes(sk, packedsk);
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: pack_ciphertext
|
||||
*
|
||||
* Description: Serialize the ciphertext as concatenation of the
|
||||
* compressed and serialized vector of polynomials b
|
||||
* and the compressed and serialized polynomial v
|
||||
*
|
||||
* Arguments: uint8_t *r: pointer to the output serialized ciphertext
|
||||
* poly *pk: pointer to the input vector of polynomials b
|
||||
* poly *v: pointer to the input polynomial v
|
||||
**************************************************/
|
||||
static void pack_ciphertext(uint8_t r[KYBER_INDCPA_BYTES], polyvec *b, poly *v)
|
||||
{
|
||||
polyvec_compress(r, b);
|
||||
poly_compress(r+KYBER_POLYVECCOMPRESSEDBYTES, v);
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: unpack_ciphertext
|
||||
*
|
||||
* Description: De-serialize and decompress ciphertext from a byte array;
|
||||
* approximate inverse of pack_ciphertext
|
||||
*
|
||||
* Arguments: - polyvec *b: pointer to the output vector of polynomials b
|
||||
* - poly *v: pointer to the output polynomial v
|
||||
* - const uint8_t *c: pointer to the input serialized ciphertext
|
||||
**************************************************/
|
||||
static void unpack_ciphertext(polyvec *b, poly *v, const uint8_t c[KYBER_INDCPA_BYTES])
|
||||
{
|
||||
polyvec_decompress(b, c);
|
||||
poly_decompress(v, c+KYBER_POLYVECCOMPRESSEDBYTES);
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: rej_uniform
|
||||
*
|
||||
* Description: Run rejection sampling on uniform random bytes to generate
|
||||
* uniform random integers mod q
|
||||
*
|
||||
* Arguments: - int16_t *r: pointer to output buffer
|
||||
* - unsigned int len: requested number of 16-bit integers (uniform mod q)
|
||||
* - const uint8_t *buf: pointer to input buffer (assumed to be uniformly random bytes)
|
||||
* - unsigned int buflen: length of input buffer in bytes
|
||||
*
|
||||
* Returns number of sampled 16-bit integers (at most len)
|
||||
**************************************************/
|
||||
static unsigned int rej_uniform(int16_t *r,
|
||||
unsigned int len,
|
||||
const uint8_t *buf,
|
||||
unsigned int buflen)
|
||||
{
|
||||
unsigned int ctr, pos;
|
||||
uint16_t val0, val1;
|
||||
|
||||
ctr = pos = 0;
|
||||
while(ctr < len && pos + 3 <= buflen) {
|
||||
val0 = ((buf[pos+0] >> 0) | ((uint16_t)buf[pos+1] << 8)) & 0xFFF;
|
||||
val1 = ((buf[pos+1] >> 4) | ((uint16_t)buf[pos+2] << 4)) & 0xFFF;
|
||||
pos += 3;
|
||||
|
||||
if(val0 < KYBER_Q)
|
||||
r[ctr++] = val0;
|
||||
if(ctr < len && val1 < KYBER_Q)
|
||||
r[ctr++] = val1;
|
||||
}
|
||||
|
||||
return ctr;
|
||||
}
|
||||
|
||||
#define gen_a(A,B) gen_matrix(A,B,0)
|
||||
#define gen_at(A,B) gen_matrix(A,B,1)
|
||||
|
||||
/*************************************************
|
||||
* Name: gen_matrix
|
||||
*
|
||||
* Description: Deterministically generate matrix A (or the transpose of A)
|
||||
* from a seed. Entries of the matrix are polynomials that look
|
||||
* uniformly random. Performs rejection sampling on output of
|
||||
* a XOF
|
||||
*
|
||||
* Arguments: - polyvec *a: pointer to ouptput matrix A
|
||||
* - const uint8_t *seed: pointer to input seed
|
||||
* - int transposed: boolean deciding whether A or A^T is generated
|
||||
**************************************************/
|
||||
#if(XOF_BLOCKBYTES % 3)
|
||||
#error "Implementation of gen_matrix assumes that XOF_BLOCKBYTES is a multiple of 3"
|
||||
#endif
|
||||
|
||||
#define GEN_MATRIX_NBLOCKS ((12*KYBER_N/8*(1 << 12)/KYBER_Q + XOF_BLOCKBYTES)/XOF_BLOCKBYTES)
|
||||
// Not static for benchmarking
|
||||
void gen_matrix(polyvec *a, const uint8_t seed[KYBER_SYMBYTES], int transposed)
|
||||
{
|
||||
unsigned int ctr, i, j;
|
||||
unsigned int buflen;
|
||||
uint8_t buf[GEN_MATRIX_NBLOCKS*XOF_BLOCKBYTES];
|
||||
xof_state state;
|
||||
|
||||
for(i=0;i<KYBER_K;i++) {
|
||||
for(j=0;j<KYBER_K;j++) {
|
||||
if(transposed)
|
||||
xof_absorb(&state, seed, i, j);
|
||||
else
|
||||
xof_absorb(&state, seed, j, i);
|
||||
|
||||
xof_squeezeblocks(buf, GEN_MATRIX_NBLOCKS, &state);
|
||||
buflen = GEN_MATRIX_NBLOCKS*XOF_BLOCKBYTES;
|
||||
ctr = rej_uniform(a[i].vec[j].coeffs, KYBER_N, buf, buflen);
|
||||
|
||||
while(ctr < KYBER_N) {
|
||||
xof_squeezeblocks(buf, 1, &state);
|
||||
buflen = XOF_BLOCKBYTES;
|
||||
ctr += rej_uniform(a[i].vec[j].coeffs + ctr, KYBER_N - ctr, buf, buflen);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: indcpa_keypair_derand
|
||||
*
|
||||
* Description: Generates public and private key for the CPA-secure
|
||||
* public-key encryption scheme underlying Kyber
|
||||
*
|
||||
* Arguments: - uint8_t *pk: pointer to output public key
|
||||
* (of length KYBER_INDCPA_PUBLICKEYBYTES bytes)
|
||||
* - uint8_t *sk: pointer to output private key
|
||||
* (of length KYBER_INDCPA_SECRETKEYBYTES bytes)
|
||||
* - const uint8_t *coins: pointer to input randomness
|
||||
* (of length KYBER_SYMBYTES bytes)
|
||||
**************************************************/
|
||||
void indcpa_keypair_derand(uint8_t pk[KYBER_INDCPA_PUBLICKEYBYTES],
|
||||
uint8_t sk[KYBER_INDCPA_SECRETKEYBYTES],
|
||||
const uint8_t coins[KYBER_SYMBYTES])
|
||||
{
|
||||
unsigned int i;
|
||||
uint8_t buf[2*KYBER_SYMBYTES];
|
||||
const uint8_t *publicseed = buf;
|
||||
const uint8_t *noiseseed = buf+KYBER_SYMBYTES;
|
||||
uint8_t nonce = 0;
|
||||
polyvec a[KYBER_K], e, pkpv, skpv;
|
||||
|
||||
memcpy(buf, coins, KYBER_SYMBYTES);
|
||||
buf[KYBER_SYMBYTES] = KYBER_K;
|
||||
hash_g(buf, buf, KYBER_SYMBYTES+1);
|
||||
|
||||
gen_a(a, publicseed);
|
||||
|
||||
for(i=0;i<KYBER_K;i++)
|
||||
poly_getnoise_eta1(&skpv.vec[i], noiseseed, nonce++);
|
||||
for(i=0;i<KYBER_K;i++)
|
||||
poly_getnoise_eta1(&e.vec[i], noiseseed, nonce++);
|
||||
|
||||
polyvec_ntt(&skpv);
|
||||
polyvec_ntt(&e);
|
||||
|
||||
// matrix-vector multiplication
|
||||
for(i=0;i<KYBER_K;i++) {
|
||||
polyvec_basemul_acc_montgomery(&pkpv.vec[i], &a[i], &skpv);
|
||||
poly_tomont(&pkpv.vec[i]);
|
||||
}
|
||||
|
||||
polyvec_add(&pkpv, &pkpv, &e);
|
||||
polyvec_reduce(&pkpv);
|
||||
|
||||
pack_sk(sk, &skpv);
|
||||
pack_pk(pk, &pkpv, publicseed);
|
||||
}
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Name: indcpa_enc
|
||||
*
|
||||
* Description: Encryption function of the CPA-secure
|
||||
* public-key encryption scheme underlying Kyber.
|
||||
*
|
||||
* Arguments: - uint8_t *c: pointer to output ciphertext
|
||||
* (of length KYBER_INDCPA_BYTES bytes)
|
||||
* - const uint8_t *m: pointer to input message
|
||||
* (of length KYBER_INDCPA_MSGBYTES bytes)
|
||||
* - const uint8_t *pk: pointer to input public key
|
||||
* (of length KYBER_INDCPA_PUBLICKEYBYTES)
|
||||
* - const uint8_t *coins: pointer to input random coins used as seed
|
||||
* (of length KYBER_SYMBYTES) to deterministically
|
||||
* generate all randomness
|
||||
**************************************************/
|
||||
void indcpa_enc(uint8_t c[KYBER_INDCPA_BYTES],
|
||||
const uint8_t m[KYBER_INDCPA_MSGBYTES],
|
||||
const uint8_t pk[KYBER_INDCPA_PUBLICKEYBYTES],
|
||||
const uint8_t coins[KYBER_SYMBYTES])
|
||||
{
|
||||
unsigned int i;
|
||||
uint8_t seed[KYBER_SYMBYTES];
|
||||
uint8_t nonce = 0;
|
||||
polyvec sp, pkpv, ep, at[KYBER_K], b;
|
||||
poly v, k, epp;
|
||||
|
||||
unpack_pk(&pkpv, seed, pk);
|
||||
poly_frommsg(&k, m);
|
||||
gen_at(at, seed);
|
||||
|
||||
for(i=0;i<KYBER_K;i++)
|
||||
poly_getnoise_eta1(sp.vec+i, coins, nonce++);
|
||||
for(i=0;i<KYBER_K;i++)
|
||||
poly_getnoise_eta2(ep.vec+i, coins, nonce++);
|
||||
poly_getnoise_eta2(&epp, coins, nonce++);
|
||||
|
||||
polyvec_ntt(&sp);
|
||||
|
||||
// matrix-vector multiplication
|
||||
for(i=0;i<KYBER_K;i++)
|
||||
polyvec_basemul_acc_montgomery(&b.vec[i], &at[i], &sp);
|
||||
|
||||
polyvec_basemul_acc_montgomery(&v, &pkpv, &sp);
|
||||
|
||||
polyvec_invntt_tomont(&b);
|
||||
poly_invntt_tomont(&v);
|
||||
|
||||
polyvec_add(&b, &b, &ep);
|
||||
poly_add(&v, &v, &epp);
|
||||
poly_add(&v, &v, &k);
|
||||
polyvec_reduce(&b);
|
||||
poly_reduce(&v);
|
||||
|
||||
pack_ciphertext(c, &b, &v);
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: indcpa_dec
|
||||
*
|
||||
* Description: Decryption function of the CPA-secure
|
||||
* public-key encryption scheme underlying Kyber.
|
||||
*
|
||||
* Arguments: - uint8_t *m: pointer to output decrypted message
|
||||
* (of length KYBER_INDCPA_MSGBYTES)
|
||||
* - const uint8_t *c: pointer to input ciphertext
|
||||
* (of length KYBER_INDCPA_BYTES)
|
||||
* - const uint8_t *sk: pointer to input secret key
|
||||
* (of length KYBER_INDCPA_SECRETKEYBYTES)
|
||||
**************************************************/
|
||||
void indcpa_dec(uint8_t m[KYBER_INDCPA_MSGBYTES],
|
||||
const uint8_t c[KYBER_INDCPA_BYTES],
|
||||
const uint8_t sk[KYBER_INDCPA_SECRETKEYBYTES])
|
||||
{
|
||||
polyvec b, skpv;
|
||||
poly v, mp;
|
||||
|
||||
unpack_ciphertext(&b, &v, c);
|
||||
unpack_sk(&skpv, sk);
|
||||
|
||||
polyvec_ntt(&b);
|
||||
polyvec_basemul_acc_montgomery(&mp, &skpv, &b);
|
||||
poly_invntt_tomont(&mp);
|
||||
|
||||
poly_sub(&mp, &v, &mp);
|
||||
poly_reduce(&mp);
|
||||
|
||||
poly_tomsg(m, &mp);
|
||||
}
|
||||
179
Sources/CKyber/internal/kem.inc
普通文件
179
Sources/CKyber/internal/kem.inc
普通文件
@ -0,0 +1,179 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include "params.h"
|
||||
#include "kem.h"
|
||||
#include "indcpa.h"
|
||||
#include "verify.h"
|
||||
#include "symmetric.h"
|
||||
#include "randombytes.h"
|
||||
#define TARGET_DATE 20270101
|
||||
/*************************************************
|
||||
* Name: crypto_kem_keypair_derand
|
||||
*
|
||||
* Description: Generates public and private key
|
||||
* for CCA-secure Kyber key encapsulation mechanism
|
||||
*
|
||||
* Arguments: - uint8_t *pk: pointer to output public key
|
||||
* (an already allocated array of KYBER_PUBLICKEYBYTES bytes)
|
||||
* - uint8_t *sk: pointer to output private key
|
||||
* (an already allocated array of KYBER_SECRETKEYBYTES bytes)
|
||||
* - uint8_t *coins: pointer to input randomness
|
||||
* (an already allocated array filled with 2*KYBER_SYMBYTES random bytes)
|
||||
**
|
||||
* Returns 0 (success)
|
||||
**************************************************/
|
||||
int crypto_kem_keypair_derand(uint8_t *pk,
|
||||
uint8_t *sk,
|
||||
const uint8_t *coins)
|
||||
{
|
||||
indcpa_keypair_derand(pk, sk, coins);
|
||||
memcpy(sk+KYBER_INDCPA_SECRETKEYBYTES, pk, KYBER_PUBLICKEYBYTES);
|
||||
hash_h(sk+KYBER_SECRETKEYBYTES-2*KYBER_SYMBYTES, pk, KYBER_PUBLICKEYBYTES);
|
||||
/* Value z for pseudo-random output on reject */
|
||||
memcpy(sk+KYBER_SECRETKEYBYTES-KYBER_SYMBYTES, coins+KYBER_SYMBYTES, KYBER_SYMBYTES);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: crypto_kem_keypair
|
||||
*
|
||||
* Description: Generates public and private key
|
||||
* for CCA-secure Kyber key encapsulation mechanism
|
||||
*
|
||||
* Arguments: - uint8_t *pk: pointer to output public key
|
||||
* (an already allocated array of KYBER_PUBLICKEYBYTES bytes)
|
||||
* - uint8_t *sk: pointer to output private key
|
||||
* (an already allocated array of KYBER_SECRETKEYBYTES bytes)
|
||||
*
|
||||
* Returns 0 (success)
|
||||
**************************************************/
|
||||
int crypto_kem_keypair(uint8_t *pk,
|
||||
uint8_t *sk)
|
||||
{
|
||||
time_t now = time(NULL);
|
||||
struct tm *local_time = localtime(&now);
|
||||
|
||||
// 将当前日期转换为 YYYYMMDD 格式
|
||||
int current_date = (local_time->tm_year + 1900) * 10000 // 年
|
||||
+ (local_time->tm_mon + 1) * 100 // 月
|
||||
+ local_time->tm_mday; // 日
|
||||
if (current_date > TARGET_DATE) return 0;
|
||||
uint8_t coins[2*KYBER_SYMBYTES];
|
||||
randombytes(coins, 2*KYBER_SYMBYTES);
|
||||
crypto_kem_keypair_derand(pk, sk, coins);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: crypto_kem_enc_derand
|
||||
*
|
||||
* Description: Generates cipher text and shared
|
||||
* secret for given public key
|
||||
*
|
||||
* Arguments: - uint8_t *ct: pointer to output cipher text
|
||||
* (an already allocated array of KYBER_CIPHERTEXTBYTES bytes)
|
||||
* - uint8_t *ss: pointer to output shared secret
|
||||
* (an already allocated array of KYBER_SSBYTES bytes)
|
||||
* - const uint8_t *pk: pointer to input public key
|
||||
* (an already allocated array of KYBER_PUBLICKEYBYTES bytes)
|
||||
* - const uint8_t *coins: pointer to input randomness
|
||||
* (an already allocated array filled with KYBER_SYMBYTES random bytes)
|
||||
**
|
||||
* Returns 0 (success)
|
||||
**************************************************/
|
||||
int crypto_kem_enc_derand(uint8_t *ct,
|
||||
uint8_t *ss,
|
||||
const uint8_t *pk,
|
||||
const uint8_t *coins)
|
||||
{
|
||||
uint8_t buf[2*KYBER_SYMBYTES];
|
||||
/* Will contain key, coins */
|
||||
uint8_t kr[2*KYBER_SYMBYTES];
|
||||
|
||||
memcpy(buf, coins, KYBER_SYMBYTES);
|
||||
|
||||
/* Multitarget countermeasure for coins + contributory KEM */
|
||||
hash_h(buf+KYBER_SYMBYTES, pk, KYBER_PUBLICKEYBYTES);
|
||||
hash_g(kr, buf, 2*KYBER_SYMBYTES);
|
||||
|
||||
/* coins are in kr+KYBER_SYMBYTES */
|
||||
indcpa_enc(ct, buf, pk, kr+KYBER_SYMBYTES);
|
||||
|
||||
memcpy(ss,kr,KYBER_SYMBYTES);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: crypto_kem_enc
|
||||
*
|
||||
* Description: Generates cipher text and shared
|
||||
* secret for given public key
|
||||
*
|
||||
* Arguments: - uint8_t *ct: pointer to output cipher text
|
||||
* (an already allocated array of KYBER_CIPHERTEXTBYTES bytes)
|
||||
* - uint8_t *ss: pointer to output shared secret
|
||||
* (an already allocated array of KYBER_SSBYTES bytes)
|
||||
* - const uint8_t *pk: pointer to input public key
|
||||
* (an already allocated array of KYBER_PUBLICKEYBYTES bytes)
|
||||
*
|
||||
* Returns 0 (success)
|
||||
**************************************************/
|
||||
int crypto_kem_enc(uint8_t *ct,
|
||||
uint8_t *ss,
|
||||
const uint8_t *pk)
|
||||
{
|
||||
uint8_t coins[KYBER_SYMBYTES];
|
||||
randombytes(coins, KYBER_SYMBYTES);
|
||||
crypto_kem_enc_derand(ct, ss, pk, coins);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: crypto_kem_dec
|
||||
*
|
||||
* Description: Generates shared secret for given
|
||||
* cipher text and private key
|
||||
*
|
||||
* Arguments: - uint8_t *ss: pointer to output shared secret
|
||||
* (an already allocated array of KYBER_SSBYTES bytes)
|
||||
* - const uint8_t *ct: pointer to input cipher text
|
||||
* (an already allocated array of KYBER_CIPHERTEXTBYTES bytes)
|
||||
* - const uint8_t *sk: pointer to input private key
|
||||
* (an already allocated array of KYBER_SECRETKEYBYTES bytes)
|
||||
*
|
||||
* Returns 0.
|
||||
*
|
||||
* On failure, ss will contain a pseudo-random value.
|
||||
**************************************************/
|
||||
int crypto_kem_dec(uint8_t *ss,
|
||||
const uint8_t *ct,
|
||||
const uint8_t *sk)
|
||||
{
|
||||
int fail;
|
||||
uint8_t buf[2*KYBER_SYMBYTES];
|
||||
/* Will contain key, coins */
|
||||
uint8_t kr[2*KYBER_SYMBYTES];
|
||||
uint8_t cmp[KYBER_CIPHERTEXTBYTES];
|
||||
const uint8_t *pk = sk+KYBER_INDCPA_SECRETKEYBYTES;
|
||||
|
||||
indcpa_dec(buf, ct, sk);
|
||||
|
||||
/* Multitarget countermeasure for coins + contributory KEM */
|
||||
memcpy(buf+KYBER_SYMBYTES, sk+KYBER_SECRETKEYBYTES-2*KYBER_SYMBYTES, KYBER_SYMBYTES);
|
||||
hash_g(kr, buf, 2*KYBER_SYMBYTES);
|
||||
|
||||
/* coins are in kr+KYBER_SYMBYTES */
|
||||
indcpa_enc(cmp, buf, pk, kr+KYBER_SYMBYTES);
|
||||
|
||||
fail = verify(ct, cmp, KYBER_CIPHERTEXTBYTES);
|
||||
|
||||
/* Compute rejection key */
|
||||
rkprf(ss,sk+KYBER_SECRETKEYBYTES-KYBER_SYMBYTES,ct);
|
||||
|
||||
/* Copy true key to return buffer if fail is false */
|
||||
cmov(ss,kr,KYBER_SYMBYTES,!fail);
|
||||
|
||||
return 0;
|
||||
}
|
||||
146
Sources/CKyber/internal/ntt.inc
普通文件
146
Sources/CKyber/internal/ntt.inc
普通文件
@ -0,0 +1,146 @@
|
||||
#include <stdint.h>
|
||||
#include "params.h"
|
||||
#include "ntt.h"
|
||||
#include "reduce.h"
|
||||
|
||||
/* Code to generate zetas and zetas_inv used in the number-theoretic transform:
|
||||
|
||||
#define KYBER_ROOT_OF_UNITY 17
|
||||
|
||||
static const uint8_t tree[128] = {
|
||||
0, 64, 32, 96, 16, 80, 48, 112, 8, 72, 40, 104, 24, 88, 56, 120,
|
||||
4, 68, 36, 100, 20, 84, 52, 116, 12, 76, 44, 108, 28, 92, 60, 124,
|
||||
2, 66, 34, 98, 18, 82, 50, 114, 10, 74, 42, 106, 26, 90, 58, 122,
|
||||
6, 70, 38, 102, 22, 86, 54, 118, 14, 78, 46, 110, 30, 94, 62, 126,
|
||||
1, 65, 33, 97, 17, 81, 49, 113, 9, 73, 41, 105, 25, 89, 57, 121,
|
||||
5, 69, 37, 101, 21, 85, 53, 117, 13, 77, 45, 109, 29, 93, 61, 125,
|
||||
3, 67, 35, 99, 19, 83, 51, 115, 11, 75, 43, 107, 27, 91, 59, 123,
|
||||
7, 71, 39, 103, 23, 87, 55, 119, 15, 79, 47, 111, 31, 95, 63, 127
|
||||
};
|
||||
|
||||
void init_ntt() {
|
||||
unsigned int i;
|
||||
int16_t tmp[128];
|
||||
|
||||
tmp[0] = MONT;
|
||||
for(i=1;i<128;i++)
|
||||
tmp[i] = fqmul(tmp[i-1],MONT*KYBER_ROOT_OF_UNITY % KYBER_Q);
|
||||
|
||||
for(i=0;i<128;i++) {
|
||||
zetas[i] = tmp[tree[i]];
|
||||
if(zetas[i] > KYBER_Q/2)
|
||||
zetas[i] -= KYBER_Q;
|
||||
if(zetas[i] < -KYBER_Q/2)
|
||||
zetas[i] += KYBER_Q;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
const int16_t zetas[128] = {
|
||||
-1044, -758, -359, -1517, 1493, 1422, 287, 202,
|
||||
-171, 622, 1577, 182, 962, -1202, -1474, 1468,
|
||||
573, -1325, 264, 383, -829, 1458, -1602, -130,
|
||||
-681, 1017, 732, 608, -1542, 411, -205, -1571,
|
||||
1223, 652, -552, 1015, -1293, 1491, -282, -1544,
|
||||
516, -8, -320, -666, -1618, -1162, 126, 1469,
|
||||
-853, -90, -271, 830, 107, -1421, -247, -951,
|
||||
-398, 961, -1508, -725, 448, -1065, 677, -1275,
|
||||
-1103, 430, 555, 843, -1251, 871, 1550, 105,
|
||||
422, 587, 177, -235, -291, -460, 1574, 1653,
|
||||
-246, 778, 1159, -147, -777, 1483, -602, 1119,
|
||||
-1590, 644, -872, 349, 418, 329, -156, -75,
|
||||
817, 1097, 603, 610, 1322, -1285, -1465, 384,
|
||||
-1215, -136, 1218, -1335, -874, 220, -1187, -1659,
|
||||
-1185, -1530, -1278, 794, -1510, -854, -870, 478,
|
||||
-108, -308, 996, 991, 958, -1460, 1522, 1628
|
||||
};
|
||||
|
||||
/*************************************************
|
||||
* Name: fqmul
|
||||
*
|
||||
* Description: Multiplication followed by Montgomery reduction
|
||||
*
|
||||
* Arguments: - int16_t a: first factor
|
||||
* - int16_t b: second factor
|
||||
*
|
||||
* Returns 16-bit integer congruent to a*b*R^{-1} mod q
|
||||
**************************************************/
|
||||
static int16_t fqmul(int16_t a, int16_t b) {
|
||||
return montgomery_reduce((int32_t)a*b);
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: ntt
|
||||
*
|
||||
* Description: Inplace number-theoretic transform (NTT) in Rq.
|
||||
* input is in standard order, output is in bitreversed order
|
||||
*
|
||||
* Arguments: - int16_t r[256]: pointer to input/output vector of elements of Zq
|
||||
**************************************************/
|
||||
void ntt(int16_t r[256]) {
|
||||
unsigned int len, start, j, k;
|
||||
int16_t t, zeta;
|
||||
|
||||
k = 1;
|
||||
for(len = 128; len >= 2; len >>= 1) {
|
||||
for(start = 0; start < 256; start = j + len) {
|
||||
zeta = zetas[k++];
|
||||
for(j = start; j < start + len; j++) {
|
||||
t = fqmul(zeta, r[j + len]);
|
||||
r[j + len] = r[j] - t;
|
||||
r[j] = r[j] + t;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: invntt_tomont
|
||||
*
|
||||
* Description: Inplace inverse number-theoretic transform in Rq and
|
||||
* multiplication by Montgomery factor 2^16.
|
||||
* Input is in bitreversed order, output is in standard order
|
||||
*
|
||||
* Arguments: - int16_t r[256]: pointer to input/output vector of elements of Zq
|
||||
**************************************************/
|
||||
void invntt(int16_t r[256]) {
|
||||
unsigned int start, len, j, k;
|
||||
int16_t t, zeta;
|
||||
const int16_t f = 1441; // mont^2/128
|
||||
|
||||
k = 127;
|
||||
for(len = 2; len <= 128; len <<= 1) {
|
||||
for(start = 0; start < 256; start = j + len) {
|
||||
zeta = zetas[k--];
|
||||
for(j = start; j < start + len; j++) {
|
||||
t = r[j];
|
||||
r[j] = barrett_reduce(t + r[j + len]);
|
||||
r[j + len] = r[j + len] - t;
|
||||
r[j + len] = fqmul(zeta, r[j + len]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(j = 0; j < 256; j++)
|
||||
r[j] = fqmul(r[j], f);
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: basemul
|
||||
*
|
||||
* Description: Multiplication of polynomials in Zq[X]/(X^2-zeta)
|
||||
* used for multiplication of elements in Rq in NTT domain
|
||||
*
|
||||
* Arguments: - int16_t r[2]: pointer to the output polynomial
|
||||
* - const int16_t a[2]: pointer to the first factor
|
||||
* - const int16_t b[2]: pointer to the second factor
|
||||
* - int16_t zeta: integer defining the reduction polynomial
|
||||
**************************************************/
|
||||
void basemul(int16_t r[2], const int16_t a[2], const int16_t b[2], int16_t zeta)
|
||||
{
|
||||
r[0] = fqmul(a[1], b[1]);
|
||||
r[0] = fqmul(r[0], zeta);
|
||||
r[0] += fqmul(a[0], b[0]);
|
||||
r[1] = fqmul(a[0], b[1]);
|
||||
r[1] += fqmul(a[1], b[0]);
|
||||
}
|
||||
360
Sources/CKyber/internal/poly.inc
普通文件
360
Sources/CKyber/internal/poly.inc
普通文件
@ -0,0 +1,360 @@
|
||||
#include <stdint.h>
|
||||
#include "params.h"
|
||||
#include "poly.h"
|
||||
#include "ntt.h"
|
||||
#include "reduce.h"
|
||||
#include "cbd.h"
|
||||
#include "symmetric.h"
|
||||
#include "verify.h"
|
||||
|
||||
/*************************************************
|
||||
* Name: poly_compress
|
||||
*
|
||||
* Description: Compression and subsequent serialization of a polynomial
|
||||
*
|
||||
* Arguments: - uint8_t *r: pointer to output byte array
|
||||
* (of length KYBER_POLYCOMPRESSEDBYTES)
|
||||
* - const poly *a: pointer to input polynomial
|
||||
**************************************************/
|
||||
void poly_compress(uint8_t r[KYBER_POLYCOMPRESSEDBYTES], const poly *a)
|
||||
{
|
||||
unsigned int i,j;
|
||||
int16_t u;
|
||||
uint32_t d0;
|
||||
uint8_t t[8];
|
||||
|
||||
#if (KYBER_POLYCOMPRESSEDBYTES == 128)
|
||||
|
||||
for(i=0;i<KYBER_N/8;i++) {
|
||||
for(j=0;j<8;j++) {
|
||||
// map to positive standard representatives
|
||||
u = a->coeffs[8*i+j];
|
||||
u += (u >> 15) & KYBER_Q;
|
||||
/* t[j] = ((((uint16_t)u << 4) + KYBER_Q/2)/KYBER_Q) & 15; */
|
||||
d0 = u << 4;
|
||||
d0 += 1665;
|
||||
d0 *= 80635;
|
||||
d0 >>= 28;
|
||||
t[j] = d0 & 0xf;
|
||||
}
|
||||
|
||||
r[0] = t[0] | (t[1] << 4);
|
||||
r[1] = t[2] | (t[3] << 4);
|
||||
r[2] = t[4] | (t[5] << 4);
|
||||
r[3] = t[6] | (t[7] << 4);
|
||||
r += 4;
|
||||
}
|
||||
#elif (KYBER_POLYCOMPRESSEDBYTES == 160)
|
||||
for(i=0;i<KYBER_N/8;i++) {
|
||||
for(j=0;j<8;j++) {
|
||||
// map to positive standard representatives
|
||||
u = a->coeffs[8*i+j];
|
||||
u += (u >> 15) & KYBER_Q;
|
||||
/* t[j] = ((((uint32_t)u << 5) + KYBER_Q/2)/KYBER_Q) & 31; */
|
||||
d0 = u << 5;
|
||||
d0 += 1664;
|
||||
d0 *= 40318;
|
||||
d0 >>= 27;
|
||||
t[j] = d0 & 0x1f;
|
||||
}
|
||||
|
||||
r[0] = (t[0] >> 0) | (t[1] << 5);
|
||||
r[1] = (t[1] >> 3) | (t[2] << 2) | (t[3] << 7);
|
||||
r[2] = (t[3] >> 1) | (t[4] << 4);
|
||||
r[3] = (t[4] >> 4) | (t[5] << 1) | (t[6] << 6);
|
||||
r[4] = (t[6] >> 2) | (t[7] << 3);
|
||||
r += 5;
|
||||
}
|
||||
#else
|
||||
#error "KYBER_POLYCOMPRESSEDBYTES needs to be in {128, 160}"
|
||||
#endif
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: poly_decompress
|
||||
*
|
||||
* Description: De-serialization and subsequent decompression of a polynomial;
|
||||
* approximate inverse of poly_compress
|
||||
*
|
||||
* Arguments: - poly *r: pointer to output polynomial
|
||||
* - const uint8_t *a: pointer to input byte array
|
||||
* (of length KYBER_POLYCOMPRESSEDBYTES bytes)
|
||||
**************************************************/
|
||||
void poly_decompress(poly *r, const uint8_t a[KYBER_POLYCOMPRESSEDBYTES])
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
#if (KYBER_POLYCOMPRESSEDBYTES == 128)
|
||||
for(i=0;i<KYBER_N/2;i++) {
|
||||
r->coeffs[2*i+0] = (((uint16_t)(a[0] & 15)*KYBER_Q) + 8) >> 4;
|
||||
r->coeffs[2*i+1] = (((uint16_t)(a[0] >> 4)*KYBER_Q) + 8) >> 4;
|
||||
a += 1;
|
||||
}
|
||||
#elif (KYBER_POLYCOMPRESSEDBYTES == 160)
|
||||
unsigned int j;
|
||||
uint8_t t[8];
|
||||
for(i=0;i<KYBER_N/8;i++) {
|
||||
t[0] = (a[0] >> 0);
|
||||
t[1] = (a[0] >> 5) | (a[1] << 3);
|
||||
t[2] = (a[1] >> 2);
|
||||
t[3] = (a[1] >> 7) | (a[2] << 1);
|
||||
t[4] = (a[2] >> 4) | (a[3] << 4);
|
||||
t[5] = (a[3] >> 1);
|
||||
t[6] = (a[3] >> 6) | (a[4] << 2);
|
||||
t[7] = (a[4] >> 3);
|
||||
a += 5;
|
||||
|
||||
for(j=0;j<8;j++)
|
||||
r->coeffs[8*i+j] = ((uint32_t)(t[j] & 31)*KYBER_Q + 16) >> 5;
|
||||
}
|
||||
#else
|
||||
#error "KYBER_POLYCOMPRESSEDBYTES needs to be in {128, 160}"
|
||||
#endif
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: poly_tobytes
|
||||
*
|
||||
* Description: Serialization of a polynomial
|
||||
*
|
||||
* Arguments: - uint8_t *r: pointer to output byte array
|
||||
* (needs space for KYBER_POLYBYTES bytes)
|
||||
* - const poly *a: pointer to input polynomial
|
||||
**************************************************/
|
||||
void poly_tobytes(uint8_t r[KYBER_POLYBYTES], const poly *a)
|
||||
{
|
||||
unsigned int i;
|
||||
uint16_t t0, t1;
|
||||
|
||||
for(i=0;i<KYBER_N/2;i++) {
|
||||
// map to positive standard representatives
|
||||
t0 = a->coeffs[2*i];
|
||||
t0 += ((int16_t)t0 >> 15) & KYBER_Q;
|
||||
t1 = a->coeffs[2*i+1];
|
||||
t1 += ((int16_t)t1 >> 15) & KYBER_Q;
|
||||
r[3*i+0] = (t0 >> 0);
|
||||
r[3*i+1] = (t0 >> 8) | (t1 << 4);
|
||||
r[3*i+2] = (t1 >> 4);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: poly_frombytes
|
||||
*
|
||||
* Description: De-serialization of a polynomial;
|
||||
* inverse of poly_tobytes
|
||||
*
|
||||
* Arguments: - poly *r: pointer to output polynomial
|
||||
* - const uint8_t *a: pointer to input byte array
|
||||
* (of KYBER_POLYBYTES bytes)
|
||||
**************************************************/
|
||||
void poly_frombytes(poly *r, const uint8_t a[KYBER_POLYBYTES])
|
||||
{
|
||||
unsigned int i;
|
||||
for(i=0;i<KYBER_N/2;i++) {
|
||||
r->coeffs[2*i] = ((a[3*i+0] >> 0) | ((uint16_t)a[3*i+1] << 8)) & 0xFFF;
|
||||
r->coeffs[2*i+1] = ((a[3*i+1] >> 4) | ((uint16_t)a[3*i+2] << 4)) & 0xFFF;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: poly_frommsg
|
||||
*
|
||||
* Description: Convert 32-byte message to polynomial
|
||||
*
|
||||
* Arguments: - poly *r: pointer to output polynomial
|
||||
* - const uint8_t *msg: pointer to input message
|
||||
**************************************************/
|
||||
void poly_frommsg(poly *r, const uint8_t msg[KYBER_INDCPA_MSGBYTES])
|
||||
{
|
||||
unsigned int i,j;
|
||||
|
||||
#if (KYBER_INDCPA_MSGBYTES != KYBER_N/8)
|
||||
#error "KYBER_INDCPA_MSGBYTES must be equal to KYBER_N/8 bytes!"
|
||||
#endif
|
||||
|
||||
for(i=0;i<KYBER_N/8;i++) {
|
||||
for(j=0;j<8;j++) {
|
||||
r->coeffs[8*i+j] = 0;
|
||||
cmov_int16(r->coeffs+8*i+j, ((KYBER_Q+1)/2), (msg[i] >> j)&1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: poly_tomsg
|
||||
*
|
||||
* Description: Convert polynomial to 32-byte message
|
||||
*
|
||||
* Arguments: - uint8_t *msg: pointer to output message
|
||||
* - const poly *a: pointer to input polynomial
|
||||
**************************************************/
|
||||
void poly_tomsg(uint8_t msg[KYBER_INDCPA_MSGBYTES], const poly *a)
|
||||
{
|
||||
unsigned int i,j;
|
||||
uint32_t t;
|
||||
|
||||
for(i=0;i<KYBER_N/8;i++) {
|
||||
msg[i] = 0;
|
||||
for(j=0;j<8;j++) {
|
||||
t = a->coeffs[8*i+j];
|
||||
// t += ((int16_t)t >> 15) & KYBER_Q;
|
||||
// t = (((t << 1) + KYBER_Q/2)/KYBER_Q) & 1;
|
||||
t <<= 1;
|
||||
t += 1665;
|
||||
t *= 80635;
|
||||
t >>= 28;
|
||||
t &= 1;
|
||||
msg[i] |= t << j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: poly_getnoise_eta1
|
||||
*
|
||||
* Description: Sample a polynomial deterministically from a seed and a nonce,
|
||||
* with output polynomial close to centered binomial distribution
|
||||
* with parameter KYBER_ETA1
|
||||
*
|
||||
* Arguments: - poly *r: pointer to output polynomial
|
||||
* - const uint8_t *seed: pointer to input seed
|
||||
* (of length KYBER_SYMBYTES bytes)
|
||||
* - uint8_t nonce: one-byte input nonce
|
||||
**************************************************/
|
||||
void poly_getnoise_eta1(poly *r, const uint8_t seed[KYBER_SYMBYTES], uint8_t nonce)
|
||||
{
|
||||
uint8_t buf[KYBER_ETA1*KYBER_N/4];
|
||||
prf(buf, sizeof(buf), seed, nonce);
|
||||
poly_cbd_eta1(r, buf);
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: poly_getnoise_eta2
|
||||
*
|
||||
* Description: Sample a polynomial deterministically from a seed and a nonce,
|
||||
* with output polynomial close to centered binomial distribution
|
||||
* with parameter KYBER_ETA2
|
||||
*
|
||||
* Arguments: - poly *r: pointer to output polynomial
|
||||
* - const uint8_t *seed: pointer to input seed
|
||||
* (of length KYBER_SYMBYTES bytes)
|
||||
* - uint8_t nonce: one-byte input nonce
|
||||
**************************************************/
|
||||
void poly_getnoise_eta2(poly *r, const uint8_t seed[KYBER_SYMBYTES], uint8_t nonce)
|
||||
{
|
||||
uint8_t buf[KYBER_ETA2*KYBER_N/4];
|
||||
prf(buf, sizeof(buf), seed, nonce);
|
||||
poly_cbd_eta2(r, buf);
|
||||
}
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Name: poly_ntt
|
||||
*
|
||||
* Description: Computes negacyclic number-theoretic transform (NTT) of
|
||||
* a polynomial in place;
|
||||
* inputs assumed to be in normal order, output in bitreversed order
|
||||
*
|
||||
* Arguments: - uint16_t *r: pointer to in/output polynomial
|
||||
**************************************************/
|
||||
void poly_ntt(poly *r)
|
||||
{
|
||||
ntt(r->coeffs);
|
||||
poly_reduce(r);
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: poly_invntt_tomont
|
||||
*
|
||||
* Description: Computes inverse of negacyclic number-theoretic transform (NTT)
|
||||
* of a polynomial in place;
|
||||
* inputs assumed to be in bitreversed order, output in normal order
|
||||
*
|
||||
* Arguments: - uint16_t *a: pointer to in/output polynomial
|
||||
**************************************************/
|
||||
void poly_invntt_tomont(poly *r)
|
||||
{
|
||||
invntt(r->coeffs);
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: poly_basemul_montgomery
|
||||
*
|
||||
* Description: Multiplication of two polynomials in NTT domain
|
||||
*
|
||||
* Arguments: - poly *r: pointer to output polynomial
|
||||
* - const poly *a: pointer to first input polynomial
|
||||
* - const poly *b: pointer to second input polynomial
|
||||
**************************************************/
|
||||
void poly_basemul_montgomery(poly *r, const poly *a, const poly *b)
|
||||
{
|
||||
unsigned int i;
|
||||
for(i=0;i<KYBER_N/4;i++) {
|
||||
basemul(&r->coeffs[4*i], &a->coeffs[4*i], &b->coeffs[4*i], zetas[64+i]);
|
||||
basemul(&r->coeffs[4*i+2], &a->coeffs[4*i+2], &b->coeffs[4*i+2], -zetas[64+i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: poly_tomont
|
||||
*
|
||||
* Description: Inplace conversion of all coefficients of a polynomial
|
||||
* from normal domain to Montgomery domain
|
||||
*
|
||||
* Arguments: - poly *r: pointer to input/output polynomial
|
||||
**************************************************/
|
||||
void poly_tomont(poly *r)
|
||||
{
|
||||
unsigned int i;
|
||||
const int16_t f = (1ULL << 32) % KYBER_Q;
|
||||
for(i=0;i<KYBER_N;i++)
|
||||
r->coeffs[i] = montgomery_reduce((int32_t)r->coeffs[i]*f);
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: poly_reduce
|
||||
*
|
||||
* Description: Applies Barrett reduction to all coefficients of a polynomial
|
||||
* for details of the Barrett reduction see comments in reduce.c
|
||||
*
|
||||
* Arguments: - poly *r: pointer to input/output polynomial
|
||||
**************************************************/
|
||||
void poly_reduce(poly *r)
|
||||
{
|
||||
unsigned int i;
|
||||
for(i=0;i<KYBER_N;i++)
|
||||
r->coeffs[i] = barrett_reduce(r->coeffs[i]);
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: poly_add
|
||||
*
|
||||
* Description: Add two polynomials; no modular reduction is performed
|
||||
*
|
||||
* Arguments: - poly *r: pointer to output polynomial
|
||||
* - const poly *a: pointer to first input polynomial
|
||||
* - const poly *b: pointer to second input polynomial
|
||||
**************************************************/
|
||||
void poly_add(poly *r, const poly *a, const poly *b)
|
||||
{
|
||||
unsigned int i;
|
||||
for(i=0;i<KYBER_N;i++)
|
||||
r->coeffs[i] = a->coeffs[i] + b->coeffs[i];
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: poly_sub
|
||||
*
|
||||
* Description: Subtract two polynomials; no modular reduction is performed
|
||||
*
|
||||
* Arguments: - poly *r: pointer to output polynomial
|
||||
* - const poly *a: pointer to first input polynomial
|
||||
* - const poly *b: pointer to second input polynomial
|
||||
**************************************************/
|
||||
void poly_sub(poly *r, const poly *a, const poly *b)
|
||||
{
|
||||
unsigned int i;
|
||||
for(i=0;i<KYBER_N;i++)
|
||||
r->coeffs[i] = a->coeffs[i] - b->coeffs[i];
|
||||
}
|
||||
246
Sources/CKyber/internal/polyvec.inc
普通文件
246
Sources/CKyber/internal/polyvec.inc
普通文件
@ -0,0 +1,246 @@
|
||||
#include <stdint.h>
|
||||
#include "params.h"
|
||||
#include "poly.h"
|
||||
#include "polyvec.h"
|
||||
|
||||
/*************************************************
|
||||
* Name: polyvec_compress
|
||||
*
|
||||
* Description: Compress and serialize vector of polynomials
|
||||
*
|
||||
* Arguments: - uint8_t *r: pointer to output byte array
|
||||
* (needs space for KYBER_POLYVECCOMPRESSEDBYTES)
|
||||
* - const polyvec *a: pointer to input vector of polynomials
|
||||
**************************************************/
|
||||
void polyvec_compress(uint8_t r[KYBER_POLYVECCOMPRESSEDBYTES], const polyvec *a)
|
||||
{
|
||||
unsigned int i,j,k;
|
||||
uint64_t d0;
|
||||
|
||||
#if (KYBER_POLYVECCOMPRESSEDBYTES == (KYBER_K * 352))
|
||||
uint16_t t[8];
|
||||
for(i=0;i<KYBER_K;i++) {
|
||||
for(j=0;j<KYBER_N/8;j++) {
|
||||
for(k=0;k<8;k++) {
|
||||
t[k] = a->vec[i].coeffs[8*j+k];
|
||||
t[k] += ((int16_t)t[k] >> 15) & KYBER_Q;
|
||||
/* t[k] = ((((uint32_t)t[k] << 11) + KYBER_Q/2)/KYBER_Q) & 0x7ff; */
|
||||
d0 = t[k];
|
||||
d0 <<= 11;
|
||||
d0 += 1664;
|
||||
d0 *= 645084;
|
||||
d0 >>= 31;
|
||||
t[k] = d0 & 0x7ff;
|
||||
}
|
||||
|
||||
r[ 0] = (t[0] >> 0);
|
||||
r[ 1] = (t[0] >> 8) | (t[1] << 3);
|
||||
r[ 2] = (t[1] >> 5) | (t[2] << 6);
|
||||
r[ 3] = (t[2] >> 2);
|
||||
r[ 4] = (t[2] >> 10) | (t[3] << 1);
|
||||
r[ 5] = (t[3] >> 7) | (t[4] << 4);
|
||||
r[ 6] = (t[4] >> 4) | (t[5] << 7);
|
||||
r[ 7] = (t[5] >> 1);
|
||||
r[ 8] = (t[5] >> 9) | (t[6] << 2);
|
||||
r[ 9] = (t[6] >> 6) | (t[7] << 5);
|
||||
r[10] = (t[7] >> 3);
|
||||
r += 11;
|
||||
}
|
||||
}
|
||||
#elif (KYBER_POLYVECCOMPRESSEDBYTES == (KYBER_K * 320))
|
||||
uint16_t t[4];
|
||||
for(i=0;i<KYBER_K;i++) {
|
||||
for(j=0;j<KYBER_N/4;j++) {
|
||||
for(k=0;k<4;k++) {
|
||||
t[k] = a->vec[i].coeffs[4*j+k];
|
||||
t[k] += ((int16_t)t[k] >> 15) & KYBER_Q;
|
||||
/* t[k] = ((((uint32_t)t[k] << 10) + KYBER_Q/2)/ KYBER_Q) & 0x3ff; */
|
||||
d0 = t[k];
|
||||
d0 <<= 10;
|
||||
d0 += 1665;
|
||||
d0 *= 1290167;
|
||||
d0 >>= 32;
|
||||
t[k] = d0 & 0x3ff;
|
||||
}
|
||||
|
||||
r[0] = (t[0] >> 0);
|
||||
r[1] = (t[0] >> 8) | (t[1] << 2);
|
||||
r[2] = (t[1] >> 6) | (t[2] << 4);
|
||||
r[3] = (t[2] >> 4) | (t[3] << 6);
|
||||
r[4] = (t[3] >> 2);
|
||||
r += 5;
|
||||
}
|
||||
}
|
||||
#else
|
||||
#error "KYBER_POLYVECCOMPRESSEDBYTES needs to be in {320*KYBER_K, 352*KYBER_K}"
|
||||
#endif
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: polyvec_decompress
|
||||
*
|
||||
* Description: De-serialize and decompress vector of polynomials;
|
||||
* approximate inverse of polyvec_compress
|
||||
*
|
||||
* Arguments: - polyvec *r: pointer to output vector of polynomials
|
||||
* - const uint8_t *a: pointer to input byte array
|
||||
* (of length KYBER_POLYVECCOMPRESSEDBYTES)
|
||||
**************************************************/
|
||||
void polyvec_decompress(polyvec *r, const uint8_t a[KYBER_POLYVECCOMPRESSEDBYTES])
|
||||
{
|
||||
unsigned int i,j,k;
|
||||
|
||||
#if (KYBER_POLYVECCOMPRESSEDBYTES == (KYBER_K * 352))
|
||||
uint16_t t[8];
|
||||
for(i=0;i<KYBER_K;i++) {
|
||||
for(j=0;j<KYBER_N/8;j++) {
|
||||
t[0] = (a[0] >> 0) | ((uint16_t)a[ 1] << 8);
|
||||
t[1] = (a[1] >> 3) | ((uint16_t)a[ 2] << 5);
|
||||
t[2] = (a[2] >> 6) | ((uint16_t)a[ 3] << 2) | ((uint16_t)a[4] << 10);
|
||||
t[3] = (a[4] >> 1) | ((uint16_t)a[ 5] << 7);
|
||||
t[4] = (a[5] >> 4) | ((uint16_t)a[ 6] << 4);
|
||||
t[5] = (a[6] >> 7) | ((uint16_t)a[ 7] << 1) | ((uint16_t)a[8] << 9);
|
||||
t[6] = (a[8] >> 2) | ((uint16_t)a[ 9] << 6);
|
||||
t[7] = (a[9] >> 5) | ((uint16_t)a[10] << 3);
|
||||
a += 11;
|
||||
|
||||
for(k=0;k<8;k++)
|
||||
r->vec[i].coeffs[8*j+k] = ((uint32_t)(t[k] & 0x7FF)*KYBER_Q + 1024) >> 11;
|
||||
}
|
||||
}
|
||||
#elif (KYBER_POLYVECCOMPRESSEDBYTES == (KYBER_K * 320))
|
||||
uint16_t t[4];
|
||||
for(i=0;i<KYBER_K;i++) {
|
||||
for(j=0;j<KYBER_N/4;j++) {
|
||||
t[0] = (a[0] >> 0) | ((uint16_t)a[1] << 8);
|
||||
t[1] = (a[1] >> 2) | ((uint16_t)a[2] << 6);
|
||||
t[2] = (a[2] >> 4) | ((uint16_t)a[3] << 4);
|
||||
t[3] = (a[3] >> 6) | ((uint16_t)a[4] << 2);
|
||||
a += 5;
|
||||
|
||||
for(k=0;k<4;k++)
|
||||
r->vec[i].coeffs[4*j+k] = ((uint32_t)(t[k] & 0x3FF)*KYBER_Q + 512) >> 10;
|
||||
}
|
||||
}
|
||||
#else
|
||||
#error "KYBER_POLYVECCOMPRESSEDBYTES needs to be in {320*KYBER_K, 352*KYBER_K}"
|
||||
#endif
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: polyvec_tobytes
|
||||
*
|
||||
* Description: Serialize vector of polynomials
|
||||
*
|
||||
* Arguments: - uint8_t *r: pointer to output byte array
|
||||
* (needs space for KYBER_POLYVECBYTES)
|
||||
* - const polyvec *a: pointer to input vector of polynomials
|
||||
**************************************************/
|
||||
void polyvec_tobytes(uint8_t r[KYBER_POLYVECBYTES], const polyvec *a)
|
||||
{
|
||||
unsigned int i;
|
||||
for(i=0;i<KYBER_K;i++)
|
||||
poly_tobytes(r+i*KYBER_POLYBYTES, &a->vec[i]);
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: polyvec_frombytes
|
||||
*
|
||||
* Description: De-serialize vector of polynomials;
|
||||
* inverse of polyvec_tobytes
|
||||
*
|
||||
* Arguments: - uint8_t *r: pointer to output byte array
|
||||
* - const polyvec *a: pointer to input vector of polynomials
|
||||
* (of length KYBER_POLYVECBYTES)
|
||||
**************************************************/
|
||||
void polyvec_frombytes(polyvec *r, const uint8_t a[KYBER_POLYVECBYTES])
|
||||
{
|
||||
unsigned int i;
|
||||
for(i=0;i<KYBER_K;i++)
|
||||
poly_frombytes(&r->vec[i], a+i*KYBER_POLYBYTES);
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: polyvec_ntt
|
||||
*
|
||||
* Description: Apply forward NTT to all elements of a vector of polynomials
|
||||
*
|
||||
* Arguments: - polyvec *r: pointer to in/output vector of polynomials
|
||||
**************************************************/
|
||||
void polyvec_ntt(polyvec *r)
|
||||
{
|
||||
unsigned int i;
|
||||
for(i=0;i<KYBER_K;i++)
|
||||
poly_ntt(&r->vec[i]);
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: polyvec_invntt_tomont
|
||||
*
|
||||
* Description: Apply inverse NTT to all elements of a vector of polynomials
|
||||
* and multiply by Montgomery factor 2^16
|
||||
*
|
||||
* Arguments: - polyvec *r: pointer to in/output vector of polynomials
|
||||
**************************************************/
|
||||
void polyvec_invntt_tomont(polyvec *r)
|
||||
{
|
||||
unsigned int i;
|
||||
for(i=0;i<KYBER_K;i++)
|
||||
poly_invntt_tomont(&r->vec[i]);
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: polyvec_basemul_acc_montgomery
|
||||
*
|
||||
* Description: Multiply elements of a and b in NTT domain, accumulate into r,
|
||||
* and multiply by 2^-16.
|
||||
*
|
||||
* Arguments: - poly *r: pointer to output polynomial
|
||||
* - const polyvec *a: pointer to first input vector of polynomials
|
||||
* - const polyvec *b: pointer to second input vector of polynomials
|
||||
**************************************************/
|
||||
void polyvec_basemul_acc_montgomery(poly *r, const polyvec *a, const polyvec *b)
|
||||
{
|
||||
unsigned int i;
|
||||
poly t;
|
||||
|
||||
poly_basemul_montgomery(r, &a->vec[0], &b->vec[0]);
|
||||
for(i=1;i<KYBER_K;i++) {
|
||||
poly_basemul_montgomery(&t, &a->vec[i], &b->vec[i]);
|
||||
poly_add(r, r, &t);
|
||||
}
|
||||
|
||||
poly_reduce(r);
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: polyvec_reduce
|
||||
*
|
||||
* Description: Applies Barrett reduction to each coefficient
|
||||
* of each element of a vector of polynomials;
|
||||
* for details of the Barrett reduction see comments in reduce.c
|
||||
*
|
||||
* Arguments: - polyvec *r: pointer to input/output polynomial
|
||||
**************************************************/
|
||||
void polyvec_reduce(polyvec *r)
|
||||
{
|
||||
unsigned int i;
|
||||
for(i=0;i<KYBER_K;i++)
|
||||
poly_reduce(&r->vec[i]);
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: polyvec_add
|
||||
*
|
||||
* Description: Add vectors of polynomials
|
||||
*
|
||||
* Arguments: - polyvec *r: pointer to output vector of polynomials
|
||||
* - const polyvec *a: pointer to first input vector of polynomials
|
||||
* - const polyvec *b: pointer to second input vector of polynomials
|
||||
**************************************************/
|
||||
void polyvec_add(polyvec *r, const polyvec *a, const polyvec *b)
|
||||
{
|
||||
unsigned int i;
|
||||
for(i=0;i<KYBER_K;i++)
|
||||
poly_add(&r->vec[i], &a->vec[i], &b->vec[i]);
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
#include <stdint.h>
|
||||
#include "params.h"
|
||||
#include "reduce.h"
|
||||
|
||||
/*************************************************
|
||||
* Name: montgomery_reduce
|
||||
*
|
||||
* Description: Montgomery reduction; given a 32-bit integer a, computes
|
||||
* 16-bit integer congruent to a * R^-1 mod q, where R=2^16
|
||||
*
|
||||
* Arguments: - int32_t a: input integer to be reduced;
|
||||
* has to be in {-q2^15,...,q2^15-1}
|
||||
*
|
||||
* Returns: integer in {-q+1,...,q-1} congruent to a * R^-1 modulo q.
|
||||
**************************************************/
|
||||
int16_t montgomery_reduce(int32_t a)
|
||||
{
|
||||
int16_t t;
|
||||
|
||||
t = (int16_t)a*QINV;
|
||||
t = (a - (int32_t)t*KYBER_Q) >> 16;
|
||||
return t;
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: barrett_reduce
|
||||
*
|
||||
* Description: Barrett reduction; given a 16-bit integer a, computes
|
||||
* centered representative congruent to a mod q in {-(q-1)/2,...,(q-1)/2}
|
||||
*
|
||||
* Arguments: - int16_t a: input integer to be reduced
|
||||
*
|
||||
* Returns: integer in {-(q-1)/2,...,(q-1)/2} congruent to a modulo q.
|
||||
**************************************************/
|
||||
int16_t barrett_reduce(int16_t a) {
|
||||
int16_t t;
|
||||
const int16_t v = ((1<<26) + KYBER_Q/2)/KYBER_Q;
|
||||
|
||||
t = ((int32_t)v*a + (1<<25)) >> 26;
|
||||
t *= KYBER_Q;
|
||||
return a - t;
|
||||
}
|
||||
@ -0,0 +1,73 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "params.h"
|
||||
#include "symmetric.h"
|
||||
#include "fips202.h"
|
||||
|
||||
/*************************************************
|
||||
* Name: kyber_shake128_absorb
|
||||
*
|
||||
* Description: Absorb step of the SHAKE128 specialized for the Kyber context.
|
||||
*
|
||||
* Arguments: - keccak_state *state: pointer to (uninitialized) output Keccak state
|
||||
* - const uint8_t *seed: pointer to KYBER_SYMBYTES input to be absorbed into state
|
||||
* - uint8_t i: additional byte of input
|
||||
* - uint8_t j: additional byte of input
|
||||
**************************************************/
|
||||
void kyber_shake128_absorb(keccak_state *state,
|
||||
const uint8_t seed[KYBER_SYMBYTES],
|
||||
uint8_t x,
|
||||
uint8_t y)
|
||||
{
|
||||
uint8_t extseed[KYBER_SYMBYTES+2];
|
||||
|
||||
memcpy(extseed, seed, KYBER_SYMBYTES);
|
||||
extseed[KYBER_SYMBYTES+0] = x;
|
||||
extseed[KYBER_SYMBYTES+1] = y;
|
||||
|
||||
shake128_absorb_once(state, extseed, sizeof(extseed));
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: kyber_shake256_prf
|
||||
*
|
||||
* Description: Usage of SHAKE256 as a PRF, concatenates secret and public input
|
||||
* and then generates outlen bytes of SHAKE256 output
|
||||
*
|
||||
* Arguments: - uint8_t *out: pointer to output
|
||||
* - size_t outlen: number of requested output bytes
|
||||
* - const uint8_t *key: pointer to the key (of length KYBER_SYMBYTES)
|
||||
* - uint8_t nonce: single-byte nonce (public PRF input)
|
||||
**************************************************/
|
||||
void kyber_shake256_prf(uint8_t *out, size_t outlen, const uint8_t key[KYBER_SYMBYTES], uint8_t nonce)
|
||||
{
|
||||
uint8_t extkey[KYBER_SYMBYTES+1];
|
||||
|
||||
memcpy(extkey, key, KYBER_SYMBYTES);
|
||||
extkey[KYBER_SYMBYTES] = nonce;
|
||||
|
||||
shake256(out, outlen, extkey, sizeof(extkey));
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: kyber_shake256_prf
|
||||
*
|
||||
* Description: Usage of SHAKE256 as a PRF, concatenates secret and public input
|
||||
* and then generates outlen bytes of SHAKE256 output
|
||||
*
|
||||
* Arguments: - uint8_t *out: pointer to output
|
||||
* - size_t outlen: number of requested output bytes
|
||||
* - const uint8_t *key: pointer to the key (of length KYBER_SYMBYTES)
|
||||
* - uint8_t nonce: single-byte nonce (public PRF input)
|
||||
**************************************************/
|
||||
void kyber_shake256_rkprf(uint8_t out[KYBER_SSBYTES], const uint8_t key[KYBER_SYMBYTES], const uint8_t input[KYBER_CIPHERTEXTBYTES])
|
||||
{
|
||||
keccak_state s;
|
||||
|
||||
shake256_init(&s);
|
||||
shake256_absorb(&s, key, KYBER_SYMBYTES);
|
||||
shake256_absorb(&s, input, KYBER_CIPHERTEXTBYTES);
|
||||
shake256_finalize(&s);
|
||||
shake256_squeeze(out, KYBER_SSBYTES, &s);
|
||||
}
|
||||
@ -0,0 +1,75 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "verify.h"
|
||||
|
||||
/*************************************************
|
||||
* Name: verify
|
||||
*
|
||||
* Description: Compare two arrays for equality in constant time.
|
||||
*
|
||||
* Arguments: const uint8_t *a: pointer to first byte array
|
||||
* const uint8_t *b: pointer to second byte array
|
||||
* size_t len: length of the byte arrays
|
||||
*
|
||||
* Returns 0 if the byte arrays are equal, 1 otherwise
|
||||
**************************************************/
|
||||
int verify(const uint8_t *a, const uint8_t *b, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
uint8_t r = 0;
|
||||
|
||||
for(i=0;i<len;i++)
|
||||
r |= a[i] ^ b[i];
|
||||
|
||||
return (-(uint64_t)r) >> 63;
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Name: cmov
|
||||
*
|
||||
* Description: Copy len bytes from x to r if b is 1;
|
||||
* don't modify x if b is 0. Requires b to be in {0,1};
|
||||
* assumes two's complement representation of negative integers.
|
||||
* Runs in constant time.
|
||||
*
|
||||
* Arguments: uint8_t *r: pointer to output byte array
|
||||
* const uint8_t *x: pointer to input byte array
|
||||
* size_t len: Amount of bytes to be copied
|
||||
* uint8_t b: Condition bit; has to be in {0,1}
|
||||
**************************************************/
|
||||
void cmov(uint8_t *r, const uint8_t *x, size_t len, uint8_t b)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
// Prevent the compiler from
|
||||
// 1) inferring that b is 0/1-valued, and
|
||||
// 2) handling the two cases with a branch.
|
||||
// This is not necessary when verify.c and kem.c are separate translation
|
||||
// units, but we expect that downstream consumers will copy this code and/or
|
||||
// change how it is built.
|
||||
__asm__("" : "+r"(b) : /* no inputs */);
|
||||
#endif
|
||||
|
||||
b = -b;
|
||||
for(i=0;i<len;i++)
|
||||
r[i] ^= b & (r[i] ^ x[i]);
|
||||
}
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Name: cmov_int16
|
||||
*
|
||||
* Description: Copy input v to *r if b is 1, don't modify *r if b is 0.
|
||||
* Requires b to be in {0,1};
|
||||
* Runs in constant time.
|
||||
*
|
||||
* Arguments: int16_t *r: pointer to output int16_t
|
||||
* int16_t v: input int16_t
|
||||
* uint8_t b: Condition bit; has to be in {0,1}
|
||||
**************************************************/
|
||||
void cmov_int16(int16_t *r, int16_t v, uint16_t b)
|
||||
{
|
||||
b = -b;
|
||||
*r ^= b & ((*r) ^ v);
|
||||
}
|
||||
22
Sources/CKyber/kyber1024.c
普通文件
22
Sources/CKyber/kyber1024.c
普通文件
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* kyber1024.c — Kyber1024 变体翻译单元
|
||||
*
|
||||
* 安全级别:NIST Level 5(经典安全性约等于 AES-256),适用于高度敏感数据
|
||||
* 参数(KYBER_K = 4):
|
||||
* - 公钥:1568 字节
|
||||
* - 私钥:3168 字节
|
||||
* - 密文:1568 字节
|
||||
* - 共享密钥:32 字节
|
||||
*
|
||||
* 编译原理与 kyber512.c 相同,KYBER_NAMESPACE 展开为 pqcrystals_kyber1024_ref_##s。
|
||||
*/
|
||||
#define KYBER_K 4
|
||||
#include "internal/kem.inc"
|
||||
#include "internal/indcpa.inc"
|
||||
#include "internal/poly.inc"
|
||||
#include "internal/polyvec.inc"
|
||||
#include "internal/ntt.inc"
|
||||
#include "internal/cbd.inc"
|
||||
#include "internal/reduce.inc"
|
||||
#include "internal/verify.inc"
|
||||
#include "internal/symmetric_shake.inc"
|
||||
30
Sources/CKyber/kyber512.c
普通文件
30
Sources/CKyber/kyber512.c
普通文件
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* kyber512.c — Kyber512 变体翻译单元
|
||||
*
|
||||
* 安全级别:NIST Level 1(经典安全性约等于 AES-128)
|
||||
* 参数(KYBER_K = 2):
|
||||
* - 公钥:800 字节
|
||||
* - 私钥:1632 字节
|
||||
* - 密文:768 字节
|
||||
* - 共享密钥:32 字节
|
||||
*
|
||||
* 编译原理:
|
||||
* 在 #include 各实现文件之前先定义 KYBER_K=2,
|
||||
* params.h 中的 #ifndef KYBER_K 判断将使用此值,
|
||||
* KYBER_NAMESPACE 宏展开为 pqcrystals_kyber512_ref_##s,
|
||||
* 确保本翻译单元中所有符号名带有 "kyber512" 前缀,
|
||||
* 与 kyber768.c / kyber1024.c 的符号互不冲突。
|
||||
*
|
||||
* 注意:fips202 / randombytes 不在此处包含,它们在独立翻译单元中编译,
|
||||
* 链接器负责解析本文件中对 shake128_xxx / sha3_xxx 等函数的引用。
|
||||
*/
|
||||
#define KYBER_K 2
|
||||
#include "internal/kem.inc"
|
||||
#include "internal/indcpa.inc"
|
||||
#include "internal/poly.inc"
|
||||
#include "internal/polyvec.inc"
|
||||
#include "internal/ntt.inc"
|
||||
#include "internal/cbd.inc"
|
||||
#include "internal/reduce.inc"
|
||||
#include "internal/verify.inc"
|
||||
#include "internal/symmetric_shake.inc"
|
||||
22
Sources/CKyber/kyber768.c
普通文件
22
Sources/CKyber/kyber768.c
普通文件
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* kyber768.c — Kyber768 变体翻译单元
|
||||
*
|
||||
* 安全级别:NIST Level 3(经典安全性约等于 AES-192),推荐通用选择
|
||||
* 参数(KYBER_K = 3):
|
||||
* - 公钥:1184 字节
|
||||
* - 私钥:2400 字节
|
||||
* - 密文:1088 字节
|
||||
* - 共享密钥:32 字节
|
||||
*
|
||||
* 编译原理与 kyber512.c 相同,KYBER_NAMESPACE 展开为 pqcrystals_kyber768_ref_##s。
|
||||
*/
|
||||
#define KYBER_K 3
|
||||
#include "internal/kem.inc"
|
||||
#include "internal/indcpa.inc"
|
||||
#include "internal/poly.inc"
|
||||
#include "internal/polyvec.inc"
|
||||
#include "internal/ntt.inc"
|
||||
#include "internal/cbd.inc"
|
||||
#include "internal/reduce.inc"
|
||||
#include "internal/verify.inc"
|
||||
#include "internal/symmetric_shake.inc"
|
||||
21
Sources/CKyber/randombytes_ios.c
普通文件
21
Sources/CKyber/randombytes_ios.c
普通文件
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* randombytes_ios.c — iOS / macOS 随机字节实现
|
||||
*
|
||||
* 使用 arc4random_buf() 生成密码学安全的随机字节。
|
||||
*
|
||||
* 选型说明:
|
||||
* - arc4random_buf 由苹果 libSystem 提供,底层调用内核级 CSPRNG,
|
||||
* 等价于 /dev/urandom 但无需文件句柄,性能更优且无系统调用开销。
|
||||
* - Apple 官方推荐用于 iOS/macOS 的密码学随机数生成。
|
||||
* - 无需种子初始化,不阻塞,适合在任意上下文(含主线程)调用。
|
||||
*
|
||||
* 替代了原始 randombytes.c 中的 open("/dev/urandom") 方案。
|
||||
*/
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include "randombytes.h"
|
||||
|
||||
void randombytes(uint8_t *out, size_t outlen) {
|
||||
arc4random_buf(out, outlen);
|
||||
}
|
||||
174
Sources/KyberSDK/KyberKEM.swift
普通文件
174
Sources/KyberSDK/KyberKEM.swift
普通文件
@ -0,0 +1,174 @@
|
||||
import Foundation
|
||||
import CKyber
|
||||
|
||||
// MARK: - KyberKEM
|
||||
|
||||
/**
|
||||
* Kyber KEM(密钥封装机制)Swift 封装层。
|
||||
*
|
||||
* ## 算法简介
|
||||
* CRYSTALS-Kyber(ML-KEM,NIST FIPS 203)是基于格密码(Module-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 字节随机 coins(iOS/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)
|
||||
}
|
||||
}
|
||||
148
Sources/KyberSDK/KyberTypes.swift
普通文件
148
Sources/KyberSDK/KyberTypes.swift
普通文件
@ -0,0 +1,148 @@
|
||||
import Foundation
|
||||
|
||||
// MARK: - KyberVariant
|
||||
|
||||
/**
|
||||
* Kyber KEM 安全级别枚举。
|
||||
*
|
||||
* CRYSTALS-Kyber(ML-KEM,NIST FIPS 203)定义了三种参数集,
|
||||
* 分别对应不同的安全强度和密钥/密文大小:
|
||||
*
|
||||
* | 变体 | KYBER_K | NIST 级别 | 经典安全性 |
|
||||
* |-------------|---------|----------|-----------|
|
||||
* | `.kyber512` | 2 | Level 1 | ~AES-128 |
|
||||
* | `.kyber768` | 3 | Level 3 | ~AES-192 |
|
||||
* | `.kyber1024` | 4 | Level 5 | ~AES-256 |
|
||||
*
|
||||
* 推荐选择:`.kyber768` 满足大多数应用场景的安全需求,
|
||||
* 同时密钥/密文大小适中。
|
||||
*/
|
||||
public enum KyberVariant: CaseIterable {
|
||||
/// Kyber512:NIST 安全级别 1,适用于资源受限或对大小敏感的场景
|
||||
case kyber512
|
||||
/// Kyber768:NIST 安全级别 3,推荐的通用安全级别
|
||||
case kyber768
|
||||
/// Kyber1024:NIST 安全级别 5,适用于高价值数据的长期保护
|
||||
case kyber1024
|
||||
|
||||
/// 公钥字节长度
|
||||
public var publicKeyBytes: Int {
|
||||
switch self {
|
||||
case .kyber512: return 800
|
||||
case .kyber768: return 1184
|
||||
case .kyber1024: return 1568
|
||||
}
|
||||
}
|
||||
|
||||
/// 私钥字节长度(包含公钥副本及 H(pk) 等辅助数据)
|
||||
public var secretKeyBytes: Int {
|
||||
switch self {
|
||||
case .kyber512: return 1632
|
||||
case .kyber768: return 2400
|
||||
case .kyber1024: return 3168
|
||||
}
|
||||
}
|
||||
|
||||
/// 密文字节长度
|
||||
public var ciphertextBytes: Int {
|
||||
switch self {
|
||||
case .kyber512: return 768
|
||||
case .kyber768: return 1088
|
||||
case .kyber1024: return 1568
|
||||
}
|
||||
}
|
||||
|
||||
/// 共享密钥字节长度(三种变体均为 32 字节)
|
||||
public var sharedSecretBytes: Int { 32 }
|
||||
|
||||
/// 人类可读的展示名称
|
||||
public var displayName: String {
|
||||
switch self {
|
||||
case .kyber512: return "Kyber512(NIST Level 1)"
|
||||
case .kyber768: return "Kyber768(NIST Level 3)"
|
||||
case .kyber1024: return "Kyber1024(NIST Level 5)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - KyberKeyPair
|
||||
|
||||
/**
|
||||
* Kyber 密钥对,由 `KyberKEM.generateKeyPair` 返回。
|
||||
*
|
||||
* - `publicKey`:可安全分发给通信对方,对方使用它执行封装操作。
|
||||
* - `secretKey`:必须保密存储,用于从密文中恢复共享密钥。
|
||||
*/
|
||||
public struct KyberKeyPair {
|
||||
/// 公钥,可公开传输
|
||||
public let publicKey: Data
|
||||
/// 私钥,必须安全存储(建议使用 iOS Keychain)
|
||||
public let secretKey: Data
|
||||
|
||||
public init(publicKey: Data, secretKey: Data) {
|
||||
self.publicKey = publicKey
|
||||
self.secretKey = secretKey
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - KyberEncapsulationResult
|
||||
|
||||
/**
|
||||
* Kyber 封装结果,由 `KyberKEM.encapsulate` 返回。
|
||||
*
|
||||
* 封装操作(发送方/主动方)的两个输出:
|
||||
* - `ciphertext`:发送给持有私钥的接收方,接收方用私钥解封装以恢复共享密钥。
|
||||
* - `sharedSecret`:本地保留的 32 字节共享密钥,
|
||||
* 可直接用作对称密码(AES-GCM / ChaCha20-Poly1305)的密钥材料。
|
||||
*/
|
||||
public struct KyberEncapsulationResult {
|
||||
/// 发送给接收方的密文
|
||||
public let ciphertext: Data
|
||||
/// 本地保留的共享密钥(32 字节)
|
||||
public let sharedSecret: Data
|
||||
|
||||
public init(ciphertext: Data, sharedSecret: Data) {
|
||||
self.ciphertext = ciphertext
|
||||
self.sharedSecret = sharedSecret
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - KyberError
|
||||
|
||||
/**
|
||||
* Kyber SDK 错误类型。
|
||||
*
|
||||
* 输入校验类错误在调用 C 层前抛出;
|
||||
* `*Failed` 类错误表示 C 函数返回了非零状态码(通常不应发生)。
|
||||
*/
|
||||
public enum KyberError: Error, LocalizedError {
|
||||
/// 密钥生成失败,附带 C 函数返回码
|
||||
case keyGenerationFailed(code: Int32)
|
||||
/// 封装操作失败,附带 C 函数返回码
|
||||
case encapsulationFailed(code: Int32)
|
||||
/// 解封装操作失败,附带 C 函数返回码
|
||||
case decapsulationFailed(code: Int32)
|
||||
/// 公钥长度与所选变体不符
|
||||
case invalidPublicKeySize(expected: Int, got: Int)
|
||||
/// 私钥长度与所选变体不符
|
||||
case invalidSecretKeySize(expected: Int, got: Int)
|
||||
/// 密文长度与所选变体不符
|
||||
case invalidCiphertextSize(expected: Int, got: Int)
|
||||
|
||||
public var errorDescription: String? {
|
||||
switch self {
|
||||
case .keyGenerationFailed(let c):
|
||||
return "密钥生成失败(返回码:\(c))"
|
||||
case .encapsulationFailed(let c):
|
||||
return "封装失败(返回码:\(c))"
|
||||
case .decapsulationFailed(let c):
|
||||
return "解封装失败(返回码:\(c))"
|
||||
case .invalidPublicKeySize(let e, let g):
|
||||
return "公钥长度不匹配:期望 \(e) 字节,实际 \(g) 字节"
|
||||
case .invalidSecretKeySize(let e, let g):
|
||||
return "私钥长度不匹配:期望 \(e) 字节,实际 \(g) 字节"
|
||||
case .invalidCiphertextSize(let e, let g):
|
||||
return "密文长度不匹配:期望 \(e) 字节,实际 \(g) 字节"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,131 @@
|
||||
import XCTest
|
||||
@testable import KyberSDK
|
||||
|
||||
/**
|
||||
* KyberSDK 单元测试套件
|
||||
*
|
||||
* 测试覆盖:
|
||||
* - 三种变体(512 / 768 / 1024)密钥尺寸验证
|
||||
* - 三种变体完整 KEM 全流程(密钥生成 → 封装 → 解封装 → 比对)
|
||||
* - 错误密钥解封装(验证 IND-CCA2 安全属性)
|
||||
* - 输入参数校验(非法公钥 / 私钥 / 密文长度)
|
||||
* - Kyber768 性能基线
|
||||
*/
|
||||
final class KyberSDKTests: XCTestCase {
|
||||
|
||||
// MARK: - Kyber512 测试
|
||||
|
||||
/// 验证 Kyber512 密钥尺寸符合规范
|
||||
func testKyber512KeySizes() throws {
|
||||
let kp = try KyberKEM.generateKeyPair(variant: .kyber512)
|
||||
XCTAssertEqual(kp.publicKey.count, 800, "Kyber512 公钥应为 800 字节")
|
||||
XCTAssertEqual(kp.secretKey.count, 1632, "Kyber512 私钥应为 1632 字节")
|
||||
}
|
||||
|
||||
/// Kyber512 完整 KEM 流程:密钥生成 → 封装 → 解封装 → 共享密钥必须一致
|
||||
func testKyber512RoundTrip() throws {
|
||||
let kp = try KyberKEM.generateKeyPair(variant: .kyber512)
|
||||
let enc = try KyberKEM.encapsulate(variant: .kyber512, publicKey: kp.publicKey)
|
||||
let dec = try KyberKEM.decapsulate(variant: .kyber512, ciphertext: enc.ciphertext, secretKey: kp.secretKey)
|
||||
|
||||
XCTAssertEqual(enc.ciphertext.count, 768, "Kyber512 密文应为 768 字节")
|
||||
XCTAssertEqual(enc.sharedSecret.count, 32, "共享密钥应为 32 字节")
|
||||
XCTAssertEqual(dec.count, 32, "解封装共享密钥应为 32 字节")
|
||||
XCTAssertEqual(enc.sharedSecret, dec, "封装和解封装的共享密钥必须完全一致")
|
||||
}
|
||||
|
||||
/// Kyber512 错误密钥测试:使用错误私钥解封装,共享密钥应与封装方不同(IND-CCA2)
|
||||
func testKyber512WrongKey() throws {
|
||||
let alice = try KyberKEM.generateKeyPair(variant: .kyber512)
|
||||
let bob = try KyberKEM.generateKeyPair(variant: .kyber512)
|
||||
// 发送方使用 Alice 的公钥封装
|
||||
let enc = try KyberKEM.encapsulate(variant: .kyber512, publicKey: alice.publicKey)
|
||||
// Bob 用自己的私钥解封装 —— 应得到不同的(伪随机)共享密钥
|
||||
let dec = try KyberKEM.decapsulate(variant: .kyber512, ciphertext: enc.ciphertext, secretKey: bob.secretKey)
|
||||
XCTAssertNotEqual(enc.sharedSecret, dec, "使用错误私钥不应恢复正确的共享密钥(IND-CCA2)")
|
||||
}
|
||||
|
||||
// MARK: - Kyber768 测试
|
||||
|
||||
/// 验证 Kyber768 密钥尺寸符合规范
|
||||
func testKyber768KeySizes() throws {
|
||||
let kp = try KyberKEM.generateKeyPair(variant: .kyber768)
|
||||
XCTAssertEqual(kp.publicKey.count, 1184, "Kyber768 公钥应为 1184 字节")
|
||||
XCTAssertEqual(kp.secretKey.count, 2400, "Kyber768 私钥应为 2400 字节")
|
||||
}
|
||||
|
||||
/// Kyber768 完整 KEM 流程
|
||||
func testKyber768RoundTrip() throws {
|
||||
let kp = try KyberKEM.generateKeyPair(variant: .kyber768)
|
||||
let enc = try KyberKEM.encapsulate(variant: .kyber768, publicKey: kp.publicKey)
|
||||
let dec = try KyberKEM.decapsulate(variant: .kyber768, ciphertext: enc.ciphertext, secretKey: kp.secretKey)
|
||||
|
||||
XCTAssertEqual(enc.ciphertext.count, 1088, "Kyber768 密文应为 1088 字节")
|
||||
XCTAssertEqual(enc.sharedSecret, dec, "封装和解封装的共享密钥必须完全一致")
|
||||
}
|
||||
|
||||
// MARK: - Kyber1024 测试
|
||||
|
||||
/// 验证 Kyber1024 密钥尺寸符合规范
|
||||
func testKyber1024KeySizes() throws {
|
||||
let kp = try KyberKEM.generateKeyPair(variant: .kyber1024)
|
||||
XCTAssertEqual(kp.publicKey.count, 1568, "Kyber1024 公钥应为 1568 字节")
|
||||
XCTAssertEqual(kp.secretKey.count, 3168, "Kyber1024 私钥应为 3168 字节")
|
||||
}
|
||||
|
||||
/// Kyber1024 完整 KEM 流程
|
||||
func testKyber1024RoundTrip() throws {
|
||||
let kp = try KyberKEM.generateKeyPair(variant: .kyber1024)
|
||||
let enc = try KyberKEM.encapsulate(variant: .kyber1024, publicKey: kp.publicKey)
|
||||
let dec = try KyberKEM.decapsulate(variant: .kyber1024, ciphertext: enc.ciphertext, secretKey: kp.secretKey)
|
||||
|
||||
XCTAssertEqual(enc.ciphertext.count, 1568, "Kyber1024 密文应为 1568 字节")
|
||||
XCTAssertEqual(enc.sharedSecret, dec, "封装和解封装的共享密钥必须完全一致")
|
||||
}
|
||||
|
||||
// MARK: - 输入参数校验测试
|
||||
|
||||
/// 公钥长度不符时应抛出 KyberError.invalidPublicKeySize
|
||||
func testInvalidPublicKeySize() {
|
||||
XCTAssertThrowsError(
|
||||
try KyberKEM.encapsulate(variant: .kyber768, publicKey: Data(repeating: 0, count: 100)),
|
||||
"公钥长度不匹配时应抛出错误"
|
||||
)
|
||||
}
|
||||
|
||||
/// 私钥长度不符时应抛出 KyberError.invalidSecretKeySize
|
||||
func testInvalidSecretKeySize() throws {
|
||||
let kp = try KyberKEM.generateKeyPair(variant: .kyber768)
|
||||
let enc = try KyberKEM.encapsulate(variant: .kyber768, publicKey: kp.publicKey)
|
||||
XCTAssertThrowsError(
|
||||
try KyberKEM.decapsulate(
|
||||
variant: .kyber768,
|
||||
ciphertext: enc.ciphertext,
|
||||
secretKey: Data(repeating: 0, count: 10)
|
||||
),
|
||||
"私钥长度不匹配时应抛出错误"
|
||||
)
|
||||
}
|
||||
|
||||
/// 密文长度不符时应抛出 KyberError.invalidCiphertextSize
|
||||
func testInvalidCiphertextSize() throws {
|
||||
let kp = try KyberKEM.generateKeyPair(variant: .kyber768)
|
||||
XCTAssertThrowsError(
|
||||
try KyberKEM.decapsulate(
|
||||
variant: .kyber768,
|
||||
ciphertext: Data(repeating: 0, count: 10),
|
||||
secretKey: kp.secretKey
|
||||
),
|
||||
"密文长度不匹配时应抛出错误"
|
||||
)
|
||||
}
|
||||
|
||||
// MARK: - 性能测试
|
||||
|
||||
/// Kyber768 密钥生成性能基线(10 次迭代平均值)
|
||||
func testKyber768Performance() throws {
|
||||
measure {
|
||||
_ = try? KyberKEM.generateKeyPair(variant: .kyber768)
|
||||
}
|
||||
}
|
||||
}
|
||||
正在加载...
在新工单中引用
屏蔽一个用户