Skip to content

Commit

Permalink
commit: refactor CommitmentId trait system and tags
Browse files Browse the repository at this point in the history
  • Loading branch information
dr-orlovsky committed Feb 1, 2024
1 parent 49173a4 commit ec9b66e
Show file tree
Hide file tree
Showing 9 changed files with 69 additions and 67 deletions.
2 changes: 0 additions & 2 deletions commit_verify/derive/src/derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ impl CommitDerive {
let (impl_generics, ty_generics, where_clause) = self.data.generics.split_for_impl();
let trait_crate = &self.conf.commit_crate;
let commitment_id = &self.conf.id;
let tag = &self.conf.tag;
let ident_name = &self.data.name;

let inner = match self.conf.strategy {
Expand All @@ -53,7 +52,6 @@ impl CommitDerive {
Ok(quote! {
#[automatically_derived]
impl #impl_generics #trait_crate::CommitEncode for #ident_name #ty_generics #where_clause {
const COMMITMENT_TAG: &'static str = #tag;
type CommitmentId = #commitment_id;

fn commit_encode(&self, engine: &mut #trait_crate::CommitEngine) {
Expand Down
9 changes: 2 additions & 7 deletions commit_verify/derive/src/params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use amplify_syn::{ArgValueReq, AttrReq, DataType, LiteralClass, ParametrizedAttr, TypeClass};
use amplify_syn::{ArgValueReq, AttrReq, DataType, ParametrizedAttr, TypeClass};
use proc_macro2::Span;
use quote::ToTokens;
use syn::{DeriveInput, Error, LitStr, Path, Result};
use syn::{DeriveInput, Error, Path, Result};

const ATTR: &str = "commit_encode";
const ATTR_CRATE: &str = "crate";
const ATTR_TAG: &str = "tag";
const ATTR_ID: &str = "id";
const ATTR_STRATEGY: &str = "strategy";
const ATTR_STRATEGY_STRICT: &str = "strict";
Expand All @@ -37,7 +36,6 @@ const ATTR_STRATEGY_MERKLIZE: &str = "merklize";
pub struct ContainerAttr {
pub commit_crate: Path,
pub strategy: StrategyAttr,
pub tag: LitStr,
pub id: Path,
}

Expand Down Expand Up @@ -77,22 +75,19 @@ impl TryFrom<ParametrizedAttr> for ContainerAttr {
let req = AttrReq::with(map![
ATTR_CRATE => ArgValueReq::optional(TypeClass::Path),
ATTR_ID => ArgValueReq::required(TypeClass::Path),
ATTR_TAG => ArgValueReq::required(LiteralClass::Str),
ATTR_STRATEGY => ArgValueReq::required(TypeClass::Path),
]);
params.check(req)?;

let path = params.arg_value(ATTR_STRATEGY).expect("must be present");
let strategy = StrategyAttr::try_from(&path)?;
let tag = params.arg_value(ATTR_TAG).expect("must be present");
let id = params.arg_value(ATTR_ID).expect("must be present");

Ok(ContainerAttr {
commit_crate: params
.arg_value(ATTR_CRATE)
.unwrap_or_else(|_| path!(commit_verify)),
strategy,
tag,
id,
})
}
Expand Down
26 changes: 15 additions & 11 deletions commit_verify/derive/tests/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ mod common;
use std::fmt::Display;

use amplify::{Bytes32, Wrapper};
use commit_verify::{CommitEncode, CommitmentId, Conceal, DigestExt, Sha256};
use commit_verify::{CommitEncode, CommitId, CommitmentId, Conceal, DigestExt, Sha256};
use strict_encoding::{StrictDecode, StrictDumb, StrictEncode};

const TEST_LIB: &str = "TestLib";
Expand All @@ -46,20 +46,24 @@ struct DumbId(
Bytes32,
);

impl CommitmentId for DumbId {
const TAG: &'static str = "";
}

impl From<Sha256> for DumbId {
fn from(value: Sha256) -> Self { value.finish().into() }
}

fn verify_commit<T: CommitmentId>(value: T, expect: &'static str)
where T::Id: Display {
assert_eq!(&value.commitment_id().to_string(), expect, "invalid commitment");
fn verify_commit<T: CommitId>(value: T, expect: &'static str)
where T::CommitmentId: Display {
assert_eq!(&value.commit_id().to_string(), expect, "invalid commitment");
}

#[test]
fn strategy_transparent() -> common::Result {
#[derive(Wrapper, Clone, PartialEq, Eq, Debug, From)]
#[derive(CommitEncode)]
#[commit_encode(strategy = transparent, tag = "", id = DumbId)]
#[commit_encode(strategy = transparent, id = DumbId)]
struct ShortLen(u16);

verify_commit(ShortLen(0), "2bb00b2f346511235882255a898a224b6858e18ebec0a11967eb51f0ed1a2ff5");
Expand All @@ -78,7 +82,7 @@ fn strategy_strict_enum() -> common::Result {
#[derive(StrictDumb, StrictType, StrictEncode, StrictDecode)]
#[strict_type(lib = TEST_LIB, tags = repr, into_u8, try_from_u8)]
#[derive(CommitEncode)]
#[commit_encode(strategy = strict, tag = "", id = DumbId)]
#[commit_encode(strategy = strict, id = DumbId)]
#[repr(u8)]
enum Prim {
#[strict_type(dumb)]
Expand All @@ -100,7 +104,7 @@ fn strategy_strict_tuple() -> common::Result {
#[derive(StrictDumb, StrictType, StrictEncode, StrictDecode)]
#[strict_type(lib = TEST_LIB)]
#[derive(CommitEncode)]
#[commit_encode(strategy = strict, tag = "", id = DumbId)]
#[commit_encode(strategy = strict, id = DumbId)]
struct TaggedInfo(u16, u64);

verify_commit(
Expand All @@ -117,7 +121,7 @@ fn strategy_strict_struct() -> common::Result {
#[derive(StrictDumb, StrictType, StrictEncode, StrictDecode)]
#[strict_type(lib = TEST_LIB)]
#[derive(CommitEncode)]
#[commit_encode(strategy = strict, tag = "", id = DumbId)]
#[commit_encode(strategy = strict, id = DumbId)]
struct TaggedInfo {
a: u16,
b: u64,
Expand All @@ -141,7 +145,7 @@ fn enum_associated() -> common::Result {
#[derive(StrictDumb, StrictType, StrictEncode, StrictDecode)]
#[strict_type(lib = TEST_LIB, tags = order)]
#[derive(CommitEncode)]
#[commit_encode(strategy = strict, tag = "", id = DumbId)]
#[commit_encode(strategy = strict, id = DumbId)]
enum Assoc {
One {
hash: [u8; 32],
Expand Down Expand Up @@ -172,7 +176,7 @@ fn enum_custom_tags() -> common::Result {
#[derive(StrictDumb, StrictType, StrictEncode, StrictDecode)]
#[strict_type(lib = TEST_LIB, tags = order)]
#[derive(CommitEncode)]
#[commit_encode(strategy = strict, tag = "", id = DumbId)]
#[commit_encode(strategy = strict, id = DumbId)]
enum Assoc {
#[strict_type(tag = 8)]
One { hash: [u8; 32], ord: u8 },
Expand Down Expand Up @@ -205,7 +209,7 @@ fn conceal() -> common::Result {
#[derive(StrictDumb, StrictType, StrictEncode, StrictDecode)]
#[strict_type(lib = TEST_LIB, tags = order, dumb = { Self::Concealed(0) })]
#[derive(CommitEncode)]
#[commit_encode(strategy = conceal, tag = "", id = DumbId)]
#[commit_encode(strategy = conceal, id = DumbId)]
enum Data {
Revealed(u128),
Concealed(u8),
Expand Down
25 changes: 11 additions & 14 deletions commit_verify/src/id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,8 @@ impl CommitEngine {
/// necessary conceal and merklization procedures, and them performing strict
/// encoding for the resulted data.
pub trait CommitEncode {
const COMMITMENT_TAG: &'static str;

/// Type of the resulting commitment.
type CommitmentId: From<Sha256> + StrictType;
type CommitmentId: CommitmentId;

/// Encodes the data for the commitment by writing them directly into a
/// [`io::Write`] writer instance
Expand All @@ -86,28 +84,27 @@ pub struct CommitmentLayout {
fields: Vec<TypeFqn>,
}

pub trait CommitmentId: Copy + Ord + From<Sha256> + StrictType {
const TAG: &'static str;
}

/// High-level API used in client-side validation for producing a single
/// commitment to the data, which includes running all necessary procedures like
/// concealment with [`crate::Conceal`], merklization, strict encoding,
/// wrapped into [`CommitEncode`], followed by the actual commitment to its
/// output.
pub trait CommitmentId: CommitEncode {
/// Type of the resulting commitment.
type Id: From<Sha256>;

pub trait CommitId: CommitEncode {
fn commit(&self) -> CommitEngine;

fn commitment_layout(&self) -> CommitmentLayout;

/// Performs commitment to client-side-validated data
fn commitment_id(&self) -> Self::Id;
fn commit_id(&self) -> Self::CommitmentId;
}

impl<T: CommitEncode> CommitmentId for T {
type Id = T::CommitmentId;

impl<T: CommitEncode> CommitId for T {
fn commit(&self) -> CommitEngine {
let mut engine = CommitEngine::new(T::COMMITMENT_TAG);
let mut engine = CommitEngine::new(T::CommitmentId::TAG);
self.commit_encode(&mut engine);
engine.set_finished();
engine
Expand All @@ -121,10 +118,10 @@ impl<T: CommitEncode> CommitmentId for T {
Self::CommitmentId::strict_name()
.expect("commitment types must have explicit type name"),
),
tag: T::COMMITMENT_TAG,
tag: T::CommitmentId::TAG,
fields,
}
}

fn commitment_id(&self) -> Self::Id { self.commit().finish().into() }
fn commit_id(&self) -> Self::CommitmentId { self.commit().finish().into() }
}
2 changes: 1 addition & 1 deletion commit_verify/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ pub use conceal::Conceal;
pub use convolve::{ConvolveCommit, ConvolveCommitProof, ConvolveVerifyError};
pub use digest::{Digest, DigestExt, Ripemd160, Sha256};
pub use embed::{EmbedCommitProof, EmbedCommitVerify, EmbedVerifyError, VerifyEq};
pub use id::{CommitEncode, CommitEngine, CommitmentId, CommitmentLayout};
pub use id::{CommitEncode, CommitEngine, CommitId, CommitmentId, CommitmentLayout};
pub use merkle::{MerkleBuoy, MerkleHash, MerkleLeaves, MerkleNode, NodeBranching};

pub const LIB_NAME_COMMIT_VERIFY: &str = "CommitVerify";
Expand Down
22 changes: 13 additions & 9 deletions commit_verify/src/merkle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use sha2::Sha256;
use strict_encoding::StrictEncode;

use crate::digest::DigestExt;
use crate::{CommitmentId, LIB_NAME_COMMIT_VERIFY};
use crate::{CommitId, CommitmentId, LIB_NAME_COMMIT_VERIFY};

/// Type of a merkle node branching.
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
Expand All @@ -55,7 +55,7 @@ pub enum NodeBranching {
#[derive(StrictDumb, StrictType, StrictEncode, StrictDecode)]
#[strict_type(lib = LIB_NAME_COMMIT_VERIFY)]
#[derive(CommitEncode)]
#[commit_encode(crate = crate, strategy = strict, id = MerkleHash, tag = "urn:lnpbp:merkle:node#2024-01-31")]
#[commit_encode(crate = crate, strategy = strict, id = MerkleHash)]
pub struct MerkleNode {
pub branching: NodeBranching,
pub depth: u8,
Expand Down Expand Up @@ -118,6 +118,10 @@ pub struct MerkleHash(
Bytes32,
);

impl CommitmentId for MerkleHash {
const TAG: &'static str = "urn:lnpbp:merkle:node#2024-01-31";
}

impl From<Sha256> for MerkleHash {
fn from(hash: Sha256) -> Self { hash.finish().into() }
}
Expand All @@ -126,11 +130,11 @@ const VIRTUAL_LEAF: MerkleHash = MerkleHash(Bytes32::from_array([0xFF; 32]));

impl MerkleHash {
pub fn void(depth: impl Into<u8>, width: impl Into<u256>) -> Self {
MerkleNode::void(depth, width).commitment_id()
MerkleNode::void(depth, width).commit_id()
}

pub fn single(depth: impl Into<u8>, width: impl Into<u256>, node: MerkleHash) -> Self {
MerkleNode::single(depth, width, node).commitment_id()
MerkleNode::single(depth, width, node).commit_id()
}

pub fn branches(
Expand All @@ -139,7 +143,7 @@ impl MerkleHash {
node1: MerkleHash,
node2: MerkleHash,
) -> Self {
MerkleNode::branches(depth, width, node1, node2).commitment_id()
MerkleNode::branches(depth, width, node1, node2).commit_id()
}
}

Expand All @@ -149,7 +153,7 @@ impl MerkleHash {
///
/// [LNPBP-81]: https://github.com/LNP-BP/LNPBPs/blob/master/lnpbp-0081.md
pub fn merklize(leaves: &impl MerkleLeaves) -> Self {
let mut nodes = leaves.merkle_leaves().map(|leaf| leaf.commitment_id());
let mut nodes = leaves.merkle_leaves().map(|leaf| leaf.commit_id());
let len = nodes.len() as u32;
if len == 1 {
// If we have just one leaf, it's MerkleNode value is the root
Expand Down Expand Up @@ -197,15 +201,15 @@ impl MerkleHash {
}

pub trait MerkleLeaves {
type Leaf: CommitmentId<Id = MerkleHash>;
type Leaf: CommitId<CommitmentId = MerkleHash>;
type LeafIter<'tmp>: ExactSizeIterator<Item = Self::Leaf>
where Self: 'tmp;

fn merkle_leaves(&self) -> Self::LeafIter<'_>;
}

impl<T, const MIN: usize> MerkleLeaves for Confined<Vec<T>, MIN, { u16::MAX as usize }>
where T: CommitmentId<Id = MerkleHash> + Copy
where T: CommitId<CommitmentId = MerkleHash> + Copy
{
type Leaf = T;
type LeafIter<'tmp> = iter::Copied<slice::Iter<'tmp, T>> where Self: 'tmp;
Expand All @@ -214,7 +218,7 @@ where T: CommitmentId<Id = MerkleHash> + Copy
}

impl<T: Ord, const MIN: usize> MerkleLeaves for Confined<BTreeSet<T>, MIN, { u16::MAX as usize }>
where T: CommitmentId<Id = MerkleHash> + Copy
where T: CommitId<CommitmentId = MerkleHash> + Copy
{
type Leaf = T;
type LeafIter<'tmp> = iter::Copied<btree_set::Iter<'tmp, T>> where Self: 'tmp;
Expand Down
8 changes: 6 additions & 2 deletions commit_verify/src/mpc/atoms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use sha2::Sha256;
use strict_encoding::StrictDumb;

use crate::merkle::MerkleHash;
use crate::DigestExt;
use crate::{CommitmentId, DigestExt};

pub const MPC_MINIMAL_DEPTH: u5 = u5::with(3);

Expand Down Expand Up @@ -86,7 +86,7 @@ impl Message {
#[derive(StrictType, StrictEncode, StrictDecode)]
#[strict_type(lib = crate::LIB_NAME_COMMIT_VERIFY, tags = custom)]
#[derive(CommitEncode)]
#[commit_encode(crate = crate, strategy = strict, tag = "urn:lnpbp:mpc:tree:leaf#2024-01-31", id = MerkleHash)]
#[commit_encode(crate = crate, strategy = strict, id = MerkleHash)]
pub enum Leaf {
// We use this constant since we'd like to be distinct from NodeBranching values
#[strict_type(tag = 0x10)]
Expand Down Expand Up @@ -132,6 +132,10 @@ pub struct Commitment(
Bytes32,
);

impl CommitmentId for Commitment {
const TAG: &'static str = "urn:lnpbp:mpc:commitment#2024-01-31";
}

impl Commitment {
pub fn copy_from_slice(slice: &[u8]) -> Result<Self, FromSliceError> {
Bytes32::copy_from_slice(slice).map(Self)
Expand Down
Loading

0 comments on commit ec9b66e

Please sign in to comment.