Ed25519.cs 47 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using System.Diagnostics;
  5. using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto;
  6. using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Digests;
  7. using BestHTTP.SecureProtocol.Org.BouncyCastle.Math.EC.Rfc7748;
  8. using BestHTTP.SecureProtocol.Org.BouncyCastle.Math.Raw;
  9. using BestHTTP.SecureProtocol.Org.BouncyCastle.Security;
  10. using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  11. namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Math.EC.Rfc8032
  12. {
  13. public abstract class Ed25519
  14. {
  15. // -x^2 + y^2 == 1 + 0x52036CEE2B6FFE738CC740797779E89800700A4D4141D8AB75EB4DCA135978A3 * x^2 * y^2
  16. public enum Algorithm
  17. {
  18. Ed25519 = 0,
  19. Ed25519ctx = 1,
  20. Ed25519ph = 2,
  21. }
  22. private class F : X25519Field {};
  23. private const long M08L = 0x000000FFL;
  24. private const long M28L = 0x0FFFFFFFL;
  25. private const long M32L = 0xFFFFFFFFL;
  26. private const int CoordUints = 8;
  27. private const int PointBytes = CoordUints * 4;
  28. private const int ScalarUints = 8;
  29. private const int ScalarBytes = ScalarUints * 4;
  30. public static readonly int PrehashSize = 64;
  31. public static readonly int PublicKeySize = PointBytes;
  32. public static readonly int SecretKeySize = 32;
  33. public static readonly int SignatureSize = PointBytes + ScalarBytes;
  34. // "SigEd25519 no Ed25519 collisions"
  35. private static readonly byte[] Dom2Prefix = new byte[]{ 0x53, 0x69, 0x67, 0x45, 0x64, 0x32, 0x35, 0x35, 0x31,
  36. 0x39, 0x20, 0x6e, 0x6f, 0x20, 0x45, 0x64, 0x32, 0x35, 0x35, 0x31, 0x39, 0x20, 0x63, 0x6f, 0x6c, 0x6c, 0x69,
  37. 0x73, 0x69, 0x6f, 0x6e, 0x73 };
  38. private static readonly uint[] P = { 0xFFFFFFEDU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU,
  39. 0xFFFFFFFFU, 0xFFFFFFFFU, 0x7FFFFFFFU };
  40. private static readonly uint[] L = { 0x5CF5D3EDU, 0x5812631AU, 0xA2F79CD6U, 0x14DEF9DEU, 0x00000000U,
  41. 0x00000000U, 0x00000000U, 0x10000000U };
  42. private const int L0 = unchecked((int)0xFCF5D3ED); // L0:26/--
  43. private const int L1 = 0x012631A6; // L1:24/22
  44. private const int L2 = 0x079CD658; // L2:27/--
  45. private const int L3 = unchecked((int)0xFF9DEA2F); // L3:23/--
  46. private const int L4 = 0x000014DF; // L4:12/11
  47. private static readonly int[] B_x = { 0x0325D51A, 0x018B5823, 0x007B2C95, 0x0304A92D, 0x00D2598E, 0x01D6DC5C,
  48. 0x01388C7F, 0x013FEC0A, 0x029E6B72, 0x0042D26D };
  49. private static readonly int[] B_y = { 0x02666658, 0x01999999, 0x00666666, 0x03333333, 0x00CCCCCC, 0x02666666,
  50. 0x01999999, 0x00666666, 0x03333333, 0x00CCCCCC, };
  51. private static readonly int[] C_d = { 0x035978A3, 0x02D37284, 0x018AB75E, 0x026A0A0E, 0x0000E014, 0x0379E898,
  52. 0x01D01E5D, 0x01E738CC, 0x03715B7F, 0x00A406D9 };
  53. private static readonly int[] C_d2 = { 0x02B2F159, 0x01A6E509, 0x01156EBD, 0x00D4141D, 0x0001C029, 0x02F3D130,
  54. 0x03A03CBB, 0x01CE7198, 0x02E2B6FF, 0x00480DB3 };
  55. private static readonly int[] C_d4 = { 0x0165E2B2, 0x034DCA13, 0x002ADD7A, 0x01A8283B, 0x00038052, 0x01E7A260,
  56. 0x03407977, 0x019CE331, 0x01C56DFF, 0x00901B67 };
  57. private const int WnafWidthBase = 7;
  58. private const int PrecompBlocks = 8;
  59. private const int PrecompTeeth = 4;
  60. private const int PrecompSpacing = 8;
  61. private const int PrecompPoints = 1 << (PrecompTeeth - 1);
  62. private const int PrecompMask = PrecompPoints - 1;
  63. private static readonly object precompLock = new object();
  64. // TODO[ed25519] Convert to PointPrecomp
  65. private static PointExt[] precompBaseTable = null;
  66. private static int[] precompBase = null;
  67. private class PointAccum
  68. {
  69. internal int[] x = F.Create();
  70. internal int[] y = F.Create();
  71. internal int[] z = F.Create();
  72. internal int[] u = F.Create();
  73. internal int[] v = F.Create();
  74. }
  75. private class PointAffine
  76. {
  77. internal int[] x = F.Create();
  78. internal int[] y = F.Create();
  79. }
  80. private class PointExt
  81. {
  82. internal int[] x = F.Create();
  83. internal int[] y = F.Create();
  84. internal int[] z = F.Create();
  85. internal int[] t = F.Create();
  86. }
  87. private class PointPrecomp
  88. {
  89. internal int[] ypx_h = F.Create();
  90. internal int[] ymx_h = F.Create();
  91. internal int[] xyd = F.Create();
  92. }
  93. private static byte[] CalculateS(byte[] r, byte[] k, byte[] s)
  94. {
  95. uint[] t = new uint[ScalarUints * 2]; DecodeScalar(r, 0, t);
  96. uint[] u = new uint[ScalarUints]; DecodeScalar(k, 0, u);
  97. uint[] v = new uint[ScalarUints]; DecodeScalar(s, 0, v);
  98. Nat256.MulAddTo(u, v, t);
  99. byte[] result = new byte[ScalarBytes * 2];
  100. for (int i = 0; i < t.Length; ++i)
  101. {
  102. Encode32(t[i], result, i * 4);
  103. }
  104. return ReduceScalar(result);
  105. }
  106. private static bool CheckContextVar(byte[] ctx, byte phflag)
  107. {
  108. return ctx == null && phflag == 0x00
  109. || ctx != null && ctx.Length < 256;
  110. }
  111. private static int CheckPoint(int[] x, int[] y)
  112. {
  113. int[] t = F.Create();
  114. int[] u = F.Create();
  115. int[] v = F.Create();
  116. F.Sqr(x, u);
  117. F.Sqr(y, v);
  118. F.Mul(u, v, t);
  119. F.Sub(v, u, v);
  120. F.Mul(t, C_d, t);
  121. F.AddOne(t);
  122. F.Sub(t, v, t);
  123. F.Normalize(t);
  124. return F.IsZero(t);
  125. }
  126. private static int CheckPoint(int[] x, int[] y, int[] z)
  127. {
  128. int[] t = F.Create();
  129. int[] u = F.Create();
  130. int[] v = F.Create();
  131. int[] w = F.Create();
  132. F.Sqr(x, u);
  133. F.Sqr(y, v);
  134. F.Sqr(z, w);
  135. F.Mul(u, v, t);
  136. F.Sub(v, u, v);
  137. F.Mul(v, w, v);
  138. F.Sqr(w, w);
  139. F.Mul(t, C_d, t);
  140. F.Add(t, w, t);
  141. F.Sub(t, v, t);
  142. F.Normalize(t);
  143. return F.IsZero(t);
  144. }
  145. private static bool CheckPointVar(byte[] p)
  146. {
  147. uint[] t = new uint[CoordUints];
  148. Decode32(p, 0, t, 0, CoordUints);
  149. t[CoordUints - 1] &= 0x7FFFFFFFU;
  150. return !Nat256.Gte(t, P);
  151. }
  152. private static bool CheckScalarVar(byte[] s, uint[] n)
  153. {
  154. DecodeScalar(s, 0, n);
  155. return !Nat256.Gte(n, L);
  156. }
  157. private static byte[] Copy(byte[] buf, int off, int len)
  158. {
  159. byte[] result = new byte[len];
  160. Array.Copy(buf, off, result, 0, len);
  161. return result;
  162. }
  163. private static IDigest CreateDigest()
  164. {
  165. return new Sha512Digest();
  166. }
  167. public static IDigest CreatePrehash()
  168. {
  169. return CreateDigest();
  170. }
  171. private static uint Decode24(byte[] bs, int off)
  172. {
  173. uint n = bs[off];
  174. n |= (uint)bs[++off] << 8;
  175. n |= (uint)bs[++off] << 16;
  176. return n;
  177. }
  178. private static uint Decode32(byte[] bs, int off)
  179. {
  180. uint n = bs[off];
  181. n |= (uint)bs[++off] << 8;
  182. n |= (uint)bs[++off] << 16;
  183. n |= (uint)bs[++off] << 24;
  184. return n;
  185. }
  186. private static void Decode32(byte[] bs, int bsOff, uint[] n, int nOff, int nLen)
  187. {
  188. for (int i = 0; i < nLen; ++i)
  189. {
  190. n[nOff + i] = Decode32(bs, bsOff + i * 4);
  191. }
  192. }
  193. private static bool DecodePointVar(byte[] p, int pOff, bool negate, PointAffine r)
  194. {
  195. byte[] py = Copy(p, pOff, PointBytes);
  196. if (!CheckPointVar(py))
  197. return false;
  198. int x_0 = (py[PointBytes - 1] & 0x80) >> 7;
  199. py[PointBytes - 1] &= 0x7F;
  200. F.Decode(py, 0, r.y);
  201. int[] u = F.Create();
  202. int[] v = F.Create();
  203. F.Sqr(r.y, u);
  204. F.Mul(C_d, u, v);
  205. F.SubOne(u);
  206. F.AddOne(v);
  207. if (!F.SqrtRatioVar(u, v, r.x))
  208. return false;
  209. F.Normalize(r.x);
  210. if (x_0 == 1 && F.IsZeroVar(r.x))
  211. return false;
  212. if (negate ^ (x_0 != (r.x[0] & 1)))
  213. {
  214. F.Negate(r.x, r.x);
  215. }
  216. return true;
  217. }
  218. private static void DecodeScalar(byte[] k, int kOff, uint[] n)
  219. {
  220. Decode32(k, kOff, n, 0, ScalarUints);
  221. }
  222. private static void Dom2(IDigest d, byte phflag, byte[] ctx)
  223. {
  224. if (ctx != null)
  225. {
  226. int n = Dom2Prefix.Length;
  227. byte[] t = new byte[n + 2 + ctx.Length];
  228. Dom2Prefix.CopyTo(t, 0);
  229. t[n] = phflag;
  230. t[n + 1] = (byte)ctx.Length;
  231. ctx.CopyTo(t, n + 2);
  232. d.BlockUpdate(t, 0, t.Length);
  233. }
  234. }
  235. private static void Encode24(uint n, byte[] bs, int off)
  236. {
  237. bs[off] = (byte)(n);
  238. bs[++off] = (byte)(n >> 8);
  239. bs[++off] = (byte)(n >> 16);
  240. }
  241. private static void Encode32(uint n, byte[] bs, int off)
  242. {
  243. bs[off] = (byte)(n);
  244. bs[++off] = (byte)(n >> 8);
  245. bs[++off] = (byte)(n >> 16);
  246. bs[++off] = (byte)(n >> 24);
  247. }
  248. private static void Encode56(ulong n, byte[] bs, int off)
  249. {
  250. Encode32((uint)n, bs, off);
  251. Encode24((uint)(n >> 32), bs, off + 4);
  252. }
  253. private static int EncodePoint(PointAccum p, byte[] r, int rOff)
  254. {
  255. int[] x = F.Create();
  256. int[] y = F.Create();
  257. F.Inv(p.z, y);
  258. F.Mul(p.x, y, x);
  259. F.Mul(p.y, y, y);
  260. F.Normalize(x);
  261. F.Normalize(y);
  262. int result = CheckPoint(x, y);
  263. F.Encode(y, r, rOff);
  264. r[rOff + PointBytes - 1] |= (byte)((x[0] & 1) << 7);
  265. return result;
  266. }
  267. public static void GeneratePrivateKey(SecureRandom random, byte[] k)
  268. {
  269. random.NextBytes(k);
  270. }
  271. public static void GeneratePublicKey(byte[] sk, int skOff, byte[] pk, int pkOff)
  272. {
  273. IDigest d = CreateDigest();
  274. byte[] h = new byte[d.GetDigestSize()];
  275. d.BlockUpdate(sk, skOff, SecretKeySize);
  276. d.DoFinal(h, 0);
  277. byte[] s = new byte[ScalarBytes];
  278. PruneScalar(h, 0, s);
  279. ScalarMultBaseEncoded(s, pk, pkOff);
  280. }
  281. private static uint GetWindow4(uint[] x, int n)
  282. {
  283. int w = (int)((uint)n >> 3), b = (n & 7) << 2;
  284. return (x[w] >> b) & 15U;
  285. }
  286. private static sbyte[] GetWnafVar(uint[] n, int width)
  287. {
  288. Debug.Assert(n[ScalarUints - 1] <= L[ScalarUints - 1]);
  289. Debug.Assert(2 <= width && width <= 8);
  290. uint[] t = new uint[ScalarUints * 2];
  291. {
  292. uint c = 0;
  293. int tPos = t.Length, i = ScalarUints;
  294. while (--i >= 0)
  295. {
  296. uint next = n[i];
  297. t[--tPos] = (next >> 16) | (c << 16);
  298. t[--tPos] = c = next;
  299. }
  300. }
  301. sbyte[] ws = new sbyte[253];
  302. int lead = 32 - width;
  303. uint carry = 0U;
  304. int j = 0;
  305. for (int i = 0; i < t.Length; ++i, j -= 16)
  306. {
  307. uint word = t[i];
  308. while (j < 16)
  309. {
  310. uint word16 = word >> j;
  311. uint bit = word16 & 1U;
  312. if (bit == carry)
  313. {
  314. ++j;
  315. continue;
  316. }
  317. uint digit = (word16 | 1U) << lead;
  318. carry = digit >> 31;
  319. ws[(i << 4) + j] = (sbyte)((int)digit >> lead);
  320. j += width;
  321. }
  322. }
  323. Debug.Assert(carry == 0);
  324. return ws;
  325. }
  326. private static void ImplSign(IDigest d, byte[] h, byte[] s, byte[] pk, int pkOff, byte[] ctx, byte phflag,
  327. byte[] m, int mOff, int mLen, byte[] sig, int sigOff)
  328. {
  329. Dom2(d, phflag, ctx);
  330. d.BlockUpdate(h, ScalarBytes, ScalarBytes);
  331. d.BlockUpdate(m, mOff, mLen);
  332. d.DoFinal(h, 0);
  333. byte[] r = ReduceScalar(h);
  334. byte[] R = new byte[PointBytes];
  335. ScalarMultBaseEncoded(r, R, 0);
  336. Dom2(d, phflag, ctx);
  337. d.BlockUpdate(R, 0, PointBytes);
  338. d.BlockUpdate(pk, pkOff, PointBytes);
  339. d.BlockUpdate(m, mOff, mLen);
  340. d.DoFinal(h, 0);
  341. byte[] k = ReduceScalar(h);
  342. byte[] S = CalculateS(r, k, s);
  343. Array.Copy(R, 0, sig, sigOff, PointBytes);
  344. Array.Copy(S, 0, sig, sigOff + PointBytes, ScalarBytes);
  345. }
  346. private static void ImplSign(byte[] sk, int skOff, byte[] ctx, byte phflag, byte[] m, int mOff, int mLen,
  347. byte[] sig, int sigOff)
  348. {
  349. if (!CheckContextVar(ctx, phflag))
  350. throw new ArgumentException("ctx");
  351. IDigest d = CreateDigest();
  352. byte[] h = new byte[d.GetDigestSize()];
  353. d.BlockUpdate(sk, skOff, SecretKeySize);
  354. d.DoFinal(h, 0);
  355. byte[] s = new byte[ScalarBytes];
  356. PruneScalar(h, 0, s);
  357. byte[] pk = new byte[PointBytes];
  358. ScalarMultBaseEncoded(s, pk, 0);
  359. ImplSign(d, h, s, pk, 0, ctx, phflag, m, mOff, mLen, sig, sigOff);
  360. }
  361. private static void ImplSign(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] ctx, byte phflag, byte[] m,
  362. int mOff, int mLen, byte[] sig, int sigOff)
  363. {
  364. if (!CheckContextVar(ctx, phflag))
  365. throw new ArgumentException("ctx");
  366. IDigest d = CreateDigest();
  367. byte[] h = new byte[d.GetDigestSize()];
  368. d.BlockUpdate(sk, skOff, SecretKeySize);
  369. d.DoFinal(h, 0);
  370. byte[] s = new byte[ScalarBytes];
  371. PruneScalar(h, 0, s);
  372. ImplSign(d, h, s, pk, pkOff, ctx, phflag, m, mOff, mLen, sig, sigOff);
  373. }
  374. private static bool ImplVerify(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, byte phflag, byte[] m,
  375. int mOff, int mLen)
  376. {
  377. if (!CheckContextVar(ctx, phflag))
  378. throw new ArgumentException("ctx");
  379. byte[] R = Copy(sig, sigOff, PointBytes);
  380. byte[] S = Copy(sig, sigOff + PointBytes, ScalarBytes);
  381. if (!CheckPointVar(R))
  382. return false;
  383. uint[] nS = new uint[ScalarUints];
  384. if (!CheckScalarVar(S, nS))
  385. return false;
  386. PointAffine pA = new PointAffine();
  387. if (!DecodePointVar(pk, pkOff, true, pA))
  388. return false;
  389. IDigest d = CreateDigest();
  390. byte[] h = new byte[d.GetDigestSize()];
  391. Dom2(d, phflag, ctx);
  392. d.BlockUpdate(R, 0, PointBytes);
  393. d.BlockUpdate(pk, pkOff, PointBytes);
  394. d.BlockUpdate(m, mOff, mLen);
  395. d.DoFinal(h, 0);
  396. byte[] k = ReduceScalar(h);
  397. uint[] nA = new uint[ScalarUints];
  398. DecodeScalar(k, 0, nA);
  399. PointAccum pR = new PointAccum();
  400. ScalarMultStrausVar(nS, nA, pA, pR);
  401. byte[] check = new byte[PointBytes];
  402. return 0 != EncodePoint(pR, check, 0) && Arrays.AreEqual(check, R);
  403. }
  404. private static bool IsNeutralElementVar(int[] x, int[] y)
  405. {
  406. return F.IsZeroVar(x) && F.IsOneVar(y);
  407. }
  408. private static bool IsNeutralElementVar(int[] x, int[] y, int[] z)
  409. {
  410. return F.IsZeroVar(x) && F.AreEqualVar(y, z);
  411. }
  412. private static void PointAdd(PointExt p, PointAccum r)
  413. {
  414. int[] a = F.Create();
  415. int[] b = F.Create();
  416. int[] c = F.Create();
  417. int[] d = F.Create();
  418. int[] e = r.u;
  419. int[] f = F.Create();
  420. int[] g = F.Create();
  421. int[] h = r.v;
  422. F.Apm(r.y, r.x, b, a);
  423. F.Apm(p.y, p.x, d, c);
  424. F.Mul(a, c, a);
  425. F.Mul(b, d, b);
  426. F.Mul(r.u, r.v, c);
  427. F.Mul(c, p.t, c);
  428. F.Mul(c, C_d2, c);
  429. F.Mul(r.z, p.z, d);
  430. F.Add(d, d, d);
  431. F.Apm(b, a, h, e);
  432. F.Apm(d, c, g, f);
  433. F.Carry(g);
  434. F.Mul(e, f, r.x);
  435. F.Mul(g, h, r.y);
  436. F.Mul(f, g, r.z);
  437. }
  438. private static void PointAdd(PointExt p, PointExt r)
  439. {
  440. int[] a = F.Create();
  441. int[] b = F.Create();
  442. int[] c = F.Create();
  443. int[] d = F.Create();
  444. int[] e = F.Create();
  445. int[] f = F.Create();
  446. int[] g = F.Create();
  447. int[] h = F.Create();
  448. F.Apm(p.y, p.x, b, a);
  449. F.Apm(r.y, r.x, d, c);
  450. F.Mul(a, c, a);
  451. F.Mul(b, d, b);
  452. F.Mul(p.t, r.t, c);
  453. F.Mul(c, C_d2, c);
  454. F.Mul(p.z, r.z, d);
  455. F.Add(d, d, d);
  456. F.Apm(b, a, h, e);
  457. F.Apm(d, c, g, f);
  458. F.Carry(g);
  459. F.Mul(e, f, r.x);
  460. F.Mul(g, h, r.y);
  461. F.Mul(f, g, r.z);
  462. F.Mul(e, h, r.t);
  463. }
  464. private static void PointAddVar(bool negate, PointExt p, PointAccum r)
  465. {
  466. int[] a = F.Create();
  467. int[] b = F.Create();
  468. int[] c = F.Create();
  469. int[] d = F.Create();
  470. int[] e = r.u;
  471. int[] f = F.Create();
  472. int[] g = F.Create();
  473. int[] h = r.v;
  474. int[] nc, nd, nf, ng;
  475. if (negate)
  476. {
  477. nc = d; nd = c; nf = g; ng = f;
  478. }
  479. else
  480. {
  481. nc = c; nd = d; nf = f; ng = g;
  482. }
  483. F.Apm(r.y, r.x, b, a);
  484. F.Apm(p.y, p.x, nd, nc);
  485. F.Mul(a, c, a);
  486. F.Mul(b, d, b);
  487. F.Mul(r.u, r.v, c);
  488. F.Mul(c, p.t, c);
  489. F.Mul(c, C_d2, c);
  490. F.Mul(r.z, p.z, d);
  491. F.Add(d, d, d);
  492. F.Apm(b, a, h, e);
  493. F.Apm(d, c, ng, nf);
  494. F.Carry(ng);
  495. F.Mul(e, f, r.x);
  496. F.Mul(g, h, r.y);
  497. F.Mul(f, g, r.z);
  498. }
  499. private static void PointAddVar(bool negate, PointExt p, PointExt q, PointExt r)
  500. {
  501. int[] a = F.Create();
  502. int[] b = F.Create();
  503. int[] c = F.Create();
  504. int[] d = F.Create();
  505. int[] e = F.Create();
  506. int[] f = F.Create();
  507. int[] g = F.Create();
  508. int[] h = F.Create();
  509. int[] nc, nd, nf, ng;
  510. if (negate)
  511. {
  512. nc = d; nd = c; nf = g; ng = f;
  513. }
  514. else
  515. {
  516. nc = c; nd = d; nf = f; ng = g;
  517. }
  518. F.Apm(p.y, p.x, b, a);
  519. F.Apm(q.y, q.x, nd, nc);
  520. F.Mul(a, c, a);
  521. F.Mul(b, d, b);
  522. F.Mul(p.t, q.t, c);
  523. F.Mul(c, C_d2, c);
  524. F.Mul(p.z, q.z, d);
  525. F.Add(d, d, d);
  526. F.Apm(b, a, h, e);
  527. F.Apm(d, c, ng, nf);
  528. F.Carry(ng);
  529. F.Mul(e, f, r.x);
  530. F.Mul(g, h, r.y);
  531. F.Mul(f, g, r.z);
  532. F.Mul(e, h, r.t);
  533. }
  534. private static void PointAddPrecomp(PointPrecomp p, PointAccum r)
  535. {
  536. int[] a = F.Create();
  537. int[] b = F.Create();
  538. int[] c = F.Create();
  539. int[] e = r.u;
  540. int[] f = F.Create();
  541. int[] g = F.Create();
  542. int[] h = r.v;
  543. F.Apm(r.y, r.x, b, a);
  544. F.Mul(a, p.ymx_h, a);
  545. F.Mul(b, p.ypx_h, b);
  546. F.Mul(r.u, r.v, c);
  547. F.Mul(c, p.xyd, c);
  548. F.Apm(b, a, h, e);
  549. F.Apm(r.z, c, g, f);
  550. F.Carry(g);
  551. F.Mul(e, f, r.x);
  552. F.Mul(g, h, r.y);
  553. F.Mul(f, g, r.z);
  554. }
  555. private static PointExt PointCopy(PointAccum p)
  556. {
  557. PointExt r = new PointExt();
  558. F.Copy(p.x, 0, r.x, 0);
  559. F.Copy(p.y, 0, r.y, 0);
  560. F.Copy(p.z, 0, r.z, 0);
  561. F.Mul(p.u, p.v, r.t);
  562. return r;
  563. }
  564. private static PointExt PointCopy(PointAffine p)
  565. {
  566. PointExt r = new PointExt();
  567. F.Copy(p.x, 0, r.x, 0);
  568. F.Copy(p.y, 0, r.y, 0);
  569. PointExtendXY(r);
  570. return r;
  571. }
  572. private static PointExt PointCopy(PointExt p)
  573. {
  574. PointExt r = new PointExt();
  575. PointCopy(p, r);
  576. return r;
  577. }
  578. private static void PointCopy(PointAffine p, PointAccum r)
  579. {
  580. F.Copy(p.x, 0, r.x, 0);
  581. F.Copy(p.y, 0, r.y, 0);
  582. PointExtendXY(r);
  583. }
  584. private static void PointCopy(PointExt p, PointExt r)
  585. {
  586. F.Copy(p.x, 0, r.x, 0);
  587. F.Copy(p.y, 0, r.y, 0);
  588. F.Copy(p.z, 0, r.z, 0);
  589. F.Copy(p.t, 0, r.t, 0);
  590. }
  591. private static void PointDouble(PointAccum r)
  592. {
  593. int[] a = F.Create();
  594. int[] b = F.Create();
  595. int[] c = F.Create();
  596. int[] e = r.u;
  597. int[] f = F.Create();
  598. int[] g = F.Create();
  599. int[] h = r.v;
  600. F.Sqr(r.x, a);
  601. F.Sqr(r.y, b);
  602. F.Sqr(r.z, c);
  603. F.Add(c, c, c);
  604. F.Apm(a, b, h, g);
  605. F.Add(r.x, r.y, e);
  606. F.Sqr(e, e);
  607. F.Sub(h, e, e);
  608. F.Add(c, g, f);
  609. F.Carry(f);
  610. F.Mul(e, f, r.x);
  611. F.Mul(g, h, r.y);
  612. F.Mul(f, g, r.z);
  613. }
  614. private static void PointExtendXY(PointAccum p)
  615. {
  616. F.One(p.z);
  617. F.Copy(p.x, 0, p.u, 0);
  618. F.Copy(p.y, 0, p.v, 0);
  619. }
  620. private static void PointExtendXY(PointExt p)
  621. {
  622. F.One(p.z);
  623. F.Mul(p.x, p.y, p.t);
  624. }
  625. private static void PointLookup(int block, int index, PointPrecomp p)
  626. {
  627. Debug.Assert(0 <= block && block < PrecompBlocks);
  628. Debug.Assert(0 <= index && index < PrecompPoints);
  629. int off = block * PrecompPoints * 3 * F.Size;
  630. for (int i = 0; i < PrecompPoints; ++i)
  631. {
  632. int cond = ((i ^ index) - 1) >> 31;
  633. F.CMov(cond, precompBase, off, p.ypx_h, 0); off += F.Size;
  634. F.CMov(cond, precompBase, off, p.ymx_h, 0); off += F.Size;
  635. F.CMov(cond, precompBase, off, p.xyd, 0); off += F.Size;
  636. }
  637. }
  638. private static void PointLookup(uint[] x, int n, int[] table, PointExt r)
  639. {
  640. // TODO This method is currently hardcoded to 4-bit windows and 8 precomputed points
  641. uint w = GetWindow4(x, n);
  642. int sign = (int)(w >> (4 - 1)) ^ 1;
  643. int abs = ((int)w ^ -sign) & 7;
  644. Debug.Assert(sign == 0 || sign == 1);
  645. Debug.Assert(0 <= abs && abs < 8);
  646. for (int i = 0, off = 0; i < 8; ++i)
  647. {
  648. int cond = ((i ^ abs) - 1) >> 31;
  649. F.CMov(cond, table, off, r.x, 0); off += F.Size;
  650. F.CMov(cond, table, off, r.y, 0); off += F.Size;
  651. F.CMov(cond, table, off, r.z, 0); off += F.Size;
  652. F.CMov(cond, table, off, r.t, 0); off += F.Size;
  653. }
  654. F.CNegate(sign, r.x);
  655. F.CNegate(sign, r.t);
  656. }
  657. private static void PointLookup(int[] table, int index, PointExt r)
  658. {
  659. int off = F.Size * 4 * index;
  660. F.Copy(table, off, r.x, 0); off += F.Size;
  661. F.Copy(table, off, r.y, 0); off += F.Size;
  662. F.Copy(table, off, r.z, 0); off += F.Size;
  663. F.Copy(table, off, r.t, 0);
  664. }
  665. private static int[] PointPrecompute(PointAffine p, int count)
  666. {
  667. Debug.Assert(count > 0);
  668. PointExt q = PointCopy(p);
  669. PointExt d = PointCopy(q);
  670. PointAdd(q, d);
  671. int[] table = F.CreateTable(count * 4);
  672. int off = 0;
  673. int i = 0;
  674. for (;;)
  675. {
  676. F.Copy(q.x, 0, table, off); off += F.Size;
  677. F.Copy(q.y, 0, table, off); off += F.Size;
  678. F.Copy(q.z, 0, table, off); off += F.Size;
  679. F.Copy(q.t, 0, table, off); off += F.Size;
  680. if (++i == count)
  681. break;
  682. PointAdd(d, q);
  683. }
  684. return table;
  685. }
  686. private static PointExt[] PointPrecomputeVar(PointExt p, int count)
  687. {
  688. Debug.Assert(count > 0);
  689. PointExt d = new PointExt();
  690. PointAddVar(false, p, p, d);
  691. PointExt[] table = new PointExt[count];
  692. table[0] = PointCopy(p);
  693. for (int i = 1; i < count; ++i)
  694. {
  695. PointAddVar(false, table[i - 1], d, table[i] = new PointExt());
  696. }
  697. return table;
  698. }
  699. private static void PointSetNeutral(PointAccum p)
  700. {
  701. F.Zero(p.x);
  702. F.One(p.y);
  703. F.One(p.z);
  704. F.Zero(p.u);
  705. F.One(p.v);
  706. }
  707. private static void PointSetNeutral(PointExt p)
  708. {
  709. F.Zero(p.x);
  710. F.One(p.y);
  711. F.One(p.z);
  712. F.Zero(p.t);
  713. }
  714. public static void Precompute()
  715. {
  716. lock (precompLock)
  717. {
  718. if (precompBase != null)
  719. return;
  720. // Precomputed table for the base point in verification ladder
  721. {
  722. PointExt b = new PointExt();
  723. F.Copy(B_x, 0, b.x, 0);
  724. F.Copy(B_y, 0, b.y, 0);
  725. PointExtendXY(b);
  726. precompBaseTable = PointPrecomputeVar(b, 1 << (WnafWidthBase - 2));
  727. }
  728. PointAccum p = new PointAccum();
  729. F.Copy(B_x, 0, p.x, 0);
  730. F.Copy(B_y, 0, p.y, 0);
  731. PointExtendXY(p);
  732. precompBase = F.CreateTable(PrecompBlocks * PrecompPoints * 3);
  733. int off = 0;
  734. for (int b = 0; b < PrecompBlocks; ++b)
  735. {
  736. PointExt[] ds = new PointExt[PrecompTeeth];
  737. PointExt sum = new PointExt();
  738. PointSetNeutral(sum);
  739. for (int t = 0; t < PrecompTeeth; ++t)
  740. {
  741. PointExt q = PointCopy(p);
  742. PointAddVar(true, sum, q, sum);
  743. PointDouble(p);
  744. ds[t] = PointCopy(p);
  745. if (b + t != PrecompBlocks + PrecompTeeth - 2)
  746. {
  747. for (int s = 1; s < PrecompSpacing; ++s)
  748. {
  749. PointDouble(p);
  750. }
  751. }
  752. }
  753. PointExt[] points = new PointExt[PrecompPoints];
  754. int k = 0;
  755. points[k++] = sum;
  756. for (int t = 0; t < (PrecompTeeth - 1); ++t)
  757. {
  758. int size = 1 << t;
  759. for (int j = 0; j < size; ++j, ++k)
  760. {
  761. PointAddVar(false, points[k - size], ds[t], points[k] = new PointExt());
  762. }
  763. }
  764. Debug.Assert(k == PrecompPoints);
  765. int[] cs = F.CreateTable(PrecompPoints);
  766. // TODO[ed25519] A single batch inversion across all blocks?
  767. {
  768. int[] u = F.Create();
  769. F.Copy(points[0].z, 0, u, 0);
  770. F.Copy(u, 0, cs, 0);
  771. int i = 0;
  772. while (++i < PrecompPoints)
  773. {
  774. F.Mul(u, points[i].z, u);
  775. F.Copy(u, 0, cs, i * F.Size);
  776. }
  777. F.Add(u, u, u);
  778. F.InvVar(u, u);
  779. --i;
  780. int[] t = F.Create();
  781. while (i > 0)
  782. {
  783. int j = i--;
  784. F.Copy(cs, i * F.Size, t, 0);
  785. F.Mul(t, u, t);
  786. F.Copy(t, 0, cs, j * F.Size);
  787. F.Mul(u, points[j].z, u);
  788. }
  789. F.Copy(u, 0, cs, 0);
  790. }
  791. for (int i = 0; i < PrecompPoints; ++i)
  792. {
  793. PointExt q = points[i];
  794. int[] x = F.Create();
  795. int[] y = F.Create();
  796. //F.Add(q.z, q.z, x);
  797. //F.InvVar(x, y);
  798. F.Copy(cs, i * F.Size, y, 0);
  799. F.Mul(q.x, y, x);
  800. F.Mul(q.y, y, y);
  801. PointPrecomp r = new PointPrecomp();
  802. F.Apm(y, x, r.ypx_h, r.ymx_h);
  803. F.Mul(x, y, r.xyd);
  804. F.Mul(r.xyd, C_d4, r.xyd);
  805. F.Normalize(r.ypx_h);
  806. F.Normalize(r.ymx_h);
  807. //F.Normalize(r.xyd);
  808. F.Copy(r.ypx_h, 0, precompBase, off); off += F.Size;
  809. F.Copy(r.ymx_h, 0, precompBase, off); off += F.Size;
  810. F.Copy(r.xyd, 0, precompBase, off); off += F.Size;
  811. }
  812. }
  813. Debug.Assert(off == precompBase.Length);
  814. }
  815. }
  816. private static void PruneScalar(byte[] n, int nOff, byte[] r)
  817. {
  818. Array.Copy(n, nOff, r, 0, ScalarBytes);
  819. r[0] &= 0xF8;
  820. r[ScalarBytes - 1] &= 0x7F;
  821. r[ScalarBytes - 1] |= 0x40;
  822. }
  823. private static byte[] ReduceScalar(byte[] n)
  824. {
  825. long x00 = Decode32(n, 0) & M32L; // x00:32/--
  826. long x01 = (Decode24(n, 4) << 4) & M32L; // x01:28/--
  827. long x02 = Decode32(n, 7) & M32L; // x02:32/--
  828. long x03 = (Decode24(n, 11) << 4) & M32L; // x03:28/--
  829. long x04 = Decode32(n, 14) & M32L; // x04:32/--
  830. long x05 = (Decode24(n, 18) << 4) & M32L; // x05:28/--
  831. long x06 = Decode32(n, 21) & M32L; // x06:32/--
  832. long x07 = (Decode24(n, 25) << 4) & M32L; // x07:28/--
  833. long x08 = Decode32(n, 28) & M32L; // x08:32/--
  834. long x09 = (Decode24(n, 32) << 4) & M32L; // x09:28/--
  835. long x10 = Decode32(n, 35) & M32L; // x10:32/--
  836. long x11 = (Decode24(n, 39) << 4) & M32L; // x11:28/--
  837. long x12 = Decode32(n, 42) & M32L; // x12:32/--
  838. long x13 = (Decode24(n, 46) << 4) & M32L; // x13:28/--
  839. long x14 = Decode32(n, 49) & M32L; // x14:32/--
  840. long x15 = (Decode24(n, 53) << 4) & M32L; // x15:28/--
  841. long x16 = Decode32(n, 56) & M32L; // x16:32/--
  842. long x17 = (Decode24(n, 60) << 4) & M32L; // x17:28/--
  843. long x18 = n[63] & M08L; // x18:08/--
  844. long t;
  845. //x18 += (x17 >> 28); x17 &= M28L;
  846. x09 -= x18 * L0; // x09:34/28
  847. x10 -= x18 * L1; // x10:33/30
  848. x11 -= x18 * L2; // x11:35/28
  849. x12 -= x18 * L3; // x12:32/31
  850. x13 -= x18 * L4; // x13:28/21
  851. x17 += (x16 >> 28); x16 &= M28L; // x17:28/--, x16:28/--
  852. x08 -= x17 * L0; // x08:54/32
  853. x09 -= x17 * L1; // x09:52/51
  854. x10 -= x17 * L2; // x10:55/34
  855. x11 -= x17 * L3; // x11:51/36
  856. x12 -= x17 * L4; // x12:41/--
  857. //x16 += (x15 >> 28); x15 &= M28L;
  858. x07 -= x16 * L0; // x07:54/28
  859. x08 -= x16 * L1; // x08:54/53
  860. x09 -= x16 * L2; // x09:55/53
  861. x10 -= x16 * L3; // x10:55/52
  862. x11 -= x16 * L4; // x11:51/41
  863. x15 += (x14 >> 28); x14 &= M28L; // x15:28/--, x14:28/--
  864. x06 -= x15 * L0; // x06:54/32
  865. x07 -= x15 * L1; // x07:54/53
  866. x08 -= x15 * L2; // x08:56/--
  867. x09 -= x15 * L3; // x09:55/54
  868. x10 -= x15 * L4; // x10:55/53
  869. //x14 += (x13 >> 28); x13 &= M28L;
  870. x05 -= x14 * L0; // x05:54/28
  871. x06 -= x14 * L1; // x06:54/53
  872. x07 -= x14 * L2; // x07:56/--
  873. x08 -= x14 * L3; // x08:56/51
  874. x09 -= x14 * L4; // x09:56/--
  875. x13 += (x12 >> 28); x12 &= M28L; // x13:28/22, x12:28/--
  876. x04 -= x13 * L0; // x04:54/49
  877. x05 -= x13 * L1; // x05:54/53
  878. x06 -= x13 * L2; // x06:56/--
  879. x07 -= x13 * L3; // x07:56/52
  880. x08 -= x13 * L4; // x08:56/52
  881. x12 += (x11 >> 28); x11 &= M28L; // x12:28/24, x11:28/--
  882. x03 -= x12 * L0; // x03:54/49
  883. x04 -= x12 * L1; // x04:54/51
  884. x05 -= x12 * L2; // x05:56/--
  885. x06 -= x12 * L3; // x06:56/52
  886. x07 -= x12 * L4; // x07:56/53
  887. x11 += (x10 >> 28); x10 &= M28L; // x11:29/--, x10:28/--
  888. x02 -= x11 * L0; // x02:55/32
  889. x03 -= x11 * L1; // x03:55/--
  890. x04 -= x11 * L2; // x04:56/55
  891. x05 -= x11 * L3; // x05:56/52
  892. x06 -= x11 * L4; // x06:56/53
  893. x10 += (x09 >> 28); x09 &= M28L; // x10:29/--, x09:28/--
  894. x01 -= x10 * L0; // x01:55/28
  895. x02 -= x10 * L1; // x02:55/54
  896. x03 -= x10 * L2; // x03:56/55
  897. x04 -= x10 * L3; // x04:57/--
  898. x05 -= x10 * L4; // x05:56/53
  899. x08 += (x07 >> 28); x07 &= M28L; // x08:56/53, x07:28/--
  900. x09 += (x08 >> 28); x08 &= M28L; // x09:29/25, x08:28/--
  901. t = (x08 >> 27) & 1L;
  902. x09 += t; // x09:29/26
  903. x00 -= x09 * L0; // x00:55/53
  904. x01 -= x09 * L1; // x01:55/54
  905. x02 -= x09 * L2; // x02:57/--
  906. x03 -= x09 * L3; // x03:57/--
  907. x04 -= x09 * L4; // x04:57/42
  908. x01 += (x00 >> 28); x00 &= M28L;
  909. x02 += (x01 >> 28); x01 &= M28L;
  910. x03 += (x02 >> 28); x02 &= M28L;
  911. x04 += (x03 >> 28); x03 &= M28L;
  912. x05 += (x04 >> 28); x04 &= M28L;
  913. x06 += (x05 >> 28); x05 &= M28L;
  914. x07 += (x06 >> 28); x06 &= M28L;
  915. x08 += (x07 >> 28); x07 &= M28L;
  916. x09 = (x08 >> 28); x08 &= M28L;
  917. x09 -= t;
  918. Debug.Assert(x09 == 0L || x09 == -1L);
  919. x00 += x09 & L0;
  920. x01 += x09 & L1;
  921. x02 += x09 & L2;
  922. x03 += x09 & L3;
  923. x04 += x09 & L4;
  924. x01 += (x00 >> 28); x00 &= M28L;
  925. x02 += (x01 >> 28); x01 &= M28L;
  926. x03 += (x02 >> 28); x02 &= M28L;
  927. x04 += (x03 >> 28); x03 &= M28L;
  928. x05 += (x04 >> 28); x04 &= M28L;
  929. x06 += (x05 >> 28); x05 &= M28L;
  930. x07 += (x06 >> 28); x06 &= M28L;
  931. x08 += (x07 >> 28); x07 &= M28L;
  932. byte[] r = new byte[ScalarBytes];
  933. Encode56((ulong)(x00 | (x01 << 28)), r, 0);
  934. Encode56((ulong)(x02 | (x03 << 28)), r, 7);
  935. Encode56((ulong)(x04 | (x05 << 28)), r, 14);
  936. Encode56((ulong)(x06 | (x07 << 28)), r, 21);
  937. Encode32((uint)x08, r, 28);
  938. return r;
  939. }
  940. private static void ScalarMult(byte[] k, PointAffine p, PointAccum r)
  941. {
  942. uint[] n = new uint[ScalarUints];
  943. DecodeScalar(k, 0, n);
  944. Debug.Assert(0U == (n[0] & 7));
  945. Debug.Assert(1U == n[ScalarUints - 1] >> 30);
  946. Nat.ShiftDownBits(ScalarUints, n, 3, 1U);
  947. // Recode the scalar into signed-digit form
  948. {
  949. uint c1 = Nat.CAdd(ScalarUints, ~(int)n[0] & 1, n, L, n); Debug.Assert(c1 == 0U);
  950. uint c2 = Nat.ShiftDownBit(ScalarUints, n, 0U); Debug.Assert(c2 == (1U << 31));
  951. }
  952. Debug.Assert(1U == n[ScalarUints - 1] >> 28);
  953. int[] table = PointPrecompute(p, 8);
  954. PointExt q = new PointExt();
  955. // Replace first 4 doublings (2^4 * P) with 1 addition (P + 15 * P)
  956. PointCopy(p, r);
  957. PointLookup(table, 7, q);
  958. PointAdd(q, r);
  959. int w = 62;
  960. for (;;)
  961. {
  962. PointLookup(n, w, table, q);
  963. PointAdd(q, r);
  964. PointDouble(r);
  965. PointDouble(r);
  966. PointDouble(r);
  967. if (--w < 0)
  968. break;
  969. PointDouble(r);
  970. }
  971. }
  972. private static void ScalarMultBase(byte[] k, PointAccum r)
  973. {
  974. Precompute();
  975. uint[] n = new uint[ScalarUints];
  976. DecodeScalar(k, 0, n);
  977. // Recode the scalar into signed-digit form, then group comb bits in each block
  978. {
  979. uint c1 = Nat.CAdd(ScalarUints, ~(int)n[0] & 1, n, L, n); Debug.Assert(c1 == 0U);
  980. uint c2 = Nat.ShiftDownBit(ScalarUints, n, 1U); Debug.Assert(c2 == (1U << 31));
  981. for (int i = 0; i < ScalarUints; ++i)
  982. {
  983. n[i] = Interleave.Shuffle2(n[i]);
  984. }
  985. }
  986. PointPrecomp p = new PointPrecomp();
  987. PointSetNeutral(r);
  988. int cOff = (PrecompSpacing - 1) * PrecompTeeth;
  989. for (;;)
  990. {
  991. for (int b = 0; b < PrecompBlocks; ++b)
  992. {
  993. uint w = n[b] >> cOff;
  994. int sign = (int)(w >> (PrecompTeeth - 1)) & 1;
  995. int abs = ((int)w ^ -sign) & PrecompMask;
  996. Debug.Assert(sign == 0 || sign == 1);
  997. Debug.Assert(0 <= abs && abs < PrecompPoints);
  998. PointLookup(b, abs, p);
  999. F.CSwap(sign, p.ypx_h, p.ymx_h);
  1000. F.CNegate(sign, p.xyd);
  1001. PointAddPrecomp(p, r);
  1002. }
  1003. if ((cOff -= PrecompTeeth) < 0)
  1004. break;
  1005. PointDouble(r);
  1006. }
  1007. }
  1008. private static void ScalarMultBaseEncoded(byte[] k, byte[] r, int rOff)
  1009. {
  1010. PointAccum p = new PointAccum();
  1011. ScalarMultBase(k, p);
  1012. if (0 == EncodePoint(p, r, rOff))
  1013. throw new InvalidOperationException();
  1014. }
  1015. internal static void ScalarMultBaseYZ(byte[] k, int kOff, int[] y, int[] z)
  1016. {
  1017. byte[] n = new byte[ScalarBytes];
  1018. PruneScalar(k, kOff, n);
  1019. PointAccum p = new PointAccum();
  1020. ScalarMultBase(n, p);
  1021. if (0 == CheckPoint(p.x, p.y, p.z))
  1022. throw new InvalidOperationException();
  1023. F.Copy(p.y, 0, y, 0);
  1024. F.Copy(p.z, 0, z, 0);
  1025. }
  1026. private static void ScalarMultOrderVar(PointAffine p, PointAccum r)
  1027. {
  1028. int width = 5;
  1029. sbyte[] ws_p = GetWnafVar(L, width);
  1030. PointExt[] tp = PointPrecomputeVar(PointCopy(p), 1 << (width - 2));
  1031. PointSetNeutral(r);
  1032. for (int bit = 252; ;)
  1033. {
  1034. int wp = ws_p[bit];
  1035. if (wp != 0)
  1036. {
  1037. int sign = wp >> 31;
  1038. int index = (wp ^ sign) >> 1;
  1039. PointAddVar((sign != 0), tp[index], r);
  1040. }
  1041. if (--bit < 0)
  1042. break;
  1043. PointDouble(r);
  1044. }
  1045. }
  1046. private static void ScalarMultStrausVar(uint[] nb, uint[] np, PointAffine p, PointAccum r)
  1047. {
  1048. Precompute();
  1049. int width = 5;
  1050. sbyte[] ws_b = GetWnafVar(nb, WnafWidthBase);
  1051. sbyte[] ws_p = GetWnafVar(np, width);
  1052. PointExt[] tp = PointPrecomputeVar(PointCopy(p), 1 << (width - 2));
  1053. PointSetNeutral(r);
  1054. for (int bit = 252;;)
  1055. {
  1056. int wb = ws_b[bit];
  1057. if (wb != 0)
  1058. {
  1059. int sign = wb >> 31;
  1060. int index = (wb ^ sign) >> 1;
  1061. PointAddVar((sign != 0), precompBaseTable[index], r);
  1062. }
  1063. int wp = ws_p[bit];
  1064. if (wp != 0)
  1065. {
  1066. int sign = wp >> 31;
  1067. int index = (wp ^ sign) >> 1;
  1068. PointAddVar((sign != 0), tp[index], r);
  1069. }
  1070. if (--bit < 0)
  1071. break;
  1072. PointDouble(r);
  1073. }
  1074. }
  1075. public static void Sign(byte[] sk, int skOff, byte[] m, int mOff, int mLen, byte[] sig, int sigOff)
  1076. {
  1077. byte[] ctx = null;
  1078. byte phflag = 0x00;
  1079. ImplSign(sk, skOff, ctx, phflag, m, mOff, mLen, sig, sigOff);
  1080. }
  1081. public static void Sign(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] m, int mOff, int mLen, byte[] sig, int sigOff)
  1082. {
  1083. byte[] ctx = null;
  1084. byte phflag = 0x00;
  1085. ImplSign(sk, skOff, pk, pkOff, ctx, phflag, m, mOff, mLen, sig, sigOff);
  1086. }
  1087. public static void Sign(byte[] sk, int skOff, byte[] ctx, byte[] m, int mOff, int mLen, byte[] sig, int sigOff)
  1088. {
  1089. byte phflag = 0x00;
  1090. ImplSign(sk, skOff, ctx, phflag, m, mOff, mLen, sig, sigOff);
  1091. }
  1092. public static void Sign(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] ctx, byte[] m, int mOff, int mLen, byte[] sig, int sigOff)
  1093. {
  1094. byte phflag = 0x00;
  1095. ImplSign(sk, skOff, pk, pkOff, ctx, phflag, m, mOff, mLen, sig, sigOff);
  1096. }
  1097. public static void SignPrehash(byte[] sk, int skOff, byte[] ctx, byte[] ph, int phOff, byte[] sig, int sigOff)
  1098. {
  1099. byte phflag = 0x01;
  1100. ImplSign(sk, skOff, ctx, phflag, ph, phOff, PrehashSize, sig, sigOff);
  1101. }
  1102. public static void SignPrehash(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] ctx, byte[] ph, int phOff, byte[] sig, int sigOff)
  1103. {
  1104. byte phflag = 0x01;
  1105. ImplSign(sk, skOff, pk, pkOff, ctx, phflag, ph, phOff, PrehashSize, sig, sigOff);
  1106. }
  1107. public static void SignPrehash(byte[] sk, int skOff, byte[] ctx, IDigest ph, byte[] sig, int sigOff)
  1108. {
  1109. byte[] m = new byte[PrehashSize];
  1110. if (PrehashSize != ph.DoFinal(m, 0))
  1111. throw new ArgumentException("ph");
  1112. byte phflag = 0x01;
  1113. ImplSign(sk, skOff, ctx, phflag, m, 0, m.Length, sig, sigOff);
  1114. }
  1115. public static void SignPrehash(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] ctx, IDigest ph, byte[] sig, int sigOff)
  1116. {
  1117. byte[] m = new byte[PrehashSize];
  1118. if (PrehashSize != ph.DoFinal(m, 0))
  1119. throw new ArgumentException("ph");
  1120. byte phflag = 0x01;
  1121. ImplSign(sk, skOff, pk, pkOff, ctx, phflag, m, 0, m.Length, sig, sigOff);
  1122. }
  1123. public static bool ValidatePublicKeyFull(byte[] pk, int pkOff)
  1124. {
  1125. PointAffine p = new PointAffine();
  1126. if (!DecodePointVar(pk, pkOff, false, p))
  1127. return false;
  1128. F.Normalize(p.x);
  1129. F.Normalize(p.y);
  1130. if (IsNeutralElementVar(p.x, p.y))
  1131. return false;
  1132. PointAccum r = new PointAccum();
  1133. ScalarMultOrderVar(p, r);
  1134. F.Normalize(r.x);
  1135. F.Normalize(r.y);
  1136. F.Normalize(r.z);
  1137. return IsNeutralElementVar(r.x, r.y, r.z);
  1138. }
  1139. public static bool ValidatePublicKeyPartial(byte[] pk, int pkOff)
  1140. {
  1141. PointAffine p = new PointAffine();
  1142. return DecodePointVar(pk, pkOff, false, p);
  1143. }
  1144. public static bool Verify(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] m, int mOff, int mLen)
  1145. {
  1146. byte[] ctx = null;
  1147. byte phflag = 0x00;
  1148. return ImplVerify(sig, sigOff, pk, pkOff, ctx, phflag, m, mOff, mLen);
  1149. }
  1150. public static bool Verify(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, byte[] m, int mOff, int mLen)
  1151. {
  1152. byte phflag = 0x00;
  1153. return ImplVerify(sig, sigOff, pk, pkOff, ctx, phflag, m, mOff, mLen);
  1154. }
  1155. public static bool VerifyPrehash(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, byte[] ph, int phOff)
  1156. {
  1157. byte phflag = 0x01;
  1158. return ImplVerify(sig, sigOff, pk, pkOff, ctx, phflag, ph, phOff, PrehashSize);
  1159. }
  1160. public static bool VerifyPrehash(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, IDigest ph)
  1161. {
  1162. byte[] m = new byte[PrehashSize];
  1163. if (PrehashSize != ph.DoFinal(m, 0))
  1164. throw new ArgumentException("ph");
  1165. byte phflag = 0x01;
  1166. return ImplVerify(sig, sigOff, pk, pkOff, ctx, phflag, m, 0, m.Length);
  1167. }
  1168. }
  1169. }
  1170. #pragma warning restore
  1171. #endif