private static void PointDouble(PointExt r) { uint[] B = X448Field.Create(); uint[] C = X448Field.Create(); uint[] D = X448Field.Create(); uint[] E = X448Field.Create(); uint[] H = X448Field.Create(); uint[] J = X448Field.Create(); X448Field.Add(r.x, r.y, B); X448Field.Sqr(B, B); X448Field.Sqr(r.x, C); X448Field.Sqr(r.y, D); X448Field.Add(C, D, E); X448Field.Carry(E); X448Field.Sqr(r.z, H); X448Field.Add(H, H, H); X448Field.Carry(H); X448Field.Sub(E, H, J); X448Field.Sub(B, E, B); X448Field.Sub(C, D, C); X448Field.Mul(B, J, r.x); X448Field.Mul(E, C, r.y); X448Field.Mul(E, J, r.z); }
private static uint[] PointPrecompute(PointExt p, int count) { Debug.Assert(count > 0); PointExt q = PointCopy(p); PointExt d = PointCopy(q); PointDouble(d); uint[] table = X448Field.CreateTable(count * 3); int off = 0; int i = 0; for (;;) { F.Copy(q.x, 0, table, off); off += F.Size; F.Copy(q.y, 0, table, off); off += F.Size; F.Copy(q.z, 0, table, off); off += F.Size; if (++i == count) { break; } PointAdd(d, q); } return(table); }
private static void PointAddPrecomp(PointPrecomp p, PointExt r) { uint[] B = X448Field.Create(); uint[] C = X448Field.Create(); uint[] D = X448Field.Create(); uint[] E = X448Field.Create(); uint[] F = X448Field.Create(); uint[] G = X448Field.Create(); uint[] H = X448Field.Create(); X448Field.Sqr(r.z, B); X448Field.Mul(p.x, r.x, C); X448Field.Mul(p.y, r.y, D); X448Field.Mul(C, D, E); X448Field.Mul(E, -C_d, E); //X448Field.Apm(B, E, F, G); X448Field.Add(B, E, F); X448Field.Sub(B, E, G); X448Field.Add(p.x, p.y, B); X448Field.Add(r.x, r.y, E); X448Field.Mul(B, E, H); //X448Field.Apm(D, C, B, E); X448Field.Add(D, C, B); X448Field.Sub(D, C, E); X448Field.Carry(B); X448Field.Sub(H, B, H); X448Field.Mul(H, r.z, H); X448Field.Mul(E, r.z, E); X448Field.Mul(F, H, r.x); X448Field.Mul(E, G, r.y); X448Field.Mul(F, G, r.z); }
private static PointExt PointCopy(PointExt p) { PointExt r = new PointExt(); X448Field.Copy(p.x, 0, r.x, 0); X448Field.Copy(p.y, 0, r.y, 0); X448Field.Copy(p.z, 0, r.z, 0); return(r); }
private static void ScalarMultBase(byte[] k, PointExt r) { Precompute(); PointSetNeutral(r); uint[] n = new uint[ScalarUints + 1]; DecodeScalar(k, 0, n); // Recode the scalar into signed-digit form { n[ScalarUints] = 4U + Nat.CAdd(ScalarUints, ~(int)n[0] & 1, n, L, n); uint c = Nat.ShiftDownBit(n.Length, n, 0); Debug.Assert(c == (1U << 31)); } PointPrecomp p = new PointPrecomp(); int cOff = PrecompSpacing - 1; for (;;) { int tPos = cOff; for (int b = 0; b < PrecompBlocks; ++b) { uint w = 0; for (int t = 0; t < PrecompTeeth; ++t) { uint tBit = n[tPos >> 5] >> (tPos & 0x1F); w &= ~(1U << t); w ^= (tBit << t); tPos += PrecompSpacing; } int sign = (int)(w >> (PrecompTeeth - 1)) & 1; int abs = ((int)w ^ -sign) & PrecompMask; Debug.Assert(sign == 0 || sign == 1); Debug.Assert(0 <= abs && abs < PrecompPoints); PointLookup(b, abs, p); X448Field.CNegate(sign, p.x); PointAddPrecomp(p, r); } if (--cOff < 0) { break; } PointDouble(r); } }
internal static void ScalarMultBaseXY(byte[] k, int kOff, uint[] x, uint[] y) { byte[] n = new byte[ScalarBytes]; PruneScalar(k, kOff, n); PointExt p = new PointExt(); ScalarMultBase(n, p); X448Field.Copy(p.x, 0, x, 0); X448Field.Copy(p.y, 0, y, 0); }
private static void PointLookup(int block, int index, PointPrecomp p) { Debug.Assert(0 <= block && block < PrecompBlocks); Debug.Assert(0 <= index && index < PrecompPoints); int off = block * PrecompPoints * 2 * X448Field.Size; for (int i = 0; i < PrecompPoints; ++i) { int cond = ((i ^ index) - 1) >> 31; X448Field.CMov(cond, precompBase, off, p.x, 0); off += X448Field.Size; X448Field.CMov(cond, precompBase, off, p.y, 0); off += X448Field.Size; } }
private static void EncodePoint(PointExt p, byte[] r, int rOff) { uint[] x = X448Field.Create(); uint[] y = X448Field.Create(); X448Field.Inv(p.z, y); X448Field.Mul(p.x, y, x); X448Field.Mul(p.y, y, y); X448Field.Normalize(x); X448Field.Normalize(y); X448Field.Encode(y, r, rOff); r[rOff + PointBytes - 1] = (byte)((x[0] & 1) << 7); }
private static int CheckPoint(uint[] x, uint[] y) { uint[] t = X448Field.Create(); uint[] u = X448Field.Create(); uint[] v = X448Field.Create(); X448Field.Sqr(x, u); X448Field.Sqr(y, v); X448Field.Mul(u, v, t); X448Field.Add(u, v, u); X448Field.Mul(t, -C_d, t); X448Field.SubOne(t); X448Field.Add(t, u, t); X448Field.Normalize(t); return(X448Field.IsZero(t)); }
internal static void ScalarMultBaseXY(byte[] k, int kOff, uint[] x, uint[] y) { byte[] n = new byte[ScalarBytes]; PruneScalar(k, kOff, n); PointExt p = new PointExt(); ScalarMultBase(n, p); if (0 == CheckPoint(p.x, p.y, p.z)) { throw new InvalidOperationException(); } X448Field.Copy(p.x, 0, x, 0); X448Field.Copy(p.y, 0, y, 0); }
private static void PointAddVar(bool negate, PointExt p, PointExt r) { uint[] A = X448Field.Create(); uint[] B = X448Field.Create(); uint[] C = X448Field.Create(); uint[] D = X448Field.Create(); uint[] E = X448Field.Create(); uint[] F = X448Field.Create(); uint[] G = X448Field.Create(); uint[] H = X448Field.Create(); uint[] b, e, f, g; if (negate) { b = E; e = B; f = G; g = F; X448Field.Sub(p.y, p.x, H); } else { b = B; e = E; f = F; g = G; X448Field.Add(p.y, p.x, H); } X448Field.Mul(p.z, r.z, A); X448Field.Sqr(A, B); X448Field.Mul(p.x, r.x, C); X448Field.Mul(p.y, r.y, D); X448Field.Mul(C, D, E); X448Field.Mul(E, -C_d, E); //X448Field.Apm(B, E, F, G); X448Field.Add(B, E, f); X448Field.Sub(B, E, g); X448Field.Add(r.x, r.y, E); X448Field.Mul(H, E, H); //X448Field.Apm(D, C, B, E); X448Field.Add(D, C, b); X448Field.Sub(D, C, e); X448Field.Carry(b); X448Field.Sub(H, B, H); X448Field.Mul(H, A, H); X448Field.Mul(E, A, E); X448Field.Mul(F, H, r.x); X448Field.Mul(E, G, r.y); X448Field.Mul(F, G, r.z); }
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; X448Field.Decode(py, 0, r.y); uint[] u = X448Field.Create(); uint[] v = X448Field.Create(); X448Field.Sqr(r.y, u); X448Field.Mul(u, (uint)-C_d, v); X448Field.Negate(u, u); X448Field.AddOne(u); X448Field.AddOne(v); if (!X448Field.SqrtRatioVar(u, v, r.x)) { return(false); } X448Field.Normalize(r.x); if (x_0 == 1 && X448Field.IsZeroVar(r.x)) { return(false); } if (negate ^ (x_0 != (r.x[0] & 1))) { X448Field.Negate(r.x, r.x); } PointExtendXY(r); return(true); }
public static void Precompute() { lock (precompLock) { if (precompBase != null) { return; } PointExt p = new PointExt(); X448Field.Copy(B_x, 0, p.x, 0); X448Field.Copy(B_y, 0, p.y, 0); PointExtendXY(p); precompBaseTable = PointPrecompVar(p, 1 << (WnafWidthBase - 2)); precompBase = new uint[PrecompBlocks * PrecompPoints * 2 * X448Field.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) { PointAddVar(true, p, 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) { points[k] = PointCopy(points[k - size]); PointAddVar(false, ds[t], points[k]); } } Debug.Assert(k == PrecompPoints); for (int i = 0; i < PrecompPoints; ++i) { PointExt q = points[i]; // TODO[ed448] Batch inversion X448Field.Inv(q.z, q.z); X448Field.Mul(q.x, q.z, q.x); X448Field.Mul(q.y, q.z, q.y); //X448Field.Normalize(q.x); //X448Field.Normalize(q.y); X448Field.Copy(q.x, 0, precompBase, off); off += X448Field.Size; X448Field.Copy(q.y, 0, precompBase, off); off += X448Field.Size; } } Debug.Assert(off == precompBase.Length); } }
private static void PointSetNeutral(PointExt p) { X448Field.Zero(p.x); X448Field.One(p.y); X448Field.One(p.z); }
private static void PointExtendXY(PointExt p) { X448Field.One(p.z); }