#class #encryption #public-key #ciphertext #composite #paillier #degree

libpaillier

Paillier密码系统是一种基于复合度余数类的公钥密码系统。Paillier密文是同态的,因为它们可以通过

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 密码学

Download history 4/week @ 2024-04-07 5/week @ 2024-04-14 16/week @ 2024-04-21 7/week @ 2024-04-28 20/week @ 2024-05-05 7/week @ 2024-05-12 9/week @ 2024-05-19 10/week @ 2024-05-26 23/week @ 2024-06-02 73/week @ 2024-06-09 42/week @ 2024-06-16 84/week @ 2024-06-23 38/week @ 2024-06-30 11/week @ 2024-07-07 35/week @ 2024-07-14 51/week @ 2024-07-21

每月135次下载
用于fast-paillier

Apache-2.0 和可能 LGPL-3.0+

26KB
352

Paillier-rs

Crates.io Documentation License-Image minimum rustc 1.50 dependency status

基于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 算法在诸如 GG20Lin17 这样的阈值 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

贡献

除非你明确声明,否则根据 Apache-2.0 许可证定义,你提交的任何有意包含在本作品中的贡献,将按照上述方式许可,不附加任何额外条款或条件。

依赖

~1.1–6.5MB
~134K SLoC