From e512159feda0bbf609e73696e502bbf1b5658b19 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 5 Dec 2023 18:21:04 +0000 Subject: [PATCH 1/7] Set up CI Closes zcash/zip32#5. --- .github/dependabot.yml | 10 +++++ .github/workflows/ci.yml | 79 ++++++++++++++++++++++++++++++++++++++++ .gitignore | 1 - Cargo.lock | 60 ++++++++++++++++++++++++++++++ rust-toolchain.toml | 3 ++ src/lib.rs | 2 + 6 files changed, 154 insertions(+), 1 deletion(-) create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/ci.yml create mode 100644 Cargo.lock create mode 100644 rust-toolchain.toml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..a070231 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,10 @@ +version: 2 +updates: +- package-ecosystem: github-actions + directory: "/" + schedule: + interval: daily + timezone: Etc/UTC + open-pull-requests-limit: 10 + labels: + - "A-CI" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..60021df --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,79 @@ +name: CI checks + +on: [push, pull_request] + +jobs: + test: + name: Test on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macOS-latest] + steps: + - uses: actions/checkout@v4 + - name: Run tests + run: cargo test --all-features --verbose + - name: Verify working directory is clean + run: git diff --exit-code + + build-latest: + name: Latest build on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macOS-latest] + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + id: toolchain + - run: rustup override set ${{steps.toolchain.outputs.name}} + - name: Remove lockfile to build with latest dependencies + run: rm Cargo.lock + - name: Build crate + run: cargo build --all-targets --all-features --verbose + - name: Verify working directory is clean (excluding lockfile) + run: git diff --exit-code ':!Cargo.lock' + + build-nodefault: + name: Build target ${{ matrix.target }} + runs-on: ubuntu-latest + strategy: + matrix: + target: + - wasm32-wasi + steps: + - uses: actions/checkout@v4 + - name: Add target + run: rustup target add ${{ matrix.target }} + - name: Build crate + run: cargo build --no-default-features --verbose --target ${{ matrix.target }} + + clippy: + name: Clippy (MSRV) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Run Clippy + uses: auguwu/clippy-action@1.3.0 + with: + token: ${{ secrets.GITHUB_TOKEN }} + working-directory: ${{ inputs.target }} + deny: warnings + + doc-links: + name: Intra-doc links + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - run: cargo fetch + # Requires #![deny(rustdoc::broken_intra_doc_links)] in crate. + - name: Check intra-doc links + run: cargo doc --all-features --document-private-items + + fmt: + name: Rustfmt + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Check formatting + run: cargo fmt -- --check diff --git a/.gitignore b/.gitignore index 6936990..53eaa21 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ /target **/*.rs.bk -Cargo.lock diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..daaa55e --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,60 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "arrayref" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "assert_matches" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" + +[[package]] +name = "blake2b_simd" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c2f0dc9a68c6317d884f97cc36cf5a3d20ba14ce404227df55e1af708ab04bc" +dependencies = [ + "arrayref", + "arrayvec", + "constant_time_eq", +] + +[[package]] +name = "constant_time_eq" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21a53c0a4d288377e7415b53dcfc3c04da5cdc2cc95c8d5ac178b58f0b861ad6" + +[[package]] +name = "memuse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2145869435ace5ea6ea3d35f59be559317ec9a0d04e1812d5f185a87b6d36f1a" + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "zip32" +version = "0.0.0" +dependencies = [ + "assert_matches", + "blake2b_simd", + "memuse", + "subtle", +] diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..ce69938 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,3 @@ +[toolchain] +channel = "1.65.0" +components = ["clippy", "rustfmt"] diff --git a/src/lib.rs b/src/lib.rs index a130b6b..accc2f9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,8 @@ //! //! [ZIP 32]: https://zips.z.cash/zip-0032 +#![deny(rustdoc::broken_intra_doc_links)] + use memuse::{self, DynamicUsage}; use subtle::{Choice, ConditionallySelectable}; From feea7316ea165674e1c556458542a5ffb4a217c7 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 5 Dec 2023 18:22:49 +0000 Subject: [PATCH 2/7] Update crate metadata --- Cargo.toml | 6 +++--- src/lib.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index cdfbebb..4d5efaf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,10 +5,10 @@ authors = [ "Jack Grigg ", "Kris Nuttycombe ", ] -description = "Library for implementing shielded hierarchical deterministic wallets" +description = "Common types for implementing shielded hierarchical deterministic wallets" documentation = "https://docs.rs/zip32/" -homepage = "https://github.com/zcash-hackworks/zip32" -repository = "https://github.com/zcash-hackworks/zip32" +homepage = "https://github.com/zcash/zip32" +repository = "https://github.com/zcash/zip32" license = "MIT OR Apache-2.0" edition = "2021" rust-version = "1.65" diff --git a/src/lib.rs b/src/lib.rs index accc2f9..5e3357f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -//! Implementation of [ZIP 32] for hierarchical deterministic key management. +//! Common types for implementing [ZIP 32] for hierarchical deterministic key management. //! //! [ZIP 32]: https://zips.z.cash/zip-0032 From ea3e731868b10a9ffc67412b0d1f30cb1eb7140c Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 5 Dec 2023 18:30:28 +0000 Subject: [PATCH 3/7] Enforce documentation and no unsafe code --- src/fingerprint.rs | 17 ++++++++++------- src/lib.rs | 5 +++++ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/fingerprint.rs b/src/fingerprint.rs index 8c4cffb..e6acfeb 100644 --- a/src/fingerprint.rs +++ b/src/fingerprint.rs @@ -1,18 +1,21 @@ //! Seed Fingerprints according to ZIP 32 //! -//! Implements section `Seed Fingerprints` of Shielded Hierarchical Deterministic Wallets (ZIP 32) +//! Implements section [Seed Fingerprints] of Shielded Hierarchical Deterministic Wallets (ZIP 32). //! -//! [Section Seed Fingerprints]: https://zips.z.cash/zip-0032#seed-fingerprints +//! [Seed Fingerprints]: https://zips.z.cash/zip-0032#seed-fingerprints use blake2b_simd::Params as Blake2bParams; -pub const ZIP32_SEED_FP_PERSONALIZATION: &[u8; 16] = b"Zcash_HD_Seed_FP"; +const ZIP32_SEED_FP_PERSONALIZATION: &[u8; 16] = b"Zcash_HD_Seed_FP"; + +/// The fingerprint for a wallet's seed bytes, as defined in [ZIP 32]. +/// +/// [ZIP 32]: https://zips.z.cash/zip-0032#seed-fingerprints pub struct SeedFingerprint([u8; 32]); impl SeedFingerprint { - /// Return the seed fingerprint of the wallet as defined in - /// or None - /// if the length of `seed_bytes` is less than 32 or - /// greater than 252. + /// Derives the fingerprint of the given seed bytes. + /// + /// Returns `None` if the length of `seed_bytes` is less than 32 or greater than 252. pub fn from_seed(seed_bytes: &[u8]) -> Option { let seed_len = seed_bytes.len(); diff --git a/src/lib.rs b/src/lib.rs index 5e3357f..0dc5b44 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,8 @@ //! //! [ZIP 32]: https://zips.z.cash/zip-0032 +#![deny(missing_docs)] +#![deny(unsafe_code)] #![deny(rustdoc::broken_intra_doc_links)] use memuse::{self, DynamicUsage}; @@ -94,6 +96,7 @@ impl ChainCode { } } +/// The index for a particular diversifier. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct DiversifierIndex(pub [u8; 11]); @@ -128,10 +131,12 @@ impl TryFrom for u32 { } impl DiversifierIndex { + /// Constructs the zero index. pub fn new() -> Self { DiversifierIndex([0; 11]) } + /// Increments this index, failing on overflow. pub fn increment(&mut self) -> Result<(), ()> { for k in 0..11 { self.0[k] = self.0[k].wrapping_add(1); From ce3830f277fe1c80b98bd38d7f8e5e583051e03e Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 5 Dec 2023 18:32:11 +0000 Subject: [PATCH 4/7] Make crate no-std --- src/fingerprint.rs | 12 ++++++------ src/lib.rs | 3 ++- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/fingerprint.rs b/src/fingerprint.rs index e6acfeb..060731d 100644 --- a/src/fingerprint.rs +++ b/src/fingerprint.rs @@ -47,17 +47,17 @@ impl SeedFingerprint { #[test] fn test_seed_fingerprint() { struct TestVector { - root_seed: Vec, - fingerprint: Vec, + root_seed: [u8; 32], + fingerprint: [u8; 32], } - let test_vectors = vec![TestVector { - root_seed: vec![ + let test_vectors = [TestVector { + root_seed: [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, ], - fingerprint: vec![ + fingerprint: [ 0xde, 0xff, 0x60, 0x4c, 0x24, 0x67, 0x10, 0xf7, 0x17, 0x6d, 0xea, 0xd0, 0x2a, 0xa7, 0x46, 0xf2, 0xfd, 0x8d, 0x53, 0x89, 0xf7, 0x7, 0x25, 0x56, 0xdc, 0xb5, 0x55, 0xfd, 0xbe, 0x5e, 0x3a, 0xe3, @@ -71,7 +71,7 @@ fn test_seed_fingerprint() { } #[test] fn test_seed_fingerprint_is_none() { - let odd_seed = vec![ + let odd_seed = [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, ]; diff --git a/src/lib.rs b/src/lib.rs index 0dc5b44..8caca8f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,7 @@ //! //! [ZIP 32]: https://zips.z.cash/zip-0032 +#![no_std] #![deny(missing_docs)] #![deny(unsafe_code)] #![deny(rustdoc::broken_intra_doc_links)] @@ -121,7 +122,7 @@ impl From for DiversifierIndex { } impl TryFrom for u32 { - type Error = std::num::TryFromIntError; + type Error = core::num::TryFromIntError; fn try_from(di: DiversifierIndex) -> Result { let mut u128_bytes = [0u8; 16]; From 6a0c9639af6a49c4e35968bc1155d85d214a8790 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 5 Dec 2023 18:36:15 +0000 Subject: [PATCH 5/7] Lower MSRV to 1.60 Closes zcash/zip32#6. --- Cargo.toml | 2 +- rust-toolchain.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4d5efaf..3bc7e2f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ homepage = "https://github.com/zcash/zip32" repository = "https://github.com/zcash/zip32" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.65" +rust-version = "1.60" [dependencies] blake2b_simd = "1" diff --git a/rust-toolchain.toml b/rust-toolchain.toml index ce69938..47fd09e 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "1.65.0" +channel = "1.60.0" components = ["clippy", "rustfmt"] From 4365a10003f32e0dd934b362248fa31d0ac34d9c Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 5 Dec 2023 18:51:58 +0000 Subject: [PATCH 6/7] Fix intra-doc link --- src/lib.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 8caca8f..8253912 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -156,11 +156,9 @@ impl DiversifierIndex { /// A "scope" narrows the visibility or usage to a level below "full". /// /// Consistent usage of `Scope` enables the user to provide consistent views over a wallet -/// to other people. For example, a user can give an external [SaplingIvk] to a merchant -/// terminal, enabling it to only detect "real" transactions from customers and not -/// internal transactions from the wallet. -/// -/// [SaplingIvk]: crate::sapling::SaplingIvk +/// to other people. For example, a user can give an external incoming viewing key to a +/// merchant terminal, enabling it to only detect "real" transactions from customers and +/// not internal transactions from the wallet. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum Scope { /// A scope used for wallet-external operations, namely deriving addresses to give to From ceb970c211fd5d0b4556221e2d57c4e1944d435a Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 5 Dec 2023 19:03:43 +0000 Subject: [PATCH 7/7] Fix clippy lint --- Cargo.toml | 4 ++++ src/lib.rs | 20 ++++++++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3bc7e2f..e4cc027 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,3 +20,7 @@ subtle = "2.2.3" [dev-dependencies] assert_matches = "1.5" + +[features] +default = ["std"] +std = [] diff --git a/src/lib.rs b/src/lib.rs index 8253912..7cf2626 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,6 +7,9 @@ #![deny(unsafe_code)] #![deny(rustdoc::broken_intra_doc_links)] +#[cfg(feature = "std")] +extern crate std; + use memuse::{self, DynamicUsage}; use subtle::{Choice, ConditionallySelectable}; @@ -138,7 +141,7 @@ impl DiversifierIndex { } /// Increments this index, failing on overflow. - pub fn increment(&mut self) -> Result<(), ()> { + pub fn increment(&mut self) -> Result<(), DiversifierIndexOverflowError> { for k in 0..11 { self.0[k] = self.0[k].wrapping_add(1); if self.0[k] != 0 { @@ -147,10 +150,23 @@ impl DiversifierIndex { } } // Overflow - Err(()) + Err(DiversifierIndexOverflowError) } } +/// The error type returned when a [`DiversifierIndex`] increment fails. +#[derive(Clone, Copy, Debug)] +pub struct DiversifierIndexOverflowError; + +impl core::fmt::Display for DiversifierIndexOverflowError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "DiversifierIndex increment overflowed") + } +} + +#[cfg(feature = "std")] +impl std::error::Error for DiversifierIndexOverflowError {} + /// The scope of a viewing key or address. /// /// A "scope" narrows the visibility or usage to a level below "full".