public Signature sign(String message){
		//System.out.println("\n---------------Sign protocol--------------");
		this.updateKey();
		this.rpk = revoc.getRpk();
		//System.out.println("\nUser: "+this.pseudo+"\n\nMessage to sign: " + message);
		long start = System.currentTimeMillis();
		Signature signature = null;
		try{
			EllipticCurve ec = new EllipticCurve(new secp256r1()); 
			Utils utils = new Utils();
			// Choose randomly RoE
			BigInteger roE = new BigInteger(opk.getOrder().bitLength()-1,new Random());
			// Compute E
			ECPoint E0 = opk.getGenerator().multiply(roE);
			ECPoint E1 = mpk.geth().add(opk.getH1().multiply(roE));
			ECPoint E2 = mpk.geth().add(opk.getH2().multiply(roE));
			if(!ec.onCurve(E0) || !ec.onCurve(E1) || !ec.onCurve(E2)){
				//System.out.println("Problem with points E: not on mother curve!!");
			}
			// Compute ACOM and s
			BigInteger roM = utils.getRandomBinaryString(Constants.Kn/2);
			BigInteger ACOM = (mpk.getA().multiply(ipk.geta2().modPow(roM,ipk.getn()))).mod(ipk.getn());
			BigInteger s = (mpk.getEPrime().add(Constants.expKe)).multiply(roM);
			// Compute BCOM and l
			BigInteger roR = utils.getRandomBinaryString(Constants.Kl/2);
			BigInteger BCOM = (mpk.getB().multiply(rpk.getw().modPow(roR,rpk.getl()))).mod(rpk.getl());
			BigInteger t = mpk.getEPrime().multiply(roR);
			// Choose randomly mu's
			BigInteger mux = utils.getRandomBinaryString(Constants.lam + Constants.Ks + Constants.Kc);
			BigInteger mus = utils.getRandomBinaryString(Constants.Kn/2 + Constants.Ks + Constants.Kc);
			BigInteger mueprime = utils.getRandomBinaryString(Constants.KePrime + Constants.Ks + Constants.Kc);
			BigInteger mut = utils.getRandomBinaryString(Constants.Kl/2 + Constants.Ks + Constants.Kc);
			BigInteger muE = new BigInteger(opk.getOrder().bitLength()-1,new Random());
			// Compute VcomCipher
			ECPoint V0 = opk.getGenerator().multiply(muE);
			ECPoint V1 = (opk.getGenerator().multiply(mux)).add(opk.getH1().multiply(muE)); 
			ECPoint V2 = (opk.getGenerator().multiply(mux)).add(opk.getH2().multiply(muE));
			if(!ec.onCurve(V0) || !ec.onCurve(V1) || !ec.onCurve(V2)){
				//System.out.println("Problem with points V: not on mother curve!!");
			}
			// Compute Vmpk
			BigInteger Vmpk = (((ipk.geta1().modPow(mux,ipk.getn()).multiply(ipk.geta2().modPow(mus,ipk.getn()))).mod(ipk.getn())).multiply(ACOM.modPow(mueprime.negate(),ipk.getn())).mod(ipk.getn()));
			// Compute Vrev
			BigInteger Vrev = ((rpk.getw().modPow(mut,rpk.getl())).multiply(BCOM.modPow(mueprime.negate(),rpk.getl()))).mod(this.rpk.getl());
			// Compute hash
			MessageDigest md = MessageDigest.getInstance("SHA-256");
			String E = E0.getx().toString()+E0.gety().toString()+E1.getx().toString()+E1.gety().toString()+E2.getx().toString()+E2.gety().toString();
			String V = V0.getx().toString()+V0.gety().toString()+V1.getx().toString()+V1.gety().toString()+V2.getx().toString()+V2.gety().toString();
			String reste = ACOM.toString() + BCOM.toString() + V + Vmpk.toString() + Vrev.toString();
			String string = E + reste + message;
			md.update(string.getBytes("UTF-8"));
		    BigInteger c = new BigInteger(1,md.digest());
		    // Compute tau's
		    BigInteger taux = c.multiply(this.msk.getx()).add(mux);
	    	BigInteger taus = c.multiply(s).add(mus);
    		BigInteger taut = c.multiply(t).add(mut);
			BigInteger tauePrime = c.multiply(this.mpk.getEPrime()).add(mueprime);
			BigInteger tauE = (c.multiply(roE).add(muE)).mod(this.getOpeningManager().getOpk().getOrder());
			// Signature formating
			signature = new Signature(E0,E1,E2,ACOM,BCOM,c,taux,taus,tauePrime,taut,tauE,this.index);
			//System.out.println("\nSignature:\nE = { E0, E1, E2 }\nACOM = "+ ACOM+"\nBCOM = "+BCOM+"\nc = "+c+"\nTx = "+taux+"\nTs = "+taus+"\nTe' = "+tauePrime+"\nTt = "+taut+"\nTE = "+ tauE +"\nIndex = " + this.index);
		}
		catch(Exception e){
			e.printStackTrace();
		}
		long end = System.currentTimeMillis();
		//System.out.println("\nExecution time was "+(end-start)+" ms.");
		//System.out.println("\n---------------DONE--------------");
		return signature;
	}