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 2019/11/20 13:07:29 UTC

[incubator-milagro-crypto-c] branch issue51 updated (a40adfc -> 50fd677)

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

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


    from a40adfc  add missing import to paillier consistency test
     new 22b7941  remove paillier from non 64 bit builds
     new c4506dd  use custom double exponentiation for paillier encryption
     new 50fd677  improve ff conversions

The 3 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.


Summary of changes:
 CMakeLists.txt     |   2 +-
 Makefile           |   6 +-
 include/ff.h.in    |  11 +++
 include/paillier.h |  10 ---
 src/ff.c.in        |  38 +++++++++
 src/paillier.c     | 234 +++++++++++++----------------------------------------
 6 files changed, 109 insertions(+), 192 deletions(-)


[incubator-milagro-crypto-c] 01/03: remove paillier from non 64 bit builds

Posted by sa...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

View the commit online:
https://github.com/apache/incubator-milagro-crypto-c/commit/22b7941cd331f0e09e79d5637d230fbc3e766031

commit 22b7941cd331f0e09e79d5637d230fbc3e766031
Author: samuele-andreoli <sa...@yahoo.it>
AuthorDate: Tue Nov 19 17:00:18 2019 +0000

    remove paillier from non 64 bit builds
---
 CMakeLists.txt | 2 +-
 Makefile       | 6 ++++--
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 746432b..ace56aa 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -118,7 +118,7 @@ option(BUILD_MPIN     "Build MPIN"     ON)
 option(BUILD_WCC      "Build WCC"      ON)
 option(BUILD_X509     "BUild X509"     ON)
 option(BUILD_BLS      "Build BLS"      ON)
-option(BUILD_PAILLIER "Build Paillier" ON)
+option(BUILD_PAILLIER "Build Paillier" OFF)
 log(BUILD_MPIN)
 log(BUILD_WCC)
 log(BUILD_X509)
diff --git a/Makefile b/Makefile
index f98eed0..0961d95 100644
--- a/Makefile
+++ b/Makefile
@@ -60,6 +60,7 @@ BUILDS_MISC64=LINUX_64BIT_C25519_RSA2048:-DWORD_SIZE=64,,-DCMAKE_INSTALL_PREFIX=
 	LINUX_64BIT_GOLDILOCKS:-DWORD_SIZE=64,,-DCMAKE_INSTALL_PREFIX=/opt/amcl,,-DAMCL_CURVE=GOLDILOCKS,,-DAMCL_RSA=2048 \
 	LINUX_64BIT_C41417:-DWORD_SIZE=64,,-DCMAKE_INSTALL_PREFIX=/opt/amcl,,-DAMCL_CURVE=C41417,,-DAMCL_RSA=2048 \
 	LINUX_64BIT_SECP256K1:-DWORD_SIZE=64,,-DCMAKE_INSTALL_PREFIX=/opt/amcl,,-DAMCL_CURVE=SECP256K1,,-DAMCL_RSA=2048 \
+	LINUX_64BIT_PAILLIER:-DWORD_SIZE=64,,-DCMAKE_INSTALL_PREFIX=/opt/amcl,,-DAMCL_CURVE=,,-DAMCL_RSA=,,-DBUILD_PAILLIER=ON \
 	WINDOWS_64BIT_BLS381:-DWORD_SIZE=64,,-DAMCL_CURVE=BLS381,,-DAMCL_RSA=2048,,-DCMAKE_TOOLCHAIN_FILE=../../resources/cmake/mingw64-cross.cmake \
 	WINDOWS_64BIT_BLS381_STATIC:-DWORD_SIZE=64,,-DAMCL_CURVE=BLS381,,-DAMCL_RSA=2048,,-DCMAKE_TOOLCHAIN_FILE=../../resources/cmake/mingw64-cross.cmake,,-DBUILD_SHARED_LIBS=OFF
 
@@ -95,7 +96,8 @@ BUILDS_ASAN=LINUX_64BIT_BLS381_ASan:-DWORD_SIZE=64,,-DCMAKE_BUILD_TYPE=ASan,,-DA
 	LINUX_64BIT_NIST521_ASan:-DWORD_SIZE=64,,-DCMAKE_BUILD_TYPE=ASan,,-DAMCL_CURVE=NIST521,,-DAMCL_RSA=2048 \
 	LINUX_64BIT_C25519_RSA2048_MONTGOMERY_ASan:-DWORD_SIZE=64,,-DCMAKE_BUILD_TYPE=ASan,,-DAMCL_CURVE=C25519,,-DAMCL_RSA=2048 \
 	LINUX_64BIT_C25519_RSA2048_EDWARDS_ASan:-DWORD_SIZE=64,,-DCMAKE_BUILD_TYPE=ASan,,-DAMCL_CURVE=C25519,,-DAMCL_RSA=2048 \
-	LINUX_64BIT_C41417_ASan:-DWORD_SIZE=64,,-DCMAKE_BUILD_TYPE=ASan,,-DAMCL_CURVE=C41417,,-DAMCL_RSA=2048 
+	LINUX_64BIT_C41417_ASan:-DWORD_SIZE=64,,-DCMAKE_BUILD_TYPE=ASan,,-DAMCL_CURVE=C41417,,-DAMCL_RSA=2048 \
+	LINUX_64BIT_PAILLIER_ASan:-DWORD_SIZE=64,,-DCMAKE_INSTALL_PREFIX=/opt/amcl,,-DAMCL_CURVE=,,-DAMCL_RSA=,,-DBUILD_PAILLIER=ON
 
 BUILDS_BN256=LINUX_64BIT_BN254CX:-DWORD_SIZE=64,,-DAMCL_CURVE=BN254CX,,-DAMCL_RSA=2048,,-DCMAKE_INSTALL_PREFIX=/opt/amcl,,${WRAPPYTHON} \
 	LINUX_64BIT_BN254:-DWORD_SIZE=64,,-DAMCL_CURVE=BN254,,-DAMCL_RSA=2048,,-DCMAKE_INSTALL_PREFIX=/opt/amcl \
@@ -107,7 +109,7 @@ BUILDS_BN256=LINUX_64BIT_BN254CX:-DWORD_SIZE=64,,-DAMCL_CURVE=BN254CX,,-DAMCL_RS
 	LINUX_32BIT_NIST256_BN254CX_RSA2048:-DCMAKE_C_FLAGS=-m32,,-DWORD_SIZE=32,,-DCMAKE_INSTALL_PREFIX=/opt/amcl,,-DAMCL_CURVE=NIST256,BN254CX,,-DAMCL_RSA=2048 \
 	LINUX_16BIT_BN254CX:-DWORD_SIZE=16,,-DCMAKE_INSTALL_PREFIX=/opt/amcl,,-DAMCL_CURVE=BN254CX,,-DAMCL_RSA=2048 \
 
-BUILDS_COVERAGE=LINUX_64BIT_COVERAGE:-DWORD_SIZE=64,,-DCMAKE_BUILD_TYPE=Coverage,,-DAMCL_CURVE=NIST256,BLS381,,-DAMCL_RSA=2048
+BUILDS_COVERAGE=LINUX_64BIT_COVERAGE:-DWORD_SIZE=64,,-DCMAKE_BUILD_TYPE=Coverage,,-DAMCL_CURVE=NIST256,BLS381,,-DAMCL_RSA=2048,,-DBUILD_PAILLIER=ON
 
 # Merge all build types in a single list
 BUILDS_64=$(BUILDS_PF64) $(BUILDS_NIST64) $(BUILDS_MISC64)


[incubator-milagro-crypto-c] 03/03: improve ff conversions

Posted by sa...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

View the commit online:
https://github.com/apache/incubator-milagro-crypto-c/commit/50fd67711a1f7df68caff5b119038607a27cbf8f

commit 50fd67711a1f7df68caff5b119038607a27cbf8f
Author: samuele-andreoli <sa...@yahoo.it>
AuthorDate: Wed Nov 20 11:16:07 2019 +0000

    improve ff conversions
---
 include/paillier.h |  10 ----
 src/paillier.c     | 168 ++++++++++++++---------------------------------------
 2 files changed, 43 insertions(+), 135 deletions(-)

diff --git a/include/paillier.h b/include/paillier.h
index fb35603..4f9fee8 100644
--- a/include/paillier.h
+++ b/include/paillier.h
@@ -43,16 +43,6 @@ under the License.
 #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>
diff --git a/src/paillier.c b/src/paillier.c
index 15a901c..d19776a 100644
--- a/src/paillier.c
+++ b/src/paillier.c
@@ -28,27 +28,6 @@ under the License.
 #include "ff_2048.h"
 #include "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];
@@ -203,7 +182,6 @@ int PAILLIER_ENCRYPT(csprng *RNG, octet* N, octet* G, octet* PT, octet* CT, octe
 
     // n2 = n^2
     BIG_512_60 n2[FFLEN_4096];
-    BIG_512_60 n28[FFLEN_8192];
 
     // Random r < n
     BIG_1024_58 n1[FFLEN_2048];
@@ -213,29 +191,14 @@ int PAILLIER_ENCRYPT(csprng *RNG, octet* N, octet* G, octet* PT, octet* CT, octe
     // 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);
+    BIG_512_60 ct[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);
+    FF_4096_zero(n, FFLEN_4096);
+    FF_4096_fromOctet(n,N,HFLEN_4096);
 
+    FF_4096_zero(g, FFLEN_4096);
+    FF_4096_fromOctet(g,G,HFLEN_4096);
 
     // In production generate R from RNG
     if (RNG!=NULL)
@@ -245,28 +208,22 @@ int PAILLIER_ENCRYPT(csprng *RNG, octet* N, octet* G, octet* PT, octet* CT, octe
         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);
+        char roct[FS_2048] = {0};
+        octet ROCT = {0,FS_2048,roct};
+        FF_2048_toOctet(&ROCT, r1, FFLEN_2048);
+
+        FF_4096_zero(r, FFLEN_4096);
+        FF_4096_fromOctet(r,&ROCT,HFLEN_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);
+        FF_4096_zero(r, FFLEN_4096);
+        FF_4096_fromOctet(r,R,HFLEN_4096);
     }
 
     FF_4096_zero(pt, FFLEN_4096);
     FF_4096_fromOctet(pt,PT,HFLEN_4096);
 
-
     // n2 = n^2
     FF_4096_sqr(n2, n, HFLEN_4096);
     FF_4096_norm(n2, FFLEN_4096);
@@ -280,12 +237,7 @@ int PAILLIER_ENCRYPT(csprng *RNG, octet* N, octet* G, octet* PT, octet* CT, octe
     // 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);
+        FF_4096_toOctet(R, r, HFLEN_4096);
     }
 
 #ifdef DEBUG
@@ -355,28 +307,20 @@ int PAILLIER_DECRYPT(octet* N, octet* L, octet* M, octet* CT, octet* PT)
     // ctln = ctl / n
     BIG_512_60 ctln[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 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_4096
-    char moct[FS_4096] = {0};
-    octet MOCT = {FS_2048,FS_4096,moct};
-    OCT_joctet(&MOCT, M);
-    FF_4096_fromOctet(m,&MOCT,FFLEN_4096);
+    FF_4096_zero(n, FFLEN_4096);
+    FF_4096_fromOctet(n,N,HFLEN_4096);
+
+    FF_4096_zero(l, FFLEN_4096);
+    FF_4096_fromOctet(l,L,HFLEN_4096);
+
+    FF_4096_zero(m, FFLEN_4096);
+    FF_4096_fromOctet(m,M,HFLEN_4096);
 
     FF_4096_fromOctet(ct,CT,FFLEN_4096);
 
     // n2 = n^2
-    FF_4096_sqr(n2, n, FFLEN_4096);
+    FF_4096_sqr(n2, n, HFLEN_4096);
+    FF_4096_norm(n2, FFLEN_4096);
 
     // ct^l mod n^2 - 1
     FF_4096_pow(ctl,ct,l,n2,FFLEN_4096);
@@ -396,7 +340,7 @@ int PAILLIER_DECRYPT(octet* N, octet* L, octet* M, octet* CT, octet* PT)
     // pt = ctln * m mod n
     // the result fits into a FF_4096 element,
     // since both m and ctln fit into a FF_2048 element
-    FF_4096_mul(pt, ctln, m, FFLEN_4096);
+    FF_4096_mul(pt, ctln, m, HFLEN_4096);
 #ifdef DEBUG
     printf("pt1 ");
     FF_4096_output(pt,FFLEN_4096);
@@ -404,13 +348,8 @@ int PAILLIER_DECRYPT(octet* N, octet* L, octet* M, octet* CT, octet* PT)
 #endif
     FF_4096_mod(pt,n,FFLEN_4096);
 
-    // Output. Convert pt from FF_4096 to FF_2046
-    char pt2[FS_4096] = {0};
-    octet PT2 = {0,FS_4096,pt2};
-    FF_4096_toOctet(&PT2, pt, FFLEN_4096);
-    PT->len = FS_2048;
-    PT2.len = FS_2048;
-    OCT_truncate(PT,&PT2);
+    // Output
+    FF_4096_toOctet(PT, pt, HFLEN_4096);
 
 #ifdef DEBUG
     printf("PAILLIER_DECRYPT n ");
@@ -455,24 +394,14 @@ int PAILLIER_ADD(octet* N, octet* CT1, octet* CT2, octet* CT)
     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);
+    FF_8192_zero(n,FFLEN_8192);
+    FF_8192_fromOctet(n,N,FFLEN_8192/4);
 
-    // 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_zero(ct1,FFLEN_8192);
+    FF_8192_fromOctet(ct1,CT1,HFLEN_8192);
 
-    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);
+    FF_8192_zero(ct2,FFLEN_8192);
+    FF_8192_fromOctet(ct2,CT2,HFLEN_8192);
 
     // n2 = n^2
     FF_8192_sqr(n2, n, HFLEN_8192);
@@ -487,7 +416,7 @@ int PAILLIER_ADD(octet* N, octet* CT1, octet* CT2, octet* CT)
 #endif
 
     // ct = ct1 * ct2 mod n^2
-    FF_8192_mul(ct,ct1,ct2,FFLEN_8192);
+    FF_8192_mul(ct,ct1,ct2,HFLEN_8192);
 
 #ifdef DEBUG
     printf("PAILLIER_ADD ct1 * ct2 ");
@@ -497,14 +426,8 @@ int PAILLIER_ADD(octet* N, octet* CT1, octet* CT2, octet* CT)
 
     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);
-
+    // Output
+    FF_8192_toOctet(CT, ct, HFLEN_8192);
 
 #ifdef DEBUG
     printf("PAILLIER_ADD n ");
@@ -544,21 +467,17 @@ int PAILLIER_MULT(octet* N, octet* CT1, octet* PT, octet* CT)
     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);
+    FF_4096_zero(n, FFLEN_4096);
+    FF_4096_fromOctet(n,N,HFLEN_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);
+    FF_4096_zero(pt, FFLEN_4096);
+    FF_4096_fromOctet(pt,PT,HFLEN_4096);
 
-    // n2 = n^2
-    FF_4096_sqr(n2, n, FFLEN_4096);
     FF_4096_fromOctet(ct1,CT1,FFLEN_4096);
 
+    // n2 = n^2
+    FF_4096_sqr(n2, n, HFLEN_4096);
+    FF_4096_norm(n2, FFLEN_4096);
 
     // ct1^pt mod n^2
     FF_4096_pow(ct,ct1,pt,n2,FFLEN_4096);
@@ -586,4 +505,3 @@ int PAILLIER_MULT(octet* N, octet* CT1, octet* PT, octet* CT)
 
     return 0;
 }
-


[incubator-milagro-crypto-c] 02/03: use custom double exponentiation for paillier encryption

Posted by sa...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

View the commit online:
https://github.com/apache/incubator-milagro-crypto-c/commit/c4506dd623e3578b1b6eb18c782a5b44c4e80cb0

commit c4506dd623e3578b1b6eb18c782a5b44c4e80cb0
Author: samuele-andreoli <sa...@yahoo.it>
AuthorDate: Wed Nov 20 10:47:13 2019 +0000

    use custom double exponentiation for paillier encryption
---
 include/ff.h.in | 11 ++++++++++
 src/ff.c.in     | 38 +++++++++++++++++++++++++++++++++++
 src/paillier.c  | 62 ++++++++++-----------------------------------------------
 3 files changed, 59 insertions(+), 52 deletions(-)

diff --git a/include/ff.h.in b/include/ff.h.in
index c3be699..d69b819 100644
--- a/include/ff.h.in
+++ b/include/ff.h.in
@@ -292,5 +292,16 @@ extern int FF_WWW_prime(BIG_XXX *x,csprng *R,int n);
 	@param n size of FF in BIGs
  */
 extern void FF_WWW_pow2(BIG_XXX *r,BIG_XXX *x,BIG_XXX e,BIG_XXX *y,BIG_XXX f,BIG_XXX *m,int n);
+/**	@brief Calculate r=x^e.y^f mod m for big e and f
+ *
+	@param r FF instance, on exit = x^e.y^f mod p
+	@param x FF instance
+	@param e FF exponent
+	@param y FF instance
+	@param f FF exponent
+	@param m FF modulus
+	@param n size of FF in BIGs
+ */
+extern void FF_WWW_bpow2(BIG_XXX *r,BIG_XXX *x,BIG_XXX *e,BIG_XXX *y,BIG_XXX *f,BIG_XXX *p,int n);
 
 #endif
diff --git a/src/ff.c.in b/src/ff.c.in
index 8f07849..1d495bf 100644
--- a/src/ff.c.in
+++ b/src/ff.c.in
@@ -921,6 +921,44 @@ void FF_WWW_pow2(BIG_XXX r[],BIG_XXX x[],BIG_XXX e,BIG_XXX y[],BIG_XXX f,BIG_XXX
     FF_WWW_redc(r,p,ND,n);
 }
 
+/* double exponentiation r=x^e.y^f mod p */
+void FF_WWW_bpow2(BIG_XXX r[],BIG_XXX x[],BIG_XXX e[],BIG_XXX y[],BIG_XXX f[],BIG_XXX p[],int n)
+{
+    int i,eb,fb;
+#ifndef C99
+    BIG_XXX xn[FFLEN_WWW],yn[FFLEN_WWW],xy[FFLEN_WWW],ND[FFLEN_WWW];
+#else
+    BIG_XXX xn[n],yn[n],xy[n],ND[n];
+#endif
+
+    FF_WWW_invmod2m(ND,p,n);
+
+    FF_WWW_copy(xn,x,n);
+    FF_WWW_copy(yn,y,n);
+    FF_WWW_nres(xn,p,n);
+    FF_WWW_nres(yn,p,n);
+    FF_WWW_modmul(xy,xn,yn,p,ND,n);
+    FF_WWW_one(r,n);
+    FF_WWW_nres(r,p,n);
+
+    for (i=8*MODBYTES_XXX*(n-1); i>=0; i--)
+    {
+        eb=BIG_XXX_bit(e[i/BIGBITS_XXX],i%BIGBITS_XXX);
+        fb=BIG_XXX_bit(f[i/BIGBITS_XXX],i%BIGBITS_XXX);
+        FF_WWW_modsqr(r,r,p,ND,n);
+        if (eb==1)
+        {
+            if (fb==1) FF_WWW_modmul(r,r,xy,p,ND,n);
+            else FF_WWW_modmul(r,r,xn,p,ND,n);
+        }
+        else
+        {
+            if (fb==1) FF_WWW_modmul(r,r,yn,p,ND,n);
+        }
+    }
+    FF_WWW_redc(r,p,ND,n);
+}
+
 static sign32 igcd(sign32 x,sign32 y)
 {
     /* integer GCD, returns GCD of x and y */
diff --git a/src/paillier.c b/src/paillier.c
index faf9548..15a901c 100644
--- a/src/paillier.c
+++ b/src/paillier.c
@@ -236,8 +236,6 @@ int PAILLIER_ENCRYPT(csprng *RNG, octet* N, octet* G, octet* PT, octet* CT, octe
     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)
@@ -265,59 +263,19 @@ int PAILLIER_ENCRYPT(csprng *RNG, octet* N, octet* G, octet* PT, octet* CT, octe
         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);
+    FF_4096_zero(pt, FFLEN_4096);
+    FF_4096_fromOctet(pt,PT,HFLEN_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);
+    // n2 = n^2
+    FF_4096_sqr(n2, n, HFLEN_4096);
+    FF_4096_norm(n2, FFLEN_4096);
 
-    // 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);
+    // ct = g^pt * r^n mod n2
+    FF_4096_bpow2(ct, g, pt, r, n, n2, FFLEN_4096);
+
+    // Output
+    FF_4096_toOctet(CT, ct, FFLEN_4096);
 
     // Output R for Debug
     if (R!=NULL)