294 lines
7.2 KiB
Text
294 lines
7.2 KiB
Text
requires(64)
|
|
enum X, Y -- rational ec point
|
|
enum A, B, N, G, R -- elliptic curve parameters
|
|
-- also signature pair(A,B)
|
|
|
|
constant mxN = 1073741789 -- maximum modulus
|
|
constant mxr = 1073807325 -- max order G = mxN + 65536
|
|
constant inf = -2147483647 -- symbolic infinity
|
|
|
|
sequence e = {0,0,0,{0,0},0} -- single global curve
|
|
constant zerO = {inf,0} -- point at infinity zerO
|
|
|
|
bool inverr -- impossible inverse mod N
|
|
|
|
function exgcd(atom v, u)
|
|
-- return mod(v^-1, u)
|
|
atom q, t, r = 0, s = 1
|
|
if v<0 then v += u end if
|
|
|
|
while v do
|
|
q = floor(u/v)
|
|
t = u-q*v
|
|
u = v
|
|
v = t
|
|
t = r-q*s
|
|
r = s
|
|
s = t
|
|
end while
|
|
|
|
if u!=1 then
|
|
printf(1," impossible inverse mod N, gcd = %d\n",{u})
|
|
inverr = true
|
|
end if
|
|
|
|
return r
|
|
end function
|
|
|
|
function modn(atom a)
|
|
-- return mod(a, N)
|
|
a = mod(a,e[N])
|
|
if a<0 then a += e[N] end if
|
|
return a
|
|
end function
|
|
|
|
function modr(atom a)
|
|
-- return mod(a, r)
|
|
a = mod(a,e[R])
|
|
if a<0 then a += e[R] end if
|
|
return a
|
|
end function
|
|
|
|
function disc()
|
|
-- return the discriminant of E
|
|
atom a = e[A], b = e[B],
|
|
c = 4*modn(a*modn(a*a))
|
|
return modn(-16*(c+27*modn(b*b)))
|
|
end function
|
|
|
|
function isO(sequence p)
|
|
-- return true if P = zerO
|
|
return (p[X]=inf and p[Y]=0)
|
|
end function
|
|
|
|
function ison(sequence p)
|
|
-- return true if P is on curve E
|
|
atom r = 0, s = 0
|
|
if not isO(p) then
|
|
r = modn(e[B]+p[X]*modn(e[A]+p[X]*p[X]))
|
|
s = modn(p[Y]*p[Y])
|
|
end if
|
|
return (r=s)
|
|
end function
|
|
|
|
procedure pprint(string f, sequence p)
|
|
-- print point P with prefix f
|
|
if isO(p) then
|
|
printf(1,"%s (0)\n",{f})
|
|
else
|
|
atom y = p[Y]
|
|
if y>e[N]-y then y -= e[N] end if
|
|
printf(1,"%s (%d,%d)\n",{f,p[X],y})
|
|
end if
|
|
end procedure
|
|
|
|
function padd(sequence p, q)
|
|
-- full ec point addition
|
|
atom la, t
|
|
|
|
if isO(p) then return q end if
|
|
if isO(q) then return p end if
|
|
|
|
if p[X]!=q[X] then -- R := P + Q
|
|
t = p[Y]-q[Y]
|
|
la = modn(t*exgcd(p[X]-q[X], e[N]))
|
|
|
|
else -- P = Q, R := 2P
|
|
if (p[Y]=q[Y]) and (p[Y]!=0) then
|
|
t = modn(3*modn(p[X]*p[X])+e[A])
|
|
la = modn(t*exgcd(2*p[Y], e[N]))
|
|
else
|
|
return zerO -- P = -Q, R := O
|
|
end if
|
|
end if
|
|
|
|
t = modn(la*la-p[X]-q[X])
|
|
sequence r = deep_copy(zerO)
|
|
r[Y] = modn(la*(p[X]-t)-p[Y])
|
|
r[X] = t
|
|
if inverr then r = zerO end if
|
|
return r
|
|
end function
|
|
|
|
function pmul(sequence p, atom k)
|
|
-- R:= multiple kP
|
|
sequence s = zerO, q = p
|
|
|
|
while k do
|
|
if and_bits(k,1) then
|
|
s = padd(s, q)
|
|
end if
|
|
if inverr then s = zerO; exit end if
|
|
k = floor(k/2)
|
|
q = padd(q, q)
|
|
end while
|
|
return s
|
|
end function
|
|
|
|
function ellinit(sequence i)
|
|
-- initialize elliptic curve
|
|
atom a = i[1], b = i[2]
|
|
inverr = false
|
|
e[N] = i[3]
|
|
|
|
if (e[N]<5) or (e[N]>mxN) then return 0 end if
|
|
|
|
e[A] = modn(a)
|
|
e[B] = modn(b)
|
|
e[G][X] = modn(i[4])
|
|
e[G][Y] = modn(i[5])
|
|
e[R] = i[6]
|
|
|
|
if (e[R]<5) or (e[R]>mxr) then return 0 end if
|
|
|
|
printf(1,"E: y^2 = x^3 + %dx + %d (mod %d)\n",{a,b,e[N]})
|
|
pprint("base point G", e[G])
|
|
printf(1,"order(G, E) = %d\n",{e[R]})
|
|
|
|
return -1
|
|
end function
|
|
|
|
function signature(atom s, f)
|
|
-- signature primitive
|
|
atom c, d, u, u1
|
|
sequence V
|
|
|
|
printf(1,"signature computation\n")
|
|
while true do
|
|
while true do
|
|
-- u = rand(e[R]-1)
|
|
u = 571533488 -- match FreeBASIC output
|
|
-- u = 605163545 -- match C output
|
|
V = pmul(e[G], u)
|
|
c = modr(V[X])
|
|
if c!=0 then exit end if
|
|
end while
|
|
|
|
u1 = exgcd(u, e[R])
|
|
d = modr(u1*(f+modr(s*c)))
|
|
if d!=0 then exit end if
|
|
end while
|
|
printf(1,"one-time u = %d\n",u)
|
|
pprint("V = uG", V)
|
|
return {c,d}
|
|
end function
|
|
|
|
function verify(sequence W, atom f, sequence sg)
|
|
-- verification primitive
|
|
atom c = sg[A], d = sg[B],
|
|
t, c1, h1, h2, h
|
|
sequence V, V2
|
|
|
|
--domain check
|
|
t = (c>0) and (c<e[R])
|
|
t = t and (d>0) and (d<e[R])
|
|
if not t then return 0 end if
|
|
|
|
printf(1,"\nsignature verification\n")
|
|
h = exgcd(d, e[R])
|
|
h1 = modr(f*h)
|
|
h2 = modr(c*h)
|
|
printf(1,"h1,h2 = %d,%d\n",{h1,h2})
|
|
V = pmul(e[G], h1)
|
|
V2 = pmul(W, h2)
|
|
pprint("h1G", V)
|
|
pprint("h2W", V2)
|
|
V = padd(V, V2)
|
|
pprint("+ =", V)
|
|
if isO(V) then return 0 end if
|
|
c1 = modr(V[X])
|
|
printf(1,"c' = %d\n",c1)
|
|
|
|
return (c1=c)
|
|
end function
|
|
|
|
procedure errmsg()
|
|
printf(1,"invalid parameter set\n")
|
|
printf(1,"_____________________\n")
|
|
end procedure
|
|
|
|
procedure ec_dsa(atom f, d)
|
|
-- digital signature on message hash f, error bit d
|
|
atom i, s, t
|
|
sequence sg, W
|
|
|
|
--parameter check
|
|
t = (disc()=0)
|
|
t = t or isO(e[G])
|
|
W = pmul(e[G], e[R])
|
|
t = t or not isO(W)
|
|
t = t or not ison(e[G])
|
|
if t then errmsg() return end if
|
|
|
|
puts(1,"\nkey generation\n")
|
|
-- s = rand(e[R] - 1)
|
|
s = 509100772 -- match FreeBASIC output
|
|
-- s = 1343570 -- match C output
|
|
W = pmul(e[G], s)
|
|
printf(1,"private key s = %d\n",{s})
|
|
pprint("public key W = sG", W)
|
|
|
|
--next highest power of 2 - 1
|
|
t = e[R]
|
|
i = 1
|
|
while i<32 do
|
|
t = or_bits(t,floor(t/power(2,i)))
|
|
i *= 2
|
|
end while
|
|
while f>t do
|
|
f = floor(f/2)
|
|
end while
|
|
printf(1,"\naligned hash %x\n\n",{f})
|
|
|
|
sg = signature(s, f)
|
|
if inverr then errmsg() return end if
|
|
printf(1,"signature c,d = %d,%d\n",sg)
|
|
|
|
if d>0 then
|
|
while d>t do
|
|
d = floor(d/2)
|
|
end while
|
|
f = xor_bits(f,d)
|
|
printf(1,"corrupted hash %x\n",{f})
|
|
end if
|
|
|
|
t = verify(W, f, sg)
|
|
if inverr then errmsg() return end if
|
|
if t then
|
|
printf(1,"Valid\n_____\n")
|
|
else
|
|
printf(1,"invalid\n_______\n")
|
|
end if
|
|
end procedure
|
|
|
|
--Test vectors: elliptic curve domain parameters,
|
|
--short Weierstrass model y^2 = x^3 + ax + b (mod N)
|
|
|
|
constant tests = {
|
|
-- a, b, modulus N, base point G, order(G, E), cofactor
|
|
{355, 671, 1073741789, 13693, 10088, 1073807281},
|
|
{ 0, 7, 67096021, 6580, 779, 16769911}, -- 4
|
|
{ -3, 1, 877073, 0, 1, 878159},
|
|
{ 0, 14, 22651, 63, 30, 151}, -- 151
|
|
{ 3, 2, 5, 2, 1, 5},
|
|
|
|
--ecdsa may fail if...
|
|
--the base point is of composite order
|
|
{ 0, 7, 67096021, 2402, 6067, 33539822}, -- 2
|
|
--the given order is a multiple of the true order
|
|
{ 0, 7, 67096021, 6580, 779, 67079644}, -- 1
|
|
--the modulus is not prime (deceptive example)
|
|
{ 0, 7, 877069, 3, 97123, 877069},
|
|
--fails if the modulus divides the discriminant
|
|
{ 39, 387, 22651, 95, 27, 22651}}
|
|
|
|
--Digital signature on message hash f,
|
|
--set d > 0 to simulate corrupted data
|
|
atom f = #789ABCDE,
|
|
d = 0
|
|
|
|
--for i=1 to length(tests) do
|
|
for i=1 to 1 do
|
|
if not ellinit(tests[i]) then exit end if
|
|
ec_dsa(f, d)
|
|
end for
|