智能合约验证签名
verify_profile示例程序在第一单元的profile_clock示例程序的基础上,增加了需要验证签名信息的add_points函数。
引入依赖
在智能合约模块的开头,引入依赖模块。
use sui::{
    clock::Clock,
    bcs,
    hash,
    ed25519
};
定义数据结构
const PK: vector<u8> = vector[185, 198, 238, 22, 48, 
    239, 62, 113, 17, 68, 166, 72, 219, 6, 187, 178, 
    40, 79, 114, 116, 207, 190, 229, 63, 252, 238, 80, 
    60, 193, 164, 146, 0];
定义常量PK来记录公钥二进制数据。
public struct ProfileData has drop {
    id: ID,
    add_points: u64,
    last_time: u64,
}
ProfileData数据结构中包含了验证的必须信息,除了需要增加的分数add_points, 还有每个Profile的Object ID和上次更新的时间last_time. 增加这些信息是为了让签名变得唯一,不可以被重复使用。
ProfileData数据结构的ability是drop, 是为了作用域结束之后可以被自动销毁。
函数实现
public fun add_points(
    profile: &mut Profile, 
    add_points: u64, 
    sig: vector<u8>,
    clock: &Clock
) {
    let profile_data = ProfileData {
        id: object::id(profile),
        add_points,
        last_time: profile.last_time,
    };
    let byte_data = bcs::to_bytes(&profile_data);
    let hash_data = hash::keccak256(&byte_data);
    let pk = PK;
    let verify = ed25519::ed25519_verify(&sig, &pk, &hash_data);
    assert!(verify == true);
    profile.points = profile.points + add_points;
    profile.last_time = clock.timestamp_ms();
}
在函数中,先构建需要验证的数据ProfileData.
let profile_data = ProfileData {
    id: object::id(profile),
    add_points,
    last_time: profile.last_time,
};
将ProfileData数据转为二进制,然后计算哈希值。
let byte_data = bcs::to_bytes(&profile_data);
let hash_data = hash::keccak256(&byte_data);
其实二进制的数据已经可以用于签名验证,但是取哈希值计算之后,会变为定长的数据,提升后续加密算法的计算效率。如果ProfileData中还包含可变长度的字符串数据,取哈希值计算是很有帮助的,这里仅作为演示使用。
复制公钥数据pk, 然后验证传入的签名数据sig和之前计算得到的哈希值hash_data.
let pk = PK;
let verify = ed25519::ed25519_verify(&sig, &pk, &hash_data);
assert!(verify == true);
最后,再添加积分,然后更新Profile的last_time属性。
profile.points = profile.points + add_points;
profile.last_time = clock.timestamp_ms();
作业
在本小节示例代码的基础上进行修改,添加一个edit_handle函数,在验证签名信息后,可以编辑Profile的handle属性。
