You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@milagro.apache.org by sa...@apache.org on 2020/02/26 20:02:19 UTC
[incubator-milagro-MPC] 04/05: Add full flow using python wrappers
This is an automated email from the ASF dual-hosted git repository.
sandreoli pushed a commit to branch issue18-add-python-flow-example
in repository https://gitbox.apache.org/repos/asf/incubator-milagro-MPC.git
commit 916cb3561989f0e04d4f0cf948cb87220b713fa5
Author: Samuele Andreoli <sa...@yahoo.it>
AuthorDate: Wed Feb 26 16:24:20 2020 +0000
Add full flow using python wrappers
---
python/examples/example_full.py | 359 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 359 insertions(+)
diff --git a/python/examples/example_full.py b/python/examples/example_full.py
new file mode 100755
index 0000000..cece81b
--- /dev/null
+++ b/python/examples/example_full.py
@@ -0,0 +1,359 @@
+#!/usr/bin/env python3
+
+"""
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+"""
+
+import os
+import sys
+
+sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
+
+from amcl import core_utils, mpc, schnorr, factoring_zk, commitments
+
+seed_hex = "78d0fb6705ce77dee47d03eb5b9c5d30"
+
+
+def generate_key_material(rng, player):
+ """ Generate Paillier and ECDSA Key Pairs
+
+ Generate key material and commitment to the ECDSA PK.
+ The key material dictionary has keys:
+ * paillier_sk
+ * paillier_pk
+ * ecdsa_sk
+ * ecdsa_pk
+
+ Args::
+
+ rng: pointer to CSPRNG
+
+ Returns::
+
+ key_material: dictionary with the generated key material
+
+ """
+ # Paillier keys
+ paillier_pk, paillier_sk = mpc.paillier_key_pair(rng)
+
+ # ECDSA keys
+ ecdsa_pk, ecdsa_sk = mpc.mpc_ecdsa_key_pair_generate(rng)
+ rc = mpc.ecp_secp256k1_public_key_validate(ecdsa_pk)
+ assert rc == 0, f"[{player}] Invalid ECDSA public key. rc {rc}"
+
+ key_material = {
+ 'paillier_pk' : paillier_pk,
+ 'paillier_sk' : paillier_sk,
+ 'ecdsa_pk' : ecdsa_pk,
+ 'ecdsa_sk' : ecdsa_sk
+ }
+
+ return key_material
+
+
+def generate_key_material_zkp(rng, key_material):
+ """ Generate ZK Proofs for key material
+
+ Generate a commitment to the ECDSA PK, a Schnorr's
+ Proof for the ECDSA PK and a factoring Proof for the
+ Paillier PK
+ The key material dictionary must have keys:
+ * paillier_sk
+ * paillier_pk
+ * ecdsa_sk
+ * ecdsa_pk
+
+ Args::
+
+ rng: pointer to CSPRNG
+ key_material: dictionary with the key material
+
+ Returns::
+
+ r: secret value for the ECDSA PK commitment
+ c: commitment for the ECDSA PK
+ sc: commitment for the Schnorr's Proof
+ sp: Schnorr's Proof
+ fe: Factoring Proof. First component
+ fy: Factoring Proof. Second component
+
+ """
+ # Commit to ECDSA PK
+ r, c = commitments.nm_commit(rng, key_material['ecdsa_pk'])
+
+ # Generate Schnorr's proof for ECDSA PK
+ sr, sc = schnorr.commit(rng)
+ e = schnorr.challenge(key_material['ecdsa_pk'], sc)
+ sp = schnorr.prove(sr, e, key_material['ecdsa_sk'])
+
+ # Generate ZKP of knowledge of factorization for
+ # Paillier key pair
+ psk_p, psk_q = mpc.mpc_dump_paillier_sk(key_material['paillier_sk'])
+
+ fe, fy = factoring_zk.prove(rng, psk_p, psk_q)
+
+ return r, c, sc, sp, fe, fy
+
+
+def verify_key_material(key_material, r, c, sc, sp, fe, fy, player):
+ """ Verify key material
+
+ Verify the conunterparty key material using the
+ proof received
+ The key material dictionary must have keys:
+ * paillier_pk
+ * ecdsa_pk
+
+ Args::
+
+ key_material: dictionary with the key material
+ r: secret value for the ECDSA PK commitment
+ c: commitment for the ECDSA PK
+ sc: commitment for the Schnorr's Proof
+ sp: Schnorr's Proof
+ fe: Factoring Proof. First component
+ fy: Factoring Proof. Second component
+
+ Returns::
+
+ """
+ # Decommit ECDSA PK
+ rc = commitments.nm_decommit(key_material['ecdsa_pk'], r, c)
+ assert rc == commitments.OK, f"[{player}] Failure decommitting ecdsa_pk. rc {rc}"
+
+ # Verify ECDSA PK Schnorr's proof
+ e = schnorr.challenge(key_material['ecdsa_pk'], sc)
+ rc = schnorr.verify(key_material['ecdsa_pk'], sc, e, sp)
+ assert rc == schnorr.OK, f"[{player}] Invalid ECDSA PK Schnorr Proof. rc {rc}"
+
+ # Verify factoring ZKP
+ n = mpc.paillier_pk_to_octet(key_material['paillier_pk'])
+ rc = factoring_zk.verify(n, fe, fy)
+ assert rc == factoring_zk.OK, f"[{player}] Invalid Factoring ZKP. rc {rc}"
+
+
+if __name__ == "__main__":
+ seed = bytes.fromhex(seed_hex)
+ rng = core_utils.create_csprng(seed)
+
+
+ ### Key setup ###
+
+ print("Setup Key Material\n")
+
+ # Generate key material
+ key_material1 = generate_key_material(rng, "Alice")
+ key_material2 = generate_key_material(rng, "Bob")
+
+ print("[Alice] Generate ECDSA and Paillier key pairs")
+ print("[Bob] Generate ECDSA and Paillier key pairs")
+
+ # Generate key material ZKP
+ r1, c1, sc1, sp1, fe1, fy1 = generate_key_material_zkp(rng, key_material1)
+ r2, c2, sc2, sp2, fe2, fy2 = generate_key_material_zkp(rng, key_material2)
+
+ print("[Alice] Generate commitment to ECDSA PK and ZKPs")
+ print("[Bob] Generate commitment to ECDSA PK and ZKPs")
+
+ # Commit to ECDSA PK by transmitting c
+ print("[Alice] Commit to ECDSA PK. Transmit c")
+ print("[Bob] Commit to ECDSA PK. Transmit c")
+
+ # Transmit decommitment and ZKP
+ print("[Alice] Transmit decommitment for ECDSA PK and ZKPs")
+ print("[Bob] Transmit decommitment for ECDSA PK and ZKPs")
+
+ # Verify decommitment and ZKP
+ c_key_material1 = {
+ 'paillier_pk' : key_material2['paillier_pk'],
+ 'ecdsa_pk' : key_material2['ecdsa_pk'],
+ }
+
+ c_key_material2 = {
+ 'paillier_pk' : key_material1['paillier_pk'],
+ 'ecdsa_pk' : key_material1['ecdsa_pk'],
+ }
+
+ print("[Alice] Verify ZKP")
+ verify_key_material(c_key_material1, r2, c2, sc2, sp2, fe2, fy2, "Alice")
+
+ print("[Bob] Verify ZKP")
+ verify_key_material(c_key_material2, r1, c1, sc1, sp1, fe1, fy1, "Bob")
+
+ # Recombine full ECDSA PK
+ rc, ecdsa_full_pk1 = mpc.mpc_sum_pk(key_material1['ecdsa_pk'], c_key_material1['ecdsa_pk'])
+ assert rc == 0, '[Alice] Error recombining full ECDSA PK'
+
+ rc, ecdsa_full_pk2 = mpc.mpc_sum_pk(key_material2['ecdsa_pk'], c_key_material2['ecdsa_pk'])
+ assert rc == 0, '[Bob] Error recombining full ECDSA PK'
+
+
+ ### Signature ###
+
+ # Message
+ M = b'test message'
+
+ print(f"\nSign message '{M.encode('utf-8')}'")
+
+ # Generate k, gamma and gamma.G
+ print("[Alice] Generate k, gamma and gamma.G")
+ GAMMA1, gamma1 = mpc.mpc_ecdsa_key_pair_generate(rng)
+ k1 = mpc.mpc_k_generate(rng)
+
+ print("[Bob] Generate k, gamma and gamma.G")
+ GAMMA2, gamma2 = mpc.mpc_ecdsa_key_pair_generate(rng)
+ k2 = mpc.mpc_k_generate(rng)
+
+ ## Commit to GAMMA1, GAMMA2
+ print("[Alice] Commit to GAMMA1")
+ GAMMAR1, GAMMAC1 = commitments.nm_commit(rng, GAMMA1)
+
+ print("[Bob] Commit to GAMMA2")
+ GAMMAR2, GAMMAC2 = commitments.nm_commit(rng, GAMMA2)
+
+ ## Engage in MTA with k_i, gamma_j
+
+ # k1, gamma2
+ print("[Alice] Engage in MTA with shares k1, gamma2")
+
+ ca = mpc.mpc_mta_client1(rng, key_material1['paillier_pk'], k1)
+ cb, beta2 = mpc.mpc_mta_server(rng, c_key_material2['paillier_pk'], gamma2, ca)
+ alpha1 = mpc.mpc_mta_client2(key_material1['paillier_sk'], cb)
+
+ # k2, gamma1
+ print("[Bob] Engage in MTA with shares k2, gamma1")
+
+ ca = mpc.mpc_mta_client1(rng, key_material2['paillier_pk'], k2)
+ cb, beta1 = mpc.mpc_mta_server(rng, c_key_material1['paillier_pk'], gamma1, ca)
+ alpha2 = mpc.mpc_mta_client2(key_material2['paillier_sk'], cb)
+
+ # Partial sums
+ print("[Alice] Combine partial sum delta1 for kgamma")
+ delta1 = mpc.mpc_sum_mta(k1, gamma1, alpha1, beta1)
+
+ print("[Bob] Combine partial sum delta2 for kgamma")
+ delta2 = mpc.mpc_sum_mta(k2, gamma2, alpha2, beta2)
+
+ ## Engage in MTA with k_i, sk_j
+
+ # k1, sk2
+ print("[Alice] Engage in MTA with k1, s2")
+ ca = mpc.mpc_mta_client1(rng, key_material1['paillier_pk'], k1)
+ cb, beta2 = mpc.mpc_mta_server(rng, c_key_material2['paillier_pk'], key_material2['ecdsa_sk'], ca)
+ alpha1 = mpc.mpc_mta_client2(key_material1['paillier_sk'], cb)
+
+ # k2, sk1
+ print("[Bob] Engage in MTA with k2, s1")
+ ca = mpc.mpc_mta_client1(rng, key_material2['paillier_pk'], k2)
+ cb, beta1 = mpc.mpc_mta_server(rng, c_key_material1['paillier_pk'], key_material1['ecdsa_sk'], ca)
+ alpha2 = mpc.mpc_mta_client2(key_material2['paillier_sk'], cb)
+
+ # Partial sums
+ print("[Alice] Combine partial sum sigma1 for kw")
+ sigma1 = mpc.mpc_sum_mta(k1, key_material1['ecdsa_sk'], alpha1, beta1)
+
+ print("[Bob] Combine partial sum sigma2 for kw")
+ sigma2 = mpc.mpc_sum_mta(k2, key_material2['ecdsa_sk'], alpha2, beta2)
+
+ ## Decommitment and Proofs for R component
+
+ # Generate Schnorr's Proofs
+ print("[Alice] Generate Schnorr's Proof")
+ GAMMA_schnorr_r1, GAMMA_schnorr_c1 = schnorr.commit(rng)
+ GAMMA_schnorr_e1 = schnorr.challenge(GAMMA1, GAMMA_schnorr_c1)
+ GAMMA_schnorr_p1 = schnorr.prove(GAMMA_schnorr_r1, GAMMA_schnorr_e1, gamma1)
+
+ print("[Bob] Generate Schnorr's Proof")
+ GAMMA_schnorr_r2, GAMMA_schnorr_c2 = schnorr.commit(rng)
+ GAMMA_schnorr_e2 = schnorr.challenge(GAMMA2, GAMMA_schnorr_c2)
+ GAMMA_schnorr_p2 = schnorr.prove(GAMMA_schnorr_r2, GAMMA_schnorr_e2, gamma2)
+
+ print("[Alice] Transmit decommitment and Schnorr Proof for GAMMA1")
+ print("[Bob] Transmit decommitment and Schnorr Proof for GAMMA2")
+
+ # Decommit GAMMAi and verify Schnorr Proof
+ rc = commitments.nm_decommit(GAMMA2, GAMMAR2, GAMMAC2)
+ assert rc == commitments.OK, f'[Alice] Error decommitting GAMMA2. rc {rc}'
+
+ GAMMA_schnorr_e2 = schnorr.challenge(GAMMA2, GAMMA_schnorr_c2)
+ rc = schnorr.verify(GAMMA2, GAMMA_schnorr_c2, GAMMA_schnorr_e2, GAMMA_schnorr_p2)
+ assert rc == schnorr.OK, f'[Alice] Error verifying Schnorr proof for GAMMA2'
+
+ rc = commitments.nm_decommit(GAMMA1, GAMMAR1, GAMMAC1)
+ assert rc == commitments.OK, f'[Bob] Error decommitting GAMMA1. rc {rc}'
+
+ GAMMA_schnorr_e1 = schnorr.challenge(GAMMA1, GAMMA_schnorr_c1)
+ rc = schnorr.verify(GAMMA1, GAMMA_schnorr_c1, GAMMA_schnorr_e1, GAMMA_schnorr_p1)
+ assert rc == schnorr.OK, f'[Bob] Error verifying Schnorr proof for GAMMA1'
+
+ ## Reconcile R component
+ print("[Alice] Recombine kgamma^(-1)")
+ ikgamma1 = mpc.mpc_invkgamma(delta1, delta2)
+ rc, R1, _ = mpc.mpc_r(ikgamma1, GAMMA1, GAMMA2)
+ assert rc == 0, f'[Alice] Error reconciling R. rc {rc}'
+
+ print("[Bob] Recombine kgamma^(-1)")
+ ikgamma2 = mpc.mpc_invkgamma(delta1, delta2)
+ rc, R2, _ = mpc.mpc_r(ikgamma2, GAMMA1, GAMMA2)
+ assert rc == 0, f'[Bob] Error reconciling R. rc {rc}'
+
+ ## Compute signature shares
+ hm = mpc.mpc_hash(M)
+
+ rc, s1 = mpc.mpc_s(hm, R1, k1, sigma1)
+ assert rc == 0, f'[Alice] Error computing signature share s1'
+
+ rc, s2 = mpc.mpc_s(hm, R2, k2, sigma2)
+ assert rc == 0, f'[Bob] Error computing signature share s1'
+
+ ## Reconcile S component
+
+ # Commit to signature shares
+ print("[Alice] Transmit commitment signature share s1")
+ SR1, SC1 = commitments.nm_commit(rng, s1)
+
+ print("[Bob] Transmit commitment signature share s2")
+ SR2, SC2 = commitments.nm_commit(rng, s2)
+
+ # Decommit signature shares and combine
+ print("[Alice] Decommit s2")
+ rc = commitments.nm_decommit(s2, SR2, SC2)
+ assert rc == 0, f'[Alice] Error decommitting s2. rc {rc}'
+
+ print("[Bob] Decommit s1")
+ rc = commitments.nm_decommit(s1, SR1, SC1)
+ assert rc == 0, f'[Bob] Error decommitting s1. rc {rc}'
+
+ print("[Alice] Recombine S component")
+ S1 = mpc.mpc_sum_s(s1, s2)
+
+ print("[Bob] Recombine S component")
+ S2 = mpc.mpc_sum_s(s1, s2)
+
+ rc = mpc.mpc_ecdsa_verify(hm, ecdsa_full_pk1, R1, S1)
+ assert rc == 0, f'[Alice] Invalid reconstructed signature'
+
+ rc = mpc.mpc_ecdsa_verify(hm, ecdsa_full_pk2, R2, S2)
+ assert rc == 0, f'[Bob] Invalid reconstructed signature'
+
+ assert R1 == R2, f'R component is different:\n{R1}\n{R2}'
+ assert S1 == S2, f'S component is different:\n{S1}\n{S2}'
+
+ print('\nReconstructed signature')
+ print(f'\tR = {R1.hex()}')
+ print(f'\tS = {S1.hex()}')