hash & encode
encode
hex
先简单介绍编码,编码可以把字节流(所有数据都可以是字节形式)显示成可视字符。 web3 世界中大部分数据操作 (hash,signature) 也是以字节为基础的。 这就使得,数据的可读性差一些。引入编码,就可以解决这个问题, 其中以 hex 编码居多。
安装 hex 编码库
cargo add hex
一个基本的 encode 、decode 示例
fn main() { let msg = b"Hello, world!"; let result = hex::encode(msg); println!("{}", &result); let msg_x = hex::decode(result).unwrap(); println!("{}", String::from_utf8(msg_x).unwrap()); }
将字节数组还原成 string 的时候,需要使用 String::from_utf8(msg_x).unwrap()
来还原。
同时,因为结果的不确定性,所以,会返回一个 Result 类型。
bcs
bcs 编码是一个二进制编码,可以把一个 满足要求的 结构体编码成字节数组,同时,也可以将一个字节流反序列化成一个结构体。 方便数据安全高效的传递,web3 中会用到 bcs 传递参数和返回结果。
安装 bcs 编码库
cargo add bcs
cargo add serde
use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize)] struct Payload { value: u8, enabled: bool, msg: String, } fn main() { let p = Payload { value: 123, enabled: false, msg: "hello world".to_string(), }; let d = bcs::to_bytes(&p).unwrap(); println!("bcs encode {}", hex::encode(&d)); let x = bcs::from_bytes::<Payload>(&d).unwrap(); println!("value is : {}", x.value); }
需要序列化的结构体,必须满足 Serialize,需要反序列化的结构体,必须满足 Deserialize 的 trait 。
可以通过 serde::{Deserialize, Serialize};
的宏来快速实现。
hash
hash 是 web3 中常用的操作,用于将数据转换为固定长度的字节数组。 一般用来唯一识别数据的完整性。
简单的 sha hash , 包含: sha256, sha384, sha512 等。
使用通用的类库 sha2 来实现。
cargo add sha2
其中 sha2 的 crates 中包含 sha256, sha384, sha512 等。 因,Hash 计算,大多数会返回不可读的字节数组,所以,一般都会和 hex 编码一起使用。
下边是一个计算 sha256 的示例
use sha2::Digest; fn main() { let msg = "Hello, world!"; let mut h = sha2::Sha256::new(); h.reset(); h.update(msg); let hash = h.finalize(); println!("{}", hex::encode(hash)); }
计算 Hash 之前,需要生成对应的编码器 : let mut h = sha2::Sha256::new(), 同时编码器,必须包含 mut 属性。 然后,将需要计算的数据写入编码器中,最后,调用 finalize 方法,获取计算结果。
如果 Hash 计算器,需要多次计算。那么,需要先调用 reset 方法,重置编码器。
hmac
在 Sha hash 的基础上,附加一个 key ,除了完成自身的数据完整性以外,还可以添加一层简单的身份认证。 这种算法,在身份认证方面,也应用较为广泛,数据发送者,与数据传递着、数据接受者之间,可以用一个 key 来做验证。
安装
cargo add hmac
计算 hmac hash 的实例:
#![allow(unused)] fn main() { let mut hx = hmac::Hmac::<sha2::Sha256>::new_from_slice(b"hello").unwrap(); hx.update(b"world"); let b = hx.finalize().into_bytes(); println!("{}", hex::encode(b)); }
指定一个 key , 然后写入数据,通过 finalize 获取对应的字节流。
hmac 在 后续的 slip10 中被用来生成子账号的秘钥。