跳到主要内容

智能合约验证签名

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);

最后,再添加积分,然后更新Profilelast_time属性。

profile.points = profile.points + add_points;
profile.last_time = clock.timestamp_ms();

作业

本小节示例代码的基础上进行修改,添加一个edit_handle函数,在验证签名信息后,可以编辑Profilehandle属性。