Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,14 @@ jobs:
run: cargo test --verbose --all-features

msrv:
name: Verify MSRV (1.87)
name: Verify MSRV (1.96)
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Install Rust Toolchain (1.87)
uses: dtolnay/rust-toolchain@1.87.0
- name: Install Rust Toolchain (1.96)
uses: dtolnay/rust-toolchain@1.96.0

- name: Check
run: cargo check --all-features
Expand Down
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,21 @@ All notable changes to this project are documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.3.0] - 2026-09-01

### Added

- Merkle-tree Lamport multisig view (`views::lamport_merkle`, behind the default `lamport` feature) wrapping the `lamport_signature_plus` 0.5.0 `Mt*` API: signature-share accumulation in `ThresholdData` and combination via `MtSignature::combine`, for 11 digest variants (SHA3-512/384/256, SHA2-512/384/256, BLAKE2b-512, BLAKE2s-256, BLAKE3-256, SHAKE-128/256) with the 22 new `LamportMerkle*Sig`/`*SigShare` codecs (codes `0x1a94`-`0x1aae`).
- `AttrId::Depth` attribute (code 11, name `depth`, one raw byte) for merkle-tree signature schemes, stamped on accumulators and combined signatures and cross-checked against the depth byte embedded in the share blobs; mismatches return `AttributesError::DepthMismatch`.
- `Builder::with_depth(depth)` and `Multisig::depth() -> Option<u8>`.
- The 11 `LamportMerkle*Sig` codecs added to `SIG_CODECS` (35→46 entries without the XMSS duplicate fix, 47 entries total) and the 11 `LamportMerkle*SigShare` codecs added to `SIG_SHARE_CODECS` (2→13).

### Changed

- Bumped `lamport_signature_plus` from `0.5.0-rc2` to `0.5.0`.
- Raised `rust-version` from `1.87` to `1.96` (required by `lamport_signature_plus` 0.5.0).
- `multi-codec` dependency raised to `1.3` (adds the `LamportMerkle*` codecs).

## [1.2.1] - 2026-08-18

### Fixed
Expand Down
14 changes: 10 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
[package]
name = "multi-sig"
version = "1.2.1"
version = "1.3.0"
edition = "2024"
rust-version = "1.87"
rust-version = "1.96"
authors = ["Dave Grantham <dwg@linuxprogrammer.org>"]
description = "Multisig self-describing multicodec implementation for digital signatures"
repository = "https://github.com/cryptidtech/multi-sig.git"
Expand All @@ -21,14 +21,15 @@ serde = []
lamport = ["dep:lamport_signature_plus", "dep:sha3", "dep:sha2", "dep:blake2", "dep:shake", "dep:blake3"]
xmss = ["dep:xmss"]

# Local multi-codec 1.3.0 until it is published (remove at release).
[dependencies]
ciborium = "0.2"
chacha20poly1305 = "0.11"
elliptic-curve = "0.14"
getrandom = { version = "0.4" }
# blsful configured per-target below (blst for native, rust for wasm)
multi-base = { version = "1.0", default-features = false }
multi-codec = "1.2"
multi-codec = "1.3"
multi-trait = { version = "1.0", default-features = false }
multi-util = "1.1"
serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] }
Expand All @@ -37,7 +38,7 @@ thiserror = { version = "2.0" }
unsigned-varint = { version = "0.8", features = ["std"] }
zeroize = "1"
# Lamport support (feature-gated, default-enabled)
lamport_signature_plus = { version = "0.5.0-rc2", optional = true }
lamport_signature_plus = { version = "0.5.0", optional = true }
sha3 = { version = "0.12", optional = true }
sha2 = { version = "0.11", optional = true }
blake2 = { version = "0.11.0-rc.6", optional = true }
Expand All @@ -59,6 +60,7 @@ ssh-key = { version = "0.7.0-rc.11", default-features = false, features = ["allo
criterion = { version = "0.8", features = ["html_reports"] }
hex = "0.4"
proptest = "1.11"
rand = "0.10"
serde_json = "1.0"
serde_test = "1.0"

Expand All @@ -75,3 +77,7 @@ multiple_crate_versions = { level = "allow", priority = 1 }

[lints.rust]
unsafe_code = "deny"

# Local multi-codec 1.3.0 until it is published (remove at release).
[patch.crates-io]
multi-codec = { path = "../multi-codec" }
7 changes: 7 additions & 0 deletions src/attrid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ pub enum AttrId {
ThresholdMetaCipher,
/// XMSS leaf index (u32 big-endian) for stateful signature schemes.
SigIndex,
/// Merkle-tree signature scheme depth (one raw byte; the tree holds
/// 2^depth one-time leaves). Cross-checked against the depth byte embedded
/// in the signature wire data.
Depth,
}

impl AttrId {
Expand All @@ -53,6 +57,7 @@ impl AttrId {
Self::EncryptedThresholdMeta => "encrypted-threshold-meta",
Self::ThresholdMetaCipher => "threshold-meta-cipher",
Self::SigIndex => "sig-index",
Self::Depth => "depth",
}
}
}
Expand All @@ -79,6 +84,7 @@ impl TryFrom<u8> for AttrId {
8 => Ok(Self::EncryptedThresholdMeta),
9 => Ok(Self::ThresholdMetaCipher),
10 => Ok(Self::SigIndex),
11 => Ok(Self::Depth),
_ => Err(AttributesError::InvalidAttributeValue(c).into()),
}
}
Expand Down Expand Up @@ -124,6 +130,7 @@ impl TryFrom<&str> for AttrId {
"encrypted-threshold-meta" => Ok(Self::EncryptedThresholdMeta),
"threshold-meta-cipher" => Ok(Self::ThresholdMetaCipher),
"sig-index" => Ok(Self::SigIndex),
"depth" => Ok(Self::Depth),
_ => Err(AttributesError::InvalidAttributeName(s.to_string()).into()),
}
}
Expand Down
9 changes: 9 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,15 @@ pub enum AttributesError {
/// Invalid attribute value
#[error("Invalid attribute value {0}")]
InvalidAttributeValue(u8),
/// A merkle-tree depth attribute does not match the depth byte embedded in
/// the signature wire data.
#[error("Depth mismatch: attribute says {expected}, wire data says {found}")]
DepthMismatch {
/// depth declared by the `depth` attribute
expected: u8,
/// depth byte embedded in the wire data
found: u8,
},
}

/// Shares errors created by this library
Expand Down
4 changes: 4 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,10 @@ pub use views::{
ThresholdView, Views, decrypt_threshold_meta, encrypt_threshold_meta, generate_meta_key,
};

/// Merkle-tree Lamport signature view
#[cfg(feature = "lamport")]
pub use views::lamport_merkle;

/// Serde serialization
#[cfg(feature = "serde")]
pub mod serde;
Expand Down
Loading
Loading