9个版本
0.1.8 | 2024年4月22日 |
---|---|
0.1.7 | 2024年4月5日 |
0.1.5 | 2024年3月4日 |
0.1.4 | 2023年12月11日 |
#367 in 加密学
用于 capycrypt
345KB
705 行
Ed448-Goldilocks
警告:此软件未经过审计。使用风险自担。
1. 目标
Edward形式曲线的Goldilocks变种在安全性和性能之间提供了一个令人信服的平衡。我们希望利用这个曲线以满足以下群属性
身份 |
---|
0 * G = 𝒪 |
G * 1 = G |
G + (-G) = 𝒪 |
2 * G = G + G |
4 * G = 2 * (2 * G) |
4 * G > 𝒪 |
r * G = 𝒪 |
(k + 1) * G = (k * G) + G |
k*G = (k % r) * G |
(k + t) * G = (k * G) + (t * G) |
k * (t * G) = t * (k * G) = (k * t % r) * G |
我们想要的
- 尽可能快的组合和双倍操作
- 标量字段操作固定时间侧信道抵抗
- 仅我们需要的功能用于Schnorr签名和非对称DH,理想情况下使此实现尽可能精简。
2. 策略
在很大程度上遵循这个和这个的方法,我们在点/标量乘法期间执行以下一系列变换
- 从扭曲形式开始
- 分解标量并重新定位到-8和8之间的16进制基数
- 创建一个P的倍数映射到16进制数字的查找表,具有固定时间查找以确保侧信道抵抗。
- 在variable_base_mul中,我们以扭曲形式执行双倍操作,在射影Niels形式中执行加法和固定时间条件否定。
- 点以扩展形式返回,最后转换为仿射形式以供用户操作。
在更高层次上,我们有
仿射 | 扩展 | 扭曲 | 射影Niels |
---|---|---|---|
(x, y) | (x, y, z, t) | (x, y, z, t1, t2) | (y + x, y - x, td, z) |
然后我们的标量乘法将遵循
仿射 → 扩展 → 扭曲 → 射影Niels → 扭曲 → 扩展 → 仿射
3. 固定时间
分解标量的查找表是计算和遍历的固定时间
/// Selects a projective niels point from a lookup table in fixed-time
pub fn select(&self, index: u32) -> ProjectiveNielsPoint {
let mut result = ProjectiveNielsPoint::id_point();
for i in 1..9 {
let swap = index.ct_eq(&(i as u32));
result.conditional_assign(&self.0[i - 1], swap);
}
result
}
这确保了固定时间乘法,无需在Montgomery形式中使用曲线点。此外,我们利用了crypto-bigint库,它确保我们的标量类型具有固定时间操作。域元素由fiat-crypto的p448-solinas-64素域表示。它在机器级别上进行了形式验证和高度优化。
4. 签名和DH
将此crate用作capyCRYPT的椭圆曲线后端,我们有
Schnorr签名
use capycrypt::{
Signable,
KeyPair,
Message,
sha3::aux_functions::byte_utils::get_random_bytes
};
/// # Schnorr Signatures
/// Signs a [`Message`] under passphrase pw.
///
/// ## Algorithm:
/// * `s` ← kmac_xof(pw, “”, 448, “SK”); s ← 4s
/// * `k` ← kmac_xof(s, m, 448, “N”); k ← 4k
/// * `𝑈` ← k*𝑮;
/// * `ℎ` ← kmac_xof(𝑈ₓ , m, 448, “T”); 𝑍 ← (𝑘 – ℎ𝑠) mod r
/// ```
fn sign(&mut self, key: &KeyPair, d: u64) {
self.d = Some(d);
let s: Scalar = bytes_to_scalar(kmac_xof(&key.priv_key, &[], 448, "SK", self.d.unwrap()))
* (Scalar::from(4_u64));
let s_bytes = scalar_to_bytes(&s);
let k: Scalar =
bytes_to_scalar(kmac_xof(&s_bytes, &self.msg, 448, "N", d)) * (Scalar::from(4_u64));
let U = ExtendedPoint::generator() * k;
let ux_bytes = U.to_affine().x.to_bytes().to_vec();
let h = kmac_xof(&ux_bytes, &self.msg, 448, "T", d);
let h_big = bytes_to_scalar(h.clone());
let z = k - (h_big.mul_mod_r(&s));
self.sig = Some(Signature { h, z })
}
5. 基准测试
运行以下命令
cargo bench
在5mb随机数据上,Intel® Core™ i7-10710U × 12的近似运行时间
操作 | ~时间(毫秒) | OpenSSL(毫秒) |
---|---|---|
加密 | 75 | |
解密 | 75 | |
签名 | 42 | 15 |
验证 | 18 |
我们的自定义SHA3与OpenSSL表现相当,但截至目前,我们还不知道那个端口的实验所使用的哈希后端是什么。因此,一些开销可能来自使用SHA3而不是OpenSSL上的更优化的哈希器,例如SHA2。尽管如此,这种性能远远优于我们之前仅使用仿射坐标的尝试。
致谢
作者衷心感谢Paulo Barreto博士在固定时间操作方面的咨询以及在该领域的一般工作。我们还希望向曲线-dalek作者此处和此处表示感谢,因为他们提供了出色的参考实现和岩石般可靠的密码学实例。感谢otsmr对原始仿射坐标Montgomery梯形的尝试。
依赖关系
~6.5MB
~137K SLoC