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:31 UTC

[incubator-milagro-MPC] branch issue9-factoring-zkp-wrapper created (now 2cab46c)

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

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


      at 2cab46c  Add zk factoring wrapper, test, benchmark and example

This branch includes the following new commits:

     new 52621af  Add NM commit wrappers with test, benchmark and example
     new 4a97005  format code
     new 69d616f  use octets in factoring zk API
     new 2cab46c  Add zk factoring wrapper, test, benchmark and example

The 4 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] 03/04: use octets in factoring zk API

Posted by sa...@apache.org.
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 69d616fcfc90917e744690c71af84fd276de61a6
Author: Samuele Andreoli <sa...@yahoo.it>
AuthorDate: Wed Feb 19 14:06:28 2020 +0000

    use octets in factoring zk API
---
 benchmark/bench_factoring_zk.c       | 12 +++--------
 examples/example_factoring_zk.c      | 15 +++-----------
 examples/example_full.c              | 16 +++++++++------
 include/amcl/factoring_zk.h          | 22 +++-----------------
 src/factoring_zk.c                   | 40 +++++++++++++++++++++---------------
 test/smoke/test_factoring_zk_smoke.c | 27 +++---------------------
 test/unit/test_factoring_zk_prove.c  | 19 +++++++++++------
 7 files changed, 59 insertions(+), 92 deletions(-)

diff --git a/benchmark/bench_factoring_zk.c b/benchmark/bench_factoring_zk.c
index e7f97df..0a7445c 100644
--- a/benchmark/bench_factoring_zk.c
+++ b/benchmark/bench_factoring_zk.c
@@ -29,6 +29,7 @@ under the License.
 
 char *P_hex = "e008507e09c24d756280f3d94912fb9ac16c0a8a1757ee01a350736acfc7f65880f87eca55d6680253383fc546d03fd9ebab7d8fa746455180888cb7c17edf58d3327296468e5ab736374bc9a0fa02606ed5d3a4a5fb1677891f87fbf3c655c3e0549a86b17b7ddce07c8f73e253105e59f5d3ed2c7ba5bdf8495df40ae71a7f";
 char *Q_hex = "dbffe278edd44c2655714e5a4cc82e66e46063f9ab69df9d0ed20eb3d7f2d8c7d985df71c28707f32b961d160ca938e9cf909cd77c4f8c630aec34b67714cbfd4942d7147c509db131bc2d6a667eb30df146f64b710f8f5247848b0a75738a38772e31014fd63f0b769209928d586499616dcc90700b393156e12eea7e15a835";
+char *N_hex = "c0870b552afb6c8c09f79e39ad6ca17ca93085c2cd7a726ade69574961ff9ce8ad33c7dda2e0703a3b0010c2e5bb7552c74164ce8dd011d85e5969090df53fe10e39cbe530704da32ff07228a6b6da34a5929e8a231c3080d812dc6e93affd81682339a6aee192927c582da8941bebf46e13c4ea3918a1477951fa66d367e70d8551b1869316d48317e0702d7bce242a326000f3dc763c44eba2044a1df713a94c1339edd464b145dcadf94e6e61be73dc270c878e1a28be720df2209202d00e101c3b255b757eaf547acd863d51eb676b851511b3dadeda926714719dceddd3af7908893ae65f2b95ee5c4d36cc6 [...]
 char *R_hex = "c05f6c79e81fab2f1aa6af48dc5afa89a21c0aee03e93944cacfefef1be90f41ec8c2055760beafa9ed87dd67dbd56b33a2568dfec62a03f06c4f8449a93eee858507f4b602bf305e1c9968d9f5b6dc3120c27e053a1d7e51590e0bacb8d36c27bccce1a57c1e3aeb0832905d4e2bb8eaee883b4df042d8660cf3e0c9777b6be34c18bef02347f92cb71f372f61c018860211932dd46de8f925212d7afe6dd2f3cda05f8d5a6bd1b138b66c5efd7fca31f926c721f6d4207b97fc01cdf325da21233f6df37adbcd67472b332f7490a4a96e0fef31beef55b9446067b8e8d807384e3d31051c7a1f27296a6ae111b3 [...]
 
 int main()
@@ -57,19 +58,12 @@ int main()
     char y[FS_2048];
     octet Y = {0, sizeof(y), y};
 
-    FACTORING_ZK_modulus m;
-
     // Load values
     OCT_fromHex(&P, P_hex);
     OCT_fromHex(&Q, Q_hex);
+    OCT_fromHex(&N, N_hex);
     OCT_fromHex(&R, R_hex);
 
-    FF_2048_fromOctet(m.p, &P, HFLEN_2048);
-    FF_2048_fromOctet(m.q, &Q, HFLEN_2048);
-
-    FF_2048_mul(m.n, m.p, m.q, HFLEN_2048);
-    FF_2048_toOctet(&N, m.n, FFLEN_2048);
-
     print_system_info();
 
     printf("Timing info\n");
@@ -79,7 +73,7 @@ int main()
     start = clock();
     do
     {
-        FACTORING_ZK_prove(&m, NULL, &R, &E, &Y);
+        FACTORING_ZK_prove(NULL, &P, &Q, &R, &E, &Y);
         iterations++;
         elapsed = (clock() - start) / (double)CLOCKS_PER_SEC;
     }
diff --git a/examples/example_factoring_zk.c b/examples/example_factoring_zk.c
index d3924f8..3a4741a 100644
--- a/examples/example_factoring_zk.c
+++ b/examples/example_factoring_zk.c
@@ -23,6 +23,7 @@ under the License.
 
 char *P_hex = "e008507e09c24d756280f3d94912fb9ac16c0a8a1757ee01a350736acfc7f65880f87eca55d6680253383fc546d03fd9ebab7d8fa746455180888cb7c17edf58d3327296468e5ab736374bc9a0fa02606ed5d3a4a5fb1677891f87fbf3c655c3e0549a86b17b7ddce07c8f73e253105e59f5d3ed2c7ba5bdf8495df40ae71a7f";
 char *Q_hex = "dbffe278edd44c2655714e5a4cc82e66e46063f9ab69df9d0ed20eb3d7f2d8c7d985df71c28707f32b961d160ca938e9cf909cd77c4f8c630aec34b67714cbfd4942d7147c509db131bc2d6a667eb30df146f64b710f8f5247848b0a75738a38772e31014fd63f0b769209928d586499616dcc90700b393156e12eea7e15a835";
+char *N_hex = "c0870b552afb6c8c09f79e39ad6ca17ca93085c2cd7a726ade69574961ff9ce8ad33c7dda2e0703a3b0010c2e5bb7552c74164ce8dd011d85e5969090df53fe10e39cbe530704da32ff07228a6b6da34a5929e8a231c3080d812dc6e93affd81682339a6aee192927c582da8941bebf46e13c4ea3918a1477951fa66d367e70d8551b1869316d48317e0702d7bce242a326000f3dc763c44eba2044a1df713a94c1339edd464b145dcadf94e6e61be73dc270c878e1a28be720df2209202d00e101c3b255b757eaf547acd863d51eb676b851511b3dadeda926714719dceddd3af7908893ae65f2b95ee5c4d36cc6 [...]
 
 int main()
 {
@@ -41,8 +42,6 @@ int main()
     char y[FS_2048];
     octet Y = {0, sizeof(y), y};
 
-    FACTORING_ZK_modulus m;
-
     // Deterministic RNG for testing
     char seed[64] = {0};
     csprng RNG;
@@ -51,12 +50,7 @@ int main()
     // Load RSA modulus
     OCT_fromHex(&P, P_hex);
     OCT_fromHex(&Q, Q_hex);
-
-    FF_2048_fromOctet(m.p, &P, HFLEN_2048);
-    FF_2048_fromOctet(m.q, &Q, HFLEN_2048);
-
-    FF_2048_mul(m.n, m.p, m.q, HFLEN_2048);
-    FF_2048_toOctet(&N, m.n, FFLEN_2048);
+    OCT_fromHex(&N, N_hex);
 
     printf("Prove knowledge of factoring for\n");
     printf("\tN = ");
@@ -68,7 +62,7 @@ int main()
 
     // ZK proof
     printf("\nGenerate proof\n");
-    FACTORING_ZK_prove(&m, &RNG, NULL, &E, &Y);
+    FACTORING_ZK_prove(&RNG, &P, &Q, NULL, &E, &Y);
 
     printf("\tE = ");
     OCT_output(&E);
@@ -87,7 +81,4 @@ int main()
     {
         printf("\tFailure!\n");
     }
-
-    // Clean memory
-    FACTORING_ZK_kill_modulus(&m);
 }
diff --git a/examples/example_full.c b/examples/example_full.c
index 55eabb6..dd5dd9a 100644
--- a/examples/example_full.c
+++ b/examples/example_full.c
@@ -131,7 +131,11 @@ void key_material_zkp(csprng *RNG, key_material *km, octet *C, octet *P, octet *
     char s_e[EGS_SECP256K1];
     octet S_E = {0, sizeof(s_e), s_e};
 
-    FACTORING_ZK_modulus m;
+    char p[HFS_2048] = {0};
+    octet M_P = {0, sizeof(p), p};
+
+    char q[HFS_2048];
+    octet M_Q = {0, sizeof(q), q};
 
     /* Prove knowledge of DLOG PK = s.G */
 
@@ -151,11 +155,10 @@ void key_material_zkp(csprng *RNG, key_material *km, octet *C, octet *P, octet *
 
     /* Prove knowledge of factorization of the Paillier modulus */
 
-    FF_2048_copy(m.p, km->paillier_sk.p, HFLEN_2048);
-    FF_2048_copy(m.q, km->paillier_sk.q, HFLEN_2048);
-    FF_2048_mul(m.n, m.p, m.q, HFLEN_2048);
+    FF_2048_toOctet(&M_P, km->paillier_sk.p, HFLEN_2048);
+    FF_2048_toOctet(&M_Q, km->paillier_sk.q, HFLEN_2048);
 
-    FACTORING_ZK_prove(&m, RNG, NULL, E, Y);
+    FACTORING_ZK_prove(RNG, &M_P, &M_Q, NULL, E, Y);
 
     printf("\n\tProve knowledge of the Paillier Secret Key\n");
     printf("\t\tE = ");
@@ -163,7 +166,8 @@ void key_material_zkp(csprng *RNG, key_material *km, octet *C, octet *P, octet *
     printf("\t\tY = ");
     OCT_output(Y);
 
-    FACTORING_ZK_kill_modulus(&m);
+    OCT_clear(&M_P);
+    OCT_clear(&M_Q);
 }
 
 int key_material_verify_zkp(key_material *km, octet *C, octet *P, octet *E, octet *Y)
diff --git a/include/amcl/factoring_zk.h b/include/amcl/factoring_zk.h
index b8738f3..bd8a81e 100644
--- a/include/amcl/factoring_zk.h
+++ b/include/amcl/factoring_zk.h
@@ -48,25 +48,16 @@ extern "C"
 #define FACTORING_ZK_OK   0  /** < Proof successfully verified */
 #define FACTORING_ZK_FAIL 91 /** < Invalid proof */
 
-/*!
- * \brief RSA modulus for ZKP
- */
-typedef struct
-{
-    BIG_1024_58 n[FFLEN_2048]; /**< Integer to prove knowledge of factoring */
-    BIG_1024_58 p[HFLEN_2048]; /**< First prime factor of n */
-    BIG_1024_58 q[HFLEN_2048]; /**< Second prime factor of n*/
-} FACTORING_ZK_modulus;
-
 /** \brief Prove knowledge of the modulus m in ZK
  *
- *  @param  m           Modulus to prove knowledge of factoring for
  *  @param  RNG         Cryptographically secure PRNG
+ *  @param  P           First prime of the factorization
+ *  @param  Q           Second prime of the factorization
  *  @param  R           Random value used in the proof. If RNG is NULL this is read
  *  @param  E           Fisrt component of the ZK proof
  *  @param  Y           Second component of the ZK proof
  */
-void FACTORING_ZK_prove(FACTORING_ZK_modulus *m, csprng *RNG, octet *R, octet *E, octet *Y);
+void FACTORING_ZK_prove(csprng *RNG, octet *P, octet *Q, octet *R, octet *E, octet *Y);
 
 /** \brief Verify ZK proof of knowledge of factoring of N
  *
@@ -79,13 +70,6 @@ void FACTORING_ZK_prove(FACTORING_ZK_modulus *m, csprng *RNG, octet *R, octet *E
  */
 int FACTORING_ZK_verify(octet *N, octet *E, octet *Y);
 
-/** \brief Clear modulus
- *
- *  @param m             Modulus for the ZK proof to clean
- *
- */
-void FACTORING_ZK_kill_modulus(FACTORING_ZK_modulus *m);
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/factoring_zk.c b/src/factoring_zk.c
index 513f364..339d349 100644
--- a/src/factoring_zk.c
+++ b/src/factoring_zk.c
@@ -93,7 +93,7 @@ void generator(hash256 *sha, int k, octet *O)
  *  e  = H'(N, Z1, Z2, X)
  *  y  = r + (N - phi(N)) * e
  */
-void FACTORING_ZK_prove(FACTORING_ZK_modulus *m, csprng *RNG, octet *R, octet *E, octet *Y)
+void FACTORING_ZK_prove(csprng *RNG, octet *P, octet *Q, octet *R, octet *E, octet *Y)
 {
     int i;
 
@@ -102,6 +102,10 @@ void FACTORING_ZK_prove(FACTORING_ZK_modulus *m, csprng *RNG, octet *R, octet *E
     hash256 sha_x;
     hash256 sha_prime;
 
+    BIG_1024_58 p[HFLEN_2048];
+    BIG_1024_58 q[HFLEN_2048];
+    BIG_1024_58 n[FFLEN_2048];
+
     BIG_1024_58 r[FFLEN_2048];
     BIG_1024_58 rp[HFLEN_2048];
     BIG_1024_58 rq[HFLEN_2048];
@@ -116,6 +120,11 @@ void FACTORING_ZK_prove(FACTORING_ZK_modulus *m, csprng *RNG, octet *R, octet *E
     char w[FS_2048];
     octet W = {0, sizeof(w), w};
 
+    // Read modulus
+    FF_2048_fromOctet(p, P, HFLEN_2048);
+    FF_2048_fromOctet(q, Q, HFLEN_2048);
+    FF_2048_mul(n, p, q, HFLEN_2048);
+
     if (RNG != NULL)
     {
         FF_2048_random(r, RNG, FFLEN_2048);
@@ -126,17 +135,17 @@ void FACTORING_ZK_prove(FACTORING_ZK_modulus *m, csprng *RNG, octet *R, octet *E
     }
 
     // Compute r mod (p-1) and r mod (q-1) for exponent with CRT
-    FF_2048_copy(hws, m->p, HFLEN_2048);
+    FF_2048_copy(hws, p, HFLEN_2048);
     FF_2048_dec(hws, 1, HFLEN_2048);
     FF_2048_dmod(rp, r, hws, HFLEN_2048);
 
-    FF_2048_copy(hws, m->q, HFLEN_2048);
+    FF_2048_copy(hws, q, HFLEN_2048);
     FF_2048_dec(hws, 1, HFLEN_2048);
     FF_2048_dmod(rq, r, hws, HFLEN_2048);
 
     // Process N in the hash function H(N, ?)
     HASH256_init(&sha);
-    FF_2048_toOctet(&W, m->n, FFLEN_2048);
+    FF_2048_toOctet(&W, n, FFLEN_2048);
     hash_oct(&sha, &W);
 
     // Duplicate the state of H so it can be used as H'(N, ?)
@@ -152,21 +161,21 @@ void FACTORING_ZK_prove(FACTORING_ZK_modulus *m, csprng *RNG, octet *R, octet *E
         generator(&mgf, i, &W);
 
         FF_2048_fromOctet(ws, &W, FFLEN_2048);
-        FF_2048_mod(ws, m->n, FFLEN_2048);
+        FF_2048_mod(ws, n, FFLEN_2048);
 
         FF_2048_toOctet(&W, ws, FFLEN_2048);
         hash_oct(&sha_prime, &W);
 
         // Compute Z_i ^ r mod P
-        FF_2048_dmod(hws, ws, m->p, HFLEN_2048);
-        FF_2048_skpow(zrp, hws, rp, m->p, HFLEN_2048, HFLEN_2048);
+        FF_2048_dmod(hws, ws, p, HFLEN_2048);
+        FF_2048_skpow(zrp, hws, rp, p, HFLEN_2048, HFLEN_2048);
 
         // Compute Z_i ^ r mod Q
-        FF_2048_dmod(hws, ws, m->q, HFLEN_2048);
-        FF_2048_skpow(zrq, hws, rq, m->q, HFLEN_2048, HFLEN_2048);
+        FF_2048_dmod(hws, ws, q, HFLEN_2048);
+        FF_2048_skpow(zrq, hws, rq, q, HFLEN_2048, HFLEN_2048);
 
         // Combine Z_i ^ r mod N with CRT
-        FF_2048_crt(ws, zrp, zrq, m->p, m->q, HFLEN_2048);
+        FF_2048_crt(ws, zrp, zrq, p, q, HFLEN_2048);
 
         // Process Z_i ^ r mod N in H
         FF_2048_toOctet(&W, ws, FFLEN_2048);
@@ -187,7 +196,7 @@ void FACTORING_ZK_prove(FACTORING_ZK_modulus *m, csprng *RNG, octet *R, octet *E
     FF_2048_fromOctet(e, &W, HFLEN_2048);
 
     // N - phi(N) = P + Q - 1
-    FF_2048_add(hws, m->p, m->q, HFLEN_2048);
+    FF_2048_add(hws, p, q, HFLEN_2048);
     FF_2048_dec(hws, 1, HFLEN_2048);
 
     // e * (N - phi(N))
@@ -201,10 +210,14 @@ void FACTORING_ZK_prove(FACTORING_ZK_modulus *m, csprng *RNG, octet *R, octet *E
 
     // Clear memory
     FF_2048_zero(r,   FFLEN_2048);
+    FF_2048_zero(n,   FFLEN_2048);
+    FF_2048_zero(p,   HFLEN_2048);
+    FF_2048_zero(q,   HFLEN_2048);
     FF_2048_zero(rp,  HFLEN_2048);
     FF_2048_zero(rq,  HFLEN_2048);
     FF_2048_zero(zrp, HFLEN_2048);
     FF_2048_zero(zrq, HFLEN_2048);
+    FF_2048_zero(hws, HFLEN_2048);
 }
 
 int FACTORING_ZK_verify(octet *N, octet *E, octet *Y)
@@ -291,8 +304,3 @@ int FACTORING_ZK_verify(octet *N, octet *E, octet *Y)
     return FACTORING_ZK_OK;
 }
 
-void FACTORING_ZK_kill_modulus(FACTORING_ZK_modulus *m)
-{
-    FF_2048_zero(m->p, HFLEN_2048);
-    FF_2048_zero(m->q, HFLEN_2048);
-}
diff --git a/test/smoke/test_factoring_zk_smoke.c b/test/smoke/test_factoring_zk_smoke.c
index 4e5f065..d2a0b54 100644
--- a/test/smoke/test_factoring_zk_smoke.c
+++ b/test/smoke/test_factoring_zk_smoke.c
@@ -23,6 +23,7 @@ under the License.
 
 char *P_hex = "e008507e09c24d756280f3d94912fb9ac16c0a8a1757ee01a350736acfc7f65880f87eca55d6680253383fc546d03fd9ebab7d8fa746455180888cb7c17edf58d3327296468e5ab736374bc9a0fa02606ed5d3a4a5fb1677891f87fbf3c655c3e0549a86b17b7ddce07c8f73e253105e59f5d3ed2c7ba5bdf8495df40ae71a7f";
 char *Q_hex = "dbffe278edd44c2655714e5a4cc82e66e46063f9ab69df9d0ed20eb3d7f2d8c7d985df71c28707f32b961d160ca938e9cf909cd77c4f8c630aec34b67714cbfd4942d7147c509db131bc2d6a667eb30df146f64b710f8f5247848b0a75738a38772e31014fd63f0b769209928d586499616dcc90700b393156e12eea7e15a835";
+char *N_hex = "c0870b552afb6c8c09f79e39ad6ca17ca93085c2cd7a726ade69574961ff9ce8ad33c7dda2e0703a3b0010c2e5bb7552c74164ce8dd011d85e5969090df53fe10e39cbe530704da32ff07228a6b6da34a5929e8a231c3080d812dc6e93affd81682339a6aee192927c582da8941bebf46e13c4ea3918a1477951fa66d367e70d8551b1869316d48317e0702d7bce242a326000f3dc763c44eba2044a1df713a94c1339edd464b145dcadf94e6e61be73dc270c878e1a28be720df2209202d00e101c3b255b757eaf547acd863d51eb676b851511b3dadeda926714719dceddd3af7908893ae65f2b95ee5c4d36cc6 [...]
 
 int main()
 {
@@ -41,8 +42,6 @@ int main()
     char y[FS_2048];
     octet Y = {0, sizeof(y), y};
 
-    FACTORING_ZK_modulus m;
-
     BIG_1024_58 zero[HFLEN_2048];
     FF_2048_zero(zero, HFLEN_2048);
 
@@ -54,16 +53,10 @@ int main()
     // Load RSA modulus
     OCT_fromHex(&P, P_hex);
     OCT_fromHex(&Q, Q_hex);
-
-    FF_2048_fromOctet(m.p, &P, HFLEN_2048);
-    FF_2048_fromOctet(m.q, &Q, HFLEN_2048);
-
-    FF_2048_mul(m.n, m.p, m.q, HFLEN_2048);
+    OCT_fromHex(&N, N_hex);
 
     // ZK proof
-    FACTORING_ZK_prove(&m, &RNG, NULL, &E, &Y);
-
-    FF_2048_toOctet(&N, m.n, FFLEN_2048);
+    FACTORING_ZK_prove(&RNG, &P, &Q, NULL, &E, &Y);
 
     // Verify proof
     if (FACTORING_ZK_verify(&N, &E, &Y) != FACTORING_ZK_OK)
@@ -72,20 +65,6 @@ int main()
         exit(EXIT_FAILURE);
     }
 
-    // Kill modulus
-    FACTORING_ZK_kill_modulus(&m);
-    if (FF_2048_comp(m.p, zero, HFLEN_2048))
-    {
-        printf("FAILUER FACTORING_ZK_kill_modulus. P not zeroed\n");
-        exit(EXIT_FAILURE);
-    }
-
-    if (FF_2048_comp(m.q, zero, HFLEN_2048))
-    {
-        printf("FAILUER FACTORING_ZK_kill_modulus. Q not zeroed\n");
-        exit(EXIT_FAILURE);
-    }
-
     printf("SUCCESS\n");
     exit(EXIT_SUCCESS);
 }
diff --git a/test/unit/test_factoring_zk_prove.c b/test/unit/test_factoring_zk_prove.c
index cab95ee..5c9c3eb 100644
--- a/test/unit/test_factoring_zk_prove.c
+++ b/test/unit/test_factoring_zk_prove.c
@@ -53,11 +53,18 @@ int main(int argc, char **argv)
     octet YGOLDEN = {0, sizeof(ygolden), ygolden};
     const char *Yline = "Y = ";
 
-    FACTORING_ZK_modulus m;
-    const char *Nline = "N = ";
+    char p[HFS_2048];
+    octet P = {0, sizeof(p), p};
     const char *Pline = "P = ";
+
+    char q[HFS_2048];
+    octet Q = {0, sizeof(q), q};
     const char *Qline = "Q = ";
 
+    char n[FS_2048];
+    octet N = {0, sizeof(n), n};
+    const char *Nline = "N = ";
+
     char e[FACTORING_ZK_B];
     octet E = {0, sizeof(e), e};
 
@@ -79,9 +86,9 @@ int main(int argc, char **argv)
         scan_int(&testNo, line, TESTline);
 
         // Read modulus
-        scan_FF_2048(fp, m.p, line, Pline, HFLEN_2048);
-        scan_FF_2048(fp, m.q, line, Qline, HFLEN_2048);
-        scan_FF_2048(fp, m.n, line, Nline, FFLEN_2048);
+        scan_OCTET(fp, &P, line, Pline);
+        scan_OCTET(fp, &Q, line, Qline);
+        scan_OCTET(fp, &N, line, Nline);
 
         // Read non-random R
         scan_OCTET(fp, &R, line, Rline);
@@ -93,7 +100,7 @@ int main(int argc, char **argv)
         // Read Y and run test
         if (!strncmp(line, last_line, strlen(last_line)))
         {
-            FACTORING_ZK_prove(&m, NULL, &R, &E, &Y);
+            FACTORING_ZK_prove(NULL, &P, &Q, &R, &E, &Y);
 
             compare_OCT(fp, testNo, "FACTORING_ZK_prove E", &E, &EGOLDEN);
             compare_OCT(fp, testNo, "FACTORING_ZK_prove Y", &Y, &YGOLDEN);


[incubator-milagro-MPC] 01/04: Add NM commit wrappers with test, benchmark and example

Posted by sa...@apache.org.
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 52621af139c442ec7febadf4b93debf623e96a66
Author: Samuele Andreoli <sa...@yahoo.it>
AuthorDate: Tue Feb 18 16:40:26 2020 +0000

    Add NM commit wrappers with test, benchmark and example
---
 python/amcl/commitments.py             | 222 +++++++++++++++++++++++++++++++++
 python/benchmark/bench_nm_commit.py    |  47 +++++++
 python/examples/example_nm_commit.py   |  54 ++++++++
 python/test/CMakeLists.txt             |  16 ++-
 python/test/test_nm_commit.py          |  90 +++++++++++++
 testVectors/commitments/nm_commit.json |  62 +++++++++
 6 files changed, 486 insertions(+), 5 deletions(-)

diff --git a/python/amcl/commitments.py b/python/amcl/commitments.py
new file mode 100644
index 0000000..153addd
--- /dev/null
+++ b/python/amcl/commitments.py
@@ -0,0 +1,222 @@
+#!/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 platform
+from amcl import core_utils
+
+_ffi = core_utils._ffi
+_ffi.cdef("""
+extern void COMMITMENTS_NM_commit(csprng *RNG, octet *X, octet *R, octet *C);
+extern int COMMITMENTS_NM_decommit(octet* X, octet* R, octet* C);
+""")
+
+if (platform.system() == 'Windows'):
+    libamcl_mpc = _ffi.dlopen("libamcl_mpc.dll")
+    libamcl_core = _ffi.dlopen("libamcl_core.dll")
+elif (platform.system() == 'Darwin'):
+    libamcl_mpc = _ffi.dlopen("libamcl_mpc.dylib")
+    libamcl_core = _ffi.dlopen("libamcl_core.dylib")
+else:
+    libamcl_mpc = _ffi.dlopen("libamcl_mpc.so")
+    libamcl_core = _ffi.dlopen("libamcl_core.so")
+
+# Constants
+SHA256 = 32
+
+OK   = 0
+FAIL = 81
+
+
+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 nm_commit(rng, x, r=None):
+    """ Commit to the value x
+
+    Generate a commitment c to the value x, using the value r.
+    If r is empty it is randomly generated
+
+    Args::
+
+        rng : Pointer to cryptographically secure pseudo-random generator instance
+        x   : value to commit
+        r   : random value for the commitment. If empty it is randomly generated
+              If not empty it must be 256 bit long
+
+    Returns::
+
+    Raises::
+
+    """
+
+    if r is None:
+        r_oct, r_val = make_octet(SHA256)
+    else:
+        r_oct, r_val = make_octet(None, r)
+        rng = _ffi.NULL
+
+    _ = r_val # Suppress warning
+
+    x_oct, x_val = make_octet(None, x)
+    c_oct, c_val = make_octet(SHA256)
+    _ = x_val, c_val # Suppress warning
+
+    libamcl_mpc.COMMITMENTS_NM_commit(rng, x_oct, r_oct, c_oct)
+
+    r = to_str(r_oct)
+
+    # Clean memory
+    libamcl_core.OCT_clear(x_oct)
+    libamcl_core.OCT_clear(r_oct)
+
+    return r, to_str(c_oct)
+
+def nm_decommit(x, r, c):
+    """ Decommit commitment c
+
+    Decommit a commitment c to the value x, using the value r.
+
+    Args::
+
+        x : value to commit
+        r : random value for the commitment. It must be 256 bit
+        c : commitment value
+
+    Returns::
+
+    Raises::
+
+    """
+
+    x_oct, x_val = make_octet(None, x)
+    r_oct, r_val = make_octet(None, r)
+    c_oct, c_val = make_octet(None, c)
+    _ = x_val, r_val, c_val # Suppress warning
+
+    ec = libamcl_mpc.COMMITMENTS_NM_decommit(x_oct, r_oct, c_oct)
+
+    return ec
diff --git a/python/benchmark/bench_nm_commit.py b/python/benchmark/bench_nm_commit.py
new file mode 100755
index 0000000..a10012e
--- /dev/null
+++ b/python/benchmark/bench_nm_commit.py
@@ -0,0 +1,47 @@
+#!/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 commitments
+
+x_hex = "40576370e36018f6bfaffc4c66780303a361f0c5f4a18a86a74fb179ca0fcf22"
+r_hex = "296f910bde4530efe3533ed3b74475d6022364db2e57773207734b6daf547ac8"
+
+if __name__ == "__main__":
+    x = bytes.fromhex(x_hex)
+    r = bytes.fromhex(r_hex)
+
+    # Generate quantities for benchmark
+    r, c = commitments.nm_commit(None, x, r)
+
+    assert commitments.nm_decommit(x, r, c) == commitments.OK
+
+    # Run benchmark
+    fncall = lambda: commitments.nm_commit(None, x, r)
+    time_func("nm_commit  ", fncall, unit="us")
+
+    fncall = lambda: commitments.nm_decommit(x, r, c)
+    time_func("nm_decommit", fncall, unit="us")
diff --git a/python/examples/example_nm_commit.py b/python/examples/example_nm_commit.py
new file mode 100755
index 0000000..024e60c
--- /dev/null
+++ b/python/examples/example_nm_commit.py
@@ -0,0 +1,54 @@
+#!/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, commitments
+
+seed_hex = "78d0fb6705ce77dee47d03eb5b9c5d30"
+
+if __name__ == "__main__":
+    seed = bytes.fromhex(seed_hex)
+    rng = core_utils.create_csprng(seed)
+
+    print("Example Non Malleable Commitment")
+    print("Message: BANANA")
+
+    x = b'BANANA'
+
+    # Commitment Phase
+    r, c = commitments.nm_commit(rng, x)
+
+    print("\nCommitment")
+    print(f"\tr = {r.hex()}")
+    print(f"\tc = {c.hex()}")
+
+    # Decommitment Phase. After both c, r and x have been revealed
+    rc = commitments.nm_decommit(x, r, c)
+
+    print("\nDecommitment")
+    if rc == commitments.OK:
+        print("\tSuccess")
+    else:
+        print("\tFailure")
diff --git a/python/test/CMakeLists.txt b/python/test/CMakeLists.txt
index a01ddf4..b2fdbc7 100644
--- a/python/test/CMakeLists.txt
+++ b/python/test/CMakeLists.txt
@@ -44,10 +44,16 @@ file(COPY ${MPC_TV} DESTINATION "${PROJECT_BINARY_DIR}/python/test/mpc/")
 file(GLOB SCHNORR_TV "${PROJECT_SOURCE_DIR}/testVectors/schnorr/*.json")
 file(COPY ${SCHNORR_TV} DESTINATION "${PROJECT_BINARY_DIR}/python/test/schnorr/")
 
+# NM Commitment test vector
+file(
+  COPY ${PROJECT_SOURCE_DIR}/testVectors/commitments/nm_commit.json
+  DESTINATION "${PROJECT_BINARY_DIR}/python/test/commitments/")
+
 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_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)
 endif(NOT CMAKE_BUILD_TYPE STREQUAL "ASan")
diff --git a/python/test/test_nm_commit.py b/python/test/test_nm_commit.py
new file mode 100755
index 0000000..a317a79
--- /dev/null
+++ b/python/test/test_nm_commit.py
@@ -0,0 +1,90 @@
+#!/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 commitments, core_utils
+
+# Load and preprocess test vectors
+with open("commitments/nm_commit.json", "r") as f:
+    vectors = json.load(f)
+
+for vector in vectors:
+    for key, val in vector.items():
+        if key != "TEST":
+            vector[key] = bytes.fromhex(val)
+
+
+class TestNMCommit(TestCase):
+    """ Test NM Commitment Commit """
+
+    def setUp(self):
+        # Deterministic PRNG for testing purposes
+        seed_hex = "78d0fb6705ce77dee47d03eb5b9c5d30"
+        seed = bytes.fromhex(seed_hex)
+        self.rng = core_utils.create_csprng(seed)
+
+        self.msg = b'BANANA'
+
+        r_hex = "296f910bde4530efe3533ed3b74475d6022364db2e57773207734b6daf547ac8"
+        c_hex = "b60ebd5193252d22c771a7702724e9922662aae5f634494225cdd3a9e22f9826"
+        self.r_golden = bytes.fromhex(r_hex)
+        self.c_golden = bytes.fromhex(c_hex)
+
+    def test_tv(self):
+        """ Test using test vectors """
+
+        for vector in vectors:
+            r, c = commitments.nm_commit(None, vector['X'], vector['R'])
+
+            self.assertEqual(vector['R'], r)
+            self.assertEqual(vector['C'], c)
+
+    def test_random(self):
+        """ Test using rng """
+        r, c = commitments.nm_commit(self.rng, self.msg)
+
+        self.assertEqual(r, self.r_golden)
+        self.assertEqual(c, self.c_golden)
+
+
+class TestNMDecommit(TestCase):
+    """ Test NM Commitment Decommit """
+
+    def test_tv(self):
+        """ Test using test vectors """
+
+        for vector in vectors:
+            rc = commitments.nm_decommit(vector['X'], vector['R'], vector['C'])
+
+            self.assertEqual(rc, commitments.OK)
+
+    def test_failure(self):
+        """ Test error codes are propagated correctly """
+
+        rc = commitments.nm_decommit(vector['X'], vector['X'], vector['C'])
+
+        self.assertEqual(rc, commitments.FAIL)
diff --git a/testVectors/commitments/nm_commit.json b/testVectors/commitments/nm_commit.json
new file mode 100644
index 0000000..aa506a3
--- /dev/null
+++ b/testVectors/commitments/nm_commit.json
@@ -0,0 +1,62 @@
+[
+    {
+        "TEST":"0",
+        "X": "3f3cc85d2a99534d",
+        "R": "bba1e28251a39a13c037b180ed41cb76c23ca5fd639725706ead86f40d7f7b1e",
+        "C": "d49772a2af3c0904199b5620014f34ee2152cb427a4f241b2e45c62ce1a11f69"
+    },
+    {
+        "TEST": "1",
+        "X": "e8687750094198b455",
+        "R": "3ec7e47abe1345061e4c54808779c43493e4b6d15749d33becd1efb418ec0d34",
+        "C": "4eb9edfe9b66dcdb1882a9ea862794b2308d9a768155e96810502cc361f2afcc"
+    },
+    {
+        "TEST": "2",
+        "X": "ed45810ce81e4bf27980",
+        "R": "18a8edb9f5211df1f0f876e012a1404973cd173acea497d6fb93b5b39b910a89",
+        "C": "52bf67e6e9f4fd68382d2c94dc4044191edf5005cbbfa2cea6a6c7b69846e043"
+    },
+    {
+        "TEST": "3",
+        "X": "965f61c651654622880bcc",
+        "R": "88a038a78dba707e72b192eef24aab965335c51c3e15e39b132229807c828c23",
+        "C": "7e1c0cbcc37b311cabe367bdd85dcacc1fc5e5dcbb374bf12ea224832a6ad91c"
+    },
+    {
+        "TEST": "4",
+        "X": "311b616d5e92ea7e7d6bb8e2",
+        "R": "ec3712c94f66098933c57abbc46c4298bb276eceac3597654e1fd72ba434191d",
+        "C": "a6b6083665669c6de43d0dcd15f29964ffcd9075ecd46ca8e58711ab359002c3"
+    },
+    {
+        "TEST": "5",
+        "X": "1ce58293a6ab70f62b4c724e60",
+        "R": "1c4c20f3d10a5af166e45afbc88c98008fff529b6cc8ce008d375848712a0778",
+        "C": "90986555e5c9bbace9048913ef0eb44a06ed8b5dd76ae3090b4911c6fa2b4d7b"
+    },
+    {
+        "TEST": "6",
+        "X": "e1c508ee1862474e1080bbaefe89",
+        "R": "4d812c8519837c696dc1967adb2452972119bea337174182768fd0f781d41b6d",
+        "C": "83594768dbd29e0fc7dedc0dd999e573a478292305d6764ed3b981d26cc55666"
+    },
+    {
+        "TEST": "7",
+        "X": "df5b2f3e4a2f35e81dc93f9d33b540",
+        "R": "4d9112b5f3b34a3e6db75078e48006b8d86459cfb9ea9093272c416a56a4794b",
+        "C": "e8d031761ed9ab072dec45457710ce7a7d88695b854b8fbd42a06387972cbb79"
+    },
+    {
+        "TEST": "8",
+        "X": "966244192989663e85ee431f90182539",
+        "R": "e330c3a33e2657eca224e778952e1abfde0ca62f8da0417ca64d34b2bb16de3f",
+        "C": "1ef1b10077de18cda783dbbeeefaacc93051d2456e6fc53958506ff1cfda064c"
+    },
+    {
+        "TEST": "9",
+        "X": "76cba6658a3730513c7b7cd2135e3e1f16",
+        "R": "40576370e36018f6bfaffc4c66780303a361f0c5f4a18a86a74fb179ca0fcf22",
+        "C": "88c318a79e481cc7ce7041bb3e66e50cbae6b88efaaa649a4b6b06fb6351b952"
+    }
+]


[incubator-milagro-MPC] 02/04: format code

Posted by sa...@apache.org.
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 4a97005be64fe01ad2d977edf31a168031957b11
Author: Samuele Andreoli <sa...@yahoo.it>
AuthorDate: Wed Feb 19 13:20:19 2020 +0000

    format code
---
 benchmark/bench.h                 | 2 +-
 examples/example_dump_keys.c      | 4 ++--
 test/smoke/test_dump_keys_smoke.c | 6 +++---
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/benchmark/bench.h b/benchmark/bench.h
index 5c60bc5..6472bf5 100644
--- a/benchmark/bench.h
+++ b/benchmark/bench.h
@@ -41,4 +41,4 @@ extern void print_system_info();
 }
 #endif
 
-#endif
\ No newline at end of file
+#endif
diff --git a/examples/example_dump_keys.c b/examples/example_dump_keys.c
index ccf0f84..0320c01 100644
--- a/examples/example_dump_keys.c
+++ b/examples/example_dump_keys.c
@@ -50,7 +50,7 @@ int main()
     PAILLIER_public_key PUB1;
     PAILLIER_private_key PRIV2;
     PAILLIER_public_key PUB2;
-    PAILLIER_public_key PUB3;    
+    PAILLIER_public_key PUB3;
 
     // Paillier public key
     char n[FS_4096] = {0};
@@ -73,7 +73,7 @@ int main()
 
     FF_2048_toOctet(&P, PRIV1.p, HFLEN_2048);
     FF_2048_toOctet(&Q, PRIV1.q, HFLEN_2048);
-    
+
     // Write secret key to octets
     MPC_DUMP_PAILLIER_SK(&PRIV1, &P, &Q);
 
diff --git a/test/smoke/test_dump_keys_smoke.c b/test/smoke/test_dump_keys_smoke.c
index 751941d..5ba8799 100644
--- a/test/smoke/test_dump_keys_smoke.c
+++ b/test/smoke/test_dump_keys_smoke.c
@@ -53,7 +53,7 @@ int main()
     PAILLIER_private_key PRIV2;
     PAILLIER_public_key PUB2;
     PAILLIER_public_key PUB3;
-    
+
     char p[FS_2048] = {0};
     octet P = {0,sizeof(p),p};
 
@@ -180,9 +180,9 @@ int main()
         fprintf(stderr, "FAILURE QQ != Q rc: %d\n", rc);
         exit(EXIT_FAILURE);
     }
-    
+
     // Read secret key from octets
-    PAILLIER_KEY_PAIR(NULL, &PP, &QQ, &PUB3, &PRIV2);    
+    PAILLIER_KEY_PAIR(NULL, &PP, &QQ, &PUB3, &PRIV2);
 
     MPC_MTA_CLIENT1(NULL, &PUB2, &A, &CA, &R);
 


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

Posted by sa...@apache.org.
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)