| | | 1 | | using System; |
| | | 2 | | |
| | | 3 | | namespace Renci.SshNet.Security.Chaos.NaCl.Internal.Ed25519Ref10 |
| | | 4 | | { |
| | | 5 | | internal static partial class GroupOperations |
| | | 6 | | { |
| | | 7 | | static byte equal(byte b, byte c) |
| | 4096 | 8 | | { |
| | | 9 | | |
| | 4096 | 10 | | byte ub = b; |
| | 4096 | 11 | | byte uc = c; |
| | 4096 | 12 | | byte x = (byte)(ub ^ uc); /* 0: yes; 1..255: no */ |
| | 4096 | 13 | | UInt32 y = x; /* 0: yes; 1..255: no */ |
| | 12288 | 14 | | unchecked { y -= 1; } /* 4294967295: yes; 0..254: no */ |
| | 4096 | 15 | | y >>= 31; /* 1: yes; 0: no */ |
| | 4096 | 16 | | return (byte)y; |
| | 4096 | 17 | | } |
| | | 18 | | |
| | | 19 | | static byte negative(sbyte b) |
| | 512 | 20 | | { |
| | 512 | 21 | | ulong x = unchecked((ulong)(long)b); /* 18446744073709551361..18446744073709551615: yes; 0..255: no */ |
| | 512 | 22 | | x >>= 63; /* 1: yes; 0: no */ |
| | 512 | 23 | | return (byte)x; |
| | 512 | 24 | | } |
| | | 25 | | |
| | | 26 | | static void cmov(ref GroupElementPreComp t, ref GroupElementPreComp u, byte b) |
| | 4608 | 27 | | { |
| | 4608 | 28 | | FieldOperations.fe_cmov(ref t.yplusx, ref u.yplusx, b); |
| | 4608 | 29 | | FieldOperations.fe_cmov(ref t.yminusx, ref u.yminusx, b); |
| | 4608 | 30 | | FieldOperations.fe_cmov(ref t.xy2d, ref u.xy2d, b); |
| | 4608 | 31 | | } |
| | | 32 | | |
| | | 33 | | static void select(out GroupElementPreComp t, int pos, sbyte b) |
| | 512 | 34 | | { |
| | | 35 | | GroupElementPreComp minust; |
| | 512 | 36 | | byte bnegative = negative(b); |
| | 512 | 37 | | byte babs = (byte)(b - (((-bnegative) & b) << 1)); |
| | | 38 | | |
| | 512 | 39 | | ge_precomp_0(out t); |
| | 512 | 40 | | var table = LookupTables.Base[pos]; |
| | 512 | 41 | | cmov(ref t, ref table[0], equal(babs, 1)); |
| | 512 | 42 | | cmov(ref t, ref table[1], equal(babs, 2)); |
| | 512 | 43 | | cmov(ref t, ref table[2], equal(babs, 3)); |
| | 512 | 44 | | cmov(ref t, ref table[3], equal(babs, 4)); |
| | 512 | 45 | | cmov(ref t, ref table[4], equal(babs, 5)); |
| | 512 | 46 | | cmov(ref t, ref table[5], equal(babs, 6)); |
| | 512 | 47 | | cmov(ref t, ref table[6], equal(babs, 7)); |
| | 512 | 48 | | cmov(ref t, ref table[7], equal(babs, 8)); |
| | 512 | 49 | | minust.yplusx = t.yminusx; |
| | 512 | 50 | | minust.yminusx = t.yplusx; |
| | 512 | 51 | | FieldOperations.fe_neg(out minust.xy2d, ref t.xy2d); |
| | 512 | 52 | | cmov(ref t, ref minust, bnegative); |
| | 512 | 53 | | } |
| | | 54 | | |
| | | 55 | | /* |
| | | 56 | | h = a * B |
| | | 57 | | where a = a[0]+256*a[1]+...+256^31 a[31] |
| | | 58 | | B is the Ed25519 base point (x,4/5) with x positive. |
| | | 59 | | |
| | | 60 | | Preconditions: |
| | | 61 | | a[31] <= 127 |
| | | 62 | | */ |
| | | 63 | | |
| | | 64 | | internal static void ge_scalarmult_base(out GroupElementP3 h, byte[] a, int offset) |
| | 8 | 65 | | { |
| | | 66 | | // todo: Perhaps remove this allocation |
| | 8 | 67 | | sbyte[] e = new sbyte[64]; |
| | | 68 | | sbyte carry; |
| | | 69 | | GroupElementP1P1 r; |
| | | 70 | | GroupElementP2 s; |
| | | 71 | | GroupElementPreComp t; |
| | | 72 | | int i; |
| | | 73 | | |
| | 528 | 74 | | for (i = 0; i < 32; ++i) |
| | 256 | 75 | | { |
| | 256 | 76 | | e[2 * i + 0] = (sbyte)((a[offset + i] >> 0) & 15); |
| | 256 | 77 | | e[2 * i + 1] = (sbyte)((a[offset + i] >> 4) & 15); |
| | 256 | 78 | | } |
| | | 79 | | /* each e[i] is between 0 and 15 */ |
| | | 80 | | /* e[63] is between 0 and 7 */ |
| | | 81 | | |
| | 8 | 82 | | carry = 0; |
| | 1024 | 83 | | for (i = 0; i < 63; ++i) |
| | 504 | 84 | | { |
| | 504 | 85 | | e[i] += carry; |
| | 504 | 86 | | carry = (sbyte)(e[i] + 8); |
| | 504 | 87 | | carry >>= 4; |
| | 504 | 88 | | e[i] -= (sbyte)(carry << 4); |
| | 504 | 89 | | } |
| | 8 | 90 | | e[63] += carry; |
| | | 91 | | /* each e[i] is between -8 and 8 */ |
| | | 92 | | |
| | 8 | 93 | | ge_p3_0(out h); |
| | 528 | 94 | | for (i = 1; i < 64; i += 2) |
| | 256 | 95 | | { |
| | 256 | 96 | | select(out t, i / 2, e[i]); |
| | 512 | 97 | | ge_madd(out r, ref h, ref t); ge_p1p1_to_p3(out h, ref r); |
| | 256 | 98 | | } |
| | | 99 | | |
| | 16 | 100 | | ge_p3_dbl(out r, ref h); ge_p1p1_to_p2(out s, ref r); |
| | 16 | 101 | | ge_p2_dbl(out r, ref s); ge_p1p1_to_p2(out s, ref r); |
| | 16 | 102 | | ge_p2_dbl(out r, ref s); ge_p1p1_to_p2(out s, ref r); |
| | 16 | 103 | | ge_p2_dbl(out r, ref s); ge_p1p1_to_p3(out h, ref r); |
| | | 104 | | |
| | 528 | 105 | | for (i = 0; i < 64; i += 2) |
| | 256 | 106 | | { |
| | 256 | 107 | | select(out t, i / 2, e[i]); |
| | 512 | 108 | | ge_madd(out r, ref h, ref t); ge_p1p1_to_p3(out h, ref r); |
| | 256 | 109 | | } |
| | 8 | 110 | | } |
| | | 111 | | |
| | | 112 | | } |
| | | 113 | | } |