def joinsplit_sign( signing_keypair: JoinsplitSigKeyPair, sender_eth_address: str, ciphertexts: List[bytes], proof_json: GenericProof, ) -> 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 = _encode_proof_and_inputs(proof_json) h.update(proof_bytes) h.update(pub_inputs_bytes) message_digest = h.digest() #print("message digest: ", message_digest) return signing.sign(signing_keypair.sk, message_digest)
def test_mix_parameters(self) -> None: ext_proof = { "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(mix_params_json) self.assertEqual(mix_params.extended_proof, mix_params_2.extended_proof) 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 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))