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 void PointAddPrecomp(PointPrecomp p, PointExt r) { uint[] b = F.Create(); uint[] c = F.Create(); uint[] d = F.Create(); uint[] e = F.Create(); uint[] f = F.Create(); uint[] g = F.Create(); uint[] h = F.Create(); F.Sqr(r.z, b); F.Mul(p.x, r.x, c); F.Mul(p.y, r.y, d); F.Mul(c, d, e); F.Mul(e, -C_d, e); //F.Apm(b, e, f, g); F.Add(b, e, f); F.Sub(b, e, g); F.Add(p.x, p.y, b); F.Add(r.x, r.y, e); F.Mul(b, e, h); //F.Apm(d, c, b, e); F.Add(d, c, b); F.Sub(d, c, e); F.Carry(b); F.Sub(h, b, h); F.Mul(h, r.z, h); F.Mul(e, r.z, e); F.Mul(f, h, r.x); F.Mul(e, g, r.y); F.Mul(f, g, r.z); }
private static void ScalarMultBase(byte[] k, PointExt r) { Precompute(); 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(); PointSetNeutral(r); 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); F.CNegate(sign, p.x); PointAddPrecomp(p, r); } if (--cOff < 0) { break; } PointDouble(r); } }
private static void ScalarMultBase(byte[] k, PointAccum r) { Precompute(); PointSetNeutral(r); uint[] n = new uint[ScalarUints]; DecodeScalar(k, 0, n); // Recode the scalar into signed-digit form, then group comb bits in each block { uint c1 = Nat.CAdd(ScalarUints, ~(int)n[0] & 1, n, L, n); Debug.Assert(c1 == 0); uint c2 = Nat.ShiftDownBit(ScalarUints, n, 1U); Debug.Assert(c2 == (1U << 31)); for (int i = 0; i < ScalarUints; ++i) { n[i] = Interleave.Shuffle2(n[i]); } } PointPrecomp p = new PointPrecomp(); int cOff = (PrecompSpacing - 1) * PrecompTeeth; for (; ;) { for (int b = 0; b < PrecompBlocks; ++b) { uint w = n[b] >> cOff; 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); X25519Field.CSwap(sign, p.ypx_h, p.ymx_h); X25519Field.CNegate(sign, p.xyd); PointAddPrecomp(p, r); } if ((cOff -= PrecompTeeth) < 0) { break; } PointDouble(r); } }
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 * F.Size; for (int i = 0; i < PrecompPoints; ++i) { int cond = ((i ^ index) - 1) >> 31; F.CMov(cond, precompBase, off, p.x, 0); off += F.Size; F.CMov(cond, precompBase, off, p.y, 0); off += F.Size; } }
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 mask = ((i ^ index) - 1) >> 31; Nat.CMov(X448Field.Size, mask, precompBase, off, p.x, 0); off += X448Field.Size; Nat.CMov(X448Field.Size, mask, precompBase, off, p.y, 0); off += X448Field.Size; } }
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 * 3 * X25519Field.Size; for (int i = 0; i < PrecompPoints; ++i) { int cond = ((i ^ index) - 1) >> 31; X25519Field.CMov(cond, precompBase, off, p.ypx_h, 0); off += X25519Field.Size; X25519Field.CMov(cond, precompBase, off, p.ymx_h, 0); off += X25519Field.Size; X25519Field.CMov(cond, precompBase, off, p.xyd, 0); off += X25519Field.Size; } }
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 PointAddPrecomp(PointPrecomp p, PointAccum r) { int[] a = F.Create(); int[] b = F.Create(); int[] c = F.Create(); int[] e = r.u; int[] f = F.Create(); int[] g = F.Create(); int[] h = r.v; F.Apm(r.y, r.x, b, a); F.Mul(a, p.ymx_h, a); F.Mul(b, p.ypx_h, b); F.Mul(r.u, r.v, c); F.Mul(c, p.xyd, c); F.Apm(b, a, h, e); F.Apm(r.z, c, g, f); F.Carry(g); F.Mul(e, f, r.x); F.Mul(g, h, r.y); F.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); } }
public static void Precompute() { lock (precompLock) { if (precompBase != null) { return; } // Precomputed table for the base point in verification ladder { PointExt b = new PointExt(); F.Copy(B_x, 0, b.x, 0); F.Copy(B_y, 0, b.y, 0); PointExtendXY(b); precompBaseTable = PointPrecomputeVar(b, 1 << (WnafWidthBase - 2)); } PointAccum p = new PointAccum(); F.Copy(B_x, 0, p.x, 0); F.Copy(B_y, 0, p.y, 0); PointExtendXY(p); precompBase = F.CreateTable(PrecompBlocks * PrecompPoints * 3); 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); int[] cs = F.CreateTable(PrecompPoints); // TODO[ed25519] A single batch inversion across all blocks? { int[] u = F.Create(); F.Copy(points[0].z, 0, u, 0); F.Copy(u, 0, cs, 0); int i = 0; while (++i < PrecompPoints) { F.Mul(u, points[i].z, u); F.Copy(u, 0, cs, i * F.Size); } F.Add(u, u, u); F.InvVar(u, u); --i; int[] t = F.Create(); while (i > 0) { int j = i--; F.Copy(cs, i * F.Size, t, 0); F.Mul(t, u, t); F.Copy(t, 0, cs, j * F.Size); F.Mul(u, points[j].z, u); } F.Copy(u, 0, cs, 0); } for (int i = 0; i < PrecompPoints; ++i) { PointExt q = points[i]; int[] x = F.Create(); int[] y = F.Create(); //F.Add(q.z, q.z, x); //F.InvVar(x, y); F.Copy(cs, i * F.Size, y, 0); F.Mul(q.x, y, x); F.Mul(q.y, y, y); PointPrecomp r = new PointPrecomp(); F.Apm(y, x, r.ypx_h, r.ymx_h); F.Mul(x, y, r.xyd); F.Mul(r.xyd, C_d4, r.xyd); F.Normalize(r.ypx_h); F.Normalize(r.ymx_h); //F.Normalize(r.xyd); F.Copy(r.ypx_h, 0, precompBase, off); off += F.Size; F.Copy(r.ymx_h, 0, precompBase, off); off += F.Size; F.Copy(r.xyd, 0, precompBase, off); off += F.Size; } } Debug.Assert(off == precompBase.Length); } }
private static void Precompute() { 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()); } } for (int i = 0; i < PrecompPoints; ++i) { PointExt q = points[i]; int[] x = new int[X25519Field.Size]; int[] y = new int[X25519Field.Size]; X25519Field.Add(q.z, q.z, x); 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.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; } } }