/** 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 * */ public static byte[] step1(SMState astate) { /* Initialize the sm state or update the secret */ astate.x2 = randomExponent(); astate.x3 = randomExponent(); BigInteger[] msg1 = new BigInteger[6]; msg1[0] = modPower(astate.g1, astate.x2, biModulus); BigInteger[] res = proofKnowLog(astate.g1, astate.x2, 1); msg1[1] = res[0]; msg1[2] = res[1]; msg1[3] = modPower(astate.g1, astate.x3, biModulus); res = proofKnowLog(astate.g1, astate.x3, 2); msg1[4] = res[0]; msg1[5] = res[1]; byte[] ret = serializeBigIntegerArray(msg1); astate.ProgState = ProgState.OK; return ret; }
/* Proof of knowledge of coordinates with first components being equal */ private static BigInteger[] proofEqualCoords(SMState state, BigInteger r, int version) { BigInteger r1 = randomExponent(); BigInteger r2 = randomExponent(); /* Compute the value of c, as c = h(g3^r1, g1^r1 g2^r2) */ BigInteger temp1 = modPower(state.g1, r1, biModulus); BigInteger temp2 = modPower(state.g2, r2, biModulus); temp2 = multipleMod(temp1, temp2, biModulus); temp1 = modPower(state.g3, r1, biModulus); BigInteger c = hash(version, temp1, temp2); /* Compute the d values, as d1 = r1 - r c, d2 = r2 - secret c */ temp1 = multipleMod(r, c, biOrder); BigInteger d1 = subtractMod(r1, temp1, biOrder); temp1 = multipleMod(state.secret, c, biOrder); BigInteger d2 = subtractMod(r2, temp1, biOrder); BigInteger[] ret = new BigInteger[3]; ret[0] = c; ret[1] = d1; ret[2] = d2; return ret; }
/* Proof of knowledge of logs with exponents being equal */ private static BigInteger[] proofEqualLogs(SMState state, int version) { BigInteger r = randomExponent(); /* Compute the value of c, as c = h(g1^r, (Qa/Qb)^r) */ BigInteger temp1 = modPower(state.g1, r, biModulus); BigInteger temp2 = modPower(state.qab, r, biModulus); BigInteger c = hash(version, temp1, temp2); /* Compute the d values, as d = r - x3 c */ temp1 = multipleMod(state.x3, c, biOrder); BigInteger d = subtractMod(r, temp1, biOrder); BigInteger[] ret = new BigInteger[2]; ret[0] = c; ret[1] = d; return ret; }
/* Verify a proof of knowledge of coordinates with first components being equal */ private static bool checkEqualCoords(BigInteger c, BigInteger d1, BigInteger d2, BigInteger p, BigInteger q, SMState state, int version) { /* 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 = modPower(state.g3, d1, biModulus); BigInteger temp3 = modPower(p, c, biModulus); BigInteger temp1 = multipleMod(temp2, temp3, biModulus); temp2 = modPower(state.g1, d1, biModulus); temp3 = modPower(state.g2, d2, biModulus); temp2 = multipleMod(temp2, temp3, biModulus); temp3 = modPower(q, c, biModulus); temp2 = multipleMod(temp3, temp2, biModulus); BigInteger cprime = hash(version, temp1, temp2); return c != cprime; }
/* Verify a proof of knowledge of logs with exponents being equal */ private static bool checkEqualLogs(BigInteger c, BigInteger d, BigInteger r, SMState state, int version) { /* 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 = modPower(state.g1, d, biModulus); BigInteger temp3 = modPower(state.g3o, c, biModulus); BigInteger temp1 = multipleMod(temp2, temp3, biModulus); temp3 = modPower(state.qab, d, biModulus); temp2 = modPower(r, c, biModulus); temp2 = multipleMod(temp3, temp2, biModulus); BigInteger cprime = hash(version, temp1, temp2); return c != cprime; }
/** Receives the readonly 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. * */ public static void step5(SMState astate, byte[] input) { /* Read from input to find the BigIntegers */ BigInteger[] msg4 = unserializeBigIntegerArray(input); astate.ProgState = ProgState.Cheated; if (checkGroupElem(msg4[0]) || checkExpon(msg4[2])) { astate.ProgStateInformation = "Invalid Parameter"; return; } /* Verify Bob's log equality proof */ if (checkEqualLogs(msg4[1], msg4[2], msg4[0], astate, 8)) { astate.ProgStateInformation = "Invalid Parameter"; return; } /* Calculate Rab and verify that secrets match */ BigInteger rab = modPower(msg4[0], astate.x3, biModulus); astate.ProgState = (rab != astate.pab) ? ProgState.Failed : ProgState.Succeeded; }
/** Create readonly message in SMP exchange. Input is a message generated * by otrl_sm_step3. Output is a serialized BigInteger 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. * */ public static byte[] step4(SMState bstate, byte[] input) { /* Read from input to find the BigIntegers */ BigInteger[] msg3 = unserializeBigIntegerArray(input); bstate.ProgState = ProgState.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])) { bstate.ProgStateInformation = "Invalid Parameter"; return new byte[0]; } /* Verify Alice's coordinate equality proof */ if (checkEqualCoords(msg3[2], msg3[3], msg3[4], msg3[0], msg3[1], bstate, 6)) { bstate.ProgStateInformation = "Invalid Parameter"; return new byte[0]; } /* Find Pa/Pb and Qa/Qb */ BigInteger inv = modInverse(bstate.p, biModulus); bstate.pab = multipleMod(msg3[0], inv, biModulus); inv = modInverse(bstate.q, biModulus); bstate.qab = multipleMod(msg3[1], inv, biModulus); /* Verify Alice's log equality proof */ if (checkEqualLogs(msg3[6], msg3[7], msg3[5], bstate, 7)) { bstate.ProgStateInformation = "Proof checking failed"; return new byte[0]; } /* Calculate Rb and proof */ msg4[0] = modPower(bstate.qab, bstate.x3, biModulus); BigInteger[] res = proofEqualLogs(bstate, 8); msg4[1] = res[0]; msg4[2] = res[1]; byte[] output = serializeBigIntegerArray(msg4); /* Calculate Rab and verify that secrets match */ BigInteger rab = modPower(msg3[5], bstate.x3, biModulus); bstate.ProgState = (rab != bstate.pab) ? ProgState.Failed : ProgState.Succeeded; return output; }
/** Create third message in SMP exchange. Input is a message generated * by otrl_sm_step2b. Output is a serialized BigInteger 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 * */ public static byte[] step3(SMState astate, byte[] input) { /* Read from input to find the BigIntegers */ astate.ProgState = ProgState.Cheated; BigInteger[] msg2 = unserializeBigIntegerArray(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])) { astate.ProgStateInformation = "Invalid Parameter"; return new byte[0]; } 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) || checkKnowLog(msg2[4], msg2[5], astate.g1, msg2[3], 4)) { astate.ProgStateInformation = "Proof checking failed"; return new byte[0]; } /* Combine the two halves from Bob and Alice and determine g2 and g3 */ astate.g2 = modPower(msg2[0], astate.x2, biModulus); astate.g3 = modPower(msg2[3], astate.x3, biModulus); /* Verify Bob's coordinate equality proof */ if (checkEqualCoords(msg2[8], msg2[9], msg2[10], msg2[6], msg2[7], astate, 5)) { astate.ProgStateInformation = "Invalid Parameter"; return new byte[0]; } /* Calculate P and Q values for Alice */ BigInteger r = randomExponent(); astate.p = modPower(astate.g3, r, biModulus); msg3[0] = astate.p; BigInteger qa1 = modPower(astate.g1, r, biModulus); BigInteger qa2 = modPower(astate.g2, astate.secret, biModulus); astate.q = multipleMod(qa1, qa2, biModulus); msg3[1] = astate.q; BigInteger[] res = proofEqualCoords(astate, r, 6); msg3[2] = res[0]; msg3[3] = res[1]; msg3[4] = res[2]; /* Calculate Ra and proof */ BigInteger inv = modInverse(msg2[6], biModulus); astate.pab = multipleMod(astate.p, inv, biModulus); inv = modInverse(msg2[7], biModulus); astate.qab = multipleMod(astate.q, inv, biModulus); msg3[5] = modPower(astate.qab, astate.x3, biModulus); res = proofEqualLogs(astate, 7); msg3[6] = res[0]; msg3[7] = res[1]; byte[] output = serializeBigIntegerArray(msg3); astate.ProgState = ProgState.OK; return output; }
/** 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 BigInteger 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 * */ public static byte[] step2b(SMState bstate) { BigInteger[] msg2 = new BigInteger[11]; msg2[0] = modPower(bstate.g1, bstate.x2, biModulus); BigInteger[] res = proofKnowLog(bstate.g1, bstate.x2, 3); msg2[1] = res[0]; msg2[2] = res[1]; msg2[3] = modPower(bstate.g1, bstate.x3, biModulus); 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(); bstate.p = modPower(bstate.g3, r, biModulus); msg2[6] = bstate.p; BigInteger qb1 = modPower(bstate.g1, r, biModulus); BigInteger qb2 = modPower(bstate.g2, bstate.secret, biModulus); bstate.q = multipleMod(qb1, qb2, biModulus); 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 serializeBigIntegerArray(msg2); }
/** Receive the first message in SMP exchange, which was generated by * step1. Input is saved until the user inputs their secret * information. No output. * */ public static void step2a(SMState bstate, byte[] input) { /* Initialize the sm state if needed */ bstate.ProgState = ProgState.Cheated; /* Read from input to find the BigIntegers */ BigInteger[] msg1 = unserializeBigIntegerArray(input); if (checkGroupElem(msg1[0]) || checkExpon(msg1[2]) || checkGroupElem(msg1[3]) || checkExpon(msg1[5])) { bstate.ProgStateInformation = "Invalid parameter"; return; } /* 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) || checkKnowLog(msg1[4], msg1[5], bstate.g1, msg1[3], 2)) { bstate.ProgStateInformation = "Proof checking failed"; return; } /* 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 = modPower(msg1[0], bstate.x2, biModulus); bstate.g3 = modPower(msg1[3], bstate.x3, biModulus); bstate.ProgState = ProgState.OK; }