Giter VIP home page Giter VIP logo

cryptotools's Introduction

About this repo

Barebones Python 3.6+ implementation (no dependencies/standard lib only) of some common cryptographic functions for educational purposes. Feel free to fork the repo and play around with it. Performance is ..abysmal but otherwise it works fine. Please do not use this for anything serious because I am not a security expert.

Install

$ pip install git+https://github.com/mcdallas/cryptotools.git@master#egg=cryptotools

Examples

HD Wallets

from cryptotools.BTC import Xprv

>>> m = Xprv.from_mnemonic('impulse prize erode winner pupil fun off addict ...')
>>> m.encode()
'xprv9s21ZrQH143K38bNJiHY54kkjio8o6aw3bRjCbzi8KgRxNy98avUribz1wk85ToSUV2VwVuc73NJWc2YGwpMtqz7bBFUh9Q77RtJeuh2zvy'

>>> m/44/0/0/0
Xprv(path=m/44/0/0/0, key=L1WKXyMwKnp8wPwAtjwiKWunACY5RSUXAzmS6jDRRHcHnDbeRiKu)

>>> m/0./123/5.  # Use floats for hardened path, alternative is // e.g m//0/123//5
Xprv(path=m/0h/123/5h, key=L3qskbdzgNu4kwjx2QU63q59khpEHVaSbqd2Pc268Jngiha6mbfQ)

>>> M = m.to_xpub()

>>> (m/123/456).to_xpub() == M/123/456
True

>>> (m/44./0./0./0/0).address('P2PKH')  # bip44
'1BTYXdyrBh1yRCDpqyDhoQG896bnzqtaPz'

>>> (m/84./0./0./0/0).address('P2WPKH')  # bip84
'bc1qjnx8cq32z2t72tsmuwql3wz22lywlpcm3w52lk'

BIP39 checksum

Say you lost the first of your 12 mnemonic words and you want to filter out the possible mnemonics from 2048 to 128 by veryfing the checksum

from cryptotools.BTC.HD import check, WORDS

phrase = "{x} decrease enjoy credit fold prepare school midnight flower wrong false already"

for word in WORDS:
    mnemonic = phrase.format(x=word)
    if check(mnemonic):
        print(mnemonic)

Sign/Verify message:

import secrets
from cryptotools.ECDSA.secp256k1 import generate_keypair, Message

private, public = generate_keypair()

>>> message = Message(secrets.token_bytes(32))
>>> sig1 = message.sign(private)          # ECDSA
>>> sig2 = message.sign_schnorr(private)  # Schnorr
>>> message.verify(sig1, public)
True
>>> message.verify(sig2, public)
True

Verify a transaction:

from cryptotools.BTC import Transaction

tx = Transaction.get('454e575aa1ed4427985a9732d753b37dc711675eb7c977637b1eea7f600ed214')

>>> tx
Transaction(inputs=1, outputs=2)

>>> tx.outputs
[Output(type=P2SH, value=0.0266 BTC),
 Output(type=P2WSH, value=0.00468 BTC)]

>>> tx.verify()  # this runs the bitcoin script
True

Create a transaction and submit it automatically

import os
os.environ['CRYPTOTOOLS_NETWORK'] = 'test'  # sets network to testnet (before library import)

from cryptotools.BTC import PrivateKey, send

key = PrivateKey.from_hex('mysupersecretkey')

>>> send(source='n4SbPWR6EmQMsWaQVYYFXiJgjweGKE4XnQ', to={'n2NGrooSecJaiD6ssp4YqFoj9eZ7GrCJ66': 0.46}, fee=0.01, private=key)
'907b92969cb3a16ddb45591bf2530f177b7f10cef4e62c331596a84f66c3b8c3'  # txid

Create and broadcast manually

import os
os.environ['CRYPTOTOOLS_NETWORK'] = 'test'

from cryptotools.BTC import PrivateKey, Address

private = PrivateKey.from_hex('mysupersecretkey')
address = Address('n2NGrooSecJaiD6ssp4YqFoj9eZ7GrCJ66')

>>> address.balance()
0.55

>>> send_to = {'n4SbPWR6EmQMsWaQVYYFXiJgjweGKE4XnQ': 0.1, 'n2NGrooSecJaiD6ssp4YqFoj9eZ7GrCJ66': 0.4}
>>> tx = address.send(to=send_to, fee=0.05, private=private)

>>> tx
Transaction(inputs=1, outputs=2)

>>> tx.inputs[0].is_signed()
True

>>> tx.verify()  # Make sure transaction is valid before broadcasting
True

>>> tx.broadcast()
'Transaction Submitted'

Create keys/addresses (including segwit)

from cryptotools.BTC import generate_keypair, push, script_to_address, OP
private, public = generate_keypair()

>>> private.hex()
'de4f177274d29f88a5805333e10525f5dd41634455dfadc8849b977802481ccd'

>>> private.wif(compressed=False)
'5KWCAYLo35uZ9ibPTzTUDXESTE6ne8p1eXviYMHwaoS4tpvYCAp'

>>> public.hex()
'047e30fd478b44869850352daef8f5f7a7b5233044018d465431afdc0b436c973e8df1244189d25ae73d90c90cc0f998eb9784adecaecc46e8c536d7d6845fa26e'

>>> public.to_address('P2PKH')
'19dFXDxiD4KrUTNFfcgeekFpQmUC553GzW'

# Simple <key> <OP_CHECKSIG> script
>>> script = push(public.encode(compressed=True)) + OP.CHECKSIG.byte
>>> script_to_address(script, 'P2WSH')
'bc1q8yh8l8ft3220q328hlapqhflpzy6xvkq6u36mctk8gq5pyxm3rwqv5h5dg'

# nested P2WSH into P2SH -- use with caution
>>> script_to_address(script, 'P2WSH-P2SH')
'34eBzenHJEdk5PK9ojuuBZvCRtNhvvysYZ'
from cryptotools.ECDSA.secp256k1 import CURVE, PrivateKey
private = PrivateKey.random()

>>> private.int()
8034465994996476238286561766373949549982328752707977290709076444881813294372

>>> public = private.to_public()
>>> public
PublicKey(102868560361119050321154887315228169307787313299675114268359376451780341556078, 83001804479408277471207716276761041184203185393579361784723900699449806360826)

>>> public.point in CURVE
True

>>> public.to_address('P2WPKH')
'bc1qh2egksgfejqpktc3kkdtuqqrukrpzzp9lr0phn'

Configuration --------

By default the library communicates with the bitcoin network (for fetching transactions) via a block explorer but as an alternative you can use a bitcoin node via it's RPC interface. Just set the following enviromental variables

CRYPTOTOOLS_BACKEND=rpc
CRYPTOTOOLS_BACKEND=localhost
CRYPTOTOOLS_RPC_PORT=8332

and optionally

CRYPTOTOOLS_RPC_USER=myuser
CRYPTOTOOLS_RPC_PW=mypassword

to switch the network to Testnet set

CRYPTOTOOLS_NETWORK=test

to run tests

$ python -m unittest

from the project directory

cryptotools's People

Contributors

anynomouss avatar captain-kark avatar mcdallas avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cryptotools's Issues

cant install with the command

:2: DeprecationWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html
Traceback (most recent call last):
File "C:\Program Files\Python312\Lib\site-packages\pip_vendor\pyproject_hooks_in_process_in_process.py", line 353, in
main()
File "C:\Program Files\Python312\Lib\site-packages\pip_vendor\pyproject_hooks_in_process_in_process.py", line 335, in main
json_out['return_val'] = hook(**hook_input['kwargs'])
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Program Files\Python312\Lib\site-packages\pip_vendor\pyproject_hooks_in_process_in_process.py", line 118, in get_requires_for_build_wheel
return hook(config_settings)
^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Administrator\AppData\Local\Temp\pip-build-env-rtgbgqaf\overlay\Lib\site-packages\setuptools\build_meta.py", line 325, in get_requires_for_build_wheel
return self._get_build_requires(config_settings, requirements=['wheel'])
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Administrator\AppData\Local\Temp\pip-build-env-rtgbgqaf\overlay\Lib\site-packages\setuptools\build_meta.py", line 295, in get_build_requires
self.run_setup()
File "C:\Users\Administrator\AppData\Local\Temp\pip-build-env-rtgbgqaf\overlay\Lib\site-packages\setuptools\build_meta.py", line 487, in run_setup
super().run_setup(setup_script=setup_script)
File "C:\Users\Administrator\AppData\Local\Temp\pip-build-env-rtgbgqaf\overlay\Lib\site-packages\setuptools\build_meta.py", line 311, in run_setup
exec(code, locals())
File "", line 5, in
File "C:\Users\Administrator\AppData\Local\Temp\pip-install-ugh8gx_x\cryptotools_8eb9764d665d4481a0088c4f43513499\cryptotools_init
.py", line 16, in
_module = loader.find_module(module_name).load_module(module_name)
^^^^^^^^^^^^^^^^^^
AttributeError: 'FileFinder' object has no attribute 'find_module'
[end of output]

How to derive all possible segwit addresses from xpub

Hello,
I need derive all possible addresses from Ledger xPub.

I've tried this:

from cryptotools import Xpub

MY_XPUB = 'xpub-as-shown-in-ledger'

key = Xpub.decode(MY_XPUB)

pubkey0 = key/0/0
print(pubkey0.address('P2WPKH'))  # Tell the wallet that you want a P2WPKH address

but it gives only 1 address.
Any idea ?

Thanks.

P2WSH and P2WPKH_P2SH etc?

besides existing on the code, I cannot use P2WSH or P2WPKH_P2SH or etc, like:

print("P2WSH: m/44./0./0./0/"+str(x)+": " + (key/44./0./0./0/x).address('P2WSH'))

so I can generate addresses starting with 3.

Error:

Traceback (most recent call last):
  File "verify.py", line 31, in <module>
    print_addresses(xprv, count)
  File "verify.py", line 21, in print_addresses
    print("P2WSH: m/44./0./0./0/"+str(x)+": " + (key/44./0./0./0/x).address('P2WSH'))
  File "/home/lz/cryptotools/cryptotools/BTC/HD/bip32.py", line 191, in address
    return self.key.to_public().to_address(addresstype or self.type.value, compressed=True)
  File "/home/lz/cryptotools/cryptotools/ECDSA/secp256k1.py", line 143, in to_address
    return pubkey_to_address(self, addrtype)
  File "/home/lz/cryptotools/cryptotools/BTC/address.py", line 73, in pubkey_to_address
    converter = key_to_addr_versions[ADDRESS(version.upper())]
KeyError: <ADDRESS.P2WSH: 'P2WSH'>

ScriptValidationError: Unknown script type

in this code

def spend(wif,bitcoin_address,recipient_address):
    private = PrivateKey.from_wif(wif)
    address = Address(bitcoin_address)
    # balance is in bitcoin
    bal=address.balance()
    net_amount=bal-0.0002
    print(net_amount)
    send_to = {recipient_address: net_amount}
    estimate_fee = estimatefee(speed="average")
    tx = address.send(to=send_to, fee=0.0002, private=private)
    print(tx)
    result=tx.broadcast()
    return result

i run with
spend("wifxxx","bc1source","bc1qdest")

i get this error

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/opt/voucherbot/wallet.py", line 152, in spend
    tx = address.send(to=send_to, fee=0.0002, private=private)
  File "/usr/local/lib/python3.8/site-packages/cryptotools/BTC/address.py", line 159, in send
    inp.sign(private)
  File "/usr/local/lib/python3.8/site-packages/cryptotools/BTC/transaction.py", line 139, in sign
    output_type = self.ref().type()
  File "/usr/local/lib/python3.8/site-packages/cryptotools/BTC/transaction.py", line 271, in type
    return get_type(self.script)
  File "/usr/local/lib/python3.8/site-packages/cryptotools/BTC/script.py", line 145, in get_type
    raise ScriptValidationError(f"Unknown script type: {bytes_to_hex(script)}")
cryptotools.BTC.error.ScriptValidationError: Unknown script type: 

but it seems that bech32 (bc1q) is supported by the lib.
where am i wrong?

How to install offline?

Simply doing sudo python3 setup.py install on my raspberry pi zero which has no internet access dit not work, I get

python3
from cryptotools import Xprv
cannot import name 'Xprv' from cryptotools

/usr/local/lib/python3.7/dist-packages/cryptotools-0.1-py3.7.egg exists but there should exist a folder here, not a .egg I guess.

Thanks

Why everytime create a transaction , sent all balance amount ?

import os
os.environ['CRYPTOTOOLS_NETWORK'] = 'test'

from btctools import PrivateKey, Address

private = PrivateKey.from_hex('mysupersecretkey')
address = Address('n2NGrooSecJaiD6ssp4YqFoj9eZ7GrCJ66')

address.balance()
0.55

send_to = {'n4SbPWR6EmQMsWaQVYYFXiJgjweGKE4XnQ': 0.1, 'n2NGrooSecJaiD6ssp4YqFoj9eZ7GrCJ66': 0.4}

tx = address.send(to=send_to, fee=0.05, private=private)

tx
Transaction(inputs=1, outputs=2)


Why everytime create a transaction , sent all balance amount ?

If one unspent_outputs can pay enough, Actually, no need to add all unspent_outputs.
such as :https://www.blocktrail.com/tBTC/tx/b32cb7e657b8ba601dc081dbff144fa83e8ca5501cc22ce8b3aa21abf582bbd9

This way is not friendly ,even waste fee

How can I fix it?

Problems installing cryptotools with pip

HI mcdallas,

Thx to your awesome library I have now a security proof script up and running, that verifies extra signatures by replacing the ones in the Witness data.
Unfortunately, it only works on one computer, the other one gives errors when installing the library.
Also others in the Grin Council who I asked to check have similar issues. I will post the errors here below, do you have any idea what the issue might be and how to solve it?:

pip install git+https://github.com/mcdallas/cryptotools.git@master
Downloading/unpacking git+https://github.com/mcdallas/cryptotools.git@master
Cloning https://github.com/mcdallas/cryptotools.git (to master) to /var/folders/mr/5qs09f_56xjgy576pm_bzm1w0000gn/T/pip-Yy0873-build
Running setup.py (path:/var/folders/mr/5qs09f_56xjgy576pm_bzm1w0000gn/T/pip-Yy0873-build/setup.py) egg_info for package from git+https://github.com/mcdallas/cryptotools.git@master
Traceback (most recent call last):
File "", line 17, in
File "/var/folders/mr/5qs09f_56xjgy576pm_bzm1w0000gn/T/pip-Yy0873-build/setup.py", line 5, in
from cryptotools import doc as docstring
File "cryptotools/init.py", line 7, in
from .BTC import *
File "cryptotools/BTC/init.py", line 1, in
from cryptotools.ECDSA.secp256k1 import (
File "cryptotools/ECDSA/init.py", line 8
assert self in curve, f"Point {x}, {y} not in curve"
^
SyntaxError: invalid syntax
Complete output from command python setup.py egg_info:
Traceback (most recent call last):

File "", line 17, in

File "/var/folders/mr/5qs09f_56xjgy576pm_bzm1w0000gn/T/pip-Yy0873-build/setup.py", line 5, in

from cryptotools import __doc__ as docstring

File "cryptotools/init.py", line 7, in

from .BTC import *

File "cryptotools/BTC/init.py", line 1, in

from cryptotools.ECDSA.secp256k1 import (

File "cryptotools/ECDSA/init.py", line 8

assert self in curve, f"Point {x}, {y} not in curve"

                                                   ^

SyntaxError: invalid syntax


Cleaning up...
Command python setup.py egg_info failed with error code 1 in /var/folders/mr/5qs09f_56xjgy576pm_bzm1w0000gn/T/pip-Yy0873-build
Storing debug log for failure in /Users/tromp/Library/Logs/pip.log
$ python --version
Python 2.7.16
$ pip --version
pip 1.5.2 from /Library/Python/2.7/site-packages/pip-1.5.2-py2.7.egg (python 2.7)_

Not working with pyinstaller

I am building an application using pyinstaller. And I get an error:
File "PyInstaller/loader/pyimod03_importers.py", line 495, in exec_module File "cryptotools/__init__.py", line 16, in <module> AttributeError: 'NoneType' object has no attribute 'load_module' [8311] Failed to execute script 'CryptoWallet' due to unhandled exception!
I'm use command: pyinstaller --onefile --windowed --collect-all cryptotools myscript.py

Will this allow arbitrary/non-dictionary mnemonic seeds?

Hello,

I am trying to seed a private key with a string of random letters, and ran in to the error of "cryptotools.BTC.HD.mnemonic.InvalidMnemonic" trying to create one with an old key, becuse my words are not dictionary words included in the BIP. Is there a way to initialize a private key with random text?

Thanks!

Probably more of a question than an issue

Hi @mcdallas
I'm interested in generating addresses for Audit purposes for Ledger Nano S. Currently I'm focusing on generating segwit addresses for bitcoin. In the ledger wallet I'm able to get access to an Xpub key and a path as shown in the image below.
screen shot 2018-07-03 at 12 17 29 pm
I then am following stack exchange link

But the address that is generated doesn't seem to match my expectation. Especially when I attempt to child = extended/49./0./0. then I get an error stating "Cannot derive a hardened key from an extended public key".

Have you used this code to generate addresses based on a Ledger xpub and path? I assume I'm missing something.

Thanks for any tips/pointers

Litecoin support? Get address from Ltub?

Just a question and not an issue: is it possible to also obtain the litecoin addresses from an Ltub key?
Should be very similar to the Xpub right?

I tried to overwrite some network settings like this:

cryptotools.BTC.network.main["extended_pub"]["P2PKH"] = b'\x01\x9d\xa4\x62'  #Ltub
cryptotools.BTC.network.main["hrp"] = 'ltc' 

and then

extended = Xpub.decode('Ltub...')
child = extended/0/0
print(child.key.to_address('P2WPKH')) #native segwit
print(child.key.to_address('P2PKH')) #Pay-to-Pubkey Hash - legacy  
print(child.key.to_address('P2WPKH-P2SH')) #segwit

... but I guess I'm still missing something. For starters I guess the derivation path is still wrong and must be M/x/x/1/0/0 instead of 0/0/0. But I can't change it and didn't find the hard coded 0 for bitcoin?!
Where is the coin type (0 for bitcoin) defined?

Any idea? Would it even work like that? :D
Thanks :)

support for passphrases?

can I enter the seed + passphrases to get public key + addresses, this verifying what the coldcard does?

It makes P2WSH not right.

from cryptotools.BTC import generate_keypair, pubkey_to_address, push, script_to_address, OP

private, public = generate_keypair()
print(private.hex())
print(private.wif())
print(private.wif(compressed=True))

script = push(public.encode(compressed=True)) + OP.CHECKSIG.byte
print(public.hex())
print(public.hex(compressed=True))
print(pubkey_to_address(public, 'P2PKH'))
print(public.to_address('P2PKH', compressed=True))
print(public.to_address('P2WPKH'))
print(script_to_address(script, 'P2WSH'))
print(script_to_address(script, 'P2WSH-P2SH'))
print(script_to_address(script, 'P2SH'))
Снимок экрана (15)

BTC private keys to address and balance check

I just stumbled on these your GitHub repo I was looking for a program that will help me convert my compressed Bitcoin private key to address and check the balance. Could you please help me update or create a python program that will help me convert my compressed private key to address and check the balance. The reason I needed this was to scan through a massive private key txt file and see if I can find my missing 6 characters private key. Please help me if I recover the wallet I will donate some BTC to you. Thanks

How to generate SegWit address

Hi!
Thanks for very useful tool.
I have a few questions:

  1. How to generate compressed address?
    For example, we have hex private key, and do following

from btctools import generate_keypair, push, script_to_address, OP, PrivateKey
private = PrivateKey.from_hex('b8849572cfec1687b47ef011c7b3f3f47bfbeba632f2dec837b87e078ffb5f65')
public = private.to_public()
print(public.to_address('P2PKH'))
1PGA3E5g4YETVFY6Hw6srhX3kYHEBhXp7a

But how to get a compressed address I can not understand. :(

  1. How to generate SegWit address (not nested), beginning with 3
    I do following

from btctools import generate_keypair, push, script_to_address, OP, PrivateKey
private = PrivateKey.from_hex('b8849572cfec1687b47ef011c7b3f3f47bfbeba632f2dec837b87e078ffb5f65')
script = push(public.encode(compressed=True)) + OP.CHECKSIG.byte
private.wif(compressed=True)
'L3QPYnvjjA7YaE9WjC7qLFNV3qsDpNk5tzA5MvdJGoRpCGWDo6j8'
print(script_to_address(script, 'P2WSH-P2SH'))
35QWouHavvHf2JkjjKU8Ufci53ZAR5SFeT
print(script_to_address(script, 'P2SH'))
37p1J2zfbEXX1wpkFR6pa2njwtf8vFVRy7

But if I use this private key with this tool - https://segwitaddress.org, I get a completely different address - 3NqryJWHYUka9t57Mp5oZ232ZtgSznfXf1
Other online tools give the same address. How can I generate the address as above?

Thanks.

Add a LICENSE

I'll be using an MIT license it's a good default.

question

Hi, just came across this interesting solution - i had a quick question and sent to your email.

thanks!

How to change to testnet?

Hi, I want to change to testnet ,and then create a address in testnet . What can I do it?
Thanks

Syntax error when importing Transaction

Traceback (most recent call last):
File "run2.py", line 4, in
from btctools import Transaction
File "btctools/cryptotools/btctools/init.py", line 1, in
from ECDSA.secp256k1 import PrivateKey, PublicKey, generate_keypair, CURVE, Point, Message
File "btctools/cryptotools/ECDSA/init.py", line 8
assert self in curve, f"Point {x}, {y} not in curve"
^
SyntaxError: invalid syntax

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.