ECCurve.cs 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. using System;
  3. using System.Collections;
  4. using Org.BouncyCastle.Math.EC.Abc;
  5. using Org.BouncyCastle.Math.EC.Endo;
  6. using Org.BouncyCastle.Math.EC.Multiplier;
  7. using Org.BouncyCastle.Math.Field;
  8. using Org.BouncyCastle.Utilities;
  9. namespace Org.BouncyCastle.Math.EC
  10. {
  11. /// <remarks>Base class for an elliptic curve.</remarks>
  12. public abstract class ECCurve
  13. {
  14. public const int COORD_AFFINE = 0;
  15. public const int COORD_HOMOGENEOUS = 1;
  16. public const int COORD_JACOBIAN = 2;
  17. public const int COORD_JACOBIAN_CHUDNOVSKY = 3;
  18. public const int COORD_JACOBIAN_MODIFIED = 4;
  19. public const int COORD_LAMBDA_AFFINE = 5;
  20. public const int COORD_LAMBDA_PROJECTIVE = 6;
  21. public const int COORD_SKEWED = 7;
  22. public static int[] GetAllCoordinateSystems()
  23. {
  24. return new int[]{ COORD_AFFINE, COORD_HOMOGENEOUS, COORD_JACOBIAN, COORD_JACOBIAN_CHUDNOVSKY,
  25. COORD_JACOBIAN_MODIFIED, COORD_LAMBDA_AFFINE, COORD_LAMBDA_PROJECTIVE, COORD_SKEWED };
  26. }
  27. public class Config
  28. {
  29. protected ECCurve outer;
  30. protected int coord;
  31. protected ECEndomorphism endomorphism;
  32. protected ECMultiplier multiplier;
  33. internal Config(ECCurve outer, int coord, ECEndomorphism endomorphism, ECMultiplier multiplier)
  34. {
  35. this.outer = outer;
  36. this.coord = coord;
  37. this.endomorphism = endomorphism;
  38. this.multiplier = multiplier;
  39. }
  40. public Config SetCoordinateSystem(int coord)
  41. {
  42. this.coord = coord;
  43. return this;
  44. }
  45. public Config SetEndomorphism(ECEndomorphism endomorphism)
  46. {
  47. this.endomorphism = endomorphism;
  48. return this;
  49. }
  50. public Config SetMultiplier(ECMultiplier multiplier)
  51. {
  52. this.multiplier = multiplier;
  53. return this;
  54. }
  55. public ECCurve Create()
  56. {
  57. if (!outer.SupportsCoordinateSystem(coord))
  58. {
  59. throw new InvalidOperationException("unsupported coordinate system");
  60. }
  61. ECCurve c = outer.CloneCurve();
  62. if (c == outer)
  63. {
  64. throw new InvalidOperationException("implementation returned current curve");
  65. }
  66. c.m_coord = coord;
  67. c.m_endomorphism = endomorphism;
  68. c.m_multiplier = multiplier;
  69. return c;
  70. }
  71. }
  72. protected readonly IFiniteField m_field;
  73. protected ECFieldElement m_a, m_b;
  74. protected BigInteger m_order, m_cofactor;
  75. protected int m_coord = COORD_AFFINE;
  76. protected ECEndomorphism m_endomorphism = null;
  77. protected ECMultiplier m_multiplier = null;
  78. protected ECCurve(IFiniteField field)
  79. {
  80. this.m_field = field;
  81. }
  82. public abstract int FieldSize { get; }
  83. public abstract ECFieldElement FromBigInteger(BigInteger x);
  84. public abstract bool IsValidFieldElement(BigInteger x);
  85. public virtual Config Configure()
  86. {
  87. return new Config(this, this.m_coord, this.m_endomorphism, this.m_multiplier);
  88. }
  89. public virtual ECPoint ValidatePoint(BigInteger x, BigInteger y)
  90. {
  91. ECPoint p = CreatePoint(x, y);
  92. if (!p.IsValid())
  93. {
  94. throw new ArgumentException("Invalid point coordinates");
  95. }
  96. return p;
  97. }
  98. public virtual ECPoint ValidatePoint(BigInteger x, BigInteger y, bool withCompression)
  99. {
  100. ECPoint p = CreatePoint(x, y, withCompression);
  101. if (!p.IsValid())
  102. {
  103. throw new ArgumentException("Invalid point coordinates");
  104. }
  105. return p;
  106. }
  107. public virtual ECPoint CreatePoint(BigInteger x, BigInteger y)
  108. {
  109. return CreatePoint(x, y, false);
  110. }
  111. public virtual ECPoint CreatePoint(BigInteger x, BigInteger y, bool withCompression)
  112. {
  113. return CreateRawPoint(FromBigInteger(x), FromBigInteger(y), withCompression);
  114. }
  115. protected abstract ECCurve CloneCurve();
  116. protected internal abstract ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression);
  117. protected internal abstract ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression);
  118. protected virtual ECMultiplier CreateDefaultMultiplier()
  119. {
  120. GlvEndomorphism glvEndomorphism = m_endomorphism as GlvEndomorphism;
  121. if (glvEndomorphism != null)
  122. {
  123. return new GlvMultiplier(this, glvEndomorphism);
  124. }
  125. return new WNafL2RMultiplier();
  126. }
  127. public virtual bool SupportsCoordinateSystem(int coord)
  128. {
  129. return coord == COORD_AFFINE;
  130. }
  131. public virtual PreCompInfo GetPreCompInfo(ECPoint point, string name)
  132. {
  133. CheckPoint(point);
  134. lock (point)
  135. {
  136. IDictionary table = point.m_preCompTable;
  137. return table == null ? null : (PreCompInfo)table[name];
  138. }
  139. }
  140. /**
  141. * Adds <code>PreCompInfo</code> for a point on this curve, under a given name. Used by
  142. * <code>ECMultiplier</code>s to save the precomputation for this <code>ECPoint</code> for use
  143. * by subsequent multiplication.
  144. *
  145. * @param point
  146. * The <code>ECPoint</code> to store precomputations for.
  147. * @param name
  148. * A <code>String</code> used to index precomputations of different types.
  149. * @param preCompInfo
  150. * The values precomputed by the <code>ECMultiplier</code>.
  151. */
  152. public virtual void SetPreCompInfo(ECPoint point, string name, PreCompInfo preCompInfo)
  153. {
  154. CheckPoint(point);
  155. lock (point)
  156. {
  157. IDictionary table = point.m_preCompTable;
  158. if (null == table)
  159. {
  160. point.m_preCompTable = table = Org.BouncyCastle.Utilities.Platform.CreateHashtable(4);
  161. }
  162. table[name] = preCompInfo;
  163. }
  164. }
  165. public virtual ECPoint ImportPoint(ECPoint p)
  166. {
  167. if (this == p.Curve)
  168. {
  169. return p;
  170. }
  171. if (p.IsInfinity)
  172. {
  173. return Infinity;
  174. }
  175. // TODO Default behaviour could be improved if the two curves have the same coordinate system by copying any Z coordinates.
  176. p = p.Normalize();
  177. return ValidatePoint(p.XCoord.ToBigInteger(), p.YCoord.ToBigInteger(), p.IsCompressed);
  178. }
  179. /**
  180. * Normalization ensures that any projective coordinate is 1, and therefore that the x, y
  181. * coordinates reflect those of the equivalent point in an affine coordinate system. Where more
  182. * than one point is to be normalized, this method will generally be more efficient than
  183. * normalizing each point separately.
  184. *
  185. * @param points
  186. * An array of points that will be updated in place with their normalized versions,
  187. * where necessary
  188. */
  189. public virtual void NormalizeAll(ECPoint[] points)
  190. {
  191. NormalizeAll(points, 0, points.Length, null);
  192. }
  193. /**
  194. * Normalization ensures that any projective coordinate is 1, and therefore that the x, y
  195. * coordinates reflect those of the equivalent point in an affine coordinate system. Where more
  196. * than one point is to be normalized, this method will generally be more efficient than
  197. * normalizing each point separately. An (optional) z-scaling factor can be applied; effectively
  198. * each z coordinate is scaled by this value prior to normalization (but only one
  199. * actual multiplication is needed).
  200. *
  201. * @param points
  202. * An array of points that will be updated in place with their normalized versions,
  203. * where necessary
  204. * @param off
  205. * The start of the range of points to normalize
  206. * @param len
  207. * The length of the range of points to normalize
  208. * @param iso
  209. * The (optional) z-scaling factor - can be null
  210. */
  211. public virtual void NormalizeAll(ECPoint[] points, int off, int len, ECFieldElement iso)
  212. {
  213. CheckPoints(points, off, len);
  214. switch (this.CoordinateSystem)
  215. {
  216. case ECCurve.COORD_AFFINE:
  217. case ECCurve.COORD_LAMBDA_AFFINE:
  218. {
  219. if (iso != null)
  220. throw new ArgumentException("not valid for affine coordinates", "iso");
  221. return;
  222. }
  223. }
  224. /*
  225. * Figure out which of the points actually need to be normalized
  226. */
  227. ECFieldElement[] zs = new ECFieldElement[len];
  228. int[] indices = new int[len];
  229. int count = 0;
  230. for (int i = 0; i < len; ++i)
  231. {
  232. ECPoint p = points[off + i];
  233. if (null != p && (iso != null || !p.IsNormalized()))
  234. {
  235. zs[count] = p.GetZCoord(0);
  236. indices[count++] = off + i;
  237. }
  238. }
  239. if (count == 0)
  240. {
  241. return;
  242. }
  243. ECAlgorithms.MontgomeryTrick(zs, 0, count, iso);
  244. for (int j = 0; j < count; ++j)
  245. {
  246. int index = indices[j];
  247. points[index] = points[index].Normalize(zs[j]);
  248. }
  249. }
  250. public abstract ECPoint Infinity { get; }
  251. public virtual IFiniteField Field
  252. {
  253. get { return m_field; }
  254. }
  255. public virtual ECFieldElement A
  256. {
  257. get { return m_a; }
  258. }
  259. public virtual ECFieldElement B
  260. {
  261. get { return m_b; }
  262. }
  263. public virtual BigInteger Order
  264. {
  265. get { return m_order; }
  266. }
  267. public virtual BigInteger Cofactor
  268. {
  269. get { return m_cofactor; }
  270. }
  271. public virtual int CoordinateSystem
  272. {
  273. get { return m_coord; }
  274. }
  275. protected virtual void CheckPoint(ECPoint point)
  276. {
  277. if (null == point || (this != point.Curve))
  278. throw new ArgumentException("must be non-null and on this curve", "point");
  279. }
  280. protected virtual void CheckPoints(ECPoint[] points)
  281. {
  282. CheckPoints(points, 0, points.Length);
  283. }
  284. protected virtual void CheckPoints(ECPoint[] points, int off, int len)
  285. {
  286. if (points == null)
  287. throw new ArgumentNullException("points");
  288. if (off < 0 || len < 0 || (off > (points.Length - len)))
  289. throw new ArgumentException("invalid range specified", "points");
  290. for (int i = 0; i < len; ++i)
  291. {
  292. ECPoint point = points[off + i];
  293. if (null != point && this != point.Curve)
  294. throw new ArgumentException("entries must be null or on this curve", "points");
  295. }
  296. }
  297. public virtual bool Equals(ECCurve other)
  298. {
  299. if (this == other)
  300. return true;
  301. if (null == other)
  302. return false;
  303. return Field.Equals(other.Field)
  304. && A.ToBigInteger().Equals(other.A.ToBigInteger())
  305. && B.ToBigInteger().Equals(other.B.ToBigInteger());
  306. }
  307. public override bool Equals(object obj)
  308. {
  309. return Equals(obj as ECCurve);
  310. }
  311. public override int GetHashCode()
  312. {
  313. return Field.GetHashCode()
  314. ^ Integers.RotateLeft(A.ToBigInteger().GetHashCode(), 8)
  315. ^ Integers.RotateLeft(B.ToBigInteger().GetHashCode(), 16);
  316. }
  317. protected abstract ECPoint DecompressPoint(int yTilde, BigInteger X1);
  318. public virtual ECEndomorphism GetEndomorphism()
  319. {
  320. return m_endomorphism;
  321. }
  322. /**
  323. * Sets the default <code>ECMultiplier</code>, unless already set.
  324. */
  325. public virtual ECMultiplier GetMultiplier()
  326. {
  327. lock (this)
  328. {
  329. if (this.m_multiplier == null)
  330. {
  331. this.m_multiplier = CreateDefaultMultiplier();
  332. }
  333. return this.m_multiplier;
  334. }
  335. }
  336. /**
  337. * Decode a point on this curve from its ASN.1 encoding. The different
  338. * encodings are taken account of, including point compression for
  339. * <code>F<sub>p</sub></code> (X9.62 s 4.2.1 pg 17).
  340. * @return The decoded point.
  341. */
  342. public virtual ECPoint DecodePoint(byte[] encoded)
  343. {
  344. ECPoint p = null;
  345. int expectedLength = (FieldSize + 7) / 8;
  346. byte type = encoded[0];
  347. switch (type)
  348. {
  349. case 0x00: // infinity
  350. {
  351. if (encoded.Length != 1)
  352. throw new ArgumentException("Incorrect length for infinity encoding", "encoded");
  353. p = Infinity;
  354. break;
  355. }
  356. case 0x02: // compressed
  357. case 0x03: // compressed
  358. {
  359. if (encoded.Length != (expectedLength + 1))
  360. throw new ArgumentException("Incorrect length for compressed encoding", "encoded");
  361. int yTilde = type & 1;
  362. BigInteger X = new BigInteger(1, encoded, 1, expectedLength);
  363. p = DecompressPoint(yTilde, X);
  364. if (!p.SatisfiesCofactor())
  365. throw new ArgumentException("Invalid point");
  366. break;
  367. }
  368. case 0x04: // uncompressed
  369. {
  370. if (encoded.Length != (2 * expectedLength + 1))
  371. throw new ArgumentException("Incorrect length for uncompressed encoding", "encoded");
  372. BigInteger X = new BigInteger(1, encoded, 1, expectedLength);
  373. BigInteger Y = new BigInteger(1, encoded, 1 + expectedLength, expectedLength);
  374. p = ValidatePoint(X, Y);
  375. break;
  376. }
  377. case 0x06: // hybrid
  378. case 0x07: // hybrid
  379. {
  380. if (encoded.Length != (2 * expectedLength + 1))
  381. throw new ArgumentException("Incorrect length for hybrid encoding", "encoded");
  382. BigInteger X = new BigInteger(1, encoded, 1, expectedLength);
  383. BigInteger Y = new BigInteger(1, encoded, 1 + expectedLength, expectedLength);
  384. if (Y.TestBit(0) != (type == 0x07))
  385. throw new ArgumentException("Inconsistent Y coordinate in hybrid encoding", "encoded");
  386. p = ValidatePoint(X, Y);
  387. break;
  388. }
  389. default:
  390. throw new FormatException("Invalid point encoding " + type);
  391. }
  392. if (type != 0x00 && p.IsInfinity)
  393. throw new ArgumentException("Invalid infinity encoding", "encoded");
  394. return p;
  395. }
  396. }
  397. public abstract class AbstractFpCurve
  398. : ECCurve
  399. {
  400. protected AbstractFpCurve(BigInteger q)
  401. : base(FiniteFields.GetPrimeField(q))
  402. {
  403. }
  404. public override bool IsValidFieldElement(BigInteger x)
  405. {
  406. return x != null && x.SignValue >= 0 && x.CompareTo(Field.Characteristic) < 0;
  407. }
  408. protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
  409. {
  410. ECFieldElement x = FromBigInteger(X1);
  411. ECFieldElement rhs = x.Square().Add(A).Multiply(x).Add(B);
  412. ECFieldElement y = rhs.Sqrt();
  413. /*
  414. * If y is not a square, then we haven't got a point on the curve
  415. */
  416. if (y == null)
  417. throw new ArgumentException("Invalid point compression");
  418. if (y.TestBitZero() != (yTilde == 1))
  419. {
  420. // Use the other root
  421. y = y.Negate();
  422. }
  423. return CreateRawPoint(x, y, true);
  424. }
  425. }
  426. /**
  427. * Elliptic curve over Fp
  428. */
  429. public class FpCurve
  430. : AbstractFpCurve
  431. {
  432. private const int FP_DEFAULT_COORDS = COORD_JACOBIAN_MODIFIED;
  433. protected readonly BigInteger m_q, m_r;
  434. protected readonly FpPoint m_infinity;
  435. public FpCurve(BigInteger q, BigInteger a, BigInteger b)
  436. : this(q, a, b, null, null)
  437. {
  438. }
  439. public FpCurve(BigInteger q, BigInteger a, BigInteger b, BigInteger order, BigInteger cofactor)
  440. : base(q)
  441. {
  442. this.m_q = q;
  443. this.m_r = FpFieldElement.CalculateResidue(q);
  444. this.m_infinity = new FpPoint(this, null, null);
  445. this.m_a = FromBigInteger(a);
  446. this.m_b = FromBigInteger(b);
  447. this.m_order = order;
  448. this.m_cofactor = cofactor;
  449. this.m_coord = FP_DEFAULT_COORDS;
  450. }
  451. protected FpCurve(BigInteger q, BigInteger r, ECFieldElement a, ECFieldElement b)
  452. : this(q, r, a, b, null, null)
  453. {
  454. }
  455. protected FpCurve(BigInteger q, BigInteger r, ECFieldElement a, ECFieldElement b, BigInteger order, BigInteger cofactor)
  456. : base(q)
  457. {
  458. this.m_q = q;
  459. this.m_r = r;
  460. this.m_infinity = new FpPoint(this, null, null);
  461. this.m_a = a;
  462. this.m_b = b;
  463. this.m_order = order;
  464. this.m_cofactor = cofactor;
  465. this.m_coord = FP_DEFAULT_COORDS;
  466. }
  467. protected override ECCurve CloneCurve()
  468. {
  469. return new FpCurve(m_q, m_r, m_a, m_b, m_order, m_cofactor);
  470. }
  471. public override bool SupportsCoordinateSystem(int coord)
  472. {
  473. switch (coord)
  474. {
  475. case COORD_AFFINE:
  476. case COORD_HOMOGENEOUS:
  477. case COORD_JACOBIAN:
  478. case COORD_JACOBIAN_MODIFIED:
  479. return true;
  480. default:
  481. return false;
  482. }
  483. }
  484. public virtual BigInteger Q
  485. {
  486. get { return m_q; }
  487. }
  488. public override ECPoint Infinity
  489. {
  490. get { return m_infinity; }
  491. }
  492. public override int FieldSize
  493. {
  494. get { return m_q.BitLength; }
  495. }
  496. public override ECFieldElement FromBigInteger(BigInteger x)
  497. {
  498. return new FpFieldElement(this.m_q, this.m_r, x);
  499. }
  500. protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
  501. {
  502. return new FpPoint(this, x, y, withCompression);
  503. }
  504. protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
  505. {
  506. return new FpPoint(this, x, y, zs, withCompression);
  507. }
  508. public override ECPoint ImportPoint(ECPoint p)
  509. {
  510. if (this != p.Curve && this.CoordinateSystem == COORD_JACOBIAN && !p.IsInfinity)
  511. {
  512. switch (p.Curve.CoordinateSystem)
  513. {
  514. case COORD_JACOBIAN:
  515. case COORD_JACOBIAN_CHUDNOVSKY:
  516. case COORD_JACOBIAN_MODIFIED:
  517. return new FpPoint(this,
  518. FromBigInteger(p.RawXCoord.ToBigInteger()),
  519. FromBigInteger(p.RawYCoord.ToBigInteger()),
  520. new ECFieldElement[] { FromBigInteger(p.GetZCoord(0).ToBigInteger()) },
  521. p.IsCompressed);
  522. default:
  523. break;
  524. }
  525. }
  526. return base.ImportPoint(p);
  527. }
  528. }
  529. public abstract class AbstractF2mCurve
  530. : ECCurve
  531. {
  532. public static BigInteger Inverse(int m, int[] ks, BigInteger x)
  533. {
  534. return new LongArray(x).ModInverse(m, ks).ToBigInteger();
  535. }
  536. /**
  537. * The auxiliary values <code>s<sub>0</sub></code> and
  538. * <code>s<sub>1</sub></code> used for partial modular reduction for
  539. * Koblitz curves.
  540. */
  541. private BigInteger[] si = null;
  542. private static IFiniteField BuildField(int m, int k1, int k2, int k3)
  543. {
  544. if (k1 == 0)
  545. {
  546. throw new ArgumentException("k1 must be > 0");
  547. }
  548. if (k2 == 0)
  549. {
  550. if (k3 != 0)
  551. {
  552. throw new ArgumentException("k3 must be 0 if k2 == 0");
  553. }
  554. return FiniteFields.GetBinaryExtensionField(new int[]{ 0, k1, m });
  555. }
  556. if (k2 <= k1)
  557. {
  558. throw new ArgumentException("k2 must be > k1");
  559. }
  560. if (k3 <= k2)
  561. {
  562. throw new ArgumentException("k3 must be > k2");
  563. }
  564. return FiniteFields.GetBinaryExtensionField(new int[]{ 0, k1, k2, k3, m });
  565. }
  566. protected AbstractF2mCurve(int m, int k1, int k2, int k3)
  567. : base(BuildField(m, k1, k2, k3))
  568. {
  569. }
  570. public override bool IsValidFieldElement(BigInteger x)
  571. {
  572. return x != null && x.SignValue >= 0 && x.BitLength <= FieldSize;
  573. }
  574. public override ECPoint CreatePoint(BigInteger x, BigInteger y, bool withCompression)
  575. {
  576. ECFieldElement X = FromBigInteger(x), Y = FromBigInteger(y);
  577. switch (this.CoordinateSystem)
  578. {
  579. case COORD_LAMBDA_AFFINE:
  580. case COORD_LAMBDA_PROJECTIVE:
  581. {
  582. if (X.IsZero)
  583. {
  584. if (!Y.Square().Equals(B))
  585. throw new ArgumentException();
  586. }
  587. else
  588. {
  589. // Y becomes Lambda (X + Y/X) here
  590. Y = Y.Divide(X).Add(X);
  591. }
  592. break;
  593. }
  594. default:
  595. {
  596. break;
  597. }
  598. }
  599. return CreateRawPoint(X, Y, withCompression);
  600. }
  601. protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
  602. {
  603. ECFieldElement xp = FromBigInteger(X1), yp = null;
  604. if (xp.IsZero)
  605. {
  606. yp = B.Sqrt();
  607. }
  608. else
  609. {
  610. ECFieldElement beta = xp.Square().Invert().Multiply(B).Add(A).Add(xp);
  611. ECFieldElement z = SolveQuadradicEquation(beta);
  612. if (z != null)
  613. {
  614. if (z.TestBitZero() != (yTilde == 1))
  615. {
  616. z = z.AddOne();
  617. }
  618. switch (this.CoordinateSystem)
  619. {
  620. case COORD_LAMBDA_AFFINE:
  621. case COORD_LAMBDA_PROJECTIVE:
  622. {
  623. yp = z.Add(xp);
  624. break;
  625. }
  626. default:
  627. {
  628. yp = z.Multiply(xp);
  629. break;
  630. }
  631. }
  632. }
  633. }
  634. if (yp == null)
  635. throw new ArgumentException("Invalid point compression");
  636. return CreateRawPoint(xp, yp, true);
  637. }
  638. /**
  639. * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
  640. * D.1.6) The other solution is <code>z + 1</code>.
  641. *
  642. * @param beta
  643. * The value to solve the qradratic equation for.
  644. * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
  645. * <code>null</code> if no solution exists.
  646. */
  647. private ECFieldElement SolveQuadradicEquation(ECFieldElement beta)
  648. {
  649. if (beta.IsZero)
  650. return beta;
  651. ECFieldElement gamma, z, zeroElement = FromBigInteger(BigInteger.Zero);
  652. int m = FieldSize;
  653. do
  654. {
  655. ECFieldElement t = FromBigInteger(BigInteger.Arbitrary(m));
  656. z = zeroElement;
  657. ECFieldElement w = beta;
  658. for (int i = 1; i < m; i++)
  659. {
  660. ECFieldElement w2 = w.Square();
  661. z = z.Square().Add(w2.Multiply(t));
  662. w = w2.Add(beta);
  663. }
  664. if (!w.IsZero)
  665. {
  666. return null;
  667. }
  668. gamma = z.Square().Add(z);
  669. }
  670. while (gamma.IsZero);
  671. return z;
  672. }
  673. /**
  674. * @return the auxiliary values <code>s<sub>0</sub></code> and
  675. * <code>s<sub>1</sub></code> used for partial modular reduction for
  676. * Koblitz curves.
  677. */
  678. internal virtual BigInteger[] GetSi()
  679. {
  680. if (si == null)
  681. {
  682. lock (this)
  683. {
  684. if (si == null)
  685. {
  686. si = Tnaf.GetSi(this);
  687. }
  688. }
  689. }
  690. return si;
  691. }
  692. /**
  693. * Returns true if this is a Koblitz curve (ABC curve).
  694. * @return true if this is a Koblitz curve (ABC curve), false otherwise
  695. */
  696. public virtual bool IsKoblitz
  697. {
  698. get
  699. {
  700. return m_order != null && m_cofactor != null && m_b.IsOne && (m_a.IsZero || m_a.IsOne);
  701. }
  702. }
  703. }
  704. /**
  705. * Elliptic curves over F2m. The Weierstrass equation is given by
  706. * <code>y<sup>2</sup> + xy = x<sup>3</sup> + ax<sup>2</sup> + b</code>.
  707. */
  708. public class F2mCurve
  709. : AbstractF2mCurve
  710. {
  711. private const int F2M_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
  712. /**
  713. * The exponent <code>m</code> of <code>F<sub>2<sup>m</sup></sub></code>.
  714. */
  715. private readonly int m;
  716. /**
  717. * TPB: The integer <code>k</code> where <code>x<sup>m</sup> +
  718. * x<sup>k</sup> + 1</code> represents the reduction polynomial
  719. * <code>f(z)</code>.<br/>
  720. * PPB: The integer <code>k1</code> where <code>x<sup>m</sup> +
  721. * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
  722. * represents the reduction polynomial <code>f(z)</code>.<br/>
  723. */
  724. private readonly int k1;
  725. /**
  726. * TPB: Always set to <code>0</code><br/>
  727. * PPB: The integer <code>k2</code> where <code>x<sup>m</sup> +
  728. * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
  729. * represents the reduction polynomial <code>f(z)</code>.<br/>
  730. */
  731. private readonly int k2;
  732. /**
  733. * TPB: Always set to <code>0</code><br/>
  734. * PPB: The integer <code>k3</code> where <code>x<sup>m</sup> +
  735. * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
  736. * represents the reduction polynomial <code>f(z)</code>.<br/>
  737. */
  738. private readonly int k3;
  739. /**
  740. * The point at infinity on this curve.
  741. */
  742. protected readonly F2mPoint m_infinity;
  743. /**
  744. * Constructor for Trinomial Polynomial Basis (TPB).
  745. * @param m The exponent <code>m</code> of
  746. * <code>F<sub>2<sup>m</sup></sub></code>.
  747. * @param k The integer <code>k</code> where <code>x<sup>m</sup> +
  748. * x<sup>k</sup> + 1</code> represents the reduction
  749. * polynomial <code>f(z)</code>.
  750. * @param a The coefficient <code>a</code> in the Weierstrass equation
  751. * for non-supersingular elliptic curves over
  752. * <code>F<sub>2<sup>m</sup></sub></code>.
  753. * @param b The coefficient <code>b</code> in the Weierstrass equation
  754. * for non-supersingular elliptic curves over
  755. * <code>F<sub>2<sup>m</sup></sub></code>.
  756. */
  757. public F2mCurve(
  758. int m,
  759. int k,
  760. BigInteger a,
  761. BigInteger b)
  762. : this(m, k, 0, 0, a, b, null, null)
  763. {
  764. }
  765. /**
  766. * Constructor for Trinomial Polynomial Basis (TPB).
  767. * @param m The exponent <code>m</code> of
  768. * <code>F<sub>2<sup>m</sup></sub></code>.
  769. * @param k The integer <code>k</code> where <code>x<sup>m</sup> +
  770. * x<sup>k</sup> + 1</code> represents the reduction
  771. * polynomial <code>f(z)</code>.
  772. * @param a The coefficient <code>a</code> in the Weierstrass equation
  773. * for non-supersingular elliptic curves over
  774. * <code>F<sub>2<sup>m</sup></sub></code>.
  775. * @param b The coefficient <code>b</code> in the Weierstrass equation
  776. * for non-supersingular elliptic curves over
  777. * <code>F<sub>2<sup>m</sup></sub></code>.
  778. * @param order The order of the main subgroup of the elliptic curve.
  779. * @param cofactor The cofactor of the elliptic curve, i.e.
  780. * <code>#E<sub>a</sub>(F<sub>2<sup>m</sup></sub>) = h * n</code>.
  781. */
  782. public F2mCurve(
  783. int m,
  784. int k,
  785. BigInteger a,
  786. BigInteger b,
  787. BigInteger order,
  788. BigInteger cofactor)
  789. : this(m, k, 0, 0, a, b, order, cofactor)
  790. {
  791. }
  792. /**
  793. * Constructor for Pentanomial Polynomial Basis (PPB).
  794. * @param m The exponent <code>m</code> of
  795. * <code>F<sub>2<sup>m</sup></sub></code>.
  796. * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> +
  797. * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
  798. * represents the reduction polynomial <code>f(z)</code>.
  799. * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> +
  800. * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
  801. * represents the reduction polynomial <code>f(z)</code>.
  802. * @param k3 The integer <code>k3</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>.
  805. * @param a The coefficient <code>a</code> in the Weierstrass equation
  806. * for non-supersingular elliptic curves over
  807. * <code>F<sub>2<sup>m</sup></sub></code>.
  808. * @param b The coefficient <code>b</code> in the Weierstrass equation
  809. * for non-supersingular elliptic curves over
  810. * <code>F<sub>2<sup>m</sup></sub></code>.
  811. */
  812. public F2mCurve(
  813. int m,
  814. int k1,
  815. int k2,
  816. int k3,
  817. BigInteger a,
  818. BigInteger b)
  819. : this(m, k1, k2, k3, a, b, null, null)
  820. {
  821. }
  822. /**
  823. * Constructor for Pentanomial Polynomial Basis (PPB).
  824. * @param m The exponent <code>m</code> of
  825. * <code>F<sub>2<sup>m</sup></sub></code>.
  826. * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> +
  827. * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
  828. * represents the reduction polynomial <code>f(z)</code>.
  829. * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> +
  830. * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
  831. * represents the reduction polynomial <code>f(z)</code>.
  832. * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> +
  833. * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
  834. * represents the reduction polynomial <code>f(z)</code>.
  835. * @param a The coefficient <code>a</code> in the Weierstrass equation
  836. * for non-supersingular elliptic curves over
  837. * <code>F<sub>2<sup>m</sup></sub></code>.
  838. * @param b The coefficient <code>b</code> in the Weierstrass equation
  839. * for non-supersingular elliptic curves over
  840. * <code>F<sub>2<sup>m</sup></sub></code>.
  841. * @param order The order of the main subgroup of the elliptic curve.
  842. * @param cofactor The cofactor of the elliptic curve, i.e.
  843. * <code>#E<sub>a</sub>(F<sub>2<sup>m</sup></sub>) = h * n</code>.
  844. */
  845. public F2mCurve(
  846. int m,
  847. int k1,
  848. int k2,
  849. int k3,
  850. BigInteger a,
  851. BigInteger b,
  852. BigInteger order,
  853. BigInteger cofactor)
  854. : base(m, k1, k2, k3)
  855. {
  856. this.m = m;
  857. this.k1 = k1;
  858. this.k2 = k2;
  859. this.k3 = k3;
  860. this.m_order = order;
  861. this.m_cofactor = cofactor;
  862. this.m_infinity = new F2mPoint(this, null, null);
  863. if (k1 == 0)
  864. throw new ArgumentException("k1 must be > 0");
  865. if (k2 == 0)
  866. {
  867. if (k3 != 0)
  868. throw new ArgumentException("k3 must be 0 if k2 == 0");
  869. }
  870. else
  871. {
  872. if (k2 <= k1)
  873. throw new ArgumentException("k2 must be > k1");
  874. if (k3 <= k2)
  875. throw new ArgumentException("k3 must be > k2");
  876. }
  877. this.m_a = FromBigInteger(a);
  878. this.m_b = FromBigInteger(b);
  879. this.m_coord = F2M_DEFAULT_COORDS;
  880. }
  881. protected F2mCurve(int m, int k1, int k2, int k3, ECFieldElement a, ECFieldElement b, BigInteger order, BigInteger cofactor)
  882. : base(m, k1, k2, k3)
  883. {
  884. this.m = m;
  885. this.k1 = k1;
  886. this.k2 = k2;
  887. this.k3 = k3;
  888. this.m_order = order;
  889. this.m_cofactor = cofactor;
  890. this.m_infinity = new F2mPoint(this, null, null);
  891. this.m_a = a;
  892. this.m_b = b;
  893. this.m_coord = F2M_DEFAULT_COORDS;
  894. }
  895. protected override ECCurve CloneCurve()
  896. {
  897. return new F2mCurve(m, k1, k2, k3, m_a, m_b, m_order, m_cofactor);
  898. }
  899. public override bool SupportsCoordinateSystem(int coord)
  900. {
  901. switch (coord)
  902. {
  903. case COORD_AFFINE:
  904. case COORD_HOMOGENEOUS:
  905. case COORD_LAMBDA_PROJECTIVE:
  906. return true;
  907. default:
  908. return false;
  909. }
  910. }
  911. protected override ECMultiplier CreateDefaultMultiplier()
  912. {
  913. if (IsKoblitz)
  914. {
  915. return new WTauNafMultiplier();
  916. }
  917. return base.CreateDefaultMultiplier();
  918. }
  919. public override int FieldSize
  920. {
  921. get { return m; }
  922. }
  923. public override ECFieldElement FromBigInteger(BigInteger x)
  924. {
  925. return new F2mFieldElement(this.m, this.k1, this.k2, this.k3, x);
  926. }
  927. protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
  928. {
  929. return new F2mPoint(this, x, y, withCompression);
  930. }
  931. protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
  932. {
  933. return new F2mPoint(this, x, y, zs, withCompression);
  934. }
  935. public override ECPoint Infinity
  936. {
  937. get { return m_infinity; }
  938. }
  939. public int M
  940. {
  941. get { return m; }
  942. }
  943. /**
  944. * Return true if curve uses a Trinomial basis.
  945. *
  946. * @return true if curve Trinomial, false otherwise.
  947. */
  948. public bool IsTrinomial()
  949. {
  950. return k2 == 0 && k3 == 0;
  951. }
  952. public int K1
  953. {
  954. get { return k1; }
  955. }
  956. public int K2
  957. {
  958. get { return k2; }
  959. }
  960. public int K3
  961. {
  962. get { return k3; }
  963. }
  964. [Obsolete("Use 'Order' property instead")]
  965. public BigInteger N
  966. {
  967. get { return m_order; }
  968. }
  969. [Obsolete("Use 'Cofactor' property instead")]
  970. public BigInteger H
  971. {
  972. get { return m_cofactor; }
  973. }
  974. }
  975. }
  976. #endif