Aptos Key Swap | Move dApp Quick Entry

Ashley is a blockchain security researcher with passion for exploring new challenges and staying up-to-date with the latest technological advancements. In addition, she is also a Solidity and Move developer with experience in building DeFi protocols and conducting vulnerability mining.

Twitter: https://twitter.com/ashleyhsu_eth

在本文中,我們將深入探討 Aptos 密鑰輪換的概念及其重要性。在開始之前,讓我們先了解什麼是 Aptos 帳戶、公鑰和私鑰的作用。當私鑰洩漏時,你的帳戶就可能遭到攻擊,但若想保留原有帳戶並確保資產安全,就需要使用密鑰輪換技術。Aptos 帳戶支持密鑰輪換,讓你更改私鑰而不必創建新帳戶,繼而保留原有帳戶的資產和身份。接下來,我們將介紹如何使用 Aptos cli 及 Python SDK 完成密鑰輪換,讓你能夠隨時保持帳戶資產及身份的安全。

0x01 什麼是帳戶(account)?

每個 Aptos 帳戶代表著區塊鏈上一個可以發送交易的實體,並由特定的 32 字節帳戶地址識別。這個帳戶是 Move 模組和 Move 資源的容器,可以包含區塊鏈資產(例如 coin 和 NFT)。這些資產在區塊鏈帳戶中表示為資源,同時帳戶也可以執行各種操作,例如將資源發送給其他人。就像在 Web2 的世界中,你的電子郵件地址代表著你的電子郵件帳戶,而在 Aptos 區塊鏈中,帳戶地址代表著帳戶本身,你可以透過這個地址進行收發資產等操作。

1.1 公鑰(public key)、私鑰(private key)

私鑰在 Aptos 區塊鏈與其他區塊鏈一樣,可以用來簽署交易以使其被認可和驗證,就像在現實生活中需要簽名或輸入密碼才能夠轉帳。簽署過後的交易才能夠對你的帳戶資產進行更改,但是只有擁有私鑰的人才能夠簽署這筆交易,因此私鑰是非常重要且敏感的一組數據。

在其他區塊鏈上,你的公開身份即為私鑰對應的公鑰,地址可以從公鑰被推算出來,公鑰也被用來驗證簽章。然而,Aptos 支援密鑰輪換,導致公鑰可能會發生變化,因此使用地址來代表帳戶。傳統上,每個帳戶都有一個特定的地址作為其識別符號,而且這個地址是不會改變的。在 Aptos 中,即使您更改了身份驗證密鑰(其中包含公鑰),帳戶地址仍然是唯一的,並且不會發生變化。

1.2 身份驗證密鑰(authentication key)

Aptos 區塊鏈支援單簽和多簽帳戶。多簽帳戶允許多個用戶共同執行數位簽章來管理帳戶資產。例如,想像一個擁有兩把鎖和兩把鑰匙的保險箱,一把鑰匙由 Alice 持有,另一把則由 Bob 掌管。打開此保險箱的唯一辦法就是兩個人同時提供鑰匙開鎖,只有其中一把鑰匙時則無法打開。多簽帳戶與此類似,它是代表多方的單一帳戶,所有發生的交易都需要所有參與方的簽名,也可以被設定一個閾值,舉個例子,2-of-3 代表三位中只要有兩個簽署即可完成交易。

多簽帳戶使用多個(私鑰,公鑰)密鑰對,沒有單個公鑰會代表這個帳戶。因此,我們需要一個代表此帳戶的密鑰,以便封裝多簽帳戶中所有用戶的公鑰,這個代表此帳戶的密鑰也就是所謂的身份驗證密鑰。

身份驗證密鑰是表示多簽帳戶中所有用戶的一種方式。簡而言之,身份驗證密鑰是通過連接所有參與用戶的公鑰的串聯散列創建的。

auth_key = sha3-256(pubkey_1 | . . . | pubkey_n | K | 0x01)

其中K是驗證交易所需的簽名閾值,0x01為 1-byte 多簽方案標識符。

對於單簽帳戶,也存在身份驗證密鑰,單簽帳戶的身份驗證密鑰只封裝了一個公鑰來代表帳戶,這樣做是為了在所有類型的帳戶上保持一致性。

auth_key = sha3-256(pubkey_A | 0x00)

其中 0x00 為 1-byte 單簽方案標識符。

我們可以說,身份驗證密鑰是私鑰的廣義公共表示。

1.3 帳戶地址

在帳戶創建過程中,產生一組公鑰及私鑰後,會計算出一個 32 字節的身份驗證密鑰,這個身份驗證密鑰將作為帳戶地址。

單簽帳戶:

auth_key = sha3-256(pubkey_A | 0x00)

其中 0x00 為 1-byte 單簽方案標識符。

多簽帳戶:

auth_key = sha3-256(pubkey_1 | . . . | pubkey_n | K | 0x01)

其中K是驗證交易所需的簽名閾值,0x01為 1-byte 多簽方案標識符。

但是,密鑰輪換後,身份驗證密鑰會發生變化,當生成新的公鑰-私鑰對時,公鑰將輪換密鑰。但帳戶地址不會改變。因此,僅在最初,32 字節身份驗證密鑰才會與 32 字節帳戶地址相同。帳戶與金鑰解耦的方法使 Aptos 能夠無縫新增新的數位簽名演算法以支援公鑰和私鑰型別。

帳戶創建後,儘管私鑰、公鑰和認證密鑰可能發生變化,但帳戶地址將保持不變The

0x02 為什麼我們需要密鑰輪換?

當私鑰洩漏時,你的帳戶就可能遭到攻擊。在 web2 中,多數人會定期修改密碼,減少被盜的風險,還有在 Instagram 或 Facebook 帳戶被盜後,你可以透過其他方式驗證身份,修改密碼並拿回自己的帳號。但是,在大多數區塊鏈中,情況並不那麼簡單。私鑰與公鑰成對出現,而鏈上身份與私鑰綁定,唯一的解決方法是創建一個新帳戶,使用新的公鑰和私鑰對並將所有資產轉移到該帳戶中。

然而,這種方法會造成很多問題,例如失去原有的帳戶資產、OG 身份的象徵、以及參與過的活動的紀念等。因此,密鑰輪換技術應運而生。Aptos 帳戶支援密鑰輪換,讓你更改私鑰而不必創建新帳戶,從而保留原有帳戶的資產和身份。這意味著你可以保持原有地址,其他人仍然可以使用你原本的地址向你發送資產。唯一會改變的是身份驗證密鑰,因為它是由公鑰計算出來的。

密鑰輪換技術實現了鏈上身份safety分離,當私鑰洩漏時,你可以替換掉私鑰,從而保護資產免於受到損失或竊取。此外,密鑰輪換也使得我們可以定期更改密鑰,減少私鑰被盜取的風險,同時也為使用多簽帳戶提供了更多彈性。

0x03 Authentication key rotation

密鑰輪換,在 Aptos 中準確來說稱為身份驗證密鑰輪換(Authentication key rotation)。

account.move 模塊包含了 Aptos 帳戶相關的所有函數。用戶可以透過 account::rotate_authentication_key 函數來達成密鑰輪換。

public entry fun rotate_authentication_key(
    account: &signer,
    from_scheme: u8,
    from_public_key_bytes: vector<u8>,
    to_scheme: u8,
    to_public_key_bytes: vector<u8>,
    cap_rotate_key: vector<u8>,
    cap_update_table: vector<u8>,
) acquires Account, OriginatingAddress {

    ...
}

為了授權輪換,我們需要兩個簽名:

  1. cap_rotate_key 是指帳戶目前擁有者對 RotationProofChallenge 的簽名,證明用戶打算並具有能力輪換此帳戶的身份驗證金鑰
  2. cap_update_table 是指所需輪換至的新金鑰(帳戶擁有者想要輪換的金鑰)對RotationProofChallenge 的簽名,證明用戶擁有新的私鑰,並有權更新 OriginatingAddress 映射與新地址映射 <new_address, originating_address>The

為了驗證這兩個簽名,我們需要它們對應的公鑰和公鑰方案:我們使用 from_scheme andfrom_public_key_bytes驗證cap_rotate_key,使用to_schemeandto_public_key_bytes驗證cap_update_tableThe

單簽為ED25519_SCHEME,多簽則為MULTI_ED25519_SCHEMEThe

3.1 使用 Aptos cli 達成單簽帳戶密鑰輪換

初始狀態,可以看到 account address 與 authentication key 相同。

產生密鑰:

aptos key generate --key-type ed25519 --output-file output.key
{
  "Result": {
    "PrivateKey Path": "output.key",
    "PublicKey Path": "output.key.pub"
  }
}

利用 aptos cli 做 key rotation,參數可以選擇直接填入私鑰或 key file:

aptos account rotate-key --new-private-key-file output.key
aptos account rotate-key --new-private-key 0xae249782eedbfafcc7da157542d1f97d97385cbda36338c806475a3ce127fd90

Do you want to submit a transaction for a range of [52100 - 78100] Octas at a gas unit price of 100 Octas? [yes/no] >
yes
{
  "transaction_hash": "0x75c412d82e038f87cec14c6c8b08c7fb08290118437e18433700c0e5d0262854",
  "gas_used": 521,
  "gas_unit_price": 100,
  "sender": "148f1f6f88d690a04451fa8a548f21129b537cf511cedaa66a6ad93abc83a607",
  "sequence_number": 0,
  "success": true,
  "timestamp_us": 1688636116823320,
  "version": 571106848,
  "vm_status": "Executed successfully"
}
Do you want to create a profile for the new key? [yes/no] >
yes
Enter the name for the profile
Update
Profile Update is saved.
{
  "Result": {
    "message": "Profile Update is saved.",
    "transaction": {
      "transaction_hash": "0x75c412d82e038f87cec14c6c8b08c7fb08290118437e18433700c0e5d0262854",
      "gas_used": 521,
      "gas_unit_price": 100,
      "sender": "148f1f6f88d690a04451fa8a548f21129b537cf511cedaa66a6ad93abc83a607",
      "sequence_number": 0,
      "success": true,
      "timestamp_us": 1688636116823320,
      "version": 571106848,
      "vm_status": "Executed successfully"
    }
  }
}

回到 Aptos explorer 查看,authentication key 已改變,account address 維持相同。

aptos cli 也可以透過 public key 來反查出帳戶地址:


aptos account lookup-address --public-key-file output.key.pub
{
  "Result": "148f1f6f88d690a04451fa8a548f21129b537cf511cedaa66a6ad93abc83a607"
}

3.2 使用 Python SDK 將單簽帳戶輪換為多簽帳戶

以 aptos-core 中 python sdk 的 multisig 範例作為參考,可以根據自己的使用情境進行修改。

總結一下流程:

  1. 建立一個單簽帳戶
  2. 建立一個多簽帳戶,這邊是建立一個 2-of-3 多簽帳戶
  3. 簽署 rotation proof challenge
  4. 執行輪換 authentication key

3.3 環境安裝

安裝 Poetry

推薦使用 Poetry 進行 Python 套件管理。

安裝 Poetry

curl -sSL https://install.python-poetry.org | python3 -

將 Poetry 加入 PATH 依照自己的系統環境,加到 .zshrc maybe .bashrc

export PATH="$HOME/.local/bin:$PATH"

確認 Poetry 安裝完成

poetry --version

安裝 Aptos Python SDK

pip3 install aptos-sdk

更多詳細資訊,可參考官網文檔。

3.4 執行 Aptos SDK Example

git clone https://github.com/aptos-labs/aptos-core.git
cd aptos-core/ecosystem/python/sdk

重現專案的 Poetry 虛擬環境

poetry env use python3

安裝套件

poetry install

執行

poetry run python -m examples.multisig

3.5 設定

引入要用到的庫:

from aptos_sdk.account import Account, RotationProofChallenge
from aptos_sdk.account_address import AccountAddress
from aptos_sdk.authenticator import Authenticator, MultiEd25519Authenticator
from aptos_sdk.bcs import Serializer
from aptos_sdk.client import FaucetClient, RestClient
from aptos_sdk.ed25519 import MultiPublicKey, MultiSignature
from aptos_sdk.transactions import (
    EntryFunction,
    RawTransaction,
    Script,
    ScriptArgument,
    SignedTransaction,
    TransactionArgument,
    TransactionPayload,
)
from aptos_sdk.type_tag import StructTag, TypeTag

設定連接節點、水龍頭資訊,這邊使用 devnet 環境:

NODE_URL = os.getenv("APTOS_NODE_URL", "https://fullnode.devnet.aptoslabs.com/v1")
FAUCET_URL = os.getenv(
    "APTOS_FAUCET_URL",
    "https://faucet.devnet.aptoslabs.com",
)

初始化客戶端

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

3.6 建立單簽帳戶

deedee = Account.generate()
faucet_client.fund_account(deedee.address(), 50_000_000)
deedee_balance = rest_client.account_balance(deedee.address())
Deedee's address:    0x7ee730f9bb87e78b0f51b4399113af2ed6bc50d0a8e0bc27f914c287af6a9d49
Deedee's auth key:   0x7ee730f9bb87e78b0f51b4399113af2ed6bc50d0a8e0bc27f914c287af6a9d49
Deedee's public key: 0x641cb41098c6cea2c2643508ee28e116459c666e353d6dc708290c5dd8f27169
Deedee's balance:    50000000

3.7 建立多簽帳戶

這邊我們選擇建立 2-of-3 多簽帳戶,所以先建立三個單簽帳戶,這樣會有三對公鑰私鑰對。

# generate account
alice = Account.generate()
bob = Account.generate()
chad = Account.generate()

# fund account
faucet_client.fund_account(alice.address(), 10_000_000)
faucet_client.fund_account(bob.address(), 20_000_000)
faucet_client.fund_account(chad.address(), 30_000_000)
=== Account addresses ===
Alice: 0xe2f0ac3bf3066f83c3f13df40eb1f1e980b15bbf6198dfee0d4bfd741baf92a8
Bob:   0x55234e90dec96a74938a4da2f7815b97494fc3c4b4d8782fa9c0e83399613310
Chad:  0x9b2ff4d016b1dead4c79487275bcb332ce56d0c707bc07cf0f15e223e64122a0

=== Authentication keys ===
Alice: 0xe2f0ac3bf3066f83c3f13df40eb1f1e980b15bbf6198dfee0d4bfd741baf92a8
Bob:   0x55234e90dec96a74938a4da2f7815b97494fc3c4b4d8782fa9c0e83399613310
Chad:  0x9b2ff4d016b1dead4c79487275bcb332ce56d0c707bc07cf0f15e223e64122a0

=== Public keys ===
Alice: 0x53a03cc129319935ddabc8ac2afb0c5e320cd5bda347413fb6fe33bcdd0b7fb3
Bob:   0x51a95405c021b0449d11d71797ecb72e931c045a55f69ae96aa6c87d55ba8098
Chad:  0x74ac180a4c5b4f6e14f13b8a5e6dd19d102c0e3543268816dcb6484f0da5444d

接下來使用上一步產生的公鑰去生成 2-of-3 多簽帳戶公鑰和地址。

# generate public key from Alice, Bob and Chad's public key
threshold = 2
multisig_public_key = MultiPublicKey(
    [alice.public_key(), bob.public_key(), chad.public_key()], threshold
)
# get address
multisig_address = AccountAddress.from_multi_ed25519(multisig_public_key)
# fund account
faucet_client.fund_account(multisig_address, 40_000_000)
=== 2-of-3 Multisig account ===
Account public key: 2-of-3 Multi-Ed25519 public key
Account address:    0x77e7728ef2189e48b3b898087c460a63f14955bcc6e4915b95aab8f864be8d05

3.8 簽署 rotation proof challenge

在調用 rotate_authentication_key 之前,需要準備傳入的參數,分別是 cap_rotate_key 及 cap_update_tableThecap_rotate_key 表 Deedee 批准此身份驗證密鑰輪換。cap_update_table 驗證多簽帳戶是否批准身份驗證密鑰輪換。

rotation_proof_challenge = RotationProofChallenge(
    sequence_number=0,
    originator=deedee.address(),
    current_auth_key=deedee.address(),
    new_public_key=multisig_public_key.to_bytes(),
)

serializer = Serializer()
rotation_proof_challenge.serialize(serializer)
rotation_proof_challenge_bcs = serializer.output()

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

cap_update_table = MultiSignature(
    multisig_public_key,
    [
        (bob.public_key(), bob.sign(rotation_proof_challenge_bcs)),
        (chad.public_key(), chad.sign(rotation_proof_challenge_bcs)),
    ],
).to_bytes()
=== Signing rotation proof challenge ===
cap_rotate_key:   0x497d25f09c29df422e620dd8eaf44ee9b7bbc2844b5143ade652d9a0d084cd1b59e66e6d0c8ebd3a4e6d5b70ddc0f635bbe321ea6ac2902d2ab07e3248e5ac08
cap_update_table: 0xe40f69589e89beca67362c2cadb145df92d77351bfe77aa9318af88f1453576b2fc8e8723fca961e696014a0077946a762c18d7a64547b3ec1f0539f88889303d89de34be00ada58151a124cc3610226ca1c0ca9814be9040bba3c6d02f169a53b922ce6cb026165746c8e90837affac8692206dc9eb0f82f0117742d331670a60000000

3.9 執行輪換 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)
)

# auth key before key rotation
auth_key = rest_client.account(deedee.address())["authentication_key"]
print(f"Auth key pre-rotation: {auth_key}")

# send key rotation tx
tx_hash = rest_client.submit_bcs_transaction(signed_transaction)
rest_client.wait_for_transaction(tx_hash)
print(f"Transaction hash:      {tx_hash}")

# auth key after key rotation
auth_key = rest_client.account(deedee.address())["authentication_key"]
print(f"New auth key:          {auth_key}")
print(f"1st multisig address:  {multisig_address}")
=== Submitting authentication key rotation transaction ===
Auth key pre-rotation: 0x7ee730f9bb87e78b0f51b4399113af2ed6bc50d0a8e0bc27f914c287af6a9d49
Transaction hash:      0x16046f72559268dc4025d28bbc2d8c91ab7a780e237cbf430965477910014df0
New auth key:          0x77e7728ef2189e48b3b898087c460a63f14955bcc6e4915b95aab8f864be8d05
1st multisig address:  0x77e7728ef2189e48b3b898087c460a63f14955bcc6e4915b95aab8f864be8d05

0x04 總結

Aptos 帳戶讓鏈上地址身份與私鑰解耦,提供了單簽及多簽帳戶,最重要的是具有密鑰輪換的功能。地址在創建帳號後維持不變,即使在密鑰輪換後仍然維持相同。密鑰輪換改變的是公鑰私鑰對以及身份驗證密鑰。

0x05 Reference

  • https://aptos.dev/concepts/accounts/
  • https://medium.com/@martian-wallet/accounts-in-aptos-1ecc3f0b1213
  • https://forum.aptoslabs.com/t/aptos-review-account-system/150437
  • https://aptos.dev/tutorials/your-first-multisig/

The above content are reproduced from the Internet, does not represent the position of AptosNews, is not investment advice, investment risk, the market need to be cautious, in case of infringement, please contact the administrator to delete.

Like (0)
Donate WeChat Sweep WeChat Sweep Alipay Sweep Alipay Sweep
Previous 2023年7月20日 pm1:14
Next July 21, 2023

Related posts

Leave a Reply

Please Login to Comment
WeChat Sweep
Baidu Sweep

Subscribe to AptosNews

Subscribe to AptosNews to stay on top of Aptos.


This will close in 25 seconds

This site has no investment advice, Investment risk, Enter the market with caution.