Compare commits

...

13 Commits
pr/2 ... master

Author SHA1 Message Date
Vivek Teega
ee50ef60b9 Renamed packge to "pyflo-lib" so we can upload to PyPI 2023-02-20 21:56:27 +05:30
Vivek Teega
64119f8baa Changes for PyPI 2023-02-20 21:10:39 +05:30
Vivek Teega
1f7cbcfa13 Changes to integrate FLO Multisig
Co-Authored-By: Sai Raj <39055732+sairajzero@users.noreply.github.com>
2023-02-20 17:01:29 +05:30
Vivek Teega
c4f1c8b5af Change verify_signature_standard_ops : Totally depends on external API 2022-07-13 16:50:12 +05:30
Vivek Teega
3618687377 Bug fix 2022-07-12 11:37:41 +00:00
Vivek Teega
498d0064cd Update verify_signature_standard_ops to check if the floid is same as public key 2022-07-12 11:20:24 +00:00
Vivek Teega
c9a58a7305 Fix bug in standard ops verification 2022-07-10 18:52:07 +00:00
Vivek Teega
a386de5197 Updated verify_signature_standard_ops to only return signature verification 2022-07-10 13:29:31 +00:00
Vivek Teega
0a3bf90767 Updated script.py to use external API for verifying Standard Ops signatures 2022-07-10 06:57:01 +00:00
042f3da96e
Update README.md 2022-07-09 16:23:45 +05:30
Vivek Teega
282edba6a0 Update Readme 2022-07-09 10:29:14 +00:00
Vivek Teega
09c24b370f
Update README.md 2022-07-09 14:55:13 +05:30
Vivek Teega
05f2f09043
Merge pull request #3 from ranchimall/pr/2
Pr/2
2022-07-09 14:50:27 +05:30
23 changed files with 156 additions and 24 deletions

5
.gitignore vendored
View File

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

101
README.md
View File

@ -63,3 +63,104 @@ 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);
```

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'\x05' MAINNET_SCRIPT_ADDRESS_BYTE_PREFIX = b'\x5e'
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,7 +22,8 @@ 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 = '3' MAINNET_SCRIPT_ADDRESS_PREFIX = 'e'
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'
@ -35,6 +36,7 @@ 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,7 +129,8 @@ 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,
@ -155,7 +156,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, if address[0] in (MAINNET_SCRIPT_ADDRESS_PREFIX, MAINNET_SCRIPT_ADDRESS_PREFIX_2,
MAINNET_ADDRESS_PREFIX): MAINNET_ADDRESS_PREFIX):
return "mainnet" return "mainnet"
elif address[:2] == MAINNET_SEGWIT_ADDRESS_PREFIX: elif address[:2] == MAINNET_SEGWIT_ADDRESS_PREFIX:
@ -178,7 +179,8 @@ 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),
@ -222,6 +224,7 @@ 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):
@ -232,7 +235,8 @@ 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:
@ -275,11 +279,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,6 +22,7 @@ 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):
@ -165,9 +166,6 @@ 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.
@ -404,6 +402,33 @@ 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
@ -613,5 +638,4 @@ 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='pybtc', setup(name='pyflo-lib',
version='2.0.9', version='2.0.9',
description='Python Bitcoin library', description='Python FLO library',
keywords='bitcoin', keywords='flo',
url='https://github.com/bitaps-com/pybtc', url='https://github.com/ranchimall/pyflo',
author='Alexsei Karpov', author='Ranchi Mall',
author_email='admin@bitaps.com', author_email='ranchimallfze@gmail.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={
'pybtc': ['bip39_word_list/*.txt', 'test/*.txt'], 'pyflo': ['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 pybtc.test import pyflo.test
testLoad = unittest.TestLoader() testLoad = unittest.TestLoader()
suites = testLoad.loadTestsFromModule(pybtc.test) suites = testLoad.loadTestsFromModule(pyflo.test)
runner = unittest.TextTestRunner(verbosity=1) runner = unittest.TextTestRunner(verbosity=1)
runner.run(suites) runner.run(suites)