1use std::collections::HashMap;
8use std::io::{Read, Write};
9
10use crate::primitives::public_key::PublicKey;
11use crate::wallet::error::WalletError;
12use crate::wallet::types::{Counterparty, CounterpartyType, Protocol};
13
14pub mod frame;
15
16pub mod abort_action;
17pub mod acquire_certificate;
18pub mod authenticated;
19pub mod certificate_ser;
20pub mod create_action;
21pub mod create_hmac;
22pub mod create_signature;
23pub mod decrypt;
24pub mod discover_by_attributes;
25pub mod discover_by_identity_key;
26pub mod discover_certificates_result;
27pub mod encrypt;
28pub mod get_header;
29pub mod get_height;
30pub mod get_network;
31pub mod get_public_key;
32pub mod get_version;
33pub mod internalize_action;
34pub mod list_actions;
35pub mod list_certificates;
36pub mod list_outputs;
37pub mod prove_certificate;
38pub mod relinquish_certificate;
39pub mod relinquish_output;
40pub mod reveal_counterparty_key_linkage;
41pub mod reveal_specific_key_linkage;
42pub mod sign_action;
43pub mod verify_hmac;
44pub mod verify_signature;
45
46const NEGATIVE_ONE: u64 = u64::MAX;
52
53const NEGATIVE_ONE_BYTE: u8 = 0xFF;
55
56const COUNTERPARTY_UNINITIALIZED: u8 = 0x00;
58const COUNTERPARTY_SELF: u8 = 0x0B;
59const COUNTERPARTY_ANYONE: u8 = 0x0C;
60
61const SIZE_PUB_KEY: usize = 33;
63
64const SIZE_TYPE: usize = 32;
66const SIZE_SERIAL: usize = 32;
67
68pub const CALL_CREATE_ACTION: u8 = 1;
70pub const CALL_SIGN_ACTION: u8 = 2;
71pub const CALL_ABORT_ACTION: u8 = 3;
72pub const CALL_LIST_ACTIONS: u8 = 4;
73pub const CALL_INTERNALIZE_ACTION: u8 = 5;
74pub const CALL_LIST_OUTPUTS: u8 = 6;
75pub const CALL_RELINQUISH_OUTPUT: u8 = 7;
76pub const CALL_GET_PUBLIC_KEY: u8 = 8;
77pub const CALL_REVEAL_COUNTERPARTY_KEY_LINKAGE: u8 = 9;
78pub const CALL_REVEAL_SPECIFIC_KEY_LINKAGE: u8 = 10;
79pub const CALL_ENCRYPT: u8 = 11;
80pub const CALL_DECRYPT: u8 = 12;
81pub const CALL_CREATE_HMAC: u8 = 13;
82pub const CALL_VERIFY_HMAC: u8 = 14;
83pub const CALL_CREATE_SIGNATURE: u8 = 15;
84pub const CALL_VERIFY_SIGNATURE: u8 = 16;
85pub const CALL_ACQUIRE_CERTIFICATE: u8 = 17;
86pub const CALL_LIST_CERTIFICATES: u8 = 18;
87pub const CALL_PROVE_CERTIFICATE: u8 = 19;
88pub const CALL_RELINQUISH_CERTIFICATE: u8 = 20;
89pub const CALL_DISCOVER_BY_IDENTITY_KEY: u8 = 21;
90pub const CALL_DISCOVER_BY_ATTRIBUTES: u8 = 22;
91pub const CALL_IS_AUTHENTICATED: u8 = 23;
92pub const CALL_WAIT_FOR_AUTHENTICATION: u8 = 24;
93pub const CALL_GET_HEIGHT: u8 = 25;
94pub const CALL_GET_HEADER_FOR_HEIGHT: u8 = 26;
95pub const CALL_GET_NETWORK: u8 = 27;
96pub const CALL_GET_VERSION: u8 = 28;
97
98pub fn write_varint(writer: &mut impl Write, value: u64) -> Result<(), WalletError> {
104 let bytes = varint_bytes(value);
105 writer
106 .write_all(&bytes)
107 .map_err(|e| WalletError::Internal(e.to_string()))
108}
109
110pub fn read_varint(reader: &mut impl Read) -> Result<u64, WalletError> {
112 let mut first = [0u8; 1];
113 reader
114 .read_exact(&mut first)
115 .map_err(|e| WalletError::Internal(e.to_string()))?;
116 match first[0] {
117 0xff => {
118 let mut buf = [0u8; 8];
119 reader
120 .read_exact(&mut buf)
121 .map_err(|e| WalletError::Internal(e.to_string()))?;
122 Ok(u64::from_le_bytes(buf))
123 }
124 0xfe => {
125 let mut buf = [0u8; 4];
126 reader
127 .read_exact(&mut buf)
128 .map_err(|e| WalletError::Internal(e.to_string()))?;
129 Ok(u32::from_le_bytes(buf) as u64)
130 }
131 0xfd => {
132 let mut buf = [0u8; 2];
133 reader
134 .read_exact(&mut buf)
135 .map_err(|e| WalletError::Internal(e.to_string()))?;
136 Ok(u16::from_le_bytes(buf) as u64)
137 }
138 b => Ok(b as u64),
139 }
140}
141
142fn varint_bytes(value: u64) -> Vec<u8> {
144 if value < 0xfd {
145 vec![value as u8]
146 } else if value < 0x10000 {
147 let mut buf = vec![0xfd, 0, 0];
148 buf[1..3].copy_from_slice(&(value as u16).to_le_bytes());
149 buf
150 } else if value < 0x100000000 {
151 let mut buf = vec![0xfe, 0, 0, 0, 0];
152 buf[1..5].copy_from_slice(&(value as u32).to_le_bytes());
153 buf
154 } else {
155 let mut buf = vec![0xff, 0, 0, 0, 0, 0, 0, 0, 0];
156 buf[1..9].copy_from_slice(&value.to_le_bytes());
157 buf
158 }
159}
160
161pub fn write_byte(writer: &mut impl Write, b: u8) -> Result<(), WalletError> {
167 writer
168 .write_all(&[b])
169 .map_err(|e| WalletError::Internal(e.to_string()))
170}
171
172pub fn read_byte(reader: &mut impl Read) -> Result<u8, WalletError> {
174 let mut buf = [0u8; 1];
175 reader
176 .read_exact(&mut buf)
177 .map_err(|e| WalletError::Internal(e.to_string()))?;
178 Ok(buf[0])
179}
180
181pub fn write_bytes(writer: &mut impl Write, data: &[u8]) -> Result<(), WalletError> {
183 write_varint(writer, data.len() as u64)?;
184 writer
185 .write_all(data)
186 .map_err(|e| WalletError::Internal(e.to_string()))
187}
188
189pub fn read_bytes(reader: &mut impl Read) -> Result<Vec<u8>, WalletError> {
191 let len = read_varint(reader)?;
192 if len == 0 {
193 return Ok(Vec::new());
194 }
195 let mut buf = vec![0u8; len as usize];
196 reader
197 .read_exact(&mut buf)
198 .map_err(|e| WalletError::Internal(e.to_string()))?;
199 Ok(buf)
200}
201
202pub fn write_raw_bytes(writer: &mut impl Write, data: &[u8]) -> Result<(), WalletError> {
204 writer
205 .write_all(data)
206 .map_err(|e| WalletError::Internal(e.to_string()))
207}
208
209pub fn read_raw_bytes(reader: &mut impl Read, n: usize) -> Result<Vec<u8>, WalletError> {
211 let mut buf = vec![0u8; n];
212 reader
213 .read_exact(&mut buf)
214 .map_err(|e| WalletError::Internal(e.to_string()))?;
215 Ok(buf)
216}
217
218pub fn read_raw_bytes_reverse(reader: &mut impl Read, n: usize) -> Result<Vec<u8>, WalletError> {
220 let mut buf = read_raw_bytes(reader, n)?;
221 buf.reverse();
222 Ok(buf)
223}
224
225pub fn write_raw_bytes_reverse(writer: &mut impl Write, data: &[u8]) -> Result<(), WalletError> {
227 let mut reversed = data.to_vec();
228 reversed.reverse();
229 write_raw_bytes(writer, &reversed)
230}
231
232pub fn write_string(writer: &mut impl Write, s: &str) -> Result<(), WalletError> {
238 let bytes = s.as_bytes();
239 write_varint(writer, bytes.len() as u64)?;
240 writer
241 .write_all(bytes)
242 .map_err(|e| WalletError::Internal(e.to_string()))
243}
244
245pub fn read_string(reader: &mut impl Read) -> Result<String, WalletError> {
247 let len = read_varint(reader)?;
248 if len == NEGATIVE_ONE || len == 0 {
249 return Ok(String::new());
250 }
251 let mut buf = vec![0u8; len as usize];
252 reader
253 .read_exact(&mut buf)
254 .map_err(|e| WalletError::Internal(e.to_string()))?;
255 String::from_utf8(buf).map_err(|e| WalletError::Internal(e.to_string()))
256}
257
258pub fn write_optional_string(
260 writer: &mut impl Write,
261 s: &Option<String>,
262) -> Result<(), WalletError> {
263 match s {
264 Some(ref val) if !val.is_empty() => write_string(writer, val),
265 _ => write_varint(writer, NEGATIVE_ONE),
266 }
267}
268
269pub fn read_optional_string(reader: &mut impl Read) -> Result<Option<String>, WalletError> {
271 let len = read_varint(reader)?;
272 if len == NEGATIVE_ONE {
273 return Ok(None);
274 }
275 if len == 0 {
276 return Ok(Some(String::new()));
277 }
278 let mut buf = vec![0u8; len as usize];
279 reader
280 .read_exact(&mut buf)
281 .map_err(|e| WalletError::Internal(e.to_string()))?;
282 let s = String::from_utf8(buf).map_err(|e| WalletError::Internal(e.to_string()))?;
283 Ok(Some(s))
284}
285
286pub fn write_string_optional(writer: &mut impl Write, s: &str) -> Result<(), WalletError> {
289 if s.is_empty() {
290 write_varint(writer, NEGATIVE_ONE)
291 } else {
292 write_string(writer, s)
293 }
294}
295
296pub fn read_string_optional(reader: &mut impl Read) -> Result<String, WalletError> {
298 let len = read_varint(reader)?;
299 if len == NEGATIVE_ONE || len == 0 {
300 return Ok(String::new());
301 }
302 let mut buf = vec![0u8; len as usize];
303 reader
304 .read_exact(&mut buf)
305 .map_err(|e| WalletError::Internal(e.to_string()))?;
306 String::from_utf8(buf).map_err(|e| WalletError::Internal(e.to_string()))
307}
308
309pub fn write_optional_bool(writer: &mut impl Write, v: Option<bool>) -> Result<(), WalletError> {
315 match v {
316 None => write_byte(writer, NEGATIVE_ONE_BYTE),
317 Some(true) => write_byte(writer, 1),
318 Some(false) => write_byte(writer, 0),
319 }
320}
321
322pub fn read_optional_bool(reader: &mut impl Read) -> Result<Option<bool>, WalletError> {
324 let b = read_byte(reader)?;
325 match b {
326 0xFF => Ok(None),
327 0 => Ok(Some(false)),
328 1 => Ok(Some(true)),
329 _ => Err(WalletError::Internal(format!(
330 "invalid optional bool byte: {b}"
331 ))),
332 }
333}
334
335pub fn write_bool(writer: &mut impl Write, v: bool) -> Result<(), WalletError> {
337 write_byte(writer, if v { 1 } else { 0 })
338}
339
340pub fn read_bool(reader: &mut impl Read) -> Result<bool, WalletError> {
342 Ok(read_byte(reader)? == 1)
343}
344
345pub fn write_uint32(writer: &mut impl Write, v: u32) -> Result<(), WalletError> {
351 writer
352 .write_all(&v.to_le_bytes())
353 .map_err(|e| WalletError::Internal(e.to_string()))
354}
355
356pub fn read_uint32(reader: &mut impl Read) -> Result<u32, WalletError> {
358 let mut buf = [0u8; 4];
359 reader
360 .read_exact(&mut buf)
361 .map_err(|e| WalletError::Internal(e.to_string()))?;
362 Ok(u32::from_le_bytes(buf))
363}
364
365pub fn write_optional_uint32(writer: &mut impl Write, v: Option<u32>) -> Result<(), WalletError> {
367 match v {
368 Some(val) => write_varint(writer, val as u64),
369 None => write_varint(writer, NEGATIVE_ONE),
370 }
371}
372
373pub fn read_optional_uint32(reader: &mut impl Read) -> Result<Option<u32>, WalletError> {
375 let val = read_varint(reader)?;
376 if val == NEGATIVE_ONE {
377 Ok(None)
378 } else {
379 Ok(Some(val as u32))
380 }
381}
382
383pub fn write_counterparty(writer: &mut impl Write, c: &Counterparty) -> Result<(), WalletError> {
390 match c.counterparty_type {
391 CounterpartyType::Uninitialized => write_byte(writer, COUNTERPARTY_UNINITIALIZED),
392 CounterpartyType::Self_ => write_byte(writer, COUNTERPARTY_SELF),
393 CounterpartyType::Anyone => write_byte(writer, COUNTERPARTY_ANYONE),
394 CounterpartyType::Other => {
395 let pk = c.public_key.as_ref().ok_or_else(|| {
396 WalletError::Internal("counterparty is Other but no public key".to_string())
397 })?;
398 let compressed = pk.to_der();
399 write_raw_bytes(writer, &compressed)
400 }
401 }
402}
403
404pub fn read_counterparty(reader: &mut impl Read) -> Result<Counterparty, WalletError> {
406 let flag = read_byte(reader)?;
407 match flag {
408 COUNTERPARTY_UNINITIALIZED => Ok(Counterparty {
409 counterparty_type: CounterpartyType::Uninitialized,
410 public_key: None,
411 }),
412 COUNTERPARTY_SELF => Ok(Counterparty {
413 counterparty_type: CounterpartyType::Self_,
414 public_key: None,
415 }),
416 COUNTERPARTY_ANYONE => Ok(Counterparty {
417 counterparty_type: CounterpartyType::Anyone,
418 public_key: None,
419 }),
420 0x02 | 0x03 => {
421 let mut buf = vec![flag];
422 let rest = read_raw_bytes(reader, 32)?;
423 buf.extend_from_slice(&rest);
424 let pk = PublicKey::from_der_bytes(&buf)?;
425 Ok(Counterparty {
426 counterparty_type: CounterpartyType::Other,
427 public_key: Some(pk),
428 })
429 }
430 _ => Err(WalletError::Internal(format!(
431 "invalid counterparty flag byte: 0x{flag:02x}"
432 ))),
433 }
434}
435
436pub fn write_protocol(writer: &mut impl Write, p: &Protocol) -> Result<(), WalletError> {
442 write_byte(writer, p.security_level)?;
443 write_string(writer, &p.protocol)
444}
445
446pub fn read_protocol(reader: &mut impl Read) -> Result<Protocol, WalletError> {
448 let security_level = read_byte(reader)?;
449 let protocol = read_string(reader)?;
450 Ok(Protocol {
451 security_level,
452 protocol,
453 })
454}
455
456pub struct KeyRelatedParams {
462 pub protocol: Protocol,
463 pub key_id: String,
464 pub counterparty: Counterparty,
465 pub privileged: Option<bool>,
466 pub privileged_reason: String,
467}
468
469pub fn write_key_related_params(
471 writer: &mut impl Write,
472 params: &KeyRelatedParams,
473) -> Result<(), WalletError> {
474 write_protocol(writer, ¶ms.protocol)?;
475 write_string(writer, ¶ms.key_id)?;
476 write_counterparty(writer, ¶ms.counterparty)?;
477 write_privileged_params(writer, params.privileged, ¶ms.privileged_reason)
478}
479
480pub fn read_key_related_params(reader: &mut impl Read) -> Result<KeyRelatedParams, WalletError> {
482 let protocol = read_protocol(reader)?;
483 let key_id = read_string(reader)?;
484 let counterparty = read_counterparty(reader)?;
485 let (privileged, privileged_reason) = read_privileged_params(reader)?;
486 Ok(KeyRelatedParams {
487 protocol,
488 key_id,
489 counterparty,
490 privileged,
491 privileged_reason,
492 })
493}
494
495pub fn write_privileged_params(
501 writer: &mut impl Write,
502 privileged: Option<bool>,
503 privileged_reason: &str,
504) -> Result<(), WalletError> {
505 write_optional_bool(writer, privileged)?;
506 if !privileged_reason.is_empty() {
507 write_string(writer, privileged_reason)
508 } else {
509 write_byte(writer, NEGATIVE_ONE_BYTE)
510 }
511}
512
513pub fn read_privileged_params(
515 reader: &mut impl Read,
516) -> Result<(Option<bool>, String), WalletError> {
517 let privileged = read_optional_bool(reader)?;
518 let b = read_byte(reader)?;
519 if b == NEGATIVE_ONE_BYTE {
520 return Ok((privileged, String::new()));
521 }
522 let len = match b {
526 0xff => {
527 return Ok((privileged, String::new()));
529 }
530 0xfe => {
531 let mut buf = [0u8; 4];
532 reader
533 .read_exact(&mut buf)
534 .map_err(|e| WalletError::Internal(e.to_string()))?;
535 u32::from_le_bytes(buf) as u64
536 }
537 0xfd => {
538 let mut buf = [0u8; 2];
539 reader
540 .read_exact(&mut buf)
541 .map_err(|e| WalletError::Internal(e.to_string()))?;
542 u16::from_le_bytes(buf) as u64
543 }
544 _ => b as u64,
545 };
546 if len == 0 {
547 return Ok((privileged, String::new()));
548 }
549 let mut buf = vec![0u8; len as usize];
550 reader
551 .read_exact(&mut buf)
552 .map_err(|e| WalletError::Internal(e.to_string()))?;
553 let reason = String::from_utf8(buf).map_err(|e| WalletError::Internal(e.to_string()))?;
554 Ok((privileged, reason))
555}
556
557pub fn write_string_slice(
563 writer: &mut impl Write,
564 slice: &Option<Vec<String>>,
565) -> Result<(), WalletError> {
566 match slice {
567 None => write_varint(writer, NEGATIVE_ONE),
568 Some(s) => {
569 write_varint(writer, s.len() as u64)?;
570 for item in s {
571 write_string_optional(writer, item)?;
572 }
573 Ok(())
574 }
575 }
576}
577
578pub fn read_string_slice(reader: &mut impl Read) -> Result<Option<Vec<String>>, WalletError> {
580 let count = read_varint(reader)?;
581 if count == NEGATIVE_ONE {
582 return Ok(None);
583 }
584 let mut result = Vec::with_capacity(count as usize);
585 for _ in 0..count {
586 result.push(read_string_optional(reader)?);
587 }
588 Ok(Some(result))
589}
590
591pub fn write_string_map(
597 writer: &mut impl Write,
598 map: &HashMap<String, String>,
599) -> Result<(), WalletError> {
600 let mut keys: Vec<&String> = map.keys().collect();
601 keys.sort();
602 write_varint(writer, keys.len() as u64)?;
603 for key in keys {
604 write_string(writer, key)?;
605 write_string(writer, &map[key])?;
606 }
607 Ok(())
608}
609
610pub fn read_string_map(reader: &mut impl Read) -> Result<HashMap<String, String>, WalletError> {
612 let count = read_varint(reader)?;
613 let mut map = HashMap::with_capacity(count as usize);
614 for _ in 0..count {
615 let key = read_string(reader)?;
616 let value = read_string(reader)?;
617 map.insert(key, value);
618 }
619 Ok(map)
620}
621
622pub fn write_optional_bytes_with_flag(
630 writer: &mut impl Write,
631 data: Option<&[u8]>,
632) -> Result<(), WalletError> {
633 match data {
634 Some(b) if !b.is_empty() => {
635 write_byte(writer, 1)?;
636 write_bytes(writer, b)
637 }
638 _ => write_byte(writer, 0),
639 }
640}
641
642pub fn read_optional_bytes_with_flag(
644 reader: &mut impl Read,
645) -> Result<Option<Vec<u8>>, WalletError> {
646 let flag = read_byte(reader)?;
647 if flag != 1 {
648 return Ok(None);
649 }
650 let data = read_bytes(reader)?;
651 Ok(Some(data))
652}
653
654pub fn write_optional_bytes_with_flag_fixed(
656 writer: &mut impl Write,
657 data: Option<&[u8]>,
658) -> Result<(), WalletError> {
659 match data {
660 Some(b) if !b.is_empty() => {
661 write_byte(writer, 1)?;
662 write_raw_bytes(writer, b)
663 }
664 _ => write_byte(writer, 0),
665 }
666}
667
668pub fn read_optional_bytes_with_flag_fixed(
670 reader: &mut impl Read,
671 size: usize,
672) -> Result<Option<Vec<u8>>, WalletError> {
673 let flag = read_byte(reader)?;
674 if flag != 1 {
675 return Ok(None);
676 }
677 read_raw_bytes(reader, size).map(Some)
678}
679
680pub fn write_optional_bytes_varint(
682 writer: &mut impl Write,
683 data: Option<&[u8]>,
684) -> Result<(), WalletError> {
685 match data {
686 Some(b) if !b.is_empty() => write_bytes(writer, b),
687 _ => write_varint(writer, NEGATIVE_ONE),
688 }
689}
690
691pub fn read_optional_bytes_varint(reader: &mut impl Read) -> Result<Option<Vec<u8>>, WalletError> {
693 let len = read_varint(reader)?;
694 if len == NEGATIVE_ONE || len == 0 {
695 return Ok(None);
696 }
697 let mut buf = vec![0u8; len as usize];
698 reader
699 .read_exact(&mut buf)
700 .map_err(|e| WalletError::Internal(e.to_string()))?;
701 Ok(Some(buf))
702}
703
704pub fn write_outpoint(writer: &mut impl Write, outpoint: &str) -> Result<(), WalletError> {
713 let parts: Vec<&str> = outpoint.split('.').collect();
714 if parts.len() != 2 {
715 return Err(WalletError::Internal(format!(
716 "invalid outpoint format: {outpoint}"
717 )));
718 }
719 let txid_bytes = hex_decode(parts[0])?;
720 if txid_bytes.len() != 32 {
721 return Err(WalletError::Internal(format!(
722 "invalid txid length: {}",
723 txid_bytes.len()
724 )));
725 }
726 write_raw_bytes(writer, &txid_bytes)?;
728 let index: u32 = parts[1].parse().map_err(|e: std::num::ParseIntError| {
729 WalletError::Internal(format!("invalid outpoint index: {e}"))
730 })?;
731 write_varint(writer, index as u64)
732}
733
734pub fn read_outpoint(reader: &mut impl Read) -> Result<String, WalletError> {
736 let txid_bytes = read_raw_bytes(reader, 32)?;
737 let index = read_varint(reader)? as u32;
738 Ok(format!("{}.{}", hex_encode(&txid_bytes), index))
739}
740
741pub fn write_public_key(writer: &mut impl Write, pk: &PublicKey) -> Result<(), WalletError> {
747 write_raw_bytes(writer, &pk.to_der())
748}
749
750pub fn read_public_key(reader: &mut impl Read) -> Result<PublicKey, WalletError> {
752 let buf = read_raw_bytes(reader, SIZE_PUB_KEY)?;
753 PublicKey::from_der_bytes(&buf).map_err(|e| WalletError::Internal(e.to_string()))
754}
755
756pub fn hex_decode(s: &str) -> Result<Vec<u8>, WalletError> {
762 let mut result = Vec::with_capacity(s.len() / 2);
763 let chars: Vec<char> = s.chars().collect();
764 if !chars.len().is_multiple_of(2) {
765 return Err(WalletError::Internal(
766 "hex string has odd length".to_string(),
767 ));
768 }
769 for i in (0..chars.len()).step_by(2) {
770 let hi = hex_nibble(chars[i])?;
771 let lo = hex_nibble(chars[i + 1])?;
772 result.push((hi << 4) | lo);
773 }
774 Ok(result)
775}
776
777fn hex_nibble(c: char) -> Result<u8, WalletError> {
778 match c {
779 '0'..='9' => Ok(c as u8 - b'0'),
780 'a'..='f' => Ok(c as u8 - b'a' + 10),
781 'A'..='F' => Ok(c as u8 - b'A' + 10),
782 _ => Err(WalletError::Internal(format!("invalid hex char: {c}"))),
783 }
784}
785
786pub fn hex_encode(data: &[u8]) -> String {
788 let mut s = String::with_capacity(data.len() * 2);
789 for b in data {
790 s.push_str(&format!("{b:02x}"));
791 }
792 s
793}
794
795pub fn serialize_to_vec<F>(f: F) -> Result<Vec<u8>, WalletError>
801where
802 F: FnOnce(&mut Vec<u8>) -> Result<(), WalletError>,
803{
804 let mut buf = Vec::new();
805 f(&mut buf)?;
806 Ok(buf)
807}