Fixing issue https://github.com/google/tink/issues/224. (#268)

Problem was: isOnCurve did not reduce the limbs before checking for equality.

PiperOrigin-RevId: 272245293
diff --git a/java/src/main/java/com/google/crypto/tink/subtle/Ed25519.java b/java/src/main/java/com/google/crypto/tink/subtle/Ed25519.java
index 0cf1530..a290320 100644
--- a/java/src/main/java/com/google/crypto/tink/subtle/Ed25519.java
+++ b/java/src/main/java/com/google/crypto/tink/subtle/Ed25519.java
@@ -145,6 +145,9 @@
       Field25519.mult(rhs, rhs, D);
       // rhs = z^4 + D * x^2 * y^2
       Field25519.sum(rhs, z4);
+      // Field25519.mult reduces its output, but Field25519.sub does not, so we have to manually
+      // reduce it here.
+      Field25519.reduce(rhs, rhs);
       // z^2 (y^2 - x^2) == z^4 + D * x^2 * y^2
       return Bytes.equal(Field25519.contract(lhs), Field25519.contract(rhs));
     }
diff --git a/java/src/main/java/com/google/crypto/tink/subtle/Field25519.java b/java/src/main/java/com/google/crypto/tink/subtle/Field25519.java
index 1795008..5a24d60 100644
--- a/java/src/main/java/com/google/crypto/tink/subtle/Field25519.java
+++ b/java/src/main/java/com/google/crypto/tink/subtle/Field25519.java
@@ -213,6 +213,27 @@
   }
 
   /**
+   * Reduce a field element by calling reduceSizeByModularReduction and reduceCoefficients.
+   *
+   * @param input An input array of any length. If the array has 19 elements, it will be used as
+   * temporary buffer and its contents changed.
+   * @param output An output array of size LIMB_CNT. After the call |output[i]| < 2^26 will hold.
+   *
+   */
+  static void reduce(long[] input, long[] output) {
+    long[] tmp;
+    if (input.length == 19) {
+      tmp = input;
+    } else {
+      tmp = new long[19];
+      System.arraycopy(input, 0, tmp, 0, input.length);
+    }
+    reduceSizeByModularReduction(tmp);
+    reduceCoefficients(tmp);
+    System.arraycopy(tmp, 0, output, 0, LIMB_CNT);
+  }
+
+  /**
    * Reduce a long form to a reduced-size form by taking the input mod 2^255 - 19.
    *
    * On entry: |output[i]| < 14*2^54
@@ -306,11 +327,8 @@
   static void mult(long[] output, long[] in, long[] in2) {
     long[] t = new long[19];
     product(t, in, in2);
-    // |t[i]| < 14*2^54
-    reduceSizeByModularReduction(t);
-    reduceCoefficients(t);
     // |t[i]| < 2^26
-    System.arraycopy(t, 0, output, 0, LIMB_CNT);
+    reduce(t, output);
   }
 
   /**
@@ -363,10 +381,7 @@
     squareInner(t, in);
     // |t[i]| < 14*2^54 because the largest product of two limbs will be < 2^(27+27) and SquareInner
     // adds together, at most, 14 of those products.
-    reduceSizeByModularReduction(t);
-    reduceCoefficients(t);
-    // |t[i]| < 2^26
-    System.arraycopy(t, 0, output, 0, LIMB_CNT);
+    reduce(t, output);
   }
 
   /**
diff --git a/java/src/test/java/com/google/crypto/tink/subtle/Ed25519Test.java b/java/src/test/java/com/google/crypto/tink/subtle/Ed25519Test.java
index b8d83b6..e8f7393 100644
--- a/java/src/test/java/com/google/crypto/tink/subtle/Ed25519Test.java
+++ b/java/src/test/java/com/google/crypto/tink/subtle/Ed25519Test.java
@@ -55,4 +55,11 @@
       assertArrayEquals(originalPublicKey, publicKey);
     }
   }
+
+  /** Test for https://github.com/google/tink/issues/224. */
+  @Test
+  public void testScalarMultWithBase() throws Exception {
+    byte[] scalar = Hex.decode("521784c403e6fb32d48e0da85969a82f5952856bde4471a42b3fa56fd8b96c0d");
+    Ed25519.scalarMultWithBaseToBytes(scalar);
+  }
 }