Skip to content

Instantly share code, notes, and snippets.

@HRezaei
Created February 11, 2022 03:57
Show Gist options
  • Save HRezaei/156f9fa347d666e67f01264c65671cad to your computer and use it in GitHub Desktop.
Save HRezaei/156f9fa347d666e67f01264c65671cad to your computer and use it in GitHub Desktop.
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
# 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