1use crate::governance::error::{GovernanceError, GovernanceResult};
9use serde::{Deserialize, Serialize};
10use std::collections::HashMap;
11
12type PsbtRawMap = HashMap<Vec<u8>, Vec<u8>>;
14
15pub const PSBT_MAGIC: [u8; 4] = [0x70, 0x73, 0x62, 0x74];
17
18pub const PSBT_SEPARATOR: u8 = 0xff;
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
23pub enum PsbtGlobalKey {
24 UnsignedTx = 0x00,
26 Xpub = 0x01,
28 Version = 0xfb,
30 Proprietary = 0xfc,
32}
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
36pub enum PsbtInputKey {
37 NonWitnessUtxo = 0x00,
39 WitnessUtxo = 0x01,
41 PartialSig = 0x02,
43 SighashType = 0x03,
45 RedeemScript = 0x04,
47 WitnessScript = 0x05,
49 Bip32Derivation = 0x06,
51 FinalScriptSig = 0x07,
53 FinalScriptWitness = 0x08,
55 Proprietary = 0xfc,
57}
58
59#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
61pub enum PsbtOutputKey {
62 RedeemScript = 0x00,
64 WitnessScript = 0x01,
66 Bip32Derivation = 0x02,
68 Proprietary = 0xfc,
70}
71
72#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
74pub struct Bip32Derivation {
75 pub pubkey: Vec<u8>,
77 pub path: Vec<u32>,
79 pub master_fingerprint: [u8; 4],
81}
82
83#[derive(Debug, Clone, PartialEq, Eq)]
85pub struct PartialSignature {
86 pub pubkey: Vec<u8>,
88 pub signature: Vec<u8>,
90}
91
92#[derive(Debug, Clone, Copy, PartialEq, Eq)]
94pub enum SighashType {
95 All = 0x01,
97 None = 0x02,
99 Single = 0x03,
101 AllAnyoneCanPay = 0x81,
103 NoneAnyoneCanPay = 0x82,
105 SingleAnyoneCanPay = 0x83,
107}
108
109impl SighashType {
110 pub fn from_byte(byte: u8) -> Option<Self> {
112 match byte {
113 0x01 => Some(SighashType::All),
114 0x02 => Some(SighashType::None),
115 0x03 => Some(SighashType::Single),
116 0x81 => Some(SighashType::AllAnyoneCanPay),
117 0x82 => Some(SighashType::NoneAnyoneCanPay),
118 0x83 => Some(SighashType::SingleAnyoneCanPay),
119 _ => None,
120 }
121 }
122
123 pub fn to_byte(self) -> u8 {
125 self as u8
126 }
127}
128
129#[derive(Debug, Clone, PartialEq, Eq)]
131pub struct PartiallySignedTransaction {
132 pub global: HashMap<Vec<u8>, Vec<u8>>,
134 pub inputs: Vec<HashMap<Vec<u8>, Vec<u8>>>,
136 pub outputs: Vec<HashMap<Vec<u8>, Vec<u8>>>,
138 pub version: u8,
140}
141
142impl PartiallySignedTransaction {
143 pub fn new(unsigned_tx: &[u8]) -> GovernanceResult<Self> {
145 let mut global = HashMap::new();
146 global.insert(vec![PsbtGlobalKey::UnsignedTx as u8], unsigned_tx.to_vec());
147 global.insert(vec![PsbtGlobalKey::Version as u8], vec![0x00]); Ok(PartiallySignedTransaction {
150 global,
151 inputs: Vec::new(),
152 outputs: Vec::new(),
153 version: 0,
154 })
155 }
156
157 pub fn add_input_data(
159 &mut self,
160 input_index: usize,
161 key: Vec<u8>,
162 value: Vec<u8>,
163 ) -> GovernanceResult<()> {
164 if input_index >= self.inputs.len() {
165 while self.inputs.len() <= input_index {
167 self.inputs.push(HashMap::new());
168 }
169 }
170 self.inputs[input_index].insert(key, value);
171 Ok(())
172 }
173
174 pub fn add_output_data(
176 &mut self,
177 output_index: usize,
178 key: Vec<u8>,
179 value: Vec<u8>,
180 ) -> GovernanceResult<()> {
181 if output_index >= self.outputs.len() {
182 while self.outputs.len() <= output_index {
184 self.outputs.push(HashMap::new());
185 }
186 }
187 self.outputs[output_index].insert(key, value);
188 Ok(())
189 }
190
191 pub fn add_partial_signature(
193 &mut self,
194 input_index: usize,
195 pubkey: Vec<u8>,
196 signature: Vec<u8>,
197 ) -> GovernanceResult<()> {
198 let mut key = vec![PsbtInputKey::PartialSig as u8];
200 key.extend_from_slice(&pubkey);
201
202 let mut value = Vec::with_capacity(1 + signature.len());
203 value.push(signature.len() as u8);
204 value.extend_from_slice(&signature);
205
206 self.add_input_data(input_index, key, value)
207 }
208
209 pub fn add_bip32_derivation(
211 &mut self,
212 input_index: usize,
213 pubkey: Vec<u8>,
214 derivation: Bip32Derivation,
215 ) -> GovernanceResult<()> {
216 let mut key = vec![PsbtInputKey::Bip32Derivation as u8];
217 key.extend_from_slice(&pubkey);
218
219 let mut value = Vec::new();
221 value.extend_from_slice(&derivation.master_fingerprint);
222 value.push(derivation.path.len() as u8);
223 for &index in &derivation.path {
224 value.extend_from_slice(&index.to_be_bytes());
225 }
226
227 self.add_input_data(input_index, key, value)
228 }
229
230 pub fn set_sighash_type(
232 &mut self,
233 input_index: usize,
234 sighash_type: SighashType,
235 ) -> GovernanceResult<()> {
236 let key = vec![PsbtInputKey::SighashType as u8];
237 let value = vec![sighash_type.to_byte()];
238 self.add_input_data(input_index, key, value)
239 }
240
241 pub fn is_finalized(&self) -> bool {
243 for input_map in &self.inputs {
244 let has_final_sig = input_map.contains_key(&vec![PsbtInputKey::FinalScriptSig as u8]);
245 let has_final_witness =
246 input_map.contains_key(&vec![PsbtInputKey::FinalScriptWitness as u8]);
247
248 if !has_final_sig && !has_final_witness {
249 return false;
250 }
251 }
252 true
253 }
254
255 pub fn extract_transaction(&self) -> GovernanceResult<Vec<u8>> {
257 if !self.is_finalized() {
258 return Err(GovernanceError::InvalidInput(
259 "PSBT is not finalized".to_string(),
260 ));
261 }
262
263 let unsigned_tx_key = vec![PsbtGlobalKey::UnsignedTx as u8];
265 let unsigned_tx = self.global.get(&unsigned_tx_key).ok_or_else(|| {
266 GovernanceError::InvalidInput("Missing unsigned transaction".to_string())
267 })?;
268
269 Ok(unsigned_tx.clone())
274 }
275
276 pub fn serialize(&self) -> GovernanceResult<Vec<u8>> {
278 let mut result = Vec::new();
279
280 result.extend_from_slice(&PSBT_MAGIC);
282 result.push(PSBT_SEPARATOR);
283
284 serialize_map(&mut result, &self.global)?;
286
287 result.push(PSBT_SEPARATOR);
289
290 for input_map in &self.inputs {
292 serialize_map(&mut result, input_map)?;
293 result.push(PSBT_SEPARATOR);
294 }
295
296 for output_map in &self.outputs {
298 serialize_map(&mut result, output_map)?;
299 result.push(PSBT_SEPARATOR);
300 }
301
302 Ok(result)
303 }
304
305 pub fn deserialize(data: &[u8]) -> GovernanceResult<Self> {
307 if data.len() < 5 || data[..4] != PSBT_MAGIC || data[4] != PSBT_SEPARATOR {
308 return Err(GovernanceError::InvalidInput(
309 "Invalid PSBT magic bytes".to_string(),
310 ));
311 }
312
313 let mut offset = 5;
314
315 let (global, new_offset) = deserialize_map(&data[offset..])?;
317 offset += new_offset;
318
319 if offset >= data.len() || data[offset] != PSBT_SEPARATOR {
321 return Err(GovernanceError::InvalidInput(
322 "Missing separator after global map".to_string(),
323 ));
324 }
325 offset += 1;
326
327 let mut inputs = Vec::new();
329 while offset < data.len() && data[offset] != PSBT_SEPARATOR {
332 let (input_map, new_offset) = deserialize_map(&data[offset..])?;
333 inputs.push(input_map);
334 offset += new_offset;
335
336 if offset < data.len() && data[offset] == PSBT_SEPARATOR {
338 offset += 1;
339 break; }
341 }
342
343 let mut outputs = Vec::new();
345 while offset < data.len() {
346 if data[offset] == PSBT_SEPARATOR && offset + 1 >= data.len() {
347 break; }
349 let (output_map, new_offset) = deserialize_map(&data[offset..])?;
350 outputs.push(output_map);
351 offset += new_offset;
352
353 if offset < data.len() && data[offset] == PSBT_SEPARATOR {
354 offset += 1;
355 }
356 }
357
358 let version_key = vec![PsbtGlobalKey::Version as u8];
360 let version = global
361 .get(&version_key)
362 .and_then(|v| v.first().copied())
363 .unwrap_or(0);
364
365 Ok(PartiallySignedTransaction {
366 global,
367 inputs,
368 outputs,
369 version,
370 })
371 }
372}
373
374fn serialize_map(result: &mut Vec<u8>, map: &HashMap<Vec<u8>, Vec<u8>>) -> GovernanceResult<()> {
376 for (key, value) in map {
377 write_compact_size(result, key.len())?;
379 result.extend_from_slice(key);
380
381 write_compact_size(result, value.len())?;
383 result.extend_from_slice(value);
384 }
385
386 result.push(0x00);
388
389 Ok(())
390}
391
392fn deserialize_map(data: &[u8]) -> GovernanceResult<(PsbtRawMap, usize)> {
394 let mut map = HashMap::new();
395 let mut offset = 0;
396
397 while offset < data.len() {
398 if data[offset] == 0x00 {
400 offset += 1;
401 break;
402 }
403
404 const MAX_PSBT_KEY_LEN: usize = 520;
406 const MAX_PSBT_VALUE_LEN: usize = 520_000;
407 let (key_len, len_offset) = read_compact_size(&data[offset..])?;
408 offset += len_offset;
409 if key_len > MAX_PSBT_KEY_LEN {
410 return Err(GovernanceError::InvalidInput(format!(
411 "PSBT key too long: {key_len} bytes (max: {MAX_PSBT_KEY_LEN})"
412 )));
413 }
414
415 if offset + key_len > data.len() {
416 return Err(GovernanceError::InvalidInput(
417 "Invalid key length".to_string(),
418 ));
419 }
420 let key = data[offset..offset + key_len].to_vec();
421 offset += key_len;
422
423 let (value_len, len_offset) = read_compact_size(&data[offset..])?;
425 offset += len_offset;
426 if value_len > MAX_PSBT_VALUE_LEN {
427 return Err(GovernanceError::InvalidInput(format!(
428 "PSBT value too long: {value_len} bytes (max: {MAX_PSBT_VALUE_LEN})"
429 )));
430 }
431
432 if offset + value_len > data.len() {
433 return Err(GovernanceError::InvalidInput(
434 "Invalid value length".to_string(),
435 ));
436 }
437 let value = data[offset..offset + value_len].to_vec();
438 offset += value_len;
439
440 map.insert(key, value);
441 }
442
443 Ok((map, offset))
444}
445
446fn write_compact_size(result: &mut Vec<u8>, size: usize) -> GovernanceResult<()> {
448 if size < 0xfd {
449 result.push(size as u8);
450 } else if size <= 0xffff {
451 result.push(0xfd);
452 result.extend_from_slice(&(size as u16).to_le_bytes());
453 } else if size <= 0xffffffff {
454 result.push(0xfe);
455 result.extend_from_slice(&(size as u32).to_le_bytes());
456 } else {
457 result.push(0xff);
458 result.extend_from_slice(&(size as u64).to_le_bytes());
459 }
460 Ok(())
461}
462
463fn read_compact_size(data: &[u8]) -> GovernanceResult<(usize, usize)> {
465 if data.is_empty() {
466 return Err(GovernanceError::InvalidInput(
467 "Unexpected end of data".to_string(),
468 ));
469 }
470
471 match data[0] {
472 n if n < 0xfd => Ok((n as usize, 1)),
473 0xfd => {
474 if data.len() < 3 {
475 return Err(GovernanceError::InvalidInput(
476 "Invalid compact size".to_string(),
477 ));
478 }
479 let value = u16::from_le_bytes([data[1], data[2]]) as usize;
480 Ok((value, 3))
481 }
482 0xfe => {
483 if data.len() < 5 {
484 return Err(GovernanceError::InvalidInput(
485 "Invalid compact size".to_string(),
486 ));
487 }
488 let value = u32::from_le_bytes([data[1], data[2], data[3], data[4]]) as usize;
489 Ok((value, 5))
490 }
491 0xff => {
492 if data.len() < 9 {
493 return Err(GovernanceError::InvalidInput(
494 "Invalid compact size".to_string(),
495 ));
496 }
497 let value = u64::from_le_bytes([
498 data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8],
499 ]) as usize;
500 Ok((value, 9))
501 }
502 _ => Err(GovernanceError::InvalidInput(
503 "Invalid compact size marker".to_string(),
504 )),
505 }
506}
507
508#[cfg(test)]
509mod tests {
510 use super::*;
511
512 #[test]
513 fn test_psbt_creation() {
514 let unsigned_tx = vec![0x01, 0x00, 0x00, 0x00]; let psbt = PartiallySignedTransaction::new(&unsigned_tx).unwrap();
516
517 assert_eq!(psbt.version, 0);
518 assert!(psbt
519 .global
520 .contains_key(&vec![PsbtGlobalKey::UnsignedTx as u8]));
521 }
522
523 #[test]
524 fn test_serialize_deserialize() {
525 let unsigned_tx = vec![0x01, 0x00, 0x00, 0x00];
526 let mut psbt = PartiallySignedTransaction::new(&unsigned_tx).unwrap();
527
528 psbt.add_partial_signature(0, vec![0x02; 33], vec![0x30; 72])
530 .unwrap();
531
532 let serialized = psbt.serialize().unwrap();
533 let deserialized = PartiallySignedTransaction::deserialize(&serialized).unwrap();
534
535 assert_eq!(psbt.global, deserialized.global);
536 }
537
538 #[test]
539 fn test_compact_size_encoding() {
540 let mut result = Vec::new();
541 write_compact_size(&mut result, 253).unwrap();
542 assert_eq!(result[0], 0xfd);
543
544 let (value, offset) = read_compact_size(&result).unwrap();
545 assert_eq!(value, 253);
546 assert_eq!(offset, 3);
547 }
548}