-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add --verify-committee-file command (#24)
* Add --verify-committee-file command * Fix linting * Update * Update * Add public keys creation, verification commands * Update message for create shard pubkeys Co-authored-by: Dmitri Tsumak <[email protected]>
- Loading branch information
Showing
34 changed files
with
321 additions
and
85 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,3 +9,4 @@ local.env | |
*.spec | ||
validator_keys/ | ||
committee/ | ||
keys/ |
This file was deleted.
Oops, something went wrong.
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
[tool.poetry] | ||
name = "operator-cli" | ||
name = "stakewise-cli" | ||
version = "1.0.0" | ||
description = "StakeWise Operator CLI is used to generate and manage ETH2 validator keys." | ||
authors = ["Dmitri Tsumak <[email protected]>"] | ||
|
File renamed without changes.
File renamed without changes.
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
import click | ||
from Crypto.Cipher import AES, PKCS1_OAEP | ||
from Crypto.PublicKey import RSA | ||
from py_ecc.bls import G2ProofOfPossession | ||
from web3 import Web3 | ||
|
||
from stakewise_cli.ipfs import upload_public_keys_to_ipfs | ||
|
||
|
||
def validate_private_key(ctx, param, value) -> str: | ||
try: | ||
with open(value, "r") as f: | ||
RSA.import_key(f.read()) | ||
|
||
return value | ||
except: # noqa: E722 | ||
pass | ||
|
||
raise click.BadParameter("Invalid Private Key") | ||
|
||
|
||
@click.command(help="Creates public keys for operator shard") | ||
@click.option( | ||
"--private-key", | ||
help="Path to the committee member private key file.", | ||
prompt="Enter path to the committee member private key", | ||
type=click.Path(exists=True, file_okay=True, dir_okay=False), | ||
callback=validate_private_key, | ||
) | ||
@click.option( | ||
"--shard", | ||
help="Path to the operator shard file.", | ||
prompt="Enter path to operator shard file", | ||
type=click.Path(exists=True, file_okay=True, dir_okay=False), | ||
) | ||
def create_shard_pubkeys(shard: str, private_key: str) -> None: | ||
try: | ||
with open(private_key, "r") as f: | ||
private_key = RSA.import_key(f.read()) | ||
with open(shard, "rb") as f: | ||
enc_session_key, nonce, tag, ciphertext = [ | ||
f.read(x) for x in (private_key.size_in_bytes(), 16, 16, -1) | ||
] | ||
except: # noqa: E722 | ||
raise click.ClickException("Invalid operator shard file") | ||
|
||
# Decrypt the session key with the private RSA key | ||
try: | ||
cipher_rsa = PKCS1_OAEP.new(private_key) | ||
session_key = cipher_rsa.decrypt(enc_session_key) | ||
except: # noqa: E722 | ||
raise click.ClickException( | ||
"Failed to decrypt the session key. Please check whether the paths to private key and shard" | ||
) | ||
|
||
# Decrypt the data with the AES session key | ||
cipher_aes = AES.new(session_key, AES.MODE_EAX, nonce) | ||
try: | ||
private_keys = cipher_aes.decrypt_and_verify(ciphertext, tag).split(b",") | ||
except: # noqa: E722 | ||
raise click.ClickException("Failed to decrypt the shard file. Is it corrupted?") | ||
|
||
public_keys = [] | ||
with click.progressbar( | ||
private_keys, | ||
label="Deriving public keys for operator shard\t\t", | ||
show_percent=False, | ||
show_pos=True, | ||
) as _private_keys: | ||
for priv_key in _private_keys: | ||
public_keys.append(Web3.toHex(G2ProofOfPossession.SkToPk(int(priv_key)))) | ||
|
||
ipfs_hash = upload_public_keys_to_ipfs(public_keys) | ||
click.echo( | ||
f'Please share the IPFS hash in "operators" Discord chat:' | ||
f" {click.style(ipfs_hash, fg='green')}", | ||
) |
This file contains 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
This file contains 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
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
import click | ||
from eth_typing import BLSPubkey | ||
from web3 import Web3 | ||
|
||
from stakewise_cli.committee_shares import reconstruct_shared_bls_public_key | ||
from stakewise_cli.ipfs import ipfs_fetch | ||
|
||
|
||
@click.command(help="Verifies public keys for operator shards") | ||
@click.option( | ||
"--deposit-data-ipfs-hash", | ||
help="IPFS hash for operator deposit data to verify.", | ||
prompt="Enter IPFS hash for operator deposit data to verify", | ||
) | ||
@click.option( | ||
"--shards-count", | ||
help="Total number of shards to verify. With 5 committee members, the number must be at least 3.", | ||
prompt="Enter total number of shards to verify", | ||
type=int, | ||
) | ||
def verify_shard_pubkeys(deposit_data_ipfs_hash: str, shards_count: int) -> None: | ||
submitted = 0 | ||
shards = {} | ||
while True: | ||
if submitted == shards_count: | ||
break | ||
|
||
index = click.prompt( | ||
text=( | ||
"Enter committee member position number " | ||
"(index in stakewise.eth ENS record)" | ||
), | ||
type=click.INT, | ||
) | ||
if index in shards: | ||
click.echo("The IPFS hash for such index was already submitted") | ||
continue | ||
|
||
public_keys_ipfs_hash = click.prompt( | ||
text=( | ||
f"Enter the shard public keys IPFS hash for {index} committee member" | ||
f" ({submitted + 1}/{shards_count})" | ||
), | ||
type=click.STRING, | ||
).strip() | ||
|
||
try: | ||
pub_keys = ipfs_fetch(public_keys_ipfs_hash) | ||
shards[index] = [Web3.toBytes(hexstr=k) for k in pub_keys] | ||
except: # noqa: E722 | ||
click.secho( | ||
f"Failed to fetch IPFS data at {public_keys_ipfs_hash}. Please try again.", | ||
fg="red", | ||
) | ||
continue | ||
|
||
submitted += 1 | ||
|
||
try: | ||
deposit_data = ipfs_fetch(deposit_data_ipfs_hash) | ||
deposit_data_pub_keys = [ | ||
Web3.toBytes(hexstr=d["public_key"]) for d in deposit_data | ||
] | ||
except: # noqa: E722 | ||
raise click.ClickException( | ||
f"Failed to fetch IPFS data at {deposit_data_ipfs_hash}. Please try again." | ||
) | ||
|
||
with click.progressbar( | ||
enumerate(deposit_data_pub_keys), | ||
label="Reconstructing public keys from shards\t\t", | ||
show_percent=False, | ||
show_pos=True, | ||
) as _deposit_data_pub_keys: | ||
for i, pub_key in _deposit_data_pub_keys: | ||
pub_key_shards = {} | ||
for committee_index in shards: | ||
pub_key_shards[committee_index] = BLSPubkey(shards[committee_index][i]) | ||
|
||
reconstructed_pub_key = reconstruct_shared_bls_public_key(pub_key_shards) | ||
if reconstructed_pub_key != pub_key: | ||
raise click.ClickException( | ||
f"Failed to reconstruct public key with index {i}" | ||
) | ||
|
||
click.secho("Successfully verified operator shards", fg="green") |
This file contains 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
This file contains 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
Oops, something went wrong.