http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/java/FP2.java
----------------------------------------------------------------------
diff --git a/version22/java/FP2.java b/version22/java/FP2.java
new file mode 100644
index 0000000..9667db9
--- /dev/null
+++ b/version22/java/FP2.java
@@ -0,0 +1,393 @@
+/*
+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.
+*/
+
+/* Finite Field arithmetic  Fp^2 functions */
+
+/* FP2 elements are of the form a+ib, where i is sqrt(-1) */
+
+public final class FP2 {
+       private final FP a;
+       private final FP b;
+
+/* reduce components mod Modulus */
+       public void reduce()
+       {
+               a.reduce();
+               b.reduce();
+       }
+
+/* normalise components of w */
+       public void norm()
+       {
+               a.norm();
+               b.norm();
+       }
+
+/* test this=0 ? */
+       public boolean iszilch() {
+               reduce();
+               return (a.iszilch() && b.iszilch());
+       }
+
+       public void cmove(FP2 g,int d)
+       {
+               a.cmove(g.a,d);
+               b.cmove(g.b,d);
+       }
+
+/* test this=1 ? */
+       public boolean isunity() {
+               FP one=new FP(1);
+               return (a.equals(one) && b.iszilch());
+       }
+
+/* test this=x */
+       public boolean equals(FP2 x) {
+               return (a.equals(x.a) && b.equals(x.b));
+       }
+
+/* Constructors */
+       public FP2(int c)
+       {
+               a=new FP(c);
+               b=new FP(0);
+       }
+
+       public FP2(FP2 x)
+       {
+               a=new FP(x.a);
+               b=new FP(x.b);
+       }
+
+       public FP2(FP c,FP d)
+       {
+               a=new FP(c);
+               b=new FP(d);
+       }
+
+       public FP2(BIG c,BIG d)
+       {
+               a=new FP(c);
+               b=new FP(d);
+       }
+
+       public FP2(FP c)
+       {
+               a=new FP(c);
+               b=new FP(0);
+       }
+
+       public FP2(BIG c)
+       {
+               a=new FP(c);
+               b=new FP(0);
+       }
+/*
+       public BIG geta()
+       {
+               return a.tobig();
+       }
+*/
+/* extract a */
+       public BIG getA()
+       { 
+               return a.redc();
+       }
+
+/* extract b */
+       public BIG getB()
+       {
+               return b.redc();
+       }
+
+/* copy this=x */
+       public void copy(FP2 x)
+       {
+               a.copy(x.a);
+               b.copy(x.b);
+       }
+
+/* set this=0 */
+       public void zero()
+       {
+               a.zero();
+               b.zero();
+       }
+
+/* set this=1 */
+       public void one()
+       {
+               a.one();
+               b.zero();
+       }
+
+/* negate this mod Modulus */
+       public void neg()
+       {
+               norm();
+               FP m=new FP(a);
+               FP t=new FP(0);
+
+               m.add(b);
+               m.neg();
+               m.norm();
+               t.copy(m); t.add(b);
+               b.copy(m);
+               b.add(a);
+               a.copy(t);
+       }
+
+/* set to a-ib */
+       public void conj()
+       {
+               b.neg();
+       }
+
+/* this+=a */
+       public void add(FP2 x)
+       {
+               a.add(x.a);
+               b.add(x.b);
+       }
+
+/* this-=a */
+       public void sub(FP2 x)
+       {
+               FP2 m=new FP2(x);
+               m.neg();
+               add(m);
+       }
+
+/* this*=s, where s is an FP */
+       public void pmul(FP s)
+       {
+               a.mul(s);
+               b.mul(s);
+       }
+
+/* this*=i, where i is an int */
+       public void imul(int c)
+       {
+               a.imul(c);
+               b.imul(c);
+       }
+
+/* this*=this */
+       public void sqr()
+       {
+               norm();
+               FP w1=new FP(a);
+               FP w3=new FP(a);
+               FP mb=new FP(b);
+
+               w3.mul(b);
+               w1.add(b);
+               mb.neg();
+               a.add(mb);
+               a.mul(w1);
+               b.copy(w3); b.add(w3);
+               norm();
+       }
+
+/* this*=y */
+       public void mul(FP2 y)
+       {
+               norm();  /* This is needed here as {a,b} is not normed before 
additions */
+
+               FP w1=new FP(a);
+               FP w2=new FP(b);
+               FP w5=new FP(a);
+               FP mw=new FP(0);
+
+               w1.mul(y.a);  // w1=a*y.a  - this norms w1 and y.a, NOT a
+               w2.mul(y.b);  // w2=b*y.b  - this norms w2 and y.b, NOT b
+               w5.add(b);    // w5=a+b
+               b.copy(y.a); b.add(y.b); // b=y.a+y.b
+
+               b.mul(w5);
+               mw.copy(w1); mw.add(w2); mw.neg();
+
+               b.add(mw); mw.add(w1);
+               a.copy(w1);     a.add(mw);
+
+               norm();
+       }
+
+/* sqrt(a+ib) = sqrt(a+sqrt(a*a-n*b*b)/2)+ib/(2*sqrt(a+sqrt(a*a-n*b*b)/2)) */
+/* returns true if this is QR */
+       public boolean sqrt()
+       {
+               if (iszilch()) return true;
+               FP w1=new FP(b);
+               FP w2=new FP(a);
+               w1.sqr(); w2.sqr(); w1.add(w2);
+               if (w1.jacobi()!=1) { zero(); return false; }
+               w1=w1.sqrt();
+               w2.copy(a); w2.add(w1); w2.div2();
+               if (w2.jacobi()!=1)
+               {
+                       w2.copy(a); w2.sub(w1); w2.div2();
+                       if (w2.jacobi()!=1) { zero(); return false; }
+               }
+               w2=w2.sqrt();
+               a.copy(w2);
+               w2.add(w2);
+               w2.inverse();
+               b.mul(w2);
+               return true;
+       }
+
+/* output to hex string */
+       public String toString() 
+       {
+               return ("["+a.toString()+","+b.toString()+"]");
+       }
+
+       public String toRawString() 
+       {
+               return ("["+a.toRawString()+","+b.toRawString()+"]");
+       }
+
+/* this=1/this */
+       public void inverse()
+       {
+               norm();
+               FP w1=new FP(a);
+               FP w2=new FP(b);
+
+               w1.sqr();
+               w2.sqr();
+               w1.add(w2);
+               w1.inverse();
+               a.mul(w1);
+               w1.neg();
+               b.mul(w1);
+       }
+
+/* this/=2 */
+       public void div2()
+       {
+               a.div2();
+               b.div2();
+       }
+
+/* this*=sqrt(-1) */
+       public void times_i()
+       {
+       //      a.norm();
+               FP z=new FP(a);
+               a.copy(b); a.neg();
+               b.copy(z);
+       }
+
+/* w*=(1+sqrt(-1)) */
+/* where X*2-(1+sqrt(-1)) is irreducible for FP4, assumes p=3 mod 8 */
+       public void mul_ip()
+       {
+               norm();
+               FP2 t=new FP2(this);
+               FP z=new FP(a);
+               a.copy(b);
+               a.neg();
+               b.copy(z);
+               add(t);
+               norm();
+       }
+
+/* w/=(1+sqrt(-1)) */
+       public void div_ip()
+       {
+               FP2 t=new FP2(0);
+               norm();
+               t.a.copy(a); t.a.add(b);
+               t.b.copy(b); t.b.sub(a);
+               copy(t);
+               div2();
+       }
+/*
+       public FP2 pow(BIG e)
+       {
+               int bt;
+               FP2 r=new FP2(1);
+               e.norm();
+               norm();
+               while (true)
+               {
+                       bt=e.parity();
+                       e.fshr(1);
+                       if (bt==1) r.mul(this);
+                       if (e.iszilch()) break;
+                       sqr();
+               }
+
+               r.reduce();
+               return r;
+       }
+
+       public static void main(String[] args) {
+               BIG m=new BIG(ROM.Modulus);
+               BIG x=new BIG(3);
+               BIG e=new BIG(27);
+               BIG pp1=new BIG(m);
+               BIG pm1=new BIG(m);
+               BIG a=new BIG(1);
+               BIG b=new BIG(1);
+               FP2 w=new FP2(a,b);
+               FP2 z=new FP2(w);
+
+               byte[] RAW=new byte[100];
+
+               RAND rng=new RAND();
+               for (int i=0;i<100;i++) RAW[i]=(byte)(i);
+
+               rng.seed(100,RAW);
+
+       //      for (int i=0;i<100;i++)
+       //      {
+                       a.randomnum(rng);
+                       b.randomnum(rng);
+
+                       w=new FP2(a,b);
+                       System.out.println("w="+w.toString());
+
+                       z=new FP2(w);
+                       z.inverse();
+                       System.out.println("z="+z.toString());
+
+                       z.inverse();
+                       if (!z.equals(w)) System.out.println("Error");
+       //      }
+
+//             System.out.println("m="+m.toString());
+//             w.sqr();
+//             w.mul(z);
+
+               System.out.println("w="+w.toString());
+
+
+               pp1.inc(1); pp1.norm();
+               pm1.dec(1); pm1.norm();
+               System.out.println("p+1="+pp1.toString());
+               System.out.println("p-1="+pm1.toString());
+               w=w.pow(pp1);
+               w=w.pow(pm1);
+               System.out.println("w="+w.toString());
+       }
+*/
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/java/FP4.java
----------------------------------------------------------------------
diff --git a/version22/java/FP4.java b/version22/java/FP4.java
new file mode 100644
index 0000000..7d8912a
--- /dev/null
+++ b/version22/java/FP4.java
@@ -0,0 +1,584 @@
+/*
+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.
+*/
+
+/* Finite Field arithmetic  Fp^4 functions */
+
+/* FP4 elements are of the form a+ib, where i is sqrt(-1+sqrt(-1))  */
+
+public final class FP4 {
+       private final FP2 a;
+       private final FP2 b;
+/* reduce all components of this mod Modulus */
+       public void reduce()
+       {
+               a.reduce();
+               b.reduce();
+       }
+/* normalise all components of this mod Modulus */
+       public void norm()
+       {
+               a.norm();
+               b.norm();
+       }
+/* test this==0 ? */
+       public boolean iszilch() {
+               reduce();
+               return (a.iszilch() && b.iszilch());
+       }
+/* test this==1 ? */
+       public boolean isunity() {
+               FP2 one=new FP2(1);
+               return (a.equals(one) && b.iszilch());
+       }
+
+/* test is w real? That is in a+ib test b is zero */
+       public boolean isreal()
+       {
+               return b.iszilch();
+       }
+/* extract real part a */
+       public FP2 real()
+       {
+               return a;
+       }
+
+       public FP2 geta()
+       {
+               return a;
+       }
+/* extract imaginary part b */
+       public FP2 getb()
+       {
+               return b;
+       }
+/* test this=x? */
+       public boolean equals(FP4 x)
+       {
+               return (a.equals(x.a) && b.equals(x.b));
+       }
+/* constructors */
+       public FP4(int c)
+       {
+               a=new FP2(c);
+               b=new FP2(0);
+       }
+
+       public FP4(FP4 x)
+       {
+               a=new FP2(x.a);
+               b=new FP2(x.b);
+       }
+
+       public FP4(FP2 c,FP2 d)
+       {
+               a=new FP2(c);
+               b=new FP2(d);
+       }
+
+       public FP4(FP2 c)
+       {
+               a=new FP2(c);
+               b=new FP2(0);
+       }
+/* copy this=x */
+       public void copy(FP4 x)
+       {
+               a.copy(x.a);
+               b.copy(x.b);
+       }
+/* set this=0 */
+       public void zero()
+       {
+               a.zero();
+               b.zero();
+       }
+/* set this=1 */
+       public void one()
+       {
+               a.one();
+               b.zero();
+       }
+/* set this=-this */
+       public void neg()
+       {
+               FP2 m=new FP2(a);
+               FP2 t=new FP2(0);
+               m.add(b);
+               m.neg();
+               m.norm();
+               t.copy(m); t.add(b);
+               b.copy(m);
+               b.add(a);
+               a.copy(t);
+       }
+/* this=conjugate(this) */
+       public void conj()
+       {
+               b.neg(); b.norm();
+       }
+/* this=-conjugate(this) */
+       public void nconj()
+       {
+               a.neg(); a.norm();
+       }
+/* this+=x */
+       public void add(FP4 x)
+       {
+               a.add(x.a);
+               b.add(x.b);
+       }
+/* this-=x */
+       public void sub(FP4 x)
+       {
+               FP4 m=new FP4(x);
+               m.neg();
+               add(m);
+       }
+
+/* this*=s where s is FP2 */
+       public void pmul(FP2 s)
+       {
+               a.mul(s);
+               b.mul(s);
+       }
+/* this*=c where c is int */
+       public void imul(int c)
+       {
+               a.imul(c);
+               b.imul(c);
+       }
+/* this*=this */       
+       public void sqr()
+       {
+               norm();
+
+               FP2 t1=new FP2(a);
+               FP2 t2=new FP2(b);
+               FP2 t3=new FP2(a);
+
+               t3.mul(b);
+               t1.add(b);
+               t2.mul_ip();
+
+               t2.add(a);
+               a.copy(t1);
+
+               a.mul(t2);
+
+               t2.copy(t3);
+               t2.mul_ip();
+               t2.add(t3);
+               t2.neg();
+               a.add(t2);
+
+               b.copy(t3);
+               b.add(t3);
+
+               norm();
+       }
+/* this*=y */
+       public void mul(FP4 y)
+       {
+               norm();
+
+               FP2 t1=new FP2(a);
+               FP2 t2=new FP2(b);
+               FP2 t3=new FP2(0);
+               FP2 t4=new FP2(b);
+
+               t1.mul(y.a);
+               t2.mul(y.b);
+               t3.copy(y.b);
+               t3.add(y.a);
+               t4.add(a);
+
+               t4.mul(t3);
+               t4.sub(t1);
+               t4.norm();
+
+               b.copy(t4);
+               b.sub(t2);
+               t2.mul_ip();
+               a.copy(t2);
+               a.add(t1);
+
+               norm();
+       }
+/* convert this to hex string */
+       public String toString() 
+       {
+               return ("["+a.toString()+","+b.toString()+"]");
+       }
+
+       public String toRawString() 
+       {
+               return ("["+a.toRawString()+","+b.toRawString()+"]");
+       }
+
+/* this=1/this */
+       public void inverse()
+       {
+               norm();
+
+               FP2 t1=new FP2(a);
+               FP2 t2=new FP2(b);
+
+               t1.sqr();
+               t2.sqr();
+               t2.mul_ip();
+               t1.sub(t2);
+               t1.inverse();
+               a.mul(t1);
+               t1.neg();
+               b.mul(t1);
+       }
+
+
+/* this*=i where i = sqrt(-1+sqrt(-1)) */
+       public void times_i()
+       {
+               norm();
+               FP2 s=new FP2(b);
+               FP2 t=new FP2(b);
+               s.times_i();
+               t.add(s);
+               t.norm();
+               b.copy(a);
+               a.copy(t);
+       }
+
+/* this=this^p using Frobenius */
+       public void frob(FP2 f)
+       {
+               a.conj();
+               b.conj();
+               b.mul(f);
+       }
+
+/* this=this^e */
+       public FP4 pow(BIG e)
+       {
+               norm();
+               e.norm();
+               FP4 w=new FP4(this);
+               BIG z=new BIG(e);
+               FP4 r=new FP4(1);
+               while (true)
+               {
+                       int bt=z.parity();
+                       z.fshr(1);
+                       if (bt==1) r.mul(w);
+                       if (z.iszilch()) break;
+                       w.sqr();
+               }
+               r.reduce();
+               return r;
+       }
+/* XTR xtr_a function */
+       public void xtr_A(FP4 w,FP4 y,FP4 z) 
+       {
+               FP4 r=new FP4(w);
+               FP4 t=new FP4(w);
+               r.sub(y);
+               r.pmul(a);
+               t.add(y);
+               t.pmul(b);
+               t.times_i();
+
+               copy(r);
+               add(t);
+               add(z);
+
+               norm();
+       }
+
+/* XTR xtr_d function */
+       public void xtr_D() {
+               FP4 w=new FP4(this);
+               sqr(); w.conj();
+               w.add(w);
+               sub(w);
+               reduce();
+       }
+
+/* r=x^n using XTR method on traces of FP12s */
+       public FP4 xtr_pow(BIG n) {
+               FP4 a=new FP4(3);
+               FP4 b=new FP4(this);
+               FP4 c=new FP4(b);
+               c.xtr_D();
+               FP4 t=new FP4(0);
+               FP4 r=new FP4(0);
+
+               n.norm();
+               int par=n.parity();
+               BIG v=new BIG(n); v.fshr(1);
+               if (par==0) {v.dec(1); v.norm();}
+
+               int nb=v.nbits();
+               for (int i=nb-1;i>=0;i--)
+               {
+                       if (v.bit(i)!=1)
+                       {
+                               t.copy(b);
+                               conj();
+                               c.conj();
+                               b.xtr_A(a,this,c);
+                               conj();
+                               c.copy(t);
+                               c.xtr_D();
+                               a.xtr_D();
+                       }
+                       else
+                       {
+                               t.copy(a); t.conj();
+                               a.copy(b);
+                               a.xtr_D();
+                               b.xtr_A(c,this,t);
+                               c.xtr_D();
+                       }
+               }
+               if (par==0) r.copy(c);
+               else r.copy(b);
+               r.reduce();
+               return r;
+       }
+
+/* r=ck^a.cl^n using XTR double exponentiation method on traces of FP12s. See 
Stam thesis. */
+       public FP4 xtr_pow2(FP4 ck,FP4 ckml,FP4 ckm2l,BIG a,BIG b)
+       {
+               a.norm(); b.norm();
+               BIG e=new BIG(a);
+               BIG d=new BIG(b);
+               BIG w=new BIG(0);
+
+               FP4 cu=new FP4(ck);  // can probably be passed in w/o copying
+               FP4 cv=new FP4(this);
+               FP4 cumv=new FP4(ckml);
+               FP4 cum2v=new FP4(ckm2l);
+               FP4 r=new FP4(0);
+               FP4 t=new FP4(0);
+
+               int f2=0;
+               while (d.parity()==0 && e.parity()==0)
+               {
+                       d.fshr(1);
+                       e.fshr(1);
+                       f2++;
+               }
+
+               while (BIG.comp(d,e)!=0)
+               {
+                       if (BIG.comp(d,e)>0)
+                       {
+                               w.copy(e); w.imul(4); w.norm();
+                               if (BIG.comp(d,w)<=0)
+                               {
+                                       w.copy(d); d.copy(e);
+                                       e.rsub(w); e.norm();
+
+                                       t.copy(cv); 
+                                       t.xtr_A(cu,cumv,cum2v);
+                                       cum2v.copy(cumv); 
+                                       cum2v.conj();
+                                       cumv.copy(cv);
+                                       cv.copy(cu);
+                                       cu.copy(t);
+
+                               }
+                               else if (d.parity()==0)
+                               {
+                                       d.fshr(1);
+                                       r.copy(cum2v); r.conj();
+                                       t.copy(cumv);
+                                       t.xtr_A(cu,cv,r);
+                                       cum2v.copy(cumv);
+                                       cum2v.xtr_D();
+                                       cumv.copy(t);
+                                       cu.xtr_D();
+                               }
+                               else if (e.parity()==1)
+                               {
+                                       d.sub(e); d.norm();
+                                       d.fshr(1);
+                                       t.copy(cv);
+                                       t.xtr_A(cu,cumv,cum2v);
+                                       cu.xtr_D();
+                                       cum2v.copy(cv);
+                                       cum2v.xtr_D();
+                                       cum2v.conj();
+                                       cv.copy(t);
+                               }
+                               else
+                               {
+                                       w.copy(d);
+                                       d.copy(e); d.fshr(1);
+                                       e.copy(w);
+                                       t.copy(cumv);
+                                       t.xtr_D();
+                                       cumv.copy(cum2v); cumv.conj();
+                                       cum2v.copy(t); cum2v.conj();
+                                       t.copy(cv);
+                                       t.xtr_D();
+                                       cv.copy(cu);
+                                       cu.copy(t);
+                               }
+                       }
+                       if (BIG.comp(d,e)<0)
+                       {
+                               w.copy(d); w.imul(4); w.norm();
+                               if (BIG.comp(e,w)<=0)
+                               {
+                                       e.sub(d); e.norm();
+                                       t.copy(cv);
+                                       t.xtr_A(cu,cumv,cum2v);
+                                       cum2v.copy(cumv);
+                                       cumv.copy(cu);
+                                       cu.copy(t);
+                               }
+                               else if (e.parity()==0)
+                               {
+                                       w.copy(d);
+                                       d.copy(e); d.fshr(1);
+                                       e.copy(w);
+                                       t.copy(cumv);
+                                       t.xtr_D();
+                                       cumv.copy(cum2v); cumv.conj();
+                                       cum2v.copy(t); cum2v.conj();
+                                       t.copy(cv);
+                                       t.xtr_D();
+                                       cv.copy(cu);
+                                       cu.copy(t);
+                               }
+                               else if (d.parity()==1)
+                               {
+                                       w.copy(e);
+                                       e.copy(d);
+                                       w.sub(d); w.norm();
+                                       d.copy(w); d.fshr(1);
+                                       t.copy(cv);
+                                       t.xtr_A(cu,cumv,cum2v);
+                                       cumv.conj();
+                                       cum2v.copy(cu);
+                                       cum2v.xtr_D();
+                                       cum2v.conj();
+                                       cu.copy(cv);
+                                       cu.xtr_D();
+                                       cv.copy(t);
+                               }
+                               else
+                               {
+                                       d.fshr(1);
+                                       r.copy(cum2v); r.conj();
+                                       t.copy(cumv);
+                                       t.xtr_A(cu,cv,r);
+                                       cum2v.copy(cumv);
+                                       cum2v.xtr_D();
+                                       cumv.copy(t);
+                                       cu.xtr_D();
+                               }
+                       }
+               }
+               r.copy(cv);
+               r.xtr_A(cu,cumv,cum2v);
+               for (int i=0;i<f2;i++)
+                       r.xtr_D();
+               r=r.xtr_pow(d);
+               return r;
+       }
+
+/*
+       public static void main(String[] args) {
+               BIG m=new BIG(ROM.Modulus);
+               BIG e=new BIG(12);
+               BIG a=new BIG(0);
+               BIG b=new BIG(0);
+               
+               a.inc(27); b.inc(45);
+
+               FP2 w0=new FP2(a,b);
+
+               a.zero(); b.zero();
+               a.inc(33); b.inc(54);
+
+               FP2 w1=new FP2(a,b);
+
+
+               FP4 w=new FP4(w0,w1);
+               FP4 t=new FP4(w);
+
+               a=new BIG(ROM.CURVE_Fra);
+               b=new BIG(ROM.CURVE_Frb);
+
+               FP2 f=new FP2(a,b);
+
+               System.out.println("w= "+w.toString());
+
+               w=w.pow(m);
+
+               System.out.println("w^p= "+w.toString());
+
+               t.frob(f);
+
+
+               System.out.println("w^p= "+t.toString());
+
+               w=w.pow(m);
+               w=w.pow(m);
+               w=w.pow(m);
+               System.out.println("w^p4= "+w.toString());
+
+
+       System.out.println("Test Inversion");
+
+               w=new FP4(w0,w1);
+
+               w.inverse();
+
+               System.out.println("1/w mod p^4 = "+w.toString());
+
+               w.inverse();
+
+               System.out.println("1/(1/w) mod p^4 = "+w.toString());
+
+               FP4 ww=new FP4(w);
+
+               w=w.xtr_pow(e);
+               System.out.println("w^e= "+w.toString());
+
+
+               a.zero(); b.zero();
+               a.inc(37); b.inc(17);
+               w0=new FP2(a,b);
+               a.zero(); b.zero();
+               a.inc(49); b.inc(31);
+               w1=new FP2(a,b);
+
+               FP4 c1=new FP4(w0,w1);
+               FP4 c2=new FP4(w0,w1);
+               FP4 c3=new FP4(w0,w1);
+
+               BIG e1=new BIG(3331);
+               BIG e2=new BIG(3372);
+
+               FP4 cr=w.xtr_pow2(c1,c2,c3,e1,e2);
+
+               System.out.println("c^e= "+cr.toString()); 
+       } */
+}

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/java/GCM.java
----------------------------------------------------------------------
diff --git a/version22/java/GCM.java b/version22/java/GCM.java
new file mode 100644
index 0000000..47e5bb2
--- /dev/null
+++ b/version22/java/GCM.java
@@ -0,0 +1,374 @@
+/*
+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.
+*/
+
+
+/*
+ * Implementation of the AES-GCM Encryption/Authentication
+ *
+ * Some restrictions.. 
+ * 1. Only for use with AES
+ * 2. Returned tag is always 128-bits. Truncate at your own risk.
+ * 3. The order of function calls must follow some rules
+ *
+ * Typical sequence of calls..
+ * 1. call GCM_init
+ * 2. call GCM_add_header any number of times, as long as length of header is 
multiple of 16 bytes (block size)
+ * 3. call GCM_add_header one last time with any length of header
+ * 4. call GCM_add_cipher any number of times, as long as length of 
cipher/plaintext is multiple of 16 bytes
+ * 5. call GCM_add_cipher one last time with any length of cipher/plaintext
+ * 6. call GCM_finish to extract the tag.
+ *
+ * See http://www.mindspring.com/~dmcgrew/gcm-nist-6.pdf
+ */
+
+public class GCM {
+       public static final int NB=4;
+       public static final int GCM_ACCEPTING_HEADER=0;
+       public static final int GCM_ACCEPTING_CIPHER=1;
+       public static final int GCM_NOT_ACCEPTING_MORE=2;
+       public static final int GCM_FINISHED=3;
+       public static final int GCM_ENCRYPTING=0;
+       public static final int GCM_DECRYPTING=1;
+
+       private int[][] table=new int[128][4]; /* 2k bytes */
+       private byte[] stateX=new byte[16];
+       private byte[]Y_0=new byte[16];
+       private int counter;
+       private int[] lenA=new int[2];
+       private int[] lenC=new int[2];
+       private int status;
+       private AES a=new AES();
+
+       private static int pack(byte[] b)
+       { /* pack bytes into a 32-bit Word */
+               return 
((((int)b[0])&0xff)<<24)|(((int)b[1]&0xff)<<16)|(((int)b[2]&0xff)<<8)|((int)b[3]&0xff);
+       }
+
+       private static byte[] unpack(int a)
+       { /* unpack bytes from a word */
+               byte [] b=new byte[4];
+               b[3]=(byte)(a);
+               b[2]=(byte)(a>>>8);
+               b[1]=(byte)(a>>>16);
+               b[0]=(byte)(a>>>24);
+               return b;
+       }
+
+       private void precompute(byte[] H)
+       {
+               int i,j,c;
+               byte[] b=new byte[4];
+
+               for (i=j=0;i<NB;i++,j+=4) 
+               {
+                       b[0]=H[j]; b[1]=H[j+1]; b[2]=H[j+2]; b[3]=H[j+3];
+                       table[0][i]=pack(b);
+               }
+               for (i=1;i<128;i++)
+               {
+                       c=0;
+                       for (j=0;j<NB;j++) {table[i][j]=c|(table[i-1][j])>>>1; 
c=table[i-1][j]<<31;}
+                       if (c!=0) table[i][0]^=0xE1000000; /* irreducible 
polynomial */
+               }
+       }
+
+       private void gf2mul()
+       { /* gf2m mul - Z=H*X mod 2^128 */
+               int i,j,m,k;
+               int[] P=new int[4];
+               int c;
+               byte[] b;//=new byte[4];
+
+               P[0]=P[1]=P[2]=P[3]=0;
+               j=8; m=0;
+               for (i=0;i<128;i++)
+               {
+                       c=(stateX[m]>>>(--j))&1; c=~c+1;
+                       for (k=0;k<NB;k++) P[k]^=(table[i][k]&c);
+                       if (j==0)
+                       {
+                               j=8; m++;
+                               if (m==16) break;
+                       }
+               }
+               for (i=j=0;i<NB;i++,j+=4) 
+               {
+                       b=unpack(P[i]);
+                       stateX[j]=b[0]; stateX[j+1]=b[1]; stateX[j+2]=b[2]; 
stateX[j+3]=b[3];
+               }
+       }
+
+       private void wrap()
+       { /* Finish off GHASH */
+               int i,j;
+               int[] F=new int[4];
+               byte[] L=new byte[16];
+               byte[] b;//=new byte[4];
+
+/* convert lengths from bytes to bits */
+               F[0]=(lenA[0]<<3)|(lenA[1]&0xE0000000)>>>29;
+               F[1]=lenA[1]<<3;
+               F[2]=(lenC[0]<<3)|(lenC[1]&0xE0000000)>>>29;
+               F[3]=lenC[1]<<3;
+               for (i=j=0;i<NB;i++,j+=4)
+               {
+                       b=unpack(F[i]);
+                       L[j]=b[0]; L[j+1]=b[1]; L[j+2]=b[2]; L[j+3]=b[3];
+               }
+               for (i=0;i<16;i++) stateX[i]^=L[i];
+               gf2mul();
+       }
+
+/* Initialize GCM mode */
+       public void init(int nk,byte[] key,int niv,byte[] iv)
+       { /* iv size niv is usually 12 bytes (96 bits). AES key size nk can be 
16,24 or 32 bytes */
+               int i;
+               byte[] H=new byte[16];
+               byte[] b;//=new byte[4];
+
+               for (i=0;i<16;i++) {H[i]=0; stateX[i]=0;}
+
+               a.init(AES.ECB,nk,key,iv);
+               a.ecb_encrypt(H);     /* E(K,0) */
+               precompute(H);
+       
+               lenA[0]=lenC[0]=lenA[1]=lenC[1]=0;
+               if (niv==12)
+               {
+                       for (i=0;i<12;i++) a.f[i]=iv[i];
+                       b=unpack((int)1);
+                       a.f[12]=b[0]; a.f[13]=b[1]; a.f[14]=b[2]; a.f[15]=b[3]; 
 /* initialise IV */
+                       for (i=0;i<16;i++) Y_0[i]=a.f[i];
+               }
+               else
+               {
+                       status=GCM_ACCEPTING_CIPHER;
+                       ghash(iv,niv); /* GHASH(H,0,IV) */
+                       wrap();
+                       for (i=0;i<16;i++) 
{a.f[i]=stateX[i];Y_0[i]=a.f[i];stateX[i]=0;}
+                       lenA[0]=lenC[0]=lenA[1]=lenC[1]=0;
+               }
+               status=GCM_ACCEPTING_HEADER;
+       }
+
+/* Add Header data - included but not encrypted */
+       public boolean add_header(byte[] header,int len)
+       { /* Add some header. Won't be encrypted, but will be authenticated. 
len is length of header */
+               int i,j=0;
+               if (status!=GCM_ACCEPTING_HEADER) return false;
+
+               while (j<len)
+               {
+                       for (i=0;i<16 && j<len;i++)
+                       {
+                               stateX[i]^=header[j++];
+                               lenA[1]++; if (lenA[1]==0) lenA[0]++;
+                       }
+                       gf2mul();
+               }
+               if (len%16!=0) status=GCM_ACCEPTING_CIPHER;
+               return true;
+       }
+
+       private boolean ghash(byte[] plain,int len)
+       {
+               int i,j=0;
+               int counter;
+       //      byte[] B=new byte[16];
+       //      byte[] b=new byte[4];
+
+               if (status==GCM_ACCEPTING_HEADER) status=GCM_ACCEPTING_CIPHER;
+               if (status!=GCM_ACCEPTING_CIPHER) return false;
+               
+               while (j<len)
+               {
+                       for (i=0;i<16 && j<len;i++)
+                       {
+                               stateX[i]^=plain[j++];
+                               lenC[1]++; if (lenC[1]==0) lenC[0]++;
+                       }
+                       gf2mul();
+               }
+               if (len%16!=0) status=GCM_NOT_ACCEPTING_MORE;
+               return true;
+       }
+
+/* Add Plaintext - included and encrypted */
+       public byte[] add_plain(byte[] plain,int len)
+       {
+               int i,j=0;
+               int counter;
+               byte[] B=new byte[16];
+               byte[] b=new byte[4];
+               byte[] cipher=new byte[len];
+
+               if (status==GCM_ACCEPTING_HEADER) status=GCM_ACCEPTING_CIPHER;
+               if (status!=GCM_ACCEPTING_CIPHER) return new byte[0];
+               
+               while (j<len)
+               {
+
+                       b[0]=a.f[12]; b[1]=a.f[13]; b[2]=a.f[14]; b[3]=a.f[15];
+                       counter=pack(b);
+                       counter++;
+                       b=unpack(counter);
+                       a.f[12]=b[0]; a.f[13]=b[1]; a.f[14]=b[2]; a.f[15]=b[3]; 
/* increment counter */
+                       for (i=0;i<16;i++) B[i]=a.f[i];
+                       a.ecb_encrypt(B);        /* encrypt it  */
+               
+                       for (i=0;i<16 && j<len;i++)
+                       {
+                               cipher[j]=(byte)(plain[j]^B[i]);
+                               stateX[i]^=cipher[j++];
+                               lenC[1]++; if (lenC[1]==0) lenC[0]++;
+                       }
+                       gf2mul();
+               }
+               if (len%16!=0) status=GCM_NOT_ACCEPTING_MORE;
+               return cipher;
+       }
+
+/* Add Ciphertext - decrypts to plaintext */
+       public byte[] add_cipher(byte[] cipher,int len)
+       {
+               int i,j=0;
+               int counter;
+               byte[] B=new byte[16];
+               byte[] b=new byte[4];
+               byte[] plain=new byte[len];
+
+               if (status==GCM_ACCEPTING_HEADER) status=GCM_ACCEPTING_CIPHER;
+               if (status!=GCM_ACCEPTING_CIPHER) return new byte[0];
+       
+               while (j<len)
+               {
+
+                       b[0]=a.f[12]; b[1]=a.f[13]; b[2]=a.f[14]; b[3]=a.f[15];
+                       counter=pack(b);
+                       counter++;
+                       b=unpack(counter);
+                       a.f[12]=b[0]; a.f[13]=b[1]; a.f[14]=b[2]; a.f[15]=b[3]; 
/* increment counter */
+                       for (i=0;i<16;i++) B[i]=a.f[i];
+                       a.ecb_encrypt(B);        /* encrypt it  */
+                       for (i=0;i<16 && j<len;i++)
+                       {
+                               byte oc=cipher[j];
+                               plain[j]=(byte)(cipher[j]^B[i]);
+                               stateX[i]^=oc; j++;
+                               lenC[1]++; if (lenC[1]==0) lenC[0]++;
+                       }
+                       gf2mul();
+               }
+               if (len%16!=0) status=GCM_NOT_ACCEPTING_MORE;
+               return plain;
+       }
+
+/* Finish and extract Tag */
+       public byte[] finish(boolean extract)
+       { /* Finish off GHASH and extract tag (MAC) */
+               int i;
+               byte[] tag=new byte[16];
+
+               wrap();
+/* extract tag */
+               if (extract)
+               {
+                       a.ecb_encrypt(Y_0);        /* E(K,Y0) */
+                       for (i=0;i<16;i++) Y_0[i]^=stateX[i];
+                       for (i=0;i<16;i++) {tag[i]=Y_0[i];Y_0[i]=stateX[i]=0;}
+               }
+               status=GCM_FINISHED;
+               a.end();
+               return tag;
+       }
+
+       public static byte[] hex2bytes(String s) {
+               int len = s.length();
+               byte[] data = new byte[len / 2];
+               for (int i = 0; i < len; i += 2) {
+                       data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) 
<< 4)
+                             + Character.digit(s.charAt(i+1), 16));
+               }
+               return data;
+       }
+/*
+       public static void main(String[] args) {
+               int i;
+
+               String KT="feffe9928665731c6d6a8f9467308308";
+               String 
MT="d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39";
+               String HT="feedfacedeadbeeffeedfacedeadbeefabaddad2";
+//     char* NT="cafebabefacedbaddecaf888";
+// Tag should be 5bc94fbc3221a5db94fae95ae7121a47
+               String 
NT="9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b";
+// Tag should be 619cc5aefffe0bfa462af43c1699d050
+
+
+               byte[] T=new byte[16];   // Tag
+               byte[] K=new byte[16];   // AES Key
+               byte[] H=new byte[64];   // Header - to be included in 
Authentication, but not encrypted
+               byte[] N=new byte[100];   // IV - Initialisation vector
+               byte[] M=new byte[100];  // Plaintext to be 
encrypted/authenticated
+               byte[] C=new byte[100];  // Ciphertext
+               byte[] P=new byte[100];  // Recovered Plaintext 
+
+               GCM g=new GCM();
+
+               M=hex2bytes(MT);
+               H=hex2bytes(HT);
+               N=hex2bytes(NT);
+               K=hex2bytes(KT);
+
+               int len=M.length;
+               int lenH=H.length;
+               int lenK=K.length;
+               int lenIV=N.length;
+
+               System.out.format("Plaintext=\n");
+               for (i=0;i<len;i++) System.out.format("%02x",M[i]);
+               System.out.format("\n");
+
+               g.init(16,K,lenIV,N);
+               g.add_header(H,lenH);
+               C=g.add_plain(M,len);
+               T=g.finish(true);
+
+               System.out.format("Ciphertext=\n");
+               for (i=0;i<len;i++) System.out.format("%02x",C[i]);
+               System.out.format("\n");
+        
+               System.out.format("Tag=\n");
+               for (i=0;i<16;i++) System.out.format("%02x",T[i]);
+               System.out.format("\n");
+
+               g.init(16,K,lenIV,N);
+               g.add_header(H,lenH);
+               P=g.add_cipher(C,len);
+               T=g.finish(true);
+
+               System.out.format("Plaintext=\n");
+               for (i=0;i<len;i++) System.out.format("%02x",P[i]);
+               System.out.format("\n");
+
+               System.out.format("Tag=\n");
+               for (i=0;i<16;i++) System.out.format("%02x",T[i]);
+               System.out.format("\n");
+       }
+*/     
+}

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/java/HASH256.java
----------------------------------------------------------------------
diff --git a/version22/java/HASH256.java b/version22/java/HASH256.java
new file mode 100644
index 0000000..c1ddbd0
--- /dev/null
+++ b/version22/java/HASH256.java
@@ -0,0 +1,216 @@
+/*
+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.
+*/
+
+/*
+ * Implementation of the Secure Hashing Algorithm (SHA-256)
+ *
+ * Generates a 256 bit message digest. It should be impossible to come
+ * come up with two messages that hash to the same value ("collision free").
+ *
+ * For use with byte-oriented messages only. 
+ */
+
+public class HASH256 {
+       private int[] length=new int[2];
+       private int[] h=new int[8];
+       private int[] w=new int[80];
+
+       public static final int H0=0x6A09E667;
+       public static final int H1=0xBB67AE85;
+       public static final int H2=0x3C6EF372;
+       public static final int H3=0xA54FF53A;
+       public static final int H4=0x510E527F;
+       public static final int H5=0x9B05688C;
+       public static final int H6=0x1F83D9AB;
+       public static final int H7=0x5BE0CD19;
+
+       public static final int len=32;
+
+       public static final int[] K={
+       
0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
+       
0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
+       
0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
+       
0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
+       
0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
+       
0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
+       
0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
+       
0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2};
+
+
+/* functions */
+       private static int S(int n,int x)
+       {
+               return (((x)>>>n) | ((x)<<(32-n)));
+       }
+
+       private static int R(int n,int x)
+       {
+               return ((x)>>>n);
+       }
+
+       private static int Ch(int x,int y,int z)
+       {
+               return ((x&y)^(~(x)&z));
+       }
+
+       private static int Maj(int x,int y,int z)
+       {
+               return ((x&y)^(x&z)^(y&z));
+       }
+
+       private static int Sig0(int x)
+       {
+               return (S(2,x)^S(13,x)^S(22,x));
+       }
+
+       private static int Sig1(int x)
+       {
+               return (S(6,x)^S(11,x)^S(25,x));
+       }
+
+       private static int theta0(int x)
+       {
+               return (S(7,x)^S(18,x)^R(3,x));
+       }
+
+       private static int theta1(int x)
+       {
+               return (S(17,x)^S(19,x)^R(10,x));
+       }
+
+
+       private void transform()
+       { /* basic transformation step */
+               int a,b,c,d,e,f,g,hh,t1,t2;
+               int j;
+               for (j=16;j<64;j++) 
+                       w[j]=theta1(w[j-2])+w[j-7]+theta0(w[j-15])+w[j-16];
+               a=h[0]; b=h[1]; c=h[2]; d=h[3]; 
+               e=h[4]; f=h[5]; g=h[6]; hh=h[7];
+
+               for (j=0;j<64;j++)
+               { /* 64 times - mush it up */
+                       t1=hh+Sig1(e)+Ch(e,f,g)+K[j]+w[j];
+                       t2=Sig0(a)+Maj(a,b,c);
+                       hh=g; g=f; f=e;
+                       e=d+t1;
+                       d=c;
+                       c=b;
+                       b=a;
+                       a=t1+t2;   
+               
+               }
+               h[0]+=a; h[1]+=b; h[2]+=c; h[3]+=d; 
+               h[4]+=e; h[5]+=f; h[6]+=g; h[7]+=hh; 
+       } 
+
+/* Initialise Hash function */
+       public void init()
+       { /* initialise */
+               int i;
+               for (i=0;i<64;i++) w[i]=0;
+               length[0]=length[1]=0;
+               h[0]=H0;
+               h[1]=H1;
+               h[2]=H2;
+               h[3]=H3;
+               h[4]=H4;
+               h[5]=H5;
+               h[6]=H6;
+               h[7]=H7;
+       }
+
+/* Constructor */
+       public HASH256()
+       {
+               init();
+       }
+
+/* process a single byte */
+       public void process(int byt)
+       { /* process the next message byte */
+               int cnt;
+               cnt=(length[0]/32)%16;
+    
+               w[cnt]<<=8;
+               w[cnt]|=(byt&0xFF);
+               length[0]+=8;
+               if (length[0]==0) { length[1]++; length[0]=0; }
+               if ((length[0]%512)==0) transform();
+       }
+
+/* process an array of bytes */        
+       public void process_array(byte[] b)
+       {
+               for (int i=0;i<b.length;i++) process((int)b[i]);
+       }
+
+/* process a 32-bit integer */
+       public void process_num(int n)
+       {
+               process((n>>24)&0xff);
+               process((n>>16)&0xff);
+               process((n>>8)&0xff);
+               process(n&0xff);
+       }
+
+/* Generate 32-byte Hash */
+       public byte[] hash()
+       { /* pad message and finish - supply digest */
+               int i;
+               byte[] digest=new byte[32];
+               int len0,len1;
+               len0=length[0];
+               len1=length[1];
+               process(0x80);
+               while ((length[0]%512)!=448) process(0);
+               w[14]=len1;
+               w[15]=len0;    
+               transform();
+               for (i=0;i<len;i++)
+               { /* convert to bytes */
+                       digest[i]=(byte)((h[i/4]>>(8*(3-i%4))) & 0xff);
+               }
+               init();
+               return digest;
+       }
+
+/* test program: should produce digest */
+
+//248d6a61 d20638b8 e5c02693 0c3e6039 a33ce459 64ff2167 f6ecedd4 19db06c1
+
+       public static void main(String[] args) {
+               byte[] 
test="abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq".getBytes();
+               byte[] digest;
+               int i;
+               HASH256 sh=new HASH256();
+  
+               for (i=0;i<test.length;i++)
+                       sh.process(test[i]);
+               
+               digest=sh.hash();    
+               for (i=0;i<32;i++) System.out.format("%02x",digest[i]);
+
+       //      for (i=0;i<32;i++) System.out.format("%d ",digest[i]);
+
+               System.out.println("");
+       } 
+}
+
+

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/java/HASH384.java
----------------------------------------------------------------------
diff --git a/version22/java/HASH384.java b/version22/java/HASH384.java
new file mode 100644
index 0000000..5422792
--- /dev/null
+++ b/version22/java/HASH384.java
@@ -0,0 +1,227 @@
+/*
+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.
+*/
+
+/*
+ * Implementation of the Secure Hashing Algorithm (SHA-512)
+ *
+ * Generates a 512 bit message digest. It should be impossible to come
+ * come up with two messages that hash to the same value ("collision free").
+ *
+ * For use with byte-oriented messages only. 
+ */
+
+public class HASH384 {
+       private long[] length=new long[2];
+       private long[] h=new long[8];
+       private long[] w=new long[80];
+
+       public static final long H0=0xcbbb9d5dc1059ed8L;
+       public static final long H1=0x629a292a367cd507L;
+       public static final long H2=0x9159015a3070dd17L;
+       public static final long H3=0x152fecd8f70e5939L;
+       public static final long H4=0x67332667ffc00b31L;
+       public static final long H5=0x8eb44a8768581511L;
+       public static final long H6=0xdb0c2e0d64f98fa7L;
+       public static final long H7=0x47b5481dbefa4fa4L;
+
+       public static final int len=48;
+
+       public static final long[] K=
+       
{0x428a2f98d728ae22L,0x7137449123ef65cdL,0xb5c0fbcfec4d3b2fL,0xe9b5dba58189dbbcL,
+       
0x3956c25bf348b538L,0x59f111f1b605d019L,0x923f82a4af194f9bL,0xab1c5ed5da6d8118L,
+       
0xd807aa98a3030242L,0x12835b0145706fbeL,0x243185be4ee4b28cL,0x550c7dc3d5ffb4e2L,
+       
0x72be5d74f27b896fL,0x80deb1fe3b1696b1L,0x9bdc06a725c71235L,0xc19bf174cf692694L,
+       
0xe49b69c19ef14ad2L,0xefbe4786384f25e3L,0x0fc19dc68b8cd5b5L,0x240ca1cc77ac9c65L,
+       
0x2de92c6f592b0275L,0x4a7484aa6ea6e483L,0x5cb0a9dcbd41fbd4L,0x76f988da831153b5L,
+       
0x983e5152ee66dfabL,0xa831c66d2db43210L,0xb00327c898fb213fL,0xbf597fc7beef0ee4L,
+       
0xc6e00bf33da88fc2L,0xd5a79147930aa725L,0x06ca6351e003826fL,0x142929670a0e6e70L,
+       
0x27b70a8546d22ffcL,0x2e1b21385c26c926L,0x4d2c6dfc5ac42aedL,0x53380d139d95b3dfL,
+       
0x650a73548baf63deL,0x766a0abb3c77b2a8L,0x81c2c92e47edaee6L,0x92722c851482353bL,
+       
0xa2bfe8a14cf10364L,0xa81a664bbc423001L,0xc24b8b70d0f89791L,0xc76c51a30654be30L,
+       
0xd192e819d6ef5218L,0xd69906245565a910L,0xf40e35855771202aL,0x106aa07032bbd1b8L,
+       
0x19a4c116b8d2d0c8L,0x1e376c085141ab53L,0x2748774cdf8eeb99L,0x34b0bcb5e19b48a8L,
+       
0x391c0cb3c5c95a63L,0x4ed8aa4ae3418acbL,0x5b9cca4f7763e373L,0x682e6ff3d6b2b8a3L,
+       
0x748f82ee5defb2fcL,0x78a5636f43172f60L,0x84c87814a1f0ab72L,0x8cc702081a6439ecL,
+       
0x90befffa23631e28L,0xa4506cebde82bde9L,0xbef9a3f7b2c67915L,0xc67178f2e372532bL,
+       
0xca273eceea26619cL,0xd186b8c721c0c207L,0xeada7dd6cde0eb1eL,0xf57d4f7fee6ed178L,
+       
0x06f067aa72176fbaL,0x0a637dc5a2c898a6L,0x113f9804bef90daeL,0x1b710b35131c471bL,
+       
0x28db77f523047d84L,0x32caab7b40c72493L,0x3c9ebe0a15c9bebcL,0x431d67c49c100d4cL,
+       
0x4cc5d4becb3e42b6L,0x597f299cfc657e2aL,0x5fcb6fab3ad6faecL,0x6c44198c4a475817L};
+
+/* functions */
+       private static long S(int n,long x)
+       {
+               return (((x)>>>n) | ((x)<<(64-n)));
+       }
+
+       private static long R(int n,long x)
+       {
+               return ((x)>>>n);
+       }
+
+       private static long Ch(long x,long y,long z)
+       {
+               return ((x&y)^(~(x)&z));
+       }
+
+       private static long Maj(long x,long y,long z)
+       {
+               return ((x&y)^(x&z)^(y&z));
+       }
+
+       private static long Sig0(long x)
+       {
+               return (S(28,x)^S(34,x)^S(39,x));
+       }
+
+       private static long Sig1(long x)
+       {
+               return (S(14,x)^S(18,x)^S(41,x));
+       }
+
+       private static long theta0(long x)
+       {
+               return (S(1,x)^S(8,x)^R(7,x));
+       }
+
+       private static long theta1(long x)
+       {
+               return (S(19,x)^S(61,x)^R(6,x));
+       }
+
+       private void transform()
+       { /* basic transformation step */
+               long a,b,c,d,e,f,g,hh,t1,t2;
+               int j;
+               for (j=16;j<80;j++) 
+                       w[j]=theta1(w[j-2])+w[j-7]+theta0(w[j-15])+w[j-16];
+               a=h[0]; b=h[1]; c=h[2]; d=h[3]; 
+               e=h[4]; f=h[5]; g=h[6]; hh=h[7];
+
+               for (j=0;j<80;j++)
+               { /* 80 times - mush it up */
+                       t1=hh+Sig1(e)+Ch(e,f,g)+K[j]+w[j];
+                       t2=Sig0(a)+Maj(a,b,c);
+                       hh=g; g=f; f=e;
+                       e=d+t1;
+                       d=c;
+                       c=b;
+                       b=a;
+                       a=t1+t2;   
+               
+               }
+               h[0]+=a; h[1]+=b; h[2]+=c; h[3]+=d; 
+               h[4]+=e; h[5]+=f; h[6]+=g; h[7]+=hh; 
+       } 
+
+/* Initialise Hash function */
+       public void init()
+       { /* initialise */
+               int i;
+               for (i=0;i<80;i++) w[i]=0L;
+               length[0]=length[1]=0L;
+               h[0]=H0;
+               h[1]=H1;
+               h[2]=H2;
+               h[3]=H3;
+               h[4]=H4;
+               h[5]=H5;
+               h[6]=H6;
+               h[7]=H7;
+       }
+
+/* Constructor */
+       public HASH384()
+       {
+               init();
+       }
+
+/* process a single byte */
+       public void process(int byt)
+       { /* process the next message byte */
+               int cnt;
+               cnt=(int)(length[0]/64)%16;
+    
+               w[cnt]<<=8;
+               w[cnt]|=(byt&0xFF);
+               length[0]+=8;
+               if (length[0]==0L) { length[1]++; length[0]=0L; }
+               if ((length[0]%1024)==0) transform();
+       }
+
+/* process an array of bytes */        
+       public void process_array(byte[] b)
+       {
+               for (int i=0;i<b.length;i++) process((int)b[i]);
+       }
+
+/* process a 32-bit integer */
+       public void process_num(int n)
+       {
+               process((n>>24)&0xff);
+               process((n>>16)&0xff);
+               process((n>>8)&0xff);
+               process(n&0xff);
+       }
+
+/* Generate 48-byte Hash */
+       public byte[] hash()
+       { /* pad message and finish - supply digest */
+               int i;
+               byte[] digest=new byte[48];
+               long len0,len1;
+               len0=length[0];
+               len1=length[1];
+               process(0x80);
+               while ((length[0]%1024)!=896) process(0);
+               w[14]=len1;
+               w[15]=len0;    
+               transform();
+               for (i=0;i<len;i++)
+               { /* convert to bytes */
+                       digest[i]=(byte)((h[i/8]>>(8*(7-i%8))) & 0xffL);
+               }
+               init();
+               return digest;
+       }
+
+/* test program: should produce digest */
+
+//09330c33f71147e8 3d192fc782cd1b47 53111b173b3b05d2 2fa08086e3b0f712 
fcc7c71a557e2db9 66c3e9fa91746039
+
+       public static void main(String[] args) {
+
+               byte[] 
test="abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu".getBytes();
+               byte[] digest;
+               int i;
+               HASH384 sh=new HASH384();
+  
+               for (i=0;i<test.length;i++)
+                       sh.process(test[i]);
+               
+               digest=sh.hash();    
+               for (i=0;i<48;i++) System.out.format("%02x",digest[i]);
+
+       //      for (i=0;i<32;i++) System.out.format("%d ",digest[i]);
+
+               System.out.println("");
+
+       } 
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/java/HASH512.java
----------------------------------------------------------------------
diff --git a/version22/java/HASH512.java b/version22/java/HASH512.java
new file mode 100644
index 0000000..75379e3
--- /dev/null
+++ b/version22/java/HASH512.java
@@ -0,0 +1,229 @@
+/*
+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.
+*/
+
+/*
+ * Implementation of the Secure Hashing Algorithm (SHA-512)
+ *
+ * Generates a 512 bit message digest. It should be impossible to come
+ * come up with two messages that hash to the same value ("collision free").
+ *
+ * For use with byte-oriented messages only. 
+ */
+
+
+public class HASH512 {
+       private long[] length=new long[2];
+       private long[] h=new long[8];
+       private long[] w=new long[80];
+
+       public static final long H0=0x6a09e667f3bcc908L;
+       public static final long H1=0xbb67ae8584caa73bL;
+       public static final long H2=0x3c6ef372fe94f82bL;
+       public static final long H3=0xa54ff53a5f1d36f1L;
+       public static final long H4=0x510e527fade682d1L;
+       public static final long H5=0x9b05688c2b3e6c1fL;
+       public static final long H6=0x1f83d9abfb41bd6bL;
+       public static final long H7=0x5be0cd19137e2179L;
+
+       public static final int len=64;
+
+       public static final long[] K=
+       
{0x428a2f98d728ae22L,0x7137449123ef65cdL,0xb5c0fbcfec4d3b2fL,0xe9b5dba58189dbbcL,
+       
0x3956c25bf348b538L,0x59f111f1b605d019L,0x923f82a4af194f9bL,0xab1c5ed5da6d8118L,
+       
0xd807aa98a3030242L,0x12835b0145706fbeL,0x243185be4ee4b28cL,0x550c7dc3d5ffb4e2L,
+       
0x72be5d74f27b896fL,0x80deb1fe3b1696b1L,0x9bdc06a725c71235L,0xc19bf174cf692694L,
+       
0xe49b69c19ef14ad2L,0xefbe4786384f25e3L,0x0fc19dc68b8cd5b5L,0x240ca1cc77ac9c65L,
+       
0x2de92c6f592b0275L,0x4a7484aa6ea6e483L,0x5cb0a9dcbd41fbd4L,0x76f988da831153b5L,
+       
0x983e5152ee66dfabL,0xa831c66d2db43210L,0xb00327c898fb213fL,0xbf597fc7beef0ee4L,
+       
0xc6e00bf33da88fc2L,0xd5a79147930aa725L,0x06ca6351e003826fL,0x142929670a0e6e70L,
+       
0x27b70a8546d22ffcL,0x2e1b21385c26c926L,0x4d2c6dfc5ac42aedL,0x53380d139d95b3dfL,
+       
0x650a73548baf63deL,0x766a0abb3c77b2a8L,0x81c2c92e47edaee6L,0x92722c851482353bL,
+       
0xa2bfe8a14cf10364L,0xa81a664bbc423001L,0xc24b8b70d0f89791L,0xc76c51a30654be30L,
+       
0xd192e819d6ef5218L,0xd69906245565a910L,0xf40e35855771202aL,0x106aa07032bbd1b8L,
+       
0x19a4c116b8d2d0c8L,0x1e376c085141ab53L,0x2748774cdf8eeb99L,0x34b0bcb5e19b48a8L,
+       
0x391c0cb3c5c95a63L,0x4ed8aa4ae3418acbL,0x5b9cca4f7763e373L,0x682e6ff3d6b2b8a3L,
+       
0x748f82ee5defb2fcL,0x78a5636f43172f60L,0x84c87814a1f0ab72L,0x8cc702081a6439ecL,
+       
0x90befffa23631e28L,0xa4506cebde82bde9L,0xbef9a3f7b2c67915L,0xc67178f2e372532bL,
+       
0xca273eceea26619cL,0xd186b8c721c0c207L,0xeada7dd6cde0eb1eL,0xf57d4f7fee6ed178L,
+       
0x06f067aa72176fbaL,0x0a637dc5a2c898a6L,0x113f9804bef90daeL,0x1b710b35131c471bL,
+       
0x28db77f523047d84L,0x32caab7b40c72493L,0x3c9ebe0a15c9bebcL,0x431d67c49c100d4cL,
+       
0x4cc5d4becb3e42b6L,0x597f299cfc657e2aL,0x5fcb6fab3ad6faecL,0x6c44198c4a475817L};
+
+/* functions */
+       private static long S(int n,long x)
+       {
+               return (((x)>>>n) | ((x)<<(64-n)));
+       }
+
+       private static long R(int n,long x)
+       {
+               return ((x)>>>n);
+       }
+
+       private static long Ch(long x,long y,long z)
+       {
+               return ((x&y)^(~(x)&z));
+       }
+
+       private static long Maj(long x,long y,long z)
+       {
+               return ((x&y)^(x&z)^(y&z));
+       }
+
+       private static long Sig0(long x)
+       {
+               return (S(28,x)^S(34,x)^S(39,x));
+       }
+
+       private static long Sig1(long x)
+       {
+               return (S(14,x)^S(18,x)^S(41,x));
+       }
+
+       private static long theta0(long x)
+       {
+               return (S(1,x)^S(8,x)^R(7,x));
+       }
+
+       private static long theta1(long x)
+       {
+               return (S(19,x)^S(61,x)^R(6,x));
+       }
+
+
+       private void transform()
+       { /* basic transformation step */
+               long a,b,c,d,e,f,g,hh,t1,t2;
+               int j;
+               for (j=16;j<80;j++) 
+                       w[j]=theta1(w[j-2])+w[j-7]+theta0(w[j-15])+w[j-16];
+               a=h[0]; b=h[1]; c=h[2]; d=h[3]; 
+               e=h[4]; f=h[5]; g=h[6]; hh=h[7];
+
+               for (j=0;j<80;j++)
+               { /* 80 times - mush it up */
+                       t1=hh+Sig1(e)+Ch(e,f,g)+K[j]+w[j];
+                       t2=Sig0(a)+Maj(a,b,c);
+                       hh=g; g=f; f=e;
+                       e=d+t1;
+                       d=c;
+                       c=b;
+                       b=a;
+                       a=t1+t2;   
+               
+               }
+               h[0]+=a; h[1]+=b; h[2]+=c; h[3]+=d; 
+               h[4]+=e; h[5]+=f; h[6]+=g; h[7]+=hh; 
+       } 
+
+/* Initialise Hash function */
+       public void init()
+       { /* initialise */
+               int i;
+               for (i=0;i<80;i++) w[i]=0L;
+               length[0]=length[1]=0L;
+               h[0]=H0;
+               h[1]=H1;
+               h[2]=H2;
+               h[3]=H3;
+               h[4]=H4;
+               h[5]=H5;
+               h[6]=H6;
+               h[7]=H7;
+       }
+
+/* Constructor */
+       public HASH512()
+       {
+               init();
+       }
+
+/* process a single byte */
+       public void process(int byt)
+       { /* process the next message byte */
+               int cnt;
+               cnt=(int)(length[0]/64)%16;
+    
+               w[cnt]<<=8;
+               w[cnt]|=(byt&0xFF);
+               length[0]+=8;
+               if (length[0]==0L) { length[1]++; length[0]=0L; }
+               if ((length[0]%1024)==0) transform();
+       }
+
+/* process an array of bytes */        
+       public void process_array(byte[] b)
+       {
+               for (int i=0;i<b.length;i++) process((int)b[i]);
+       }
+
+/* process a 32-bit integer */
+       public void process_num(int n)
+       {
+               process((n>>24)&0xff);
+               process((n>>16)&0xff);
+               process((n>>8)&0xff);
+               process(n&0xff);
+       }
+
+/* Generate 64-byte Hash */
+       public byte[] hash()
+       { /* pad message and finish - supply digest */
+               int i;
+               byte[] digest=new byte[64];
+               long len0,len1;
+               len0=length[0];
+               len1=length[1];
+               process(0x80);
+               while ((length[0]%1024)!=896) process(0);
+               w[14]=len1;
+               w[15]=len0;    
+               transform();
+               for (i=0;i<len;i++)
+               { /* convert to bytes */
+                       digest[i]=(byte)((h[i/8]>>(8*(7-i%8))) & 0xffL);
+               }
+               init();
+               return digest;
+       }
+
+/* test program: should produce digest */
+
+//8e959b75dae313da 8cf4f72814fc143f 8f7779c6eb9f7fa1 7299aeadb6889018 
501d289e4900f7e4 331b99dec4b5433a c7d329eeb6dd2654 5e96e55b874be909
+
+       public static void main(String[] args) {
+
+               byte[] 
test="abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu".getBytes();
+               byte[] digest;
+               int i;
+               HASH512 sh=new HASH512();
+  
+               for (i=0;i<test.length;i++)
+                       sh.process(test[i]);
+               
+               digest=sh.hash();    
+               for (i=0;i<64;i++) System.out.format("%02x",digest[i]);
+
+       //      for (i=0;i<32;i++) System.out.format("%d ",digest[i]);
+
+               System.out.println("");
+
+       } 
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/java/MPIN.java
----------------------------------------------------------------------
diff --git a/version22/java/MPIN.java b/version22/java/MPIN.java
new file mode 100644
index 0000000..a2bd094
--- /dev/null
+++ b/version22/java/MPIN.java
@@ -0,0 +1,853 @@
+/*
+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 API Functions */
+
+import java.util.Date;
+
+public class MPIN
+{
+       public static final int EFS=ROM.MODBYTES;
+       public static final int EGS=ROM.MODBYTES;
+       public static final int PAS=16;
+       public static final int INVALID_POINT=-14;
+       public static final int BAD_PARAMS=-11;
+       public static final int WRONG_ORDER=-18;
+       public static final int BAD_PIN=-19;
+       public static final int SHA256=32;
+       public static final int SHA384=48;
+       public static final int SHA512=64;
+
+/* Configure your PIN here */
+
+       public static final int MAXPIN=10000;  /* PIN less than this */
+       public static final int PBLEN=14;      /* Number of bits in PIN */
+       public static final int TS=10;         /* 10 for 4 digit PIN, 14 for 
6-digit PIN - 2^TS/TS approx = sqrt(MAXPIN) */
+       public static final int TRAP=200;      /* 200 for 4 digit PIN, 2000 for 
6-digit PIN  - approx 2*sqrt(MAXPIN) */
+
+       public static final int HASH_TYPE=SHA256;
+
+       public static byte[] mpin_hash(int sha,FP4 c,ECP U)
+       {
+               byte[] w=new byte[EFS];
+               byte[] t=new byte[6*EFS];
+               byte[] h=null;
+               c.geta().getA().toBytes(w); for (int i=0;i<EFS;i++) t[i]=w[i];
+               c.geta().getB().toBytes(w); for (int i=EFS;i<2*EFS;i++) 
t[i]=w[i-EFS];
+               c.getb().getA().toBytes(w); for (int i=2*EFS;i<3*EFS;i++) 
t[i]=w[i-2*EFS];
+               c.getb().getB().toBytes(w); for (int i=3*EFS;i<4*EFS;i++) 
t[i]=w[i-3*EFS];
+               
+               U.getX().toBytes(w); for (int i=4*EFS;i<5*EFS;i++) 
t[i]=w[i-4*EFS];
+               U.getY().toBytes(w); for (int i=5*EFS;i<6*EFS;i++) 
t[i]=w[i-5*EFS];
+               
+               if (sha==SHA256)
+               {
+                       HASH256 H=new HASH256();
+                       H.process_array(t);
+                       h=H.hash();
+               }
+               if (sha==SHA384)
+               {
+                       HASH384 H=new HASH384();
+                       H.process_array(t);
+                       h=H.hash();
+               }
+               if (sha==SHA512)
+               {
+                       HASH512 H=new HASH512();
+                       H.process_array(t);
+                       h=H.hash();
+               }
+               if (h==null) return null;
+               byte[] R=new byte[PAS];
+               for (int i=0;i<PAS;i++) R[i]=h[i];
+               return R;
+       }
+
+/* Hash number (optional) and string to array size of Bigs */
+
+       public static byte[] hashit(int sha,int n,byte[] B)
+       {
+               byte[] R=null;
+
+               if (sha==SHA256)
+               {
+                       HASH256 H=new HASH256();
+                       if (n>0) H.process_num(n);
+                       H.process_array(B);
+                       R=H.hash();
+               }
+               if (sha==SHA384)
+               {
+                       HASH384 H=new HASH384();
+                       if (n>0) H.process_num(n);
+                       H.process_array(B);
+                       R=H.hash();
+               }
+               if (sha==SHA512)
+               {
+                       HASH512 H=new HASH512();
+                       if (n>0) H.process_num(n);
+                       H.process_array(B);
+                       R=H.hash();
+               }
+               if (R==null) return null;
+               byte[] W=new byte[ROM.MODBYTES];
+
+               if (sha>=ROM.MODBYTES)
+                       for (int i=0;i<ROM.MODBYTES;i++) W[i]=R[i];
+               else
+               {
+                       for (int i=0;i<sha;i++) W[i]=R[i];
+                       for (int i=sha;i<ROM.MODBYTES;i++) W[i]=0;
+               }
+               return W;
+       }
+
+       public static ECP mapit(byte[] h)
+       {
+               BIG q=new BIG(ROM.Modulus);
+               BIG x=BIG.fromBytes(h);
+               x.mod(q);
+               ECP P;
+               while (true)
+               {
+                       P=new ECP(x,0);
+                       if (!P.is_infinity()) break;
+                       x.inc(1); x.norm();
+               }
+
+               if (ROM.CURVE_PAIRING_TYPE!=ROM.BN_CURVE)
+               {
+                       BIG c=new BIG(ROM.CURVE_Cof);
+                       P=P.mul(c);
+               }
+               return P;
+       }
+
+/* needed for SOK */
+       public static ECP2 mapit2(byte[] h)
+       {
+               BIG q=new BIG(ROM.Modulus);
+               BIG x=BIG.fromBytes(h);
+               BIG one=new BIG(1);
+               FP2 X;
+               ECP2 Q,T,K;
+               x.mod(q);
+               while (true)
+               {
+                       X=new FP2(one,x);
+                       Q=new ECP2(X);
+                       if (!Q.is_infinity()) break;
+                       x.inc(1); x.norm();
+               }
+/* Fast Hashing to G2 - Fuentes-Castaneda, Knapp and Rodriguez-Henriquez */
+               BIG Fra=new BIG(ROM.CURVE_Fra);
+               BIG Frb=new BIG(ROM.CURVE_Frb);
+               X=new FP2(Fra,Frb);
+               x=new BIG(ROM.CURVE_Bnx);
+
+               T=new ECP2(); T.copy(Q);
+               T.mul(x); T.neg();
+               K=new ECP2(); K.copy(T);
+               K.dbl(); K.add(T); K.affine();
+
+               K.frob(X);
+               Q.frob(X); Q.frob(X); Q.frob(X);
+               Q.add(T); Q.add(K);
+               T.frob(X); T.frob(X);
+               Q.add(T);
+               Q.affine();
+               return Q;
+       }
+
+/* return time in slots since epoch */
+       public static int today() {
+               Date date=new Date();
+               return (int) (date.getTime()/(1000*60*1440));
+       }
+
+/* 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 */
+       public static ECP map(BIG u,int cb)
+       {
+               ECP P;
+               BIG x=new BIG(u);
+               BIG p=new BIG(ROM.Modulus);
+               x.mod(p);
+               while (true)
+               {
+                       P=new ECP(x,cb);
+                       if (!P.is_infinity()) break;
+                       x.inc(1);  x.norm();
+               }
+               return P;
+       }
+
+/* returns u derived from P. Random value in range 1 to return value should 
then be added to u */
+       public static int unmap(BIG u,ECP P)
+       {
+               int s=P.getS();
+               ECP R;
+               int r=0;
+               BIG x=P.getX();
+               u.copy(x);
+               while (true)
+               {
+                       u.dec(1); u.norm();
+                       r++;
+                       R=new ECP(u,s);
+                       if (!R.is_infinity()) break;
+               }
+               return r;
+       }
+
+       public static byte[] HASH_ID(int sha,byte[] ID)
+       {
+               return hashit(sha,0,ID);
+       }
+
+
+/* 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 */
+       public static int ENCODING(RAND rng,byte[] E)
+       {
+               int rn,m,su,sv;
+               byte[] T=new byte[EFS];
+
+               for (int i=0;i<EFS;i++) T[i]=E[i+1];
+               BIG u=BIG.fromBytes(T);
+               for (int i=0;i<EFS;i++) T[i]=E[i+EFS+1];
+               BIG v=BIG.fromBytes(T);
+               
+               ECP P=new ECP(u,v);
+               if (P.is_infinity()) return INVALID_POINT;
+
+               BIG p=new BIG(ROM.Modulus);
+               u=BIG.randomnum(p,rng);
+
+               su=rng.getByte(); /*if (su<0) su=-su;*/ su%=2;
+               
+               ECP W=map(u,su);
+               P.sub(W);
+               sv=P.getS();
+               rn=unmap(v,P);
+               m=rng.getByte(); /*if (m<0) m=-m;*/ m%=rn;
+               v.inc(m+1);
+               E[0]=(byte)(su+2*sv);
+               u.toBytes(T);
+               for (int i=0;i<EFS;i++) E[i+1]=T[i];
+               v.toBytes(T);
+               for (int i=0;i<EFS;i++) E[i+EFS+1]=T[i];                
+               
+               return 0;
+       }
+
+       public static int DECODING(byte[] D)
+       {
+               int su,sv;
+               byte[] T=new byte[EFS];
+
+               if ((D[0]&0x04)!=0) return INVALID_POINT;
+
+               for (int i=0;i<EFS;i++) T[i]=D[i+1];
+               BIG u=BIG.fromBytes(T);
+               for (int i=0;i<EFS;i++) T[i]=D[i+EFS+1];
+               BIG v=BIG.fromBytes(T);
+
+               su=D[0]&1;
+               sv=(D[0]>>1)&1;
+               ECP W=map(u,su);
+               ECP P=map(v,sv);
+               P.add(W);
+               u=P.getX();
+               v=P.getY();
+               D[0]=0x04;
+               u.toBytes(T);
+               for (int i=0;i<EFS;i++) D[i+1]=T[i];
+               v.toBytes(T);
+               for (int i=0;i<EFS;i++) D[i+EFS+1]=T[i];                
+               
+               return 0;
+       }
+
+/* R=R1+R2 in group G1 */
+       public static int RECOMBINE_G1(byte[] R1,byte[] R2,byte[] R)
+       {
+               ECP P=ECP.fromBytes(R1);
+               ECP Q=ECP.fromBytes(R2);
+
+               if (P.is_infinity() || Q.is_infinity()) return INVALID_POINT;
+
+               P.add(Q);
+
+               P.toBytes(R);
+               return 0;
+       }
+
+/* W=W1+W2 in group G2 */
+       public static int RECOMBINE_G2(byte[] W1,byte[] W2,byte[] W)
+       {
+               ECP2 P=ECP2.fromBytes(W1);
+               ECP2 Q=ECP2.fromBytes(W2);
+
+               if (P.is_infinity() || Q.is_infinity()) return INVALID_POINT;
+
+               P.add(Q);
+       
+               P.toBytes(W);
+               return 0;
+       }
+       
+/* create random secret S */
+       public static int RANDOM_GENERATE(RAND rng,byte[] S)
+       {
+               BIG s;
+               BIG r=new BIG(ROM.CURVE_Order);
+               s=BIG.randomnum(r,rng);
+               if (ROM.AES_S>0)
+               {
+                       s.mod2m(2*ROM.AES_S);
+               }
+               s.toBytes(S);
+               return 0;
+       }
+
+/* Extract PIN from TOKEN for identity CID */
+       public static int EXTRACT_PIN(int sha,byte[] CID,int pin,byte[] TOKEN)
+       {
+               ECP P=ECP.fromBytes(TOKEN);
+               if (P.is_infinity()) return INVALID_POINT;
+               byte[] h=hashit(sha,0,CID);
+               ECP R=mapit(h);
+
+
+               pin%=MAXPIN;
+
+               R=R.pinmul(pin,PBLEN);
+               P.sub(R);
+
+               P.toBytes(TOKEN);
+
+               return 0;
+       }
+
+/* Implement step 2 on client side of MPin protocol */
+       public static int CLIENT_2(byte[] X,byte[] Y,byte[] SEC)
+       {
+               BIG r=new BIG(ROM.CURVE_Order);
+               ECP P=ECP.fromBytes(SEC);
+               if (P.is_infinity()) return INVALID_POINT;
+
+               BIG px=BIG.fromBytes(X);
+               BIG py=BIG.fromBytes(Y);
+               px.add(py);
+               px.mod(r);
+       //      px.rsub(r);
+
+               P=PAIR.G1mul(P,px);
+               P.neg();
+               P.toBytes(SEC);
+               return 0;
+       }
+
+/* Implement step 1 on client side of MPin protocol */
+       public static int CLIENT_1(int sha,int date,byte[] CLIENT_ID,RAND 
rng,byte[] X,int pin,byte[] TOKEN,byte[] SEC,byte[] xID,byte[] xCID,byte[] 
PERMIT)
+       {
+               BIG r=new BIG(ROM.CURVE_Order);
+               BIG x;
+               if (rng!=null)
+               {
+                       x=BIG.randomnum(r,rng);
+                       if (ROM.AES_S>0)
+                       {
+                               x.mod2m(2*ROM.AES_S);
+                       }
+                       x.toBytes(X);
+               }
+               else
+               {
+                       x=BIG.fromBytes(X);
+               }
+               ECP P,T,W;
+               BIG px;
+//             byte[] t=new byte[EFS];
+
+               byte[] h=hashit(sha,0,CLIENT_ID);
+               P=mapit(h);
+       
+               T=ECP.fromBytes(TOKEN);
+               if (T.is_infinity()) return INVALID_POINT;
+
+               pin%=MAXPIN;
+               W=P.pinmul(pin,PBLEN);
+               T.add(W);
+               if (date!=0)
+               {
+                       W=ECP.fromBytes(PERMIT);
+                       if (W.is_infinity()) return INVALID_POINT;
+                       T.add(W);
+                       h=hashit(sha,date,h);
+                       W=mapit(h);
+                       if (xID!=null)
+                       {
+                               P=PAIR.G1mul(P,x);
+                               P.toBytes(xID);
+                               W=PAIR.G1mul(W,x);
+                               P.add(W);
+                       }
+                       else
+                       {
+                               P.add(W);
+                               P=PAIR.G1mul(P,x);
+                       }
+                       if (xCID!=null) P.toBytes(xCID);
+               }
+               else
+               {
+                       if (xID!=null)
+                       {
+                               P=PAIR.G1mul(P,x);
+                               P.toBytes(xID);
+                       }
+               }
+
+
+               T.toBytes(SEC);
+               return 0;
+       }
+
+/* Extract Server Secret SST=S*Q where Q is fixed generator in G2 and S is 
master secret */
+       public static int GET_SERVER_SECRET(byte[] S,byte[] SST)
+       {
+               ECP2 Q=new ECP2(new FP2(new BIG(ROM.CURVE_Pxa),new 
BIG(ROM.CURVE_Pxb)),new FP2(new BIG(ROM.CURVE_Pya),new BIG(ROM.CURVE_Pyb)));
+
+               BIG s=BIG.fromBytes(S);
+               Q=PAIR.G2mul(Q,s);
+               Q.toBytes(SST);
+               return 0;
+       }
+
+/*
+ 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
+*/
+       public static int GET_G1_MULTIPLE(RAND rng, int type,byte[] X,byte[] 
G,byte[] W)
+       {
+               BIG x;
+               BIG r=new BIG(ROM.CURVE_Order);
+               if (rng!=null)
+               {
+                       x=BIG.randomnum(r,rng);
+                       if (ROM.AES_S>0)
+                       {
+                               x.mod2m(2*ROM.AES_S);
+                       }
+                       x.toBytes(X);
+               }
+               else
+               {
+                       x=BIG.fromBytes(X);
+               }
+               ECP P;
+               if (type==0)
+               {
+                       P=ECP.fromBytes(G);
+                       if (P.is_infinity()) return INVALID_POINT;
+               }
+               else
+                       P=mapit(G);
+
+               PAIR.G1mul(P,x).toBytes(W);
+               return 0;
+       }
+
+/* Client secret CST=S*H(CID) where CID is client ID and S is master secret */
+/* CID is hashed externally */
+       public static int GET_CLIENT_SECRET(byte[] S,byte[] CID,byte[] CST)
+       {
+               return GET_G1_MULTIPLE(null,1,S,CID,CST);
+       }
+
+/* Time Permit CTT=S*(date|H(CID)) where S is master secret */
+       public static int GET_CLIENT_PERMIT(int sha,int date,byte[] S,byte[] 
CID,byte[] CTT)
+       {
+               byte[] h=hashit(sha,date,CID);
+               ECP P=mapit(h);
+
+               BIG s=BIG.fromBytes(S);
+               PAIR.G1mul(P,s).toBytes(CTT);
+               return 0;
+       }
+
+/* Outputs H(CID) and H(T|H(CID)) for time permits. If no time permits set 
HID=HTID */
+       public static void SERVER_1(int sha,int date,byte[] CID,byte[] 
HID,byte[] HTID)
+       {
+               byte[] h=hashit(sha,0,CID);
+               ECP R,P=mapit(h);
+
+               P.toBytes(HID);   // new
+               if (date!=0)
+               {
+       //              if (HID!=null) P.toBytes(HID);
+                       h=hashit(sha,date,h);
+                       R=mapit(h);
+                       P.add(R);
+                       P.toBytes(HTID);
+               }
+       //      else P.toBytes(HID);
+       }
+
+/* Implement step 2 of MPin protocol on server side */
+       public static int SERVER_2(int date,byte[] HID,byte[] HTID,byte[] 
Y,byte[] SST,byte[] xID,byte[] xCID,byte[] mSEC,byte[] E,byte[] F)
+       {
+               BIG q=new BIG(ROM.Modulus);
+               ECP2 Q=new ECP2(new FP2(new BIG(ROM.CURVE_Pxa),new 
BIG(ROM.CURVE_Pxb)),new FP2(new BIG(ROM.CURVE_Pya),new BIG(ROM.CURVE_Pyb)));
+
+               ECP2 sQ=ECP2.fromBytes(SST);
+               if (sQ.is_infinity()) return INVALID_POINT;     
+
+               ECP R;
+               if (date!=0)
+                       R=ECP.fromBytes(xCID);
+               else 
+               {
+                       if (xID==null) return BAD_PARAMS;
+                       R=ECP.fromBytes(xID);
+               }
+               if (R.is_infinity()) return INVALID_POINT;
+
+               BIG y=BIG.fromBytes(Y);
+               ECP P;
+               if (date!=0) P=ECP.fromBytes(HTID);
+               else 
+               {
+                       if (HID==null) return BAD_PARAMS;
+                       P=ECP.fromBytes(HID);
+               }
+       
+               if (P.is_infinity()) return INVALID_POINT;
+
+               P=PAIR.G1mul(P,y);
+               P.add(R);
+               R=ECP.fromBytes(mSEC);
+               if (R.is_infinity()) return INVALID_POINT;
+
+               FP12 g;
+
+               g=PAIR.ate2(Q,R,sQ,P);
+               g=PAIR.fexp(g);
+
+               if (!g.isunity())
+               {
+                       if (HID!=null && xID!=null && E!=null && F!=null)
+                       {
+                               g.toBytes(E);
+                               if (date!=0)
+                               {
+                                       P=ECP.fromBytes(HID);
+                                       if (P.is_infinity()) return 
INVALID_POINT;
+                                       R=ECP.fromBytes(xID);
+                                       if (R.is_infinity()) return 
INVALID_POINT;
+
+                                       P=PAIR.G1mul(P,y);
+                                       P.add(R);
+                               }
+                               g=PAIR.ate(Q,P);
+                               g=PAIR.fexp(g);
+                               g.toBytes(F);
+                       }
+                       return BAD_PIN;
+               }
+
+               return 0;
+       }
+
+/* Pollards kangaroos used to return PIN error */
+       public static int KANGAROO(byte[] E,byte[] F)
+       {
+               FP12 ge=FP12.fromBytes(E);
+               FP12 gf=FP12.fromBytes(F);
+               int[] distance = new int[TS];
+               FP12 t=new FP12(gf);
+               FP12[] table=new FP12[TS];
+               int i,j,m,s,dn,dm,res,steps;
+
+               s=1;
+               for (m=0;m<TS;m++)
+               {
+                       distance[m]=s;
+                       table[m]=new FP12(t);
+                       s*=2;
+                       t.usqr();
+               }
+               t.one();
+               dn=0;
+               for (j=0;j<TRAP;j++)
+               {
+                       i=t.geta().geta().getA().lastbits(20)%TS;
+                       t.mul(table[i]);
+                       dn+=distance[i];
+               }
+               gf.copy(t); gf.conj();
+               steps=0; dm=0;
+               res=0;
+               while (dm-dn<MAXPIN)
+               {
+                       steps++;
+                       if (steps>4*TRAP) break;
+                       i=ge.geta().geta().getA().lastbits(20)%TS;
+                       ge.mul(table[i]);
+                       dm+=distance[i];
+                       if (ge.equals(t))
+                       {
+                               res=dm-dn;
+                               break;
+                       }
+                       if (ge.equals(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 */
+
+       public static int PRECOMPUTE(byte[] TOKEN,byte[] CID,byte[] G1,byte[] 
G2)
+       {
+               ECP P,T;
+               FP12 g;
+
+               T=ECP.fromBytes(TOKEN);
+               if (T.is_infinity()) return INVALID_POINT; 
+
+               P=mapit(CID);
+
+               ECP2 Q=new ECP2(new FP2(new BIG(ROM.CURVE_Pxa),new 
BIG(ROM.CURVE_Pxb)),new FP2(new BIG(ROM.CURVE_Pya),new BIG(ROM.CURVE_Pyb)));
+
+               g=PAIR.ate(Q,T);
+               g=PAIR.fexp(g);
+               g.toBytes(G1);
+
+               g=PAIR.ate(Q,P);
+               g=PAIR.fexp(g);
+               g.toBytes(G2);
+
+               return 0;
+       }
+
+/* Hash the M-Pin transcript - new */
+
+       public static byte[] HASH_ALL(int sha,byte[] HID,byte[] xID,byte[] 
xCID,byte[] SEC,byte[] Y,byte[] R,byte[] W)
+       {
+               int i,tlen=0;
+               byte[] T = new byte[10*ROM.MODBYTES+4];
+
+               for (i=0;i<HID.length;i++) T[i]=HID[i];
+               tlen+=HID.length;
+               if (xCID!=null)
+               {
+                       for (i=0;i<xCID.length;i++) T[i+tlen]=xCID[i];
+                       tlen+=xCID.length;
+               }       
+               else
+               {
+                       for (i=0;i<xID.length;i++) T[i+tlen]=xID[i];
+                       tlen+=xID.length;
+               }       
+               for (i=0;i<SEC.length;i++) T[i+tlen]=SEC[i];
+               tlen+=SEC.length;               
+               for (i=0;i<Y.length;i++) T[i+tlen]=Y[i];
+               tlen+=Y.length; 
+               for (i=0;i<R.length;i++) T[i+tlen]=R[i];
+               tlen+=R.length;         
+               for (i=0;i<W.length;i++) T[i+tlen]=W[i];
+               tlen+=W.length;         
+
+               return hashit(sha,0,T);
+       }
+
+/* calculate common key on client side */
+/* wCID = w.(A+AT) */
+       public static int CLIENT_KEY(int sha,byte[] G1,byte[] G2,int pin,byte[] 
R,byte[] X,byte[] H,byte[] wCID,byte[] CK)
+       {
+               byte[] t;
+
+               FP12 g1=FP12.fromBytes(G1);
+               FP12 g2=FP12.fromBytes(G2);
+               BIG z=BIG.fromBytes(R);
+               BIG x=BIG.fromBytes(X);
+               BIG h=BIG.fromBytes(H);
+
+               ECP W=ECP.fromBytes(wCID);
+               if (W.is_infinity()) return INVALID_POINT; 
+
+               W=PAIR.G1mul(W,x);
+
+               FP2 f=new FP2(new BIG(ROM.CURVE_Fra),new BIG(ROM.CURVE_Frb));
+               BIG r=new BIG(ROM.CURVE_Order);
+               BIG q=new BIG(ROM.Modulus);
+
+               z.add(h);       //new
+               z.mod(r);
+
+               BIG m=new BIG(q);
+               m.mod(r);
+
+               BIG a=new BIG(z);
+               a.mod(m);
+
+               BIG b=new BIG(z);
+               b.div(m);
+
+               g2.pinpow(pin,PBLEN);
+               g1.mul(g2);
+
+               FP4 c=g1.trace();
+               g2.copy(g1);
+               g2.frob(f);
+               FP4 cp=g2.trace();
+               g1.conj();
+               g2.mul(g1);
+               FP4 cpm1=g2.trace();
+               g2.mul(g1);
+               FP4 cpm2=g2.trace();
+
+               c=c.xtr_pow2(cp,cpm1,cpm2,a,b);
+
+               t=mpin_hash(sha,c,W);
+
+               for (int i=0;i<PAS;i++) CK[i]=t[i];
+
+               return 0;
+       }
+
+/* calculate common key on server side */
+/* Z=r.A - no time permits involved */
+
+       public static int SERVER_KEY(int sha,byte[] Z,byte[] SST,byte[] 
W,byte[] H,byte[] HID,byte[] xID,byte[] xCID,byte[] SK)
+       {
+               byte[] t;
+
+               ECP2 sQ=ECP2.fromBytes(SST);
+               if (sQ.is_infinity()) return INVALID_POINT; 
+               ECP R=ECP.fromBytes(Z);
+               if (R.is_infinity()) return INVALID_POINT; 
+               ECP A=ECP.fromBytes(HID);
+               if (A.is_infinity()) return INVALID_POINT; 
+
+               ECP U;
+               if (xCID!=null)
+                       U=ECP.fromBytes(xCID);
+               else
+                       U=ECP.fromBytes(xID);
+               if (U.is_infinity()) return INVALID_POINT; 
+
+               BIG w=BIG.fromBytes(W);
+               BIG h=BIG.fromBytes(H);
+               A=PAIR.G1mul(A,h);      // new
+               R.add(A);
+
+               U=PAIR.G1mul(U,w);
+               FP12 g=PAIR.ate(sQ,R);
+               g=PAIR.fexp(g);
+
+               FP4 c=g.trace();
+
+               t=mpin_hash(sha,c,U);
+
+               for (int i=0;i<PAS;i++) SK[i]=t[i];
+
+               return 0;
+       }
+
+/* return time since epoch */
+       public static int GET_TIME() {
+               Date date=new Date();
+               return (int) (date.getTime()/1000);
+       }
+
+/* Generate Y = H(epoch, xCID/xID) */
+       public static void GET_Y(int sha,int TimeValue,byte[] xCID,byte[] Y)
+       {
+               byte[] h = hashit(sha,TimeValue,xCID);
+               BIG y = BIG.fromBytes(h);
+               BIG q=new BIG(ROM.CURVE_Order);
+               y.mod(q);
+               if (ROM.AES_S>0)
+               {
+                       y.mod2m(2*ROM.AES_S);
+               }
+               y.toBytes(Y);
+       }
+        
+/* One pass MPIN Client */
+        public static int CLIENT(int sha,int date,byte[] CLIENT_ID,RAND 
RNG,byte[] X,int pin,byte[] TOKEN,byte[] SEC,byte[] xID,byte[] xCID,byte[] 
PERMIT, int TimeValue, byte[] Y)
+        {
+          int rtn=0;
+        
+          byte[] pID;
+          if (date == 0)
+            pID = xID;
+          else
+            pID = xCID;
+          
+          rtn = 
CLIENT_1(sha,date,CLIENT_ID,RNG,X,pin,TOKEN,SEC,xID,xCID,PERMIT);
+          if (rtn != 0)
+            return rtn;
+        
+          GET_Y(sha,TimeValue,pID,Y);
+        
+          rtn = CLIENT_2(X,Y,SEC);
+          if (rtn != 0)
+            return rtn;
+        
+          return 0;
+        }
+        
+/* One pass MPIN Server */
+        public static int SERVER(int sha,int date,byte[] HID,byte[] 
HTID,byte[] Y,byte[] SST,byte[] xID,byte[] xCID,byte[] SEC,byte[] E,byte[] 
F,byte[] CID, int TimeValue)
+        {
+          int rtn=0;
+        
+          byte[] pID;
+          if (date == 0)
+            pID = xID;
+          else
+            pID = xCID;
+          
+          SERVER_1(sha,date,CID,HID,HTID);
+        
+          GET_Y(sha,TimeValue,pID,Y);
+          
+          rtn = SERVER_2(date,HID,HTID,Y,SST,xID,xCID,SEC,E,F);
+          if (rtn != 0)
+            return rtn;
+        
+          return 0;
+        }
+        
+}

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/java/PAIR.java
----------------------------------------------------------------------
diff --git a/version22/java/PAIR.java b/version22/java/PAIR.java
new file mode 100644
index 0000000..518f3ae
--- /dev/null
+++ b/version22/java/PAIR.java
@@ -0,0 +1,685 @@
+/*
+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 BN Curve Pairing functions */
+
+public final class PAIR {
+
+/* Line function */
+       public static FP12 line(ECP2 A,ECP2 B,FP Qx,FP Qy)
+       {
+               ECP2 P=new ECP2();
+
+               FP4 a,b,c;
+               P.copy(A);
+               FP2 ZZ=new FP2(P.getz());
+               ZZ.sqr();
+               int D;
+               if (A==B) D=A.dbl(); /* Check this return value in ecp2.c */
+               else D=A.add(B);
+               if (D<0) 
+                       return new FP12(1);
+               FP2 Z3=new FP2(A.getz());
+               c=new FP4(0);
+               if (D==0)
+               { /* Addition */
+                       FP2 X=new FP2(B.getx());
+                       FP2 Y=new FP2(B.gety());
+                       FP2 T=new FP2(P.getz()); 
+                       T.mul(Y);
+                       ZZ.mul(T);
+
+                       FP2 NY=new FP2(P.gety()); NY.neg();
+                       ZZ.add(NY);
+                       Z3.pmul(Qy);
+                       T.mul(P.getx());
+                       X.mul(NY);
+                       T.add(X);
+                       a=new FP4(Z3,T);
+                       ZZ.neg();
+                       ZZ.pmul(Qx);
+                       b=new FP4(ZZ);
+               }
+               else
+               { /* Doubling */
+                       FP2 X=new FP2(P.getx());
+                       FP2 Y=new FP2(P.gety());
+                       FP2 T=new FP2(P.getx());
+                       T.sqr();
+                       T.imul(3);
+
+                       Y.sqr();
+                       Y.add(Y);
+                       Z3.mul(ZZ);
+                       Z3.pmul(Qy);
+
+                       X.mul(T);
+                       X.sub(Y);
+                       a=new FP4(Z3,X);
+                       T.neg();
+                       ZZ.mul(T);
+                       ZZ.pmul(Qx);
+                       b=new FP4(ZZ);
+               }
+               return new FP12(a,b,c);
+       }
+
+/* Optimal R-ate pairing */
+       public static FP12 ate(ECP2 P,ECP Q)
+       {
+               FP2 f=new FP2(new BIG(ROM.CURVE_Fra),new BIG(ROM.CURVE_Frb));
+               BIG x=new BIG(ROM.CURVE_Bnx);
+               BIG n=new BIG(x);
+               ECP2 K=new ECP2();
+               FP12 lv;
+
+               if (ROM.CURVE_PAIRING_TYPE==ROM.BN_CURVE)
+               {
+                       n.pmul(6); n.dec(2);
+               }
+               else
+                       n.copy(x);
+               n.norm();
+               
+               P.affine();
+               Q.affine();
+               FP Qx=new FP(Q.getx());
+               FP Qy=new FP(Q.gety());
+
+               ECP2 A=new ECP2();
+               FP12 r=new FP12(1);
+
+               A.copy(P);
+               int nb=n.nbits();
+
+               for (int i=nb-2;i>=1;i--)
+               {
+                       lv=line(A,A,Qx,Qy);
+                       r.smul(lv);
+
+                       if (n.bit(i)==1)
+                       {
+                               lv=line(A,P,Qx,Qy);
+                               r.smul(lv);
+                       }
+                       r.sqr();
+               }
+
+               lv=line(A,A,Qx,Qy);
+               r.smul(lv);
+               if (n.parity()==1)
+               {
+                       lv=line(A,P,Qx,Qy);
+                       r.smul(lv);
+               }
+
+/* R-ate fixup required for BN curves */
+               if (ROM.CURVE_PAIRING_TYPE==ROM.BN_CURVE)
+               {
+                       r.conj();
+                       K.copy(P);
+                       K.frob(f);
+                       A.neg();
+                       lv=line(A,K,Qx,Qy);
+                       r.smul(lv);
+                       K.frob(f);
+                       K.neg();
+                       lv=line(A,K,Qx,Qy);
+                       r.smul(lv);
+               }
+               return r;
+       }
+
+/* Optimal R-ate double pairing e(P,Q).e(R,S) */
+       public static FP12 ate2(ECP2 P,ECP Q,ECP2 R,ECP S)
+       {
+               FP2 f=new FP2(new BIG(ROM.CURVE_Fra),new BIG(ROM.CURVE_Frb));
+               BIG x=new BIG(ROM.CURVE_Bnx);
+               BIG n=new BIG(x);
+               ECP2 K=new ECP2();
+               FP12 lv;
+
+               if (ROM.CURVE_PAIRING_TYPE==ROM.BN_CURVE)
+               {
+                       n.pmul(6); n.dec(2);
+               }
+               else
+                       n.copy(x);
+               n.norm();
+
+               P.affine();
+               Q.affine();
+               R.affine();
+               S.affine();
+
+               FP Qx=new FP(Q.getx());
+               FP Qy=new FP(Q.gety());
+               FP Sx=new FP(S.getx());
+               FP Sy=new FP(S.gety());
+
+               ECP2 A=new ECP2();
+               ECP2 B=new ECP2();
+               FP12 r=new FP12(1);
+
+               A.copy(P);
+               B.copy(R);
+               int nb=n.nbits();
+
+               for (int i=nb-2;i>=1;i--)
+               {
+                       lv=line(A,A,Qx,Qy);
+                       r.smul(lv);
+                       lv=line(B,B,Sx,Sy);
+                       r.smul(lv);
+
+                       if (n.bit(i)==1)
+                       {
+                               lv=line(A,P,Qx,Qy);
+                               r.smul(lv);
+                               lv=line(B,R,Sx,Sy);
+                               r.smul(lv);
+                       }
+                       r.sqr();
+               }
+
+               lv=line(A,A,Qx,Qy);
+               r.smul(lv);
+               lv=line(B,B,Sx,Sy);
+               r.smul(lv);
+               if (n.parity()==1)
+               {
+                       lv=line(A,P,Qx,Qy);
+                       r.smul(lv);
+                       lv=line(B,R,Sx,Sy);
+                       r.smul(lv);
+               }
+
+/* R-ate fixup required for BN curves */
+               if (ROM.CURVE_PAIRING_TYPE==ROM.BN_CURVE)
+               {
+                       r.conj();
+                       K.copy(P);
+                       K.frob(f);
+                       A.neg();
+                       lv=line(A,K,Qx,Qy);
+                       r.smul(lv);
+                       K.frob(f);
+                       K.neg();
+                       lv=line(A,K,Qx,Qy);
+                       r.smul(lv);
+
+                       K.copy(R);
+                       K.frob(f);
+                       B.neg();
+                       lv=line(B,K,Sx,Sy);
+                       r.smul(lv);
+                       K.frob(f);
+                       K.neg();
+                       lv=line(B,K,Sx,Sy);
+                       r.smul(lv);
+               }
+               return r;
+       }
+
+/* final exponentiation - keep separate for multi-pairings and to avoid 
thrashing stack */
+       public static FP12 fexp(FP12 m)
+       {
+               FP2 f=new FP2(new BIG(ROM.CURVE_Fra),new BIG(ROM.CURVE_Frb));
+               BIG x=new BIG(ROM.CURVE_Bnx);
+               FP12 r=new FP12(m);
+
+/* Easy part of final exp */
+               FP12 lv=new FP12(r);
+               lv.inverse();
+               r.conj();
+
+               r.mul(lv);
+               lv.copy(r);
+               r.frob(f);
+               r.frob(f);
+               r.mul(lv);
+/* Hard part of final exp */
+               if (ROM.CURVE_PAIRING_TYPE==ROM.BN_CURVE)
+               {
+                       FP12 x0,x1,x2,x3,x4,x5;                 
+                       lv.copy(r);
+                       lv.frob(f);
+                       x0=new FP12(lv);
+                       x0.frob(f);
+                       lv.mul(r);
+                       x0.mul(lv);
+                       x0.frob(f);
+                       x1=new FP12(r);
+                       x1.conj();
+                       x4=r.pow(x);
+
+                       x3=new FP12(x4);
+                       x3.frob(f);
+
+                       x2=x4.pow(x);
+
+                       x5=new FP12(x2); x5.conj();
+                       lv=x2.pow(x);
+
+                       x2.frob(f);
+                       r.copy(x2); r.conj();
+
+                       x4.mul(r);
+                       x2.frob(f);
+
+                       r.copy(lv);
+                       r.frob(f);
+                       lv.mul(r);
+
+                       lv.usqr();
+                       lv.mul(x4);
+                       lv.mul(x5);
+                       r.copy(x3);
+                       r.mul(x5);
+                       r.mul(lv);
+                       lv.mul(x2);
+                       r.usqr();
+                       r.mul(lv);
+                       r.usqr();
+                       lv.copy(r);
+                       lv.mul(x1);
+                       r.mul(x0);
+                       lv.usqr();
+                       r.mul(lv);
+                       r.reduce();
+               }
+               else
+               {
+
+                       FP12 y0,y1,y2,y3;
+// Ghamman & Fouotsa Method
+                       y0=new FP12(r); y0.usqr();
+                       y1=y0.pow(x);
+                       x.fshr(1); y2=y1.pow(x); x.fshl(1);
+                       y3=new FP12(r); y3.conj();
+                       y1.mul(y3);
+
+                       y1.conj();
+                       y1.mul(y2);
+
+                       y2=y1.pow(x);
+
+                       y3=y2.pow(x);
+                       y1.conj();
+                       y3.mul(y1);
+
+                       y1.conj();
+                       y1.frob(f); y1.frob(f); y1.frob(f);
+                       y2.frob(f); y2.frob(f);
+                       y1.mul(y2);
+
+                       y2=y3.pow(x);
+                       y2.mul(y0);
+                       y2.mul(r);
+
+                       y1.mul(y2);
+                       y2.copy(y3); y2.frob(f);
+                       y1.mul(y2);
+                       r.copy(y1);
+                       r.reduce();
+
+/*
+                       x0=new FP12(r);
+                       x1=new FP12(r);
+                       lv.copy(r); lv.frob(f);
+                       x3=new FP12(lv); x3.conj(); x1.mul(x3);
+                       lv.frob(f); lv.frob(f);
+                       x1.mul(lv);
+
+                       r.copy(r.pow(x));  //r=r.pow(x);
+                       x3.copy(r); x3.conj(); x1.mul(x3);
+                       lv.copy(r); lv.frob(f);
+                       x0.mul(lv);
+                       lv.frob(f);
+                       x1.mul(lv);
+                       lv.frob(f);
+                       x3.copy(lv); x3.conj(); x0.mul(x3);
+
+                       r.copy(r.pow(x));
+                       x0.mul(r);
+                       lv.copy(r); lv.frob(f); lv.frob(f);
+                       x3.copy(lv); x3.conj(); x0.mul(x3);
+                       lv.frob(f);
+                       x1.mul(lv);
+
+                       r.copy(r.pow(x));
+                       lv.copy(r); lv.frob(f);
+                       x3.copy(lv); x3.conj(); x0.mul(x3);
+                       lv.frob(f);
+                       x1.mul(lv);
+
+                       r.copy(r.pow(x));
+                       x3.copy(r); x3.conj(); x0.mul(x3);
+                       lv.copy(r); lv.frob(f);
+                       x1.mul(lv);
+
+                       r.copy(r.pow(x));
+                       x1.mul(r);
+
+                       x0.usqr();
+                       x0.mul(x1);
+                       r.copy(x0);
+                       r.reduce(); */
+               }
+               
+               return r;
+       }
+
+/* GLV method */
+       public static BIG[] glv(BIG e)
+       {
+               BIG[] u=new BIG[2];
+               if (ROM.CURVE_PAIRING_TYPE==ROM.BN_CURVE)
+               {
+                       int i,j;
+                       BIG t=new BIG(0);
+                       BIG q=new BIG(ROM.CURVE_Order);
+
+                       BIG[] v=new BIG[2];
+                       for (i=0;i<2;i++)
+                       {
+                               t.copy(new BIG(ROM.CURVE_W[i]));  // why not 
just t=new BIG(ROM.CURVE_W[i]); 
+                               DBIG d=BIG.mul(t,e);
+                               v[i]=new BIG(d.div(q));
+                               u[i]=new BIG(0);
+                       }
+                       u[0].copy(e);
+                       for (i=0;i<2;i++)
+                               for (j=0;j<2;j++)
+                               {
+                                       t.copy(new BIG(ROM.CURVE_SB[j][i]));
+                                       t.copy(BIG.modmul(v[j],t,q));
+                                       u[i].add(q);
+                                       u[i].sub(t);
+                                       u[i].mod(q);
+                               }
+               }
+               else
+               { // -(x^2).P = (Beta.x,y)
+                       BIG q=new BIG(ROM.CURVE_Order);
+                       BIG x=new BIG(ROM.CURVE_Bnx);
+                       BIG x2=BIG.smul(x,x);
+                       u[0]=new BIG(e);
+                       u[0].mod(x2);
+                       u[1]=new BIG(e);
+                       u[1].div(x2);
+                       u[1].rsub(q);
+               }
+               return u;
+       }
+
+/* Galbraith & Scott Method */
+       public static BIG[] gs(BIG e)
+       {
+               BIG[] u=new BIG[4];
+               if (ROM.CURVE_PAIRING_TYPE==ROM.BN_CURVE)
+               {
+                       int i,j;
+                       BIG t=new BIG(0);
+                       BIG q=new BIG(ROM.CURVE_Order);
+                       BIG[] v=new BIG[4];
+                       for (i=0;i<4;i++)
+                       {
+                               t.copy(new BIG(ROM.CURVE_WB[i]));
+                               DBIG d=BIG.mul(t,e);
+                               v[i]=new BIG(d.div(q));
+                               u[i]=new BIG(0);
+                       }
+                       u[0].copy(e);
+                       for (i=0;i<4;i++)
+                               for (j=0;j<4;j++)
+                               {
+                                       t.copy(new BIG(ROM.CURVE_BB[j][i]));
+                                       t.copy(BIG.modmul(v[j],t,q));
+                                       u[i].add(q);
+                                       u[i].sub(t);
+                                       u[i].mod(q);
+                               }
+               }
+               else
+               {
+                       BIG x=new BIG(ROM.CURVE_Bnx);
+                       BIG w=new BIG(e);
+                       for (int i=0;i<4;i++)
+                       {
+                               u[i]=new BIG(w);
+                               u[i].mod(x);
+                               w.div(x);
+                       }
+               }
+               return u;
+       }       
+
+/* Multiply P by e in group G1 */
+       public static ECP G1mul(ECP P,BIG e)
+       {
+               ECP R;
+               if (ROM.USE_GLV)
+               {
+                       P.affine();
+                       R=new ECP();
+                       R.copy(P);
+                       int i,np,nn;
+                       ECP Q=new ECP();
+                       Q.copy(P);
+                       BIG q=new BIG(ROM.CURVE_Order);
+                       FP cru=new FP(new BIG(ROM.CURVE_Cru));
+                       BIG t=new BIG(0);
+                       BIG[] u=glv(e);
+                       Q.getx().mul(cru);
+
+                       np=u[0].nbits();
+                       t.copy(BIG.modneg(u[0],q));
+                       nn=t.nbits();
+                       if (nn<np)
+                       {
+                               u[0].copy(t);
+                               R.neg();
+                       }
+
+                       np=u[1].nbits();
+                       t.copy(BIG.modneg(u[1],q));
+                       nn=t.nbits();
+                       if (nn<np)
+                       {
+                               u[1].copy(t);
+                               Q.neg();
+                       }
+
+                       R=R.mul2(u[0],Q,u[1]);
+                       
+               }
+               else
+               {
+                       R=P.mul(e);
+               }
+               return R;
+       }
+
+/* Multiply P by e in group G2 */
+       public static ECP2 G2mul(ECP2 P,BIG e)
+       {
+               ECP2 R;
+               if (ROM.USE_GS_G2)
+               {
+                       ECP2[] Q=new ECP2[4];
+                       FP2 f=new FP2(new BIG(ROM.CURVE_Fra),new 
BIG(ROM.CURVE_Frb));
+                       BIG q=new BIG(ROM.CURVE_Order);
+                       BIG[] u=gs(e);
+
+
+
+                       BIG t=new BIG(0);
+                       int i,np,nn;
+                       P.affine();
+                       Q[0]=new ECP2(); Q[0].copy(P);
+                       for (i=1;i<4;i++)
+                       {
+                               Q[i]=new ECP2(); Q[i].copy(Q[i-1]);
+                               Q[i].frob(f);
+                       }
+                       for (i=0;i<4;i++)
+                       {
+                               np=u[i].nbits();
+                               t.copy(BIG.modneg(u[i],q));
+                               nn=t.nbits();
+                               if (nn<np)
+                               {
+                                       u[i].copy(t);
+                                       Q[i].neg();
+                               }
+                       }
+
+                       R=ECP2.mul4(Q,u);
+               }
+               else
+               {
+                       R=P.mul(e);
+               }
+               return R;
+       }
+
+/* f=f^e */
+/* Note that this method requires a lot of RAM! Better to use compressed XTR 
method, see FP4.java */
+       public static FP12 GTpow(FP12 d,BIG e)
+       {
+               FP12 r;
+               if (ROM.USE_GS_GT)
+               {
+                       FP12[] g=new FP12[4];
+                       FP2 f=new FP2(new BIG(ROM.CURVE_Fra),new 
BIG(ROM.CURVE_Frb));
+                       BIG q=new BIG(ROM.CURVE_Order);
+                       BIG t=new BIG(0);
+                       int i,np,nn;
+                       BIG[] u=gs(e);
+
+                       g[0]=new FP12(d);
+                       for (i=1;i<4;i++)
+                       {
+                               g[i]=new FP12(0); g[i].copy(g[i-1]);
+                               g[i].frob(f);
+                       }
+                       for (i=0;i<4;i++)
+                       {
+                               np=u[i].nbits();
+                               t.copy(BIG.modneg(u[i],q));
+                               nn=t.nbits();
+                               if (nn<np)
+                               {
+                                       u[i].copy(t);
+                                       g[i].conj();
+                               }
+                       }
+                       r=FP12.pow4(g,u);
+               }
+               else
+               {
+                       r=d.pow(e);
+               }
+               return r;
+       }
+
+/* test group membership - no longer needed */
+/* with GT-Strong curve, now only check that m!=1, conj(m)*m==1, and 
m.m^{p^4}=m^{p^2} */
+/*
+       public static boolean GTmember(FP12 m)
+       {
+               if (m.isunity()) return false;
+               FP12 r=new FP12(m);
+               r.conj();
+               r.mul(m);
+               if (!r.isunity()) return false;
+
+               FP2 f=new FP2(new BIG(ROM.CURVE_Fra),new BIG(ROM.CURVE_Frb));
+
+               r.copy(m); r.frob(f); r.frob(f);
+               FP12 w=new FP12(r); w.frob(f); w.frob(f);
+               w.mul(m);
+               if (!ROM.GT_STRONG)
+               {
+                       if (!w.equals(r)) return false;
+                       BIG x=new BIG(ROM.CURVE_Bnx);
+                       r.copy(m); w=r.pow(x); w=w.pow(x);
+                       r.copy(w); r.sqr(); r.mul(w); r.sqr();
+                       w.copy(m); w.frob(f);
+               }
+               return w.equals(r);
+       }
+*/
+/*
+       public static void main(String[] args) {
+               ECP Q=new ECP(new BIG(ROM.CURVE_Gx),new BIG(ROM.CURVE_Gy));
+               ECP2 P=new ECP2(new FP2(new BIG(ROM.CURVE_Pxa),new 
BIG(ROM.CURVE_Pxb)),new FP2(new BIG(ROM.CURVE_Pya),new BIG(ROM.CURVE_Pyb)));
+
+               BIG r=new BIG(ROM.CURVE_Order);
+               BIG xa=new BIG(ROM.CURVE_Pxa);
+
+               System.out.println("P= "+P.toString());
+               System.out.println("Q= "+Q.toString());
+
+               BIG m=new BIG(17);
+
+               FP12 e=ate(P,Q);
+               System.out.println("\ne= "+e.toString());
+
+               e=fexp(e);
+
+               for (int i=1;i<1000;i++)
+               {
+                       e=ate(P,Q);
+                       e=fexp(e);
+               }
+       //      e=GTpow(e,m);
+
+               System.out.println("\ne= "+e.toString());
+
+               BIG [] GLV=glv(r);
+
+               System.out.println("GLV[0]= "+GLV[0].toString());
+               System.out.println("GLV[0]= "+GLV[1].toString());
+
+               ECP G=new ECP(); G.copy(Q);
+               ECP2 R=new ECP2(); R.copy(P);
+
+
+               e=ate(R,Q);
+               e=fexp(e);
+
+               e=GTpow(e,xa);
+               System.out.println("\ne= "+e.toString()); 
+
+
+               R=G2mul(R,xa);
+               e=ate(R,G);
+               e=fexp(e);
+
+               System.out.println("\ne= "+e.toString());
+
+               G=G1mul(G,xa);
+               e=ate(P,G);
+               e=fexp(e);
+               System.out.println("\ne= "+e.toString()); 
+       } */
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/java/RAND.java
----------------------------------------------------------------------
diff --git a/version22/java/RAND.java b/version22/java/RAND.java
new file mode 100644
index 0000000..7494eff
--- /dev/null
+++ b/version22/java/RAND.java
@@ -0,0 +1,161 @@
+/*
+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.
+*/
+
+/*
+ *   Cryptographic strong random number generator 
+ *
+ *   Unguessable seed -> SHA -> PRNG internal state -> SHA -> random numbers
+ *   Slow - but secure
+ *
+ *   See ftp://ftp.rsasecurity.com/pub/pdfs/bull-1.pdf for a justification
+ */
+
+/* Marsaglia & Zaman Random number generator constants */
+
+
+public class RAND {
+/* Cryptographically strong pseudo-random number generator */
+
+       private static final int NK=21;
+       private static final int NJ=6;
+       private static final int NV=8;
+       private int[] ira=new int[NK];  /* random number...   */
+       private int rndptr;   /* ...array & pointer */
+       private int borrow;
+       private int pool_ptr;
+       private byte[] pool=new byte[32];    /* random pool */
+
+       public RAND()
+       {
+               clean();
+       }
+
+       private int sbrand()
+       { /* Marsaglia & Zaman random number generator */
+               int i,k;
+               long pdiff,t;
+
+               rndptr++;
+               if (rndptr<NK) return ira[rndptr];
+               rndptr=0;
+               for (i=0,k=NK-NJ;i<NK;i++,k++)
+               { /* calculate next NK values */
+                       if (k==NK) k=0;
+                       t=((long)ira[k])&0xffffffffL;
+                       pdiff=(t - (((long)ira[i])&0xffffffffL) - 
(long)borrow)&0xffffffffL;
+                       if (pdiff<t) borrow=0;
+                       if (pdiff>t) borrow=1;
+                       ira[i]=(int)(pdiff&0xffffffffL); 
+               }
+
+               return ira[0];
+       }
+
+       public void sirand(int seed)
+       {
+               int i,in;
+               int t,m=1;
+               borrow=0;
+               rndptr=0;
+               ira[0]^=seed;
+               for (i=1;i<NK;i++)
+               { /* fill initialisation vector */
+                       in=(NV*i)%NK;
+                       ira[in]^=m;      /* note XOR */
+                       t=m;
+                       m=seed-m;
+                       seed=t;
+               }
+               for (i=0;i<10000;i++) sbrand(); /* "warm-up" & stir the 
generator */
+       }
+
+       private void fill_pool()
+       {
+               HASH256 sh=new HASH256();
+               for (int i=0;i<128;i++) sh.process(sbrand());
+               pool=sh.hash();
+               pool_ptr=0;
+       }
+
+       private static int pack(byte[] b)
+       { /* pack 4 bytes into a 32-bit Word */
+               return 
((((int)b[3])&0xff)<<24)|(((int)b[2]&0xff)<<16)|(((int)b[1]&0xff)<<8)|((int)b[0]&0xff);
+       }
+
+/* Initialize RNG with some real entropy from some external source */
+       public void seed(int rawlen,byte[] raw)
+       { /* initialise from at least 128 byte string of raw random entropy */
+               int i;
+               byte [] digest;
+               byte [] b=new byte[4];
+               HASH256 sh=new HASH256();
+               pool_ptr=0;
+               for (i=0;i<NK;i++) ira[i]=0;
+               if (rawlen>0)
+               {
+                       for (i=0;i<rawlen;i++)
+                               sh.process(raw[i]);
+                       digest=sh.hash();
+
+/* initialise PRNG from distilled randomness */
+
+                       for (i=0;i<8;i++) 
+                       {
+                               b[0]=digest[4*i]; b[1]=digest[4*i+1]; 
b[2]=digest[4*i+2]; b[3]=digest[4*i+3];
+                               sirand(pack(b));
+                       }
+               }
+               fill_pool();
+       }
+
+/* Terminate and clean up */
+       public void clean()
+       { /* kill internal state */
+               int i;
+               pool_ptr=rndptr=0;
+               for (i=0;i<32;i++) pool[i]=0;
+               for (i=0;i<NK;i++) ira[i]=0;
+               borrow=0;
+       }
+
+/* get random byte */
+       public int getByte()
+       { 
+               int r;
+               r=pool[pool_ptr++];
+               if (pool_ptr>=32) fill_pool();
+               return (r&0xff);
+       }
+
+/* test main program */
+/*
+       public static void main(String[] args) {
+               int i;
+               byte[] raw=new byte[100];
+               RAND rng=new RAND();
+
+               rng.clean();
+               for (i=0;i<100;i++) raw[i]=(byte)i;
+
+               rng.seed(100,raw);
+ 
+               for (i=0;i<1000;i++)
+                       System.out.format("%03d ",rng.getByte());
+       } */
+}

Reply via email to