diff --git a/Cargo.lock b/Cargo.lock index 086aa04d..d8005967 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -527,7 +527,6 @@ dependencies = [ "bitcoin-primitives", "bitcoin-units", "dash-num", - "dash-pow", "dash-primitives", "dash-script", "dash-types", @@ -551,7 +550,6 @@ dependencies = [ "hex-conservative 0.3.2", "k256", "rand_core 0.6.4", - "rayon", "rstest", "serde", "sha2", @@ -563,12 +561,9 @@ dependencies = [ name = "dash-pow" version = "0.0.0" dependencies = [ - "cfg-if", "dash-dev", - "dash-num", "divan", "hex-literal", - "rayon", "rstest", ] diff --git a/README.md b/README.md index b7191b85..cb179f0e 100644 --- a/README.md +++ b/README.md @@ -33,15 +33,18 @@ > [!NOTE] > Solid lines are build dependencies. Dotted lines are test dependencies. + + ```mermaid +%%{init: { "flowchart": { "curve": "basis" } } }%% graph LR subgraph " " types[dash-types] num[dash-num] + pow[dash-pow] end subgraph " " script[dash-script] - pow[dash-pow] pkc[dash-pkc] end subgraph " " @@ -52,24 +55,17 @@ graph LR types --> num types --> script - types --> pkc - types --> primitives - types --> p2p_core - num --> pow num --> pkc num --> primitives - num --> params - num --> p2p_core script --> primitives - script --> p2p_core pkc --> p2p_core pow --> primitives - pow -.-> params primitives --> params - primitives --> p2p_core params --> p2p_core ``` + + ## Features All crates support these standard features: @@ -85,7 +81,7 @@ Specific crates define additional features: | Feature | Description | Crates | |---------|-------------|--------| -| `k256` | Enable secp256k1 support | [pkc](./pkgs/pkc) | +| `ecdsa` | Enable secp256k1 support | [pkc](./pkgs/pkc) | | `bls` | Enable standard and legacy BLS support | [pkc](./pkgs/pkc) | | `aes_hw` | Enable hardware-accelerated AES on supported platforms | [pow](./pkgs/pow) | | `simd` | Use SIMD backends (requires nightly) | [pow](./pkgs/pow) | diff --git a/contrib/codeql/codeql-config.yml b/contrib/codeql/codeql-config.yml index 309b2c37..fcd140f9 100644 --- a/contrib/codeql/codeql-config.yml +++ b/contrib/codeql/codeql-config.yml @@ -1,2 +1,5 @@ +disable-default-queries: true paths-ignore: - public +queries: + - uses: ./contrib/codeql diff --git a/contrib/lint/lint_codeql.py b/contrib/lint/lint_codeql.py index 1f15730c..5422958a 100755 --- a/contrib/lint/lint_codeql.py +++ b/contrib/lint/lint_codeql.py @@ -124,11 +124,28 @@ def _print_csv_diagnostics(results_path: Path) -> int: return count -def _search_suite(parser: argparse.ArgumentParser, name: str) -> str: - """Validate CodeQL suite *name* and return its query-suite reference.""" - if not re.fullmatch(r"[A-Za-z0-9._-]+", name): - parser.error(f"invalid --with-suite name: {name!r}") - return f"codeql/rust-queries:codeql-suites/{name}.qls" +def _locked_pack(pack: str) -> str: + """Return *pack* pinned to the version the lock file records.""" + lock_file = root_dir() / "contrib" / "codeql" / "codeql-pack.lock.yml" + if not lock_file.is_file(): + raise ValueError(f"missing lock file {lock_file}") + text = lock_file.read_text(encoding="latin-1") + match = re.search( + rf"^\s+{re.escape(pack)}:\s*$\n\s+version:\s*(\S+)\s*$", + text, + re.MULTILINE, + ) + if not match: + raise ValueError(f"no pinned version for {pack} in {lock_file}") + return f"{pack}@{match.group(1)}" + + +def _search_suites(pack: str, names: list[str]) -> list[str]: + """Return query-suite references under the pinned *pack*.""" + for name in names: + if not re.fullmatch(r"[A-Za-z0-9._-]+", name): + raise ValueError(f"invalid --with-suite name: {name!r}") + return [f"{pack}:codeql-suites/{name}.qls" for name in names] @contextlib.contextmanager @@ -181,9 +198,7 @@ def _parse_args(argv: list[str]) -> argparse.Namespace: metavar="NAME", help=("run a 'codeql/rust-queries' suite by name (default: none)"), ) - args = parser.parse_args(argv) - args.suites = [_search_suite(parser, name) for name in args.suites] - return args + return parser.parse_args(argv) def main(argv: list[str] | None = None) -> int: @@ -244,6 +259,12 @@ def main(argv: list[str] | None = None) -> int: ) return RETCODE_ERR + try: + suites = _search_suites(_locked_pack("codeql/rust-queries"), args.suites) + except ValueError as e: + print(f"error: {e}", file=sys.stderr) + return RETCODE_ERR + # Install CodeQL pack dependencies. subprocess.run( # noqa: S603 [codeql_bin, "pack", "install", "--no-strict-mode", str(query_dir)], @@ -294,7 +315,7 @@ def main(argv: list[str] | None = None) -> int: "analyze", str(active_db), *[str(q) for q in queries], - *args.suites, + *suites, "--format=csv", f"--output={results_path}", f"--threads={usable_threads()}", diff --git a/contrib/samples/Cargo.lock b/contrib/samples/Cargo.lock index fa450cb5..aff0574a 100644 --- a/contrib/samples/Cargo.lock +++ b/contrib/samples/Cargo.lock @@ -8,12 +8,6 @@ version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" -[[package]] -name = "base16ct" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" - [[package]] name = "base58ck" version = "0.4.0" @@ -76,15 +70,6 @@ dependencies = [ "serde", ] -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - [[package]] name = "bumpalo" version = "3.20.3" @@ -97,43 +82,6 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" -[[package]] -name = "const-oid" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" - -[[package]] -name = "cpufeatures" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" -dependencies = [ - "libc", -] - -[[package]] -name = "crypto-bigint" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" -dependencies = [ - "generic-array", - "rand_core", - "subtle", - "zeroize", -] - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - [[package]] name = "dash-num" version = "0.0.0" @@ -148,15 +96,11 @@ name = "dash-pkc" version = "0.0.0" dependencies = [ "base58ck", - "bitcoin-consensus-encoding", "bitcoin_hashes", "cfg-if", "dash-num", "dash-types", "hex-conservative 0.3.2", - "hex-literal", - "k256", - "rand_core", "serde", "subtle", "zeroize", @@ -165,10 +109,6 @@ dependencies = [ [[package]] name = "dash-pow" version = "0.0.0" -dependencies = [ - "cfg-if", - "dash-num", -] [[package]] name = "dash-primitives" @@ -243,6 +183,7 @@ dependencies = [ "dash-types-marker", "hex-conservative 0.3.2", "serde", + "subtle", "zeroize", ] @@ -255,91 +196,6 @@ dependencies = [ "xxhash-rust", ] -[[package]] -name = "der" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" -dependencies = [ - "const-oid", - "zeroize", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "const-oid", - "crypto-common", - "subtle", -] - -[[package]] -name = "ecdsa" -version = "0.16.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" -dependencies = [ - "der", - "digest", - "elliptic-curve", - "rfc6979", - "signature", -] - -[[package]] -name = "elliptic-curve" -version = "0.13.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" -dependencies = [ - "base16ct", - "crypto-bigint", - "digest", - "ff", - "generic-array", - "group", - "rand_core", - "sec1", - "subtle", - "zeroize", -] - -[[package]] -name = "ff" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" -dependencies = [ - "rand_core", - "subtle", -] - -[[package]] -name = "generic-array" -version = "0.14.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" -dependencies = [ - "typenum", - "version_check", - "zeroize", -] - -[[package]] -name = "group" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" -dependencies = [ - "ff", - "rand_core", - "subtle", -] - [[package]] name = "hex-conservative" version = "0.3.2" @@ -358,45 +214,12 @@ dependencies = [ "arrayvec", ] -[[package]] -name = "hex-literal" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - [[package]] name = "itoa" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" -[[package]] -name = "k256" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" -dependencies = [ - "cfg-if", - "ecdsa", - "elliptic-curve", - "sha2", -] - -[[package]] -name = "libc" -version = "0.2.189" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" - [[package]] name = "libm" version = "0.2.16" @@ -433,41 +256,12 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" - -[[package]] -name = "rfc6979" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" -dependencies = [ - "hmac", - "subtle", -] - [[package]] name = "rustversion" version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" -[[package]] -name = "sec1" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" -dependencies = [ - "base16ct", - "der", - "generic-array", - "subtle", - "zeroize", -] - [[package]] name = "serde" version = "1.0.229" @@ -511,27 +305,6 @@ dependencies = [ "zmij", ] -[[package]] -name = "sha2" -version = "0.10.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "signature" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" -dependencies = [ - "digest", - "rand_core", -] - [[package]] name = "subtle" version = "2.6.1" @@ -560,24 +333,12 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "typenum" -version = "1.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" - [[package]] name = "unicode-ident" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - [[package]] name = "wasm-bindgen" version = "0.2.126" diff --git a/contrib/samples/solver/solver.rs b/contrib/samples/solver/solver.rs index cb5770cf..cb699725 100644 --- a/contrib/samples/solver/solver.rs +++ b/contrib/samples/solver/solver.rs @@ -13,7 +13,7 @@ extern crate alloc; use bitcoin_consensus_encoding::encode_to_vec; use bitcoin_primitives::script::{ScriptPubKeyBuf, ScriptSigBuf}; use bitcoin_units::Amount; -use dash_num::{Arith256, CompactTarget}; +use dash_num::{Arith256, CompactTarget, Hash256}; use dash_primitives::{BlockHash, BlockHeader, MerkleRoot, OutPoint, Transaction, TxHash, TxIn, TxOut, TxType}; use dash_types::codec::Hashable; use hex_conservative::FromHex; @@ -111,7 +111,7 @@ pub fn scanhash( let mut hashes: u32 = 0; while hashes < nonce_count { header_buf[76..80].copy_from_slice(&nonce.to_le_bytes()); - let hash = dash_pow::hash(&header_buf); + let hash = Hash256::from(dash_pow::hash(&header_buf)); hashes += 1; if Arith256::from(hash) <= target { let result = ScanResult { diff --git a/contrib/semgrep/workspace.yml b/contrib/semgrep/workspace.yml index fbfadaa1..ea12d282 100644 --- a/contrib/semgrep/workspace.yml +++ b/contrib/semgrep/workspace.yml @@ -217,6 +217,18 @@ rules: include: [/pkgs/**/*.rs, /contrib/samples/**/*.rs] pattern-regex: '[^\x00-\xFF]' + - id: typeid-no-manual-impl + message: "use #[derive(TypeId)]; hand-written impls bypass the collision scanner" + severity: ERROR + languages: [rust] + paths: + include: + - /pkgs/**/*.rs + - /contrib/samples/**/*.rs + exclude: + - /pkgs/types/marker/** + pattern-regex: '\bconst[ \t]+TYPE_ID[ \t]*:[^;]*=' + - id: use-pub-roots-only message: "pub use re-exports belong in lib.rs or mod.rs, not in leaf modules" severity: ERROR diff --git a/docs/zen/index.md b/docs/zen/index.md index b450cb7e..a4380544 100644 --- a/docs/zen/index.md +++ b/docs/zen/index.md @@ -15,42 +15,7 @@ utilised by your packages. * Base packages. These packages implement specific algorithms but without chain-distinguishing consensus logic. * Protocol packages. These packages define the Dash protocol as deployed, blocks, transactions, chain parameters. -```mermaid -graph LR - subgraph " " - types[dash-types] - num[dash-num] - end - subgraph " " - script[dash-script] - pow[dash-pow] - pkc[dash-pkc] - end - subgraph " " - primitives[dash-primitives] - params[dash-params] - p2p_core[dash-p2p-core] - end - - types --> num - types --> script - types --> pkc - types --> primitives - types --> p2p_core - num --> pow - num --> pkc - num --> primitives - num --> params - num --> p2p_core - script --> primitives - script --> p2p_core - pkc --> p2p_core - pow --> primitives - pow -.-> params - primitives --> params - primitives --> p2p_core - params --> p2p_core -``` +--8<-- "README.md:crate-graph" *Note: Solid lines are build dependencies, dotted lines are test dependencies.* diff --git a/pkgs/dev/Cargo.toml b/pkgs/dev/Cargo.toml index 2b3f4cef..95fdb3c0 100644 --- a/pkgs/dev/Cargo.toml +++ b/pkgs/dev/Cargo.toml @@ -38,6 +38,7 @@ bin = [ [build-dependencies] built = { version = "0.7", features = ["dependency-tree", "git2"] } +dash-types = { version = "0.0.0", path = "../types", default-features = false } proc-macro2 = "1" syn = { version = "2", features = ["full", "visit"] } xxhash-rust = { version = "0.8", features = ["xxh32"] } diff --git a/pkgs/dev/build.rs b/pkgs/dev/build.rs index 7f8408d9..975d50f4 100644 --- a/pkgs/dev/build.rs +++ b/pkgs/dev/build.rs @@ -8,9 +8,11 @@ #![expect(clippy::expect_used, clippy::unwrap_used, clippy::panic, reason = "build script")] +use dash_types::type_id::mix; use proc_macro2::{TokenStream, TokenTree}; -use syn::visit::{visit_item_enum, visit_item_macro, visit_item_struct, Visit}; -use syn::{parse_file, Attribute, ItemEnum, ItemMacro, ItemStruct}; +use syn::visit::{visit_item_enum, visit_item_impl, visit_item_macro, visit_item_struct, Visit}; +use syn::{parse_file, Attribute, Generics, Ident, ItemEnum, ItemImpl, ItemMacro, ItemStruct}; +use syn::{Type, TypeParam, TypeParamBound, WherePredicate}; use xxhash_rust::xxh32::xxh32; use std::collections::{BTreeSet, HashMap}; @@ -50,27 +52,124 @@ fn main() { } } - assert!(!scan.names.is_empty(), "scanner produced no TypeId entries"); + let ids = emitted_ids(&scan); + assert!(!ids.is_empty(), "scanner produced no TypeId entries"); + check_unique(&ids); + + built::write_built_file().expect("failed to write built.rs metadata"); +} + +/// Expands every derive site into the ids its instantiations carry. +/// +/// A generic's base name only seeds the fold, so it is not an id any value +/// holds. Parameters resolve through their bounds and the cross product +/// folds through [`mix`], the same function the derive expands to. +fn emitted_ids(scan: &ScanResult) -> Vec<(String, u32)> { + let mut out: Vec<(String, u32)> = scan + .names + .iter() + .map(|name| (name.clone(), xxh32(name.as_bytes(), 0))) + .collect(); + + let mut plain: Vec<&str> = scan.names.iter().map(String::as_str).collect(); + plain.sort_unstable(); + plain.dedup(); + + for site in &scan.generics { + let seed = xxh32(site.name.as_bytes(), 0); + let per_param: Vec> = site + .bounds + .iter() + .map(|bounds| implementors(scan, &plain, bounds)) + .collect(); + for (idx, args) in per_param.iter().enumerate() { + assert!( + !args.is_empty(), + "{}: parameter {idx} bound has no id-bearing implementors", + site.name + ); + } + + let mut combos = vec![(String::new(), seed)]; + for args in &per_param { + combos = combos + .iter() + .flat_map(|(label, acc)| { + args.iter().map(move |arg| { + let sep = if label.is_empty() { "" } else { ", " }; + (format!("{label}{sep}{arg}"), mix(*acc, xxh32(arg.as_bytes(), 0))) + }) + }) + .collect(); + } + out.extend( + combos + .into_iter() + .map(|(args, id)| (format!("{}<{args}>", site.name), id)), + ); + } + + out +} + +/// Returns the `TypeId`-bearing types implementing every trait in `bounds`. +/// +/// The `TypeId` bound is skipped. The derive supplies it, so no impl records +/// to match. If that leaves no bounds, the result is empty, which the caller +/// turns into a build failure naming the site. +fn implementors(scan: &ScanResult, plain: &[&str], bounds: &[String]) -> Vec { + let required: Vec<&str> = bounds.iter().map(String::as_str).filter(|b| *b != "TypeId").collect(); + if required.is_empty() { + return Vec::new(); + } + + let implements = |ty: &str, tr: &str| scan.impls.iter().any(|(t, y)| t == tr && y == ty); + let mut found: Vec = plain + .iter() + .filter(|ty| required.iter().all(|tr| implements(ty, tr))) + .map(|ty| (*ty).to_string()) + .collect(); + found.sort_unstable(); + found.dedup(); + found +} + +/// Fails the build on a shared id, as it'd decode one type into another's slot. +/// +/// # Panics +/// +/// Panics when two distinct entries carry the same id. +fn check_unique(entries: &[(String, u32)]) { + // One type arrives from several macros, so equal labels are one entry. let mut seen: HashMap = HashMap::new(); - for name in &scan.names { - let id = xxh32(name.as_bytes(), 0); - if let Some(prev) = seen.insert(id, name) { - if prev != name { - panic!("TypeId collision: {name} and {prev} share id {id:#010x}"); + for (label, id) in entries { + if let Some(prev) = seen.insert(*id, label) { + if prev != label { + panic!("TypeId collision: {label} and {prev} share id {id:#010x}"); } } } +} - built::write_built_file().expect("failed to write built.rs metadata"); +/// A generic derive site and the bounds that gate each type parameter. +struct GenericSite { + /// Bare type name, seeding the fold. + name: String, + /// Bound trait names per type parameter, in declaration order. + bounds: Vec>, } #[derive(Default)] struct ScanResult { /// `macro_rules!` names whose body contains `TypeId`. type_id_macros: BTreeSet, - /// Type names with direct `#[derive(TypeId)]`. + /// Non-generic derive sites, where id is exactly the XXH32 of the name. names: Vec, + /// Generic derive sites, where the name hash is only the fold's seed. + generics: Vec, + /// `(trait_name, type_name)` for every non-generic trait impl seen. + impls: Vec<(String, String)>, /// Unresolved `(macro_name, type_name)` from invocation sites. pending: Vec<(String, String)>, } @@ -101,27 +200,46 @@ fn scan_file(path: &Path, scan: &mut ScanResult) { impl V<'_> { fn has_type_id_derive(attrs: &[Attribute]) -> bool { - attrs.iter().any(|attr| { - (attr.path().is_ident("derive") || attr.path().is_ident("cfg_attr")) && attr_contains_ident(attr, "TypeId") - }) + attrs.iter().any(|attr| attr_derives_ident(attr, "TypeId")) + } + + fn record(&mut self, ident: &Ident, generics: &Generics) { + let params: Vec<&TypeParam> = generics.type_params().collect(); + if params.is_empty() { + self.scan.names.push(ident.to_string()); + return; + } + self.scan.generics.push(GenericSite { + name: ident.to_string(), + bounds: params.iter().map(|p| param_bounds(p, generics)).collect(), + }); } } impl<'ast> Visit<'ast> for V<'_> { fn visit_item_struct(&mut self, node: &'ast ItemStruct) { if Self::has_type_id_derive(&node.attrs) { - self.scan.names.push(node.ident.to_string()); + self.record(&node.ident, &node.generics); } visit_item_struct(self, node); } fn visit_item_enum(&mut self, node: &'ast ItemEnum) { if Self::has_type_id_derive(&node.attrs) { - self.scan.names.push(node.ident.to_string()); + self.record(&node.ident, &node.generics); } visit_item_enum(self, node); } + fn visit_item_impl(&mut self, node: &'ast ItemImpl) { + if let Some((_, path, _)) = &node.trait_ { + if let (Some(seg), Some(ty)) = (path.segments.last(), bare_type_ident(&node.self_ty)) { + self.scan.impls.push((seg.ident.to_string(), ty)); + } + } + visit_item_impl(self, node); + } + fn visit_item_macro(&mut self, node: &'ast ItemMacro) { if let Some(ident) = &node.ident { if tokens_contain_ident(&node.mac.tokens, "TypeId") { @@ -138,6 +256,43 @@ fn scan_file(path: &Path, scan: &mut ScanResult) { V { scan }.visit_file(&file); } +/// Collects the trait names bounding `param`, inline and in `where`. +fn param_bounds(param: &TypeParam, generics: &Generics) -> Vec { + let mut bounds: Vec = param.bounds.iter().filter_map(trait_bound_name).collect(); + + let predicates = generics.where_clause.iter().flat_map(|w| w.predicates.iter()); + for pred in predicates { + let WherePredicate::Type(pred) = pred else { + continue; + }; + if bare_type_ident(&pred.bounded_ty).as_deref() == Some(¶m.ident.to_string()) { + bounds.extend(pred.bounds.iter().filter_map(trait_bound_name)); + } + } + + bounds +} + +/// Returns the final path segment of a trait bound, skipping lifetimes. +fn trait_bound_name(bound: &TypeParamBound) -> Option { + match bound { + TypeParamBound::Trait(bound) => Some(bound.path.segments.last()?.ident.to_string()), + _ => None, + } +} + +/// Returns the name of a plain path type, or `None` if it carries arguments. +fn bare_type_ident(ty: &Type) -> Option { + let Type::Path(ty) = ty else { + return None; + }; + if ty.qself.is_some() { + return None; + } + let seg = ty.path.segments.last()?; + seg.arguments.is_none().then(|| seg.ident.to_string()) +} + /// Checks whether a token stream contains `target`, recursing into groups. fn tokens_contain_ident(tokens: &TokenStream, target: &str) -> bool { tokens.clone().into_iter().any(|tt| match tt { @@ -147,15 +302,46 @@ fn tokens_contain_ident(tokens: &TokenStream, target: &str) -> bool { }) } -/// Checks whether an attribute contains `target` as a top-level ident. -fn attr_contains_ident(attr: &Attribute, target: &str) -> bool { - attr - .meta - .require_list() - .ok() - .into_iter() - .flat_map(|list| list.tokens.clone()) - .any(|tt| matches!(tt, TokenTree::Ident(ref id) if id == target)) +/// Checks whether an attribute derives `target`. +/// +/// A `derive` lists it directly, while a `cfg_attr` nests it inside a +/// `derive(..)` group its predicate guards. +fn attr_derives_ident(attr: &Attribute, target: &str) -> bool { + let Ok(list) = attr.meta.require_list() else { + return false; + }; + if attr.path().is_ident("derive") { + return list + .tokens + .clone() + .into_iter() + .any(|tt| matches!(tt, TokenTree::Ident(ref id) if id == target)); + } + attr.path().is_ident("cfg_attr") && derive_group_contains(&list.tokens, target) +} + +/// Checks whether a `derive(..)` group in `tokens` carries `target`. +/// +/// Only the groups a `derive` introduces count, so a predicate naming the +/// same ident elsewhere is not mistaken for one. +fn derive_group_contains(tokens: &TokenStream, target: &str) -> bool { + let mut after_derive = false; + for tt in tokens.clone() { + match tt { + TokenTree::Ident(ref id) => after_derive = id == "derive", + TokenTree::Group(ref group) => { + if after_derive && tokens_contain_ident(&group.stream(), target) { + return true; + } + if derive_group_contains(&group.stream(), target) { + return true; + } + after_derive = false; + } + _ => after_derive = false, + } + } + false } /// Returns `(macro_name, last_UpperCamelCase_ident)` from an invocation. diff --git a/pkgs/num/src/util.rs b/pkgs/num/src/util.rs index eb2addf9..a19be4ba 100644 --- a/pkgs/num/src/util.rs +++ b/pkgs/num/src/util.rs @@ -53,7 +53,7 @@ macro_rules! make_hash { $name:ident ) => { $(#[$attr])* - #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, $crate::__private::dash_types::TypeId)] + #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, $crate::__private::dash_types::type_id::TypeId)] pub struct $name($base); $crate::cfg_serde! { diff --git a/pkgs/p2p_core/src/command.rs b/pkgs/p2p_core/src/command.rs index f0ff0cd4..2b26a4ab 100644 --- a/pkgs/p2p_core/src/command.rs +++ b/pkgs/p2p_core/src/command.rs @@ -7,7 +7,8 @@ //! Twelve-byte null-padded command string for P2P message dispatch. use dash_primitives::hash_impl; -use dash_types::{impl_bytes, TypeId}; +use dash_types::impl_bytes; +use dash_types::type_id::TypeId; use core::fmt; diff --git a/pkgs/p2p_core/src/error.rs b/pkgs/p2p_core/src/error.rs index 13ea849a..19120f8c 100644 --- a/pkgs/p2p_core/src/error.rs +++ b/pkgs/p2p_core/src/error.rs @@ -9,7 +9,7 @@ use crate::prelude::*; use dash_types::codec::DecodeError; -use dash_types::Unencodable; +use dash_types::type_id::Unencodable; use core::fmt; diff --git a/pkgs/p2p_core/src/msg/addr.rs b/pkgs/p2p_core/src/msg/addr.rs index aa736385..79754309 100644 --- a/pkgs/p2p_core/src/msg/addr.rs +++ b/pkgs/p2p_core/src/msg/addr.rs @@ -12,7 +12,8 @@ use crate::prelude::*; use dash_primitives::{hash_impl, AddrV2, ServiceV1}; use dash_types::codec::{self, BaseCodec, DecodeError, EncodeBuf}; -use dash_types::{CompactSize, TypeId}; +use dash_types::type_id::TypeId; +use dash_types::CompactSize; use core::fmt; diff --git a/pkgs/p2p_core/src/msg/gov.rs b/pkgs/p2p_core/src/msg/gov.rs index 473a5f3d..b85ec0fa 100644 --- a/pkgs/p2p_core/src/msg/gov.rs +++ b/pkgs/p2p_core/src/msg/gov.rs @@ -10,7 +10,7 @@ use crate::codec::codec_p2p; use crate::prelude::*; use dash_num::Hash256; -use dash_types::TypeId; +use dash_types::type_id::TypeId; /// Requests governance objects and votes from a peer. /// diff --git a/pkgs/p2p_core/src/msg/headers.rs b/pkgs/p2p_core/src/msg/headers.rs index 8b9d20e8..92d6183d 100644 --- a/pkgs/p2p_core/src/msg/headers.rs +++ b/pkgs/p2p_core/src/msg/headers.rs @@ -12,7 +12,8 @@ use crate::version::ProtocolVersion; use dash_primitives::{hash_impl, BlockHash, BlockHeader, MerkleRoot}; use dash_types::codec::{BaseCodec, DecodeError, EncodeBuf}; -use dash_types::{CompactSize, TypeId}; +use dash_types::type_id::TypeId; +use dash_types::CompactSize; /// Maximum headers per message. const MAX_HEADERS: usize = 2_000; diff --git a/pkgs/p2p_core/src/msg/headers2.rs b/pkgs/p2p_core/src/msg/headers2.rs index 685426f0..3d7cc8f3 100644 --- a/pkgs/p2p_core/src/msg/headers2.rs +++ b/pkgs/p2p_core/src/msg/headers2.rs @@ -12,7 +12,8 @@ use crate::version::ProtocolVersion; use dash_primitives::{hash_impl, BlockHash, BlockHeader, MerkleRoot}; use dash_types::codec::{BaseCodec, DecodeError, EncodeBuf, Hashable}; -use dash_types::{CompactSize, TypeId, Unencodable}; +use dash_types::type_id::{TypeId, Unencodable}; +use dash_types::CompactSize; /// Maximum headers per message. const MAX_HEADERS: usize = 2_000; diff --git a/pkgs/p2p_core/src/msg/inv.rs b/pkgs/p2p_core/src/msg/inv.rs index a9fc655f..c48fb0ac 100644 --- a/pkgs/p2p_core/src/msg/inv.rs +++ b/pkgs/p2p_core/src/msg/inv.rs @@ -11,7 +11,8 @@ use crate::prelude::*; use dash_num::Hash256; use dash_primitives::hash_impl; -use dash_types::{enum_map, impl_num, TypeId}; +use dash_types::type_id::TypeId; +use dash_types::{enum_map, impl_num}; use core::fmt; diff --git a/pkgs/p2p_core/src/msg/mn_list.rs b/pkgs/p2p_core/src/msg/mn_list.rs index a6a7b9a3..784cc247 100644 --- a/pkgs/p2p_core/src/msg/mn_list.rs +++ b/pkgs/p2p_core/src/msg/mn_list.rs @@ -15,7 +15,7 @@ use dash_primitives::{ }; use dash_script::PubKeyHash; use dash_types::codec::{BaseCodec, DecodeError, EncodeBuf, NumCodec}; -use dash_types::TypeId; +use dash_types::type_id::TypeId; use core::fmt; diff --git a/pkgs/p2p_core/src/msg/mod.rs b/pkgs/p2p_core/src/msg/mod.rs index 5806664a..c618caba 100644 --- a/pkgs/p2p_core/src/msg/mod.rs +++ b/pkgs/p2p_core/src/msg/mod.rs @@ -24,7 +24,7 @@ use bitcoin_p2p_messages::message_bloom::{FilterAdd, FilterLoad}; use bitcoin_p2p_messages::message_compact_blocks::SendCmpct; use bitcoin_p2p_messages::message_filter::{CFCheckpt, CFHeaders, CFilter, GetCFCheckpt, GetCFHeaders, GetCFilters}; use dash_primitives::{GovObject, GovVote}; -use dash_types::Unencodable; +use dash_types::type_id::Unencodable; pub use addr::{Addr, AddrV2Entry, AddrV2Msg, TimestampedAddr}; pub use gov::GovSync; diff --git a/pkgs/p2p_core/src/msg/ping.rs b/pkgs/p2p_core/src/msg/ping.rs index 92a4fca3..a9217c35 100644 --- a/pkgs/p2p_core/src/msg/ping.rs +++ b/pkgs/p2p_core/src/msg/ping.rs @@ -8,7 +8,7 @@ use crate::codec::codec_p2p; -use dash_types::TypeId; +use dash_types::type_id::TypeId; /// Keepalive request carrying a random nonce. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, TypeId)] diff --git a/pkgs/p2p_core/src/msg/version.rs b/pkgs/p2p_core/src/msg/version.rs index d21b4e98..72a46ee4 100644 --- a/pkgs/p2p_core/src/msg/version.rs +++ b/pkgs/p2p_core/src/msg/version.rs @@ -13,7 +13,8 @@ use crate::version::ProtocolVersion; use dash_num::Hash256; use dash_primitives::{hash_impl, ServiceV1}; use dash_types::codec::{self, BaseCodec, DecodeError, EncodeBuf}; -use dash_types::{make_num, CompactSize, TypeId, Unencodable}; +use dash_types::type_id::{TypeId, Unencodable}; +use dash_types::{make_num, CompactSize}; use core::fmt; use core::ops::{BitAnd, BitOr, BitOrAssign}; diff --git a/pkgs/p2p_core/src/serialize.rs b/pkgs/p2p_core/src/serialize.rs index b0cdb5b5..b2b868db 100644 --- a/pkgs/p2p_core/src/serialize.rs +++ b/pkgs/p2p_core/src/serialize.rs @@ -10,7 +10,7 @@ use crate::prelude::*; use bitcoin_primitives::BlockHash; use bitcoin_units::BlockHeight; -use dash_types::Unencodable; +use dash_types::type_id::Unencodable; use serde::{Deserialize, Deserializer, Serialize, Serializer}; /// For [`BlockHash`](bitcoin_primitives::BlockHash) as a hex string. diff --git a/pkgs/p2p_core/src/short_id.rs b/pkgs/p2p_core/src/short_id.rs index 20a4fc78..8502e5d7 100644 --- a/pkgs/p2p_core/src/short_id.rs +++ b/pkgs/p2p_core/src/short_id.rs @@ -8,7 +8,7 @@ use crate::command::CommandString; -use dash_types::Unencodable; +use dash_types::type_id::Unencodable; /// A resolved V2 short ID. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Unencodable)] diff --git a/pkgs/params/Cargo.toml b/pkgs/params/Cargo.toml index 45828fb2..e52fc74f 100644 --- a/pkgs/params/Cargo.toml +++ b/pkgs/params/Cargo.toml @@ -19,7 +19,6 @@ hex-literal = "0.4" [dev-dependencies] bitcoin-consensus-encoding = { workspace = true, features = ["alloc"] } -dash-pow = { version = "0.0.0", path = "../pow" } dash-types = { version = "0.0.0", path = "../types", default-features = false } hex-literal = "0.4" rstest = "0.25" diff --git a/pkgs/pkc/Cargo.toml b/pkgs/pkc/Cargo.toml index ba23aee4..da942bf8 100644 --- a/pkgs/pkc/Cargo.toml +++ b/pkgs/pkc/Cargo.toml @@ -6,7 +6,6 @@ license = "MIT" [dependencies] base58ck = { workspace = true, features = ["alloc"] } -bitcoin-consensus-encoding = { workspace = true, features = ["alloc"] } bitcoin_hashes = { workspace = true, features = ["alloc"] } blst = { version = "0.3", default-features = false, optional = true } cfg-if = "1" @@ -20,8 +19,7 @@ k256 = { version = "0.13", default-features = false, features = [ "ecdsa", "sha256", ], optional = true } -rand_core = { version = "0.6", default-features = false } -rayon = { version = "1", optional = true } +rand_core = { version = "0.6", default-features = false, optional = true } rstest = { version = "0.25", optional = true } serde = { version = "1", default-features = false, features = [ "alloc", @@ -35,6 +33,7 @@ zeroize = { version = "1", default-features = false, features = [ ] } [dev-dependencies] +bitcoin-consensus-encoding = { workspace = true, features = ["alloc"] } dash-dev = { version = "0.0.0", path = "../dev", features = ["full"] } divan = "0.1" hex-conservative = "0.3" @@ -44,15 +43,9 @@ serde = { version = "1", features = ["derive"] } [features] default = [] -std = [ - "dep:rayon", - "base58ck/std", - "bitcoin_hashes/std", - "dash-types/std", - "rand_core/getrandom", -] -bls = ["dep:blst", "dep:sha2"] -ecdsa = ["dep:k256"] +std = ["base58ck/std", "bitcoin_hashes/std", "dash-types/std"] +bls = ["dep:blst", "dep:rand_core", "dep:sha2"] +ecdsa = ["dep:k256", "dep:rand_core"] serde = ["dep:serde", "dash-num/serde", "dash-types/serde"] full = ["ecdsa", "bls", "serde", "std", "tests"] tests = ["std", "dep:rstest"] @@ -68,4 +61,3 @@ name = "pkc" path = "bench/main.rs" harness = false required-features = ["tests"] - diff --git a/pkgs/pkc/bench/bls.rs b/pkgs/pkc/bench/bls.rs index 8c05dcb6..235df9b8 100644 --- a/pkgs/pkc/bench/bls.rs +++ b/pkgs/pkc/bench/bls.rs @@ -240,40 +240,3 @@ mod ietf { bencher.bench(|| pk.verify_possession(&pop)); } } - -#[cfg(feature = "std")] -mod worker { - use super::*; - - use dash_pkc::worker; - - fn setup_sigs(n: usize) -> Vec<(BlsSignature, BlsPublicKey, [u8; 32])> { - (0..n) - .map(|i| { - let sk = BlsSecretKey::::generate(&test_ikm(i)).unwrap(); - let msg = test_msg(i); - let pk = sk.public_key(); - let sig = sk.sign(S::msg_ref(&msg)); - (sig, pk, msg) - }) - .collect() - } - - #[divan::bench(types = [BlsScChia, BlsScIetf], args = [100, 1000])] - fn verify_n(bencher: Bencher, n: usize) { - let tuples = setup_sigs::(n); - bencher - .counter(ItemsCount::new(n)) - .bench(|| worker::par_verify(&tuples, |(sig, pk, msg)| sig.verify(S::msg_ref(msg), pk).is_ok())); - } - - #[divan::bench(types = [BlsScChia, BlsScIetf], args = [100, 1000])] - fn aggregate_pk_n(bencher: Bencher, n: usize) { - let pks: Vec> = (0..n) - .map(|i| BlsSecretKey::::generate(&test_ikm(i)).unwrap().public_key()) - .collect(); - bencher - .counter(ItemsCount::new(n)) - .bench(|| worker::par_reduce(pks.clone(), |a, b| BlsPublicKey::::aggregate(&[&a, &b]).unwrap())); - } -} diff --git a/pkgs/pkc/bench/ecdsa.rs b/pkgs/pkc/bench/ecdsa.rs index 4ea47e8c..8e95d260 100644 --- a/pkgs/pkc/bench/ecdsa.rs +++ b/pkgs/pkc/bench/ecdsa.rs @@ -62,30 +62,3 @@ fn deser_pk(bencher: divan::Bencher) { let bytes = test_key().public_key().to_compressed(); bencher.bench(|| EcdsaPublicKey::from_bytes(&bytes).unwrap()); } - -#[cfg(feature = "std")] -mod worker_benches { - use dash_pkc::ecdsa::tests::{message_hash, BOB_SK}; - use dash_pkc::ecdsa::{Compression, EcdsaPublicKey, EcdsaSecretKey, EcdsaSignature}; - use dash_pkc::worker; - - fn setup_sigs(n: usize) -> Vec<(EcdsaSignature, EcdsaPublicKey, [u8; 32])> { - let sk = EcdsaSecretKey::from_bytes(&BOB_SK, Compression::Compressed).unwrap(); - let pk = sk.public_key(); - (0..n) - .map(|i| { - let msg = message_hash(i as u16); - let sig = sk.sign(&msg).unwrap(); - (sig, pk.clone(), msg) - }) - .collect() - } - - #[divan::bench(args = [100, 1000])] - fn worker_verify_n(bencher: divan::Bencher, n: usize) { - let tuples = setup_sigs(n); - bencher - .counter(divan::counter::ItemsCount::new(n)) - .bench(|| worker::par_verify(&tuples, |(sig, pk, msg)| pk.verify(msg, sig).is_ok())); - } -} diff --git a/pkgs/pkc/src/bls/blst_ffi.rs b/pkgs/pkc/src/bls/blst_ffi.rs index ae96e107..70473192 100644 --- a/pkgs/pkc/src/bls/blst_ffi.rs +++ b/pkgs/pkc/src/bls/blst_ffi.rs @@ -7,7 +7,8 @@ //! Bridging routines for unsafe blst FFI operations. use blst::*; -use dash_types::{type_cvrt, Unencodable}; +use dash_types::type_cvrt; +use dash_types::type_id::Unencodable; use zeroize::Zeroize; use core::fmt; diff --git a/pkgs/pkc/src/bls/public_bytes.rs b/pkgs/pkc/src/bls/public_bytes.rs index 8d669042..60238f0c 100644 --- a/pkgs/pkc/src/bls/public_bytes.rs +++ b/pkgs/pkc/src/bls/public_bytes.rs @@ -10,7 +10,8 @@ use crate::bls::BlsSchemeId; use bitcoin_hashes::sha256d::Hash as Sha256d; use dash_num::Hash256; -use dash_types::codec::{Hashable, TypeId}; +use dash_types::codec::Hashable; +use dash_types::type_id::TypeId; use dash_types::{derive_bytes, impl_bytes}; use core::marker::PhantomData; @@ -19,6 +20,7 @@ use core::marker::PhantomData; pub const BLS_PK_LEN: usize = 48; /// Scheme-tagged BLS public key bytes (48 bytes, unvalidated). +#[derive(TypeId)] pub struct BlsPkBytes { inner: [u8; BLS_PK_LEN], _scheme: PhantomData, @@ -54,8 +56,4 @@ impl BlsPkBytes { } } -impl TypeId for BlsPkBytes { - const TYPE_ID: u32 = S::PK_TYPE_ID; -} - derive_bytes!(for[S: BlsSchemeId] BlsPkBytes, BLS_PK_LEN); diff --git a/pkgs/pkc/src/bls/public_ops.rs b/pkgs/pkc/src/bls/public_ops.rs index 6fca131e..c5a02f48 100644 --- a/pkgs/pkc/src/bls/public_ops.rs +++ b/pkgs/pkc/src/bls/public_ops.rs @@ -12,7 +12,7 @@ use super::{BlsPkBytes, BLS_PK_LEN}; use crate::prelude::*; use dash_num::Hash256; -use dash_types::codec::TypeId; +use dash_types::type_id::TypeId; use dash_types::{dlgt_codec, qtypestr, type_cvrt}; use hex_conservative::DisplayHex; @@ -24,6 +24,7 @@ use core::hash::{Hash, Hasher}; #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] #[cfg_attr(feature = "serde", serde(into = "BlsPkBytes", try_from = "BlsPkBytes",))] #[cfg_attr(feature = "serde", serde(bound(serialize = "", deserialize = "")))] +#[derive(TypeId)] pub struct BlsPublicKey(pub(crate) S::InnerPk); dlgt_codec!(for[S: BlsScheme] BlsPublicKey => BlsPkBytes, Hash256, BlsError, BLS_PK_LEN); @@ -98,10 +99,6 @@ impl PartialEq for BlsPublicKey { } } -impl TypeId for BlsPublicKey { - const TYPE_ID: u32 = S::PK_TYPE_ID; -} - type_cvrt!(for[S: BlsScheme] From> for BlsPkBytes, |pk| { Self::from_bytes(pk.to_bytes()) }); @@ -116,7 +113,7 @@ mod tests { use super::*; use crate::bls::tests::{ ietf_g1_encoding, G1_OFF_SUBGROUP_CHIA, G1_OFF_SUBGROUP_IETF, G1_X_EQ_PRIME_CHIA, G1_X_GE_PRIME_CHIA, - G1_X_MAX_CHIA, SEED_0, SEED_1, + G1_X_MAX_CHIA, RSEED, }; use crate::bls::{BlsScChia, BlsScIetf, BlsSecretKey}; @@ -165,8 +162,8 @@ mod tests { } fn assert_dh_roundtrip() { - let sk_a = BlsSecretKey::::generate(&SEED_0).unwrap(); - let sk_b = BlsSecretKey::::generate(&SEED_1).unwrap(); + let sk_a = BlsSecretKey::::generate(&RSEED[0]).unwrap(); + let sk_b = BlsSecretKey::::generate(&RSEED[1]).unwrap(); let shared_ab = sk_a.dh_exchange(&sk_b.public_key()).unwrap(); let shared_ba = sk_b.dh_exchange(&sk_a.public_key()).unwrap(); @@ -183,7 +180,7 @@ mod tests { /// In the Chia scheme, DH weighs whatever the decoder passed, which leaks /// the scalar mod the cofactor's small factors. IETF rejects this. fn assert_off_subgroup_peer_policy(encoded: &[u8; 48], reaches_dh: bool) { - let sk = BlsSecretKey::::generate(&SEED_0).unwrap(); + let sk = BlsSecretKey::::generate(&RSEED[0]).unwrap(); match BlsPublicKey::::from_bytes(encoded) { Ok(peer) => { @@ -209,7 +206,7 @@ mod tests { /// Conversion re-encodes one point, so a round trip returns the original and /// the same-scheme case is a copy. fn assert_scheme_conversion_round_trips() { - let pk = BlsSecretKey::::generate(&SEED_0).unwrap().public_key(); + let pk = BlsSecretKey::::generate(&RSEED[0]).unwrap().public_key(); let there = pk.to_scheme::().unwrap(); assert_eq!(there.to_scheme::().unwrap().to_bytes(), pk.to_bytes()); @@ -252,7 +249,7 @@ mod tests { } fn assert_pk_roundtrip() { - let pk = BlsSecretKey::::generate(&SEED_0).unwrap().public_key(); + let pk = BlsSecretKey::::generate(&RSEED[0]).unwrap().public_key(); let bytes = pk.to_bytes(); assert_eq!(BlsPublicKey::::from_bytes(&bytes).unwrap().to_bytes(), bytes); } @@ -336,7 +333,7 @@ mod tests { /// round-trips back to its canonical form. #[rstest] fn chia_masks_stray_public_key_bits() { - let clean = BlsSecretKey::::generate(&SEED_0) + let clean = BlsSecretKey::::generate(&RSEED[0]) .unwrap() .public_key() .to_bytes(); diff --git a/pkgs/pkc/src/bls/scheme_chia.rs b/pkgs/pkc/src/bls/scheme_chia.rs index b7155cfb..56af217d 100644 --- a/pkgs/pkc/src/bls/scheme_chia.rs +++ b/pkgs/pkc/src/bls/scheme_chia.rs @@ -286,7 +286,7 @@ impl BlsScheme for BlsScChia { #[expect(clippy::unwrap_used, reason = "test code")] mod tests { use super::*; - use crate::bls::tests::{MSG_DEADBEEF, SEED_0, SEED_1}; + use crate::bls::tests::{MSG_8BADFOOD, MSG_DEADBEEF, RSEED}; use dash_dev::{arr_from_hex, Corpus}; use hex_conservative::DisplayHex; @@ -353,21 +353,21 @@ mod tests { #[test] fn signing_verifies_and_rejects_mismatches() { - let sk0 = BlsScChia::generate(&SEED_0).unwrap(); - let sk1 = BlsScChia::generate(&SEED_1).unwrap(); + let sk0 = BlsScChia::generate(&RSEED[0]).unwrap(); + let sk1 = BlsScChia::generate(&RSEED[1]).unwrap(); let pk0 = BlsScChia::derive_pk(&sk0); let pk1 = BlsScChia::derive_pk(&sk1); let sig = BlsScChia::sign(&sk0, &MSG_DEADBEEF); assert!(BlsScChia::verify(&sig, &MSG_DEADBEEF, &pk0).is_ok()); - assert!(BlsScChia::verify(&sig, &[0x42; 32], &pk0).is_err()); + assert!(BlsScChia::verify(&sig, &MSG_8BADFOOD, &pk0).is_err()); assert!(BlsScChia::verify(&sig, &MSG_DEADBEEF, &pk1).is_err()); assert_eq!(BlsScChia::sign(&sk0, &MSG_DEADBEEF), sig); } #[test] fn secure_verify_rejects_infinity_input_key() { - let sk = BlsScChia::generate(&SEED_0).unwrap(); + let sk = BlsScChia::generate(&RSEED[0]).unwrap(); let real_pk = BlsScChia::derive_pk(&sk); let inf_pk = G1::identity().to_affine(); // The identity key serializes to the infinity marker (bits 6-7 set). diff --git a/pkgs/pkc/src/bls/scheme_ietf.rs b/pkgs/pkc/src/bls/scheme_ietf.rs index 73469ac6..fcb3f1e5 100644 --- a/pkgs/pkc/src/bls/scheme_ietf.rs +++ b/pkgs/pkc/src/bls/scheme_ietf.rs @@ -217,7 +217,7 @@ impl BlsScIetf { #[expect(clippy::unwrap_used, reason = "test code")] mod tests { use super::*; - use crate::bls::tests::{MSG_DEADBEEF, SEED_0, SEED_1}; + use crate::bls::tests::{MSG_DEADBEEF, RSEED}; use dash_dev::{arr_from_hex, vec_from_hex, Corpus}; use hex_conservative::hex; @@ -281,8 +281,8 @@ mod tests { #[test] fn signing_verifies_and_rejects_mismatches() { - let sk0 = BlsScIetf::generate(&SEED_0).unwrap(); - let sk1 = BlsScIetf::generate(&SEED_1).unwrap(); + let sk0 = BlsScIetf::generate(&RSEED[0]).unwrap(); + let sk1 = BlsScIetf::generate(&RSEED[1]).unwrap(); let pk0 = BlsScIetf::derive_pk(&sk0); let pk1 = BlsScIetf::derive_pk(&sk1); let sig = BlsScIetf::sign(&sk0, &MSG_DEADBEEF); diff --git a/pkgs/pkc/src/bls/schemes.rs b/pkgs/pkc/src/bls/schemes.rs index 521de2a9..2c7c711d 100644 --- a/pkgs/pkc/src/bls/schemes.rs +++ b/pkgs/pkc/src/bls/schemes.rs @@ -6,40 +6,19 @@ //! BLS scheme trait and marker types. -use dash_types::Unencodable; +use dash_types::type_id::{TypeId, Unencodable}; /// BLS scheme discriminator. -pub trait BlsSchemeId: 'static { - /// `TypeId` constant for `BlsPkBytes`. - const PK_TYPE_ID: u32; - /// `TypeId` constant for `BlsSkBytes`. - const SK_TYPE_ID: u32; - /// `TypeId` constant for `BlsSigBytes`. - const SIG_TYPE_ID: u32; -} +pub trait BlsSchemeId: TypeId + 'static {} /// Legacy (Chia) BLS scheme marker. -#[derive(Clone, Debug, Eq, Hash, PartialEq, Unencodable)] +#[derive(Clone, Debug, Eq, Hash, PartialEq, TypeId, Unencodable)] pub enum BlsScChia {} -impl BlsSchemeId for BlsScChia { - // xxh32(b"BlsPkBytesChia", 0) - const PK_TYPE_ID: u32 = 0xE377_6DA7; - // xxh32(b"BlsSkBytesChia", 0) - const SK_TYPE_ID: u32 = 0x3D50_6855; - // xxh32(b"BlsSigBytesChia", 0) - const SIG_TYPE_ID: u32 = 0xEF4A_E265; -} +impl BlsSchemeId for BlsScChia {} /// IETF-standard BLS scheme marker. -#[derive(Clone, Debug, Eq, Hash, PartialEq, Unencodable)] +#[derive(Clone, Debug, Eq, Hash, PartialEq, TypeId, Unencodable)] pub enum BlsScIetf {} -impl BlsSchemeId for BlsScIetf { - // xxh32(b"BlsPkBytesIetf", 0) - const PK_TYPE_ID: u32 = 0x6D54_3438; - // xxh32(b"BlsSkBytesIetf", 0) - const SK_TYPE_ID: u32 = 0xB5CE_BF45; - // xxh32(b"BlsSigBytesIetf", 0) - const SIG_TYPE_ID: u32 = 0xF57D_EF57; -} +impl BlsSchemeId for BlsScIetf {} diff --git a/pkgs/pkc/src/bls/secret_bytes.rs b/pkgs/pkc/src/bls/secret_bytes.rs index f277dfc0..15b97385 100644 --- a/pkgs/pkc/src/bls/secret_bytes.rs +++ b/pkgs/pkc/src/bls/secret_bytes.rs @@ -10,7 +10,8 @@ use crate::bls::BlsSchemeId; use bitcoin_hashes::sha256d::Hash as Sha256d; use dash_num::Hash256; -use dash_types::codec::{Hashable, TypeId}; +use dash_types::codec::Hashable; +use dash_types::type_id::TypeId; use dash_types::{derive_sbytes, impl_sbytes}; use subtle::ConstantTimeEq; use zeroize::{Zeroize, Zeroizing}; @@ -21,6 +22,7 @@ use core::marker::PhantomData; pub const BLS_SK_LEN: usize = 32; /// Scheme-tagged BLS secret key bytes (32 bytes, zeroized on drop). +#[derive(TypeId)] pub struct BlsSkBytes { inner: [u8; BLS_SK_LEN], _scheme: PhantomData, @@ -56,10 +58,6 @@ impl BlsSkBytes { } } -impl TypeId for BlsSkBytes { - const TYPE_ID: u32 = S::SK_TYPE_ID; -} - impl Zeroize for BlsSkBytes { fn zeroize(&mut self) { self.inner.zeroize(); diff --git a/pkgs/pkc/src/bls/secret_ops.rs b/pkgs/pkc/src/bls/secret_ops.rs index 4cc15015..4aa5840d 100644 --- a/pkgs/pkc/src/bls/secret_ops.rs +++ b/pkgs/pkc/src/bls/secret_ops.rs @@ -15,13 +15,14 @@ use super::{BlsScIetf, BlsSigId, BlsSkBytes, BLS_SK_LEN}; use crate::prelude::*; use dash_num::Hash256; -use dash_types::codec::TypeId; +use dash_types::type_id::TypeId; use dash_types::{dlgt_scodec, qtypestr, type_cvrt}; use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing}; use core::fmt::{Debug, Formatter, Result as FmtResult}; /// A BLS secret key (32-byte scalar). +#[derive(TypeId)] pub struct BlsSecretKey(pub(crate) S::InnerSk); dlgt_scodec!(for[S: BlsScheme] BlsSecretKey => BlsSkBytes, Hash256, BlsError, BLS_SK_LEN); @@ -131,10 +132,6 @@ impl Zeroize for BlsSecretKey { impl ZeroizeOnDrop for BlsSecretKey {} -impl TypeId for BlsSecretKey { - const TYPE_ID: u32 = S::SK_TYPE_ID; -} - type_cvrt!(for[S: BlsScheme] From> for BlsSkBytes, |sk| { Self::from_bytes(*sk.to_bytes()) }); @@ -147,7 +144,7 @@ type_cvrt!(for[S: BlsScheme] TryFrom> for BlsSecretKey, BlsErro #[expect(clippy::unwrap_used, reason = "test code")] mod tests { use super::*; - use crate::bls::tests::{RSEED, SEED_0}; + use crate::bls::tests::RSEED; use crate::bls::{BlsScChia, BlsScIetf}; use dash_dev::{arr_from_hex, Corpus}; @@ -168,7 +165,7 @@ mod tests { } fn assert_roundtrip() { - let sk = BlsSecretKey::::generate(&SEED_0).unwrap(); + let sk = BlsSecretKey::::generate(&RSEED[0]).unwrap(); let bytes = sk.to_bytes(); let decoded = BlsSecretKey::::from_bytes(&bytes).unwrap(); assert_eq!(decoded.to_bytes(), bytes); @@ -229,7 +226,7 @@ mod tests { /// scheme mix-up cannot go unnoticed. #[rstest] fn public_key_formats_differ() { - let chia = BlsSecretKey::::generate(&SEED_0).unwrap(); + let chia = BlsSecretKey::::generate(&RSEED[0]).unwrap(); let ietf = BlsSecretKey::::from_bytes(&chia.to_bytes()).unwrap(); assert_ne!(chia.public_key().to_bytes(), ietf.public_key().to_bytes()); } @@ -237,7 +234,7 @@ mod tests { fn assert_codec_roundtrip() { use dash_types::codec::BaseCodec; - let sk = BlsSecretKey::::generate(&SEED_0).unwrap(); + let sk = BlsSecretKey::::generate(&RSEED[0]).unwrap(); let mut buf = Vec::new(); sk.encode(&mut buf); assert_eq!(buf.len(), 32); diff --git a/pkgs/pkc/src/bls/share_ops.rs b/pkgs/pkc/src/bls/share_ops.rs index 36ddd9e9..a5773258 100644 --- a/pkgs/pkc/src/bls/share_ops.rs +++ b/pkgs/pkc/src/bls/share_ops.rs @@ -14,7 +14,8 @@ use super::sig_basic::BlsSignature; use crate::prelude::*; use dash_num::Hash256; -use dash_types::{qtypestr, Unencodable}; +use dash_types::qtypestr; +use dash_types::type_id::Unencodable; use rand_core::CryptoRngCore; use core::fmt::{Debug, Formatter, Result as FmtResult}; @@ -179,7 +180,7 @@ impl BlsPublicKey { #[expect(clippy::unwrap_used, reason = "test code")] mod tests { use super::*; - use crate::bls::tests::{hash_from_hex, make_id, sequential_ids, GROUP_ORDER, MSG_DEADBEEF, RSEED, SEED_0, SEED_1}; + use crate::bls::tests::{hash_from_hex, make_id, sequential_ids, GROUP_ORDER, MSG_DEADBEEF, RSEED}; use crate::bls::{BlsScChia, BlsScIetf}; use cfg_if::cfg_if; @@ -205,7 +206,7 @@ mod tests { /// below 2 is rejected; one above the participant count yields a quorum that /// can never sign. fn assert_invalid_thresholds_rejected() { - let sk = BlsSecretKey::::generate(&SEED_0).unwrap(); + let sk = BlsSecretKey::::generate(&RSEED[0]).unwrap(); let ids = sequential_ids(5); for threshold in [0, 1, ids.len() + 1] { assert!(matches!( @@ -226,7 +227,7 @@ mod tests { /// An id congruent to zero mod `r` would make the share equal the master key, /// so both the zero hash and the group order are rejected. fn assert_zero_reducing_id_rejected() { - let sk = BlsSecretKey::::generate(&SEED_0).unwrap(); + let sk = BlsSecretKey::::generate(&RSEED[0]).unwrap(); let zero = Hash256::from_bytes([0u8; 32]); let ids = [make_id(1), zero]; @@ -247,7 +248,7 @@ mod tests { /// Two ids congruent mod `r` collide during interpolation, and a raw-byte /// duplicate check would miss `1` and `r + 1`. fn assert_congruent_ids_rejected() { - let sk = BlsSecretKey::::generate(&SEED_0).unwrap(); + let sk = BlsSecretKey::::generate(&RSEED[0]).unwrap(); let ids = [make_id(1), group_order_plus_one()]; assert!(matches!(sk.split(2, &ids, &mut OsRng), Err(BlsError::DuplicateShareId))); } @@ -298,7 +299,7 @@ mod tests { /// Evaluating the verification-vector polynomial needs at least two /// coefficients, so a single master key is rejected. fn assert_derive_share_rejects_short_vv() { - let pk = BlsSecretKey::::generate(&SEED_0).unwrap().public_key(); + let pk = BlsSecretKey::::generate(&RSEED[0]).unwrap().public_key(); assert!(matches!( BlsPublicKey::::derive_share(&[&pk], &make_id(1)), Err(BlsError::InvalidVerificationVector) @@ -656,8 +657,8 @@ mod tests { /// quietly dropping a field. Shares agreeing on id and signature compare and /// hash alike; changing either separates them. fn assert_share_eq_and_hash() { - let sk = BlsSecretKey::::generate(&SEED_0).unwrap(); - let other_sk = BlsSecretKey::::generate(&SEED_1).unwrap(); + let sk = BlsSecretKey::::generate(&RSEED[0]).unwrap(); + let other_sk = BlsSecretKey::::generate(&RSEED[1]).unwrap(); let msg = S::msg_ref(&MSG_DEADBEEF); let share = BlsSkShare::new(make_id(1), sk.clone()).sign(msg); @@ -690,7 +691,7 @@ mod tests { use dash_dev::assert_json_rt; fn assert_share_serde_roundtrip() { - let sk = BlsSecretKey::::generate(&SEED_0).unwrap(); + let sk = BlsSecretKey::::generate(&RSEED[0]).unwrap(); assert_json_rt(&BlsSkShare::new(make_id(1), sk).sign(S::msg_ref(&MSG_DEADBEEF))); } diff --git a/pkgs/pkc/src/bls/sig_aggregate.rs b/pkgs/pkc/src/bls/sig_aggregate.rs index b8642eee..49f3ece6 100644 --- a/pkgs/pkc/src/bls/sig_aggregate.rs +++ b/pkgs/pkc/src/bls/sig_aggregate.rs @@ -90,7 +90,7 @@ impl BlsSignature { mod tests { use super::*; use crate::bls::secret_ops::BlsSecretKey; - use crate::bls::tests::{MSG_DEADBEEF, SEED_0, SEED_1}; + use crate::bls::tests::{MSG_8BADFOOD, MSG_DEADBEEF, RSEED}; use crate::bls::{BlsScChia, BlsScIetf}; use dash_dev::{arr_from_hex, Corpus}; @@ -121,8 +121,8 @@ mod tests { } fn assert_aggregate_same_message() { - let sk1 = BlsSecretKey::::generate(&SEED_0).unwrap(); - let sk2 = BlsSecretKey::::generate(&SEED_1).unwrap(); + let sk1 = BlsSecretKey::::generate(&RSEED[0]).unwrap(); + let sk2 = BlsSecretKey::::generate(&RSEED[1]).unwrap(); let sig1 = sk1.sign(S::msg_ref(&MSG_DEADBEEF)); let sig2 = sk2.sign(S::msg_ref(&MSG_DEADBEEF)); @@ -133,7 +133,7 @@ mod tests { let msg = S::msg_ref(&MSG_DEADBEEF); assert!(agg.fast_verify_aggregates(msg, &[&pk1, &pk2]).is_ok()); // A key not in the set must make verification fail. - let pk3 = BlsSecretKey::::generate(&[9u8; 32]).unwrap().public_key(); + let pk3 = BlsSecretKey::::generate(&RSEED[2]).unwrap().public_key(); assert!(agg.fast_verify_aggregates(msg, &[&pk1, &pk3]).is_err()); // Rogue-key resistance: a naive aggregate must not pass weighted verify. assert!(agg.secure_verify_aggregates(msg, &[&pk1, &pk2]).is_err()); @@ -173,10 +173,10 @@ mod tests { /// the two fails. Both schemes agree here, along with the count and /// emptiness contracts. fn assert_distinct_messages_verify() { - let sk1 = BlsSecretKey::::generate(&SEED_0).unwrap(); - let sk2 = BlsSecretKey::::generate(&SEED_1).unwrap(); + let sk1 = BlsSecretKey::::generate(&RSEED[0]).unwrap(); + let sk2 = BlsSecretKey::::generate(&RSEED[1]).unwrap(); - let msg1 = S::msg_ref(&[0x11u8; 32]); + let msg1 = S::msg_ref(&MSG_8BADFOOD); let msg2 = S::msg_ref(&MSG_DEADBEEF); let sig1 = sk1.sign(msg1); let sig2 = sk2.sign(msg2); @@ -205,8 +205,8 @@ mod tests { /// which either could have picked to cancel the other. IETF refuses it; Chia /// accepts. fn assert_duplicate_message_policy(accepted: bool) { - let sk1 = BlsSecretKey::::generate(&SEED_0).unwrap(); - let sk2 = BlsSecretKey::::generate(&SEED_1).unwrap(); + let sk1 = BlsSecretKey::::generate(&RSEED[0]).unwrap(); + let sk2 = BlsSecretKey::::generate(&RSEED[1]).unwrap(); let msg = S::msg_ref(&MSG_DEADBEEF); let sig1 = sk1.sign(msg); @@ -270,8 +270,8 @@ mod tests { /// weights follow the sorted keys rather than the caller's order, so the /// same set aggregates alike however it is presented. fn assert_secure_aggregate_round_trips() { - let sk1 = BlsSecretKey::::generate(&SEED_0).unwrap(); - let sk2 = BlsSecretKey::::generate(&SEED_1).unwrap(); + let sk1 = BlsSecretKey::::generate(&RSEED[0]).unwrap(); + let sk2 = BlsSecretKey::::generate(&RSEED[1]).unwrap(); let msg = S::msg_ref(&MSG_DEADBEEF); let sig1 = sk1.sign(msg); @@ -348,10 +348,10 @@ mod tests { /// [`secure_aggregate_round_trips`] holds the distinct-key case, where the /// keys give a total order and the argument order stops mattering. fn assert_duplicate_key_pairing_is_order_bound() { - let sk = BlsSecretKey::::generate(&SEED_0).unwrap(); + let sk = BlsSecretKey::::generate(&RSEED[0]).unwrap(); let pk = sk.public_key(); - let sig_a = sk.sign(S::msg_ref(&[0x11u8; 32])); + let sig_a = sk.sign(S::msg_ref(&MSG_8BADFOOD)); let sig_b = sk.sign(S::msg_ref(&MSG_DEADBEEF)); let ab = BlsSignature::::secure_aggregate(&[&sig_a, &sig_b], &[&pk, &pk]).unwrap(); @@ -385,7 +385,7 @@ mod tests { /// Aggregation is a group sum, so neither the aggregate nor the verification /// may depend on the order the caller supplies. fn assert_order_independent() { - let sks: Vec> = [SEED_0, SEED_1, [2u8; 32]] + let sks: Vec> = [RSEED[0], RSEED[1], RSEED[2]] .iter() .map(|seed| BlsSecretKey::::generate(seed).unwrap()) .collect(); @@ -440,8 +440,8 @@ mod tests { /// and consensus depends on it continuing to; the IETF scheme rejects it. /// The sign bit sits at bit 7 for legacy and bit 5 for IETF. fn assert_identity_cancellation(sign_bit: u8, accepted: bool) { - let sk = BlsSecretKey::::generate(&SEED_0).unwrap(); - let signed = [0x11u8; 32]; + let sk = BlsSecretKey::::generate(&RSEED[0]).unwrap(); + let signed = MSG_8BADFOOD; let sig = sk.sign(S::msg_ref(&signed)); let pk = sk.public_key(); @@ -466,8 +466,8 @@ mod tests { /// by computation, not off the wire. #[rstest] fn chia_identity_encodes_canonically() { - let sk = BlsSecretKey::::generate(&SEED_0).unwrap(); - let sig = sk.sign(&[0x11u8; 32]); + let sk = BlsSecretKey::::generate(&RSEED[0]).unwrap(); + let sig = sk.sign(&MSG_8BADFOOD); let mut neg_bytes = sig.to_bytes(); neg_bytes[0] ^= 0x80; diff --git a/pkgs/pkc/src/bls/sig_basic.rs b/pkgs/pkc/src/bls/sig_basic.rs index 6afc4847..792158f7 100644 --- a/pkgs/pkc/src/bls/sig_basic.rs +++ b/pkgs/pkc/src/bls/sig_basic.rs @@ -12,7 +12,7 @@ use super::scheme_ops::BlsScheme; use super::{BlsScIetf, BlsSigBytes, BlsSigId, BLS_SIG_LEN}; use dash_num::Hash256; -use dash_types::codec::TypeId; +use dash_types::type_id::TypeId; use dash_types::{dlgt_codec, qtypestr, type_cvrt}; use hex_conservative::DisplayHex; @@ -23,6 +23,7 @@ use core::hash::{Hash, Hasher}; #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] #[cfg_attr(feature = "serde", serde(into = "BlsSigBytes", try_from = "BlsSigBytes"))] #[cfg_attr(feature = "serde", serde(bound(serialize = "", deserialize = "")))] +#[derive(TypeId)] pub struct BlsSignature(pub(crate) S::InnerSig); dlgt_codec!(for[S: BlsScheme] BlsSignature => BlsSigBytes, Hash256, BlsError, BLS_SIG_LEN); @@ -107,10 +108,6 @@ impl Hash for BlsSignature { } } -impl TypeId for BlsSignature { - const TYPE_ID: u32 = S::SIG_TYPE_ID; -} - type_cvrt!(for[S: BlsScheme] From> for BlsSigBytes, |sig| { Self::from_bytes(sig.to_bytes()) }); @@ -124,7 +121,9 @@ type_cvrt!(for[S: BlsScheme] TryFrom> for BlsSignature, BlsErr mod tests { use super::*; use crate::bls::secret_ops::BlsSecretKey; - use crate::bls::tests::{G2_OFF_SUBGROUP_CHIA, G2_OFF_SUBGROUP_IETF, MSG_DEADBEEF, SEED_0, SEED_1}; + use crate::bls::tests::{ + test_ikm, test_msg, G2_OFF_SUBGROUP_CHIA, G2_OFF_SUBGROUP_IETF, MSG_8BADFOOD, MSG_DEADBEEF, RSEED, + }; use crate::bls::{BlsScChia, BlsScIetf}; use crate::prelude::*; @@ -148,14 +147,14 @@ mod tests { } fn assert_sign_verify() { - let sk = BlsSecretKey::::generate(&SEED_0).unwrap(); + let sk = BlsSecretKey::::generate(&RSEED[0]).unwrap(); let pk = sk.public_key(); let sig = sk.sign(S::msg_ref(&MSG_DEADBEEF)); assert!(sig.verify(S::msg_ref(&MSG_DEADBEEF), &pk).is_ok()); - assert!(sig.verify(S::msg_ref(&[0x42; 32]), &pk).is_err()); + assert!(sig.verify(S::msg_ref(&MSG_8BADFOOD), &pk).is_err()); - let other_pk = BlsSecretKey::::generate(&SEED_1).unwrap().public_key(); + let other_pk = BlsSecretKey::::generate(&RSEED[1]).unwrap().public_key(); assert!(sig.verify(S::msg_ref(&MSG_DEADBEEF), &other_pk).is_err()); } @@ -171,9 +170,9 @@ mod tests { /// and another key all fail. #[rstest] fn ietf_signature_variant_contract() { - let sk = BlsSecretKey::::generate(&SEED_0).unwrap(); + let sk = BlsSecretKey::::generate(&RSEED[0]).unwrap(); let pk = sk.public_key(); - let other_pk = BlsSecretKey::::generate(&SEED_1).unwrap().public_key(); + let other_pk = BlsSecretKey::::generate(&RSEED[1]).unwrap().public_key(); let msg = b"variant-bound message"; let wrong_msg = b"another message"; @@ -201,7 +200,7 @@ mod tests { /// BLS signing draws no randomness, so the same key over the same message /// yields the same signature every time. fn assert_sign_is_deterministic() { - let sk = BlsSecretKey::::generate(&SEED_0).unwrap(); + let sk = BlsSecretKey::::generate(&RSEED[0]).unwrap(); let msg = S::msg_ref(&MSG_DEADBEEF); assert_eq!(sk.sign(msg), sk.sign(msg)); } @@ -214,7 +213,7 @@ mod tests { } fn assert_sig_roundtrip() { - let sk = BlsSecretKey::::generate(&SEED_0).unwrap(); + let sk = BlsSecretKey::::generate(&RSEED[0]).unwrap(); let bytes = sk.sign(S::msg_ref(&MSG_DEADBEEF)).to_bytes(); assert_eq!(BlsSignature::::from_bytes(&bytes).unwrap().to_bytes(), bytes); } @@ -233,10 +232,10 @@ mod tests { let mut pk_signs = [false; 2]; let mut sig_signs = [false; 2]; - for seed_byte in 0..64u8 { - let sk = BlsSecretKey::::generate(&[seed_byte; 32]).unwrap(); + for i in 0..64 { + let sk = BlsSecretKey::::generate(&test_ikm(i)).unwrap(); let pk = sk.public_key(); - let sig = sk.sign(S::msg_ref(&MSG_DEADBEEF)); + let sig = sk.sign(S::msg_ref(&test_msg(i))); let pk_bytes = pk.to_bytes(); let sig_bytes = sig.to_bytes(); @@ -286,7 +285,7 @@ mod tests { #[case::sign_byte(0, 0x20)] #[case::swizzled_byte(48, 0x40)] fn chia_rejects_stray_signature_bits(#[case] index: usize, #[case] mask: u8) { - let clean = BlsSecretKey::::generate(&SEED_0) + let clean = BlsSecretKey::::generate(&RSEED[0]) .unwrap() .sign(&MSG_DEADBEEF) .to_bytes(); @@ -378,14 +377,14 @@ mod tests { /// scheme mix-up cannot go unnoticed. #[rstest] fn signatures_differ_across_schemes() { - let chia = BlsSecretKey::::generate(&SEED_0).unwrap(); + let chia = BlsSecretKey::::generate(&RSEED[0]).unwrap(); let ietf = BlsSecretKey::::from_bytes(&chia.to_bytes()).unwrap(); assert_ne!(chia.sign(&MSG_DEADBEEF).to_bytes(), ietf.sign(&MSG_DEADBEEF).to_bytes()); } /// Conversion re-encodes one point, so a round trip returns the original. fn assert_sig_scheme_conversion_round_trips() { - let sk = BlsSecretKey::::generate(&SEED_0).unwrap(); + let sk = BlsSecretKey::::generate(&RSEED[0]).unwrap(); let sig = sk.sign(S::msg_ref(&MSG_DEADBEEF)); let there = sig.to_scheme::().unwrap(); @@ -406,7 +405,7 @@ mod tests { /// hash nor the target's key. #[rstest] fn sig_scheme_conversion_does_not_move_the_augmentation() { - let sk = BlsSecretKey::::generate(&SEED_0).unwrap(); + let sk = BlsSecretKey::::generate(&RSEED[0]).unwrap(); let sig = sk.sign(&MSG_DEADBEEF); let converted = sig.to_scheme::().unwrap(); @@ -432,18 +431,18 @@ mod tests { /// pinned per scheme. #[rstest] fn serde_roundtrip() { - let chia = BlsSecretKey::::generate(&SEED_0).unwrap(); + let chia = BlsSecretKey::::generate(&RSEED[0]).unwrap(); assert_json_rt(&chia.sign(&MSG_DEADBEEF)); - let ietf = BlsSecretKey::::generate(&SEED_0).unwrap(); + let ietf = BlsSecretKey::::generate(&RSEED[0]).unwrap(); assert_json_rt(&ietf.sign(&MSG_DEADBEEF)); } #[rstest] fn serde_emits_hex_string() { - let chia = BlsSecretKey::::generate(&SEED_0) + let chia = BlsSecretKey::::generate(&RSEED[0]) .unwrap() .sign(&MSG_DEADBEEF); - let ietf = BlsSecretKey::::generate(&SEED_0) + let ietf = BlsSecretKey::::generate(&RSEED[0]) .unwrap() .sign(&MSG_DEADBEEF); diff --git a/pkgs/pkc/src/bls/sig_bytes.rs b/pkgs/pkc/src/bls/sig_bytes.rs index c7578622..112348df 100644 --- a/pkgs/pkc/src/bls/sig_bytes.rs +++ b/pkgs/pkc/src/bls/sig_bytes.rs @@ -10,7 +10,8 @@ use crate::bls::BlsSchemeId; use bitcoin_hashes::sha256d::Hash as Sha256d; use dash_num::Hash256; -use dash_types::codec::{Hashable, TypeId}; +use dash_types::codec::Hashable; +use dash_types::type_id::TypeId; use dash_types::{derive_bytes, impl_bytes}; use core::marker::PhantomData; @@ -19,6 +20,7 @@ use core::marker::PhantomData; pub const BLS_SIG_LEN: usize = 96; /// Scheme-tagged BLS signature bytes (96 bytes, unvalidated). +#[derive(TypeId)] pub struct BlsSigBytes { inner: [u8; BLS_SIG_LEN], _scheme: PhantomData, @@ -54,8 +56,4 @@ impl BlsSigBytes { } } -impl TypeId for BlsSigBytes { - const TYPE_ID: u32 = S::SIG_TYPE_ID; -} - derive_bytes!(for[S: BlsSchemeId] BlsSigBytes, BLS_SIG_LEN); diff --git a/pkgs/pkc/src/bls/sig_id.rs b/pkgs/pkc/src/bls/sig_id.rs index 7fae85fa..0172553a 100644 --- a/pkgs/pkc/src/bls/sig_id.rs +++ b/pkgs/pkc/src/bls/sig_id.rs @@ -6,7 +6,7 @@ //! Signature types. -use dash_types::Unencodable; +use dash_types::type_id::Unencodable; /// BLS signature variant. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Unencodable)] diff --git a/pkgs/pkc/src/bls/sig_pop.rs b/pkgs/pkc/src/bls/sig_pop.rs index c6a2194b..f5b89e42 100644 --- a/pkgs/pkc/src/bls/sig_pop.rs +++ b/pkgs/pkc/src/bls/sig_pop.rs @@ -40,21 +40,21 @@ impl BlsPublicKey { #[expect(clippy::unwrap_used, reason = "test code")] mod tests { use super::*; - use crate::bls::tests::{SEED_0, SEED_1}; + use crate::bls::tests::RSEED; use rstest::rstest; #[rstest] fn ietf_proof_of_possession_roundtrip() { - let sk = BlsSecretKey::::generate(&SEED_0).unwrap(); + let sk = BlsSecretKey::::generate(&RSEED[0]).unwrap(); let proof = sk.prove_possession(); assert!(sk.public_key().verify_possession(&proof).is_ok()); } #[rstest] fn ietf_proof_of_possession_rejects_wrong_key() { - let sk0 = BlsSecretKey::::generate(&SEED_0).unwrap(); - let sk1 = BlsSecretKey::::generate(&SEED_1).unwrap(); + let sk0 = BlsSecretKey::::generate(&RSEED[0]).unwrap(); + let sk1 = BlsSecretKey::::generate(&RSEED[1]).unwrap(); let proof = sk0.prove_possession(); assert!(sk1.public_key().verify_possession(&proof).is_err()); } diff --git a/pkgs/pkc/src/bls/sig_threshold.rs b/pkgs/pkc/src/bls/sig_threshold.rs index 47166551..ed2ba849 100644 --- a/pkgs/pkc/src/bls/sig_threshold.rs +++ b/pkgs/pkc/src/bls/sig_threshold.rs @@ -35,7 +35,7 @@ impl BlsSignature { #[expect(clippy::unwrap_used, reason = "test code")] mod tests { use crate::bls::scheme_ops::BlsScheme; - use crate::bls::tests::{make_id, sequential_ids, MSG_DEADBEEF, SEED_0}; + use crate::bls::tests::{make_id, sequential_ids, MSG_DEADBEEF, RSEED}; use crate::bls::{BlsError, BlsScChia, BlsScIetf, BlsSecretKey, BlsSigShare, BlsSignature, BlsSkShare}; use crate::prelude::*; @@ -45,7 +45,7 @@ mod tests { use rstest::rstest; fn assert_threshold_split_recover() { - let sk = BlsSecretKey::::generate(&SEED_0).unwrap(); + let sk = BlsSecretKey::::generate(&RSEED[0]).unwrap(); let pk = sk.public_key(); let ids = sequential_ids(5); @@ -79,7 +79,7 @@ mod tests { /// Interpolating fewer than `threshold` shares still yields a point, so the /// guard against a short quorum is that the result fails verification. fn assert_sub_threshold_does_not_verify() { - let sk = BlsSecretKey::::generate(&SEED_0).unwrap(); + let sk = BlsSecretKey::::generate(&RSEED[0]).unwrap(); let pk = sk.public_key(); let shares = sk.split(3, &sequential_ids(5), &mut OsRng).unwrap(); let msg = S::msg_ref(&MSG_DEADBEEF); @@ -105,7 +105,7 @@ mod tests { Err(BlsError::InsufficientShares) )); - let sk = BlsSecretKey::::generate(&SEED_0).unwrap(); + let sk = BlsSecretKey::::generate(&RSEED[0]).unwrap(); let ids = sequential_ids(3); let shares = sk.split(2, &ids, &mut OsRng).unwrap(); let one = shares[0].sign(S::msg_ref(&MSG_DEADBEEF)); diff --git a/pkgs/pkc/src/bls/tests.rs b/pkgs/pkc/src/bls/tests.rs index 9865a74a..31e0dcce 100644 --- a/pkgs/pkc/src/bls/tests.rs +++ b/pkgs/pkc/src/bls/tests.rs @@ -10,12 +10,6 @@ use crate::prelude::*; use hex_conservative::hex; -/// IKM producing the first deterministic test key. -pub const SEED_0: [u8; 32] = [0u8; 32]; - -/// IKM producing the second deterministic test key. -pub const SEED_1: [u8; 32] = [1u8; 32]; - /// BLS12-381 scalar field order r, big-endian. pub const GROUP_ORDER: [u8; 32] = hex!("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001"); @@ -25,6 +19,9 @@ pub const RSEED: [[u8; 32]; 4] = [[0u8; 32], [1u8; 32], [2u8; 32], [3u8; 32]]; /// Test message. pub const MSG_DEADBEEF: [u8; 32] = hex!("deadbeefdeadbeefdeadbeefdeadbeefcafebabecafebabecafebabecafebabe"); +/// A message distinct from [`MSG_DEADBEEF`]. +pub const MSG_8BADFOOD: [u8; 32] = hex!("8badf00d8badf00d8badf00d8badf00dfeedfacefeedfacefeedfacefeedface"); + /// Smallest off-subgroup G1 point, Chia-encoded: `x = 4` is the least `x` /// with `x^3 + 4` a residue mod `p` and `[r]P != O`. pub const G1_OFF_SUBGROUP_CHIA: [u8; 48] = diff --git a/pkgs/pkc/src/ecdsa/mod.rs b/pkgs/pkc/src/ecdsa/mod.rs index dff72daf..0caddf92 100644 --- a/pkgs/pkc/src/ecdsa/mod.rs +++ b/pkgs/pkc/src/ecdsa/mod.rs @@ -13,7 +13,7 @@ mod secret_bytes; mod sig_bytes; mod sig_rec_bytes; -use dash_types::Unencodable; +use dash_types::type_id::Unencodable; pub use error::EcdsaError; pub use public_bytes::{EcdsaPkBytes, ECDSA_PK_LEN}; diff --git a/pkgs/pkc/src/ecdsa/public_bytes.rs b/pkgs/pkc/src/ecdsa/public_bytes.rs index 5b054efd..0fe910eb 100644 --- a/pkgs/pkc/src/ecdsa/public_bytes.rs +++ b/pkgs/pkc/src/ecdsa/public_bytes.rs @@ -12,7 +12,7 @@ use crate::prelude::*; use bitcoin_hashes::{ripemd160, sha256}; use cfg_if::cfg_if; use dash_types::codec::{read_bytes, BaseCodec, DecodeError, EncodeBuf, Hashable}; -use dash_types::TypeId; +use dash_types::type_id::TypeId; use dash_types::{enum_map, impl_type, CompactSize}; use core::cmp::Ordering; diff --git a/pkgs/pkc/src/ecdsa/public_ops.rs b/pkgs/pkc/src/ecdsa/public_ops.rs index 6c3cb329..17c7312a 100644 --- a/pkgs/pkc/src/ecdsa/public_ops.rs +++ b/pkgs/pkc/src/ecdsa/public_ops.rs @@ -12,7 +12,8 @@ use super::sig_ops::EcdsaSignature; use super::sig_rec_ops::EcdsaRecSignature; use super::{Compression, EcdsaRecSigBytes, PubKeyHash}; -use dash_types::{dlgt_codec, type_cvrt, TypeId, Unencodable}; +use dash_types::type_id::{TypeId, Unencodable}; +use dash_types::{dlgt_codec, type_cvrt}; use k256::ecdsa::{signature::hazmat::PrehashVerifier, VerifyingKey}; use core::hash::{Hash, Hasher}; diff --git a/pkgs/pkc/src/ecdsa/secret_ops.rs b/pkgs/pkc/src/ecdsa/secret_ops.rs index 99f778fd..635a797a 100644 --- a/pkgs/pkc/src/ecdsa/secret_ops.rs +++ b/pkgs/pkc/src/ecdsa/secret_ops.rs @@ -16,7 +16,8 @@ use super::{Compression, EcdsaRecSigBytes}; use bitcoin_hashes::sha256d; use dash_num::Hash256; use dash_types::codec::{ensure, BaseCodec, DecodeError, EncodeBuf, Hashable}; -use dash_types::{impl_stype, type_cvrt, ArrayBuf, TypeId}; +use dash_types::type_id::TypeId; +use dash_types::{impl_stype, type_cvrt, ArrayBuf}; use hex_conservative::hex; use k256::ecdsa::{signature::hazmat::PrehashSigner, SigningKey}; use k256::elliptic_curve::ops::Neg; diff --git a/pkgs/pkc/src/ecdsa/sig_bytes.rs b/pkgs/pkc/src/ecdsa/sig_bytes.rs index abf50eb3..2b6e5645 100644 --- a/pkgs/pkc/src/ecdsa/sig_bytes.rs +++ b/pkgs/pkc/src/ecdsa/sig_bytes.rs @@ -12,7 +12,8 @@ use bitcoin_hashes::sha256d; use cfg_if::cfg_if; use dash_num::Hash256; use dash_types::codec::{read_bytes, BaseCodec, DecodeError, EncodeBuf, Hashable}; -use dash_types::{impl_type, type_cvrt, CompactSize, TypeId}; +use dash_types::type_id::TypeId; +use dash_types::{impl_type, type_cvrt, CompactSize}; use core::fmt; diff --git a/pkgs/pkc/src/ecdsa/sig_ops.rs b/pkgs/pkc/src/ecdsa/sig_ops.rs index b26b2f24..6889ef1c 100644 --- a/pkgs/pkc/src/ecdsa/sig_ops.rs +++ b/pkgs/pkc/src/ecdsa/sig_ops.rs @@ -11,7 +11,8 @@ use super::sig_bytes::ECDSA_SIG_LEN; use super::EcdsaSigBytes; use dash_num::Hash256; -use dash_types::{dlgt_codec, type_cvrt, TypeId, Unencodable}; +use dash_types::type_id::{TypeId, Unencodable}; +use dash_types::{dlgt_codec, type_cvrt}; use k256::ecdsa::{DerSignature, Signature}; use core::hash::{Hash, Hasher}; diff --git a/pkgs/pkc/src/ecdsa/sig_rec_bytes.rs b/pkgs/pkc/src/ecdsa/sig_rec_bytes.rs index 6959029a..4eb4992e 100644 --- a/pkgs/pkc/src/ecdsa/sig_rec_bytes.rs +++ b/pkgs/pkc/src/ecdsa/sig_rec_bytes.rs @@ -14,7 +14,8 @@ use bitcoin_hashes::sha256d; use cfg_if::cfg_if; use dash_num::Hash256; use dash_types::codec::{read_bytes, BaseCodec, DecodeError, EncodeBuf, Hashable}; -use dash_types::{enum_map, impl_type, type_cvrt, CompactSize, TypeId}; +use dash_types::type_id::TypeId; +use dash_types::{enum_map, impl_type, type_cvrt, CompactSize}; use core::fmt; diff --git a/pkgs/pkc/src/ecdsa/sig_rec_ops.rs b/pkgs/pkc/src/ecdsa/sig_rec_ops.rs index d5ac6d8a..3df33a7e 100644 --- a/pkgs/pkc/src/ecdsa/sig_rec_ops.rs +++ b/pkgs/pkc/src/ecdsa/sig_rec_ops.rs @@ -13,7 +13,8 @@ use super::sig_rec_bytes::{CompactFlags, EcdsaRecSigBytes}; use super::Compression; use dash_num::Hash256; -use dash_types::{dlgt_codec, type_cvrt, TypeId}; +use dash_types::type_id::TypeId; +use dash_types::{dlgt_codec, type_cvrt}; use k256::ecdsa::{RecoveryId, Signature}; /// An ECDSA signature with recovery id and compression metadata. diff --git a/pkgs/pkc/src/lib.rs b/pkgs/pkc/src/lib.rs index 21824285..ac201ec1 100644 --- a/pkgs/pkc/src/lib.rs +++ b/pkgs/pkc/src/lib.rs @@ -17,8 +17,6 @@ mod prelude; pub mod bls; pub mod ecdsa; -#[cfg(feature = "std")] -pub mod worker; #[doc(hidden)] pub mod __private { diff --git a/pkgs/pkc/src/worker.rs b/pkgs/pkc/src/worker.rs deleted file mode 100644 index 2fb483ed..00000000 --- a/pkgs/pkc/src/worker.rs +++ /dev/null @@ -1,49 +0,0 @@ -// -// Copyright (c) 2026-present, The Dash Core developers -// SPDX-License-Identifier: MIT -// See the accompanying file LICENSE or https://opensource.org/license/MIT -// - -//! Generic parallel work distribution. -//! -//! Thin layer over rayon that parallelizes cryptographic operations without -//! coupling to any specific scheme. The caller provides the operation; the -//! worker handles thread pooling and work stealing. - -use crate::prelude::*; - -use rayon::prelude::*; - -/// Verify N items in parallel. Returns per-item pass/fail. -pub fn par_verify(items: &[T], verify: F) -> Vec -where - T: Sync, - F: Fn(&T) -> bool + Sync, -{ - items.par_iter().map(&verify).collect() -} - -/// Map N items in parallel. -pub fn par_map(items: &[T], f: F) -> Vec -where - T: Sync, - U: Send, - F: Fn(&T) -> U + Sync, -{ - items.par_iter().map(&f).collect() -} - -/// Tree-reduce N items in parallel. -pub fn par_reduce(items: Vec, combine: F) -> Option -where - T: Send, - F: Fn(T, T) -> T + Sync + Send, -{ - items.into_par_iter().reduce_with(combine) -} - -/// Set the global thread pool size. Call once at startup. -/// Subsequent calls are silently ignored. -pub fn init(num_threads: usize) { - let _ = rayon::ThreadPoolBuilder::new().num_threads(num_threads).build_global(); -} diff --git a/pkgs/pow/Cargo.toml b/pkgs/pow/Cargo.toml index 39209d93..574e1c20 100644 --- a/pkgs/pow/Cargo.toml +++ b/pkgs/pow/Cargo.toml @@ -6,16 +6,11 @@ license = "MIT" [features] default = [] -std = ["dep:rayon"] +std = [] full = ["std", "aes_hw", "simd"] aes_hw = [] simd = [] -[dependencies] -cfg-if = "1" -dash-num = { version = "0.0.0", path = "../num" } -rayon = { version = "1", optional = true } - [dev-dependencies] dash-dev = { version = "0.0.0", path = "../dev", features = ["full"] } divan = "0.1" @@ -48,7 +43,7 @@ name = "skein" name = "pow" path = "bench/main.rs" harness = false -required-features = ["std", "simd"] +required-features = ["simd"] [lints] workspace = true diff --git a/pkgs/pow/bench/main.rs b/pkgs/pow/bench/main.rs index 8ab42041..29ed1dc2 100644 --- a/pkgs/pow/bench/main.rs +++ b/pkgs/pow/bench/main.rs @@ -6,8 +6,6 @@ //! Proof of work total and constituent benchmarks. -#[cfg(feature = "std")] -use dash_pow::worker::par_hash; use dash_pow::{__private as pow_crate, hash as pow_hash}; use divan::{black_box, Bencher}; @@ -44,16 +42,6 @@ mod pow { let input = vec![0u8; n]; bencher.counter(1u32).bench(|| black_box(pow_hash(black_box(&input)))); } - - #[cfg(feature = "std")] - #[divan::bench(args = [32, 80, 128, 512, 1024, 2048])] - fn par(bencher: Bencher, n: usize) { - let buf = vec![0u8; n]; - let inputs: Vec<&[u8]> = vec![buf.as_slice(); 1000]; - bencher - .counter(inputs.len() as u32) - .bench(|| black_box(par_hash(&inputs))); - } } bench_algo!(blake); diff --git a/pkgs/pow/src/blake/mod.rs b/pkgs/pow/src/blake/mod.rs index b3ff08db..51be8f8f 100644 --- a/pkgs/pow/src/blake/mod.rs +++ b/pkgs/pow/src/blake/mod.rs @@ -19,10 +19,7 @@ pub mod scalar; #[doc(hidden)] pub mod simd; -cfg_if::cfg_if! { - if #[cfg(feature = "simd")] { - pub use simd::hash512; - } else { - pub use scalar::hash512; - } -} +#[cfg(not(feature = "simd"))] +pub use scalar::hash512; +#[cfg(feature = "simd")] +pub use simd::hash512; diff --git a/pkgs/pow/src/blake/scalar.rs b/pkgs/pow/src/blake/scalar.rs index 82388e45..072bc4d5 100644 --- a/pkgs/pow/src/blake/scalar.rs +++ b/pkgs/pow/src/blake/scalar.rs @@ -9,8 +9,6 @@ use super::consts::{BLOCK, CB, IV, SIGMA}; use crate::util::memops::{extract, load_u64_be, store_u64_be}; -use dash_num::Hash512; - /// Compresses one 128-byte block into the state. /// /// `t0`/`t1` is the 128-bit counter AFTER the +1024 advance for this block. @@ -76,7 +74,7 @@ const fn advance_counter(t0: &mut u64, t1: &mut u64) { } } -pub const fn hash512(data: &[u8]) -> Hash512 { +pub const fn hash512(data: &[u8]) -> [u8; 64] { let mut h = IV; let mut t0: u64 = 0; let mut t1: u64 = 0; @@ -146,7 +144,7 @@ pub const fn hash512(data: &[u8]) -> Hash512 { store_u64_be(&mut out, i, h[i]); i += 1; } - Hash512::from_bytes(out) + out } #[cfg(test)] @@ -154,5 +152,5 @@ mod tests { use super::*; /// Proves hash512 evaluates at compile time. - const _: Hash512 = hash512(b""); + const _: [u8; 64] = hash512(b""); } diff --git a/pkgs/pow/src/blake/simd.rs b/pkgs/pow/src/blake/simd.rs index 875b69e2..5e7551dd 100644 --- a/pkgs/pow/src/blake/simd.rs +++ b/pkgs/pow/src/blake/simd.rs @@ -19,8 +19,6 @@ use super::consts::{BLOCK, CB, IV, SIGMA}; use crate::util::memops::{load_u64_le, store_u64_le}; -use dash_num::Hash512; - /// Compresses one 128-byte block into the chaining state. /// /// `t0` and `t1` are the 128-bit bit counter after this block has been counted. @@ -140,7 +138,7 @@ pub fn hash_to_state(data: &[u8]) -> [u64; 8] { h } -pub fn hash512(data: &[u8]) -> Hash512 { +pub fn hash512(data: &[u8]) -> [u8; 64] { let h = hash_to_state(data); let mut out = [0u8; 64]; let mut i = 0; @@ -148,5 +146,5 @@ pub fn hash512(data: &[u8]) -> Hash512 { store_u64_le(&mut out, i, h[i].swap_bytes()); i += 1; } - out.into() + out } diff --git a/pkgs/pow/src/bmw/mod.rs b/pkgs/pow/src/bmw/mod.rs index 7b149776..e10ba0f1 100644 --- a/pkgs/pow/src/bmw/mod.rs +++ b/pkgs/pow/src/bmw/mod.rs @@ -14,10 +14,7 @@ pub mod scalar; #[doc(hidden)] pub mod simd; -cfg_if::cfg_if! { - if #[cfg(feature = "simd")] { - pub use simd::hash512; - } else { - pub use scalar::hash512; - } -} +#[cfg(not(feature = "simd"))] +pub use scalar::hash512; +#[cfg(feature = "simd")] +pub use simd::hash512; diff --git a/pkgs/pow/src/bmw/scalar.rs b/pkgs/pow/src/bmw/scalar.rs index e8e335de..8e426d83 100644 --- a/pkgs/pow/src/bmw/scalar.rs +++ b/pkgs/pow/src/bmw/scalar.rs @@ -9,8 +9,6 @@ use super::consts::*; use crate::util::memops::{extract, load_u64_le, store_u64_le}; -use dash_num::Hash512; - /// S-function: parameterized shift/rotate mixing. /// /// For n < 4: `(x >> A) ^ (x << B) ^ rotl(x, C) ^ rotl(x, D)`. For n >= 4: `(x @@ -166,7 +164,7 @@ const fn state_to_bytes(state: &[u64; 16]) -> [u8; BLOCK] { buf } -pub const fn hash512(data: &[u8]) -> Hash512 { +pub const fn hash512(data: &[u8]) -> [u8; 64] { let mut h1 = IV; let mut h2 = [0u64; 16]; let mut current = &mut h1; @@ -215,7 +213,7 @@ pub const fn hash512(data: &[u8]) -> Hash512 { store_u64_le(&mut out, i, next[i + 8]); i += 1; } - Hash512::from_bytes(out) + out } #[cfg(test)] @@ -223,5 +221,5 @@ mod tests { use super::*; /// Proves hash512 evaluates at compile time. - const _: Hash512 = hash512(b""); + const _: [u8; 64] = hash512(b""); } diff --git a/pkgs/pow/src/bmw/simd.rs b/pkgs/pow/src/bmw/simd.rs index 96c0ea88..fbca4485 100644 --- a/pkgs/pow/src/bmw/simd.rs +++ b/pkgs/pow/src/bmw/simd.rs @@ -9,8 +9,6 @@ use super::consts::*; use crate::util::memops::{load_u64_le, store_u64_le}; -use dash_num::Hash512; - const WORDS: usize = 16; const QWORDS: usize = 32; @@ -226,7 +224,7 @@ fn hash_to_words(data: &[u8]) -> [u64; 8] { out } -pub fn hash512(data: &[u8]) -> Hash512 { +pub fn hash512(data: &[u8]) -> [u8; 64] { let words = hash_to_words(data); let mut out = [0u8; 64]; let mut index = 0; @@ -234,5 +232,5 @@ pub fn hash512(data: &[u8]) -> Hash512 { store_u64_le(&mut out, index, words[index]); index += 1; } - out.into() + out } diff --git a/pkgs/pow/src/cubehash/mod.rs b/pkgs/pow/src/cubehash/mod.rs index 20cde186..7dc89d56 100644 --- a/pkgs/pow/src/cubehash/mod.rs +++ b/pkgs/pow/src/cubehash/mod.rs @@ -14,10 +14,7 @@ pub mod scalar; #[doc(hidden)] pub mod simd; -cfg_if::cfg_if! { - if #[cfg(feature = "simd")] { - pub use simd::hash512; - } else { - pub use scalar::hash512; - } -} +#[cfg(not(feature = "simd"))] +pub use scalar::hash512; +#[cfg(feature = "simd")] +pub use simd::hash512; diff --git a/pkgs/pow/src/cubehash/scalar.rs b/pkgs/pow/src/cubehash/scalar.rs index 22e60cb4..91d13a5d 100644 --- a/pkgs/pow/src/cubehash/scalar.rs +++ b/pkgs/pow/src/cubehash/scalar.rs @@ -9,8 +9,6 @@ use super::consts::{round_pair, BLOCK, IV}; use crate::util::memops::{extract, load_u32_le, store_u32_le}; -use dash_num::Hash512; - /// Applies 16 rounds (8 round-pairs) of the CubeHash permutation. #[inline] pub const fn sixteen_rounds(s: &mut [u32; 32]) { @@ -31,7 +29,7 @@ pub const fn absorb_block(state: &mut [u32; 32], block: &[u8]) { sixteen_rounds(state); } -pub const fn hash512(data: &[u8]) -> Hash512 { +pub const fn hash512(data: &[u8]) -> [u8; 64] { let mut state = IV; // Absorb full blocks @@ -67,5 +65,5 @@ pub const fn hash512(data: &[u8]) -> Hash512 { store_u32_le(&mut out, i, state[i]); i += 1; } - Hash512::from_bytes(out) + out } diff --git a/pkgs/pow/src/cubehash/simd.rs b/pkgs/pow/src/cubehash/simd.rs index d4fecf9a..babdc5f2 100644 --- a/pkgs/pow/src/cubehash/simd.rs +++ b/pkgs/pow/src/cubehash/simd.rs @@ -10,8 +10,6 @@ use super::consts::{BLOCK, IV}; use crate::util::arx::rotl_u32x4; use crate::util::memops::{load_u32_le, store_u32_le}; -use dash_num::Hash512; - use core::simd::Simd; /// Four neighbouring state words packed into one group. @@ -131,7 +129,7 @@ fn absorb_block(state: &mut [U32x4; 8], block: &[u8]) { absorb_words(state, lo, hi); } -pub fn hash512(data: &[u8]) -> Hash512 { +pub fn hash512(data: &[u8]) -> [u8; 64] { let mut words = IV; let mut state = [ load_vec(&words, 0), @@ -179,5 +177,5 @@ pub fn hash512(data: &[u8]) -> Hash512 { store_u32_le(&mut out, i, words[i]); i += 1; } - out.into() + out } diff --git a/pkgs/pow/src/echo/mod.rs b/pkgs/pow/src/echo/mod.rs index 6400e2f3..6b2b4b85 100644 --- a/pkgs/pow/src/echo/mod.rs +++ b/pkgs/pow/src/echo/mod.rs @@ -14,10 +14,7 @@ pub mod scalar; #[doc(hidden)] pub mod simd; -cfg_if::cfg_if! { - if #[cfg(feature = "simd")] { - pub use simd::hash512; - } else { - pub use scalar::hash512; - } -} +#[cfg(not(feature = "simd"))] +pub use scalar::hash512; +#[cfg(feature = "simd")] +pub use simd::hash512; diff --git a/pkgs/pow/src/echo/scalar.rs b/pkgs/pow/src/echo/scalar.rs index 1471b1df..e2924fd4 100644 --- a/pkgs/pow/src/echo/scalar.rs +++ b/pkgs/pow/src/echo/scalar.rs @@ -10,8 +10,6 @@ use super::consts::BLOCK; use crate::util::aes::{round, round_nk}; use crate::util::memops::{extract, load_u32_le, store_u32_le}; -use dash_num::Hash512; - /// Increments a 128-bit counter by `val`. const fn inc_counter(cnt: &mut [u32; 4], val: u32) { cnt[0] = cnt[0].wrapping_add(val); @@ -151,7 +149,7 @@ pub const fn compress(v: &mut [[u32; 4]; 8], buf: &[u8], cnt: &[u32; 4]) { } } -pub const fn hash512(data: &[u8]) -> Hash512 { +pub const fn hash512(data: &[u8]) -> [u8; 64] { let mut v = [[512, 0, 0, 0]; 8]; let mut cnt = [0u32; 4]; @@ -223,7 +221,7 @@ pub const fn hash512(data: &[u8]) -> Hash512 { } i += 1; } - Hash512::from_bytes(out) + out } #[cfg(test)] @@ -231,5 +229,5 @@ mod tests { use super::*; /// Proves hash512 evaluates at compile time. - const _: Hash512 = hash512(b""); + const _: [u8; 64] = hash512(b""); } diff --git a/pkgs/pow/src/echo/simd.rs b/pkgs/pow/src/echo/simd.rs index 3f724210..6341af36 100644 --- a/pkgs/pow/src/echo/simd.rs +++ b/pkgs/pow/src/echo/simd.rs @@ -13,8 +13,6 @@ use crate::util::aes::cpu::{round, round_nk}; use crate::util::aes::simd::xtime_packed_u32; use crate::util::memops::{load_u32_le, store_u32_le}; -use dash_num::Hash512; - #[cfg(all(feature = "aes_hw", target_arch = "aarch64"))] use core::simd::Simd; @@ -341,7 +339,7 @@ fn hash_to_cells(data: &[u8]) -> ChainingValue { chaining_value } -pub fn hash512(data: &[u8]) -> Hash512 { +pub fn hash512(data: &[u8]) -> [u8; 64] { let cells = hash_to_cells(data); let mut out = [0u8; 64]; let mut cell = 0; @@ -353,5 +351,5 @@ pub fn hash512(data: &[u8]) -> Hash512 { } cell += 1; } - out.into() + out } diff --git a/pkgs/pow/src/groestl/mod.rs b/pkgs/pow/src/groestl/mod.rs index fe4c7179..ab30ef7c 100644 --- a/pkgs/pow/src/groestl/mod.rs +++ b/pkgs/pow/src/groestl/mod.rs @@ -14,10 +14,7 @@ pub mod scalar; #[doc(hidden)] pub mod simd; -cfg_if::cfg_if! { - if #[cfg(feature = "simd")] { - pub use simd::hash512; - } else { - pub use scalar::hash512; - } -} +#[cfg(not(feature = "simd"))] +pub use scalar::hash512; +#[cfg(feature = "simd")] +pub use simd::hash512; diff --git a/pkgs/pow/src/groestl/scalar.rs b/pkgs/pow/src/groestl/scalar.rs index 8f8ab129..454028e9 100644 --- a/pkgs/pow/src/groestl/scalar.rs +++ b/pkgs/pow/src/groestl/scalar.rs @@ -9,8 +9,6 @@ use super::consts::{BLOCK, IV, ROUNDS, T0, T4}; use crate::util::memops::{extract, load_u64_le, store_u64_le}; -use dash_num::Hash512; - // Byte extraction from u64 (LE convention). #[inline] const fn b0(x: u64) -> usize { @@ -168,7 +166,7 @@ pub const fn output_transform(h: &mut [u64; 16]) { } } -pub const fn hash512(data: &[u8]) -> Hash512 { +pub const fn hash512(data: &[u8]) -> [u8; 64] { let mut h = IV; let mut count = 0u64; @@ -222,7 +220,7 @@ pub const fn hash512(data: &[u8]) -> Hash512 { store_u64_le(&mut out, i, h[i + 8]); i += 1; } - Hash512::from_bytes(out) + out } #[cfg(test)] @@ -230,5 +228,5 @@ mod tests { use super::*; /// Proves hash512 evaluates at compile time. - const _: Hash512 = hash512(b""); + const _: [u8; 64] = hash512(b""); } diff --git a/pkgs/pow/src/groestl/simd.rs b/pkgs/pow/src/groestl/simd.rs index 44fc8ac2..9df048ca 100644 --- a/pkgs/pow/src/groestl/simd.rs +++ b/pkgs/pow/src/groestl/simd.rs @@ -12,8 +12,6 @@ use super::consts::{SUBSH_P, SUBSH_Q}; #[cfg(not(all(feature = "aes_hw", target_arch = "aarch64")))] use crate::util::aes::consts::SBOX; -use dash_num::Hash512; - use core::simd::num::{SimdInt, SimdUint}; #[cfg(not(all(feature = "aes_hw", target_arch = "aarch64")))] use core::simd::simd_swizzle; @@ -352,7 +350,7 @@ pub fn output_transform(chaining_value: &mut [Row; 8]) { *chaining_value = xor_rows(chaining_value, &state); } -pub fn hash512(data: &[u8]) -> Hash512 { +pub fn hash512(data: &[u8]) -> [u8; 64] { let mut chaining_value = [Row::splat(0); 8]; let mut row = 0; while row < 8 { @@ -397,5 +395,5 @@ pub fn hash512(data: &[u8]) -> Hash512 { let mut out = [0u8; 64]; extract_right_half(&chaining_value, &mut out); - out.into() + out } diff --git a/pkgs/pow/src/jh/mod.rs b/pkgs/pow/src/jh/mod.rs index ad95d118..301d440c 100644 --- a/pkgs/pow/src/jh/mod.rs +++ b/pkgs/pow/src/jh/mod.rs @@ -14,10 +14,7 @@ pub mod scalar; #[doc(hidden)] pub mod simd; -cfg_if::cfg_if! { - if #[cfg(feature = "simd")] { - pub use simd::hash512; - } else { - pub use scalar::hash512; - } -} +#[cfg(not(feature = "simd"))] +pub use scalar::hash512; +#[cfg(feature = "simd")] +pub use simd::hash512; diff --git a/pkgs/pow/src/jh/scalar.rs b/pkgs/pow/src/jh/scalar.rs index 830fbab4..05a85138 100644 --- a/pkgs/pow/src/jh/scalar.rs +++ b/pkgs/pow/src/jh/scalar.rs @@ -8,8 +8,6 @@ use super::consts::{BLOCK, IV, ROUND_CONSTS}; -use dash_num::Hash512; - /// E8 permutation on 16 u64 words: 42 rounds cycling W0-W6. pub const fn e8(h: &mut [u64; 16]) { // Extract to locals to avoid array borrow issues. @@ -200,7 +198,7 @@ const fn flatten_iv() -> [u64; 16] { h } -pub const fn hash512(data: &[u8]) -> Hash512 { +pub const fn hash512(data: &[u8]) -> [u8; 64] { let mut h = flatten_iv(); let mut block_count: u64 = 0; let mut buf = [0u8; BLOCK]; @@ -272,7 +270,7 @@ pub const fn hash512(data: &[u8]) -> Hash512 { } i += 1; } - Hash512::from_bytes(out) + out } #[cfg(test)] @@ -280,5 +278,5 @@ mod tests { use super::*; /// Proves hash512 evaluates at compile time. - const _: Hash512 = hash512(b""); + const _: [u8; 64] = hash512(b""); } diff --git a/pkgs/pow/src/jh/simd.rs b/pkgs/pow/src/jh/simd.rs index 90d0667b..a1c9dd89 100644 --- a/pkgs/pow/src/jh/simd.rs +++ b/pkgs/pow/src/jh/simd.rs @@ -9,8 +9,6 @@ use super::consts::{BLOCK, IV, ROUND_CONSTS}; use crate::util::memops::{load_u64_le, store_u64_le}; -use dash_num::Hash512; - use core::simd::{simd_swizzle, Simd}; /// One 128-bit JH row, stored as four 32-bit lanes. @@ -218,7 +216,7 @@ fn load_block_words(buf: &[u8]) -> [u64; 8] { core::array::from_fn(|i| load_u64_le(buf, i)) } -pub fn hash512(data: &[u8]) -> Hash512 { +pub fn hash512(data: &[u8]) -> [u8; 64] { let mut state = IV.map(row_from_u64_pair); let mut block_count = 0u64; let mut buf = [0u8; BLOCK]; @@ -257,5 +255,5 @@ pub fn hash512(data: &[u8]) -> Hash512 { store_row(&mut out, row, state[row + 4]); row += 1; } - out.into() + out } diff --git a/pkgs/pow/src/keccak/mod.rs b/pkgs/pow/src/keccak/mod.rs index b848c926..fc7d1fc4 100644 --- a/pkgs/pow/src/keccak/mod.rs +++ b/pkgs/pow/src/keccak/mod.rs @@ -14,17 +14,14 @@ pub mod scalar; #[doc(hidden)] pub mod simd; -cfg_if::cfg_if! { - if #[cfg(feature = "simd")] { - pub use simd::hash512; - } else { - pub use scalar::hash512; - } -} +#[cfg(not(feature = "simd"))] +pub use scalar::hash512; +#[cfg(feature = "simd")] +pub use simd::hash512; /// Keccak-512 sponge parameterised over a permutation function. #[cfg(feature = "simd")] -pub(crate) fn sponge(data: &[u8], perm: fn(&mut [u64; 25])) -> dash_num::Hash512 { +pub(crate) fn sponge(data: &[u8], perm: fn(&mut [u64; 25])) -> [u8; 64] { use crate::util::memops::{load_u64_le, store_u64_le}; use consts::RATE; @@ -59,5 +56,5 @@ pub(crate) fn sponge(data: &[u8], perm: fn(&mut [u64; 25])) -> dash_num::Hash512 store_u64_le(&mut out, i, state[i]); i += 1; } - dash_num::Hash512::from(out) + out } diff --git a/pkgs/pow/src/keccak/scalar.rs b/pkgs/pow/src/keccak/scalar.rs index 3748591a..22d5bd95 100644 --- a/pkgs/pow/src/keccak/scalar.rs +++ b/pkgs/pow/src/keccak/scalar.rs @@ -9,8 +9,6 @@ use super::consts::{RATE, RC, ROTC}; use crate::util::memops::{extract, load_u64_le, store_u64_le}; -use dash_num::Hash512; - /// Applies the Keccak-f[1600] permutation in place (24 rounds). /// /// State is a 5x5 matrix of 64-bit lanes stored in row-major order as @@ -78,7 +76,7 @@ const fn absorb_block(state: &mut [u64; 25], block: &[u8]) { keccak_f1600(state); } -pub const fn hash512(data: &[u8]) -> Hash512 { +pub const fn hash512(data: &[u8]) -> [u8; 64] { let mut state = [0u64; 25]; // Absorb full blocks @@ -107,7 +105,7 @@ pub const fn hash512(data: &[u8]) -> Hash512 { store_u64_le(&mut out, i, state[i]); i += 1; } - Hash512::from_bytes(out) + out } #[cfg(test)] @@ -115,5 +113,5 @@ mod tests { use super::*; /// Proves hash512 evaluates at compile time. - const _: Hash512 = hash512(b""); + const _: [u8; 64] = hash512(b""); } diff --git a/pkgs/pow/src/keccak/simd.rs b/pkgs/pow/src/keccak/simd.rs index 7cf74e8c..70c12fd0 100644 --- a/pkgs/pow/src/keccak/simd.rs +++ b/pkgs/pow/src/keccak/simd.rs @@ -8,8 +8,6 @@ use super::consts::RC; -use dash_num::Hash512; - /// Applies one round of the permutation, reading from `src` and writing to /// `dst`. /// @@ -112,6 +110,6 @@ pub fn keccak_f1600(state: &mut [u64; 25]) { } } -pub fn hash512(data: &[u8]) -> Hash512 { +pub fn hash512(data: &[u8]) -> [u8; 64] { super::sponge(data, keccak_f1600) } diff --git a/pkgs/pow/src/lib.rs b/pkgs/pow/src/lib.rs index 0b79ca86..ff0394b4 100644 --- a/pkgs/pow/src/lib.rs +++ b/pkgs/pow/src/lib.rs @@ -25,16 +25,11 @@ mod groestl; mod jh; mod keccak; mod luffa; -#[allow(unused_imports, reason = "ergonomic shim, exports may be unused")] -mod prelude; mod shavite; mod simd_hash; mod skein; mod util; -#[cfg(feature = "std")] -pub mod worker; - #[doc(hidden)] pub mod __private { pub mod blake { @@ -73,19 +68,22 @@ pub mod __private { } /// Computes the Dash proof-of-work hash. -pub fn hash(data: &[u8]) -> dash_num::Hash256 { +/// +/// The digest is little-endian, matching the consensus byte order of a +/// block hash. +pub fn hash(data: &[u8]) -> [u8; 32] { let h = blake::hash512(data); - let h = bmw::hash512(h.as_ref()); - let h = groestl::hash512(h.as_ref()); - let h = skein::hash512(h.as_ref()); - let h = jh::hash512(h.as_ref()); - let h = keccak::hash512(h.as_ref()); - let h = luffa::hash512(h.as_ref()); - let h = cubehash::hash512(h.as_ref()); - let h = shavite::hash512(h.as_ref()); - let h = simd_hash::hash512(h.as_ref()); - let h = echo::hash512(h.as_ref()); + let h = bmw::hash512(&h); + let h = groestl::hash512(&h); + let h = skein::hash512(&h); + let h = jh::hash512(&h); + let h = keccak::hash512(&h); + let h = luffa::hash512(&h); + let h = cubehash::hash512(&h); + let h = shavite::hash512(&h); + let h = simd_hash::hash512(&h); + let h = echo::hash512(&h); let mut out = [0u8; 32]; - out.copy_from_slice(&h.as_bytes()[..32]); - dash_num::Hash256::from(out) + out.copy_from_slice(&h[..32]); + out } diff --git a/pkgs/pow/src/luffa/mod.rs b/pkgs/pow/src/luffa/mod.rs index 23f5125f..957f3b20 100644 --- a/pkgs/pow/src/luffa/mod.rs +++ b/pkgs/pow/src/luffa/mod.rs @@ -14,10 +14,7 @@ pub mod scalar; #[doc(hidden)] pub mod simd; -cfg_if::cfg_if! { - if #[cfg(feature = "simd")] { - pub use simd::hash512; - } else { - pub use scalar::hash512; - } -} +#[cfg(not(feature = "simd"))] +pub use scalar::hash512; +#[cfg(feature = "simd")] +pub use simd::hash512; diff --git a/pkgs/pow/src/luffa/scalar.rs b/pkgs/pow/src/luffa/scalar.rs index 2c588979..0eaa2f0e 100644 --- a/pkgs/pow/src/luffa/scalar.rs +++ b/pkgs/pow/src/luffa/scalar.rs @@ -9,8 +9,6 @@ use super::consts::{BLOCK, IV, RC}; use crate::util::memops::extract; -use dash_num::Hash512; - /// SubCrumb: 4-input bitslice S-box at word indices. const fn sub_crumb(w: &mut [u32; 8], i0: usize, i1: usize, i2: usize, i3: usize) { let (mut a0, mut a1, mut a2, mut a3) = (w[i0], w[i1], w[i2], w[i3]); @@ -194,7 +192,7 @@ const fn load_msg(buf: &[u8]) -> [u32; 8] { out } -pub const fn hash512(data: &[u8]) -> Hash512 { +pub const fn hash512(data: &[u8]) -> [u8; 64] { let mut v: [[u32; 8]; 5] = IV; let mut pos = 0; @@ -226,7 +224,7 @@ pub const fn hash512(data: &[u8]) -> Hash512 { } i += 1; } - Hash512::from_bytes(out) + out } #[cfg(test)] @@ -234,5 +232,5 @@ mod tests { use super::*; /// Proves hash512 evaluates at compile time. - const _: Hash512 = hash512(b""); + const _: [u8; 64] = hash512(b""); } diff --git a/pkgs/pow/src/luffa/simd.rs b/pkgs/pow/src/luffa/simd.rs index b431a099..75831bec 100644 --- a/pkgs/pow/src/luffa/simd.rs +++ b/pkgs/pow/src/luffa/simd.rs @@ -10,8 +10,6 @@ use super::consts::{BLOCK, IV, RC, RC_FIRST4_HIGH, RC_FIRST4_LOW}; use crate::util::arx::rotl_u32x4; use crate::util::memops::{load_u32_le, store_u32_le}; -use dash_num::Hash512; - use core::simd::Simd; type WordVec = Simd; @@ -275,7 +273,7 @@ fn permute_first_four_branches(state: &mut [[u32; 8]; 5]) { } } -pub fn hash512(data: &[u8]) -> Hash512 { +pub fn hash512(data: &[u8]) -> [u8; 64] { let mut state: [[u32; 8]; 5] = IV; let mut pos = 0; @@ -305,5 +303,5 @@ pub fn hash512(data: &[u8]) -> Hash512 { final_round += 1; } - out.into() + out } diff --git a/pkgs/pow/src/prelude.rs b/pkgs/pow/src/prelude.rs deleted file mode 100644 index 16d40d0b..00000000 --- a/pkgs/pow/src/prelude.rs +++ /dev/null @@ -1,10 +0,0 @@ -// -// Copyright (c) 2026-present, The Dash Core developers -// SPDX-License-Identifier: MIT -// See the accompanying file LICENSE or https://opensource.org/license/MIT -// - -//! Re-exports for no_std compatibility. - -pub(crate) use alloc::string::String; -pub(crate) use alloc::vec::Vec; diff --git a/pkgs/pow/src/shavite/mod.rs b/pkgs/pow/src/shavite/mod.rs index 08a4dcdc..6f501b2a 100644 --- a/pkgs/pow/src/shavite/mod.rs +++ b/pkgs/pow/src/shavite/mod.rs @@ -14,10 +14,7 @@ pub mod scalar; #[doc(hidden)] pub mod simd; -cfg_if::cfg_if! { - if #[cfg(feature = "simd")] { - pub use simd::hash512; - } else { - pub use scalar::hash512; - } -} +#[cfg(not(feature = "simd"))] +pub use scalar::hash512; +#[cfg(feature = "simd")] +pub use simd::hash512; diff --git a/pkgs/pow/src/shavite/scalar.rs b/pkgs/pow/src/shavite/scalar.rs index 6dfaccdf..ec22258e 100644 --- a/pkgs/pow/src/shavite/scalar.rs +++ b/pkgs/pow/src/shavite/scalar.rs @@ -10,8 +10,6 @@ use super::consts::{BLOCK, IV}; use crate::util::aes::round_nk; use crate::util::memops::{extract, load_u32_le, store_u32_le}; -use dash_num::Hash512; - /// Expands 128-byte message block into 448 round keys. const fn key_schedule(msg: &[u8], cnt: &[u32; 4]) -> [u32; 448] { let mut rk = [0u32; 448]; @@ -153,7 +151,7 @@ const fn inc_counter(cnt: &mut [u32; 4], bits: u32) { } } -pub const fn hash512(data: &[u8]) -> Hash512 { +pub const fn hash512(data: &[u8]) -> [u8; 64] { let mut h = IV; let mut cnt = [0u32; 4]; @@ -214,7 +212,7 @@ pub const fn hash512(data: &[u8]) -> Hash512 { store_u32_le(&mut out, i, h[i]); i += 1; } - Hash512::from_bytes(out) + out } #[cfg(test)] @@ -222,5 +220,5 @@ mod tests { use super::*; /// Proves hash512 evaluates at compile time. - const _: Hash512 = hash512(b""); + const _: [u8; 64] = hash512(b""); } diff --git a/pkgs/pow/src/shavite/simd.rs b/pkgs/pow/src/shavite/simd.rs index d9c6934b..6e5c6cbf 100644 --- a/pkgs/pow/src/shavite/simd.rs +++ b/pkgs/pow/src/shavite/simd.rs @@ -10,8 +10,6 @@ use super::consts::{BLOCK, IV}; use crate::util::aes::cpu::round_nk; use crate::util::memops::{load_u32_le, store_u32_le}; -use dash_num::Hash512; - const SCHEDULE_BUNDLES: usize = 112; type Bundle = [u32; 4]; type State = [u32; 16]; @@ -325,7 +323,7 @@ fn hash_to_words(data: &[u8]) -> State { chaining_value } -pub fn hash512(data: &[u8]) -> Hash512 { +pub fn hash512(data: &[u8]) -> [u8; 64] { let result = hash_to_words(data); let mut out = [0u8; 64]; let mut word = 0; @@ -333,5 +331,5 @@ pub fn hash512(data: &[u8]) -> Hash512 { store_u32_le(&mut out, word, result[word]); word += 1; } - out.into() + out } diff --git a/pkgs/pow/src/simd_hash/mod.rs b/pkgs/pow/src/simd_hash/mod.rs index aef1f32c..1701f3b5 100644 --- a/pkgs/pow/src/simd_hash/mod.rs +++ b/pkgs/pow/src/simd_hash/mod.rs @@ -14,10 +14,7 @@ pub mod scalar; #[doc(hidden)] pub mod simd; -cfg_if::cfg_if! { - if #[cfg(feature = "simd")] { - pub use simd::hash512; - } else { - pub use scalar::hash512; - } -} +#[cfg(not(feature = "simd"))] +pub use scalar::hash512; +#[cfg(feature = "simd")] +pub use simd::hash512; diff --git a/pkgs/pow/src/simd_hash/scalar.rs b/pkgs/pow/src/simd_hash/scalar.rs index bb785698..ec620225 100644 --- a/pkgs/pow/src/simd_hash/scalar.rs +++ b/pkgs/pow/src/simd_hash/scalar.rs @@ -9,8 +9,6 @@ use super::consts::{ALPHA_TAB, BLOCK, IV, PP8K, YOFF_B_F, YOFF_B_N}; use crate::util::memops::{extract, load_u32_le, store_u32_le}; -use dash_num::Hash512; - // Modular reductions for Z/257Z arithmetic. const fn reds1(x: i32) -> i32 { (x & 0xFF) - (x >> 8) @@ -284,7 +282,7 @@ const fn encode_count(dst: &mut [u8], low: u32, high: u32, ptr: usize) { dst[7] = hi_b[3]; } -pub const fn hash512(data: &[u8]) -> Hash512 { +pub const fn hash512(data: &[u8]) -> [u8; 64] { let mut h = IV; let mut count_low = 0u32; let mut count_high = 0u32; @@ -322,7 +320,7 @@ pub const fn hash512(data: &[u8]) -> Hash512 { store_u32_le(&mut out, i, h[i]); i += 1; } - Hash512::from_bytes(out) + out } #[cfg(test)] @@ -330,5 +328,5 @@ mod tests { use super::*; /// Proves hash512 evaluates at compile time. - const _: Hash512 = hash512(b""); + const _: [u8; 64] = hash512(b""); } diff --git a/pkgs/pow/src/simd_hash/simd.rs b/pkgs/pow/src/simd_hash/simd.rs index d289f86c..b8db86de 100644 --- a/pkgs/pow/src/simd_hash/simd.rs +++ b/pkgs/pow/src/simd_hash/simd.rs @@ -9,8 +9,6 @@ use super::consts::{ALPHA_TAB, BLOCK, IV, PP8K, WBP, YOFF_B_F, YOFF_B_N}; use crate::util::memops::{load_u32_le, store_u32_le}; -use dash_num::Hash512; - use core::simd::cmp::SimdPartialOrd; use core::simd::{simd_swizzle, Select, Simd}; @@ -437,7 +435,7 @@ pub(super) fn hash_to_words(data: &[u8]) -> [u32; 16] { out } -pub fn hash512(data: &[u8]) -> Hash512 { +pub fn hash512(data: &[u8]) -> [u8; 64] { let result = hash_to_words(data); let mut out = [0u8; 64]; let mut i = 0; @@ -445,5 +443,5 @@ pub fn hash512(data: &[u8]) -> Hash512 { store_u32_le(&mut out, i, result[i]); i += 1; } - out.into() + out } diff --git a/pkgs/pow/src/skein/mod.rs b/pkgs/pow/src/skein/mod.rs index b4076744..81558f00 100644 --- a/pkgs/pow/src/skein/mod.rs +++ b/pkgs/pow/src/skein/mod.rs @@ -14,10 +14,7 @@ pub mod scalar; #[doc(hidden)] pub mod simd; -cfg_if::cfg_if! { - if #[cfg(feature = "simd")] { - pub use simd::hash512; - } else { - pub use scalar::hash512; - } -} +#[cfg(not(feature = "simd"))] +pub use scalar::hash512; +#[cfg(feature = "simd")] +pub use simd::hash512; diff --git a/pkgs/pow/src/skein/scalar.rs b/pkgs/pow/src/skein/scalar.rs index ec078062..6c4b39fd 100644 --- a/pkgs/pow/src/skein/scalar.rs +++ b/pkgs/pow/src/skein/scalar.rs @@ -10,8 +10,6 @@ use super::consts::{BLOCK, IV, NW}; use crate::util::memops::{extract, load_u64_le, store_u64_le}; use crate::util::threefish; -use dash_num::Hash512; - /// UBI chaining: processes one 64-byte block. /// /// `etype` encodes the block type and first/final flags in bits 55..62. @@ -37,7 +35,7 @@ pub const fn ubi(h: &mut [u64; NW], block: &[u8], bcount: u64, extra: usize, ety } } -pub const fn hash512(data: &[u8]) -> Hash512 { +pub const fn hash512(data: &[u8]) -> [u8; 64] { let mut h = IV; let mut bcount: u64 = 0; @@ -77,7 +75,7 @@ pub const fn hash512(data: &[u8]) -> Hash512 { store_u64_le(&mut out, i, h[i]); i += 1; } - Hash512::from_bytes(out) + out } #[cfg(test)] @@ -85,5 +83,5 @@ mod tests { use super::*; /// Proves hash512 evaluates at compile time. - const _: Hash512 = hash512(b""); + const _: [u8; 64] = hash512(b""); } diff --git a/pkgs/pow/src/skein/simd.rs b/pkgs/pow/src/skein/simd.rs index a952fffa..17ab1edd 100644 --- a/pkgs/pow/src/skein/simd.rs +++ b/pkgs/pow/src/skein/simd.rs @@ -10,8 +10,6 @@ use super::consts::{BLOCK, IV, NW}; use crate::util::memops::{load_u64_le, store_u64_le}; use crate::util::threefish::encrypt; -use dash_num::Hash512; - /// UBI type code for message blocks. pub(super) const TYPE_MSG: u64 = 48; /// UBI type code for output blocks. @@ -126,7 +124,7 @@ pub fn output_block(state: &mut Chaining) { ubi(state, &zero, tweak); } -pub fn hash512(data: &[u8]) -> Hash512 { +pub fn hash512(data: &[u8]) -> [u8; 64] { let mut state = IV; hash_message_blocks(&mut state, data); output_block(&mut state); @@ -137,5 +135,5 @@ pub fn hash512(data: &[u8]) -> Hash512 { store_u64_le(&mut out, index, state[index]); index += 1; } - out.into() + out } diff --git a/pkgs/pow/src/util/aes/cpu.rs b/pkgs/pow/src/util/aes/cpu.rs index 2aedf3f9..33ac5fd4 100644 --- a/pkgs/pow/src/util/aes/cpu.rs +++ b/pkgs/pow/src/util/aes/cpu.rs @@ -9,12 +9,9 @@ //! Hardware-accelerated on aarch64 with `aes_hw`, scalar T-table fallback //! otherwise. -cfg_if::cfg_if! { - if #[cfg(all(feature = "aes_hw", target_arch = "aarch64"))] { - #[cfg(test)] - pub(crate) use super::aarch64::round; - pub(crate) use super::aarch64::round_nk; - } else { - pub(crate) use super::scalar::{round, round_nk}; - } -} +#[cfg(all(feature = "aes_hw", target_arch = "aarch64", test))] +pub(crate) use super::aarch64::round; +#[cfg(all(feature = "aes_hw", target_arch = "aarch64"))] +pub(crate) use super::aarch64::round_nk; +#[cfg(not(all(feature = "aes_hw", target_arch = "aarch64")))] +pub(crate) use super::scalar::{round, round_nk}; diff --git a/pkgs/pow/src/util/mod.rs b/pkgs/pow/src/util/mod.rs index c6cb2e7a..90580e4d 100644 --- a/pkgs/pow/src/util/mod.rs +++ b/pkgs/pow/src/util/mod.rs @@ -25,7 +25,7 @@ pub(crate) const fn parse_hex(b: u8) -> u8 { } #[cfg(test)] -pub(crate) fn from_hex(s: &str) -> dash_num::Hash512 { +pub(crate) fn from_hex(s: &str) -> [u8; 64] { let s = s.strip_prefix("0x").or_else(|| s.strip_prefix("0X")).unwrap_or(s); assert_eq!(s.len(), 128, "expected 128 hex chars for a 512-bit digest"); let b = s.as_bytes(); @@ -35,13 +35,13 @@ pub(crate) fn from_hex(s: &str) -> dash_num::Hash512 { out[i] = (parse_hex(b[2 * i]) << 4) | parse_hex(b[2 * i + 1]); i += 1; } - dash_num::Hash512::from(out) + out } #[cfg(test)] -pub(crate) fn to_hex(digest: &dash_num::Hash512) -> [u8; 128] { +pub(crate) fn to_hex(digest: &[u8; 64]) -> [u8; 128] { const LUT: &[u8; 16] = b"0123456789abcdef"; - let b = digest.as_bytes(); + let b = digest; let mut out = [0u8; 128]; let mut i = 0; while i < 64 { diff --git a/pkgs/pow/src/worker.rs b/pkgs/pow/src/worker.rs deleted file mode 100644 index 7950ff18..00000000 --- a/pkgs/pow/src/worker.rs +++ /dev/null @@ -1,23 +0,0 @@ -// -// Copyright (c) 2026-present, The Dash Core developers -// SPDX-License-Identifier: MIT -// See the accompanying file LICENSE or https://opensource.org/license/MIT -// - -//! Parallel proof-of-work hashing. - -use crate::prelude::*; - -use dash_num::Hash256; -use rayon::prelude::*; - -/// Hash N inputs in parallel, returning one digest per input. -pub fn par_hash(inputs: &[&[u8]]) -> Vec { - inputs.par_iter().map(|data| crate::hash(data)).collect() -} - -/// Set the global thread pool size. Call once at startup. -/// Subsequent calls are silently ignored. -pub fn init(num_threads: usize) { - let _ = rayon::ThreadPoolBuilder::new().num_threads(num_threads).build_global(); -} diff --git a/pkgs/pow/tests/chain.rs b/pkgs/pow/tests/chain.rs index 84951cc4..9c097da2 100644 --- a/pkgs/pow/tests/chain.rs +++ b/pkgs/pow/tests/chain.rs @@ -6,7 +6,6 @@ //! Proof of work chained hash tests. -use dash_num::Hash256; use dash_pow::hash; use hex_literal::hex; use rstest::rstest; @@ -22,5 +21,5 @@ use rstest::rstest; )] fn known_hash(#[case] input: &[u8], #[case] expected: [u8; 32]) { let got = hash(input); - assert_eq!(got, Hash256::from(expected)); + assert_eq!(got, expected); } diff --git a/pkgs/pow/tests/common/mod.rs b/pkgs/pow/tests/common/mod.rs index 8e3f761d..75564c5a 100644 --- a/pkgs/pow/tests/common/mod.rs +++ b/pkgs/pow/tests/common/mod.rs @@ -31,11 +31,11 @@ pub fn load(name: &str) -> NistVectors { } /// Runs all NIST KAT vectors for a given hash function. -pub fn run_nist_kat(name: &str, vectors: &NistVectors, hash_fn: fn(&[u8]) -> dash_num::Hash512) { +pub fn run_nist_kat(name: &str, vectors: &NistVectors, hash_fn: fn(&[u8]) -> [u8; 64]) { for (byte_len, digest) in vectors.iter().enumerate() { let input = nist_input(byte_len); let expected: [u8; 64] = arr_from_hex(digest); let got = hash_fn(input); - assert_eq!(got.to_bytes(), expected, "{name}: mismatch at byte_len={byte_len}"); + assert_eq!(got, expected, "{name}: mismatch at byte_len={byte_len}"); } } diff --git a/pkgs/primitives/Cargo.toml b/pkgs/primitives/Cargo.toml index 47d377ee..4a11fc8e 100644 --- a/pkgs/primitives/Cargo.toml +++ b/pkgs/primitives/Cargo.toml @@ -14,7 +14,6 @@ std = [ "bitcoin-units/std", "dash-num/std", "dash-pkc/std", - "dash-pow/std", "dash-script/std", "dash-types/std", "hex-conservative/std", diff --git a/pkgs/primitives/src/block.rs b/pkgs/primitives/src/block.rs index 515a5b38..e21a99d3 100644 --- a/pkgs/primitives/src/block.rs +++ b/pkgs/primitives/src/block.rs @@ -14,7 +14,8 @@ use bitcoin_hashes::sha256d; use dash_num::{make_hash, Arith256, CompactTarget, Hash256}; use dash_pow::hash as pow_hash; use dash_types::codec::{BaseCodec, Checkable, Hashable}; -use dash_types::{ArrayBuf, TypeId, Unencodable}; +use dash_types::type_id::{TypeId, Unencodable}; +use dash_types::ArrayBuf; use core::fmt; diff --git a/pkgs/primitives/src/codec.rs b/pkgs/primitives/src/codec.rs index c4b1ee41..e9e69186 100644 --- a/pkgs/primitives/src/codec.rs +++ b/pkgs/primitives/src/codec.rs @@ -30,7 +30,12 @@ macro_rules! hash_impl { } const _: () = { - fn _assert() {} + fn _assert() + where + T: $crate::__private::dash_types::codec::BaseCodec, + T: $crate::__private::dash_types::type_id::TypeId, + { + } fn _check() { _assert::<$ty>(); } }; )* }; diff --git a/pkgs/primitives/src/gov.rs b/pkgs/primitives/src/gov.rs index 3126931b..ac683fd6 100644 --- a/pkgs/primitives/src/gov.rs +++ b/pkgs/primitives/src/gov.rs @@ -14,7 +14,8 @@ use bitcoin_hashes::sha256d; use bitcoin_units::Amount; use dash_num::Hash256; use dash_types::codec::{BaseCodec, Checkable, Hashable}; -use dash_types::{enum_map, impl_num, ArrayBuf, TypeId, Unencodable}; +use dash_types::type_id::{TypeId, Unencodable}; +use dash_types::{enum_map, impl_num, ArrayBuf}; use hex_conservative::DisplayHex; use core::fmt; diff --git a/pkgs/primitives/src/payload/assetlock.rs b/pkgs/primitives/src/payload/assetlock.rs index 9f5c9312..c9fbf125 100644 --- a/pkgs/primitives/src/payload/assetlock.rs +++ b/pkgs/primitives/src/payload/assetlock.rs @@ -12,7 +12,7 @@ use crate::transaction::TxOut; use dash_script::Recipient; use dash_types::codec::Checkable; -use dash_types::{TypeId, Unencodable}; +use dash_types::type_id::{TypeId, Unencodable}; use core::fmt; diff --git a/pkgs/primitives/src/payload/assetunlock.rs b/pkgs/primitives/src/payload/assetunlock.rs index 1ba89fc8..377466b1 100644 --- a/pkgs/primitives/src/payload/assetunlock.rs +++ b/pkgs/primitives/src/payload/assetunlock.rs @@ -11,7 +11,7 @@ use crate::codec::codec_payload; use dash_pkc::bls::{BlsScIetf, BlsSigBytes}; use dash_types::codec::Checkable; -use dash_types::{TypeId, Unencodable}; +use dash_types::type_id::{TypeId, Unencodable}; use core::fmt; diff --git a/pkgs/primitives/src/payload/cbtx.rs b/pkgs/primitives/src/payload/cbtx.rs index 9031406b..22843868 100644 --- a/pkgs/primitives/src/payload/cbtx.rs +++ b/pkgs/primitives/src/payload/cbtx.rs @@ -12,7 +12,8 @@ use crate::{hash_impl, MerkleRoot}; use bitcoin_units::BlockHeight; use dash_pkc::bls::{BlsScIetf, BlsSigBytes}; use dash_types::codec::{BaseCodec, Checkable, DecodeError, EncodeBuf}; -use dash_types::{CompactSize, TypeId, Unencodable}; +use dash_types::type_id::{TypeId, Unencodable}; +use dash_types::CompactSize; use core::fmt; diff --git a/pkgs/primitives/src/payload/mnhftx.rs b/pkgs/primitives/src/payload/mnhftx.rs index acd2b311..d7cb33b4 100644 --- a/pkgs/primitives/src/payload/mnhftx.rs +++ b/pkgs/primitives/src/payload/mnhftx.rs @@ -11,7 +11,7 @@ use crate::codec::codec_payload; use dash_pkc::bls::{BlsScIetf, BlsSigBytes}; use dash_types::codec::Checkable; -use dash_types::{TypeId, Unencodable}; +use dash_types::type_id::{TypeId, Unencodable}; use core::fmt; diff --git a/pkgs/primitives/src/payload/mod.rs b/pkgs/primitives/src/payload/mod.rs index 347e7a32..31f365c6 100644 --- a/pkgs/primitives/src/payload/mod.rs +++ b/pkgs/primitives/src/payload/mod.rs @@ -25,7 +25,8 @@ use crate::types::{NIError, NIPurpose, NITrait, NetInfoV2}; use dash_num::{make_hash, Hash256}; use dash_types::codec::Checkable; -use dash_types::{enum_map, impl_num, TypeId, Unencodable}; +use dash_types::type_id::{TypeId, Unencodable}; +use dash_types::{enum_map, impl_num}; use core::fmt; diff --git a/pkgs/primitives/src/payload/proregtx.rs b/pkgs/primitives/src/payload/proregtx.rs index 2194e7c3..ce124e70 100644 --- a/pkgs/primitives/src/payload/proregtx.rs +++ b/pkgs/primitives/src/payload/proregtx.rs @@ -19,7 +19,8 @@ use bitcoin_primitives::script::ScriptPubKeyBuf; use dash_pkc::bls::{BlsPkBytes, BlsScIetf}; use dash_script::{PubKeyHash, Recipient}; use dash_types::codec::{BaseCodec, Checkable, DecodeError, EncodeBuf, NumCodec}; -use dash_types::{make_bytes, TypeId}; +use dash_types::make_bytes; +use dash_types::type_id::TypeId; use core::fmt; diff --git a/pkgs/primitives/src/payload/proupregtx.rs b/pkgs/primitives/src/payload/proupregtx.rs index 6f3453ed..3f5326ee 100644 --- a/pkgs/primitives/src/payload/proupregtx.rs +++ b/pkgs/primitives/src/payload/proupregtx.rs @@ -15,7 +15,7 @@ use bitcoin_primitives::script::ScriptPubKeyBuf; use dash_pkc::bls::{BlsPkBytes, BlsScIetf}; use dash_script::{PubKeyHash, Recipient}; use dash_types::codec::Checkable; -use dash_types::TypeId; +use dash_types::type_id::TypeId; use core::fmt; diff --git a/pkgs/primitives/src/payload/prouprevtx.rs b/pkgs/primitives/src/payload/prouprevtx.rs index 97d4d3a6..ca699763 100644 --- a/pkgs/primitives/src/payload/prouprevtx.rs +++ b/pkgs/primitives/src/payload/prouprevtx.rs @@ -13,7 +13,7 @@ use crate::TxHash; use dash_pkc::bls::{BlsScIetf, BlsSigBytes}; use dash_types::codec::Checkable; -use dash_types::TypeId; +use dash_types::type_id::TypeId; use core::fmt; diff --git a/pkgs/primitives/src/payload/proupservtx.rs b/pkgs/primitives/src/payload/proupservtx.rs index 60c669f4..e0947622 100644 --- a/pkgs/primitives/src/payload/proupservtx.rs +++ b/pkgs/primitives/src/payload/proupservtx.rs @@ -15,7 +15,7 @@ use crate::{hash_impl, TxHash}; use bitcoin_primitives::script::ScriptPubKeyBuf; use dash_pkc::bls::{BlsScIetf, BlsSigBytes}; use dash_types::codec::{BaseCodec, Checkable, DecodeError, EncodeBuf, NumCodec}; -use dash_types::TypeId; +use dash_types::type_id::TypeId; use core::fmt; diff --git a/pkgs/primitives/src/payload/quorum.rs b/pkgs/primitives/src/payload/quorum.rs index fa7fe004..9be2d988 100644 --- a/pkgs/primitives/src/payload/quorum.rs +++ b/pkgs/primitives/src/payload/quorum.rs @@ -14,7 +14,7 @@ use crate::support::{DynBitset, LlmqType}; use dash_num::{make_hash, Hash256}; use dash_pkc::bls::{BlsPkBytes, BlsScIetf, BlsSigBytes}; use dash_types::codec::{BaseCodec, Checkable, DecodeError, EncodeBuf, NumCodec}; -use dash_types::{TypeId, Unencodable}; +use dash_types::type_id::{TypeId, Unencodable}; use core::fmt; diff --git a/pkgs/primitives/src/support.rs b/pkgs/primitives/src/support.rs index b363d864..93a14a3d 100644 --- a/pkgs/primitives/src/support.rs +++ b/pkgs/primitives/src/support.rs @@ -10,7 +10,8 @@ use crate::hash_impl; use crate::prelude::*; use dash_types::codec::{self, BaseCodec, DecodeError, EncodeBuf}; -use dash_types::{enum_map, impl_num, impl_type, CompactSize, TypeId, Unencodable}; +use dash_types::type_id::{TypeId, Unencodable}; +use dash_types::{enum_map, impl_num, impl_type, CompactSize}; enum_map! { /// LLMQ type (quorum size/threshold configuration). diff --git a/pkgs/primitives/src/transaction.rs b/pkgs/primitives/src/transaction.rs index 9063c7ba..ef01165b 100644 --- a/pkgs/primitives/src/transaction.rs +++ b/pkgs/primitives/src/transaction.rs @@ -16,7 +16,8 @@ use bitcoin_primitives::script::{ScriptPubKeyBuf, ScriptSigBuf}; use bitcoin_units::Amount; use dash_num::{make_hash, Hash256}; use dash_types::codec::{self, BaseCodec, Checkable, DecodeError, EncodeBuf, Hashable, NumCodec}; -use dash_types::{impl_type, CompactSize, TypeId, Unencodable}; +use dash_types::type_id::{TypeId, Unencodable}; +use dash_types::{impl_type, CompactSize}; use core::fmt; diff --git a/pkgs/primitives/src/types/addrv1.rs b/pkgs/primitives/src/types/addrv1.rs index 666aae9b..4b970310 100644 --- a/pkgs/primitives/src/types/addrv1.rs +++ b/pkgs/primitives/src/types/addrv1.rs @@ -11,7 +11,8 @@ use super::netaddr::{NetAddr, NetAddrError, NetworkType}; use crate::hash_impl; use dash_types::codec::{self, BaseCodec, Checkable, DecodeError, EncodeBuf}; -use dash_types::{impl_bytes, impl_type, type_cvrt, TypeId}; +use dash_types::type_id::TypeId; +use dash_types::{impl_bytes, impl_type, type_cvrt}; use core::fmt; use core::net::{Ipv4Addr, Ipv6Addr}; diff --git a/pkgs/primitives/src/types/addrv2.rs b/pkgs/primitives/src/types/addrv2.rs index 0291808b..628f2c62 100644 --- a/pkgs/primitives/src/types/addrv2.rs +++ b/pkgs/primitives/src/types/addrv2.rs @@ -14,7 +14,8 @@ use crate::prelude::*; use bitcoin_hashes::sha3_256; use dash_types::codec::{self, BaseCodec, Checkable, DecodeError, EncodeBuf, NumCodec}; -use dash_types::{impl_type, type_cvrt, CompactSize, TypeId}; +use dash_types::type_id::TypeId; +use dash_types::{impl_type, type_cvrt, CompactSize}; use core::fmt; use core::net::{Ipv4Addr, Ipv6Addr}; diff --git a/pkgs/primitives/src/types/netaddr.rs b/pkgs/primitives/src/types/netaddr.rs index ee68a02e..29b9b9c0 100644 --- a/pkgs/primitives/src/types/netaddr.rs +++ b/pkgs/primitives/src/types/netaddr.rs @@ -8,7 +8,8 @@ use crate::hash_impl; -use dash_types::{enum_map, impl_num, TypeId}; +use dash_types::type_id::TypeId; +use dash_types::{enum_map, impl_num}; use core::fmt; diff --git a/pkgs/primitives/src/types/netinfo.rs b/pkgs/primitives/src/types/netinfo.rs index a0bba220..1c9f85c2 100644 --- a/pkgs/primitives/src/types/netinfo.rs +++ b/pkgs/primitives/src/types/netinfo.rs @@ -12,7 +12,8 @@ use crate::hash_impl; use crate::prelude::*; use dash_types::codec::{self, BaseCodec, Checkable, DecodeError, EncodeBuf, NumCodec}; -use dash_types::{enum_map, impl_num, impl_type, CompactSize, TypeId, Unencodable}; +use dash_types::type_id::{TypeId, Unencodable}; +use dash_types::{enum_map, impl_num, impl_type, CompactSize}; use core::fmt; diff --git a/pkgs/script/Cargo.toml b/pkgs/script/Cargo.toml index 0615e0c0..37e550b1 100644 --- a/pkgs/script/Cargo.toml +++ b/pkgs/script/Cargo.toml @@ -19,9 +19,7 @@ serde = ["dep:serde", "dash-pkc/serde", "dash-types/serde"] base58ck = { workspace = true, features = ["alloc"] } bitcoin-consensus-encoding = { workspace = true, features = ["alloc"] } dash-num = { version = "0.0.0", path = "../num", default-features = false } -dash-pkc = { version = "0.0.0", path = "../pkc", default-features = false, features = [ - "ecdsa", -] } +dash-pkc = { version = "0.0.0", path = "../pkc", default-features = false } dash-types = { version = "0.0.0", path = "../types", default-features = false, features = [ "bitcoin-primitives", ] } diff --git a/pkgs/script/src/addrs.rs b/pkgs/script/src/addrs.rs index 15355a39..cd7da3fd 100644 --- a/pkgs/script/src/addrs.rs +++ b/pkgs/script/src/addrs.rs @@ -13,7 +13,8 @@ use base58ck::decode_check; use dash_num::Hash160; use dash_pkc::ecdsa::EcdsaPkBytes; use dash_types::codec::{BaseCodec, EncodeBuf, Hashable, NumCodec}; -use dash_types::{type_cvrt, Unencodable}; +use dash_types::type_cvrt; +use dash_types::type_id::Unencodable; /// Network address encoding parameters. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Unencodable)] diff --git a/pkgs/types/marker/src/lib.rs b/pkgs/types/marker/src/lib.rs index 1688493f..3179343d 100644 --- a/pkgs/types/marker/src/lib.rs +++ b/pkgs/types/marker/src/lib.rs @@ -8,7 +8,9 @@ use proc_macro::TokenStream; use quote::quote; -use syn::{parse_macro_input, DeriveInput}; +use syn::punctuated::Punctuated; +use syn::token::Plus; +use syn::{parse_macro_input, DeriveInput, Generics, Type, TypeParam, TypeParamBound, WherePredicate}; use xxhash_rust::xxh32::xxh32; /// Derives `__CodecMarker` for types that are not wire-encodable. @@ -22,29 +24,78 @@ pub fn derive_unencodable(input: TokenStream) -> TokenStream { let name = &input.ident; let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); - let expanded = quote! { - impl #impl_generics ::dash_types::codec::__CodecMarker for #name #ty_generics #where_clause {} - impl #impl_generics ::dash_types::codec::__UnencodableMarker for #name #ty_generics #where_clause {} - }; - - expanded.into() + let codec = quote!(::dash_types::codec); + quote! { + impl #impl_generics #codec::__CodecMarker for #name #ty_generics #where_clause {} + impl #impl_generics #codec::__UnencodableMarker for #name #ty_generics #where_clause {} + } + .into() } -/// Derives `TypeId` with a compile-time XXH32 hash of the type name. +/// Derives `TypeId` from the type name and its type parameters' own ids. +/// +/// Each parameter's `TYPE_ID` folds into the XXH32 of the bare name in +/// declaration order. Lifetimes are ignored; const parameters and openly +/// bounded ones are rejected, as neither yields an enumerable set of ids. #[proc_macro_derive(TypeId)] pub fn derive_type_id(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); let name = &input.ident; + + if let Some(param) = input.generics.const_params().next() { + let msg = "cannot derive TypeId on a type with const parameters, as its instantiations would share one id"; + return syn::Error::new_spanned(param, msg).to_compile_error().into(); + } + + for param in input.generics.type_params() { + if bound_names(param, &input.generics).iter().all(|b| b == "TypeId") { + let msg = "cannot derive TypeId on openly bounded type params; bound it with a marker trait"; + return syn::Error::new_spanned(param, msg).to_compile_error().into(); + } + } + let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); - let name_str = name.to_string(); - let id = xxh32(name_str.as_bytes(), 0); + let tid = quote!(::dash_types::type_id); + let params: Vec<_> = input.generics.type_params().map(|p| &p.ident).collect(); + let base = xxh32(name.to_string().as_bytes(), 0); + let id = params.iter().fold( + quote!(#base), + |acc, param| quote!(#tid::mix(#acc, <#param as #tid::TypeId>::TYPE_ID)), + ); + let kept = where_clause.into_iter().flat_map(|w| w.predicates.iter()); - let expanded = quote! { - impl #impl_generics ::dash_types::codec::TypeId for #name #ty_generics #where_clause { + quote! { + impl #impl_generics #tid::TypeId for #name #ty_generics + where #(#kept,)* #(#params: #tid::TypeId,)* { const TYPE_ID: u32 = #id; } - }; + } + .into() +} - expanded.into() +/// Collects the trait names bounding `param`, inline and in `where`. +fn bound_names(param: &TypeParam, generics: &Generics) -> Vec { + fn named(bounds: &Punctuated) -> Vec { + bounds + .iter() + .filter_map(|bound| match bound { + TypeParamBound::Trait(bound) => Some(bound.path.segments.last()?.ident.to_string()), + _ => None, + }) + .collect() + } + + let mut names = named(¶m.bounds); + for pred in generics.where_clause.iter().flat_map(|w| w.predicates.iter()) { + let WherePredicate::Type(pred) = pred else { + continue; + }; + if let Type::Path(ty) = &pred.bounded_ty { + if ty.qself.is_none() && ty.path.is_ident(¶m.ident) { + names.extend(named(&pred.bounds)); + } + } + } + names } diff --git a/pkgs/types/src/codec.rs b/pkgs/types/src/codec.rs index db2727a3..b5376f49 100644 --- a/pkgs/types/src/codec.rs +++ b/pkgs/types/src/codec.rs @@ -7,6 +7,7 @@ //! Codec traits and helpers. use crate::prelude::*; +use crate::type_id::TypeId; use crate::CompactSize; use core::convert::Infallible; @@ -185,11 +186,6 @@ pub trait NumCodec: Sized { fn to_base(&self) -> N; } -/// Stable per-type identifier derived from the type name. -pub trait TypeId { - const TYPE_ID: u32; -} - /// Cursor-based encode/decode for consensus wire types. pub trait BaseCodec: Sized { /// Decodes from the cursor, advancing it past consumed bytes. diff --git a/pkgs/types/src/entity.rs b/pkgs/types/src/entity.rs index 40359a86..b98b7952 100644 --- a/pkgs/types/src/entity.rs +++ b/pkgs/types/src/entity.rs @@ -340,7 +340,7 @@ macro_rules! make_bytes { $name:ident, $n:literal ) => { $(#[$attr])* - #[derive($crate::TypeId)] + #[derive($crate::type_id::TypeId)] pub struct $name(pub [u8; $n]); $crate::impl_bytes!($name, $n); diff --git a/pkgs/types/src/lib.rs b/pkgs/types/src/lib.rs index 9699b3b7..e1a02d86 100644 --- a/pkgs/types/src/lib.rs +++ b/pkgs/types/src/lib.rs @@ -26,9 +26,9 @@ mod uint; pub mod codec; #[cfg(feature = "serde")] pub mod serialize; +pub mod type_id; pub use compact::CompactSize; -pub use dash_types_marker::{TypeId, Unencodable}; pub use entity::{VecDecoder, VecEncoder, MAX_SER_SIZE}; pub use secret::{qtypestr, ArrDecoder, ArrEncoder, ArrayBuf, MAX_ARR_SIZE}; diff --git a/pkgs/types/src/type_id.rs b/pkgs/types/src/type_id.rs new file mode 100644 index 00000000..8c55079d --- /dev/null +++ b/pkgs/types/src/type_id.rs @@ -0,0 +1,104 @@ +// +// Copyright (c) 2026-present, The Dash Core developers +// SPDX-License-Identifier: MIT +// See the accompanying file LICENSE or https://opensource.org/license/MIT +// + +//! Stable type identifiers. + +// nosemgrep: use-pub-roots-only +pub use dash_types_marker::{TypeId, Unencodable}; + +/// Odd, so multiplying by it is a bijection over `u32` and no two +/// accumulators can collapse into one. The golden ratio constant. +const TYPE_ID_MIX_A: u32 = 0x9E37_79B1; + +/// Odd as well, and distinct from [`TYPE_ID_MIX_A`] so the two rounds of +/// multiplication do not compose into one. XXH32's second prime. +const TYPE_ID_MIX_B: u32 = 0x85EB_CA77; + +/// Stable identifier derived from the type name and its parameters. +pub trait TypeId { + const TYPE_ID: u32; +} + +/// Carries type parameters into an identifier. +/// +/// Rotating only the accumulator keeps the fold order-sensitive, so `Foo` +/// and `Foo` differ. +#[doc(hidden)] +#[must_use] +pub const fn mix(acc: u32, param: u32) -> u32 { + let mut h = acc.rotate_left(5).wrapping_add(TYPE_ID_MIX_A) ^ param.wrapping_mul(TYPE_ID_MIX_B); + h = h.wrapping_mul(TYPE_ID_MIX_A); + h ^= h >> 15; + h = h.wrapping_mul(TYPE_ID_MIX_B); + h ^= h >> 13; + h +} + +#[cfg(test)] +mod tests { + use super::{mix, TypeId}; + + use rstest::*; + + use core::marker::PhantomData; + + /// Pins mixing outputs given set of fixed inputs, wire-critical. + #[rstest] + #[case(0x0000_0000, 0x0000_0000, 0x2E23_CDE1)] + #[case(0x0000_0001, 0x0000_0000, 0x547E_AC0B)] + #[case(0x0000_0000, 0x0000_0001, 0x6B2D_FE60)] + #[case(0xDEAD_BEEF, 0x1234_5678, 0x1807_3B33)] + fn mix_is_pinned(#[case] acc: u32, #[case] param: u32, #[case] want: u32) { + assert_eq!(mix(acc, param), want); + } + + #[rstest] + #[case(1, 2)] + #[case(0xDEAD_BEEF, 0x1234_5678)] + fn mix_is_order_sensitive(#[case] a: u32, #[case] b: u32) { + assert_ne!(mix(a, b), mix(b, a)); + assert_ne!(mix(mix(0, a), b), mix(mix(0, b), a)); + } + + #[rstest] + #[case(0, 0)] + #[case(1, 2)] + #[case(0xDEAD_BEEF, 0x1234_5678)] + fn mix_moves_away_from_both_inputs(#[case] acc: u32, #[case] param: u32) { + let mixed = mix(acc, param); + assert_ne!(mixed, acc); + assert_ne!(mixed, param); + } + + #[derive(TypeId)] + struct MixA; + + #[derive(TypeId)] + struct MixB; + + trait MixMark {} + impl MixMark for MixA {} + impl MixMark for MixB {} + + #[derive(TypeId)] + struct MixPair(PhantomData<(X, Y)>); + + /// Bare names keep the XXH32 of stringized type name, mustn't be shifted. + #[rstest] + fn plain_derive_hashes_the_bare_name() { + assert_eq!(MixA::TYPE_ID, 0x8B87_3C41); + assert_eq!(MixB::TYPE_ID, 0x053E_1B33); + } + + /// Each instantiation gets its own id, sensitive to argument order. + #[rstest] + fn generic_derive_folds_the_type_parameters() { + assert_eq!(MixPair::::TYPE_ID, 0xEE0D_108A); + assert_eq!(MixPair::::TYPE_ID, 0x08C7_53E2); + assert_ne!(MixPair::::TYPE_ID, MixPair::::TYPE_ID); + assert_ne!(MixPair::::TYPE_ID, MixA::TYPE_ID); + } +} diff --git a/pkgs/types/src/uint.rs b/pkgs/types/src/uint.rs index edf8a1bd..d4ded221 100644 --- a/pkgs/types/src/uint.rs +++ b/pkgs/types/src/uint.rs @@ -73,7 +73,7 @@ macro_rules! make_num { $name:ident, $uint:tt, $n:literal ) => { $(#[$attr])* - #[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, $crate::TypeId)] + #[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, $crate::type_id::TypeId)] pub struct $name(pub $uint); impl $crate::codec::NumCodec<$uint> for $name {