Skip to main content

ark/
encode.rs

1//!
2//! Definitions of protocol encodings.
3//!
4
5
6use std::borrow::Cow;
7use std::{fmt, io};
8
9use bitcoin::hashes::{sha256, Hash};
10// We use bitcoin::io::{Read, Write} here but we shouldn't have to.
11// I created this issue in the hope that rust-bitcoin fixes this nuisance:
12//  https://github.com/rust-bitcoin/rust-bitcoin/issues/4530
13use bitcoin::secp256k1::{self, schnorr, PublicKey, XOnlyPublicKey};
14use secp256k1_musig::musig;
15
16
17/// Error occuring during protocol decoding.
18#[derive(Debug, thiserror::Error)]
19pub enum ProtocolDecodingError {
20	#[error("I/O error: {0}")]
21	Io(#[from] io::Error),
22	#[error("invalid protocol encoding: {message}")]
23	Invalid {
24		message: String,
25		#[source]
26		source: Option<Box<dyn std::error::Error + Send + Sync + 'static>>,
27	},
28}
29
30impl ProtocolDecodingError {
31	/// Create a new [ProtocolDecodingError::Invalid] with the given message.
32	pub fn invalid(message: impl fmt::Display) -> Self {
33		Self::Invalid {
34			message: message.to_string(),
35			source: None,
36		}
37	}
38
39	/// Create a new [ProtocolDecodingError::Invalid] with the given message and source error.
40	pub fn invalid_err<E>(source: E, message: impl fmt::Display) -> Self
41	where
42		E: std::error::Error + Send + Sync + 'static,
43	{
44		Self::Invalid {
45			message: message.to_string(),
46			source: Some(Box::new(source)),
47		}
48	}
49}
50
51impl From<bitcoin::consensus::encode::Error> for ProtocolDecodingError {
52	fn from(e: bitcoin::consensus::encode::Error) -> Self {
53		match e {
54			bitcoin::consensus::encode::Error::Io(e) => Self::Io(e.into()),
55			e => Self::invalid_err(e, "bitcoin protocol decoding error"),
56		}
57	}
58}
59
60impl From<bitcoin::io::Error> for ProtocolDecodingError {
61	fn from(e: bitcoin::io::Error) -> Self {
62	    Self::Io(e.into())
63	}
64}
65
66/// Trait for encoding objects according to the bark protocol encoding.
67pub trait ProtocolEncoding: Sized {
68	/// Encode the object into the writer.
69	//TODO(stevenroose) return nb of bytes written like bitcoin::consensus::Encodable does?
70	fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<(), io::Error>;
71
72	/// Decode the object from the writer.
73	fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, ProtocolDecodingError>;
74
75	/// Serialize the object into a byte vector.
76	fn serialize(&self) -> Vec<u8> {
77		let mut buf = Vec::new();
78		self.encode(&mut buf).expect("buffers don't produce I/O errors");
79		buf
80	}
81
82	/// Deserialize object from the given byte slice.
83	fn deserialize(mut byte_slice: &[u8]) -> Result<Self, ProtocolDecodingError> {
84		Self::decode(&mut byte_slice)
85	}
86
87	/// Serialize the object to a lowercase hex string.
88	fn serialize_hex(&self) -> String {
89		use hex_conservative::Case::Lower;
90		let mut buf = String::new();
91		let mut writer = hex_conservative::display::HexWriter::new(&mut buf, Lower);
92		self.encode(&mut writer).expect("no I/O errors for buffers");
93		buf
94	}
95
96	/// Deserialize object from hex slice.
97	fn deserialize_hex(hex_str: &str) -> Result<Self, ProtocolDecodingError> {
98		let mut iter = hex_conservative::HexToBytesIter::new(hex_str).map_err(|e| {
99			ProtocolDecodingError::Io(io::Error::new(io::ErrorKind::InvalidData, e))
100		})?;
101		Self::decode(&mut iter)
102	}
103}
104
105/// Utility trait to write some primitive values into our encoding format.
106pub trait WriteExt: io::Write {
107	/// Write an 8-bit unsigned integer in little-endian.
108	fn emit_u8(&mut self, v: u8) -> Result<(), io::Error> {
109		self.write_all(&v.to_le_bytes())
110	}
111
112	/// Write a 16-bit unsigned integer in little-endian.
113	fn emit_u16(&mut self, v: u16) -> Result<(), io::Error> {
114		self.write_all(&v.to_le_bytes())
115	}
116
117	/// Write a 32-bit unsigned integer in little-endian.
118	fn emit_u32(&mut self, v: u32) -> Result<(), io::Error> {
119		self.write_all(&v.to_le_bytes())
120	}
121
122	/// Write a 64-bit unsigned integer in little-endian.
123	fn emit_u64(&mut self, v: u64) -> Result<(), io::Error> {
124		self.write_all(&v.to_le_bytes())
125	}
126
127	/// Write the entire slice to the writer.
128	fn emit_slice(&mut self, slice: &[u8]) -> Result<(), io::Error> {
129		self.write_all(slice)
130	}
131
132	/// Write a value in compact size aka "VarInt" encoding.
133	fn emit_compact_size(&mut self, value: impl Into<u64>) -> Result<usize, io::Error> {
134		let value = value.into();
135		match value {
136			0..=0xFC => {
137				self.emit_u8(value as u8)?;
138				Ok(1)
139			},
140			0xFD..=0xFFFF => {
141				self.emit_u8(0xFD)?;
142				self.emit_u16(value as u16)?;
143				Ok(3)
144			},
145			0x10000..=0xFFFFFFFF => {
146				self.emit_u8(0xFE)?;
147				self.emit_u32(value as u32)?;
148				Ok(5)
149			},
150			_ => {
151				self.emit_u8(0xFF)?;
152				self.emit_u64(value)?;
153				Ok(9)
154			},
155		}
156	}
157}
158
159impl<W: io::Write + ?Sized> WriteExt for W {}
160
161/// Utility trait to read some primitive values into our encoding format.
162pub trait ReadExt: io::Read {
163	/// Read an 8-bit unsigned integer in little-endian.
164	fn read_u8(&mut self) -> Result<u8, io::Error> {
165		let mut buf = [0; 1];
166		self.read_exact(&mut buf[..])?;
167		Ok(u8::from_le_bytes(buf))
168	}
169
170	/// Read a 16-bit unsigned integer in little-endian.
171	fn read_u16(&mut self) -> Result<u16, io::Error> {
172		let mut buf = [0; 2];
173		self.read_exact(&mut buf[..])?;
174		Ok(u16::from_le_bytes(buf))
175	}
176
177	/// Read a 32-bit unsigned integer in little-endian.
178	fn read_u32(&mut self) -> Result<u32, io::Error> {
179		let mut buf = [0; 4];
180		self.read_exact(&mut buf[..])?;
181		Ok(u32::from_le_bytes(buf))
182	}
183
184	/// Read a 64-bit unsigned integer in little-endian.
185	fn read_u64(&mut self) -> Result<u64, io::Error> {
186		let mut buf = [0; 8];
187		self.read_exact(&mut buf[..])?;
188		Ok(u64::from_le_bytes(buf))
189	}
190
191	/// Read from the reader to fill the entire slice.
192	fn read_slice(&mut self, slice: &mut [u8]) -> Result<(), io::Error> {
193		self.read_exact(slice)
194	}
195
196	/// Read a byte array
197	fn read_byte_array<const N: usize>(&mut self) -> Result<[u8; N], io::Error> {
198		let mut ret = [0u8; N];
199		self.read_exact(&mut ret)?;
200		Ok(ret)
201	}
202
203	/// Read a value in compact size aka "VarInt" encoding.
204	fn read_compact_size(&mut self) -> Result<u64, io::Error> {
205		match self.read_u8()? {
206			0xFF => {
207				let x = self.read_u64()?;
208				if x < 0x1_0000_0000 { // I.e., would have fit in a `u32`.
209					Err(io::Error::new(io::ErrorKind::InvalidData, "non-minimal varint"))
210				} else {
211					Ok(x)
212				}
213			},
214			0xFE => {
215				let x = self.read_u32()?;
216				if x < 0x1_0000 { // I.e., would have fit in a `u16`.
217					Err(io::Error::new(io::ErrorKind::InvalidData, "non-minimal varint"))
218				} else {
219					Ok(x as u64)
220				}
221			},
222			0xFD => {
223				let x = self.read_u16()?;
224				if x < 0xFD { // Could have been encoded as a `u8`.
225					Err(io::Error::new(io::ErrorKind::InvalidData, "non-minimal varint"))
226				} else {
227					Ok(x as u64)
228				}
229			},
230			n => Ok(n as u64),
231		}
232	}
233}
234
235impl<R: io::Read + ?Sized> ReadExt for R {}
236
237
238impl ProtocolEncoding for PublicKey {
239	fn encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<(), io::Error> {
240		w.emit_slice(&self.serialize())
241	}
242
243	fn decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, ProtocolDecodingError> {
244		let mut buf = [0; secp256k1::constants::PUBLIC_KEY_SIZE];
245		r.read_slice(&mut buf[..])?;
246		PublicKey::from_slice(&buf).map_err(|e| {
247			ProtocolDecodingError::invalid_err(e, "invalid public key")
248		})
249	}
250}
251
252impl ProtocolEncoding for XOnlyPublicKey {
253	fn encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<(), io::Error> {
254		w.emit_slice(&self.serialize())
255	}
256
257	fn decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, ProtocolDecodingError> {
258		let mut buf = [0; 32];
259		r.read_slice(&mut buf[..])?;
260		XOnlyPublicKey::from_slice(&buf).map_err(|e| {
261			ProtocolDecodingError::invalid_err(e, "invalid x-only public key")
262		})
263	}
264}
265
266impl ProtocolEncoding for Option<sha256::Hash> {
267	fn encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<(), io::Error> {
268		if let Some(h) = self {
269			w.emit_u8(1)?;
270			w.emit_slice(&h.as_byte_array()[..])
271		} else {
272			w.emit_u8(0)
273		}
274	}
275
276	fn decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, ProtocolDecodingError> {
277		let first = r.read_u8()?;
278		if first == 0 {
279			Ok(None)
280		} else if first == 1 {
281			let mut buf = [0u8; 32];
282			r.read_slice(&mut buf)?;
283			Ok(Some(sha256::Hash::from_byte_array(buf)))
284		} else {
285			Err(ProtocolDecodingError::invalid("invalid optional hash prefix byte"))
286		}
287	}
288}
289
290impl ProtocolEncoding for Option<PublicKey> {
291	fn encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<(), io::Error> {
292		if let Some(pk) = self {
293			w.emit_slice(&pk.serialize())
294		} else {
295			w.emit_u8(0)
296		}
297	}
298
299	fn decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, ProtocolDecodingError> {
300		let first = r.read_u8()?;
301		if first == 0 {
302			Ok(None)
303		} else {
304			let mut pk = [first; secp256k1::constants::PUBLIC_KEY_SIZE];
305			r.read_slice(&mut pk[1..])?;
306			Ok(Some(PublicKey::from_slice(&pk).map_err(|e| {
307				ProtocolDecodingError::invalid_err(e, "invalid public key")
308			})?))
309		}
310	}
311}
312
313impl ProtocolEncoding for schnorr::Signature {
314	fn encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<(), io::Error> {
315		w.emit_slice(&self.serialize())
316	}
317
318	fn decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, ProtocolDecodingError> {
319		let mut buf = [0; secp256k1::constants::SCHNORR_SIGNATURE_SIZE];
320		r.read_slice(&mut buf[..])?;
321		schnorr::Signature::from_slice(&buf).map_err(|e| {
322			ProtocolDecodingError::invalid_err(e, "invalid schnorr signature")
323		})
324	}
325}
326
327impl ProtocolEncoding for Option<schnorr::Signature> {
328	fn encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<(), io::Error> {
329		if let Some(sig) = self {
330			w.emit_slice(&sig.serialize())
331		} else {
332			w.emit_slice(&[0; secp256k1::constants::SCHNORR_SIGNATURE_SIZE])
333		}
334	}
335
336	fn decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, ProtocolDecodingError> {
337		let mut buf = [0; secp256k1::constants::SCHNORR_SIGNATURE_SIZE];
338		r.read_slice(&mut buf[..])?;
339		if buf == [0; secp256k1::constants::SCHNORR_SIGNATURE_SIZE] {
340			Ok(None)
341		} else {
342			Ok(Some(schnorr::Signature::from_slice(&buf).map_err(|e| {
343				ProtocolDecodingError::invalid_err(e, "invalid schnorr signature")
344			})?))
345		}
346	}
347}
348
349impl ProtocolEncoding for sha256::Hash {
350	fn encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<(), io::Error> {
351		w.emit_slice(&self[..])
352	}
353
354	fn decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, ProtocolDecodingError> {
355		let mut buf = [0; sha256::Hash::LEN];
356		r.read_exact(&mut buf[..])?;
357		Ok(sha256::Hash::from_byte_array(buf))
358	}
359}
360
361impl ProtocolEncoding for musig::PublicNonce {
362	fn encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<(), io::Error> {
363	    w.emit_slice(&self.serialize())
364	}
365	fn decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, ProtocolDecodingError> {
366		Ok(Self::from_byte_array(&r.read_byte_array()?).map_err(|e| {
367			ProtocolDecodingError::invalid_err(e, "invalid musig public nonce")
368		})?)
369	}
370}
371
372impl ProtocolEncoding for musig::PartialSignature {
373	fn encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<(), io::Error> {
374	    w.emit_slice(&self.serialize())
375	}
376	fn decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, ProtocolDecodingError> {
377		Ok(Self::from_byte_array(&r.read_byte_array()?).map_err(|e| {
378			ProtocolDecodingError::invalid_err(e, "invalid musig public nonce")
379		})?)
380	}
381}
382
383/// A macro to implement our [ProtocolEncoding] for a rust-bitcoin type that
384/// implements their `consensus::Encodable/Decodable` traits.
385macro_rules! impl_bitcoin_encode {
386	($name:ty) => {
387		impl ProtocolEncoding for $name {
388			fn encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<(), io::Error> {
389				let mut wrapped = bitcoin::io::FromStd::new(w);
390				bitcoin::consensus::Encodable::consensus_encode(self, &mut wrapped)?;
391				Ok(())
392			}
393
394			fn decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, ProtocolDecodingError> {
395				let mut wrapped = bitcoin::io::FromStd::new(r);
396				let ret = bitcoin::consensus::Decodable::consensus_decode(&mut wrapped)?;
397				Ok(ret)
398			}
399		}
400	};
401}
402
403impl_bitcoin_encode!(bitcoin::BlockHash);
404impl_bitcoin_encode!(bitcoin::OutPoint);
405impl_bitcoin_encode!(bitcoin::TxOut);
406
407impl ProtocolEncoding for bitcoin::taproot::TapTweakHash {
408	fn encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<(), io::Error> {
409		w.emit_slice(&self.to_byte_array())
410	}
411
412	fn decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, ProtocolDecodingError> {
413		Ok(Self::from_byte_array(r.read_byte_array().map_err(|e| {
414			ProtocolDecodingError::invalid_err(e, "TapTweakHash must be 32 bytes")
415		})?))
416	}
417}
418
419impl<'a, T: ProtocolEncoding + Clone> ProtocolEncoding for Cow<'a, T> {
420	fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<(), io::Error> {
421	    ProtocolEncoding::encode(self.as_ref(), writer)
422	}
423
424	fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, ProtocolDecodingError> {
425	    Ok(Cow::Owned(ProtocolEncoding::decode(reader)?))
426	}
427}
428
429
430pub mod serde {
431	//! Module that helps to encode [ProtocolEncoding] objects with serde.
432	//!
433	//! By default, the objects will be encoded as bytes for regular serializers,
434	//! and as hex for human-readable serializers.
435	//!
436	//! Can be used as follows:
437	//! ```no_run
438	//! # use ark::Vtxo;
439	//! # use serde::{Serialize, Deserialize};
440	//! #[derive(Serialize, Deserialize)]
441	//! struct SomeStruct {
442	//! 	#[serde(with = "ark::encode::serde")]
443	//! 	single: Vtxo,
444	//! 	#[serde(with = "ark::encode::serde::vec")]
445	//! 	multiple: Vec<Vtxo>,
446	//! }
447	//! ```
448
449	use std::fmt;
450	use std::borrow::Cow;
451	use std::marker::PhantomData;
452
453	use serde::{de, ser, Deserialize, Deserializer, Serialize, Serializer};
454
455	use super::ProtocolEncoding;
456
457	struct SerWrapper<'a, T>(&'a T);
458
459	impl<'a, T: ProtocolEncoding> Serialize for SerWrapper<'a, T> {
460		fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
461			if s.is_human_readable() {
462				s.serialize_str(&self.0.serialize_hex())
463			} else {
464				s.serialize_bytes(&self.0.serialize())
465			}
466		}
467	}
468
469	struct DeWrapper<T>(T);
470
471	impl<'de, T: ProtocolEncoding> Deserialize<'de> for DeWrapper<T> {
472		fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
473			if d.is_human_readable() {
474				let s = <Cow<'de, str>>::deserialize(d)?;
475				Ok(DeWrapper(ProtocolEncoding::deserialize_hex(s.as_ref())
476					.map_err(serde::de::Error::custom)?))
477			} else {
478				let b = <Cow<'de, [u8]>>::deserialize(d)?;
479				Ok(DeWrapper(ProtocolEncoding::deserialize(b.as_ref())
480					.map_err(serde::de::Error::custom)?))
481			}
482		}
483	}
484
485	pub fn serialize<T: ProtocolEncoding, S: Serializer>(v: &T, s: S) -> Result<S::Ok, S::Error> {
486		SerWrapper(v).serialize(s)
487	}
488
489	pub fn deserialize<'d, T: ProtocolEncoding, D: Deserializer<'d>>(d: D) -> Result<T, D::Error> {
490		Ok(DeWrapper::<T>::deserialize(d)?.0)
491	}
492
493	pub mod vec {
494		use super::*;
495
496		pub fn serialize<T: ProtocolEncoding, S: Serializer>(v: &[T], s: S) -> Result<S::Ok, S::Error> {
497			let mut seq = s.serialize_seq(Some(v.len()))?;
498			for item in v {
499				ser::SerializeSeq::serialize_element(&mut seq, &SerWrapper(item))?;
500			}
501			ser::SerializeSeq::end(seq)
502		}
503
504		pub fn deserialize<'d, T: ProtocolEncoding, D: Deserializer<'d>>(d: D) -> Result<Vec<T>, D::Error> {
505			struct Visitor<T>(PhantomData<T>);
506
507			impl<'de, T: ProtocolEncoding> de::Visitor<'de> for Visitor<T> {
508				type Value = Vec<T>;
509
510				fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
511					f.write_str("a vector of objects implementing ProtocolEncoding")
512				}
513
514				fn visit_seq<A: de::SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
515					let mut ret = Vec::with_capacity(seq.size_hint().unwrap_or_default());
516					while let Some(v) = seq.next_element::<DeWrapper<T>>()? {
517						ret.push(v.0);
518					}
519					Ok(ret)
520				}
521			}
522			d.deserialize_seq(Visitor(PhantomData))
523		}
524	}
525
526	pub mod cow {
527		use super::*;
528
529		use std::borrow::Cow;
530
531		pub fn serialize<'a, T, S>(v: &Cow<'a, T>, s: S) -> Result<S::Ok, S::Error>
532		where
533			T: ProtocolEncoding + Clone,
534			S: Serializer,
535		{
536			SerWrapper(v.as_ref()).serialize(s)
537		}
538
539		pub fn deserialize<'d, T, D>(d: D) -> Result<Cow<'static, T>, D::Error>
540		where
541			T: ProtocolEncoding + Clone,
542			D: Deserializer<'d>,
543		{
544			Ok(Cow::Owned(DeWrapper::<T>::deserialize(d)?.0))
545		}
546
547		pub mod vec {
548			use super::*;
549
550			use std::borrow::Cow;
551
552			pub fn serialize<'a, T, S>(v: &Cow<'a, [T]>, s: S) -> Result<S::Ok, S::Error>
553			where
554				T: ProtocolEncoding + Clone,
555				S: Serializer,
556			{
557				let mut seq = s.serialize_seq(Some(v.len()))?;
558				for item in v.as_ref().iter() {
559					ser::SerializeSeq::serialize_element(&mut seq, &SerWrapper(item))?;
560				}
561				ser::SerializeSeq::end(seq)
562			}
563
564			pub fn deserialize<'d, T, D>(d: D) -> Result<Cow<'static, [T]>, D::Error>
565			where
566				T: ProtocolEncoding + Clone,
567				D: Deserializer<'d>,
568			{
569				struct Visitor<T>(PhantomData<T>);
570
571				impl<'de, T: ProtocolEncoding + Clone + 'static> de::Visitor<'de> for Visitor<T> {
572					type Value = Cow<'static, [T]>;
573
574					fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
575						f.write_str("a vector of objects implementing ProtocolEncoding")
576					}
577
578					fn visit_seq<A: de::SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
579						let mut ret = Vec::with_capacity(seq.size_hint().unwrap_or_default());
580						while let Some(v) = seq.next_element::<DeWrapper<T>>()? {
581							ret.push(v.0);
582						}
583						Ok(ret.into())
584					}
585				}
586				d.deserialize_seq(Visitor(PhantomData))
587			}
588		}
589	}
590}
591
592
593#[cfg(test)]
594mod test {
595	use bitcoin::hex::DisplayHex;
596	use bitcoin::secp256k1::{self, Keypair};
597
598	use crate::SECP;
599	use super::*;
600
601
602	#[test]
603	fn option_pubkey() {
604		let key = Keypair::new(&SECP, &mut secp256k1::rand::thread_rng());
605		let pk = key.public_key();
606
607		println!("pk: {}", pk);
608
609		println!("serialize option: {}",
610			<Option<PublicKey> as ProtocolEncoding>::serialize(&Some(pk)).as_hex(),
611		);
612
613		assert_eq!(pk,
614			ProtocolEncoding::deserialize(&ProtocolEncoding::serialize(&pk)).unwrap(),
615		);
616
617		assert_eq!(Some(pk),
618			ProtocolEncoding::deserialize(&ProtocolEncoding::serialize(&Some(pk))).unwrap(),
619		);
620
621		assert_eq!(None,
622			<Option<PublicKey> as ProtocolEncoding>::deserialize(
623				&ProtocolEncoding::serialize(&Option::<PublicKey>::None),
624			).unwrap(),
625		);
626
627	}
628}