Compare commits
No commits in common. "master" and "pr/2" have entirely different histories.
3
.gitignore
vendored
3
.gitignore
vendored
@ -3,6 +3,5 @@ build/
|
|||||||
dist/
|
dist/
|
||||||
.github/
|
.github/
|
||||||
pybtc.egg-info/
|
pybtc.egg-info/
|
||||||
pyflo.egg-info/
|
|
||||||
pyflo_lib.egg-info/
|
|
||||||
*.pyc
|
*.pyc
|
||||||
|
|
||||||
|
|||||||
101
README.md
101
README.md
@ -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);
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|||||||
BIN
pyflo/__pycache__/__init__.cpython-36.pyc
Normal file
BIN
pyflo/__pycache__/__init__.cpython-36.pyc
Normal file
Binary file not shown.
BIN
pyflo/__pycache__/__init__.cpython-38.pyc
Normal file
BIN
pyflo/__pycache__/__init__.cpython-38.pyc
Normal file
Binary file not shown.
BIN
pyflo/__pycache__/address.cpython-36.pyc
Normal file
BIN
pyflo/__pycache__/address.cpython-36.pyc
Normal file
Binary file not shown.
BIN
pyflo/__pycache__/address.cpython-38.pyc
Normal file
BIN
pyflo/__pycache__/address.cpython-38.pyc
Normal file
Binary file not shown.
BIN
pyflo/__pycache__/block.cpython-36.pyc
Normal file
BIN
pyflo/__pycache__/block.cpython-36.pyc
Normal file
Binary file not shown.
BIN
pyflo/__pycache__/block.cpython-38.pyc
Normal file
BIN
pyflo/__pycache__/block.cpython-38.pyc
Normal file
Binary file not shown.
BIN
pyflo/__pycache__/consensus.cpython-36.pyc
Normal file
BIN
pyflo/__pycache__/consensus.cpython-36.pyc
Normal file
Binary file not shown.
BIN
pyflo/__pycache__/consensus.cpython-38.pyc
Normal file
BIN
pyflo/__pycache__/consensus.cpython-38.pyc
Normal file
Binary file not shown.
BIN
pyflo/__pycache__/constants.cpython-36.pyc
Normal file
BIN
pyflo/__pycache__/constants.cpython-36.pyc
Normal file
Binary file not shown.
BIN
pyflo/__pycache__/constants.cpython-38.pyc
Normal file
BIN
pyflo/__pycache__/constants.cpython-38.pyc
Normal file
Binary file not shown.
BIN
pyflo/__pycache__/opcodes.cpython-36.pyc
Normal file
BIN
pyflo/__pycache__/opcodes.cpython-36.pyc
Normal file
Binary file not shown.
BIN
pyflo/__pycache__/opcodes.cpython-38.pyc
Normal file
BIN
pyflo/__pycache__/opcodes.cpython-38.pyc
Normal file
Binary file not shown.
BIN
pyflo/__pycache__/transaction.cpython-36.pyc
Normal file
BIN
pyflo/__pycache__/transaction.cpython-36.pyc
Normal file
Binary file not shown.
BIN
pyflo/__pycache__/transaction.cpython-38.pyc
Normal file
BIN
pyflo/__pycache__/transaction.cpython-38.pyc
Normal file
Binary file not shown.
BIN
pyflo/__pycache__/wallet.cpython-36.pyc
Normal file
BIN
pyflo/__pycache__/wallet.cpython-36.pyc
Normal file
Binary file not shown.
BIN
pyflo/__pycache__/wallet.cpython-38.pyc
Normal file
BIN
pyflo/__pycache__/wallet.cpython-38.pyc
Normal file
Binary file not shown.
@ -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,
|
||||||
|
|||||||
@ -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]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
@ -639,3 +614,4 @@ def is_valid_signature_encoding(sig):
|
|||||||
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
|
||||||
|
|
||||||
|
|||||||
14
setup.py
14
setup.py
@ -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)
|
||||||
|
|||||||
4
tests.py
4
tests.py
@ -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)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user