ClpMod.pas 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  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 ClpMod;
  14. {$I ..\..\Include\CryptoLib.inc}
  15. interface
  16. uses
  17. ClpCryptoLibTypes,
  18. {$IFDEF DELPHI}
  19. ClpBitConverter,
  20. {$ENDIF DELPHI}
  21. ClpNat,
  22. ClpConverters,
  23. ClpSecureRandom,
  24. ClpISecureRandom,
  25. SysUtils;
  26. resourcestring
  27. SCannotBeZero = 'cannot be 0, "x"';
  28. type
  29. TMod = class abstract(TObject)
  30. strict private
  31. class var
  32. FRandomSource: ISecureRandom;
  33. class constructor &Mod();
  34. class procedure InversionResult(p: TCryptoLibUInt32Array; ac: Int32;
  35. a: TCryptoLibUInt32Array; z: TCryptoLibUInt32Array); static; inline;
  36. class procedure InversionStep(p, u: TCryptoLibUInt32Array; uLen: Int32;
  37. x: TCryptoLibUInt32Array; var xc: Int32); static;
  38. public
  39. class procedure Invert(p, x, z: TCryptoLibUInt32Array); static;
  40. class function Random(p: TCryptoLibUInt32Array)
  41. : TCryptoLibUInt32Array; static;
  42. class procedure Add(p, x, y, z: TCryptoLibUInt32Array); static; inline;
  43. class procedure Subtract(p, x, y, z: TCryptoLibUInt32Array); static; inline;
  44. class function GetTrailingZeroes(x: UInt32): Int32; static; inline;
  45. end;
  46. implementation
  47. { TMod }
  48. class procedure TMod.Add(p, x, y, z: TCryptoLibUInt32Array);
  49. var
  50. len: Int32;
  51. c: UInt32;
  52. begin
  53. len := System.Length(p);
  54. c := TNat.Add(len, x, y, z);
  55. if (c <> 0) then
  56. begin
  57. TNat.SubFrom(len, p, z);
  58. end;
  59. end;
  60. class function TMod.GetTrailingZeroes(x: UInt32): Int32;
  61. var
  62. count: Int32;
  63. begin
  64. {$IFDEF DEBUG}
  65. System.Assert(x <> 0);
  66. {$ENDIF DEBUG}
  67. count := 0;
  68. while ((x and 1) = 0) do
  69. begin
  70. x := x shr 1;
  71. System.Inc(count);
  72. end;
  73. result := count;
  74. end;
  75. class procedure TMod.InversionResult(p: TCryptoLibUInt32Array; ac: Int32;
  76. a, z: TCryptoLibUInt32Array);
  77. begin
  78. if (ac < 0) then
  79. begin
  80. TNat.Add(System.Length(p), a, p, z);
  81. end
  82. else
  83. begin
  84. System.Move(a[0], z[0], System.Length(p) * System.SizeOf(UInt32));
  85. end;
  86. end;
  87. class procedure TMod.InversionStep(p, u: TCryptoLibUInt32Array; uLen: Int32;
  88. x: TCryptoLibUInt32Array; var xc: Int32);
  89. var
  90. len, count, zeroes, i: Int32;
  91. begin
  92. len := System.Length(p);
  93. count := 0;
  94. while (u[0] = 0) do
  95. begin
  96. TNat.ShiftDownWord(uLen, u, 0);
  97. count := count + 32;
  98. end;
  99. zeroes := GetTrailingZeroes(u[0]);
  100. if (zeroes > 0) then
  101. begin
  102. TNat.ShiftDownBits(uLen, u, zeroes, 0);
  103. count := count + zeroes;
  104. end;
  105. i := 0;
  106. while i < count do
  107. begin
  108. if ((x[0] and 1) <> 0) then
  109. begin
  110. if (xc < 0) then
  111. begin
  112. xc := xc + Int32(TNat.AddTo(len, p, x));
  113. end
  114. else
  115. begin
  116. xc := xc + (TNat.SubFrom(len, p, x));
  117. end;
  118. end;
  119. {$IFDEF DEBUG}
  120. System.Assert((xc = 0) or (xc = -1));
  121. {$ENDIF DEBUG}
  122. TNat.ShiftDownBit(len, x, UInt32(xc));
  123. System.Inc(i);
  124. end;
  125. end;
  126. class procedure TMod.Invert(p, x, z: TCryptoLibUInt32Array);
  127. var
  128. len, ac, bc, uvLen: Int32;
  129. u, a, v, b: TCryptoLibUInt32Array;
  130. begin
  131. len := System.Length(p);
  132. if (TNat.IsZero(len, x)) then
  133. begin
  134. raise EArgumentCryptoLibException.CreateRes(@SCannotBeZero);
  135. end;
  136. if (TNat.IsOne(len, x)) then
  137. begin
  138. System.Move(x[0], z[0], len * System.SizeOf(UInt32));
  139. Exit;
  140. end;
  141. u := TNat.Copy(len, x);
  142. a := TNat.Create(len);
  143. a[0] := 1;
  144. ac := 0;
  145. if ((u[0] and 1) = 0) then
  146. begin
  147. InversionStep(p, u, len, a, ac);
  148. end;
  149. if (TNat.IsOne(len, u)) then
  150. begin
  151. InversionResult(p, ac, a, z);
  152. Exit;
  153. end;
  154. v := TNat.Copy(len, p);
  155. b := TNat.Create(len);
  156. bc := 0;
  157. uvLen := len;
  158. while True do
  159. begin
  160. while ((u[uvLen - 1] = 0) and (v[uvLen - 1] = 0)) do
  161. begin
  162. System.Dec(uvLen);
  163. end;
  164. if (TNat.Gte(len, u, v)) then
  165. begin
  166. TNat.SubFrom(len, v, u);
  167. {$IFDEF DEBUG}
  168. System.Assert((u[0] and 1) = 0);
  169. {$ENDIF DEBUG}
  170. ac := ac + (TNat.SubFrom(len, b, a) - bc);
  171. InversionStep(p, u, uvLen, a, ac);
  172. if (TNat.IsOne(len, u)) then
  173. begin
  174. InversionResult(p, ac, a, z);
  175. Exit;
  176. end;
  177. end
  178. else
  179. begin
  180. TNat.SubFrom(len, u, v);
  181. {$IFDEF DEBUG}
  182. System.Assert((v[0] and 1) = 0);
  183. {$ENDIF DEBUG}
  184. bc := bc + (TNat.SubFrom(len, a, b) - ac);
  185. InversionStep(p, v, uvLen, b, bc);
  186. if (TNat.IsOne(len, v)) then
  187. begin
  188. InversionResult(p, bc, b, z);
  189. Exit;
  190. end;
  191. end;
  192. end;
  193. end;
  194. class constructor TMod.&Mod;
  195. begin
  196. TSecureRandom.Boot;
  197. FRandomSource := TSecureRandom.Create();
  198. end;
  199. class function TMod.Random(p: TCryptoLibUInt32Array): TCryptoLibUInt32Array;
  200. var
  201. len: Int32;
  202. m: UInt32;
  203. s: TCryptoLibUInt32Array;
  204. bytes: TCryptoLibByteArray;
  205. begin
  206. len := System.Length(p);
  207. s := TNat.Create(len);
  208. m := p[len - 1];
  209. m := m or (m shr 1);
  210. m := m or (m shr 2);
  211. m := m or (m shr 4);
  212. m := m or (m shr 8);
  213. m := m or (m shr 16);
  214. System.SetLength(bytes, len shl 2);
  215. repeat
  216. FRandomSource.NextBytes(bytes);
  217. TConverters.be32_copy(PByte(bytes), 0, PCardinal(s), 0, System.Length(s));
  218. s[len - 1] := s[len - 1] and m;
  219. until (not(TNat.Gte(len, s, p)));
  220. result := s;
  221. end;
  222. class procedure TMod.Subtract(p, x, y, z: TCryptoLibUInt32Array);
  223. var
  224. len, c: Int32;
  225. begin
  226. len := System.Length(p);
  227. c := TNat.Sub(len, x, y, z);
  228. if (c <> 0) then
  229. begin
  230. TNat.AddTo(len, p, z);
  231. end;
  232. end;
  233. end.