http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/85fabaa6/go/amcl-go/FP12.go ---------------------------------------------------------------------- diff --git a/go/amcl-go/FP12.go b/go/amcl-go/FP12.go new file mode 100644 index 0000000..8e9cb4c --- /dev/null +++ b/go/amcl-go/FP12.go @@ -0,0 +1,654 @@ +/* +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 Fp^12 functions */ +/* FP12 elements are of the form a+i.b+i^2.c */ + +package amcl + +//import "fmt" + +type FP12 struct { + a *FP4 + b *FP4 + c *FP4 +} + +/* Constructors */ +func NewFP12fp4(d *FP4) *FP12 { + F := new(FP12) + F.a = NewFP4copy(d) + F.b = NewFP4int(0) + F.c = NewFP4int(0) + return F +} + +func NewFP12int(d int) *FP12 { + F := new(FP12) + F.a = NewFP4int(d) + F.b = NewFP4int(0) + F.c = NewFP4int(0) + return F +} + +func NewFP12fp4s(d *FP4, e *FP4, f *FP4) *FP12 { + F := new(FP12) + F.a = NewFP4copy(d) + F.b = NewFP4copy(e) + F.c = NewFP4copy(f) + return F +} + +func NewFP12copy(x *FP12) *FP12 { + F := new(FP12) + F.a = NewFP4copy(x.a) + F.b = NewFP4copy(x.b) + F.c = NewFP4copy(x.c) + return F +} + +/* reduce all components of this mod Modulus */ +func (F *FP12) reduce() { + F.a.reduce() + F.b.reduce() + F.c.reduce() +} + +/* normalise all components of this */ +func (F *FP12) norm() { + F.a.norm() + F.b.norm() + F.c.norm() +} + +/* test x==0 ? */ +func (F *FP12) iszilch() bool { + F.reduce() + return (F.a.iszilch() && F.b.iszilch() && F.c.iszilch()) +} + +/* test x==1 ? */ +func (F *FP12) isunity() bool { + one := NewFP4int(1) + return (F.a.equals(one) && F.b.iszilch() && F.c.iszilch()) +} + +/* return 1 if x==y, else 0 */ +func (F *FP12) equals(x *FP12) bool { + return (F.a.equals(x.a) && F.b.equals(x.b) && F.c.equals(x.c)) +} + +/* extract a from this */ +func (F *FP12) geta() *FP4 { + return F.a +} + +/* extract b */ +func (F *FP12) getb() *FP4 { + return F.b +} + +/* extract c */ +func (F *FP12) getc() *FP4 { + return F.c +} + +/* copy this=x */ +func (F *FP12) copy(x *FP12) { + F.a.copy(x.a) + F.b.copy(x.b) + F.c.copy(x.c) +} + +/* set this=1 */ +func (F *FP12) one() { + F.a.one() + F.b.zero() + F.c.zero() +} + +/* this=conj(this) */ +func (F *FP12) conj() { + F.a.conj() + F.b.nconj() + F.c.conj() +} + +/* Granger-Scott Unitary Squaring */ +func (F *FP12) usqr() { + A := NewFP4copy(F.a) + B := NewFP4copy(F.c) + C := NewFP4copy(F.b) + D := NewFP4int(0) + + F.a.sqr() + D.copy(F.a) + D.add(F.a) + F.a.add(D) + + // a.norm(); + A.nconj() + + A.add(A) + F.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(); + + F.b.conj() + F.b.add(F.b) + F.c.nconj() + + F.c.add(F.c) + F.b.add(B) + F.c.add(C) + F.reduce() + +} + +/* Chung-Hasan SQR2 method from http://cacr.uwaterloo.ca/techreports/2006/cacr2006-24.pdf */ +func (F *FP12) sqr() { + A := NewFP4copy(F.a) + B := NewFP4copy(F.b) + C := NewFP4copy(F.c) + D := NewFP4copy(F.a) + + A.sqr() + B.mul(F.c) + B.add(B) + C.sqr() + D.mul(F.b) + D.add(D) + + F.c.add(F.a) + F.c.add(F.b) + F.c.sqr() + + F.a.copy(A) + + A.add(B) + // A.norm(); + A.add(C) + A.add(D) + // A.norm(); + + A.neg() + B.times_i() + C.times_i() + + F.a.add(B) + + F.b.copy(C) + F.b.add(D) + F.c.add(A) + F.norm() +} + +/* FP12 full multiplication this=this*y */ +func (F *FP12) mul(y *FP12) { + z0 := NewFP4copy(F.a) + z1 := NewFP4int(0) + z2 := NewFP4copy(F.b) + z3 := NewFP4int(0) + t0 := NewFP4copy(F.a) + t1 := NewFP4copy(y.a) + + z0.mul(y.a) + z2.mul(y.b) + + t0.add(F.b) + t1.add(y.b) + + z1.copy(t0) + z1.mul(t1) + t0.copy(F.b) + t0.add(F.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(); + F.b.copy(z1) + F.b.add(t1) + + z3.add(t1) + z2.add(t0) + + t0.copy(F.a) + t0.add(F.c) + t1.copy(y.a) + t1.add(y.c) + t0.mul(t1) + z2.add(t0) + + t0.copy(F.c) + t0.mul(y.c) + t1.copy(t0) + t1.neg() + + // z2.norm(); + // z3.norm(); + // b.norm(); + + F.c.copy(z2) + F.c.add(t1) + z3.add(t1) + t0.times_i() + F.b.add(t0) + + z3.times_i() + F.a.copy(z0) + F.a.add(z3) + F.norm() +} + +/* Special case of multiplication arises from special form of ATE pairing line function */ +func (F *FP12) smul(y *FP12) { + z0 := NewFP4copy(F.a) + z2 := NewFP4copy(F.b) + z3 := NewFP4copy(F.b) + t0 := NewFP4int(0) + t1 := NewFP4copy(y.a) + + z0.mul(y.a) + z2.pmul(y.b.real()) + F.b.add(F.a) + t1.real().add(y.b.real()) + + F.b.mul(t1) + z3.add(F.c) + z3.pmul(y.b.real()) + + t0.copy(z0) + t0.neg() + t1.copy(z2) + t1.neg() + + F.b.add(t0) + // b.norm(); + + F.b.add(t1) + z3.add(t1) + z2.add(t0) + + t0.copy(F.a) + t0.add(F.c) + t0.mul(y.a) + F.c.copy(z2) + F.c.add(t0) + + z3.times_i() + F.a.copy(z0) + F.a.add(z3) + + F.norm() +} + +/* this=1/this */ +func (F *FP12) inverse() { + f0 := NewFP4copy(F.a) + f1 := NewFP4copy(F.b) + f2 := NewFP4copy(F.a) + f3 := NewFP4int(0) + + F.norm() + f0.sqr() + f1.mul(F.c) + f1.times_i() + f0.sub(f1) + + f1.copy(F.c) + f1.sqr() + f1.times_i() + f2.mul(F.b) + f1.sub(f2) + + f2.copy(F.b) + f2.sqr() + f3.copy(F.a) + f3.mul(F.c) + f2.sub(f3) + + f3.copy(F.b) + f3.mul(f2) + f3.times_i() + F.a.mul(f0) + f3.add(F.a) + F.c.mul(f1) + F.c.times_i() + + f3.add(F.c) + f3.inverse() + F.a.copy(f0) + F.a.mul(f3) + F.b.copy(f1) + F.b.mul(f3) + F.c.copy(f2) + F.c.mul(f3) +} + +/* this=this^p using Frobenius */ +func (F *FP12) frob(f *FP2) { + f2 := NewFP2copy(f) + f3 := NewFP2copy(f) + + f2.sqr() + f3.mul(f2) + + F.a.frob(f3) + F.b.frob(f3) + F.c.frob(f3) + + F.b.pmul(f) + F.c.pmul(f2) +} + +/* trace function */ +func (F *FP12) trace() *FP4 { + t := NewFP4int(0) + t.copy(F.a) + t.imul(3) + t.reduce() + return t +} + +/* convert from byte array to FP12 */ +func FP12_fromBytes(w []byte) *FP12 { + var t [int(MODBYTES)]byte + MB := int(MODBYTES) + + for i := 0; i < MB; i++ { + t[i] = w[i] + } + a := fromBytes(t[:]) + for i := 0; i < MB; i++ { + t[i] = w[i+MB] + } + b := fromBytes(t[:]) + c := NewFP2bigs(a, b) + + for i := 0; i < MB; i++ { + t[i] = w[i+2*MB] + } + a = fromBytes(t[:]) + for i := 0; i < MB; i++ { + t[i] = w[i+3*MB] + } + b = fromBytes(t[:]) + d := NewFP2bigs(a, b) + + e := NewFP4fp2s(c, d) + + for i := 0; i < MB; i++ { + t[i] = w[i+4*MB] + } + a = fromBytes(t[:]) + for i := 0; i < MB; i++ { + t[i] = w[i+5*MB] + } + b = fromBytes(t[:]) + c = NewFP2bigs(a, b) + + for i := 0; i < MB; i++ { + t[i] = w[i+6*MB] + } + a = fromBytes(t[:]) + for i := 0; i < MB; i++ { + t[i] = w[i+7*MB] + } + b = fromBytes(t[:]) + d = NewFP2bigs(a, b) + + f := NewFP4fp2s(c, d) + + for i := 0; i < MB; i++ { + t[i] = w[i+8*MB] + } + a = fromBytes(t[:]) + for i := 0; i < MB; i++ { + t[i] = w[i+9*MB] + } + b = fromBytes(t[:]) + + c = NewFP2bigs(a, b) + + for i := 0; i < MB; i++ { + t[i] = w[i+10*MB] + } + a = fromBytes(t[:]) + for i := 0; i < MB; i++ { + t[i] = w[i+11*MB] + } + b = fromBytes(t[:]) + d = NewFP2bigs(a, b) + + g := NewFP4fp2s(c, d) + + return NewFP12fp4s(e, f, g) +} + +/* convert this to byte array */ +func (F *FP12) toBytes(w []byte) { + var t [int(MODBYTES)]byte + MB := int(MODBYTES) + F.a.geta().getA().toBytes(t[:]) + for i := 0; i < MB; i++ { + w[i] = t[i] + } + F.a.geta().getB().toBytes(t[:]) + for i := 0; i < MB; i++ { + w[i+MB] = t[i] + } + F.a.getb().getA().toBytes(t[:]) + for i := 0; i < MB; i++ { + w[i+2*MB] = t[i] + } + F.a.getb().getB().toBytes(t[:]) + for i := 0; i < MB; i++ { + w[i+3*MB] = t[i] + } + + F.b.geta().getA().toBytes(t[:]) + for i := 0; i < MB; i++ { + w[i+4*MB] = t[i] + } + F.b.geta().getB().toBytes(t[:]) + for i := 0; i < MB; i++ { + w[i+5*MB] = t[i] + } + F.b.getb().getA().toBytes(t[:]) + for i := 0; i < MB; i++ { + w[i+6*MB] = t[i] + } + F.b.getb().getB().toBytes(t[:]) + for i := 0; i < MB; i++ { + w[i+7*MB] = t[i] + } + + F.c.geta().getA().toBytes(t[:]) + for i := 0; i < MB; i++ { + w[i+8*MB] = t[i] + } + F.c.geta().getB().toBytes(t[:]) + for i := 0; i < MB; i++ { + w[i+9*MB] = t[i] + } + F.c.getb().getA().toBytes(t[:]) + for i := 0; i < MB; i++ { + w[i+10*MB] = t[i] + } + F.c.getb().getB().toBytes(t[:]) + for i := 0; i < MB; i++ { + w[i+11*MB] = t[i] + } +} + +/* convert to hex string */ +func (F *FP12) toString() string { + return ("[" + F.a.toString() + "," + F.b.toString() + "," + F.c.toString() + "]") +} + +/* this=this^e */ +func (F *FP12) pow(e *BIG) *FP12 { + F.norm() + e.norm() + w := NewFP12copy(F) + z := NewBIGcopy(e) + r := NewFP12int(1) + + for true { + 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 (F *FP12) pinpow(e int, bts int) { + var R []*FP12 + R = append(R, NewFP12int(1)) + R = append(R, NewFP12copy(F)) + + for i := bts - 1; i >= 0; i-- { + b := (e >> uint(i)) & 1 + R[1-b].mul(R[b]) + R[b].usqr() + } + F.copy(R[0]) +} + +/* p=q0^u0.q1^u1.q2^u2.q3^u3 */ +/* Timing attack secure, but not cache attack secure */ + +func pow4(q []*FP12, u []*BIG) *FP12 { + var a [4]int8 + var g []*FP12 + var s []*FP12 + c := NewFP12int(1) + p := NewFP12int(0) + var w [NLEN*int(BASEBITS) + 1]int8 + var t []*BIG + mt := NewBIGint(0) + + for i := 0; i < 4; i++ { + t = append(t, NewBIGcopy(u[i])) + } + + s = append(s, NewFP12int(0)) + s = append(s, NewFP12int(0)) + + g = append(g, NewFP12copy(q[0])) + s[0].copy(q[1]) + s[0].conj() + g[0].mul(s[0]) + g = append(g, NewFP12copy(g[0])) + g = append(g, NewFP12copy(g[0])) + g = append(g, NewFP12copy(g[0])) + g = append(g, NewFP12copy(q[0])) + g[4].mul(q[1]) + g = append(g, NewFP12copy(g[4])) + g = append(g, NewFP12copy(g[4])) + g = append(g, NewFP12copy(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 := 0; i < 4; i++ { + if t[i].parity() == 0 { + t[i].inc(1) + t[i].norm() + c.mul(q[i]) + } + mt.add(t[i]) + mt.norm() + } + c.conj() + nb := 1 + mt.nbits() + + /* convert exponent to signed 1-bit window */ + for j := 0; j < nb; j++ { + for i := 0; i < 4; i++ { + a[i] = int8(t[i].lastbits(2) - 2) + t[i].dec(int(a[i])) + t[i].norm() + t[i].fshr(1) + } + w[j] = (8*a[0] + 4*a[1] + 2*a[2] + a[3]) + } + w[nb] = int8(8*t[0].lastbits(2) + 4*t[1].lastbits(2) + 2*t[2].lastbits(2) + t[3].lastbits(2)) + p.copy(g[(w[nb]-1)/2]) + + for i := nb - 1; i >= 0; i-- { + m := w[i] >> 7 + j := (w[i] ^ m) - m /* j=abs(w[i]) */ + j = (j - 1) / 2 + s[0].copy(g[j]) + s[1].copy(g[j]) + s[1].conj() + p.usqr() + p.mul(s[m&1]) + } + p.mul(c) /* apply correction */ + p.reduce() + return p +}
http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/85fabaa6/go/amcl-go/FP2.go ---------------------------------------------------------------------- diff --git a/go/amcl-go/FP2.go b/go/amcl-go/FP2.go new file mode 100644 index 0000000..599fbcc --- /dev/null +++ b/go/amcl-go/FP2.go @@ -0,0 +1,324 @@ +/* +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) */ + +package amcl + +//import "fmt" + +type FP2 struct { + a *FP + b *FP +} + +/* Constructors */ +func NewFP2int(a int) *FP2 { + F := new(FP2) + F.a = NewFPint(a) + F.b = NewFPint(0) + return F +} + +func NewFP2copy(x *FP2) *FP2 { + F := new(FP2) + F.a = NewFPcopy(x.a) + F.b = NewFPcopy(x.b) + return F +} + +func NewFP2fps(c *FP, d *FP) *FP2 { + F := new(FP2) + F.a = NewFPcopy(c) + F.b = NewFPcopy(d) + return F +} + +func NewFP2bigs(c *BIG, d *BIG) *FP2 { + F := new(FP2) + F.a = NewFPbig(c) + F.b = NewFPbig(d) + return F +} + +func NewFP2fp(c *FP) *FP2 { + F := new(FP2) + F.a = NewFPcopy(c) + F.b = NewFPint(0) + return F +} + +func NewFP2big(c *BIG) *FP2 { + F := new(FP2) + F.a = NewFPbig(c) + F.b = NewFPint(0) + return F +} + +/* reduce components mod Modulus */ +func (F *FP2) reduce() { + F.a.reduce() + F.b.reduce() +} + +/* normalise components of w */ +func (F *FP2) norm() { + F.a.norm() + F.b.norm() +} + +/* test this=0 ? */ +func (F *FP2) iszilch() bool { + F.reduce() + return (F.a.iszilch() && F.b.iszilch()) +} + +func (F *FP2) cmove(g *FP2, d int32) { + F.a.cmove(g.a, d) + F.b.cmove(g.b, d) +} + +/* test this=1 ? */ +func (F *FP2) isunity() bool { + one := NewFPint(1) + return (F.a.equals(one) && F.b.iszilch()) +} + +/* test this=x */ +func (F *FP2) equals(x *FP2) bool { + return (F.a.equals(x.a) && F.b.equals(x.b)) +} + +/* extract a */ +func (F *FP2) getA() *BIG { + return F.a.redc() +} + +/* extract b */ +func (F *FP2) getB() *BIG { + return F.b.redc() +} + +/* copy this=x */ +func (F *FP2) copy(x *FP2) { + F.a.copy(x.a) + F.b.copy(x.b) +} + +/* set this=0 */ +func (F *FP2) zero() { + F.a.zero() + F.b.zero() +} + +/* set this=1 */ +func (F *FP2) one() { + F.a.one() + F.b.zero() +} + +/* negate this mod Modulus */ +func (F *FP2) neg() { + F.norm() + m := NewFPcopy(F.a) + t := NewFPint(0) + + m.add(F.b) + m.neg() + m.norm() + t.copy(m) + t.add(F.b) + F.b.copy(m) + F.b.add(F.a) + F.a.copy(t) +} + +/* set to a-ib */ +func (F *FP2) conj() { + F.b.neg() +} + +/* this+=a */ +func (F *FP2) add(x *FP2) { + F.a.add(x.a) + F.b.add(x.b) +} + +/* this-=a */ +func (F *FP2) sub(x *FP2) { + m := NewFP2copy(x) + m.neg() + F.add(m) +} + +/* this*=s, where s is an FP */ +func (F *FP2) pmul(s *FP) { + F.a.mul(s) + F.b.mul(s) +} + +/* this*=i, where i is an int */ +func (F *FP2) imul(c int) { + F.a.imul(c) + F.b.imul(c) +} + +/* this*=this */ +func (F *FP2) sqr() { + F.norm() + w1 := NewFPcopy(F.a) + w3 := NewFPcopy(F.a) + mb := NewFPcopy(F.b) + + w3.mul(F.b) + w1.add(F.b) + mb.neg() + F.a.add(mb) + F.a.mul(w1) + F.b.copy(w3) + F.b.add(w3) + + F.norm() +} + +/* this*=y */ +func (F *FP2) mul(y *FP2) { + F.norm() /* This is needed here as {a,b} is not normed before additions */ + + w1 := NewFPcopy(F.a) + w2 := NewFPcopy(F.b) + w5 := NewFPcopy(F.a) + mw := NewFPint(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(F.b) // w5=a+b + F.b.copy(y.a) + F.b.add(y.b) // b=y.a+y.b + + F.b.mul(w5) + mw.copy(w1) + mw.add(w2) + mw.neg() + + F.b.add(mw) + mw.add(w1) + F.a.copy(w1) + F.a.add(mw) + + F.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 (F *FP2) sqrt() bool { + if F.iszilch() { + return true + } + w1 := NewFPcopy(F.b) + w2 := NewFPcopy(F.a) + w1.sqr() + w2.sqr() + w1.add(w2) + if w1.jacobi() != 1 { + F.zero() + return false + } + w1 = w1.sqrt() + w2.copy(F.a) + w2.add(w1) + w2.div2() + if w2.jacobi() != 1 { + w2.copy(F.a) + w2.sub(w1) + w2.div2() + if w2.jacobi() != 1 { + F.zero() + return false + } + } + w2 = w2.sqrt() + F.a.copy(w2) + w2.add(w2) + w2.inverse() + F.b.mul(w2) + return true +} + +/* output to hex string */ +func (F *FP2) toString() string { + return ("[" + F.a.toString() + "," + F.b.toString() + "]") +} + +/* this=1/this */ +func (F *FP2) inverse() { + F.norm() + w1 := NewFPcopy(F.a) + w2 := NewFPcopy(F.b) + + w1.sqr() + w2.sqr() + w1.add(w2) + w1.inverse() + F.a.mul(w1) + w1.neg() + F.b.mul(w1) +} + +/* this/=2 */ +func (F *FP2) div2() { + F.a.div2() + F.b.div2() +} + +/* this*=sqrt(-1) */ +func (F *FP2) times_i() { + // a.norm(); + z := NewFPcopy(F.a) + F.a.copy(F.b) + F.a.neg() + F.b.copy(z) +} + +/* w*=(1+sqrt(-1)) */ +/* where X*2-(1+sqrt(-1)) is irreducible for FP4, assumes p=3 mod 8 */ +func (F *FP2) mul_ip() { + F.norm() + t := NewFP2copy(F) + z := NewFPcopy(F.a) + F.a.copy(F.b) + F.a.neg() + F.b.copy(z) + F.add(t) + F.norm() +} + +/* w/=(1+sqrt(-1)) */ +func (F *FP2) div_ip() { + t := NewFP2int(0) + F.norm() + t.a.copy(F.a) + t.a.add(F.b) + t.b.copy(F.b) + t.b.sub(F.a) + F.copy(t) + F.div2() +} http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/85fabaa6/go/amcl-go/FP4.go ---------------------------------------------------------------------- diff --git a/go/amcl-go/FP4.go b/go/amcl-go/FP4.go new file mode 100644 index 0000000..76e9d1e --- /dev/null +++ b/go/amcl-go/FP4.go @@ -0,0 +1,522 @@ +/* +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)) */ + +package amcl + +//import "fmt" + +type FP4 struct { + a *FP2 + b *FP2 +} + +/* Constructors */ +func NewFP4int(a int) *FP4 { + F := new(FP4) + F.a = NewFP2int(a) + F.b = NewFP2int(0) + return F +} + +func NewFP4copy(x *FP4) *FP4 { + F := new(FP4) + F.a = NewFP2copy(x.a) + F.b = NewFP2copy(x.b) + return F +} + +func NewFP4fp2s(c *FP2, d *FP2) *FP4 { + F := new(FP4) + F.a = NewFP2copy(c) + F.b = NewFP2copy(d) + return F +} + +func NewFP4fp2(c *FP2) *FP4 { + F := new(FP4) + F.a = NewFP2copy(c) + F.b = NewFP2int(0) + return F +} + +/* reduce all components of this mod Modulus */ +func (F *FP4) reduce() { + F.a.reduce() + F.b.reduce() +} + +/* normalise all components of this mod Modulus */ +func (F *FP4) norm() { + F.a.norm() + F.b.norm() +} + +/* test this==0 ? */ +func (F *FP4) iszilch() bool { + F.reduce() + return F.a.iszilch() && F.b.iszilch() +} + +/* test this==1 ? */ +func (F *FP4) isunity() bool { + one := NewFP2int(1) + return F.a.equals(one) && F.b.iszilch() +} + +/* test is w real? That is in a+ib test b is zero */ +func (F *FP4) isreal() bool { + return F.b.iszilch() +} + +/* extract real part a */ +func (F *FP4) real() *FP2 { + return F.a +} + +func (F *FP4) geta() *FP2 { + return F.a +} + +/* extract imaginary part b */ +func (F *FP4) getb() *FP2 { + return F.b +} + +/* test this=x? */ +func (F *FP4) equals(x *FP4) bool { + return (F.a.equals(x.a) && F.b.equals(x.b)) +} + +/* copy this=x */ +func (F *FP4) copy(x *FP4) { + F.a.copy(x.a) + F.b.copy(x.b) +} + +/* set this=0 */ +func (F *FP4) zero() { + F.a.zero() + F.b.zero() +} + +/* set this=1 */ +func (F *FP4) one() { + F.a.one() + F.b.zero() +} + +/* set this=-this */ +func (F *FP4) neg() { + m := NewFP2copy(F.a) + t := NewFP2int(0) + m.add(F.b) + m.neg() + m.norm() + t.copy(m) + t.add(F.b) + F.b.copy(m) + F.b.add(F.a) + F.a.copy(t) +} + +/* this=conjugate(this) */ +func (F *FP4) conj() { + F.b.neg() + F.b.norm() +} + +/* this=-conjugate(this) */ +func (F *FP4) nconj() { + F.a.neg() + F.a.norm() +} + +/* this+=x */ +func (F *FP4) add(x *FP4) { + F.a.add(x.a) + F.b.add(x.b) +} + +/* this-=x */ +func (F *FP4) sub(x *FP4) { + m := NewFP4copy(x) + m.neg() + F.add(m) +} + +/* this*=s where s is FP2 */ +func (F *FP4) pmul(s *FP2) { + F.a.mul(s) + F.b.mul(s) +} + +/* this*=c where c is int */ +func (F *FP4) imul(c int) { + F.a.imul(c) + F.b.imul(c) +} + +/* this*=this */ +func (F *FP4) sqr() { + F.norm() + + t1 := NewFP2copy(F.a) + t2 := NewFP2copy(F.b) + t3 := NewFP2copy(F.a) + + t3.mul(F.b) + t1.add(F.b) + t2.mul_ip() + + t2.add(F.a) + F.a.copy(t1) + + F.a.mul(t2) + + t2.copy(t3) + t2.mul_ip() + t2.add(t3) + t2.neg() + F.a.add(t2) + + F.b.copy(t3) + F.b.add(t3) + + F.norm() +} + +/* this*=y */ +func (F *FP4) mul(y *FP4) { + F.norm() + + t1 := NewFP2copy(F.a) + t2 := NewFP2copy(F.b) + t3 := NewFP2int(0) + t4 := NewFP2copy(F.b) + + t1.mul(y.a) + t2.mul(y.b) + t3.copy(y.b) + t3.add(y.a) + t4.add(F.a) + + t4.mul(t3) + t4.sub(t1) + // t4.norm(); + + F.b.copy(t4) + F.b.sub(t2) + t2.mul_ip() + F.a.copy(t2) + F.a.add(t1) + + F.norm() +} + +/* convert this to hex string */ +func (F *FP4) toString() string { + return ("[" + F.a.toString() + "," + F.b.toString() + "]") +} + +/* this=1/this */ +func (F *FP4) inverse() { + F.norm() + + t1 := NewFP2copy(F.a) + t2 := NewFP2copy(F.b) + + t1.sqr() + t2.sqr() + t2.mul_ip() + t1.sub(t2) + t1.inverse() + F.a.mul(t1) + t1.neg() + F.b.mul(t1) +} + +/* this*=i where i = sqrt(-1+sqrt(-1)) */ +func (F *FP4) times_i() { + F.norm() + s := NewFP2copy(F.b) + t := NewFP2copy(F.b) + s.times_i() + t.add(s) + // t.norm(); + F.b.copy(F.a) + F.a.copy(t) +} + +/* this=this^p using Frobenius */ +func (F *FP4) frob(f *FP2) { + F.a.conj() + F.b.conj() + F.b.mul(f) +} + +/* this=this^e */ +func (F *FP4) pow(e *BIG) *FP4 { + F.norm() + e.norm() + w := NewFP4copy(F) + z := NewBIGcopy(e) + r := NewFP4int(1) + for true { + 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 (F *FP4) xtr_A(w *FP4, y *FP4, z *FP4) { + r := NewFP4copy(w) + t := NewFP4copy(w) + r.sub(y) + r.pmul(F.a) + t.add(y) + t.pmul(F.b) + t.times_i() + + F.copy(r) + F.add(t) + F.add(z) + + F.norm() +} + +/* XTR xtr_d function */ +func (F *FP4) xtr_D() { + w := NewFP4copy(F) + F.sqr() + w.conj() + w.add(w) + F.sub(w) + F.reduce() +} + +/* r=x^n using XTR method on traces of FP12s */ +func (F *FP4) xtr_pow(n *BIG) *FP4 { + a := NewFP4int(3) + b := NewFP4copy(F) + c := NewFP4copy(b) + c.xtr_D() + t := NewFP4int(0) + r := NewFP4int(0) + + n.norm() + par := n.parity() + v := NewBIGcopy(n) + v.fshr(1) + if par == 0 { + v.dec(1) + v.norm() + } + + nb := v.nbits() + for i := nb - 1; i >= 0; i-- { + if v.bit(i) != 1 { + t.copy(b) + F.conj() + c.conj() + b.xtr_A(a, F, c) + F.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, F, 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. */ +func (F *FP4) xtr_pow2(ck *FP4, ckml *FP4, ckm2l *FP4, a *BIG, b *BIG) *FP4 { + a.norm() + b.norm() + e := NewBIGcopy(a) + d := NewBIGcopy(b) + w := NewBIGint(0) + + cu := NewFP4copy(ck) // can probably be passed in w/o copying + cv := NewFP4copy(F) + cumv := NewFP4copy(ckml) + cum2v := NewFP4copy(ckm2l) + r := NewFP4int(0) + t := NewFP4int(0) + + f2 := 0 + for d.parity() == 0 && e.parity() == 0 { + d.fshr(1) + e.fshr(1) + f2++ + } + + for comp(d, e) != 0 { + if comp(d, e) > 0 { + w.copy(e) + w.imul(4) + w.norm() + if 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 comp(d, e) < 0 { + w.copy(d) + w.imul(4) + w.norm() + if 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 i := 0; i < f2; i++ { + r.xtr_D() + } + r = r.xtr_pow(d) + return r +} http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/85fabaa6/go/amcl-go/GCM.go ---------------------------------------------------------------------- diff --git a/go/amcl-go/GCM.go b/go/amcl-go/GCM.go new file mode 100644 index 0000000..2fc4da3 --- /dev/null +++ b/go/amcl-go/GCM.go @@ -0,0 +1,472 @@ +/* +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 + */ + +package amcl + +/* +import +( + "fmt" + "strconv" +) +*/ +const gcm_NB int = 4 +const GCM_ACCEPTING_HEADER int = 0 +const GCM_ACCEPTING_CIPHER int = 1 +const GCM_NOT_ACCEPTING_MORE int = 2 +const GCM_FINISHED int = 3 +const GCM_ENCRYPTING int = 0 +const GCM_DECRYPTING int = 1 + +type GCM struct { + table [128][4]uint32 /* 2k bytes */ + stateX [16]byte + Y_0 [16]byte + counter int + lenA [2]uint32 + lenC [2]uint32 + status int + a *AES +} + +func gcm_pack(b [4]byte) uint32 { /* pack bytes into a 32-bit Word */ + return ((uint32(b[0]) & 0xff) << 24) | ((uint32(b[1]) & 0xff) << 16) | ((uint32(b[2]) & 0xff) << 8) | (uint32(b[3]) & 0xff) +} + +func gcm_unpack(a uint32) [4]byte { /* unpack bytes from a word */ + var b = [4]byte{byte((a >> 24) & 0xff), byte((a >> 16) & 0xff), byte((a >> 8) & 0xff), byte(a & 0xff)} + return b +} + +func (G *GCM) precompute(H []byte) { + var b [4]byte + j := 0 + for i := 0; i < gcm_NB; i++ { + b[0] = H[j] + b[1] = H[j+1] + b[2] = H[j+2] + b[3] = H[j+3] + G.table[0][i] = gcm_pack(b) + j += 4 + } + for i := 1; i < 128; i++ { + c := uint32(0) + for j := 0; j < gcm_NB; j++ { + G.table[i][j] = c | (G.table[i-1][j])>>1 + c = G.table[i-1][j] << 31 + } + if c != 0 { + G.table[i][0] ^= 0xE1000000 + } /* irreducible polynomial */ + } +} + +func (G *GCM) gf2mul() { /* gf2m mul - Z=H*X mod 2^128 */ + var P [4]uint32 + + for i := 0; i < 4; i++ { + P[i] = 0 + } + j := uint(8) + m := 0 + for i := 0; i < 128; i++ { + j-- + c := (G.stateX[m] >> j) & 1 + if c != 0 { + for k := 0; k < gcm_NB; k++ { + P[k] ^= G.table[i][k] + } + } + if j == 0 { + j = 8 + m++ + if m == 16 { + break + } + } + } + j = 0 + for i := 0; i < gcm_NB; i++ { + b := gcm_unpack(P[i]) + G.stateX[j] = b[0] + G.stateX[j+1] = b[1] + G.stateX[j+2] = b[2] + G.stateX[j+3] = b[3] + j += 4 + } +} + +func (G *GCM) wrap() { /* Finish off GHASH */ + var F [4]uint32 + var L [16]byte + + /* convert lengths from bytes to bits */ + F[0] = (G.lenA[0] << 3) | (G.lenA[1]&0xE0000000)>>29 + F[1] = G.lenA[1] << 3 + F[2] = (G.lenC[0] << 3) | (G.lenC[1]&0xE0000000)>>29 + F[3] = G.lenC[1] << 3 + j := 0 + for i := 0; i < gcm_NB; i++ { + 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 := 0; i < 16; i++ { + G.stateX[i] ^= L[i] + } + G.gf2mul() +} + +func (G *GCM) ghash(plain []byte, len int) bool { + if G.status == GCM_ACCEPTING_HEADER { + G.status = GCM_ACCEPTING_CIPHER + } + if G.status != GCM_ACCEPTING_CIPHER { + return false + } + + j := 0 + for j < len { + for i := 0; i < 16 && j < len; i++ { + G.stateX[i] ^= plain[j] + j++ + G.lenC[1]++ + if G.lenC[1] == 0 { + G.lenC[0]++ + } + } + G.gf2mul() + } + if len%16 != 0 { + G.status = GCM_NOT_ACCEPTING_MORE + } + return true +} + +/* Initialize GCM mode */ +func (G *GCM) Init(key []byte, niv int, iv []byte) { /* iv size niv is usually 12 bytes (96 bits). AES key size nk can be 16,24 or 32 bytes */ + var H [16]byte + + for i := 0; i < 16; i++ { + H[i] = 0 + G.stateX[i] = 0 + } + + G.a = new(AES) + + G.a.Init(aes_ECB, key, iv) + G.a.ecb_encrypt(H[:]) /* E(K,0) */ + G.precompute(H[:]) + + G.lenA[0] = 0 + G.lenC[0] = 0 + G.lenA[1] = 0 + G.lenC[1] = 0 + if niv == 12 { + for i := 0; i < 12; i++ { + G.a.f[i] = iv[i] + } + b := gcm_unpack(uint32(1)) + G.a.f[12] = b[0] + G.a.f[13] = b[1] + G.a.f[14] = b[2] + G.a.f[15] = b[3] /* initialise IV */ + for i := 0; i < 16; i++ { + G.Y_0[i] = G.a.f[i] + } + } else { + G.status = GCM_ACCEPTING_CIPHER + G.ghash(iv, niv) /* GHASH(H,0,IV) */ + G.wrap() + for i := 0; i < 16; i++ { + G.a.f[i] = G.stateX[i] + G.Y_0[i] = G.a.f[i] + G.stateX[i] = 0 + } + G.lenA[0] = 0 + G.lenC[0] = 0 + G.lenA[1] = 0 + G.lenC[1] = 0 + } + G.status = GCM_ACCEPTING_HEADER +} + +/* Add Header data - included but not encrypted */ +func (G *GCM) Add_header(header []byte, len int) bool { /* Add some header. Won't be encrypted, but will be authenticated. len is length of header */ + if G.status != GCM_ACCEPTING_HEADER { + return false + } + + j := 0 + for j < len { + for i := 0; i < 16 && j < len; i++ { + G.stateX[i] ^= header[j] + j++ + G.lenA[1]++ + if G.lenA[1] == 0 { + G.lenA[0]++ + } + } + G.gf2mul() + } + if len%16 != 0 { + G.status = GCM_ACCEPTING_CIPHER + } + return true +} + +/* Add Plaintext - included and encrypted */ +func (G *GCM) Add_plain(plain []byte, len int) []byte { + var B [16]byte + var b [4]byte + + cipher := make([]byte, len) + var counter uint32 = 0 + if G.status == GCM_ACCEPTING_HEADER { + G.status = GCM_ACCEPTING_CIPHER + } + if G.status != GCM_ACCEPTING_CIPHER { + return nil + } + + j := 0 + for j < len { + + b[0] = G.a.f[12] + b[1] = G.a.f[13] + b[2] = G.a.f[14] + b[3] = G.a.f[15] + counter = gcm_pack(b) + counter++ + b = gcm_unpack(counter) + G.a.f[12] = b[0] + G.a.f[13] = b[1] + G.a.f[14] = b[2] + G.a.f[15] = b[3] /* increment counter */ + for i := 0; i < 16; i++ { + B[i] = G.a.f[i] + } + G.a.ecb_encrypt(B[:]) /* encrypt it */ + + for i := 0; i < 16 && j < len; i++ { + cipher[j] = (plain[j] ^ B[i]) + G.stateX[i] ^= cipher[j] + j++ + G.lenC[1]++ + if G.lenC[1] == 0 { + G.lenC[0]++ + } + } + G.gf2mul() + } + if len%16 != 0 { + G.status = GCM_NOT_ACCEPTING_MORE + } + return cipher +} + +/* Add Ciphertext - decrypts to plaintext */ +func (G *GCM) Add_cipher(cipher []byte, len int) []byte { + var B [16]byte + var b [4]byte + + plain := make([]byte, len) + var counter uint32 = 0 + + if G.status == GCM_ACCEPTING_HEADER { + G.status = GCM_ACCEPTING_CIPHER + } + if G.status != GCM_ACCEPTING_CIPHER { + return nil + } + + j := 0 + for j < len { + b[0] = G.a.f[12] + b[1] = G.a.f[13] + b[2] = G.a.f[14] + b[3] = G.a.f[15] + counter = gcm_pack(b) + counter++ + b = gcm_unpack(counter) + G.a.f[12] = b[0] + G.a.f[13] = b[1] + G.a.f[14] = b[2] + G.a.f[15] = b[3] /* increment counter */ + for i := 0; i < 16; i++ { + B[i] = G.a.f[i] + } + G.a.ecb_encrypt(B[:]) /* encrypt it */ + for i := 0; i < 16 && j < len; i++ { + plain[j] = (cipher[j] ^ B[i]) + G.stateX[i] ^= cipher[j] + j++ + G.lenC[1]++ + if G.lenC[1] == 0 { + G.lenC[0]++ + } + } + G.gf2mul() + } + if len%16 != 0 { + G.status = GCM_NOT_ACCEPTING_MORE + } + return plain +} + +/* Finish and extract Tag */ +func (G *GCM) Finish(extract bool) [16]byte { /* Finish off GHASH and extract tag (MAC) */ + var tag [16]byte + + G.wrap() + /* extract tag */ + if extract { + G.a.ecb_encrypt(G.Y_0[:]) /* E(K,Y0) */ + for i := 0; i < 16; i++ { + G.Y_0[i] ^= G.stateX[i] + } + for i := 0; i < 16; i++ { + tag[i] = G.Y_0[i] + G.Y_0[i] = 0 + G.stateX[i] = 0 + } + } + G.status = GCM_FINISHED + G.a.End() + return tag +} + +/* AES-GCM Encryption: + K is key, H is header, IV is initialization vector and P is plaintext. + Returns cipthertext and tag (MAC) */ +func AES_GCM_ENCRYPT(K, IV, H, P []byte) ([]byte, []byte) { + g := new(GCM) + lenIV := len(IV) + lenH := len(H) + lenP := len(P) + + g.Init(K, lenIV, IV) + g.Add_header(H, lenH) + C := g.Add_plain(P, lenP) + T := g.Finish(true) + return C, T[:] +} + +/* AES-GCM Deryption: + K is key, H is header, IV is initialization vector and P is plaintext. + Returns cipthertext and tag (MAC) */ +func AES_GCM_DECRYPT(K, IV, H, C []byte) ([]byte, []byte) { + g := new(GCM) + lenIV := len(IV) + lenH := len(H) + lenC := len(C) + + g.Init(K, lenIV, IV) + g.Add_header(H, lenH) + P := g.Add_cipher(C, lenC) + T := g.Finish(true) + return P, T[:] +} + +/* +func hex2bytes(s string) []byte { + lgh:=len(s) + data:=make([]byte,lgh/2) + + for i:=0;i<lgh;i+=2 { + a,_ := strconv.ParseInt(s[i:i+2],16,32) + data[i/2]=byte(a) + } + return data +} + +func main() { + + KT:="feffe9928665731c6d6a8f9467308308" + MT:="d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39" + HT:="feedfacedeadbeeffeedfacedeadbeefabaddad2" + + NT:="9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b"; +// Tag should be 619cc5aefffe0bfa462af43c1699d050 + + g:=new(GCM) + + M:=hex2bytes(MT) + H:=hex2bytes(HT) + N:=hex2bytes(NT) + K:=hex2bytes(KT) + + lenM:=len(M) + lenH:=len(H) + //lenK:=len(K) + lenIV:=len(N) + + fmt.Printf("Plaintext=\n"); + for i:=0;i<lenM;i++ {fmt.Printf("%02x",M[i])} + fmt.Printf("\n") + + g.Init(K,lenIV,N) + g.Add_header(H,lenH) + C:=g.Add_plain(M,lenM) + T:=g.Finish(true) + + fmt.Printf("Ciphertext=\n") + for i:=0;i<lenM;i++ {fmt.Printf("%02x",C[i])} + fmt.Printf("\n") + + fmt.Printf("Tag=\n") + for i:=0;i<16;i++ {fmt.Printf("%02x",T[i])} + fmt.Printf("\n") + + g.Init(K,lenIV,N) + g.Add_header(H,lenH) + P:=g.Add_cipher(C,lenM) + T=g.Finish(true) + + fmt.Printf("Plaintext=\n"); + for i:=0;i<lenM;i++ {fmt.Printf("%02x",P[i])} + fmt.Printf("\n") + + fmt.Printf("Tag=\n"); + for i:=0;i<16;i++ {fmt.Printf("%02x",T[i])} + fmt.Printf("\n") +} +*/ http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/85fabaa6/go/amcl-go/HASH.go ---------------------------------------------------------------------- diff --git a/go/amcl-go/HASH.go b/go/amcl-go/HASH.go new file mode 100644 index 0000000..c31f51a --- /dev/null +++ b/go/amcl-go/HASH.go @@ -0,0 +1,215 @@ +/* +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. + */ + +package amcl + +//import "fmt" + +const hash_H0 uint32 = 0x6A09E667 +const hash_H1 uint32 = 0xBB67AE85 +const hash_H2 uint32 = 0x3C6EF372 +const hash_H3 uint32 = 0xA54FF53A +const hash_H4 uint32 = 0x510E527F +const hash_H5 uint32 = 0x9B05688C +const hash_H6 uint32 = 0x1F83D9AB +const hash_H7 uint32 = 0x5BE0CD19 + +var hash_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} + +type HASH struct { + length [2]uint32 + h [8]uint32 + w [64]uint32 +} + +/* functions */ +func hash_S(n uint32, x uint32) uint32 { + return (((x) >> n) | ((x) << (32 - n))) +} + +func hash_R(n uint32, x uint32) uint32 { + return ((x) >> n) +} + +func hash_Ch(x, y, z uint32) uint32 { + return ((x & y) ^ (^(x) & z)) +} + +func hash_Maj(x, y, z uint32) uint32 { + return ((x & y) ^ (x & z) ^ (y & z)) +} + +func hash_Sig0(x uint32) uint32 { + return (hash_S(2, x) ^ hash_S(13, x) ^ hash_S(22, x)) +} + +func hash_Sig1(x uint32) uint32 { + return (hash_S(6, x) ^ hash_S(11, x) ^ hash_S(25, x)) +} + +func hash_theta0(x uint32) uint32 { + return (hash_S(7, x) ^ hash_S(18, x) ^ hash_R(3, x)) +} + +func hash_theta1(x uint32) uint32 { + return (hash_S(17, x) ^ hash_S(19, x) ^ hash_R(10, x)) +} + +func (H *HASH) transform() { /* basic transformation step */ + for j := 16; j < 64; j++ { + H.w[j] = hash_theta1(H.w[j-2]) + H.w[j-7] + hash_theta0(H.w[j-15]) + H.w[j-16] + } + a := H.h[0] + b := H.h[1] + c := H.h[2] + d := H.h[3] + e := H.h[4] + f := H.h[5] + g := H.h[6] + hh := H.h[7] + for j := 0; j < 64; j++ { /* 64 times - mush it up */ + t1 := hh + hash_Sig1(e) + hash_Ch(e, f, g) + hash_K[j] + H.w[j] + t2 := hash_Sig0(a) + hash_Maj(a, b, c) + hh = g + g = f + f = e + e = d + t1 + d = c + c = b + b = a + a = t1 + t2 + } + H.h[0] += a + H.h[1] += b + H.h[2] += c + H.h[3] += d + H.h[4] += e + H.h[5] += f + H.h[6] += g + H.h[7] += hh +} + +/* Initialise Hash function */ +func (H *HASH) Init() { /* initialise */ + for i := 0; i < 64; i++ { + H.w[i] = 0 + } + H.length[0] = 0 + H.length[1] = 0 + H.h[0] = hash_H0 + H.h[1] = hash_H1 + H.h[2] = hash_H2 + H.h[3] = hash_H3 + H.h[4] = hash_H4 + H.h[5] = hash_H5 + H.h[6] = hash_H6 + H.h[7] = hash_H7 +} + +func NewHASH() *HASH { + H := new(HASH) + H.Init() + return H +} + +/* process a single byte */ +func (H *HASH) Process(byt byte) { /* process the next message byte */ + cnt := (H.length[0] / 32) % 16 + + H.w[cnt] <<= 8 + H.w[cnt] |= uint32(byt & 0xFF) + H.length[0] += 8 + if H.length[0] == 0 { + H.length[1]++ + H.length[0] = 0 + } + if (H.length[0] % 512) == 0 { + H.transform() + } +} + +/* process an array of bytes */ +func (H *HASH) Process_array(b []byte) { + for i := 0; i < len(b); i++ { + H.Process((b[i])) + } +} + +/* process a 32-bit integer */ +func (H *HASH) Process_num(n int32) { + H.Process(byte((n >> 24) & 0xff)) + H.Process(byte((n >> 16) & 0xff)) + H.Process(byte((n >> 8) & 0xff)) + H.Process(byte(n & 0xff)) +} + +/* Generate 32-byte Hash */ +func (H *HASH) Hash() [32]byte { /* pad message and finish - supply digest */ + var digest [32]byte + len0 := H.length[0] + len1 := H.length[1] + H.Process(0x80) + for (H.length[0] % 512) != 448 { + H.Process(0) + } + H.w[14] = len1 + H.w[15] = len0 + H.transform() + for i := 0; i < 32; i++ { /* convert to bytes */ + digest[i] = byte((H.h[i/4] >> uint(8*(3-i%4))) & 0xff) + } + H.Init() + return digest +} + +/* test program: should produce digest */ + +//248d6a61 d20638b8 e5c02693 0c3e6039 a33ce459 64ff2167 f6ecedd4 19db06c1 +/* +func main() { + + test := []byte("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") + sh:=NewHASH() + + for i:=0;i<len(test);i++ { + sh.Process(test[i]) + } + + digest:=sh.Hash() + for i:=0;i<32;i++ {fmt.Printf("%02x",digest[i])} + +} +*/ http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/85fabaa6/go/amcl-go/MPIN.go ---------------------------------------------------------------------- diff --git a/go/amcl-go/MPIN.go b/go/amcl-go/MPIN.go new file mode 100644 index 0000000..42a2443 --- /dev/null +++ b/go/amcl-go/MPIN.go @@ -0,0 +1,807 @@ +/* +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 */ + +package amcl + +import "time" + +import "fmt" + +/* Configure mode of operation */ + +const PERMITS bool = true +const PINERROR bool = true +const FULL bool = true +const SINGLE_PASS bool = false + +const MPIN_EFS int = int(MODBYTES) +const MPIN_EGS int = int(MODBYTES) +const MPIN_PAS int = 16 +const MPIN_BAD_PARAMS int = -11 +const MPIN_INVALID_POINT int = -14 +const MPIN_WRONG_ORDER int = -18 +const MPIN_BAD_PIN int = -19 + +/* Configure your PIN here */ + +const MPIN_MAXPIN int32 = 10000 /* PIN less than this */ +const MPIN_PBLEN int32 = 14 /* Number of bits in PIN */ +const MPIN_TS int = 10 /* 10 for 4 digit PIN, 14 for 6-digit PIN - 2^TS/TS approx = sqrt(MAXPIN) */ +const MPIN_TRAP int = 200 /* 200 for 4 digit PIN, 2000 for 6-digit PIN - approx 2*sqrt(MAXPIN) */ + +/* Hash number (optional) and string to point on curve */ + +func Hashit(n int32, ID []byte) []byte { + H := NewHASH() + if n != 0 { + H.Process_num(n) + } + H.Process_array(ID) + h := H.Hash() + return h[:] +} + +func mapit(h []byte) *ECP { + q := NewBIGints(Modulus) + x := fromBytes(h[:]) + x.mod(q) + var P *ECP + for true { + P = NewECPbigint(x, 0) + if !P.is_infinity() { + break + } + x.inc(1) + x.norm() + } + return P +} + +/* needed for SOK */ +func mapit2(h []byte) *ECP2 { + q := NewBIGints(Modulus) + x := fromBytes(h[:]) + one := NewBIGint(1) + var X *FP2 + var Q, T, K *ECP2 + x.mod(q) + for true { + X = NewFP2bigs(one, x) + Q = NewECP2fp2(X) + if !Q.is_infinity() { + break + } + x.inc(1) + x.norm() + } + /* Fast Hashing to G2 - Fuentes-Castaneda, Knapp and Rodriguez-Henriquez */ + Fra := NewBIGints(CURVE_Fra) + Frb := NewBIGints(CURVE_Frb) + X = NewFP2bigs(Fra, Frb) + x = NewBIGints(CURVE_Bnx) + + T = NewECP2() + T.copy(Q) + T.mul(x) + T.neg() + K = NewECP2() + 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 */ +func MPIN_today() int { + now := time.Now() + return int(now.Unix()) / (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 */ +func emap(u *BIG, cb int) *ECP { + var P *ECP + x := NewBIGcopy(u) + p := NewBIGints(Modulus) + x.mod(p) + for true { + P = NewECPbigint(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 */ +func unmap(u *BIG, P *ECP) int { + s := P.getS() + var R *ECP + r := 0 + x := P.getX() + u.copy(x) + for true { + u.dec(1) + u.norm() + r++ + R = NewECPbigint(u, s) + if !R.is_infinity() { + break + } + } + return r +} + +func MPIN_HASH_ID(ID []byte) []byte { + return Hashit(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 */ +func MPIN_ENCODING(rng *RAND, E []byte) int { + var T [MPIN_EFS]byte + + for i := 0; i < MPIN_EFS; i++ { + T[i] = E[i+1] + } + u := fromBytes(T[:]) + for i := 0; i < MPIN_EFS; i++ { + T[i] = E[i+MPIN_EFS+1] + } + v := fromBytes(T[:]) + + P := NewECPbigs(u, v) + if P.is_infinity() { + return MPIN_INVALID_POINT + } + + p := NewBIGints(Modulus) + u = randomnum(p, rng) + + su := int(rng.GetByte()) + su %= 2 + + W := emap(u, su) + P.sub(W) + sv := P.getS() + rn := unmap(v, P) + m := int(rng.GetByte()) + m %= rn + v.inc(m + 1) + E[0] = byte(su + 2*sv) + u.toBytes(T[:]) + for i := 0; i < MPIN_EFS; i++ { + E[i+1] = T[i] + } + v.toBytes(T[:]) + for i := 0; i < MPIN_EFS; i++ { + E[i+MPIN_EFS+1] = T[i] + } + + return 0 +} + +func MPIN_DECODING(D []byte) int { + var T [MPIN_EFS]byte + + if (D[0] & 0x04) != 0 { + return MPIN_INVALID_POINT + } + + for i := 0; i < MPIN_EFS; i++ { + T[i] = D[i+1] + } + u := fromBytes(T[:]) + for i := 0; i < MPIN_EFS; i++ { + T[i] = D[i+MPIN_EFS+1] + } + v := fromBytes(T[:]) + + su := int(D[0] & 1) + sv := int((D[0] >> 1) & 1) + W := emap(u, su) + P := emap(v, sv) + P.add(W) + u = P.getX() + v = P.getY() + D[0] = 0x04 + u.toBytes(T[:]) + for i := 0; i < MPIN_EFS; i++ { + D[i+1] = T[i] + } + v.toBytes(T[:]) + for i := 0; i < MPIN_EFS; i++ { + D[i+MPIN_EFS+1] = T[i] + } + + return 0 +} + +/* R=R1+R2 in group G1 */ +func MPIN_RECOMBINE_G1(R1 []byte, R2 []byte, R []byte) int { + P := ECP_fromBytes(R1) + Q := ECP_fromBytes(R2) + + if P.is_infinity() || Q.is_infinity() { + return MPIN_INVALID_POINT + } + + P.add(Q) + + P.toBytes(R[:]) + return 0 +} + +/* W=W1+W2 in group G2 */ +func MPIN_RECOMBINE_G2(W1 []byte, W2 []byte, W []byte) int { + P := ECP2_fromBytes(W1) + Q := ECP2_fromBytes(W2) + + if P.is_infinity() || Q.is_infinity() { + return MPIN_INVALID_POINT + } + + P.add(Q) + + P.toBytes(W) + return 0 +} + +/* create random secret S */ +func MPIN_RANDOM_GENERATE(rng *RAND, S []byte) int { + r := NewBIGints(CURVE_Order) + s := randomnum(r, rng) + + s.toBytes(S) + return 0 +} + +/* Extract PIN from TOKEN for identity CID */ +func MPIN_EXTRACT_PIN(CID []byte, pin int, TOKEN []byte) int { + P := ECP_fromBytes(TOKEN) + if P.is_infinity() { + return MPIN_INVALID_POINT + } + h := Hashit(0, CID) + R := mapit(h) + + R = R.pinmul(int32(pin)%MPIN_MAXPIN, MPIN_PBLEN) + P.sub(R) + + P.toBytes(TOKEN) + + return 0 +} + +/* Implement step 2 on client side of MPin protocol */ +func MPIN_CLIENT_2(X []byte, Y []byte, SEC []byte) int { + r := NewBIGints(CURVE_Order) + P := ECP_fromBytes(SEC) + if P.is_infinity() { + return MPIN_INVALID_POINT + } + + px := fromBytes(X) + py := fromBytes(Y) + px.add(py) + px.mod(r) + px.rsub(r) + + G1mul(P, px).toBytes(SEC) + return 0 +} + +/* Implement step 1 on client side of MPin protocol */ +func MPIN_CLIENT_1(date int, CLIENT_ID []byte, rng *RAND, X []byte, pin int, TOKEN []byte, SEC []byte, xID []byte, xCID []byte, PERMIT []byte) int { + r := NewBIGints(CURVE_Order) + + var x *BIG + if rng != nil { + x = randomnum(r, rng) + x.toBytes(X) + } else { + x = fromBytes(X) + } + + h := Hashit(0, CLIENT_ID) + P := mapit(h) + + T := ECP_fromBytes(TOKEN) + if T.is_infinity() { + return MPIN_INVALID_POINT + } + + W := P.pinmul(int32(pin)%MPIN_MAXPIN, MPIN_PBLEN) + T.add(W) + if date != 0 { + W = ECP_fromBytes(PERMIT) + if W.is_infinity() { + return MPIN_INVALID_POINT + } + T.add(W) + h = Hashit(int32(date), h) + W = mapit(h) + if xID != nil { + P = G1mul(P, x) + P.toBytes(xID) + W = G1mul(W, x) + P.add(W) + } else { + P.add(W) + P = G1mul(P, x) + } + if xCID != nil { + P.toBytes(xCID) + } + } else { + if xID != nil { + P = 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 */ +func MPIN_GET_SERVER_SECRET(S []byte, SST []byte) int { + Q := NewECP2fp2s(NewFP2bigs(NewBIGints(CURVE_Pxa), NewBIGints(CURVE_Pxb)), NewFP2bigs(NewBIGints(CURVE_Pya), NewBIGints(CURVE_Pyb))) + + s := fromBytes(S) + Q = 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 +*/ +func MPIN_GET_G1_MULTIPLE(rng *RAND, typ int, X []byte, G []byte, W []byte) int { + var x *BIG + r := NewBIGints(CURVE_Order) + if rng != nil { + x = randomnum(r, rng) + x.toBytes(X) + } else { + x = fromBytes(X) + } + var P *ECP + if typ == 0 { + P = ECP_fromBytes(G) + if P.is_infinity() { + return MPIN_INVALID_POINT + } + } else { + P = mapit(G) + } + + 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 */ +func MPIN_GET_CLIENT_SECRET(S []byte, CID []byte, CST []byte) int { + return MPIN_GET_G1_MULTIPLE(nil, 1, S, CID, CST) +} + +/* Time Permit CTT=S*(date|H(CID)) where S is master secret */ +func MPIN_GET_CLIENT_PERMIT(date int, S []byte, CID []byte, CTT []byte) int { + h := Hashit(int32(date), CID) + P := mapit(h) + + s := fromBytes(S) + 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 */ +func MPIN_SERVER_1(date int, CID []byte, HID []byte, HTID []byte) { + h := Hashit(0, CID) + P := mapit(h) + + if date != 0 { + if HID != nil { + P.toBytes(HID) + } + h = Hashit(int32(date), h) + R := mapit(h) + P.add(R) + P.toBytes(HTID) + } else { + P.toBytes(HID) + } +} + +/* Implement step 2 of MPin protocol on server side */ +func MPIN_SERVER_2(date int, HID []byte, HTID []byte, Y []byte, SST []byte, xID []byte, xCID []byte, mSEC []byte, E []byte, F []byte) int { + // q:=NewBIGints(Modulus) + Q := NewECP2fp2s(NewFP2bigs(NewBIGints(CURVE_Pxa), NewBIGints(CURVE_Pxb)), NewFP2bigs(NewBIGints(CURVE_Pya), NewBIGints(CURVE_Pyb))) + + sQ := ECP2_fromBytes(SST) + if sQ.is_infinity() { + return MPIN_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 MPIN_INVALID_POINT + } + + y := 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 MPIN_INVALID_POINT + } + + P = G1mul(P, y) + P.add(R) + R = ECP_fromBytes(mSEC) + if R.is_infinity() { + return MPIN_INVALID_POINT + } + + var g *FP12 + // FP12 g1=new FP12(0); + + g = ate2(Q, R, sQ, P) + g = 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 = G1mul(P, y) + P.add(R) + } + g = ate(Q, P) + g = fexp(g) + g.toBytes(F) + } + return MPIN_BAD_PIN + } + + return 0 +} + +/* Pollards kangaroos used to return PIN error */ +func MPIN_KANGAROO(E []byte, F []byte) int { + ge := FP12_fromBytes(E) + gf := FP12_fromBytes(F) + var distance [MPIN_TS]int + t := NewFP12copy(gf) + + var table []*FP12 + var i int + s := 1 + for m := 0; m < MPIN_TS; m++ { + distance[m] = s + table = append(table, NewFP12copy(t)) + s *= 2 + t.usqr() + } + t.one() + dn := 0 + for j := 0; j < MPIN_TRAP; j++ { + i = t.geta().geta().getA().lastbits(8) % MPIN_TS + t.mul(table[i]) + dn += distance[i] + } + gf.copy(t) + gf.conj() + steps := 0 + dm := 0 + res := 0 + for dm-dn < int(MPIN_MAXPIN) { + steps++ + if steps > 4*MPIN_TRAP { + break + } + i = ge.geta().geta().getA().lastbits(8) % MPIN_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*MPIN_TRAP || dm-dn >= int(MPIN_MAXPIN) { + res = 0 + } // Trap Failed - probable invalid token + return int(res) +} + +/* Functions to support M-Pin Full */ + +func MPIN_PRECOMPUTE(TOKEN []byte, CID []byte, G1 []byte, G2 []byte) int { + var P, T *ECP + var g *FP12 + + T = ECP_fromBytes(TOKEN) + if T.is_infinity() { + return MPIN_INVALID_POINT + } + + P = mapit(CID) + + Q := NewECP2fp2s(NewFP2bigs(NewBIGints(CURVE_Pxa), NewBIGints(CURVE_Pxb)), NewFP2bigs(NewBIGints(CURVE_Pya), NewBIGints(CURVE_Pyb))) + + g = ate(Q, T) + g = fexp(g) + g.toBytes(G1) + + g = ate(Q, P) + g = fexp(g) + g.toBytes(G2) + + return 0 +} + +/* calculate common key on client side */ +/* wCID = w.(A+AT) */ +func MPIN_CLIENT_KEY(G1 []byte, G2 []byte, pin int, R []byte, X []byte, wCID []byte, CK []byte) int { + H := NewHASH() + var t [MPIN_EFS]byte + + g1 := FP12_fromBytes(G1) + g2 := FP12_fromBytes(G2) + z := fromBytes(R) + x := fromBytes(X) + + W := ECP_fromBytes(wCID) + if W.is_infinity() { + return MPIN_INVALID_POINT + } + + W = G1mul(W, x) + + f := NewFP2bigs(NewBIGints(CURVE_Fra), NewBIGints(CURVE_Frb)) + r := NewBIGints(CURVE_Order) + q := NewBIGints(Modulus) + + m := NewBIGcopy(q) + m.mod(r) + + a := NewBIGcopy(z) + a.mod(m) + + b := NewBIGcopy(z) + b.div(m) + + g2.pinpow(pin, int(MPIN_PBLEN)) + g1.mul(g2) + + c := g1.trace() + g2.copy(g1) + g2.frob(f) + cp := g2.trace() + g1.conj() + g2.mul(g1) + cpm1 := g2.trace() + g2.mul(g1) + cpm2 := g2.trace() + + c = c.xtr_pow2(cp, cpm1, cpm2, a, b) + + c.geta().getA().toBytes(t[:]) + H.Process_array(t[:]) + c.geta().getB().toBytes(t[:]) + H.Process_array(t[:]) + c.getb().getA().toBytes(t[:]) + H.Process_array(t[:]) + c.getb().getB().toBytes(t[:]) + H.Process_array(t[:]) + + W.getX().toBytes(t[:]) + H.Process_array(t[:]) + W.getY().toBytes(t[:]) + H.Process_array(t[:]) + + t = H.Hash() + for i := 0; i < MPIN_PAS; i++ { + CK[i] = t[i] + } + + return 0 +} + +/* calculate common key on server side */ +/* Z=r.A - no time permits involved */ + +func MPIN_SERVER_KEY(Z []byte, SST []byte, W []byte, xID []byte, xCID []byte, SK []byte) int { + H := NewHASH() + var t [MPIN_EFS]byte + + sQ := ECP2_fromBytes(SST) + if sQ.is_infinity() { + return MPIN_INVALID_POINT + } + R := ECP_fromBytes(Z) + if R.is_infinity() { + return MPIN_INVALID_POINT + } + + var U *ECP + if xCID != nil { + U = ECP_fromBytes(xCID) + } else { + U = ECP_fromBytes(xID) + } + if U.is_infinity() { + return MPIN_INVALID_POINT + } + + w := fromBytes(W) + U = G1mul(U, w) + g := ate(sQ, R) + g = fexp(g) + + c := g.trace() + c.geta().getA().toBytes(t[:]) + H.Process_array(t[:]) + c.geta().getB().toBytes(t[:]) + H.Process_array(t[:]) + c.getb().getA().toBytes(t[:]) + H.Process_array(t[:]) + c.getb().getB().toBytes(t[:]) + H.Process_array(t[:]) + + U.getX().toBytes(t[:]) + H.Process_array(t[:]) + U.getY().toBytes(t[:]) + H.Process_array(t[:]) + + t = H.Hash() + for i := 0; i < MPIN_PAS; i++ { + SK[i] = t[i] + } + + return 0 +} + +/* return time since epoch */ +func MPIN_GET_TIME() int { + now := time.Now() + return int(now.Unix()) +} + +/* Generate Y = H(epoch, xCID/xID) */ +func MPIN_GET_Y(TimeValue int, xCID []byte, Y []byte) { + h := Hashit(int32(TimeValue), xCID) + y := fromBytes(h) + q := NewBIGints(CURVE_Order) + y.mod(q) + y.toBytes(Y) +} + +/* One pass MPIN Client */ +func MPIN_CLIENT(date int, CLIENT_ID []byte, RNG *RAND, X []byte, pin int, TOKEN []byte, SEC []byte, xID []byte, xCID []byte, PERMIT []byte, MESSAGE []byte, TimeValue int, Y []byte) int { + rtn := 0 + + var M []byte + if date == 0 { + M = xID + } else { + M = xCID + } + + rtn = MPIN_CLIENT_1(date, CLIENT_ID, RNG, X, pin, TOKEN, SEC, xID, xCID, PERMIT) + if rtn != 0 { + return rtn + } + + if MESSAGE != nil { + M = append(M, MESSAGE...) + } + + MPIN_GET_Y(TimeValue, M, Y) + + rtn = MPIN_CLIENT_2(X, Y, SEC) + if rtn != 0 { + return rtn + } + + return 0 +} + +/* One pass MPIN Server */ +func MPIN_SERVER(date int, HID []byte, HTID []byte, Y []byte, SST []byte, xID []byte, xCID []byte, SEC []byte, E []byte, F []byte, CID []byte, MESSAGE []byte, TimeValue int) int { + rtn := 0 + + var M []byte + if date == 0 { + M = xID + } else { + M = xCID + } + + MPIN_SERVER_1(date, CID, HID, HTID) + + if MESSAGE != nil { + M = append(M, MESSAGE...) + } + + MPIN_GET_Y(TimeValue, M, Y) + + rtn = MPIN_SERVER_2(date, HID, HTID, Y, SST, xID, xCID, SEC, E, F) + if rtn != 0 { + return rtn + } + + return 0 +} + +func MPIN_printBinary(array []byte) { + for i := 0; i < len(array); i++ { + fmt.Printf("%02x", array[i]) + } + fmt.Printf("\n") +} http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/85fabaa6/go/amcl-go/MPIN_test.go ---------------------------------------------------------------------- diff --git a/go/amcl-go/MPIN_test.go b/go/amcl-go/MPIN_test.go new file mode 100644 index 0000000..f489bea --- /dev/null +++ b/go/amcl-go/MPIN_test.go @@ -0,0 +1,898 @@ +/* +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. +*/ + +package amcl + +import ( + "crypto/rand" + "encoding/hex" + "fmt" + "testing" +) + +func TestGoodPIN(t *testing.T) { + want := 0 + // Assign the End-User an ID + IDstr := "[email protected]" + ID := []byte(IDstr) + + // Epoch time in days + date := 16660 + + // Epoch time in seconds + timeValue := 1439465203 + + // PIN variable to create token + PIN1 := 1234 + // PIN variable to authenticate + PIN2 := 1234 + + // Seed value for Random Number Generator (RNG) + seedHex := "9e8b4178790cd57a5761c4a6f164ba72" + seed, err := hex.DecodeString(seedHex) + if err != nil { + fmt.Println("Error decoding seed value") + return + } + rng := NewRAND() + rng.Seed(len(seed), seed) + + // Message to sign + var MESSAGE []byte + // MESSAGE := []byte("test sign message") + + const EGS = MPIN_EGS + const EFS = MPIN_EFS + const G1S = 2*EFS + 1 /* Group 1 Size */ + const G2S = 4 * EFS /* Group 2 Size */ + const EAS = MPIN_PAS + + var MS1 [EGS]byte + var SS1 [G2S]byte + var CS1 [G1S]byte + var TP1 [G1S]byte + var MS2 [EGS]byte + var SS2 [G2S]byte + var CS2 [G1S]byte + var TP2 [G1S]byte + var SS [G2S]byte + var TP [G1S]byte + var TOKEN [G1S]byte + var SEC [G1S]byte + var U [G1S]byte + var UT [G1S]byte + var X [EGS]byte + var Y [EGS]byte + var E [12 * EFS]byte + var F [12 * EFS]byte + var HID [G1S]byte + var HTID [G1S]byte + + // Generate Master Secret Share 1 + MPIN_RANDOM_GENERATE(rng, MS1[:]) + + // Generate Master Secret Share 2 + MPIN_RANDOM_GENERATE(rng, MS2[:]) + + // Either Client or TA calculates Hash(ID) + HCID := MPIN_HASH_ID(ID) + + // Generate server secret share 1 + MPIN_GET_SERVER_SECRET(MS1[:], SS1[:]) + + // Generate server secret share 2 + MPIN_GET_SERVER_SECRET(MS2[:], SS2[:]) + + // Combine server secret shares + MPIN_RECOMBINE_G2(SS1[:], SS2[:], SS[:]) + + // Generate client secret share 1 + MPIN_GET_CLIENT_SECRET(MS1[:], HCID, CS1[:]) + + // Generate client secret share 2 + MPIN_GET_CLIENT_SECRET(MS2[:], HCID, CS2[:]) + + // Combine client secret shares : TOKEN is the full client secret + MPIN_RECOMBINE_G1(CS1[:], CS2[:], TOKEN[:]) + + // Generate time permit share 1 + MPIN_GET_CLIENT_PERMIT(date, MS1[:], HCID, TP1[:]) + + // Generate time permit share 2 + MPIN_GET_CLIENT_PERMIT(date, MS2[:], HCID, TP2[:]) + + // Combine time permit shares + MPIN_RECOMBINE_G1(TP1[:], TP2[:], TP[:]) + + // Create token + MPIN_EXTRACT_PIN(ID, PIN1, TOKEN[:]) + + // Authenticate + MPIN_CLIENT(date, ID, rng, X[:], PIN2, TOKEN[:], SEC[:], U[:], UT[:], TP[:], MESSAGE, timeValue, Y[:]) + + got := MPIN_SERVER(date, HID[:], HTID[:], Y[:], SS[:], U[:], UT[:], SEC[:], E[:], F[:], ID, MESSAGE, timeValue) + if got != want { + t.Errorf("MPIN GOOD PIN %d != %d", want, got) + } +} + +func TestBadPIN(t *testing.T) { + want := -19 + // Assign the End-User an ID + IDstr := "[email protected]" + ID := []byte(IDstr) + + // Epoch time in days + date := 16660 + + // Epoch time in seconds + timeValue := 1439465203 + + // PIN variable to create token + PIN1 := 1234 + // PIN variable to authenticate + PIN2 := 1235 + + // Seed value for Random Number Generator (RNG) + seedHex := "9e8b4178790cd57a5761c4a6f164ba72" + seed, err := hex.DecodeString(seedHex) + if err != nil { + fmt.Println("Error decoding seed value") + return + } + rng := NewRAND() + rng.Seed(len(seed), seed) + + // Message to sign + var MESSAGE []byte + // MESSAGE := []byte("test sign message") + + const EGS = MPIN_EGS + const EFS = MPIN_EFS + const G1S = 2*EFS + 1 /* Group 1 Size */ + const G2S = 4 * EFS /* Group 2 Size */ + const EAS = MPIN_PAS + + var MS1 [EGS]byte + var SS1 [G2S]byte + var CS1 [G1S]byte + var TP1 [G1S]byte + var MS2 [EGS]byte + var SS2 [G2S]byte + var CS2 [G1S]byte + var TP2 [G1S]byte + var SS [G2S]byte + var TP [G1S]byte + var TOKEN [G1S]byte + var SEC [G1S]byte + var U [G1S]byte + var UT [G1S]byte + var X [EGS]byte + var Y [EGS]byte + var E [12 * EFS]byte + var F [12 * EFS]byte + var HID [G1S]byte + var HTID [G1S]byte + + // Generate Master Secret Share 1 + MPIN_RANDOM_GENERATE(rng, MS1[:]) + + // Generate Master Secret Share 2 + MPIN_RANDOM_GENERATE(rng, MS2[:]) + + // Either Client or TA calculates Hash(ID) + HCID := MPIN_HASH_ID(ID) + + // Generate server secret share 1 + MPIN_GET_SERVER_SECRET(MS1[:], SS1[:]) + + // Generate server secret share 2 + MPIN_GET_SERVER_SECRET(MS2[:], SS2[:]) + + // Combine server secret shares + MPIN_RECOMBINE_G2(SS1[:], SS2[:], SS[:]) + + // Generate client secret share 1 + MPIN_GET_CLIENT_SECRET(MS1[:], HCID, CS1[:]) + + // Generate client secret share 2 + MPIN_GET_CLIENT_SECRET(MS2[:], HCID, CS2[:]) + + // Combine client secret shares : TOKEN is the full client secret + MPIN_RECOMBINE_G1(CS1[:], CS2[:], TOKEN[:]) + + // Generate time permit share 1 + MPIN_GET_CLIENT_PERMIT(date, MS1[:], HCID, TP1[:]) + + // Generate time permit share 2 + MPIN_GET_CLIENT_PERMIT(date, MS2[:], HCID, TP2[:]) + + // Combine time permit shares + MPIN_RECOMBINE_G1(TP1[:], TP2[:], TP[:]) + + // Create token + MPIN_EXTRACT_PIN(ID, PIN1, TOKEN[:]) + + // Authenticate + MPIN_CLIENT(date, ID, rng, X[:], PIN2, TOKEN[:], SEC[:], U[:], UT[:], TP[:], MESSAGE, timeValue, Y[:]) + + got := MPIN_SERVER(date, HID[:], HTID[:], Y[:], SS[:], U[:], UT[:], SEC[:], E[:], F[:], ID, MESSAGE, timeValue) + if got != want { + t.Errorf("TestBadPIN %d != %d", want, got) + } +} + +func TestBadToken(t *testing.T) { + want := -19 + // Assign the End-User an ID + IDstr := "[email protected]" + ID := []byte(IDstr) + + // Epoch time in days + date := 16660 + + // Epoch time in seconds + timeValue := 1439465203 + + // PIN variable to create token + PIN1 := 1234 + // PIN variable to authenticate + PIN2 := 1234 + + // Seed value for Random Number Generator (RNG) + seedHex := "9e8b4178790cd57a5761c4a6f164ba72" + seed, err := hex.DecodeString(seedHex) + if err != nil { + fmt.Println("Error decoding seed value") + return + } + rng := NewRAND() + rng.Seed(len(seed), seed) + + // Message to sign + var MESSAGE []byte + // MESSAGE := []byte("test sign message") + + const EGS = MPIN_EGS + const EFS = MPIN_EFS + const G1S = 2*EFS + 1 /* Group 1 Size */ + const G2S = 4 * EFS /* Group 2 Size */ + const EAS = MPIN_PAS + + var MS1 [EGS]byte + var SS1 [G2S]byte + var CS1 [G1S]byte + var TP1 [G1S]byte + var MS2 [EGS]byte + var SS2 [G2S]byte + var CS2 [G1S]byte + var TP2 [G1S]byte + var SS [G2S]byte + var TP [G1S]byte + var TOKEN [G1S]byte + var SEC [G1S]byte + var U [G1S]byte + var UT [G1S]byte + var X [EGS]byte + var Y [EGS]byte + var E [12 * EFS]byte + var F [12 * EFS]byte + var HID [G1S]byte + var HTID [G1S]byte + + // Generate Master Secret Share 1 + MPIN_RANDOM_GENERATE(rng, MS1[:]) + + // Generate Master Secret Share 2 + MPIN_RANDOM_GENERATE(rng, MS2[:]) + + // Either Client or TA calculates Hash(ID) + HCID := MPIN_HASH_ID(ID) + + // Generate server secret share 1 + MPIN_GET_SERVER_SECRET(MS1[:], SS1[:]) + + // Generate server secret share 2 + MPIN_GET_SERVER_SECRET(MS2[:], SS2[:]) + + // Combine server secret shares + MPIN_RECOMBINE_G2(SS1[:], SS2[:], SS[:]) + + // Generate client secret share 1 + MPIN_GET_CLIENT_SECRET(MS1[:], HCID, CS1[:]) + + // Generate client secret share 2 + MPIN_GET_CLIENT_SECRET(MS2[:], HCID, CS2[:]) + + // Combine client secret shares : TOKEN is the full client secret + MPIN_RECOMBINE_G1(CS1[:], CS2[:], TOKEN[:]) + + // Generate time permit share 1 + MPIN_GET_CLIENT_PERMIT(date, MS1[:], HCID, TP1[:]) + + // Generate time permit share 2 + MPIN_GET_CLIENT_PERMIT(date, MS2[:], HCID, TP2[:]) + + // Combine time permit shares + MPIN_RECOMBINE_G1(TP1[:], TP2[:], TP[:]) + + // Create token + MPIN_EXTRACT_PIN(ID, PIN1, TOKEN[:]) + + // Authenticate + MPIN_CLIENT(date, ID, rng, X[:], PIN2, TOKEN[:], SEC[:], U[:], UT[:], TP[:], MESSAGE, timeValue, Y[:]) + + // Send UT as V to model bad token + got := MPIN_SERVER(date, HID[:], HTID[:], Y[:], SS[:], U[:], UT[:], UT[:], E[:], F[:], ID, MESSAGE, timeValue) + if got != want { + t.Errorf("TestBadToken %d != %d", want, got) + } +} + +func TestRandom(t *testing.T) { + want := 0 + // Assign the End-User an ID + IDstr := "[email protected]" + ID := []byte(IDstr) + + // Epoch time in days + date := 16660 + + // Epoch time in seconds + timeValue := 1439465203 + + // PIN variable to create token + PIN1 := 1234 + // PIN variable to authenticate + PIN2 := 1234 + + // Seed value for Random Number Generator (RNG) + seed := make([]byte, 16) + rand.Read(seed) + rng := NewRAND() + rng.Seed(len(seed), seed) + + // Message to sign + var MESSAGE []byte + // MESSAGE := []byte("test sign message") + + const EGS = MPIN_EGS + const EFS = MPIN_EFS + const G1S = 2*EFS + 1 /* Group 1 Size */ + const G2S = 4 * EFS /* Group 2 Size */ + const EAS = MPIN_PAS + + var MS1 [EGS]byte + var SS1 [G2S]byte + var CS1 [G1S]byte + var TP1 [G1S]byte + var MS2 [EGS]byte + var SS2 [G2S]byte + var CS2 [G1S]byte + var TP2 [G1S]byte + var SS [G2S]byte + var TP [G1S]byte + var TOKEN [G1S]byte + var SEC [G1S]byte + var U [G1S]byte + var UT [G1S]byte + var X [EGS]byte + var Y [EGS]byte + var E [12 * EFS]byte + var F [12 * EFS]byte + var HID [G1S]byte + var HTID [G1S]byte + + // Generate Master Secret Share 1 + MPIN_RANDOM_GENERATE(rng, MS1[:]) + + // Generate Master Secret Share 2 + MPIN_RANDOM_GENERATE(rng, MS2[:]) + + // Either Client or TA calculates Hash(ID) + HCID := MPIN_HASH_ID(ID) + + // Generate server secret share 1 + MPIN_GET_SERVER_SECRET(MS1[:], SS1[:]) + + // Generate server secret share 2 + MPIN_GET_SERVER_SECRET(MS2[:], SS2[:]) + + // Combine server secret shares + MPIN_RECOMBINE_G2(SS1[:], SS2[:], SS[:]) + + // Generate client secret share 1 + MPIN_GET_CLIENT_SECRET(MS1[:], HCID, CS1[:]) + + // Generate client secret share 2 + MPIN_GET_CLIENT_SECRET(MS2[:], HCID, CS2[:]) + + // Combine client secret shares : TOKEN is the full client secret + MPIN_RECOMBINE_G1(CS1[:], CS2[:], TOKEN[:]) + + // Generate time permit share 1 + MPIN_GET_CLIENT_PERMIT(date, MS1[:], HCID, TP1[:]) + + // Generate time permit share 2 + MPIN_GET_CLIENT_PERMIT(date, MS2[:], HCID, TP2[:]) + + // Combine time permit shares + MPIN_RECOMBINE_G1(TP1[:], TP2[:], TP[:]) + + // Create token + MPIN_EXTRACT_PIN(ID, PIN1, TOKEN[:]) + + // Authenticate + MPIN_CLIENT(date, ID, rng, X[:], PIN2, TOKEN[:], SEC[:], U[:], UT[:], TP[:], MESSAGE, timeValue, Y[:]) + + got := MPIN_SERVER(date, HID[:], HTID[:], Y[:], SS[:], U[:], UT[:], SEC[:], E[:], F[:], ID, MESSAGE, timeValue) + if got != want { + t.Errorf("TestRandom %d != %d", want, got) + } +} + +func TestGoodSignature(t *testing.T) { + want := 0 + // Assign the End-User an ID + IDstr := "[email protected]" + ID := []byte(IDstr) + + // Message to sign + MESSAGE := []byte("test message to sign") + + // Epoch time in days + date := 16660 + + // Epoch time in seconds + timeValue := 1439465203 + + // PIN variable to create token + PIN1 := 1234 + // PIN variable to authenticate + PIN2 := 1234 + + // Seed value for Random Number Generator (RNG) + seedHex := "9e8b4178790cd57a5761c4a6f164ba72" + seed, err := hex.DecodeString(seedHex) + if err != nil { + fmt.Println("Error decoding seed value") + return + } + rng := NewRAND() + rng.Seed(len(seed), seed) + + const EGS = MPIN_EGS + const EFS = MPIN_EFS + const G1S = 2*EFS + 1 /* Group 1 Size */ + const G2S = 4 * EFS /* Group 2 Size */ + const EAS = MPIN_PAS + + var MS1 [EGS]byte + var SS1 [G2S]byte + var CS1 [G1S]byte + var TP1 [G1S]byte + var MS2 [EGS]byte + var SS2 [G2S]byte + var CS2 [G1S]byte + var TP2 [G1S]byte + var SS [G2S]byte + var TP [G1S]byte + var TOKEN [G1S]byte + var SEC [G1S]byte + var U [G1S]byte + var UT [G1S]byte + var X [EGS]byte + var Y [EGS]byte + var E [12 * EFS]byte + var F [12 * EFS]byte + var HID [G1S]byte + var HTID [G1S]byte + + // Generate Master Secret Share 1 + MPIN_RANDOM_GENERATE(rng, MS1[:]) + + // Generate Master Secret Share 2 + MPIN_RANDOM_GENERATE(rng, MS2[:]) + + // Either Client or TA calculates Hash(ID) + HCID := MPIN_HASH_ID(ID) + + // Generate server secret share 1 + MPIN_GET_SERVER_SECRET(MS1[:], SS1[:]) + + // Generate server secret share 2 + MPIN_GET_SERVER_SECRET(MS2[:], SS2[:]) + + // Combine server secret shares + MPIN_RECOMBINE_G2(SS1[:], SS2[:], SS[:]) + + // Generate client secret share 1 + MPIN_GET_CLIENT_SECRET(MS1[:], HCID, CS1[:]) + + // Generate client secret share 2 + MPIN_GET_CLIENT_SECRET(MS2[:], HCID, CS2[:]) + + // Combine client secret shares : TOKEN is the full client secret + MPIN_RECOMBINE_G1(CS1[:], CS2[:], TOKEN[:]) + + // Generate time permit share 1 + MPIN_GET_CLIENT_PERMIT(date, MS1[:], HCID, TP1[:]) + + // Generate time permit share 2 + MPIN_GET_CLIENT_PERMIT(date, MS2[:], HCID, TP2[:]) + + // Combine time permit shares + MPIN_RECOMBINE_G1(TP1[:], TP2[:], TP[:]) + + // Create token + MPIN_EXTRACT_PIN(ID, PIN1, TOKEN[:]) + + // Authenticate + MPIN_CLIENT(date, ID, rng, X[:], PIN2, TOKEN[:], SEC[:], U[:], UT[:], TP[:], MESSAGE, timeValue, Y[:]) + + got := MPIN_SERVER(date, HID[:], HTID[:], Y[:], SS[:], U[:], UT[:], SEC[:], E[:], F[:], ID, MESSAGE, timeValue) + if got != want { + t.Errorf("TestGoodSignature %d != %d", want, got) + } +} + +func TestSignatureExpired(t *testing.T) { + want := -19 + // Assign the End-User an ID + IDstr := "[email protected]" + ID := []byte(IDstr) + + // Epoch time in days + date := 16660 + + // Epoch time in seconds + timeValue := 1439465203 + + // PIN variable to create token + PIN1 := 1234 + // PIN variable to authenticate + PIN2 := 1234 + + // Seed value for Random Number Generator (RNG) + seedHex := "9e8b4178790cd57a5761c4a6f164ba72" + seed, err := hex.DecodeString(seedHex) + if err != nil { + fmt.Println("Error decoding seed value") + return + } + rng := NewRAND() + rng.Seed(len(seed), seed) + + // Message to sign + MESSAGE := []byte("test message to sign") + + const EGS = MPIN_EGS + const EFS = MPIN_EFS + const G1S = 2*EFS + 1 /* Group 1 Size */ + const G2S = 4 * EFS /* Group 2 Size */ + const EAS = MPIN_PAS + + var MS1 [EGS]byte + var SS1 [G2S]byte + var CS1 [G1S]byte + var TP1 [G1S]byte + var MS2 [EGS]byte + var SS2 [G2S]byte + var CS2 [G1S]byte + var TP2 [G1S]byte + var SS [G2S]byte + var TP [G1S]byte + var TOKEN [G1S]byte + var SEC [G1S]byte + var U [G1S]byte + var UT [G1S]byte + var X [EGS]byte + var Y [EGS]byte + var E [12 * EFS]byte + var F [12 * EFS]byte + var HID [G1S]byte + var HTID [G1S]byte + + // Generate Master Secret Share 1 + MPIN_RANDOM_GENERATE(rng, MS1[:]) + + // Generate Master Secret Share 2 + MPIN_RANDOM_GENERATE(rng, MS2[:]) + + // Either Client or TA calculates Hash(ID) + HCID := MPIN_HASH_ID(ID) + + // Generate server secret share 1 + MPIN_GET_SERVER_SECRET(MS1[:], SS1[:]) + + // Generate server secret share 2 + MPIN_GET_SERVER_SECRET(MS2[:], SS2[:]) + + // Combine server secret shares + MPIN_RECOMBINE_G2(SS1[:], SS2[:], SS[:]) + + // Generate client secret share 1 + MPIN_GET_CLIENT_SECRET(MS1[:], HCID, CS1[:]) + + // Generate client secret share 2 + MPIN_GET_CLIENT_SECRET(MS2[:], HCID, CS2[:]) + + // Combine client secret shares : TOKEN is the full client secret + MPIN_RECOMBINE_G1(CS1[:], CS2[:], TOKEN[:]) + + // Generate time permit share 1 + MPIN_GET_CLIENT_PERMIT(date, MS1[:], HCID, TP1[:]) + + // Generate time permit share 2 + MPIN_GET_CLIENT_PERMIT(date, MS2[:], HCID, TP2[:]) + + // Combine time permit shares + MPIN_RECOMBINE_G1(TP1[:], TP2[:], TP[:]) + + // Create token + MPIN_EXTRACT_PIN(ID, PIN1, TOKEN[:]) + + // Authenticate + MPIN_CLIENT(date, ID, rng, X[:], PIN2, TOKEN[:], SEC[:], U[:], UT[:], TP[:], MESSAGE, timeValue, Y[:]) + + timeValue += 10 + got := MPIN_SERVER(date, HID[:], HTID[:], Y[:], SS[:], U[:], UT[:], SEC[:], E[:], F[:], ID, MESSAGE, timeValue) + if got != want { + t.Errorf("TestSignatureExpired %d != %d", want, got) + } +} + +func TestBadSignature(t *testing.T) { + want := -19 + // Assign the End-User an ID + IDstr := "[email protected]" + ID := []byte(IDstr) + + // Epoch time in days + date := 16660 + + // Epoch time in seconds + timeValue := 1439465203 + + // PIN variable to create token + PIN1 := 1234 + // PIN variable to authenticate + PIN2 := 1234 + + // Seed value for Random Number Generator (RNG) + seedHex := "9e8b4178790cd57a5761c4a6f164ba72" + seed, err := hex.DecodeString(seedHex) + if err != nil { + fmt.Println("Error decoding seed value") + return + } + rng := NewRAND() + rng.Seed(len(seed), seed) + + // Message to sign + MESSAGE := []byte("test message to sign") + + const EGS = MPIN_EGS + const EFS = MPIN_EFS + const G1S = 2*EFS + 1 /* Group 1 Size */ + const G2S = 4 * EFS /* Group 2 Size */ + const EAS = MPIN_PAS + + var MS1 [EGS]byte + var SS1 [G2S]byte + var CS1 [G1S]byte + var TP1 [G1S]byte + var MS2 [EGS]byte + var SS2 [G2S]byte + var CS2 [G1S]byte + var TP2 [G1S]byte + var SS [G2S]byte + var TP [G1S]byte + var TOKEN [G1S]byte + var SEC [G1S]byte + var U [G1S]byte + var UT [G1S]byte + var X [EGS]byte + var Y [EGS]byte + var E [12 * EFS]byte + var F [12 * EFS]byte + var HID [G1S]byte + var HTID [G1S]byte + + // Generate Master Secret Share 1 + MPIN_RANDOM_GENERATE(rng, MS1[:]) + + // Generate Master Secret Share 2 + MPIN_RANDOM_GENERATE(rng, MS2[:]) + + // Either Client or TA calculates Hash(ID) + HCID := MPIN_HASH_ID(ID) + + // Generate server secret share 1 + MPIN_GET_SERVER_SECRET(MS1[:], SS1[:]) + + // Generate server secret share 2 + MPIN_GET_SERVER_SECRET(MS2[:], SS2[:]) + + // Combine server secret shares + MPIN_RECOMBINE_G2(SS1[:], SS2[:], SS[:]) + + // Generate client secret share 1 + MPIN_GET_CLIENT_SECRET(MS1[:], HCID, CS1[:]) + + // Generate client secret share 2 + MPIN_GET_CLIENT_SECRET(MS2[:], HCID, CS2[:]) + + // Combine client secret shares : TOKEN is the full client secret + MPIN_RECOMBINE_G1(CS1[:], CS2[:], TOKEN[:]) + + // Generate time permit share 1 + MPIN_GET_CLIENT_PERMIT(date, MS1[:], HCID, TP1[:]) + + // Generate time permit share 2 + MPIN_GET_CLIENT_PERMIT(date, MS2[:], HCID, TP2[:]) + + // Combine time permit shares + MPIN_RECOMBINE_G1(TP1[:], TP2[:], TP[:]) + + // Create token + MPIN_EXTRACT_PIN(ID, PIN1, TOKEN[:]) + + // Authenticate + MPIN_CLIENT(date, ID, rng, X[:], PIN2, TOKEN[:], SEC[:], U[:], UT[:], TP[:], MESSAGE, timeValue, Y[:]) + + MESSAGE[0] = 00 + got := MPIN_SERVER(date, HID[:], HTID[:], Y[:], SS[:], U[:], UT[:], SEC[:], E[:], F[:], ID, MESSAGE, timeValue) + if got != want { + t.Errorf("TestBadSignature %d != %d", want, got) + } +} + +func TestMPINFull(t *testing.T) { + want := "0afc948b03b2733a0663571f86411a07" + // Assign the End-User an ID + IDstr := "[email protected]" + ID := []byte(IDstr) + + // Epoch time in days + date := 16660 + + // Epoch time in seconds + timeValue := 1439465203 + + // PIN variable to create token + PIN1 := 1234 + // PIN variable to authenticate + PIN2 := 1234 + + // Seed value for Random Number Generator (RNG) + seedHex := "9e8b4178790cd57a5761c4a6f164ba72" + seed, err := hex.DecodeString(seedHex) + if err != nil { + fmt.Println("Error decoding seed value") + return + } + rng := NewRAND() + rng.Seed(len(seed), seed) + + // Message to sign + var MESSAGE []byte + // MESSAGE := []byte("test sign message") + + const EGS = MPIN_EGS + const EFS = MPIN_EFS + const G1S = 2*EFS + 1 /* Group 1 Size */ + const G2S = 4 * EFS /* Group 2 Size */ + const EAS = MPIN_PAS + + var MS1 [EGS]byte + var SS1 [G2S]byte + var CS1 [G1S]byte + var TP1 [G1S]byte + var MS2 [EGS]byte + var SS2 [G2S]byte + var CS2 [G1S]byte + var TP2 [G1S]byte + var SS [G2S]byte + var TP [G1S]byte + var TOKEN [G1S]byte + var SEC [G1S]byte + var U [G1S]byte + var UT [G1S]byte + var X [EGS]byte + var Y [EGS]byte + var E [12 * EFS]byte + var F [12 * EFS]byte + var HID [G1S]byte + var HTID [G1S]byte + + var G1 [12 * EFS]byte + var G2 [12 * EFS]byte + var R [EGS]byte + var Z [G1S]byte + var W [EGS]byte + var T [G1S]byte + var AES_KEY_CLIENT [EAS]byte + var AES_KEY_SERVER [EAS]byte + + // Generate Master Secret Share 1 + MPIN_RANDOM_GENERATE(rng, MS1[:]) + + // Generate Master Secret Share 2 + MPIN_RANDOM_GENERATE(rng, MS2[:]) + + // Either Client or TA calculates Hash(ID) + HCID := MPIN_HASH_ID(ID) + + // Generate server secret share 1 + MPIN_GET_SERVER_SECRET(MS1[:], SS1[:]) + + // Generate server secret share 2 + MPIN_GET_SERVER_SECRET(MS2[:], SS2[:]) + + // Combine server secret shares + MPIN_RECOMBINE_G2(SS1[:], SS2[:], SS[:]) + + // Generate client secret share 1 + MPIN_GET_CLIENT_SECRET(MS1[:], HCID, CS1[:]) + + // Generate client secret share 2 + MPIN_GET_CLIENT_SECRET(MS2[:], HCID, CS2[:]) + + // Combine client secret shares : TOKEN is the full client secret + MPIN_RECOMBINE_G1(CS1[:], CS2[:], TOKEN[:]) + + // Generate time permit share 1 + MPIN_GET_CLIENT_PERMIT(date, MS1[:], HCID, TP1[:]) + + // Generate time permit share 2 + MPIN_GET_CLIENT_PERMIT(date, MS2[:], HCID, TP2[:]) + + // Combine time permit shares + MPIN_RECOMBINE_G1(TP1[:], TP2[:], TP[:]) + + // Create token + MPIN_EXTRACT_PIN(ID, PIN1, TOKEN[:]) + + // precomputation + MPIN_PRECOMPUTE(TOKEN[:], HCID, G1[:], G2[:]) + + // Authenticate + MPIN_CLIENT(date, ID, rng, X[:], PIN2, TOKEN[:], SEC[:], U[:], UT[:], TP[:], MESSAGE, timeValue, Y[:]) + + // Send Z=r.ID to Server + MPIN_GET_G1_MULTIPLE(rng, 1, R[:], HCID, Z[:]) + + MPIN_SERVER(date, HID[:], HTID[:], Y[:], SS[:], U[:], UT[:], SEC[:], E[:], F[:], ID, MESSAGE, timeValue) + + // send T=w.ID to client + MPIN_GET_G1_MULTIPLE(rng, 0, W[:], HTID[:], T[:]) + + MPIN_SERVER_KEY(Z[:], SS[:], W[:], U[:], UT[:], AES_KEY_SERVER[:]) + got := hex.EncodeToString(AES_KEY_SERVER[:]) + if got != want { + t.Errorf("TestMPINFull %s != %s", want, got) + } + + MPIN_CLIENT_KEY(G1[:], G2[:], PIN2, R[:], X[:], T[:], AES_KEY_CLIENT[:]) + got = hex.EncodeToString(AES_KEY_CLIENT[:]) + if got != want { + t.Errorf("TestMPINFull %s != %s", want, got) + } +}
