You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@milagro.apache.org by br...@apache.org on 2018/11/07 23:49:44 UTC

[07/51] [partial] incubator-milagro-crypto git commit: update code

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/70e3a3a3/version22/c/arch.h
----------------------------------------------------------------------
diff --git a/version22/c/arch.h b/version22/c/arch.h
new file mode 100644
index 0000000..21753bd
--- /dev/null
+++ b/version22/c/arch.h
@@ -0,0 +1,119 @@
+/*
+	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.
+*/
+
+/* Architecture definition header file */
+
+/**
+ * @file arch.h
+ * @author Mike Scott
+ * @date 23rd February 2016
+ * @brief Architecture Header File
+ *
+ * Specify Processor Architecture
+ *
+ */
+
+/* NOTE: There is only one user configurable section in this header - see below */
+
+#ifndef ARCH_H
+#define ARCH_H
+
+
+
+
+/*** START OF USER CONFIGURABLE SECTION - set architecture ***/
+
+#ifdef CMAKE
+#define CHUNK @AMCL_CHUNK@  /**< size of chunk in bits = wordlength of computer = 16, 32 or 64. Note not all curve options are supported on 16-bit processors - see rom.c */
+#else
+#define CHUNK 32		/**< size of chunk in bits = wordlength of computer = 16, 32 or 64. Note not all curve options are supported on 16-bit processors - see rom.c */
+#endif
+
+/*** END OF USER CONFIGURABLE SECTION ***/
+
+
+
+/* Create Integer types */
+/* Support for C99?  Note for GCC need to explicitly include -std=c99 in command line */
+
+#if __STDC_VERSION__ >= 199901L
+/* C99 code */
+#define C99
+#else
+/* Not C99 code */
+#endif
+
+#ifndef C99  /* You are on your own! These are for Microsoft C */
+#define sign32 __int32			/**< 32-bit signed integer */
+#define sign8 signed char		/**< 8-bit signed integer */
+#define unsign32 unsigned __int32 /**< 32-bit unsigned integer */
+#define unsign64 unsigned long long  /**< 64-bit unsigned integer */
+#else
+#include <stdint.h>
+#define sign8 int8_t			/**< 8-bit signed integer */
+#define sign32 int32_t			/**< 32-bit signed integer */
+#define unsign32 uint32_t		/**< 32-bit unsigned integer */
+#define unsign64 uint64_t		/**< 64-bit unsigned integer */
+#endif
+
+#define uchar unsigned char  /**<  Unsigned char */
+
+/* Don't mess with anything below this line unless you know what you are doing */
+/* This next is probably OK, but may need changing for non-C99-standard environments */
+
+/* This next is probably OK, but may need changing for non-C99-standard environments */
+
+#if CHUNK==16
+#ifndef C99
+#define chunk __int16		/**< C type corresponding to word length */
+#define dchunk __int32		/**< Always define double length chunk type if available */
+#else
+#define chunk int16_t		/**< C type corresponding to word length */
+#define dchunk int32_t		/**< Always define double length chunk type if available */
+#endif
+#endif
+
+#if CHUNK == 32
+#ifndef C99
+#define chunk __int32		/**< C type corresponding to word length */
+#define dchunk __int64		/**< Always define double length chunk type if available */
+#else
+#define chunk int32_t		/**< C type corresponding to word length */
+#define dchunk int64_t		/**< Always define double length chunk type if available */
+#endif
+#endif
+
+#if CHUNK == 64
+
+#ifndef C99
+#define chunk __int64		/**< C type corresponding to word length */
+/**< Note - no 128-bit type available    */
+#else
+#define chunk int64_t		/**< C type corresponding to word length */
+#ifdef __GNUC__
+#define dchunk __int128		/**< Always define double length chunk type if available - GCC supports 128 bit type  ??? */
+#endif
+#endif
+#endif
+
+#ifdef dchunk
+#define COMBA      /**< Use COMBA method for faster BN muls, sqrs and reductions */
+#endif
+
+#endif

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/70e3a3a3/version22/c/benchtest_ec.c
----------------------------------------------------------------------
diff --git a/version22/c/benchtest_ec.c b/version22/c/benchtest_ec.c
new file mode 100644
index 0000000..5929d0b
--- /dev/null
+++ b/version22/c/benchtest_ec.c
@@ -0,0 +1,212 @@
+/* Test and benchmark elliptic curve and RSA functions
+	First build amcl.a from build_ec batch file
+	gcc -O3 benchtest_ec.c amcl.a -o benchtest_ec.exe
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include "amcl.h"
+#include "rsa.h"
+
+#define MIN_TIME 10.0
+#define MIN_ITERS 10 
+
+int main()
+{
+    csprng RNG;
+	BIG s,r,x,y;
+	ECP P,G;
+	FP12 g;
+    int i,iterations;
+    clock_t start;
+    double elapsed;
+	char pr[10];
+	unsigned long ran;
+    rsa_public_key pub;
+    rsa_private_key priv;
+    char m[RFS],d[RFS],c[RFS];
+    octet M= {0,sizeof(m),m};
+    octet D= {0,sizeof(d),d};
+    octet C= {0,sizeof(c),c};
+
+#if CHOICE==NIST256 
+	printf("NIST256 Curve\n");
+#endif
+#if CHOICE==C25519 
+	printf("C25519 Curve\n");
+#endif
+#if CHOICE==BRAINPOOL
+	printf("BRAINPOOL Curve\n");
+#endif
+#if CHOICE==ANSSI
+	printf("ANSSI Curve\n");
+#endif
+#if CHOICE==MF254
+	printf("MF254 Curve\n");
+#endif
+#if CHOICE==MS255
+	printf("MS255 Curve\n");
+#endif
+#if CHOICE==MF256
+	printf("MF256 Curve\n");
+#endif
+#if CHOICE==MS256
+	printf("MS256 Curve\n");
+#endif
+#if CHOICE==HIFIVE
+	printf("HIFIVE Curve\n");
+#endif
+#if CHOICE==GOLDILOCKS
+	printf("GOLDILOCKS Curve\n");
+#endif
+#if CHOICE==NIST384
+	printf("NIST384 Curve\n");
+#endif
+#if CHOICE==C41417
+	printf("C41417 Curve\n");
+#endif
+#if CHOICE==NIST521
+	printf("NIST521 Curve\n");
+#endif
+
+#if CHOICE==BN254
+	printf("BN254 Curve\n");
+#endif
+#if CHOICE==BN454
+	printf("BN454 Curve\n");	
+#endif
+#if CHOICE==BN646
+	printf("BN646 Curve\n");	
+#endif
+
+#if CHOICE==BN254_CX 
+	printf("BN254_CX Curve\n");	
+#endif
+#if CHOICE==BN254_T
+	printf("BN254_T Curve\n");	
+#endif	
+#if CHOICE==BN254_T2 
+	printf("BN254_T2 Curve\n");	
+#endif
+#if CHOICE==BLS455 
+	printf("BLS455 Curve\n");	
+#endif
+#if CHOICE==BLS383 
+	printf("BLS383 Curve\n");	
+#endif
+
+#if CURVETYPE==WEIERSTRASS
+	printf("Weierstrass parameterization\n");
+#endif
+#if CURVETYPE==EDWARDS
+	printf("Edwards parameterization\n");
+#endif
+#if CURVETYPE==MONTGOMERY
+	printf("Montgomery parameterization\n");
+#endif
+
+#if CHUNK==16
+	printf("16-bit Build\n");
+#endif
+#if CHUNK==32
+	printf("32-bit Build\n");
+#endif
+#if CHUNK==64
+	printf("64-bit Build\n");
+#endif
+
+	time((time_t *)&ran);
+	pr[0]=ran;
+	pr[1]=ran>>8;
+	pr[2]=ran>>16;
+	pr[3]=ran>>24;
+	for (i=4;i<10;i++) pr[i]=i;
+    RAND_seed(&RNG,10,pr);
+
+	BIG_rcopy(x,CURVE_Gx);
+#if CURVETYPE!=MONTGOMERY
+	BIG_rcopy(y,CURVE_Gy);
+    ECP_set(&G,x,y);
+#else
+    ECP_set(&G,x);
+#endif
+	
+	BIG_rcopy(r,CURVE_Order);
+	BIG_randomnum(s,r,&RNG);
+	ECP_copy(&P,&G);
+    ECP_mul(&P,r);
+
+	if (!ECP_isinf(&P))
+	{
+		printf("FAILURE - rG!=O\n");
+		return 0;
+	}
+
+	iterations=0;
+    start=clock();
+    do {
+		ECP_copy(&P,&G);
+		ECP_mul(&P,s);
+
+		iterations++;
+		elapsed=(clock()-start)/(double)CLOCKS_PER_SEC;
+    } while (elapsed<MIN_TIME || iterations<MIN_ITERS);
+    elapsed=1000.0*elapsed/iterations;
+    printf("EC  mul - %8d iterations  ",iterations);
+    printf(" %8.2lf ms per iteration\n",elapsed);
+	
+	printf("Generating %d-bit RSA public/private key pair\n",FFLEN*BIGBITS);
+
+	iterations=0;
+    start=clock();
+    do {
+      RSA_KEY_PAIR(&RNG,65537,&priv,&pub,NULL,NULL);
+		iterations++;
+		elapsed=(clock()-start)/(double)CLOCKS_PER_SEC;
+    } while (elapsed<MIN_TIME || iterations<MIN_ITERS);
+    elapsed=1000.0*elapsed/iterations;
+    printf("RSA gen - %8d iterations  ",iterations);
+    printf(" %8.2lf ms per iteration\n",elapsed);
+
+    //FF_randomnum(plain,pub.n,&RNG,FFLEN);
+
+	M.len=RFS;
+	for (i=0;i<RFS;i++) M.val[i]=i%128;
+
+	iterations=0;
+    start=clock();
+    do {
+		RSA_ENCRYPT(&pub,&M,&C);
+		iterations++;
+		elapsed=(clock()-start)/(double)CLOCKS_PER_SEC;
+    } while (elapsed<MIN_TIME || iterations<MIN_ITERS);
+    elapsed=1000.0*elapsed/iterations;
+    printf("RSA enc - %8d iterations  ",iterations);
+    printf(" %8.2lf ms per iteration\n",elapsed);
+
+	iterations=0;
+    start=clock();
+    do {
+		RSA_DECRYPT(&priv,&C,&D);
+		iterations++;
+		elapsed=(clock()-start)/(double)CLOCKS_PER_SEC;
+    } while (elapsed<MIN_TIME || iterations<MIN_ITERS);
+    elapsed=1000.0*elapsed/iterations;
+    printf("RSA dec - %8d iterations  ",iterations);
+    printf(" %8.2lf ms per iteration\n",elapsed);
+
+	for (i=0;i<RFS;i++)
+	{
+		if (M.val[i]!=D.val[i])
+		{
+			printf("FAILURE - RSA decryption\n");
+			return 0;
+		}
+	}
+
+	printf("All tests pass\n");
+
+	return 0;
+}

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/70e3a3a3/version22/c/benchtest_pair.c
----------------------------------------------------------------------
diff --git a/version22/c/benchtest_pair.c b/version22/c/benchtest_pair.c
new file mode 100644
index 0000000..c9dcf38
--- /dev/null
+++ b/version22/c/benchtest_pair.c
@@ -0,0 +1,257 @@
+/* Test and benchmark pairing functions
+	First build amcl.a from build_pair batch file
+	gcc -O3 benchtest_pair.c amcl.a -o benchtest_pair.exe
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include "amcl.h" /* Make sure and select a pairing-friendly curve in here! */
+
+#define MIN_TIME 10.0
+#define MIN_ITERS 10 
+
+int main()
+{
+    csprng RNG;
+	BIG q,s,r,x,y,a,b,m;
+	ECP P,G;
+	FP2 wx,wy,f; 
+	FP4 c,cp,cpm1,cpm2,cr;
+    ECP2 Q,W;
+	FP12 g,w;
+	unsigned long ran;
+
+    int i,iterations;
+    clock_t start;
+    double elapsed;
+	char pr[10];
+
+#if CHOICE==BN254
+	printf("BN254 Curve\n");
+#endif
+#if CHOICE==BN454
+	printf("BN454 Curve\n");	
+#endif
+#if CHOICE==BN646
+	printf("BN646 Curve\n");	
+#endif
+
+#if CHOICE==BN254_CX 
+	printf("BN254_CX Curve\n");	
+#endif
+#if CHOICE==BN254_T
+	printf("BN254_T Curve\n");	
+#endif	
+#if CHOICE==BN254_T2 
+	printf("BN254_T2 Curve\n");	
+#endif
+#if CHOICE==BLS455 
+	printf("BLS455 Curve\n");	
+#endif
+#if CHOICE==BLS383 
+	printf("BLS383 Curve\n");	
+#endif
+
+#if CHUNK==16
+	printf("16-bit Build\n");
+#endif
+#if CHUNK==32
+	printf("32-bit Build\n");
+#endif
+#if CHUNK==64
+	printf("64-bit Build\n");
+#endif
+
+	time((time_t *)&ran);
+	pr[0]=ran;
+	pr[1]=ran>>8;
+	pr[2]=ran>>16;
+	pr[3]=ran>>24;
+	for (i=4;i<10;i++) pr[i]=i;
+
+    RAND_seed(&RNG,10,pr);
+
+	BIG_rcopy(x,CURVE_Gx);
+
+	BIG_rcopy(y,CURVE_Gy);
+    ECP_set(&G,x,y);
+
+	
+	BIG_rcopy(r,CURVE_Order);
+	BIG_randomnum(s,r,&RNG);
+	ECP_copy(&P,&G);
+    PAIR_G1mul(&P,r);
+
+	if (!ECP_isinf(&P))
+	{
+		printf("FAILURE - rG!=O\n");
+		return 0;
+	}
+	
+	iterations=0;
+    start=clock();
+    do {
+		ECP_copy(&P,&G);
+		PAIR_G1mul(&P,s);
+
+		iterations++;
+		elapsed=(clock()-start)/(double)CLOCKS_PER_SEC;
+    } while (elapsed<MIN_TIME || iterations<MIN_ITERS);
+    elapsed=1000.0*elapsed/iterations;
+    printf("G1 mul              - %8d iterations  ",iterations);
+    printf(" %8.2lf ms per iteration\n",elapsed);
+
+    
+    BIG_rcopy(wx.a,CURVE_Pxa); FP_nres(wx.a);
+    BIG_rcopy(wx.b,CURVE_Pxb); FP_nres(wx.b);
+    BIG_rcopy(wy.a,CURVE_Pya); FP_nres(wy.a);
+    BIG_rcopy(wy.b,CURVE_Pyb); FP_nres(wy.b);    
+	ECP2_set(&W,&wx,&wy);
+
+	ECP2_copy(&Q,&W);
+    ECP2_mul(&Q,r);
+
+	if (!ECP2_isinf(&Q))
+	{
+		printf("FAILURE - rQ!=O\n");
+		return 0;
+	}
+
+	iterations=0;
+    start=clock();
+    do {
+		ECP2_copy(&Q,&W);
+		PAIR_G2mul(&Q,s);
+
+		iterations++;
+		elapsed=(clock()-start)/(double)CLOCKS_PER_SEC;
+    } while (elapsed<MIN_TIME || iterations<MIN_ITERS);
+    elapsed=1000.0*elapsed/iterations;
+    printf("G2 mul              - %8d iterations  ",iterations);
+    printf(" %8.2lf ms per iteration\n",elapsed);
+
+	PAIR_ate(&w,&Q,&P);
+	PAIR_fexp(&w);
+
+	FP12_copy(&g,&w);
+
+	PAIR_GTpow(&g,r);
+
+	if (!FP12_isunity(&g))
+	{
+		printf("FAILURE - g^r!=1\n");
+		return 0;
+	}
+
+	iterations=0;
+    start=clock();
+    do {
+		FP12_copy(&g,&w);
+		PAIR_GTpow(&g,s);
+
+		iterations++;
+		elapsed=(clock()-start)/(double)CLOCKS_PER_SEC;
+    } while (elapsed<MIN_TIME || iterations<MIN_ITERS);
+    elapsed=1000.0*elapsed/iterations;
+    printf("GT pow              - %8d iterations  ",iterations);
+    printf(" %8.2lf ms per iteration\n",elapsed);
+
+	BIG_rcopy(a,CURVE_Fra);
+	BIG_rcopy(b,CURVE_Frb);
+	FP2_from_BIGs(&f,a,b);
+
+	BIG_rcopy(q,Modulus);
+
+	BIG_copy(m,q);
+	BIG_mod(m,r);
+
+	BIG_copy(a,s);
+	BIG_mod(a,m);
+
+	BIG_copy(b,s);
+	BIG_sdiv(b,m);
+
+	FP12_copy(&g,&w);
+	FP12_trace(&c,&g);
+
+	FP12_frob(&g,&f);
+	FP12_trace(&cp,&g);
+
+	FP12_conj(&w,&w);
+	FP12_mul(&g,&w);
+
+	FP12_trace(&cpm1,&g);
+	FP12_mul(&g,&w);
+	FP12_trace(&cpm2,&g);
+
+	iterations=0;
+    start=clock();
+    do {
+		FP4_xtr_pow2(&cr,&cp,&c,&cpm1,&cpm2,a,b);
+		iterations++;
+		elapsed=(clock()-start)/(double)CLOCKS_PER_SEC;
+    } while (elapsed<MIN_TIME || iterations<MIN_ITERS);
+    elapsed=1000.0*elapsed/iterations;
+    printf("GT pow (compressed) - %8d iterations  ",iterations);
+    printf(" %8.2lf ms per iteration\n",elapsed);
+
+	iterations=0;
+    start=clock();
+    do {
+		PAIR_ate(&w,&Q,&P);
+		iterations++;
+		elapsed=(clock()-start)/(double)CLOCKS_PER_SEC;
+    } while (elapsed<MIN_TIME || iterations<MIN_ITERS);
+    elapsed=1000.0*elapsed/iterations;
+    printf("PAIRing ATE         - %8d iterations  ",iterations);
+    printf(" %8.2lf ms per iteration\n",elapsed);
+
+	iterations=0;
+    start=clock();
+    do {
+		FP12_copy(&g,&w);
+		PAIR_fexp(&g);
+		iterations++;
+		elapsed=(clock()-start)/(double)CLOCKS_PER_SEC;
+    } while (elapsed<MIN_TIME || iterations<MIN_ITERS);
+    elapsed=1000.0*elapsed/iterations;
+    printf("PAIRing FEXP        - %8d iterations  ",iterations);
+    printf(" %8.2lf ms per iteration\n",elapsed);
+
+	ECP_copy(&P,&G);	
+	ECP2_copy(&Q,&W);
+
+	PAIR_G1mul(&P,s);
+	PAIR_ate(&g,&Q,&P);
+	PAIR_fexp(&g);
+
+	ECP_copy(&P,&G);
+
+	PAIR_G2mul(&Q,s);
+	PAIR_ate(&w,&Q,&P);
+	PAIR_fexp(&w);
+
+	if (!FP12_equals(&g,&w))
+	{
+		printf("FAILURE - e(sQ,p)!=e(Q,sP) \n");
+		return 0;
+	}
+
+	ECP2_copy(&Q,&W);
+	PAIR_ate(&g,&Q,&P);
+	PAIR_fexp(&g);
+
+	PAIR_GTpow(&g,s);
+
+	if (!FP12_equals(&g,&w))
+	{
+		printf("FAILURE - e(sQ,p)!=e(Q,P)^s \n");
+		return 0;
+	}
+
+	printf("All tests pass\n");
+
+	return 0;
+}

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/70e3a3a3/version22/c/big.c
----------------------------------------------------------------------
diff --git a/version22/c/big.c b/version22/c/big.c
new file mode 100644
index 0000000..1fe6259
--- /dev/null
+++ b/version22/c/big.c
@@ -0,0 +1,1525 @@
+/*
+	Licensed to the Apache Software Foundation (ASF) under one
+	or more contributor license agreements.  See the NOTICE file
+	distributed with this work for additional information
+	regarding copyright ownership.  The ASF licenses this file
+	to you under the Apache License, Version 2.0 (the
+	"License"); you may not use this file except in compliance
+	with the License.  You may obtain a copy of the License at
+
+	  http://www.apache.org/licenses/LICENSE-2.0
+
+	Unless required by applicable law or agreed to in writing,
+	software distributed under the License is distributed on an
+	"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+	KIND, either express or implied.  See the License for the
+	specific language governing permissions and limitations
+	under the License.
+*/
+
+/* AMCL basic functions for BIG type */
+/* SU=m, SU is Stack Usage */
+
+#include "amcl.h"
+
+/* Calculates x*y+c+*r */
+
+#ifdef dchunk
+
+/* Method required to calculate x*y+c+r, bottom half in r, top half returned */
+chunk muladd(chunk x,chunk y,chunk c,chunk *r)
+{
+    dchunk prod=(dchunk)x*y+c+*r;
+    *r=(chunk)prod&BMASK;
+    return (chunk)(prod>>BASEBITS);
+}
+
+#else
+
+/* No integer type available that can store double the wordlength */
+/* accumulate partial products */
+
+chunk muladd(chunk x,chunk y,chunk c,chunk *r)
+{
+    chunk x0,x1,y0,y1;
+    chunk bot,top,mid,carry;
+    x0=x&HMASK;
+    x1=(x>>HBITS);
+    y0=y&HMASK;
+    y1=(y>>HBITS);
+    bot=x0*y0;
+    top=x1*y1;
+    mid=x0*y1+x1*y0;
+    x0=mid&HMASK1;
+    x1=(mid>>HBITS1);
+    bot+=x0<<HBITS;
+    bot+=*r;
+    bot+=c;
+
+#if HDIFF==1
+    bot+=(top&HDIFF)<<(BASEBITS-1);
+    top>>=HDIFF;
+#endif
+
+    top+=x1;
+    carry=bot>>BASEBITS;
+    bot&=BMASK;
+    top+=carry;
+
+    *r=bot;
+    return top;
+}
+
+#endif
+
+/*
+
+// Alternative non Standard Solution required if no type available that can store double the wordlength
+// The use of compiler intrinsics is permitted
+
+
+#if CHUNK==64
+#ifdef _WIN64
+#include <intrin.h>
+
+static INLINE chunk muladd(chunk x,chunk y,chunk c,chunk *r)
+{
+	chunk t,e;
+	uchunk b;
+	b=_mul128(x,y,&t);
+	e=c+*r;
+	b+=e;
+// make correction for possible carry to top half
+	if (e<0)
+		t-=(b>e);
+	else
+		t+=(b<e);
+
+	*r=b&MASK;
+	return (chunk)((t<<(CHUNK-BASEBITS)) | (b>>BASEBITS));
+}
+
+#endif
+#endif
+
+*/
+
+/* test a=0? */
+int BIG_iszilch(BIG a)
+{
+    int i;
+    for (i=0; i<NLEN; i++)
+        if (a[i]!=0) return 0;
+    return 1;
+}
+
+/* test a=0? */
+int BIG_diszilch(DBIG a)
+{
+    int i;
+    for (i=0; i<DNLEN; i++)
+        if (a[i]!=0) return 0;
+    return 1;
+}
+
+/* SU= 56 */
+/* output a */
+void BIG_output(BIG a)
+{
+    BIG b;
+    int i,len;
+    len=BIG_nbits(a);
+    if (len%4==0) len/=4;
+    else
+    {
+        len/=4;
+        len++;
+    }
+    if (len<MODBYTES*2) len=MODBYTES*2;
+
+    for (i=len-1; i>=0; i--)
+    {
+        BIG_copy(b,a);
+        BIG_shr(b,i*4);
+        printf("%01x",(unsigned int) b[0]&15);
+    }
+}
+
+/* SU= 16 */
+void BIG_rawoutput(BIG a)
+{
+    int i;
+    printf("(");
+    for (i=0; i<NLEN-1; i++)
+#if CHUNK==64
+        printf("%"PRIxMAX",",(uint64_t) a[i]);
+    printf("%"PRIxMAX")",(uint64_t) a[NLEN-1]);
+#else
+        printf("%x,",(unsigned int) a[i]);
+    printf("%x)",(unsigned int) a[NLEN-1]);
+#endif
+}
+/*
+void BIG_rawdoutput(DBIG a)
+{
+	int i;
+	printf("(");
+	for (i=0;i<DNLEN-1;i++)
+#if CHUNK==64
+	  printf("%llx,",(long long unsigned int) a[i]);
+	printf("%llx)",(long long unsigned int) a[DNLEN-1]);
+#else
+	  printf("%x,",(unsigned int) a[i]);
+	printf("%x)",(unsigned int) a[NLEN-1]);
+#endif
+}
+*/
+/* Swap a and b if d=1 */
+void BIG_cswap(BIG a,BIG b,int d)
+{
+    int i;
+    chunk t,c=d;
+    c=~(c-1);
+#ifdef DEBUG_NORM
+    for (i=0; i<=NLEN; i++)
+#else
+    for (i=0; i<NLEN; i++)
+#endif
+    {
+        t=c&(a[i]^b[i]);
+        a[i]^=t;
+        b[i]^=t;
+    }
+}
+
+/* Move b to a if d=1 */
+void BIG_cmove(BIG f,BIG g,int d)
+{
+    int i;
+    chunk b=(chunk)-d;
+#ifdef DEBUG_NORM
+    for (i=0; i<=NLEN; i++)
+#else
+    for (i=0; i<NLEN; i++)
+#endif
+    {
+        f[i]^=(f[i]^g[i])&b;
+    }
+}
+
+/* Move g to f if d=1 */
+void BIG_dcmove(DBIG f,DBIG g,int d)
+{
+    int i;
+    chunk b=(chunk)-d;
+#ifdef DEBUG_NORM
+    for (i=0; i<=DNLEN; i++)
+#else
+    for (i=0; i<DNLEN; i++)
+#endif
+    {
+        f[i]^=(f[i]^g[i])&b;
+    }
+}
+
+/* convert BIG to/from bytes */
+/* SU= 64 */
+void BIG_toBytes(char *b,BIG a)
+{
+    int i;
+    BIG c;
+    BIG_norm(a);
+    BIG_copy(c,a);
+    for (i=MODBYTES-1; i>=0; i--)
+    {
+        b[i]=c[0]&0xff;
+        BIG_fshr(c,8);
+    }
+}
+
+/* SU= 16 */
+void BIG_fromBytes(BIG a,char *b)
+{
+    int i;
+    BIG_zero(a);
+    for (i=0; i<MODBYTES; i++)
+    {
+        BIG_fshl(a,8);
+        a[0]+=(int)(unsigned char)b[i];
+        //BIG_inc(a,(int)(unsigned char)b[i]); BIG_norm(a);
+    }
+#ifdef DEBUG_NORM
+    a[NLEN]=0;
+#endif
+}
+
+void BIG_fromBytesLen(BIG a,char *b,int s)
+{
+    int i,len=s;
+    BIG_zero(a);
+
+    if (s>MODBYTES) s=MODBYTES;
+    for (i=0; i<len; i++)
+    {
+        BIG_fshl(a,8);
+        a[0]+=(int)(unsigned char)b[i];
+    }
+#ifdef DEBUG_NORM
+    a[NLEN]=0;
+#endif
+}
+
+
+
+/* SU= 88 */
+void BIG_doutput(DBIG a)
+{
+    DBIG b;
+    int i,len;
+    BIG_dnorm(a);
+    len=BIG_dnbits(a);
+    if (len%4==0) len/=4;
+    else
+    {
+        len/=4;
+        len++;
+    }
+
+    for (i=len-1; i>=0; i--)
+    {
+        BIG_dcopy(b,a);
+        BIG_dshr(b,i*4);
+        printf("%01x",(unsigned int) b[0]&15);
+    }
+}
+
+/* Copy b=a */
+void BIG_copy(BIG b,BIG a)
+{
+    int i;
+    for (i=0; i<NLEN; i++)
+        b[i]=a[i];
+#ifdef DEBUG_NORM
+    b[NLEN]=a[NLEN];
+#endif
+}
+
+/* Copy from ROM b=a */
+void BIG_rcopy(BIG b,const BIG a)
+{
+    int i;
+    for (i=0; i<NLEN; i++)
+        b[i]=a[i];
+#ifdef DEBUG_NORM
+    b[NLEN]=0;
+#endif
+}
+
+/* double length DBIG copy b=a */
+void BIG_dcopy(DBIG b,DBIG a)
+{
+    int i;
+    for (i=0; i<DNLEN; i++)
+        b[i]=a[i];
+#ifdef DEBUG_NORM
+    b[DNLEN]=a[DNLEN];
+#endif
+}
+
+/* Copy BIG to bottom half of DBIG */
+void BIG_dscopy(DBIG b,BIG a)
+{
+    int i;
+    for (i=0; i<NLEN-1; i++)
+        b[i]=a[i];
+
+    b[NLEN-1]=a[NLEN-1]&BMASK; /* top word normalized */
+    b[NLEN]=a[NLEN-1]>>BASEBITS;
+
+    for (i=NLEN+1; i<DNLEN; i++) b[i]=0;
+#ifdef DEBUG_NORM
+    b[DNLEN]=a[NLEN];
+#endif
+}
+
+/* Copy BIG to top half of DBIG */
+void BIG_dsucopy(DBIG b,BIG a)
+{
+    int i;
+    for (i=0; i<NLEN; i++)
+        b[i]=0;
+    for (i=NLEN; i<DNLEN; i++)
+        b[i]=a[i-NLEN];
+#ifdef DEBUG_NORM
+    b[DNLEN]=a[NLEN];
+#endif
+}
+
+/* Copy bottom half of DBIG to BIG */
+void BIG_sdcopy(BIG b,DBIG a)
+{
+    int i;
+    for (i=0; i<NLEN; i++)
+        b[i]=a[i];
+#ifdef DEBUG_NORM
+    b[NLEN]=a[DNLEN];
+#endif
+}
+
+/* Copy top half of DBIG to BIG */
+void BIG_sducopy(BIG b,DBIG a)
+{
+    int i;
+    for (i=0; i<NLEN; i++)
+        b[i]=a[i+NLEN];
+#ifdef DEBUG_NORM
+    b[NLEN]=a[DNLEN];
+#endif
+}
+
+/* Set a=0 */
+void BIG_zero(BIG a)
+{
+    int i;
+    for (i=0; i<NLEN; i++)
+        a[i]=0;
+#ifdef DEBUG_NORM
+    a[NLEN]=0;
+#endif
+}
+
+void BIG_dzero(DBIG a)
+{
+    int i;
+    for (i=0; i<DNLEN; i++)
+        a[i]=0;
+#ifdef DEBUG_NORM
+    a[DNLEN]=0;
+#endif
+}
+
+/* set a=1 */
+void BIG_one(BIG a)
+{
+    int i;
+    a[0]=1;
+    for (i=1; i<NLEN; i++)
+        a[i]=0;
+#ifdef DEBUG_NORM
+    a[NLEN]=0;
+#endif
+}
+
+
+
+/* Set c=a+b */
+/* SU= 8 */
+void BIG_add(BIG c,BIG a,BIG b)
+{
+    int i;
+    for (i=0; i<NLEN; i++)
+        c[i]=a[i]+b[i];
+#ifdef DEBUG_NORM
+    c[NLEN]=a[NLEN]+b[NLEN]+1;
+    if (c[NLEN]>=NEXCESS) printf("add problem - digit overflow %d\n",c[NLEN]);
+#endif
+}
+
+/* Set c=c+d */
+void BIG_inc(BIG c,int d)
+{
+    BIG_norm(c);
+    c[0]+=(chunk)d;
+#ifdef DEBUG_NORM
+    c[NLEN]=1;
+#endif
+}
+
+/* Set c=a-b */
+/* SU= 8 */
+void BIG_sub(BIG c,BIG a,BIG b)
+{
+    int i;
+    for (i=0; i<NLEN; i++)
+        c[i]=a[i]-b[i];
+#ifdef DEBUG_NORM
+    c[NLEN]=a[NLEN]+b[NLEN]+1;
+    if (c[NLEN]>=NEXCESS) printf("sub problem - digit overflow %d\n",c[NLEN]);
+#endif
+}
+
+/* SU= 8 */
+
+void BIG_dsub(DBIG c,DBIG a,DBIG b)
+{
+    int i;
+    for (i=0; i<DNLEN; i++)
+        c[i]=a[i]-b[i];
+#ifdef DEBUG_NORM
+    c[DNLEN]=a[DNLEN]+b[DNLEN]+1;
+    if (c[DNLEN]>=NEXCESS) printf("sub problem - digit overflow %d\n",c[DNLEN]);
+#endif
+}
+
+
+/* Set c=c-1 */
+void BIG_dec(BIG c,int d)
+{
+    BIG_norm(c);
+    c[0]-=(chunk)d;
+#ifdef DEBUG_NORM
+    c[NLEN]=1;
+#endif
+}
+
+/* multiplication r=a*c by c<=NEXCESS */
+void BIG_imul(BIG r,BIG a,int c)
+{
+    int i;
+    for (i=0; i<NLEN; i++) r[i]=a[i]*c;
+#ifdef DEBUG_NORM
+    r[NLEN]=(a[NLEN]+1)*c-1;
+    if (r[NLEN]>=NEXCESS) printf("int mul problem - digit overflow %d\n",r[NLEN]);
+#endif
+}
+
+/* multiplication r=a*c by larger integer - c<=FEXCESS */
+/* SU= 24 */
+chunk BIG_pmul(BIG r,BIG a,int c)
+{
+    int i;
+    chunk ak,carry=0;
+    BIG_norm(a);
+    for (i=0; i<NLEN; i++)
+    {
+        ak=a[i];
+        r[i]=0;
+        carry=muladd(ak,(chunk)c,carry,&r[i]);
+    }
+#ifdef DEBUG_NORM
+    r[NLEN]=0;
+#endif
+    return carry;
+}
+
+/* r/=3 */
+/* SU= 16 */
+int BIG_div3(BIG r)
+{
+    int i;
+    chunk ak,base,carry=0;
+    BIG_norm(r);
+    base=((chunk)1<<BASEBITS);
+    for (i=NLEN-1; i>=0; i--)
+    {
+        ak=(carry*base+r[i]);
+        r[i]=ak/3;
+        carry=ak%3;
+    }
+    return (int)carry;
+}
+
+/* multiplication c=a*b by even larger integer b>FEXCESS, resulting in DBIG */
+/* SU= 24 */
+void BIG_pxmul(DBIG c,BIG a,int b)
+{
+    int j;
+    chunk carry;
+    BIG_dzero(c);
+    carry=0;
+    for (j=0; j<NLEN; j++)
+        carry=muladd(a[j],(chunk)b,carry,&c[j]);
+    c[NLEN]=carry;
+#ifdef DEBUG_NORM
+    c[DNLEN]=0;
+#endif
+}
+
+/* .. if you know the result will fit in a BIG, c must be distinct from a and b */
+/* SU= 40 */
+void BIG_smul(BIG c,BIG a,BIG b)
+{
+    int i,j;
+    chunk carry;
+    BIG_norm(a);
+    BIG_norm(b);
+
+    BIG_zero(c);
+    for (i=0; i<NLEN; i++)
+    {
+        carry=0;
+        for (j=0; j<NLEN; j++)
+        {
+            if (i+j<NLEN)
+                carry=muladd(a[i],b[j],carry,&c[i+j]);
+        }
+    }
+#ifdef DEBUG_NORM
+    c[NLEN]=0;
+#endif
+}
+
+/* Set c=a*b */
+/* SU= 72 */
+void BIG_mul(DBIG c,BIG a,BIG b)
+{
+    int i;
+#ifdef dchunk
+    dchunk t,co;
+    dchunk s;
+    dchunk d[NLEN];
+    int k;
+#endif
+
+    /* change here - a and b MUST be normed on input */
+
+//	BIG_norm(a);  /* needed here to prevent overflow from addition of partial products */
+//	BIG_norm(b);
+
+    /* Faster to Combafy it.. Let the compiler unroll the loops! */
+
+#ifdef COMBA
+
+    /* faster psuedo-Karatsuba method */
+#ifdef UNWOUND
+
+    /* Insert output of faster.c here */
+
+#else
+    for (i=0; i<NLEN; i++)
+        d[i]=(dchunk)a[i]*b[i];
+
+    s=d[0];
+    t=s;
+    c[0]=(chunk)t&BMASK;
+    co=t>>BASEBITS;
+
+    for (k=1; k<NLEN; k++)
+    {
+        s+=d[k];
+        t=co+s;
+        for (i=k; i>=1+k/2; i--) t+=(dchunk)(a[i]-a[k-i])*(b[k-i]-b[i]);
+        c[k]=(chunk)t&BMASK;
+        co=t>>BASEBITS;
+    }
+    for (k=NLEN; k<2*NLEN-1; k++)
+    {
+        s-=d[k-NLEN];
+        t=co+s;
+        for (i=NLEN-1; i>=1+k/2; i--) t+=(dchunk)(a[i]-a[k-i])*(b[k-i]-b[i]);
+        c[k]=(chunk)t&BMASK;
+        co=t>>BASEBITS;
+    }
+    c[2*NLEN-1]=(chunk)co;
+
+#endif
+
+#else
+    int j;
+    chunk carry;
+    BIG_dzero(c);
+    for (i=0; i<NLEN; i++)
+    {
+        carry=0;
+        for (j=0; j<NLEN; j++)
+            carry=muladd(a[i],b[j],carry,&c[i+j]);
+
+        c[NLEN+i]=carry;
+    }
+
+#endif
+
+#ifdef DEBUG_NORM
+    c[DNLEN]=0;
+#endif
+}
+
+/* Set c=a*a */
+/* SU= 80 */
+void BIG_sqr(DBIG c,BIG a)
+{
+    int i,j,last;
+#ifdef dchunk
+    dchunk t,co;
+#endif
+
+    /* change here - a MUST be normed on input */
+//	BIG_norm(a);
+
+    /* Note 2*a[i] in loop below and extra addition */
+
+#ifdef COMBA
+
+#ifdef UNWOUND
+
+    /* Insert output of faster.c here */
+
+#else
+
+    t=(dchunk)a[0]*a[0];
+    c[0]=(chunk)t&BMASK;
+    co=t>>BASEBITS;
+    t=(dchunk)a[1]*a[0];
+    t+=t;
+    t+=co;
+    c[1]=(chunk)t&BMASK;
+    co=t>>BASEBITS;
+
+    last=NLEN-NLEN%2;
+    for (j=2; j<last; j+=2)
+    {
+        t=(dchunk)a[j]*a[0];
+        for (i=1; i<(j+1)/2; i++) t+=(dchunk)a[j-i]*a[i];
+        t+=t;
+        t+=co;
+        t+=(dchunk)a[j/2]*a[j/2];
+        c[j]=(chunk)t&BMASK;
+        co=t>>BASEBITS;
+        t=(dchunk)a[j+1]*a[0];
+        for (i=1; i<(j+2)/2; i++) t+=(dchunk)a[j+1-i]*a[i];
+        t+=t;
+        t+=co;
+        c[j+1]=(chunk)t&BMASK;
+        co=t>>BASEBITS;
+    }
+    j=last;
+#if NLEN%2==1
+    t=(dchunk)a[j]*a[0];
+    for (i=1; i<(j+1)/2; i++) t+=(dchunk)a[j-i]*a[i];
+    t+=t;
+    t+=co;
+    t+=(dchunk)a[j/2]*a[j/2];
+    c[j]=(chunk)t&BMASK;
+    co=t>>BASEBITS;
+    j++;
+    t=(dchunk)a[NLEN-1]*a[j-NLEN+1];
+    for (i=j-NLEN+2; i<(j+1)/2; i++) t+=(dchunk)a[j-i]*a[i];
+    t+=t;
+    t+=co;
+    c[j]=(chunk)t&BMASK;
+    co=t>>BASEBITS;
+    j++;
+#endif
+    for (; j<DNLEN-2; j+=2)
+    {
+        t=(dchunk)a[NLEN-1]*a[j-NLEN+1];
+        for (i=j-NLEN+2; i<(j+1)/2; i++) t+=(dchunk)a[j-i]*a[i];
+        t+=t;
+        t+=co;
+        t+=(dchunk)a[j/2]*a[j/2];
+        c[j]=(chunk)t&BMASK;
+        co=t>>BASEBITS;
+        t=(dchunk)a[NLEN-1]*a[j-NLEN+2];
+        for (i=j-NLEN+3; i<(j+2)/2; i++) t+=(dchunk)a[j+1-i]*a[i];
+        t+=t;
+        t+=co;
+        c[j+1]=(chunk)t&BMASK;
+        co=t>>BASEBITS;
+    }
+
+    t=(dchunk)a[NLEN-1]*a[NLEN-1]+co;
+    c[DNLEN-2]=(chunk)t&BMASK;
+    co=t>>BASEBITS;
+    c[DNLEN-1]=(chunk)co;
+#endif
+
+#else
+    chunk carry;
+    BIG_dzero(c);
+    for (i=0; i<NLEN; i++)
+    {
+        carry=0;
+        for (j=i+1; j<NLEN; j++)
+            carry=muladd(a[i],a[j],carry,&c[i+j]);
+        c[NLEN+i]=carry;
+    }
+
+    for (i=0; i<DNLEN; i++) c[i]*=2;
+
+    for (i=0; i<NLEN; i++)
+        c[2*i+1]+=muladd(a[i],a[i],0,&c[2*i]);
+
+    BIG_dnorm(c);
+#endif
+
+
+#ifdef DEBUG_NORM
+    c[DNLEN]=0;
+#endif
+
+}
+
+/* Montgomery reduction */
+void BIG_monty(BIG a,BIG md,chunk MC,DBIG d)
+{
+    int i,k;
+
+#ifdef dchunk
+    dchunk t,c,s;
+    dchunk dd[NLEN];
+    chunk v[NLEN];
+#endif
+
+#ifdef COMBA
+
+#ifdef UNWOUND
+
+    /* Insert output of faster.c here */
+
+#else
+
+    t=d[0];
+    v[0]=((chunk)t*MC)&BMASK;
+    t+=(dchunk)v[0]*md[0];
+    c=(t>>BASEBITS)+d[1];
+    s=0;
+
+    for (k=1; k<NLEN; k++)
+    {
+        t=c+s+(dchunk)v[0]*md[k];
+        for (i=k-1; i>k/2; i--) t+=(dchunk)(v[k-i]-v[i])*(md[i]-md[k-i]);
+        v[k]=((chunk)t*MC)&BMASK;
+        t+=(dchunk)v[k]*md[0];
+        c=(t>>BASEBITS)+d[k+1];
+        dd[k]=(dchunk)v[k]*md[k];
+        s+=dd[k];
+    }
+    for (k=NLEN; k<2*NLEN-1; k++)
+    {
+        t=c+s;
+        for (i=NLEN-1; i>=1+k/2; i--) t+=(dchunk)(v[k-i]-v[i])*(md[i]-md[k-i]);
+        a[k-NLEN]=(chunk)t&BMASK;
+        c=(t>>BASEBITS)+d[k+1];
+        s-=dd[k-NLEN+1];
+    }
+    a[NLEN-1]=(chunk)c&BMASK;
+
+#endif
+
+#ifdef DEBUG_NORM
+    a[NLEN]=0;
+#endif
+
+#else
+    int j;
+    chunk m,carry;
+    for (i=0; i<NLEN; i++)
+    {
+        if (MC==-1) m=(-d[i])&BMASK;
+        else
+        {
+            if (MC==1) m=d[i];
+            else m=(MC*d[i])&BMASK;
+        }
+        carry=0;
+        for (j=0; j<NLEN; j++)
+            carry=muladd(m,md[j],carry,&d[i+j]);
+        d[NLEN+i]+=carry;
+    }
+    BIG_sducopy(a,d);
+    BIG_norm(a);
+
+#endif
+}
+
+/* General shift left of a by n bits */
+/* a MUST be normalised */
+/* SU= 32 */
+void BIG_shl(BIG a,int k)
+{
+    int i;
+    int n=k%BASEBITS;
+    int m=k/BASEBITS;
+
+//	a[NLEN-1]=((a[NLEN-1-m]<<n))|(a[NLEN-m-2]>>(BASEBITS-n));
+
+    a[NLEN-1]=((a[NLEN-1-m]<<n));
+    if (NLEN>=m+2) a[NLEN-1]|=(a[NLEN-m-2]>>(BASEBITS-n));
+
+    for (i=NLEN-2; i>m; i--)
+        a[i]=((a[i-m]<<n)&BMASK)|(a[i-m-1]>>(BASEBITS-n));
+    a[m]=(a[0]<<n)&BMASK;
+    for (i=0; i<m; i++) a[i]=0;
+
+}
+
+/* Fast shift left of a by n bits, where n less than a word, Return excess (but store it as well) */
+/* a MUST be normalised */
+/* SU= 16 */
+int BIG_fshl(BIG a,int n)
+{
+    int i;
+
+    a[NLEN-1]=((a[NLEN-1]<<n))|(a[NLEN-2]>>(BASEBITS-n)); /* top word not masked */
+    for (i=NLEN-2; i>0; i--)
+        a[i]=((a[i]<<n)&BMASK)|(a[i-1]>>(BASEBITS-n));
+    a[0]=(a[0]<<n)&BMASK;
+
+    return (int)(a[NLEN-1]>>((8*MODBYTES)%BASEBITS)); /* return excess - only used in ff.c */
+}
+
+/* double length left shift of a by k bits - k can be > BASEBITS , a MUST be normalised */
+/* SU= 32 */
+void BIG_dshl(DBIG a,int k)
+{
+    int i;
+    int n=k%BASEBITS;
+    int m=k/BASEBITS;
+
+    a[DNLEN-1]=((a[DNLEN-1-m]<<n))|(a[DNLEN-m-2]>>(BASEBITS-n));
+
+    for (i=DNLEN-2; i>m; i--)
+        a[i]=((a[i-m]<<n)&BMASK)|(a[i-m-1]>>(BASEBITS-n));
+    a[m]=(a[0]<<n)&BMASK;
+    for (i=0; i<m; i++) a[i]=0;
+
+}
+
+/* General shift rightof a by k bits */
+/* a MUST be normalised */
+/* SU= 32 */
+void BIG_shr(BIG a,int k)
+{
+    int i;
+    int n=k%BASEBITS;
+    int m=k/BASEBITS;
+    for (i=0; i<NLEN-m-1; i++)
+        a[i]=(a[m+i]>>n)|((a[m+i+1]<<(BASEBITS-n))&BMASK);
+    if (NLEN>m)  a[NLEN-m-1]=a[NLEN-1]>>n;
+    for (i=NLEN-m; i<NLEN; i++) a[i]=0;
+
+}
+
+/* Faster shift right of a by k bits. Return shifted out part */
+/* a MUST be normalised */
+/* SU= 16 */
+int BIG_fshr(BIG a,int k)
+{
+    int i;
+    chunk r=a[0]&(((chunk)1<<k)-1); /* shifted out part */
+    for (i=0; i<NLEN-1; i++)
+        a[i]=(a[i]>>k)|((a[i+1]<<(BASEBITS-k))&BMASK);
+    a[NLEN-1]=a[NLEN-1]>>k;
+    return (int)r;
+}
+
+/* double length right shift of a by k bits - can be > BASEBITS */
+/* SU= 32 */
+void BIG_dshr(DBIG a,int k)
+{
+    int i;
+    int n=k%BASEBITS;
+    int m=k/BASEBITS;
+    for (i=0; i<DNLEN-m-1; i++)
+        a[i]=(a[m+i]>>n)|((a[m+i+1]<<(BASEBITS-n))&BMASK);
+    a[DNLEN-m-1]=a[DNLEN-1]>>n;
+    for (i=DNLEN-m; i<DNLEN; i++ ) a[i]=0;
+}
+
+/* Split DBIG d into two BIGs t|b. Split happens at n bits, where n falls into NLEN word */
+/* d MUST be normalised */
+/* SU= 24 */
+chunk BIG_split(BIG t,BIG b,DBIG d,int n)
+{
+    int i;
+    chunk nw,carry=0;
+    int m=n%BASEBITS;
+//	BIG_dnorm(d);
+
+    if (m==0)
+    {
+        for (i=0; i<NLEN; i++) b[i]=d[i];
+        if (t!=b)
+        {
+            for (i=NLEN; i<2*NLEN; i++) t[i-NLEN]=d[i];
+            carry=t[NLEN-1]>>BASEBITS;
+            t[NLEN-1]=t[NLEN-1]&BMASK; /* top word normalized */
+        }
+        return carry;
+    }
+
+    for (i=0; i<NLEN-1; i++) b[i]=d[i];
+
+    b[NLEN-1]=d[NLEN-1]&(((chunk)1<<m)-1);
+
+    if (t!=b)
+    {
+        carry=(d[DNLEN-1]<<(BASEBITS-m));
+        for (i=DNLEN-2; i>=NLEN-1; i--)
+        {
+            nw=(d[i]>>m)|carry;
+            carry=(d[i]<<(BASEBITS-m))&BMASK;
+            t[i-NLEN+1]=nw;
+        }
+    }
+#ifdef DEBUG_NORM
+    t[NLEN]=0;
+    b[NLEN]=0;
+#endif
+    return carry;
+}
+
+/* you gotta keep the sign of carry! Look - no branching! */
+/* Note that sign bit is needed to disambiguate between +ve and -ve values */
+/* normalise BIG - force all digits < 2^BASEBITS */
+chunk BIG_norm(BIG a)
+{
+    int i;
+    chunk d,carry=0;
+    for (i=0; i<NLEN-1; i++)
+    {
+        d=a[i]+carry;
+        a[i]=d&BMASK;
+        carry=d>>BASEBITS;
+    }
+    a[NLEN-1]=(a[NLEN-1]+carry);
+
+#ifdef DEBUG_NORM
+    a[NLEN]=0;
+#endif
+    return (a[NLEN-1]>>((8*MODBYTES)%BASEBITS));  /* only used in ff.c */
+}
+
+void BIG_dnorm(DBIG a)
+{
+    int i;
+    chunk d,carry=0;
+    for (i=0; i<DNLEN-1; i++)
+    {
+        d=a[i]+carry;
+        a[i]=d&BMASK;
+        carry=d>>BASEBITS;
+    }
+    a[DNLEN-1]=(a[DNLEN-1]+carry);
+#ifdef DEBUG_NORM
+    a[DNLEN]=0;
+#endif
+}
+
+/* Compare a and b. Return 1 for a>b, -1 for a<b, 0 for a==b */
+/* a and b MUST be normalised before call */
+int BIG_comp(BIG a,BIG b)
+{
+    int i;
+    for (i=NLEN-1; i>=0; i--)
+    {
+        if (a[i]==b[i]) continue;
+        if (a[i]>b[i]) return 1;
+        else  return -1;
+    }
+    return 0;
+}
+
+int BIG_dcomp(DBIG a,DBIG b)
+{
+    int i;
+    for (i=DNLEN-1; i>=0; i--)
+    {
+        if (a[i]==b[i]) continue;
+        if (a[i]>b[i]) return 1;
+        else  return -1;
+    }
+    return 0;
+}
+
+/* return number of bits in a */
+/* SU= 8 */
+int BIG_nbits(BIG a)
+{
+    int bts,k=NLEN-1;
+    chunk c;
+    BIG_norm(a);
+    while (k>=0 && a[k]==0) k--;
+    if (k<0) return 0;
+    bts=BASEBITS*k;
+    c=a[k];
+    while (c!=0)
+    {
+        c/=2;
+        bts++;
+    }
+    return bts;
+}
+
+/* SU= 8, Calculate number of bits in a DBIG - output normalised */
+int BIG_dnbits(DBIG a)
+{
+    int bts,k=DNLEN-1;
+    chunk c;
+    BIG_dnorm(a);
+    while (k>=0 && a[k]==0) k--;
+    if (k<0) return 0;
+    bts=BASEBITS*k;
+    c=a[k];
+    while (c!=0)
+    {
+        c/=2;
+        bts++;
+    }
+    return bts;
+}
+
+
+/* Set b=b mod c */
+/* SU= 16 */
+void BIG_mod(BIG b,BIG c)
+{
+    int k=0;
+    BIG r; /**/
+
+    BIG_norm(b);
+    if (BIG_comp(b,c)<0)
+        return;
+    do
+    {
+        BIG_fshl(c,1);
+        k++;
+    }
+    while (BIG_comp(b,c)>=0);
+
+    while (k>0)
+    {
+        BIG_fshr(c,1);
+
+// constant time...
+        BIG_sub(r,b,c);
+        BIG_norm(r);
+        BIG_cmove(b,r,1-((r[NLEN-1]>>(CHUNK-1))&1));
+        /*
+                if (BIG_comp(b,c)>=0)
+                {
+                    BIG_sub(b,b,c);
+                    BIG_norm(b);
+                }
+        */
+        k--;
+    }
+}
+
+/* Set a=b mod c, b is destroyed. Slow but rarely used. */
+/* SU= 96 */
+void BIG_dmod(BIG a,DBIG b,BIG c)
+{
+    int k=0;
+    DBIG m,r;
+    BIG_dnorm(b);
+    BIG_dscopy(m,c);
+
+    if (BIG_dcomp(b,m)<0)
+    {
+        BIG_sdcopy(a,b);
+        return;
+    }
+
+    do
+    {
+        BIG_dshl(m,1);
+        k++;
+    }
+    while (BIG_dcomp(b,m)>=0);
+
+    while (k>0)
+    {
+        BIG_dshr(m,1);
+// constant time...
+        BIG_dsub(r,b,m);
+        BIG_dnorm(r);
+        BIG_dcmove(b,r,1-((r[DNLEN-1]>>(CHUNK-1))&1));
+        /*
+                if (BIG_dcomp(b,m)>=0)
+                {
+                    BIG_dsub(b,b,m);
+                    BIG_dnorm(b);
+                }
+        */
+        k--;
+    }
+    BIG_sdcopy(a,b);
+}
+
+/* Set a=b/c,  b is destroyed. Slow but rarely used. */
+/* SU= 136 */
+
+void BIG_ddiv(BIG a,DBIG b,BIG c)
+{
+    int d,k=0;
+    DBIG m,dr;
+    BIG e,r;
+    BIG_dnorm(b);
+    BIG_dscopy(m,c);
+
+    BIG_zero(a);
+    BIG_zero(e);
+    BIG_inc(e,1);
+
+    while (BIG_dcomp(b,m)>=0)
+    {
+        BIG_fshl(e,1);
+        BIG_dshl(m,1);
+        k++;
+    }
+
+    while (k>0)
+    {
+        BIG_dshr(m,1);
+        BIG_fshr(e,1);
+
+        BIG_dsub(dr,b,m);
+        BIG_dnorm(dr);
+        d=1-((dr[DNLEN-1]>>(CHUNK-1))&1);
+        BIG_dcmove(b,dr,d);
+
+        BIG_add(r,a,e);
+        BIG_norm(r);
+        BIG_cmove(a,r,d);
+        /*
+        		if (BIG_dcomp(b,m)>=0)
+        		{
+        			BIG_add(a,a,e);
+        			BIG_norm(a);
+        			BIG_dsub(b,b,m);
+        			BIG_dnorm(b);
+        		} */
+        k--;
+    }
+}
+
+/* SU= 136 */
+
+void BIG_sdiv(BIG a,BIG c)
+{
+    int d,k=0;
+    BIG m,e,b,r;
+    BIG_norm(a);
+    BIG_copy(b,a);
+    BIG_copy(m,c);
+
+    BIG_zero(a);
+    BIG_zero(e);
+    BIG_inc(e,1);
+
+    while (BIG_comp(b,m)>=0)
+    {
+        BIG_fshl(e,1);
+        BIG_fshl(m,1);
+        k++;
+    }
+
+    while (k>0)
+    {
+        BIG_fshr(m,1);
+        BIG_fshr(e,1);
+
+        BIG_sub(r,b,m);
+        BIG_norm(r);
+        d=1-((r[NLEN-1]>>(CHUNK-1))&1);
+        BIG_cmove(b,r,d);
+
+        BIG_add(r,a,e);
+        BIG_norm(r);
+        BIG_cmove(a,r,d);
+        /*
+        		if (BIG_comp(b,m)>=0)
+        		{
+        			BIG_sub(b,b,m);
+        			BIG_norm(b);
+        			BIG_add(a,a,e);
+        			BIG_norm(a);
+        		} */
+        k--;
+    }
+}
+
+/* return LSB of a */
+int BIG_parity(BIG a)
+{
+    return a[0]%2;
+}
+
+/* return n-th bit of a */
+/* SU= 16 */
+int BIG_bit(BIG a,int n)
+{
+    if (a[n/BASEBITS]&((chunk)1<<(n%BASEBITS))) return 1;
+    else return 0;
+}
+
+/* return NAF value as +/- 1, 3 or 5. x and x3 should be normed.
+nbs is number of bits processed, and nzs is number of trailing 0s detected */
+/* SU= 32 */
+/*
+int BIG_nafbits(BIG x,BIG x3,int i,int *nbs,int *nzs)
+{
+	int j,r,nb;
+
+	nb=BIG_bit(x3,i)-BIG_bit(x,i);
+	*nbs=1;
+	*nzs=0;
+	if (nb==0) return 0;
+	if (i==0) return nb;
+
+    if (nb>0) r=1;
+    else      r=(-1);
+
+    for (j=i-1;j>0;j--)
+    {
+        (*nbs)++;
+        r*=2;
+        nb=BIG_bit(x3,j)-BIG_bit(x,j);
+        if (nb>0) r+=1;
+        if (nb<0) r-=1;
+        if (abs(r)>5) break;
+    }
+
+	if (r%2!=0 && j!=0)
+    { // backtrack
+        if (nb>0) r=(r-1)/2;
+        if (nb<0) r=(r+1)/2;
+        (*nbs)--;
+    }
+
+    while (r%2==0)
+    { // remove trailing zeros
+        r/=2;
+        (*nzs)++;
+        (*nbs)--;
+    }
+    return r;
+}
+*/
+
+/* return last n bits of a, where n is small < BASEBITS */
+/* SU= 16 */
+int BIG_lastbits(BIG a,int n)
+{
+    int msk=(1<<n)-1;
+    BIG_norm(a);
+    return ((int)a[0])&msk;
+}
+
+/* get 8*MODBYTES size random number */
+void BIG_random(BIG m,csprng *rng)
+{
+    int i,b,j=0,r=0;
+    int len=8*MODBYTES;
+
+    BIG_zero(m);
+    /* generate random BIG */
+    for (i=0; i<len; i++)
+    {
+        if (j==0) r=RAND_byte(rng);
+        else r>>=1;
+        b=r&1;
+        BIG_shl(m,1);
+        m[0]+=b;
+        j++;
+        j&=7;
+    }
+
+#ifdef DEBUG_NORM
+    m[NLEN]=0;
+#endif
+}
+
+/* get random BIG from rng, modulo q. Done one bit at a time, so its portable */
+
+void BIG_randomnum(BIG m,BIG q,csprng *rng)
+{
+    int i,b,j=0,r=0;
+    DBIG d;
+    BIG_dzero(d);
+    /* generate random DBIG */
+    for (i=0; i<2*MODBITS; i++)
+    {
+        if (j==0) r=RAND_byte(rng);
+        else r>>=1;
+        b=r&1;
+        BIG_dshl(d,1);
+        d[0]+=b;
+        j++;
+        j&=7;
+    }
+    /* reduce modulo a BIG. Removes bias */
+    BIG_dmod(m,d,q);
+#ifdef DEBUG_NORM
+    m[NLEN]=0;
+#endif
+}
+
+/* Set r=a*b mod m */
+/* SU= 96 */
+void BIG_modmul(BIG r,BIG a,BIG b,BIG m)
+{
+    DBIG d;
+    BIG_mod(a,m);
+    BIG_mod(b,m);
+//BIG_norm(a); BIG_norm(b);
+    BIG_mul(d,a,b);
+    BIG_dmod(r,d,m);
+}
+
+/* Set a=a*a mod m */
+/* SU= 88 */
+void BIG_modsqr(BIG r,BIG a,BIG m)
+{
+    DBIG d;
+    BIG_mod(a,m);
+//BIG_norm(a);
+    BIG_sqr(d,a);
+    BIG_dmod(r,d,m);
+}
+
+/* Set r=-a mod m */
+/* SU= 16 */
+void BIG_modneg(BIG r,BIG a,BIG m)
+{
+    BIG_mod(a,m);
+    BIG_sub(r,m,a);
+    BIG_mod(r,m);
+}
+
+/* Set a=a/b mod m */
+/* SU= 136 */
+void BIG_moddiv(BIG r,BIG a,BIG b,BIG m)
+{
+    DBIG d;
+    BIG z;
+    BIG_mod(a,m);
+    BIG_invmodp(z,b,m);
+//BIG_norm(a); BIG_norm(z);
+    BIG_mul(d,a,z);
+    BIG_dmod(r,d,m);
+}
+
+/* Get jacobi Symbol (a/p). Returns 0, 1 or -1 */
+/* SU= 216 */
+int BIG_jacobi(BIG a,BIG p)
+{
+    int n8,k,m=0;
+    BIG t,x,n,zilch,one;
+    BIG_one(one);
+    BIG_zero(zilch);
+    if (BIG_parity(p)==0 || BIG_comp(a,zilch)==0 || BIG_comp(p,one)<=0) return 0;
+    BIG_norm(a);
+    BIG_copy(x,a);
+    BIG_copy(n,p);
+    BIG_mod(x,p);
+
+    while (BIG_comp(n,one)>0)
+    {
+        if (BIG_comp(x,zilch)==0) return 0;
+        n8=BIG_lastbits(n,3);
+        k=0;
+        while (BIG_parity(x)==0)
+        {
+            k++;
+            BIG_shr(x,1);
+        }
+        if (k%2==1) m+=(n8*n8-1)/8;
+        m+=(n8-1)*(BIG_lastbits(x,2)-1)/4;
+        BIG_copy(t,n);
+
+        BIG_mod(t,x);
+        BIG_copy(n,x);
+        BIG_copy(x,t);
+        m%=2;
+
+    }
+    if (m==0) return 1;
+    else return -1;
+}
+
+/* Set r=1/a mod p. Binary method */
+/* SU= 240 */
+void BIG_invmodp(BIG r,BIG a,BIG p)
+{
+    BIG u,v,x1,x2,t,one;
+    BIG_mod(a,p);
+    BIG_copy(u,a);
+    BIG_copy(v,p);
+    BIG_one(one);
+    BIG_copy(x1,one);
+    BIG_zero(x2);
+
+    while (BIG_comp(u,one)!=0 && BIG_comp(v,one)!=0)
+    {
+        while (BIG_parity(u)==0)
+        {
+            BIG_shr(u,1);
+            if (BIG_parity(x1)!=0)
+            {
+                BIG_add(x1,p,x1);
+                BIG_norm(x1);
+            }
+            BIG_shr(x1,1);
+        }
+        while (BIG_parity(v)==0)
+        {
+            BIG_shr(v,1);
+            if (BIG_parity(x2)!=0)
+            {
+                BIG_add(x2,p,x2);
+                BIG_norm(x2);
+            }
+            BIG_shr(x2,1);
+        }
+        if (BIG_comp(u,v)>=0)
+        {
+            BIG_sub(u,u,v);
+            BIG_norm(u);
+            if (BIG_comp(x1,x2)>=0) BIG_sub(x1,x1,x2);
+            else
+            {
+                BIG_sub(t,p,x2);
+                BIG_add(x1,x1,t);
+            }
+            BIG_norm(x1);
+        }
+        else
+        {
+            BIG_sub(v,v,u);
+            BIG_norm(v);
+            if (BIG_comp(x2,x1)>=0) BIG_sub(x2,x2,x1);
+            else
+            {
+                BIG_sub(t,p,x1);
+                BIG_add(x2,x2,t);
+            }
+            BIG_norm(x2);
+        }
+    }
+    if (BIG_comp(u,one)==0)
+        BIG_copy(r,x1);
+    else
+        BIG_copy(r,x2);
+}
+
+/* set x = x mod 2^m */
+void BIG_mod2m(BIG x,int m)
+{
+    int i,wd,bt;
+    chunk msk;
+//	if (m>=MODBITS) return;
+    wd=m/BASEBITS;
+    bt=m%BASEBITS;
+    msk=((chunk)1<<bt)-1;
+    x[wd]&=msk;
+    for (i=wd+1; i<NLEN; i++) x[i]=0;
+}
+
+// new
+/* Convert to DBIG number from byte array of given length */
+void BIG_dfromBytesLen(DBIG a,char *b,int s)
+{
+    int i,len=s;
+    BIG_dzero(a);
+
+    for (i=0; i<len; i++)
+    {
+        BIG_dshl(a,8);
+        a[0]+=(int)(unsigned char)b[i];
+    }
+#ifdef DEBUG_NORM
+    a[NLEN]=0;
+#endif
+}

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/70e3a3a3/version22/c/build_ec
----------------------------------------------------------------------
diff --git a/version22/c/build_ec b/version22/c/build_ec
new file mode 100644
index 0000000..b5dc735
--- /dev/null
+++ b/version22/c/build_ec
@@ -0,0 +1,22 @@
+
+gcc -std=c99 -c -O3 big.c
+gcc -std=c99 -c -O3 fp.c
+gcc -std=c99 -c -O3 ecp.c
+gcc -std=c99 -c -O3 hash.c
+gcc -std=c99 -c -O3 rand.c
+gcc -std=c99 -c -O3 aes.c
+gcc -std=c99 -c -O3 gcm.c
+gcc -std=c99 -c -O3 oct.c
+gcc -std=c99 -c -O3 rom.c
+
+gcc -std=c99 -c -O3 ff.c
+
+rm amcl.a
+ar rc amcl.a big.o fp.o ecp.o hash.o ff.o
+ar r amcl.a rand.o aes.o gcm.o oct.o rom.o
+
+gcc -std=c99 -O3 testecdh.c ecdh.c randapi.c amcl.a -o testecdh
+gcc -std=c99 -O3 testrsa.c rsa.c randapi.c amcl.a -o testrsa
+gcc -std=c99 -O3 benchtest_ec.c rsa.c amcl.a -o benchtest_ec
+
+rm *.o

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/70e3a3a3/version22/c/build_ec.bat
----------------------------------------------------------------------
diff --git a/version22/c/build_ec.bat b/version22/c/build_ec.bat
new file mode 100644
index 0000000..a49fc25
--- /dev/null
+++ b/version22/c/build_ec.bat
@@ -0,0 +1,22 @@
+
+gcc -std=c99 -c -O3 big.c
+gcc -std=c99 -c -O3 fp.c
+gcc -std=c99 -c -O3 ecp.c
+gcc -std=c99 -c -O3 hash.c
+gcc -std=c99 -c -O3 rand.c
+gcc -std=c99 -c -O3 aes.c
+gcc -std=c99 -c -O3 gcm.c
+gcc -std=c99 -c -O3 oct.c
+gcc -std=c99 -c -O3 rom.c
+
+gcc -std=c99 -c -O3 ff.c
+
+del amcl.a
+ar rc amcl.a big.o fp.o ecp.o hash.o ff.o
+ar r amcl.a rand.o aes.o gcm.o oct.o rom.o
+
+gcc -std=c99 -O3 testecdh.c ecdh.c randapi.c amcl.a -o testecdh.exe
+gcc -std=c99 -O3 testrsa.c rsa.c randapi.c amcl.a -o testrsa.exe
+gcc -std=c99 -O3 benchtest_ec.c rsa.c amcl.a -o benchtest_ec.exe
+
+del *.o

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/70e3a3a3/version22/c/build_pair
----------------------------------------------------------------------
diff --git a/version22/c/build_pair b/version22/c/build_pair
new file mode 100644
index 0000000..6b6bae2
--- /dev/null
+++ b/version22/c/build_pair
@@ -0,0 +1,27 @@
+
+gcc -std=c99 -c -O3 big.c
+gcc -std=c99 -c -O3 fp.c
+gcc -std=c99 -c -O3 ecp.c
+gcc -std=c99 -c -O3 hash.c
+gcc -std=c99 -c -O3 rand.c
+gcc -std=c99 -c -O3 aes.c
+gcc -std=c99 -c -O3 gcm.c
+gcc -std=c99 -c -O3 oct.c
+gcc -std=c99 -c -O3 rom.c
+
+gcc -std=c99 -c -O3 fp2.c
+gcc -std=c99 -c -O3 ecp2.c
+gcc -std=c99 -c -O3 fp4.c
+gcc -std=c99 -c -O3 fp12.c
+gcc -std=c99 -c -O3 pair.c
+
+rm amcl.a
+ar rc amcl.a big.o fp.o ecp.o hash.o
+ar r amcl.a rand.o aes.o gcm.o oct.o rom.o
+
+ar r amcl.a pair.o fp2.o ecp2.o fp4.o fp12.o
+
+gcc -std=c99 -O3 testmpin.c mpin.c randapi.c amcl.a -o testmpin
+gcc -std=c99 -O3 benchtest_pair.c amcl.a -o benchtest_pair
+
+rm *.o

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/70e3a3a3/version22/c/build_pair.bat
----------------------------------------------------------------------
diff --git a/version22/c/build_pair.bat b/version22/c/build_pair.bat
new file mode 100644
index 0000000..88b5daf
--- /dev/null
+++ b/version22/c/build_pair.bat
@@ -0,0 +1,27 @@
+
+gcc -std=c99 -c -O3 big.c
+gcc -std=c99 -c -O3 fp.c
+gcc -std=c99 -c -O3 ecp.c
+gcc -std=c99 -c -O3 hash.c
+gcc -std=c99 -c -O3 rand.c
+gcc -std=c99 -c -O3 aes.c
+gcc -std=c99 -c -O3 gcm.c
+gcc -std=c99 -c -O3 oct.c
+gcc -std=c99 -c -O3 rom.c
+
+gcc -std=c99 -c -O3 fp2.c
+gcc -std=c99 -c -O3 ecp2.c
+gcc -std=c99 -c -O3 fp4.c
+gcc -std=c99 -c -O3 fp12.c
+gcc -std=c99 -c -O3 pair.c
+
+del amcl.a
+ar rc amcl.a big.o fp.o ecp.o hash.o
+ar r amcl.a rand.o aes.o gcm.o oct.o rom.o
+
+ar r amcl.a pair.o fp2.o ecp2.o fp4.o fp12.o
+
+gcc -std=c99 -O3 testmpin.c mpin.c randapi.c amcl.a -o testmpin.exe
+gcc -std=c99 -O3 benchtest_pair.c amcl.a -o benchtest_pair.exe
+
+del *.o

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/70e3a3a3/version22/c/ca.crt
----------------------------------------------------------------------
diff --git a/version22/c/ca.crt b/version22/c/ca.crt
new file mode 100644
index 0000000..e3ad02f
--- /dev/null
+++ b/version22/c/ca.crt
@@ -0,0 +1,23 @@
+-----BEGIN CERTIFICATE-----
+MIID6zCCAtOgAwIBAgIJALJxywTGMUA7MA0GCSqGSIb3DQEBCwUAMIGLMQswCQYD
+VQQGEwJJRTEQMA4GA1UECAwHSXJlbGFuZDEPMA0GA1UEBwwGRHVibGluMQ8wDQYD
+VQQKDAZNSVJBQ0wxDTALBgNVBAsMBGxhYnMxEzARBgNVBAMMCk1pa2UgU2NvdHQx
+JDAiBgkqhkiG9w0BCQEWFW1pa2Uuc2NvdHRAbWlyYWNsLmNvbTAeFw0xNjA2MzAx
+NzQyNDFaFw0yMTA2MzAxNzQyNDFaMIGLMQswCQYDVQQGEwJJRTEQMA4GA1UECAwH
+SXJlbGFuZDEPMA0GA1UEBwwGRHVibGluMQ8wDQYDVQQKDAZNSVJBQ0wxDTALBgNV
+BAsMBGxhYnMxEzARBgNVBAMMCk1pa2UgU2NvdHQxJDAiBgkqhkiG9w0BCQEWFW1p
+a2Uuc2NvdHRAbWlyYWNsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAPCTPcPWgiI0ka5Czd0ZzW+gTaMEe9QW7FGu5+9fS6ALrCpdbxdwDX8+OQXZ
+uQJpLYEAIq1pDh3fVQguH/jUM9gQQrS2Lmz3KhXC/J3yv85FRotCGv13ztapMedT
+y2IxzbtPvoQQc+IAlUPX6DtD8JqBoAstrlQUnkMChKztMGR2OERdjNzXmXm+KMMP
+lZzk+EvRwCornVA+SB5QAWj7y/3ISFo0y1WG8ewoQEx3HQYrjXbQP1VTdiLW7dHP
+QP86XKoTMtTBEYWuFhKB9ClCeu4Qqqxqa9UPIVfdro7SoZScCt+OX4KhzLnOCFup
+oLxE+yTDhDpYcCcmI1yglCv9DpMCAwEAAaNQME4wHQYDVR0OBBYEFFH18YEMoxms
+7121N/nQ+Wm3b5smMB8GA1UdIwQYMBaAFFH18YEMoxms7121N/nQ+Wm3b5smMAwG
+A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBALCUob0y2O4DSzsqG76yrtCx
+XWxDdgjSkHKzwFK62BzZK5EuCDJrVgCyoLX0SvYvoT9x0wtS+bxJ7TNEGn7Rkp5/
+iSQCUSF7sVRoHqzErk70xVKKDy5FS+zre8k08nJrtRg2u1PmY95NO1SE96BtUVLs
++8rQuqEX283tqlmqE/SF2+lxOb0WaVrya4oCJfj/XT83pRTcd5w9i7huWltMbKba
+gkmlQ/5q9Ayp/Jh1lLXmxr+/xEbZ2xEop/y+mgVF0vLxap7R5toBA0Yk7vvirlYv
+0hZGqGi5lBc9VeUqm1H/7XCi5xRU3AtJ4QRk4Z1xUa4qAPKfiqlPKd1dVe3Ah3w=
+-----END CERTIFICATE-----

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/70e3a3a3/version22/c/eccert.pem
----------------------------------------------------------------------
diff --git a/version22/c/eccert.pem b/version22/c/eccert.pem
new file mode 100644
index 0000000..b9dfca5
--- /dev/null
+++ b/version22/c/eccert.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICqjCCAZICCQCk9jKdJYtnjDANBgkqhkiG9w0BAQsFADCBizELMAkGA1UEBhMC
+SUUxEDAOBgNVBAgMB0lyZWxhbmQxDzANBgNVBAcMBkR1YmxpbjEPMA0GA1UECgwG
+TUlSQUNMMQ0wCwYDVQQLDARsYWJzMRMwEQYDVQQDDApNaWtlIFNjb3R0MSQwIgYJ
+KoZIhvcNAQkBFhVtaWtlLnNjb3R0QG1pcmFjbC5jb20wHhcNMTYwNjMwMTc0NjQ4
+WhcNMTYwNzMwMTc0NjQ4WjCBjDELMAkGA1UEBhMCSUUxEDAOBgNVBAgMB0lyZWxh
+bmQxDzANBgNVBAcMBkR1YmxpbjEPMA0GA1UECgwGTUlSQUNMMQ0wCwYDVQQLDARs
+YWJzMRgwFgYDVQQDDA9LZWFsYW4gTWNDdXNrZXIxIDAeBgkqhkiG9w0BCQEWEWtl
+YWxhbkBtaXJhY2wuY29tMDkwFAYHKoZIzj0CAQYJKwYBBAHaRw8BAyEASiRQmhO9
+PP+SqodOhXYrnSlcyAOog63E6a4KLDFvAzEwDQYJKoZIhvcNAQELBQADggEBALBy
+fCM/EhdqWBrEnDHtH2/U8xr1eSylHdcfnDSDR+X6KXH5rIJ/397lZQMHB6QSsEiV
+rWzfFDFPPjDN3xEDsZw09ZTT+L8Wi5P3UKR1gtawQCx3ciKEywAU1CU2dV05gvye
+bqIsbFUyH7jOlj6/1hIx9zaiLcoEex6D55MYQuWo664HF3CNdJFk1k4HF+fclRhy
+l4iryp0F9p0Wl5vyn96kg0NwaBZG860oCWDHZsjRq1JeSSaRf9CKNXWbQwjByeEc
+DphpprqmoVcI60cC0TvZZm1x4y7vjCXLD6uCDw3P7fnSp40yce64+IKUr8/cS+QY
+us58KHdLaLXsojZHL3c=
+-----END CERTIFICATE-----

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/70e3a3a3/version22/c/ecdh.c
----------------------------------------------------------------------
diff --git a/version22/c/ecdh.c b/version22/c/ecdh.c
new file mode 100644
index 0000000..74694f7
--- /dev/null
+++ b/version22/c/ecdh.c
@@ -0,0 +1,751 @@
+/*
+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.
+*/
+
+/* ECDH/ECIES/ECDSA Functions - see main program below */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include "ecdh.h"
+
+#define ROUNDUP(a,b) ((a)-1)/(b)+1
+
+/* general purpose hash function w=hash(p|n|x|y) */
+/* pad or truncate ouput to length pad if pad!=0 */
+static void hashit(int sha,octet *p,int n,octet *x,octet *w,int pad)
+{
+    int i,c[4],hlen;
+    hash256 sha256;
+    hash512 sha512;
+    char hh[64];
+
+    switch (sha)
+    {
+    case SHA256:
+        HASH256_init(&sha256);
+        break;
+    case SHA384:
+        HASH384_init(&sha512);
+        break;
+    case SHA512:
+        HASH512_init(&sha512);
+        break;
+    }
+
+    hlen=sha;
+
+    for (i=0; i<p->len; i++)
+    {
+        switch(sha)
+        {
+        case SHA256:
+            HASH256_process(&sha256,p->val[i]);
+            break;
+        case SHA384:
+            HASH384_process(&sha512,p->val[i]);
+            break;
+        case SHA512:
+            HASH512_process(&sha512,p->val[i]);
+            break;
+        }
+    }
+    if (n>0)
+    {
+        c[0]=(n>>24)&0xff;
+        c[1]=(n>>16)&0xff;
+        c[2]=(n>>8)&0xff;
+        c[3]=(n)&0xff;
+        for (i=0; i<4; i++)
+        {
+            switch(sha)
+            {
+            case SHA256:
+                HASH256_process(&sha256,c[i]);
+                break;
+            case SHA384:
+                HASH384_process(&sha512,c[i]);
+                break;
+            case SHA512:
+                HASH512_process(&sha512,c[i]);
+                break;
+            }
+        }
+    }
+    if (x!=NULL) for (i=0; i<x->len; i++)
+        {
+            switch(sha)
+            {
+            case SHA256:
+                HASH256_process(&sha256,x->val[i]);
+                break;
+            case SHA384:
+                HASH384_process(&sha512,x->val[i]);
+                break;
+            case SHA512:
+                HASH512_process(&sha512,x->val[i]);
+                break;
+            }
+        }
+
+    switch (sha)
+    {
+    case SHA256:
+        HASH256_hash(&sha256,hh);
+        break;
+    case SHA384:
+        HASH384_hash(&sha512,hh);
+        break;
+    case SHA512:
+        HASH512_hash(&sha512,hh);
+        break;
+    }
+
+    OCT_empty(w);
+    if (!pad)
+        OCT_jbytes(w,hh,hlen);
+    else
+    {
+        if (pad<=hlen)
+            OCT_jbytes(w,hh,pad);
+        else
+        {
+            OCT_jbytes(w,hh,hlen);
+            OCT_jbyte(w,0,pad-hlen);
+        }
+    }
+    return;
+}
+
+/* Hash octet p to octet w */
+void HASH(int sha,octet *p,octet *w)
+{
+    hashit(sha,p,-1,NULL,w,0);
+}
+
+/* Calculate HMAC of m using key k. HMAC is tag of length olen */
+int HMAC(int sha,octet *m,octet *k,int olen,octet *tag)
+{
+    /* Input is from an octet m        *
+     * olen is requested output length in bytes. k is the key  *
+     * The output is the calculated tag */
+    int hlen,b;
+    char h[128],k0[128];
+    octet H= {0,sizeof(h),h};
+    octet K0= {0,sizeof(k0),k0};
+
+    hlen=sha;
+    if (hlen>32) b=128;
+    else b=64;
+
+    if (olen<4 /*|| olen>hlen*/) return 0;
+
+    if (k->len > b) hashit(sha,k,-1,NULL,&K0,0);
+    else            OCT_copy(&K0,k);
+
+    OCT_jbyte(&K0,0,b-K0.len);
+
+    OCT_xorbyte(&K0,0x36);
+
+    hashit(sha,&K0,-1,m,&H,0);
+
+    OCT_xorbyte(&K0,0x6a);   /* 0x6a = 0x36 ^ 0x5c */
+    hashit(sha,&K0,-1,&H,&H,olen);
+
+    OCT_empty(tag);
+
+    OCT_jbytes(tag,H.val,olen);
+
+    return 1;
+}
+
+/* Key Derivation Functions */
+/* Input octet z */
+/* Output key of length olen */
+/*
+void KDF1(octet *z,int olen,octet *key)
+{
+    char h[32];
+	octet H={0,sizeof(h),h};
+    int counter,cthreshold;
+    int hlen=32;
+
+    OCT_empty(key);
+
+    cthreshold=ROUNDUP(olen,hlen);
+
+    for (counter=0;counter<cthreshold;counter++)
+    {
+        hashit(z,counter,NULL,NULL,&H);
+        if (key->len+hlen>olen) OCT_jbytes(key,H.val,olen%hlen);
+        else                    OCT_joctet(key,&H);
+    }
+}
+*/
+void KDF2(int sha,octet *z,octet *p,int olen,octet *key)
+{
+    /* NOTE: the parameter olen is the length of the output k in bytes */
+    char h[64];
+    octet H= {0,sizeof(h),h};
+    int counter,cthreshold;
+    int hlen=sha;
+
+    OCT_empty(key);
+
+    cthreshold=ROUNDUP(olen,hlen);
+
+    for (counter=1; counter<=cthreshold; counter++)
+    {
+        hashit(sha,z,counter,p,&H,0);
+        if (key->len+hlen>olen)  OCT_jbytes(key,H.val,olen%hlen);
+        else                     OCT_joctet(key,&H);
+    }
+
+}
+
+/* Password based Key Derivation Function */
+/* Input password p, salt s, and repeat count */
+/* Output key of length olen */
+void PBKDF2(int sha,octet *p,octet *s,int rep,int olen,octet *key)
+{
+    int i,j,len,d=ROUNDUP(olen,sha);
+    char f[64],u[64];   /*****/
+    octet F= {0,sizeof(f),f};
+    octet U= {0,sizeof(u),u};
+    OCT_empty(key);
+
+    for (i=1; i<=d; i++)
+    {
+        len=s->len;
+        OCT_jint(s,i,4);
+
+        HMAC(sha,s,p,sha,&F);  /* sha not EFS */
+
+        s->len=len;
+        OCT_copy(&U,&F);
+        for (j=2; j<=rep; j++)
+        {
+            HMAC(sha,&U,p,sha,&U); /* sha not EFS */
+            OCT_xor(&F,&U);
+        }
+
+        OCT_joctet(key,&F);
+    }
+
+    OCT_chop(key,NULL,olen);
+}
+
+/* AES encryption/decryption. Encrypt byte array M using key K and returns ciphertext */
+void AES_CBC_IV0_ENCRYPT(octet *k,octet *m,octet *c)
+{
+    /* AES CBC encryption, with Null IV and key k */
+    /* Input is from an octet string m, output is to an octet string c */
+    /* Input is padded as necessary to make up a full final block */
+    amcl_aes a;
+    int fin;
+    int i,j,ipt,opt;
+    char buff[16];
+    int padlen;
+
+    OCT_clear(c);
+    if (m->len==0) return;
+    AES_init(&a,CBC,k->len,k->val,NULL);
+
+    ipt=opt=0;
+    fin=0;
+    for(;;)
+    {
+        for (i=0; i<16; i++)
+        {
+            if (ipt<m->len) buff[i]=m->val[ipt++];
+            else
+            {
+                fin=1;
+                break;
+            }
+        }
+        if (fin) break;
+        AES_encrypt(&a,buff);
+        for (i=0; i<16; i++)
+            if (opt<c->max) c->val[opt++]=buff[i];
+    }
+
+    /* last block, filled up to i-th index */
+
+    padlen=16-i;
+    for (j=i; j<16; j++) buff[j]=padlen;
+    AES_encrypt(&a,buff);
+    for (i=0; i<16; i++)
+        if (opt<c->max) c->val[opt++]=buff[i];
+    AES_end(&a);
+    c->len=opt;
+}
+
+/* decrypts and returns TRUE if all consistent, else returns FALSE */
+int AES_CBC_IV0_DECRYPT(octet *k,octet *c,octet *m)
+{
+    /* padding is removed */
+    amcl_aes a;
+    int i,ipt,opt,ch;
+    char buff[16];
+    int fin,bad;
+    int padlen;
+    ipt=opt=0;
+
+    OCT_clear(m);
+    if (c->len==0) return 1;
+    ch=c->val[ipt++];
+
+    AES_init(&a,CBC,k->len,k->val,NULL);
+    fin=0;
+
+    for(;;)
+    {
+        for (i=0; i<16; i++)
+        {
+            buff[i]=ch;
+            if (ipt>=c->len)
+            {
+                fin=1;
+                break;
+            }
+            else ch=c->val[ipt++];
+        }
+        AES_decrypt(&a,buff);
+        if (fin) break;
+        for (i=0; i<16; i++)
+            if (opt<m->max) m->val[opt++]=buff[i];
+    }
+    AES_end(&a);
+    bad=0;
+    padlen=buff[15];
+    if (i!=15 || padlen<1 || padlen>16) bad=1;
+    if (padlen>=2 && padlen<=16)
+        for (i=16-padlen; i<16; i++) if (buff[i]!=padlen) bad=1;
+
+    if (!bad) for (i=0; i<16-padlen; i++)
+            if (opt<m->max) m->val[opt++]=buff[i];
+
+    m->len=opt;
+    if (bad) return 0;
+    return 1;
+}
+
+/* Calculate a public/private EC GF(p) key pair. W=S.G mod EC(p),
+ * where S is the secret key and W is the public key
+ * and G is fixed generator.
+ * If RNG is NULL then the private key is provided externally in S
+ * otherwise it is generated randomly internally */
+int ECP_KEY_PAIR_GENERATE(csprng *RNG,octet* S,octet *W)
+{
+    BIG r,gx,s;
+    ECP G;
+    int res=0;
+    BIG_rcopy(gx,CURVE_Gx);
+
+#if CURVETYPE!=MONTGOMERY
+    BIG gy;
+    BIG_rcopy(gy,CURVE_Gy);
+    ECP_set(&G,gx,gy);
+#else
+    ECP_set(&G,gx);
+#endif
+
+    BIG_rcopy(r,CURVE_Order);
+    if (RNG!=NULL)
+    {
+        BIG_randomnum(s,r,RNG);
+    }
+    else
+    {
+        BIG_fromBytes(s,S->val);
+        BIG_mod(s,r);
+    }
+
+#ifdef AES_S
+    BIG_mod2m(s,2*AES_S);
+//	BIG_toBytes(S->val,s);
+#endif
+
+    ECP_mul(&G,s);
+#if CURVETYPE!=MONTGOMERY
+    ECP_get(gx,gy,&G);
+#else
+    ECP_get(gx,&G);
+    /*
+    	ECP_rhs(gy,gx);
+    	FP_sqrt(gy,gy);
+    	FP_neg(gy,gy);
+    	FP_inv(gy,gy);
+    	FP_mul(r,gx,gy);
+    	FP_reduce(r);
+
+        BIG_zero(gy);
+    	BIG_inc(gy,486664);
+    	FP_neg(gy,gy);
+    	FP_sqrt(gy,gy);
+    	FP_reduce(gy);
+    	FP_mul(r,r,gy);
+    	FP_reduce(r);
+
+    	printf("x= "); BIG_output(r); printf("\n");
+
+    	BIG_copy(r,gx);
+    	BIG_dec(r,1);
+    	BIG_copy(gy,gx);
+    	BIG_inc(gy,1);
+    	FP_inv(gy,gy);
+    	FP_mul(r,r,gy);
+    	FP_reduce(r);
+
+    	printf("y= "); BIG_output(r); printf("\n");
+
+    	BIG_zero(r);
+    	BIG_inc(r,121665);
+    	BIG_zero(gy);
+    	BIG_inc(gy,121666);
+    	FP_inv(gy,gy);
+    	FP_mul(r,r,gy);
+    	FP_neg(r,r);
+    	FP_reduce(r);
+
+    	printf("d= "); BIG_output(r); printf("\n");
+    */
+
+#endif
+
+    S->len=EGS;
+    BIG_toBytes(S->val,s);
+
+#if CURVETYPE!=MONTGOMERY
+    W->len=2*EFS+1;
+    W->val[0]=4;
+    BIG_toBytes(&(W->val[1]),gx);
+    BIG_toBytes(&(W->val[EFS+1]),gy);
+#else
+    W->len=EFS+1;
+    W->val[0]=2;
+    BIG_toBytes(&(W->val[1]),gx);
+#endif
+
+    return res;
+}
+
+/* validate public key. Set full=true for fuller check */
+int ECP_PUBLIC_KEY_VALIDATE(int full,octet *W)
+{
+    BIG q,r,wx;
+    ECP WP;
+    int valid;
+    int res=0;
+
+    BIG_rcopy(q,Modulus);
+    BIG_rcopy(r,CURVE_Order);
+
+    BIG_fromBytes(wx,&(W->val[1]));
+    if (BIG_comp(wx,q)>=0) res=ECDH_INVALID_PUBLIC_KEY;
+#if CURVETYPE!=MONTGOMERY
+    BIG wy;
+    BIG_fromBytes(wy,&(W->val[EFS+1]));
+    if (BIG_comp(wy,q)>=0) res=ECDH_INVALID_PUBLIC_KEY;
+#endif
+    if (res==0)
+    {
+
+#if CURVETYPE!=MONTGOMERY
+        valid=ECP_set(&WP,wx,wy);
+#else
+        valid=ECP_set(&WP,wx);
+#endif
+        if (!valid || ECP_isinf(&WP)) res=ECDH_INVALID_PUBLIC_KEY;
+        if (res==0 && full)
+        {
+
+            ECP_mul(&WP,r);
+            if (!ECP_isinf(&WP)) res=ECDH_INVALID_PUBLIC_KEY;
+        }
+    }
+
+    return res;
+}
+
+/* IEEE-1363 Diffie-Hellman online calculation Z=S.WD */
+int ECPSVDP_DH(octet *S,octet *WD,octet *Z)
+{
+    BIG r,s,wx;
+    int valid;
+    ECP W;
+    int res=0;
+
+    BIG_fromBytes(s,S->val);
+
+    BIG_fromBytes(wx,&(WD->val[1]));
+#if CURVETYPE!=MONTGOMERY
+    BIG wy;
+    BIG_fromBytes(wy,&(WD->val[EFS+1]));
+    valid=ECP_set(&W,wx,wy);
+#else
+    valid=ECP_set(&W,wx);
+#endif
+    if (!valid) res=ECDH_ERROR;
+    if (res==0)
+    {
+        BIG_rcopy(r,CURVE_Order);
+        BIG_mod(s,r);
+
+        ECP_mul(&W,s);
+        if (ECP_isinf(&W)) res=ECDH_ERROR;
+        else
+        {
+#if CURVETYPE!=MONTGOMERY
+            ECP_get(wx,wx,&W);
+#else
+            ECP_get(wx,&W);
+#endif
+            Z->len=MODBYTES;
+            BIG_toBytes(Z->val,wx);
+        }
+    }
+    return res;
+}
+
+#if CURVETYPE!=MONTGOMERY
+
+/* IEEE ECDSA Signature, C and D are signature on F using private key S */
+int ECPSP_DSA(int sha,csprng *RNG,octet *K,octet *S,octet *F,octet *C,octet *D)
+{
+    char h[128];
+    octet H= {0,sizeof(h),h};
+
+    BIG gx,gy,r,s,f,c,d,u,vx,w;
+    ECP G,V;
+
+    hashit(sha,F,-1,NULL,&H,sha);
+    BIG_rcopy(gx,CURVE_Gx);
+    BIG_rcopy(gy,CURVE_Gy);
+    BIG_rcopy(r,CURVE_Order);
+
+    BIG_fromBytes(s,S->val);
+
+    int hlen=H.len;
+    if (H.len>MODBYTES) hlen=MODBYTES;
+    BIG_fromBytesLen(f,H.val,hlen);
+
+    ECP_set(&G,gx,gy);
+
+    do
+    {
+        if (RNG!=NULL)
+        {
+            BIG_randomnum(u,r,RNG);
+            BIG_randomnum(w,r,RNG); /* randomize calculation */
+        }
+        else
+        {
+            BIG_fromBytes(u,K->val);
+            BIG_mod(u,r);
+        }
+
+#ifdef AES_S
+        BIG_mod2m(u,2*AES_S);
+#endif
+        ECP_copy(&V,&G);
+        ECP_mul(&V,u);
+
+        ECP_get(vx,vx,&V);
+
+        BIG_copy(c,vx);
+        BIG_mod(c,r);
+        if (BIG_iszilch(c)) continue;
+        if (RNG!=NULL)
+        {
+            BIG_modmul(u,u,w,r);
+        }
+
+        BIG_invmodp(u,u,r);
+        BIG_modmul(d,s,c,r);
+
+        BIG_add(d,f,d);
+        if (RNG!=NULL)
+        {
+            BIG_modmul(d,d,w,r);
+        }
+
+        BIG_modmul(d,u,d,r);
+
+    }
+    while (BIG_iszilch(d));
+
+    C->len=D->len=EGS;
+
+    BIG_toBytes(C->val,c);
+    BIG_toBytes(D->val,d);
+
+    return 0;
+}
+
+/* IEEE1363 ECDSA Signature Verification. Signature C and D on F is verified using public key W */
+int ECPVP_DSA(int sha,octet *W,octet *F, octet *C,octet *D)
+{
+    char h[128];
+    octet H= {0,sizeof(h),h};
+
+    BIG r,gx,gy,wx,wy,f,c,d,h2;
+    int res=0;
+    ECP G,WP;
+    int valid;
+
+    hashit(sha,F,-1,NULL,&H,sha);
+    BIG_rcopy(gx,CURVE_Gx);
+    BIG_rcopy(gy,CURVE_Gy);
+    BIG_rcopy(r,CURVE_Order);
+
+    OCT_shl(C,C->len-MODBYTES);
+    OCT_shl(D,D->len-MODBYTES);
+
+    BIG_fromBytes(c,C->val);
+    BIG_fromBytes(d,D->val);
+
+    int hlen=H.len;
+    if (hlen>MODBYTES) hlen=MODBYTES;
+
+    BIG_fromBytesLen(f,H.val,hlen);
+
+    //BIG_fromBytes(f,H.val);
+
+    if (BIG_iszilch(c) || BIG_comp(c,r)>=0 || BIG_iszilch(d) || BIG_comp(d,r)>=0)
+        res=ECDH_INVALID;
+
+    if (res==0)
+    {
+        BIG_invmodp(d,d,r);
+        BIG_modmul(f,f,d,r);
+        BIG_modmul(h2,c,d,r);
+
+        ECP_set(&G,gx,gy);
+
+        BIG_fromBytes(wx,&(W->val[1]));
+        BIG_fromBytes(wy,&(W->val[EFS+1]));
+
+        valid=ECP_set(&WP,wx,wy);
+
+        if (!valid) res=ECDH_ERROR;
+        else
+        {
+            ECP_mul2(&WP,&G,h2,f);
+
+            if (ECP_isinf(&WP)) res=ECDH_INVALID;
+            else
+            {
+                ECP_get(d,d,&WP);
+                BIG_mod(d,r);
+                if (BIG_comp(d,c)!=0) res=ECDH_INVALID;
+            }
+        }
+    }
+
+    return res;
+}
+
+/* IEEE1363 ECIES encryption. Encryption of plaintext M uses public key W and produces ciphertext V,C,T */
+void ECP_ECIES_ENCRYPT(int sha,octet *P1,octet *P2,csprng *RNG,octet *W,octet *M,int tlen,octet *V,octet *C,octet *T)
+{
+
+    int i,len;
+    char z[EFS],vz[3*EFS+1],k[2*EAS],k1[EAS],k2[EAS],l2[8],u[EFS];
+    octet Z= {0,sizeof(z),z};
+    octet VZ= {0,sizeof(vz),vz};
+    octet K= {0,sizeof(k),k};
+    octet K1= {0,sizeof(k1),k1};
+    octet K2= {0,sizeof(k2),k2};
+    octet L2= {0,sizeof(l2),l2};
+    octet U= {0,sizeof(u),u};
+
+    if (ECP_KEY_PAIR_GENERATE(RNG,&U,V)!=0) return;
+    if (ECPSVDP_DH(&U,W,&Z)!=0) return;
+
+    OCT_copy(&VZ,V);
+    OCT_joctet(&VZ,&Z);
+
+    KDF2(sha,&VZ,P1,2*EAS,&K);
+
+    K1.len=K2.len=EAS;
+    for (i=0; i<EAS; i++)
+    {
+        K1.val[i]=K.val[i];
+        K2.val[i]=K.val[EAS+i];
+    }
+
+    AES_CBC_IV0_ENCRYPT(&K1,M,C);
+
+    OCT_jint(&L2,P2->len,8);
+
+    len=C->len;
+    OCT_joctet(C,P2);
+    OCT_joctet(C,&L2);
+    HMAC(sha,C,&K2,tlen,T);
+    C->len=len;
+}
+
+/* IEEE1363 ECIES decryption. Decryption of ciphertext V,C,T using private key U outputs plaintext M */
+int ECP_ECIES_DECRYPT(int sha,octet *P1,octet *P2,octet *V,octet *C,octet *T,octet *U,octet *M)
+{
+
+    int i,len;
+    char z[EFS],vz[3*EFS+1],k[2*EAS],k1[EAS],k2[EAS],l2[8],tag[32];
+    octet Z= {0,sizeof(z),z};
+    octet VZ= {0,sizeof(vz),vz};
+    octet K= {0,sizeof(k),k};
+    octet K1= {0,sizeof(k1),k1};
+    octet K2= {0,sizeof(k2),k2};
+    octet L2= {0,sizeof(l2),l2};
+    octet TAG= {0,sizeof(tag),tag};
+
+    if (ECPSVDP_DH(U,V,&Z)!=0) return 0;
+
+    OCT_copy(&VZ,V);
+    OCT_joctet(&VZ,&Z);
+
+    KDF2(sha,&VZ,P1,EFS,&K);
+
+    K1.len=K2.len=EAS;
+    for (i=0; i<EAS; i++)
+    {
+        K1.val[i]=K.val[i];
+        K2.val[i]=K.val[EAS+i];
+    }
+
+    if (!AES_CBC_IV0_DECRYPT(&K1,C,M)) return 0;
+
+    OCT_jint(&L2,P2->len,8);
+
+    len=C->len;
+    OCT_joctet(C,P2);
+    OCT_joctet(C,&L2);
+    HMAC(sha,C,&K2,T->len,&TAG);
+    C->len=len;
+
+    if (!OCT_comp(T,&TAG)) return 0;
+
+    return 1;
+
+}
+
+#endif

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/70e3a3a3/version22/c/ecdh.h
----------------------------------------------------------------------
diff --git a/version22/c/ecdh.h b/version22/c/ecdh.h
new file mode 100644
index 0000000..7d0536b
--- /dev/null
+++ b/version22/c/ecdh.h
@@ -0,0 +1,206 @@
+/*
+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 ecdh.h
+ * @author Mike Scott and Kealan McCusker
+ * @date 2nd June 2015
+ * @brief ECDH Header file for implementation of standard EC protocols
+ *
+ * declares functions
+ *
+ */
+
+#ifndef ECDH_H
+#define ECDH_H
+
+#include "amcl.h"
+
+#define EAS 16 /**< Symmetric Key size - 128 bits */
+#define EGS MODBYTES  /**< ECC Group Size in bytes */
+#define EFS MODBYTES  /**< ECC Field Size in bytes */
+
+#define HASH_TYPE_ECC SHA256  /**< Hash type */
+
+#define ECDH_OK                     0     /**< Function completed without error */
+/*#define ECDH_DOMAIN_ERROR          -1*/
+#define ECDH_INVALID_PUBLIC_KEY    -2	/**< Public Key is Invalid */
+#define ECDH_ERROR                 -3	/**< ECDH Internal Error */
+#define ECDH_INVALID               -4	/**< ECDH Internal Error */
+/*#define ECDH_DOMAIN_NOT_FOUND      -5
+#define ECDH_OUT_OF_MEMORY         -6
+#define ECDH_DIV_BY_ZERO           -7
+#define ECDH_BAD_ASSUMPTION        -8*/
+
+/* ECDH Auxiliary Functions */
+
+
+/**	@brief hash an octet into another octet
+ *
+ 	@param h is the hash type
+	@param I input octet
+	@param O output octet - H(I)
+ */
+extern void HASH(int h,octet *I,octet *O);
+/**	@brief HMAC of message M using key K to create tag of length len in octet tag
+ *
+	IEEE-1363 MAC1 function. Uses SHA256 internally.
+	@param h is the hash type
+	@param M input message octet
+	@param K input encryption key
+	@param len is output desired length of HMAC tag
+	@param tag is the output HMAC
+	@return 0 for bad parameters, else 1
+ */
+extern int HMAC(int h,octet *M,octet *K,int len,octet *tag);
+
+/*extern void KDF1(octet *,int,octet *);*/
+
+/**	@brief Key Derivation Function - generates key K from inputs Z and P
+ *
+	IEEE-1363 KDF2 Key Derivation Function. Uses SHA256 internally.
+	@param h is the hash type
+	@param Z input octet
+	@param P input key derivation parameters - can be NULL
+	@param len is output desired length of key
+	@param K is the derived key
+ */
+extern void KDF2(int h,octet *Z,octet *P,int len,octet *K);
+/**	@brief Password Based Key Derivation Function - generates key K from password, salt and repeat counter
+ *
+	PBKDF2 Password Based Key Derivation Function. Uses SHA256 internally.
+	@param h is the hash type
+	@param P input password
+	@param S input salt
+	@param rep Number of times to be iterated.
+	@param len is output desired length
+	@param K is the derived key
+ */
+extern void PBKDF2(int h,octet *P,octet *S,int rep,int len,octet *K);
+/**	@brief AES encrypts a plaintext to a ciphtertext
+ *
+	IEEE-1363 AES_CBC_IV0_ENCRYPT function. Encrypts in CBC mode with a zero IV, padding as necessary to create a full final block.
+	@param K AES key
+	@param P input plaintext octet
+	@param C output ciphertext octet
+ */
+extern void AES_CBC_IV0_ENCRYPT(octet *K,octet *P,octet *C);
+/**	@brief AES encrypts a plaintext to a ciphtertext
+ *
+	IEEE-1363 AES_CBC_IV0_DECRYPT function. Decrypts in CBC mode with a zero IV.
+	@param K AES key
+	@param C input ciphertext octet
+	@param P output plaintext octet
+	@return 0 if bad input, else 1
+ */
+extern int AES_CBC_IV0_DECRYPT(octet *K,octet *C,octet *P);
+
+/* ECDH primitives - support functions */
+/**	@brief Generate an ECC public/private key pair
+ *
+	@param R is a pointer to a cryptographically secure random number generator
+	@param s the private key, an output internally randomly generated if R!=NULL, otherwise must be provided as an input
+	@param W the output public key, which is s.G, where G is a fixed generator
+	@return 0 or an error code
+ */
+extern int  ECP_KEY_PAIR_GENERATE(csprng *R,octet *s,octet *W);
+/**	@brief Validate an ECC public key
+ *
+	@param f if = 0 just does some simple checks, else tests that W is of the correct order
+	@param W the input public key to be validated
+	@return 0 if public key is OK, or an error code
+ */
+extern int  ECP_PUBLIC_KEY_VALIDATE(int f,octet *W);
+
+/* ECDH primitives */
+
+/**	@brief Generate Diffie-Hellman shared key
+ *
+	IEEE-1363 Diffie-Hellman shared secret calculation
+	@param s is the input private key,
+	@param W the input public key of the other party
+	@param K the output shared key, in fact the x-coordinate of s.W
+	@return 0 or an error code
+ */
+extern int ECPSVDP_DH(octet *s,octet *W,octet *K);
+/*extern int ECPSVDP_DHC(octet *,octet *,int,octet *);*/
+
+/*#if CURVETYPE!=MONTGOMERY */
+/* ECIES functions */
+/*#if CURVETYPE!=MONTGOMERY */
+/* ECIES functions */
+/**	@brief ECIES Encryption
+ *
+	IEEE-1363 ECIES Encryption
+	@param h is the hash type
+	@param P1 input Key Derivation parameters
+	@param P2 input Encoding parameters
+	@param R is a pointer to a cryptographically secure random number generator
+	@param W the input public key of the recieving party
+	@param M is the plaintext message to be encrypted
+	@param len the length of the HMAC tag
+	@param V component of the output ciphertext
+	@param C the output ciphertext
+	@param T the output HMAC tag, part of the ciphertext
+ */
+extern void ECP_ECIES_ENCRYPT(int h,octet *P1,octet *P2,csprng *R,octet *W,octet *M,int len,octet *V,octet *C,octet *T);
+/**	@brief ECIES Decryption
+ *
+	IEEE-1363 ECIES Decryption
+	@param h is the hash type
+	@param P1 input Key Derivation parameters
+	@param P2 input Encoding parameters
+	@param V component of the input ciphertext
+	@param C the input ciphertext
+	@param T the input HMAC tag, part of the ciphertext
+	@param U the input private key for decryption
+	@param M the output plaintext message
+	@return 1 if successful, else 0
+ */
+extern int ECP_ECIES_DECRYPT(int h,octet *P1,octet *P2,octet *V,octet *C,octet *T,octet *U,octet *M);
+
+/* ECDSA functions */
+/**	@brief ECDSA Signature
+ *
+	IEEE-1363 ECDSA Signature
+	@param h is the hash type
+	@param R is a pointer to a cryptographically secure random number generator
+        @param k Ephemeral key. This value is used when R=NULL
+	@param s the input private signing key
+	@param M the input message to be signed
+	@param c component of the output signature
+	@param d component of the output signature
+
+ */
+extern int ECPSP_DSA(int h,csprng *R,octet *k,octet *s,octet *M,octet *c,octet *d);
+/**	@brief ECDSA Signature Verification
+ *
+	IEEE-1363 ECDSA Signature Verification
+	@param h is the hash type
+	@param W the input public key
+	@param M the input message
+	@param c component of the input signature
+	@param d component of the input signature
+	@return 0 or an error code
+ */
+extern int ECPVP_DSA(int h,octet *W,octet *M,octet *c,octet *d);
+/*#endif*/
+
+#endif
+