def test_mix_parameters(self) -> None: zksnark = Groth16() ext_proof = ExtendedProof(proof=Groth16.proof_from_json_dict({ "a": ["1234", "2345"], "b": [["3456", "4567"], ["5678", "6789"]], "c": ["789a", "89ab"], }), inputs=[ "9abc", "abcd", "bcde", "cdef", ]) sig_keypair = gen_signing_keypair() sig_vk = sig_keypair.vk sig = sign(sig_keypair.sk, bytes.fromhex("00112233")) receiver_enc_keypair = generate_encryption_keypair() ciphertexts = [ encrypt(token_bytes(NOTE_LENGTH_BYTES), receiver_enc_keypair.k_pk), encrypt(token_bytes(NOTE_LENGTH_BYTES), receiver_enc_keypair.k_pk), ] mix_params = MixParameters(ext_proof, sig_vk, sig, ciphertexts) mix_params_json = mix_params.to_json() mix_params_2 = MixParameters.from_json(zksnark, mix_params_json) self.assertEqual(mix_params.extended_proof.to_json_dict(), mix_params_2.extended_proof.to_json_dict()) self.assertEqual(encode_vk_to_bytes(mix_params.signature_vk), encode_vk_to_bytes(mix_params_2.signature_vk)) self.assertEqual(mix_params.signature, mix_params_2.signature) self.assertEqual(mix_params.ciphertexts, mix_params_2.ciphertexts)
def joinsplit_sign(zksnark: IZKSnarkProvider, pp: PairingParameters, signing_keypair: JoinsplitSigKeyPair, sender_eth_address: str, ciphertexts: List[bytes], extproof: ExtendedProof) -> int: """ Generate a signature on the hash of the ciphertexts, proofs and primary inputs. This is used to solve transaction malleability. We chose to sign the hash and not the values themselves for modularity (to use the same code regardless of whether GROTH16 or PGHR13 proof system is chosen), and sign the hash of the ciphers and inputs for consistency. """ assert len(ciphertexts) == constants.JS_INPUTS # The message to sign consists of (in order): # - senders Ethereum address # - ciphertexts # - proof elements # - public input elements h = sha256() h.update(eth_address_to_bytes32(sender_eth_address)) for ciphertext in ciphertexts: h.update(ciphertext) proof_bytes, pub_inputs_bytes = _proof_and_inputs_to_bytes( zksnark, pp, extproof) h.update(proof_bytes) h.update(pub_inputs_bytes) message_digest = h.digest() return signing.sign(signing_keypair.sk, message_digest)
def test_signature_encoding(self) -> None: """ Test encoding and decoding of signatures. """ m = sha256("clearmatics".encode()).digest() sig = signing.sign(self.keypair.sk, m) sig_encoded = signing.encode_signature_to_bytes(sig) sig_decoded = signing.decode_signature_from_bytes(sig_encoded) self.assertEqual(sig, sig_decoded)
def test_sign_verify_random(self) -> None: """ Test the correct signing-verification flow with random message: verify(vk, sign(sk,m), m) = 1 """ m = urandom(32) sigma = signing.sign(self.keypair.sk, m) self.assertTrue(signing.verify(self.keypair.vk, m, sigma)) keypair2 = signing.gen_signing_keypair() self.assertFalse(signing.verify(keypair2.vk, m, sigma))
def test_sign_verify(self) -> None: """ Test the correct signing-verification flow: verify(vk, sign(sk,m), m) = 1 """ m = sha256("clearmatics".encode()).digest() sigma = signing.sign(self.keypair.sk, m) self.assertTrue(signing.verify(self.keypair.vk, m, sigma)) keypair2 = signing.gen_signing_keypair() self.assertFalse(signing.verify(keypair2.vk, m, sigma))
def joinsplit_sign(zksnark: IZKSnarkProvider, pp: PairingParameters, signing_keypair: JoinsplitSigKeyPair, sender_eth_address: str, ciphertexts: List[bytes], extproof: ExtendedProof, public_data: List[int], for_dispatch_call: bool = False) -> int: """ Generate a signature on the hash of the ciphertexts, proofs and primary inputs. This is used to solve transaction malleability. We chose to sign the hash and not the values themselves for modularity (to use the same code regardless of whether GROTH16 or PGHR13 proof system is chosen), and sign the hash of the ciphers and inputs for consistency. If for_dispatch_call is set, the parameters are to be passed to the Mixer's `dispatch` call in a later operation (in which proof data is not available), hence proof is ommitted from the signature. """ assert len(ciphertexts) == constants.JS_INPUTS # The message to sign consists of (in order): # - senders Ethereum address # - ciphertexts # - proof elements (if for_dispatch_call is False) # - public input elements h = sha256() h.update(eth_address_to_bytes32(sender_eth_address)) for ciphertext in ciphertexts: h.update(ciphertext) proof_bytes, pub_inputs_bytes = _proof_and_inputs_to_bytes( zksnark, pp, extproof, public_data) # If for_dispatch_call is set, omit proof from the signature. See # AbstractMixer.sol. if not for_dispatch_call: h.update(proof_bytes) h.update(pub_inputs_bytes) message_digest = h.digest() return signing.sign(signing_keypair.sk, message_digest)