8个版本 (5个破坏性更新)
0.6.0 | 2024年2月13日 |
---|---|
0.5.0 | 2022年12月1日 |
0.4.0 | 2022年10月19日 |
0.3.1 | 2022年8月8日 |
0.1.0 | 2021年5月25日 |
#701 in 密码学
每月135次下载
用于fast-paillier
26KB
352 行
Paillier-rs
基于P99的Paillier密码系统的实现。
Paillier支持同态加密,其计算复杂度与RSA相当。
这个crate使用了unknown-order crate,它允许根据许可证偏好和性能选择底层大数实现。因此,这个crate重新导出unknown_order
,这样使用者就不需要单独依赖。
为什么需要这个crate?
在Rust中,存在其他Paillier的实现,但它们没有提供所有我需要的特性,如实现ops traits或灵活选择大数后端。其中一些甚至没有文档,这意味着用户需要查看代码,这并不理想,或者它们是过时的,没有跟上2018或更新的版本。我的目标是创建一个简单易懂的Paillier库,具有易于误用的API。
此实现尚未经过审查或审计。请自行承担风险使用。
已采取措施减轻某些侧信道攻击,但最终涉及许多因素。关于这方面的良好阅读材料,请参阅Thomas Pornin的Why Constant-Time Crypto文章。
加密
加密消息时,要求消息长度小于复合模数n
。如果消息长度大于n
,则加密将返回None
。Paillier密文是概率性的,因为在加密过程中使用了随机nonce,因此消息可以加密成多个密文。nonce可以由方法生成,也可以从外部提供。如果需要,nonce将返回给调用者。解密不需要nonce。
示例加密/解密
use libpaillier::{
unknown_order::BigNumber,
*
};
fn main() {
// Generate a new random key from two safe-primes
let res = DecryptionKey::random();
let sk = res.unwrap();
let pk = EncryptionKey::from(&sk);
let m = b"this is a test message";
let res = pk.encrypt(m, None);
let (c, _) = res.unwrap();
let res = sk.decrypt(&c);
let m1 = res.unwrap();
assert_eq!(m1, m);
// bad messages
let nn1: BigNumber = pk.nn() + 1;
let nn = pk.nn().to_bytes();
let nn1_bytes = nn1.to_bytes();
let bad_messages: [&[u8]; 3] = [b"", nn.as_slice(), nn1_bytes.as_slice()];
for b in &bad_messages {
let res = pk.encrypt(&b, None);
assert!(res.is_none());
}
}
示例乘法密文
use libpaillier::{
unknown_order::BigNumber,
*
};
fn main() {
let res = DecryptionKey::random();
let sk = res.unwrap();
let pk = EncryptionKey::from(&sk);
let m1 = BigNumber::from(7);
let m2 = BigNumber::from(6);
let res1 = pk.encrypt(&m1.to_bytes(), None);
let (c1, _) = res1.unwrap();
// Multiply the ciphertext
let res = pk.mul(&c1, &m2);
assert!(res.is_some());
let c2 = res.unwrap();
let res = sk.decrypt(&c2);
assert!(res.is_some());
let bytes = res.unwrap();
let m3 = BigNumber::from_slice(bytes.as_slice());
// Prove homomorphic properties worked
assert_eq!(m3, BigNumber::from(42));
}
示例两个密文的加法
use libpaillier::{
unknown_order::BigNumber,
*
};
fn main() {
let res = DecryptionKey::random();
let sk = res.unwrap();
let pk = EncryptionKey::from(&sk);
let m1 = BigNumber::from(7);
let m2 = BigNumber::from(6);
let res1 = pk.encrypt(&m1.to_bytes(), None);
let res2 = pk.encrypt(&m2.to_bytes(), None);
assert!(res1.is_some());
assert!(res2.is_some());
let (c1, _) = res1.unwrap();
let (c2, _) = res2.unwrap();
let res = pk.add(&c1, &c2);
assert!(res.is_some());
let c3 = res.unwrap();
let res = sk.decrypt(&c3);
assert!(res.is_some());
let bytes = res.unwrap();
let m3 = BigNumber::from_slice(bytes);
assert_eq!(m3, BigNumber::from(13));
}
证明
Paillier 算法在诸如 GG20 和 Lin17 这样的阈值 ECDSA 签名协议中变得越来越常见。在生成 Paillier 密钥时,这些协议使用模数是平方自由的证明。本软件包包含这个证明作为便利,并提供一个使用合理参数以实现 128 位安全性的通用实现。
use libpaillier::{
unknown_order::BigNumber,
*
};
fn main() {
let res = DecryptionKey::random();
let sk = res.unwrap();
let pk = EncryptionKey::from(&sk);
// Commonly used proof for tECDSA
let signing_key = k256::DecryptionKey::random(rand::rngs::OsRng::default());
let verification_key = signing_key.public_key();
let mut nonce = Vec::new();
nonce.extend_from_slice(
k256::AffinePoint::generator()
.to_encoded_point(true)
.as_bytes(),
);
nonce.extend_from_slice(
&hex::decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F").unwrap(),
);
nonce.extend_from_slice(verification_key.as_affine().to_encoded_point(true).as_bytes());
nonce.push(1u8);
let res = ProofSquareFree::generate::<sha2::Sha256>(&sk, nonce.as_slice());
assert!(res.is_some());
let proof = res.unwrap();
assert!(proof.verify::<sha2::Sha256>(&pk, nonce.as_slice()));
let mut bytes = proof.to_bytes();
let res = ProofSquareFree::from_bytes(bytes.as_slice());
assert!(res.is_ok());
let proof1 = res.unwrap();
assert_eq!(proof1.to_bytes(), proof.to_bytes());
bytes[0] = bytes[1];
let res = ProofSquareFree::from_bytes(bytes.as_slice());
assert!(res.is_err());
}
许可证
贡献
除非你明确声明,否则根据 Apache-2.0 许可证定义,你提交的任何有意包含在本作品中的贡献,将按照上述方式许可,不附加任何额外条款或条件。
依赖
~1.1–6.5MB
~134K SLoC