private static void EncodePoint(PointAccum p, byte[] r, int rOff) { int[] x = X25519Field.Create(); int[] y = X25519Field.Create(); X25519Field.Inv(p.z, y); X25519Field.Mul(p.x, y, x); X25519Field.Mul(p.y, y, y); X25519Field.Normalize(x); X25519Field.Normalize(y); X25519Field.Encode(y, r, rOff); r[rOff + PointBytes - 1] |= (byte)((x[0] & 1) << 7); }
private static int CheckPoint(int[] x, int[] y) { int[] t = X25519Field.Create(); int[] u = X25519Field.Create(); int[] v = X25519Field.Create(); X25519Field.Sqr(x, u); X25519Field.Sqr(y, v); X25519Field.Mul(u, v, t); X25519Field.Sub(v, u, v); X25519Field.Mul(t, C_d, t); X25519Field.AddOne(t); X25519Field.Sub(t, v, t); X25519Field.Normalize(t); return(X25519Field.IsZero(t)); }
private byte[] ConvertEdPublicKeyToMontgomery(byte[] edPublicKey) { int[] x = X25519Field.Create(); int[] oneMinusY = X25519Field.Create(); int[] aY = new int[X25519Field.Size]; X25519Field.Decode(edPublicKey, 0, aY); X25519Field.One(oneMinusY); X25519Field.Sub(oneMinusY, aY, oneMinusY); X25519Field.One(x); X25519Field.Add(x, aY, x); X25519Field.Inv(oneMinusY, oneMinusY); X25519Field.Mul(x, oneMinusY, x); byte[] xpublicKey = new byte[X25519PublicKeyParameters.KeySize]; X25519Field.Encode(x, xpublicKey, 0); // UPDATE: the reality of the situation is that it's OK to check if it works, because the vast, vast majority work right off the bat, and it takes very little time to generate // I have no idea, but it has always worked....: I am very unhappy with it (tested 1m times, didn't fail). But since I don't trust it, I check it too (when it is possible) if (xpublicKey[X25519PublicKeyParameters.KeySize - 1] >= 128) { // Take off 128 xpublicKey[X25519PublicKeyParameters.KeySize - 1] -= 128; // We need to add 19 as well... xpublicKey[0] = (byte)((xpublicKey[0] + 19) % 256); if (xpublicKey[0] < 19) { int index = 0; while (true) { index++; if (xpublicKey[index] != 255) { xpublicKey[index] += 1; break; } xpublicKey[index] = 0; } } } return(xpublicKey); }
private static bool DecodePointVar(byte[] p, int pOff, bool negate, PointExt r) { byte[] py = Arrays.CopyOfRange(p, pOff, pOff + PointBytes); if (!CheckPointVar(py)) { return(false); } int x_0 = (py[PointBytes - 1] & 0x80) >> 7; py[PointBytes - 1] &= 0x7F; X25519Field.Decode(py, 0, r.y); int[] u = X25519Field.Create(); int[] v = X25519Field.Create(); X25519Field.Sqr(r.y, u); X25519Field.Mul(C_d, u, v); X25519Field.SubOne(u); X25519Field.AddOne(v); if (!X25519Field.SqrtRatioVar(u, v, r.x)) { return(false); } X25519Field.Normalize(r.x); if (x_0 == 1 && X25519Field.IsZeroVar(r.x)) { return(false); } if (negate ^ (x_0 != (r.x[0] & 1))) { X25519Field.Negate(r.x, r.x); } PointExtendXY(r); return(true); }
private static void PointAddPrecomp(PointPrecomp p, PointAccum r) { int[] A = X25519Field.Create(); int[] B = X25519Field.Create(); int[] C = X25519Field.Create(); int[] E = r.u; int[] F = X25519Field.Create(); int[] G = X25519Field.Create(); int[] H = r.v; X25519Field.Apm(r.y, r.x, B, A); X25519Field.Mul(A, p.ymx_h, A); X25519Field.Mul(B, p.ypx_h, B); X25519Field.Mul(r.u, r.v, C); X25519Field.Mul(C, p.xyd, C); X25519Field.Apm(B, A, H, E); X25519Field.Apm(r.z, C, G, F); X25519Field.Carry(G); X25519Field.Mul(E, F, r.x); X25519Field.Mul(G, H, r.y); X25519Field.Mul(F, G, r.z); }
private static void PointAddVar(bool negate, PointExt p, PointExt q, PointExt r) { int[] A = X25519Field.Create(); int[] B = X25519Field.Create(); int[] C = X25519Field.Create(); int[] D = X25519Field.Create(); int[] E = X25519Field.Create(); int[] F = X25519Field.Create(); int[] G = X25519Field.Create(); int[] H = X25519Field.Create(); int[] c, d, f, g; if (negate) { c = D; d = C; f = G; g = F; } else { c = C; d = D; f = F; g = G; } X25519Field.Apm(p.y, p.x, B, A); X25519Field.Apm(q.y, q.x, d, c); X25519Field.Mul(A, C, A); X25519Field.Mul(B, D, B); X25519Field.Mul(p.t, q.t, C); X25519Field.Mul(C, C_d2, C); X25519Field.Mul(p.z, q.z, D); X25519Field.Add(D, D, D); X25519Field.Apm(B, A, H, E); X25519Field.Apm(D, C, g, f); X25519Field.Carry(g); X25519Field.Mul(E, F, r.x); X25519Field.Mul(G, H, r.y); X25519Field.Mul(F, G, r.z); X25519Field.Mul(E, H, r.t); }
private static void PointDouble(PointAccum r) { int[] A = X25519Field.Create(); int[] B = X25519Field.Create(); int[] C = X25519Field.Create(); int[] E = r.u; int[] F = X25519Field.Create(); int[] G = X25519Field.Create(); int[] H = r.v; X25519Field.Sqr(r.x, A); X25519Field.Sqr(r.y, B); X25519Field.Sqr(r.z, C); X25519Field.Add(C, C, C); X25519Field.Apm(A, B, H, G); X25519Field.Add(r.x, r.y, E); X25519Field.Sqr(E, E); X25519Field.Sub(H, E, E); X25519Field.Add(C, G, F); X25519Field.Carry(F); X25519Field.Mul(E, F, r.x); X25519Field.Mul(G, H, r.y); X25519Field.Mul(F, G, r.z); }
public static void Precompute() { lock (precompLock) { if (precompBase != null) { return; } // Precomputed table for the base point in verification ladder { PointExt b = new PointExt(); X25519Field.Copy(B_x, 0, b.x, 0); X25519Field.Copy(B_y, 0, b.y, 0); PointExtendXY(b); precompBaseTable = PointPrecompVar(b, 1 << (WnafWidthBase - 2)); } PointAccum p = new PointAccum(); X25519Field.Copy(B_x, 0, p.x, 0); X25519Field.Copy(B_y, 0, p.y, 0); PointExtendXY(p); precompBase = new int[PrecompBlocks * PrecompPoints * 3 * X25519Field.Size]; int off = 0; for (int b = 0; b < PrecompBlocks; ++b) { PointExt[] ds = new PointExt[PrecompTeeth]; PointExt sum = new PointExt(); PointSetNeutral(sum); for (int t = 0; t < PrecompTeeth; ++t) { PointExt q = PointCopy(p); PointAddVar(true, sum, q, sum); PointDouble(p); ds[t] = PointCopy(p); if (b + t != PrecompBlocks + PrecompTeeth - 2) { for (int s = 1; s < PrecompSpacing; ++s) { PointDouble(p); } } } PointExt[] points = new PointExt[PrecompPoints]; int k = 0; points[k++] = sum; for (int t = 0; t < (PrecompTeeth - 1); ++t) { int size = 1 << t; for (int j = 0; j < size; ++j, ++k) { PointAddVar(false, points[k - size], ds[t], points[k] = new PointExt()); } } Debug.Assert(k == PrecompPoints); for (int i = 0; i < PrecompPoints; ++i) { PointExt q = points[i]; int[] x = X25519Field.Create(); int[] y = X25519Field.Create(); X25519Field.Add(q.z, q.z, x); // TODO[ed25519] Batch inversion X25519Field.Inv(x, y); X25519Field.Mul(q.x, y, x); X25519Field.Mul(q.y, y, y); PointPrecomp r = new PointPrecomp(); X25519Field.Apm(y, x, r.ypx_h, r.ymx_h); X25519Field.Mul(x, y, r.xyd); X25519Field.Mul(r.xyd, C_d4, r.xyd); X25519Field.Normalize(r.ypx_h); X25519Field.Normalize(r.ymx_h); //X25519Field.Normalize(r.xyd); X25519Field.Copy(r.ypx_h, 0, precompBase, off); off += X25519Field.Size; X25519Field.Copy(r.ymx_h, 0, precompBase, off); off += X25519Field.Size; X25519Field.Copy(r.xyd, 0, precompBase, off); off += X25519Field.Size; } } Debug.Assert(off == precompBase.Length); } }