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/19 16:05:35 UTC

[incubator-milagro-MPC] 04/04: Add zk factoring wrapper, test, benchmark and example

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

sandreoli pushed a commit to branch issue9-factoring-zkp-wrapper
in repository https://gitbox.apache.org/repos/asf/incubator-milagro-MPC.git

commit 2cab46cceff5cd8e6f4fbed37cf99c538bb502af
Author: Samuele Andreoli <sa...@yahoo.it>
AuthorDate: Wed Feb 19 16:04:57 2020 +0000

    Add zk factoring wrapper, test, benchmark and example
---
 python/amcl/factoring_zk.py             | 120 ++++++++++++++++++++++++++++++++
 python/amcl/schnorr.py                  |   1 -
 python/benchmark/bench_zk_factoring.py  |  49 +++++++++++++
 python/examples/example_zk_factoring.py |  63 +++++++++++++++++
 python/test/CMakeLists.txt              |  17 +++--
 python/test/test_zk_factoring.py        | 103 +++++++++++++++++++++++++++
 6 files changed, 346 insertions(+), 7 deletions(-)

diff --git a/python/amcl/factoring_zk.py b/python/amcl/factoring_zk.py
new file mode 100644
index 0000000..a2a895e
--- /dev/null
+++ b/python/amcl/factoring_zk.py
@@ -0,0 +1,120 @@
+"""
+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 platform
+from amcl import core_utils
+
+_ffi = core_utils._ffi
+_ffi.cdef("""
+void FACTORING_ZK_prove(csprng *RNG, octet *P, octet *Q, octet *R, octet *E, octet *Y);
+int FACTORING_ZK_verify(octet *N, octet *E, octet *Y);
+""")
+
+if (platform.system() == 'Windows'):
+    _libamcl_mpc = _ffi.dlopen("libamcl_mpc.dll")
+    _libamcl_paillier = _ffi.dlopen("libamcl_paillier.dll")
+elif (platform.system() == 'Darwin'):
+    _libamcl_mpc = _ffi.dlopen("libamcl_mpc.dylib")
+    _libamcl_paillier = _ffi.dlopen("libamcl_paillier.dylib")
+else:
+    _libamcl_mpc = _ffi.dlopen("libamcl_mpc.so")
+    _libamcl_paillier = _ffi.dlopen("libamcl_paillier.so")
+
+# Constants
+B        = 16  # Security parameter - 128 bit
+FS_2048  = 256 # Size in bytes of an FF_2048
+HFS_2048 = 128 # Half size in bytes of an FF_2048
+
+OK   = 0
+FAIL = 91
+
+
+def prove(rng, p, q, r=None):
+    """Generate factoring knowledge proof
+
+
+
+    Args::
+
+        rng : Pointer to cryptographically secure pseudo-random
+              number generator instance
+        p   : First prime factor of n. HFS_2048 bytes long
+        q   : Second prime factor of n. HFS_2048 bytes long
+        r   : Deterministic value for r. FS_2048 bytes long
+
+    Returns::
+
+        e : First component of the factoring proof. B bytes long
+        y : Second component of the factoring proof. FS_2048 bytes long
+
+    Raises:
+
+    """
+    if r is None:
+        r_oct = _ffi.NULL
+    else:
+        r_oct, r_val = core_utils.make_octet(None, r)
+        _ = r_val # Suppress warning
+        rng = _ffi.NULL
+
+    p_oct, p_val = core_utils.make_octet(None, p)
+    q_oct, q_val = core_utils.make_octet(None, q)
+    e_oct, e_val = core_utils.make_octet(B)
+    y_oct, y_val = core_utils.make_octet(FS_2048)
+    _ = p_val, q_val, e_val, y_val # Suppress warnings
+
+    _libamcl_mpc.FACTORING_ZK_prove(rng, p_oct, q_oct, r_oct, e_oct, y_oct)
+
+    # Clear memory
+    core_utils.clear_octet(p_oct)
+    core_utils.clear_octet(q_oct)
+
+    return core_utils.to_str(e_oct), core_utils.to_str(y_oct)
+
+
+def verify(n, e, y):
+    """Verify knowledge of factoring proof
+
+    Args::
+
+        n : public modulus
+        e : First component of the factoring proof. B bytes long
+        y : Second component of the factoring proof. FS_2048 bytes long
+
+    Returns::
+
+        rc : OK if the verification is successful or an error code
+
+    Raises:
+
+    """
+    n_oct, n_val = core_utils.make_octet(None, n)
+    e_oct, e_val = core_utils.make_octet(None, e)
+    y_oct, y_val = core_utils.make_octet(None, y)
+    _ = n_val, e_val, y_val # Suppress warning
+
+    rc = _libamcl_mpc.FACTORING_ZK_verify(n_oct, e_oct, y_oct)
+
+    return rc
diff --git a/python/amcl/schnorr.py b/python/amcl/schnorr.py
index ec556d4..126d38f 100644
--- a/python/amcl/schnorr.py
+++ b/python/amcl/schnorr.py
@@ -111,7 +111,6 @@ def commit(rng, r=None):
     C, C_val = core_utils.make_octet(PTS)
     _ = r_val, C_val # Suppress warning
 
-
     _libamcl_mpc.SCHNORR_commit(rng, r_oct, C)
 
     r = core_utils.to_str(r_oct)
diff --git a/python/benchmark/bench_zk_factoring.py b/python/benchmark/bench_zk_factoring.py
new file mode 100755
index 0000000..f9ab584
--- /dev/null
+++ b/python/benchmark/bench_zk_factoring.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python3
+
+"""
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+"""
+import os
+import sys
+from bench import time_func
+
+sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
+
+from amcl import factoring_zk
+
+p_hex = "e008507e09c24d756280f3d94912fb9ac16c0a8a1757ee01a350736acfc7f65880f87eca55d6680253383fc546d03fd9ebab7d8fa746455180888cb7c17edf58d3327296468e5ab736374bc9a0fa02606ed5d3a4a5fb1677891f87fbf3c655c3e0549a86b17b7ddce07c8f73e253105e59f5d3ed2c7ba5bdf8495df40ae71a7f"
+q_hex = "dbffe278edd44c2655714e5a4cc82e66e46063f9ab69df9d0ed20eb3d7f2d8c7d985df71c28707f32b961d160ca938e9cf909cd77c4f8c630aec34b67714cbfd4942d7147c509db131bc2d6a667eb30df146f64b710f8f5247848b0a75738a38772e31014fd63f0b769209928d586499616dcc90700b393156e12eea7e15a835"
+n_hex = "c0870b552afb6c8c09f79e39ad6ca17ca93085c2cd7a726ade69574961ff9ce8ad33c7dda2e0703a3b0010c2e5bb7552c74164ce8dd011d85e5969090df53fe10e39cbe530704da32ff07228a6b6da34a5929e8a231c3080d812dc6e93affd81682339a6aee192927c582da8941bebf46e13c4ea3918a1477951fa66d367e70d8551b1869316d48317e0702d7bce242a326000f3dc763c44eba2044a1df713a94c1339edd464b145dcadf94e6e61be73dc270c878e1a28be720df2209202d00e101c3b255b757eaf547acd863d51eb676b851511b3dadeda926714719dceddd3af7908893ae65f2b95ee5c4d36cc6862cbe [...]
+r_hex = "c05f6c79e81fab2f1aa6af48dc5afa89a21c0aee03e93944cacfefef1be90f41ec8c2055760beafa9ed87dd67dbd56b33a2568dfec62a03f06c4f8449a93eee858507f4b602bf305e1c9968d9f5b6dc3120c27e053a1d7e51590e0bacb8d36c27bccce1a57c1e3aeb0832905d4e2bb8eaee883b4df042d8660cf3e0c9777b6be34c18bef02347f92cb71f372f61c018860211932dd46de8f925212d7afe6dd2f3cda05f8d5a6bd1b138b66c5efd7fca31f926c721f6d4207b97fc01cdf325da21233f6df37adbcd67472b332f7490a4a96e0fef31beef55b9446067b8e8d807384e3d31051c7a1f27296a6ae111b30c3d1f [...]
+
+if __name__ == "__main__":
+    p = bytes.fromhex(p_hex)
+    q = bytes.fromhex(q_hex)
+    n = bytes.fromhex(n_hex)
+    r = bytes.fromhex(r_hex)
+
+    # Generate quantities for benchmark
+    e, y = factoring_zk.prove(None, p, q, r)
+    assert factoring_zk.verify(n, e, y) == factoring_zk.OK
+
+    # Run benchmark
+    fncall = lambda: factoring_zk.prove(None, p, q, r)
+    time_func("prove ", fncall)
+
+    fncall = lambda: factoring_zk.verify(n, e, y)
+    time_func("verify", fncall)
diff --git a/python/examples/example_zk_factoring.py b/python/examples/example_zk_factoring.py
new file mode 100755
index 0000000..08d6f6a
--- /dev/null
+++ b/python/examples/example_zk_factoring.py
@@ -0,0 +1,63 @@
+#!/usr/bin/env python3
+
+"""
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+"""
+
+import os
+import sys
+
+sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
+
+from amcl import core_utils, factoring_zk
+
+seed_hex = "78d0fb6705ce77dee47d03eb5b9c5d30"
+
+p_hex = "e008507e09c24d756280f3d94912fb9ac16c0a8a1757ee01a350736acfc7f65880f87eca55d6680253383fc546d03fd9ebab7d8fa746455180888cb7c17edf58d3327296468e5ab736374bc9a0fa02606ed5d3a4a5fb1677891f87fbf3c655c3e0549a86b17b7ddce07c8f73e253105e59f5d3ed2c7ba5bdf8495df40ae71a7f"
+q_hex = "dbffe278edd44c2655714e5a4cc82e66e46063f9ab69df9d0ed20eb3d7f2d8c7d985df71c28707f32b961d160ca938e9cf909cd77c4f8c630aec34b67714cbfd4942d7147c509db131bc2d6a667eb30df146f64b710f8f5247848b0a75738a38772e31014fd63f0b769209928d586499616dcc90700b393156e12eea7e15a835"
+n_hex = "c0870b552afb6c8c09f79e39ad6ca17ca93085c2cd7a726ade69574961ff9ce8ad33c7dda2e0703a3b0010c2e5bb7552c74164ce8dd011d85e5969090df53fe10e39cbe530704da32ff07228a6b6da34a5929e8a231c3080d812dc6e93affd81682339a6aee192927c582da8941bebf46e13c4ea3918a1477951fa66d367e70d8551b1869316d48317e0702d7bce242a326000f3dc763c44eba2044a1df713a94c1339edd464b145dcadf94e6e61be73dc270c878e1a28be720df2209202d00e101c3b255b757eaf547acd863d51eb676b851511b3dadeda926714719dceddd3af7908893ae65f2b95ee5c4d36cc6862cbe [...]
+
+if __name__ == "__main__":
+    seed = bytes.fromhex(seed_hex)
+    rng = core_utils.create_csprng(seed)
+
+    p = bytes.fromhex(p_hex)
+    q = bytes.fromhex(q_hex)
+    n = bytes.fromhex(n_hex)
+
+    print("Example ZK Proof of Knowledge of factoring")
+    print("Parameters")
+    print(f"\tP = {p.hex()}")
+    print(f"\tQ = {q.hex()}")
+    print(f"\tN = {n.hex()}")
+
+    # Prove
+    e, y = factoring_zk.prove(rng, p, q, None)
+
+    print("\nGenerate proof")
+    print(f"\tE = {e.hex()}")
+    print(f"\tY = {y.hex()}")
+
+    # Verify
+    ec = factoring_zk.verify(n, e, y)
+
+    print("\nVerify proof")
+    if ec == factoring_zk.OK:
+        print("\tSuccess")
+    else:
+        print("\tFailure")
diff --git a/python/test/CMakeLists.txt b/python/test/CMakeLists.txt
index b2fdbc7..4290634 100644
--- a/python/test/CMakeLists.txt
+++ b/python/test/CMakeLists.txt
@@ -49,11 +49,16 @@ file(
   COPY ${PROJECT_SOURCE_DIR}/testVectors/commitments/nm_commit.json
   DESTINATION "${PROJECT_BINARY_DIR}/python/test/commitments/")
 
+# ZK Factoring test vectors
+file(GLOB SCHNORR_TV "${PROJECT_SOURCE_DIR}/testVectors/factoring_zk/*.json")
+file(COPY ${SCHNORR_TV} DESTINATION "${PROJECT_BINARY_DIR}/python/test/factoring_zk/")
+
 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)
-  add_python_test(test_python_mpc_nm_commit test_nm_commit.py)
+  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)
+  add_python_test(test_python_mpc_nm_commit    test_nm_commit.py)
+  add_python_test(test_python_mpc_zk_factoring test_zk_factoring.py)
 endif(NOT CMAKE_BUILD_TYPE STREQUAL "ASan")
diff --git a/python/test/test_zk_factoring.py b/python/test/test_zk_factoring.py
new file mode 100755
index 0000000..e8ad703
--- /dev/null
+++ b/python/test/test_zk_factoring.py
@@ -0,0 +1,103 @@
+#!/usr/bin/env python3
+
+"""
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+"""
+
+import os
+import sys
+import json
+from unittest import TestCase
+
+sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
+
+from amcl import core_utils, factoring_zk
+
+seed_hex = "78d0fb6705ce77dee47d03eb5b9c5d30"
+
+p_hex = "e008507e09c24d756280f3d94912fb9ac16c0a8a1757ee01a350736acfc7f65880f87eca55d6680253383fc546d03fd9ebab7d8fa746455180888cb7c17edf58d3327296468e5ab736374bc9a0fa02606ed5d3a4a5fb1677891f87fbf3c655c3e0549a86b17b7ddce07c8f73e253105e59f5d3ed2c7ba5bdf8495df40ae71a7f"
+q_hex = "dbffe278edd44c2655714e5a4cc82e66e46063f9ab69df9d0ed20eb3d7f2d8c7d985df71c28707f32b961d160ca938e9cf909cd77c4f8c630aec34b67714cbfd4942d7147c509db131bc2d6a667eb30df146f64b710f8f5247848b0a75738a38772e31014fd63f0b769209928d586499616dcc90700b393156e12eea7e15a835"
+
+e_hex = "32c670610e73c428785944ab7b582371"
+y_hex = "b4ebebd6177b2eb04149aa463ede7ba2216657e3b4de42f496c0d493b4d734131e63edcde042d951b9bf285622b9d69e9ee170156deeb173725032a952068e68b18f69bd4e52677d48d846055988877ce9e97b962f01e3f425f3101a6a589f020c858b1ee5ae8f79e4c63ce2356d8a9aa703100b3b3588d0aae7d7857b672d1beb25afc90a93045837aca1c39511816d4fc84ad0db35edf9adac810c46965868e79a5eb9509f9d7c315c5439daf561b312c0dd276263464409aef75a65c157277ba0bcef2cb1929995ba6749a8c54187cf2a9cfc9febc40bee8b149973590f9d34ae8c79111792e92b5fcdbd993f6ce8ad1 [...]
+
+
+class TestProve(TestCase):
+    """ Test ZK factoring Prove """
+
+    def setUp(self):
+        # Deterministic PRNG for testing purposes
+        seed = bytes.fromhex(seed_hex)
+        self.rng = core_utils.create_csprng(seed)
+
+        self.p = bytes.fromhex(p_hex)
+        self.q = bytes.fromhex(q_hex)
+        self.e = bytes.fromhex(e_hex)
+        self.y = bytes.fromhex(y_hex)
+
+        with open("factoring_zk/prove.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_tv(self):
+        """ test using test vectors """
+
+        for vector in self.tv:
+            e, y = factoring_zk.prove(None, vector['P'], vector['Q'], vector['R'])
+
+            self.assertEqual(e, vector['E'])
+            self.assertEqual(y, vector['Y'])
+
+    def test_random(self):
+        """ test using PRNG """
+
+        e, y = factoring_zk.prove(self.rng, self.p, self.q)
+
+        self.assertEqual(e, self.e)
+        self.assertEqual(y, self.y)
+
+class TestVerify(TestCase):
+    """ Test ZK factoring Verify """
+
+    def setUp(self):
+        with open("factoring_zk/verify.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_tv(self):
+        """ test using test vectors """
+
+        for vector in self.tv:
+            ec = factoring_zk.verify(vector['N'], vector['E'], vector['Y'])
+
+            self.assertEqual(ec, factoring_zk.OK)
+
+    def test_failure(self):
+        """ Test error codes are propagated correctly """
+
+        ec = factoring_zk.verify(self.tv[0]['Y'], self.tv[0]['E'], self.tv[0]['N'])
+
+        self.assertEqual(ec, factoring_zk.FAIL)