importScripts('http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/sha1.js');
importScripts('biginteger.js');
 
 function randomNum (size){
	var random;
	var step = 1000;
	size--;
	random = BigInteger(2).pow(size);
	random = BigInteger(random).prev();
	random = BigInteger(random).multiply(Math.floor(Math.random()*step))	
	random = BigInteger(random).divide(step);
	random = BigInteger(random).add(BigInteger(2).pow(size));
	return random;
}

var gcd = function(a, b) {
	if (BigInteger(b).compare(0) == 0) {
        return a;
    }else
	return gcd(b, BigInteger(a).remainder(b));
}

function bitSize(num) {
    return num.toString(2).length;
}


function inverseMod2(a,n)
        {
            i = BigInteger(n);
			v = BigInteger(0);
			d = BigInteger(1);
            while (BigInteger(a).compare(0) > 0)
            {
                t = BigInteger(i).divide(a);
				x = BigInteger(a);
                a = BigInteger(i).remainder(x);
                i = BigInteger(x);
                x = BigInteger(d);
                d = BigInteger(v).subtract(BigInteger(t).multiply(x));
                v = BigInteger(x);
            }
            v = BigInteger(v).remainder(n);
            if (v < 0) 
				v = BigInteger(BigInteger(v).add(n)).remainder(n);
            return v;
        }


// nastavení pevných hodnot

nSize = 1024;
rSize = 350;
sSize = 324;
w1Size = 160; //160
w2Size = 80;
S1Size = 243;
S2Size = 160;
S3invSize = 80;
KSSize = 160;
k = HashSize = 160;
m = ErrorSize = 80;
qSize = k + m + w1Size;

p = BigInteger.parse("101862844851154724810521866756806184115759102013232486884348263759146526161843874769371336879030201425871889242675940015251426354666548206718423877096229648193044977951319785408967737059042844244979063919894147031364568000502331137837661070299500684743193335355862365725393062284044823825981346977695601810323");
q = BigInteger.parse("1611506022683788087139493090782141978301032034281221926267352807644661373642263028369676255264125579023939643047645235239");
alpha = BigInteger.parse("63209720235183006422723482355701182028707045028111706167458376742512969114855004094507744139930540026847443847193752649646050820844148922223672545838025385996719166874624650890037451047198");
r = BigInteger.parse("2049529615600998849234671311919703548559815439159275479128689020827400495280598226592935657102666868540159");
s = BigInteger.parse("29616799931743574532866062672608501611837417685616204080156539343232276716597231012767449008520439");

radkovani = 103; 


// setup

var h1 = randomNum(nSize);
var h2 = randomNum(nSize);
while (BigInteger(h1).modPow(alpha,p) == 1){
	h1 = randomNum(nSize);
}
while (BigInteger(h2).modPow(alpha,p) == 1){
	h2 = randomNum(nSize);
}

h1 = BigInteger(h1).modPow(alpha,p);
h2 = BigInteger(h2).modPow(alpha,p);

n = BigInteger(BigInteger(r).pow(2)).multiply(s);
phi = BigInteger(BigInteger(n).subtract(BigInteger(n).divide(r))).add(BigInteger(BigInteger(n).divide(BigInteger(r).multiply(s))).subtract(BigInteger(n).divide(s)) );

S1 = randomNum(S1Size);
i = 0;
while ((gcd(S1,phi) != 1)){
 S1 = randomNum(S1Size);
 i++;
}

var S2 = randomNum(S2Size);
i = 0;
while ((gcd(S2,phi) != 1) ){
 S2 = randomNum(S2Size);
 i++;
}

var S3inv = randomNum(S3invSize);
i = 0;
while ((gcd(S3inv,phi) != 1)){
 S3inv = randomNum(S3invSize);
 i++;
}

S3 = BigInteger(inverseMod2(S3inv,phi));

g1 = randomNum(350); // 3-350 // (rSize = 350)
while ( BigInteger(g1).modPow(BigInteger(phi).divide(r),n) == 1 || 
		BigInteger(g1).modPow(BigInteger(phi).divide(BigInteger(BigInteger(r).subtract(1)).divide(BigInteger(2))),n) == 1 || 
		BigInteger(g1).modPow(BigInteger(phi).divide(BigInteger(BigInteger(s).subtract(1)).divide(BigInteger(2))),n) == 1 || 
		BigInteger(g1).modPow(BigInteger(2).multiply(r),BigInteger(r).pow(2)) == 1 ||  
		BigInteger(g1).modPow(BigInteger(r).subtract(1),BigInteger(r).pow(2)) == 1 
		)
{
	BigInteger(g1).add(BigInteger(1));
	document.write("<br>g1 iterace<br>");
}
	
g2 =  BigInteger(g1).modPow(S2,n);
g3 =  BigInteger(g1).modPow(S3,n);

Aseed = BigInteger(g1).modPow(S1,n);


// issueAtt 1

w1 = randomNum(w1Size);
w2 = randomNum(w2Size);

rand = randomNum(k);
rand_issue1 = BigInteger(rand).toString(10);

CI = BigInteger(BigInteger( BigInteger(h1).modPow(w1,p) ).multiply( BigInteger(h2).modPow(w2,p) )).modPow(BigInteger(1),p);
CI_issue1 = BigInteger(CI).toString(10);

r1 = randomNum(k + m + w1Size);
r2 = randomNum(k + m + w2Size);
CiI = BigInteger(BigInteger( BigInteger(h1).modPow(r1,p) ).multiply( BigInteger(h2).modPow(r2,p) )).modPow(BigInteger(1),p);

fce = BigInteger(CI).toString(10) + BigInteger(CiI).toString(10) + BigInteger(rand).toString(10);
hash = CryptoJS.SHA1(fce);
e = BigInteger.parse(hash,16);
e_issue1 = BigInteger(e).toString(10);

z1 = BigInteger(r1).subtract( BigInteger(e).multiply(w1) );
z1_issue1 = BigInteger(z1).toString(10);

z2 = BigInteger(r2).subtract( BigInteger(e).multiply(w2) );
z2_issue1 = BigInteger(z2).toString(10);


/*
// test
pom = BigInteger(BigInteger(BigInteger( BigInteger(CI).modPow(e,p) ).multiply( BigInteger(h1).modPow(z1,p) )).multiply( BigInteger(h2).modPow(z2,p) )).modPow(BigInteger(1),p);
fce = BigInteger(CI).toString(10) + BigInteger(pom).toString(10) + BigInteger(rand).toString(10);
hash = CryptoJS.SHA1(fce);
e_test1 = BigInteger.parse(hash,16);

document.write("<br>");
document.write("issueAtt 1");
document.write("<br>");
document.write("e - hash test:<br>");
document.write(e);
document.write("<br>");

if ( BigInteger(e).compare(e_test1) == 0) document.write("OK"); else document.write("FAIL<br>");
document.write("<br>");
*/


// issueAtt 2

Aiseed = BigInteger(BigInteger( BigInteger(g1).modPow(w1,n) ).multiply( BigInteger(g2).modPow(w2,n) )).modPow(BigInteger(1),n);
Aiseed_issue2 = BigInteger(rand).toString(10);

rand = randomNum(k);
rand_issue2 = BigInteger(rand).toString(10);

r1 = randomNum(k + m + w1Size);
r2 = randomNum(k + m + w2Size);
CiI = BigInteger(BigInteger( BigInteger(h1).modPow(r1,p) ).multiply( BigInteger(h2).modPow(r2,p) )).modPow(BigInteger(1),p);
AiseedI = BigInteger(BigInteger( BigInteger(g1).modPow(r1,n) ).multiply( BigInteger(g2).modPow(r2,n) )).modPow(BigInteger(1),n);

fce = BigInteger(CI).toString(10) + BigInteger(CiI).toString(10) + BigInteger(Aiseed).toString(10) + BigInteger(AiseedI).toString(10) + BigInteger(rand).toString(10);
hash = CryptoJS.SHA1(fce);
e = BigInteger.parse(hash,16);
e_issue2 = BigInteger(e).toString(10);

z1 = BigInteger(r1).subtract( BigInteger(e).multiply(w1) );
z1_issue2 = BigInteger(z1).toString(10);


z2 = BigInteger(r2).subtract( BigInteger(e).multiply(w2) );
z2_issue2 = BigInteger(z2).toString(10);



/*
// test
pom1 = BigInteger(BigInteger(BigInteger( BigInteger(CI).modPow(e,p) ).multiply( BigInteger(h1).modPow(z1,p) )).multiply( BigInteger(h2).modPow(z2,p) )).modPow(BigInteger(1),p);
pom2 = BigInteger(BigInteger(BigInteger( BigInteger(Aiseed).modPow(e,n) ).multiply( BigInteger(g1).modPow(z1,n) )).multiply( BigInteger(g2).modPow(z2,n) )).modPow(BigInteger(1),n);
fce = BigInteger(CI).toString(10) + BigInteger(pom1).toString(10) + BigInteger(Aiseed).toString(10) + BigInteger(pom2).toString(10) + BigInteger(rand).toString(10);
hash = CryptoJS.SHA1(fce);
e_test2 = BigInteger.parse(hash,16);

document.write("<br>");
document.write("issueAtt 2");
document.write("<br>");
document.write("e - hash test:<br>");
document.write(e);
document.write("<br>");
if ( BigInteger(e).compare(e_test2) == 0) document.write("OK"); else document.write("FAIL<br>");
document.write("<br>");
*/

a = BigInteger(inverseMod2(Aiseed,n ) ).multiply(Aseed);
b = BigInteger( BigInteger(a).modPow(BigInteger(1),n) ).modPow( BigInteger(r).subtract(1), BigInteger(r).pow(2) );
c = BigInteger(g3).modPow( BigInteger(r).subtract(1), BigInteger(r).pow(2) );
d = BigInteger(inverseMod2( BigInteger( BigInteger(c).subtract(1) ).divide(r) ,r ));
e = BigInteger(BigInteger(BigInteger(b).subtract(1)).divide(r)).multiply(d);
wrr = BigInteger(e).modPow(BigInteger(1),r);
wrrSize = bitSize(wrr);


// proveAtt

Ks = randomNum(KSSize); 
A = BigInteger(Aseed).modPow(Ks,n);
C1 = BigInteger(g3).modPow((BigInteger(Ks).multiply(wrr)),n);
C2 = BigInteger(g3).modPow(Ks,n);
r1 = randomNum(k + KSSize + m + w1Size); //479
r2 = randomNum(k + KSSize + m + w2Size); //399
r3 = randomNum(k + KSSize + m + wrrSize); //599
rS = randomNum(k + KSSize + m); //319
Aseedi = BigInteger(BigInteger(BigInteger(g1).modPow(r1,n)).multiply(BigInteger(g2).modPow(r2,n)).multiply(BigInteger(g3).modPow(r3,n))).modPow(BigInteger(1),n);
Ai = BigInteger(Aseed).modPow(rS,n);
C1i = BigInteger(g3).modPow(r3,n);
C2i = BigInteger(g3).modPow(rS,n);

fce = BigInteger(A).toString(10) + BigInteger(Ai).toString(10) + BigInteger(Aseed).toString(10) + BigInteger(Aseedi).toString(10) + BigInteger(C1).toString(10) + BigInteger(C2).toString(10) + BigInteger(C1i).toString(10) + BigInteger(C2i).toString(10);
hash = CryptoJS.SHA1(fce);
e = BigInteger.parse(hash,16);
e_prove = BigInteger(e).toString(10);

z1 = BigInteger(r1).subtract(BigInteger(e).multiply(Ks).multiply(w1));
z1_prove = BigInteger(z1).toString(10);
z2 = BigInteger(r2).subtract(BigInteger(e).multiply(Ks).multiply(w2));
z2_prove = BigInteger(z2).toString(10);
z3 = BigInteger(r3).subtract(BigInteger(e).multiply(Ks).multiply(wrr));
z3_prove = BigInteger(z3).toString(10);
zS = BigInteger(rS).subtract(BigInteger(e).multiply(Ks));
zs_prove = BigInteger(zS).toString(10);

 
 ////////////////////////////////////////////////////////////////////////////////////

/* // proveAtt na straně Verifier
var Aseediu = BigInteger(BigInteger(BigInteger(A).modPow(e,n)).multiply(BigInteger(g1).modPow(z1,n)).multiply(BigInteger(g2).modPow(z2,n)).multiply(BigInteger(g3).modPow(z3,n))).modPow(BigInteger(1),n);
var Aiu = BigInteger(BigInteger(BigInteger(A).modPow(e,n)).multiply(BigInteger(Aseed).modPow(zS,n))).modPow(BigInteger(1),n);
var C1iu = BigInteger(BigInteger(BigInteger(C1).modPow(e,n)).multiply(BigInteger(g3).modPow(z3,n))).modPow(BigInteger(1),n);
var C2iu = BigInteger(BigInteger(BigInteger(C2).modPow(e,n)).multiply(BigInteger(g3).modPow(zS,n))).modPow(BigInteger(1),n);
*/

// ověření na terminálu
a = BigInteger(C1).modPow(BigInteger(r).subtract(1),BigInteger(r).pow(BigInteger(2)));	
b = BigInteger(C2).modPow(BigInteger(r).subtract(1),BigInteger(r).pow(BigInteger(2)));	
c = inverseMod2(BigInteger(BigInteger(b).subtract(1)).divide(r),r);
rev = BigInteger(BigInteger(BigInteger(BigInteger(a).subtract(1)).divide(r)).multiply(c)).modPow(BigInteger(1),r);


// odeslání hodnot
postMessage([w1.toString(10),w2.toString(10),rand_issue1,e_issue1,z1_issue1,z2_issue1,CI_issue1,rand_issue2,e_issue2,z1_issue2,z2_issue2,Aiseed_issue2,wrr.toString(10),h1.toString(10),h2.toString(10),g1.toString(10),g2.toString(10),g3.toString(10),Aseed.toString(10),A.toString(10),C1.toString(10),C2.toString(10),e_prove,z1_prove,z2_prove,z3_prove,zs_prove,rev.toString(10)]);
