public static byte[] step4(SMState bstate, byte[] input, Provider prov) throws OTRException
	{
	    /* Read from input to find the mpis */
	    MPI[] msg3 = unserializeMPIArray(input);

	    bstate.smProgState = PROG_CHEATED;
	    
	    MPI[] msg4 = new MPI[3];

	    if (checkGroupElem(msg3[0], prov) || checkGroupElem(msg3[1], prov) ||
		    checkGroupElem(msg3[5], prov) || checkExpon(msg3[3], prov) ||
		    checkExpon(msg3[4], prov) || checkExpon(msg3[7], prov))  {
	    	throw new OTRException("Invalid Parameter");
	    }

	    /* Verify Alice's coordinate equality proof */
	    if (checkEqualCoords(msg3[2], msg3[3], msg3[4], msg3[0], msg3[1], bstate, 6, prov)!=0)
	    	throw new OTRException("Invalid Parameter");
	    
	    /* Find Pa/Pb and Qa/Qb */
	    MPI inv = prov.invm(bstate.p, new MPI(MODULUS_S));
	    bstate.pab = prov.mulm(msg3[0], inv, new MPI(MODULUS_S));
	    inv = prov.invm(bstate.q, new MPI(MODULUS_S));
	    bstate.qab = prov.mulm(msg3[1], inv, new MPI(MODULUS_S));
   

	    /* Verify Alice's log equality proof */
	    if (checkEqualLogs(msg3[6], msg3[7], msg3[5], bstate, 7, prov)!=0){
	    	throw new OTRException("Proof checking failed");
	    }

	    /* Calculate Rb and proof */
	    msg4[0] = prov.powm(bstate.qab, bstate.x3, new MPI(MODULUS_S));
	    MPI[] res = proofEqualLogs(bstate,8, prov);
	    msg4[1]=res[0];
	    msg4[2]=res[1];
	    
	    byte[] output = serializeMPIArray(msg4);

	    /* Calculate Rab and verify that secrets match */
	    
	    MPI rab = prov.powm(msg3[5], bstate.x3, new MPI(MODULUS_S));
	    //Util.checkBytes("rab", rab.getValue());
	    //Util.checkBytes("pab", bstate.pab.getValue());
	    int comp = prov.compareMPI(rab, bstate.pab);

	    bstate.smProgState = (comp!=0) ? PROG_FAILED : PROG_SUCCEEDED;

	    return output;
	}