<PackageReference Include="SSH.NET" Version="2020.0.0" />

GroupOperations

static class GroupOperations
namespace Renci.SshNet.Security.Chaos.NaCl.Internal.Ed25519Ref10 { internal static class GroupOperations { internal static void ge_add(out GroupElementP1P1 r, ref GroupElementP3 p, ref GroupElementCached q) { FieldOperations.fe_add(out r.X, ref p.Y, ref p.X); FieldOperations.fe_sub(out r.Y, ref p.Y, ref p.X); FieldOperations.fe_mul(out r.Z, ref r.X, ref q.YplusX); FieldOperations.fe_mul(out r.Y, ref r.Y, ref q.YminusX); FieldOperations.fe_mul(out r.T, ref q.T2d, ref p.T); FieldOperations.fe_mul(out r.X, ref p.Z, ref q.Z); FieldOperations.fe_add(out FieldElement h, ref r.X, ref r.X); FieldOperations.fe_sub(out r.X, ref r.Z, ref r.Y); FieldOperations.fe_add(out r.Y, ref r.Z, ref r.Y); FieldOperations.fe_add(out r.Z, ref h, ref r.T); FieldOperations.fe_sub(out r.T, ref h, ref r.T); } private static void slide(sbyte[] r, byte[] a) { for (int i = 0; i < 256; i++) { r[i] = (sbyte)(1 & (a[i >> 3] >> (i & 7))); } for (int i = 0; i < 256; i++) { if (r[i] != 0) { for (int j = 1; j <= 6 && i + j < 256; j++) { if (r[i + j] != 0) { if (r[i] + (r[i + j] << j) <= 15) { r[i] += (sbyte)(r[i + j] << j); r[i + j] = 0; } else { if (r[i] - (r[i + j] << j) < -15) break; r[i] -= (sbyte)(r[i + j] << j); for (int k = i + j; k < 256; k++) { if (r[k] == 0) { r[k] = 1; break; } r[k] = 0; } } } } } } } internal static void ge_double_scalarmult_vartime(out GroupElementP2 r, byte[] a, ref GroupElementP3 A, byte[] b) { GroupElementPreComp[] base = LookupTables.Base2; sbyte[] array = new sbyte[256]; sbyte[] array2 = new sbyte[256]; GroupElementCached[] array3 = new GroupElementCached[8]; slide(array, a); slide(array2, b); ge_p3_to_cached(out array3[0], ref A); ge_p3_dbl(out GroupElementP1P1 r2, ref A); ge_p1p1_to_p3(out GroupElementP3 r3, ref r2); ge_add(out r2, ref r3, ref array3[0]); ge_p1p1_to_p3(out GroupElementP3 r4, ref r2); ge_p3_to_cached(out array3[1], ref r4); ge_add(out r2, ref r3, ref array3[1]); ge_p1p1_to_p3(out r4, ref r2); ge_p3_to_cached(out array3[2], ref r4); ge_add(out r2, ref r3, ref array3[2]); ge_p1p1_to_p3(out r4, ref r2); ge_p3_to_cached(out array3[3], ref r4); ge_add(out r2, ref r3, ref array3[3]); ge_p1p1_to_p3(out r4, ref r2); ge_p3_to_cached(out array3[4], ref r4); ge_add(out r2, ref r3, ref array3[4]); ge_p1p1_to_p3(out r4, ref r2); ge_p3_to_cached(out array3[5], ref r4); ge_add(out r2, ref r3, ref array3[5]); ge_p1p1_to_p3(out r4, ref r2); ge_p3_to_cached(out array3[6], ref r4); ge_add(out r2, ref r3, ref array3[6]); ge_p1p1_to_p3(out r4, ref r2); ge_p3_to_cached(out array3[7], ref r4); ge_p2_0(out r); int num = 255; while (num >= 0 && array[num] == 0 && array2[num] == 0) { num--; } while (num >= 0) { ge_p2_dbl(out r2, ref r); if (array[num] > 0) { ge_p1p1_to_p3(out r4, ref r2); ge_add(out r2, ref r4, ref array3[array[num] / 2]); } else if (array[num] < 0) { ge_p1p1_to_p3(out r4, ref r2); ge_sub(out r2, ref r4, ref array3[-array[num] / 2]); } if (array2[num] > 0) { ge_p1p1_to_p3(out r4, ref r2); ge_madd(out r2, ref r4, ref base[array2[num] / 2]); } else if (array2[num] < 0) { ge_p1p1_to_p3(out r4, ref r2); ge_msub(out r2, ref r4, ref base[-array2[num] / 2]); } ge_p1p1_to_p2(out r, ref r2); num--; } } internal static int ge_frombytes_negate_vartime(out GroupElementP3 h, byte[] data, int offset) { FieldOperations.fe_frombytes(out h.Y, data, offset); FieldOperations.fe_1(out h.Z); FieldOperations.fe_sq(out FieldElement h2, ref h.Y); FieldOperations.fe_mul(out FieldElement h3, ref h2, ref LookupTables.d); FieldOperations.fe_sub(out h2, ref h2, ref h.Z); FieldOperations.fe_add(out h3, ref h3, ref h.Z); FieldOperations.fe_sq(out FieldElement h4, ref h3); FieldOperations.fe_mul(out h4, ref h4, ref h3); FieldOperations.fe_sq(out h.X, ref h4); FieldOperations.fe_mul(out h.X, ref h.X, ref h3); FieldOperations.fe_mul(out h.X, ref h.X, ref h2); FieldOperations.fe_pow22523(out h.X, ref h.X); FieldOperations.fe_mul(out h.X, ref h.X, ref h4); FieldOperations.fe_mul(out h.X, ref h.X, ref h2); FieldOperations.fe_sq(out FieldElement h5, ref h.X); FieldOperations.fe_mul(out h5, ref h5, ref h3); FieldOperations.fe_sub(out FieldElement h6, ref h5, ref h2); if (FieldOperations.fe_isnonzero(ref h6) != 0) { FieldOperations.fe_add(out h6, ref h5, ref h2); if (FieldOperations.fe_isnonzero(ref h6) != 0) { h = default(GroupElementP3); return -1; } FieldOperations.fe_mul(out h.X, ref h.X, ref LookupTables.sqrtm1); } if (FieldOperations.fe_isnegative(ref h.X) == data[offset + 31] >> 7) FieldOperations.fe_neg(out h.X, ref h.X); FieldOperations.fe_mul(out h.T, ref h.X, ref h.Y); return 0; } internal static void ge_madd(out GroupElementP1P1 r, ref GroupElementP3 p, ref GroupElementPreComp q) { FieldOperations.fe_add(out r.X, ref p.Y, ref p.X); FieldOperations.fe_sub(out r.Y, ref p.Y, ref p.X); FieldOperations.fe_mul(out r.Z, ref r.X, ref q.yplusx); FieldOperations.fe_mul(out r.Y, ref r.Y, ref q.yminusx); FieldOperations.fe_mul(out r.T, ref q.xy2d, ref p.T); FieldOperations.fe_add(out FieldElement h, ref p.Z, ref p.Z); FieldOperations.fe_sub(out r.X, ref r.Z, ref r.Y); FieldOperations.fe_add(out r.Y, ref r.Z, ref r.Y); FieldOperations.fe_add(out r.Z, ref h, ref r.T); FieldOperations.fe_sub(out r.T, ref h, ref r.T); } internal static void ge_msub(out GroupElementP1P1 r, ref GroupElementP3 p, ref GroupElementPreComp q) { FieldOperations.fe_add(out r.X, ref p.Y, ref p.X); FieldOperations.fe_sub(out r.Y, ref p.Y, ref p.X); FieldOperations.fe_mul(out r.Z, ref r.X, ref q.yminusx); FieldOperations.fe_mul(out r.Y, ref r.Y, ref q.yplusx); FieldOperations.fe_mul(out r.T, ref q.xy2d, ref p.T); FieldOperations.fe_add(out FieldElement h, ref p.Z, ref p.Z); FieldOperations.fe_sub(out r.X, ref r.Z, ref r.Y); FieldOperations.fe_add(out r.Y, ref r.Z, ref r.Y); FieldOperations.fe_sub(out r.Z, ref h, ref r.T); FieldOperations.fe_add(out r.T, ref h, ref r.T); } internal static void ge_p1p1_to_p2(out GroupElementP2 r, ref GroupElementP1P1 p) { FieldOperations.fe_mul(out r.X, ref p.X, ref p.T); FieldOperations.fe_mul(out r.Y, ref p.Y, ref p.Z); FieldOperations.fe_mul(out r.Z, ref p.Z, ref p.T); } internal static void ge_p1p1_to_p3(out GroupElementP3 r, ref GroupElementP1P1 p) { FieldOperations.fe_mul(out r.X, ref p.X, ref p.T); FieldOperations.fe_mul(out r.Y, ref p.Y, ref p.Z); FieldOperations.fe_mul(out r.Z, ref p.Z, ref p.T); FieldOperations.fe_mul(out r.T, ref p.X, ref p.Y); } internal static void ge_p2_0(out GroupElementP2 h) { FieldOperations.fe_0(out h.X); FieldOperations.fe_1(out h.Y); FieldOperations.fe_1(out h.Z); } internal static void ge_p2_dbl(out GroupElementP1P1 r, ref GroupElementP2 p) { FieldOperations.fe_sq(out r.X, ref p.X); FieldOperations.fe_sq(out r.Z, ref p.Y); FieldOperations.fe_sq2(out r.T, ref p.Z); FieldOperations.fe_add(out r.Y, ref p.X, ref p.Y); FieldOperations.fe_sq(out FieldElement h, ref r.Y); FieldOperations.fe_add(out r.Y, ref r.Z, ref r.X); FieldOperations.fe_sub(out r.Z, ref r.Z, ref r.X); FieldOperations.fe_sub(out r.X, ref h, ref r.Y); FieldOperations.fe_sub(out r.T, ref r.T, ref r.Z); } internal static void ge_p3_0(out GroupElementP3 h) { FieldOperations.fe_0(out h.X); FieldOperations.fe_1(out h.Y); FieldOperations.fe_1(out h.Z); FieldOperations.fe_0(out h.T); } internal static void ge_p3_dbl(out GroupElementP1P1 r, ref GroupElementP3 p) { ge_p3_to_p2(out GroupElementP2 r2, ref p); ge_p2_dbl(out r, ref r2); } internal static void ge_p3_tobytes(byte[] s, int offset, ref GroupElementP3 h) { FieldOperations.fe_invert(out FieldElement result, ref h.Z); FieldOperations.fe_mul(out FieldElement h2, ref h.X, ref result); FieldOperations.fe_mul(out FieldElement h3, ref h.Y, ref result); FieldOperations.fe_tobytes(s, offset, ref h3); s[offset + 31] ^= (byte)(FieldOperations.fe_isnegative(ref h2) << 7); } internal static void ge_p3_to_cached(out GroupElementCached r, ref GroupElementP3 p) { FieldOperations.fe_add(out r.YplusX, ref p.Y, ref p.X); FieldOperations.fe_sub(out r.YminusX, ref p.Y, ref p.X); r.Z = p.Z; FieldOperations.fe_mul(out r.T2d, ref p.T, ref LookupTables.d2); } internal static void ge_p3_to_p2(out GroupElementP2 r, ref GroupElementP3 p) { r.X = p.X; r.Y = p.Y; r.Z = p.Z; } internal static void ge_precomp_0(out GroupElementPreComp h) { FieldOperations.fe_1(out h.yplusx); FieldOperations.fe_1(out h.yminusx); FieldOperations.fe_0(out h.xy2d); } private static byte equal(byte b, byte c) { byte b2 = c; return (byte)((uint)((byte)(b ^ b2) - 1) >> 31); } private static byte negative(sbyte b) { return (byte)((ulong)b >> 63); } private static void cmov(ref GroupElementPreComp t, ref GroupElementPreComp u, byte b) { FieldOperations.fe_cmov(ref t.yplusx, ref u.yplusx, b); FieldOperations.fe_cmov(ref t.yminusx, ref u.yminusx, b); FieldOperations.fe_cmov(ref t.xy2d, ref u.xy2d, b); } private static void select(out GroupElementPreComp t, int pos, sbyte b) { byte b2 = negative(b); byte b3 = (byte)(b - ((-b2 & b) << 1)); ge_precomp_0(out t); GroupElementPreComp[] array = LookupTables.Base[pos]; cmov(ref t, ref array[0], equal(b3, 1)); cmov(ref t, ref array[1], equal(b3, 2)); cmov(ref t, ref array[2], equal(b3, 3)); cmov(ref t, ref array[3], equal(b3, 4)); cmov(ref t, ref array[4], equal(b3, 5)); cmov(ref t, ref array[5], equal(b3, 6)); cmov(ref t, ref array[6], equal(b3, 7)); cmov(ref t, ref array[7], equal(b3, 8)); GroupElementPreComp u = default(GroupElementPreComp); u.yplusx = t.yminusx; u.yminusx = t.yplusx; FieldOperations.fe_neg(out u.xy2d, ref t.xy2d); cmov(ref t, ref u, b2); } internal static void ge_scalarmult_base(out GroupElementP3 h, byte[] a, int offset) { sbyte[] array = new sbyte[64]; for (int i = 0; i < 32; i++) { array[2 * i] = (sbyte)(a[offset + i] & 15); array[2 * i + 1] = (sbyte)((a[offset + i] >> 4) & 15); } sbyte b = 0; for (int i = 0; i < 63; i++) { array[i] += b; b = (sbyte)(array[i] + 8); b = (sbyte)(b >> 4); array[i] -= (sbyte)(b << 4); } array[63] += b; ge_p3_0(out h); GroupElementPreComp t; GroupElementP1P1 r; for (int i = 1; i < 64; i += 2) { select(out t, i / 2, array[i]); ge_madd(out r, ref h, ref t); ge_p1p1_to_p3(out h, ref r); } ge_p3_dbl(out r, ref h); ge_p1p1_to_p2(out GroupElementP2 r2, ref r); ge_p2_dbl(out r, ref r2); ge_p1p1_to_p2(out r2, ref r); ge_p2_dbl(out r, ref r2); ge_p1p1_to_p2(out r2, ref r); ge_p2_dbl(out r, ref r2); ge_p1p1_to_p3(out h, ref r); for (int i = 0; i < 64; i += 2) { select(out t, i / 2, array[i]); ge_madd(out r, ref h, ref t); ge_p1p1_to_p3(out h, ref r); } } internal static void ge_sub(out GroupElementP1P1 r, ref GroupElementP3 p, ref GroupElementCached q) { FieldOperations.fe_add(out r.X, ref p.Y, ref p.X); FieldOperations.fe_sub(out r.Y, ref p.Y, ref p.X); FieldOperations.fe_mul(out r.Z, ref r.X, ref q.YminusX); FieldOperations.fe_mul(out r.Y, ref r.Y, ref q.YplusX); FieldOperations.fe_mul(out r.T, ref q.T2d, ref p.T); FieldOperations.fe_mul(out r.X, ref p.Z, ref q.Z); FieldOperations.fe_add(out FieldElement h, ref r.X, ref r.X); FieldOperations.fe_sub(out r.X, ref r.Z, ref r.Y); FieldOperations.fe_add(out r.Y, ref r.Z, ref r.Y); FieldOperations.fe_sub(out r.Z, ref h, ref r.T); FieldOperations.fe_add(out r.T, ref h, ref r.T); } internal static void ge_tobytes(byte[] s, int offset, ref GroupElementP2 h) { FieldOperations.fe_invert(out FieldElement result, ref h.Z); FieldOperations.fe_mul(out FieldElement h2, ref h.X, ref result); FieldOperations.fe_mul(out FieldElement h3, ref h.Y, ref result); FieldOperations.fe_tobytes(s, offset, ref h3); s[offset + 31] ^= (byte)(FieldOperations.fe_isnegative(ref h2) << 7); } } }