Skip to content
This repository has been archived by the owner on Sep 10, 2019. It is now read-only.

Commit

Permalink
Merge pull request #28 from CityOfZion/feature-keypair
Browse files Browse the repository at this point in the history
move cryptography + keypair to neocore
  • Loading branch information
localhuman committed Jan 8, 2018
2 parents 2e3f853 + 3dc156a commit 9ebba05
Show file tree
Hide file tree
Showing 12 changed files with 2,086 additions and 3 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ install:

script:
# run internal tests
- coverage run --source neocore setup.py test
- coverage run --omit neocore/Cryptography/ECCurve.py --source neocore setup.py test
- pycodestyle neocore tests

# now test the upstream neo-python dev branch with the current neocore code
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ test: ## run tests quickly with the default Python

coverage: ## check code coverage quickly with the default Python
coverage run --source neocore setup.py test
coverage report -m
coverage report -m --omit=neocore/Cryptography/ECCurve.py
coverage html
$(BROWSER) htmlcov/index.html

Expand Down
218 changes: 218 additions & 0 deletions neocore/Cryptography/Crypto.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
import bitcoin
from ecdsa import NIST256p, VerifyingKey
from logzero import logger
from .Helper import *
from neocore.UInt160 import UInt160
from .ECCurve import EllipticCurve


class Crypto(object):

@staticmethod
def SetupSignatureCurve():
"""
Setup the Elliptic curve parameters.
"""
bitcoin.change_curve(
int("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF", 16),
int("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551", 16),
int("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC", 16),
int("5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B", 16),
int("6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296", 16),
int("4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5", 16)
)

@staticmethod
def Default():
"""
Get the default Crypto instance.
Returns:
CryptoInstance:
"""
return CryptoInstance()

@staticmethod
def Hash160(message):
"""
Get a hash of the provided message using the ripemd160 algorithm.
Args:
message (str): message to hash.
Returns:
str: hash as a double digit hex string.
"""
return bin_hash160(message)

@staticmethod
def Hash160Bytes(message):
"""
Get a hash of the provided message using the ripemd160 algorithm.
Args:
message (str): message to hash.
Returns:
bytes: hash.
"""
return bin_hash160Bytes(message)

@staticmethod
def Hash256(message):
"""
Get a the hash of a double SHA256 operation on the message. i.e. SHA256(SHA256(message))
Args:
message (str): message to hash.
Returns:
bytes: hash.
"""
return bin_dbl_sha256(message)

@staticmethod
def ToScriptHash(data, unhex=True):
"""
Get a script hash of the data.
Args:
data (bytes): data to hash.
unhex (bool): (Default) True. Set to unhexlify the stream. Use when the bytes are not raw bytes; i.e. b'aabb'
Returns:
UInt160: script hash.
"""
if len(data) > 1 and unhex:
data = binascii.unhexlify(data)
return UInt160(data=binascii.unhexlify(bytes(Crypto.Hash160(data), encoding='utf-8')))

@staticmethod
def ToAddress(script_hash):
"""
Get the public address of the script hash.
Args:
script_hash (UInt160):
Returns:
str: base58 encoded string representing the wallet address.
"""
return scripthash_to_address(script_hash.Data)

@staticmethod
def Sign(message, private_key, public_key):
"""
Sign the message with the given private key.
Args:
message (str): message to be signed
private_key (str): 32 byte key as a double digit hex string (e.g. having a length of 64)
public_key: UNUSED.
Returns:
bytearray: the signature of the message.
"""
Crypto.SetupSignatureCurve()

hash = hashlib.sha256(binascii.unhexlify(message)).hexdigest()

v, r, s = bitcoin.ecdsa_raw_sign(hash, private_key)

rb = bytearray(r.to_bytes(32, 'big'))
sb = bytearray(s.to_bytes(32, 'big'))

sig = rb + sb

return sig

@staticmethod
def VerifySignature(message, signature, public_key):
"""
Verify the integrity of the message.
Args:
message (str): the message to verify.
signature (bytearray): the signature belonging to the message.
public_key (ECPoint|bytes): the public key to use for verifying the signature. If `public_key` is of type bytes then it should be raw bytes (i.e. b'\xAA\xBB').
Returns:
bool: True if verification passes. False otherwise.
"""
Crypto.SetupSignatureCurve()

if type(public_key) is EllipticCurve.ECPoint:
pubkey_x = public_key.x.value.to_bytes(32, 'big')
pubkey_y = public_key.y.value.to_bytes(32, 'big')

public_key = pubkey_x + pubkey_y

m = message
try:
m = binascii.unhexlify(message)
except Exception as e:
logger.error("could not get m: %s" % e)

if len(public_key) == 33:
public_key = bitcoin.decompress(public_key)
public_key = public_key[1:]

try:
vk = VerifyingKey.from_string(public_key, curve=NIST256p, hashfunc=hashlib.sha256)
res = vk.verify(signature, m, hashfunc=hashlib.sha256)
return res
except Exception as e:
pass

return False


class CryptoInstance():

def Hash160(self, message):
"""
Get a hash of the provided message using the ripemd160 algorithm.
Args:
message (str): message to hash.
Returns:
str: hash as a double digit hex string.
"""
return Crypto.Hash160Bytes(message)

def Hash256(self, message):
"""
Get a the hash of a double SHA256 operation on the message. i.e. SHA256(SHA256(message))
Args:
message (str): message to hash.
Returns:
bytes: hash.
"""
return Crypto.Hash256(message)

def Sign(self, message, prikey, public_key):
"""
Sign the message with the given private key.
Args:
message (str): message to be signed
prikey (str): 32 byte key as a double digit hex string (e.g. having a length of 64)
public_key: UNUSED.
Returns:
bytearray: the signature of the message.
"""
return Crypto.Sign(message, prikey, public_key)

def VerifySignature(self, message, signature, pubkey):
"""
Verify the integrity of the message.
Args:
message (str): the message to verify.
signature (bytearray): the signature belonging to the message.
pubkey (ECPoint): the public key to use for verifying the signature.
Returns:
bool: True if verification passes. False otherwise.
"""
return Crypto.VerifySignature(message, signature, pubkey)
Loading

0 comments on commit 9ebba05

Please sign in to comment.