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 <[email protected]> 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)
