Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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

OffsetFieldSizeDescription
0discriminator114
1version11
2dwallet32dWallet pubkey
34message_hash32Message hash that was signed
66user_pubkey32User public key
98signature_scheme1Ed25519(0), Secp256k1(1), Secp256r1(2)
99caller_program32Program that approved
131cpi_authority32CPI authority PDA
163(internal fields)
139status1Pending(0) or Signed(1)
140signature_len2Signature byte count (LE u16)
142signature128Signature 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.