diff --git a/Cargo.lock b/Cargo.lock index 5d7da426..b46c0b66 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -113,6 +113,12 @@ dependencies = [ "sha2", ] +[[package]] +name = "base58" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6107fe1be6682a68940da878d9e9f5e90ca5745b3dec9fd1bb393c8777d4f581" + [[package]] name = "base64" version = "0.22.1" @@ -200,7 +206,7 @@ name = "bp-dbc" version = "0.12.0" dependencies = [ "amplify", - "base85", + "base58", "bp-consensus", "commit_verify", "getrandom 0.2.16", @@ -218,6 +224,7 @@ name = "bp-seals" version = "0.12.0" dependencies = [ "amplify", + "base58", "bp-consensus", "bp-dbc", "commit_verify", diff --git a/Cargo.toml b/Cargo.toml index 7e9df49d..edae0bbf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,7 @@ license = "Apache-2.0" [workspace.dependencies] amplify = "4.9.0" +base58 = "0.2.0" strict_encoding = "2.9.1" strict_types = "2.9.0" commit_verify = "0.12.0" diff --git a/dbc/Cargo.toml b/dbc/Cargo.toml index 4c3e2eb9..5b8f052f 100644 --- a/dbc/Cargo.toml +++ b/dbc/Cargo.toml @@ -18,7 +18,7 @@ path = "src/lib.rs" [dependencies] amplify = { workspace = true } -base85 = "=2.0.0" +base58 = { workspace = true } strict_encoding = { workspace = true } commit_verify = { workspace = true, features = ["rand"] } bp-consensus = { workspace = true } diff --git a/dbc/src/tapret/tapscript.rs b/dbc/src/tapret/tapscript.rs index cbae3010..6509ad20 100644 --- a/dbc/src/tapret/tapscript.rs +++ b/dbc/src/tapret/tapscript.rs @@ -26,6 +26,7 @@ use std::fmt::{self, Display, Formatter}; use std::str::FromStr; use amplify::confinement::Confined; +use base58::{FromBase58, ToBase58}; use bc::{TapCode, TapScript}; use commit_verify::{mpc, CommitVerify}; use strict_encoding::{ @@ -72,17 +73,16 @@ impl TapretCommitment { impl Display for TapretCommitment { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - let s = base85::encode(&self.to_vec()); + let s = self.to_vec().to_base58(); f.write_str(&s) } } impl FromStr for TapretCommitment { type Err = DeserializeError; fn from_str(s: &str) -> Result { - let data = base85::decode(s).map_err(|err| { + let data = s.from_base58().map_err(|_| { DecodeError::DataIntegrityError(format!( - "invalid Base85 encoding of tapret data \"{s}\": {}", - err.to_string().to_lowercase() + "invalid Base58 encoding of tapret data \"{s}\"", )) })?; let data = Confined::try_from(data).map_err(DecodeError::from)?; @@ -181,10 +181,10 @@ mod test { } #[test] - pub fn tapret_commitment_baid64() { + pub fn tapret_commitment_base58() { let commitment = commitment(); let s = commitment.to_string(); - assert_eq!(s, "k#7JerF92P=PEN7cf&`GWfS*?rIEdfEup1%zausI2m"); + assert_eq!(s, "kCmE8g7LJYxPC977vnhUQv4YqMGc5jzip3Rio6Aqau3yZ"); assert_eq!(Ok(commitment.clone()), TapretCommitment::from_str(&s)); } } diff --git a/seals/Cargo.toml b/seals/Cargo.toml index 4897ce7e..f4e954f9 100644 --- a/seals/Cargo.toml +++ b/seals/Cargo.toml @@ -18,6 +18,7 @@ path = "src/lib.rs" [dependencies] amplify = { workspace = true } +base58 = { workspace = true } single_use_seals = { workspace = true } commit_verify = { workspace = true } strict_encoding = { workspace = true } diff --git a/seals/src/txout.rs b/seals/src/txout.rs index f3f6cef5..06d965fe 100644 --- a/seals/src/txout.rs +++ b/seals/src/txout.rs @@ -27,8 +27,11 @@ use core::error::Error; use core::fmt::Debug; +use std::fmt::{Display, Formatter}; +use std::str::FromStr; use amplify::{ByteArray, Bytes, Bytes32}; +use base58::{FromBase58, ToBase58}; use bc::{Outpoint, Tx, Txid}; use commit_verify::{ CommitId, ConvolveVerifyError, DigestExt, EmbedVerifyError, ReservedBytes, Sha256, @@ -42,11 +45,9 @@ use crate::WOutpoint; /// A noise, which acts as a placeholder for seal definitions lacking fallback seal (see /// [`TxoSealExt::Noise`]). -#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display, From)] -#[display("{0:x}")] +#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)] #[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] #[strict_type(lib = dbc::LIB_NAME_BPCORE)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(transparent))] pub struct Noise(Bytes<40>); impl Noise { @@ -71,6 +72,62 @@ impl Noise { } } +impl Display for Noise { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let s = self.0[..32].to_base58(); + f.write_str(&s) + } +} + +impl FromStr for Noise { + type Err = base58::FromBase58Error; + + fn from_str(s: &str) -> Result { + let vec = s.from_base58()?; + if vec.len() != 32 { + return Err(base58::FromBase58Error::InvalidBase58Length); + } + let mut buf = [0xFFu8; 40]; + buf[..32].copy_from_slice(&vec); + Ok(Self(buf.into())) + } +} + +#[cfg(feature = "serde")] +mod _serde { + use amplify::Bytes; + use serde::de::Error; + use serde::{Deserialize, Deserializer, Serialize, Serializer}; + + use super::*; + + impl Serialize for Noise { + fn serialize(&self, serializer: S) -> Result + where S: Serializer { + if serializer.is_human_readable() { + self.to_string().serialize(serializer) + } else { + self.0[..32].serialize(serializer) + } + } + } + + impl<'de> Deserialize<'de> for Noise { + fn deserialize(deserializer: D) -> Result + where D: Deserializer<'de> { + if deserializer.is_human_readable() { + let s = String::deserialize(deserializer)?; + Self::from_str(&s).map_err(|_| D::Error::custom("invalid Base58 encoding")) + } else { + let slice = <[u8; 32]>::deserialize(deserializer)?; + let mut buf = [0xFF; 40]; + buf[..32].copy_from_slice(&slice); + Ok(Self::from(Bytes::from_byte_array(buf))) + } + } + } +} + /// Multi-message bundles. /// /// Multi-message bundles allow putting multiple independent messages into a single commitment under @@ -495,6 +552,16 @@ mod test { use crate::mpc::{MessageMap, MessageSource}; use crate::TxoSealError; + #[test] + fn noise_text() { + let mut noise = Noise::from(Bytes::from_byte_array([0xADu8; 40])); + noise.0[32..].fill(0xFF); + let s = noise.to_string(); + assert_eq!(s, "Cgy8m6ZmJbPC8fGoTgRxLSWyEUPpWzmrfbJX5kkeFdoJ"); + let noise2 = Noise::from_str(&s).unwrap(); + assert_eq!(noise, noise2); + } + fn setup_opret() -> (Vec, BundleProof, Vec, SealWitness) { setup(false) }