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: {}",
331 b
332 ))),
333 }
334}
335
336pub fn write_bool(writer: &mut impl Write, v: bool) -> Result<(), WalletError> {
338 write_byte(writer, if v { 1 } else { 0 })
339}
340
341pub fn read_bool(reader: &mut impl Read) -> Result<bool, WalletError> {
343 Ok(read_byte(reader)? == 1)
344}
345
346pub fn write_uint32(writer: &mut impl Write, v: u32) -> Result<(), WalletError> {
352 writer
353 .write_all(&v.to_le_bytes())
354 .map_err(|e| WalletError::Internal(e.to_string()))
355}
356
357pub fn read_uint32(reader: &mut impl Read) -> Result<u32, WalletError> {
359 let mut buf = [0u8; 4];
360 reader
361 .read_exact(&mut buf)
362 .map_err(|e| WalletError::Internal(e.to_string()))?;
363 Ok(u32::from_le_bytes(buf))
364}
365
366pub fn write_optional_uint32(writer: &mut impl Write, v: Option<u32>) -> Result<(), WalletError> {
368 match v {
369 Some(val) => write_varint(writer, val as u64),
370 None => write_varint(writer, NEGATIVE_ONE),
371 }
372}
373
374pub fn read_optional_uint32(reader: &mut impl Read) -> Result<Option<u32>, WalletError> {
376 let val = read_varint(reader)?;
377 if val == NEGATIVE_ONE {
378 Ok(None)
379 } else {
380 Ok(Some(val as u32))
381 }
382}
383
384pub fn write_counterparty(writer: &mut impl Write, c: &Counterparty) -> Result<(), WalletError> {
391 match c.counterparty_type {
392 CounterpartyType::Uninitialized => write_byte(writer, COUNTERPARTY_UNINITIALIZED),
393 CounterpartyType::Self_ => write_byte(writer, COUNTERPARTY_SELF),
394 CounterpartyType::Anyone => write_byte(writer, COUNTERPARTY_ANYONE),
395 CounterpartyType::Other => {
396 let pk = c.public_key.as_ref().ok_or_else(|| {
397 WalletError::Internal("counterparty is Other but no public key".to_string())
398 })?;
399 let compressed = pk.to_der();
400 write_raw_bytes(writer, &compressed)
401 }
402 }
403}
404
405pub fn read_counterparty(reader: &mut impl Read) -> Result<Counterparty, WalletError> {
407 let flag = read_byte(reader)?;
408 match flag {
409 COUNTERPARTY_UNINITIALIZED => Ok(Counterparty {
410 counterparty_type: CounterpartyType::Uninitialized,
411 public_key: None,
412 }),
413 COUNTERPARTY_SELF => Ok(Counterparty {
414 counterparty_type: CounterpartyType::Self_,
415 public_key: None,
416 }),
417 COUNTERPARTY_ANYONE => Ok(Counterparty {
418 counterparty_type: CounterpartyType::Anyone,
419 public_key: None,
420 }),
421 0x02 | 0x03 => {
422 let mut buf = vec![flag];
423 let rest = read_raw_bytes(reader, 32)?;
424 buf.extend_from_slice(&rest);
425 let pk = PublicKey::from_der_bytes(&buf)?;
426 Ok(Counterparty {
427 counterparty_type: CounterpartyType::Other,
428 public_key: Some(pk),
429 })
430 }
431 _ => Err(WalletError::Internal(format!(
432 "invalid counterparty flag byte: 0x{:02x}",
433 flag
434 ))),
435 }
436}
437
438pub fn write_protocol(writer: &mut impl Write, p: &Protocol) -> Result<(), WalletError> {
444 write_byte(writer, p.security_level)?;
445 write_string(writer, &p.protocol)
446}
447
448pub fn read_protocol(reader: &mut impl Read) -> Result<Protocol, WalletError> {
450 let security_level = read_byte(reader)?;
451 let protocol = read_string(reader)?;
452 Ok(Protocol {
453 security_level,
454 protocol,
455 })
456}
457
458pub struct KeyRelatedParams {
464 pub protocol: Protocol,
465 pub key_id: String,
466 pub counterparty: Counterparty,
467 pub privileged: Option<bool>,
468 pub privileged_reason: String,
469}
470
471pub fn write_key_related_params(
473 writer: &mut impl Write,
474 params: &KeyRelatedParams,
475) -> Result<(), WalletError> {
476 write_protocol(writer, ¶ms.protocol)?;
477 write_string(writer, ¶ms.key_id)?;
478 write_counterparty(writer, ¶ms.counterparty)?;
479 write_privileged_params(writer, params.privileged, ¶ms.privileged_reason)
480}
481
482pub fn read_key_related_params(reader: &mut impl Read) -> Result<KeyRelatedParams, WalletError> {
484 let protocol = read_protocol(reader)?;
485 let key_id = read_string(reader)?;
486 let counterparty = read_counterparty(reader)?;
487 let (privileged, privileged_reason) = read_privileged_params(reader)?;
488 Ok(KeyRelatedParams {
489 protocol,
490 key_id,
491 counterparty,
492 privileged,
493 privileged_reason,
494 })
495}
496
497pub fn write_privileged_params(
503 writer: &mut impl Write,
504 privileged: Option<bool>,
505 privileged_reason: &str,
506) -> Result<(), WalletError> {
507 write_optional_bool(writer, privileged)?;
508 if !privileged_reason.is_empty() {
509 write_string(writer, privileged_reason)
510 } else {
511 write_byte(writer, NEGATIVE_ONE_BYTE)
512 }
513}
514
515pub fn read_privileged_params(
517 reader: &mut impl Read,
518) -> Result<(Option<bool>, String), WalletError> {
519 let privileged = read_optional_bool(reader)?;
520 let b = read_byte(reader)?;
521 if b == NEGATIVE_ONE_BYTE {
522 return Ok((privileged, String::new()));
523 }
524 let len = match b {
528 0xff => {
529 return Ok((privileged, String::new()));
531 }
532 0xfe => {
533 let mut buf = [0u8; 4];
534 reader
535 .read_exact(&mut buf)
536 .map_err(|e| WalletError::Internal(e.to_string()))?;
537 u32::from_le_bytes(buf) as u64
538 }
539 0xfd => {
540 let mut buf = [0u8; 2];
541 reader
542 .read_exact(&mut buf)
543 .map_err(|e| WalletError::Internal(e.to_string()))?;
544 u16::from_le_bytes(buf) as u64
545 }
546 _ => b as u64,
547 };
548 if len == 0 {
549 return Ok((privileged, String::new()));
550 }
551 let mut buf = vec![0u8; len as usize];
552 reader
553 .read_exact(&mut buf)
554 .map_err(|e| WalletError::Internal(e.to_string()))?;
555 let reason = String::from_utf8(buf).map_err(|e| WalletError::Internal(e.to_string()))?;
556 Ok((privileged, reason))
557}
558
559pub fn write_string_slice(
565 writer: &mut impl Write,
566 slice: &Option<Vec<String>>,
567) -> Result<(), WalletError> {
568 match slice {
569 None => write_varint(writer, NEGATIVE_ONE),
570 Some(s) => {
571 write_varint(writer, s.len() as u64)?;
572 for item in s {
573 write_string_optional(writer, item)?;
574 }
575 Ok(())
576 }
577 }
578}
579
580pub fn read_string_slice(reader: &mut impl Read) -> Result<Option<Vec<String>>, WalletError> {
582 let count = read_varint(reader)?;
583 if count == NEGATIVE_ONE {
584 return Ok(None);
585 }
586 let mut result = Vec::with_capacity(count as usize);
587 for _ in 0..count {
588 result.push(read_string_optional(reader)?);
589 }
590 Ok(Some(result))
591}
592
593pub fn write_string_map(
599 writer: &mut impl Write,
600 map: &HashMap<String, String>,
601) -> Result<(), WalletError> {
602 let mut keys: Vec<&String> = map.keys().collect();
603 keys.sort();
604 write_varint(writer, keys.len() as u64)?;
605 for key in keys {
606 write_string(writer, key)?;
607 write_string(writer, &map[key])?;
608 }
609 Ok(())
610}
611
612pub fn read_string_map(reader: &mut impl Read) -> Result<HashMap<String, String>, WalletError> {
614 let count = read_varint(reader)?;
615 let mut map = HashMap::with_capacity(count as usize);
616 for _ in 0..count {
617 let key = read_string(reader)?;
618 let value = read_string(reader)?;
619 map.insert(key, value);
620 }
621 Ok(map)
622}
623
624pub fn write_optional_bytes_with_flag(
632 writer: &mut impl Write,
633 data: Option<&[u8]>,
634) -> Result<(), WalletError> {
635 match data {
636 Some(b) if !b.is_empty() => {
637 write_byte(writer, 1)?;
638 write_bytes(writer, b)
639 }
640 _ => write_byte(writer, 0),
641 }
642}
643
644pub fn read_optional_bytes_with_flag(
646 reader: &mut impl Read,
647) -> Result<Option<Vec<u8>>, WalletError> {
648 let flag = read_byte(reader)?;
649 if flag != 1 {
650 return Ok(None);
651 }
652 let data = read_bytes(reader)?;
653 Ok(Some(data))
654}
655
656pub fn write_optional_bytes_with_flag_fixed(
658 writer: &mut impl Write,
659 data: Option<&[u8]>,
660) -> Result<(), WalletError> {
661 match data {
662 Some(b) if !b.is_empty() => {
663 write_byte(writer, 1)?;
664 write_raw_bytes(writer, b)
665 }
666 _ => write_byte(writer, 0),
667 }
668}
669
670pub fn read_optional_bytes_with_flag_fixed(
672 reader: &mut impl Read,
673 size: usize,
674) -> Result<Option<Vec<u8>>, WalletError> {
675 let flag = read_byte(reader)?;
676 if flag != 1 {
677 return Ok(None);
678 }
679 read_raw_bytes(reader, size).map(Some)
680}
681
682pub fn write_optional_bytes_varint(
684 writer: &mut impl Write,
685 data: Option<&[u8]>,
686) -> Result<(), WalletError> {
687 match data {
688 Some(b) if !b.is_empty() => write_bytes(writer, b),
689 _ => write_varint(writer, NEGATIVE_ONE),
690 }
691}
692
693pub fn read_optional_bytes_varint(reader: &mut impl Read) -> Result<Option<Vec<u8>>, WalletError> {
695 let len = read_varint(reader)?;
696 if len == NEGATIVE_ONE || len == 0 {
697 return Ok(None);
698 }
699 let mut buf = vec![0u8; len as usize];
700 reader
701 .read_exact(&mut buf)
702 .map_err(|e| WalletError::Internal(e.to_string()))?;
703 Ok(Some(buf))
704}
705
706pub fn write_outpoint(writer: &mut impl Write, outpoint: &str) -> Result<(), WalletError> {
715 let parts: Vec<&str> = outpoint.split('.').collect();
716 if parts.len() != 2 {
717 return Err(WalletError::Internal(format!(
718 "invalid outpoint format: {}",
719 outpoint
720 )));
721 }
722 let txid_bytes = hex_decode(parts[0])?;
723 if txid_bytes.len() != 32 {
724 return Err(WalletError::Internal(format!(
725 "invalid txid length: {}",
726 txid_bytes.len()
727 )));
728 }
729 write_raw_bytes(writer, &txid_bytes)?;
731 let index: u32 = parts[1].parse().map_err(|e: std::num::ParseIntError| {
732 WalletError::Internal(format!("invalid outpoint index: {}", e))
733 })?;
734 write_varint(writer, index as u64)
735}
736
737pub fn read_outpoint(reader: &mut impl Read) -> Result<String, WalletError> {
739 let txid_bytes = read_raw_bytes(reader, 32)?;
740 let index = read_varint(reader)? as u32;
741 Ok(format!("{}.{}", hex_encode(&txid_bytes), index))
742}
743
744pub fn write_public_key(writer: &mut impl Write, pk: &PublicKey) -> Result<(), WalletError> {
750 write_raw_bytes(writer, &pk.to_der())
751}
752
753pub fn read_public_key(reader: &mut impl Read) -> Result<PublicKey, WalletError> {
755 let buf = read_raw_bytes(reader, SIZE_PUB_KEY)?;
756 PublicKey::from_der_bytes(&buf).map_err(|e| WalletError::Internal(e.to_string()))
757}
758
759pub fn hex_decode(s: &str) -> Result<Vec<u8>, WalletError> {
765 let mut result = Vec::with_capacity(s.len() / 2);
766 let chars: Vec<char> = s.chars().collect();
767 if !chars.len().is_multiple_of(2) {
768 return Err(WalletError::Internal(
769 "hex string has odd length".to_string(),
770 ));
771 }
772 for i in (0..chars.len()).step_by(2) {
773 let hi = hex_nibble(chars[i])?;
774 let lo = hex_nibble(chars[i + 1])?;
775 result.push((hi << 4) | lo);
776 }
777 Ok(result)
778}
779
780fn hex_nibble(c: char) -> Result<u8, WalletError> {
781 match c {
782 '0'..='9' => Ok(c as u8 - b'0'),
783 'a'..='f' => Ok(c as u8 - b'a' + 10),
784 'A'..='F' => Ok(c as u8 - b'A' + 10),
785 _ => Err(WalletError::Internal(format!("invalid hex char: {}", c))),
786 }
787}
788
789pub fn hex_encode(data: &[u8]) -> String {
791 let mut s = String::with_capacity(data.len() * 2);
792 for b in data {
793 s.push_str(&format!("{:02x}", b));
794 }
795 s
796}
797
798pub fn serialize_to_vec<F>(f: F) -> Result<Vec<u8>, WalletError>
804where
805 F: FnOnce(&mut Vec<u8>) -> Result<(), WalletError>,
806{
807 let mut buf = Vec::new();
808 f(&mut buf)?;
809 Ok(buf)
810}