From 32dea7ba1a55851fb488a5cead6788312176032a Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Tue, 29 Jul 2025 16:09:58 +0200 Subject: [PATCH 1/3] stl: use Vesper 0.2.3. Improve commitment Vesper representation --- Cargo.lock | 12 +-- Cargo.toml | 2 +- commit_verify/Cargo.toml | 6 +- commit_verify/derive/src/derive.rs | 2 +- commit_verify/src/id.rs | 24 +++-- commit_verify/src/vesper.rs | 46 ++++++---- stl/Merkle.vesper | 138 ++++++++++++++--------------- 7 files changed, 126 insertions(+), 104 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b6ed6f7e..b112155f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -76,9 +76,9 @@ dependencies = [ [[package]] name = "baid64" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cb4a8b2f1afee4ef00a190b260ad871842b93206177b59631fecd325d48d538" +checksum = "61eced31ae690ea39ffe808ed970bd11ebbb3ccc6861d2ab787d848b03a0d049" dependencies = [ "amplify", "base64", @@ -491,9 +491,9 @@ dependencies = [ [[package]] name = "strict_types" -version = "2.9.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "493821521630a023d79a210033fe1f5135ae3d3f8fccd8dbf1a98b7dfe56b144" +checksum = "b15dbefeb173aed20f7e92c69a7ad341534f2b3edcbb80a0c4fd236056fec8a2" dependencies = [ "amplify", "ascii-armor", @@ -579,9 +579,9 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "vesper-lang" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd2b7e3e27aeb0524204e58042f6e4531a720745d1b1a3978d3a084f1885f63d" +checksum = "2d744003ca4d792e891d3f55fabb1f0458d78635f2ec6c75198b77f62c64814f" dependencies = [ "amplify", "strict_encoding", diff --git a/Cargo.toml b/Cargo.toml index b375292d..8b799041 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ license = "Apache-2.0" [workspace.dependencies] amplify = "~4.9.0" strict_encoding = "~2.9.1" -strict_types = "~2.9.0" +strict_types = "~2.9.1" serde = { version = "1", features = ["derive"] } [package] diff --git a/commit_verify/Cargo.toml b/commit_verify/Cargo.toml index ec6e113d..67668741 100644 --- a/commit_verify/Cargo.toml +++ b/commit_verify/Cargo.toml @@ -25,7 +25,7 @@ required-features = ["stl", "vesper"] amplify = { workspace = true } strict_encoding = { workspace = true } strict_types = { workspace = true } -vesper-lang = "0.2.1" +vesper-lang = "0.2.3" commit_encoding_derive = { version = "0.12.0", path = "derive" } sha2 = "0.10.8" ripemd = "0.1.3" @@ -40,8 +40,8 @@ default = ["derive"] all = ["rand", "derive", "stl", "vesper", "serde"] derive = [] rand = ["dep:rand"] -stl = ["strict_types/armor"] -vesper = [] +stl = ["strict_types/armor", "strict_types/stl"] +vesper = ["strict_types/vesper"] serde = ["dep:serde", "amplify/serde"] [target.'cfg(target_arch = "wasm32")'.dependencies] diff --git a/commit_verify/derive/src/derive.rs b/commit_verify/derive/src/derive.rs index 3e9d5be3..c0ffd92e 100644 --- a/commit_verify/derive/src/derive.rs +++ b/commit_verify/derive/src/derive.rs @@ -41,7 +41,7 @@ impl CommitDerive { }, StrategyAttr::ConcealStrict => quote! { use #trait_crate::Conceal; - engine.commit_to_concealed(&self.conceal()); + engine.commit_to_concealed(self); }, StrategyAttr::Transparent => quote! { use amplify::Wrapper; diff --git a/commit_verify/src/id.rs b/commit_verify/src/id.rs index 24b31077..13c5adcf 100644 --- a/commit_verify/src/id.rs +++ b/commit_verify/src/id.rs @@ -77,7 +77,12 @@ pub enum CommitStep { Merklized(TypeFqn), /// Serialization with [`CommitEngine::commit_to_concealed`]. - Concealed(TypeFqn), + Concealed { + /// The source type to which the concealment is applied. + src: TypeFqn, + /// The destination type of the concealment. + dst: TypeFqn, + }, } /// A helper engine used in computing commitment ids. @@ -183,9 +188,13 @@ impl CommitEngine { T: Conceal + StrictType, T::Concealed: StrictEncode, { - let fqn = commitment_fqn::(); + let src = commitment_fqn::(); + let dst = commitment_fqn::(); self.layout - .push(CommitStep::Concealed(fqn)) + .push(CommitStep::Concealed { + src, + dst: dst.clone(), + }) .expect("too many fields for commitment"); let concealed = value.conceal(); @@ -311,6 +320,7 @@ pub trait CommitEncode { #[derive(Getters, Clone, Eq, PartialEq, Hash, Debug)] pub struct CommitLayout { idty: TypeFqn, + ty: TypeFqn, #[getter(as_copy)] tag: &'static str, fields: TinyVec, @@ -339,12 +349,13 @@ pub trait CommitmentLayout: CommitEncode { } impl CommitmentLayout for T -where T: CommitEncode + StrictDumb +where T: CommitEncode + StrictType + StrictDumb { fn commitment_layout() -> CommitLayout { let dumb = Self::strict_dumb(); let fields = dumb.commit().into_layout(); CommitLayout { + ty: commitment_fqn::(), idty: TypeFqn::with( libname!(Self::CommitmentId::STRICT_LIB_NAME), Self::CommitmentId::strict_name() @@ -474,7 +485,10 @@ mod tests { engine.commit_to_concealed(&val); engine.set_finished(); let (id, layout) = engine.finish_layout(); - assert_eq!(layout, tiny_vec![CommitStep::Concealed(TypeFqn::from("Test.DumbConceal"))]); + assert_eq!(layout, tiny_vec![CommitStep::Concealed { + src: TypeFqn::from("Test.DumbConceal"), + dst: TypeFqn::from("Test.DumbHash") + },]); assert_eq!( id.finish(), Sha256::from_tag("test") diff --git a/commit_verify/src/vesper.rs b/commit_verify/src/vesper.rs index f7b2aab2..1d85d543 100644 --- a/commit_verify/src/vesper.rs +++ b/commit_verify/src/vesper.rs @@ -35,10 +35,10 @@ pub type VesperCommit = TExpr; #[display(lowercase)] pub enum Pred { Commitment, - Serialized, - Hashed, - Merklized, - Concealed, + Serialize, + Hash, + Merklize, + Conceal, List, Set, Element, @@ -55,6 +55,7 @@ impl Predicate for Pred { #[derive(Clone, Eq, PartialEq, Hash, Debug)] pub enum Attr { + For(TypeFqn), Tagged(&'static str), Concealed(TypeFqn), LenRange(LenRange), @@ -74,8 +75,9 @@ impl Attribute for Attr { fn name(&self) -> Option { match self { + Attr::For(_) => Some(ident!("for")), Attr::Tagged(_) => Some(ident!("tagged")), - Attr::Concealed(_) => Some(ident!("concealed")), + Attr::Concealed { .. } => Some(ident!("to")), Attr::LenRange(_) => Some(ident!("len")), Attr::Hasher => Some(ident!("hasher")), } @@ -83,6 +85,7 @@ impl Attribute for Attr { fn value(&self) -> AttrVal { match self { + Attr::For(fqn) => AttrVal::Ident(fqn.name.to_ident()), Attr::Tagged(tag) => AttrVal::Expr(AttrExpr::Tag(tag)), Attr::Concealed(fqn) => AttrVal::Ident(fqn.name.to_ident()), Attr::LenRange(range) => AttrVal::Expr(AttrExpr::LenRange(range.clone())), @@ -98,7 +101,7 @@ impl CommitStep { CommitStep::Collection(_, _, fqn) => fqn, CommitStep::Hashed(fqn) => fqn, CommitStep::Merklized(fqn) => fqn, - CommitStep::Concealed(fqn) => fqn, + CommitStep::Concealed { src, dst: _ } => src, } .name .to_ident() @@ -106,20 +109,20 @@ impl CommitStep { fn predicate(&self) -> Pred { match self { - CommitStep::Serialized(_) => Pred::Serialized, + CommitStep::Serialized(_) => Pred::Serialize, CommitStep::Collection(CommitColType::List, _, _) => Pred::List, CommitStep::Collection(CommitColType::Set, _, _) => Pred::Set, CommitStep::Collection(CommitColType::Map { .. }, _, _) => Pred::Map, - CommitStep::Hashed(_) => Pred::Hashed, - CommitStep::Merklized(_) => Pred::Merklized, - CommitStep::Concealed(_) => Pred::Concealed, + CommitStep::Hashed(_) => Pred::Hash, + CommitStep::Merklized(_) => Pred::Merklize, + CommitStep::Concealed { .. } => Pred::Conceal, } } fn attributes(&self) -> SmallVec { match self { CommitStep::Collection(_, sizing, _) => small_vec![Attr::LenRange((*sizing).into())], - CommitStep::Concealed(from) => small_vec![Attr::Concealed(from.clone())], + CommitStep::Concealed { src: _, dst } => small_vec![Attr::Concealed(dst.clone())], CommitStep::Serialized(_) | CommitStep::Hashed(_) | CommitStep::Merklized(_) => none!(), } } @@ -154,10 +157,17 @@ impl CommitStep { }) ] } - CommitStep::Serialized(_) | - CommitStep::Hashed(_) | - CommitStep::Merklized(_) | - CommitStep::Concealed(_) => empty!(), + CommitStep::Serialized(_) => none!(), + + CommitStep::Hashed(subj) | + CommitStep::Merklized(subj) | + CommitStep::Concealed { src: _, dst: subj } => tiny_vec![Box::new(VesperCommit { + subject: subj.name.to_ident(), + predicate: Pred::Serialize, + attributes: none!(), + content: none!(), + comment: None, + })], } } } @@ -182,7 +192,11 @@ impl CommitLayout { VesperCommit { subject, predicate: Pred::Commitment, - attributes: small_vec![Attr::Hasher, Attr::Tagged(self.tag())], + attributes: small_vec![ + Attr::For(self.ty().clone()), + Attr::Hasher, + Attr::Tagged(self.tag()) + ], content: Confined::from_iter_checked(content), comment: None, } diff --git a/stl/Merkle.vesper b/stl/Merkle.vesper index 7c82750c..4b611074 100644 --- a/stl/Merkle.vesper +++ b/stl/Merkle.vesper @@ -10,93 +10,87 @@ Merklization vesper lexicon=types+commitments -- General merklization workflows -commitment MerkleHash, hasher SHA256, tagged urn:ubideco:merkle:node#2024-01-31 - serialized MerkleNode +commitment MerkleHash: for MerkleNode, hasher SHA256, tagged urn:ubideco:merkle:node#2024-01-31 + serialize MerkleNode -rec MerkleNode - enum branching, NodeBranching, void 0, single 1, branch 2 - is depth, U8 - is width, U256 - bytes node1, len 32, aka MerkleHash - bytes node2, len 32, aka MerkleHash +struct MerkleNode + enum branching: NodeBranching, void 0, single 1, branch 2 + field depth: U8 + field width: U256 + bytes node1: len 32, alias MerkleHash + bytes node2: len 32, alias MerkleHash -- Multi-protocol commitment workflows -commitment MerkleHash, hasher SHA256, tagged urn:ubideco:merkle:node#2024-01-31 - serialized Leaf +commitment MerkleHash: for Leaf, hasher SHA256, tagged urn:ubideco:merkle:node#2024-01-31 + serialize Leaf union Leaf - rec inhabited, tag 0 - bytes protocol, len 32, aka ProtocolId - bytes message, len 32, aka Message - rec entropy, tag 1 - is entropy, U64 - is pos, U32 - -commitment Commitment, hasher SHA256, tagged urn:ubideco:mpc:commitment#2024-01-31 - serialized MerkleConcealed - -rec MerkleConcealed - enum depth { - U5, _0 0, _1 1, _2 2, _3 3, _4 4, _5 5, _6 6, _7 7 - _8 8, _9 9, _10 10, _11 11, _12 12, _13 13, _14 14, _15 15 - _16 16, _17 17, _18 18, _19 19, _20 20, _21 21, _22 22, _23 23 + struct inhabited: tag 0 + bytes protocol: len 32, alias ProtocolId + bytes message: len 32, alias Message + struct entropy: tag 1 + field entropy: U64 + field pos: U32 + +commitment Commitment: for MerkleConcealed, hasher SHA256, tagged urn:ubideco:mpc:commitment#2024-01-31 + serialize MerkleConcealed + +struct MerkleConcealed + enum depth: U5, _0 0, _1 1, _2 2, _3 3, _4 4, _5 5, _6 6, _7 7, + _8 8, _9 9, _10 10, _11 11, _12 12, _13 13, _14 14, _15 15, + _16 16, _17 17, _18 18, _19 19, _20 20, _21 21, _22 22, _23 23, _24 24, _25 25, _26 26, _27 27, _28 28, _29 29, _30 30, _31 31 - } - is cofactor, U16 - bytes merkleRoot, len 32, aka MerkleHash - -commitment Commitment, hasher SHA256, tagged urn:ubideco:mpc:commitment#2024-01-31 - concealed MerkleConcealed, concealed MerkleConcealed - -rec MerkleBlock - enum method, Method, sha256t 0 - enum depth { - U5, _0 0, _1 1, _2 2, _3 3, _4 4, _5 5, _6 6, _7 7 - _8 8, _9 9, _10 10, _11 11, _12 12, _13 13, _14 14, _15 15 - _16 16, _17 17, _18 18, _19 19, _20 20, _21 21, _22 22, _23 23 + field cofactor: U16 + bytes merkleRoot: len 32, alias MerkleHash + +commitment Commitment: for MerkleBlock, hasher SHA256, tagged urn:ubideco:mpc:commitment#2024-01-31 + conceal MerkleBlock: to MerkleConcealed + serialize MerkleConcealed + +struct MerkleBlock + enum method: Method, sha256t 0 + enum depth: U5, _0 0, _1 1, _2 2, _3 3, _4 4, _5 5, _6 6, _7 7, + _8 8, _9 9, _10 10, _11 11, _12 12, _13 13, _14 14, _15 15, + _16 16, _17 17, _18 18, _19 19, _20 20, _21 21, _22 22, _23 23, _24 24, _25 25, _26 26, _27 27, _28 28, _29 29, _30 30, _31 31 - } - is cofactor, U16 - list crossSection, len 1..MAX32 + field cofactor: U16 + list crossSection: len 1..<2^32 union TreeNode - rec concealedNode, tag 0 - enum depth { - U5, _0 0, _1 1, _2 2, _3 3, _4 4, _5 5, _6 6, _7 7 - _8 8, _9 9, _10 10, _11 11, _12 12, _13 13, _14 14, _15 15 - _16 16, _17 17, _18 18, _19 19, _20 20, _21 21, _22 22, _23 23 + struct concealedNode: tag 0 + enum depth: U5, _0 0, _1 1, _2 2, _3 3, _4 4, _5 5, _6 6, _7 7, + _8 8, _9 9, _10 10, _11 11, _12 12, _13 13, _14 14, _15 15, + _16 16, _17 17, _18 18, _19 19, _20 20, _21 21, _22 22, _23 23, _24 24, _25 25, _26 26, _27 27, _28 28, _29 29, _30 30, _31 31 - } - bytes hash, len 32, aka MerkleHash - rec commitmentLeaf, tag 1 - bytes protocolId, len 32, aka ProtocolId - bytes message, len 32, aka Message - is some, U64, option, wrapped, tag 1 - -commitment Commitment, hasher SHA256, tagged urn:ubideco:mpc:commitment#2024-01-31 - concealed MerkleConcealed, concealed MerkleConcealed - -rec MerkleTree - enum method, Method, sha256t 0 - enum depth { - U5, _0 0, _1 1, _2 2, _3 3, _4 4, _5 5, _6 6, _7 7 - _8 8, _9 9, _10 10, _11 11, _12 12, _13 13, _14 14, _15 15 - _16 16, _17 17, _18 18, _19 19, _20 20, _21 21, _22 22, _23 23 + bytes hash: len 32, alias MerkleHash + struct commitmentLeaf: tag 1 + bytes protocolId: len 32, alias ProtocolId + bytes message: len 32, alias Message + field some: U64, option, wrapped, tag 1 + +commitment Commitment: for MerkleTree, hasher SHA256, tagged urn:ubideco:mpc:commitment#2024-01-31 + conceal MerkleTree: to MerkleConcealed + serialize MerkleConcealed + +struct MerkleTree + enum method: Method, sha256t 0 + enum depth: U5, _0 0, _1 1, _2 2, _3 3, _4 4, _5 5, _6 6, _7 7, + _8 8, _9 9, _10 10, _11 11, _12 12, _13 13, _14 14, _15 15, + _16 16, _17 17, _18 18, _19 19, _20 20, _21 21, _22 22, _23 23, _24 24, _25 25, _26 26, _27 27, _28 28, _29 29, _30 30, _31 31 - } - is entropy, U64 - is cofactor, U16 - map messages, len 0..MAX24 - bytes key, len 32, aka ProtocolId - bytes value, len 32, aka Message - map map, len 0..MAX24 - is key, U32 + field entropy: U64 + field cofactor: U16 + map messages: len 0..<2^24 + bytes key: len 32, alias ProtocolId + bytes value: len 32, alias Message + map map: len 0..<2^24 + field key: U32 tuple value - bytes _, len 32, aka ProtocolId - bytes _, len 32, aka Message + bytes _: len 32, alias ProtocolId + bytes _: len 32, alias Message From 648c72e956f591e5017a21721a879c2cf16b3677 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Tue, 29 Jul 2025 17:17:47 +0200 Subject: [PATCH 2/3] test: vesper serialization --- commit_verify/src/id.rs | 8 ++--- commit_verify/src/vesper.rs | 66 +++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 4 deletions(-) diff --git a/commit_verify/src/id.rs b/commit_verify/src/id.rs index 13c5adcf..4db53ece 100644 --- a/commit_verify/src/id.rs +++ b/commit_verify/src/id.rs @@ -418,14 +418,14 @@ impl From for StrictHash { } #[cfg(test)] -mod tests { +pub(crate) mod tests { #![cfg_attr(coverage_nightly, coverage(off))] use super::*; #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Default)] #[derive(StrictType, StrictEncode, StrictDecode)] #[strict_type(lib = "Test")] - struct DumbConceal(u8); + pub struct DumbConceal(u8); impl Conceal for DumbConceal { type Concealed = DumbHash; @@ -437,14 +437,14 @@ mod tests { #[strict_type(lib = "Test")] #[derive(CommitEncode)] #[commit_encode(crate = self, strategy = strict, id = StrictHash)] - struct DumbHash(u8); + pub struct DumbHash(u8); #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Default)] #[derive(StrictType, StrictEncode, StrictDecode)] #[strict_type(lib = "Test")] #[derive(CommitEncode)] #[commit_encode(crate = self, strategy = strict, id = MerkleHash)] - struct DumbMerkle(u8); + pub struct DumbMerkle(u8); #[test] fn commit_engine_strict() { diff --git a/commit_verify/src/vesper.rs b/commit_verify/src/vesper.rs index 1d85d543..6d184fd3 100644 --- a/commit_verify/src/vesper.rs +++ b/commit_verify/src/vesper.rs @@ -202,3 +202,69 @@ impl CommitLayout { } } } + +#[cfg(test)] +mod tests { + #![cfg_attr(coverage_nightly, coverage(off))] + + use amplify::confinement::{LargeString, SmallOrdMap, SmallOrdSet}; + use strict_encoding::{StrictDecode, StrictEncode}; + + use super::*; + use crate::id::tests::*; + use crate::{CommitEncode, CommitEngine, CommitmentLayout, StrictHash}; + + #[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Default)] + #[derive(StrictType, StrictEncode, StrictDecode)] + #[strict_type(lib = "Test")] + struct NamedWrapper(T); + + #[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Default)] + #[derive(StrictType, StrictEncode, StrictDecode)] + #[strict_type(lib = "Test")] + struct Test { + serialized: NamedWrapper, + concealed: DumbConceal, + hash: DumbHash, + merkle_list: TinyVec, + set: SmallOrdSet, + map: SmallOrdMap, + } + impl CommitEncode for Test { + type CommitmentId = StrictHash; + fn commit_encode(&self, e: &mut CommitEngine) { + e.commit_to_serialized(&self.serialized); + e.commit_to_concealed(&self.concealed); + e.commit_to_hash(&self.hash); + e.commit_to_merkle(&self.merkle_list); + e.commit_to_linear_set(&self.set); + e.commit_to_linear_map(&self.map); + } + } + + #[test] + fn display() { + let layout = Test::commitment_layout(); + assert_eq!( + layout + .to_vesper() + .display() + .to_string() + .replace(" \n", "\n"), + r#"commitment StrictHash: for Test, hasher SHA256, tagged urn:ubideco:strict-types:value-hash#2024-02-10 + serialize NamedWrapperConfinedString04294967295 + conceal DumbConceal: to DumbHash + serialize DumbHash + hash DumbHash + serialize DumbHash + merklize DumbMerkle + serialize DumbMerkle + set DumbHash: len 0..<2^16 + element DumbHash + map U64: len 0..<2^16 + mapKey U8 + mapValue U64 +"# + ); + } +} From a471665ffc3b3b61a43f679e568aabcd9d18fb16 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Tue, 29 Jul 2025 17:50:27 +0200 Subject: [PATCH 3/3] chore: bump the version to 0.12.1 --- Cargo.lock | 8 ++++---- Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b112155f..7d20389a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -139,7 +139,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "client_side_validation" -version = "0.12.0" +version = "0.12.1" dependencies = [ "commit_verify", "serde", @@ -148,7 +148,7 @@ dependencies = [ [[package]] name = "commit_encoding_derive" -version = "0.12.0" +version = "0.12.1" dependencies = [ "amplify", "amplify_syn", @@ -161,7 +161,7 @@ dependencies = [ [[package]] name = "commit_verify" -version = "0.12.0" +version = "0.12.1" dependencies = [ "amplify", "commit_encoding_derive", @@ -457,7 +457,7 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "single_use_seals" -version = "0.12.0" +version = "0.12.1" dependencies = [ "serde", "strict_encoding", diff --git a/Cargo.toml b/Cargo.toml index 8b799041..625a6e53 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ default-members = [ ] [workspace.package] -version = "0.12.0" +version = "0.12.1" authors = ["Dr Maxim Orlovsky "] homepage = "https://github.com/LNP-BP" repository = "https://github.com/LNP-BP/client_side_validation"