X25519 { @SuppressWarnings("NarrowingCompoundAssignment") public static byte[] computeSharedSecret(byte[] privateKey, byte[] peersPublicValue) throws InvalidKeyException { if (privateKey.length != Field25519.FIELD_LEN) { throw new InvalidKeyException("Private key must have 32 bytes."); } long[] x = new long[Field25519.LIMB_CNT + 1]; byte[] e = Arrays.copyOf(privateKey, Field25519.FIELD_LEN); e[0] &= 248; e[31] &= 127; e[31] |= 64; Curve25519.curveMult(x, e, peersPublicValue); return Field25519.contract(x); }  @SuppressWarnings("NarrowingCompoundAssignment") static byte[] generatePrivateKey(); @SuppressWarnings("NarrowingCompoundAssignment") static byte[] computeSharedSecret(byte[] privateKey, byte[] peersPublicValue); static byte[] publicFromPrivate(byte[] privateKey);  }
@Test public void testComputeSharedSecretWithRfcIteration() throws Exception { byte[] k = new byte[32]; k[0] = 9; byte[] prevK = k; k = X25519.computeSharedSecret(k, prevK); assertEquals( "422c8e7a6227d7bca1350b3e2bb7279f7897b87bb6854b783c60e80311ae3079", TestUtil.hexEncode(k)); for (int i = 0; i < 999; i++) { byte[] tmp = k; k = X25519.computeSharedSecret(k, prevK); prevK = tmp; } assertEquals( "684cf59ba83309552800ef566f2f4d3c1c3887c49360e3875f2eb94d99532c51", TestUtil.hexEncode(k)); }
@Test public void testComputeSharedSecretWithWycheproofVectors() throws Exception { JSONObject json = WycheproofTestUtil.readJson("../wycheproof/testvectors/x25519_test.json"); int errors = 0; int cntSkippedTests = 0; JSONArray testGroups = json.getJSONArray("testGroups"); for (int i = 0; i < testGroups.length(); i++) { JSONObject group = testGroups.getJSONObject(i); JSONArray tests = group.getJSONArray("tests"); String curve = group.getString("curve"); for (int j = 0; j < tests.length(); j++) { JSONObject testcase = tests.getJSONObject(j); String tcId = String.format( "testcase %d (%s)", testcase.getInt("tcId"), testcase.getString("comment")); String result = testcase.getString("result"); String hexPubKey = testcase.getString("public"); String hexPrivKey = testcase.getString("private"); String expectedSharedSecret = testcase.getString("shared"); if (!curve.equals("curve25519")) { System.out.printf("Skipping %s, unknown curve name: %s", tcId, curve); cntSkippedTests++; continue; } try { String sharedSecret = Hex.encode(X25519.computeSharedSecret(Hex.decode(hexPrivKey), Hex.decode(hexPubKey))); if (result.equals("invalid")) { System.out.printf( "FAIL %s: accepting invalid parameters, shared secret: %s%n", tcId, sharedSecret); errors++; } else if (!expectedSharedSecret.equals(sharedSecret)) { System.out.printf( "FAIL %s: incorrect shared secret, computed: %s, expected: %s%n", tcId, sharedSecret, expectedSharedSecret); errors++; } } catch (GeneralSecurityException ex) { if (result.equals("valid")) { System.out.printf("FAIL %s, exception %s%n", tcId, ex); errors++; } } catch (Exception ex) { System.out.printf("FAIL %s, exception %s%n", tcId, ex); errors++; } } } System.out.printf("Number of tests skipped: %d", cntSkippedTests); assertEquals(0, errors); }