密码学实用工具

概述

密码学实用工具为 Soroban Smart Contract 提供了一组密码学工具, 包括哈希函数、Merkle 树验证和基于 Merkle 的分发系统。 这些实用工具实现了安全的数据验证和高效的代币分发机制。 密码学实用工具由两个主要包组成:

  • Crypto:一组用于 Soroban 合约的密码学原语和实用工具。

  • Merkle Distributor:一种使用 Merkle 证明来验证分发代币或其他资产的系统。

Crypto 包

crypto 包为 Soroban 合约提供了基本的密码学原语和实用工具, 重点是哈希和 Merkle 树操作。

主要组件

Hashers(哈希器)

提供了一个通用的 Hasher 特征以及常见哈希函数的实现:

  • Sha256:SHA-256 哈希函数的实现

  • Keccak256:Keccak-256 哈希函数的实现(在 Ethereum 中使用)

每个哈希器都遵循相同的接口:

pub trait Hasher {
    type Output;

    fn new(e: &Env) -> Self;
    fn update(&mut self, input: Bytes);
    fn finalize(self) -> Self::Output;
}

Hashable(可哈希)

Hashable 特征允许使用任何 Hasher 实现对类型进行哈希处理:

pub trait Hashable {
    fn hash<H: Hasher>(&self, hasher: &mut H);
}

BytesN<32>Bytes 提供了内置实现。

实用函数

  • hash_pair:将两个值一起哈希

  • commutative_hash_pair:以确定性顺序(对于 Merkle 树很重要)哈希两个值

Merkle 树验证

Verifier 结构体提供了验证 Merkle 证明的功能:

impl<H> Verifier<H>
where
    H: Hasher<Output = Bytes32>,
{
    pub fn verify(e: &Env, proof: Vec<Bytes32>, root: Bytes32, leaf: Bytes32) -> bool {
        // 实现验证叶子是根定义的树的一部分
    }
}

使用示例

哈希数据

use soroban_sdk::{Bytes, Env};
use stellar_contract_utils::crypto::keccak::Keccak256;
use stellar_contract_utils::crypto::hasher::Hasher;

// 使用 Keccak256 哈希一些数据
let e = Env::default();
let data = Bytes::from_slice(&e, "Hello, world!".as_bytes());

let mut hasher = Keccak256::new(&e);
hasher.update(data);
let hash = hasher.finalize();

验证 Merkle 证明

use soroban_sdk::{BytesN, Env, Vec};
use stellar_crypto::keccak::Keccak256;
use stellar_crypto::merkle::Verifier;

// 验证叶子是 Merkle 树的一部分
let e = Env::default();
let root = /* merkle 根作为 BytesN<32> */;
let leaf = /* 要验证的叶子作为 BytesN<32> */;
let proof = /* 证明作为 Vec<BytesN<32>> */;

let is_valid = Verifier::<Keccak256>::verify(&e, proof, root, leaf);

Merkle Distributor

Merkle Distributor 包构建在 crypto 包之上,提供了一个使用 Merkle 证明来验证分发代币或 其他资产的系统。

关键概念

IndexableLeaf(可索引叶子)

IndexableLeaf 特征定义了 Merkle 树中节点的结构:

pub trait IndexableLeaf {
    fn index(&self) -> u32;
}

每个节点必须包含一个唯一的索引,该索引标识其在 Merkle 树中的位置。

MerkleDistributor

MerkleDistributor 结构体提供了以下功能:

  • 设置 Merkle 根

  • 检查是否已声明索引

  • 验证证明并将索引标记为已声明

使用示例

use soroban_sdk::{contract, contractimpl, contracttype, Address, BytesN, Env, Vec};
use stellar_contract_utils::crypto::keccak::Keccak256;
use stellar_contract_utils::merkle_distributor::{IndexableLeaf, MerkleDistributor};

// 定义叶节点结构
#[contracttype]
struct LeafData {
    pub index: u32,
    pub address: Address,
    pub amount: i128,
}

// 为叶子结构实现 IndexableLeaf
impl IndexableLeaf for LeafData {
    fn index(&self) -> u32 {
        self.index
    }
}

#[contract]
pub struct TokenDistributor;

#[contractimpl]
impl TokenDistributor {
    // 使用 Merkle 根初始化分发器
    pub fn initialize(e: &Env, root: BytesN<32>) {
        MerkleDistributor::<Keccak256>::set_root(e, root);
    }

    // 通过提供证明来声明代币
    pub fn claim(e: &Env, leaf: LeafData, proof: Vec<BytesN<32>>) {
        // 验证证明并标记为已声明
        MerkleDistributor::<Keccak256>::verify_and_set_claimed(e, leaf.clone(), proof);

        // 根据叶子数据转移代币或执行其他操作
        // ...
    }

    // 检查是否已声明索引
    pub fn is_claimed(e: &Env, index: u32) -> bool {
        MerkleDistributor::<Keccak256>::is_claimed(e, index)
    }
}

用例

代币空投

高效地将代币分发给大量接收者,而无需为每个接收者进行单独的交易。

NFT 分发

将 NFT 分发到地址白名单,每个地址可能收到不同的 NFT。

链下许可名单

维护一个符合条件的地址的链下列表,并允许它们在链上声明代币或其他资产。

基于快照的投票

在特定区块创建代币持有者的快照,并允许他们根据其持有量进行投票。