1use std::collections::BTreeMap;
4
5pub const PSBT_MAGIC: [u8; 5] = [0x70, 0x73, 0x62, 0x74, 0xff];
7
8pub const PSBT_SEPARATOR: u8 = 0x00;
10
11pub const PSBT_GLOBAL_UNSIGNED_TX: u8 = 0x00;
13pub const PSBT_GLOBAL_XPUB: u8 = 0x01;
14pub const PSBT_GLOBAL_TX_VERSION: u8 = 0x02;
15pub const PSBT_GLOBAL_FALLBACK_LOCKTIME: u8 = 0x03;
16pub const PSBT_GLOBAL_INPUT_COUNT: u8 = 0x04;
17pub const PSBT_GLOBAL_OUTPUT_COUNT: u8 = 0x05;
18pub const PSBT_GLOBAL_TX_MODIFIABLE: u8 = 0x06;
19pub const PSBT_GLOBAL_VERSION: u8 = 0xFB;
20pub const PSBT_GLOBAL_PROPRIETARY: u8 = 0xFC;
21
22pub const PSBT_IN_NON_WITNESS_UTXO: u8 = 0x00;
24pub const PSBT_IN_WITNESS_UTXO: u8 = 0x01;
25pub const PSBT_IN_PARTIAL_SIG: u8 = 0x02;
26pub const PSBT_IN_SIGHASH_TYPE: u8 = 0x03;
27pub const PSBT_IN_REDEEM_SCRIPT: u8 = 0x04;
28pub const PSBT_IN_WITNESS_SCRIPT: u8 = 0x05;
29pub const PSBT_IN_BIP32_DERIVATION: u8 = 0x06;
30pub const PSBT_IN_FINAL_SCRIPTSIG: u8 = 0x07;
31pub const PSBT_IN_FINAL_SCRIPTWITNESS: u8 = 0x08;
32pub const PSBT_IN_POR_COMMITMENT: u8 = 0x09;
33pub const PSBT_IN_RIPEMD160: u8 = 0x0A;
34pub const PSBT_IN_SHA256: u8 = 0x0B;
35pub const PSBT_IN_HASH160: u8 = 0x0C;
36pub const PSBT_IN_HASH256: u8 = 0x0D;
37pub const PSBT_IN_PREVIOUS_TXID: u8 = 0x0E;
38pub const PSBT_IN_OUTPUT_INDEX: u8 = 0x0F;
39pub const PSBT_IN_SEQUENCE: u8 = 0x10;
40pub const PSBT_IN_REQUIRED_TIME_LOCKTIME: u8 = 0x11;
41pub const PSBT_IN_REQUIRED_HEIGHT_LOCKTIME: u8 = 0x12;
42pub const PSBT_IN_TAP_KEY_SIG: u8 = 0x13;
43pub const PSBT_IN_TAP_SCRIPT_SIG: u8 = 0x14;
44pub const PSBT_IN_TAP_LEAF_SCRIPT: u8 = 0x15;
45pub const PSBT_IN_TAP_BIP32_DERIVATION: u8 = 0x16;
46pub const PSBT_IN_TAP_INTERNAL_KEY: u8 = 0x17;
47pub const PSBT_IN_TAP_MERKLE_ROOT: u8 = 0x18;
48pub const PSBT_IN_PROPRIETARY: u8 = 0xFC;
49
50pub const PSBT_OUT_REDEEM_SCRIPT: u8 = 0x00;
52pub const PSBT_OUT_WITNESS_SCRIPT: u8 = 0x01;
53pub const PSBT_OUT_BIP32_DERIVATION: u8 = 0x02;
54pub const PSBT_OUT_AMOUNT: u8 = 0x03;
55pub const PSBT_OUT_SCRIPT: u8 = 0x04;
56pub const PSBT_OUT_TAP_INTERNAL_KEY: u8 = 0x05;
57pub const PSBT_OUT_TAP_TREE: u8 = 0x06;
58pub const PSBT_OUT_TAP_BIP32_DERIVATION: u8 = 0x07;
59pub const PSBT_OUT_PROPRIETARY: u8 = 0xFC;
60
61#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
63pub enum PsbtSighashType {
64 #[default]
66 All,
67 None,
69 Single,
71 AllAnyoneCanPay,
73 NoneAnyoneCanPay,
75 SingleAnyoneCanPay,
77 Default,
79}
80
81impl PsbtSighashType {
82 pub fn to_u32(self) -> u32 {
84 match self {
85 Self::All => 0x01,
86 Self::None => 0x02,
87 Self::Single => 0x03,
88 Self::AllAnyoneCanPay => 0x81,
89 Self::NoneAnyoneCanPay => 0x82,
90 Self::SingleAnyoneCanPay => 0x83,
91 Self::Default => 0x00,
92 }
93 }
94
95 pub fn from_u32(value: u32) -> Option<Self> {
97 match value {
98 0x00 => Some(Self::Default),
99 0x01 => Some(Self::All),
100 0x02 => Some(Self::None),
101 0x03 => Some(Self::Single),
102 0x81 => Some(Self::AllAnyoneCanPay),
103 0x82 => Some(Self::NoneAnyoneCanPay),
104 0x83 => Some(Self::SingleAnyoneCanPay),
105 _ => None,
106 }
107 }
108}
109
110#[derive(Debug, Clone, PartialEq, Eq)]
112pub struct KeySource {
113 pub fingerprint: [u8; 4],
115 pub path: Vec<u32>,
117}
118
119impl KeySource {
120 pub fn new(fingerprint: [u8; 4], path: Vec<u32>) -> Self {
122 Self { fingerprint, path }
123 }
124
125 pub fn to_bytes(&self) -> Vec<u8> {
127 let mut bytes = Vec::with_capacity(4 + self.path.len() * 4);
128 bytes.extend_from_slice(&self.fingerprint);
129 for &index in &self.path {
130 bytes.extend_from_slice(&index.to_le_bytes());
131 }
132 bytes
133 }
134
135 pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
137 if bytes.len() < 4 || !((bytes.len() - 4).is_multiple_of(4)) {
138 return None;
139 }
140
141 let mut fingerprint = [0u8; 4];
142 fingerprint.copy_from_slice(&bytes[0..4]);
143
144 let path_len = (bytes.len() - 4) / 4;
145 let mut path = Vec::with_capacity(path_len);
146 for i in 0..path_len {
147 let start = 4 + i * 4;
148 let index = u32::from_le_bytes([
149 bytes[start],
150 bytes[start + 1],
151 bytes[start + 2],
152 bytes[start + 3],
153 ]);
154 path.push(index);
155 }
156
157 Some(Self { fingerprint, path })
158 }
159
160 pub fn path_string(&self) -> String {
162 let mut s = String::from("m");
163 for &index in &self.path {
164 if index >= 0x80000000 {
165 s.push_str(&format!("/{}'", index - 0x80000000));
166 } else {
167 s.push_str(&format!("/{}", index));
168 }
169 }
170 s
171 }
172}
173
174#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
176pub struct ProprietaryKey {
177 pub prefix: Vec<u8>,
179 pub subtype: u8,
181 pub key: Vec<u8>,
183}
184
185impl ProprietaryKey {
186 pub fn new(prefix: Vec<u8>, subtype: u8, key: Vec<u8>) -> Self {
188 Self { prefix, subtype, key }
189 }
190
191 pub fn to_bytes(&self) -> Vec<u8> {
193 let mut bytes = Vec::new();
194 bytes.push(self.prefix.len() as u8);
196 bytes.extend_from_slice(&self.prefix);
197 bytes.push(self.subtype);
198 bytes.extend_from_slice(&self.key);
199 bytes
200 }
201
202 pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
204 if bytes.is_empty() {
205 return None;
206 }
207
208 let prefix_len = bytes[0] as usize;
209 if bytes.len() < 1 + prefix_len + 1 {
210 return None;
211 }
212
213 let prefix = bytes[1..1 + prefix_len].to_vec();
214 let subtype = bytes[1 + prefix_len];
215 let key = bytes[2 + prefix_len..].to_vec();
216
217 Some(Self { prefix, subtype, key })
218 }
219}
220
221#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
223pub struct RawKey {
224 pub key_type: u8,
226 pub key_data: Vec<u8>,
228}
229
230impl RawKey {
231 pub fn new(key_type: u8, key_data: Vec<u8>) -> Self {
233 Self { key_type, key_data }
234 }
235
236 pub fn type_only(key_type: u8) -> Self {
238 Self {
239 key_type,
240 key_data: Vec::new(),
241 }
242 }
243}
244
245pub type UnknownFields = BTreeMap<RawKey, Vec<u8>>;
247
248pub type ProprietaryFields = BTreeMap<ProprietaryKey, Vec<u8>>;
250
251#[cfg(test)]
252mod tests {
253 use super::*;
254
255 #[test]
256 fn test_sighash_type_roundtrip() {
257 let types = [
258 PsbtSighashType::All,
259 PsbtSighashType::None,
260 PsbtSighashType::Single,
261 PsbtSighashType::AllAnyoneCanPay,
262 PsbtSighashType::NoneAnyoneCanPay,
263 PsbtSighashType::SingleAnyoneCanPay,
264 PsbtSighashType::Default,
265 ];
266
267 for sighash in types {
268 let value = sighash.to_u32();
269 let parsed = PsbtSighashType::from_u32(value).unwrap();
270 assert_eq!(sighash, parsed);
271 }
272 }
273
274 #[test]
275 fn test_key_source_roundtrip() {
276 let source = KeySource::new(
277 [0x01, 0x02, 0x03, 0x04],
278 vec![0x80000054, 0x80000000, 0x80000000, 0, 0],
279 );
280
281 let bytes = source.to_bytes();
282 let parsed = KeySource::from_bytes(&bytes).unwrap();
283
284 assert_eq!(source, parsed);
285 assert_eq!(parsed.path_string(), "m/84'/0'/0'/0/0");
286 }
287
288 #[test]
289 fn test_proprietary_key_roundtrip() {
290 let key = ProprietaryKey::new(b"test".to_vec(), 0x01, b"data".to_vec());
291 let bytes = key.to_bytes();
292 let parsed = ProprietaryKey::from_bytes(&bytes).unwrap();
293 assert_eq!(key, parsed);
294 }
295}