ECPoint.cs 74 KB

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