Skip to content
This repository has been archived by the owner on Mar 25, 2024. It is now read-only.

Commit

Permalink
Add zk factoring wrapper, test, benchmark and example
Browse files Browse the repository at this point in the history
  • Loading branch information
samuele-andreoli committed Feb 20, 2020
1 parent c1e9389 commit b070e9e
Show file tree
Hide file tree
Showing 6 changed files with 346 additions and 7 deletions.
120 changes: 120 additions & 0 deletions 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
1 change: 0 additions & 1 deletion python/amcl/schnorr.py
Expand Up @@ -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)
Expand Down
49 changes: 49 additions & 0 deletions 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 = "c0870b552afb6c8c09f79e39ad6ca17ca93085c2cd7a726ade69574961ff9ce8ad33c7dda2e0703a3b0010c2e5bb7552c74164ce8dd011d85e5969090df53fe10e39cbe530704da32ff07228a6b6da34a5929e8a231c3080d812dc6e93affd81682339a6aee192927c582da8941bebf46e13c4ea3918a1477951fa66d367e70d8551b1869316d48317e0702d7bce242a326000f3dc763c44eba2044a1df713a94c1339edd464b145dcadf94e6e61be73dc270c878e1a28be720df2209202d00e101c3b255b757eaf547acd863d51eb676b851511b3dadeda926714719dceddd3af7908893ae65f2b95ee5c4d36cc6862cbe6886a62d7c1e2d0db48c399a6d44b"
r_hex = "c05f6c79e81fab2f1aa6af48dc5afa89a21c0aee03e93944cacfefef1be90f41ec8c2055760beafa9ed87dd67dbd56b33a2568dfec62a03f06c4f8449a93eee858507f4b602bf305e1c9968d9f5b6dc3120c27e053a1d7e51590e0bacb8d36c27bccce1a57c1e3aeb0832905d4e2bb8eaee883b4df042d8660cf3e0c9777b6be34c18bef02347f92cb71f372f61c018860211932dd46de8f925212d7afe6dd2f3cda05f8d5a6bd1b138b66c5efd7fca31f926c721f6d4207b97fc01cdf325da21233f6df37adbcd67472b332f7490a4a96e0fef31beef55b9446067b8e8d807384e3d31051c7a1f27296a6ae111b30c3d1f3f81666fd9ad99df531bb68428029"

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)
63 changes: 63 additions & 0 deletions 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 = "c0870b552afb6c8c09f79e39ad6ca17ca93085c2cd7a726ade69574961ff9ce8ad33c7dda2e0703a3b0010c2e5bb7552c74164ce8dd011d85e5969090df53fe10e39cbe530704da32ff07228a6b6da34a5929e8a231c3080d812dc6e93affd81682339a6aee192927c582da8941bebf46e13c4ea3918a1477951fa66d367e70d8551b1869316d48317e0702d7bce242a326000f3dc763c44eba2044a1df713a94c1339edd464b145dcadf94e6e61be73dc270c878e1a28be720df2209202d00e101c3b255b757eaf547acd863d51eb676b851511b3dadeda926714719dceddd3af7908893ae65f2b95ee5c4d36cc6862cbe6886a62d7c1e2d0db48c399a6d44b"

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")
17 changes: 11 additions & 6 deletions python/test/CMakeLists.txt
Expand Up @@ -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")
103 changes: 103 additions & 0 deletions 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 = "b4ebebd6177b2eb04149aa463ede7ba2216657e3b4de42f496c0d493b4d734131e63edcde042d951b9bf285622b9d69e9ee170156deeb173725032a952068e68b18f69bd4e52677d48d846055988877ce9e97b962f01e3f425f3101a6a589f020c858b1ee5ae8f79e4c63ce2356d8a9aa703100b3b3588d0aae7d7857b672d1beb25afc90a93045837aca1c39511816d4fc84ad0db35edf9adac810c46965868e79a5eb9509f9d7c315c5439daf561b312c0dd276263464409aef75a65c157277ba0bcef2cb1929995ba6749a8c54187cf2a9cfc9febc40bee8b149973590f9d34ae8c79111792e92b5fcdbd993f6ce8ad1558f5f8e691c3ce2ca9b2c15f599c"


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)

0 comments on commit b070e9e

Please sign in to comment.