/** * Invert this field element and return the result. The inverse is found via Fermat's little * theorem: a^p congruent a mod p and therefore a^(p-2) congruent a^-1 mod p * * @return The inverse of this field element. */ public Ed25519FieldElement invert() { Ed25519FieldElement f0, f1; // comments describe how exponent is created // 2 == 2 * 1 f0 = this.square(); // 9 == 9 f1 = this.pow2to9(); // 11 == 9 + 2 f0 = f0.multiply(f1); // 2^252 - 2^2 f1 = this.pow2to252sub4(); // 2^255 - 2^5 for (int i = 1; i < 4; ++i) { f1 = f1.square(); } // 2^255 - 21 return f1.multiply(f0); }
@Override public boolean equals(final Object obj) { if (!(obj instanceof Ed25519FieldElement)) { return false; } final Ed25519FieldElement f = (Ed25519FieldElement) obj; return this.encode().equals(f.encode()); }
/** * Encodes a given field element in its 32 byte 2^8 bit representation. This is done in two steps. * Step 1: Reduce the value of the field element modulo p. Step 2: Convert the field element to * the 32 byte representation. * * @return Encoded field element (32 bytes). */ public Ed25519EncodedFieldElement encode() { // Step 1: final Ed25519FieldElement g = this.modP(); final int[] gValues = g.getRaw(); final int h0 = gValues[0]; final int h1 = gValues[1]; final int h2 = gValues[2]; final int h3 = gValues[3]; final int h4 = gValues[4]; final int h5 = gValues[5]; final int h6 = gValues[6]; final int h7 = gValues[7]; final int h8 = gValues[8]; final int h9 = gValues[9]; // Step 2: final byte[] s = new byte[32]; s[0] = (byte) (h0); s[1] = (byte) (h0 >> 8); s[2] = (byte) (h0 >> 16); s[3] = (byte) ((h0 >> 24) | (h1 << 2)); s[4] = (byte) (h1 >> 6); s[5] = (byte) (h1 >> 14); s[6] = (byte) ((h1 >> 22) | (h2 << 3)); s[7] = (byte) (h2 >> 5); s[8] = (byte) (h2 >> 13); s[9] = (byte) ((h2 >> 21) | (h3 << 5)); s[10] = (byte) (h3 >> 3); s[11] = (byte) (h3 >> 11); s[12] = (byte) ((h3 >> 19) | (h4 << 6)); s[13] = (byte) (h4 >> 2); s[14] = (byte) (h4 >> 10); s[15] = (byte) (h4 >> 18); s[16] = (byte) (h5); s[17] = (byte) (h5 >> 8); s[18] = (byte) (h5 >> 16); s[19] = (byte) ((h5 >> 24) | (h6 << 1)); s[20] = (byte) (h6 >> 7); s[21] = (byte) (h6 >> 15); s[22] = (byte) ((h6 >> 23) | (h7 << 3)); s[23] = (byte) (h7 >> 5); s[24] = (byte) (h7 >> 13); s[25] = (byte) ((h7 >> 21) | (h8 << 4)); s[26] = (byte) (h8 >> 4); s[27] = (byte) (h8 >> 12); s[28] = (byte) ((h8 >> 20) | (h9 << 6)); s[29] = (byte) (h9 >> 2); s[30] = (byte) (h9 >> 10); s[31] = (byte) (h9 >> 18); return new Ed25519EncodedFieldElement(s); }
/** * Computes this field element to the power of (2^9) and returns the result. * * @return This field element to the power of (2^9). */ private Ed25519FieldElement pow2to9() { Ed25519FieldElement f; // 2 == 2 * 1 f = this.square(); // 4 == 2 * 2 f = f.square(); // 8 == 2 * 4 f = f.square(); // 9 == 1 + 8 return this.multiply(f); }
/** * Calculates and returns one of the square roots of u / v. * * <pre>{@code * x = (u * v^3) * (u * v^7)^((p - 5) / 8) ==> x^2 = +-(u / v). * }</pre> * * Note that this means x can be sqrt(u / v), -sqrt(u / v), +i * sqrt(u / v), -i * sqrt(u / v). * * @param u The nominator of the fraction. * @param v The denominator of the fraction. * @return The square root of u / v. */ public static Ed25519FieldElement sqrt(final Ed25519FieldElement u, final Ed25519FieldElement v) { Ed25519FieldElement x; final Ed25519FieldElement v3; // v3 = v^3 v3 = v.square().multiply(v); // x = (v3^2) * v * u = u * v^7 x = v3.square().multiply(v).multiply(u); // x = (u * v^7)^((q - 5) / 8) x = x.pow2to252sub4().multiply(x); // 2^252 - 3 // x = u * v^3 * (u * v^7)^((q - 5) / 8) x = v3.multiply(u).multiply(x); return x; }
/** * Computes this field element to the power of (2^252 - 4) and returns the result. This is a * helper function for calculating the square root. * * @return This field element to the power of (2^252 - 4). */ private Ed25519FieldElement pow2to252sub4() { Ed25519FieldElement f0, f1, f2; // 2 == 2 * 1 f0 = this.square(); // 9 f1 = this.pow2to9(); // 11 == 9 + 2 f0 = f0.multiply(f1); // 22 == 2 * 11 f0 = f0.square(); // 31 == 22 + 9 f0 = f1.multiply(f0); // 2^6 - 2^1 f1 = f0.square(); // 2^10 - 2^5 for (int i = 1; i < 5; ++i) { f1 = f1.square(); } // 2^10 - 2^0 f0 = f1.multiply(f0); // 2^11 - 2^1 f1 = f0.square(); // 2^20 - 2^10 for (int i = 1; i < 10; ++i) { f1 = f1.square(); } // 2^20 - 2^0 f1 = f1.multiply(f0); // 2^21 - 2^1 f2 = f1.square(); // 2^40 - 2^20 for (int i = 1; i < 20; ++i) { f2 = f2.square(); } // 2^40 - 2^0 f1 = f2.multiply(f1); // 2^41 - 2^1 f1 = f1.square(); // 2^50 - 2^10 for (int i = 1; i < 10; ++i) { f1 = f1.square(); } // 2^50 - 2^0 f0 = f1.multiply(f0); // 2^51 - 2^1 f1 = f0.square(); // 2^100 - 2^50 for (int i = 1; i < 50; ++i) { f1 = f1.square(); } // 2^100 - 2^0 f1 = f1.multiply(f0); // 2^101 - 2^1 f2 = f1.square(); // 2^200 - 2^100 for (int i = 1; i < 100; ++i) { f2 = f2.square(); } // 2^200 - 2^0 f1 = f2.multiply(f1); // 2^201 - 2^1 f1 = f1.square(); // 2^250 - 2^50 for (int i = 1; i < 50; ++i) { f1 = f1.square(); } // 2^250 - 2^0 f0 = f1.multiply(f0); // 2^251 - 2^1 f0 = f0.square(); // 2^252 - 2^2 return f0.square(); }