Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Signing Complete #2

Open
wants to merge 3 commits into
base: standard_ops
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ build/
dist/
.github/
pybtc.egg-info/

*.pyc
86 changes: 50 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,49 +1,63 @@
<img src="docs/img/pybtc.png" width="100">

## Python bitcoin library

Current version is 2.0


### Feature Support

* Basic functions
* Supports addresses types PUBKEY, P2PKH, P2SH, P2SH-PWPKH, P2WPKH, P2WSH.
* Supports BIP32(Hierarchical Deterministic Wallets), BIP39(Mnemonic code generation)
* Supports BIP141(Segregated Witness)
* Transaction constructor

## Python bitcoin library modified for FLO

### Installation
To install pyflo,

To install pybtc, simply use pip

$ git clone https://github.com/bitaps-com/pybtc
$ cd pybtc
$ python3 setup.py install
$ git clone https://github.com/ranchimall/pyflo
$ cd pyflo
$ sudo python3 setup.py install

### Dependencies

* Python 3.3.3+
* secp256k1


### Documentation

Documentation is available at https://pybtc.readthedocs.io


### How to Contribute

In order to make a clone of the GitHub repo: open the link and press the “Fork” button on the upper-right menu of the web page.

Workflow is pretty straightforward:
#### Message signing and verification

Every message sent to the Blockchain is in hash format, and not in plain string. So we convert the message we are signing into a SHA256 hash before.

```
>>> import pyflo

# ADDRESS GENERATION
>>> a = pyflo.Address(address_type="P2PKH")
>>> a.address
'FTP7LL7QjhgKfqYX1pis18bCqEpZaGSRzZ'
>>> a.private_key.wif
'R8Gw2Mr3n2fY1ydB2X5gEehxHkdhboeUD6yw4wRtVKHaqAd9gdkK'
>>> a.private_key.hex
'16b6aca5ff6a3bf3a1332dd4edf87880b2883cb4fe16effd073e2e866aa141aa'
>>> a.public_key.hex
'033c30b269e2d5df229f3f0ce294b19c4f0a3a8d12280415ce41e7bd3784a619c4'

# CONVERT MESSAGE INTO SHA-256 HASH
>>> pyflo.sha256(b'vivek'.hex())
b'\xa3\xdas\x97e\x01\x81,\xd7\xb8!\xa2\x0b\xfb\t\xaf\nj\x89\x1eA\x9c\xdf\xb7a\xfb\x19\xa9,\x91BB'
>>> pyflo.sha256(b'vivek'.hex()).hex()
'a3da73976501812cd7b821a20bfb09af0a6a891e419cdfb761fb19a92c914242'
>>> msg = b'vivek'.hex()
>>> msg_hash_hex = pyflo.sha256(msg).hex()
>>> msg_hash_bytes = pyflo.sha256(msg)
>>> msg
'766976656b'
>>> msg_hash_hex
'a3da73976501812cd7b821a20bfb09af0a6a891e419cdfb761fb19a92c914242'
>>> msg_hash_bytes
b'\xa3\xdas\x97e\x01\x81,\xd7\xb8!\xa2\x0b\xfb\t\xaf\nj\x89\x1eA\x9c\xdf\xb7a\xfb\x19\xa9,\x91BB'

# SIGN AND VERIFY THE MESSAGE
>>> sig_msg_hex = pyflo.sign_message(msg_hash_hex, a.private_key.wif)
>>> pyflo.verify_signature(sig_msg_hex, a.public_key.hex, msg_hash_hex)
True

# SIGN AND VERIFY MESSAGE IN STANDARD OPERATION
sig_msg_hex = pyflo.sign_message_standard_ops('vivek', a.private_key.wif)

# To verify the above signature, run the following in the console of any Standard Ops app
floCrypto.verifySign('vivek', sig_msg_hex, a.public_key.hex)

```

1. Clone the GitHub
2. Make a change
3. Make sure all tests passed
4. Add a record into file into change.log.
5. Commit changes to own pybtc clone
6. Make pull request from github page for your clone against master branch


10 changes: 0 additions & 10 deletions pybtc/__init__.py

This file was deleted.

10 changes: 10 additions & 0 deletions pyflo/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from pyflo.constants import *
from pyflo.opcodes import *
from pyflo.consensus import *
from pyflo.functions import *


from .transaction import *
from .block import *
from .address import *
from .wallet import *
Binary file added pyflo/__pycache__/__init__.cpython-38.pyc
Binary file not shown.
Binary file added pyflo/__pycache__/address.cpython-38.pyc
Binary file not shown.
Binary file added pyflo/__pycache__/block.cpython-38.pyc
Binary file not shown.
Binary file added pyflo/__pycache__/consensus.cpython-38.pyc
Binary file not shown.
Binary file added pyflo/__pycache__/constants.cpython-38.pyc
Binary file not shown.
Binary file added pyflo/__pycache__/opcodes.cpython-38.pyc
Binary file not shown.
Binary file added pyflo/__pycache__/transaction.cpython-38.pyc
Binary file not shown.
Binary file added pyflo/__pycache__/wallet.cpython-38.pyc
Binary file not shown.
File renamed without changes.
14 changes: 7 additions & 7 deletions pybtc/address.py → pyflo/address.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from pybtc.constants import *
from pybtc.opcodes import *
from pybtc.functions.tools import bytes_from_hex, int_to_var_int
from pybtc.functions.script import op_push_data, decode_script
from pybtc.functions.hash import hash160, sha256
from pybtc.functions.address import hash_to_address, public_key_to_p2sh_p2wpkh_script
from pybtc.functions.key import (create_private_key,
from pyflo.constants import *
from pyflo.opcodes import *
from pyflo.functions.tools import bytes_from_hex, int_to_var_int
from pyflo.functions.script import op_push_data, decode_script
from pyflo.functions.hash import hash160, sha256
from pyflo.functions.address import hash_to_address, public_key_to_p2sh_p2wpkh_script
from pyflo.functions.key import (create_private_key,
private_key_to_wif,
is_wif_valid,
wif_to_private_key,
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
8 changes: 4 additions & 4 deletions pybtc/block.py → pyflo/block.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from struct import unpack, pack
from io import BytesIO
from pybtc.functions.block import bits_to_target, target_to_difficulty
from pybtc.functions.hash import double_sha256
from pybtc.functions.tools import var_int_to_int, read_var_int, var_int_len, rh2s
from pybtc.transaction import Transaction
from pyflo.functions.block import bits_to_target, target_to_difficulty
from pyflo.functions.hash import double_sha256
from pyflo.functions.tools import var_int_to_int, read_var_int, var_int_len, rh2s
from pyflo.transaction import Transaction


class Block(dict):
Expand Down
File renamed without changes.
File renamed without changes.
6 changes: 6 additions & 0 deletions pyflo/ellipticcurve/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from .utils.compatibility import *
from .privateKey import PrivateKey
from .publicKey import PublicKey
from .signature import Signature
from .utils.file import File
from .ecdsa import Ecdsa
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added pyflo/ellipticcurve/__pycache__/point.cpython-38.pyc
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
79 changes: 79 additions & 0 deletions pyflo/ellipticcurve/curve.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#
# Elliptic Curve Equation
#
# y^2 = x^3 + A*x + B (mod P)
#
from .point import Point


class CurveFp:

def __init__(self, A, B, P, N, Gx, Gy, name, oid, nistName=None):
self.A = A
self.B = B
self.P = P
self.N = N
self.G = Point(Gx, Gy)
self.name = name
self.nistName = nistName
self.oid = oid # ASN.1 Object Identifier

def contains(self, p):
"""
Verify if the point `p` is on the curve

:param p: Point p = Point(x, y)
:return: boolean
"""
if not 0 <= p.x <= self.P - 1:
return False
if not 0 <= p.y <= self.P - 1:
return False
if (p.y**2 - (p.x**3 + self.A * p.x + self.B)) % self.P != 0:
return False
return True

def length(self):
return (1 + len("%x" % self.N)) // 2


secp256k1 = CurveFp(
name="secp256k1",
A=0x0000000000000000000000000000000000000000000000000000000000000000,
B=0x0000000000000000000000000000000000000000000000000000000000000007,
P=0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f,
N=0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141,
Gx=0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,
Gy=0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8,
oid=[1, 3, 132, 0, 10]
)

prime256v1 = CurveFp(
name="prime256v1",
nistName="P-256",
A=0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc,
B=0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b,
P=0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff,
N=0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551,
Gx=0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296,
Gy=0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5,
oid=[1, 2, 840, 10045, 3, 1, 7],
)

p256 = prime256v1

supportedCurves = [
secp256k1,
prime256v1,
]

_curvesByOid = {tuple(curve.oid): curve for curve in supportedCurves}


def getCurveByOid(oid):
if oid not in _curvesByOid:
raise Exception("Unknown curve with oid {oid}; The following are registered: {names}".format(
oid=".".join([str(number) for number in oid]),
names=", ".join([curve.name for curve in supportedCurves]),
))
return _curvesByOid[oid]
46 changes: 46 additions & 0 deletions pyflo/ellipticcurve/ecdsa.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
from hashlib import sha256
from .signature import Signature
from .math import Math
from .utils.integer import RandomInteger
from .utils.binary import numberFromByteString
from .utils.compatibility import *


class Ecdsa:

@classmethod
def sign(cls, message, privateKey, hashfunc=sha256):
byteMessage = hashfunc(toBytes(message)).digest()
numberMessage = numberFromByteString(byteMessage)
curve = privateKey.curve

r, s, randSignPoint = 0, 0, None
while r == 0 or s == 0:
randNum = RandomInteger.between(1, curve.N - 1)
randSignPoint = Math.multiply(curve.G, n=randNum, A=curve.A, P=curve.P, N=curve.N)
r = randSignPoint.x % curve.N
s = ((numberMessage + r * privateKey.secret) * (Math.inv(randNum, curve.N))) % curve.N
recoveryId = randSignPoint.y & 1
if randSignPoint.y > curve.N:
recoveryId += 2

return Signature(r=r, s=s, recoveryId=recoveryId)

@classmethod
def verify(cls, message, signature, publicKey, hashfunc=sha256):
byteMessage = hashfunc(toBytes(message)).digest()
numberMessage = numberFromByteString(byteMessage)
curve = publicKey.curve
r = signature.r
s = signature.s
if not 1 <= r <= curve.N - 1:
return False
if not 1 <= s <= curve.N - 1:
return False
inv = Math.inv(s, curve.N)
u1 = Math.multiply(curve.G, n=(numberMessage * inv) % curve.N, N=curve.N, A=curve.A, P=curve.P)
u2 = Math.multiply(publicKey.point, n=(r * inv) % curve.N, N=curve.N, A=curve.A, P=curve.P)
v = Math.add(u1, u2, A=curve.A, P=curve.P)
if v.isAtInfinity():
return False
return v.x % curve.N == r
Loading