名称:multiversx-crypto-verification 描述:MultiversX智能合约中的加密操作。用于数据哈希(SHA256、Keccak256、RIPEMD160)、验证签名(Ed25519、secp256k1、secp256r1、BLS)或在链上逻辑中编码签名。
MultiversX加密验证 — self.crypto() API参考
MultiversX智能合约中哈希和签名验证的完整参考(SDK v0.64+)。
哈希函数
所有哈希函数都接受&ManagedBuffer(或任何可借用为ManagedBuffer的类型)并返回固定大小的ManagedByteArray。
| 方法 | 返回类型 | 输出大小 | 使用场景 |
|---|---|---|---|
.sha256(data) |
ManagedByteArray<A, 32> |
32字节 | 通用哈希、默克尔树 |
.keccak256(data) |
ManagedByteArray<A, 32> |
32字节 | 以太坊兼容性、EIP-712 |
.ripemd160(data) |
ManagedByteArray<A, 20> |
20字节 | 比特币地址派生(少见) |
// 哈希消息
let message = ManagedBuffer::from("要哈希的数据");
let hash: ManagedByteArray<Self::Api, 32> = self.crypto().sha256(&message);
// 用于以太坊兼容性的哈希
let eth_hash = self.crypto().keccak256(&abi_encoded_data);
签名验证
关键区别:Panic vs Bool
基于Panic — 无效签名时交易立即失败。无法进行错误处理。当无效签名等于未经授权的操作时使用。
基于Bool — 返回true/false。合约继续执行。当需要优雅的错误处理或多个验证尝试时使用。
| 方法 | 返回 | 无效签名时 |
|---|---|---|
verify_ed25519(key, message, signature) |
() |
Panics — 交易以“无效签名”失败 |
verify_bls(key, message, signature) |
() |
Panics |
verify_secp256r1(key, message, signature) |
() |
Panics |
verify_bls_signature_share(key, message, signature) |
() |
Panics |
verify_bls_aggregated_signature(keys, message, signature) |
() |
Panics |
verify_secp256k1(key, message, signature) |
bool |
返回false |
verify_custom_secp256k1(key, message, signature, hash_type) |
bool |
返回false |
方法签名
// 基于Panic(无返回值)
fn verify_ed25519(
&self,
key: &ManagedBuffer<A>, // 32字节公钥
message: &ManagedBuffer<A>, // 任意消息
signature: &ManagedBuffer<A>, // 64字节签名
)
fn verify_bls(
&self,
key: &ManagedBuffer<A>, // 96字节BLS公钥
message: &ManagedBuffer<A>,
signature: &ManagedBuffer<A>, // 48字节BLS签名
)
fn verify_secp256r1(
&self,
key: &ManagedBuffer<A>, // 33或65字节公钥
message: &ManagedBuffer<A>,
signature: &ManagedBuffer<A>,
)
fn verify_bls_signature_share(
&self,
key: &ManagedBuffer<A>,
message: &ManagedBuffer<A>,
signature: &ManagedBuffer<A>,
)
fn verify_bls_aggregated_signature(
&self,
keys: &ManagedVec<A, ManagedBuffer<A>>, // BLS公钥列表
message: &ManagedBuffer<A>,
signature: &ManagedBuffer<A>, // 聚合签名
)
// 基于Bool
fn verify_secp256k1(
&self,
key: &ManagedBuffer<A>,
message: &ManagedBuffer<A>,
signature: &ManagedBuffer<A>, // DER编码或原始(至少2字节)
) -> bool
fn verify_custom_secp256k1(
&self,
key: &ManagedBuffer<A>,
message: &ManagedBuffer<A>,
signature: &ManagedBuffer<A>,
hash_type: MessageHashType, // 消息哈希方式
) -> bool
MessageHashType枚举
用于verify_custom_secp256k1以指定消息的预哈希方式:
pub enum MessageHashType {
ECDSAPlainMsg, // 消息未哈希(原始)
ECDSASha256, // 消息已SHA-256哈希
ECDSADoubleSha256, // 消息已双重SHA-256哈希(比特币)
ECDSAKeccak256, // 消息已Keccak-256哈希(以太坊)
ECDSARipemd160, // 消息已RIPEMD-160哈希
ECDSABlake2b, // 消息已Blake2b哈希
}
DER签名编码
将原始(r, s)组件转换为secp256k1的DER格式:
fn encode_secp256k1_der_signature(
&self,
r: &ManagedBuffer<A>, // 32字节r组件
s: &ManagedBuffer<A>, // 32字节s组件
) -> ManagedBuffer<A> // DER编码签名
算法选择指南
| 算法 | 何时使用 |
|---|---|
| Ed25519 | MultiversX原生签名。验证来自链的用户/智能合约签名。默认选择。 |
| secp256k1 | 以太坊/比特币兼容性。桥接合约、跨链验证。 |
| secp256r1 | NIST P-256 / WebAuthn / Apple Secure Enclave。基于密钥的认证。 |
| BLS | 验证器签名、多签名聚合、门限方案。 |
| BLS聚合 | 验证多个验证器的单个聚合签名。 |
常见模式
Ed25519签名门控(MultiversX原生)
#[endpoint(executeWithSignature)]
fn execute_with_signature(
&self,
data: ManagedBuffer,
signature: ManagedBuffer,
) {
let signer = self.trusted_signer().get();
// 无效则Panic — 交易自动回滚
self.crypto().verify_ed25519(
&signer,
&data,
&signature,
);
// 仅在签名有效时到达
self.process_data(&data);
}
以太坊签名验证(优雅处理)
#[endpoint(verifyEthSignature)]
fn verify_eth_signature(
&self,
key: ManagedBuffer,
message: ManagedBuffer,
signature: ManagedBuffer,
) -> bool {
// 返回bool — 优雅处理失败
let valid = self.crypto().verify_custom_secp256k1(
&key,
&message,
&signature,
MessageHashType::ECDSAKeccak256,
);
require!(valid, "无效以太坊签名");
valid
}
多验证器BLS聚合检查
#[endpoint(verifyValidators)]
fn verify_validators(
&self,
validator_keys: ManagedVec<ManagedBuffer>,
message: ManagedBuffer,
aggregated_sig: ManagedBuffer,
) {
// 聚合签名无效则Panic
self.crypto().verify_bls_aggregated_signature(
&validator_keys,
&message,
&aggregated_sig,
);
}
基于哈希的承诺-揭示
#[endpoint(commit)]
fn commit(&self, hash: ManagedByteArray<Self::Api, 32>) {
let caller = self.blockchain().get_caller();
self.commitments(&caller).set(hash);
}
#[endpoint(reveal)]
fn reveal(&self, value: ManagedBuffer) {
let caller = self.blockchain().get_caller();
let stored_hash = self.commitments(&caller).get();
let computed_hash = self.crypto().sha256(&value);
require!(stored_hash == computed_hash, "哈希不匹配");
self.commitments(&caller).clear();
self.process_reveal(&caller, &value);
}
secp256k1的DER编码
// 当您有原始r,s组件时(例如,来自预言机)
let r = ManagedBuffer::from(&r_bytes[..]);
let s = ManagedBuffer::from(&s_bytes[..]);
let der_sig = self.crypto().encode_secp256k1_der_signature(&r, &s);
let valid = self.crypto().verify_secp256k1(&pubkey, &message, &der_sig);
反模式
// 错误:尝试捕获Ed25519失败 — 它会Panic,无法捕获
let result = self.crypto().verify_ed25519(&key, &msg, &sig);
// ← verify_ed25519返回(),不是Result。如果无效,交易已失败。
// 正确:将Ed25519用作门控(Panic是预期行为)
self.crypto().verify_ed25519(&key, &msg, &sig);
// 仅在有效时继续执行
// 错误:使用verify_secp256k1但不检查bool
self.crypto().verify_secp256k1(&key, &msg, &sig);
// ← 编译正常但忽略结果!签名实际上未被检查。
// 正确:始终检查bool返回值
let valid = self.crypto().verify_secp256k1(&key, &msg, &sig);
require!(valid, "无效签名");
// 错误:对以太坊签名使用错误的哈希类型
self.crypto().verify_custom_secp256k1(&key, &msg, &sig, MessageHashType::ECDSASha256);
// ← 以太坊使用Keccak256,不是SHA256
// 正确:将哈希类型与链匹配
self.crypto().verify_custom_secp256k1(&key, &msg, &sig, MessageHashType::ECDSAKeccak256);