ClpECAlgorithms.pas 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886
  1. { *********************************************************************************** }
  2. { * CryptoLib Library * }
  3. { * Copyright (c) 2018 Ugochukwu Mmaduekwe * }
  4. { * Github Repository <https://github.com/Xor-el> * }
  5. { * Distributed under the MIT software license, see the accompanying file LICENSE * }
  6. { * or visit http://www.opensource.org/licenses/mit-license.php. * }
  7. { * Acknowledgements: * }
  8. { * * }
  9. { * Thanks to Sphere 10 Software (http://sphere10.com) for sponsoring * }
  10. { * the development of this library * }
  11. { * ******************************************************************************* * }
  12. (* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& *)
  13. unit ClpECAlgorithms;
  14. {$I ..\..\Include\CryptoLib.inc}
  15. interface
  16. uses
  17. SysUtils,
  18. Math,
  19. ClpCryptoLibTypes,
  20. ClpBits,
  21. ClpBigInteger,
  22. ClpWNafUtilities,
  23. ClpIPolynomialExtensionField,
  24. ClpIGlvEndomorphism,
  25. ClpIWNafPreCompInfo,
  26. ClpIECInterface,
  27. ClpIECFieldElement,
  28. ClpIFiniteField;
  29. resourcestring
  30. SInvalidArray =
  31. 'Point and Scalar Arrays Should be Non-Null, and of Equal, Non-Zero, Length';
  32. SInvalidPointLocation = 'Point Must be on the Same Curve';
  33. SInvalidPoint = 'Invalid Point, "P"';
  34. type
  35. TECAlgorithms = class sealed(TObject)
  36. strict private
  37. class function ImplShamirsTrickWNaf(preCompP,
  38. preCompNegP: TCryptoLibGenericArray<IECPoint>; wnafP: TCryptoLibByteArray;
  39. preCompQ, preCompNegQ: TCryptoLibGenericArray<IECPoint>;
  40. wnafQ: TCryptoLibByteArray): IECPoint; overload; static;
  41. class function ImplSumOfMultiplies(negs: TCryptoLibBooleanArray;
  42. infos: TCryptoLibGenericArray<IWNafPreCompInfo>;
  43. wnafs: TCryptoLibMatrixByteArray): IECPoint; overload; static;
  44. public
  45. class function IsF2mCurve(const c: IECCurve): Boolean; static;
  46. class function IsF2mField(const field: IFiniteField): Boolean; static;
  47. class function IsFpCurve(const c: IECCurve): Boolean; static;
  48. class function IsFpField(const field: IFiniteField): Boolean; static;
  49. class function SumOfMultiplies(ps: TCryptoLibGenericArray<IECPoint>;
  50. ks: TCryptoLibGenericArray<TBigInteger>): IECPoint; static;
  51. class function SumOfTwoMultiplies(const P: IECPoint; const a: TBigInteger;
  52. Q: IECPoint; const b: TBigInteger): IECPoint; static;
  53. // /*
  54. // * "Shamir's Trick", originally due to E. G. Straus
  55. // * (Addition chains of vectors. American Mathematical Monthly,
  56. // * 71(7):806-808, Aug./Sept. 1964)
  57. // *
  58. // * Input: The points P, Q, scalar k = (km?, ... , k1, k0)
  59. // * and scalar l = (lm?, ... , l1, l0).
  60. // * Output: R = k * P + l * Q.
  61. // * 1: Z <- P + Q
  62. // * 2: R <- O
  63. // * 3: for i from m-1 down to 0 do
  64. // * 4: R <- R + R {point doubling}
  65. // * 5: if (ki = 1) and (li = 0) then R <- R + P end if
  66. // * 6: if (ki = 0) and (li = 1) then R <- R + Q end if
  67. // * 7: if (ki = 1) and (li = 1) then R <- R + Z end if
  68. // * 8: end for
  69. // * 9: return R
  70. // */
  71. class function ShamirsTrick(const P: IECPoint; const k: TBigInteger;
  72. Q: IECPoint; const l: TBigInteger): IECPoint; static;
  73. class function ImportPoint(const c: IECCurve; const P: IECPoint): IECPoint;
  74. static; inline;
  75. class procedure MontgomeryTrick(zs: TCryptoLibGenericArray<IECFieldElement>;
  76. off, len: Int32); overload; static; inline;
  77. class procedure MontgomeryTrick(zs: TCryptoLibGenericArray<IECFieldElement>;
  78. off, len: Int32; const scale: IECFieldElement); overload; static;
  79. // /**
  80. // * Simple shift-and-add multiplication. Serves as reference implementation
  81. // * to verify (possibly faster) implementations, and for very small scalars.
  82. // *
  83. // * @param p
  84. // * The point to multiply.
  85. // * @param k
  86. // * The multiplier.
  87. // * @return The result of the point multiplication <code>kP</code>.
  88. // */
  89. class function ReferenceMultiply(P: IECPoint; const k: TBigInteger)
  90. : IECPoint; static;
  91. class function ValidatePoint(const P: IECPoint): IECPoint; static;
  92. class function ImplShamirsTrickJsf(const P: IECPoint; const k: TBigInteger;
  93. const Q: IECPoint; const l: TBigInteger): IECPoint; static;
  94. class function ImplShamirsTrickWNaf(const P: IECPoint; k: TBigInteger;
  95. const Q: IECPoint; l: TBigInteger): IECPoint; overload; static;
  96. class function ImplShamirsTrickWNaf(const P: IECPoint; k: TBigInteger;
  97. const pointMapQ: IECPointMap; l: TBigInteger): IECPoint; overload; static;
  98. class function ImplSumOfMultiplies(ps: TCryptoLibGenericArray<IECPoint>;
  99. ks: TCryptoLibGenericArray<TBigInteger>): IECPoint; overload; static;
  100. class function ImplSumOfMultipliesGlv(ps: TCryptoLibGenericArray<IECPoint>;
  101. ks: TCryptoLibGenericArray<TBigInteger>;
  102. const glvEndomorphism: IGlvEndomorphism): IECPoint; static;
  103. class function ImplSumOfMultiplies(ps: TCryptoLibGenericArray<IECPoint>;
  104. const pointMap: IECPointMap; ks: TCryptoLibGenericArray<TBigInteger>)
  105. : IECPoint; overload; static;
  106. end;
  107. implementation
  108. { TECAlgorithms }
  109. class function TECAlgorithms.ValidatePoint(const P: IECPoint): IECPoint;
  110. begin
  111. if (not P.IsValid()) then
  112. begin
  113. raise EArgumentCryptoLibException.CreateRes(@SInvalidPoint);
  114. end;
  115. result := P;
  116. end;
  117. class function TECAlgorithms.ImplShamirsTrickJsf(const P: IECPoint;
  118. const k: TBigInteger; const Q: IECPoint; const l: TBigInteger): IECPoint;
  119. var
  120. curve: IECCurve;
  121. infinity, R: IECPoint;
  122. PaddQ, PsubQ: IECPoint;
  123. points, table: TCryptoLibGenericArray<IECPoint>;
  124. jsf: TCryptoLibByteArray;
  125. i, jsfi, kDigit, lDigit, index: Int32;
  126. begin
  127. curve := P.curve;
  128. infinity := curve.infinity;
  129. // TODO conjugate co-Z addition (ZADDC) can return both of these
  130. PaddQ := P.Add(Q);
  131. PsubQ := P.Subtract(Q);
  132. points := TCryptoLibGenericArray<IECPoint>.Create(Q, PsubQ, P, PaddQ);
  133. curve.NormalizeAll(points);
  134. table := TCryptoLibGenericArray<IECPoint>.Create(points[3].Negate(),
  135. points[2].Negate(), points[1].Negate(), points[0].Negate(), infinity,
  136. points[0], points[1], points[2], points[3]);
  137. jsf := TWNafUtilities.GenerateJsf(k, l);
  138. R := infinity;
  139. i := System.Length(jsf);
  140. System.Dec(i);
  141. while (i >= 0) do
  142. begin
  143. jsfi := jsf[i];
  144. // NOTE: The shifting ensures the sign is extended correctly
  145. kDigit := (TBits.Asr32((jsfi shl 24), 28));
  146. lDigit := (TBits.Asr32((jsfi shl 28), 28));
  147. index := 4 + (kDigit * 3) + lDigit;
  148. R := R.TwicePlus(table[index]);
  149. System.Dec(i);
  150. end;
  151. result := R;
  152. end;
  153. class function TECAlgorithms.ImplShamirsTrickWNaf(const P: IECPoint;
  154. k: TBigInteger; const pointMapQ: IECPointMap; l: TBigInteger): IECPoint;
  155. var
  156. negK, negL: Boolean;
  157. width: Int32;
  158. Q: IECPoint;
  159. infoP, infoQ: IWNafPreCompInfo;
  160. preCompP, preCompQ, preCompNegP, preCompNegQ
  161. : TCryptoLibGenericArray<IECPoint>;
  162. wnafP, wnafQ: TCryptoLibByteArray;
  163. begin
  164. negK := k.SignValue < 0;
  165. negL := l.SignValue < 0;
  166. k := k.Abs();
  167. l := l.Abs();
  168. width := Max(2, Min(16, TWNafUtilities.GetWindowSize(Max(k.BitLength,
  169. l.BitLength))));
  170. Q := TWNafUtilities.MapPointWithPrecomp(P, width, true, pointMapQ);
  171. infoP := TWNafUtilities.GetWNafPreCompInfo(P);
  172. infoQ := TWNafUtilities.GetWNafPreCompInfo(Q);
  173. if negK then
  174. begin
  175. preCompP := infoP.PreCompNeg
  176. end
  177. else
  178. begin
  179. preCompP := infoP.PreComp
  180. end;
  181. if negL then
  182. begin
  183. preCompQ := infoQ.PreCompNeg
  184. end
  185. else
  186. begin
  187. preCompQ := infoQ.PreComp
  188. end;
  189. if negK then
  190. begin
  191. preCompNegP := infoP.PreComp
  192. end
  193. else
  194. begin
  195. preCompNegP := infoP.PreCompNeg
  196. end;
  197. if negL then
  198. begin
  199. preCompNegQ := infoQ.PreComp
  200. end
  201. else
  202. begin
  203. preCompNegQ := infoQ.PreCompNeg
  204. end;
  205. wnafP := TWNafUtilities.GenerateWindowNaf(width, k);
  206. wnafQ := TWNafUtilities.GenerateWindowNaf(width, l);
  207. result := ImplShamirsTrickWNaf(preCompP, preCompNegP, wnafP, preCompQ,
  208. preCompNegQ, wnafQ);
  209. infoP.PreComp := Nil;
  210. infoP.PreCompNeg := Nil;
  211. infoQ.PreComp := Nil;
  212. infoQ.PreCompNeg := Nil;
  213. end;
  214. class function TECAlgorithms.ImplShamirsTrickWNaf(const P: IECPoint;
  215. k: TBigInteger; const Q: IECPoint; l: TBigInteger): IECPoint;
  216. var
  217. negK, negL: Boolean;
  218. widthP, widthQ: Int32;
  219. infoP, infoQ: IWNafPreCompInfo;
  220. preCompP, preCompQ, preCompNegP, preCompNegQ
  221. : TCryptoLibGenericArray<IECPoint>;
  222. wnafP, wnafQ: TCryptoLibByteArray;
  223. begin
  224. negK := k.SignValue < 0;
  225. negL := l.SignValue < 0;
  226. k := k.Abs();
  227. l := l.Abs();
  228. widthP := Max(2, Min(16, TWNafUtilities.GetWindowSize(k.BitLength)));
  229. widthQ := Max(2, Min(16, TWNafUtilities.GetWindowSize(l.BitLength)));
  230. infoP := TWNafUtilities.Precompute(P, widthP, true);
  231. infoQ := TWNafUtilities.Precompute(Q, widthQ, true);
  232. if negK then
  233. begin
  234. preCompP := infoP.PreCompNeg
  235. end
  236. else
  237. begin
  238. preCompP := infoP.PreComp
  239. end;
  240. if negL then
  241. begin
  242. preCompQ := infoQ.PreCompNeg
  243. end
  244. else
  245. begin
  246. preCompQ := infoQ.PreComp
  247. end;
  248. if negK then
  249. begin
  250. preCompNegP := infoP.PreComp
  251. end
  252. else
  253. begin
  254. preCompNegP := infoP.PreCompNeg
  255. end;
  256. if negL then
  257. begin
  258. preCompNegQ := infoQ.PreComp
  259. end
  260. else
  261. begin
  262. preCompNegQ := infoQ.PreCompNeg
  263. end;
  264. wnafP := TWNafUtilities.GenerateWindowNaf(widthP, k);
  265. wnafQ := TWNafUtilities.GenerateWindowNaf(widthQ, l);
  266. result := ImplShamirsTrickWNaf(preCompP, preCompNegP, wnafP, preCompQ,
  267. preCompNegQ, wnafQ);
  268. infoP.PreComp := Nil;
  269. infoP.PreCompNeg := Nil;
  270. infoQ.PreComp := Nil;
  271. infoQ.PreCompNeg := Nil;
  272. end;
  273. class function TECAlgorithms.ImplShamirsTrickWNaf(preCompP,
  274. preCompNegP: TCryptoLibGenericArray<IECPoint>; wnafP: TCryptoLibByteArray;
  275. preCompQ, preCompNegQ: TCryptoLibGenericArray<IECPoint>;
  276. wnafQ: TCryptoLibByteArray): IECPoint;
  277. var
  278. len, zeroes, i, wiP, wiQ, nP, nQ: Int32;
  279. curve: IECCurve;
  280. infinity, R, point: IECPoint;
  281. tableP, tableQ: TCryptoLibGenericArray<IECPoint>;
  282. begin
  283. len := Math.Max(System.Length(wnafP), System.Length(wnafQ));
  284. curve := preCompP[0].curve;
  285. infinity := curve.infinity;
  286. R := infinity;
  287. zeroes := 0;
  288. i := len - 1;
  289. while (i >= 0) do
  290. begin
  291. if i < System.Length(wnafP) then
  292. begin
  293. wiP := Int32(ShortInt(wnafP[i]));
  294. end
  295. else
  296. begin
  297. wiP := 0;
  298. end;
  299. if i < System.Length(wnafQ) then
  300. begin
  301. wiQ := Int32(ShortInt(wnafQ[i]));
  302. end
  303. else
  304. begin
  305. wiQ := 0;
  306. end;
  307. if ((wiP or wiQ) = 0) then
  308. begin
  309. System.Inc(zeroes);
  310. System.Dec(i);
  311. continue;
  312. end;
  313. point := infinity;
  314. if (wiP <> 0) then
  315. begin
  316. nP := System.Abs(wiP);
  317. if wiP < 0 then
  318. begin
  319. tableP := preCompNegP;
  320. end
  321. else
  322. begin
  323. tableP := preCompP;
  324. end;
  325. point := point.Add(tableP[TBits.Asr32(nP, 1)]);
  326. end;
  327. if (wiQ <> 0) then
  328. begin
  329. nQ := System.Abs(wiQ);
  330. if wiQ < 0 then
  331. begin
  332. tableQ := preCompNegQ;
  333. end
  334. else
  335. begin
  336. tableQ := preCompQ;
  337. end;
  338. point := point.Add(tableQ[TBits.Asr32(nQ, 1)]);
  339. end;
  340. if (zeroes > 0) then
  341. begin
  342. R := R.TimesPow2(zeroes);
  343. zeroes := 0;
  344. end;
  345. R := R.TwicePlus(point);
  346. System.Dec(i);
  347. end;
  348. if (zeroes > 0) then
  349. begin
  350. R := R.TimesPow2(zeroes);
  351. end;
  352. result := R;
  353. end;
  354. class function TECAlgorithms.ImplSumOfMultiplies
  355. (ps: TCryptoLibGenericArray<IECPoint>; const pointMap: IECPointMap;
  356. ks: TCryptoLibGenericArray<TBigInteger>): IECPoint;
  357. var
  358. halfCount, fullCount: Int32;
  359. negs: TCryptoLibBooleanArray;
  360. infos: TCryptoLibGenericArray<IWNafPreCompInfo>;
  361. wnafs: TCryptoLibMatrixByteArray;
  362. i, j0, j1, width: Int32;
  363. kj0, kj1: TBigInteger;
  364. P, Q: IECPoint;
  365. begin
  366. halfCount := System.Length(ps);
  367. fullCount := halfCount shl 1;
  368. System.SetLength(negs, fullCount);
  369. System.SetLength(infos, fullCount);
  370. System.SetLength(wnafs, fullCount);
  371. for i := 0 to System.Pred(halfCount) do
  372. begin
  373. j0 := i shl 1;
  374. j1 := j0 + 1;
  375. kj0 := ks[j0];
  376. negs[j0] := kj0.SignValue < 0;
  377. kj0 := kj0.Abs();
  378. kj1 := ks[j1];
  379. negs[j1] := kj1.SignValue < 0;
  380. kj1 := kj1.Abs();
  381. width := Max(2, Min(16, TWNafUtilities.GetWindowSize(Max(kj0.BitLength,
  382. kj1.BitLength))));
  383. P := ps[i];
  384. Q := TWNafUtilities.MapPointWithPrecomp(P, width, true, pointMap);
  385. infos[j0] := TWNafUtilities.GetWNafPreCompInfo(P);
  386. infos[j1] := TWNafUtilities.GetWNafPreCompInfo(Q);
  387. wnafs[j0] := TWNafUtilities.GenerateWindowNaf(width, kj0);
  388. wnafs[j1] := TWNafUtilities.GenerateWindowNaf(width, kj1);
  389. end;
  390. result := ImplSumOfMultiplies(negs, infos, wnafs);
  391. for i := System.Low(infos) to System.High(infos) do
  392. begin
  393. infos[i].PreComp := Nil;
  394. infos[i].PreCompNeg := Nil;
  395. end;
  396. end;
  397. class function TECAlgorithms.ImplSumOfMultiplies
  398. (ps: TCryptoLibGenericArray<IECPoint>;
  399. ks: TCryptoLibGenericArray<TBigInteger>): IECPoint;
  400. var
  401. count, i, width: Int32;
  402. negs: TCryptoLibBooleanArray;
  403. infos: TCryptoLibGenericArray<IWNafPreCompInfo>;
  404. wnafs: TCryptoLibMatrixByteArray;
  405. ki: TBigInteger;
  406. begin
  407. count := System.Length(ps);
  408. System.SetLength(negs, count);
  409. System.SetLength(infos, count);
  410. System.SetLength(wnafs, count);
  411. for i := 0 to System.Pred(count) do
  412. begin
  413. ki := ks[i];
  414. negs[i] := ki.SignValue < 0;
  415. ki := ki.Abs();
  416. width := Max(2, Min(16, TWNafUtilities.GetWindowSize(ki.BitLength)));
  417. infos[i] := TWNafUtilities.Precompute(ps[i], width, true);
  418. wnafs[i] := TWNafUtilities.GenerateWindowNaf(width, ki);
  419. end;
  420. result := ImplSumOfMultiplies(negs, infos, wnafs);
  421. end;
  422. class function TECAlgorithms.ImplSumOfMultiplies(negs: TCryptoLibBooleanArray;
  423. infos: TCryptoLibGenericArray<IWNafPreCompInfo>;
  424. wnafs: TCryptoLibMatrixByteArray): IECPoint;
  425. var
  426. len, count, zeroes: Int32;
  427. i, J, wi, n: Int32;
  428. curve: IECCurve;
  429. infinity, R, point: IECPoint;
  430. wnaf: TCryptoLibByteArray;
  431. info: IWNafPreCompInfo;
  432. table: TCryptoLibGenericArray<IECPoint>;
  433. begin
  434. len := 0;
  435. count := System.Length(wnafs);
  436. for i := 0 to System.Pred(count) do
  437. begin
  438. len := Max(len, System.Length(wnafs[i]));
  439. end;
  440. curve := infos[0].PreComp[0].curve;
  441. infinity := curve.infinity;
  442. R := infinity;
  443. zeroes := 0;
  444. i := len - 1;
  445. while (i >= 0) do
  446. begin
  447. point := infinity;
  448. for J := 0 to System.Pred(count) do
  449. begin
  450. wnaf := wnafs[J];
  451. if i < System.Length(wnaf) then
  452. begin
  453. wi := Int32(ShortInt(wnaf[i]));
  454. end
  455. else
  456. begin
  457. wi := 0;
  458. end;
  459. if (wi <> 0) then
  460. begin
  461. n := System.Abs(wi);
  462. info := infos[J];
  463. if (wi < 0 = negs[J]) then
  464. begin
  465. table := info.PreComp;
  466. end
  467. else
  468. begin
  469. table := info.PreCompNeg;
  470. end;
  471. point := point.Add(table[TBits.Asr32(n, 1)]);
  472. end;
  473. end;
  474. if (point = infinity) then
  475. begin
  476. System.Inc(zeroes);
  477. System.Dec(i);
  478. continue;
  479. end;
  480. if (zeroes > 0) then
  481. begin
  482. R := R.TimesPow2(zeroes);
  483. zeroes := 0;
  484. end;
  485. R := R.TwicePlus(point);
  486. System.Dec(i);
  487. end;
  488. if (zeroes > 0) then
  489. begin
  490. R := R.TimesPow2(zeroes);
  491. end;
  492. result := R;
  493. end;
  494. class function TECAlgorithms.ImplSumOfMultipliesGlv
  495. (ps: TCryptoLibGenericArray<IECPoint>;
  496. ks: TCryptoLibGenericArray<TBigInteger>;
  497. const glvEndomorphism: IGlvEndomorphism): IECPoint;
  498. var
  499. n: TBigInteger;
  500. len, i, J: Int32;
  501. &abs, ab: TCryptoLibGenericArray<TBigInteger>;
  502. pointMap: IECPointMap;
  503. pqs: TCryptoLibGenericArray<IECPoint>;
  504. P, Q: IECPoint;
  505. begin
  506. n := ps[0].curve.Order;
  507. len := System.Length(ps);
  508. System.SetLength(Abs, len shl 1);
  509. i := 0;
  510. J := 0;
  511. while (i < len) do
  512. begin
  513. ab := glvEndomorphism.DecomposeScalar(ks[i].&Mod(n));
  514. Abs[J] := ab[0];
  515. System.Inc(J);
  516. Abs[J] := ab[1];
  517. System.Inc(J);
  518. System.Inc(i);
  519. end;
  520. pointMap := glvEndomorphism.pointMap;
  521. if (glvEndomorphism.HasEfficientPointMap) then
  522. begin
  523. result := TECAlgorithms.ImplSumOfMultiplies(ps, pointMap, Abs);
  524. Exit;
  525. end;
  526. System.SetLength(pqs, len shl 1);
  527. i := 0;
  528. J := 0;
  529. while (i < len) do
  530. begin
  531. P := ps[i];
  532. Q := pointMap.Map(P);
  533. pqs[J] := P;
  534. System.Inc(J);
  535. pqs[J] := Q;
  536. System.Inc(J);
  537. System.Inc(i);
  538. end;
  539. result := TECAlgorithms.ImplSumOfMultiplies(pqs, Abs);
  540. end;
  541. class function TECAlgorithms.ImportPoint(const c: IECCurve; const P: IECPoint)
  542. : IECPoint;
  543. var
  544. cp: IECCurve;
  545. begin
  546. cp := P.curve;
  547. if (not c.Equals(cp)) then
  548. begin
  549. raise EArgumentCryptoLibException.CreateRes(@SInvalidPointLocation);
  550. end;
  551. result := c.ImportPoint(P);
  552. end;
  553. class function TECAlgorithms.IsF2mField(const field: IFiniteField): Boolean;
  554. begin
  555. result := (field.Dimension > 1) and
  556. (field.Characteristic.Equals(TBigInteger.Two)) and
  557. (Supports(field, IPolynomialExtensionField));
  558. end;
  559. class function TECAlgorithms.IsF2mCurve(const c: IECCurve): Boolean;
  560. begin
  561. result := IsF2mField(c.field);
  562. end;
  563. class function TECAlgorithms.IsFpField(const field: IFiniteField): Boolean;
  564. begin
  565. result := field.Dimension = 1;
  566. end;
  567. class function TECAlgorithms.IsFpCurve(const c: IECCurve): Boolean;
  568. begin
  569. result := IsFpField(c.field);
  570. end;
  571. class procedure TECAlgorithms.MontgomeryTrick
  572. (zs: TCryptoLibGenericArray<IECFieldElement>; off, len: Int32;
  573. const scale: IECFieldElement);
  574. var
  575. c: TCryptoLibGenericArray<IECFieldElement>;
  576. i, J: Int32;
  577. u, tmp: IECFieldElement;
  578. begin
  579. // /*
  580. // * Uses the "Montgomery Trick" to invert many field elements, with only a single actual
  581. // * field inversion. See e.g. the paper:
  582. // * "Fast Multi-scalar Multiplication Methods on Elliptic Curves with Precomputation Strategy Using Montgomery Trick"
  583. // * by Katsuyuki Okeya, Kouichi Sakurai.
  584. // */
  585. System.SetLength(c, len);
  586. c[0] := zs[off];
  587. i := 0;
  588. System.Inc(i);
  589. while (i < len) do
  590. begin
  591. c[i] := c[i - 1].Multiply(zs[off + i]);
  592. System.Inc(i);
  593. end;
  594. System.Dec(i);
  595. if (scale <> Nil) then
  596. begin
  597. c[i] := c[i].Multiply(scale);
  598. end;
  599. u := c[i].Invert();
  600. while (i > 0) do
  601. begin
  602. J := off + i;
  603. System.Dec(i);
  604. tmp := zs[J];
  605. zs[J] := c[i].Multiply(u);
  606. u := u.Multiply(tmp);
  607. end;
  608. zs[off] := u;
  609. end;
  610. class procedure TECAlgorithms.MontgomeryTrick
  611. (zs: TCryptoLibGenericArray<IECFieldElement>; off, len: Int32);
  612. begin
  613. MontgomeryTrick(zs, off, len, Nil);
  614. end;
  615. class function TECAlgorithms.ReferenceMultiply(P: IECPoint;
  616. const k: TBigInteger): IECPoint;
  617. var
  618. x: TBigInteger;
  619. Q: IECPoint;
  620. t, i: Int32;
  621. begin
  622. x := k.Abs();
  623. Q := P.curve.infinity;
  624. t := x.BitLength;
  625. if (t > 0) then
  626. begin
  627. if (x.TestBit(0)) then
  628. begin
  629. Q := P;
  630. end;
  631. i := 1;
  632. while (i < t) do
  633. begin
  634. P := P.Twice();
  635. if (x.TestBit(i)) then
  636. begin
  637. Q := Q.Add(P);
  638. end;
  639. System.Inc(i);
  640. end;
  641. end;
  642. if k.SignValue < 0 then
  643. begin
  644. result := Q.Negate();
  645. end
  646. else
  647. begin
  648. result := Q;
  649. end;
  650. end;
  651. class function TECAlgorithms.ShamirsTrick(const P: IECPoint;
  652. const k: TBigInteger; Q: IECPoint; const l: TBigInteger): IECPoint;
  653. var
  654. cp: IECCurve;
  655. begin
  656. cp := P.curve;
  657. Q := ImportPoint(cp, Q);
  658. result := ValidatePoint(ImplShamirsTrickJsf(P, k, Q, l));
  659. end;
  660. class function TECAlgorithms.SumOfMultiplies
  661. (ps: TCryptoLibGenericArray<IECPoint>;
  662. ks: TCryptoLibGenericArray<TBigInteger>): IECPoint;
  663. var
  664. count: Int32;
  665. P: IECPoint;
  666. c: IECCurve;
  667. i: Int32;
  668. imported: TCryptoLibGenericArray<IECPoint>;
  669. glvEndomorphism: IGlvEndomorphism;
  670. begin
  671. if ((ps = Nil) or (ks = Nil) or (System.Length(ps) <> System.Length(ks)) or
  672. (System.Length(ps) < 1)) then
  673. begin
  674. raise EArgumentCryptoLibException.CreateRes(@SInvalidArray);
  675. end;
  676. count := System.Length(ps);
  677. case count of
  678. 1:
  679. begin
  680. result := ps[0].Multiply(ks[0]);
  681. Exit;
  682. end;
  683. 2:
  684. begin
  685. result := SumOfTwoMultiplies(ps[0], ks[0], ps[1], ks[1]);
  686. Exit;
  687. end;
  688. end;
  689. P := ps[0];
  690. c := P.curve;
  691. System.SetLength(imported, count);
  692. imported[0] := P;
  693. for i := 1 to System.Pred(count) do
  694. begin
  695. imported[i] := ImportPoint(c, ps[i]);
  696. end;
  697. if Supports(c.GetEndomorphism(), IGlvEndomorphism, glvEndomorphism) then
  698. begin
  699. result := ValidatePoint(ImplSumOfMultipliesGlv(imported, ks,
  700. glvEndomorphism));
  701. Exit;
  702. end;
  703. result := ValidatePoint(ImplSumOfMultiplies(imported, ks));
  704. end;
  705. class function TECAlgorithms.SumOfTwoMultiplies(const P: IECPoint;
  706. const a: TBigInteger; Q: IECPoint; const b: TBigInteger): IECPoint;
  707. var
  708. cp: IECCurve;
  709. f2mCurve: IAbstractF2mCurve;
  710. glvEndomorphism: IGlvEndomorphism;
  711. begin
  712. cp := P.curve;
  713. Q := ImportPoint(cp, Q);
  714. // Point multiplication for Koblitz curves (using WTNAF) beats Shamir's trick
  715. if (Supports(cp, IAbstractF2mCurve, f2mCurve) and (f2mCurve.IsKoblitz)) then
  716. begin
  717. result := ValidatePoint(P.Multiply(a).Add(Q.Multiply(b)));
  718. Exit;
  719. end;
  720. if Supports(cp.GetEndomorphism(), IGlvEndomorphism, glvEndomorphism) then
  721. begin
  722. result := ValidatePoint
  723. (ImplSumOfMultipliesGlv(TCryptoLibGenericArray<IECPoint>.Create(P, Q),
  724. TCryptoLibGenericArray<TBigInteger>.Create(a, b), glvEndomorphism));
  725. Exit;
  726. end;
  727. result := ValidatePoint(ImplShamirsTrickWNaf(P, a, Q, b));
  728. end;
  729. end.