http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version3/c/mpin192.h
----------------------------------------------------------------------
diff --git a/version3/c/mpin192.h b/version3/c/mpin192.h
new file mode 100644
index 0000000..79f562c
--- /dev/null
+++ b/version3/c/mpin192.h
@@ -0,0 +1,339 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+/**
+ * @file mpin.h
+ * @author Mike Scott and Kealan McCusker
+ * @date 2nd June 2015
+ * @brief M-Pin Header file
+ *
+ * Allows some user configuration
+ * defines structures
+ * declares functions
+ *
+ */
+
+#ifndef MPIN_ZZZ_H
+#define MPIN_ZZZ_H
+
+#include "pair192_ZZZ.h"
+#include "pbc_support.h"
+
+/* Field size is assumed to be greater than or equal to group size */
+
+#define PGS_ZZZ MODBYTES_XXX  /**< MPIN Group Size */
+#define PFS_ZZZ MODBYTES_XXX  /**< MPIN Field Size */
+
+#define MPIN_OK             0   /**< Function completed without error */
+#define MPIN_INVALID_POINT  -14        /**< Point is NOT on the curve */
+#define MPIN_BAD_PIN        -19 /**< Bad PIN number entered */
+
+#define MAXPIN 10000         /**< max PIN */
+#define PBLEN 14             /**< max length of PIN in bits */
+
+//#define PAS_ZZZ 24        /**< MPIN Symmetric Key Size 192 bits  */
+//#define HASH_TYPE_MPIN_ZZZ SHA384   /**< Choose Hash function */
+
+#define MESSAGE_SIZE 256        /**< Signature message size  */
+#define M_SIZE_ZZZ (MESSAGE_SIZE+2*PFS_ZZZ+1)   /**< Signature message size 
and G1 size */
+
+
+/* MPIN support functions */
+
+/* MPIN primitives */
+
+
+void MPIN_ZZZ_GET_Y(int h,int t,octet *O,octet *Y);
+/**    @brief Extract a PIN number from a client secret
+ *
+       @param h is the hash type
+       @param ID is the input client identity
+       @param factor is an input factor
+       @param facbits is the number of bits in the factor
+       @param CS is the client secret from which the factor is to be extracted
+       @return 0 or an error code
+ */
+int MPIN_ZZZ_EXTRACT_FACTOR(int h,octet *ID,int factor,int facbits,octet *CS);
+
+/**    @brief Extract a PIN number from a client secret
+ *
+       @param h is the hash type
+       @param ID is the input client identity
+       @param factor is an input factor
+       @param facbits is the number of bits in the factor
+       @param CS is the client secret to which the factor is to be added
+       @return 0 or an error code
+ */
+int MPIN_ZZZ_RESTORE_FACTOR(int h,octet *ID,int factor,int facbits,octet *CS);
+
+
+/**    @brief Extract a PIN number from a client secret
+ *
+       @param h is the hash type
+       @param ID is the input client identity
+       @param pin is an input PIN number
+       @param CS is the client secret from which the PIN is to be extracted
+       @return 0 or an error code
+ */
+int MPIN_ZZZ_EXTRACT_PIN(int h,octet *ID,int pin,octet *CS);
+
+/**    @brief Perform client side of the one-pass version of the M-Pin protocol
+ *
+       If Time Permits are disabled, set d = 0, and UT is not generated and 
can be set to NULL.
+       If Time Permits are enabled, and PIN error detection is OFF, U is not 
generated and can be set to NULL.
+       If Time Permits are enabled, and PIN error detection is ON, U and UT 
are both generated.
+       @param h is the hash type
+       @param d is input date, in days since the epoch. Set to 0 if Time 
permits disabled
+       @param ID is the input client identity
+       @param R is a pointer to a cryptographically secure random number 
generator
+       @param x an output internally randomly generated if R!=NULL, otherwise 
must be provided as an input
+       @param pin is the input PIN number
+       @param T is the input M-Pin token (the client secret with PIN portion 
removed)
+       @param V is output = -(x+y)(CS+TP), where CS is the reconstructed 
client secret, and TP is the time permit
+       @param U is output = x.H(ID)
+       @param UT is output = x.(H(ID)+H(d|H(ID)))
+       @param TP is the input time permit
+       @param MESSAGE is the message to be signed
+       @param t is input epoch time in seconds - a timestamp
+       @param y is output H(t|U) or H(t|UT) if Time Permits enabled
+       @return 0 or an error code
+ */
+int MPIN_ZZZ_CLIENT(int h,int d,octet *ID,csprng *R,octet *x,int pin,octet 
*T,octet *V,octet *U,octet *UT,octet *TP, octet* MESSAGE, int t, octet *y);
+/**    @brief Perform first pass of the client side of the 3-pass version of 
the M-Pin protocol
+ *
+       If Time Permits are disabled, set d = 0, and UT is not generated and 
can be set to NULL.
+       If Time Permits are enabled, and PIN error detection is OFF, U is not 
generated and can be set to NULL.
+       If Time Permits are enabled, and PIN error detection is ON, U and UT 
are both generated.
+       @param h is the hash type
+       @param d is input date, in days since the epoch. Set to 0 if Time 
permits disabled
+       @param ID is the input client identity
+       @param R is a pointer to a cryptographically secure random number 
generator
+       @param x an output internally randomly generated if R!=NULL, otherwise 
must be provided as an input
+       @param pin is the input PIN number
+       @param T is the input M-Pin token (the client secret with PIN portion 
removed)
+       @param S is output = CS+TP, where CS=is the reconstructed client 
secret, and TP is the time permit
+       @param U is output = x.H(ID)
+       @param UT is output = x.(H(ID)+H(d|H(ID)))
+       @param TP is the input time permit
+       @return 0 or an error code
+ */
+int MPIN_ZZZ_CLIENT_1(int h,int d,octet *ID,csprng *R,octet *x,int pin,octet 
*T,octet *S,octet *U,octet *UT,octet *TP);
+/**    @brief Generate a random group element
+ *
+       @param R is a pointer to a cryptographically secure random number 
generator
+       @param S is the output random octet
+       @return 0 or an error code
+ */
+int MPIN_ZZZ_RANDOM_GENERATE(csprng *R,octet *S);
+/**    @brief Perform second pass of the client side of the 3-pass version of 
the M-Pin protocol
+ *
+       @param x an input, a locally generated random number
+       @param y an input random challenge from the server
+       @param V on output = -(x+y).V
+       @return 0 or an error code
+ */
+int MPIN_ZZZ_CLIENT_2(octet *x,octet *y,octet *V);
+/**    @brief Perform server side of the one-pass version of the M-Pin protocol
+ *
+       If Time Permits are disabled, set d = 0, and UT and HTID are not 
generated and can be set to NULL.
+       If Time Permits are enabled, and PIN error detection is OFF, U and HID 
are not needed and can be set to NULL.
+       If Time Permits are enabled, and PIN error detection is ON, U, UT, HID 
and HTID are all required.
+       @param h is the hash type
+       @param d is input date, in days since the epoch. Set to 0 if Time 
permits disabled
+       @param HID is output H(ID), a hash of the client ID
+       @param HTID is output H(ID)+H(d|H(ID))
+       @param y is output H(t|U) or H(t|UT) if Time Permits enabled
+       @param SS is the input server secret
+       @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 V is an input from the client
+       @param E is an output to help the Kangaroos to find the PIN error, or 
NULL if not required
+       @param F is an output to help the Kangaroos to find the PIN error, or 
NULL if not required
+       @param ID is the input claimed client identity
+       @param MESSAGE is the message to be signed
+       @param t is input epoch time in seconds - a timestamp
+       @param Pa is input from the client z.Q or NULL if the key-escrow less 
scheme is not used
+       @return 0 or an error code
+ */
+int MPIN_ZZZ_SERVER(int h,int d,octet *HID,octet *HTID,octet *y,octet 
*SS,octet *U,octet *UT,octet *V,octet *E,octet *F,octet *ID,octet *MESSAGE, int 
t, octet *Pa);
+/**    @brief Perform first pass of the server side of the 3-pass version of 
the M-Pin protocol
+ *
+       @param h is the hash type
+       @param d is input date, in days since the epoch. Set to 0 if Time 
permits disabled
+       @param ID is the input claimed client identity
+       @param HID is output H(ID), a hash of the client ID
+       @param HTID is output H(ID)+H(d|H(ID))
+       @return 0 or an error code
+ */
+void MPIN_ZZZ_SERVER_1(int h,int d,octet *ID,octet *HID,octet *HTID);
+/**    @brief Perform third pass on the server side of the 3-pass version of 
the M-Pin protocol
+ *
+       If Time Permits are disabled, set d = 0, and UT and HTID are not needed 
and can be set to NULL.
+       If Time Permits are enabled, and PIN error detection is OFF, U and HID 
are not needed and can be set to NULL.
+       If Time Permits are enabled, and PIN error detection is ON, U, UT, HID 
and HTID are all required.
+       @param d is input date, in days since the epoch. Set to 0 if Time 
permits disabled
+       @param HID is input H(ID), a hash of the client ID
+       @param HTID is input H(ID)+H(d|H(ID))
+       @param y is the input server's randomly generated challenge
+       @param SS is the input server secret
+       @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 V is an input from the client
+       @param E is an output to help the Kangaroos to find the PIN error, or 
NULL if not required
+       @param F is an output to help the Kangaroos to find the PIN error, or 
NULL if not required
+       @param Pa is the input public key from the client, z.Q or NULL if the 
client uses regular mpin
+       @return 0 or an error code
+ */
+int MPIN_ZZZ_SERVER_2(int d,octet *HID,octet *HTID,octet *y,octet *SS,octet 
*U,octet *UT,octet *V,octet *E,octet *F,octet *Pa);
+/**    @brief Add two members from the group G1
+ *
+       @param Q1 an input member of G1
+       @param Q2 an input member of G1
+       @param Q an output member of G1 = Q1+Q2
+       @return 0 or an error code
+ */
+int MPIN_ZZZ_RECOMBINE_G1(octet *Q1,octet *Q2,octet *Q);
+/**    @brief Add two members from the group G2
+ *
+       @param P1 an input member of G2
+       @param P2 an input member of G2
+       @param P an output member of G2 = P1+P2
+       @return 0 or an error code
+ */
+int MPIN_ZZZ_RECOMBINE_G2(octet *P1,octet *P2,octet *P);
+/**    @brief Use Kangaroos to find PIN error
+ *
+       @param E a member of the group GT
+       @param F a member of the group GT =  E^e
+       @return 0 if Kangaroos failed, or the PIN error e
+ */
+int MPIN_ZZZ_KANGAROO(octet *E,octet *F);
+/**    @brief Encoding of a Time Permit to make it indistinguishable from a 
random string
+ *
+       @param R is a pointer to a cryptographically secure random number 
generator
+       @param TP is the input time permit, obfuscated on output
+       @return 0 or an error code
+ */
+int MPIN_ZZZ_ENCODING(csprng *R,octet *TP);
+/**    @brief Encoding of an obfuscated Time Permit
+ *
+       @param TP is the input obfuscated time permit, restored on output
+       @return 0 or an error code
+ */
+int MPIN_ZZZ_DECODING(octet *TP);
+
+/**    @brief Find a random multiple of a point in G1
+ *
+       @param R is a pointer to a cryptographically secure random number 
generator
+       @param type determines type of action to be taken
+       @param x an output internally randomly generated if R!=NULL, otherwise 
must be provided as an input
+       @param G if type=0 a point in G1, else an octet to be mapped to G1
+       @param W the output =x.G or x.M(G), where M(.) is a mapping
+       @return 0 or an error code
+ */
+int MPIN_ZZZ_GET_G1_MULTIPLE(csprng *R,int type,octet *x,octet *G,octet *W);
+/**    @brief Find a random multiple of a point in G1
+ *
+       @param R is a pointer to a cryptographically secure random number 
generator
+       @param type determines type of action to betaken
+       @param x an output internally randomly generated if R!=NULL, otherwise 
must be provided as an input
+       @param G a point in G2
+       @param W the output =x.G or (1/x).G
+       @return 0 or an error code
+ */
+int MPIN_ZZZ_GET_G2_MULTIPLE(csprng *R,int type,octet *x,octet *G,octet *W);
+
+/**    @brief Create a client secret in G1 from a master secret and the client 
ID
+ *
+       @param S is an input master secret
+       @param ID is the input client identity
+       @param CS is the full client secret = s.H(ID)
+       @return 0 or an error code
+ */
+int MPIN_ZZZ_GET_CLIENT_SECRET(octet *S,octet *ID,octet *CS);
+/**    @brief Create a Time Permit in G1 from a master secret and the client ID
+ *
+       @param h is the hash type
+       @param d is input date, in days since the epoch.
+       @param S is an input master secret
+       @param ID is the input client identity
+       @param TP is a Time Permit for the given date = s.H(d|H(ID))
+       @return 0 or an error code
+ */
+int MPIN_ZZZ_GET_CLIENT_PERMIT(int h,int d,octet *S,octet *ID,octet *TP);
+/**    @brief Create a server secret in G2 from a master secret
+ *
+       @param S is an input master secret
+       @param SS is the server secret = s.Q where Q is a fixed generator of G2
+       @return 0 or an error code
+ */
+int MPIN_ZZZ_GET_SERVER_SECRET(octet *S,octet *SS);
+/* int MPIN_TEST_PAIRING(octet *,octet *); */
+
+/* For M-Pin Full */
+/**    @brief Precompute values for use by the client side of M-Pin Full
+ *
+       @param T is the input M-Pin token (the client secret with PIN portion 
removed)
+       @param ID is the input client identity
+       @param CP is Public Key (or NULL)
+       @param g1 precomputed output
+       @param g2 precomputed output
+       @return 0 or an error code
+ */
+int MPIN_ZZZ_PRECOMPUTE(octet *T,octet *ID,octet *CP,octet *g1,octet *g2);
+/**    @brief Calculate Key on Server side for M-Pin Full
+ *
+       Uses UT internally for the key calculation, unless not available in 
which case U is used
+       @param h is the hash type
+       @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
+ */
+int MPIN_ZZZ_SERVER_KEY(int h,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 h is the hash type
+       @param g1 precomputed input
+       @param g2 precomputed input
+       @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
+ */
+int MPIN_ZZZ_CLIENT_KEY(int h,octet *g1,octet *g2,int pin,octet *r,octet 
*x,octet *p,octet *T,octet *K);
+
+/** @brief Generates a random public key for the client z.Q
+ *
+       @param R is a pointer to a cryptographically secure random number 
generator
+       @param Z an output internally randomly generated if R!=NULL, otherwise 
it must be provided as an input
+       @param Pa the output public key for the client
+ */
+int MPIN_ZZZ_GET_DVS_KEYPAIR(csprng *R,octet *Z,octet *Pa);
+
+#endif
+

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version3/c/mpin256.c
----------------------------------------------------------------------
diff --git a/version3/c/mpin256.c b/version3/c/mpin256.c
new file mode 100644
index 0000000..d8d9ea3
--- /dev/null
+++ b/version3/c/mpin256.c
@@ -0,0 +1,967 @@
+/*
+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.
+*/
+
+/* MPIN Functions */
+
+/* Version 3.0 - supports Time Permits */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "mpin256_ZZZ.h"
+
+
+#define ROUNDUP(a,b) ((a)-1)/(b)+1
+
+
+/* Special mpin hashing */
+static void mpin_hash(int sha,FP16_YYY *f, ECP_ZZZ *P,octet *w)
+{
+    int i;
+    BIG_XXX x,y;
+    char h[64];
+    hash256 sha256;
+    hash512 sha512;
+    char t[18*MODBYTES_XXX];  // to hold 10 BIGs
+    int hlen=sha;
+
+       FP_YYY_redc(x,&(f->a.a.a.a));
+    BIG_XXX_toBytes(&t[0],x);
+       FP_YYY_redc(x,&(f->a.a.a.b));
+    BIG_XXX_toBytes(&t[MODBYTES_XXX],x);
+
+    FP_YYY_redc(x,&(f->a.a.b.a));
+    BIG_XXX_toBytes(&t[2*MODBYTES_XXX],x);
+    FP_YYY_redc(x,&(f->a.a.b.b));
+    BIG_XXX_toBytes(&t[3*MODBYTES_XXX],x);
+
+    FP_YYY_redc(x,&(f->a.b.a.a));
+    BIG_XXX_toBytes(&t[4*MODBYTES_XXX],x);
+    FP_YYY_redc(x,&(f->a.b.a.b));
+    BIG_XXX_toBytes(&t[5*MODBYTES_XXX],x);
+
+    FP_YYY_redc(x,&(f->a.b.b.a));
+    BIG_XXX_toBytes(&t[6*MODBYTES_XXX],x);
+    FP_YYY_redc(x,&(f->a.b.b.b));
+    BIG_XXX_toBytes(&t[7*MODBYTES_XXX],x);
+
+       FP_YYY_redc(x,&(f->b.a.a.a));
+    BIG_XXX_toBytes(&t[8*MODBYTES_XXX],x);
+       FP_YYY_redc(x,&(f->b.a.a.b));
+    BIG_XXX_toBytes(&t[9*MODBYTES_XXX],x);
+
+    FP_YYY_redc(x,&(f->b.a.b.a));
+    BIG_XXX_toBytes(&t[10*MODBYTES_XXX],x);
+       FP_YYY_redc(x,&(f->b.a.b.b));
+    BIG_XXX_toBytes(&t[11*MODBYTES_XXX],x);
+
+    FP_YYY_redc(x,&(f->b.b.a.a));
+    BIG_XXX_toBytes(&t[12*MODBYTES_XXX],x);
+    FP_YYY_redc(x,&(f->b.b.a.b));
+    BIG_XXX_toBytes(&t[13*MODBYTES_XXX],x);
+
+    FP_YYY_redc(x,&(f->b.b.b.a));
+    BIG_XXX_toBytes(&t[14*MODBYTES_XXX],x);
+    FP_YYY_redc(x,&(f->b.b.b.b));
+    BIG_XXX_toBytes(&t[15*MODBYTES_XXX],x);
+
+    ECP_ZZZ_get(x,y,P);
+    BIG_XXX_toBytes(&t[16*MODBYTES_XXX],x);
+    BIG_XXX_toBytes(&t[17*MODBYTES_XXX],y);
+
+    OCT_empty(w);
+    switch (sha)
+    {
+    case SHA256:
+        HASH256_init(&sha256);
+        for (i=0; i<18*MODBYTES_XXX; i++) HASH256_process(&sha256,t[i]);
+        HASH256_hash(&sha256,h);
+        break;
+    case SHA384:
+        HASH384_init(&sha512);
+        for (i=0; i<18*MODBYTES_XXX; i++) HASH384_process(&sha512,t[i]);
+        HASH384_hash(&sha512,h);
+        break;
+    case SHA512:
+        HASH512_init(&sha512);
+        for (i=0; i<18*MODBYTES_XXX; i++) HASH512_process(&sha512,t[i]);
+        HASH512_hash(&sha512,h);
+        break;
+    }
+
+    OCT_jbytes(w,h,AESKEY_ZZZ);
+    for (i=0; i<hlen; i++) h[i]=0;
+}
+
+/* these next two functions help to implement elligator squared - 
http://eprint.iacr.org/2014/043 */
+/* maps a random u to a point on the curve */
+static void map(ECP_ZZZ *P,BIG_XXX u,int cb)
+{
+    BIG_XXX x,q;
+
+    BIG_XXX_rcopy(q,Modulus_YYY);
+    BIG_XXX_copy(x,u);
+    BIG_XXX_mod(x,q);
+
+    while (!ECP_ZZZ_setx(P,x,cb))
+       {
+        BIG_XXX_inc(x,1); BIG_XXX_norm(x);
+       }
+}
+
+/* returns u derived from P. Random value in range 1 to return value should 
then be added to u */
+static int unmap(BIG_XXX u,int *cb,ECP_ZZZ *P)
+{
+    int s,r=0;
+    BIG_XXX x;
+
+    s=ECP_ZZZ_get(x,x,P);
+    BIG_XXX_copy(u,x);
+    do
+    {
+        BIG_XXX_dec(u,1); BIG_XXX_norm(u);
+        r++;
+    }
+    while (!ECP_ZZZ_setx(P,u,s));
+    ECP_ZZZ_setx(P,x,s);
+
+    *cb=s;
+
+    return r;
+}
+
+/* these next two functions implement elligator squared - 
http://eprint.iacr.org/2014/043 */
+/* Elliptic curve point E in format (0x04,x,y} is converted to form {0x0-,u,v} 
*/
+/* Note that u and v are indistinguisible from random strings */
+int MPIN_ZZZ_ENCODING(csprng *RNG,octet *E)
+{
+    int rn,m,su,sv,res=0;
+
+    BIG_XXX q,u,v;
+    ECP_ZZZ P,W;
+
+    if (!ECP_ZZZ_fromOctet(&P,E)) res=MPIN_INVALID_POINT;
+    if (res==0)
+    {
+        BIG_XXX_rcopy(q,Modulus_YYY);
+
+        BIG_XXX_randomnum(u,q,RNG);
+
+        su=RAND_byte(RNG);
+        if (su<0) su=-su;
+        su%=2;
+        map(&W,u,su);
+        ECP_ZZZ_sub(&P,&W); 
+
+        rn=unmap(v,&sv,&P);
+        m=RAND_byte(RNG);
+        if (m<0) m=-m;
+        m%=rn;
+        BIG_XXX_inc(v,m+1);
+        E->val[0]=su+2*sv;
+        BIG_XXX_toBytes(&(E->val[1]),u);
+        BIG_XXX_toBytes(&(E->val[PFS_ZZZ+1]),v);
+    }
+    return res;
+}
+
+int MPIN_ZZZ_DECODING(octet *D)
+{
+    int su,sv;
+    BIG_XXX u,v;
+    ECP_ZZZ P,W;
+    int res=0;
+
+    if ((D->val[0]&0x04)!=0) res=MPIN_INVALID_POINT;
+    if (res==0)
+    {
+
+        BIG_XXX_fromBytes(u,&(D->val[1]));
+        BIG_XXX_fromBytes(v,&(D->val[PFS_ZZZ+1]));
+
+        su=D->val[0]&1;
+        sv=(D->val[0]>>1)&1;
+        map(&W,u,su);
+        map(&P,v,sv);
+        ECP_ZZZ_add(&P,&W); 
+        ECP_ZZZ_toOctet(D,&P,false);
+    }
+
+    return res;
+}
+
+/* R=R1+R2 in group G1 */
+int MPIN_ZZZ_RECOMBINE_G1(octet *R1,octet *R2,octet *R)
+{
+    ECP_ZZZ P,T;
+    int res=0;
+    if (res==0)
+    {
+        if (!ECP_ZZZ_fromOctet(&P,R1)) res=MPIN_INVALID_POINT;
+        if (!ECP_ZZZ_fromOctet(&T,R2)) res=MPIN_INVALID_POINT;
+    }
+    if (res==0)
+    {
+        ECP_ZZZ_add(&P,&T); 
+        ECP_ZZZ_toOctet(R,&P,false);
+    }
+    return res;
+}
+
+/* W=W1+W2 in group G2 */
+int MPIN_ZZZ_RECOMBINE_G2(octet *W1,octet *W2,octet *W)
+{
+    ECP8_ZZZ Q,T;
+    int res=0;
+    if (!ECP8_ZZZ_fromOctet(&Q,W1)) res=MPIN_INVALID_POINT;
+    if (!ECP8_ZZZ_fromOctet(&T,W2)) res=MPIN_INVALID_POINT;
+    if (res==0)
+    {
+        ECP8_ZZZ_add(&Q,&T); 
+        ECP8_ZZZ_toOctet(W,&Q);
+    }
+    return res;
+}
+
+/* create random secret S */
+int MPIN_ZZZ_RANDOM_GENERATE(csprng *RNG,octet* S)
+{
+    BIG_XXX r,s;
+
+    BIG_XXX_rcopy(r,CURVE_Order_ZZZ);
+    BIG_XXX_randomnum(s,r,RNG);
+#ifdef AES_S
+    BIG_XXX_mod2m(s,2*AES_S);
+#endif
+    BIG_XXX_toBytes(S->val,s);
+    S->len=MODBYTES_XXX;
+    return 0;
+}
+
+/* Extract PIN from TOKEN for identity CID */
+int MPIN_ZZZ_EXTRACT_PIN(int sha,octet *CID,int pin,octet *TOKEN)
+{
+       pin%=MAXPIN;
+       return MPIN_ZZZ_EXTRACT_FACTOR(sha,CID,pin,PBLEN,TOKEN);
+}
+
+/* Extract a factor < 32 bits for identity CID */
+int MPIN_ZZZ_EXTRACT_FACTOR(int sha,octet *CID,int factor,int facbits,octet 
*TOKEN)
+{
+    ECP_ZZZ P,R;
+    int res=0;
+    char h[MODBYTES_XXX];
+    octet H= {0,sizeof(h),h};
+
+    if (!ECP_ZZZ_fromOctet(&P,TOKEN))  res=MPIN_INVALID_POINT;
+    if (res==0)
+    {
+        mhashit(sha,-1,CID,&H);
+        ECP_ZZZ_mapit(&R,&H);
+
+        ECP_ZZZ_pinmul(&R,factor,facbits);
+        ECP_ZZZ_sub(&P,&R); 
+
+        ECP_ZZZ_toOctet(TOKEN,&P,false);
+    }
+    return res;
+}
+
+/* Extract a factor < 32 bits for identity CID */
+int MPIN_ZZZ_RESTORE_FACTOR(int sha,octet *CID,int factor,int facbits,octet 
*TOKEN)
+{
+    ECP_ZZZ P,R;
+    int res=0;
+    char h[MODBYTES_XXX];
+    octet H= {0,sizeof(h),h};
+
+    if (!ECP_ZZZ_fromOctet(&P,TOKEN))  res=MPIN_INVALID_POINT;
+    if (res==0)
+    {
+        mhashit(sha,-1,CID,&H);
+        ECP_ZZZ_mapit(&R,&H);
+
+        ECP_ZZZ_pinmul(&R,factor,facbits);
+        ECP_ZZZ_add(&P,&R); 
+
+        ECP_ZZZ_toOctet(TOKEN,&P,false);
+    }
+    return res;
+}
+
+/* Implement step 2 on client side of MPin protocol - SEC=-(x+y)*SEC */
+int MPIN_ZZZ_CLIENT_2(octet *X,octet *Y,octet *SEC)
+{
+    BIG_XXX px,py,r;
+    ECP_ZZZ P;
+    int res=0;
+    BIG_XXX_rcopy(r,CURVE_Order_ZZZ);
+    if (!ECP_ZZZ_fromOctet(&P,SEC)) res=MPIN_INVALID_POINT;
+    if (res==0)
+    {
+        BIG_XXX_fromBytes(px,X->val);
+        BIG_XXX_fromBytes(py,Y->val);
+        BIG_XXX_add(px,px,py);
+        BIG_XXX_mod(px,r);
+        PAIR_ZZZ_G1mul(&P,px);
+        ECP_ZZZ_neg(&P);
+        ECP_ZZZ_toOctet(SEC,&P,false);
+    }
+    return res;
+}
+
+/*
+ W=x*H(G);
+ if RNG == NULL then X is passed in
+ if RNG != NULL the X is passed out
+ if type=0 W=x*G where G is point on the curve, else W=x*M(G), where M(G) is 
mapping of octet G to point on the curve
+*/
+
+int MPIN_ZZZ_GET_G1_MULTIPLE(csprng *RNG,int type,octet *X,octet *G,octet *W)
+{
+    ECP_ZZZ P;
+    BIG_XXX r,x;
+    int res=0;
+    if (RNG!=NULL)
+    {
+        BIG_XXX_rcopy(r,CURVE_Order_ZZZ);
+        BIG_XXX_randomnum(x,r,RNG);
+#ifdef AES_S
+        BIG_XXX_mod2m(x,2*AES_S);
+#endif
+        X->len=MODBYTES_XXX;
+        BIG_XXX_toBytes(X->val,x);
+    }
+    else
+        BIG_XXX_fromBytes(x,X->val);
+
+    if (type==0)
+    {
+        if (!ECP_ZZZ_fromOctet(&P,G)) res=MPIN_INVALID_POINT;
+    }
+    else 
+       {
+               ECP_ZZZ_mapit(&P,G);
+       }
+
+    if (res==0)
+    {
+        PAIR_ZZZ_G1mul(&P,x);
+        ECP_ZZZ_toOctet(W,&P,false);
+    }
+    return res;
+}
+
+/*
+ if RNG == NULL then X is passed in
+ if RNG != NULL the X is passed out
+ W=x*G where G is point on the curve
+ if type==1 W=(x^-1)G
+*/
+
+int MPIN_ZZZ_GET_G2_MULTIPLE(csprng *RNG,int type,octet *X,octet *G,octet *W)
+{
+    ECP8_ZZZ P;
+    BIG_XXX r,x;
+    int res=0;
+    BIG_XXX_rcopy(r,CURVE_Order_ZZZ);
+    if (RNG!=NULL)
+    {
+        BIG_XXX_randomnum(x,r,RNG);
+#ifdef AES_S
+        BIG_XXX_mod2m(x,2*AES_S);
+#endif
+        X->len=MODBYTES_XXX;
+        BIG_XXX_toBytes(X->val,x);
+    }
+    else
+    {
+        BIG_XXX_fromBytes(x,X->val);
+        if (type==1) BIG_XXX_invmodp(x,x,r);
+    }
+
+    if (!ECP8_ZZZ_fromOctet(&P,G)) res=MPIN_INVALID_POINT;
+
+    if (res==0)
+    {
+        PAIR_ZZZ_G2mul(&P,x);
+        ECP8_ZZZ_toOctet(W,&P);
+    }
+    return res;
+}
+
+
+
+/* Client secret CST=s*H(CID) where CID is client ID and s is master secret */
+/* CID is hashed externally */
+int MPIN_ZZZ_GET_CLIENT_SECRET(octet *S,octet *CID,octet *CST)
+{
+    return MPIN_ZZZ_GET_G1_MULTIPLE(NULL,1,S,CID,CST);
+}
+
+/* Implement step 1 on client side of MPin protocol */
+int MPIN_ZZZ_CLIENT_1(int sha,int date,octet *CLIENT_ID,csprng *RNG,octet 
*X,int pin,octet *TOKEN,octet *SEC,octet *xID,octet *xCID,octet *PERMIT)
+{
+    BIG_XXX r,x;
+    ECP_ZZZ P,T,W;
+    int res=0;
+    char h[MODBYTES_XXX];
+    octet H= {0,sizeof(h),h};
+
+    BIG_XXX_rcopy(r,CURVE_Order_ZZZ);
+    if (RNG!=NULL)
+    {
+        BIG_XXX_randomnum(x,r,RNG);
+#ifdef AES_S
+        BIG_XXX_mod2m(x,2*AES_S);
+#endif
+        X->len=MODBYTES_XXX;
+        BIG_XXX_toBytes(X->val,x);
+    }
+    else
+        BIG_XXX_fromBytes(x,X->val);
+
+    mhashit(sha,-1,CLIENT_ID,&H);
+
+    ECP_ZZZ_mapit(&P,&H);
+
+    if (!ECP_ZZZ_fromOctet(&T,TOKEN)) res=MPIN_INVALID_POINT;
+
+    if (res==0)
+    {
+        pin%=MAXPIN;
+
+        ECP_ZZZ_copy(&W,&P);                           // W=H(ID)
+        ECP_ZZZ_pinmul(&W,pin,PBLEN);                  // W=alpha.H(ID)
+        ECP_ZZZ_add(&T,&W);                                    // 
T=Token+alpha.H(ID) = s.H(ID)
+
+        if (date)
+        {
+            if (PERMIT!=NULL)
+            {
+                if (!ECP_ZZZ_fromOctet(&W,PERMIT)) res=MPIN_INVALID_POINT;
+                ECP_ZZZ_add(&T,&W);                                    // 
SEC=s.H(ID)+s.H(T|ID)
+            }
+            mhashit(sha,date,&H,&H);
+
+            ECP_ZZZ_mapit(&W,&H);
+            if (xID!=NULL)
+            {
+                PAIR_ZZZ_G1mul(&P,x);                          // P=x.H(ID)
+                ECP_ZZZ_toOctet(xID,&P,false);  // xID
+                PAIR_ZZZ_G1mul(&W,x);               // W=x.H(T|ID)
+                ECP_ZZZ_add(&P,&W); 
+            }
+            else
+            {
+                ECP_ZZZ_add(&P,&W); 
+                PAIR_ZZZ_G1mul(&P,x);
+            }
+            if (xCID!=NULL) ECP_ZZZ_toOctet(xCID,&P,false);  // U
+        }
+        else
+        {
+            if (xID!=NULL)
+            {
+                PAIR_ZZZ_G1mul(&P,x);                          // P=x.H(ID)
+                ECP_ZZZ_toOctet(xID,&P,false);  // xID
+            }
+        }
+    }
+
+    if (res==0)
+       {
+        ECP_ZZZ_toOctet(SEC,&T,false);  // V
+       }
+    return res;
+}
+
+/* Extract Server Secret SST=S*Q where Q is fixed generator in G2 and S is 
master secret */
+int MPIN_ZZZ_GET_SERVER_SECRET(octet *S,octet *SST)
+{
+    BIG_XXX r,s;
+    ECP8_ZZZ Q;
+    int res=0;
+
+    BIG_XXX_rcopy(r,CURVE_Order_ZZZ);
+
+       ECP8_ZZZ_generator(&Q);
+
+    if (res==0)
+    {
+        BIG_XXX_fromBytes(s,S->val);
+        PAIR_ZZZ_G2mul(&Q,s);
+        ECP8_ZZZ_toOctet(SST,&Q);
+    }
+
+    return res;
+}
+
+
+/* Time Permit CTT=s*H(date|H(CID)) where s is master secret */
+int MPIN_ZZZ_GET_CLIENT_PERMIT(int sha,int date,octet *S,octet *CID,octet *CTT)
+{
+    BIG_XXX s;
+    ECP_ZZZ P;
+    char h[MODBYTES_XXX];
+    octet H= {0,sizeof(h),h};
+
+    mhashit(sha,date,CID,&H);
+
+    ECP_ZZZ_mapit(&P,&H);
+
+    BIG_XXX_fromBytes(s,S->val);
+
+    PAIR_ZZZ_G1mul(&P,s);
+
+    ECP_ZZZ_toOctet(CTT,&P,false);
+    return 0;
+}
+
+// if date=0 only use HID, set HCID=NULL
+// if date and PE, use HID and HCID
+
+/* Outputs H(CID) and H(CID)+H(T|H(CID)) for time permits. If no time permits 
set HTID=NULL */
+void MPIN_ZZZ_SERVER_1(int sha,int date,octet *CID,octet *HID,octet *HTID)
+{
+    char h[MODBYTES_XXX];
+    octet H= {0,sizeof(h),h};
+    ECP_ZZZ P,R;
+       BIG_XXX x;
+
+#ifdef USE_ANONYMOUS
+    ECP_ZZZ_mapit(&P,CID);
+#else
+    mhashit(sha,-1,CID,&H);
+    ECP_ZZZ_mapit(&P,&H);
+#endif
+
+    ECP_ZZZ_toOctet(HID,&P,false);  // new
+
+    if (date)
+    {
+#ifdef USE_ANONYMOUS
+        mhashit(sha,date,CID,&H);
+#else
+        mhashit(sha,date,&H,&H);
+#endif
+        ECP_ZZZ_mapit(&R,&H);
+        ECP_ZZZ_add(&P,&R); 
+        ECP_ZZZ_toOctet(HTID,&P,false);
+    }
+}
+
+/* Implement M-Pin on server side */
+int MPIN_ZZZ_SERVER_2(int date,octet *HID,octet *HTID,octet *Y,octet 
*SST,octet *xID,octet *xCID,octet *mSEC,octet *E,octet *F,octet *Pa)
+{
+    BIG_XXX px,py,y;
+    FP48_YYY g;
+    ECP8_ZZZ Q,sQ;
+    ECP_ZZZ P,R;
+    int res=0;
+
+       ECP8_ZZZ_generator(&Q);
+
+    // key-escrow less scheme: use Pa instead of Q in pairing computation
+    // Q left for backward compatiblity
+    if (Pa!=NULL)
+    {
+        if (!ECP8_ZZZ_fromOctet(&Q, Pa)) res=MPIN_INVALID_POINT;
+    }
+
+
+    if (res==0)
+    {
+        if (!ECP8_ZZZ_fromOctet(&sQ,SST)) res=MPIN_INVALID_POINT;
+    }
+
+    if (res==0)
+    {
+       if (date)
+        {
+                       if (!ECP_ZZZ_fromOctet(&R,xCID))  
res=MPIN_INVALID_POINT;
+        }
+        else
+        {
+                       if (!ECP_ZZZ_fromOctet(&R,xID))  res=MPIN_INVALID_POINT;
+        }
+    }
+    if (res==0)
+    {
+        BIG_XXX_fromBytes(y,Y->val);
+        if (date)
+        {
+            if (!ECP_ZZZ_fromOctet(&P,HTID))  res=MPIN_INVALID_POINT;
+        }
+        else
+        {
+            if (!ECP_ZZZ_fromOctet(&P,HID))  res=MPIN_INVALID_POINT;
+        }
+    }
+    if (res==0)
+    {
+        PAIR_ZZZ_G1mul(&P,y);  // y(A+AT)
+        ECP_ZZZ_add(&P,&R); // x(A+AT)+y(A+T)
+        if (!ECP_ZZZ_fromOctet(&R,mSEC))  res=MPIN_INVALID_POINT; // V
+    }
+    if (res==0)
+    {
+
+        PAIR_ZZZ_double_ate(&g,&Q,&R,&sQ,&P);
+        PAIR_ZZZ_fexp(&g);
+
+        if (!FP48_YYY_isunity(&g))
+        {
+            if (HID!=NULL && xID!=NULL && E!=NULL && F !=NULL)
+            {
+                /* xID is set to NULL if there is no way to calculate PIN 
error */
+                FP48_YYY_toOctet(E,&g);
+
+                /* Note error is in the PIN, not in the time permit! Hence the 
need to exclude Time Permit from this check */
+
+                if (date)
+                {
+                    if (!ECP_ZZZ_fromOctet(&P,HID)) res=MPIN_INVALID_POINT;
+                    if (!ECP_ZZZ_fromOctet(&R,xID)) res=MPIN_INVALID_POINT; // 
U
+
+                    if (res==0)
+                    {
+                        PAIR_ZZZ_G1mul(&P,y);  // yA
+                        ECP_ZZZ_add(&P,&R); // yA+xA
+                    }
+                }
+                if (res==0)
+                {
+                    PAIR_ZZZ_ate(&g,&Q,&P);
+                    PAIR_ZZZ_fexp(&g);
+                    FP48_YYY_toOctet(F,&g);
+                }
+            }
+            res=MPIN_BAD_PIN;
+        }
+    }
+
+    return res;
+}
+
+#if MAXPIN==10000
+#define MR_TS 10  /* 2^10/10 approx = sqrt(MAXPIN) */
+#define TRAP 200  /* 2*sqrt(MAXPIN) */
+#endif
+
+#if MAXPIN==1000000
+#define MR_TS 14
+#define TRAP 2000
+#endif
+
+/* Pollards kangaroos used to return PIN error */
+int MPIN_ZZZ_KANGAROO(octet *E,octet *F)
+{
+    int i,j,m,s,dn,dm,steps;
+    int distance[MR_TS];
+    FP48_YYY ge,gf,t,table[MR_TS];
+    int res=0;
+
+    FP48_YYY_fromOctet(&ge,E);
+    FP48_YYY_fromOctet(&gf,F);
+
+    FP48_YYY_copy(&t,&gf);
+
+    for (s=1,m=0; m<MR_TS; m++)
+    {
+        distance[m]=s;
+        FP48_YYY_copy(&table[m],&t);
+        s*=2;
+        FP48_YYY_usqr(&t,&t);
+        FP48_YYY_reduce(&t);
+    }
+
+    FP48_YYY_one(&t);
+
+    for (dn=0,j=0; j<TRAP; j++)
+    {
+        i=t.a.a.a.a.a.g[0]%MR_TS;
+
+        FP48_YYY_mul(&t,&table[i]);
+        FP48_YYY_reduce(&t);
+        dn+=distance[i];
+    }
+
+    FP48_YYY_conj(&gf,&t);
+    steps=0;
+    dm=0;
+    while (dm-dn<MAXPIN)
+    {
+        steps++;
+        if (steps>4*TRAP) break;
+        i=ge.a.a.a.a.a.g[0]%MR_TS;
+
+        FP48_YYY_mul(&ge,&table[i]);
+        FP48_YYY_reduce(&ge);
+        dm+=distance[i];
+        if (FP48_YYY_equals(&ge,&t))
+        {
+            res=dm-dn;
+            break;
+        }
+        if (FP48_YYY_equals(&ge,&gf))
+        {
+            res=dn-dm;
+            break;
+        }
+    }
+    if (steps>4*TRAP || dm-dn>=MAXPIN)
+    {
+        res=0;    /* Trap Failed  - probable invalid token */
+    }
+
+    return res;
+}
+
+/* Functions to support M-Pin Full */
+
+int MPIN_ZZZ_PRECOMPUTE(octet *TOKEN,octet *CID,octet *CP,octet *G1,octet *G2)
+{
+    ECP_ZZZ P,T;
+    ECP8_ZZZ Q;
+    FP48_YYY g;
+       BIG_XXX x;
+    int res=0;
+
+    if (!ECP_ZZZ_fromOctet(&T,TOKEN)) res=MPIN_INVALID_POINT;
+
+    if (res==0)
+    {
+        ECP_ZZZ_mapit(&P,CID);
+        if (CP!=NULL)
+        {
+            if (!ECP8_ZZZ_fromOctet(&Q,CP)) res=MPIN_INVALID_POINT;
+        }
+        else
+        {
+                       ECP8_ZZZ_generator(&Q);
+        }
+    }
+    if (res==0)
+    {
+        PAIR_ZZZ_ate(&g,&Q,&T);
+        PAIR_ZZZ_fexp(&g);
+
+        FP48_YYY_toOctet(G1,&g);
+        if (G2!=NULL)
+        {
+            PAIR_ZZZ_ate(&g,&Q,&P);
+            PAIR_ZZZ_fexp(&g);
+            FP48_YYY_toOctet(G2,&g);
+        }
+    }
+    return res;
+}
+
+/* calculate common key on client side */
+/* wCID = w.(A+AT) */
+int MPIN_ZZZ_CLIENT_KEY(int sha,octet *G1,octet *G2,int pin,octet *R,octet 
*X,octet *H,octet *wCID,octet *CK)
+{
+    FP48_YYY g1,g2;
+       FP16_YYY c;
+
+    ECP_ZZZ W;
+    int res=0;
+    BIG_XXX r,z,x,h;
+
+    FP48_YYY_fromOctet(&g1,G1);
+    FP48_YYY_fromOctet(&g2,G2);
+    BIG_XXX_fromBytes(z,R->val);
+    BIG_XXX_fromBytes(x,X->val);
+    BIG_XXX_fromBytes(h,H->val);
+
+    if (!ECP_ZZZ_fromOctet(&W,wCID)) res=MPIN_INVALID_POINT;
+
+    if (res==0)
+    {
+        BIG_XXX_rcopy(r,CURVE_Order_ZZZ);
+        BIG_XXX_add(z,z,h);    // new
+        BIG_XXX_mod(z,r);
+
+        FP48_YYY_pinpow(&g2,pin,PBLEN);
+        FP48_YYY_mul(&g1,&g2);
+
+               PAIR_ZZZ_G1mul(&W,x);
+
+               FP48_YYY_compow(&c,&g1,z,r);
+               mpin_hash(sha,&c,&W,CK);
+
+    }
+    return res;
+}
+
+/* calculate common key on server side */
+/* Z=r.A - no time permits involved */
+
+int MPIN_ZZZ_SERVER_KEY(int sha,octet *Z,octet *SST,octet *W,octet *H,octet 
*HID,octet *xID,octet *xCID,octet *SK)
+{
+    int res=0;
+    FP48_YYY g;
+    FP16_YYY c;
+    ECP_ZZZ R,U,A;
+    ECP8_ZZZ sQ;
+    BIG_XXX w,h;
+
+    if (!ECP8_ZZZ_fromOctet(&sQ,SST)) res=MPIN_INVALID_POINT;
+    if (!ECP_ZZZ_fromOctet(&R,Z)) res=MPIN_INVALID_POINT;
+
+
+    if (!ECP_ZZZ_fromOctet(&A,HID)) res=MPIN_INVALID_POINT;
+
+    // new
+    if (xCID!=NULL)
+    {
+        if (!ECP_ZZZ_fromOctet(&U,xCID)) res=MPIN_INVALID_POINT;
+    }
+    else
+    {
+        if (!ECP_ZZZ_fromOctet(&U,xID)) res=MPIN_INVALID_POINT;
+    }
+    BIG_XXX_fromBytes(w,W->val);
+    BIG_XXX_fromBytes(h,H->val);
+
+
+    PAIR_ZZZ_ate(&g,&sQ,&A);
+    PAIR_ZZZ_fexp(&g);
+
+    if (res==0)
+    {
+        PAIR_ZZZ_G1mul(&A,h);
+        ECP_ZZZ_add(&R,&A);  // new
+        PAIR_ZZZ_ate(&g,&sQ,&R);
+        PAIR_ZZZ_fexp(&g);
+        PAIR_ZZZ_G1mul(&U,w);
+        FP48_YYY_trace(&c,&g);
+        mpin_hash(sha,&c,&U,SK);
+    }
+    return res;
+}
+
+/* Generate Y = H(TimeValue, xCID/xID) */
+void MPIN_ZZZ_GET_Y(int sha,int TimeValue,octet *xCID,octet *Y)
+{
+    BIG_XXX q,y;
+    char h[MODBYTES_XXX];
+    octet H= {0,sizeof(h),h};
+
+    mhashit(sha,TimeValue,xCID,&H);
+    BIG_XXX_fromBytes(y,H.val);
+    BIG_XXX_rcopy(q,CURVE_Order_ZZZ);
+    BIG_XXX_mod(y,q);
+    BIG_XXX_toBytes(Y->val,y);
+    Y->len=PGS_ZZZ;
+}
+
+/* One pass MPIN Client */
+int MPIN_ZZZ_CLIENT(int sha,int date,octet *ID,csprng *RNG,octet *X,int 
pin,octet *TOKEN,octet *V,octet *U,octet *UT,octet *TP,octet *MESSAGE,int 
TimeValue,octet *Y)
+{
+    int rtn=0;
+    char m[M_SIZE_ZZZ];
+    octet M= {0,sizeof(m),m};
+
+    octet *pID;
+    if (date == 0)
+        pID = U;
+    else
+        pID = UT;
+
+    rtn = MPIN_ZZZ_CLIENT_1(sha,date,ID,RNG,X,pin,TOKEN,V,U,UT,TP);
+    if (rtn != 0)
+        return rtn;
+
+    OCT_joctet(&M,pID);
+   if (MESSAGE!=NULL)
+   {
+       OCT_joctet(&M,MESSAGE);
+   }
+
+    MPIN_ZZZ_GET_Y(sha,TimeValue,&M,Y);
+
+    rtn = MPIN_ZZZ_CLIENT_2(X,Y,V);
+    if (rtn != 0)
+        return rtn;
+
+    return 0;
+}
+
+/* One pass MPIN Server */
+int MPIN_ZZZ_SERVER(int sha,int date,octet *HID,octet *HTID,octet *Y,octet 
*sQ,octet *U,octet *UT,octet *V,octet *E,octet *F,octet *ID,octet *MESSAGE,int 
TimeValue, octet *Pa)
+{
+    int rtn=0;
+    char m[M_SIZE_ZZZ];
+    octet M= {0,sizeof(m),m};
+
+    octet *pU;
+    if (date == 0)
+        pU = U;
+    else
+        pU = UT;
+
+    MPIN_ZZZ_SERVER_1(sha,date,ID,HID,HTID);
+
+    OCT_joctet(&M,pU);
+   if (MESSAGE!=NULL)
+   {
+       OCT_joctet(&M,MESSAGE);
+   }
+
+    MPIN_ZZZ_GET_Y(sha,TimeValue,&M,Y);
+
+    rtn = MPIN_ZZZ_SERVER_2(date,HID,HTID,Y,sQ,U,UT,V,E,F,Pa);
+    if (rtn != 0)
+        return rtn;
+
+    return 0;
+}
+
+int MPIN_ZZZ_GET_DVS_KEYPAIR(csprng *R,octet *Z,octet *Pa)
+{
+    BIG_XXX z,r;
+    ECP8_ZZZ Q;
+    int res=0;
+
+    BIG_XXX_rcopy(r,CURVE_Order_ZZZ);
+
+    if (R!=NULL)
+    {
+        BIG_XXX_randomnum(z,r,R);
+        Z->len=MODBYTES_XXX;
+        BIG_XXX_toBytes(Z->val,z);
+    }
+    else
+        BIG_XXX_fromBytes(z,Z->val);
+
+    BIG_XXX_invmodp(z,z,r);
+
+       ECP8_ZZZ_generator(&Q);
+
+    if (res==0)
+    {
+        PAIR_ZZZ_G2mul(&Q,z);
+        ECP8_ZZZ_toOctet(Pa,&Q);
+    }
+
+    return res;
+}

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version3/c/mpin256.h
----------------------------------------------------------------------
diff --git a/version3/c/mpin256.h b/version3/c/mpin256.h
new file mode 100644
index 0000000..46ba21a
--- /dev/null
+++ b/version3/c/mpin256.h
@@ -0,0 +1,339 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+
+/**
+ * @file mpin.h
+ * @author Mike Scott and Kealan McCusker
+ * @date 2nd June 2015
+ * @brief M-Pin Header file
+ *
+ * Allows some user configuration
+ * defines structures
+ * declares functions
+ *
+ */
+
+#ifndef MPIN_ZZZ_H
+#define MPIN_ZZZ_H
+
+#include "pair256_ZZZ.h"
+#include "pbc_support.h"
+
+
+/* Field size is assumed to be greater than or equal to group size */
+
+#define PGS_ZZZ MODBYTES_XXX  /**< MPIN Group Size */
+#define PFS_ZZZ MODBYTES_XXX  /**< MPIN Field Size */
+
+#define MPIN_OK             0   /**< Function completed without error */
+#define MPIN_INVALID_POINT  -14        /**< Point is NOT on the curve */
+#define MPIN_BAD_PIN        -19 /**< Bad PIN number entered */
+
+#define MAXPIN 10000         /**< max PIN */
+#define PBLEN 14             /**< max length of PIN in bits */
+
+//#define PAS_ZZZ 24        /**< MPIN Symmetric Key Size 192 bits  */
+//#define HASH_TYPE_MPIN_ZZZ SHA384   /**< Choose Hash function */
+
+#define MESSAGE_SIZE 256        /**< Signature message size  */
+#define M_SIZE_ZZZ (MESSAGE_SIZE+2*PFS_ZZZ+1)   /**< Signature message size 
and G1 size */
+
+/* MPIN support functions */
+
+/* MPIN primitives */
+
+
+void MPIN_ZZZ_GET_Y(int h,int t,octet *O,octet *Y);
+/**    @brief Extract a PIN number from a client secret
+ *
+       @param h is the hash type
+       @param ID is the input client identity
+       @param factor is an input factor
+       @param facbits is the number of bits in the factor
+       @param CS is the client secret from which the factor is to be extracted
+       @return 0 or an error code
+ */
+int MPIN_ZZZ_EXTRACT_FACTOR(int h,octet *ID,int factor,int facbits,octet *CS);
+
+/**    @brief Extract a PIN number from a client secret
+ *
+       @param h is the hash type
+       @param ID is the input client identity
+       @param factor is an input factor
+       @param facbits is the number of bits in the factor
+       @param CS is the client secret to which the factor is to be added
+       @return 0 or an error code
+ */
+int MPIN_ZZZ_RESTORE_FACTOR(int h,octet *ID,int factor,int facbits,octet *CS);
+
+
+/**    @brief Extract a PIN number from a client secret
+ *
+       @param h is the hash type
+       @param ID is the input client identity
+       @param pin is an input PIN number
+       @param CS is the client secret from which the PIN is to be extracted
+       @return 0 or an error code
+ */
+int MPIN_ZZZ_EXTRACT_PIN(int h,octet *ID,int pin,octet *CS);
+
+/**    @brief Perform client side of the one-pass version of the M-Pin protocol
+ *
+       If Time Permits are disabled, set d = 0, and UT is not generated and 
can be set to NULL.
+       If Time Permits are enabled, and PIN error detection is OFF, U is not 
generated and can be set to NULL.
+       If Time Permits are enabled, and PIN error detection is ON, U and UT 
are both generated.
+       @param h is the hash type
+       @param d is input date, in days since the epoch. Set to 0 if Time 
permits disabled
+       @param ID is the input client identity
+       @param R is a pointer to a cryptographically secure random number 
generator
+       @param x an output internally randomly generated if R!=NULL, otherwise 
must be provided as an input
+       @param pin is the input PIN number
+       @param T is the input M-Pin token (the client secret with PIN portion 
removed)
+       @param V is output = -(x+y)(CS+TP), where CS is the reconstructed 
client secret, and TP is the time permit
+       @param U is output = x.H(ID)
+       @param UT is output = x.(H(ID)+H(d|H(ID)))
+       @param TP is the input time permit
+       @param MESSAGE is the message to be signed
+       @param t is input epoch time in seconds - a timestamp
+       @param y is output H(t|U) or H(t|UT) if Time Permits enabled
+       @return 0 or an error code
+ */
+int MPIN_ZZZ_CLIENT(int h,int d,octet *ID,csprng *R,octet *x,int pin,octet 
*T,octet *V,octet *U,octet *UT,octet *TP, octet* MESSAGE, int t, octet *y);
+/**    @brief Perform first pass of the client side of the 3-pass version of 
the M-Pin protocol
+ *
+       If Time Permits are disabled, set d = 0, and UT is not generated and 
can be set to NULL.
+       If Time Permits are enabled, and PIN error detection is OFF, U is not 
generated and can be set to NULL.
+       If Time Permits are enabled, and PIN error detection is ON, U and UT 
are both generated.
+       @param h is the hash type
+       @param d is input date, in days since the epoch. Set to 0 if Time 
permits disabled
+       @param ID is the input client identity
+       @param R is a pointer to a cryptographically secure random number 
generator
+       @param x an output internally randomly generated if R!=NULL, otherwise 
must be provided as an input
+       @param pin is the input PIN number
+       @param T is the input M-Pin token (the client secret with PIN portion 
removed)
+       @param S is output = CS+TP, where CS=is the reconstructed client 
secret, and TP is the time permit
+       @param U is output = x.H(ID)
+       @param UT is output = x.(H(ID)+H(d|H(ID)))
+       @param TP is the input time permit
+       @return 0 or an error code
+ */
+int MPIN_ZZZ_CLIENT_1(int h,int d,octet *ID,csprng *R,octet *x,int pin,octet 
*T,octet *S,octet *U,octet *UT,octet *TP);
+/**    @brief Generate a random group element
+ *
+       @param R is a pointer to a cryptographically secure random number 
generator
+       @param S is the output random octet
+       @return 0 or an error code
+ */
+int MPIN_ZZZ_RANDOM_GENERATE(csprng *R,octet *S);
+/**    @brief Perform second pass of the client side of the 3-pass version of 
the M-Pin protocol
+ *
+       @param x an input, a locally generated random number
+       @param y an input random challenge from the server
+       @param V on output = -(x+y).V
+       @return 0 or an error code
+ */
+int MPIN_ZZZ_CLIENT_2(octet *x,octet *y,octet *V);
+/**    @brief Perform server side of the one-pass version of the M-Pin protocol
+ *
+       If Time Permits are disabled, set d = 0, and UT and HTID are not 
generated and can be set to NULL.
+       If Time Permits are enabled, and PIN error detection is OFF, U and HID 
are not needed and can be set to NULL.
+       If Time Permits are enabled, and PIN error detection is ON, U, UT, HID 
and HTID are all required.
+       @param h is the hash type
+       @param d is input date, in days since the epoch. Set to 0 if Time 
permits disabled
+       @param HID is output H(ID), a hash of the client ID
+       @param HTID is output H(ID)+H(d|H(ID))
+       @param y is output H(t|U) or H(t|UT) if Time Permits enabled
+       @param SS is the input server secret
+       @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 V is an input from the client
+       @param E is an output to help the Kangaroos to find the PIN error, or 
NULL if not required
+       @param F is an output to help the Kangaroos to find the PIN error, or 
NULL if not required
+       @param ID is the input claimed client identity
+       @param MESSAGE is the message to be signed
+       @param t is input epoch time in seconds - a timestamp
+       @param Pa is input from the client z.Q or NULL if the key-escrow less 
scheme is not used
+       @return 0 or an error code
+ */
+int MPIN_ZZZ_SERVER(int h,int d,octet *HID,octet *HTID,octet *y,octet 
*SS,octet *U,octet *UT,octet *V,octet *E,octet *F,octet *ID,octet *MESSAGE, int 
t, octet *Pa);
+/**    @brief Perform first pass of the server side of the 3-pass version of 
the M-Pin protocol
+ *
+       @param h is the hash type
+       @param d is input date, in days since the epoch. Set to 0 if Time 
permits disabled
+       @param ID is the input claimed client identity
+       @param HID is output H(ID), a hash of the client ID
+       @param HTID is output H(ID)+H(d|H(ID))
+       @return 0 or an error code
+ */
+void MPIN_ZZZ_SERVER_1(int h,int d,octet *ID,octet *HID,octet *HTID);
+/**    @brief Perform third pass on the server side of the 3-pass version of 
the M-Pin protocol
+ *
+       If Time Permits are disabled, set d = 0, and UT and HTID are not needed 
and can be set to NULL.
+       If Time Permits are enabled, and PIN error detection is OFF, U and HID 
are not needed and can be set to NULL.
+       If Time Permits are enabled, and PIN error detection is ON, U, UT, HID 
and HTID are all required.
+       @param d is input date, in days since the epoch. Set to 0 if Time 
permits disabled
+       @param HID is input H(ID), a hash of the client ID
+       @param HTID is input H(ID)+H(d|H(ID))
+       @param y is the input server's randomly generated challenge
+       @param SS is the input server secret
+       @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 V is an input from the client
+       @param E is an output to help the Kangaroos to find the PIN error, or 
NULL if not required
+       @param F is an output to help the Kangaroos to find the PIN error, or 
NULL if not required
+       @param Pa is the input public key from the client, z.Q or NULL if the 
client uses regular mpin
+       @return 0 or an error code
+ */
+int MPIN_ZZZ_SERVER_2(int d,octet *HID,octet *HTID,octet *y,octet *SS,octet 
*U,octet *UT,octet *V,octet *E,octet *F,octet *Pa);
+/**    @brief Add two members from the group G1
+ *
+       @param Q1 an input member of G1
+       @param Q2 an input member of G1
+       @param Q an output member of G1 = Q1+Q2
+       @return 0 or an error code
+ */
+int MPIN_ZZZ_RECOMBINE_G1(octet *Q1,octet *Q2,octet *Q);
+/**    @brief Add two members from the group G2
+ *
+       @param P1 an input member of G2
+       @param P2 an input member of G2
+       @param P an output member of G2 = P1+P2
+       @return 0 or an error code
+ */
+int MPIN_ZZZ_RECOMBINE_G2(octet *P1,octet *P2,octet *P);
+/**    @brief Use Kangaroos to find PIN error
+ *
+       @param E a member of the group GT
+       @param F a member of the group GT =  E^e
+       @return 0 if Kangaroos failed, or the PIN error e
+ */
+int MPIN_ZZZ_KANGAROO(octet *E,octet *F);
+/**    @brief Encoding of a Time Permit to make it indistinguishable from a 
random string
+ *
+       @param R is a pointer to a cryptographically secure random number 
generator
+       @param TP is the input time permit, obfuscated on output
+       @return 0 or an error code
+ */
+int MPIN_ZZZ_ENCODING(csprng *R,octet *TP);
+/**    @brief Encoding of an obfuscated Time Permit
+ *
+       @param TP is the input obfuscated time permit, restored on output
+       @return 0 or an error code
+ */
+int MPIN_ZZZ_DECODING(octet *TP);
+
+/**    @brief Find a random multiple of a point in G1
+ *
+       @param R is a pointer to a cryptographically secure random number 
generator
+       @param type determines type of action to be taken
+       @param x an output internally randomly generated if R!=NULL, otherwise 
must be provided as an input
+       @param G if type=0 a point in G1, else an octet to be mapped to G1
+       @param W the output =x.G or x.M(G), where M(.) is a mapping
+       @return 0 or an error code
+ */
+int MPIN_ZZZ_GET_G1_MULTIPLE(csprng *R,int type,octet *x,octet *G,octet *W);
+/**    @brief Find a random multiple of a point in G1
+ *
+       @param R is a pointer to a cryptographically secure random number 
generator
+       @param type determines type of action to betaken
+       @param x an output internally randomly generated if R!=NULL, otherwise 
must be provided as an input
+       @param G a point in G2
+       @param W the output =x.G or (1/x).G
+       @return 0 or an error code
+ */
+int MPIN_ZZZ_GET_G2_MULTIPLE(csprng *R,int type,octet *x,octet *G,octet *W);
+
+/**    @brief Create a client secret in G1 from a master secret and the client 
ID
+ *
+       @param S is an input master secret
+       @param ID is the input client identity
+       @param CS is the full client secret = s.H(ID)
+       @return 0 or an error code
+ */
+int MPIN_ZZZ_GET_CLIENT_SECRET(octet *S,octet *ID,octet *CS);
+/**    @brief Create a Time Permit in G1 from a master secret and the client ID
+ *
+       @param h is the hash type
+       @param d is input date, in days since the epoch.
+       @param S is an input master secret
+       @param ID is the input client identity
+       @param TP is a Time Permit for the given date = s.H(d|H(ID))
+       @return 0 or an error code
+ */
+int MPIN_ZZZ_GET_CLIENT_PERMIT(int h,int d,octet *S,octet *ID,octet *TP);
+/**    @brief Create a server secret in G2 from a master secret
+ *
+       @param S is an input master secret
+       @param SS is the server secret = s.Q where Q is a fixed generator of G2
+       @return 0 or an error code
+ */
+int MPIN_ZZZ_GET_SERVER_SECRET(octet *S,octet *SS);
+/* int MPIN_TEST_PAIRING(octet *,octet *); */
+
+/* For M-Pin Full */
+/**    @brief Precompute values for use by the client side of M-Pin Full
+ *
+       @param T is the input M-Pin token (the client secret with PIN portion 
removed)
+       @param ID is the input client identity
+       @param CP is Public Key (or NULL)
+       @param g1 precomputed output
+       @param g2 precomputed output
+       @return 0 or an error code
+ */
+int MPIN_ZZZ_PRECOMPUTE(octet *T,octet *ID,octet *CP,octet *g1,octet *g2);
+/**    @brief Calculate Key on Server side for M-Pin Full
+ *
+       Uses UT internally for the key calculation, unless not available in 
which case U is used
+       @param h is the hash type
+       @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
+ */
+int MPIN_ZZZ_SERVER_KEY(int h,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 h is the hash type
+       @param g1 precomputed input
+       @param g2 precomputed input
+       @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
+ */
+int MPIN_ZZZ_CLIENT_KEY(int h,octet *g1,octet *g2,int pin,octet *r,octet 
*x,octet *p,octet *T,octet *K);
+
+/** @brief Generates a random public key for the client z.Q
+ *
+       @param R is a pointer to a cryptographically secure random number 
generator
+       @param Z an output internally randomly generated if R!=NULL, otherwise 
it must be provided as an input
+       @param Pa the output public key for the client
+ */
+int MPIN_ZZZ_GET_DVS_KEYPAIR(csprng *R,octet *Z,octet *Pa);
+
+#endif
+

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version3/c/newhope.c
----------------------------------------------------------------------
diff --git a/version3/c/newhope.c b/version3/c/newhope.c
new file mode 100644
index 0000000..0d02552
--- /dev/null
+++ b/version3/c/newhope.c
@@ -0,0 +1,510 @@
+/*
+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.
+*/
+
+/* NewHope API implementation. Constant time.
+
+       LOOK - no if statements!
+
+   M.Scott 21/07/2017
+*/
+
+#include "newhope.h"
+
+const sign16 roots[] 
={0x2ac8,0x2baf,0x299b,0x685,0x2f04,0x158d,0x2d49,0x24b5,0x1edc,0xab3,0x2a95,0x24d,0x3cb,0x6a8,0x12f9,0x15ba,0x1861,0x2a89,0x1c5c,0xbe6,0xc1e,0x2024,0x207,0x19ce,0x2710,0x1744,0x18bc,0x2cd7,0x396,0x18d5,0x1c45,0xc4,0x21a6,0xe03,0x2b3c,0x2d91,0xc5d,0x432,0x1fbc,0xcae,0x2512,0x2979,0x3b2,0x714,0xb2e,0x1a97,0x1a03,0x1bcd,0x2216,0x2701,0xa,0x263c,0x1179,0x200c,0x2d08,0x1c34,0x291,0x2c99,0x2a5a,0x723,0xb1d,0x1ccc,0x1fb6,0x2f58,0x2bfe,0x1cda,0x2a0,0x5f1,0x2de,0x1fc7,0x1ea8,0x1719,0x2fa7,0x27ec,0x20ff,0x12c0,0x1ac1,0x2232,0x2f9b,0xd3e,0x2aed,0x15f0,0x11e8,0xed0,0x26a,0x1de5,0xa3f,0xf43,0xebf,0x204e,0xac7,0x2d9c,0x5ea,0x25d1,0xb6,0x49c,0x995,0x2555,0x26e2,0x100,0x1878,0x5aa,0x2e10,0x271c,0xcb,0x1b4c,0x2fb8,0x25b7,0x1543,0x2c7b,0x241a,0x2223,0x20ca,0x24ed,0x137,0x1b65,0x1dc2,0x7c7,0x2ec3,0xd0c,0x1169,0x1c7a,0x1ea1,0xf89,0x2199,0x291d,0x1088,0x2046,0x256d,0x2bc7,0x2e9b,0x41f,0x1b55,0x2b38,0xd0,0x2e6a,0x1755,0x6bc,0x2724,0x3ba,0x222e,0x2c5c,0x2da5,0x213c,0x10fe,0x169a,0x15
 
52,0x5d3,0x300,0x1b5d,0x1342,0x2004,0x256f,0x2039,0x667,0x23b5,0x1123,0xdb,0x2da0,0xe1e,0x2f54,0x2767,0x154a,0x40a,0x11d3,0x2821,0xc09,0x974,0x694,0xfbf,0x27ba,0x132,0x83f,0x2d06,0x10e,0x183f,0x29ae,0x28c3,0x2dc9,0x1144,0x2c70,0x2a4a,0xf3c,0x1e32,0x1171,0x1e43,0xdd4,0x2ddf,0x28d2,0xfac,0x3c4,0x2f19,0x10a6,0x2f7,0xe1d,0x828,0x138f,0x1332,0xfab,0xcf6,0x13f8,0x24a0,0x112d,0x2717,0x6e7,0x1044,0x36e,0xfe8,0x6a,0xba7,0x1d69,0x29ec,0x23b2,0xaee,0x16df,0x1068,0x1a7e,0x253f,0x24c,0xb33,0x2683,0x15ce,0x1ad3,0x1a36,0xc96,0xaea,0x260a,0xce,0x28b1,0xe4f,0x2b11,0x5f8,0x1fc4,0xe77,0x2366,0x11f9,0x153c,0x24eb,0x20cd,0x1398,0x22,0x2b97,0x249b,0x8eb,0x12b2,0x2fe3,0x29c1,0x1b00,0x2663,0xeaa,0x2e06,0xe0,0x1569,0x10f5,0x284e,0xa38,0x201d,0x1c53,0x1681,0x1f6f,0x2f95,0x2fe8,0xacb,0x1680,0x17fd,0x2c39,0x165a,0x10bb,0x29d8,0x2622,0x1196,0x884,0x2a79,0x140e,0x2d80,0x6fa,0x11b2,0x26c4,0x355,0x1054,0x29e9,0x23ed,0xbe3,0x24fa,0x1fb3,0x10ac,0x2919,0x2584,0x10a4,0xe85,0x650,0x1893,0x1dc1,0xd8e,0x12dc,0x2d42,0x284
 
d,0xfff,0x250f,0xacd,0x13c3,0x6cc,0x1a79,0x1221,0x2614,0x270a,0x1ea,0x155,0x2818,0x222c,0x2e5b,0x25d8,0x1dbf,0x191c,0xb0f,0xdac,0x1082,0x12ef,0x11b6,0xfa8,0x2b72,0x159d,0x209e,0x31b,0x2c7c,0x14f7,0xe09,0x1bb2,0x1ec7,0x2404,0x20ae,0x6ad,0xed6,0x2b70,0x1c7b,0x18d1,0x2732,0x12da,0xd56,0x5c1,0x1648,0x18b7,0x1605,0x1bc4,0x280,0x2ece,0xc,0x1aae,0x1c4,0x1cdb,0x22d6,0x21d8,0x257c,0x51f,0x211b,0xff,0x2ee0,0x2585,0xe1,0x2c35,0x26db,0x2971,0x2208,0x17e1,0x21be,0x135e,0x28d6,0x2891,0x1689,0x2138,0xb86,0x2e3a,0x1204,0x2d10,0x2324,0xf3f,0x2508,0x33d,0xcb2,0x292a,0xe27,0x2e64,0x29f8,0x2d46,0x9b7,0x20eb,0x1b7c,0x9eb,0x2b2a,0x58c,0x27d0,0x121b,0x272e,0x29f6,0x2dbd,0x2697,0x2aac,0xd6f,0x1c67,0x2c5b,0x108d,0x363,0x249d,0x2d5e,0x2fd,0x2cb2,0x1f8f,0x20a4,0xa19,0x2ac9,0x19b1,0x1581,0x17a2,0x29eb,0x1b72,0x13b0,0xee4,0xa8f,0x2315,0x5e6,0x951,0x2e29,0xdad,0x1f2b,0x224e,0x37f,0x1a72,0xa91,0x1407,0x2df9,0x3ad,0x23f7,0x1a24,0x1d2a,0x234b,0x1df3,0x1143,0x7ff,0x1a6d,0x2774,0x2690,0x2ab5,0x586,0x2781,0x2009,0x2fd
 
d,0x2881,0x399,0x2fb6,0x144,0x137f,0xfa0,0x2e4c,0x1c7f,0x2fac,0xb09,0x1264,0x127b,0x198c,0x2b40,0x230,0x1cf4,0x180b,0xb58,0x144a,0x2aec,0xfb,0x2602,0x14ee,0x783,0x1098,0x23d8,0x203,0xe9,0x108a,0x14b8,0xeec,0xc58,0x1248,0x243c,0x28aa,0x6bf,0x27c4,0x276e,0x19b8,0x1d11,0x2e16,0x472,0x1464,0x24b9,0x662,0x1097,0x2067,0x20d6,0x171c,0x4,0x682,0x17bb,0x1186,0x4f2,0x3ff,0x2a43,0x1dc7,0x1ae5,0x8cc,0x2e7c,0x2ef8,0x2ae0,0x2904,0xed4,0x6c5,0x14ae,0xb72,0x11c3,0x337,0x2da3,0x2916,0x6d8,0x1cf9,0x10ee,0x1800,0x1ae4,0xa0d,0x101b,0x1a8d,0x2e98,0x24cd,0x813,0x1aa4,0x9b9,0x680,0x2349,0x24d1,0x20f8,0xe31,0x249f,0x216b,0x12d9,0x1d21,0x19db,0x191a,0x1dd0,0x5df,0x55c,0x2b86,0x213,0xe9e,0x1ef1,0x268a,0x1d5e,0x1e20,0x28c1,0x1379,0x249,0x19de,0x18b,0x1e41,0x2a1e,0x2612,0x297,0x2e96,0x2102,0x46,0x1b9f,0x1a4d,0x2050,0x1b32,0x568,0x11f7,0x1829,0x870,0x1f4,0x1dca,0x990,0x1df6,0x2b62,0x13ec,0x9f2,0x1260,0x2997,0x1412,0x1e6d,0x1694,0x11ac,0x2d8b,0x276f,0x26f5,0x233e,0x2b44,0x2f5a,0x2d37,0x2cb1,0xc75,0x98d,0x1d56,0x
 
7ae,0x10e6,0x113f,0x17b8,0xad3,0x737,0x221e,0x1b70,0x1f3e,0x2966,0x18b2,0x4fa,0x2044,0x1312,0x154e,0x2029,0x700,0x1b45,0x27a6,0x226a,0x21bf,0x58d,0x2f11,0x2e02,0x17fc,0x4d2,0x1757,0xcb1,0x2ef1,0x2582,0x1276,0x881,0x2fc0,0x104a,0x670,0x274f,0x2b53,0x19dd,0x752,0x1663,0xcbd,0x2b2b,0x2fc6,0x13b6,0x21e6,0x15f6,0x126b,0x2637,0x1cd9,0x2f50,0xe82,0x5b0,0x24e0,0x1350,0x2f24,0x21f7,0x1a16,0x2f3e,0x167e,0x1f7d,0x28a0,0x16f0,0xe33,0x53b,0x28c5,0x1500,0x2f88,0x26cc,0x2018,0x1604,0x218b,0x2cd1,0x9ee,0x17f3,0x5fd,0x1f5a,0x2d0,0x2b46,0x23cc,0x503,0x1c46,0x1cc3,0x28e2,0x243e,0x122b,0x2e0c,0xe37,0x2611,0x85e,0x9b8,0x1b24,0x762,0x19b6,0x3bc,0x2d50,0x2079,0x18da,0x170a,0x800,0xaa2,0x135a,0x1a15,0x13d1,0xca,0x2113,0x2db9,0xdb2,0x1a5c,0x29a9,0x1488,0x14c1,0x2c9,0x917,0x28e7,0x265c,0xdab,0x2ab9,0x2bc6,0x105b,0x1839,0x219c,0x50,0x11da,0x1802,0xf56,0x2e6,0x2190,0xddb,0x56e,0x9d9,0x1c81,0x1016,0x12d6,0x296f,0x14b4,0x1014,0x1e64,0x1d90,0x89f,0x2bc2,0x2777,0x2819,0x1c65,0x1a41,0x5a2,0x2cd2,0x427,0xd71,0x29c8,
 
0x1e58,0x53f,0x7c5,0x1dcd,0x4a1,0x1268,0x2597,0x2926,0xee,0x111b,0x1038,0xe6c,0x22dc,0x2f2f,0x441,0x2cfd,0x1cb0,0x6a4,0x2224,0x620,0x5dc,0x16b1,0x2a1d,0x1787,0x20c7,0x641,0xd84,0x1c05,0x2d0d,0x2f52,0x1b8c,0xd7d,0x17e8,0x1589,0xc73,0x151b,0x4e2,0x1ae9,0x1b18,0xb9b,0x949,0x2c60,0x1e7a,0xd5,0x1bdc,0x1f57,0x1753,0x124a,0x559,0xb76,0x2334,0x12d1,0x1de1,0x14b2,0x2faa,0x1697,0x147a,0x5a1,0x2c30,0x1c02,0x1043,0x2ee1,0x2402,0x1cc8,0x2a16,0xff7,0x1364,0x1b9a,0x2a53,0x2f94,0x294c,0x1ee5,0x1a87,0x2141,0xd66,0x953,0x28a3,0x2f30,0x2477,0x18e3,0x1035,0x1fc1,0x1d68,0x2fb3,0x138c,0x2487,0x1bf8,0xd96,0x1018,0x748,0x244e,0x15bd,0x175e,0x2be,0x23d,0x1da,0x176d,0xc17,0x24be,0x2ebb,0x7d8,0x100a,0x759,0x1db4,0x2259,0x23f4,0x2d59,0x2847,0xbf5,0x1cfe,0xa20,0x258,0x1180,0x279c,0x54,0x2abf,0xc5c,0x9f9,0x3d5,0x2ce4,0x165f,0x23d9,0x27b9,0x6f9,0x281a,0x169e,0x627,0x156d,0x1ff8,0x211,0x2e34,0x1724,0x2c2e,0x2790,0x2dd5,0x2bf2,0xdbc,0x2884,0x20a9,0x2390,0x1e1a,0x1b6a,0x5f7,0xab7,0x1333,0x16ab,0x28dd,0x20,0x30f,0x24
 
b6,0x5c2,0x1ce4,0x1400,0x2669,0x60,0x156c,0xe20,0x26d4,0x26ab,0x1ebb,0x223d,0x5b4,0x2025,0x1e1c,0xaae,0x2e08,0x6cd,0x1677,0x13d9,0x17b5,0x1046,0x1d8c,0x14eb,0x18d8,0x1ce5,0x2478,0x16ae,0xb79,0x23d4,0x684,0x156b,0x567,0x1a,0x29ce,0x83a,0x19e8,0x58e,0x294a,0x1136,0x2319,0x2fba,0x1a29,0x1d,0x1879,0x291b,0x19f6,0x2c2f,0x21c9,0x19bb,0xbbc,0x26f9,0xc22,0x708,0x11a1,0x18d3,0x7f8,0x28f8,0x2427,0x1deb,0xaed,0x26aa,0x2482,0x203b,0x2f05,0x2b82,0x192f,0x2df4,0x8dc,0x2877,0xd5e,0x240e,0x775,0x2dae,0x1d3e,0x20ba,0x215b,0x22d1,0xeba,0xf50,0xaa8,0x184a,0x1f67,0x2e04,0xc6e,0x6dd,0x1a09,0x27f,0x494,0x1426,0xae3,0xe15,0x65f,0x13c4,0x105,0x872,0x2667,0x1ff6,0xd9f,0x2ca1,0x2f39,0x2657,0x23fd,0x2405,0xb73,0x2294,0x1f1e,0x2eba,0x110a,0x2cae,0x141f,0x22cd,0x25d6,0x11c1,0x1c,0x2d8e,0x161a,0x1aa8,0x229e,0x1bf9,0x7cf,0x106d,0x2c40,0xd93,0x255e,0x28c2,0xc1a,0x2f17,0x7ca,0x2f63,0xbf};
+const sign16 iroots[]= 
{0x2ac8,0x452,0x297c,0x666,0xb4c,0x2b8,0x1a74,0xfd,0x1a47,0x1d08,0x2959,0x2c36,0x2db4,0x56c,0x254e,0x1125,0x2f3d,0x13bc,0x172c,0x2c6b,0x32a,0x1745,0x18bd,0x8f1,0x1633,0x2dfa,0xfdd,0x23e3,0x241b,0x13a5,0x578,0x17a0,0xa9,0x104b,0x1335,0x24e4,0x28de,0x5a7,0x368,0x2d70,0x13cd,0x2f9,0xff5,0x1e88,0x9c5,0x2ff7,0x900,0xdeb,0x1434,0x15fe,0x156a,0x24d3,0x28ed,0x2c4f,0x688,0xaef,0x2353,0x1045,0x2bcf,0x23a4,0x270,0x4c5,0x21fe,0xe5b,0xfbb,0x1f79,0x6e4,0xe68,0x2078,0x1160,0x1387,0x1e98,0x22f5,0x13e,0x283a,0x123f,0x149c,0x2eca,0xb14,0xf37,0xdde,0xbe7,0x386,0x1abe,0xa4a,0x49,0x14b5,0x2f36,0x8e5,0x1f1,0x2a57,0x1789,0x2f01,0x91f,0xaac,0x266c,0x2b65,0x2f4b,0xa30,0x2a17,0x265,0x253a,0xfb3,0x2142,0x20be,0x25c2,0x121c,0x2d97,0x2131,0x1e19,0x1a11,0x514,0x22c3,0x66,0xdcf,0x1540,0x1d41,0xf02,0x815,0x5a,0x18e8,0x1159,0x103a,0x2d23,0x2a10,0x2d61,0x1327,0x403,0x25c9,0x7b3,0x1f0c,0x1a98,0x2f21,0x1fb,0x2157,0x99e,0x1501,0x640,0x1e,0x1d4f,0x2716,0xb66,0x46a,0x2fdf,0x1c69,0xf34,0xb16,0x1ac5,
 
0x1e08,0xc9b,0x218a,0x103d,0x2a09,0x4f0,0x21b2,0x750,0x2f33,0x9f7,0x2517,0x236b,0x15cb,0x152e,0x1a33,0x97e,0x24ce,0x2db5,0xac2,0x1583,0x1f99,0x1922,0x2513,0xc4f,0x615,0x1298,0x245a,0x2f97,0x2019,0x2c93,0x1fbd,0x291a,0x8ea,0x1ed4,0xb61,0x1c09,0x230b,0x2056,0x1ccf,0x1c72,0x27d9,0x21e4,0x2d0a,0x1f5b,0xe8,0x2c3d,0x2055,0x72f,0x222,0x222d,0x11be,0x1e90,0x11cf,0x20c5,0x5b7,0x391,0x1ebd,0x238,0x73e,0x653,0x17c2,0x2ef3,0x2fb,0x27c2,0x2ecf,0x847,0x2042,0x296d,0x268d,0x23f8,0x7e0,0x1e2e,0x2bf7,0x1ab7,0x89a,0xad,0x21e3,0x261,0x2f26,0x1ede,0xc4c,0x299a,0xfc8,0xa92,0xffd,0x1cbf,0x14a4,0x2d01,0x2a2e,0x1aaf,0x1967,0x1f03,0xec5,0x25c,0x3a5,0xdd3,0x2c47,0x8dd,0x2945,0x18ac,0x197,0x2f31,0x4c9,0x14ac,0x2be2,0x166,0x43a,0xa94,0x1b53,0x293c,0x212d,0x6fd,0x521,0x109,0x185,0x2735,0x151c,0x123a,0x5be,0x2c02,0x2b0f,0x1e7b,0x1846,0x297f,0x2ffd,0x18e5,0xf2b,0xf9a,0x1f6a,0x299f,0xb48,0x1b9d,0x2b8f,0x1eb,0x12f0,0x1649,0x893,0x83d,0x2942,0x757,0xbc5,0x1db9,0x23a9,0x2115,0x1b49,0x1f77,0x2f18,0x2dfe,0xc29,0x1f69,0
 
x287e,0x1b13,0x9ff,0x2f06,0x515,0x1bb7,0x24a9,0x17f6,0x130d,0x2dd1,0x4c1,0x1675,0x1d86,0x1d9d,0x24f8,0x55,0x1382,0x1b5,0x2061,0x1c82,0x2ebd,0x4b,0x2c68,0x780,0x24,0xff8,0x880,0x2a7b,0x54c,0x971,0x88d,0x1594,0x2802,0x1ebe,0x120e,0xcb6,0x12d7,0x15dd,0xc0a,0x2c54,0x208,0x1bfa,0x2570,0x158f,0x2c82,0xdb3,0x10d6,0x2254,0x1d8,0x26b0,0x2a1b,0xcec,0x2572,0x211d,0x1c51,0x148f,0x616,0x185f,0x1a80,0x1650,0x538,0x25e8,0xf5d,0x1072,0x34f,0x2d04,0x2a3,0xb64,0x2c9e,0x1f74,0x3a6,0x139a,0x2292,0x555,0x96a,0x244,0x60b,0x8d3,0x1de6,0x831,0x2a75,0x4d7,0x2616,0x1485,0xf16,0x264a,0x2bb,0x609,0x19d,0x21da,0x6d7,0x234f,0x2cc4,0xaf9,0x20c2,0xcdd,0x2f1,0x1dfd,0x1c7,0x247b,0xec9,0x1978,0x770,0x72b,0x1ca3,0xe43,0x1820,0xdf9,0x690,0x926,0x3cc,0x2f20,0xa7c,0x121,0x2f02,0xee6,0x2ae2,0xa85,0xe29,0xd2b,0x1326,0x2e3d,0x1553,0x2ff5,0x133,0x2d81,0x143d,0x19fc,0x174a,0x19b9,0x2a40,0x22ab,0x1d27,0x8cf,0x1730,0x1386,0x491,0x212b,0x2954,0xf53,0xbfd,0x113a,0x144f,0x21f8,0x1b0a,0x385,0x2ce6,0xf63,0x1a64,0x48f,0x2059,0x1e4b,0
 
x1d12,0x1f7f,0x2255,0x24f2,0x16e5,0x1242,0xa29,0x1a6,0xdd5,0x7e9,0x2eac,0x2e17,0x8f7,0x9ed,0x1de0,0x1588,0x2935,0x1c3e,0x2534,0xaf2,0x2002,0x7b4,0x2bf,0x1d25,0x2273,0x1240,0x176e,0x29b1,0x217c,0x1f5d,0xa7d,0x6e8,0x1f55,0x104e,0xb07,0x241e,0xc14,0x618,0x1fad,0x2cac,0x93d,0x1e4f,0x2907,0x281,0x1bf3,0x588,0x277d,0x1e6b,0x9df,0x629,0x1f46,0x19a7,0x3c8,0x1804,0x1981,0x2536,0x19,0x6c,0x1092,0x1980,0x13ae,0xfe4,0x2f42,0x9e,0x2837,0xea,0x23e7,0x73f,0xaa3,0x226e,0x3c1,0x1f94,0x2832,0x1408,0xd63,0x1559,0x19e7,0x273,0x2fe5,0x1e40,0xa2b,0xd34,0x1be2,0x353,0x1ef7,0x147,0x10e3,0xd6d,0x248e,0xbfc,0xc04,0x9aa,0xc8,0x360,0x2262,0x100b,0x99a,0x278f,0x2efc,0x1c3d,0x29a2,0x21ec,0x251e,0x1bdb,0x2b6d,0x2d82,0x15f8,0x2924,0x2393,0x1fd,0x109a,0x17b7,0x2559,0x20b1,0x2147,0xd30,0xea6,0xf47,0x12c3,0x253,0x288c,0xbf3,0x22a3,0x78a,0x2725,0x20d,0x16d2,0x47f,0xfc,0xfc6,0xb7f,0x957,0x2514,0x1216,0xbda,0x709,0x2809,0x172e,0x1e60,0x28f9,0x23df,0x908,0x2445,0x1646,0xe38,0x3d2,0x160b,0x6e6,0x1788,0x2fe4,0x15d8,0x47,0x
 
ce8,0x1ecb,0x6b7,0x2a73,0x1619,0x27c7,0x633,0x2fe7,0x2a9a,0x1a96,0x297d,0xc2d,0x2488,0x1953,0xb89,0x131c,0x1729,0x1b16,0x1275,0x1fbb,0x184c,0x1c28,0x198a,0x2934,0x1f9,0x2553,0x11e5,0xfdc,0x2a4d,0xdc4,0x1146,0x956,0x92d,0x21e1,0x1a95,0x2fa1,0x998,0x1c01,0x131d,0x2a3f,0xb4b,0x2cf2,0x2fe1,0x724,0x1956,0x1cce,0x254a,0x2a0a,0x1497,0x11e7,0xc71,0xf58,0x77d,0x2245,0x40f,0x22c,0x871,0x3d3,0x18dd,0x1cd,0x2df0,0x1009,0x1a94,0x29da,0x1963,0x7e7,0x2908,0x848,0xc28,0x19a2,0x31d,0x2c2c,0x2608,0x23a5,0x542,0x2fad,0x865,0x1e81,0x2da9,0x25e1,0x1303,0x240c,0x7ba,0x2a8,0xc0d,0xda8,0x124d,0x28a8,0x1ff7,0x2829,0x146,0xb43,0x23ea,0x1894,0x2e27,0x2dc4,0x2d43,0x18a3,0x1a44,0xbb3,0x28b9,0x1fe9,0x226b,0x1409,0xb7a,0x1c75,0x4e,0x1299,0x1040,0x1fcc,0x171e,0xb8a,0xd1,0x75e,0x26ae,0x229b,0xec0,0x157a,0x111c,0x6b5,0x6d,0x5ae,0x1467,0x1c9d,0x200a,0x5eb,0x1339,0xbff,0x120,0x1fbe,0x13ff,0x3d1,0x2a60,0x1b87,0x196a,0x57,0x1b4f,0x1220,0x1d30,0xccd,0x248b,0x2aa8,0x1db7,0x18ae,0x10aa,0x1425,0x2f2c,0x1187,0x3a1,0x26b8,0x2
 
466,0x14e9,0x1518,0x2b1f,0x1ae6,0x238e,0x1a78,0x1819,0x2284,0x1475,0xaf,0x2f4,0x13fc,0x227d,0x29c0,0xf3a,0x187a,0x5e4,0x1950,0x2a25,0x29e1,0xddd,0x295d,0x1351,0x304,0x2bc0,0xd2,0xd25,0x2195,0x1fc9,0x1ee6,0x2f13,0x6db,0xa6a,0x1d99,0x2b60,0x1234,0x283c,0x2ac2,0x11a9,0x639,0x2290,0x2bda,0x32f,0x2a5f,0x15c0,0x139c,0x7e8,0x88a,0x43f,0x2762,0x1271,0x119d,0x1fed,0x1b4d,0x692,0x1d2b,0x1feb,0x1380,0x2628,0x2a93,0x2226,0xe71,0x2d1b,0x20ab,0x17ff,0x1e27,0x2fb1,0xe65,0x17c8,0x1fa6,0x43b,0x548,0x2256,0x9a5,0x71a,0x26ea,0x2d38,0x1b40,0x1b79,0x658,0x15a5,0x224f,0x248,0xeee,0x2f37,0x1c30,0x15ec,0x1ca7,0x255f,0x2801,0x18f7,0x1727,0xf88,0x2b1,0x2c45,0x164b,0x289f,0x14dd,0x2649,0x27a3,0x9f0,0x21ca,0x1f5,0x1dd6,0xbc3,0x71f,0x133e,0x13bb,0x2afe,0xc35,0x4bb,0x2d31,0x10a7,0x2a04,0x180e,0x2613,0x330,0xe76,0x19fd,0xfe9,0x935,0x79,0x1b01,0x73c,0x2ac6,0x21ce,0x1911,0x761,0x1084,0x1983,0xc3,0x15eb,0xe0a,0xdd,0x1cb1,0xb21,0x2a51,0x217f,0xb1,0x1328,0x9ca,0x1d96,0x1a0b,0xe1b,0x1c4b,0x3b,0x4d6,0x2344,0x199e,0x28af
 
,0x1624,0x4ae,0x8b2,0x2991,0x1fb7,0x41,0x2780,0x1d8b,0xa7f,0x110,0x2350,0x18aa,0x2b2f,0x1805,0x1ff,0xf0,0x2a74,0xe42,0xd97,0x85b,0x14bc,0x2901,0xfd8,0x1ab3,0x1cef,0xfbd,0x2b07,0x174f,0x69b,0x10c3,0x1491,0xde3,0x28ca,0x252e,0x1849,0x1ec2,0x1f1b,0x2853,0x12ab,0x2674,0x238c,0x350,0x2ca,0xa7,0x4bd,0xcc3,0x90c,0x892,0x276,0x1e55,0x196d,0x1194,0x1bef,0x66a,0x1da1,0x260f,0x1c15,0x49f,0x120b,0x2671,0x1237,0x2e0d,0x2791,0x17d8,0x1e0a,0x2a99,0x14cf,0xfb1,0x15b4,0x1462,0x2fbb,0xeff,0x16b,0x2d6a,0x9ef,0x5e3,0x11c0,0x2e76,0x1623,0x2db8,0x1c88,0x740,0x11e1,0x12a3,0x977,0x1110,0x2163,0x2dee,0x47b,0x2aa5,0x2a22,0x1231,0x16e7,0x1626,0x12e0,0x1d28,0xe96,0xb62,0x21d0,0xf09,0xb30,0xcb8,0x2981,0x2648,0x155d,0x27ee,0xb34,0x169,0x1574,0x1fe6,0x25f4,0x151d,0x1801,0x1f13,0x1308,0x2929,0x6eb,0x25e,0x2cca,0x1e3e,0x248f};
+const sign16 inv= 0xeab;
+const sign16 invpr= 0x2c2a;
+
+#define DEGREE (1<<RLWE_LGN)
+#define WL 32
+
+#define round(a,b) (((a)+((b)/2))/(b))
+
+/* constant time absolute vaue */
+static sign32 nabs(sign32 x)
+{
+       sign32 mask=(x>>31);
+       return (x+mask)^mask;
+}
+
+/* Montgomery stuff */
+
+static sign32 redc(unsign64 T)
+{
+       unsign32 m=(unsign32)T*(unsign32)RLWE_ND;
+       return ((unsign64)m*RLWE_PRIME+T)>>WL;
+}
+
+static sign32 nres(unsign32 x)
+{
+       return redc((unsign64)x*RLWE_R2MODP);
+}
+
+static sign32 modmul(unsign32 a,unsign32 b)
+{
+       return redc((unsign64)a*b);
+}
+
+/* NTT code */
+/* Cooley-Tukey NTT */
+
+static void ntt(sign32 *x)
+{
+       int m,i,j,k,t=DEGREE/2;
+       sign32 S,U,V,W,q=RLWE_PRIME;
+
+/* Convert to Montgomery form */
+       for (j=0;j<DEGREE;j++)
+               x[j]=nres(x[j]);
+
+       m=1;
+       while (m<DEGREE)
+       {
+               k=0;
+               for (i=0;i<m;i++)
+               {
+                       S=roots[m+i];
+                       for (j=k;j<k+t;j++)
+                       {
+                               U=x[j];   
+                               V=modmul(x[j+t],S);
+                               x[j]=U+V;
+                               x[j+t]=U+2*q-V;
+                       }
+                       k+=2*t;
+               }
+               t/=2;
+               m*=2;
+       }
+}
+
+/* Gentleman-Sande INTT */
+
+static void intt(sign32 *x)
+{
+       int m,i,j,k,t=1;
+       sign32 S,U,V,W,q=RLWE_PRIME;
+
+       m=DEGREE/2;
+       while (m>1)
+       {
+               k=0;
+               for (i=0;i<m;i++)
+               {
+                       S=iroots[m+i];
+                       for (j=k;j<k+t;j++)
+                       {       
+                               U=x[j]; 
+                               V=x[j+t];
+                               x[j]=U+V;       
+                               W=U+DEGREE*q-V; 
+                               x[j+t]=modmul(W,S); 
+                       }
+                       k+=2*t;
+               }
+               t*=2;
+               m/=2;
+       }
+
+/* Last iteration merged with n^-1 */
+
+       t=DEGREE/2;
+       for (j=0;j<t;j++)
+       {
+               U=x[j];
+               V=x[j+t];
+               W=U+DEGREE*q-V; 
+               x[j+t]=modmul(W,(sign32)invpr); 
+               x[j]=modmul(U+V,(sign32)inv);
+       }
+/* convert back from Montgomery to "normal" form */
+       for (j=0;j<DEGREE;j++)
+       {
+               x[j]=redc(x[j]);  
+               x[j]-=q;
+               x[j]+=(x[j]>>(WL-1))&q;
+       } 
+}
+
+/* See https://eprint.iacr.org/2016/1157.pdf */ 
+
+static void NHSEncode(byte *key,sign32 *poly)
+{
+       int i,j,b,k,kj,q2;
+
+       q2=RLWE_PRIME/2;
+       for (i=j=0;i<256;)
+       {
+               kj=key[j++];
+               for (k=0;k<8;k++)
+               {
+                       b=kj&1;
+                       poly[i]=b*q2;
+                       poly[i+256]=b*q2;
+                       poly[i+512]=b*q2;
+                       poly[i+768]=b*q2;
+                       kj>>=1;
+                       i++;
+               }
+       }               
+}
+
+static void NHSDecode(sign32 *poly,byte *key)
+{
+       int i,j,k;
+       sign32 b,t,q2;
+       q2=RLWE_PRIME/2;
+       for (i=0;i<32;i++)
+               key[i]=0;
+
+       for (i=j=0;i<256;)
+       {
+               for (k=0;k<8;k++)
+               {
+                       
t=nabs(poly[i]-q2)+nabs(poly[i+256]-q2)+nabs(poly[i+512]-q2)+nabs(poly[i+768]-q2);
+
+                       b=t-RLWE_PRIME;
+                       b=(b>>31)&1;
+                       key[j]=(key[j]>>1)+(b<<7);
+                       i++;
+               }
+               j++;
+       }
+}
+
+/* convert 32-byte seed to random polynomial */
+
+static void parse(byte *seed,sign32 *poly)
+{
+       int i,j;
+       sign32 n;
+       byte hash[4*DEGREE];
+       sha3 sh;
+
+       SHA3_init(&sh,SHAKE128);
+       for (i=0;i<32;i++)
+               SHA3_process(&sh,seed[i]);
+       SHA3_shake(&sh,(char *)hash,4*DEGREE);
+
+       for (i=j=0;i<DEGREE;i++)
+       {
+
+               n=hash[j]&0x7f; n<<=8;
+               n+=hash[j+1]; n<<=8;
+               n+=hash[j+2]; n<<=8;
+               n+=hash[j+3]; j+=4;
+               poly[i]=nres(n);
+       }
+} 
+
+/* Compress 14 bits polynomial coefficients into byte array */
+/* 7 bytes is 3x14 */
+
+static void NHSpack(sign32 *poly,byte *array)
+{
+       int i,j;
+       sign32 a,b,c,d;
+
+       for (i=j=0;i<DEGREE; )
+       {
+               a=poly[i++]; b=poly[i++]; c=poly[i++]; d=poly[i++];
+               array[j++]=(byte)(a&0xff);
+               array[j++]=(byte)(((a>>8)|(b<<6))&0xff);
+               array[j++]=(byte)((b>>2)&0xff);
+               array[j++]=(byte)(((b>>10)|(c<<4))&0xff);
+               array[j++]=(byte)((c>>4)&0xff);
+               array[j++]=(byte)(((c>>12)|(d<<2))&0xff);
+               array[j++]=(byte)(d>>6);
+       }
+}
+
+static void NHSunpack(byte *array,sign32 *poly)
+{
+       int i,j;
+       sign32 a,b,c,d,e,f,g;
+
+       for (i=j=0;i<DEGREE; )
+       {
+               a=((sign32)array[j++])&0xff; b=((sign32)array[j++])&0xff; 
c=((sign32)array[j++])&0xff; d=((sign32)array[j++])&0xff; 
e=((sign32)array[j++])&0xff; f=((sign32)array[j++])&0xff; 
g=((sign32)array[j++])&0xff;
+               poly[i++]=a|((b&0x3f)<<8);
+               poly[i++]=(b>>6)|(c<<2)|((d&0xf)<<10);
+               poly[i++]=(d>>4)|(e<<4)|((f&3)<<12);
+               poly[i++]=(f>>2)|(g<<6);
+       }
+}
+
+/* See https://eprint.iacr.org/2016/1157.pdf */ 
+
+static void NHSCompress(sign32 *poly,byte *array)
+{
+       int i,j,k,b;
+       unsign32 col=0;
+
+       for (i=j=0;i<DEGREE;)
+       {
+               for (k=0;k<8;k++)
+               {
+                       b=round((poly[i]*8),RLWE_PRIME)&7; 
+                       col=(col<<3)+b;
+                       i++;
+               }
+               array[j]=col&0xff;
+               array[j+1]=(col>>8)&0xff;
+               array[j+2]=(col>>16)&0xff;
+               j+=3; col=0;
+       }
+}
+
+static void NHSDecompress(byte *array,sign32 *poly)
+{
+       int i,j,k,b;
+       unsign32 col=0;
+
+       for (i=j=0;i<DEGREE;)
+       {
+               col=array[j+2];
+               col=(col<<8)+array[j+1];
+               col=(col<<8)+array[j];
+               j+=3;
+               for (k=0;k<8;k++)
+               {
+                       b=(col&0xe00000)>>21; col<<=3;
+                       poly[i]=round((b*RLWE_PRIME),8);
+                       i++;
+               }
+       }
+}
+
+/* generate centered binomial distribution */ 
+
+static void NHSError(csprng *RNG,sign32 *poly)
+{
+       int i,j;
+       sign32 n1,n2,r;
+       for (i=0;i<DEGREE;i++)
+       {
+               n1=RAND_byte(RNG)+(RAND_byte(RNG)<<8);
+               n2=RAND_byte(RNG)+(RAND_byte(RNG)<<8);
+               r=0;
+               for (j=0;j<16;j++)
+               {
+                       r+=(n1&1)-(n2&1);
+                       n1>>=1; n2>>=1;
+               }
+               poly[i]=(r+RLWE_PRIME);
+       }
+}
+
+static void redc_it(sign32 *p)
+{
+       int i;
+       for (i=0;i<DEGREE;i++)
+               p[i]=redc(p[i]);
+}
+
+static void nres_it(sign32 *p)
+{
+       int i;
+       for (i=0;i<DEGREE;i++)
+               p[i]=nres(p[i]);
+}
+
+static void poly_mul(sign32 *p1,sign32 *p2,sign32 *p3)
+{
+       int i;
+       for (i=0;i<DEGREE;i++)
+               p1[i]=modmul(p2[i],p3[i]);
+}
+
+static void poly_add(sign32 *p1,sign32 *p2,sign32 *p3)
+{
+       int i;
+       for (i=0;i<DEGREE;i++)
+               p1[i]=(p2[i]+p3[i]);
+}
+
+static void poly_sub(sign32 *p1,sign32 *p2,sign32 *p3)
+{
+       int i;
+       for (i=0;i<DEGREE;i++)
+               p1[i]=(p2[i]+RLWE_PRIME-p3[i]);
+}
+
+/* reduces inputs < 2q */
+static void poly_soft_reduce(sign32 *poly)
+{
+       int i;
+       sign32 e;
+       for (i=0;i<DEGREE;i++)
+       {
+               e=poly[i]-RLWE_PRIME;
+               poly[i]=e+((e>>(WL-1))&RLWE_PRIME);
+       }
+}
+
+/* fully reduces modulo q */
+static void poly_hard_reduce(sign32 *poly)
+{
+       int i;
+       sign32 e;
+       for (i=0;i<DEGREE;i++)
+       {
+               e=modmul(poly[i],RLWE_ONE);
+               e=e-RLWE_PRIME;
+               poly[i]=e+((e>>(WL-1))&RLWE_PRIME);
+       }
+}
+
+/* API files */
+
+void NHS_SERVER_1(csprng *RNG,octet *SB,octet *S)
+{
+       int i;
+       byte seed[32],array[1792];
+       sign32 s[DEGREE],e[DEGREE],b[DEGREE];
+
+       for (i=0;i<32;i++)
+               seed[i]=RAND_byte(RNG);
+
+       parse(seed,b);
+       
+       NHSError(RNG,e);
+       NHSError(RNG,s);
+
+       ntt(s);
+       ntt(e);
+       poly_mul(b,b,s);
+       poly_add(b,b,e);
+       poly_hard_reduce(b);
+
+       redc_it(b);
+       NHSpack(b,array);
+
+       OCT_empty(SB);
+       OCT_jbytes(SB,(char *)seed,32);
+       OCT_jbytes(SB,(char *)array,1792);
+
+       poly_hard_reduce(s);
+
+       NHSpack(s,array);
+       OCT_empty(S);
+       OCT_jbytes(S,(char *)array,1792);
+
+}
+
+void NHS_CLIENT(csprng *RNG,octet *SB,octet *UC,octet *KEY)
+{
+       int i;
+       sha3 sh;
+       byte seed[32],array[1792],key[32],cc[384];
+       sign32 sd[DEGREE],ed[DEGREE],u[DEGREE],k[DEGREE],c[DEGREE];
+       NHSError(RNG,sd);
+       NHSError(RNG,ed);
+
+       ntt(sd);
+       ntt(ed);
+
+       for (i=0;i<32;i++)
+               seed[i]=SB->val[i];
+
+       for (i=0;i<1792;i++)
+               array[i]=SB->val[i+32];
+
+       parse(seed,u);
+
+       poly_mul(u,u,sd);
+       poly_add(u,u,ed);
+       poly_hard_reduce(u);
+
+       for (i=0;i<32;i++)
+               key[i]=RAND_byte(RNG);
+
+       SHA3_init(&sh,SHA3_HASH256);
+       for (i=0;i<32;i++)
+               SHA3_process(&sh,key[i]);
+       SHA3_hash(&sh,(char *)key);
+
+       NHSEncode(key,k);
+
+       NHSunpack(array,c);
+       nres_it(c);
+
+       poly_mul(c,c,sd);
+       intt(c);
+       NHSError(RNG,ed);
+       poly_add(c,c,ed);
+       poly_add(c,c,k);
+
+       NHSCompress(c,cc);
+
+       SHA3_init(&sh,SHA3_HASH256);
+       for (i=0;i<32;i++)
+               SHA3_process(&sh,key[i]);
+       SHA3_hash(&sh,(char *)key);
+
+       OCT_empty(KEY);
+       OCT_jbytes(KEY,(char *)key,32);
+
+       redc_it(u);
+       NHSpack(u,array);
+
+       OCT_empty(UC);
+       OCT_jbytes(UC,(char *)array,1792);
+       OCT_jbytes(UC,(char *)cc,384);
+}
+
+void NHS_SERVER_2(octet *S,octet *UC,octet *KEY)
+{
+       int i;
+       sha3 sh;
+       sign32 c[DEGREE],s[DEGREE],k[DEGREE];
+       byte array[1792],key[32],cc[384];
+
+       for (i=0;i<1792;i++)
+               array[i]=UC->val[i];
+
+       NHSunpack(array,k);
+       nres_it(k);
+
+       for (i=0;i<384;i++)
+               cc[i]=UC->val[i+1792];
+
+       NHSDecompress(cc,c);
+
+       for (i=0;i<1792;i++)
+               array[i]=S->val[i];
+
+       NHSunpack(array,s);
+
+       poly_mul(k,k,s);
+       intt(k);
+       poly_sub(k,c,k);
+       poly_soft_reduce(k);
+
+       NHSDecode(k,key);
+
+       SHA3_init(&sh,SHA3_HASH256);
+       for (i=0;i<32;i++)
+               SHA3_process(&sh,key[i]);
+       SHA3_hash(&sh,(char *)key);
+
+       OCT_empty(KEY);
+       OCT_jbytes(KEY,(char *)key,32);
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version3/c/newhope.h
----------------------------------------------------------------------
diff --git a/version3/c/newhope.h b/version3/c/newhope.h
new file mode 100644
index 0000000..8e18a9a
--- /dev/null
+++ b/version3/c/newhope.h
@@ -0,0 +1,51 @@
+/*
+       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.
+*/
+
+/* NewHope Simple API */
+
+#ifndef NHS_H
+#define NHS_H
+
+#include "amcl.h"
+
+/**    @brief NHS server first pass
+ *
+       @param RNG Random Number Generator handle
+       @param SB seed and polynomial B concatenated - output
+       @param S server secret - output
+       
+ */
+extern void NHS_SERVER_1(csprng *RNG,octet *SB,octet *S);
+/**    @brief NHS client pass
+ *
+       @param RNG Random Number Generator handle
+       @param SB seed and polynomial B concatenated - input
+       @param UC polynomial U and compressed polynomial c - output
+       @param KEY client key
+ */
+extern void NHS_CLIENT(csprng *RNG,octet *SB,octet *UC,octet *KEY);
+/**    @brief NHS server second pass
+ *
+       @param S server secret - input
+       @param UC polynomial U and compressed polynomial c - input
+       @param KEY server key
+ */
+extern void NHS_SERVER_2(octet *S,octet *UC,octet *KEY);
+
+#endif
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version3/c/oct.c
----------------------------------------------------------------------
diff --git a/version3/c/oct.c b/version3/c/oct.c
new file mode 100644
index 0000000..866c96c
--- /dev/null
+++ b/version3/c/oct.c
@@ -0,0 +1,401 @@
+/*
+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.
+*/
+
+/*** Basic Octet string maintainance routines  ***/
+/* SU=m, m is Stack Usage */
+
+#include <string.h>
+#include "amcl.h"
+
+/* Output an octet string (Debug Only) */
+
+/* SU= 16 */
+/* output octet */
+void OCT_output(octet *w)
+{
+    int i;
+    unsigned char ch;
+    for (i=0; i<w->len; i++)
+    {
+        ch=w->val[i];
+        printf("%02x",ch);
+    }
+    printf("\n");
+}
+
+/* SU= 16 */
+void OCT_output_string(octet *w)
+{
+    int i;
+    unsigned char ch;
+    for (i=0; i<w->len; i++)
+    {
+        ch=w->val[i];
+        printf("%c",ch);
+    }
+    /*  printf("\n"); */
+}
+
+/* Convert C string to octet format - truncates if no room  */
+void OCT_jstring(octet *y,char *s)
+{
+    int i,j;
+    i=y->len;
+    j=0;
+    while (s[j]!=0 && i<y->max)
+    {
+        y->val[i]=s[j];
+        y->len++;
+        i++;
+        j++;
+    }
+}
+
+/* compare 2 octet strings.
+ * If x==y return TRUE, else return FALSE */
+/* SU= 8 */
+int OCT_comp(octet *x,octet *y)
+{
+    int i;
+    if (x->len>y->len) return 0;
+    if (x->len<y->len) return 0;
+    for (i=0; i<x->len; i++)
+    {
+        if (x->val[i]!=y->val[i]) return 0;
+    }
+    return 1;
+}
+
+/* check are first n bytes the same (in constant time) */
+
+int OCT_ncomp(octet *x,octet *y,int n)
+{
+    int i,res=0;
+    if (n>y->len || n>x->len) return 0;
+    for (i=0; i<n; i++)
+    {
+        res|=(int)(x->val[i]^y->val[i]);
+    }
+    if (res==0) return 1;
+       return 0;
+}
+
+/* Shift octet to the left by n bytes. Leftmost bytes disappear  */
+void OCT_shl(octet *x,int n)
+{
+    int i;
+    if (n>=x->len)
+    {
+        x->len=0;
+        return;
+    }
+    x->len-=n;
+    for (i=0; i<x->len; i++)
+        x->val[i]=x->val[i+n];
+}
+
+/* Append binary string to octet - truncates if no room */
+/* SU= 12 */
+void OCT_jbytes(octet *y,char *b,int len)
+{
+    int i,j;
+    i=y->len;
+    for (j=0; j<len && i<y->max; j++)
+    {
+        y->val[i]=b[j];
+        y->len++;
+        i++;
+    }
+}
+
+/* Concatenates two octet strings */
+/* SU= 8 */
+void OCT_joctet(octet *y,octet *x)
+{
+    /* y=y || x */
+    int i,j;
+    if (x==NULL) return;
+
+    for (i=0; i<x->len; i++)
+    {
+        j=y->len+i;
+        if (j>=y->max)
+        {
+            y->len=y->max;
+            return;
+        }
+        y->val[j]=x->val[i];
+    }
+    y->len+=x->len;
+}
+
+/* Append byte to octet rep times */
+/* SU= 8 */
+void OCT_jbyte(octet *y,int ch,int rep)
+{
+    int i,j;
+    i=y->len;
+    for (j=0; j<rep && i<y->max; j++)
+    {
+        y->val[i]=ch;
+        y->len++;
+        i++;
+    }
+}
+
+/* XOR common bytes of x with y */
+/* SU= 8 */
+void OCT_xor(octet *y,octet *x)
+{
+    /* xor first x->len bytes of y */
+
+    int i;
+    for (i=0; i<x->len && i<y->len; i++)
+    {
+        y->val[i]^=x->val[i];
+    }
+}
+
+/* clear an octet */
+void OCT_empty(octet *w)
+{
+    w->len=0;
+}
+
+/* Kill an octet string - Zeroise it for security */
+void OCT_clear(octet *w)
+{
+    int i;
+    for (i=0; i<w->max; i++) w->val[i]=0;
+    w->len=0;
+}
+
+/* appends int x of length len bytes to OCTET string */
+/* SU= 8 */
+void OCT_jint(octet *y,int x,int len)
+{
+    int i,n;
+    n=y->len+len;
+    if (n>y->max || len<=0) return;
+    for (i=y->len; i<n; i++) y->val[i]=0;
+    y->len=n;
+
+    i=y->len;
+    while (x>0 && i>0)
+    {
+        i--;
+        y->val[i]=x%256;
+        x/=256;
+    }
+}
+
+/* Pad an octet to a given length */
+/* SU= 8 */
+int OCT_pad(octet *w,int n)
+{
+    int i,d;
+    if (w->len>n || n>w->max) return 0;
+    if (n==w->len) return 1;
+    d=n-w->len;
+    for (i=n-1; i>=d; i--)
+        w->val[i]=w->val[i-d];
+    for (i=d-1; i>=0; i--)
+        w->val[i]=0;
+    w->len=n;
+    return 1;
+}
+
+
+/* Convert an octet string to base64 string */
+/* SU= 56 */
+void OCT_tobase64(char *b,octet *w)
+{
+    int i,j,k,rem,last;
+    int c,ch[4];
+    unsigned char ptr[3];
+    rem=w->len%3;
+    j=k=0;
+    last=4;
+    while (j<w->len)
+    {
+        for (i=0; i<3; i++)
+        {
+            if (j<w->len) ptr[i]=w->val[j++];
+            else
+            {
+                ptr[i]=0;
+                last--;
+            }
+        }
+        ch[0]=(ptr[0]>>2)&0x3f;
+        ch[1]=((ptr[0]<<4)|(ptr[1]>>4))&0x3f;
+        ch[2]=((ptr[1]<<2)|(ptr[2]>>6))&0x3f;
+        ch[3]=ptr[2]&0x3f;
+        for (i=0; i<last; i++)
+        {
+            c=ch[i];
+            if (c<26) c+=65;
+            if (c>=26 && c<52) c+=71;
+            if (c>=52 && c<62) c-=4;
+            if (c==62) c='+';
+            if (c==63) c='/';
+            b[k++]=c;
+        }
+    }
+    if (rem>0) for (i=rem; i<3; i++) b[k++]='=';
+    b[k]='\0';  /* dangerous! */
+}
+
+/* SU= 56 */
+void OCT_frombase64(octet *w,char *b)
+{
+    int i,j,k,pads,len=(int)strlen(b);
+    int c,ch[4],ptr[3];
+    j=k=0;
+    while (j<len && k<w->max)
+    {
+        pads=0;
+        for (i=0; i<4; i++)
+        {
+            c=80+b[j++];
+            if (c<=112) continue; /* ignore white space */
+            if (c>144 && c<171) c-=145;
+            if (c>176 && c<203) c-=151;
+            if (c>127 && c<138) c-=76;
+            if (c==123) c=62;
+            if (c==127) c=63;
+            if (c==141)
+            {
+                pads++;    /* ignore pads '=' */
+                continue;
+            }
+            ch[i]=c;
+        }
+        ptr[0]=(ch[0]<<2)|(ch[1]>>4);
+        ptr[1]=(ch[1]<<4)|(ch[2]>>2);
+        ptr[2]=(ch[2]<<6)|ch[3];
+        for (i=0; i<3-pads && k<w->max; i++)
+        {
+            /* don't put in leading zeros */
+            w->val[k++]=ptr[i];
+        }
+    }
+    w->len=k;
+}
+
+/* copy an octet string - truncates if no room */
+/* SU= 16 */
+void OCT_copy(octet *y,octet *x)
+{
+    int i;
+    OCT_clear(y);
+    y->len=x->len;
+    if (y->len>y->max) y->len=y->max;
+
+    for (i=0; i<y->len; i++)
+        y->val[i]=x->val[i];
+}
+
+/* XOR m with all of x */
+void OCT_xorbyte(octet *x,int m)
+{
+    int i;
+    for (i=0; i<x->len; i++) x->val[i]^=m;
+}
+
+/* truncates x to n bytes and places the rest in y (if y is not NULL) */
+/* SU= 8 */
+void OCT_chop(octet *x,octet *y,int n)
+{
+    int i;
+    if (n>=x->len)
+    {
+        if (y!=NULL) y->len=0;
+        return;
+    }
+    if (y!=NULL) y->len=x->len-n;
+    x->len=n;
+
+    if (y!=NULL)
+    {
+        for (i=0; i<y->len && i<y->max; i++) y->val[i]=x->val[i+n];
+    }
+}
+
+/* set x to len random bytes */
+void OCT_rand(octet *x,csprng *RNG,int len)
+{
+    int i;
+    if (len>x->max) len=x->max;
+    x->len=len;
+
+    for (i=0; i<len; i++) x->val[i]=RAND_byte(RNG);
+}
+
+/* Convert an octet to a hex string */
+void OCT_toHex(octet *src,char *dst)
+{
+    int i;
+    unsigned char ch;
+    for (i=0; i<src->len; i++)
+    {
+        ch=src->val[i];
+        sprintf(&dst[i*2],"%02x", ch);
+    }
+}
+
+static int char2int(char input)
+{
+    if(input >= '0' && input <= '9')
+        return input - '0';
+    if(input >= 'A' && input <= 'F')
+        return input - 'A' + 10;
+    if(input >= 'a' && input <= 'f')
+        return input - 'a' + 10;
+    return 0;
+}
+
+/* Convert from a hex string */
+void OCT_fromHex(octet *dst,char *src)
+{
+    int i=0;
+    int j=0;
+    OCT_clear(dst);
+
+    while(src[j]!=0)
+    {
+        dst->val[i++] = char2int(src[j])*16 + char2int(src[j+1]);
+        j += 2;
+    }
+    dst->len=i;
+}
+
+
+/* Convert an octet to a string */
+void OCT_toStr(octet *src,char *dst)
+{
+    int i;
+    unsigned char ch;
+    for (i=0; i<src->len; i++)
+    {
+        ch=src->val[i];
+        sprintf(&dst[i],"%c", ch);
+    }
+}
+

Reply via email to