VerifySignature - Validate Transaction Signatures
Verify cryptographic signatures for Sui transactions via gRPC. Essential for security validation and multi-sig workflows with Dwellir.
Validate Transaction Signatures
The VerifySignature method verifies that a cryptographic signature is valid for given transaction data and public key. This is essential for security validation, multi-signature workflows, and ensuring transaction authenticity before execution.
Method Signature
Service: sui.rpc.v2.SignatureVerificationService
Method: VerifySignature
Type: Unary RPC
Use Cases
Pre-Execution Validation
async function validateBeforeExecution(
transactionBytes: Uint8Array,
signature: Uint8Array,
publicKey: Uint8Array,
scheme: SignatureScheme
): Promise<boolean> {
const verification = await verifySignature(
transactionBytes,
signature,
publicKey,
scheme
);
if (!verification.isValid) {
console.error('Cannot execute: Invalid signature');
console.error('Reason:', verification.error);
return false;
}
console.log('Signature verified, safe to execute');
return true;
}
// Usage
const canExecute = await validateBeforeExecution(
txBytes,
signatureBytes,
publicKeyBytes,
SignatureScheme.ED25519
);
if (canExecute) {
await executeTransaction(txBytes, signatureBytes, publicKeyBytes);
}Multi-Signature Verification
interface SignerInfo {
publicKey: Uint8Array;
signature: Uint8Array;
scheme: SignatureScheme;
}
async function verifyMultiSig(
transactionBytes: Uint8Array,
signers: SignerInfo[],
threshold: number
): Promise<{
isValid: boolean;
validSignatures: number;
invalidSigners: number[];
}> {
const verificationPromises = signers.map((signer, index) =>
verifySignature(
transactionBytes,
signer.signature,
signer.publicKey,
signer.scheme
)
.then(result => ({ index, ...result }))
.catch(() => ({ index, isValid: false, error: 'Verification failed' }))
);
const results = await Promise.all(verificationPromises);
const validSignatures = results.filter(r => r.isValid).length;
const invalidSigners = results.filter(r => !r.isValid).map(r => r.index);
return {
isValid: validSignatures >= threshold,
validSignatures,
invalidSigners
};
}
// Usage - 2 of 3 multisig
const signers: SignerInfo[] = [
{ publicKey: pk1, signature: sig1, scheme: SignatureScheme.ED25519 },
{ publicKey: pk2, signature: sig2, scheme: SignatureScheme.ED25519 },
{ publicKey: pk3, signature: sig3, scheme: SignatureScheme.ED25519 }
];
const multiSigResult = await verifyMultiSig(txBytes, signers, 2);
if (multiSigResult.isValid) {
console.log(`Valid: ${multiSigResult.validSignatures}/3 signatures`);
} else {
console.error('Insufficient valid signatures');
console.error('Invalid signers:', multiSigResult.invalidSigners);
}Signature Scheme Detection
async function detectAndVerifySignature(
transactionBytes: Uint8Array,
signature: Uint8Array,
publicKey: Uint8Array
): Promise<{ scheme: SignatureScheme; isValid: boolean } | null> {
const schemes = [
SignatureScheme.ED25519,
SignatureScheme.SECP256K1,
SignatureScheme.SECP256R1
];
for (const scheme of schemes) {
try {
const result = await verifySignature(
transactionBytes,
signature,
publicKey,
scheme
);
if (result.isValid) {
return { scheme, isValid: true };
}
} catch (error) {
// Try next scheme
continue;
}
}
return null;
}
// Usage
const detection = await detectAndVerifySignature(txBytes, sig, pubKey);
if (detection) {
console.log(`Valid signature using ${SignatureScheme[detection.scheme]}`);
} else {
console.error('No valid signature scheme found');
}Transaction Replay Protection
class SignatureValidator {
private verifiedSignatures = new Set<string>();
async verifyOnce(
transactionBytes: Uint8Array,
signature: Uint8Array,
publicKey: Uint8Array,
scheme: SignatureScheme
): Promise<boolean> {
// Create unique key for this transaction+signature
const key = this.createSignatureKey(transactionBytes, signature);
if (this.verifiedSignatures.has(key)) {
console.warn('Signature already used (replay attempt detected)');
return false;
}
const result = await verifySignature(
transactionBytes,
signature,
publicKey,
scheme
);
if (result.isValid) {
this.verifiedSignatures.add(key);
return true;
}
return false;
}
private createSignatureKey(tx: Uint8Array, sig: Uint8Array): string {
// Simple concatenation - use proper hash in production
return `${Array.from(tx).join(',')}_${Array.from(sig).join(',')}`;
}
clear(): void {
this.verifiedSignatures.clear();
}
}
// Usage
const validator = new SignatureValidator();
const isValid = await validator.verifyOnce(txBytes, sig, pubKey, scheme);
const isDuplicate = await validator.verifyOnce(txBytes, sig, pubKey, scheme);
console.log('First verification:', isValid);
console.log('Second verification (replay):', isDuplicate); // falseBatch Signature Verification
interface BatchVerificationItem {
transactionBytes: Uint8Array;
signature: Uint8Array;
publicKey: Uint8Array;
scheme: SignatureScheme;
id: string;
}
async function batchVerifySignatures(
items: BatchVerificationItem[]
): Promise<Map<string, boolean>> {
const results = new Map<string, boolean>();
const verifications = items.map(async item => {
try {
const result = await verifySignature(
item.transactionBytes,
item.signature,
item.publicKey,
item.scheme
);
results.set(item.id, result.isValid);
} catch (error) {
results.set(item.id, false);
}
});
await Promise.all(verifications);
return results;
}
// Usage
const batch: BatchVerificationItem[] = [
{ id: 'tx1', transactionBytes: tx1, signature: sig1, publicKey: pk1, scheme: SignatureScheme.ED25519 },
{ id: 'tx2', transactionBytes: tx2, signature: sig2, publicKey: pk2, scheme: SignatureScheme.ED25519 },
{ id: 'tx3', transactionBytes: tx3, signature: sig3, publicKey: pk3, scheme: SignatureScheme.SECP256K1 }
];
const results = await batchVerifySignatures(batch);
for (const [id, isValid] of results) {
console.log(`${id}: ${isValid ? 'Valid' : 'Invalid'}`);
}Best Practices
Always Verify Before Execute
async function safeExecuteTransaction(
transactionBytes: Uint8Array,
signature: Uint8Array,
publicKey: Uint8Array,
scheme: SignatureScheme
): Promise<any> {
// Step 1: Verify signature
const verification = await verifySignature(
transactionBytes,
signature,
publicKey,
scheme
);
if (!verification.isValid) {
throw new Error(`Invalid signature: ${verification.error}`);
}
// Step 2: Execute only if valid
return await executeTransaction(transactionBytes, signature, publicKey);
}Handle Verification Errors Gracefully
async function verifySignatureSafe(
transactionBytes: Uint8Array,
signature: Uint8Array,
publicKey: Uint8Array,
scheme: SignatureScheme
): Promise<{ isValid: boolean; error?: string }> {
try {
return await verifySignature(transactionBytes, signature, publicKey, scheme);
} catch (error: any) {
console.error('Signature verification failed:', error.message);
return {
isValid: false,
error: error.message
};
}
}Cache Verification Results
class VerificationCache {
private cache = new Map<string, { isValid: boolean; timestamp: number }>();
private ttl = 60000; // 1 minute
async verify(
transactionBytes: Uint8Array,
signature: Uint8Array,
publicKey: Uint8Array,
scheme: SignatureScheme
): Promise<boolean> {
const key = this.createKey(transactionBytes, signature, publicKey);
const cached = this.cache.get(key);
if (cached && Date.now() - cached.timestamp < this.ttl) {
return cached.isValid;
}
const result = await verifySignature(
transactionBytes,
signature,
publicKey,
scheme
);
this.cache.set(key, {
isValid: result.isValid,
timestamp: Date.now()
});
return result.isValid;
}
private createKey(tx: Uint8Array, sig: Uint8Array, pk: Uint8Array): string {
return `${tx.length}_${sig.length}_${pk.length}`;
}
}Performance Characteristics
| Metric | Value |
|---|---|
| Typical Latency | 10-30ms |
| Response Size | Less than 100 bytes |
| Cache Recommended | Yes (short TTL) |
| Rate Limit Impact | Low |
Signature Scheme Comparison
| Scheme | Security | Performance | Use Case |
|---|---|---|---|
| ED25519 | High | Fast | General purpose, recommended |
| SECP256K1 | High | Moderate | Ethereum compatibility |
| SECP256R1 | High | Moderate | WebAuthn, mobile devices |
| MULTISIG | High | Slower | Multi-party approval |
Common Errors
| Error Code | Scenario | Solution |
|---|---|---|
INVALID_ARGUMENT | Malformed signature or key | Verify byte encoding |
FAILED_PRECONDITION | Invalid scheme for key type | Match scheme to key type |
UNAUTHENTICATED | Missing/invalid token | Verify x-api-key header |
Related Methods
- ExecuteTransaction - Execute verified transactions
- SimulateTransaction - Test transactions before signing
Need help? Contact support@dwellir.com or check the gRPC overview.
GetPackage
Retrieve comprehensive Move package information via gRPC including modules, functions, and datatypes. Essential for smart contract exploration with Dwellir.
GetBalance
Query Sui coin balances efficiently using the gRPC GetBalance method. Check SUI and custom token balances with high-performance binary serialization through Dwellir's Sui infrastructure.