Added Wang / Chow-Choo
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 73c0bde..a6fd195 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,7 +3,7 @@
 enable_testing()
 
 set(AMCL_VERSION_MAJOR "1")
-set(AMCL_VERSION_MINOR "0")
+set(AMCL_VERSION_MINOR "1")
 set(AMCL_VERSION_PATCH "0")
 set(PROJECT_VERSION "${AMCL_VERSION_MAJOR}.${AMCL_VERSION_MINOR}.${AMCL_VERSION_PATCH}")
 message(STATUS "PROJECT_VERSION='${PROJECT_VERSION}'")
@@ -13,8 +13,10 @@
 option (BUILD_SHARED_LIBS "Build Shared Libraries" ON)
 option (BUILD_PYTHON "Build Python" ON) 
 option (BUILD_MPIN "Build MPIN" ON) 
+option (BUILD_WCC "Build WCC" OFF) 
 option (BUILD_DOXYGEN "Build Doxygen" ON) 
 option (USE_PATENTS "Use alleged patents" ON)
+option (USE_ANONYMOUS "Anonymous authenticaion for M-Pin Full" OFF)
 
 # Allow the developer to select if Dynamic or Static libraries are built
 # Set the default LIB_TYPE variable to STATIC
@@ -71,10 +73,11 @@
 if(NOT(FIELD_CHOICE MATCHES "BN"))
   message(STATUS "Field choice prevents MPIN being built")
   set(BUILD_MPIN OFF)
+  set(BUILD_WSS OFF)
 endif(NOT(FIELD_CHOICE MATCHES "BN"))
 
 # test configuration
-if(BUILD_MPIN)
+if(BUILD_MPIN OR BUILD_WCC)
   set(MPIN_TIME_PERMIT_TESTS 10 CACHE STRING "Number of days in the future to test M-PIN time permits")
   set(MPIN_RANDOM_TESTS 10 CACHE STRING "Number of random M-PIN tests")
   message(STATUS "MPIN_TIME_PERMIT_TESTS=${MPIN_TIME_PERMIT_TESTS}")
@@ -84,7 +87,7 @@
     "${PROJECT_SOURCE_DIR}/c/tests/config.h.in"
     "${PROJECT_BINARY_DIR}/c/tests/config.h"
   )
-endif(BUILD_MPIN)
+endif(BUILD_MPIN OR BUILD_WCC)
 
 # Set a default build type if none was specified
 if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
@@ -124,6 +127,8 @@
   endif(DOXYGEN_FOUND)
 endif (BUILD_DOXYGEN)
 
+message(STATUS "Install ${CMAKE_INSTALL_PREFIX}")
+
 # uninstall target
 configure_file(
     "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
diff --git a/c/CMakeLists.txt b/c/CMakeLists.txt
index 50270fb..663adbd 100644
--- a/c/CMakeLists.txt
+++ b/c/CMakeLists.txt
@@ -47,7 +47,19 @@
   target_link_libraries (testmpin mpin) 
 endif(BUILD_MPIN)
 
-  
+# Build libwcc
+if(BUILD_WCC)
+  message(STATUS "Build WCC")
+  add_library(wcc ${LIB_TYPE} pair.c wcc.c utils.c)
+  target_link_libraries (wcc amcl) 
+  add_executable (testwcc testwcc.c)
+  add_executable (testwcc_tp testwcc_tp.c)
+  add_executable (testwcc_dta testwcc_dta.c)
+  target_link_libraries (testwcc wcc) 
+  target_link_libraries (testwcc_tp wcc) 
+  target_link_libraries (testwcc_dta wcc) 
+endif(BUILD_WCC)
+
 # Copy built libs to c/tests which allows testing without
 # having to install the libs.
 if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
@@ -64,7 +76,15 @@
                   POST_BUILD
                   COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_BINARY_DIR}/libmpin.dll" "${PROJECT_BINARY_DIR}/c/tests/")
     endif(BUILD_MPIN)
-  
+
+    if(BUILD_WCC)
+      message(STATUS "Copy libwcc.dll to c/tests for testing")
+      add_custom_command(
+                  TARGET wcc
+                  POST_BUILD
+                  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_BINARY_DIR}/libwcc.dll" "${PROJECT_BINARY_DIR}/c/tests/")
+    endif(BUILD_WCC)
+
 endif(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
 
 # Copy built libs to pythonCFFI which allows testing without
@@ -81,6 +101,14 @@
                   COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_BINARY_DIR}/libmpin.so" "${PROJECT_BINARY_DIR}/pythonCFFI/")
     endif(BUILD_MPIN)
 
+    if(BUILD_WCC)
+      message(STATUS "Copy libwcc.so to pythonCFFI for testing")
+      add_custom_command(
+                  TARGET wcc
+                  POST_BUILD
+                  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_BINARY_DIR}/libwcc.so" "${PROJECT_BINARY_DIR}/pythonCFFI/")
+    endif(BUILD_WCC)  
+
   endif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
 
   if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
@@ -98,6 +126,14 @@
                   COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_BINARY_DIR}/libmpin.dll" "${PROJECT_BINARY_DIR}/pythonCFFI/")
     endif(BUILD_MPIN)
 
+    if(BUILD_WCC)
+      message(STATUS "Copy libwcc.dll to pythonCFFI for testing")
+      add_custom_command(
+                  TARGET wcc
+                  POST_BUILD
+                  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_BINARY_DIR}/libwcc.dll" "${PROJECT_BINARY_DIR}/pythonCFFI/")
+    endif(BUILD_WCC)
+
   endif(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
 
   if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
@@ -116,6 +152,15 @@
                   COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_BINARY_DIR}/libmpin.dylib" "${PROJECT_BINARY_DIR}/pythonCFFI/")
     endif(BUILD_MPIN)
 
+    if(BUILD_WCC)
+      message(STATUS "Copy libwcc.dylib to pythonCFFI for testing")
+      add_custom_command(
+                  TARGET wcc
+                  POST_BUILD
+                  COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_BINARY_DIR}/libwcc.dylib" "${PROJECT_BINARY_DIR}/pythonCFFI/")
+    endif(BUILD_WCC)  
+
+
   endif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
 
 
@@ -133,7 +178,7 @@
 
 # Install libs and headers
 if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
-  install(DIRECTORY DESTINATION include/amcl DIRECTORY_PERMISSIONS
+  install(DIRECTORY DESTINATION include DIRECTORY_PERMISSIONS
           OWNER_WRITE OWNER_READ OWNER_EXECUTE
           GROUP_WRITE GROUP_READ
           WORLD_WRITE WORLD_READ WORLD_EXECUTE)
@@ -141,15 +186,15 @@
           OWNER_WRITE OWNER_READ OWNER_EXECUTE
           GROUP_READ GROUP_EXECUTE
           WORLD_READ WORLD_EXECUTE)
-  install (FILES ${CMAKE_CURRENT_BINARY_DIR}/amcl.h DESTINATION include/amcl PERMISSIONS
+  install (FILES ${CMAKE_CURRENT_BINARY_DIR}/amcl.h DESTINATION include PERMISSIONS
           OWNER_WRITE OWNER_READ OWNER_EXECUTE
           GROUP_READ GROUP_EXECUTE
           WORLD_READ WORLD_EXECUTE)
-  install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/utils.h DESTINATION include/amcl PERMISSIONS
+  install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/utils.h DESTINATION include PERMISSIONS
           OWNER_WRITE OWNER_READ OWNER_EXECUTE
           GROUP_READ GROUP_EXECUTE
           WORLD_READ WORLD_EXECUTE)
-  install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/DLLDefines.h DESTINATION include/amcl PERMISSIONS
+  install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/DLLDefines.h DESTINATION include PERMISSIONS
           OWNER_WRITE OWNER_READ OWNER_EXECUTE
           GROUP_READ GROUP_EXECUTE
           WORLD_READ WORLD_EXECUTE)
@@ -159,12 +204,23 @@
             OWNER_WRITE OWNER_READ OWNER_EXECUTE
             GROUP_READ GROUP_EXECUTE
             WORLD_READ WORLD_EXECUTE)
-    install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/mpin.h DESTINATION include/amcl PERMISSIONS
+    install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/mpin.h DESTINATION include PERMISSIONS
             OWNER_WRITE OWNER_READ OWNER_EXECUTE
             GROUP_READ GROUP_EXECUTE
             WORLD_READ WORLD_EXECUTE)
   endif(BUILD_MPIN)
   
+  if(BUILD_WCC)
+    install (TARGETS wcc DESTINATION lib PERMISSIONS
+            OWNER_WRITE OWNER_READ OWNER_EXECUTE
+            GROUP_READ GROUP_EXECUTE
+            WORLD_READ WORLD_EXECUTE)
+    install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/wcc.h DESTINATION include PERMISSIONS
+            OWNER_WRITE OWNER_READ OWNER_EXECUTE
+            GROUP_READ GROUP_EXECUTE
+            WORLD_READ WORLD_EXECUTE)
+  endif(BUILD_WCC)
+
 endif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
 
 if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
@@ -179,11 +235,16 @@
     install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/mpin.h DESTINATION lib)
   endif(BUILD_MPIN)
   
+  if(BUILD_WCC)
+    install (TARGETS wcc DESTINATION lib)
+    install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/wcc.h DESTINATION lib)
+  endif(BUILD_WCC)
+
 endif(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
 
 if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
   # Mac OS X specific code
-  install(DIRECTORY DESTINATION include/amcl DIRECTORY_PERMISSIONS
+  install(DIRECTORY DESTINATION include DIRECTORY_PERMISSIONS
           OWNER_WRITE OWNER_READ OWNER_EXECUTE
           GROUP_WRITE GROUP_READ
           WORLD_WRITE WORLD_READ WORLD_EXECUTE)
@@ -191,15 +252,15 @@
           OWNER_WRITE OWNER_READ OWNER_EXECUTE
           GROUP_READ GROUP_EXECUTE
           WORLD_READ WORLD_EXECUTE)
-  install (FILES ${CMAKE_CURRENT_BINARY_DIR}/amcl.h DESTINATION include/amcl PERMISSIONS
+  install (FILES ${CMAKE_CURRENT_BINARY_DIR}/amcl.h DESTINATION include PERMISSIONS
           OWNER_WRITE OWNER_READ OWNER_EXECUTE
           GROUP_READ GROUP_EXECUTE
           WORLD_READ WORLD_EXECUTE)
-  install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/utils.h DESTINATION include/amcl PERMISSIONS
+  install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/utils.h DESTINATION include PERMISSIONS
           OWNER_WRITE OWNER_READ OWNER_EXECUTE
           GROUP_READ GROUP_EXECUTE
           WORLD_READ WORLD_EXECUTE)
-  install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/DLLDefines.h DESTINATION include/amcl PERMISSIONS
+  install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/DLLDefines.h DESTINATION include PERMISSIONS
           OWNER_WRITE OWNER_READ OWNER_EXECUTE
           GROUP_READ GROUP_EXECUTE
           WORLD_READ WORLD_EXECUTE)
@@ -209,10 +270,22 @@
             OWNER_WRITE OWNER_READ OWNER_EXECUTE
             GROUP_READ GROUP_EXECUTE
             WORLD_READ WORLD_EXECUTE)
-    install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/mpin.h DESTINATION include/amcl PERMISSIONS
+    install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/mpin.h DESTINATION include PERMISSIONS
             OWNER_WRITE OWNER_READ OWNER_EXECUTE
             GROUP_READ GROUP_EXECUTE
             WORLD_READ WORLD_EXECUTE)
   endif(BUILD_MPIN)
 
+  if(BUILD_WCC)
+    install (TARGETS wcc DESTINATION lib PERMISSIONS
+            OWNER_WRITE OWNER_READ OWNER_EXECUTE
+            GROUP_READ GROUP_EXECUTE
+            WORLD_READ WORLD_EXECUTE)
+    install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/wcc.h DESTINATION include PERMISSIONS
+            OWNER_WRITE OWNER_READ OWNER_EXECUTE
+            GROUP_READ GROUP_EXECUTE
+            WORLD_READ WORLD_EXECUTE)
+  endif(BUILD_WCC)
+
+
 endif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
diff --git a/c/amcl.h.in b/c/amcl.h.in
index d9e7b37..3bbec0e 100755
--- a/c/amcl.h.in
+++ b/c/amcl.h.in
@@ -51,6 +51,7 @@
 #define AMCL_VERSION_PATCH @AMCL_VERSION_PATCH@
 #define OS "@OS@"
 #cmakedefine USE_PATENTS
+#cmakedefine USE_ANONYMOUS
 
 /* Support for C99?  Note for GCC need to explicitly include -std=c99 in command line */
 
diff --git a/c/ecdh.c b/c/ecdh.c
index 9d037d0..56152da 100755
--- a/c/ecdh.c
+++ b/c/ecdh.c
@@ -60,25 +60,25 @@
 }
 
 /* Hash octet p to octet w */
-void HASH(octet *p,octet *w)
+void ECP_HASH(octet *p,octet *w)
 {
 	hashit(p,-1,NULL,NULL,w);
 }
 
 /* Initialise a Cryptographically Strong Random Number Generator from
    an octet of raw random data */
-void CREATE_CSPRNG(csprng *RNG,octet *RAW)
+void ECP_CREATE_CSPRNG(csprng *RNG,octet *RAW)
 {
     RAND_seed(RNG,RAW->len,RAW->val);
 }
 
-void KILL_CSPRNG(csprng *RNG)
+void ECP_KILL_CSPRNG(csprng *RNG)
 {
     RAND_clean(RNG);
 }
 
 /* Calculate HMAC of m using key k. HMAC is tag of length olen */
-int HMAC(octet *m,octet *k,int olen,octet *tag)
+int ECP_HMAC(octet *m,octet *k,int olen,octet *tag)
 {
 /* Input is from an octet m        *
  * olen is requested output length in bytes. k is the key  *
@@ -132,7 +132,7 @@
     }
 }
 */
-void KDF2(octet *z,octet *p,int olen,octet *key)
+void ECP_KDF2(octet *z,octet *p,int olen,octet *key)
 {
 /* NOTE: the parameter olen is the length of the output k in bytes */
     char h[32];
@@ -155,7 +155,7 @@
 /* Password based Key Derivation Function */
 /* Input password p, salt s, and repeat count */
 /* Output key of length olen */
-void PBKDF2(octet *p,octet *s,int rep,int olen,octet *key)
+void ECP_PBKDF2(octet *p,octet *s,int rep,int olen,octet *key)
 {
 	int i,j,len,d=ROUNDUP(olen,32);
 	char f[EFS],u[EFS];
@@ -167,12 +167,12 @@
 	{
 		len=s->len;
 		OCT_jint(s,i,4);
-		HMAC(s,p,EFS,&F);
+		ECP_HMAC(s,p,EFS,&F);
 		s->len=len;
 		OCT_copy(&U,&F);
 		for (j=2;j<=rep;j++)
 		{
-			HMAC(&U,p,EFS,&U);
+			ECP_HMAC(&U,p,EFS,&U);
 			OCT_xor(&F,&U);
 		}
 
@@ -182,7 +182,7 @@
 }
 
 /* AES encryption/decryption. Encrypt byte array M using key K and returns ciphertext */
-void AES_CBC_IV0_ENCRYPT(octet *k,octet *m,octet *c)
+void ECP_AES_CBC_IV0_ENCRYPT(octet *k,octet *m,octet *c)
 { /* AES CBC encryption, with Null IV and key k */
   /* Input is from an octet string m, output is to an octet string c */
   /* Input is padded as necessary to make up a full final block */
@@ -223,7 +223,7 @@
 }
 
 /* decrypts and returns TRUE if all consistent, else returns FALSE */
-int AES_CBC_IV0_DECRYPT(octet *k,octet *c,octet *m)
+int ECP_AES_CBC_IV0_DECRYPT(octet *k,octet *c,octet *m)
 { /* padding is removed */
     aes a;
     int i,ipt,opt,ch;
@@ -354,7 +354,7 @@
 }
 
 /* IEEE-1363 Diffie-Hellman online calculation Z=S.WD */
-int ECPSVDP_DH(octet *S,octet *WD,octet *Z)
+int ECP_SVDP_DH(octet *S,octet *WD,octet *Z)
 {
     BIG r,s,wx,wy;
     int valid;
@@ -395,7 +395,7 @@
 #if CURVETYPE!=MONTGOMERY
 
 /* IEEE ECDSA Signature, C and D are signature on F using private key S */
-int ECPSP_DSA(csprng *RNG,octet *S,octet *F,octet *C,octet *D)
+int ECP_SP_DSA(csprng *RNG,octet *S,octet *F,octet *C,octet *D)
 {
 	char h[32];
 	octet H={0,sizeof(h),h};
@@ -443,7 +443,7 @@
 }
 
 /* IEEE1363 ECDSA Signature Verification. Signature C and D on F is verified using public key W */
-int ECPVP_DSA(octet *W,octet *F, octet *C,octet *D)
+int ECP_VP_DSA(octet *W,octet *F, octet *C,octet *D)
 {
 	char h[32];
 	octet H={0,sizeof(h),h};
@@ -512,25 +512,25 @@
 	octet U={0,sizeof(u),u};
 
     if (ECP_KEY_PAIR_GENERATE(RNG,&U,V)!=0) return;
-    if (ECPSVDP_DH(&U,W,&Z)!=0) return;
+    if (ECP_SVDP_DH(&U,W,&Z)!=0) return;
 
     OCT_copy(&VZ,V);
     OCT_joctet(&VZ,&Z);
 
-	KDF2(&VZ,P1,EFS,&K);
+    ECP_KDF2(&VZ,P1,EFS,&K);
 
-	K1.len=K2.len=16;
+    K1.len=K2.len=16;
     for (i=0;i<16;i++) {K1.val[i]=K.val[i]; K2.val[i]=K.val[16+i];}
 
-	AES_CBC_IV0_ENCRYPT(&K1,M,C);
+    ECP_AES_CBC_IV0_ENCRYPT(&K1,M,C);
 
-	OCT_jint(&L2,P2->len,8);
+    OCT_jint(&L2,P2->len,8);
 
-	len=C->len;
-	OCT_joctet(C,P2);
+    len=C->len;
+    OCT_joctet(C,P2);
     OCT_joctet(C,&L2);
-	HMAC(C,&K2,tlen,T);
-	C->len=len;
+    ECP_HMAC(C,&K2,tlen,T);
+    C->len=len;
 }
 
 /* IEEE1363 ECIES decryption. Decryption of ciphertext V,C,T using private key U outputs plaintext M */
@@ -547,24 +547,24 @@
 	octet L2={0,sizeof(l2),l2};
 	octet TAG={0,sizeof(tag),tag};
 
-	if (ECPSVDP_DH(U,V,&Z)!=0) return 0;
+	if (ECP_SVDP_DH(U,V,&Z)!=0) return 0;
 
     OCT_copy(&VZ,V);
     OCT_joctet(&VZ,&Z);
 
-	KDF2(&VZ,P1,EFS,&K);
+	ECP_KDF2(&VZ,P1,EFS,&K);
 
 	K1.len=K2.len=16;
     for (i=0;i<16;i++) {K1.val[i]=K.val[i]; K2.val[i]=K.val[16+i];}
 
-	if (!AES_CBC_IV0_DECRYPT(&K1,C,M)) return 0;
+	if (!ECP_AES_CBC_IV0_DECRYPT(&K1,C,M)) return 0;
 
 	OCT_jint(&L2,P2->len,8);
 
 	len=C->len;
 	OCT_joctet(C,P2);
     OCT_joctet(C,&L2);
-	HMAC(C,&K2,T->len,&TAG);
+	ECP_HMAC(C,&K2,T->len,&TAG);
 	C->len=len;
 
 	if (!OCT_comp(T,&TAG)) return 0;
diff --git a/c/ecdh.h b/c/ecdh.h
index 2dfef9b..0dae41a 100755
--- a/c/ecdh.h
+++ b/c/ecdh.h
@@ -53,19 +53,19 @@
 	@param R is a pointer to a cryptographically secure random number generator
 	@param S is an input truly random seed value
  */
-extern void CREATE_CSPRNG(csprng *R,octet *S);
+extern void ECP_CREATE_CSPRNG(csprng *R,octet *S);
 /**	@brief Kill a random number generator
  *
 	Deletes all internal state
 	@param R is a pointer to a cryptographically secure random number generator
  */
-extern void KILL_CSPRNG(csprng *R);
+extern void ECP_KILL_CSPRNG(csprng *R);
 /**	@brief hash an octet into another octet
  *
 	@param I input octet
 	@param O output octet - H(I)
  */
-extern void HASH(octet *I,octet *O);
+extern void ECP_HASH(octet *I,octet *O);
 /**	@brief HMAC of message M using key K to create tag of length len in octet tag
  *
 	IEEE-1363 MAC1 function. Uses SHA256 internally.
@@ -75,7 +75,7 @@
 	@param tag is the output HMAC
 	@return 0 for bad parameters, else 1
  */
-extern int HMAC(octet *M,octet *K,int len,octet *tag);
+extern int ECP_HMAC(octet *M,octet *K,int len,octet *tag);
 
 /*extern void KDF1(octet *,int,octet *);*/
 
@@ -87,7 +87,7 @@
 	@param len is output desired length of key
 	@param K is the derived key
  */
-extern void KDF2(octet *Z,octet *P,int len,octet *K);
+extern void ECP_KDF2(octet *Z,octet *P,int len,octet *K);
 /**	@brief Password Based Key Derivation Function - generates key K from password, salt and repeat counter
  *
 	PBKDF2 Password Based Key Derivation Function. Uses SHA256 internally.
@@ -97,7 +97,7 @@
 	@param len is output desired length of key
 	@param K is the derived key
  */
-extern void PBKDF2(octet *P,octet *S,int rep,int len,octet *K);
+extern void ECP_PBKDF2(octet *P,octet *S,int rep,int len,octet *K);
 /**	@brief AES encrypts a plaintext to a ciphtertext
  *
 	IEEE-1363 AES_CBC_IV0_ENCRYPT function. Encrypts in CBC mode with a zero IV, padding as necessary to create a full final block.
@@ -105,7 +105,7 @@
 	@param P input plaintext octet
 	@param C output ciphertext octet
  */
-extern void AES_CBC_IV0_ENCRYPT(octet *K,octet *P,octet *C);
+extern void ECP_AES_CBC_IV0_ENCRYPT(octet *K,octet *P,octet *C);
 /**	@brief AES encrypts a plaintext to a ciphtertext
  *
 	IEEE-1363 AES_CBC_IV0_DECRYPT function. Decrypts in CBC mode with a zero IV.
@@ -114,7 +114,7 @@
 	@param P output plaintext octet
 	@return 0 if bad input, else 1
  */
-extern int AES_CBC_IV0_DECRYPT(octet *K,octet *C,octet *P);
+extern int ECP_AES_CBC_IV0_DECRYPT(octet *K,octet *C,octet *P);
 
 /* ECDH primitives - support functions */
 /**	@brief Generate an ECC public/private key pair
@@ -143,7 +143,7 @@
 	@param K the output shared key, in fact the x-coordinate of s.W
 	@return 0 or an error code
  */
-extern int ECPSVDP_DH(octet *s,octet *W,octet *K);
+extern int ECP_SVDP_DH(octet *s,octet *W,octet *K);
 /*extern int ECPSVDP_DHC(octet *,octet *,int,octet *);*/
 
 /*#if CURVETYPE!=MONTGOMERY */
@@ -187,7 +187,7 @@
 	@param d component of the output signature
 
  */
-extern int ECPSP_DSA(csprng *R,octet *s,octet *M,octet *c,octet *d);
+extern int ECP_SP_DSA(csprng *R,octet *s,octet *M,octet *c,octet *d);
 /**	@brief ECDSA Signature Verification
  *
 	IEEE-1363 ECDSA Signature Verification
@@ -197,7 +197,7 @@
 	@param d component of the input signature
 	@return 0 or an error code
  */
-extern int ECPVP_DSA(octet *W,octet *M,octet *c,octet *d);
+extern int ECP_VP_DSA(octet *W,octet *M,octet *c,octet *d);
 /*#endif*/
 
 #endif
diff --git a/c/mpin.c b/c/mpin.c
index 9c388af..a29dfe0 100755
--- a/c/mpin.c
+++ b/c/mpin.c
@@ -164,7 +164,7 @@
     for (i=0;i<32;i++) hh[i]=0;
 }
 
-unsign32 today(void)
+unsign32 MPIN_today(void)
 { /* return time in slots since epoch */
 	unsign32 ti=(unsign32)time(NULL);
 	return (long)(ti/(60*TIME_SLOT_MINUTES));
@@ -173,12 +173,12 @@
 /* Initialise a Cryptographically Strong Random Number Generator from
    an octet of raw random data */
 
-void CREATE_CSPRNG(csprng *RNG,octet *RAW)
+void MPIN_CREATE_CSPRNG(csprng *RNG,octet *RAW)
 {
     RAND_seed(RNG,RAW->len,RAW->val);
 }
 
-void KILL_CSPRNG(csprng *RNG)
+void MPIN_KILL_CSPRNG(csprng *RNG)
 {
     RAND_clean(RNG);
 }
@@ -499,22 +499,32 @@
 /* Outputs H(CID) and H(CID)+H(T|H(CID)) for time permits. If no time permits set HTID=NULL */
 void MPIN_SERVER_1(int date,octet *CID,octet *HID,octet *HTID)
 {
-	char h[HASH_BYTES];
-	octet H={0,sizeof(h),h};
-	ECP P,R;
+  char h[HASH_BYTES];
+  octet H={0,sizeof(h),h};
+  ECP P,R;
 
-	hashit(-1,CID,&H);
-	mapit(&H,&P);
+#ifdef USE_ANONYMOUS
+  mapit(CID,&P);
+#else 
+  hashit(-1,CID,&H);
+  mapit(&H,&P);
+#endif
 
-	if (date)
-	{
-		if (HID!=NULL) ECP_toOctet(HID,&P);
-		hashit(date,&H,&H);
-		mapit(&H,&R);
-		ECP_add(&P,&R);
-		ECP_toOctet(HTID,&P);
-	}
-	else ECP_toOctet(HID,&P);
+  if (date) {
+    if (HID!=NULL) {
+      ECP_toOctet(HID,&P);
+    }
+#ifdef USE_ANONYMOUS
+    hashit(date,CID,&H);
+#else
+    hashit(date,&H,&H);
+#endif
+    mapit(&H,&R);
+    ECP_add(&P,&R);
+    ECP_toOctet(HTID,&P);
+  } else {
+    ECP_toOctet(HID,&P);
+  }
 
 }
 
@@ -715,14 +725,14 @@
 
 /* calculate common key on client side */
 /* wCID = w.(A+AT) */
-int MPIN_CLIENT_KEY(octet *G1,octet *G2,int pin,octet *R,octet *X,octet *wCID,octet *CK)
+int MPIN_CLIENT_KEY(octet *G1,octet *G2,int pin,octet *R,octet *X,octet *H,octet *wCID,octet *CK)
 {
 	FP12 g1,g2;
 	FP4 c,cp,cpm1,cpm2;
 	FP2 f;
 	ECP W;
-    int res=0;
-	BIG r,z,x,q,m,a,b;
+        int res=0;
+	BIG r,z,x,q,m,a,b,h;
 	hash sha;
 	char ht[HASH_BYTES];
 	octet HT={0,sizeof(ht),ht};
@@ -731,18 +741,22 @@
 	FP12_fromOctet(&g2,G2);
 	BIG_fromBytes(z,R->val);
 	BIG_fromBytes(x,X->val);
+	BIG_fromBytes(h,H->val);
 
 	if (!ECP_fromOctet(&W,wCID)) res=MPIN_INVALID_POINT;
 
 	if (res==0)
 	{
+		BIG_rcopy(r,CURVE_Order);
+		BIG_add(z,z,h);    // new
+		BIG_mod(z,r);
+
 		PAIR_G1mul(&W,x);
 
 		BIG_rcopy(a,CURVE_Fra);
 		BIG_rcopy(b,CURVE_Frb);
 		FP2_from_BIGs(&f,a,b);
 
-		BIG_rcopy(r,CURVE_Order);
 		BIG_rcopy(q,Modulus);
 		BIG_copy(m,q);
 		BIG_mod(m,r);
@@ -798,21 +812,26 @@
 /* calculate common key on server side */
 /* Z=r.A - no time permits involved */
 
-int MPIN_SERVER_KEY(octet *Z,octet *SST,octet *W,octet *xID,octet *xCID,octet *SK)
+int MPIN_SERVER_KEY(octet *Z,octet *SST,octet *W,octet *H,octet *HID,octet *xID,octet *xCID,octet *SK)
 {
 	int res=0;
 	FP12 g;
 	FP4 c;
 	FP2 qx,qy;
-	ECP R,U;
+	ECP R,U,A;
 	ECP2 sQ;
-	BIG w,x,y;
+	BIG w,x,y,h;
 	hash sha;
 	char ht[HASH_BYTES];
 	octet HT={0,sizeof(ht),ht};
 
 	if (!ECP2_fromOctet(&sQ,SST)) res=MPIN_INVALID_POINT;
 	if (!ECP_fromOctet(&R,Z)) res=MPIN_INVALID_POINT;
+
+
+	if (!ECP_fromOctet(&A,HID)) res=MPIN_INVALID_POINT;
+
+	// new
 	if (xCID!=NULL)
 	{
 		if (!ECP_fromOctet(&U,xCID)) res=MPIN_INVALID_POINT;
@@ -822,9 +841,13 @@
 		if (!ECP_fromOctet(&U,xID)) res=MPIN_INVALID_POINT;
 	}
 	BIG_fromBytes(w,W->val);
+	BIG_fromBytes(h,H->val);
 
 	if (res==0)
 	{
+		PAIR_G1mul(&A,h);
+		ECP_add(&R,&A);  // new
+
 		PAIR_ate(&g,&sQ,&R);
 		PAIR_fexp(&g);
 		PAIR_G1mul(&U,w);
@@ -935,7 +958,7 @@
 
 /* AES-GCM Encryption of octets, K is key, H is header,
    P is plaintext, C is ciphertext, T is authentication tag */
-void AES_GCM_ENCRYPT(octet *K,octet *IV,octet *H,octet *P,octet *C,octet *T)
+void MPIN_AES_GCM_ENCRYPT(octet *K,octet *IV,octet *H,octet *P,octet *C,octet *T)
 {
   gcm g;
   GCM_init(&g,K->val,IV->len,IV->val);
@@ -948,7 +971,7 @@
 
 /* AES-GCM Decryption of octets, K is key, H is header,
    P is plaintext, C is ciphertext, T is authentication tag */
-void AES_GCM_DECRYPT(octet *K,octet *IV,octet *H,octet *C,octet *P,octet *T)
+void MPIN_AES_GCM_DECRYPT(octet *K,octet *IV,octet *H,octet *C,octet *P,octet *T)
 {
   gcm g;
   GCM_init(&g,K->val,IV->len,IV->val);
@@ -991,7 +1014,7 @@
 }
 
 /* Calculate HMAC of m using key k. HMAC is tag of length olen */
-int HMAC(octet *m,octet *k,int olen,octet *tag)
+int MPIN_HMAC(octet *m,octet *k,int olen,octet *tag)
 {
 /* Input is from an octet m        *
  * olen is requested output length in bytes. k is the key  *
@@ -1025,7 +1048,7 @@
 /* Password based Key Derivation Function */
 /* Input password p, salt s, and repeat count */
 /* Output key of length olen */
-void PBKDF2(octet *p,octet *s,int rep,int olen,octet *key)
+void MPIN_PBKDF2(octet *p,octet *s,int rep,int olen,octet *key)
 {
 	int i,j,len,d=ROUNDUP(olen,32);
 	char f[PFS],u[PFS];
@@ -1037,12 +1060,12 @@
 	{
 		len=s->len;
 		OCT_jint(s,i,4);
-		HMAC(s,p,PFS,&F);
+		MPIN_HMAC(s,p,PFS,&F);
 		s->len=len;
 		OCT_copy(&U,&F);
 		for (j=2;j<=rep;j++)
 		{
-			HMAC(&U,p,PFS,&U);
+			MPIN_HMAC(&U,p,PFS,&U);
 			OCT_xor(&F,&U);
 		}
 
@@ -1051,6 +1074,23 @@
 	OCT_chop(key,NULL,olen);
 }
 
+/* Hash the M-Pin transcript - new */
+void MPIN_HASH_ALL(octet *HID,octet *xID,octet *xCID,octet *SEC,octet *Y,octet *R,octet *W,octet *H)
+{
+	char t[10*PFS+4];
+	octet T={0,sizeof(t),t};
+
+	OCT_joctet(&T,HID);
+	if (xCID!=NULL) OCT_joctet(&T,xCID);
+	else OCT_joctet(&T,xID);
+	OCT_joctet(&T,SEC);
+	OCT_joctet(&T,Y);
+	OCT_joctet(&T,R);
+	OCT_joctet(&T,W);
+
+	hashit(0,&T,H);
+}
+
 /*
 int MPIN_TEST_PAIRING(octet *CID,octet *R)
 {
diff --git a/c/mpin.h b/c/mpin.h
index 0610c96..dd49d75 100755
--- a/c/mpin.h
+++ b/c/mpin.h
@@ -75,7 +75,7 @@
 	@return current epoch time in seconds
  */
 DLL_EXPORT unsign32 MPIN_GET_TIME(void);
-/**	@brief Generate Y=H(s,O), where s is epoch time, O is an octet, and H(.) is a hash function
+/**	@brief Generate Y=H(t,O), where t is epoch time, O is an octet, and H(.) is a hash function
  *
 	@param t is epoch time in seconds
 	@param O is an input octet
@@ -232,19 +232,19 @@
  *
 	@return today's date, as number of days elapsed since the epoch
  */
-DLL_EXPORT unsign32 today(void);
+DLL_EXPORT unsign32 MPIN_today(void);
 /**	@brief Initialise a random number generator
  *
 	@param R is a pointer to a cryptographically secure random number generator
 	@param S is an input truly random seed value
  */
-DLL_EXPORT void CREATE_CSPRNG(csprng *R,octet *S);
+DLL_EXPORT void MPIN_CREATE_CSPRNG(csprng *R,octet *S);
 /**	@brief Kill a random number generator
  *
 	Deletes all internal state
 	@param R is a pointer to a cryptographically secure random number generator
  */
-DLL_EXPORT void KILL_CSPRNG(csprng *R);
+DLL_EXPORT void MPIN_KILL_CSPRNG(csprng *R);
 /**	@brief Find a random multiple of a point in G1
  *
 	@param R is a pointer to a cryptographically secure random number generator
@@ -297,12 +297,14 @@
 	@param Z is the input Client-side Diffie-Hellman component
 	@param SS is the input server secret
 	@param w is an input random number generated by the server
+	@param p is an input, hash of the protocol transcript
+	@param I is the hashed input client ID = H(ID)
 	@param U is input from the client = x.H(ID)
 	@param UT is input from the client= x.(H(ID)+H(d|H(ID)))
 	@param K is the output calculated shared key
 	@return 0 or an error code
  */
-DLL_EXPORT int MPIN_SERVER_KEY(octet *Z,octet *SS,octet *w,octet *U,octet *UT,octet *K);
+DLL_EXPORT int MPIN_SERVER_KEY(octet *Z,octet *SS,octet *w,octet *p,octet *I,octet *U,octet *UT,octet *K);
 /**	@brief Calculate Key on Client side for M-Pin Full
  *
 	@param g1 precomputed input
@@ -310,11 +312,12 @@
 	@param pin is the input PIN number
 	@param r is an input, a locally generated random number
 	@param x is an input, a locally generated random number
+	@param p is an input, hash of the protocol transcript
 	@param T is the input Server-side Diffie-Hellman component
 	@param K is the output calculated shared key
 	@return 0 or an error code
  */
-DLL_EXPORT int MPIN_CLIENT_KEY(octet *g1,octet *g2,int pin,octet *r,octet *x,octet *T,octet *K);
+DLL_EXPORT int MPIN_CLIENT_KEY(octet *g1,octet *g2,int pin,octet *r,octet *x,octet *p,octet *T,octet *K);
 
 /**	@brief AES-GCM Encryption
  *
@@ -325,7 +328,7 @@
 	@param C Ciphertext
 	@param T Checksum
  */
-DLL_EXPORT void AES_GCM_ENCRYPT(octet *K,octet *IV,octet *H,octet *P,octet *C,octet *T);
+DLL_EXPORT void MPIN_AES_GCM_ENCRYPT(octet *K,octet *IV,octet *H,octet *P,octet *C,octet *T);
 
 /**	@brief AES-GCM Decryption
  *
@@ -336,7 +339,7 @@
 	@param C Ciphertext
 	@param T Checksum
  */
-DLL_EXPORT void AES_GCM_DECRYPT(octet *K,octet *IV,octet *H,octet *C,octet *P,octet *T);
+DLL_EXPORT void MPIN_AES_GCM_DECRYPT(octet *K,octet *IV,octet *H,octet *C,octet *P,octet *T);
 
 /**	@brief HMAC of message M using key K to create tag of length len in octet tag
  *
@@ -347,7 +350,7 @@
 	@param tag is the output HMAC
 	@return 0 for bad parameters, else 1
  */
-DLL_EXPORT int HMAC(octet *M,octet *K,int len,octet *tag);
+DLL_EXPORT int MPIN_HMAC(octet *M,octet *K,int len,octet *tag);
 
 /**	@brief Password Based Key Derivation Function - generates key K from password, salt and repeat counter
  *
@@ -358,7 +361,19 @@
 	@param len is output desired length of key
 	@param K is the derived key
  */
-DLL_EXPORT void PBKDF2(octet *P,octet *S,int rep,int len,octet *K);
+DLL_EXPORT void MPIN_PBKDF2(octet *P,octet *S,int rep,int len,octet *K);
+
+/** @brief Hash the session transcript 
+	@param I is the hashed input client ID = H(ID)
+	@param U is the client output = x.H(ID)
+	@param CU is the client output = x.(H(ID)+H(T|H(ID)))
+	@param Y is the server challenge
+	@param V is the client part response
+	@param R is the client part response
+	@param W is the server part response
+	@param H the output is the hash of all of the above that apply
+*/
+DLL_EXPORT void MPIN_HASH_ALL(octet *I,octet *U,octet *CU,octet *V,octet *Y,octet *R,octet *W,octet *H);
 
 #endif
 
diff --git a/c/rsa.c b/c/rsa.c
index 429d5e2..d74ff97 100755
--- a/c/rsa.c
+++ b/c/rsa.c
@@ -57,12 +57,12 @@
 
 /* Initialise a Cryptographically Strong Random Number Generator from
    an octet of raw random data */
-void CREATE_CSPRNG(csprng *RNG,octet *RAW)
+void RSA_CREATE_CSPRNG(csprng *RNG,octet *RAW)
 {
     RAND_seed(RNG,RAW->len,RAW->val);
 }
 
-void KILL_CSPRNG(csprng *RNG)
+void RSA_KILL_CSPRNG(csprng *RNG)
 {
     RAND_clean(RNG);
 }
@@ -150,7 +150,7 @@
 
 /* OAEP Message Encoding for Encryption */
 
-int OAEP_ENCODE(octet *m,csprng *RNG,octet *p,octet *f)
+int RSA_OAEP_ENCODE(octet *m,csprng *RNG,octet *p,octet *f)
 {
     int i,slen,olen=RFS-1;
     int mlen=m->len;
@@ -191,7 +191,7 @@
 
 /* OAEP Message Decoding for Decryption */
 
-int OAEP_DECODE(octet *p,octet *f)
+int RSA_OAEP_DECODE(octet *p,octet *f)
 {
     int comp,x,t;
     int i,k,olen=RFS-1;
diff --git a/c/rsa.h b/c/rsa.h
index 533d389..df1a151 100755
--- a/c/rsa.h
+++ b/c/rsa.h
@@ -40,13 +40,13 @@
 	@param R is a pointer to a cryptographically secure random number generator
 	@param S is an input truly random seed value
  */
-extern void CREATE_CSPRNG(csprng *R,octet *S);
+extern void RSA_CREATE_CSPRNG(csprng *R,octet *S);
 /**	@brief Kill a random number generator
  *
 	Deletes all internal state
 	@param R is a pointer to a cryptographically secure random number generator
  */
-extern void KILL_CSPRNG(csprng *R);
+extern void RSA_KILL_CSPRNG(csprng *R);
 /**	@brief RSA Key Pair Generator
  *
 	@param R is a pointer to a cryptographically secure random number generator
@@ -63,7 +63,7 @@
 	@param F is the output encoding, ready for RSA encryption
 	@return 1 if OK, else 0
  */
-extern int	OAEP_ENCODE(octet *M,csprng *R,octet *P,octet *F);
+extern int RSA_OAEP_ENCODE(octet *M,csprng *R,octet *P,octet *F);
 /**	@brief OAEP unpadding of a message after RSA decryption
  *
 	Unpadding is done in-place
@@ -71,7 +71,7 @@
 	@param F is input padded message, unpadded on output
 	@return 1 if OK, else 0
  */
-extern int  OAEP_DECODE(octet *P,octet *F);
+extern int RSA_OAEP_DECODE(octet *P,octet *F);
 /**	@brief RSA encryption of suitably padded plaintext
  *
 	@param PUB the input RSA public key
diff --git a/c/testecdh.c b/c/testecdh.c
index 5bfc8ac..26621a7 100755
--- a/c/testecdh.c
+++ b/c/testecdh.c
@@ -67,7 +67,7 @@
     RAW.val[3]=ran>>24;
     for (i=0;i<100;i++) RAW.val[i]=i;
 
-    CREATE_CSPRNG(&RNG,&RAW);   /* initialise strong RNG */
+    ECP_CREATE_CSPRNG(&RNG,&RAW);   /* initialise strong RNG */
 
 //for (j=0;j<100;j++)
 //{
@@ -81,7 +81,7 @@
 
 /* private key S0 of size EGS bytes derived from Password and Salt */
 
-	PBKDF2(&PW,&SALT,1000,EGS,&S0);
+	ECP_PBKDF2(&PW,&SALT,1000,EGS,&S0);
 	printf("Alices private key= 0x"); OCT_output(&S0);
 
 /* Generate Key pair S/W */
@@ -110,8 +110,8 @@
 
 /* Calculate common key using DH - IEEE 1363 method */
 
-    ECPSVDP_DH(&S0,&W1,&Z0);
-    ECPSVDP_DH(&S1,&W0,&Z1);
+    ECP_SVDP_DH(&S0,&W1,&Z0);
+    ECP_SVDP_DH(&S1,&W0,&Z1);
 
 	if (!OCT_comp(&Z0,&Z1))
     {
@@ -119,7 +119,7 @@
         return 0;
     }
 
-	KDF2(&Z0,NULL,EAS,&KEY);
+	ECP_KDF2(&Z0,NULL,EAS,&KEY);
 
 	printf("Alice's DH Key=  0x"); OCT_output(&KEY);
 	printf("Servers DH Key=  0x"); OCT_output(&KEY);
@@ -151,7 +151,7 @@
 
 	printf("Testing ECDSA\n");
 
-	if (ECPSP_DSA(&RNG,&S0,&M,&CS,&DS)!=0)
+	if (ECP_SP_DSA(&RNG,&S0,&M,&CS,&DS)!=0)
 	{
 		printf("***ECDSA Signature Failed\n");
 		return 0;
@@ -160,7 +160,7 @@
 	printf("Signature C = 0x"); OCT_output(&CS);
 	printf("Signature D = 0x"); OCT_output(&DS);
 
-	if (ECPVP_DSA(&W0,&M,&CS,&DS)!=0)
+	if (ECP_VP_DSA(&W0,&M,&CS,&DS)!=0)
 	{
 		printf("***ECDSA Verification Failed\n");
 		return 0;
@@ -168,7 +168,7 @@
 	else printf("ECDSA Signature/Verification succeeded %d\n",j);
 //}
 //printf("Test Completed Successfully\n");
-	KILL_CSPRNG(&RNG);
+	ECP_KILL_CSPRNG(&RNG);
 
     return 0;
 }
diff --git a/c/testecm.c b/c/testecm.c
index 9461ee2..94c996d 100755
--- a/c/testecm.c
+++ b/c/testecm.c
@@ -59,7 +59,7 @@
     RAW.val[3]=ran>>24;
     for (i=4;i<100;i++) RAW.val[i]=i;
 
-    CREATE_CSPRNG(&RNG,&RAW);   /* initialise strong RNG */
+    ECP_CREATE_CSPRNG(&RNG,&RAW);   /* initialise strong RNG */
 
 //for (j=0;j<1000;j++)
 //{
@@ -73,7 +73,7 @@
 
 /* private key S0 of size EGS bytes derived from Password and Salt */
 
-	PBKDF2(&PW,&SALT,1000,EGS,&S0);
+	ECP_PBKDF2(&PW,&SALT,1000,EGS,&S0);
 	printf("Alices private key= 0x"); OCT_output(&S0);
 
 /* Generate Key pair S/W */
@@ -103,16 +103,16 @@
 
 /* Calculate common key using DH - IEEE 1363 method */
 
-    ECPSVDP_DH(&S0,&W1,&Z0);
-    ECPSVDP_DH(&S1,&W0,&Z1);
+    ECP_SVDP_DH(&S0,&W1,&Z0);
+    ECP_SVDP_DH(&S1,&W0,&Z1);
 
 	if (!OCT_comp(&Z0,&Z1))
     {
-        printf("*** ECPSVDP-DH Failed\n");
+        printf("*** ECP_SVDP-DH Failed\n");
         return 0;
     }
 
-	KDF2(&Z0,NULL,EAS,&KEY);
+	ECP_KDF2(&Z0,NULL,EAS,&KEY);
 
 	printf("Alice's DH Key=  0x"); OCT_output(&KEY);
 	printf("Servers DH Key=  0x"); OCT_output(&KEY);
diff --git a/c/testmpin.c b/c/testmpin.c
index a2568dc..6dedf7c 100755
--- a/c/testmpin.c
+++ b/c/testmpin.c
@@ -23,7 +23,7 @@
 
 /* Build executible after installation:
 
-  gcc -std=c99 -O3 ./testmpin.c  -I/usr/local/include/amcl -L/usr/local/lib -lmpin -lamcl -o testmpin
+  gcc -std=c99 -g ./testmpin.c -I/opt/amcl/include -L/opt/amcl/lib -lamcl -lmpin -o testmpin
 
 */
 
@@ -42,13 +42,13 @@
 {
   int i,pin,rtn,err,timeValue;
 #ifdef PERMITS
-  int date=today();
+  int date=MPIN_today();
 #else
   int date=0;
 #endif
   unsigned long ran;
   char x[PGS],s[PGS],y[PGS],client_id[100],raw[100],sst[4*PFS],token[2*PFS+1],sec[2*PFS+1],permit[2*PFS+1],xcid[2*PFS+1],xid[2*PFS+1],e[12*PFS],f[12*PFS];
-  char hcid[HASH_BYTES],hid[2*PFS+1],htid[2*PFS+1];
+  char hcid[HASH_BYTES],hsid[HASH_BYTES],hid[2*PFS+1],htid[2*PFS+1],h[PGS];
 #ifdef FULL
   char r[PGS],z[2*PFS+1],w[PGS],t[2*PFS+1];
   char g1[12*PFS],g2[12*PFS];
@@ -57,6 +57,7 @@
   octet S={0,sizeof(s),s};
   octet X={0,sizeof(x),x};
   octet Y={0,sizeof(y),y};
+  octet H={0,sizeof(h),h};
   octet RAW={0,sizeof(raw),raw};
   octet CLIENT_ID={0,sizeof(client_id),client_id};
   octet SST={0,sizeof(sst),sst};
@@ -66,6 +67,7 @@
   octet xCID={0,sizeof(xcid),xcid};
   octet xID={0,sizeof(xid),xid};
   octet HCID={0,sizeof(hcid),hcid};
+  octet HSID={0,sizeof(hsid),hsid};
   octet HID={0,sizeof(hid),hid};
   octet HTID={0,sizeof(htid),htid};
   octet E={0,sizeof(e),e};
@@ -94,7 +96,7 @@
   for (i=4;i<100;i++) RAW.val[i]=i+1;
 
   /* initialise strong RNG */
-  CREATE_CSPRNG(&RNG,&RAW);
+  MPIN_CREATE_CSPRNG(&RNG,&RAW);
 
   /* Trusted Authority set-up */
   MPIN_RANDOM_GENERATE(&RNG,&S);
@@ -105,6 +107,14 @@
   MPIN_HASH_ID(&CLIENT_ID,&HCID);  /* Either Client or TA calculates Hash(ID) - you decide! */
   printf("Client ID= "); OCT_output_string(&CLIENT_ID); printf("\n");
 
+  /* When set only send hashed IDs to server */
+  octet *pID;
+#ifdef USE_ANONYMOUS
+  pID = &HCID;
+#else
+  pID = &CLIENT_ID;
+#endif
+
   /* Client and Server are issued secrets by DTA */
   MPIN_GET_SERVER_SECRET(&S,&SST);
   printf("Server Secret= "); OCT_output(&SST);
@@ -150,6 +160,9 @@
   If PERMITS are is use, then date!=0 and PERMIT is added to secret and xCID = x.(H(CLIENT_ID)+H(date|H(CLIENT_ID)))
   Random value x is supplied externally if RNG=NULL, otherwise generated and passed out by RNG
 
+  HSID - hashed client ID as calculated by the server
+  HCID - hashed client ID as calculated by the client
+
   IMPORTANT: To save space and time..
   If Time Permits OFF set xCID = NULL, HTID=NULL and use xID and HID only
   If Time permits are ON, AND pin error detection is required then all of xID, xCID, HID and HTID are required
@@ -169,7 +182,7 @@
   prHID=pHTID;
 #ifndef PINERROR
    pxID=NULL;
-   pHID=NULL;
+   // pHID=NULL;
 #endif
 #else
    prHID=pHID;
@@ -193,24 +206,22 @@
   }
 
 #ifdef FULL
-  MPIN_HASH_ID(&CLIENT_ID,&HCID);
   MPIN_GET_G1_MULTIPLE(&RNG,1,&R,&HCID,&Z);  /* Also Send Z=r.ID to Server, remember random r */
 #endif
 
-
   rtn=MPIN_SERVER(date,pHID,pHTID,&Y,&SST,pxID,pxCID,&SEC,pE,pF,&CLIENT_ID,NULL,timeValue);
   if (rtn != 0)
   {
     printf("MPIN_SERVER ERROR %d\n", rtn);
   }
 
-
 #ifdef FULL
   MPIN_GET_G1_MULTIPLE(&RNG,0,&W,prHID,&T);  /* Also send T=w.ID to client, remember random w  */
 #endif
 
 #else // SINGLE_PASS
   printf("MPIN Multi Pass\n");
+
   if (MPIN_CLIENT_1(date,&CLIENT_ID,&RNG,&X,pin,&TOKEN,&SEC,pxID,pxCID,pPERMIT)!=0)
   {
     printf("Error from Client side - First Pass\n");
@@ -220,12 +231,11 @@
   /* Send U=x.ID to server, and recreate secret from token and pin */
 
 #ifdef FULL
-  MPIN_HASH_ID(&CLIENT_ID,&HCID);
   MPIN_GET_G1_MULTIPLE(&RNG,1,&R,&HCID,&Z);  /* Also Send Z=r.ID to Server, remember random r */
 #endif
 
   /* Server calculates H(ID) and H(ID)+H(T|H(ID)) (if time permits enabled), and maps them to points on the curve HID and HTID resp. */
-  MPIN_SERVER_1(date,&CLIENT_ID,pHID,pHTID);
+  MPIN_SERVER_1(date,pID,pHID,pHTID);
 
   /* Server generates Random number Y and sends it to Client */
   MPIN_RANDOM_GENERATE(&RNG,&Y);
@@ -248,7 +258,7 @@
 
   if (rtn!=0)
     {
-      printf("Server says - Bad Pin. I don't know you. Feck off.\n");
+      printf("Server says - Bad Pin. \n");
 #ifdef PINERROR
 
       err=MPIN_KANGAROO(&E,&F);
@@ -259,15 +269,22 @@
     }
   else
     {
-      printf("Server says - PIN is good! You really are "); OCT_output_string(&CLIENT_ID); printf(".\n");
+      printf("Server says - PIN is good! ID: "); 
+      OCT_output_string(&CLIENT_ID); 
+      printf(".\n");
     }
 
 #ifdef FULL
-  MPIN_CLIENT_KEY(&G1,&G2,pin,&R,&X,&T,&CK);
-  printf("Client Key = "); OCT_output(&CK);
+  MPIN_HASH_ALL(&HCID,pxID,pxCID,&SEC,&Y,&Z,&T,&H);  
+  MPIN_CLIENT_KEY(&G1,&G2,pin,&R,&X,&H,&T,&CK);      
+  printf("Client Key = "); OCT_output(&CK); 
 
-  MPIN_SERVER_KEY(&Z,&SST,&W,pxID,pxCID,&SK);
-  printf("Server Key = "); OCT_output(&SK);
+  /* Server will use the hashed ID if anonymous connection required.
+     MPIN_HASH_ID(&CLIENT_ID,&HSID);
+     MPIN_HASH_ALL(&HSID,pxID,pxCID,&SEC,&Y,&Z,&T,&H);
+  */
+  MPIN_SERVER_KEY(&Z,&SST,&W,&H,pHID,pxID,pxCID,&SK);
+  printf("Server Key = "); OCT_output(&SK); 
 #endif
   return 0;
 }
diff --git a/c/testrsa.c b/c/testrsa.c
index 7d74f50..81b5887 100755
--- a/c/testrsa.c
+++ b/c/testrsa.c
@@ -48,7 +48,7 @@
     RAW.val[3]=ran>>24;
     for (i=4;i<100;i++) RAW.val[i]=i;
 
-    CREATE_CSPRNG(&RNG,&RAW);   /* initialise strong RNG */
+    RSA_CREATE_CSPRNG(&RNG,&RAW);   /* initialise strong RNG */
 //for (i=0;i<10;i++)
 //{
 
@@ -57,7 +57,7 @@
 
 	printf("Encrypting test string\n");
 	OCT_jstring(&M,(char *)"Hello World\n");
-	OAEP_ENCODE(&M,&RNG,NULL,&E); /* OAEP encode message m to e  */
+	RSA_OAEP_ENCODE(&M,&RNG,NULL,&E); /* OAEP encode message m to e  */
 
 	RSA_ENCRYPT(&pub,&E,&C);     /* encrypt encoded message */
 	printf("Ciphertext= "); OCT_output(&C);
@@ -65,13 +65,13 @@
 	printf("Decrypting test string\n");
     RSA_DECRYPT(&priv,&C,&ML);   /* ... and then decrypt it */
 
-    OAEP_DECODE(NULL,&ML);    /* decode it */
+    RSA_OAEP_DECODE(NULL,&ML);    /* decode it */
 	OCT_output_string(&ML);
 
     OCT_clear(&M); OCT_clear(&ML);   /* clean up afterwards */
     OCT_clear(&C); OCT_clear(&RAW); OCT_clear(&E);
 //}
-	KILL_CSPRNG(&RNG);
+	RSA_KILL_CSPRNG(&RNG);
 
 	RSA_PRIVATE_KEY_KILL(&priv);
 
diff --git a/c/tests/CMakeLists.txt b/c/tests/CMakeLists.txt
index ad56285..6405c0b 100644
--- a/c/tests/CMakeLists.txt
+++ b/c/tests/CMakeLists.txt
@@ -25,7 +25,8 @@
   add_executable (test_mpin_tp test_mpin_tp.c config.h)
   add_executable (test_mpin_random test_mpin_random.c config.h)
   add_executable (test_mpinfull test_mpinfull.c)
-  #add_executable (test_mpinfull_random test_mpinfull_random.c config.h)
+  add_executable (test_mpinfullSingle test_mpinfullSingle.c)
+  add_executable (test_mpinfull_random test_mpinfull_random.c config.h)
   # Link the executable to the libraries
   target_link_libraries (test_mpin mpin) 
   target_link_libraries (test_mpin_sign mpin) 
@@ -36,7 +37,8 @@
   target_link_libraries (test_mpin_tp mpin) 
   target_link_libraries (test_mpin_random mpin) 
   target_link_libraries (test_mpinfull mpin) 
-  #target_link_libraries (test_mpinfull_random mpin) 
+  target_link_libraries (test_mpinfullSingle mpin) 
+  target_link_libraries (test_mpinfull_random mpin) 
   # tests
   do_test (test_mpin "SUCCESS Error Code 0")
   do_test (test_mpin_sign "TEST PASSED")
@@ -47,9 +49,38 @@
   do_test (test_mpin_tp "Iteration ${MPIN_TIME_PERMIT_TESTS} SUCCESS Error Code 0")
   do_test (test_mpin_random "Iteration ${MPIN_RANDOM_TESTS} SUCCESS Error Code 0")
   do_test (test_mpinfull "SUCCESS")
-  #do_test (test_mpinfull_random "Iteration ${MPIN_RANDOM_TESTS} SUCCESS")
+  do_test (test_mpinfullSingle "SUCCESS")
+  do_test (test_mpinfull_random "Iteration ${MPIN_RANDOM_TESTS} SUCCESS")
 endif(BUILD_MPIN)
   
+if(BUILD_SOK)
+  add_executable (test_sok_gcm test_sok_gcm.c)
+  add_executable (test_sok test_sok.c)
+  add_executable (test_sok_tp test_sok_tp.c config.h)
+  # Link the executable to the libraries
+  target_link_libraries (test_sok_gcm sok) 
+  target_link_libraries (test_sok sok) 
+  target_link_libraries (test_sok_tp sok) 
+  # tests  
+  do_test (test_sok_gcm "SUCCESS")
+  do_test (test_sok "SUCCESS")
+  do_test (test_sok_tp "Iteration ${MPIN_RANDOM_TESTS} SUCCESS")
+endif(BUILD_SOK)  
+
+if(BUILD_WCC)
+  add_executable (test_wcc_gcm test_wcc_gcm.c)
+  add_executable (test_wcc test_wcc.c)
+  add_executable (test_wcc_random test_wcc_random.c)
+  # Link the executable to the libraries
+  target_link_libraries (test_wcc_gcm wcc) 
+  target_link_libraries (test_wcc wcc) 
+  target_link_libraries (test_wcc_random wcc) 
+  # tests  
+  do_test (test_wcc_gcm "SUCCESS")
+  do_test (test_wcc "SUCCESS")
+  do_test (test_wcc_random "SUCCESS")
+endif(BUILD_WCC)  
+
 # General tests
 add_executable (test_rsa ${PROJECT_SOURCE_DIR}/c/rsa.c test_rsa.c)
 add_executable (test_ecm ${PROJECT_SOURCE_DIR}/c/ecdh.c test_ecm.c)
diff --git a/c/tests/test_ecdh.c b/c/tests/test_ecdh.c
index 9233adb..8bb9e8c 100755
--- a/c/tests/test_ecdh.c
+++ b/c/tests/test_ecdh.c
@@ -66,7 +66,7 @@
   RAW.val[3]=ran>>24;
   for (i=0;i<100;i++) RAW.val[i]=i;
   /* initialise strong RNG */
-  CREATE_CSPRNG(&RNG,&RAW);
+  ECP_CREATE_CSPRNG(&RNG,&RAW);
 
   SALT.len=8;
   for (i=0;i<8;i++) SALT.val[i]=i+1;  // set Salt
@@ -77,7 +77,7 @@
   OCT_jstring(&PW,pp);   // set Password from string
 
   /* private key S0 of size EGS bytes derived from Password and Salt */
-  PBKDF2(&PW,&SALT,1000,EGS,&S0);
+  ECP_PBKDF2(&PW,&SALT,1000,EGS,&S0);
   printf("Alices private key= 0x"); OCT_output(&S0);
 
   /* Generate Key pair S/W */
@@ -104,8 +104,8 @@
   printf("Servers public key= 0x");   OCT_output(&W1);
 
   /* Calculate common key using DH - IEEE 1363 method */
-  ECPSVDP_DH(&S0,&W1,&Z0);
-  ECPSVDP_DH(&S1,&W0,&Z1);
+  ECP_SVDP_DH(&S0,&W1,&Z0);
+  ECP_SVDP_DH(&S1,&W0,&Z1);
 
   if (!OCT_comp(&Z0,&Z1))
   {
@@ -113,7 +113,7 @@
     return 0;
   }
 
-  KDF2(&Z0,NULL,EAS,&KEY);
+  ECP_KDF2(&Z0,NULL,EAS,&KEY);
 
   printf("Alice's DH Key=  0x"); OCT_output(&KEY);
   printf("Servers DH Key=  0x"); OCT_output(&KEY);
@@ -144,7 +144,7 @@
 
   printf("Testing ECDSA\n");
 
-  if (ECPSP_DSA(&RNG,&S0,&M,&CS,&DS)!=0)
+  if (ECP_SP_DSA(&RNG,&S0,&M,&CS,&DS)!=0)
   {
     printf("***ECDSA Signature Failed\n");
     return 1;
@@ -153,14 +153,14 @@
   printf("Signature C = 0x"); OCT_output(&CS);
   printf("Signature D = 0x"); OCT_output(&DS);
 
-  if (ECPVP_DSA(&W0,&M,&CS,&DS)!=0)
+  if (ECP_VP_DSA(&W0,&M,&CS,&DS)!=0)
   {
     printf("***ECDSA Verification Failed\n");
     return 1;
   }
   else printf("ECDSA Signature/Verification succeeded %d\n",j);
 
-  KILL_CSPRNG(&RNG);
+  ECP_KILL_CSPRNG(&RNG);
 
   printf("SUCCESS\n");
   return 0;
diff --git a/c/tests/test_ecm.c b/c/tests/test_ecm.c
index 454d753..c96e4ab 100755
--- a/c/tests/test_ecm.c
+++ b/c/tests/test_ecm.c
@@ -58,7 +58,7 @@
   RAW.val[3]=ran>>24;
   for (i=4;i<100;i++) RAW.val[i]=i;
 
-  CREATE_CSPRNG(&RNG,&RAW);   /* initialise strong RNG */
+  ECP_CREATE_CSPRNG(&RNG,&RAW);   /* initialise strong RNG */
 
   SALT.len=8;
   for (i=0;i<8;i++) SALT.val[i]=i+1;  // set Salt
@@ -69,7 +69,7 @@
   OCT_jstring(&PW,pp);   // set Password from string
 
   /* private key S0 of size EGS bytes derived from Password and Salt */
-  PBKDF2(&PW,&SALT,1000,EGS,&S0);
+  ECP_PBKDF2(&PW,&SALT,1000,EGS,&S0);
   printf("Alices private key= 0x"); OCT_output(&S0);
 
   /* Generate Key pair S/W */
@@ -98,8 +98,8 @@
 
   /* Calculate common key using DH - IEEE 1363 method */
 
-  ECPSVDP_DH(&S0,&W1,&Z0);
-  ECPSVDP_DH(&S1,&W0,&Z1);
+  ECP_SVDP_DH(&S0,&W1,&Z0);
+  ECP_SVDP_DH(&S1,&W0,&Z1);
 
   if (!OCT_comp(&Z0,&Z1))
   {
@@ -107,7 +107,7 @@
     return 1;
   }
 
-  KDF2(&Z0,NULL,EAS,&KEY);
+  ECP_KDF2(&Z0,NULL,EAS,&KEY);
 
   printf("Alice's DH Key=  0x"); OCT_output(&KEY);
   printf("Servers DH Key=  0x"); OCT_output(&KEY);
diff --git a/c/tests/test_mpin.c b/c/tests/test_mpin.c
index 907b2fe..b747fc9 100755
--- a/c/tests/test_mpin.c
+++ b/c/tests/test_mpin.c
@@ -29,8 +29,8 @@
 {
   int i,PIN1,PIN2,rtn,err;
 
-  char client_id[256];
-  octet CLIENT_ID = {0,sizeof(client_id),client_id};
+  char id[256];
+  octet ID = {0,sizeof(id),id};
 
   char x[PGS],y1[PGS],y2[PGS];
   octet X={sizeof(x), sizeof(x),x};
@@ -87,7 +87,7 @@
 
   /* Assign the End-User an ID */
   char* user = "testuser@miracl.com";
-  OCT_jstring(&CLIENT_ID,user);
+  OCT_jstring(&ID,user);
   printf("CLIENT: ID %s\n", user);
 
   int date = 0;
@@ -100,25 +100,31 @@
   for (i=0;i<100;i++) SEED.val[i]=i+1;
 
   /* initialise random number generator */
-  CREATE_CSPRNG(&RNG,&SEED);
+  MPIN_CREATE_CSPRNG(&RNG,&SEED);
 
-  /* Hash CLIENT_ID */
-  MPIN_HASH_ID(&CLIENT_ID,&HCID);
+  /* Hash ID */
+  MPIN_HASH_ID(&ID,&HCID);
   OCT_output(&HCID);
 
+  /* When set only send hashed IDs to server */
+  octet *pID;
+#ifdef USE_ANONYMOUS
+  pID = &HCID;
+#else
+  pID = &ID;
+#endif
+
   /* Generate Client master secret for MIRACL and Customer */
   rtn = MPIN_RANDOM_GENERATE(&RNG,&MS1);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_RANDOM_GENERATE(&RNG,&MS1) Error %d\n", rtn);
       return 1;
-    }
+  }
   rtn = MPIN_RANDOM_GENERATE(&RNG,&MS2);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_RANDOM_GENERATE(&RNG,&MS2) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("MASTER SECRET MIRACL:= 0x");
   OCT_output(&MS1);
   printf("MASTER SECRET CUSTOMER:= 0x");
@@ -126,17 +132,15 @@
 
   /* Generate server secret shares */
   rtn = MPIN_GET_SERVER_SECRET(&MS1,&SS1);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_SERVER_SECRET(&MS1,&SS1) Error %d\n", rtn);
       return 1;
-    }
+  }
   rtn = MPIN_GET_SERVER_SECRET(&MS2,&SS2);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_SERVER_SECRET(&MS2,&SS2) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("SS1 = 0x");
   OCT_output(&SS1);
   printf("SS2 = 0x");
@@ -144,27 +148,24 @@
 
   /* Combine server secret share */
   rtn = MPIN_RECOMBINE_G2(&SS1, &SS2, &ServerSecret);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_RECOMBINE_G2(&SS1, &SS2, &ServerSecret) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("ServerSecret = 0x");
   OCT_output(&ServerSecret);
 
   /* Generate client secret shares */
   rtn = MPIN_GET_CLIENT_SECRET(&MS1,&HCID,&CS1);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_CLIENT_SECRET(&MS1,&HCID,&CS1) Error %d\n", rtn);
       return 1;
-    }
+  }
   rtn = MPIN_GET_CLIENT_SECRET(&MS2,&HCID,&CS2);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_CLIENT_SECRET(&MS2,&HCID,&CS2) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("CS1 = 0x");
   OCT_output(&CS1);
   printf("CS2 = 0x");
@@ -172,29 +173,26 @@
 
   /* Combine client secret shares : TOKEN is the full client secret */
   rtn = MPIN_RECOMBINE_G1(&CS1, &CS2, &TOKEN);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_RECOMBINE_G1(&CS1, &CS2, &TOKEN) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("Client Secret = 0x");
   OCT_output(&TOKEN);
 
   /* Generate Time Permit shares */
-  date = today();
+  date = MPIN_today();
   printf("Date %d \n", date);
   rtn = MPIN_GET_CLIENT_PERMIT(date,&MS1,&HCID,&TP1);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_CLIENT_PERMIT(date,&MS1,&HCID,&TP1) Error %d\n", rtn);
       return 1;
-    }
+  }
   rtn = MPIN_GET_CLIENT_PERMIT(date,&MS2,&HCID,&TP2);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_CLIENT_PERMIT(date,&MS2,&HCID,&TP2) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("TP1 = 0x");
   OCT_output(&TP1);
   printf("TP2 = 0x");
@@ -202,56 +200,44 @@
 
   /* Combine Time Permit shares */
   rtn = MPIN_RECOMBINE_G1(&TP1, &TP2, &TP);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_RECOMBINE_G1(&TP1, &TP2, &TP) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("Time Permit = 0x");
   OCT_output(&TP);
 
-  /* This encoding makes Time permit look random */
-  if (MPIN_ENCODING(&RNG,&TP)!=0) printf("Encoding error\n");
-  printf("Encoded Time Permit= "); OCT_output(&TP);
-  if (MPIN_DECODING(&TP)!=0) printf("Decoding error\n");
-  printf("Decoded Time Permit= "); OCT_output(&TP);
-
   /* Client extracts PIN1 from secret to create Token */
-  rtn = MPIN_EXTRACT_PIN(&CLIENT_ID, PIN1, &TOKEN);
-  if (rtn != 0)
-    {
-      printf("MPIN_EXTRACT_PIN( &CLIENT_ID, PIN, &TOKEN) Error %d\n", rtn);
+  rtn = MPIN_EXTRACT_PIN(&ID, PIN1, &TOKEN);
+  if (rtn != 0) {
+      printf("MPIN_EXTRACT_PIN( &ID, PIN, &TOKEN) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("Token = 0x");
   OCT_output(&TOKEN);
 
-  /* One pass MPIN protocol */
+  /* Single pass MPIN protocol */
   /* Client  */
   TimeValue = MPIN_GET_TIME();
   printf("TimeValue %d \n", TimeValue);
-  rtn = MPIN_CLIENT(date,&CLIENT_ID,&RNG,&X,PIN2,&TOKEN,&SEC,NULL,&UT,&TP,NULL,TimeValue,&Y1);
-  if (rtn != 0)
-    {
+  rtn = MPIN_CLIENT(date,&ID,&RNG,&X,PIN2,&TOKEN,&SEC,NULL,&UT,&TP,NULL,TimeValue,&Y1);
+  if (rtn != 0) {
       printf("MPIN_CLIENT ERROR %d\n", rtn);
       return 1;
-    }
+  }
   printf("Y1 = 0x");
   OCT_output(&Y1);
   printf("V = 0x");
   OCT_output(&SEC);
 
   /* Server  */
-  rtn = MPIN_SERVER(date,NULL,&HTID,&Y2,&ServerSecret,NULL,&UT,&SEC,&E,&F,&CLIENT_ID,NULL,TimeValue);
+  rtn = MPIN_SERVER(date,NULL,&HTID,&Y2,&ServerSecret,NULL,&UT,&SEC,&E,&F,pID,NULL,TimeValue);
   printf("Y2 = 0x");
   OCT_output(&Y2);
-  if (rtn != 0)
-    {
-      printf("FAILURE Invalid Token Error Code %d\n", rtn);
-    }
-  else
-    {
-      printf("SUCCESS Error Code %d\n", rtn);
-    }
+  if (rtn != 0) {
+    printf("FAILURE Invalid Token Error Code %d\n", rtn);
+  } else {
+    printf("SUCCESS Error Code %d\n", rtn);
+  }
   return 0;
 }
diff --git a/c/tests/test_mpin_bad_pin.c b/c/tests/test_mpin_bad_pin.c
index 2ba5007..454cbfc 100755
--- a/c/tests/test_mpin_bad_pin.c
+++ b/c/tests/test_mpin_bad_pin.c
@@ -29,8 +29,8 @@
 {
   int i,PIN1,PIN2,rtn,err;
 
-  char client_id[256];
-  octet CLIENT_ID = {0,sizeof(client_id),client_id};
+  char id[256];
+  octet ID = {0,sizeof(id),id};
 
   char x[PGS],y[PGS];
   octet X={sizeof(x), sizeof(x),x};
@@ -41,7 +41,7 @@
   octet MS1={sizeof(ms1),sizeof(ms1),ms1};
   octet MS2={sizeof(ms2),sizeof(ms2),ms2};
 
-  /* Hash values of CLIENT_ID */
+  /* Hash values of ID */
   char hcid[32];
   octet HCID={sizeof(hcid),sizeof(hcid), hcid};
 
@@ -84,7 +84,7 @@
 
   /* Assign the End-User an ID */
   char* user = "testuser@miracl.com";
-  OCT_jstring(&CLIENT_ID,user);
+  OCT_jstring(&ID,user);
   printf("CLIENT: ID %s\n", user);
 
   int date = 16512;
@@ -97,25 +97,31 @@
   for (i=0;i<100;i++) SEED.val[i]=i+1;
 
   /* initialise random number generator */
-  CREATE_CSPRNG(&RNG,&SEED);
+  MPIN_CREATE_CSPRNG(&RNG,&SEED);
 
-  /* Hash CLIENT_ID */
-  MPIN_HASH_ID(&CLIENT_ID,&HCID);
+  /* Hash ID */
+  MPIN_HASH_ID(&ID,&HCID);
   OCT_output(&HCID);
 
+  /* When set only send hashed IDs to server */
+  octet *pID;
+#ifdef USE_ANONYMOUS
+  pID = &HCID;
+#else
+  pID = &ID;
+#endif
+
   /* Generate Client master secret for MIRACL and Customer */
   rtn = MPIN_RANDOM_GENERATE(&RNG,&MS1);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_RANDOM_GENERATE(&RNG,&MS1) Error %d\n", rtn);
       return 1;
-    }
+  }
   rtn = MPIN_RANDOM_GENERATE(&RNG,&MS2);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_RANDOM_GENERATE(&RNG,&MS2) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("MASTER SECRET MIRACL:= 0x");
   OCT_output(&MS1);
   printf("MASTER SECRET CUSTOMER:= 0x");
@@ -123,17 +129,15 @@
 
   /* Generate server secret shares */
   rtn = MPIN_GET_SERVER_SECRET(&MS1,&SS1);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_SERVER_SECRET(&MS1,&SS1) Error %d\n", rtn);
       return 1;
-    }
+  }
   rtn = MPIN_GET_SERVER_SECRET(&MS2,&SS2);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_SERVER_SECRET(&MS2,&SS2) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("SS1 = 0x");
   OCT_output(&SS1);
   printf("SS2 = 0x");
@@ -141,27 +145,24 @@
 
   /* Combine server secret share */
   rtn = MPIN_RECOMBINE_G2(&SS1, &SS2, &ServerSecret);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_RECOMBINE_G2(&SS1, &SS2, &ServerSecret) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("ServerSecret = 0x");
   OCT_output(&ServerSecret);
 
   /* Generate client secret shares */
   rtn = MPIN_GET_CLIENT_SECRET(&MS1,&HCID,&CS1);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_CLIENT_SECRET(&MS1,&HCID,&CS1) Error %d\n", rtn);
       return 1;
-    }
+  }
   rtn = MPIN_GET_CLIENT_SECRET(&MS2,&HCID,&CS2);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_CLIENT_SECRET(&MS2,&HCID,&CS2) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("CS1 = 0x");
   OCT_output(&CS1);
   printf("CS2 = 0x");
@@ -169,28 +170,25 @@
 
   /* Combine client secret shares : TOKEN is the full client secret */
   rtn = MPIN_RECOMBINE_G1(&CS1, &CS2, &TOKEN);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_RECOMBINE_G1(&CS1, &CS2, &TOKEN) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("Client Secret = 0x");
   OCT_output(&TOKEN);
 
   /* Generate Time Permit shares */
   printf("Date %d \n", date);
   rtn = MPIN_GET_CLIENT_PERMIT(date,&MS1,&HCID,&TP1);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_CLIENT_PERMIT(date,&MS1,&HCID,&TP1) Error %d\n", rtn);
       return 1;
-    }
+  }
   rtn = MPIN_GET_CLIENT_PERMIT(date,&MS2,&HCID,&TP2);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_CLIENT_PERMIT(date,&MS2,&HCID,&TP2) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("TP1 = 0x");
   OCT_output(&TP1);
   printf("TP2 = 0x");
@@ -198,71 +196,61 @@
 
   /* Combine Time Permit shares */
   rtn = MPIN_RECOMBINE_G1(&TP1, &TP2, &TP);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_RECOMBINE_G1(&TP1, &TP2, &TP) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("Time Permit = 0x");
   OCT_output(&TP);
 
-  /* This encoding makes Time permit look random */
-  if (MPIN_ENCODING(&RNG,&TP)!=0) printf("Encoding error\n");
-  printf("Encoded Time Permit= "); OCT_output(&TP);
-  if (MPIN_DECODING(&TP)!=0) printf("Decoding error\n");
-  printf("Decoded Time Permit= "); OCT_output(&TP);
-
   /* Client extracts PIN1 from secret to create Token */
-  rtn = MPIN_EXTRACT_PIN(&CLIENT_ID, PIN1, &TOKEN);
-  if (rtn != 0)
-    {
-      printf("MPIN_EXTRACT_PIN(&CLIENT_ID, PIN, &TOKEN) Error %d\n", rtn);
+  rtn = MPIN_EXTRACT_PIN(&ID, PIN1, &TOKEN);
+  if (rtn != 0) {
+      printf("MPIN_EXTRACT_PIN(&ID, PIN, &TOKEN) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("Token = 0x");
   OCT_output(&TOKEN);
 
   /* Client first pass */
-  rtn = MPIN_CLIENT_1(date,&CLIENT_ID,&RNG,&X,PIN2,&TOKEN,&SEC,&U,&UT,&TP);
-  if (rtn != 0)
-    {
+  rtn = MPIN_CLIENT_1(date,&ID,&RNG,&X,PIN2,&TOKEN,&SEC,&U,&UT,&TP);
+  if (rtn != 0) {
       printf("MPIN_CLIENT_1 ERROR %d\n", rtn);
       return 1;
-    }
+  }
 
   /* Server calculates H(ID) and H(T|H(ID)) (if time permits enabled), and maps them to points on the curve HID and HTID resp. */
-  MPIN_SERVER_1(date,&CLIENT_ID,&HID,&HTID);
+  MPIN_SERVER_1(date,pID,&HID,&HTID);
 
   /* Server generates Random number Y and sends it to Client */
   rtn = MPIN_RANDOM_GENERATE(&RNG,&Y);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_RANDOM_GENERATE(&RNG,&Y) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("Y = 0x");
   OCT_output(&Y);
 
   /* Client second pass */
   rtn = MPIN_CLIENT_2(&X,&Y,&SEC);
-  if (rtn != 0)
+  if (rtn != 0) {
     printf("MPIN_CLIENT_2(&X,&Y,&SEC) Error %d\n", rtn);
+  }
   printf("V = 0x");
   OCT_output(&SEC);
 
   /* Server second pass */
   rtn = MPIN_SERVER_2(date,&HID,&HTID,&Y,&ServerSecret,&U,&UT,&SEC,&E,&F);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       err=MPIN_KANGAROO(&E,&F);
       if (err)
         printf("FAILURE PIN Error %d, Error Code %d\n",err, rtn);
       else
         printf("FAILURE Invalid Token Error Code %d\n", rtn);
-    }
-  else
-    {
-      printf("SUCCESS Error Code %d\n", rtn); OCT_output_string(&CLIENT_ID); printf("\n");
-    }
+  } else {
+      printf("SUCCESS Error Code %d\n", rtn); 
+      OCT_output_string(&ID); 
+      printf("\n");
+  }
   return 0;
 }
diff --git a/c/tests/test_mpin_bad_token.c b/c/tests/test_mpin_bad_token.c
index 0bd540f..61e4838 100755
--- a/c/tests/test_mpin_bad_token.c
+++ b/c/tests/test_mpin_bad_token.c
@@ -29,8 +29,8 @@
 {
   int i,PIN1,PIN2,rtn,err;
 
-  char client_id[256];
-  octet CLIENT_ID = {0,sizeof(client_id),client_id};
+  char id[256];
+  octet ID = {0,sizeof(id),id};
 
   char x[PGS],y[PGS];
   octet X={sizeof(x), sizeof(x),x};
@@ -41,7 +41,7 @@
   octet MS1={sizeof(ms1),sizeof(ms1),ms1};
   octet MS2={sizeof(ms2),sizeof(ms2),ms2};
 
-  /* Hash values of CLIENT_ID */
+  /* Hash values of ID */
   char hcid[32];
   octet HCID={sizeof(hcid),sizeof(hcid), hcid};
 
@@ -84,7 +84,7 @@
 
   /* Assign the End-User an ID */
   char* user = "testuser@miracl.com";
-  OCT_jstring(&CLIENT_ID,user);
+  OCT_jstring(&ID,user);
   printf("CLIENT: ID %s\n", user);
 
   int date = 0;
@@ -97,25 +97,31 @@
   for (i=0;i<100;i++) SEED.val[i]=i+1;
 
   /* initialise random number generator */
-  CREATE_CSPRNG(&RNG,&SEED);
+  MPIN_CREATE_CSPRNG(&RNG,&SEED);
 
-  /* Hash CLIENT_ID */
-  MPIN_HASH_ID(&CLIENT_ID,&HCID);
+  /* Hash ID */
+  MPIN_HASH_ID(&ID,&HCID);
   OCT_output(&HCID);
 
+  /* When set only send hashed IDs to server */
+  octet *pID;
+#ifdef USE_ANONYMOUS
+  pID = &HCID;
+#else
+  pID = &ID;
+#endif
+
   /* Generate Client master secret for MIRACL and Customer */
   rtn = MPIN_RANDOM_GENERATE(&RNG,&MS1);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_RANDOM_GENERATE(&RNG,&MS1) Error %d\n", rtn);
       return 1;
-    }
+  }
   rtn = MPIN_RANDOM_GENERATE(&RNG,&MS2);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_RANDOM_GENERATE(&RNG,&MS2) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("MASTER SECRET MIRACL:= 0x");
   OCT_output(&MS1);
   printf("MASTER SECRET CUSTOMER:= 0x");
@@ -123,17 +129,15 @@
 
   /* Generate server secret shares */
   rtn = MPIN_GET_SERVER_SECRET(&MS1,&SS1);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_SERVER_SECRET(&MS1,&SS1) Error %d\n", rtn);
       return 1;
-    }
+  }
   rtn = MPIN_GET_SERVER_SECRET(&MS2,&SS2);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_SERVER_SECRET(&MS2,&SS2) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("SS1 = 0x");
   OCT_output(&SS1);
   printf("SS2 = 0x");
@@ -141,27 +145,24 @@
 
   /* Combine server secret share */
   rtn = MPIN_RECOMBINE_G2(&SS1, &SS2, &ServerSecret);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_RECOMBINE_G2(&SS1, &SS2, &ServerSecret) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("ServerSecret = 0x");
   OCT_output(&ServerSecret);
 
   /* Generate client secret shares */
   rtn = MPIN_GET_CLIENT_SECRET(&MS1,&HCID,&CS1);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_CLIENT_SECRET(&MS1,&HCID,&CS1) Error %d\n", rtn);
       return 1;
-    }
+  }
   rtn = MPIN_GET_CLIENT_SECRET(&MS2,&HCID,&CS2);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_CLIENT_SECRET(&MS2,&HCID,&CS2) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("CS1 = 0x");
   OCT_output(&CS1);
   printf("CS2 = 0x");
@@ -169,29 +170,26 @@
 
   /* Combine client secret shares : TOKEN is the full client secret */
   rtn = MPIN_RECOMBINE_G1(&CS1, &CS2, &TOKEN);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_RECOMBINE_G1(&CS1, &CS2, &TOKEN) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("Client Secret = 0x");
   OCT_output(&TOKEN);
 
   /* Generate Time Permit shares */
-  date = today();
+  date = MPIN_today();
   printf("Date %d \n", date);
   rtn = MPIN_GET_CLIENT_PERMIT(date,&MS1,&HCID,&TP1);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_CLIENT_PERMIT(date,&MS1,&HCID,&TP1) Error %d\n", rtn);
       return 1;
-    }
+  }
   rtn = MPIN_GET_CLIENT_PERMIT(date,&MS2,&HCID,&TP2);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_CLIENT_PERMIT(date,&MS2,&HCID,&TP2) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("TP1 = 0x");
   OCT_output(&TP1);
   printf("TP2 = 0x");
@@ -199,70 +197,59 @@
 
   /* Combine Time Permit shares */
   rtn = MPIN_RECOMBINE_G1(&TP1, &TP2, &TP);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_RECOMBINE_G1(&TP1, &TP2, &TP) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("Time Permit = 0x");
   OCT_output(&TP);
 
-  /* This encoding makes Time permit look random */
-  if (MPIN_ENCODING(&RNG,&TP)!=0) printf("Encoding error\n");
-  printf("Encoded Time Permit= "); OCT_output(&TP);
-  if (MPIN_DECODING(&TP)!=0) printf("Decoding error\n");
-  printf("Decoded Time Permit= "); OCT_output(&TP);
-
   /* Client extracts PIN1 from secret to create Token */
-  rtn = MPIN_EXTRACT_PIN(&CLIENT_ID, PIN1, &TOKEN);
-  if (rtn != 0)
-    {
-      printf("MPIN_EXTRACT_PIN(&CLIENT_ID, PIN, &TOKEN) Error %d\n", rtn);
+  rtn = MPIN_EXTRACT_PIN(&ID, PIN1, &TOKEN);
+  if (rtn != 0) {
+      printf("MPIN_EXTRACT_PIN(&ID, PIN, &TOKEN) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("Token = 0x");
   OCT_output(&TOKEN);
 
   /* Client first pass */
-  rtn = MPIN_CLIENT_1(date,&CLIENT_ID,&RNG,&X,PIN2,&TOKEN,&SEC,&U,&UT,&TP);
-  if (rtn != 0)
-    {
+  rtn = MPIN_CLIENT_1(date,&ID,&RNG,&X,PIN2,&TOKEN,&SEC,&U,&UT,&TP);
+  if (rtn != 0) {
       printf("MPIN_CLIENT_1 ERROR %d\n", rtn);
       return 1;
-    }
+  }
 
   /* Server calculates H(ID) and H(T|H(ID)) (if time permits enabled), and maps them to points on the curve HID and HTID resp. */
-  MPIN_SERVER_1(date,&CLIENT_ID,&HID,&HTID);
+  MPIN_SERVER_1(date,pID,&HID,&HTID);
 
   /* Server generates Random number Y and sends it to Client */
   rtn = MPIN_RANDOM_GENERATE(&RNG,&Y);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_RANDOM_GENERATE(&RNG,&Y) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("Y = 0x");
   OCT_output(&Y);
 
   /* Client second pass */
   rtn = MPIN_CLIENT_2(&X,&Y,&SEC);
-  if (rtn != 0)
+  if (rtn != 0) {
     printf("MPIN_CLIENT_2(&X,&Y,&SEC) Error %d\n", rtn);
+  }
   printf("V = 0x");
   OCT_output(&SEC);
 
   /* Server second pass */
   /* Set SEC to UT to simulate a bad token */
   rtn = MPIN_SERVER_2(date,&HID,&HTID,&Y,&ServerSecret,&U,&UT,&UT,&E,&F);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       err=MPIN_KANGAROO(&E,&F);
       if (err==0) printf("FAILURE Invalid Token Error Code %d\n", rtn);
       else printf("FAILURE PIN Error %d, Error Code %d\n",err, rtn);
-    }
-  else
-    {
-      printf("SUCCESS Error Code %d\n", rtn); OCT_output_string(&CLIENT_ID); printf("\n");
-    }
+  } else {
+      printf("SUCCESS Error Code %d\n", rtn); 
+      OCT_output_string(&ID); printf("\n");
+  }
   return 0;
 }
diff --git a/c/tests/test_mpin_expired_tp.c b/c/tests/test_mpin_expired_tp.c
index e2ddc25..cb7f23e 100755
--- a/c/tests/test_mpin_expired_tp.c
+++ b/c/tests/test_mpin_expired_tp.c
@@ -29,8 +29,8 @@
 {
   int i,PIN1,PIN2,rtn,err;
 
-  char client_id[256];
-  octet CLIENT_ID = {0,sizeof(client_id),client_id};
+  char id[256];
+  octet ID = {0,sizeof(id),id};
 
   char x[PGS],y[PGS];
   octet X={sizeof(x), sizeof(x),x};
@@ -41,7 +41,7 @@
   octet MS1={sizeof(ms1),sizeof(ms1),ms1};
   octet MS2={sizeof(ms2),sizeof(ms2),ms2};
 
-  /* Hash values of CLIENT_ID */
+  /* Hash values of ID */
   char hcid[32];
   octet HCID={sizeof(hcid),sizeof(hcid), hcid};
 
@@ -84,7 +84,7 @@
 
   /* Assign the End-User an ID */
   char* user = "testuser@miracl.com";
-  OCT_jstring(&CLIENT_ID,user);
+  OCT_jstring(&ID,user);
   printf("CLIENT: ID %s\n", user);
 
   int date = 0;
@@ -97,25 +97,31 @@
   for (i=0;i<100;i++) SEED.val[i]=i+1;
 
   /* initialise random number generator */
-  CREATE_CSPRNG(&RNG,&SEED);
+  MPIN_CREATE_CSPRNG(&RNG,&SEED);
 
-  /* Hash CLIENT_ID */
-  MPIN_HASH_ID(&CLIENT_ID,&HCID);
+  /* Hash ID */
+  MPIN_HASH_ID(&ID,&HCID);
   OCT_output(&HCID);
 
+  /* When set only send hashed IDs to server */
+  octet *pID;
+#ifdef USE_ANONYMOUS
+  pID = &HCID;
+#else
+  pID = &ID;
+#endif
+
   /* Generate Client master secret for MIRACL and Customer */
   rtn = MPIN_RANDOM_GENERATE(&RNG,&MS1);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_RANDOM_GENERATE(&RNG,&MS1) Error %d\n", rtn);
       return 1;
-    }
+  }
   rtn = MPIN_RANDOM_GENERATE(&RNG,&MS2);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_RANDOM_GENERATE(&RNG,&MS2) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("MASTER SECRET MIRACL:= 0x");
   OCT_output(&MS1);
   printf("MASTER SECRET CUSTOMER:= 0x");
@@ -123,17 +129,15 @@
 
   /* Generate server secret shares */
   rtn = MPIN_GET_SERVER_SECRET(&MS1,&SS1);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_SERVER_SECRET(&MS1,&SS1) Error %d\n", rtn);
       return 1;
-    }
+  }
   rtn = MPIN_GET_SERVER_SECRET(&MS2,&SS2);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_SERVER_SECRET(&MS2,&SS2) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("SS1 = 0x");
   OCT_output(&SS1);
   printf("SS2 = 0x");
@@ -141,27 +145,24 @@
 
   /* Combine server secret share */
   rtn = MPIN_RECOMBINE_G2(&SS1, &SS2, &ServerSecret);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_RECOMBINE_G2(&SS1, &SS2, &ServerSecret) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("ServerSecret = 0x");
   OCT_output(&ServerSecret);
 
   /* Generate client secret shares */
   rtn = MPIN_GET_CLIENT_SECRET(&MS1,&HCID,&CS1);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_CLIENT_SECRET(&MS1,&HCID,&CS1) Error %d\n", rtn);
       return 1;
-    }
+  }
   rtn = MPIN_GET_CLIENT_SECRET(&MS2,&HCID,&CS2);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_CLIENT_SECRET(&MS2,&HCID,&CS2) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("CS1 = 0x");
   OCT_output(&CS1);
   printf("CS2 = 0x");
@@ -169,30 +170,27 @@
 
   /* Combine client secret shares : TOKEN is the full client secret */
   rtn = MPIN_RECOMBINE_G1(&CS1, &CS2, &TOKEN);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_RECOMBINE_G1(&CS1, &CS2, &TOKEN) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("Client Secret = 0x");
   OCT_output(&TOKEN);
 
   /* Generate Time Permit shares */
-  date = today();
+  date = MPIN_today();
   printf("Date %d \n", date);
   int yesterday = date -1;
   rtn = MPIN_GET_CLIENT_PERMIT(yesterday,&MS1,&HCID,&TP1);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_CLIENT_PERMIT(yesterday,&MS1,&HCID,&TP1) Error %d\n", rtn);
       return 1;
-    }
+  }
   rtn = MPIN_GET_CLIENT_PERMIT(yesterday,&MS2,&HCID,&TP2);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_CLIENT_PERMIT(yesterday,&MS2,&HCID,&TP2) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("TP1 = 0x");
   OCT_output(&TP1);
   printf("TP2 = 0x");
@@ -200,63 +198,58 @@
 
   /* Combine Time Permit shares */
   rtn = MPIN_RECOMBINE_G1(&TP1, &TP2, &TP);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_RECOMBINE_G1(&TP1, &TP2, &TP) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("Time Permit = 0x");
   OCT_output(&TP);
 
   /* Client extracts PIN1 from secret to create Token */
-  rtn = MPIN_EXTRACT_PIN(&CLIENT_ID, PIN1, &TOKEN);
-  if (rtn != 0)
-    {
-      printf("MPIN_EXTRACT_PIN(&CLIENT_ID, PIN, &TOKEN) Error %d\n", rtn);
+  rtn = MPIN_EXTRACT_PIN(&ID, PIN1, &TOKEN);
+  if (rtn != 0) {
+      printf("MPIN_EXTRACT_PIN(&ID, PIN, &TOKEN) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("Token = 0x");
   OCT_output(&TOKEN);
 
   /* Client first pass */
-  rtn = MPIN_CLIENT_1(date,&CLIENT_ID,&RNG,&X,PIN2,&TOKEN,&SEC,&U,&UT,&TP);
-  if (rtn != 0)
-    {
+  rtn = MPIN_CLIENT_1(date,&ID,&RNG,&X,PIN2,&TOKEN,&SEC,&U,&UT,&TP);
+  if (rtn != 0) {
       printf("MPIN_CLIENT_1 ERROR %d\n", rtn);
       return 1;
-    }
+  }
 
   /* Server calculates H(ID) and H(T|H(ID)) (if time permits enabled), and maps them to points on the curve HID and HTID resp. */
-  MPIN_SERVER_1(date,&CLIENT_ID,&HID,&HTID);
+  MPIN_SERVER_1(date,pID,&HID,&HTID);
 
   /* Server generates Random number Y and sends it to Client */
   rtn = MPIN_RANDOM_GENERATE(&RNG,&Y);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_RANDOM_GENERATE(&RNG,&Y) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("Y = 0x");
   OCT_output(&Y);
 
   /* Client second pass */
   rtn = MPIN_CLIENT_2(&X,&Y,&SEC);
-  if (rtn != 0)
+  if (rtn != 0) {
     printf("MPIN_CLIENT_2(&X,&Y,&SEC) Error %d\n", rtn);
+  }
   printf("V = 0x");
   OCT_output(&SEC);
 
   /* Server second pass */
   rtn = MPIN_SERVER_2(date,&HID,&HTID,&Y,&ServerSecret,&U,&UT,&SEC,&E,&F);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       err=MPIN_KANGAROO(&E,&F);
       if (err==0) printf("FAILURE Invalid Token Error Code %d\n", rtn);
       else printf("FAILURE PIN Error %d, Error Code %d\n",err, rtn);
-    }
-  else
-    {
-      printf("SUCCESS Error Code %d\n", rtn); OCT_output_string(&CLIENT_ID); printf("\n");
-    }
+  } else {
+      printf("SUCCESS Error Code %d\n", rtn); 
+      OCT_output_string(&ID); printf("\n");
+  }
   return 0;
 }
diff --git a/c/tests/test_mpin_good.c b/c/tests/test_mpin_good.c
index 21067f8..d43de5e 100755
--- a/c/tests/test_mpin_good.c
+++ b/c/tests/test_mpin_good.c
@@ -29,8 +29,8 @@
 {
   int i,PIN1,PIN2,rtn,err;
 
-  char client_id[256];
-  octet CLIENT_ID = {0,sizeof(client_id),client_id};
+  char id[256];
+  octet ID = {0,sizeof(id),id};
 
   char x[PGS],y[PGS];
   octet X={sizeof(x), sizeof(x),x};
@@ -84,7 +84,7 @@
 
   /* Assign the End-User an ID */
   char* user = "testuser@miracl.com";
-  OCT_jstring(&CLIENT_ID,user);
+  OCT_jstring(&ID,user);
   printf("CLIENT: ID %s\n", user);
 
   int date = 0;
@@ -97,25 +97,31 @@
   for (i=0;i<100;i++) SEED.val[i]=i+1;
 
   /* initialise random number generator */
-  CREATE_CSPRNG(&RNG,&SEED);
+  MPIN_CREATE_CSPRNG(&RNG,&SEED);
 
-  /* Hash CLIENT_ID */
-  MPIN_HASH_ID(&CLIENT_ID,&HCID);
+  /* Hash ID */
+  MPIN_HASH_ID(&ID,&HCID);
   OCT_output(&HCID);
 
+  /* When set only send hashed IDs to server */
+  octet *pID;
+#ifdef USE_ANONYMOUS
+  pID = &HCID;
+#else
+  pID = &ID;
+#endif
+
   /* Generate Client master secret for MIRACL and Customer */
   rtn = MPIN_RANDOM_GENERATE(&RNG,&MS1);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_RANDOM_GENERATE(&RNG,&MS1) Error %d\n", rtn);
       return 1;
-    }
+  }
   rtn = MPIN_RANDOM_GENERATE(&RNG,&MS2);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_RANDOM_GENERATE(&RNG,&MS2) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("MASTER SECRET MIRACL:= 0x");
   OCT_output(&MS1);
   printf("MASTER SECRET CUSTOMER:= 0x");
@@ -123,17 +129,15 @@
 
   /* Generate server secret shares */
   rtn = MPIN_GET_SERVER_SECRET(&MS1,&SS1);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_SERVER_SECRET(&MS1,&SS1) Error %d\n", rtn);
       return 1;
-    }
+  }
   rtn = MPIN_GET_SERVER_SECRET(&MS2,&SS2);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_SERVER_SECRET(&MS2,&SS2) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("SS1 = 0x");
   OCT_output(&SS1);
   printf("SS2 = 0x");
@@ -141,27 +145,24 @@
 
   /* Combine server secret share */
   rtn = MPIN_RECOMBINE_G2(&SS1, &SS2, &ServerSecret);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_RECOMBINE_G2(&SS1, &SS2, &ServerSecret) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("ServerSecret = 0x");
   OCT_output(&ServerSecret);
 
   /* Generate client secret shares */
   rtn = MPIN_GET_CLIENT_SECRET(&MS1,&HCID,&CS1);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_CLIENT_SECRET(&MS1,&HCID,&CS1) Error %d\n", rtn);
       return 1;
-    }
+  }
   rtn = MPIN_GET_CLIENT_SECRET(&MS2,&HCID,&CS2);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_CLIENT_SECRET(&MS2,&HCID,&CS2) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("CS1 = 0x");
   OCT_output(&CS1);
   printf("CS2 = 0x");
@@ -178,20 +179,18 @@
   OCT_output(&TOKEN);
 
   /* Generate Time Permit shares */
-  date = today();
+  date = MPIN_today();
   printf("Date %d \n", date);
   rtn = MPIN_GET_CLIENT_PERMIT(date,&MS1,&HCID,&TP1);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_CLIENT_PERMIT(date,&MS1,&HCID,&TP1) Error %d\n", rtn);
       return 1;
-    }
+  }
   rtn = MPIN_GET_CLIENT_PERMIT(date,&MS2,&HCID,&TP2);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_CLIENT_PERMIT(date,&MS2,&HCID,&TP2) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("TP1 = 0x");
   OCT_output(&TP1);
   printf("TP2 = 0x");
@@ -199,76 +198,62 @@
 
   /* Combine Time Permit shares */
   rtn = MPIN_RECOMBINE_G1(&TP1, &TP2, &TP);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_RECOMBINE_G1(&TP1, &TP2, &TP) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("Time Permit = 0x");
   OCT_output(&TP);
 
-  /* This encoding makes Time permit look random */
-  if (MPIN_ENCODING(&RNG,&TP)!=0) printf("Encoding error\n");
-  printf("Encoded Time Permit= "); OCT_output(&TP);
-  if (MPIN_DECODING(&TP)!=0) printf("Decoding error\n");
-  printf("Decoded Time Permit= "); OCT_output(&TP);
-
   /* Client extracts PIN1 from secret to create Token */
-  rtn = MPIN_EXTRACT_PIN(&CLIENT_ID, PIN1, &TOKEN);
-  if (rtn != 0)
-    {
-      printf("MPIN_EXTRACT_PIN( &CLIENT_ID, PIN, &TOKEN) Error %d\n", rtn);
+  rtn = MPIN_EXTRACT_PIN(&ID, PIN1, &TOKEN);
+  if (rtn != 0) {
+      printf("MPIN_EXTRACT_PIN( &ID, PIN, &TOKEN) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("Token = 0x");
   OCT_output(&TOKEN);
 
   /* Client first pass */
-  rtn = MPIN_CLIENT_1(date,&CLIENT_ID,&RNG,&X,PIN2,&TOKEN,&SEC,&U,&UT,&TP);
-  if (rtn != 0)
-    {
+  rtn = MPIN_CLIENT_1(date,&ID,&RNG,&X,PIN2,&TOKEN,&SEC,&U,&UT,&TP);
+  if (rtn != 0) {
       printf("MPIN_CLIENT_1 ERROR %d\n", rtn);
       return 1;
-    }
+  }
 
   /* Server calculates H(ID) and H(T|H(ID)) (if time permits enabled), and maps them to points on the curve HID and HTID resp. */
-  MPIN_SERVER_1(date,&CLIENT_ID,&HID,&HTID);
+  MPIN_SERVER_1(date,pID,&HID,&HTID);
 
   /* Server generates Random number Y and sends it to Client */
   rtn = MPIN_RANDOM_GENERATE(&RNG,&Y);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_RANDOM_GENERATE(&RNG,&Y) Error %d\n", rtn);
       return 1;
-    }
+  }
 
   printf("Y = 0x");
   OCT_output(&Y);
 
   /* Client second pass */
   rtn = MPIN_CLIENT_2(&X,&Y,&SEC);
-  if (rtn != 0)
-    printf("MPIN_CLIENT_2(&X,&Y,&SEC) Error %d\n", rtn);
+  if (rtn != 0) {
+      printf("MPIN_CLIENT_2(&X,&Y,&SEC) Error %d\n", rtn);
+      return 1;
+  }
   printf("V = 0x");
   OCT_output(&SEC);
 
   /* Server second pass */
   rtn = MPIN_SERVER_2(date,&HID,&HTID,&Y,&ServerSecret,&U,&UT,&SEC,&E,&F);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       err=MPIN_KANGAROO(&E,&F);
-      if (err==0)
-        {
+      if (err==0) {
           printf("FAILURE Invalid Token Error Code %d\n", rtn);
-	}
-      else
-        {
+      } else {
           printf("FAILURE PIN Error %d, Error> Code %d\n",err, rtn);
-	}
-    }
-  else
-    {
+      }
+  } else {
       printf("SUCCESS Error Code %d\n", rtn);
-    }
+  }
   return 0;
 }
diff --git a/c/tests/test_mpin_random.c b/c/tests/test_mpin_random.c
index 61210d5..645cb19 100755
--- a/c/tests/test_mpin_random.c
+++ b/c/tests/test_mpin_random.c
@@ -29,16 +29,17 @@
 // Define PIN range:
 #define MAX_RANGE 10000
 
-void rand_str(char *dest, size_t length) {
-    char charset[] = "0123456789@.*"
-                     "abcdefghijklmnopqrstuvwxyz"
-                     "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-    srand ( time (NULL) );
-    while (length-- > 0) {
-        size_t index = rand() % (sizeof charset);
-        *dest++ = charset[index];
-    }
-    *dest = '\0';
+void rand_str(char *dest, size_t length,csprng *RNG) {
+  BIG r;
+  char charset[] = "0123456789@.*"
+                   "abcdefghijklmnopqrstuvwxyz"
+                   "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+  while (length-- > 0) {
+    BIG_random(r,RNG);
+    size_t index = r[0] % (sizeof charset);
+    *dest++ = charset[index];
+  }
+  *dest = '\0';
 }
 
 int main()
@@ -54,7 +55,7 @@
   octet MS1={sizeof(ms1),sizeof(ms1),ms1};
   octet MS2={sizeof(ms2),sizeof(ms2),ms2};
 
-  /* Hash values of CLIENT_ID */
+  /* Hash values of ID */
   char hcid[32];
   octet HCID={sizeof(hcid),sizeof(hcid), hcid};
 
@@ -92,6 +93,8 @@
   octet E={sizeof(e),sizeof(e),e};
   octet F={sizeof(f),sizeof(f),f};
 
+  octet *pID;
+
   int date = 0;
 
   unsigned long ran;
@@ -119,23 +122,21 @@
   OCT_output(&SEED);
 
   /* initialise random number generator */
-  CREATE_CSPRNG(&RNG,&SEED);
+  MPIN_CREATE_CSPRNG(&RNG,&SEED);
 
   for(iter=1; iter<nRandomTests+1; iter++)
     {
       /* Generate Client master secret for MIRACL and Customer */
       rtn = MPIN_RANDOM_GENERATE(&RNG,&MS1);
-      if (rtn != 0)
-        {
+      if (rtn != 0) {
           printf("MPIN_RANDOM_GENERATE(&RNG,&MS1) Error %d\n", rtn);
           return 1;
-        }
+      }
       rtn = MPIN_RANDOM_GENERATE(&RNG,&MS2);
-      if (rtn != 0)
-        {
+      if (rtn != 0) {
           printf("MPIN_RANDOM_GENERATE(&RNG,&MS2) Error %d\n", rtn);
           return 1;
-        }
+      }
       printf("MASTER SECRET MIRACL:= 0x");
       OCT_output(&MS1);
       printf("MASTER SECRET CUSTOMER:= 0x");
@@ -143,17 +144,15 @@
 
       /* Generate server secret shares */
       rtn = MPIN_GET_SERVER_SECRET(&MS1,&SS1);
-      if (rtn != 0)
-        {
+      if (rtn != 0) {
           printf("MPIN_GET_SERVER_SECRET(&MS1,&SS1) Error %d\n", rtn);
           return 1;
-        }
+      }
       rtn = MPIN_GET_SERVER_SECRET(&MS2,&SS2);
-      if (rtn != 0)
-        {
+      if (rtn != 0) {
           printf("MPIN_GET_SERVER_SECRET(&MS2,&SS2) Error %d\n", rtn);
           return 1;
-        }
+      }
       printf("SS1 = 0x");
       OCT_output(&SS1);
       printf("SS2 = 0x");
@@ -161,25 +160,30 @@
 
       /* Combine server secret share */
       rtn = MPIN_RECOMBINE_G2(&SS1, &SS2, &ServerSecret);
-      if (rtn != 0)
-        {
+      if (rtn != 0) {
           printf("MPIN_RECOMBINE_G2(&SS1, &SS2, &ServerSecret) Error %d\n", rtn);
           return 1;
-        }
+      }
       printf("ServerSecret = 0x");
       OCT_output(&ServerSecret);
 
       /* Assign the End-User an ID */
-      char client_id[256];
-      octet CLIENT_ID = {0,sizeof(client_id),client_id};
-      rand_str(client_id,256);
-      OCT_jstring(&CLIENT_ID,client_id);
-      printf("CLIENT: ID %s\n", client_id);
+      char id[256];
+      octet ID = {0,sizeof(id),id};
+      rand_str(id,256,&RNG);
+      OCT_jstring(&ID,id);
+      printf("CLIENT: ID %s\n", id);
 
-      /* Hash CLIENT_ID */
-      MPIN_HASH_ID(&CLIENT_ID,&HCID);
+      /* Hash ID */
+      MPIN_HASH_ID(&ID,&HCID);
       OCT_output(&HCID);
 
+#ifdef USE_ANONYMOUS
+      pID = &HCID;
+#else
+      pID = &ID;
+#endif
+
       srand ( time (NULL) );
       PIN1 = rand()%MAX_RANGE; // Get random between 0 and MAX_RANGE
       PIN2 = PIN1;
@@ -187,17 +191,15 @@
 
       /* Generate client secret shares */
       rtn = MPIN_GET_CLIENT_SECRET(&MS1,&HCID,&CS1);
-      if (rtn != 0)
-        {
+      if (rtn != 0) {
           printf("MPIN_GET_CLIENT_SECRET(&MS1,&HCID,&CS1) Error %d\n", rtn);
           return 1;
-        }
+      }
       rtn = MPIN_GET_CLIENT_SECRET(&MS2,&HCID,&CS2);
-      if (rtn != 0)
-        {
+      if (rtn != 0) {
           printf("MPIN_GET_CLIENT_SECRET(&MS2,&HCID,&CS2) Error %d\n", rtn);
           return 1;
-        }
+      }
       printf("CS1 = 0x");
       OCT_output(&CS1);
       printf("CS2 = 0x");
@@ -205,40 +207,36 @@
 
       /* Combine client secret shares : TOKEN is the full client secret */
       rtn = MPIN_RECOMBINE_G1(&CS1, &CS2, &TOKEN);
-      if (rtn != 0)
-        {
+      if (rtn != 0) {
           printf("MPIN_RECOMBINE_G1(&CS1, &CS2, &TOKEN) Error %d\n", rtn);
           return 1;
-        }
+      }
       printf("Client Secret = 0x");
       OCT_output(&TOKEN);
 
       /* Client extracts PIN1 from secret to create Token */
-      rtn = MPIN_EXTRACT_PIN(&CLIENT_ID, PIN1, &TOKEN);
-      if (rtn != 0)
-        {
-          printf("MPIN_EXTRACT_PIN( &CLIENT_ID, PIN, &TOKEN) Error %d\n", rtn);
+      rtn = MPIN_EXTRACT_PIN(&ID, PIN1, &TOKEN);
+      if (rtn != 0) {
+          printf("MPIN_EXTRACT_PIN( &ID, PIN, &TOKEN) Error %d\n", rtn);
           return 1;
-        }
+      }
       printf("Token = 0x");
       OCT_output(&TOKEN);
 
       /* Generate Time Permit shares */
-      date = today();
+      date = MPIN_today();
 
       printf("Date %d \n", date);
       rtn = MPIN_GET_CLIENT_PERMIT(date,&MS1,&HCID,&TP1);
-      if (rtn != 0)
-        {
+      if (rtn != 0) {
           printf("MPIN_GET_CLIENT_PERMIT(date,&MS1,&HCID,&TP1) Error %d\n", rtn);
           return 1;
-        }
+      }
       rtn = MPIN_GET_CLIENT_PERMIT(date,&MS2,&HCID,&TP2);
-      if (rtn != 0)
-        {
+      if (rtn != 0) {
           printf("MPIN_GET_CLIENT_PERMIT(date,&MS2,&HCID,&TP2) Error %d\n", rtn);
           return 1;
-        }
+      }
       printf("TP1 = 0x");
       OCT_output(&TP1);
       printf("TP2 = 0x");
@@ -246,69 +244,55 @@
 
       /* Combine Time Permit shares */
       rtn = MPIN_RECOMBINE_G1(&TP1, &TP2, &TP);
-      if (rtn != 0)
-        {
+      if (rtn != 0) {
           printf("MPIN_RECOMBINE_G1(&TP1, &TP2, &TP) Error %d\n", rtn);
           return 1;
-        }
+      }
       printf("Time Permit = 0x");
       OCT_output(&TP);
 
-      /* This encoding makes Time permit look random */
-      if (MPIN_ENCODING(&RNG,&TP)!=0) printf("Encoding error\n");
-      printf("Encoded Time Permit= "); OCT_output(&TP);
-      if (MPIN_DECODING(&TP)!=0) printf("Decoding error\n");
-      printf("Decoded Time Permit= "); OCT_output(&TP);
-
-
       /* Client first pass */
-      rtn = MPIN_CLIENT_1(date,&CLIENT_ID,&RNG,&X,PIN2,&TOKEN,&SEC,&U,&UT,&TP);
-      if (rtn != 0)
-        {
+      rtn = MPIN_CLIENT_1(date,&ID,&RNG,&X,PIN2,&TOKEN,&SEC,&U,&UT,&TP);
+      if (rtn != 0) {
           printf("MPIN_CLIENT_1 ERROR %d\n", rtn);
           return 1;
-        }
+      }
 
       /* Server calculates H(ID) and H(T|H(ID)) (if time permits enabled), and maps them to points on the curve HID and HTID resp. */
-      MPIN_SERVER_1(date,&CLIENT_ID,&HID,&HTID);
+      MPIN_SERVER_1(date,pID,&HID,&HTID);
 
       /* Server generates Random number Y and sends it to Client */
       rtn = MPIN_RANDOM_GENERATE(&RNG,&Y);
-      if (rtn != 0)
-        {
+      if (rtn != 0) {
           printf("MPIN_RANDOM_GENERATE(&RNG,&Y) Error %d\n", rtn);
           return 1;
-        }
+      }
       printf("Y = 0x");
       OCT_output(&Y);
 
       /* Client second pass */
       rtn = MPIN_CLIENT_2(&X,&Y,&SEC);
-      if (rtn != 0)
-        printf("MPIN_CLIENT_2(&X,&Y,&SEC) Error %d\n", rtn);
+      if (rtn != 0) {
+          printf("MPIN_CLIENT_2(&X,&Y,&SEC) Error %d\n", rtn);
+          return 1;
+      }
       printf("V = 0x");
       OCT_output(&SEC);
 
       /* Server second pass */
       rtn = MPIN_SERVER_2(date,&HID,&HTID,&Y,&ServerSecret,&U,&UT,&SEC,&E,&F);
-      if (rtn != 0)
-        {
+      if (rtn != 0) {
           err=MPIN_KANGAROO(&E,&F);
-          if (err==0)
-            {
+          if (err==0) {
               printf("Iteration %d FAILURE Invalid Token Error Code %d\n", iter, rtn);
               return 1;
-	    }
-          else
-            {
+	  } else {
               printf("Iteration %d FAILURE PIN Error %d, Error Code %d\n", iter, err, rtn);
               return 1;
-	    }
-        }
-      else
-        {
+	  }
+      } else {
           printf("Iteration %d SUCCESS Error Code %d\n\n", iter, rtn);
-        }
+      }
     }
   return 0;
 }
diff --git a/c/tests/test_mpin_sign.c b/c/tests/test_mpin_sign.c
index 5915769..7743e66 100755
--- a/c/tests/test_mpin_sign.c
+++ b/c/tests/test_mpin_sign.c
@@ -86,6 +86,8 @@
   octet E={sizeof(e),sizeof(e),e};
   octet F={sizeof(f),sizeof(f),f};
 
+
+
   int TimeValue = 0;
 
   PIN1 = 1234;
@@ -106,25 +108,31 @@
   for (i=0;i<100;i++) SEED.val[i]=i+1;
 
   /* initialise random number generator */
-  CREATE_CSPRNG(&RNG,&SEED);
+  MPIN_CREATE_CSPRNG(&RNG,&SEED);
 
   /* Hash ID */
   MPIN_HASH_ID(&ID,&HCID);
   OCT_output(&HCID);
 
+  /* When set only send hashed IDs to server */
+  octet *pID;
+#ifdef USE_ANONYMOUS
+  pID = &HCID;
+#else
+  pID = &ID;
+#endif
+
   /* Generate Client master secret for MIRACL and Customer */
   rtn = MPIN_RANDOM_GENERATE(&RNG,&MS1);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_RANDOM_GENERATE(&RNG,&MS1) Error %d\n", rtn);
       return 1;
-    }
+  }
   rtn = MPIN_RANDOM_GENERATE(&RNG,&MS2);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_RANDOM_GENERATE(&RNG,&MS2) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("MASTER SECRET MIRACL:= 0x");
   OCT_output(&MS1);
   printf("MASTER SECRET CUSTOMER:= 0x");
@@ -132,17 +140,15 @@
 
   /* Generate server secret shares */
   rtn = MPIN_GET_SERVER_SECRET(&MS1,&SS1);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_SERVER_SECRET(&MS1,&SS1) Error %d\n", rtn);
       return 1;
-    }
+  }
   rtn = MPIN_GET_SERVER_SECRET(&MS2,&SS2);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_SERVER_SECRET(&MS2,&SS2) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("SS1 = 0x");
   OCT_output(&SS1);
   printf("SS2 = 0x");
@@ -150,27 +156,24 @@
 
   /* Combine server secret share */
   rtn = MPIN_RECOMBINE_G2(&SS1, &SS2, &ServerSecret);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_RECOMBINE_G2(&SS1, &SS2, &ServerSecret) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("ServerSecret = 0x");
   OCT_output(&ServerSecret);
 
   /* Generate client secret shares */
   rtn = MPIN_GET_CLIENT_SECRET(&MS1,&HCID,&CS1);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_CLIENT_SECRET(&MS1,&HCID,&CS1) Error %d\n", rtn);
       return 1;
-    }
+  }
   rtn = MPIN_GET_CLIENT_SECRET(&MS2,&HCID,&CS2);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_CLIENT_SECRET(&MS2,&HCID,&CS2) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("CS1 = 0x");
   OCT_output(&CS1);
   printf("CS2 = 0x");
@@ -178,29 +181,26 @@
 
   /* Combine client secret shares : TOKEN is the full client secret */
   rtn = MPIN_RECOMBINE_G1(&CS1, &CS2, &TOKEN);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_RECOMBINE_G1(&CS1, &CS2, &TOKEN) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("Client Secret = 0x");
   OCT_output(&TOKEN);
 
   /* Generate Time Permit shares */
-  date = today();
+  date = MPIN_today();
   printf("Date %d \n", date);
   rtn = MPIN_GET_CLIENT_PERMIT(date,&MS1,&HCID,&TP1);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_CLIENT_PERMIT(date,&MS1,&HCID,&TP1) Error %d\n", rtn);
       return 1;
-    }
+  }
   rtn = MPIN_GET_CLIENT_PERMIT(date,&MS2,&HCID,&TP2);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_CLIENT_PERMIT(date,&MS2,&HCID,&TP2) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("TP1 = 0x");
   OCT_output(&TP1);
   printf("TP2 = 0x");
@@ -208,27 +208,19 @@
 
   /* Combine Time Permit shares */
   rtn = MPIN_RECOMBINE_G1(&TP1, &TP2, &TP);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_RECOMBINE_G1(&TP1, &TP2, &TP) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("Time Permit = 0x");
   OCT_output(&TP);
 
-  /* This encoding makes Time permit look random */
-  if (MPIN_ENCODING(&RNG,&TP)!=0) printf("Encoding error\n");
-  printf("Encoded Time Permit= "); OCT_output(&TP);
-  if (MPIN_DECODING(&TP)!=0) printf("Decoding error\n");
-  printf("Decoded Time Permit= "); OCT_output(&TP);
-
   /* Client extracts PIN1 from secret to create Token */
   rtn = MPIN_EXTRACT_PIN(&ID, PIN1, &TOKEN);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_EXTRACT_PIN( &ID, PIN, &TOKEN) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("Token = 0x");
   OCT_output(&TOKEN);
 
@@ -240,18 +232,17 @@
   TimeValue = MPIN_GET_TIME();
   printf("TimeValue %d \n", TimeValue);
   rtn = MPIN_CLIENT(date,&ID,&RNG,&X,PIN2,&TOKEN,&SEC,NULL,&UT,&TP,&M,TimeValue,&Y1);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_CLIENT ERROR %d\n", rtn);
       return 1;
-    }
+  }
   printf("Y1 = 0x");
   OCT_output(&Y1);
   printf("V = 0x");
   OCT_output(&SEC);
 
   /* Server  */
-  rtn = MPIN_SERVER(date,NULL,&HTID,&Y2,&ServerSecret,NULL,&UT,&SEC,&E,&F,&ID,&M,TimeValue);
+  rtn = MPIN_SERVER(date,NULL,&HTID,&Y2,&ServerSecret,NULL,&UT,&SEC,&E,&F,pID,&M,TimeValue);
   printf("Y2 = 0x");
   OCT_output(&Y2);
   if (rtn != 0) {
@@ -270,11 +261,10 @@
   TimeValue = MPIN_GET_TIME();
   printf("TimeValue %d \n", TimeValue);
   rtn = MPIN_CLIENT(date,&ID,&RNG,&X,PIN2,&TOKEN,&SEC,NULL,&UT,&TP,&M,TimeValue,&Y1);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_CLIENT ERROR %d\n", rtn);
       return 1;
-    }
+  }
   printf("Y1 = 0x");
   OCT_output(&Y1);
   printf("V = 0x");
@@ -282,7 +272,7 @@
 
   /* Server  */
   TimeValue += 10;
-  rtn = MPIN_SERVER(date,NULL,&HTID,&Y2,&ServerSecret,NULL,&UT,&SEC,&E,&F,&ID,&M,TimeValue);
+  rtn = MPIN_SERVER(date,NULL,&HTID,&Y2,&ServerSecret,NULL,&UT,&SEC,&E,&F,pID,&M,TimeValue);
   printf("Y2 = 0x");
   OCT_output(&Y2);
   if (rtn != -19) {
@@ -301,11 +291,10 @@
   TimeValue = MPIN_GET_TIME();
   printf("TimeValue %d \n", TimeValue);
   rtn = MPIN_CLIENT(date,&ID,&RNG,&X,PIN2,&TOKEN,&SEC,NULL,&UT,&TP,&M,TimeValue,&Y1);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_CLIENT ERROR %d\n", rtn);
       return 1;
-    }
+  }
   printf("Y1 = 0x");
   OCT_output(&Y1);
   printf("V = 0x");
@@ -315,7 +304,7 @@
   OCT_clear(&M);
   message = "bad message";
   OCT_jstring(&M,message);
-  rtn = MPIN_SERVER(date,NULL,&HTID,&Y2,&ServerSecret,NULL,&UT,&SEC,&E,&F,&ID,&M,TimeValue);
+  rtn = MPIN_SERVER(date,NULL,&HTID,&Y2,&ServerSecret,NULL,&UT,&SEC,&E,&F,pID,&M,TimeValue);
   printf("Y2 = 0x");
   OCT_output(&Y2);
   if (rtn != -19) {
diff --git a/c/tests/test_mpin_tp.c b/c/tests/test_mpin_tp.c
index 3bb7a32..05562b9 100755
--- a/c/tests/test_mpin_tp.c
+++ b/c/tests/test_mpin_tp.c
@@ -31,8 +31,8 @@
 {
   int i,PIN1,PIN2,rtn,err,iter;
 
-  char client_id[256];
-  octet CLIENT_ID = {0,sizeof(client_id),client_id};
+  char id[256];
+  octet ID = {0,sizeof(id),id};
 
   char x[PGS],y[PGS];
   octet X={sizeof(x), sizeof(x),x};
@@ -43,7 +43,7 @@
   octet MS1={sizeof(ms1),sizeof(ms1),ms1};
   octet MS2={sizeof(ms2),sizeof(ms2),ms2};
 
-  /* Hash values of CLIENT_ID */
+  /* Hash values of ID */
   char hcid[32];
   octet HCID={sizeof(hcid),sizeof(hcid), hcid};
 
@@ -81,12 +81,14 @@
   octet E={sizeof(e),sizeof(e),e};
   octet F={sizeof(f),sizeof(f),f};
 
+  octet *pID;
+
   PIN1 = 1234;
   PIN2 = 1234;
 
   /* Assign the End-User an ID */
   char* user = "testuser@miracl.com";
-  OCT_jstring(&CLIENT_ID,user);
+  OCT_jstring(&ID,user);
   printf("CLIENT: ID %s\n", user);
 
   int date = 0;
@@ -99,25 +101,30 @@
   for (i=0;i<100;i++) SEED.val[i]=i+1;
 
   /* initialise random number generator */
-  CREATE_CSPRNG(&RNG,&SEED);
+  MPIN_CREATE_CSPRNG(&RNG,&SEED);
 
-  /* Hash CLIENT_ID */
-  MPIN_HASH_ID(&CLIENT_ID,&HCID);
+  /* Hash ID */
+  MPIN_HASH_ID(&ID,&HCID);
   OCT_output(&HCID);
 
+  /* When set only send hashed IDs to server */
+#ifdef USE_ANONYMOUS
+  pID = &HCID;
+#else
+  pID = &ID;
+#endif
+
   /* Generate Client master secret for MIRACL and Customer */
   rtn = MPIN_RANDOM_GENERATE(&RNG,&MS1);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_RANDOM_GENERATE(&RNG,&MS1) Error %d\n", rtn);
       return 1;
-    }
+  }
   rtn = MPIN_RANDOM_GENERATE(&RNG,&MS2);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_RANDOM_GENERATE(&RNG,&MS2) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("MASTER SECRET MIRACL:= 0x");
   OCT_output(&MS1);
   printf("MASTER SECRET CUSTOMER:= 0x");
@@ -125,17 +132,15 @@
 
   /* Generate server secret shares */
   rtn = MPIN_GET_SERVER_SECRET(&MS1,&SS1);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_SERVER_SECRET(&MS1,&SS1) Error %d\n", rtn);
       return 1;
-    }
+  }
   rtn = MPIN_GET_SERVER_SECRET(&MS2,&SS2);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_SERVER_SECRET(&MS2,&SS2) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("SS1 = 0x");
   OCT_output(&SS1);
   printf("SS2 = 0x");
@@ -143,27 +148,24 @@
 
   /* Combine server secret share */
   rtn = MPIN_RECOMBINE_G2(&SS1, &SS2, &ServerSecret);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_RECOMBINE_G2(&SS1, &SS2, &ServerSecret) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("ServerSecret = 0x");
   OCT_output(&ServerSecret);
 
   /* Generate client secret shares */
   rtn = MPIN_GET_CLIENT_SECRET(&MS1,&HCID,&CS1);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_CLIENT_SECRET(&MS1,&HCID,&CS1) Error %d\n", rtn);
       return 1;
-    }
+  }
   rtn = MPIN_GET_CLIENT_SECRET(&MS2,&HCID,&CS2);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_CLIENT_SECRET(&MS2,&HCID,&CS2) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("CS1 = 0x");
   OCT_output(&CS1);
   printf("CS2 = 0x");
@@ -171,41 +173,37 @@
 
   /* Combine client secret shares : TOKEN is the full client secret */
   rtn = MPIN_RECOMBINE_G1(&CS1, &CS2, &TOKEN);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_RECOMBINE_G1(&CS1, &CS2, &TOKEN) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("Client Secret = 0x");
   OCT_output(&TOKEN);
 
   /* Client extracts PIN1 from secret to create Token */
-  rtn = MPIN_EXTRACT_PIN(&CLIENT_ID, PIN1, &TOKEN);
-  if (rtn != 0)
-    {
-      printf("MPIN_EXTRACT_PIN( &CLIENT_ID, PIN, &TOKEN) Error %d\n", rtn);
+  rtn = MPIN_EXTRACT_PIN(&ID, PIN1, &TOKEN);
+  if (rtn != 0) {
+      printf("MPIN_EXTRACT_PIN( &ID, PIN, &TOKEN) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("Token = 0x");
   OCT_output(&TOKEN);
 
   /* Generate Time Permit shares */
-  date = today();
+  date = MPIN_today();
   for(iter=1; iter<nTimePermitTests+1; iter++)
     {
       printf("Date %d \n", date);
       rtn = MPIN_GET_CLIENT_PERMIT(date,&MS1,&HCID,&TP1);
-      if (rtn != 0)
-        {
+      if (rtn != 0) {
           printf("MPIN_GET_CLIENT_PERMIT(date,&MS1,&HCID,&TP1) Error %d\n", rtn);
           return 1;
-        }
+      }
       rtn = MPIN_GET_CLIENT_PERMIT(date,&MS2,&HCID,&TP2);
-      if (rtn != 0)
-        {
+      if (rtn != 0) {
           printf("MPIN_GET_CLIENT_PERMIT(date,&MS2,&HCID,&TP2) Error %d\n", rtn);
           return 1;
-        }
+      }
       printf("TP1 = 0x");
       OCT_output(&TP1);
       printf("TP2 = 0x");
@@ -213,68 +211,55 @@
 
       /* Combine Time Permit shares */
       rtn = MPIN_RECOMBINE_G1(&TP1, &TP2, &TP);
-      if (rtn != 0)
-        {
+      if (rtn != 0) {
           printf("MPIN_RECOMBINE_G1(&TP1, &TP2, &TP) Error %d\n", rtn);
           return 1;
-        }
+      }
       printf("Time Permit = 0x");
       OCT_output(&TP);
 
-      /* This encoding makes Time permit look random */
-      if (MPIN_ENCODING(&RNG,&TP)!=0) printf("Encoding error\n");
-      printf("Encoded Time Permit= "); OCT_output(&TP);
-      if (MPIN_DECODING(&TP)!=0) printf("Decoding error\n");
-      printf("Decoded Time Permit= "); OCT_output(&TP);
-
       /* Client first pass */
-      rtn = MPIN_CLIENT_1(date,&CLIENT_ID,&RNG,&X,PIN2,&TOKEN,&SEC,&U,&UT,&TP);
-      if (rtn != 0)
-        {
+      rtn = MPIN_CLIENT_1(date,&ID,&RNG,&X,PIN2,&TOKEN,&SEC,&U,&UT,&TP);
+      if (rtn != 0) {
           printf("MPIN_CLIENT_1 ERROR %d\n", rtn);
           return 1;
-        }
+      }
 
       /* Server calculates H(ID) and H(T|H(ID)) (if time permits enabled), and maps them to points on the curve HID and HTID resp. */
-      MPIN_SERVER_1(date,&CLIENT_ID,&HID,&HTID);
+      MPIN_SERVER_1(date,pID,&HID,&HTID);
 
       /* Server generates Random number Y and sends it to Client */
       rtn = MPIN_RANDOM_GENERATE(&RNG,&Y);
-      if (rtn != 0)
-        {
+      if (rtn != 0) {
           printf("MPIN_RANDOM_GENERATE(&RNG,&Y) Error %d\n", rtn);
           return 1;
-        }
+      }
       printf("Y = 0x");
       OCT_output(&Y);
 
       /* Client second pass */
       rtn = MPIN_CLIENT_2(&X,&Y,&SEC);
-      if (rtn != 0)
-        printf("MPIN_CLIENT_2(&X,&Y,&SEC) Error %d\n", rtn);
+      if (rtn != 0) {
+          printf("MPIN_CLIENT_2(&X,&Y,&SEC) Error %d\n", rtn);
+          return 1;
+      }
       printf("V = 0x");
       OCT_output(&SEC);
 
       /* Server second pass */
       rtn = MPIN_SERVER_2(date,&HID,&HTID,&Y,&ServerSecret,&U,&UT,&SEC,&E,&F);
-      if (rtn != 0)
-        {
+      if (rtn != 0) {
           err=MPIN_KANGAROO(&E,&F);
-          if (err==0)
-            {
+          if (err==0) {
               printf("Iteration %d FAILURE Invalid Token Error Code %d\n", iter, rtn);
               break;
-	    }
-          else
-            {
+	  } else {
               printf("Iteration %d FAILURE PIN Error %d, Error Code %d\n", iter, err, rtn);
               break;
-	    }
-        }
-      else
-        {
+	   }
+      } else {
           printf("Iteration %d SUCCESS Error Code %d\n", iter, rtn);
-        }
+      }
       date++;
     }
   return 0;
diff --git a/c/tests/test_mpinfull.c b/c/tests/test_mpinfull.c
index 12cabe8..10cc857 100755
--- a/c/tests/test_mpinfull.c
+++ b/c/tests/test_mpinfull.c
@@ -17,7 +17,7 @@
 under the License.
 */
 
-/* Test good token and correct PIN with D-TA */
+/* Test M-Pin Full */
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -29,8 +29,8 @@
 {
   int i,PIN1,PIN2,rtn,err;
 
-  char client_id[256];
-  octet CLIENT_ID = {0,sizeof(client_id),client_id};
+  char id[256];
+  octet ID = {0,sizeof(id),id};
 
   char x[PGS],y[PGS];
   octet X={sizeof(x), sizeof(x),x};
@@ -42,8 +42,14 @@
   octet MS2={sizeof(ms2),sizeof(ms2),ms2};
 
   /* Hash values of client ID */
-  char hcid[32];
+  char hcid[HASH_BYTES];
   octet HCID={sizeof(hcid),sizeof(hcid), hcid};
+  char hsid[HASH_BYTES];
+  octet HSID={sizeof(hsid),sizeof(hsid), hsid};
+
+  /* Hash values of messages */
+  char hm[HASH_BYTES];
+  octet HM={sizeof(hm),sizeof(hm), hm};
 
   /* Client secret and shares */
   char cs1[2*PFS+1], cs2[2*PFS+1], sec[2*PFS+1];
@@ -63,10 +69,15 @@
   octet TP1={sizeof(tp1),sizeof(tp1),tp1};
   octet TP2={sizeof(tp2),sizeof(tp2),tp2};
 
-  /* Token stored on computer */
+  /* Token stored on device */
   char token[2*PFS+1];
   octet TOKEN={sizeof(token),sizeof(token),token};
 
+  /* Precomputed values stored on device */
+  char g1[12*PFS],g2[12*PFS];
+  octet G1={0,sizeof(g1),g1};
+  octet G2={0,sizeof(g2),g2};
+
   char ut[2*PFS+1],u[2*PFS+1];
   octet UT={sizeof(ut),sizeof(ut),ut};
   octet U={sizeof(u),sizeof(u),u};
@@ -80,14 +91,12 @@
   octet F={sizeof(f),sizeof(f),f};
 
   char r[PGS],z[2*PFS+1],w[PGS],t[2*PFS+1];
-  char g1[12*PFS],g2[12*PFS];
+
   char ck[PAS],sk[PAS];
   octet R={0,sizeof(r),r};
   octet Z={0,sizeof(z),z};
   octet W={0,sizeof(w),w};
   octet T={0,sizeof(t),t};
-  octet G1={0,sizeof(g1),g1};
-  octet G2={0,sizeof(g2),g2};
   octet SK={0,sizeof(sk),sk};
   octet CK={0,sizeof(ck),ck};
 
@@ -96,7 +105,7 @@
 
   /* Assign the End-User an ID */
   char* user = "testuser@miracl.com";
-  OCT_jstring(&CLIENT_ID,user);
+  OCT_jstring(&ID,user);
   printf("CLIENT: ID %s\n", user);
 
   int date = 0;
@@ -109,25 +118,31 @@
   for (i=0;i<100;i++) SEED.val[i]=i+1;
 
   /* initialise random number generator */
-  CREATE_CSPRNG(&RNG,&SEED);
+  MPIN_CREATE_CSPRNG(&RNG,&SEED);
 
-  /* Hash CLIENT_ID */
-  MPIN_HASH_ID(&CLIENT_ID,&HCID);
+  /* Hash ID */
+  MPIN_HASH_ID(&ID,&HCID);
   OCT_output(&HCID);
 
+  /* When set only send hashed IDs to server */
+  octet *pID;
+#ifdef USE_ANONYMOUS
+  pID = &HCID;
+#else
+  pID = &ID;
+#endif
+
   /* Generate Client master secret for MIRACL and Customer */
   rtn = MPIN_RANDOM_GENERATE(&RNG,&MS1);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_RANDOM_GENERATE(&RNG,&MS1) Error %d\n", rtn);
       return 1;
-    }
+  }
   rtn = MPIN_RANDOM_GENERATE(&RNG,&MS2);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_RANDOM_GENERATE(&RNG,&MS2) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("MASTER SECRET MIRACL:= 0x");
   OCT_output(&MS1);
   printf("MASTER SECRET CUSTOMER:= 0x");
@@ -135,17 +150,15 @@
 
   /* Generate server secret shares */
   rtn = MPIN_GET_SERVER_SECRET(&MS1,&SS1);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_SERVER_SECRET(&MS1,&SS1) Error %d\n", rtn);
       return 1;
-    }
+  }
   rtn = MPIN_GET_SERVER_SECRET(&MS2,&SS2);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_SERVER_SECRET(&MS2,&SS2) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("SS1 = 0x");
   OCT_output(&SS1);
   printf("SS2 = 0x");
@@ -153,27 +166,24 @@
 
   /* Combine server secret share */
   rtn = MPIN_RECOMBINE_G2(&SS1, &SS2, &ServerSecret);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_RECOMBINE_G2(&SS1, &SS2, &ServerSecret) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("ServerSecret = 0x");
   OCT_output(&ServerSecret);
 
   /* Generate client secret shares */
   rtn = MPIN_GET_CLIENT_SECRET(&MS1,&HCID,&CS1);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_CLIENT_SECRET(&MS1,&HCID,&CS1) Error %d\n", rtn);
       return 1;
-    }
+  }
   rtn = MPIN_GET_CLIENT_SECRET(&MS2,&HCID,&CS2);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_CLIENT_SECRET(&MS2,&HCID,&CS2) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("CS1 = 0x");
   OCT_output(&CS1);
   printf("CS2 = 0x");
@@ -181,29 +191,26 @@
 
   /* Combine client secret shares : TOKEN is the full client secret */
   rtn = MPIN_RECOMBINE_G1(&CS1, &CS2, &TOKEN);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_RECOMBINE_G1(&CS1, &CS2, &TOKEN) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("Client Secret = 0x");
   OCT_output(&TOKEN);
 
   /* Generate Time Permit shares */
-  date = today();
+  date = MPIN_today();
   printf("Date %d \n", date);
   rtn = MPIN_GET_CLIENT_PERMIT(date,&MS1,&HCID,&TP1);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_CLIENT_PERMIT(date,&MS1,&HCID,&TP1) Error %d\n", rtn);
       return 1;
-    }
+  }
   rtn = MPIN_GET_CLIENT_PERMIT(date,&MS2,&HCID,&TP2);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_GET_CLIENT_PERMIT(date,&MS2,&HCID,&TP2) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("TP1 = 0x");
   OCT_output(&TP1);
   printf("TP2 = 0x");
@@ -211,11 +218,10 @@
 
   /* Combine Time Permit shares */
   rtn = MPIN_RECOMBINE_G1(&TP1, &TP2, &TP);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_RECOMBINE_G1(&TP1, &TP2, &TP) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("Time Permit = 0x");
   OCT_output(&TP);
 
@@ -226,12 +232,11 @@
   printf("Decoded Time Permit= "); OCT_output(&TP);
 
   /* Client extracts PIN1 from secret to create Token */
-  rtn = MPIN_EXTRACT_PIN(&CLIENT_ID, PIN1, &TOKEN);
-  if (rtn != 0)
-    {
-      printf("MPIN_EXTRACT_PIN( &CLIENT_ID, PIN, &TOKEN) Error %d\n", rtn);
+  rtn = MPIN_EXTRACT_PIN(&ID, PIN1, &TOKEN);
+  if (rtn != 0) {
+      printf("MPIN_EXTRACT_PIN( &ID, PIN, &TOKEN) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("Token = 0x");
   OCT_output(&TOKEN);
 
@@ -239,26 +244,24 @@
   MPIN_PRECOMPUTE(&TOKEN,&HCID,&G1,&G2);
 
   /* Client first pass */
-  rtn = MPIN_CLIENT_1(date,&CLIENT_ID,&RNG,&X,PIN2,&TOKEN,&SEC,&U,&UT,&TP);
-  if (rtn != 0)
-    {
+  rtn = MPIN_CLIENT_1(date,&ID,&RNG,&X,PIN2,&TOKEN,&SEC,&U,&UT,&TP);
+  if (rtn != 0) {
       printf("MPIN_CLIENT_1 ERROR %d\n", rtn);
       return 1;
-    }
+  }
 
   /* Client sends Z=r.ID to Server */
   MPIN_GET_G1_MULTIPLE(&RNG,1,&R,&HCID,&Z);
 
   /* Server calculates H(ID) and H(T|H(ID)) (if time permits enabled), and maps them to points on the curve HID and HTID resp. */
-  MPIN_SERVER_1(date,&CLIENT_ID,NULL,&HTID);
+  MPIN_SERVER_1(date,pID,&HID,&HTID);
 
   /* Server generates Random number Y and sends it to Client */
   rtn = MPIN_RANDOM_GENERATE(&RNG,&Y);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("MPIN_RANDOM_GENERATE(&RNG,&Y) Error %d\n", rtn);
       return 1;
-    }
+  }
   printf("Y = 0x");
   OCT_output(&Y);
 
@@ -269,29 +272,35 @@
 
   /* Client second pass */
   rtn = MPIN_CLIENT_2(&X,&Y,&SEC);
-  if (rtn != 0)
+  if (rtn != 0) {
     printf("MPIN_CLIENT_2(&X,&Y,&SEC) Error %d\n", rtn);
+  }
   printf("V = 0x");
   OCT_output(&SEC);
 
   /* Server second pass */
   rtn = MPIN_SERVER_2(date,NULL,&HTID,&Y,&ServerSecret,NULL,&UT,&SEC,&E,&F);
-  if (rtn != 0)
-    {
+  if (rtn != 0) {
       printf("FAILURE Invalid Token Error Code %d\n", rtn);
-    }
+  }
 
-  MPIN_CLIENT_KEY(&G1,&G2,PIN2,&R,&X,&T,&CK);
-  printf("Client Key = "); OCT_output(&CK);
+  MPIN_HASH_ALL(&HCID,NULL,&UT,&SEC,&Y,&Z,&T,&HM);  
+  MPIN_CLIENT_KEY(&G1,&G2,PIN2,&R,&X,&HM,&T,&CK);      
+  printf("Client Key = "); 
+  OCT_output(&CK);
 
-  MPIN_SERVER_KEY(&Z,&ServerSecret,&W,NULL,&UT,&SK);
-  printf("Server Key = "); OCT_output(&SK);
+  /* Server will use the hashed ID if anonymous connection required.
+  MPIN_HASH_ID(&ID,&HSID);
+  MPIN_HASH_ALL(&HSID,NULL,&UT,&SEC,&Y,&Z,&T,&HM);
+  */
+  MPIN_SERVER_KEY(&Z,&ServerSecret,&W,&HM,&HID,NULL,&UT,&SK);
+  printf("Server Key = "); 
+  OCT_output(&SK);
 
-  if (!OCT_comp(&CK,&SK))
-    {
+  if (!OCT_comp(&CK,&SK)) {
       printf("FAILURE Keys are different\n");
       return 1;
-    }
+  }
 
   printf("SUCCESS\n");
   return 0;
diff --git a/c/tests/test_mpinfull_random.c b/c/tests/test_mpinfull_random.c
index 409966a..1638464 100755
--- a/c/tests/test_mpinfull_random.c
+++ b/c/tests/test_mpinfull_random.c
@@ -29,24 +29,25 @@
 // Define PIN range:
 #define MAX_RANGE 10000
 
-void rand_str(char *dest, size_t length) {
-    char charset[] = "0123456789@.*"
-                     "abcdefghijklmnopqrstuvwxyz"
-                     "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-
-    while (length-- > 0) {
-        size_t index = rand() % (sizeof charset);
-        *dest++ = charset[index];
-    }
-    *dest = '\0';
+void rand_str(char *dest, size_t length,csprng *RNG) {
+  BIG r;
+  char charset[] = "0123456789@.*"
+                   "abcdefghijklmnopqrstuvwxyz"
+                   "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+  while (length-- > 0) {
+    BIG_random(r,RNG);
+    size_t index = r[0] % (sizeof charset);
+    *dest++ = charset[index];
+  }
+  *dest = '\0';
 }
 
 int main()
 {
   int i,PIN1,PIN2,rtn,err,iter;
 
-  char client_id[256];
-  octet CLIENT_ID = {0,sizeof(client_id),client_id};
+  char id[256];
+  octet ID = {0,sizeof(id),id};
 
   char x[PGS],y[PGS];
   octet X={sizeof(x), sizeof(x),x};
@@ -58,8 +59,14 @@
   octet MS2={sizeof(ms2),sizeof(ms2),ms2};
 
   /* Hash values of client ID */
-  char hcid[32];
+  char hcid[HASH_BYTES];
   octet HCID={sizeof(hcid),sizeof(hcid), hcid};
+  char hsid[HASH_BYTES];
+  octet HSID={sizeof(hsid),sizeof(hsid), hsid};
+
+  /* Hash values of messages */
+  char hm[HASH_BYTES];
+  octet HM={sizeof(hm),sizeof(hm), hm};
 
   /* Client secret and shares */
   char cs1[2*PFS+1], cs2[2*PFS+1], sec[2*PFS+1];
@@ -83,6 +90,11 @@
   char token[2*PFS+1];
   octet TOKEN={sizeof(token),sizeof(token),token};
 
+  /* Precomputed values stored on device */
+  char g1[12*PFS],g2[12*PFS];
+  octet G1={0,sizeof(g1),g1};
+  octet G2={0,sizeof(g2),g2};
+
   char ut[2*PFS+1],u[2*PFS+1];
   octet UT={sizeof(ut),sizeof(ut),ut};
   octet U={sizeof(u),sizeof(u),u};
@@ -96,17 +108,16 @@
   octet F={sizeof(f),sizeof(f),f};
 
   char r[PGS],z[2*PFS+1],w[PGS],t[2*PFS+1];
-  char g1[12*PFS],g2[12*PFS];
   char ck[PAS],sk[PAS];
   octet R={0,sizeof(r),r};
   octet Z={0,sizeof(z),z};
   octet W={0,sizeof(w),w};
   octet T={0,sizeof(t),t};
-  octet G1={0,sizeof(g1),g1};
-  octet G2={0,sizeof(g2),g2};
   octet SK={0,sizeof(sk),sk};
   octet CK={0,sizeof(ck),ck};
 
+  octet *pID;
+
   int date = 0;
 
   unsigned long ran;
@@ -132,23 +143,21 @@
   OCT_output(&SEED);
 
   /* initialise random number generator */
-  CREATE_CSPRNG(&RNG,&SEED);
+  MPIN_CREATE_CSPRNG(&RNG,&SEED);
 
   for(iter=1; iter<nRandomTests+1; iter++)
     {
       /* Generate Client master secret for MIRACL and Customer */
       rtn = MPIN_RANDOM_GENERATE(&RNG,&MS1);
-      if (rtn != 0)
-        {
+      if (rtn != 0) {
           printf("MPIN_RANDOM_GENERATE(&RNG,&MS1) Error %d\n", rtn);
           return 1;
-        }
+      }
       rtn = MPIN_RANDOM_GENERATE(&RNG,&MS2);
-      if (rtn != 0)
-        {
+      if (rtn != 0) {
           printf("MPIN_RANDOM_GENERATE(&RNG,&MS2) Error %d\n", rtn);
           return 1;
-        }
+      }
       printf("MASTER SECRET MIRACL:= 0x");
       OCT_output(&MS1);
       printf("MASTER SECRET CUSTOMER:= 0x");
@@ -156,17 +165,15 @@
 
       /* Generate server secret shares */
       rtn = MPIN_GET_SERVER_SECRET(&MS1,&SS1);
-      if (rtn != 0)
-        {
+      if (rtn != 0) {
           printf("MPIN_GET_SERVER_SECRET(&MS1,&SS1) Error %d\n", rtn);
           return 1;
-        }
+      }
       rtn = MPIN_GET_SERVER_SECRET(&MS2,&SS2);
-      if (rtn != 0)
-        {
+      if (rtn != 0) {
           printf("MPIN_GET_SERVER_SECRET(&MS2,&SS2) Error %d\n", rtn);
           return 1;
-        }
+      }
       printf("SS1 = 0x");
       OCT_output(&SS1);
       printf("SS2 = 0x");
@@ -174,41 +181,45 @@
 
       /* Combine server secret share */
       rtn = MPIN_RECOMBINE_G2(&SS1, &SS2, &ServerSecret);
-      if (rtn != 0)
-        {
+      if (rtn != 0) {
           printf("MPIN_RECOMBINE_G2(&SS1, &SS2, &ServerSecret) Error %d\n", rtn);
           return 1;
-        }
+      }
       printf("ServerSecret = 0x");
       OCT_output(&ServerSecret);
 
       /* Assign the End-User an ID */
-      rand_str(client_id,256);
-      OCT_jstring(&CLIENT_ID,client_id);
-      printf("CLIENT: ID %s\n", client_id);
+      rand_str(id,256,&RNG);
+      OCT_jstring(&ID,id);
+      printf("CLIENT: ID %s\n", id);
 
-      srand ( time (NULL) );
+      srand(time(NULL));
       PIN1 = rand()%MAX_RANGE; // Get random between 0 and MAX_RANGE
       PIN2 = PIN1;
       printf("PIN1 %d PIN2 %d\n", PIN1, PIN2);
 
-      /* Hash CLIENT_ID */
-      MPIN_HASH_ID(&CLIENT_ID,&HCID);
+      /* Hash ID */
+      MPIN_HASH_ID(&ID,&HCID);
       OCT_output(&HCID);
 
+      /* When set only send hashed IDs to server */
+#ifdef USE_ANONYMOUS
+      pID = &HCID;
+#else
+      pID = &ID;
+#endif
+
       /* Generate client secret shares */
       rtn = MPIN_GET_CLIENT_SECRET(&MS1,&HCID,&CS1);
-      if (rtn != 0)
-        {
+      if (rtn != 0) {
           printf("MPIN_GET_CLIENT_SECRET(&MS1,&HCID,&CS1) Error %d\n", rtn);
           return 1;
-        }
+      }
       rtn = MPIN_GET_CLIENT_SECRET(&MS2,&HCID,&CS2);
-      if (rtn != 0)
-        {
+      if (rtn != 0) {
           printf("MPIN_GET_CLIENT_SECRET(&MS2,&HCID,&CS2) Error %d\n", rtn);
           return 1;
-        }
+      }
       printf("CS1 = 0x");
       OCT_output(&CS1);
       printf("CS2 = 0x");
@@ -216,29 +227,26 @@
 
       /* Combine client secret shares : TOKEN is the full client secret */
       rtn = MPIN_RECOMBINE_G1(&CS1, &CS2, &TOKEN);
-      if (rtn != 0)
-        {
+      if (rtn != 0) {
           printf("MPIN_RECOMBINE_G1(&CS1, &CS2, &TOKEN) Error %d\n", rtn);
           return 1;
-        }
+      }
       printf("Client Secret = 0x");
       OCT_output(&TOKEN);
 
       /* Generate Time Permit shares */
-      date = today();
+      date = MPIN_today();
       printf("Date %d \n", date);
       rtn = MPIN_GET_CLIENT_PERMIT(date,&MS1,&HCID,&TP1);
-      if (rtn != 0)
-        {
+      if (rtn != 0) {
           printf("MPIN_GET_CLIENT_PERMIT(date,&MS1,&HCID,&TP1) Error %d\n", rtn);
           return 1;
-        }
+      }
       rtn = MPIN_GET_CLIENT_PERMIT(date,&MS2,&HCID,&TP2);
-      if (rtn != 0)
-        {
+      if (rtn != 0) {
           printf("MPIN_GET_CLIENT_PERMIT(date,&MS2,&HCID,&TP2) Error %d\n", rtn);
           return 1;
-        }
+      }
       printf("TP1 = 0x");
       OCT_output(&TP1);
       printf("TP2 = 0x");
@@ -246,11 +254,10 @@
 
       /* Combine Time Permit shares */
       rtn = MPIN_RECOMBINE_G1(&TP1, &TP2, &TP);
-      if (rtn != 0)
-        {
+      if (rtn != 0) {
           printf("MPIN_RECOMBINE_G1(&TP1, &TP2, &TP) Error %d\n", rtn);
           return 1;
-        }
+      }
       printf("Time Permit = 0x");
       OCT_output(&TP);
 
@@ -261,12 +268,11 @@
       printf("Decoded Time Permit= "); OCT_output(&TP);
 
       /* Client extracts PIN1 from secret to create Token */
-      rtn = MPIN_EXTRACT_PIN(&CLIENT_ID, PIN1, &TOKEN);
-      if (rtn != 0)
-        {
-          printf("MPIN_EXTRACT_PIN( &CLIENT_ID, PIN, &TOKEN) Error %d\n", rtn);
+      rtn = MPIN_EXTRACT_PIN(&ID, PIN1, &TOKEN);
+      if (rtn != 0) {
+          printf("MPIN_EXTRACT_PIN( &ID, PIN, &TOKEN) Error %d\n", rtn);
           return 1;
-        }
+      }
       printf("Token = 0x");
       OCT_output(&TOKEN);
 
@@ -274,26 +280,24 @@
       MPIN_PRECOMPUTE(&TOKEN,&HCID,&G1,&G2);
 
       /* Client first pass */
-      rtn = MPIN_CLIENT_1(date,&CLIENT_ID,&RNG,&X,PIN2,&TOKEN,&SEC,&U,&UT,&TP);
-      if (rtn != 0)
-        {
+      rtn = MPIN_CLIENT_1(date,&ID,&RNG,&X,PIN2,&TOKEN,&SEC,&U,&UT,&TP);
+      if (rtn != 0) {
           printf("MPIN_CLIENT_1 ERROR %d\n", rtn);
           return 1;
-        }
+      }
 
       /* Client sends Z=r.ID to Server */
       MPIN_GET_G1_MULTIPLE(&RNG,1,&R,&HCID,&Z);
 
       /* Server calculates H(ID) and H(T|H(ID)) (if time permits enabled), and maps them to points on the curve HID and HTID resp. */
-      MPIN_SERVER_1(date,&CLIENT_ID,&HID,&HTID);
+      MPIN_SERVER_1(date,pID,&HID,&HTID);
 
       /* Server generates Random number Y and sends it to Client */
       rtn = MPIN_RANDOM_GENERATE(&RNG,&Y);
-      if (rtn != 0)
-        {
+      if (rtn != 0) {
           printf("MPIN_RANDOM_GENERATE(&RNG,&Y) Error %d\n", rtn);
           return 1;
-        }
+      }
       printf("Y = 0x");
       OCT_output(&Y);
 
@@ -304,41 +308,42 @@
 
       /* Client second pass */
       rtn = MPIN_CLIENT_2(&X,&Y,&SEC);
-      if (rtn != 0)
+      if (rtn != 0) {
         printf("MPIN_CLIENT_2(&X,&Y,&SEC) Error %d\n", rtn);
+      }
       printf("V = 0x");
       OCT_output(&SEC);
 
       /* Server second pass */
       rtn = MPIN_SERVER_2(date,&HID,&HTID,&Y,&ServerSecret,&U,&UT,&SEC,&E,&F);
-      if (rtn != 0)
-        {
-          err=MPIN_KANGAROO(&E,&F);
-          if (err==0)
-            {
-              printf("FAILURE Invalid Token Error Code %d\n", rtn);
-      }
-          else
-            {
-              printf("FAILURE PIN Error %d, Error> Code %d\n",err, rtn);
-      }
+      if (rtn != 0) {
+        err=MPIN_KANGAROO(&E,&F);
+        if (err==0) {
+          printf("FAILURE Invalid Token Error Code %d\n", rtn);
+        } else {
+          printf("FAILURE PIN Error %d, Error Code %d\n",err, rtn);
         }
+      }
 
-      MPIN_CLIENT_KEY(&G1,&G2,PIN2,&R,&X,&T,&CK);
-      printf("Client Key = "); OCT_output(&CK);
+      MPIN_HASH_ALL(&HCID,&U,&UT,&SEC,&Y,&Z,&T,&HM);  
+      MPIN_CLIENT_KEY(&G1,&G2,PIN2,&R,&X,&HM,&T,&CK);      
+      printf("Client Key = "); 
+      OCT_output(&CK);
 
-      MPIN_SERVER_KEY(&Z,&ServerSecret,&W,&U,&UT,&SK);
-      printf("Server Key = "); OCT_output(&SK);
+      /* Server will use the hashed ID if anonymous connection required.
+      MPIN_HASH_ID(&ID,&HSID);
+      MPIN_HASH_ALL(&HSID,NULL,&UT,&SEC,&Y,&Z,&T,&HM);
+      */
+      MPIN_SERVER_KEY(&Z,&ServerSecret,&W,&HM,&HID,NULL,&UT,&SK);
+      printf("Server Key = "); 
+      OCT_output(&SK);
 
-      if (!OCT_comp(&CK,&SK))
-        {
+      if (!OCT_comp(&CK,&SK)) {
           printf("Iteration %d FAILURE keys are different\n", iter);
           return 1;
-        }
-      else
-        {
+      } else {
           printf("Iteration %d SUCCESS\n\n", iter);
-        }
+      }
     }
   return 0;
 }
diff --git a/c/tests/test_rsa.c b/c/tests/test_rsa.c
index 7e17ecb..d2aa8a3 100755
--- a/c/tests/test_rsa.c
+++ b/c/tests/test_rsa.c
@@ -46,14 +46,14 @@
   RAW.val[3]=ran>>24;
   for (i=4;i<100;i++) RAW.val[i]=i;
 
-  CREATE_CSPRNG(&RNG,&RAW);   /* initialise strong RNG */
+  RSA_CREATE_CSPRNG(&RNG,&RAW);   /* initialise strong RNG */
 
   printf("Generating public/private key pair\n");
   RSA_KEY_PAIR(&RNG,65537,&priv,&pub);
 
   printf("Encrypting test string\n");
   OCT_jstring(&M,(char *)"Hello World\n");
-  OAEP_ENCODE(&M,&RNG,NULL,&E); /* OAEP encode message m to e  */
+  RSA_OAEP_ENCODE(&M,&RNG,NULL,&E); /* OAEP encode message m to e  */
 
   RSA_ENCRYPT(&pub,&E,&C);     /* encrypt encoded message */
   printf("Ciphertext= "); OCT_output(&C);
@@ -61,7 +61,7 @@
   printf("Decrypting test string\n");
   RSA_DECRYPT(&priv,&C,&ML);   /* ... and then decrypt it */
 
-  OAEP_DECODE(NULL,&ML);    /* decode it */
+  RSA_OAEP_DECODE(NULL,&ML);    /* decode it */
   OCT_output_string(&ML);
 
   if (!OCT_comp(&M,&ML))
@@ -73,7 +73,7 @@
   OCT_clear(&M); OCT_clear(&ML);   /* clean up afterwards */
   OCT_clear(&C); OCT_clear(&RAW); OCT_clear(&E);
 
-  KILL_CSPRNG(&RNG);
+  RSA_KILL_CSPRNG(&RNG);
 
   RSA_PRIVATE_KEY_KILL(&priv);
 
diff --git a/c/tests/test_wcc.c b/c/tests/test_wcc.c
new file mode 100755
index 0000000..d5204fa
--- /dev/null
+++ b/c/tests/test_wcc.c
@@ -0,0 +1,208 @@
+/*
+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 WCC with and without time permits */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "wcc.h"
+#include "utils.h"
+
+int main()
+{
+  int i,rtn;
+
+  /* Master secret */
+  char ms[PGS];
+  octet MS={sizeof(ms),sizeof(ms),ms};
+
+  // sender key
+  char akeyG1[2*PFS+1];
+  octet AKeyG1={0,sizeof(akeyG1), akeyG1};
+
+  // receiver key
+  char bkeyG2[4*PFS];
+  octet BKeyG2={0,sizeof(bkeyG2), bkeyG2};
+
+  char hv[HASH_BYTES],alice_id[256],bob_id[256];
+  octet HV={0,sizeof(hv),hv};
+
+  octet IdA={0,sizeof(alice_id),alice_id};
+  octet IdB={0,sizeof(bob_id),bob_id};
+
+  char x[PGS];
+  octet X={sizeof(x),sizeof(x),x};
+  char y[PGS];
+  octet Y={sizeof(y),sizeof(y),y};
+  char w[PGS];
+  octet W={sizeof(w),sizeof(w),w};
+  char pia[PGS];
+  octet PIA={sizeof(pia),sizeof(pia),pia};
+  char pib[PGS];
+  octet PIB={sizeof(pib),sizeof(pib),pib};
+
+  char pgg1[2*PFS+1];
+  octet PgG1={0,sizeof(pgg1), pgg1};
+
+  char pag1[2*PFS+1];
+  octet PaG1={0,sizeof(pag1), pag1};
+
+  char pbg2[4*PFS];
+  octet PbG2={0,sizeof(pbg2), pbg2};
+
+  char seed[32] = {0};
+  octet SEED = {0,sizeof(seed),seed};
+  csprng RNG;
+
+  char message1[256];
+  octet MESSAGE1 = {0, sizeof(message1), message1};
+  OCT_jstring(&MESSAGE1,"Hello Bob");
+
+  char t1[16];  // Tag
+  char t2[16];  // Tag
+  char k1[16];  // AES Key
+  char k2[16];  // AES Key
+  char iv[12]; // IV - Initialisation vector
+  char c[100];  // Ciphertext
+  char p[100];  // Recovered Plaintext
+  octet T1={sizeof(t1),sizeof(t1),t1};
+  octet T2={sizeof(t2),sizeof(t2),t2};
+  octet K1={0,sizeof(k1),k1};
+  octet K2={0,sizeof(k2),k2};
+  octet IV={0,sizeof(iv),iv};
+  octet C={0,sizeof(c),c};
+  octet P={0,sizeof(p),p};
+
+  int date;
+
+  int hashDoneOn = 1;
+  int hashDoneOff = 0;
+
+  date = 0;
+
+  /* unrandom seed value! */
+  SEED.len=32;
+  for (i=0;i<32;i++) SEED.val[i]=i+1;
+
+  /* initialise random number generator */
+  WCC_CREATE_CSPRNG(&RNG,&SEED);
+
+  /* TA: Generate master secret  */
+  rtn = WCC_RANDOM_GENERATE(&RNG,&MS);
+  if (rtn != 0) {
+      printf("TA WCC_RANDOM_GENERATE(&RNG,&MS) Error %d\n", rtn);
+      return 1;
+  }
+
+  // Alice's ID
+  OCT_jstring(&IdA,"alice@miracl.com");
+
+  // TA: Generate Alices's sender key
+  WCC_HASH_ID(&IdA,&HV);
+  rtn = WCC_GET_G1_MULTIPLE(hashDoneOn,&MS,&HV,&AKeyG1);
+  if (rtn != 0) {
+      printf("TA WCC_GET_G1_MULTIPLE() Error %d\n", rtn);
+      return 1;
+  }
+
+  // Bob's ID
+  OCT_jstring(&IdB,"bob@miracl.com");
+
+  // TA: Generate Bob's receiver key
+  WCC_HASH_ID(&IdB,&HV);
+  rtn = WCC_GET_G2_MULTIPLE(hashDoneOn,&MS,&HV,&BKeyG2);
+  if (rtn != 0) {
+      printf("TA WCC_GET_G2_MULTIPLE() Error %d\n", rtn);
+      return 1;
+  }
+
+  rtn = WCC_RANDOM_GENERATE(&RNG,&X);
+  if (rtn != 0) {
+      printf("Alice WCC_RANDOM_GENERATE(&RNG,&X) Error %d\n", rtn);
+      return 1;
+  }
+
+  rtn = WCC_GET_G1_MULTIPLE(hashDoneOff,&X,&IdA,&PaG1);
+  if (rtn != 0) {
+      printf("Alice WCC_GET_G1_MULTIPLE() Error %d\n", rtn);
+      return 1;
+  }
+
+  rtn = WCC_RANDOM_GENERATE(&RNG,&W);
+  if (rtn != 0) {
+      printf("Bob WCC_RANDOM_GENERATE(&RNG,&W) Error %d\n", rtn);
+      return 1;
+  }
+  rtn = WCC_GET_G1_MULTIPLE(hashDoneOff,&W,&IdA,&PgG1);
+  if (rtn != 0) {
+      printf("Bob WCC_GET_G1_MULTIPLE() Error %d\n", rtn);
+      return 1;
+  }
+
+  rtn = WCC_RANDOM_GENERATE(&RNG,&Y);
+  if (rtn != 0) {
+      printf("Bob WCC_RANDOM_GENERATE(&RNG,&Y) Error %d\n", rtn);
+      return 1;
+  }
+
+  rtn = WCC_GET_G2_MULTIPLE(hashDoneOff,&Y,&IdB,&PbG2);
+  if (rtn != 0) {
+      printf("Bob WCC_GET_G1_MULTIPLE() Error %d\n", rtn);
+      return 1;
+  }
+
+  // pia = Hq(PaG1,PbG2,PgG1,IdB)
+  WCC_Hq(&PaG1,&PbG2,&PgG1,&IdB,&PIA);
+
+  // pib = Hq(PbG2,PaG1,PgG1,IdA)
+  WCC_Hq(&PbG2,&PaG1,&PgG1,&IdA,&PIB);
+
+  // Bob calculates AES Key
+  WCC_RECEIVER_KEY(date, &Y, &W,  &PIA, &PIB,  &PaG1, &PgG1, &BKeyG2, NULL, &IdA, &K2);
+  if (rtn != 0) {
+      printf("Bob WCC_RECEIVER_KEY() Error %d\n", rtn);
+      return 1;
+  }
+
+  // pia = Hq(PaG1,PbG2,PgG1,IdB)
+  WCC_Hq(&PaG1,&PbG2,&PgG1,&IdB,&PIA);
+
+  // pib = Hq(PbG2,PaG1,PgG1,IdA)
+  WCC_Hq(&PbG2,&PaG1,&PgG1,&IdA,&PIB);
+
+  // Alice calculates AES Key
+  rtn = WCC_SENDER_KEY(date, &X, &PIA, &PIB, &PbG2, &PgG1, &AKeyG1, NULL, &IdB, &K1);
+  if (rtn != 0) {
+      printf("Alice WCC_SENDER_KEY() Error %d\n", rtn);
+      return 1;
+  }
+
+  if (!OCT_comp(&K1,&K2))
+    {
+      printf("FAILURE No Time Permit Test. OCT_comp(&K1,&K2)\n");
+      return 1;
+    }
+
+  WCC_KILL_CSPRNG(&RNG);
+
+  printf("SUCCESS\n");
+  return 0;
+}
diff --git a/c/tests/test_wcc_gcm.c b/c/tests/test_wcc_gcm.c
new file mode 100755
index 0000000..5cef3a9
--- /dev/null
+++ b/c/tests/test_wcc_gcm.c
@@ -0,0 +1,105 @@
+/*
+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.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include "amcl.h"
+#include "wcc.h"
+#include "utils.h"
+
+
+int main()
+{
+  char* KT="feffe9928665731c6d6a8f9467308308";
+  char* MT="d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39";
+  char* HT="feedfacedeadbeeffeedfacedeadbeefabaddad2";
+  char* NT="9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b";
+  // Tag should be 619cc5aefffe0bfa462af43c1699d050
+
+  int lenM=strlen(MT)/2;
+  int lenH=strlen(HT)/2;
+  int lenK=strlen(KT)/2;
+  int lenIV=strlen(NT)/2;
+
+  char t1[16];  // Tag
+  char t2[16];  // Tag
+  char k[16];   // AES Key
+  char h[64];   // Header - to be included in Authentication, but not encrypted
+  char iv[100]; // IV - Initialisation vector
+  char m[100];  // Plaintext to be encrypted/authenticated
+  char c[100];  // Ciphertext
+  char p[100];  // Recovered Plaintext
+  octet T1={sizeof(t1),sizeof(t1),t1};
+  octet T2={sizeof(t2),sizeof(t2),t2};
+  octet K={0,sizeof(k),k};
+  octet H={0,sizeof(h),h};
+  octet IV={0,sizeof(iv),iv};
+  octet M={0,sizeof(m),m};
+  octet C={0,sizeof(c),c};
+  octet P={0,sizeof(p),p};
+  M.len=lenM;
+  K.len=lenK;
+  H.len=lenH;
+  IV.len=lenIV;
+
+  hex2bytes(MT, m);
+  hex2bytes(HT, h);
+  hex2bytes(NT, iv);
+  hex2bytes(KT, k);
+
+  printf("Plaintext: ");
+  OCT_output(&M);
+  printf("\n");
+
+  WCC_AES_GCM_ENCRYPT(&K, &IV, &H, &M, &C, &T1);
+
+  printf("Ciphertext: ");
+  OCT_output(&C);
+  printf("\n");
+
+  printf("Encryption Tag: ");
+  OCT_output(&T1);
+  printf("\n");
+
+  WCC_AES_GCM_DECRYPT(&K, &IV, &H, &C, &P, &T2);
+
+  printf("Plaintext: ");
+  OCT_output(&P);
+  printf("\n");
+
+  printf("Decryption Tag: ");
+  OCT_output(&T2);
+  printf("\n");
+
+  if (!OCT_comp(&M,&P))
+    {
+      printf("FAILURE Decryption\n");
+      return 1;
+    }
+
+  if (!OCT_comp(&T1,&T2))
+    {
+      printf("FAILURE TAG mismatch\n");
+      return 1;
+    }
+
+  printf("SUCCESS\n");
+  return 0;
+}
+
diff --git a/c/tests/test_wcc_random.c b/c/tests/test_wcc_random.c
new file mode 100755
index 0000000..5749adf
--- /dev/null
+++ b/c/tests/test_wcc_random.c
@@ -0,0 +1,469 @@
+/*
+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 WCC with two TAs and time permits for random values */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "config.h"
+#include "wcc.h"
+
+#define DEBUG
+
+void rand_str(char *dest, size_t length,csprng *RNG) {
+  BIG r;
+  char charset[] = "0123456789@.*"
+                   "abcdefghijklmnopqrstuvwxyz"
+                   "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+  while (length-- > 0) {
+    BIG_random(r,RNG);
+    size_t index = r[0] % (sizeof charset);
+    *dest++ = charset[index];
+  }
+  *dest = '\0';
+}
+
+int main()
+{
+  int i,rtn,iter;
+
+  /* Master secret shares */
+  char ms1[PGS], ms2[PGS];
+  octet MS1={sizeof(ms1),sizeof(ms1),ms1};
+  octet MS2={sizeof(ms2),sizeof(ms2),ms2};
+
+  // Sender keys
+  char a1keyG1[2*PFS+1], a2keyG1[2*PFS+1];
+  octet A1KeyG1={0,sizeof(a1keyG1), a1keyG1};
+  octet A2KeyG1={0,sizeof(a2keyG1), a2keyG1};
+  char akeyG1[2*PFS+1];
+  octet AKeyG1={0,sizeof(akeyG1), akeyG1};
+
+  // Sender time permits
+  char a1TPG1[2*PFS+1], a2TPG1[2*PFS+1];
+  octet A1TPG1={sizeof(a1TPG1),sizeof(a1TPG1), a1TPG1};
+  octet A2TPG1={sizeof(a2TPG1),sizeof(a2TPG1), a2TPG1};
+  char aTPG1[2*PFS+1];
+  octet ATPG1={0,sizeof(aTPG1), aTPG1};
+
+  // Receiver keys
+  char b1keyG2[4*PFS], b2keyG2[4*PFS];
+  octet B1KeyG2={0,sizeof(b1keyG2), b1keyG2};
+  octet B2KeyG2={0,sizeof(b2keyG2), b2keyG2};
+  char bkeyG2[4*PFS];
+  octet BKeyG2={0,sizeof(bkeyG2), bkeyG2};
+
+  // Receiver time permits
+  char b1TPG2[4*PFS], b2TPG2[4*PFS];
+  octet B1TPG2={sizeof(b1TPG2),sizeof(b1TPG2), b1TPG2};
+  octet B2TPG2={sizeof(b2TPG2),sizeof(b2TPG2), b2TPG2};
+  char bTPG2[4*PFS];
+  octet BTPG2={0,sizeof(bTPG2), bTPG2};
+
+  char ahv[HASH_BYTES],alice_id[256],bhv[HASH_BYTES],bob_id[256];
+  octet AHV={0,sizeof(ahv),ahv};
+  octet BHV={0,sizeof(bhv),bhv};
+
+  octet IdA={0,sizeof(alice_id),alice_id};
+  octet IdB={0,sizeof(bob_id),bob_id};
+
+  char x[PGS];
+  octet X={sizeof(x),sizeof(x),x};
+  char y[PGS];
+  octet Y={sizeof(y),sizeof(y),y};
+  char w[PGS];
+  octet W={sizeof(w),sizeof(w),w};
+  char pia[PGS];
+  octet PIA={sizeof(pia),sizeof(pia),pia};
+  char pib[PGS];
+  octet PIB={sizeof(pib),sizeof(pib),pib};
+
+  char pgg1[2*PFS+1];
+  octet PgG1={0,sizeof(pgg1), pgg1};
+
+  char pag1[2*PFS+1];
+  octet PaG1={0,sizeof(pag1), pag1};
+
+  char pbg2[4*PFS];
+  octet PbG2={0,sizeof(pbg2), pbg2};
+
+  char message1[256];
+  char message2[256];
+  octet MESSAGE1 = {0, sizeof(message1), message1};
+  octet MESSAGE2 = {0, sizeof(message2), message2};
+
+  char t1[16];  // Tag
+  char t2[16];  // Tag
+  char k1[16];  // AES Key
+  char k2[16];  // AES Key
+  char iv[12]; // IV - Initialisation vector
+  char c[100];  // Ciphertext
+  char p[100];  // Recovered Plaintext
+  octet T1={sizeof(t1),sizeof(t1),t1};
+  octet T2={sizeof(t2),sizeof(t2),t2};
+  octet K1={0,sizeof(k1),k1};
+  octet K2={0,sizeof(k2),k2};
+  octet IV={0,sizeof(iv),iv};
+  octet C={0,sizeof(c),c};
+  octet P={0,sizeof(p),p};
+
+  int date;
+  date = WCC_today();
+  printf("Date %d \n", date);
+
+  int hashDoneOn = 1;
+  int hashDoneOff = 0;
+
+  OCT_jstring(&MESSAGE1,"Hello Bob");
+  OCT_jstring(&MESSAGE2,"Hello Alice");
+
+  unsigned long ran;
+  int byte_count = 32;
+  FILE *fp;
+  char seed[32] = {0};
+  octet SEED = {sizeof(seed),sizeof(seed),seed};
+  csprng RNG;
+
+#ifdef __linux__
+  size_t readSize;
+  fp = fopen("/dev/urandom", "r");
+  readSize = fread(&seed, 1, byte_count, fp);
+  fclose(fp);
+#else
+  /* non random seed value! */
+  time((time_t *)&ran);
+  SEED.val[0]=ran;
+  SEED.val[1]=ran>>8;
+  SEED.val[2]=ran>>16;
+  SEED.val[3]=ran>>24;
+  for (i=4;i<byte_count;i++) SEED.val[i]=i+1;
+#endif
+  printf("SEED 0x");
+  OCT_output(&SEED);
+
+  /* initialise random number generator */
+  WCC_CREATE_CSPRNG(&RNG,&SEED);
+
+  for(iter=1; iter<nRandomTests+1; iter++) {
+
+    /* Generate Client master secret for MIRACL and Customer */
+    rtn = WCC_RANDOM_GENERATE(&RNG,&MS1);
+    if (rtn != 0) {
+        printf("TA WCC_RANDOM_GENERATE(&RNG,&MS1) Error %d\n", rtn);
+        return 1;
+    }
+    rtn = WCC_RANDOM_GENERATE(&RNG,&MS2);
+    if (rtn != 0) {
+        printf("TA WCC_RANDOM_GENERATE(&RNG,&MS2) Error %d\n", rtn);
+        return 1;
+    }
+    printf("TA MASTER SECRET MIRACL: ");
+    OCT_output(&MS1);
+    printf("TA MASTER SECRET CUSTOMER: ");
+    OCT_output(&MS2);
+  
+    // Alice's ID
+    rand_str(alice_id,256,&RNG);
+    OCT_jstring(&IdA,alice_id);
+    printf("ALICE ID: %s\n", alice_id);
+
+     // TA: Generate Alice's sender key
+    WCC_HASH_ID(&IdA,&AHV);
+    rtn = WCC_GET_G1_MULTIPLE(hashDoneOn,&MS1,&AHV,&A1KeyG1);
+    if (rtn != 0) {
+        printf("TA WCC_GET_G1_MULTIPLE(hashDoneOn,&MS1,&AHV,&A1KeyG1) Error %d\n", rtn);
+        return 1;
+    }
+    rtn = WCC_GET_G1_MULTIPLE(hashDoneOn,&MS2,&AHV,&A2KeyG1);
+    if (rtn != 0) {
+        printf("TA WCC_GET_G1_MULTIPLE(hashDoneOn,&MS2,&AHV,&A2KeyG1) Error %d\n", rtn);
+        return 1;
+    }
+    printf("TA A1KeyG1: ");
+    OCT_output(&A1KeyG1);
+    printf("TA A2KeyG1: ");
+    OCT_output(&A2KeyG1);
+  
+    rtn = WCC_RECOMBINE_G1(&A1KeyG1, &A2KeyG1, &AKeyG1);
+    if (rtn != 0) {
+        printf("TA WCC_RECOMBINE_G1(&A1KeyG1, &A2KeyG1, &AKeyG1) Error %d\n", rtn);
+        return 1;
+    }
+    printf("TA Alice's sender key: ");
+    OCT_output(&AKeyG1);
+  
+    // TA: Generate Alice's G1 time permit
+    rtn = WCC_GET_G1_PERMIT(date,&MS1,&AHV,&A1TPG1);
+    if (rtn != 0) {
+        printf("TA WCC_GET_G1_PERMIT(date,&MS1,&AHV,&A1TPG1) Error %d\n", rtn);
+        return 1;
+    }
+    rtn = WCC_GET_G1_PERMIT(date,&MS2,&AHV,&A2TPG1);
+    if (rtn != 0) {
+        printf("TA WCC_GET_G1_PERMIT(date,&MS2,&AHV,&A2TPG1) Error %d\n", rtn);
+        return 1;
+    }
+    printf("TA A1TPG1: ");
+    OCT_output(&A1TPG1);
+    printf("TA A2TPG1: ");
+    OCT_output(&A2TPG1);
+  
+    rtn = WCC_RECOMBINE_G1(&A1TPG1, &A2TPG1, &ATPG1);
+    if (rtn != 0) {
+        printf("Alice WCC_RECOMBINE_G1(&A1TPG1, &A2TPG1, &ATPG1) Error %d\n", rtn);
+        return 1;
+    }
+    printf("TA Alice's sender time permit: ");
+    OCT_output(&ATPG1);
+  
+    // Bob's ID
+    rand_str(bob_id,256,&RNG);
+    OCT_jstring(&IdB,bob_id);
+    printf("BOB ID: %s\n", bob_id);
+  
+    // TA: Generate Bob's receiver key
+    WCC_HASH_ID(&IdB,&BHV);
+    rtn = WCC_GET_G2_MULTIPLE(hashDoneOn,&MS1,&BHV,&B1KeyG2);
+    if (rtn != 0) {
+        printf("TA WCC_GET_G2_MULTIPLE(hashDoneOn,&MS1,&BHV,&B1KeyG2) Error %d\n", rtn);
+        return 1;
+    }
+    rtn = WCC_GET_G2_MULTIPLE(hashDoneOn,&MS2,&BHV,&B2KeyG2);
+    if (rtn != 0) {
+        printf("Bob WCC_GET_G2_MULTIPLE(hashDoneOn,&MS2,&BHV,&B2KeyG2) Error %d\n", rtn);
+        return 1;
+    }
+    printf("TA B1KeyG2: ");
+    OCT_output(&B1KeyG2);
+    printf("TA B2KeyG2: ");
+    OCT_output(&B2KeyG2);
+  
+    rtn = WCC_RECOMBINE_G2(&B1KeyG2, &B2KeyG2, &BKeyG2);
+    if (rtn != 0) {
+        printf("Bob WCC_RECOMBINE_G2(&B1KeyG1, &B2KeyG1, &BKeyG2) Error %d\n", rtn);
+        return 1;
+    }
+    printf("TA Bob's receiver key: ");
+    OCT_output(&BKeyG2);
+  
+    // TA: Generate Bob's receiver time permit
+    rtn = WCC_GET_G2_PERMIT(date,&MS1,&BHV,&B1TPG2);
+    if (rtn != 0) {
+        printf("TA WCC_GET_G2_PERMIT(date,&MS1,&BHV,&B1TPG2) Error %d\n", rtn);
+        return 1;
+    }
+    rtn = WCC_GET_G2_PERMIT(date,&MS2,&BHV,&B2TPG2);
+    if (rtn != 0) {
+        printf("TA WCC_GET_G2_PERMIT(date,&MS2,&BHV,&B2TPG2) Error %d\n", rtn);
+        return 1;
+    }
+    printf("TA B1TPG2: ");
+    OCT_output(&B1TPG2);
+    printf("TA B2TPG2: ");
+    OCT_output(&B2TPG2);
+  
+    rtn = WCC_RECOMBINE_G2(&B1TPG2, &B2TPG2, &BTPG2);
+    if (rtn != 0) {
+        printf("Bob WCC_RECOMBINE_G2(&B1TPG2, &B2TPG2, &BTPG2) Error %d\n", rtn);
+        return 1;
+    }
+    printf("TA Bob's receiver time permit: ");
+    OCT_output(&BTPG2);
+    printf("\n");
+  
+    printf("Alice\n");
+  
+    rtn = WCC_RANDOM_GENERATE(&RNG,&X);
+    if (rtn != 0) {
+        printf("Alice WCC_RANDOM_GENERATE(&RNG,&X) Error %d\n", rtn);
+        return 1;
+    }
+  #ifdef DEBUG
+    printf("Alice X: ");
+    OCT_output(&X);
+    printf("\n");
+  #endif
+  
+    rtn = WCC_GET_G1_TPMULT(date,&X,&IdA,&PaG1);
+    if (rtn != 0) {
+        printf("Alice WCC_GET_G1_TPMULT(date,&X,&IdA,&PaG1) Error %d\n", rtn);
+        return 1;
+    }
+  
+    printf("Alice sends IdA and PaG1 to Bob\n\n");
+    printf("Alice IdA: "); 
+    OCT_output_string(&IdA); 
+    printf("\n");
+    printf("Alice PaG1: ");
+    OCT_output(&PaG1);
+    printf("\n");
+  
+    printf("Bob\n");
+  
+    rtn = WCC_RANDOM_GENERATE(&RNG,&W);
+    if (rtn != 0) {
+        printf("Bob WCC_RANDOM_GENERATE(&RNG,&W) Error %d\n", rtn);
+        return 1;
+    }
+  #ifdef DEBUG
+    printf("Bob W: ");
+    OCT_output(&W);
+    printf("\n");
+  #endif
+    rtn = WCC_GET_G1_TPMULT(date,&W,&IdA,&PgG1);
+    if (rtn != 0) {
+        printf("Bob WCC_GET_G1_TPMULT(date,&W,&IdA,&PgG1) Error %d\n", rtn);
+        return 1;
+    }
+  #ifdef DEBUG
+    printf("PgG1: ");
+    OCT_output(&PgG1);
+    printf("\n");
+  #endif
+  
+    rtn = WCC_RANDOM_GENERATE(&RNG,&Y);
+    if (rtn != 0) {
+        printf("Bob WCC_RANDOM_GENERATE(&RNG,&Y) Error %d\n", rtn);
+        return 1;
+    }
+  #ifdef DEBUG
+    printf("Bob Y: ");
+    OCT_output(&Y);
+    printf("\n");
+  #endif
+    rtn = WCC_GET_G2_TPMULT(date,&Y,&IdB,&PbG2);
+    if (rtn != 0) {
+        printf("Bob WCC_GET_G1_TPMULT(date,&Y,&IdB,&PbG2) Error %d\n", rtn);
+        return 1;
+    }
+  #ifdef DEBUG
+    printf("Bob PbG2: ");
+    OCT_output(&PbG2);
+    printf("\n");
+  #endif
+  
+    // pia = Hq(PaG1,PbG2,PgG1,IdB)
+    WCC_Hq(&PaG1,&PbG2,&PgG1,&IdB,&PIA);
+
+    // pib = Hq(PbG2,PaG1,PgG1,IdA)
+    WCC_Hq(&PbG2,&PaG1,&PgG1,&IdA,&PIB);
+  
+  #ifdef DEBUG
+    printf("Bob PIA: ");
+    OCT_output(&PIA);
+    printf("\n");
+    printf("Bob PIB: ");
+    OCT_output(&PIB);
+    printf("\n");
+  #endif
+  
+    // Bob calculates AES Key
+    WCC_RECEIVER_KEY(date, &Y, &W,  &PIA, &PIB,  &PaG1, &PgG1, &BKeyG2, &BTPG2, &IdA, &K2);
+    if (rtn != 0) {
+        printf("Bob WCC_RECEIVER_KEY() Error %d\n", rtn);
+        return 1;
+    }
+    printf("Bob AES Key: ");
+    OCT_output(&K2);
+  
+    printf("Bob sends IdB, PbG2 and PgG1 to Alice\n\n");
+    printf("Bob IdB: "); 
+    OCT_output_string(&IdB); 
+    printf("\n");
+    printf("Bob PbG2: ");
+    OCT_output(&PbG2);
+    printf("\n");
+    printf("Bob PgG1: ");
+    OCT_output(&PgG1);
+    printf("\n");
+  
+    printf("Alice\n");
+  
+    // pia = Hq(PaG1,PbG2,PgG1,IdB)
+    WCC_Hq(&PaG1,&PbG2,&PgG1,&IdB,&PIA);
+
+    // pib = Hq(PbG2,PaG1,PgG1,IdA)
+    WCC_Hq(&PbG2,&PaG1,&PgG1,&IdA,&PIB);
+  
+  #ifdef DEBUG
+    printf("Alice PIA: ");
+    OCT_output(&PIA);
+    printf("\n");
+    printf("Alice PIB: ");
+    OCT_output(&PIB);
+    printf("\n");
+  #endif
+  
+    // Alice calculates AES Key
+    rtn = WCC_SENDER_KEY(date, &X, &PIA, &PIB, &PbG2, &PgG1, &AKeyG1, &ATPG1, &IdB, &K1);
+    if (rtn != 0) {
+        printf("Alice WCC_SENDER_KEY() Error %d\n", rtn);
+        return 1;
+    }
+    printf("Alice AES Key: ");
+    OCT_output(&K1);
+  
+    // Send message
+    IV.len=12;
+    for (i=0;i<IV.len;i++)
+      IV.val[i]=i+1;
+    printf("Alice: IV ");
+    OCT_output(&IV);
+  
+    printf("Alice: Message to encrypt for Bob: ");
+    OCT_output_string(&MESSAGE1);
+    printf("\n");
+  
+    WCC_AES_GCM_ENCRYPT(&K1, &IV, &IdA, &MESSAGE1, &C, &T1);
+  
+    printf("Alice: Ciphertext: ");
+    OCT_output(&C);
+  
+    printf("Alice: Encryption Tag: ");
+    OCT_output(&T1);
+    printf("\n");
+  
+    WCC_AES_GCM_DECRYPT(&K2, &IV, &IdA, &C, &P, &T2);
+  
+    printf("Bob: Decrypted message received from Alice: ");
+    OCT_output_string(&P);
+    printf("\n");
+  
+    printf("Bob: Decryption Tag: ");
+    OCT_output(&T2);
+    printf("\n");
+  
+    if (!OCT_comp(&MESSAGE1,&P)) {
+        printf("FAILURE Decryption\n");
+        return 1;
+    }
+  
+    if (!OCT_comp(&T1,&T2)) {
+        printf("FAILURE TAG mismatch\n");
+        return 1;
+    }
+    printf("Iteration %d SUCCESS \n\n", iter);
+  }
+
+  WCC_KILL_CSPRNG(&RNG);
+  return 0;
+}
diff --git a/c/testwcc.c b/c/testwcc.c
new file mode 100755
index 0000000..f01300d
--- /dev/null
+++ b/c/testwcc.c
@@ -0,0 +1,340 @@
+/*
+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.
+*/
+
+
+/* Demonstrate WCC with one TA and no time permits */
+
+/* Build executible after installation:
+   gcc -std=c99 -g testwcc.c -I/opt/amcl/include -L/opt/amcl/lib -lamcl -lwcc -o testwcc */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "wcc.h"
+
+#define DEBUG
+
+int main()
+{
+  int i,rtn;
+
+  /* Master secret */
+  char ms[PGS];
+  octet MS={sizeof(ms),sizeof(ms),ms};
+
+  // sender keys
+  char akeyG1[2*PFS+1];
+  octet AKeyG1={0,sizeof(akeyG1), akeyG1};
+
+  // receiver keys
+  char bkeyG2[4*PFS];
+  octet BKeyG2={0,sizeof(bkeyG2), bkeyG2};
+
+  char hv[HASH_BYTES],alice_id[256],bob_id[256];
+  octet HV={0,sizeof(hv),hv};
+
+  octet IdA={0,sizeof(alice_id),alice_id};
+  octet IdB={0,sizeof(bob_id),bob_id};
+
+  char x[PGS];
+  octet X={sizeof(x),sizeof(x),x};
+  char y[PGS];
+  octet Y={sizeof(y),sizeof(y),y};
+  char w[PGS];
+  octet W={sizeof(w),sizeof(w),w};
+  char pia[PGS];
+  octet PIA={sizeof(pia),sizeof(pia),pia};
+  char pib[PGS];
+  octet PIB={sizeof(pib),sizeof(pib),pib};
+
+  char pgg1[2*PFS+1];
+  octet PgG1={0,sizeof(pgg1), pgg1};
+
+  char pag1[2*PFS+1];
+  octet PaG1={0,sizeof(pag1), pag1};
+
+  char pbg2[4*PFS];
+  octet PbG2={0,sizeof(pbg2), pbg2};
+
+  char seed[32] = {0};
+  octet SEED = {0,sizeof(seed),seed};
+  csprng RNG;
+
+  char message1[256];
+  octet MESSAGE1 = {0, sizeof(message1), message1};
+  OCT_jstring(&MESSAGE1,"Hello Bob");
+
+  char t1[16];  // Tag
+  char t2[16];  // Tag
+  char k1[16];  // AES Key
+  char k2[16];  // AES Key
+  char iv[12]; // IV - Initialisation vector
+  char c[100];  // Ciphertext
+  char p[100];  // Recovered Plaintext
+  octet T1={sizeof(t1),sizeof(t1),t1};
+  octet T2={sizeof(t2),sizeof(t2),t2};
+  octet K1={0,sizeof(k1),k1};
+  octet K2={0,sizeof(k2),k2};
+  octet IV={0,sizeof(iv),iv};
+  octet C={0,sizeof(c),c};
+  octet P={0,sizeof(p),p};
+
+  int date;
+
+  int hashDoneOn = 1;
+  int hashDoneOff = 0;
+
+  date = 0;
+#ifdef DEBUG
+  printf("Date %d \n", date);
+#endif
+
+  /* unrandom seed value! */
+  SEED.len=32;
+  for (i=0;i<32;i++) SEED.val[i]=i+1;
+#ifdef DEBUG
+  printf("SEED: ");
+  OCT_output(&SEED);
+  printf("\n");
+#endif
+
+  /* initialise random number generator */
+  WCC_CREATE_CSPRNG(&RNG,&SEED);
+
+  /* TA: Generate master secret  */
+  rtn = WCC_RANDOM_GENERATE(&RNG,&MS);
+  if (rtn != 0) {
+      printf("TA WCC_RANDOM_GENERATE(&RNG,&MS) Error %d\n", rtn);
+      return 1;
+  }
+#ifdef DEBUG
+  printf("TA MASTER SECRET: ");
+  OCT_output(&MS);
+  printf("\n");
+#endif
+
+  // Alice's ID
+  OCT_jstring(&IdA,"alice@miracl.com");
+
+  // TA: Generate Alices's sender key
+  WCC_HASH_ID(&IdA,&HV);
+  rtn = WCC_GET_G1_MULTIPLE(hashDoneOn,&MS,&HV,&AKeyG1);
+  if (rtn != 0) {
+      printf("TA WCC_GET_G1_MULTIPLE() Error %d\n", rtn);
+      return 1;
+  }
+#ifdef DEBUG
+  printf("TA Alice's sender key: ");
+  OCT_output(&AKeyG1);
+#endif
+
+  // Bob's ID
+  OCT_jstring(&IdB,"bob@miracl.com");
+
+  // TA: Generate Bob's receiver key
+  WCC_HASH_ID(&IdB,&HV);
+  rtn = WCC_GET_G2_MULTIPLE(hashDoneOn,&MS,&HV,&BKeyG2);
+  if (rtn != 0) {
+      printf("TA WCC_GET_G2_MULTIPLE() Error %d\n", rtn);
+      return 1;
+  }
+#ifdef DEBUG
+  printf("TA Bob's receiver key: ");
+  OCT_output(&BKeyG2);
+  printf("\n");
+#endif
+
+  printf("Alice\n");
+
+  rtn = WCC_RANDOM_GENERATE(&RNG,&X);
+  if (rtn != 0) {
+      printf("Alice WCC_RANDOM_GENERATE(&RNG,&X) Error %d\n", rtn);
+      return 1;
+  }
+#ifdef DEBUG
+  printf("Alice X: ");
+  OCT_output(&X);
+  printf("\n");
+#endif
+
+  rtn = WCC_GET_G1_MULTIPLE(hashDoneOff,&X,&IdA,&PaG1);
+  if (rtn != 0) {
+      printf("Alice WCC_GET_G1_MULTIPLE() Error %d\n", rtn);
+      return 1;
+  }
+
+  printf("Alice sends IdA and PaG1 to Bob\n\n");
+  printf("Alice IdA: "); 
+  OCT_output_string(&IdA); 
+  printf("\n");
+  printf("Alice PaG1: ");
+  OCT_output(&PaG1);
+  printf("\n");
+
+  printf("Bob\n");
+
+  rtn = WCC_RANDOM_GENERATE(&RNG,&W);
+  if (rtn != 0) {
+      printf("Bob WCC_RANDOM_GENERATE(&RNG,&W) Error %d\n", rtn);
+      return 1;
+  }
+#ifdef DEBUG
+  printf("Bob W: ");
+  OCT_output(&W);
+  printf("\n");
+#endif
+  rtn = WCC_GET_G1_MULTIPLE(hashDoneOff,&W,&IdA,&PgG1);
+  if (rtn != 0) {
+      printf("Bob WCC_GET_G1_MULTIPLE() Error %d\n", rtn);
+      return 1;
+  }
+#ifdef DEBUG
+  printf("PgG1: ");
+  OCT_output(&PgG1);
+  printf("\n");
+#endif
+
+  rtn = WCC_RANDOM_GENERATE(&RNG,&Y);
+  if (rtn != 0) {
+      printf("Bob WCC_RANDOM_GENERATE(&RNG,&Y) Error %d\n", rtn);
+      return 1;
+  }
+#ifdef DEBUG
+  printf("Bob Y: ");
+  OCT_output(&Y);
+  printf("\n");
+#endif
+  rtn = WCC_GET_G2_MULTIPLE(hashDoneOff,&Y,&IdB,&PbG2);
+  if (rtn != 0) {
+      printf("Bob WCC_GET_G1_MULTIPLE() Error %d\n", rtn);
+      return 1;
+  }
+#ifdef DEBUG
+  printf("Bob PbG2: ");
+  OCT_output(&PbG2);
+  printf("\n");
+#endif
+
+  // pia = Hq(PaG1,PbG2,PgG1,IdB)
+  WCC_Hq(&PaG1,&PbG2,&PgG1,&IdB,&PIA);
+
+  // pib = Hq(PbG2,PaG1,PgG1,IdA)
+  WCC_Hq(&PbG2,&PaG1,&PgG1,&IdA,&PIB);
+
+#ifdef DEBUG
+  printf("Bob PIA: ");
+  OCT_output(&PIA);
+  printf("\n");
+  printf("Bob PIB: ");
+  OCT_output(&PIB);
+  printf("\n");
+#endif
+
+  // Bob calculates AES Key
+  WCC_RECEIVER_KEY(date, &Y, &W,  &PIA, &PIB,  &PaG1, &PgG1, &BKeyG2, NULL, &IdA, &K2);
+  if (rtn != 0) {
+      printf("Bob WCC_RECEIVER_KEY() Error %d\n", rtn);
+      return 1;
+  }
+  printf("Bob AES Key: ");
+  OCT_output(&K2);
+
+  printf("Bob sends IdB, PbG2 and PgG1 to Alice\n\n");
+  printf("Bob IdB: "); 
+  OCT_output_string(&IdB); 
+  printf("\n");
+  printf("Bob PbG2: ");
+  OCT_output(&PbG2);
+  printf("\n");
+  printf("Bob PgG1: ");
+  OCT_output(&PgG1);
+  printf("\n");
+
+  printf("Alice\n");
+
+  // pia = Hq(PaG1,PbG2,PgG1,IdB)
+  WCC_Hq(&PaG1,&PbG2,&PgG1,&IdB,&PIA);
+
+  // pib = Hq(PbG2,PaG1,PgG1,IdA)
+  WCC_Hq(&PbG2,&PaG1,&PgG1,&IdA,&PIB);
+
+#ifdef DEBUG
+  printf("Alice PIA: ");
+  OCT_output(&PIA);
+  printf("\n");
+  printf("Alice PIB: ");
+  OCT_output(&PIB);
+  printf("\n");
+#endif
+
+  // Alice calculates AES Key
+  rtn = WCC_SENDER_KEY(date, &X, &PIA, &PIB, &PbG2, &PgG1, &AKeyG1, NULL, &IdB, &K1);
+  if (rtn != 0) {
+      printf("Alice WCC_SENDER_KEY() Error %d\n", rtn);
+      return 1;
+  }
+  printf("Alice AES Key: ");
+  OCT_output(&K1);
+
+
+  // Send message
+  IV.len=12;
+  for (i=0;i<IV.len;i++)
+    IV.val[i]=i+1;
+  printf("Alice: IV ");
+  OCT_output(&IV);
+
+  printf("Alice: Message to encrypt for Bob: ");
+  OCT_output_string(&MESSAGE1);
+  printf("\n");
+
+  WCC_AES_GCM_ENCRYPT(&K1, &IV, &IdA, &MESSAGE1, &C, &T1);
+
+  printf("Alice: Ciphertext: ");
+  OCT_output(&C);
+
+  printf("Alice: Encryption Tag: ");
+  OCT_output(&T1);
+  printf("\n");
+
+  WCC_AES_GCM_DECRYPT(&K2, &IV, &IdA, &C, &P, &T2);
+
+  printf("Bob: Decrypted message received from Alice: ");
+  OCT_output_string(&P);
+  printf("\n");
+
+  printf("Bob: Decryption Tag: ");
+  OCT_output(&T2);
+  printf("\n");
+
+  if (!OCT_comp(&MESSAGE1,&P)) {
+      printf("FAILURE Decryption\n");
+      return 1;
+  }
+
+  if (!OCT_comp(&T1,&T2)) {
+      printf("FAILURE TAG mismatch\n");
+      return 1;
+  }
+
+  WCC_KILL_CSPRNG(&RNG);
+
+  return 0;
+}
diff --git a/c/testwcc_dta.c b/c/testwcc_dta.c
new file mode 100755
index 0000000..d05d70f
--- /dev/null
+++ b/c/testwcc_dta.c
@@ -0,0 +1,438 @@
+/*
+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.
+*/
+
+
+/* Demonstrate WCC with two TAs and time permits */
+
+/* Build executible after installation:
+   gcc -std=c99 -g testwcc_dta.c  -I/opt/amcl/include -L/opt/amcl/lib -lamcl -lwcc -o testwcc_dta */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "mpin.h"
+#include "wcc.h"
+
+#define DEBUG
+
+int main()
+{
+  int i,rtn;
+
+  /* Master secret shares */
+  char ms1[PGS], ms2[PGS];
+  octet MS1={sizeof(ms1),sizeof(ms1),ms1};
+  octet MS2={sizeof(ms2),sizeof(ms2),ms2};
+
+  // Sender keys
+  char a1keyG1[2*PFS+1], a2keyG1[2*PFS+1];
+  octet A1KeyG1={0,sizeof(a1keyG1), a1keyG1};
+  octet A2KeyG1={0,sizeof(a2keyG1), a2keyG1};
+  char akeyG1[2*PFS+1];
+  octet AKeyG1={0,sizeof(akeyG1), akeyG1};
+
+  // Sender time permits
+  char a1TPG1[2*PFS+1], a2TPG1[2*PFS+1];
+  octet A1TPG1={sizeof(a1TPG1),sizeof(a1TPG1), a1TPG1};
+  octet A2TPG1={sizeof(a2TPG1),sizeof(a2TPG1), a2TPG1};
+  char aTPG1[2*PFS+1];
+  octet ATPG1={0,sizeof(aTPG1), aTPG1};
+
+  // Receiver keys
+  char b1keyG2[4*PFS], b2keyG2[4*PFS];
+  octet B1KeyG2={0,sizeof(b1keyG2), b1keyG2};
+  octet B2KeyG2={0,sizeof(b2keyG2), b2keyG2};
+  char bkeyG2[4*PFS];
+  octet BKeyG2={0,sizeof(bkeyG2), bkeyG2};
+
+  // Receiver time permits
+  char b1TPG2[4*PFS], b2TPG2[4*PFS];
+  octet B1TPG2={sizeof(b1TPG2),sizeof(b1TPG2), b1TPG2};
+  octet B2TPG2={sizeof(b2TPG2),sizeof(b2TPG2), b2TPG2};
+  char bTPG2[4*PFS];
+  octet BTPG2={0,sizeof(bTPG2), bTPG2};
+
+  char ahv[HASH_BYTES],alice_id[256],bhv[HASH_BYTES],bob_id[256];
+  octet AHV={0,sizeof(ahv),ahv};
+  octet BHV={0,sizeof(bhv),bhv};
+
+  octet IdA={0,sizeof(alice_id),alice_id};
+  octet IdB={0,sizeof(bob_id),bob_id};
+
+  char x[PGS];
+  octet X={sizeof(x),sizeof(x),x};
+  char y[PGS];
+  octet Y={sizeof(y),sizeof(y),y};
+  char w[PGS];
+  octet W={sizeof(w),sizeof(w),w};
+  char pia[PGS];
+  octet PIA={sizeof(pia),sizeof(pia),pia};
+  char pib[PGS];
+  octet PIB={sizeof(pib),sizeof(pib),pib};
+
+  char pgg1[2*PFS+1];
+  octet PgG1={0,sizeof(pgg1), pgg1};
+
+  char pag1[2*PFS+1];
+  octet PaG1={0,sizeof(pag1), pag1};
+
+  char pbg2[4*PFS];
+  octet PbG2={0,sizeof(pbg2), pbg2};
+
+  char seed[32] = {0};
+  octet SEED = {0,sizeof(seed),seed};
+  csprng RNG;
+
+  char message1[256];
+  char message2[256];
+  octet MESSAGE1 = {0, sizeof(message1), message1};
+  octet MESSAGE2 = {0, sizeof(message2), message2};
+
+  char t1[16];  // Tag
+  char t2[16];  // Tag
+  char k1[16];  // AES Key
+  char k2[16];  // AES Key
+  char iv[12]; // IV - Initialisation vector
+  char c[100];  // Ciphertext
+  char p[100];  // Recovered Plaintext
+  octet T1={sizeof(t1),sizeof(t1),t1};
+  octet T2={sizeof(t2),sizeof(t2),t2};
+  octet K1={0,sizeof(k1),k1};
+  octet K2={0,sizeof(k2),k2};
+  octet IV={0,sizeof(iv),iv};
+  octet C={0,sizeof(c),c};
+  octet P={0,sizeof(p),p};
+
+  int date;
+  date = WCC_today();
+  printf("Date %d \n", date);
+
+  int hashDoneOn = 1;
+  int hashDoneOff = 0;
+
+  OCT_jstring(&MESSAGE1,"Hello Bob");
+  OCT_jstring(&MESSAGE2,"Hello Alice");
+
+  /* unrandom seed value! */
+  SEED.len=32;
+  for (i=0;i<32;i++) SEED.val[i]=i+1;
+
+  /* initialise random number generator */
+  WCC_CREATE_CSPRNG(&RNG,&SEED);
+
+  /* Generate Client master secret for MIRACL and Customer */
+  rtn = WCC_RANDOM_GENERATE(&RNG,&MS1);
+  if (rtn != 0) {
+      printf("TA WCC_RANDOM_GENERATE(&RNG,&MS1) Error %d\n", rtn);
+      return 1;
+  }
+  rtn = WCC_RANDOM_GENERATE(&RNG,&MS2);
+  if (rtn != 0)
+    {
+      printf("TA WCC_RANDOM_GENERATE(&RNG,&MS2) Error %d\n", rtn);
+      return 1;
+    }
+  printf("TA MASTER SECRET MIRACL: ");
+  OCT_output(&MS1);
+  printf("TA MASTER SECRET CUSTOMER: ");
+  OCT_output(&MS2);
+
+  // Alice's ID
+  OCT_jstring(&IdA,"alice@miracl.com");
+
+  // TA: Generate Alice's sender key
+  WCC_HASH_ID(&IdA,&AHV);
+  rtn = WCC_GET_G1_MULTIPLE(hashDoneOn,&MS1,&AHV,&A1KeyG1);
+  if (rtn != 0) {
+      printf("TA WCC_GET_G1_MULTIPLE(hashDoneOn,&MS1,&AHV,&A1KeyG1) Error %d\n", rtn);
+      return 1;
+  }
+  rtn = WCC_GET_G1_MULTIPLE(hashDoneOn,&MS2,&AHV,&A2KeyG1);
+  if (rtn != 0) {
+      printf("TA WCC_GET_G1_MULTIPLE(hashDoneOn,&MS2,&AHV,&A2KeyG1) Error %d\n", rtn);
+      return 1;
+  }
+  printf("TA A1KeyG1: ");
+  OCT_output(&A1KeyG1);
+  printf("TA A2KeyG1: ");
+  OCT_output(&A2KeyG1);
+
+  rtn = WCC_RECOMBINE_G1(&A1KeyG1, &A2KeyG1, &AKeyG1);
+  if (rtn != 0) {
+      printf("TA WCC_RECOMBINE_G1(&A1KeyG1, &A2KeyG1, &AKeyG1) Error %d\n", rtn);
+      return 1;
+  }
+  printf("TA Alice's sender key: ");
+  OCT_output(&AKeyG1);
+
+  // TA: Generate Alice's G1 time permit
+  rtn = WCC_GET_G1_PERMIT(date,&MS1,&AHV,&A1TPG1);
+  if (rtn != 0) {
+      printf("TA WCC_GET_G1_PERMIT(date,&MS1,&AHV,&A1TPG1) Error %d\n", rtn);
+      return 1;
+  }
+  rtn = WCC_GET_G1_PERMIT(date,&MS2,&AHV,&A2TPG1);
+  if (rtn != 0) {
+      printf("TA WCC_GET_G1_PERMIT(date,&MS2,&AHV,&A2TPG1) Error %d\n", rtn);
+      return 1;
+  }
+  printf("TA A1TPG1: ");
+  OCT_output(&A1TPG1);
+  printf("TA A2TPG1: ");
+  OCT_output(&A2TPG1);
+
+  rtn = WCC_RECOMBINE_G1(&A1TPG1, &A2TPG1, &ATPG1);
+  if (rtn != 0) {
+      printf("Alice WCC_RECOMBINE_G1(&A1TPG1, &A2TPG1, &ATPG1) Error %d\n", rtn);
+      return 1;
+  }
+  printf("TA Alice's sender time permit: ");
+  OCT_output(&ATPG1);
+
+  // Bob's ID
+  OCT_jstring(&IdB,"bob@miracl.com");
+
+  // TA: Generate Bob's receiver key
+  WCC_HASH_ID(&IdB,&BHV);
+  rtn = WCC_GET_G2_MULTIPLE(hashDoneOn,&MS1,&BHV,&B1KeyG2);
+  if (rtn != 0) {
+      printf("TA WCC_GET_G2_MULTIPLE(hashDoneOn,&MS1,&BHV,&B1KeyG2) Error %d\n", rtn);
+      return 1;
+  }
+  rtn = WCC_GET_G2_MULTIPLE(hashDoneOn,&MS2,&BHV,&B2KeyG2);
+  if (rtn != 0) {
+      printf("Bob WCC_GET_G2_MULTIPLE(hashDoneOn,&MS2,&BHV,&B2KeyG2) Error %d\n", rtn);
+      return 1;
+  }
+  printf("TA B1KeyG2: ");
+  OCT_output(&B1KeyG2);
+  printf("TA B2KeyG2: ");
+  OCT_output(&B2KeyG2);
+
+  rtn = WCC_RECOMBINE_G2(&B1KeyG2, &B2KeyG2, &BKeyG2);
+  if (rtn != 0) {
+      printf("Bob WCC_RECOMBINE_G2(&B1KeyG1, &B2KeyG1, &BKeyG2) Error %d\n", rtn);
+      return 1;
+  }
+  printf("TA Bob's receiver key: ");
+  OCT_output(&BKeyG2);
+
+  // TA: Generate Bob's receiver time permit
+  rtn = WCC_GET_G2_PERMIT(date,&MS1,&BHV,&B1TPG2);
+  if (rtn != 0)
+    {
+      printf("TA WCC_GET_G2_PERMIT(date,&MS1,&BHV,&B1TPG2) Error %d\n", rtn);
+      return 1;
+    }
+  rtn = WCC_GET_G2_PERMIT(date,&MS2,&BHV,&B2TPG2);
+  if (rtn != 0) {
+      printf("TA WCC_GET_G2_PERMIT(date,&MS2,&BHV,&B2TPG2) Error %d\n", rtn);
+      return 1;
+  }
+  printf("TA B1TPG2: ");
+  OCT_output(&B1TPG2);
+  printf("TA B2TPG2: ");
+  OCT_output(&B2TPG2);
+
+  rtn = WCC_RECOMBINE_G2(&B1TPG2, &B2TPG2, &BTPG2);
+  if (rtn != 0) {
+      printf("Bob WCC_RECOMBINE_G2(&B1TPG2, &B2TPG2, &BTPG2) Error %d\n", rtn);
+      return 1;
+  }
+  printf("TA Bob's receiver time permit: ");
+  OCT_output(&BTPG2);
+  printf("\n");
+
+  printf("Alice\n");
+
+  rtn = WCC_RANDOM_GENERATE(&RNG,&X);
+  if (rtn != 0) {
+      printf("Alice WCC_RANDOM_GENERATE(&RNG,&X) Error %d\n", rtn);
+      return 1;
+  }
+#ifdef DEBUG
+  printf("Alice X: ");
+  OCT_output(&X);
+  printf("\n");
+#endif
+
+  rtn = WCC_GET_G1_TPMULT(date,&X,&IdA,&PaG1);
+  if (rtn != 0) {
+      printf("Alice WCC_GET_G1_TPMULT(date,&X,&IdA,&PaG1) Error %d\n", rtn);
+      return 1;
+  }
+
+  printf("Alice sends IdA and PaG1 to Bob\n\n");
+  printf("Alice IdA: "); 
+  OCT_output_string(&IdA); 
+  printf("\n");
+  printf("Alice PaG1: ");
+  OCT_output(&PaG1);
+  printf("\n");
+
+  printf("Bob\n");
+
+  rtn = WCC_RANDOM_GENERATE(&RNG,&W);
+  if (rtn != 0) {
+      printf("Bob WCC_RANDOM_GENERATE(&RNG,&W) Error %d\n", rtn);
+      return 1;
+  }
+#ifdef DEBUG
+  printf("Bob W: ");
+  OCT_output(&W);
+  printf("\n");
+#endif
+  rtn = WCC_GET_G1_TPMULT(date,&W,&IdA,&PgG1);
+  if (rtn != 0) {
+      printf("Bob WCC_GET_G1_TPMULT(date,&W,&IdA,&PgG1) Error %d\n", rtn);
+      return 1;
+  }
+#ifdef DEBUG
+  printf("PgG1: ");
+  OCT_output(&PgG1);
+  printf("\n");
+#endif
+
+  rtn = WCC_RANDOM_GENERATE(&RNG,&Y);
+  if (rtn != 0) {
+      printf("Bob WCC_RANDOM_GENERATE(&RNG,&Y) Error %d\n", rtn);
+      return 1;
+  }
+#ifdef DEBUG
+  printf("Bob Y: ");
+  OCT_output(&Y);
+  printf("\n");
+#endif
+  rtn = WCC_GET_G2_TPMULT(date,&Y,&IdB,&PbG2);
+  if (rtn != 0) {
+      printf("Bob WCC_GET_G1_TPMULT(date,&Y,&IdB,&PbG2) Error %d\n", rtn);
+      return 1;
+  }
+#ifdef DEBUG
+  printf("Bob PbG2: ");
+  OCT_output(&PbG2);
+  printf("\n");
+#endif
+
+  // pia = Hq(PaG1,PbG2,PgG1,IdB)
+  WCC_Hq(&PaG1,&PbG2,&PgG1,&IdB,&PIA);
+
+  // pib = Hq(PbG2,PaG1,PgG1,IdA)
+  WCC_Hq(&PbG2,&PaG1,&PgG1,&IdA,&PIB);
+
+#ifdef DEBUG
+  printf("Bob PIA: ");
+  OCT_output(&PIA);
+  printf("\n");
+  printf("Bob PIB: ");
+  OCT_output(&PIB);
+  printf("\n");
+#endif
+
+  // Bob calculates AES Key
+  WCC_RECEIVER_KEY(date, &Y, &W,  &PIA, &PIB,  &PaG1, &PgG1, &BKeyG2, &BTPG2, &IdA, &K2);
+  if (rtn != 0) {
+      printf("Bob WCC_RECEIVER_KEY() Error %d\n", rtn);
+      return 1;
+  }
+  printf("Bob AES Key: ");
+  OCT_output(&K2);
+
+  printf("Bob sends IdB, PbG2 and PgG1 to Alice\n\n");
+  printf("Bob IdB: "); 
+  OCT_output_string(&IdB); 
+  printf("\n");
+  printf("Bob PbG2: ");
+  OCT_output(&PbG2);
+  printf("\n");
+  printf("Bob PgG1: ");
+  OCT_output(&PgG1);
+  printf("\n");
+
+  printf("Alice\n");
+
+  // pia = Hq(PaG1,PbG2,PgG1,IdB)
+  WCC_Hq(&PaG1,&PbG2,&PgG1,&IdB,&PIA);
+
+  // pib = Hq(PbG2,PaG1,PgG1,IdA)
+  WCC_Hq(&PbG2,&PaG1,&PgG1,&IdA,&PIB);
+
+#ifdef DEBUG
+  printf("Alice PIA: ");
+  OCT_output(&PIA);
+  printf("\n");
+  printf("Alice PIB: ");
+  OCT_output(&PIB);
+  printf("\n");
+#endif
+
+  // Alice calculates AES Key
+  rtn = WCC_SENDER_KEY(date, &X, &PIA, &PIB, &PbG2, &PgG1, &AKeyG1, &ATPG1, &IdB, &K1);
+  if (rtn != 0) {
+      printf("Alice WCC_SENDER_KEY() Error %d\n", rtn);
+      return 1;
+  }
+  printf("Alice AES Key: ");
+  OCT_output(&K1);
+
+  // Send message
+  IV.len=12;
+  for (i=0;i<IV.len;i++)
+    IV.val[i]=i+1;
+  printf("Alice: IV ");
+  OCT_output(&IV);
+
+  printf("Alice: Message to encrypt for Bob: ");
+  OCT_output_string(&MESSAGE1);
+  printf("\n");
+
+  WCC_AES_GCM_ENCRYPT(&K1, &IV, &IdA, &MESSAGE1, &C, &T1);
+
+  printf("Alice: Ciphertext: ");
+  OCT_output(&C);
+
+  printf("Alice: Encryption Tag: ");
+  OCT_output(&T1);
+  printf("\n");
+
+  WCC_AES_GCM_DECRYPT(&K2, &IV, &IdA, &C, &P, &T2);
+
+  printf("Bob: Decrypted message received from Alice: ");
+  OCT_output_string(&P);
+  printf("\n");
+
+  printf("Bob: Decryption Tag: ");
+  OCT_output(&T2);
+  printf("\n");
+
+  if (!OCT_comp(&MESSAGE1,&P)) {
+      printf("FAILURE Decryption\n");
+      return 1;
+  }
+
+  if (!OCT_comp(&T1,&T2)) {
+      printf("FAILURE TAG mismatch\n");
+      return 1;
+  }
+
+  WCC_KILL_CSPRNG(&RNG);
+
+  return 0;
+}
diff --git a/c/testwcc_tp.c b/c/testwcc_tp.c
new file mode 100755
index 0000000..280fa85
--- /dev/null
+++ b/c/testwcc_tp.c
@@ -0,0 +1,357 @@
+/*
+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.
+*/
+
+
+/* Demonstrate WCC with time permits */
+
+/* Build executible after installation:
+   gcc -std=c99 -g testwcc_dta.c  -I/opt/amcl/include -L/opt/amcl/lib -lamcl -lwcc -o testwcc_dta */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "mpin.h"
+#include "wcc.h"
+
+#define DEBUG
+
+int main()
+{
+  int i,rtn;
+
+  /* Master secret shares */
+  char ms[PGS];
+  octet MS={sizeof(ms),sizeof(ms),ms};
+
+  // Sender key
+  char akeyG1[2*PFS+1];
+  octet AKeyG1={0,sizeof(akeyG1), akeyG1};
+
+  // Sender time permits
+  char aTPG1[2*PFS+1];
+  octet ATPG1={sizeof(aTPG1),sizeof(aTPG1), aTPG1};
+
+  // Receiver keys
+  char bkeyG2[4*PFS];
+  octet BKeyG2={0,sizeof(bkeyG2), bkeyG2};
+
+  // Receiver time permits
+  char bTPG2[4*PFS];
+  octet BTPG2={sizeof(bTPG2),sizeof(bTPG2), bTPG2};
+
+  char ahv[HASH_BYTES],alice_id[256],bhv[HASH_BYTES],bob_id[256];
+  octet AHV={0,sizeof(ahv),ahv};
+  octet BHV={0,sizeof(bhv),bhv};
+
+  octet IdA={0,sizeof(alice_id),alice_id};
+  octet IdB={0,sizeof(bob_id),bob_id};
+
+  char x[PGS];
+  octet X={sizeof(x),sizeof(x),x};
+  char y[PGS];
+  octet Y={sizeof(y),sizeof(y),y};
+  char w[PGS];
+  octet W={sizeof(w),sizeof(w),w};
+  char pia[PGS];
+  octet PIA={sizeof(pia),sizeof(pia),pia};
+  char pib[PGS];
+  octet PIB={sizeof(pib),sizeof(pib),pib};
+
+  char pgg1[2*PFS+1];
+  octet PgG1={0,sizeof(pgg1), pgg1};
+
+  char pag1[2*PFS+1];
+  octet PaG1={0,sizeof(pag1), pag1};
+
+  char pbg2[4*PFS];
+  octet PbG2={0,sizeof(pbg2), pbg2};
+
+  char seed[32] = {0};
+  octet SEED = {0,sizeof(seed),seed};
+  csprng RNG;
+
+  char message1[256];
+  char message2[256];
+  octet MESSAGE1 = {0, sizeof(message1), message1};
+  octet MESSAGE2 = {0, sizeof(message2), message2};
+
+  char t1[16];  // Tag
+  char t2[16];  // Tag
+  char k1[16];  // AES Key
+  char k2[16];  // AES Key
+  char iv[12]; // IV - Initialisation vector
+  char c[100];  // Ciphertext
+  char p[100];  // Recovered Plaintext
+  octet T1={sizeof(t1),sizeof(t1),t1};
+  octet T2={sizeof(t2),sizeof(t2),t2};
+  octet K1={0,sizeof(k1),k1};
+  octet K2={0,sizeof(k2),k2};
+  octet IV={0,sizeof(iv),iv};
+  octet C={0,sizeof(c),c};
+  octet P={0,sizeof(p),p};
+
+  int date;
+  date = WCC_today();
+  printf("Date %d \n", date);
+
+  int hashDoneOn = 1;
+  int hashDoneOff = 0;
+
+  OCT_jstring(&MESSAGE1,"Hello Bob");
+  OCT_jstring(&MESSAGE2,"Hello Alice");
+
+  /* unrandom seed value! */
+  SEED.len=32;
+  for (i=0;i<32;i++) SEED.val[i]=i+1;
+
+  /* initialise random number generator */
+  WCC_CREATE_CSPRNG(&RNG,&SEED);
+
+  /* Generate Client master secret for MIRACL and Customer */
+  rtn = WCC_RANDOM_GENERATE(&RNG,&MS);
+  if (rtn != 0) {
+      printf("TA WCC_RANDOM_GENERATE(&RNG,&MS) Error %d\n", rtn);
+      return 1;
+  }
+  printf("TA MASTER SECRET: ");
+  OCT_output(&MS);
+
+  // Alice's ID
+  OCT_jstring(&IdA,"alice@miracl.com");
+
+  // TA: Generate Alice's sender key
+  WCC_HASH_ID(&IdA,&AHV);
+  rtn = WCC_GET_G1_MULTIPLE(hashDoneOn,&MS,&AHV,&AKeyG1);
+  if (rtn != 0) {
+      printf("TA WCC_GET_G1_MULTIPLE(hashDoneOn,&MS,&AHV,&AKeyG1) Error %d\n", rtn);
+      return 1;
+  }
+  printf("TA Alice's sender key: ");
+  OCT_output(&AKeyG1);
+
+  // TA: Generate Alice's G1 time permit
+  rtn = WCC_GET_G1_PERMIT(date,&MS,&AHV,&ATPG1);
+  if (rtn != 0) {
+      printf("TA WCC_GET_G1_PERMIT(date,&MS,&AHV,&ATPG1) Error %d\n", rtn);
+      return 1;
+  }
+  printf("TA Alice's sender time permit: ");
+  OCT_output(&ATPG1);
+
+  // Bob's ID
+  OCT_jstring(&IdB,"bob@miracl.com");
+
+  // TA: Generate Bob's receiver key
+  WCC_HASH_ID(&IdB,&BHV);
+  rtn = WCC_GET_G2_MULTIPLE(hashDoneOn,&MS,&BHV,&BKeyG2);
+  if (rtn != 0) {
+      printf("TA WCC_GET_G2_MULTIPLE(hashDoneOn,&MS,&BHV,&BKeyG2) Error %d\n", rtn);
+      return 1;
+  }
+  printf("TA Bob's receiver key: ");
+  OCT_output(&BKeyG2);
+
+  // TA: Generate Bob's receiver time permit
+  rtn = WCC_GET_G2_PERMIT(date,&MS,&BHV,&BTPG2);
+  if (rtn != 0)
+    {
+      printf("TA WCC_GET_G2_PERMIT(date,&MS,&BHV,&BTPG2) Error %d\n", rtn);
+      return 1;
+    }
+  printf("TA Bob's receiver time permit: ");
+  OCT_output(&BTPG2);
+  printf("\n");
+
+  printf("Alice\n");
+
+  rtn = WCC_RANDOM_GENERATE(&RNG,&X);
+  if (rtn != 0) {
+      printf("Alice WCC_RANDOM_GENERATE(&RNG,&X) Error %d\n", rtn);
+      return 1;
+  }
+#ifdef DEBUG
+  printf("Alice X: ");
+  OCT_output(&X);
+  printf("\n");
+#endif
+
+  rtn = WCC_GET_G1_TPMULT(date,&X,&IdA,&PaG1);
+  if (rtn != 0) {
+      printf("Alice WCC_GET_G1_TPMULT(date,&X,&IdA,&PaG1) Error %d\n", rtn);
+      return 1;
+  }
+
+  printf("Alice sends IdA and PaG1 to Bob\n\n");
+  printf("Alice IdA: "); 
+  OCT_output_string(&IdA); 
+  printf("\n");
+  printf("Alice PaG1: ");
+  OCT_output(&PaG1);
+  printf("\n");
+
+  printf("Bob\n");
+
+  rtn = WCC_RANDOM_GENERATE(&RNG,&W);
+  if (rtn != 0) {
+      printf("Bob WCC_RANDOM_GENERATE(&RNG,&W) Error %d\n", rtn);
+      return 1;
+  }
+#ifdef DEBUG
+  printf("Bob W: ");
+  OCT_output(&W);
+  printf("\n");
+#endif
+  rtn = WCC_GET_G1_TPMULT(date,&W,&IdA,&PgG1);
+  if (rtn != 0) {
+      printf("Bob WCC_GET_G1_TPMULT(date,&W,&IdA,&PgG1) Error %d\n", rtn);
+      return 1;
+  }
+#ifdef DEBUG
+  printf("PgG1: ");
+  OCT_output(&PgG1);
+  printf("\n");
+#endif
+
+  rtn = WCC_RANDOM_GENERATE(&RNG,&Y);
+  if (rtn != 0) {
+      printf("Bob WCC_RANDOM_GENERATE(&RNG,&Y) Error %d\n", rtn);
+      return 1;
+  }
+#ifdef DEBUG
+  printf("Bob Y: ");
+  OCT_output(&Y);
+  printf("\n");
+#endif
+  rtn = WCC_GET_G2_TPMULT(date,&Y,&IdB,&PbG2);
+  if (rtn != 0) {
+      printf("Bob WCC_GET_G1_TPMULT(date,&Y,&IdB,&PbG2) Error %d\n", rtn);
+      return 1;
+  }
+#ifdef DEBUG
+  printf("Bob PbG2: ");
+  OCT_output(&PbG2);
+  printf("\n");
+#endif
+
+  // pia = Hq(PaG1,PbG2,PgG1,IdB)
+  WCC_Hq(&PaG1,&PbG2,&PgG1,&IdB,&PIA);
+
+  // pib = Hq(PbG2,PaG1,PgG1,IdA)
+  WCC_Hq(&PbG2,&PaG1,&PgG1,&IdA,&PIB);
+
+#ifdef DEBUG
+  printf("Bob PIA: ");
+  OCT_output(&PIA);
+  printf("\n");
+  printf("Bob PIB: ");
+  OCT_output(&PIB);
+  printf("\n");
+#endif
+
+  // Bob calculates AES Key
+  WCC_RECEIVER_KEY(date, &Y, &W,  &PIA, &PIB,  &PaG1, &PgG1, &BKeyG2, &BTPG2, &IdA, &K2);
+  if (rtn != 0) {
+      printf("Bob WCC_RECEIVER_KEY() Error %d\n", rtn);
+      return 1;
+  }
+  printf("Bob AES Key: ");
+  OCT_output(&K2);
+
+  printf("Bob sends IdB, PbG2 and PgG1 to Alice\n\n");
+  printf("Bob IdB: "); 
+  OCT_output_string(&IdB); 
+  printf("\n");
+  printf("Bob PbG2: ");
+  OCT_output(&PbG2);
+  printf("\n");
+  printf("Bob PgG1: ");
+  OCT_output(&PgG1);
+  printf("\n");
+
+  printf("Alice\n");
+
+  // pia = Hq(PaG1,PbG2,PgG1,IdB)
+  WCC_Hq(&PaG1,&PbG2,&PgG1,&IdB,&PIA);
+
+  // pib = Hq(PbG2,PaG1,PgG1,IdA)
+  WCC_Hq(&PbG2,&PaG1,&PgG1,&IdA,&PIB);
+
+#ifdef DEBUG
+  printf("Alice PIA: ");
+  OCT_output(&PIA);
+  printf("\n");
+  printf("Alice PIB: ");
+  OCT_output(&PIB);
+  printf("\n");
+#endif
+
+  // Alice calculates AES Key
+  rtn = WCC_SENDER_KEY(date, &X, &PIA, &PIB, &PbG2, &PgG1, &AKeyG1, &ATPG1, &IdB, &K1);
+  if (rtn != 0) {
+      printf("Alice WCC_SENDER_KEY() Error %d\n", rtn);
+      return 1;
+  }
+  printf("Alice AES Key: ");
+  OCT_output(&K1);
+
+  // Send message
+  IV.len=12;
+  for (i=0;i<IV.len;i++)
+    IV.val[i]=i+1;
+  printf("Alice: IV ");
+  OCT_output(&IV);
+
+  printf("Alice: Message to encrypt for Bob: ");
+  OCT_output_string(&MESSAGE1);
+  printf("\n");
+
+  WCC_AES_GCM_ENCRYPT(&K1, &IV, &IdA, &MESSAGE1, &C, &T1);
+
+  printf("Alice: Ciphertext: ");
+  OCT_output(&C);
+
+  printf("Alice: Encryption Tag: ");
+  OCT_output(&T1);
+  printf("\n");
+
+  WCC_AES_GCM_DECRYPT(&K2, &IV, &IdA, &C, &P, &T2);
+
+  printf("Bob: Decrypted message received from Alice: ");
+  OCT_output_string(&P);
+  printf("\n");
+
+  printf("Bob: Decryption Tag: ");
+  OCT_output(&T2);
+  printf("\n");
+
+  if (!OCT_comp(&MESSAGE1,&P)) {
+      printf("FAILURE Decryption\n");
+      return 1;
+  }
+
+  if (!OCT_comp(&T1,&T2)) {
+      printf("FAILURE TAG mismatch\n");
+      return 1;
+  }
+
+  WCC_KILL_CSPRNG(&RNG);
+
+  return 0;
+}
diff --git a/c/wcc.c b/c/wcc.c
new file mode 100755
index 0000000..48c6392
--- /dev/null
+++ b/c/wcc.c
@@ -0,0 +1,818 @@
+/*
+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.
+*/
+
+/* Wang Functions */
+
+/* Version 3.0 - supports Time Permits */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "wcc.h"
+
+// #define DEBUG
+
+/* general purpose hashing functions */
+static void start_hash(hash *sha)
+{
+  HASH_init(sha);
+}
+
+static void add_to_hash(hash *sha,octet *x)
+{
+  int i;
+  for (i=0;i<x->len;i++)
+  {
+    /*printf("%d,",(unsigned char)x->val[i]);*/
+    HASH_process(sha,x->val[i]);
+  }
+}
+
+static void finish_hash(hash *sha,octet *w)
+{
+  int i;
+  char hh[HASH_BYTES];
+  HASH_hash(sha,hh);
+
+  OCT_empty(w);
+  OCT_jbytes(w,hh,HASH_BYTES);
+  for (i=0;i<HASH_BYTES;i++) hh[i]=0;
+}
+
+/* map octet string to point on curve */
+static void mapit(octet *h,ECP *P)
+{
+  BIG q,px;
+  BIG_fromBytes(px,h->val);
+  BIG_rcopy(q,Modulus);
+  BIG_mod(px,q);
+
+  while (!ECP_setx(P,px,0))
+    BIG_inc(px,1);
+}
+
+/* maps to hash value to point on G2 */
+static void mapit2(octet *h,ECP2 *Q)
+{
+  BIG q,one,Fx,Fy,x,hv;
+  FP2 X;
+  ECP2 T,K;
+  BIG_fromBytes(hv,h->val);
+  BIG_rcopy(q,Modulus);
+  BIG_one(one);
+  BIG_mod(hv,q);
+
+  for (;;)
+  {
+    FP2_from_BIGs(&X,one,hv);
+    if (ECP2_setx(Q,&X)) break;
+    BIG_inc(hv,1);
+  }
+
+  /* Fast Hashing to G2 - Fuentes-Castaneda, Knapp and Rodriguez-Henriquez */
+  BIG_rcopy(Fx,CURVE_Fra);
+  BIG_rcopy(Fy,CURVE_Frb);
+  FP2_from_BIGs(&X,Fx,Fy);
+  BIG_rcopy(x,CURVE_Bnx);
+
+  ECP2_copy(&T,Q);
+  ECP2_mul(&T,x);
+  ECP2_neg(&T);  /* our x is negative */
+  ECP2_copy(&K,&T);
+  ECP2_dbl(&K);
+  ECP2_add(&K,&T);
+  ECP2_affine(&K);
+
+  ECP2_frob(&K,&X);
+  ECP2_frob(Q,&X); ECP2_frob(Q,&X); ECP2_frob(Q,&X);
+  ECP2_add(Q,&T);
+  ECP2_add(Q,&K);
+  ECP2_frob(&T,&X); ECP2_frob(&T,&X);
+  ECP2_add(Q,&T);
+  ECP2_affine(Q);
+}
+
+/* Hash number (optional) and octet to octet */
+static void hashit(int n,octet *x,octet *h)
+{
+  int i,c[4];
+  hash sha;
+  char hh[HASH_BYTES];
+  BIG px;
+
+  HASH_init(&sha);
+  if (n>0)
+  {
+    c[0]=(n>>24)&0xff;
+    c[1]=(n>>16)&0xff;
+    c[2]=(n>>8)&0xff;
+    c[3]=(n)&0xff;
+    for (i=0;i<4;i++) HASH_process(&sha,c[i]);
+  }
+  for (i=0;i<x->len;i++) HASH_process(&sha,x->val[i]);
+  HASH_hash(&sha,hh);
+  OCT_empty(h);
+  OCT_jbytes(h,hh,HASH_BYTES);
+  for (i=0;i<HASH_BYTES;i++) hh[i]=0;
+}
+
+
+/*! \brief Hash EC Points and Id to an integer 
+ *
+ *  Perform sha256 of EC Points and Id. Map to an integer modulus the 
+ *  curve order
+ * 
+ *  <ol>
+ *  <li> x = toInteger(sha256(A,B,C,D))
+ *  <li> h = x % q where q is the curve order
+ *  </ol>
+ *
+ *  @param  A        EC Point
+ *  @param  B        EC Point
+ *  @param  C        EC Point
+ *  @param  D        Identity
+ *  @return h        Integer
+ */
+void WCC_Hq(octet *A,octet *B,octet *C,octet *D,octet *h)
+{
+  int i;
+  hash sha;
+  char hh[HASH_BYTES];
+  BIG q,hs;
+
+  BIG_rcopy(q,CURVE_Order);
+
+#ifdef DEBUG
+  printf("WCC_Hq: A: ");
+  OCT_output(A);
+  printf("\n");
+  printf("WCC_Hq: B: ");
+  OCT_output(B);
+  printf("\n");
+  printf("WCC_Hq: C: ");
+  OCT_output(C);
+  printf("\n");
+  printf("WCC_Hq: D: ");
+  OCT_output(D);
+  printf("\n");
+#endif
+
+  HASH_init(&sha);
+  for (i=0;i<A->len;i++) {
+    HASH_process(&sha,A->val[i]);
+  }
+
+  for (i=0;i<B->len;i++) {
+    HASH_process(&sha,B->val[i]);
+  }
+
+  for (i=0;i<C->len;i++) {
+    HASH_process(&sha,C->val[i]);
+  }
+
+  for (i=0;i<D->len;i++) {
+    HASH_process(&sha,D->val[i]);
+  }
+
+  HASH_hash(&sha,hh);
+
+  BIG_fromBytes(hs,hh);
+  BIG_mod(hs,q);
+  for (i=0;i<HASH_BYTES;i++) {
+    hh[i]=0;
+  }
+  BIG_toBytes(h->val,hs);
+  h->len=PGS;
+}
+
+/*! \brief Calculate value in G1 multiplied by an integer
+ *
+ *  Calculate a value in G1. VG1 = s*H1(ID) where ID is the identity.
+ * 
+ *  <ol>
+ *  <li> VG1 = s*H1(ID)
+ *  </ol>
+ *
+ *  @param  hashDone    ID value is already hashed if set to 1
+ *  @param  S           integer modulus curve order
+ *  @param  ID          ID value or sha256(ID)
+ *  @param  VG1         EC point VG1 = s*H1(ID)
+ *  @return rtn         Returns 0 if successful or else an error code  
+ */
+int WCC_GET_G1_MULTIPLE(int hashDone, octet *S,octet *ID,octet *VG1)
+{
+  BIG s;
+  ECP P;
+  char h[HASH_BYTES];
+  octet H={0,sizeof(h),h};
+
+  if (hashDone) {
+    mapit(ID,&P);
+  } else {
+    hashit(0,ID,&H);
+    mapit(&H,&P);
+  }
+
+  BIG_fromBytes(s,S->val);
+  PAIR_G1mul(&P,s);
+
+  ECP_toOctet(VG1,&P);
+  return 0;
+}
+
+/*! \brief Calculate a value in G1 used for when time permits are enabled
+ *
+ *  Calculate a value in G1 used for when time permits are enabled
+ * 
+ *  <ol>
+ *  <li> VG1 = s*H1(ID) + s*H1(date|sha256(ID))
+ *  </ol>
+ *
+ *  @param  date        Epoch days
+ *  @param  S           integer modulus curve order
+ *  @param  ID          ID value or sha256(ID)
+ *  @param  VG1         EC point in G1
+ *  @return rtn         Returns 0 if successful or else an error code  
+ */
+int WCC_GET_G1_TPMULT(int date, octet *S,octet *ID,octet *VG1)
+{
+  BIG s;
+  ECP P,Q;
+  char h1[HASH_BYTES];
+  octet H1={0,sizeof(h1),h1};
+  char h2[HASH_BYTES];
+  octet H2={0,sizeof(h2),h2};
+
+  // H1(ID)
+  hashit(0,ID,&H1);
+  mapit(&H1,&P);
+
+  // H1(date|sha256(ID))
+  hashit(date,&H1,&H2);
+  mapit(&H2,&Q);
+
+  // P = P + Q
+  ECP_add(&P,&Q);
+
+  // P = s(P+Q)
+  BIG_fromBytes(s,S->val);
+  PAIR_G1mul(&P,s);
+
+  ECP_toOctet(VG1,&P);
+  return 0;
+}
+
+/*! \brief Calculate a value in G2 used for when time permits are enabled
+ *
+ *  Calculate a value in G2 used for when time permits are enabled
+ * 
+ *  <ol>
+ *  <li> VG2 = s*H1(ID) + s*H1(date|sha256(ID))
+ *  </ol>
+ *
+ *  @param  date        Epoch days
+ *  @param  S           integer modulus curve order
+ *  @param  ID          ID value or sha256(ID)
+ *  @param  VG2         EC point in G2
+ *  @return rtn         Returns 0 if successful or else an error code  
+ */
+int WCC_GET_G2_TPMULT(int date, octet *S,octet *ID,octet *VG2)
+{
+  BIG s;
+  ECP2 P,Q;
+  char h1[HASH_BYTES];
+  octet H1={0,sizeof(h1),h1};
+  char h2[HASH_BYTES];
+  octet H2={0,sizeof(h2),h2};
+
+  // H1(ID)
+  hashit(0,ID,&H1);
+  mapit2(&H1,&P);
+
+  // H1(date|sha256(ID))
+  hashit(date,&H1,&H2);
+  mapit2(&H2,&Q);
+
+  // P = P + Q
+  ECP2_add(&P,&Q);
+
+  // P = s(P+Q)
+  BIG_fromBytes(s,S->val);
+  PAIR_G2mul(&P,s);
+
+  ECP2_toOctet(VG2,&P);
+  return 0;
+}
+
+/*! \brief Calculate value in G2 multiplied by an integer
+ *
+ *  Calculate a value in G2. VG2 = s*H2(ID) where ID is the identity.
+ * 
+ *  <ol>
+ *  <li> VG2 = s*H2(ID)
+ *  </ol>
+ *
+ *  @param  hashDone  ID is value is already hashed if set to 1
+ *  @param  S         integer modulus curve order
+ *  @param  ID        ID Value or sha256(ID)
+ *  @param  VG2       EC Point VG2 = s*H2(ID)
+ *  @return rtn       Returns 0 if successful or else an error code  
+ */
+int WCC_GET_G2_MULTIPLE(int hashDone, octet *S,octet *ID,octet *VG2)
+{
+  BIG s;
+  ECP2 P;
+  char h[HASH_BYTES];
+  octet H={0,sizeof(h),h};
+
+  if (hashDone) {
+    mapit2(ID,&P);
+  } else {
+    hashit(0,ID,&H);
+    mapit2(&H,&P);
+  }
+
+  BIG_fromBytes(s,S->val);
+  PAIR_G2mul(&P,s);
+
+  ECP2_toOctet(VG2,&P);
+  return 0;
+}
+
+/*! \brief Calculate time permit in G2 
+ *
+ *  Calculate time permit in G2. 
+ * 
+ *  <ol>
+ *  <li> TPG2=s*H2(date|sha256(ID))
+ *  </ol>
+ *
+ *  @param  date      Epoch days
+ *  @param  S         Master secret
+ *  @param  HID       sha256(ID)
+ *  @param  TPG2      Time Permit in G2
+ *  @return rtn       Returns 0 if successful or else an error code  
+ */
+int WCC_GET_G2_PERMIT(int date,octet *S,octet *HID,octet *TPG2)
+{
+  BIG s;
+  ECP2 P;
+  char h[HASH_BYTES];
+  octet H={0,sizeof(h),h};
+
+  hashit(date,HID,&H);
+  mapit2(&H,&P);
+  BIG_fromBytes(s,S->val);
+  PAIR_G2mul(&P,s);
+
+  ECP2_toOctet(TPG2,&P);
+  return 0;
+}
+
+/*! \brief Calculate the sender AES key
+ *
+ *  Calculate the sender AES Key
+ * 
+ *  <ol>
+ *  <li> j=e((x+pia).AKeyG1,pib.BG2+PbG2)
+ *  <li> K=H(j,x.PgG1)
+ *  </ol>
+ *
+ *  @param  date        Epoch days
+ *  @param  xOct        Random x < q where q is the curve order
+ *  @param  piaOct      Hq(PaG1,PbG2,PgG1)
+ *  @param  pibOct      Hq(PbG2,PaG1,PgG1)
+ *  @param  PbG2Oct     y.BG2 where y < q
+ *  @param  PgG1Oct     w.AG1 where w < q
+ *  @param  AKeyG1Oct   Sender key 
+ *  @param  ATPG1Oct    Sender time permit 
+ *  @param  IdBOct      Receiver identity
+ *  @return AESKeyOct   AES key
+ *  @return rtn         Returns 0 if successful or else an error code  
+ */
+int WCC_SENDER_KEY(int date, octet *xOct, octet *piaOct, octet *pibOct, octet *PbG2Oct, octet *PgG1Oct, octet *AKeyG1Oct, octet *ATPG1Oct, octet *IdBOct, octet *AESKeyOct)
+{
+  ECP sAG1,ATPG1,PgG1;
+  ECP2 BG2,dateBG2,PbG2;
+  char hv1[HASH_BYTES],hv2[HASH_BYTES];
+  octet HV1={0,sizeof(hv1),hv1};
+  octet HV2={0,sizeof(hv2),hv2};
+
+  // Pairing outputs
+  FP12 g;
+  char pair[12*PFS];
+  octet PAIR={0,sizeof(pair),pair};
+
+  FP4 c;
+  BIG t,x,z,pia,pib;
+  char ht[HASH_BYTES];
+  octet HT={0,sizeof(ht),ht};
+  hash sha;
+  char xpgg1[2*PFS+1];
+  octet xPgG1Oct={0,sizeof(xpgg1), xpgg1};
+
+  BIG_fromBytes(x,xOct->val);
+  BIG_fromBytes(pia,piaOct->val);
+  BIG_fromBytes(pib,pibOct->val);
+
+  if (!ECP2_fromOctet(&PbG2,PbG2Oct)) {
+#ifdef DEBUG
+    printf("PbG2Oct Invalid Point: ");
+    OCT_output(PbG2Oct);
+    printf("\n");
+#endif
+    return WCC_INVALID_POINT;
+  }
+
+  if (!ECP_fromOctet(&PgG1,PgG1Oct)) {
+#ifdef DEBUG
+    printf("PgG1Oct Invalid Point: ");
+    OCT_output(PgG1Oct);
+    printf("\n");
+#endif
+    return WCC_INVALID_POINT;
+  }
+
+  hashit(0,IdBOct,&HV1);
+  mapit2(&HV1,&BG2);
+
+  if (!ECP_fromOctet(&sAG1,AKeyG1Oct)) {
+#ifdef DEBUG
+    printf("AKeyG1Oct Invalid Point: ");
+    OCT_output(AKeyG1Oct);
+    printf("\n");
+#endif
+    return WCC_INVALID_POINT;
+  }
+
+  // Use time permits
+  if (date)
+    {
+      // calculate e( (s*A+s*H(date|H(AID))) , (B+H(date|H(BID))) )
+      if (!ECP_fromOctet(&ATPG1,ATPG1Oct)) {
+#ifdef DEBUG
+        printf("ATPG1Oct Invalid Point: ");
+        OCT_output(ATPG1Oct);
+        printf("\n");
+        return WCC_INVALID_POINT;
+#endif
+      }
+
+      // H2(date|sha256(IdB))
+      hashit(date,&HV1,&HV2);
+      mapit2(&HV2,&dateBG2);
+
+      // sAG1 = sAG1 + ATPG1
+      ECP_add(&sAG1, &ATPG1);
+      // BG2 = BG2 + H(date|H(IdB))
+      ECP2_add(&BG2, &dateBG2);
+    }
+  // z =  x + pia
+  BIG_add(z,x,pia);
+
+  // (x+pia).AKeyG1
+  PAIR_G1mul(&sAG1,z);
+
+  // pib.BG2
+  PAIR_G2mul(&BG2,pib);
+
+  // pib.BG2+PbG2
+  ECP2_add(&BG2, &PbG2);
+
+  PAIR_ate(&g,&BG2,&sAG1);
+  PAIR_fexp(&g);
+  // printf("WCC_SENDER_KEY e(sAG1,BG2) = ");FP12_output(&g); printf("\n");
+
+  // x.PgG1
+  PAIR_G1mul(&PgG1,x);
+  ECP_toOctet(&xPgG1Oct,&PgG1);
+
+  // Generate AES Key : K=H(k,x.PgG1)
+  FP12_trace(&c,&g);
+  HT.len=HASH_BYTES;
+  start_hash(&sha);
+  BIG_copy(t,c.a.a); FP_redc(t); BIG_toBytes(&(HT.val[0]),t);
+  add_to_hash(&sha,&HT);
+  BIG_copy(t,c.a.b); FP_redc(t); BIG_toBytes(&(HT.val[0]),t);
+  add_to_hash(&sha,&HT);
+  BIG_copy(t,c.b.a); FP_redc(t); BIG_toBytes(&(HT.val[0]),t);
+  add_to_hash(&sha,&HT);
+  BIG_copy(t,c.b.b); FP_redc(t); BIG_toBytes(&(HT.val[0]),t);
+  add_to_hash(&sha,&HT);
+  add_to_hash(&sha,&xPgG1Oct);
+  finish_hash(&sha,&HT);
+  OCT_empty(AESKeyOct);
+  OCT_jbytes(AESKeyOct,HT.val,PAS);
+
+  return 0;
+}
+
+/*! \brief Calculate the receiver AES key
+ *
+ *  Calculate time permit in G2. 
+ * 
+ *  <ol>
+ *  <li> j=e(pia.AG1+PaG1,(y+pib).BKeyG2)
+ *  <li> K=H(j,w.PaG1)
+ *  </ol>
+ *
+ *  @param  date        Epoch days
+ *  @param  yOct        Random y < q where q is the curve order
+ *  @param  wOct        Random w < q where q is the curve order
+ *  @param  piaOct      Hq(PaG1,PbG2,PgG1)
+ *  @param  pibOct      Hq(PbG2,PaG1,PgG1)
+ *  @param  PaG1Oct     x.AG1 where x < q
+ *  @param  PgG1Oct     w.AG1 where w < q
+ *  @param  BKeyG2Oct   Receiver key 
+ *  @param  BTPG2Oct    Receiver time permit 
+ *  @param  IdAOct      Sender identity
+ *  @return AESKeyOct   AES key
+ *  @return rtn         Returns 0 if successful or else an error code  
+ */
+int WCC_RECEIVER_KEY(int date, octet *yOct, octet *wOct,  octet *piaOct, octet *pibOct,  octet *PaG1Oct, octet *PgG1Oct, octet *BKeyG2Oct,octet *BTPG2Oct,  octet *IdAOct, octet *AESKeyOct)
+{
+  ECP AG1,dateAG1,PgG1,PaG1;
+  ECP2 sBG2,BTPG2;
+  char hv1[HASH_BYTES],hv2[HASH_BYTES];
+  octet HV1={0,sizeof(hv1),hv1};
+  octet HV2={0,sizeof(hv2),hv2};
+
+  // Pairing outputs
+  FP12 g;
+  char pair[12*PFS];
+  octet PAIR={0,sizeof(pair),pair};
+
+  FP4 c;
+  BIG t,w,y,pia,pib;;
+  char ht[HASH_BYTES];
+  octet HT={0,sizeof(ht),ht};
+  hash sha;
+  char wpag1[2*PFS+1];
+  octet wPaG1Oct={0,sizeof(wpag1), wpag1};
+  BIG_fromBytes(y,yOct->val);
+  BIG_fromBytes(w,wOct->val);
+  BIG_fromBytes(pia,piaOct->val);
+  BIG_fromBytes(pib,pibOct->val);
+
+  if (!ECP_fromOctet(&PaG1,PaG1Oct))
+    return WCC_INVALID_POINT;
+
+  if (!ECP_fromOctet(&PgG1,PgG1Oct))
+    return WCC_INVALID_POINT;
+
+  hashit(0,IdAOct,&HV1);
+  mapit(&HV1,&AG1);
+
+  if (!ECP2_fromOctet(&sBG2,BKeyG2Oct))
+    return WCC_INVALID_POINT;
+
+  if (date) {       
+    // Calculate e( (A+H(date|H(AID))) , (s*B+s*H(date|H(IdB))) )
+    if (!ECP2_fromOctet(&BTPG2,BTPG2Oct))   
+      return WCC_INVALID_POINT;
+
+    // H1(date|sha256(AID))
+    hashit(date,&HV1,&HV2);
+    mapit(&HV2,&dateAG1);
+
+    // sBG2 = sBG2 + TPG2
+    ECP2_add(&sBG2, &BTPG2);
+    // AG1 = AG1 + H(date|H(AID))
+    ECP_add(&AG1, &dateAG1);
+  }
+  // y =  y + pib
+  BIG_add(y,y,pib);
+
+  // (y+pib).BKeyG2
+  PAIR_G2mul(&sBG2,y);
+
+  // pia.AG1
+  PAIR_G1mul(&AG1,pia);
+
+  // pia.AG1+PaG1
+  ECP_add(&AG1, &PaG1);
+
+  PAIR_ate(&g,&sBG2,&AG1);
+  PAIR_fexp(&g);
+  // printf("WCC_RECEIVER_KEY e(AG1,sBG2) = ");FP12_output(&g); printf("\n");
+
+  // w.PaG1
+  PAIR_G1mul(&PaG1,w);
+  ECP_toOctet(&wPaG1Oct,&PaG1);
+
+  // Generate AES Key: K=H(k,w.PaG1)
+  FP12_trace(&c,&g);
+  HT.len=HASH_BYTES;
+  start_hash(&sha);
+  BIG_copy(t,c.a.a); FP_redc(t); BIG_toBytes(&(HT.val[0]),t);
+  add_to_hash(&sha,&HT);
+  BIG_copy(t,c.a.b); FP_redc(t); BIG_toBytes(&(HT.val[0]),t);
+  add_to_hash(&sha,&HT);
+  BIG_copy(t,c.b.a); FP_redc(t); BIG_toBytes(&(HT.val[0]),t);
+  add_to_hash(&sha,&HT);
+  BIG_copy(t,c.b.b); FP_redc(t); BIG_toBytes(&(HT.val[0]),t);
+  add_to_hash(&sha,&HT);
+  add_to_hash(&sha,&wPaG1Oct);
+  finish_hash(&sha,&HT);
+  OCT_empty(AESKeyOct);
+  OCT_jbytes(AESKeyOct,HT.val,PAS);
+
+  return 0;
+
+}
+
+/*! \brief Encrypt data using AES GCM
+ *
+ *  AES is run as a block cypher in the GCM  mode of operation. The key size is 128 bits.
+ *  This function will encrypt any data length.
+ *
+ *  @param  K             128 bit secret key
+ *  @param  IV            96 bit initialization vector
+ *  @param  H             Additional authenticated data (AAD). This data is authenticated, but not encrypted.
+ *  @param  P             Plaintext
+ *  @return C             Ciphertext. It is the same length as the plaintext.
+ *  @return T             128 bit authentication tag.
+ */
+void WCC_AES_GCM_ENCRYPT(octet *K,octet *IV,octet *H,octet *P,octet *C,octet *T)
+{
+  gcm g;
+  GCM_init(&g,K->val,IV->len,IV->val);
+  GCM_add_header(&g,H->val,H->len);
+  GCM_add_plain(&g,C->val,P->val,P->len);
+  C->len=P->len;
+  GCM_finish(&g,T->val);
+  T->len=16;
+}
+
+/*! \brief Decrypt data using AES GCM
+ *
+ *  AES is run as a block cypher in the GCM  mode of operation. The key size is 128 bits.
+ *  This function will decrypt any data length.
+ *
+ *  @param  K             128 bit secret key
+ *  @param  IV            96 bit initialization vector
+ *  @param  H             Additional authenticated data (AAD). This data is authenticated, but not encrypted.
+ *  @param  C             Ciphertext.
+ *  @return P             Decrypted data. It is the same length as the ciphertext.Plaintext
+ *  @return T             128 bit authentication tag.
+ */
+void WCC_AES_GCM_DECRYPT(octet *K,octet *IV,octet *H,octet *C,octet *P,octet *T)
+{
+  gcm g;
+  GCM_init(&g,K->val,IV->len,IV->val);
+  GCM_add_header(&g,H->val,H->len);
+  GCM_add_cipher(&g,P->val,C->val,C->len);
+  P->len=C->len;
+  GCM_finish(&g,T->val);
+  T->len=16;
+}
+
+/*!  \brief Get today's date as days from the epoch
+ *
+ *   @return today's date, as number of days elapsed since the epoch
+ */
+unsign32 WCC_today(void)
+{
+  unsign32 ti=(unsign32)time(NULL);
+  return (long)(ti/(60*TIME_SLOT_MINUTES));
+}
+
+/*!  \brief Initialise a random number generator
+ *
+ *   @param RNG     cryptographically secure random number generator
+ *   @param SEED    random seed value
+ */
+void WCC_CREATE_CSPRNG(csprng *RNG,octet *SEED)
+{
+  RAND_seed(RNG,SEED->len,SEED->val);
+}
+
+/*!  \brief Kill a random number generator
+ *   
+ *   Deletes all internal state
+ * 
+ *   @param RNG    cryptographically secure random number generator
+ */
+void WCC_KILL_CSPRNG(csprng *RNG)
+{
+  RAND_clean(RNG);
+}
+
+/*!  \brief Perform sha256
+ *   
+ *   Hash ID
+ * 
+ *   @param  ID     Value to hash
+ *   @return HID    sha256 hashed value
+ */
+void WCC_HASH_ID(octet *ID,octet *HID)
+{
+  hashit(0,ID,HID);
+}
+
+/*!  \brief Generate a random integer
+ *   
+ *   Generate a random number modulus the group order
+ * 
+ *   @param  RNG    cryptographically secure random number generator
+ *   @return S      Random integer modulus the group order
+ */
+int WCC_RANDOM_GENERATE(csprng *RNG,octet* S)
+{
+  BIG r,s;
+  BIG_rcopy(r,CURVE_Order);
+  BIG_randomnum(s,r,RNG);
+  BIG_toBytes(S->val,s);
+  S->len=PGS;
+  return 0;
+}
+
+
+/*! \brief Calculate time permit in G2 
+ *
+ *  Calculate time permit in G2. 
+ * 
+ *  <ol>
+ *  <li> TPG1=s*H1(date|sha256(ID))
+ *  </ol>
+ *
+ *  @param  date      Epoch days
+ *  @param  S         Master secret
+ *  @param  HID       sha256(ID)
+ *  @param  TPG1      Time Permit in G1
+ *  @return rtn       Returns 0 if successful or else an error code  
+ */
+int WCC_GET_G1_PERMIT(int date,octet *S,octet *HID,octet *TPG1)
+{
+  BIG s;
+  ECP P;
+  char h[HASH_BYTES];
+  octet H={0,sizeof(h),h};
+
+  hashit(date,HID,&H);
+  mapit(&H,&P);
+  BIG_fromBytes(s,S->val);
+  PAIR_G1mul(&P,s);
+
+  ECP_toOctet(TPG1,&P);
+  return 0;
+}
+
+/*! \brief Add two members from the group G1
+ *
+ *   @param  R1      member of G1 
+ *   @param  R2      member of G1 
+ *   @return R       member of G1 = R1+R2
+ *   @return         Returns 0 if successful or else an error code
+ */
+int WCC_RECOMBINE_G1(octet *R1,octet *R2,octet *R)
+{
+  ECP P,T;
+  int res=0;
+  if (!ECP_fromOctet(&P,R1)) res=WCC_INVALID_POINT;
+  if (!ECP_fromOctet(&T,R2)) res=WCC_INVALID_POINT;
+  if (res==0)
+  {
+    ECP_add(&P,&T);
+    ECP_toOctet(R,&P);
+  }
+  return res;
+}
+
+/*! \brief Add two members from the group G2
+ *
+ *   @param  W1      member of G2 
+ *   @param  W2      member of G2 
+ *   @return W       member of G2 = W1+W2
+ *   @return         Weturns 0 if successful or else an error code
+ */
+int WCC_RECOMBINE_G2(octet *W1,octet *W2,octet *W)
+{
+  ECP2 Q,T;
+  int res=0;
+  if (!ECP2_fromOctet(&Q,W1)) res=WCC_INVALID_POINT;
+  if (!ECP2_fromOctet(&T,W2)) res=WCC_INVALID_POINT;
+  if (res==0)
+  {
+    ECP2_add(&Q,&T);
+    ECP2_toOctet(W,&Q);
+  }
+  return res;
+}
diff --git a/c/wcc.h b/c/wcc.h
new file mode 100755
index 0000000..1f4bfad
--- /dev/null
+++ b/c/wcc.h
@@ -0,0 +1,98 @@
+/*
+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.
+*/
+
+/*
+ *  AMCL Wang / Chow Choo (WCC)  header file
+ */
+
+#ifndef WCC_H
+#define WCC_H
+
+#include "amcl.h"
+
+/* Field size is assumed to be greater than or equal to group size */
+
+#define PGS 32  /* WCC Group Size */
+#define PFS 32  /* WCC Field Size */
+#define PAS 16  /* AES Symmetric Key Size */
+
+#define WCC_OK                     0
+#define WCC_INVALID_POINT         -51
+
+
+
+#define TIME_SLOT_MINUTES 1440 /* Time Slot = 1 day */
+#define HASH_BYTES 32
+
+/*! \brief Generate a random integer */
+DLL_EXPORT int WCC_RANDOM_GENERATE(csprng *RNG,octet* S);
+
+/*! \brief Hash EC Points and Id to an integer */
+DLL_EXPORT void WCC_Hq(octet *A,octet *B,octet *C,octet *D,octet *h);
+
+/*! \brief Calculate value in G2 multiplied by an integer */
+DLL_EXPORT int WCC_GET_G2_MULTIPLE(int hashDone,octet *S,octet *ID,octet *VG2);
+
+/*! \brief Calculate value in G1 multiplied by an integer */
+DLL_EXPORT int WCC_GET_G1_MULTIPLE(int hashDone,octet *S,octet *ID,octet *VG1);
+
+/*! \brief Calculate a value in G1 used for when time permits are enabled */
+DLL_EXPORT int WCC_GET_G1_TPMULT(int date, octet *S,octet *ID,octet *VG1);
+
+/*! \brief Calculate a value in G2 used for when time permits are enabled */
+DLL_EXPORT int WCC_GET_G2_TPMULT(int date, octet *S,octet *ID,octet *VG2);
+
+/*! \brief Calculate time permit in G2 */
+DLL_EXPORT int WCC_GET_G1_PERMIT(int date,octet *S,octet *HID,octet *G1TP);
+
+/*! \brief Calculate time permit in G2 */
+DLL_EXPORT int WCC_GET_G2_PERMIT(int date,octet *S,octet *HID,octet *G2TP);
+
+/*! \brief Calculate the sender AES key */
+DLL_EXPORT int WCC_SENDER_KEY(int date, octet *xOct, octet *piaOct, octet *pibOct, octet *PbG2Oct, octet *PgG1Oct, octet *AKeyG1Oct, octet *ATPG1Oct, octet *IdBOct, octet *AESKeyOct);
+
+/*! \brief Calculate the receiver AES key */
+DLL_EXPORT int WCC_RECEIVER_KEY(int date, octet *yOct, octet *wOct,  octet *piaOct, octet *pibOct,  octet *PaG1Oct, octet *PgG1Oct, octet *BKeyG2Oct,octet *BTPG2Oct,  octet *IdAOct, octet *AESKeyOct);
+
+/*! \brief Encrypt data using AES GCM */
+DLL_EXPORT void WCC_AES_GCM_ENCRYPT(octet *K,octet *IV,octet *H,octet *P,octet *C,octet *T);
+
+/*! \brief Decrypt data using AES GCM */
+DLL_EXPORT void WCC_AES_GCM_DECRYPT(octet *K,octet *IV,octet *H,octet *C,octet *P,octet *T);
+
+/*!  \brief Perform sha256 */
+DLL_EXPORT void WCC_HASH_ID(octet *,octet *);
+
+/*! \brief Add two members from the group G1 */
+DLL_EXPORT int WCC_RECOMBINE_G1(octet *,octet *,octet *);
+
+/*! \brief Add two members from the group G2 */
+DLL_EXPORT int WCC_RECOMBINE_G2(octet *,octet *,octet *);
+
+/*! \brief Get today's date as days from the epoch */
+DLL_EXPORT unsign32 WCC_today(void);
+
+/*! \brief Initialise a random number generator */
+DLL_EXPORT void WCC_CREATE_CSPRNG(csprng *,octet *);
+
+/*! \brief Kill a random number generator */
+DLL_EXPORT void WCC_KILL_CSPRNG(csprng *RNG);
+
+
+#endif
diff --git a/docs/AMCL.dox b/docs/AMCL.dox
index ee206be..8cd39ec 100755
--- a/docs/AMCL.dox
+++ b/docs/AMCL.dox
@@ -109,7 +109,7 @@
 <p>The build can be configured using by setting flags on the command line i.e.</p>
 
 <ol type="disc">
-  <li>cmake -DWORD_LENGTH=64 ..</li>
+  <li>cmake  -D CMAKE_INSTALL_PREFIX=/opt/amcl -D WORD_LENGTH=64 ..</li>
 </ol>
 
 <h2>Uninstall software</h2>
diff --git a/docs/latex/README.txt b/docs/latex/README.txt
new file mode 100644
index 0000000..ad1c410
--- /dev/null
+++ b/docs/latex/README.txt
@@ -0,0 +1,3 @@
+latex amcl.tex
+dvips -Ppdf -G0 amcl.dvi
+ps2pdf  amcl.ps
diff --git a/docs/latex/amcl.bib b/docs/latex/amcl.bib
new file mode 100644
index 0000000..3d6d22e
--- /dev/null
+++ b/docs/latex/amcl.bib
@@ -0,0 +1,156 @@
+@misc{aranha-karabina-longa-gebotys-lopez,

+	author = "D.~F.~Aranha and K.~Karabina and P.~Longa and C.~H.~ Gebotys and J.~Lopez",

+	title = "Faster Explicit Formulae for Computing Pairings over Ordinary Curves",

+	year = "2010",

+	howpublished = "Cryptology ePrint Archive, Report 2010/526",

+	note = {\url{http://eprint.iacr.org/2010/526}},

+}

+

+@misc{bernstein-chuengsatiansup-lange,

+    author = {Daniel J. Bernstein and Chitchanok Chuengsatiansup and Tanja Lange},

+    title = {Curve41417: Karatsuba revisited},

+    howpublished = {Cryptology ePrint Archive, Report 2014/526},

+    year = {2014},

+    note = {\url{http://eprint.iacr.org/2014/526}},

+}

+

+@article{montgomery,

+	author={Peter L. Montgomery},

+	title={Modular Multiplication Without Trial Division},

+	journal={Mathematics of Computation},

+	volume="44",

+	number="170",

+	pages="519–-521",

+	year="1985"

+}

+

+@misc{bos-costello-longa-naehrig,

+    author = {Joppe W. Bos and Craig Costello and Patrick Longa and Michael Naehrig},

+    title = {Selecting Elliptic Curves for Cryptography: An Efficiency and Security Analysis},

+    howpublished = {Cryptology ePrint Archive, Report 2014/130},

+    year = {2014},

+    note = {\url{http://eprint.iacr.org/2014/130}},

+}

+

+@misc{bernstein-duif-lange-schwabe-yang,

+    author = {Daniel J. Bernstein and Niels Duif and Tanja Lange and Peter Schwabe and Bo-Yin Yang},

+    title = {High-speed high-security signatures},

+    howpublished = {Cryptology ePrint Archive, Report 2011/368},

+    year = {2011},

+    note = {\url{http://eprint.iacr.org/2011/368}},

+}

+

+@misc{tss,

+	author="Tangible Software Solutions",

+	note={\url{http://www.tangiblesoftwaresolutions.com/}},

+}

+

+@misc{ml,

+	author="A.~ Miele and A.~K.~Lenstra",

+	title = "Efficient ephemeral elliptic curve cryptographic keys",

+	year="2015",

+	note={\url{http://csrc.nist.gov/groups/ST/ecc-workshop-2015/papers/session1-miele-paper.pdf}},

+}

+

+@misc{gol,

+	author="Google j2objc",

+	note={\url{https://github.com/google/j2objc}},

+}

+

+@Inproceedings{bernstein,

+	author={Daniel J. Bernstein},

+	title={Curve25519: new {D}iffie-{H}ellman speed records},

+	booktitle="PKC 2006", 

+	pages="207--228", 

+	publisher="Springer-Verlag",

+	series = "Lecture Notes in Computer Science",

+	volume="3958",

+	year="2006"

+}

+

+@misc{nist,

+	author="National Institute for Standards and Technology",

+	title="Federal Information Processing Standards Publication 186-2",

+	year="2000",

+	note = {\url{http://csrc.nist.gov/publications/fips/archive/fips186-2/fips186-2.pdf}},

+}

+

+@misc{mpin,

+	author="M. ~Scott",

+	title= "M-{P}in: A Multi-Factor Zero Knowledge Authentication Protocol",

+	year="2014",

+	note={\url{http://www.miracl.com/crypto-labs}},

+}

+

+@Inproceedings{barreto-naehrig,

+	author="P.S.L.M.~Barreto and M.~Naehrig",

+	title="Pairing-Friendly elliptic curves of prime order", 

+	booktitle="Selected Areas in Cryptology -- {SAC} 2005", 

+	pages="319--331", 

+	publisher="Springer-Verlag",

+	series = "Lecture Notes in Computer Science",

+	volume= "3897", 

+	year="2006",

+}

+

+@book{knuth,

+ author = {Knuth, Donald E.},

+ title = {The Art of Computer Programming, Volume 2 (3rd Ed.): Seminumerical Algorithms},

+ year = {1997},

+ isbn = {0-201-89684-2},

+ publisher = {Addison-Wesley Longman Publishing Co., Inc.},

+} 

+

+

+

+@Inproceedings{scott,

+	author="M.~ Scott",

+	title= "Implementing Cryptographic Pairings",

+	booktitle="Pairing 2007",

+	pages="177--196",

+	year="2007",

+	series = "Lecture Notes in Computer Science",

+	volume= "4575"

+}

+

+@article{montgomery2,

+	author={Peter L. Montgomery},

+	title="Speeding the {P}ollard and Elliptic Curve Methods of Factorisation",

+	journal={Mathematics of Computation},

+	volume="48",

+	number="177",

+	pages="243–-264",

+	year="1987"

+}

+

+@misc{bernstein-lange,

+    author = {Daniel J. Bernstein and Tanja Lange},

+    title = {Inverted {E}dwards coordinates},

+    howpublished = {Cryptology ePrint Archive, Report 2007/410},

+    year = {2007},

+    note = {\url{http://eprint.iacr.org/2007/410}},

+}

+

+@misc{brainpool,

+	author="Brainpool",

+	title="{ECC} Brainpool standard curves and curve generation.",

+	year={2005},

+	note={\url{http://www.ecc-brainpool.org/download/Domain-parameters.pdf}},

+}

+

+@misc{ANSSI,

+	author="{ANSSI}",

+	title="Publication d'un paramétrage de courbe elliptique visant des applications de passeport électronique et de l'administration électronique française.",

+	year={2011},

+	note={\url{http://www.legifrance.gouv.fr/affichTexte.do?cidTexte=JORFTEXT000024668816}},

+}

+

+@misc{certicom,

+	author="Certicom",

+	title="SEC 2: Recommended Elliptic Curve Domain Parameters, Version 2.0",

+	year={2010},

+	note={\url{ http://www.secg.org/download/aid-784/sec2-v2.pdf }},

+}

+

+

+

diff --git a/docs/latex/amcl.tex b/docs/latex/amcl.tex
new file mode 100644
index 0000000..2f897a2
--- /dev/null
+++ b/docs/latex/amcl.tex
@@ -0,0 +1,416 @@
+\documentclass{llncs}

+\usepackage{amsmath,amssymb,url}

+\usepackage{algorithm}

+\usepackage{algpseudocode}

+\usepackage{graphicx}

+\usepackage{mathcomp}

+

+\newcommand{\Cyc}{\mathrm{\Phi}}

+\newcommand{\Frob}{\mathrm{\Phi}}

+\newcommand{\twist}{\mathrm{\Psi}}

+\newcommand{\F}{\mathbb{F}}

+\newcommand{\half}[1]{{\lfloor#1/2\rfloor}}

+\newcommand{\ord}{\qopname\relax{no}{ord}}

+\newcommand{\sign}{\qopname\relax{no}{sign}}

+\newcommand{\tr}{\qopname\relax{no}{tr}}

+\newcommand{\Z}{\mathbb{Z}}

+\newcommand{\Cpp}{C\kern-0.05em\texttt{+\kern-0.03em+}}

+\newcommand{\pp}{\,\kern-0.05em\texttt{+\kern-0.031em+}}

+\newcommand\T{\rule{0pt}{2.6ex}}

+

+\newcommand{\Input}{\item[\textsc{Input:}]}

+\newcommand{\Output}{\item[\textsc{Output:}]}

+

+\sloppy

+

+\begin{document}

+

+\pagestyle{plain}

+

+\title{The Apache Milagro Crypto Library}

+

+\author{

+Michael Scott 

+}

+

+\institute{}

+

+\institute{

+%Chief Cryptographer \\

+MIRACL Labs\\%

+%\bf{For Internal Distribution Only} \\

+\email{mike.scott@miracl.com} \\

+}

+

+\maketitle

+

+\begin{abstract}

+

+We introduce a new multi-lingual crypto library, specifically designed to support the Internet of Things.

+

+\end{abstract} 

+

+\section{Introduction}\label{sec:intro}

+

+%One of the major mysteries in the real-world of crypto is resistance to the exploitation of new research ideas. Its not that cryptographic research has failed to throw up new ideas that have

+%the potential for commercial exploitation -- far from it. But in the real-world 1970's crypto rules supreme, and very little happens that isn't PKI/RSA based. The reasons for this are many and varied.

+%However one part of the puzzle might be the non-availability of easy-to-use open source cryptographic tools, that do not require in depth cryptographic expertise to deploy.

+

+%In particular 

+There are many crypto libraries out there. Many offer a bewildering variety of cryptographic primitives, at different levels of security. Many use extensive assembly language 

+in order to be as fast as possible. Many are very big, even bloated. Some rely on other external libraries. Many were designed by academics for academics, and so are not really suitable for 

+commercial use. Many are otherwise excellent, but not written in our favourite language.

+

+The Apache Milagro Crypto Library (AMCL) \footnote{\url{https://github.com/MIRACL/amcl.git}} is different. AMCL is completely self-contained (except for the requirement for an external entropy source for random number generation). AMCL is for use in 

+the pre-quantum era -- that is in the here and now. With 

+the advent of a workable quantum computer, AMCL will become history. But we are not expecting that to happen any time soon.

+

+AMCL is portable -- there is no assembly language. The original version is written in C, Java, Javascript, Go and Swift using only generic programming constructs, but AMCL is truly 

+multi-lingual, as compatible 

+versions will be available in many other languages (see below). These versions will be identical in that for the same inputs they will not only produce the same outputs, but all internal calculations will also be the same. 

+AMCL is fast, but does not attempt to set speed records (a particular academic obsession). There are of course contexts where speed is of the essence -- for example for a server farm which must handle 

+multiple SSL connections, and where a 10\% speed increase implies the need for 10\% less servers, with a a 10\% saving on electricity. But in the Internet of Things we would suggest that this is less 

+important. In general the speed

+is expected to be ``good enough''. However AMCL is small. Some libraries boast of having hundreds of thousands of lines of code - AMCL has less than 10,000. AMCL takes up the minimum of 

+ROM/RAM resources in order to fit into the smallest possible embedded footprint, consistent with other design constraints. It is expected that this will be vital for implementations that 

+support security in the Internet of Things. AMCL (the C version) only uses stack memory, and is thus natively multi-threaded.

+

+Only one level of security is supported, equivalent to 128-bit AES. This is the current standard level for cryptography that is expected to be unbreakable. As a justification we could not 

+improve on that given by Miele and Lenstra \cite{ml} -- ``With 128-bit security more than sufficient for the foreseeable future, it is not 

+clear either what purpose is served by higher security levels, other than catering 

+to “TOP SECRET” 192-bit security ..... In this context it is interesting to 

+note that 256-bit AES, also prescribed ...... for “TOP SECRET”, was introduced 

+only to still have a 128-bit secure symmetric cipher in the post-quantum world 

+......, and that 192-bit security was merely a side-effect that resulted from 

+the calculation (128+256)/2 ....... In that world ECC is obsolete anyhow.''

+

+

+AMCL makes most 

+of the choices for you as to which primitives to use, based on the best available current advice. Specifically it uses AES-128 for symmetric encryption, SHA256 for hashing, 256-bit prime field elliptic

+curves for public key protocols, and 256-bit BN curves to support pairing-based protocols. However three different parameterizations of Elliptic curve are supported - Weierstrass, Edwards and 

+Montgomery, as each is appropriate within its own niche. In each case only the standard projective coordinates are used. But you do get to 

+choose the actual elliptic curve, with support for three different 

+forms of the modulus. For pairings we assume a modulus congruent to $3 \bmod 8$ with a D-type twist, parameterized by a negative $x$ value \cite{barreto-naehrig}.

+Standard modes of AES are supported, plus GCM mode for authenticated encryption.

+

+The C version of AMCL is configured at compile time for 16, 32 or 64 bit processors, and for a specific elliptic curve. The Java and Javascript versions are (obviously) processor agnostic, 

+but the same choices of elliptic curve are available.

+

+AMCL is written with an awareness of the abilities of modern pipelined processors. In particular there was an awareness that the unpredictable program branch should be avoided at all costs, not 

+only as it slows down the processor, but as it may open the door to side-channel attacks. The innocuous looking {\tt if} statement -- unless its outcome can be accurately predicted -- is the enemy 

+of quality crypto software.

+

+In the sequel we refer to the C version of AMCL, unless otherwise specified. We emphasis that all AMCL versions are completely self-contained. No external 

+libraries or packages are required to implement all of the supported cryptographic functionality (other than for an external entropy source).

+

+\section{Context}

+

+A crypto library does not function is isolation. The AMCL was originally designed to support the MIRACL IoT solution. The MIRACL IoT solution is based on a cloud-based infrastructure designed by MIRACL 

+to support the M-Pin protocol \cite{mpin}, but which has wider application to novel protocols of particular relevance to the IoT. This document describes the AMCL library which was originally designed for internal use, 

+but which has now reached a level of maturity where we are pleased to make it available as a service to the wider community as an open source product, under a standard Apache 2.0 license.

+

+\section{Library Structure}

+

+The modules that make up AMCL are shown below, with some indication of how they interact. Several example APIs will be provided to implement common protocols. Note that all

+interaction with the API is via machine-independent endian-indifferent arrays of bytes (a.k.a. octet strings). 

+Therefore the underlying workings of the library are invisible to the consumer of its services.

+

+\begin{figure}[!htb]

+  \begin{center}

+    \includegraphics[width=120mm ]{clint.eps}

+  \end{center}

+  \caption{\small The AMCL library.}

+  \label{clint}

+\end{figure}

+

+The symmetric encryption and hashing code, along with the random number generation, is uninteresting, and since we make no claims for it, we will not refer to it again. It was mostly

+borrowed from our well-known MIRACL library.

+

+\section{Handling 256-bit Numbers}

+

+\subsection{Representation}

+

+One of the major design decisions is how to represent the 256-bit field elements required for the elliptic curve and pairing-based cryptography. Here there are two different approaches. 

+One is to pack the bits as tightly as possible into computer words. For example on a 64-bit computer 256-bit numbers can be stored in just 4 words. However to manipulate numbers in this 

+form, even for simple addition, requires handling of carry bits if overflow is to be avoided, 

+and a high-level language does not have direct access to carry flags. It is possible to emulate the flags, but this would be inefficient. In fact this approach is only really suitable 

+for an assembly language implementation.

+

+The alternative idea is to use extra words for the representation, and then try to offset the additional cost by taking full advantage of the ``spare'' bits in every word. 

+This idea follows a ``corner of the literature'' \cite{bernstein-chuengsatiansup-lange} which has been promoted by Bernstein and his collaborators in several publications.

+Refer to figure \ref{words}, where each digit of the representation is stored as a signed integer which is the size of the processor word-length. 

+

+

+Note that almost all arithmetic takes place modulo a 256-bit prime number, the modulus representing the field over which the elliptic curve is defined, here denoted as $p$.

+

+On 64-bit processors, AMCL represents numbers to the base $2^{56}$ in a 5 element array, the Word Excess is 7 bits, and for a 256-bit modulus the Field Excess is 24 bits

+

+On 32-bit processors, AMCL represents numbers to the base $2^{29}$ in a 9 element array, the Word Excess is 2 bits, and for a 256-bit modulus the Field Excess is 5 bits

+

+On 16-bit processors, AMCL represents numbers to the base $2^{13}$ in a 20 element array, the Word Excess is 2 bits, and for a 256-bit modulus the Field Excess is 4 bits

+

+Such a representation of a 256-bit number is referred to as a {BIG}. Addition or subtraction of a pair of {BIG}s, results in another {BIG}.

+

+The Java version uses exactly the same 32-bit representation as above. For Javascript (where all numbers are stored as 64-bit floating point with a 52-bit mantissa, but mostly 

+manipulated as 32-bit integers), numbers

+are represented to the base $2^{24}$ in an 11 element array, the Word Excess is 7 bits, and the Field Excess for a 256-bit modulus is 8 bits. 

+

+\subsection{Addition and Subtraction}

+

+The existance of a word excess means for example that multiple field elements can be added together digit by digit, without processing of carries, before overflow can occur. 

+Only occasionally will there be a requirement to {\it normalise} these {\it extended} values,  that is to force them back into the original format. Note that this is independent of the modulus.

+

+The existance of a field excess means that, independent of the word excess, multiple field elements can be added together before it is required to reduce the sum with respect to the modulus. In the 

+literature this is referred to as lazy, or delayed, reduction. In fact we allow the modulus to be as small as 254 bits, which obviously increases the field excess.

+

+Note that these two mechanisms associated with the word excess and the field excess (often confused in the literature) operate largely independently of each other.

+

+AMCL has no support for negative numbers. Therefore subtraction will be implemented as field negation followed by addition. Negation is performed using the method described as 

+Option 1 in \cite{aranha-karabina-longa-gebotys-lopez}. Basically the 

+number of the active bits in the field excess of the number to be negated is determined, the modulus is shifted left by this amount plus one, and the value to be negated is subtracted from this value.

+Note that because of the ``plus 1'', this will always produce a positive result at the cost of eating a bit into the field excess.

+

+\begin{figure}[!htb]

+  \begin{center}

+    \includegraphics[width=120mm ]{words.eps}

+  \end{center}

+  \caption{\small 256-bit number representation}

+  \label{words}

+\end{figure}

+

+Normalisation of extended numbers requires the word excess of each digit to be shifted right by the number of base bits, and added to the next digit, working right to left. Note that when numbers 

+are subtracted digit-by-digit individual digits may become negative. However

+since we are avoiding using the sign bit, due to the magic of 2's complement arithmetic, this all works fine without any conditional branches.

+

+Reduction of unreduced BIG numbers is carried out using a simple shift-compare-and-subtract of the modulus, with one subtraction needed on average half of the time for every active bit in the field excess. 

+Hopefully such reductions will rarely be required, as they are slow and involve unpredictable program branches.

+

+Since the length of field elements is fixed at compile time, it is expected that the compiler will unroll most of the time-critical loops. In any case the conditional branch required at the foot of a 

+fixed-size loop can be accurately predicted by modern hardware.

+

+The problem now is to decide when to normalise and when to reduce numbers to avoid the possibility of overflow. There are two ways of doing this. One is to monitor the excesses at run-time and act when the 

+threat of overflow arises. The second is to do a careful analysis of the code and insert normalisation and reduction code at points where the possibility of overflow may arise, based on a static worst-case 

+analysis. 

+

+The field excess $E_n$ of a number $n$ is easily captured by a simple masking and shifting of the top word. If two normalised numbers $a$ and $b$ are to be added then the excess of their sum will be at worst 

+$E_a + E_b +1$. As long as this is less than $2^{FE}$ where $FE$ is the field excess, then we are fine. Otherwise both numbers should be reduced prior to the addition. In AMCL these checks are 

+performed at run-time. However, as we shall see, in practise these reductions are very rarely required. So the {\tt if} statement used to control them is highly predictable. Observe that even

+in the worst case, for a 16-bit implementation, the excess is a generous $FE=4$, and so many elements can be added or subtracted before reduction is required.

+

+The worst case word excess for the result of a calculation is harder to calculate at run time, as it would require inspection of every digit of every {BIG}. This would slow computation down to an unacceptable extent. 

+Therefore in this case

+we use static analysis and insert normalisation code where we know it might be needed. This process was supported by special debugging code that warned of places where overflow was possible, based on a simple

+worst-case analysis.

+

+\subsection{Multiplication and Reduction}

+

+To support multiplication of {BIG}s, we will require a double-length {DBIG} type. Also the partial products that arise in the process of long multiplication will require a double-length data type. Fortunately many 

+popular C compilers, like Gnu {GCC}, always support an integer type that is double the native word-length. For Java the ``int'' type is 32-bits and there is a double-length ``long'' type which is 64-bit.

+Of course for Javascript a double length type is not possible, and so the partial products must be accomodated within the 52-bit mantissa.

+

+It is generally accepted that the fastest way to do multi-precision multiplication is to accumulate the double-length partial products that contribute to each column in the classic school-boy long multiplication

+algorithm, also known as the Comba method. Then at the foot of the column the total is split into the sum for that column, and the carry to the next column, working right-to-left. If the numbers are normalised 

+prior to the multiplication, then 

+with the word excesses that we have chosen, this will not result in overflow. The {DBIG} product will be automatically normalised as a result of this process. Squaring can be done in a 

+similar fashion, but only requires just over half of the number of partial products, and so it may be somewhat faster.

+

+The {DBIG} value that results from a multiplication or squaring may be immediately reduced with respect to the modulus to bring it back to a {BIG}. However again we may choose to delay this 

+reduction, and therefore we need the ability to safely add and subtract DBIG numbers while again avoiding overflow.

+

+The method used for full reduction of a DBIG back to a BIG depends on the form of the modulus. We choose to support three distinct types of modulus, (a) pseudo Mersenne of the form $2^n-c$ where 

+$c$ is small and $n$ is the size of the modulus in bits, 

+(b) Montgomery-friendly of the form $k.2^n-1$, and (c) moduli of no special form. For cases (b) and (c) we convert all 

+field elements to Montgomery's {\it n}-residue form, and use Montgomery's fast method for modular reduction \cite{montgomery}. In all cases the DBIG number to be reduced $y$ must be in the 

+range $0<y<pR$ (a requirement of Montgomery's method), and the result $x$ is guaranteed to 

+be in the range $0<x<2p$, where $R=2^{256+FE}$ for a 256-bit modulus. Note that the BIG result will be (nearly) fully reduced. The fact than we allow $x$ to be larger than $p$ means that we can avoid

+the notorious Montgomery ``final subtraction'' \cite{montgomery}.

+

+Observe how unreduced numbers involved in complex calculations tend to be (nearly fully) reduced if they are involved in a modular multiplication. So for example if field element $x$ has a large field excess,

+and if we calculate $x=x.y$, then as long as the unreduced product is less than $pR$, the result will be a nearly fully reduced $x$. So in many cases there is a natural tendency for field excesses 

+not to grow without limit, and not to overflow, without requiring explicit action on our part.

+

+Consider now a sequence of code that adds, subtracts and multiplies field elements, as might arise in elliptic curve additions and doublings. Assume that the code has been analysed and that normalisation 

+code has been inserted where needed. Assume that the reduction code that 

+activates if there is a possibility of an element overflowing its field excess, while present, never in fact is triggered (due to the behaviour described above). Then we assert that there is only one 

+possible place in which an unpredicted branch may occur. This will be in the negation code associated with a subtraction, where the number of bits in the field excess must be counted. However we would 

+point out that some architectures do now support machine code instructions that count the number of active bits in a computer register -- although unfortunately this capability is not supported by the 

+typical high-level language syntax.

+

+\section{Extension Field arithmetic}

+

+To support cryptographic pairings we will need support for extension fields. We use a towering of extensions, from $\F_p$ to $\F_{p^2}$ to $\F_{p^4}$ to $\F_{p^{12}}$ as required for 

+BN curves \cite{barreto-naehrig}. An element 

+of the quadratic extension field will be represented as $f=a+ib$, where $i$ is the square root of the quadratic non-residue -1.

+To add, subtract and multiply them we use the obvious methods. However for negation we can construct $-f=-a-ib$ as $b-(a+b)+i.(a-(a+b)$ which requires only one base field negation. A similar idea 

+can be used recursively for higher order extensions, so that only one base field negation is ever required.

+

+

+\section{Elliptic Curves}

+

+Three types of Elliptic curve are supported for the implementation of Elliptic Curve Cryptography (ECC), but curves are limited to popular families that support faster implementation. Weierstrass 

+curves are supported using the Short Weierstrass representation:-

+

+$$ y^2=x^3+Ax+B $$

+

+where $A=0$ or $A=-3$. Edwards curves are supported using both regular and twisted Edwards format:-

+

+$$ Ax^2+y^2=1+Bx^2y^2 $$

+

+where $A=1$ or $A=-1$. Montgomery curves are represented as:-

+

+$$ y^2=x^3+Ax^2+x $$

+

+where $A$ must be small.

+

+In the particular case of elliptic curve point multiplication, there are potentially a myriad of very dangerous side-channel attacks that arise from using the classic double-and-add algorithm

+and its variants. Vulnerabilities arise if branches are taken that depend on secret bits, or if data is even accessed using secret values as indices.

+Many types of counter-measures have been suggested. The simplest solution is to use a constant-time algorithm like the Montgomery ladder, which has a very simple structure, uses very little 

+memory and has no key-bit-dependent branches. 

+If using a Montgomery representation of the elliptic curve the Montgomery ladder \cite{montgomery2} is in fact the optimal algorithm for point multiplication. For other representations we use a 

+fixed-sized signed window method, as described in \cite{bos-costello-longa-naehrig}. 

+

+AMCL has built-in support for most standardised elliptic curves, along with many curves that have been proposed for standardisation at our chosen level of security. 

+Specifically it supports the NIST curve \cite{certicom}, \cite{nist}, the well known Curve25519 \cite{bernstein}, the 256-bit Brainpool curve \cite{brainpool}, the ANSSI curve \cite{ANSSI}, and four

+NUMS (Nothing-Up-My-Sleeve) curves proposed by Bos et al. \cite{bos-costello-longa-naehrig}. Some of these proposals support only a Weierstrass representation, but many also allow an Edwards and Montgomery 

+form. Tools are provided to allow easy integration of more curves.

+

+

+\section{Support for classic Finite Field Methods}

+

+Before Elliptic Curves, cryptography depended on methods based on simple finite fields. The most famous of these would be the well known RSA method. These methods have the advantage of

+being effectively parameterless, and therefore the issue of trust in parameters that arises for elliptic curves, is not an issue. However these methods are subject to index calculus based

+methods of cryptanalysis, and so fields and keys are typically much larger. So how to support for example a 2048-bit implementation of RSA based on a library designed for optimized 256-bit operations? The idea is simple --

+use AMCL as a virtual 256-bit machine, and build 2048-bit arithmetic on top of that. And to claw back some decent performance use the Karatsuba method \cite{knuth} so that for example 2048-bit multiplication

+recurses efficiently right down to 256-bit operations. Of course the downside of the Karatsuba method is that while it saves on multiplications, the number of additions and subtractions is greatly increased.

+However the existance of generous word excesses in our representation makes this less of a problem, as most additions can be carried out without normalisation. 

+

+Secret key operations like RSA decryption use the Montgomery ladder to achieve side-channel-attack resistance.

+

+The implementation can currently support $1024.2^n$ bit fields, so for example 2048-bit RSA can be used to get reasonably close to the AES-128-bit level of security, and if desired 4096 bit RSA can be used to

+comfortably exceed it. 

+

+Note that this code is supported independently of the elliptic curve code. So for example RSA and ECC can be run together within a single application. 

+

+However we regard these methods as ``legacy'' as in our view ECC based methods are a much better fit for the IoT. 

+

+\section{Multi-Lingual support}

+

+It is a big ask to develop and maintain multiple versions of a crypto library written in radically different languages such as C, Java, Javascript, Go and Swift. This has discouraged the use of

+language specific methods (which are in any case of little relevance here), and strongly encouraged the use of simple, generic computer language constructs. 

+

+This approach brings a surprising bonus: AMCL can be automatically converted to many other languages using available translator tools. For example Tangible Software Solutions \cite{tss}

+market a Java to C\# converter. This generated an efficient fully functional C\# version of AMCL within minutes. The same company market a Java to Visual Basic converter. 

+Google have a Java to Objective C

+converter \cite{gol} specifically designed to convert Android apps developed in Java, to iOS apps written in Objective C.

+

+Of course not all languages can be supported in this way, so support for some will be developed manually. In particular a Rust version is currently under development.

+

+

+\section{Discussion}

+

+We found in our code that, with few exceptions, reductions due to possible overflow of the field excess of a BIG were very rare, especially for the 64-bit version of the library. Similarly 

+normalisation was 

+rarely needed for the 64-bit code. This is due to the much greater excesses that apply in the 64-bit representation. In some experiments we calculated thousands of random pairings, 

+and reduction due to field excess overflow detection never happened.

+

+In general in developing AMCL we tried to use optimal methods, without going to what we (very subjectively) regarded as extremes in order to maximise performance. 

+Algorithms that require less memory were generally preferred if the impact on performance was not large. Some optimizations, while perfectly valid, are hard to 

+implement without having a significant impact on program readability and maintainability. Deciding which optimizations to use and which to reject (on the grounds of code size and negative impact on code 

+readability and maintainability) is admittedly rather arbitrary!

+

+One notable omission from AMCL is the use of precomputation on fixed parameters in order to speed up certain calculations. We try to justify this, rather unconvincingly, by pointing out 

+that precomputation must of necessity increase code size. Furthermore such methods are more sensitive to side-channel attacks and much of their speed advantage will be lost if they are to be 

+fully side-channel protected. Also precomputation on secret values clearly increases the amount of secret data that needs to be protected.

+However our view might change in later versions depending on our in-the-field experiences of using AMCL.

+

+%\newpage

+\bibliographystyle{plain}

+\bibliography{amcl}

+

+%\newpage

+\appendix

+

+\section*{Benchmarks}

+

+Since AMCL is intended for the Internet of Things, we think it appropriate to give some timings based on an implementation on the Raspberry Pi (version 2) computer, which is

+based on a 32-bit ARM7 chip. We do not overclock the 900MHz processor. 

+

+We developed three API programs, one which tests standard methods of elliptic curve key exchange, public key cryptography and digital signature. Another implements all components of our M-Pin protocol,

+a pairing-based protocol of medium complexity \cite{mpin}.  The former uses the ed25519 Edwards curve \cite{bernstein-duif-lange-schwabe-yang} with its pseudo-mersenne modulus, and the latter a BN curve.

+Finally we implement all the steps of the RSA public key encryption protocol using 2048-bit keys, that is key generation, encryption and decryption.

+

+These might be regarded as representative of what might be expected for an implementation of a typical elliptic curve (ECC) protocol, a typical pairing-based (PBC) protocol, and a typical classic 

+public key protocol based on RSA.

+The results in the first table indicate the code and stack requirements when these programs were compiled using version 4.8 of the GCC compiler, using the standard  -O3 (optimize for best performance) and -Os

+(optimize for minimum size) flags, and a flag to indicate the specific ARM architecture (Cortex-A7).

+

+

+\begin{table}

+\centering

+\begin{tabular}{|l|c|c|}

+\hline

+&~~Code Size~~&~Maximum Stack Usage~\\

+\hline

+~ECC  -O3 & 68085 & 4140  \\  %

+~ECC  -Os & 31115 & 3752 \\   %

+~PBC  -O3 & 84031 & 8140 \\   %

+~PBC  -Os & 46044 & 7904 \\   %

+~RSA  -O3 & 61461 & 5332 \\   %

+~RSA  -Os & 23449 & 5228 \\   %

+\hline

+\end{tabular}

+~\\

+\caption{Typical Memory Footprint}

+\label{footprint}

+\end{table}

+

+

+Next we give some timings for a single SPA-protected ECC point multiplication on an Edwards curve, for the calculation of a single PBC pairing on the BN curve, and for a SPA-protected 2048-bit RSA decryption.

+

+\begin{table}

+\centering

+\begin{tabular}{|l|c|}

+\hline

+&~Time in milliseconds~\\

+\hline

+~ECC point multiplication -O3 & 3.9  \\ % 

+~ECC point multiplication -Os & 5.9 \\ % 

+~PBC pairing -O3 & 47.4 \\ % 

+~PBC pairing -Os & 77.3 \\ % 

+~RSA decryption -O3 & 155 \\  %  

+~RSA decryption -Os & 233 \\  % 

+\hline

+\end{tabular}

+~\\

+\caption{C Benchmarks}

+\label{cspeed}

+\end{table}

+

+Observe that we do not compare these timings with any other -- because that is not the point.

+The point is -- are they ``good enough'' for whatever application you have in mind? And we suspect that, in the great majority of cases, they are.

+

+Clearly for Java and Javascript we are completely at the mercy of the efficiency (or otherwise) of the virtual machine. As can be seen from these Javascript timings, these

+can vary significantly.

+

+

+\begin{table}

+\centering

+\begin{tabular}{|l|l|l|c|}

+\hline

+ & ~Device~ & ~Browser~ &~Time in seconds~\\

+\hline

+~ECC point multiplication~  & ~Raspberry Pi~ & ~Epiphany~ & 0.65  \\

+  & ~Apple iPad 2~ & ~Safari~ & 0.096  \\

+  & ~Samsung Galaxy Note 4~ & ~Chrome~ & 0.018  \\

+~PBC pairing~  &  ~Raspberry Pi~ & ~Epiphany~ & 11.0\\

+ &  ~Apple iPad 2~ & ~Safari~ & 1.6\\

+ &  ~Samsung Galaxy Note 4~ & ~Chrome~ & 0.30\\

+\hline

+\end{tabular}

+~\\

+\caption{JavaScript Benchmarks}

+\label{jsspeed}

+\end{table}

+

+

+\end{document}

diff --git a/docs/latex/clint.eps b/docs/latex/clint.eps
new file mode 100644
index 0000000..ac8d8d0
--- /dev/null
+++ b/docs/latex/clint.eps
@@ -0,0 +1,682 @@
+%!PS-Adobe-2.0 EPSF-2.0

+%%Title: C:\Users\Shamus\Pictures\ngcl.dia

+%%Creator: Dia v0.97.2

+%%CreationDate: Thu Dec 04 10:27:13 2014

+%%For: Shamus

+%%Orientation: Portrait

+%%Magnification: 1.0000

+%%BoundingBox: 0 0 1109 740

+%%BeginSetup

+%%EndSetup

+%%EndComments

+%%BeginProlog

+[ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef

+/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef

+/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef

+/.notdef /.notdef /space /exclam /quotedbl /numbersign /dollar /percent /ampersand /quoteright

+/parenleft /parenright /asterisk /plus /comma /hyphen /period /slash /zero /one

+/two /three /four /five /six /seven /eight /nine /colon /semicolon

+/less /equal /greater /question /at /A /B /C /D /E

+/F /G /H /I /J /K /L /M /N /O

+/P /Q /R /S /T /U /V /W /X /Y

+/Z /bracketleft /backslash /bracketright /asciicircum /underscore /quoteleft /a /b /c

+/d /e /f /g /h /i /j /k /l /m

+/n /o /p /q /r /s /t /u /v /w

+/x /y /z /braceleft /bar /braceright /asciitilde /.notdef /.notdef /.notdef

+/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef

+/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef

+/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef

+/space /exclamdown /cent /sterling /currency /yen /brokenbar /section /dieresis /copyright

+/ordfeminine /guillemotleft /logicalnot /hyphen /registered /macron /degree /plusminus /twosuperior /threesuperior

+/acute /mu /paragraph /periodcentered /cedilla /onesuperior /ordmasculine /guillemotright /onequarter /onehalf

+/threequarters /questiondown /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla

+/Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth /Ntilde

+/Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply /Oslash /Ugrave /Uacute /Ucircumflex

+/Udieresis /Yacute /Thorn /germandbls /agrave /aacute /acircumflex /atilde /adieresis /aring

+/ae /ccedilla /egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis

+/eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide /oslash /ugrave

+/uacute /ucircumflex /udieresis /yacute /thorn /ydieresis] /isolatin1encoding exch def

+/cp {closepath} bind def

+/c {curveto} bind def

+/f {fill} bind def

+/a {arc} bind def

+/ef {eofill} bind def

+/ex {exch} bind def

+/gr {grestore} bind def

+/gs {gsave} bind def

+/sa {save} bind def

+/rs {restore} bind def

+/l {lineto} bind def

+/m {moveto} bind def

+/rm {rmoveto} bind def

+/n {newpath} bind def

+/s {stroke} bind def

+/sh {show} bind def

+/slc {setlinecap} bind def

+/slj {setlinejoin} bind def

+/slw {setlinewidth} bind def

+/srgb {setrgbcolor} bind def

+/rot {rotate} bind def

+/sc {scale} bind def

+/sd {setdash} bind def

+/ff {findfont} bind def

+/sf {setfont} bind def

+/scf {scalefont} bind def

+/sw {stringwidth pop} bind def

+/tr {translate} bind def

+

+/ellipsedict 8 dict def

+ellipsedict /mtrx matrix put

+/ellipse

+{ ellipsedict begin

+   /endangle exch def

+   /startangle exch def

+   /yrad exch def

+   /xrad exch def

+   /y exch def

+   /x exch def   /savematrix mtrx currentmatrix def

+   x y tr xrad yrad sc

+   0 0 1 startangle endangle arc

+   savematrix setmatrix

+   end

+} def

+

+/mergeprocs {

+dup length

+3 -1 roll

+dup

+length

+dup

+5 1 roll

+3 -1 roll

+add

+array cvx

+dup

+3 -1 roll

+0 exch

+putinterval

+dup

+4 2 roll

+putinterval

+} bind def

+/Times-Roman-latin1

+    /Times-Roman findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Times-Italic-latin1

+    /Times-Italic findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Times-Bold-latin1

+    /Times-Bold findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Times-BoldItalic-latin1

+    /Times-BoldItalic findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/AvantGarde-Gothic-latin1

+    /AvantGarde-Gothic findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/AvantGarde-BookOblique-latin1

+    /AvantGarde-BookOblique findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/AvantGarde-Demi-latin1

+    /AvantGarde-Demi findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/AvantGarde-DemiOblique-latin1

+    /AvantGarde-DemiOblique findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Bookman-Light-latin1

+    /Bookman-Light findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Bookman-LightItalic-latin1

+    /Bookman-LightItalic findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Bookman-Demi-latin1

+    /Bookman-Demi findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Bookman-DemiItalic-latin1

+    /Bookman-DemiItalic findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Courier-latin1

+    /Courier findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Courier-Oblique-latin1

+    /Courier-Oblique findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Courier-Bold-latin1

+    /Courier-Bold findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Courier-BoldOblique-latin1

+    /Courier-BoldOblique findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Helvetica-latin1

+    /Helvetica findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Helvetica-Oblique-latin1

+    /Helvetica-Oblique findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Helvetica-Bold-latin1

+    /Helvetica-Bold findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Helvetica-BoldOblique-latin1

+    /Helvetica-BoldOblique findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Helvetica-Narrow-latin1

+    /Helvetica-Narrow findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Helvetica-Narrow-Oblique-latin1

+    /Helvetica-Narrow-Oblique findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Helvetica-Narrow-Bold-latin1

+    /Helvetica-Narrow-Bold findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Helvetica-Narrow-BoldOblique-latin1

+    /Helvetica-Narrow-BoldOblique findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/NewCenturySchlbk-Roman-latin1

+    /NewCenturySchlbk-Roman findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/NewCenturySchlbk-Italic-latin1

+    /NewCenturySchlbk-Italic findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/NewCenturySchlbk-Bold-latin1

+    /NewCenturySchlbk-Bold findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/NewCenturySchlbk-BoldItalic-latin1

+    /NewCenturySchlbk-BoldItalic findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Palatino-Roman-latin1

+    /Palatino-Roman findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Palatino-Italic-latin1

+    /Palatino-Italic findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Palatino-Bold-latin1

+    /Palatino-Bold findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Palatino-BoldItalic-latin1

+    /Palatino-BoldItalic findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Symbol-latin1

+    /Symbol findfont

+definefont pop

+/ZapfChancery-MediumItalic-latin1

+    /ZapfChancery-MediumItalic findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/ZapfDingbats-latin1

+    /ZapfDingbats findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+28.346000 -28.346000 scale

+-0.950000 -18.050000 translate

+%%EndProlog

+

+

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slj

+1.000000 1.000000 1.000000 srgb

+n 14.000000 15.000000 m 14.000000 18.000000 l 26.000000 18.000000 l 26.000000 15.000000 l f

+0.000000 0.000000 0.000000 srgb

+n 14.000000 15.000000 m 14.000000 18.000000 l 26.000000 18.000000 l 26.000000 15.000000 l cp s

+/Helvetica-latin1 ff 0.560000 scf sf

+(BIG - Big Number support) 15.000000 16.880000 m

+ gs 1 -1 sc sh gr

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slj

+1.000000 1.000000 1.000000 srgb

+n 14.000000 11.000000 m 14.000000 14.000000 l 26.000000 14.000000 l 26.000000 11.000000 l f

+0.000000 0.000000 0.000000 srgb

+n 14.000000 11.000000 m 14.000000 14.000000 l 26.000000 14.000000 l 26.000000 11.000000 l cp s

+/Helvetica-latin1 ff 0.560000 scf sf

+(FP - Finite Field Functions) 15.000000 12.880000 m

+ gs 1 -1 sc sh gr

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slj

+1.000000 1.000000 1.000000 srgb

+n 28.000000 11.000000 m 28.000000 14.000000 l 40.000000 14.000000 l 40.000000 11.000000 l f

+0.000000 0.000000 0.000000 srgb

+n 28.000000 11.000000 m 28.000000 14.000000 l 40.000000 14.000000 l 40.000000 11.000000 l cp s

+/Helvetica-latin1 ff 0.560000 scf sf

+(ECP - Elliptic Curves over Fp) 29.000000 12.880000 m

+ gs 1 -1 sc sh gr

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slc

+n 26.000000 12.500000 m 27.513197 12.500000 l s

+[] 0 sd

+0 slj

+0 slc

+n 27.888197 12.500000 m 27.388197 12.750000 l 27.513197 12.500000 l 27.388197 12.250000 l ef

+n 27.888197 12.500000 m 27.388197 12.750000 l 27.513197 12.500000 l 27.388197 12.250000 l cp s

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slj

+1.000000 1.000000 1.000000 srgb

+n 14.000000 7.000000 m 14.000000 10.000000 l 26.000000 10.000000 l 26.000000 7.000000 l f

+0.000000 0.000000 0.000000 srgb

+n 14.000000 7.000000 m 14.000000 10.000000 l 26.000000 10.000000 l 26.000000 7.000000 l cp s

+/Helvetica-latin1 ff 0.560000 scf sf

+(FP2 - Extension Field Fp2) 15.000000 8.880000 m

+ gs 1 -1 sc sh gr

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slj

+1.000000 1.000000 1.000000 srgb

+n 14.000000 3.000000 m 14.000000 6.000000 l 26.000000 6.000000 l 26.000000 3.000000 l f

+0.000000 0.000000 0.000000 srgb

+n 14.000000 3.000000 m 14.000000 6.000000 l 26.000000 6.000000 l 26.000000 3.000000 l cp s

+/Helvetica-latin1 ff 0.560000 scf sf

+(FP4 - Extension Field Fp4) 16.000000 4.880000 m

+ gs 1 -1 sc sh gr

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slj

+1.000000 1.000000 1.000000 srgb

+n 14.000000 -1.000000 m 14.000000 2.000000 l 26.000000 2.000000 l 26.000000 -1.000000 l f

+0.000000 0.000000 0.000000 srgb

+n 14.000000 -1.000000 m 14.000000 2.000000 l 26.000000 2.000000 l 26.000000 -1.000000 l cp s

+/Helvetica-latin1 ff 0.560000 scf sf

+(FP12 - Extension Field Fp12) 16.000000 0.880000 m

+ gs 1 -1 sc sh gr

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slj

+1.000000 1.000000 1.000000 srgb

+n 28.000000 7.000000 m 28.000000 10.000000 l 40.000000 10.000000 l 40.000000 7.000000 l f

+0.000000 0.000000 0.000000 srgb

+n 28.000000 7.000000 m 28.000000 10.000000 l 40.000000 10.000000 l 40.000000 7.000000 l cp s

+/Helvetica-latin1 ff 0.560000 scf sf

+(ECP2 - Elliptic Curves over Fp2) 29.000000 8.880000 m

+ gs 1 -1 sc sh gr

+/Helvetica-latin1 ff 0.560000 scf sf

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slc

+n 34.000000 10.950928 m 34.000000 10.486803 l s

+[] 0 sd

+0 slj

+0 slc

+n 34.000000 10.111803 m 34.250000 10.611803 l 34.000000 10.486803 l 33.750000 10.611803 l ef

+n 34.000000 10.111803 m 34.250000 10.611803 l 34.000000 10.486803 l 33.750000 10.611803 l cp s

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slc

+n 20.000000 11.000000 m 20.000000 10.486803 l s

+[] 0 sd

+0 slj

+0 slc

+n 20.000000 10.111803 m 20.250000 10.611803 l 20.000000 10.486803 l 19.750000 10.611803 l ef

+n 20.000000 10.111803 m 20.250000 10.611803 l 20.000000 10.486803 l 19.750000 10.611803 l cp s

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slc

+n 20.000000 7.000000 m 20.000000 6.486803 l s

+[] 0 sd

+0 slj

+0 slc

+n 20.000000 6.111803 m 20.250000 6.611803 l 20.000000 6.486803 l 19.750000 6.611803 l ef

+n 20.000000 6.111803 m 20.250000 6.611803 l 20.000000 6.486803 l 19.750000 6.611803 l cp s

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slc

+n 20.000000 3.000000 m 20.000000 2.486803 l s

+[] 0 sd

+0 slj

+0 slc

+n 20.000000 2.111803 m 20.250000 2.611803 l 20.000000 2.486803 l 19.750000 2.611803 l ef

+n 20.000000 2.111803 m 20.250000 2.611803 l 20.000000 2.486803 l 19.750000 2.611803 l cp s

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slj

+1.000000 1.000000 1.000000 srgb

+n 28.000000 3.000000 m 28.000000 6.000000 l 40.000000 6.000000 l 40.000000 3.000000 l f

+0.000000 0.000000 0.000000 srgb

+n 28.000000 3.000000 m 28.000000 6.000000 l 40.000000 6.000000 l 40.000000 3.000000 l cp s

+/Helvetica-latin1 ff 0.560000 scf sf

+(PAIR - Pairings on BN curves) 29.000000 4.880000 m

+ gs 1 -1 sc sh gr

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slc

+n 34.000000 6.950928 m 34.000000 6.486803 l s

+[] 0 sd

+0 slj

+0 slc

+n 34.000000 6.111803 m 34.250000 6.611803 l 34.000000 6.486803 l 33.750000 6.611803 l ef

+n 34.000000 6.111803 m 34.250000 6.611803 l 34.000000 6.486803 l 33.750000 6.611803 l cp s

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slc

+n 26.000000 0.500000 m 27.695896 2.619870 l s

+[] 0 sd

+0 slj

+0 slc

+n 27.930157 2.912696 m 27.422592 2.678436 l 27.695896 2.619870 l 27.813027 2.366088 l ef

+n 27.930157 2.912696 m 27.422592 2.678436 l 27.695896 2.619870 l 27.813027 2.366088 l cp s

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slj

+1.000000 1.000000 1.000000 srgb

+n 1.000000 3.000000 m 1.000000 6.000000 l 12.000000 6.000000 l 12.000000 3.000000 l f

+0.000000 0.000000 0.000000 srgb

+n 1.000000 3.000000 m 1.000000 6.000000 l 12.000000 6.000000 l 12.000000 3.000000 l cp s

+/Helvetica-latin1 ff 0.560000 scf sf

+(AES - Symmetric Encryption) 2.000000 4.880000 m

+ gs 1 -1 sc sh gr

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slj

+1.000000 1.000000 1.000000 srgb

+n 1.000000 11.000000 m 1.000000 14.000000 l 12.000000 14.000000 l 12.000000 11.000000 l f

+0.000000 0.000000 0.000000 srgb

+n 1.000000 11.000000 m 1.000000 14.000000 l 12.000000 14.000000 l 12.000000 11.000000 l cp s

+/Helvetica-latin1 ff 0.560000 scf sf

+(RAND - Random Numbers) 2.000000 12.880000 m

+ gs 1 -1 sc sh gr

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slc

+n 12.000000 12.500000 m 13.695896 14.619870 l s

+[] 0 sd

+0 slj

+0 slc

+n 13.930157 14.912696 m 13.422592 14.678436 l 13.695896 14.619870 l 13.813027 14.366088 l ef

+n 13.930157 14.912696 m 13.422592 14.678436 l 13.695896 14.619870 l 13.813027 14.366088 l cp s

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slj

+1.000000 1.000000 1.000000 srgb

+n 1.000000 15.000000 m 1.000000 18.000000 l 12.000000 18.000000 l 12.000000 15.000000 l f

+0.000000 0.000000 0.000000 srgb

+n 1.000000 15.000000 m 1.000000 18.000000 l 12.000000 18.000000 l 12.000000 15.000000 l cp s

+/Helvetica-latin1 ff 0.560000 scf sf

+(HASH - Hashing) 2.000000 8.880000 m

+ gs 1 -1 sc sh gr

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slc

+n 6.500000 14.535876 m 6.500000 15.000000 l s

+[] 0 sd

+0 slj

+0 slc

+n 6.500000 14.160876 m 6.750000 14.660876 l 6.500000 14.535876 l 6.250000 14.660876 l ef

+n 6.500000 14.160876 m 6.750000 14.660876 l 6.500000 14.535876 l 6.250000 14.660876 l cp s

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slj

+n 1.000000 7.000000 m 1.000000 10.000000 l 12.000000 10.000000 l 12.000000 7.000000 l cp s

+/Helvetica-latin1 ff 0.560000 scf sf

+(External Entropy Source) 3.000000 16.880000 m

+ gs 1 -1 sc sh gr

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slc

+n 6.500000 10.000000 m 6.500000 10.513197 l s

+[] 0 sd

+0 slj

+0 slc

+n 6.500000 10.888197 m 6.250000 10.388197 l 6.500000 10.513197 l 6.750000 10.388197 l ef

+n 6.500000 10.888197 m 6.250000 10.388197 l 6.500000 10.513197 l 6.750000 10.388197 l cp s

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slj

+1.000000 1.000000 1.000000 srgb

+n 28.000000 -1.000000 m 28.000000 2.000000 l 40.000000 2.000000 l 40.000000 -1.000000 l f

+0.000000 0.000000 0.000000 srgb

+n 28.000000 -1.000000 m 28.000000 2.000000 l 40.000000 2.000000 l 40.000000 -1.000000 l cp s

+/Helvetica-latin1 ff 0.560000 scf sf

+(OCT - Octet Input/Output ) 29.000000 0.880000 m

+ gs 1 -1 sc sh gr

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slj

+1.000000 1.000000 1.000000 srgb

+n 28.000000 15.000000 m 28.000000 18.000000 l 40.000000 18.000000 l 40.000000 15.000000 l f

+0.000000 0.000000 0.000000 srgb

+n 28.000000 15.000000 m 28.000000 18.000000 l 40.000000 18.000000 l 40.000000 15.000000 l cp s

+/Helvetica-latin1 ff 0.560000 scf sf

+(ROM - Field/Curve Constants) 29.000000 16.880000 m

+ gs 1 -1 sc sh gr

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slj

+1.000000 1.000000 1.000000 srgb

+n 4.000000 -8.000000 m 4.000000 -4.000000 l 36.000000 -4.000000 l 36.000000 -8.000000 l f

+0.000000 0.000000 0.000000 srgb

+n 4.000000 -8.000000 m 4.000000 -4.000000 l 36.000000 -4.000000 l 36.000000 -8.000000 l cp s

+/Helvetica-latin1 ff 0.560000 scf sf

+(Your API) 20.000000 -6.120000 m

+ gs 1 -1 sc sh gr

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slc

+n 30.662354 -1.049622 m 24.850715 -3.747882 l s

+[] 0 sd

+0 slj

+0 slc

+n 24.510586 -3.905799 m 25.069369 -3.921996 l 24.850715 -3.747882 l 24.858813 -3.468491 l ef

+n 24.510586 -3.905799 m 25.069369 -3.921996 l 24.850715 -3.747882 l 24.858813 -3.468491 l cp s

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slj

+1.000000 1.000000 1.000000 srgb

+n 1.000000 -1.000000 m 1.000000 2.000000 l 12.000000 2.000000 l 12.000000 -1.000000 l f

+0.000000 0.000000 0.000000 srgb

+n 1.000000 -1.000000 m 1.000000 2.000000 l 12.000000 2.000000 l 12.000000 -1.000000 l cp s

+/Helvetica-latin1 ff 0.560000 scf sf

+(GCM - authenticated encryption ) 2.000000 0.880000 m

+ gs 1 -1 sc sh gr

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slc

+n 26.000000 8.500000 m 27.513197 8.500000 l s

+[] 0 sd

+0 slj

+0 slc

+n 27.888197 8.500000 m 27.388197 8.750000 l 27.513197 8.500000 l 27.388197 8.250000 l ef

+n 27.888197 8.500000 m 27.388197 8.750000 l 27.513197 8.500000 l 27.388197 8.250000 l cp s

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slc

+n 6.500000 2.950928 m 6.500000 2.486803 l s

+[] 0 sd

+0 slj

+0 slc

+n 6.500000 2.111803 m 6.750000 2.611803 l 6.500000 2.486803 l 6.250000 2.611803 l ef

+n 6.500000 2.111803 m 6.750000 2.611803 l 6.500000 2.486803 l 6.250000 2.611803 l cp s

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slc

+n 20.000000 15.000000 m 20.000000 14.486803 l s

+[] 0 sd

+0 slj

+0 slc

+n 20.000000 14.111803 m 20.250000 14.611803 l 20.000000 14.486803 l 19.750000 14.611803 l ef

+n 20.000000 14.111803 m 20.250000 14.611803 l 20.000000 14.486803 l 19.750000 14.611803 l cp s

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slc

+n 34.000000 15.000000 m 34.000000 14.486803 l s

+[] 0 sd

+0 slj

+0 slc

+n 34.000000 14.111803 m 34.250000 14.611803 l 34.000000 14.486803 l 33.750000 14.611803 l ef

+n 34.000000 14.111803 m 34.250000 14.611803 l 34.000000 14.486803 l 33.750000 14.611803 l cp s

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slc

+n 28.000000 16.500000 m 26.304104 14.380130 l s

+[] 0 sd

+0 slj

+0 slc

+n 26.069843 14.087304 m 26.577408 14.321564 l 26.304104 14.380130 l 26.186973 14.633912 l ef

+n 26.069843 14.087304 m 26.577408 14.321564 l 26.304104 14.380130 l 26.186973 14.633912 l cp s

+showpage

diff --git a/docs/latex/llncs.cls b/docs/latex/llncs.cls
new file mode 100644
index 0000000..23fd1c6
--- /dev/null
+++ b/docs/latex/llncs.cls
@@ -0,0 +1,1190 @@
+% LLNCS DOCUMENT CLASS -- version 2.14 (17-Aug-2004)

+% Springer Verlag LaTeX2e support for Lecture Notes in Computer Science

+%

+%%

+%% \CharacterTable

+%%  {Upper-case    \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z

+%%   Lower-case    \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z

+%%   Digits        \0\1\2\3\4\5\6\7\8\9

+%%   Exclamation   \!     Double quote  \"     Hash (number) \#

+%%   Dollar        \$     Percent       \%     Ampersand     \&

+%%   Acute accent  \'     Left paren    \(     Right paren   \)

+%%   Asterisk      \*     Plus          \+     Comma         \,

+%%   Minus         \-     Point         \.     Solidus       \/

+%%   Colon         \:     Semicolon     \;     Less than     \<

+%%   Equals        \=     Greater than  \>     Question mark \?

+%%   Commercial at \@     Left bracket  \[     Backslash     \\

+%%   Right bracket \]     Circumflex    \^     Underscore    \_

+%%   Grave accent  \`     Left brace    \{     Vertical bar  \|

+%%   Right brace   \}     Tilde         \~}

+%%

+\NeedsTeXFormat{LaTeX2e}[1995/12/01]

+\ProvidesClass{llncs}[2004/08/17 v2.14

+^^J LaTeX document class for Lecture Notes in Computer Science]

+% Options

+\let\if@envcntreset\iffalse

+\DeclareOption{envcountreset}{\let\if@envcntreset\iftrue}

+\DeclareOption{citeauthoryear}{\let\citeauthoryear=Y}

+\DeclareOption{oribibl}{\let\oribibl=Y}

+\let\if@custvec\iftrue

+\DeclareOption{orivec}{\let\if@custvec\iffalse}

+\let\if@envcntsame\iffalse

+\DeclareOption{envcountsame}{\let\if@envcntsame\iftrue}

+\let\if@envcntsect\iffalse

+\DeclareOption{envcountsect}{\let\if@envcntsect\iftrue}

+\let\if@runhead\iffalse

+\DeclareOption{runningheads}{\let\if@runhead\iftrue}

+

+\let\if@openbib\iffalse

+\DeclareOption{openbib}{\let\if@openbib\iftrue}

+

+% languages

+\let\switcht@@therlang\relax

+\def\ds@deutsch{\def\switcht@@therlang{\switcht@deutsch}}

+\def\ds@francais{\def\switcht@@therlang{\switcht@francais}}

+

+\DeclareOption*{\PassOptionsToClass{\CurrentOption}{article}}

+

+\ProcessOptions

+

+\LoadClass[twoside]{article}

+\RequirePackage{multicol} % needed for the list of participants, index

+

+\setlength{\textwidth}{12.2cm}

+\setlength{\textheight}{19.3cm}

+\renewcommand\@pnumwidth{2em}

+\renewcommand\@tocrmarg{3.5em}

+%

+\def\@dottedtocline#1#2#3#4#5{%

+  \ifnum #1>\c@tocdepth \else

+    \vskip \z@ \@plus.2\p@

+    {\leftskip #2\relax \rightskip \@tocrmarg \advance\rightskip by 0pt plus 2cm

+               \parfillskip -\rightskip \pretolerance=10000

+     \parindent #2\relax\@afterindenttrue

+     \interlinepenalty\@M

+     \leavevmode

+     \@tempdima #3\relax

+     \advance\leftskip \@tempdima \null\nobreak\hskip -\leftskip

+     {#4}\nobreak

+     \leaders\hbox{$\m@th

+        \mkern \@dotsep mu\hbox{.}\mkern \@dotsep

+        mu$}\hfill

+     \nobreak

+     \hb@xt@\@pnumwidth{\hfil\normalfont \normalcolor #5}%

+     \par}%

+  \fi}

+%

+\def\switcht@albion{%

+\def\abstractname{Abstract.}

+\def\ackname{Acknowledgement.}

+\def\andname{and}

+\def\lastandname{\unskip, and}

+\def\appendixname{Appendix}

+\def\chaptername{Chapter}

+\def\claimname{Claim}

+\def\conjecturename{Conjecture}

+\def\contentsname{Table of Contents}

+\def\corollaryname{Corollary}

+\def\definitionname{Definition}

+\def\examplename{Example}

+\def\exercisename{Exercise}

+\def\figurename{Fig.}

+\def\keywordname{{\bf Key words:}}

+\def\indexname{Index}

+\def\lemmaname{Lemma}

+\def\contriblistname{List of Contributors}

+\def\listfigurename{List of Figures}

+\def\listtablename{List of Tables}

+\def\mailname{{\it Correspondence to\/}:}

+\def\noteaddname{Note added in proof}

+\def\notename{Note}

+\def\partname{Part}

+\def\problemname{Problem}

+\def\proofname{Proof}

+\def\propertyname{Property}

+\def\propositionname{Proposition}

+\def\questionname{Question}

+\def\remarkname{Remark}

+\def\seename{see}

+\def\solutionname{Solution}

+\def\subclassname{{\it Subject Classifications\/}:}

+\def\tablename{Table}

+\def\theoremname{Theorem}}

+\switcht@albion

+% Names of theorem like environments are already defined

+% but must be translated if another language is chosen

+%

+% French section

+\def\switcht@francais{%\typeout{On parle francais.}%

+ \def\abstractname{R\'esum\'e.}%

+ \def\ackname{Remerciements.}%

+ \def\andname{et}%

+ \def\lastandname{ et}%

+ \def\appendixname{Appendice}

+ \def\chaptername{Chapitre}%

+ \def\claimname{Pr\'etention}%

+ \def\conjecturename{Hypoth\`ese}%

+ \def\contentsname{Table des mati\`eres}%

+ \def\corollaryname{Corollaire}%

+ \def\definitionname{D\'efinition}%

+ \def\examplename{Exemple}%

+ \def\exercisename{Exercice}%

+ \def\figurename{Fig.}%

+ \def\keywordname{{\bf Mots-cl\'e:}}

+ \def\indexname{Index}

+ \def\lemmaname{Lemme}%

+ \def\contriblistname{Liste des contributeurs}

+ \def\listfigurename{Liste des figures}%

+ \def\listtablename{Liste des tables}%

+ \def\mailname{{\it Correspondence to\/}:}

+ \def\noteaddname{Note ajout\'ee \`a l'\'epreuve}%

+ \def\notename{Remarque}%

+ \def\partname{Partie}%

+ \def\problemname{Probl\`eme}%

+ \def\proofname{Preuve}%

+ \def\propertyname{Caract\'eristique}%

+%\def\propositionname{Proposition}%

+ \def\questionname{Question}%

+ \def\remarkname{Remarque}%

+ \def\seename{voir}

+ \def\solutionname{Solution}%

+ \def\subclassname{{\it Subject Classifications\/}:}

+ \def\tablename{Tableau}%

+ \def\theoremname{Th\'eor\`eme}%

+}

+%

+% German section

+\def\switcht@deutsch{%\typeout{Man spricht deutsch.}%

+ \def\abstractname{Zusammenfassung.}%

+ \def\ackname{Danksagung.}%

+ \def\andname{und}%

+ \def\lastandname{ und}%

+ \def\appendixname{Anhang}%

+ \def\chaptername{Kapitel}%

+ \def\claimname{Behauptung}%

+ \def\conjecturename{Hypothese}%

+ \def\contentsname{Inhaltsverzeichnis}%

+ \def\corollaryname{Korollar}%

+%\def\definitionname{Definition}%

+ \def\examplename{Beispiel}%

+ \def\exercisename{\"Ubung}%

+ \def\figurename{Abb.}%

+ \def\keywordname{{\bf Schl\"usselw\"orter:}}

+ \def\indexname{Index}

+%\def\lemmaname{Lemma}%

+ \def\contriblistname{Mitarbeiter}

+ \def\listfigurename{Abbildungsverzeichnis}%

+ \def\listtablename{Tabellenverzeichnis}%

+ \def\mailname{{\it Correspondence to\/}:}

+ \def\noteaddname{Nachtrag}%

+ \def\notename{Anmerkung}%

+ \def\partname{Teil}%

+%\def\problemname{Problem}%

+ \def\proofname{Beweis}%

+ \def\propertyname{Eigenschaft}%

+%\def\propositionname{Proposition}%

+ \def\questionname{Frage}%

+ \def\remarkname{Anmerkung}%

+ \def\seename{siehe}

+ \def\solutionname{L\"osung}%

+ \def\subclassname{{\it Subject Classifications\/}:}

+ \def\tablename{Tabelle}%

+%\def\theoremname{Theorem}%

+}

+

+% Ragged bottom for the actual page

+\def\thisbottomragged{\def\@textbottom{\vskip\z@ plus.0001fil

+\global\let\@textbottom\relax}}

+

+\renewcommand\small{%

+   \@setfontsize\small\@ixpt{11}%

+   \abovedisplayskip 8.5\p@ \@plus3\p@ \@minus4\p@

+   \abovedisplayshortskip \z@ \@plus2\p@

+   \belowdisplayshortskip 4\p@ \@plus2\p@ \@minus2\p@

+   \def\@listi{\leftmargin\leftmargini

+               \parsep 0\p@ \@plus1\p@ \@minus\p@

+               \topsep 8\p@ \@plus2\p@ \@minus4\p@

+               \itemsep0\p@}%

+   \belowdisplayskip \abovedisplayskip

+}

+

+\frenchspacing

+\widowpenalty=10000

+\clubpenalty=10000

+

+\setlength\oddsidemargin   {63\p@}

+\setlength\evensidemargin  {63\p@}

+\setlength\marginparwidth  {90\p@}

+

+\setlength\headsep   {16\p@}

+

+\setlength\footnotesep{7.7\p@}

+\setlength\textfloatsep{8mm\@plus 2\p@ \@minus 4\p@}

+\setlength\intextsep   {8mm\@plus 2\p@ \@minus 2\p@}

+

+\setcounter{secnumdepth}{2}

+

+\newcounter {chapter}

+\renewcommand\thechapter      {\@arabic\c@chapter}

+

+\newif\if@mainmatter \@mainmattertrue

+\newcommand\frontmatter{\cleardoublepage

+            \@mainmatterfalse\pagenumbering{Roman}}

+\newcommand\mainmatter{\cleardoublepage

+       \@mainmattertrue\pagenumbering{arabic}}

+\newcommand\backmatter{\if@openright\cleardoublepage\else\clearpage\fi

+      \@mainmatterfalse}

+

+\renewcommand\part{\cleardoublepage

+                 \thispagestyle{empty}%

+                 \if@twocolumn

+                     \onecolumn

+                     \@tempswatrue

+                   \else

+                     \@tempswafalse

+                 \fi

+                 \null\vfil

+                 \secdef\@part\@spart}

+

+\def\@part[#1]#2{%

+    \ifnum \c@secnumdepth >-2\relax

+      \refstepcounter{part}%

+      \addcontentsline{toc}{part}{\thepart\hspace{1em}#1}%

+    \else

+      \addcontentsline{toc}{part}{#1}%

+    \fi

+    \markboth{}{}%

+    {\centering

+     \interlinepenalty \@M

+     \normalfont

+     \ifnum \c@secnumdepth >-2\relax

+       \huge\bfseries \partname~\thepart

+       \par

+       \vskip 20\p@

+     \fi

+     \Huge \bfseries #2\par}%

+    \@endpart}

+\def\@spart#1{%

+    {\centering

+     \interlinepenalty \@M

+     \normalfont

+     \Huge \bfseries #1\par}%

+    \@endpart}

+\def\@endpart{\vfil\newpage

+              \if@twoside

+                \null

+                \thispagestyle{empty}%

+                \newpage

+              \fi

+              \if@tempswa

+                \twocolumn

+              \fi}

+

+\newcommand\chapter{\clearpage

+                    \thispagestyle{empty}%

+                    \global\@topnum\z@

+                    \@afterindentfalse

+                    \secdef\@chapter\@schapter}

+\def\@chapter[#1]#2{\ifnum \c@secnumdepth >\m@ne

+                       \if@mainmatter

+                         \refstepcounter{chapter}%

+                         \typeout{\@chapapp\space\thechapter.}%

+                         \addcontentsline{toc}{chapter}%

+                                  {\protect\numberline{\thechapter}#1}%

+                       \else

+                         \addcontentsline{toc}{chapter}{#1}%

+                       \fi

+                    \else

+                      \addcontentsline{toc}{chapter}{#1}%

+                    \fi

+                    \chaptermark{#1}%

+                    \addtocontents{lof}{\protect\addvspace{10\p@}}%

+                    \addtocontents{lot}{\protect\addvspace{10\p@}}%

+                    \if@twocolumn

+                      \@topnewpage[\@makechapterhead{#2}]%

+                    \else

+                      \@makechapterhead{#2}%

+                      \@afterheading

+                    \fi}

+\def\@makechapterhead#1{%

+% \vspace*{50\p@}%

+  {\centering

+    \ifnum \c@secnumdepth >\m@ne

+      \if@mainmatter

+        \large\bfseries \@chapapp{} \thechapter

+        \par\nobreak

+        \vskip 20\p@

+      \fi

+    \fi

+    \interlinepenalty\@M

+    \Large \bfseries #1\par\nobreak

+    \vskip 40\p@

+  }}

+\def\@schapter#1{\if@twocolumn

+                   \@topnewpage[\@makeschapterhead{#1}]%

+                 \else

+                   \@makeschapterhead{#1}%

+                   \@afterheading

+                 \fi}

+\def\@makeschapterhead#1{%

+% \vspace*{50\p@}%

+  {\centering

+    \normalfont

+    \interlinepenalty\@M

+    \Large \bfseries  #1\par\nobreak

+    \vskip 40\p@

+  }}

+

+\renewcommand\section{\@startsection{section}{1}{\z@}%

+                       {-18\p@ \@plus -4\p@ \@minus -4\p@}%

+                       {12\p@ \@plus 4\p@ \@minus 4\p@}%

+                       {\normalfont\large\bfseries\boldmath

+                        \rightskip=\z@ \@plus 8em\pretolerance=10000 }}

+\renewcommand\subsection{\@startsection{subsection}{2}{\z@}%

+                       {-18\p@ \@plus -4\p@ \@minus -4\p@}%

+                       {8\p@ \@plus 4\p@ \@minus 4\p@}%

+                       {\normalfont\normalsize\bfseries\boldmath

+                        \rightskip=\z@ \@plus 8em\pretolerance=10000 }}

+\renewcommand\subsubsection{\@startsection{subsubsection}{3}{\z@}%

+                       {-18\p@ \@plus -4\p@ \@minus -4\p@}%

+                       {-0.5em \@plus -0.22em \@minus -0.1em}%

+                       {\normalfont\normalsize\bfseries\boldmath}}

+\renewcommand\paragraph{\@startsection{paragraph}{4}{\z@}%

+                       {-12\p@ \@plus -4\p@ \@minus -4\p@}%

+                       {-0.5em \@plus -0.22em \@minus -0.1em}%

+                       {\normalfont\normalsize\itshape}}

+\renewcommand\subparagraph[1]{\typeout{LLNCS warning: You should not use

+                  \string\subparagraph\space with this class}\vskip0.5cm

+You should not use \verb|\subparagraph| with this class.\vskip0.5cm}

+

+\DeclareMathSymbol{\Gamma}{\mathalpha}{letters}{"00}

+\DeclareMathSymbol{\Delta}{\mathalpha}{letters}{"01}

+\DeclareMathSymbol{\Theta}{\mathalpha}{letters}{"02}

+\DeclareMathSymbol{\Lambda}{\mathalpha}{letters}{"03}

+\DeclareMathSymbol{\Xi}{\mathalpha}{letters}{"04}

+\DeclareMathSymbol{\Pi}{\mathalpha}{letters}{"05}

+\DeclareMathSymbol{\Sigma}{\mathalpha}{letters}{"06}

+\DeclareMathSymbol{\Upsilon}{\mathalpha}{letters}{"07}

+\DeclareMathSymbol{\Phi}{\mathalpha}{letters}{"08}

+\DeclareMathSymbol{\Psi}{\mathalpha}{letters}{"09}

+\DeclareMathSymbol{\Omega}{\mathalpha}{letters}{"0A}

+

+\let\footnotesize\small

+

+\if@custvec

+\def\vec#1{\mathchoice{\mbox{\boldmath$\displaystyle#1$}}

+{\mbox{\boldmath$\textstyle#1$}}

+{\mbox{\boldmath$\scriptstyle#1$}}

+{\mbox{\boldmath$\scriptscriptstyle#1$}}}

+\fi

+

+\def\squareforqed{\hbox{\rlap{$\sqcap$}$\sqcup$}}

+\def\qed{\ifmmode\squareforqed\else{\unskip\nobreak\hfil

+\penalty50\hskip1em\null\nobreak\hfil\squareforqed

+\parfillskip=0pt\finalhyphendemerits=0\endgraf}\fi}

+

+\def\getsto{\mathrel{\mathchoice {\vcenter{\offinterlineskip

+\halign{\hfil

+$\displaystyle##$\hfil\cr\gets\cr\to\cr}}}

+{\vcenter{\offinterlineskip\halign{\hfil$\textstyle##$\hfil\cr\gets

+\cr\to\cr}}}

+{\vcenter{\offinterlineskip\halign{\hfil$\scriptstyle##$\hfil\cr\gets

+\cr\to\cr}}}

+{\vcenter{\offinterlineskip\halign{\hfil$\scriptscriptstyle##$\hfil\cr

+\gets\cr\to\cr}}}}}

+\def\lid{\mathrel{\mathchoice {\vcenter{\offinterlineskip\halign{\hfil

+$\displaystyle##$\hfil\cr<\cr\noalign{\vskip1.2pt}=\cr}}}

+{\vcenter{\offinterlineskip\halign{\hfil$\textstyle##$\hfil\cr<\cr

+\noalign{\vskip1.2pt}=\cr}}}

+{\vcenter{\offinterlineskip\halign{\hfil$\scriptstyle##$\hfil\cr<\cr

+\noalign{\vskip1pt}=\cr}}}

+{\vcenter{\offinterlineskip\halign{\hfil$\scriptscriptstyle##$\hfil\cr

+<\cr

+\noalign{\vskip0.9pt}=\cr}}}}}

+\def\gid{\mathrel{\mathchoice {\vcenter{\offinterlineskip\halign{\hfil

+$\displaystyle##$\hfil\cr>\cr\noalign{\vskip1.2pt}=\cr}}}

+{\vcenter{\offinterlineskip\halign{\hfil$\textstyle##$\hfil\cr>\cr

+\noalign{\vskip1.2pt}=\cr}}}

+{\vcenter{\offinterlineskip\halign{\hfil$\scriptstyle##$\hfil\cr>\cr

+\noalign{\vskip1pt}=\cr}}}

+{\vcenter{\offinterlineskip\halign{\hfil$\scriptscriptstyle##$\hfil\cr

+>\cr

+\noalign{\vskip0.9pt}=\cr}}}}}

+\def\grole{\mathrel{\mathchoice {\vcenter{\offinterlineskip

+\halign{\hfil

+$\displaystyle##$\hfil\cr>\cr\noalign{\vskip-1pt}<\cr}}}

+{\vcenter{\offinterlineskip\halign{\hfil$\textstyle##$\hfil\cr

+>\cr\noalign{\vskip-1pt}<\cr}}}

+{\vcenter{\offinterlineskip\halign{\hfil$\scriptstyle##$\hfil\cr

+>\cr\noalign{\vskip-0.8pt}<\cr}}}

+{\vcenter{\offinterlineskip\halign{\hfil$\scriptscriptstyle##$\hfil\cr

+>\cr\noalign{\vskip-0.3pt}<\cr}}}}}

+\def\bbbr{{\rm I\!R}} %reelle Zahlen

+\def\bbbm{{\rm I\!M}}

+\def\bbbn{{\rm I\!N}} %natuerliche Zahlen

+\def\bbbf{{\rm I\!F}}

+\def\bbbh{{\rm I\!H}}

+\def\bbbk{{\rm I\!K}}

+\def\bbbp{{\rm I\!P}}

+\def\bbbone{{\mathchoice {\rm 1\mskip-4mu l} {\rm 1\mskip-4mu l}

+{\rm 1\mskip-4.5mu l} {\rm 1\mskip-5mu l}}}

+\def\bbbc{{\mathchoice {\setbox0=\hbox{$\displaystyle\rm C$}\hbox{\hbox

+to0pt{\kern0.4\wd0\vrule height0.9\ht0\hss}\box0}}

+{\setbox0=\hbox{$\textstyle\rm C$}\hbox{\hbox

+to0pt{\kern0.4\wd0\vrule height0.9\ht0\hss}\box0}}

+{\setbox0=\hbox{$\scriptstyle\rm C$}\hbox{\hbox

+to0pt{\kern0.4\wd0\vrule height0.9\ht0\hss}\box0}}

+{\setbox0=\hbox{$\scriptscriptstyle\rm C$}\hbox{\hbox

+to0pt{\kern0.4\wd0\vrule height0.9\ht0\hss}\box0}}}}

+\def\bbbq{{\mathchoice {\setbox0=\hbox{$\displaystyle\rm

+Q$}\hbox{\raise

+0.15\ht0\hbox to0pt{\kern0.4\wd0\vrule height0.8\ht0\hss}\box0}}

+{\setbox0=\hbox{$\textstyle\rm Q$}\hbox{\raise

+0.15\ht0\hbox to0pt{\kern0.4\wd0\vrule height0.8\ht0\hss}\box0}}

+{\setbox0=\hbox{$\scriptstyle\rm Q$}\hbox{\raise

+0.15\ht0\hbox to0pt{\kern0.4\wd0\vrule height0.7\ht0\hss}\box0}}

+{\setbox0=\hbox{$\scriptscriptstyle\rm Q$}\hbox{\raise

+0.15\ht0\hbox to0pt{\kern0.4\wd0\vrule height0.7\ht0\hss}\box0}}}}

+\def\bbbt{{\mathchoice {\setbox0=\hbox{$\displaystyle\rm

+T$}\hbox{\hbox to0pt{\kern0.3\wd0\vrule height0.9\ht0\hss}\box0}}

+{\setbox0=\hbox{$\textstyle\rm T$}\hbox{\hbox

+to0pt{\kern0.3\wd0\vrule height0.9\ht0\hss}\box0}}

+{\setbox0=\hbox{$\scriptstyle\rm T$}\hbox{\hbox

+to0pt{\kern0.3\wd0\vrule height0.9\ht0\hss}\box0}}

+{\setbox0=\hbox{$\scriptscriptstyle\rm T$}\hbox{\hbox

+to0pt{\kern0.3\wd0\vrule height0.9\ht0\hss}\box0}}}}

+\def\bbbs{{\mathchoice

+{\setbox0=\hbox{$\displaystyle     \rm S$}\hbox{\raise0.5\ht0\hbox

+to0pt{\kern0.35\wd0\vrule height0.45\ht0\hss}\hbox

+to0pt{\kern0.55\wd0\vrule height0.5\ht0\hss}\box0}}

+{\setbox0=\hbox{$\textstyle        \rm S$}\hbox{\raise0.5\ht0\hbox

+to0pt{\kern0.35\wd0\vrule height0.45\ht0\hss}\hbox

+to0pt{\kern0.55\wd0\vrule height0.5\ht0\hss}\box0}}

+{\setbox0=\hbox{$\scriptstyle      \rm S$}\hbox{\raise0.5\ht0\hbox

+to0pt{\kern0.35\wd0\vrule height0.45\ht0\hss}\raise0.05\ht0\hbox

+to0pt{\kern0.5\wd0\vrule height0.45\ht0\hss}\box0}}

+{\setbox0=\hbox{$\scriptscriptstyle\rm S$}\hbox{\raise0.5\ht0\hbox

+to0pt{\kern0.4\wd0\vrule height0.45\ht0\hss}\raise0.05\ht0\hbox

+to0pt{\kern0.55\wd0\vrule height0.45\ht0\hss}\box0}}}}

+\def\bbbz{{\mathchoice {\hbox{$\mathsf\textstyle Z\kern-0.4em Z$}}

+{\hbox{$\mathsf\textstyle Z\kern-0.4em Z$}}

+{\hbox{$\mathsf\scriptstyle Z\kern-0.3em Z$}}

+{\hbox{$\mathsf\scriptscriptstyle Z\kern-0.2em Z$}}}}

+

+\let\ts\,

+

+\setlength\leftmargini  {17\p@}

+\setlength\leftmargin    {\leftmargini}

+\setlength\leftmarginii  {\leftmargini}

+\setlength\leftmarginiii {\leftmargini}

+\setlength\leftmarginiv  {\leftmargini}

+\setlength  \labelsep  {.5em}

+\setlength  \labelwidth{\leftmargini}

+\addtolength\labelwidth{-\labelsep}

+

+\def\@listI{\leftmargin\leftmargini

+            \parsep 0\p@ \@plus1\p@ \@minus\p@

+            \topsep 8\p@ \@plus2\p@ \@minus4\p@

+            \itemsep0\p@}

+\let\@listi\@listI

+\@listi

+\def\@listii {\leftmargin\leftmarginii

+              \labelwidth\leftmarginii

+              \advance\labelwidth-\labelsep

+              \topsep    0\p@ \@plus2\p@ \@minus\p@}

+\def\@listiii{\leftmargin\leftmarginiii

+              \labelwidth\leftmarginiii

+              \advance\labelwidth-\labelsep

+              \topsep    0\p@ \@plus\p@\@minus\p@

+              \parsep    \z@

+              \partopsep \p@ \@plus\z@ \@minus\p@}

+

+\renewcommand\labelitemi{\normalfont\bfseries --}

+\renewcommand\labelitemii{$\m@th\bullet$}

+

+\setlength\arraycolsep{1.4\p@}

+\setlength\tabcolsep{1.4\p@}

+

+\def\tableofcontents{\chapter*{\contentsname\@mkboth{{\contentsname}}%

+                                                    {{\contentsname}}}

+ \def\authcount##1{\setcounter{auco}{##1}\setcounter{@auth}{1}}

+ \def\lastand{\ifnum\value{auco}=2\relax

+                 \unskip{} \andname\

+              \else

+                 \unskip \lastandname\

+              \fi}%

+ \def\and{\stepcounter{@auth}\relax

+          \ifnum\value{@auth}=\value{auco}%

+             \lastand

+          \else

+             \unskip,

+          \fi}%

+ \@starttoc{toc}\if@restonecol\twocolumn\fi}

+

+\def\l@part#1#2{\addpenalty{\@secpenalty}%

+   \addvspace{2em plus\p@}%  % space above part line

+   \begingroup

+     \parindent \z@

+     \rightskip \z@ plus 5em

+     \hrule\vskip5pt

+     \large               % same size as for a contribution heading

+     \bfseries\boldmath   % set line in boldface

+     \leavevmode          % TeX command to enter horizontal mode.

+     #1\par

+     \vskip5pt

+     \hrule

+     \vskip1pt

+     \nobreak             % Never break after part entry

+   \endgroup}

+

+\def\@dotsep{2}

+

+\def\hyperhrefextend{\ifx\hyper@anchor\@undefined\else

+{chapter.\thechapter}\fi}

+

+\def\addnumcontentsmark#1#2#3{%

+\addtocontents{#1}{\protect\contentsline{#2}{\protect\numberline

+                     {\thechapter}#3}{\thepage}\hyperhrefextend}}

+\def\addcontentsmark#1#2#3{%

+\addtocontents{#1}{\protect\contentsline{#2}{#3}{\thepage}\hyperhrefextend}}

+\def\addcontentsmarkwop#1#2#3{%

+\addtocontents{#1}{\protect\contentsline{#2}{#3}{0}\hyperhrefextend}}

+

+\def\@adcmk[#1]{\ifcase #1 \or

+\def\@gtempa{\addnumcontentsmark}%

+  \or    \def\@gtempa{\addcontentsmark}%

+  \or    \def\@gtempa{\addcontentsmarkwop}%

+  \fi\@gtempa{toc}{chapter}}

+\def\addtocmark{\@ifnextchar[{\@adcmk}{\@adcmk[3]}}

+

+\def\l@chapter#1#2{\addpenalty{-\@highpenalty}

+ \vskip 1.0em plus 1pt \@tempdima 1.5em \begingroup

+ \parindent \z@ \rightskip \@tocrmarg

+ \advance\rightskip by 0pt plus 2cm

+ \parfillskip -\rightskip \pretolerance=10000

+ \leavevmode \advance\leftskip\@tempdima \hskip -\leftskip

+ {\large\bfseries\boldmath#1}\ifx0#2\hfil\null

+ \else

+      \nobreak

+      \leaders\hbox{$\m@th \mkern \@dotsep mu.\mkern

+      \@dotsep mu$}\hfill

+      \nobreak\hbox to\@pnumwidth{\hss #2}%

+ \fi\par

+ \penalty\@highpenalty \endgroup}

+

+\def\l@title#1#2{\addpenalty{-\@highpenalty}

+ \addvspace{8pt plus 1pt}

+ \@tempdima \z@

+ \begingroup

+ \parindent \z@ \rightskip \@tocrmarg

+ \advance\rightskip by 0pt plus 2cm

+ \parfillskip -\rightskip \pretolerance=10000

+ \leavevmode \advance\leftskip\@tempdima \hskip -\leftskip

+ #1\nobreak

+ \leaders\hbox{$\m@th \mkern \@dotsep mu.\mkern

+ \@dotsep mu$}\hfill

+ \nobreak\hbox to\@pnumwidth{\hss #2}\par

+ \penalty\@highpenalty \endgroup}

+

+\def\l@author#1#2{\addpenalty{\@highpenalty}

+ \@tempdima=15\p@ %\z@

+ \begingroup

+ \parindent \z@ \rightskip \@tocrmarg

+ \advance\rightskip by 0pt plus 2cm

+ \pretolerance=10000

+ \leavevmode \advance\leftskip\@tempdima %\hskip -\leftskip

+ \textit{#1}\par

+ \penalty\@highpenalty \endgroup}

+

+\setcounter{tocdepth}{0}

+\newdimen\tocchpnum

+\newdimen\tocsecnum

+\newdimen\tocsectotal

+\newdimen\tocsubsecnum

+\newdimen\tocsubsectotal

+\newdimen\tocsubsubsecnum

+\newdimen\tocsubsubsectotal

+\newdimen\tocparanum

+\newdimen\tocparatotal

+\newdimen\tocsubparanum

+\tocchpnum=\z@            % no chapter numbers

+\tocsecnum=15\p@          % section 88. plus 2.222pt

+\tocsubsecnum=23\p@       % subsection 88.8 plus 2.222pt

+\tocsubsubsecnum=27\p@    % subsubsection 88.8.8 plus 1.444pt

+\tocparanum=35\p@         % paragraph 88.8.8.8 plus 1.666pt

+\tocsubparanum=43\p@      % subparagraph 88.8.8.8.8 plus 1.888pt

+\def\calctocindent{%

+\tocsectotal=\tocchpnum

+\advance\tocsectotal by\tocsecnum

+\tocsubsectotal=\tocsectotal

+\advance\tocsubsectotal by\tocsubsecnum

+\tocsubsubsectotal=\tocsubsectotal

+\advance\tocsubsubsectotal by\tocsubsubsecnum

+\tocparatotal=\tocsubsubsectotal

+\advance\tocparatotal by\tocparanum}

+\calctocindent

+

+\def\l@section{\@dottedtocline{1}{\tocchpnum}{\tocsecnum}}

+\def\l@subsection{\@dottedtocline{2}{\tocsectotal}{\tocsubsecnum}}

+\def\l@subsubsection{\@dottedtocline{3}{\tocsubsectotal}{\tocsubsubsecnum}}

+\def\l@paragraph{\@dottedtocline{4}{\tocsubsubsectotal}{\tocparanum}}

+\def\l@subparagraph{\@dottedtocline{5}{\tocparatotal}{\tocsubparanum}}

+

+\def\listoffigures{\@restonecolfalse\if@twocolumn\@restonecoltrue\onecolumn

+ \fi\section*{\listfigurename\@mkboth{{\listfigurename}}{{\listfigurename}}}

+ \@starttoc{lof}\if@restonecol\twocolumn\fi}

+\def\l@figure{\@dottedtocline{1}{0em}{1.5em}}

+

+\def\listoftables{\@restonecolfalse\if@twocolumn\@restonecoltrue\onecolumn

+ \fi\section*{\listtablename\@mkboth{{\listtablename}}{{\listtablename}}}

+ \@starttoc{lot}\if@restonecol\twocolumn\fi}

+\let\l@table\l@figure

+

+\renewcommand\listoffigures{%

+    \section*{\listfigurename

+      \@mkboth{\listfigurename}{\listfigurename}}%

+    \@starttoc{lof}%

+    }

+

+\renewcommand\listoftables{%

+    \section*{\listtablename

+      \@mkboth{\listtablename}{\listtablename}}%

+    \@starttoc{lot}%

+    }

+

+\ifx\oribibl\undefined

+\ifx\citeauthoryear\undefined

+\renewenvironment{thebibliography}[1]

+     {\section*{\refname}

+      \def\@biblabel##1{##1.}

+      \small

+      \list{\@biblabel{\@arabic\c@enumiv}}%

+           {\settowidth\labelwidth{\@biblabel{#1}}%

+            \leftmargin\labelwidth

+            \advance\leftmargin\labelsep

+            \if@openbib

+              \advance\leftmargin\bibindent

+              \itemindent -\bibindent

+              \listparindent \itemindent

+              \parsep \z@

+            \fi

+            \usecounter{enumiv}%

+            \let\p@enumiv\@empty

+            \renewcommand\theenumiv{\@arabic\c@enumiv}}%

+      \if@openbib

+        \renewcommand\newblock{\par}%

+      \else

+        \renewcommand\newblock{\hskip .11em \@plus.33em \@minus.07em}%

+      \fi

+      \sloppy\clubpenalty4000\widowpenalty4000%

+      \sfcode`\.=\@m}

+     {\def\@noitemerr

+       {\@latex@warning{Empty `thebibliography' environment}}%

+      \endlist}

+\def\@lbibitem[#1]#2{\item[{[#1]}\hfill]\if@filesw

+     {\let\protect\noexpand\immediate

+     \write\@auxout{\string\bibcite{#2}{#1}}}\fi\ignorespaces}

+\newcount\@tempcntc

+\def\@citex[#1]#2{\if@filesw\immediate\write\@auxout{\string\citation{#2}}\fi

+  \@tempcnta\z@\@tempcntb\m@ne\def\@citea{}\@cite{\@for\@citeb:=#2\do

+    {\@ifundefined

+       {b@\@citeb}{\@citeo\@tempcntb\m@ne\@citea\def\@citea{,}{\bfseries

+        ?}\@warning

+       {Citation `\@citeb' on page \thepage \space undefined}}%

+    {\setbox\z@\hbox{\global\@tempcntc0\csname b@\@citeb\endcsname\relax}%

+     \ifnum\@tempcntc=\z@ \@citeo\@tempcntb\m@ne

+       \@citea\def\@citea{,}\hbox{\csname b@\@citeb\endcsname}%

+     \else

+      \advance\@tempcntb\@ne

+      \ifnum\@tempcntb=\@tempcntc

+      \else\advance\@tempcntb\m@ne\@citeo

+      \@tempcnta\@tempcntc\@tempcntb\@tempcntc\fi\fi}}\@citeo}{#1}}

+\def\@citeo{\ifnum\@tempcnta>\@tempcntb\else

+               \@citea\def\@citea{,\,\hskip\z@skip}%

+               \ifnum\@tempcnta=\@tempcntb\the\@tempcnta\else

+               {\advance\@tempcnta\@ne\ifnum\@tempcnta=\@tempcntb \else

+                \def\@citea{--}\fi

+      \advance\@tempcnta\m@ne\the\@tempcnta\@citea\the\@tempcntb}\fi\fi}

+\else

+\renewenvironment{thebibliography}[1]

+     {\section*{\refname}

+      \small

+      \list{}%

+           {\settowidth\labelwidth{}%

+            \leftmargin\parindent

+            \itemindent=-\parindent

+            \labelsep=\z@

+            \if@openbib

+              \advance\leftmargin\bibindent

+              \itemindent -\bibindent

+              \listparindent \itemindent

+              \parsep \z@

+            \fi

+            \usecounter{enumiv}%

+            \let\p@enumiv\@empty

+            \renewcommand\theenumiv{}}%

+      \if@openbib

+        \renewcommand\newblock{\par}%

+      \else

+        \renewcommand\newblock{\hskip .11em \@plus.33em \@minus.07em}%

+      \fi

+      \sloppy\clubpenalty4000\widowpenalty4000%

+      \sfcode`\.=\@m}

+     {\def\@noitemerr

+       {\@latex@warning{Empty `thebibliography' environment}}%

+      \endlist}

+      \def\@cite#1{#1}%

+      \def\@lbibitem[#1]#2{\item[]\if@filesw

+        {\def\protect##1{\string ##1\space}\immediate

+      \write\@auxout{\string\bibcite{#2}{#1}}}\fi\ignorespaces}

+   \fi

+\else

+\@cons\@openbib@code{\noexpand\small}

+\fi

+

+\def\idxquad{\hskip 10\p@}% space that divides entry from number

+

+\def\@idxitem{\par\hangindent 10\p@}

+

+\def\subitem{\par\setbox0=\hbox{--\enspace}% second order

+                \noindent\hangindent\wd0\box0}% index entry

+

+\def\subsubitem{\par\setbox0=\hbox{--\,--\enspace}% third

+                \noindent\hangindent\wd0\box0}% order index entry

+

+\def\indexspace{\par \vskip 10\p@ plus5\p@ minus3\p@\relax}

+

+\renewenvironment{theindex}

+               {\@mkboth{\indexname}{\indexname}%

+                \thispagestyle{empty}\parindent\z@

+                \parskip\z@ \@plus .3\p@\relax

+                \let\item\par

+                \def\,{\relax\ifmmode\mskip\thinmuskip

+                             \else\hskip0.2em\ignorespaces\fi}%

+                \normalfont\small

+                \begin{multicols}{2}[\@makeschapterhead{\indexname}]%

+                }

+                {\end{multicols}}

+

+\renewcommand\footnoterule{%

+  \kern-3\p@

+  \hrule\@width 2truecm

+  \kern2.6\p@}

+  \newdimen\fnindent

+  \fnindent1em

+\long\def\@makefntext#1{%

+    \parindent \fnindent%

+    \leftskip \fnindent%

+    \noindent

+    \llap{\hb@xt@1em{\hss\@makefnmark\ }}\ignorespaces#1}

+

+\long\def\@makecaption#1#2{%

+  \vskip\abovecaptionskip

+  \sbox\@tempboxa{{\bfseries #1.} #2}%

+  \ifdim \wd\@tempboxa >\hsize

+    {\bfseries #1.} #2\par

+  \else

+    \global \@minipagefalse

+    \hb@xt@\hsize{\hfil\box\@tempboxa\hfil}%

+  \fi

+  \vskip\belowcaptionskip}

+

+\def\fps@figure{htbp}

+\def\fnum@figure{\figurename\thinspace\thefigure}

+\def \@floatboxreset {%

+        \reset@font

+        \small

+        \@setnobreak

+        \@setminipage

+}

+\def\fps@table{htbp}

+\def\fnum@table{\tablename~\thetable}

+\renewenvironment{table}

+               {\setlength\abovecaptionskip{0\p@}%

+                \setlength\belowcaptionskip{10\p@}%

+                \@float{table}}

+               {\end@float}

+\renewenvironment{table*}

+               {\setlength\abovecaptionskip{0\p@}%

+                \setlength\belowcaptionskip{10\p@}%

+                \@dblfloat{table}}

+               {\end@dblfloat}

+

+\long\def\@caption#1[#2]#3{\par\addcontentsline{\csname

+  ext@#1\endcsname}{#1}{\protect\numberline{\csname

+  the#1\endcsname}{\ignorespaces #2}}\begingroup

+    \@parboxrestore

+    \@makecaption{\csname fnum@#1\endcsname}{\ignorespaces #3}\par

+  \endgroup}

+

+% LaTeX does not provide a command to enter the authors institute

+% addresses. The \institute command is defined here.

+

+\newcounter{@inst}

+\newcounter{@auth}

+\newcounter{auco}

+\newdimen\instindent

+\newbox\authrun

+\newtoks\authorrunning

+\newtoks\tocauthor

+\newbox\titrun

+\newtoks\titlerunning

+\newtoks\toctitle

+

+\def\clearheadinfo{\gdef\@author{No Author Given}%

+                   \gdef\@title{No Title Given}%

+                   \gdef\@subtitle{}%

+                   \gdef\@institute{No Institute Given}%

+                   \gdef\@thanks{}%

+                   \global\titlerunning={}\global\authorrunning={}%

+                   \global\toctitle={}\global\tocauthor={}}

+

+\def\institute#1{\gdef\@institute{#1}}

+

+\def\institutename{\par

+ \begingroup

+ \parskip=\z@

+ \parindent=\z@

+ \setcounter{@inst}{1}%

+ \def\and{\par\stepcounter{@inst}%

+ \noindent$^{\the@inst}$\enspace\ignorespaces}%

+ \setbox0=\vbox{\def\thanks##1{}\@institute}%

+ \ifnum\c@@inst=1\relax

+   \gdef\fnnstart{0}%

+ \else

+   \xdef\fnnstart{\c@@inst}%

+   \setcounter{@inst}{1}%

+   \noindent$^{\the@inst}$\enspace

+ \fi

+ \ignorespaces

+ \@institute\par

+ \endgroup}

+

+\def\@fnsymbol#1{\ensuremath{\ifcase#1\or\star\or{\star\star}\or

+   {\star\star\star}\or \dagger\or \ddagger\or

+   \mathchar "278\or \mathchar "27B\or \|\or **\or \dagger\dagger

+   \or \ddagger\ddagger \else\@ctrerr\fi}}

+

+\def\inst#1{\unskip$^{#1}$}

+\def\fnmsep{\unskip$^,$}

+\def\email#1{{\tt#1}}

+\AtBeginDocument{\@ifundefined{url}{\def\url#1{#1}}{}%

+\@ifpackageloaded{babel}{%

+\@ifundefined{extrasenglish}{}{\addto\extrasenglish{\switcht@albion}}%

+\@ifundefined{extrasfrenchb}{}{\addto\extrasfrenchb{\switcht@francais}}%

+\@ifundefined{extrasgerman}{}{\addto\extrasgerman{\switcht@deutsch}}%

+}{\switcht@@therlang}%

+}

+\def\homedir{\~{ }}

+

+\def\subtitle#1{\gdef\@subtitle{#1}}

+\clearheadinfo

+%

+\renewcommand\maketitle{\newpage

+  \refstepcounter{chapter}%

+  \stepcounter{section}%

+  \setcounter{section}{0}%

+  \setcounter{subsection}{0}%

+  \setcounter{figure}{0}

+  \setcounter{table}{0}

+  \setcounter{equation}{0}

+  \setcounter{footnote}{0}%

+  \begingroup

+    \parindent=\z@

+    \renewcommand\thefootnote{\@fnsymbol\c@footnote}%

+    \if@twocolumn

+      \ifnum \col@number=\@ne

+        \@maketitle

+      \else

+        \twocolumn[\@maketitle]%

+      \fi

+    \else

+      \newpage

+      \global\@topnum\z@   % Prevents figures from going at top of page.

+      \@maketitle

+    \fi

+    \thispagestyle{empty}\@thanks

+%

+    \def\\{\unskip\ \ignorespaces}\def\inst##1{\unskip{}}%

+    \def\thanks##1{\unskip{}}\def\fnmsep{\unskip}%

+    \instindent=\hsize

+    \advance\instindent by-\headlineindent

+    \if!\the\toctitle!\addcontentsline{toc}{title}{\@title}\else

+       \addcontentsline{toc}{title}{\the\toctitle}\fi

+    \if@runhead

+       \if!\the\titlerunning!\else

+         \edef\@title{\the\titlerunning}%

+       \fi

+       \global\setbox\titrun=\hbox{\small\rm\unboldmath\ignorespaces\@title}%

+       \ifdim\wd\titrun>\instindent

+          \typeout{Title too long for running head. Please supply}%

+          \typeout{a shorter form with \string\titlerunning\space prior to

+                   \string\maketitle}%

+          \global\setbox\titrun=\hbox{\small\rm

+          Title Suppressed Due to Excessive Length}%

+       \fi

+       \xdef\@title{\copy\titrun}%

+    \fi

+%

+    \if!\the\tocauthor!\relax

+      {\def\and{\noexpand\protect\noexpand\and}%

+      \protected@xdef\toc@uthor{\@author}}%

+    \else

+      \def\\{\noexpand\protect\noexpand\newline}%

+      \protected@xdef\scratch{\the\tocauthor}%

+      \protected@xdef\toc@uthor{\scratch}%

+    \fi

+    \addtocontents{toc}{\noexpand\protect\noexpand\authcount{\the\c@auco}}%

+    \addcontentsline{toc}{author}{\toc@uthor}%

+    \if@runhead

+       \if!\the\authorrunning!

+         \value{@inst}=\value{@auth}%

+         \setcounter{@auth}{1}%

+       \else

+         \edef\@author{\the\authorrunning}%

+       \fi

+       \global\setbox\authrun=\hbox{\small\unboldmath\@author\unskip}%

+       \ifdim\wd\authrun>\instindent

+          \typeout{Names of authors too long for running head. Please supply}%

+          \typeout{a shorter form with \string\authorrunning\space prior to

+                   \string\maketitle}%

+          \global\setbox\authrun=\hbox{\small\rm

+          Authors Suppressed Due to Excessive Length}%

+       \fi

+       \xdef\@author{\copy\authrun}%

+       \markboth{\@author}{\@title}%

+     \fi

+  \endgroup

+  \setcounter{footnote}{\fnnstart}%

+  \clearheadinfo}

+%

+\def\@maketitle{\newpage

+ \markboth{}{}%

+ \def\lastand{\ifnum\value{@inst}=2\relax

+                 \unskip{} \andname\

+              \else

+                 \unskip \lastandname\

+              \fi}%

+ \def\and{\stepcounter{@auth}\relax

+          \ifnum\value{@auth}=\value{@inst}%

+             \lastand

+          \else

+             \unskip,

+          \fi}%

+ \begin{center}%

+ \let\newline\\

+ {\Large \bfseries\boldmath

+  \pretolerance=10000

+  \@title \par}\vskip .8cm

+\if!\@subtitle!\else {\large \bfseries\boldmath

+  \vskip -.65cm

+  \pretolerance=10000

+  \@subtitle \par}\vskip .8cm\fi

+ \setbox0=\vbox{\setcounter{@auth}{1}\def\and{\stepcounter{@auth}}%

+ \def\thanks##1{}\@author}%

+ \global\value{@inst}=\value{@auth}%

+ \global\value{auco}=\value{@auth}%

+ \setcounter{@auth}{1}%

+{\lineskip .5em

+\noindent\ignorespaces

+\@author\vskip.35cm}

+ {\small\institutename}

+ \end{center}%

+ }

+

+% definition of the "\spnewtheorem" command.

+%

+% Usage:

+%

+%     \spnewtheorem{env_nam}{caption}[within]{cap_font}{body_font}

+% or  \spnewtheorem{env_nam}[numbered_like]{caption}{cap_font}{body_font}

+% or  \spnewtheorem*{env_nam}{caption}{cap_font}{body_font}

+%

+% New is "cap_font" and "body_font". It stands for

+% fontdefinition of the caption and the text itself.

+%

+% "\spnewtheorem*" gives a theorem without number.

+%

+% A defined spnewthoerem environment is used as described

+% by Lamport.

+%

+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

+

+\def\@thmcountersep{}

+\def\@thmcounterend{.}

+

+\def\spnewtheorem{\@ifstar{\@sthm}{\@Sthm}}

+

+% definition of \spnewtheorem with number

+

+\def\@spnthm#1#2{%

+  \@ifnextchar[{\@spxnthm{#1}{#2}}{\@spynthm{#1}{#2}}}

+\def\@Sthm#1{\@ifnextchar[{\@spothm{#1}}{\@spnthm{#1}}}

+

+\def\@spxnthm#1#2[#3]#4#5{\expandafter\@ifdefinable\csname #1\endcsname

+   {\@definecounter{#1}\@addtoreset{#1}{#3}%

+   \expandafter\xdef\csname the#1\endcsname{\expandafter\noexpand

+     \csname the#3\endcsname \noexpand\@thmcountersep \@thmcounter{#1}}%

+   \expandafter\xdef\csname #1name\endcsname{#2}%

+   \global\@namedef{#1}{\@spthm{#1}{\csname #1name\endcsname}{#4}{#5}}%

+                              \global\@namedef{end#1}{\@endtheorem}}}

+

+\def\@spynthm#1#2#3#4{\expandafter\@ifdefinable\csname #1\endcsname

+   {\@definecounter{#1}%

+   \expandafter\xdef\csname the#1\endcsname{\@thmcounter{#1}}%

+   \expandafter\xdef\csname #1name\endcsname{#2}%

+   \global\@namedef{#1}{\@spthm{#1}{\csname #1name\endcsname}{#3}{#4}}%

+                               \global\@namedef{end#1}{\@endtheorem}}}

+

+\def\@spothm#1[#2]#3#4#5{%

+  \@ifundefined{c@#2}{\@latexerr{No theorem environment `#2' defined}\@eha}%

+  {\expandafter\@ifdefinable\csname #1\endcsname

+  {\global\@namedef{the#1}{\@nameuse{the#2}}%

+  \expandafter\xdef\csname #1name\endcsname{#3}%

+  \global\@namedef{#1}{\@spthm{#2}{\csname #1name\endcsname}{#4}{#5}}%

+  \global\@namedef{end#1}{\@endtheorem}}}}

+

+\def\@spthm#1#2#3#4{\topsep 7\p@ \@plus2\p@ \@minus4\p@

+\refstepcounter{#1}%

+\@ifnextchar[{\@spythm{#1}{#2}{#3}{#4}}{\@spxthm{#1}{#2}{#3}{#4}}}

+

+\def\@spxthm#1#2#3#4{\@spbegintheorem{#2}{\csname the#1\endcsname}{#3}{#4}%

+                    \ignorespaces}

+

+\def\@spythm#1#2#3#4[#5]{\@spopargbegintheorem{#2}{\csname

+       the#1\endcsname}{#5}{#3}{#4}\ignorespaces}

+

+\def\@spbegintheorem#1#2#3#4{\trivlist

+                 \item[\hskip\labelsep{#3#1\ #2\@thmcounterend}]#4}

+

+\def\@spopargbegintheorem#1#2#3#4#5{\trivlist

+      \item[\hskip\labelsep{#4#1\ #2}]{#4(#3)\@thmcounterend\ }#5}

+

+% definition of \spnewtheorem* without number

+

+\def\@sthm#1#2{\@Ynthm{#1}{#2}}

+

+\def\@Ynthm#1#2#3#4{\expandafter\@ifdefinable\csname #1\endcsname

+   {\global\@namedef{#1}{\@Thm{\csname #1name\endcsname}{#3}{#4}}%

+    \expandafter\xdef\csname #1name\endcsname{#2}%

+    \global\@namedef{end#1}{\@endtheorem}}}

+

+\def\@Thm#1#2#3{\topsep 7\p@ \@plus2\p@ \@minus4\p@

+\@ifnextchar[{\@Ythm{#1}{#2}{#3}}{\@Xthm{#1}{#2}{#3}}}

+

+\def\@Xthm#1#2#3{\@Begintheorem{#1}{#2}{#3}\ignorespaces}

+

+\def\@Ythm#1#2#3[#4]{\@Opargbegintheorem{#1}

+       {#4}{#2}{#3}\ignorespaces}

+

+\def\@Begintheorem#1#2#3{#3\trivlist

+                           \item[\hskip\labelsep{#2#1\@thmcounterend}]}

+

+\def\@Opargbegintheorem#1#2#3#4{#4\trivlist

+      \item[\hskip\labelsep{#3#1}]{#3(#2)\@thmcounterend\ }}

+

+\if@envcntsect

+   \def\@thmcountersep{.}

+   \spnewtheorem{theorem}{Theorem}[section]{\bfseries}{\itshape}

+\else

+   \spnewtheorem{theorem}{Theorem}{\bfseries}{\itshape}

+   \if@envcntreset

+      \@addtoreset{theorem}{section}

+   \else

+      \@addtoreset{theorem}{chapter}

+   \fi

+\fi

+

+%definition of divers theorem environments

+\spnewtheorem*{claim}{Claim}{\itshape}{\rmfamily}

+\spnewtheorem*{proof}{Proof}{\itshape}{\rmfamily}

+\if@envcntsame % alle Umgebungen wie Theorem.

+   \def\spn@wtheorem#1#2#3#4{\@spothm{#1}[theorem]{#2}{#3}{#4}}

+\else % alle Umgebungen mit eigenem Zaehler

+   \if@envcntsect % mit section numeriert

+      \def\spn@wtheorem#1#2#3#4{\@spxnthm{#1}{#2}[section]{#3}{#4}}

+   \else % nicht mit section numeriert

+      \if@envcntreset

+         \def\spn@wtheorem#1#2#3#4{\@spynthm{#1}{#2}{#3}{#4}

+                                   \@addtoreset{#1}{section}}

+      \else

+         \def\spn@wtheorem#1#2#3#4{\@spynthm{#1}{#2}{#3}{#4}

+                                   \@addtoreset{#1}{chapter}}%

+      \fi

+   \fi

+\fi

+\spn@wtheorem{case}{Case}{\itshape}{\rmfamily}

+\spn@wtheorem{conjecture}{Conjecture}{\itshape}{\rmfamily}

+\spn@wtheorem{corollary}{Corollary}{\bfseries}{\itshape}

+\spn@wtheorem{definition}{Definition}{\bfseries}{\itshape}

+\spn@wtheorem{example}{Example}{\itshape}{\rmfamily}

+\spn@wtheorem{exercise}{Exercise}{\itshape}{\rmfamily}

+\spn@wtheorem{lemma}{Lemma}{\bfseries}{\itshape}

+\spn@wtheorem{note}{Note}{\itshape}{\rmfamily}

+\spn@wtheorem{problem}{Problem}{\itshape}{\rmfamily}

+\spn@wtheorem{property}{Property}{\itshape}{\rmfamily}

+\spn@wtheorem{proposition}{Proposition}{\bfseries}{\itshape}

+\spn@wtheorem{question}{Question}{\itshape}{\rmfamily}

+\spn@wtheorem{solution}{Solution}{\itshape}{\rmfamily}

+\spn@wtheorem{remark}{Remark}{\itshape}{\rmfamily}

+

+\def\@takefromreset#1#2{%

+    \def\@tempa{#1}%

+    \let\@tempd\@elt

+    \def\@elt##1{%

+        \def\@tempb{##1}%

+        \ifx\@tempa\@tempb\else

+            \@addtoreset{##1}{#2}%

+        \fi}%

+    \expandafter\expandafter\let\expandafter\@tempc\csname cl@#2\endcsname

+    \expandafter\def\csname cl@#2\endcsname{}%

+    \@tempc

+    \let\@elt\@tempd}

+

+\def\theopargself{\def\@spopargbegintheorem##1##2##3##4##5{\trivlist

+      \item[\hskip\labelsep{##4##1\ ##2}]{##4##3\@thmcounterend\ }##5}

+                  \def\@Opargbegintheorem##1##2##3##4{##4\trivlist

+      \item[\hskip\labelsep{##3##1}]{##3##2\@thmcounterend\ }}

+      }

+

+\renewenvironment{abstract}{%

+      \list{}{\advance\topsep by0.35cm\relax\small

+      \leftmargin=1cm

+      \labelwidth=\z@

+      \listparindent=\z@

+      \itemindent\listparindent

+      \rightmargin\leftmargin}\item[\hskip\labelsep

+                                    \bfseries\abstractname]}

+    {\endlist}

+

+\newdimen\headlineindent             % dimension for space between

+\headlineindent=1.166cm              % number and text of headings.

+

+\def\ps@headings{\let\@mkboth\@gobbletwo

+   \let\@oddfoot\@empty\let\@evenfoot\@empty

+   \def\@evenhead{\normalfont\small\rlap{\thepage}\hspace{\headlineindent}%

+                  \leftmark\hfil}

+   \def\@oddhead{\normalfont\small\hfil\rightmark\hspace{\headlineindent}%

+                 \llap{\thepage}}

+   \def\chaptermark##1{}%

+   \def\sectionmark##1{}%

+   \def\subsectionmark##1{}}

+

+\def\ps@titlepage{\let\@mkboth\@gobbletwo

+   \let\@oddfoot\@empty\let\@evenfoot\@empty

+   \def\@evenhead{\normalfont\small\rlap{\thepage}\hspace{\headlineindent}%

+                  \hfil}

+   \def\@oddhead{\normalfont\small\hfil\hspace{\headlineindent}%

+                 \llap{\thepage}}

+   \def\chaptermark##1{}%

+   \def\sectionmark##1{}%

+   \def\subsectionmark##1{}}

+

+\if@runhead\ps@headings\else

+\ps@empty\fi

+

+\setlength\arraycolsep{1.4\p@}

+\setlength\tabcolsep{1.4\p@}

+

+\endinput

+%end of file llncs.cls

diff --git a/docs/latex/words.eps b/docs/latex/words.eps
new file mode 100644
index 0000000..6651c4b
--- /dev/null
+++ b/docs/latex/words.eps
@@ -0,0 +1,469 @@
+%!PS-Adobe-2.0 EPSF-2.0

+%%Title: C:\Users\Shamus\Pictures\words.dia

+%%Creator: Dia v0.97.2

+%%CreationDate: Tue Jul 29 11:17:31 2014

+%%For: Shamus

+%%Orientation: Portrait

+%%Magnification: 1.0000

+%%BoundingBox: 0 0 966 249

+%%BeginSetup

+%%EndSetup

+%%EndComments

+%%BeginProlog

+[ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef

+/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef

+/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef

+/.notdef /.notdef /space /exclam /quotedbl /numbersign /dollar /percent /ampersand /quoteright

+/parenleft /parenright /asterisk /plus /comma /hyphen /period /slash /zero /one

+/two /three /four /five /six /seven /eight /nine /colon /semicolon

+/less /equal /greater /question /at /A /B /C /D /E

+/F /G /H /I /J /K /L /M /N /O

+/P /Q /R /S /T /U /V /W /X /Y

+/Z /bracketleft /backslash /bracketright /asciicircum /underscore /quoteleft /a /b /c

+/d /e /f /g /h /i /j /k /l /m

+/n /o /p /q /r /s /t /u /v /w

+/x /y /z /braceleft /bar /braceright /asciitilde /.notdef /.notdef /.notdef

+/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef

+/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef

+/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef

+/space /exclamdown /cent /sterling /currency /yen /brokenbar /section /dieresis /copyright

+/ordfeminine /guillemotleft /logicalnot /hyphen /registered /macron /degree /plusminus /twosuperior /threesuperior

+/acute /mu /paragraph /periodcentered /cedilla /onesuperior /ordmasculine /guillemotright /onequarter /onehalf

+/threequarters /questiondown /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla

+/Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth /Ntilde

+/Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply /Oslash /Ugrave /Uacute /Ucircumflex

+/Udieresis /Yacute /Thorn /germandbls /agrave /aacute /acircumflex /atilde /adieresis /aring

+/ae /ccedilla /egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis

+/eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide /oslash /ugrave

+/uacute /ucircumflex /udieresis /yacute /thorn /ydieresis] /isolatin1encoding exch def

+/cp {closepath} bind def

+/c {curveto} bind def

+/f {fill} bind def

+/a {arc} bind def

+/ef {eofill} bind def

+/ex {exch} bind def

+/gr {grestore} bind def

+/gs {gsave} bind def

+/sa {save} bind def

+/rs {restore} bind def

+/l {lineto} bind def

+/m {moveto} bind def

+/rm {rmoveto} bind def

+/n {newpath} bind def

+/s {stroke} bind def

+/sh {show} bind def

+/slc {setlinecap} bind def

+/slj {setlinejoin} bind def

+/slw {setlinewidth} bind def

+/srgb {setrgbcolor} bind def

+/rot {rotate} bind def

+/sc {scale} bind def

+/sd {setdash} bind def

+/ff {findfont} bind def

+/sf {setfont} bind def

+/scf {scalefont} bind def

+/sw {stringwidth pop} bind def

+/tr {translate} bind def

+

+/ellipsedict 8 dict def

+ellipsedict /mtrx matrix put

+/ellipse

+{ ellipsedict begin

+   /endangle exch def

+   /startangle exch def

+   /yrad exch def

+   /xrad exch def

+   /y exch def

+   /x exch def   /savematrix mtrx currentmatrix def

+   x y tr xrad yrad sc

+   0 0 1 startangle endangle arc

+   savematrix setmatrix

+   end

+} def

+

+/mergeprocs {

+dup length

+3 -1 roll

+dup

+length

+dup

+5 1 roll

+3 -1 roll

+add

+array cvx

+dup

+3 -1 roll

+0 exch

+putinterval

+dup

+4 2 roll

+putinterval

+} bind def

+/Times-Roman-latin1

+    /Times-Roman findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Times-Italic-latin1

+    /Times-Italic findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Times-Bold-latin1

+    /Times-Bold findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Times-BoldItalic-latin1

+    /Times-BoldItalic findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/AvantGarde-Gothic-latin1

+    /AvantGarde-Gothic findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/AvantGarde-BookOblique-latin1

+    /AvantGarde-BookOblique findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/AvantGarde-Demi-latin1

+    /AvantGarde-Demi findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/AvantGarde-DemiOblique-latin1

+    /AvantGarde-DemiOblique findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Bookman-Light-latin1

+    /Bookman-Light findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Bookman-LightItalic-latin1

+    /Bookman-LightItalic findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Bookman-Demi-latin1

+    /Bookman-Demi findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Bookman-DemiItalic-latin1

+    /Bookman-DemiItalic findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Courier-latin1

+    /Courier findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Courier-Oblique-latin1

+    /Courier-Oblique findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Courier-Bold-latin1

+    /Courier-Bold findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Courier-BoldOblique-latin1

+    /Courier-BoldOblique findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Helvetica-latin1

+    /Helvetica findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Helvetica-Oblique-latin1

+    /Helvetica-Oblique findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Helvetica-Bold-latin1

+    /Helvetica-Bold findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Helvetica-BoldOblique-latin1

+    /Helvetica-BoldOblique findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Helvetica-Narrow-latin1

+    /Helvetica-Narrow findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Helvetica-Narrow-Oblique-latin1

+    /Helvetica-Narrow-Oblique findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Helvetica-Narrow-Bold-latin1

+    /Helvetica-Narrow-Bold findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Helvetica-Narrow-BoldOblique-latin1

+    /Helvetica-Narrow-BoldOblique findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/NewCenturySchlbk-Roman-latin1

+    /NewCenturySchlbk-Roman findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/NewCenturySchlbk-Italic-latin1

+    /NewCenturySchlbk-Italic findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/NewCenturySchlbk-Bold-latin1

+    /NewCenturySchlbk-Bold findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/NewCenturySchlbk-BoldItalic-latin1

+    /NewCenturySchlbk-BoldItalic findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Palatino-Roman-latin1

+    /Palatino-Roman findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Palatino-Italic-latin1

+    /Palatino-Italic findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Palatino-Bold-latin1

+    /Palatino-Bold findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Palatino-BoldItalic-latin1

+    /Palatino-BoldItalic findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/Symbol-latin1

+    /Symbol findfont

+definefont pop

+/ZapfChancery-MediumItalic-latin1

+    /ZapfChancery-MediumItalic findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+/ZapfDingbats-latin1

+    /ZapfDingbats findfont

+    dup length dict begin

+	{1 index /FID ne {def} {pop pop} ifelse} forall

+	/Encoding isolatin1encoding def

+    currentdict end

+definefont pop

+28.346000 -28.346000 scale

+-4.000000 2.867500 translate

+%%EndProlog

+

+

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slj

+0.000000 0.000000 0.000000 srgb

+n 5.000000 -10.000000 m 5.000000 -7.000000 l 14.000000 -7.000000 l 14.000000 -10.000000 l cp s

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slc

+n 8.000000 -10.000000 m 8.000000 -7.000000 l s

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slj

+n 15.000000 -10.000000 m 15.000000 -7.000000 l 24.000000 -7.000000 l 24.000000 -10.000000 l cp s

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slc

+n 16.000000 -10.000000 m 16.000000 -7.000000 l s

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slj

+n 29.000000 -10.000000 m 29.000000 -7.000000 l 38.000000 -7.000000 l 38.000000 -10.000000 l cp s

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slc

+n 30.000000 -10.000000 m 30.000000 -7.000000 l s

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slc

+n 11.000000 -10.000000 m 11.000000 -7.000000 l s

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slc

+n 6.000000 -10.000000 m 6.000000 -7.000000 l s

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slc

+n 18.000000 -10.000000 m 18.000000 -7.000000 l s

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slc

+n 32.000000 -10.000000 m 32.000000 -7.000000 l s

+/Helvetica-latin1 ff 0.560000 scf sf

+(Sign bit) 4.000000 -3.120000 m

+ gs 1 -1 sc sh gr

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slc

+n 5.000000 -4.000000 m 5.000000 -5.513197 l s

+[] 0 sd

+0 slj

+0 slc

+n 5.000000 -5.888197 m 5.250000 -5.388197 l 5.000000 -5.513197 l 4.750000 -5.388197 l ef

+n 5.000000 -5.888197 m 5.250000 -5.388197 l 5.000000 -5.513197 l 4.750000 -5.388197 l cp s

+/Helvetica-latin1 ff 0.560000 scf sf

+(Field Excess) 8.000000 -3.120000 m

+ gs 1 -1 sc sh gr

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slc

+n 9.000000 -4.000000 m 9.000000 -5.513197 l s

+[] 0 sd

+0 slj

+0 slc

+n 9.000000 -5.888197 m 9.250000 -5.388197 l 9.000000 -5.513197 l 8.750000 -5.388197 l ef

+n 9.000000 -5.888197 m 9.250000 -5.388197 l 9.000000 -5.513197 l 8.750000 -5.388197 l cp s

+/Helvetica-latin1 ff 0.560000 scf sf

+(Word Excess) 15.000000 -3.120000 m

+ gs 1 -1 sc sh gr

+/Helvetica-latin1 ff 0.560000 scf sf

+(Word Excess) 29.000000 -3.120000 m

+ gs 1 -1 sc sh gr

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slc

+n 17.000000 -4.000000 m 17.000000 -5.513197 l s

+[] 0 sd

+0 slj

+0 slc

+n 17.000000 -5.888197 m 17.250000 -5.388197 l 17.000000 -5.513197 l 16.750000 -5.388197 l ef

+n 17.000000 -5.888197 m 17.250000 -5.388197 l 17.000000 -5.513197 l 16.750000 -5.388197 l cp s

+0.100000 slw

+[] 0 sd

+[] 0 sd

+0 slc

+n 31.000000 -4.000000 m 31.000000 -5.513197 l s

+[] 0 sd

+0 slj

+0 slc

+n 31.000000 -5.888197 m 31.250000 -5.388197 l 31.000000 -5.513197 l 30.750000 -5.388197 l ef

+n 31.000000 -5.888197 m 31.250000 -5.388197 l 31.000000 -5.513197 l 30.750000 -5.388197 l cp s

+/Helvetica-latin1 ff 0.560000 scf sf

+(Base Bits) 20.000000 -8.120000 m

+ gs 1 -1 sc sh gr

+/Helvetica-latin1 ff 0.560000 scf sf

+(Base Bits) 34.000000 -8.120000 m

+ gs 1 -1 sc sh gr

+/Helvetica-latin1 ff 0.560000 scf sf

+(Top Bits) 11.000000 -8.120000 m

+ gs 1 -1 sc sh gr

+/Helvetica-latin1 ff 0.560000 scf sf

+(..........) 26.000000 -7.120000 m

+ gs 1 -1 sc sh gr

+/Helvetica-latin1 ff 0.560000 scf sf

+(Most Significant Word) 7.000000 -11.120000 m

+ gs 1 -1 sc sh gr

+/Helvetica-latin1 ff 0.560000 scf sf

+(Least Significant Word) 30.000000 -11.120000 m

+ gs 1 -1 sc sh gr

+showpage

diff --git a/go/src/github.com/miracl/amcl-cgo/README.txt b/go/src/github.com/miracl/amcl-cgo/README.txt
new file mode 100644
index 0000000..79b1cee
--- /dev/null
+++ b/go/src/github.com/miracl/amcl-cgo/README.txt
@@ -0,0 +1,9 @@
+When the library is built with;
+
+-D USE_ANONYMOUS=on 
+
+then set
+
+const USE_ANONYMOUS = true
+
+in crypto_test.go
diff --git a/go/src/github.com/miracl/amcl-cgo/crypto.go b/go/src/github.com/miracl/amcl-cgo/crypto.go
index 38ac3ad..2207490 100644
--- a/go/src/github.com/miracl/amcl-cgo/crypto.go
+++ b/go/src/github.com/miracl/amcl-cgo/crypto.go
@@ -20,8 +20,8 @@
 package amcl
 
 /*
-#cgo CFLAGS:  -std=c99 -O3 -I/usr/local/include/amcl
-#cgo LDFLAGS: -L/usr/local/lib -lmpin  -lamcl -lm
+#cgo CFLAGS:  -std=c99 -O3 -I/opt/amcl/include
+#cgo LDFLAGS: -L/opt/amcl/lib -lmpin  -lamcl -lm
 #include <stdio.h>
 #include <stdlib.h>
 #include "amcl.h"
@@ -122,7 +122,7 @@
 
 /* return time in slots since epoch */
 func MPIN_today() int {
-	date := C.today()
+	date := C.MPIN_today()
 	return int(date)
 }
 
@@ -132,12 +132,12 @@
 	return int(timeValue)
 }
 
-func CREATE_CSPRNG(RNG *C.csprng, SEED []byte) {
+func MPIN_CREATE_CSPRNG(RNG *C.csprng, SEED []byte) {
 	// Form Octet
 	SEEDStr := string(SEED)
 	SEEDOct := GetOctet(SEEDStr)
 	defer OCT_free(&SEEDOct)
-	C.CREATE_CSPRNG(RNG, &SEEDOct)
+	C.MPIN_CREATE_CSPRNG(RNG, &SEEDOct)
 }
 
 func MPIN_HASH_ID(ID []byte) (HASHID []byte) {
@@ -476,7 +476,7 @@
 
 /* calculate common key on server side */
 /* Z=r.A - no time permits involved */
-func MPIN_SERVER_KEY_WRAP(Z, SS, W, U, UT []byte) (errorCode int, SK []byte) {
+func MPIN_SERVER_KEY_WRAP(Z, SS, W, P, I, U, UT []byte) (errorCode int, SK []byte) {
 	ZStr := string(Z)
 	ZOct := GetOctet(ZStr)
 	defer OCT_free(&ZOct)
@@ -486,6 +486,12 @@
 	WStr := string(W)
 	WOct := GetOctet(WStr)
 	defer OCT_free(&WOct)
+	PStr := string(P)
+	POct := GetOctet(PStr)
+	defer OCT_free(&POct)
+	IStr := string(I)
+	IOct := GetOctet(IStr)
+	defer OCT_free(&IOct)
 	UStr := string(U)
 	UOct := GetOctet(UStr)
 	defer OCT_free(&UOct)
@@ -496,7 +502,7 @@
 	SKOct := GetOctetZero(EAS)
 	defer OCT_free(&SKOct)
 
-	rtn := C.MPIN_SERVER_KEY(&ZOct, &SSOct, &WOct, &UOct, &UTOct, &SKOct)
+	rtn := C.MPIN_SERVER_KEY(&ZOct, &SSOct, &WOct, &POct, &IOct, &UOct, &UTOct, &SKOct)
 	errorCode = int(rtn)
 
 	// Convert octet to bytes
@@ -507,7 +513,7 @@
 
 /* calculate common key on client side */
 /* wCID = w.(A+AT) */
-func MPIN_CLIENT_KEY_WRAP(PIN int, GT1, GT2, R, X, T []byte) (errorCode int, CK []byte) {
+func MPIN_CLIENT_KEY_WRAP(PIN int, GT1, GT2, R, X, P, T []byte) (errorCode int, CK []byte) {
 	GT1Str := string(GT1)
 	GT1Oct := GetOctet(GT1Str)
 	defer OCT_free(&GT1Oct)
@@ -520,6 +526,9 @@
 	XStr := string(X)
 	XOct := GetOctet(XStr)
 	defer OCT_free(&XOct)
+	PStr := string(P)
+	POct := GetOctet(PStr)
+	defer OCT_free(&POct)
 	TStr := string(T)
 	TOct := GetOctet(TStr)
 	defer OCT_free(&TOct)
@@ -527,7 +536,7 @@
 	CKOct := GetOctetZero(EAS)
 	defer OCT_free(&CKOct)
 
-	rtn := C.MPIN_CLIENT_KEY(&GT1Oct, &GT2Oct, C.int(PIN), &ROct, &XOct, &TOct, &CKOct)
+	rtn := C.MPIN_CLIENT_KEY(&GT1Oct, &GT2Oct, C.int(PIN), &ROct, &XOct, &POct, &TOct, &CKOct)
 	errorCode = int(rtn)
 
 	// Convert octet to bytes
@@ -558,7 +567,7 @@
 /* AES-GCM Encryption:
    K is key, H is header, IV is initialization vector and P is plaintext.
    Returns cipthertext and tag (MAC) */
-func AES_GCM_ENCRYPT(K, IV, H, P []byte) ([]byte, []byte) {
+func MPIN_AES_GCM_ENCRYPT(K, IV, H, P []byte) ([]byte, []byte) {
 	KStr := string(K)
 	KOct := GetOctet(KStr)
 	defer OCT_free(&KOct)
@@ -578,7 +587,7 @@
 	COct := GetOctetZero(lenC)
 	defer OCT_free(&COct)
 
-	C.AES_GCM_ENCRYPT(&KOct, &IVOct, &HOct, &POct, &COct, &TOct)
+	C.MPIN_AES_GCM_ENCRYPT(&KOct, &IVOct, &HOct, &POct, &COct, &TOct)
 
 	// Convert octet to bytes
 	C := OCT_toBytes(&COct)
@@ -590,7 +599,7 @@
 /* AES-GCM Deryption:
    K is key, H is header, IV is initialization vector and P is plaintext.
    Returns cipthertext and tag (MAC) */
-func AES_GCM_DECRYPT(K, IV, H, C []byte) ([]byte, []byte) {
+func MPIN_AES_GCM_DECRYPT(K, IV, H, C []byte) ([]byte, []byte) {
 	KStr := string(K)
 	KOct := GetOctet(KStr)
 	defer OCT_free(&KOct)
@@ -610,7 +619,7 @@
 	POct := GetOctetZero(lenP)
 	defer OCT_free(&POct)
 
-	C.AES_GCM_DECRYPT(&KOct, &IVOct, &HOct, &COct, &POct, &TOct)
+	C.MPIN_AES_GCM_DECRYPT(&KOct, &IVOct, &HOct, &COct, &POct, &TOct)
 
 	// Convert octet to bytes
 	P := OCT_toBytes(&POct)
@@ -622,7 +631,7 @@
 /* Password based Key Derivation Function */
 /* Input password p, salt s, and repeat count */
 /* Output key of length olen */
-func PBKDF2(Pass, Salt []byte, rep, olen int) (Key []byte) {
+func MPIN_PBKDF2(Pass, Salt []byte, rep, olen int) (Key []byte) {
 	PassStr := string(Pass)
 	PassOct := GetOctet(PassStr)
 	defer OCT_free(&PassOct)
@@ -633,7 +642,7 @@
 	KeyOct := GetOctetZero(olen)
 	defer OCT_free(&KeyOct)
 
-	C.PBKDF2(&PassOct, &SaltOct, C.int(rep), C.int(olen), &KeyOct)
+	C.MPIN_PBKDF2(&PassOct, &SaltOct, C.int(rep), C.int(olen), &KeyOct)
 
 	// Convert octet to bytes
 	Key = OCT_toBytes(&KeyOct)
@@ -775,3 +784,45 @@
 
 	return
 }
+
+func MPIN_HASH_ALL_WRAP(I, U, UT, Y, V, R, W []byte) (HM []byte) {
+	// Form Octets
+	IStr := string(I)
+	IOct := GetOctet(IStr)
+	defer OCT_free(&IOct)
+
+	UStr := string(U)
+	UOct := GetOctet(UStr)
+	defer OCT_free(&UOct)
+
+	UTStr := string(UT)
+	UTOct := GetOctet(UTStr)
+	defer OCT_free(&UTOct)
+
+	YStr := string(Y)
+	YOct := GetOctet(YStr)
+	defer OCT_free(&YOct)
+
+	VStr := string(V)
+	VOct := GetOctet(VStr)
+	defer OCT_free(&VOct)
+
+	RStr := string(R)
+	ROct := GetOctet(RStr)
+	defer OCT_free(&ROct)
+
+	WStr := string(W)
+	WOct := GetOctet(WStr)
+	defer OCT_free(&WOct)
+
+	HMOct := GetOctetZero(HASH_BYTES)
+	defer OCT_free(&HMOct)
+
+	// Hash values
+	C.MPIN_HASH_ALL(&IOct, &UOct, &UTOct, &YOct, &VOct, &ROct, &WOct, &HMOct)
+
+	// Convert octet to bytes
+	HM = OCT_toBytes(&HMOct)
+
+	return
+}
diff --git a/go/src/github.com/miracl/amcl-cgo/crypto_test.go b/go/src/github.com/miracl/amcl-cgo/crypto_test.go
index 454e943..435f954 100644
--- a/go/src/github.com/miracl/amcl-cgo/crypto_test.go
+++ b/go/src/github.com/miracl/amcl-cgo/crypto_test.go
@@ -31,10 +31,15 @@
 	amclgo "github.com/miracl/amcl-go"
 )
 
-const nIter int = 1000
+const nIter int = 100
+
+// Set to true if library built with "-D USE_ANONYMOUS=on"
+const USE_ANONYMOUS = false
 
 func TestGoodPIN(t *testing.T) {
 	want := 0
+	var got int
+
 	// Assign the End-User an ID
 	IDstr := "testUser@miracl.com"
 	ID := []byte(IDstr)
@@ -107,12 +112,18 @@
 	var X [EGS]byte
 	_, _, _, V, U, UT := MPIN_CLIENT_WRAP(date, timeValue, PIN2, rng, ID[:], X[:], TOKEN[:], TP[:], MESSAGE[:])
 
-	got, _, _, _, _, _ := MPIN_SERVER_WRAP(date, timeValue, SS[:], U[:], UT[:], V[:], ID[:], MESSAGE[:])
+	if USE_ANONYMOUS {
+		got, _, _, _, _, _ = MPIN_SERVER_WRAP(date, timeValue, SS[:], U[:], UT[:], V[:], HCID[:], MESSAGE[:])
+	} else {
+		got, _, _, _, _, _ = MPIN_SERVER_WRAP(date, timeValue, SS[:], U[:], UT[:], V[:], ID[:], MESSAGE[:])
+	}
 	assert.Equal(t, want, got, "Should be equal")
 }
 
 func TestBadPIN(t *testing.T) {
 	want := -19
+	var got int
+
 	// Assign the End-User an ID
 	IDstr := "testUser@miracl.com"
 	ID := []byte(IDstr)
@@ -188,12 +199,18 @@
 	_, _, _, V, U, UT := MPIN_CLIENT_WRAP(date, timeValue, PIN2, rng, ID[:], X[:], TOKEN[:], TP[:], MESSAGE[:])
 
 	//////   Server   //////
-	got, _, _, _, _, _ := MPIN_SERVER_WRAP(date, timeValue, SS[:], U[:], UT[:], V[:], ID[:], MESSAGE[:])
+	if USE_ANONYMOUS {
+		got, _, _, _, _, _ = MPIN_SERVER_WRAP(date, timeValue, SS[:], U[:], UT[:], V[:], HCID[:], MESSAGE[:])
+	} else {
+		got, _, _, _, _, _ = MPIN_SERVER_WRAP(date, timeValue, SS[:], U[:], UT[:], V[:], ID[:], MESSAGE[:])
+	}
 	assert.Equal(t, want, got, "Should be equal")
 }
 
 func TestBadToken(t *testing.T) {
 	want := -19
+	var got int
+
 	// Assign the End-User an ID
 	IDstr := "testUser@miracl.com"
 	ID := []byte(IDstr)
@@ -267,12 +284,17 @@
 	_, _, _, _, U, UT := MPIN_CLIENT_WRAP(date, timeValue, PIN2, rng, ID[:], X[:], TOKEN[:], TP[:], MESSAGE[:])
 
 	// Send UT as V to model bad token
-	got, _, _, _, _, _ := MPIN_SERVER_WRAP(date, timeValue, SS[:], U[:], UT[:], UT[:], ID[:], MESSAGE[:])
+	if USE_ANONYMOUS {
+		got, _, _, _, _, _ = MPIN_SERVER_WRAP(date, timeValue, SS[:], U[:], UT[:], UT[:], HCID[:], MESSAGE[:])
+	} else {
+		got, _, _, _, _, _ = MPIN_SERVER_WRAP(date, timeValue, SS[:], U[:], UT[:], UT[:], ID[:], MESSAGE[:])
+	}
 	assert.Equal(t, want, got, "Should be equal")
 }
 
 func TestRandom(t *testing.T) {
 	want := 0
+	var got int
 
 	for i := 0; i < nIter; i++ {
 
@@ -344,13 +366,19 @@
 		var X [EGS]byte
 		_, _, _, V, U, UT := MPIN_CLIENT_WRAP(date, timeValue, PIN2, rng, ID[:], X[:], TOKEN[:], TP[:], MESSAGE[:])
 
-		got, _, _, _, _, _ := MPIN_SERVER_WRAP(date, timeValue, SS[:], U[:], UT[:], V[:], ID[:], MESSAGE[:])
+		if USE_ANONYMOUS {
+			got, _, _, _, _, _ = MPIN_SERVER_WRAP(date, timeValue, SS[:], U[:], UT[:], V[:], HCID[:], MESSAGE[:])
+		} else {
+			got, _, _, _, _, _ = MPIN_SERVER_WRAP(date, timeValue, SS[:], U[:], UT[:], V[:], ID[:], MESSAGE[:])
+		}
 		assert.Equal(t, want, got, "Should be equal")
 	}
 }
 
 func TestGoodSignature(t *testing.T) {
 	want := 0
+	var got int
+
 	// Assign the End-User an ID
 	IDstr := "testUser@miracl.com"
 	ID := []byte(IDstr)
@@ -424,12 +452,18 @@
 	_, _, _, V, U, UT := MPIN_CLIENT_WRAP(date, timeValue, PIN2, rng, ID[:], X[:], TOKEN[:], TP[:], MESSAGE[:])
 
 	// Authenticate
-	got, _, _, _, _, _ := MPIN_SERVER_WRAP(date, timeValue, SS[:], U[:], UT[:], V[:], ID[:], MESSAGE[:])
+	if USE_ANONYMOUS {
+		got, _, _, _, _, _ = MPIN_SERVER_WRAP(date, timeValue, SS[:], U[:], UT[:], V[:], HCID[:], MESSAGE[:])
+	} else {
+		got, _, _, _, _, _ = MPIN_SERVER_WRAP(date, timeValue, SS[:], U[:], UT[:], V[:], ID[:], MESSAGE[:])
+	}
 	assert.Equal(t, want, got, "Should be equal")
 }
 
 func TestSignatureExpired(t *testing.T) {
 	want := -19
+	var got int
+
 	// Assign the End-User an ID
 	IDstr := "testUser@miracl.com"
 	ID := []byte(IDstr)
@@ -504,12 +538,18 @@
 
 	timeValue += 10
 	// Authenticate
-	got, _, _, _, _, _ := MPIN_SERVER_WRAP(date, timeValue, SS[:], U[:], UT[:], V[:], ID[:], MESSAGE[:])
+	if USE_ANONYMOUS {
+		got, _, _, _, _, _ = MPIN_SERVER_WRAP(date, timeValue, SS[:], U[:], UT[:], V[:], HCID[:], MESSAGE[:])
+	} else {
+		got, _, _, _, _, _ = MPIN_SERVER_WRAP(date, timeValue, SS[:], U[:], UT[:], V[:], ID[:], MESSAGE[:])
+	}
 	assert.Equal(t, want, got, "Should be equal")
 }
 
 func TestBadSignature(t *testing.T) {
 	want := -19
+	var got int
+
 	// Assign the End-User an ID
 	IDstr := "testUser@miracl.com"
 	ID := []byte(IDstr)
@@ -584,7 +624,11 @@
 
 	// Authenticate
 	MESSAGE[0] = 00
-	got, _, _, _, _, _ := MPIN_SERVER_WRAP(date, timeValue, SS[:], U[:], UT[:], V[:], ID[:], MESSAGE[:])
+	if USE_ANONYMOUS {
+		got, _, _, _, _, _ = MPIN_SERVER_WRAP(date, timeValue, SS[:], U[:], UT[:], V[:], HCID[:], MESSAGE[:])
+	} else {
+		got, _, _, _, _, _ = MPIN_SERVER_WRAP(date, timeValue, SS[:], U[:], UT[:], V[:], ID[:], MESSAGE[:])
+	}
 	assert.Equal(t, want, got, "Should be equal")
 }
 
@@ -662,14 +706,20 @@
 	var X [EGS]byte
 	_, _, _, V, U, UT := MPIN_CLIENT_WRAP(date, timeValue, PIN2, rng, ID[:], X[:], TOKEN[:], TP[:], MESSAGE[:])
 
-	_, _, _, _, E, F := MPIN_SERVER_WRAP(date, timeValue, SS[:], U[:], UT[:], V[:], ID[:], MESSAGE[:])
+	var E []byte
+	var F []byte
+	if USE_ANONYMOUS {
+		_, _, _, _, E, F = MPIN_SERVER_WRAP(date, timeValue, SS[:], U[:], UT[:], V[:], HCID[:], MESSAGE[:])
+	} else {
+		_, _, _, _, E, F = MPIN_SERVER_WRAP(date, timeValue, SS[:], U[:], UT[:], V[:], ID[:], MESSAGE[:])
+	}
 
 	got := MPIN_KANGAROO(E[:], F[:])
 	assert.Equal(t, want, got, "Should be equal")
 }
 
 func TestMPINFull(t *testing.T) {
-	want := "0afc948b03b2733a0663571f86411a07"
+	want := "4e0317c9962dc2944c121ec41c800e16"
 	// Assign the End-User an ID
 	IDstr := "testUser@miracl.com"
 	ID := []byte(IDstr)
@@ -750,20 +800,31 @@
 	_, ROut, Z := MPIN_GET_G1_MULTIPLE_WRAP(rng, 1, R[:], HCID[:])
 
 	// Authenticate
-	_, _, HTID, _, _, _ := MPIN_SERVER_WRAP(date, timeValue, SS[:], U[:], UT[:], V[:], ID[:], MESSAGE[:])
+	var HID []byte
+	var HTID []byte
+	var Y []byte
+	if USE_ANONYMOUS {
+		_, HID, HTID, Y, _, _ = MPIN_SERVER_WRAP(date, timeValue, SS[:], U[:], UT[:], V[:], HCID[:], MESSAGE[:])
+	} else {
+		_, HID, HTID, Y, _, _ = MPIN_SERVER_WRAP(date, timeValue, SS[:], U[:], UT[:], V[:], ID[:], MESSAGE[:])
+	}
 
 	// send T=w.ID to client
 	var W [EGS]byte
 	_, WOut, T := MPIN_GET_G1_MULTIPLE_WRAP(rng, 0, W[:], HTID[:])
 
-	_, AES_KEY_SERVER := MPIN_SERVER_KEY_WRAP(Z[:], SS[:], WOut[:], U[:], UT[:])
+	// Hash all values
+	HM := MPIN_HASH_ALL_WRAP(HCID[:], U[:], UT[:], Y[:], V[:], Z[:], T[:])
+
+	_, AES_KEY_SERVER := MPIN_SERVER_KEY_WRAP(Z[:], SS[:], WOut[:], HM[:], HID[:], U[:], UT[:])
 	got := hex.EncodeToString(AES_KEY_SERVER[:])
 	if got != want {
 		t.Errorf("%s != %s", want, got)
 	}
 
-	_, AES_KEY_CLIENT := MPIN_CLIENT_KEY_WRAP(PIN2, G1[:], G2[:], ROut[:], XOut[:], T[:])
+	_, AES_KEY_CLIENT := MPIN_CLIENT_KEY_WRAP(PIN2, G1[:], G2[:], ROut[:], XOut[:], HM[:], T[:])
 	got = hex.EncodeToString(AES_KEY_CLIENT[:])
+
 	assert.Equal(t, want, got, "Should be equal")
 }
 
@@ -836,7 +897,13 @@
 	_, _, SEC, U, UT := MPIN_CLIENT_1_WRAP(date, ID, rng, X[:], PIN2, TOKEN[:], TP[:])
 
 	// Server Pass 1
-	HID, HTID := MPIN_SERVER_1_WRAP(date, ID)
+	var HID []byte
+	var HTID []byte
+	if USE_ANONYMOUS {
+		HID, HTID = MPIN_SERVER_1_WRAP(date, HCID)
+	} else {
+		HID, HTID = MPIN_SERVER_1_WRAP(date, ID)
+	}
 	_, Y := MPIN_RANDOM_GENERATE_WRAP(rng)
 
 	// Client Pass 2
@@ -916,7 +983,13 @@
 	_, _, SEC, U, UT := MPIN_CLIENT_1_WRAP(date, ID, rng, X[:], PIN2, TOKEN[:], TP[:])
 
 	// Server Pass 1
-	HID, HTID := MPIN_SERVER_1_WRAP(date, ID)
+	var HID []byte
+	var HTID []byte
+	if USE_ANONYMOUS {
+		HID, HTID = MPIN_SERVER_1_WRAP(date, HCID)
+	} else {
+		HID, HTID = MPIN_SERVER_1_WRAP(date, ID)
+	}
 	_, Y := MPIN_RANDOM_GENERATE_WRAP(rng)
 
 	// Client Pass 2
@@ -996,7 +1069,13 @@
 	_, _, SEC, U, UT := MPIN_CLIENT_1_WRAP(date, ID, rng, X[:], PIN2, TOKEN[:], TP[:])
 
 	// Server Pass 1
-	HID, HTID := MPIN_SERVER_1_WRAP(date, ID)
+	var HID []byte
+	var HTID []byte
+	if USE_ANONYMOUS {
+		HID, HTID = MPIN_SERVER_1_WRAP(date, HCID)
+	} else {
+		HID, HTID = MPIN_SERVER_1_WRAP(date, ID)
+	}
 	_, Y := MPIN_RANDOM_GENERATE_WRAP(rng)
 
 	// Client Pass 2
@@ -1076,7 +1155,13 @@
 		_, _, SEC, U, UT := MPIN_CLIENT_1_WRAP(date, ID, rng, X[:], PIN2, TOKEN[:], TP[:])
 
 		// Server Pass 1
-		HID, HTID := MPIN_SERVER_1_WRAP(date, ID)
+		var HID []byte
+		var HTID []byte
+		if USE_ANONYMOUS {
+			HID, HTID = MPIN_SERVER_1_WRAP(date, HCID)
+		} else {
+			HID, HTID = MPIN_SERVER_1_WRAP(date, ID)
+		}
 		_, Y := MPIN_RANDOM_GENERATE_WRAP(rng)
 
 		// Client Pass 2
diff --git a/go/src/github.com/miracl/examples-cgo/README.txt b/go/src/github.com/miracl/examples-cgo/README.txt
new file mode 100644
index 0000000..cc05766
--- /dev/null
+++ b/go/src/github.com/miracl/examples-cgo/README.txt
@@ -0,0 +1,5 @@
+When the library is built with;
+
+-D USE_ANONYMOUS=on 
+
+then the only example that works is mpinfullAnon.go
diff --git a/go/src/github.com/miracl/examples-cgo/mpinfull.go b/go/src/github.com/miracl/examples-cgo/mpinfull.go
index 785952f..3d19092 100644
--- a/go/src/github.com/miracl/examples-cgo/mpinfull.go
+++ b/go/src/github.com/miracl/examples-cgo/mpinfull.go
@@ -193,7 +193,7 @@
 	var X [amclcgo.EGS]byte
 	fmt.Printf("X: 0x")
 	amclcgo.MPIN_printBinary(X[:])
-	rtn, XOut, Y1, SEC, U, UT := amclcgo.MPIN_CLIENT_WRAP(date, timeValue, PIN2, rng, ID[:], X[:], TOKEN[:], TP[:], MESSAGE[:])
+	rtn, XOut, Y1, V, U, UT := amclcgo.MPIN_CLIENT_WRAP(date, timeValue, PIN2, rng, ID[:], X[:], TOKEN[:], TP[:], MESSAGE[:])
 	if rtn != 0 {
 		fmt.Printf("FAILURE: CLIENT rtn: %d\n", rtn)
 		return
@@ -212,7 +212,7 @@
 	amclcgo.MPIN_printBinary(ROut[:])
 
 	//////   Server   //////
-	rtn, HID, HTID, Y2, E, F := amclcgo.MPIN_SERVER_WRAP(date, timeValue, SS[:], U[:], UT[:], SEC[:], ID[:], MESSAGE[:])
+	rtn, HID, HTID, Y2, E, F := amclcgo.MPIN_SERVER_WRAP(date, timeValue, SS[:], U[:], UT[:], V[:], ID[:], MESSAGE[:])
 	if rtn != 0 {
 		fmt.Printf("FAILURE: SERVER rtn: %d\n", rtn)
 	}
@@ -244,11 +244,14 @@
 	fmt.Printf("T: 0x")
 	amclcgo.MPIN_printBinary(T[:])
 
-	rtn, AES_KEY_SERVER := amclcgo.MPIN_SERVER_KEY_WRAP(Z[:], SS[:], WOut[:], U[:], UT[:])
+        // Hash all values
+        HM := amclcgo.MPIN_HASH_ALL_WRAP(ID[:],U[:],UT[:],Y2[:],V[:],Z[:],T[:])
+
+	rtn, AES_KEY_SERVER := amclcgo.MPIN_SERVER_KEY_WRAP(Z[:], SS[:], WOut[:], HM[:],HID[:],U[:], UT[:])
 	fmt.Printf("Server Key =  0x")
 	amclcgo.MPIN_printBinary(AES_KEY_SERVER[:])
 
-	rtn, AES_KEY_CLIENT := amclcgo.MPIN_CLIENT_KEY_WRAP(PIN2, G1[:], G2[:], ROut[:], XOut[:], T[:])
+	rtn, AES_KEY_CLIENT := amclcgo.MPIN_CLIENT_KEY_WRAP(PIN2, G1[:], G2[:], ROut[:], XOut[:], HM[:],T[:])
 	fmt.Printf("Client Key =  0x")
 	amclcgo.MPIN_printBinary(AES_KEY_CLIENT[:])
 
@@ -272,7 +275,7 @@
 	amclcgo.MPIN_printBinary(PLAINTEXT1[:])
 
 	// AES-GCM Encryption
-	CIPHERTEXT, TAG1 := amclcgo.AES_GCM_ENCRYPT(AES_KEY_SERVER[:], IV[:], HEADER[:], PLAINTEXT1[:])
+	CIPHERTEXT, TAG1 := amclcgo.MPIN_AES_GCM_ENCRYPT(AES_KEY_SERVER[:], IV[:], HEADER[:], PLAINTEXT1[:])
 	fmt.Printf("CIPHERTEXT:  0x")
 	amclcgo.MPIN_printBinary(CIPHERTEXT[:])
 	fmt.Printf("TAG1:  0x")
@@ -281,7 +284,7 @@
 	// Send IV, HEADER, CIPHERTEXT and TAG1 to client
 
 	// AES-GCM Decryption
-	PLAINTEXT2, TAG2 := amclcgo.AES_GCM_DECRYPT(AES_KEY_CLIENT[:], IV[:], HEADER[:], CIPHERTEXT[:])
+	PLAINTEXT2, TAG2 := amclcgo.MPIN_AES_GCM_DECRYPT(AES_KEY_CLIENT[:], IV[:], HEADER[:], CIPHERTEXT[:])
 	fmt.Printf("PLAINTEXT2:  0x")
 	amclcgo.MPIN_printBinary(PLAINTEXT2[:])
 	fmt.Printf("TAG2:  0x")
diff --git a/go/src/github.com/miracl/examples-cgo/mpinfullAnon.go b/go/src/github.com/miracl/examples-cgo/mpinfullAnon.go
new file mode 100644
index 0000000..b5cfe3b
--- /dev/null
+++ b/go/src/github.com/miracl/examples-cgo/mpinfullAnon.go
@@ -0,0 +1,295 @@
+/*
+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.
+*/
+
+// Use MPIN with only hashed IDs to the server
+
+package main
+
+import (
+	"encoding/hex"
+	"fmt"
+
+	amclcgo "github.com/miracl/amcl-cgo"
+	amclgo "github.com/miracl/amcl-go"
+)
+
+func main() {
+	// Assign the End-User an ID
+	IDstr := "testUser@miracl.com"
+	ID := []byte(IDstr)
+	fmt.Printf("ID: ")
+	amclcgo.MPIN_printBinary(ID)
+	fmt.Printf("\n")
+
+	// Epoch time in days
+	date := amclcgo.MPIN_today()
+
+	// Epoch time in seconds
+	timeValue := amclcgo.MPIN_GET_TIME()
+
+	// PIN variable to create token
+	PIN1 := -1
+	// PIN variable to authenticate
+	PIN2 := -1
+
+	// Seed value for Random Number Generator (RNG)
+	seedHex := "9e8b4178790cd57a5761c4a6f164ba72"
+	seed, err := hex.DecodeString(seedHex)
+	if err != nil {
+		fmt.Println("Error decoding seed value")
+		return
+	}
+	rng := amclgo.NewRAND()
+	rng.Seed(len(seed), seed)
+
+	// Message to sign
+	var MESSAGE []byte
+	// MESSAGE := []byte("test sign message")
+
+	// Generate Master Secret Share 1
+	rtn, MS1 := amclcgo.MPIN_RANDOM_GENERATE_WRAP(rng)
+	if rtn != 0 {
+		fmt.Println("MPIN_RANDOM_GENERATE Error:", rtn)
+		return
+	}
+	fmt.Printf("MS1: 0x")
+	amclcgo.MPIN_printBinary(MS1[:])
+
+	// Generate Master Secret Share 2
+	rtn, MS2 := amclcgo.MPIN_RANDOM_GENERATE_WRAP(rng)
+	if rtn != 0 {
+		fmt.Println("MPIN_RANDOM_GENERATE Error:", rtn)
+		return
+	}
+	fmt.Printf("MS2: 0x")
+	amclcgo.MPIN_printBinary(MS2[:])
+
+	// Either Client or TA calculates Hash(ID)
+	HCID := amclcgo.MPIN_HASH_ID(ID)
+
+	// Generate server secret share 1
+	rtn, SS1 := amclcgo.MPIN_GET_SERVER_SECRET_WRAP(MS1[:])
+	if rtn != 0 {
+		fmt.Println("MPIN_GET_SERVER_SECRET Error:", rtn)
+		return
+	}
+	fmt.Printf("SS1: 0x")
+	amclcgo.MPIN_printBinary(SS1[:])
+
+	// Generate server secret share 2
+	rtn, SS2 := amclcgo.MPIN_GET_SERVER_SECRET_WRAP(MS2[:])
+	if rtn != 0 {
+		fmt.Println("MPIN_GET_SERVER_SECRET Error:", rtn)
+		return
+	}
+	fmt.Printf("SS2: 0x")
+	amclcgo.MPIN_printBinary(SS2[:])
+
+	// Combine server secret shares
+	rtn, SS := amclcgo.MPIN_RECOMBINE_G2_WRAP(SS1[:], SS2[:])
+	if rtn != 0 {
+		fmt.Println("MPIN_RECOMBINE_G2(SS1, SS2) Error:", rtn)
+		return
+	}
+	fmt.Printf("SS: 0x")
+	amclcgo.MPIN_printBinary(SS[:])
+
+	// Generate client secret share 1
+	rtn, CS1 := amclcgo.MPIN_GET_CLIENT_SECRET_WRAP(MS1[:], HCID)
+	if rtn != 0 {
+		fmt.Println("MPIN_GET_CLIENT_SECRET Error:", rtn)
+		return
+	}
+	fmt.Printf("Client Secret Share CS1: 0x")
+	amclcgo.MPIN_printBinary(CS1[:])
+
+	// Generate client secret share 2
+	rtn, CS2 := amclcgo.MPIN_GET_CLIENT_SECRET_WRAP(MS2[:], HCID)
+	if rtn != 0 {
+		fmt.Println("MPIN_GET_CLIENT_SECRET Error:", rtn)
+		return
+	}
+	fmt.Printf("Client Secret Share CS2: 0x")
+	amclcgo.MPIN_printBinary(CS2[:])
+
+	// Combine client secret shares
+	CS := make([]byte, amclcgo.G1S)
+	rtn, CS = amclcgo.MPIN_RECOMBINE_G1_WRAP(CS1[:], CS2[:])
+	if rtn != 0 {
+		fmt.Println("MPIN_RECOMBINE_G1 Error:", rtn)
+		return
+	}
+	fmt.Printf("Client Secret CS: 0x")
+	amclcgo.MPIN_printBinary(CS[:])
+
+	// Generate time permit share 1
+	rtn, TP1 := amclcgo.MPIN_GET_CLIENT_PERMIT_WRAP(date, MS1[:], HCID)
+	if rtn != 0 {
+		fmt.Println("MPIN_GET_CLIENT_PERMIT Error:", rtn)
+		return
+	}
+	fmt.Printf("TP1: 0x")
+	amclcgo.MPIN_printBinary(TP1[:])
+
+	// Generate time permit share 2
+	rtn, TP2 := amclcgo.MPIN_GET_CLIENT_PERMIT_WRAP(date, MS2[:], HCID)
+	if rtn != 0 {
+		fmt.Println("MPIN_GET_CLIENT_PERMIT Error:", rtn)
+		return
+	}
+	fmt.Printf("TP2: 0x")
+	amclcgo.MPIN_printBinary(TP2[:])
+
+	// Combine time permit shares
+	rtn, TP := amclcgo.MPIN_RECOMBINE_G1_WRAP(TP1[:], TP2[:])
+	if rtn != 0 {
+		fmt.Println("MPIN_RECOMBINE_G1(TP1, TP2) Error:", rtn)
+		return
+	}
+
+	// Client extracts PIN1 from secret to create Token
+	for PIN1 < 0 {
+		fmt.Printf("Please enter PIN to create token: ")
+		fmt.Scan(&PIN1)
+	}
+
+	rtn, TOKEN := amclcgo.MPIN_EXTRACT_PIN_WRAP(ID[:], PIN1, CS[:])
+	if rtn != 0 {
+		fmt.Printf("FAILURE: EXTRACT_PIN rtn: %d\n", rtn)
+		return
+	}
+	fmt.Printf("Client Token TK: 0x")
+	amclcgo.MPIN_printBinary(TOKEN[:])
+
+	//////   Client   //////
+
+	// Precomputation
+	rtn, G1, G2 := amclcgo.MPIN_PRECOMPUTE_WRAP(TOKEN[:], HCID)
+	if rtn != 0 {
+		fmt.Println("MPIN_PRECOMPUTE(TOKEN[:], HCID) Error:", rtn)
+		return
+	}
+
+	for PIN2 < 0 {
+		fmt.Printf("Please enter PIN to authenticate: ")
+		fmt.Scan(&PIN2)
+	}
+
+	// Send U, UT, V, timeValue and Message to server
+	var X [amclcgo.EGS]byte
+	fmt.Printf("X: 0x")
+	amclcgo.MPIN_printBinary(X[:])
+	rtn, XOut, Y1, V, U, UT := amclcgo.MPIN_CLIENT_WRAP(date, timeValue, PIN2, rng, ID[:], X[:], TOKEN[:], TP[:], MESSAGE[:])
+	if rtn != 0 {
+		fmt.Printf("FAILURE: CLIENT rtn: %d\n", rtn)
+		return
+	}
+	fmt.Printf("Y1: 0x")
+	amclcgo.MPIN_printBinary(Y1[:])
+	fmt.Printf("XOut: 0x")
+	amclcgo.MPIN_printBinary(XOut[:])
+
+	// Send Z=r.ID to Server
+	var R [amclcgo.EGS]byte
+	fmt.Printf("R: 0x")
+	amclcgo.MPIN_printBinary(R[:])
+	rtn, ROut, Z := amclcgo.MPIN_GET_G1_MULTIPLE_WRAP(rng, 1, R[:], HCID[:])
+	fmt.Printf("ROut: 0x")
+	amclcgo.MPIN_printBinary(ROut[:])
+
+	//////   Server   //////
+	rtn, HID, HTID, Y2, E, F := amclcgo.MPIN_SERVER_WRAP(date, timeValue, SS[:], U[:], UT[:], V[:], HCID[:], MESSAGE[:])
+	if rtn != 0 {
+		fmt.Printf("FAILURE: SERVER rtn: %d\n", rtn)
+	}
+	fmt.Printf("Y2: 0x")
+	amclcgo.MPIN_printBinary(Y2[:])
+	fmt.Printf("HID: 0x")
+	amclcgo.MPIN_printBinary(HID[:])
+	fmt.Printf("HTID: 0x")
+	amclcgo.MPIN_printBinary(HTID[:])
+
+	if rtn != 0 {
+		fmt.Printf("Authentication failed Error Code %d\n", rtn)
+		err := amclcgo.MPIN_KANGAROO(E[:], F[:])
+		if err != 0 {
+			fmt.Printf("PIN Error %d\n", err)
+		}
+		return
+	} else {
+		fmt.Printf("Authenticated ID: %s \n", IDstr)
+	}
+
+	// send T=w.ID to client
+	var W [amclcgo.EGS]byte
+	fmt.Printf("W: 0x")
+	amclcgo.MPIN_printBinary(W[:])
+	rtn, WOut, T := amclcgo.MPIN_GET_G1_MULTIPLE_WRAP(rng, 0, W[:], HTID[:])
+	fmt.Printf("WOut: 0x")
+	amclcgo.MPIN_printBinary(WOut[:])
+	fmt.Printf("T: 0x")
+	amclcgo.MPIN_printBinary(T[:])
+
+	// Hash all values
+	HM := amclcgo.MPIN_HASH_ALL_WRAP(HCID[:], U[:], UT[:], Y2[:], V[:], Z[:], T[:])
+
+	rtn, AES_KEY_SERVER := amclcgo.MPIN_SERVER_KEY_WRAP(Z[:], SS[:], WOut[:], HM[:], HID[:], U[:], UT[:])
+	fmt.Printf("Server Key =  0x")
+	amclcgo.MPIN_printBinary(AES_KEY_SERVER[:])
+
+	rtn, AES_KEY_CLIENT := amclcgo.MPIN_CLIENT_KEY_WRAP(PIN2, G1[:], G2[:], ROut[:], XOut[:], HM[:], T[:])
+	fmt.Printf("Client Key =  0x")
+	amclcgo.MPIN_printBinary(AES_KEY_CLIENT[:])
+
+	//////   Server   //////
+
+	// Initialization vector
+	IV := amclgo.GENERATE_RANDOM(rng, 12)
+	fmt.Printf("IV: 0x")
+	amclcgo.MPIN_printBinary(IV[:])
+
+	// header
+	HEADER := amclgo.GENERATE_RANDOM(rng, 16)
+	fmt.Printf("HEADER: 0x")
+	amclcgo.MPIN_printBinary(HEADER[:])
+
+	// Input plaintext
+	plaintextStr := "A test message"
+	PLAINTEXT1 := []byte(plaintextStr)
+	fmt.Printf("String to encrypt: %s \n", plaintextStr)
+	fmt.Printf("PLAINTEXT1: 0x")
+	amclcgo.MPIN_printBinary(PLAINTEXT1[:])
+
+	// AES-GCM Encryption
+	CIPHERTEXT, TAG1 := amclcgo.MPIN_AES_GCM_ENCRYPT(AES_KEY_SERVER[:], IV[:], HEADER[:], PLAINTEXT1[:])
+	fmt.Printf("CIPHERTEXT:  0x")
+	amclcgo.MPIN_printBinary(CIPHERTEXT[:])
+	fmt.Printf("TAG1:  0x")
+	amclcgo.MPIN_printBinary(TAG1[:])
+
+	// Send IV, HEADER, CIPHERTEXT and TAG1 to client
+
+	// AES-GCM Decryption
+	PLAINTEXT2, TAG2 := amclcgo.MPIN_AES_GCM_DECRYPT(AES_KEY_CLIENT[:], IV[:], HEADER[:], CIPHERTEXT[:])
+	fmt.Printf("PLAINTEXT2:  0x")
+	amclcgo.MPIN_printBinary(PLAINTEXT2[:])
+	fmt.Printf("TAG2:  0x")
+	amclcgo.MPIN_printBinary(TAG2[:])
+	fmt.Printf("Decrypted string: %s \n", string(PLAINTEXT2))
+}
diff --git a/pythonCFFI/CMakeLists.txt b/pythonCFFI/CMakeLists.txt
index 5de4587..557a8e6 100644
--- a/pythonCFFI/CMakeLists.txt
+++ b/pythonCFFI/CMakeLists.txt
@@ -6,16 +6,29 @@
             OWNER_WRITE OWNER_READ OWNER_EXECUTE
             GROUP_READ GROUP_EXECUTE
             WORLD_READ WORLD_EXECUTE)
-    INSTALL(FILES ${PROJECT_SOURCE_DIR}/pythonCFFI/TestMPINInstall.py DESTINATION bin PERMISSIONS
-            OWNER_WRITE OWNER_READ OWNER_EXECUTE
-            GROUP_READ GROUP_EXECUTE
-            WORLD_READ WORLD_EXECUTE)
+
+    if (USE_ANONYMOUS)
+        INSTALL(FILES ${PROJECT_SOURCE_DIR}/pythonCFFI/TestMPINAnonInstall.py DESTINATION bin PERMISSIONS
+                OWNER_WRITE OWNER_READ OWNER_EXECUTE
+                GROUP_READ GROUP_EXECUTE
+                WORLD_READ WORLD_EXECUTE)
+    else (USE_ANONYMOUS)
+        INSTALL(FILES ${PROJECT_SOURCE_DIR}/pythonCFFI/TestMPINInstall.py DESTINATION bin PERMISSIONS
+                OWNER_WRITE OWNER_READ OWNER_EXECUTE
+                GROUP_READ GROUP_EXECUTE
+                WORLD_READ WORLD_EXECUTE)
+    endif (USE_ANONYMOUS)
+
   endif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
 
   if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
     # Windows specific code
     INSTALL(FILES ${PROJECT_SOURCE_DIR}/pythonCFFI/mpin.py DESTINATION lib)
-    INSTALL(FILES ${PROJECT_SOURCE_DIR}/pythonCFFI/TestMPINInstall.py DESTINATION lib)
+    if (USE_ANONYMOUS)
+        INSTALL(FILES ${PROJECT_SOURCE_DIR}/pythonCFFI/TestMPINAnonInstall.py DESTINATION lib)
+    else (USE_ANONYMOUS)
+        INSTALL(FILES ${PROJECT_SOURCE_DIR}/pythonCFFI/TestMPINInstall.py DESTINATION lib)
+    endif (USE_ANONYMOUS)
   endif(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
 
   if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
@@ -24,21 +37,102 @@
             OWNER_WRITE OWNER_READ OWNER_EXECUTE
             GROUP_READ GROUP_EXECUTE
             WORLD_READ WORLD_EXECUTE)
-    INSTALL(FILES ${PROJECT_SOURCE_DIR}/pythonCFFI/TestMPINInstall.py DESTINATION bin PERMISSIONS
+
+    if (USE_ANONYMOUS)
+        INSTALL(FILES ${PROJECT_SOURCE_DIR}/pythonCFFI/TestMPINAnonInstall.py DESTINATION bin PERMISSIONS
+                OWNER_WRITE OWNER_READ OWNER_EXECUTE
+                GROUP_READ GROUP_EXECUTE
+                WORLD_READ WORLD_EXECUTE)
+    else (USE_ANONYMOUS)
+        INSTALL(FILES ${PROJECT_SOURCE_DIR}/pythonCFFI/TestMPINInstall.py DESTINATION bin PERMISSIONS
+                OWNER_WRITE OWNER_READ OWNER_EXECUTE
+                GROUP_READ GROUP_EXECUTE
+                WORLD_READ WORLD_EXECUTE)
+    endif (USE_ANONYMOUS)
+
+  endif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+
+  file(COPY mpin.py DESTINATION "${PROJECT_BINARY_DIR}/pythonCFFI/")
+  if (USE_ANONYMOUS)
+      file(COPY TestMPINAnonInstall.py DESTINATION "${PROJECT_BINARY_DIR}/pythonCFFI/")
+      add_test (TestMPINAnonInstall python TestMPINAnonInstall.py) 
+  else (USE_ANONYMOUS)
+      file(COPY TestMPINInstall.py DESTINATION "${PROJECT_BINARY_DIR}/pythonCFFI/")   
+      add_test (TestMPINInstall python TestMPINInstall.py) 
+  endif (USE_ANONYMOUS) 
+  
+
+  if(FIELD_CHOICE STREQUAL "BNCX")
+      if (USE_ANONYMOUS)
+          file(COPY TestMPINAnon.py DESTINATION "${PROJECT_BINARY_DIR}/pythonCFFI/")
+          add_test (TestMPINAnonBNCX python TestMPINAnon.py)
+      else (USE_ANONYMOUS)
+          file(COPY TestMPIN.py DESTINATION "${PROJECT_BINARY_DIR}/pythonCFFI/")
+          add_test (TestMPINBNCX python TestMPIN.py)
+      endif (USE_ANONYMOUS) 
+  endif(FIELD_CHOICE STREQUAL "BNCX")
+
+  
+endif(BUILD_MPIN)
+
+
+if(BUILD_SOK)
+  if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+    INSTALL(FILES ${PROJECT_SOURCE_DIR}/pythonCFFI/sok.py DESTINATION "${PYTHON_SITE_PACKAGES}" PERMISSIONS
+            OWNER_WRITE OWNER_READ OWNER_EXECUTE
+            GROUP_READ GROUP_EXECUTE
+            WORLD_READ WORLD_EXECUTE)
+    INSTALL(FILES ${PROJECT_SOURCE_DIR}/pythonCFFI/TestSOKInstall.py DESTINATION bin PERMISSIONS
+            OWNER_WRITE OWNER_READ OWNER_EXECUTE
+            GROUP_READ GROUP_EXECUTE
+            WORLD_READ WORLD_EXECUTE)
+  endif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+
+  if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
+    # Windows specific code
+    INSTALL(FILES ${PROJECT_SOURCE_DIR}/pythonCFFI/sok.py DESTINATION lib)
+    INSTALL(FILES ${PROJECT_SOURCE_DIR}/pythonCFFI/TestSOKInstall.py DESTINATION lib)
+  endif(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
+
+  if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+    # Mac OS X specific code
+    INSTALL(FILES ${PROJECT_SOURCE_DIR}/pythonCFFI/sok.py DESTINATION "${PYTHON_SITE_PACKAGES}" PERMISSIONS
+            OWNER_WRITE OWNER_READ OWNER_EXECUTE
+            GROUP_READ GROUP_EXECUTE
+            WORLD_READ WORLD_EXECUTE)
+    INSTALL(FILES ${PROJECT_SOURCE_DIR}/pythonCFFI/TestSOKInstall.py DESTINATION bin PERMISSIONS
             OWNER_WRITE OWNER_READ OWNER_EXECUTE
             GROUP_READ GROUP_EXECUTE
             WORLD_READ WORLD_EXECUTE)
   endif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
 
-  file(COPY mpin.py DESTINATION "${PROJECT_BINARY_DIR}/pythonCFFI/")
-  file(COPY TestMPINInstall.py DESTINATION "${PROJECT_BINARY_DIR}/pythonCFFI/")
+  file(COPY sok.py DESTINATION "${PROJECT_BINARY_DIR}/pythonCFFI/")
+  file(COPY TestSOKInstall.py DESTINATION "${PROJECT_BINARY_DIR}/pythonCFFI/")
 
-  if(FIELD_CHOICE STREQUAL "BNCX")
-    file(COPY TestMPIN.py DESTINATION "${PROJECT_BINARY_DIR}/pythonCFFI/")
-    add_test (TestMPINBNCX python TestMPIN.py)
-  endif(FIELD_CHOICE STREQUAL "BNCX")
-
-  add_test (TestMPINInstall python TestMPINInstall.py)
-endif(BUILD_MPIN)
+  add_test (TestSOKInstall python TestSOKInstall.py)
+endif(BUILD_SOK)
 
 
+if(BUILD_WCC)
+  if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+    INSTALL(FILES ${PROJECT_SOURCE_DIR}/pythonCFFI/wcc.py DESTINATION "${PYTHON_SITE_PACKAGES}" PERMISSIONS
+            OWNER_WRITE OWNER_READ OWNER_EXECUTE
+            GROUP_READ GROUP_EXECUTE
+            WORLD_READ WORLD_EXECUTE)
+  endif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+
+  if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
+    # Windows specific code
+    INSTALL(FILES ${PROJECT_SOURCE_DIR}/pythonCFFI/wcc.py DESTINATION lib)
+  endif(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
+
+  if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+    # Mac OS X specific code
+    INSTALL(FILES ${PROJECT_SOURCE_DIR}/pythonCFFI/wcc.py DESTINATION "${PYTHON_SITE_PACKAGES}" PERMISSIONS
+            OWNER_WRITE OWNER_READ OWNER_EXECUTE
+            GROUP_READ GROUP_EXECUTE
+            WORLD_READ WORLD_EXECUTE)
+  endif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+
+  file(COPY wcc.py DESTINATION "${PROJECT_BINARY_DIR}/pythonCFFI/")
+endif(BUILD_WCC)
diff --git a/pythonCFFI/README.md b/pythonCFFI/README.md
index d080129..e672502 100644
--- a/pythonCFFI/README.md
+++ b/pythonCFFI/README.md
@@ -9,3 +9,7 @@
 
 ./TestSOKInstall.py -v
 
+To run all WCC tests
+
+./TestWCCInstall.py -v
+
diff --git a/pythonCFFI/TestMPIN.py b/pythonCFFI/TestMPIN.py
index bac9e0f..24cb516 100755
--- a/pythonCFFI/TestMPIN.py
+++ b/pythonCFFI/TestMPIN.py
@@ -203,7 +203,7 @@
 
             # random number generator
             RNG = ffi.new("csprng*")
-            libmpin.CREATE_CSPRNG(RNG, self.RAW)
+            libmpin.MPIN_CREATE_CSPRNG(RNG, self.RAW)
 
             MS1_HEX = vector['MS1']
             MS2_HEX = vector['MS2']
diff --git a/pythonCFFI/TestMPINAnon.py b/pythonCFFI/TestMPINAnon.py
new file mode 100755
index 0000000..ae332c5
--- /dev/null
+++ b/pythonCFFI/TestMPINAnon.py
@@ -0,0 +1,326 @@
+#!/usr/bin/env python
+
+"""
+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 unittest
+import json
+
+from mpin import ffi, G1, G2, HASH_BYTES, libmpin, PFS, PGS, toHex
+
+# Master Secret Shares
+MS1 = ffi.new("octet*")
+MS1val = ffi.new("char []", PGS)
+MS1[0].val = MS1val
+MS1[0].max = PGS
+MS1[0].len = PGS
+
+MS2 = ffi.new("octet*")
+MS2val = ffi.new("char []", PGS)
+MS2[0].val = MS2val
+MS2[0].max = PGS
+MS2[0].len = PGS
+
+# Client secret and shares
+CS1 = ffi.new("octet*")
+CS1val = ffi.new("char []", G1)
+CS1[0].val = CS1val
+CS1[0].max = G1
+CS1[0].len = G1
+
+CS2 = ffi.new("octet*")
+CS2val = ffi.new("char []", G1)
+CS2[0].val = CS2val
+CS2[0].max = G1
+CS2[0].len = G1
+
+SEC = ffi.new("octet*")
+SECval = ffi.new("char []", G1)
+SEC[0].val = SECval
+SEC[0].max = G1
+SEC[0].len = G1
+
+# Server secret and shares
+SS1 = ffi.new("octet*")
+SS1val = ffi.new("char []", G2)
+SS1[0].val = SS1val
+SS1[0].max = G2
+SS1[0].len = G2
+
+SS2 = ffi.new("octet*")
+SS2val = ffi.new("char []", G2)
+SS2[0].val = SS2val
+SS2[0].max = G2
+SS2[0].len = G2
+
+SERVER_SECRET = ffi.new("octet*")
+SERVER_SECRETval = ffi.new("char []", G2)
+SERVER_SECRET[0].val = SERVER_SECRETval
+SERVER_SECRET[0].max = G2
+SERVER_SECRET[0].len = G2
+
+# Time Permit and shares
+TP1 = ffi.new("octet*")
+TP1val = ffi.new("char []", G1)
+TP1[0].val = TP1val
+TP1[0].max = G1
+TP1[0].len = G1
+
+TP2 = ffi.new("octet*")
+TP2val = ffi.new("char []", G1)
+TP2[0].val = TP2val
+TP2[0].max = G1
+TP2[0].len = G1
+
+TIME_PERMIT = ffi.new("octet*")
+TIME_PERMITval = ffi.new("char []", G1)
+TIME_PERMIT[0].val = TIME_PERMITval
+TIME_PERMIT[0].max = G1
+TIME_PERMIT[0].len = G1
+
+# Token stored on computer
+TOKEN = ffi.new("octet*")
+TOKENval = ffi.new("char []", G1)
+TOKEN[0].val = TOKENval
+TOKEN[0].max = G1
+TOKEN[0].len = G1
+
+UT = ffi.new("octet*")
+UTval = ffi.new("char []", G1)
+UT[0].val = UTval
+UT[0].max = G1
+UT[0].len = G1
+
+U = ffi.new("octet*")
+Uval = ffi.new("char []", G1)
+U[0].val = Uval
+U[0].max = G1
+U[0].len = G1
+
+X = ffi.new("octet*")
+Xval = ffi.new("char []", PGS)
+X[0].val = Xval
+X[0].max = PGS
+X[0].len = PGS
+
+Y = ffi.new("octet*")
+Yval = ffi.new("char []", PGS)
+Y[0].val = Yval
+Y[0].max = PGS
+Y[0].len = PGS
+
+lenEF = 12 * PFS
+E = ffi.new("octet*")
+Eval = ffi.new("char []", lenEF)
+E[0].val = Eval
+E[0].max = lenEF
+E[0].len = lenEF
+
+F = ffi.new("octet*")
+Fval = ffi.new("char []", lenEF)
+F[0].val = Fval
+F[0].max = lenEF
+F[0].len = lenEF
+
+# H(ID)
+HID = ffi.new("octet*")
+HIDval = ffi.new("char []", G1)
+HID[0].val = HIDval
+HID[0].max = G1
+HID[0].len = G1
+
+# H(T|H(ID))
+HTID = ffi.new("octet*")
+HTIDval = ffi.new("char []", G1)
+HTID[0].val = HTIDval
+HTID[0].max = G1
+HTID[0].len = G1
+
+
+class TestMPIN(unittest.TestCase):
+    """Tests M-Pin crypto code"""
+
+    def setUp(self):
+
+        # Form MPin ID
+        endUserData = {
+            "issued": "2013-10-19T06:12:28Z",
+            "userID": "testUser@miracl.com",
+            "mobile": 1,
+            "salt": "e985da112a378c222cfc2f7226097b0c"
+        }
+        mpin_id = json.dumps(endUserData)
+
+        self.MPIN_ID = ffi.new("octet*")
+        self.MPIN_IDval = ffi.new("char [%s]" % len(mpin_id), mpin_id)
+        self.MPIN_ID[0].val = self.MPIN_IDval
+        self.MPIN_ID[0].max = len(mpin_id)
+        self.MPIN_ID[0].len = len(mpin_id)
+
+        # Hash value of MPIN_ID
+        self.HASH_MPIN_ID = ffi.new("octet*")
+        self.HASH_MPIN_IDval = ffi.new("char []",  HASH_BYTES)
+        self.HASH_MPIN_ID[0].val = self.HASH_MPIN_IDval
+        self.HASH_MPIN_ID[0].max = HASH_BYTES
+        self.HASH_MPIN_ID[0].len = HASH_BYTES
+        libmpin.MPIN_HASH_ID(self.MPIN_ID, self.HASH_MPIN_ID)
+
+        # Assign a seed value
+        seedHex = "3ade3d4a5c698e8910bf92f25d97ceeb7c25ed838901a5cb5db2cf25434c1fe76c7f79b7af2e5e1e4988e4294dbd9bd9fa3960197fb7aec373609fb890d74b16a4b14b2ae7e23b75f15d36c21791272372863c4f8af39980283ae69a79cf4e48e908f9e0"
+        self.seed = seedHex.decode("hex")
+        self.RAW = ffi.new("octet*")
+        self.RAWval = ffi.new("char [%s]" % len(self.seed), self.seed)
+        self.RAW[0].val = self.RAWval
+        self.RAW[0].len = len(self.seed)
+        self.RAW[0].max = len(self.seed)
+
+        self.date = 16238
+
+    def test_1(self):
+        """test_1 Good PIN and good token"""
+        vectors = json.load(open("./MPINTestVectors.json", "r"))
+        for vector in vectors:
+            print "Test vector {}".format(vector['test_no'])
+
+            PIN1 = vector['PIN1']
+            PIN2 = vector['PIN2']
+            date = vector['DATE']
+
+            # random number generator
+            RNG = ffi.new("csprng*")
+            libmpin.MPIN_CREATE_CSPRNG(RNG, self.RAW)
+
+            MS1_HEX = vector['MS1']
+            MS2_HEX = vector['MS2']
+
+            ms1_bin = MS1_HEX.decode("hex")
+            MS1 = ffi.new("octet*")
+            MS1val = ffi.new("char [%s]" % len(ms1_bin), ms1_bin)
+            MS1[0].val = MS1val
+            MS1[0].max = PGS
+            MS1[0].len = PGS
+
+            ms2_bin = MS2_HEX.decode("hex")
+            MS2 = ffi.new("octet*")
+            MS2val = ffi.new("char [%s]" % len(ms2_bin), ms2_bin)
+            MS2[0].val = MS2val
+            MS2[0].max = PGS
+            MS2[0].len = PGS
+
+            # Generate server secret shares
+            rtn = libmpin.MPIN_GET_SERVER_SECRET(MS1, SS1)
+            self.assertEqual(rtn, 0)
+            self.assertEqual(vector['SS1'], toHex(SS1))
+            rtn = libmpin.MPIN_GET_SERVER_SECRET(MS2, SS2)
+            self.assertEqual(rtn, 0)
+            self.assertEqual(vector['SS2'], toHex(SS2))
+
+            # Combine server secret shares
+            rtn = libmpin.MPIN_RECOMBINE_G2(SS1, SS2, SERVER_SECRET)
+            self.assertEqual(rtn, 0)
+            self.assertEqual(vector['SERVER_SECRET'], toHex(SERVER_SECRET))
+
+            mpin_id = vector['MPIN_ID_HEX'].decode("hex")
+            MPIN_ID = ffi.new("octet*")
+            MPIN_IDval = ffi.new("char [%s]" % len(mpin_id), mpin_id)
+            MPIN_ID[0].val = MPIN_IDval
+            MPIN_ID[0].max = len(mpin_id)
+            MPIN_ID[0].len = len(mpin_id)
+
+            # Hash value of MPIN_ID
+            HASH_MPIN_ID = ffi.new("octet*")
+            HASH_MPIN_IDval = ffi.new("char []",  HASH_BYTES)
+            HASH_MPIN_ID[0].val = HASH_MPIN_IDval
+            HASH_MPIN_ID[0].max = HASH_BYTES
+            HASH_MPIN_ID[0].len = HASH_BYTES
+            libmpin.MPIN_HASH_ID(MPIN_ID, HASH_MPIN_ID)
+            self.assertEqual(vector['HASH_MPIN_ID_HEX'], toHex(HASH_MPIN_ID))
+
+            # Generate client secret shares
+            rtn = libmpin.MPIN_GET_CLIENT_SECRET(MS1, HASH_MPIN_ID, CS1)
+            self.assertEqual(rtn, 0)
+            self.assertEqual(vector['CS1'], toHex(CS1))
+            rtn = libmpin.MPIN_GET_CLIENT_SECRET(MS2, HASH_MPIN_ID, CS2)
+            self.assertEqual(rtn, 0)
+            self.assertEqual(vector['CS2'], toHex(CS2))
+
+            # Combine client secret shares : TOKEN is the full client secret
+            rtn = libmpin.MPIN_RECOMBINE_G1(CS1, CS2, TOKEN)
+            self.assertEqual(rtn, 0)
+            self.assertEqual(vector['CLIENT_SECRET'], toHex(TOKEN))
+
+            # Generate Time Permit shares
+            rtn = libmpin.MPIN_GET_CLIENT_PERMIT(date, MS1, HASH_MPIN_ID, TP1)
+            self.assertEqual(rtn, 0)
+            self.assertEqual(vector['TP1'], toHex(TP1))
+            rtn = libmpin.MPIN_GET_CLIENT_PERMIT(date, MS2, HASH_MPIN_ID, TP2)
+            self.assertEqual(rtn, 0)
+            self.assertEqual(vector['TP2'], toHex(TP2))
+
+            # Combine Time Permit shares
+            rtn = libmpin.MPIN_RECOMBINE_G1(TP1, TP2, TIME_PERMIT)
+            self.assertEqual(rtn, 0)
+            self.assertEqual(vector['TIME_PERMIT'], toHex(TIME_PERMIT))
+
+            # Client extracts PIN from secret to create Token
+            rtn = libmpin.MPIN_EXTRACT_PIN(MPIN_ID, PIN1, TOKEN)
+            self.assertEqual(rtn, 0)
+            self.assertEqual(vector['TOKEN'], toHex(TOKEN))
+
+            x = vector['X'].decode("hex")
+            X = ffi.new("octet*")
+            Xval = ffi.new("char [%s]" % PGS, x)
+            X[0].val = Xval
+            X[0].max = PGS
+            X[0].len = PGS
+
+            # Client first pass. Use X value from test vectors
+            rtn = libmpin.MPIN_CLIENT_1(date, MPIN_ID, ffi.NULL, X, PIN2, TOKEN, SEC, U, UT, TIME_PERMIT)
+            self.assertEqual(rtn, 0)
+            self.assertEqual(vector['X'], toHex(X))
+            self.assertEqual(vector['U'], toHex(U))
+            self.assertEqual(vector['UT'], toHex(UT))
+            self.assertEqual(vector['SEC'], toHex(SEC))
+
+            # Server calculates H(ID) and H(T|H(ID))
+            libmpin.MPIN_SERVER_1(date, HASH_MPIN_ID, HID, HTID)
+
+            # Server generates Random number Y and sends it to Client
+            # rtn = libmpin.MPIN_RANDOM_GENERATE(RNG,Y)
+            # self.assertEqual(rtn, 0)
+
+            # Use Y value from test vectors
+            y = vector['Y'].decode("hex")
+            Y = ffi.new("octet*")
+            Yval = ffi.new("char [%s]" % PGS, y)
+            Y[0].val = Yval
+            Y[0].max = PGS
+            Y[0].len = PGS
+
+            # Client second pass
+            rtn = libmpin.MPIN_CLIENT_2(X, Y, SEC)
+            self.assertEqual(rtn, 0)
+            self.assertEqual(vector['V'], toHex(SEC))
+
+            # Server second pass
+            rtn = libmpin.MPIN_SERVER_2(date, HID, HTID, Y, SERVER_SECRET, U, UT, SEC, E, F)
+            self.assertEqual(rtn, vector['SERVER_OUTPUT'])
+
+if __name__ == '__main__':
+    # Run tests
+    unittest.main()
diff --git a/pythonCFFI/TestMPINAnonInstall.py b/pythonCFFI/TestMPINAnonInstall.py
new file mode 100755
index 0000000..7d67721
--- /dev/null
+++ b/pythonCFFI/TestMPINAnonInstall.py
@@ -0,0 +1,703 @@
+#!/usr/bin/env python
+
+"""
+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 unittest
+import json
+import hashlib
+
+from mpin import ffi, G1, G2, HASH_BYTES, IVL, libmpin, PAS, PFS, PGS, toHex
+
+# Master Secret Shares
+MS1 = ffi.new("octet*")
+MS1val = ffi.new("char []", PGS)
+MS1[0].val = MS1val
+MS1[0].max = PGS
+MS1[0].len = PGS
+
+MS2 = ffi.new("octet*")
+MS2val = ffi.new("char []", PGS)
+MS2[0].val = MS2val
+MS2[0].max = PGS
+MS2[0].len = PGS
+
+# Client secret and shares
+CS1 = ffi.new("octet*")
+CS1val = ffi.new("char []", G1)
+CS1[0].val = CS1val
+CS1[0].max = G1
+CS1[0].len = G1
+
+CS2 = ffi.new("octet*")
+CS2val = ffi.new("char []", G1)
+CS2[0].val = CS2val
+CS2[0].max = G1
+CS2[0].len = G1
+
+SEC = ffi.new("octet*")
+SECval = ffi.new("char []", G1)
+SEC[0].val = SECval
+SEC[0].max = G1
+SEC[0].len = G1
+
+# Server secret and shares
+SS1 = ffi.new("octet*")
+SS1val = ffi.new("char []", G2)
+SS1[0].val = SS1val
+SS1[0].max = G2
+SS1[0].len = G2
+
+SS2 = ffi.new("octet*")
+SS2val = ffi.new("char []", G2)
+SS2[0].val = SS2val
+SS2[0].max = G2
+SS2[0].len = G2
+
+SERVER_SECRET = ffi.new("octet*")
+SERVER_SECRETval = ffi.new("char []", G2)
+SERVER_SECRET[0].val = SERVER_SECRETval
+SERVER_SECRET[0].max = G2
+SERVER_SECRET[0].len = G2
+
+# Time Permit and shares
+TP1 = ffi.new("octet*")
+TP1val = ffi.new("char []", G1)
+TP1[0].val = TP1val
+TP1[0].max = G1
+TP1[0].len = G1
+
+TP2 = ffi.new("octet*")
+TP2val = ffi.new("char []", G1)
+TP2[0].val = TP2val
+TP2[0].max = G1
+TP2[0].len = G1
+
+TIME_PERMIT = ffi.new("octet*")
+TIME_PERMITval = ffi.new("char []", G1)
+TIME_PERMIT[0].val = TIME_PERMITval
+TIME_PERMIT[0].max = G1
+TIME_PERMIT[0].len = G1
+
+# Token stored on computer
+TOKEN = ffi.new("octet*")
+TOKENval = ffi.new("char []", G1)
+TOKEN[0].val = TOKENval
+TOKEN[0].max = G1
+TOKEN[0].len = G1
+
+UT = ffi.new("octet*")
+UTval = ffi.new("char []", G1)
+UT[0].val = UTval
+UT[0].max = G1
+UT[0].len = G1
+
+U = ffi.new("octet*")
+Uval = ffi.new("char []", G1)
+U[0].val = Uval
+U[0].max = G1
+U[0].len = G1
+
+X = ffi.new("octet*")
+Xval = ffi.new("char []", PGS)
+X[0].val = Xval
+X[0].max = PGS
+X[0].len = PGS
+
+Y = ffi.new("octet*")
+Yval = ffi.new("char []", PGS)
+Y[0].val = Yval
+Y[0].max = PGS
+Y[0].len = PGS
+
+lenEF = 12 * PFS
+E = ffi.new("octet*")
+Eval = ffi.new("char []", lenEF)
+E[0].val = Eval
+E[0].max = lenEF
+E[0].len = lenEF
+
+F = ffi.new("octet*")
+Fval = ffi.new("char []", lenEF)
+F[0].val = Fval
+F[0].max = lenEF
+F[0].len = lenEF
+
+# H(ID)
+HID = ffi.new("octet*")
+HIDval = ffi.new("char []", G1)
+HID[0].val = HIDval
+HID[0].max = G1
+HID[0].len = G1
+
+# H(T|H(ID))
+HTID = ffi.new("octet*")
+HTIDval = ffi.new("char []", G1)
+HTID[0].val = HTIDval
+HTID[0].max = G1
+HTID[0].len = G1
+
+
+class TestMPIN(unittest.TestCase):
+    """Tests M-Pin crypto code"""
+
+    def setUp(self):
+
+        # Form MPin ID
+        endUserData = {
+            "issued": "2013-10-19T06:12:28Z",
+            "userID": "testUser@miracl.com",
+            "mobile": 1,
+            "salt": "e985da112a378c222cfc2f7226097b0c"
+        }
+        mpin_id = json.dumps(endUserData)
+
+        self.MPIN_ID = ffi.new("octet*")
+        self.MPIN_IDval = ffi.new("char [%s]" % len(mpin_id), mpin_id)
+        self.MPIN_ID[0].val = self.MPIN_IDval
+        self.MPIN_ID[0].max = len(mpin_id)
+        self.MPIN_ID[0].len = len(mpin_id)
+
+        # Hash value of MPIN_ID
+        self.HASH_MPIN_ID = ffi.new("octet*")
+        self.HASH_MPIN_IDval = ffi.new("char []",  HASH_BYTES)
+        self.HASH_MPIN_ID[0].val = self.HASH_MPIN_IDval
+        self.HASH_MPIN_ID[0].max = HASH_BYTES
+        self.HASH_MPIN_ID[0].len = HASH_BYTES
+        libmpin.MPIN_HASH_ID(self.MPIN_ID, self.HASH_MPIN_ID)
+
+        # Assign a seed value
+        seedHex = "3ade3d4a5c698e8910bf92f25d97ceeb7c25ed838901a5cb5db2cf25434c1fe76c7f79b7af2e5e1e4988e4294dbd9bd9fa3960197fb7aec373609fb890d74b16a4b14b2ae7e23b75f15d36c21791272372863c4f8af39980283ae69a79cf4e48e908f9e0"
+        self.seed = seedHex.decode("hex")
+        self.RAW = ffi.new("octet*")
+        self.RAWval = ffi.new("char [%s]" % len(self.seed), self.seed)
+        self.RAW[0].val = self.RAWval
+        self.RAW[0].len = len(self.seed)
+        self.RAW[0].max = len(self.seed)
+
+        self.date = 16238
+
+    def test_1(self):
+        """test_1 Good PIN and good token"""
+        PIN1 = 1234
+        PIN2 = 1234
+
+        # random number generator
+        RNG = ffi.new("csprng*")
+        libmpin.MPIN_CREATE_CSPRNG(RNG, self.RAW)
+
+        # Generate Client master secret share for MIRACL and Customer
+        rtn = libmpin.MPIN_RANDOM_GENERATE(RNG, MS1)
+        self.assertEqual(rtn, 0)
+        rtn = libmpin.MPIN_RANDOM_GENERATE(RNG, MS2)
+        self.assertEqual(rtn, 0)
+
+        # Generate server secret shares
+        rtn = libmpin.MPIN_GET_SERVER_SECRET(MS1, SS1)
+        self.assertEqual(rtn, 0)
+        rtn = libmpin.MPIN_GET_SERVER_SECRET(MS2, SS2)
+        self.assertEqual(rtn, 0)
+
+        # Combine server secret shares
+        rtn = libmpin.MPIN_RECOMBINE_G2(SS1, SS2, SERVER_SECRET)
+        self.assertEqual(rtn, 0)
+
+        # Generate client secret shares
+        rtn = libmpin.MPIN_GET_CLIENT_SECRET(MS1, self.HASH_MPIN_ID, CS1)
+        self.assertEqual(rtn, 0)
+        rtn = libmpin.MPIN_GET_CLIENT_SECRET(MS2, self.HASH_MPIN_ID, CS2)
+        self.assertEqual(rtn, 0)
+
+        # Combine client secret shares : TOKEN is the full client secret
+        rtn = libmpin.MPIN_RECOMBINE_G1(CS1, CS2, TOKEN)
+        self.assertEqual(rtn, 0)
+
+        # Generate Time Permit shares
+        rtn = libmpin.MPIN_GET_CLIENT_PERMIT(self.date, MS1, self.HASH_MPIN_ID, TP1)
+        self.assertEqual(rtn, 0)
+        rtn = libmpin.MPIN_GET_CLIENT_PERMIT(self.date, MS2, self.HASH_MPIN_ID, TP2)
+        self.assertEqual(rtn, 0)
+
+        # Combine Time Permit shares
+        rtn = libmpin.MPIN_RECOMBINE_G1(TP1, TP2, TIME_PERMIT)
+        self.assertEqual(rtn, 0)
+
+        # Client extracts PIN from secret to create Token
+        PIN1 = 1234
+        rtn = libmpin.MPIN_EXTRACT_PIN(self.MPIN_ID, PIN1, TOKEN)
+        self.assertEqual(rtn, 0)
+
+        # Client first pass
+        rtn = libmpin.MPIN_CLIENT_1(self.date, self.MPIN_ID, RNG, X, PIN2, TOKEN, SEC, U, UT, TIME_PERMIT)
+        self.assertEqual(rtn, 0)
+
+        # Server calculates H(ID) and H(T|H(ID))
+        libmpin.MPIN_SERVER_1(self.date, self.HASH_MPIN_ID, HID, HTID)
+
+        # Server generates Random number Y and sends it to Client
+        rtn = libmpin.MPIN_RANDOM_GENERATE(RNG, Y)
+        self.assertEqual(rtn, 0)
+
+        # Client second pass
+        rtn = libmpin.MPIN_CLIENT_2(X, Y, SEC)
+        self.assertEqual(rtn, 0)
+
+        # Server second pass
+        rtn = libmpin.MPIN_SERVER_2(self.date, HID, HTID, Y, SERVER_SECRET, U, UT, SEC, E, F)
+        self.assertEqual(rtn, 0)
+
+    def test_2(self):
+        """test_2 Bad PIN and good token"""
+        PIN1 = 1234
+        PIN2 = 2000
+
+        # random number generator
+        RNG = ffi.new("csprng*")
+        libmpin.MPIN_CREATE_CSPRNG(RNG, self.RAW)
+
+        # Generate Client master secret share for MIRACL and Customer
+        rtn = libmpin.MPIN_RANDOM_GENERATE(RNG, MS1)
+        self.assertEqual(rtn, 0)
+        rtn = libmpin.MPIN_RANDOM_GENERATE(RNG, MS2)
+        self.assertEqual(rtn, 0)
+
+        # Generate server secret shares
+        rtn = libmpin.MPIN_GET_SERVER_SECRET(MS1, SS1)
+        self.assertEqual(rtn, 0)
+        rtn = libmpin.MPIN_GET_SERVER_SECRET(MS2, SS2)
+        self.assertEqual(rtn, 0)
+
+        # Combine server secret shares
+        rtn = libmpin.MPIN_RECOMBINE_G2(SS1, SS2, SERVER_SECRET)
+        self.assertEqual(rtn, 0)
+
+        # Generate client secret shares
+        rtn = libmpin.MPIN_GET_CLIENT_SECRET(MS1, self.HASH_MPIN_ID, CS1)
+        self.assertEqual(rtn, 0)
+        rtn = libmpin.MPIN_GET_CLIENT_SECRET(MS2, self.HASH_MPIN_ID, CS2)
+        self.assertEqual(rtn, 0)
+
+        # Combine client secret shares : TOKEN is the full client secret
+        rtn = libmpin.MPIN_RECOMBINE_G1(CS1, CS2, TOKEN)
+        self.assertEqual(rtn, 0)
+
+        # Generate Time Permit shares
+        rtn = libmpin.MPIN_GET_CLIENT_PERMIT(self.date, MS1, self.HASH_MPIN_ID, TP1)
+        self.assertEqual(rtn, 0)
+        rtn = libmpin.MPIN_GET_CLIENT_PERMIT(self.date, MS2, self.HASH_MPIN_ID, TP2)
+        self.assertEqual(rtn, 0)
+
+        # Combine Time Permit shares
+        rtn = libmpin.MPIN_RECOMBINE_G1(TP1, TP2, TIME_PERMIT)
+        self.assertEqual(rtn, 0)
+
+        # Client extracts PIN from secret to create Token
+        PIN1 = 1234
+        rtn = libmpin.MPIN_EXTRACT_PIN(self.MPIN_ID, PIN1, TOKEN)
+        self.assertEqual(rtn, 0)
+
+        # Client first pass
+        rtn = libmpin.MPIN_CLIENT_1(self.date, self.MPIN_ID, RNG, X, PIN2, TOKEN, SEC, U, UT, TIME_PERMIT)
+        self.assertEqual(rtn, 0)
+
+        # Server calculates H(ID) and H(T|H(ID))
+        libmpin.MPIN_SERVER_1(self.date, self.HASH_MPIN_ID, HID, HTID)
+
+        # Server generates Random number Y and sends it to Client
+        rtn = libmpin.MPIN_RANDOM_GENERATE(RNG, Y)
+        self.assertEqual(rtn, 0)
+
+        # Client second pass
+        rtn = libmpin.MPIN_CLIENT_2(X, Y, SEC)
+        self.assertEqual(rtn, 0)
+
+        # Server second pass
+        rtn = libmpin.MPIN_SERVER_2(self.date, HID, HTID, Y, SERVER_SECRET, U, UT, SEC, E, F)
+        self.assertEqual(rtn, -19)
+
+    def test_3(self):
+        """test_3 Good PIN and bad token"""
+        PIN1 = 1234
+        PIN2 = 1234
+
+        # random number generator
+        RNG = ffi.new("csprng*")
+        libmpin.MPIN_CREATE_CSPRNG(RNG, self.RAW)
+
+        # Generate Client master secret share for MIRACL and Customer
+        rtn = libmpin.MPIN_RANDOM_GENERATE(RNG, MS1)
+        self.assertEqual(rtn, 0)
+        rtn = libmpin.MPIN_RANDOM_GENERATE(RNG, MS2)
+        self.assertEqual(rtn, 0)
+
+        # Generate server secret shares
+        rtn = libmpin.MPIN_GET_SERVER_SECRET(MS1, SS1)
+        self.assertEqual(rtn, 0)
+        rtn = libmpin.MPIN_GET_SERVER_SECRET(MS2, SS2)
+        self.assertEqual(rtn, 0)
+
+        # Combine server secret shares
+        rtn = libmpin.MPIN_RECOMBINE_G2(SS1, SS2, SERVER_SECRET)
+        self.assertEqual(rtn, 0)
+
+        # Generate client secret shares
+        rtn = libmpin.MPIN_GET_CLIENT_SECRET(MS1, self.HASH_MPIN_ID, CS1)
+        self.assertEqual(rtn, 0)
+        rtn = libmpin.MPIN_GET_CLIENT_SECRET(MS2, self.HASH_MPIN_ID, CS2)
+        self.assertEqual(rtn, 0)
+
+        # Combine client secret shares : TOKEN is the full client secret
+        rtn = libmpin.MPIN_RECOMBINE_G1(CS1, CS2, TOKEN)
+        self.assertEqual(rtn, 0)
+
+        # Generate Time Permit shares
+        rtn = libmpin.MPIN_GET_CLIENT_PERMIT(self.date, MS1, self.HASH_MPIN_ID, TP1)
+        self.assertEqual(rtn, 0)
+        rtn = libmpin.MPIN_GET_CLIENT_PERMIT(self.date, MS2, self.HASH_MPIN_ID, TP2)
+        self.assertEqual(rtn, 0)
+
+        # Combine Time Permit shares
+        rtn = libmpin.MPIN_RECOMBINE_G1(TP1, TP2, TIME_PERMIT)
+        self.assertEqual(rtn, 0)
+
+        # Client extracts PIN from secret to create Token
+        PIN1 = 1234
+        rtn = libmpin.MPIN_EXTRACT_PIN(self.MPIN_ID, PIN1, TOKEN)
+        self.assertEqual(rtn, 0)
+
+        # Client first pass
+        rtn = libmpin.MPIN_CLIENT_1(self.date, self.MPIN_ID, RNG, X, PIN2, TOKEN, SEC, U, UT, TIME_PERMIT)
+        self.assertEqual(rtn, 0)
+
+        # Server calculates H(ID) and H(T|H(ID))
+        libmpin.MPIN_SERVER_1(self.date, self.HASH_MPIN_ID, HID, HTID)
+
+        # Server generates Random number Y and sends it to Client
+        rtn = libmpin.MPIN_RANDOM_GENERATE(RNG, Y)
+        self.assertEqual(rtn, 0)
+
+        # Client second pass
+        rtn = libmpin.MPIN_CLIENT_2(X, Y, SEC)
+        self.assertEqual(rtn, 0)
+
+        # Server second pass
+        # clientSecret aka V is equal to UT to model a bad token
+        rtn = libmpin.MPIN_SERVER_2(self.date, HID, HTID, Y, SERVER_SECRET, U, UT, UT, E, F)
+        self.assertEqual(rtn, -19)
+
+    def test_4(self):
+        """test_4 Test hash function"""
+        HASH_MPIN_ID = ffi.new("octet*")
+        HASH_MPIN_IDval = ffi.new("char []",  HASH_BYTES)
+        HASH_MPIN_ID[0].val = HASH_MPIN_IDval
+        HASH_MPIN_ID[0].max = HASH_BYTES
+        HASH_MPIN_ID[0].len = HASH_BYTES
+
+        for i in range(1, 10000):
+            bytesStr = os.urandom(128)
+            hash_object2 = hashlib.sha256(bytesStr)
+            digest = hash_object2.hexdigest()
+            MPIN_ID = ffi.new("octet*")
+            MPIN_IDval = ffi.new("char [%s]" % len(bytesStr), bytesStr)
+            MPIN_ID[0].val = MPIN_IDval
+            MPIN_ID[0].max = len(bytesStr)
+            MPIN_ID[0].len = len(bytesStr)
+            libmpin.MPIN_HASH_ID(MPIN_ID, HASH_MPIN_ID)
+            self.assertEqual(digest, toHex(HASH_MPIN_ID))
+
+    def test_5(self):
+        """test_5 Make sure all client secret are unique"""
+        # random number generator
+        RNG = ffi.new("csprng*")
+        libmpin.MPIN_CREATE_CSPRNG(RNG, self.RAW)
+
+        # Generate master secret share
+        rtn = libmpin.MPIN_RANDOM_GENERATE(RNG, MS1)
+        self.assertEqual(rtn, 0)
+
+        s = set()
+        match = 0
+        for i in range(1, 1000):
+            rand_val = os.urandom(32)
+            HASH_MPIN_ID = ffi.new("octet*")
+            HASH_MPIN_IDval = ffi.new("char [%s]" % HASH_BYTES, rand_val)
+            HASH_MPIN_ID[0].val = HASH_MPIN_IDval
+            HASH_MPIN_ID[0].max = HASH_BYTES
+            HASH_MPIN_ID[0].len = HASH_BYTES
+
+            # Generate client secret shares
+            rtn = libmpin.MPIN_GET_CLIENT_SECRET(MS1, HASH_MPIN_ID, CS1)
+            self.assertEqual(rtn, 0)
+            cs1Hex = toHex(CS1)
+            if cs1Hex in s:
+                match = 1
+            self.assertEqual(match, 0)
+            s.add(cs1Hex)
+
+    def test_6(self):
+        """test_6 Make sure all one time passwords are random i.e. they should collide"""
+        # random number generator
+        RNG = ffi.new("csprng*")
+        libmpin.MPIN_CREATE_CSPRNG(RNG, self.RAW)
+
+        s = set()
+        match = 0
+        for i in range(1, 10000):
+            OTP = libmpin.generateOTP(RNG)
+            if OTP in s:
+                # print i
+                match = 1
+            s.add(OTP)
+        self.assertEqual(match, 1)
+
+    def test_7(self):
+        """test_7 Make sure all random values are random i.e. they should collide"""
+        # random number generator
+        RNG = ffi.new("csprng*")
+        libmpin.MPIN_CREATE_CSPRNG(RNG, self.RAW)
+
+        # Generate 100 byte random number
+        RANDOMlen = 3
+        RANDOM = ffi.new("octet*")
+        RANDOMval = ffi.new("char []",  RANDOMlen)
+        RANDOM[0].val = RANDOMval
+        RANDOM[0].max = RANDOMlen
+        RANDOM[0].len = RANDOMlen
+
+        s = set()
+        match = 0
+        for i in range(1, 10000):
+            libmpin.generateRandom(RNG, RANDOM)
+            random = toHex(RANDOM)
+            if random in s:
+                # print i
+                match = 1
+            s.add(random)
+        self.assertEqual(match, 1)
+
+    def test_8(self):
+        """test_8 AES-GCM: Successful encryption and decryption"""
+
+        # Generate 16 byte key
+        key_val = os.urandom(PAS)
+        AES_KEY = ffi.new("octet*")
+        AES_KEYval = ffi.new("char [%s]" % PAS, key_val)
+        AES_KEY[0].val = AES_KEYval
+        AES_KEY[0].max = PAS
+        AES_KEY[0].len = PAS
+
+        # Generate 12 byte IV
+        iv_val = os.urandom(IVL)
+        IV = ffi.new("octet*")
+        IVval = ffi.new("char [%s]" % IVL, iv_val)
+        IV[0].val = IVval
+        IV[0].max = IVL
+        IV[0].len = IVL
+
+        # Generate a 32 byte random header
+        header_val = os.urandom(32)
+        HEADER = ffi.new("octet*")
+        HEADERval = ffi.new("char [%s]" % len(header_val), header_val)
+        HEADER[0].val = HEADERval
+        HEADER[0].max = len(header_val)
+        HEADER[0].len = len(header_val)
+
+        # Plaintext input
+        plaintext1 = "A test message"
+        PLAINTEXT1 = ffi.new("octet*")
+        PLAINTEXT1val = ffi.new("char [%s]" % len(plaintext1), plaintext1)
+        PLAINTEXT1[0].val = PLAINTEXT1val
+        PLAINTEXT1[0].max = len(plaintext1)
+        PLAINTEXT1[0].len = len(plaintext1)
+        # print "Input message: %s" % ffi.string(PLAINTEXT1[0].val, PLAINTEXT1[0].len)
+
+        # Ciphertext
+        CIPHERTEXT = ffi.new("octet*")
+        CIPHERTEXTval = ffi.new("char []", len(plaintext1))
+        CIPHERTEXT[0].val = CIPHERTEXTval
+        CIPHERTEXT[0].max = len(plaintext1)
+
+        # 16 byte authentication tag
+        TAG1 = ffi.new("octet*")
+        TAG1val = ffi.new("char []",  PAS)
+        TAG1[0].val = TAG1val
+        TAG1[0].max = PAS
+
+        libmpin.MPIN_AES_GCM_ENCRYPT(AES_KEY, IV, HEADER, PLAINTEXT1, CIPHERTEXT, TAG1)
+        # Plaintext output
+        PLAINTEXT2 = ffi.new("octet*")
+        PLAINTEXT2val = ffi.new("char []", CIPHERTEXT[0].len)
+        PLAINTEXT2[0].val = PLAINTEXT2val
+        PLAINTEXT2[0].max = CIPHERTEXT[0].len
+        PLAINTEXT2[0].len = CIPHERTEXT[0].len
+
+        # 16 byte authentication tag
+        TAG2 = ffi.new("octet*")
+        TAG2val = ffi.new("char []", PAS)
+        TAG2[0].val = TAG2val
+        TAG2[0].max = PAS
+
+        libmpin.MPIN_AES_GCM_DECRYPT(AES_KEY, IV, HEADER, CIPHERTEXT, PLAINTEXT2, TAG2)
+        self.assertEqual(toHex(TAG1), toHex(TAG2))
+        self.assertEqual(toHex(PLAINTEXT1), toHex(PLAINTEXT2))
+        # print "Output message: %s" % ffi.string(PLAINTEXT2[0].val, PLAINTEXT2[0].len)
+
+    def test_9(self):
+        """test_9 AES-GCM: Failed encryption and decryption by changing a ciphertext byte"""
+
+        # Generate 16 byte key
+        key_val = os.urandom(PAS)
+        AES_KEY = ffi.new("octet*")
+        AES_KEYval = ffi.new("char [%s]" % PAS, key_val)
+        AES_KEY[0].val = AES_KEYval
+        AES_KEY[0].max = PAS
+        AES_KEY[0].len = PAS
+
+        # Generate 12 byte IV
+        iv_val = os.urandom(IVL)
+        IV = ffi.new("octet*")
+        IVval = ffi.new("char [%s]" % IVL, iv_val)
+        IV[0].val = IVval
+        IV[0].max = IVL
+        IV[0].len = IVL
+
+        # Generate a 32 byte random header
+        header_val = os.urandom(32)
+        HEADER = ffi.new("octet*")
+        HEADERval = ffi.new("char [%s]" % len(header_val), header_val)
+        HEADER[0].val = HEADERval
+        HEADER[0].max = len(header_val)
+        HEADER[0].len = len(header_val)
+
+        # Plaintext input
+        plaintext1 = "A test message"
+        PLAINTEXT1 = ffi.new("octet*")
+        PLAINTEXT1val = ffi.new("char [%s]" % len(plaintext1), plaintext1)
+        PLAINTEXT1[0].val = PLAINTEXT1val
+        PLAINTEXT1[0].max = len(plaintext1)
+        PLAINTEXT1[0].len = len(plaintext1)
+        # print "Input message: %s" % ffi.string(PLAINTEXT1[0].val, PLAINTEXT1[0].len)
+
+        # Ciphertext
+        CIPHERTEXT = ffi.new("octet*")
+        CIPHERTEXTval = ffi.new("char []", len(plaintext1))
+        CIPHERTEXT[0].val = CIPHERTEXTval
+        CIPHERTEXT[0].max = len(plaintext1)
+
+        # 16 byte authentication tag
+        TAG1 = ffi.new("octet*")
+        TAG1val = ffi.new("char []",  PAS)
+        TAG1[0].val = TAG1val
+        TAG1[0].max = PAS
+
+        libmpin.MPIN_AES_GCM_ENCRYPT(AES_KEY, IV, HEADER, PLAINTEXT1, CIPHERTEXT, TAG1)
+
+        # Change one byte of ciphertext
+        CIPHERTEXT[0].val[0] = "\xa5"
+
+        # Plaintext output
+        PLAINTEXT2 = ffi.new("octet*")
+        PLAINTEXT2val = ffi.new("char []", CIPHERTEXT[0].len)
+        PLAINTEXT2[0].val = PLAINTEXT2val
+        PLAINTEXT2[0].max = CIPHERTEXT[0].len
+        PLAINTEXT2[0].len = CIPHERTEXT[0].len
+
+        # 16 byte authentication tag
+        TAG2 = ffi.new("octet*")
+        TAG2val = ffi.new("char []", PAS)
+        TAG2[0].val = TAG2val
+        TAG2[0].max = PAS
+
+        libmpin.MPIN_AES_GCM_DECRYPT(AES_KEY, IV, HEADER, CIPHERTEXT, PLAINTEXT2, TAG2)
+        self.assertNotEqual(toHex(TAG1), toHex(TAG2))
+        self.assertNotEqual(toHex(PLAINTEXT1), toHex(PLAINTEXT2))
+        # print "Output message: %s" % ffi.string(PLAINTEXT2[0].val, PLAINTEXT2[0].len)
+
+    def test_10(self):
+        """test_10 AES-GCM: Failed encryption and decryption by changing a header byte"""
+
+        # Generate 16 byte key
+        key_val = os.urandom(PAS)
+        AES_KEY = ffi.new("octet*")
+        AES_KEYval = ffi.new("char [%s]" % PAS, key_val)
+        AES_KEY[0].val = AES_KEYval
+        AES_KEY[0].max = PAS
+        AES_KEY[0].len = PAS
+
+        # Generate 12 byte IV
+        iv_val = os.urandom(IVL)
+        IV = ffi.new("octet*")
+        IVval = ffi.new("char [%s]" % IVL, iv_val)
+        IV[0].val = IVval
+        IV[0].max = IVL
+        IV[0].len = IVL
+
+        # Generate a 32 byte random header
+        header_val = os.urandom(32)
+        HEADER = ffi.new("octet*")
+        HEADERval = ffi.new("char [%s]" % len(header_val), header_val)
+        HEADER[0].val = HEADERval
+        HEADER[0].max = len(header_val)
+        HEADER[0].len = len(header_val)
+
+        # Plaintext input
+        plaintext1 = "A test message"
+        PLAINTEXT1 = ffi.new("octet*")
+        PLAINTEXT1val = ffi.new("char [%s]" % len(plaintext1), plaintext1)
+        PLAINTEXT1[0].val = PLAINTEXT1val
+        PLAINTEXT1[0].max = len(plaintext1)
+        PLAINTEXT1[0].len = len(plaintext1)
+        # print "Input message: %s" % ffi.string(PLAINTEXT1[0].val, PLAINTEXT1[0].len)
+
+        # Ciphertext
+        CIPHERTEXT = ffi.new("octet*")
+        CIPHERTEXTval = ffi.new("char []", len(plaintext1))
+        CIPHERTEXT[0].val = CIPHERTEXTval
+        CIPHERTEXT[0].max = len(plaintext1)
+
+        # 16 byte authentication tag
+        TAG1 = ffi.new("octet*")
+        TAG1val = ffi.new("char []",  PAS)
+        TAG1[0].val = TAG1val
+        TAG1[0].max = PAS
+
+        libmpin.MPIN_AES_GCM_ENCRYPT(AES_KEY, IV, HEADER, PLAINTEXT1, CIPHERTEXT, TAG1)
+        # Plaintext output
+        PLAINTEXT2 = ffi.new("octet*")
+        PLAINTEXT2val = ffi.new("char []", CIPHERTEXT[0].len)
+        PLAINTEXT2[0].val = PLAINTEXT2val
+        PLAINTEXT2[0].max = CIPHERTEXT[0].len
+        PLAINTEXT2[0].len = CIPHERTEXT[0].len
+
+        # Change one byte of header
+        HEADER[0].val[0] = "\xa5"
+
+        # 16 byte authentication tag
+        TAG2 = ffi.new("octet*")
+        TAG2val = ffi.new("char []", PAS)
+        TAG2[0].val = TAG2val
+        TAG2[0].max = PAS
+
+        libmpin.MPIN_AES_GCM_DECRYPT(AES_KEY, IV, HEADER, CIPHERTEXT, PLAINTEXT2, TAG2)
+        self.assertNotEqual(toHex(TAG1), toHex(TAG2))
+        self.assertEqual(toHex(PLAINTEXT1), toHex(PLAINTEXT2))
+
+if __name__ == '__main__':
+    # Run tests
+    unittest.main()
diff --git a/pythonCFFI/TestMPINBNCX.py b/pythonCFFI/TestMPINBNCX.py
deleted file mode 100755
index 23cbd43..0000000
--- a/pythonCFFI/TestMPINBNCX.py
+++ /dev/null
@@ -1,584 +0,0 @@
-#!/usr/bin/env python
-
-"""
-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 unittest
-import json
-import hashlib
-
-from mpin import ffi, G1, G2, HASH_BYTES, libmpin, PFS, PGS, toHex
-
-# Master Secret Shares
-MS1 = ffi.new("octet*")
-MS1val = ffi.new("char []", PGS)
-MS1[0].val = MS1val
-MS1[0].max = PGS
-MS1[0].len = PGS
-
-MS2 = ffi.new("octet*")
-MS2val = ffi.new("char []", PGS)
-MS2[0].val = MS2val
-MS2[0].max = PGS
-MS2[0].len = PGS
-
-# Client secret and shares
-CS1 = ffi.new("octet*")
-CS1val = ffi.new("char []", G1)
-CS1[0].val = CS1val
-CS1[0].max = G1
-CS1[0].len = G1
-
-CS2 = ffi.new("octet*")
-CS2val = ffi.new("char []", G1)
-CS2[0].val = CS2val
-CS2[0].max = G1
-CS2[0].len = G1
-
-SEC = ffi.new("octet*")
-SECval = ffi.new("char []", G1)
-SEC[0].val = SECval
-SEC[0].max = G1
-SEC[0].len = G1
-
-# Server secret and shares
-SS1 = ffi.new("octet*")
-SS1val = ffi.new("char []", G2)
-SS1[0].val = SS1val
-SS1[0].max = G2
-SS1[0].len = G2
-
-SS2 = ffi.new("octet*")
-SS2val = ffi.new("char []", G2)
-SS2[0].val = SS2val
-SS2[0].max = G2
-SS2[0].len = G2
-
-SERVER_SECRET = ffi.new("octet*")
-SERVER_SECRETval = ffi.new("char []", G2)
-SERVER_SECRET[0].val = SERVER_SECRETval
-SERVER_SECRET[0].max = G2
-SERVER_SECRET[0].len = G2
-
-# Time Permit and shares
-TP1 = ffi.new("octet*")
-TP1val = ffi.new("char []", G1)
-TP1[0].val = TP1val
-TP1[0].max = G1
-TP1[0].len = G1
-
-TP2 = ffi.new("octet*")
-TP2val = ffi.new("char []", G1)
-TP2[0].val = TP2val
-TP2[0].max = G1
-TP2[0].len = G1
-
-TIME_PERMIT = ffi.new("octet*")
-TIME_PERMITval = ffi.new("char []", G1)
-TIME_PERMIT[0].val = TIME_PERMITval
-TIME_PERMIT[0].max = G1
-TIME_PERMIT[0].len = G1
-
-# Token stored on computer
-TOKEN = ffi.new("octet*")
-TOKENval = ffi.new("char []", G1)
-TOKEN[0].val = TOKENval
-TOKEN[0].max = G1
-TOKEN[0].len = G1
-
-UT = ffi.new("octet*")
-UTval = ffi.new("char []", G1)
-UT[0].val = UTval
-UT[0].max = G1
-UT[0].len = G1
-
-U = ffi.new("octet*")
-Uval = ffi.new("char []", G1)
-U[0].val = Uval
-U[0].max = G1
-U[0].len = G1
-
-X = ffi.new("octet*")
-Xval = ffi.new("char []", PGS)
-X[0].val = Xval
-X[0].max = PGS
-X[0].len = PGS
-
-Y = ffi.new("octet*")
-Yval = ffi.new("char []", PGS)
-Y[0].val = Yval
-Y[0].max = PGS
-Y[0].len = PGS
-
-lenEF = 12 * PFS
-E = ffi.new("octet*")
-Eval = ffi.new("char []", lenEF)
-E[0].val = Eval
-E[0].max = lenEF
-E[0].len = lenEF
-
-F = ffi.new("octet*")
-Fval = ffi.new("char []", lenEF)
-F[0].val = Fval
-F[0].max = lenEF
-F[0].len = lenEF
-
-# H(ID)
-HID = ffi.new("octet*")
-HIDval = ffi.new("char []", G1)
-HID[0].val = HIDval
-HID[0].max = G1
-HID[0].len = G1
-
-# H(T|H(ID))
-HTID = ffi.new("octet*")
-HTIDval = ffi.new("char []", G1)
-HTID[0].val = HTIDval
-HTID[0].max = G1
-HTID[0].len = G1
-
-
-class TestMPIN(unittest.TestCase):
-    """Tests M-Pin crypto code"""
-
-    def setUp(self):
-
-        # Form MPin ID
-        endUserData = {
-            "issued": "2013-10-19T06:12:28Z",
-            "userID": "testUser@miracl.com",
-            "mobile": 1,
-            "salt": "e985da112a378c222cfc2f7226097b0c"
-        }
-        mpin_id = json.dumps(endUserData)
-
-        self.MPIN_ID = ffi.new("octet*")
-        self.MPIN_IDval = ffi.new("char [%s]" % len(mpin_id), mpin_id)
-        self.MPIN_ID[0].val = self.MPIN_IDval
-        self.MPIN_ID[0].max = len(mpin_id)
-        self.MPIN_ID[0].len = len(mpin_id)
-
-        # Hash value of MPIN_ID
-        self.HASH_MPIN_ID = ffi.new("octet*")
-        self.HASH_MPIN_IDval = ffi.new("char []",  HASH_BYTES)
-        self.HASH_MPIN_ID[0].val = self.HASH_MPIN_IDval
-        self.HASH_MPIN_ID[0].max = HASH_BYTES
-        self.HASH_MPIN_ID[0].len = HASH_BYTES
-        libmpin.MPIN_HASH_ID(self.MPIN_ID, self.HASH_MPIN_ID)
-
-        # Assign a seed value
-        seedHex = "3ade3d4a5c698e8910bf92f25d97ceeb7c25ed838901a5cb5db2cf25434c1fe76c7f79b7af2e5e1e4988e4294dbd9bd9fa3960197fb7aec373609fb890d74b16a4b14b2ae7e23b75f15d36c21791272372863c4f8af39980283ae69a79cf4e48e908f9e0"
-        self.seed = seedHex.decode("hex")
-        self.RAW = ffi.new("octet*")
-        self.RAWval = ffi.new("char [%s]" % len(self.seed), self.seed)
-        self.RAW[0].val = self.RAWval
-        self.RAW[0].len = len(self.seed)
-        self.RAW[0].max = len(self.seed)
-
-        self.date = 16238
-        self.ms1Hex = "035fb3138d1dfa87cd7aab637faa7400f0c8416ab7e922ddea8dc0462bc0123a"
-        self.ms2Hex = "1c9c8ad28f36fd10f5f33ea3b9db0a1eaf8ef7fc13cd55d1b47d7e607e3ca619"
-        self.ss1Hex = "114658f8ccb93969fc7ec23257397dbe820a329016182d3168cb2d9b8ce9cbcc0d580feb5b621d6c00ed12e70688ec130a138a48b2c2fd57695bad71290c365d1d621117cbcd2061357965ca2f81468979ca527c9888ae87d84d8df0589e6814041a1ca3163dd77d9b0c29c0a6aadca1cbaa7c2905d8eb8ab12051ea06f12439"
-        self.ss2Hex = "239b55f12040f70b6a5e53c45985aa4bfa368a3d26a000775f7960a2716023350b08851b5753c33bddba07c172f4745abb70e587902dca52e49199ee4c2562130a910fb6402c417e753a873b907153820ae5854a4c27948806000e82452d77f3127e66573cae233c07137e63fbac8f09ef39718c421f71f1b9be5f150a17bd12"
-        self.serverSecretHex = "09aa0e36fa30c9b0cc9d5fa7b2be33595542f408a49ad0c91c4f7bba3d993cfc23eca9811699525fa8523069b6d6e1540deeb94eaa26c1e15776b4ab65e4603c0a161baa02d75fb1e966863b51ac5ee67872f663926b8537292dd170e83a136e098e2da97161db6c75a182088af1da6557d06a7816ec6ac7882262ce183fc605"
-        self.cs1Hex = "04050de8b61fa91b4747017a7ed72ceb4b26056382435413eab2b9259a4c99f9161eb63db017296616b59b861f2433f44cc56a3d8d5ed600cf338de0f7ce62b900"
-        self.cs2Hex = "0420b7333796a1d7a5abc553dcbacff281f5a4b8dea937da548ee6103c0089b6a218e0d1d617a55f9b789c4ebd25f5cf8aafd0f666306031cf5b6faa9e50d88f50"
-        self.clientSecretHex = "040b98a2b31786a50f548bd692171f99d1d1be26129725519624d3cc90b98bd17321a24c5b9511ff887672e460d6157b1c5461114e4e4f62d6207f5e8d48919fad"
-        self.tp1Hex = "04123c806b8366721e3718a731fa109c144561f033ff5fe44356091a3c2365c9182218b86526247eb7fd552575800ef3cc9da22c6655d7795377b216030c9f1f62"
-        self.tp2Hex = "041cf3f5604e5f8ecb44bc3e36f5fa1fe68e873b0822646a3a8f0fcf0477f561241a6bda4a9e93a455a6b940126feae5959ca855870cd8275d7dd1a4df4ddb6211"
-        self.timePermitHex = "0405198cbd152cfc860cc22d6c16d92ff1a1d5d6d9b268588c3a74c4e6fc056a0002d35c769458aaaf01ecc34cbaf7b6d8154deb2d26db332c5a421557f4fe1ba3"
-        self.tokenHex = "04213945622f5c6638c13692d77f12983cb0664fb51f7f36a5664872894b87dc051786a8747cf01b749f78fb75aa64bc932e71c9a6e1ee261aa687564bf38be329"
-
-        # Token
-        self.token = self.tokenHex.decode("hex")
-        self.TOKEN = ffi.new("octet*")
-        self.TOKENval = ffi.new("char [%s]" % len(self.token), self.token)
-        self.TOKEN[0].val = self.TOKENval
-        self.TOKEN[0].len = len(self.token)
-        self.TOKEN[0].max = len(self.token)
-
-        # TIME_PERMIT
-        self.timePermit = self.timePermitHex.decode("hex")
-        self.TIMEPERMIT = ffi.new("octet*")
-        self.TIMEPERMITval = ffi.new("char [%s]" % len(self.timePermit), self.timePermit)
-        self.TIMEPERMIT[0].val = self.TIMEPERMITval
-        self.TIMEPERMIT[0].len = len(self.timePermit)
-        self.TIMEPERMIT[0].max = len(self.timePermit)
-
-        # SERVER_SECRET
-        self.serverSecret = self.serverSecretHex.decode("hex")
-        self.SERVER_SECRET = ffi.new("octet*")
-        self.SERVER_SECRETval = ffi.new("char [%s]" % len(self.serverSecret), self.serverSecret)
-        self.SERVER_SECRET[0].val = self.SERVER_SECRETval
-        self.SERVER_SECRET[0].len = len(self.serverSecret)
-        self.SERVER_SECRET[0].max = len(self.serverSecret)
-
-        self.ms1 = self.ms1Hex.decode("hex")
-        self.clientSecret = self.clientSecretHex.decode("hex")
-        self.timePermit = self.timePermitHex.decode("hex")
-
-    def test_1(self):
-        """test_1 Good PIN and good token"""
-        PIN = 1234
-
-        # random number generator
-        RNG = ffi.new("csprng*")
-        libmpin.CREATE_CSPRNG(RNG, self.RAW)
-
-        # Client first pass
-        rtn = libmpin.MPIN_CLIENT_1(self.date, self.MPIN_ID, RNG, X, PIN, self.TOKEN, SEC, U, UT, self.TIMEPERMIT)
-        self.assertEqual(rtn, 0)
-
-        # Server calculates H(ID) and H(T|H(ID))
-        libmpin.MPIN_SERVER_1(self.date, self.MPIN_ID, HID, HTID)
-
-        # Server generates Random number Y and sends it to Client
-        rtn = libmpin.MPIN_RANDOM_GENERATE(RNG, Y)
-        self.assertEqual(rtn, 0)
-
-        # Client second pass
-        rtn = libmpin.MPIN_CLIENT_2(X, Y, SEC)
-        self.assertEqual(rtn, 0)
-
-        # Server second pass
-        rtn = libmpin.MPIN_SERVER_2(self.date, HID, HTID, Y, self.SERVER_SECRET, U, UT, SEC, E, F)
-        self.assertEqual(rtn, 0)
-
-    def test_2(self):
-        """test_2 Bad PIN and good token"""
-        PIN = 2000
-
-        # random number generator
-        RNG = ffi.new("csprng*")
-        libmpin.CREATE_CSPRNG(RNG, self.RAW)
-
-        # Client first pass
-        rtn = libmpin.MPIN_CLIENT_1(self.date, self.MPIN_ID, RNG, X, PIN, self.TOKEN, SEC, U, UT, self.TIMEPERMIT)
-        self.assertEqual(rtn, 0)
-
-        # Server calculates H(ID) and H(T|H(ID))
-        libmpin.MPIN_SERVER_1(self.date, self.MPIN_ID, HID, HTID)
-
-        # Server generates Random number Y and sends it to Client
-        rtn = libmpin.MPIN_RANDOM_GENERATE(RNG, Y)
-        self.assertEqual(rtn, 0)
-
-        # Client second pass
-        rtn = libmpin.MPIN_CLIENT_2(X, Y, SEC)
-        self.assertEqual(rtn, 0)
-
-        # Server second pass
-        rtn = libmpin.MPIN_SERVER_2(self.date, HID, HTID, Y, self.SERVER_SECRET, U, UT, SEC, E, F)
-        self.assertEqual(rtn, -19)
-
-    def test_3(self):
-        """test_3 Good PIN and bad token"""
-        PIN = 1234
-
-        # random number generator
-        RNG = ffi.new("csprng*")
-        libmpin.CREATE_CSPRNG(RNG, self.RAW)
-
-        # Client first pass
-        rtn = libmpin.MPIN_CLIENT_1(self.date, self.MPIN_ID, RNG, X, PIN, self.TOKEN, SEC, U, UT, self.TIMEPERMIT)
-        self.assertEqual(rtn, 0)
-
-        # Server calculates H(ID) and H(T|H(ID))
-        libmpin.MPIN_SERVER_1(self.date, self.MPIN_ID, HID, HTID)
-
-        # Server generates Random number Y and sends it to Client
-        rtn = libmpin.MPIN_RANDOM_GENERATE(RNG, Y)
-        self.assertEqual(rtn, 0)
-
-        # Client second pass
-        rtn = libmpin.MPIN_CLIENT_2(X, Y, SEC)
-        self.assertEqual(rtn, 0)
-
-        # Server second pass
-        # clientSecret aka V is equal to UT to model a bad token
-        rtn = libmpin.MPIN_SERVER_2(self.date, HID, HTID, Y, self.SERVER_SECRET, U, UT, UT, E, F)
-        self.assertEqual(rtn, -19)
-
-    def test_4(self):
-        """test_4 Test hash function"""
-        HASH_MPIN_ID = ffi.new("octet*")
-        HASH_MPIN_IDval = ffi.new("char []",  HASH_BYTES)
-        HASH_MPIN_ID[0].val = HASH_MPIN_IDval
-        HASH_MPIN_ID[0].max = HASH_BYTES
-        HASH_MPIN_ID[0].len = HASH_BYTES
-
-        for i in range(1, 10000):
-            bytesStr = os.urandom(128)
-            hash_object2 = hashlib.sha256(bytesStr)
-            digest = hash_object2.hexdigest()
-            MPIN_ID = ffi.new("octet*")
-            MPIN_IDval = ffi.new("char [%s]" % len(bytesStr), bytesStr)
-            MPIN_ID[0].val = MPIN_IDval
-            MPIN_ID[0].max = len(bytesStr)
-            MPIN_ID[0].len = len(bytesStr)
-            libmpin.MPIN_HASH_ID(MPIN_ID, HASH_MPIN_ID)
-            self.assertEqual(digest, toHex(HASH_MPIN_ID))
-
-    def test_5(self):
-        """test_5 Make sure all client secret are unique"""
-        # random number generator
-        RNG = ffi.new("csprng*")
-        libmpin.CREATE_CSPRNG(RNG, self.RAW)
-
-        # Generate master secret share
-        rtn = libmpin.MPIN_RANDOM_GENERATE(RNG, MS1)
-        self.assertEqual(rtn, 0)
-
-        s = set()
-        match = 0
-        for i in range(1, 1000):
-            rand_val = os.urandom(32)
-            HASH_MPIN_ID = ffi.new("octet*")
-            HASH_MPIN_IDval = ffi.new("char [%s]" % HASH_BYTES, rand_val)
-            HASH_MPIN_ID[0].val = HASH_MPIN_IDval
-            HASH_MPIN_ID[0].max = HASH_BYTES
-            HASH_MPIN_ID[0].len = HASH_BYTES
-
-            # Generate client secret shares
-            rtn = libmpin.MPIN_GET_CLIENT_SECRET(MS1, HASH_MPIN_ID, CS1)
-            self.assertEqual(rtn, 0)
-            cs1Hex = toHex(CS1)
-            if cs1Hex in s:
-                match = 1
-            self.assertEqual(match, 0)
-            s.add(cs1Hex)
-
-    def test_6(self):
-        """test_6 Make sure all one time passwords are random i.e. they should collide"""
-        # random number generator
-        RNG = ffi.new("csprng*")
-        libmpin.CREATE_CSPRNG(RNG, self.RAW)
-
-        s = set()
-        match = 0
-        for i in range(1, 10000):
-            OTP = libmpin.generateOTP(RNG)
-            if OTP in s:
-                # print i
-                match = 1
-            s.add(OTP)
-        self.assertEqual(match, 1)
-
-    def test_7(self):
-        """test_7 Make sure all random values are random i.e. they should collide"""
-        # random number generator
-        RNG = ffi.new("csprng*")
-        libmpin.CREATE_CSPRNG(RNG, self.RAW)
-
-        # Generate 100 byte random number
-        RANDOMlen = 3
-        RANDOM = ffi.new("octet*")
-        RANDOMval = ffi.new("char []",  RANDOMlen)
-        RANDOM[0].val = RANDOMval
-        RANDOM[0].max = RANDOMlen
-        RANDOM[0].len = RANDOMlen
-
-        s = set()
-        match = 0
-        for i in range(1, 10000):
-            libmpin.generateRandom(RNG, RANDOM)
-            random = toHex(RANDOM)
-            if random in s:
-                # print i
-                match = 1
-            s.add(random)
-        self.assertEqual(match, 1)
-
-    def test_8(self):
-        """test_8 Generation of secrets and time permits"""
-
-        # random number generator
-        RNG = ffi.new("csprng*")
-        libmpin.CREATE_CSPRNG(RNG, self.RAW)
-
-        # Generate Client master secret share for MIRACL and Customer
-        rtn = libmpin.MPIN_RANDOM_GENERATE(RNG, MS1)
-        self.assertEqual(rtn, 0)
-        self.assertEqual(self.ms1Hex, toHex(MS1))
-        rtn = libmpin.MPIN_RANDOM_GENERATE(RNG, MS2)
-        self.assertEqual(rtn, 0)
-        self.assertEqual(self.ms2Hex, toHex(MS2))
-
-        # Generate server secret shares
-        rtn = libmpin.MPIN_GET_SERVER_SECRET(MS1, SS1)
-        self.assertEqual(rtn, 0)
-        self.assertEqual(self.ss1Hex, toHex(SS1))
-        rtn = libmpin.MPIN_GET_SERVER_SECRET(MS2, SS2)
-        self.assertEqual(rtn, 0)
-        self.assertEqual(self.ss2Hex, toHex(SS2))
-
-        # Combine server secret shares
-        rtn = libmpin.MPIN_RECOMBINE_G2(SS1, SS2, SERVER_SECRET)
-        self.assertEqual(rtn, 0)
-        self.assertEqual(self.serverSecretHex, toHex(SERVER_SECRET))
-
-        # Generate client secret shares
-        rtn = libmpin.MPIN_GET_CLIENT_SECRET(MS1, self.HASH_MPIN_ID, CS1)
-        self.assertEqual(rtn, 0)
-        self.assertEqual(self.cs1Hex, toHex(CS1))
-        rtn = libmpin.MPIN_GET_CLIENT_SECRET(MS2, self.HASH_MPIN_ID, CS2)
-        self.assertEqual(rtn, 0)
-        self.assertEqual(self.cs2Hex, toHex(CS2))
-
-        # Combine client secret shares : TOKEN is the full client secret
-        rtn = libmpin.MPIN_RECOMBINE_G1(CS1, CS2, TOKEN)
-        self.assertEqual(rtn, 0)
-        self.assertEqual(self.clientSecretHex, toHex(TOKEN))
-
-        # Generate Time Permit shares
-        rtn = libmpin.MPIN_GET_CLIENT_PERMIT(self.date, MS1, self.HASH_MPIN_ID, TP1)
-        self.assertEqual(rtn, 0)
-        self.assertEqual(self.tp1Hex, toHex(TP1))
-        rtn = libmpin.MPIN_GET_CLIENT_PERMIT(self.date, MS2, self.HASH_MPIN_ID, TP2)
-        self.assertEqual(rtn, 0)
-        self.assertEqual(self.tp2Hex, toHex(TP2))
-
-        # Combine Time Permit shares
-        rtn = libmpin.MPIN_RECOMBINE_G1(TP1, TP2, TIME_PERMIT)
-        self.assertEqual(rtn, 0)
-        self.assertEqual(self.timePermitHex, toHex(TIME_PERMIT))
-
-        # Client extracts PIN from secret to create Token
-        PIN = 1234
-        rtn = libmpin.MPIN_EXTRACT_PIN(self.MPIN_ID, PIN, TOKEN)
-        self.assertEqual(rtn, 0)
-        self.assertEqual(self.tokenHex, toHex(TOKEN))
-
-    def test_9(self):
-        """test_9 Test successful authentication for different master secrets"""
-
-        for i in range(1, 1000):
-            # Assign a seed value
-            seed = os.urandom(32)
-            RAW = ffi.new("octet*")
-            RAWval = ffi.new("char [%s]" % len(seed), seed)
-            RAW[0].val = RAWval
-            RAW[0].len = len(seed)
-            RAW[0].max = len(seed)
-
-            # random number generator
-            RNG = ffi.new("csprng*")
-            libmpin.CREATE_CSPRNG(RNG, RAW)
-
-            # Generate Client master secret share for MIRACL and Customer
-            rtn = libmpin.MPIN_RANDOM_GENERATE(RNG, MS1)
-            self.assertEqual(rtn, 0)
-            rtn = libmpin.MPIN_RANDOM_GENERATE(RNG, MS2)
-            self.assertEqual(rtn, 0)
-
-            # Generate server secret shares
-            rtn = libmpin.MPIN_GET_SERVER_SECRET(MS1, SS1)
-            self.assertEqual(rtn, 0)
-            rtn = libmpin.MPIN_GET_SERVER_SECRET(MS2, SS2)
-            self.assertEqual(rtn, 0)
-
-            # Combine server secret shares
-            rtn = libmpin.MPIN_RECOMBINE_G2(SS1, SS2, SERVER_SECRET)
-            self.assertEqual(rtn, 0)
-
-            # Generate client secret shares
-            rtn = libmpin.MPIN_GET_CLIENT_SECRET(MS1, self.HASH_MPIN_ID, CS1)
-            self.assertEqual(rtn, 0)
-            rtn = libmpin.MPIN_GET_CLIENT_SECRET(MS2, self.HASH_MPIN_ID, CS2)
-            self.assertEqual(rtn, 0)
-
-            # Combine client secret shares : TOKEN is the full client secret
-            rtn = libmpin.MPIN_RECOMBINE_G1(CS1, CS2, TOKEN)
-            self.assertEqual(rtn, 0)
-
-            # Generate Time Permit shares
-            rtn = libmpin.MPIN_GET_CLIENT_PERMIT(self.date, MS1, self.HASH_MPIN_ID, TP1)
-            self.assertEqual(rtn, 0)
-            rtn = libmpin.MPIN_GET_CLIENT_PERMIT(self.date, MS2, self.HASH_MPIN_ID, TP2)
-            self.assertEqual(rtn, 0)
-
-            # Combine Time Permit shares
-            rtn = libmpin.MPIN_RECOMBINE_G1(TP1, TP2, TIME_PERMIT)
-            self.assertEqual(rtn, 0)
-
-            # Client extracts PIN from secret to create Token
-            PIN = 1234
-            rtn = libmpin.MPIN_EXTRACT_PIN(self.MPIN_ID, PIN, TOKEN)
-            self.assertEqual(rtn, 0)
-
-            # Client first pass
-            rtn = libmpin.MPIN_CLIENT_1(self.date, self.MPIN_ID, RNG, X, PIN, TOKEN, SEC, U, UT, TIME_PERMIT)
-            self.assertEqual(rtn, 0)
-
-            # Server calculates H(ID) and H(T|H(ID))
-            libmpin.MPIN_SERVER_1(self.date, self.MPIN_ID, HID, HTID)
-
-            # Server generates Random number Y and sends it to Client
-            rtn = libmpin.MPIN_RANDOM_GENERATE(RNG, Y)
-            self.assertEqual(rtn, 0)
-
-            # Client second pass
-            rtn = libmpin.MPIN_CLIENT_2(X, Y, SEC)
-            self.assertEqual(rtn, 0)
-
-            # Server second pass
-            rtn = libmpin.MPIN_SERVER_2(self.date, HID, HTID, Y, SERVER_SECRET, U, UT, SEC, E, F)
-            self.assertEqual(rtn, 0)
-
-    def test_10(self):
-        """test_10 Test mss starting with 00 are handled correctly"""
-
-        for i in range(1, 1000):
-            # Assign a seed value
-            seed = os.urandom(32)
-            RAW = ffi.new("octet*")
-            RAWval = ffi.new("char [%s]" % len(seed), seed)
-            RAW[0].val = RAWval
-            RAW[0].len = len(seed)
-            RAW[0].max = len(seed)
-
-            # random number generator
-            RNG = ffi.new("csprng*")
-            libmpin.CREATE_CSPRNG(RNG, RAW)
-
-            # Generate master secret - ms1
-            rtn = libmpin.MPIN_RANDOM_GENERATE(RNG, MS1)
-            self.assertEqual(rtn, 0)
-            ms1_hex = toHex(MS1)
-            ms1 = ms1_hex.decode("hex")
-            # Assign ms1 to ms2 if it starts with "00"
-            if ms1_hex.startswith('00'):
-                MS2 = ffi.new("octet*")
-                MS2val = ffi.new("char [%s]" % PGS, ms1)
-                MS2[0].val = MS2val
-                MS2[0].max = PGS
-                MS2[0].len = PGS
-
-                # Generate client secret shares
-                rtn = libmpin.MPIN_GET_CLIENT_SECRET(MS1, self.HASH_MPIN_ID, CS1)
-                self.assertEqual(rtn, 0)
-                cs1_hex = toHex(CS1)
-                rtn = libmpin.MPIN_GET_CLIENT_SECRET(MS2, self.HASH_MPIN_ID, CS2)
-                self.assertEqual(rtn, 0)
-                cs2_hex = toHex(CS2)
-                self.assertEqual(cs1_hex, cs2_hex)
-
-if __name__ == '__main__':
-    # Run tests
-    unittest.main()
diff --git a/pythonCFFI/TestMPINInstall.py b/pythonCFFI/TestMPINInstall.py
index 525a17e..3c36c55 100755
--- a/pythonCFFI/TestMPINInstall.py
+++ b/pythonCFFI/TestMPINInstall.py
@@ -200,7 +200,7 @@
 
         # random number generator
         RNG = ffi.new("csprng*")
-        libmpin.CREATE_CSPRNG(RNG, self.RAW)
+        libmpin.MPIN_CREATE_CSPRNG(RNG, self.RAW)
 
         # Generate Client master secret share for MIRACL and Customer
         rtn = libmpin.MPIN_RANDOM_GENERATE(RNG, MS1)
@@ -269,7 +269,7 @@
 
         # random number generator
         RNG = ffi.new("csprng*")
-        libmpin.CREATE_CSPRNG(RNG, self.RAW)
+        libmpin.MPIN_CREATE_CSPRNG(RNG, self.RAW)
 
         # Generate Client master secret share for MIRACL and Customer
         rtn = libmpin.MPIN_RANDOM_GENERATE(RNG, MS1)
@@ -338,7 +338,7 @@
 
         # random number generator
         RNG = ffi.new("csprng*")
-        libmpin.CREATE_CSPRNG(RNG, self.RAW)
+        libmpin.MPIN_CREATE_CSPRNG(RNG, self.RAW)
 
         # Generate Client master secret share for MIRACL and Customer
         rtn = libmpin.MPIN_RANDOM_GENERATE(RNG, MS1)
@@ -425,7 +425,7 @@
         """test_5 Make sure all client secret are unique"""
         # random number generator
         RNG = ffi.new("csprng*")
-        libmpin.CREATE_CSPRNG(RNG, self.RAW)
+        libmpin.MPIN_CREATE_CSPRNG(RNG, self.RAW)
 
         # Generate master secret share
         rtn = libmpin.MPIN_RANDOM_GENERATE(RNG, MS1)
@@ -454,7 +454,7 @@
         """test_6 Make sure all one time passwords are random i.e. they should collide"""
         # random number generator
         RNG = ffi.new("csprng*")
-        libmpin.CREATE_CSPRNG(RNG, self.RAW)
+        libmpin.MPIN_CREATE_CSPRNG(RNG, self.RAW)
 
         s = set()
         match = 0
@@ -470,7 +470,7 @@
         """test_7 Make sure all random values are random i.e. they should collide"""
         # random number generator
         RNG = ffi.new("csprng*")
-        libmpin.CREATE_CSPRNG(RNG, self.RAW)
+        libmpin.MPIN_CREATE_CSPRNG(RNG, self.RAW)
 
         # Generate 100 byte random number
         RANDOMlen = 3
@@ -539,7 +539,7 @@
         TAG1[0].val = TAG1val
         TAG1[0].max = PAS
 
-        libmpin.AES_GCM_ENCRYPT(AES_KEY, IV, HEADER, PLAINTEXT1, CIPHERTEXT, TAG1)
+        libmpin.MPIN_AES_GCM_ENCRYPT(AES_KEY, IV, HEADER, PLAINTEXT1, CIPHERTEXT, TAG1)
         # Plaintext output
         PLAINTEXT2 = ffi.new("octet*")
         PLAINTEXT2val = ffi.new("char []", CIPHERTEXT[0].len)
@@ -553,7 +553,7 @@
         TAG2[0].val = TAG2val
         TAG2[0].max = PAS
 
-        libmpin.AES_GCM_DECRYPT(AES_KEY, IV, HEADER, CIPHERTEXT, PLAINTEXT2, TAG2)
+        libmpin.MPIN_AES_GCM_DECRYPT(AES_KEY, IV, HEADER, CIPHERTEXT, PLAINTEXT2, TAG2)
         self.assertEqual(toHex(TAG1), toHex(TAG2))
         self.assertEqual(toHex(PLAINTEXT1), toHex(PLAINTEXT2))
         # print "Output message: %s" % ffi.string(PLAINTEXT2[0].val, PLAINTEXT2[0].len)
@@ -606,7 +606,7 @@
         TAG1[0].val = TAG1val
         TAG1[0].max = PAS
 
-        libmpin.AES_GCM_ENCRYPT(AES_KEY, IV, HEADER, PLAINTEXT1, CIPHERTEXT, TAG1)
+        libmpin.MPIN_AES_GCM_ENCRYPT(AES_KEY, IV, HEADER, PLAINTEXT1, CIPHERTEXT, TAG1)
 
         # Change one byte of ciphertext
         CIPHERTEXT[0].val[0] = "\xa5"
@@ -624,7 +624,7 @@
         TAG2[0].val = TAG2val
         TAG2[0].max = PAS
 
-        libmpin.AES_GCM_DECRYPT(AES_KEY, IV, HEADER, CIPHERTEXT, PLAINTEXT2, TAG2)
+        libmpin.MPIN_AES_GCM_DECRYPT(AES_KEY, IV, HEADER, CIPHERTEXT, PLAINTEXT2, TAG2)
         self.assertNotEqual(toHex(TAG1), toHex(TAG2))
         self.assertNotEqual(toHex(PLAINTEXT1), toHex(PLAINTEXT2))
         # print "Output message: %s" % ffi.string(PLAINTEXT2[0].val, PLAINTEXT2[0].len)
@@ -677,7 +677,7 @@
         TAG1[0].val = TAG1val
         TAG1[0].max = PAS
 
-        libmpin.AES_GCM_ENCRYPT(AES_KEY, IV, HEADER, PLAINTEXT1, CIPHERTEXT, TAG1)
+        libmpin.MPIN_AES_GCM_ENCRYPT(AES_KEY, IV, HEADER, PLAINTEXT1, CIPHERTEXT, TAG1)
         # Plaintext output
         PLAINTEXT2 = ffi.new("octet*")
         PLAINTEXT2val = ffi.new("char []", CIPHERTEXT[0].len)
@@ -694,7 +694,7 @@
         TAG2[0].val = TAG2val
         TAG2[0].max = PAS
 
-        libmpin.AES_GCM_DECRYPT(AES_KEY, IV, HEADER, CIPHERTEXT, PLAINTEXT2, TAG2)
+        libmpin.MPIN_AES_GCM_DECRYPT(AES_KEY, IV, HEADER, CIPHERTEXT, PLAINTEXT2, TAG2)
         self.assertNotEqual(toHex(TAG1), toHex(TAG2))
         self.assertEqual(toHex(PLAINTEXT1), toHex(PLAINTEXT2))
 
diff --git a/pythonCFFI/TimeMPIN.py b/pythonCFFI/TimeMPIN.py
index e0b784c..5273322 100755
--- a/pythonCFFI/TimeMPIN.py
+++ b/pythonCFFI/TimeMPIN.py
@@ -183,7 +183,7 @@
     E = ffi.NULL
     F = ffi.NULL
 
-    date = libmpin.today()
+    date = libmpin.MPIN_today()
     if date:
         HID = ffi.NULL
         U = ffi.NULL
@@ -202,7 +202,7 @@
 
     # random number generator
     RNG = ffi.new("csprng*")
-    libmpin.CREATE_CSPRNG(RNG, RAW)
+    libmpin.MPIN_CREATE_CSPRNG(RNG, RAW)
 
     # Hash MPIN_ID
     libmpin.MPIN_HASH_ID(MPIN_ID, HASH_MPIN_ID)
diff --git a/pythonCFFI/TimeMPINFull.py b/pythonCFFI/TimeMPINFull.py
index e3c1e37..6ca5022 100755
--- a/pythonCFFI/TimeMPINFull.py
+++ b/pythonCFFI/TimeMPINFull.py
@@ -49,7 +49,7 @@
     TIME_PERMITS = True
 
     if TIME_PERMITS:
-        date = libmpin.today()
+        date = libmpin.MPIN_today()
     else:
         date = 0
 
@@ -259,7 +259,7 @@
 
     # random number generator
     RNG = ffi.new("csprng*")
-    libmpin.CREATE_CSPRNG(RNG, RAW)
+    libmpin.MPIN_CREATE_CSPRNG(RNG, RAW)
 
     # Hash MPIN_ID
     libmpin.MPIN_HASH_ID(MPIN_ID,  HASH_MPIN_ID)
diff --git a/pythonCFFI/mpin.py b/pythonCFFI/mpin.py
index 48141b3..7032e45 100755
--- a/pythonCFFI/mpin.py
+++ b/pythonCFFI/mpin.py
@@ -79,12 +79,12 @@
 extern int MPIN_ENCODING(csprng *,octet *);
 extern int MPIN_DECODING(octet *);
 
-extern unsigned int today(void);
-extern void CREATE_CSPRNG(csprng *,octet *);
-extern void KILL_CSPRNG(csprng *);
+extern unsigned int MPIN_today(void);
+extern void MPIN_CREATE_CSPRNG(csprng *,octet *);
+extern void MPIN_KILL_CSPRNG(csprng *);
 extern int MPIN_PRECOMPUTE(octet *,octet *,octet *,octet *);
-extern int MPIN_SERVER_KEY(octet *,octet *,octet *,octet *,octet *,octet *);
-extern int MPIN_CLIENT_KEY(octet *,octet *,int ,octet *,octet *,octet *,octet *);
+extern int MPIN_SERVER_KEY(octet *Z,octet *SS,octet *w,octet *p,octet *I,octet *U,octet *UT,octet *K);
+extern int MPIN_CLIENT_KEY(octet *g1,octet *g2,int pin,octet *r,octet *x,octet *p,octet *T,octet *K);
 extern int MPIN_GET_G1_MULTIPLE(csprng *,int,octet *,octet *,octet *);
 extern int MPIN_GET_CLIENT_SECRET(octet *,octet *,octet *);
 extern int MPIN_GET_CLIENT_PERMIT(int,octet *,octet *,octet *);
@@ -93,8 +93,9 @@
 extern void hex2bytes(char *hex, char *bin);
 extern void generateRandom(csprng*, octet*);
 extern int generateOTP(csprng*);
-extern void AES_GCM_ENCRYPT(octet *K,octet *IV,octet *H,octet *P,octet *C,octet *T);
-extern void AES_GCM_DECRYPT(octet *K,octet *IV,octet *H,octet *C,octet *P,octet *T);
+extern void MPIN_AES_GCM_ENCRYPT(octet *K,octet *IV,octet *H,octet *P,octet *C,octet *T);
+extern void MPIN_AES_GCM_DECRYPT(octet *K,octet *IV,octet *H,octet *C,octet *P,octet *T);
+extern void MPIN_HASH_ALL(octet *I,octet *U,octet *CU,octet *V,octet *Y,octet *R,octet *W,octet *H);
 
 """)
 
@@ -137,9 +138,10 @@
     TIME_PERMITS = True
     MPIN_FULL = False
     PIN_ERROR = True
+    USE_ANONYMOUS = False
 
     if TIME_PERMITS:
-        date = libmpin.today()
+        date = libmpin.MPIN_today()
     else:
         date = 0
 
@@ -338,10 +340,16 @@
     CK[0].max = PAS
     CK[0].len = PAS
 
+    # Hash value of transmission
+    HM = ffi.new("octet*")
+    HMval = ffi.new("char []",  HASH_BYTES)
+    HM[0].val = HMval
+    HM[0].max = HASH_BYTES
+    HM[0].len = HASH_BYTES
+
     if date:
         prHID = HTID
         if not PIN_ERROR:
-            HID = ffi.NULL
             U = ffi.NULL
     else:
         HTID = ffi.NULL
@@ -364,7 +372,7 @@
 
     # random number generator
     RNG = ffi.new("csprng*")
-    libmpin.CREATE_CSPRNG(RNG, RAW)
+    libmpin.MPIN_CREATE_CSPRNG(RNG, RAW)
 
     # Hash MPIN_ID
     libmpin.MPIN_HASH_ID(MPIN_ID, HASH_MPIN_ID)
@@ -372,6 +380,11 @@
         print "MPIN_ID: %s" % toHex(MPIN_ID)
         print "HASH_MPIN_ID: %s" % toHex(HASH_MPIN_ID)
 
+    if USE_ANONYMOUS:
+        pID = HASH_MPIN_ID
+    else:
+        pID = MPIN_ID
+        
     # Generate master secret for MIRACL and Customer
     rtn = libmpin.MPIN_RANDOM_GENERATE(RNG, MS1)
     if rtn != 0:
@@ -468,7 +481,7 @@
             libmpin.MPIN_GET_G1_MULTIPLE(RNG, 1, R, HASH_MPIN_ID, Z)
 
         # Server MPIN
-        rtn = libmpin.MPIN_SERVER(date, HID, HTID, Y, SERVER_SECRET, U, UT, SEC, E, F, MPIN_ID, ffi.NULL, TimeValue)
+        rtn = libmpin.MPIN_SERVER(date, HID, HTID, Y, SERVER_SECRET, U, UT, SEC, E, F, pID, ffi.NULL, TimeValue)
         if rtn != 0:
             print "ERROR: Single Pass %s is not authenticated" % identity
             if PIN_ERROR:
@@ -483,11 +496,13 @@
             print "T: %s" % toHex(T)
 
         if MPIN_FULL:
-            libmpin.MPIN_CLIENT_KEY(TATE1, TATE2, PIN, R, X, T, CK)
-            print "Client Key: %s" % toHex(CK)
+            libmpin.MPIN_HASH_ALL(prHID,U,UT,SEC,Y,Z,T,HM);
+            
+            libmpin.MPIN_CLIENT_KEY(TATE1, TATE2, PIN, R, X, HM, T, CK)
+            print "Client AES Key: %s" % toHex(CK)
 
-            libmpin.MPIN_SERVER_KEY(Z, SERVER_SECRET, W, U, UT, SK)
-            print "Server Key: %s" % toHex(SK)
+            libmpin.MPIN_SERVER_KEY(Z, SERVER_SECRET, W, HM, HID, U, UT, SK)
+            print "Server AES Key: %s" % toHex(SK)
 
     else:
         print "M-Pin Multi Pass"
@@ -506,7 +521,7 @@
 
         # Server calculates H(ID) and H(T|H(ID)) (if time permits enabled),
         # and maps them to points on the curve HID and HTID resp.
-        libmpin.MPIN_SERVER_1(date, MPIN_ID, HID, HTID)
+        libmpin.MPIN_SERVER_1(date, pID, HID, HTID)
 
         # Server generates Random number Y and sends it to Client
         rtn = libmpin.MPIN_RANDOM_GENERATE(RNG, Y)
@@ -544,12 +559,14 @@
             if rtn != 0:
                 print "ERROR: Generating T %s" % rtn
 
-            rtn = libmpin.MPIN_CLIENT_KEY(TATE1, TATE2, PIN, R, X, T, CK)
+            libmpin.MPIN_HASH_ALL(HASH_MPIN_ID,U,UT,SEC,Y,Z,T,HM);                
+
+            rtn = libmpin.MPIN_CLIENT_KEY(TATE1, TATE2, PIN, R, X, HM, T, CK)
             if rtn != 0:
                 print "ERROR: Generating CK %s" % rtn
-            print "Client Key: %s" % toHex(CK)
+            print "Client AES Key: %s" % toHex(CK)
 
-            rtn = libmpin.MPIN_SERVER_KEY(Z, SERVER_SECRET, W, U, UT, SK)
+            rtn = libmpin.MPIN_SERVER_KEY(Z, SERVER_SECRET, W, HM, HID, U, UT, SK)
             if rtn != 0:
                 print "ERROR: Generating SK %s" % rtn
-            print "Server Key: %s" % toHex(SK)
+            print "Server AES Key: %s" % toHex(SK)
diff --git a/pythonCFFI/wcc.py b/pythonCFFI/wcc.py
new file mode 100755
index 0000000..efd991d
--- /dev/null
+++ b/pythonCFFI/wcc.py
@@ -0,0 +1,478 @@
+#!/usr/bin/env python
+
+"""
+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.
+"""
+
+
+"""
+wcc
+
+This module use cffi to access the c functions in the WCC library.
+
+There is also an example usage program in this file.
+
+"""
+import cffi
+import platform
+
+# WCC Group Size
+PGS = 32
+# WCC Field Size
+PFS = 32
+G1 = 2*PFS + 1
+G2 = 4*PFS
+# Length of hash
+HASH_BYTES = 32
+# AES-GCM IV length
+IVL = 12
+# AES Key length
+PAS = 16
+
+ffi = cffi.FFI()
+ffi.cdef("""
+typedef struct {
+unsigned int ira[21];  /* random number...   */
+int rndptr;   /* ...array & pointer */
+unsigned int borrow;
+int pool_ptr;
+char pool[32];    /* random pool */
+} csprng;
+
+typedef struct
+{
+  int len;
+  int max;
+  char *val;
+} octet;
+
+extern int WCC_RANDOM_GENERATE(csprng *RNG,octet* S);
+extern void  WCC_Hq(octet *A,octet *B,octet *C,octet *D,octet *h);
+extern int WCC_GET_G2_MULTIPLE(int hashDone,octet *S,octet *ID,octet *VG2);
+extern int WCC_GET_G1_MULTIPLE(int hashDone,octet *S,octet *ID,octet *VG1);
+extern int WCC_GET_G1_TPMULT(int date, octet *S,octet *ID,octet *VG1);
+extern int WCC_GET_G2_TPMULT(int date, octet *S,octet *ID,octet *VG2);
+extern int WCC_GET_G1_PERMIT(int date,octet *S,octet *HID,octet *G1TP);
+extern int WCC_GET_G2_PERMIT(int date,octet *S,octet *HID,octet *G2TP);
+extern int WCC_SENDER_KEY(int date, octet *xOct, octet *piaOct, octet *pibOct, octet *PbG2Oct, octet *PgG1Oct, octet *AKeyG1Oct, octet *ATPG1Oct, octet *IdBOct, octet *AESKeyOct);
+extern int WCC_RECEIVER_KEY(int date, octet *yOct, octet *wOct,  octet *piaOct, octet *pibOct,  octet *PaG1Oct, octet *PgG1Oct, octet *BKeyG2Oct,octet *BTPG2Oct,  octet *IdAOct, octet *AESKeyOct);
+extern void WCC_AES_GCM_ENCRYPT(octet *K,octet *IV,octet *H,octet *P,octet *C,octet *T);
+extern void WCC_AES_GCM_DECRYPT(octet *K,octet *IV,octet *H,octet *C,octet *P,octet *T);
+extern void WCC_HASH_ID(octet *,octet *);
+extern int WCC_RECOMBINE_G1(octet *,octet *,octet *);
+extern int WCC_RECOMBINE_G2(octet *,octet *,octet *);
+extern unsigned int WCC_today(void);
+extern void WCC_CREATE_CSPRNG(csprng *,octet *);
+extern void WCC_KILL_CSPRNG(csprng *RNG);
+extern void version(char* info);
+
+""")
+
+if (platform.system() == 'Windows'):
+    libwcc = ffi.dlopen("libwcc.dll")
+elif (platform.system() == 'Darwin'):
+    libwcc = ffi.dlopen("libwcc.dylib")
+else:
+    libwcc = ffi.dlopen("libwcc.so")
+
+
+def toHex(octetValue):
+    """Converts an octet type into a string
+
+    Add all the values in an octet into an array. This arrays is then
+    converted to a string and hex encoded.
+
+    Args::
+
+        octetValue. An octet type
+
+    Returns::
+
+        String
+
+    Raises:
+        Exception
+    """
+    i = 0
+    val = []
+    while i < octetValue[0].len:
+        val.append(octetValue[0].val[i])
+        i = i+1
+    return ''.join(val).encode("hex")
+
+
+if __name__ == "__main__":
+    # Print hex values
+    DEBUG = False
+
+    build_version = ffi.new("char []", 256)
+    libwcc.version(build_version)
+    print ffi.string(build_version)
+
+    # Seed
+    seedHex = "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20"
+    seed = seedHex.decode("hex")
+
+    # Master Secret Shares
+    MS1 = ffi.new("octet*")
+    MS1val = ffi.new("char []", PGS)
+    MS1[0].val = MS1val
+    MS1[0].max = PGS
+    MS1[0].len = PGS
+
+    MS2 = ffi.new("octet*")
+    MS2val = ffi.new("char []", PGS)
+    MS2[0].val = MS2val
+    MS2[0].max = PGS
+    MS2[0].len = PGS
+
+    # Alice Identity
+    alice_id = raw_input("Please enter Alice's identity:")
+    IdA = ffi.new("octet*")
+    IdAval = ffi.new("char [%s]" % len(alice_id), alice_id)
+    IdA[0].val = IdAval
+    IdA[0].max = len(alice_id)
+    IdA[0].len = len(alice_id)
+
+    # Hash value of IdA
+    AHV = ffi.new("octet*")
+    AHVval = ffi.new("char []",  HASH_BYTES)
+    AHV[0].val = AHVval
+    AHV[0].max = HASH_BYTES
+    AHV[0].len = HASH_BYTES
+
+    # Bob Identity
+    bob_id = raw_input("Please enter Bob's identity:")
+    IdB = ffi.new("octet*")
+    IdBval = ffi.new("char [%s]" % len(bob_id), bob_id)
+    IdB[0].val = IdBval
+    IdB[0].max = len(bob_id)
+    IdB[0].len = len(bob_id)
+
+    # Hash value of IdB
+    BHV = ffi.new("octet*")
+    BHVval = ffi.new("char []",  HASH_BYTES)
+    BHV[0].val = BHVval
+    BHV[0].max = HASH_BYTES
+    BHV[0].len = HASH_BYTES
+
+    # Sender keys
+    A1KeyG1 = ffi.new("octet*")
+    A1KeyG1val = ffi.new("char []", G1)
+    A1KeyG1[0].val = A1KeyG1val
+    A1KeyG1[0].max = G1
+    A1KeyG1[0].len = G1
+
+    A2KeyG1 = ffi.new("octet*")
+    A2KeyG1val = ffi.new("char []", G1)
+    A2KeyG1[0].val = A2KeyG1val
+    A2KeyG1[0].max = G1
+    A2KeyG1[0].len = G1
+
+    AKeyG1 = ffi.new("octet*")
+    AKeyG1val = ffi.new("char []", G1)
+    AKeyG1[0].val = AKeyG1val
+    AKeyG1[0].max = G1
+    AKeyG1[0].len = G1
+
+    # Receiver keys
+    B1KeyG2 = ffi.new("octet*")
+    B1KeyG2val = ffi.new("char []", G2)
+    B1KeyG2[0].val = B1KeyG2val
+    B1KeyG2[0].max = G2
+    B1KeyG2[0].len = G2
+
+    B2KeyG2 = ffi.new("octet*")
+    B2KeyG2val = ffi.new("char []", G2)
+    B2KeyG2[0].val = B2KeyG2val
+    B2KeyG2[0].max = G2
+    B2KeyG2[0].len = G2
+
+    BKeyG2 = ffi.new("octet*")
+    BKeyG2val = ffi.new("char []", G2)
+    BKeyG2[0].val = BKeyG2val
+    BKeyG2[0].max = G2
+    BKeyG2[0].len = G2
+
+    # Sender time permits
+    A1TPG1 = ffi.new("octet*")
+    A1TPG1val = ffi.new("char []", G1)
+    A1TPG1[0].val = A1TPG1val
+    A1TPG1[0].max = G1
+    A1TPG1[0].len = G1
+
+    A2TPG1 = ffi.new("octet*")
+    A2TPG1val = ffi.new("char []", G1)
+    A2TPG1[0].val = A2TPG1val
+    A2TPG1[0].max = G1
+    A2TPG1[0].len = G1
+
+    ATPG1 = ffi.new("octet*")
+    ATPG1val = ffi.new("char []", G1)
+    ATPG1[0].val = ATPG1val
+    ATPG1[0].max = G1
+    ATPG1[0].len = G1
+
+    # Receiver time permits
+    B1TPG2 = ffi.new("octet*")
+    B1TPG2val = ffi.new("char []", G2)
+    B1TPG2[0].val = B1TPG2val
+    B1TPG2[0].max = G2
+    B1TPG2[0].len = G2
+
+    B2TPG2 = ffi.new("octet*")
+    B2TPG2val = ffi.new("char []", G2)
+    B2TPG2[0].val = B2TPG2val
+    B2TPG2[0].max = G2
+    B2TPG2[0].len = G2
+
+    BTPG2 = ffi.new("octet*")
+    BTPG2val = ffi.new("char []", G2)
+    BTPG2[0].val = BTPG2val
+    BTPG2[0].max = G2
+    BTPG2[0].len = G2
+
+    # AES Keys
+    KEY1 = ffi.new("octet*")
+    KEY1val = ffi.new("char []", PAS)
+    KEY1[0].val = KEY1val
+    KEY1[0].max = PAS
+    KEY1[0].len = PAS
+
+    KEY2 = ffi.new("octet*")
+    KEY2val = ffi.new("char []", PAS)
+    KEY2[0].val = KEY2val
+    KEY2[0].max = PAS
+    KEY2[0].len = PAS
+
+    X = ffi.new("octet*")
+    Xval = ffi.new("char []", PGS)
+    X[0].val = Xval
+    X[0].max = PGS
+    X[0].len = PGS
+
+    Y = ffi.new("octet*")
+    Yval = ffi.new("char []", PGS)
+    Y[0].val = Yval
+    Y[0].max = PGS
+    Y[0].len = PGS
+
+    W = ffi.new("octet*")
+    Wval = ffi.new("char []", PGS)
+    W[0].val = Wval
+    W[0].max = PGS
+    W[0].len = PGS
+
+    PIA = ffi.new("octet*")
+    PIAval = ffi.new("char []", PGS)
+    PIA[0].val = PIAval
+    PIA[0].max = PGS
+    PIA[0].len = PGS
+
+    PIB = ffi.new("octet*")
+    PIBval = ffi.new("char []", PGS)
+    PIB[0].val = PIBval
+    PIB[0].max = PGS
+    PIB[0].len = PGS
+
+    PaG1 = ffi.new("octet*")
+    PaG1val = ffi.new("char []", G1)
+    PaG1[0].val = PaG1val
+    PaG1[0].max = G1
+    PaG1[0].len = G1
+
+    PgG1 = ffi.new("octet*")
+    PgG1val = ffi.new("char []", G1)
+    PgG1[0].val = PgG1val
+    PgG1[0].max = G1
+    PgG1[0].len = G1
+
+    PbG2 = ffi.new("octet*")
+    PbG2val = ffi.new("char []", G2)
+    PbG2[0].val = PbG2val
+    PbG2[0].max = G2
+    PbG2[0].len = G2
+
+    # Assign a seed value
+    RAW = ffi.new("octet*")
+    RAWval = ffi.new("char [%s]" % len(seed), seed)
+    RAW[0].val = RAWval
+    RAW[0].len = len(seed)
+    RAW[0].max = len(seed)
+    if DEBUG:
+        print "RAW: %s" % toHex(RAW)
+
+    # random number generator
+    RNG = ffi.new("csprng*")
+    libwcc.WCC_CREATE_CSPRNG(RNG, RAW)
+
+    # Today's date in epoch days
+    date = libwcc.WCC_today()
+    if DEBUG:
+        print "Date %s" % date
+
+    # Hash IdA
+    libwcc.WCC_HASH_ID(IdA, AHV)
+    if DEBUG:
+        print "IdA: %s" % toHex(IdA)
+        print "AHV: %s" % toHex(AHV)
+
+    # Hash IdB
+    libwcc.WCC_HASH_ID(IdB, BHV)
+    if DEBUG:
+        print "IdB: %s" % toHex(IdB)
+        print "BHV: %s" % toHex(BHV)
+
+    # Generate master secret for MIRACL and Customer
+    rtn = libwcc.WCC_RANDOM_GENERATE(RNG, MS1)
+    if rtn != 0:
+        print "libwcc.WCC_RANDOM_GENERATE(RNG,MS1) Error %s", rtn
+    rtn = libwcc.WCC_RANDOM_GENERATE(RNG, MS2)
+    if rtn != 0:
+        print "libwcc.WCC_RANDOM_GENERATE(RNG,MS2) Error %s" % rtn
+    if DEBUG:
+        print "MS1: %s" % toHex(MS1)
+        print "MS2: %s" % toHex(MS2)
+
+    # Generate Alice's sender key shares
+    rtn = libwcc.WCC_GET_G1_MULTIPLE(1,MS1, AHV, A1KeyG1)
+    if rtn != 0:
+        print "libwcc.WCC_GET_G1_MULTIPLE(MS1,AHV,A1KeyG1) Error %s" % rtn
+    rtn = libwcc.WCC_GET_G1_MULTIPLE(1,MS2, AHV, A2KeyG1)
+    if rtn != 0:
+        print "libwcc.WCC_GET_G1_MULTIPLE(MS2,AHV,A2KeyG1) Error %s" % rtn
+    if DEBUG:
+        print "A1KeyG1: %s" % toHex(A1KeyG1)
+        print "A2KeyG1: %s" % toHex(A2KeyG1)
+
+    # Combine Alices's sender key shares
+    rtn = libwcc.WCC_RECOMBINE_G1(A1KeyG1, A2KeyG1, AKeyG1)
+    if rtn != 0:
+        print "libwcc.WCC_RECOMBINE_G1(A1KeyG1, A2KeyG1, AKeyG1) Error %s" % rtn
+    print "AKeyG1: %s" % toHex(AKeyG1)
+
+    # Generate Alice's sender time permit shares
+    rtn = libwcc.WCC_GET_G1_PERMIT(date, MS1, AHV, A1TPG1)
+    if rtn != 0:
+        print "libwcc.WCC_GET_G1_PERMIT(date,MS1,AHV,A1TPG1) Error %s" % rtn
+    rtn = libwcc.WCC_GET_G1_PERMIT(date, MS2, AHV, A2TPG1)
+    if rtn != 0:
+        print "libwcc.WCC_GET_G1_PERMIT(date,MS2,AHV,A2TPG1) Error %s" % rtn
+    if DEBUG:
+        print "A1TPG1: %s" % toHex(A1TPG1)
+        print "A2TPG1: %s" % toHex(A2TPG1)
+
+    # Combine Alice's sender Time Permit shares
+    rtn = libwcc.WCC_RECOMBINE_G1(A1TPG1, A2TPG1, ATPG1)
+    if rtn != 0:
+        print "libwcc.WCC_RECOMBINE_G1(A1TPG1, A2TPG1, ATPG1) Error %s" % rtn
+    print "ATPG1: %s" % toHex(ATPG1)
+
+    # Generate Bob's receiver secret key shares
+    rtn = libwcc.WCC_GET_G2_MULTIPLE(1,MS1, BHV, B1KeyG2)
+    if rtn != 0:
+        print "libwcc.WCC_GET_G2_MULTIPLE(MS1,BHV,B1KeyG2) Error %s" % rtn
+    rtn = libwcc.WCC_GET_G2_MULTIPLE(1,MS2, BHV, B2KeyG2)
+    if rtn != 0:
+        print "libwcc.WCC_GET_G2_MULTIPLE(MS2,BHV,B2KeyG2) Error %s" % rtn
+    if DEBUG:
+        print "B1KeyG2: %s" % toHex(B1KeyG2)
+        print "B2KeyG2: %s" % toHex(B2KeyG2)
+
+    # Combine Bobs's receiver secret key shares
+    rtn = libwcc.WCC_RECOMBINE_G2(B1KeyG2, B2KeyG2, BKeyG2)
+    if rtn != 0:
+        print "libwcc.WCC_RECOMBINE_G2(B1KeyG2, B2KeyG2, BKeyG2) Error %s" % rtn
+    print "BKeyG2: %s" % toHex(BKeyG2)
+
+    # Generate Bob's receiver time permit shares
+    rtn = libwcc.WCC_GET_G2_PERMIT(date, MS1, BHV, B1TPG2)
+    if rtn != 0:
+        print "libwcc.WCC_GET_G2_PERMIT(date,MS1,BHV,B1TPG2) Error %s" % rtn
+    rtn = libwcc.WCC_GET_G2_PERMIT(date, MS2, BHV, B2TPG2)
+    if rtn != 0:
+        print "libwcc.WCC_GET_G2_PERMIT(date,MS2,BHV,B2TPG2) Error %s" % rtn
+    if DEBUG:
+        print "B1TPG2: %s" % toHex(B1TPG2)
+        print "B2TPG2: %s" % toHex(B2TPG2)
+
+    # Combine Bob's receiver time permit shares
+    rtn = libwcc.WCC_RECOMBINE_G2(B1TPG2, B2TPG2, BTPG2)
+    if rtn != 0:
+        print "libwcc.WCC_RECOMBINE_G2(B1TPG2, B2TPG2, BTPG2) Error %s" % rtn
+    print "BTPG2: %s" % toHex(BTPG2)
+
+    rtn = libwcc.WCC_RANDOM_GENERATE(RNG, X)
+    if rtn != 0:
+        print "libwcc.WCC_RANDOM_GENERATE(RNG,X) Error %s", rtn
+    if DEBUG:
+        print "X: %s" % toHex(X)
+
+    rtn = libwcc.WCC_GET_G1_TPMULT(date,X,IdA,PaG1);
+    if rtn != 0:
+        print "libwcc.WCC_GET_G1_TPMULT(date,X,IdA,PaG1) Error %s", rtn
+    if DEBUG:
+        print "PaG1: %s" % toHex(PaG1)
+
+    rtn = libwcc.WCC_RANDOM_GENERATE(RNG, W)
+    if rtn != 0:
+        print "libwcc.WCC_RANDOM_GENERATE(RNG,W) Error %s", rtn
+    if DEBUG:
+        print "W: %s" % toHex(W)
+
+    rtn = libwcc.WCC_GET_G1_TPMULT(date,W,IdA,PgG1);
+    if rtn != 0:
+        print "libwcc.WCC_GET_G1_TPMULT(date,W,IdA,PgG1) Error %s", rtn
+    if DEBUG:
+        print "PgG1: %s" % toHex(PgG1)
+
+    rtn = libwcc.WCC_RANDOM_GENERATE(RNG, Y)
+    if rtn != 0:
+        print "libwcc.WCC_RANDOM_GENERATE(RNG,Y) Error %s", rtn
+    if DEBUG:
+        print "Y: %s" % toHex(Y)
+
+    rtn = libwcc.WCC_GET_G2_TPMULT(date,Y,IdB,PbG2);
+    if rtn != 0:
+        print "libwcc.WCC_GET_G1_TPMULT(date,Y,IdB,PbG2) Error %s", rtn
+    if DEBUG:
+        print "PbG2: %s" % toHex(PbG2)
+
+    # PIA = Hq(PaG1,PbG2,PgG1,IdB)
+    libwcc.WCC_Hq(PaG1,PbG2,PgG1,IdB,PIA);
+    if DEBUG:
+        print "PIA: %s" % toHex(PIA)
+
+    # PIB = Hq(PbG2,PaG1,PgG1,IdA)
+    libwcc.WCC_Hq(PbG2,PaG1,PgG1,IdA,PIB);
+    if DEBUG:
+        print "PIB: %s" % toHex(PIB)
+        
+    # Alice calculates AES Key 
+    rtn = libwcc.WCC_SENDER_KEY(date, X, PIA, PIB, PbG2, PgG1, AKeyG1, ATPG1, IdB, KEY1)
+    if rtn != 0:
+        print "libwcc.WCC_SENDER_KEY(date, X, PIA, PIB, PbG2, PgG1, AKeyG1, ATPG1, IdB, KEY1) Error %s" % rtn
+    print "{0}'s AES Key: {1}".format(alice_id, toHex(KEY1))
+
+    # Bob calculates AES Key
+    rtn = libwcc.WCC_RECEIVER_KEY(date, Y, W, PIA, PIB, PaG1, PgG1, BKeyG2, BTPG2, IdA, KEY2)
+    if rtn != 0:
+        print "libwcc.WCC_RECEIVER_KEY(date, Y, W, PIA, PIB, PaG1, PgG1, BKeyG2, BTPG2, IdA, KEY2) Error %s" % rtn
+    print "{0}'s AES Key: {1}".format(bob_id, toHex(KEY2))
+
+    libwcc.WCC_KILL_CSPRNG(RNG)