Verify Signature
Pre-Alpha Disclaimer: This is an early pre-alpha release for exploring the SDK and starting development only. There is no real MPC signing — all signatures are generated by a single mock signer, not a distributed network. Do not submit any real transactions for signing or rely on any security guarantees. The dWallet keys, trust model, and signing protocol are not final; do not rely on any key material until mainnet. All interfaces, APIs, and data formats are subject to change without notice. The Solana program and all on-chain data will be wiped periodically and everything will be deleted when we transition to Ika Alpha 1. This software is provided “as is” without warranty of any kind; use is entirely at your own risk and dWallet Labs assumes no liability for any damages arising from its use.
Reading the Signature
After the Ika network signs, the MessageApproval account is updated with the signature. You can read it from any client.
MessageApproval Account Layout
| Offset | Field | Size | Description |
|---|---|---|---|
| 0 | discriminator | 1 | 14 |
| 1 | version | 1 | 1 |
| 2 | dwallet | 32 | dWallet pubkey |
| 34 | message_hash | 32 | Message hash that was signed |
| 66 | user_pubkey | 32 | User public key |
| 98 | signature_scheme | 1 | Ed25519(0), Secp256k1(1), Secp256r1(2) |
| 99 | caller_program | 32 | Program that approved |
| 131 | cpi_authority | 32 | CPI authority PDA |
| 163 | (internal fields) | … | … |
| 139 | status | 1 | Pending(0) or Signed(1) |
| 140 | signature_len | 2 | Signature byte count (LE u16) |
| 142 | signature | 128 | Signature bytes (padded) |
Total: 287 bytes (2 + 285).
Polling for Signature Completion
#![allow(unused)]
fn main() {
use solana_rpc_client::rpc_client::RpcClient;
fn wait_for_signature(client: &RpcClient, message_approval: &Pubkey) -> Vec<u8> {
loop {
let data = client.get_account(message_approval).unwrap().data;
let status = data[139];
if status == 1 { // Signed
let sig_len = u16::from_le_bytes(
data[140..142].try_into().unwrap()
) as usize;
return data[142..142 + sig_len].to_vec();
}
std::thread::sleep(Duration::from_millis(500));
}
}
}
Signature Verification
The signature can be verified against the dWallet’s public key using standard cryptographic libraries. The verification algorithm depends on the signature scheme:
#![allow(unused)]
fn main() {
// Ed25519 verification example
use ed25519_dalek::{Signature, VerifyingKey};
let verifying_key = VerifyingKey::from_bytes(&dwallet_public_key)?;
let signature = Signature::from_bytes(&signature_bytes)?;
verifying_key.verify_strict(&message_hash, &signature)?;
}
For Secp256k1 (Bitcoin/Ethereum):
#![allow(unused)]
fn main() {
use secp256k1::{Message, PublicKey, Secp256k1, ecdsa::Signature};
let secp = Secp256k1::verification_only();
let pubkey = PublicKey::from_slice(&dwallet_public_key)?;
let message = Message::from_digest(message_hash);
let signature = Signature::from_compact(&signature_bytes)?;
secp.verify_ecdsa(&message, &signature, &pubkey)?;
}
E2E Flow Summary
The complete lifecycle from the E2E demo:
1. Create dWallet (CommitDWallet) → dWallet PDA created
2. Transfer authority to CPI PDA → dWallet.authority = CPI PDA
3. Create proposal (message_hash, quorum=3) → Proposal PDA created
4. Vote 1: Alice votes YES → VoteRecord created, yes_votes=1
5. Vote 2: Bob votes YES → VoteRecord created, yes_votes=2
6. Vote 3: Charlie votes YES (triggers quorum) → MessageApproval created (Pending)
7. NOA signs and commits → MessageApproval updated (Signed)
8. Read signature from MessageApproval → 64-byte Ed25519 signature
Next Step
The next chapter covers testing the voting program at different levels.