I'm trying to split a private key into shares using tinysig but am having difficulty. I.e. I'm trying to create an MPC wallet.

Ultimately I want to generate a private key, split it into two shares, A and B. Then, to sign a transaction, I first sign with the A share, and secondly, with the B share. When these two signatures are combined, the resulting signature should be exactly the same as if I had signed the transaction with the whole private key. If I understand correctly, this is how MPC wallets work; the private key is never used for transactions, except when being split into shares.

I'm following the tinysig demo here. In the __init__ of the ThresholdSignature class, a private and public key pair are generated using the paillier library:

ecdsa_setup = ECDSASetup(curve="P-256")
ecnil = ThresholdSignature(N, C, setup=ecdsa_setup)

digging deeper into the paillier library shows that the default key size when generating keys is 3072.

If I try to find out the client's private key in the ecnil object, I see something like this:

>>> ecnil.clients[0].he_private_key.p
>>> ecnil.clients[0].he_private_key.q

If i try to convert that to an address using web3, it doesn't work because the size of the int is not correct:

from web3 import Web3
from eth_account import Account
web3 = Web3()
acct = Account.from_key(web3.toHex(2284723268498922442467539110301303113041396131923481892914304164561860516362704406582357150386060442220415604374817669817782608284218360611971475754798359898054270836755192466701829211135957771688507906420521463101430090812282615974325344598670919411450138371876632456288671211630413157360230608646088568665029609192353084475386230592428901701657079883001218882863749314535183212389843720395778273220367267835720610100215510411774932266742652445986156432050732757))

ValueError: The private key must be exactly 32 bytes long, instead of 386 bytes.

So, if I modify the src file tecdsa.py of tinysig to generate a private key of the correct length (this line)

pub_key, priv_key = paillier.generate_paillier_keypair(n_length=512)

Then the he_private_key.q and he_private_key.p integers are the correct size to generate a valid ethereum wallet address, but I get an OverFlow error later in the process:

from tinysig.setup import DSASetup, ECDSASetup
from tinysig.tecdsa import ThresholdSignature
ecdsa_setup = ECDSASetup(curve="P-256")
ecnil = ThresholdSignature(N, C, setup=ecdsa_setup)
client_id = 1
message = 'hello world'
ecnil.ts_online_protocol(message, client_id)

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "tinysig/tecdsa.py", line 794, in ts_online_protocol
    self.decrypt_reconstruct_unmask_verify_sig_local(message, label_enc_sig, client)
  File "tinysig/tecdsa.py", line 738, in decrypt_reconstruct_unmask_verify_sig_local
    dec_sh_per_node = [client.he_private_key.decrypt(enc_sh) for enc_sh in enc_sh_per_node]
  File "tinysig/tecdsa.py", line 738, in <listcomp>
    dec_sh_per_node = [client.he_private_key.decrypt(enc_sh) for enc_sh in enc_sh_per_node]
  File "phe/paillier.py", line 291, in decrypt
    return encoded.decode()
  File "phe/encoding.py", line 221, in decode
    raise OverflowError('Overflow detected in decrypted number')
OverflowError: Overflow detected in decrypted number

Any idea how I can use tinysig to a) generate a valid ethereum private key and b) split that key into shares which can be used in combination to sign transactions?


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.