coinex-api 0.0.89__py3-none-any.whl → 0.0.110__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of coinex-api might be problematic. Click here for more details.

Files changed (197) hide show
  1. coinex/ccxt/__init__.py +1 -1
  2. coinex/ccxt/async_support/__init__.py +1 -1
  3. coinex/ccxt/async_support/base/exchange.py +139 -10
  4. coinex/ccxt/async_support/base/throttler.py +1 -1
  5. coinex/ccxt/async_support/base/ws/cache.py +1 -0
  6. coinex/ccxt/async_support/base/ws/client.py +26 -4
  7. coinex/ccxt/async_support/coinex.py +2 -2
  8. coinex/ccxt/base/exchange.py +587 -91
  9. coinex/ccxt/base/types.py +11 -2
  10. coinex/ccxt/coinex.py +2 -2
  11. coinex/ccxt/pro/__init__.py +1 -1
  12. coinex/ccxt/pro/coinex.py +10 -7
  13. coinex/ccxt/static_dependencies/bip/__init__.py +6 -0
  14. coinex/ccxt/static_dependencies/bip/addr/P2PKH_addr.py +205 -0
  15. coinex/ccxt/static_dependencies/bip/addr/__init__.py +5 -0
  16. coinex/ccxt/static_dependencies/bip/addr/addr_dec_utils.py +125 -0
  17. coinex/ccxt/static_dependencies/bip/addr/addr_key_validator.py +162 -0
  18. coinex/ccxt/static_dependencies/bip/addr/iaddr_decoder.py +48 -0
  19. coinex/ccxt/static_dependencies/bip/addr/iaddr_encoder.py +50 -0
  20. coinex/ccxt/static_dependencies/bip/base58/__init__.py +3 -0
  21. coinex/ccxt/static_dependencies/bip/base58/base58.py +207 -0
  22. coinex/ccxt/static_dependencies/bip/base58/base58_ex.py +25 -0
  23. coinex/ccxt/static_dependencies/bip/base58/base58_xmr.py +155 -0
  24. coinex/ccxt/static_dependencies/bip/bech32/__init__.py +4 -0
  25. coinex/ccxt/static_dependencies/bip/bech32/bch_bech32.py +220 -0
  26. coinex/ccxt/static_dependencies/bip/bech32/bech32.py +235 -0
  27. coinex/ccxt/static_dependencies/bip/bech32/bech32_base.py +246 -0
  28. coinex/ccxt/static_dependencies/bip/bech32/bech32_ex.py +25 -0
  29. coinex/ccxt/static_dependencies/bip/bech32/segwit_bech32.py +173 -0
  30. coinex/ccxt/static_dependencies/bip/bip32/__init__.py +14 -0
  31. coinex/ccxt/static_dependencies/bip/bip32/base/__init__.py +3 -0
  32. coinex/ccxt/static_dependencies/bip/bip32/base/bip32_base.py +581 -0
  33. coinex/ccxt/static_dependencies/bip/bip32/base/ibip32_key_derivator.py +83 -0
  34. coinex/ccxt/static_dependencies/bip/bip32/base/ibip32_mst_key_generator.py +47 -0
  35. coinex/ccxt/static_dependencies/bip/bip32/bip32_const.py +35 -0
  36. coinex/ccxt/static_dependencies/bip/bip32/bip32_ex.py +29 -0
  37. coinex/ccxt/static_dependencies/bip/bip32/bip32_key_data.py +500 -0
  38. coinex/ccxt/static_dependencies/bip/bip32/bip32_key_net_ver.py +83 -0
  39. coinex/ccxt/static_dependencies/bip/bip32/bip32_key_ser.py +294 -0
  40. coinex/ccxt/static_dependencies/bip/bip32/bip32_keys.py +457 -0
  41. coinex/ccxt/static_dependencies/bip/bip32/bip32_path.py +247 -0
  42. coinex/ccxt/static_dependencies/bip/bip32/bip32_utils.py +72 -0
  43. coinex/ccxt/static_dependencies/bip/bip32/kholaw/__init__.py +4 -0
  44. coinex/ccxt/static_dependencies/bip/bip32/kholaw/bip32_kholaw_ed25519.py +82 -0
  45. coinex/ccxt/static_dependencies/bip/bip32/kholaw/bip32_kholaw_ed25519_key_derivator.py +118 -0
  46. coinex/ccxt/static_dependencies/bip/bip32/kholaw/bip32_kholaw_key_derivator_base.py +204 -0
  47. coinex/ccxt/static_dependencies/bip/bip32/kholaw/bip32_kholaw_mst_key_generator.py +119 -0
  48. coinex/ccxt/static_dependencies/bip/bip32/slip10/__init__.py +1 -0
  49. coinex/ccxt/static_dependencies/bip/bip32/slip10/bip32_slip10_key_derivator.py +200 -0
  50. coinex/ccxt/static_dependencies/bip/bip32/slip10/bip32_slip10_mst_key_generator.py +168 -0
  51. coinex/ccxt/static_dependencies/bip/bip32/slip10/bip32_slip10_secp256k1.py +82 -0
  52. coinex/ccxt/static_dependencies/bip/bip44/__init__.py +1 -0
  53. coinex/ccxt/static_dependencies/bip/bip44/bip44.py +265 -0
  54. coinex/ccxt/static_dependencies/bip/bip44_base/__init__.py +3 -0
  55. coinex/ccxt/static_dependencies/bip/bip44_base/bip44_base.py +624 -0
  56. coinex/ccxt/static_dependencies/bip/bip44_base/bip44_base_ex.py +25 -0
  57. coinex/ccxt/static_dependencies/bip/bip44_base/bip44_keys.py +225 -0
  58. coinex/ccxt/static_dependencies/bip/coin_conf/__init__.py +2 -0
  59. coinex/ccxt/static_dependencies/bip/coin_conf/coin_conf.py +68 -0
  60. coinex/ccxt/static_dependencies/bip/coin_conf/coins_conf.py +890 -0
  61. coinex/ccxt/static_dependencies/bip/conf/__init__.py +0 -0
  62. coinex/ccxt/static_dependencies/bip/conf/bip44/__init__.py +3 -0
  63. coinex/ccxt/static_dependencies/bip/conf/bip44/bip44_coins.py +126 -0
  64. coinex/ccxt/static_dependencies/bip/conf/bip44/bip44_conf.py +1360 -0
  65. coinex/ccxt/static_dependencies/bip/conf/bip44/bip44_conf_getter.py +153 -0
  66. coinex/ccxt/static_dependencies/bip/conf/bip49/__init__.py +3 -0
  67. coinex/ccxt/static_dependencies/bip/conf/bip49/bip49_coins.py +53 -0
  68. coinex/ccxt/static_dependencies/bip/conf/bip49/bip49_conf.py +366 -0
  69. coinex/ccxt/static_dependencies/bip/conf/bip49/bip49_conf_getter.py +80 -0
  70. coinex/ccxt/static_dependencies/bip/conf/bip84/__init__.py +3 -0
  71. coinex/ccxt/static_dependencies/bip/conf/bip84/bip84_coins.py +39 -0
  72. coinex/ccxt/static_dependencies/bip/conf/bip84/bip84_conf.py +113 -0
  73. coinex/ccxt/static_dependencies/bip/conf/bip84/bip84_conf_getter.py +66 -0
  74. coinex/ccxt/static_dependencies/bip/conf/bip86/__init__.py +3 -0
  75. coinex/ccxt/static_dependencies/bip/conf/bip86/bip86_coins.py +37 -0
  76. coinex/ccxt/static_dependencies/bip/conf/bip86/bip86_conf.py +83 -0
  77. coinex/ccxt/static_dependencies/bip/conf/bip86/bip86_conf_getter.py +64 -0
  78. coinex/ccxt/static_dependencies/bip/conf/common/__init__.py +8 -0
  79. coinex/ccxt/static_dependencies/bip/conf/common/atom_addr.py +104 -0
  80. coinex/ccxt/static_dependencies/bip/conf/common/bip_bitcoin_cash_conf.py +106 -0
  81. coinex/ccxt/static_dependencies/bip/conf/common/bip_coin_conf.py +217 -0
  82. coinex/ccxt/static_dependencies/bip/conf/common/bip_coins.py +28 -0
  83. coinex/ccxt/static_dependencies/bip/conf/common/bip_conf_const.py +30 -0
  84. coinex/ccxt/static_dependencies/bip/conf/common/bip_litecoin_conf.py +121 -0
  85. coinex/ccxt/static_dependencies/bip/ecc/__init__.py +42 -0
  86. coinex/ccxt/static_dependencies/bip/ecc/common/__init__.py +0 -0
  87. coinex/ccxt/static_dependencies/bip/ecc/common/dummy_point.py +219 -0
  88. coinex/ccxt/static_dependencies/bip/ecc/common/ikeys.py +263 -0
  89. coinex/ccxt/static_dependencies/bip/ecc/common/ipoint.py +190 -0
  90. coinex/ccxt/static_dependencies/bip/ecc/conf.py +28 -0
  91. coinex/ccxt/static_dependencies/bip/ecc/curve/__init__.py +0 -0
  92. coinex/ccxt/static_dependencies/bip/ecc/curve/elliptic_curve.py +121 -0
  93. coinex/ccxt/static_dependencies/bip/ecc/curve/elliptic_curve_getter.py +74 -0
  94. coinex/ccxt/static_dependencies/bip/ecc/curve/elliptic_curve_types.py +37 -0
  95. coinex/ccxt/static_dependencies/bip/ecc/ecdsa/__init__.py +0 -0
  96. coinex/ccxt/static_dependencies/bip/ecc/ecdsa/ecdsa_keys.py +36 -0
  97. coinex/ccxt/static_dependencies/bip/ecc/secp256k1/__init__.py +0 -0
  98. coinex/ccxt/static_dependencies/bip/ecc/secp256k1/secp256k1.py +36 -0
  99. coinex/ccxt/static_dependencies/bip/ecc/secp256k1/secp256k1_const.py +59 -0
  100. coinex/ccxt/static_dependencies/bip/ecc/secp256k1/secp256k1_keys_ecdsa.py +248 -0
  101. coinex/ccxt/static_dependencies/bip/ecc/secp256k1/secp256k1_point_ecdsa.py +234 -0
  102. coinex/ccxt/static_dependencies/bip/slip/__init__.py +0 -0
  103. coinex/ccxt/static_dependencies/bip/slip/slip173/__init__.py +1 -0
  104. coinex/ccxt/static_dependencies/bip/slip/slip173/slip173.py +60 -0
  105. coinex/ccxt/static_dependencies/bip/slip/slip32/__init__.py +4 -0
  106. coinex/ccxt/static_dependencies/bip/slip/slip32/slip32.py +322 -0
  107. coinex/ccxt/static_dependencies/bip/slip/slip32/slip32_key_net_ver.py +62 -0
  108. coinex/ccxt/static_dependencies/bip/slip/slip44/__init__.py +1 -0
  109. coinex/ccxt/static_dependencies/bip/slip/slip44/slip44.py +81 -0
  110. coinex/ccxt/static_dependencies/bip/utils/__init__.py +0 -0
  111. coinex/ccxt/static_dependencies/bip/utils/conf/__init__.py +1 -0
  112. coinex/ccxt/static_dependencies/bip/utils/conf/coin_names.py +59 -0
  113. coinex/ccxt/static_dependencies/bip/utils/crypto/__init__.py +10 -0
  114. coinex/ccxt/static_dependencies/bip/utils/crypto/aes_ecb.py +152 -0
  115. coinex/ccxt/static_dependencies/bip/utils/crypto/blake2.py +191 -0
  116. coinex/ccxt/static_dependencies/bip/utils/crypto/chacha20_poly1305.py +101 -0
  117. coinex/ccxt/static_dependencies/bip/utils/crypto/hash160.py +57 -0
  118. coinex/ccxt/static_dependencies/bip/utils/crypto/hmac.py +118 -0
  119. coinex/ccxt/static_dependencies/bip/utils/crypto/pbkdf2.py +66 -0
  120. coinex/ccxt/static_dependencies/bip/utils/crypto/ripemd.py +58 -0
  121. coinex/ccxt/static_dependencies/bip/utils/crypto/scrypt.py +66 -0
  122. coinex/ccxt/static_dependencies/bip/utils/crypto/sha2.py +182 -0
  123. coinex/ccxt/static_dependencies/bip/utils/crypto/sha3.py +99 -0
  124. coinex/ccxt/static_dependencies/bip/utils/misc/__init__.py +7 -0
  125. coinex/ccxt/static_dependencies/bip/utils/misc/algo.py +108 -0
  126. coinex/ccxt/static_dependencies/bip/utils/misc/base32.py +151 -0
  127. coinex/ccxt/static_dependencies/bip/utils/misc/bit.py +115 -0
  128. coinex/ccxt/static_dependencies/bip/utils/misc/bytes.py +200 -0
  129. coinex/ccxt/static_dependencies/bip/utils/misc/data_bytes.py +181 -0
  130. coinex/ccxt/static_dependencies/bip/utils/misc/integer.py +97 -0
  131. coinex/ccxt/static_dependencies/bip/utils/misc/string.py +54 -0
  132. coinex/ccxt/static_dependencies/bip/utils/typing/__init__.py +1 -0
  133. coinex/ccxt/static_dependencies/bip/utils/typing/literal.py +27 -0
  134. coinex/ccxt/static_dependencies/bip/wif/__init__.py +1 -0
  135. coinex/ccxt/static_dependencies/bip/wif/wif.py +144 -0
  136. coinex/ccxt/static_dependencies/dydx_v4_client/amino/amino_pb2.py +31 -0
  137. coinex/ccxt/static_dependencies/dydx_v4_client/cosmos/base/v1beta1/coin_pb2.py +47 -0
  138. coinex/ccxt/static_dependencies/dydx_v4_client/cosmos/crypto/multisig/keys_pb2.py +33 -0
  139. coinex/ccxt/static_dependencies/dydx_v4_client/cosmos/crypto/multisig/v1beta1/multisig_pb2.py +33 -0
  140. coinex/ccxt/static_dependencies/dydx_v4_client/cosmos/crypto/secp256k1/keys_pb2.py +34 -0
  141. coinex/ccxt/static_dependencies/dydx_v4_client/cosmos/msg/v1/msg_pb2.py +27 -0
  142. coinex/ccxt/static_dependencies/dydx_v4_client/cosmos/tx/signing/v1beta1/signing_pb2.py +38 -0
  143. coinex/ccxt/static_dependencies/dydx_v4_client/cosmos/tx/v1beta1/tx_pb2.py +75 -0
  144. coinex/ccxt/static_dependencies/dydx_v4_client/cosmos_proto/cosmos_pb2.py +36 -0
  145. coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/accountplus/accountplus_pb2.py +31 -0
  146. coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/accountplus/genesis_pb2.py +40 -0
  147. coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/accountplus/models_pb2.py +26 -0
  148. coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/accountplus/params_pb2.py +29 -0
  149. coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/accountplus/query_pb2.py +57 -0
  150. coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/accountplus/tx_pb2.py +51 -0
  151. coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/block_rate_limit_config_pb2.py +37 -0
  152. coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/clob_pair_pb2.py +41 -0
  153. coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/equity_tier_limit_config_pb2.py +35 -0
  154. coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/finalize_block_pb2.py +27 -0
  155. coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/liquidations_config_pb2.py +39 -0
  156. coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/liquidations_pb2.py +38 -0
  157. coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/matches_pb2.py +55 -0
  158. coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/mev_pb2.py +49 -0
  159. coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/operation_pb2.py +32 -0
  160. coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/order_pb2.py +86 -0
  161. coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/order_removals_pb2.py +32 -0
  162. coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/process_proposer_matches_events_pb2.py +42 -0
  163. coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/query_pb2.py +124 -0
  164. coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/streaming_pb2.py +29 -0
  165. coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/clob/tx_pb2.py +117 -0
  166. coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/sending/genesis_pb2.py +26 -0
  167. coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/sending/query_pb2.py +26 -0
  168. coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/sending/transfer_pb2.py +61 -0
  169. coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/sending/tx_pb2.py +37 -0
  170. coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/subaccounts/asset_position_pb2.py +29 -0
  171. coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/subaccounts/genesis_pb2.py +30 -0
  172. coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/subaccounts/perpetual_position_pb2.py +33 -0
  173. coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/subaccounts/query_pb2.py +63 -0
  174. coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/subaccounts/streaming_pb2.py +31 -0
  175. coinex/ccxt/static_dependencies/dydx_v4_client/dydxprotocol/subaccounts/subaccount_pb2.py +33 -0
  176. coinex/ccxt/static_dependencies/dydx_v4_client/gogoproto/gogo_pb2.py +102 -0
  177. coinex/ccxt/static_dependencies/dydx_v4_client/registry.py +38 -0
  178. coinex/ccxt/static_dependencies/ecdsa/ellipticcurve.py +842 -0
  179. coinex/ccxt/static_dependencies/ecdsa/keys.py +15 -4
  180. coinex/ccxt/static_dependencies/mnemonic/__init__.py +4 -0
  181. coinex/ccxt/static_dependencies/mnemonic/mnemonic.py +282 -0
  182. coinex/ccxt/static_dependencies/mnemonic/py.typed +1 -0
  183. coinex/ccxt/static_dependencies/mnemonic/wordlist/chinese_simplified.txt +2048 -0
  184. coinex/ccxt/static_dependencies/mnemonic/wordlist/chinese_traditional.txt +2048 -0
  185. coinex/ccxt/static_dependencies/mnemonic/wordlist/czech.txt +2048 -0
  186. coinex/ccxt/static_dependencies/mnemonic/wordlist/english.txt +2048 -0
  187. coinex/ccxt/static_dependencies/mnemonic/wordlist/french.txt +2048 -0
  188. coinex/ccxt/static_dependencies/mnemonic/wordlist/italian.txt +2048 -0
  189. coinex/ccxt/static_dependencies/mnemonic/wordlist/japanese.txt +2048 -0
  190. coinex/ccxt/static_dependencies/mnemonic/wordlist/korean.txt +2048 -0
  191. coinex/ccxt/static_dependencies/mnemonic/wordlist/portuguese.txt +2048 -0
  192. coinex/ccxt/static_dependencies/mnemonic/wordlist/russian.txt +2048 -0
  193. coinex/ccxt/static_dependencies/mnemonic/wordlist/spanish.txt +2048 -0
  194. coinex/ccxt/static_dependencies/mnemonic/wordlist/turkish.txt +2048 -0
  195. {coinex_api-0.0.89.dist-info → coinex_api-0.0.110.dist-info}/METADATA +3 -3
  196. {coinex_api-0.0.89.dist-info → coinex_api-0.0.110.dist-info}/RECORD +197 -17
  197. {coinex_api-0.0.89.dist-info → coinex_api-0.0.110.dist-info}/WHEEL +1 -1
@@ -192,6 +192,848 @@ class Point(object):
192
192
  def order(self):
193
193
  return self.__order
194
194
 
195
+ class AbstractPoint(object):
196
+ """Class for common methods of elliptic curve points."""
197
+
198
+ @staticmethod
199
+ def _from_raw_encoding(data, raw_encoding_length):
200
+ """
201
+ Decode public point from :term:`raw encoding`.
202
+
203
+ :term:`raw encoding` is the same as the :term:`uncompressed` encoding,
204
+ but without the 0x04 byte at the beginning.
205
+ """
206
+ # real assert, from_bytes() should not call us with different length
207
+ assert len(data) == raw_encoding_length
208
+ xs = data[: raw_encoding_length // 2]
209
+ ys = data[raw_encoding_length // 2 :]
210
+ # real assert, raw_encoding_length is calculated by multiplying an
211
+ # integer by two so it will always be even
212
+ assert len(xs) == raw_encoding_length // 2
213
+ assert len(ys) == raw_encoding_length // 2
214
+ coord_x = string_to_number(xs)
215
+ coord_y = string_to_number(ys)
216
+
217
+ return coord_x, coord_y
218
+
219
+ @staticmethod
220
+ def _from_compressed(data, curve):
221
+ """Decode public point from compressed encoding."""
222
+ if data[:1] not in (b"\x02", b"\x03"):
223
+ raise MalformedPointError("Malformed compressed point encoding")
224
+
225
+ is_even = data[:1] == b"\x02"
226
+ x = string_to_number(data[1:])
227
+ p = curve.p()
228
+ alpha = (pow(x, 3, p) + (curve.a() * x) + curve.b()) % p
229
+ try:
230
+ beta = numbertheory.square_root_mod_prime(alpha, p)
231
+ except numbertheory.Error as e:
232
+ raise MalformedPointError(
233
+ "Encoding does not correspond to a point on curve", e
234
+ )
235
+ if is_even == bool(beta & 1):
236
+ y = p - beta
237
+ else:
238
+ y = beta
239
+ return x, y
240
+
241
+ @classmethod
242
+ def _from_hybrid(cls, data, raw_encoding_length, validate_encoding):
243
+ """Decode public point from hybrid encoding."""
244
+ # real assert, from_bytes() should not call us with different types
245
+ assert data[:1] in (b"\x06", b"\x07")
246
+
247
+ # primarily use the uncompressed as it's easiest to handle
248
+ x, y = cls._from_raw_encoding(data[1:], raw_encoding_length)
249
+
250
+ # but validate if it's self-consistent if we're asked to do that
251
+ if validate_encoding and (
252
+ y & 1
253
+ and data[:1] != b"\x07"
254
+ or (not y & 1)
255
+ and data[:1] != b"\x06"
256
+ ):
257
+ raise MalformedPointError("Inconsistent hybrid point encoding")
258
+
259
+ return x, y
260
+
261
+ @classmethod
262
+ def _from_edwards(cls, curve, data):
263
+ """Decode a point on an Edwards curve."""
264
+ data = bytearray(data)
265
+ p = curve.p()
266
+ # add 1 for the sign bit and then round up
267
+ exp_len = (bit_length(p) + 1 + 7) // 8
268
+ if len(data) != exp_len:
269
+ raise MalformedPointError("Point length doesn't match the curve.")
270
+ x_0 = (data[-1] & 0x80) >> 7
271
+
272
+ data[-1] &= 0x80 - 1
273
+
274
+ y = bytes_to_int(data, "little")
275
+ if GMPY:
276
+ y = mpz(y)
277
+
278
+ x2 = (
279
+ (y * y - 1)
280
+ * numbertheory.inverse_mod(curve.d() * y * y - curve.a(), p)
281
+ % p
282
+ )
283
+
284
+ try:
285
+ x = numbertheory.square_root_mod_prime(x2, p)
286
+ except numbertheory.Error as e:
287
+ raise MalformedPointError(
288
+ "Encoding does not correspond to a point on curve", e
289
+ )
290
+
291
+ if x % 2 != x_0:
292
+ x = -x % p
293
+
294
+ return x, y
295
+
296
+ @classmethod
297
+ def from_bytes(
298
+ cls, curve, data, validate_encoding=True, valid_encodings=None
299
+ ):
300
+ """
301
+ Initialise the object from byte encoding of a point.
302
+
303
+ The method does accept and automatically detect the type of point
304
+ encoding used. It supports the :term:`raw encoding`,
305
+ :term:`uncompressed`, :term:`compressed`, and :term:`hybrid` encodings.
306
+
307
+ Note: generally you will want to call the ``from_bytes()`` method of
308
+ either a child class, PointJacobi or Point.
309
+
310
+ :param data: single point encoding of the public key
311
+ :type data: :term:`bytes-like object`
312
+ :param curve: the curve on which the public key is expected to lay
313
+ :type curve: ~ecdsa.ellipticcurve.CurveFp
314
+ :param validate_encoding: whether to verify that the encoding of the
315
+ point is self-consistent, defaults to True, has effect only
316
+ on ``hybrid`` encoding
317
+ :type validate_encoding: bool
318
+ :param valid_encodings: list of acceptable point encoding formats,
319
+ supported ones are: :term:`uncompressed`, :term:`compressed`,
320
+ :term:`hybrid`, and :term:`raw encoding` (specified with ``raw``
321
+ name). All formats by default (specified with ``None``).
322
+ :type valid_encodings: :term:`set-like object`
323
+
324
+ :raises `~ecdsa.errors.MalformedPointError`: if the public point does
325
+ not lay on the curve or the encoding is invalid
326
+
327
+ :return: x and y coordinates of the encoded point
328
+ :rtype: tuple(int, int)
329
+ """
330
+ if not valid_encodings:
331
+ valid_encodings = set(
332
+ ["uncompressed", "compressed", "hybrid", "raw"]
333
+ )
334
+ if not all(
335
+ i in set(("uncompressed", "compressed", "hybrid", "raw"))
336
+ for i in valid_encodings
337
+ ):
338
+ raise ValueError(
339
+ "Only uncompressed, compressed, hybrid or raw encoding "
340
+ "supported."
341
+ )
342
+ data = normalise_bytes(data)
343
+
344
+ if isinstance(curve, CurveEdTw):
345
+ return cls._from_edwards(curve, data)
346
+
347
+ key_len = len(data)
348
+ raw_encoding_length = 2 * orderlen(curve.p())
349
+ if key_len == raw_encoding_length and "raw" in valid_encodings:
350
+ coord_x, coord_y = cls._from_raw_encoding(
351
+ data, raw_encoding_length
352
+ )
353
+ elif key_len == raw_encoding_length + 1 and (
354
+ "hybrid" in valid_encodings or "uncompressed" in valid_encodings
355
+ ):
356
+ if data[:1] in (b"\x06", b"\x07") and "hybrid" in valid_encodings:
357
+ coord_x, coord_y = cls._from_hybrid(
358
+ data, raw_encoding_length, validate_encoding
359
+ )
360
+ elif data[:1] == b"\x04" and "uncompressed" in valid_encodings:
361
+ coord_x, coord_y = cls._from_raw_encoding(
362
+ data[1:], raw_encoding_length
363
+ )
364
+ else:
365
+ raise MalformedPointError(
366
+ "Invalid X9.62 encoding of the public point"
367
+ )
368
+ elif (
369
+ key_len == raw_encoding_length // 2 + 1
370
+ and "compressed" in valid_encodings
371
+ ):
372
+ coord_x, coord_y = cls._from_compressed(data, curve)
373
+ else:
374
+ raise MalformedPointError(
375
+ "Length of string does not match lengths of "
376
+ "any of the enabled ({0}) encodings of the "
377
+ "curve.".format(", ".join(valid_encodings))
378
+ )
379
+ return coord_x, coord_y
380
+
381
+ def _raw_encode(self):
382
+ """Convert the point to the :term:`raw encoding`."""
383
+ prime = self.curve().p()
384
+ x_str = number_to_string(self.x(), prime)
385
+ y_str = number_to_string(self.y(), prime)
386
+ return x_str + y_str
387
+
388
+ def _compressed_encode(self):
389
+ """Encode the point into the compressed form."""
390
+ prime = self.curve().p()
391
+ x_str = number_to_string(self.x(), prime)
392
+ if self.y() & 1:
393
+ return b"\x03" + x_str
394
+ return b"\x02" + x_str
395
+
396
+ def _hybrid_encode(self):
397
+ """Encode the point into the hybrid form."""
398
+ raw_enc = self._raw_encode()
399
+ if self.y() & 1:
400
+ return b"\x07" + raw_enc
401
+ return b"\x06" + raw_enc
402
+
403
+ def _edwards_encode(self):
404
+ """Encode the point according to RFC8032 encoding."""
405
+ self.scale()
406
+ x, y, p = self.x(), self.y(), self.curve().p()
407
+
408
+ # add 1 for the sign bit and then round up
409
+ enc_len = (bit_length(p) + 1 + 7) // 8
410
+ y_str = int_to_bytes(y, enc_len, "little")
411
+ if x % 2:
412
+ y_str[-1] |= 0x80
413
+ return y_str
414
+
415
+ def to_bytes(self, encoding="raw"):
416
+ """
417
+ Convert the point to a byte string.
418
+
419
+ The method by default uses the :term:`raw encoding` (specified
420
+ by `encoding="raw"`. It can also output points in :term:`uncompressed`,
421
+ :term:`compressed`, and :term:`hybrid` formats.
422
+
423
+ For points on Edwards curves `encoding` is ignored and only the
424
+ encoding defined in RFC 8032 is supported.
425
+
426
+ :return: :term:`raw encoding` of a public on the curve
427
+ :rtype: bytes
428
+ """
429
+ assert encoding in ("raw", "uncompressed", "compressed", "hybrid")
430
+ curve = self.curve()
431
+ if isinstance(curve, CurveEdTw):
432
+ return self._edwards_encode()
433
+ elif encoding == "raw":
434
+ return self._raw_encode()
435
+ elif encoding == "uncompressed":
436
+ return b"\x04" + self._raw_encode()
437
+ elif encoding == "hybrid":
438
+ return self._hybrid_encode()
439
+ else:
440
+ return self._compressed_encode()
441
+
442
+ @staticmethod
443
+ def _naf(mult):
444
+ """Calculate non-adjacent form of number."""
445
+ ret = []
446
+ while mult:
447
+ if mult % 2:
448
+ nd = mult % 4
449
+ if nd >= 2:
450
+ nd -= 4
451
+ ret.append(nd)
452
+ mult -= nd
453
+ else:
454
+ ret.append(0)
455
+ mult //= 2
456
+ return ret
457
+
458
+
459
+ class PointJacobi(AbstractPoint):
460
+ """
461
+ Point on a short Weierstrass elliptic curve. Uses Jacobi coordinates.
462
+
463
+ In Jacobian coordinates, there are three parameters, X, Y and Z.
464
+ They correspond to affine parameters 'x' and 'y' like so:
465
+
466
+ x = X / Z²
467
+ y = Y / Z³
468
+ """
469
+
470
+ def __init__(self, curve, x, y, z, order=None, generator=False):
471
+ """
472
+ Initialise a point that uses Jacobi representation internally.
473
+
474
+ :param CurveFp curve: curve on which the point resides
475
+ :param int x: the X parameter of Jacobi representation (equal to x when
476
+ converting from affine coordinates
477
+ :param int y: the Y parameter of Jacobi representation (equal to y when
478
+ converting from affine coordinates
479
+ :param int z: the Z parameter of Jacobi representation (equal to 1 when
480
+ converting from affine coordinates
481
+ :param int order: the point order, must be non zero when using
482
+ generator=True
483
+ :param bool generator: the point provided is a curve generator, as
484
+ such, it will be commonly used with scalar multiplication. This will
485
+ cause to precompute multiplication table generation for it
486
+ """
487
+ super(PointJacobi, self).__init__()
488
+ self.__curve = curve
489
+ if GMPY: # pragma: no branch
490
+ self.__coords = (mpz(x), mpz(y), mpz(z))
491
+ self.__order = order and mpz(order)
492
+ else: # pragma: no branch
493
+ self.__coords = (x, y, z)
494
+ self.__order = order
495
+ self.__generator = generator
496
+ self.__precompute = []
497
+
498
+ @classmethod
499
+ def from_bytes(
500
+ cls,
501
+ curve,
502
+ data,
503
+ validate_encoding=True,
504
+ valid_encodings=None,
505
+ order=None,
506
+ generator=False,
507
+ ):
508
+ """
509
+ Initialise the object from byte encoding of a point.
510
+
511
+ The method does accept and automatically detect the type of point
512
+ encoding used. It supports the :term:`raw encoding`,
513
+ :term:`uncompressed`, :term:`compressed`, and :term:`hybrid` encodings.
514
+
515
+ :param data: single point encoding of the public key
516
+ :type data: :term:`bytes-like object`
517
+ :param curve: the curve on which the public key is expected to lay
518
+ :type curve: ~ecdsa.ellipticcurve.CurveFp
519
+ :param validate_encoding: whether to verify that the encoding of the
520
+ point is self-consistent, defaults to True, has effect only
521
+ on ``hybrid`` encoding
522
+ :type validate_encoding: bool
523
+ :param valid_encodings: list of acceptable point encoding formats,
524
+ supported ones are: :term:`uncompressed`, :term:`compressed`,
525
+ :term:`hybrid`, and :term:`raw encoding` (specified with ``raw``
526
+ name). All formats by default (specified with ``None``).
527
+ :type valid_encodings: :term:`set-like object`
528
+ :param int order: the point order, must be non zero when using
529
+ generator=True
530
+ :param bool generator: the point provided is a curve generator, as
531
+ such, it will be commonly used with scalar multiplication. This
532
+ will cause to precompute multiplication table generation for it
533
+
534
+ :raises `~ecdsa.errors.MalformedPointError`: if the public point does
535
+ not lay on the curve or the encoding is invalid
536
+
537
+ :return: Point on curve
538
+ :rtype: PointJacobi
539
+ """
540
+ coord_x, coord_y = super(PointJacobi, cls).from_bytes(
541
+ curve, data, validate_encoding, valid_encodings
542
+ )
543
+ return PointJacobi(curve, coord_x, coord_y, 1, order, generator)
544
+
545
+ def _maybe_precompute(self):
546
+ if not self.__generator or self.__precompute:
547
+ return
548
+
549
+ # since this code will execute just once, and it's fully deterministic,
550
+ # depend on atomicity of the last assignment to switch from empty
551
+ # self.__precompute to filled one and just ignore the unlikely
552
+ # situation when two threads execute it at the same time (as it won't
553
+ # lead to inconsistent __precompute)
554
+ order = self.__order
555
+ assert order
556
+ precompute = []
557
+ i = 1
558
+ order *= 2
559
+ coord_x, coord_y, coord_z = self.__coords
560
+ doubler = PointJacobi(self.__curve, coord_x, coord_y, coord_z, order)
561
+ order *= 2
562
+ precompute.append((doubler.x(), doubler.y()))
563
+
564
+ while i < order:
565
+ i *= 2
566
+ doubler = doubler.double().scale()
567
+ precompute.append((doubler.x(), doubler.y()))
568
+
569
+ self.__precompute = precompute
570
+
571
+ def __getstate__(self):
572
+ # while this code can execute at the same time as _maybe_precompute()
573
+ # is updating the __precompute or scale() is updating the __coords,
574
+ # there is no requirement for consistency between __coords and
575
+ # __precompute
576
+ state = self.__dict__.copy()
577
+ return state
578
+
579
+ def __setstate__(self, state):
580
+ self.__dict__.update(state)
581
+
582
+ def __eq__(self, other):
583
+ """Compare for equality two points with each-other.
584
+
585
+ Note: only points that lay on the same curve can be equal.
586
+ """
587
+ x1, y1, z1 = self.__coords
588
+ if other is INFINITY:
589
+ return not z1
590
+ if isinstance(other, Point):
591
+ x2, y2, z2 = other.x(), other.y(), 1
592
+ elif isinstance(other, PointJacobi):
593
+ x2, y2, z2 = other.__coords
594
+ else:
595
+ return NotImplemented
596
+ if self.__curve != other.curve():
597
+ return False
598
+ p = self.__curve.p()
599
+
600
+ zz1 = z1 * z1 % p
601
+ zz2 = z2 * z2 % p
602
+
603
+ # compare the fractions by bringing them to the same denominator
604
+ # depend on short-circuit to save 4 multiplications in case of
605
+ # inequality
606
+ return (x1 * zz2 - x2 * zz1) % p == 0 and (
607
+ y1 * zz2 * z2 - y2 * zz1 * z1
608
+ ) % p == 0
609
+
610
+ def __ne__(self, other):
611
+ """Compare for inequality two points with each-other."""
612
+ return not self == other
613
+
614
+ def order(self):
615
+ """Return the order of the point.
616
+
617
+ None if it is undefined.
618
+ """
619
+ return self.__order
620
+
621
+ def curve(self):
622
+ """Return curve over which the point is defined."""
623
+ return self.__curve
624
+
625
+ def x(self):
626
+ """
627
+ Return affine x coordinate.
628
+
629
+ This method should be used only when the 'y' coordinate is not needed.
630
+ It's computationally more efficient to use `to_affine()` and then
631
+ call x() and y() on the returned instance. Or call `scale()`
632
+ and then x() and y() on the returned instance.
633
+ """
634
+ x, _, z = self.__coords
635
+ if z == 1:
636
+ return x
637
+ p = self.__curve.p()
638
+ z = numbertheory.inverse_mod(z, p)
639
+ return x * z**2 % p
640
+
641
+ def y(self):
642
+ """
643
+ Return affine y coordinate.
644
+
645
+ This method should be used only when the 'x' coordinate is not needed.
646
+ It's computationally more efficient to use `to_affine()` and then
647
+ call x() and y() on the returned instance. Or call `scale()`
648
+ and then x() and y() on the returned instance.
649
+ """
650
+ _, y, z = self.__coords
651
+ if z == 1:
652
+ return y
653
+ p = self.__curve.p()
654
+ z = numbertheory.inverse_mod(z, p)
655
+ return y * z**3 % p
656
+
657
+ def scale(self):
658
+ """
659
+ Return point scaled so that z == 1.
660
+
661
+ Modifies point in place, returns self.
662
+ """
663
+ x, y, z = self.__coords
664
+ if z == 1:
665
+ return self
666
+
667
+ # scaling is deterministic, so even if two threads execute the below
668
+ # code at the same time, they will set __coords to the same value
669
+ p = self.__curve.p()
670
+ z_inv = numbertheory.inverse_mod(z, p)
671
+ zz_inv = z_inv * z_inv % p
672
+ x = x * zz_inv % p
673
+ y = y * zz_inv * z_inv % p
674
+ self.__coords = (x, y, 1)
675
+ return self
676
+
677
+ def to_affine(self):
678
+ """Return point in affine form."""
679
+ _, _, z = self.__coords
680
+ p = self.__curve.p()
681
+ if not (z % p):
682
+ return INFINITY
683
+ self.scale()
684
+ x, y, z = self.__coords
685
+ assert z == 1
686
+ return Point(self.__curve, x, y, self.__order)
687
+
688
+ @staticmethod
689
+ def from_affine(point, generator=False):
690
+ """Create from an affine point.
691
+
692
+ :param bool generator: set to True to make the point to precalculate
693
+ multiplication table - useful for public point when verifying many
694
+ signatures (around 100 or so) or for generator points of a curve.
695
+ """
696
+ return PointJacobi(
697
+ point.curve(), point.x(), point.y(), 1, point.order(), generator
698
+ )
699
+
700
+ # please note that all the methods that use the equations from
701
+ # hyperelliptic
702
+ # are formatted in a way to maximise performance.
703
+ # Things that make code faster: multiplying instead of taking to the power
704
+ # (`xx = x * x; xxxx = xx * xx % p` is faster than `xxxx = x**4 % p` and
705
+ # `pow(x, 4, p)`),
706
+ # multiple assignments at the same time (`x1, x2 = self.x1, self.x2` is
707
+ # faster than `x1 = self.x1; x2 = self.x2`),
708
+ # similarly, sometimes the `% p` is skipped if it makes the calculation
709
+ # faster and the result of calculation is later reduced modulo `p`
710
+
711
+ def _double_with_z_1(self, X1, Y1, p, a):
712
+ """Add a point to itself with z == 1."""
713
+ # after:
714
+ # http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#doubling-mdbl-2007-bl
715
+ XX, YY = X1 * X1 % p, Y1 * Y1 % p
716
+ if not YY:
717
+ return 0, 0, 0
718
+ YYYY = YY * YY % p
719
+ S = 2 * ((X1 + YY) ** 2 - XX - YYYY) % p
720
+ M = 3 * XX + a
721
+ T = (M * M - 2 * S) % p
722
+ # X3 = T
723
+ Y3 = (M * (S - T) - 8 * YYYY) % p
724
+ Z3 = 2 * Y1 % p
725
+ return T, Y3, Z3
726
+
727
+ def _double(self, X1, Y1, Z1, p, a):
728
+ """Add a point to itself, arbitrary z."""
729
+ if Z1 == 1:
730
+ return self._double_with_z_1(X1, Y1, p, a)
731
+ if not Z1:
732
+ return 0, 0, 0
733
+ # after:
734
+ # http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#doubling-dbl-2007-bl
735
+ XX, YY = X1 * X1 % p, Y1 * Y1 % p
736
+ if not YY:
737
+ return 0, 0, 0
738
+ YYYY = YY * YY % p
739
+ ZZ = Z1 * Z1 % p
740
+ S = 2 * ((X1 + YY) ** 2 - XX - YYYY) % p
741
+ M = (3 * XX + a * ZZ * ZZ) % p
742
+ T = (M * M - 2 * S) % p
743
+ # X3 = T
744
+ Y3 = (M * (S - T) - 8 * YYYY) % p
745
+ Z3 = ((Y1 + Z1) ** 2 - YY - ZZ) % p
746
+
747
+ return T, Y3, Z3
748
+
749
+ def double(self):
750
+ """Add a point to itself."""
751
+ X1, Y1, Z1 = self.__coords
752
+
753
+ if not Z1:
754
+ return INFINITY
755
+
756
+ p, a = self.__curve.p(), self.__curve.a()
757
+
758
+ X3, Y3, Z3 = self._double(X1, Y1, Z1, p, a)
759
+
760
+ if not Z3:
761
+ return INFINITY
762
+ return PointJacobi(self.__curve, X3, Y3, Z3, self.__order)
763
+
764
+ def _add_with_z_1(self, X1, Y1, X2, Y2, p):
765
+ """add points when both Z1 and Z2 equal 1"""
766
+ # after:
767
+ # http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#addition-mmadd-2007-bl
768
+ H = X2 - X1
769
+ HH = H * H
770
+ I = 4 * HH % p
771
+ J = H * I
772
+ r = 2 * (Y2 - Y1)
773
+ if not H and not r:
774
+ return self._double_with_z_1(X1, Y1, p, self.__curve.a())
775
+ V = X1 * I
776
+ X3 = (r**2 - J - 2 * V) % p
777
+ Y3 = (r * (V - X3) - 2 * Y1 * J) % p
778
+ Z3 = 2 * H % p
779
+ return X3, Y3, Z3
780
+
781
+ def _add_with_z_eq(self, X1, Y1, Z1, X2, Y2, p):
782
+ """add points when Z1 == Z2"""
783
+ # after:
784
+ # http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#addition-zadd-2007-m
785
+ A = (X2 - X1) ** 2 % p
786
+ B = X1 * A % p
787
+ C = X2 * A
788
+ D = (Y2 - Y1) ** 2 % p
789
+ if not A and not D:
790
+ return self._double(X1, Y1, Z1, p, self.__curve.a())
791
+ X3 = (D - B - C) % p
792
+ Y3 = ((Y2 - Y1) * (B - X3) - Y1 * (C - B)) % p
793
+ Z3 = Z1 * (X2 - X1) % p
794
+ return X3, Y3, Z3
795
+
796
+ def _add_with_z2_1(self, X1, Y1, Z1, X2, Y2, p):
797
+ """add points when Z2 == 1"""
798
+ # after:
799
+ # http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#addition-madd-2007-bl
800
+ Z1Z1 = Z1 * Z1 % p
801
+ U2, S2 = X2 * Z1Z1 % p, Y2 * Z1 * Z1Z1 % p
802
+ H = (U2 - X1) % p
803
+ HH = H * H % p
804
+ I = 4 * HH % p
805
+ J = H * I
806
+ r = 2 * (S2 - Y1) % p
807
+ if not r and not H:
808
+ return self._double_with_z_1(X2, Y2, p, self.__curve.a())
809
+ V = X1 * I
810
+ X3 = (r * r - J - 2 * V) % p
811
+ Y3 = (r * (V - X3) - 2 * Y1 * J) % p
812
+ Z3 = ((Z1 + H) ** 2 - Z1Z1 - HH) % p
813
+ return X3, Y3, Z3
814
+
815
+ def _add_with_z_ne(self, X1, Y1, Z1, X2, Y2, Z2, p):
816
+ """add points with arbitrary z"""
817
+ # after:
818
+ # http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#addition-add-2007-bl
819
+ Z1Z1 = Z1 * Z1 % p
820
+ Z2Z2 = Z2 * Z2 % p
821
+ U1 = X1 * Z2Z2 % p
822
+ U2 = X2 * Z1Z1 % p
823
+ S1 = Y1 * Z2 * Z2Z2 % p
824
+ S2 = Y2 * Z1 * Z1Z1 % p
825
+ H = U2 - U1
826
+ I = 4 * H * H % p
827
+ J = H * I % p
828
+ r = 2 * (S2 - S1) % p
829
+ if not H and not r:
830
+ return self._double(X1, Y1, Z1, p, self.__curve.a())
831
+ V = U1 * I
832
+ X3 = (r * r - J - 2 * V) % p
833
+ Y3 = (r * (V - X3) - 2 * S1 * J) % p
834
+ Z3 = ((Z1 + Z2) ** 2 - Z1Z1 - Z2Z2) * H % p
835
+
836
+ return X3, Y3, Z3
837
+
838
+ def __radd__(self, other):
839
+ """Add other to self."""
840
+ return self + other
841
+
842
+ def _add(self, X1, Y1, Z1, X2, Y2, Z2, p):
843
+ """add two points, select fastest method."""
844
+ if not Z1:
845
+ return X2 % p, Y2 % p, Z2 % p
846
+ if not Z2:
847
+ return X1 % p, Y1 % p, Z1 % p
848
+ if Z1 == Z2:
849
+ if Z1 == 1:
850
+ return self._add_with_z_1(X1, Y1, X2, Y2, p)
851
+ return self._add_with_z_eq(X1, Y1, Z1, X2, Y2, p)
852
+ if Z1 == 1:
853
+ return self._add_with_z2_1(X2, Y2, Z2, X1, Y1, p)
854
+ if Z2 == 1:
855
+ return self._add_with_z2_1(X1, Y1, Z1, X2, Y2, p)
856
+ return self._add_with_z_ne(X1, Y1, Z1, X2, Y2, Z2, p)
857
+
858
+ def __add__(self, other):
859
+ """Add two points on elliptic curve."""
860
+ if self == INFINITY:
861
+ return other
862
+ if other == INFINITY:
863
+ return self
864
+ if isinstance(other, Point):
865
+ other = PointJacobi.from_affine(other)
866
+ if self.__curve != other.__curve:
867
+ raise ValueError("The other point is on different curve")
868
+
869
+ p = self.__curve.p()
870
+ X1, Y1, Z1 = self.__coords
871
+ X2, Y2, Z2 = other.__coords
872
+
873
+ X3, Y3, Z3 = self._add(X1, Y1, Z1, X2, Y2, Z2, p)
874
+
875
+ if not Z3:
876
+ return INFINITY
877
+ return PointJacobi(self.__curve, X3, Y3, Z3, self.__order)
878
+
879
+ def __rmul__(self, other):
880
+ """Multiply point by an integer."""
881
+ return self * other
882
+
883
+ def _mul_precompute(self, other):
884
+ """Multiply point by integer with precomputation table."""
885
+ X3, Y3, Z3, p = 0, 0, 0, self.__curve.p()
886
+ _add = self._add
887
+ for X2, Y2 in self.__precompute:
888
+ if other % 2:
889
+ if other % 4 >= 2:
890
+ other = (other + 1) // 2
891
+ X3, Y3, Z3 = _add(X3, Y3, Z3, X2, -Y2, 1, p)
892
+ else:
893
+ other = (other - 1) // 2
894
+ X3, Y3, Z3 = _add(X3, Y3, Z3, X2, Y2, 1, p)
895
+ else:
896
+ other //= 2
897
+
898
+ if not Z3:
899
+ return INFINITY
900
+ return PointJacobi(self.__curve, X3, Y3, Z3, self.__order)
901
+
902
+ def __mul__(self, other):
903
+ """Multiply point by an integer."""
904
+ if not self.__coords[1] or not other:
905
+ return INFINITY
906
+ if other == 1:
907
+ return self
908
+ if self.__order:
909
+ # order*2 as a protection for Minerva
910
+ other = other % (self.__order * 2)
911
+ self._maybe_precompute()
912
+ if self.__precompute:
913
+ return self._mul_precompute(other)
914
+
915
+ self = self.scale()
916
+ X2, Y2, _ = self.__coords
917
+ X3, Y3, Z3 = 0, 0, 0
918
+ p, a = self.__curve.p(), self.__curve.a()
919
+ _double = self._double
920
+ _add = self._add
921
+ # since adding points when at least one of them is scaled
922
+ # is quicker, reverse the NAF order
923
+ for i in reversed(self._naf(other)):
924
+ X3, Y3, Z3 = _double(X3, Y3, Z3, p, a)
925
+ if i < 0:
926
+ X3, Y3, Z3 = _add(X3, Y3, Z3, X2, -Y2, 1, p)
927
+ elif i > 0:
928
+ X3, Y3, Z3 = _add(X3, Y3, Z3, X2, Y2, 1, p)
929
+
930
+ if not Z3:
931
+ return INFINITY
932
+
933
+ return PointJacobi(self.__curve, X3, Y3, Z3, self.__order)
934
+
935
+ def mul_add(self, self_mul, other, other_mul):
936
+ """
937
+ Do two multiplications at the same time, add results.
938
+
939
+ calculates self*self_mul + other*other_mul
940
+ """
941
+ if other == INFINITY or other_mul == 0:
942
+ return self * self_mul
943
+ if self_mul == 0:
944
+ return other * other_mul
945
+ if not isinstance(other, PointJacobi):
946
+ other = PointJacobi.from_affine(other)
947
+ # when the points have precomputed answers, then multiplying them alone
948
+ # is faster (as it uses NAF and no point doublings)
949
+ self._maybe_precompute()
950
+ other._maybe_precompute()
951
+ if self.__precompute and other.__precompute:
952
+ return self * self_mul + other * other_mul
953
+
954
+ if self.__order:
955
+ self_mul = self_mul % self.__order
956
+ other_mul = other_mul % self.__order
957
+
958
+ # (X3, Y3, Z3) is the accumulator
959
+ X3, Y3, Z3 = 0, 0, 0
960
+ p, a = self.__curve.p(), self.__curve.a()
961
+
962
+ # as we have 6 unique points to work with, we can't scale all of them,
963
+ # but do scale the ones that are used most often
964
+ self.scale()
965
+ X1, Y1, Z1 = self.__coords
966
+ other.scale()
967
+ X2, Y2, Z2 = other.__coords
968
+
969
+ _double = self._double
970
+ _add = self._add
971
+
972
+ # with NAF we have 3 options: no add, subtract, add
973
+ # so with 2 points, we have 9 combinations:
974
+ # 0, -A, +A, -B, -A-B, +A-B, +B, -A+B, +A+B
975
+ # so we need 4 combined points:
976
+ mAmB_X, mAmB_Y, mAmB_Z = _add(X1, -Y1, Z1, X2, -Y2, Z2, p)
977
+ pAmB_X, pAmB_Y, pAmB_Z = _add(X1, Y1, Z1, X2, -Y2, Z2, p)
978
+ mApB_X, mApB_Y, mApB_Z = pAmB_X, -pAmB_Y, pAmB_Z
979
+ pApB_X, pApB_Y, pApB_Z = mAmB_X, -mAmB_Y, mAmB_Z
980
+ # when the self and other sum to infinity, we need to add them
981
+ # one by one to get correct result but as that's very unlikely to
982
+ # happen in regular operation, we don't need to optimise this case
983
+ if not pApB_Z:
984
+ return self * self_mul + other * other_mul
985
+
986
+ # gmp object creation has cumulatively higher overhead than the
987
+ # speedup we get from calculating the NAF using gmp so ensure use
988
+ # of int()
989
+ self_naf = list(reversed(self._naf(int(self_mul))))
990
+ other_naf = list(reversed(self._naf(int(other_mul))))
991
+ # ensure that the lists are the same length (zip() will truncate
992
+ # longer one otherwise)
993
+ if len(self_naf) < len(other_naf):
994
+ self_naf = [0] * (len(other_naf) - len(self_naf)) + self_naf
995
+ elif len(self_naf) > len(other_naf):
996
+ other_naf = [0] * (len(self_naf) - len(other_naf)) + other_naf
997
+
998
+ for A, B in zip(self_naf, other_naf):
999
+ X3, Y3, Z3 = _double(X3, Y3, Z3, p, a)
1000
+
1001
+ # conditions ordered from most to least likely
1002
+ if A == 0:
1003
+ if B == 0:
1004
+ pass
1005
+ elif B < 0:
1006
+ X3, Y3, Z3 = _add(X3, Y3, Z3, X2, -Y2, Z2, p)
1007
+ else:
1008
+ assert B > 0
1009
+ X3, Y3, Z3 = _add(X3, Y3, Z3, X2, Y2, Z2, p)
1010
+ elif A < 0:
1011
+ if B == 0:
1012
+ X3, Y3, Z3 = _add(X3, Y3, Z3, X1, -Y1, Z1, p)
1013
+ elif B < 0:
1014
+ X3, Y3, Z3 = _add(X3, Y3, Z3, mAmB_X, mAmB_Y, mAmB_Z, p)
1015
+ else:
1016
+ assert B > 0
1017
+ X3, Y3, Z3 = _add(X3, Y3, Z3, mApB_X, mApB_Y, mApB_Z, p)
1018
+ else:
1019
+ assert A > 0
1020
+ if B == 0:
1021
+ X3, Y3, Z3 = _add(X3, Y3, Z3, X1, Y1, Z1, p)
1022
+ elif B < 0:
1023
+ X3, Y3, Z3 = _add(X3, Y3, Z3, pAmB_X, pAmB_Y, pAmB_Z, p)
1024
+ else:
1025
+ assert B > 0
1026
+ X3, Y3, Z3 = _add(X3, Y3, Z3, pApB_X, pApB_Y, pApB_Z, p)
1027
+
1028
+ if not Z3:
1029
+ return INFINITY
1030
+
1031
+ return PointJacobi(self.__curve, X3, Y3, Z3, self.__order)
1032
+
1033
+ def __neg__(self):
1034
+ """Return negated point."""
1035
+ x, y, z = self.__coords
1036
+ return PointJacobi(self.__curve, x, -y, z, self.__order)
195
1037
 
196
1038
  # This one point is the Point At Infinity for all purposes:
197
1039
  INFINITY = Point(None, None, None)