头图

Aptos 链上的资产,都属于某个账户。所谓资产,是指包括币、NFT在内的,天然稀缺的东西,所以他们的访问,一定要有控制。任何资产,在区块链账户中,都表现为一种资源(resource)。资源是 Move 语言中一种原始数据类型,它表现出稀缺性和访问控制能力。不过,资源也可以用于代表其他的链上能力,可识别信息,或者访问控制。
每一个账户都可以用一条32字节的地址来表示。账户中可以包含数据,数据被保存在资源里。一个账户的初始资源,就是账户本身的数据(认证秘钥和序列号)。创建完账户后,可以再添加其他资源(比如币和NFT)。

账户地址示例:
账户地址由32个字节组成,通常用64个16进制数字表示,每个数字表示半个字节(nibble)。在 你的第一笔交易 中,有关于地址的例子,大概是下面这样:
Alice: eeff357ea5c1a4e7bc11b2b17ff2dc2dcca69750bfef1e1ebcaccf8c8018175b
Bob: 19aadeca9388e009d136245b9a67423f3eee242b03142849eb4f81a4a409e59c

创建账户

当用户通过 Aptos SDK 创建一个账户,会经历下面几个加密步骤:

  • 首先创建一组秘钥对:一个公钥 + 一个私钥
  • 用户明确要使用的签名策略:对于一笔交易,要使用单签还是多签
  • 结合公钥和签名策略,生个一个32字节的认证秘钥
  • 初始化账户序列号为0。把上一步生成的认证秘钥和序列号,都存进账户的初始化资源中
  • 基于认证秘钥,生成32字节的账户地址

从现在开始,用户就可以用账户私钥来签署每一笔交易了。

账户序列号

序列号,用于表示一个账户中,有多少笔交易被提交到链上,并且确认过了。每一笔从该账户发出的交易,无论最终执行了,还是取消了,只要被链上保存,都会导致序列号自增1。
发起交易的时候,就需要附带上账户的当前序列号。当 Aptos 公链准备执行交易的时候,它会检查这个序列号,跟链上保存的账户当前序列号做比较。只有在交易附带序列号和账户序列号相等时,交易才会被执行,否则就会拒绝。通过这种方式,可以避免旧的交易被重复执行,从而避免了重放攻击(replay attack)。
这些交易(译注:联系上下文,应该是指所有序列号大于账户当前序列号的交易)会被暂存在 mempool 中,知道它们正好是账户的下一个序列号(随着交易的执行,账户序列号会不断增长);或者直到它们过期被清除。交易执行之后,账户序列号自增1。账户序列号永远是单调递增的。

账户地址

在创建新账户的过程中,会生成一个32字节的认证秘钥,然后,这个认证秘钥就会作为账户地址返回。
不过,认证秘钥以后是可以变更的,比如,你生成了新的一组秘钥对来重置秘钥。但账户地址是不变的。因此,只有初始化账户生成的32字节认证秘钥,跟地址相同。在账户创建之后,无论私钥、公钥还是认证秘钥产生变更,账户地址都不变了。账户地址自创建之后,是永远不会变化的。

签名策略

Aptos 链支持下列签名策略:

  1. 单签使用 ED25519 标准
  2. 多签使用 MultiED25519 标准

缺省策略是单签。

签名策略标识

在生成认证秘钥的时候,你要提供1字节的签名策略标识,来表示到底使用单签还是多签。

  • 单签标识:0x00
  • 多签标识:0x01。注意多签的情况下,还需要提供 K 值,来生成 K-of-N 形态的多签秘钥。

    单签认证

    要生成单签的认证秘钥和账户地址:

  1. 创建秘钥对:新建一组秘钥对(privkey_A, pubkey_A)。Aptos 链在Ed25519曲线算法的基础上,使用 PureEdDSA 策略生成秘钥对,正如 RFC8032 标准定义的那样。
  2. 派生一个 32字节的认证秘钥:

    auth_key = sha3-256(pubkey_A | 0x00)

    其中 | 表示连接, 0x00 是单字节的单签策略标识。

  3. 用这个初始化认证秘钥,作为永久的账户地址

    多签认证

    所谓 K-of-N 多签的认证秘钥,是指一个账户具有 N 个签名人,至少其中的 K 个人签署之后,交易才会被认证为已签发。
    要生成多签的认证秘钥和账户地址:

  4. 创建秘钥对:生成 N 个 Ed25519 标准的公钥: p_1, ..., p_n
  5. 确认 K 值:签发交易需要的最少签名人数量
  6. 派生一个 32字节的认证秘钥:

    auth_key = sha3-256(p_1 | . . . | p_n | K | 0x01)

    其中 | 表示连接, 0x01 是单字节的多签策略标识。

  7. 用这个初始化认证秘钥,作为永久的账户地址。

    签名人访问控制

    交易的发起人,总是由一个签名人来表示。当调用 Move 模块中的函数时,如果有 signer 作为参数,Move 虚拟机将签署交易的账户身份转化为 Move 模块入口中的 signer。下面的代码,展示了初始化和提现时, signer 的用法;反之,如果一个函数中没有 signer 这个参数,例如下面的充值函数,它就不需要访问控制:

    module Test::Coin {
      struct Coin has key { amount: u64 }
    
      public fun initialize(account: &signer) {
     move_to(account, Coin { amount: 1000 });
      }
    
      public fun withdraw(account: &signer, amount: u64): Coin acquires Coin {
     let balance = &mut borrow_global_mut<Coin>(Signer::address_of(account)).amount;
     *balance = *balance - amount;
     Coin { amount }
      }
    
      public fun deposit(account: address, coin: Coin) acquires Coin {
       let balance = &mut borrow_global_mut<Coin>(account).amount;
       *balance = *balance + coin.amount;
       Coin { amount: _ } = coin;
      }
    }

    账户状态

    账户的状态,由账户所属的代码(Move modules)和数据(Move resoruces)共同组成。一个账户中,可以包含任意数量的代码和数据。

  • 代码/模块(Move modules):Move 在模块中包含代码,比如 类型 和 过程声明,但是不包含数据。Move 模块编码了 Aptos 链的全局状态规则。
  • 资源(Move resoruces):资源包含了数据,但不含代码。每条资源都有对应的类型,而类型是在 Move 模块中声明的,并且会发布到链上的分布式数据库。

原文来自我的语雀笔记


songofhawk
303 声望24 粉丝