Fix sonar report
diff --git a/benchmark/bench_factoring_zk.c b/benchmark/bench_factoring_zk.c
index fa46877..9cded2e 100644
--- a/benchmark/bench_factoring_zk.c
+++ b/benchmark/bench_factoring_zk.c
@@ -67,6 +67,8 @@
     char y[FS_2048];
     octet Y = {0, sizeof(y), y};
 
+    FACTORING_ZK_modulus m;
+
     // Load values
     OCT_jstring(&ID, ID_str);
     OCT_fromHex(&AD, AD_hex);
@@ -85,14 +87,28 @@
     start = clock();
     do
     {
-        FACTORING_ZK_prove(NULL, &P, &Q, &ID, &AD, &R, &E, &Y);
+        FACTORING_ZK_modulus_fromOctets(&m, &P, &Q);
         iterations++;
         elapsed = (clock() - start) / (double)CLOCKS_PER_SEC;
     }
     while (elapsed < MIN_TIME || iterations < MIN_ITERS);
 
     elapsed = MILLISECOND * elapsed / iterations;
-    printf("\tFACTORING_ZK_prove\t%8d iterations\t", iterations);
+    printf("\tFACTORING_ZK_modulus_fromOctets\t%8d iterations\t", iterations);
+    printf("%8.2lf ms per iteration\n", elapsed);
+
+    iterations = 0;
+    start = clock();
+    do
+    {
+        FACTORING_ZK_prove(NULL, &m, &ID, &AD, &R, &E, &Y);
+        iterations++;
+        elapsed = (clock() - start) / (double)CLOCKS_PER_SEC;
+    }
+    while (elapsed < MIN_TIME || iterations < MIN_ITERS);
+
+    elapsed = MILLISECOND * elapsed / iterations;
+    printf("\tFACTORING_ZK_prove\t\t%8d iterations\t", iterations);
     printf("%8.2lf ms per iteration\n", elapsed);
 
     iterations = 0;
@@ -112,8 +128,22 @@
     }
 
     elapsed = MILLISECOND * elapsed / iterations;
-    printf("\tFACTORING_ZK_verify\t%8d iterations\t", iterations);
+    printf("\tFACTORING_ZK_verify\t\t%8d iterations\t", iterations);
     printf("%8.2lf ms per iteration\n", elapsed);
 
+    iterations = 0;
+    start = clock();
+    do
+    {
+        FACTORING_ZK_modulus_kill(&m);
+        iterations++;
+        elapsed = (clock() - start) / (double)CLOCKS_PER_SEC;
+    }
+    while (elapsed < MIN_TIME || iterations < MIN_ITERS);
+
+    elapsed = MICROSECOND * elapsed / iterations;
+    printf("\tFACTORING_ZK_modulus_kill\t%8d iterations\t", iterations);
+    printf("%8.2lf us per iteration\n", elapsed);
+
     exit(EXIT_SUCCESS);
 }
diff --git a/examples/example_factoring_zk.c b/examples/example_factoring_zk.c
index f36aaf3..d67b63c 100644
--- a/examples/example_factoring_zk.c
+++ b/examples/example_factoring_zk.c
@@ -48,6 +48,8 @@
     char y[FS_2048];
     octet Y = {0, sizeof(y), y};
 
+    FACTORING_ZK_modulus m;
+
     // Deterministic RNG for testing
     char seed[64] = {0};
     csprng RNG;
@@ -72,7 +74,8 @@
 
     // ZK proof
     printf("\nGenerate proof\n");
-    FACTORING_ZK_prove(&RNG, &P, &Q, &ID, &AD, NULL, &E, &Y);
+    FACTORING_ZK_modulus_fromOctets(&m, &P, &Q);
+    FACTORING_ZK_prove(&RNG, &m, &ID, &AD, NULL, &E, &Y);
 
     printf("\tE = ");
     OCT_output(&E);
@@ -91,4 +94,7 @@
     {
         printf("\tFailure!\n");
     }
+
+    // Clean memory
+    FACTORING_ZK_modulus_kill(&m);
 }
diff --git a/examples/example_full.c b/examples/example_full.c
index 0727b5f..625bd54 100644
--- a/examples/example_full.c
+++ b/examples/example_full.c
@@ -136,6 +136,8 @@
     char q[HFS_2048];
     octet M_Q = {0, sizeof(q), q};
 
+    FACTORING_ZK_modulus m;
+
     /* Prove knowledge of DLOG PK = s.G */
 
     SCHNORR_commit(RNG, &R, C);
@@ -161,7 +163,8 @@
     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(RNG, &M_P, &M_Q, ID, AD, NULL, E, Y);
+    FACTORING_ZK_modulus_fromOctets(&m, &M_P, &M_Q);
+    FACTORING_ZK_prove(RNG, &m, ID, AD, NULL, E, Y);
 
     printf("\n\tProve knowledge of the Paillier Secret Key\n");
     printf("\t\tE = ");
@@ -171,6 +174,7 @@
 
     OCT_clear(&M_P);
     OCT_clear(&M_Q);
+    FACTORING_ZK_modulus_kill(&m);
 }
 
 int key_material_verify_zkp(key_material *km, octet *C, octet *P, octet *E, octet *Y, octet *ID, octet *AD)
diff --git a/include/amcl/factoring_zk.h b/include/amcl/factoring_zk.h
index 4ae7a39..7b2c6f0 100644
--- a/include/amcl/factoring_zk.h
+++ b/include/amcl/factoring_zk.h
@@ -50,18 +50,26 @@
 #define FACTORING_ZK_FAIL 91          /**< Invalid proof */
 #define FACTORING_ZK_OUT_OF_BOUNDS 92 /**< Invalid proof bounds */
 
+/*! \brief Modulus to prove knowledge of factoring */
+typedef struct
+{
+    BIG_1024_58 p[HFLEN_2048];     /**< First factor of the modulus */
+    BIG_1024_58 q[HFLEN_2048];     /**< Second factor of the modulus */
+    BIG_1024_58 invpq[HFLEN_2048]; /**< Precomputed inverse for CRT */
+    BIG_1024_58 n[FFLEN_2048];     /**< Modulus */
+} FACTORING_ZK_modulus;
+
 /** \brief Prove knowledge of the modulus m in ZK
  *
  *  @param  RNG         Cryptographically secure PRNG
- *  @param  P           First prime of the factorization
- *  @param  Q           Second prime of the factorization
+ *  @param  m           Modulus to prove knowldege of factoring
  *  @param  ID          Prover unique identifier
  *  @param  AD          Additional data to bind in the proof - Optional
  *  @param  R           Random value used in the proof. If RNG is NULL this is read
  *  @param  E           First component of the ZK proof
  *  @param  Y           Second component of the ZK proof
  */
-void FACTORING_ZK_prove(csprng *RNG, octet *P, octet *Q, octet *ID, octet *AD, octet *R, octet *E, octet *Y);
+void FACTORING_ZK_prove(csprng *RNG, FACTORING_ZK_modulus *m, const octet *ID, const octet *AD, octet *R, octet *E, octet *Y);
 
 /** \brief Verify ZK proof of knowledge of factoring of N
  *
@@ -74,7 +82,21 @@
  *  @param  AD          Additional data to bind in the proof - Optional
  *  @return             1 if the proof is valid, 0 otherwise
  */
-int FACTORING_ZK_verify(octet *N, octet *E, octet *Y, octet *ID, octet *AD);
+int FACTORING_ZK_verify(octet *N, octet *E, octet *Y, const octet *ID, const octet *AD);
+
+/** \brief Read a modulus from octets
+ *
+ *  @param  m           The destination modulus
+ *  @param  P           The first factor of the modulus
+ *  @param  Q           The second factor of the modulus 
+ */
+void FACTORING_ZK_modulus_fromOctets(FACTORING_ZK_modulus *m, octet *P, octet *Q);
+
+/** \brief Clean memory associated to a modulus 
+ *
+ *  @param  m           The modulus to clean 
+ */
+void FACTORING_ZK_modulus_kill(FACTORING_ZK_modulus *m);
 
 #ifdef __cplusplus
 }
diff --git a/include/amcl/schnorr.h b/include/amcl/schnorr.h
index 8ab93a8..9f2f464 100644
--- a/include/amcl/schnorr.h
+++ b/include/amcl/schnorr.h
@@ -72,7 +72,7 @@
  * @param AD    Additional data to bind in the challenge - Optional
  * @param E     Challenge generated
  */
-extern void SCHNORR_challenge(const octet *V, const octet *C, octet *ID, octet *AD, octet *E);
+extern void SCHNORR_challenge(const octet *V, const octet *C, const octet *ID, const octet *AD, octet *E);
 
 /*! \brief Generate the proof for the given commitment and challenge
  *
@@ -122,7 +122,7 @@
  * @param AD    Additional data to bind in the challenge - Optional
  * @param E     Challenge generated
  */
-extern void SCHNORR_D_challenge(const octet *R, const octet *V, const octet *C, octet* ID, octet *AD, octet *E);
+extern void SCHNORR_D_challenge(const octet *R, const octet *V, const octet *C, const octet* ID, const octet *AD, octet *E);
 
 /*! \brief Generate the proof for the given commitment and challenge
  *
diff --git a/python/amcl/factoring_zk.py b/python/amcl/factoring_zk.py
index 32b8f3f..4584585 100644
--- a/python/amcl/factoring_zk.py
+++ b/python/amcl/factoring_zk.py
@@ -28,8 +28,18 @@
 
 _ffi = core_utils._ffi
 _ffi.cdef("""
-void FACTORING_ZK_prove(csprng *RNG, octet *P, octet *Q, octet *ID, octet *AD, octet *R, octet *E, octet *Y);
-int FACTORING_ZK_verify(octet *N, octet *E, octet *Y, octet *ID, octet *AD);
+typedef struct
+{
+    BIG_1024_58 p[1];
+    BIG_1024_58 q[1];
+    BIG_1024_58 invpq[1];
+    BIG_1024_58 n[2];
+} FACTORING_ZK_modulus;
+
+void FACTORING_ZK_prove(csprng *RNG, FACTORING_ZK_modulus *m, const octet *ID, const octet *AD, octet *R, octet *E, octet *Y);
+int FACTORING_ZK_verify(octet *N, octet *E, octet *Y, const octet *ID, const octet *AD);
+void FACTORING_ZK_modulus_fromOctets(FACTORING_ZK_modulus *m, octet *P, octet *Q);
+void FACTORING_ZK_modulus_kill(FACTORING_ZK_modulus *m);
 """)
 
 if (platform.system() == 'Windows'):
@@ -94,9 +104,13 @@
     id_oct, id_val = core_utils.make_octet(None, id)
     _ = p_val, q_val, e_val, y_val, id_val # Suppress warnings
 
-    _libamcl_mpc.FACTORING_ZK_prove(rng, p_oct, q_oct, id_oct, ad_oct, r_oct, e_oct, y_oct)
+    modulus = _ffi.new('FACTORING_ZK_modulus*')
+
+    _libamcl_mpc.FACTORING_ZK_modulus_fromOctets(modulus, p_oct, q_oct)
+    _libamcl_mpc.FACTORING_ZK_prove(rng, modulus, id_oct, ad_oct, r_oct, e_oct, y_oct)
 
     # Clear memory
+    _libamcl_mpc.FACTORING_ZK_modulus_kill(modulus)
     core_utils.clear_octet(p_oct)
     core_utils.clear_octet(q_oct)
 
diff --git a/src/factoring_zk.c b/src/factoring_zk.c
index d8d24e9..bd001f9 100644
--- a/src/factoring_zk.c
+++ b/src/factoring_zk.c
@@ -93,7 +93,7 @@
  *  e  = H'(N, Z1, Z2, X, ID, AD)
  *  y  = r + (N - phi(N)) * e
  */
-void FACTORING_ZK_prove(csprng *RNG, octet *P, octet *Q, octet *ID, octet *AD, octet *R, octet *E, octet *Y)
+void FACTORING_ZK_prove(csprng *RNG, FACTORING_ZK_modulus *m, const octet *ID, const octet *AD, octet *R, octet *E, octet *Y)
 {
     int i;
 
@@ -102,10 +102,7 @@
     hash256 sha_x;
     hash256 sha_prime;
 
-    BIG_1024_58 p[HFLEN_2048];
-    BIG_1024_58 q[HFLEN_2048];
     BIG_1024_58 invpq[HFLEN_2048];
-    BIG_1024_58 n[FFLEN_2048];
 
     BIG_1024_58 r[FFLEN_2048];
     BIG_1024_58 rp[HFLEN_2048];
@@ -121,11 +118,7 @@
     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);
-    FF_2048_invmodp(invpq, p, q, HFLEN_2048);
+    FF_2048_invmodp(invpq, m->p, m->q, HFLEN_2048);
 
     if (RNG != NULL)
     {
@@ -137,17 +130,17 @@
     }
 
     // Compute r mod (p-1) and r mod (q-1) for exponent with CRT
-    FF_2048_copy(hws, p, HFLEN_2048);
+    FF_2048_copy(hws, m->p, HFLEN_2048);
     FF_2048_dec(hws, 1, HFLEN_2048);
     FF_2048_dmod(rp, r, hws, HFLEN_2048);
 
-    FF_2048_copy(hws, q, HFLEN_2048);
+    FF_2048_copy(hws, m->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, n, FFLEN_2048);
+    FF_2048_toOctet(&W, m->n, FFLEN_2048);
     hash_oct(&sha, &W);
 
     // Duplicate the state of H so it can be used as H'(N, ?)
@@ -163,21 +156,21 @@
         generator(&mgf, i, &W);
 
         FF_2048_fromOctet(ws, &W, FFLEN_2048);
-        FF_2048_mod(ws, n, FFLEN_2048);
+        FF_2048_mod(ws, m->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, p, HFLEN_2048);
-        FF_2048_ct_pow(zrp, hws, rp, p, HFLEN_2048, HFLEN_2048);
+        FF_2048_dmod(hws, ws, m->p, HFLEN_2048);
+        FF_2048_ct_pow(zrp, hws, rp, m->p, HFLEN_2048, HFLEN_2048);
 
         // Compute Z_i ^ r mod Q
-        FF_2048_dmod(hws, ws, q, HFLEN_2048);
-        FF_2048_ct_pow(zrq, hws, rq, q, HFLEN_2048, HFLEN_2048);
+        FF_2048_dmod(hws, ws, m->q, HFLEN_2048);
+        FF_2048_ct_pow(zrq, hws, rq, m->q, HFLEN_2048, HFLEN_2048);
 
         // Combine Z_i ^ r mod N with CRT
-        FF_2048_crt(ws, zrp, zrq, p, invpq, n, HFLEN_2048);
+        FF_2048_crt(ws, zrp, zrq, m->p, invpq, m->n, HFLEN_2048);
 
         // Process Z_i ^ r mod N in H
         FF_2048_toOctet(&W, ws, FFLEN_2048);
@@ -205,7 +198,7 @@
     FF_2048_fromOctet(e, &W, HFLEN_2048);
 
     // N - phi(N) = P + Q - 1
-    FF_2048_add(hws, p, q, HFLEN_2048);
+    FF_2048_add(hws, m->p, m->q, HFLEN_2048);
     FF_2048_dec(hws, 1, HFLEN_2048);
 
     // e * (N - phi(N))
@@ -218,18 +211,15 @@
     FF_2048_toOctet(Y, ws, FFLEN_2048);
 
     // 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);
+    FF_2048_zero(r,     FFLEN_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, octet *ID, octet *AD)
+int FACTORING_ZK_verify(octet *N, octet *E, octet *Y, const octet *ID, const octet *AD)
 {
     int i;
 
@@ -330,3 +320,18 @@
     return FACTORING_ZK_OK;
 }
 
+void FACTORING_ZK_modulus_kill(FACTORING_ZK_modulus *m)
+{
+    FF_2048_zero(m->p,     HFLEN_2048);
+    FF_2048_zero(m->q,     HFLEN_2048);
+    FF_2048_zero(m->invpq, HFLEN_2048);
+}
+
+void FACTORING_ZK_modulus_fromOctets(FACTORING_ZK_modulus *m, octet *P, octet *Q)
+{
+    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_invmodp(m->invpq, m->p, m->q, HFLEN_2048);
+}
diff --git a/src/schnorr.c b/src/schnorr.c
index f5082ce..4e72740 100644
--- a/src/schnorr.c
+++ b/src/schnorr.c
@@ -75,7 +75,7 @@
     BIG_256_56_zero(r);
 }
 
-void SCHNORR_challenge(const octet *V, const octet *C, octet *ID, octet *AD, octet *E)
+void SCHNORR_challenge(const octet *V, const octet *C, const octet *ID, const octet *AD, octet *E)
 {
     hash256 sha;
 
@@ -226,7 +226,7 @@
     return SCHNORR_OK;
 }
 
-void SCHNORR_D_challenge(const octet *R, const octet *V, const octet *C, octet *ID, octet *AD, octet *E)
+void SCHNORR_D_challenge(const octet *R, const octet *V, const octet *C, const octet *ID, const octet *AD, octet *E)
 {
     hash256 sha;
 
diff --git a/test/smoke/test_factoring_zk_smoke.c b/test/smoke/test_factoring_zk_smoke.c
index 2984c1c..32df6fe 100644
--- a/test/smoke/test_factoring_zk_smoke.c
+++ b/test/smoke/test_factoring_zk_smoke.c
@@ -48,8 +48,7 @@
     char y[FS_2048];
     octet Y = {0, sizeof(y), y};
 
-    BIG_1024_58 zero[HFLEN_2048];
-    FF_2048_zero(zero, HFLEN_2048);
+    FACTORING_ZK_modulus m;
 
     // Deterministic RNG for testing
     char seed[64] = {0};
@@ -65,7 +64,8 @@
     OCT_fromHex(&N, N_hex);
 
     // ZK proof
-    FACTORING_ZK_prove(&RNG, &P, &Q, &ID, &AD, NULL, &E, &Y);
+    FACTORING_ZK_modulus_fromOctets(&m, &P, &Q);
+    FACTORING_ZK_prove(&RNG, &m, &ID, &AD, NULL, &E, &Y);
 
     // Verify proof
     if (FACTORING_ZK_verify(&N, &E, &Y, &ID, &AD) != FACTORING_ZK_OK)
@@ -74,6 +74,26 @@
         exit(EXIT_FAILURE);
     }
 
+    // Clean memory
+    FACTORING_ZK_modulus_kill(&m);
+    if (!FF_2048_iszilch(m.p, HFLEN_2048))
+    {
+        printf("FAILURE FACTORING_ZK_modulus_kill p\n");
+        exit(EXIT_FAILURE);
+    }
+
+    if (!FF_2048_iszilch(m.q, HFLEN_2048))
+    {
+        printf("FAILURE FACTORING_ZK_modulus_kill q\n");
+        exit(EXIT_FAILURE);
+    }
+
+    if (!FF_2048_iszilch(m.invpq, HFLEN_2048))
+    {
+        printf("FAILURE FACTORING_ZK_modulus_kill invpq\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 9712dd5..7f0b2a8 100644
--- a/test/unit/test_factoring_zk_prove.c
+++ b/test/unit/test_factoring_zk_prove.c
@@ -82,6 +82,8 @@
     char y[FS_2048];
     octet Y = {0, sizeof(y), y};
 
+    FACTORING_ZK_modulus m;
+
     // Line terminating a test vector
     const char *last_line = Yline;
 
@@ -120,7 +122,8 @@
                 AD_ptr = &AD;
             }
 
-            FACTORING_ZK_prove(NULL, &P, &Q, &ID, AD_ptr, &R, &E, &Y);
+            FACTORING_ZK_modulus_fromOctets(&m, &P, &Q);
+            FACTORING_ZK_prove(NULL, &m, &ID, AD_ptr, &R, &E, &Y);
 
             compare_OCT(fp, testNo, "FACTORING_ZK_prove E", &E, &EGOLDEN);
             compare_OCT(fp, testNo, "FACTORING_ZK_prove Y", &Y, &YGOLDEN);