module Paillier
Public Class Methods
decrypt(privKey, pubKey, ciphertext)
click to toggle source
Decrypts a message, returning plaintext
Example:
>> Paillier.decrypt(priv, pub, Paillier.encrypt(priv, pub, 3)) => 3
Arguments:
privKey: (Paillier::PrivateKey) pubKey: (Paillier::PublicKey) ciphertext: (Int, OpenSSL::BN, String)
# File lib/paillier.rb, line 203 def self.decrypt(privKey, pubKey, ciphertext) if( ciphertext.is_a?(String) ) ciphertext = OpenSSL::BN.new(ciphertext) end # We want to run: x = ((cipher ** priv.l) % pub.n_sq) - 1 # But the numbers are too big, so we'll use openssl x = ciphertext.to_bn.mod_exp(privKey.l, pubKey.n_sq) - 1 plain = (x.to_i / pubKey.n.to_i).to_bn.mod_mul(privKey.m, pubKey.n) return plain end
eAdd(publicKey, a, b)
click to toggle source
Adds one encrypted int to another
Example:
>> Paillier.eAdd(publicKey, cx, cy) => #<OpenSSL::BN::cyphertext>
Arguments:
publicKey: (Paillier::PublicKey) a: (Int, OpenSSL::BN, String) b: (Int, OpenSSL::BN, String)
# File lib/paillier.rb, line 143 def self.eAdd(publicKey, a, b) if( a.is_a?(String) ) a = OpenSSL::BN.new(a) end if( b.is_a?(String) ) b = OpenSSL::BN.new(b) end return a.to_bn.mod_mul(b, publicKey.n_sq) end
eAddConst(publicKey, a, n)
click to toggle source
Adds a plaintext constant 'n' to an encrypted int
Example:
>> Paillier.eAddConst(publicKey, cyphertext, 3) => #<OpenSSL::BN::cyphertext>
Arguments:
publicKey: (Paillier::PublicKey) a: (Int, OpenSSL::BN, String) n: (Int, OpenSSL::BN, String)
# File lib/paillier.rb, line 163 def self.eAddConst(publicKey, a, n) if( a.is_a?(String) ) a = OpenSSL::BN.new(a) end if( n.is_a?(String) ) n = OpenSSL::BN.new(n) end return a.to_bn.mod_mul(modPow(publicKey.g, n, publicKey.n_sq), publicKey.n_sq) end
eMulConst(publicKey, a, n)
click to toggle source
Multiplies an encrypted int by a constant
Example:
>> Paillier.eMulConst(publicKey, cyphertext, 2) => #<OpenSSL::BN::cyphertext>
Arguments:
publicKey: (Paillier::PublicKey) a: (Int, OpenSSL::BN, String) n: (Int, OpenSSL::BN, String)
# File lib/paillier.rb, line 183 def self.eMulConst(publicKey, a, n) if( a.is_a?(String) ) a = OpenSSL::BN.new(a) end if( n.is_a?(String) ) n = OpenSSL::BN.new(n) end return modPow(a, n, publicKey.n_sq) end
encrypt(publicKey, plaintext)
click to toggle source
Encrypts a message with the provided public key
Example:
>> Paillier.encrypt(publicKey, 3) => #<OpenSSL::BN:cyphertext>
Arguments:
publicKey: (Paillier::PublicKey) plaintext: (Int, OpenSSL::BN, String)
# File lib/paillier.rb, line 126 def self.encrypt(publicKey, plaintext) if( plaintext.is_a?(String) ) plaintext = OpenSSL::BN.new(plaintext) end return rEncrypt(publicKey, plaintext)[1] end
generateKeypair(bits)
click to toggle source
Generates a new public private keypair
Example:
>> Paillier.generateKeypair(2048) => [#<Paillier::PrivateKey>, #<Paillier::PublicKey>]
Arguments:
bits: (Int)
# File lib/paillier.rb, line 71 def self.generateKeypair(bits) p = Primes.generatePrime(bits/2) q = Primes.generatePrime(bits/2) n = p * q # actual keygen grumble grumble # all the libraries we found did it wrong and just made lambda = phi(n) # and set mu to phi(n)^-1 # this is the actual spec for it lambda_n = ( (p-1) * (q-1) ) / gcd( (p-1), (q-1) ) # this is technically a shortcut but not incorrect, the public key is unrelated to the private one g = n + 1 # intermediary step u = (g.to_bn.mod_exp(lambda_n, n * n)).to_i # intermediary step u_2 = (u - 1) / n # now we have mu mu = Paillier.modInv(u_2, n) return PrivateKey.new(lambda_n, mu), PublicKey.new(n) end
sign(priv, pub, data)
click to toggle source
Returns a detached signature for any message
Example:
>> Paillier.sign(priv, pub, 3) => #<Paillier::Signature>
Arguments:
priv: (Paillier::PrivateKey) pub: (Paillier::PublicKey) data: (Int, OpenSSL::BN, String)
# File lib/paillier.rb, line 224 def self.sign(priv, pub, data) if( data.is_a?(String) ) data = OpenSSL::BN.new(data) end hashData = hash(data) # L(u) = (u-1)/n numerators1 = ((hashData.to_bn.mod_exp(priv.l, pub.n_sq) - 1) / pub.n.to_bn)[0] denominators1 = ((pub.g.to_bn.mod_exp(priv.l, pub.n_sq) - 1) / pub.n.to_bn)[0] #s1 = ((numerators1[0] / denominators1[0]))[0] % pub.n inverse_denom = Paillier.modInv(denominators1.to_i, pub.n) s1 = numerators1.to_bn.mod_mul(inverse_denom, pub.n) inverse_n = Paillier.modInv(pub.n, priv.l) inverse_g = Paillier.modInv(pub.g.to_bn.mod_exp(s1.to_bn, pub.n).to_i, pub.n) s2 = (hashData * inverse_g).to_bn.mod_exp(inverse_n, pub.n) return Signature.new(s1, s2) end
validSignature?(pub, message, sig)
click to toggle source
Validates the signature for a given message Returns true if signature is good, false otherwise
Example:
>> Paillier.validSignature(pub, 3, Paillier.sign(priv, pub, 3)) => true
Arguments:
pub: (Paillier::PublicKey) message: (Int, OpenSSL::BN, String) sig: (Paillier::Signature)
# File lib/paillier.rb, line 258 def self.validSignature?(pub, message, sig) if( message.is_a?(String) ) message = OpenSSL::BN.new(message) end hash = Digest::SHA256.hexdigest(message.to_s).to_i(16) # We want to run (g ** s1) * (s2 ** n) % (n**2) # But all those numbers are huge, so we approach it in stages a = pub.g.to_bn.mod_exp(sig.s1, pub.n_sq) b = sig.s2.to_bn.mod_exp(pub.n, pub.n_sq) sighash = a.mod_mul(b, pub.n_sq) return (hash == sighash) end