blob: 42a2443bb8ec4853515e1912842302198a09056f [file] [log] [blame]
/*
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")
}