/** * Constant-time conditional move. Well, actually it is a conditional copy. * Logic is inspired by the SUPERCOP implementation at: * https://github.com/floodyberry/supercop/blob/master/crypto_sign/ed25519/ref10/fe_cmov.c * * @param val the other field element. * @param b must be 0 or 1, otherwise results are undefined. * @return a copy of this if b == 0, or a copy of val if b == 1. * @since 0.9.36 */ @Override public FieldElement cmov(FieldElement val, int b) { Ed25519FieldElement that = (Ed25519FieldElement) val; b = -b; int[] result = new int[10]; for (int i = 0; i < 10; i++) { result[i] = this.t[i]; int x = this.t[i] ^ that.t[i]; x &= b; result[i] ^= x; } return new Ed25519FieldElement(this.f, result); }
/** * h = -f * <p> * TODO-CR BR: see above. * <p> * Preconditions: * </p><ul> * <li>|f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. * </ul><p> * Postconditions: * </p><ul> * <li>|h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. * </ul> * * @return The field element (-1) * this. */ public FieldElement negate() { int[] h = new int[10]; for (int i = 0; i < 10; i++) { h[i] = - t[i]; } return new Ed25519FieldElement(f, h); }
/** * h = f - g * <p> * Can overlap h with f or g. * <p> * TODO-CR BR: See above. * <p> * Preconditions: * </p><ul> * <li>|f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. * <li>|g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. * </ul><p> * Postconditions: * </p><ul> * <li>|h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. * </ul> * * @param val The field element to subtract. * @return The field element this - val. **/ public FieldElement subtract(FieldElement val) { int[] g = ((Ed25519FieldElement)val).t; int[] h = new int[10]; for (int i = 0; i < 10; i++) { h[i] = t[i] - g[i]; } return new Ed25519FieldElement(f, h); }
/** * h = f + g * <p> * TODO-CR BR: h is allocated via new, probably not a good idea. Do we need the copying into temp variables if we do that? * <p> * Preconditions: * </p><ul> * <li>|f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. * <li>|g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. * </ul><p> * Postconditions: * </p><ul> * <li>|h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. * </ul> * * @param val The field element to add. * @return The field element this + val. */ public FieldElement add(FieldElement val) { int[] g = ((Ed25519FieldElement)val).t; int[] h = new int[10]; for (int i = 0; i < 10; i++) { h[i] = t[i] + g[i]; } return new Ed25519FieldElement(f, h); }
h[8] = (int) h8; h[9] = (int) h9; return new Ed25519FieldElement(f, h);
h[8] = (int) h8; h[9] = (int) h9; return new Ed25519FieldElement(f, h);
h[8] = (int) h8; h[9] = (int) h9; return new Ed25519FieldElement(f, h);
@Test (expected = IllegalArgumentException.class) public void cannotConstructFieldElementWithoutField() { // Assert: new Ed25519FieldElement(null, new int[9]); }
protected FieldElement getNonZeroFieldElement() { final int[] t = new int[10]; t[0] = 5; return new Ed25519FieldElement(MathUtils.getField(), t); }
/** * Gets a random field element where |t[i]| <= 2^24 for 0 <= i <= 9. * * @return The field element. */ public static FieldElement getRandomFieldElement() { final int[] t = new int[10]; for (int j=0; j<10; j++) { t[j] = random.nextInt(1 << 25) - (1 << 24); } return new Ed25519FieldElement(getField(), t); }
protected FieldElement getZeroFieldElement() { return new Ed25519FieldElement(MathUtils.getField(), new int[10]); }
@Test public void canConstructFieldElementFromArrayWithCorrectLength() { // Assert: new Ed25519FieldElement(MathUtils.getField(), new int[10]); }
@Test (expected = IllegalArgumentException.class) public void cannotConstructFieldElementFromArrayWithIncorrectLength() { // Assert: new Ed25519FieldElement(MathUtils.getField(), new int[9]); }
@Test public void isNegativeReturnsCorrectResult() { for (int i=0; i<10000; i++) { // Arrange: final int[] t = new int[10]; for (int j=0; j<10; j++) { t[j] = random.nextInt(1 << 28) - (1 << 27); } final boolean isNegative = MathUtils.toBigInteger(t).mod(MathUtils.getQ()).mod(new BigInteger("2")).equals(BigInteger.ONE); final FieldElement f = new Ed25519FieldElement(MathUtils.getField(), t); // Assert: Assert.assertThat(MathUtils.getField().getEncoding().isNegative(f), IsEqual.equalTo(isNegative)); } } }
@Test public void encodeReturnsCorrectByteArray() { for (int i=0; i<10000; i++){ // Arrange: final int[] t = new int[10]; for (int j=0; j<10; j++) { t[j] = random.nextInt(1 << 28) - (1 << 27); } final FieldElement fieldElement1 = new Ed25519FieldElement(MathUtils.getField(), t); final BigInteger b = MathUtils.toBigInteger(t); // Act: final byte[] bytes = MathUtils.getField().getEncoding().encode(fieldElement1); // Assert: Assert.assertThat(bytes, IsEqual.equalTo(MathUtils.toByteArray(b.mod(MathUtils.getQ())))); } }
@Test public void encodeReturnsCorrectByteArrayForSimpleFieldElements() { // Arrange: final int[] t1 = new int[10]; final int[] t2 = new int[10]; t2[0] = 1; final FieldElement fieldElement1 = new Ed25519FieldElement(MathUtils.getField(), t1); final FieldElement fieldElement2 = new Ed25519FieldElement(MathUtils.getField(), t2); // Act: final byte[] bytes1 = MathUtils.getField().getEncoding().encode(fieldElement1); final byte[] bytes2 = MathUtils.getField().getEncoding().encode(fieldElement2); // Assert: Assert.assertThat(bytes1, IsEqual.equalTo(MathUtils.toByteArray(BigInteger.ZERO))); Assert.assertThat(bytes2, IsEqual.equalTo(MathUtils.toByteArray(BigInteger.ONE))); }
/** * Constant-time conditional move. Well, actually it is a conditional copy. * Logic is inspired by the SUPERCOP implementation at: * https://github.com/floodyberry/supercop/blob/master/crypto_sign/ed25519/ref10/fe_cmov.c * * @param val the other field element. * @param b must be 0 or 1, otherwise results are undefined. * @return a copy of this if $b == 0$, or a copy of val if $b == 1$. */ @Override public FieldElement cmov(FieldElement val, int b) { Ed25519FieldElement that = (Ed25519FieldElement) val; b = -b; int[] result = new int[10]; for (int i = 0; i < 10; i++) { result[i] = this.t[i]; int x = this.t[i] ^ that.t[i]; x &= b; result[i] ^= x; } return new Ed25519FieldElement(this.f, result); }
/** * $h = f + g$ * <p> * TODO-CR BR: $h$ is allocated via new, probably not a good idea. Do we need the copying into temp variables if we do that? * <p> * Preconditions: * </p><ul> * <li>$|f|$ bounded by $1.1*2^{25},1.1*2^{24},1.1*2^{25},1.1*2^{24},$ etc. * <li>$|g|$ bounded by $1.1*2^{25},1.1*2^{24},1.1*2^{25},1.1*2^{24},$ etc. * </ul><p> * Postconditions: * </p><ul> * <li>$|h|$ bounded by $1.1*2^{26},1.1*2^{25},1.1*2^{26},1.1*2^{25},$ etc. * </ul> * * @param val The field element to add. * @return The field element this + val. */ public FieldElement add(FieldElement val) { int[] g = ((Ed25519FieldElement)val).t; int[] h = new int[10]; for (int i = 0; i < 10; i++) { h[i] = t[i] + g[i]; } return new Ed25519FieldElement(f, h); }
/** * $h = -f$ * <p> * TODO-CR BR: see above. * <p> * Preconditions: * </p><ul> * <li>$|f|$ bounded by $1.1*2^{25},1.1*2^{24},1.1*2^{25},1.1*2^{24},$ etc. * </ul><p> * Postconditions: * </p><ul> * <li>$|h|$ bounded by $1.1*2^{25},1.1*2^{24},1.1*2^{25},1.1*2^{24},$ etc. * </ul> * * @return The field element (-1) * this. */ public FieldElement negate() { int[] h = new int[10]; for (int i = 0; i < 10; i++) { h[i] = - t[i]; } return new Ed25519FieldElement(f, h); }
h[8] = (int) h8; h[9] = (int) h9; return new Ed25519FieldElement(f, h);