Skip to main content

qualia_client_core/wallet/
signer.rs

1use crate::wallet::transaction::{encode_varint, Transaction};
2use bip32::XPrv;
3use k256::ecdsa::{signature::Signer, SigningKey};
4use sha2::{Digest, Sha256};
5
6pub const SIGHASH_ALL: u32 = 0x01;
7pub const SIGHASH_FORKID: u32 = 0x40;
8
9pub fn double_sha256(data: &[u8]) -> Vec<u8> {
10    let hash1 = Sha256::digest(data);
11    let hash2 = Sha256::digest(&hash1);
12    hash2.to_vec()
13}
14
15pub fn hash160(data: &[u8]) -> Vec<u8> {
16    use ripemd::{Digest as _, Ripemd160};
17    let sha = Sha256::digest(data);
18    let rip = Ripemd160::digest(&sha);
19    rip.to_vec()
20}
21
22pub fn sign_p2pkh_input(
23    tx: &Transaction,
24    input_index: usize,
25    prev_value: u64,
26    priv_key: &XPrv,
27) -> Vec<u8> {
28    let sighash_type = SIGHASH_ALL | SIGHASH_FORKID;
29
30    let mut hash_prevouts = Vec::new();
31    for input in &tx.inputs {
32        let mut txid_bytes = hex::decode(&input.prev_txid).unwrap_or_else(|_| vec![0; 32]);
33        txid_bytes.reverse();
34        hash_prevouts.extend_from_slice(&txid_bytes);
35        hash_prevouts.extend_from_slice(&input.prev_out_idx.to_le_bytes());
36    }
37    let hash_prevouts = double_sha256(&hash_prevouts);
38
39    let mut hash_sequence = Vec::new();
40    for input in &tx.inputs {
41        hash_sequence.extend_from_slice(&input.sequence.to_le_bytes());
42    }
43    let hash_sequence = double_sha256(&hash_sequence);
44
45    let mut hash_outputs = Vec::new();
46    for output in &tx.outputs {
47        hash_outputs.extend_from_slice(&output.value.to_le_bytes());
48        hash_outputs.extend_from_slice(&encode_varint(output.pk_script.len() as u64));
49        hash_outputs.extend_from_slice(&output.pk_script);
50    }
51    let hash_outputs = double_sha256(&hash_outputs);
52
53    let mut preimage = Vec::new();
54    preimage.extend_from_slice(&tx.version.to_le_bytes());
55    preimage.extend_from_slice(&hash_prevouts);
56    preimage.extend_from_slice(&hash_sequence);
57
58    let input = &tx.inputs[input_index];
59    let mut txid_bytes = hex::decode(&input.prev_txid).unwrap_or_else(|_| vec![0; 32]);
60    txid_bytes.reverse();
61    preimage.extend_from_slice(&txid_bytes);
62    preimage.extend_from_slice(&input.prev_out_idx.to_le_bytes());
63
64    // scriptCode for P2PKH: 0x19 0x76 0xa9 0x14 <pubkey_hash> 0x88 0xac
65    let pubkey = priv_key.public_key().to_bytes();
66    let pubkey_hash = hash160(&pubkey);
67    let mut script_code = vec![0x76, 0xa9, 0x14];
68    script_code.extend_from_slice(&pubkey_hash);
69    script_code.extend_from_slice(&[0x88, 0xac]);
70    preimage.extend_from_slice(&encode_varint(script_code.len() as u64));
71    preimage.extend_from_slice(&script_code);
72
73    preimage.extend_from_slice(&prev_value.to_le_bytes());
74    preimage.extend_from_slice(&input.sequence.to_le_bytes());
75    preimage.extend_from_slice(&hash_outputs);
76    preimage.extend_from_slice(&tx.lock_time.to_le_bytes());
77    preimage.extend_from_slice(&sighash_type.to_le_bytes());
78
79    let sighash = double_sha256(&preimage);
80
81    let private_key_bytes = priv_key.private_key().to_bytes();
82    let signing_key = SigningKey::from_slice(private_key_bytes.as_slice()).expect("Valid key");
83    let signature: k256::ecdsa::Signature = signing_key.sign(&sighash);
84    let mut der_sig = signature.to_der().to_bytes().to_vec();
85
86    // Append sighash type byte to DER signature
87    der_sig.push(sighash_type as u8);
88
89    // Build final scriptSig: <sig_len><sig><pubkey_len><pubkey>
90    let mut script_sig = Vec::new();
91    script_sig.push(der_sig.len() as u8);
92    script_sig.extend_from_slice(&der_sig);
93    script_sig.push(pubkey.len() as u8);
94    script_sig.extend_from_slice(&pubkey);
95
96    script_sig
97}