chore: release KyberSDK 1.0.0

这个提交包含在:
KyberSDK Release Bot 2026-05-06 22:28:00 +08:00
当前提交 a77fcc3a41
共有 34 个文件被更改,包括 3591 次插入0 次删除

1
.sdk-version 普通文件
查看文件

@ -0,0 +1 @@
1.0.0

61
Package.swift 普通文件
查看文件

@ -0,0 +1,61 @@
// swift-tools-version: 5.9
// KyberSDK CRYSTALS-KyberML-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-simulatorApple 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 普通文件
查看文件

@ -0,0 +1,173 @@
# KyberSDK — iOS / macOS Swift Package
基于 CRYSTALS-KyberML-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 # 主 APIgenerateKeyPair / 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 普通文件
查看文件

@ -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]);
}

查看文件

@ -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

查看文件

@ -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

查看文件

@ -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

查看文件

@ -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

查看文件

@ -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 */

查看文件

@ -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

查看文件

@ -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

查看文件

@ -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

查看文件

@ -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

查看文件

@ -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 */

查看文件

@ -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

查看文件

@ -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
}

查看文件

@ -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);
}

查看文件

@ -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;
}

查看文件

@ -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]);
}

查看文件

@ -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];
}

查看文件

@ -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 普通文件
查看文件

@ -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 普通文件
查看文件

@ -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 普通文件
查看文件

@ -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"

查看文件

@ -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);
}

查看文件

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

查看文件

@ -0,0 +1,148 @@
import Foundation
// MARK: - KyberVariant
/**
* Kyber KEM
*
* CRYSTALS-KyberML-KEMNIST 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 {
/// Kyber512NIST 1
case kyber512
/// Kyber768NIST 3
case kyber768
/// Kyber1024NIST 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 "Kyber512NIST Level 1"
case .kyber768: return "Kyber768NIST Level 3"
case .kyber1024: return "Kyber1024NIST 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)
}
}
}