一个加密货币钱包,主要依赖加密算法构建。这部分逻辑无关iOS还是Android,特别适合用Rust去实现。我们看看如何实现一个生成一个模拟钱包,准备供小程序开发采用
前言
在之前的内容我们介绍了整个端到端开发环境的搭建。
其中,我们用 Xcode 开发一个 iOS native App 的“壳”,并集成了
我们又介绍了 Rust 的编译环境针对 iOS 进行编译构建代码所需要安装的相关工具。要端到端开发一个完整的应用,确实涉及到比较多的东西,有学习了解技术工具的学习成本,有时其繁琐性让人却步。但只要搭建起来,就一劳永逸,我们可以开始聚焦应用逻辑本身。
万事俱备,开搞开搞
万事俱备,那就让我们开干吧。作为一个范例,我们需要找一个逻辑比较简单又确实适合用 Rust 来实现的场景。在这里,我们选择实现一个加密钱包。设想是这样的:
- 用 Rust 来实现密钥对的生成、加密存储、交易签名。加密算法,背后都是数学逻辑,显然在什么硬件、操作系统上实现,都应该是一样通用的对吧?
- 用小程序来实现各种 dApp 的前端,可以是账户余额、交易历史、支付转账之类的账户管理小程序,也可以是各种 DeFi、GameFi 应用,也可以是 NFT 相关工具... 在 Web3 世界里,限制我们的只是想象力
当然,本文焦点不在于这些内容的具体实现,简单起见我们只象征性的实现一个密钥对的生成,其他剩余的事情,有待感兴趣的朋友去发掘。
特别提醒:加密货币钱包是 Web3 技术的基础,没有了它你什么 Web3 技术都试验不了,了解 Web3,从加密技术常识开始。
项目目录结构
我们姑且把这个项目称之为
不忙于手工创建所有这些子目录,我们先从 Rust 部分开始:
Cargo 将创建一个 rust 目录,里面非常简单,仅包含以下内容:
我们就用这个目录去写一个只有密钥对生成功能的“钱包”。
加密货币钱包的 Rust 实现
什么是加密钱包?在开发之前我们总得了解一下它的基本特征。
什么是加密货币钱包
在一般的电子钱包中,我们习惯于看到一些信息例如一某种货币单位为度量的账户余额、交易历史、持有的资产与价值等等,以及支持一些操作如支付、转账等。
加密货币钱包的最核心功能,相比之下就极其简单了,它本质上就是安全存储密钥,以便于持有者通过密钥去访问其链上的加密数字资产 - 资产在某条区块链上,并不在钱包中,除了密钥,钱包里什么都不存储。
在本项目中,简单起见我们仅实现以下两个钱包属性:
- 一对公私钥:public key 和 private key。私钥是钱包的“命根子”,私钥被盗了(或者自己弄丢了),在链上的资产也就不再是你的。一个公私钥对的例子:公钥是“03fc56c8fa9233a9db9a57b47973058e5cdd7707233619719c604cb11a03dd46d6”,私钥是“721d468dfd4584e88702da69e8e25ebe79bf338ac268413dae3cf73475f5a870”
- 一个从 public key 产生的 public address。这是便于他人转账、支付给你的账户地址。不同类型的加密数字货币,有不同的地址格式。例如光 Bitcoin 就有 P2PKH、P2SH、Bech32 三种不同格式标准。以太坊的地址格式则是以“0x”起头的 40 位 16 进制字母,例如“0x6400f8fb4953e50ca072e44ddd5fef4c995371a6”
怎样生成密钥
生成密钥对通常基于 ECC(Elliptical Curve Cryptography,椭圆曲线)。Bitcoin 和 Ethereum 均采用了一种叫 secp256k1 的算法实现了 ECDSA(Elliptical Curve Digital Signature Algorithm)。
非常幸运的,我们不用自己去啃这个算法、自己去实现,Rust/C 的实现早就有了,这是一个
需要用到的一些库
除了最关键的密钥生成算法,还有以下一些库是我们未来可能用得着的,先列在这里:
- serde: 一个在 Rust 中常用的 serialization/deserialization framework,我们可能把私钥序列化存储在手机设备中,就会用到它
- serde_json: 一个 JSON serialization 库,我们把私钥序列化存储时,可能以 JSON 格式存储
- tokio: 一个事件驱动、非阻塞型、异步高性能网络库
- web3: Ethereum JSON-RPC client. 如果想把自己开发的这个钱包接入以太坊测试链试试的话,这个库跑不掉
- tiny_keccak:SHA3 等哈希算法的实现
在本篇内容范围内,我们在 Cargo.toml 先作如下配置:
超级简单的代码实现
代码方面,我们打算这么写:首先写一个 wallet 的实现,内容上就是密钥对的生成、公共地址的生成,其他附加功能先留白了。再写一个转换层,基于 Rust FFI(Foreign Function Interface),把 wallet 的功能输出为 C 接口。
这里的工作比较繁琐,就是把Rust的数据类型转换成 C 的类型,以及对要输出的函数及数据结构用 Rust 提供的 macro 去标识,指导编译器作符合 C 语言规范的编译输出。
我们的代码如下:
wallet_impl.rs 目前主要是调用 secp256k1 的函数生成密钥对和钱包地址,看上去有点取巧,好像自己啥都没干,就是封装一下。
但如上所述,我们先“留白”,加密存储密钥、建立网络连接、向测试链查询资产、支付转账等等功能,应该是在此实现的,以后慢慢玩吧,但不影响我们这个项目的根本验证目标(FinClip 小程序调用Rust 功能)。