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

kmccusker pushed a commit to branch issue51
in repository https://gitbox.apache.org/repos/asf/incubator-milagro-crypto-c.git


The following commit(s) were added to refs/heads/issue51 by this push:
     new 39c881a  added paillier code
39c881a is described below

commit 39c881a01608cc58e5df95db770d9afd9640a783
Author: Kealan McCusker <[email protected]>
AuthorDate: Mon Nov 11 10:52:01 2019 +0000

    added paillier code
---
 include/paillier.h | 162 +++++++++++++
 src/paillier.c     | 661 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 823 insertions(+)

diff --git a/include/paillier.h b/include/paillier.h
new file mode 100644
index 0000000..2dcacf9
--- /dev/null
+++ b/include/paillier.h
@@ -0,0 +1,162 @@
+/*
+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.
+*/
+
+/**
+ * @file paillier.h
+ * @brief Paillier declarations
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <amcl/ff_8192.h>
+#include <amcl/ff_4096.h>
+#include <amcl/ff_2048.h>
+#include <amcl/randapi.h>
+
+#define HASH_TYPE SHA256  /**< Hash function used */
+
+// Field size
+#define FS_8192 MODBYTES_512_60*FFLEN_8192    /**< 8192 field size in bytes */
+#define FS_4096 MODBYTES_512_60*FFLEN_4096    /**< 4096 field size in bytes */
+#define FS_2048 MODBYTES_1024_58*FFLEN_2048   /**< 2048 field size in bytes */
+
+// Half field size
+#define HFS_8192 MODBYTES_512_60*HFLEN_8192   /**< Half 8192 field size in 
bytes */
+#define HFS_4096 MODBYTES_512_60*HFLEN_4096   /**< Half 4096 field size in 
bytes */
+#define HFS_2048 MODBYTES_1024_58*HFLEN_2048  /**< Half 2048 field size in 
bytes */
+
+/*! \brief Truncates an octet string
+ *
+ *  Add the top x->len bytes of y to x
+ *
+ *  @param  y       Output octet
+ *  @param  x       Input octet
+ *  @return         Returns 0 or else error code
+ */
+void OCT_truncate(octet *y,octet *x);
+
+/*! \brief quotient of y divided by x
+ *
+ *  <ol>
+ *  <li> \f$ z = y / x \f$
+ *  </ol>
+ *
+ *  @param  x       Demominator
+ *  @param  y       Numerator
+ *  @param  z       Quotient of y divided by x
+ *  @return         Returns 0 or else error code
+ */
+int FF_4096_divide(BIG_512_60 x[], BIG_512_60 y[], BIG_512_60 z[]);
+
+/*! \brief Generate the key pair
+ *
+ *  Pick large prime numbers of the same size \f$ p \f$ and \f$ q \f$
+ *
+ *  <ol>
+ *  <li> \f$ n = pq \f$
+ *  <li> \f$ g = n + 1 \f$
+ *  <li> \f$ l = (p-1)(q-1) \f$
+ *  <li> \f$ m = l^{-1} \pmod{n} \f$
+ *  </ol>
+ *
+ *  @param  RNG              Pointer to a cryptographically secure random 
number generator
+ *  @param  P                Prime number. If RNG is NULL then this value is 
read
+ *  @param  Q                Prime number. If RNG is NULL then this value is 
read
+ *  @param  N                Public key (see above)
+ *  @param  G                Public key (see above)
+ *  @param  L                Private key (see above)
+ *  @param  M                Private key (see above)
+ *  @return                  Returns 0 or else error code
+ */
+int PAILLIER_KEY_PAIR(csprng *RNG, octet *P, octet* Q, octet* N, octet* G, 
octet* L, octet* M);
+
+/*! \brief Encrypt a plaintext
+ *
+ *  These are the encryption steps.
+ *
+ *  <ol>
+ *  <li> \f$ m < n \f$
+ *  <li> \f$ r < n \f$
+ *  <li> \f$ c = g^m.r^n\pmod{n^2} \f$
+ *  </ol>
+ *
+ *  @param  RNG              Pointer to a cryptographically secure random 
number generator
+ *  @param  N                Public key
+ *  @param  G                Public key (see above)
+ *  @param  PT               Plaintext
+ *  @param  CT               Ciphertext
+ *  @param  R                R value for testing. If RNG is NULL then this 
value is read.
+ *  @return                  Returns 0 or else error code
+ */
+int PAILLIER_ENCRYPT(csprng *RNG, octet* N, octet* G, octet* PT, octet* CT, 
octet* R);
+
+/*! \brief Decrypt ciphertext
+ *
+ *  These are the decryption steps.
+ *
+ *  <ol>
+ *  <li> \f$ n2  = n*n \f$
+ *  <li> \f$ ctl = ct^l \pmod{n2} - 1 \f$
+ *  <li> \f$ ctln = ctl / n \f$
+ *  <li> \f$ pt = ctln * m \pmod{n} \f$
+ *  </ol>
+ *
+ *  @param   N                Public key
+ *  @param   L                Private key (see above)
+ *  @param   M                Private key (see above)
+ *  @param   CT               Ciphertext
+ *  @param   PT               Plaintext
+ *  @return                   Returns 0 or else error code
+ */
+int PAILLIER_DECRYPT(octet* N, octet* L, octet* M, octet* CT, octet* PT);
+
+/*! \brief Homomorphic addition of plaintexts
+ *
+ *  \f$ E(m1+m2) = E(m1)*E(m2) \f$
+ *
+ *  <ol>
+ *  <li> \f$ ct = ct1*ct2 \pmod{n^2} \f$
+ *  </ol>
+ *
+ *  @param   N                Public key
+ *  @param   CT1              Ciphertext one
+ *  @param   CT2              Ciphertext two
+ *  @param   CT               Ciphertext
+ *  @return                   Returns 0 or else error code
+ */
+int PAILLIER_ADD(octet* N, octet* CT1, octet* CT2, octet* CT);
+
+/*! \brief Homomorphic multipication of plaintexts
+ *
+ *  \f$ E(m1*m2) = E(m1)^{m2} \f$
+ *
+ *  <ol>
+ *  <li> \f$ ct = ct1^{m2} \pmod{n^2} \f$
+ *  </ol>
+ *
+ *  @param   N                Public key
+ *  @param   CT1              Ciphertext one
+ *  @param   PT               Plaintext constant
+ *  @param   CT               Ciphertext
+ *  @return                   Returns 0 or else error code
+ */
+int PAILLIER_MULT(octet* N, octet* CT1, octet* PT, octet* CT);
diff --git a/src/paillier.c b/src/paillier.c
new file mode 100644
index 0000000..dcbb03c
--- /dev/null
+++ b/src/paillier.c
@@ -0,0 +1,661 @@
+/*
+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.
+*/
+
+/* test driver and function exerciser for Paillier functions */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <amcl/ff_8192.h>
+#include <amcl/ff_4096.h>
+#include <amcl/ff_2048.h>
+#include <amcl/randapi.h>
+#include <amcl/paillier.h>
+
+/* Truncates an octet string */
+void OCT_truncate(octet *y,octet *x)
+{
+    /* y < x */
+    int i=0;
+    int j=0;
+    if (x==NULL) return;
+    if (y==NULL) return;
+
+    for (i=0; i<y->len; i++)
+    {
+        j=x->len+i;
+        if (i>=y->max)
+        {
+            y->len=y->max;
+            return;
+        }
+        y->val[i]=x->val[j];
+    }
+}
+
+int FF_4096_divide(BIG_512_60 x[], BIG_512_60 y[], BIG_512_60 z[])
+{
+    BIG_512_60 d[FFLEN_4096];
+    BIG_512_60 q[FFLEN_4096];
+
+    FF_4096_one(q,FFLEN_4096);
+    FF_4096_zero(d,FFLEN_4096);
+    FF_4096_zero(z,FFLEN_4096);
+    FF_4096_add(d,d,x,FFLEN_4096);
+
+    while(FF_4096_comp(d,y,FFLEN_4096) <= 0)
+    {
+        // left shift the denominator until bigger that remainder
+        while(FF_4096_comp(d,y,FFLEN_4096) == -1)
+        {
+            FF_4096_shl(d,FFLEN_4096);
+            FF_4096_shl(q,FFLEN_4096);
+        }
+
+        // Right shift the denominator if bigger than the remainder
+        if(FF_4096_comp(d,y,FFLEN_4096) == 1)
+        {
+            FF_4096_shr(q,FFLEN_4096);
+            FF_4096_shr(d,FFLEN_4096);
+        }
+
+        // y = y - d i.e. remainder
+        FF_4096_sub(y,y,d,FFLEN_4096);
+        FF_4096_norm(y,FFLEN_4096);
+
+        // z = z + q i.e. update quotient
+        FF_4096_add(z,z,q,FFLEN_4096);
+
+        // Reset values
+        FF_4096_one(q,FFLEN_4096);
+        FF_4096_zero(d,FFLEN_4096);
+        FF_4096_add(d,d,x,FFLEN_4096);
+    }
+
+    return 0;
+}
+
+/* generate a Paillier key pair */
+int PAILLIER_KEY_PAIR(csprng *RNG, octet *P, octet* Q, octet* N, octet* G, 
octet* L, octet* M)
+{
+    BIG_1024_58 p[HFLEN_2048];
+    BIG_1024_58 q[HFLEN_2048];
+    BIG_1024_58 p1[HFLEN_2048];
+    BIG_1024_58 q1[HFLEN_2048];
+
+    // Public key
+    BIG_1024_58 n[FFLEN_2048];
+    BIG_1024_58 g[FFLEN_2048];
+
+    // secret key
+    BIG_1024_58 l[FFLEN_2048];
+    BIG_1024_58 m[FFLEN_2048];
+
+    if (RNG!=NULL)
+    {
+
+        // p
+        FF_2048_random(p,RNG,HFLEN_2048);
+        while (FF_2048_lastbits(p,2)!=3)
+        {
+            FF_2048_inc(p,1,HFLEN_2048);
+        }
+        while (!FF_2048_prime(p,RNG,HFLEN_2048))
+        {
+            FF_2048_inc(p,4,HFLEN_2048);
+        }
+
+        // p1=p-1
+        FF_2048_copy(p1,p,HFLEN_2048);
+        FF_2048_dec(p1,1,HFLEN_2048);
+
+        // q
+        FF_2048_random(q,RNG,HFLEN_2048);
+        while (FF_2048_lastbits(q,2)!=3)
+        {
+            FF_2048_inc(q,1,HFLEN_2048);
+        }
+        while (!FF_2048_prime(q,RNG,HFLEN_2048))
+        {
+            FF_2048_inc(q,4,HFLEN_2048);
+        }
+
+        // q1 = q-1
+        FF_2048_copy(q1,q,HFLEN_2048);
+        FF_2048_dec(q1,1,HFLEN_2048);
+    }
+    else
+    {
+        FF_2048_fromOctet(p,P,HFLEN_2048);
+        FF_2048_fromOctet(q,Q,HFLEN_2048);
+
+        FF_2048_copy(p1,p,HFLEN_2048);
+        FF_2048_dec(p1,1,HFLEN_2048);
+
+        FF_2048_copy(q1,q,HFLEN_2048);
+        FF_2048_dec(q1,1,HFLEN_2048);
+    }
+
+    // n = p * q
+    FF_2048_mul(n,p,q,HFLEN_2048);
+
+    // g = n + 1
+    FF_2048_copy(g,n,FFLEN_2048);
+    FF_2048_inc(g,1,FFLEN_2048);
+
+    // l = (p-1) * (q-1)
+    FF_2048_mul(l,p1,q1,HFLEN_2048);
+
+    // m = ( (p-1) * (q-1) ^{-1} mod n
+    FF_2048_invmodp(m,l,n,FFLEN_2048);
+
+    // Output
+    FF_2048_toOctet(P, p, HFLEN_2048);
+    FF_2048_toOctet(Q, q, HFLEN_2048);
+
+    FF_2048_toOctet(N, n, FFLEN_2048);
+    FF_2048_toOctet(G, g, FFLEN_2048);
+
+    FF_2048_toOctet(L, l, FFLEN_2048);
+    FF_2048_toOctet(M, m, FFLEN_2048);
+
+#ifdef DEBUG
+    printf("p ");
+    FF_2048_output(p,HFLEN_2048);
+    printf("\n");
+    printf("q ");
+    FF_2048_output(q,HFLEN_2048);
+    printf("\n");
+
+    printf("n ");
+    FF_2048_output(n,FFLEN_2048);
+    printf("\n");
+    printf("g ");
+    FF_2048_output(g,FFLEN_2048);
+    printf("\n");
+
+    printf("l ");
+    FF_2048_output(l,FFLEN_2048);
+    printf("\n");
+    printf("m ");
+    FF_2048_output(m,FFLEN_2048);
+    printf("\n");
+#endif
+
+    return 0;
+}
+
+/* Paillier encrypt
+ R is for testing
+*/
+int PAILLIER_ENCRYPT(csprng *RNG, octet* N, octet* G, octet* PT, octet* CT, 
octet* R)
+{
+    // Public key
+    BIG_512_60 n[FFLEN_4096];
+    BIG_512_60 g[FFLEN_4096];
+
+    // n2 = n^2
+    BIG_512_60 n2[FFLEN_4096];
+    BIG_512_60 n28[FFLEN_8192];
+
+    // Random r < n
+    BIG_1024_58 n1[FFLEN_2048];
+    BIG_1024_58 r1[FFLEN_2048];
+    BIG_512_60 r[FFLEN_4096];
+
+    // plaintext
+    BIG_512_60 pt[FFLEN_4096];
+
+    // g^pt mod n^2
+    BIG_512_60 gpt[FFLEN_4096];
+    BIG_512_60 gpt8[FFLEN_8192];
+
+    // r^n mod n^2
+    BIG_512_60 rn[FFLEN_4096];
+    BIG_512_60 rn8[FFLEN_8192];
+
+    // ciphertext
+    BIG_512_60 ct[FFLEN_8192];
+
+    // Convert n from FF_2048 to FF_4096
+    char noct[FS_4096] = {0};
+    octet NOCT = {FS_2048,FS_4096,noct};
+    OCT_joctet(&NOCT, N);
+    FF_4096_fromOctet(n,&NOCT,FFLEN_4096);
+
+    // Convert g from FF_2048 to FF_4096
+    char goct[FS_4096] = {0};
+    octet GOCT = {FS_2048,FS_4096,goct};
+    OCT_joctet(&GOCT, G);
+    FF_4096_fromOctet(g,&GOCT,FFLEN_4096);
+
+    // n2 = n^2
+    FF_4096_sqr(n2, n, FFLEN_4096);
+
+    // In production generate R from RNG
+    if (RNG!=NULL)
+    {
+        // r < n
+        FF_2048_fromOctet(n1,N,FFLEN_2048);
+        FF_2048_randomnum(r1,n1,RNG,FFLEN_2048);
+
+        // Convert r from FF_2048 to FF_4096
+        char r1oct[FS_2048] = {0};
+        octet R1OCT = {0,FS_2048,r1oct};
+        FF_2048_toOctet(&R1OCT, r1, FFLEN_2048);
+
+        char roct[FS_4096] = {0};
+        octet ROCT = {FS_2048,FS_4096,roct};
+        OCT_joctet(&ROCT, &R1OCT);
+        FF_4096_fromOctet(r,&ROCT,FFLEN_4096);
+    }
+    else
+    {
+        // Convert r from FF_2048 to FF_4096
+        char roct[FS_4096] = {0};
+        octet ROCT = {FS_2048,FS_4096,roct};
+        OCT_joctet(&ROCT, R);
+        FF_4096_fromOctet(r,&ROCT,FFLEN_4096);
+    }
+
+    // Convert pt from FF_2048 to FF_4096
+    char ptoct[FS_4096] = {0};
+    octet PTOCT = {FS_2048,FS_4096,ptoct};
+    OCT_joctet(&PTOCT, PT);
+    FF_4096_fromOctet(pt,&PTOCT,FFLEN_4096);
+
+    // g^pt mod n^2
+    FF_4096_pow(gpt,g,pt,n2,FFLEN_4096);
+
+    // r^n mod n^2
+    FF_4096_pow(rn,r,n,n2,FFLEN_4096);
+
+    // Convert gpt from FF_4096 to FF_8192
+    char gpt1[FS_4096] = {0};
+    octet GPT1 = {0,FS_4096,gpt1};
+    FF_4096_toOctet(&GPT1, gpt, FFLEN_4096);
+
+    char gpt2[FS_8192] = {0};
+    octet GPT2 = {FS_4096,FS_8192,gpt2};
+    OCT_joctet(&GPT2, &GPT1);
+    FF_8192_fromOctet(gpt8,&GPT2,FFLEN_8192);
+
+    // Convert rn from FF_4096 to FF_8192
+    char rn1[FS_4096] = {0};
+    octet RN1 = {0,FS_4096,rn1};
+    FF_4096_toOctet(&RN1, rn, FFLEN_4096);
+
+    char rn2[FS_8192] = {0};
+    octet RN2 = {FS_4096,FS_8192,rn2};
+    OCT_joctet(&RN2, &RN1);
+    FF_8192_fromOctet(rn8,&RN2,FFLEN_8192);
+
+    // Convert n2 from FF_4096 to FF_8192
+    char n21[FS_4096] = {0};
+    octet N21 = {0,FS_4096,n21};
+    FF_4096_toOctet(&N21, n2, FFLEN_4096);
+
+    char n22[FS_8192] = {0};
+    octet N22 = {FS_4096,FS_8192,n22};
+    OCT_joctet(&N22, &N21);
+    FF_8192_fromOctet(n28,&N22,FFLEN_8192);
+
+    // ct = g^{pt}.r^n mod n^2
+    FF_8192_mul(ct,gpt8,rn8,FFLEN_8192);
+    FF_8192_mod(ct,n28,FFLEN_8192);
+
+    // Output. Convert ct from FF_8192 to FF_4096
+    char ct2[FS_8192] = {0};
+    octet CT2 = {0,FS_8192,ct2};
+    FF_8192_toOctet(&CT2, ct, FFLEN_8192);
+    CT->len = FS_4096;
+    CT2.len = FS_4096;
+    OCT_truncate(CT,&CT2);
+
+    // Output R for Debug
+    if (R!=NULL)
+    {
+        char r2[FS_4096] = {0};
+        octet R2 = {0,FS_4096,r2};
+        FF_4096_toOctet(&R2, r, FFLEN_4096);
+        R->len = FS_2048;
+        R2.len = FS_2048;
+        OCT_truncate(R,&R2);
+
+    }
+
+#ifdef DEBUG
+    printf("n ");
+    FF_4096_output(n,FFLEN_4096);
+    printf("\n\n");
+    printf("g ");
+    FF_4096_output(g,FFLEN_4096);
+    printf("\n\n");
+    printf("n2 ");
+    FF_4096_output(n2,FFLEN_4096);
+    printf("\n\n");
+    printf("r ");
+    FF_4096_output(r,FFLEN_4096);
+    printf("\n\n");
+    printf("pt ");
+    FF_4096_output(pt,FFLEN_4096);
+    printf("\n\n");
+    printf("gpt ");
+    FF_4096_output(gpt,FFLEN_4096);
+    printf("\n\n");
+    printf("rn ");
+    FF_4096_output(rn,FFLEN_4096);
+    printf("\n\n");
+    printf("gpt8 ");
+    FF_8192_output(gpt8,FFLEN_8192);
+    printf("\n\n");
+    printf("rn8 ");
+    FF_8192_output(rn8,FFLEN_8192);
+    printf("\n\n");
+    printf("ct ");
+    FF_8192_output(ct,FFLEN_8192);
+    printf("\n\n");
+    printf("CT2: ");
+    OCT_output(&CT2);
+    printf("\n");
+    printf("CT: ");
+    OCT_output(CT);
+    printf("\n");
+#endif
+
+    return 0;
+}
+
+/* Paillier decrypt */
+int PAILLIER_DECRYPT(octet* N, octet* L, octet* M, octet* CT, octet* PT)
+{
+    // Public key
+    BIG_512_60 n[FFLEN_4096];
+    BIG_512_60 n8[FFLEN_8192];
+
+    // secret key
+    BIG_512_60 l[FFLEN_4096];
+    BIG_512_60 m[FFLEN_8192];
+
+    // Ciphertext
+    BIG_512_60 ct[FFLEN_4096];
+
+    // Plaintext
+    BIG_512_60 pt[FFLEN_8192];
+
+    // n2 = n^2
+    BIG_512_60 n2[FFLEN_4096];
+
+    // ctl = ct^l mod n^2
+    BIG_512_60 ctl[FFLEN_4096];
+
+    // ctln = ctl / n
+    BIG_512_60 ctln[FFLEN_4096];
+    BIG_512_60 ctln8[FFLEN_8192];
+
+    // Convert n from FF_2048 to FF_4096
+    char noct[FS_4096] = {0};
+    octet NOCT = {FS_2048,FS_4096,noct};
+    OCT_joctet(&NOCT, N);
+    FF_4096_fromOctet(n,&NOCT,FFLEN_4096);
+
+    // Convert l from FF_2048 to FF_4096
+    char loct[FS_4096] = {0};
+    octet LOCT = {FS_2048,FS_4096,loct};
+    OCT_joctet(&LOCT, L);
+    FF_4096_fromOctet(l,&LOCT,FFLEN_4096);
+
+    // Convert m from FF_2048 to FF_8192
+    char moct[FS_8192] = {0};
+    int len = FS_2048 * 3;
+    octet MOCT = {len,FS_8192,moct};
+    OCT_joctet(&MOCT, M);
+    FF_8192_fromOctet(m,&MOCT,FFLEN_8192);
+
+    // Convert n from FF_2048 to FF_8192
+    char noct8[FS_8192] = {0};
+    len = FS_2048 * 3;
+    octet NOCT8 = {len,FS_8192,noct8};
+    OCT_joctet(&NOCT8, N);
+    FF_8192_fromOctet(n8,&NOCT8,FFLEN_8192);
+
+    FF_4096_fromOctet(ct,CT,FFLEN_4096);
+
+    // n2 = n^2
+    FF_4096_sqr(n2, n, FFLEN_4096);
+
+    // ct^l mod n^2 - 1
+    FF_4096_pow(ctl, ct,l,n2,FFLEN_4096);
+    FF_4096_dec(ctl,1,FFLEN_4096);
+
+#ifdef DEBUG
+    printf("PAILLIER_DECRYPT ctl ");
+    FF_4096_output(ctl,FFLEN_4096);
+    printf("\n\n");
+#endif
+
+    // ctln = ctl / n
+    FF_4096_divide(n, ctl, ctln);
+
+    // Convert ctln from FF_4096 to FF_8192
+    char ctln1[FS_4096] = {0};
+    octet CTLN1 = {0,FS_4096,ctln1};
+    FF_4096_toOctet(&CTLN1, ctln, FFLEN_4096);
+    char ctln2[FS_8192] = {0};
+    octet CTLN2 = {FS_4096,FS_8192,ctln2};
+    OCT_joctet(&CTLN2, &CTLN1);
+    FF_8192_fromOctet(ctln8,&CTLN2,FFLEN_8192);
+
+    // pt = ctln * m mod n
+    FF_8192_mul(pt,ctln8,m,FFLEN_8192);
+#ifdef DEBUG
+    printf("pt1 ");
+    FF_8192_output(pt,FFLEN_8192);
+    printf("\n\n");
+#endif
+    FF_8192_mod(pt,n8,FFLEN_8192);
+
+    // Output. Convert pt from FF_8192 to FF_2046
+    char pt2[FS_8192] = {0};
+    octet PT2 = {0,FS_8192,pt2};
+    FF_8192_toOctet(&PT2, pt, FFLEN_8192);
+    PT->len = FS_2048;
+    PT2.len = FS_2048*3;
+    OCT_truncate(PT,&PT2);
+
+#ifdef DEBUG
+    printf("PAILLIER_DECRYPT n ");
+    FF_4096_output(n,FFLEN_4096);
+    printf("\n\n");
+    printf("PAILLIER_DECRYPT n8 ");
+    FF_8192_output(n8,FFLEN_8192);
+    printf("\n\n");
+    printf("PAILLIER_DECRYPT l ");
+    FF_4096_output(l,FFLEN_4096);
+    printf("\n\n");
+    printf("PAILLIER_DECRYPT m ");
+    FF_8192_output(m,FFLEN_8192);
+    printf("\n\n");
+    printf("PAILLIER_DECRYPT ct ");
+    FF_4096_output(ct,FFLEN_4096);
+    printf("\n\n");
+    printf("PAILLIER_DECRYPT ctln ");
+    FF_4096_output(ctln,FFLEN_4096);
+    printf("\n\n");
+    printf("PAILLIER_DECRYPT pt ");
+    FF_8192_output(pt,FFLEN_8192);
+    printf("\n\n");
+#endif
+
+    return 0;
+
+}
+
+/* Homomorphic addition of plaintexts */
+/*  n2 = n * n
+    ct = ct1 * ct2
+    ct = ct % n2
+*/
+int PAILLIER_ADD(octet* N, octet* CT1, octet* CT2, octet* CT)
+{
+    // Public key
+    BIG_512_60 n[FFLEN_8192];
+
+    // n2 = n^2
+    BIG_512_60 n2[FFLEN_8192];
+
+    // ciphertext
+    BIG_512_60 ct1[FFLEN_8192];
+    BIG_512_60 ct2[FFLEN_8192];
+    BIG_512_60 ct[FFLEN_8192];
+
+    // Convert n from FF_2048 to FF_8192
+    char noct[FS_8192] = {0};
+    octet NOCT = {FS_2048*3,FS_8192,noct};
+    OCT_joctet(&NOCT, N);
+    FF_8192_fromOctet(n,&NOCT,FFLEN_8192);
+
+    // Convert ct1 from FF_4096 to FF_8192
+    char ct1oct[FS_8192] = {0};
+    octet CT1OCT = {FS_4096,FS_8192,ct1oct};
+    OCT_joctet(&CT1OCT, CT1);
+
+    FF_8192_fromOctet(ct1,&CT1OCT,FFLEN_8192);
+
+    // Convert ct2 from FF_4096 to FF_8192
+    char ct2oct[FS_8192] = {0};
+    octet CT2OCT = {FS_4096,FS_8192,ct2oct};
+    OCT_joctet(&CT2OCT, CT2);
+    FF_8192_fromOctet(ct2,&CT2OCT,FFLEN_8192);
+
+    // n2 = n^2
+    FF_8192_sqr(n2, n, HFLEN_8192);
+
+#ifdef DEBUG
+    printf("PAILLIER_ADD ct1 ");
+    FF_8192_output(ct1,FFLEN_8192);
+    printf("\n\n");
+    printf("PAILLIER_ADD ct2 ");
+    FF_8192_output(ct2,FFLEN_8192);
+    printf("\n\n");
+#endif
+
+    // ct = ct1 * ct2 mod n^2
+    FF_8192_mul(ct,ct1,ct2,FFLEN_8192);
+
+#ifdef DEBUG
+    printf("PAILLIER_ADD ct1 * ct2 ");
+    FF_8192_output(ct,FFLEN_8192);
+    printf("\n\n");
+#endif
+
+    FF_8192_mod(ct,n2,FFLEN_8192);
+
+    // Output. Convert ct from FF_8192 to FF_4096
+    char cto2[FS_8192] = {0};
+    octet CTO2 = {0,FS_8192,cto2};
+    FF_8192_toOctet(&CTO2, ct, FFLEN_8192);
+    CT->len = FS_4096;
+    CTO2.len = FS_4096;
+    OCT_truncate(CT,&CTO2);
+
+
+#ifdef DEBUG
+    printf("PAILLIER_ADD n ");
+    FF_8192_output(n,FFLEN_8192);
+    printf("\n\n");
+    printf("PAILLIER_ADD ct1 ");
+    FF_8192_output(ct1,FFLEN_8192);
+    printf("\n\n");
+    printf("PAILLIER_ADD ct2 ");
+    FF_8192_output(ct2,FFLEN_8192);
+    printf("\n\n");
+#endif
+
+    return 0;
+}
+
+/* Homomorphic multiplation of plaintext
+
+    ct = ct1 ^ pt mod n^2
+
+*/
+int PAILLIER_MULT(octet* N, octet* CT1, octet* PT, octet* CT)
+{
+
+    // Public key
+    BIG_512_60 n[FFLEN_4096];
+
+    // n^2
+    BIG_512_60 n2[FFLEN_4096];
+
+    // Ciphertext
+    BIG_512_60 ct1[FFLEN_4096];
+
+    // Plaintext
+    BIG_512_60 pt[FFLEN_4096];
+
+    // Ciphertext output. ct = ct1 ^ pt mod n^2
+    BIG_512_60 ct[FFLEN_4096];
+
+    // Convert n from FF_2048 to FF_4096
+    char noct[FS_4096] = {0};
+    octet NOCT = {FS_2048,FS_4096,noct};
+    OCT_joctet(&NOCT, N);
+    FF_4096_fromOctet(n,&NOCT,FFLEN_4096);
+
+    // Convert pt from FF_2048 to FF_4096
+    char ptoct[FS_4096] = {0};
+    octet PTOCT = {FS_2048,FS_4096,ptoct};
+    OCT_joctet(&PTOCT, PT);
+    FF_4096_fromOctet(pt,&PTOCT,FFLEN_4096);
+
+    // n2 = n^2
+    FF_4096_sqr(n2, n, FFLEN_4096);
+    FF_4096_fromOctet(ct1,CT1,FFLEN_4096);
+
+
+    // ct1^pt mod n^2
+    FF_4096_pow(ct,ct1,pt,n2,FFLEN_4096);
+
+    // output
+    FF_4096_toOctet(CT, ct, FFLEN_4096);
+
+#ifdef DEBUG
+    printf("PAILLIER_MULT n: ");
+    FF_4096_output(n,FFLEN_4096);
+    printf("\n\n");
+    printf("PAILLIER_MULT n2: ");
+    FF_4096_output(n2,FFLEN_4096);
+    printf("\n\n");
+    printf("PAILLIER_MULT ct1: ");
+    FF_4096_output(ct1,FFLEN_4096);
+    printf("\n\n");
+    printf("PAILLIER_MULT pt: ");
+    FF_4096_output(pt,FFLEN_4096);
+    printf("\n\n");
+    printf("PAILLIER_MULT ct: ");
+    FF_4096_output(ct,FFLEN_4096);
+    printf("\n\n");
+#endif
+
+    return 0;
+}
+

Reply via email to