ECCurve.cs 47 KB

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