├── .gitignore ├── LICENSE ├── README.md ├── __init__.py ├── crypto.py ├── ecdsa.py ├── ecdsa_base.py ├── ecdsa_openssl.py ├── ecdsa_python.py ├── openssl.py ├── requirements.txt └── utils.py /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | bin 3 | include 4 | lib 5 | .Python 6 | pip-selfcheck.json 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017-2018, Michail Brynard 2 | Copyright (c) 2015-2017, 21 Inc. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | 25 | The views and conclusions contained in the software and documentation are those 26 | of the authors and should not be interpreted as representing official policies, 27 | either expressed or implied, of 21 Inc. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Ethereum BIP44 Python 2 | ================================ 3 | 4 | *Code adapted from two1 library for bitcoin by 21 Inc. (https://github.com/21dotco/two1-python/tree/master/two1) 5 | 6 | ### Requirements 7 | Python packages: 8 | `pip install -r requirements.txt` 9 | 10 | Imports: 11 | `from crypto import HDPrivateKey, HDPublicKey, HDKey` 12 | 13 | ### BIP32 Master Keys Creation: 14 | ``` 15 | master_key, mnemonic = HDPrivateKey.master_key_from_entropy() 16 | print('BIP32 Wallet Generated.') 17 | print('Mnemonic Secret: ' + mnemonic) 18 | ``` 19 | 20 | ### Accounts creation 21 | Creation of multiple accounts under master key derived from seed phrase. 22 | Compatible with [Metamask](https://metamask.io). You can just restore your wallet 23 | with seed phrase and get access to all the accounts under master key via Metamask. 24 | ``` 25 | from crypto import HDPrivateKey, HDKey 26 | master_key = HDPrivateKey.master_key_from_mnemonic('laundry snap patient survey sleep strategy finger bone real west arch protect') 27 | root_keys = HDKey.from_path(master_key,"m/44'/60'/0'") 28 | acct_priv_key = root_keys[-1] 29 | for i in range(10): 30 | keys = HDKey.from_path(acct_priv_key,'{change}/{index}'.format(change=0, index=i)) 31 | private_key = keys[-1] 32 | public_key = private_key.public_key 33 | print("Index %s:" % i) 34 | print(" Private key (hex, compressed): " + private_key._key.to_hex()) 35 | print(" Address: " + private_key.public_key.address()) 36 | ``` 37 | 38 | ### Get Account XPUB 39 | ``` 40 | master_key = HDPrivateKey.master_key_from_mnemonic('laundry snap patient survey sleep strategy finger bone real west arch protect') 41 | root_keys = HDKey.from_path(master_key,"m/44'/60'/0'") 42 | acct_priv_key = root_keys[-1] 43 | acct_pub_key = acct_priv_key.public_key 44 | print('Account Master Public Key (Hex): ' + acct_pub_key.to_hex()) 45 | print('XPUB format: ' + acct_pub_key.to_b58check()) 46 | ``` 47 | 48 | ### Get Address from XPUB 49 | ``` 50 | acct_pub_key = HDKey.from_b58check('xpub6DKMR7KpgCJbiN4TdzcqcB1Nk84D9bsYUBhbk43EjRqH4RTjz7UgGLZxcQ4JdHBSHDmTUDLApMwYHRQCbbMCPQEtcbVofZEQjFazpGPT1nW') 51 | keys = HDKey.from_path(acct_pub_key,'{change}/{index}'.format(change=0, index=0)) 52 | address = keys[-1].address() 53 | print('Account address: ' + address) 54 | ``` 55 | ### Get 64 Character Private Key from XPRIV 56 | ``` 57 | print(Private key (hex): " + private_key._key.to_hex()) 58 | 59 | ``` 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michailbrynard/ethereum-bip44-python/dd21c27ef3fe85a5d3aeca9bca73e3af07848324/__init__.py -------------------------------------------------------------------------------- /crypto.py: -------------------------------------------------------------------------------- 1 | """This submodule provides the PublicKey, PrivateKey, and Signature classes. 2 | It also provides HDPublicKey and HDPrivateKey classes for working with HD 3 | wallets.""" 4 | import math 5 | import base58 6 | import base64 7 | import hashlib 8 | import hmac 9 | from mnemonic.mnemonic import Mnemonic 10 | import random 11 | from utils import bytes_to_str 12 | from utils import address_to_key_hash 13 | from utils import rand_bytes 14 | from ecdsa_base import Point 15 | from ecdsa import ECPointAffine 16 | from ecdsa import secp256k1 17 | 18 | bitcoin_curve = secp256k1() 19 | 20 | from eth_utils import encode_hex 21 | 22 | from Crypto.Hash import keccak 23 | sha3_256 = lambda x: keccak.new(digest_bits=256, data=x) 24 | 25 | 26 | def sha3(seed): 27 | return sha3_256(seed).digest() 28 | 29 | 30 | def get_bytes(s): 31 | """Returns the byte representation of a hex- or byte-string.""" 32 | if isinstance(s, bytes): 33 | b = s 34 | elif isinstance(s, str): 35 | b = bytes.fromhex(s) 36 | else: 37 | raise TypeError("s must be either 'bytes' or 'str'!") 38 | 39 | return b 40 | 41 | 42 | class PrivateKeyBase(object): 43 | """ Base class for both PrivateKey and HDPrivateKey. 44 | 45 | As this class is a base class it should not be used directly. 46 | 47 | Args: 48 | k (int): The private key. 49 | 50 | Returns: 51 | PrivateKey: The object representing the private key. 52 | """ 53 | 54 | @staticmethod 55 | def from_b58check(private_key): 56 | """ Decodes a Base58Check encoded private-key. 57 | 58 | Args: 59 | private_key (str): A Base58Check encoded private key. 60 | 61 | Returns: 62 | PrivateKey: A PrivateKey object 63 | """ 64 | raise NotImplementedError 65 | 66 | def __init__(self, k): 67 | self.key = k 68 | self._public_key = None 69 | 70 | @property 71 | def public_key(self): 72 | """ Returns the public key associated with this private key. 73 | 74 | Returns: 75 | PublicKey: 76 | The PublicKey object that corresponds to this 77 | private key. 78 | """ 79 | return self._public_key 80 | 81 | def raw_sign(self, message, do_hash=True): 82 | """ Signs message using this private key. 83 | 84 | Args: 85 | message (bytes): The message to be signed. If a string is 86 | provided it is assumed the encoding is 'ascii' and 87 | converted to bytes. If this is not the case, it is up 88 | to the caller to convert the string to bytes 89 | appropriately and pass in the bytes. 90 | do_hash (bool): True if the message should be hashed prior 91 | to signing, False if not. This should always be left as 92 | True except in special situations which require doing 93 | the hash outside (e.g. handling Bitcoin bugs). 94 | 95 | Returns: 96 | ECPointAffine: 97 | a raw point (r = pt.x, s = pt.y) which is 98 | the signature. 99 | """ 100 | raise NotImplementedError 101 | 102 | def sign(self, message, do_hash=True): 103 | """ Signs message using this private key. 104 | 105 | Note: 106 | This differs from `raw_sign()` since it returns a 107 | Signature object. 108 | 109 | Args: 110 | message (bytes or str): The message to be signed. If a 111 | string is provided it is assumed the encoding is 112 | 'ascii' and converted to bytes. If this is not the 113 | case, it is up to the caller to convert the string to 114 | bytes appropriately and pass in the bytes. 115 | do_hash (bool): True if the message should be hashed prior 116 | to signing, False if not. This should always be left as 117 | True except in special situations which require doing 118 | the hash outside (e.g. handling Bitcoin bugs). 119 | 120 | Returns: 121 | Signature: The signature corresponding to message. 122 | """ 123 | raise NotImplementedError 124 | 125 | def sign_bitcoin(self, message, compressed=False): 126 | """ Signs a message using this private key such that it 127 | is compatible with bitcoind, bx, and other Bitcoin 128 | clients/nodes/utilities. 129 | 130 | Note: 131 | 0x18 + b\"Bitcoin Signed Message:" + newline + len(message) is 132 | prepended to the message before signing. 133 | 134 | Args: 135 | message (bytes or str): Message to be signed. 136 | compressed (bool): True if the corresponding public key will be 137 | used in compressed format. False if the uncompressed version 138 | is used. 139 | 140 | Returns: 141 | bytes: A Base64-encoded byte string of the signed message. 142 | The first byte of the encoded message contains information 143 | about how to recover the public key. In bitcoind parlance, 144 | this is the magic number containing the recovery ID and 145 | whether or not the key was compressed or not. (This function 146 | always processes full, uncompressed public-keys, so the magic 147 | number will always be either 27 or 28). 148 | """ 149 | raise NotImplementedError 150 | 151 | def to_b58check(self, testnet=False): 152 | """ Generates a Base58Check encoding of this private key. 153 | 154 | Returns: 155 | str: A Base58Check encoded string representing the key. 156 | """ 157 | raise NotImplementedError 158 | 159 | def to_hex(self): 160 | """ Generates a hex encoding of the serialized key. 161 | 162 | Returns: 163 | str: A hex encoded string representing the key. 164 | """ 165 | return bytes_to_str(bytes(self)) 166 | 167 | def __bytes__(self): 168 | raise NotImplementedError 169 | 170 | def __int__(self): 171 | raise NotImplementedError 172 | 173 | 174 | class PublicKeyBase(object): 175 | """ Base class for both PublicKey and HDPublicKey. 176 | 177 | As this class is a base class it should not be used directly. 178 | 179 | Args: 180 | x (int): The x component of the public key point. 181 | y (int): The y component of the public key point. 182 | 183 | Returns: 184 | PublicKey: The object representing the public key. 185 | 186 | """ 187 | 188 | @staticmethod 189 | def from_bytes(key_bytes): 190 | """ Generates a public key object from a byte (or hex) string. 191 | 192 | Args: 193 | key_bytes (bytes or str): A byte stream. 194 | 195 | Returns: 196 | PublicKey: A PublicKey object. 197 | """ 198 | raise NotImplementedError 199 | 200 | @staticmethod 201 | def from_private_key(private_key): 202 | """ Generates a public key object from a PrivateKey object. 203 | 204 | Args: 205 | private_key (PrivateKey): The private key object from 206 | which to derive this object. 207 | 208 | Returns: 209 | PublicKey: A PublicKey object. 210 | """ 211 | return private_key.public_key 212 | 213 | def __init__(self): 214 | pass 215 | 216 | def hash160(self, compressed=True): 217 | """ Return the RIPEMD-160 hash of the SHA-256 hash of the 218 | public key. 219 | 220 | Args: 221 | compressed (bool): Whether or not the compressed key should 222 | be used. 223 | Returns: 224 | bytes: RIPEMD-160 byte string. 225 | """ 226 | raise NotImplementedError 227 | 228 | def address(self, compressed=True, testnet=False): 229 | """ Address property that returns the Base58Check 230 | encoded version of the HASH160. 231 | 232 | Args: 233 | compressed (bool): Whether or not the compressed key should 234 | be used. 235 | testnet (bool): Whether or not the key is intended for testnet 236 | usage. False indicates mainnet usage. 237 | 238 | Returns: 239 | bytes: Base58Check encoded string 240 | """ 241 | raise NotImplementedError 242 | 243 | def verify(self, message, signature, do_hash=True): 244 | """ Verifies that message was appropriately signed. 245 | 246 | Args: 247 | message (bytes): The message to be verified. 248 | signature (Signature): A signature object. 249 | do_hash (bool): True if the message should be hashed prior 250 | to signing, False if not. This should always be left as 251 | True except in special situations which require doing 252 | the hash outside (e.g. handling Bitcoin bugs). 253 | 254 | Returns: 255 | verified (bool): True if the signature is verified, False 256 | otherwise. 257 | """ 258 | raise NotImplementedError 259 | 260 | def to_hex(self): 261 | """ Hex representation of the serialized byte stream. 262 | 263 | Returns: 264 | h (str): A hex-encoded string. 265 | """ 266 | return bytes_to_str(bytes(self)) 267 | 268 | def __bytes__(self): 269 | raise NotImplementedError 270 | 271 | def __int__(self): 272 | raise NotImplementedError 273 | 274 | @property 275 | def compressed_bytes(self): 276 | """ Byte string corresponding to a compressed representation 277 | of this public key. 278 | 279 | Returns: 280 | b (bytes): A 33-byte long byte string. 281 | """ 282 | raise NotImplementedError 283 | 284 | 285 | class PrivateKey(PrivateKeyBase): 286 | """ Encapsulation of a Bitcoin ECDSA private key. 287 | 288 | This class provides capability to generate private keys, 289 | obtain the corresponding public key, sign messages and 290 | serialize/deserialize into a variety of formats. 291 | 292 | Args: 293 | k (int): The private key. 294 | 295 | Returns: 296 | PrivateKey: The object representing the private key. 297 | """ 298 | TESTNET_VERSION = 0xEF 299 | MAINNET_VERSION = 0x80 300 | 301 | @staticmethod 302 | def from_bytes(b): 303 | """ Generates PrivateKey from the underlying bytes. 304 | 305 | Args: 306 | b (bytes): A byte stream containing a 256-bit (32-byte) integer. 307 | 308 | Returns: 309 | tuple(PrivateKey, bytes): A PrivateKey object and the remainder 310 | of the bytes. 311 | """ 312 | if len(b) < 32: 313 | raise ValueError('b must contain at least 32 bytes') 314 | 315 | return PrivateKey(int.from_bytes(b[:32], 'big')) 316 | 317 | @staticmethod 318 | def from_hex(h): 319 | """ Generates PrivateKey from a hex-encoded string. 320 | 321 | Args: 322 | h (str): A hex-encoded string containing a 256-bit 323 | (32-byte) integer. 324 | 325 | Returns: 326 | PrivateKey: A PrivateKey object. 327 | """ 328 | return PrivateKey.from_bytes(bytes.fromhex(h)) 329 | 330 | @staticmethod 331 | def from_int(i): 332 | """ Initializes a private key from an integer. 333 | 334 | Args: 335 | i (int): Integer that is the private key. 336 | 337 | Returns: 338 | PrivateKey: The object representing the private key. 339 | """ 340 | return PrivateKey(i) 341 | 342 | @staticmethod 343 | def from_b58check(private_key): 344 | """ Decodes a Base58Check encoded private-key. 345 | 346 | Args: 347 | private_key (str): A Base58Check encoded private key. 348 | 349 | Returns: 350 | PrivateKey: A PrivateKey object 351 | """ 352 | b58dec = base58.b58decode_check(private_key) 353 | version = b58dec[0] 354 | assert version in [PrivateKey.TESTNET_VERSION, 355 | PrivateKey.MAINNET_VERSION] 356 | 357 | return PrivateKey(int.from_bytes(b58dec[1:], 'big')) 358 | 359 | @staticmethod 360 | def from_random(): 361 | """ Initializes a private key from a random integer. 362 | 363 | Returns: 364 | PrivateKey: The object representing the private key. 365 | """ 366 | return PrivateKey(random.SystemRandom().randrange(1, bitcoin_curve.n)) 367 | 368 | def __init__(self, k): 369 | self.key = k 370 | self._public_key = None 371 | 372 | @property 373 | def public_key(self): 374 | """ Returns the public key associated with this private key. 375 | 376 | Returns: 377 | PublicKey: 378 | The PublicKey object that corresponds to this 379 | private key. 380 | """ 381 | if self._public_key is None: 382 | self._public_key = PublicKey.from_point( 383 | bitcoin_curve.public_key(self.key)) 384 | return self._public_key 385 | 386 | def raw_sign(self, message, do_hash=True): 387 | """ Signs message using this private key. 388 | 389 | Args: 390 | message (bytes): The message to be signed. If a string is 391 | provided it is assumed the encoding is 'ascii' and 392 | converted to bytes. If this is not the case, it is up 393 | to the caller to convert the string to bytes 394 | appropriately and pass in the bytes. 395 | do_hash (bool): True if the message should be hashed prior 396 | to signing, False if not. This should always be left as 397 | True except in special situations which require doing 398 | the hash outside (e.g. handling Bitcoin bugs). 399 | 400 | Returns: 401 | ECPointAffine: 402 | a raw point (r = pt.x, s = pt.y) which is 403 | the signature. 404 | """ 405 | if isinstance(message, str): 406 | msg = bytes(message, 'ascii') 407 | elif isinstance(message, bytes): 408 | msg = message 409 | else: 410 | raise TypeError("message must be either str or bytes!") 411 | 412 | sig_pt, rec_id = bitcoin_curve.sign(msg, self.key, do_hash) 413 | 414 | # Take care of large s: 415 | # Bitcoin deals with large s, by subtracting 416 | # s from the curve order. See: 417 | # https://bitcointalk.org/index.php?topic=285142.30;wap2 418 | if sig_pt.y >= (bitcoin_curve.n // 2): 419 | sig_pt = Point(sig_pt.x, bitcoin_curve.n - sig_pt.y) 420 | rec_id ^= 0x1 421 | 422 | return (sig_pt, rec_id) 423 | 424 | def sign(self, message, do_hash=True): 425 | """ Signs message using this private key. 426 | 427 | Note: 428 | This differs from `raw_sign()` since it returns a Signature object. 429 | 430 | Args: 431 | message (bytes or str): The message to be signed. If a 432 | string is provided it is assumed the encoding is 433 | 'ascii' and converted to bytes. If this is not the 434 | case, it is up to the caller to convert the string to 435 | bytes appropriately and pass in the bytes. 436 | do_hash (bool): True if the message should be hashed prior 437 | to signing, False if not. This should always be left as 438 | True except in special situations which require doing 439 | the hash outside (e.g. handling Bitcoin bugs). 440 | 441 | Returns: 442 | Signature: The signature corresponding to message. 443 | """ 444 | # Some BTC things want to have the recovery id to extract the public 445 | # key, so we should figure that out. 446 | sig_pt, rec_id = self.raw_sign(message, do_hash) 447 | 448 | return Signature(sig_pt.x, sig_pt.y, rec_id) 449 | 450 | def sign_bitcoin(self, message, compressed=False): 451 | """ Signs a message using this private key such that it 452 | is compatible with bitcoind, bx, and other Bitcoin 453 | clients/nodes/utilities. 454 | 455 | Note: 456 | 0x18 + b\"Bitcoin Signed Message:" + newline + len(message) is 457 | prepended to the message before signing. 458 | 459 | Args: 460 | message (bytes or str): Message to be signed. 461 | compressed (bool): True if the corresponding public key will be 462 | used in compressed format. False if the uncompressed version 463 | is used. 464 | 465 | Returns: 466 | bytes: A Base64-encoded byte string of the signed message. 467 | The first byte of the encoded message contains information 468 | about how to recover the public key. In bitcoind parlance, 469 | this is the magic number containing the recovery ID and 470 | whether or not the key was compressed or not. 471 | """ 472 | if isinstance(message, str): 473 | msg_in = bytes(message, 'ascii') 474 | elif isinstance(message, bytes): 475 | msg_in = message 476 | else: 477 | raise TypeError("message must be either str or bytes!") 478 | 479 | msg = b"\x18Bitcoin Signed Message:\n" + bytes([len(msg_in)]) + msg_in 480 | msg_hash = hashlib.sha256(msg).digest() 481 | 482 | sig = self.sign(msg_hash) 483 | comp_adder = 4 if compressed else 0 484 | magic = 27 + sig.recovery_id + comp_adder 485 | 486 | return base64.b64encode(bytes([magic]) + bytes(sig)) 487 | 488 | def to_b58check(self, testnet=False): 489 | """ Generates a Base58Check encoding of this private key. 490 | 491 | Returns: 492 | str: A Base58Check encoded string representing the key. 493 | """ 494 | version = self.TESTNET_VERSION if testnet else self.MAINNET_VERSION 495 | return base58.b58encode_check(bytes([version]) + bytes(self)) 496 | 497 | def __bytes__(self): 498 | return self.key.to_bytes(32, 'big') 499 | 500 | def __int__(self): 501 | return self.key 502 | 503 | 504 | class PublicKey(PublicKeyBase): 505 | """ Encapsulation of a Bitcoin ECDSA public key. 506 | 507 | This class provides a high-level API to using an ECDSA public 508 | key, specifically for Bitcoin (secp256k1) purposes. 509 | 510 | Args: 511 | x (int): The x component of the public key point. 512 | y (int): The y component of the public key point. 513 | 514 | Returns: 515 | PublicKey: The object representing the public key. 516 | """ 517 | 518 | TESTNET_VERSION = 0x6F 519 | MAINNET_VERSION = 0x00 520 | 521 | @staticmethod 522 | def from_point(p): 523 | """ Generates a public key object from any object 524 | containing x, y coordinates. 525 | 526 | Args: 527 | p (Point): An object containing a two-dimensional, affine 528 | representation of a point on the secp256k1 curve. 529 | 530 | Returns: 531 | PublicKey: A PublicKey object. 532 | """ 533 | return PublicKey(p.x, p.y) 534 | 535 | @staticmethod 536 | def from_int(i): 537 | """ Generates a public key object from an integer. 538 | 539 | Note: 540 | This assumes that the upper 32 bytes of the integer 541 | are the x component of the public key point and the 542 | lower 32 bytes are the y component. 543 | 544 | Args: 545 | i (Bignum): A 512-bit integer representing the public 546 | key point on the secp256k1 curve. 547 | 548 | Returns: 549 | PublicKey: A PublicKey object. 550 | """ 551 | point = ECPointAffine.from_int(bitcoin_curve, i) 552 | return PublicKey.from_point(point) 553 | 554 | @staticmethod 555 | def from_base64(b64str, testnet=False): 556 | """ Generates a public key object from a Base64 encoded string. 557 | 558 | Args: 559 | b64str (str): A Base64-encoded string. 560 | testnet (bool) (Optional): If True, changes the version that 561 | is prepended to the key. 562 | 563 | Returns: 564 | PublicKey: A PublicKey object. 565 | """ 566 | return PublicKey.from_bytes(base64.b64decode(b64str)) 567 | 568 | @staticmethod 569 | def from_bytes(key_bytes): 570 | """ Generates a public key object from a byte (or hex) string. 571 | 572 | The byte stream must be of the SEC variety 573 | (http://www.secg.org/): beginning with a single byte telling 574 | what key representation follows. A full, uncompressed key 575 | is represented by: 0x04 followed by 64 bytes containing 576 | the x and y components of the point. For compressed keys 577 | with an even y component, 0x02 is followed by 32 bytes 578 | containing the x component. For compressed keys with an 579 | odd y component, 0x03 is followed by 32 bytes containing 580 | the x component. 581 | 582 | Args: 583 | key_bytes (bytes or str): A byte stream that conforms to the above. 584 | 585 | Returns: 586 | PublicKey: A PublicKey object. 587 | """ 588 | b = get_bytes(key_bytes) 589 | key_bytes_len = len(b) 590 | 591 | key_type = b[0] 592 | if key_type == 0x04: 593 | # Uncompressed 594 | if key_bytes_len != 65: 595 | raise ValueError("key_bytes must be exactly 65 bytes long when uncompressed.") 596 | 597 | x = int.from_bytes(b[1:33], 'big') 598 | y = int.from_bytes(b[33:65], 'big') 599 | elif key_type == 0x02 or key_type == 0x03: 600 | if key_bytes_len != 33: 601 | raise ValueError("key_bytes must be exactly 33 bytes long when compressed.") 602 | 603 | x = int.from_bytes(b[1:33], 'big') 604 | ys = bitcoin_curve.y_from_x(x) 605 | 606 | # Pick the one that corresponds to key_type 607 | last_bit = key_type - 0x2 608 | for y in ys: 609 | if y & 0x1 == last_bit: 610 | break 611 | else: 612 | return None 613 | 614 | return PublicKey(x, y) 615 | 616 | @staticmethod 617 | def from_hex(h): 618 | """ Generates a public key object from a hex-encoded string. 619 | 620 | See from_bytes() for requirements of the hex string. 621 | 622 | Args: 623 | h (str): A hex-encoded string. 624 | 625 | Returns: 626 | PublicKey: A PublicKey object. 627 | """ 628 | return PublicKey.from_bytes(h) 629 | 630 | @staticmethod 631 | def from_signature(message, signature): 632 | """ Attempts to create PublicKey object by deriving it 633 | from the message and signature. 634 | 635 | Args: 636 | message (bytes): The message to be verified. 637 | signature (Signature): The signature for message. 638 | The recovery_id must not be None! 639 | 640 | Returns: 641 | PublicKey: 642 | A PublicKey object derived from the 643 | signature, it it exists. None otherwise. 644 | """ 645 | if signature.recovery_id is None: 646 | raise ValueError("The signature must have a recovery_id.") 647 | 648 | msg = get_bytes(message) 649 | pub_keys = bitcoin_curve.recover_public_key(msg, 650 | signature, 651 | signature.recovery_id) 652 | 653 | for k, recid in pub_keys: 654 | if signature.recovery_id is not None and recid == signature.recovery_id: 655 | return PublicKey(k.x, k.y) 656 | 657 | return None 658 | 659 | @staticmethod 660 | def verify_bitcoin(message, signature, address): 661 | """ Verifies a message signed using PrivateKey.sign_bitcoin() 662 | or any of the bitcoin utils (e.g. bitcoin-cli, bx, etc.) 663 | 664 | Args: 665 | message(bytes): The message that the signature corresponds to. 666 | signature (bytes or str): A Base64 encoded signature 667 | address (str): Base58Check encoded address. 668 | 669 | Returns: 670 | bool: True if the signature verified properly, False otherwise. 671 | """ 672 | magic_sig = base64.b64decode(signature) 673 | 674 | magic = magic_sig[0] 675 | sig = Signature.from_bytes(magic_sig[1:]) 676 | sig.recovery_id = (magic - 27) & 0x3 677 | compressed = ((magic - 27) & 0x4) != 0 678 | 679 | # Build the message that was signed 680 | msg = b"\x18Bitcoin Signed Message:\n" + bytes([len(message)]) + message 681 | msg_hash = hashlib.sha256(msg).digest() 682 | 683 | derived_public_key = PublicKey.from_signature(msg_hash, sig) 684 | if derived_public_key is None: 685 | raise ValueError("Could not recover public key from the provided signature.") 686 | 687 | ver, h160 = address_to_key_hash(address) 688 | hash160 = derived_public_key.hash160(compressed) 689 | if hash160 != h160: 690 | return False 691 | 692 | return derived_public_key.verify(msg_hash, sig) 693 | 694 | def __init__(self, x, y): 695 | p = ECPointAffine(bitcoin_curve, x, y) 696 | if not bitcoin_curve.is_on_curve(p): 697 | raise ValueError("The provided (x, y) are not on the secp256k1 curve.") 698 | 699 | self.point = p 700 | 701 | # RIPEMD-160 of SHA-256 702 | r = hashlib.new('ripemd160') 703 | r.update(hashlib.sha256(bytes(self)).digest()) 704 | self.ripe = r.digest() 705 | 706 | r = hashlib.new('ripemd160') 707 | r.update(hashlib.sha256(self.compressed_bytes).digest()) 708 | self.ripe_compressed = r.digest() 709 | 710 | self.keccak = sha3(bytes(self)[1:]) 711 | 712 | def hash160(self, compressed=True): 713 | """ Return the RIPEMD-160 hash of the SHA-256 hash of the 714 | public key. 715 | 716 | Args: 717 | compressed (bool): Whether or not the compressed key should 718 | be used. 719 | Returns: 720 | bytes: RIPEMD-160 byte string. 721 | """ 722 | return self.ripe_compressed if compressed else self.ripe 723 | 724 | def address(self, compressed=True): 725 | """ Address property that returns the Base58Check 726 | encoded version of the HASH160. 727 | 728 | Args: 729 | compressed (bool): Whether or not the compressed key should 730 | be used. 731 | 732 | Returns: 733 | bytes: Base58Check encoded string 734 | """ 735 | return encode_hex(self.keccak[12:]) 736 | 737 | def verify(self, message, signature, do_hash=True): 738 | """ Verifies that message was appropriately signed. 739 | 740 | Args: 741 | message (bytes): The message to be verified. 742 | signature (Signature): A signature object. 743 | do_hash (bool): True if the message should be hashed prior 744 | to signing, False if not. This should always be left as 745 | True except in special situations which require doing 746 | the hash outside (e.g. handling Bitcoin bugs). 747 | 748 | Returns: 749 | verified (bool): True if the signature is verified, False 750 | otherwise. 751 | """ 752 | msg = get_bytes(message) 753 | return bitcoin_curve.verify(msg, signature, self.point, do_hash) 754 | 755 | def to_base64(self): 756 | """ Hex representation of the serialized byte stream. 757 | 758 | Returns: 759 | b (str): A Base64-encoded string. 760 | """ 761 | return base64.b64encode(bytes(self)) 762 | 763 | def __int__(self): 764 | mask = 2 ** 256 - 1 765 | return ((self.point.x & mask) << bitcoin_curve.nlen) | (self.point.y & mask) 766 | 767 | def __bytes__(self): 768 | return bytes(self.point) 769 | 770 | @property 771 | def compressed_bytes(self): 772 | """ Byte string corresponding to a compressed representation 773 | of this public key. 774 | 775 | Returns: 776 | b (bytes): A 33-byte long byte string. 777 | """ 778 | return self.point.compressed_bytes 779 | 780 | 781 | class Signature(object): 782 | """ Encapsulation of a ECDSA signature for Bitcoin purposes. 783 | 784 | Args: 785 | r (Bignum): r component of the signature. 786 | s (Bignum): s component of the signature. 787 | recovery_id (int) (Optional): Must be between 0 and 3 specifying 788 | which of the public keys generated by the algorithm specified 789 | in http://www.secg.org/sec1-v2.pdf Section 4.1.6 (Public Key 790 | Recovery Operation) is the correct one for this signature. 791 | 792 | Returns: 793 | sig (Signature): A Signature object. 794 | """ 795 | 796 | @staticmethod 797 | def from_der(der): 798 | """ Decodes a Signature that was DER-encoded. 799 | 800 | Args: 801 | der (bytes or str): The DER encoding to be decoded. 802 | 803 | Returns: 804 | Signature: The deserialized signature. 805 | """ 806 | d = get_bytes(der) 807 | # d must conform to (from btcd): 808 | # [0 ] 0x30 - ASN.1 identifier for sequence 809 | # [1 ] <1-byte> - total remaining length 810 | # [2 ] 0x02 - ASN.1 identifier to specify an integer follows 811 | # [3 ] <1-byte> - length of R 812 | # [4.] - R 813 | # [..] 0x02 - ASN.1 identifier to specify an integer follows 814 | # [..] <1-byte> - length of S 815 | # [..] - S 816 | 817 | # 6 bytes + R (min. 1 byte) + S (min. 1 byte) 818 | if len(d) < 8: 819 | raise ValueError("DER signature string is too short.") 820 | # 6 bytes + R (max. 33 bytes) + S (max. 33 bytes) 821 | if len(d) > 72: 822 | raise ValueError("DER signature string is too long.") 823 | if d[0] != 0x30: 824 | raise ValueError("DER signature does not start with 0x30.") 825 | if d[1] != len(d[2:]): 826 | raise ValueError("DER signature length incorrect.") 827 | 828 | total_length = d[1] 829 | 830 | if d[2] != 0x02: 831 | raise ValueError("DER signature no 1st int marker.") 832 | if d[3] <= 0 or d[3] > (total_length - 7): 833 | raise ValueError("DER signature incorrect R length.") 834 | 835 | # Grab R, check for errors 836 | rlen = d[3] 837 | s_magic_index = 4 + rlen 838 | rb = d[4:s_magic_index] 839 | 840 | if rb[0] & 0x80 != 0: 841 | raise ValueError("DER signature R is negative.") 842 | if len(rb) > 1 and rb[0] == 0 and rb[1] & 0x80 != 0x80: 843 | raise ValueError("DER signature R is excessively padded.") 844 | 845 | r = int.from_bytes(rb, 'big') 846 | 847 | # Grab S, check for errors 848 | if d[s_magic_index] != 0x02: 849 | raise ValueError("DER signature no 2nd int marker.") 850 | slen_index = s_magic_index + 1 851 | slen = d[slen_index] 852 | if slen <= 0 or slen > len(d) - (slen_index + 1): 853 | raise ValueError("DER signature incorrect S length.") 854 | 855 | sb = d[slen_index + 1:] 856 | 857 | if sb[0] & 0x80 != 0: 858 | raise ValueError("DER signature S is negative.") 859 | if len(sb) > 1 and sb[0] == 0 and sb[1] & 0x80 != 0x80: 860 | raise ValueError("DER signature S is excessively padded.") 861 | 862 | s = int.from_bytes(sb, 'big') 863 | 864 | if r < 1 or r >= bitcoin_curve.n: 865 | raise ValueError("DER signature R is not between 1 and N - 1.") 866 | if s < 1 or s >= bitcoin_curve.n: 867 | raise ValueError("DER signature S is not between 1 and N - 1.") 868 | 869 | return Signature(r, s) 870 | 871 | @staticmethod 872 | def from_base64(b64str): 873 | """ Generates a signature object from a Base64 encoded string. 874 | 875 | Args: 876 | b64str (str): A Base64-encoded string. 877 | 878 | Returns: 879 | Signature: A Signature object. 880 | """ 881 | return Signature.from_bytes(base64.b64decode(b64str)) 882 | 883 | @staticmethod 884 | def from_bytes(b): 885 | """ Extracts the r and s components from a byte string. 886 | 887 | Args: 888 | b (bytes): A 64-byte long string. The first 32 bytes are 889 | extracted as the r component and the second 32 bytes 890 | are extracted as the s component. 891 | 892 | Returns: 893 | Signature: A Signature object. 894 | 895 | Raises: 896 | ValueError: If signature is incorrect length 897 | """ 898 | if len(b) != 64: 899 | raise ValueError("from_bytes: Signature length != 64.") 900 | r = int.from_bytes(b[0:32], 'big') 901 | s = int.from_bytes(b[32:64], 'big') 902 | return Signature(r, s) 903 | 904 | @staticmethod 905 | def from_hex(h): 906 | """ Extracts the r and s components from a hex-encoded string. 907 | 908 | Args: 909 | h (str): A 64-byte (128 character) long string. The first 910 | 32 bytes are extracted as the r component and the 911 | second 32 bytes are extracted as the s component. 912 | 913 | Returns: 914 | Signature: A Signature object. 915 | """ 916 | return Signature.from_bytes(bytes.fromhex(h)) 917 | 918 | def __init__(self, r, s, recovery_id=None): 919 | self.r = r 920 | self.s = s 921 | self.recovery_id = recovery_id 922 | 923 | @property 924 | def x(self): 925 | """ Convenience property for any method that requires 926 | this object to provide a Point interface. 927 | """ 928 | return self.r 929 | 930 | @property 931 | def y(self): 932 | """ Convenience property for any method that requires 933 | this object to provide a Point interface. 934 | """ 935 | return self.s 936 | 937 | def _canonicalize(self): 938 | rv = [] 939 | for x in [self.r, self.s]: 940 | # Compute minimum bytes to represent integer 941 | bl = math.ceil(x.bit_length() / 8) 942 | # Make sure it's at least one byte in length 943 | if bl == 0: 944 | bl += 1 945 | x_bytes = x.to_bytes(bl, 'big') 946 | 947 | # make sure there's no way it could be interpreted 948 | # as a negative integer 949 | if x_bytes[0] & 0x80: 950 | x_bytes = bytes([0]) + x_bytes 951 | 952 | rv.append(x_bytes) 953 | 954 | return rv 955 | 956 | def to_der(self): 957 | """ Encodes this signature using DER 958 | 959 | Returns: 960 | bytes: The DER encoding of (self.r, self.s). 961 | """ 962 | # Output should be: 963 | # 0x30 0x02 r 0x02 s 964 | r, s = self._canonicalize() 965 | 966 | total_length = 6 + len(r) + len(s) 967 | der = bytes([0x30, total_length - 2, 0x02, len(r)]) + r + bytes([0x02, len(s)]) + s 968 | return der 969 | 970 | def to_hex(self): 971 | """ Hex representation of the serialized byte stream. 972 | 973 | Returns: 974 | str: A hex-encoded string. 975 | """ 976 | return bytes_to_str(bytes(self)) 977 | 978 | def to_base64(self): 979 | """ Hex representation of the serialized byte stream. 980 | 981 | Returns: 982 | str: A Base64-encoded string. 983 | """ 984 | return base64.b64encode(bytes(self)) 985 | 986 | def __bytes__(self): 987 | nbytes = math.ceil(bitcoin_curve.nlen / 8) 988 | return self.r.to_bytes(nbytes, 'big') + self.s.to_bytes(nbytes, 'big') 989 | 990 | 991 | class HDKey(object): 992 | """ Base class for HDPrivateKey and HDPublicKey. 993 | 994 | Args: 995 | key (PrivateKey or PublicKey): The underlying simple private or 996 | public key that is used to sign/verify. 997 | chain_code (bytes): The chain code associated with the HD key. 998 | depth (int): How many levels below the master node this key is. By 999 | definition, depth = 0 for the master node. 1000 | index (int): A value between 0 and 0xffffffff indicating the child 1001 | number. Values >= 0x80000000 are considered hardened children. 1002 | parent_fingerprint (bytes): The fingerprint of the parent node. This 1003 | is 0x00000000 for the master node. 1004 | 1005 | Returns: 1006 | HDKey: An HDKey object. 1007 | """ 1008 | @staticmethod 1009 | def from_b58check(key): 1010 | """ Decodes a Base58Check encoded key. 1011 | 1012 | The encoding must conform to the description in: 1013 | https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#serialization-format 1014 | 1015 | Args: 1016 | key (str): A Base58Check encoded key. 1017 | 1018 | Returns: 1019 | HDPrivateKey or HDPublicKey: 1020 | Either an HD private or 1021 | public key object, depending on what was serialized. 1022 | """ 1023 | return HDKey.from_bytes(base58.b58decode_check(key)) 1024 | 1025 | @staticmethod 1026 | def from_bytes(b): 1027 | """ Generates either a HDPrivateKey or HDPublicKey from the underlying 1028 | bytes. 1029 | 1030 | The serialization must conform to the description in: 1031 | https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#serialization-format 1032 | 1033 | Args: 1034 | b (bytes): A byte stream conforming to the above. 1035 | 1036 | Returns: 1037 | HDPrivateKey or HDPublicKey: 1038 | Either an HD private or 1039 | public key object, depending on what was serialized. 1040 | """ 1041 | if len(b) < 78: 1042 | raise ValueError("b must be at least 78 bytes long.") 1043 | 1044 | version = int.from_bytes(b[:4], 'big') 1045 | depth = b[4] 1046 | parent_fingerprint = b[5:9] 1047 | index = int.from_bytes(b[9:13], 'big') 1048 | chain_code = b[13:45] 1049 | key_bytes = b[45:78] 1050 | 1051 | rv = None 1052 | if version == HDPrivateKey.MAINNET_VERSION or version == HDPrivateKey.TESTNET_VERSION: 1053 | if key_bytes[0] != 0: 1054 | raise ValueError("First byte of private key must be 0x00!") 1055 | 1056 | private_key = int.from_bytes(key_bytes[1:], 'big') 1057 | rv = HDPrivateKey(key=private_key, 1058 | chain_code=chain_code, 1059 | index=index, 1060 | depth=depth, 1061 | parent_fingerprint=parent_fingerprint) 1062 | elif version == HDPublicKey.MAINNET_VERSION or version == HDPublicKey.TESTNET_VERSION: 1063 | if key_bytes[0] != 0x02 and key_bytes[0] != 0x03: 1064 | raise ValueError("First byte of public key must be 0x02 or 0x03!") 1065 | 1066 | public_key = PublicKey.from_bytes(key_bytes) 1067 | rv = HDPublicKey(x=public_key.point.x, 1068 | y=public_key.point.y, 1069 | chain_code=chain_code, 1070 | index=index, 1071 | depth=depth, 1072 | parent_fingerprint=parent_fingerprint) 1073 | else: 1074 | raise ValueError("incorrect encoding.") 1075 | 1076 | return rv 1077 | 1078 | @staticmethod 1079 | def from_hex(h): 1080 | """ Generates either a HDPrivateKey or HDPublicKey from the underlying 1081 | hex-encoded string. 1082 | 1083 | The serialization must conform to the description in: 1084 | https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#serialization-format 1085 | 1086 | Args: 1087 | h (str): A hex-encoded string conforming to the above. 1088 | 1089 | Returns: 1090 | HDPrivateKey or HDPublicKey: 1091 | Either an HD private or 1092 | public key object, depending on what was serialized. 1093 | """ 1094 | return HDKey.from_bytes(bytes.fromhex(h)) 1095 | 1096 | @staticmethod 1097 | def from_path(root_key, path): 1098 | p = HDKey.parse_path(path) 1099 | 1100 | if p[0] == "m": 1101 | if root_key.master: 1102 | p = p[1:] 1103 | else: 1104 | raise ValueError("root_key must be a master key if 'm' is the first element of the path.") 1105 | 1106 | keys = [root_key] 1107 | for i in p: 1108 | if isinstance(i, str): 1109 | hardened = i[-1] == "'" 1110 | index = int(i[:-1], 0) | 0x80000000 if hardened else int(i, 0) 1111 | else: 1112 | index = i 1113 | k = keys[-1] 1114 | klass = k.__class__ 1115 | keys.append(klass.from_parent(k, index)) 1116 | 1117 | return keys 1118 | 1119 | @staticmethod 1120 | def parse_path(path): 1121 | if isinstance(path, str): 1122 | # Remove trailing "/" 1123 | p = path.rstrip("/").split("/") 1124 | elif isinstance(path, bytes): 1125 | p = path.decode('utf-8').rstrip("/").split("/") 1126 | else: 1127 | p = list(path) 1128 | 1129 | return p 1130 | 1131 | @staticmethod 1132 | def path_from_indices(l): 1133 | p = [] 1134 | for n in l: 1135 | if n == "m": 1136 | p.append(n) 1137 | else: 1138 | if n & 0x80000000: 1139 | _n = n & 0x7fffffff 1140 | p.append(str(_n) + "'") 1141 | else: 1142 | p.append(str(n)) 1143 | 1144 | return "/".join(p) 1145 | 1146 | def __init__(self, key, chain_code, index, depth, parent_fingerprint): 1147 | if index < 0 or index > 0xffffffff: 1148 | raise ValueError("index is out of range: 0 <= index <= 2**32 - 1") 1149 | 1150 | if not isinstance(chain_code, bytes): 1151 | raise TypeError("chain_code must be bytes") 1152 | 1153 | self._key = key 1154 | self.chain_code = chain_code 1155 | self.depth = depth 1156 | self.index = index 1157 | 1158 | self.parent_fingerprint = get_bytes(parent_fingerprint) 1159 | 1160 | @property 1161 | def master(self): 1162 | """ Whether or not this is a master node. 1163 | 1164 | Returns: 1165 | bool: True if this is a master node, False otherwise. 1166 | """ 1167 | return self.depth == 0 1168 | 1169 | @property 1170 | def hardened(self): 1171 | """ Whether or not this is a hardened node. 1172 | 1173 | Hardened nodes are those with indices >= 0x80000000. 1174 | 1175 | Returns: 1176 | bool: True if this is hardened, False otherwise. 1177 | """ 1178 | # A hardened key is a key with index >= 2 ** 31, so 1179 | # we check that the MSB of a uint32 is set. 1180 | return self.index & 0x80000000 1181 | 1182 | @property 1183 | def identifier(self): 1184 | """ Returns the identifier for the key. 1185 | 1186 | A key's identifier and fingerprint are defined as: 1187 | https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#key-identifiers 1188 | 1189 | Returns: 1190 | bytes: A 20-byte RIPEMD-160 hash. 1191 | """ 1192 | raise NotImplementedError 1193 | 1194 | @property 1195 | def fingerprint(self): 1196 | """ Returns the key's fingerprint, which is the first 4 bytes 1197 | of its identifier. 1198 | 1199 | A key's identifier and fingerprint are defined as: 1200 | https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#key-identifiers 1201 | 1202 | Returns: 1203 | bytes: The first 4 bytes of the RIPEMD-160 hash. 1204 | """ 1205 | return self.identifier[:4] 1206 | 1207 | def to_b58check(self, testnet=False): 1208 | """ Generates a Base58Check encoding of this key. 1209 | 1210 | Args: 1211 | testnet (bool): True if the key is to be used with 1212 | testnet, False otherwise. 1213 | Returns: 1214 | str: A Base58Check encoded string representing the key. 1215 | """ 1216 | b = self.testnet_bytes if testnet else bytes(self) 1217 | return base58.b58encode_check(b) 1218 | 1219 | def _serialize(self, testnet=False): 1220 | version = self.TESTNET_VERSION if testnet else self.MAINNET_VERSION 1221 | key_bytes = self._key.compressed_bytes if isinstance(self, HDPublicKey) else b'\x00' + bytes(self._key) 1222 | return (version.to_bytes(length=4, byteorder='big') + 1223 | bytes([self.depth]) + 1224 | self.parent_fingerprint + 1225 | self.index.to_bytes(length=4, byteorder='big') + 1226 | self.chain_code + 1227 | key_bytes) 1228 | 1229 | def __bytes__(self): 1230 | return self._serialize() 1231 | 1232 | @property 1233 | def testnet_bytes(self): 1234 | """ Serialization of the key for testnet. 1235 | 1236 | Returns: 1237 | bytes: 1238 | A 78-byte serialization of the key, specifically for 1239 | testnet (i.e. the first 2 bytes will be 0x0435). 1240 | """ 1241 | return self._serialize(True) 1242 | 1243 | 1244 | class HDPrivateKey(HDKey, PrivateKeyBase): 1245 | """ Implements an HD Private Key according to BIP-0032: 1246 | https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki 1247 | 1248 | For the vast majority of use cases, the 3 static functions 1249 | (HDPrivateKey.master_key_from_entropy, 1250 | HDPrivateKey.master_key_from_seed and 1251 | HDPrivateKey.from_parent) will be used rather than directly 1252 | constructing an object. 1253 | 1254 | Args: 1255 | key (PrivateKey or PublicKey): The underlying simple private or 1256 | public key that is used to sign/verify. 1257 | chain_code (bytes): The chain code associated with the HD key. 1258 | depth (int): How many levels below the master node this key is. By 1259 | definition, depth = 0 for the master node. 1260 | index (int): A value between 0 and 0xffffffff indicating the child 1261 | number. Values >= 0x80000000 are considered hardened children. 1262 | parent_fingerprint (bytes): The fingerprint of the parent node. This 1263 | is 0x00000000 for the master node. 1264 | 1265 | Returns: 1266 | HDKey: An HDKey object. 1267 | 1268 | """ 1269 | MAINNET_VERSION = 0x0488ADE4 1270 | TESTNET_VERSION = 0x04358394 1271 | 1272 | @staticmethod 1273 | def master_key_from_mnemonic(mnemonic, passphrase=''): 1274 | """ Generates a master key from a mnemonic. 1275 | 1276 | Args: 1277 | mnemonic (str): The mnemonic sentence representing 1278 | the seed from which to generate the master key. 1279 | passphrase (str): Password if one was used. 1280 | 1281 | Returns: 1282 | HDPrivateKey: the master private key. 1283 | """ 1284 | return HDPrivateKey.master_key_from_seed( 1285 | Mnemonic.to_seed(mnemonic, passphrase)) 1286 | 1287 | @staticmethod 1288 | def master_key_from_entropy(passphrase='', strength=128): 1289 | """ Generates a master key from system entropy. 1290 | 1291 | Args: 1292 | strength (int): Amount of entropy desired. This should be 1293 | a multiple of 32 between 128 and 256. 1294 | passphrase (str): An optional passphrase for the generated 1295 | mnemonic string. 1296 | 1297 | Returns: 1298 | HDPrivateKey, str: 1299 | a tuple consisting of the master 1300 | private key and a mnemonic string from which the seed 1301 | can be recovered. 1302 | """ 1303 | if strength % 32 != 0: 1304 | raise ValueError("strength must be a multiple of 32") 1305 | if strength < 128 or strength > 256: 1306 | raise ValueError("strength should be >= 128 and <= 256") 1307 | entropy = rand_bytes(strength // 8) 1308 | m = Mnemonic(language='english') 1309 | n = m.to_mnemonic(entropy) 1310 | return HDPrivateKey.master_key_from_seed( 1311 | Mnemonic.to_seed(n, passphrase)), n 1312 | 1313 | @staticmethod 1314 | def master_key_from_seed(seed): 1315 | """ Generates a master key from a provided seed. 1316 | 1317 | Args: 1318 | seed (bytes or str): a string of bytes or a hex string 1319 | 1320 | Returns: 1321 | HDPrivateKey: the master private key. 1322 | """ 1323 | S = get_bytes(seed) 1324 | I = hmac.new(b"Bitcoin seed", S, hashlib.sha512).digest() 1325 | Il, Ir = I[:32], I[32:] 1326 | parse_Il = int.from_bytes(Il, 'big') 1327 | if parse_Il == 0 or parse_Il >= bitcoin_curve.n: 1328 | raise ValueError("Bad seed, resulting in invalid key!") 1329 | 1330 | return HDPrivateKey(key=parse_Il, chain_code=Ir, index=0, depth=0) 1331 | 1332 | @staticmethod 1333 | def from_parent(parent_key, i): 1334 | """ Derives a child private key from a parent 1335 | private key. It is not possible to derive a child 1336 | private key from a public parent key. 1337 | 1338 | Args: 1339 | parent_private_key (HDPrivateKey): 1340 | """ 1341 | if not isinstance(parent_key, HDPrivateKey): 1342 | raise TypeError("parent_key must be an HDPrivateKey object.") 1343 | 1344 | hmac_key = parent_key.chain_code 1345 | if i & 0x80000000: 1346 | hmac_data = b'\x00' + bytes(parent_key._key) + i.to_bytes(length=4, byteorder='big') 1347 | else: 1348 | hmac_data = parent_key.public_key.compressed_bytes + i.to_bytes(length=4, byteorder='big') 1349 | 1350 | I = hmac.new(hmac_key, hmac_data, hashlib.sha512).digest() 1351 | Il, Ir = I[:32], I[32:] 1352 | 1353 | parse_Il = int.from_bytes(Il, 'big') 1354 | if parse_Il >= bitcoin_curve.n: 1355 | return None 1356 | 1357 | child_key = (parse_Il + parent_key._key.key) % bitcoin_curve.n 1358 | 1359 | if child_key == 0: 1360 | # Incredibly unlucky choice 1361 | return None 1362 | 1363 | child_depth = parent_key.depth + 1 1364 | return HDPrivateKey(key=child_key, 1365 | chain_code=Ir, 1366 | index=i, 1367 | depth=child_depth, 1368 | parent_fingerprint=parent_key.fingerprint) 1369 | 1370 | def __init__(self, key, chain_code, index, depth, 1371 | parent_fingerprint=b'\x00\x00\x00\x00'): 1372 | if index < 0 or index > 0xffffffff: 1373 | raise ValueError("index is out of range: 0 <= index <= 2**32 - 1") 1374 | 1375 | private_key = PrivateKey(key) 1376 | HDKey.__init__(self, private_key, chain_code, index, depth, 1377 | parent_fingerprint) 1378 | self._public_key = None 1379 | 1380 | @property 1381 | def public_key(self): 1382 | """ Returns the public key associated with this private key. 1383 | 1384 | Returns: 1385 | HDPublicKey: 1386 | The HDPublicKey object that corresponds to this 1387 | private key. 1388 | """ 1389 | if self._public_key is None: 1390 | self._public_key = HDPublicKey(x=self._key.public_key.point.x, 1391 | y=self._key.public_key.point.y, 1392 | chain_code=self.chain_code, 1393 | index=self.index, 1394 | depth=self.depth, 1395 | parent_fingerprint=self.parent_fingerprint) 1396 | 1397 | return self._public_key 1398 | 1399 | def raw_sign(self, message, do_hash=True): 1400 | """ Signs message using the underlying non-extended private key. 1401 | 1402 | Args: 1403 | message (bytes): The message to be signed. If a string is 1404 | provided it is assumed the encoding is 'ascii' and 1405 | converted to bytes. If this is not the case, it is up 1406 | to the caller to convert the string to bytes 1407 | appropriately and pass in the bytes. 1408 | do_hash (bool): True if the message should be hashed prior 1409 | to signing, False if not. This should always be left as 1410 | True except in special situations which require doing 1411 | the hash outside (e.g. handling Bitcoin bugs). 1412 | 1413 | Returns: 1414 | ECPointAffine: 1415 | a raw point (r = pt.x, s = pt.y) which is 1416 | the signature. 1417 | """ 1418 | return self._key.raw_sign(message, do_hash) 1419 | 1420 | def sign(self, message, do_hash=True): 1421 | """ Signs message using the underlying non-extended private key. 1422 | 1423 | Note: 1424 | This differs from `raw_sign()` since it returns a Signature object. 1425 | 1426 | Args: 1427 | message (bytes or str): The message to be signed. If a 1428 | string is provided it is assumed the encoding is 1429 | 'ascii' and converted to bytes. If this is not the 1430 | case, it is up to the caller to convert the string to 1431 | bytes appropriately and pass in the bytes. 1432 | do_hash (bool): True if the message should be hashed prior 1433 | to signing, False if not. This should always be left as 1434 | True except in special situations which require doing 1435 | the hash outside (e.g. handling Bitcoin bugs). 1436 | 1437 | Returns: 1438 | Signature: The signature corresponding to message. 1439 | """ 1440 | return self._key.sign(message, do_hash) 1441 | 1442 | def sign_bitcoin(self, message, compressed=False): 1443 | """ Signs a message using the underlying non-extended private 1444 | key such that it is compatible with bitcoind, bx, and other 1445 | Bitcoin clients/nodes/utilities. 1446 | 1447 | Note: 1448 | 0x18 + b\"Bitcoin Signed Message:" + newline + len(message) is 1449 | prepended to the message before signing. 1450 | 1451 | Args: 1452 | message (bytes or str): Message to be signed. 1453 | compressed (bool): 1454 | True if the corresponding public key will be 1455 | used in compressed format. False if the uncompressed version 1456 | is used. 1457 | 1458 | Returns: 1459 | bytes: A Base64-encoded byte string of the signed message. 1460 | The first byte of the encoded message contains information 1461 | about how to recover the public key. In bitcoind parlance, 1462 | this is the magic number containing the recovery ID and 1463 | whether or not the key was compressed or not. (This function 1464 | always processes full, uncompressed public-keys, so the 1465 | magic number will always be either 27 or 28). 1466 | """ 1467 | 1468 | return self._key.sign_bitcoin(message, compressed) 1469 | 1470 | @property 1471 | def identifier(self): 1472 | """ Returns the identifier for the key. 1473 | 1474 | A key's identifier and fingerprint are defined as: 1475 | https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#key-identifiers 1476 | 1477 | In this case, it will return the RIPEMD-160 hash of the 1478 | corresponding public key. 1479 | 1480 | Returns: 1481 | bytes: A 20-byte RIPEMD-160 hash. 1482 | """ 1483 | return self.public_key.hash160() 1484 | 1485 | def __int__(self): 1486 | return int(self.key) 1487 | 1488 | 1489 | class HDPublicKey(HDKey, PublicKeyBase): 1490 | """ Implements an HD Public Key according to BIP-0032: 1491 | https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki 1492 | 1493 | For the vast majority of use cases, the static function 1494 | HDPublicKey.from_parent() will be used rather than directly 1495 | constructing an object. 1496 | 1497 | Args: 1498 | x (int): x component of the point representing the public key. 1499 | y (int): y component of the point representing the public key. 1500 | chain_code (bytes): The chain code associated with the HD key. 1501 | depth (int): How many levels below the master node this key is. By 1502 | definition, depth = 0 for the master node. 1503 | index (int): A value between 0 and 0xffffffff indicating the child 1504 | number. Values >= 0x80000000 are considered hardened children. 1505 | parent_fingerprint (bytes): The fingerprint of the parent node. This 1506 | is 0x00000000 for the master node. 1507 | 1508 | Returns: 1509 | HDPublicKey: An HDPublicKey object. 1510 | 1511 | """ 1512 | 1513 | MAINNET_VERSION = 0x0488B21E 1514 | TESTNET_VERSION = 0x043587CF 1515 | 1516 | @staticmethod 1517 | def from_parent(parent_key, i): 1518 | """ 1519 | """ 1520 | if isinstance(parent_key, HDPrivateKey): 1521 | # Get child private key 1522 | return HDPrivateKey.from_parent(parent_key, i).public_key 1523 | elif isinstance(parent_key, HDPublicKey): 1524 | if i & 0x80000000: 1525 | raise ValueError("Can't generate a hardened child key from a parent public key.") 1526 | else: 1527 | I = hmac.new(parent_key.chain_code, 1528 | parent_key.compressed_bytes + i.to_bytes(length=4, byteorder='big'), 1529 | hashlib.sha512).digest() 1530 | Il, Ir = I[:32], I[32:] 1531 | parse_Il = int.from_bytes(Il, 'big') 1532 | if parse_Il >= bitcoin_curve.n: 1533 | return None 1534 | 1535 | temp_priv_key = PrivateKey(parse_Il) 1536 | Ki = temp_priv_key.public_key.point + parent_key._key.point 1537 | if Ki.infinity: 1538 | return None 1539 | 1540 | child_depth = parent_key.depth + 1 1541 | return HDPublicKey(x=Ki.x, 1542 | y=Ki.y, 1543 | chain_code=Ir, 1544 | index=i, 1545 | depth=child_depth, 1546 | parent_fingerprint=parent_key.fingerprint) 1547 | else: 1548 | raise TypeError("parent_key must be either a HDPrivateKey or HDPublicKey object") 1549 | 1550 | def __init__(self, x, y, chain_code, index, depth, 1551 | parent_fingerprint=b'\x00\x00\x00\x00'): 1552 | key = PublicKey(x, y) 1553 | HDKey.__init__(self, key, chain_code, index, depth, parent_fingerprint) 1554 | PublicKeyBase.__init__(self) 1555 | 1556 | @property 1557 | def identifier(self): 1558 | """ Returns the identifier for the key. 1559 | 1560 | A key's identifier and fingerprint are defined as: 1561 | https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#key-identifiers 1562 | 1563 | In this case, it will return the RIPEMD-160 hash of the 1564 | non-extended public key. 1565 | 1566 | Returns: 1567 | bytes: A 20-byte RIPEMD-160 hash. 1568 | """ 1569 | return self.hash160() 1570 | 1571 | def hash160(self, compressed=True): 1572 | """ Return the RIPEMD-160 hash of the SHA-256 hash of the 1573 | non-extended public key. 1574 | 1575 | Note: 1576 | This always returns the hash of the compressed version of 1577 | the public key. 1578 | 1579 | Returns: 1580 | bytes: RIPEMD-160 byte string. 1581 | """ 1582 | return self._key.hash160(True) 1583 | 1584 | def address(self, compressed=True, testnet=False): 1585 | """ Address property that returns the Base58Check 1586 | encoded version of the HASH160. 1587 | 1588 | Args: 1589 | compressed (bool): Whether or not the compressed key should 1590 | be used. 1591 | testnet (bool): Whether or not the key is intended for testnet 1592 | usage. False indicates mainnet usage. 1593 | 1594 | Returns: 1595 | bytes: Base58Check encoded string 1596 | """ 1597 | return self._key.address(True) 1598 | 1599 | def verify(self, message, signature, do_hash=True): 1600 | """ Verifies that message was appropriately signed. 1601 | 1602 | Args: 1603 | message (bytes): The message to be verified. 1604 | signature (Signature): A signature object. 1605 | do_hash (bool): True if the message should be hashed prior 1606 | to signing, False if not. This should always be left as 1607 | True except in special situations which require doing 1608 | the hash outside (e.g. handling Bitcoin bugs). 1609 | 1610 | Returns: 1611 | verified (bool): True if the signature is verified, False 1612 | otherwise. 1613 | """ 1614 | return self._key.verify(message, signature, do_hash) 1615 | 1616 | @property 1617 | def compressed_bytes(self): 1618 | """ Byte string corresponding to a compressed representation 1619 | of this public key. 1620 | 1621 | Returns: 1622 | b (bytes): A 33-byte long byte string. 1623 | """ 1624 | return self._key.compressed_bytes 1625 | -------------------------------------------------------------------------------- /ecdsa.py: -------------------------------------------------------------------------------- 1 | try: 2 | import ecdsa_openssl as _ecdsa 3 | except: 4 | import ecdsa_python as _ecdsa 5 | 6 | ECPointAffine = _ecdsa.ECPointAffine 7 | EllipticCurve = _ecdsa.EllipticCurve 8 | secp256k1 = _ecdsa.secp256k1 -------------------------------------------------------------------------------- /ecdsa_base.py: -------------------------------------------------------------------------------- 1 | from collections import namedtuple 2 | import hmac 3 | import random 4 | 5 | 6 | Point = namedtuple('Point', ['x', 'y']) 7 | 8 | 9 | class EllipticCurveBase(object): 10 | """ A generic class for elliptic curves and operations on them. 11 | The curves must be of the form: y^2 = x^3 + a*x + b. 12 | """ 13 | 14 | def __init__(self, hash_function): 15 | self.hash_function = hash_function 16 | 17 | def is_on_curve(self, p): 18 | """ Checks whether a point is on the curve. 19 | Args: 20 | p (ECPointAffine): Point to be checked 21 | Returns: 22 | bool: True if p is on the curve, False otherwise. 23 | """ 24 | raise NotImplementedError 25 | 26 | def y_from_x(self, x): 27 | """ Computes the y component corresponding to x. 28 | Since elliptic curves are symmetric about the x-axis, 29 | the x component (and sign) is all that is required to determine 30 | a point on the curve. 31 | Args: 32 | x (int): x component of the point. 33 | Returns: 34 | tuple: both possible y components of the point. 35 | """ 36 | raise NotImplementedError 37 | 38 | def gen_key_pair(self, random_generator=random.SystemRandom()): 39 | """ Generates a public/private key pair. 40 | Args: 41 | random_generator (generator): The random generator to use. 42 | Returns: 43 | tuple: A private key in the range of 1 to `self.n - 1` 44 | and an ECPointAffine containing the public key point. 45 | """ 46 | raise NotImplementedError 47 | 48 | def public_key(self, private_key): 49 | """ Returns the public (verifying) key for a given private key. 50 | Args: 51 | private_key (int): the private key to derive the public key for. 52 | Returns: 53 | ECPointAffine: The point representing the public key. 54 | """ 55 | raise NotImplementedError 56 | 57 | def recover_public_key(self, message, signature, recovery_id=None): 58 | """ Recovers possibilities for the public key associated with the 59 | private key used to sign message and generate signature. 60 | Since there are multiple possibilities (two for curves with 61 | co-factor = 1), each possibility that successfully verifies the 62 | signature is returned. 63 | Args: 64 | message (bytes): The message that was signed. 65 | signature (ECPointAffine): The point representing the signature. 66 | recovery_id (int) (Optional): If provided, limits the valid x and y 67 | point to only that described by the recovery_id. 68 | Returns: 69 | list(ECPointAffine): List of points representing valid public 70 | keys that verify signature. 71 | """ 72 | raise NotImplementedError 73 | 74 | def _sign(self, message, private_key, do_hash=True, secret=None): 75 | raise NotImplementedError 76 | 77 | def sign(self, message, private_key, do_hash=True): 78 | """ Signs a message with the given private key. 79 | Args: 80 | message (bytes): The message to be signed 81 | private_key (int): Integer that is the private key 82 | do_hash (bool): True if the message should be hashed prior 83 | to signing, False if not. This should always be left as 84 | True except in special situations which require doing 85 | the hash outside (e.g. handling Bitcoin bugs). 86 | Returns: 87 | (Point, int): The point (r, s) representing the signature 88 | and the ID representing which public key possibility 89 | is associated with the private key being used to sign. 90 | """ 91 | return self._sign(message, private_key, do_hash) 92 | 93 | def verify(self, message, signature, public_key, do_hash=True): 94 | """ Verifies that signature was generated with a private key corresponding 95 | to public key, operating on message. 96 | Args: 97 | message (bytes): The message to be signed 98 | signature (Point): (r, s) representing the signature 99 | public_key (ECPointAffine): ECPointAffine of the public key 100 | do_hash (bool): True if the message should be hashed prior 101 | to signing, False if not. This should always be left as 102 | True except in special situations which require doing 103 | the hash outside (e.g. handling Bitcoin bugs). 104 | Returns: 105 | bool: True if the signature is verified, False otherwise. 106 | """ 107 | raise NotImplementedError 108 | 109 | def _nonce_random(self): 110 | return random.SystemRandom().randrange(1, self.n - 1) 111 | 112 | def _nonce_rfc6979(self, private_key, message): 113 | """ Computes a deterministic nonce (k) for use when signing 114 | according to RFC6979 (https://tools.ietf.org/html/rfc6979), 115 | Section 3.2. 116 | Args: 117 | private_key (int): The private key. 118 | message (bytes): A hash of the input message. 119 | Returns: 120 | int: A deterministic nonce. 121 | """ 122 | hash_bytes = 32 123 | x = private_key.to_bytes(hash_bytes, 'big') 124 | # Message should already be hashed by the time it gets here, 125 | # so don't bother doing another hash. 126 | x_msg = x + message 127 | 128 | # Step b 129 | V = bytes([0x1] * hash_bytes) 130 | 131 | # Step c 132 | K = bytes([0x0] * hash_bytes) 133 | 134 | # Step d 135 | K = hmac.new(K, V + bytes([0]) + x_msg, self.hash_function).digest() 136 | 137 | # Step e 138 | V = hmac.new(K, V, self.hash_function).digest() 139 | 140 | # Step f 141 | K = hmac.new(K, V + bytes([0x1]) + x_msg, self.hash_function).digest() 142 | 143 | # Step g 144 | V = hmac.new(K, V, self.hash_function).digest() 145 | 146 | while True: 147 | # Step h.1 148 | T = bytes() 149 | 150 | # Step h.2 151 | while 8 * len(T) < self.nlen: 152 | V = hmac.new(K, V, self.hash_function).digest() 153 | T += V 154 | 155 | # Step h.3 156 | k = int.from_bytes(T, 'big') 157 | if k >= 1 and k < (self.n - 1): 158 | return k 159 | 160 | K = hmac.new(K, V + bytes([0]), self.hash_function).digest() 161 | V = hmac.new(K, V, self.hash_function).digest() -------------------------------------------------------------------------------- /ecdsa_openssl.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | import math 3 | import random 4 | 5 | from ctypes import c_char_p 6 | from ctypes import c_void_p 7 | from ctypes import create_string_buffer 8 | 9 | from ecdsa_base import EllipticCurveBase 10 | from ecdsa_base import Point 11 | import openssl as ossl 12 | 13 | 14 | class ECPointAffine(object): 15 | """ An affine (2D) representation of an elliptic curve point. 16 | In this implementation, only the minimum functionality 17 | required for bitcoin crypto-API compatibility is provided. 18 | All math operations make use of OpenSSL primitives. 19 | Args: 20 | curve (EllipticCurve): The curve the point is on. 21 | x (int): x component of point. 22 | y (int): y component of point. 23 | infinity (bool): Whether or not this point is at infinity. 24 | Returns: 25 | ECPointAffine: the point formed by (x, y) on curve. 26 | """ 27 | 28 | def __init__(self, curve, x, y, infinity=False): 29 | self.x = x 30 | self.y = y 31 | self.curve = curve 32 | self.infinity = infinity 33 | 34 | def __str__(self): 35 | return "(0x%x, 0x%x)" % (self.x, self.y) 36 | 37 | def __eq__(self, b): 38 | return ((self.x == b.x) and (self.y == b.y)) or \ 39 | (self.infinity and b.infinity) 40 | 41 | def __add__(self, b): 42 | assert self.curve == b.curve 43 | 44 | a_pt = ossl.point_new_from_ints(self.curve.os_group, self.x, self.y, self.infinity) 45 | b_pt = ossl.point_new_from_ints(b.curve.os_group, b.x, b.y, b.infinity) 46 | ossl.lc.EC_POINT_add(self.curve.os_group, a_pt, a_pt, b_pt, None) 47 | 48 | x, y, inf = ossl.point_get_xy_ints(self.curve.os_group, a_pt) 49 | 50 | ossl.lc.EC_POINT_free(a_pt) 51 | ossl.lc.EC_POINT_free(b_pt) 52 | 53 | return ECPointAffine(self.curve, x, y, inf) 54 | 55 | @property 56 | def compressed_bytes(self): 57 | """ Returns the compressed bytes for this point. 58 | If pt.y is odd, 0x03 is pre-pended to pt.x. 59 | If pt.y is even, 0x02 is pre-pended to pt.x. 60 | Returns: 61 | bytes: Compressed byte representation. 62 | """ 63 | nbytes = math.ceil(self.curve.nlen / 8) 64 | return bytes([(self.y & 0x1) + 0x02]) + self.x.to_bytes(nbytes, 'big') 65 | 66 | def __bytes__(self): 67 | """ Returns the full-uncompressed point 68 | """ 69 | nbytes = math.ceil(self.curve.nlen / 8) 70 | return bytes([0x04]) + self.x.to_bytes(nbytes, 'big') + self.y.to_bytes(nbytes, 'big') 71 | 72 | 73 | class EllipticCurve(EllipticCurveBase): 74 | """ A generic class for elliptic curves and operations on them. 75 | The curves must be of the form: y^2 = x^3 + a*x + b. 76 | Args: 77 | hash_function (function): The function to use for hashing messages. 78 | """ 79 | curve_name = None 80 | 81 | def __init__(self, hash_function): 82 | super().__init__(hash_function) 83 | self.os_group = c_void_p(ossl.lc.EC_GROUP_new_by_curve_name( 84 | self.curve_name)) 85 | 86 | params = ossl.get_curve_params(self.os_group) 87 | 88 | self.p = params['p'] 89 | self.a = params['a'] 90 | self.b = params['b'] 91 | self.n = params['n'] 92 | self.h = params['h'] 93 | 94 | self.nlen = self.n.bit_length() 95 | self.plen = self.p.bit_length() 96 | 97 | # We keep a pointer to the libcrypto CDLL object so that 98 | # it is guaranteed to be around when __del__ is called. If 99 | # we don't, a race condition exists whereby if the garbage 100 | # collector disposes of ossl.lc before this object, we won't 101 | # be able to free self.os_group (in __del__). 102 | self._lc = ossl.lc 103 | 104 | def __del__(self): 105 | self._lc.EC_GROUP_free(self.os_group) 106 | 107 | def is_on_curve(self, p): 108 | """ Checks whether a point is on the curve. 109 | Args: 110 | p (ECPointAffine): Point to be checked 111 | Returns: 112 | bool: True if p is on the curve, False otherwise. 113 | """ 114 | ec_pt = ossl.point_new_from_ints(self.os_group, p.x, p.y) 115 | on_curve = ossl.lc.EC_POINT_is_on_curve(self.os_group, ec_pt, None) 116 | ossl.lc.EC_POINT_free(ec_pt) 117 | 118 | return bool(on_curve) 119 | 120 | def y_from_x(self, x): 121 | """ Computes the y component corresponding to x. 122 | Since elliptic curves are symmetric about the x-axis, 123 | the x component (and sign) is all that is required to determine 124 | a point on the curve. 125 | Args: 126 | x (int): x component of the point. 127 | Returns: 128 | tuple: both possible y components of the point. 129 | """ 130 | rv = [] 131 | x_bn = ossl.int_to_bn(x) 132 | for y_bit in [0, 1]: 133 | # Create a new point 134 | ec_pt = c_void_p(ossl.lc.EC_POINT_new(self.os_group)) 135 | ossl.lc.EC_POINT_set_compressed_coordinates_GFp(self.os_group, 136 | ec_pt, 137 | x_bn, 138 | y_bit, 139 | c_void_p()) 140 | 141 | on_curve = ossl.lc.EC_POINT_is_on_curve(self.os_group, 142 | ec_pt, 143 | c_void_p()) 144 | if not on_curve: 145 | ossl.lc.EC_POINT_free(ec_pt) 146 | rv.append(None) 147 | continue 148 | 149 | # Get the y value 150 | _, y, _ = ossl.point_get_xy_ints(self.os_group, ec_pt) 151 | rv.append(y) 152 | ossl.lc.EC_POINT_free(ec_pt) 153 | 154 | ossl.lc.BN_free(x_bn) 155 | 156 | return rv 157 | 158 | def gen_key_pair(self, random_generator=random.SystemRandom()): 159 | """ Generates a public/private key pair. 160 | Args: 161 | random_generator (generator): The random generator to use. 162 | Returns: 163 | tuple: 164 | A private key in the range of 1 to `self.n - 1` 165 | and an ECPointAffine containing the public key point. 166 | """ 167 | private = random_generator.randrange(1, self.n) 168 | return private, self.public_key(private) 169 | 170 | def public_key(self, private_key): 171 | """ Returns the public (verifying) key for a given private key. 172 | Args: 173 | private_key (int): the private key to derive the public key for. 174 | Returns: 175 | ECPointAffine: The point representing the public key. 176 | """ 177 | k = ossl.new_key(self.curve_name, private_key) 178 | pub_x, pub_y, is_inf = ossl.get_public_key_ints(k) 179 | ossl.lc.EC_KEY_free(k) 180 | return ECPointAffine(self, pub_x, pub_y, is_inf) 181 | 182 | def recover_public_key(self, message, signature, recovery_id=None): 183 | """ Recovers possibilities for the public key associated with the 184 | private key used to sign message and generate signature. 185 | Since there are multiple possibilities (two for curves with 186 | co-factor = 1), each possibility that successfully verifies the 187 | signature is returned. 188 | Args: 189 | message (bytes): The message that was signed. 190 | signature (ECPointAffine): The point representing the signature. 191 | recovery_id (int) (Optional): If provided, limits the valid x and y 192 | point to only that described by the recovery_id. 193 | Returns: 194 | list(ECPointAffine): List of points representing valid public 195 | keys that verify signature. 196 | """ 197 | r = signature.x 198 | s = signature.y 199 | 200 | ctx = c_void_p(ossl.lc.BN_CTX_new()) 201 | ossl.lc.BN_CTX_start(ctx) 202 | 203 | order_bn = c_void_p(ossl.lc.BN_CTX_get(ctx)) 204 | x_bn = c_void_p(ossl.lc.BN_CTX_get(ctx)) 205 | i_bn = c_void_p(ossl.lc.BN_CTX_get(ctx)) 206 | in_bn = c_void_p(ossl.lc.BN_CTX_get(ctx)) 207 | p_bn = c_void_p(ossl.lc.BN_CTX_get(ctx)) 208 | r_bn = c_void_p(ossl.lc.BN_CTX_get(ctx)) 209 | s_bn = c_void_p(ossl.lc.BN_CTX_get(ctx)) 210 | rinv_bn = c_void_p(ossl.lc.BN_CTX_get(ctx)) 211 | z_bn = c_void_p(ossl.lc.BN_CTX_get(ctx)) 212 | ossl.lc.EC_GROUP_get_order(self.os_group, order_bn, ctx) 213 | 214 | ossl.int_to_bn(self.p, p_bn) 215 | ossl.int_to_bn(r, r_bn) 216 | ossl.int_to_bn(s, s_bn) 217 | ossl.lc.BN_mod_inverse(rinv_bn, r_bn, order_bn, ctx) 218 | 219 | if recovery_id is not None: 220 | i_list = [recovery_id >> 1] 221 | k_list = [recovery_id & 0x1] 222 | else: 223 | i_list = range(2) 224 | k_list = range(2) 225 | 226 | rv = [] 227 | num_bytes = math.ceil(self.nlen / 8) 228 | 229 | z = int.from_bytes(self.hash_function(message).digest()[:num_bytes], 'big') 230 | ossl.int_to_bn(z, z_bn) 231 | 232 | zG = c_void_p(ossl.lc.EC_POINT_new(self.os_group)) 233 | sR = c_void_p(ossl.lc.EC_POINT_new(self.os_group)) 234 | temp = c_void_p(ossl.lc.EC_POINT_new(self.os_group)) 235 | pub_key = c_void_p(ossl.lc.EC_POINT_new(self.os_group)) 236 | Rn = c_void_p(ossl.lc.EC_POINT_new(self.os_group)) 237 | 238 | for i in i_list: 239 | ossl.int_to_bn(i, i_bn) 240 | ossl.lc.BN_mod_mul(in_bn, i_bn, order_bn, p_bn, ctx) 241 | ossl.lc.BN_mod_add(x_bn, r_bn, in_bn, p_bn, ctx) 242 | x = ossl.bn_to_int(x_bn) 243 | ys = self.y_from_x(x) 244 | 245 | for k in k_list: 246 | y = ys[k] 247 | if y & 0x1 != k: 248 | y = ys[k ^ 1] 249 | 250 | R = ossl.point_new_from_ints(self.os_group, r, y) 251 | ossl.lc.EC_POINT_mul(self.os_group, 252 | Rn, 253 | None, 254 | R, 255 | order_bn, 256 | ctx) 257 | if not ossl.lc.EC_POINT_is_at_infinity(self.os_group, Rn): 258 | continue 259 | 260 | ossl.lc.EC_POINT_mul(self.os_group, 261 | zG, 262 | z_bn, 263 | None, 264 | None, 265 | ctx) 266 | ossl.lc.EC_POINT_invert(self.os_group, zG, ctx) 267 | ossl.lc.EC_POINT_mul(self.os_group, 268 | sR, 269 | None, 270 | R, 271 | s_bn, 272 | ctx) 273 | ossl.lc.EC_POINT_add(self.os_group, temp, sR, zG, ctx) 274 | ossl.lc.EC_POINT_mul(self.os_group, 275 | pub_key, 276 | None, 277 | temp, 278 | rinv_bn, 279 | ctx) 280 | 281 | ossl.lc.EC_POINT_free(R) 282 | 283 | # Convert to ECPointAffine 284 | pub_x, pub_y, inf = ossl.point_get_xy_ints(self.os_group, pub_key) 285 | rv.append((ECPointAffine(self, pub_x, pub_y, inf), 2 * i + k)) 286 | 287 | ossl.lc.EC_POINT_free(zG) 288 | ossl.lc.EC_POINT_free(sR) 289 | ossl.lc.EC_POINT_free(temp) 290 | ossl.lc.EC_POINT_free(pub_key) 291 | ossl.lc.EC_POINT_free(Rn) 292 | 293 | ossl.lc.BN_CTX_end(ctx) 294 | ossl.lc.BN_CTX_free(ctx) 295 | 296 | return rv 297 | 298 | def _sign(self, message, private_key, do_hash=True, secret=None): 299 | # This function computes k, kinv and rp before sending into 300 | # OpenSSL ECDSA_do_sign_ex() rather than using ECDSA_do_sign() 301 | # directly. The reason for this is that as of the commit that 302 | # introduces this comment, OpenSSL only supports deterministic 303 | # signing nonces (RFC6979) in the master branch and not any 304 | # release. As a result, we cannot depend on callers having any 305 | # OpenSSL version capable of RFC6979 deterministic nonces. 306 | # Nevertheless, computation of kinv (from k) and rp is done 307 | # using OpenSSL primitives. 308 | ossl.lc.ERR_clear_error() 309 | 310 | hashed = self.hash_function(message).digest() if do_hash else message 311 | 312 | r = 0 313 | s = 0 314 | recovery_id = 0 315 | 316 | key = ossl.new_key(self.curve_name, private_key) 317 | 318 | ctx = c_void_p(ossl.lc.BN_CTX_new()) 319 | ossl.lc.BN_CTX_start(ctx) 320 | 321 | order_bn = c_void_p(ossl.lc.BN_CTX_get(ctx)) 322 | k_bn = c_void_p(ossl.lc.BN_CTX_get(ctx)) 323 | kinv_bn = c_void_p(ossl.lc.BN_CTX_get(ctx)) 324 | px_bn = c_void_p(ossl.lc.BN_CTX_get(ctx)) 325 | r_bn = c_void_p(ossl.lc.BN_CTX_get(ctx)) 326 | ossl.lc.EC_GROUP_get_order(self.os_group, order_bn, ctx) 327 | 328 | while r == 0 or s == 0: 329 | k = self._nonce_rfc6979(private_key, hashed) if secret is None else secret 330 | ossl.int_to_bn(k, k_bn) 331 | 332 | ossl.lc.BN_mod_inverse(kinv_bn, k_bn, order_bn, ctx) 333 | 334 | p = c_void_p(ossl.lc.EC_POINT_new(self.os_group)) 335 | ossl.lc.EC_POINT_mul(self.os_group, 336 | p, 337 | k_bn, 338 | c_void_p(), 339 | c_void_p(), 340 | ctx) 341 | assert self.h == 1 342 | 343 | px, py, _ = ossl.point_get_xy_ints(self.os_group, p) 344 | recovery_id = 2 if px > self.n else 0 345 | recovery_id |= (py & 0x1) 346 | 347 | # Get r 348 | ossl.int_to_bn(px, px_bn) 349 | ossl.lc.BN_nnmod(r_bn, px_bn, order_bn, ctx) 350 | r = ossl.bn_to_int(r_bn) 351 | 352 | if r == 0: 353 | continue 354 | 355 | hashed_buf = c_char_p(hashed) 356 | sig = ossl.lc.ECDSA_do_sign_ex(hashed_buf, 357 | len(hashed), 358 | kinv_bn, 359 | r_bn, 360 | key) 361 | err = ossl.lc.ERR_peek_error() 362 | if err: 363 | err_buf = create_string_buffer(120) 364 | ossl.lc.ERR_error_string(err, err_buf) 365 | raise Exception("Problem when signing: %s" % 366 | err_buf.raw.decode()) 367 | 368 | sig_r = ossl.bn_to_int(sig.contents.r) 369 | sig_s = ossl.bn_to_int(sig.contents.s) 370 | 371 | if sig_r != r: 372 | raise ValueError("Didn't get the same r value.") 373 | s = sig_s 374 | 375 | ossl.lc.EC_KEY_free(key) 376 | ossl.lc.BN_CTX_end(ctx) 377 | ossl.lc.BN_CTX_free(ctx) 378 | 379 | return (Point(r, s), recovery_id) 380 | 381 | def verify(self, message, signature, public_key, do_hash=True): 382 | """ Verifies that signature was generated with a private key corresponding 383 | to public key, operating on message. 384 | Args: 385 | message (bytes): The message to be signed 386 | signature (Point): (r, s) representing the signature 387 | public_key (ECPointAffine): ECPointAffine of the public key 388 | do_hash (bool): True if the message should be hashed prior 389 | to signing, False if not. This should always be left as 390 | True except in special situations which require doing 391 | the hash outside (e.g. handling Bitcoin bugs). 392 | Returns: 393 | bool: True if the signature is verified, False otherwise. 394 | """ 395 | r = signature.x 396 | s = signature.y 397 | 398 | sig = ossl.sig_new_from_ints(r, s) 399 | 400 | hashed = self.hash_function(message).digest() if do_hash else message 401 | 402 | key = c_void_p(ossl.lc.EC_KEY_new_by_curve_name(self.curve_name)) 403 | ossl.set_public_key_from_ints(key=key, 404 | x=public_key.x, 405 | y=public_key.y, 406 | infinity=public_key.infinity) 407 | 408 | dig_buf = create_string_buffer(hashed) 409 | verified = ossl.lc.ECDSA_do_verify(dig_buf, len(hashed), sig, key) 410 | 411 | ossl.lc.ECDSA_SIG_free(sig) 412 | ossl.lc.EC_KEY_free(key) 413 | 414 | return bool(verified) 415 | 416 | 417 | class p256(EllipticCurve): 418 | curve_name = ossl.lc.OBJ_sn2nid(c_char_p(b"prime256v1")) 419 | 420 | def __init__(self): 421 | super().__init__(hashlib.sha256) 422 | 423 | 424 | class secp256k1(EllipticCurve): 425 | curve_name = ossl.lc.OBJ_sn2nid(c_char_p(b"secp256k1")) 426 | 427 | def __init__(self): 428 | super().__init__(hashlib.sha256) -------------------------------------------------------------------------------- /ecdsa_python.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | import math 3 | import random 4 | 5 | from ctypes import c_char_p 6 | from ctypes import c_void_p 7 | from ctypes import create_string_buffer 8 | 9 | from ecdsa_base import EllipticCurveBase 10 | from ecdsa_base import Point 11 | import openssl as ossl 12 | 13 | 14 | class ECPointAffine(object): 15 | """ An affine (2D) representation of an elliptic curve point. 16 | In this implementation, only the minimum functionality 17 | required for bitcoin crypto-API compatibility is provided. 18 | All math operations make use of OpenSSL primitives. 19 | Args: 20 | curve (EllipticCurve): The curve the point is on. 21 | x (int): x component of point. 22 | y (int): y component of point. 23 | infinity (bool): Whether or not this point is at infinity. 24 | Returns: 25 | ECPointAffine: the point formed by (x, y) on curve. 26 | """ 27 | 28 | def __init__(self, curve, x, y, infinity=False): 29 | self.x = x 30 | self.y = y 31 | self.curve = curve 32 | self.infinity = infinity 33 | 34 | def __str__(self): 35 | return "(0x%x, 0x%x)" % (self.x, self.y) 36 | 37 | def __eq__(self, b): 38 | return ((self.x == b.x) and (self.y == b.y)) or \ 39 | (self.infinity and b.infinity) 40 | 41 | def __add__(self, b): 42 | assert self.curve == b.curve 43 | 44 | a_pt = ossl.point_new_from_ints(self.curve.os_group, self.x, self.y, self.infinity) 45 | b_pt = ossl.point_new_from_ints(b.curve.os_group, b.x, b.y, b.infinity) 46 | ossl.lc.EC_POINT_add(self.curve.os_group, a_pt, a_pt, b_pt, None) 47 | 48 | x, y, inf = ossl.point_get_xy_ints(self.curve.os_group, a_pt) 49 | 50 | ossl.lc.EC_POINT_free(a_pt) 51 | ossl.lc.EC_POINT_free(b_pt) 52 | 53 | return ECPointAffine(self.curve, x, y, inf) 54 | 55 | @property 56 | def compressed_bytes(self): 57 | """ Returns the compressed bytes for this point. 58 | If pt.y is odd, 0x03 is pre-pended to pt.x. 59 | If pt.y is even, 0x02 is pre-pended to pt.x. 60 | Returns: 61 | bytes: Compressed byte representation. 62 | """ 63 | nbytes = math.ceil(self.curve.nlen / 8) 64 | return bytes([(self.y & 0x1) + 0x02]) + self.x.to_bytes(nbytes, 'big') 65 | 66 | def __bytes__(self): 67 | """ Returns the full-uncompressed point 68 | """ 69 | nbytes = math.ceil(self.curve.nlen / 8) 70 | return bytes([0x04]) + self.x.to_bytes(nbytes, 'big') + self.y.to_bytes(nbytes, 'big') 71 | 72 | 73 | class EllipticCurve(EllipticCurveBase): 74 | """ A generic class for elliptic curves and operations on them. 75 | The curves must be of the form: y^2 = x^3 + a*x + b. 76 | Args: 77 | hash_function (function): The function to use for hashing messages. 78 | """ 79 | curve_name = None 80 | 81 | def __init__(self, hash_function): 82 | super().__init__(hash_function) 83 | self.os_group = c_void_p(ossl.lc.EC_GROUP_new_by_curve_name( 84 | self.curve_name)) 85 | 86 | params = ossl.get_curve_params(self.os_group) 87 | 88 | self.p = params['p'] 89 | self.a = params['a'] 90 | self.b = params['b'] 91 | self.n = params['n'] 92 | self.h = params['h'] 93 | 94 | self.nlen = self.n.bit_length() 95 | self.plen = self.p.bit_length() 96 | 97 | # We keep a pointer to the libcrypto CDLL object so that 98 | # it is guaranteed to be around when __del__ is called. If 99 | # we don't, a race condition exists whereby if the garbage 100 | # collector disposes of ossl.lc before this object, we won't 101 | # be able to free self.os_group (in __del__). 102 | self._lc = ossl.lc 103 | 104 | def __del__(self): 105 | self._lc.EC_GROUP_free(self.os_group) 106 | 107 | def is_on_curve(self, p): 108 | """ Checks whether a point is on the curve. 109 | Args: 110 | p (ECPointAffine): Point to be checked 111 | Returns: 112 | bool: True if p is on the curve, False otherwise. 113 | """ 114 | ec_pt = ossl.point_new_from_ints(self.os_group, p.x, p.y) 115 | on_curve = ossl.lc.EC_POINT_is_on_curve(self.os_group, ec_pt, None) 116 | ossl.lc.EC_POINT_free(ec_pt) 117 | 118 | return bool(on_curve) 119 | 120 | def y_from_x(self, x): 121 | """ Computes the y component corresponding to x. 122 | Since elliptic curves are symmetric about the x-axis, 123 | the x component (and sign) is all that is required to determine 124 | a point on the curve. 125 | Args: 126 | x (int): x component of the point. 127 | Returns: 128 | tuple: both possible y components of the point. 129 | """ 130 | rv = [] 131 | x_bn = ossl.int_to_bn(x) 132 | for y_bit in [0, 1]: 133 | # Create a new point 134 | ec_pt = c_void_p(ossl.lc.EC_POINT_new(self.os_group)) 135 | ossl.lc.EC_POINT_set_compressed_coordinates_GFp(self.os_group, 136 | ec_pt, 137 | x_bn, 138 | y_bit, 139 | c_void_p()) 140 | 141 | on_curve = ossl.lc.EC_POINT_is_on_curve(self.os_group, 142 | ec_pt, 143 | c_void_p()) 144 | if not on_curve: 145 | ossl.lc.EC_POINT_free(ec_pt) 146 | rv.append(None) 147 | continue 148 | 149 | # Get the y value 150 | _, y, _ = ossl.point_get_xy_ints(self.os_group, ec_pt) 151 | rv.append(y) 152 | ossl.lc.EC_POINT_free(ec_pt) 153 | 154 | ossl.lc.BN_free(x_bn) 155 | 156 | return rv 157 | 158 | def gen_key_pair(self, random_generator=random.SystemRandom()): 159 | """ Generates a public/private key pair. 160 | Args: 161 | random_generator (generator): The random generator to use. 162 | Returns: 163 | tuple: 164 | A private key in the range of 1 to `self.n - 1` 165 | and an ECPointAffine containing the public key point. 166 | """ 167 | private = random_generator.randrange(1, self.n) 168 | return private, self.public_key(private) 169 | 170 | def public_key(self, private_key): 171 | """ Returns the public (verifying) key for a given private key. 172 | Args: 173 | private_key (int): the private key to derive the public key for. 174 | Returns: 175 | ECPointAffine: The point representing the public key. 176 | """ 177 | k = ossl.new_key(self.curve_name, private_key) 178 | pub_x, pub_y, is_inf = ossl.get_public_key_ints(k) 179 | ossl.lc.EC_KEY_free(k) 180 | return ECPointAffine(self, pub_x, pub_y, is_inf) 181 | 182 | def recover_public_key(self, message, signature, recovery_id=None): 183 | """ Recovers possibilities for the public key associated with the 184 | private key used to sign message and generate signature. 185 | Since there are multiple possibilities (two for curves with 186 | co-factor = 1), each possibility that successfully verifies the 187 | signature is returned. 188 | Args: 189 | message (bytes): The message that was signed. 190 | signature (ECPointAffine): The point representing the signature. 191 | recovery_id (int) (Optional): If provided, limits the valid x and y 192 | point to only that described by the recovery_id. 193 | Returns: 194 | list(ECPointAffine): List of points representing valid public 195 | keys that verify signature. 196 | """ 197 | r = signature.x 198 | s = signature.y 199 | 200 | ctx = c_void_p(ossl.lc.BN_CTX_new()) 201 | ossl.lc.BN_CTX_start(ctx) 202 | 203 | order_bn = c_void_p(ossl.lc.BN_CTX_get(ctx)) 204 | x_bn = c_void_p(ossl.lc.BN_CTX_get(ctx)) 205 | i_bn = c_void_p(ossl.lc.BN_CTX_get(ctx)) 206 | in_bn = c_void_p(ossl.lc.BN_CTX_get(ctx)) 207 | p_bn = c_void_p(ossl.lc.BN_CTX_get(ctx)) 208 | r_bn = c_void_p(ossl.lc.BN_CTX_get(ctx)) 209 | s_bn = c_void_p(ossl.lc.BN_CTX_get(ctx)) 210 | rinv_bn = c_void_p(ossl.lc.BN_CTX_get(ctx)) 211 | z_bn = c_void_p(ossl.lc.BN_CTX_get(ctx)) 212 | ossl.lc.EC_GROUP_get_order(self.os_group, order_bn, ctx) 213 | 214 | ossl.int_to_bn(self.p, p_bn) 215 | ossl.int_to_bn(r, r_bn) 216 | ossl.int_to_bn(s, s_bn) 217 | ossl.lc.BN_mod_inverse(rinv_bn, r_bn, order_bn, ctx) 218 | 219 | if recovery_id is not None: 220 | i_list = [recovery_id >> 1] 221 | k_list = [recovery_id & 0x1] 222 | else: 223 | i_list = range(2) 224 | k_list = range(2) 225 | 226 | rv = [] 227 | num_bytes = math.ceil(self.nlen / 8) 228 | 229 | z = int.from_bytes(self.hash_function(message).digest()[:num_bytes], 'big') 230 | ossl.int_to_bn(z, z_bn) 231 | 232 | zG = c_void_p(ossl.lc.EC_POINT_new(self.os_group)) 233 | sR = c_void_p(ossl.lc.EC_POINT_new(self.os_group)) 234 | temp = c_void_p(ossl.lc.EC_POINT_new(self.os_group)) 235 | pub_key = c_void_p(ossl.lc.EC_POINT_new(self.os_group)) 236 | Rn = c_void_p(ossl.lc.EC_POINT_new(self.os_group)) 237 | 238 | for i in i_list: 239 | ossl.int_to_bn(i, i_bn) 240 | ossl.lc.BN_mod_mul(in_bn, i_bn, order_bn, p_bn, ctx) 241 | ossl.lc.BN_mod_add(x_bn, r_bn, in_bn, p_bn, ctx) 242 | x = ossl.bn_to_int(x_bn) 243 | ys = self.y_from_x(x) 244 | 245 | for k in k_list: 246 | y = ys[k] 247 | if y & 0x1 != k: 248 | y = ys[k ^ 1] 249 | 250 | R = ossl.point_new_from_ints(self.os_group, r, y) 251 | ossl.lc.EC_POINT_mul(self.os_group, 252 | Rn, 253 | None, 254 | R, 255 | order_bn, 256 | ctx) 257 | if not ossl.lc.EC_POINT_is_at_infinity(self.os_group, Rn): 258 | continue 259 | 260 | ossl.lc.EC_POINT_mul(self.os_group, 261 | zG, 262 | z_bn, 263 | None, 264 | None, 265 | ctx) 266 | ossl.lc.EC_POINT_invert(self.os_group, zG, ctx) 267 | ossl.lc.EC_POINT_mul(self.os_group, 268 | sR, 269 | None, 270 | R, 271 | s_bn, 272 | ctx) 273 | ossl.lc.EC_POINT_add(self.os_group, temp, sR, zG, ctx) 274 | ossl.lc.EC_POINT_mul(self.os_group, 275 | pub_key, 276 | None, 277 | temp, 278 | rinv_bn, 279 | ctx) 280 | 281 | ossl.lc.EC_POINT_free(R) 282 | 283 | # Convert to ECPointAffine 284 | pub_x, pub_y, inf = ossl.point_get_xy_ints(self.os_group, pub_key) 285 | rv.append((ECPointAffine(self, pub_x, pub_y, inf), 2 * i + k)) 286 | 287 | ossl.lc.EC_POINT_free(zG) 288 | ossl.lc.EC_POINT_free(sR) 289 | ossl.lc.EC_POINT_free(temp) 290 | ossl.lc.EC_POINT_free(pub_key) 291 | ossl.lc.EC_POINT_free(Rn) 292 | 293 | ossl.lc.BN_CTX_end(ctx) 294 | ossl.lc.BN_CTX_free(ctx) 295 | 296 | return rv 297 | 298 | def _sign(self, message, private_key, do_hash=True, secret=None): 299 | # This function computes k, kinv and rp before sending into 300 | # OpenSSL ECDSA_do_sign_ex() rather than using ECDSA_do_sign() 301 | # directly. The reason for this is that as of the commit that 302 | # introduces this comment, OpenSSL only supports deterministic 303 | # signing nonces (RFC6979) in the master branch and not any 304 | # release. As a result, we cannot depend on callers having any 305 | # OpenSSL version capable of RFC6979 deterministic nonces. 306 | # Nevertheless, computation of kinv (from k) and rp is done 307 | # using OpenSSL primitives. 308 | ossl.lc.ERR_clear_error() 309 | 310 | hashed = self.hash_function(message).digest() if do_hash else message 311 | 312 | r = 0 313 | s = 0 314 | recovery_id = 0 315 | 316 | key = ossl.new_key(self.curve_name, private_key) 317 | 318 | ctx = c_void_p(ossl.lc.BN_CTX_new()) 319 | ossl.lc.BN_CTX_start(ctx) 320 | 321 | order_bn = c_void_p(ossl.lc.BN_CTX_get(ctx)) 322 | k_bn = c_void_p(ossl.lc.BN_CTX_get(ctx)) 323 | kinv_bn = c_void_p(ossl.lc.BN_CTX_get(ctx)) 324 | px_bn = c_void_p(ossl.lc.BN_CTX_get(ctx)) 325 | r_bn = c_void_p(ossl.lc.BN_CTX_get(ctx)) 326 | ossl.lc.EC_GROUP_get_order(self.os_group, order_bn, ctx) 327 | 328 | while r == 0 or s == 0: 329 | k = self._nonce_rfc6979(private_key, hashed) if secret is None else secret 330 | ossl.int_to_bn(k, k_bn) 331 | 332 | ossl.lc.BN_mod_inverse(kinv_bn, k_bn, order_bn, ctx) 333 | 334 | p = c_void_p(ossl.lc.EC_POINT_new(self.os_group)) 335 | ossl.lc.EC_POINT_mul(self.os_group, 336 | p, 337 | k_bn, 338 | c_void_p(), 339 | c_void_p(), 340 | ctx) 341 | assert self.h == 1 342 | 343 | px, py, _ = ossl.point_get_xy_ints(self.os_group, p) 344 | recovery_id = 2 if px > self.n else 0 345 | recovery_id |= (py & 0x1) 346 | 347 | # Get r 348 | ossl.int_to_bn(px, px_bn) 349 | ossl.lc.BN_nnmod(r_bn, px_bn, order_bn, ctx) 350 | r = ossl.bn_to_int(r_bn) 351 | 352 | if r == 0: 353 | continue 354 | 355 | hashed_buf = c_char_p(hashed) 356 | sig = ossl.lc.ECDSA_do_sign_ex(hashed_buf, 357 | len(hashed), 358 | kinv_bn, 359 | r_bn, 360 | key) 361 | err = ossl.lc.ERR_peek_error() 362 | if err: 363 | err_buf = create_string_buffer(120) 364 | ossl.lc.ERR_error_string(err, err_buf) 365 | raise Exception("Problem when signing: %s" % 366 | err_buf.raw.decode()) 367 | 368 | sig_r = ossl.bn_to_int(sig.contents.r) 369 | sig_s = ossl.bn_to_int(sig.contents.s) 370 | 371 | if sig_r != r: 372 | raise ValueError("Didn't get the same r value.") 373 | s = sig_s 374 | 375 | ossl.lc.EC_KEY_free(key) 376 | ossl.lc.BN_CTX_end(ctx) 377 | ossl.lc.BN_CTX_free(ctx) 378 | 379 | return (Point(r, s), recovery_id) 380 | 381 | def verify(self, message, signature, public_key, do_hash=True): 382 | """ Verifies that signature was generated with a private key corresponding 383 | to public key, operating on message. 384 | Args: 385 | message (bytes): The message to be signed 386 | signature (Point): (r, s) representing the signature 387 | public_key (ECPointAffine): ECPointAffine of the public key 388 | do_hash (bool): True if the message should be hashed prior 389 | to signing, False if not. This should always be left as 390 | True except in special situations which require doing 391 | the hash outside (e.g. handling Bitcoin bugs). 392 | Returns: 393 | bool: True if the signature is verified, False otherwise. 394 | """ 395 | r = signature.x 396 | s = signature.y 397 | 398 | sig = ossl.sig_new_from_ints(r, s) 399 | 400 | hashed = self.hash_function(message).digest() if do_hash else message 401 | 402 | key = c_void_p(ossl.lc.EC_KEY_new_by_curve_name(self.curve_name)) 403 | ossl.set_public_key_from_ints(key=key, 404 | x=public_key.x, 405 | y=public_key.y, 406 | infinity=public_key.infinity) 407 | 408 | dig_buf = create_string_buffer(hashed) 409 | verified = ossl.lc.ECDSA_do_verify(dig_buf, len(hashed), sig, key) 410 | 411 | ossl.lc.ECDSA_SIG_free(sig) 412 | ossl.lc.EC_KEY_free(key) 413 | 414 | return bool(verified) 415 | 416 | 417 | class p256(EllipticCurve): 418 | curve_name = ossl.lc.OBJ_sn2nid(c_char_p(b"prime256v1")) 419 | 420 | def __init__(self): 421 | super().__init__(hashlib.sha256) 422 | 423 | 424 | class secp256k1(EllipticCurve): 425 | curve_name = ossl.lc.OBJ_sn2nid(c_char_p(b"secp256k1")) 426 | 427 | def __init__(self): 428 | super().__init__(hashlib.sha256) -------------------------------------------------------------------------------- /openssl.py: -------------------------------------------------------------------------------- 1 | from ctypes import c_int 2 | from ctypes import c_char_p 3 | from ctypes import c_long 4 | from ctypes import c_void_p 5 | from ctypes import create_string_buffer 6 | from ctypes import CDLL 7 | from ctypes import POINTER 8 | from ctypes import Structure 9 | 10 | import math 11 | import platform 12 | 13 | 14 | class OpenSSLSignature(Structure): 15 | _fields_ = [("r", c_void_p), 16 | ("s", c_void_p)] 17 | 18 | sys_type = platform.system() 19 | if sys_type == "Darwin": 20 | libcrypto = CDLL('libcrypto.dylib') 21 | elif sys_type == "Linux": 22 | libcrypto = CDLL('libcrypto.so') 23 | else: 24 | raise Exception("Unsupported platform %s" % sys_type) 25 | 26 | lc = libcrypto 27 | 28 | lc.OBJ_sn2nid.argtypes = [c_char_p] 29 | lc.OBJ_sn2nid.restype = c_int 30 | 31 | lc.EC_KEY_new_by_curve_name.restype = c_void_p 32 | lc.EC_KEY_generate_key.argtypes = [c_void_p] 33 | lc.EC_KEY_generate_key.restype = c_int 34 | lc.EC_KEY_check_key.argtypes = [c_void_p] 35 | lc.EC_KEY_check_key.restype = c_int 36 | lc.EC_KEY_get0_private_key.argtypes = [c_void_p] 37 | lc.EC_KEY_get0_private_key.restype = c_void_p 38 | lc.EC_KEY_get0_public_key.argtypes = [c_void_p] 39 | lc.EC_KEY_get0_public_key.restype = c_void_p 40 | lc.EC_KEY_set_private_key.argtypes = [c_void_p, c_void_p] 41 | lc.EC_KEY_set_private_key.restype = c_int 42 | lc.EC_KEY_set_public_key.argtypes = [c_void_p, c_void_p] 43 | lc.EC_KEY_set_public_key.restype = c_int 44 | lc.EC_KEY_get0_group.argtypes = [c_void_p] 45 | lc.EC_KEY_get0_group.restype = c_void_p 46 | lc.EC_KEY_free.argtypes = [c_void_p] 47 | 48 | lc.EC_GROUP_new_by_curve_name.restype = c_void_p 49 | lc.EC_GROUP_get_order.argtypes = [c_void_p] * 3 50 | lc.EC_GROUP_get_order.restype = c_int 51 | lc.EC_GROUP_get_curve_GFp.argtypes = [c_void_p] * 5 52 | lc.EC_GROUP_get_curve_GFp.restype = c_int 53 | lc.EC_GROUP_free.argtypes = [c_void_p] 54 | 55 | lc.EC_POINT_new.argtypes = [c_void_p] 56 | lc.EC_POINT_new.restype = c_void_p 57 | lc.EC_POINT_point2oct.argtypes = [c_void_p] 58 | lc.EC_POINT_point2oct.restype = c_int 59 | lc.EC_POINT_mul.argtypes = [c_void_p] * 6 60 | lc.EC_POINT_mul.restype = c_int 61 | lc.EC_POINT_invert.argtypes = [c_void_p] * 3 62 | lc.EC_POINT_invert.restype = c_int 63 | lc.EC_POINT_get_affine_coordinates_GFp.argtypes = [c_void_p] * 5 64 | lc.EC_POINT_set_affine_coordinates_GFp.argtypes = [c_void_p] * 5 65 | lc.EC_POINT_set_affine_coordinates_GFp.restype = c_int 66 | lc.EC_POINT_set_compressed_coordinates_GFp.argtypes = [ 67 | c_void_p, c_void_p, c_void_p, c_int, c_void_p] 68 | lc.EC_POINT_set_compressed_coordinates_GFp.restype = c_int 69 | lc.EC_POINT_is_at_infinity.argtypes = [c_void_p, c_void_p] 70 | lc.EC_POINT_is_at_infinity.restype = c_int 71 | lc.EC_POINT_set_to_infinity.argtypes = [c_void_p, c_void_p] 72 | lc.EC_POINT_set_to_infinity.restype = c_int 73 | lc.EC_POINT_is_on_curve.argtypes = [c_void_p] * 3 74 | lc.EC_POINT_is_on_curve.restype = c_int 75 | 76 | lc.d2i_ECDSA_SIG.argtypes = [c_void_p, c_void_p, c_long] 77 | lc.d2i_ECDSA_SIG.restype = POINTER(OpenSSLSignature) 78 | lc.ECDSA_SIG_new.argtypes = [] 79 | lc.ECDSA_SIG_new.restype = POINTER(OpenSSLSignature) 80 | lc.ECDSA_SIG_free.argtypes = [POINTER(OpenSSLSignature)] 81 | lc.ECDSA_do_sign_ex.argtypes = [ 82 | c_char_p, c_int, c_void_p, c_void_p, c_void_p] 83 | lc.ECDSA_do_sign_ex.restype = POINTER(OpenSSLSignature) 84 | lc.ECDSA_do_verify.argtypes = [ 85 | c_void_p, c_int, POINTER(OpenSSLSignature), c_void_p] 86 | lc.ECDSA_do_verify.restype = c_int 87 | 88 | lc.BN_new.restype = c_void_p 89 | lc.BN_num_bits.argtypes = [c_void_p] 90 | lc.BN_num_bits.restype = c_int 91 | lc.BN_bn2bin.argtypes = [c_void_p, c_char_p] 92 | lc.BN_bn2bin.restype = c_int 93 | lc.BN_bin2bn.argtypes = [c_char_p, c_int, c_void_p] 94 | lc.BN_bin2bn.restype = c_void_p 95 | lc.BN_mod_mul.argtypes = [c_void_p] * 5 96 | lc.BN_mod_mul.restype = c_int 97 | lc.BN_mod_add.argtypes = [c_void_p] * 5 98 | lc.BN_mod_add.restype = c_int 99 | lc.BN_mod_inverse.argtypes = [c_void_p] * 4 100 | lc.BN_mod_inverse.restype = c_void_p 101 | lc.BN_free.argtypes = [c_void_p] 102 | lc.BN_CTX_new.restype = c_void_p 103 | lc.BN_CTX_start.argtypes = [c_void_p] 104 | lc.BN_CTX_get.argtypes = [c_void_p] 105 | lc.BN_CTX_get.restype = c_void_p 106 | lc.BN_CTX_end.argtypes = [c_void_p] 107 | lc.BN_CTX_free.argtypes = [c_void_p] 108 | 109 | # lc.ERR_load_crypto_strings() 110 | 111 | 112 | def get_curve_params(group): 113 | """ Retrieves all elliptic curve parameters 114 | Args: 115 | group (c_void_p): The OpenSSL group (curve) to 116 | retrieve the parameters for. 117 | Returns: 118 | dict: With the following key/value pairs: 119 | p: Prime defining the field 120 | a: Linear coefficient of the curve 121 | b: Curve constant 122 | n: Curve order 123 | h: Curve co-factor 124 | """ 125 | ctx = c_void_p(lc.BN_CTX_new()) 126 | lc.BN_CTX_start(ctx) 127 | 128 | order_bn = c_void_p(lc.BN_CTX_get(ctx)) 129 | cofactor_bn = c_void_p(lc.BN_CTX_get(ctx)) 130 | p_bn = c_void_p(lc.BN_CTX_get(ctx)) 131 | a_bn = c_void_p(lc.BN_CTX_get(ctx)) 132 | b_bn = c_void_p(lc.BN_CTX_get(ctx)) 133 | lc.EC_GROUP_get_order(group, order_bn, c_void_p()) 134 | lc.EC_GROUP_get_cofactor(group, cofactor_bn, c_void_p()) 135 | lc.EC_GROUP_get_curve_GFp(group, p_bn, a_bn, b_bn, ctx) 136 | 137 | rv = {} 138 | rv['p'] = bn_to_int(p_bn) 139 | rv['a'] = bn_to_int(a_bn) 140 | rv['b'] = bn_to_int(b_bn) 141 | rv['n'] = bn_to_int(order_bn) 142 | rv['h'] = bn_to_int(cofactor_bn) 143 | 144 | lc.BN_CTX_end(ctx) 145 | lc.BN_CTX_free(ctx) 146 | 147 | return rv 148 | 149 | 150 | def new_key(curve_name, private_key=None): 151 | """ Generates a new EC_KEY 152 | Args: 153 | curve_name (int): The OpenSSL identifier of the curve which 154 | the key will be part of. 155 | private_key (int): If not provided, a random key pair will be 156 | generated. Otherwise, the key will be initiated with the 157 | provided private key (and corresponding public key) 158 | Returns: 159 | c_void_p: An opaque pointer to the new EC_KEY object. The 160 | caller is responsible for freeing the key object. 161 | """ 162 | k = c_void_p(lc.EC_KEY_new_by_curve_name(curve_name)) 163 | 164 | if private_key is None: 165 | lc.EC_KEY_generate_key(k) 166 | else: 167 | key_ok = set_private_key_from_int(k, private_key) 168 | if not key_ok: 169 | raise ValueError("Key is not ok") 170 | 171 | return k 172 | 173 | 174 | def get_private_key_bytes(key): 175 | """ Retrieves the bytes corresponding to the private key. 176 | Args: 177 | key (c_void_p): A pointer to an EC_KEY object. 178 | Returns: 179 | bytes: A byte stream containing the private key. 180 | """ 181 | priv_key_bn = c_void_p(lc.EC_KEY_get0_private_key(key)) 182 | priv_key_bytes = bn_to_bytes(priv_key_bn) 183 | 184 | return priv_key_bytes 185 | 186 | 187 | def get_private_key_int(key): 188 | """ Retrieves the integer corresponding to the private key. 189 | Args: 190 | key (c_void_p): A pointer to an EC_KEY object. 191 | Returns: 192 | int: The integer representation of the private key. 193 | """ 194 | rv = None 195 | b = get_private_key_bytes(key) 196 | if b is not None: 197 | rv = int.from_bytes(b, byteorder='big') 198 | 199 | return rv 200 | 201 | 202 | def set_private_key_from_bytes(key, b): 203 | """ Sets the private portion of key from b. 204 | This function also sets the public key portion of 205 | key after computing the public key from the provided 206 | bytes of the private key. 207 | Args: 208 | key (c_void_p): A pointer to an EC_KEY object. 209 | b (bytes): The bytes representing the private key. 210 | Returns: 211 | bool: Whether key passes OpenSSL's sanity checks after 212 | both private & public keys are set. 213 | """ 214 | priv_bn = bytes_to_bn(b) 215 | 216 | group = c_void_p(lc.EC_KEY_get0_group(key)) 217 | 218 | lc.EC_KEY_set_private_key(key, priv_bn) 219 | 220 | # Now jam the public key 221 | pub_pt = c_void_p(lc.EC_POINT_new(group)) 222 | lc.EC_POINT_mul(group, 223 | pub_pt, 224 | priv_bn, 225 | c_void_p(), 226 | c_void_p(), 227 | c_void_p()) 228 | lc.EC_KEY_set_public_key(key, pub_pt) 229 | 230 | lc.EC_POINT_free(pub_pt) 231 | 232 | return lc.EC_KEY_check_key(key) 233 | 234 | 235 | def set_private_key_from_int(key, i, size=32): 236 | """ Sets the private portion of key from i. 237 | This function also sets the public key portion of 238 | key after computing the public key from the provided 239 | private key. 240 | Args: 241 | key (c_void_p): A pointer to an EC_KEY object. 242 | i (int): The integer representing the private key. 243 | size (int): Size in bytes the key should be. 244 | Returns: 245 | bool: Whether key passes OpenSSL's sanity checks after 246 | both private & public keys are set. 247 | """ 248 | b = i.to_bytes(size, byteorder='big') 249 | return set_private_key_from_bytes(key, b) 250 | 251 | 252 | def bn_to_bytes(bn): 253 | """ Translates an OpenSSL big number (BN) to bytes. 254 | Args: 255 | bn (c_void_p): A pointer to an OpenSSL BN object. 256 | Returns: 257 | bytes: The bytes corresponding to the BN object. It is 258 | returned as a big-endian positive number. 259 | """ 260 | size = math.ceil(lc.BN_num_bits(bn) / 8.0) 261 | b = create_string_buffer(b'\x00' * size) 262 | lc.BN_bn2bin(bn, b) 263 | 264 | return b[:size] 265 | 266 | 267 | def bytes_to_bn(b, bn=None): 268 | """ Translates bytes to an OpenSSL big number (BN). 269 | Args: 270 | b (bytes): Big-endian, positive number to translate. 271 | bn (c_void_p): If not None, sets it to the number represented 272 | by b. 273 | Returns: 274 | c_void_p: If bn is None, a pointer to a new OpenSSL BN object, 275 | otherwise bn. In all cases, the caller is responsible for 276 | freeing the memory associated with the OpenSSL object. 277 | """ 278 | buf = create_string_buffer(b) 279 | return c_void_p(lc.BN_bin2bn(buf, len(b), bn)) 280 | 281 | 282 | def bn_to_int(bn): 283 | """ Translates an OpenSSL big number (BN) to a Python integer. 284 | Args: 285 | bn (c_void_p): A pointer to an OpenSSL BN object. 286 | Returns: 287 | int: The python integer corresponding to the BN object. 288 | """ 289 | return int.from_bytes(bn_to_bytes(bn), byteorder='big') 290 | 291 | 292 | def int_to_bn(i, bn=None, size=32): 293 | """ Translates a python integer to an OpenSSL big number (BN). 294 | Args: 295 | i (int): Integer to translate. 296 | bn (c_void_p): If not None, sets it to the number represented 297 | by i. 298 | size (int): The maximal byte-length of i. 299 | Returns: 300 | c_void_p: If bn is None, a pointer to a new OpenSSL BN object, 301 | otherwise bn. In all cases, the caller is responsible for 302 | freeing the memory associated with the OpenSSL object. 303 | """ 304 | return bytes_to_bn(i.to_bytes(size, byteorder='big'), bn) 305 | 306 | 307 | def point_get_xy_bytes(group, pt): 308 | """ Gets bytes for x and y components of an EC_POINT. 309 | This uses `bn_to_bytes` to create the bytes objects after 310 | extracting the x and y components of pt. 311 | Args: 312 | group (c_void_p): An opaque pointer to the group (curve) that 313 | pt is part of. 314 | pt (c_void_p): An opaque pointer to the OpenSSL EC_POINT object. 315 | Returns: 316 | tuple: Containing the x bytes, y bytes and a boolean representing 317 | whether the point is at infinity or not. 318 | """ 319 | x_bn = c_void_p(lc.BN_new()) 320 | y_bn = c_void_p(lc.BN_new()) 321 | lc.EC_POINT_make_affine(group, pt, c_void_p(None)) 322 | lc.EC_POINT_get_affine_coordinates_GFp(group, 323 | pt, 324 | x_bn, 325 | y_bn, 326 | c_void_p(None)) 327 | inf = bool(lc.EC_POINT_is_at_infinity(group, pt)) 328 | 329 | x_bytes = bn_to_bytes(x_bn) 330 | y_bytes = bn_to_bytes(y_bn) 331 | 332 | lc.BN_free(x_bn) 333 | lc.BN_free(y_bn) 334 | 335 | return (x_bytes, y_bytes, inf) 336 | 337 | 338 | def point_get_xy_ints(group, pt): 339 | """ Gets the x and y components of an EC_POINT. 340 | Args: 341 | group (c_void_p): An opaque pointer to the group (curve) that 342 | pt is part of. 343 | pt (c_void_p): An opaque pointer to the OpenSSL EC_POINT object. 344 | Returns: 345 | tuple: Containing x, y and a boolean representing whether the 346 | point is at infinity or not. 347 | """ 348 | x_b, y_b, inf = point_get_xy_bytes(group, pt) 349 | x = int.from_bytes(x_b, byteorder='big') 350 | y = int.from_bytes(y_b, byteorder='big') 351 | 352 | return (x, y, inf) 353 | 354 | 355 | def point_new_from_bytes(group, x_bytes, y_bytes, infinity=False): 356 | """ Creates a new OpenSSL EC_POINT from bytes. 357 | Args: 358 | group (c_void_p): An opaque pointer to the group (curve) that 359 | the point should be part of. 360 | x_bytes (bytes): Big-endian, positive byte representation of x. 361 | y_bytes (bytes): Big-endian, positive byte representation of y. 362 | infinity (bool): True if the point is at infinity, False otherwise. 363 | Returns: 364 | c_void_p: An opaque pointer to the newly constructed OpenSSL 365 | EC_POINT object. The caller bears responsibility for freeing 366 | the memory associated with the returned object. 367 | """ 368 | pt = c_void_p(lc.EC_POINT_new(group)) 369 | 370 | x_bn = bytes_to_bn(x_bytes) 371 | y_bn = bytes_to_bn(y_bytes) 372 | 373 | res = lc.EC_POINT_set_affine_coordinates_GFp(group, 374 | pt, 375 | x_bn, 376 | y_bn, 377 | c_void_p(None)) 378 | if not res: 379 | lc.EC_POINT_free(pt) 380 | return None 381 | 382 | if infinity: 383 | lc.EC_POINT_set_to_infinity(group, pt) 384 | 385 | return pt 386 | 387 | 388 | def point_new_from_ints(group, x, y, infinity=False, size=32): 389 | """ Creates a new OpenSSL EC_POINT from x & y integers. 390 | Args: 391 | group (c_void_p): An opaque pointer to the group (curve) that 392 | the point should be part of. 393 | x_bytes (bytes): Big-endian, positive byte representation of x. 394 | y_bytes (bytes): Big-endian, positive byte representation of y. 395 | infinity (bool): True if the point is at infinity, False otherwise. 396 | size (int): Maximal byte-length of x and y. 397 | Returns: 398 | c_void_p: An opaque pointer to the newly constructed OpenSSL 399 | EC_POINT object. The caller bears responsibility for freeing 400 | the memory associated with the returned object. 401 | """ 402 | x_bytes = x.to_bytes(size, byteorder='big') 403 | y_bytes = y.to_bytes(size, byteorder='big') 404 | 405 | return point_new_from_bytes(group, x_bytes, y_bytes, infinity) 406 | 407 | 408 | def get_public_key_bytes(key): 409 | """ Returns the bytes corresponding to the public key coordinates. 410 | Args: 411 | key (c_void_p): An opaque pointer to an OpenSSL EC_KEY object. 412 | Returns: 413 | tuple: Containing bytes for x & y public key components and a 414 | boolean indicating whether the point is at infinity or not. 415 | """ 416 | group = c_void_p(lc.EC_KEY_get0_group(key)) 417 | pub_key_point = c_void_p(lc.EC_KEY_get0_public_key(key)) 418 | x_b, y_b, inf = point_get_xy_bytes(group, pub_key_point) 419 | 420 | return (x_b, y_b, inf) 421 | 422 | 423 | def get_public_key_ints(key): 424 | """ Returns the integers corresponding to the public key coordinates. 425 | Args: 426 | key (c_void_p): An opaque pointer to an OpenSSL EC_KEY object. 427 | Returns: 428 | tuple: Containing the x & y public key components and a 429 | boolean indicating whether the point is at infinity or not. 430 | """ 431 | xb, yb, inf = get_public_key_bytes(key) 432 | x = int.from_bytes(xb, byteorder='big') 433 | y = int.from_bytes(yb, byteorder='big') 434 | 435 | return (x, y, inf) 436 | 437 | 438 | def set_public_key_from_bytes(key, x_bytes, y_bytes, infinity): 439 | """ Sets the public key portion of an OpenSSL EC_KEY object from 440 | bytes representations of the x & y components of the public key. 441 | Args: 442 | key (c_void_p): An opaque pointer to an OpenSSL EC_KEY object. 443 | x_bytes (bytes): Big-endian, positive byte-representation of the 444 | x component of the public-key point. 445 | y_bytes (bytes): Big-endian, positive byte-representation of the 446 | y component of the public-key point. 447 | infinity (bool): True if the point is at infinity, False otherwise. 448 | Returns: 449 | bool: True if the public key was set properly, False otherwise. 450 | """ 451 | group = c_void_p(lc.EC_KEY_get0_group(key)) 452 | pub_pt = point_new_from_bytes(group, x_bytes, y_bytes, infinity) 453 | res = lc.EC_KEY_set_public_key(key, pub_pt) 454 | 455 | return bool(res) 456 | 457 | 458 | def set_public_key_from_ints(key, x, y, infinity, size=32): 459 | """ Sets the public key portion of an OpenSSL EC_KEY object from 460 | bytes representations of the x & y components of the public key. 461 | Args: 462 | key (c_void_p): An opaque pointer to an OpenSSL EC_KEY object. 463 | x (int): X component of the public-key point. 464 | y (int): Y component of the public-key point. 465 | infinity (bool): True if the point is at infinity, False otherwise. 466 | size (int): Maximal byte-size of x and y. 467 | Returns: 468 | bool: True if the public key was set properly, False otherwise. 469 | """ 470 | x_bytes = x.to_bytes(size, byteorder='big') 471 | y_bytes = y.to_bytes(size, byteorder='big') 472 | return set_public_key_from_bytes(key, 473 | x_bytes, 474 | y_bytes, 475 | infinity) 476 | 477 | 478 | def sig_new_from_bytes(r_bytes, s_bytes): 479 | """ Creates a new OpenSSL ECDSA_SIG structure from r & s bytes. 480 | Args: 481 | r_bytes (bytes): Big-endian, positive byte-representation of the 482 | r component of the signature. 483 | s_bytes (bytes): Big-endian, positive byte-representation of the 484 | s component of the signature. 485 | Returns: 486 | c_void_p: An opaque pointer to a new OpenSSL ECDSA_SIG structure 487 | represented by the `OpenSSLSignature` class. 488 | """ 489 | sig = lc.ECDSA_SIG_new() 490 | 491 | r_buf = create_string_buffer(r_bytes) 492 | s_buf = create_string_buffer(s_bytes) 493 | lc.BN_bin2bn(r_buf, len(r_bytes), sig.contents.r) 494 | lc.BN_bin2bn(s_buf, len(s_bytes), sig.contents.s) 495 | 496 | return sig 497 | 498 | 499 | def sig_new_from_ints(r, s, size=32): 500 | """ Creates a new OpenSSL ECDSA_SIG structure from r & s integers. 501 | Args: 502 | r (int): R component of the signature. 503 | s (int): S component of the signature. 504 | size (int): Maximal byte-size of r & s. 505 | Returns: 506 | c_void_p: An opaque pointer to a new OpenSSL ECDSA_SIG structure 507 | represented by the `OpenSSLSignature` class. 508 | """ 509 | return sig_new_from_bytes(r_bytes=r.to_bytes(size, byteorder='big'), 510 | s_bytes=s.to_bytes(size, byteorder='big')) -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | rlp 2 | eth_utils 3 | pycrypto 4 | pycryptodome 5 | base58 6 | mnemonic 7 | -------------------------------------------------------------------------------- /utils.py: -------------------------------------------------------------------------------- 1 | """This submodule provides functions for accomplishing common tasks encountered 2 | in creating and parsing Bitcoin objects, like turning difficulties into targets 3 | or deserializing and serializing various kinds of packed byte formats.""" 4 | import base58 5 | import codecs 6 | import hashlib 7 | import random 8 | import struct 9 | import os 10 | 11 | MAX_TARGET = 0x00000000FFFF0000000000000000000000000000000000000000000000000000 12 | 13 | 14 | def rand_bytes(n, secure=True): 15 | """ Returns n random bytes. 16 | Args: 17 | n (int): number of bytes to return. 18 | secure (bool): If True, uses os.urandom to generate 19 | cryptographically secure random bytes. Otherwise, uses 20 | random.randint() which generates pseudo-random numbers. 21 | Returns: 22 | b (bytes): n random bytes. 23 | """ 24 | if secure: 25 | return os.urandom(n) 26 | else: 27 | return bytes([random.randint(0, 255) for i in range(n)]) 28 | 29 | 30 | def bytes_to_str(b): 31 | """ Converts bytes into a hex-encoded string. 32 | Args: 33 | b (bytes): bytes to encode 34 | Returns: 35 | h (str): hex-encoded string corresponding to b. 36 | """ 37 | return codecs.encode(b, 'hex_codec').decode('ascii') 38 | 39 | 40 | def hex_str_to_bytes(h): 41 | """ Converts a hex-encoded string to bytes. 42 | Args: 43 | h (str): hex-encoded string to convert. 44 | Returns: 45 | b (bytes): bytes corresponding to h. 46 | """ 47 | return bytes.fromhex(h) 48 | 49 | 50 | # Is there a better way of doing this? 51 | def render_int(n): 52 | """ Renders an int in the shortest possible form. 53 | When packing the height into the coinbase script, the integer 54 | representing the height must be encoded in the shortest possible 55 | manner. See: https://bitcoin.org/en/developer-reference#coinbase. 56 | Args: 57 | n (int): number to be encoded. 58 | Returns: 59 | b (bytes): bytes representing n in the shortest possible form. 60 | """ 61 | # little-endian byte stream 62 | if n < 0: 63 | neg = True 64 | n = -n 65 | else: 66 | neg = False 67 | r = [] 68 | while n: 69 | r.append(n & 0xff) 70 | n >>= 8 71 | if neg: 72 | if r[-1] & 0x80: 73 | r.append(0x80) 74 | else: 75 | r[-1] |= 0x80 76 | elif r and (r[-1] & 0x80): 77 | r.append(0) 78 | return bytes(r) 79 | 80 | 81 | def pack_compact_int(i): 82 | """ See 83 | https://bitcoin.org/en/developer-reference#compactsize-unsigned-integers 84 | Args: 85 | i (int): Integer to be serialized. 86 | Returns: 87 | b (bytes): Serialized bytes corresponding to i. 88 | """ 89 | if i < 0xfd: 90 | return struct.pack('> 24 198 | target = (bits & 0xffffff) * (1 << (8 * (shift - 3))) 199 | return target 200 | 201 | 202 | def bits_to_difficulty(bits): 203 | """ Determines the difficulty corresponding to bits. 204 | See: https://en.bitcoin.it/wiki/Difficulty 205 | Args: 206 | bits (int): Compact target (32 bits) 207 | Returns: 208 | diff (float): Measure of how hard it is to find a solution 209 | below the target represented by bits. 210 | """ 211 | target = bits_to_target(bits) 212 | return MAX_TARGET / target 213 | 214 | 215 | def difficulty_to_target(difficulty): 216 | """ Converts a difficulty to a long-form target. 217 | Args: 218 | difficulty (float): The difficulty to return the appropriate target for 219 | Returns: 220 | target (int): The corresponding target 221 | """ 222 | return int(MAX_TARGET / difficulty) 223 | 224 | 225 | def target_to_bits(target): 226 | """ Creates a compact target representation for a given target. 227 | Args: 228 | target (Bignum): The long-form target to make compact. 229 | Returns: 230 | ct (int): Compact target 231 | """ 232 | # Get bit length 233 | nbits = target.bit_length() 234 | # Round up to next 8-bits 235 | nbits = ((nbits + 7) & ~0x7) 236 | exponent = (int(nbits/8) & 0xff) 237 | coefficient = (target >> (nbits - 24)) & 0xffffff 238 | if coefficient & 0x800000: 239 | coefficient >>= 8 240 | exponent += 1 241 | return (exponent << 24) | coefficient 242 | 243 | 244 | def difficulty_to_bits(difficulty): 245 | """ Converts a difficulty to a compact target. 246 | Args: 247 | difficulty (float): The difficulty to create a target for 248 | Returns: 249 | ct (int): Compact target 250 | """ 251 | return target_to_bits(difficulty_to_target(difficulty)) 252 | 253 | 254 | def address_to_key_hash(s): 255 | """ Given a Bitcoin address decodes the version and 256 | RIPEMD-160 hash of the public key. 257 | Args: 258 | s (bytes): The Bitcoin address to decode 259 | Returns: 260 | (version, h160) (tuple): A tuple containing the version and 261 | RIPEMD-160 hash of the public key. 262 | """ 263 | n = base58.b58decode_check(s) 264 | version = n[0] 265 | h160 = n[1:] 266 | return version, h160 267 | 268 | 269 | def key_hash_to_address(hash160, version=0x0): 270 | """Convert RIPEMD-160 hash to bitcoin address. 271 | Args: 272 | hash160 (bytes/str): bitcoin hash160 to decode 273 | version (int): The version prefix 274 | Returns: 275 | (bitcoin address): base58 encoded bitcoin address 276 | """ 277 | if isinstance(hash160, str): 278 | # if 0x in string, strip it 279 | if "0x" in hash160: 280 | h160 = hex_str_to_bytes(hash160[2:]) 281 | else: 282 | h160 = hex_str_to_bytes(hash160) 283 | elif isinstance(hash160, bytes): 284 | h160 = hash160 285 | 286 | address = base58.b58encode_check(bytes([version]) + h160) 287 | return address 288 | 289 | 290 | def hash160(b): 291 | """ Computes the HASH160 of b. 292 | Args: 293 | b (bytes): A byte string to compute the HASH160 of. 294 | Returns: 295 | The RIPEMD-160 digest of the SHA256 hash of b. 296 | """ 297 | r = hashlib.new('ripemd160') 298 | r.update(hashlib.sha256(b).digest()) 299 | 300 | return r.digest() 301 | 302 | 303 | def compute_reward(height): 304 | """ Computes the block reward for a block at the supplied height. 305 | See: https://en.bitcoin.it/wiki/Controlled_supply for the reward 306 | schedule. 307 | Args: 308 | height (int): Block height 309 | Returns: 310 | reward (int): Number of satoshis rewarded for solving a block at the 311 | given height. 312 | """ 313 | base_subsidy = 50 * 100000000 314 | era = height // 210000 315 | if era == 0: 316 | return base_subsidy 317 | return int(base_subsidy / 2 ** era) --------------------------------------------------------------------------------