Giter Club home page Giter Club logo

paillier.jl's Introduction

Paillier.jl is a Julia package implementing the basics of the Paillier partially homomorphic cryptosystem.

Build Status

The homomorphic properties of the paillier crypto system are:

  • Encrypted numbers can be multiplied by a non encrypted scalar.
  • Encrypted numbers can be added together.

Warning - Here be dragons.

This is rough! Don't use for anything serious yet! Not reviewed by a cryptographer.

Constant time functions have not been used, so this could be susceptible to timing side channel attacks.

We don't obfuscate the results of encrypted math operations by default. This is an optimization copied from python-paillier, however after any homomorphic operation - before sharing an EncryptedNumber or EncryptedArray you must call obfuscate() to secure the ciphertext. Ideally this will occur behind the scenes at serialization time, but this library does not help with serialization (yet).

Based off the sketch written by Morten Dahl at Snips, and the python-paillier library written by CSIRO's Data61 as part of N1 Analytics.

paillier.jl's People

Contributors

github-actions[bot] avatar hardbyte avatar

Stargazers

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

Watchers

 avatar  avatar

Forkers

sarahsama

paillier.jl's Issues

Raw cryptosystem shouldn't be signed

In cryptosystem.jl I have a helper function to calculate the maximum plaintext integer:
max_int(n::BigInt) = BigInt(floor(n // 3))

This is used in the multiplication function:

function raw_multiply(public_key::PublicKey, ciphertext::Ciphertext, plaintext::Integer)::Ciphertext
    @debug "Raw encrypted multiply by $plaintext"

    if public_key.n - max_int(public_key) <= plaintext
        neg_ciphertext = invmod(ciphertext, public_key.n_sq)
        neg_scalar = public_key.n - plaintext
        new_ciphertext = powermod(neg_ciphertext, neg_scalar, public_key.n_sq)
    else
        new_ciphertext = powermod(ciphertext, plaintext, public_key.n_sq)
    end
    return new_ciphertext
end

This is from copying python-paillier which doesn't make a clear distinction between raw unsigned integer encryption and working with encoded numbers.

In the case of Paillier.jl I'd like to keep the concepts separate by supporting the full range for all operations for the raw cryptosystem.

Encoding should be a parametric type to allow multiple dispatch

I've been thinking about how Paillier.jl composes with other parts of the Julia ecosystem, in particular the fact that users should be able to encode and encrypt/decrypt user defined types easily.

Currently using the library with Measurement.jl numbers is messy. One method would be to create an array of both the value and the error from the measurement object:

> encoding = Encoding(Float64, publickey)
> Paillier.encode_and_encrypt(plaintext::Measurement, encoding::Encoding) = Paillier.encode_and_encrypt([plaintext.val, plaintext.err], encoding)
> encrypted_g_with_uncertainty = encode_and_encrypt(9.79 ± 0.02, encoding);
> decrypt_and_decode(privatekey, encrypted_g_with_uncertainty)
2-element Array{Float16,1}:
 9.79
 0.02

However as the encoding doesn't include the Measurement type we can't nicely reconstruct a Measurement object after decryption and decoding.

Creating an encoding of a Measurement doesn't work either:

> measurementencoding = Encoding(Measurement{Float64}, publickey)
> encrypted_g_2 = encode_and_encrypt(9.79 ± 0.02, measurementencoding)
MethodError: no method matching precision(::Type{Measurement{Float64}})
Closest candidates are:
  precision(!Matched::BigFloat) at mpfr.jl:805
  precision(!Matched::Type{Float16}) at float.jl:579
  precision(!Matched::Type{Float32}) at float.jl:580
  ...

Stacktrace:
 [1] encode(::Float64, ::Encoding) at src\Encoding.jl:200

As Julia tries to ascertain the precision of a Measurement within the encode method.

Now while we could probably hack the precision method to unwrap the measurement object, there is still a question of how to encode the measurement into one or more integers suitable for encryption. A better strategy for handling encoding of arbitrary user defined types might be to have users override encode for their user defined Encoding type.

So instead of Encoding being defined as:

struct Encoding
    datatype::DataType
    public_key::PublicKey
    base::Int64
end

Perhaps it should be a parametric type:

struct Encoding{T}
    public_key::PublicKey
    base::Int64
end

# Example use:
encoding = Encoding{Measurement{Float64}}(publickey, 16)

# Then a user can specialize the `encode` and `decode` methods for their data type. E.g.:
Paillier.encode(scalar::Measurement{Float64}, encoding::Encoding{Measurement{T}}) where T = Paillier.encode(
    [scalar.val, scalar.err], 
    Encoding{T}(encoding.public_key, encoding.base)
)

# decode would need more work as decrypt_and_decode calls decode for each element
# of an encrypted array and not with an array of encodings. But that refactoring seems sensible 
# at first glance. Which for our example of encoding a Measurement as an array of encrypted numbers give something like this for the decode method:
decode(encoded::Array{BigInt}, exponent, encoding::Encoding{Measurement{T}}) where T = 
    measurement(decode(encoded[1], exponent, T), decode(encoded[2], exponent, T))

Pass in rng to key generation and obfuscation steps

It is best practice to pass in io streams and random number generators to functions, I need to modify the key generator and the obfuscate functions to allow/require a rng to be passed by the caller.

Not requiring the user to pass in a rng would be nice to keep.

Random number stream/pool

It would be faster to precompute a bunch of n bit random numbers for a given public key's n so that during use (in particular during the obfuscation step) the numbers are already to go.

One idea is that a Channel is created with a specific sized buffer and a Task has the job of keeping it full.

It would be worth benchmarking before and after this.

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.