1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
|
--dsa by rnd
--digital signature algorithm
--MAIN IDEA: present equation thats hard to solve in general but trivial to solve
--if you know the private key.
-- parameters: p,q,g
-- 1. p,q primes such that p-1 = a'*q, for example p safe prime, p-1=2q (N bits, L bits)
-- 2. select g in Z_p of order q ( for example h^(p-1)/q will work almost always with h=2)
-- user keys: x in Z_q private key, y = g^x in Z_p = private key
-- MAIN IDEA: given h = hash(message m) in Z_q and random k in Z_q and r = g^k %p %q find
-- w in Z_q such that: g^(hash(m)*w + x*r*w) %p %q = g^k %p %q
-- this is easy if we know x -> solve w*(h+x*r) = k in Z_q -> w = (h+x*r)^-1*k in Z_q
-- now we hide k and x and show only y = g^x%p and r = g^k %p %q, problem is rewritten as:
-- PROBLEM:
-- g^(h*w) * y^(r*w) %p %q = r. So problem is determining such r and w.
-- NOTES: the idea of %p %q is to make brute force even slower, since:
--0. x=y %p %q if x=y+t1*q+t2*p for some p,q
--1. attacker doesnt have much freedom with h since he cant precisely control hash values
--2. suppose same k is reused for 2 different m. Write s = w^-1 mod q. Since
--s = k^-1*(h+r*x) mod q we get: s2 = k^-1*(h2+r*x) and s1 = k^-1*(h1+r*x),
-- or s2-s1 = k^-1( h2-h1) -> k = (s2-s1)^-1*(h2-h1).. and r^-1*(k*s-h)=x = BAD
-- must be careful that we pick very different k each time
-- 3. CAREFUL! k1 s1 = (h1+r1*x), k2 s2 =(h2+r2*x) -> k1 s1- k2 s2 - (h1-h2) = (r1-r2)*x.
-- so if we know there is little difference between k1,k2 we can try small sample different k2 and try to solve for x!
local bignum = _G.bignum; local crypto = _G.crypto;
--512 bit
--c1d3a133c9b3720da868dda10b6a0bde0e1a47d797d3e02f2673157ad26c33970553352abd72114a48813b3f1a3d86120c2150d9c33780bf0ce31acf2e28b813
p = {base = 67108864, sgn = 1,digits = {36222995, 13022155, 782542, 57085150, 34349392, 42951044, 1291249, 4532514, 19578226, 29447373, 19317561, 30168555, 65023782, 32892404, 31515044, 2992175, 6872481, 14451562, 34815131, 198478}}
barrettp = {["k"] = 42, ["m"] = {["base"] = 67108864, ["sgn"] = 1,["digits"] = {28949715, 54423101, 2288892, 15960629, 25093079, 30961036, 9893219, 18572583, 6060506, 53345934, 62824245, 21175570, 51585074, 64634085, 50626132, 23908947, 34461644, 49242303, 44848557, 11882353, 4640537, 7818826, 338}}, ["n"] = {["base"] = 67108864, ["sgn"] = 1, ["digits"] = {36222995, 13022155, 782542, 57085150, 34349392, 42951044, 1291249, 4532514, 19578226, 29447373, 19317561, 30168555, 65023782, 32892404, 31515044, 2992175, 6872481, 14451562, 34815131, 198478}}}
q = {["base"] = 67108864, ["sgn"] = 1, ["digits"] = {51665929, 6511077, 391271, 28542575, 17174696, 55029954, 645624, 2266257, 43343545, 48278118, 43213212, 15084277, 32511891, 16446202, 49311954, 35050519, 3436240, 40780213, 17407565, 99239}}
barrettq = {["k"] = 42, ["m"] = {["base"] = 67108864, ["sgn"] = 1, ["digits"] = {50630993, 11411608, 4806431, 31921258, 50186158, 61922072, 19786438, 37145166, 12121012, 39583004, 58539627, 42351141, 36061284, 62159307, 34143401, 47817895, 1814424, 31375743, 22588251, 23764707, 9281074, 15637652, 676}}, ["n"] = {["base"] = 67108864, ["sgn"] = 1, ["digits"] = {51665929, 6511077, 391271, 28542575, 17174696, 55029954, 645624, 2266257, 43343545, 48278118, 43213212, 15084277, 32511891, 16446202, 49311954, 35050519, 3436240, 40780213, 17407565, 99239}}}
--2048 bit
--db726369acb4a51666ee14e0dc4305afc11692cc0dfa9d06b399ebc7b541b095ca3f48633ed936e0d4633af1c8b72886829c5fdd98861c44acdadc54075dc3beeb3d4a4bf9fb13b2c943e8bcb8c8df4440a84753c87d1512ff3db5083941ac88764c674da50771fdd7f4db99d7281e653253191df1f0137004b81488ecf9d15c49462c5438d4c060fa5a36e3e8e73ca1969d312b1b11df3e6fa3ce0a87641f4007884470d4911da45df914143c2c446a51443d6595c84cf83467825cf08007546e04c5137acac3ec0f413c522f5904d3b5230b4f5f2a26a0a8ad318ab541d1cd69079b0cb040827e2eb48f4fb7bc76623b96c7d38c603a186e24ae70a3bd66b3
-- p = {
-- base = 2^26, sgn = 1,
-- digits = {62744243, 19635240, 60917474, 55456128, 37459655, 32447896, 55112955, 34207930, 51163200, 56246758, 55844124, 45401642, 36085928, 47437770, 20664880, 12411923, 54606930, 45153027, 5322668, 22132755, 15761415, 18473111, 8703875, 16094807, 6967620, 17763089, 31428929, 38041233, 4485332, 63963618, 11040321, 29265720, 51502910, 55331526, 63576425, 59745180, 16407094, 37040152, 6473027, 54882597, 8973561, 77317, 52363575, 21783671, 1991986, 48657866, 64847693, 43261383, 38561613, 7021085, 55608212, 4979958, 63470869, 2757076, 9303108, 61010659, 62048579, 50233028, 45339812, 24579835, 47993863, 51456822, 31033441, 34238847, 12003462, 13548658, 57544006, 26016612, 30031688, 22047781, 27180155, 41163470, 46927354, 66078116, 29634650, 62411651, 10819174, 14314285, 898854}
-- }
-- barrettp = {
-- ["k"] = 160, ["m"] = {["base"] = 67108864, ["sgn"] = 1,
-- ["digits"] = {52173231, 58926316, 7134135, 58005281, 29642925, 1996, 43704342, 19181367, 51834951, 40753938, 5670116, 25083444, 53681109, 39194353, 21018693, 16186348, 52641345, 34474171, 45582158, 65632598, 6663244, 17715531, 46582518, 715815, 35941432, 62741031, 14063905, 37500214, 33724930, 25815530, 29521098, 42349641, 30021354, 56331771, 20197595, 44642351, 39774, 15935544, 18538053, 54085894, 20262092, 170794, 877950, 7075184, 15922733, 42275553, 19627281, 61124663, 6351068, 20488035, 52369744, 26751026, 17905178, 25990200, 47243983, 42954366, 65859731, 23375626, 40610711, 9951837, 9139091, 55630155, 4911180, 17490059, 43409254, 37055369, 1417704, 12145177, 9055946, 41623298, 33230333, 1111792, 21966597, 20877280, 44498082, 6831928, 22418430, 4437100, 27282748, 12568457, 44322344, 74}}, ["n"] = {["base"] = 67108864, ["sgn"] = 1, ["digits"] = {62744243, 19635240, 60917474, 55456128, 37459655, 32447896, 55112955, 34207930, 51163200, 56246758, 55844124, 45401642, 36085928, 47437770, 20664880, 12411923, 54606930, 45153027, 5322668, 22132755, 15761415, 18473111, 8703875, 16094807, 6967620, 17763089, 31428929, 38041233, 4485332, 63963618, 11040321, 29265720, 51502910, 55331526, 63576425, 59745180, 16407094, 37040152, 6473027, 54882597, 8973561, 77317, 52363575, 21783671, 1991986, 48657866, 64847693, 43261383, 38561613, 7021085, 55608212, 4979958, 63470869, 2757076, 9303108, 61010659, 62048579, 50233028, 45339812, 24579835, 47993863, 51456822, 31033441, 34238847, 12003462, 13548658, 57544006, 26016612, 30031688, 22047781, 27180155, 41163470, 46927354, 66078116, 29634650, 62411651, 10819174, 14314285, 898854}}
local importsshprime = function(GH) -- use this to precompute all the needed prime stuff for extra speed
local base = 2^26;
local G1 = bignum.importhex(GH); local G2 = bignum.base2binary(G1);
local p = bignum.binary2base(G2,base);
code1 = minetest.serialize(p.digits) -- prime GH digits
local t = os.clock();
local barrettp = bignum.get_barrett(p);say(os.clock()-t) -- precompute barrett form
local code2 = minetest.serialize(barrettp)
local q = bignum.new(base,1,p.digits); q.digits[1] = q.digits[1]-1; bignum.div2(q,q); -- q = (p-1)/2
local code3 = minetest.serialize(q)
local barrettq = bignum.get_barrett(q); -- precompute q and this!
local code4 = minetest.serialize(barrettq)
local msg = "p " ..code1.."\nbarrettp " .. code2 .. "\nq " .. code3 .. "\nbarrettq " .. code4;
local form = "size[5,5] textarea[0,0;6,6;MSG;MESSAGE;" .. minetest.formspec_escape(msg) .. "]"
minetest.show_formspec("robot", form)
end
--importsshprime("c1d3a133c9b3720da868dda10b6a0bde0e1a47d797d3e02f2673157ad26c33970553352abd72114a48813b3f1a3d86120c2150d9c33780bf0ce31acf2e28b813")
DSA = {};
--msg = 520 bit number base 2^26
-- MAIN IDEA: given h = hash(message m) in Z_q and random k in Z_q and r = g^k %p %q find
-- w in Z_q such that: g^(hash(m)*w + x*r*w) %p %q = g^k %p %q
-- this is easy if we know x -> solve w*(h+x*r) = k in Z_q -> w = (h+x*r)^-1*k in Z_q
local DSA_sign = function(msg,x) -- msg = (hash) message as number, x = private key
local m = 20; local base = 2^26;
local temp = bignum.rnd(base,1,m); -- random value, k should be <q!
local k = bignum.new(base,1,{}); bignum.mod(temp, barrettq, k);
--warning: possible problem if q1.digits[1]-2 = 1-2<0 cause we didnt do carry! in our case its 51665929. otherwise extremely unlikely, since digits in base 2^26.
local q2 = bignum.new(base,1,bignum.tablecopy(q.digits)); q2.digits[1] = q2.digits[1]-2; -- q-2, needed to compute c^-1 = c^(q-2) mod q.
local g = bignum.new(base,1,{2^2}); -- g^q = 1 mod p ( g = 2^(p-1)/q mod p = 2^2)
temp = bignum.modpow(g,k, barrettp);
local r = bignum.new(base,1,{}); bignum.mod(temp,barrettq,r); --r = g^k mod p mod q
local mxr = bignum.new(base,1,{}) -- will be m+x*r mod q
local temp1 = bignum.new(base,1,{})
bignum.mul(x,r,temp); bignum._add(msg,temp,temp1); -- temp1 = m+x*r
bignum.mod(temp1,barrettq,mxr) -- range is very important, temp1 < q or modpow can freeze
temp = bignum.modpow(mxr, q2, barrettq); --(m+x*r)^-1 -- FREEZE PROBLEM if temp1>q. cause then temp1^2>q^2 and barret modpow fail..
local w = bignum.new(base,1,{});
bignum.mul(temp,k,temp1);bignum.mod(temp1,barrettq,w) -- w = (m+x*r)^-1*k
return {r,w} -- w = temp1 = (m+x*r)^-1*k in Z_q
end
local dsa_sign_test = function()
local x = bignum.rnd(2^26,1,20) -- private key
local g = bignum.new(2^26,1,{2^2});
local y = bignum.modpow(g,x,barrettp); -- public key
local msg = bignum.importascii("hello world",2^26) -- will cut off at 520 bytes, use hash here for real thing
local sig = DSA_sign(msg,x)
--say(minetest.serialize(sig))
end
--dsa_sign_test()
local DSA_verify = function(msg,sig,y) -- m = message, sig = {r,w} = signature, y = public key (= g^x)
-- CHECK: g^(m*w) * y^(r*w) %p %q == r
local temp1 = bignum.new(base,1,{});
local m = 20; local base = 2^26;
local g = bignum.new(base,1,{2^2});
bignum.mul(msg,sig[2],temp1); temp1 = bignum.modpow(g,temp1,barrettp); -- temp1 = g^(m*w) mod p
local temp2 = bignum.new(base,1,{});
bignum.mul(sig[1],sig[2],temp2); temp2 = bignum.modpow(y,temp2,barrettp); -- temp2 = y^(r*w) mod p
local temp = bignum.new(base,1,{});
bignum.mul(temp1,temp2,temp); bignum.mod(temp,barrettp,temp1); -- temp1 = g^(m*w) * y^(r*w) %p
bignum.mod(temp1,barrettq,temp); -- temp = g^(m*w) * y^(r*w) %p %q
return bignum.is_equal(temp,sig[1])
end
local dsa__test = function()
local x = bignum.rnd(2^26,1,20) -- private key
local g = bignum.new(2^26,1,{2^2});
local y = bignum.modpow(g,x,barrettp) -- public key
local msg = bignum.importascii("hello world",2^26) -- will cut off at 520 bytes, use hash here for real thing
local sig = DSA_sign(msg,x) -- create signature
local ok = DSA_verify(msg,sig,y) -- verify signature
say(bignum.exportbase64(sig[1]) .."&" .. bignum.exportbase64(sig[2]))
say(ok and "signature ok." or "signature failed.")
end
--dsa__test()
DSA.sign = function(msg,privatekey)
local x = bignum.importbase64(privatekey,2^26)
local hash = bignum.importascii(crypto.rndhash(msg,512),2^26);
local sig = DSA_sign(hash,x);
return bignum.exportbase64(sig[1]) .."&" .. bignum.exportbase64(sig[2])
end
DSA.verify = function(msg,sig,publickey)
local y = bignum.importbase64(publickey,2^26)
local hash = bignum.importascii(crypto.rndhash(msg,512),2^26);
local i = string.find(sig,"&")
local rs,ws;
if i then rs = string.sub(sig,1,i-1); ws = string.sub(sig,i+1) else return false end
local r = bignum.importbase64(rs,2^26);local w = bignum.importbase64(ws,2^26);
return DSA_verify(hash,{r,w},y)
end
local DSAtest = function ()
say(minetest.colorize("red","DSA by rnd"))
local privatex = bignum.rnd(2^26,1,20)
local privatekey = bignum.exportbase64(privatex);
say("PRIVATE KEY = " .. privatekey)
local publicy = bignum.modpow(bignum.new(2^26,1,{2^2}),privatex,barrettp)
local publickey = bignum.exportbase64(publicy);
say("PUBLIC KEY = " .. publickey)
local msg = "05/20/2018 i, rnd, state that i wrote all this from scratch :)";
say("MESSAGE = " .. msg)
local sig = DSA.sign(msg,privatekey)
say("SIGNATURE = " .. sig)
local msg1 = "05/20/2018 i, rnd, state that i wrote all this from scratch :)"
local ok = DSA.verify(msg1,sig,publickey);
if ok then say(minetest.colorize("lawngreen","VERIFY: ok")) else say(minetest.colorize("red","VERIFY: fail")) end
end
DSAtest()
self.remove()
|