def simulate_proof(self, challenge=None, *args, **kwargs): # Simulate the n-1 first subproofs, computes the complementary challenge and # simulates the last proof using this challenge. if challenge is None: challenge = get_random_num(bits=CHALLENGE_LENGTH) com = [] resp = [] or_chals = [] precom = [] # Generate one simulation at a time and update a list of each attribute. for index, subproof in enumerate(self.subproofs[:-1]): transcript = subproof.simulate_proof() com.append(transcript.commitment) resp.append(transcript.responses) or_chals.append(transcript.challenge) precom.append(transcript.precommitment) # Generate the last simulation. final_chal = _find_residual_challenge(or_chals, challenge, CHALLENGE_LENGTH) or_chals.append(final_chal) final_transcript = self.subproofs[index + 1].simulate_proof( challenge=final_chal) com.append(final_transcript.commitment) resp.append(final_transcript.responses) precom.append(final_transcript.precommitment) # Pack everything into a SimulationTranscript, pack the or-challenges in the response field. return SimulationTranscript( commitment=com, challenge=challenge, responses=(or_chals, resp), precommitment=precom, )
def ZK_equality(G,H): ##Generate two El-Gamal ciphertexts (C1,C2) and (D1,D2) # Setup: generate secret randomizers. # m is the secret bit. m = Secret(utils.get_random_num(bits=2)) r1 = Secret(utils.get_random_num(bits=128)) r2 = Secret(utils.get_random_num(bits=128)) C1 = r1.value*G #print("this is C1:", C1) C2 = r1.value * H + m.value * G D1 = r2.value * G D2 = r2.value * H + m.value * G ##Generate a NIZK proving equality of the plaintexts stmt = DLRep(C1,r1*G) & DLRep(C2,r1*H+m*G) & DLRep(D1,r2*G) & DLRep(D2,r2*H+m*G) zk_proof = stmt.prove() #Return two ciphertexts and the proof return (C1,C2), (D1,D2), zk_proof
def test_statement_zk_proof() -> None: vm = sy.VirtualMachine() client = vm.get_root_client() sy.load("zksk") # third party from zksk import DLRep from zksk import Secret from zksk import utils num = 2 seed = 42 num_sy = sy.lib.python.Int(num) seed_sy = sy.lib.python.Int(seed) # Setup: Peggy and Victor agree on two group generators. G, H = utils.make_generators(num=num, seed=seed) # Setup: generate a secret randomizer. r = Secret(utils.get_random_num(bits=128)) # This is Peggy's secret bit. top_secret_bit = 1 # A Pedersen commitment to the secret bit. C = top_secret_bit * G + r.value * H # Peggy's definition of the proof statement, and proof generation. # (The first or-clause corresponds to the secret value 0, and the second to the value 1. Because # the real value of the bit is 1, the clause that corresponds to zero is marked as simulated.) stmt = DLRep(C, r * H, simulated=True) | DLRep(C - G, r * H) zk_proof = stmt.prove() # send over the network and get back num_ptr = num_sy.send(client) seed_prt = seed_sy.send(client) c_ptr = C.send(client) zk_proof_ptr = zk_proof.send(client) num2 = num_ptr.get().upcast() seed2 = seed_prt.get().upcast() C2 = c_ptr.get() zk_proof2 = zk_proof_ptr.get() # Setup: get the agreed group generators. G, H = utils.make_generators(num=num2, seed=seed2) # Setup: define a randomizer with an unknown value. r = Secret() stmt = DLRep(C2, r * H) | DLRep(C2 - G, r * H) assert stmt.verify(zk_proof2)
def send_challenge(self, commitment): """ Store the received commitment and generate a challenge. The challenge is chosen at random between 0 and ``CHALLENGE_LENGTH`` (excluded). Args: commitment: A tuple containing a hash of the stmt statement, to be compared against the local statement, and the commmitment as a (potentially multi-level list of) base(s) of the group. """ statement, self.commitment = commitment self.stmt.check_statement(statement) self.challenge = get_random_num(bits=CHALLENGE_LENGTH) return self.challenge
def simulate_proof(self, responses_dict=None, challenge=None): """ Returns a transcript of a proof simulation. Responses and challenge can be enforced. The function will misbehave if passed a non-empty but incomplete responses_dict. Args: responses_dict: Optinal mapping from secrets or secret names to responses. challenge: Optional challenge to use in the simulation """ # Fill the missing positions of the responses dictionary responses_dict = self.update_randomizers(responses_dict) if challenge is None: challenge = get_random_num(CHALLENGE_LENGTH) responses = [responses_dict[m] for m in self.secret_vars] # Random responses, the same for shared secrets commitment = self.recompute_commitment(challenge, responses) return SimulationTranscript(commitment=commitment, challenge=challenge, responses=responses)
def send_challenge(self, commitment, ignore_statement_hash_checks=False): """ Store the received commitment and generate a challenge. Additionally checks the received hashed statement matches the one of the current proof. Only called at the highest level or in extended proofs. Args: commitment: A tuple (statement, actual_commitment) with actual_commitment a list of commitments, one for each subproof. ignore_statement_hash_checks: Optional parameter to deactivate the statement check. In this case, the commitment parameter is simply the actual commitment. Useful in 2-level proofs for which we don't check the inner statements. """ if ignore_statement_hash_checks: self.commitment = commitment else: statement, self.commitment = commitment self.stmt.check_statement(statement) self.challenge = get_random_num(CHALLENGE_LENGTH) return self.challenge
def test_nizk_serde() -> None: vm = sy.VirtualMachine() client = vm.get_root_client() # third party from zksk import DLRep from zksk import Secret from zksk import utils sy.load("zksk") num = 2 seed = 42 G, H = utils.make_generators(num=num, seed=seed) # Setup: generate a secret randomizer. r = Secret(utils.get_random_num(bits=128)) # This is Peggy's secret bit. top_secret_bit = 1 # A Pedersen commitment to the secret bit. C = top_secret_bit * G + r.value * H # Peggy's definition of the proof statement, and proof generation. # (The first or-clause corresponds to the secret value 0, and the second to the value 1. Because # the real value of the bit is 1, the clause that corresponds to zero is marked as simulated.) stmt = DLRep(C, r * H, simulated=True) | DLRep(C - G, r * H) # zksk.base.NIZK zk_proof = stmt.prove() # test serde zk_proof_ptr = zk_proof.send(client) zk_proof2 = zk_proof_ptr.get() assert zk_proof == zk_proof2
def simulate_proof(self, responses_dict=None, challenge=None): """ Simulate the And proof To do so, draw a global challenge, a global dictionary of responses (for consistency) and simulate each subproof. Gathers the commitments, and pack everything into a :py:class:`base.SimulationTranscript`. Args: responses_dict: A dictionary of responses to override (could come from an upper And Proof, for example). Draw randomly if None. challenge: The challenge to use in the proof. Draw one if None. """ # Fill the missing positions of the responses dictionary responses_dict = self.update_randomizers(responses_dict) if challenge is None: challenge = get_random_num(CHALLENGE_LENGTH) com = [] resp = [] precom = [] # Simulate all subproofs and gather their attributes, repack them in a unique # SimulationTranscript. for sub in self.subproofs: simulation = sub.simulate_proof(challenge=challenge, responses_dict=responses_dict) com.append(simulation.commitment) resp.append(simulation.responses) precom.append(simulation.precommitment) return SimulationTranscript(commitment=com, challenge=challenge, responses=resp, precommitment=precom)