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