/* * Java OTR library Copyright (C) 2008-2009 Ian Goldberg, Muhaimeen Ashraf, * Andrew Chung, Can Tang * * This library is free software; you can redistribute it and/or modify it under * the terms of version 2.1 of the GNU Lesser General Public License as * published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* Ported to otr4j by devrandom */ package net.java.otr4j.crypto; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.math.BigInteger; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import net.java.otr4j.io.OtrInputStream; import net.java.otr4j.io.OtrOutputStream; import net.java.otr4j.io.SerializationUtils; public class SM { static public class SMState { BigInteger secret, x2, x3, g1, g2, g3, g3o, p, q, pab, qab; public int nextExpected; boolean receivedQuestion; public int smProgState; public SMState() { g1 = new BigInteger(1, SM.GENERATOR_S); smProgState = SM.PROG_OK; } public boolean isReceivedQuestion() { return receivedQuestion; } } static public class SMException extends Exception { private static final long serialVersionUID = 1L; public SMException() { super(""); } public SMException(Throwable t) { super(t.getMessage()); } public SMException(String s) { super(s); } }; public static final int EXPECT1 = 0; public static final int EXPECT2 = 1; public static final int EXPECT3 = 2; public static final int EXPECT4 = 3; public static final int EXPECT5 = 4; public static final int PROG_OK = 0; public static final int PROG_CHEATED = -2; public static final int PROG_FAILED = -1; public static final int PROG_SUCCEEDED = 1; public static final int MSG1_LEN = 6; public static final int MSG2_LEN = 11; public static final int MSG3_LEN = 8; public static final int MSG4_LEN = 3; public static final BigInteger MODULUS_S = new BigInteger( "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF", 16); public static final BigInteger MODULUS_MINUS_2 = new BigInteger( "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFD", 16); public static final BigInteger ORDER_S = new BigInteger( "7FFFFFFFFFFFFFFFE487ED5110B4611A62633145C06E0E68" + "948127044533E63A0105DF531D89CD9128A5043CC71A026E" + "F7CA8CD9E69D218D98158536F92F8A1BA7F09AB6B6A8E122" + "F242DABB312F3F637A262174D31BF6B585FFAE5B7A035BF6" + "F71C35FDAD44CFD2D74F9208BE258FF324943328F6722D9E" + "E1003E5C50B1DF82CC6D241B0E2AE9CD348B1FD47E9267AF" + "C1B2AE91EE51D6CB0E3179AB1042A95DCF6A9483B84B4B36" + "B3861AA7255E4C0278BA36046511B993FFFFFFFFFFFFFFFF", 16); public static final byte[] GENERATOR_S = Util.hexStringToBytes("02"); public static final int MOD_LEN_BITS = 1536; public static final int MOD_LEN_BYTES = 192; /** Generate a random exponent */ public static BigInteger randomExponent() { SecureRandom sr = new SecureRandom(); byte[] sb = new byte[MOD_LEN_BYTES]; sr.nextBytes(sb); return new BigInteger(1, sb); } /** * Hash one or two BigIntegers. To hash only one BigInteger, b may be set to * NULL. */ public static BigInteger hash(int version, BigInteger a, BigInteger b) throws SMException { try { MessageDigest sha256 = MessageDigest.getInstance("SHA-256"); sha256.update((byte) version); sha256.update(SerializationUtils.writeMpi(a)); if (b != null) sha256.update(SerializationUtils.writeMpi(b)); return new BigInteger(1, sha256.digest()); } catch (NoSuchAlgorithmException e) { throw new SMException("cannot find SHA-256"); } catch (IOException e) { throw new SMException("cannot serialize bigint"); } } public static byte[] serialize(BigInteger[] ints) throws SMException { try { ByteArrayOutputStream out = new ByteArrayOutputStream(); OtrOutputStream oos = new OtrOutputStream(out); oos.writeInt(ints.length); for (BigInteger i : ints) { oos.writeBigInt(i); } byte[] b = out.toByteArray(); oos.close(); return b; } catch (IOException ex) { throw new SMException("cannot serialize bigints"); } } public static BigInteger[] unserialize(byte[] bytes) throws SMException { try { ByteArrayInputStream in = new ByteArrayInputStream(bytes); OtrInputStream ois = new OtrInputStream(in); int len = ois.readInt(); if (len > 100) { ois.close(); throw new SMException("Too many ints"); } BigInteger[] ints = new BigInteger[len]; for (int i = 0; i < len; i++) { ints[i] = ois.readBigInt(); } ois.close(); return ints; } catch (IOException ex) { throw new SMException("cannot unserialize bigints"); } } /** * Check that an BigInteger is in the right range to be a (non-unit) group * element */ public static boolean checkGroupElem(BigInteger g) { return g.compareTo(BigInteger.valueOf(2)) < 0 || g.compareTo(SM.MODULUS_MINUS_2) > 0; } /** * Check that an BigInteger is in the right range to be a (non-zero) * exponent */ public static boolean checkExpon(BigInteger x) { return x.compareTo(BigInteger.ONE) < 0 || x.compareTo(SM.ORDER_S) >= 0; } /** * Proof of knowledge of a discrete logarithm * * @throws SMException */ public static BigInteger[] proofKnowLog(BigInteger g, BigInteger x, int version) throws SMException { BigInteger r = randomExponent(); BigInteger temp = g.modPow(r, SM.MODULUS_S); BigInteger c = hash(version, temp, null); temp = x.multiply(c).mod(ORDER_S); BigInteger d = r.subtract(temp).mod(ORDER_S); BigInteger[] ret = new BigInteger[2]; ret[0] = c; ret[1] = d; return ret; } /** * Verify a proof of knowledge of a discrete logarithm. Checks that c = * h(g^d x^c) * * @throws SMException */ public static int checkKnowLog(BigInteger c, BigInteger d, BigInteger g, BigInteger x, int version) throws SMException { BigInteger gd = g.modPow(d, MODULUS_S); BigInteger xc = x.modPow(c, MODULUS_S); BigInteger gdxc = gd.multiply(xc).mod(MODULUS_S); BigInteger hgdxc = hash(version, gdxc, null); return hgdxc.compareTo(c); } /** * Proof of knowledge of coordinates with first components being equal * * @throws SMException */ public static BigInteger[] proofEqualCoords(SMState state, BigInteger r, int version) throws SMException { BigInteger r1 = randomExponent(); BigInteger r2 = randomExponent(); /* Compute the value of c, as c = h(g3^r1, g1^r1 g2^r2) */ BigInteger temp1 = state.g1.modPow(r1, MODULUS_S); BigInteger temp2 = state.g2.modPow(r2, MODULUS_S); temp2 = temp1.multiply(temp2).mod(MODULUS_S); temp1 = state.g3.modPow(r1, MODULUS_S); BigInteger c = hash(version, temp1, temp2); /* Compute the d values, as d1 = r1 - r c, d2 = r2 - secret c */ temp1 = r.multiply(c).mod(ORDER_S); BigInteger d1 = r1.subtract(temp1).mod(ORDER_S); temp1 = state.secret.multiply(c).mod(ORDER_S); BigInteger d2 = r2.subtract(temp1).mod(ORDER_S); BigInteger[] ret = new BigInteger[3]; ret[0] = c; ret[1] = d1; ret[2] = d2; return ret; } /** * Verify a proof of knowledge of coordinates with first components being * equal * * @throws SMException */ public static int checkEqualCoords(BigInteger c, BigInteger d1, BigInteger d2, BigInteger p, BigInteger q, SMState state, int version) throws SMException { /* To verify, we test that hash(g3^d1 * p^c, g1^d1 * g2^d2 * q^c) = c * If indeed c = hash(g3^r1, g1^r1 g2^r2), d1 = r1 - r*c, * d2 = r2 - secret*c. And if indeed p = g3^r, q = g1^r * g2^secret * Then we should have that: * hash(g3^d1 * p^c, g1^d1 * g2^d2 * q^c) * = hash(g3^(r1 - r*c + r*c), g1^(r1 - r*c + q*c) * * g2^(r2 - secret*c + secret*c)) * = hash(g3^r1, g1^r1 g2^r2) * = c */ BigInteger temp2 = state.g3.modPow(d1, MODULUS_S); BigInteger temp3 = p.modPow(c, MODULUS_S); BigInteger temp1 = temp2.multiply(temp3).mod(MODULUS_S); temp2 = state.g1.modPow(d1, MODULUS_S); temp3 = state.g2.modPow(d2, MODULUS_S); temp2 = temp2.multiply(temp3).mod(MODULUS_S); temp3 = q.modPow(c, MODULUS_S); temp2 = temp3.multiply(temp2).mod(MODULUS_S); BigInteger cprime = hash(version, temp1, temp2); return c.compareTo(cprime); } /** * Proof of knowledge of logs with exponents being equal * * @throws SMException */ public static BigInteger[] proofEqualLogs(SMState state, int version) throws SMException { BigInteger r = randomExponent(); /* Compute the value of c, as c = h(g1^r, (Qa/Qb)^r) */ BigInteger temp1 = state.g1.modPow(r, MODULUS_S); BigInteger temp2 = state.qab.modPow(r, MODULUS_S); BigInteger c = hash(version, temp1, temp2); /* Compute the d values, as d = r - x3 c */ temp1 = state.x3.multiply(c).mod(ORDER_S); BigInteger d = r.subtract(temp1).mod(ORDER_S); BigInteger[] ret = new BigInteger[2]; ret[0] = c; ret[1] = d; return ret; } /** * Verify a proof of knowledge of logs with exponents being equal * * @throws SMException */ public static int checkEqualLogs(BigInteger c, BigInteger d, BigInteger r, SMState state, int version) throws SMException { /* Here, we recall the exponents used to create g3. * If we have previously seen g3o = g1^x where x is unknown * during the DH exchange to produce g3, then we may proceed with: * * To verify, we test that hash(g1^d * g3o^c, qab^d * r^c) = c * If indeed c = hash(g1^r1, qab^r1), d = r1- x * c * And if indeed r = qab^x * Then we should have that: * hash(g1^d * g3o^c, qab^d r^c) * = hash(g1^(r1 - x*c + x*c), qab^(r1 - x*c + x*c)) * = hash(g1^r1, qab^r1) * = c */ BigInteger temp2 = state.g1.modPow(d, MODULUS_S); BigInteger temp3 = state.g3o.modPow(c, MODULUS_S); BigInteger temp1 = temp2.multiply(temp3).mod(MODULUS_S); temp3 = state.qab.modPow(d, MODULUS_S); temp2 = r.modPow(c, MODULUS_S); temp2 = temp3.multiply(temp2).mod(MODULUS_S); BigInteger cprime = hash(version, temp1, temp2); return c.compareTo(cprime); } /** * Create first message in SMP exchange. Input is Alice's secret value which * this protocol aims to compare to Bob's. The return value is a serialized * BigInteger array whose elements correspond to the following: [0] = g2a, * Alice's half of DH exchange to determine g2 [1] = c2, [2] = d2, Alice's * ZK proof of knowledge of g2a exponent [3] = g3a, Alice's half of DH * exchange to determine g3 [4] = c3, [5] = d3, Alice's ZK proof of * knowledge of g3a exponent * * @throws SMException */ public static byte[] step1(SMState astate, byte[] secret) throws SMException { /* Initialize the sm state or update the secret */ //Util.checkBytes("secret", secret); BigInteger secret_mpi = new BigInteger(1, secret); astate.secret = secret_mpi; astate.receivedQuestion = false; astate.x2 = randomExponent(); astate.x3 = randomExponent(); BigInteger[] msg1 = new BigInteger[6]; msg1[0] = astate.g1.modPow(astate.x2, MODULUS_S); BigInteger[] res = proofKnowLog(astate.g1, astate.x2, 1); msg1[1] = res[0]; msg1[2] = res[1]; msg1[3] = astate.g1.modPow(astate.x3, MODULUS_S); res = proofKnowLog(astate.g1, astate.x3, 2); msg1[4] = res[0]; msg1[5] = res[1]; byte[] ret = serialize(msg1); astate.smProgState = PROG_OK; return ret; } /** * Receive the first message in SMP exchange, which was generated by step1. * Input is saved until the user inputs their secret information. No output. * * @throws SMException */ public static void step2a(SMState bstate, byte[] input, boolean received_question) throws SMException { /* Initialize the sm state if needed */ bstate.receivedQuestion = received_question; bstate.smProgState = PROG_CHEATED; /* Read from input to find the mpis */ BigInteger[] msg1 = unserialize(input); if (checkGroupElem(msg1[0]) || checkExpon(msg1[2]) || checkGroupElem(msg1[3]) || checkExpon(msg1[5])) { throw new SMException("Invalid parameter"); } /* Store Alice's g3a value for later in the protocol */ bstate.g3o = msg1[3]; /* Verify Alice's proofs */ if (checkKnowLog(msg1[1], msg1[2], bstate.g1, msg1[0], 1) != 0 || checkKnowLog(msg1[4], msg1[5], bstate.g1, msg1[3], 2) != 0) { throw new SMException("Proof checking failed"); } /* Create Bob's half of the generators g2 and g3 */ bstate.x2 = randomExponent(); bstate.x3 = randomExponent(); /* Combine the two halves from Bob and Alice and determine g2 and g3 */ bstate.g2 = msg1[0].modPow(bstate.x2, MODULUS_S); //Util.checkBytes("g2b", bstate.g2.getValue()); bstate.g3 = msg1[3].modPow(bstate.x3, MODULUS_S); //Util.checkBytes("g3b", bstate.g3.getValue()); bstate.smProgState = PROG_OK; } /** * Create second message in SMP exchange. Input is Bob's secret value. * Information from earlier steps in the exchange is taken from Bob's state. * Output is a serialized mpi array whose elements correspond to the * following: [0] = g2b, Bob's half of DH exchange to determine g2 [1] = c2, * [2] = d2, Bob's ZK proof of knowledge of g2b exponent [3] = g3b, Bob's * half of DH exchange to determine g3 [4] = c3, [5] = d3, Bob's ZK proof of * knowledge of g3b exponent [6] = pb, [7] = qb, Bob's halves of the (Pa/Pb) * and (Qa/Qb) values [8] = cp, [9] = d5, [10] = d6, Bob's ZK proof that pb, * qb formed correctly * * @throws SMException */ public static byte[] step2b(SMState bstate, byte[] secret) throws SMException { /* Convert the given secret to the proper form and store it */ //Util.checkBytes("secret", secret); BigInteger secret_mpi = new BigInteger(1, secret); bstate.secret = secret_mpi; BigInteger[] msg2 = new BigInteger[11]; msg2[0] = bstate.g1.modPow(bstate.x2, MODULUS_S); BigInteger[] res = proofKnowLog(bstate.g1, bstate.x2, 3); msg2[1] = res[0]; msg2[2] = res[1]; msg2[3] = bstate.g1.modPow(bstate.x3, MODULUS_S); res = proofKnowLog(bstate.g1, bstate.x3, 4); msg2[4] = res[0]; msg2[5] = res[1]; /* Calculate P and Q values for Bob */ BigInteger r = randomExponent(); //BigInteger r = new BigInteger(SM.GENERATOR_S); bstate.p = bstate.g3.modPow(r, MODULUS_S); //Util.checkBytes("Pb", bstate.p.getValue()); msg2[6] = bstate.p; BigInteger qb1 = bstate.g1.modPow(r, MODULUS_S); //Util.checkBytes("Qb1", qb1.getValue()); BigInteger qb2 = bstate.g2.modPow(bstate.secret, MODULUS_S); //Util.checkBytes("Qb2", qb2.getValue()); //Util.checkBytes("g2", bstate.g2.getValue()); //Util.checkBytes("secret", bstate.secret.getValue()); bstate.q = qb1.multiply(qb2).mod(MODULUS_S); //Util.checkBytes("Qb", bstate.q.getValue()); msg2[7] = bstate.q; res = proofEqualCoords(bstate, r, 5); msg2[8] = res[0]; msg2[9] = res[1]; msg2[10] = res[2]; /* Convert to serialized form */ return serialize(msg2); } /** * Create third message in SMP exchange. Input is a message generated by * otrl_sm_step2b. Output is a serialized mpi array whose elements * correspond to the following: [0] = pa, [1] = qa, Alice's halves of the * (Pa/Pb) and (Qa/Qb) values [2] = cp, [3] = d5, [4] = d6, Alice's ZK proof * that pa, qa formed correctly [5] = ra, calculated as (Qa/Qb)^x3 where x3 * is the exponent used in g3a [6] = cr, [7] = d7, Alice's ZK proof that ra * is formed correctly * * @throws SMException */ public static byte[] step3(SMState astate, byte[] input) throws SMException { /* Read from input to find the mpis */ astate.smProgState = PROG_CHEATED; BigInteger[] msg2 = unserialize(input); if (checkGroupElem(msg2[0]) || checkGroupElem(msg2[3]) || checkGroupElem(msg2[6]) || checkGroupElem(msg2[7]) || checkExpon(msg2[2]) || checkExpon(msg2[5]) || checkExpon(msg2[9]) || checkExpon(msg2[10])) { throw new SMException("Invalid Parameter"); } BigInteger[] msg3 = new BigInteger[8]; /* Store Bob's g3a value for later in the protocol */ astate.g3o = msg2[3]; /* Verify Bob's knowledge of discreet log proofs */ if (checkKnowLog(msg2[1], msg2[2], astate.g1, msg2[0], 3) != 0 || checkKnowLog(msg2[4], msg2[5], astate.g1, msg2[3], 4) != 0) { throw new SMException("Proof checking failed"); } /* Combine the two halves from Bob and Alice and determine g2 and g3 */ astate.g2 = msg2[0].modPow(astate.x2, MODULUS_S); //Util.checkBytes("g2a", astate.g2.getValue()); astate.g3 = msg2[3].modPow(astate.x3, MODULUS_S); //Util.checkBytes("g3a", astate.g3.getValue()); /* Verify Bob's coordinate equality proof */ if (checkEqualCoords(msg2[8], msg2[9], msg2[10], msg2[6], msg2[7], astate, 5) != 0) throw new SMException("Invalid Parameter"); /* Calculate P and Q values for Alice */ BigInteger r = randomExponent(); //BigInteger r = new BigInteger(SM.GENERATOR_S); astate.p = astate.g3.modPow(r, MODULUS_S); //Util.checkBytes("Pa", astate.p.getValue()); msg3[0] = astate.p; BigInteger qa1 = astate.g1.modPow(r, MODULUS_S); //Util.checkBytes("Qa1", qa1.getValue()); BigInteger qa2 = astate.g2.modPow(astate.secret, MODULUS_S); //Util.checkBytes("Qa2", qa2.getValue()); //Util.checkBytes("g2", astate.g2.getValue()); //Util.checkBytes("secret", astate.secret.getValue()); astate.q = qa1.multiply(qa2).mod(MODULUS_S); msg3[1] = astate.q; //Util.checkBytes("Qa", astate.q.getValue()); BigInteger[] res = proofEqualCoords(astate, r, 6); msg3[2] = res[0]; msg3[3] = res[1]; msg3[4] = res[2]; /* Calculate Ra and proof */ BigInteger inv = msg2[6].modInverse(MODULUS_S); astate.pab = astate.p.multiply(inv).mod(MODULUS_S); inv = msg2[7].modInverse(MODULUS_S); astate.qab = astate.q.multiply(inv).mod(MODULUS_S); msg3[5] = astate.qab.modPow(astate.x3, MODULUS_S); res = proofEqualLogs(astate, 7); msg3[6] = res[0]; msg3[7] = res[1]; byte[] output = serialize(msg3); astate.smProgState = PROG_OK; return output; } /** * Create final message in SMP exchange. Input is a message generated by * otrl_sm_step3. Output is a serialized mpi array whose elements correspond * to the following: [0] = rb, calculated as (Qa/Qb)^x3 where x3 is the * exponent used in g3b [1] = cr, [2] = d7, Bob's ZK proof that rb is formed * correctly This method also checks if Alice and Bob's secrets were the * same. If so, it returns NO_ERROR. If the secrets differ, an INV_VALUE * error is returned instead. * * @throws SMException */ public static byte[] step4(SMState bstate, byte[] input) throws SMException { /* Read from input to find the mpis */ BigInteger[] msg3 = unserialize(input); bstate.smProgState = PROG_CHEATED; BigInteger[] msg4 = new BigInteger[3]; if (checkGroupElem(msg3[0]) || checkGroupElem(msg3[1]) || checkGroupElem(msg3[5]) || checkExpon(msg3[3]) || checkExpon(msg3[4]) || checkExpon(msg3[7])) { throw new SMException("Invalid Parameter"); } /* Verify Alice's coordinate equality proof */ if (checkEqualCoords(msg3[2], msg3[3], msg3[4], msg3[0], msg3[1], bstate, 6) != 0) throw new SMException("Invalid Parameter"); /* Find Pa/Pb and Qa/Qb */ BigInteger inv = bstate.p.modInverse(MODULUS_S); bstate.pab = msg3[0].multiply(inv).mod(MODULUS_S); inv = bstate.q.modInverse(MODULUS_S); bstate.qab = msg3[1].multiply(inv).mod(MODULUS_S); /* Verify Alice's log equality proof */ if (checkEqualLogs(msg3[6], msg3[7], msg3[5], bstate, 7) != 0) { throw new SMException("Proof checking failed"); } /* Calculate Rb and proof */ msg4[0] = bstate.qab.modPow(bstate.x3, MODULUS_S); BigInteger[] res = proofEqualLogs(bstate, 8); msg4[1] = res[0]; msg4[2] = res[1]; byte[] output = serialize(msg4); /* Calculate Rab and verify that secrets match */ BigInteger rab = msg3[5].modPow(bstate.x3, MODULUS_S); //Util.checkBytes("rab", rab.getValue()); //Util.checkBytes("pab", bstate.pab.getValue()); int comp = rab.compareTo(bstate.pab); bstate.smProgState = (comp != 0) ? PROG_FAILED : PROG_SUCCEEDED; return output; } /** * Receives the final SMP message, which was generated in otrl_sm_step. This * method checks if Alice and Bob's secrets were the same. If so, it returns * NO_ERROR. If the secrets differ, an INV_VALUE error is returned instead. * * @throws SMException */ public static void step5(SMState astate, byte[] input) throws SMException { /* Read from input to find the mpis */ BigInteger[] msg4 = unserialize(input); astate.smProgState = PROG_CHEATED; if (checkGroupElem(msg4[0]) || checkExpon(msg4[2])) { throw new SMException("Invalid Parameter"); } /* Verify Bob's log equality proof */ if (checkEqualLogs(msg4[1], msg4[2], msg4[0], astate, 8) != 0) throw new SMException("Invalid Parameter"); /* Calculate Rab and verify that secrets match */ BigInteger rab = msg4[0].modPow(astate.x3, MODULUS_S); //Util.checkBytes("rab", rab.getValue()); //Util.checkBytes("pab", astate.pab.getValue()); int comp = rab.compareTo(astate.pab); if (comp != 0) { //System.out.println("checking failed"); } astate.smProgState = (comp != 0) ? PROG_FAILED : PROG_SUCCEEDED; return; } }