Skip to main content

keymaster_multisig/
types.rs

1use crate::error::{MultisigError, Result};
2use serde::{Deserialize, Serialize};
3use sha2::{Digest, Sha256};
4use wasm_bindgen::prelude::*;
5
6#[wasm_bindgen]
7#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
8pub struct PublicKey {
9    #[wasm_bindgen(skip)]
10    pub key: Vec<u8>,
11}
12
13#[wasm_bindgen]
14impl PublicKey {
15    #[wasm_bindgen(constructor)]
16    pub fn new(key: Vec<u8>) -> PublicKey {
17        PublicKey { key }
18    }
19    pub fn to_bytes(&self) -> Vec<u8> {
20        self.key.clone()
21    }
22}
23
24#[wasm_bindgen]
25#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
26pub struct PrivateKey {
27    #[wasm_bindgen(skip)]
28    pub key: Vec<u8>,
29}
30
31#[wasm_bindgen]
32impl PrivateKey {
33    #[wasm_bindgen(constructor)]
34    pub fn new(key: Vec<u8>) -> PrivateKey {
35        PrivateKey { key }
36    }
37    pub fn to_bytes(&self) -> Vec<u8> {
38        self.key.clone()
39    }
40}
41
42#[wasm_bindgen]
43#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
44pub struct TransactionOutput {
45    pub satoshis: u64,
46    #[wasm_bindgen(skip)]
47    pub locking_script: Vec<u8>,
48}
49
50#[wasm_bindgen]
51impl TransactionOutput {
52    #[wasm_bindgen(constructor)]
53    pub fn new(satoshis: u64, locking_script: Vec<u8>) -> TransactionOutput {
54        TransactionOutput {
55            satoshis,
56            locking_script,
57        }
58    }
59}
60
61#[wasm_bindgen]
62#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
63pub struct TransactionInput {
64    #[wasm_bindgen(skip)]
65    pub source_txid: String,
66    pub source_output_index: u32,
67    #[wasm_bindgen(skip)]
68    pub unlocking_script: Vec<u8>,
69    pub sequence: u32,
70    #[wasm_bindgen(skip)]
71    pub source_output: Option<TransactionOutput>,
72}
73
74#[wasm_bindgen]
75impl TransactionInput {
76    #[wasm_bindgen(constructor)]
77    pub fn new(source_txid: String, source_output_index: u32, sequence: u32) -> TransactionInput {
78        TransactionInput {
79            source_txid,
80            source_output_index,
81            unlocking_script: Vec::new(),
82            sequence,
83            source_output: None,
84        }
85    }
86}
87
88#[wasm_bindgen]
89#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
90pub struct Transaction {
91    pub version: u32,
92    #[wasm_bindgen(skip)]
93    pub inputs: Vec<TransactionInput>,
94    #[wasm_bindgen(skip)]
95    pub outputs: Vec<TransactionOutput>,
96    pub lock_time: u32,
97}
98
99#[wasm_bindgen]
100impl Transaction {
101    #[wasm_bindgen(constructor)]
102    pub fn new(
103        version: u32,
104        inputs: Vec<TransactionInput>,
105        outputs: Vec<TransactionOutput>,
106        lock_time: u32,
107    ) -> Transaction {
108        Transaction {
109            version,
110            inputs,
111            outputs,
112            lock_time,
113        }
114    }
115}
116
117impl Transaction {
118    pub fn serialize(&self) -> Result<Vec<u8>> {
119        let mut result = Vec::new();
120        result.extend_from_slice(&self.version.to_le_bytes());
121        result.extend(encode_varint(self.inputs.len() as u64));
122        for input in &self.inputs {
123            let mut txid = hex::decode(&input.source_txid)
124                .map_err(|_| MultisigError::TransactionError("Invalid source txid".to_string()))?;
125            if txid.len() != 32 {
126                return Err(MultisigError::TransactionError(
127                    "Invalid source txid length".to_string(),
128                ));
129            }
130            txid.reverse();
131            result.extend(txid);
132            result.extend_from_slice(&input.source_output_index.to_le_bytes());
133            result.extend(encode_varint(input.unlocking_script.len() as u64));
134            result.extend(&input.unlocking_script);
135            result.extend_from_slice(&input.sequence.to_le_bytes());
136        }
137        result.extend(encode_varint(self.outputs.len() as u64));
138        for output in &self.outputs {
139            result.extend_from_slice(&output.satoshis.to_le_bytes());
140            result.extend(encode_varint(output.locking_script.len() as u64));
141            result.extend(&output.locking_script);
142        }
143        result.extend_from_slice(&self.lock_time.to_le_bytes());
144        Ok(result)
145    }
146
147    pub fn to_hex(&self) -> Result<String> {
148        Ok(hex::encode(self.serialize()?))
149    }
150
151    pub fn from_hex(value: &str) -> Result<Transaction> {
152        let bytes = hex::decode(value).map_err(|_| {
153            MultisigError::SerializationError("Invalid transaction hex".to_string())
154        })?;
155        let (transaction, offset) = Transaction::from_bytes(&bytes)?;
156        if offset != bytes.len() {
157            return Err(MultisigError::SerializationError(
158                "Trailing transaction bytes".to_string(),
159            ));
160        }
161        Ok(transaction)
162    }
163
164    pub fn from_bytes(bytes: &[u8]) -> Result<(Transaction, usize)> {
165        let mut cursor = Cursor { bytes, offset: 0 };
166        let version = cursor.read_u32()?;
167        let input_count = cursor.read_varint()? as usize;
168        let mut inputs = Vec::with_capacity(input_count);
169        for _ in 0..input_count {
170            let mut txid = cursor.read_exact(32)?.to_vec();
171            txid.reverse();
172            let source_output_index = cursor.read_u32()?;
173            let script_len = cursor.read_varint()? as usize;
174            let unlocking_script = cursor.read_exact(script_len)?.to_vec();
175            let sequence = cursor.read_u32()?;
176            inputs.push(TransactionInput {
177                source_txid: hex::encode(txid),
178                source_output_index,
179                unlocking_script,
180                sequence,
181                source_output: None,
182            });
183        }
184        let output_count = cursor.read_varint()? as usize;
185        let mut outputs = Vec::with_capacity(output_count);
186        for _ in 0..output_count {
187            let satoshis = cursor.read_u64()?;
188            let script_len = cursor.read_varint()? as usize;
189            let locking_script = cursor.read_exact(script_len)?.to_vec();
190            outputs.push(TransactionOutput {
191                satoshis,
192                locking_script,
193            });
194        }
195        let lock_time = cursor.read_u32()?;
196        Ok((
197            Transaction {
198                version,
199                inputs,
200                outputs,
201                lock_time,
202            },
203            cursor.offset,
204        ))
205    }
206
207    pub fn txid(&self) -> Result<String> {
208        let first = Sha256::digest(self.serialize()?);
209        let second = Sha256::digest(first);
210        Ok(hex::encode(
211            second.iter().rev().copied().collect::<Vec<u8>>(),
212        ))
213    }
214}
215
216#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
217pub struct Utxo {
218    pub txid: String,
219    pub vout: u32,
220    pub satoshis: u64,
221}
222
223#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
224pub struct MultisigConfig {
225    pub public_keys: Vec<PublicKey>,
226    pub m: usize,
227    pub sig_hash_type: u8,
228}
229
230#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
231pub struct Signature {
232    pub r: Vec<u8>,
233    pub s: Vec<u8>,
234    pub sighash_type: u8,
235}
236
237pub fn encode_varint(value: u64) -> Vec<u8> {
238    match value {
239        0..=0xfc => vec![value as u8],
240        0xfd..=0xffff => {
241            let mut v = vec![0xfd];
242            v.extend_from_slice(&(value as u16).to_le_bytes());
243            v
244        }
245        0x10000..=0xffff_ffff => {
246            let mut v = vec![0xfe];
247            v.extend_from_slice(&(value as u32).to_le_bytes());
248            v
249        }
250        _ => {
251            let mut v = vec![0xff];
252            v.extend_from_slice(&value.to_le_bytes());
253            v
254        }
255    }
256}
257
258struct Cursor<'a> {
259    bytes: &'a [u8],
260    offset: usize,
261}
262impl<'a> Cursor<'a> {
263    fn read_exact(&mut self, length: usize) -> Result<&'a [u8]> {
264        let end = self.offset.checked_add(length).ok_or_else(|| {
265            MultisigError::SerializationError("Transaction length overflow".to_string())
266        })?;
267        if end > self.bytes.len() {
268            return Err(MultisigError::SerializationError(
269                "Unexpected end of transaction".to_string(),
270            ));
271        }
272        let value = &self.bytes[self.offset..end];
273        self.offset = end;
274        Ok(value)
275    }
276    fn read_u32(&mut self) -> Result<u32> {
277        Ok(u32::from_le_bytes(self.read_exact(4)?.try_into().unwrap()))
278    }
279    fn read_u64(&mut self) -> Result<u64> {
280        Ok(u64::from_le_bytes(self.read_exact(8)?.try_into().unwrap()))
281    }
282    fn read_varint(&mut self) -> Result<u64> {
283        let prefix = self.read_exact(1)?[0];
284        match prefix {
285            0xfd => Ok(u16::from_le_bytes(self.read_exact(2)?.try_into().unwrap()) as u64),
286            0xfe => Ok(u32::from_le_bytes(self.read_exact(4)?.try_into().unwrap()) as u64),
287            0xff => Ok(u64::from_le_bytes(self.read_exact(8)?.try_into().unwrap())),
288            value => Ok(value as u64),
289        }
290    }
291}