Giter Site home page Giter Site logo

paillier-rs's Introduction

Paillier-rs

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

An implementation of the Paillier cryptosystem based on P99.

Paillier supports homomorphic encryption and is computationally comparable to RSA.

This crate uses the unknown-order crate which allows switching the underlying big number implementation based on license preferences and performance. As such, this crate reexports unknown_order so consumers of this crate do not have to have a separate dependency.

Why this crate?

There are other implementations of Paillier in rust, but none of them offer everything I needed like implementing ops traits, or the flexibility to choose a big number backend. Also, some of them do not even have documentation which means users are expected to look at code which is not ideal, or are outdated and not current with 2018 or newer edition. My goal was to create a simple Paillier library with an easy-to-understand misuse resistant API.

This implementation has not been reviewed or audited. Use at your own risk.

Efforts have been made to mitigate some side channel attacks but ultimately there are many factors involved. For a good read, see Thomas Pornin's Why Constant-Time Crypto article.

Encryption

Encrypting messages requires that the messages be less than the composite modulus n. If messages > n, encrypt will return None. Paillier ciphertexts are probabilistic in that a random nonce is used during encryption, thus a message encrypts to multiple ciphertexts. This nonce can optionally be provided externally, or generated by the method. The nonce is returned to callers in case it is needed. The nonce is not needed for decryption.

Example Encryption/Decryption

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

Example Multiply Ciphertext

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

Example Add Two Ciphertexts

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

Proofs

Paillier has become more common in protocols like threshold ECDSA signing like GG20 and Lin17. When generating Paillier keys, these protocols use proofs that the modulus is square free. This crate includes this proof as a convenience and to provide a common implementation that uses reasonable parameters to achieve 128-bit security.

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

License

Apache License, Version 2.0

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be licensed as above, without any additional terms or conditions.

paillier-rs's People

Contributors

mikelodder7 avatar s0l0ist avatar survived avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

paillier-rs's Issues

Failure to compile when using `gmp` backend.

Hello! Thank you for making this library. We are trying to use libpaillier with the GMP backend (as we have measured this backend to be faster than the others). We used to specify this dependency in our Cargo.toml as:

libpaillier = { version = "0.5", default-features = false, features = ["gmp"] }

However this no longer works. We currently get this compilation error:

error[E0599]: no method named `to_string_radix` found for struct `rug::Integer` in the current scope
  --> /home/user/.cargo/registry/src/index.crates.io-6f17d22bba15001f/unknown_order-0.6.0/src/gmp_backend.rs:46:18
   |
46 |     |b: &Bn| b.0.to_string_radix(16),
   |                  ^^^^^^^^^^^^^^^ method not found in `Integer`
error: could not compile `unknown_order` (lib) due to 4 previous errors

Cargo tree (our library is called tss-ecdsa):

rug v1.24.0
└── unknown_order v0.6.0
    └── libpaillier v0.5.0
        └── tss-ecdsa v0.0.0 (/home/user/Programming/tss-ecdsa)

This error happens because rug v1.24 changes to_string_radix to have a feature cfg on std:

    #[cfg(feature = "std")]
    #[inline]
    pub fn to_string_radix(&self, radix: i32) -> String {

I believe default-features = false is turning off the std feature. So the compiler cannot find this function.

It works if I specify rug a separate dependency:

libpaillier = { version = "0.5", default-features = false, features = ["gmp"] }
rug = { version = "1.24.0"}

But we don't actually directly use rug. It took me a while to understand what was happening. Please let me know if there is a better way to specify our libpaillier or you consider this a bug on unknown_order or rug?

Thanks.

cargo test occurs errors!

Hi, I encounter two problem when use this repo.

  1. I git clone this repo and use cargo test to run the test case, but the error occurs. Such as:
error[E0433]: failed to resolve: use of undeclared crate or module `rand`
   --> tests/paillier.rs:164:39
    |
164 |     let ssk = k256::SecretKey::random(rand::rngs::OsRng::default());
    |                                       ^^^^ use of undeclared crate or module `rand`

error[E0599]: no method named `n` found for enum `Result` in the current scope
   --> tests/paillier.rs:144:20
    |
144 |     assert_eq!(pk1.n(), pk.n());
    |                    ^ method not found in `Result<libpaillier::EncryptionKey, std::string::String>`

Some errors have detailed explanations: E0433, E0599.
For more information about an error, try `rustc --explain E0433`.
  1. I use this reop an a libary in another project. I use the Encryption and Decryption examples . I execute cargo run, however, the process don't end in long time.

Need examples for BigNumber to BigInt cross compatibility

Firstly, many thanks for this updated library.

I'm using curv, more specifically Secp256k1.
It'd be helpful to have little more documentation on how I can use BigNumber with BigInt ( curv::BigInt ), and if it is possible to use both side by side.

Update `unknown_order` to 0.6

New version of dependency was just released, would be great to have libpaillier compatible with it. Let me know if you would be interested in PR for bumping dependency.

Proofs

Hi,
are there any examples of using zero knowledge proofs with the paillier-rs?

Update to unknown_order 0.4

New version of unknown_order has from_rng functions that I need.
It would be great if this library updated to it so that it could interact with that version of BigNumbers.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.