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()); + } */ +}
