module Paillier::ZKP
Public Class Methods
new(pubkey, message, valid_messages)
click to toggle source
Wrapper function that creates a ZKP
object for the user. Instead of needing to call Paillier::ZKP::ZKP.new(args)
, the user calls Paillier::ZKP.new(args)
.
Example:
>> myZKP = Paillier::ZKP.new(key, 65, [23, 38, 52, 65, 77, 94]) => [#<@p = plaintext>, #<@pubkey = <key>>, #<@ciphertext = <ciphertext>>, #<@cyphertext = <ciphertext>>, #<@commitment = <commitment>>]
Arguments:
public_key: The key to be used for the encryption (Paillier::PublicKey) plaintext: The message to be encrypted (Integer) valid_messages: The set of valid messages for encryption (Array)
NOTE: the order of valid_messages should be the same for both prover and verifier
# File lib/paillier/zkp.rb, line 144 def self.new(pubkey, message, valid_messages) return Paillier::ZKP::ZKP.new(pubkey, message, valid_messages) end
verifyZKP?(pubkey, ciphertext, valid_messages, commitment)
click to toggle source
Function that verifies whether a ciphertext is within the set of valid messages.
Example:
>> Paillier::ZKP.verifyZKP?(key, ciphertext, [23, 38, 65, 77, 94], commitment) => true
Arguments:
pubkey: The key used for the encryption (Paillier::PublicKey) ciphertext: The ciphertext generated using the public key (OpenSSL::BN) valid_messages: The set of valid messages for encryption (Array) commitment: The commitment generated by the prover (Paillier::ZKP::ZKPCommit)
NOTE: the order of valid_messages should be the same for both prover and verifier
# File lib/paillier/zkp.rb, line 162 def self.verifyZKP?(pubkey, ciphertext, valid_messages, commitment) u_s = Array.new for m_k in valid_messages do # g_mk = g ^ m_k (mod n^2) g_mk = pubkey.g.to_bn.mod_exp(m_k.to_bn, pubkey.n_sq) # u_k = c / g_mk (mod n^2) = c * invmod(g_mk) (mod n^2) u_k = OpenSSL::BN.new(ciphertext).mod_mul( Paillier.modInv(g_mk, pubkey.n_sq), pubkey.n_sq ) u_s.push(u_k) end # calculate the challenge_string sha256 = OpenSSL::Digest::SHA256.new for a_k in commitment.a_s do sha256 << a_k.to_s end challenge_string = sha256.digest.unpack('H*')[0].to_i(16) e_sum = 0.to_bn big_mod = 2.to_bn big_mod = big_mod ** 256 for e_k in commitment.e_s do e_sum = (e_sum + e_k.to_bn) % big_mod end # first we check that the sum matches correctly unless e_sum == OpenSSL::BN.new(challenge_string) return false end # then we check that z_k^n = a_k * (u_k^e_k) (mod n^2) for i in (0 .. (commitment.z_s.size - 1)) do a_k = commitment.a_s[i] e_k = commitment.e_s[i] u_k = u_s[i] z_k = commitment.z_s[i] # left hand side # z_kn = z_k ^ n (mod n^2) z_kn = z_k.to_bn.mod_exp(pubkey.n, pubkey.n_sq) # right hand side # u_ke = u_k ^ e_k (mod n^2) u_ke = u_k.to_bn.mod_exp(e_k, pubkey.n_sq) # a_kue = a_k * u_ke (mod n^2) a_kue = a_k.to_bn.mod_mul(u_ke, pubkey.n_sq) # z_k ^ n ?= a_k * (u_k ^ e_k) unless(z_kn == a_kue) return false end end # if it passes both tests, then we have validated the contents return true end