Created
February 11, 2022 03:55
-
-
Save HRezaei/fd82a4701fe115fd356f31679c516b10 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
import binascii | |
import json | |
import os | |
import subprocess | |
from time import sleep | |
import ed25519 | |
from ecpy.curves import Curve | |
from solana.publickey import PublicKey | |
from solana.rpc.api import Client | |
from solana.transaction import Transaction, SigPubkeyPair | |
import solana.system_program as sp | |
from eth_utils import int_to_big_endian | |
from nacl import signing # type: ignore | |
TSS_EXECUTABLE = "/tss-ecdsa-cli/target/debug/tss_cli" | |
TSS_KEYS_FILE = "/tmp/ed1.store" | |
cv25519 = Curve.get_curve("Ed25519") | |
debug = {} | |
ed25519.SigningKey | |
def encodepoint(P): | |
x = P[0] | |
y = P[1] | |
# MSB of output equals x.b0 (=x&1) | |
# rest of output is little-endian y | |
assert 0 <= y < (1 << 255) # always < 0x7fff..ff | |
if x & 1: | |
y += 1 << 255 | |
return binascii.unhexlify("%064x" % y)[::-1] | |
def create_point(x, y): | |
class myp: pass | |
mypoint = myp() | |
mypoint.x = x # 0x161474b35b82c2917bc483ac0516a2dbd1a85c8b582ec28f394bc49c0052e86d | |
mypoint.y = y | |
return cv25519.encode_point(mypoint) | |
def pad32(value: bytes) -> bytes: | |
return value.rjust(32, b'\x00') | |
def to_bytes(r, s) -> bytes: | |
rb = pad32(int_to_big_endian(r)) | |
sb = pad32(int_to_big_endian(s)) | |
return b''.join((rb, sb)) | |
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/ed" + 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 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 test_nacl_sigining(): | |
path = '1/2' | |
msg = b"hi" | |
cmd = f'{TSS_EXECUTABLE} pubkey {TSS_KEYS_FILE} -p {path} -ceddsa' | |
debug['cmd'] = cmd | |
output = subprocess.check_output(cmd.split(' ')) | |
debug['tss output'] = output | |
xy_dict = json.loads(output) | |
debug['x'] = xy_dict['x'] | |
debug['y'] = xy_dict['y'] | |
x = int(xy_dict['x'], 16) | |
y = int(xy_dict['y'], 16) | |
address_bytes = create_point(x, y) | |
debug['address_bytes'] = address_bytes | |
sender_public_key = PublicKey(address_bytes) | |
debug['sender public key'] = sender_public_key | |
verify_key = signing.VerifyKey(address_bytes) | |
debug['verify_key'] = verify_key | |
sign_dict = tss_signer(msg.hex(), path) | |
raw_signed = generate_sig_from_rs(sign_dict["r"], sign_dict["s"]) | |
assert verify_key.verify(msg, raw_signed) | |
return | |
def test_solana_tss(): | |
path = '1/2' | |
msg = "hi" | |
cmd = f'{TSS_EXECUTABLE} pubkey {TSS_KEYS_FILE} -p {path} -ceddsa' | |
debug['cmd'] = cmd | |
output = subprocess.check_output(cmd.split(' ')) | |
debug['tss output'] = output | |
xy_dict = json.loads(output) | |
debug['x'] = xy_dict['x'] | |
debug['y'] = xy_dict['y'] | |
x = int(xy_dict['x'], 16) | |
y = int(xy_dict['y'], 16) | |
address_bytes = create_point(x, y) | |
debug['address_bytes'] = address_bytes | |
sender_public_key = PublicKey(address_bytes) | |
debug['sender public key'] = sender_public_key | |
verify_key = signing.VerifyKey(address_bytes) | |
debug['verify_key'] = verify_key | |
debug['on_curve'] = PublicKey._is_on_curve(bytes(sender_public_key)) | |
debug['pub_key'] = sender_public_key.to_base58().hex() | |
# This is mainnet I think: | |
# url = 'https://solana-api.projectserum.com' | |
# This one is testnet | |
url = "https://api.devnet.solana.com" | |
cli = Client(url) | |
account_info = cli.get_account_info(sender_public_key) | |
debug['sender account info'] = account_info | |
#pub_key_for_program_id = PublicKey('CJsLwbP1iu5DuUikHEJnLfANgKy6stB2uFgvBBHoyxwz') | |
receiver_public_key = PublicKey('C8cZHbugbX6gQVrxqLGAgiumKh85khhM5cXXeB1rsGMc') | |
recent_blockhash = cli.get_recent_blockhash()['result']['value']['blockhash'] | |
transaction = Transaction(recent_blockhash=recent_blockhash) | |
transaction.add(sp.transfer(sp.TransferParams( | |
from_pubkey=sender_public_key, | |
to_pubkey=receiver_public_key, | |
lamports=cli.get_minimum_balance_for_rent_exemption(88).get('result'), | |
))) | |
transaction.fee_payer = sender_public_key | |
transaction_data_to_sign = transaction.serialize_message() | |
sign_dict = tss_signer(transaction_data_to_sign.hex(), path) | |
signature = generate_sig_from_rs(sign_dict['r'], sign_dict['s']) | |
transaction.signatures = [SigPubkeyPair(sender_public_key)] | |
transaction.signatures[0].signature = signature | |
signed_hash = transaction.serialize() | |
debug['signed_with_lib'] = signed_hash | |
try: | |
debug['send_tx'] = cli.send_raw_transaction(signed_hash) | |
except Exception as e: | |
debug['error'] = e | |
#test_nacl_sigining() | |
test_solana_tss() | |
print(debug) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment