ECCurve.cs 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287
  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.Math.Raw;
  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 virtual Config Configure()
  88. {
  89. return new Config(this, this.m_coord, this.m_endomorphism, this.m_multiplier);
  90. }
  91. public virtual ECPoint ValidatePoint(BigInteger x, BigInteger y)
  92. {
  93. ECPoint p = CreatePoint(x, y);
  94. if (!p.IsValid())
  95. {
  96. throw new ArgumentException("Invalid point coordinates");
  97. }
  98. return p;
  99. }
  100. [Obsolete("Per-point compression property will be removed")]
  101. public virtual ECPoint ValidatePoint(BigInteger x, BigInteger y, bool withCompression)
  102. {
  103. ECPoint p = CreatePoint(x, y, withCompression);
  104. if (!p.IsValid())
  105. {
  106. throw new ArgumentException("Invalid point coordinates");
  107. }
  108. return p;
  109. }
  110. public virtual ECPoint CreatePoint(BigInteger x, BigInteger y)
  111. {
  112. return CreatePoint(x, y, false);
  113. }
  114. [Obsolete("Per-point compression property will be removed")]
  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. public virtual ECMultiplier GetMultiplier()
  369. {
  370. lock (this)
  371. {
  372. if (this.m_multiplier == null)
  373. {
  374. this.m_multiplier = CreateDefaultMultiplier();
  375. }
  376. return this.m_multiplier;
  377. }
  378. }
  379. /**
  380. * Decode a point on this curve from its ASN.1 encoding. The different
  381. * encodings are taken account of, including point compression for
  382. * <code>F<sub>p</sub></code> (X9.62 s 4.2.1 pg 17).
  383. * @return The decoded point.
  384. */
  385. public virtual ECPoint DecodePoint(byte[] encoded)
  386. {
  387. ECPoint p = null;
  388. int expectedLength = (FieldSize + 7) / 8;
  389. byte type = encoded[0];
  390. switch (type)
  391. {
  392. case 0x00: // infinity
  393. {
  394. if (encoded.Length != 1)
  395. throw new ArgumentException("Incorrect length for infinity encoding", "encoded");
  396. p = Infinity;
  397. break;
  398. }
  399. case 0x02: // compressed
  400. case 0x03: // compressed
  401. {
  402. if (encoded.Length != (expectedLength + 1))
  403. throw new ArgumentException("Incorrect length for compressed encoding", "encoded");
  404. int yTilde = type & 1;
  405. BigInteger X = new BigInteger(1, encoded, 1, expectedLength);
  406. p = DecompressPoint(yTilde, X);
  407. if (!p.ImplIsValid(true, true))
  408. throw new ArgumentException("Invalid point");
  409. break;
  410. }
  411. case 0x04: // uncompressed
  412. {
  413. if (encoded.Length != (2 * expectedLength + 1))
  414. throw new ArgumentException("Incorrect length for uncompressed encoding", "encoded");
  415. BigInteger X = new BigInteger(1, encoded, 1, expectedLength);
  416. BigInteger Y = new BigInteger(1, encoded, 1 + expectedLength, expectedLength);
  417. p = ValidatePoint(X, Y);
  418. break;
  419. }
  420. case 0x06: // hybrid
  421. case 0x07: // hybrid
  422. {
  423. if (encoded.Length != (2 * expectedLength + 1))
  424. throw new ArgumentException("Incorrect length for hybrid encoding", "encoded");
  425. BigInteger X = new BigInteger(1, encoded, 1, expectedLength);
  426. BigInteger Y = new BigInteger(1, encoded, 1 + expectedLength, expectedLength);
  427. if (Y.TestBit(0) != (type == 0x07))
  428. throw new ArgumentException("Inconsistent Y coordinate in hybrid encoding", "encoded");
  429. p = ValidatePoint(X, Y);
  430. break;
  431. }
  432. default:
  433. throw new FormatException("Invalid point encoding " + type);
  434. }
  435. if (type != 0x00 && p.IsInfinity)
  436. throw new ArgumentException("Invalid infinity encoding", "encoded");
  437. return p;
  438. }
  439. private class DefaultLookupTable
  440. : ECLookupTable
  441. {
  442. private readonly ECCurve m_outer;
  443. private readonly byte[] m_table;
  444. private readonly int m_size;
  445. internal DefaultLookupTable(ECCurve outer, byte[] table, int size)
  446. {
  447. this.m_outer = outer;
  448. this.m_table = table;
  449. this.m_size = size;
  450. }
  451. public virtual int Size
  452. {
  453. get { return m_size; }
  454. }
  455. public virtual ECPoint Lookup(int index)
  456. {
  457. int FE_BYTES = (m_outer.FieldSize + 7) / 8;
  458. byte[] x = new byte[FE_BYTES], y = new byte[FE_BYTES];
  459. int pos = 0;
  460. for (int i = 0; i < m_size; ++i)
  461. {
  462. byte MASK = (byte)(((i ^ index) - 1) >> 31);
  463. for (int j = 0; j < FE_BYTES; ++j)
  464. {
  465. x[j] ^= (byte)(m_table[pos + j] & MASK);
  466. y[j] ^= (byte)(m_table[pos + FE_BYTES + j] & MASK);
  467. }
  468. pos += (FE_BYTES * 2);
  469. }
  470. ECFieldElement X = m_outer.FromBigInteger(new BigInteger(1, x));
  471. ECFieldElement Y = m_outer.FromBigInteger(new BigInteger(1, y));
  472. return m_outer.CreateRawPoint(X, Y, false);
  473. }
  474. }
  475. }
  476. public abstract class AbstractFpCurve
  477. : ECCurve
  478. {
  479. protected AbstractFpCurve(BigInteger q)
  480. : base(FiniteFields.GetPrimeField(q))
  481. {
  482. }
  483. public override bool IsValidFieldElement(BigInteger x)
  484. {
  485. return x != null && x.SignValue >= 0 && x.CompareTo(Field.Characteristic) < 0;
  486. }
  487. protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
  488. {
  489. ECFieldElement x = FromBigInteger(X1);
  490. ECFieldElement rhs = x.Square().Add(A).Multiply(x).Add(B);
  491. ECFieldElement y = rhs.Sqrt();
  492. /*
  493. * If y is not a square, then we haven't got a point on the curve
  494. */
  495. if (y == null)
  496. throw new ArgumentException("Invalid point compression");
  497. if (y.TestBitZero() != (yTilde == 1))
  498. {
  499. // Use the other root
  500. y = y.Negate();
  501. }
  502. return CreateRawPoint(x, y, true);
  503. }
  504. }
  505. /**
  506. * Elliptic curve over Fp
  507. */
  508. public class FpCurve
  509. : AbstractFpCurve
  510. {
  511. private const int FP_DEFAULT_COORDS = COORD_JACOBIAN_MODIFIED;
  512. protected readonly BigInteger m_q, m_r;
  513. protected readonly FpPoint m_infinity;
  514. [Obsolete("Use constructor taking order/cofactor")]
  515. public FpCurve(BigInteger q, BigInteger a, BigInteger b)
  516. : this(q, a, b, null, null)
  517. {
  518. }
  519. public FpCurve(BigInteger q, BigInteger a, BigInteger b, BigInteger order, BigInteger cofactor)
  520. : base(q)
  521. {
  522. this.m_q = q;
  523. this.m_r = FpFieldElement.CalculateResidue(q);
  524. this.m_infinity = new FpPoint(this, null, null, false);
  525. this.m_a = FromBigInteger(a);
  526. this.m_b = FromBigInteger(b);
  527. this.m_order = order;
  528. this.m_cofactor = cofactor;
  529. this.m_coord = FP_DEFAULT_COORDS;
  530. }
  531. [Obsolete("Use constructor taking order/cofactor")]
  532. protected FpCurve(BigInteger q, BigInteger r, ECFieldElement a, ECFieldElement b)
  533. : this(q, r, a, b, null, null)
  534. {
  535. }
  536. protected FpCurve(BigInteger q, BigInteger r, ECFieldElement a, ECFieldElement b, BigInteger order, BigInteger cofactor)
  537. : base(q)
  538. {
  539. this.m_q = q;
  540. this.m_r = r;
  541. this.m_infinity = new FpPoint(this, null, null, false);
  542. this.m_a = a;
  543. this.m_b = b;
  544. this.m_order = order;
  545. this.m_cofactor = cofactor;
  546. this.m_coord = FP_DEFAULT_COORDS;
  547. }
  548. protected override ECCurve CloneCurve()
  549. {
  550. return new FpCurve(m_q, m_r, m_a, m_b, m_order, m_cofactor);
  551. }
  552. public override bool SupportsCoordinateSystem(int coord)
  553. {
  554. switch (coord)
  555. {
  556. case COORD_AFFINE:
  557. case COORD_HOMOGENEOUS:
  558. case COORD_JACOBIAN:
  559. case COORD_JACOBIAN_MODIFIED:
  560. return true;
  561. default:
  562. return false;
  563. }
  564. }
  565. public virtual BigInteger Q
  566. {
  567. get { return m_q; }
  568. }
  569. public override ECPoint Infinity
  570. {
  571. get { return m_infinity; }
  572. }
  573. public override int FieldSize
  574. {
  575. get { return m_q.BitLength; }
  576. }
  577. public override ECFieldElement FromBigInteger(BigInteger x)
  578. {
  579. return new FpFieldElement(this.m_q, this.m_r, x);
  580. }
  581. protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
  582. {
  583. return new FpPoint(this, x, y, withCompression);
  584. }
  585. protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
  586. {
  587. return new FpPoint(this, x, y, zs, withCompression);
  588. }
  589. public override ECPoint ImportPoint(ECPoint p)
  590. {
  591. if (this != p.Curve && this.CoordinateSystem == COORD_JACOBIAN && !p.IsInfinity)
  592. {
  593. switch (p.Curve.CoordinateSystem)
  594. {
  595. case COORD_JACOBIAN:
  596. case COORD_JACOBIAN_CHUDNOVSKY:
  597. case COORD_JACOBIAN_MODIFIED:
  598. return new FpPoint(this,
  599. FromBigInteger(p.RawXCoord.ToBigInteger()),
  600. FromBigInteger(p.RawYCoord.ToBigInteger()),
  601. new ECFieldElement[] { FromBigInteger(p.GetZCoord(0).ToBigInteger()) },
  602. p.IsCompressed);
  603. default:
  604. break;
  605. }
  606. }
  607. return base.ImportPoint(p);
  608. }
  609. }
  610. public abstract class AbstractF2mCurve
  611. : ECCurve
  612. {
  613. public static BigInteger Inverse(int m, int[] ks, BigInteger x)
  614. {
  615. return new LongArray(x).ModInverse(m, ks).ToBigInteger();
  616. }
  617. /**
  618. * The auxiliary values <code>s<sub>0</sub></code> and
  619. * <code>s<sub>1</sub></code> used for partial modular reduction for
  620. * Koblitz curves.
  621. */
  622. private BigInteger[] si = null;
  623. private static IFiniteField BuildField(int m, int k1, int k2, int k3)
  624. {
  625. if (k1 == 0)
  626. {
  627. throw new ArgumentException("k1 must be > 0");
  628. }
  629. if (k2 == 0)
  630. {
  631. if (k3 != 0)
  632. {
  633. throw new ArgumentException("k3 must be 0 if k2 == 0");
  634. }
  635. return FiniteFields.GetBinaryExtensionField(new int[]{ 0, k1, m });
  636. }
  637. if (k2 <= k1)
  638. {
  639. throw new ArgumentException("k2 must be > k1");
  640. }
  641. if (k3 <= k2)
  642. {
  643. throw new ArgumentException("k3 must be > k2");
  644. }
  645. return FiniteFields.GetBinaryExtensionField(new int[]{ 0, k1, k2, k3, m });
  646. }
  647. protected AbstractF2mCurve(int m, int k1, int k2, int k3)
  648. : base(BuildField(m, k1, k2, k3))
  649. {
  650. }
  651. public override bool IsValidFieldElement(BigInteger x)
  652. {
  653. return x != null && x.SignValue >= 0 && x.BitLength <= FieldSize;
  654. }
  655. [Obsolete("Per-point compression property will be removed")]
  656. public override ECPoint CreatePoint(BigInteger x, BigInteger y, bool withCompression)
  657. {
  658. ECFieldElement X = FromBigInteger(x), Y = FromBigInteger(y);
  659. switch (this.CoordinateSystem)
  660. {
  661. case COORD_LAMBDA_AFFINE:
  662. case COORD_LAMBDA_PROJECTIVE:
  663. {
  664. if (X.IsZero)
  665. {
  666. if (!Y.Square().Equals(B))
  667. throw new ArgumentException();
  668. }
  669. else
  670. {
  671. // Y becomes Lambda (X + Y/X) here
  672. Y = Y.Divide(X).Add(X);
  673. }
  674. break;
  675. }
  676. default:
  677. {
  678. break;
  679. }
  680. }
  681. return CreateRawPoint(X, Y, withCompression);
  682. }
  683. protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
  684. {
  685. ECFieldElement xp = FromBigInteger(X1), yp = null;
  686. if (xp.IsZero)
  687. {
  688. yp = B.Sqrt();
  689. }
  690. else
  691. {
  692. ECFieldElement beta = xp.Square().Invert().Multiply(B).Add(A).Add(xp);
  693. ECFieldElement z = SolveQuadraticEquation(beta);
  694. if (z != null)
  695. {
  696. if (z.TestBitZero() != (yTilde == 1))
  697. {
  698. z = z.AddOne();
  699. }
  700. switch (this.CoordinateSystem)
  701. {
  702. case COORD_LAMBDA_AFFINE:
  703. case COORD_LAMBDA_PROJECTIVE:
  704. {
  705. yp = z.Add(xp);
  706. break;
  707. }
  708. default:
  709. {
  710. yp = z.Multiply(xp);
  711. break;
  712. }
  713. }
  714. }
  715. }
  716. if (yp == null)
  717. throw new ArgumentException("Invalid point compression");
  718. return CreateRawPoint(xp, yp, true);
  719. }
  720. /**
  721. * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
  722. * D.1.6) The other solution is <code>z + 1</code>.
  723. *
  724. * @param beta
  725. * The value to solve the quadratic equation for.
  726. * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
  727. * <code>null</code> if no solution exists.
  728. */
  729. internal ECFieldElement SolveQuadraticEquation(ECFieldElement beta)
  730. {
  731. if (beta.IsZero)
  732. return beta;
  733. ECFieldElement gamma, z, zeroElement = FromBigInteger(BigInteger.Zero);
  734. int m = FieldSize;
  735. do
  736. {
  737. ECFieldElement t = FromBigInteger(BigInteger.Arbitrary(m));
  738. z = zeroElement;
  739. ECFieldElement w = beta;
  740. for (int i = 1; i < m; i++)
  741. {
  742. ECFieldElement w2 = w.Square();
  743. z = z.Square().Add(w2.Multiply(t));
  744. w = w2.Add(beta);
  745. }
  746. if (!w.IsZero)
  747. {
  748. return null;
  749. }
  750. gamma = z.Square().Add(z);
  751. }
  752. while (gamma.IsZero);
  753. return z;
  754. }
  755. /**
  756. * @return the auxiliary values <code>s<sub>0</sub></code> and
  757. * <code>s<sub>1</sub></code> used for partial modular reduction for
  758. * Koblitz curves.
  759. */
  760. internal virtual BigInteger[] GetSi()
  761. {
  762. if (si == null)
  763. {
  764. lock (this)
  765. {
  766. if (si == null)
  767. {
  768. si = Tnaf.GetSi(this);
  769. }
  770. }
  771. }
  772. return si;
  773. }
  774. /**
  775. * Returns true if this is a Koblitz curve (ABC curve).
  776. * @return true if this is a Koblitz curve (ABC curve), false otherwise
  777. */
  778. public virtual bool IsKoblitz
  779. {
  780. get
  781. {
  782. return m_order != null && m_cofactor != null && m_b.IsOne && (m_a.IsZero || m_a.IsOne);
  783. }
  784. }
  785. }
  786. /**
  787. * Elliptic curves over F2m. The Weierstrass equation is given by
  788. * <code>y<sup>2</sup> + xy = x<sup>3</sup> + ax<sup>2</sup> + b</code>.
  789. */
  790. public class F2mCurve
  791. : AbstractF2mCurve
  792. {
  793. private const int F2M_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
  794. /**
  795. * The exponent <code>m</code> of <code>F<sub>2<sup>m</sup></sub></code>.
  796. */
  797. private readonly int m;
  798. /**
  799. * TPB: The integer <code>k</code> where <code>x<sup>m</sup> +
  800. * x<sup>k</sup> + 1</code> represents the reduction polynomial
  801. * <code>f(z)</code>.<br/>
  802. * PPB: The integer <code>k1</code> where <code>x<sup>m</sup> +
  803. * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
  804. * represents the reduction polynomial <code>f(z)</code>.<br/>
  805. */
  806. private readonly int k1;
  807. /**
  808. * TPB: Always set to <code>0</code><br/>
  809. * PPB: The integer <code>k2</code> where <code>x<sup>m</sup> +
  810. * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
  811. * represents the reduction polynomial <code>f(z)</code>.<br/>
  812. */
  813. private readonly int k2;
  814. /**
  815. * TPB: Always set to <code>0</code><br/>
  816. * PPB: The integer <code>k3</code> where <code>x<sup>m</sup> +
  817. * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
  818. * represents the reduction polynomial <code>f(z)</code>.<br/>
  819. */
  820. private readonly int k3;
  821. /**
  822. * The point at infinity on this curve.
  823. */
  824. protected readonly F2mPoint m_infinity;
  825. /**
  826. * Constructor for Trinomial Polynomial Basis (TPB).
  827. * @param m The exponent <code>m</code> of
  828. * <code>F<sub>2<sup>m</sup></sub></code>.
  829. * @param k The integer <code>k</code> where <code>x<sup>m</sup> +
  830. * x<sup>k</sup> + 1</code> represents the reduction
  831. * polynomial <code>f(z)</code>.
  832. * @param a The coefficient <code>a</code> in the Weierstrass equation
  833. * for non-supersingular elliptic curves over
  834. * <code>F<sub>2<sup>m</sup></sub></code>.
  835. * @param b The coefficient <code>b</code> in the Weierstrass equation
  836. * for non-supersingular elliptic curves over
  837. * <code>F<sub>2<sup>m</sup></sub></code>.
  838. */
  839. [Obsolete("Use constructor taking order/cofactor")]
  840. public F2mCurve(
  841. int m,
  842. int k,
  843. BigInteger a,
  844. BigInteger b)
  845. : this(m, k, 0, 0, a, b, null, null)
  846. {
  847. }
  848. /**
  849. * Constructor for Trinomial Polynomial Basis (TPB).
  850. * @param m The exponent <code>m</code> of
  851. * <code>F<sub>2<sup>m</sup></sub></code>.
  852. * @param k The integer <code>k</code> where <code>x<sup>m</sup> +
  853. * x<sup>k</sup> + 1</code> represents the reduction
  854. * polynomial <code>f(z)</code>.
  855. * @param a The coefficient <code>a</code> in the Weierstrass equation
  856. * for non-supersingular elliptic curves over
  857. * <code>F<sub>2<sup>m</sup></sub></code>.
  858. * @param b The coefficient <code>b</code> in the Weierstrass equation
  859. * for non-supersingular elliptic curves over
  860. * <code>F<sub>2<sup>m</sup></sub></code>.
  861. * @param order The order of the main subgroup of the elliptic curve.
  862. * @param cofactor The cofactor of the elliptic curve, i.e.
  863. * <code>#E<sub>a</sub>(F<sub>2<sup>m</sup></sub>) = h * n</code>.
  864. */
  865. public F2mCurve(
  866. int m,
  867. int k,
  868. BigInteger a,
  869. BigInteger b,
  870. BigInteger order,
  871. BigInteger cofactor)
  872. : this(m, k, 0, 0, a, b, order, cofactor)
  873. {
  874. }
  875. /**
  876. * Constructor for Pentanomial Polynomial Basis (PPB).
  877. * @param m The exponent <code>m</code> of
  878. * <code>F<sub>2<sup>m</sup></sub></code>.
  879. * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> +
  880. * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
  881. * represents the reduction polynomial <code>f(z)</code>.
  882. * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> +
  883. * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
  884. * represents the reduction polynomial <code>f(z)</code>.
  885. * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> +
  886. * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
  887. * represents the reduction polynomial <code>f(z)</code>.
  888. * @param a The coefficient <code>a</code> in the Weierstrass equation
  889. * for non-supersingular elliptic curves over
  890. * <code>F<sub>2<sup>m</sup></sub></code>.
  891. * @param b The coefficient <code>b</code> in the Weierstrass equation
  892. * for non-supersingular elliptic curves over
  893. * <code>F<sub>2<sup>m</sup></sub></code>.
  894. */
  895. [Obsolete("Use constructor taking order/cofactor")]
  896. public F2mCurve(
  897. int m,
  898. int k1,
  899. int k2,
  900. int k3,
  901. BigInteger a,
  902. BigInteger b)
  903. : this(m, k1, k2, k3, a, b, null, null)
  904. {
  905. }
  906. /**
  907. * Constructor for Pentanomial Polynomial Basis (PPB).
  908. * @param m The exponent <code>m</code> of
  909. * <code>F<sub>2<sup>m</sup></sub></code>.
  910. * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> +
  911. * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
  912. * represents the reduction polynomial <code>f(z)</code>.
  913. * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> +
  914. * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
  915. * represents the reduction polynomial <code>f(z)</code>.
  916. * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> +
  917. * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
  918. * represents the reduction polynomial <code>f(z)</code>.
  919. * @param a The coefficient <code>a</code> in the Weierstrass equation
  920. * for non-supersingular elliptic curves over
  921. * <code>F<sub>2<sup>m</sup></sub></code>.
  922. * @param b The coefficient <code>b</code> in the Weierstrass equation
  923. * for non-supersingular elliptic curves over
  924. * <code>F<sub>2<sup>m</sup></sub></code>.
  925. * @param order The order of the main subgroup of the elliptic curve.
  926. * @param cofactor The cofactor of the elliptic curve, i.e.
  927. * <code>#E<sub>a</sub>(F<sub>2<sup>m</sup></sub>) = h * n</code>.
  928. */
  929. public F2mCurve(
  930. int m,
  931. int k1,
  932. int k2,
  933. int k3,
  934. BigInteger a,
  935. BigInteger b,
  936. BigInteger order,
  937. BigInteger cofactor)
  938. : base(m, k1, k2, k3)
  939. {
  940. this.m = m;
  941. this.k1 = k1;
  942. this.k2 = k2;
  943. this.k3 = k3;
  944. this.m_order = order;
  945. this.m_cofactor = cofactor;
  946. this.m_infinity = new F2mPoint(this, null, null, false);
  947. if (k1 == 0)
  948. throw new ArgumentException("k1 must be > 0");
  949. if (k2 == 0)
  950. {
  951. if (k3 != 0)
  952. throw new ArgumentException("k3 must be 0 if k2 == 0");
  953. }
  954. else
  955. {
  956. if (k2 <= k1)
  957. throw new ArgumentException("k2 must be > k1");
  958. if (k3 <= k2)
  959. throw new ArgumentException("k3 must be > k2");
  960. }
  961. this.m_a = FromBigInteger(a);
  962. this.m_b = FromBigInteger(b);
  963. this.m_coord = F2M_DEFAULT_COORDS;
  964. }
  965. protected F2mCurve(int m, int k1, int k2, int k3, ECFieldElement a, ECFieldElement b, BigInteger order, BigInteger cofactor)
  966. : base(m, k1, k2, k3)
  967. {
  968. this.m = m;
  969. this.k1 = k1;
  970. this.k2 = k2;
  971. this.k3 = k3;
  972. this.m_order = order;
  973. this.m_cofactor = cofactor;
  974. this.m_infinity = new F2mPoint(this, null, null, false);
  975. this.m_a = a;
  976. this.m_b = b;
  977. this.m_coord = F2M_DEFAULT_COORDS;
  978. }
  979. protected override ECCurve CloneCurve()
  980. {
  981. return new F2mCurve(m, k1, k2, k3, m_a, m_b, m_order, m_cofactor);
  982. }
  983. public override bool SupportsCoordinateSystem(int coord)
  984. {
  985. switch (coord)
  986. {
  987. case COORD_AFFINE:
  988. case COORD_HOMOGENEOUS:
  989. case COORD_LAMBDA_PROJECTIVE:
  990. return true;
  991. default:
  992. return false;
  993. }
  994. }
  995. protected override ECMultiplier CreateDefaultMultiplier()
  996. {
  997. if (IsKoblitz)
  998. {
  999. return new WTauNafMultiplier();
  1000. }
  1001. return base.CreateDefaultMultiplier();
  1002. }
  1003. public override int FieldSize
  1004. {
  1005. get { return m; }
  1006. }
  1007. public override ECFieldElement FromBigInteger(BigInteger x)
  1008. {
  1009. return new F2mFieldElement(this.m, this.k1, this.k2, this.k3, x);
  1010. }
  1011. protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
  1012. {
  1013. return new F2mPoint(this, x, y, withCompression);
  1014. }
  1015. protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
  1016. {
  1017. return new F2mPoint(this, x, y, zs, withCompression);
  1018. }
  1019. public override ECPoint Infinity
  1020. {
  1021. get { return m_infinity; }
  1022. }
  1023. public int M
  1024. {
  1025. get { return m; }
  1026. }
  1027. /**
  1028. * Return true if curve uses a Trinomial basis.
  1029. *
  1030. * @return true if curve Trinomial, false otherwise.
  1031. */
  1032. public bool IsTrinomial()
  1033. {
  1034. return k2 == 0 && k3 == 0;
  1035. }
  1036. public int K1
  1037. {
  1038. get { return k1; }
  1039. }
  1040. public int K2
  1041. {
  1042. get { return k2; }
  1043. }
  1044. public int K3
  1045. {
  1046. get { return k3; }
  1047. }
  1048. public override ECLookupTable CreateCacheSafeLookupTable(ECPoint[] points, int off, int len)
  1049. {
  1050. int FE_LONGS = (m + 63) / 64;
  1051. long[] table = new long[len * FE_LONGS * 2];
  1052. {
  1053. int pos = 0;
  1054. for (int i = 0; i < len; ++i)
  1055. {
  1056. ECPoint p = points[off + i];
  1057. ((F2mFieldElement)p.RawXCoord).x.CopyTo(table, pos); pos += FE_LONGS;
  1058. ((F2mFieldElement)p.RawYCoord).x.CopyTo(table, pos); pos += FE_LONGS;
  1059. }
  1060. }
  1061. return new DefaultF2mLookupTable(this, table, len);
  1062. }
  1063. private class DefaultF2mLookupTable
  1064. : ECLookupTable
  1065. {
  1066. private readonly F2mCurve m_outer;
  1067. private readonly long[] m_table;
  1068. private readonly int m_size;
  1069. internal DefaultF2mLookupTable(F2mCurve outer, long[] table, int size)
  1070. {
  1071. this.m_outer = outer;
  1072. this.m_table = table;
  1073. this.m_size = size;
  1074. }
  1075. public virtual int Size
  1076. {
  1077. get { return m_size; }
  1078. }
  1079. public virtual ECPoint Lookup(int index)
  1080. {
  1081. int m = m_outer.m;
  1082. int[] ks = m_outer.IsTrinomial() ? new int[]{ m_outer.k1 } : new int[]{ m_outer.k1, m_outer.k2, m_outer.k3 };
  1083. int FE_LONGS = (m_outer.m + 63) / 64;
  1084. long[] x = new long[FE_LONGS], y = new long[FE_LONGS];
  1085. int pos = 0;
  1086. for (int i = 0; i < m_size; ++i)
  1087. {
  1088. long MASK =((i ^ index) - 1) >> 31;
  1089. for (int j = 0; j < FE_LONGS; ++j)
  1090. {
  1091. x[j] ^= m_table[pos + j] & MASK;
  1092. y[j] ^= m_table[pos + FE_LONGS + j] & MASK;
  1093. }
  1094. pos += (FE_LONGS * 2);
  1095. }
  1096. ECFieldElement X = new F2mFieldElement(m, ks, new LongArray(x));
  1097. ECFieldElement Y = new F2mFieldElement(m, ks, new LongArray(y));
  1098. return m_outer.CreateRawPoint(X, Y, false);
  1099. }
  1100. }
  1101. }
  1102. }
  1103. #pragma warning restore
  1104. #endif