blob: 4fbec4c88143fff09ff1636e5a11505972cf3615 [file] [log] [blame]
#
# Python 3.7 Code to implement basic MPIN protocol API
# M.Scott August 2018
#
import hashlib
from XXX import ecp
from XXX import ecp2
from XXX import curve
from XXX import big
from XXX.ecp import *
from XXX.ecp2 import *
from XXX import pair
from XXX.fp12 import *
# hash ID to point on curve
def H(mpin_id):
r = curve.r
p = curve.p
h = hashlib.new(curve.SHA)
h.update(bytes(mpin_id, 'utf-8'))
x = big.from_bytes(h.digest())
x %= p
P = ECp()
while not P.set(x):
x = x + 1
# work out co-factor
nb = p.bit_length()
cf = 1
cf = cf << (nb + 4) // 2
cf += p
cf //= r
if cf != 1:
P = cf * P
return P
def random_generate():
FS = curve.EFS
s = big.rand(curve.r)
Z = big.to_bytes(s)
return Z
def get_server_secret(Z):
Q = ecp2.generator()
s = big.from_bytes(Z)
Q = s * Q
return Q.toBytes()
def get_client_secret(Z, ID):
P = H(ID)
s = big.from_bytes(Z)
P = s * P
return P.toBytes(False)
# subtract pin.ID from Secret key SK to create Token
def extract_pin(ID, PIN, SK):
P = H(ID)
P = -(PIN * P)
S = ECp()
if not S.fromBytes(SK):
return bytearray(0)
S.add(P)
# S.affine()
return S.toBytes(False)
# U=xH(ID)
def client_1(ID, X):
P = H(ID)
if X:
w = big.from_bytes(X)
else:
w = big.rand(curve.r)
X = big.to_bytes(w)
P = w * P
return (X, P.toBytes(False))
# reconstitute Client secret S from Token and PIN
# V=(x+y)S
def client_2(X, Y, ID, PIN, TK):
P = H(ID)
S = ECp()
if not S.fromBytes(TK):
return bytearray(0)
x = big.from_bytes(X)
y = big.from_bytes(Y)
x = (x + y) % curve.r
x = curve.r - x
S.add(PIN * P)
S = x * S
return S.toBytes(False)
# authenticate
def server(ID, Y, SS, U, V):
P = H(ID)
y = big.from_bytes(Y)
Q = ecp2.generator()
P = y * P
sQ = ECp2()
if not sQ.fromBytes(SS):
return (False, Fp12(), Fp12())
TU = ECp()
if not TU.fromBytes(U):
return (False, bytearray(0), bytearray(0))
TV = ECp()
if not TV.fromBytes(V):
return (False, bytearray(0), bytearray(0))
TU.add(P)
# TU.affine()
r = pair.double_miller(Q, TV, sQ, TU)
r = pair.fexp(r)
if r.isone():
return (True, bytearray(0), bytearray(0))
# failed - diagnose it
E = r.toBytes()
r = pair.e(Q, TU)
F = r.toBytes()
return (False, E, F)
MAXPIN = 10000
TS = 10
TRAP = 200
def kangaroo(E, F):
FS = curve.EFS
e = Fp12()
e.fromBytes(E)
f = Fp12()
f.fromBytes(F)
# Pollards Kangaroos
t = f.copy()
distance = []
table = []
s = 1
for m in range(0, TS):
distance.append(s)
table.append(t.copy())
s *= 2
t.usqr()
t = Fp12.one()
# set trap
dn = 0
for j in range(0, TRAP):
i = t.a.a.a.int() % TS
t *= table[i]
dn += distance[i]
# release wild kangaroo
f = t.copy()
f.conj()
steps = 0
dm = 0
while dm - dn < MAXPIN:
steps = steps + 1
if steps > 4 * TRAP:
break
i = e.a.a.a.int() % TS
e *= table[i]
dm += distance[i]
if e == t:
res = dm - dn
break
if e == f:
res = dn - dm
break
if steps > 4 * TRAP or dm - dn >= MAXPIN:
res = 0
return res
def add_G1(A, B):
""" Add two points in G1: C = A + B """
A1 = ECp()
B1 = ECp()
if not A1.fromBytes(A):
return None
if not B1.fromBytes(B):
return None
A1.add(B1)
return A1.toBytes(False)
def add_G2(A, B):
""" Add two points in G2: C = A + B """
A1 = ECp2()
B1 = ECp2()
if not A1.fromBytes(A):
return None
if not B1.fromBytes(B):
return None
A1.add(B1)
return A1.toBytes()