Skip to content

Commit

Permalink
Add key rotation tutorial up until failed proof
Browse files Browse the repository at this point in the history
  • Loading branch information
alnoki committed Jan 29, 2023
1 parent 37b6047 commit b50b870
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 7 deletions.
50 changes: 48 additions & 2 deletions developer-docs-site/docs/tutorials/first-multisig.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ Run the [`multisig.py`](../../../ecosystem/python/sdk/examples/multisig.py) exam
python multisig.py
```

## Step 3: Generate signers
## Step 3: Generate single signer accounts

First, we will generate single signer accounts for Alice, Bob, and Chad:

Expand Down Expand Up @@ -148,4 +148,50 @@ Multisig balance: 39945700
```
Note that even though Alice and Bob signed the transaction, their account balances have not changed.
Chad, however, has received 100 octas from the multisig account, which assumed the gas costs of the transaction and thus has had more than 100 octas deducted.
Chad, however, has received 100 octas from the multisig account, which assumed the gas costs of the transaction and thus has had more than 100 octas deducted.
## Step 7: Create a vanity address multisig
In this section, a fourth user named Deedee will generate a vanity address, then rotate her account to the two-of-three multisig.
### Step 7.1 Generate a vanity address
A fourth user, Deedee, wants her account address to start with `0xdd..`, so she generates random accounts until she finds one with a matching account address:
```python
:!: static/sdks/python/examples/multisig.py section_7
```
```zsh
=== Funding vanity address ===
Deedee's address: 0xdd063617b654750fa97ae2bc82f85efe79770d08029aa9aa8f8c4f4f1271e05e
Deedee's public key: 0xca8b97f8efc2b0be7a241479802cfd39b70969da1fcfacb08aabd79fa0fb6d73
Deedee's balance: 50000000
```

### Step 7.2 Sign a rotation proof challenge

Deedee and the two-of-three multisig must both sign a `RotationProofChallenge`, yielding two signatures.
Deedee's signature, `cap_rotate_key`, verifies that she approves of the authentication key rotation.
The multisig signature, `cap_update_table`, verifies that the multisig approves of the authentication key rotation.
Here, Bob and Chad provide individual signatures for the multisig:
```python
:!: static/sdks/python/examples/multisig.py section_8
```
```zsh
=== Signing rotation proof challenge ===
cap_rotate_key: 0x61ad912862c3647c9bb1f10d88494f7b157eeccc685e1cb45c338c3b9ea2d1c3a9e0473378f1e1d340b66eea352c961901ef6c5eaf25b7ba439cfa1e32014b03
cap_update_table: 0xcb49863bbc000a1c62f780115843b7b7c06661525d9195c3b3518aebd9541d73e48e298ef877c114314e91cc1b9001c01ab0bcbf889119350274a3cd447cf40bdade8af39ed873c913ddcd3de4c8a7aa453278664c374190936e7d974a021408c32b53f07c0d21b74cad2b429b3b48285c61be40d636feb6e0d10f4b695cb00360000000
```
### Step 7.3 Rotate the authentication key
```python
:!: static/sdks/python/examples/multisig.py section_9
```
:::warning
Move abort in 0x1::account: EINVALID_PROOF_OF_KNOWLEDGE(0x10008): Specified proof of knowledge required to prove ownership of a public key is invalid
:::
85 changes: 80 additions & 5 deletions ecosystem/python/sdk/examples/multisig.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@

from common import NODE_URL, FAUCET_URL

wait_for_user = True
wait_for_user = False

if __name__ == '__main__':

rest_client = RestClient(NODE_URL)
faucet_client = FaucetClient(FAUCET_URL, rest_client)

# :!:>section_1
alice = Account.generate()
bob = Account.generate()
Expand Down Expand Up @@ -57,9 +60,6 @@
if wait_for_user: input("\nPress Enter to continue...")

# :!:>section_3
rest_client = RestClient(NODE_URL)
faucet_client = FaucetClient(FAUCET_URL, rest_client)

print("\n=== Funding accounts ===")
alice_start = 10_000_000
bob_start = 20_000_000
Expand Down Expand Up @@ -113,11 +113,15 @@
# :!:>section_5
signatures_map = [(alice.public_key(), alice_signature),
(bob.public_key(), bob_signature)]

multisig_signature = MultiEd25519Signature(multisig_public_key,
signatures_map)

authenticator = Authenticator(MultiEd25519Authenticator(
multisig_public_key, multisig_signature))

signed_transaction = SignedTransaction(raw_transaction, authenticator)

print("\n=== Submitting transaction ===")
tx_hash = rest_client.submit_bcs_transaction(signed_transaction)
print(f"Transaction hash: {tx_hash}") # <:!:section_5
Expand All @@ -136,4 +140,75 @@
chad_balance = rest_client.account_balance(chad.address())
print(f"Chad's balance: {chad_balance}")
multisig_balance = rest_client.account_balance(multisig_address)
print(f"Multisig balance: {multisig_balance}") # <:!:section_6
print(f"Multisig balance: {multisig_balance}") # <:!:section_6

if wait_for_user: input("\nPress Enter to continue...")

# :!:>section_7
print("\n=== Funding vanity address ===")

deedee = Account.generate()
while (deedee.address().hex()[2:4] != 'dd'):
deedee = Account.generate()
print(f"Deedee's address: {deedee.address()}")
print(f"Deedee's public key: {deedee.public_key()}")

deedee_start = 50_000_000
faucet_client.fund_account(deedee.address(), deedee_start)
deedee_balance = rest_client.account_balance(deedee.address())
print(f"Deedee's balance: {deedee_balance}") # <:!:section_7

if wait_for_user: input("\nPress Enter to continue...")

# :!:>section_8
print("\n=== Signing rotation proof challenge ===")

sequence_number = int(0).to_bytes(8, 'big') # 8 bytes, big endian.
originator = deedee.address().address
current_auth_key = originator
new_public_key = multisig_public_key.to_bytes()

rotation_proof_challenge = \
sequence_number + originator + current_auth_key + new_public_key

cap_rotate_key = deedee.sign(rotation_proof_challenge).data()

cap_update_table = MultiEd25519Signature(
multisig_public_key,
[(bob.public_key(), bob.sign(rotation_proof_challenge)),
(chad.public_key(), chad.sign(rotation_proof_challenge))]
).to_bytes()

cap_rotate_key_hex = f"0x{cap_rotate_key.hex()}"
cap_update_table_hex = f"0x{cap_update_table.hex()}"
print(f"cap_rotate_key: {cap_rotate_key_hex}")
print(f"cap_update_table: {cap_update_table_hex}") # <:!:section_8

if wait_for_user: input("\nPress Enter to continue...")

# :!:>section_9
print("\n=== Rotating authentication key ===")

from_scheme = Authenticator.ED25519
from_public_key_bytes = deedee.public_key().key.encode()
to_scheme = Authenticator.MULTI_ED25519
to_public_key_bytes = multisig_public_key.to_bytes()

entry_function = EntryFunction.natural(
module="0x1::account",
function="rotate_authentication_key",
ty_args=[],
args=[TransactionArgument(from_scheme, Serializer.u8),
TransactionArgument(from_public_key_bytes,
Serializer.to_bytes),
TransactionArgument(to_scheme, Serializer.u8),
TransactionArgument(to_public_key_bytes, Serializer.to_bytes),
TransactionArgument(cap_rotate_key, Serializer.to_bytes),
TransactionArgument(cap_update_table, Serializer.to_bytes)])

signed_transaction = rest_client.create_bcs_signed_transaction(
deedee, TransactionPayload(entry_function))

tx = rest_client.submit_bcs_transaction(signed_transaction)

print(f"https://explorer.aptoslabs.com/txn/{tx}") # <:!:section_9

0 comments on commit b50b870

Please sign in to comment.