Skip to content

rs19hack/cryptotools

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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.

Examples

HD Wallets

from btctools 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'

Sign/Verify message:

from ECDSA.secp256k1 import generate_keypair, Message

>>> private, public = generate_keypair()

>>> message = Message.from_str('kinakuta')
>>> signature = message.sign(private)
>>> message.verify(signature, public)
True

Verify a transaction:

from btctools 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()
True

Create a transaction and submit it automatically

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

from btctools 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 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)

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

>>> tx.verify()
True

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

Create keys/addresses (including segwit)

>>> from btctools 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
>>> script_to_address(script, 'P2WSH-P2SH')
'34eBzenHJEdk5PK9ojuuBZvCRtNhvvysYZ'
>>> from 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'

Vanity address generator

>>> from btctools.address import vanity

>>> private, public, address = vanity('Bob')  # Takes forever
Found address starting with Bob in 1:17:55 after 80,111 tries

RSA

>>> import RSA

>>> private, public = RSA.generate_keypair(512)

>>> txt = 'deadbeef'
>>> message = RSA.Message.from_hex(txt)
>>> message
b'\xde\xad\xbe\xef'


>>> message.encrypt(public)
>>> message
b'\x05\xe3q\x92\x1c=)\xaev\xe8\x8d\x8c\x9f\x8d\xde\x17\xdc\x95y\x1e\x90N\xf1A\x816\xb7|z\x83...'

>>> message.decrypt(private)
>>> message.hex() == txt
True

>>> message.encrypt(private)
>>> message.decrypt(public)
>>> message.hex() == txt
True

to run tests

$ python -m unittest

from the project directory

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Python 100.0%