http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/go/MPIN.go ---------------------------------------------------------------------- diff --git a/version22/go/MPIN.go b/version22/go/MPIN.go new file mode 100644 index 0000000..43b5f32 --- /dev/null +++ b/version22/go/MPIN.go @@ -0,0 +1,769 @@ +/* +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 main + +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 +const MPIN_SHA256 int=32 +const MPIN_SHA384 int=48 +const MPIN_SHA512 int=64 + +/* 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) */ + +const MPIN_HASH_TYPE int=MPIN_SHA256 + +func mpin_hash(sha int,c *FP4,U *ECP) []byte { + var w [MPIN_EFS]byte + var t [6*MPIN_EFS]byte + var h []byte + + c.geta().getA().toBytes(w[:]); for i:=0;i<MPIN_EFS;i++ {t[i]=w[i]} + c.geta().getB().toBytes(w[:]); for i:=MPIN_EFS;i<2*MPIN_EFS;i++ {t[i]=w[i-MPIN_EFS]} + c.getb().getA().toBytes(w[:]); for i:=2*MPIN_EFS;i<3*MPIN_EFS;i++ {t[i]=w[i-2*MPIN_EFS]} + c.getb().getB().toBytes(w[:]); for i:=3*MPIN_EFS;i<4*MPIN_EFS;i++ {t[i]=w[i-3*MPIN_EFS]} + + U.getX().toBytes(w[:]); for i:=4*MPIN_EFS;i<5*MPIN_EFS;i++ {t[i]=w[i-4*MPIN_EFS]} + U.getY().toBytes(w[:]); for i:=5*MPIN_EFS;i<6*MPIN_EFS;i++ {t[i]=w[i-5*MPIN_EFS]} + + if sha==MPIN_SHA256 { + H:=NewHASH256() + H.Process_array(t[:]) + h=H.Hash() + } + if sha==MPIN_SHA384 { + H:=NewHASH384() + H.Process_array(t[:]) + h=H.Hash() + } + if sha==MPIN_SHA512 { + H:=NewHASH512() + H.Process_array(t[:]) + h=H.Hash() + } + if h==nil {return nil} + R:=make([]byte,MPIN_PAS) + for i:=0;i<MPIN_PAS;i++ {R[i]=h[i]} + return R +} + +/* Hash number (optional) and string to coordinate on curve */ + +func mhashit(sha int,n int32,ID []byte) []byte { + var R []byte + if sha==MPIN_SHA256 { + H:=NewHASH256() + if n!=0 {H.Process_num(n)} + H.Process_array(ID) + R=H.Hash() + } + if sha==MPIN_SHA384 { + H:=NewHASH384() + if n!=0 {H.Process_num(n)} + H.Process_array(ID) + R=H.Hash() + } + if sha==MPIN_SHA512 { + H:=NewHASH512() + if n!=0 {H.Process_num(n)} + H.Process_array(ID) + R=H.Hash() + } + if R==nil {return nil} + const RM int=int(MODBYTES) + var W [RM]byte + if sha>RM { + for i:=0;i<RM;i++ {W[i]=R[i]} + } else { + for i:=0;i<sha;i++ {W[i]=R[i]} + for i:=sha;i<RM;i++ {W[i]=0} + } + + return W[:] +} + +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() + } + if CURVE_PAIRING_TYPE!=BN_CURVE { + c:=NewBIGints(CURVE_Cof) + P=P.mul(c) + } + 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(sha int,ID []byte) []byte { + return mhashit(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 */ +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()); /*if (su<0) su=-su;*/ su%=2 + + W:=emap(u,su) + P.sub(W) + sv:=P.getS() + rn:=unmap(v,P) + m:=int(rng.GetByte()); /*if (m<0) m=-m;*/ 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) + if AES_S>0 { + s.mod2m(2*AES_S) + } + s.toBytes(S) + return 0 +} + +/* Extract PIN from TOKEN for identity CID */ +func MPIN_EXTRACT_PIN(sha int,CID []byte,pin int,TOKEN []byte) int { + P:=ECP_fromBytes(TOKEN) + if P.is_infinity() {return MPIN_INVALID_POINT} + h:=mhashit(sha,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) + + P=G1mul(P,px) + P.neg() + P.toBytes(SEC) + //G1mul(P,px).toBytes(SEC) + return 0 +} + +/* Implement step 1 on client side of MPin protocol */ +func MPIN_CLIENT_1(sha int,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) + if AES_S>0 { + x.mod2m(2*AES_S) + } + x.toBytes(X) + } else { + x=fromBytes(X) + } + + h:=mhashit(sha,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=mhashit(sha,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) + if AES_S>0 { + x.mod2m(2*AES_S) + } + 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(sha,date int,S []byte,CID []byte,CTT []byte) int { + h:=mhashit(sha,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(sha int,date int,CID []byte,HID []byte,HTID []byte) { + h:=mhashit(sha,0,CID) + P:=mapit(h) + + P.toBytes(HID); + if date!=0 { + // if HID!=nil {P.toBytes(HID)} + h=mhashit(sha,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(20)%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(20)%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 +} + +/* Hash the M-Pin transcript - new */ + +func MPIN_HASH_ALL(sha int,HID []byte,xID []byte,xCID []byte,SEC []byte,Y []byte,R []byte,W []byte) []byte { + tlen:=0 + var T [10*int(MODBYTES)+4]byte + + for i:=0;i<len(HID);i++ {T[i]=HID[i]} + tlen+=len(HID) + if xCID!=nil { + for i:=0;i<len(xCID);i++ {T[i+tlen]=xCID[i]} + tlen+=len(xCID) + } else { + for i:=0;i<len(xID);i++ {T[i+tlen]=xID[i]} + tlen+=len(xID) + } + for i:=0;i<len(SEC);i++ {T[i+tlen]=SEC[i]} + tlen+=len(SEC) + for i:=0;i<len(Y);i++ {T[i+tlen]=Y[i]} + tlen+=len(Y) + for i:=0;i<len(R);i++ {T[i+tlen]=R[i]} + tlen+=len(R) + for i:=0;i<len(W);i++ {T[i+tlen]=W[i]} + tlen+=len(W) + + return mhashit(sha,0,T[:]) +} + +/* calculate common key on client side */ +/* wCID = w.(A+AT) */ +func MPIN_CLIENT_KEY(sha int,G1 []byte,G2 []byte,pin int,R []byte,X []byte,H []byte,wCID []byte,CK []byte) int { + + g1:=FP12_fromBytes(G1) + g2:=FP12_fromBytes(G2) + z:=fromBytes(R) + x:=fromBytes(X) + h:=fromBytes(H) + + 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) + + z.add(h); //new + z.mod(r); + + 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) + + t:=mpin_hash(sha,c,W); + + 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(sha int,Z []byte,SST []byte,W []byte,H []byte,HID []byte,xID []byte,xCID []byte,SK []byte) int { + sQ:=ECP2_fromBytes(SST) + if sQ.is_infinity() {return MPIN_INVALID_POINT} + R:=ECP_fromBytes(Z) + if R.is_infinity() {return MPIN_INVALID_POINT} + A:=ECP_fromBytes(HID) + if A.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) + h:=fromBytes(H) + A=G1mul(A,h) // new + R.add(A) + + U=G1mul(U,w) + g:=ate(sQ,R) + g=fexp(g) + + c:=g.trace() + + t:=mpin_hash(sha,c,U) + + 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(sha int,TimeValue int,xCID []byte,Y []byte) { + h:= mhashit(sha,int32(TimeValue),xCID) + y:= fromBytes(h) + q:=NewBIGints(CURVE_Order) + y.mod(q) + if AES_S>0 { + y.mod2m(2*AES_S) + } + y.toBytes(Y) +} + +/* One pass MPIN Client */ +func MPIN_CLIENT(sha int,date int,CLIENT_ID []byte,RNG *RAND,X []byte,pin int,TOKEN []byte,SEC []byte,xID []byte,xCID []byte,PERMIT []byte,TimeValue int,Y []byte) int { + rtn:=0 + + var pID []byte + if date == 0 { + pID = xID + } else {pID = xCID} + + rtn = MPIN_CLIENT_1(sha,date,CLIENT_ID,RNG,X,pin,TOKEN,SEC,xID,xCID,PERMIT) + if rtn != 0 {return rtn} + + MPIN_GET_Y(sha,TimeValue,pID,Y) + + rtn = MPIN_CLIENT_2(X,Y,SEC) + if rtn != 0 {return rtn} + + return 0 +} + +/* One pass MPIN Server */ +func MPIN_SERVER(sha int,date int,HID []byte,HTID []byte,Y []byte,SST []byte,xID []byte,xCID []byte,SEC []byte,E []byte,F []byte,CID []byte,TimeValue int) int { + rtn:=0 + + var pID []byte + if date == 0 { + pID = xID + } else {pID = xCID} + + MPIN_SERVER_1(sha,date,CID,HID,HTID) + MPIN_GET_Y(sha,TimeValue,pID,Y); + + rtn = MPIN_SERVER_2(date,HID,HTID,Y,SST,xID,xCID,SEC,E,F) + if rtn != 0 {return rtn} + + return 0 +} +
http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/go/PAIR.go ---------------------------------------------------------------------- diff --git a/version22/go/PAIR.go b/version22/go/PAIR.go new file mode 100644 index 0000000..89c80ce --- /dev/null +++ b/version22/go/PAIR.go @@ -0,0 +1,641 @@ +/* +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. +*/ + +/* MiotCL BN Curve Pairing functions */ + +package main + +//import "fmt" + +/* Line function */ +func line(A *ECP2,B *ECP2,Qx *FP,Qy *FP) *FP12 { + P:=NewECP2() + + P.copy(A); + ZZ:=NewFP2copy(P.getz()) + ZZ.sqr() + var D int + if A==B { + D=A.dbl() + } else {D=A.add(B)} + + if D<0 {return NewFP12int(1)} + + Z3:=NewFP2copy(A.getz()) + + var a *FP4 + var b *FP4 + c:=NewFP4int(0) + + if (D==0) { /* Addition */ + X:=NewFP2copy(B.getx()) + Y:=NewFP2copy(B.gety()) + T:=NewFP2copy(P.getz()) + T.mul(Y) + ZZ.mul(T) + + NY:=NewFP2copy(P.gety()); NY.neg() + ZZ.add(NY) + Z3.pmul(Qy) + T.mul(P.getx()); + X.mul(NY); + T.add(X); + a=NewFP4fp2s(Z3,T) + ZZ.neg(); + ZZ.pmul(Qx) + b=NewFP4fp2(ZZ) + } else { /* Doubling */ + X:=NewFP2copy(P.getx()) + Y:=NewFP2copy(P.gety()) + T:=NewFP2copy(P.getx()) + T.sqr() + T.imul(3) + + Y.sqr() + Y.add(Y) + Z3.mul(ZZ) + Z3.pmul(Qy) + + X.mul(T) + X.sub(Y) + a=NewFP4fp2s(Z3,X) + T.neg() + ZZ.mul(T) + ZZ.pmul(Qx) + b=NewFP4fp2(ZZ) + } + return NewFP12fp4s(a,b,c) +} + +/* Optimal R-ate pairing */ +func ate(P *ECP2,Q *ECP) *FP12 { + f:=NewFP2bigs(NewBIGints(CURVE_Fra),NewBIGints(CURVE_Frb)) + x:=NewBIGints(CURVE_Bnx) + n:=NewBIGcopy(x) + K:=NewECP2() + var lv *FP12 + + if CURVE_PAIRING_TYPE == BN_CURVE { + n.pmul(6); n.dec(2) + } else {n.copy(x)} + + n.norm() + P.affine() + Q.affine() + Qx:=NewFPcopy(Q.getx()) + Qy:=NewFPcopy(Q.gety()) + + A:=NewECP2() + r:=NewFP12int(1) + + A.copy(P) + nb:=n.nbits() + + for i:=nb-2;i>=1;i-- { + lv=line(A,A,Qx,Qy) + r.smul(lv) + if n.bit(i)==1 { + + lv=line(A,P,Qx,Qy) + + r.smul(lv) + } + r.sqr() + } + + lv=line(A,A,Qx,Qy) + r.smul(lv) + + if n.parity()==1 { + lv=line(A,P,Qx,Qy) + r.smul(lv) + } + +/* R-ate fixup required for BN curves */ + + if CURVE_PAIRING_TYPE == BN_CURVE { + r.conj() + K.copy(P) + K.frob(f) + A.neg() + lv=line(A,K,Qx,Qy) + r.smul(lv) + K.frob(f) + K.neg() + lv=line(A,K,Qx,Qy) + r.smul(lv) + } + + return r +} + +/* Optimal R-ate double pairing e(P,Q).e(R,S) */ +func ate2(P *ECP2,Q *ECP,R *ECP2,S *ECP) *FP12 { + f:=NewFP2bigs(NewBIGints(CURVE_Fra),NewBIGints(CURVE_Frb)) + x:=NewBIGints(CURVE_Bnx) + n:=NewBIGcopy(x) + K:=NewECP2() + var lv *FP12 + + if CURVE_PAIRING_TYPE == BN_CURVE { + n.pmul(6); n.dec(2) + } else {n.copy(x)} + + n.norm() + P.affine() + Q.affine() + R.affine() + S.affine() + + Qx:=NewFPcopy(Q.getx()) + Qy:=NewFPcopy(Q.gety()) + Sx:=NewFPcopy(S.getx()) + Sy:=NewFPcopy(S.gety()) + + A:=NewECP2() + B:=NewECP2() + r:=NewFP12int(1) + + A.copy(P) + B.copy(R) + nb:=n.nbits() + + for i:=nb-2;i>=1;i-- { + lv=line(A,A,Qx,Qy) + r.smul(lv) + lv=line(B,B,Sx,Sy) + r.smul(lv) + + if n.bit(i)==1 { + lv=line(A,P,Qx,Qy) + r.smul(lv) + lv=line(B,R,Sx,Sy) + r.smul(lv) + } + r.sqr() + } + + lv=line(A,A,Qx,Qy) + r.smul(lv) + lv=line(B,B,Sx,Sy) + r.smul(lv) + if n.parity()==1 { + lv=line(A,P,Qx,Qy) + r.smul(lv) + lv=line(B,R,Sx,Sy) + r.smul(lv) + } + +/* R-ate fixup */ + if CURVE_PAIRING_TYPE == BN_CURVE { + r.conj() + K.copy(P) + K.frob(f) + A.neg() + lv=line(A,K,Qx,Qy) + r.smul(lv) + K.frob(f) + K.neg() + lv=line(A,K,Qx,Qy) + r.smul(lv) + + K.copy(R) + K.frob(f) + B.neg() + lv=line(B,K,Sx,Sy) + r.smul(lv) + K.frob(f) + K.neg() + lv=line(B,K,Sx,Sy) + r.smul(lv) + } + + return r +} + +/* final exponentiation - keep separate for multi-pairings and to avoid thrashing stack */ +func fexp(m *FP12) *FP12 { + f:=NewFP2bigs(NewBIGints(CURVE_Fra),NewBIGints(CURVE_Frb)) + x:=NewBIGints(CURVE_Bnx) + r:=NewFP12copy(m) + +/* Easy part of final exp */ + lv:=NewFP12copy(r) + lv.inverse() + r.conj() + + r.mul(lv) + lv.copy(r) + r.frob(f) + r.frob(f) + r.mul(lv) +/* Hard part of final exp */ + if CURVE_PAIRING_TYPE == BN_CURVE { + lv.copy(r) + lv.frob(f) + x0:=NewFP12copy(lv) + x0.frob(f) + lv.mul(r) + x0.mul(lv) + x0.frob(f) + x1:=NewFP12copy(r) + x1.conj() + x4:=r.pow(x) + + x3:=NewFP12copy(x4) + x3.frob(f) + + x2:=x4.pow(x) + + x5:=NewFP12copy(x2); x5.conj() + lv=x2.pow(x) + + x2.frob(f) + r.copy(x2); r.conj() + + x4.mul(r) + x2.frob(f) + + r.copy(lv) + r.frob(f) + lv.mul(r) + + lv.usqr() + lv.mul(x4) + lv.mul(x5) + r.copy(x3) + r.mul(x5) + r.mul(lv) + lv.mul(x2) + r.usqr() + r.mul(lv) + r.usqr() + lv.copy(r) + lv.mul(x1) + r.mul(x0) + lv.usqr() + r.mul(lv) + r.reduce() + } else { + +// Ghamman & Fouotsa Method + y0:=NewFP12copy(r); y0.usqr() + y1:=y0.pow(x) + x.fshr(1); y2:=y1.pow(x); x.fshl(1) + y3:=NewFP12copy(r); y3.conj() + y1.mul(y3) + + y1.conj() + y1.mul(y2) + + y2=y1.pow(x) + + y3=y2.pow(x) + y1.conj() + y3.mul(y1) + + y1.conj(); + y1.frob(f); y1.frob(f); y1.frob(f) + y2.frob(f); y2.frob(f) + y1.mul(y2) + + y2=y3.pow(x) + y2.mul(y0) + y2.mul(r) + + y1.mul(y2) + y2.copy(y3); y2.frob(f) + y1.mul(y2) + r.copy(y1) + r.reduce() + + +/* + x0:=NewFP12copy(r) + x1:=NewFP12copy(r) + lv.copy(r); lv.frob(f) + x3:=NewFP12copy(lv); x3.conj(); x1.mul(x3) + lv.frob(f); lv.frob(f) + x1.mul(lv) + + r.copy(r.pow(x)) //r=r.pow(x); + x3.copy(r); x3.conj(); x1.mul(x3) + lv.copy(r); lv.frob(f) + x0.mul(lv) + lv.frob(f) + x1.mul(lv) + lv.frob(f) + x3.copy(lv); x3.conj(); x0.mul(x3) + + r.copy(r.pow(x)) + x0.mul(r) + lv.copy(r); lv.frob(f); lv.frob(f) + x3.copy(lv); x3.conj(); x0.mul(x3) + lv.frob(f) + x1.mul(lv) + + r.copy(r.pow(x)) + lv.copy(r); lv.frob(f) + x3.copy(lv); x3.conj(); x0.mul(x3) + lv.frob(f) + x1.mul(lv) + + r.copy(r.pow(x)) + x3.copy(r); x3.conj(); x0.mul(x3) + lv.copy(r); lv.frob(f) + x1.mul(lv) + + r.copy(r.pow(x)) + x1.mul(r) + + x0.usqr() + x0.mul(x1) + r.copy(x0) + r.reduce() */ + } + return r +} + +/* GLV method */ +func glv(e *BIG) []*BIG { + var u []*BIG + if CURVE_PAIRING_TYPE == BN_CURVE { + t:=NewBIGint(0) + q:=NewBIGints(CURVE_Order) + var v []*BIG + + for i:=0;i<2;i++ { + t.copy(NewBIGints(CURVE_W[i])) // why not just t=new BIG(ROM.CURVE_W[i]); + d:=mul(t,e) + v=append(v,NewBIGcopy(d.div(q))) + u=append(u,NewBIGint(0)) + } + u[0].copy(e) + for i:=0;i<2;i++ { + for j:=0;j<2;j++ { + t.copy(NewBIGints(CURVE_SB[j][i])) + t.copy(modmul(v[j],t,q)) + u[i].add(q) + u[i].sub(t) + u[i].mod(q) + } + } + } else { + q:=NewBIGints(CURVE_Order) + x:=NewBIGints(CURVE_Bnx) + x2:=smul(x,x) + u=append(u,NewBIGcopy(e)) + u[0].mod(x2) + u=append(u,NewBIGcopy(e)) + u[1].div(x2) + u[1].rsub(q) + } + return u +} + +/* Galbraith & Scott Method */ +func gs(e *BIG) []*BIG { + var u []*BIG + if CURVE_PAIRING_TYPE == BN_CURVE { + t:=NewBIGint(0) + q:=NewBIGints(CURVE_Order) + + var v []*BIG + for i:=0;i<4;i++ { + t.copy(NewBIGints(CURVE_WB[i])) + d:=mul(t,e) + v=append(v,NewBIGcopy(d.div(q))) + u=append(u,NewBIGint(0)) + } + u[0].copy(e) + for i:=0;i<4;i++ { + for j:=0;j<4;j++ { + t.copy(NewBIGints(CURVE_BB[j][i])) + t.copy(modmul(v[j],t,q)) + u[i].add(q) + u[i].sub(t) + u[i].mod(q) + } + } + } else { + x:=NewBIGints(CURVE_Bnx) + w:=NewBIGcopy(e) + for i:=0;i<4;i++ { + u=append(u,NewBIGcopy(w)) + u[i].mod(x) + w.div(x) + } + } + return u +} + +/* Multiply P by e in group G1 */ +func G1mul(P *ECP,e *BIG) *ECP { + var R *ECP + if (USE_GLV) { + P.affine() + R=NewECP() + R.copy(P) + Q:=NewECP() + Q.copy(P) + q:=NewBIGints(CURVE_Order); + cru:=NewFPbig(NewBIGints(CURVE_Cru)) + t:=NewBIGint(0) + u:=glv(e) + Q.getx().mul(cru) + + np:=u[0].nbits() + t.copy(modneg(u[0],q)) + nn:=t.nbits() + if nn<np { + u[0].copy(t) + R.neg() + } + + np=u[1].nbits() + t.copy(modneg(u[1],q)) + nn=t.nbits() + if nn<np { + u[1].copy(t) + Q.neg() + } + + R=R.mul2(u[0],Q,u[1]) + + } else { + R=P.mul(e) + } + return R +} + +/* Multiply P by e in group G2 */ +func G2mul(P *ECP2,e *BIG) *ECP2 { + var R *ECP2 + if (USE_GS_G2) { + var Q []*ECP2 + f:=NewFP2bigs(NewBIGints(CURVE_Fra),NewBIGints(CURVE_Frb)) + q:=NewBIGints(CURVE_Order) + u:=gs(e) + + t:=NewBIGint(0) + P.affine() + Q=append(Q,NewECP2()); Q[0].copy(P); + for i:=1;i<4;i++ { + Q=append(Q,NewECP2()); Q[i].copy(Q[i-1]) + Q[i].frob(f) + } + for i:=0;i<4;i++ { + np:=u[i].nbits() + t.copy(modneg(u[i],q)) + nn:=t.nbits() + if nn<np { + u[i].copy(t) + Q[i].neg() + } + } + + R=mul4(Q,u) + + } else { + R=P.mul(e) + } + return R +} + +/* f=f^e */ +/* Note that this method requires a lot of RAM! Better to use compressed XTR method, see FP4.java */ +func GTpow(d *FP12,e *BIG) *FP12 { + var r *FP12 + if USE_GS_GT { + var g []*FP12 + f:=NewFP2bigs(NewBIGints(CURVE_Fra),NewBIGints(CURVE_Frb)) + q:=NewBIGints(CURVE_Order) + t:=NewBIGint(0) + + u:=gs(e) + + g=append(g,NewFP12copy(d)) + for i:=1;i<4;i++ { + g=append(g,NewFP12int(0)) + g[i].copy(g[i-1]) + g[i].frob(f) + } + for i:=0;i<4;i++ { + np:=u[i].nbits() + t.copy(modneg(u[i],q)) + nn:=t.nbits() + if nn<np { + u[i].copy(t) + g[i].conj() + } + } + r=pow4(g,u) + } else { + r=d.pow(e) + } + return r +} + +/* test group membership - no longer needed*/ +/* with GT-Strong curve, now only check that m!=1, conj(m)*m==1, and m.m^{p^4}=m^{p^2} */ +/* +func GTmember(m *FP12) bool { + if m.isunity() {return false} + r:=NewFP12copy(m) + r.conj() + r.mul(m) + if !r.isunity() {return false} + + f:=NewFP2bigs(NewBIGints(CURVE_Fra),NewBIGints(CURVE_Frb)) + + r.copy(m); r.frob(f); r.frob(f) + w:=NewFP12copy(r); w.frob(f); w.frob(f) + w.mul(m) + if !GT_STRONG { + if !w.equals(r) {return false} + x:=NewBIGints(CURVE_Bnx); + r.copy(m); w=r.pow(x); w=w.pow(x) + r.copy(w); r.sqr(); r.mul(w); r.sqr() + w.copy(m); w.frob(f) + } + return w.equals(r) +} +*/ +/* +func main() { + + Q:=NewECPbigs(NewBIGints(CURVE_Gx),NewBIGints(CURVE_Gy)) + P:=NewECP2fp2s(NewFP2bigs(NewBIGints(CURVE_Pxa),NewBIGints(CURVE_Pxb)),NewFP2bigs(NewBIGints(CURVE_Pya),NewBIGints(CURVE_Pyb))) + + //r:=NewBIGints(CURVE_Order) + //xa:=NewBIGints(CURVE_Pxa) + + fmt.Printf("P= "+P.toString()) + fmt.Printf("\n"); + fmt.Printf("Q= "+Q.toString()); + fmt.Printf("\n"); + + //m:=NewBIGint(17) + + e:=ate(P,Q) + e=fexp(e) + for i:=1;i<1000;i++ { + e=ate(P,Q) +// fmt.Printf("\ne= "+e.toString()) +// fmt.Printf("\n") + + e=fexp(e) + } + // e=GTpow(e,m); + + fmt.Printf("\ne= "+e.toString()) + fmt.Printf("\n"); + GLV:=glv(r) + + fmt.Printf("GLV[0]= "+GLV[0].toString()) + fmt.Printf("\n") + + fmt.Printf("GLV[0]= "+GLV[1].toString()) + fmt.Printf("\n") + + G:=NewECP(); G.copy(Q) + R:=NewECP2(); R.copy(P) + + + e=ate(R,Q) + e=fexp(e) + + e=GTpow(e,xa) + fmt.Printf("\ne= "+e.toString()); + fmt.Printf("\n") + + R=G2mul(R,xa) + e=ate(R,G) + e=fexp(e) + + fmt.Printf("\ne= "+e.toString()) + fmt.Printf("\n") + + G=G1mul(G,xa) + e=ate(P,G) + e=fexp(e) + fmt.Printf("\ne= "+e.toString()) + fmt.Printf("\n") +} +*/ http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version22/go/RAND.go ---------------------------------------------------------------------- diff --git a/version22/go/RAND.go b/version22/go/RAND.go new file mode 100644 index 0000000..2b30ec4 --- /dev/null +++ b/version22/go/RAND.go @@ -0,0 +1,153 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +*/ + +/* + * Cryptographic strong random number generator + * + * Unguessable seed -> SHA -> PRNG internal state -> SHA -> random numbers + * Slow - but secure + * + * See ftp://ftp.rsasecurity.com/pub/pdfs/bull-1.pdf for a justification + */ + +/* Marsaglia & Zaman Random number generator constants */ + + +package main + +//import "fmt" + +const rand_NK int=21 +const rand_NJ int=6 +const rand_NV int=8 + +type RAND struct { + ira [rand_NK]uint32 /* random number... */ + rndptr int + borrow uint32 + pool_ptr int + pool [32]byte +} + +/* Terminate and clean up */ +func (R *RAND) Clean() { /* kill internal state */ + R.pool_ptr=0; R.rndptr=0; + for i:=0;i<32;i++ {R.pool[i]=0} + for i:=0;i<rand_NK;i++ {R.ira[i]=0} + R.borrow=0; +} + +func NewRAND() *RAND { + R:=new(RAND) + R.Clean() + return R +} + +func (R *RAND) sbrand() uint32 { /* Marsaglia & Zaman random number generator */ + R.rndptr++ + if R.rndptr<rand_NK {return R.ira[R.rndptr]} + R.rndptr=0 + k:=rand_NK-rand_NJ + for i:=0;i<rand_NK;i++{ /* calculate next NK values */ + if k==rand_NK {k=0} + t:=R.ira[k] + pdiff:=t-R.ira[i]-R.borrow + if pdiff<t {R.borrow=0} + if pdiff>t {R.borrow=1} + R.ira[i]=pdiff + k++ + } + + return R.ira[0]; +} + +func (R *RAND) sirand(seed uint32) { + var m uint32=1; + R.borrow=0 + R.rndptr=0 + R.ira[0]^=seed; + for i:=1;i<rand_NK;i++ { /* fill initialisation vector */ + in:=(rand_NV*i)%rand_NK; + R.ira[in]^=m; /* note XOR */ + t:=m + m=seed-m + seed=t + } + for i:=0;i<10000;i++ {R.sbrand()} /* "warm-up" & stir the generator */ +} + +func (R *RAND) fill_pool() { + sh:=NewHASH256() + for i:=0;i<128;i++ {sh.Process(byte(R.sbrand()&0xff))} + W:=sh.Hash() + for i:=0;i<32;i++ {R.pool[i]=W[i]} + R.pool_ptr=0; +} + +func pack(b [4]byte) uint32 { /* pack 4 bytes into a 32-bit Word */ + return (((uint32(b[3]))&0xff)<<24)|((uint32(b[2])&0xff)<<16)|((uint32(b[1])&0xff)<<8)|(uint32(b[0])&0xff) +} + +/* Initialize RNG with some real entropy from some external source */ +func (R *RAND) Seed(rawlen int,raw []byte) { /* initialise from at least 128 byte string of raw random entropy */ + var b [4]byte + sh:=NewHASH256() + R.pool_ptr=0; + + for i:=0;i<rand_NK;i++ {R.ira[i]=0} + if rawlen>0 { + for i:=0;i<rawlen;i++ { + sh.Process(raw[i]) + } + digest:=sh.Hash() + +/* initialise PRNG from distilled randomness */ + + for i:=0;i<8;i++ { + b[0]=digest[4*i]; b[1]=digest[4*i+1]; b[2]=digest[4*i+2]; b[3]=digest[4*i+3] + R.sirand(pack(b)) + } + } + R.fill_pool() +} + +/* get random byte */ +func (R *RAND) GetByte() byte { + r:=R.pool[R.pool_ptr] + R.pool_ptr++ + if R.pool_ptr>=32 {R.fill_pool()} + return byte(r&0xff) +} + +/* test main program */ +/* +func main() { + var raw [100]byte + rng:=NewRAND() + + rng.Clean() + for i:=0;i<100;i++ {raw[i]=byte(i)} + + rng.Seed(100,raw[:]) + + for i:=0;i<1000;i++ { + fmt.Printf("%03d ",rng.GetByte()) + } +} +*/
