def generate_proof(self, project_dir: str, contract: str, function: str, priv_values: List, in_vals: List, out_vals: List[Union[int, CipherValue]]) -> List[int]: """ Generate a NIZK-proof using the provided circuit for the given arguments. Note: circuit arguments must be in the same order as they are declared inside the circuit. (i.e. in execution order) :param project_dir: directory where the manifest and the prover keys are located :param contract: contract of which the function which requires verification is part of :param function: the contract member function for which a proof needs to be generated :param priv_values: private/auxiliary circuit inputs in correct order :param in_vals: public circuit inputs in correct order :param out_vals: public circuit outputs in correct order :raise ProofGenerationError: if proof generation fails :return: the proof, serialized into an uint256 array """ for i in range(len(priv_values)): arg = priv_values[i] assert not isinstance(arg, Value) or isinstance(arg, (RandomnessValue, AddressValue)) if isinstance(arg, AddressValue): priv_values[i] = int.from_bytes(arg.val, byteorder='big') zk_print(f'Generating proof for {contract}.{function}') zk_print(f'[priv: {Value.collection_to_string(priv_values)}] ' f'[in: {Value.collection_to_string(in_vals)}] [out: {Value.collection_to_string(out_vals)}]', verbosity_level=2) priv_values, in_vals, out_vals = Value.unwrap_values(Value.flatten(priv_values)), Value.unwrap_values(in_vals), Value.unwrap_values(out_vals) # Check for overflows for arg in priv_values + in_vals + out_vals: assert int(arg) < bn128_scalar_field, 'argument overflow' with time_measure(f'generate_proof', True): verify_dir = cfg.get_circuit_output_dir_name(cfg.get_verification_contract_name(contract, function)) return self._generate_proof(os.path.join(project_dir, verify_dir), priv_values, in_vals, out_vals)
def compile_zkay_file(input_file_path: str, output_dir: str, import_keys: bool = False, **kwargs): """ Parse, type-check and compile the given zkay contract file. :param input_file_path: path to the zkay contract file :param output_dir: path to a directory where the compilation output should be generated :param import_keys: | if false, zk-snark of all modified circuits will be generated during compilation | if true, zk-snark keys for all circuits are expected to be already present in the output directory, and the compilation will use the provided keys to generate the verification contracts | This option is mostly used internally when connecting to a zkay contract provided by a 3rd-party :raise ZkayCompilerError: if any compilation stage fails :raise RuntimeError: if import_keys is True and zkay file, manifest file or any of the key files is missing """ code = read_file(input_file_path) # log specific features of compiled program my_logging.data('originalLoc', lines_of_code(code)) m = re.search(r'\/\/ Description: (.*)', code) if m: my_logging.data('description', m.group(1)) m = re.search(r'\/\/ Domain: (.*)', code) if m: my_logging.data('domain', m.group(1)) _, filename = os.path.split(input_file_path) # compile with time_measure('compileFull'): cg, _ = compile_zkay(code, output_dir, import_keys, **kwargs)
def generate_circuits(self, *, import_keys: bool): """ Generate circuit code and verification contracts based on the provided circuits and proving scheme. :param import_keys: if false, new verification and prover keys will be generated, otherwise key files for all verifiers are expected to be already present in the respective output directories """ # Generate proof circuit code # Compile circuits c_count = len(self.circuits_to_prove) zk_print(f'Compiling {c_count} circuits...') gen_circs = functools.partial(self._generate_zkcircuit, import_keys) with time_measure('circuit_compilation', True): if cfg.is_unit_test: modified = list(map(gen_circs, self.circuits_to_prove)) else: with Pool(processes=self.p_count) as pool: modified = pool.map(gen_circs, self.circuits_to_prove) if import_keys: for path in self.get_all_key_paths(): if not os.path.exists(path): raise RuntimeError("Zkay contract import failed: Missing keys") else: modified_circuits_to_prove = [circ for t, circ in zip(modified, self.circuits_to_prove) if t or not all(map(os.path.exists, self._get_vk_and_pk_paths(circ)))] # Generate keys in parallel zk_print(f'Generating keys for {c_count} circuits...') with time_measure('key_generation', True): if self.parallel_keygen and not cfg.is_unit_test: counter = Value('i', 0) with Pool(processes=self.p_count, initializer=self.__init_worker, initargs=(counter, c_count,)) as pool: pool.map(self._generate_keys_par, modified_circuits_to_prove) else: for circ in modified_circuits_to_prove: self._generate_keys(circ) with print_step('Write verification contracts'): for circuit in self.circuits_to_prove: vk = self._parse_verification_key(circuit) pk_hash = self._get_prover_key_hash(circuit) with open(os.path.join(self.output_dir, circuit.verifier_contract_filename), 'w') as f: primary_inputs = self._get_primary_inputs(circuit) f.write(self.proving_scheme.generate_verification_contract(vk, circuit, primary_inputs, pk_hash))
def transaction_benchmark_ctx(contract_dir: str, log_filename='log') -> ContextManager[Any]: use_configuration_from_manifest(contract_dir) cfg.verbosity = 0 cfg.log_dir = contract_dir log_file = my_logging.get_log_file(filename=log_filename, include_timestamp=False, label=None) my_logging.prepare_logger(log_file) with time_measure('all_transactions', should_print=True): yield load_transaction_interface_from_directory(contract_dir) pass
def test_timer_context_manager(self): log_file = base_log_file + '_context_manager' my_logging.prepare_logger(log_file) my_logging.shutdown() with time_measure('mykey2'): time.sleep(0.5) content = read_file(log_file + '_data.log') d = json.loads(content) self.assertAlmostEqual(0.5, d['value'], 1)
def _dec(self, cipher: Tuple[int, ...], sk: Any) -> Tuple[int, List[int]]: with time_measure("elgamal_decrypt"): c1 = babyjubjub.Point(babyjubjub.Fq(cipher[0]), babyjubjub.Fq(cipher[1])) c2 = babyjubjub.Point(babyjubjub.Fq(cipher[2]), babyjubjub.Fq(cipher[3])) shared_secret = c1 * babyjubjub.Fr(sk) plain_embedded = c2 + shared_secret.negate() plain = self._de_embed(plain_embedded) # TODO randomness misused for the secret key, which is an extremely ugly hack... return plain, [sk]
def _generate_proof(self, verifier_dir: str, priv_values: List[int], in_vals: List[int], out_vals: List[int]) -> List[int]: args = list(map(int, in_vals + out_vals + priv_values)) # Generate proof in temporary directory with TemporaryDirectory() as tempd: proof_path = os.path.join(tempd, 'proof.out') try: with time_measure("jsnark_prepare_proof"): jsnark.prepare_proof(verifier_dir, tempd, args) with time_measure("libsnark_gen_proof"): libsnark.generate_proof(verifier_dir, tempd, proof_path, self.proving_scheme) except SubprocessError as e: raise ProofGenerationError(e.args) with open(proof_path) as f: proof_lines = f.read().splitlines() proof = list(map(lambda x: int(x, 0), proof_lines)) return proof
def _deploy_dependencies(self, sender: Union[bytes, str], project_dir: str, verifier_names: List[str]) -> Dict[str, AddressValue]: # Deploy verification contracts if not already done vf = {} for verifier_name in verifier_names: with log_context('constructor'): with log_context(f'{verifier_name}'): filename = os.path.join(project_dir, f'{verifier_name}.sol') cout = self.compile_contract(filename, verifier_name, self.lib_addresses) with time_measure("transaction_full"): vf[verifier_name] = AddressValue(self._deploy_contract(sender, cout).address) for crypto_params in cfg.all_crypto_params(): pki_contract_name = cfg.get_pki_contract_name(crypto_params) pki_contract_address = self.pki_contract(crypto_params.crypto_name).address vf[pki_contract_name] = AddressValue(pki_contract_address) return vf