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/18 14:37:30 UTC

[incubator-milagro-MPC] branch issue7-schnorr-python-wrapper created (now 942c67b)

This is an automated email from the ASF dual-hosted git repository.

sandreoli pushed a change to branch issue7-schnorr-python-wrapper
in repository https://gitbox.apache.org/repos/asf/incubator-milagro-MPC.git.


      at 942c67b  remove copied .so files to python dir

This branch includes the following new commits:

     new 743bbb4  Add wrapper for Schnorr Proof
     new 30602c6  First cleanup and move src into module
     new 25e1117  Refactor tests
     new 92df5e8  Refactor examples
     new 33ea100  Refactor benchmarks
     new 942c67b  remove copied .so files to python dir

The 6 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[incubator-milagro-MPC] 04/06: Refactor examples

Posted by sa...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sandreoli pushed a commit to branch issue7-schnorr-python-wrapper
in repository https://gitbox.apache.org/repos/asf/incubator-milagro-MPC.git

commit 92df5e8fbc662e78873b3123066e604f738a3821
Author: Samuele Andreoli <sa...@yahoo.it>
AuthorDate: Tue Feb 18 14:03:42 2020 +0000

    Refactor examples
---
 python/CMakeLists.txt                      |  1 +
 python/{ => examples}/CMakeLists.txt       |  8 +---
 python/examples/context.py                 | 25 ++++++++++
 python/{ => examples}/example_dump_keys.py |  2 +-
 python/{ => examples}/example_ecdsa.py     |  2 +-
 python/{ => examples}/example_mta.py       |  2 +-
 python/{ => examples}/example_r.py         |  2 +-
 python/{ => examples}/example_s.py         |  2 +-
 python/examples/example_schnorr.py         | 74 ++++++++++++++++++++++++++++++
 9 files changed, 107 insertions(+), 11 deletions(-)

diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt
index 55b719c..d7ed21c 100644
--- a/python/CMakeLists.txt
+++ b/python/CMakeLists.txt
@@ -19,3 +19,4 @@ include(PythonSiteDirs)
 
 add_subdirectory(amcl)
 add_subdirectory(test)
+add_subdirectory(examples)
diff --git a/python/CMakeLists.txt b/python/examples/CMakeLists.txt
similarity index 86%
copy from python/CMakeLists.txt
copy to python/examples/CMakeLists.txt
index 55b719c..1d768ba 100644
--- a/python/CMakeLists.txt
+++ b/python/examples/CMakeLists.txt
@@ -13,9 +13,5 @@
 # License for the specific language governing permissions and limitations under
 # the License.
 
-cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
-
-include(PythonSiteDirs)
-
-add_subdirectory(amcl)
-add_subdirectory(test)
+file(GLOB EXAMPLES *.py)
+file(COPY ${EXAMPLES} DESTINATION "${PROJECT_BINARY_DIR}/python/examples")
diff --git a/python/examples/context.py b/python/examples/context.py
new file mode 100644
index 0000000..c7a9ac2
--- /dev/null
+++ b/python/examples/context.py
@@ -0,0 +1,25 @@
+"""
+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 mpc, schnorr
diff --git a/python/example_dump_keys.py b/python/examples/example_dump_keys.py
similarity index 99%
rename from python/example_dump_keys.py
rename to python/examples/example_dump_keys.py
index 8fe5665..5e6ac46 100755
--- a/python/example_dump_keys.py
+++ b/python/examples/example_dump_keys.py
@@ -19,7 +19,7 @@ specific language governing permissions and limitations
 under the License.
 """
 
-from amcl import mpc
+from context import mpc
 
 P_hex = "94f689d07ba20cf7c7ca7ccbed22ae6b40c426db74eaee4ce0ced2b6f52a5e136663f5f1ef379cdbb0c4fdd6e4074d6cff21082d4803d43d89e42fd8dfa82b135aa31a8844ffea25f255f956cbc1b9d8631d01baf1010d028a190b94ce40f3b72897e8196df19edf1ff62e6556f2701d52cef1442e3301db7608ecbdcca703db"
 Q_hex = "9a9ad73f246df853e129c589925fdad9df05606a61081e62e72be4fb33f6e5ec492cc734f28bfb71fbe2ba9a11e4c02e2c0d103a5cbb0a9d6402c07de63b1b995dd72ac8f29825d66923a088b421fb4d52b0b855d2f5dde2be9b0ca0cee6f7a94e5566735fe6cff1fcad3199602f88528d19aa8d0263adff8f5053c38254a2a3"
diff --git a/python/example_ecdsa.py b/python/examples/example_ecdsa.py
similarity index 99%
rename from python/example_ecdsa.py
rename to python/examples/example_ecdsa.py
index 39c5607..8b0c9ea 100755
--- a/python/example_ecdsa.py
+++ b/python/examples/example_ecdsa.py
@@ -19,7 +19,7 @@ specific language governing permissions and limitations
 under the License.
 """
 
-from amcl import mpc
+from context import mpc
 
 seed_hex = "78d0fb6705ce77dee47d03eb5b9c5d30"
 
diff --git a/python/example_mta.py b/python/examples/example_mta.py
similarity index 99%
rename from python/example_mta.py
rename to python/examples/example_mta.py
index 1491120..e22b920 100755
--- a/python/example_mta.py
+++ b/python/examples/example_mta.py
@@ -19,7 +19,7 @@ specific language governing permissions and limitations
 under the License.
 """
 
-from amcl import mpc
+from context import mpc
 
 seed_hex = "78d0fb6705ce77dee47d03eb5b9c5d30"
 
diff --git a/python/example_r.py b/python/examples/example_r.py
similarity index 99%
rename from python/example_r.py
rename to python/examples/example_r.py
index 7f55ce0..5fca2a1 100755
--- a/python/example_r.py
+++ b/python/examples/example_r.py
@@ -19,7 +19,7 @@ specific language governing permissions and limitations
 under the License.
 """
 
-from amcl import mpc
+from context import mpc
 
 seed_hex = "78d0fb6705ce77dee47d03eb5b9c5d30"
 
diff --git a/python/example_s.py b/python/examples/example_s.py
similarity index 99%
rename from python/example_s.py
rename to python/examples/example_s.py
index 011a437..122a433 100755
--- a/python/example_s.py
+++ b/python/examples/example_s.py
@@ -19,7 +19,7 @@ specific language governing permissions and limitations
 under the License.
 """
 
-from amcl import mpc
+from context import mpc
 
 seed_hex = "78d0fb6705ce77dee47d03eb5b9c5d30"
 
diff --git a/python/examples/example_schnorr.py b/python/examples/example_schnorr.py
new file mode 100755
index 0000000..d906d5f
--- /dev/null
+++ b/python/examples/example_schnorr.py
@@ -0,0 +1,74 @@
+#!/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.
+"""
+
+from context import schnorr
+
+seed_hex = "78d0fb6705ce77dee47d03eb5b9c5d30"
+
+x_hex = "fab4ce512dff74bd9c71c89a14de5b877af45dca0329ee3fcb72611c0784fef3"
+V_hex = "032cf4b348c9d00718f01ed98923e164df53b5e8bc4c2250662ed2df784e1784f4"
+
+if __name__ == "__main__":
+    seed = bytes.fromhex(seed_hex)
+
+    x = bytes.fromhex(x_hex)
+    V = bytes.fromhex(V_hex)
+
+    # random number generator
+    rng = schnorr.create_csprng(seed)
+
+    print("Example Schnorr Protocol")
+    print("DLOG: V = x.G")
+    print(f"\tx = {x_hex}")
+    print(f"\tV = {V_hex}")
+
+    # Generate commitment C = r.G, r random in [0, ..., q]
+    r, C = schnorr.commit(rng)
+
+    print("\n[Prover] Commitment C = r.G")
+    print(f"\tr = {r.hex()}")
+    print(f"\tC = {C.hex()}")
+
+    # Generate deterministic challenge e = H(G, V, C)
+    e = schnorr.challenge(V, C)
+
+    print("\n[Prover] Deterministic Challenge e = H(G, V, C)")
+    print(f"\te = {e.hex()}")
+
+    # Generate proof p = r - ex mod q
+    p = schnorr.prove(r, e, x)
+
+    print("\n[Prover] Generate proof p = r - ex")
+    print(f"\tp = {p.hex()}")
+
+    # Verifier regenerates deterministic challenge
+    e = schnorr.challenge(V, C)
+    print("\n[Verifier] Deterministic Challenge e = H(G, V, C)")
+    print(f"\te = {e.hex()}")
+
+    # Verify
+    rc = schnorr.verify(V, C, e, p)
+
+    print("\n[Verifier] Verify proof p")
+    if rc == schnorr.OK:
+        print("\tSuccess")
+    else:
+        print("\tFailure")


[incubator-milagro-MPC] 01/06: Add wrapper for Schnorr Proof

Posted by sa...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sandreoli pushed a commit to branch issue7-schnorr-python-wrapper
in repository https://gitbox.apache.org/repos/asf/incubator-milagro-MPC.git

commit 743bbb45238686810eef6dc8e4743a733524cd0d
Author: Samuele Andreoli <sa...@yahoo.it>
AuthorDate: Mon Feb 17 16:17:43 2020 +0000

    Add wrapper for Schnorr Proof
---
 python/CMakeLists.txt  |  31 +++--
 python/amcl_mpc.py     |   0
 python/amcl_schnorr.py | 352 +++++++++++++++++++++++++++++++++++++++++++++++++
 python/test_schnorr.py | 144 ++++++++++++++++++++
 4 files changed, 515 insertions(+), 12 deletions(-)

diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt
index c2cdbd6..4da1c7f 100644
--- a/python/CMakeLists.txt
+++ b/python/CMakeLists.txt
@@ -17,23 +17,30 @@ cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
 
 include(PythonSiteDirs)
 
-install(FILES amcl_mpc.py DESTINATION ${PYTHON_SITE_PACKAGES})
+install(FILES amcl_mpc.py     DESTINATION ${PYTHON_SITE_PACKAGES})
+install(FILES amcl_schnorr.py DESTINATION ${PYTHON_SITE_PACKAGES})
 
-file(COPY amcl_mpc.py DESTINATION "${PROJECT_BINARY_DIR}/python/")
-file(COPY test_mta.py DESTINATION "${PROJECT_BINARY_DIR}/python/")
-file(COPY test_r.py DESTINATION "${PROJECT_BINARY_DIR}/python/")
-file(COPY test_s.py DESTINATION "${PROJECT_BINARY_DIR}/python/")
-file(COPY test_ecdsa.py DESTINATION "${PROJECT_BINARY_DIR}/python/")
+file(COPY amcl_mpc.py     DESTINATION "${PROJECT_BINARY_DIR}/python/")
+file(COPY amcl_schnorr.py DESTINATION "${PROJECT_BINARY_DIR}/python/")
+file(COPY test_mta.py     DESTINATION "${PROJECT_BINARY_DIR}/python/")
+file(COPY test_r.py       DESTINATION "${PROJECT_BINARY_DIR}/python/")
+file(COPY test_s.py       DESTINATION "${PROJECT_BINARY_DIR}/python/")
+file(COPY test_ecdsa.py   DESTINATION "${PROJECT_BINARY_DIR}/python/")
+file(COPY test_schnorr.py DESTINATION "${PROJECT_BINARY_DIR}/python/")
 
 file(COPY "${PROJECT_SOURCE_DIR}/testVectors/mpc/MTA.json" DESTINATION "${PROJECT_BINARY_DIR}/python/")
-file(COPY "${PROJECT_SOURCE_DIR}/testVectors/mpc/R.json" DESTINATION "${PROJECT_BINARY_DIR}/python/")
-file(COPY "${PROJECT_SOURCE_DIR}/testVectors/mpc/S.json" DESTINATION "${PROJECT_BINARY_DIR}/python/")
+file(COPY "${PROJECT_SOURCE_DIR}/testVectors/mpc/R.json"   DESTINATION "${PROJECT_BINARY_DIR}/python/")
+file(COPY "${PROJECT_SOURCE_DIR}/testVectors/mpc/S.json"   DESTINATION "${PROJECT_BINARY_DIR}/python/")
+
+file(GLOB SCHNORR_TV "${PROJECT_SOURCE_DIR}/testVectors/schnorr/*.json")
+file(COPY ${SCHNORR_TV} DESTINATION "${PROJECT_BINARY_DIR}/python/schnorr/")
 
 if(NOT CMAKE_BUILD_TYPE STREQUAL "ASan")
-  add_test(test_python_mpc_mta python3 test_mta.py)
-  add_test(test_python_mpc_r python3 test_r.py)
-  add_test(test_python_mpc_s python3 test_s.py)
-  add_test(test_python_mpc_ecdsa python3 test_ecdsa.py)
+  add_test(test_python_mpc_mta     python3 test_mta.py)
+  add_test(test_python_mpc_r       python3 test_r.py)
+  add_test(test_python_mpc_s       python3 test_s.py)
+  add_test(test_python_mpc_ecdsa   python3 test_ecdsa.py)
+  add_test(test_python_mpc_schnorr python3 test_schnorr.py)
 endif(NOT CMAKE_BUILD_TYPE STREQUAL "ASan")
 
 # Set the LD_LIBRARY_PATH or equivalent to the libraries can be loaded when
diff --git a/python/amcl_mpc.py b/python/amcl_mpc.py
old mode 100755
new mode 100644
diff --git a/python/amcl_schnorr.py b/python/amcl_schnorr.py
new file mode 100644
index 0000000..07c671d
--- /dev/null
+++ b/python/amcl_schnorr.py
@@ -0,0 +1,352 @@
+#!/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.
+"""
+
+"""
+
+This module use cffi to access the c functions in the amcl_mpc library.
+
+"""
+import cffi
+import platform
+import os
+
+import gc
+
+ffi = cffi.FFI()
+ffi.cdef("""
+typedef long unsigned int BIG_512_60[9];
+typedef long unsigned int BIG_1024_58[18];
+
+typedef struct {
+unsigned int ira[21];  /* random number...   */
+int rndptr;   /* ...array & pointer */
+unsigned int borrow;
+int pool_ptr;
+char pool[32];    /* random pool */
+} csprng;
+
+typedef struct
+{
+  int len;
+  int max;
+  char *val;
+} octet;
+
+extern void RAND_seed(csprng *R,int n,char *b);
+extern void RAND_clean(csprng *R);
+extern void OCT_clear(octet *O);
+
+extern void SCHNORR_random_challenge(csprng *RNG, octet *E);
+
+extern void SCHNORR_commit(csprng *RNG, octet *R, octet *C);
+extern void SCHNORR_challenge(octet *V, octet *C, octet *E);
+extern void SCHNORR_prove(octet *R, octet *E, octet *X, octet *P);
+extern int  SCHNORR_verify(octet *V, octet *C, octet *E, octet *P);
+""")
+
+if (platform.system() == 'Windows'):
+    libamcl_mpc = ffi.dlopen("libamcl_mpc.dll")
+    libamcl_curve_secp256k1 = ffi.dlopen("libamcl_curve_SECP256K1.dll")
+    libamcl_core = ffi.dlopen("libamcl_core.dll")
+elif (platform.system() == 'Darwin'):
+    libamcl_mpc = ffi.dlopen("libamcl_mpc.dylib")
+    libamcl_curve_secp256k1 = ffi.dlopen("libamcl_curve_SECP256K1.dylib")
+    libamcl_core = ffi.dlopen("libamcl_core.dylib")
+else:
+    libamcl_mpc = ffi.dlopen("libamcl_mpc.so")
+    libamcl_curve_secp256k1 = ffi.dlopen("libamcl_curve_SECP256K1.so")
+    libamcl_core = ffi.dlopen("libamcl_core.so")
+
+# Constants
+EGS = 32
+EFS = 32
+PTS = EFS + 1
+
+OK          = 0
+FAIL        = 51
+INVALID_ECP = 52
+
+def to_str(octet_value):
+    """Converts an octet type into a string
+
+    Add all the values in an octet into an array.
+
+    Args::
+
+        octet_value. An octet pointer type
+
+    Returns::
+
+        String
+
+    Raises:
+        Exception
+    """
+    i = 0
+    val = []
+    while i < octet_value.len:
+        val.append(octet_value.val[i])
+        i = i + 1
+    out = b''
+    for x in val:
+        out = out + x
+    return out
+
+
+def make_octet(length, value=None):
+    """Generates an octet pointer
+
+    Generates an empty octet or one filled with the input value
+
+    Args::
+
+        length: Length of empty octet
+        value:  Data to assign to octet
+
+    Returns::
+
+        oct_ptr: octet pointer
+        val: data associated with octet to prevent garbage collection
+
+    Raises:
+
+    """
+    oct_ptr = ffi.new("octet*")
+    if value:
+        val = ffi.new("char [%s]" % len(value), value)
+        oct_ptr.val = val
+        oct_ptr.max = len(value)
+        oct_ptr.len = len(value)
+    else:
+        val = ffi.new("char []", length)
+        oct_ptr.val = val
+        oct_ptr.max = length
+        oct_ptr.len = 0
+    return oct_ptr, val
+
+
+def create_csprng(seed):
+    """Make a Cryptographically secure pseudo-random number generator instance
+
+    Make a Cryptographically secure pseudo-random number generator instance
+
+    Args::
+
+        seed:   random seed value
+
+    Returns::
+
+        rng: Pointer to cryptographically secure pseudo-random number generator instance
+
+    Raises:
+
+    """
+    seed_val = ffi.new("char [%s]" % len(seed), seed)
+    seed_len = len(seed)
+
+    # random number generator
+    rng = ffi.new('csprng*')
+    libamcl_core.RAND_seed(rng, seed_len, seed_val)
+
+    return rng
+
+
+def kill_csprng(rng):
+    """Kill a random number generator
+
+    Deletes all internal state
+
+    Args::
+
+        rng: Pointer to cryptographically secure pseudo-random number generator instance
+
+    Returns::
+
+    Raises:
+
+    """
+    libamcl_core.RAND_clean(rng)
+
+    return 0
+
+
+def random_challenge(rng):
+    """Generate a random challenge for the Schnorr's Proof
+
+    Generates a random value e in [0, .., q] suitable as a
+    random challenge for Schnorr's Proofs
+
+    Args::
+
+        rng: Pointer to cryptographically secure pseudo-random
+             number generator instance
+
+    Returns::
+
+        e: Random challenge
+
+    Raises:
+
+    """
+
+    e, e_val = make_octet(EGS)
+    _ = e_val # Suppress warning
+
+    libamcl_mpc.SCHNORR_random_challenge(rng, e)
+
+    return to_str(e)
+
+
+def commit(rng, r=None):
+    """Generate a commitment for the Schnorr's proof
+
+    Generates a random value r in [0, .., q] and masks it
+    with a DLOG
+
+    Args::
+
+        rng : Pointer to cryptographically secure pseudo-random
+              number generator instance
+        r   : Deterministic value for r
+
+    Returns::
+
+        r : Generated random value
+        C : Public ECP of the DLOG. r.G
+
+    Raises:
+
+    """
+    if r is None:
+        r_oct, r_val = make_octet(EGS)
+    else:
+        r_oct, r_val = make_octet(None, r)
+        rng = ffi.NULL
+
+    C, C_val = make_octet(PTS)
+    _ = r_val, C_val # Suppress warning
+
+
+    libamcl_mpc.SCHNORR_commit(rng, r_oct, C)
+
+    r = to_str(r_oct)
+
+    # Clean memory
+    libamcl_core.OCT_clear(r_oct)
+
+    return r, to_str(C)
+
+
+def challenge(V, C):
+    """Generate a deterministic challenge for the Schnorr's Proof
+
+    Generates a deterministic value r in [0, .., q] suitable as a
+    random challenge for Schnorr's Proofs. It is generated as
+    described in RFC8235#section-3.3
+
+    Args::
+
+        V : Public ECP of the DLOG. V = x.G
+        C : Commitment for the Schnorr's Proof
+
+    Returns::
+
+        e : Deterministic challenge
+
+    Raises:
+
+    """
+    V_oct, V_val = make_octet(None, V)
+    C_oct, C_val = make_octet(None, C)
+    _ = V_val, C_val # Suppress warning
+
+    e, e_val = make_octet(EGS)
+    _ = e_val # Suppress warning
+
+    libamcl_mpc.SCHNORR_challenge(V_oct, C_oct, e)
+
+    return to_str(e)
+
+
+def prove(r, e, x):
+    """Generate proof
+
+    Generates the proof for the Schnorr protocol.
+    P = r - e * x mod q
+
+    Args::
+
+        r : Secret value used in the commitment
+        e : Challenge for the Schnorr's protocol
+        x : Secret exponent of the DLOG V = x.G
+
+    Returns::
+
+        p : Proof for the Schnorr's protocol
+
+    Raises:
+
+    """
+    r_oct, r_val = make_octet(None, r)
+    e_oct, e_val = make_octet(None, e)
+    x_oct, x_val = make_octet(None, x)
+    _ = r_val, e_val, x_val # Suppress warning
+
+    p, p_val = make_octet(EGS)
+    _ = p_val # Suppress warning
+
+    libamcl_mpc.SCHNORR_prove(r_oct, e_oct, x_oct, p)
+
+    # Clean memory
+    libamcl_core.OCT_clear(r_oct)
+    libamcl_core.OCT_clear(x_oct)
+
+    return to_str(p)
+
+
+def verify(V, C, e, p):
+    """Verify a Schnorr's proof
+
+    Check that C = p.G + e.V
+
+    Args::
+
+        V : Public ECP of the DLOG. V = x.G
+        C : Commitment for the Schnorr's Proof
+        e : Challenge for the Schnorr's Proof
+        p : Proof
+
+    Returns::
+
+        ec : OK if the verification is successful, or an error code
+
+    Raises:
+
+    """
+    V_oct, V_val = make_octet(None, V)
+    C_oct, C_val = make_octet(None, C)
+    e_oct, e_val = make_octet(None, e)
+    p_oct, p_val = make_octet(None, p)
+    _ = V_val, C_val, e_val, p_val # Suppress warning
+
+    ec = libamcl_mpc.SCHNORR_verify(V_oct, C_oct, e_oct, p_oct)
+
+    return ec
diff --git a/python/test_schnorr.py b/python/test_schnorr.py
new file mode 100755
index 0000000..1392acb
--- /dev/null
+++ b/python/test_schnorr.py
@@ -0,0 +1,144 @@
+#!/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 unittest
+import json
+import amcl_schnorr
+
+
+class TestCommit(unittest.TestCase):
+    """ Test Schnorr's Proof Commitment """
+
+    def setUp(self):
+        # Deterministic PRNG for testing purposes
+        seed_hex = "78d0fb6705ce77dee47d03eb5b9c5d30"
+        seed = bytes.fromhex(seed_hex)
+        self.rng = amcl_schnorr.create_csprng(seed)
+
+        r_hex = "e8a04212cc20520429d854a5bb02b51b4281e663c90a4a4ec0b505171f9bc26a"
+        C_hex = "028fe6cafe6e6cef6c47be31cb449faa9495d22a6cb47e057b91c97d807882c439"
+        self.r_golden = bytes.fromhex(r_hex)
+        self.C_golden = bytes.fromhex(C_hex)
+
+        with open("schnorr/commit.json", "r") as f:
+            self.tv = json.load(f)
+
+    def test_tv(self):
+        """ Test using test vectors """
+
+        for vector in self.tv:
+            r_golden = bytes.fromhex(vector["R"])
+            C_golden = bytes.fromhex(vector["C"])
+
+            r, C = amcl_schnorr.commit(None, r_golden)
+
+            self.assertEqual(r, r_golden)
+            self.assertEqual(C, C_golden)
+
+    def test_random(self):
+        """ Test using pseudo random r """
+
+        r, C = amcl_schnorr.commit(self.rng)
+
+        self.assertEqual(r, self.r_golden)
+        self.assertEqual(C, self.C_golden)
+
+
+class TestChallenge(unittest.TestCase):
+    """ Test Schnorr's Proof Deterministic Challenge """
+
+    def setUp(self):
+        with open("schnorr/challenge.json", "r") as f:
+            self.tv = json.load(f)
+
+    def test_tv(self):
+        """ Test using test vectors """
+
+        for vector in self.tv:
+            V = bytes.fromhex(vector["V"])
+            C = bytes.fromhex(vector["C"])
+
+            e_golden = bytes.fromhex(vector["E"])
+
+            e = amcl_schnorr.challenge(V, C)
+
+            self.assertEqual(e, e_golden)
+
+
+class TestProve(unittest.TestCase):
+    """ Test Schnorr's Proof Proof generation """
+
+    def setUp(self):
+        with open("schnorr/prove.json", "r") as f:
+            self.tv = json.load(f)
+
+    def test_tv(self):
+        """ Test using test vectors """
+
+        for vector in self.tv:
+            r = bytes.fromhex(vector["R"])
+            e = bytes.fromhex(vector["E"])
+            x = bytes.fromhex(vector["X"])
+
+            p_golden = bytes.fromhex(vector["P"])
+
+            p = amcl_schnorr.prove(r, e, x)
+
+            self.assertEqual(p, p_golden)
+
+
+class TestVerify(unittest.TestCase):
+    """ Test Schnorr's Proof Verification """
+
+    def setUp(self):
+        with open("schnorr/verify.json", "r") as f:
+            self.tv = json.load(f)
+
+    def test_tv(self):
+        """ Test using test vectors """
+
+        for vector in self.tv:
+            V = bytes.fromhex(vector["V"])
+            C = bytes.fromhex(vector["C"])
+            e = bytes.fromhex(vector["E"])
+            p = bytes.fromhex(vector["P"])
+
+            ec = amcl_schnorr.verify(V, C, e, p)
+
+            self.assertEqual(ec, amcl_schnorr.OK)
+
+    def test_error_code(self):
+        """ Test error codes are propagated """
+
+        vector = self.tv[0]
+
+        V = bytes.fromhex(vector["C"])
+        C = bytes.fromhex(vector["V"])
+        e = bytes.fromhex(vector["E"])
+        p = bytes.fromhex(vector["P"])
+
+        ec = amcl_schnorr.verify(V, C, e, p)
+
+        self.assertEqual(ec, amcl_schnorr.FAIL)
+
+
+if __name__ == '__main__':
+    unittest.main()


[incubator-milagro-MPC] 06/06: remove copied .so files to python dir

Posted by sa...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sandreoli pushed a commit to branch issue7-schnorr-python-wrapper
in repository https://gitbox.apache.org/repos/asf/incubator-milagro-MPC.git

commit 942c67ba85de39382302a33156abe33aa6bb83ce
Author: Samuele Andreoli <sa...@yahoo.it>
AuthorDate: Tue Feb 18 14:37:02 2020 +0000

    remove copied .so files to python dir
---
 src/CMakeLists.txt | 8 --------
 1 file changed, 8 deletions(-)

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index c6f46e3..1311df2 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -39,11 +39,3 @@ install(TARGETS ${target} DESTINATION lib PERMISSIONS
   OWNER_WRITE OWNER_READ OWNER_EXECUTE
   GROUP_READ GROUP_EXECUTE
   WORLD_READ WORLD_EXECUTE)
-
-if(BUILD_PYTHON)
-  message(STATUS "Copy ${target} library to python directory for testing")
-  add_custom_command(TARGET ${target} POST_BUILD
-    COMMAND ${CMAKE_COMMAND} -E copy
-    "${CMAKE_CURRENT_BINARY_DIR}/lib*"
-    "${PROJECT_BINARY_DIR}/python/")
-endif(BUILD_PYTHON)


[incubator-milagro-MPC] 02/06: First cleanup and move src into module

Posted by sa...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sandreoli pushed a commit to branch issue7-schnorr-python-wrapper
in repository https://gitbox.apache.org/repos/asf/incubator-milagro-MPC.git

commit 30602c6eb6c805fbdf7dbbd37ddd75a39f602b6b
Author: Samuele Andreoli <sa...@yahoo.it>
AuthorDate: Mon Feb 17 17:14:13 2020 +0000

    First cleanup and move src into module
---
 python/CMakeLists.txt                       |   5 +-
 python/amcl/CMakeLists.txt                  |  19 ++++
 python/amcl/__init__.py                     |   0
 python/{amcl_mpc.py => amcl/mpc.py}         | 134 ++++++++++++++--------------
 python/{amcl_schnorr.py => amcl/schnorr.py} |   0
 python/bench_mpc.py                         |  39 ++++----
 python/example_dump_keys.py                 |  67 +++++---------
 python/example_ecdsa.py                     |  94 +++++++++----------
 python/example_mta.py                       |  78 +++++++---------
 python/example_r.py                         | 105 ++++++++--------------
 python/example_s.py                         | 112 ++++++++---------------
 python/test_ecdsa.py                        | 108 +++++++++-------------
 python/test_mta.py                          |  43 ++++-----
 python/test_r.py                            |  75 ++++++++--------
 python/test_s.py                            |  85 +++++++++---------
 python/test_schnorr.py                      |  20 ++---
 16 files changed, 435 insertions(+), 549 deletions(-)

diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt
index 4da1c7f..c53f313 100644
--- a/python/CMakeLists.txt
+++ b/python/CMakeLists.txt
@@ -17,11 +17,8 @@ cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
 
 include(PythonSiteDirs)
 
-install(FILES amcl_mpc.py     DESTINATION ${PYTHON_SITE_PACKAGES})
-install(FILES amcl_schnorr.py DESTINATION ${PYTHON_SITE_PACKAGES})
+add_subdirectory(amcl)
 
-file(COPY amcl_mpc.py     DESTINATION "${PROJECT_BINARY_DIR}/python/")
-file(COPY amcl_schnorr.py DESTINATION "${PROJECT_BINARY_DIR}/python/")
 file(COPY test_mta.py     DESTINATION "${PROJECT_BINARY_DIR}/python/")
 file(COPY test_r.py       DESTINATION "${PROJECT_BINARY_DIR}/python/")
 file(COPY test_s.py       DESTINATION "${PROJECT_BINARY_DIR}/python/")
diff --git a/python/amcl/CMakeLists.txt b/python/amcl/CMakeLists.txt
new file mode 100644
index 0000000..b92ebd8
--- /dev/null
+++ b/python/amcl/CMakeLists.txt
@@ -0,0 +1,19 @@
+# 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.
+
+file(GLOB SRCS *.py)
+file(COPY ${SRCS} DESTINATION "${PROJECT_BINARY_DIR}/python/amcl")
+
+install(FILES ${SRCS} DESTINATION ${PYTHON_SITE_PACKAGES}/amcl) 
diff --git a/python/amcl/__init__.py b/python/amcl/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/python/amcl_mpc.py b/python/amcl/mpc.py
similarity index 89%
rename from python/amcl_mpc.py
rename to python/amcl/mpc.py
index 48ea776..58af8b1 100644
--- a/python/amcl_mpc.py
+++ b/python/amcl/mpc.py
@@ -112,17 +112,17 @@ extern void MPC_DUMP_PAILLIER_SK(PAILLIER_private_key *PRIV, octet *P, octet *Q)
 if (platform.system() == 'Windows'):
     libamcl_mpc = ffi.dlopen("libamcl_mpc.dll")
     libamcl_paillier = ffi.dlopen("libamcl_paillier.dll")
-    libamcl_curve_secp256k1 = ffi.dlopen("libamcl_curve_SECP256K1.dll")    
+    libamcl_curve_secp256k1 = ffi.dlopen("libamcl_curve_SECP256K1.dll")
     libamcl_core = ffi.dlopen("libamcl_core.dll")
 elif (platform.system() == 'Darwin'):
     libamcl_mpc = ffi.dlopen("libamcl_mpc.dylib")
-    libamcl_paillier = ffi.dlopen("libamcl_paillier.dylib")    
+    libamcl_paillier = ffi.dlopen("libamcl_paillier.dylib")
     libamcl_curve_secp256k1 = ffi.dlopen("libamcl_curve_SECP256K1.dylib")
     libamcl_core = ffi.dlopen("libamcl_core.dylib")
 else:
     libamcl_mpc = ffi.dlopen("libamcl_mpc.so")
     libamcl_paillier = ffi.dlopen("libamcl_paillier.so")
-    libamcl_curve_secp256k1 = ffi.dlopen("libamcl_curve_SECP256K1.so")    
+    libamcl_curve_secp256k1 = ffi.dlopen("libamcl_curve_SECP256K1.so")
     libamcl_core = ffi.dlopen("libamcl_core.so")
 
 
@@ -259,15 +259,15 @@ def paillier_key_pair(rng, p=None, q=None):
     """
     if p:
         p1, p1_val = make_octet(None, p)
-        q1, q1_val = make_octet(None, q)        
+        q1, q1_val = make_octet(None, q)
         rng = ffi.NULL
     else:
-        p1 = ffi.NULL 
-        q1 = ffi.NULL               
+        p1 = ffi.NULL
+        q1 = ffi.NULL
 
     paillier_pk = ffi.new('PAILLIER_public_key*')
-    paillier_sk = ffi.new('PAILLIER_private_key*')    
-    
+    paillier_sk = ffi.new('PAILLIER_private_key*')
+
     libamcl_paillier.PAILLIER_KEY_PAIR(rng, p1, q1, paillier_pk, paillier_sk)
 
     return paillier_pk, paillier_sk
@@ -288,12 +288,12 @@ def paillier_private_key_kill(paillier_sk):
     Raises:
 
     """
-    libamcl_paillier.PAILLIER_PRIVATE_KEY_KILL(PAILLIER_private_key *PRIV);
+    libamcl_paillier.PAILLIER_PRIVATE_KEY_KILL(paillier_sk)
 
     return 0
 
 
-def paillier_pk_to_octet(paillier_pk):    
+def paillier_pk_to_octet(paillier_pk):
     """Write Paillier public key to byte array
 
     Write Paillier public key to byte array
@@ -310,14 +310,14 @@ def paillier_pk_to_octet(paillier_pk):
 
     """
     n1, n1_val = make_octet(FS_4096)
-    
+
     libamcl_paillier.PAILLIER_PK_toOctet(n1, paillier_pk)
 
     n2 = to_str(n1)
 
     return n2
 
-def paillier_pk_from_octet(n):    
+def paillier_pk_from_octet(n):
     """Read Paillier public key from byte array
 
     Read Paillier public key from byte array
@@ -364,18 +364,18 @@ def ecp_secp256k1_key_pair_generate(rng, ecdsa_sk=None):
         ecdsa_sk1, ecdsa_sk1_val = make_octet(None, ecdsa_sk)
         rng = ffi.NULL
     else:
-        ecdsa_sk1, ecdsa_sk1_val = make_octet(EGS_SECP256K1)        
+        ecdsa_sk1, ecdsa_sk1_val = make_octet(EGS_SECP256K1)
 
-    ecdsa_pk1, ecdsa_pk1_val = make_octet(2 * EFS_SECP256K1)                
+    ecdsa_pk1, ecdsa_pk1_val = make_octet(2 * EFS_SECP256K1 + 1)
 
     rc = libamcl_curve_secp256k1.ECP_SECP256K1_KEY_PAIR_GENERATE(rng, ecdsa_sk1, ecdsa_pk1)
 
     ecdsa_sk2 = to_str(ecdsa_sk1)
     ecdsa_pk2 = to_str(ecdsa_pk1)
-    
+
     return rc, ecdsa_pk2, ecdsa_sk2
 
-def ecp_secp256k1_public_key_validate(ecdsa_pk):    
+def ecp_secp256k1_public_key_validate(ecdsa_pk):
     """Validate an ECDSA public key
 
     Validate an ECDSA public key
@@ -394,7 +394,7 @@ def ecp_secp256k1_public_key_validate(ecdsa_pk):
     ecdsa_pk1, ecdsa_pk1_val = make_octet(None, ecdsa_pk)
 
     rc = libamcl_curve_secp256k1.ECP_SECP256K1_PUBLIC_KEY_VALIDATE(ecdsa_pk1)
-    
+
     return rc
 
 def mpc_mta_client1(rng, paillier_pk, a, r=None):
@@ -407,7 +407,7 @@ def mpc_mta_client1(rng, paillier_pk, a, r=None):
         rng: Pointer to cryptographically secure pseudo-random number generator instance
         paillier_pk: Pointer to Paillier public keys
         a: Multiplicative share of secret
-        r: R value for testing. 
+        r: R value for testing.
 
     Returns::
 
@@ -424,12 +424,12 @@ def mpc_mta_client1(rng, paillier_pk, a, r=None):
         r1 = ffi.NULL
 
     a1, a1_val = make_octet(None, a)
-    ca1, ca1_val = make_octet(FS_4096)        
-    
+    ca1, ca1_val = make_octet(FS_4096)
+
     libamcl_mpc.MPC_MTA_CLIENT1(rng, paillier_pk, a1, ca1, r1)
 
     ca2 = to_str(ca1)
-    
+
     return ca2
 
 def mpc_mta_client2(paillier_sk, cb):
@@ -450,12 +450,12 @@ def mpc_mta_client2(paillier_sk, cb):
 
     """
     cb1, cb1_val = make_octet(None, cb)
-    alpha1, alpha1_val = make_octet(EGS_SECP256K1)        
-    
+    alpha1, alpha1_val = make_octet(EGS_SECP256K1)
+
     libamcl_mpc.MPC_MTA_CLIENT2(paillier_sk, cb1, alpha1)
 
     alpha2 = to_str(alpha1)
-    
+
     return alpha2
 
 def mpc_mta_server(rng, paillier_pk, b, ca, z=None, r=None):
@@ -474,30 +474,30 @@ def mpc_mta_server(rng, paillier_pk, b, ca, z=None, r=None):
 
     Returns::
 
-        cb: Ciphertext 
-        beta: Additive share of secret 
+        cb: Ciphertext
+        beta: Additive share of secret
 
     Raises:
 
     """
     if r:
         r1, r1_val = make_octet(None, r)
-        z1, z1_val = make_octet(None, z)        
+        z1, z1_val = make_octet(None, z)
         rng = ffi.NULL
     else:
-        r1 = ffi.NULL        
-        z1 = ffi.NULL        
+        r1 = ffi.NULL
+        z1 = ffi.NULL
 
     b1, b1_val = make_octet(None, b)
-    ca1, ca1_val = make_octet(None, ca)            
-    beta1, beta1_val = make_octet(EGS_SECP256K1)        
-    cb1, cb1_val = make_octet(FS_4096)        
-    
+    ca1, ca1_val = make_octet(None, ca)
+    beta1, beta1_val = make_octet(EGS_SECP256K1)
+    cb1, cb1_val = make_octet(FS_4096)
+
     libamcl_mpc.MPC_MTA_SERVER(rng, paillier_pk, b1, ca1, z1, r1, cb1, beta1)
 
     beta2 = to_str(beta1)
-    cb2 = to_str(cb1)    
-    
+    cb2 = to_str(cb1)
+
     return cb2, beta2
 
 def mpc_sum_mta(a, b, alpha, beta):
@@ -523,13 +523,13 @@ def mpc_sum_mta(a, b, alpha, beta):
     b1, b1_val = make_octet(None, b)
     alpha1, alpha1_val = make_octet(None, alpha)
     beta1, beta1_val = make_octet(None, beta)
-    
+
     sum1, sum1_val = make_octet(EGS_SECP256K1)
-    
-    libamcl_mpc.MPC_SUM_MTA(a1, b1, alpha1, beta1, sum1);
+
+    libamcl_mpc.MPC_SUM_MTA(a1, b1, alpha1, beta1, sum1)
 
     sum2 = to_str(sum1)
-    
+
     return sum2
 
 def mpc_invkgamma(kgamma1, kgamma2):
@@ -550,14 +550,14 @@ def mpc_invkgamma(kgamma1, kgamma2):
 
     """
     kgamma11, kgamma11_val = make_octet(None, kgamma1)
-    kgamma21, kgamma21_val = make_octet(None, kgamma2)    
-    
+    kgamma21, kgamma21_val = make_octet(None, kgamma2)
+
     invkgamma1, invkgamma1_val = make_octet(EGS_SECP256K1)
-    
+
     libamcl_mpc.MPC_INVKGAMMA(kgamma11, kgamma21, invkgamma1)
 
     invkgamma2 = to_str(invkgamma1)
-    
+
     return invkgamma2
 
 def mpc_r(invkgamma, gammapt1, gammapt2):
@@ -581,16 +581,16 @@ def mpc_r(invkgamma, gammapt1, gammapt2):
     """
     invkgamma1, invkgamma1_val = make_octet(None, invkgamma)
     gammapt11, gammapt11_val = make_octet(None, gammapt1)
-    gammapt21, gammapt21_val = make_octet(None, gammapt2)    
-    
+    gammapt21, gammapt21_val = make_octet(None, gammapt2)
+
     r1, r1_val = make_octet(EGS_SECP256K1)
     rp, rp_val = make_octet(EFS_SECP256K1 + 1)
-    
+
     rc = libamcl_mpc.MPC_R(invkgamma1, gammapt11, gammapt21, r1, rp)
 
     r2 = to_str(r1)
     rp_str = to_str(rp)
-    
+
     return rc, r2, rp_str
 
 def mpc_hash(message):
@@ -604,18 +604,18 @@ def mpc_hash(message):
 
     Returns::
 
-        hm: hash of message 
+        hm: hash of message
 
     Raises:
 
     """
     message1, message1_val = make_octet(None, message)
     hm1, hm1_val = make_octet(SHA256)
-    
+
     libamcl_mpc.MPC_HASH(SHA256, message1, hm1)
 
     hm2 = to_str(hm1)
-    
+
     return hm2
 
 def mpc_s(hm, r, k, sigma):
@@ -641,14 +641,14 @@ def mpc_s(hm, r, k, sigma):
     hm1, hm1_val = make_octet(None, hm)
     r1, r1_val = make_octet(None, r)
     k1, k1_val = make_octet(None, k)
-    sigma1, sigma1_val = make_octet(None, sigma)    
+    sigma1, sigma1_val = make_octet(None, sigma)
 
     s1, s1_val = make_octet(EGS_SECP256K1)
-    
+
     rc = libamcl_mpc.MPC_S(hm1, r1, k1, sigma1, s1)
 
     s2 = to_str(s1)
-    
+
     return rc, s2
 
 def mpc_ecdsa_verify(hm, pk, r, s):
@@ -673,8 +673,8 @@ def mpc_ecdsa_verify(hm, pk, r, s):
     hm1, hm1_val = make_octet(None, hm)
     pk1, pk1_val = make_octet(None, pk)
     r1, r1_val = make_octet(None, r)
-    s1, s1_val = make_octet(None, s)        
-    
+    s1, s1_val = make_octet(None, s)
+
     rc = libamcl_mpc.MPC_ECDSA_VERIFY(hm1, pk1, r1, s1)
 
     return rc
@@ -697,14 +697,14 @@ def mpc_sum_s(s1, s2):
 
     """
     s11, s11_val = make_octet(None, s1)
-    s21, s21_val = make_octet(None, s2)    
-    
+    s21, s21_val = make_octet(None, s2)
+
     s1, s1_val = make_octet(EGS_SECP256K1)
-    
-    libamcl_mpc.MPC_SUM_S(s11, s21, s1);
+
+    libamcl_mpc.MPC_SUM_S(s11, s21, s1)
 
     s2 = to_str(s1)
-    
+
     return s2
 
 def mpc_sum_pk(pk1, pk2):
@@ -726,14 +726,14 @@ def mpc_sum_pk(pk1, pk2):
 
     """
     pk11, pk11_val = make_octet(None, pk1)
-    pk21, pk21_val = make_octet(None, pk2)    
-    
+    pk21, pk21_val = make_octet(None, pk2)
+
     pk1, pk1_val = make_octet(EFS_SECP256K1 + 1)
 
-    rc = libamcl_mpc.MPC_SUM_PK(pk11, pk21, pk1);
+    rc = libamcl_mpc.MPC_SUM_PK(pk11, pk21, pk1)
 
     pk2 = to_str(pk1)
-    
+
     return rc, pk2
 
 def mpc_dump_paillier_sk(paillier_sk):
@@ -747,14 +747,14 @@ def mpc_dump_paillier_sk(paillier_sk):
 
     Returns::
 
-        p:           Secret prime number 
-        q:           Secret prime number 
+        p:           Secret prime number
+        q:           Secret prime number
 
     Raises:
 
     """
     p, p_val = make_octet(HFS_2048)
-    q, q_val = make_octet(HFS_2048)    
+    q, q_val = make_octet(HFS_2048)
 
     libamcl_mpc.MPC_DUMP_PAILLIER_SK(paillier_sk, p, q)
 
diff --git a/python/amcl_schnorr.py b/python/amcl/schnorr.py
similarity index 100%
rename from python/amcl_schnorr.py
rename to python/amcl/schnorr.py
diff --git a/python/bench_mpc.py b/python/bench_mpc.py
index f6aa5b0..d246a1a 100755
--- a/python/bench_mpc.py
+++ b/python/bench_mpc.py
@@ -9,7 +9,7 @@ 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
+    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
@@ -21,12 +21,12 @@ under the License.
 
 import time
 import warnings
-import amcl_mpc
+from amcl import mpc
 
 warnings.filterwarnings("ignore")
 
 
-def time_func(fncall, n=10):
+def time_func(stmt, fncall, n=10):
     t = time.process_time()
     for i in range(1,i):
         fncall
@@ -50,28 +50,28 @@ b_hex = "0000000000000000000000000000000000000000000000000000000000000003"
 
 if __name__ == "__main__":
 
-    seed = bytes.fromhex(seed_hex)    
+    seed = bytes.fromhex(seed_hex)
     p = bytes.fromhex(P_hex)
     q = bytes.fromhex(Q_hex)
     a = bytes.fromhex(a_hex)
     b = bytes.fromhex(b_hex)
 
     ai = int(a_hex, 16)
-    bi = int(b_hex, 16)    
-    expected = ai * bi % amcl_mpc.curve_order
-    
+    bi = int(b_hex, 16)
+    expected = ai * bi % mpc.curve_order
+
     # random number generator
-    rng = amcl_mpc.create_csprng(seed)
-    
-    paillier_pk, paillier_sk = amcl_mpc.paillier_key_pair(rng)
+    rng = mpc.create_csprng(seed)
+
+    paillier_pk, paillier_sk = mpc.paillier_key_pair(rng)
 
     total_time=0
     for i in range(1,nIter):
         #t = time.process_time()
         t = time.time()
-        ca = amcl_mpc.mpc_mta_client1(rng, paillier_pk, a)
+        ca = mpc.mpc_mta_client1(rng, paillier_pk, a)
         # elapsed_time = time.process_time() - t
-        elapsed_time = time.time() - t        
+        elapsed_time = time.time() - t
         total_time = total_time + elapsed_time
     iter_time = int ((total_time * 1000) / nIter)
     print(f"mpc_mta_client1 iteractions: {nIter} total_time: {total_time} iter_time: {iter_time}")
@@ -79,7 +79,7 @@ if __name__ == "__main__":
     total_time=0
     for i in range(1,nIter):
         t = time.time()
-        cb, beta = amcl_mpc.mpc_mta_server(rng, paillier_pk, b, ca)
+        cb, beta = mpc.mpc_mta_server(rng, paillier_pk, b, ca)
         elapsed_time = time.time() - t
         total_time = total_time + elapsed_time
     iter_time = int ((total_time * 1000) / nIter)
@@ -88,18 +88,17 @@ if __name__ == "__main__":
     total_time=0
     for i in range(1,nIter):
         t = time.time()
-        alpha = amcl_mpc.mpc_mta_client2(paillier_sk, cb)
+        alpha = mpc.mpc_mta_client2(paillier_sk, cb)
         elapsed_time = time.time() - t
         total_time = total_time + elapsed_time
     iter_time = int ((total_time * 1000) / nIter)
     print(f"mpc_mta_client2 iteractions: {nIter} total_time: {total_time} iter_time: {iter_time}")
-    
+
     alphai = int(alpha.hex(), 16)
     betai = int(beta.hex(), 16)
-    got = ( alphai + betai ) % amcl_mpc.curve_order
+    got = ( alphai + betai ) % mpc.curve_order
 
-    assert got == expected, f"expected {expected.hex()} got {got.hex()}"
-    
-    # Clear memory
-    amcl_mpc.kill_csprng(rng)
+    assert got == expected, f"expected {hex(expected)} got {hex(got)}"
 
+    # Clear memory
+    mpc.kill_csprng(rng)
diff --git a/python/example_dump_keys.py b/python/example_dump_keys.py
index 71bff57..8fe5665 100755
--- a/python/example_dump_keys.py
+++ b/python/example_dump_keys.py
@@ -9,7 +9,7 @@ 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
+    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
@@ -19,88 +19,67 @@ specific language governing permissions and limitations
 under the License.
 """
 
-import amcl_mpc
-
-seed_hex = "78d0fb6705ce77dee47d03eb5b9c5d30"
+from amcl import mpc
 
 P_hex = "94f689d07ba20cf7c7ca7ccbed22ae6b40c426db74eaee4ce0ced2b6f52a5e136663f5f1ef379cdbb0c4fdd6e4074d6cff21082d4803d43d89e42fd8dfa82b135aa31a8844ffea25f255f956cbc1b9d8631d01baf1010d028a190b94ce40f3b72897e8196df19edf1ff62e6556f2701d52cef1442e3301db7608ecbdcca703db"
-
 Q_hex = "9a9ad73f246df853e129c589925fdad9df05606a61081e62e72be4fb33f6e5ec492cc734f28bfb71fbe2ba9a11e4c02e2c0d103a5cbb0a9d6402c07de63b1b995dd72ac8f29825d66923a088b421fb4d52b0b855d2f5dde2be9b0ca0cee6f7a94e5566735fe6cff1fcad3199602f88528d19aa8d0263adff8f5053c38254a2a3"
 
 a_hex = "0000000000000000000000000000000000000000000000000000000000000002"
-
 b_hex = "0000000000000000000000000000000000000000000000000000000000000003"
-
 ca_hex = "19c8b725dbd74b7dcaf72bd9ff2cd207b47cb1095393685906171af9e2f2959e7f68729e0e40f97a22bbca93373d618ad51dd077c0d102938598a8ecc8a656e978ebd14007da99db8e691d85fc18a428097ee8a63dcf95b84b660294474a20ed2edcf2b1b4f305c1cc25860a08d1348c2a4d24cc1a97b51f920e2985b8108b3392a5eafc443cf3449e288eb49dbde2228a56233afa5a6643e5ae6ec6aa8937a666ef74a30625c35bb22c3cc57b700f8eae7690f8d37edbfd27ccb2e882f70d0d85e0cc825347453a28e98e877ab1eeaa6efa09f034bc8976bffb86420106978066ff52221b315f71eb32cbf608d2b72cfa [...]
-
 R_hex = "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 [...]
 
 cb_hex = "1f1f087e749c85aacdacaace8659a33b53baad5eec1e56628435d335a8b150f96865d6e090f53146e120e7089b6f4a91c762622b24d0d2fba0e703301170a0b826a1336d4d6bb83dccd29ad9ef0936614bf14e992ea4daa202c63ace9bd3f95b9a8a6edd7949e89ec165541e7c01bd41395baf3e2fe7f3a9611af8b5ed8639c02a2bfc236c17a136bef6d09f966db718f3df9d6f4f40b618b4b6058b4e4ec241e6c2424404d0aee0ef5cd666e5c4253a62ae9deb09289fb84657109e0b933f58871ba7ea77190d6ea45a04be68360478adf43a85851cf583c5575543578635996d2dcd020aeceabf18be6ff8b45e4ecd63 [...]
+z_hex = "0000000000000000000000000000000000000000000000000000000000000004"
+beta_hex = "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd036413d"
 
-z_hex = "0000000000000000000000000000000000000000000000000000000000000004";
-
-beta_hex = "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd036413d";
-
-alpha_hex = "000000000000000000000000000000000000000000000000000000000000000a";
+alpha_hex = "000000000000000000000000000000000000000000000000000000000000000a"
 
 if __name__ == "__main__":
-
-    seed = bytes.fromhex(seed_hex)    
     p0 = bytes.fromhex(P_hex)
     q0 = bytes.fromhex(Q_hex)
     a = bytes.fromhex(a_hex)
     b = bytes.fromhex(b_hex)
-    z = bytes.fromhex(z_hex)        
+    z = bytes.fromhex(z_hex)
     r = bytes.fromhex(R_hex)
 
     ai = int(a_hex, 16)
-    bi = int(b_hex, 16)    
-    expected = ai * bi % amcl_mpc.curve_order
+    bi = int(b_hex, 16)
+    expected = ai * bi % mpc.curve_order
     print(f"expected {hex(expected)}")
-    
-    # random number generator
-    rng = amcl_mpc.create_csprng(seed)
 
     # Deterministic
-
-    paillier_pk1, paillier_sk1 = amcl_mpc.paillier_key_pair(rng, p0, q0)
+    paillier_pk1, paillier_sk1 = mpc.paillier_key_pair(None, p0, q0)
 
     # Dump and load Paillier public key
-    
-    n  = amcl_mpc.paillier_pk_to_octet(paillier_pk1)
+
+    n = mpc.paillier_pk_to_octet(paillier_pk1)
     print(f"paillier_pk1.n {n.hex()}")
 
-    paillier_pk2 = amcl_mpc.paillier_pk_from_octet(n)
+    paillier_pk2 = mpc.paillier_pk_from_octet(n)
 
     # Dump and load Paillier secret key
-    p, q  = amcl_mpc.mpc_dump_paillier_sk(paillier_sk1)
+    p, q  = mpc.mpc_dump_paillier_sk(paillier_sk1)
     print(f"paillier_sk1.p {p.hex()}")
     print(f"paillier_sk1.q {q.hex()}")
 
-    paillier_pk3, paillier_sk2 = amcl_mpc.paillier_key_pair(rng, p, q)    
-    
-    ca = amcl_mpc.mpc_mta_client1(rng, paillier_pk2, a, r)
+    paillier_pk3, paillier_sk2 = mpc.paillier_key_pair(None, p, q)
 
+    ca = mpc.mpc_mta_client1(None, paillier_pk2, a, r)
     ca1_hex = ca.hex()
-    assert ca_hex == ca1_hex, f"expected {ca_hex} got {ca1_hex}"    
-
-    cb, beta = amcl_mpc.mpc_mta_server(rng, paillier_pk2, b, ca, z, r)
+    assert ca_hex == ca1_hex, f"expected {ca_hex} got {ca1_hex}"
 
+    cb, beta = mpc.mpc_mta_server(None, paillier_pk2, b, ca, z, r)
     cb1_hex = cb.hex()
-    assert cb_hex == cb1_hex, f"expected {cb_hex} got {cb1_hex}"    
+    assert cb_hex == cb1_hex, f"expected {cb_hex} got {cb1_hex}"
 
-    alpha = amcl_mpc.mpc_mta_client2(paillier_sk2, cb)
+    alpha = mpc.mpc_mta_client2(paillier_sk2, cb)
 
     print(f"alpha {alpha.hex()}")
     print(f"beta {beta.hex()}")
-    
+
     alphai = int(alpha.hex(), 16)
     betai = int(beta.hex(), 16)
-    got = ( alphai + betai ) % amcl_mpc.curve_order
-    print(f"got {hex(got)}")    
-
-    assert got == expected, f"expected {expected.hex()} got {got.hex()}"
-    
-    # Clear memory
-    amcl_mpc.kill_csprng(rng)
-
+    got = ( alphai + betai ) % mpc.curve_order
+    print(f"got {hex(got)}")
+    assert got == expected, f"expected {hex(expected)} got {hex(got)}"
diff --git a/python/example_ecdsa.py b/python/example_ecdsa.py
index 6c99a72..39c5607 100755
--- a/python/example_ecdsa.py
+++ b/python/example_ecdsa.py
@@ -9,7 +9,7 @@ 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
+    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
@@ -19,124 +19,116 @@ specific language governing permissions and limitations
 under the License.
 """
 
-import amcl_mpc
+from amcl import mpc
 
 seed_hex = "78d0fb6705ce77dee47d03eb5b9c5d30"
 
 if __name__ == "__main__":
-
-    seed = bytes.fromhex(seed_hex)    
+    seed = bytes.fromhex(seed_hex)
 
     # random number generator
-    rng = amcl_mpc.create_csprng(seed)
+    rng = mpc.create_csprng(seed)
 
     # Paillier keys
-    paillier_pk1, paillier_sk1 = amcl_mpc.paillier_key_pair(rng)
-    paillier_pk2, paillier_sk2 = amcl_mpc.paillier_key_pair(rng)
+    paillier_pk1, paillier_sk1 = mpc.paillier_key_pair(rng)
+    paillier_pk2, paillier_sk2 = mpc.paillier_key_pair(rng)
 
     # ECDSA keys
-    rc, PK1, W1 = amcl_mpc.ecp_secp256k1_key_pair_generate(rng)
-    rc = amcl_mpc.ecp_secp256k1_public_key_validate(PK1)    
+    rc, PK1, W1 = mpc.ecp_secp256k1_key_pair_generate(rng)
+    rc = mpc.ecp_secp256k1_public_key_validate(PK1)
     assert rc == 0, f"Invalid ECDSA public key"
 
-    rc, PK2, W2 = amcl_mpc.ecp_secp256k1_key_pair_generate(rng)
-    rc = amcl_mpc.ecp_secp256k1_public_key_validate(PK2)    
+    rc, PK2, W2 = mpc.ecp_secp256k1_key_pair_generate(rng)
+    rc = mpc.ecp_secp256k1_public_key_validate(PK2)
     assert rc == 0, f"Invalid ECDSA public key"
 
     # Gamma values
-    rc, GAMMAPT1, GAMMA1 = amcl_mpc.ecp_secp256k1_key_pair_generate(rng)
-    rc, GAMMAPT2, GAMMA2 = amcl_mpc.ecp_secp256k1_key_pair_generate(rng)
+    rc, GAMMAPT1, GAMMA1 = mpc.ecp_secp256k1_key_pair_generate(rng)
+    rc, GAMMAPT2, GAMMA2 = mpc.ecp_secp256k1_key_pair_generate(rng)
 
     # K values
-    rc, TMP1, K1 = amcl_mpc.ecp_secp256k1_key_pair_generate(rng)
-    rc, TMP2, K2 = amcl_mpc.ecp_secp256k1_key_pair_generate(rng)
+    rc, TMP1, K1 = mpc.ecp_secp256k1_key_pair_generate(rng)
+    rc, TMP2, K2 = mpc.ecp_secp256k1_key_pair_generate(rng)
 
     # Message
     M = b'test message'
-    
-    # ALPHA1 + BETA2 = K1 * GAMMA2    
-
-    CA11 = amcl_mpc.mpc_mta_client1(rng, paillier_pk1, K1)
 
-    CB12, BETA2 = amcl_mpc.mpc_mta_server(rng, paillier_pk1, GAMMA2, CA11)
-
-    ALPHA1 = amcl_mpc.mpc_mta_client2(paillier_sk1, CB12)
+    # ALPHA1 + BETA2 = K1 * GAMMA2
+    CA11 = mpc.mpc_mta_client1(rng, paillier_pk1, K1)
+    CB12, BETA2 = mpc.mpc_mta_server(rng, paillier_pk1, GAMMA2, CA11)
+    ALPHA1 = mpc.mpc_mta_client2(paillier_sk1, CB12)
 
     # ALPHA2 + BETA1 = K2 * GAMMA1
-
-    CA22 = amcl_mpc.mpc_mta_client1(rng, paillier_pk2, K2)
-    
-    CB21, BETA1 = amcl_mpc.mpc_mta_server(rng, paillier_pk2, GAMMA1, CA22)
-
-    ALPHA2 = amcl_mpc.mpc_mta_client2(paillier_sk2, CB21)
+    CA22 = mpc.mpc_mta_client1(rng, paillier_pk2, K2)
+    CB21, BETA1 = mpc.mpc_mta_server(rng, paillier_pk2, GAMMA1, CA22)
+    ALPHA2 = mpc.mpc_mta_client2(paillier_sk2, CB21)
 
     # sum = K1.GAMMA1 + alpha1  + beta1
 
-    SUM1 = amcl_mpc.mpc_sum_mta(K1, GAMMA1,  ALPHA1,  BETA1)
+    SUM1 = mpc.mpc_sum_mta(K1, GAMMA1,  ALPHA1,  BETA1)
 
     # sum = K2.GAMMA2 + alpha2  + beta2
 
-    SUM2 = amcl_mpc.mpc_sum_mta(K2, GAMMA2, ALPHA2, BETA2)
+    SUM2 = mpc.mpc_sum_mta(K2, GAMMA2, ALPHA2, BETA2)
 
     # Calculate the inverse of kgamma
 
-    INVKGAMMA = amcl_mpc.mpc_invkgamma(SUM1, SUM2)
+    INVKGAMMA = mpc.mpc_invkgamma(SUM1, SUM2)
 
     # Calculate the R signature component
 
-    rc, SIG_R, _ = amcl_mpc.mpc_r(INVKGAMMA, GAMMAPT1, GAMMAPT2)
+    rc, SIG_R, _ = mpc.mpc_r(INVKGAMMA, GAMMAPT1, GAMMAPT2)
 
+    # ALPHA1 + BETA2 = K1 * W2
 
-    # ALPHA1 + BETA2 = K1 * W2    
+    CA11 = mpc.mpc_mta_client1(rng, paillier_pk1, K1)
 
-    CA11 = amcl_mpc.mpc_mta_client1(rng, paillier_pk1, K1)
+    CB12, BETA2 = mpc.mpc_mta_server(rng, paillier_pk1, W2, CA11)
 
-    CB12, BETA2 = amcl_mpc.mpc_mta_server(rng, paillier_pk1, W2, CA11)
+    ALPHA1 = mpc.mpc_mta_client2(paillier_sk1, CB12)
 
-    ALPHA1 = amcl_mpc.mpc_mta_client2(paillier_sk1, CB12)
-    
     # ALPHA2 + BETA1 = K2 * W1
 
-    CA22 = amcl_mpc.mpc_mta_client1(rng, paillier_pk2, K2)
-    
-    CB21, BETA1 = amcl_mpc.mpc_mta_server(rng, paillier_pk2, W1, CA22)
+    CA22 = mpc.mpc_mta_client1(rng, paillier_pk2, K2)
+
+    CB21, BETA1 = mpc.mpc_mta_server(rng, paillier_pk2, W1, CA22)
 
-    ALPHA2 = amcl_mpc.mpc_mta_client2(paillier_sk2, CB21)
+    ALPHA2 = mpc.mpc_mta_client2(paillier_sk2, CB21)
 
     # sum = K1.W1 + alpha1  + beta1
 
-    SUM1 = amcl_mpc.mpc_sum_mta(K1, W1,  ALPHA1,  BETA1)
+    SUM1 = mpc.mpc_sum_mta(K1, W1,  ALPHA1,  BETA1)
 
     # sum = K2.W2 + alpha2  + beta2
 
-    SUM2 = amcl_mpc.mpc_sum_mta(K2, W2, ALPHA2, BETA2)
+    SUM2 = mpc.mpc_sum_mta(K2, W2, ALPHA2, BETA2)
 
     # Calculate the message hash
-    
-    HM = amcl_mpc.mpc_hash(M)
+
+    HM = mpc.mpc_hash(M)
 
     # Calculate the S1 signature component
 
-    rc, SIG_S1 = amcl_mpc.mpc_s(HM, SIG_R, K1, SUM1)
+    rc, SIG_S1 = mpc.mpc_s(HM, SIG_R, K1, SUM1)
 
     # Calculate the S2 signature component
 
-    rc, SIG_S2 = amcl_mpc.mpc_s(HM, SIG_R, K2, SUM2)
+    rc, SIG_S2 = mpc.mpc_s(HM, SIG_R, K2, SUM2)
 
     # Sum S signature component
 
-    SIG_S = amcl_mpc.mpc_sum_s(SIG_S1, SIG_S2)
+    SIG_S = mpc.mpc_sum_s(SIG_S1, SIG_S2)
 
     print(f"r component {SIG_R.hex()}")
-    print(f"s component {SIG_S.hex()}")    
+    print(f"s component {SIG_S.hex()}")
 
     # Sum ECDSA public keys
 
-    rc, PK = amcl_mpc.mpc_sum_pk(PK1, PK2)
+    rc, PK = mpc.mpc_sum_pk(PK1, PK2)
 
     # Verify final signature
 
-    rc = amcl_mpc.mpc_ecdsa_verify(HM, PK, SIG_R, SIG_S)
+    rc = mpc.mpc_ecdsa_verify(HM, PK, SIG_R, SIG_S)
     assert rc == 0, f"Invalid ECDSA signature"
 
     print("SUCCESS")
diff --git a/python/example_mta.py b/python/example_mta.py
index 18f2d9a..1491120 100755
--- a/python/example_mta.py
+++ b/python/example_mta.py
@@ -9,7 +9,7 @@ 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
+    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
@@ -19,94 +19,82 @@ specific language governing permissions and limitations
 under the License.
 """
 
-import amcl_mpc
+from amcl import mpc
 
 seed_hex = "78d0fb6705ce77dee47d03eb5b9c5d30"
 
 P_hex = "94f689d07ba20cf7c7ca7ccbed22ae6b40c426db74eaee4ce0ced2b6f52a5e136663f5f1ef379cdbb0c4fdd6e4074d6cff21082d4803d43d89e42fd8dfa82b135aa31a8844ffea25f255f956cbc1b9d8631d01baf1010d028a190b94ce40f3b72897e8196df19edf1ff62e6556f2701d52cef1442e3301db7608ecbdcca703db"
-
 Q_hex = "9a9ad73f246df853e129c589925fdad9df05606a61081e62e72be4fb33f6e5ec492cc734f28bfb71fbe2ba9a11e4c02e2c0d103a5cbb0a9d6402c07de63b1b995dd72ac8f29825d66923a088b421fb4d52b0b855d2f5dde2be9b0ca0cee6f7a94e5566735fe6cff1fcad3199602f88528d19aa8d0263adff8f5053c38254a2a3"
 
 a_hex = "0000000000000000000000000000000000000000000000000000000000000002"
-
 b_hex = "0000000000000000000000000000000000000000000000000000000000000003"
-
 ca_hex = "19c8b725dbd74b7dcaf72bd9ff2cd207b47cb1095393685906171af9e2f2959e7f68729e0e40f97a22bbca93373d618ad51dd077c0d102938598a8ecc8a656e978ebd14007da99db8e691d85fc18a428097ee8a63dcf95b84b660294474a20ed2edcf2b1b4f305c1cc25860a08d1348c2a4d24cc1a97b51f920e2985b8108b3392a5eafc443cf3449e288eb49dbde2228a56233afa5a6643e5ae6ec6aa8937a666ef74a30625c35bb22c3cc57b700f8eae7690f8d37edbfd27ccb2e882f70d0d85e0cc825347453a28e98e877ab1eeaa6efa09f034bc8976bffb86420106978066ff52221b315f71eb32cbf608d2b72cfa [...]
-
 R_hex = "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 [...]
 
 cb_hex = "1f1f087e749c85aacdacaace8659a33b53baad5eec1e56628435d335a8b150f96865d6e090f53146e120e7089b6f4a91c762622b24d0d2fba0e703301170a0b826a1336d4d6bb83dccd29ad9ef0936614bf14e992ea4daa202c63ace9bd3f95b9a8a6edd7949e89ec165541e7c01bd41395baf3e2fe7f3a9611af8b5ed8639c02a2bfc236c17a136bef6d09f966db718f3df9d6f4f40b618b4b6058b4e4ec241e6c2424404d0aee0ef5cd666e5c4253a62ae9deb09289fb84657109e0b933f58871ba7ea77190d6ea45a04be68360478adf43a85851cf583c5575543578635996d2dcd020aeceabf18be6ff8b45e4ecd63 [...]
+z_hex = "0000000000000000000000000000000000000000000000000000000000000004"
+beta_hex = "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd036413d"
 
-z_hex = "0000000000000000000000000000000000000000000000000000000000000004";
-
-beta_hex = "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd036413d";
-
-alpha_hex = "000000000000000000000000000000000000000000000000000000000000000a";
+alpha_hex = "000000000000000000000000000000000000000000000000000000000000000a"
 
 if __name__ == "__main__":
-
-    seed = bytes.fromhex(seed_hex)    
+    seed = bytes.fromhex(seed_hex)
     p = bytes.fromhex(P_hex)
     q = bytes.fromhex(Q_hex)
     a = bytes.fromhex(a_hex)
     b = bytes.fromhex(b_hex)
-    z = bytes.fromhex(z_hex)        
+    z = bytes.fromhex(z_hex)
     r = bytes.fromhex(R_hex)
 
     ai = int(a_hex, 16)
-    bi = int(b_hex, 16)    
-    expected = ai * bi % amcl_mpc.curve_order
+    bi = int(b_hex, 16)
+    expected = ai * bi % mpc.curve_order
     print(f"expected {hex(expected)}")
-    
+
     # random number generator
-    rng = amcl_mpc.create_csprng(seed)
+    rng = mpc.create_csprng(seed)
 
     # Deterministic
+    paillier_pk, paillier_sk = mpc.paillier_key_pair(None, p, q)
 
-    paillier_pk, paillier_sk = amcl_mpc.paillier_key_pair(rng, p, q)
-
-    ca = amcl_mpc.mpc_mta_client1(rng, paillier_pk, a, r)
-
+    ca = mpc.mpc_mta_client1(rng, paillier_pk, a, r)
     ca1_hex = ca.hex()
-    assert ca_hex == ca1_hex, f"expected {ca_hex} got {ca1_hex}"    
-
-    cb, beta = amcl_mpc.mpc_mta_server(rng, paillier_pk, b, ca, z, r)
+    assert ca_hex == ca1_hex, f"expected {ca_hex} got {ca1_hex}"
 
+    cb, beta = mpc.mpc_mta_server(rng, paillier_pk, b, ca, z, r)
     cb1_hex = cb.hex()
-    assert cb_hex == cb1_hex, f"expected {cb_hex} got {cb1_hex}"    
+    assert cb_hex == cb1_hex, f"expected {cb_hex} got {cb1_hex}"
 
-    alpha = amcl_mpc.mpc_mta_client2(paillier_sk, cb)
+    alpha = mpc.mpc_mta_client2(paillier_sk, cb)
 
     print(f"alpha {alpha.hex()}")
     print(f"beta {beta.hex()}")
-    
+
     alphai = int(alpha.hex(), 16)
     betai = int(beta.hex(), 16)
-    got = ( alphai + betai ) % amcl_mpc.curve_order
-    print(f"got {hex(got)}")    
+    got = ( alphai + betai ) % mpc.curve_order
 
-    assert got == expected, f"expected {expected.hex()} got {got.hex()}"
-    
-    # Random
-    
-    paillier_pk, paillier_sk = amcl_mpc.paillier_key_pair(rng)
-    ca = amcl_mpc.mpc_mta_client1(rng, paillier_pk, a)
+    print(f"got {hex(got)}")
 
-    cb, beta = amcl_mpc.mpc_mta_server(rng, paillier_pk, b, ca)
+    assert got == expected, f"expected {hex(expected)} got {hex(got)}"
 
-    alpha = amcl_mpc.mpc_mta_client2(paillier_sk, cb)
+    # Random
+    paillier_pk, paillier_sk = mpc.paillier_key_pair(rng)
+    ca = mpc.mpc_mta_client1(rng, paillier_pk, a)
+    cb, beta = mpc.mpc_mta_server(rng, paillier_pk, b, ca)
+    alpha = mpc.mpc_mta_client2(paillier_sk, cb)
 
     print(f"alpha {alpha.hex()}")
     print(f"beta {beta.hex()}")
-    
+
     alphai = int(alpha.hex(), 16)
     betai = int(beta.hex(), 16)
-    got = ( alphai + betai ) % amcl_mpc.curve_order
-    print(f"got {hex(got)}")    
+    got = ( alphai + betai ) % mpc.curve_order
 
-    assert got == expected, f"expected {expected.hex()} got {got.hex()}"
+    print(f"got {hex(got)}")
 
-    
-    # Clear memory
-    amcl_mpc.kill_csprng(rng)
+    assert got == expected, f"expected {hex(expected)} got {hex(got)}"
 
+    # Clear memory
+    mpc.kill_csprng(rng)
+    mpc.paillier_private_key_kill(paillier_sk)
diff --git a/python/example_r.py b/python/example_r.py
index fbed92e..7f55ce0 100755
--- a/python/example_r.py
+++ b/python/example_r.py
@@ -9,7 +9,7 @@ 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
+    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
@@ -19,68 +19,53 @@ specific language governing permissions and limitations
 under the License.
 """
 
-import amcl_mpc
+from amcl import mpc
 
 seed_hex = "78d0fb6705ce77dee47d03eb5b9c5d30"
 
 P1_hex = "94f689d07ba20cf7c7ca7ccbed22ae6b40c426db74eaee4ce0ced2b6f52a5e136663f5f1ef379cdbb0c4fdd6e4074d6cff21082d4803d43d89e42fd8dfa82b135aa31a8844ffea25f255f956cbc1b9d8631d01baf1010d028a190b94ce40f3b72897e8196df19edf1ff62e6556f2701d52cef1442e3301db7608ecbdcca703db"
-
 Q1_hex = "9a9ad73f246df853e129c589925fdad9df05606a61081e62e72be4fb33f6e5ec492cc734f28bfb71fbe2ba9a11e4c02e2c0d103a5cbb0a9d6402c07de63b1b995dd72ac8f29825d66923a088b421fb4d52b0b855d2f5dde2be9b0ca0cee6f7a94e5566735fe6cff1fcad3199602f88528d19aa8d0263adff8f5053c38254a2a3"
 
 K1_hex = "52b7fe8435a2532b79ee252e5444c6a7178757f29a7ff17176ed9098ad168883"
-
 GAMMA2_hex = "2f595fbef2fa542fd1d20d07f02c7d4c50b4abb2d1f76b4952219edf59f3ccf7"
 
 CA11GOLDEN_hex = "159a663e0aea1bcd6a9caf1a2a6d2b868459cb65081f133d510b46863d1658894cdd93c0b325252f2c681c15acbad6a30eef0a05babe6bc1d9267f3268d84387c13348afa0bce0a9795008cf1d81a39ab8483cebacf4ae9bb617bdcce3b3864a36838a88357b74ea38cad34650d0d3fea2bfdd2949ee9bd58f529b2c0b717c3ced1c9ddcfa85abeaffc78b5ed6a8dd54aef7cfb9dabaa78d0c3dbc2b58fc682a52ada4628c3c3e004f2fdc9b8f15392c6d4acaa93b6eb1f7a0807e3ce905ea58ff7ba778737c001765117367723626a82c8f3c89deed8157a13ec30adeb8eba000ca5e7a72ffa045de558a1515 [...]
-
 R11_hex = "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 [...]
 
 CB12GOLDEN_hex = "1d7a81d4c53465b04668d95e16c75382fefa7942b7142c2758c9f386d6611151b9740d2c3402c3637c89a49b4166c5c16448f04bd1a6c06558e96bccabd322d6990e03ce0c0d78228af32ec185c281a1eae026d332690b49e5182db4a70df419cb57bdf29055e6242d3ba49e494ab60690c314aa0f1e4b4683344fed6080464733afe19e65565f569be80343b23b7d22e7ab157c311ed601e03ac480b0a6d1eacea71ecc1f6290a7ecd3b3b7de1b50174c5ca9f9d27e2c8fd5017ff72e9e4ca44725cecd2ee6ced380655d0e9febdee53c61a25322a217ad61b1486600791d3952dbf3f33cb762ce04a3653e82 [...]
-
 R12_hex = "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 [...]
-
 Z12_hex = "0207c724d58036400bcb7d99286aeb835745711fcf18c124fedb14bb252870bc"
-
 BETA2GOLDEN_hex = "fdf838db2a7fc9bff4348266d795147b63696bc6e02fdf16c0f749d1ab0dd085"
 
 ALPHA1GOLDEN_hex = "a43803ffcc7aa295dff0ede560973c151ef9f9c8160500bbcda7e18d0c2eac03"
 
 P2_hex = "c227a6d88ef469ceb323bcd95a18ab41d9cde9b349c093e7273e7d05f1636c517a21890f22785d45aeeb892da40a69267d3e2f1bd7e0f164cb23306402122512ed70d1cbb20c470d0c03a54adc47abfcc9eadff2ba175bb29aea70464f31f7804a8fc9c9fed60c505e11c594c9415fc96e1b44a3e5f437772bbce91e063827bf"
-
 Q2_hex = "e729b4e468f6076ad00dc9af0b820158be147727f4ead55b4d6268647d53c8f65e92338af9b24b819de20244e404800f659ce8595a8020ba941cf116b30ee31b0dc6367721714e511abae6157b3de5241ffd28ad309a70b9c316b5a40571808b85db4e00d82d80da4e7b5b6b37b10fd5c2c3815b7429f6eabddcd284d927352f"
 
 K2_hex = "6f6aa64cdf2f28bb081ec019b3a8e2eed89052441626172daf106f523b0b44cc"
-
 GAMMA1_hex = "0f757744e20d00dce6763b71ecb95f9fa9d4e788cfb9e39775d133e5e350ea93"
 
 CA22GOLDEN_hex = "3192b9daade647a4d17b5e2e0f08e6e3d0666fac576ff8e20be4a1072b23e0202195cb9738bf7d4f5784577d23071bec7c326b6ddf25bb2f4a415cb5a95b89c5a42d4d31a740f72576d798746d30078e15ba1a91d1687563bee2af7b4eceac2f0f13184df619a5ecde5caf9e88b123438afe73d4cc9c2c50ffde42f713cd9384b5cba6cda395d03383e7f8335ac61852fd18ea7012480c49aafc27f035045303f46d0a40fe4e7fce17facbc16e55a418c18256bb30216613a2590edcc0fbe1b18d0f6507273def2e2b740b04a880648d9dc5a5225884fc07bcdaec34d91b6f84ada7c274ba960f316c04765d0e [...]
-
 R22_hex = "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 [...]
 
 CB21GOLDEN_hex = "17b2dfb8b37675e4551f557c807a5f94950a0902b8627bb7840c37a054070da1028089b822e55df859dd2d95cd790691e2c27c08603d17bbb016fa159023776651befd64bc7e28bcdfcbeaf6b524fdaf8787217764b4d9385c922c76fd54118fbc7a897a7fc3288c813302f91424b7671b223aa9958f42dbc3dd3b600b57aa76998c68ef668af138bce9332d2983cffb25add049fc4a1be85410bcd17c9ba001c817a2a03802b85d7583a386650ea65fcbf243d8e5a66f2e79afbfaa2e42abcf8200f8f74a9aed2628bdb5c3dd3dcfe3a3f2f4dc7c23a12981e9637c5237c826bd445a3265b775e3c8d0e738f7 [...]
-
 R21_hex = "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 [...]
-
 Z21_hex = "101c7abf2665c3f311a11c988798476216b28d576657fe0e7795e7024086051a"
-
 BETA1GOLDEN_hex = "efe38540d99a3c0cee5ee3677867b89ca3fc4f8f48f0a22d483c778a8fb03c27"
 
 ALPHA2GOLDEN_hex = "945a07ddc50b23d9421aca78b7192d5647856a7e9c3cf951f149d3431273b5ff"
 
 SUM1GOLDEN_hex = "7d8436ceb1b37b1eb9829968350c721c70f3aa2eeee57c35442dc41c9a519abe"
-
 SUM2GOLDEN_hex = "c2cce80b56c443c5ead466b586e67bf490214bba39a3f484327d7d1de9bbc6d8"
 
 INVKGAMMAGOLDEN_hex = "f9419b11580cdc098cbcbfd3ac06e70d2d4827447353f64bd97daa5667b34ef9"
 
 GAMMAPT1_hex = "04206b7c7ae7ecf8fe79ac581d8de90b9a12a27f79732268649fb0ae109faade73385833cafe293b42e33097a79397c77c94a7d12a32304514a890a0c2d747a40d"
-
 GAMMAPT2_hex = "04fc86f69384e2b0cc3d563dc24ebb3a7ca0ac12dfa671e4cda4abdec35f33ed326fdc2404c8e236d5bea82bcbe4aeeb7545c8b5d0a19a39e00bacf8a7143800a9"
 
 SIG_RGOLDEN_hex = "8adf50a4f51443cac2b4d488092ab49925da09e3feb57a1fc03b5b917ca6de9f"
 
 if __name__ == "__main__":
-
     seed = bytes.fromhex(seed_hex)
     P1 = bytes.fromhex(P1_hex)
     Q1 = bytes.fromhex(Q1_hex)
@@ -98,80 +83,66 @@ if __name__ == "__main__":
     Z21 = bytes.fromhex(Z21_hex)
     GAMMAPT1 = bytes.fromhex(GAMMAPT1_hex)
     GAMMAPT2 = bytes.fromhex(GAMMAPT2_hex)
-        
+
     # random number generator
-    rng = amcl_mpc.create_csprng(seed)
+    rng = mpc.create_csprng(seed)
 
     # Deterministic
 
     # Paillier key pairs
-    paillier_pk1, paillier_sk1 = amcl_mpc.paillier_key_pair(rng, P1, Q1)
-    paillier_pk2, paillier_sk2 = amcl_mpc.paillier_key_pair(rng, P2, Q2)    
-    
-    # ALPHA1 + BETA2 = K1 * GAMMA2    
-
-    CA11 = amcl_mpc.mpc_mta_client1(rng, paillier_pk1, K1, R11)
+    paillier_pk1, paillier_sk1 = mpc.paillier_key_pair(None, P1, Q1)
+    paillier_pk2, paillier_sk2 = mpc.paillier_key_pair(None, P2, Q2)
 
+    # ALPHA1 + BETA2 = K1 * GAMMA2
+    CA11 = mpc.mpc_mta_client1(rng, paillier_pk1, K1, R11)
     CA11_hex = CA11.hex()
-    assert CA11GOLDEN_hex == CA11_hex, f"expected {CA11GOLDEN_hex} got {CA11_hex}"    
-    
-    CB12, BETA2 = amcl_mpc.mpc_mta_server(rng, paillier_pk1, GAMMA2, CA11, Z12, R12)
+    assert CA11GOLDEN_hex == CA11_hex, f"expected {CA11GOLDEN_hex} got {CA11_hex}"
 
+    CB12, BETA2 = mpc.mpc_mta_server(rng, paillier_pk1, GAMMA2, CA11, Z12, R12)
     CB12_hex = CB12.hex()
-    assert CB12GOLDEN_hex == CB12_hex, f"expected {CB12GOLDEN_hex} got {CB12_hex}"    
-    
-    BETA2_hex = BETA2.hex()    
-    assert BETA2GOLDEN_hex == BETA2_hex, f"expected {BETA2GOLDEN_hex} got {BETA2_hex}"    
+    assert CB12GOLDEN_hex == CB12_hex, f"expected {CB12GOLDEN_hex} got {CB12_hex}"
 
-    ALPHA1 = amcl_mpc.mpc_mta_client2(paillier_sk1, CB12)
+    BETA2_hex = BETA2.hex()
+    assert BETA2GOLDEN_hex == BETA2_hex, f"expected {BETA2GOLDEN_hex} got {BETA2_hex}"
 
-    ALPHA1_hex = ALPHA1.hex()        
+    ALPHA1 = mpc.mpc_mta_client2(paillier_sk1, CB12)
+    ALPHA1_hex = ALPHA1.hex()
     assert ALPHA1GOLDEN_hex == ALPHA1_hex, f"expected {ALPHA1GOLDEN_hex} got {ALPHA1_hex}"
-    
-    # ALPHA2 + BETA1 = K2 * GAMMA1
-
-    CA22 = amcl_mpc.mpc_mta_client1(rng, paillier_pk2, K2, R22)
 
+    # ALPHA2 + BETA1 = K2 * GAMMA1
+    CA22 = mpc.mpc_mta_client1(rng, paillier_pk2, K2, R22)
     CA22_hex = CA22.hex()
-    assert CA22GOLDEN_hex == CA22_hex, f"expected {CA22GOLDEN_hex} got {CA22_hex}"    
-    
-    CB21, BETA1 = amcl_mpc.mpc_mta_server(rng, paillier_pk2, GAMMA1, CA22, Z21, R21)
+    assert CA22GOLDEN_hex == CA22_hex, f"expected {CA22GOLDEN_hex} got {CA22_hex}"
 
+    CB21, BETA1 = mpc.mpc_mta_server(rng, paillier_pk2, GAMMA1, CA22, Z21, R21)
     CB21_hex = CB21.hex()
-    assert CB21GOLDEN_hex == CB21_hex, f"expected {CB21GOLDEN_hex} got {CB21_hex}"    
-    
-    BETA1_hex = BETA1.hex()    
-    assert BETA1GOLDEN_hex == BETA1_hex, f"expected {BETA1GOLDEN_hex} got {BETA1_hex}"    
+    assert CB21GOLDEN_hex == CB21_hex, f"expected {CB21GOLDEN_hex} got {CB21_hex}"
 
-    ALPHA2 = amcl_mpc.mpc_mta_client2(paillier_sk2, CB21)
+    BETA1_hex = BETA1.hex()
+    assert BETA1GOLDEN_hex == BETA1_hex, f"expected {BETA1GOLDEN_hex} got {BETA1_hex}"
 
-    ALPHA2_hex = ALPHA2.hex()        
-    assert ALPHA2GOLDEN_hex == ALPHA2_hex, f"expected {ALPHA2GOLDEN_hex} got {ALPHA2_hex}"    
-    # sum = K1.GAMMA1 + alpha1  + beta1
+    ALPHA2 = mpc.mpc_mta_client2(paillier_sk2, CB21)
+    ALPHA2_hex = ALPHA2.hex()
+    assert ALPHA2GOLDEN_hex == ALPHA2_hex, f"expected {ALPHA2GOLDEN_hex} got {ALPHA2_hex}"
 
-    SUM1 = amcl_mpc.mpc_sum_mta(K1, GAMMA1,  ALPHA1,  BETA1)
-
-    SUM1_hex = SUM1.hex()        
-    assert SUM1GOLDEN_hex == SUM1_hex, f"expected {SUM1GOLDEN_hex} got {SUM1_hex}"      
+    # sum = K1.GAMMA1 + alpha1  + beta1
+    SUM1 = mpc.mpc_sum_mta(K1, GAMMA1,  ALPHA1,  BETA1)
+    SUM1_hex = SUM1.hex()
+    assert SUM1GOLDEN_hex == SUM1_hex, f"expected {SUM1GOLDEN_hex} got {SUM1_hex}"
 
     # sum = K2.GAMMA2 + alpha2  + beta2
-
-    SUM2 = amcl_mpc.mpc_sum_mta(K2, GAMMA2, ALPHA2, BETA2)
-
-    SUM2_hex = SUM2.hex()        
-    assert SUM2GOLDEN_hex == SUM2_hex, f"expected {SUM2GOLDEN_hex} got {SUM2_hex}"      
+    SUM2 = mpc.mpc_sum_mta(K2, GAMMA2, ALPHA2, BETA2)
+    SUM2_hex = SUM2.hex()
+    assert SUM2GOLDEN_hex == SUM2_hex, f"expected {SUM2GOLDEN_hex} got {SUM2_hex}"
 
     # Calculate the inverse of kgamma
+    INVKGAMMA = mpc.mpc_invkgamma(SUM1, SUM2)
+    INVKGAMMA_hex = INVKGAMMA.hex()
+    assert INVKGAMMAGOLDEN_hex == INVKGAMMA_hex, f"expected {INVKGAMMAGOLDEN_hex} got {INVKGAMMA_hex}"
 
-    INVKGAMMA = amcl_mpc.mpc_invkgamma(SUM1, SUM2)
-
-    INVKGAMMA_hex = INVKGAMMA.hex()        
-    assert INVKGAMMAGOLDEN_hex == INVKGAMMA_hex, f"expected {INVKGAMMAGOLDEN_hex} got {INVKGAMMA_hex}"      
     # Calculate the R signature component
+    rc, SIG_R, _ = mpc.mpc_r(INVKGAMMA, GAMMAPT1, GAMMAPT2)
+    SIG_R_hex = SIG_R.hex()
+    assert SIG_RGOLDEN_hex == SIG_R_hex, f"expected {SIG_RGOLDEN_hex} got {SIG_R_hex}"
 
-    rc, SIG_R, _ = amcl_mpc.mpc_r(INVKGAMMA, GAMMAPT1, GAMMAPT2)
-
-    SIG_R_hex = SIG_R.hex()        
-    assert SIG_RGOLDEN_hex == SIG_R_hex, f"expected {SIG_RGOLDEN_hex} got {SIG_R_hex}"      
-    
     print(f"r component {SIG_R_hex}")
diff --git a/python/example_s.py b/python/example_s.py
index f3029d0..011a437 100755
--- a/python/example_s.py
+++ b/python/example_s.py
@@ -19,56 +19,43 @@ specific language governing permissions and limitations
 under the License.
 """
 
-import amcl_mpc
+from amcl import mpc
 
 seed_hex = "78d0fb6705ce77dee47d03eb5b9c5d30"
 
 P1_hex = "94f689d07ba20cf7c7ca7ccbed22ae6b40c426db74eaee4ce0ced2b6f52a5e136663f5f1ef379cdbb0c4fdd6e4074d6cff21082d4803d43d89e42fd8dfa82b135aa31a8844ffea25f255f956cbc1b9d8631d01baf1010d028a190b94ce40f3b72897e8196df19edf1ff62e6556f2701d52cef1442e3301db7608ecbdcca703db"
-
 Q1_hex = "9a9ad73f246df853e129c589925fdad9df05606a61081e62e72be4fb33f6e5ec492cc734f28bfb71fbe2ba9a11e4c02e2c0d103a5cbb0a9d6402c07de63b1b995dd72ac8f29825d66923a088b421fb4d52b0b855d2f5dde2be9b0ca0cee6f7a94e5566735fe6cff1fcad3199602f88528d19aa8d0263adff8f5053c38254a2a3"
 
 K1_hex = "52b7fe8435a2532b79ee252e5444c6a7178757f29a7ff17176ed9098ad168883"
-
 W2_hex = "0aec8feb32fd8bbb4526b6d5af6681519e195874ada7474255c89926efe53291"
 
 CA11GOLDEN_hex = "159a663e0aea1bcd6a9caf1a2a6d2b868459cb65081f133d510b46863d1658894cdd93c0b325252f2c681c15acbad6a30eef0a05babe6bc1d9267f3268d84387c13348afa0bce0a9795008cf1d81a39ab8483cebacf4ae9bb617bdcce3b3864a36838a88357b74ea38cad34650d0d3fea2bfdd2949ee9bd58f529b2c0b717c3ced1c9ddcfa85abeaffc78b5ed6a8dd54aef7cfb9dabaa78d0c3dbc2b58fc682a52ada4628c3c3e004f2fdc9b8f15392c6d4acaa93b6eb1f7a0807e3ce905ea58ff7ba778737c001765117367723626a82c8f3c89deed8157a13ec30adeb8eba000ca5e7a72ffa045de558a1515 [...]
-
 R11_hex = "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 [...]
 
 CB12GOLDEN_hex = "09c9e0fe1ba09663cafa368daa6b404df6e719646a7d4ade95909e7513086cc947e3d5dfc14e22d3cdf842df917617e6a79997b5cca3c0d45894e3d6aeef854d8c10ed5abaeb40c9e35142cb4acdbcbfc51e72d259cb5a26efe77626ba21922d6a09897c8ac3eb080de36f7b622f09c4d70a6315bbed69fff3aa7406358f6c588cd01fc1c5abf9899e76ed8da9fda4d323687d9746ff35e46cc64947b25f25f6d9ae9365cb8a019d508ef76f02673a6dee9376a8ac2aef9c1045966e856e5e08de3f93aeb7ea1fa2fe9adf2587ea5e12f245cb30859293c36eb27e41c35db18df8743fd14f76e581c518add321 [...]
-
 R12_hex = "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 [...]
-
 Z12_hex = "0207c724d58036400bcb7d99286aeb835745711fcf18c124fedb14bb252870bc"
-
 BETA2GOLDEN_hex = "fdf838db2a7fc9bff4348266d795147b63696bc6e02fdf16c0f749d1ab0dd085"
 
 ALPHA1GOLDEN_hex = "a0e312daab26f391796f16c358dba05ca8da9dad5ecaeccbb0433a95049bd390"
 
 P2_hex = "c227a6d88ef469ceb323bcd95a18ab41d9cde9b349c093e7273e7d05f1636c517a21890f22785d45aeeb892da40a69267d3e2f1bd7e0f164cb23306402122512ed70d1cbb20c470d0c03a54adc47abfcc9eadff2ba175bb29aea70464f31f7804a8fc9c9fed60c505e11c594c9415fc96e1b44a3e5f437772bbce91e063827bf"
-
 Q2_hex = "e729b4e468f6076ad00dc9af0b820158be147727f4ead55b4d6268647d53c8f65e92338af9b24b819de20244e404800f659ce8595a8020ba941cf116b30ee31b0dc6367721714e511abae6157b3de5241ffd28ad309a70b9c316b5a40571808b85db4e00d82d80da4e7b5b6b37b10fd5c2c3815b7429f6eabddcd284d927352f"
 
 K2_hex = "6f6aa64cdf2f28bb081ec019b3a8e2eed89052441626172daf106f523b0b44cc"
-
 W1_hex = "248ea4e0ce968bdd1febd48e2d246f7268070eb468eca0c1e911cc1642bd8041"
 
 CA22GOLDEN_hex = "3192b9daade647a4d17b5e2e0f08e6e3d0666fac576ff8e20be4a1072b23e0202195cb9738bf7d4f5784577d23071bec7c326b6ddf25bb2f4a415cb5a95b89c5a42d4d31a740f72576d798746d30078e15ba1a91d1687563bee2af7b4eceac2f0f13184df619a5ecde5caf9e88b123438afe73d4cc9c2c50ffde42f713cd9384b5cba6cda395d03383e7f8335ac61852fd18ea7012480c49aafc27f035045303f46d0a40fe4e7fce17facbc16e55a418c18256bb30216613a2590edcc0fbe1b18d0f6507273def2e2b740b04a880648d9dc5a5225884fc07bcdaec34d91b6f84ada7c274ba960f316c04765d0e [...]
-
 R22_hex = "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 [...]
 
 CB21GOLDEN_hex = "195a0cb5a5677bd8b22606346aa2c80e42be21442119079d56ee169eb6ee84b54e8f8c5b1196edc133520c9b60f6735ea444880e9c47eabe41b409cf3a1ac9e51e1b48e855e47f92c7395f825ad2c82648c0b4e303d02345130b6c7df80fe8da0df632ea61bfb4b2373587cc59c37810eee25ec4e74db801729b32134e03e9df04edbc354c42ee9bee52f5939f12783854ed221bcb7e3ce366843c3b40b7396574bffdd2e5ad6d85487f95e62858cedf91e14fe31e922603303a4da6190f1940243539bdfd833920071aaefe5e719310bf4e99bff85154a19dac944a395ad0c820bfe8ead7a3a80aa32cd2a601 [...]
-
 R21_hex = "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 [...]
-
 Z21_hex = "101c7abf2665c3f311a11c988798476216b28d576657fe0e7795e7024086051a"
-
 BETA1GOLDEN_hex = "efe38540d99a3c0cee5ee3677867b89ca3fc4f8f48f0a22d483c778a8fb03c27"
 
 ALPHA2GOLDEN_hex = "75cf36d1b9c257313412185bc75b86f158dfd7d09c8584a98aa3a3ee852f512e"
 
 SUM1GOLDEN_hex = "68891b7166cf16ec847db1ce65c472d8978dbdb1fc01089330e151f4face11b4"
-
 SUM2GOLDEN_hex = "3231b07d70de00c4e250f7b545bfbfebe19f71f6a7e85ffefc2dc19b8ba4aeee"
 
 SIG_R_hex = "8adf50a4f51443cac2b4d488092ab49925da09e3feb57a1fc03b5b917ca6de9f"
@@ -76,13 +63,10 @@ SIG_R_hex = "8adf50a4f51443cac2b4d488092ab49925da09e3feb57a1fc03b5b917ca6de9f"
 M_hex = "74657374206d657373616765"
 
 SIG_S1GOLDEN_hex = "d14b16fbbd346f5a9f184a064c351eca2d516a2e88ed3aab5713fea9766aa2b1"
-
 SIG_S2GOLDEN_hex = "44548a9ba59d1459a047a7ae5095b0cc70f7d1de6cd5730730cdd762619d8c9a"
-
 SIG_SGOLDEN_hex = "159fa19762d183b43f5ff1b49ccacf97e39a5f26467a0d76c80f777f07d1ee0a"
 
 if __name__ == "__main__":
-
     seed = bytes.fromhex(seed_hex)
     P1 = bytes.fromhex(P1_hex)
     Q1 = bytes.fromhex(Q1_hex)
@@ -99,91 +83,73 @@ if __name__ == "__main__":
     R21 = bytes.fromhex(R21_hex)
     Z21 = bytes.fromhex(Z21_hex)
     M = bytes.fromhex(M_hex)
-    SIG_R = bytes.fromhex(SIG_R_hex)        
-        
+    SIG_R = bytes.fromhex(SIG_R_hex)
+
     # random number generator
-    rng = amcl_mpc.create_csprng(seed)
+    rng = mpc.create_csprng(seed)
 
     # Deterministic
 
     # Paillier key pairs
-    paillier_pk1, paillier_sk1 = amcl_mpc.paillier_key_pair(rng, P1, Q1)
-    paillier_pk2, paillier_sk2 = amcl_mpc.paillier_key_pair(rng, P2, Q2)    
-    
-    # ALPHA1 + BETA2 = K1 * W2    
-    CA11 = amcl_mpc.mpc_mta_client1(rng, paillier_pk1, K1, R11)
+    paillier_pk1, paillier_sk1 = mpc.paillier_key_pair(None, P1, Q1)
+    paillier_pk2, paillier_sk2 = mpc.paillier_key_pair(None, P2, Q2)
 
+    # ALPHA1 + BETA2 = K1 * W2
+    CA11 = mpc.mpc_mta_client1(rng, paillier_pk1, K1, R11)
     CA11_hex = CA11.hex()
-    assert CA11GOLDEN_hex == CA11_hex, f"expected {CA11GOLDEN_hex} got {CA11_hex}"    
-    
-    CB12, BETA2 = amcl_mpc.mpc_mta_server(rng, paillier_pk1, W2, CA11, Z12, R12)
+    assert CA11GOLDEN_hex == CA11_hex, f"expected {CA11GOLDEN_hex} got {CA11_hex}"
 
+    CB12, BETA2 = mpc.mpc_mta_server(rng, paillier_pk1, W2, CA11, Z12, R12)
     CB12_hex = CB12.hex()
-    assert CB12GOLDEN_hex == CB12_hex, f"expected {CB12GOLDEN_hex} got {CB12_hex}"    
-    
-    BETA2_hex = BETA2.hex()    
-    assert BETA2GOLDEN_hex == BETA2_hex, f"expected {BETA2GOLDEN_hex} got {BETA2_hex}"    
+    assert CB12GOLDEN_hex == CB12_hex, f"expected {CB12GOLDEN_hex} got {CB12_hex}"
 
-    ALPHA1 = amcl_mpc.mpc_mta_client2(paillier_sk1, CB12)
+    BETA2_hex = BETA2.hex()
+    assert BETA2GOLDEN_hex == BETA2_hex, f"expected {BETA2GOLDEN_hex} got {BETA2_hex}"
 
-    ALPHA1_hex = ALPHA1.hex()        
+    ALPHA1 = mpc.mpc_mta_client2(paillier_sk1, CB12)
+    ALPHA1_hex = ALPHA1.hex()
     assert ALPHA1GOLDEN_hex == ALPHA1_hex, f"expected {ALPHA1GOLDEN_hex} got {ALPHA1_hex}"
-    
-    # ALPHA2 + BETA1 = K2 * W1
-    CA22 = amcl_mpc.mpc_mta_client1(rng, paillier_pk2, K2, R22)
 
+    # ALPHA2 + BETA1 = K2 * W1
+    CA22 = mpc.mpc_mta_client1(rng, paillier_pk2, K2, R22)
     CA22_hex = CA22.hex()
-    assert CA22GOLDEN_hex == CA22_hex, f"expected {CA22GOLDEN_hex} got {CA22_hex}"    
-    
-    CB21, BETA1 = amcl_mpc.mpc_mta_server(rng, paillier_pk2, W1, CA22, Z21, R21)
+    assert CA22GOLDEN_hex == CA22_hex, f"expected {CA22GOLDEN_hex} got {CA22_hex}"
 
+    CB21, BETA1 = mpc.mpc_mta_server(rng, paillier_pk2, W1, CA22, Z21, R21)
     CB21_hex = CB21.hex()
-    assert CB21GOLDEN_hex == CB21_hex, f"expected {CB21GOLDEN_hex} got {CB21_hex}"    
-    
-    BETA1_hex = BETA1.hex()    
-    assert BETA1GOLDEN_hex == BETA1_hex, f"expected {BETA1GOLDEN_hex} got {BETA1_hex}"    
+    assert CB21GOLDEN_hex == CB21_hex, f"expected {CB21GOLDEN_hex} got {CB21_hex}"
 
-    ALPHA2 = amcl_mpc.mpc_mta_client2(paillier_sk2, CB21)
+    BETA1_hex = BETA1.hex()
+    assert BETA1GOLDEN_hex == BETA1_hex, f"expected {BETA1GOLDEN_hex} got {BETA1_hex}"
 
-    ALPHA2_hex = ALPHA2.hex()        
+    ALPHA2 = mpc.mpc_mta_client2(paillier_sk2, CB21)
+    ALPHA2_hex = ALPHA2.hex()
     assert ALPHA2GOLDEN_hex == ALPHA2_hex, f"expected {ALPHA2GOLDEN_hex} got {ALPHA2_hex}"
-    
-    # sum = K1.W1 + alpha1  + beta1
-
-    SUM1 = amcl_mpc.mpc_sum_mta(K1, W1,  ALPHA1,  BETA1)
 
-    SUM1_hex = SUM1.hex()        
-    assert SUM1GOLDEN_hex == SUM1_hex, f"expected {SUM1GOLDEN_hex} got {SUM1_hex}"      
+    # sum = K1.W1 + alpha1  + beta1
+    SUM1 = mpc.mpc_sum_mta(K1, W1,  ALPHA1,  BETA1)
+    SUM1_hex = SUM1.hex()
+    assert SUM1GOLDEN_hex == SUM1_hex, f"expected {SUM1GOLDEN_hex} got {SUM1_hex}"
 
     # sum = K2.W2 + alpha2  + beta2
-
-    SUM2 = amcl_mpc.mpc_sum_mta(K2, W2, ALPHA2, BETA2)
-
-    SUM2_hex = SUM2.hex()        
-    assert SUM2GOLDEN_hex == SUM2_hex, f"expected {SUM2GOLDEN_hex} got {SUM2_hex}"      
+    SUM2 = mpc.mpc_sum_mta(K2, W2, ALPHA2, BETA2)
+    SUM2_hex = SUM2.hex()
+    assert SUM2GOLDEN_hex == SUM2_hex, f"expected {SUM2GOLDEN_hex} got {SUM2_hex}"
 
     # Calculate the message hash
-    
-    HM = amcl_mpc.mpc_hash(M)
+    HM = mpc.mpc_hash(M)
 
     # Calculate the S1 signature component
-
-    rc, SIG_S1 = amcl_mpc.mpc_s(HM, SIG_R, K1, SUM1)
-
-    SIG_S1_hex = SIG_S1.hex()        
+    rc, SIG_S1 = mpc.mpc_s(HM, SIG_R, K1, SUM1)
+    SIG_S1_hex = SIG_S1.hex()
     assert SIG_S1GOLDEN_hex == SIG_S1_hex, f"expected {SIG_S1GOLDEN_hex} got {SIG_S1_hex}"
 
     # Calculate the S2 signature component
-
-    rc, SIG_S2 = amcl_mpc.mpc_s(HM, SIG_R, K2, SUM2)
-
-    SIG_S2_hex = SIG_S2.hex()        
+    rc, SIG_S2 = mpc.mpc_s(HM, SIG_R, K2, SUM2)
+    SIG_S2_hex = SIG_S2.hex()
     assert SIG_S2GOLDEN_hex == SIG_S2_hex, f"expected {SIG_S2GOLDEN_hex} got {SIG_S2_hex}"
 
     # Sum S signature component
-
-    SIG_S = amcl_mpc.mpc_sum_s(SIG_S1, SIG_S2)
-
-    SIG_S_hex = SIG_S.hex()        
-    assert SIG_SGOLDEN_hex == SIG_S_hex, f"expected {SIG_SGOLDEN_hex} got {SIG_S_hex}"      
-    
+    SIG_S = mpc.mpc_sum_s(SIG_S1, SIG_S2)
+    SIG_S_hex = SIG_S.hex()
+    assert SIG_SGOLDEN_hex == SIG_S_hex, f"expected {SIG_SGOLDEN_hex} got {SIG_S_hex}"
diff --git a/python/test_ecdsa.py b/python/test_ecdsa.py
index 98c85a0..1c60bfd 100755
--- a/python/test_ecdsa.py
+++ b/python/test_ecdsa.py
@@ -21,128 +21,102 @@ under the License.
 import unittest
 import json
 import os
-import amcl_mpc
+from amcl import mpc
 
 
 class TestECDSA(unittest.TestCase):
     """Tests MPC ECDSA"""
 
-    def setUp(self):
-        None
-
     def test_1(self):
         """test_1 Test MPC ECDSA"""
         for i in range(1,11):
             print(f"Test {i}")
 
             seed = os.urandom(16)
-            rng = amcl_mpc.create_csprng(seed)
-            
+            rng = mpc.create_csprng(seed)
+
             # Paillier keys
-            paillier_pk1, paillier_sk1 = amcl_mpc.paillier_key_pair(rng)
-            paillier_pk2, paillier_sk2 = amcl_mpc.paillier_key_pair(rng)
+            paillier_pk1, paillier_sk1 = mpc.paillier_key_pair(rng)
+            paillier_pk2, paillier_sk2 = mpc.paillier_key_pair(rng)
 
             # ECDSA keys
-            rc, PK1, W1 = amcl_mpc.ecp_secp256k1_key_pair_generate(rng)
-            rc = amcl_mpc.ecp_secp256k1_public_key_validate(PK1)    
+            rc, PK1, W1 = mpc.ecp_secp256k1_key_pair_generate(rng)
+            rc = mpc.ecp_secp256k1_public_key_validate(PK1)
             assert rc == 0, f"Invalid ECDSA public key"
 
-            rc, PK2, W2 = amcl_mpc.ecp_secp256k1_key_pair_generate(rng)
-            rc = amcl_mpc.ecp_secp256k1_public_key_validate(PK2)    
+            rc, PK2, W2 = mpc.ecp_secp256k1_key_pair_generate(rng)
+            rc = mpc.ecp_secp256k1_public_key_validate(PK2)
             assert rc == 0, f"Invalid ECDSA public key"
 
             # Gamma values
-            rc, GAMMAPT1, GAMMA1 = amcl_mpc.ecp_secp256k1_key_pair_generate(rng)
-            rc, GAMMAPT2, GAMMA2 = amcl_mpc.ecp_secp256k1_key_pair_generate(rng)
+            rc, GAMMAPT1, GAMMA1 = mpc.ecp_secp256k1_key_pair_generate(rng)
+            rc, GAMMAPT2, GAMMA2 = mpc.ecp_secp256k1_key_pair_generate(rng)
 
             # K values
-            rc, TMP1, K1 = amcl_mpc.ecp_secp256k1_key_pair_generate(rng)
-            rc, TMP2, K2 = amcl_mpc.ecp_secp256k1_key_pair_generate(rng)
+            rc, _, K1 = mpc.ecp_secp256k1_key_pair_generate(rng)
+            rc, _, K2 = mpc.ecp_secp256k1_key_pair_generate(rng)
 
             # Message
             M = b'test message'
-    
-            # ALPHA1 + BETA2 = K1 * GAMMA2    
-
-            CA11 = amcl_mpc.mpc_mta_client1(rng, paillier_pk1, K1)
 
-            CB12, BETA2 = amcl_mpc.mpc_mta_server(rng, paillier_pk1, GAMMA2, CA11)
-
-            ALPHA1 = amcl_mpc.mpc_mta_client2(paillier_sk1, CB12)
+            # ALPHA1 + BETA2 = K1 * GAMMA2
+            CA11 = mpc.mpc_mta_client1(rng, paillier_pk1, K1)
+            CB12, BETA2 = mpc.mpc_mta_server(rng, paillier_pk1, GAMMA2, CA11)
+            ALPHA1 = mpc.mpc_mta_client2(paillier_sk1, CB12)
 
             # ALPHA2 + BETA1 = K2 * GAMMA1
-
-            CA22 = amcl_mpc.mpc_mta_client1(rng, paillier_pk2, K2)
-    
-            CB21, BETA1 = amcl_mpc.mpc_mta_server(rng, paillier_pk2, GAMMA1, CA22)
-
-            ALPHA2 = amcl_mpc.mpc_mta_client2(paillier_sk2, CB21)
+            CA22 = mpc.mpc_mta_client1(rng, paillier_pk2, K2)
+            CB21, BETA1 = mpc.mpc_mta_server(rng, paillier_pk2, GAMMA1, CA22)
+            ALPHA2 = mpc.mpc_mta_client2(paillier_sk2, CB21)
 
             # sum = K1.GAMMA1 + alpha1  + beta1
-
-            SUM1 = amcl_mpc.mpc_sum_mta(K1, GAMMA1,  ALPHA1,  BETA1)
+            SUM1 = mpc.mpc_sum_mta(K1, GAMMA1,  ALPHA1,  BETA1)
 
             # sum = K2.GAMMA2 + alpha2  + beta2
-
-            SUM2 = amcl_mpc.mpc_sum_mta(K2, GAMMA2, ALPHA2, BETA2)
+            SUM2 = mpc.mpc_sum_mta(K2, GAMMA2, ALPHA2, BETA2)
 
             # Calculate the inverse of kgamma
-
-            INVKGAMMA = amcl_mpc.mpc_invkgamma(SUM1, SUM2)
+            INVKGAMMA = mpc.mpc_invkgamma(SUM1, SUM2)
 
             # Calculate the R signature component
+            rc, SIG_R, _ = mpc.mpc_r(INVKGAMMA, GAMMAPT1, GAMMAPT2)
 
-            rc, SIG_R, _ = amcl_mpc.mpc_r(INVKGAMMA, GAMMAPT1, GAMMAPT2)
-           
-            # ALPHA1 + BETA2 = K1 * W2    
-
-            CA11 = amcl_mpc.mpc_mta_client1(rng, paillier_pk1, K1)
+            # ALPHA1 + BETA2 = K1 * W2
+            CA11 = mpc.mpc_mta_client1(rng, paillier_pk1, K1)
+            CB12, BETA2 = mpc.mpc_mta_server(rng, paillier_pk1, W2, CA11)
+            ALPHA1 = mpc.mpc_mta_client2(paillier_sk1, CB12)
 
-            CB12, BETA2 = amcl_mpc.mpc_mta_server(rng, paillier_pk1, W2, CA11)
- 
-            ALPHA1 = amcl_mpc.mpc_mta_client2(paillier_sk1, CB12)
-    
             # ALPHA2 + BETA1 = K2 * W1
-
-            CA22 = amcl_mpc.mpc_mta_client1(rng, paillier_pk2, K2)
-    
-            CB21, BETA1 = amcl_mpc.mpc_mta_server(rng, paillier_pk2, W1, CA22)
-
-            ALPHA2 = amcl_mpc.mpc_mta_client2(paillier_sk2, CB21)
+            CA22 = mpc.mpc_mta_client1(rng, paillier_pk2, K2)
+            CB21, BETA1 = mpc.mpc_mta_server(rng, paillier_pk2, W1, CA22)
+            ALPHA2 = mpc.mpc_mta_client2(paillier_sk2, CB21)
 
             # sum = K1.W1 + alpha1  + beta1
-
-            SUM1 = amcl_mpc.mpc_sum_mta(K1, W1,  ALPHA1,  BETA1)
+            SUM1 = mpc.mpc_sum_mta(K1, W1,  ALPHA1,  BETA1)
 
             # sum = K2.W2 + alpha2  + beta2
-
-            SUM2 = amcl_mpc.mpc_sum_mta(K2, W2, ALPHA2, BETA2)
+            SUM2 = mpc.mpc_sum_mta(K2, W2, ALPHA2, BETA2)
 
             # Calculate the message hash
-    
-            HM = amcl_mpc.mpc_hash(M)
+            HM = mpc.mpc_hash(M)
 
             # Calculate the S1 signature component
-
-            rc, SIG_S1 = amcl_mpc.mpc_s(HM, SIG_R, K1, SUM1)
+            rc, SIG_S1 = mpc.mpc_s(HM, SIG_R, K1, SUM1)
 
             # Calculate the S2 signature component
-
-            rc, SIG_S2 = amcl_mpc.mpc_s(HM, SIG_R, K2, SUM2)
+            rc, SIG_S2 = mpc.mpc_s(HM, SIG_R, K2, SUM2)
 
             # Sum S signature component
-
-            SIG_S = amcl_mpc.mpc_sum_s(SIG_S1, SIG_S2)
+            SIG_S = mpc.mpc_sum_s(SIG_S1, SIG_S2)
 
             # Sum ECDSA public keys
-
-            rc, PK = amcl_mpc.mpc_sum_pk(PK1, PK2)
+            rc, PK = mpc.mpc_sum_pk(PK1, PK2)
 
             # Verify final signature
+            rc = mpc.mpc_ecdsa_verify(HM, PK, SIG_R, SIG_S)
+
+            self.assertEqual(rc, 0)
 
-            rc = amcl_mpc.mpc_ecdsa_verify(HM, PK, SIG_R, SIG_S)
-            self.assertEqual(rc, 0)  
-            
 
 if __name__ == '__main__':
     # Run tests
diff --git a/python/test_mta.py b/python/test_mta.py
index 02c3396..8a74971 100755
--- a/python/test_mta.py
+++ b/python/test_mta.py
@@ -20,39 +20,42 @@ under the License.
 """
 import unittest
 import json
-import amcl_mpc
+from amcl import mpc
 
 
 class TestMtA(unittest.TestCase):
     """Tests MPC MtA"""
 
     def setUp(self):
-        seed_hex = "78d0fb6705ce77dee47d03eb5b9c5d30"
-        seed = bytes.fromhex(seed_hex)
-        self.rng = amcl_mpc.create_csprng(seed)
+        with open("MTA.json", "r") as f:
+            self.tv = json.load(f)
+
+        for vector in self.tv:
+            for key, val in vector.items():
+                if key != "TEST":
+                    vector[key] = bytes.fromhex(val)
 
     def test_1(self):
         """test_1 Test Vector test"""
-        with open("MTA.json", "r") as f:
-            vectors = json.load(f)
-        for vector in vectors:
+
+        for vector in self.tv:
             print(f"Test vector {vector['TEST']}")
-            test = {}
-            for key, val in vector.items():
-                if key != "TEST":
-                    # print(f"{key} = {val}\n")
-                    test[key] = bytes.fromhex(val)
-            paillier_pk, paillier_sk = amcl_mpc.paillier_key_pair(self.rng, test['P'], test['Q'])
 
-            ca = amcl_mpc.mpc_mta_client1(self.rng, paillier_pk, test['A'], test['R1'])
-            self.assertEqual(vector['CA'], ca.hex())
+            paillier_pk, paillier_sk = mpc.paillier_key_pair(None, vector['P'], vector['Q'])
+
+            ca = mpc.mpc_mta_client1(None, paillier_pk, vector['A'], vector['R1'])
+
+            self.assertEqual(vector['CA'], ca)
+
+            cb, beta = mpc.mpc_mta_server(None, paillier_pk, vector['B'], vector['CA'], vector['Z'], vector['R2'])
+
+            self.assertEqual(vector['CB'], cb)
+            self.assertEqual(vector['BETA'], beta)
+
+            alpha = mpc.mpc_mta_client2(paillier_sk, vector['CB'])
 
-            cb, beta = amcl_mpc.mpc_mta_server(self.rng, paillier_pk, test['B'], test['CA'], test['Z'], test['R2'])
-            self.assertEqual(vector['CB'], cb.hex())
-            self.assertEqual(vector['BETA'], beta.hex())
+            self.assertEqual(vector['ALPHA'], alpha)
 
-            alpha = amcl_mpc.mpc_mta_client2(paillier_sk, test['CB'])
-            self.assertEqual(vector['ALPHA'], alpha.hex())            
 
 if __name__ == '__main__':
     # Run tests
diff --git a/python/test_r.py b/python/test_r.py
index f3175ea..2b53ca6 100755
--- a/python/test_r.py
+++ b/python/test_r.py
@@ -18,70 +18,71 @@ KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 """
+
 import unittest
 import json
-import amcl_mpc
+from amcl import mpc
 
 
 class TestR(unittest.TestCase):
     """Tests MPC R"""
 
     def setUp(self):
-        seed_hex = "78d0fb6705ce77dee47d03eb5b9c5d30"
-        seed = bytes.fromhex(seed_hex)
-        self.rng = amcl_mpc.create_csprng(seed)
+        with open("R.json", "r") as f:
+            self.tv = json.load(f)
+
+        for vector in self.tv:
+            for key, val in vector.items():
+                if key != "TEST":
+                    vector[key] = bytes.fromhex(val)
 
     def test_1(self):
         """test_1 Test Vector test"""
-        with open("R.json", "r") as f:
-            vectors = json.load(f)
-        for vector in vectors:
+
+        for vector in self.tv:
             print(f"Test vector {vector['TEST']}")
-            test = {}
-            for key, val in vector.items():
-                if key != "TEST":
-                    # print(f"{key} = {val}\n")
-                    test[key] = bytes.fromhex(val)
-            PUB1, PRIV1 = amcl_mpc.paillier_key_pair(self.rng, test['P1'], test['Q1'])
-            PUB2, PRIV2 = amcl_mpc.paillier_key_pair(self.rng, test['P2'], test['Q2'])            
+
+            PUB1, PRIV1 = mpc.paillier_key_pair(None, vector['P1'], vector['Q1'])
+            PUB2, PRIV2 = mpc.paillier_key_pair(None, vector['P2'], vector['Q2'])
 
             # ALPHA1 + BETA2 = A1 * B2
-            ca11 = amcl_mpc.mpc_mta_client1(self.rng, PUB1, test['A1'], test['R11'])
-            cb12, beta2 = amcl_mpc.mpc_mta_server(self.rng, PUB1, test['B2'], ca11, test['Z12'], test['R12'])
-            alpha1 = amcl_mpc.mpc_mta_client2(PRIV1, cb12)
-            
-            self.assertEqual(vector['ALPHA1'], alpha1.hex())
-            self.assertEqual(vector['BETA2'], beta2.hex())             
+            ca11 = mpc.mpc_mta_client1(None, PUB1, vector['A1'], vector['R11'])
+            cb12, beta2 = mpc.mpc_mta_server(None, PUB1, vector['B2'], ca11, vector['Z12'], vector['R12'])
+            alpha1 = mpc.mpc_mta_client2(PRIV1, cb12)
+
+            self.assertEqual(vector['ALPHA1'], alpha1)
+            self.assertEqual(vector['BETA2'], beta2)
 
             # ALPHA2 + BETA1 = A2 * B1
-            ca22 = amcl_mpc.mpc_mta_client1(self.rng, PUB2, test['A2'], test['R22'])
-            cb21, beta1 = amcl_mpc.mpc_mta_server(self.rng, PUB2, test['B1'], ca22, test['Z21'], test['R21'])
-            alpha2 = amcl_mpc.mpc_mta_client2(PRIV2, cb21)
-            
-            self.assertEqual(vector['ALPHA2'], alpha2.hex())
-            self.assertEqual(vector['BETA1'], beta1.hex())             
+            ca22 = mpc.mpc_mta_client1(None, PUB2, vector['A2'], vector['R22'])
+            cb21, beta1 = mpc.mpc_mta_server(None, PUB2, vector['B1'], ca22, vector['Z21'], vector['R21'])
+            alpha2 = mpc.mpc_mta_client2(PRIV2, cb21)
+
+            self.assertEqual(vector['ALPHA2'], alpha2)
+            self.assertEqual(vector['BETA1'], beta1)
 
             # sum1 = A1.B1 + alpha1 + beta1
+            sum1 = mpc.mpc_sum_mta(vector['A1'], vector['B1'],  alpha1,  beta1)
 
-            sum1 = amcl_mpc.mpc_sum_mta(test['A1'], test['B1'],  alpha1,  beta1)
-            self.assertEqual(vector['SUM1'], sum1.hex())            
+            self.assertEqual(vector['SUM1'], sum1)
 
             # sum2 = A2.B2 + alpha2 + beta2
+            sum2 = mpc.mpc_sum_mta(vector['A2'], vector['B2'],  alpha2,  beta2)
+
+            self.assertEqual(vector['SUM2'], sum2)
 
-            sum2 = amcl_mpc.mpc_sum_mta(test['A2'], test['B2'],  alpha2,  beta2)
-            self.assertEqual(vector['SUM2'], sum2.hex())            
-            
             # Calculate the inverse of kgamma
+            invkgamma= mpc.mpc_invkgamma(sum1, sum2)
 
-            invkgamma= amcl_mpc.mpc_invkgamma(sum1, sum2)
-            self.assertEqual(vector['INVKGAMMA'], invkgamma.hex())                        
+            self.assertEqual(vector['INVKGAMMA'], invkgamma)
 
             # Calculate the R signature component
+            rc, sig_r, _ = mpc.mpc_r(invkgamma, vector['GAMMAPT1'], vector['GAMMAPT2'])
+
+            self.assertEqual(vector['SIG_R'], sig_r)
+            self.assertEqual(rc, 0)
+
 
-            rc, sig_r, _ = amcl_mpc.mpc_r(invkgamma, test['GAMMAPT1'], test['GAMMAPT2'])
-            self.assertEqual(vector['SIG_R'], sig_r.hex())
-            self.assertEqual(rc, 0)            
-            
 if __name__ == '__main__':
     # Run tests
     unittest.main()
diff --git a/python/test_s.py b/python/test_s.py
index 79fa928..ed07453 100755
--- a/python/test_s.py
+++ b/python/test_s.py
@@ -18,81 +18,78 @@ KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 """
+
 import unittest
 import json
-import amcl_mpc
+from amcl import mpc
 
 
 class TestS(unittest.TestCase):
     """Tests MPC S"""
 
     def setUp(self):
-        seed_hex = "78d0fb6705ce77dee47d03eb5b9c5d30"
-        seed = bytes.fromhex(seed_hex)
-        self.rng = amcl_mpc.create_csprng(seed)
+        with open("S.json", "r") as f:
+            self.tv = json.load(f)
+
+        for vector in self.tv:
+            for key, val in vector.items():
+                if key != "TEST":
+                    vector[key] = bytes.fromhex(val)
 
     def test_1(self):
         """test_1 Test Vector test"""
-        with open("S.json", "r") as f:
-            vectors = json.load(f)
-        for vector in vectors:
+
+        for vector in self.tv:
             print(f"Test vector {vector['TEST']}")
-            test = {}
-            for key, val in vector.items():
-                if key != "TEST":
-                    #print(f"{key} = {val}\n")
-                    test[key] = bytes.fromhex(val)
-            PUB1, PRIV1 = amcl_mpc.paillier_key_pair(self.rng, test['P1'], test['Q1'])
-            PUB2, PRIV2 = amcl_mpc.paillier_key_pair(self.rng, test['P2'], test['Q2'])            
+
+            PUB1, PRIV1 = mpc.paillier_key_pair(None, vector['P1'], vector['Q1'])
+            PUB2, PRIV2 = mpc.paillier_key_pair(None, vector['P2'], vector['Q2'])
 
             # ALPHA1 + BETA2 = K1 * W2
-            ca11 = amcl_mpc.mpc_mta_client1(self.rng, PUB1, test['K1'], test['R11'])
-            cb12, beta2 = amcl_mpc.mpc_mta_server(self.rng, PUB1, test['W2'], ca11, test['Z12'], test['R12'])
-            alpha1 = amcl_mpc.mpc_mta_client2(PRIV1, cb12)
-            
-            self.assertEqual(vector['ALPHA1'], alpha1.hex())
-            self.assertEqual(vector['BETA2'], beta2.hex())             
+            ca11 = mpc.mpc_mta_client1(None, PUB1, vector['K1'], vector['R11'])
+            cb12, beta2 = mpc.mpc_mta_server(None, PUB1, vector['W2'], ca11, vector['Z12'], vector['R12'])
+            alpha1 = mpc.mpc_mta_client2(PRIV1, cb12)
+
+            self.assertEqual(vector['ALPHA1'], alpha1)
+            self.assertEqual(vector['BETA2'], beta2)
 
             # ALPHA2 + BETA1 = K2 * W1
-            ca22 = amcl_mpc.mpc_mta_client1(self.rng, PUB2, test['K2'], test['R22'])
-            cb21, beta1 = amcl_mpc.mpc_mta_server(self.rng, PUB2, test['W1'], ca22, test['Z21'], test['R21'])
-            alpha2 = amcl_mpc.mpc_mta_client2(PRIV2, cb21)
-            
-            self.assertEqual(vector['ALPHA2'], alpha2.hex())
-            self.assertEqual(vector['BETA1'], beta1.hex())             
+            ca22 = mpc.mpc_mta_client1(None, PUB2, vector['K2'], vector['R22'])
+            cb21, beta1 = mpc.mpc_mta_server(None, PUB2, vector['W1'], ca22, vector['Z21'], vector['R21'])
+            alpha2 = mpc.mpc_mta_client2(PRIV2, cb21)
+
+            self.assertEqual(vector['ALPHA2'], alpha2)
+            self.assertEqual(vector['BETA1'], beta1)
 
             # sum1 = K1.W1 + alpha1 + beta1
+            SUM1 = mpc.mpc_sum_mta(vector['K1'], vector['W1'],  alpha1,  beta1)
 
-            SUM1 = amcl_mpc.mpc_sum_mta(test['K1'], test['W1'],  alpha1,  beta1)
-            self.assertEqual(vector['SUM1'], SUM1.hex())            
+            self.assertEqual(vector['SUM1'], SUM1)
 
             # sum2 = K2.W2 + alpha2 + beta2
+            SUM2 = mpc.mpc_sum_mta(vector['K2'], vector['W2'],  alpha2,  beta2)
 
-            SUM2 = amcl_mpc.mpc_sum_mta(test['K2'], test['W2'],  alpha2,  beta2)
-            self.assertEqual(vector['SUM2'], SUM2.hex())            
+            self.assertEqual(vector['SUM2'], SUM2)
 
             # Calculate the message hash
-    
-            HM = amcl_mpc.mpc_hash(test['M'])
+            HM = mpc.mpc_hash(vector['M'])
 
             # Calculate the S1 signature component
-
-            rc, SIG_S1 = amcl_mpc.mpc_s(HM, test['SIG_R'], test['K1'], SUM1)
-            self.assertEqual(vector['SIG_S1'], SIG_S1.hex())
-            self.assertEqual(rc, 0)            
+            rc, SIG_S1 = mpc.mpc_s(HM, vector['SIG_R'], vector['K1'], SUM1)
+            self.assertEqual(vector['SIG_S1'], SIG_S1)
+            self.assertEqual(rc, 0)
 
             # Calculate the S2 signature component
-
-            rc, SIG_S2 = amcl_mpc.mpc_s(HM, test['SIG_R'], test['K2'], SUM2)
-            self.assertEqual(vector['SIG_S2'], SIG_S2.hex())
-            self.assertEqual(rc, 0)            
+            rc, SIG_S2 = mpc.mpc_s(HM, vector['SIG_R'], vector['K2'], SUM2)
+            self.assertEqual(vector['SIG_S2'], SIG_S2)
+            self.assertEqual(rc, 0)
 
             # Sum S signature component
+            SIG_S = mpc.mpc_sum_s(SIG_S1, SIG_S2)
+            self.assertEqual(vector['SIG_S'], SIG_S)
+            self.assertEqual(rc, 0)
+
 
-            SIG_S = amcl_mpc.mpc_sum_s(SIG_S1, SIG_S2)
-            self.assertEqual(vector['SIG_S'], SIG_S.hex())
-            self.assertEqual(rc, 0)            
-            
 if __name__ == '__main__':
     # Run tests
     unittest.main()
diff --git a/python/test_schnorr.py b/python/test_schnorr.py
index 1392acb..e6b1b84 100755
--- a/python/test_schnorr.py
+++ b/python/test_schnorr.py
@@ -21,7 +21,7 @@ under the License.
 
 import unittest
 import json
-import amcl_schnorr
+from amcl import schnorr
 
 
 class TestCommit(unittest.TestCase):
@@ -31,7 +31,7 @@ class TestCommit(unittest.TestCase):
         # Deterministic PRNG for testing purposes
         seed_hex = "78d0fb6705ce77dee47d03eb5b9c5d30"
         seed = bytes.fromhex(seed_hex)
-        self.rng = amcl_schnorr.create_csprng(seed)
+        self.rng = schnorr.create_csprng(seed)
 
         r_hex = "e8a04212cc20520429d854a5bb02b51b4281e663c90a4a4ec0b505171f9bc26a"
         C_hex = "028fe6cafe6e6cef6c47be31cb449faa9495d22a6cb47e057b91c97d807882c439"
@@ -48,7 +48,7 @@ class TestCommit(unittest.TestCase):
             r_golden = bytes.fromhex(vector["R"])
             C_golden = bytes.fromhex(vector["C"])
 
-            r, C = amcl_schnorr.commit(None, r_golden)
+            r, C = schnorr.commit(None, r_golden)
 
             self.assertEqual(r, r_golden)
             self.assertEqual(C, C_golden)
@@ -56,7 +56,7 @@ class TestCommit(unittest.TestCase):
     def test_random(self):
         """ Test using pseudo random r """
 
-        r, C = amcl_schnorr.commit(self.rng)
+        r, C = schnorr.commit(self.rng)
 
         self.assertEqual(r, self.r_golden)
         self.assertEqual(C, self.C_golden)
@@ -78,7 +78,7 @@ class TestChallenge(unittest.TestCase):
 
             e_golden = bytes.fromhex(vector["E"])
 
-            e = amcl_schnorr.challenge(V, C)
+            e = schnorr.challenge(V, C)
 
             self.assertEqual(e, e_golden)
 
@@ -100,7 +100,7 @@ class TestProve(unittest.TestCase):
 
             p_golden = bytes.fromhex(vector["P"])
 
-            p = amcl_schnorr.prove(r, e, x)
+            p = schnorr.prove(r, e, x)
 
             self.assertEqual(p, p_golden)
 
@@ -121,9 +121,9 @@ class TestVerify(unittest.TestCase):
             e = bytes.fromhex(vector["E"])
             p = bytes.fromhex(vector["P"])
 
-            ec = amcl_schnorr.verify(V, C, e, p)
+            ec = schnorr.verify(V, C, e, p)
 
-            self.assertEqual(ec, amcl_schnorr.OK)
+            self.assertEqual(ec, schnorr.OK)
 
     def test_error_code(self):
         """ Test error codes are propagated """
@@ -135,9 +135,9 @@ class TestVerify(unittest.TestCase):
         e = bytes.fromhex(vector["E"])
         p = bytes.fromhex(vector["P"])
 
-        ec = amcl_schnorr.verify(V, C, e, p)
+        ec = schnorr.verify(V, C, e, p)
 
-        self.assertEqual(ec, amcl_schnorr.FAIL)
+        self.assertEqual(ec, schnorr.FAIL)
 
 
 if __name__ == '__main__':


[incubator-milagro-MPC] 05/06: Refactor benchmarks

Posted by sa...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sandreoli pushed a commit to branch issue7-schnorr-python-wrapper
in repository https://gitbox.apache.org/repos/asf/incubator-milagro-MPC.git

commit 33ea100ab5236329bc463ff8eed34dffc7b18f1c
Author: Samuele Andreoli <sa...@yahoo.it>
AuthorDate: Tue Feb 18 14:04:05 2020 +0000

    Refactor benchmarks
---
 python/CMakeLists.txt                           |  1 +
 python/README.md                                | 45 ++++++++++++++-
 python/{ => benchmark}/CMakeLists.txt           |  9 +--
 python/benchmark/bench.py                       | 62 +++++++++++++++++++++
 python/{bench_mpc.py => benchmark/bench_mta.py} | 73 +++++++------------------
 python/benchmark/bench_schnorr.py               | 53 ++++++++++++++++++
 python/benchmark/context.py                     | 25 +++++++++
 7 files changed, 206 insertions(+), 62 deletions(-)

diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt
index d7ed21c..5971f47 100644
--- a/python/CMakeLists.txt
+++ b/python/CMakeLists.txt
@@ -20,3 +20,4 @@ include(PythonSiteDirs)
 add_subdirectory(amcl)
 add_subdirectory(test)
 add_subdirectory(examples)
+add_subdirectory(benchmark)
diff --git a/python/README.md b/python/README.md
index 8489444..1075b2d 100644
--- a/python/README.md
+++ b/python/README.md
@@ -2,8 +2,49 @@
 
 This directory contains the C code wrapper for Python.
 
-After installation to run an example
+## Tests
 
+### Automatic run
+
+The simplest way to run the wrapper tests is using the Makefile
+in the build directory or in the python build directory
+
+```sh
+make test
+```
+
+### Manual run
+
+Individual tests can be executed after installation using
+
+```sh
+./test_mta.py
+```
+
+To run individual tests manually before installation add
+the build `src` directory to your system dynamic library path.
+
+e.g. for Linux
+
+```sh
+export LD_LIBRARY_PATH=<build_dir>/src/:$LD_LIBRARY_PATH
 ```
+
+## Benchmark and examples
+
+Individual benchmarks or examples can be executed after
+installation using
+
+```sh
 ./example_ecdsa.py
-```
\ No newline at end of file
+```
+
+To run individual benchmarks and examples manually before
+installation add the build `src` directory to your system
+dynamic library path.
+
+e.g. for Linux
+
+```sh
+export LD_LIBRARY_PATH=<build_dir>/src/:$LD_LIBRARY_PATH
+```
diff --git a/python/CMakeLists.txt b/python/benchmark/CMakeLists.txt
similarity index 84%
copy from python/CMakeLists.txt
copy to python/benchmark/CMakeLists.txt
index d7ed21c..8a39633 100644
--- a/python/CMakeLists.txt
+++ b/python/benchmark/CMakeLists.txt
@@ -13,10 +13,5 @@
 # License for the specific language governing permissions and limitations under
 # the License.
 
-cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
-
-include(PythonSiteDirs)
-
-add_subdirectory(amcl)
-add_subdirectory(test)
-add_subdirectory(examples)
+file(GLOB BENCH *.py)
+file(COPY ${BENCH} DESTINATION "${PROJECT_BINARY_DIR}/python/benchmark")
diff --git a/python/benchmark/bench.py b/python/benchmark/bench.py
new file mode 100644
index 0000000..43ed625
--- /dev/null
+++ b/python/benchmark/bench.py
@@ -0,0 +1,62 @@
+"""
+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 time
+
+multipliers = {
+    "ms": 1000,
+    "us": 1000000
+}
+
+def time_func(stmt, fncall, minIter=10, minTime=1, unit="ms"):
+    """Benchmark a function
+
+    Benchmark fncall(). It iterates until minIter or minTime is reached.
+    The results are printed using the specified time unit
+
+    Args::
+
+        stmt    : name of the benchmarked function
+        fncall  : function call initialized with the functools partial
+        minIter : minimum number of iterations to run, regardless of time spent
+        minTime : minimum number of time to spend, regardless of iterations
+        unit    : "ms" or "us", the time unit for the benchmark
+
+    Returns::
+
+    Raises::
+        KeyError
+    """
+
+    unit_multiplier = multipliers[unit]
+
+    total_time = 0
+    nIter = 0
+
+    while nIter < minIter or total_time < minTime:
+        t = time.time()
+
+        fncall()
+
+        elapsed_time = time.time() - t
+        total_time = total_time + elapsed_time
+        nIter+=1
+
+    iter_time = (total_time * unit_multiplier) / nIter
+    print("func: {} \tnIter: {} \ttotal_time: {:.2f}s \titer_time: {:.2f}{}".format(stmt, nIter, total_time, iter_time, unit))
diff --git a/python/bench_mpc.py b/python/benchmark/bench_mta.py
similarity index 57%
rename from python/bench_mpc.py
rename to python/benchmark/bench_mta.py
index d246a1a..8ae292c 100755
--- a/python/bench_mpc.py
+++ b/python/benchmark/bench_mta.py
@@ -19,80 +19,37 @@ specific language governing permissions and limitations
 under the License.
 """
 
-import time
-import warnings
-from amcl import mpc
-
-warnings.filterwarnings("ignore")
-
-
-def time_func(stmt, fncall, n=10):
-    t = time.process_time()
-    for i in range(1,i):
-        fncall
-        total_time = time.process_time() - t
-        iter_time = total_time / n
-        iter_per_sec = n / total_time
-        print(f"func:{stmt} nIter:{n} total_time:{total_time} iter_time:{iter_time} iter_per_sec: {iter_per_sec}")
-
-
-nIter = 10
+from context import mpc
+from bench import time_func
 
 seed_hex = "78d0fb6705ce77dee47d03eb5b9c5d30"
 
 P_hex = "94f689d07ba20cf7c7ca7ccbed22ae6b40c426db74eaee4ce0ced2b6f52a5e136663f5f1ef379cdbb0c4fdd6e4074d6cff21082d4803d43d89e42fd8dfa82b135aa31a8844ffea25f255f956cbc1b9d8631d01baf1010d028a190b94ce40f3b72897e8196df19edf1ff62e6556f2701d52cef1442e3301db7608ecbdcca703db"
-
 Q_hex = "9a9ad73f246df853e129c589925fdad9df05606a61081e62e72be4fb33f6e5ec492cc734f28bfb71fbe2ba9a11e4c02e2c0d103a5cbb0a9d6402c07de63b1b995dd72ac8f29825d66923a088b421fb4d52b0b855d2f5dde2be9b0ca0cee6f7a94e5566735fe6cff1fcad3199602f88528d19aa8d0263adff8f5053c38254a2a3"
 
 a_hex = "0000000000000000000000000000000000000000000000000000000000000002"
-
 b_hex = "0000000000000000000000000000000000000000000000000000000000000003"
 
 if __name__ == "__main__":
-
     seed = bytes.fromhex(seed_hex)
     p = bytes.fromhex(P_hex)
     q = bytes.fromhex(Q_hex)
     a = bytes.fromhex(a_hex)
     b = bytes.fromhex(b_hex)
 
-    ai = int(a_hex, 16)
-    bi = int(b_hex, 16)
-    expected = ai * bi % mpc.curve_order
-
     # random number generator
     rng = mpc.create_csprng(seed)
 
+    # Generate quantities for benchmark
     paillier_pk, paillier_sk = mpc.paillier_key_pair(rng)
+    ca = mpc.mpc_mta_client1(rng, paillier_pk, a)
+    cb, beta = mpc.mpc_mta_server(rng, paillier_pk, b, ca)
+    alpha = mpc.mpc_mta_client2(paillier_sk, cb)
 
-    total_time=0
-    for i in range(1,nIter):
-        #t = time.process_time()
-        t = time.time()
-        ca = mpc.mpc_mta_client1(rng, paillier_pk, a)
-        # elapsed_time = time.process_time() - t
-        elapsed_time = time.time() - t
-        total_time = total_time + elapsed_time
-    iter_time = int ((total_time * 1000) / nIter)
-    print(f"mpc_mta_client1 iteractions: {nIter} total_time: {total_time} iter_time: {iter_time}")
-
-    total_time=0
-    for i in range(1,nIter):
-        t = time.time()
-        cb, beta = mpc.mpc_mta_server(rng, paillier_pk, b, ca)
-        elapsed_time = time.time() - t
-        total_time = total_time + elapsed_time
-    iter_time = int ((total_time * 1000) / nIter)
-    print(f"mpc_mta_server iteractions: {nIter} total_time: {total_time} iter_time: {iter_time}")
-
-    total_time=0
-    for i in range(1,nIter):
-        t = time.time()
-        alpha = mpc.mpc_mta_client2(paillier_sk, cb)
-        elapsed_time = time.time() - t
-        total_time = total_time + elapsed_time
-    iter_time = int ((total_time * 1000) / nIter)
-    print(f"mpc_mta_client2 iteractions: {nIter} total_time: {total_time} iter_time: {iter_time}")
+    # Check consistency of the generated quantities
+    ai = int(a_hex, 16)
+    bi = int(b_hex, 16)
+    expected = ai * bi % mpc.curve_order
 
     alphai = int(alpha.hex(), 16)
     betai = int(beta.hex(), 16)
@@ -100,5 +57,15 @@ if __name__ == "__main__":
 
     assert got == expected, f"expected {hex(expected)} got {hex(got)}"
 
+    # Run benchmark
+    fncall = lambda: mpc.mpc_mta_client1(rng, paillier_pk, a)
+    time_func("mpc_mta_client1", fncall)
+
+    fncall = lambda: mpc.mpc_mta_server(rng, paillier_pk, b, ca)
+    time_func("mpc_mta_server ", fncall)
+
+    fncall = lambda: mpc.mpc_mta_client2(paillier_sk, cb)
+    time_func("mpc_mta_client2", fncall)
+
     # Clear memory
     mpc.kill_csprng(rng)
diff --git a/python/benchmark/bench_schnorr.py b/python/benchmark/bench_schnorr.py
new file mode 100755
index 0000000..ab0d2af
--- /dev/null
+++ b/python/benchmark/bench_schnorr.py
@@ -0,0 +1,53 @@
+#!/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.
+"""
+
+from context import schnorr
+from bench import time_func
+
+r_hex = "803ccd21cddad626e15f21b1ad787949e9beef08e6e68a9e00df59dec16ed290"
+x_hex = "fab4ce512dff74bd9c71c89a14de5b877af45dca0329ee3fcb72611c0784fef3"
+V_hex = "032cf4b348c9d00718f01ed98923e164df53b5e8bc4c2250662ed2df784e1784f4"
+
+if __name__ == "__main__":
+    r = bytes.fromhex(r_hex)
+    x = bytes.fromhex(x_hex)
+    V = bytes.fromhex(V_hex)
+
+    # Generate quantities for benchmark
+    r, C = schnorr.commit(None, r)
+    e = schnorr.challenge(V, C)
+    p = schnorr.prove(r, e, x)
+
+    # Check consistency of the generated quantities
+    assert schnorr.verify(V, C, e, p) == schnorr.OK
+
+    # Run benchmark
+    fncall = lambda: schnorr.commit(None, r)
+    time_func("commit   ", fncall, unit="us")
+
+    fncall = lambda: schnorr.challenge(V, C)
+    time_func("challenge", fncall, unit="us")
+
+    fncall = lambda: schnorr.prove(r, e, x)
+    time_func("prove    ", fncall, unit="us")
+
+    fncall = lambda: schnorr.verify(V, C, e, p)
+    time_func("verify   ", fncall, unit="us")
diff --git a/python/benchmark/context.py b/python/benchmark/context.py
new file mode 100644
index 0000000..c7a9ac2
--- /dev/null
+++ b/python/benchmark/context.py
@@ -0,0 +1,25 @@
+"""
+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 mpc, schnorr


[incubator-milagro-MPC] 03/06: Refactor tests

Posted by sa...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sandreoli pushed a commit to branch issue7-schnorr-python-wrapper
in repository https://gitbox.apache.org/repos/asf/incubator-milagro-MPC.git

commit 25e11170b886b97338bb590641cee9085b6e8034
Author: Samuele Andreoli <sa...@yahoo.it>
AuthorDate: Tue Feb 18 14:03:07 2020 +0000

    Refactor tests
---
 Dockerfile                        |  2 +-
 python/CMakeLists.txt             | 35 +-------------------------
 python/amcl/CMakeLists.txt        |  2 +-
 python/test/CMakeLists.txt        | 53 +++++++++++++++++++++++++++++++++++++++
 python/test/context.py            | 25 ++++++++++++++++++
 python/{ => test}/test_ecdsa.py   |  3 ++-
 python/{ => test}/test_mta.py     |  5 ++--
 python/{ => test}/test_r.py       |  4 +--
 python/{ => test}/test_s.py       |  4 +--
 python/{ => test}/test_schnorr.py |  2 +-
 10 files changed, 91 insertions(+), 44 deletions(-)

diff --git a/Dockerfile b/Dockerfile
index fb02245..465d617 100755
--- a/Dockerfile
+++ b/Dockerfile
@@ -26,7 +26,7 @@
 
 FROM ubuntu:bionic
 
-MAINTAINER kealanmccusker@gmail.com
+LABEL maintainer="kealanmccusker@gmail.com"
 
 WORKDIR /root
 
diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt
index c53f313..55b719c 100644
--- a/python/CMakeLists.txt
+++ b/python/CMakeLists.txt
@@ -18,37 +18,4 @@ cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
 include(PythonSiteDirs)
 
 add_subdirectory(amcl)
-
-file(COPY test_mta.py     DESTINATION "${PROJECT_BINARY_DIR}/python/")
-file(COPY test_r.py       DESTINATION "${PROJECT_BINARY_DIR}/python/")
-file(COPY test_s.py       DESTINATION "${PROJECT_BINARY_DIR}/python/")
-file(COPY test_ecdsa.py   DESTINATION "${PROJECT_BINARY_DIR}/python/")
-file(COPY test_schnorr.py DESTINATION "${PROJECT_BINARY_DIR}/python/")
-
-file(COPY "${PROJECT_SOURCE_DIR}/testVectors/mpc/MTA.json" DESTINATION "${PROJECT_BINARY_DIR}/python/")
-file(COPY "${PROJECT_SOURCE_DIR}/testVectors/mpc/R.json"   DESTINATION "${PROJECT_BINARY_DIR}/python/")
-file(COPY "${PROJECT_SOURCE_DIR}/testVectors/mpc/S.json"   DESTINATION "${PROJECT_BINARY_DIR}/python/")
-
-file(GLOB SCHNORR_TV "${PROJECT_SOURCE_DIR}/testVectors/schnorr/*.json")
-file(COPY ${SCHNORR_TV} DESTINATION "${PROJECT_BINARY_DIR}/python/schnorr/")
-
-if(NOT CMAKE_BUILD_TYPE STREQUAL "ASan")
-  add_test(test_python_mpc_mta     python3 test_mta.py)
-  add_test(test_python_mpc_r       python3 test_r.py)
-  add_test(test_python_mpc_s       python3 test_s.py)
-  add_test(test_python_mpc_ecdsa   python3 test_ecdsa.py)
-  add_test(test_python_mpc_schnorr python3 test_schnorr.py)
-endif(NOT CMAKE_BUILD_TYPE STREQUAL "ASan")
-
-# Set the LD_LIBRARY_PATH or equivalent to the libraries can be loaded when
-# running the test.
-#if(CMAKE_SYSTEM_NAME MATCHES "Darwin")
-#  set(ld_library_path_var "DYLD_LIBRARY_PATH")
-#elseif(CMAKE_SYSTEM_NAME MATCHES "Linux")
-#  set(ld_library_path_var "LD_LIBRARY_PATH")
-#elseif(CMAKE_SYSTEM_NAME MATCHES "Windows")
-#  set(ld_library_path_var "PATH")
-#endif()
-#set_tests_properties(test_python_mpc_mta PROPERTIES ENVIRONMENT
-#             "${ld_library_path_var}=${CMAKE_LIBRARY_OUTPUT_DIRECTORY}")
-
+add_subdirectory(test)
diff --git a/python/amcl/CMakeLists.txt b/python/amcl/CMakeLists.txt
index b92ebd8..ca45bda 100644
--- a/python/amcl/CMakeLists.txt
+++ b/python/amcl/CMakeLists.txt
@@ -16,4 +16,4 @@
 file(GLOB SRCS *.py)
 file(COPY ${SRCS} DESTINATION "${PROJECT_BINARY_DIR}/python/amcl")
 
-install(FILES ${SRCS} DESTINATION ${PYTHON_SITE_PACKAGES}/amcl) 
+install(FILES ${SRCS} DESTINATION ${PYTHON_SITE_PACKAGES}/amcl)
diff --git a/python/test/CMakeLists.txt b/python/test/CMakeLists.txt
new file mode 100644
index 0000000..a01ddf4
--- /dev/null
+++ b/python/test/CMakeLists.txt
@@ -0,0 +1,53 @@
+# 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.
+
+# Set the LD_LIBRARY_PATH or equivalent to the libraries can be loaded when
+# running the test.
+if(CMAKE_SYSTEM_NAME MATCHES "Darwin")
+  set(ld_library_path_var "DYLD_LIBRARY_PATH")
+elseif(CMAKE_SYSTEM_NAME MATCHES "Linux")
+  set(ld_library_path_var "LD_LIBRARY_PATH")
+elseif(CMAKE_SYSTEM_NAME MATCHES "Windows")
+  set(ld_library_path_var "PATH")
+endif()
+
+# Prepend the env dynamic library path with the mpc path
+set(dynamic_library_path ${PROJECT_BINARY_DIR}/src:$ENV{${ld_library_path_var}})
+
+function(add_python_test name source)
+  add_test(${name} python3 ${source})
+
+  set_tests_properties(${name} PROPERTIES ENVIRONMENT "${ld_library_path_var}=${dynamic_library_path}")
+endfunction()
+
+# Tests
+file(GLOB TESTS *.py)
+file(COPY ${TESTS} DESTINATION "${PROJECT_BINARY_DIR}/python/test")
+
+# MPC test vectors
+file(GLOB MPC_TV "${PROJECT_SOURCE_DIR}/testVectors/mpc/*.json")
+file(COPY ${MPC_TV} DESTINATION "${PROJECT_BINARY_DIR}/python/test/mpc/")
+
+# Schnorr test vectors
+file(GLOB SCHNORR_TV "${PROJECT_SOURCE_DIR}/testVectors/schnorr/*.json")
+file(COPY ${SCHNORR_TV} DESTINATION "${PROJECT_BINARY_DIR}/python/test/schnorr/")
+
+if(NOT CMAKE_BUILD_TYPE STREQUAL "ASan")
+  add_python_test(test_python_mpc_mta     test_mta.py)
+  add_python_test(test_python_mpc_r       test_r.py)
+  add_python_test(test_python_mpc_s       test_s.py)
+  add_python_test(test_python_mpc_ecdsa   test_ecdsa.py)
+  add_python_test(test_python_mpc_schnorr test_schnorr.py)
+endif(NOT CMAKE_BUILD_TYPE STREQUAL "ASan")
diff --git a/python/test/context.py b/python/test/context.py
new file mode 100644
index 0000000..c7a9ac2
--- /dev/null
+++ b/python/test/context.py
@@ -0,0 +1,25 @@
+"""
+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 mpc, schnorr
diff --git a/python/test_ecdsa.py b/python/test/test_ecdsa.py
similarity index 99%
rename from python/test_ecdsa.py
rename to python/test/test_ecdsa.py
index 1c60bfd..8a118be 100755
--- a/python/test_ecdsa.py
+++ b/python/test/test_ecdsa.py
@@ -18,10 +18,11 @@ KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 """
+
 import unittest
 import json
 import os
-from amcl import mpc
+from context import mpc
 
 
 class TestECDSA(unittest.TestCase):
diff --git a/python/test_mta.py b/python/test/test_mta.py
similarity index 96%
rename from python/test_mta.py
rename to python/test/test_mta.py
index 8a74971..dea53ae 100755
--- a/python/test_mta.py
+++ b/python/test/test_mta.py
@@ -18,16 +18,17 @@ KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 """
+
 import unittest
 import json
-from amcl import mpc
+from context import mpc
 
 
 class TestMtA(unittest.TestCase):
     """Tests MPC MtA"""
 
     def setUp(self):
-        with open("MTA.json", "r") as f:
+        with open("mpc/MTA.json", "r") as f:
             self.tv = json.load(f)
 
         for vector in self.tv:
diff --git a/python/test_r.py b/python/test/test_r.py
similarity index 97%
rename from python/test_r.py
rename to python/test/test_r.py
index 2b53ca6..0a8034d 100755
--- a/python/test_r.py
+++ b/python/test/test_r.py
@@ -21,14 +21,14 @@ under the License.
 
 import unittest
 import json
-from amcl import mpc
+from context import mpc
 
 
 class TestR(unittest.TestCase):
     """Tests MPC R"""
 
     def setUp(self):
-        with open("R.json", "r") as f:
+        with open("mpc/R.json", "r") as f:
             self.tv = json.load(f)
 
         for vector in self.tv:
diff --git a/python/test_s.py b/python/test/test_s.py
similarity index 98%
rename from python/test_s.py
rename to python/test/test_s.py
index ed07453..526e7fb 100755
--- a/python/test_s.py
+++ b/python/test/test_s.py
@@ -21,14 +21,14 @@ under the License.
 
 import unittest
 import json
-from amcl import mpc
+from context import mpc
 
 
 class TestS(unittest.TestCase):
     """Tests MPC S"""
 
     def setUp(self):
-        with open("S.json", "r") as f:
+        with open("mpc/S.json", "r") as f:
             self.tv = json.load(f)
 
         for vector in self.tv:
diff --git a/python/test_schnorr.py b/python/test/test_schnorr.py
similarity index 99%
rename from python/test_schnorr.py
rename to python/test/test_schnorr.py
index e6b1b84..a232ac5 100755
--- a/python/test_schnorr.py
+++ b/python/test/test_schnorr.py
@@ -21,7 +21,7 @@ under the License.
 
 import unittest
 import json
-from amcl import schnorr
+from context import schnorr
 
 
 class TestCommit(unittest.TestCase):