ClpECAlgorithms.pas 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069
  1. { *********************************************************************************** }
  2. { * CryptoLib Library * }
  3. { * Copyright (c) 2018 - 20XX 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://www.sphere10.com/) for sponsoring * }
  10. { * 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. ClpBigInteger,
  21. ClpBits,
  22. ClpNat,
  23. ClpIECC,
  24. ClpECCompUtilities,
  25. ClpIWNafPreCompInfo,
  26. ClpIFiniteField,
  27. ClpIFixedPointPreCompInfo,
  28. ClpIGlvEndomorphism,
  29. ClpIMultipliers,
  30. ClpMultipliers,
  31. ClpIPolynomialExtensionField;
  32. resourcestring
  33. SInvalidArray =
  34. 'Point and Scalar Arrays Should be Non-Null, and of Equal, Non-Zero, Length';
  35. SInvalidPointLocation = 'Point Must be on the Same Curve';
  36. SInvalidPoint = 'Invalid Point, "P"';
  37. SInvalidResult = 'Invalid Result';
  38. SInvalidComputation =
  39. 'Fixed-Point Comb Doesn''t Support Scalars Larger Than The Curve Order';
  40. type
  41. TECAlgorithms = class sealed(TObject)
  42. strict private
  43. class function ImplShamirsTrickWNaf(const preCompP,
  44. preCompNegP: TCryptoLibGenericArray<IECPoint>;
  45. const wnafP: TCryptoLibByteArray;
  46. const preCompQ, preCompNegQ: TCryptoLibGenericArray<IECPoint>;
  47. const wnafQ: TCryptoLibByteArray): IECPoint; overload; static;
  48. class function ImplSumOfMultiplies(const negs: TCryptoLibBooleanArray;
  49. const infos: TCryptoLibGenericArray<IWNafPreCompInfo>;
  50. const wnafs: TCryptoLibMatrixByteArray): IECPoint; overload; static;
  51. class function ImplShamirsTrickFixedPoint(const p: IECPoint;
  52. const k: TBigInteger; const q: IECPoint; const l: TBigInteger)
  53. : IECPoint; static;
  54. public
  55. class function IsF2mCurve(const c: IECCurve): Boolean; static;
  56. class function IsF2mField(const field: IFiniteField): Boolean; static;
  57. class function IsFpCurve(const c: IECCurve): Boolean; static;
  58. class function IsFpField(const field: IFiniteField): Boolean; static;
  59. class function SumOfMultiplies(const ps: TCryptoLibGenericArray<IECPoint>;
  60. const ks: TCryptoLibGenericArray<TBigInteger>): IECPoint; static;
  61. class function SumOfTwoMultiplies(const p: IECPoint; const a: TBigInteger;
  62. const q: IECPoint; const b: TBigInteger): IECPoint; static;
  63. // /*
  64. // * "Shamir's Trick", originally due to E. G. Straus
  65. // * (Addition chains of vectors. American Mathematical Monthly,
  66. // * 71(7):806-808, Aug./Sept. 1964)
  67. // *
  68. // * Input: The points P, Q, scalar k = (km?, ... , k1, k0)
  69. // * and scalar l = (lm?, ... , l1, l0).
  70. // * Output: R = k * P + l * Q.
  71. // * 1: Z <- P + Q
  72. // * 2: R <- O
  73. // * 3: for i from m-1 down to 0 do
  74. // * 4: R <- R + R {point doubling}
  75. // * 5: if (ki = 1) and (li = 0) then R <- R + P end if
  76. // * 6: if (ki = 0) and (li = 1) then R <- R + Q end if
  77. // * 7: if (ki = 1) and (li = 1) then R <- R + Z end if
  78. // * 8: end for
  79. // * 9: return R
  80. // */
  81. class function ShamirsTrick(const p: IECPoint; const k: TBigInteger;
  82. const q: IECPoint; const l: TBigInteger): IECPoint; static;
  83. class function ImportPoint(const c: IECCurve; const p: IECPoint)
  84. : IECPoint; static;
  85. class procedure MontgomeryTrick(const zs
  86. : TCryptoLibGenericArray<IECFieldElement>; off, len: Int32); overload;
  87. static; inline;
  88. class procedure MontgomeryTrick(const zs
  89. : TCryptoLibGenericArray<IECFieldElement>; off, len: Int32;
  90. const scale: IECFieldElement); overload; static;
  91. // /**
  92. // * Simple shift-and-add multiplication. Serves as reference implementation
  93. // * to verify (possibly faster) implementations, and for very small scalars.
  94. // *
  95. // * @param p
  96. // * The point to multiply.
  97. // * @param k
  98. // * The multiplier.
  99. // * @return The result of the point multiplication <code>kP</code>.
  100. // */
  101. class function ReferenceMultiply(const p: IECPoint; const k: TBigInteger)
  102. : IECPoint; static;
  103. class function ImplCheckResult(const p: IECPoint): IECPoint; static;
  104. class function ValidatePoint(const p: IECPoint): IECPoint; static;
  105. class function CleanPoint(const c: IECCurve; const p: IECPoint)
  106. : IECPoint; static;
  107. class function ImplShamirsTrickJsf(const p: IECPoint; const k: TBigInteger;
  108. const q: IECPoint; const l: TBigInteger): IECPoint; static;
  109. class function ImplShamirsTrickWNaf(const p: IECPoint; const k: TBigInteger;
  110. const q: IECPoint; const l: TBigInteger): IECPoint; overload; static;
  111. class function ImplShamirsTrickWNaf(const endomorphism: IECEndomorphism;
  112. const p: IECPoint; const k, l: TBigInteger): IECPoint; overload; static;
  113. class function ImplSumOfMultiplies
  114. (const ps: TCryptoLibGenericArray<IECPoint>;
  115. const ks: TCryptoLibGenericArray<TBigInteger>): IECPoint;
  116. overload; static;
  117. class function ImplSumOfMultipliesGlv
  118. (const ps: TCryptoLibGenericArray<IECPoint>;
  119. const ks: TCryptoLibGenericArray<TBigInteger>;
  120. const glvEndomorphism: IGlvEndomorphism): IECPoint; static;
  121. class function ImplSumOfMultiplies(const endomorphism: IECEndomorphism;
  122. const ps: TCryptoLibGenericArray<IECPoint>;
  123. const ks: TCryptoLibGenericArray<TBigInteger>): IECPoint;
  124. overload; static;
  125. end;
  126. implementation
  127. { TECAlgorithms }
  128. class function TECAlgorithms.ImplCheckResult(const p: IECPoint): IECPoint;
  129. begin
  130. if (not(p.IsValidPartial())) then
  131. begin
  132. raise EArgumentCryptoLibException.CreateRes(@SInvalidResult);
  133. end;
  134. result := p;
  135. end;
  136. class function TECAlgorithms.CleanPoint(const c: IECCurve; const p: IECPoint)
  137. : IECPoint;
  138. var
  139. cp: IECCurve;
  140. begin
  141. cp := p.Curve;
  142. if (not c.Equals(cp)) then
  143. begin
  144. raise EArgumentCryptoLibException.CreateRes(@SInvalidPointLocation);
  145. end;
  146. result := c.DecodePoint(p.getEncoded(false));
  147. end;
  148. class function TECAlgorithms.ValidatePoint(const p: IECPoint): IECPoint;
  149. begin
  150. if (not p.IsValid()) then
  151. begin
  152. raise EArgumentCryptoLibException.CreateRes(@SInvalidPoint);
  153. end;
  154. result := p;
  155. end;
  156. class function TECAlgorithms.ImplShamirsTrickFixedPoint(const p: IECPoint;
  157. const k: TBigInteger; const q: IECPoint; const l: TBigInteger): IECPoint;
  158. var
  159. c: IECCurve;
  160. combSize, widthP, widthQ, width, d, fullComb, i, top, j: Int32;
  161. infoP, infoQ: IFixedPointPreCompInfo;
  162. lookupTableP, lookupTableQ: IECLookupTable;
  163. m: IFixedPointCombMultiplier;
  164. r1, r2, R, addP, addQ, t: IECPoint;
  165. BigK, BigL: TCryptoLibUInt32Array;
  166. secretBitK, secretBitL, secretIndexK, secretIndexL: UInt32;
  167. begin
  168. c := p.Curve;
  169. combSize := TFixedPointUtilities.GetCombSize(c);
  170. if (((k.BitLength) > combSize) or (l.BitLength > combSize)) then
  171. begin
  172. (*
  173. * TODO The comb works best when the scalars are less than the (possibly unknown) order.
  174. * Still, if we want to handle larger scalars, we could allow customization of the comb
  175. * size, or alternatively we could deal with the 'extra' bits either by running the comb
  176. * multiple times as necessary, or by using an alternative multiplier as prelude.
  177. *)
  178. raise EInvalidOperationCryptoLibException.CreateRes(@SInvalidComputation);
  179. end;
  180. infoP := TFixedPointUtilities.Precompute(p);
  181. infoQ := TFixedPointUtilities.Precompute(q);
  182. lookupTableP := infoP.LookupTable;
  183. lookupTableQ := infoQ.LookupTable;
  184. widthP := infoP.width;
  185. widthQ := infoQ.width;
  186. // TODO This shouldn't normally happen, but a better "solution" is desirable anyway
  187. if (widthP <> widthQ) then
  188. begin
  189. m := TFixedPointCombMultiplier.Create();
  190. r1 := m.Multiply(p, k);
  191. r2 := m.Multiply(q, l);
  192. result := r1.Add(r2);
  193. Exit;
  194. end;
  195. width := widthP;
  196. d := ((combSize + width) - 1) div width;
  197. R := c.Infinity;
  198. fullComb := d * width;
  199. BigK := TNat.FromBigInteger(fullComb, k);
  200. BigL := TNat.FromBigInteger(fullComb, l);
  201. top := fullComb - 1;
  202. for i := 0 to System.Pred(d) do
  203. begin
  204. secretIndexK := 0;
  205. secretIndexL := 0;
  206. j := top - i;
  207. while j >= 0 do
  208. begin
  209. secretBitK := BigK[TBits.Asr32(j, 5)] shr (j and $1F);
  210. secretIndexK := secretIndexK xor (secretBitK shr 1);
  211. secretIndexK := secretIndexK shl 1;
  212. secretIndexK := secretIndexK xor secretBitK;
  213. secretBitL := BigL[TBits.Asr32(j, 5)] shr (j and $1F);
  214. secretIndexL := secretIndexL xor (secretBitL shr 1);
  215. secretIndexL := secretIndexL shl 1;
  216. secretIndexL := secretIndexL xor secretBitL;
  217. System.Dec(j, d);
  218. end;
  219. addP := lookupTableP.LookupVar(Int32(secretIndexK));
  220. addQ := lookupTableQ.LookupVar(Int32(secretIndexL));
  221. t := addP.Add(addQ);
  222. R := R.TwicePlus(t);
  223. end;
  224. result := R.Add(infoP.Offset).Add(infoQ.Offset);
  225. end;
  226. class function TECAlgorithms.ImplShamirsTrickJsf(const p: IECPoint;
  227. const k: TBigInteger; const q: IECPoint; const l: TBigInteger): IECPoint;
  228. var
  229. Curve: IECCurve;
  230. Infinity, R: IECPoint;
  231. PaddQ, PsubQ: IECPoint;
  232. points, table: TCryptoLibGenericArray<IECPoint>;
  233. jsf: TCryptoLibByteArray;
  234. i, jsfi, kDigit, lDigit, index: Int32;
  235. begin
  236. Curve := p.Curve;
  237. Infinity := Curve.Infinity;
  238. // TODO conjugate co-Z addition (ZADDC) can return both of these
  239. PaddQ := p.Add(q);
  240. PsubQ := p.Subtract(q);
  241. points := TCryptoLibGenericArray<IECPoint>.Create(q, PsubQ, p, PaddQ);
  242. Curve.NormalizeAll(points);
  243. table := TCryptoLibGenericArray<IECPoint>.Create(points[3].Negate(),
  244. points[2].Negate(), points[1].Negate(), points[0].Negate(), Infinity,
  245. points[0], points[1], points[2], points[3]);
  246. jsf := TWNafUtilities.GenerateJsf(k, l);
  247. R := Infinity;
  248. i := System.length(jsf);
  249. System.Dec(i);
  250. while (i >= 0) do
  251. begin
  252. jsfi := jsf[i];
  253. // NOTE: The shifting ensures the sign is extended correctly
  254. kDigit := (TBits.Asr32((jsfi shl 24), 28));
  255. lDigit := (TBits.Asr32((jsfi shl 28), 28));
  256. index := 4 + (kDigit * 3) + lDigit;
  257. R := R.TwicePlus(table[index]);
  258. System.Dec(i);
  259. end;
  260. result := R;
  261. end;
  262. class function TECAlgorithms.ImplShamirsTrickWNaf(const endomorphism
  263. : IECEndomorphism; const p: IECPoint; const k, l: TBigInteger): IECPoint;
  264. var
  265. negK, negL: Boolean;
  266. minWidth, widthP, widthQ: Int32;
  267. q: IECPoint;
  268. infoP, infoQ: IWNafPreCompInfo;
  269. preCompP, preCompQ, preCompNegP, preCompNegQ
  270. : TCryptoLibGenericArray<IECPoint>;
  271. wnafP, wnafQ: TCryptoLibByteArray;
  272. LK, LL: TBigInteger;
  273. begin
  274. LK := k;
  275. LL := l;
  276. negK := LK.SignValue < 0;
  277. negL := LL.SignValue < 0;
  278. LK := LK.Abs();
  279. LL := LL.Abs();
  280. minWidth := TWNafUtilities.GetWindowSize(Max(k.BitLength, l.BitLength), 8);
  281. infoP := TWNafUtilities.Precompute(p, minWidth, true);
  282. q := TEndoUtilities.MapPoint(endomorphism, p);
  283. infoQ := TWNafUtilities.PrecomputeWithPointMap(q, endomorphism.pointMap,
  284. infoP, true);
  285. widthP := Min(8, infoP.width);
  286. widthQ := Min(8, infoQ.width);
  287. case negK of
  288. true:
  289. preCompP := infoP.PreCompNeg;
  290. false:
  291. preCompP := infoP.PreComp;
  292. end;
  293. case negL of
  294. true:
  295. preCompQ := infoQ.PreCompNeg;
  296. false:
  297. preCompQ := infoQ.PreComp
  298. end;
  299. case negK of
  300. true:
  301. preCompNegP := infoP.PreComp;
  302. false:
  303. preCompNegP := infoP.PreCompNeg;
  304. end;
  305. case negL of
  306. true:
  307. preCompNegQ := infoQ.PreComp;
  308. false:
  309. preCompNegQ := infoQ.PreCompNeg
  310. end;
  311. wnafP := TWNafUtilities.GenerateWindowNaf(widthP, LK);
  312. wnafQ := TWNafUtilities.GenerateWindowNaf(widthQ, LL);
  313. result := ImplShamirsTrickWNaf(preCompP, preCompNegP, wnafP, preCompQ,
  314. preCompNegQ, wnafQ);
  315. infoP.PreComp := Nil; // Review
  316. infoP.PreCompNeg := Nil; // Review
  317. infoQ.PreComp := Nil; // Review
  318. infoQ.PreCompNeg := Nil; // Review
  319. end;
  320. class function TECAlgorithms.ImplShamirsTrickWNaf(const p: IECPoint;
  321. const k: TBigInteger; const q: IECPoint; const l: TBigInteger): IECPoint;
  322. var
  323. negK, negL: Boolean;
  324. minWidthP, minWidthQ, widthP, widthQ, combSize: Int32;
  325. infoP, infoQ: IWNafPreCompInfo;
  326. preCompP, preCompQ, preCompNegP, preCompNegQ
  327. : TCryptoLibGenericArray<IECPoint>;
  328. wnafP, wnafQ: TCryptoLibByteArray;
  329. kAbs, lAbs: TBigInteger;
  330. c: IECCurve;
  331. begin
  332. negK := k.SignValue < 0;
  333. negL := l.SignValue < 0;
  334. kAbs := k.Abs();
  335. lAbs := l.Abs();
  336. minWidthP := TWNafUtilities.GetWindowSize(kAbs.BitLength, 8);
  337. minWidthQ := TWNafUtilities.GetWindowSize(lAbs.BitLength, 8);
  338. infoP := TWNafUtilities.Precompute(p, minWidthP, true);
  339. infoQ := TWNafUtilities.Precompute(q, minWidthQ, true);
  340. // When P, Q are 'promoted' (i.e. reused several times), switch to fixed-point algorithm
  341. c := p.Curve;
  342. combSize := TFixedPointUtilities.GetCombSize(c);
  343. if ((not negK) and (not negL) and (k.BitLength <= combSize) and
  344. (l.BitLength <= combSize) and (infoP.IsPromoted) and (infoQ.IsPromoted))
  345. then
  346. begin
  347. result := ImplShamirsTrickFixedPoint(p, k, q, l);
  348. infoP.PreComp := Nil; // Review
  349. infoP.PreCompNeg := Nil; // Review
  350. infoQ.PreComp := Nil; // Review
  351. infoQ.PreCompNeg := Nil; // Review
  352. Exit;
  353. end;
  354. widthP := Min(8, infoP.width);
  355. widthQ := Min(8, infoQ.width);
  356. if negK then
  357. begin
  358. preCompP := infoP.PreCompNeg
  359. end
  360. else
  361. begin
  362. preCompP := infoP.PreComp
  363. end;
  364. if negL then
  365. begin
  366. preCompQ := infoQ.PreCompNeg
  367. end
  368. else
  369. begin
  370. preCompQ := infoQ.PreComp
  371. end;
  372. if negK then
  373. begin
  374. preCompNegP := infoP.PreComp
  375. end
  376. else
  377. begin
  378. preCompNegP := infoP.PreCompNeg
  379. end;
  380. if negL then
  381. begin
  382. preCompNegQ := infoQ.PreComp
  383. end
  384. else
  385. begin
  386. preCompNegQ := infoQ.PreCompNeg
  387. end;
  388. wnafP := TWNafUtilities.GenerateWindowNaf(widthP, kAbs);
  389. wnafQ := TWNafUtilities.GenerateWindowNaf(widthQ, lAbs);
  390. result := ImplShamirsTrickWNaf(preCompP, preCompNegP, wnafP, preCompQ,
  391. preCompNegQ, wnafQ);
  392. infoP.PreComp := Nil; // Review
  393. infoP.PreCompNeg := Nil; // Review
  394. infoQ.PreComp := Nil; // Review
  395. infoQ.PreCompNeg := Nil; // Review
  396. end;
  397. class function TECAlgorithms.ImplShamirsTrickWNaf(const preCompP,
  398. preCompNegP: TCryptoLibGenericArray<IECPoint>;
  399. const wnafP: TCryptoLibByteArray;
  400. const preCompQ, preCompNegQ: TCryptoLibGenericArray<IECPoint>;
  401. const wnafQ: TCryptoLibByteArray): IECPoint;
  402. var
  403. len, zeroes, i, wiP, wiQ, nP, nQ: Int32;
  404. Curve: IECCurve;
  405. Infinity, R, point: IECPoint;
  406. tableP, tableQ: TCryptoLibGenericArray<IECPoint>;
  407. begin
  408. len := Max(System.length(wnafP), System.length(wnafQ));
  409. Curve := preCompP[0].Curve;
  410. Infinity := Curve.Infinity;
  411. R := Infinity;
  412. zeroes := 0;
  413. i := len - 1;
  414. while (i >= 0) do
  415. begin
  416. if i < System.length(wnafP) then
  417. begin
  418. wiP := Int32(ShortInt(wnafP[i]));
  419. end
  420. else
  421. begin
  422. wiP := 0;
  423. end;
  424. if i < System.length(wnafQ) then
  425. begin
  426. wiQ := Int32(ShortInt(wnafQ[i]));
  427. end
  428. else
  429. begin
  430. wiQ := 0;
  431. end;
  432. if ((wiP or wiQ) = 0) then
  433. begin
  434. System.Inc(zeroes);
  435. System.Dec(i);
  436. continue;
  437. end;
  438. point := Infinity;
  439. if (wiP <> 0) then
  440. begin
  441. nP := System.Abs(wiP);
  442. if wiP < 0 then
  443. begin
  444. tableP := preCompNegP;
  445. end
  446. else
  447. begin
  448. tableP := preCompP;
  449. end;
  450. point := point.Add(tableP[TBits.Asr32(nP, 1)]);
  451. end;
  452. if (wiQ <> 0) then
  453. begin
  454. nQ := System.Abs(wiQ);
  455. if wiQ < 0 then
  456. begin
  457. tableQ := preCompNegQ;
  458. end
  459. else
  460. begin
  461. tableQ := preCompQ;
  462. end;
  463. point := point.Add(tableQ[TBits.Asr32(nQ, 1)]);
  464. end;
  465. if (zeroes > 0) then
  466. begin
  467. R := R.TimesPow2(zeroes);
  468. zeroes := 0;
  469. end;
  470. R := R.TwicePlus(point);
  471. System.Dec(i);
  472. end;
  473. if (zeroes > 0) then
  474. begin
  475. R := R.TimesPow2(zeroes);
  476. end;
  477. result := R;
  478. end;
  479. class function TECAlgorithms.ImplSumOfMultiplies(const endomorphism
  480. : IECEndomorphism; const ps: TCryptoLibGenericArray<IECPoint>;
  481. const ks: TCryptoLibGenericArray<TBigInteger>): IECPoint;
  482. var
  483. halfCount, fullCount: Int32;
  484. negs: TCryptoLibBooleanArray;
  485. infos: TCryptoLibGenericArray<IWNafPreCompInfo>;
  486. infoP, infoQ: IWNafPreCompInfo;
  487. wnafs: TCryptoLibMatrixByteArray;
  488. i, j0, j1, minWidth, widthP, widthQ: Int32;
  489. kj0, kj1: TBigInteger;
  490. p, q: IECPoint;
  491. pointMap: IECPointMap;
  492. begin
  493. halfCount := System.length(ps);
  494. fullCount := halfCount shl 1;
  495. System.SetLength(negs, fullCount);
  496. System.SetLength(infos, fullCount);
  497. System.SetLength(wnafs, fullCount);
  498. pointMap := endomorphism.pointMap;
  499. for i := 0 to System.Pred(halfCount) do
  500. begin
  501. j0 := i shl 1;
  502. j1 := j0 + 1;
  503. kj0 := ks[j0];
  504. negs[j0] := kj0.SignValue < 0;
  505. kj0 := kj0.Abs();
  506. kj1 := ks[j1];
  507. negs[j1] := kj1.SignValue < 0;
  508. kj1 := kj1.Abs();
  509. minWidth := TWNafUtilities.GetWindowSize
  510. (Max(kj0.BitLength, kj1.BitLength), 8);
  511. p := ps[i];
  512. infoP := TWNafUtilities.Precompute(p, minWidth, true);
  513. q := TEndoUtilities.MapPoint(endomorphism, p);
  514. infoQ := TWNafUtilities.PrecomputeWithPointMap(q, pointMap, infoP, true);
  515. widthP := Min(8, infoP.width);
  516. widthQ := Min(8, infoQ.width);
  517. infos[j0] := infoP;
  518. infos[j1] := infoQ;
  519. wnafs[j0] := TWNafUtilities.GenerateWindowNaf(widthP, kj0);
  520. wnafs[j1] := TWNafUtilities.GenerateWindowNaf(widthQ, kj1);
  521. end;
  522. result := ImplSumOfMultiplies(negs, infos, wnafs);
  523. for i := System.Low(infos) to System.High(infos) do
  524. begin
  525. infos[i].PreComp := Nil; // Review
  526. infos[i].PreCompNeg := Nil; // Review
  527. end;
  528. end;
  529. class function TECAlgorithms.ImplSumOfMultiplies
  530. (const ps: TCryptoLibGenericArray<IECPoint>;
  531. const ks: TCryptoLibGenericArray<TBigInteger>): IECPoint;
  532. var
  533. count, i, width, minWidth: Int32;
  534. negs: TCryptoLibBooleanArray;
  535. info: IWNafPreCompInfo;
  536. infos: TCryptoLibGenericArray<IWNafPreCompInfo>;
  537. wnafs: TCryptoLibMatrixByteArray;
  538. ki: TBigInteger;
  539. begin
  540. count := System.length(ps);
  541. System.SetLength(negs, count);
  542. System.SetLength(infos, count);
  543. System.SetLength(wnafs, count);
  544. for i := 0 to System.Pred(count) do
  545. begin
  546. ki := ks[i];
  547. negs[i] := ki.SignValue < 0;
  548. ki := ki.Abs();
  549. minWidth := TWNafUtilities.GetWindowSize(ki.BitLength, 8);
  550. info := TWNafUtilities.Precompute(ps[i], minWidth, true);
  551. width := Min(8, info.width);
  552. infos[i] := info;
  553. wnafs[i] := TWNafUtilities.GenerateWindowNaf(width, ki);
  554. end;
  555. result := ImplSumOfMultiplies(negs, infos, wnafs);
  556. for i := System.Low(infos) to System.High(infos) do
  557. begin
  558. infos[i].PreComp := Nil; // Review
  559. infos[i].PreCompNeg := Nil; // Review
  560. end;
  561. end;
  562. class function TECAlgorithms.ImplSumOfMultiplies
  563. (const negs: TCryptoLibBooleanArray;
  564. const infos: TCryptoLibGenericArray<IWNafPreCompInfo>;
  565. const wnafs: TCryptoLibMatrixByteArray): IECPoint;
  566. var
  567. len, count, zeroes: Int32;
  568. i, j, wi, n: Int32;
  569. Curve: IECCurve;
  570. Infinity, R, point: IECPoint;
  571. wnaf: TCryptoLibByteArray;
  572. info: IWNafPreCompInfo;
  573. table: TCryptoLibGenericArray<IECPoint>;
  574. begin
  575. len := 0;
  576. count := System.length(wnafs);
  577. for i := 0 to System.Pred(count) do
  578. begin
  579. len := Max(len, System.length(wnafs[i]));
  580. end;
  581. Curve := infos[0].PreComp[0].Curve;
  582. Infinity := Curve.Infinity;
  583. R := Infinity;
  584. zeroes := 0;
  585. i := len - 1;
  586. while (i >= 0) do
  587. begin
  588. point := Infinity;
  589. for j := 0 to System.Pred(count) do
  590. begin
  591. wnaf := wnafs[j];
  592. if i < System.length(wnaf) then
  593. begin
  594. wi := Int32(ShortInt(wnaf[i]));
  595. end
  596. else
  597. begin
  598. wi := 0;
  599. end;
  600. if (wi <> 0) then
  601. begin
  602. n := System.Abs(wi);
  603. info := infos[j];
  604. if (wi < 0 = negs[j]) then
  605. begin
  606. table := info.PreComp;
  607. end
  608. else
  609. begin
  610. table := info.PreCompNeg;
  611. end;
  612. point := point.Add(table[TBits.Asr32(n, 1)]);
  613. end;
  614. end;
  615. if (point = Infinity) then
  616. begin
  617. System.Inc(zeroes);
  618. System.Dec(i);
  619. continue;
  620. end;
  621. if (zeroes > 0) then
  622. begin
  623. R := R.TimesPow2(zeroes);
  624. zeroes := 0;
  625. end;
  626. R := R.TwicePlus(point);
  627. System.Dec(i);
  628. end;
  629. if (zeroes > 0) then
  630. begin
  631. R := R.TimesPow2(zeroes);
  632. end;
  633. result := R;
  634. end;
  635. class function TECAlgorithms.ImplSumOfMultipliesGlv
  636. (const ps: TCryptoLibGenericArray<IECPoint>;
  637. const ks: TCryptoLibGenericArray<TBigInteger>;
  638. const glvEndomorphism: IGlvEndomorphism): IECPoint;
  639. var
  640. n: TBigInteger;
  641. len, i, j: Int32;
  642. &abs, ab: TCryptoLibGenericArray<TBigInteger>;
  643. pqs: TCryptoLibGenericArray<IECPoint>;
  644. p, q: IECPoint;
  645. begin
  646. n := ps[0].Curve.Order;
  647. len := System.length(ps);
  648. System.SetLength(Abs, len shl 1);
  649. i := 0;
  650. j := 0;
  651. while (i < len) do
  652. begin
  653. ab := glvEndomorphism.DecomposeScalar(ks[i].&Mod(n));
  654. Abs[j] := ab[0];
  655. System.Inc(j);
  656. Abs[j] := ab[1];
  657. System.Inc(j);
  658. System.Inc(i);
  659. end;
  660. if (glvEndomorphism.HasEfficientPointMap) then
  661. begin
  662. result := TECAlgorithms.ImplSumOfMultiplies(glvEndomorphism, ps, Abs);
  663. Exit;
  664. end;
  665. System.SetLength(pqs, len shl 1);
  666. i := 0;
  667. j := 0;
  668. while (i < len) do
  669. begin
  670. p := ps[i];
  671. q := TEndoUtilities.MapPoint(glvEndomorphism, p);
  672. pqs[j] := p;
  673. System.Inc(j);
  674. pqs[j] := q;
  675. System.Inc(j);
  676. System.Inc(i);
  677. end;
  678. result := TECAlgorithms.ImplSumOfMultiplies(pqs, Abs);
  679. end;
  680. class function TECAlgorithms.ImportPoint(const c: IECCurve; const p: IECPoint)
  681. : IECPoint;
  682. var
  683. cp: IECCurve;
  684. begin
  685. cp := p.Curve;
  686. if (not c.Equals(cp)) then
  687. begin
  688. raise EArgumentCryptoLibException.CreateRes(@SInvalidPointLocation);
  689. end;
  690. result := c.ImportPoint(p);
  691. end;
  692. class function TECAlgorithms.IsF2mField(const field: IFiniteField): Boolean;
  693. begin
  694. result := (field.Dimension > 1) and
  695. (field.Characteristic.Equals(TBigInteger.Two)) and
  696. (Supports(field, IPolynomialExtensionField));
  697. end;
  698. class function TECAlgorithms.IsF2mCurve(const c: IECCurve): Boolean;
  699. begin
  700. result := IsF2mField(c.field);
  701. end;
  702. class function TECAlgorithms.IsFpField(const field: IFiniteField): Boolean;
  703. begin
  704. result := field.Dimension = 1;
  705. end;
  706. class function TECAlgorithms.IsFpCurve(const c: IECCurve): Boolean;
  707. begin
  708. result := IsFpField(c.field);
  709. end;
  710. class procedure TECAlgorithms.MontgomeryTrick
  711. (const zs: TCryptoLibGenericArray<IECFieldElement>; off, len: Int32;
  712. const scale: IECFieldElement);
  713. var
  714. c: TCryptoLibGenericArray<IECFieldElement>;
  715. i, j: Int32;
  716. u, tmp: IECFieldElement;
  717. begin
  718. // /*
  719. // * Uses the "Montgomery Trick" to invert many field elements, with only a single actual
  720. // * field inversion. See e.g. the paper:
  721. // * "Fast Multi-scalar Multiplication Methods on Elliptic Curves with Precomputation Strategy Using Montgomery Trick"
  722. // * by Katsuyuki Okeya, Kouichi Sakurai.
  723. // */
  724. System.SetLength(c, len);
  725. c[0] := zs[off];
  726. i := 0;
  727. System.Inc(i);
  728. while (i < len) do
  729. begin
  730. c[i] := c[i - 1].Multiply(zs[off + i]);
  731. System.Inc(i);
  732. end;
  733. System.Dec(i);
  734. if (scale <> Nil) then
  735. begin
  736. c[i] := c[i].Multiply(scale);
  737. end;
  738. u := c[i].Invert();
  739. while (i > 0) do
  740. begin
  741. j := off + i;
  742. System.Dec(i);
  743. tmp := zs[j];
  744. zs[j] := c[i].Multiply(u);
  745. u := u.Multiply(tmp);
  746. end;
  747. zs[off] := u;
  748. end;
  749. class procedure TECAlgorithms.MontgomeryTrick
  750. (const zs: TCryptoLibGenericArray<IECFieldElement>; off, len: Int32);
  751. begin
  752. MontgomeryTrick(zs, off, len, Nil);
  753. end;
  754. class function TECAlgorithms.ReferenceMultiply(const p: IECPoint;
  755. const k: TBigInteger): IECPoint;
  756. var
  757. x: TBigInteger;
  758. q, LP: IECPoint;
  759. t, i: Int32;
  760. begin
  761. LP := p;
  762. x := k.Abs();
  763. q := LP.Curve.Infinity;
  764. t := x.BitLength;
  765. if (t > 0) then
  766. begin
  767. if (x.TestBit(0)) then
  768. begin
  769. q := LP;
  770. end;
  771. i := 1;
  772. while (i < t) do
  773. begin
  774. LP := LP.Twice();
  775. if (x.TestBit(i)) then
  776. begin
  777. q := q.Add(LP);
  778. end;
  779. System.Inc(i);
  780. end;
  781. end;
  782. if k.SignValue < 0 then
  783. begin
  784. result := q.Negate();
  785. end
  786. else
  787. begin
  788. result := q;
  789. end;
  790. end;
  791. class function TECAlgorithms.ShamirsTrick(const p: IECPoint;
  792. const k: TBigInteger; const q: IECPoint; const l: TBigInteger): IECPoint;
  793. var
  794. cp: IECCurve;
  795. LQ: IECPoint;
  796. begin
  797. cp := p.Curve;
  798. LQ := q;
  799. LQ := ImportPoint(cp, LQ);
  800. result := ImplCheckResult(ImplShamirsTrickJsf(p, k, LQ, l));
  801. end;
  802. class function TECAlgorithms.SumOfMultiplies
  803. (const ps: TCryptoLibGenericArray<IECPoint>;
  804. const ks: TCryptoLibGenericArray<TBigInteger>): IECPoint;
  805. var
  806. count: Int32;
  807. p: IECPoint;
  808. c: IECCurve;
  809. i: Int32;
  810. imported: TCryptoLibGenericArray<IECPoint>;
  811. glvEndomorphism: IGlvEndomorphism;
  812. begin
  813. if ((ps = Nil) or (ks = Nil) or (System.length(ps) <> System.length(ks)) or
  814. (System.length(ps) < 1)) then
  815. begin
  816. raise EArgumentCryptoLibException.CreateRes(@SInvalidArray);
  817. end;
  818. count := System.length(ps);
  819. case count of
  820. 1:
  821. begin
  822. result := ps[0].Multiply(ks[0]);
  823. Exit;
  824. end;
  825. 2:
  826. begin
  827. result := SumOfTwoMultiplies(ps[0], ks[0], ps[1], ks[1]);
  828. Exit;
  829. end;
  830. end;
  831. p := ps[0];
  832. c := p.Curve;
  833. System.SetLength(imported, count);
  834. imported[0] := p;
  835. for i := 1 to System.Pred(count) do
  836. begin
  837. imported[i] := ImportPoint(c, ps[i]);
  838. end;
  839. if Supports(c.GetEndomorphism(), IGlvEndomorphism, glvEndomorphism) then
  840. begin
  841. result := ImplCheckResult(ImplSumOfMultipliesGlv(imported, ks,
  842. glvEndomorphism));
  843. Exit;
  844. end;
  845. result := ImplCheckResult(ImplSumOfMultiplies(imported, ks));
  846. end;
  847. class function TECAlgorithms.SumOfTwoMultiplies(const p: IECPoint;
  848. const a: TBigInteger; const q: IECPoint; const b: TBigInteger): IECPoint;
  849. var
  850. cp: IECCurve;
  851. f2mCurve: IAbstractF2mCurve;
  852. glvEndomorphism: IGlvEndomorphism;
  853. LQ: IECPoint;
  854. begin
  855. cp := p.Curve;
  856. LQ := q;
  857. LQ := ImportPoint(cp, LQ);
  858. // Point multiplication for Koblitz curves (using WTNAF) beats Shamir's trick
  859. if (Supports(cp, IAbstractF2mCurve, f2mCurve) and (f2mCurve.IsKoblitz)) then
  860. begin
  861. result := ImplCheckResult(p.Multiply(a).Add(LQ.Multiply(b)));
  862. Exit;
  863. end;
  864. if Supports(cp.GetEndomorphism(), IGlvEndomorphism, glvEndomorphism) then
  865. begin
  866. result := ImplCheckResult
  867. (ImplSumOfMultipliesGlv(TCryptoLibGenericArray<IECPoint>.Create(p, LQ),
  868. TCryptoLibGenericArray<TBigInteger>.Create(a, b), glvEndomorphism));
  869. Exit;
  870. end;
  871. result := ImplCheckResult(ImplShamirsTrickWNaf(p, a, LQ, b));
  872. end;
  873. end.