Commit 6e0464aa authored by Robert Ransom's avatar Robert Ransom
Browse files

Clamp curve25519-donna outputs to 0..2**255-20 (inclusive)

This doesn't change the test results.
parent ad4fcf7a
Loading
Loading
Loading
Loading
+43 −0
Original line number Diff line number Diff line
@@ -420,6 +420,17 @@ fexpand(limb *output, const u8 *input) {
#error "This code only works when >> does sign-extension on negative numbers"
#endif

/* Return 1 if input1 >= input2; return 0 otherwise.  input1 and
   input2 must have absolute value less than 2**29. */
static s32
sub_s32_geq(s32 input1, s32 input2) {
  s32 a = input1 - input2; /* a >= 0 iff input1 >= input2 */
  s32 b = a >> 31; /* b == 0 if input1 >= input2; b == -1 otherwise */
  s32 c = b + 1;

  return c;
}

/* Take a fully reduced polynomial form number and contract it into a
 * little-endian, 32-byte array
 */
@@ -471,6 +482,38 @@ fcontract(u8 *output, limb *input) {
     negative values will remain in the array until the end.
   */

  /* Now ensure that input is not greater than 2**255 - 20. */
  {
    limb tmp[10];
    /* sub_s32_geq uses considerably fewer operations than sub_s32_equal did.
     */
    s32 out_of_bounds_p
                     = sub_s32_geq(input[9], 0x1ffffff);
    out_of_bounds_p &= sub_s32_geq(input[8], 0x3ffffff);
    out_of_bounds_p &= sub_s32_geq(input[7], 0x1ffffff);
    out_of_bounds_p &= sub_s32_geq(input[6], 0x3ffffff);
    out_of_bounds_p &= sub_s32_geq(input[5], 0x1ffffff);
    out_of_bounds_p &= sub_s32_geq(input[4], 0x3ffffff);
    out_of_bounds_p &= sub_s32_geq(input[3], 0x1ffffff);
    out_of_bounds_p &= sub_s32_geq(input[2], 0x3ffffff);
    out_of_bounds_p &= sub_s32_geq(input[1], 0x1ffffff);
    out_of_bounds_p &= sub_s32_geq(input[0], 0x3ffffff - 18);

    tmp[9] = (-out_of_bounds_p) &  0x1ffffff;
    tmp[8] = (-out_of_bounds_p) &  0x3ffffff;
    tmp[7] = (-out_of_bounds_p) &  0x1ffffff;
    tmp[6] = (-out_of_bounds_p) &  0x3ffffff;
    tmp[5] = (-out_of_bounds_p) &  0x1ffffff;
    tmp[4] = (-out_of_bounds_p) &  0x3ffffff;
    tmp[3] = (-out_of_bounds_p) &  0x1ffffff;
    tmp[2] = (-out_of_bounds_p) &  0x3ffffff;
    tmp[1] = (-out_of_bounds_p) &  0x1ffffff;
    tmp[0] = (-out_of_bounds_p) & (0x3ffffff - 18);

    fdifference(tmp, input); /* XXXX could use s32 arithmetic here instead */
    memcpy(input, tmp, sizeof(tmp));
  }

  input[1] <<= 2;
  input[2] <<= 3;
  input[3] <<= 5;