ECPoint.cs 72 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122
  1. using System;
  2. using System.Collections;
  3. using System.Diagnostics;
  4. using System.Text;
  5. using Renci.SshNet.Security.Org.BouncyCastle.Math.EC.Multiplier;
  6. namespace Renci.SshNet.Security.Org.BouncyCastle.Math.EC
  7. {
  8. /**
  9. * base class for points on elliptic curves.
  10. */
  11. internal abstract class ECPoint
  12. {
  13. protected static ECFieldElement[] EMPTY_ZS = new ECFieldElement[0];
  14. protected static ECFieldElement[] GetInitialZCoords(ECCurve curve)
  15. {
  16. // Cope with null curve, most commonly used by implicitlyCa
  17. int coord = null == curve ? ECCurve.COORD_AFFINE : curve.CoordinateSystem;
  18. switch (coord)
  19. {
  20. case ECCurve.COORD_AFFINE:
  21. case ECCurve.COORD_LAMBDA_AFFINE:
  22. return EMPTY_ZS;
  23. default:
  24. break;
  25. }
  26. ECFieldElement one = curve.FromBigInteger(BigInteger.One);
  27. switch (coord)
  28. {
  29. case ECCurve.COORD_HOMOGENEOUS:
  30. case ECCurve.COORD_JACOBIAN:
  31. case ECCurve.COORD_LAMBDA_PROJECTIVE:
  32. return new ECFieldElement[] { one };
  33. case ECCurve.COORD_JACOBIAN_CHUDNOVSKY:
  34. return new ECFieldElement[] { one, one, one };
  35. case ECCurve.COORD_JACOBIAN_MODIFIED:
  36. return new ECFieldElement[] { one, curve.A };
  37. default:
  38. throw new ArgumentException("unknown coordinate system");
  39. }
  40. }
  41. protected internal readonly ECCurve m_curve;
  42. protected internal readonly ECFieldElement m_x, m_y;
  43. protected internal readonly ECFieldElement[] m_zs;
  44. protected internal readonly bool m_withCompression;
  45. // Dictionary is (string -> PreCompInfo)
  46. protected internal IDictionary m_preCompTable = null;
  47. protected ECPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
  48. : this(curve, x, y, GetInitialZCoords(curve), withCompression)
  49. {
  50. }
  51. internal ECPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
  52. {
  53. this.m_curve = curve;
  54. this.m_x = x;
  55. this.m_y = y;
  56. this.m_zs = zs;
  57. this.m_withCompression = withCompression;
  58. }
  59. protected abstract bool SatisfiesCurveEquation();
  60. protected virtual bool SatisfiesOrder()
  61. {
  62. if (BigInteger.One.Equals(Curve.Cofactor))
  63. return true;
  64. BigInteger n = Curve.Order;
  65. // TODO Require order to be available for all curves
  66. return n == null || ECAlgorithms.ReferenceMultiply(this, n).IsInfinity;
  67. }
  68. public ECPoint GetDetachedPoint()
  69. {
  70. return Normalize().Detach();
  71. }
  72. public virtual ECCurve Curve
  73. {
  74. get { return m_curve; }
  75. }
  76. protected abstract ECPoint Detach();
  77. protected virtual int CurveCoordinateSystem
  78. {
  79. get
  80. {
  81. // Cope with null curve, most commonly used by implicitlyCa
  82. return null == m_curve ? ECCurve.COORD_AFFINE : m_curve.CoordinateSystem;
  83. }
  84. }
  85. /**
  86. * Returns the affine x-coordinate after checking that this point is normalized.
  87. *
  88. * @return The affine x-coordinate of this point
  89. * @throws IllegalStateException if the point is not normalized
  90. */
  91. public virtual ECFieldElement AffineXCoord
  92. {
  93. get
  94. {
  95. CheckNormalized();
  96. return XCoord;
  97. }
  98. }
  99. /**
  100. * Returns the affine y-coordinate after checking that this point is normalized
  101. *
  102. * @return The affine y-coordinate of this point
  103. * @throws IllegalStateException if the point is not normalized
  104. */
  105. public virtual ECFieldElement AffineYCoord
  106. {
  107. get
  108. {
  109. CheckNormalized();
  110. return YCoord;
  111. }
  112. }
  113. /**
  114. * Returns the x-coordinate.
  115. *
  116. * Caution: depending on the curve's coordinate system, this may not be the same value as in an
  117. * affine coordinate system; use Normalize() to get a point where the coordinates have their
  118. * affine values, or use AffineXCoord if you expect the point to already have been normalized.
  119. *
  120. * @return the x-coordinate of this point
  121. */
  122. public virtual ECFieldElement XCoord
  123. {
  124. get { return m_x; }
  125. }
  126. /**
  127. * Returns the y-coordinate.
  128. *
  129. * Caution: depending on the curve's coordinate system, this may not be the same value as in an
  130. * affine coordinate system; use Normalize() to get a point where the coordinates have their
  131. * affine values, or use AffineYCoord if you expect the point to already have been normalized.
  132. *
  133. * @return the y-coordinate of this point
  134. */
  135. public virtual ECFieldElement YCoord
  136. {
  137. get { return m_y; }
  138. }
  139. public virtual ECFieldElement GetZCoord(int index)
  140. {
  141. return (index < 0 || index >= m_zs.Length) ? null : m_zs[index];
  142. }
  143. public virtual ECFieldElement[] GetZCoords()
  144. {
  145. int zsLen = m_zs.Length;
  146. if (zsLen == 0)
  147. {
  148. return m_zs;
  149. }
  150. ECFieldElement[] copy = new ECFieldElement[zsLen];
  151. Array.Copy(m_zs, 0, copy, 0, zsLen);
  152. return copy;
  153. }
  154. protected internal ECFieldElement RawXCoord
  155. {
  156. get { return m_x; }
  157. }
  158. protected internal ECFieldElement RawYCoord
  159. {
  160. get { return m_y; }
  161. }
  162. protected internal ECFieldElement[] RawZCoords
  163. {
  164. get { return m_zs; }
  165. }
  166. protected virtual void CheckNormalized()
  167. {
  168. if (!IsNormalized())
  169. throw new InvalidOperationException("point not in normal form");
  170. }
  171. public virtual bool IsNormalized()
  172. {
  173. int coord = this.CurveCoordinateSystem;
  174. return coord == ECCurve.COORD_AFFINE
  175. || coord == ECCurve.COORD_LAMBDA_AFFINE
  176. || IsInfinity
  177. || RawZCoords[0].IsOne;
  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.
  182. *
  183. * @return a new ECPoint instance representing the same point, but with normalized coordinates
  184. */
  185. public virtual ECPoint Normalize()
  186. {
  187. if (this.IsInfinity)
  188. {
  189. return this;
  190. }
  191. switch (this.CurveCoordinateSystem)
  192. {
  193. case ECCurve.COORD_AFFINE:
  194. case ECCurve.COORD_LAMBDA_AFFINE:
  195. {
  196. return this;
  197. }
  198. default:
  199. {
  200. ECFieldElement Z1 = RawZCoords[0];
  201. if (Z1.IsOne)
  202. {
  203. return this;
  204. }
  205. return Normalize(Z1.Invert());
  206. }
  207. }
  208. }
  209. internal virtual ECPoint Normalize(ECFieldElement zInv)
  210. {
  211. switch (this.CurveCoordinateSystem)
  212. {
  213. case ECCurve.COORD_HOMOGENEOUS:
  214. case ECCurve.COORD_LAMBDA_PROJECTIVE:
  215. {
  216. return CreateScaledPoint(zInv, zInv);
  217. }
  218. case ECCurve.COORD_JACOBIAN:
  219. case ECCurve.COORD_JACOBIAN_CHUDNOVSKY:
  220. case ECCurve.COORD_JACOBIAN_MODIFIED:
  221. {
  222. ECFieldElement zInv2 = zInv.Square(), zInv3 = zInv2.Multiply(zInv);
  223. return CreateScaledPoint(zInv2, zInv3);
  224. }
  225. default:
  226. {
  227. throw new InvalidOperationException("not a projective coordinate system");
  228. }
  229. }
  230. }
  231. protected virtual ECPoint CreateScaledPoint(ECFieldElement sx, ECFieldElement sy)
  232. {
  233. return Curve.CreateRawPoint(RawXCoord.Multiply(sx), RawYCoord.Multiply(sy), IsCompressed);
  234. }
  235. public bool IsInfinity
  236. {
  237. get { return m_x == null && m_y == null; }
  238. }
  239. public bool IsCompressed
  240. {
  241. get { return m_withCompression; }
  242. }
  243. public bool IsValid()
  244. {
  245. return ImplIsValid(false, true);
  246. }
  247. internal bool IsValidPartial()
  248. {
  249. return ImplIsValid(false, false);
  250. }
  251. internal bool ImplIsValid(bool decompressed, bool checkOrder)
  252. {
  253. if (IsInfinity)
  254. return true;
  255. ValidityCallback callback = new ValidityCallback(this, decompressed, checkOrder);
  256. ValidityPreCompInfo validity = (ValidityPreCompInfo)Curve.Precompute(this, ValidityPreCompInfo.PRECOMP_NAME, callback);
  257. return !validity.HasFailed();
  258. }
  259. public virtual ECPoint ScaleX(ECFieldElement scale)
  260. {
  261. return IsInfinity
  262. ? this
  263. : Curve.CreateRawPoint(RawXCoord.Multiply(scale), RawYCoord, RawZCoords, IsCompressed);
  264. }
  265. public virtual ECPoint ScaleY(ECFieldElement scale)
  266. {
  267. return IsInfinity
  268. ? this
  269. : Curve.CreateRawPoint(RawXCoord, RawYCoord.Multiply(scale), RawZCoords, IsCompressed);
  270. }
  271. public override bool Equals(object obj)
  272. {
  273. return Equals(obj as ECPoint);
  274. }
  275. public virtual bool Equals(ECPoint other)
  276. {
  277. if (this == other)
  278. return true;
  279. if (null == other)
  280. return false;
  281. ECCurve c1 = this.Curve, c2 = other.Curve;
  282. bool n1 = (null == c1), n2 = (null == c2);
  283. bool i1 = IsInfinity, i2 = other.IsInfinity;
  284. if (i1 || i2)
  285. {
  286. return (i1 && i2) && (n1 || n2 || c1.Equals(c2));
  287. }
  288. ECPoint p1 = this, p2 = other;
  289. if (n1 && n2)
  290. {
  291. // Points with null curve are in affine form, so already normalized
  292. }
  293. else if (n1)
  294. {
  295. p2 = p2.Normalize();
  296. }
  297. else if (n2)
  298. {
  299. p1 = p1.Normalize();
  300. }
  301. else if (!c1.Equals(c2))
  302. {
  303. return false;
  304. }
  305. else
  306. {
  307. // TODO Consider just requiring already normalized, to avoid silent performance degradation
  308. ECPoint[] points = new ECPoint[] { this, c1.ImportPoint(p2) };
  309. // TODO This is a little strong, really only requires coZNormalizeAll to get Zs equal
  310. c1.NormalizeAll(points);
  311. p1 = points[0];
  312. p2 = points[1];
  313. }
  314. return p1.XCoord.Equals(p2.XCoord) && p1.YCoord.Equals(p2.YCoord);
  315. }
  316. public override int GetHashCode()
  317. {
  318. ECCurve c = this.Curve;
  319. int hc = (null == c) ? 0 : ~c.GetHashCode();
  320. if (!this.IsInfinity)
  321. {
  322. // TODO Consider just requiring already normalized, to avoid silent performance degradation
  323. ECPoint p = Normalize();
  324. hc ^= p.XCoord.GetHashCode() * 17;
  325. hc ^= p.YCoord.GetHashCode() * 257;
  326. }
  327. return hc;
  328. }
  329. public override string ToString()
  330. {
  331. if (this.IsInfinity)
  332. {
  333. return "INF";
  334. }
  335. StringBuilder sb = new StringBuilder();
  336. sb.Append('(');
  337. sb.Append(RawXCoord);
  338. sb.Append(',');
  339. sb.Append(RawYCoord);
  340. for (int i = 0; i < m_zs.Length; ++i)
  341. {
  342. sb.Append(',');
  343. sb.Append(m_zs[i]);
  344. }
  345. sb.Append(')');
  346. return sb.ToString();
  347. }
  348. public virtual byte[] GetEncoded()
  349. {
  350. return GetEncoded(m_withCompression);
  351. }
  352. public abstract byte[] GetEncoded(bool compressed);
  353. protected internal abstract bool CompressionYTilde { get; }
  354. public abstract ECPoint Add(ECPoint b);
  355. public abstract ECPoint Subtract(ECPoint b);
  356. public abstract ECPoint Negate();
  357. public virtual ECPoint TimesPow2(int e)
  358. {
  359. if (e < 0)
  360. throw new ArgumentException("cannot be negative", "e");
  361. ECPoint p = this;
  362. while (--e >= 0)
  363. {
  364. p = p.Twice();
  365. }
  366. return p;
  367. }
  368. public abstract ECPoint Twice();
  369. public abstract ECPoint Multiply(BigInteger b);
  370. public virtual ECPoint TwicePlus(ECPoint b)
  371. {
  372. return Twice().Add(b);
  373. }
  374. public virtual ECPoint ThreeTimes()
  375. {
  376. return TwicePlus(this);
  377. }
  378. private class ValidityCallback
  379. : IPreCompCallback
  380. {
  381. private readonly ECPoint m_outer;
  382. private readonly bool m_decompressed, m_checkOrder;
  383. internal ValidityCallback(ECPoint outer, bool decompressed, bool checkOrder)
  384. {
  385. this.m_outer = outer;
  386. this.m_decompressed = decompressed;
  387. this.m_checkOrder = checkOrder;
  388. }
  389. public PreCompInfo Precompute(PreCompInfo existing)
  390. {
  391. ValidityPreCompInfo info = existing as ValidityPreCompInfo;
  392. if (info == null)
  393. {
  394. info = new ValidityPreCompInfo();
  395. }
  396. if (info.HasFailed())
  397. return info;
  398. if (!info.HasCurveEquationPassed())
  399. {
  400. if (!m_decompressed && !m_outer.SatisfiesCurveEquation())
  401. {
  402. info.ReportFailed();
  403. return info;
  404. }
  405. info.ReportCurveEquationPassed();
  406. }
  407. if (m_checkOrder && !info.HasOrderPassed())
  408. {
  409. if (!m_outer.SatisfiesOrder())
  410. {
  411. info.ReportFailed();
  412. return info;
  413. }
  414. info.ReportOrderPassed();
  415. }
  416. return info;
  417. }
  418. }
  419. }
  420. internal abstract class ECPointBase
  421. : ECPoint
  422. {
  423. protected internal ECPointBase(
  424. ECCurve curve,
  425. ECFieldElement x,
  426. ECFieldElement y,
  427. bool withCompression)
  428. : base(curve, x, y, withCompression)
  429. {
  430. }
  431. protected internal ECPointBase(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
  432. : base(curve, x, y, zs, withCompression)
  433. {
  434. }
  435. /**
  436. * return the field element encoded with point compression. (S 4.3.6)
  437. */
  438. public override byte[] GetEncoded(bool compressed)
  439. {
  440. if (this.IsInfinity)
  441. {
  442. return new byte[1];
  443. }
  444. ECPoint normed = Normalize();
  445. byte[] X = normed.XCoord.GetEncoded();
  446. if (compressed)
  447. {
  448. byte[] PO = new byte[X.Length + 1];
  449. PO[0] = (byte)(normed.CompressionYTilde ? 0x03 : 0x02);
  450. Array.Copy(X, 0, PO, 1, X.Length);
  451. return PO;
  452. }
  453. byte[] Y = normed.YCoord.GetEncoded();
  454. {
  455. byte[] PO = new byte[X.Length + Y.Length + 1];
  456. PO[0] = 0x04;
  457. Array.Copy(X, 0, PO, 1, X.Length);
  458. Array.Copy(Y, 0, PO, X.Length + 1, Y.Length);
  459. return PO;
  460. }
  461. }
  462. /**
  463. * Multiplies this <code>ECPoint</code> by the given number.
  464. * @param k The multiplicator.
  465. * @return <code>k * this</code>.
  466. */
  467. public override ECPoint Multiply(BigInteger k)
  468. {
  469. return this.Curve.GetMultiplier().Multiply(this, k);
  470. }
  471. }
  472. internal abstract class AbstractFpPoint
  473. : ECPointBase
  474. {
  475. protected AbstractFpPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
  476. : base(curve, x, y, withCompression)
  477. {
  478. }
  479. protected AbstractFpPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
  480. : base(curve, x, y, zs, withCompression)
  481. {
  482. }
  483. protected internal override bool CompressionYTilde
  484. {
  485. get { return this.AffineYCoord.TestBitZero(); }
  486. }
  487. protected override bool SatisfiesCurveEquation()
  488. {
  489. ECFieldElement X = this.RawXCoord, Y = this.RawYCoord, A = Curve.A, B = Curve.B;
  490. ECFieldElement lhs = Y.Square();
  491. switch (CurveCoordinateSystem)
  492. {
  493. case ECCurve.COORD_AFFINE:
  494. break;
  495. case ECCurve.COORD_HOMOGENEOUS:
  496. {
  497. ECFieldElement Z = this.RawZCoords[0];
  498. if (!Z.IsOne)
  499. {
  500. ECFieldElement Z2 = Z.Square(), Z3 = Z.Multiply(Z2);
  501. lhs = lhs.Multiply(Z);
  502. A = A.Multiply(Z2);
  503. B = B.Multiply(Z3);
  504. }
  505. break;
  506. }
  507. case ECCurve.COORD_JACOBIAN:
  508. case ECCurve.COORD_JACOBIAN_CHUDNOVSKY:
  509. case ECCurve.COORD_JACOBIAN_MODIFIED:
  510. {
  511. ECFieldElement Z = this.RawZCoords[0];
  512. if (!Z.IsOne)
  513. {
  514. ECFieldElement Z2 = Z.Square(), Z4 = Z2.Square(), Z6 = Z2.Multiply(Z4);
  515. A = A.Multiply(Z4);
  516. B = B.Multiply(Z6);
  517. }
  518. break;
  519. }
  520. default:
  521. throw new InvalidOperationException("unsupported coordinate system");
  522. }
  523. ECFieldElement rhs = X.Square().Add(A).Multiply(X).Add(B);
  524. return lhs.Equals(rhs);
  525. }
  526. public override ECPoint Subtract(ECPoint b)
  527. {
  528. if (b.IsInfinity)
  529. return this;
  530. // Add -b
  531. return Add(b.Negate());
  532. }
  533. }
  534. /**
  535. * Elliptic curve points over Fp
  536. */
  537. internal class FpPoint
  538. : AbstractFpPoint
  539. {
  540. /**
  541. * Create a point which encodes without point compression.
  542. *
  543. * @param curve the curve to use
  544. * @param x affine x co-ordinate
  545. * @param y affine y co-ordinate
  546. */
  547. public FpPoint(ECCurve curve, ECFieldElement x, ECFieldElement y)
  548. : this(curve, x, y, false)
  549. {
  550. }
  551. /**
  552. * Create a point that encodes with or without point compression.
  553. *
  554. * @param curve the curve to use
  555. * @param x affine x co-ordinate
  556. * @param y affine y co-ordinate
  557. * @param withCompression if true encode with point compression
  558. */
  559. public FpPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
  560. : base(curve, x, y, withCompression)
  561. {
  562. if ((x == null) != (y == null))
  563. throw new ArgumentException("Exactly one of the field elements is null");
  564. }
  565. internal FpPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
  566. : base(curve, x, y, zs, withCompression)
  567. {
  568. }
  569. protected override ECPoint Detach()
  570. {
  571. return new FpPoint(null, AffineXCoord, AffineYCoord, false);
  572. }
  573. public override ECFieldElement GetZCoord(int index)
  574. {
  575. if (index == 1 && ECCurve.COORD_JACOBIAN_MODIFIED == this.CurveCoordinateSystem)
  576. {
  577. return GetJacobianModifiedW();
  578. }
  579. return base.GetZCoord(index);
  580. }
  581. // B.3 pg 62
  582. public override ECPoint Add(ECPoint b)
  583. {
  584. if (this.IsInfinity)
  585. return b;
  586. if (b.IsInfinity)
  587. return this;
  588. if (this == b)
  589. return Twice();
  590. ECCurve curve = this.Curve;
  591. int coord = curve.CoordinateSystem;
  592. ECFieldElement X1 = this.RawXCoord, Y1 = this.RawYCoord;
  593. ECFieldElement X2 = b.RawXCoord, Y2 = b.RawYCoord;
  594. switch (coord)
  595. {
  596. case ECCurve.COORD_AFFINE:
  597. {
  598. ECFieldElement dx = X2.Subtract(X1), dy = Y2.Subtract(Y1);
  599. if (dx.IsZero)
  600. {
  601. if (dy.IsZero)
  602. {
  603. // this == b, i.e. this must be doubled
  604. return Twice();
  605. }
  606. // this == -b, i.e. the result is the point at infinity
  607. return Curve.Infinity;
  608. }
  609. ECFieldElement gamma = dy.Divide(dx);
  610. ECFieldElement X3 = gamma.Square().Subtract(X1).Subtract(X2);
  611. ECFieldElement Y3 = gamma.Multiply(X1.Subtract(X3)).Subtract(Y1);
  612. return new FpPoint(Curve, X3, Y3, IsCompressed);
  613. }
  614. case ECCurve.COORD_HOMOGENEOUS:
  615. {
  616. ECFieldElement Z1 = this.RawZCoords[0];
  617. ECFieldElement Z2 = b.RawZCoords[0];
  618. bool Z1IsOne = Z1.IsOne;
  619. bool Z2IsOne = Z2.IsOne;
  620. ECFieldElement u1 = Z1IsOne ? Y2 : Y2.Multiply(Z1);
  621. ECFieldElement u2 = Z2IsOne ? Y1 : Y1.Multiply(Z2);
  622. ECFieldElement u = u1.Subtract(u2);
  623. ECFieldElement v1 = Z1IsOne ? X2 : X2.Multiply(Z1);
  624. ECFieldElement v2 = Z2IsOne ? X1 : X1.Multiply(Z2);
  625. ECFieldElement v = v1.Subtract(v2);
  626. // Check if b == this or b == -this
  627. if (v.IsZero)
  628. {
  629. if (u.IsZero)
  630. {
  631. // this == b, i.e. this must be doubled
  632. return this.Twice();
  633. }
  634. // this == -b, i.e. the result is the point at infinity
  635. return curve.Infinity;
  636. }
  637. // TODO Optimize for when w == 1
  638. ECFieldElement w = Z1IsOne ? Z2 : Z2IsOne ? Z1 : Z1.Multiply(Z2);
  639. ECFieldElement vSquared = v.Square();
  640. ECFieldElement vCubed = vSquared.Multiply(v);
  641. ECFieldElement vSquaredV2 = vSquared.Multiply(v2);
  642. ECFieldElement A = u.Square().Multiply(w).Subtract(vCubed).Subtract(Two(vSquaredV2));
  643. ECFieldElement X3 = v.Multiply(A);
  644. ECFieldElement Y3 = vSquaredV2.Subtract(A).MultiplyMinusProduct(u, u2, vCubed);
  645. ECFieldElement Z3 = vCubed.Multiply(w);
  646. return new FpPoint(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed);
  647. }
  648. case ECCurve.COORD_JACOBIAN:
  649. case ECCurve.COORD_JACOBIAN_MODIFIED:
  650. {
  651. ECFieldElement Z1 = this.RawZCoords[0];
  652. ECFieldElement Z2 = b.RawZCoords[0];
  653. bool Z1IsOne = Z1.IsOne;
  654. ECFieldElement X3, Y3, Z3, Z3Squared = null;
  655. if (!Z1IsOne && Z1.Equals(Z2))
  656. {
  657. // TODO Make this available as public method coZAdd?
  658. ECFieldElement dx = X1.Subtract(X2), dy = Y1.Subtract(Y2);
  659. if (dx.IsZero)
  660. {
  661. if (dy.IsZero)
  662. {
  663. return Twice();
  664. }
  665. return curve.Infinity;
  666. }
  667. ECFieldElement C = dx.Square();
  668. ECFieldElement W1 = X1.Multiply(C), W2 = X2.Multiply(C);
  669. ECFieldElement A1 = W1.Subtract(W2).Multiply(Y1);
  670. X3 = dy.Square().Subtract(W1).Subtract(W2);
  671. Y3 = W1.Subtract(X3).Multiply(dy).Subtract(A1);
  672. Z3 = dx;
  673. if (Z1IsOne)
  674. {
  675. Z3Squared = C;
  676. }
  677. else
  678. {
  679. Z3 = Z3.Multiply(Z1);
  680. }
  681. }
  682. else
  683. {
  684. ECFieldElement Z1Squared, U2, S2;
  685. if (Z1IsOne)
  686. {
  687. Z1Squared = Z1; U2 = X2; S2 = Y2;
  688. }
  689. else
  690. {
  691. Z1Squared = Z1.Square();
  692. U2 = Z1Squared.Multiply(X2);
  693. ECFieldElement Z1Cubed = Z1Squared.Multiply(Z1);
  694. S2 = Z1Cubed.Multiply(Y2);
  695. }
  696. bool Z2IsOne = Z2.IsOne;
  697. ECFieldElement Z2Squared, U1, S1;
  698. if (Z2IsOne)
  699. {
  700. Z2Squared = Z2; U1 = X1; S1 = Y1;
  701. }
  702. else
  703. {
  704. Z2Squared = Z2.Square();
  705. U1 = Z2Squared.Multiply(X1);
  706. ECFieldElement Z2Cubed = Z2Squared.Multiply(Z2);
  707. S1 = Z2Cubed.Multiply(Y1);
  708. }
  709. ECFieldElement H = U1.Subtract(U2);
  710. ECFieldElement R = S1.Subtract(S2);
  711. // Check if b == this or b == -this
  712. if (H.IsZero)
  713. {
  714. if (R.IsZero)
  715. {
  716. // this == b, i.e. this must be doubled
  717. return this.Twice();
  718. }
  719. // this == -b, i.e. the result is the point at infinity
  720. return curve.Infinity;
  721. }
  722. ECFieldElement HSquared = H.Square();
  723. ECFieldElement G = HSquared.Multiply(H);
  724. ECFieldElement V = HSquared.Multiply(U1);
  725. X3 = R.Square().Add(G).Subtract(Two(V));
  726. Y3 = V.Subtract(X3).MultiplyMinusProduct(R, G, S1);
  727. Z3 = H;
  728. if (!Z1IsOne)
  729. {
  730. Z3 = Z3.Multiply(Z1);
  731. }
  732. if (!Z2IsOne)
  733. {
  734. Z3 = Z3.Multiply(Z2);
  735. }
  736. // Alternative calculation of Z3 using fast square
  737. //X3 = four(X3);
  738. //Y3 = eight(Y3);
  739. //Z3 = doubleProductFromSquares(Z1, Z2, Z1Squared, Z2Squared).Multiply(H);
  740. if (Z3 == H)
  741. {
  742. Z3Squared = HSquared;
  743. }
  744. }
  745. ECFieldElement[] zs;
  746. if (coord == ECCurve.COORD_JACOBIAN_MODIFIED)
  747. {
  748. // TODO If the result will only be used in a subsequent addition, we don't need W3
  749. ECFieldElement W3 = CalculateJacobianModifiedW(Z3, Z3Squared);
  750. zs = new ECFieldElement[] { Z3, W3 };
  751. }
  752. else
  753. {
  754. zs = new ECFieldElement[] { Z3 };
  755. }
  756. return new FpPoint(curve, X3, Y3, zs, IsCompressed);
  757. }
  758. default:
  759. {
  760. throw new InvalidOperationException("unsupported coordinate system");
  761. }
  762. }
  763. }
  764. // B.3 pg 62
  765. public override ECPoint Twice()
  766. {
  767. if (this.IsInfinity)
  768. return this;
  769. ECCurve curve = this.Curve;
  770. ECFieldElement Y1 = this.RawYCoord;
  771. if (Y1.IsZero)
  772. return curve.Infinity;
  773. int coord = curve.CoordinateSystem;
  774. ECFieldElement X1 = this.RawXCoord;
  775. switch (coord)
  776. {
  777. case ECCurve.COORD_AFFINE:
  778. {
  779. ECFieldElement X1Squared = X1.Square();
  780. ECFieldElement gamma = Three(X1Squared).Add(this.Curve.A).Divide(Two(Y1));
  781. ECFieldElement X3 = gamma.Square().Subtract(Two(X1));
  782. ECFieldElement Y3 = gamma.Multiply(X1.Subtract(X3)).Subtract(Y1);
  783. return new FpPoint(Curve, X3, Y3, IsCompressed);
  784. }
  785. case ECCurve.COORD_HOMOGENEOUS:
  786. {
  787. ECFieldElement Z1 = this.RawZCoords[0];
  788. bool Z1IsOne = Z1.IsOne;
  789. // TODO Optimize for small negative a4 and -3
  790. ECFieldElement w = curve.A;
  791. if (!w.IsZero && !Z1IsOne)
  792. {
  793. w = w.Multiply(Z1.Square());
  794. }
  795. w = w.Add(Three(X1.Square()));
  796. ECFieldElement s = Z1IsOne ? Y1 : Y1.Multiply(Z1);
  797. ECFieldElement t = Z1IsOne ? Y1.Square() : s.Multiply(Y1);
  798. ECFieldElement B = X1.Multiply(t);
  799. ECFieldElement _4B = Four(B);
  800. ECFieldElement h = w.Square().Subtract(Two(_4B));
  801. ECFieldElement _2s = Two(s);
  802. ECFieldElement X3 = h.Multiply(_2s);
  803. ECFieldElement _2t = Two(t);
  804. ECFieldElement Y3 = _4B.Subtract(h).Multiply(w).Subtract(Two(_2t.Square()));
  805. ECFieldElement _4sSquared = Z1IsOne ? Two(_2t) : _2s.Square();
  806. ECFieldElement Z3 = Two(_4sSquared).Multiply(s);
  807. return new FpPoint(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed);
  808. }
  809. case ECCurve.COORD_JACOBIAN:
  810. {
  811. ECFieldElement Z1 = this.RawZCoords[0];
  812. bool Z1IsOne = Z1.IsOne;
  813. ECFieldElement Y1Squared = Y1.Square();
  814. ECFieldElement T = Y1Squared.Square();
  815. ECFieldElement a4 = curve.A;
  816. ECFieldElement a4Neg = a4.Negate();
  817. ECFieldElement M, S;
  818. if (a4Neg.ToBigInteger().Equals(BigInteger.ValueOf(3)))
  819. {
  820. ECFieldElement Z1Squared = Z1IsOne ? Z1 : Z1.Square();
  821. M = Three(X1.Add(Z1Squared).Multiply(X1.Subtract(Z1Squared)));
  822. S = Four(Y1Squared.Multiply(X1));
  823. }
  824. else
  825. {
  826. ECFieldElement X1Squared = X1.Square();
  827. M = Three(X1Squared);
  828. if (Z1IsOne)
  829. {
  830. M = M.Add(a4);
  831. }
  832. else if (!a4.IsZero)
  833. {
  834. ECFieldElement Z1Squared = Z1IsOne ? Z1 : Z1.Square();
  835. ECFieldElement Z1Pow4 = Z1Squared.Square();
  836. if (a4Neg.BitLength < a4.BitLength)
  837. {
  838. M = M.Subtract(Z1Pow4.Multiply(a4Neg));
  839. }
  840. else
  841. {
  842. M = M.Add(Z1Pow4.Multiply(a4));
  843. }
  844. }
  845. //S = two(doubleProductFromSquares(X1, Y1Squared, X1Squared, T));
  846. S = Four(X1.Multiply(Y1Squared));
  847. }
  848. ECFieldElement X3 = M.Square().Subtract(Two(S));
  849. ECFieldElement Y3 = S.Subtract(X3).Multiply(M).Subtract(Eight(T));
  850. ECFieldElement Z3 = Two(Y1);
  851. if (!Z1IsOne)
  852. {
  853. Z3 = Z3.Multiply(Z1);
  854. }
  855. // Alternative calculation of Z3 using fast square
  856. //ECFieldElement Z3 = doubleProductFromSquares(Y1, Z1, Y1Squared, Z1Squared);
  857. return new FpPoint(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed);
  858. }
  859. case ECCurve.COORD_JACOBIAN_MODIFIED:
  860. {
  861. return TwiceJacobianModified(true);
  862. }
  863. default:
  864. {
  865. throw new InvalidOperationException("unsupported coordinate system");
  866. }
  867. }
  868. }
  869. public override ECPoint TwicePlus(ECPoint b)
  870. {
  871. if (this == b)
  872. return ThreeTimes();
  873. if (this.IsInfinity)
  874. return b;
  875. if (b.IsInfinity)
  876. return Twice();
  877. ECFieldElement Y1 = this.RawYCoord;
  878. if (Y1.IsZero)
  879. return b;
  880. ECCurve curve = this.Curve;
  881. int coord = curve.CoordinateSystem;
  882. switch (coord)
  883. {
  884. case ECCurve.COORD_AFFINE:
  885. {
  886. ECFieldElement X1 = this.RawXCoord;
  887. ECFieldElement X2 = b.RawXCoord, Y2 = b.RawYCoord;
  888. ECFieldElement dx = X2.Subtract(X1), dy = Y2.Subtract(Y1);
  889. if (dx.IsZero)
  890. {
  891. if (dy.IsZero)
  892. {
  893. // this == b i.e. the result is 3P
  894. return ThreeTimes();
  895. }
  896. // this == -b, i.e. the result is P
  897. return this;
  898. }
  899. /*
  900. * Optimized calculation of 2P + Q, as described in "Trading Inversions for
  901. * Multiplications in Elliptic Curve Cryptography", by Ciet, Joye, Lauter, Montgomery.
  902. */
  903. ECFieldElement X = dx.Square(), Y = dy.Square();
  904. ECFieldElement d = X.Multiply(Two(X1).Add(X2)).Subtract(Y);
  905. if (d.IsZero)
  906. {
  907. return Curve.Infinity;
  908. }
  909. ECFieldElement D = d.Multiply(dx);
  910. ECFieldElement I = D.Invert();
  911. ECFieldElement L1 = d.Multiply(I).Multiply(dy);
  912. ECFieldElement L2 = Two(Y1).Multiply(X).Multiply(dx).Multiply(I).Subtract(L1);
  913. ECFieldElement X4 = (L2.Subtract(L1)).Multiply(L1.Add(L2)).Add(X2);
  914. ECFieldElement Y4 = (X1.Subtract(X4)).Multiply(L2).Subtract(Y1);
  915. return new FpPoint(Curve, X4, Y4, IsCompressed);
  916. }
  917. case ECCurve.COORD_JACOBIAN_MODIFIED:
  918. {
  919. return TwiceJacobianModified(false).Add(b);
  920. }
  921. default:
  922. {
  923. return Twice().Add(b);
  924. }
  925. }
  926. }
  927. public override ECPoint ThreeTimes()
  928. {
  929. if (this.IsInfinity)
  930. return this;
  931. ECFieldElement Y1 = this.RawYCoord;
  932. if (Y1.IsZero)
  933. return this;
  934. ECCurve curve = this.Curve;
  935. int coord = curve.CoordinateSystem;
  936. switch (coord)
  937. {
  938. case ECCurve.COORD_AFFINE:
  939. {
  940. ECFieldElement X1 = this.RawXCoord;
  941. ECFieldElement _2Y1 = Two(Y1);
  942. ECFieldElement X = _2Y1.Square();
  943. ECFieldElement Z = Three(X1.Square()).Add(Curve.A);
  944. ECFieldElement Y = Z.Square();
  945. ECFieldElement d = Three(X1).Multiply(X).Subtract(Y);
  946. if (d.IsZero)
  947. {
  948. return Curve.Infinity;
  949. }
  950. ECFieldElement D = d.Multiply(_2Y1);
  951. ECFieldElement I = D.Invert();
  952. ECFieldElement L1 = d.Multiply(I).Multiply(Z);
  953. ECFieldElement L2 = X.Square().Multiply(I).Subtract(L1);
  954. ECFieldElement X4 = (L2.Subtract(L1)).Multiply(L1.Add(L2)).Add(X1);
  955. ECFieldElement Y4 = (X1.Subtract(X4)).Multiply(L2).Subtract(Y1);
  956. return new FpPoint(Curve, X4, Y4, IsCompressed);
  957. }
  958. case ECCurve.COORD_JACOBIAN_MODIFIED:
  959. {
  960. return TwiceJacobianModified(false).Add(this);
  961. }
  962. default:
  963. {
  964. // NOTE: Be careful about recursions between TwicePlus and ThreeTimes
  965. return Twice().Add(this);
  966. }
  967. }
  968. }
  969. public override ECPoint TimesPow2(int e)
  970. {
  971. if (e < 0)
  972. throw new ArgumentException("cannot be negative", "e");
  973. if (e == 0 || this.IsInfinity)
  974. return this;
  975. if (e == 1)
  976. return Twice();
  977. ECCurve curve = this.Curve;
  978. ECFieldElement Y1 = this.RawYCoord;
  979. if (Y1.IsZero)
  980. return curve.Infinity;
  981. int coord = curve.CoordinateSystem;
  982. ECFieldElement W1 = curve.A;
  983. ECFieldElement X1 = this.RawXCoord;
  984. ECFieldElement Z1 = this.RawZCoords.Length < 1 ? curve.FromBigInteger(BigInteger.One) : this.RawZCoords[0];
  985. if (!Z1.IsOne)
  986. {
  987. switch (coord)
  988. {
  989. case ECCurve.COORD_HOMOGENEOUS:
  990. ECFieldElement Z1Sq = Z1.Square();
  991. X1 = X1.Multiply(Z1);
  992. Y1 = Y1.Multiply(Z1Sq);
  993. W1 = CalculateJacobianModifiedW(Z1, Z1Sq);
  994. break;
  995. case ECCurve.COORD_JACOBIAN:
  996. W1 = CalculateJacobianModifiedW(Z1, null);
  997. break;
  998. case ECCurve.COORD_JACOBIAN_MODIFIED:
  999. W1 = GetJacobianModifiedW();
  1000. break;
  1001. }
  1002. }
  1003. for (int i = 0; i < e; ++i)
  1004. {
  1005. if (Y1.IsZero)
  1006. return curve.Infinity;
  1007. ECFieldElement X1Squared = X1.Square();
  1008. ECFieldElement M = Three(X1Squared);
  1009. ECFieldElement _2Y1 = Two(Y1);
  1010. ECFieldElement _2Y1Squared = _2Y1.Multiply(Y1);
  1011. ECFieldElement S = Two(X1.Multiply(_2Y1Squared));
  1012. ECFieldElement _4T = _2Y1Squared.Square();
  1013. ECFieldElement _8T = Two(_4T);
  1014. if (!W1.IsZero)
  1015. {
  1016. M = M.Add(W1);
  1017. W1 = Two(_8T.Multiply(W1));
  1018. }
  1019. X1 = M.Square().Subtract(Two(S));
  1020. Y1 = M.Multiply(S.Subtract(X1)).Subtract(_8T);
  1021. Z1 = Z1.IsOne ? _2Y1 : _2Y1.Multiply(Z1);
  1022. }
  1023. switch (coord)
  1024. {
  1025. case ECCurve.COORD_AFFINE:
  1026. ECFieldElement zInv = Z1.Invert(), zInv2 = zInv.Square(), zInv3 = zInv2.Multiply(zInv);
  1027. return new FpPoint(curve, X1.Multiply(zInv2), Y1.Multiply(zInv3), IsCompressed);
  1028. case ECCurve.COORD_HOMOGENEOUS:
  1029. X1 = X1.Multiply(Z1);
  1030. Z1 = Z1.Multiply(Z1.Square());
  1031. return new FpPoint(curve, X1, Y1, new ECFieldElement[] { Z1 }, IsCompressed);
  1032. case ECCurve.COORD_JACOBIAN:
  1033. return new FpPoint(curve, X1, Y1, new ECFieldElement[] { Z1 }, IsCompressed);
  1034. case ECCurve.COORD_JACOBIAN_MODIFIED:
  1035. return new FpPoint(curve, X1, Y1, new ECFieldElement[] { Z1, W1 }, IsCompressed);
  1036. default:
  1037. throw new InvalidOperationException("unsupported coordinate system");
  1038. }
  1039. }
  1040. protected virtual ECFieldElement Two(ECFieldElement x)
  1041. {
  1042. return x.Add(x);
  1043. }
  1044. protected virtual ECFieldElement Three(ECFieldElement x)
  1045. {
  1046. return Two(x).Add(x);
  1047. }
  1048. protected virtual ECFieldElement Four(ECFieldElement x)
  1049. {
  1050. return Two(Two(x));
  1051. }
  1052. protected virtual ECFieldElement Eight(ECFieldElement x)
  1053. {
  1054. return Four(Two(x));
  1055. }
  1056. protected virtual ECFieldElement DoubleProductFromSquares(ECFieldElement a, ECFieldElement b,
  1057. ECFieldElement aSquared, ECFieldElement bSquared)
  1058. {
  1059. /*
  1060. * NOTE: If squaring in the field is faster than multiplication, then this is a quicker
  1061. * way to calculate 2.A.B, if A^2 and B^2 are already known.
  1062. */
  1063. return a.Add(b).Square().Subtract(aSquared).Subtract(bSquared);
  1064. }
  1065. public override ECPoint Negate()
  1066. {
  1067. if (IsInfinity)
  1068. return this;
  1069. ECCurve curve = Curve;
  1070. int coord = curve.CoordinateSystem;
  1071. if (ECCurve.COORD_AFFINE != coord)
  1072. {
  1073. return new FpPoint(curve, RawXCoord, RawYCoord.Negate(), RawZCoords, IsCompressed);
  1074. }
  1075. return new FpPoint(curve, RawXCoord, RawYCoord.Negate(), IsCompressed);
  1076. }
  1077. protected virtual ECFieldElement CalculateJacobianModifiedW(ECFieldElement Z, ECFieldElement ZSquared)
  1078. {
  1079. ECFieldElement a4 = this.Curve.A;
  1080. if (a4.IsZero || Z.IsOne)
  1081. return a4;
  1082. if (ZSquared == null)
  1083. {
  1084. ZSquared = Z.Square();
  1085. }
  1086. ECFieldElement W = ZSquared.Square();
  1087. ECFieldElement a4Neg = a4.Negate();
  1088. if (a4Neg.BitLength < a4.BitLength)
  1089. {
  1090. W = W.Multiply(a4Neg).Negate();
  1091. }
  1092. else
  1093. {
  1094. W = W.Multiply(a4);
  1095. }
  1096. return W;
  1097. }
  1098. protected virtual ECFieldElement GetJacobianModifiedW()
  1099. {
  1100. ECFieldElement[] ZZ = this.RawZCoords;
  1101. ECFieldElement W = ZZ[1];
  1102. if (W == null)
  1103. {
  1104. // NOTE: Rarely, TwicePlus will result in the need for a lazy W1 calculation here
  1105. ZZ[1] = W = CalculateJacobianModifiedW(ZZ[0], null);
  1106. }
  1107. return W;
  1108. }
  1109. protected virtual FpPoint TwiceJacobianModified(bool calculateW)
  1110. {
  1111. ECFieldElement X1 = this.RawXCoord, Y1 = this.RawYCoord, Z1 = this.RawZCoords[0], W1 = GetJacobianModifiedW();
  1112. ECFieldElement X1Squared = X1.Square();
  1113. ECFieldElement M = Three(X1Squared).Add(W1);
  1114. ECFieldElement _2Y1 = Two(Y1);
  1115. ECFieldElement _2Y1Squared = _2Y1.Multiply(Y1);
  1116. ECFieldElement S = Two(X1.Multiply(_2Y1Squared));
  1117. ECFieldElement X3 = M.Square().Subtract(Two(S));
  1118. ECFieldElement _4T = _2Y1Squared.Square();
  1119. ECFieldElement _8T = Two(_4T);
  1120. ECFieldElement Y3 = M.Multiply(S.Subtract(X3)).Subtract(_8T);
  1121. ECFieldElement W3 = calculateW ? Two(_8T.Multiply(W1)) : null;
  1122. ECFieldElement Z3 = Z1.IsOne ? _2Y1 : _2Y1.Multiply(Z1);
  1123. return new FpPoint(this.Curve, X3, Y3, new ECFieldElement[] { Z3, W3 }, IsCompressed);
  1124. }
  1125. }
  1126. internal abstract class AbstractF2mPoint
  1127. : ECPointBase
  1128. {
  1129. protected AbstractF2mPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
  1130. : base(curve, x, y, withCompression)
  1131. {
  1132. }
  1133. protected AbstractF2mPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
  1134. : base(curve, x, y, zs, withCompression)
  1135. {
  1136. }
  1137. protected override bool SatisfiesCurveEquation()
  1138. {
  1139. ECCurve curve = Curve;
  1140. ECFieldElement X = this.RawXCoord, Y = this.RawYCoord, A = curve.A, B = curve.B;
  1141. ECFieldElement lhs, rhs;
  1142. int coord = curve.CoordinateSystem;
  1143. if (coord == ECCurve.COORD_LAMBDA_PROJECTIVE)
  1144. {
  1145. ECFieldElement Z = this.RawZCoords[0];
  1146. bool ZIsOne = Z.IsOne;
  1147. if (X.IsZero)
  1148. {
  1149. // NOTE: For x == 0, we expect the affine-y instead of the lambda-y
  1150. lhs = Y.Square();
  1151. rhs = B;
  1152. if (!ZIsOne)
  1153. {
  1154. ECFieldElement Z2 = Z.Square();
  1155. rhs = rhs.Multiply(Z2);
  1156. }
  1157. }
  1158. else
  1159. {
  1160. ECFieldElement L = Y, X2 = X.Square();
  1161. if (ZIsOne)
  1162. {
  1163. lhs = L.Square().Add(L).Add(A);
  1164. rhs = X2.Square().Add(B);
  1165. }
  1166. else
  1167. {
  1168. ECFieldElement Z2 = Z.Square(), Z4 = Z2.Square();
  1169. lhs = L.Add(Z).MultiplyPlusProduct(L, A, Z2);
  1170. // TODO If sqrt(b) is precomputed this can be simplified to a single square
  1171. rhs = X2.SquarePlusProduct(B, Z4);
  1172. }
  1173. lhs = lhs.Multiply(X2);
  1174. }
  1175. }
  1176. else
  1177. {
  1178. lhs = Y.Add(X).Multiply(Y);
  1179. switch (coord)
  1180. {
  1181. case ECCurve.COORD_AFFINE:
  1182. break;
  1183. case ECCurve.COORD_HOMOGENEOUS:
  1184. {
  1185. ECFieldElement Z = this.RawZCoords[0];
  1186. if (!Z.IsOne)
  1187. {
  1188. ECFieldElement Z2 = Z.Square(), Z3 = Z.Multiply(Z2);
  1189. lhs = lhs.Multiply(Z);
  1190. A = A.Multiply(Z);
  1191. B = B.Multiply(Z3);
  1192. }
  1193. break;
  1194. }
  1195. default:
  1196. throw new InvalidOperationException("unsupported coordinate system");
  1197. }
  1198. rhs = X.Add(A).Multiply(X.Square()).Add(B);
  1199. }
  1200. return lhs.Equals(rhs);
  1201. }
  1202. protected override bool SatisfiesOrder()
  1203. {
  1204. ECCurve curve = Curve;
  1205. BigInteger cofactor = curve.Cofactor;
  1206. if (BigInteger.Two.Equals(cofactor))
  1207. {
  1208. /*
  1209. * Check that the trace of (X + A) is 0, then there exists a solution to L^2 + L = X + A,
  1210. * and so a halving is possible, so this point is the double of another.
  1211. */
  1212. ECPoint N = this.Normalize();
  1213. ECFieldElement X = N.AffineXCoord;
  1214. ECFieldElement rhs = X.Add(curve.A);
  1215. return ((AbstractF2mFieldElement)rhs).Trace() == 0;
  1216. }
  1217. if (BigInteger.ValueOf(4).Equals(cofactor))
  1218. {
  1219. /*
  1220. * Solve L^2 + L = X + A to find the half of this point, if it exists (fail if not).
  1221. * Generate both possibilities for the square of the half-point's x-coordinate (w),
  1222. * and check if Tr(w + A) == 0 for at least one; then a second halving is possible
  1223. * (see comments for cofactor 2 above), so this point is four times another.
  1224. *
  1225. * Note: Tr(x^2) == Tr(x).
  1226. */
  1227. ECPoint N = this.Normalize();
  1228. ECFieldElement X = N.AffineXCoord;
  1229. ECFieldElement lambda = ((AbstractF2mCurve)curve).SolveQuadraticEquation(X.Add(curve.A));
  1230. if (lambda == null)
  1231. return false;
  1232. ECFieldElement w = X.Multiply(lambda).Add(N.AffineYCoord);
  1233. ECFieldElement t = w.Add(curve.A);
  1234. return ((AbstractF2mFieldElement)t).Trace() == 0
  1235. || ((AbstractF2mFieldElement)(t.Add(X))).Trace() == 0;
  1236. }
  1237. return base.SatisfiesOrder();
  1238. }
  1239. public override ECPoint ScaleX(ECFieldElement scale)
  1240. {
  1241. if (this.IsInfinity)
  1242. return this;
  1243. switch (CurveCoordinateSystem)
  1244. {
  1245. case ECCurve.COORD_LAMBDA_AFFINE:
  1246. {
  1247. // Y is actually Lambda (X + Y/X) here
  1248. ECFieldElement X = RawXCoord, L = RawYCoord;
  1249. ECFieldElement X2 = X.Multiply(scale);
  1250. ECFieldElement L2 = L.Add(X).Divide(scale).Add(X2);
  1251. return Curve.CreateRawPoint(X, L2, RawZCoords, IsCompressed);
  1252. }
  1253. case ECCurve.COORD_LAMBDA_PROJECTIVE:
  1254. {
  1255. // Y is actually Lambda (X + Y/X) here
  1256. ECFieldElement X = RawXCoord, L = RawYCoord, Z = RawZCoords[0];
  1257. // We scale the Z coordinate also, to avoid an inversion
  1258. ECFieldElement X2 = X.Multiply(scale.Square());
  1259. ECFieldElement L2 = L.Add(X).Add(X2);
  1260. ECFieldElement Z2 = Z.Multiply(scale);
  1261. return Curve.CreateRawPoint(X, L2, new ECFieldElement[] { Z2 }, IsCompressed);
  1262. }
  1263. default:
  1264. {
  1265. return base.ScaleX(scale);
  1266. }
  1267. }
  1268. }
  1269. public override ECPoint ScaleY(ECFieldElement scale)
  1270. {
  1271. if (this.IsInfinity)
  1272. return this;
  1273. switch (CurveCoordinateSystem)
  1274. {
  1275. case ECCurve.COORD_LAMBDA_AFFINE:
  1276. case ECCurve.COORD_LAMBDA_PROJECTIVE:
  1277. {
  1278. ECFieldElement X = RawXCoord, L = RawYCoord;
  1279. // Y is actually Lambda (X + Y/X) here
  1280. ECFieldElement L2 = L.Add(X).Multiply(scale).Add(X);
  1281. return Curve.CreateRawPoint(X, L2, RawZCoords, IsCompressed);
  1282. }
  1283. default:
  1284. {
  1285. return base.ScaleY(scale);
  1286. }
  1287. }
  1288. }
  1289. public override ECPoint Subtract(ECPoint b)
  1290. {
  1291. if (b.IsInfinity)
  1292. return this;
  1293. // Add -b
  1294. return Add(b.Negate());
  1295. }
  1296. public virtual AbstractF2mPoint Tau()
  1297. {
  1298. if (this.IsInfinity)
  1299. return this;
  1300. ECCurve curve = this.Curve;
  1301. int coord = curve.CoordinateSystem;
  1302. ECFieldElement X1 = this.RawXCoord;
  1303. switch (coord)
  1304. {
  1305. case ECCurve.COORD_AFFINE:
  1306. case ECCurve.COORD_LAMBDA_AFFINE:
  1307. {
  1308. ECFieldElement Y1 = this.RawYCoord;
  1309. return (AbstractF2mPoint)curve.CreateRawPoint(X1.Square(), Y1.Square(), IsCompressed);
  1310. }
  1311. case ECCurve.COORD_HOMOGENEOUS:
  1312. case ECCurve.COORD_LAMBDA_PROJECTIVE:
  1313. {
  1314. ECFieldElement Y1 = this.RawYCoord, Z1 = this.RawZCoords[0];
  1315. return (AbstractF2mPoint)curve.CreateRawPoint(X1.Square(), Y1.Square(),
  1316. new ECFieldElement[] { Z1.Square() }, IsCompressed);
  1317. }
  1318. default:
  1319. {
  1320. throw new InvalidOperationException("unsupported coordinate system");
  1321. }
  1322. }
  1323. }
  1324. public virtual AbstractF2mPoint TauPow(int pow)
  1325. {
  1326. if (this.IsInfinity)
  1327. return this;
  1328. ECCurve curve = this.Curve;
  1329. int coord = curve.CoordinateSystem;
  1330. ECFieldElement X1 = this.RawXCoord;
  1331. switch (coord)
  1332. {
  1333. case ECCurve.COORD_AFFINE:
  1334. case ECCurve.COORD_LAMBDA_AFFINE:
  1335. {
  1336. ECFieldElement Y1 = this.RawYCoord;
  1337. return (AbstractF2mPoint)curve.CreateRawPoint(X1.SquarePow(pow), Y1.SquarePow(pow), IsCompressed);
  1338. }
  1339. case ECCurve.COORD_HOMOGENEOUS:
  1340. case ECCurve.COORD_LAMBDA_PROJECTIVE:
  1341. {
  1342. ECFieldElement Y1 = this.RawYCoord, Z1 = this.RawZCoords[0];
  1343. return (AbstractF2mPoint)curve.CreateRawPoint(X1.SquarePow(pow), Y1.SquarePow(pow),
  1344. new ECFieldElement[] { Z1.SquarePow(pow) }, IsCompressed);
  1345. }
  1346. default:
  1347. {
  1348. throw new InvalidOperationException("unsupported coordinate system");
  1349. }
  1350. }
  1351. }
  1352. }
  1353. /**
  1354. * Elliptic curve points over F2m
  1355. */
  1356. internal class F2mPoint
  1357. : AbstractF2mPoint
  1358. {
  1359. /**
  1360. * @param curve base curve
  1361. * @param x x point
  1362. * @param y y point
  1363. */
  1364. public F2mPoint(
  1365. ECCurve curve,
  1366. ECFieldElement x,
  1367. ECFieldElement y)
  1368. : this(curve, x, y, false)
  1369. {
  1370. }
  1371. /**
  1372. * @param curve base curve
  1373. * @param x x point
  1374. * @param y y point
  1375. * @param withCompression true if encode with point compression.
  1376. */
  1377. public F2mPoint(
  1378. ECCurve curve,
  1379. ECFieldElement x,
  1380. ECFieldElement y,
  1381. bool withCompression)
  1382. : base(curve, x, y, withCompression)
  1383. {
  1384. if ((x == null) != (y == null))
  1385. {
  1386. throw new ArgumentException("Exactly one of the field elements is null");
  1387. }
  1388. if (x != null)
  1389. {
  1390. // Check if x and y are elements of the same field
  1391. F2mFieldElement.CheckFieldElements(x, y);
  1392. // Check if x and a are elements of the same field
  1393. if (curve != null)
  1394. {
  1395. F2mFieldElement.CheckFieldElements(x, curve.A);
  1396. }
  1397. }
  1398. }
  1399. internal F2mPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
  1400. : base(curve, x, y, zs, withCompression)
  1401. {
  1402. }
  1403. protected override ECPoint Detach()
  1404. {
  1405. return new F2mPoint(null, AffineXCoord, AffineYCoord, false);
  1406. }
  1407. public override ECFieldElement YCoord
  1408. {
  1409. get
  1410. {
  1411. int coord = this.CurveCoordinateSystem;
  1412. switch (coord)
  1413. {
  1414. case ECCurve.COORD_LAMBDA_AFFINE:
  1415. case ECCurve.COORD_LAMBDA_PROJECTIVE:
  1416. {
  1417. ECFieldElement X = RawXCoord, L = RawYCoord;
  1418. if (this.IsInfinity || X.IsZero)
  1419. return L;
  1420. // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
  1421. ECFieldElement Y = L.Add(X).Multiply(X);
  1422. if (ECCurve.COORD_LAMBDA_PROJECTIVE == coord)
  1423. {
  1424. ECFieldElement Z = RawZCoords[0];
  1425. if (!Z.IsOne)
  1426. {
  1427. Y = Y.Divide(Z);
  1428. }
  1429. }
  1430. return Y;
  1431. }
  1432. default:
  1433. {
  1434. return RawYCoord;
  1435. }
  1436. }
  1437. }
  1438. }
  1439. protected internal override bool CompressionYTilde
  1440. {
  1441. get
  1442. {
  1443. ECFieldElement X = this.RawXCoord;
  1444. if (X.IsZero)
  1445. {
  1446. return false;
  1447. }
  1448. ECFieldElement Y = this.RawYCoord;
  1449. switch (this.CurveCoordinateSystem)
  1450. {
  1451. case ECCurve.COORD_LAMBDA_AFFINE:
  1452. case ECCurve.COORD_LAMBDA_PROJECTIVE:
  1453. {
  1454. // Y is actually Lambda (X + Y/X) here
  1455. return Y.TestBitZero() != X.TestBitZero();
  1456. }
  1457. default:
  1458. {
  1459. return Y.Divide(X).TestBitZero();
  1460. }
  1461. }
  1462. }
  1463. }
  1464. public override ECPoint Add(ECPoint b)
  1465. {
  1466. if (this.IsInfinity)
  1467. return b;
  1468. if (b.IsInfinity)
  1469. return this;
  1470. ECCurve curve = this.Curve;
  1471. int coord = curve.CoordinateSystem;
  1472. ECFieldElement X1 = this.RawXCoord;
  1473. ECFieldElement X2 = b.RawXCoord;
  1474. switch (coord)
  1475. {
  1476. case ECCurve.COORD_AFFINE:
  1477. {
  1478. ECFieldElement Y1 = this.RawYCoord;
  1479. ECFieldElement Y2 = b.RawYCoord;
  1480. ECFieldElement dx = X1.Add(X2), dy = Y1.Add(Y2);
  1481. if (dx.IsZero)
  1482. {
  1483. if (dy.IsZero)
  1484. {
  1485. return Twice();
  1486. }
  1487. return curve.Infinity;
  1488. }
  1489. ECFieldElement L = dy.Divide(dx);
  1490. ECFieldElement X3 = L.Square().Add(L).Add(dx).Add(curve.A);
  1491. ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
  1492. return new F2mPoint(curve, X3, Y3, IsCompressed);
  1493. }
  1494. case ECCurve.COORD_HOMOGENEOUS:
  1495. {
  1496. ECFieldElement Y1 = this.RawYCoord, Z1 = this.RawZCoords[0];
  1497. ECFieldElement Y2 = b.RawYCoord, Z2 = b.RawZCoords[0];
  1498. bool Z1IsOne = Z1.IsOne;
  1499. ECFieldElement U1 = Y2, V1 = X2;
  1500. if (!Z1IsOne)
  1501. {
  1502. U1 = U1.Multiply(Z1);
  1503. V1 = V1.Multiply(Z1);
  1504. }
  1505. bool Z2IsOne = Z2.IsOne;
  1506. ECFieldElement U2 = Y1, V2 = X1;
  1507. if (!Z2IsOne)
  1508. {
  1509. U2 = U2.Multiply(Z2);
  1510. V2 = V2.Multiply(Z2);
  1511. }
  1512. ECFieldElement U = U1.Add(U2);
  1513. ECFieldElement V = V1.Add(V2);
  1514. if (V.IsZero)
  1515. {
  1516. if (U.IsZero)
  1517. {
  1518. return Twice();
  1519. }
  1520. return curve.Infinity;
  1521. }
  1522. ECFieldElement VSq = V.Square();
  1523. ECFieldElement VCu = VSq.Multiply(V);
  1524. ECFieldElement W = Z1IsOne ? Z2 : Z2IsOne ? Z1 : Z1.Multiply(Z2);
  1525. ECFieldElement uv = U.Add(V);
  1526. ECFieldElement A = uv.MultiplyPlusProduct(U, VSq, curve.A).Multiply(W).Add(VCu);
  1527. ECFieldElement X3 = V.Multiply(A);
  1528. ECFieldElement VSqZ2 = Z2IsOne ? VSq : VSq.Multiply(Z2);
  1529. ECFieldElement Y3 = U.MultiplyPlusProduct(X1, V, Y1).MultiplyPlusProduct(VSqZ2, uv, A);
  1530. ECFieldElement Z3 = VCu.Multiply(W);
  1531. return new F2mPoint(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed);
  1532. }
  1533. case ECCurve.COORD_LAMBDA_PROJECTIVE:
  1534. {
  1535. if (X1.IsZero)
  1536. {
  1537. if (X2.IsZero)
  1538. return curve.Infinity;
  1539. return b.Add(this);
  1540. }
  1541. ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
  1542. ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
  1543. bool Z1IsOne = Z1.IsOne;
  1544. ECFieldElement U2 = X2, S2 = L2;
  1545. if (!Z1IsOne)
  1546. {
  1547. U2 = U2.Multiply(Z1);
  1548. S2 = S2.Multiply(Z1);
  1549. }
  1550. bool Z2IsOne = Z2.IsOne;
  1551. ECFieldElement U1 = X1, S1 = L1;
  1552. if (!Z2IsOne)
  1553. {
  1554. U1 = U1.Multiply(Z2);
  1555. S1 = S1.Multiply(Z2);
  1556. }
  1557. ECFieldElement A = S1.Add(S2);
  1558. ECFieldElement B = U1.Add(U2);
  1559. if (B.IsZero)
  1560. {
  1561. if (A.IsZero)
  1562. {
  1563. return Twice();
  1564. }
  1565. return curve.Infinity;
  1566. }
  1567. ECFieldElement X3, L3, Z3;
  1568. if (X2.IsZero)
  1569. {
  1570. // TODO This can probably be optimized quite a bit
  1571. ECPoint p = this.Normalize();
  1572. X1 = p.RawXCoord;
  1573. ECFieldElement Y1 = p.YCoord;
  1574. ECFieldElement Y2 = L2;
  1575. ECFieldElement L = Y1.Add(Y2).Divide(X1);
  1576. X3 = L.Square().Add(L).Add(X1).Add(curve.A);
  1577. if (X3.IsZero)
  1578. {
  1579. return new F2mPoint(curve, X3, curve.B.Sqrt(), IsCompressed);
  1580. }
  1581. ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
  1582. L3 = Y3.Divide(X3).Add(X3);
  1583. Z3 = curve.FromBigInteger(BigInteger.One);
  1584. }
  1585. else
  1586. {
  1587. B = B.Square();
  1588. ECFieldElement AU1 = A.Multiply(U1);
  1589. ECFieldElement AU2 = A.Multiply(U2);
  1590. X3 = AU1.Multiply(AU2);
  1591. if (X3.IsZero)
  1592. {
  1593. return new F2mPoint(curve, X3, curve.B.Sqrt(), IsCompressed);
  1594. }
  1595. ECFieldElement ABZ2 = A.Multiply(B);
  1596. if (!Z2IsOne)
  1597. {
  1598. ABZ2 = ABZ2.Multiply(Z2);
  1599. }
  1600. L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
  1601. Z3 = ABZ2;
  1602. if (!Z1IsOne)
  1603. {
  1604. Z3 = Z3.Multiply(Z1);
  1605. }
  1606. }
  1607. return new F2mPoint(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
  1608. }
  1609. default:
  1610. {
  1611. throw new InvalidOperationException("unsupported coordinate system");
  1612. }
  1613. }
  1614. }
  1615. /* (non-Javadoc)
  1616. * @see Org.BouncyCastle.Math.EC.ECPoint#twice()
  1617. */
  1618. public override ECPoint Twice()
  1619. {
  1620. if (this.IsInfinity)
  1621. return this;
  1622. ECCurve curve = this.Curve;
  1623. ECFieldElement X1 = this.RawXCoord;
  1624. if (X1.IsZero)
  1625. {
  1626. // A point with X == 0 is it's own additive inverse
  1627. return curve.Infinity;
  1628. }
  1629. int coord = curve.CoordinateSystem;
  1630. switch (coord)
  1631. {
  1632. case ECCurve.COORD_AFFINE:
  1633. {
  1634. ECFieldElement Y1 = this.RawYCoord;
  1635. ECFieldElement L1 = Y1.Divide(X1).Add(X1);
  1636. ECFieldElement X3 = L1.Square().Add(L1).Add(curve.A);
  1637. ECFieldElement Y3 = X1.SquarePlusProduct(X3, L1.AddOne());
  1638. return new F2mPoint(curve, X3, Y3, IsCompressed);
  1639. }
  1640. case ECCurve.COORD_HOMOGENEOUS:
  1641. {
  1642. ECFieldElement Y1 = this.RawYCoord, Z1 = this.RawZCoords[0];
  1643. bool Z1IsOne = Z1.IsOne;
  1644. ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1);
  1645. ECFieldElement Y1Z1 = Z1IsOne ? Y1 : Y1.Multiply(Z1);
  1646. ECFieldElement X1Sq = X1.Square();
  1647. ECFieldElement S = X1Sq.Add(Y1Z1);
  1648. ECFieldElement V = X1Z1;
  1649. ECFieldElement vSquared = V.Square();
  1650. ECFieldElement sv = S.Add(V);
  1651. ECFieldElement h = sv.MultiplyPlusProduct(S, vSquared, curve.A);
  1652. ECFieldElement X3 = V.Multiply(h);
  1653. ECFieldElement Y3 = X1Sq.Square().MultiplyPlusProduct(V, h, sv);
  1654. ECFieldElement Z3 = V.Multiply(vSquared);
  1655. return new F2mPoint(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed);
  1656. }
  1657. case ECCurve.COORD_LAMBDA_PROJECTIVE:
  1658. {
  1659. ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
  1660. bool Z1IsOne = Z1.IsOne;
  1661. ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.Multiply(Z1);
  1662. ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
  1663. ECFieldElement a = curve.A;
  1664. ECFieldElement aZ1Sq = Z1IsOne ? a : a.Multiply(Z1Sq);
  1665. ECFieldElement T = L1.Square().Add(L1Z1).Add(aZ1Sq);
  1666. if (T.IsZero)
  1667. {
  1668. return new F2mPoint(curve, T, curve.B.Sqrt(), IsCompressed);
  1669. }
  1670. ECFieldElement X3 = T.Square();
  1671. ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
  1672. ECFieldElement b = curve.B;
  1673. ECFieldElement L3;
  1674. if (b.BitLength < (curve.FieldSize >> 1))
  1675. {
  1676. ECFieldElement t1 = L1.Add(X1).Square();
  1677. ECFieldElement t2;
  1678. if (b.IsOne)
  1679. {
  1680. t2 = aZ1Sq.Add(Z1Sq).Square();
  1681. }
  1682. else
  1683. {
  1684. // TODO Can be calculated with one square if we pre-compute sqrt(b)
  1685. t2 = aZ1Sq.SquarePlusProduct(b, Z1Sq.Square());
  1686. }
  1687. L3 = t1.Add(T).Add(Z1Sq).Multiply(t1).Add(t2).Add(X3);
  1688. if (a.IsZero)
  1689. {
  1690. L3 = L3.Add(Z3);
  1691. }
  1692. else if (!a.IsOne)
  1693. {
  1694. L3 = L3.Add(a.AddOne().Multiply(Z3));
  1695. }
  1696. }
  1697. else
  1698. {
  1699. ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1);
  1700. L3 = X1Z1.SquarePlusProduct(T, L1Z1).Add(X3).Add(Z3);
  1701. }
  1702. return new F2mPoint(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
  1703. }
  1704. default:
  1705. {
  1706. throw new InvalidOperationException("unsupported coordinate system");
  1707. }
  1708. }
  1709. }
  1710. public override ECPoint TwicePlus(ECPoint b)
  1711. {
  1712. if (this.IsInfinity)
  1713. return b;
  1714. if (b.IsInfinity)
  1715. return Twice();
  1716. ECCurve curve = this.Curve;
  1717. ECFieldElement X1 = this.RawXCoord;
  1718. if (X1.IsZero)
  1719. {
  1720. // A point with X == 0 is it's own additive inverse
  1721. return b;
  1722. }
  1723. int coord = curve.CoordinateSystem;
  1724. switch (coord)
  1725. {
  1726. case ECCurve.COORD_LAMBDA_PROJECTIVE:
  1727. {
  1728. // NOTE: twicePlus() only optimized for lambda-affine argument
  1729. ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
  1730. if (X2.IsZero || !Z2.IsOne)
  1731. {
  1732. return Twice().Add(b);
  1733. }
  1734. ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
  1735. ECFieldElement L2 = b.RawYCoord;
  1736. ECFieldElement X1Sq = X1.Square();
  1737. ECFieldElement L1Sq = L1.Square();
  1738. ECFieldElement Z1Sq = Z1.Square();
  1739. ECFieldElement L1Z1 = L1.Multiply(Z1);
  1740. ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
  1741. ECFieldElement L2plus1 = L2.AddOne();
  1742. ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
  1743. ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
  1744. ECFieldElement B = X2Z1Sq.Add(T).Square();
  1745. if (B.IsZero)
  1746. {
  1747. if (A.IsZero)
  1748. {
  1749. return b.Twice();
  1750. }
  1751. return curve.Infinity;
  1752. }
  1753. if (A.IsZero)
  1754. {
  1755. return new F2mPoint(curve, A, curve.B.Sqrt(), IsCompressed);
  1756. }
  1757. ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
  1758. ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
  1759. ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
  1760. return new F2mPoint(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
  1761. }
  1762. default:
  1763. {
  1764. return Twice().Add(b);
  1765. }
  1766. }
  1767. }
  1768. public override ECPoint Negate()
  1769. {
  1770. if (this.IsInfinity)
  1771. return this;
  1772. ECFieldElement X = this.RawXCoord;
  1773. if (X.IsZero)
  1774. return this;
  1775. ECCurve curve = this.Curve;
  1776. int coord = curve.CoordinateSystem;
  1777. switch (coord)
  1778. {
  1779. case ECCurve.COORD_AFFINE:
  1780. {
  1781. ECFieldElement Y = this.RawYCoord;
  1782. return new F2mPoint(curve, X, Y.Add(X), IsCompressed);
  1783. }
  1784. case ECCurve.COORD_HOMOGENEOUS:
  1785. {
  1786. ECFieldElement Y = this.RawYCoord, Z = this.RawZCoords[0];
  1787. return new F2mPoint(curve, X, Y.Add(X), new ECFieldElement[] { Z }, IsCompressed);
  1788. }
  1789. case ECCurve.COORD_LAMBDA_AFFINE:
  1790. {
  1791. ECFieldElement L = this.RawYCoord;
  1792. return new F2mPoint(curve, X, L.AddOne(), IsCompressed);
  1793. }
  1794. case ECCurve.COORD_LAMBDA_PROJECTIVE:
  1795. {
  1796. // L is actually Lambda (X + Y/X) here
  1797. ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
  1798. return new F2mPoint(curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
  1799. }
  1800. default:
  1801. {
  1802. throw new InvalidOperationException("unsupported coordinate system");
  1803. }
  1804. }
  1805. }
  1806. }
  1807. }