multiversx-crypto-verification
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseMultiversX Crypto Verification — self.crypto()
API Reference
self.crypto()MultiversX 加密验证 — self.crypto()
API 参考文档
self.crypto()Complete reference for hashing and signature verification in MultiversX smart contracts (SDK v0.64+).
MultiversX智能合约中哈希与签名验证的完整参考(SDK v0.64+)。
Hashing Functions
哈希函数
All hashing functions take (or anything that borrows as ) and return a fixed-size .
&ManagedBufferManagedBufferManagedByteArray| Method | Return Type | Output Size | Use Case |
|---|---|---|---|
| | 32 bytes | General purpose hashing, Merkle trees |
| | 32 bytes | Ethereum compatibility, EIP-712 |
| | 20 bytes | Bitcoin address derivation (rare) |
rust
// Hash a message
let message = ManagedBuffer::from("data to hash");
let hash: ManagedByteArray<Self::Api, 32> = self.crypto().sha256(&message);
// Hash for Ethereum compatibility
let eth_hash = self.crypto().keccak256(&abi_encoded_data);所有哈希函数接收(或任何可借用为的类型)并返回固定大小的。
&ManagedBufferManagedBufferManagedByteArray| 方法 | 返回类型 | 输出大小 | 使用场景 |
|---|---|---|---|
| | 32字节 | 通用哈希、默克尔树 |
| | 32字节 | 以太坊兼容性、EIP-712 |
| | 20字节 | 比特币地址推导(少见) |
rust
// 哈希消息
let message = ManagedBuffer::from("data to hash");
let hash: ManagedByteArray<Self::Api, 32> = self.crypto().sha256(&message);
// 以太坊兼容哈希
let eth_hash = self.crypto().keccak256(&abi_encoded_data);Signature Verification
签名验证
Critical Distinction: Panic vs Bool
关键区别:Panic 与返回布尔值
Panic-based — Transaction fails immediately on invalid signature. No error handling possible. Use when invalid signature = unauthorized action.
Bool-based — Returns /. Contract continues execution. Use when you need graceful error handling or multiple verification attempts.
truefalse| Method | Returns | On Invalid Signature |
|---|---|---|
| | Panics — tx fails with "invalid signature" |
| | Panics |
| | Panics |
| | Panics |
| | Panics |
| | Returns false |
| | Returns false |
Panic模式 — 签名无效时交易立即失败,无法进行错误处理。适用于签名无效即代表未授权操作的场景。
布尔返回模式 — 返回/,合约继续执行。适用于需要优雅错误处理或多次验证尝试的场景。
truefalse| 方法 | 返回值 | 签名无效时的行为 |
|---|---|---|
| | 触发Panic — 交易因"无效签名"失败 |
| | 触发Panic |
| | 触发Panic |
| | 触发Panic |
| | 触发Panic |
| | 返回false |
| | 返回false |
Method Signatures
方法签名
rust
// Panic-based (no return value)
fn verify_ed25519(
&self,
key: &ManagedBuffer<A>, // 32-byte public key
message: &ManagedBuffer<A>, // arbitrary message
signature: &ManagedBuffer<A>, // 64-byte signature
)
fn verify_bls(
&self,
key: &ManagedBuffer<A>, // 96-byte BLS public key
message: &ManagedBuffer<A>,
signature: &ManagedBuffer<A>, // 48-byte BLS signature
)
fn verify_secp256r1(
&self,
key: &ManagedBuffer<A>, // 33 or 65-byte public key
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>>, // list of BLS public keys
message: &ManagedBuffer<A>,
signature: &ManagedBuffer<A>, // aggregated signature
)
// Bool-based
fn verify_secp256k1(
&self,
key: &ManagedBuffer<A>,
message: &ManagedBuffer<A>,
signature: &ManagedBuffer<A>, // DER-encoded or raw (min 2 bytes)
) -> bool
fn verify_custom_secp256k1(
&self,
key: &ManagedBuffer<A>,
message: &ManagedBuffer<A>,
signature: &ManagedBuffer<A>,
hash_type: MessageHashType, // how the message was hashed
) -> boolrust
// Panic-based (no return value)
fn verify_ed25519(
&self,
key: &ManagedBuffer<A>, // 32-byte public key
message: &ManagedBuffer<A>, // arbitrary message
signature: &ManagedBuffer<A>, // 64-byte signature
)
fn verify_bls(
&self,
key: &ManagedBuffer<A>, // 96-byte BLS public key
message: &ManagedBuffer<A>,
signature: &ManagedBuffer<A>, // 48-byte BLS signature
)
fn verify_secp256r1(
&self,
key: &ManagedBuffer<A>, // 33 or 65-byte public key
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>>, // list of BLS public keys
message: &ManagedBuffer<A>,
signature: &ManagedBuffer<A>, // aggregated signature
)
// Bool-based
fn verify_secp256k1(
&self,
key: &ManagedBuffer<A>,
message: &ManagedBuffer<A>,
signature: &ManagedBuffer<A>, // DER-encoded or raw (min 2 bytes)
) -> bool
fn verify_custom_secp256k1(
&self,
key: &ManagedBuffer<A>,
message: &ManagedBuffer<A>,
signature: &ManagedBuffer<A>,
hash_type: MessageHashType, // how the message was hashed
) -> boolMessageHashType Enum
MessageHashType 枚举
Used with to specify how the message was pre-hashed:
verify_custom_secp256k1rust
pub enum MessageHashType {
ECDSAPlainMsg, // Message is not hashed (raw)
ECDSASha256, // Message was SHA-256 hashed
ECDSADoubleSha256, // Message was double SHA-256 hashed (Bitcoin)
ECDSAKeccak256, // Message was Keccak-256 hashed (Ethereum)
ECDSARipemd160, // Message was RIPEMD-160 hashed
ECDSABlake2b, // Message was Blake2b hashed
}用于,指定消息的预哈希方式:
verify_custom_secp256k1rust
pub enum MessageHashType {
ECDSAPlainMsg, // Message is not hashed (raw)
ECDSASha256, // Message was SHA-256 hashed
ECDSADoubleSha256, // Message was double SHA-256 hashed (Bitcoin)
ECDSAKeccak256, // Message was Keccak-256 hashed (Ethereum)
ECDSARipemd160, // Message was RIPEMD-160 hashed
ECDSABlake2b, // Message was Blake2b hashed
}DER Signature Encoding
DER签名编码
Convert raw (r, s) components to DER format for secp256k1:
rust
fn encode_secp256k1_der_signature(
&self,
r: &ManagedBuffer<A>, // 32-byte r component
s: &ManagedBuffer<A>, // 32-byte s component
) -> ManagedBuffer<A> // DER-encoded signature将原始(r, s)组件转换为secp256k1的DER格式:
rust
fn encode_secp256k1_der_signature(
&self,
r: &ManagedBuffer<A>, // 32-byte r component
s: &ManagedBuffer<A>, // 32-byte s component
) -> ManagedBuffer<A> // DER-encoded signatureAlgorithm Selection Guide
算法选择指南
| Algorithm | When to Use |
|---|---|
| Ed25519 | MultiversX native signatures. Verify user/SC signatures from the chain. Default choice. |
| secp256k1 | Ethereum/Bitcoin compatibility. Bridge contracts, cross-chain verification. |
| secp256r1 | NIST P-256 / WebAuthn / Apple Secure Enclave. Passkey-based auth. |
| BLS | Validator signatures, multi-sig aggregation, threshold schemes. |
| BLS aggregated | Verify a single aggregated signature from multiple validators. |
| 算法 | 使用场景 |
|---|---|
| Ed25519 | MultiversX原生签名。验证链上用户/智能合约签名。默认选择。 |
| secp256k1 | 以太坊/比特币兼容性。桥接合约、跨链验证。 |
| secp256r1 | NIST P-256 / WebAuthn / Apple安全隔区。基于Passkey的身份验证。 |
| BLS | 验证者签名、多签聚合、门限方案。 |
| BLS聚合签名 | 验证来自多个验证者的单个聚合签名。 |
Common Patterns
常见模式
Ed25519 Signature Gate (MultiversX Native)
Ed25519签名校验门(MultiversX原生)
rust
#[endpoint(executeWithSignature)]
fn execute_with_signature(
&self,
data: ManagedBuffer,
signature: ManagedBuffer,
) {
let signer = self.trusted_signer().get();
// Panics if invalid — tx reverts automatically
self.crypto().verify_ed25519(
&signer,
&data,
&signature,
);
// Only reached if signature is valid
self.process_data(&data);
}rust
#[endpoint(executeWithSignature)]
fn execute_with_signature(
&self,
data: ManagedBuffer,
signature: ManagedBuffer,
) {
let signer = self.trusted_signer().get();
// Panics if invalid — tx reverts automatically
self.crypto().verify_ed25519(
&signer,
&data,
&signature,
);
// Only reached if signature is valid
self.process_data(&data);
}Ethereum Signature Verification (Graceful)
以太坊签名验证(优雅处理)
rust
#[endpoint(verifyEthSignature)]
fn verify_eth_signature(
&self,
key: ManagedBuffer,
message: ManagedBuffer,
signature: ManagedBuffer,
) -> bool {
// Returns bool — handle failure gracefully
let valid = self.crypto().verify_custom_secp256k1(
&key,
&message,
&signature,
MessageHashType::ECDSAKeccak256,
);
require!(valid, "Invalid Ethereum signature");
valid
}rust
#[endpoint(verifyEthSignature)]
fn verify_eth_signature(
&self,
key: ManagedBuffer,
message: ManagedBuffer,
signature: ManagedBuffer,
) -> bool {
// Returns bool — handle failure gracefully
let valid = self.crypto().verify_custom_secp256k1(
&key,
&message,
&signature,
MessageHashType::ECDSAKeccak256,
);
require!(valid, "Invalid Ethereum signature");
valid
}Multi-Validator BLS Aggregated Check
多验证者BLS聚合签名校验
rust
#[endpoint(verifyValidators)]
fn verify_validators(
&self,
validator_keys: ManagedVec<ManagedBuffer>,
message: ManagedBuffer,
aggregated_sig: ManagedBuffer,
) {
// Panics if aggregated signature is invalid
self.crypto().verify_bls_aggregated_signature(
&validator_keys,
&message,
&aggregated_sig,
);
}rust
#[endpoint(verifyValidators)]
fn verify_validators(
&self,
validator_keys: ManagedVec<ManagedBuffer>,
message: ManagedBuffer,
aggregated_sig: ManagedBuffer,
) {
// Panics if aggregated signature is invalid
self.crypto().verify_bls_aggregated_signature(
&validator_keys,
&message,
&aggregated_sig,
);
}Hash-Based Commit-Reveal
基于哈希的提交-揭示模式
rust
#[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, "Hash mismatch");
self.commitments(&caller).clear();
self.process_reveal(&caller, &value);
}rust
#[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, "Hash mismatch");
self.commitments(&caller).clear();
self.process_reveal(&caller, &value);
}DER Encoding for secp256k1
secp256k1的DER编码
rust
// When you have raw r,s components (e.g., from an oracle)
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);rust
// When you have raw r,s components (e.g., from an oracle)
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);Anti-Patterns
反模式
rust
// BAD: Trying to catch Ed25519 failure — it panics, there's nothing to catch
let result = self.crypto().verify_ed25519(&key, &msg, &sig);
// ← verify_ed25519 returns (), not Result. If invalid, tx is already dead.
// GOOD: Use Ed25519 as a gate (panic is the intended behavior)
self.crypto().verify_ed25519(&key, &msg, &sig);
// Execution continues only if valid
// BAD: Using verify_secp256k1 without checking the bool
self.crypto().verify_secp256k1(&key, &msg, &sig);
// ← Compiles fine but ignores the result! Signature not actually checked.
// GOOD: Always check the bool return
let valid = self.crypto().verify_secp256k1(&key, &msg, &sig);
require!(valid, "Invalid signature");
// BAD: Using wrong hash type for Ethereum signatures
self.crypto().verify_custom_secp256k1(&key, &msg, &sig, MessageHashType::ECDSASha256);
// ← Ethereum uses Keccak256, not SHA256
// GOOD: Match the hash type to the chain
self.crypto().verify_custom_secp256k1(&key, &msg, &sig, MessageHashType::ECDSAKeccak256);rust
// BAD: Trying to catch Ed25519 failure — it panics, there's nothing to catch
let result = self.crypto().verify_ed25519(&key, &msg, &sig);
// ← verify_ed25519 returns (), not Result. If invalid, tx is already dead.
// GOOD: Use Ed25519 as a gate (panic is the intended behavior)
self.crypto().verify_ed25519(&key, &msg, &sig);
// Execution continues only if valid
// BAD: Using verify_secp256k1 without checking the bool
self.crypto().verify_secp256k1(&key, &msg, &sig);
// ← Compiles fine but ignores the result! Signature not actually checked.
// GOOD: Always check the bool return
let valid = self.crypto().verify_secp256k1(&key, &msg, &sig);
require!(valid, "Invalid signature");
// BAD: Using wrong hash type for Ethereum signatures
self.crypto().verify_custom_secp256k1(&key, &msg, &sig, MessageHashType::ECDSASha256);
// ← Ethereum uses Keccak256, not SHA256
// GOOD: Match the hash type to the chain
self.crypto().verify_custom_secp256k1(&key, &msg, &sig, MessageHashType::ECDSAKeccak256);