http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/swift/fp12.swift ---------------------------------------------------------------------- diff --git a/version22/swift/fp12.swift b/version22/swift/fp12.swift new file mode 100644 index 0000000..8743677 --- /dev/null +++ b/version22/swift/fp12.swift @@ -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. +*/ + +// +// fp12.swift +// +// Created by Michael Scott on 07/07/2015. +// Copyright (c) 2015 Michael Scott. All rights reserved. +// + +/* AMCL Fp^12 functions */ +/* FP12 elements are of the form a+i.b+i^2.c */ + +final class FP12 +{ + private final var a:FP4 + private final var b:FP4 + private final var c:FP4 + + /* reduce all components of this mod Modulus */ + func reduce() + { + a.reduce() + b.reduce() + c.reduce() + } + /* normalise all components of this */ + func norm() + { + a.norm(); + b.norm(); + c.norm(); + } + /* Constructors */ + init(_ d:FP4) + { + a=FP4(d) + b=FP4(0) + c=FP4(0) + } + + init(_ d:Int) + { + a=FP4(d) + b=FP4(0) + c=FP4(0) + } + + init(_ d:FP4,_ e:FP4,_ f:FP4) + { + a=FP4(d) + b=FP4(e) + c=FP4(f) + } + + init(_ x:FP12) + { + a=FP4(x.a) + b=FP4(x.b) + c=FP4(x.c) + } + /* test x==0 ? */ + func iszilch() -> Bool + { + reduce(); + return a.iszilch() && b.iszilch() && c.iszilch() + } + /* test x==1 ? */ + func isunity() -> Bool + { + let one=FP4(1) + return a.equals(one) && b.iszilch() && c.iszilch() + } + /* return 1 if x==y, else 0 */ + func equals(_ x:FP12) -> Bool + { + return a.equals(x.a) && b.equals(x.b) && c.equals(x.c) + } + /* extract a from self */ + func geta() -> FP4 + { + return a + } + /* extract b */ + func getb() -> FP4 + { + return b + } + /* extract c */ + func getc() -> FP4 + { + return c + } + /* copy self=x */ + func copy(_ x:FP12) + { + a.copy(x.a) + b.copy(x.b) + c.copy(x.c) + } + /* set self=1 */ + func one() + { + a.one() + b.zero() + c.zero() + } + /* self=conj(self) */ + func conj() + { + a.conj() + b.nconj() + c.conj() + } + /* Granger-Scott Unitary Squaring */ + func usqr() + { + let A=FP4(a) + let B=FP4(c) + let C=FP4(b) + let D=FP4(0) + + a.sqr() + D.copy(a); D.add(a) + a.add(D) + + a.norm() + A.nconj() + + A.add(A) + a.add(A) + B.sqr() + B.times_i() + + D.copy(B); D.add(B) + B.add(D) + B.norm() + + C.sqr() + D.copy(C); D.add(C) + C.add(D) + C.norm() + + b.conj() + b.add(b) + c.nconj() + + c.add(c) + b.add(B) + c.add(C) + reduce() + + } + /* Chung-Hasan SQR2 method from http://cacr.uwaterloo.ca/techreports/2006/cacr2006-24.pdf */ + func sqr() + { + let A=FP4(a) + let B=FP4(b) + let C=FP4(c) + let D=FP4(a) + + A.sqr() + B.mul(c) + B.add(B) + C.sqr() + D.mul(b) + D.add(D) + + c.add(a) + c.add(b) + c.sqr() + + a.copy(A) + + A.add(B) + A.norm() + A.add(C) + A.add(D) + A.norm() + + A.neg() + B.times_i() + C.times_i() + + a.add(B) + + b.copy(C); b.add(D) + c.add(A) + + norm() + } + + /* FP12 full multiplication this=this*y */ + func mul(_ y:FP12) + { + let z0=FP4(a) + let z1=FP4(0) + let z2=FP4(b) + let z3=FP4(0) + let t0=FP4(a) + let t1=FP4(y.a) + + z0.mul(y.a) + z2.mul(y.b) + + t0.add(b) + t1.add(y.b) + + z1.copy(t0); z1.mul(t1) + t0.copy(b); t0.add(c) + + t1.copy(y.b); t1.add(y.c) + z3.copy(t0); z3.mul(t1) + + t0.copy(z0); t0.neg() + t1.copy(z2); t1.neg() + + z1.add(t0) + z1.norm() + b.copy(z1); b.add(t1) + + z3.add(t1) + z2.add(t0) + + t0.copy(a); t0.add(c) + t1.copy(y.a); t1.add(y.c) + t0.mul(t1) + z2.add(t0) + + t0.copy(c); t0.mul(y.c) + t1.copy(t0); t1.neg() + + z2.norm() + z3.norm() + b.norm() + + c.copy(z2); c.add(t1) + z3.add(t1) + t0.times_i() + b.add(t0) + + z3.times_i() + a.copy(z0); a.add(z3) + + norm() + } + + /* Special case of multiplication arises from special form of ATE pairing line function */ + func smul(_ y:FP12) + { + let z0=FP4(a) + let z2=FP4(b) + let z3=FP4(b) + let t0=FP4(0) + let t1=FP4(y.a) + + z0.mul(y.a) + z2.pmul(y.b.real()) + b.add(a) + t1.real().add(y.b.real()) + + b.mul(t1) + z3.add(c) + z3.pmul(y.b.real()) + + t0.copy(z0); t0.neg() + t1.copy(z2); t1.neg() + + b.add(t0) + b.norm() + + b.add(t1) + z3.add(t1) + z2.add(t0) + + t0.copy(a); t0.add(c) + t0.mul(y.a) + c.copy(z2); c.add(t0) + + z3.times_i() + a.copy(z0); a.add(z3) + + norm() + } + /* self=1/self */ + func inverse() + { + let f0=FP4(a) + let f1=FP4(b) + let f2=FP4(a) + let f3=FP4(0) + + norm() + f0.sqr() + f1.mul(c) + f1.times_i() + f0.sub(f1) + + f1.copy(c); f1.sqr() + f1.times_i() + f2.mul(b) + f1.sub(f2) + + f2.copy(b); f2.sqr() + f3.copy(a); f3.mul(c) + f2.sub(f3) + + f3.copy(b); f3.mul(f2) + f3.times_i() + a.mul(f0) + f3.add(a) + c.mul(f1) + c.times_i() + + f3.add(c) + f3.inverse() + a.copy(f0); a.mul(f3) + b.copy(f1); b.mul(f3) + c.copy(f2); c.mul(f3) + } + + /* self=self^p using Frobenius */ + func frob(_ f:FP2) + { + let f2=FP2(f) + let f3=FP2(f) + + f2.sqr() + f3.mul(f2) + + a.frob(f3) + b.frob(f3) + c.frob(f3) + + b.pmul(f) + c.pmul(f2) + } + + /* trace function */ + func trace() -> FP4 + { + let t=FP4(0) + t.copy(a) + t.imul(3) + t.reduce() + return t + } + /* convert from byte array to FP12 */ + static func fromBytes(_ w:[UInt8]) -> FP12 + { + let RM=Int(ROM.MODBYTES) + var t=[UInt8](repeating: 0,count: RM) + + for i in 0 ..< RM {t[i]=w[i]} + var a=BIG.fromBytes(t) + for i in 0 ..< RM {t[i]=w[i+RM]} + var b=BIG.fromBytes(t) + var c=FP2(a,b) + + for i in 0 ..< RM {t[i]=w[i+2*RM]} + a=BIG.fromBytes(t) + for i in 0 ..< RM {t[i]=w[i+3*RM]} + b=BIG.fromBytes(t) + var d=FP2(a,b) + + let e=FP4(c,d) + + for i in 0 ..< RM {t[i]=w[i+4*RM]} + a=BIG.fromBytes(t) + for i in 0 ..< RM {t[i]=w[i+5*RM]} + b=BIG.fromBytes(t) + c=FP2(a,b) + + for i in 0 ..< RM {t[i]=w[i+6*RM]} + a=BIG.fromBytes(t) + for i in 0 ..< RM {t[i]=w[i+7*RM]} + b=BIG.fromBytes(t) + d=FP2(a,b) + + let f=FP4(c,d) + + + for i in 0 ..< RM {t[i]=w[i+8*RM]} + a=BIG.fromBytes(t) + for i in 0 ..< RM {t[i]=w[i+9*RM]} + b=BIG.fromBytes(t) + c=FP2(a,b) + + for i in 0 ..< RM {t[i]=w[i+10*RM]} + a=BIG.fromBytes(t) + for i in 0 ..< RM {t[i]=w[i+11*RM]} + b=BIG.fromBytes(t); + d=FP2(a,b) + + let g=FP4(c,d) + + return FP12(e,f,g) + } + + /* convert this to byte array */ + func toBytes(_ w:inout [UInt8]) + { + let RM=Int(ROM.MODBYTES) + var t=[UInt8](repeating: 0,count: RM) + + a.geta().getA().toBytes(&t) + for i in 0 ..< RM {w[i]=t[i]} + a.geta().getB().toBytes(&t) + for i in 0 ..< RM {w[i+RM]=t[i]} + a.getb().getA().toBytes(&t) + for i in 0 ..< RM {w[i+2*RM]=t[i]} + a.getb().getB().toBytes(&t) + for i in 0 ..< RM {w[i+3*RM]=t[i]} + + b.geta().getA().toBytes(&t) + for i in 0 ..< RM {w[i+4*RM]=t[i]} + b.geta().getB().toBytes(&t); + for i in 0 ..< RM {w[i+5*RM]=t[i]} + b.getb().getA().toBytes(&t) + for i in 0 ..< RM {w[i+6*RM]=t[i]} + b.getb().getB().toBytes(&t) + for i in 0 ..< RM {w[i+7*RM]=t[i]} + + c.geta().getA().toBytes(&t) + for i in 0 ..< RM {w[i+8*RM]=t[i]} + c.geta().getB().toBytes(&t) + for i in 0 ..< RM {w[i+9*RM]=t[i]} + c.getb().getA().toBytes(&t) + for i in 0 ..< RM {w[i+10*RM]=t[i]} + c.getb().getB().toBytes(&t) + for i in 0 ..< RM {w[i+11*RM]=t[i]} + } + /* convert to hex string */ + func toString() -> String + { + return ("["+a.toString()+","+b.toString()+","+c.toString()+"]") + } + + /* self=self^e */ + /* Note this is simple square and multiply, so not side-channel safe */ + func pow(_ e:BIG) -> FP12 + { + norm() + e.norm() + let w=FP12(self) + let z=BIG(e) + let r=FP12(1) + + while (true) + { + let bt=z.parity() + z.fshr(1) + if bt==1 {r.mul(w)} + if z.iszilch() {break} + w.usqr() + } + r.reduce() + return r + } + /* constant time powering by small integer of max length bts */ + func pinpow(_ e:Int32,_ bts:Int32) + { + var R=[FP12]() + R.append(FP12(1)); + R.append(FP12(self)); + + //for var i=bts-1;i>=0;i-- + for i in (0...bts-1).reversed() + { + let b=Int((e>>i)&1) + R[1-b].mul(R[b]) + R[b].usqr() + } + copy(R[0]); + } + + /* p=q0^u0.q1^u1.q2^u2.q3^u3 */ + /* Timing attack secure, but not cache attack secure */ + + static func pow4(_ q:[FP12],_ u:[BIG]) -> FP12 + { + var a=[Int32](repeating: 0,count: 4) + var g=[FP12](); + + for _ in 0 ..< 8 {g.append(FP12(0))} + var s=[FP12](); + for _ in 0 ..< 2 {s.append(FP12(0))} + + let c=FP12(1) + let p=FP12(0) + + var t=[BIG]() + for i in 0 ..< 4 + {t.append(BIG(u[i]))} + + let mt=BIG(0); + var w=[Int8](repeating: 0,count: ROM.NLEN*Int(ROM.BASEBITS)+1) + + g[0].copy(q[0]); s[0].copy(q[1]); s[0].conj(); g[0].mul(s[0]) + g[1].copy(g[0]) + g[2].copy(g[0]) + g[3].copy(g[0]) + g[4].copy(q[0]); g[4].mul(q[1]) + g[5].copy(g[4]) + g[6].copy(g[4]) + g[7].copy(g[4]) + + s[1].copy(q[2]); s[0].copy(q[3]); s[0].conj(); s[1].mul(s[0]) + s[0].copy(s[1]); s[0].conj(); g[1].mul(s[0]) + g[2].mul(s[1]) + g[5].mul(s[0]) + g[6].mul(s[1]) + s[1].copy(q[2]); s[1].mul(q[3]) + s[0].copy(s[1]); s[0].conj(); g[0].mul(s[0]) + g[3].mul(s[1]) + g[4].mul(s[0]) + g[7].mul(s[1]) + + /* if power is even add 1 to power, and add q to correction */ + + for i in 0 ..< 4 + { + if t[i].parity()==0 + { + t[i].inc(1); t[i].norm() + c.mul(q[i]) + } + mt.add(t[i]); mt.norm() + } + c.conj(); + let nb=1+mt.nbits(); + + /* convert exponent to signed 1-bit window */ + for j in 0 ..< nb + { + for i in 0 ..< 4 + { + a[i]=Int32(t[i].lastbits(2)-2) + t[i].dec(Int(a[i])); + t[i].norm() + t[i].fshr(1) + } + w[j]=Int8(8*a[0]+4*a[1]+2*a[2]+a[3]) + } + w[nb]=Int8(8*t[0].lastbits(2)+4*t[1].lastbits(2)) + w[nb]+=Int8(2*t[2].lastbits(2)+t[3].lastbits(2)) + p.copy(g[Int(w[nb]-1)/2]) + + //for var i=nb-1;i>=0;i-- + for i in (0...nb-1).reversed() + { + let m=w[i]>>7 + let j=(w[i]^m)-m /* j=abs(w[i]) */ + let k=Int((j-1)/2) + s[0].copy(g[k]); s[1].copy(g[k]); s[1].conj() + p.usqr() + p.mul(s[Int(m&1)]) + } + p.mul(c) /* apply correction */ + p.reduce() + return p + } + + + + + +}
http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/swift/fp2.swift ---------------------------------------------------------------------- diff --git a/version22/swift/fp2.swift b/version22/swift/fp2.swift new file mode 100644 index 0000000..cdc1711 --- /dev/null +++ b/version22/swift/fp2.swift @@ -0,0 +1,329 @@ +/* + 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. +*/ + +// +// fp2.swift +// +// Created by Michael Scott on 07/07/2015. +// Copyright (c) 2015 Michael Scott. All rights reserved. +// + +/* Finite Field arithmetic Fp^2 functions */ + +/* FP2 elements are of the form a+ib, where i is sqrt(-1) */ + + +final class FP2 +{ + private var a:FP + private var b:FP + + /* Constructors */ + init(_ c: Int) + { + a=FP(c) + b=FP(0) + } + + init(_ x:FP2) + { + a=FP(x.a) + b=FP(x.b) + } + + init(_ c:FP,_ d:FP) + { + a=FP(c) + b=FP(d) + } + + init(_ c:BIG,_ d:BIG) + { + a=FP(c) + b=FP(d) + } + + init(_ c:FP) + { + a=FP(c) + b=FP(0) + } + + init(_ c:BIG) + { + a=FP(c) + b=FP(0) + } + + /* test this=0 ? */ + func iszilch() -> Bool + { + reduce() + return (a.iszilch() && b.iszilch()) + } + + func cmove(_ g:FP2,_ d:Int) + { + a.cmove(g.a,d) + b.cmove(g.b,d) + } + + /* test this=1 ? */ + func isunity() -> Bool + { + let one=FP(1) + return (a.equals(one) && b.iszilch()) + } + + /* test this=x */ + func equals(_ x:FP2) -> Bool + { + return (a.equals(x.a) && b.equals(x.b)); + } + + + /* reduce components mod Modulus */ + func reduce() + { + a.reduce() + b.reduce() + } + + /* normalise components of w */ + func norm() + { + a.norm() + b.norm() + } + + /* extract a */ + func getA() -> BIG + { + return a.redc() + } + + /* extract b */ + func getB() -> BIG + { + return b.redc() + } + + /* copy self=x */ + func copy(_ x:FP2) + { + a.copy(x.a) + b.copy(x.b) + } + + /* set self=0 */ + func zero() + { + a.zero() + b.zero() + } + + /* set self=1 */ + func one() + { + a.one() + b.zero() + } + + /* negate self mod Modulus */ + func neg() + { + norm(); + let m=FP(a) + let t=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 */ + func conj() + { + b.neg() + } + + /* self+=a */ + func add(_ x:FP2) + { + a.add(x.a) + b.add(x.b) + } + + /* self-=a */ + func sub(_ x:FP2) + { + let m=FP2(x) + m.neg() + add(m) + } + + /* self*=s, where s is an FP */ + func pmul(_ s:FP) + { + a.mul(s) + b.mul(s) + } + + /* self*=i, where i is an int */ + func imul(_ c:Int) + { + a.imul(c); + b.imul(c); + } + + /* self*=self */ + func sqr() + { + norm(); + + let w1=FP(a) + let w3=FP(a) + let mb=FP(b) + w3.mul(b) + w1.add(b) + mb.neg() + a.add(mb) + a.mul(w1) + b.copy(w3); b.add(w3) + norm() + } + /* self*=y */ + func mul(_ y:FP2) + { + norm(); /* This is needed here as {a,b} is not normed before additions */ + + let w1=FP(a) + let w2=FP(b) + let w5=FP(a) + let mw=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 */ + func sqrt() -> Bool + { + if iszilch() {return true} + var w1=FP(b) + var w2=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 */ + func toString() -> String + { + return ("["+a.toString()+","+b.toString()+"]") + } + + func toRawString() -> String + { + return ("["+a.toRawString()+","+b.toRawString()+"]") + } + + /* self=1/self */ + func inverse() + { + norm(); + let w1=FP(a) + let w2=FP(b) + + w1.sqr() + w2.sqr() + w1.add(w2) + w1.inverse() + a.mul(w1) + w1.neg() + b.mul(w1) + } + + /* self/=2 */ + func div2() + { + a.div2(); + b.div2(); + } + + /* self*=sqrt(-1) */ + func times_i() + { + let z=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 */ + func mul_ip() + { + norm(); + let t=FP2(self) + let z=FP(a) + a.copy(b) + a.neg() + b.copy(z) + add(t) + norm() + } + /* w/=(1+sqrt(-1)) */ + func div_ip() + { + let t=FP2(0) + norm() + t.a.copy(a); t.a.add(b) + t.b.copy(b); t.b.sub(a) + copy(t) + div2() + } + +} http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/swift/fp4.swift ---------------------------------------------------------------------- diff --git a/version22/swift/fp4.swift b/version22/swift/fp4.swift new file mode 100644 index 0000000..3cba394 --- /dev/null +++ b/version22/swift/fp4.swift @@ -0,0 +1,517 @@ +/* + 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. +*/ + +// +// fp4.swift +// +// Created by Michael Scott on 07/07/2015. +// Copyright (c) 2015 Michael Scott. All rights reserved. +// + +/* Finite Field arithmetic Fp^4 functions */ + +/* FP4 elements are of the form a+ib, where i is sqrt(-1+sqrt(-1)) */ + +final class FP4 { + private final var a:FP2 + private final var b:FP2 + + /* constructors */ + init(_ c:Int) + { + a=FP2(c) + b=FP2(0) + } + + init(_ x:FP4) + { + a=FP2(x.a) + b=FP2(x.b) + } + + init(_ c:FP2,_ d:FP2) + { + a=FP2(c) + b=FP2(d) + } + + init(_ c:FP2) + { + a=FP2(c) + b=FP2(0) + } + /* reduce all components of this mod Modulus */ + func reduce() + { + a.reduce() + b.reduce() + } + /* normalise all components of this mod Modulus */ + func norm() + { + a.norm() + b.norm() + } + /* test this==0 ? */ + func iszilch() -> Bool + { + reduce() + return a.iszilch() && b.iszilch() + } + /* test this==1 ? */ + func isunity() -> Bool + { + let one=FP2(1); + return a.equals(one) && b.iszilch() + } + + /* test is w real? That is in a+ib test b is zero */ + func isreal() -> Bool + { + return b.iszilch(); + } + /* extract real part a */ + func real() -> FP2 + { + return a; + } + + func geta() -> FP2 + { + return a; + } + /* extract imaginary part b */ + func getb() -> FP2 + { + return b; + } + /* test self=x? */ + func equals(_ x:FP4) -> Bool + { + return a.equals(x.a) && b.equals(x.b) + } + /* copy self=x */ + func copy(_ x:FP4) + { + a.copy(x.a) + b.copy(x.b) + } + /* set this=0 */ + func zero() + { + a.zero() + b.zero() + } + /* set this=1 */ + func one() + { + a.one() + b.zero() + } + /* set self=-self */ + func neg() + { + let m=FP2(a) + let t=FP2(0) + m.add(b) + m.neg() + m.norm() + t.copy(m); t.add(b) + b.copy(m) + b.add(a) + a.copy(t) + } + /* self=conjugate(self) */ + func conj() + { + b.neg(); b.norm() + } + /* this=-conjugate(this) */ + func nconj() + { + a.neg(); a.norm() + } + /* self+=x */ + func add(_ x:FP4) + { + a.add(x.a) + b.add(x.b) + } + /* self-=x */ + func sub(_ x:FP4) + { + let m=FP4(x) + m.neg() + add(m) + } + + /* self*=s where s is FP2 */ + func pmul(_ s:FP2) + { + a.mul(s) + b.mul(s) + } + /* self*=c where c is int */ + func imul(_ c:Int) + { + a.imul(c) + b.imul(c) + } + /* self*=self */ + func sqr() + { + norm(); + + let t1=FP2(a) + let t2=FP2(b) + let t3=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() + } + /* self*=y */ + func mul(_ y:FP4) + { + norm(); + + let t1=FP2(a) + let t2=FP2(b) + let t3=FP2(0) + let t4=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 */ + func toString() -> String + { + return ("["+a.toString()+","+b.toString()+"]") + } + + func toRawString() -> String + { + return ("["+a.toRawString()+","+b.toRawString()+"]") + } + /* self=1/self */ + func inverse() + { + norm(); + + let t1=FP2(a) + let t2=FP2(b) + + t1.sqr() + t2.sqr() + t2.mul_ip() + t1.sub(t2) + t1.inverse() + a.mul(t1) + t1.neg() + b.mul(t1) + } + + /* self*=i where i = sqrt(-1+sqrt(-1)) */ + func times_i() + { + norm(); + let s=FP2(b) + let t=FP2(b) + s.times_i() + t.add(s) + t.norm() + b.copy(a) + a.copy(t) + } + + /* self=self^p using Frobenius */ + func frob(_ f:FP2) + { + a.conj() + b.conj() + b.mul(f) + } + /* self=self^e */ + func pow(_ e:BIG) -> FP4 + { + norm() + e.norm() + let w=FP4(self) + let z=BIG(e) + let r=FP4(1) + while (true) + { + let 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 */ + func xtr_A(_ w:FP4,_ y:FP4,_ z:FP4) + { + let r=FP4(w) + let t=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 */ + func xtr_D() + { + let w=FP4(self) + sqr(); w.conj() + w.add(w) + sub(w) + reduce() + } + /* r=x^n using XTR method on traces of FP12s */ + func xtr_pow(_ n:BIG) -> FP4 + { + let a=FP4(3) + let b=FP4(self) + let c=FP4(b) + c.xtr_D() + let t=FP4(0) + let r=FP4(0) + + n.norm(); + let par=n.parity() + let v=BIG(n); v.fshr(1) + if par==0 {v.dec(1); v.norm()} + + let nb=v.nbits() + //for i in (0...nb-1).reverse() + var i=nb-1 + //for var i=nb-1;i>=0;i-- + while i>=0 + { + if (v.bit(UInt(i)) != 1) + { + t.copy(b) + conj() + c.conj() + b.xtr_A(a,self,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,self,t) + c.xtr_D() + } + i-=1 + } + 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. */ + func xtr_pow2(_ ck:FP4,_ ckml:FP4,_ ckm2l:FP4,_ a:BIG,_ b:BIG) -> FP4 + { + a.norm(); b.norm() + let e=BIG(a) + let d=BIG(b) + let w=BIG(0) + + let cu=FP4(ck) // can probably be passed in w/o copying + let cv=FP4(self) + let cumv=FP4(ckml) + let cum2v=FP4(ckm2l) + var r=FP4(0) + let t=FP4(0) + + var f2:Int=0 + while d.parity()==0 && e.parity()==0 + { + d.fshr(1); + e.fshr(1); + f2 += 1; + } + + 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 _ in 0 ..< f2 + {r.xtr_D()} + r=r.xtr_pow(d) + return r + } + +} http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/swift/gcm.swift ---------------------------------------------------------------------- diff --git a/version22/swift/gcm.swift b/version22/swift/gcm.swift new file mode 100644 index 0000000..15a6657 --- /dev/null +++ b/version22/swift/gcm.swift @@ -0,0 +1,326 @@ +/* + 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. +*/ + +// +// gcm.swift +// +// Created by Michael Scott on 23/06/2015. +// Copyright (c) 2015 Michael Scott. All rights reserved. +// + +import Foundation + +/* +* 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 +*/ + +final class GCM { + static let NB:Int=4 + static let GCM_ACCEPTING_HEADER:Int=0 + static let GCM_ACCEPTING_CIPHER:Int=1 + static let GCM_NOT_ACCEPTING_MORE:Int=2 + static let GCM_FINISHED:Int=3 + static let GCM_ENCRYPTING:Int=0 + static let GCM_DECRYPTING:Int=1 + + private var table=[[UInt32]](repeating: [UInt32](repeating: 0,count: 4),count: 128) /* 2k bytes */ + private var stateX=[UInt8](repeating: 0,count: 16) + private var Y_0=[UInt8](repeating: 0,count: 16) + + private var counter:Int=0 + private var lenA=[UInt32](repeating: 0,count: 2) + private var lenC=[UInt32](repeating: 0,count: 2) + private var status:Int=0 + private var a=AES() + + private static func pack(_ b: [UInt8]) -> UInt32 + { /* pack bytes into a 32-bit Word */ + var r=((UInt32(b[0])&0xff)<<24)|((UInt32(b[1])&0xff)<<16) + r = r|((UInt32(b[2])&0xff)<<8)|(UInt32(b[3])&0xff) + return r + } + + private static func unpack(_ a: UInt32) -> [UInt8] + { /* unpack bytes from a word */ + let b:[UInt8]=[UInt8((a>>24)&0xff),UInt8((a>>16)&0xff),UInt8((a>>8)&0xff),UInt8(a&0xff)]; + return b + } + + private func precompute(_ H: [UInt8]) + { + var b=[UInt8](repeating: 0,count: 4) + var j=0 + for i in 0 ..< GCM.NB + { + b[0]=H[j]; b[1]=H[j+1]; b[2]=H[j+2]; b[3]=H[j+3]; + table[0][i]=GCM.pack(b); + j+=4 + } + for i in 1 ..< 128 + { + var c:UInt32=0 + for j in 0 ..< GCM.NB {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 func gf2mul() + { /* gf2m mul - Z=H*X mod 2^128 */ + var P=[UInt32](repeating: 0,count: 4) + + for i in 0 ..< 4 {P[i]=0} + var j=8; var m=0; + for i in 0 ..< 128 + { + j-=1 + var c=UInt32((stateX[m]>>UInt8(j))&1); c = ( ~c ) + 1 + for k in 0 ..< GCM.NB {P[k]^=(table[i][k] & c)} + if (j==0) + { + j=8; m += 1; + if (m==16) {break} + } + } + j=0 + for i in 0 ..< GCM.NB + { + var b=GCM.unpack(P[i]) + stateX[j]=b[0]; stateX[j+1]=b[1]; stateX[j+2]=b[2]; stateX[j+3]=b[3]; + j+=4 + } + } + private func wrap() + { /* Finish off GHASH */ + var F=[UInt32](repeating: 0,count: 4) + var L=[UInt8](repeating: 0,count: 16) + + /* 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; + var j=0 + for i in 0 ..< GCM.NB + { + var b=GCM.unpack(F[i]); + L[j]=b[0]; L[j+1]=b[1]; L[j+2]=b[2]; L[j+3]=b[3] + j+=4 + } + for i in 0 ..< 16 {stateX[i]^=L[i]} + gf2mul() + } + + private func ghash(_ plain: [UInt8],_ len: Int) -> Bool + { + // var B=[UInt8](count:16,repeatedValue:0) + + if status==GCM.GCM_ACCEPTING_HEADER {status=GCM.GCM_ACCEPTING_CIPHER} + if (status != GCM.GCM_ACCEPTING_CIPHER) {return false} + + var j=0; + while (j<len) + { + for i in 0 ..< 16 + { + stateX[i]^=plain[j]; + j+=1; + lenC[1]+=1; if lenC[1]==0 {lenC[0]+=1} + if j>=len {break;} + } + gf2mul(); + } + if len%16 != 0 {status=GCM.GCM_NOT_ACCEPTING_MORE} + return true; + } + + /* Initialize GCM mode */ + func init_it(_ key: [UInt8],_ niv: Int,_ iv: [UInt8]) + { /* iv size niv is usually 12 bytes (96 bits). AES key size nk can be 16,24 or 32 bytes */ + var H=[UInt8](repeating: 0,count: 16) + + for i in 0 ..< 16 {H[i]=0; stateX[i]=0} + + a.init_it(AES.ECB,key,iv) + a.ecb_encrypt(&H); /* E(K,0) */ + precompute(H) + + lenA[0]=0;lenC[0]=0;lenA[1]=0;lenC[1]=0; + if (niv==12) + { + for i in 0 ..< 12 {a.f[i]=iv[i]} + var b=GCM.unpack(UInt32(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 in 0 ..< 16 {Y_0[i]=a.f[i]} + } + else + { + status=GCM.GCM_ACCEPTING_CIPHER; + ghash(iv,niv) /* GHASH(H,0,IV) */ + wrap() + for i in 0 ..< 16 {a.f[i]=stateX[i];Y_0[i]=a.f[i];stateX[i]=0} + lenA[0]=0;lenC[0]=0;lenA[1]=0;lenC[1]=0; + } + status=GCM.GCM_ACCEPTING_HEADER; + } + + /* Add Header data - included but not encrypted */ + func add_header(_ header: [UInt8],_ len: Int) -> Bool + { /* Add some header. Won't be encrypted, but will be authenticated. len is length of header */ + if status != GCM.GCM_ACCEPTING_HEADER {return false} + + var j=0 + while (j<len) + { + for i in 0 ..< 16 + { + stateX[i]^=header[j]; + j+=1; + lenA[1]+=1; if lenA[1]==0 {lenA[0]+=1} + if j>=len {break} + } + gf2mul(); + } + if len%16 != 0 {status=GCM.GCM_ACCEPTING_CIPHER} + return true; + } + /* Add Plaintext - included and encrypted */ + func add_plain(_ plain: [UInt8],_ len: Int) -> [UInt8] + { + var B=[UInt8](repeating: 0,count: 16) + var b=[UInt8](repeating: 0,count: 4) + + var cipher=[UInt8](repeating: 0,count: len) + var counter:UInt32=0 + if status == GCM.GCM_ACCEPTING_HEADER {status=GCM.GCM_ACCEPTING_CIPHER} + if status != GCM.GCM_ACCEPTING_CIPHER {return [UInt8]()} + + var j=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=GCM.pack(b); + counter+=1; + b=GCM.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 in 0 ..< 16 {B[i]=a.f[i]} + a.ecb_encrypt(&B); /* encrypt it */ + + for i in 0 ..< 16 + { + cipher[j]=(plain[j]^B[i]); + stateX[i]^=cipher[j]; + j+=1; + lenC[1]+=1; if lenC[1]==0 {lenC[0]+=1} + if j>=len {break} + } + gf2mul(); + } + if len%16 != 0 {status=GCM.GCM_NOT_ACCEPTING_MORE} + return cipher; + } + /* Add Ciphertext - decrypts to plaintext */ + func add_cipher(_ cipher: [UInt8],_ len: Int) -> [UInt8] + { + var B=[UInt8](repeating: 0,count: 16) + var b=[UInt8](repeating: 0,count: 4) + + var plain=[UInt8](repeating: 0,count: len) + var counter:UInt32=0 + + if status==GCM.GCM_ACCEPTING_HEADER {status=GCM.GCM_ACCEPTING_CIPHER} + if status != GCM.GCM_ACCEPTING_CIPHER {return [UInt8]()} + + var j=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=GCM.pack(b); + counter+=1; + b=GCM.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 in 0 ..< 16 {B[i]=a.f[i]} + a.ecb_encrypt(&B); /* encrypt it */ + for i in 0 ..< 16 + { + let oc=cipher[j] + plain[j]=(cipher[j]^B[i]); + stateX[i]^=oc; + j+=1; + lenC[1]+=1; if lenC[1]==0 {lenC[0]+=1} + if j>=len {break} + } + gf2mul() + } + if len%16 != 0 {status=GCM.GCM_NOT_ACCEPTING_MORE} + return plain; + } + + /* Finish and extract Tag */ + func finish(_ extract: Bool) -> [UInt8] + { /* Finish off GHASH and extract tag (MAC) */ + var tag=[UInt8](repeating: 0,count: 16) + + wrap(); + /* extract tag */ + if (extract) + { + a.ecb_encrypt(&Y_0); /* E(K,Y0) */ + for i in 0 ..< 16 {Y_0[i]^=stateX[i]} + for i in 0 ..< 16 {tag[i]=Y_0[i];Y_0[i]=0;stateX[i]=0;} + } + status=GCM.GCM_FINISHED; + a.end(); + return tag; + } + + static func hex2bytes(_ s: String) -> [UInt8] + { + var array=Array(arrayLiteral: s) + let len=array.count; + var data=[UInt8](repeating: 0,count: len/2) + + var i=0 + while (i<len) + { + data[i / 2] = UInt8(strtoul(String(array[i]),nil,16)<<4)+UInt8(strtoul(String(array[i+1]),nil,16)) + i+=2 + } + return data; + } + + +} + http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/swift/hash256.swift ---------------------------------------------------------------------- diff --git a/version22/swift/hash256.swift b/version22/swift/hash256.swift new file mode 100644 index 0000000..6140da5 --- /dev/null +++ b/version22/swift/hash256.swift @@ -0,0 +1,188 @@ +/* + 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. +*/ + +// +// hash256.swift - Implementation of SHA-256 +// +// Created by Michael Scott on 17/06/2015. +// Copyright (c) 2015 Michael Scott. All rights reserved. +// SHA256 Implementation +// + +final class HASH256{ + + private var length=[UInt32](repeating: 0,count: 2) + private var h=[UInt32](repeating: 0,count: 8) + private var w=[UInt32](repeating: 0,count: 64) + static let H0:UInt32=0x6A09E667 + static let H1:UInt32=0xBB67AE85 + static let H2:UInt32=0x3C6EF372 + static let H3:UInt32=0xA54FF53A + static let H4:UInt32=0x510E527F + static let H5:UInt32=0x9B05688C + static let H6:UInt32=0x1F83D9AB + static let H7:UInt32=0x5BE0CD19 + + static let len:Int=32 + + static let K:[UInt32]=[ + 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] + + + private static func S(_ n: UInt32,_ x: UInt32) -> UInt32 + { + return ((x>>n)|(x<<(32-n))) + } + + private static func R(_ n: UInt32,_ x: UInt32) -> UInt32 + { + return (x>>n) + } + + private static func Ch(_ x: UInt32,_ y: UInt32,_ z:UInt32) -> UInt32 + { + return ((x&y)^(~(x)&z)) + } + + private static func Maj(_ x: UInt32,_ y: UInt32,_ z:UInt32) -> UInt32 + { + return ((x&y)^(x&z)^(y&z)) + } + + private static func Sig0(_ x: UInt32) -> UInt32 + { + return (S(2,x)^S(13,x)^S(22,x)) + } + + private static func Sig1(_ x: UInt32) -> UInt32 + { + return (S(6,x)^S(11,x)^S(25,x)) + } + + private static func theta0(_ x: UInt32) -> UInt32 + { + return (S(7,x)^S(18,x)^R(3,x)) + } + + private static func theta1(_ x: UInt32) -> UInt32 + { + return (S(17,x)^S(19,x)^R(10,x)) + } + + private func transform() + { /* basic transformation step */ + var a,b,c,d,e,f,g,hh,t1,t2 :UInt32 + for j in 16 ..< 64 + { + w[j]=HASH256.theta1(w[j-2])&+w[j-7]&+HASH256.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 in 0 ..< 64 + { /* 64 times - mush it up */ + t1=hh&+HASH256.Sig1(e)&+HASH256.Ch(e,f,g)&+HASH256.K[j]&+w[j] + t2=HASH256.Sig0(a)&+HASH256.Maj(a,b,c) + hh=g; g=f; f=e; + e=d&+t1; + d=c; + c=b; + b=a; + a=t1&+t2; + } + h[0]=h[0]&+a; h[1]=h[1]&+b; h[2]=h[2]&+c; h[3]=h[3]&+d + h[4]=h[4]&+e; h[5]=h[5]&+f; h[6]=h[6]&+g; h[7]=h[7]&+hh; + } + + /* Re-Initialise Hash function */ + func init_it() + { /* initialise */ + for i in 0 ..< 64 {w[i]=0} + length[0]=0; length[1]=0 + h[0]=HASH256.H0; + h[1]=HASH256.H1; + h[2]=HASH256.H2; + h[3]=HASH256.H3; + h[4]=HASH256.H4; + h[5]=HASH256.H5; + h[6]=HASH256.H6; + h[7]=HASH256.H7; + } + + init() + { + init_it() + } + + /* process a single byte */ + func process(_ byt: UInt8) + { /* process the next message byte */ + let cnt=Int((length[0]/32)%16) + w[cnt]<<=8; + w[cnt]|=(UInt32(byt)&0xFF); + length[0]+=8; + if (length[0]==0) { length[1] += 1; length[0]=0 } + if ((length[0]%512)==0) {transform()} + } + + /* process an array of bytes */ + func process_array(_ b: [UInt8]) + { + for i in 0 ..< b.count {process((b[i]))} + } + + /* process a 32-bit integer */ + func process_num(_ n:Int32) + { + process(UInt8((n>>24)&0xff)) + process(UInt8((n>>16)&0xff)) + process(UInt8((n>>8)&0xff)) + process(UInt8(n&0xff)) + } + + /* Generate 32-byte Hash */ + func hash() -> [UInt8] + { /* pad message and finish - supply digest */ + var digest=[UInt8](repeating: 0,count: 32) + + let len0=length[0] + let len1=length[1] + process(0x80); + while ((length[0]%512) != 448) {process(0)} + w[14]=len1 + w[15]=len0; + transform() + for i in 0 ..< HASH256.len + { /* convert to bytes */ + let r=(8*(3-UInt32(i)%4)); + digest[i]=UInt8((h[i/4]>>r) & 0xff); + } + init_it(); + return digest; + } + + +} http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/swift/hash384.swift ---------------------------------------------------------------------- diff --git a/version22/swift/hash384.swift b/version22/swift/hash384.swift new file mode 100644 index 0000000..de89d4c --- /dev/null +++ b/version22/swift/hash384.swift @@ -0,0 +1,198 @@ +/* + 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. +*/ + +// +// hash384.swift - Implementation of SHA-384 +// +// Created by Michael Scott on 29/03/2016. +// Copyright © 2016 Michael Scott. All rights reserved. +// + +import Foundation + +final class HASH384{ + + private var length=[UInt64](repeating: 0,count: 2) + private var h=[UInt64](repeating: 0,count: 8) + private var w=[UInt64](repeating: 0,count: 80) + static let H0:UInt64=0xcbbb9d5dc1059ed8 + static let H1:UInt64=0x629a292a367cd507 + static let H2:UInt64=0x9159015a3070dd17 + static let H3:UInt64=0x152fecd8f70e5939 + static let H4:UInt64=0x67332667ffc00b31 + static let H5:UInt64=0x8eb44a8768581511 + static let H6:UInt64=0xdb0c2e0d64f98fa7 + static let H7:UInt64=0x47b5481dbefa4fa4 + + static let len:Int=48 + + static let K:[UInt64]=[ + 0x428a2f98d728ae22,0x7137449123ef65cd,0xb5c0fbcfec4d3b2f,0xe9b5dba58189dbbc, + 0x3956c25bf348b538,0x59f111f1b605d019,0x923f82a4af194f9b,0xab1c5ed5da6d8118, + 0xd807aa98a3030242,0x12835b0145706fbe,0x243185be4ee4b28c,0x550c7dc3d5ffb4e2, + 0x72be5d74f27b896f,0x80deb1fe3b1696b1,0x9bdc06a725c71235,0xc19bf174cf692694, + 0xe49b69c19ef14ad2,0xefbe4786384f25e3,0x0fc19dc68b8cd5b5,0x240ca1cc77ac9c65, + 0x2de92c6f592b0275,0x4a7484aa6ea6e483,0x5cb0a9dcbd41fbd4,0x76f988da831153b5, + 0x983e5152ee66dfab,0xa831c66d2db43210,0xb00327c898fb213f,0xbf597fc7beef0ee4, + 0xc6e00bf33da88fc2,0xd5a79147930aa725,0x06ca6351e003826f,0x142929670a0e6e70, + 0x27b70a8546d22ffc,0x2e1b21385c26c926,0x4d2c6dfc5ac42aed,0x53380d139d95b3df, + 0x650a73548baf63de,0x766a0abb3c77b2a8,0x81c2c92e47edaee6,0x92722c851482353b, + 0xa2bfe8a14cf10364,0xa81a664bbc423001,0xc24b8b70d0f89791,0xc76c51a30654be30, + 0xd192e819d6ef5218,0xd69906245565a910,0xf40e35855771202a,0x106aa07032bbd1b8, + 0x19a4c116b8d2d0c8,0x1e376c085141ab53,0x2748774cdf8eeb99,0x34b0bcb5e19b48a8, + 0x391c0cb3c5c95a63,0x4ed8aa4ae3418acb,0x5b9cca4f7763e373,0x682e6ff3d6b2b8a3, + 0x748f82ee5defb2fc,0x78a5636f43172f60,0x84c87814a1f0ab72,0x8cc702081a6439ec, + 0x90befffa23631e28,0xa4506cebde82bde9,0xbef9a3f7b2c67915,0xc67178f2e372532b, + 0xca273eceea26619c,0xd186b8c721c0c207,0xeada7dd6cde0eb1e,0xf57d4f7fee6ed178, + 0x06f067aa72176fba,0x0a637dc5a2c898a6,0x113f9804bef90dae,0x1b710b35131c471b, + 0x28db77f523047d84,0x32caab7b40c72493,0x3c9ebe0a15c9bebc,0x431d67c49c100d4c, + 0x4cc5d4becb3e42b6,0x597f299cfc657e2a,0x5fcb6fab3ad6faec,0x6c44198c4a475817] + + private static func S(_ n: UInt32,_ x: UInt64) -> UInt64 + { + return ((x>>UInt64(n))|(x<<(64-UInt64(n)))) + } + + private static func R(_ n: UInt32,_ x: UInt64) -> UInt64 + { + return (x>>UInt64(n)) + } + + private static func Ch(_ x: UInt64,_ y: UInt64,_ z:UInt64) -> UInt64 + { + return ((x&y)^(~(x)&z)) + } + + private static func Maj(_ x: UInt64,_ y: UInt64,_ z:UInt64) -> UInt64 + { + return ((x&y)^(x&z)^(y&z)) + } + + private static func Sig0(_ x: UInt64) -> UInt64 + { + return (S(28,x)^S(34,x)^S(39,x)) + } + + private static func Sig1(_ x: UInt64) -> UInt64 + { + return (S(14,x)^S(18,x)^S(41,x)) + } + + private static func theta0(_ x: UInt64) -> UInt64 + { + return (S(1,x)^S(8,x)^R(7,x)) + } + + private static func theta1(_ x: UInt64) -> UInt64 + { + return (S(19,x)^S(61,x)^R(6,x)) + } + + private func transform() + { /* basic transformation step */ + var a,b,c,d,e,f,g,hh,t1,t2 :UInt64 + for j in 16 ..< 80 + { + w[j]=HASH384.theta1(w[j-2])&+w[j-7]&+HASH384.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 in 0 ..< 80 + { /* 64 times - mush it up */ + t1=hh&+HASH384.Sig1(e)&+HASH384.Ch(e,f,g)&+HASH384.K[j]&+w[j] + t2=HASH384.Sig0(a)&+HASH384.Maj(a,b,c) + hh=g; g=f; f=e; + e=d&+t1; + d=c; + c=b; + b=a; + a=t1&+t2; + } + h[0]=h[0]&+a; h[1]=h[1]&+b; h[2]=h[2]&+c; h[3]=h[3]&+d + h[4]=h[4]&+e; h[5]=h[5]&+f; h[6]=h[6]&+g; h[7]=h[7]&+hh; + } + + /* Re-Initialise Hash function */ + func init_it() + { /* initialise */ + for i in 0 ..< 80 {w[i]=0} + length[0]=0; length[1]=0 + h[0]=HASH384.H0; + h[1]=HASH384.H1; + h[2]=HASH384.H2; + h[3]=HASH384.H3; + h[4]=HASH384.H4; + h[5]=HASH384.H5; + h[6]=HASH384.H6; + h[7]=HASH384.H7; + } + + init() + { + init_it() + } + + /* process a single byte */ + func process(_ byt: UInt8) + { /* process the next message byte */ + let cnt=Int((length[0]/64)%16) + w[cnt]<<=8; + w[cnt]|=(UInt64(byt)&0xFF); + length[0]+=8; + if (length[0]==0) { length[1] += 1; length[0]=0 } + if ((length[0]%1024)==0) {transform()} + } + + /* process an array of bytes */ + func process_array(_ b: [UInt8]) + { + for i in 0 ..< b.count {process((b[i]))} + } + + /* process a 32-bit integer */ + func process_num(_ n:Int32) + { + process(UInt8((n>>24)&0xff)) + process(UInt8((n>>16)&0xff)) + process(UInt8((n>>8)&0xff)) + process(UInt8(n&0xff)) + } + + /* Generate 48-byte Hash */ + func hash() -> [UInt8] + { /* pad message and finish - supply digest */ + var digest=[UInt8](repeating: 0,count: 48) + + let len0=length[0] + let len1=length[1] + process(0x80); + while ((length[0]%1024) != 896) {process(0)} + w[14]=len1 + w[15]=len0; + transform() + for i in 0 ..< HASH384.len + { /* convert to bytes */ + digest[i]=UInt8((h[i/8]>>(8*(7-UInt64(i)%8))) & 0xff); + } + init_it(); + return digest; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/swift/hash512.swift ---------------------------------------------------------------------- diff --git a/version22/swift/hash512.swift b/version22/swift/hash512.swift new file mode 100644 index 0000000..634f944 --- /dev/null +++ b/version22/swift/hash512.swift @@ -0,0 +1,198 @@ +/* + 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. +*/ + +// +// hash512.swift - Implementation of SHA-512 +// +// Created by Michael Scott on 29/03/2016. +// Copyright © 2016 Michael Scott. All rights reserved. +// + +import Foundation + +final class HASH512{ + + private var length=[UInt64](repeating: 0,count: 2) + private var h=[UInt64](repeating: 0,count: 8) + private var w=[UInt64](repeating: 0,count: 80) + static let H0:UInt64=0x6a09e667f3bcc908 + static let H1:UInt64=0xbb67ae8584caa73b + static let H2:UInt64=0x3c6ef372fe94f82b + static let H3:UInt64=0xa54ff53a5f1d36f1 + static let H4:UInt64=0x510e527fade682d1 + static let H5:UInt64=0x9b05688c2b3e6c1f + static let H6:UInt64=0x1f83d9abfb41bd6b + static let H7:UInt64=0x5be0cd19137e2179 + + static let len:Int=64 + + static let K:[UInt64]=[ + 0x428a2f98d728ae22,0x7137449123ef65cd,0xb5c0fbcfec4d3b2f,0xe9b5dba58189dbbc, + 0x3956c25bf348b538,0x59f111f1b605d019,0x923f82a4af194f9b,0xab1c5ed5da6d8118, + 0xd807aa98a3030242,0x12835b0145706fbe,0x243185be4ee4b28c,0x550c7dc3d5ffb4e2, + 0x72be5d74f27b896f,0x80deb1fe3b1696b1,0x9bdc06a725c71235,0xc19bf174cf692694, + 0xe49b69c19ef14ad2,0xefbe4786384f25e3,0x0fc19dc68b8cd5b5,0x240ca1cc77ac9c65, + 0x2de92c6f592b0275,0x4a7484aa6ea6e483,0x5cb0a9dcbd41fbd4,0x76f988da831153b5, + 0x983e5152ee66dfab,0xa831c66d2db43210,0xb00327c898fb213f,0xbf597fc7beef0ee4, + 0xc6e00bf33da88fc2,0xd5a79147930aa725,0x06ca6351e003826f,0x142929670a0e6e70, + 0x27b70a8546d22ffc,0x2e1b21385c26c926,0x4d2c6dfc5ac42aed,0x53380d139d95b3df, + 0x650a73548baf63de,0x766a0abb3c77b2a8,0x81c2c92e47edaee6,0x92722c851482353b, + 0xa2bfe8a14cf10364,0xa81a664bbc423001,0xc24b8b70d0f89791,0xc76c51a30654be30, + 0xd192e819d6ef5218,0xd69906245565a910,0xf40e35855771202a,0x106aa07032bbd1b8, + 0x19a4c116b8d2d0c8,0x1e376c085141ab53,0x2748774cdf8eeb99,0x34b0bcb5e19b48a8, + 0x391c0cb3c5c95a63,0x4ed8aa4ae3418acb,0x5b9cca4f7763e373,0x682e6ff3d6b2b8a3, + 0x748f82ee5defb2fc,0x78a5636f43172f60,0x84c87814a1f0ab72,0x8cc702081a6439ec, + 0x90befffa23631e28,0xa4506cebde82bde9,0xbef9a3f7b2c67915,0xc67178f2e372532b, + 0xca273eceea26619c,0xd186b8c721c0c207,0xeada7dd6cde0eb1e,0xf57d4f7fee6ed178, + 0x06f067aa72176fba,0x0a637dc5a2c898a6,0x113f9804bef90dae,0x1b710b35131c471b, + 0x28db77f523047d84,0x32caab7b40c72493,0x3c9ebe0a15c9bebc,0x431d67c49c100d4c, + 0x4cc5d4becb3e42b6,0x597f299cfc657e2a,0x5fcb6fab3ad6faec,0x6c44198c4a475817] + + private static func S(_ n: UInt32,_ x: UInt64) -> UInt64 + { + return ((x>>UInt64(n))|(x<<(64-UInt64(n)))) + } + + private static func R(_ n: UInt32,_ x: UInt64) -> UInt64 + { + return (x>>UInt64(n)) + } + + private static func Ch(_ x: UInt64,_ y: UInt64,_ z:UInt64) -> UInt64 + { + return ((x&y)^(~(x)&z)) + } + + private static func Maj(_ x: UInt64,_ y: UInt64,_ z:UInt64) -> UInt64 + { + return ((x&y)^(x&z)^(y&z)) + } + + private static func Sig0(_ x: UInt64) -> UInt64 + { + return (S(28,x)^S(34,x)^S(39,x)) + } + + private static func Sig1(_ x: UInt64) -> UInt64 + { + return (S(14,x)^S(18,x)^S(41,x)) + } + + private static func theta0(_ x: UInt64) -> UInt64 + { + return (S(1,x)^S(8,x)^R(7,x)) + } + + private static func theta1(_ x: UInt64) -> UInt64 + { + return (S(19,x)^S(61,x)^R(6,x)) + } + + private func transform() + { /* basic transformation step */ + var a,b,c,d,e,f,g,hh,t1,t2 :UInt64 + for j in 16 ..< 80 + { + w[j]=HASH512.theta1(w[j-2])&+w[j-7]&+HASH512.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 in 0 ..< 80 + { /* 64 times - mush it up */ + t1=hh&+HASH512.Sig1(e)&+HASH512.Ch(e,f,g)&+HASH512.K[j]&+w[j] + t2=HASH512.Sig0(a)&+HASH512.Maj(a,b,c) + hh=g; g=f; f=e; + e=d&+t1; + d=c; + c=b; + b=a; + a=t1&+t2; + } + h[0]=h[0]&+a; h[1]=h[1]&+b; h[2]=h[2]&+c; h[3]=h[3]&+d + h[4]=h[4]&+e; h[5]=h[5]&+f; h[6]=h[6]&+g; h[7]=h[7]&+hh; + } + + /* Re-Initialise Hash function */ + func init_it() + { /* initialise */ + for i in 0 ..< 80 {w[i]=0} + length[0]=0; length[1]=0 + h[0]=HASH512.H0; + h[1]=HASH512.H1; + h[2]=HASH512.H2; + h[3]=HASH512.H3; + h[4]=HASH512.H4; + h[5]=HASH512.H5; + h[6]=HASH512.H6; + h[7]=HASH512.H7; + } + + init() + { + init_it() + } + + /* process a single byte */ + func process(_ byt: UInt8) + { /* process the next message byte */ + let cnt=Int((length[0]/64)%16) + w[cnt]<<=8; + w[cnt]|=(UInt64(byt)&0xFF); + length[0]+=8; + if (length[0]==0) { length[1] += 1; length[0]=0 } + if ((length[0]%1024)==0) {transform()} + } + + /* process an array of bytes */ + func process_array(_ b: [UInt8]) + { + for i in 0 ..< b.count {process((b[i]))} + } + + /* process a 32-bit integer */ + func process_num(_ n:Int32) + { + process(UInt8((n>>24)&0xff)) + process(UInt8((n>>16)&0xff)) + process(UInt8((n>>8)&0xff)) + process(UInt8(n&0xff)) + } + + /* Generate 48-byte Hash */ + func hash() -> [UInt8] + { /* pad message and finish - supply digest */ + var digest=[UInt8](repeating: 0,count: 64) + + let len0=length[0] + let len1=length[1] + process(0x80); + while ((length[0]%1024) != 896) {process(0)} + w[14]=len1 + w[15]=len0; + transform() + for i in 0 ..< HASH512.len + { /* convert to bytes */ + digest[i]=UInt8((h[i/8]>>(8*(7-UInt64(i)%8))) & 0xff); + } + init_it(); + return digest; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/swift/main.swift ---------------------------------------------------------------------- diff --git a/version22/swift/main.swift b/version22/swift/main.swift new file mode 100644 index 0000000..e464a0e --- /dev/null +++ b/version22/swift/main.swift @@ -0,0 +1,13 @@ +// +// main.swift +// +// Created by Michael Scott on 12/06/2015. +// Copyright (c) 2015 Michael Scott. All rights reserved. +// + +BenchtestPAIR() +BenchtestEC() +TestRSA() +TestECDH() +TestMPIN() + http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/swift/mpin.swift ---------------------------------------------------------------------- diff --git a/version22/swift/mpin.swift b/version22/swift/mpin.swift new file mode 100644 index 0000000..c4bc28e --- /dev/null +++ b/version22/swift/mpin.swift @@ -0,0 +1,833 @@ +/* + 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.swift +// +// Created by Michael Scott on 08/07/2015. +// Copyright (c) 2015 Michael Scott. All rights reserved. +// + + +import Foundation + +final public class MPIN +{ + static public let EFS=Int(ROM.MODBYTES) + static public let EGS=Int(ROM.MODBYTES) + static public let PAS:Int=16 + static let INVALID_POINT:Int = -14 + static let BAD_PARAMS:Int = -11 + static let WRONG_ORDER:Int = -18 + static public let BAD_PIN:Int = -19 + static public let SHA256=32 + static public let SHA384=48 + static public let SHA512=64 + + /* Configure your PIN here */ + + static let MAXPIN:Int32 = 10000 // PIN less than this + static let PBLEN:Int32 = 14 // Number of bits in PIN + static let TS:Int = 10 // 10 for 4 digit PIN, 14 for 6-digit PIN - 2^TS/TS approx = sqrt(MAXPIN) + static let TRAP:Int = 200 // 200 for 4 digit PIN, 2000 for 6-digit PIN - approx 2*sqrt(MAXPIN) + + static public let HASH_TYPE=SHA256 + + private static func mpin_hash(_ sha:Int,_ c: FP4,_ U: ECP) -> [UInt8] + { + var w=[UInt8](repeating: 0,count: EFS) + var t=[UInt8](repeating: 0,count: 6*EFS) + var h=[UInt8]() + + c.geta().getA().toBytes(&w); for i in 0 ..< EFS {t[i]=w[i]} + c.geta().getB().toBytes(&w); for i in EFS ..< 2*EFS {t[i]=w[i-EFS]} + c.getb().getA().toBytes(&w); for i in 2*EFS ..< 3*EFS {t[i]=w[i-2*EFS]} + c.getb().getB().toBytes(&w); for i in 3*EFS ..< 4*EFS {t[i]=w[i-3*EFS]} + + U.getX().toBytes(&w); for i in 4*EFS ..< 5*EFS {t[i]=w[i-4*EFS]} + U.getY().toBytes(&w); for i in 5*EFS ..< 6*EFS {t[i]=w[i-5*EFS]} + + if sha==SHA256 + { + let H=HASH256() + H.process_array(t) + h=H.hash() + } + if sha==SHA384 + { + let H=HASH384() + H.process_array(t) + h=H.hash() + } + if sha==SHA512 + { + let H=HASH512() + H.process_array(t) + h=H.hash() + } + if h.isEmpty {return h} + var R=[UInt8](repeating: 0,count: PAS) + for i in 0 ..< PAS {R[i]=h[i]} + return R + } + + // Hash number (optional) and string to point on curve + + private static func hashit(_ sha:Int,_ n:Int32,_ ID:[UInt8]) -> [UInt8] + { + var R=[UInt8]() + if sha==SHA256 + { + let H=HASH256() + if n != 0 {H.process_num(n)} + H.process_array(ID) + R=H.hash() + } + if sha==SHA384 + { + let H=HASH384() + if n != 0 {H.process_num(n)} + H.process_array(ID) + R=H.hash() + } + if sha==SHA512 + { + let H=HASH512() + if n != 0 {H.process_num(n)} + H.process_array(ID) + R=H.hash() + } + if R.isEmpty {return R} + let RM=Int(ROM.MODBYTES) + var W=[UInt8](repeating: 0,count: RM) + if sha >= RM + { + for i in 0 ..< RM {W[i]=R[i]} + } + else + { + for i in 0 ..< sha {W[i]=R[i]} + } + return W + } + + static func mapit(_ h:[UInt8]) -> ECP + { + let q=BIG(ROM.Modulus) + let x=BIG.fromBytes(h) + x.mod(q) + var P=ECP(x,0) + while (true) + { + if !P.is_infinity() {break} + x.inc(1); x.norm(); + P=ECP(x,0); + } + if ROM.CURVE_PAIRING_TYPE != ROM.BN_CURVE { + let c=BIG(ROM.CURVE_Cof) + P=P.mul(c) + } + + return P + } + + // needed for SOK + static func mapit2(_ h:[UInt8]) -> ECP2 + { + let q=BIG(ROM.Modulus) + var x=BIG.fromBytes(h) + let one=BIG(1) + var Q=ECP2() + x.mod(q); + while (true) + { + let X=FP2(one,x); + Q=ECP2(X); + if !Q.is_infinity() {break} + x.inc(1); x.norm(); + } + // Fast Hashing to G2 - Fuentes-Castaneda, Knapp and Rodriguez-Henriquez + let Fra=BIG(ROM.CURVE_Fra); + let Frb=BIG(ROM.CURVE_Frb); + let X=FP2(Fra,Frb); + x=BIG(ROM.CURVE_Bnx); + + let T=ECP2(); T.copy(Q) + T.mul(x); T.neg() + let K=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 + static public func today() -> Int32 + { + let date=Date() + return (Int32(date.timeIntervalSince1970/(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 + static func map(_ u:BIG,_ cb:Int) -> ECP + { + let x=BIG(u) + let p=BIG(ROM.Modulus) + x.mod(p) + var P=ECP(x,cb) + while (true) + { + if !P.is_infinity() {break} + x.inc(1); x.norm() + P=ECP(x,cb) + } + return P + } + + // returns u derived from P. Random value in range 1 to return value should then be added to u + static func unmap(_ u:inout BIG,_ P:ECP) -> Int + { + let s=P.getS() + var r:Int32=0 + let x=P.getX() + u.copy(x) + var R=ECP() + while (true) + { + u.dec(1); u.norm() + r += 1 + R=ECP(u,s) + if !R.is_infinity() {break} + } + return Int(r) + } + + static public func HASH_ID(_ sha:Int,_ ID:[UInt8]) -> [UInt8] + { + 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 + static public func ENCODING(_ rng:RAND,_ E:inout [UInt8]) -> Int + { + var T=[UInt8](repeating: 0,count: EFS) + + for i in 0 ..< EFS {T[i]=E[i+1]} + var u=BIG.fromBytes(T); + for i in 0 ..< EFS {T[i]=E[i+EFS+1]} + var v=BIG.fromBytes(T) + + let P=ECP(u,v); + if P.is_infinity() {return INVALID_POINT} + + let p=BIG(ROM.Modulus) + u=BIG.randomnum(p,rng) + + var su=rng.getByte(); + su%=2 + + let W=MPIN.map(u,Int(su)) + P.sub(W); + let sv=P.getS(); + let rn=MPIN.unmap(&v,P) + let m=rng.getByte(); + let incr=1+Int(m)%rn + v.inc(incr) + E[0]=(su+UInt8(2*sv)) + u.toBytes(&T) + for i in 0 ..< EFS {E[i+1]=T[i]} + v.toBytes(&T) + for i in 0 ..< EFS {E[i+EFS+1]=T[i]} + + return 0; + } + + static public func DECODING(_ D:inout [UInt8]) -> Int + { + var T=[UInt8](repeating: 0,count: EFS) + + if (D[0]&0x04) != 0 {return INVALID_POINT} + + for i in 0 ..< EFS {T[i]=D[i+1]} + var u=BIG.fromBytes(T) + for i in 0 ..< EFS {T[i]=D[i+EFS+1]} + var v=BIG.fromBytes(T) + + let su=D[0]&1 + let sv=(D[0]>>1)&1 + let W=map(u,Int(su)) + let P=map(v,Int(sv)) + P.add(W) + u=P.getX() + v=P.getY() + D[0]=0x04 + u.toBytes(&T); + for i in 0 ..< EFS {D[i+1]=T[i]} + v.toBytes(&T) + for i in 0 ..< EFS {D[i+EFS+1]=T[i]} + + return 0 + } + // R=R1+R2 in group G1 + static public func RECOMBINE_G1(_ R1:[UInt8],_ R2:[UInt8],_ R:inout [UInt8]) -> Int + { + let P=ECP.fromBytes(R1) + let 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 + static public func RECOMBINE_G2(_ W1:[UInt8],_ W2:[UInt8],_ W:inout [UInt8]) -> Int + { + let P=ECP2.fromBytes(W1) + let 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 + static public func RANDOM_GENERATE(_ rng:RAND,_ S:inout [UInt8]) -> Int + { + let r=BIG(ROM.CURVE_Order) + let 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 + static public func EXTRACT_PIN(_ sha:Int,_ CID:[UInt8],_ pin:Int32,_ TOKEN:inout [UInt8]) -> Int + { + let P=ECP.fromBytes(TOKEN) + if P.is_infinity() {return INVALID_POINT} + let h=MPIN.hashit(sha,0,CID) + var R=MPIN.mapit(h) + + R=R.pinmul(pin%MAXPIN,MPIN.PBLEN) + P.sub(R) + + P.toBytes(&TOKEN) + + return 0 + } + // Implement step 2 on client side of MPin protocol + static public func CLIENT_2(_ X:[UInt8],_ Y:[UInt8],_ SEC:inout [UInt8]) -> Int + { + let r=BIG(ROM.CURVE_Order) + var P=ECP.fromBytes(SEC) + if P.is_infinity() {return INVALID_POINT} + + let px=BIG.fromBytes(X) + let py=BIG.fromBytes(Y) + px.add(py) + px.mod(r) + // px.rsub(r) + + P=PAIR.G1mul(P,px) + P.neg() + P.toBytes(&SEC); + // PAIR.G1mul(P,px).toBytes(&SEC) + return 0 + } + + // Implement step 1 on client side of MPin protocol + static public func CLIENT_1(_ sha:Int,_ date:Int32,_ CLIENT_ID:[UInt8],_ rng:RAND?,_ X:inout [UInt8],_ pin:Int32,_ TOKEN:[UInt8],_ SEC:inout [UInt8],_ xID:inout [UInt8]?,_ xCID:inout [UInt8]?,_ PERMIT:[UInt8]) -> Int + { + let r=BIG(ROM.CURVE_Order) + // let q=BIG(ROM.Modulus) + var x:BIG + if rng != nil + { + x=BIG.randomnum(r,rng!) + if ROM.AES_S>0 + { + x.mod2m(2*ROM.AES_S) + } + x.toBytes(&X); + } + else + { + x=BIG.fromBytes(X); + } + // var t=[UInt8](count:EFS,repeatedValue:0) + + var h=MPIN.hashit(sha,0,CLIENT_ID) + var P=mapit(h); + + let T=ECP.fromBytes(TOKEN); + if T.is_infinity() {return INVALID_POINT} + + var W=P.pinmul(pin%MPIN.MAXPIN,MPIN.PBLEN) + T.add(W) + if date != 0 + { + W=ECP.fromBytes(PERMIT) + if W.is_infinity() {return INVALID_POINT} + T.add(W); + h=MPIN.hashit(sha,date,h) + W=MPIN.mapit(h); + if xID != nil + { + 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 != nil {P.toBytes(&xCID!)} + } + else + { + if xID != nil + { + 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 + static public func GET_SERVER_SECRET(_ S:[UInt8],_ SST:inout [UInt8]) -> Int + { + var Q=ECP2(FP2(BIG(ROM.CURVE_Pxa),BIG(ROM.CURVE_Pxb)),FP2(BIG(ROM.CURVE_Pya),BIG(ROM.CURVE_Pyb))) + + let 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 + + static public func GET_G1_MULTIPLE(_ rng:RAND?,_ type:Int,_ X:inout [UInt8],_ G:[UInt8],_ W:inout [UInt8]) -> Int + { + var x:BIG + let r=BIG(ROM.CURVE_Order) + if rng != nil + { + x=BIG.randomnum(r,rng!) + if ROM.AES_S>0 + { + x.mod2m(2*ROM.AES_S) + } + x.toBytes(&X) + } + else + { + x=BIG.fromBytes(X); + } + var P:ECP + if type==0 + { + P=ECP.fromBytes(G) + if P.is_infinity() {return INVALID_POINT} + } + else + {P=MPIN.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 + static public func GET_CLIENT_SECRET(_ S:inout [UInt8],_ CID:[UInt8],_ CST:inout [UInt8]) -> Int + { + return GET_G1_MULTIPLE(nil,1,&S,CID,&CST) + } + // Time Permit CTT=S*(date|H(CID)) where S is master secret + static public func GET_CLIENT_PERMIT(_ sha:Int,_ date:Int32,_ S:[UInt8],_ CID:[UInt8],_ CTT:inout [UInt8]) -> Int + { + let h=MPIN.hashit(sha,date,CID) + let P=MPIN.mapit(h) + + let 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 + static public func SERVER_1(_ sha:Int,_ date:Int32,_ CID:[UInt8],_ HID:inout [UInt8],_ HTID:inout [UInt8]) + { + var h=MPIN.hashit(sha,0,CID) + let P=MPIN.mapit(h) + + P.toBytes(&HID) + if date != 0 + { + // if HID != nil {P.toBytes(&HID!)} + h=hashit(sha,date,h) + let R=MPIN.mapit(h) + P.add(R) + P.toBytes(&HTID) + } + //else {P.toBytes(&HID!)} + } + // Implement step 2 of MPin protocol on server side + static public func SERVER_2(_ date:Int32,_ HID:[UInt8]?,_ HTID:[UInt8]?,_ Y:[UInt8],_ SST:[UInt8],_ xID:[UInt8]?,_ xCID:[UInt8]?,_ mSEC:[UInt8],_ E:inout [UInt8]?,_ F:inout [UInt8]?) -> Int + { + // _=BIG(ROM.Modulus); + let Q=ECP2(FP2(BIG(ROM.CURVE_Pxa),BIG(ROM.CURVE_Pxb)),FP2(BIG(ROM.CURVE_Pya),BIG(ROM.CURVE_Pyb))) + let sQ=ECP2.fromBytes(SST) + if sQ.is_infinity() {return INVALID_POINT} + + var R:ECP + if date != 0 + {R=ECP.fromBytes(xCID!)} + else + { + if xID==nil {return MPIN.BAD_PARAMS} + R=ECP.fromBytes(xID!) + } + if R.is_infinity() {return INVALID_POINT} + + let y=BIG.fromBytes(Y) + var P:ECP + if date != 0 {P=ECP.fromBytes(HTID!)} + else + { + if HID==nil {return MPIN.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 MPIN.INVALID_POINT} + + + var g=PAIR.ate2(Q,R,sQ,P) + g=PAIR.fexp(g) + + if !g.isunity() + { + if HID != nil && xID != nil && E != nil && F != nil + { + g.toBytes(&E!) + if date != 0 + { + P=ECP.fromBytes(HID!) + if P.is_infinity() {return MPIN.INVALID_POINT} + R=ECP.fromBytes(xID!) + if R.is_infinity() {return MPIN.INVALID_POINT} + + P=PAIR.G1mul(P,y); + P.add(R); + } + g=PAIR.ate(Q,P); + g=PAIR.fexp(g); + g.toBytes(&F!); + } + return MPIN.BAD_PIN; + } + + return 0 + } + // Pollards kangaroos used to return PIN error + static public func KANGAROO(_ E:[UInt8],_ F:[UInt8]) -> Int + { + let ge=FP12.fromBytes(E) + let gf=FP12.fromBytes(F) + var distance=[Int](); + let t=FP12(gf); + var table=[FP12]() + + var s:Int=1 + for _ in 0 ..< Int(TS) + { + distance.append(s) + table.append(FP12(t)) + s*=2 + t.usqr() + + } + t.one() + var dn:Int=0 + for _ in 0 ..< TRAP + { + let i=Int(t.geta().geta().getA().lastbits(8))%TS + t.mul(table[i]) + dn+=distance[i] + } + gf.copy(t); gf.conj() + var steps=0; var dm:Int=0 + var res=0; + while (dm-dn<Int(MAXPIN)) + { + steps += 1; + if steps>4*TRAP {break} + let i=Int(ge.geta().geta().getA().lastbits(8))%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>=Int(MAXPIN) {res=0 } // Trap Failed - probable invalid token + return res + } + // Functions to support M-Pin Full + + static public func PRECOMPUTE(_ TOKEN:[UInt8],_ CID:[UInt8],_ G1:inout [UInt8],_ G2:inout [UInt8]) -> Int + { + let T=ECP.fromBytes(TOKEN); + if T.is_infinity() {return INVALID_POINT} + + let P=MPIN.mapit(CID) + + let Q=ECP2(FP2(BIG(ROM.CURVE_Pxa),BIG(ROM.CURVE_Pxb)),FP2(BIG(ROM.CURVE_Pya),BIG(ROM.CURVE_Pyb))) + + var 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 + } + + static public func HASH_ALL(_ sha:Int,_ HID:[UInt8],_ xID:[UInt8]?,_ xCID:[UInt8]?,_ SEC:[UInt8],_ Y:[UInt8],_ R:[UInt8],_ W:[UInt8] ) -> [UInt8] + { + var T=[UInt8](repeating: 0,count: 10*EFS+4) + var tlen=0 + + for i in 0 ..< HID.count {T[i]=HID[i]} + tlen+=HID.count + if xCID != nil { + for i in 0 ..< xCID!.count {T[i+tlen]=xCID![i]} + tlen+=xCID!.count + } else { + for i in 0 ..< xID!.count {T[i+tlen]=xID![i]} + tlen+=xID!.count + } + for i in 0 ..< SEC.count {T[i+tlen]=SEC[i]} + tlen+=SEC.count; + for i in 0 ..< Y.count {T[i+tlen]=Y[i]} + tlen+=Y.count; + for i in 0 ..< R.count {T[i+tlen]=R[i]} + tlen+=R.count; + for i in 0 ..< W.count {T[i+tlen]=W[i]} + tlen+=W.count; + + return hashit(sha,0,T); + } + + // calculate common key on client side + // wCID = w.(A+AT) + static public func CLIENT_KEY(_ sha:Int,_ G1:[UInt8],_ G2:[UInt8],_ pin:Int32,_ R:[UInt8],_ X:[UInt8],_ H:[UInt8],_ wCID:[UInt8],_ CK:inout [UInt8]) -> Int + { + let g1=FP12.fromBytes(G1) + let g2=FP12.fromBytes(G2) + let z=BIG.fromBytes(R) + let x=BIG.fromBytes(X) + let h=BIG.fromBytes(H) + + var W=ECP.fromBytes(wCID) + if W.is_infinity() {return INVALID_POINT} + + W=PAIR.G1mul(W,x) + + let f=FP2(BIG(ROM.CURVE_Fra),BIG(ROM.CURVE_Frb)) + let r=BIG(ROM.CURVE_Order) + let q=BIG(ROM.Modulus) + + z.add(h) // new + z.mod(r) + + let m=BIG(q) + m.mod(r) + + let a=BIG(z) + a.mod(m) + + let b=BIG(z) + b.div(m); + + g2.pinpow(pin,PBLEN); + g1.mul(g2); + + var c=g1.trace() + g2.copy(g1) + g2.frob(f) + let cp=g2.trace() + g1.conj() + g2.mul(g1) + let cpm1=g2.trace() + g2.mul(g1) + let cpm2=g2.trace() + + c=c.xtr_pow2(cp,cpm1,cpm2,a,b) + + let t=mpin_hash(sha,c,W) + + for i in 0 ..< PAS {CK[i]=t[i]} + + return 0 + } + // calculate common key on server side + // Z=r.A - no time permits involved + + static public func SERVER_KEY(_ sha:Int,_ Z:[UInt8],_ SST:[UInt8],_ W:[UInt8],_ H:[UInt8],_ HID:[UInt8],_ xID:[UInt8],_ xCID:[UInt8]?,_ SK:inout [UInt8]) -> Int + { + // var t=[UInt8](count:EFS,repeatedValue:0) + + let sQ=ECP2.fromBytes(SST) + if sQ.is_infinity() {return INVALID_POINT} + let R=ECP.fromBytes(Z) + if R.is_infinity() {return INVALID_POINT} + var A=ECP.fromBytes(HID) + if A.is_infinity() {return INVALID_POINT} + + var U:ECP + if xCID != nil + {U=ECP.fromBytes(xCID!)} + else + {U=ECP.fromBytes(xID)} + + if U.is_infinity() {return INVALID_POINT} + + let w=BIG.fromBytes(W) + let h=BIG.fromBytes(H) + A=PAIR.G1mul(A,h) + R.add(A) + + U=PAIR.G1mul(U,w) + var g=PAIR.ate(sQ,R) + g=PAIR.fexp(g) + + let c=g.trace() + + let t=mpin_hash(sha,c,U) + + for i in 0 ..< PAS {SK[i]=t[i]} + + return 0 + } + + // return time since epoch + static public func GET_TIME() -> Int32 + { + let date=Date() + return (Int32(date.timeIntervalSince1970)) + } + + // Generate Y = H(epoch, xCID/xID) + static public func GET_Y(_ sha:Int,_ TimeValue:Int32,_ xCID:[UInt8],_ Y:inout [UInt8]) + { + let h = MPIN.hashit(sha,TimeValue,xCID) + let y = BIG.fromBytes(h) + let q=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 + static public func CLIENT(_ sha:Int,_ date:Int32,_ CLIENT_ID:[UInt8],_ RNG:RAND?,_ X:inout [UInt8],_ pin:Int32,_ TOKEN:[UInt8],_ SEC:inout [UInt8],_ xID:inout [UInt8]?,_ xCID:inout [UInt8]?,_ PERMIT:[UInt8],_ TimeValue:Int32,_ Y:inout [UInt8]) -> Int + { + var rtn=0 + + rtn = MPIN.CLIENT_1(sha,date,CLIENT_ID,RNG,&X,pin,TOKEN,&SEC,&xID,&xCID,PERMIT) + + if rtn != 0 {return rtn} + + if date==0 {MPIN.GET_Y(sha,TimeValue,xID!,&Y)} + else {MPIN.GET_Y(sha,TimeValue,xCID!,&Y)} + + rtn = MPIN.CLIENT_2(X,Y,&SEC) + if (rtn != 0) {return rtn} + + return 0 + } + // One pass MPIN Server + static public func SERVER(_ sha:Int,_ date:Int32,_ HID:inout [UInt8],_ HTID:inout [UInt8]?,_ Y:inout [UInt8],_ SST:[UInt8],_ xID:[UInt8]?,_ xCID:[UInt8],_ SEC:[UInt8],_ E:inout [UInt8]?,_ F:inout [UInt8]?,_ CID:[UInt8],_ TimeValue:Int32) -> Int + { + var rtn=0 + + var pID:[UInt8] + 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 + } + + static public func printBinary(_ array: [UInt8]) + { + for i in 0 ..< array.count + { + let h=String(format:"%02x",array[i]) + print("\(h)", terminator: "") + } + print(" "); + } +} + +
