ECCurve.cs 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using System.Collections.Generic;
  5. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Math.EC.Abc;
  6. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Math.EC.Endo;
  7. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Math.EC.Multiplier;
  8. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Math.Field;
  9. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Security;
  10. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  11. namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Math.EC
  12. {
  13. /// <remarks>Base class for an elliptic curve.</remarks>
  14. public abstract class ECCurve
  15. {
  16. public const int COORD_AFFINE = 0;
  17. public const int COORD_HOMOGENEOUS = 1;
  18. public const int COORD_JACOBIAN = 2;
  19. public const int COORD_JACOBIAN_CHUDNOVSKY = 3;
  20. public const int COORD_JACOBIAN_MODIFIED = 4;
  21. public const int COORD_LAMBDA_AFFINE = 5;
  22. public const int COORD_LAMBDA_PROJECTIVE = 6;
  23. public const int COORD_SKEWED = 7;
  24. public static int[] GetAllCoordinateSystems()
  25. {
  26. return new int[]{ COORD_AFFINE, COORD_HOMOGENEOUS, COORD_JACOBIAN, COORD_JACOBIAN_CHUDNOVSKY,
  27. COORD_JACOBIAN_MODIFIED, COORD_LAMBDA_AFFINE, COORD_LAMBDA_PROJECTIVE, COORD_SKEWED };
  28. }
  29. public class Config
  30. {
  31. protected ECCurve outer;
  32. protected int coord;
  33. protected ECEndomorphism endomorphism;
  34. protected ECMultiplier multiplier;
  35. internal Config(ECCurve outer, int coord, ECEndomorphism endomorphism, ECMultiplier multiplier)
  36. {
  37. this.outer = outer;
  38. this.coord = coord;
  39. this.endomorphism = endomorphism;
  40. this.multiplier = multiplier;
  41. }
  42. public Config SetCoordinateSystem(int coord)
  43. {
  44. this.coord = coord;
  45. return this;
  46. }
  47. public Config SetEndomorphism(ECEndomorphism endomorphism)
  48. {
  49. this.endomorphism = endomorphism;
  50. return this;
  51. }
  52. public Config SetMultiplier(ECMultiplier multiplier)
  53. {
  54. this.multiplier = multiplier;
  55. return this;
  56. }
  57. public ECCurve Create()
  58. {
  59. if (!outer.SupportsCoordinateSystem(coord))
  60. {
  61. throw new InvalidOperationException("unsupported coordinate system");
  62. }
  63. ECCurve c = outer.CloneCurve();
  64. if (c == outer)
  65. {
  66. throw new InvalidOperationException("implementation returned current curve");
  67. }
  68. c.m_coord = coord;
  69. c.m_endomorphism = endomorphism;
  70. c.m_multiplier = multiplier;
  71. return c;
  72. }
  73. }
  74. protected readonly IFiniteField m_field;
  75. protected ECFieldElement m_a, m_b;
  76. protected BigInteger m_order, m_cofactor;
  77. protected int m_coord = COORD_AFFINE;
  78. protected ECEndomorphism m_endomorphism = null;
  79. protected ECMultiplier m_multiplier = null;
  80. protected ECCurve(IFiniteField field)
  81. {
  82. this.m_field = field;
  83. }
  84. public abstract int FieldSize { get; }
  85. public abstract ECFieldElement FromBigInteger(BigInteger x);
  86. public abstract bool IsValidFieldElement(BigInteger x);
  87. public abstract ECFieldElement RandomFieldElement(SecureRandom r);
  88. public abstract ECFieldElement RandomFieldElementMult(SecureRandom r);
  89. public virtual Config Configure()
  90. {
  91. return new Config(this, this.m_coord, this.m_endomorphism, this.m_multiplier);
  92. }
  93. public virtual ECPoint ValidatePoint(BigInteger x, BigInteger y)
  94. {
  95. ECPoint p = CreatePoint(x, y);
  96. if (!p.IsValid())
  97. throw new ArgumentException("Invalid point coordinates");
  98. return p;
  99. }
  100. public virtual ECPoint CreatePoint(BigInteger x, BigInteger y)
  101. {
  102. return CreateRawPoint(FromBigInteger(x), FromBigInteger(y));
  103. }
  104. protected abstract ECCurve CloneCurve();
  105. protected internal abstract ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y);
  106. protected internal abstract ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs);
  107. protected virtual ECMultiplier CreateDefaultMultiplier()
  108. {
  109. GlvEndomorphism glvEndomorphism = m_endomorphism as GlvEndomorphism;
  110. if (glvEndomorphism != null)
  111. {
  112. return new GlvMultiplier(this, glvEndomorphism);
  113. }
  114. return new WNafL2RMultiplier();
  115. }
  116. public virtual bool SupportsCoordinateSystem(int coord)
  117. {
  118. return coord == COORD_AFFINE;
  119. }
  120. public virtual PreCompInfo GetPreCompInfo(ECPoint point, string name)
  121. {
  122. CheckPoint(point);
  123. IDictionary<string, PreCompInfo> table;
  124. lock (point)
  125. {
  126. table = point.m_preCompTable;
  127. }
  128. if (null == table)
  129. return null;
  130. lock (table)
  131. {
  132. return table.TryGetValue(name, out var preCompInfo) ? preCompInfo : null;
  133. }
  134. }
  135. /**
  136. * Compute a <code>PreCompInfo</code> for a point on this curve, under a given name. Used by
  137. * <code>ECMultiplier</code>s to save the precomputation for this <code>ECPoint</code> for use
  138. * by subsequent multiplication.
  139. *
  140. * @param point
  141. * The <code>ECPoint</code> to store precomputations for.
  142. * @param name
  143. * A <code>String</code> used to index precomputations of different types.
  144. * @param callback
  145. * Called to calculate the <code>PreCompInfo</code>.
  146. */
  147. public virtual PreCompInfo Precompute(ECPoint point, string name, IPreCompCallback callback)
  148. {
  149. CheckPoint(point);
  150. IDictionary<string, PreCompInfo> table;
  151. lock (point)
  152. {
  153. table = point.m_preCompTable;
  154. if (null == table)
  155. {
  156. point.m_preCompTable = table = new Dictionary<string, PreCompInfo>();
  157. }
  158. }
  159. lock (table)
  160. {
  161. PreCompInfo existing = table.TryGetValue(name, out var preCompInfo) ? preCompInfo : null;
  162. PreCompInfo result = callback.Precompute(existing);
  163. if (result != existing)
  164. {
  165. table[name] = result;
  166. }
  167. return result;
  168. }
  169. }
  170. public virtual ECPoint ImportPoint(ECPoint p)
  171. {
  172. if (this == p.Curve)
  173. {
  174. return p;
  175. }
  176. if (p.IsInfinity)
  177. {
  178. return Infinity;
  179. }
  180. // TODO Default behaviour could be improved if the two curves have the same coordinate system by copying any Z coordinates.
  181. p = p.Normalize();
  182. return CreatePoint(p.XCoord.ToBigInteger(), p.YCoord.ToBigInteger());
  183. }
  184. /**
  185. * Normalization ensures that any projective coordinate is 1, and therefore that the x, y
  186. * coordinates reflect those of the equivalent point in an affine coordinate system. Where more
  187. * than one point is to be normalized, this method will generally be more efficient than
  188. * normalizing each point separately.
  189. *
  190. * @param points
  191. * An array of points that will be updated in place with their normalized versions,
  192. * where necessary
  193. */
  194. public virtual void NormalizeAll(ECPoint[] points)
  195. {
  196. NormalizeAll(points, 0, points.Length, null);
  197. }
  198. /**
  199. * Normalization ensures that any projective coordinate is 1, and therefore that the x, y
  200. * coordinates reflect those of the equivalent point in an affine coordinate system. Where more
  201. * than one point is to be normalized, this method will generally be more efficient than
  202. * normalizing each point separately. An (optional) z-scaling factor can be applied; effectively
  203. * each z coordinate is scaled by this value prior to normalization (but only one
  204. * actual multiplication is needed).
  205. *
  206. * @param points
  207. * An array of points that will be updated in place with their normalized versions,
  208. * where necessary
  209. * @param off
  210. * The start of the range of points to normalize
  211. * @param len
  212. * The length of the range of points to normalize
  213. * @param iso
  214. * The (optional) z-scaling factor - can be null
  215. */
  216. public virtual void NormalizeAll(ECPoint[] points, int off, int len, ECFieldElement iso)
  217. {
  218. CheckPoints(points, off, len);
  219. switch (this.CoordinateSystem)
  220. {
  221. case ECCurve.COORD_AFFINE:
  222. case ECCurve.COORD_LAMBDA_AFFINE:
  223. {
  224. if (iso != null)
  225. throw new ArgumentException("not valid for affine coordinates", "iso");
  226. return;
  227. }
  228. }
  229. /*
  230. * Figure out which of the points actually need to be normalized
  231. */
  232. ECFieldElement[] zs = new ECFieldElement[len];
  233. int[] indices = new int[len];
  234. int count = 0;
  235. for (int i = 0; i < len; ++i)
  236. {
  237. ECPoint p = points[off + i];
  238. if (null != p && (iso != null || !p.IsNormalized()))
  239. {
  240. zs[count] = p.GetZCoord(0);
  241. indices[count++] = off + i;
  242. }
  243. }
  244. if (count == 0)
  245. {
  246. return;
  247. }
  248. ECAlgorithms.MontgomeryTrick(zs, 0, count, iso);
  249. for (int j = 0; j < count; ++j)
  250. {
  251. int index = indices[j];
  252. points[index] = points[index].Normalize(zs[j]);
  253. }
  254. }
  255. public abstract ECPoint Infinity { get; }
  256. public virtual IFiniteField Field
  257. {
  258. get { return m_field; }
  259. }
  260. public virtual ECFieldElement A
  261. {
  262. get { return m_a; }
  263. }
  264. public virtual ECFieldElement B
  265. {
  266. get { return m_b; }
  267. }
  268. public virtual BigInteger Order
  269. {
  270. get { return m_order; }
  271. }
  272. public virtual BigInteger Cofactor
  273. {
  274. get { return m_cofactor; }
  275. }
  276. public virtual int CoordinateSystem
  277. {
  278. get { return m_coord; }
  279. }
  280. /**
  281. * Create a cache-safe lookup table for the specified sequence of points. All the points MUST
  282. * belong to this <code>ECCurve</code> instance, and MUST already be normalized.
  283. */
  284. public virtual ECLookupTable CreateCacheSafeLookupTable(ECPoint[] points, int off, int len)
  285. {
  286. int FE_BYTES = (FieldSize + 7) / 8;
  287. byte[] table = new byte[len * FE_BYTES * 2];
  288. {
  289. int pos = 0;
  290. for (int i = 0; i < len; ++i)
  291. {
  292. ECPoint p = points[off + i];
  293. byte[] px = p.RawXCoord.ToBigInteger().ToByteArray();
  294. byte[] py = p.RawYCoord.ToBigInteger().ToByteArray();
  295. int pxStart = px.Length > FE_BYTES ? 1 : 0, pxLen = px.Length - pxStart;
  296. int pyStart = py.Length > FE_BYTES ? 1 : 0, pyLen = py.Length - pyStart;
  297. Array.Copy(px, pxStart, table, pos + FE_BYTES - pxLen, pxLen); pos += FE_BYTES;
  298. Array.Copy(py, pyStart, table, pos + FE_BYTES - pyLen, pyLen); pos += FE_BYTES;
  299. }
  300. }
  301. return new DefaultLookupTable(this, table, len);
  302. }
  303. protected virtual void CheckPoint(ECPoint point)
  304. {
  305. if (null == point || (this != point.Curve))
  306. throw new ArgumentException("must be non-null and on this curve", "point");
  307. }
  308. protected virtual void CheckPoints(ECPoint[] points)
  309. {
  310. CheckPoints(points, 0, points.Length);
  311. }
  312. protected virtual void CheckPoints(ECPoint[] points, int off, int len)
  313. {
  314. if (points == null)
  315. throw new ArgumentNullException("points");
  316. if (off < 0 || len < 0 || (off > (points.Length - len)))
  317. throw new ArgumentException("invalid range specified", "points");
  318. for (int i = 0; i < len; ++i)
  319. {
  320. ECPoint point = points[off + i];
  321. if (null != point && this != point.Curve)
  322. throw new ArgumentException("entries must be null or on this curve", "points");
  323. }
  324. }
  325. public virtual bool Equals(ECCurve other)
  326. {
  327. if (this == other)
  328. return true;
  329. if (null == other)
  330. return false;
  331. return Field.Equals(other.Field)
  332. && A.ToBigInteger().Equals(other.A.ToBigInteger())
  333. && B.ToBigInteger().Equals(other.B.ToBigInteger());
  334. }
  335. public override bool Equals(object obj)
  336. {
  337. return Equals(obj as ECCurve);
  338. }
  339. public override int GetHashCode()
  340. {
  341. return Field.GetHashCode()
  342. ^ Integers.RotateLeft(A.ToBigInteger().GetHashCode(), 8)
  343. ^ Integers.RotateLeft(B.ToBigInteger().GetHashCode(), 16);
  344. }
  345. protected abstract ECPoint DecompressPoint(int yTilde, BigInteger X1);
  346. public virtual ECEndomorphism GetEndomorphism()
  347. {
  348. return m_endomorphism;
  349. }
  350. /**
  351. * Sets the default <code>ECMultiplier</code>, unless already set.
  352. *
  353. * We avoid locking for performance reasons, so there is no uniqueness guarantee.
  354. */
  355. public virtual ECMultiplier GetMultiplier()
  356. {
  357. if (this.m_multiplier == null)
  358. {
  359. this.m_multiplier = CreateDefaultMultiplier();
  360. }
  361. return this.m_multiplier;
  362. }
  363. /**
  364. * Decode a point on this curve from its ASN.1 encoding. The different
  365. * encodings are taken account of, including point compression for
  366. * <code>F<sub>p</sub></code> (X9.62 s 4.2.1 pg 17).
  367. * @return The decoded point.
  368. */
  369. public virtual ECPoint DecodePoint(byte[] encoded)
  370. {
  371. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  372. return DecodePoint(encoded.AsSpan());
  373. #else
  374. ECPoint p;
  375. int expectedLength = (FieldSize + 7) / 8;
  376. byte type = encoded[0];
  377. switch (type)
  378. {
  379. case 0x00: // infinity
  380. {
  381. if (encoded.Length != 1)
  382. throw new ArgumentException("Incorrect length for infinity encoding", "encoded");
  383. p = Infinity;
  384. break;
  385. }
  386. case 0x02: // compressed
  387. case 0x03: // compressed
  388. {
  389. if (encoded.Length != (expectedLength + 1))
  390. throw new ArgumentException("Incorrect length for compressed encoding", "encoded");
  391. int yTilde = type & 1;
  392. BigInteger X = new BigInteger(1, encoded, 1, expectedLength);
  393. p = DecompressPoint(yTilde, X);
  394. if (!p.ImplIsValid(true, true))
  395. throw new ArgumentException("Invalid point");
  396. break;
  397. }
  398. case 0x04: // uncompressed
  399. {
  400. if (encoded.Length != (2 * expectedLength + 1))
  401. throw new ArgumentException("Incorrect length for uncompressed encoding", "encoded");
  402. BigInteger X = new BigInteger(1, encoded, 1, expectedLength);
  403. BigInteger Y = new BigInteger(1, encoded, 1 + expectedLength, expectedLength);
  404. p = ValidatePoint(X, Y);
  405. break;
  406. }
  407. case 0x06: // hybrid
  408. case 0x07: // hybrid
  409. {
  410. if (encoded.Length != (2 * expectedLength + 1))
  411. throw new ArgumentException("Incorrect length for hybrid encoding", "encoded");
  412. BigInteger X = new BigInteger(1, encoded, 1, expectedLength);
  413. BigInteger Y = new BigInteger(1, encoded, 1 + expectedLength, expectedLength);
  414. if (Y.TestBit(0) != (type == 0x07))
  415. throw new ArgumentException("Inconsistent Y coordinate in hybrid encoding", "encoded");
  416. p = ValidatePoint(X, Y);
  417. break;
  418. }
  419. default:
  420. throw new FormatException("Invalid point encoding " + type);
  421. }
  422. if (type != 0x00 && p.IsInfinity)
  423. throw new ArgumentException("Invalid infinity encoding", "encoded");
  424. return p;
  425. #endif
  426. }
  427. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  428. public virtual ECPoint DecodePoint(ReadOnlySpan<byte> encoded)
  429. {
  430. ECPoint p;
  431. int expectedLength = (FieldSize + 7) / 8;
  432. byte type = encoded[0];
  433. switch (type)
  434. {
  435. case 0x00: // infinity
  436. {
  437. if (encoded.Length != 1)
  438. throw new ArgumentException("Incorrect length for infinity encoding", "encoded");
  439. p = Infinity;
  440. break;
  441. }
  442. case 0x02: // compressed
  443. case 0x03: // compressed
  444. {
  445. if (encoded.Length != (expectedLength + 1))
  446. throw new ArgumentException("Incorrect length for compressed encoding", "encoded");
  447. int yTilde = type & 1;
  448. BigInteger X = new BigInteger(1, encoded[1..]);
  449. p = DecompressPoint(yTilde, X);
  450. if (!p.ImplIsValid(true, true))
  451. throw new ArgumentException("Invalid point");
  452. break;
  453. }
  454. case 0x04: // uncompressed
  455. {
  456. if (encoded.Length != (2 * expectedLength + 1))
  457. throw new ArgumentException("Incorrect length for uncompressed encoding", "encoded");
  458. BigInteger X = new BigInteger(1, encoded[1..(1 + expectedLength)]);
  459. BigInteger Y = new BigInteger(1, encoded[(1 + expectedLength)..]);
  460. p = ValidatePoint(X, Y);
  461. break;
  462. }
  463. case 0x06: // hybrid
  464. case 0x07: // hybrid
  465. {
  466. if (encoded.Length != (2 * expectedLength + 1))
  467. throw new ArgumentException("Incorrect length for hybrid encoding", "encoded");
  468. BigInteger X = new BigInteger(1, encoded[1..(1 + expectedLength)]);
  469. BigInteger Y = new BigInteger(1, encoded[(1 + expectedLength)..]);
  470. if (Y.TestBit(0) != (type == 0x07))
  471. throw new ArgumentException("Inconsistent Y coordinate in hybrid encoding", "encoded");
  472. p = ValidatePoint(X, Y);
  473. break;
  474. }
  475. default:
  476. throw new FormatException("Invalid point encoding " + type);
  477. }
  478. if (type != 0x00 && p.IsInfinity)
  479. throw new ArgumentException("Invalid infinity encoding", "encoded");
  480. return p;
  481. }
  482. #endif
  483. private class DefaultLookupTable
  484. : AbstractECLookupTable
  485. {
  486. private readonly ECCurve m_outer;
  487. private readonly byte[] m_table;
  488. private readonly int m_size;
  489. internal DefaultLookupTable(ECCurve outer, byte[] table, int size)
  490. {
  491. this.m_outer = outer;
  492. this.m_table = table;
  493. this.m_size = size;
  494. }
  495. public override int Size
  496. {
  497. get { return m_size; }
  498. }
  499. public override ECPoint Lookup(int index)
  500. {
  501. int FE_BYTES = (m_outer.FieldSize + 7) / 8;
  502. byte[] x = new byte[FE_BYTES], y = new byte[FE_BYTES];
  503. int pos = 0;
  504. for (int i = 0; i < m_size; ++i)
  505. {
  506. byte MASK = (byte)(((i ^ index) - 1) >> 31);
  507. for (int j = 0; j < FE_BYTES; ++j)
  508. {
  509. x[j] ^= (byte)(m_table[pos + j] & MASK);
  510. y[j] ^= (byte)(m_table[pos + FE_BYTES + j] & MASK);
  511. }
  512. pos += (FE_BYTES * 2);
  513. }
  514. return CreatePoint(x, y);
  515. }
  516. public override ECPoint LookupVar(int index)
  517. {
  518. int FE_BYTES = (m_outer.FieldSize + 7) / 8;
  519. byte[] x = new byte[FE_BYTES], y = new byte[FE_BYTES];
  520. int pos = index * FE_BYTES * 2;
  521. for (int j = 0; j < FE_BYTES; ++j)
  522. {
  523. x[j] = m_table[pos + j];
  524. y[j] = m_table[pos + FE_BYTES + j];
  525. }
  526. return CreatePoint(x, y);
  527. }
  528. private ECPoint CreatePoint(byte[] x, byte[] y)
  529. {
  530. ECFieldElement X = m_outer.FromBigInteger(new BigInteger(1, x));
  531. ECFieldElement Y = m_outer.FromBigInteger(new BigInteger(1, y));
  532. return m_outer.CreateRawPoint(X, Y);
  533. }
  534. }
  535. }
  536. public abstract class AbstractFpCurve
  537. : ECCurve
  538. {
  539. protected AbstractFpCurve(BigInteger q)
  540. : base(FiniteFields.GetPrimeField(q))
  541. {
  542. }
  543. public override bool IsValidFieldElement(BigInteger x)
  544. {
  545. return x != null && x.SignValue >= 0 && x.CompareTo(Field.Characteristic) < 0;
  546. }
  547. public override ECFieldElement RandomFieldElement(SecureRandom r)
  548. {
  549. /*
  550. * NOTE: BigInteger comparisons in the rejection sampling are not constant-time, so we
  551. * use the product of two independent elements to mitigate side-channels.
  552. */
  553. BigInteger p = Field.Characteristic;
  554. ECFieldElement fe1 = FromBigInteger(ImplRandomFieldElement(r, p));
  555. ECFieldElement fe2 = FromBigInteger(ImplRandomFieldElement(r, p));
  556. return fe1.Multiply(fe2);
  557. }
  558. public override ECFieldElement RandomFieldElementMult(SecureRandom r)
  559. {
  560. /*
  561. * NOTE: BigInteger comparisons in the rejection sampling are not constant-time, so we
  562. * use the product of two independent elements to mitigate side-channels.
  563. */
  564. BigInteger p = Field.Characteristic;
  565. ECFieldElement fe1 = FromBigInteger(ImplRandomFieldElementMult(r, p));
  566. ECFieldElement fe2 = FromBigInteger(ImplRandomFieldElementMult(r, p));
  567. return fe1.Multiply(fe2);
  568. }
  569. protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
  570. {
  571. ECFieldElement x = FromBigInteger(X1);
  572. ECFieldElement rhs = x.Square().Add(A).Multiply(x).Add(B);
  573. ECFieldElement y = rhs.Sqrt();
  574. /*
  575. * If y is not a square, then we haven't got a point on the curve
  576. */
  577. if (y == null)
  578. throw new ArgumentException("Invalid point compression");
  579. if (y.TestBitZero() != (yTilde == 1))
  580. {
  581. // Use the other root
  582. y = y.Negate();
  583. }
  584. return CreateRawPoint(x, y);
  585. }
  586. private static BigInteger ImplRandomFieldElement(SecureRandom r, BigInteger p)
  587. {
  588. BigInteger x;
  589. do
  590. {
  591. x = BigIntegers.CreateRandomBigInteger(p.BitLength, r);
  592. }
  593. while (x.CompareTo(p) >= 0);
  594. return x;
  595. }
  596. private static BigInteger ImplRandomFieldElementMult(SecureRandom r, BigInteger p)
  597. {
  598. BigInteger x;
  599. do
  600. {
  601. x = BigIntegers.CreateRandomBigInteger(p.BitLength, r);
  602. }
  603. while (x.SignValue <= 0 || x.CompareTo(p) >= 0);
  604. return x;
  605. }
  606. }
  607. /**
  608. * Elliptic curve over Fp
  609. */
  610. public class FpCurve
  611. : AbstractFpCurve
  612. {
  613. private const int FP_DEFAULT_COORDS = COORD_JACOBIAN_MODIFIED;
  614. private static readonly HashSet<BigInteger> KnownQs = new HashSet<BigInteger>();
  615. protected readonly BigInteger m_q, m_r;
  616. protected readonly FpPoint m_infinity;
  617. public FpCurve(BigInteger q, BigInteger a, BigInteger b)
  618. : this(q, a, b, null, null)
  619. {
  620. }
  621. public FpCurve(BigInteger q, BigInteger a, BigInteger b, BigInteger order, BigInteger cofactor)
  622. : this(q, a, b, order, cofactor, false)
  623. {
  624. }
  625. internal FpCurve(BigInteger q, BigInteger a, BigInteger b, BigInteger order, BigInteger cofactor, bool isInternal)
  626. : base(q)
  627. {
  628. if (!isInternal)
  629. {
  630. bool unknownQ;
  631. lock (KnownQs) unknownQ = !KnownQs.Contains(q);
  632. if (unknownQ)
  633. {
  634. int maxBitLength = AsInteger("Best.HTTP.SecureProtocol.Org.BouncyCastle.EC.Fp_MaxSize", 1042); // 2 * 521
  635. int certainty = AsInteger("Best.HTTP.SecureProtocol.Org.BouncyCastle.EC.Fp_Certainty", 100);
  636. int qBitLength = q.BitLength;
  637. if (maxBitLength < qBitLength)
  638. throw new ArgumentException("Fp q value out of range");
  639. if (Primes.HasAnySmallFactors(q) ||
  640. !Primes.IsMRProbablePrime(q, SecureRandom.ArbitraryRandom,
  641. GetNumberOfIterations(qBitLength, certainty)))
  642. {
  643. throw new ArgumentException("Fp q value not prime");
  644. }
  645. }
  646. }
  647. lock (KnownQs) KnownQs.Add(q);
  648. this.m_q = q;
  649. this.m_r = FpFieldElement.CalculateResidue(q);
  650. this.m_infinity = new FpPoint(this, null, null);
  651. this.m_a = FromBigInteger(a);
  652. this.m_b = FromBigInteger(b);
  653. this.m_order = order;
  654. this.m_cofactor = cofactor;
  655. this.m_coord = FP_DEFAULT_COORDS;
  656. }
  657. internal FpCurve(BigInteger q, BigInteger r, ECFieldElement a, ECFieldElement b, BigInteger order,
  658. BigInteger cofactor)
  659. : base(q)
  660. {
  661. this.m_q = q;
  662. this.m_r = r;
  663. this.m_infinity = new FpPoint(this, null, null);
  664. this.m_a = a;
  665. this.m_b = b;
  666. this.m_order = order;
  667. this.m_cofactor = cofactor;
  668. this.m_coord = FP_DEFAULT_COORDS;
  669. }
  670. protected override ECCurve CloneCurve()
  671. {
  672. return new FpCurve(m_q, m_r, m_a, m_b, m_order, m_cofactor);
  673. }
  674. public override bool SupportsCoordinateSystem(int coord)
  675. {
  676. switch (coord)
  677. {
  678. case COORD_AFFINE:
  679. case COORD_HOMOGENEOUS:
  680. case COORD_JACOBIAN:
  681. case COORD_JACOBIAN_MODIFIED:
  682. return true;
  683. default:
  684. return false;
  685. }
  686. }
  687. public virtual BigInteger Q
  688. {
  689. get { return m_q; }
  690. }
  691. public override ECPoint Infinity
  692. {
  693. get { return m_infinity; }
  694. }
  695. public override int FieldSize
  696. {
  697. get { return m_q.BitLength; }
  698. }
  699. public override ECFieldElement FromBigInteger(BigInteger x)
  700. {
  701. if (x == null || x.SignValue < 0 || x.CompareTo(m_q) >= 0)
  702. throw new ArgumentException("value invalid for Fp field element", "x");
  703. return new FpFieldElement(this.m_q, this.m_r, x);
  704. }
  705. protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y)
  706. {
  707. return new FpPoint(this, x, y);
  708. }
  709. protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs)
  710. {
  711. return new FpPoint(this, x, y, zs);
  712. }
  713. public override ECPoint ImportPoint(ECPoint p)
  714. {
  715. if (this != p.Curve && this.CoordinateSystem == COORD_JACOBIAN && !p.IsInfinity)
  716. {
  717. switch (p.Curve.CoordinateSystem)
  718. {
  719. case COORD_JACOBIAN:
  720. case COORD_JACOBIAN_CHUDNOVSKY:
  721. case COORD_JACOBIAN_MODIFIED:
  722. return new FpPoint(this,
  723. FromBigInteger(p.RawXCoord.ToBigInteger()),
  724. FromBigInteger(p.RawYCoord.ToBigInteger()),
  725. new ECFieldElement[] { FromBigInteger(p.GetZCoord(0).ToBigInteger()) });
  726. default:
  727. break;
  728. }
  729. }
  730. return base.ImportPoint(p);
  731. }
  732. private int GetNumberOfIterations(int bits, int certainty)
  733. {
  734. /*
  735. * NOTE: We enforce a minimum 'certainty' of 100 for bits >= 1024 (else 80). Where the
  736. * certainty is higher than the FIPS 186-4 tables (C.2/C.3) cater to, extra iterations
  737. * are added at the "worst case rate" for the excess.
  738. */
  739. if (bits >= 1536)
  740. {
  741. return certainty <= 100 ? 3
  742. : certainty <= 128 ? 4
  743. : 4 + (certainty - 128 + 1) / 2;
  744. }
  745. else if (bits >= 1024)
  746. {
  747. return certainty <= 100 ? 4
  748. : certainty <= 112 ? 5
  749. : 5 + (certainty - 112 + 1) / 2;
  750. }
  751. else if (bits >= 512)
  752. {
  753. return certainty <= 80 ? 5
  754. : certainty <= 100 ? 7
  755. : 7 + (certainty - 100 + 1) / 2;
  756. }
  757. else
  758. {
  759. return certainty <= 80 ? 40
  760. : 40 + (certainty - 80 + 1) / 2;
  761. }
  762. }
  763. int AsInteger(string envVariable, int defaultValue)
  764. {
  765. string v = Org.BouncyCastle.Utilities.Platform.GetEnvironmentVariable(envVariable);
  766. if (v == null)
  767. {
  768. return defaultValue;
  769. }
  770. return int.Parse(v);
  771. }
  772. }
  773. public abstract class AbstractF2mCurve
  774. : ECCurve
  775. {
  776. public static BigInteger Inverse(int m, int[] ks, BigInteger x)
  777. {
  778. return new LongArray(x).ModInverse(m, ks).ToBigInteger();
  779. }
  780. /**
  781. * The auxiliary values <code>s<sub>0</sub></code> and
  782. * <code>s<sub>1</sub></code> used for partial modular reduction for
  783. * Koblitz curves.
  784. */
  785. private BigInteger[] si = null;
  786. private static IFiniteField BuildField(int m, int k1, int k2, int k3)
  787. {
  788. int[] exponents = (k2 | k3) == 0
  789. ? new int[]{ 0, k1, m }
  790. : new int[]{ 0, k1, k2, k3, m };
  791. return FiniteFields.GetBinaryExtensionField(exponents);
  792. }
  793. protected AbstractF2mCurve(int m, int k1, int k2, int k3)
  794. : base(BuildField(m, k1, k2, k3))
  795. {
  796. }
  797. public override ECPoint CreatePoint(BigInteger x, BigInteger y)
  798. {
  799. ECFieldElement X = FromBigInteger(x), Y = FromBigInteger(y);
  800. switch (this.CoordinateSystem)
  801. {
  802. case COORD_LAMBDA_AFFINE:
  803. case COORD_LAMBDA_PROJECTIVE:
  804. {
  805. if (X.IsZero)
  806. {
  807. if (!Y.Square().Equals(B))
  808. throw new ArgumentException();
  809. }
  810. else
  811. {
  812. // Y becomes Lambda (X + Y/X) here
  813. Y = Y.Divide(X).Add(X);
  814. }
  815. break;
  816. }
  817. default:
  818. {
  819. break;
  820. }
  821. }
  822. return CreateRawPoint(X, Y);
  823. }
  824. public override bool IsValidFieldElement(BigInteger x)
  825. {
  826. return x != null && x.SignValue >= 0 && x.BitLength <= FieldSize;
  827. }
  828. public override ECFieldElement RandomFieldElement(SecureRandom r)
  829. {
  830. int m = FieldSize;
  831. return FromBigInteger(BigIntegers.CreateRandomBigInteger(m, r));
  832. }
  833. public override ECFieldElement RandomFieldElementMult(SecureRandom r)
  834. {
  835. /*
  836. * NOTE: BigInteger comparisons in the rejection sampling are not constant-time, so we
  837. * use the product of two independent elements to mitigate side-channels.
  838. */
  839. int m = FieldSize;
  840. ECFieldElement fe1 = FromBigInteger(ImplRandomFieldElementMult(r, m));
  841. ECFieldElement fe2 = FromBigInteger(ImplRandomFieldElementMult(r, m));
  842. return fe1.Multiply(fe2);
  843. }
  844. protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
  845. {
  846. ECFieldElement xp = FromBigInteger(X1), yp = null;
  847. if (xp.IsZero)
  848. {
  849. yp = B.Sqrt();
  850. }
  851. else
  852. {
  853. ECFieldElement beta = xp.Square().Invert().Multiply(B).Add(A).Add(xp);
  854. ECFieldElement z = SolveQuadraticEquation(beta);
  855. if (z != null)
  856. {
  857. if (z.TestBitZero() != (yTilde == 1))
  858. {
  859. z = z.AddOne();
  860. }
  861. switch (this.CoordinateSystem)
  862. {
  863. case COORD_LAMBDA_AFFINE:
  864. case COORD_LAMBDA_PROJECTIVE:
  865. {
  866. yp = z.Add(xp);
  867. break;
  868. }
  869. default:
  870. {
  871. yp = z.Multiply(xp);
  872. break;
  873. }
  874. }
  875. }
  876. }
  877. if (yp == null)
  878. throw new ArgumentException("Invalid point compression");
  879. return CreateRawPoint(xp, yp);
  880. }
  881. /**
  882. * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
  883. * D.1.6) The other solution is <code>z + 1</code>.
  884. *
  885. * @param beta
  886. * The value to solve the quadratic equation for.
  887. * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
  888. * <code>null</code> if no solution exists.
  889. */
  890. internal ECFieldElement SolveQuadraticEquation(ECFieldElement beta)
  891. {
  892. AbstractF2mFieldElement betaF2m = (AbstractF2mFieldElement)beta;
  893. bool fastTrace = betaF2m.HasFastTrace;
  894. if (fastTrace && 0 != betaF2m.Trace())
  895. return null;
  896. int m = FieldSize;
  897. // For odd m, use the half-trace
  898. if (0 != (m & 1))
  899. {
  900. ECFieldElement r = betaF2m.HalfTrace();
  901. if (fastTrace || r.Square().Add(r).Add(beta).IsZero)
  902. return r;
  903. return null;
  904. }
  905. if (beta.IsZero)
  906. return beta;
  907. ECFieldElement gamma, z, zeroElement = FromBigInteger(BigInteger.Zero);
  908. do
  909. {
  910. ECFieldElement t = FromBigInteger(BigInteger.Arbitrary(m));
  911. z = zeroElement;
  912. ECFieldElement w = beta;
  913. for (int i = 1; i < m; i++)
  914. {
  915. ECFieldElement w2 = w.Square();
  916. z = z.Square().Add(w2.Multiply(t));
  917. w = w2.Add(beta);
  918. }
  919. if (!w.IsZero)
  920. {
  921. return null;
  922. }
  923. gamma = z.Square().Add(z);
  924. }
  925. while (gamma.IsZero);
  926. return z;
  927. }
  928. /**
  929. * @return the auxiliary values <code>s<sub>0</sub></code> and
  930. * <code>s<sub>1</sub></code> used for partial modular reduction for
  931. * Koblitz curves.
  932. */
  933. internal virtual BigInteger[] GetSi()
  934. {
  935. if (si == null)
  936. {
  937. lock (this)
  938. {
  939. if (si == null)
  940. {
  941. si = Tnaf.GetSi(this);
  942. }
  943. }
  944. }
  945. return si;
  946. }
  947. /**
  948. * Returns true if this is a Koblitz curve (ABC curve).
  949. * @return true if this is a Koblitz curve (ABC curve), false otherwise
  950. */
  951. public virtual bool IsKoblitz
  952. {
  953. get
  954. {
  955. return m_order != null && m_cofactor != null && m_b.IsOne && (m_a.IsZero || m_a.IsOne);
  956. }
  957. }
  958. private static BigInteger ImplRandomFieldElementMult(SecureRandom r, int m)
  959. {
  960. BigInteger x;
  961. do
  962. {
  963. x = BigIntegers.CreateRandomBigInteger(m, r);
  964. }
  965. while (x.SignValue <= 0);
  966. return x;
  967. }
  968. }
  969. /**
  970. * Elliptic curves over F2m. The Weierstrass equation is given by
  971. * <code>y<sup>2</sup> + xy = x<sup>3</sup> + ax<sup>2</sup> + b</code>.
  972. */
  973. public class F2mCurve
  974. : AbstractF2mCurve
  975. {
  976. private const int F2M_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
  977. /**
  978. * The exponent <code>m</code> of <code>F<sub>2<sup>m</sup></sub></code>.
  979. */
  980. private readonly int m;
  981. /**
  982. * TPB: The integer <code>k</code> where <code>x<sup>m</sup> +
  983. * x<sup>k</sup> + 1</code> represents the reduction polynomial
  984. * <code>f(z)</code>.<br/>
  985. * PPB: The integer <code>k1</code> where <code>x<sup>m</sup> +
  986. * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
  987. * represents the reduction polynomial <code>f(z)</code>.<br/>
  988. */
  989. private readonly int k1;
  990. /**
  991. * TPB: Always set to <code>0</code><br/>
  992. * PPB: The integer <code>k2</code> where <code>x<sup>m</sup> +
  993. * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
  994. * represents the reduction polynomial <code>f(z)</code>.<br/>
  995. */
  996. private readonly int k2;
  997. /**
  998. * TPB: Always set to <code>0</code><br/>
  999. * PPB: The integer <code>k3</code> where <code>x<sup>m</sup> +
  1000. * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
  1001. * represents the reduction polynomial <code>f(z)</code>.<br/>
  1002. */
  1003. private readonly int k3;
  1004. /**
  1005. * The point at infinity on this curve.
  1006. */
  1007. protected readonly F2mPoint m_infinity;
  1008. /**
  1009. * Constructor for Trinomial Polynomial Basis (TPB).
  1010. * @param m The exponent <code>m</code> of
  1011. * <code>F<sub>2<sup>m</sup></sub></code>.
  1012. * @param k The integer <code>k</code> where <code>x<sup>m</sup> +
  1013. * x<sup>k</sup> + 1</code> represents the reduction
  1014. * polynomial <code>f(z)</code>.
  1015. * @param a The coefficient <code>a</code> in the Weierstrass equation
  1016. * for non-supersingular elliptic curves over
  1017. * <code>F<sub>2<sup>m</sup></sub></code>.
  1018. * @param b The coefficient <code>b</code> in the Weierstrass equation
  1019. * for non-supersingular elliptic curves over
  1020. * <code>F<sub>2<sup>m</sup></sub></code>.
  1021. */
  1022. public F2mCurve(
  1023. int m,
  1024. int k,
  1025. BigInteger a,
  1026. BigInteger b)
  1027. : this(m, k, 0, 0, a, b, null, null)
  1028. {
  1029. }
  1030. /**
  1031. * Constructor for Trinomial Polynomial Basis (TPB).
  1032. * @param m The exponent <code>m</code> of
  1033. * <code>F<sub>2<sup>m</sup></sub></code>.
  1034. * @param k The integer <code>k</code> where <code>x<sup>m</sup> +
  1035. * x<sup>k</sup> + 1</code> represents the reduction
  1036. * polynomial <code>f(z)</code>.
  1037. * @param a The coefficient <code>a</code> in the Weierstrass equation
  1038. * for non-supersingular elliptic curves over
  1039. * <code>F<sub>2<sup>m</sup></sub></code>.
  1040. * @param b The coefficient <code>b</code> in the Weierstrass equation
  1041. * for non-supersingular elliptic curves over
  1042. * <code>F<sub>2<sup>m</sup></sub></code>.
  1043. * @param order The order of the main subgroup of the elliptic curve.
  1044. * @param cofactor The cofactor of the elliptic curve, i.e.
  1045. * <code>#E<sub>a</sub>(F<sub>2<sup>m</sup></sub>) = h * n</code>.
  1046. */
  1047. public F2mCurve(
  1048. int m,
  1049. int k,
  1050. BigInteger a,
  1051. BigInteger b,
  1052. BigInteger order,
  1053. BigInteger cofactor)
  1054. : this(m, k, 0, 0, a, b, order, cofactor)
  1055. {
  1056. }
  1057. /**
  1058. * Constructor for Pentanomial Polynomial Basis (PPB).
  1059. * @param m The exponent <code>m</code> of
  1060. * <code>F<sub>2<sup>m</sup></sub></code>.
  1061. * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> +
  1062. * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
  1063. * represents the reduction polynomial <code>f(z)</code>.
  1064. * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> +
  1065. * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
  1066. * represents the reduction polynomial <code>f(z)</code>.
  1067. * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> +
  1068. * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
  1069. * represents the reduction polynomial <code>f(z)</code>.
  1070. * @param a The coefficient <code>a</code> in the Weierstrass equation
  1071. * for non-supersingular elliptic curves over
  1072. * <code>F<sub>2<sup>m</sup></sub></code>.
  1073. * @param b The coefficient <code>b</code> in the Weierstrass equation
  1074. * for non-supersingular elliptic curves over
  1075. * <code>F<sub>2<sup>m</sup></sub></code>.
  1076. */
  1077. public F2mCurve(
  1078. int m,
  1079. int k1,
  1080. int k2,
  1081. int k3,
  1082. BigInteger a,
  1083. BigInteger b)
  1084. : this(m, k1, k2, k3, a, b, null, null)
  1085. {
  1086. }
  1087. /**
  1088. * Constructor for Pentanomial Polynomial Basis (PPB).
  1089. * @param m The exponent <code>m</code> of
  1090. * <code>F<sub>2<sup>m</sup></sub></code>.
  1091. * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> +
  1092. * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
  1093. * represents the reduction polynomial <code>f(z)</code>.
  1094. * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> +
  1095. * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
  1096. * represents the reduction polynomial <code>f(z)</code>.
  1097. * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> +
  1098. * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
  1099. * represents the reduction polynomial <code>f(z)</code>.
  1100. * @param a The coefficient <code>a</code> in the Weierstrass equation
  1101. * for non-supersingular elliptic curves over
  1102. * <code>F<sub>2<sup>m</sup></sub></code>.
  1103. * @param b The coefficient <code>b</code> in the Weierstrass equation
  1104. * for non-supersingular elliptic curves over
  1105. * <code>F<sub>2<sup>m</sup></sub></code>.
  1106. * @param order The order of the main subgroup of the elliptic curve.
  1107. * @param cofactor The cofactor of the elliptic curve, i.e.
  1108. * <code>#E<sub>a</sub>(F<sub>2<sup>m</sup></sub>) = h * n</code>.
  1109. */
  1110. public F2mCurve(int m, int k1, int k2, int k3, BigInteger a, BigInteger b, BigInteger order,
  1111. BigInteger cofactor)
  1112. : base(m, k1, k2, k3)
  1113. {
  1114. this.m = m;
  1115. this.k1 = k1;
  1116. this.k2 = k2;
  1117. this.k3 = k3;
  1118. this.m_order = order;
  1119. this.m_cofactor = cofactor;
  1120. this.m_infinity = new F2mPoint(this, null, null);
  1121. this.m_a = FromBigInteger(a);
  1122. this.m_b = FromBigInteger(b);
  1123. this.m_coord = F2M_DEFAULT_COORDS;
  1124. }
  1125. internal F2mCurve(int m, int k1, int k2, int k3, ECFieldElement a, ECFieldElement b, BigInteger order,
  1126. BigInteger cofactor)
  1127. : base(m, k1, k2, k3)
  1128. {
  1129. this.m = m;
  1130. this.k1 = k1;
  1131. this.k2 = k2;
  1132. this.k3 = k3;
  1133. this.m_order = order;
  1134. this.m_cofactor = cofactor;
  1135. this.m_infinity = new F2mPoint(this, null, null);
  1136. this.m_a = a;
  1137. this.m_b = b;
  1138. this.m_coord = F2M_DEFAULT_COORDS;
  1139. }
  1140. protected override ECCurve CloneCurve()
  1141. {
  1142. return new F2mCurve(m, k1, k2, k3, m_a, m_b, m_order, m_cofactor);
  1143. }
  1144. public override bool SupportsCoordinateSystem(int coord)
  1145. {
  1146. switch (coord)
  1147. {
  1148. case COORD_AFFINE:
  1149. case COORD_HOMOGENEOUS:
  1150. case COORD_LAMBDA_PROJECTIVE:
  1151. return true;
  1152. default:
  1153. return false;
  1154. }
  1155. }
  1156. protected override ECMultiplier CreateDefaultMultiplier()
  1157. {
  1158. if (IsKoblitz)
  1159. {
  1160. return new WTauNafMultiplier();
  1161. }
  1162. return base.CreateDefaultMultiplier();
  1163. }
  1164. public override int FieldSize
  1165. {
  1166. get { return m; }
  1167. }
  1168. public override ECFieldElement FromBigInteger(BigInteger x)
  1169. {
  1170. if (x == null || x.SignValue < 0 || x.BitLength > m)
  1171. throw new ArgumentException("value invalid for F2m field element", "x");
  1172. int[] ks = (k2 | k3) == 0
  1173. ? new int[]{ k1 }
  1174. : new int[]{ k1, k2, k3 };
  1175. return new F2mFieldElement(m, ks, new LongArray(x));
  1176. }
  1177. protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y)
  1178. {
  1179. return new F2mPoint(this, x, y);
  1180. }
  1181. protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs)
  1182. {
  1183. return new F2mPoint(this, x, y, zs);
  1184. }
  1185. public override ECPoint Infinity
  1186. {
  1187. get { return m_infinity; }
  1188. }
  1189. public int M
  1190. {
  1191. get { return m; }
  1192. }
  1193. /**
  1194. * Return true if curve uses a Trinomial basis.
  1195. *
  1196. * @return true if curve Trinomial, false otherwise.
  1197. */
  1198. public bool IsTrinomial()
  1199. {
  1200. return k2 == 0 && k3 == 0;
  1201. }
  1202. public int K1
  1203. {
  1204. get { return k1; }
  1205. }
  1206. public int K2
  1207. {
  1208. get { return k2; }
  1209. }
  1210. public int K3
  1211. {
  1212. get { return k3; }
  1213. }
  1214. public override ECLookupTable CreateCacheSafeLookupTable(ECPoint[] points, int off, int len)
  1215. {
  1216. int FE_LONGS = (m + 63) / 64;
  1217. ulong[] table = new ulong[len * FE_LONGS * 2];
  1218. {
  1219. int pos = 0;
  1220. for (int i = 0; i < len; ++i)
  1221. {
  1222. ECPoint p = points[off + i];
  1223. ((F2mFieldElement)p.RawXCoord).x.CopyTo(table, pos); pos += FE_LONGS;
  1224. ((F2mFieldElement)p.RawYCoord).x.CopyTo(table, pos); pos += FE_LONGS;
  1225. }
  1226. }
  1227. return new DefaultF2mLookupTable(this, table, len);
  1228. }
  1229. private class DefaultF2mLookupTable
  1230. : AbstractECLookupTable
  1231. {
  1232. private readonly F2mCurve m_outer;
  1233. private readonly ulong[] m_table;
  1234. private readonly int m_size;
  1235. internal DefaultF2mLookupTable(F2mCurve outer, ulong[] table, int size)
  1236. {
  1237. this.m_outer = outer;
  1238. this.m_table = table;
  1239. this.m_size = size;
  1240. }
  1241. public override int Size
  1242. {
  1243. get { return m_size; }
  1244. }
  1245. public override ECPoint Lookup(int index)
  1246. {
  1247. int FE_LONGS = (m_outer.m + 63) / 64;
  1248. ulong[] x = new ulong[FE_LONGS], y = new ulong[FE_LONGS];
  1249. int pos = 0;
  1250. for (int i = 0; i < m_size; ++i)
  1251. {
  1252. ulong MASK = (ulong)(long)(((i ^ index) - 1) >> 31);
  1253. for (int j = 0; j < FE_LONGS; ++j)
  1254. {
  1255. x[j] ^= m_table[pos + j] & MASK;
  1256. y[j] ^= m_table[pos + FE_LONGS + j] & MASK;
  1257. }
  1258. pos += (FE_LONGS * 2);
  1259. }
  1260. return CreatePoint(x, y);
  1261. }
  1262. public override ECPoint LookupVar(int index)
  1263. {
  1264. int FE_LONGS = (m_outer.m + 63) / 64;
  1265. ulong[] x = new ulong[FE_LONGS], y = new ulong[FE_LONGS];
  1266. int pos = index * FE_LONGS * 2;
  1267. for (int j = 0; j < FE_LONGS; ++j)
  1268. {
  1269. x[j] = m_table[pos + j];
  1270. y[j] = m_table[pos + FE_LONGS + j];
  1271. }
  1272. return CreatePoint(x, y);
  1273. }
  1274. private ECPoint CreatePoint(ulong[] x, ulong[] y)
  1275. {
  1276. int m = m_outer.m;
  1277. int[] ks = m_outer.IsTrinomial()
  1278. ? new int[]{ m_outer.k1 }
  1279. : new int[]{ m_outer.k1, m_outer.k2, m_outer.k3 };
  1280. ECFieldElement X = new F2mFieldElement(m, ks, new LongArray(x));
  1281. ECFieldElement Y = new F2mFieldElement(m, ks, new LongArray(y));
  1282. return m_outer.CreateRawPoint(X, Y);
  1283. }
  1284. }
  1285. }
  1286. }
  1287. #pragma warning restore
  1288. #endif