Compare commits

..

No commits in common. "master" and "pr/2" have entirely different histories.
master ... pr/2

23 changed files with 24 additions and 156 deletions

5
.gitignore vendored
View File

@ -3,6 +3,5 @@ build/
dist/ dist/
.github/ .github/
pybtc.egg-info/ pybtc.egg-info/
pyflo.egg-info/ *.pyc
pyflo_lib.egg-info/
*.pyc

101
README.md
View File

@ -63,104 +63,3 @@ True
true true
``` ```
The **sign_message_standard_ops** function verifies with [RanchiMall standard operations](https://github.com/ranchimall/Standard_Operations).
Things to note:
The function now takes 2 parameters -
1. Message in string ( not hex-encoded string)
2. Private key in wif (not bytes etc.)
The hex parameter has been removed as we are always returning hex in standard ops
New libraries used - hashlib
The elliptical curve folder, holds the code taken from starkbank ecdsa (MIT License)
no other additional dependencies
The signature generated with **sign_message_standard_ops** cannot be verified using purely Pyflo. Users can use the following API to verify signatures
** Python **
```
import requests
url = 'https://flo-sign-validator.duckdns.org'
myobj = {'floID': floID,
'pubKey': pubKey,
'message': message,
'sign': sign}
x = requests.post(url, json = myobj)
print(x.text)
```
** JavaScript **
```
fetch("https://flo-sign-validator.duckdns.org", {
method: "POST",
body: JSON.stringify({
floID: floID,
pubKey: pubKey,
message: message,
sign: sign
}),
headers: {
"Content-type": "application/json; charset=UTF-8",
},
})
.then(function (response) {
return response.json();
})
.then(function (data) {
console.log(data);
})
.catch((error) => console.error("Error:", error));
```
** PHP **
```
function callAPI($method, $url, $data){
$curl = curl_init();
switch ($method){
case "POST":
curl_setopt($curl, CURLOPT_POST, 1);
if ($data)
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
break;
case "PUT":
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "PUT");
if ($data)
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
break;
default:
if ($data)
$url = sprintf("%s?%s", $url, http_build_query($data));
}
// OPTIONS:
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_HTTPHEADER, array(
'APIKEY: 111111111111111111111',
'Content-Type: application/json',
));
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
// EXECUTE:
$result = curl_exec($curl);
curl_close($curl);
return $result;
}
$floID = $_POST['floID'];
$pubKey = $_POST['floPubKey'];
$message = $_POST['message'];
$signDataWithFlo = $_POST['signDataWithFlo'];
$data_array = array( "floID" => $floID, "pubKey" => $pubKey, "message" => $message, "sign" => $signDataWithFlo );
$make_call = callAPI('POST', 'https://flo-sign-validator.duckdns.org', json_encode($data_array));
$response = json_decode($make_call, true);
print_r($response);
```

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -14,7 +14,7 @@ ECDSA_SEC256K1_ORDER = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8
MAINNET_ADDRESS_BYTE_PREFIX = b'\x23' MAINNET_ADDRESS_BYTE_PREFIX = b'\x23'
TESTNET_ADDRESS_BYTE_PREFIX = b'\x73' TESTNET_ADDRESS_BYTE_PREFIX = b'\x73'
MAINNET_SCRIPT_ADDRESS_BYTE_PREFIX = b'\x5e' MAINNET_SCRIPT_ADDRESS_BYTE_PREFIX = b'\x05'
TESTNET_SCRIPT_ADDRESS_BYTE_PREFIX = b'\xc4' TESTNET_SCRIPT_ADDRESS_BYTE_PREFIX = b'\xc4'
MAINNET_SEGWIT_ADDRESS_BYTE_PREFIX = b'\x03\x03\x00\x02\x03' MAINNET_SEGWIT_ADDRESS_BYTE_PREFIX = b'\x03\x03\x00\x02\x03'
TESTNET_SEGWIT_ADDRESS_BYTE_PREFIX = b'\x03\x03\x00\x14\x02' TESTNET_SEGWIT_ADDRESS_BYTE_PREFIX = b'\x03\x03\x00\x14\x02'
@ -22,8 +22,7 @@ TESTNET_SEGWIT_ADDRESS_BYTE_PREFIX = b'\x03\x03\x00\x14\x02'
MAINNET_ADDRESS_PREFIX = 'F' MAINNET_ADDRESS_PREFIX = 'F'
TESTNET_ADDRESS_PREFIX = 'o' TESTNET_ADDRESS_PREFIX = 'o'
TESTNET_ADDRESS_PREFIX_2 = 'o' TESTNET_ADDRESS_PREFIX_2 = 'o'
MAINNET_SCRIPT_ADDRESS_PREFIX = 'e' MAINNET_SCRIPT_ADDRESS_PREFIX = '3'
MAINNET_SCRIPT_ADDRESS_PREFIX_2 = 'f'
TESTNET_SCRIPT_ADDRESS_PREFIX = '2' TESTNET_SCRIPT_ADDRESS_PREFIX = '2'
MAINNET_PRIVATE_KEY_UNCOMPRESSED_PREFIX = '5' MAINNET_PRIVATE_KEY_UNCOMPRESSED_PREFIX = '5'
@ -36,7 +35,6 @@ ADDRESS_PREFIX_LIST = (MAINNET_ADDRESS_PREFIX,
TESTNET_ADDRESS_PREFIX, TESTNET_ADDRESS_PREFIX,
TESTNET_ADDRESS_PREFIX_2, TESTNET_ADDRESS_PREFIX_2,
MAINNET_SCRIPT_ADDRESS_PREFIX, MAINNET_SCRIPT_ADDRESS_PREFIX,
MAINNET_SCRIPT_ADDRESS_PREFIX_2,
TESTNET_SCRIPT_ADDRESS_PREFIX) TESTNET_SCRIPT_ADDRESS_PREFIX)
PRIVATE_KEY_PREFIX_LIST = (MAINNET_PRIVATE_KEY_UNCOMPRESSED_PREFIX, PRIVATE_KEY_PREFIX_LIST = (MAINNET_PRIVATE_KEY_UNCOMPRESSED_PREFIX,

View File

@ -129,8 +129,7 @@ def address_type(address, num=False):
:return: address type in string or numeric format. :return: address type in string or numeric format.
""" """
if address[0] in (TESTNET_SCRIPT_ADDRESS_PREFIX, if address[0] in (TESTNET_SCRIPT_ADDRESS_PREFIX,
MAINNET_SCRIPT_ADDRESS_PREFIX, MAINNET_SCRIPT_ADDRESS_PREFIX):
MAINNET_SCRIPT_ADDRESS_PREFIX_2):
t = 'P2SH' t = 'P2SH'
elif address[0] in (MAINNET_ADDRESS_PREFIX, elif address[0] in (MAINNET_ADDRESS_PREFIX,
TESTNET_ADDRESS_PREFIX, TESTNET_ADDRESS_PREFIX,
@ -156,7 +155,7 @@ def address_net_type(address):
:param address: address in base58 or bech32 format. :param address: address in base58 or bech32 format.
:return: address network type in string format or None. :return: address network type in string format or None.
""" """
if address[0] in (MAINNET_SCRIPT_ADDRESS_PREFIX, MAINNET_SCRIPT_ADDRESS_PREFIX_2, if address[0] in (MAINNET_SCRIPT_ADDRESS_PREFIX,
MAINNET_ADDRESS_PREFIX): MAINNET_ADDRESS_PREFIX):
return "mainnet" return "mainnet"
elif address[:2] == MAINNET_SEGWIT_ADDRESS_PREFIX: elif address[:2] == MAINNET_SEGWIT_ADDRESS_PREFIX:
@ -179,8 +178,7 @@ def address_to_script(address, hex=False):
:return: public key script in HEX or bytes string. :return: public key script in HEX or bytes string.
""" """
if address[0] in (TESTNET_SCRIPT_ADDRESS_PREFIX, if address[0] in (TESTNET_SCRIPT_ADDRESS_PREFIX,
MAINNET_SCRIPT_ADDRESS_PREFIX, MAINNET_SCRIPT_ADDRESS_PREFIX):
MAINNET_SCRIPT_ADDRESS_PREFIX_2):
s = [OP_HASH160, s = [OP_HASH160,
b'\x14', b'\x14',
address_to_hash(address, hex=False), address_to_hash(address, hex=False),
@ -224,7 +222,6 @@ def is_address_valid(address, testnet=False):
return False return False
if address[0] in (MAINNET_ADDRESS_PREFIX, if address[0] in (MAINNET_ADDRESS_PREFIX,
MAINNET_SCRIPT_ADDRESS_PREFIX, MAINNET_SCRIPT_ADDRESS_PREFIX,
MAINNET_SCRIPT_ADDRESS_PREFIX_2,
TESTNET_ADDRESS_PREFIX, TESTNET_ADDRESS_PREFIX,
TESTNET_ADDRESS_PREFIX_2, TESTNET_ADDRESS_PREFIX_2,
TESTNET_SCRIPT_ADDRESS_PREFIX): TESTNET_SCRIPT_ADDRESS_PREFIX):
@ -235,8 +232,7 @@ def is_address_valid(address, testnet=False):
return False return False
else: else:
if address[0] not in (MAINNET_ADDRESS_PREFIX, if address[0] not in (MAINNET_ADDRESS_PREFIX,
MAINNET_SCRIPT_ADDRESS_PREFIX, MAINNET_SCRIPT_ADDRESS_PREFIX):
MAINNET_SCRIPT_ADDRESS_PREFIX_2):
return False return False
h = decode_base58(address) h = decode_base58(address)
if len(h) != 25: if len(h) != 25:
@ -279,11 +275,11 @@ def is_address_valid(address, testnet=False):
if checksum != checksum2: if checksum != checksum2:
return False return False
return True return True
else:
return False
def get_witness_version(address): def get_witness_version(address):
address = address.split("1")[1] address = address.split("1")[1]
h = rebase_32_to_5(address) h = rebase_32_to_5(address)
return h[0] return h[0]

View File

@ -22,7 +22,6 @@ from pyflo.functions.tools import bytes_from_hex, int_to_bytes, get_stream
from pyflo.functions.hash import hash160, sha256 from pyflo.functions.hash import hash160, sha256
from pyflo.functions.address import hash_to_address from pyflo.functions.address import hash_to_address
from pyflo.functions.key import is_wif_valid, wif_to_private_key from pyflo.functions.key import is_wif_valid, wif_to_private_key
import requests, json
def public_key_to_pubkey_script(key, hex=True): def public_key_to_pubkey_script(key, hex=True):
@ -166,6 +165,9 @@ def script_to_address(script, testnet=False):
return None return None
def decode_script(script, asm=False): def decode_script(script, asm=False):
""" """
Decode script to ASM format or to human readable OPCODES string. Decode script to ASM format or to human readable OPCODES string.
@ -402,33 +404,6 @@ def verify_signature(sig, pub_key, msg):
result = secp256k1_ecdsa_verify(ECDSA_CONTEXT_VERIFY, raw_sig, msg, raw_pubkey) result = secp256k1_ecdsa_verify(ECDSA_CONTEXT_VERIFY, raw_sig, msg, raw_pubkey)
return True if result else False return True if result else False
def verify_signature_standard_ops(sig, pub_key, msg, floID):
"""
Verify signature for message and given public key
:param sig: signature in bytes or HEX encoded string.
:param pub_key: public key in bytes or HEX encoded string.
:param msg: message in bytes, string or HEX encoded string.
:flo_id: FLO ID in HEX encoded string.
:return: boolean.
"""
url = 'https://flo-sign-validator.duckdns.org'
post_data = {
'floID': floID,
'pubKey': pub_key,
'message': msg,
'sign': sig
}
signature_verification = requests.post(url, json = post_data)
signature_verification = json.loads(signature_verification.text)
if signature_verification['success']:
return True
else:
return False
def to_base(n, base): def to_base(n, base):
if base == 10: if base == 10:
return n return n
@ -638,4 +613,5 @@ def is_valid_signature_encoding(sig):
# interpreted as a negative number. # interpreted as a negative number.
if (len_s > 1) and (sig[len_r + 6] == 0x00) and (not sig[len_r + 7] & 0x80): if (len_s > 1) and (sig[len_r + 6] == 0x00) and (not sig[len_r + 7] & 0x80):
return False return False
return True return True

View File

@ -4,19 +4,19 @@
from setuptools import setup, find_packages from setuptools import setup, find_packages
setup(name='pyflo-lib', setup(name='pybtc',
version='2.0.9', version='2.0.9',
description='Python FLO library', description='Python Bitcoin library',
keywords='flo', keywords='bitcoin',
url='https://github.com/ranchimall/pyflo', url='https://github.com/bitaps-com/pybtc',
author='Ranchi Mall', author='Alexsei Karpov',
author_email='ranchimallfze@gmail.com', author_email='admin@bitaps.com',
license='GPL-3.0', license='GPL-3.0',
packages=find_packages(), packages=find_packages(),
install_requires=['secp256k1'], install_requires=['secp256k1'],
include_package_data=True, include_package_data=True,
package_data={ package_data={
'pyflo': ['bip39_word_list/*.txt', 'test/*.txt'], 'pybtc': ['bip39_word_list/*.txt', 'test/*.txt'],
}, },
test_suite='tests', test_suite='tests',
zip_safe=False) zip_safe=False)

View File

@ -1,9 +1,9 @@
import unittest import unittest
import pyflo.test import pybtc.test
testLoad = unittest.TestLoader() testLoad = unittest.TestLoader()
suites = testLoad.loadTestsFromModule(pyflo.test) suites = testLoad.loadTestsFromModule(pybtc.test)
runner = unittest.TextTestRunner(verbosity=1) runner = unittest.TextTestRunner(verbosity=1)
runner.run(suites) runner.run(suites)