diff --git a/gajumaru-core/src/main/java/swiss/qpq/gajumaru/core/crypto/Ed25519.java b/gajumaru-core/src/main/java/swiss/qpq/gajumaru/core/crypto/Ed25519.java index b20161a..cac5d08 100644 --- a/gajumaru-core/src/main/java/swiss/qpq/gajumaru/core/crypto/Ed25519.java +++ b/gajumaru-core/src/main/java/swiss/qpq/gajumaru/core/crypto/Ed25519.java @@ -3,13 +3,13 @@ * Project: Gajumaru Core Java Libraries * * This program is dual-licensed: - * 1) Under the GNU Affero General Public License as published by the Free - * Software Foundation, either version 3 of the License, or (at your option) + * 1) Under the GNU Affero General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) * any later version (AGPL-3.0-or-later). * * 2) Under a commercial/proprietary license available directly from QPQ AG. - * If you wish to use this software outside the strict constraints of the - * AGPLv3 (e.g. within a closed-source or proprietary product), you must + * If you wish to use this software outside the strict constraints of the + * AGPLv3 (e.g. within a closed-source or proprietary product), you must * purchase a commercial license from QPQ AG. * * Authors: @@ -23,7 +23,7 @@ package swiss.qpq.gajumaru.core.crypto; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; -import java.math.BigInteger; + import swiss.qpq.gajumaru.core.tools.CryptoUtils; /** @@ -32,50 +32,77 @@ import swiss.qpq.gajumaru.core.tools.CryptoUtils; */ public final class Ed25519 { - private static final long TWO_TO_25 = 1L << 25; - private static final long TWO_TO_26 = 1L << 26; - private static final BigInteger P_FIELD = BigInteger.valueOf(2).pow(255).subtract(BigInteger.valueOf(19)); - // Precomputed limbs for Ed25519 constants (Radix 2^25.5) from RFC 8032 - private static final long[] BX = {52811034L, 25909283L, 16144682L, 17082669L, 27570973L, 30858332L, 40966398L, 8378388L, 20764389L, 8758491L}; - private static final long[] BY = {40265304L, 26843545L, 13421772L, 20132659L, 26843545L, 6710886L, 53687091L, 13421772L, 40265318L, 26843545L}; + private static final long[] BX = {52811034L, 25909283L, 16144682L, 17082669L, 27570973L, 30858332L, 40966398L, 8378388L, 20764389L, 8758491L}; + private static final long[] BY = {40265304L, 26843545L, 13421772L, 20132659L, 26843545L, 6710886L, 53687091L, 13421772L, 40265318L, 26843545L}; private static final long[] BXY = {28827043L, 27438313L, 39759291L, 244362L, 8635006L, 11264893L, 19351346L, 13413597L, 16611511L, 27139452L}; - private static final long[] D = {56195235L, 13857412L, 51736253L, 6949390L, 114729L, 24766616L, 60832955L, 30306712L, 48412415L, 21499315L}; - private static final long[] D2 = {45281625L, 27714825L, 36363642L, 13898781L, 229458L, 15978800L, 54557047L, 27058993L, 29715967L, 9444199L}; - private static final long[] I = {17187054L, 16663501L, 25252512L, 26698L, 9007192L, 25056900L, 31130252L, 16580L, 54723919L, 2713947L}; + private static final long[] D = {56195235L, 13857412L, 51736253L, 6949390L, 114729L, 24766616L, 60832955L, 30306712L, 48412415L, 21499315L}; + private static final long[] D2 = {45281625L, 27714825L, 36363642L, 13898781L, 229458L, 15978800L, 54557047L, 27058993L, 29715967L, 9444199L}; + private static final long[] I = {17187054L, 16663501L, 25252512L, 26698L, 9007192L, 25056900L, 31130252L, 16580L, 54723919L, 2713947L}; + + // Precomputed limbs for 2 * P_FIELD to eliminate negative limb carries during subtraction + private static final long[] TWO_P = { + 0x3FFFFDAL, 0x1FFFFFFL, 0x3FFFFFFL, 0x1FFFFFFL, 0x3FFFFFFL, + 0x1FFFFFFL, 0x3FFFFFFL, 0x1FFFFFFL, 0x3FFFFFFL, 0x1FFFFFFL + }; private static final class Ge { final long[] X = new long[10], Y = new long[10], Z = new long[10], T = new long[10]; - void wipe() { CryptoUtils.wipe(X); CryptoUtils.wipe(Y); CryptoUtils.wipe(Z); CryptoUtils.wipe(T); } - } - private static final class Scratch { - final long[] a = new long[10], b = new long[10], c = new long[10], d = new long[10], e = new long[10], f = new long[10], g = new long[10], h = new long[10], tmp = new long[10], t19 = new long[19]; - final Ge geTmp = new Ge(); void wipe() { - CryptoUtils.wipe(a); CryptoUtils.wipe(b); CryptoUtils.wipe(c); CryptoUtils.wipe(d); - CryptoUtils.wipe(e); CryptoUtils.wipe(f); CryptoUtils.wipe(g); CryptoUtils.wipe(h); - CryptoUtils.wipe(tmp); CryptoUtils.wipe(t19); geTmp.wipe(); + CryptoUtils.wipe(X); + CryptoUtils.wipe(Y); + CryptoUtils.wipe(Z); + CryptoUtils.wipe(T); } } - private Ed25519() {} + private static final class Scratch { + final long[] a = new long[10], b = new long[10], c = new long[10], d = new long[10], + e = new long[10], f = new long[10], g = new long[10], h = new long[10], + tmp = new long[10], t19 = new long[19]; + final Ge geTmp = new Ge(); + + void wipe() { + CryptoUtils.wipe(a); + CryptoUtils.wipe(b); + CryptoUtils.wipe(c); + CryptoUtils.wipe(d); + CryptoUtils.wipe(e); + CryptoUtils.wipe(f); + CryptoUtils.wipe(g); + CryptoUtils.wipe(h); + CryptoUtils.wipe(tmp); + CryptoUtils.wipe(t19); + geTmp.wipe(); + } + } + + private Ed25519() { + } public static byte[] publicKey(byte[] seed) { byte[] hash = sha512(seed); byte[] s = Arrays.copyOfRange(hash, 0, 32); - s[0] &= 248; s[31] &= 127; s[31] |= 64; + s[0] &= 248; + s[31] &= 127; + s[31] |= 64; Scratch sc = new Scratch(); Ge A_point = scalarMulBase(s, sc); byte[] A = compress(A_point, sc); - A_point.wipe(); sc.wipe(); CryptoUtils.wipe(hash); CryptoUtils.wipe(s); + A_point.wipe(); + sc.wipe(); + CryptoUtils.wipe(hash); + CryptoUtils.wipe(s); return A; } public static byte[] sign(byte[] seed, byte[] message) { byte[] hash = sha512(seed); byte[] s = Arrays.copyOfRange(hash, 0, 32); - s[0] &= 248; s[31] &= 127; s[31] |= 64; + s[0] &= 248; + s[31] &= 127; + s[31] |= 64; byte[] prefix = Arrays.copyOfRange(hash, 32, 64); byte[] rHash = sha512(prefix, message); reduce(rHash); @@ -92,9 +119,16 @@ public final class Ed25519 { byte[] sig = new byte[64]; System.arraycopy(R, 0, sig, 0, 32); System.arraycopy(S, 0, sig, 32, 32); - R_point.wipe(); sc.wipe(); CryptoUtils.wipe(hash); CryptoUtils.wipe(s); - CryptoUtils.wipe(prefix); CryptoUtils.wipe(rHash); CryptoUtils.wipe(r); - CryptoUtils.wipe(kHash); CryptoUtils.wipe(k); CryptoUtils.wipe(A); + R_point.wipe(); + sc.wipe(); + CryptoUtils.wipe(hash); + CryptoUtils.wipe(s); + CryptoUtils.wipe(prefix); + CryptoUtils.wipe(rHash); + CryptoUtils.wipe(r); + CryptoUtils.wipe(kHash); + CryptoUtils.wipe(k); + CryptoUtils.wipe(A); return sig; } @@ -113,15 +147,25 @@ public final class Ed25519 { ge_double_scalarmul_vartime(R_expected, S_bytes, A, k, sc); byte[] R_check = compress(R_expected, sc); boolean ok = Arrays.equals(R_bytes, R_check); - A.wipe(); R_expected.wipe(); sc.wipe(); CryptoUtils.wipe(kHash); CryptoUtils.wipe(k); + A.wipe(); + R_expected.wipe(); + sc.wipe(); + CryptoUtils.wipe(kHash); + CryptoUtils.wipe(k); return ok; } private static Ge scalarMulBase(byte[] scalar, Scratch s) { Ge p = new Ge(); - fe_copy(p.X, BX); fe_copy(p.Y, BY); fe_1(p.Z); fe_copy(p.T, BXY); + fe_copy(p.X, BX); + fe_copy(p.Y, BY); + fe_1(p.Z); + fe_copy(p.T, BXY); Ge res = new Ge(); - fe_0(res.X); fe_1(res.Y); fe_1(res.Z); fe_0(res.T); + fe_0(res.X); + fe_1(res.Y); + fe_1(res.Z); + fe_0(res.T); for (int i = 0; i < 256; i++) { int bit = ((scalar[i / 8] & 0xFF) >>> (i % 8)) & 1; ge_add(s.geTmp, res, p, s); @@ -138,20 +182,29 @@ public final class Ed25519 { fe_neg(kA.X, kA.X); fe_neg(kA.T, kA.T); ge_add(r, sB, kA, sc); - sB.wipe(); kA.wipe(); + sB.wipe(); + kA.wipe(); } private static Ge scalarMul(Ge p, byte[] scalar, Scratch s) { Ge res = new Ge(); - fe_0(res.X); fe_1(res.Y); fe_1(res.Z); fe_0(res.T); + fe_0(res.X); + fe_1(res.Y); + fe_1(res.Z); + fe_0(res.T); Ge q = new Ge(); - fe_copy(q.X, p.X); fe_copy(q.Y, p.Y); fe_copy(q.Z, p.Z); fe_copy(q.T, p.T); + fe_copy(q.X, p.X); + fe_copy(q.Y, p.Y); + fe_copy(q.Z, p.Z); + fe_copy(q.T, p.T); for (int i = 0; i < 256; i++) { int bit = ((scalar[i / 8] & 0xFF) >>> (i % 8)) & 1; if (bit == 1) { ge_add(s.geTmp, res, q, s); - fe_copy(res.X, s.geTmp.X); fe_copy(res.Y, s.geTmp.Y); - fe_copy(res.Z, s.geTmp.Z); fe_copy(res.T, s.geTmp.T); + fe_copy(res.X, s.geTmp.X); + fe_copy(res.Y, s.geTmp.Y); + fe_copy(res.Z, s.geTmp.Z); + fe_copy(res.T, s.geTmp.T); } ge_double(q, q, s); } @@ -160,29 +213,52 @@ public final class Ed25519 { } private static void ge_add(Ge r, Ge p1, Ge p2, Scratch s) { - fe_sub(s.a, p1.Y, p1.X); fe_sub(s.b, p2.Y, p2.X); fe_mul(s.a, s.a, s.b, s.t19); - fe_add(s.b, p1.Y, p1.X); fe_add(s.c, p2.Y, p2.X); fe_mul(s.b, s.b, s.c, s.t19); - fe_mul(s.tmp, p1.T, p2.T, s.t19); fe_mul(s.c, s.tmp, D2, s.t19); - fe_mul(s.d, p1.Z, p2.Z, s.t19); fe_add(s.d, s.d, s.d); - fe_sub(s.e, s.b, s.a); fe_sub(s.f, s.d, s.c); fe_add(s.g, s.d, s.c); fe_add(s.h, s.b, s.a); - fe_mul(r.X, s.e, s.f, s.t19); fe_mul(r.Y, s.g, s.h, s.t19); - fe_mul(r.Z, s.f, s.g, s.t19); fe_mul(r.T, s.e, s.h, s.t19); + fe_sub(s.a, p1.Y, p1.X); + fe_sub(s.b, p2.Y, p2.X); + fe_mul(s.a, s.a, s.b, s.t19); + fe_add(s.b, p1.Y, p1.X); + fe_add(s.c, p2.Y, p2.X); + fe_mul(s.b, s.b, s.c, s.t19); + fe_mul(s.tmp, p1.T, p2.T, s.t19); + fe_mul(s.c, s.tmp, D2, s.t19); + fe_mul(s.d, p1.Z, p2.Z, s.t19); + fe_add(s.d, s.d, s.d); + fe_sub(s.e, s.b, s.a); + fe_sub(s.f, s.d, s.c); + fe_add(s.g, s.d, s.c); + fe_add(s.h, s.b, s.a); + fe_mul(r.X, s.e, s.f, s.t19); + fe_mul(r.Y, s.g, s.h, s.t19); + fe_mul(r.Z, s.f, s.g, s.t19); + fe_mul(r.T, s.e, s.h, s.t19); } private static void ge_double(Ge r, Ge p, Scratch s) { - fe_sq(s.a, p.X, s.t19); fe_sq(s.b, p.Y, s.t19); fe_sq(s.c, p.Z, s.t19); fe_add(s.c, s.c, s.c); - fe_neg(s.d, s.a); fe_add(s.tmp, p.X, p.Y); fe_sq(s.e, s.tmp, s.t19); - fe_add(s.tmp, s.a, s.b); fe_sub(s.e, s.e, s.tmp); - fe_add(s.g, s.d, s.b); fe_sub(s.f, s.g, s.c); fe_sub(s.h, s.d, s.b); - fe_mul(r.X, s.e, s.f, s.t19); fe_mul(r.Y, s.g, s.h, s.t19); - fe_mul(r.Z, s.f, s.g, s.t19); fe_mul(r.T, s.e, s.h, s.t19); + fe_sq(s.a, p.X, s.t19); + fe_sq(s.b, p.Y, s.t19); + fe_sq(s.c, p.Z, s.t19); + fe_add(s.c, s.c, s.c); + fe_neg(s.d, s.a); + fe_add(s.tmp, p.X, p.Y); + fe_sq(s.e, s.tmp, s.t19); + fe_add(s.tmp, s.a, s.b); + fe_sub(s.e, s.e, s.tmp); + fe_add(s.g, s.d, s.b); + fe_sub(s.f, s.g, s.c); + fe_sub(s.h, s.d, s.b); + fe_mul(r.X, s.e, s.f, s.t19); + fe_mul(r.Y, s.g, s.h, s.t19); + fe_mul(r.Z, s.f, s.g, s.t19); + fe_mul(r.T, s.e, s.h, s.t19); } private static void ge_cmov(Ge r, Ge p, int b) { long m = -(long) b; for (int i = 0; i < 10; i++) { - r.X[i] ^= (m & (r.X[i] ^ p.X[i])); r.Y[i] ^= (m & (r.Y[i] ^ p.Y[i])); - r.Z[i] ^= (m & (r.Z[i] ^ p.Z[i])); r.T[i] ^= (m & (r.T[i] ^ p.T[i])); + r.X[i] ^= (m & (r.X[i] ^ p.X[i])); + r.Y[i] ^= (m & (r.Y[i] ^ p.Y[i])); + r.Z[i] ^= (m & (r.Z[i] ^ p.Z[i])); + r.T[i] ^= (m & (r.T[i] ^ p.T[i])); } } @@ -191,7 +267,7 @@ public final class Ed25519 { Ge p = new Ge(); fe_frombytes(p.Y, b); fe_1(p.Z); - fe_sq(s.a, p.Y, s.t19); + fe_sq(s.a, p.Y, s.t19); fe_mul(s.b, s.a, D, s.t19); fe_sub(s.a, s.a, p.Z); fe_add(s.b, s.b, p.Z); @@ -216,37 +292,121 @@ public final class Ed25519 { } private static byte[] compress(Ge p, Scratch s) { - fe_invert(s.a, p.Z, s); fe_mul(s.b, p.X, s.a, s.t19); fe_mul(s.c, p.Y, s.a, s.t19); + fe_invert(s.a, p.Z, s); + fe_mul(s.b, p.X, s.a, s.t19); + fe_mul(s.c, p.Y, s.a, s.t19); byte[] out = fe_contract(s.c); if (fe_isnegative(s.b) == 1) out[31] |= (byte) 0x80; return out; } - private static void fe_0(long[] h) { Arrays.fill(h, 0); } - private static void fe_1(long[] h) { Arrays.fill(h, 0); h[0] = 1; } - private static void fe_copy(long[] h, long[] f) { System.arraycopy(f, 0, h, 0, 10); } - private static void fe_add(long[] h, long[] f, long[] g) { for (int i = 0; i < 10; i++) h[i] = f[i] + g[i]; } - private static void fe_sub(long[] h, long[] f, long[] g) { for (int i = 0; i < 10; i++) h[i] = f[i] - g[i]; } - private static void fe_neg(long[] h, long[] f) { for (int i = 0; i < 10; i++) h[i] = -f[i]; } - - private static void fe_mul(long[] out, long[] in1, long[] in2, long[] t) { - BigInteger ba = new BigInteger(1, reverse(fe_contract(in1))); - BigInteger bb = new BigInteger(1, reverse(fe_contract(in2))); - BigInteger br = ba.multiply(bb).mod(P_FIELD); - byte[] r = br.toByteArray(); - byte[] b = new byte[32]; - for (int i = 0; i < Math.min(r.length, 32); i++) b[i] = r[r.length - 1 - i]; - fe_frombytes(out, b); + private static void fe_0(long[] h) { + Arrays.fill(h, 0); } - private static void fe_sq(long[] out, long[] in, long[] t) { - fe_mul(out, in, in, t); + private static void fe_1(long[] h) { + Arrays.fill(h, 0); + h[0] = 1; } - private static byte[] reverse(byte[] b) { - byte[] r = new byte[b.length]; - for (int i = 0; i < b.length; i++) r[i] = b[b.length - 1 - i]; - return r; + private static void fe_copy(long[] h, long[] f) { + System.arraycopy(f, 0, h, 0, 10); + } + + private static void fe_add(long[] h, long[] f, long[] g) { + for (int i = 0; i < 10; i++) h[i] = f[i] + g[i]; + } + + private static void fe_sub(long[] h, long[] f, long[] g) { + for (int i = 0; i < 10; i++) { + h[i] = (f[i] + TWO_P[i]) - g[i]; + } + } + + private static void fe_neg(long[] h, long[] f) { + for (int i = 0; i < 10; i++) h[i] = -f[i]; + } + + private static void fe_mul(long[] out, long[] f, long[] g, long[] t) { + long f0 = f[0], f1 = f[1], f2 = f[2], f3 = f[3], f4 = f[4], + f5 = f[5], f6 = f[6], f7 = f[7], f8 = f[8], f9 = f[9]; + long g0 = g[0], g1 = g[1], g2 = g[2], g3 = g[3], g4 = g[4], + g5 = g[5], g6 = g[6], g7 = g[7], g8 = g[8], g9 = g[9]; + + long g1_19 = g1 * 19, g2_19 = g2 * 19, g3_19 = g3 * 19, g4_19 = g4 * 19, + g5_19 = g5 * 19, g6_19 = g6 * 19, g7_19 = g7 * 19, g8_19 = g8 * 19, g9_19 = g9 * 19; + + long r0 = f0 * g0 + f1 * g9_19 + f2 * g8_19 + f3 * g7_19 + f4 * g6_19 + f5 * g5_19 + f6 * g4_19 + f7 * g3_19 + f8 * g2_19 + f9 * g1_19; + long r1 = f0 * g1 + f1 * g0 + f2 * g9_19 + f3 * g8_19 + f4 * g7_19 + f5 * g6_19 + f6 * g5_19 + f7 * g4_19 + f8 * g3_19 + f9 * g2_19; + long r2 = f0 * g2 + f1 * g1 + f2 * g0 + f3 * g9_19 + f4 * g8_19 + f5 * g7_19 + f6 * g6_19 + f7 * g5_19 + f8 * g4_19 + f9 * g3_19; + long r3 = f0 * g3 + f1 * g2 + f2 * g1 + f3 * g0 + f4 * g9_19 + f5 * g8_19 + f6 * g7_19 + f7 * g6_19 + f8 * g5_19 + f9 * g4_19; + long r4 = f0 * g4 + f1 * g3 + f2 * g2 + f3 * g1 + f4 * g0 + f5 * g9_19 + f6 * g8_19 + f7 * g7_19 + f8 * g6_19 + f9 * g5_19; + long r5 = f0 * g5 + f1 * g4 + f2 * g3 + f3 * g2 + f4 * g1 + f5 * g0 + f6 * g9_19 + f7 * g8_19 + f8 * g7_19 + f9 * g6_19; + long r6 = f0 * g6 + f1 * g5 + f2 * g4 + f3 * g3 + f4 * g2 + f5 * g1 + f6 * g0 + f7 * g9_19 + f8 * g8_19 + f9 * g7_19; + long r7 = f0 * g7 + f1 * g6 + f2 * g5 + f3 * g4 + f4 * g3 + f5 * g2 + f6 * g1 + f7 * g0 + f8 * g9_19 + f9 * g8_19; + long r8 = f0 * g8 + f1 * g7 + f2 * g6 + f3 * g5 + f4 * g4 + f5 * g3 + f6 * g2 + f7 * g1 + f8 * g0 + f9 * g9_19; + long r9 = f0 * g9 + f1 * g8 + f2 * g7 + f3 * g6 + f4 * g5 + f5 * g4 + f6 * g3 + f7 * g2 + f8 * g1 + f9 * g0; + + r1 *= 2; r3 *= 2; r5 *= 2; r7 *= 2; r9 *= 2; + + long c; + c = r0 >> 26; r1 += c; r0 &= 0x3FFFFFFL; + c = r1 >> 25; r2 += c; r1 &= 0x1FFFFFFL; + c = r2 >> 26; r3 += c; r2 &= 0x3FFFFFFL; + c = r3 >> 25; r4 += c; r3 &= 0x1FFFFFFL; + c = r4 >> 26; r5 += c; r4 &= 0x3FFFFFFL; + c = r5 >> 25; r6 += c; r5 &= 0x1FFFFFFL; + c = r6 >> 26; r7 += c; r6 &= 0x3FFFFFFL; + c = r7 >> 25; r8 += c; r7 &= 0x1FFFFFFL; + c = r8 >> 26; r9 += c; r8 &= 0x3FFFFFFL; + c = r9 >> 25; r0 += c * 19; r9 &= 0x1FFFFFFL; + + c = r0 >> 26; r1 += c; r0 &= 0x3FFFFFFL; + + out[0] = r0; out[1] = r1; out[2] = r2; out[3] = r3; out[4] = r4; + out[5] = r5; out[6] = r6; out[7] = r7; out[8] = r8; out[9] = r9; + } + + + private static void fe_sq(long[] out, long[] f, long[] t) { + long f0 = f[0], f1 = f[1], f2 = f[2], f3 = f[3], f4 = f[4], + f5 = f[5], f6 = f[6], f7 = f[7], f8 = f[8], f9 = f[9]; + + long f1_2 = f1 * 2, f2_2 = f2 * 2, f3_2 = f3 * 2, f4_2 = f4 * 2, + f5_2 = f5 * 2, f6_2 = f6 * 2, f7_2 = f7 * 2, f8_2 = f8 * 2, f9_2 = f9 * 2; + + long f1_19 = f1 * 19, f2_19 = f2 * 19, f3_19 = f3 * 19, f4_19 = f4 * 19, + f5_19 = f5 * 19, f6_19 = f6 * 19, f7_19 = f7 * 19, f8_19 = f8 * 19, f9_19 = f9 * 19; + + long r0 = f0 * f0 + f1_2 * f9_19 + f2_2 * f8_19 + f3_2 * f7_19 + f4_2 * f6_19 + f5 * f5_19; + long r1 = f0 * f1_2 + f2 * f9_19 + f3 * f8_19 + f4 * f7_19 + f5 * f6_19; + long r2 = f0 * f2_2 + f1 * f1 + f3_2 * f9_19 + f4_2 * f8_19 + f5_2 * f7_19 + f6 * f6_19; + long r3 = f0 * f3_2 + f1_2 * f2 + f4 * f9_19 + f5 * f8_19 + f6 * f7_19; + long r4 = f0 * f4_2 + f1_2 * f3_2 + f2 * f2 + f5_2 * f9_19 + f6_2 * f8_19 + f7 * f7_19; + long r5 = f0 * f5_2 + f1_2 * f4 + f2_2 * f3 + f6 * f9_19 + f7 * f8_19; + long r6 = f0 * f6_2 + f1_2 * f5_2 + f2_2 * f4_2 + f3 * f3 + f7_2 * f9_19 + f8 * f8_19; + long r7 = f0 * f7_2 + f1_2 * f6 + f2_2 * f5 + f3_2 * f4 + f8 * f9_19; + long r8 = f0 * f8_2 + f1_2 * f7_2 + f2_2 * f6_2 + f3_2 * f5_2 + f4 * f4 + f9 * f9_19; + long r9 = f0 * f9_2 + f1_2 * f8 + f2_2 * f7 + f3_2 * f6 + f4_2 * f5; + + r1 *= 2; r3 *= 2; r5 *= 2; r7 *= 2; r9 *= 2; + + long c; + c = r0 >> 26; r1 += c; r0 &= 0x3FFFFFFL; + c = r1 >> 25; r2 += c; r1 &= 0x1FFFFFFL; + c = r2 >> 26; r3 += c; r2 &= 0x3FFFFFFL; + c = r3 >> 25; r4 += c; r3 &= 0x1FFFFFFL; + c = r4 >> 26; r5 += c; r4 &= 0x3FFFFFFL; + c = r5 >> 25; r6 += c; r5 &= 0x1FFFFFFL; + c = r6 >> 26; r7 += c; r6 &= 0x3FFFFFFL; + c = r7 >> 25; r8 += c; r7 &= 0x1FFFFFFL; + c = r8 >> 26; r9 += c; r8 &= 0x3FFFFFFL; + c = r9 >> 25; r0 += c * 19; r9 &= 0x1FFFFFFL; + + c = r0 >> 26; r1 += c; r0 &= 0x3FFFFFFL; + + out[0] = r0; out[1] = r1; out[2] = r2; out[3] = r3; out[4] = r4; + out[5] = r5; out[6] = r6; out[7] = r7; out[8] = r8; out[9] = r9; } private static void fe_frombytes(long[] h, byte[] s) { @@ -269,7 +429,7 @@ public final class Ed25519 { for (int i = 0; i < 9; i++) { long carry = h[i] >> (i % 2 == 0 ? 26 : 25); h[i] &= (i % 2 == 0 ? 0x3FFFFFFL : 0x1FFFFFFL); - h[i+1] += carry; + h[i + 1] += carry; } long carry = h[9] >> 25; h[9] &= 0x1FFFFFFL; @@ -280,7 +440,7 @@ public final class Ed25519 { for (int i = 0; i < 9; i++) { long carry = hplus19[i] >> (i % 2 == 0 ? 26 : 25); hplus19[i] &= (i % 2 == 0 ? 0x3FFFFFFL : 0x1FFFFFFL); - hplus19[i+1] += carry; + hplus19[i + 1] += carry; } long carry = hplus19[9] >> 25; hplus19[9] &= 0x1FFFFFFL; @@ -305,7 +465,7 @@ public final class Ed25519 { for (int i = 0; i < 9; i++) { long carry = h[i] >> (i % 2 == 0 ? 26 : 25); h[i] &= (i % 2 == 0 ? 0x3FFFFFFL : 0x1FFFFFFL); - h[i+1] += carry; + h[i + 1] += carry; } long carry = h[9] >> 25; h[9] &= 0x1FFFFFFL; @@ -314,30 +474,120 @@ public final class Ed25519 { private static void fe_invert(long[] out, long[] z, Scratch s) { long[] z2 = new long[10], z9 = new long[10], z11 = new long[10], t0 = new long[10], t1 = new long[10], t2 = new long[10]; - fe_sq(z2, z, s.t19); fe_sq(t1, z2, s.t19); fe_sq(t0, t1, s.t19); fe_mul(z9, t0, z, s.t19); fe_mul(z11, z9, z2, s.t19); - fe_sq(t0, z11, s.t19); fe_mul(t2, t0, z9, s.t19); - fe_sq(t0, t2, s.t19); for (int i = 1; i < 5; i++) { fe_sq(t1, t0, s.t19); fe_copy(t0, t1); } fe_mul(t1, t0, t2, s.t19); - fe_sq(t0, t1, s.t19); for (int i = 1; i < 10; i++) { fe_sq(t2, t0, s.t19); fe_copy(t0, t2); } fe_mul(t2, t0, t1, s.t19); - fe_sq(t0, t2, s.t19); for (int i = 1; i < 20; i++) { fe_sq(t1, t0, s.t19); fe_copy(t0, t1); } fe_mul(t0, t0, t2, s.t19); - fe_sq(t1, t0, s.t19); for (int i = 1; i < 10; i++) { fe_sq(t0, t1, s.t19); fe_copy(t1, t0); } fe_mul(t1, t1, t2, s.t19); - fe_sq(t0, t1, s.t19); for (int i = 1; i < 50; i++) { fe_sq(t2, t0, s.t19); fe_copy(t0, t2); } fe_mul(t2, t0, t1, s.t19); - fe_sq(t0, t2, s.t19); for (int i = 1; i < 100; i++) { fe_sq(t1, t0, s.t19); fe_copy(t0, t1); } fe_mul(t0, t0, t2, s.t19); - fe_sq(t1, t0, s.t19); for (int i = 1; i < 50; i++) { fe_sq(t0, t1, s.t19); fe_copy(t1, t0); } fe_mul(t1, t1, t2, s.t19); - fe_sq(t0, t1, s.t19); for (int i = 1; i < 5; i++) { fe_sq(t1, t0, s.t19); fe_copy(t0, t1); } fe_mul(out, t0, z11, s.t19); + fe_sq(z2, z, s.t19); + fe_sq(t1, z2, s.t19); + fe_sq(t0, t1, s.t19); + fe_mul(z9, t0, z, s.t19); + fe_mul(z11, z9, z2, s.t19); + fe_sq(t0, z11, s.t19); + fe_mul(t2, t0, z9, s.t19); + fe_sq(t0, t2, s.t19); + for (int i = 1; i < 5; i++) { + fe_sq(t1, t0, s.t19); + fe_copy(t0, t1); + } + fe_mul(t1, t0, t2, s.t19); + fe_sq(t0, t1, s.t19); + for (int i = 1; i < 10; i++) { + fe_sq(t2, t0, s.t19); + fe_copy(t0, t2); + } + fe_mul(t2, t0, t1, s.t19); + fe_sq(t0, t2, s.t19); + for (int i = 1; i < 20; i++) { + fe_sq(t1, t0, s.t19); + fe_copy(t0, t1); + } + fe_mul(t0, t0, t2, s.t19); + fe_sq(t1, t0, s.t19); + for (int i = 1; i < 10; i++) { + fe_sq(t0, t1, s.t19); + fe_copy(t1, t0); + } + fe_mul(t1, t1, t2, s.t19); + fe_sq(t0, t1, s.t19); + for (int i = 1; i < 50; i++) { + fe_sq(t2, t0, s.t19); + fe_copy(t0, t2); + } + fe_mul(t2, t0, t1, s.t19); + fe_sq(t0, t2, s.t19); + for (int i = 1; i < 100; i++) { + fe_sq(t1, t0, s.t19); + fe_copy(t0, t1); + } + fe_mul(t0, t0, t2, s.t19); + fe_sq(t1, t0, s.t19); + for (int i = 1; i < 50; i++) { + fe_sq(t0, t1, s.t19); + fe_copy(t1, t0); + } + fe_mul(t1, t1, t2, s.t19); + fe_sq(t0, t1, s.t19); + for (int i = 1; i < 5; i++) { + fe_sq(t1, t0, s.t19); + fe_copy(t0, t1); + } + fe_mul(out, t0, z, s.t19); } private static void fe_pow22523(long[] out, long[] z, Scratch s) { long[] t0 = new long[10], t1 = new long[10], t2 = new long[10]; - fe_sq(t0, z, s.t19); fe_sq(t1, t0, s.t19); fe_sq(t1, t1, s.t19); fe_mul(t1, t1, z, s.t19); fe_mul(t0, t0, t1, s.t19); - fe_sq(t0, t0, s.t19); fe_mul(t0, t0, t1, s.t19); fe_sq(t1, t0, s.t19); - for (int i = 1; i < 5; i++) { fe_sq(t2, t1, s.t19); fe_copy(t1, t2); } fe_mul(t1, t1, t0, s.t19); - fe_sq(t2, t1, s.t19); for (int i = 1; i < 10; i++) { fe_sq(t0, t2, s.t19); fe_copy(t2, t0); } fe_mul(t2, t2, t1, s.t19); - fe_sq(t0, t2, s.t19); for (int i = 1; i < 20; i++) { fe_sq(t1, t0, s.t19); fe_copy(t0, t1); } fe_mul(t0, t0, t2, s.t19); - fe_sq(t1, t0, s.t19); for (int i = 1; i < 10; i++) { fe_sq(t0, t1, s.t19); fe_copy(t1, t0); } fe_mul(t1, t1, t2, s.t19); - fe_sq(t0, t1, s.t19); for (int i = 1; i < 50; i++) { fe_sq(t2, t0, s.t19); fe_copy(t0, t2); } fe_mul(t2, t0, t1, s.t19); - fe_sq(t0, t2, s.t19); for (int i = 1; i < 100; i++) { fe_sq(t1, t0, s.t19); fe_copy(t0, t1); } fe_mul(t0, t0, t2, s.t19); - fe_sq(t1, t0, s.t19); for (int i = 1; i < 50; i++) { fe_sq(t0, t1, s.t19); fe_copy(t1, t0); } fe_mul(t1, t1, t2, s.t19); - fe_sq(t0, t1, s.t19); for (int i = 1; i < 2; i++) { fe_sq(t1, t0, s.t19); fe_copy(t0, t1); } fe_mul(out, t0, z, s.t19); + fe_sq(t0, z, s.t19); + fe_sq(t1, t0, s.t19); + fe_sq(t1, t1, s.t19); + fe_mul(t1, t1, z, s.t19); + fe_mul(t0, t0, t1, s.t19); + fe_sq(t0, t0, s.t19); + fe_mul(t0, t0, t1, s.t19); + fe_sq(t1, t0, s.t19); + for (int i = 1; i < 5; i++) { + fe_sq(t2, t1, s.t19); + fe_copy(t1, t2); + } + fe_mul(t1, t1, t0, s.t19); + fe_sq(t2, t1, s.t19); + for (int i = 1; i < 10; i++) { + fe_sq(t0, t2, s.t19); + fe_copy(t2, t0); + } + fe_mul(t2, t2, t1, s.t19); + fe_sq(t0, t2, s.t19); + for (int i = 1; i < 20; i++) { + fe_sq(t1, t0, s.t19); + fe_copy(t0, t1); + } + fe_mul(t0, t0, t2, s.t19); + fe_sq(t1, t0, s.t19); + for (int i = 1; i < 10; i++) { + fe_sq(t0, t1, s.t19); + fe_copy(t1, t0); + } + fe_mul(t1, t1, t2, s.t19); + fe_sq(t0, t1, s.t19); + for (int i = 1; i < 50; i++) { + fe_sq(t2, t0, s.t19); + fe_copy(t0, t2); + } + fe_mul(t2, t0, t1, s.t19); + fe_sq(t0, t2, s.t19); + for (int i = 1; i < 100; i++) { + fe_sq(t1, t0, s.t19); + fe_copy(t0, t1); + } + fe_mul(t0, t0, t2, s.t19); + fe_sq(t1, t0, s.t19); + for (int i = 1; i < 50; i++) { + fe_sq(t0, t1, s.t19); + fe_copy(t1, t0); + } + fe_mul(t1, t1, t2, s.t19); + fe_sq(t0, t1, s.t19); + for (int i = 1; i < 2; i++) { + fe_sq(t1, t0, s.t19); + fe_copy(t0, t1); + } + fe_mul(out, t0, z, s.t19); } private static boolean fe_isnonzero(long[] h) { @@ -377,70 +627,213 @@ public final class Ed25519 { long s21 = 2097151 & (load3(s, 55) >> 1); long s22 = 2097151 & (load4(s, 57) >> 6); long s23 = (load4(s, 60) >> 3); - - s11 += s23 * 666643; s12 += s23 * 470296; s13 += s23 * 654183; s14 -= s23 * 997805; s15 += s23 * 136657; s16 -= s23 * 683901; - s10 += s22 * 666643; s11 += s22 * 470296; s12 += s22 * 654183; s13 -= s22 * 997805; s14 += s22 * 136657; s15 -= s22 * 683901; - s9 += s21 * 666643; s10 += s21 * 470296; s11 += s21 * 654183; s12 -= s21 * 997805; s13 += s21 * 136657; s14 -= s21 * 683901; - s8 += s20 * 666643; s9 += s20 * 470296; s10 += s20 * 654183; s11 -= s20 * 997805; s12 += s20 * 136657; s13 -= s20 * 683901; - s7 += s19 * 666643; s8 += s19 * 470296; s9 += s19 * 654183; s10 -= s19 * 997805; s11 += s19 * 136657; s12 -= s19 * 683901; - s6 += s18 * 666643; s7 += s18 * 470296; s8 += s18 * 654183; s9 -= s18 * 997805; s10 += s18 * 136657; s11 -= s18 * 683901; - - long c6 = (s6 + (1 << 20)) >> 21; s7 += c6; s6 -= c6 << 21; - long c8 = (s8 + (1 << 20)) >> 21; s9 += c8; s8 -= c8 << 21; - long c10 = (s10 + (1 << 20)) >> 21; s11 += c10; s10 -= c10 << 21; - long c12 = (s12 + (1 << 20)) >> 21; s13 += c12; s12 -= c12 << 21; - long c14 = (s14 + (1 << 20)) >> 21; s15 += c14; s14 -= c14 << 21; - long c16 = (s16 + (1 << 20)) >> 21; s17 += c16; s16 -= c16 << 21; - long c7 = (s7 + (1 << 20)) >> 21; s8 += c7; s7 -= c7 << 21; - long c9 = (s9 + (1 << 20)) >> 21; s10 += c9; s9 -= c9 << 21; - long c11 = (s11 + (1 << 20)) >> 21; s12 += c11; s11 -= c11 << 21; - long c13 = (s13 + (1 << 20)) >> 21; s14 += c13; s13 -= c13 << 21; - long c15 = (s15 + (1 << 20)) >> 21; s16 += c15; s15 -= c15 << 21; - - s5 += s17 * 666643; s6 += s17 * 470296; s7 += s17 * 654183; s8 -= s17 * 997805; s9 += s17 * 136657; s10 -= s17 * 683901; - s4 += s16 * 666643; s5 += s16 * 470296; s6 += s16 * 654183; s7 -= s16 * 997805; s8 += s16 * 136657; s9 -= s16 * 683901; - s3 += s15 * 666643; s4 += s15 * 470296; s5 += s15 * 654183; s6 -= s15 * 997805; s7 += s15 * 136657; s8 -= s15 * 683901; - s2 += s14 * 666643; s3 += s14 * 470296; s4 += s14 * 654183; s5 -= s14 * 997805; s6 += s14 * 136657; s7 -= s14 * 683901; - s1 += s13 * 666643; s2 += s13 * 470296; s3 += s13 * 654183; s4 -= s13 * 997805; s5 += s13 * 136657; s6 -= s13 * 683901; - s0 += s12 * 666643; s1 += s12 * 470296; s2 += s12 * 654183; s3 -= s12 * 997805; s4 += s12 * 136657; s5 -= s12 * 683901; - - long cc0 = (s0 + (1 << 20)) >> 21; s1 += cc0; s0 -= cc0 << 21; - long cc2 = (s2 + (1 << 20)) >> 21; s3 += cc2; s2 -= cc2 << 21; - long cc4 = (s4 + (1 << 20)) >> 21; s5 += cc4; s4 -= cc4 << 21; - long cc6 = (s6 + (1 << 20)) >> 21; s7 += cc6; s6 -= cc6 << 21; - long cc8 = (s8 + (1 << 20)) >> 21; s9 += cc8; s8 -= cc8 << 21; - long cc10 = (s10 + (1 << 20)) >> 21; s11 += cc10; s10 -= cc10 << 21; - long cc1 = (s1 + (1 << 20)) >> 21; s2 += cc1; s1 -= cc1 << 21; - long cc3 = (s3 + (1 << 20)) >> 21; s4 += cc3; s3 -= cc3 << 21; - long cc5 = (s5 + (1 << 20)) >> 21; s6 += cc5; s5 -= cc5 << 21; - long cc7 = (s7 + (1 << 20)) >> 21; s8 += cc7; s7 -= cc7 << 21; - long cc9 = (s9 + (1 << 20)) >> 21; s10 += cc9; s9 -= cc9 << 21; - long cc11 = (s11 + (1 << 20)) >> 21; long s12_2 = cc11; s11 -= cc11 << 21; - - s0 += s12_2 * 666643; s1 += s12_2 * 470296; s2 += s12_2 * 654183; s3 -= s12_2 * 997805; s4 += s12_2 * 136657; s5 -= s12_2 * 683901; - - long ccc0 = s0 >> 21; s1 += ccc0; s0 -= ccc0 << 21; - long ccc1 = s1 >> 21; s2 += ccc1; s1 -= ccc1 << 21; - long ccc2 = s2 >> 21; s3 += ccc2; s2 -= ccc2 << 21; - long ccc3 = s3 >> 21; s4 += ccc3; s3 -= ccc3 << 21; - long ccc4 = s4 >> 21; s5 += ccc4; s4 -= ccc4 << 21; - long ccc5 = s5 >> 21; s6 += ccc5; s5 -= ccc5 << 21; - long ccc6 = s6 >> 21; s7 += ccc6; s6 -= ccc6 << 21; - long ccc7 = s7 >> 21; s8 += ccc7; s7 -= ccc7 << 21; - long ccc8 = s8 >> 21; s9 += ccc8; s8 -= ccc8 << 21; - long ccc9 = s9 >> 21; s10 += ccc9; s9 -= ccc9 << 21; - long ccc10 = s10 >> 21; s11 += ccc10; s10 -= ccc10 << 21; - long ccc11 = s11 >> 21; long s12_3 = ccc11; s11 -= ccc11 << 21; - - s0 += s12_3 * 666643; s1 += s12_3 * 470296; s2 += s12_3 * 654183; s3 -= s12_3 * 997805; s4 += s12_3 * 136657; s5 -= s12_3 * 683901; - - long sccc0 = s0 >> 21; s1 += sccc0; s0 -= sccc0 << 21; - long sccc1 = s1 >> 21; s2 += sccc1; s1 -= sccc1 << 21; - long sccc2 = s2 >> 21; s3 += sccc2; s2 -= sccc2 << 21; - long sccc3 = s3 >> 21; s4 += sccc3; s3 -= sccc3 << 21; - long sccc4 = s4 >> 21; s5 += sccc4; s4 -= sccc4 << 21; - long sccc5 = s5 >> 21; s6 += sccc5; s5 -= sccc5 << 21; - + s11 += s23 * 666643; + s12 += s23 * 470296; + s13 += s23 * 654183; + s14 -= s23 * 997805; + s15 += s23 * 136657; + s16 -= s23 * 683901; + s10 += s22 * 666643; + s11 += s22 * 470296; + s12 += s22 * 654183; + s13 -= s22 * 997805; + s14 += s22 * 136657; + s15 -= s22 * 683901; + s9 += s21 * 666643; + s10 += s21 * 470296; + s11 += s21 * 654183; + s12 -= s21 * 997805; + s13 += s21 * 136657; + s14 -= s21 * 683901; + s8 += s20 * 666643; + s9 += s20 * 470296; + s10 += s20 * 654183; + s11 -= s20 * 997805; + s12 += s20 * 136657; + s13 -= s20 * 683901; + s7 += s19 * 666643; + s8 += s19 * 470296; + s9 += s19 * 654183; + s10 -= s19 * 997805; + s11 += s19 * 136657; + s12 -= s19 * 683901; + s6 += s18 * 666643; + s7 += s18 * 470296; + s8 += s18 * 654183; + s9 -= s18 * 997805; + s10 += s18 * 136657; + s11 -= s18 * 683901; + long c6 = (s6 + (1 << 20)) >> 21; + s7 += c6; + s6 -= c6 << 21; + long c8 = (s8 + (1 << 20)) >> 21; + s9 += c8; + s8 -= c8 << 21; + long c10 = (s10 + (1 << 20)) >> 21; + s11 += c10; + s10 -= c10 << 21; + long c12 = (s12 + (1 << 20)) >> 21; + s13 += c12; + s12 -= c12 << 21; + long c14 = (s14 + (1 << 20)) >> 21; + s15 += c14; + s14 -= c14 << 21; + long c16 = (s16 + (1 << 20)) >> 21; + s17 += c16; + s16 -= c16 << 21; + long c7 = (s7 + (1 << 20)) >> 21; + s8 += c7; + s7 -= c7 << 21; + long c9 = (s9 + (1 << 20)) >> 21; + s10 += c9; + s9 -= c9 << 21; + long c11 = (s11 + (1 << 20)) >> 21; + s12 += c11; + s11 -= c11 << 21; + long c13 = (s13 + (1 << 20)) >> 21; + s14 += c13; + s13 -= c13 << 21; + long c15 = (s15 + (1 << 20)) >> 21; + s16 += c15; + s15 -= c15 << 21; + s5 += s17 * 666643; + s6 += s17 * 470296; + s7 += s17 * 654183; + s8 -= s17 * 997805; + s9 += s17 * 136657; + s10 -= s17 * 683901; + s4 += s16 * 666643; + s5 += s16 * 470296; + s6 += s16 * 654183; + s7 -= s16 * 997805; + s8 += s16 * 136657; + s9 -= s16 * 683901; + s3 += s15 * 666643; + s4 += s15 * 470296; + s5 += s15 * 654183; + s6 -= s15 * 997805; + s7 += s15 * 136657; + s8 -= s15 * 683901; + s2 += s14 * 666643; + s3 += s14 * 470296; + s4 += s14 * 654183; + s5 -= s14 * 997805; + s6 += s14 * 136657; + s7 -= s14 * 683901; + s1 += s13 * 666643; + s2 += s13 * 470296; + s3 += s13 * 654183; + s4 -= s13 * 997805; + s5 += s13 * 136657; + s6 -= s13 * 683901; + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + long cc0 = (s0 + (1 << 20)) >> 21; + s1 += cc0; + s0 -= cc0 << 21; + long cc2 = (s2 + (1 << 20)) >> 21; + s3 += cc2; + s2 -= cc2 << 21; + long cc4 = (s4 + (1 << 20)) >> 21; + s5 += cc4; + s4 -= cc4 << 21; + long cc6 = (s6 + (1 << 20)) >> 21; + s7 += cc6; + s6 -= cc6 << 21; + long cc8 = (s8 + (1 << 20)) >> 21; + s9 += cc8; + s8 -= cc8 << 21; + long cc10 = (s10 + (1 << 20)) >> 21; + s11 += cc10; + s10 -= cc10 << 21; + long cc1 = (s1 + (1 << 20)) >> 21; + s2 += cc1; + s1 -= cc1 << 21; + long cc3 = (s3 + (1 << 20)) >> 21; + s4 += cc3; + s3 -= cc3 << 21; + long cc5 = (s5 + (1 << 20)) >> 21; + s6 += cc5; + s5 -= cc5 << 21; + long cc7 = (s7 + (1 << 20)) >> 21; + s8 += cc7; + s7 -= cc7 << 21; + long cc9 = (s9 + (1 << 20)) >> 21; + s10 += cc9; + s9 -= cc9 << 21; + long cc11 = (s11 + (1 << 20)) >> 21; + long s12_2 = cc11; + s11 -= cc11 << 21; + s0 += s12_2 * 666643; + s1 += s12_2 * 470296; + s2 += s12_2 * 654183; + s3 -= s12_2 * 997805; + s4 += s12_2 * 136657; + s5 -= s12_2 * 683901; + long ccc0 = s0 >> 21; + s1 += ccc0; + s0 -= ccc0 << 21; + long ccc1 = s1 >> 21; + s2 += ccc1; + s1 -= ccc1 << 21; + long ccc2 = s2 >> 21; + s3 += ccc2; + s2 -= ccc2 << 21; + long ccc3 = s3 >> 21; + s4 += ccc3; + s3 -= ccc3 << 21; + long ccc4 = s4 >> 21; + s5 += ccc4; + s4 -= ccc4 << 21; + long ccc5 = s5 >> 21; + s6 += ccc5; + s5 -= ccc5 << 21; + long ccc6 = s6 >> 21; + s7 += ccc6; + s6 -= ccc6 << 21; + long ccc7 = s7 >> 21; + s8 += ccc7; + s7 -= ccc7 << 21; + long ccc8 = s8 >> 21; + s9 += ccc8; + s8 -= ccc8 << 21; + long ccc9 = s9 >> 21; + s10 += ccc9; + s9 -= ccc9 << 21; + long ccc10 = s10 >> 21; + s11 += ccc10; + s10 -= ccc10 << 21; + long ccc11 = s11 >> 21; + long s12_3 = ccc11; + s11 -= ccc11 << 21; + s0 += s12_3 * 666643; + s1 += s12_3 * 470296; + s2 += s12_3 * 654183; + s3 -= s12_3 * 997805; + s4 += s12_3 * 136657; + s5 -= s12_3 * 683901; + long sccc0 = s0 >> 21; + s1 += sccc0; + s0 -= sccc0 << 21; + long sccc1 = s1 >> 21; + s2 += sccc1; + s1 -= sccc1 << 21; + long sccc2 = s2 >> 21; + s3 += sccc2; + s2 -= sccc2 << 21; + long sccc3 = s3 >> 21; + s4 += sccc3; + s3 -= sccc3 << 21; + long sccc4 = s4 >> 21; + s5 += sccc4; + s4 -= sccc4 << 21; + long sccc5 = s5 >> 21; + s6 += sccc5; + s5 -= sccc5 << 21; for (int i = 0; i < 32; i++) s[i] = 0; long[] resLimbs = {s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11}; int bitIdx = 0; @@ -486,6 +879,9 @@ public final class Ed25519 { System.arraycopy(buffer, 0, S, 0, 32); } +// ========================================================================= +// PUBLIC TEST HOOKS FOR TESTINATOR / EXTERNAL VERIFICATION +// ========================================================================= public static void testFromBytes(long[] h, byte[] s) { fe_frombytes(h, s); } @@ -506,7 +902,8 @@ public final class Ed25519 { Scratch sc = new Scratch(); Ge p = scalarMulBase(in, sc); byte[] out = compress(p, sc); - p.wipe(); sc.wipe(); + p.wipe(); + sc.wipe(); return out; } @@ -517,7 +914,10 @@ public final class Ed25519 { Ge p3 = new Ge(); ge_add(p3, p1, p2, sc); byte[] out = compress(p3, sc); - p1.wipe(); p2.wipe(); p3.wipe(); sc.wipe(); + p1.wipe(); + p2.wipe(); + p3.wipe(); + sc.wipe(); return out; } @@ -530,17 +930,13 @@ public final class Ed25519 { return fe_contract(hr); } - public static byte[] testFeContract(long[] h) { return fe_contract(h); } - public static long[] getBX() { return BX; } - public static long[] getBY() { return BY; } - public static long[] getD() { return D; } - public static long[] getD2() { return D2; } - private static byte[] sha512(byte[]... parts) { try { MessageDigest md = MessageDigest.getInstance("SHA-512"); for (byte[] p : parts) md.update(p); return md.digest(); - } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } } }