Created
February 11, 2022 03:57
-
-
Save HRezaei/156f9fa347d666e67f01264c65671cad to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
ECPy==1.2.5 | |
eth_keys==0.3.3 | |
eth_utils==1.10.0 | |
nacl==0.0.0 | |
PyNaCl==1.4.0 | |
requests==2.26.0 | |
stellar_sdk==7.0.0 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Alice pay 10.25 XLM to Bob | |
import json | |
import os | |
import subprocess | |
from time import sleep | |
import requests | |
from ecpy.curves import Curve | |
from ecpy.formatters import encode_sig | |
from eth_keys.utils.padding import pad32 | |
from eth_utils import int_to_big_endian | |
from nacl import hash | |
from stellar_sdk import Asset, Server, Keypair, TransactionBuilder, Network | |
from stellar_sdk.decorated_signature import DecoratedSignature | |
TSS_EXECUTABLE = "/tss-ecdsa-cli/target/debug/tss_cli" | |
#TSS_EXECUTABLE = "/tmp/tss-ecdsa-cli/target/debug/tss_cli" | |
TSS_KEYS_FILE = "/tmp/ted1.store" | |
EDDSA_EXECUTABLE_PATH = "/multi-party-eddsa/target/debug/examples/" | |
cv25519 = Curve.get_curve("Ed25519") | |
def tss_signer(hex, path): | |
signature_output_file = "signature.json" | |
try: | |
os.remove(signature_output_file) | |
except Exception as e: | |
print(e) | |
for i in range(1, 4): | |
command = TSS_EXECUTABLE + " sign /tmp/ted" + str(i) + ".store 2/3 \"" + hex + "\" -ceddsa" | |
if len(path) > 0: | |
command = command + " -p" + path | |
#command = TSS_EXECUTABLE + " sign /tmp/ed" + str(i) + ".store 2/3 -ceddsa \"" + hex + "\"" | |
if i != 3: | |
command = command + ' >> /dev/null &' | |
else: | |
#command = command + ' > ' + signature_output_file | |
print("TSS sign command: ", command) | |
os.system(command) | |
sleep(1) | |
file = open(signature_output_file, "r") | |
#content = file.read() | |
#content = "{\"" + content.split("{\"")[1] | |
sign_output = json.load(file) | |
print("TSS output: ", sign_output) | |
file.close() | |
return sign_output | |
def create_stellar_keypair_from_seed_hex(seed_hex): | |
private_key_seed_int = int(seed_hex, 16) | |
private_key_seed_bytes = private_key_seed_int.to_bytes(32, 'big') | |
private_key = Keypair.from_raw_ed25519_seed(private_key_seed_bytes) | |
return private_key | |
def create_stellar_pubkey_from_hex(pubkey_hex): | |
point_on_curve = bytes.fromhex(pubkey_hex) | |
keypair = Keypair.from_raw_ed25519_public_key(point_on_curve) | |
return keypair.verify_key | |
def create_stellar_public_keypair_from_xy(x_hex, y_hex): | |
""" | |
Creates a public Keypair | |
Public Keypairs cannot be used for signing, just for verification. | |
:param x_hex: | |
:param y_hex: | |
:return: | |
""" | |
x, y = int(x_hex, 16), int(y_hex, 16) | |
point = create_point(x, y) | |
keypair = Keypair.from_raw_ed25519_public_key(point) | |
return keypair | |
def generate_sig_from_rs(r_hex, s_hex): | |
r, s = int(r_hex, 16), int(s_hex, 16) | |
rb_be = pad32(int_to_big_endian(r)) | |
sb_le = pad32(int_to_big_endian(s)) | |
signature_rs_bytes = b''.join((rb_be, sb_le)) | |
return signature_rs_bytes | |
def create_point(x, y): | |
class myp: pass | |
mypoint = myp() | |
mypoint.x = x # 0x161474b35b82c2917bc483ac0516a2dbd1a85c8b582ec28f394bc49c0052e86d | |
mypoint.y = y | |
return cv25519.encode_point(mypoint) | |
def format_signature_from_r_s(r_hex, s_hex): | |
eR, S = int(r_hex, 16), int(s_hex, 16) | |
raw_signed = encode_sig(eR, S, "EDDSA", 32) | |
return raw_signed | |
def read_xy_from_tss_pubkey(path): | |
# cmd = f'{TSS_EXECUTABLE} pubkey {TSS_KEYS_FILE} -p {path} -c eddsa' | |
cmd = f'{TSS_EXECUTABLE} pubkey {TSS_KEYS_FILE} -c eddsa' | |
if path: | |
cmd = cmd + " -p " + path | |
print("TSS pubkey command: ", cmd) | |
output = subprocess.check_output(cmd.split(' ')) | |
xy_dict = json.loads(output) | |
print('Key file x,y:', xy_dict) | |
return xy_dict | |
def read_store_file(file_path): | |
with open(file_path, 'r') as file: | |
store_data = json.load(file) | |
return store_data | |
def eddsa_signer(hex, method="eph"): | |
executable = "eph_sign_client" if method == "eph" else "gg18_sign_client" | |
for i in range(1, 4): | |
"Message for Ed25519 signing" | |
command = EDDSA_EXECUTABLE_PATH + executable + " http://127.0.0.1:8001 /tmp/ted" + str(i) + "2.store \"" + hex + "\"" | |
if i != 3: | |
command = command + ' >> /dev/null &' | |
#os.system(command) | |
else: | |
command = command + " " | |
print("TSS sign command: ", command) | |
#output = subprocess.check_output(command.split(' ')) | |
os.system(command) | |
sleep(2) | |
file = open("signature.json") | |
xy_dict = json.load(file) | |
print("EDDSA output: ", xy_dict) | |
return xy_dict | |
def test1(): | |
""" | |
This function tries to sign a custom message with TSS -> signature | |
and create an Stellar public key from the x,y of public key which TSS has used | |
and then verify the signature | |
""" | |
msg = b"hi" | |
path = '0/1' | |
xy_dict = read_xy_from_tss_pubkey(path) | |
public_key = create_stellar_public_keypair_from_xy(xy_dict['x'], xy_dict['y']) | |
print(public_key.raw_public_key().hex()) | |
sign_dict = tss_signer(msg.hex(), path) | |
assert sign_dict['x'] == xy_dict['x'] | |
assert sign_dict['y'] == xy_dict['y'] | |
raw_signed = generate_sig_from_rs(sign_dict["r"], sign_dict["s"]) | |
public_key.verify(msg, raw_signed) | |
print("Verified successfully") | |
return | |
def test2(): | |
""" | |
This function tries to sign a custom message with TSS -> signature | |
and create an Stellar public key from the private key which TSS has used | |
and then verify the signature | |
""" | |
msg = b"hi" | |
path = '' | |
store_data = read_store_file('/tmp/single.store') | |
'''store_data = store_data['multisig'] | |
private_seed = store_data['private_key'] | |
public_key = store_data['public_key']['bytes_str'] | |
''' | |
'''store_data = store_data['thresholdsig'] | |
private_seed = store_data['u_i'] | |
public_key = store_data['y_i']['bytes_str']''' | |
store_data = store_data['aggsig'] | |
private_seed = store_data['expended_private_key']['private_key'] | |
public_key = store_data['public_key']['bytes_str'] | |
private_key_seed_hex = private_seed.zfill(64) | |
private_key_seed_hex = '48ab347b2846f96b7bcd00bf985c52b83b92415c5c914bc1f3b09e186cf2b14f' | |
print("private key hex : ", private_key_seed_hex, len(private_key_seed_hex)) | |
private_key_seed_int = int(private_key_seed_hex, 16) | |
private_key_seed_bytes = private_key_seed_int.to_bytes(32, 'big') | |
print("private key rehex: ", private_key_seed_bytes.hex()) | |
print("private key byte array: ", [i for i in private_key_seed_bytes]) | |
print("private key bytes: ", private_key_seed_bytes, len(private_key_seed_bytes)) | |
msg_hash = hash.sha512(private_key_seed_bytes) | |
lower_32_bytes_hash = msg_hash[-32:] | |
print(int.from_bytes(lower_32_bytes_hash, 'big')) | |
#private_key_seed_bytes = private_key_seed_bytes[::-1] | |
private_key = Keypair.from_raw_ed25519_seed(private_key_seed_bytes) | |
print("public key derived from private:", private_key.raw_public_key().hex()) | |
print("public key from store file :", public_key) | |
# Todo sign with tss | |
sign_dict = eddsa_signer(msg.hex()) | |
print(sign_dict) | |
#signature = format_signature_from_r_s(sign_dict[1], sign_dict[3]) | |
signature = generate_sig_from_rs(sign_dict[1], sign_dict[3]) | |
print(signature.hex()) | |
# todo verify with keypair | |
try: | |
private_key.verify(msg, signature) | |
except: | |
print("Failed to verify the EDDSA signature") | |
signature = private_key.sign(msg) | |
private_key.verify(msg, signature) | |
print(signature.hex()) | |
return | |
def test3(): | |
msg = b"hi" | |
path = '' | |
# Todo sign with tss | |
sign_dict = eddsa_signer(msg.hex()) | |
public_key_hex = sign_dict['y']['point'] | |
public_key_bytes = bytes.fromhex(public_key_hex) | |
public_key = Keypair.from_raw_ed25519_public_key(public_key_bytes) | |
print("public key: ", public_key) | |
signature = generate_sig_from_rs(sign_dict["r"], sign_dict["s"]) | |
print(signature.hex()) | |
# todo verify with keypair | |
try: | |
public_key.verify(msg, signature) | |
print("VERIFIED SUCCESSFULLY") | |
except: | |
print("Failed to verify the EDDSA signature") | |
return | |
def test_with_fixed_literals(): | |
private_key_seed_hex = '48ab347b2846f96b7bcd00bf985c52b83b92415c5c914bc1f3b09e186cf2b14f' | |
corresponding_public_key_hex = 'c7d17a93f129527bf7ca413f34a0f23c8462a9c3a3edd4f04550a43cdd60b27a' | |
private_key = create_stellar_keypair_from_seed_hex(private_key_seed_hex) | |
public_key = create_stellar_pubkey_from_hex(corresponding_public_key_hex) | |
print("public key derived from private:", private_key.raw_public_key().hex()) | |
print("public key from store file :", public_key.__bytes__().hex()) | |
print(private_key.signing_key.__bytes__().hex()) | |
msg = b'hi' | |
sig = private_key.sign(msg) | |
public_key.verify(msg, sig) | |
def test_stellar(): | |
path = '9/5/4' | |
xy_dict = read_xy_from_tss_pubkey(path) | |
bob_public_key = create_stellar_public_keypair_from_xy(xy_dict['x'], xy_dict['y']) | |
print(bob_public_key.raw_public_key().hex()) | |
bob_address = bob_public_key.public_key | |
print("Bob's address: ", bob_address) | |
# Create account if not exists: | |
requests.request("GET", "https://friendbot.stellar.org/?addr=" + bob_address) | |
alice_keypair = Keypair.from_secret("SBFZCHU5645DOKRWYBXVOXY2ELGJKFRX6VGGPRYUWHQ7PMXXJNDZFMKD") | |
alice_address = alice_keypair.public_key | |
print("Alice's address: ", alice_address) | |
server = Server("https://horizon-testnet.stellar.org") | |
alice_account = server.load_account(alice_address) | |
bob_account = server.load_account(bob_address) | |
print("Bob's balance: ", bob_account.raw_data['balances']) | |
# exit() | |
base_fee = 100 | |
transaction = ( | |
TransactionBuilder( | |
source_account=bob_account, | |
network_passphrase=Network.TESTNET_NETWORK_PASSPHRASE, | |
base_fee=base_fee, | |
) | |
.add_text_memo("Hello, Stellar!") | |
.append_payment_op(alice_address, Asset.native(), "10.25") | |
.set_timeout(30) | |
.build() | |
) | |
tx_hash = transaction.hash() | |
print("Transaction hash(hex): ", tx_hash.hex()) | |
# perform sign using tss | |
sign_dict = tss_signer(tx_hash.hex(), path) | |
assert sign_dict['x'] == xy_dict['x'] | |
assert sign_dict['y'] == xy_dict['y'] | |
raw_signed = generate_sig_from_rs(sign_dict["r"], sign_dict["s"]) | |
bob_public_key.verify(tx_hash, raw_signed) | |
print("Verified successfully") | |
hint = bob_public_key.signature_hint() | |
print(hint) | |
sig = DecoratedSignature(hint, raw_signed) | |
# transaction.signatures.pop() # Remove the signature generated by stellar_sdk | |
transaction.signatures.append(sig) | |
response = server.submit_transaction(transaction) | |
print(response) | |
if __name__ == "__main__": | |
test_stellar() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment