/** * 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); }
/** * 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(); }