An arduino cold ethereum wallet implementing Shamir Secret Sharing (SSS), intended for use on a Gnosis safe. This project basically glues various libraries together resulting in a do-it-yourself Arduino cold wallet that splits the private key using SSS. One out of the three SSS shares (the zero-index share) is continuously stored on EEPROM until a new wallet is created, and the private key is only written to EEPROM after wallet creation and private key recovery. After splitting and transaction hash signing, the private key is overwritten in EEPROM. By default, at least 2/3 shares are required to recover the private key
- A new cold wallet is created with
create_wallet_mode.ino
- A Gnosis safe contract is created with a "hot" Metamask-generated wallet and the "cold" Arduino wallet as owners, where confirmations from both wallets are required to execute transactions. Native or non-native tokens are sent to the safe contract for storage
- The private key is split into three SSS shares with
shamir_split_key_mode.ino
. The user saves the "primary" share and the "backup" share. There is by default a two share minimum required to recover the secret. - If tokens need to be sent out of the contract, the private key is recovered with
shamir_recover_key_mode.ino
by passing the "primary" SSS share via Serial communication. This writes the private key "above" the zeroth SSS share in EEPROM. - The intended transaction hash is generated by either calling
getTransactionHash
on the safe contract or by using the helper scripttransact.py
to get a hash of the transaction. To run the helper script,streamlit
is required. It can be used by doingpython3.8 -m streamlit run transact.py --server.headless true
. Using the helper script makes the process much easier sign_signature_mode.ino
is loaded onto the Arduino and the transaction hash is passed to it via Serial. The Arduino reveals the signed transaction hash.- Now the goal is to call
execTransaction
on the safe contract with the "hot" Metamask wallet, providing the signature from the "cold" wallet. This can be accomplished by:- Going to the safe contract's page on the appropriate blockchain explorer website (e.g. etherscan, etc) and connecting the hot Metamask wallet OR
- Submitting a regular send transaction to the safe contract with a value of zero and passing unique Hex data to call
execTransaction
- Again, the helper script
transact.py
makes both of these options much easier, as additional data is added around the transaction hash signature that is required forexecTransaction
.
https://github.com/BlockchainCommons/bc-crypto-base
https://github.com/BlockchainCommons/bc-shamir
https://github.com/firefly/wallet/tree/master/source/libs/ethers
https://github.com/gonzalobellino/ephemeralwallet/tree/master/arduino/libraries/entropy
https://pypi.org/project/streamlit/
Due to memory limitations, the "cold" wallet part of this project has four Arduino sketch files, which put the microcontroller in a particular "mode". The four modes are:
- Private key generation: create_wallet_mode.ino
The public wallet address is displayed. The private key is written to EEPROM. The private key can be displayed by uncommenting in the sketch, in case a separate encrypted backup is needed.
- Private key splitting into three Shamir Secret Sharing (SSS) shares: shamir_split_key_mode.ino
The SSS share with index zero is written to EEPROM, overwriting the private key. The zero-index key isn't revealed to the user, and is always sitting in EEPROM for subsequent modes (until a new wallet is generated). The two remaining SSS shares are shown the user. One is the "primary" share, and one is a "backup". The cold wallet would be in this mode most of the time, only being called for private key recovery and transaction hash signing.
- Private key recovery: shamir_recover_key_mode.ino
The user provides the primary SSS share, (e.g.
<237b...f9fe>
) and the private key is recovered and written to EEPROM. To use the backup share instead, line 179 would be changed touint8_t recovery_share_indexes[2] = {0,2};
- Transaction hash signing: sign_signature_mode.ino
The user provides a transaction hash to be signed (e.g.
<3327...ac9fe>
). Once the hash is signed the signature is displayed and the private key is cleared from EEPROM.
The cold wallet transaction hash signature needs to have 1b
or 1c
appended to the end, and I haven't figured out when to use which, so the helper script reports both. If the signature with 1b
doesn't work, try the one with 1c
.
The sketches and helper script come with no guarantees. I made this to help me understand how Gnosis safes and SSS and cold wallets work.
Add a pin number to encode SSS shares and temporary private key writing.
Figure out when to use 1b
or 1c
at the end of transactin hash signatures