File: dsa.lua

package info (click to toggle)
minetest-mod-basic-robot-csm 0.0~git20190703.e082c6a-2
  • links: PTS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 268 kB
  • sloc: makefile: 2
file content (191 lines) | stat: -rw-r--r-- 12,199 bytes parent folder | download
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()