├── .deepsource.toml
├── .github
├── CODE-OF-CONDUCT.md
├── CODEOWNERS
├── SECURITY.md
├── dependabot.yml
├── funding.yml
└── workflows
│ ├── audit.yml
│ ├── check.yml
│ ├── coverage.yml
│ ├── document.yml
│ ├── lint.yml
│ ├── release.yml
│ └── test.yml
├── .gitignore
├── AUTHORS.md
├── CONTRIBUTING.md
├── Cargo.lock
├── Cargo.toml
├── LICENSE-APACHE
├── LICENSE-MIT
├── README.md
├── TEMPLATE.md
├── benches
└── criterion.rs
├── build.rs
├── deny.toml
├── examples
└── hsh.rs
├── rustfmt.toml
├── src
├── algorithms
│ ├── argon2i.rs
│ ├── bcrypt.rs
│ ├── mod.rs
│ └── scrypt.rs
├── lib.rs
├── macros.rs
├── main.rs
└── models
│ ├── hash.rs
│ ├── hash_algorithm.rs
│ └── mod.rs
└── tests
├── test_argon2i.rs
├── test_bcrypt.rs
├── test_hash.rs
├── test_hash_algorithm.rs
├── test_lib.rs
├── test_macros.rs
├── test_main.rs
└── test_scrypt.rs
/.deepsource.toml:
--------------------------------------------------------------------------------
1 | version = 1
2 |
3 | [[analyzers]]
4 | name = "rust"
5 | enabled = true
6 |
7 | [analyzers.meta]
8 | msrv = "stable"
--------------------------------------------------------------------------------
/.github/CODE-OF-CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our
7 | project and our community a harassment-free experience for everyone,
8 | regardless of age, body size, disability, ethnicity, gender identity and
9 | expression, level of experience, nationality, personal appearance, race,
10 | religion, or sexual identity and orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behaviour that contributes to creating a positive
15 | environment include:
16 |
17 | - Using welcoming and inclusive language
18 | - Being respectful of differing viewpoints and experiences
19 | - Gracefully accepting constructive criticism
20 | - Focusing on what is best for the community
21 | - Showing empathy towards other community members
22 |
23 | Examples of unacceptable behaviour by participants include:
24 |
25 | - The use of sexualized language or imagery and unwelcome sexual
26 | attention or advances
27 | - Trolling, insulting/derogatory comments, and personal or political
28 | attacks
29 | - Public or private harassment
30 | - Publishing others' private information, such as a physical or
31 | electronic address, without explicit permission
32 | - Other conduct which could reasonably be considered inappropriate in a
33 | professional setting
34 |
35 | ## Our Responsibilities
36 |
37 | Project maintainers are responsible for clarifying the standards of
38 | acceptable behaviour and are expected to take appropriate and fair
39 | corrective action in response to any instances of unacceptable
40 | behaviour.
41 |
42 | Project maintainers have the right and responsibility to remove, edit,
43 | or reject comments, commits, code, wiki edits, issues, and other
44 | contributions that are not aligned to this Code of Conduct, or to ban
45 | temporarily or permanently any contributor for other behaviors that they
46 | deem inappropriate, threatening, offensive, or harmful.
47 |
48 | ## Scope
49 |
50 | This Code of Conduct applies both within project spaces and in public
51 | spaces when an individual is representing the project or its community.
52 | Examples of representing a project or community include using an
53 | official project e-mail address, posting via an official social media
54 | account, or acting as an appointed representative at an online or
55 | offline event. Representation of a project may be further defined and
56 | clarified by project maintainers.
57 |
58 | ## Enforcement
59 |
60 | Instances of abusive, harassing, or otherwise unacceptable behaviour may
61 | be reported by contacting the project team. The project team will review
62 | and investigate all complaints, and will respond in a way that it deems
63 | appropriate to the circumstances. The project team is obligated to
64 | maintain confidentiality with regard to the reporter of an incident.
65 | Further details of specific enforcement policies may be posted
66 | separately.
67 |
68 | Project maintainers who do not follow or enforce the Code of Conduct in
69 | good faith may face temporary or permanent repercussions as determined
70 | by other members of the project's leadership.
71 |
72 | ## Attribution
73 |
74 | This Code of Conduct is adapted from the Contributor Covenant homepage,
75 | version 1.4, available at
76 | [version](http://contributor-covenant.org/version/1/4)
77 |
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | @sebastienrousseau/hsh
--------------------------------------------------------------------------------
/.github/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Security
2 |
3 | We take the security of our software products and services seriously,
4 | which includes all source code repositories managed through our GitHub
5 | repositories.
6 |
7 | If you believe you have found a security vulnerability in any of our
8 | repository, please report it to us as described below.
9 |
10 | ## Reporting Security Issues
11 |
12 | Please include the requested information listed below (as much as you
13 | can provide) to help us better understand the nature and scope of the
14 | possible issue:
15 |
16 | - Type of issue (e.g. buffer overflow, SQL injection, cross-site
17 | scripting, etc.)
18 | - Full paths of source file(s) related to the manifestation of the issue
19 | - The location of the affected source code (tag/branch/commit or direct
20 | URL)
21 | - Any special configuration required to reproduce the issue
22 | - Step-by-step instructions to reproduce the issue
23 | - Proof-of-concept or exploit code (if possible)
24 | - Impact of the issue, including how an attacker might exploit the issue
25 |
26 | This information will help us triage your report more quickly.
27 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "cargo"
4 | directory: "/"
5 | schedule:
6 | interval: "daily"
7 |
8 | - package-ecosystem: "github-actions"
9 | directory: "/"
10 | schedule:
11 | interval: "daily"
12 |
--------------------------------------------------------------------------------
/.github/funding.yml:
--------------------------------------------------------------------------------
1 | github: sebastienrousseau
2 | custom: https://paypal.me/wwdseb
3 |
--------------------------------------------------------------------------------
/.github/workflows/audit.yml:
--------------------------------------------------------------------------------
1 | name: 🧪 Audit
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | - feat/hsh
8 | pull_request:
9 | branches:
10 | - feat/hsh
11 | release:
12 | types: [created]
13 |
14 | jobs:
15 | dependencies:
16 | name: Audit dependencies
17 | runs-on: ubuntu-latest
18 | steps:
19 | - uses: hecrj/setup-rust-action@v2
20 | - name: Install cargo-audit
21 | run: cargo install cargo-audit
22 |
23 | - uses: actions/checkout@v4
24 | - name: Resolve dependencies
25 | run: cargo update
26 |
27 | - name: Audit vulnerabilities
28 | run: cargo audit
--------------------------------------------------------------------------------
/.github/workflows/check.yml:
--------------------------------------------------------------------------------
1 | name: 🧪 Check
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | - feat/hsh
8 | pull_request:
9 | branches:
10 | - feat/hsh
11 | release:
12 | types: [created]
13 |
14 | jobs:
15 | all:
16 | name: Check
17 | runs-on: ubuntu-latest
18 | steps:
19 | - uses: hecrj/setup-rust-action@v2
20 | with:
21 | components: clippy
22 | - uses: actions/checkout@v4
23 | - name: Check lints
24 | run: cargo check --all-targets --workspace --all-features
--------------------------------------------------------------------------------
/.github/workflows/coverage.yml:
--------------------------------------------------------------------------------
1 | name: 📶 Coverage
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | pull_request:
8 |
9 | env:
10 | CARGO_TERM_COLOR: always
11 |
12 | jobs:
13 | coverage:
14 | name: Code Coverage
15 | runs-on: ubuntu-latest
16 | env:
17 | CARGO_INCREMENTAL: "0"
18 | RUSTFLAGS: "-Zprofile -Ccodegen-units=1 -Cinline-threshold=0 -Clink-dead-code -Coverflow-checks=off -Cpanic=abort -Zpanic_abort_tests"
19 | RUSTDOCFLAGS: "-Zprofile -Ccodegen-units=1 -Cinline-threshold=0 -Clink-dead-code -Coverflow-checks=off -Cpanic=abort -Zpanic_abort_tests"
20 |
21 | steps:
22 | # Checkout the repository
23 | - name: Checkout repository
24 | uses: actions/checkout@v4
25 |
26 | # Setup Rust nightly
27 | - name: Install Rust
28 | uses: actions-rs/toolchain@v1
29 | id: toolchain
30 | with:
31 | toolchain: nightly
32 | override: true
33 |
34 | # Configure cache for Cargo
35 | - name: Cache Cargo registry, index
36 | uses: actions/cache@v4
37 | id: cache-cargo
38 | with:
39 | path: |
40 | ~/.cargo/registry
41 | ~/.cargo/bin
42 | ~/.cargo/git
43 | key: linux-${{ steps.toolchain.outputs.rustc_hash }}-rust-cov-${{ hashFiles('**/Cargo.lock') }}
44 |
45 | # Run tests with all features
46 | - name: Test (cargo test)
47 | uses: actions-rs/cargo@v1
48 | with:
49 | command: test
50 | args: "--workspace"
51 |
52 | # Install grcov
53 | - uses: actions-rs/grcov@v0.1
54 | id: coverage
55 |
56 | # Upload to Codecov.io
57 | - name: Upload to Codecov.io
58 | uses: codecov/codecov-action@v5
59 | with:
60 | token: ${{ secrets.CODECOV_TOKEN }}
61 | file: ${{ steps.coverage.outputs.report }}
--------------------------------------------------------------------------------
/.github/workflows/document.yml:
--------------------------------------------------------------------------------
1 | name: 🧪 Document
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | pull_request:
8 | branches:
9 | - main
10 | release:
11 | types: [created]
12 |
13 | jobs:
14 | all:
15 | name: Document
16 | if: github.ref == 'refs/heads/main' && github.event_name == 'push'
17 | runs-on: ubuntu-latest
18 | concurrency:
19 | group: ${{ github.workflow }}-${{ github.ref }}
20 | steps:
21 | - uses: hecrj/setup-rust-action@v2
22 | with:
23 | rust-version: nightly
24 |
25 | - uses: actions/checkout@v4
26 |
27 | - name: Update libssl
28 | run: |
29 | sudo apt-get update
30 | sudo apt-get install -y libssl1.1
31 |
32 | - name: Generate documentation for all features and publish it
33 | run: |
34 | RUSTDOCFLAGS="--cfg docsrs" \
35 | cargo doc --no-deps --all-features --workspace
36 | # Write index.html with redirect
37 | echo '
' > ./target/doc/index.html
38 |
39 | - name: Deploy
40 | uses: actions/upload-artifact@v4
41 | with:
42 | name: documentation
43 | path: target/doc
44 | if-no-files-found: error
45 | retention-days: 1
46 |
47 | - name: Write CNAME file
48 | run: echo 'doc.hshlib.com' > ./target/doc/CNAME
49 |
50 | - name: Deploy to GitHub Pages
51 | uses: peaceiris/actions-gh-pages@v4
52 | with:
53 | cname: true
54 | commit_message: Deploy documentation at ${{ github.sha }}
55 | github_token: ${{ secrets.GITHUB_TOKEN }}
56 | publish_branch: gh-pages
57 | publish_dir: ./target/doc
58 | user_email: actions@users.noreply.github.com
59 | user_name: github-actions
--------------------------------------------------------------------------------
/.github/workflows/lint.yml:
--------------------------------------------------------------------------------
1 | name: 🧪 Lint
2 |
3 | on:
4 | push:
5 | branches:
6 | - feat/hsh
7 | pull_request:
8 | branches:
9 | - feat/hsh
10 | release:
11 | types: [created]
12 |
13 | jobs:
14 | all:
15 | name: Lint
16 | runs-on: ubuntu-latest
17 | steps:
18 | - uses: hecrj/setup-rust-action@v2
19 | with:
20 | components: clippy
21 | - uses: actions/checkout@v4
22 | - name: Check lints
23 | run: cargo clippy --workspace --all-features --all-targets --no-deps -- -D warnings
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: 🧪 Release
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | - feat/hsh
8 | pull_request:
9 | branches:
10 | - feat/hsh
11 | release:
12 | types: [created]
13 |
14 | concurrency:
15 | group: ${{ github.ref }}
16 | cancel-in-progress: true
17 |
18 | jobs:
19 | # Build the project for all the targets and generate artifacts.
20 | build:
21 | # This job builds the project for all the targets and generates a
22 | # release artifact that contains the binaries for all the targets.
23 | name: ❯ Build 🛠
24 |
25 | # Only run this job on the main branch when a commit is pushed.
26 | if: github.ref == 'refs/heads/main' && github.event_name == 'push'
27 |
28 | # Set up the job environment variables.
29 | env:
30 | BUILD_ID: ${{ github.run_id }}
31 | CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_API_TOKEN }}
32 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
33 | OS: ${{ matrix.platform.os }}
34 | TARGET: ${{ matrix.platform.target }}
35 |
36 | strategy:
37 | fail-fast: false
38 | matrix:
39 | platform:
40 | - target: x86_64-pc-windows-msvc
41 | os: windows-latest
42 | - target: aarch64-pc-windows-msvc
43 | os: windows-latest
44 | - target: x86_64-apple-darwin
45 | os: macos-latest
46 | - target: aarch64-apple-darwin
47 | os: macos-latest
48 | - target: x86_64-unknown-linux-gnu
49 | os: ubuntu-latest
50 |
51 | runs-on: ${{ matrix.platform.os }}
52 |
53 | steps:
54 | # Check out the repository code.
55 | - name: Checkout sources
56 | id: checkout
57 | uses: actions/checkout@v4
58 |
59 | # Install the stable Rust toolchain.
60 | - name: Install stable toolchain
61 | id: install-toolchain
62 | uses: actions-rs/toolchain@v1
63 | with:
64 | toolchain: stable
65 | override: true
66 |
67 | # Cache dependencies to speed up subsequent builds.
68 | - name: Cache dependencies
69 | id: cache-dependencies
70 | uses: actions/cache@v4
71 | with:
72 | path: ~/.cargo
73 | key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
74 | restore-keys: ${{ runner.os }}-cargo-
75 |
76 | # Install the targets for the cross-compilation toolchain
77 | - name: Install target
78 | id: install-target
79 | run: rustup target add ${{ env.TARGET }}
80 |
81 | # Build the targets
82 | - name: Build targets
83 | id: build-targets
84 | uses: actions-rs/cargo@v1
85 | with:
86 | command: build
87 | args: --verbose --workspace --release --target ${{ env.TARGET }}
88 |
89 | # Package the binary for each target
90 | - name: Package the binary
91 | id: package-binary
92 | run: |
93 | mkdir -p target/package
94 | tar czf target/package/${{ env.TARGET }}.tar.gz -C target/${{ env.TARGET }}/release .
95 | echo "${{ env.TARGET }}.tar.gz=target/package/${{ env.TARGET }}.tar.gz" >> $GITHUB_ENV
96 |
97 | # Upload the binary for each target
98 | - name: Upload the binary
99 | id: upload-binary
100 | uses: actions/upload-artifact@v4
101 | with:
102 | name: ${{ env.TARGET }}.tar.gz
103 | path: target/package/${{ env.TARGET }}.tar.gz
104 |
105 | # Release the binary to GitHub Releases
106 | release:
107 | name: ❯ Release 🚀
108 | if: github.ref == 'refs/heads/main' && github.event_name == 'push'
109 | needs: build
110 | runs-on: ubuntu-latest
111 | steps:
112 | # Check out the repository code
113 | - name: Checkout sources
114 | uses: actions/checkout@v4
115 |
116 | # Install the stable Rust toolchain
117 | - name: Install stable toolchain
118 | uses: actions-rs/toolchain@v1
119 | with:
120 | toolchain: stable
121 | override: true
122 |
123 | # Update the version number based on the Cargo.toml file
124 | - name: Update version number
125 | run: |
126 | NEW_VERSION=$(grep version Cargo.toml | sed -n 2p | cut -d '"' -f 2)
127 | echo "VERSION=$NEW_VERSION" >> "$GITHUB_ENV"
128 | shell: /bin/bash -e {0}
129 |
130 | # Cache dependencies to speed up subsequent builds
131 | - name: Cache dependencies
132 | uses: actions/cache@v4
133 | with:
134 | path: ~/.cargo
135 | key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
136 | restore-keys: ${{ runner.os }}-cargo-
137 |
138 | # Download the artifacts from the build job
139 | - name: Download artifacts
140 | run: |
141 | for target in ${{ env.TARGET }}; do
142 | echo "Downloading $target artifact"
143 | name="${target}.tar.gz"
144 | echo "Artifact name: $name"
145 | mkdir -p target/package
146 | curl -sSL -H "Authorization: token ${GITHUB_TOKEN}" -H "Accept: application/vnd.github.v3+json" -L "${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/actions/runs/${BUILD_ID}/artifacts/${name}" -o "target/package/${name}"
147 | done
148 |
149 | env:
150 | VERSION: ${{ env.VERSION }}
151 | TARGET: ${{ env.TARGET }}
152 | OS: ${{ env.OS }}
153 |
154 | # Generate the changelog based on the git log
155 | - name: Generate Changelog
156 | id: generate-changelog
157 | env:
158 | BUILD_ID: ${{ github.run_id }}
159 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
160 | RELEASE_URL: https://github.com/sebastienrousseau/hsh/releases
161 | TARGET: ${{ env.TARGET }}
162 |
163 | run: |
164 | if [[ ! -f CHANGELOG.md ]]; then
165 | # Set path to changelog file
166 | changelog_file="${{ github.workspace }}/CHANGELOG.md"
167 |
168 | # Get version from Cargo.toml
169 | version=$(grep version Cargo.toml | sed -n 2p | cut -d '"' -f 2)
170 |
171 | # Append version information to changelog
172 | echo "## Release v${version} - $(date +'%Y-%m-%d')" >> "${changelog_file}"
173 |
174 | # Copy content of template file to changelog
175 | cat TEMPLATE.md >> "${changelog_file}"
176 |
177 | # Append git log to changelog
178 | echo "$(git log --pretty=format:'%s' --reverse HEAD)" >> "${changelog_file}"
179 |
180 | # Append empty line to changelog
181 | echo "" >> "${changelog_file}"
182 |
183 | fi
184 | shell: bash
185 |
186 | # Create the release on GitHub releases
187 | - name: Create Release
188 | id: create-release
189 | uses: actions/create-release@v1
190 | env:
191 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
192 | VERSION: ${{ env.VERSION }}
193 | with:
194 | tag_name: v${{ env.VERSION }}
195 | release_name: Hash (HSH) 🦀 v${{ env.VERSION }}
196 | body_path: ${{ github.workspace }}/CHANGELOG.md
197 | draft: true
198 | prerelease: false
199 |
200 | # Publish the release to Crates.io automatically
201 | crate:
202 | name: ❯ Crate.io 🦀
203 | if: github.ref == 'refs/heads/main' && github.event_name == 'push'
204 | needs: release
205 | runs-on: ubuntu-latest
206 |
207 | steps:
208 | # Check out the repository code
209 | - name: Checkout
210 | uses: actions/checkout@v4
211 |
212 | # Install the stable Rust toolchain
213 | - name: Install stable toolchain
214 | id: install-toolchain
215 | uses: actions-rs/toolchain@v1
216 | with:
217 | toolchain: stable
218 | override: true
219 |
220 | # Cache dependencies to speed up subsequent builds
221 | - name: Cache dependencies
222 | id: cache-dependencies
223 | uses: actions/cache@v4
224 | with:
225 | path: /home/runner/.cargo/registry/index/
226 | key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }}
227 | restore-keys: ${{ runner.os }}-cargo-index-
228 |
229 | # Update the version number based on the Cargo.toml file
230 | - name: Update version number
231 | id: update-version
232 | run: |
233 | NEW_VERSION=$(grep version Cargo.toml | sed -n 2p | cut -d '"' -f 2)
234 | echo "VERSION=$NEW_VERSION" >> "$GITHUB_ENV"
235 | shell: /bin/bash -e {0}
236 |
237 | # Log in to crates.io
238 | - name: Log in to crates.io
239 | id: login-crate-io
240 | run: cargo login ${{ secrets.CARGO_API_TOKEN }}
241 |
242 | # Publish the Rust library to Crate.io
243 | - name: Publish Library to Crate.io
244 | id: publish-library
245 | uses: actions-rs/cargo@v1
246 | env:
247 | CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_API_TOKEN }}
248 | with:
249 | command: publish
250 | args: "--no-verify --allow-dirty"
251 | use-cross: false
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: 🧪 Test
2 |
3 | on: [pull_request, push]
4 | jobs:
5 | test-lib:
6 | name: Test library
7 | runs-on: ubuntu-latest
8 | strategy:
9 | matrix:
10 | os: [ubuntu-latest]
11 | toolchain: [stable, nightly]
12 | continue-on-error: true
13 |
14 | steps:
15 | # Checkout the repository
16 | - name: Checkout repository
17 | uses: actions/checkout@v4
18 |
19 | # Setup Rust
20 | - name: Setup Rust
21 | run: |
22 | rustup toolchain add ${{ matrix.toolchain }} --component llvm-tools-preview
23 | rustup override set ${{ matrix.toolchain }}
24 |
25 | # Configure cache
26 | - name: Configure cache
27 | uses: actions/cache@v4
28 | with:
29 | path: |
30 | ~/.cargo/bin/
31 | ~/.cargo/registry/index/
32 | ~/.cargo/registry/cache/
33 | ~/.cargo/git/db/
34 | target/
35 | key: test-${{ runner.os }}-cargo-${{ matrix.toolchain }}-${{ hashFiles('**/Cargo.lock') }}
36 |
37 | # Run tests with all features
38 | - name: Run tests with all features
39 | id: run-tests-all-features
40 | run: cargo test --verbose --workspace --all-features
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.DS_Store
2 | *.profraw
3 | /.vscode/
4 | /output/
5 | /public/
6 | /target/
7 | build
8 | Icon?
9 | src/.DS_Store
10 | tarpaulin-report.html
11 | Cargo.lock
--------------------------------------------------------------------------------
/AUTHORS.md:
--------------------------------------------------------------------------------
1 | # Authors
2 |
3 | * [Sebastien Rousseau](mailto:sebastian.rousseau@gmail.com) (Original Contributor)
4 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to `Hash (HSH)`
2 |
3 | Welcome! We're thrilled that you're interested in contributing to the `Hash (HSH)` library. Whether you're looking to evangelize, submit feedback, or contribute code, we appreciate your involvement in making `Hash (HSH)` a better tool for everyone. Here's how you can get started.
4 |
5 | ## Evangelize
6 |
7 | One of the simplest ways to help us out is by spreading the word about Hash (HSH). We believe that a bigger, more involved community makes for a better framework, and that better frameworks make the world a better place. If you know people who might benefit from using Hash (HSH), please let them know!
8 |
9 | ## How to Contribute
10 |
11 | If you're interested in making a more direct contribution, there are several ways you can help us improve Hash (HSH). Here are some guidelines for submitting feedback, bug reports, and code contributions.
12 |
13 | ### Feedback
14 |
15 | Your feedback is incredibly valuable to us, and we're always looking for ways to make Hash (HSH) better. If you have ideas, suggestions, or questions about Hash (HSH), we'd love to hear them. Here's how you can provide feedback:
16 |
17 | - Click [here][2] to submit a new feedback.
18 | - Use a descriptive title that clearly summarizes your feedback.
19 | - Provide a detailed description of the issue or suggestion.
20 | - Be patient while we review and respond to your feedback.
21 |
22 | ### Bug Reports
23 |
24 | If you encounter a bug while using Hash (HSH), please let us know so we can fix it. Here's how you can submit a bug report:
25 |
26 | - Click [here][2] to submit a new issue.
27 | - Use a descriptive title that clearly summarizes the bug.
28 | - Provide a detailed description of the issue, including steps to reproduce it.
29 | - Be patient while we review and respond to your bug report.
30 |
31 | ### Code Contributions
32 |
33 | If you're interested in contributing code to Hash (HSH), we're excited to have your help! Here's what you need to know:
34 |
35 | #### Feature Requests
36 |
37 | If you have an idea for a new feature or improvement, we'd love to hear it. Here's how you can contribute code for a new feature to Hash (HSH):
38 |
39 | - Fork the repo.
40 | - Clone the Hash [HSH](1) repo by running:
41 | `git clone {repository}`
42 | - Edit files in the `src/` folder. The `src/` folder contains the source code for Hash (HSH).
43 | - Submit a pull request, and we'll review and merge your changes if they fit with our vision for Hash (HSH).
44 |
45 | #### Submitting Code
46 |
47 | If you've identified a bug or have a specific code improvement in mind, we welcome your pull requests. Here's how to submit your code changes:
48 |
49 | - Fork the repo.
50 | - Clone the Hash (HSH) repo by running:
51 | `git clone {repository}`
52 | - Edit files in the `src/` folder. The `src/` folder contains the source code for Hash (HSH).
53 | - Submit a pull request, and we'll review and merge your changes if they fit with our vision for Hash (HSH).
54 |
55 | We hope that this guide has been helpful in explaining how you can contribute to Hash (HSH). Thank you for your interest and involvement in our project!
56 |
57 | [2]: https://github.com/sebastienrousseau/dtt/issues/new
58 |
--------------------------------------------------------------------------------
/Cargo.lock:
--------------------------------------------------------------------------------
1 | # This file is automatically @generated by Cargo.
2 | # It is not intended for manual editing.
3 | version = 3
4 |
5 | [[package]]
6 | name = "addr2line"
7 | version = "0.21.0"
8 | source = "registry+https://github.com/rust-lang/crates.io-index"
9 | checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
10 | dependencies = [
11 | "gimli",
12 | ]
13 |
14 | [[package]]
15 | name = "adler"
16 | version = "1.0.2"
17 | source = "registry+https://github.com/rust-lang/crates.io-index"
18 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
19 |
20 | [[package]]
21 | name = "aho-corasick"
22 | version = "1.1.3"
23 | source = "registry+https://github.com/rust-lang/crates.io-index"
24 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
25 | dependencies = [
26 | "memchr",
27 | ]
28 |
29 | [[package]]
30 | name = "anes"
31 | version = "0.1.6"
32 | source = "registry+https://github.com/rust-lang/crates.io-index"
33 | checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
34 |
35 | [[package]]
36 | name = "anstyle"
37 | version = "1.0.7"
38 | source = "registry+https://github.com/rust-lang/crates.io-index"
39 | checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b"
40 |
41 | [[package]]
42 | name = "argon2rs"
43 | version = "0.2.5"
44 | source = "registry+https://github.com/rust-lang/crates.io-index"
45 | checksum = "3f67b0b6a86dae6e67ff4ca2b6201396074996379fba2b92ff649126f37cb392"
46 | dependencies = [
47 | "blake2-rfc",
48 | "scoped_threadpool",
49 | ]
50 |
51 | [[package]]
52 | name = "arrayvec"
53 | version = "0.4.12"
54 | source = "registry+https://github.com/rust-lang/crates.io-index"
55 | checksum = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9"
56 | dependencies = [
57 | "nodrop",
58 | ]
59 |
60 | [[package]]
61 | name = "assert_cmd"
62 | version = "2.0.14"
63 | source = "registry+https://github.com/rust-lang/crates.io-index"
64 | checksum = "ed72493ac66d5804837f480ab3766c72bdfab91a65e565fc54fa9e42db0073a8"
65 | dependencies = [
66 | "anstyle",
67 | "bstr",
68 | "doc-comment",
69 | "predicates",
70 | "predicates-core",
71 | "predicates-tree",
72 | "wait-timeout",
73 | ]
74 |
75 | [[package]]
76 | name = "autocfg"
77 | version = "1.3.0"
78 | source = "registry+https://github.com/rust-lang/crates.io-index"
79 | checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
80 |
81 | [[package]]
82 | name = "backtrace"
83 | version = "0.3.71"
84 | source = "registry+https://github.com/rust-lang/crates.io-index"
85 | checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d"
86 | dependencies = [
87 | "addr2line",
88 | "cc",
89 | "cfg-if",
90 | "libc",
91 | "miniz_oxide",
92 | "object",
93 | "rustc-demangle",
94 | ]
95 |
96 | [[package]]
97 | name = "base64"
98 | version = "0.22.1"
99 | source = "registry+https://github.com/rust-lang/crates.io-index"
100 | checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
101 |
102 | [[package]]
103 | name = "base64ct"
104 | version = "1.6.0"
105 | source = "registry+https://github.com/rust-lang/crates.io-index"
106 | checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
107 |
108 | [[package]]
109 | name = "bcrypt"
110 | version = "0.16.0"
111 | source = "registry+https://github.com/rust-lang/crates.io-index"
112 | checksum = "2b1866ecef4f2d06a0bb77880015fdf2b89e25a1c2e5addacb87e459c86dc67e"
113 | dependencies = [
114 | "base64",
115 | "blowfish",
116 | "getrandom",
117 | "subtle",
118 | "zeroize",
119 | ]
120 |
121 | [[package]]
122 | name = "bitflags"
123 | version = "2.7.0"
124 | source = "registry+https://github.com/rust-lang/crates.io-index"
125 | checksum = "1be3f42a67d6d345ecd59f675f3f012d6974981560836e938c22b424b85ce1be"
126 |
127 | [[package]]
128 | name = "blake2-rfc"
129 | version = "0.2.18"
130 | source = "registry+https://github.com/rust-lang/crates.io-index"
131 | checksum = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400"
132 | dependencies = [
133 | "arrayvec",
134 | "constant_time_eq",
135 | ]
136 |
137 | [[package]]
138 | name = "block-buffer"
139 | version = "0.10.4"
140 | source = "registry+https://github.com/rust-lang/crates.io-index"
141 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
142 | dependencies = [
143 | "generic-array",
144 | ]
145 |
146 | [[package]]
147 | name = "blowfish"
148 | version = "0.9.1"
149 | source = "registry+https://github.com/rust-lang/crates.io-index"
150 | checksum = "e412e2cd0f2b2d93e02543ceae7917b3c70331573df19ee046bcbc35e45e87d7"
151 | dependencies = [
152 | "byteorder",
153 | "cipher",
154 | ]
155 |
156 | [[package]]
157 | name = "bstr"
158 | version = "1.9.1"
159 | source = "registry+https://github.com/rust-lang/crates.io-index"
160 | checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706"
161 | dependencies = [
162 | "memchr",
163 | "regex-automata",
164 | "serde",
165 | ]
166 |
167 | [[package]]
168 | name = "bumpalo"
169 | version = "3.16.0"
170 | source = "registry+https://github.com/rust-lang/crates.io-index"
171 | checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
172 |
173 | [[package]]
174 | name = "byteorder"
175 | version = "1.5.0"
176 | source = "registry+https://github.com/rust-lang/crates.io-index"
177 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
178 |
179 | [[package]]
180 | name = "bytes"
181 | version = "1.6.0"
182 | source = "registry+https://github.com/rust-lang/crates.io-index"
183 | checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9"
184 |
185 | [[package]]
186 | name = "cast"
187 | version = "0.3.0"
188 | source = "registry+https://github.com/rust-lang/crates.io-index"
189 | checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
190 |
191 | [[package]]
192 | name = "cc"
193 | version = "1.0.97"
194 | source = "registry+https://github.com/rust-lang/crates.io-index"
195 | checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4"
196 |
197 | [[package]]
198 | name = "cfg-if"
199 | version = "1.0.0"
200 | source = "registry+https://github.com/rust-lang/crates.io-index"
201 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
202 |
203 | [[package]]
204 | name = "ciborium"
205 | version = "0.2.2"
206 | source = "registry+https://github.com/rust-lang/crates.io-index"
207 | checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e"
208 | dependencies = [
209 | "ciborium-io",
210 | "ciborium-ll",
211 | "serde",
212 | ]
213 |
214 | [[package]]
215 | name = "ciborium-io"
216 | version = "0.2.2"
217 | source = "registry+https://github.com/rust-lang/crates.io-index"
218 | checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757"
219 |
220 | [[package]]
221 | name = "ciborium-ll"
222 | version = "0.2.2"
223 | source = "registry+https://github.com/rust-lang/crates.io-index"
224 | checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9"
225 | dependencies = [
226 | "ciborium-io",
227 | "half",
228 | ]
229 |
230 | [[package]]
231 | name = "cipher"
232 | version = "0.4.4"
233 | source = "registry+https://github.com/rust-lang/crates.io-index"
234 | checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
235 | dependencies = [
236 | "crypto-common",
237 | "inout",
238 | ]
239 |
240 | [[package]]
241 | name = "clap"
242 | version = "4.5.4"
243 | source = "registry+https://github.com/rust-lang/crates.io-index"
244 | checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0"
245 | dependencies = [
246 | "clap_builder",
247 | ]
248 |
249 | [[package]]
250 | name = "clap_builder"
251 | version = "4.5.2"
252 | source = "registry+https://github.com/rust-lang/crates.io-index"
253 | checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4"
254 | dependencies = [
255 | "anstyle",
256 | "clap_lex",
257 | ]
258 |
259 | [[package]]
260 | name = "clap_lex"
261 | version = "0.7.0"
262 | source = "registry+https://github.com/rust-lang/crates.io-index"
263 | checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
264 |
265 | [[package]]
266 | name = "constant_time_eq"
267 | version = "0.1.5"
268 | source = "registry+https://github.com/rust-lang/crates.io-index"
269 | checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
270 |
271 | [[package]]
272 | name = "cpufeatures"
273 | version = "0.2.12"
274 | source = "registry+https://github.com/rust-lang/crates.io-index"
275 | checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504"
276 | dependencies = [
277 | "libc",
278 | ]
279 |
280 | [[package]]
281 | name = "criterion"
282 | version = "0.5.1"
283 | source = "registry+https://github.com/rust-lang/crates.io-index"
284 | checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f"
285 | dependencies = [
286 | "anes",
287 | "cast",
288 | "ciborium",
289 | "clap",
290 | "criterion-plot",
291 | "is-terminal",
292 | "itertools",
293 | "num-traits",
294 | "once_cell",
295 | "oorandom",
296 | "plotters",
297 | "rayon",
298 | "regex",
299 | "serde",
300 | "serde_derive",
301 | "serde_json",
302 | "tinytemplate",
303 | "walkdir",
304 | ]
305 |
306 | [[package]]
307 | name = "criterion-plot"
308 | version = "0.5.0"
309 | source = "registry+https://github.com/rust-lang/crates.io-index"
310 | checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1"
311 | dependencies = [
312 | "cast",
313 | "itertools",
314 | ]
315 |
316 | [[package]]
317 | name = "crossbeam-deque"
318 | version = "0.8.5"
319 | source = "registry+https://github.com/rust-lang/crates.io-index"
320 | checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
321 | dependencies = [
322 | "crossbeam-epoch",
323 | "crossbeam-utils",
324 | ]
325 |
326 | [[package]]
327 | name = "crossbeam-epoch"
328 | version = "0.9.18"
329 | source = "registry+https://github.com/rust-lang/crates.io-index"
330 | checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
331 | dependencies = [
332 | "crossbeam-utils",
333 | ]
334 |
335 | [[package]]
336 | name = "crossbeam-utils"
337 | version = "0.8.19"
338 | source = "registry+https://github.com/rust-lang/crates.io-index"
339 | checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
340 |
341 | [[package]]
342 | name = "crunchy"
343 | version = "0.2.2"
344 | source = "registry+https://github.com/rust-lang/crates.io-index"
345 | checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
346 |
347 | [[package]]
348 | name = "crypto-common"
349 | version = "0.1.6"
350 | source = "registry+https://github.com/rust-lang/crates.io-index"
351 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
352 | dependencies = [
353 | "generic-array",
354 | "typenum",
355 | ]
356 |
357 | [[package]]
358 | name = "deranged"
359 | version = "0.3.11"
360 | source = "registry+https://github.com/rust-lang/crates.io-index"
361 | checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
362 | dependencies = [
363 | "powerfmt",
364 | "serde",
365 | ]
366 |
367 | [[package]]
368 | name = "difflib"
369 | version = "0.4.0"
370 | source = "registry+https://github.com/rust-lang/crates.io-index"
371 | checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8"
372 |
373 | [[package]]
374 | name = "digest"
375 | version = "0.10.7"
376 | source = "registry+https://github.com/rust-lang/crates.io-index"
377 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
378 | dependencies = [
379 | "block-buffer",
380 | "crypto-common",
381 | "subtle",
382 | ]
383 |
384 | [[package]]
385 | name = "doc-comment"
386 | version = "0.3.3"
387 | source = "registry+https://github.com/rust-lang/crates.io-index"
388 | checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
389 |
390 | [[package]]
391 | name = "dtt"
392 | version = "0.0.5"
393 | source = "registry+https://github.com/rust-lang/crates.io-index"
394 | checksum = "d6b2dd9ee2d76888dc4c17d6da74629fa11b3cb1e8094fdc159b7f8ff259fc88"
395 | dependencies = [
396 | "regex",
397 | "serde",
398 | "time",
399 | ]
400 |
401 | [[package]]
402 | name = "dtt"
403 | version = "0.0.6"
404 | source = "registry+https://github.com/rust-lang/crates.io-index"
405 | checksum = "21191da49ce48aa9200e9ac040032d680b3b71a158fbecaa1a99282821c3c251"
406 | dependencies = [
407 | "regex",
408 | "serde",
409 | "time",
410 | ]
411 |
412 | [[package]]
413 | name = "dtt"
414 | version = "0.0.9"
415 | source = "registry+https://github.com/rust-lang/crates.io-index"
416 | checksum = "a3d0ded54a7c92b3bbc6d8a6a5ae97f120caa634ab7ee49d0b20ac2041037e2d"
417 | dependencies = [
418 | "lazy_static",
419 | "paste",
420 | "regex",
421 | "serde",
422 | "serde_json",
423 | "thiserror",
424 | "time",
425 | "version_check",
426 | ]
427 |
428 | [[package]]
429 | name = "either"
430 | version = "1.11.0"
431 | source = "registry+https://github.com/rust-lang/crates.io-index"
432 | checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2"
433 |
434 | [[package]]
435 | name = "generic-array"
436 | version = "0.14.7"
437 | source = "registry+https://github.com/rust-lang/crates.io-index"
438 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
439 | dependencies = [
440 | "typenum",
441 | "version_check",
442 | ]
443 |
444 | [[package]]
445 | name = "getrandom"
446 | version = "0.2.15"
447 | source = "registry+https://github.com/rust-lang/crates.io-index"
448 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
449 | dependencies = [
450 | "cfg-if",
451 | "libc",
452 | "wasi",
453 | ]
454 |
455 | [[package]]
456 | name = "gimli"
457 | version = "0.28.1"
458 | source = "registry+https://github.com/rust-lang/crates.io-index"
459 | checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
460 |
461 | [[package]]
462 | name = "half"
463 | version = "2.4.1"
464 | source = "registry+https://github.com/rust-lang/crates.io-index"
465 | checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888"
466 | dependencies = [
467 | "cfg-if",
468 | "crunchy",
469 | ]
470 |
471 | [[package]]
472 | name = "hermit-abi"
473 | version = "0.3.9"
474 | source = "registry+https://github.com/rust-lang/crates.io-index"
475 | checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
476 |
477 | [[package]]
478 | name = "hmac"
479 | version = "0.12.1"
480 | source = "registry+https://github.com/rust-lang/crates.io-index"
481 | checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
482 | dependencies = [
483 | "digest",
484 | ]
485 |
486 | [[package]]
487 | name = "hostname"
488 | version = "0.3.1"
489 | source = "registry+https://github.com/rust-lang/crates.io-index"
490 | checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867"
491 | dependencies = [
492 | "libc",
493 | "match_cfg",
494 | "winapi",
495 | ]
496 |
497 | [[package]]
498 | name = "hostname"
499 | version = "0.4.0"
500 | source = "registry+https://github.com/rust-lang/crates.io-index"
501 | checksum = "f9c7c7c8ac16c798734b8a24560c1362120597c40d5e1459f09498f8f6c8f2ba"
502 | dependencies = [
503 | "cfg-if",
504 | "libc",
505 | "windows",
506 | ]
507 |
508 | [[package]]
509 | name = "hsh"
510 | version = "0.0.8"
511 | dependencies = [
512 | "argon2rs",
513 | "assert_cmd",
514 | "base64",
515 | "bcrypt",
516 | "criterion",
517 | "dtt 0.0.9",
518 | "log",
519 | "scrypt",
520 | "serde",
521 | "serde_json",
522 | "vrd 0.0.8",
523 | ]
524 |
525 | [[package]]
526 | name = "inout"
527 | version = "0.1.3"
528 | source = "registry+https://github.com/rust-lang/crates.io-index"
529 | checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
530 | dependencies = [
531 | "generic-array",
532 | ]
533 |
534 | [[package]]
535 | name = "is-terminal"
536 | version = "0.4.12"
537 | source = "registry+https://github.com/rust-lang/crates.io-index"
538 | checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b"
539 | dependencies = [
540 | "hermit-abi",
541 | "libc",
542 | "windows-sys",
543 | ]
544 |
545 | [[package]]
546 | name = "itertools"
547 | version = "0.10.5"
548 | source = "registry+https://github.com/rust-lang/crates.io-index"
549 | checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
550 | dependencies = [
551 | "either",
552 | ]
553 |
554 | [[package]]
555 | name = "itoa"
556 | version = "1.0.11"
557 | source = "registry+https://github.com/rust-lang/crates.io-index"
558 | checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
559 |
560 | [[package]]
561 | name = "js-sys"
562 | version = "0.3.69"
563 | source = "registry+https://github.com/rust-lang/crates.io-index"
564 | checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
565 | dependencies = [
566 | "wasm-bindgen",
567 | ]
568 |
569 | [[package]]
570 | name = "lazy_static"
571 | version = "1.5.0"
572 | source = "registry+https://github.com/rust-lang/crates.io-index"
573 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
574 |
575 | [[package]]
576 | name = "libc"
577 | version = "0.2.169"
578 | source = "registry+https://github.com/rust-lang/crates.io-index"
579 | checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
580 |
581 | [[package]]
582 | name = "lock_api"
583 | version = "0.4.12"
584 | source = "registry+https://github.com/rust-lang/crates.io-index"
585 | checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
586 | dependencies = [
587 | "autocfg",
588 | "scopeguard",
589 | ]
590 |
591 | [[package]]
592 | name = "log"
593 | version = "0.4.25"
594 | source = "registry+https://github.com/rust-lang/crates.io-index"
595 | checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
596 |
597 | [[package]]
598 | name = "match_cfg"
599 | version = "0.1.0"
600 | source = "registry+https://github.com/rust-lang/crates.io-index"
601 | checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4"
602 |
603 | [[package]]
604 | name = "memchr"
605 | version = "2.7.2"
606 | source = "registry+https://github.com/rust-lang/crates.io-index"
607 | checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
608 |
609 | [[package]]
610 | name = "miniz_oxide"
611 | version = "0.7.2"
612 | source = "registry+https://github.com/rust-lang/crates.io-index"
613 | checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
614 | dependencies = [
615 | "adler",
616 | ]
617 |
618 | [[package]]
619 | name = "mio"
620 | version = "1.0.3"
621 | source = "registry+https://github.com/rust-lang/crates.io-index"
622 | checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
623 | dependencies = [
624 | "libc",
625 | "wasi",
626 | "windows-sys",
627 | ]
628 |
629 | [[package]]
630 | name = "nodrop"
631 | version = "0.1.14"
632 | source = "registry+https://github.com/rust-lang/crates.io-index"
633 | checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
634 |
635 | [[package]]
636 | name = "num-conv"
637 | version = "0.1.0"
638 | source = "registry+https://github.com/rust-lang/crates.io-index"
639 | checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
640 |
641 | [[package]]
642 | name = "num-traits"
643 | version = "0.2.19"
644 | source = "registry+https://github.com/rust-lang/crates.io-index"
645 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
646 | dependencies = [
647 | "autocfg",
648 | ]
649 |
650 | [[package]]
651 | name = "object"
652 | version = "0.32.2"
653 | source = "registry+https://github.com/rust-lang/crates.io-index"
654 | checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
655 | dependencies = [
656 | "memchr",
657 | ]
658 |
659 | [[package]]
660 | name = "once_cell"
661 | version = "1.19.0"
662 | source = "registry+https://github.com/rust-lang/crates.io-index"
663 | checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
664 |
665 | [[package]]
666 | name = "oorandom"
667 | version = "11.1.3"
668 | source = "registry+https://github.com/rust-lang/crates.io-index"
669 | checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
670 |
671 | [[package]]
672 | name = "parking_lot"
673 | version = "0.12.2"
674 | source = "registry+https://github.com/rust-lang/crates.io-index"
675 | checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb"
676 | dependencies = [
677 | "lock_api",
678 | "parking_lot_core",
679 | ]
680 |
681 | [[package]]
682 | name = "parking_lot_core"
683 | version = "0.9.10"
684 | source = "registry+https://github.com/rust-lang/crates.io-index"
685 | checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
686 | dependencies = [
687 | "cfg-if",
688 | "libc",
689 | "redox_syscall",
690 | "smallvec",
691 | "windows-targets",
692 | ]
693 |
694 | [[package]]
695 | name = "password-hash"
696 | version = "0.5.0"
697 | source = "registry+https://github.com/rust-lang/crates.io-index"
698 | checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166"
699 | dependencies = [
700 | "base64ct",
701 | "rand_core",
702 | "subtle",
703 | ]
704 |
705 | [[package]]
706 | name = "paste"
707 | version = "1.0.15"
708 | source = "registry+https://github.com/rust-lang/crates.io-index"
709 | checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
710 |
711 | [[package]]
712 | name = "pbkdf2"
713 | version = "0.12.2"
714 | source = "registry+https://github.com/rust-lang/crates.io-index"
715 | checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2"
716 | dependencies = [
717 | "digest",
718 | "hmac",
719 | ]
720 |
721 | [[package]]
722 | name = "pin-project-lite"
723 | version = "0.2.14"
724 | source = "registry+https://github.com/rust-lang/crates.io-index"
725 | checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
726 |
727 | [[package]]
728 | name = "plotters"
729 | version = "0.3.5"
730 | source = "registry+https://github.com/rust-lang/crates.io-index"
731 | checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45"
732 | dependencies = [
733 | "num-traits",
734 | "plotters-backend",
735 | "plotters-svg",
736 | "wasm-bindgen",
737 | "web-sys",
738 | ]
739 |
740 | [[package]]
741 | name = "plotters-backend"
742 | version = "0.3.5"
743 | source = "registry+https://github.com/rust-lang/crates.io-index"
744 | checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609"
745 |
746 | [[package]]
747 | name = "plotters-svg"
748 | version = "0.3.5"
749 | source = "registry+https://github.com/rust-lang/crates.io-index"
750 | checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab"
751 | dependencies = [
752 | "plotters-backend",
753 | ]
754 |
755 | [[package]]
756 | name = "powerfmt"
757 | version = "0.2.0"
758 | source = "registry+https://github.com/rust-lang/crates.io-index"
759 | checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
760 |
761 | [[package]]
762 | name = "ppv-lite86"
763 | version = "0.2.17"
764 | source = "registry+https://github.com/rust-lang/crates.io-index"
765 | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
766 |
767 | [[package]]
768 | name = "predicates"
769 | version = "3.1.0"
770 | source = "registry+https://github.com/rust-lang/crates.io-index"
771 | checksum = "68b87bfd4605926cdfefc1c3b5f8fe560e3feca9d5552cf68c466d3d8236c7e8"
772 | dependencies = [
773 | "anstyle",
774 | "difflib",
775 | "predicates-core",
776 | ]
777 |
778 | [[package]]
779 | name = "predicates-core"
780 | version = "1.0.6"
781 | source = "registry+https://github.com/rust-lang/crates.io-index"
782 | checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174"
783 |
784 | [[package]]
785 | name = "predicates-tree"
786 | version = "1.0.9"
787 | source = "registry+https://github.com/rust-lang/crates.io-index"
788 | checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf"
789 | dependencies = [
790 | "predicates-core",
791 | "termtree",
792 | ]
793 |
794 | [[package]]
795 | name = "proc-macro2"
796 | version = "1.0.92"
797 | source = "registry+https://github.com/rust-lang/crates.io-index"
798 | checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
799 | dependencies = [
800 | "unicode-ident",
801 | ]
802 |
803 | [[package]]
804 | name = "quote"
805 | version = "1.0.36"
806 | source = "registry+https://github.com/rust-lang/crates.io-index"
807 | checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
808 | dependencies = [
809 | "proc-macro2",
810 | ]
811 |
812 | [[package]]
813 | name = "rand"
814 | version = "0.8.5"
815 | source = "registry+https://github.com/rust-lang/crates.io-index"
816 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
817 | dependencies = [
818 | "libc",
819 | "rand_chacha",
820 | "rand_core",
821 | ]
822 |
823 | [[package]]
824 | name = "rand_chacha"
825 | version = "0.3.1"
826 | source = "registry+https://github.com/rust-lang/crates.io-index"
827 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
828 | dependencies = [
829 | "ppv-lite86",
830 | "rand_core",
831 | ]
832 |
833 | [[package]]
834 | name = "rand_core"
835 | version = "0.6.4"
836 | source = "registry+https://github.com/rust-lang/crates.io-index"
837 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
838 | dependencies = [
839 | "getrandom",
840 | ]
841 |
842 | [[package]]
843 | name = "rayon"
844 | version = "1.10.0"
845 | source = "registry+https://github.com/rust-lang/crates.io-index"
846 | checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
847 | dependencies = [
848 | "either",
849 | "rayon-core",
850 | ]
851 |
852 | [[package]]
853 | name = "rayon-core"
854 | version = "1.12.1"
855 | source = "registry+https://github.com/rust-lang/crates.io-index"
856 | checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
857 | dependencies = [
858 | "crossbeam-deque",
859 | "crossbeam-utils",
860 | ]
861 |
862 | [[package]]
863 | name = "redox_syscall"
864 | version = "0.5.1"
865 | source = "registry+https://github.com/rust-lang/crates.io-index"
866 | checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e"
867 | dependencies = [
868 | "bitflags",
869 | ]
870 |
871 | [[package]]
872 | name = "regex"
873 | version = "1.11.1"
874 | source = "registry+https://github.com/rust-lang/crates.io-index"
875 | checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
876 | dependencies = [
877 | "aho-corasick",
878 | "memchr",
879 | "regex-automata",
880 | "regex-syntax",
881 | ]
882 |
883 | [[package]]
884 | name = "regex-automata"
885 | version = "0.4.9"
886 | source = "registry+https://github.com/rust-lang/crates.io-index"
887 | checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
888 | dependencies = [
889 | "aho-corasick",
890 | "memchr",
891 | "regex-syntax",
892 | ]
893 |
894 | [[package]]
895 | name = "regex-syntax"
896 | version = "0.8.5"
897 | source = "registry+https://github.com/rust-lang/crates.io-index"
898 | checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
899 |
900 | [[package]]
901 | name = "rlg"
902 | version = "0.0.3"
903 | source = "registry+https://github.com/rust-lang/crates.io-index"
904 | checksum = "9e02c717e23f67b23032a4acb01cf63534d6259938d592e6d2451c02f09fc368"
905 | dependencies = [
906 | "dtt 0.0.5",
907 | "hostname 0.3.1",
908 | "serde_json",
909 | "tokio",
910 | "vrd 0.0.5",
911 | ]
912 |
913 | [[package]]
914 | name = "rlg"
915 | version = "0.0.4"
916 | source = "registry+https://github.com/rust-lang/crates.io-index"
917 | checksum = "fa9550dfcf50ac8601b165168e8825d66e45db390f7740a3d45c640946c4a971"
918 | dependencies = [
919 | "dtt 0.0.6",
920 | "hostname 0.4.0",
921 | "serde",
922 | "serde_json",
923 | "tokio",
924 | "version_check",
925 | "vrd 0.0.7",
926 | ]
927 |
928 | [[package]]
929 | name = "rustc-demangle"
930 | version = "0.1.24"
931 | source = "registry+https://github.com/rust-lang/crates.io-index"
932 | checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
933 |
934 | [[package]]
935 | name = "ryu"
936 | version = "1.0.18"
937 | source = "registry+https://github.com/rust-lang/crates.io-index"
938 | checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
939 |
940 | [[package]]
941 | name = "salsa20"
942 | version = "0.10.2"
943 | source = "registry+https://github.com/rust-lang/crates.io-index"
944 | checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213"
945 | dependencies = [
946 | "cipher",
947 | ]
948 |
949 | [[package]]
950 | name = "same-file"
951 | version = "1.0.6"
952 | source = "registry+https://github.com/rust-lang/crates.io-index"
953 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
954 | dependencies = [
955 | "winapi-util",
956 | ]
957 |
958 | [[package]]
959 | name = "scoped_threadpool"
960 | version = "0.1.9"
961 | source = "registry+https://github.com/rust-lang/crates.io-index"
962 | checksum = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8"
963 |
964 | [[package]]
965 | name = "scopeguard"
966 | version = "1.2.0"
967 | source = "registry+https://github.com/rust-lang/crates.io-index"
968 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
969 |
970 | [[package]]
971 | name = "scrypt"
972 | version = "0.11.0"
973 | source = "registry+https://github.com/rust-lang/crates.io-index"
974 | checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f"
975 | dependencies = [
976 | "password-hash",
977 | "pbkdf2",
978 | "salsa20",
979 | "sha2",
980 | ]
981 |
982 | [[package]]
983 | name = "serde"
984 | version = "1.0.217"
985 | source = "registry+https://github.com/rust-lang/crates.io-index"
986 | checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70"
987 | dependencies = [
988 | "serde_derive",
989 | ]
990 |
991 | [[package]]
992 | name = "serde-big-array"
993 | version = "0.5.1"
994 | source = "registry+https://github.com/rust-lang/crates.io-index"
995 | checksum = "11fc7cc2c76d73e0f27ee52abbd64eec84d46f370c88371120433196934e4b7f"
996 | dependencies = [
997 | "serde",
998 | ]
999 |
1000 | [[package]]
1001 | name = "serde_derive"
1002 | version = "1.0.217"
1003 | source = "registry+https://github.com/rust-lang/crates.io-index"
1004 | checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
1005 | dependencies = [
1006 | "proc-macro2",
1007 | "quote",
1008 | "syn",
1009 | ]
1010 |
1011 | [[package]]
1012 | name = "serde_json"
1013 | version = "1.0.137"
1014 | source = "registry+https://github.com/rust-lang/crates.io-index"
1015 | checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b"
1016 | dependencies = [
1017 | "itoa",
1018 | "memchr",
1019 | "ryu",
1020 | "serde",
1021 | ]
1022 |
1023 | [[package]]
1024 | name = "sha2"
1025 | version = "0.10.8"
1026 | source = "registry+https://github.com/rust-lang/crates.io-index"
1027 | checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
1028 | dependencies = [
1029 | "cfg-if",
1030 | "cpufeatures",
1031 | "digest",
1032 | ]
1033 |
1034 | [[package]]
1035 | name = "signal-hook-registry"
1036 | version = "1.4.2"
1037 | source = "registry+https://github.com/rust-lang/crates.io-index"
1038 | checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
1039 | dependencies = [
1040 | "libc",
1041 | ]
1042 |
1043 | [[package]]
1044 | name = "smallvec"
1045 | version = "1.13.2"
1046 | source = "registry+https://github.com/rust-lang/crates.io-index"
1047 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
1048 |
1049 | [[package]]
1050 | name = "socket2"
1051 | version = "0.5.7"
1052 | source = "registry+https://github.com/rust-lang/crates.io-index"
1053 | checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c"
1054 | dependencies = [
1055 | "libc",
1056 | "windows-sys",
1057 | ]
1058 |
1059 | [[package]]
1060 | name = "subtle"
1061 | version = "2.5.0"
1062 | source = "registry+https://github.com/rust-lang/crates.io-index"
1063 | checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
1064 |
1065 | [[package]]
1066 | name = "syn"
1067 | version = "2.0.93"
1068 | source = "registry+https://github.com/rust-lang/crates.io-index"
1069 | checksum = "9c786062daee0d6db1132800e623df74274a0a87322d8e183338e01b3d98d058"
1070 | dependencies = [
1071 | "proc-macro2",
1072 | "quote",
1073 | "unicode-ident",
1074 | ]
1075 |
1076 | [[package]]
1077 | name = "termtree"
1078 | version = "0.4.1"
1079 | source = "registry+https://github.com/rust-lang/crates.io-index"
1080 | checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76"
1081 |
1082 | [[package]]
1083 | name = "thiserror"
1084 | version = "2.0.9"
1085 | source = "registry+https://github.com/rust-lang/crates.io-index"
1086 | checksum = "f072643fd0190df67a8bab670c20ef5d8737177d6ac6b2e9a236cb096206b2cc"
1087 | dependencies = [
1088 | "thiserror-impl",
1089 | ]
1090 |
1091 | [[package]]
1092 | name = "thiserror-impl"
1093 | version = "2.0.9"
1094 | source = "registry+https://github.com/rust-lang/crates.io-index"
1095 | checksum = "7b50fa271071aae2e6ee85f842e2e28ba8cd2c5fb67f11fcb1fd70b276f9e7d4"
1096 | dependencies = [
1097 | "proc-macro2",
1098 | "quote",
1099 | "syn",
1100 | ]
1101 |
1102 | [[package]]
1103 | name = "time"
1104 | version = "0.3.37"
1105 | source = "registry+https://github.com/rust-lang/crates.io-index"
1106 | checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21"
1107 | dependencies = [
1108 | "deranged",
1109 | "itoa",
1110 | "num-conv",
1111 | "powerfmt",
1112 | "serde",
1113 | "time-core",
1114 | "time-macros",
1115 | ]
1116 |
1117 | [[package]]
1118 | name = "time-core"
1119 | version = "0.1.2"
1120 | source = "registry+https://github.com/rust-lang/crates.io-index"
1121 | checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
1122 |
1123 | [[package]]
1124 | name = "time-macros"
1125 | version = "0.2.19"
1126 | source = "registry+https://github.com/rust-lang/crates.io-index"
1127 | checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de"
1128 | dependencies = [
1129 | "num-conv",
1130 | "time-core",
1131 | ]
1132 |
1133 | [[package]]
1134 | name = "tinytemplate"
1135 | version = "1.2.1"
1136 | source = "registry+https://github.com/rust-lang/crates.io-index"
1137 | checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
1138 | dependencies = [
1139 | "serde",
1140 | "serde_json",
1141 | ]
1142 |
1143 | [[package]]
1144 | name = "tokio"
1145 | version = "1.43.0"
1146 | source = "registry+https://github.com/rust-lang/crates.io-index"
1147 | checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e"
1148 | dependencies = [
1149 | "backtrace",
1150 | "bytes",
1151 | "libc",
1152 | "mio",
1153 | "parking_lot",
1154 | "pin-project-lite",
1155 | "signal-hook-registry",
1156 | "socket2",
1157 | "tokio-macros",
1158 | "windows-sys",
1159 | ]
1160 |
1161 | [[package]]
1162 | name = "tokio-macros"
1163 | version = "2.5.0"
1164 | source = "registry+https://github.com/rust-lang/crates.io-index"
1165 | checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8"
1166 | dependencies = [
1167 | "proc-macro2",
1168 | "quote",
1169 | "syn",
1170 | ]
1171 |
1172 | [[package]]
1173 | name = "typenum"
1174 | version = "1.17.0"
1175 | source = "registry+https://github.com/rust-lang/crates.io-index"
1176 | checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
1177 |
1178 | [[package]]
1179 | name = "unicode-ident"
1180 | version = "1.0.12"
1181 | source = "registry+https://github.com/rust-lang/crates.io-index"
1182 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
1183 |
1184 | [[package]]
1185 | name = "uuid"
1186 | version = "1.11.1"
1187 | source = "registry+https://github.com/rust-lang/crates.io-index"
1188 | checksum = "b913a3b5fe84142e269d63cc62b64319ccaf89b748fc31fe025177f767a756c4"
1189 | dependencies = [
1190 | "getrandom",
1191 | ]
1192 |
1193 | [[package]]
1194 | name = "version_check"
1195 | version = "0.9.5"
1196 | source = "registry+https://github.com/rust-lang/crates.io-index"
1197 | checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
1198 |
1199 | [[package]]
1200 | name = "vrd"
1201 | version = "0.0.5"
1202 | source = "registry+https://github.com/rust-lang/crates.io-index"
1203 | checksum = "ee1067b8d17481f5be71b59d11c329e955ffe36348907e0a4a41b619682bb4af"
1204 | dependencies = [
1205 | "rand",
1206 | "serde",
1207 | ]
1208 |
1209 | [[package]]
1210 | name = "vrd"
1211 | version = "0.0.7"
1212 | source = "registry+https://github.com/rust-lang/crates.io-index"
1213 | checksum = "08fd4c00822f48600521b6dfa7ed8103e9f38c720e198ff4db0400c925414c80"
1214 | dependencies = [
1215 | "bitflags",
1216 | "dtt 0.0.5",
1217 | "rand",
1218 | "rlg 0.0.3",
1219 | "serde",
1220 | "serde-big-array",
1221 | "serde_json",
1222 | "tokio",
1223 | "uuid",
1224 | ]
1225 |
1226 | [[package]]
1227 | name = "vrd"
1228 | version = "0.0.8"
1229 | source = "registry+https://github.com/rust-lang/crates.io-index"
1230 | checksum = "46865c0eccde4965b89ced6849abf44ffe603dd838a3666dfff3cc2d9437549d"
1231 | dependencies = [
1232 | "bitflags",
1233 | "dtt 0.0.6",
1234 | "rand",
1235 | "rlg 0.0.4",
1236 | "serde",
1237 | "serde-big-array",
1238 | "serde_json",
1239 | "tokio",
1240 | "uuid",
1241 | "version_check",
1242 | ]
1243 |
1244 | [[package]]
1245 | name = "wait-timeout"
1246 | version = "0.2.0"
1247 | source = "registry+https://github.com/rust-lang/crates.io-index"
1248 | checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
1249 | dependencies = [
1250 | "libc",
1251 | ]
1252 |
1253 | [[package]]
1254 | name = "walkdir"
1255 | version = "2.5.0"
1256 | source = "registry+https://github.com/rust-lang/crates.io-index"
1257 | checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
1258 | dependencies = [
1259 | "same-file",
1260 | "winapi-util",
1261 | ]
1262 |
1263 | [[package]]
1264 | name = "wasi"
1265 | version = "0.11.0+wasi-snapshot-preview1"
1266 | source = "registry+https://github.com/rust-lang/crates.io-index"
1267 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
1268 |
1269 | [[package]]
1270 | name = "wasm-bindgen"
1271 | version = "0.2.92"
1272 | source = "registry+https://github.com/rust-lang/crates.io-index"
1273 | checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
1274 | dependencies = [
1275 | "cfg-if",
1276 | "wasm-bindgen-macro",
1277 | ]
1278 |
1279 | [[package]]
1280 | name = "wasm-bindgen-backend"
1281 | version = "0.2.92"
1282 | source = "registry+https://github.com/rust-lang/crates.io-index"
1283 | checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
1284 | dependencies = [
1285 | "bumpalo",
1286 | "log",
1287 | "once_cell",
1288 | "proc-macro2",
1289 | "quote",
1290 | "syn",
1291 | "wasm-bindgen-shared",
1292 | ]
1293 |
1294 | [[package]]
1295 | name = "wasm-bindgen-macro"
1296 | version = "0.2.92"
1297 | source = "registry+https://github.com/rust-lang/crates.io-index"
1298 | checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
1299 | dependencies = [
1300 | "quote",
1301 | "wasm-bindgen-macro-support",
1302 | ]
1303 |
1304 | [[package]]
1305 | name = "wasm-bindgen-macro-support"
1306 | version = "0.2.92"
1307 | source = "registry+https://github.com/rust-lang/crates.io-index"
1308 | checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
1309 | dependencies = [
1310 | "proc-macro2",
1311 | "quote",
1312 | "syn",
1313 | "wasm-bindgen-backend",
1314 | "wasm-bindgen-shared",
1315 | ]
1316 |
1317 | [[package]]
1318 | name = "wasm-bindgen-shared"
1319 | version = "0.2.92"
1320 | source = "registry+https://github.com/rust-lang/crates.io-index"
1321 | checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
1322 |
1323 | [[package]]
1324 | name = "web-sys"
1325 | version = "0.3.69"
1326 | source = "registry+https://github.com/rust-lang/crates.io-index"
1327 | checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef"
1328 | dependencies = [
1329 | "js-sys",
1330 | "wasm-bindgen",
1331 | ]
1332 |
1333 | [[package]]
1334 | name = "winapi"
1335 | version = "0.3.9"
1336 | source = "registry+https://github.com/rust-lang/crates.io-index"
1337 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
1338 | dependencies = [
1339 | "winapi-i686-pc-windows-gnu",
1340 | "winapi-x86_64-pc-windows-gnu",
1341 | ]
1342 |
1343 | [[package]]
1344 | name = "winapi-i686-pc-windows-gnu"
1345 | version = "0.4.0"
1346 | source = "registry+https://github.com/rust-lang/crates.io-index"
1347 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
1348 |
1349 | [[package]]
1350 | name = "winapi-util"
1351 | version = "0.1.8"
1352 | source = "registry+https://github.com/rust-lang/crates.io-index"
1353 | checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b"
1354 | dependencies = [
1355 | "windows-sys",
1356 | ]
1357 |
1358 | [[package]]
1359 | name = "winapi-x86_64-pc-windows-gnu"
1360 | version = "0.4.0"
1361 | source = "registry+https://github.com/rust-lang/crates.io-index"
1362 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
1363 |
1364 | [[package]]
1365 | name = "windows"
1366 | version = "0.52.0"
1367 | source = "registry+https://github.com/rust-lang/crates.io-index"
1368 | checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
1369 | dependencies = [
1370 | "windows-core",
1371 | "windows-targets",
1372 | ]
1373 |
1374 | [[package]]
1375 | name = "windows-core"
1376 | version = "0.52.0"
1377 | source = "registry+https://github.com/rust-lang/crates.io-index"
1378 | checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
1379 | dependencies = [
1380 | "windows-targets",
1381 | ]
1382 |
1383 | [[package]]
1384 | name = "windows-sys"
1385 | version = "0.52.0"
1386 | source = "registry+https://github.com/rust-lang/crates.io-index"
1387 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
1388 | dependencies = [
1389 | "windows-targets",
1390 | ]
1391 |
1392 | [[package]]
1393 | name = "windows-targets"
1394 | version = "0.52.5"
1395 | source = "registry+https://github.com/rust-lang/crates.io-index"
1396 | checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
1397 | dependencies = [
1398 | "windows_aarch64_gnullvm",
1399 | "windows_aarch64_msvc",
1400 | "windows_i686_gnu",
1401 | "windows_i686_gnullvm",
1402 | "windows_i686_msvc",
1403 | "windows_x86_64_gnu",
1404 | "windows_x86_64_gnullvm",
1405 | "windows_x86_64_msvc",
1406 | ]
1407 |
1408 | [[package]]
1409 | name = "windows_aarch64_gnullvm"
1410 | version = "0.52.5"
1411 | source = "registry+https://github.com/rust-lang/crates.io-index"
1412 | checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
1413 |
1414 | [[package]]
1415 | name = "windows_aarch64_msvc"
1416 | version = "0.52.5"
1417 | source = "registry+https://github.com/rust-lang/crates.io-index"
1418 | checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
1419 |
1420 | [[package]]
1421 | name = "windows_i686_gnu"
1422 | version = "0.52.5"
1423 | source = "registry+https://github.com/rust-lang/crates.io-index"
1424 | checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
1425 |
1426 | [[package]]
1427 | name = "windows_i686_gnullvm"
1428 | version = "0.52.5"
1429 | source = "registry+https://github.com/rust-lang/crates.io-index"
1430 | checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
1431 |
1432 | [[package]]
1433 | name = "windows_i686_msvc"
1434 | version = "0.52.5"
1435 | source = "registry+https://github.com/rust-lang/crates.io-index"
1436 | checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
1437 |
1438 | [[package]]
1439 | name = "windows_x86_64_gnu"
1440 | version = "0.52.5"
1441 | source = "registry+https://github.com/rust-lang/crates.io-index"
1442 | checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
1443 |
1444 | [[package]]
1445 | name = "windows_x86_64_gnullvm"
1446 | version = "0.52.5"
1447 | source = "registry+https://github.com/rust-lang/crates.io-index"
1448 | checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
1449 |
1450 | [[package]]
1451 | name = "windows_x86_64_msvc"
1452 | version = "0.52.5"
1453 | source = "registry+https://github.com/rust-lang/crates.io-index"
1454 | checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
1455 |
1456 | [[package]]
1457 | name = "zeroize"
1458 | version = "1.7.0"
1459 | source = "registry+https://github.com/rust-lang/crates.io-index"
1460 | checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d"
1461 |
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | # Metadata about the package.
3 | authors = ["The Hash (HSH) library contributors "]
4 | build = "build.rs"
5 | categories = [
6 | "algorithms",
7 | "authentication",
8 | "cryptography",
9 | "data-structures",
10 | "encoding",
11 | ]
12 | description = """
13 | Quantum-Resistant Cryptographic Hash Library for Password Encryption and
14 | Verification in Rust.
15 | """
16 | documentation = "https://docs.rs/hsh"
17 | edition = "2021"
18 | exclude = [
19 | "/.git/*",
20 | "/.github/*",
21 | "/.gitignore",
22 | "/.vscode/*"
23 | ]
24 | homepage = "https://hshlib.com/"
25 | include = [
26 | "/CONTRIBUTING.md",
27 | "/LICENSE-APACHE",
28 | "/LICENSE-MIT",
29 | "/benches/**",
30 | "/build.rs",
31 | "/Cargo.toml",
32 | "/examples/**",
33 | "/README.md",
34 | "/src/**",
35 | "/tests/**",
36 | ]
37 | keywords = ["argon2", "argon2i", "hash", "password", "security"]
38 | license = "MIT OR Apache-2.0"
39 | name = "hsh"
40 | readme = "README.md"
41 | repository = "https://github.com/sebastienrousseau/hsh/"
42 | rust-version = "1.60"
43 | version = "0.0.8"
44 |
45 | [[bench]]
46 | # Benchmarking configuration.
47 | name = "benchmark"
48 | harness = false
49 | path = "benches/criterion.rs"
50 |
51 | [profile.bench]
52 | debug = true
53 |
54 | [[example]]
55 | # Example configuration.
56 | name = "hsh"
57 | path = "examples/hsh.rs"
58 |
59 | [dependencies]
60 | # Dependencies of the package.
61 | argon2rs = "0.2.5"
62 | base64 = "0.22.1"
63 | bcrypt = "0.16.0"
64 | dtt = "0.0.9"
65 | log = {version="0.4.25", features = ["std"] }
66 | scrypt = "0.11.0"
67 | serde = { version = "1.0.216", features = ["derive"] }
68 | serde_json = "1.0.137"
69 | vrd = "0.0.8"
70 |
71 | [dev-dependencies]
72 | # Dependencies for testing and development.
73 | assert_cmd = "2.0.14"
74 | criterion = "0.5.1"
75 |
76 | [lib]
77 | # Metadata about the library.
78 | crate-type = ["lib"]
79 | name = "hsh"
80 | path = "src/lib.rs"
81 |
82 | [features]
83 | # No default features
84 | default = []
85 |
86 | [package.metadata.docs.rs]
87 | targets = ["x86_64-unknown-linux-gnu"]
88 | rustdoc-args = ["--generate-link-to-definition"]
89 |
90 | # Linting config
91 | [lints.rust]
92 |
93 | ## Warn
94 | # box_pointers = "warn"
95 | missing_copy_implementations = "warn"
96 | missing_docs = "warn"
97 | unstable_features = "warn"
98 | # unused_crate_dependencies = "warn"
99 | unused_extern_crates = "warn"
100 | unused_results = "warn"
101 |
102 | ## Allow
103 | bare_trait_objects = "allow"
104 | elided_lifetimes_in_paths = "allow"
105 | non_camel_case_types = "allow"
106 | non_upper_case_globals = "allow"
107 | trivial_bounds = "allow"
108 | unsafe_code = "allow"
109 |
110 | ## Forbid
111 | missing_debug_implementations = "forbid"
112 | non_ascii_idents = "forbid"
113 | unreachable_pub = "forbid"
114 |
115 | ## Deny
116 | dead_code = "deny"
117 | deprecated_in_future = "deny"
118 | ellipsis_inclusive_range_patterns = "deny"
119 | explicit_outlives_requirements = "deny"
120 | future_incompatible = { level = "deny", priority = -1 }
121 | keyword_idents = "deny"
122 | macro_use_extern_crate = "deny"
123 | meta_variable_misuse = "deny"
124 | missing_fragment_specifier = "deny"
125 | noop_method_call = "deny"
126 | pointer_structural_match = "deny"
127 | rust_2018_idioms = { level = "deny", priority = -1 }
128 | rust_2021_compatibility = { level = "deny", priority = -1 }
129 | single_use_lifetimes = "deny"
130 | trivial_casts = "deny"
131 | trivial_numeric_casts = "deny"
132 | unused = { level = "deny", priority = -1 }
133 | unused_features = "deny"
134 | unused_import_braces = "deny"
135 | unused_labels = "deny"
136 | unused_lifetimes = "deny"
137 | unused_macro_rules = "deny"
138 | unused_qualifications = "deny"
139 | variant_size_differences = "deny"
140 |
141 | [package.metadata.clippy]
142 | warn-lints = ["clippy::all", "clippy::pedantic", "clippy::cargo", "clippy::nursery"]
143 |
144 | [profile.dev]
145 | codegen-units = 256
146 | debug = true
147 | debug-assertions = true
148 | incremental = true
149 | lto = false
150 | opt-level = 0
151 | overflow-checks = true
152 | panic = 'unwind'
153 | rpath = false
154 | strip = false
155 |
156 | [profile.release]
157 | codegen-units = 1
158 | debug = false
159 | debug-assertions = false
160 | incremental = false
161 | lto = true
162 | opt-level = "s"
163 | overflow-checks = false
164 | panic = "abort"
165 | rpath = false
166 | strip = "symbols"
167 |
168 | [profile.test]
169 | codegen-units = 256
170 | debug = true
171 | debug-assertions = true
172 | incremental = true
173 | lto = false
174 | opt-level = 0
175 | overflow-checks = true
176 | rpath = false
177 | strip = false
178 |
--------------------------------------------------------------------------------
/LICENSE-APACHE:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright © 2022-2023 Mini Functions. All rights reserved.
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | https://opensource.org/licenses/Apache-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
203 |
--------------------------------------------------------------------------------
/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022-2023 Sebastien Rousseau
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 | # Hash (HSH)
8 |
9 | Quantum-Resistant Cryptographic Hash Library for Password Hashing and
10 | Verification
11 |
12 | *Part of the [Mini Functions][0] family of libraries.*
13 |
14 |
15 |
16 |
17 |
18 | ![Hash (HSH) Banner][banner]
19 |
20 | [![Made With Rust][made-with-rust]][6] [![Crates.io][crates-badge]][8]
21 | [![Lib.rs][libs-badge]][10] [![Docs.rs][docs-badge]][9]
22 | [![License][license-badge]][2] [![Codecov][codecov-badge]][11]
23 |
24 | • [Website][0] • [Documentation][9] • [Report Bug][3]
25 | • [Request Feature][3] • [Contributing Guidelines][4]
26 |
27 |
28 |
29 |
30 |
31 | ![divider][divider]
32 |
33 | ## Overview 📖
34 |
35 | The `Hash (HSH)` Rust library provides an interface for implementing
36 | secure hash and digest algorithms, specifically designed for password
37 | encryption and verification.
38 |
39 | The library provides a simple API that makes it easy to store and verify
40 | hashed passwords. It enables robust security for passwords, using the
41 | latest advancements in `Quantum-resistant cryptography`. Quantum-
42 | resistant cryptography refers to cryptographic algorithms, usually
43 | public-key algorithms, that are thought to be secure against an attack
44 | by a quantum computer. As quantum computing continues to advance, this
45 | feature of the library assures that the passwords managed through this
46 | system remain secure even against cutting-edge computational
47 | capabilities.
48 |
49 | The library supports the following Password Hashing Schemes (Password
50 | Based Key Derivation Functions):
51 |
52 | - [**Argon2i**](): A cutting-edge
53 | and highly secure key derivation function designed to protect against
54 | both traditional brute-force attacks and rainbow table attacks.
55 | (Recommended)
56 | - [**Bcrypt**](): A password
57 | hashing function designed to be secure against brute-force attacks.
58 | It is a work-factor function, which means that it takes a certain
59 | amount of time to compute. This makes it difficult to attack with a
60 | brute-force algorithm.
61 | - [**Scrypt**](): A password
62 | hashing function designed to be secure against both brute-force
63 | attacks and rainbow table attacks. It is a memory-hard and work-
64 | factor function, which means that it requires a lot of memory and
65 | time to compute. This makes it very difficult to attack with a GPU
66 | or other parallel computing device.
67 |
68 | The library is a valuable tool for developers who need to store and
69 | verify passwords in a secure manner. It is easy to use and can be
70 | integrated into a variety of applications.
71 |
72 | ## Features ✨
73 |
74 | - **Compliant with multiple Password Hashing Schemes (Password Based Key Derivation Functions) such as Argon2i, Bcrypt and Scrypt.** This makes the library more versatile and can be used in a variety of applications.
75 | - **Quantum-resistant, making it secure against future attacks using quantum computers.** This is an important feature as quantum computers become more powerful.
76 | - **Easy to use.** The library provides a simple API that makes it easy to store and verify hashed passwords.
77 | - **Can be integrated into a variety of applications.** The library is written in Rust, which makes it easy to integrate into any Rust project and is fast, efficient, and secure.
78 |
79 | ### Secure password storage
80 |
81 | Hash (HSH) provides a secure way to store and verify hashed passwords.
82 | Passwords are hashed using the argon2i, bcrypt, scrypt algorithms, which
83 | are considered one of the most secure hashing algorithms available
84 | today. The library provides a simple interface for generating and
85 | verifying hashes, making it easy to implement secure password storage
86 | in any Rust application.
87 |
88 | ### Easy to use
89 |
90 | Hash (HSH) includes simple functions for generating and verifying
91 | password hashes, and managing password and salt values. Developers can
92 | easily integrate the library into their Rust projects and start using
93 | it right away. The library is designed to be intuitive and easy to use,
94 | so developers can build apps without worrying about password security.
95 |
96 | ### Flexible
97 |
98 | Hash (HSH) allows users to customize the length of passwords and salts
99 | used in generating hashes. This flexibility allows developers to tailor
100 | the library to their specific needs, whether they require shorter or
101 | longer password and salt values. The library also includes macros that
102 | make it easy to work with the Hash structure, allowing developers to
103 | quickly and easily set and retrieve password and salt values.
104 |
105 | ### Lightweight
106 |
107 | Hash (HSH) is a lightweight library that can easily integrate into any
108 | Rust project. The library has no external dependencies and is efficient.
109 | It means that developers can add secure password storage to their
110 | applications without having to worry about significant performance
111 | overheads.
112 |
113 | ## Installation 📦
114 |
115 | It takes just a few minutes to get up and running with `hsh`.
116 |
117 | ### Requirements
118 |
119 | The minimum supported Rust toolchain version is currently Rust
120 | **1.60** or later (stable). It is recommended that you install the
121 | latest stable version of Rust.
122 |
123 | ### Platform support
124 |
125 | `hsh` supports a variety of CPU architectures. It is supported and tested on
126 | MacOS, Linux, and Windows.
127 |
128 | ### Documentation
129 |
130 | > ℹ️ **Info:** Please check out our [website][0] for more information
131 | and find our documentation on [docs.rs][9], [lib.rs][10] and
132 | [crates.io][8].
133 |
134 | ## Usage 📖
135 |
136 | To use `hsh` in your project, add the following to your `Cargo.toml`
137 | file:
138 |
139 | ```toml
140 | [dependencies]
141 | hsh = "0.0.8"
142 | ```
143 |
144 | Add the following to your `main.rs` file:
145 |
146 | ```rust
147 | extern crate hsh;
148 | use hsh::*;
149 | ```
150 |
151 | then you can use the functions in your application code.
152 |
153 | ### Examples
154 |
155 | `Hash (HSH)` comes with a set of examples that you can use to get
156 | started. The examples are located in the `examples` directory of the
157 | project. To run the examples, clone the repository and run the following
158 | command in your terminal from the project root directory.
159 |
160 | ```shell
161 | cargo run --example hsh
162 | ```
163 |
164 | ## Semantic Versioning Policy 🚥
165 |
166 | For transparency into our release cycle and in striving to maintain
167 | backward compatibility, `Hash (HSH)` follows [semantic versioning][7].
168 |
169 | ## License 📝
170 |
171 | The project is licensed under the terms of both the MIT license and the
172 | Apache License (Version 2.0).
173 |
174 | - [Apache License, Version 2.0][1]
175 | - [MIT license][2]
176 |
177 | ## Contribution 🤝
178 |
179 | Unless you explicitly state otherwise, any contribution intentionally
180 | submitted for inclusion in the work by you, as defined in the Apache-2.0
181 | license, shall be dual licensed as above, without any additional terms
182 | or conditions.
183 |
184 | ![divider][divider]
185 |
186 | ## Acknowledgements 💙
187 |
188 | A big thank you to all the awesome contributors of [Mini Functions][6]
189 | for their help and support.
190 |
191 | And a special thank you goes to the
192 | [Rust Reddit](https://www.reddit.com/r/rust/) community for providing a
193 | lot of useful suggestions on how to improve this project.
194 |
195 | [0]: https://minifunctions.com/hsh
196 | [1]: http://www.apache.org/licenses/LICENSE-2.0
197 | [2]: http://opensource.org/licenses/MIT
198 | [3]: https://github.com/sebastienrousseau/hsh/issues
199 | [4]: https://raw.githubusercontent.com/sebastienrousseau/hsh/main/.github/CONTRIBUTING.md
200 | [6]: https://github.com/sebastienrousseau/hsh/graphs/contributors
201 | [7]: http://semver.org/
202 | [8]: https://crates.io/crates/hsh
203 | [9]: https://docs.rs/hsh
204 | [10]: https://lib.rs/crates/hsh
205 | [11]: https://codecov.io/github/sebastienrousseau/hsh
206 |
207 | [banner]: https://kura.pro/hsh/images/titles/title-hsh.svg "Hash (HSH) Banner"
208 | [codecov-badge]: https://img.shields.io/codecov/c/github/sebastienrousseau/cmn?style=for-the-badge&token=DMNW4DN0LO 'Codecov'
209 | [crates-badge]: https://img.shields.io/crates/v/hsh.svg?style=for-the-badge 'Crates.io'
210 | [divider]: https://kura.pro/common/images/elements/divider.svg "divider"
211 | [docs-badge]: https://img.shields.io/docsrs/hsh.svg?style=for-the-badge 'Docs.rs'
212 | [libs-badge]: https://img.shields.io/badge/lib.rs-v0.0.8-orange.svg?style=for-the-badge 'Lib.rs'
213 | [license-badge]: https://img.shields.io/crates/l/hsh.svg?style=for-the-badge 'License'
214 | [made-with-rust]: https://img.shields.io/badge/rust-f04041?style=for-the-badge&labelColor=c0282d&logo=rust 'Made With Rust'
215 |
--------------------------------------------------------------------------------
/TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 | # Hash (HSH) v0.0.8
8 |
9 | Quantum-Resistant Cryptographic Hash Library for Password Hashing and
10 | Verification
11 |
12 | *Part of the [Mini Functions][0] family of libraries.*
13 |
14 |
15 |
16 |
17 |
18 | ![Hash (HSH) Banner][banner]
19 |
20 | [![Made With Rust][made-with-rust]][6] [![Crates.io][crates-badge]][8]
21 | [![Lib.rs][libs-badge]][10] [![Docs.rs][docs-badge]][9]
22 | [![License][license-badge]][2] [![Codecov][codecov-badge]][11]
23 |
24 | • [Website][0] • [Documentation][9] • [Report Bug][3]
25 | • [Request Feature][3] • [Contributing Guidelines][4]
26 |
27 |
28 |
29 |
30 |
31 | ![divider][divider]
32 |
33 | ## Overview 📖
34 |
35 | The `Hash (HSH)` Rust library provides an interface for implementing secure hash and digest algorithms, specifically designed for password encryption and verification.
36 |
37 | The library provides a simple API that makes it easy to store and verify hashed passwords. It enables robust security for passwords, using the latest advancements in **Quantum-resistant cryptography**. Quantum-resistant cryptography refers to cryptographic algorithms, that are thought to be secure against an attack by a quantum computer. As quantum computing continues to advance, this feature of the library assures that the passwords managed through this system remain secure even against cutting-edge computational capabilities.
38 |
39 | The library supports the following Password Hashing Schemes (Password Based Key Derivation Functions):
40 |
41 | - [**Argon2i**](): A cutting-edge and highly secure key derivation function designed to protect against both traditional brute-force attacks and rainbow table attacks. (Recommended)
42 | - [**Bcrypt**](): A password hashing function designed to be secure against brute-force attacks. It is a work-factor function, which means that it takes a certain amount of time to compute. This makes it difficult to attack with a brute-force algorithm.
43 | - [**Scrypt**](): A password hashing function designed to be secure against both brute-force attacks and rainbow table attacks. It is a memory-hard and work-factor function, which means that it requires a lot of memory and time to compute. This makes it very difficult to attack with a GPU or other parallel computing device.
44 |
45 | The library is a valuable tool for developers who need to store and verify passwords in a secure manner. It is easy to use and can be integrated into a variety of applications.
46 |
47 | ## Features ✨
48 |
49 | - **Compliant with multiple Password Hashing Schemes (Password Based Key Derivation Functions) such as Argon2i, Bcrypt and Scrypt.** This makes the library more versatile and can be used in a variety of applications.
50 | - **Quantum-resistant, making it secure against future attacks using quantum computers.** This is an important feature as quantum computers become more powerful.
51 | - **Easy to use.** The library provides a simple API that makes it easy to store and verify hashed passwords.
52 | - **Can be integrated into a variety of applications.** The library is written in Rust, which makes it easy to integrate into any Rust project and is fast, efficient, and secure.
53 |
54 | ### Secure password storage
55 |
56 | Hash (HSH) provides a secure way to store and verify hashed passwords. Passwords are hashed using the argon2i, bcrypt, scrypt algorithms, which are considered one of the most secure hashing algorithms available today. The library provides a simple interface for generating and verifying hashes, making it easy to implement secure password storage in any Rust application.
57 |
58 | ### Easy to use
59 |
60 | Hash (HSH) includes simple functions for generating and verifying password hashes, and managing password and salt values. Developers can easily integrate the library into their Rust projects and start using it right away. The library is designed to be intuitive and easy to use, so developers can build apps without worrying about password security.
61 |
62 | ### Flexible
63 |
64 | Hash (HSH) allows users to customize the length of passwords and salts used in generating hashes. This flexibility allows developers to tailor the library to their specific needs, whether they require shorter or longer password and salt values. The library also includes macros that make it easy to work with the Hash structure, allowing developers to quickly and easily set and retrieve password and salt values.
65 |
66 | ### Lightweight
67 |
68 | Hash (HSH) is a lightweight library that can easily integrate into any Rust project. The library has no external dependencies and is efficient. It means that developers can add secure password storage to their applications without having to worry about significant performance overheads.
69 |
70 | [0]: https://minifunctions.com/hsh
71 | [2]: http://opensource.org/licenses/MIT
72 | [3]: https://github.com/sebastienrousseau/hsh/issues
73 | [4]: https://raw.githubusercontent.com/sebastienrousseau/hsh/main/.github/CONTRIBUTING.md
74 | [6]: https://github.com/sebastienrousseau/hsh/graphs/contributors
75 | [8]: https://crates.io/crates/hsh
76 | [9]: https://docs.rs/hsh
77 | [10]: https://lib.rs/crates/hsh
78 | [11]: https://codecov.io/github/sebastienrousseau/hsh
79 |
80 | [banner]: https://kura.pro/hsh/images/titles/title-hsh.svg "Hash (HSH) Banner"
81 | [codecov-badge]: https://img.shields.io/codecov/c/github/sebastienrousseau/cmn?style=for-the-badge&token=DMNW4DN0LO 'Codecov'
82 | [crates-badge]: https://img.shields.io/crates/v/hsh.svg?style=for-the-badge 'Crates.io'
83 | [divider]: https://kura.pro/common/images/elements/divider.svg "divider"
84 | [docs-badge]: https://img.shields.io/docsrs/hsh.svg?style=for-the-badge 'Docs.rs'
85 | [libs-badge]: https://img.shields.io/badge/lib.rs-v0.0.8-orange.svg?style=for-the-badge 'Lib.rs'
86 | [license-badge]: https://img.shields.io/crates/l/hsh.svg?style=for-the-badge 'License'
87 | [made-with-rust]: https://img.shields.io/badge/rust-f04041?style=for-the-badge&labelColor=c0282d&logo=rust 'Made With Rust'
88 |
89 | ## Changelog 📚
90 |
91 | -
92 |
--------------------------------------------------------------------------------
/benches/criterion.rs:
--------------------------------------------------------------------------------
1 | // Copyright © 2023-2024 Hash (HSH) library. All rights reserved.
2 | // SPDX-License-Identifier: Apache-2.0 OR MIT
3 |
4 | //! Benchmarking the Hash (HSH) library using Criterion.rs
5 |
6 | #![allow(missing_docs)]
7 |
8 | use criterion::{
9 | black_box, criterion_group, criterion_main, Criterion,
10 | };
11 | use hsh::models::hash::Hash;
12 |
13 | #[allow(unused_results)]
14 | fn generate_hash_benchmark(c: &mut Criterion) {
15 | c.bench_function("generate_hash", |b| {
16 | b.iter(|| {
17 | Hash::generate_hash(
18 | black_box("password"),
19 | black_box("salt12345"),
20 | black_box("argon2i"),
21 | )
22 | })
23 | });
24 | }
25 |
26 | #[allow(unused_results)]
27 | fn new_hash_benchmark(c: &mut Criterion) {
28 | c.bench_function("new_hash", |b| {
29 | b.iter(|| {
30 | Hash::new(
31 | black_box("password"),
32 | black_box("salt12345"),
33 | black_box("argon2i"),
34 | )
35 | })
36 | });
37 | }
38 |
39 | #[allow(unused_results)]
40 | fn set_password_benchmark(c: &mut Criterion) {
41 | let mut hash =
42 | Hash::new("password", "salt12345", "argon2i").unwrap(); // Unwrap the Result
43 |
44 | c.bench_function("set_password", |b| {
45 | b.iter(|| {
46 | Hash::set_password(
47 | &mut hash, // Pass the `hash` instance
48 | black_box("new_password"),
49 | black_box("new_salt12345"),
50 | black_box("argon2i"),
51 | )
52 | .unwrap() // Unwrap the Result
53 | })
54 | });
55 | }
56 |
57 | #[allow(unused_results)]
58 | fn verify_benchmark(c: &mut Criterion) {
59 | let hash = Hash::new("password", "salt12345", "argon2i").unwrap(); // Unwrap the Result
60 |
61 | c.bench_function("verify", |b| {
62 | b.iter(|| hash.verify(black_box("password")).unwrap()) // Call verify on the instance
63 | });
64 | }
65 |
66 | // Run the benchmarks in a group
67 | criterion_group!(
68 | // Run `benches`
69 | benches,
70 | // Run `generate_hash_benchmark`
71 | generate_hash_benchmark,
72 | // Run `new_hash_benchmark`
73 | new_hash_benchmark,
74 | // Run `set_password_benchmark`
75 | set_password_benchmark,
76 | // Run `verify_benchmark`
77 | verify_benchmark
78 | );
79 |
80 | criterion_main!(benches);
81 |
--------------------------------------------------------------------------------
/build.rs:
--------------------------------------------------------------------------------
1 | // Copyright © 2023-2024 Hash (HSH) library. All rights reserved.
2 | // SPDX-License-Identifier: Apache-2.0 OR MIT
3 |
4 | //! This is the main function for the build script.
5 | //!
6 | //! Currently, it only instructs Cargo to re-run this build script if `build.rs` is changed.
7 | fn main() {
8 | // Avoid unnecessary re-building.
9 | println!("cargo:rerun-if-changed=build.rs");
10 | }
11 |
--------------------------------------------------------------------------------
/deny.toml:
--------------------------------------------------------------------------------
1 | [licenses]
2 | # The lint level for crates which do not have a detectable license
3 | unlicensed = "deny"
4 |
5 | # List of explicitly allowed licenses
6 | # See https://spdx.org/licenses/ for list of possible licenses
7 | # [possible values: any SPDX 3.7 short identifier (+ optional exception)].
8 | allow = [
9 | "Apache-2.0",
10 | "MIT",
11 | "CC0-1.0",
12 | "ISC",
13 | "0BSD",
14 | "BSD-2-Clause",
15 | "BSD-3-Clause",
16 | "Unlicense",
17 | "Unicode-DFS-2016",
18 | ]
19 |
20 | # List of banned licenses
21 | [bans]
22 | multiple-versions = "deny"
23 |
24 |
25 | # The lint level for licenses considered copyleft
26 | copyleft = "deny"
27 |
28 | # Blanket approval or denial for OSI-approved or FSF Free/Libre licenses
29 | # * both - The license will only be approved if it is both OSI-approved *AND* FSF/Free
30 | # * either - The license will be approved if it is either OSI-approved *OR* FSF/Free
31 | # * osi-only - The license will be approved if is OSI-approved *AND NOT* FSF/Free
32 | # * fsf-only - The license will be approved if is FSF/Free *AND NOT* OSI-approved
33 | # * neither - The license will be denied if is FSF/Free *OR* OSI-approved
34 | allow-osi-fsf-free = "either"
35 |
36 | # The confidence threshold for detecting a license from license text.
37 | # The higher the value, the more closely the license text must be to the
38 | # canonical license text of a valid SPDX license file.
39 | # [possible values: any between 0.0 and 1.0].
40 | confidence-threshold = 0.8
41 |
42 | # The graph highlighting used when creating dotgraphs for crates
43 | # with multiple versions
44 | # * lowest-version - The path to the lowest versioned duplicate is highlighted
45 | # * simplest-path - The path to the version with the fewest edges is highlighted
46 | # * all - Both lowest-version and simplest-path are used
47 | highlight = "all"
48 |
49 | # List of crates that are allowed. Use with care!
50 | allow = []
51 |
52 | # List of crates to deny
53 | deny = [
54 | # Each entry the name of a crate and a version range. If version is
55 | # not specified, all versions will be matched.
56 | ]
57 |
58 | # Certain crates/versions that will be skipped when doing duplicate detection.
59 | skip = []
60 |
61 | # Similarly to `skip` allows you to skip certain crates during duplicate detection,
62 | # unlike skip, it also includes the entire tree of transitive dependencies starting at
63 | # the specified crate, up to a certain depth, which is by default infinite
64 | skip-tree = []
65 |
66 |
67 | [advisories]
68 | notice = "deny"
69 | unmaintained = "deny"
70 | unsound = "deny"
71 | vulnerability = "deny"
--------------------------------------------------------------------------------
/examples/hsh.rs:
--------------------------------------------------------------------------------
1 | // Copyright © 2023-2024 Hash (HSH) library. All rights reserved.
2 | // SPDX-License-Identifier: Apache-2.0 OR MIT
3 |
4 | //! Using the Hash (HSH) library
5 |
6 | use hsh::{
7 | models::{hash::Hash, hash_algorithm::HashAlgorithm},
8 | new_hash,
9 | };
10 | use std::str::FromStr;
11 |
12 | /// This function demonstrates how to create and verify password hashes using Argon2i, Bcrypt, and Scrypt algorithms.
13 | ///
14 | /// # Example
15 | ///
16 | /// ```rust
17 | /// use hsh::models::{hash::Hash, salt::Salt};
18 | ///
19 | /// // Function to create and verify hash
20 | /// fn create_and_verify_hash() {
21 | /// // Create new hashes for Argon2i, Bcrypt, and Scrypt
22 | /// let password = "password";
23 | /// let salt_argon2i: Salt = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
24 | /// let salt_scrypt: Salt = vec![10, 11, 12, 13, 14, 15, 16, 17, 18, 19];
25 | /// let cost_bcrypt = 16;
26 | ///
27 | /// let hash_argon2i = Hash::new_argon2i(password, salt_argon2i).unwrap();
28 | /// let hash_bcrypt = Hash::new_bcrypt(password, cost_bcrypt).unwrap();
29 | /// let hash_scrypt = Hash::new_scrypt(password, salt_scrypt).unwrap();
30 | ///
31 | /// // Verify these hashes
32 | /// verify_password(&hash_argon2i, "password", "Argon2i");
33 | /// verify_password(&hash_bcrypt, "password", "BCrypt");
34 | /// verify_password(&hash_scrypt, "password", "Scrypt");
35 | ///
36 | /// // ... (the rest of the function)
37 | /// }
38 | /// ```
39 | ///
40 | /// Note: This is a simplified example, and in a real-world application, you should handle errors and edge cases more carefully.
41 | fn create_and_verify_hash() {
42 | // Create new hashes for Argon2i, Bcrypt, and Scrypt
43 | let hash_argon2i =
44 | Hash::new_argon2i("password", "salt1234".into()).unwrap();
45 | let hash_bcrypt = Hash::new_bcrypt("password", 16).unwrap();
46 | let hash_scrypt =
47 | Hash::new_scrypt("password", "salt1234".into()).unwrap();
48 |
49 | // Verify these hashes
50 | verify_password(&hash_argon2i, "password", "Argon2i");
51 | verify_password(&hash_bcrypt, "password", "BCrypt");
52 | verify_password(&hash_scrypt, "password", "Scrypt");
53 |
54 | // Update the hashes
55 | let mut new_hash_argon2i = hash_argon2i.clone();
56 | new_hash_argon2i
57 | .set_password("new_password", "salt1234", "argon2i")
58 | .unwrap();
59 |
60 | let mut new_hash_bcrypt = hash_bcrypt.clone();
61 | new_hash_bcrypt
62 | .set_password("new_password", "salt1234", "bcrypt")
63 | .unwrap();
64 |
65 | let mut new_hash_scrypt = hash_scrypt.clone();
66 | new_hash_scrypt
67 | .set_password("new_password", "salt1234", "scrypt")
68 | .unwrap();
69 |
70 | // Verify the updated hashes
71 | verify_password(&new_hash_argon2i, "new_password", "Argon2i");
72 | verify_password(&new_hash_bcrypt, "new_password", "BCrypt");
73 | verify_password(&new_hash_scrypt, "new_password", "Scrypt");
74 | }
75 |
76 | // Function to verify the password
77 | fn verify_password(hash: &Hash, password: &str, algorithm: &str) {
78 | // Print header
79 | println!(
80 | "\n===[ Verifying Password with {} Algorithm ]===\n",
81 | algorithm
82 | );
83 |
84 | let is_valid = hash.verify(password);
85 | match is_valid {
86 | Ok(valid) => {
87 | println!("Algorithm: {}", algorithm);
88 | println!(
89 | "Provided password for verification: {}",
90 | password
91 | );
92 | println!(
93 | "Salt used for verification: {}",
94 | String::from_utf8_lossy(hash.salt())
95 | );
96 | println!(
97 | "🦀 Password verification result for {}: ✅ {:?}",
98 | algorithm, valid
99 | );
100 | }
101 | Err(e) => {
102 | eprintln!(
103 | "🦀 Error during password verification for {}: ❌ {}",
104 | algorithm, e
105 | );
106 | }
107 | }
108 |
109 | // Print footer
110 | println!("\n==================================================\n");
111 | }
112 |
113 | // Function to parse and display hash algorithms and their string representations
114 | fn parse_and_display_hash() {
115 | // Print header for parsing algorithms
116 | println!("\n===[ Parsing Hash Algorithms ]===\n");
117 |
118 | let parsed_argon2i = HashAlgorithm::from_str("argon2i").unwrap();
119 | let parsed_bcrypt = HashAlgorithm::from_str("bcrypt").unwrap();
120 | let parsed_scrypt = HashAlgorithm::from_str("scrypt").unwrap();
121 |
122 | println!("🦀 Parsed Argon2i hash algorithm: {}", parsed_argon2i);
123 | println!("🦀 Parsed Bcrypt hash algorithm: {}", parsed_bcrypt);
124 | println!("🦀 Parsed Scrypt hash algorithm: {}", parsed_scrypt);
125 |
126 | // Print footer for parsing algorithms
127 | println!("\n======================================\n");
128 |
129 | // Print header for hash to string conversion
130 | println!("\n===[ Hash to String Conversion ]===\n");
131 |
132 | let argon2i_hash = new_hash!("password", "salt12345", "argon2i");
133 | let bcrypt_hash = new_hash!("password", "salt12345", "bcrypt");
134 | let scrypt_hash = new_hash!("password", "salt12345", "scrypt");
135 |
136 | let argon2i_hash_string = match argon2i_hash {
137 | Ok(hash) => hash.to_string_representation(),
138 | Err(e) => format!("Error: {}", e),
139 | };
140 | let bcrypt_hash_string = match bcrypt_hash {
141 | Ok(hash) => hash.to_string_representation(),
142 | Err(e) => format!("Error: {}", e),
143 | };
144 | let scrypt_hash_string = match scrypt_hash {
145 | Ok(hash) => hash.to_string_representation(),
146 | Err(e) => format!("Error: {}", e),
147 | };
148 |
149 | println!("🦀 Argon2i Hash to a string: {}", argon2i_hash_string);
150 | println!("🦀 Bcrypt Hash to a string: {}", bcrypt_hash_string);
151 | println!("🦀 Scrypt Hash to a string: {}", scrypt_hash_string);
152 |
153 | // Print footer for hash to string conversion
154 | println!("\n========================================\n");
155 | }
156 |
157 | // Main function
158 | fn main() {
159 | create_and_verify_hash();
160 | parse_and_display_hash();
161 | }
162 |
--------------------------------------------------------------------------------
/rustfmt.toml:
--------------------------------------------------------------------------------
1 | edition = "2021"
2 | max_width = 72
3 | tab_spaces = 4
4 | use_field_init_shorthand = true
--------------------------------------------------------------------------------
/src/algorithms/argon2i.rs:
--------------------------------------------------------------------------------
1 | // Copyright © 2023-2024 Hash (HSH) library. All rights reserved.
2 | // SPDX-License-Identifier: Apache-2.0 OR MIT
3 |
4 | use crate::models::hash_algorithm::HashingAlgorithm;
5 | use argon2rs::argon2i_simple;
6 | use serde::{Deserialize, Serialize};
7 |
8 | /// Implementation of the Argon2i hashing algorithm.
9 | ///
10 | /// `Argon2i` is a struct that represents the Argon2i hashing algorithm,
11 | /// which is a memory-hard algorithm resistant to GPU-based attacks and side-channel attacks.
12 | /// It is one of the multiple hashing algorithms that can be used for password hashing in this library.
13 | ///
14 | /// This struct implements the `HashingAlgorithm` trait, providing a concrete implementation
15 | /// for hashing passwords using the Argon2i algorithm.
16 | #[derive(
17 | Clone,
18 | Copy,
19 | Debug,
20 | Eq,
21 | Hash,
22 | Ord,
23 | PartialEq,
24 | PartialOrd,
25 | Serialize,
26 | Deserialize,
27 | )]
28 | pub struct Argon2i;
29 |
30 | impl HashingAlgorithm for Argon2i {
31 | /// Hashes a given password using the Argon2i algorithm.
32 | ///
33 | /// This method computes a hashed representation of the plaintext `password` using the Argon2i algorithm,
34 | /// combined with the provided `salt` for added security.
35 | ///
36 | /// # Parameters
37 | ///
38 | /// - `password`: The plaintext password to be hashed.
39 | /// - `salt`: A cryptographic salt to prevent rainbow table attacks.
40 | ///
41 | /// # Returns
42 | ///
43 | /// Returns a `Result` with `Ok`, containing the hashed password as a vector of bytes.
44 | /// Currently, this function does not handle hashing errors and will always return `Ok`.
45 | fn hash_password(
46 | password: &str,
47 | salt: &str,
48 | ) -> Result, String> {
49 | Ok(argon2i_simple(password, salt).into_iter().collect())
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/algorithms/bcrypt.rs:
--------------------------------------------------------------------------------
1 | // Copyright © 2023-2024 Hash (HSH) library. All rights reserved.
2 | // SPDX-License-Identifier: Apache-2.0 OR MIT
3 |
4 | use crate::models::hash_algorithm::HashingAlgorithm;
5 | use bcrypt::{hash, DEFAULT_COST};
6 | use serde::{Deserialize, Serialize};
7 |
8 | /// Implementation of the Bcrypt hashing algorithm.
9 | ///
10 | /// `Bcrypt` is a struct that represents the Bcrypt hashing algorithm,
11 | /// which is based on the Blowfish cipher and is particularly effective against brute-force attacks.
12 | ///
13 | /// This struct implements the `HashingAlgorithm` trait, providing a concrete implementation
14 | /// for hashing passwords using the Bcrypt algorithm.
15 | ///
16 | /// # Features
17 | ///
18 | /// - Computationally intensive, making brute-force attacks more difficult.
19 | /// - Uses key stretching to make pre-computed attacks (like rainbow tables) less effective.
20 | ///
21 | /// # Examples
22 | ///
23 | /// ```
24 | /// use hsh::models::hash_algorithm::HashingAlgorithm;
25 | /// use hsh::algorithms::bcrypt::Bcrypt;
26 | ///
27 | /// let password = "supersecret";
28 | /// let salt = "randomsalt";
29 | ///
30 | /// let hashed_password = Bcrypt::hash_password(password, salt).unwrap();
31 | /// ```
32 | #[derive(
33 | Clone,
34 | Copy,
35 | Debug,
36 | Eq,
37 | Hash,
38 | Ord,
39 | PartialEq,
40 | PartialOrd,
41 | Serialize,
42 | Deserialize,
43 | )]
44 | pub struct Bcrypt;
45 |
46 | impl HashingAlgorithm for Bcrypt {
47 | /// Hashes a given password using the Bcrypt algorithm.
48 | ///
49 | /// This method computes a hashed representation of the plaintext `password` using the Bcrypt algorithm.
50 | /// Note that the `salt` parameter is not used in this implementation, as Bcrypt generates its own salt internally.
51 | ///
52 | /// # Parameters
53 | ///
54 | /// - `password`: The plaintext password to be hashed.
55 | /// - `_salt`: Unused in this implementation, provided for interface compatibility.
56 | ///
57 | /// # Returns
58 | ///
59 | /// Returns a `Result` containing the hashed password as a vector of bytes.
60 | /// If hashing fails for some reason, returns a `String` detailing the error.
61 | fn hash_password(
62 | password: &str,
63 | _salt: &str,
64 | ) -> Result, String> {
65 | hash(password, DEFAULT_COST)
66 | .map_err(|e| e.to_string())
67 | .map(|hash_parts| hash_parts.into_bytes())
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/algorithms/mod.rs:
--------------------------------------------------------------------------------
1 | // Copyright © 2023-2024 Hash (HSH) library. All rights reserved.
2 | // SPDX-License-Identifier: Apache-2.0 OR MIT
3 |
4 | /// The `argon2i` module contains the Argon2i password hashing algorithm.
5 | pub mod argon2i;
6 |
7 | /// The `bcrypt` module contains the Bcrypt password hashing algorithm.
8 | pub mod bcrypt;
9 |
10 | /// The `scrypt` module contains the Scrypt password hashing algorithm.
11 | pub mod scrypt;
12 |
--------------------------------------------------------------------------------
/src/algorithms/scrypt.rs:
--------------------------------------------------------------------------------
1 | // Copyright © 2023-2024 Hash (HSH) library. All rights reserved.
2 | // SPDX-License-Identifier: Apache-2.0 OR MIT
3 |
4 | use crate::models::hash_algorithm::HashingAlgorithm;
5 | use scrypt::scrypt;
6 | use scrypt::Params;
7 | use serde::{Deserialize, Serialize};
8 |
9 | /// Implementation of the Scrypt hashing algorithm.
10 | ///
11 | /// `Scrypt` is a struct that represents the Scrypt hashing algorithm,
12 | /// which is a memory-hard algorithm designed to be computationally intensive,
13 | /// thereby making it difficult to perform large-scale custom hardware attacks.
14 | ///
15 | /// This struct implements the `HashingAlgorithm` trait, providing a concrete implementation
16 | /// for hashing passwords using the Scrypt algorithm.
17 | #[derive(
18 | Clone,
19 | Copy,
20 | Debug,
21 | Eq,
22 | Hash,
23 | Ord,
24 | PartialEq,
25 | PartialOrd,
26 | Serialize,
27 | Deserialize,
28 | )]
29 | pub struct Scrypt;
30 |
31 | impl HashingAlgorithm for Scrypt {
32 | /// Hashes a given password using the Scrypt algorithm.
33 | ///
34 | /// Given a plaintext `password` and a `salt`, this method returns a hashed representation
35 | /// of the password using the Scrypt algorithm.
36 | ///
37 | /// # Parameters
38 | ///
39 | /// - `password`: The plaintext password to be hashed.
40 | /// - `salt`: A cryptographic salt to prevent rainbow table attacks.
41 | ///
42 | /// # Returns
43 | ///
44 | /// Returns a `Result` containing the hashed password as a vector of bytes.
45 | /// If hashing fails for some reason, it returns a `String` detailing the error.
46 | fn hash_password(
47 | password: &str,
48 | salt: &str,
49 | ) -> Result, String> {
50 | // The `Params` struct is initialized with specific parameters that define the
51 | // computational cost of the hashing process. The parameters used here are chosen
52 | // to provide a balance between security and performance. Adjust these values based
53 | // on the security requirements and the expected computational capacity.
54 | let params =
55 | Params::new(14, 8, 1, 64).map_err(|e| e.to_string())?;
56 | let mut output = [0u8; 64];
57 | scrypt(
58 | password.as_bytes(),
59 | salt.as_bytes(),
60 | ¶ms,
61 | &mut output,
62 | )
63 | .map_err(|e| e.to_string())
64 | .map(|_| output.to_vec())
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/lib.rs:
--------------------------------------------------------------------------------
1 | // Copyright © 2023-2024 Hash (HSH) library. All rights reserved.
2 | // SPDX-License-Identifier: Apache-2.0 OR MIT
3 |
4 | // Copyright © 2023-2024 Hash (HSH) library. All rights reserved.
5 | // SPDX-License-Identifier: Apache-2.0 OR MIT
6 |
7 | //! # Hash (HSH), a Quantum-Resistant Cryptographic Hash Library
8 | //!
9 | //! A Highly Secure Quantum-Resistant Cryptographic Hash Library for Password Encryption and Verification in Rust. Designed with quantum-resistant cryptography, this library provides a robust line of defence against current and emerging computational threats.
10 | //!
11 | //! [![Hash (HSH) Banner][banner]][00]
12 | //!
13 | //! Part of the [Mini Functions][01] family of libraries.
14 | //!
15 | //! [![Available on Crates.io][crate-shield]](https://crates.io/crates/hsh)
16 | //! [![GitHub Repository][github-shield]](https://github.com/sebastienrousseau/hsh)
17 | //! [![Available on Lib.rs][lib-rs-shield]](https://lib.rs/hsh)
18 | //! [![MIT License][license-shield]](http://opensource.org/licenses/MIT)
19 | //! [![Built with Rust][rust-shield]](https://www.rust-lang.org)
20 | //!
21 | //! ## Overview
22 | //!
23 | //! The Hash (HSH) Rust library provides an interface for implementing secure hash and digest algorithms, specifically designed for password encryption and verification.
24 | //!
25 | //! The library provides a simple API that makes it easy to store and verify hashed passwords. It enables robust security for passwords, using the latest advancements in Quantum-resistant cryptography. Quantum- resistant cryptography refers to cryptographic algorithms, usually public-key algorithms, that are thought to be secure against an attack by a quantum computer. As quantum computing continues to advance, this feature of the library assures that the passwords managed through this system remain secure even against cutting-edge computational capabilities.
26 | //!
27 | //! The library supports the following Password Hashing Schemes (Password Based Key Derivation Functions):
28 | //!
29 | //! - **Argon2i**: A cutting-edge and highly secure key derivation function designed to protect against both traditional brute-force attacks and rainbow table attacks. (Recommended)
30 | //! - **Bcrypt**: A password hashing function designed to be secure against brute-force attacks. It is a work-factor function, which means that it takes a certain amount of time to compute. This makes it difficult to attack with a brute-force algorithm.
31 | //! - **Scrypt**: A password hashing function designed to be secure against both brute-force attacks and rainbow table attacks. It is a memory-hard and work- factor function, which means that it requires a lot of memory and time to compute. This makes it very difficult to attack with a GPU or other parallel computing device.
32 | //!
33 | //! ## Features
34 | //!
35 | //! - **Ease of Use**: Simple API for storing and verifying hashed passwords.
36 | //! - **Future-Proof**: Quantum-resistant cryptography to secure against future technological advancements.
37 | //! - **Integrable**: Written in Rust, the library is fast, efficient, and easily integrable into other Rust projects.
38 | //! - **Versatility**: Supports multiple Password Hashing Schemes like Argon2i, Bcrypt, and Scrypt.
39 | //!
40 | //! ## Core Components
41 | //!
42 | //! ### `Hash` Struct
43 | //!
44 | //! Contains:
45 | //!
46 | //! - **algorithm**: Enum representing the hashing algorithm (Argon2i, Bcrypt, Scrypt).
47 | //! - **hash**: Byte vector containing the hashed password.
48 | //! - **salt**: Byte vector containing the salt used in hashing.
49 | //!
50 | //! ### `HashAlgorithm` Enum
51 | //!
52 | //! Provides variants for supported hashing algorithms: Argon2i, Bcrypt, and Scrypt.
53 | //!
54 | //! ## Methods
55 | //!
56 | //! The `Hash` struct offers methods for password hashing and management, including but not limited to:
57 | //!
58 | //! - Creating new Hash objects.
59 | //! - Generating and setting salts and hashes.
60 | //! - Verifying passwords against stored hashes.
61 | //!
62 | //! ## Getting Started
63 | //!
64 | //! Add `Hash (HSH)` as a dependency in your `Cargo.toml` and import it in your main Rust file.
65 | //!
66 | //! ### Example
67 | //!
68 | //! Here's a simple example demonstrating basic usage:
69 | //!
70 | //! ```rust
71 | //! use hsh::models::hash::Hash; // Import the Hash struct
72 | //!
73 | //! let password = "password123";
74 | //! let salt = "somesalt";
75 | //! let algo = "argon2i";
76 | //
77 | //! let original_hash = Hash::new(password, salt, algo).expect("Failed to create hash");
78 | //! let hashed_password = original_hash.hash.clone();
79 | //
80 | //! assert_eq!(original_hash.hash(), &hashed_password);
81 | //! ```
82 | //!
83 | //! ## License
84 | //!
85 | //! Licensed under the MIT and Apache License (Version 2.0).
86 | //!
87 | //! [banner]: https://kura.pro/hsh/images/banners/banner-hsh.webp
88 | //! [crate-shield]: https://img.shields.io/crates/v/hsh.svg?style=for-the-badge&color=success&labelColor=27A006
89 | //! [github-shield]: https://img.shields.io/badge/github-555555?style=for-the-badge&labelColor=000000&logo=github
90 | //! [lib-rs-shield]: https://img.shields.io/badge/lib.rs-v0.0.8-success.svg?style=for-the-badge&color=8A48FF&labelColor=6F36E4
91 | //! [license-shield]: https://img.shields.io/crates/l/hsh.svg?style=for-the-badge&color=007EC6&labelColor=03589B
92 | //! [rust-shield]: https://img.shields.io/badge/rust-f04041?style=for-the-badge&labelColor=c0282d&logo=rust
93 | //!
94 | //! [00]: https://hshlib.com/
95 | //! [01]: https://minifunctions.com/
96 | //! [02]: http://www.apache.org/licenses/LICENSE-2.0
97 | //! [03]: http://opensource.org/licenses/MIT
98 |
99 | #![cfg_attr(feature = "bench", feature(test))]
100 | #![doc(
101 | html_favicon_url = "https://kura.pro/hsh/images/favicon.ico",
102 | html_logo_url = "https://kura.pro/hsh/images/logos/hsh.svg",
103 | html_root_url = "https://docs.rs/hsh"
104 | )]
105 | #![crate_name = "hsh"]
106 | #![crate_type = "lib"]
107 |
108 | /// The `algorithms` module contains the password hashing algorithms.
109 | pub mod algorithms;
110 |
111 | /// The `macros` module contains functions for generating macros.
112 | pub mod macros;
113 |
114 | /// The `models` module contains the data models for the library.
115 | pub mod models;
116 |
117 | /// This is the main entry point for the `Hash (HSH)` library.
118 | pub fn run() -> Result<(), Box> {
119 | if std::env::var("HSH_TEST_MODE").unwrap_or_default() == "1" {
120 | return Err("Simulated error".into());
121 | }
122 |
123 | let name = "hsh";
124 | println!("Welcome to `{}` 👋!", name.to_uppercase());
125 | println!(
126 | "Quantum-Resistant Cryptographic Hash Library for Password Encryption and Verification."
127 | );
128 | Ok(())
129 | }
130 |
--------------------------------------------------------------------------------
/src/macros.rs:
--------------------------------------------------------------------------------
1 | // Copyright © 2023-2024 Hash (HSH) library. All rights reserved.
2 | // SPDX-License-Identifier: Apache-2.0 OR MIT
3 |
4 | //! # Macros for the `hsh` crate.
5 | //!
6 | //! This module contains macros that simplify working with Hash structs.
7 | //!
8 | //! These macros can greatly simplify code that uses the Hash struct,
9 | //! making it easier to read and maintain.
10 | //!
11 | //! ## Generic macros for the hsh crate.
12 | //!
13 | //! This crate provides the following macros:
14 | //!
15 | //! | Macro | Description |
16 | //! |--------|------------|
17 | //! | `hsh` | Calls the `parse` method on the `Hash` struct from the hsh crate. |
18 | //! | `hsh_assert` | Asserts that a given condition is true. If the condition is false, the macro will cause the program to panic with the message "Assertion failed!". |
19 | //! | `hsh_contains` | Checks if a given string contains a specified substring. |
20 | //! | `hsh_in_range` | Checks if a given value is within a specified range (inclusive). |
21 | //! | `hsh_join` | Joins multiple strings together using a specified separator. |
22 | //! | `hsh_max` | Returns the maximum value from a set of given values. |
23 | //! | `hsh_min` | Returns the minimum value from a set of given values. |
24 | //! | `hsh_print` | Prints the given arguments to the console, similar to the `println!` macro. |
25 | //! | `hsh_print_vec` | Prints the elements of a given vector to the console, each on a new line. |
26 | //! | `hsh_split` | Splits a given string into a vector of words, dividing at each occurrence of whitespace. |
27 | //! | `hsh_vec` | Creates a new vector containing the given elements. |
28 | //! | `hsh_parse` | Attempts to parse a given input into a u64 value, returning a Result. |
29 | //!
30 | //! ## HSH Macros
31 | //!
32 | //! The library also provides several macros for common operations on the `Hash` struct:
33 | //!
34 | //! - `to_str_error`: Abstracts away the error handling for the `to_string` method.
35 | //! - `random_string`: Generates a random string of a specified length, consisting of alphanumeric characters.
36 | //! - `match_algo`: Matches given hash algorithm strings to their corresponding enum variants.
37 | //! - `generate_hash`: Generates a new hash for a given password, salt, and algorithm.
38 | //! - `new_hash`: Creates a new instance of the `Hash` struct with a given password, salt, and algorithm.
39 | //! - `hash_length`: Returns the length of the hash for a given `Hash` struct instance.
40 | //!
41 |
42 | /// This macro takes any number of arguments and parses them into a Rust
43 | /// value. The parsed value is returned wrapped in
44 | /// `hsh::Hash::parse()` function call.
45 | ///
46 | #[macro_export]
47 | macro_rules! hsh {
48 | ($($token:tt)*) => {
49 | hsh::Hash::parse($($token)*)
50 | };
51 | }
52 |
53 | /// This macro asserts that the given condition is true. If the
54 | /// condition is false, the macro panics with the message "Assertion
55 | /// failed!".
56 | ///
57 | /// # Example
58 | ///
59 | /// ```
60 | /// extern crate hsh;
61 | /// use hsh::{ hsh_assert };
62 | ///
63 | /// hsh_assert!(1 == 1); // This will not panic
64 | /// hsh_assert!(1 == 2); // This will panic
65 | /// ```
66 | ///
67 | #[macro_export]
68 | macro_rules! hsh_assert {
69 | ($($arg:tt)*) => {
70 | if !$($arg)* {
71 | panic!("Assertion failed!");
72 | }
73 | };
74 | }
75 |
76 | /// This macro checks if the given string contains the given substring.
77 | ///
78 | /// # Example
79 | ///
80 | /// ```
81 | /// extern crate hsh;
82 | /// use hsh::{ hsh_contains };
83 | ///
84 | /// let contains = hsh_contains!("Hello world", "world");
85 | /// ```
86 | ///
87 | #[macro_export]
88 | macro_rules! hsh_contains {
89 | ($s:expr, $sub:expr) => {
90 | $s.contains($sub)
91 | };
92 | }
93 |
94 | /// This macro checks if the given value is within the given range. The
95 | /// range is inclusive of both endpoints.
96 | ///
97 | /// # Example
98 | ///
99 | /// ```
100 | /// extern crate hsh;
101 | /// use hsh::{ hsh_in_range };
102 | ///
103 | /// let in_range = hsh_in_range!(5, 1, 10); // `in_range` will be true
104 | /// ```
105 | ///
106 | #[macro_export]
107 | macro_rules! hsh_in_range {
108 | ($value:expr, $min:expr, $max:expr) => {
109 | $value >= $min && $value <= $max
110 | };
111 | }
112 |
113 | /// This macro joins the given strings together with the given
114 | /// separator.
115 | ///
116 | /// # Example
117 | ///
118 | /// ```
119 | /// extern crate hsh;
120 | /// use hsh::{ hsh_join };
121 | ///
122 | /// let joined = hsh_join!(", ", "Hello", "world");
123 | /// ```
124 | ///
125 | #[macro_export]
126 | macro_rules! hsh_join {
127 | ($sep:expr, $($s:expr),*) => {{
128 | let vec = vec![$($s.to_string()),*];
129 | vec.join($sep)
130 | }};
131 | }
132 |
133 | /// This macro finds the maximum value of the given values.
134 | ///
135 | /// # Example
136 | ///
137 | /// ```
138 | /// extern crate hsh;
139 | /// use hsh::{ hsh_max };
140 | ///
141 | /// let max = hsh_max!(1, 2, 3); // `max` will be 3
142 | /// ```
143 | #[macro_export]
144 | macro_rules! hsh_max {
145 | ($x:expr $(, $y:expr)*) => {{
146 | let mut max = $x;
147 | $(
148 | if max < $y { max = $y; }
149 | )*
150 | max
151 | }};
152 | }
153 |
154 | /// This macro finds the minimum value of the given values.
155 | ///
156 | /// # Example
157 | ///
158 | /// ```
159 | /// extern crate hsh;
160 | /// use hsh::{ hsh_min };
161 | ///
162 | /// let min = hsh_min!(1, 2, 3); // `min` will be 1
163 | /// ```
164 | ///
165 | #[macro_export]
166 | macro_rules! hsh_min {
167 | ($x:expr $(, $y:expr)*) => {{
168 | let mut min = $x;
169 | $(
170 | if min > $y { min = $y; }
171 | )*
172 | min
173 | }};
174 | }
175 |
176 | /// This macro prints the given arguments to the console.
177 | ///
178 | /// # Example
179 | ///
180 | /// ```
181 | /// extern crate hsh;
182 | /// use hsh::{ hsh_print };
183 | ///
184 | /// hsh_print!("Hello {}", "world"); // This will print "Hello world"
185 | /// ```
186 | #[macro_export]
187 | macro_rules! hsh_print {
188 | ($($arg:tt)*) => {
189 | println!($($arg)*);
190 | };
191 | }
192 |
193 | /// This macro prints the given vector of values to the console. Each
194 | /// value is printed on a new line.
195 | ///
196 | /// # Example
197 | ///
198 | /// ```
199 | /// extern crate hsh;
200 | /// use hsh::{ hsh_print_vec };
201 | ///
202 | /// let vec = vec![1, 2, 3];
203 | /// hsh_print_vec!(vec); // This will print 1, 2, 3 on separate lines
204 | /// ```
205 | ///
206 | #[macro_export]
207 | macro_rules! hsh_print_vec {
208 | ($($v:expr),*) => {
209 | for v in $($v),* {
210 | println!("{}", v);
211 | }
212 | };
213 | }
214 |
215 | /// This macro splits the given string into a vector of strings. The
216 | /// string is split on whitespace characters.
217 | ///
218 | /// # Example
219 | ///
220 | /// ```
221 | /// extern crate hsh;
222 | /// use hsh::{ hsh_split };
223 | ///
224 | /// let split = hsh_split!("Hello world");
225 | /// ```
226 | ///
227 | #[macro_export]
228 | macro_rules! hsh_split {
229 | ($s:expr) => {
230 | $s.split_whitespace()
231 | .map(|w| w.to_string())
232 | .collect::>()
233 | };
234 | }
235 |
236 | /// This macro creates a new vector with the given elements.
237 | ///
238 | /// # Example
239 | ///
240 | /// ```
241 | /// extern crate hsh;
242 | /// use hsh::{ hsh_vec };
243 | ///
244 | /// let vec = hsh_vec!(1, 2, 3); // `vec` will be [1, 2, 3]
245 | /// ```
246 | ///
247 | #[macro_export]
248 | macro_rules! hsh_vec {
249 | ($($elem:expr),*) => {{
250 | let mut v = Vec::new();
251 | $(v.push($elem);)*
252 | v
253 | }};
254 | }
255 |
256 | /// This macro attempts to parse the given input into a u64 value. If
257 | /// parsing fails, an error is returned with a message indicating the
258 | /// failure.
259 | ///
260 | /// # Example
261 | ///
262 | /// ```
263 | /// extern crate hsh;
264 | /// use hsh::{ hsh_parse };
265 | ///
266 | /// let parsed = hsh_parse!("123"); // `parsed` will be Ok(123)
267 | /// ```
268 | #[macro_export]
269 | macro_rules! hsh_parse {
270 | ($input:expr) => {
271 | $input
272 | .parse::()
273 | .map_err(|e| format!("Failed to parse input: {}", e))
274 | };
275 | }
276 |
277 | /// This macro abstracts away the error handling for the `to_string`
278 | /// method. If the method fails, an error is returned with the failure
279 | /// message.
280 | ///
281 | /// # Example
282 | ///
283 | /// ```
284 | /// extern crate hsh;
285 | /// use hsh::{ to_str_error };
286 | ///
287 | /// let result: Result<(), String> = Ok(());
288 | /// let error: Result<(), String> =
289 | /// Err("Error message".to_string());
290 | ///
291 | /// let result_str = to_str_error!(result);
292 | /// assert_eq!(result_str, Ok(()));
293 | ///
294 | /// ```
295 | #[macro_export]
296 | macro_rules! to_str_error {
297 | ($expr:expr) => {
298 | $expr.map_err(|e| e.to_string())
299 | };
300 | }
301 |
302 | /// This macro generates a random string of the given length. The string
303 | /// consists of alphanumeric characters (both upper and lower case).
304 | ///
305 | /// # Example
306 | ///
307 | /// ```
308 | /// extern crate hsh;
309 | /// use hsh::{ random_string };
310 | ///
311 | /// let random = random_string!(10);
312 | /// ```
313 | ///
314 | #[macro_export]
315 | macro_rules! random_string {
316 | ($len:expr) => {{
317 | let chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
318 | let mut rng = vrd::random::Random::default();
319 | (0..$len as usize)
320 | .map(|_| {
321 | let index = vrd::rand_int!(rng, 0, (chars.len() - 1) as i32) as usize;
322 | chars
323 | .chars()
324 | .nth(index)
325 | .unwrap()
326 | })
327 | .collect::()
328 | }};
329 | }
330 |
331 | /// This macro matches the hash algorithm strings to their corresponding
332 | /// enum variants.
333 | ///
334 | /// # Example
335 | ///
336 | /// ```
337 | /// extern crate hsh;
338 | /// use hsh::{ match_algo, models::hash_algorithm::HashAlgorithm };
339 | ///
340 | /// let algo = match_algo!("bcrypt");
341 | /// ```
342 | ///
343 | #[macro_export]
344 | macro_rules! match_algo {
345 | ($algo_str:expr) => {
346 | match $algo_str {
347 | "argon2i" => Ok(HashAlgorithm::Argon2i),
348 | "bcrypt" => Ok(HashAlgorithm::Bcrypt),
349 | "scrypt" => Ok(HashAlgorithm::Scrypt),
350 | _ => Err(format!(
351 | "Unsupported hash algorithm: {}",
352 | $algo_str
353 | )),
354 | }
355 | };
356 | }
357 |
358 | /// This macro generates a new hash for a given password, salt, and
359 | /// algorithm.
360 | ///
361 | /// # Example
362 | ///
363 | /// ```
364 | /// extern crate hsh;
365 | /// use hsh::models::hash::Hash;
366 | /// use hsh::{generate_hash, models::hash_algorithm::{HashAlgorithm}};
367 | ///
368 | /// let password = "password";
369 | /// let salt = "salt";
370 | /// let algo = "bcrypt";
371 | /// let hash_bytes = generate_hash!(password, salt, algo);
372 | ///
373 | /// assert!(hash_bytes.is_ok());
374 | /// ```
375 | ///
376 | #[macro_export]
377 | macro_rules! generate_hash {
378 | ($password:expr, $salt:expr, $algo:expr) => {
379 | Hash::generate_hash($password, $salt, $algo)
380 | };
381 | }
382 |
383 | /// This macro creates a new instance of the `Hash` struct with the
384 | /// given password, salt, and algorithm.
385 | ///
386 | /// # Example
387 | ///
388 | /// ```
389 | /// extern crate hsh;
390 | /// use hsh::{new_hash, models::{hash::Hash, hash_algorithm::{HashAlgorithm}}};
391 | ///
392 | ///
393 | /// let password = "password";
394 | /// let salt = "salt";
395 | /// let algo = "bcrypt";
396 | /// let hash = new_hash!(password, salt, algo);
397 | ///
398 | /// assert!(hash.is_ok());
399 | /// ```
400 | #[macro_export]
401 | macro_rules! new_hash {
402 | ($password:expr, $salt:expr, $algo:expr) => {
403 | Hash::new($password, $salt, $algo)
404 | };
405 | }
406 |
407 | /// This macro returns the length of the password for a given `Hash`
408 | /// struct instance.
409 | ///
410 | /// # Example
411 | ///
412 | /// ```
413 | /// extern crate hsh;
414 | /// use hsh::models::{hash::Hash, hash_algorithm::{HashAlgorithm}};
415 | /// use hsh::{ hash_length, new_hash };
416 | ///
417 | ///
418 | /// let password = "password";
419 | /// let salt = "salt";
420 | /// let algo = "bcrypt";
421 | ///
422 | /// let hash = new_hash!(password, salt, algo);
423 | /// assert!(hash.is_ok());
424 | /// let hash = hash.unwrap();
425 | ///
426 | /// let password_length = hash_length!(hash);
427 | /// assert_eq!(password_length, 60);
428 | /// ```
429 | ///
430 | #[macro_export]
431 | macro_rules! hash_length {
432 | ($hash:expr) => {
433 | $hash.hash_length()
434 | };
435 | }
436 |
437 | /// Macros related to executing shell commands.
438 | ///
439 | /// Executes a shell command, logs the start and completion of the operation, and handles any errors that occur.
440 | ///
441 | /// # Parameters
442 | ///
443 | /// * `$command`: The shell command to execute.
444 | /// * `$package`: The name of the package the command is being run on.
445 | /// * `$operation`: A description of the operation being performed.
446 | /// * `$start_message`: The log message to be displayed at the start of the operation.
447 | /// * `$complete_message`: The log message to be displayed upon successful completion of the operation.
448 | /// * `$error_message`: The log message to be displayed in case of an error.
449 | ///
450 | /// # Returns
451 | ///
452 | /// Returns a `Result<(), anyhow::Error>` indicating the success or failure of the operation.
453 | ///
454 | #[macro_export]
455 | macro_rules! macro_execute_and_log {
456 | ($command:expr, $package:expr, $operation:expr, $start_message:expr, $complete_message:expr, $error_message:expr) => {{
457 | use anyhow::{Context, Result as AnyResult};
458 | use $crate::loggers::{LogFormat, LogLevel};
459 | use $crate::macro_log_info;
460 |
461 | macro_log_info!(
462 | LogLevel::INFO,
463 | $operation,
464 | $start_message,
465 | LogFormat::CLF
466 | );
467 |
468 | $command
469 | .run()
470 | .map(|_| ())
471 | .map_err(|err| {
472 | macro_log_info!(
473 | LogLevel::ERROR,
474 | $operation,
475 | $error_message,
476 | LogFormat::CLF
477 | );
478 | err
479 | })
480 | .with_context(|| {
481 | format!(
482 | "Failed to execute '{}' for {} on package '{}'",
483 | stringify!($command),
484 | $operation,
485 | $package
486 | )
487 | })?;
488 |
489 | macro_log_info!(
490 | LogLevel::INFO,
491 | $operation,
492 | $complete_message,
493 | LogFormat::CLF
494 | );
495 | Ok(())
496 | }};
497 | }
498 |
--------------------------------------------------------------------------------
/src/main.rs:
--------------------------------------------------------------------------------
1 | // Copyright © 2023-2024 Hash (HSH) library. All rights reserved.
2 | // SPDX-License-Identifier: Apache-2.0 OR MIT
3 |
4 | //! This is the main entry point for the hsh application.
5 | fn main() {
6 | // Call the `run()` function from the `Hash (HSH)` module.
7 | if let Err(err) = hsh::run() {
8 | eprintln!("Error running hsh: {}", err);
9 | std::process::exit(1);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/models/hash.rs:
--------------------------------------------------------------------------------
1 | // Copyright © 2023-2024 Hash (HSH) library. All rights reserved.
2 | // SPDX-License-Identifier: Apache-2.0 OR MIT
3 |
4 | use super::hash_algorithm::HashAlgorithm;
5 | use crate::algorithms;
6 | use crate::models::hash_algorithm::HashingAlgorithm;
7 | use algorithms::{argon2i::Argon2i, bcrypt::Bcrypt, scrypt::Scrypt};
8 | use serde::{Deserialize, Serialize};
9 |
10 | // use algorithms::{argon2i::Argon2i, bcrypt::Bcrypt, scrypt::Scrypt};
11 | use argon2rs::argon2i_simple;
12 | use base64::{engine::general_purpose, Engine as _};
13 | // use models::{hash::*, hash_algorithm::*};
14 | use scrypt::scrypt;
15 | use std::{fmt, str::FromStr};
16 | use vrd::random::Random;
17 |
18 | /// A type alias for a salt.
19 | pub type Salt = Vec;
20 |
21 | /// A struct for storing and verifying hashed passwords.
22 | /// It uses `#[non_exhaustive]` and derive macros for common functionalities.
23 | #[non_exhaustive]
24 | #[derive(
25 | Clone,
26 | Debug,
27 | Eq,
28 | Hash,
29 | Ord,
30 | PartialEq,
31 | PartialOrd,
32 | Serialize,
33 | Deserialize,
34 | )]
35 | pub struct Hash {
36 | /// The password hash.
37 | pub hash: Vec,
38 | /// The salt used for hashing.
39 | pub salt: Salt,
40 | /// The hash algorithm used.
41 | pub algorithm: HashAlgorithm,
42 | }
43 |
44 | impl Hash {
45 | /// Creates a new `Hash` instance using Argon2i algorithm for password hashing.
46 | ///
47 | /// # Example
48 | ///
49 | /// ```
50 | /// use hsh::models::hash::{Hash, Salt};
51 | ///
52 | /// let password = "my_password";
53 | /// let salt: Salt = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
54 | ///
55 | /// let result = Hash::new_argon2i(password, salt);
56 | /// match result {
57 | /// Ok(hash) => println!("Successfully created Argon2i hash"),
58 | /// Err(e) => println!("An error occurred: {}", e),
59 | /// }
60 | /// ```
61 | pub fn new_argon2i(
62 | password: &str,
63 | salt: Salt,
64 | ) -> Result {
65 | // Convert the Vec salt to a &str
66 | let salt_str = std::str::from_utf8(&salt)
67 | .map_err(|_| "Failed to convert salt to string")?;
68 |
69 | // Perform Argon2i hashing
70 | let calculated_hash =
71 | argon2i_simple(password, salt_str).to_vec();
72 |
73 | HashBuilder::new()
74 | .hash(calculated_hash)
75 | .salt(salt)
76 | .algorithm(HashAlgorithm::Argon2i)
77 | .build()
78 | }
79 |
80 | /// Creates a new `Hash` instance using Bcrypt algorithm for password hashing.
81 | ///
82 | /// # Example
83 | ///
84 | /// ```
85 | /// use hsh::models::hash::Hash;
86 | ///
87 | /// let password = "my_password";
88 | /// let cost: u32 = 16;
89 | ///
90 | /// let result = Hash::new_bcrypt(password, cost);
91 | /// match result {
92 | /// Ok(hash) => println!("Successfully created Bcrypt hash"),
93 | /// Err(e) => println!("An error occurred: {}", e),
94 | /// }
95 | /// ```
96 | pub fn new_bcrypt(
97 | password: &str,
98 | cost: u32,
99 | ) -> Result {
100 | // Perform Bcrypt hashing
101 | let hashed_password =
102 | bcrypt::hash(password, cost).map_err(|e| {
103 | format!("Failed to hash password with Bcrypt: {}", e)
104 | })?;
105 |
106 | // In Bcrypt, the salt is embedded in the hashed password.
107 | // So, you can just use an empty salt when building the Hash object.
108 | let empty_salt = Vec::new();
109 |
110 | HashBuilder::new()
111 | .hash(hashed_password.as_bytes().to_vec())
112 | .salt(empty_salt)
113 | .algorithm(HashAlgorithm::Bcrypt)
114 | .build()
115 | }
116 |
117 | /// Creates a new `Hash` instance using Scrypt algorithm for password hashing.
118 | ///
119 | /// # Example
120 | ///
121 | /// ```
122 | /// use hsh::models::hash::{Hash, Salt};
123 | ///
124 | /// let password = "my_password";
125 | /// let salt: Salt = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
126 | ///
127 | /// let result = Hash::new_scrypt(password, salt);
128 | /// match result {
129 | /// Ok(hash) => println!("Successfully created Scrypt hash"),
130 | /// Err(e) => println!("An error occurred: {}", e),
131 | /// }
132 | /// ```
133 | pub fn new_scrypt(
134 | password: &str,
135 | salt: Salt,
136 | ) -> Result {
137 | // Convert the Vec salt to a &str for hashing
138 | let salt_str = std::str::from_utf8(&salt)
139 | .map_err(|_| "Failed to convert salt to string")?;
140 |
141 | // Perform Scrypt hashing using a wrapper function that sets the parameters
142 | let calculated_hash =
143 | Scrypt::hash_password(password, salt_str)?;
144 |
145 | // Use the builder pattern to construct the Hash instance
146 | HashBuilder::new()
147 | .hash(calculated_hash)
148 | .salt(salt)
149 | .algorithm(HashAlgorithm::Scrypt)
150 | .build()
151 | }
152 |
153 | /// A function that returns the hash algorithm used by the hash map.
154 | pub fn algorithm(&self) -> HashAlgorithm {
155 | self.algorithm
156 | }
157 |
158 | /// A function that creates a new hash object from a hash value and a hash algorithm.
159 | pub fn from_hash(hash: &[u8], algo: &str) -> Result {
160 | let algorithm = match algo {
161 | "argon2i" => Ok(HashAlgorithm::Argon2i),
162 | "bcrypt" => Ok(HashAlgorithm::Bcrypt),
163 | "scrypt" => Ok(HashAlgorithm::Scrypt),
164 | _ => Err(format!("Unsupported hash algorithm: {}", algo)),
165 | }?;
166 |
167 | Ok(Hash {
168 | salt: Vec::new(),
169 | hash: hash.to_vec(),
170 | algorithm,
171 | })
172 | }
173 |
174 | /// A function that creates a new hash object from a hash string in the format algorithm$salt$hash.
175 | pub fn from_string(hash_str: &str) -> Result {
176 | // Split the hash string into six parts, using the `$` character as the delimiter.
177 | let parts: Vec<&str> = hash_str.split('$').collect();
178 |
179 | // If the hash string does not contain six parts, return an error.
180 | if parts.len() != 6 {
181 | return Err(String::from("Invalid hash string"));
182 | }
183 |
184 | // Parse the algorithm from the first part of the hash string.
185 | let algorithm = Self::parse_algorithm(hash_str)?;
186 |
187 | // Parse the salt from the second, third, fourth, and fifth parts of the hash string.
188 | let salt = format!(
189 | "${}${}${}${}",
190 | parts[1], parts[2], parts[3], parts[4]
191 | );
192 |
193 | // Decode the hash bytes from the sixth part of the hash string.
194 | let hash_bytes =
195 | general_purpose::STANDARD.decode(parts[5]).map_err(
196 | |_| format!("Failed to decode base64: {}", parts[5]),
197 | )?;
198 |
199 | // Create the `Hash` object and return it.
200 | Ok(Hash {
201 | salt: salt.into_bytes(),
202 | hash: hash_bytes,
203 | algorithm,
204 | })
205 | }
206 |
207 | /// A function that generates a hash value for a password using the specified hash algorithm.
208 | /// The function takes three arguments:
209 | ///
210 | /// - password: The password to be hashed.
211 | /// - salt: A random string used to make the hash value unique.
212 | /// - algo: The name of the hash algorithm to use.
213 | ///
214 | /// The function returns a `Result` object containing the hash value if successful, or an error message if unsuccessful.
215 | pub fn generate_hash(
216 | password: &str,
217 | salt: &str,
218 | algo: &str,
219 | ) -> Result, String> {
220 | match algo {
221 | "argon2i" => Argon2i::hash_password(password, salt),
222 | "bcrypt" => Bcrypt::hash_password(password, salt),
223 | "scrypt" => Scrypt::hash_password(password, salt),
224 | _ => Err(format!("Unsupported hash algorithm: {}", algo)),
225 | }
226 | }
227 |
228 | /// A function that generates a random string of the specified length.
229 | pub fn generate_random_string(len: usize) -> String {
230 | let mut rng = Random::default();
231 | let chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
232 | (0..len)
233 | .map(|_| {
234 | chars
235 | .chars()
236 | .nth(rng.random_range(0, chars.len() as u32)
237 | as usize)
238 | .unwrap()
239 | })
240 | .collect()
241 | }
242 |
243 | /// A function that generates a random salt for a password using the specified hash algorithm.
244 | pub fn generate_salt(algo: &str) -> Result {
245 | let mut rng = Random::default();
246 | match algo {
247 | "argon2i" => Ok(Self::generate_random_string(16)),
248 | "bcrypt" => {
249 | let salt: Vec = rng.bytes(16);
250 | let salt_array: [u8; 16] =
251 | salt.try_into().map_err(|_| {
252 | "Error: failed to convert salt to an array"
253 | })?;
254 | Ok(general_purpose::STANDARD.encode(&salt_array[..]))
255 | }
256 | "scrypt" => {
257 | let salt: Vec = rng.bytes(32);
258 | let salt_array: [u8; 32] =
259 | salt.try_into().map_err(|_| {
260 | "Error: failed to convert salt to an array"
261 | })?;
262 | Ok(general_purpose::STANDARD.encode(&salt_array[..]))
263 | }
264 | _ => Err(format!("Unsupported hash algorithm: {}", algo)),
265 | }
266 | }
267 |
268 | /// A function that returns the hash value of a hash object.
269 | pub fn hash(&self) -> &[u8] {
270 | &self.hash
271 | }
272 |
273 | /// A function that returns the length of the hash value of a hash object.
274 | pub fn hash_length(&self) -> usize {
275 | self.hash.len()
276 | }
277 |
278 | /// A function that creates a new hash object from a password, salt, and hash algorithm.
279 | pub fn new(
280 | password: &str,
281 | salt: &str,
282 | algo: &str,
283 | ) -> Result {
284 | // Enforce a minimum password length of 8 characters.
285 | if password.len() < 8 {
286 | return Err(String::from("Password is too short. It must be at least 8 characters."));
287 | }
288 | let hash = Self::generate_hash(password, salt, algo)?;
289 |
290 | let algorithm = match algo {
291 | "argon2i" => Ok(HashAlgorithm::Argon2i),
292 | "bcrypt" => Ok(HashAlgorithm::Bcrypt),
293 | "scrypt" => Ok(HashAlgorithm::Scrypt),
294 | _ => Err(format!("Unsupported hash algorithm: {}", algo)),
295 | }?;
296 |
297 | Ok(Self {
298 | hash,
299 | salt: salt.as_bytes().to_vec(),
300 | algorithm,
301 | })
302 | }
303 |
304 | /// A function that parses a JSON string into a hash object.
305 | pub fn parse(
306 | input: &str,
307 | ) -> Result> {
308 | let hash: Hash = serde_json::from_str(input)?;
309 | Ok(hash)
310 | }
311 |
312 | /// A function that parses a hash string into a hash algorithm.
313 | pub fn parse_algorithm(
314 | hash_str: &str,
315 | ) -> Result {
316 | let parts: Vec<&str> = hash_str.split('$').collect();
317 | if parts.len() < 2 {
318 | return Err(String::from("Invalid hash string"));
319 | }
320 | match parts[1] {
321 | "argon2i" => Ok(HashAlgorithm::Argon2i),
322 | "bcrypt" => Ok(HashAlgorithm::Bcrypt),
323 | "scrypt" => Ok(HashAlgorithm::Scrypt),
324 | _ => {
325 | Err(format!("Unsupported hash algorithm: {}", parts[1]))
326 | }
327 | }
328 | }
329 |
330 | /// A function that returns the salt used to hash a password.
331 | pub fn salt(&self) -> &[u8] {
332 | &self.salt
333 | }
334 |
335 | /// A function that sets the hash value of a hash object.
336 | pub fn set_hash(&mut self, hash: &[u8]) {
337 | self.hash = hash.to_vec();
338 | }
339 |
340 | /// A function that sets the password of a hash object.
341 | pub fn set_password(
342 | &mut self,
343 | password: &str,
344 | salt: &str,
345 | algo: &str,
346 | ) -> Result<(), String> {
347 | self.hash = Self::generate_hash(password, salt, algo)?;
348 | Ok(())
349 | }
350 |
351 | /// A function that sets the salt of a hash object.
352 | pub fn set_salt(&mut self, salt: &[u8]) {
353 | self.salt = salt.to_vec();
354 | }
355 |
356 | /// A function that converts a hash object to a string representation.
357 | pub fn to_string_representation(&self) -> String {
358 | let hash_str = self
359 | .hash
360 | .iter()
361 | .map(|b| format!("{:02x}", b))
362 | .collect::>()
363 | .join("");
364 |
365 | format!("{}:{}", String::from_utf8_lossy(&self.salt), hash_str)
366 | }
367 |
368 | /// A function that verifies a password against a hash object.
369 | pub fn verify(&self, password: &str) -> Result {
370 | let salt = std::str::from_utf8(&self.salt)
371 | .map_err(|_| "Failed to convert salt to string")?;
372 |
373 | match self.algorithm {
374 | HashAlgorithm::Argon2i => {
375 | // Hash the password once
376 | let calculated_hash =
377 | argon2i_simple(password, salt).to_vec();
378 |
379 | // Debugging information
380 | println!("Algorithm: Argon2i");
381 | println!(
382 | "Provided password for verification: {}",
383 | password
384 | );
385 | println!("Salt used for verification: {}", salt);
386 | println!("Calculated Hash: {:?}", calculated_hash);
387 | println!("Stored Hash: {:?}", self.hash);
388 |
389 | // Perform the verification
390 | Ok(calculated_hash == self.hash)
391 | }
392 | HashAlgorithm::Bcrypt => {
393 | // Debugging information
394 | println!("Algorithm: Bcrypt");
395 | println!(
396 | "Provided password for verification: {}",
397 | password
398 | );
399 |
400 | let hash_str = std::str::from_utf8(&self.hash)
401 | .map_err(|_| "Failed to convert hash to string")?;
402 | bcrypt::verify(password, hash_str)
403 | .map_err(|_| "Failed to verify Bcrypt password")
404 | }
405 | HashAlgorithm::Scrypt => {
406 | // Debugging information
407 | println!("Algorithm: Scrypt");
408 | println!(
409 | "Provided password for verification: {}",
410 | password
411 | );
412 | println!("Salt used for verification: {}", salt);
413 |
414 | let scrypt_params = scrypt::Params::new(14, 8, 1, 64)
415 | .map_err(|_| {
416 | "Failed to create Scrypt params"
417 | })?;
418 | let mut output = [0u8; 64];
419 | match scrypt(
420 | password.as_bytes(),
421 | salt.as_bytes(),
422 | &scrypt_params,
423 | &mut output,
424 | ) {
425 | Ok(_) => {
426 | println!(
427 | "Calculated Hash: {:?}",
428 | output.to_vec()
429 | );
430 | println!("Stored Hash: {:?}", self.hash);
431 | Ok(output.to_vec() == self.hash)
432 | }
433 | Err(_) => Err("Scrypt hashing failed"),
434 | }
435 | }
436 | }
437 | }
438 | }
439 |
440 | impl fmt::Display for Hash {
441 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
442 | write!(f, "Hash {{ hash: {:?} }}", self.hash)
443 | }
444 | }
445 |
446 | impl fmt::Display for HashAlgorithm {
447 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
448 | write!(f, "{:?}", self)
449 | }
450 | }
451 |
452 | impl FromStr for HashAlgorithm {
453 | type Err = String;
454 |
455 | fn from_str(s: &str) -> Result {
456 | let algorithm = match s {
457 | "argon2i" => HashAlgorithm::Argon2i,
458 | "bcrypt" => HashAlgorithm::Bcrypt,
459 | "scrypt" => HashAlgorithm::Scrypt,
460 | _ => return Err(String::from("Invalid hash algorithm")),
461 | };
462 | Ok(algorithm)
463 | }
464 | }
465 |
466 | /// A builder struct for the `Hash` struct.
467 | /// It contains optional fields that correspond to the fields in `Hash`.
468 | /// The `#[derive(Default)]` allows us to initialize all fields to `None`.
469 | #[derive(
470 | Clone,
471 | Debug,
472 | Eq,
473 | Hash,
474 | Ord,
475 | PartialEq,
476 | PartialOrd,
477 | Serialize,
478 | Deserialize,
479 | )]
480 | pub struct HashBuilder {
481 | /// The password hash.
482 | hash: Option>,
483 | /// The salt used for hashing.
484 | salt: Option,
485 | /// The hash algorithm used.
486 | algorithm: Option,
487 | }
488 |
489 | impl HashBuilder {
490 | /// Creates a new `HashBuilder` with all fields set to `None`.
491 | pub fn new() -> Self {
492 | HashBuilder {
493 | hash: None,
494 | salt: None,
495 | algorithm: None,
496 | }
497 | }
498 |
499 | /// Sets the `hash` field in the builder.
500 | /// The `self` parameter is consumed and returned to allow for method chaining.
501 | pub fn hash(mut self, hash: Vec) -> Self {
502 | self.hash = Some(hash);
503 | self
504 | }
505 |
506 | /// Sets the `salt` field in the builder.
507 | /// The `self` parameter is consumed and returned to allow for method chaining.
508 | pub fn salt(mut self, salt: Salt) -> Self {
509 | self.salt = Some(salt);
510 | self
511 | }
512 |
513 | /// Sets the `algorithm` field in the builder.
514 | /// The `self` parameter is consumed and returned to allow for method chaining.
515 | pub fn algorithm(mut self, algorithm: HashAlgorithm) -> Self {
516 | self.algorithm = Some(algorithm);
517 | self
518 | }
519 |
520 | /// Consumes the builder and returns a `Hash` if all fields are set.
521 | /// Otherwise, it returns an error.
522 | pub fn build(self) -> Result {
523 | if let (Some(hash), Some(salt), Some(algorithm)) =
524 | (self.hash, self.salt, self.algorithm)
525 | {
526 | Ok(Hash {
527 | hash,
528 | salt,
529 | algorithm,
530 | })
531 | } else {
532 | Err("Missing fields".to_string())
533 | }
534 | }
535 | }
536 |
537 | /// Creates a new `HashBuilder` with all fields set to `None`.
538 | impl Default for HashBuilder {
539 | fn default() -> Self {
540 | Self::new()
541 | }
542 | }
543 |
--------------------------------------------------------------------------------
/src/models/hash_algorithm.rs:
--------------------------------------------------------------------------------
1 | // Copyright © 2023-2024 Hash (HSH) library. All rights reserved.
2 | // SPDX-License-Identifier: Apache-2.0 OR MIT
3 |
4 | use serde::{Deserialize, Serialize};
5 |
6 | /// Represents the different algorithms available for password hashing.
7 | ///
8 | /// This enum is used to specify which hashing algorithm should be used
9 | /// when creating a new hashed password.
10 | ///
11 | #[derive(
12 | Clone,
13 | Copy,
14 | Debug,
15 | Eq,
16 | Hash,
17 | Ord,
18 | PartialEq,
19 | PartialOrd,
20 | Serialize,
21 | Deserialize,
22 | )]
23 | pub enum HashAlgorithm {
24 | /// Argon2i - A memory-hard password hashing algorithm.
25 | ///
26 | /// Resistant against various types of attacks, including:
27 | /// - GPU-based attacks
28 | /// - Side-channel attacks
29 | ///
30 | /// Incorporates multiple parameters to deter attackers:
31 | /// - Memory usage
32 | /// - Parallelism
33 | /// - Time cost
34 | Argon2i,
35 |
36 | /// Bcrypt - A widely used, computationally intensive password hashing algorithm.
37 | ///
38 | /// Features:
39 | /// - Based on the Blowfish encryption cipher
40 | /// - Uses key stretching technique
41 | /// - Time-consuming and resource-intensive, which makes it resistant to cracking
42 | Bcrypt,
43 |
44 | /// Scrypt - A memory-hard password hashing algorithm designed for resistance to brute-force attacks.
45 | ///
46 | /// Features:
47 | /// - Consumes a large amount of memory
48 | /// - Makes parallelized attacks difficult and costly
49 | Scrypt,
50 | }
51 |
52 | /// Represents a generic hashing algorithm.
53 | ///
54 | /// The `HashingAlgorithm` trait defines a common interface for hashing algorithms.
55 | /// Implementing this trait for different hashing algorithms ensures that they can be used
56 | /// interchangeably for hashing passwords.
57 | ///
58 | /// The primary consumer of this trait is the `Hash` struct, which uses it to handle the hashing
59 | /// logic in a decoupled and extendable manner.
60 | pub trait HashingAlgorithm {
61 | /// Hashes a given password using a specific salt.
62 | ///
63 | /// Given a plaintext `password` and a `salt`, this method returns a hashed representation
64 | /// of the password. The hashing algorithm used is determined by the implementing type.
65 | ///
66 | /// # Parameters
67 | ///
68 | /// - `password`: The plaintext password to be hashed.
69 | /// - `salt`: A cryptographic salt to prevent rainbow table attacks.
70 | ///
71 | /// # Returns
72 | ///
73 | /// Returns a `Result` containing the hashed password as a vector of bytes.
74 | /// If hashing fails, returns a `String` detailing the error.
75 | fn hash_password(
76 | password: &str,
77 | salt: &str,
78 | ) -> Result, String>;
79 | }
80 |
--------------------------------------------------------------------------------
/src/models/mod.rs:
--------------------------------------------------------------------------------
1 | // Copyright © 2023-2024 Hash (HSH) library. All rights reserved.
2 | // SPDX-License-Identifier: Apache-2.0 OR MIT
3 |
4 | /// The `data` module contains the structs.
5 | pub mod hash;
6 |
7 | /// The `hash_algorithm` module contains the `HashAlgorithm` enum.
8 | pub mod hash_algorithm;
9 |
--------------------------------------------------------------------------------
/tests/test_argon2i.rs:
--------------------------------------------------------------------------------
1 | // Copyright © 2023-2024 Hash (HSH) library. All rights reserved.
2 | // SPDX-License-Identifier: Apache-2.0 OR MIT
3 |
4 | #[cfg(test)]
5 | mod tests {
6 | use hsh::algorithms::argon2i::Argon2i;
7 | use hsh::models::hash::Hash;
8 | use hsh::models::hash_algorithm::{
9 | HashAlgorithm, HashingAlgorithm,
10 | };
11 |
12 | #[test]
13 | fn test_hash_differs_from_password() {
14 | let password = "password123";
15 | let salt = "somesalt";
16 | let hashed_password =
17 | Argon2i::hash_password(password, salt).unwrap();
18 |
19 | assert_ne!(hashed_password, password.as_bytes());
20 | }
21 |
22 | #[test]
23 | fn test_different_salts_produce_different_hashes() {
24 | let password = "password123";
25 | let salt1 = "salt123456789012345678901234567";
26 | let salt2 = "salt234567890123456789012345678";
27 |
28 | let hash1 = Argon2i::hash_password(password, salt1).unwrap();
29 | let hash2 = Argon2i::hash_password(password, salt2).unwrap();
30 |
31 | assert_ne!(hash1, hash2);
32 | }
33 |
34 | #[test]
35 | fn test_same_password_and_salt_produce_same_hash() {
36 | let password = "password123";
37 | let salt = "somesalt";
38 |
39 | let hash1 = Argon2i::hash_password(password, salt).unwrap();
40 | let hash2 = Argon2i::hash_password(password, salt).unwrap();
41 |
42 | assert_eq!(hash1, hash2);
43 | }
44 |
45 | #[test]
46 | fn test_hash_password_length() {
47 | let password = "password123";
48 | let salt = "somesalt";
49 | let hashed_password =
50 | Argon2i::hash_password(password, salt).unwrap();
51 |
52 | assert_eq!(hashed_password.len(), 32); // Assuming a 32-byte hash
53 | }
54 |
55 | #[test]
56 | fn test_hash_password_not_empty() {
57 | let password = "password123";
58 | let salt = "somesalt";
59 | let hashed_password =
60 | Argon2i::hash_password(password, salt).unwrap();
61 |
62 | assert!(!hashed_password.is_empty());
63 | }
64 |
65 | #[test]
66 | fn test_hash_password_error() {
67 | let password = "password123";
68 | let salt = "somesalt";
69 | let hashed_password =
70 | Argon2i::hash_password(password, salt).unwrap();
71 |
72 | assert!(!hashed_password.is_empty());
73 | }
74 |
75 | #[test]
76 | fn test_from_hash() {
77 | let hash_bytes = vec![1, 2, 3, 4];
78 | let hash = Hash::from_hash(&hash_bytes, "argon2i").unwrap();
79 | assert_eq!(hash.hash, hash_bytes);
80 | assert_eq!(hash.algorithm, HashAlgorithm::Argon2i);
81 | }
82 |
83 | #[test]
84 | fn test_from_hash_error() {
85 | let hash_bytes = vec![1, 2, 3, 4];
86 | let hash = Hash::from_hash(&hash_bytes, "argon2i").unwrap();
87 | assert_eq!(hash.hash, hash_bytes);
88 | assert_eq!(hash.algorithm, HashAlgorithm::Argon2i);
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/tests/test_bcrypt.rs:
--------------------------------------------------------------------------------
1 | // Copyright © 2023-2024 Hash (HSH) library. All rights reserved.
2 | // SPDX-License-Identifier: Apache-2.0 OR MIT
3 |
4 | #[cfg(test)]
5 | mod tests {
6 | use hsh::algorithms::bcrypt::Bcrypt;
7 | use hsh::models::hash::
8 | Hash;
9 | use hsh::models::hash_algorithm::{
10 | HashAlgorithm, HashingAlgorithm,
11 | };
12 |
13 | #[test]
14 | fn test_hash_differs_from_password() {
15 | let password = "password123";
16 | let salt = "somesalt";
17 | let hashed_password =
18 | Bcrypt::hash_password(password, salt).unwrap();
19 |
20 | assert_ne!(hashed_password, password.as_bytes());
21 | }
22 |
23 | #[test]
24 | fn test_different_salts_produce_different_hashes() {
25 | let password = "password123";
26 | let salt1 = "salt1";
27 | let salt2 = "salt2";
28 |
29 | let hash1 = Bcrypt::hash_password(password, salt1).unwrap();
30 | let hash2 = Bcrypt::hash_password(password, salt2).unwrap();
31 |
32 | assert_ne!(hash1, hash2);
33 | }
34 |
35 | #[test]
36 | fn test_hashing_error() {
37 | // Setup conditions for hashing to fail
38 | let password = "password123";
39 |
40 | // Intentionally using an invalid cost to force an error
41 | let invalid_cost: u32 = 1;
42 | let result = bcrypt::hash(password, invalid_cost);
43 |
44 | assert!(result.is_err());
45 | }
46 |
47 | #[test]
48 | fn test_new_bcrypt() {
49 | let password = "password123";
50 | let cost: u32 = 12;
51 | let hash = Hash::new_bcrypt(password, cost).unwrap();
52 |
53 | assert_eq!(hash.algorithm, HashAlgorithm::Bcrypt);
54 | assert!(!hash.hash.is_empty());
55 | assert_eq!(hash.salt.len(), 0);
56 | }
57 |
58 | #[test]
59 | fn test_new_bcrypt_error() {
60 | let password = "password123";
61 | let invalid_cost: u32 = 0;
62 | let result = Hash::new_bcrypt(password, invalid_cost);
63 |
64 | assert!(result.is_err());
65 | }
66 |
67 | #[test]
68 | fn test_from_hash() {
69 | let hash_bytes = vec![1, 2, 3, 4];
70 | let hash = Hash::from_hash(&hash_bytes, "bcrypt").unwrap();
71 | assert_eq!(hash.hash, hash_bytes);
72 | assert_eq!(hash.algorithm, HashAlgorithm::Bcrypt);
73 | }
74 |
75 | #[test]
76 | fn test_from_hash_error() {
77 | let hash_bytes = vec![1, 2, 3, 4];
78 | let hash = Hash::from_hash(&hash_bytes, "invalid").unwrap_err();
79 | assert_eq!(hash, "Unsupported hash algorithm: invalid");
80 | }
81 |
82 | #[test]
83 | fn test_verify_bcrypt() {
84 | let password = "password123";
85 | let hash = Hash::new_bcrypt(password, 12).unwrap();
86 |
87 | assert!(hash.verify(password).unwrap());
88 | assert!(!hash.verify("wrong_password").unwrap());
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/tests/test_hash.rs:
--------------------------------------------------------------------------------
1 | // Copyright © 2023-2024 Hash (HSH) library. All rights reserved.
2 | // SPDX-License-Identifier: Apache-2.0 OR MIT
3 |
4 | #[cfg(test)]
5 | mod tests {
6 | use hsh::models::hash::{Hash, HashBuilder, Salt};
7 | use hsh::models::hash_algorithm::HashAlgorithm;
8 | use std::str::FromStr;
9 |
10 | #[test]
11 | fn test_new_argon2i() {
12 | let password = "password123";
13 | let salt: Salt = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
14 | let hash = Hash::new_argon2i(password, salt.clone()).unwrap();
15 | assert_eq!(hash.salt, salt);
16 | assert_eq!(hash.algorithm, HashAlgorithm::Argon2i);
17 | }
18 |
19 | #[test]
20 | fn test_new_bcrypt() {
21 | let password = "password123";
22 | let cost = 4;
23 | let hash = Hash::new_bcrypt(password, cost).unwrap();
24 | assert_eq!(hash.algorithm, HashAlgorithm::Bcrypt);
25 | }
26 |
27 | #[test]
28 | fn test_new_scrypt() {
29 | let password = "password123";
30 | let salt: Salt = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
31 | let hash = Hash::new_scrypt(password, salt.clone()).unwrap();
32 | assert_eq!(hash.salt, salt);
33 | assert_eq!(hash.algorithm, HashAlgorithm::Scrypt);
34 | }
35 |
36 | #[test]
37 | fn test_from_hash() {
38 | let hash_bytes = vec![1, 2, 3, 4];
39 | let hash = Hash::from_hash(&hash_bytes, "argon2i").unwrap();
40 | assert_eq!(hash.hash, hash_bytes);
41 | assert_eq!(hash.algorithm, HashAlgorithm::Argon2i);
42 | }
43 |
44 | #[test]
45 | fn test_hash_algorithm_from_str() {
46 | let algorithm = HashAlgorithm::from_str("argon2i").unwrap();
47 | assert_eq!(algorithm, HashAlgorithm::Argon2i);
48 | }
49 |
50 | #[test]
51 | fn test_hash_builder() {
52 | let hash = vec![1, 2, 3, 4];
53 | let salt: Salt = vec![0, 1, 2, 3];
54 | let algorithm = HashAlgorithm::Argon2i;
55 | let built_hash = HashBuilder::new()
56 | .hash(hash.clone())
57 | .salt(salt.clone())
58 | .algorithm(algorithm)
59 | .build()
60 | .unwrap();
61 |
62 | assert_eq!(built_hash.hash, hash);
63 | assert_eq!(built_hash.salt, salt);
64 | assert_eq!(built_hash.algorithm, algorithm);
65 | }
66 |
67 | // Add more tests such as verification, string representation, etc.
68 | }
69 |
--------------------------------------------------------------------------------
/tests/test_hash_algorithm.rs:
--------------------------------------------------------------------------------
1 | // Copyright © 2023-2024 Hash (HSH) library. All rights reserved.
2 | // SPDX-License-Identifier: Apache-2.0 OR MIT
3 |
4 | #[cfg(test)]
5 | mod tests {
6 | use hsh::models::hash_algorithm::{
7 | HashAlgorithm, HashingAlgorithm,
8 | };
9 |
10 | // Dummy struct to implement HashingAlgorithm for testing
11 | struct DummyAlgorithm;
12 |
13 | impl HashingAlgorithm for DummyAlgorithm {
14 | fn hash_password(
15 | _password: &str,
16 | _salt: &str,
17 | ) -> Result, String> {
18 | Ok(vec![1, 2, 3, 4]) // Dummy logic
19 | }
20 | }
21 |
22 | #[test]
23 | fn test_hash_algorithm_enum() {
24 | let argon2i = HashAlgorithm::Argon2i;
25 | let bcrypt = HashAlgorithm::Bcrypt;
26 | let scrypt = HashAlgorithm::Scrypt;
27 |
28 | assert_eq!(argon2i as i32, 0);
29 | assert_eq!(bcrypt as i32, 1);
30 | assert_eq!(scrypt as i32, 2);
31 | }
32 |
33 | #[test]
34 | fn test_hashing_algorithm_trait() {
35 | let password = "password123";
36 | let salt = "salt123";
37 | let hashed =
38 | DummyAlgorithm::hash_password(password, salt).unwrap();
39 | assert_eq!(hashed, vec![1, 2, 3, 4]);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/tests/test_lib.rs:
--------------------------------------------------------------------------------
1 | // Copyright © 2023-2024 Hash (HSH) library. All rights reserved.
2 | // SPDX-License-Identifier: Apache-2.0 OR MIT
3 |
4 | #[cfg(test)]
5 | mod tests {
6 | use hsh::models::hash::Hash;
7 | use hsh::models::hash_algorithm::HashAlgorithm;
8 |
9 | #[test]
10 | fn test_new() {
11 | let password = "password123";
12 | let salt = "somesalt";
13 | let algo = "argon2i";
14 |
15 | let hash = Hash::new(password, salt, algo).unwrap();
16 |
17 | assert_eq!(hash.algorithm, HashAlgorithm::Argon2i);
18 | assert_eq!(hash.salt, salt.as_bytes().to_vec());
19 | }
20 |
21 | #[test]
22 | fn test_new_with_unsupported_algo() {
23 | let password = "password123";
24 | let salt = "somesalt";
25 | let algo = "unsupported_algo";
26 |
27 | let hash = Hash::new(password, salt, algo);
28 |
29 | match hash {
30 | Ok(_) => {
31 | panic!("Expected an error for unsupported hash algorithm, but got Ok");
32 | }
33 | Err(e) => {
34 | assert_eq!(
35 | e,
36 | format!("Unsupported hash algorithm: {}", algo)
37 | );
38 | }
39 | }
40 | }
41 |
42 | #[test]
43 | fn test_verify() {
44 | let password = "password123";
45 | let salt = "somesalt";
46 | let algo = "argon2i";
47 |
48 | let hash = Hash::new(password, salt, algo).unwrap();
49 |
50 | assert!(hash.verify(password).unwrap());
51 | assert!(!hash.verify("wrongpassword").unwrap());
52 | }
53 |
54 | #[test]
55 | fn test_from_string() {
56 | // You'll need to provide a valid hash string here for this test
57 | let hash_string = "$argon2i$v=19$m=4096,t=3,p=1$c29tZXNhbHQ$RdescudvJCsgt3ub+b+dWRWJTmaaJObG";
58 |
59 | let hash = Hash::from_string(hash_string);
60 |
61 | match hash {
62 | Ok(hash) => {
63 | // Assert that the hash, salt, and algorithm are as expected
64 | assert_eq!(hash.algorithm, HashAlgorithm::Argon2i);
65 | }
66 | Err(e) => {
67 | panic!("Failed to parse hash string: {}", e);
68 | }
69 | }
70 | }
71 |
72 | #[test]
73 | fn test_from_string_invalid_hash_string() {
74 | // Provide an invalid hash string
75 | let invalid_hash_string = "invalid$hash$string";
76 |
77 | let hash = Hash::from_string(invalid_hash_string);
78 |
79 | // Expect an error to be returned
80 | assert!(hash.is_err());
81 |
82 | // Check the error message
83 | match hash {
84 | Err(e) => {
85 | assert_eq!(e, String::from("Invalid hash string"))
86 | }
87 | _ => panic!("Expected Err, got Ok"),
88 | }
89 | }
90 |
91 | #[test]
92 | fn test_generate_salt() {
93 | let algo = "argon2i";
94 |
95 | let salt = Hash::generate_salt(algo).unwrap();
96 |
97 | // Assert that the salt is of the correct length and format
98 | assert_eq!(salt.len(), 16);
99 | }
100 |
101 | #[test]
102 | fn test_generate_salt_invalid_algorithm() {
103 | let invalid_algo = "unsupported_algo";
104 |
105 | let salt = Hash::generate_salt(invalid_algo);
106 |
107 | // Expect an error to be returned
108 | assert!(salt.is_err());
109 |
110 | // Check the error message
111 | match salt {
112 | Err(e) => assert_eq!(
113 | e,
114 | format!("Unsupported hash algorithm: {}", invalid_algo)
115 | ),
116 | _ => panic!("Expected Err, got Ok"),
117 | }
118 | }
119 |
120 | #[test]
121 | fn test_generate_salt_bcrypt() {
122 | let algo = "bcrypt";
123 |
124 | let salt = Hash::generate_salt(algo).unwrap();
125 |
126 | // Assert that the salt is of the correct length and format
127 | assert_eq!(salt.len(), 24); // bcrypt salt will be longer due to base64 encoding
128 | }
129 |
130 | #[test]
131 | fn test_generate_salt_scrypt() {
132 | let algo = "scrypt";
133 |
134 | let salt = Hash::generate_salt(algo).unwrap();
135 |
136 | // Assert that the salt is of the correct length and format
137 | assert_eq!(salt.len(), 44); // scrypt salt will be longer due to base64 encoding
138 | }
139 |
140 | #[test]
141 | fn test_argon2i_hashing() {
142 | let password = "password123";
143 | let salt = "somesalt";
144 | let algo = "argon2i";
145 |
146 | let hash = Hash::new(password, salt, algo).unwrap();
147 |
148 | assert!(hash.verify(password).unwrap());
149 | assert!(!hash.verify("wrongpassword").unwrap());
150 | }
151 |
152 | #[test]
153 | fn test_bcrypt_hashing() {
154 | let password = "password123";
155 | let salt = Hash::generate_salt("bcrypt").unwrap();
156 | let algo = "bcrypt";
157 |
158 | let hash = Hash::new(password, &salt, algo).unwrap();
159 |
160 | assert!(hash.verify(password).unwrap());
161 | assert!(!hash.verify("wrongpassword").unwrap());
162 | }
163 |
164 | #[test]
165 | fn test_scrypt_hashing() {
166 | let password = "password123";
167 | let salt = Hash::generate_salt("scrypt").unwrap();
168 | let algo = "scrypt";
169 |
170 | let hash = Hash::new(password, &salt, algo).unwrap();
171 |
172 | assert!(hash.verify(password).unwrap());
173 | assert!(!hash.verify("wrongpassword").unwrap());
174 | }
175 |
176 | #[test]
177 | fn test_set_password() {
178 | let password = "password123";
179 | let salt = "somesalt";
180 | let algo = "argon2i";
181 |
182 | let mut hash = Hash::new(password, salt, algo).unwrap();
183 |
184 | let new_password = "newpassword123";
185 | hash.set_password(new_password, salt, algo).unwrap();
186 |
187 | assert!(hash.verify(new_password).unwrap());
188 | assert!(!hash.verify(password).unwrap());
189 | }
190 |
191 | #[test]
192 | fn test_invalid_algorithm() {
193 | let password = "password123";
194 | let salt = "somesalt";
195 | let algo = "invalid_algo";
196 |
197 | let hash = Hash::new(password, salt, algo);
198 |
199 | assert!(hash.is_err());
200 | }
201 |
202 | #[test]
203 | fn test_short_password() {
204 | let password = "short";
205 | let salt = "somesalt";
206 | let algo = "argon2i";
207 |
208 | let hash = Hash::new(password, salt, algo);
209 |
210 | assert!(hash.is_err());
211 | }
212 |
213 | #[test]
214 | fn test_algorithm() {
215 | let password = "password123";
216 | let salt = "somesalt";
217 | let algo = "bcrypt";
218 |
219 | let hash = Hash::new(password, salt, algo).unwrap();
220 |
221 | assert_eq!(HashAlgorithm::Bcrypt, hash.algorithm());
222 | }
223 |
224 | #[test]
225 | fn test_from_hash() {
226 | let password = "password123";
227 | let salt = "somesalt";
228 | let algo = "scrypt";
229 |
230 | // Generate a hash from the password
231 | let original_hash = Hash::new(password, salt, algo).unwrap();
232 |
233 | // Get the hashed password bytes
234 | let hashed_password = original_hash.hash;
235 |
236 | // Now try to create a new Hash struct from the hashed password bytes
237 | let from_hash = Hash::from_hash(&hashed_password, algo);
238 |
239 | // Check that from_hash is Ok
240 | assert!(from_hash.is_ok());
241 |
242 | // Unwrap the Result and get the Hash struct
243 | let from_hash = from_hash.unwrap();
244 |
245 | // Check that the algorithm is correct
246 | assert_eq!(from_hash.algorithm(), HashAlgorithm::Scrypt);
247 |
248 | // Check that the hash is correct
249 | assert_eq!(from_hash.hash, hashed_password);
250 |
251 | // Check that the salt is empty (since from_hash doesn't set the salt)
252 | assert_eq!(from_hash.salt, Vec::::new());
253 | }
254 |
255 | #[test]
256 | fn test_from_hash_invalid_algorithm() {
257 | let password = "password123";
258 | let salt = "somesalt";
259 | let algo = "unsupported_algo";
260 |
261 | // Generate a hash from the password
262 | let original_hash =
263 | Hash::new(password, salt, "bcrypt").unwrap();
264 |
265 | // Get the hashed password bytes
266 | let hashed_password = original_hash.hash;
267 |
268 | // Now try to create a new Hash struct from the hashed password bytes
269 | let from_hash = Hash::from_hash(&hashed_password, algo);
270 |
271 | // Check that from_hash is Err
272 | assert!(from_hash.is_err());
273 |
274 | // Check the error message
275 | match from_hash {
276 | Err(e) => assert_eq!(
277 | e,
278 | format!("Unsupported hash algorithm: {}", algo)
279 | ),
280 | _ => panic!("Expected Err, got Ok"),
281 | }
282 | }
283 |
284 | #[test]
285 | fn test_hash() {
286 | let password = "password123";
287 | let salt = "somesalt";
288 | let algo = "bcrypt";
289 |
290 | // Create a new Hash
291 | let original_hash = Hash::new(password, salt, algo).unwrap();
292 |
293 | // Get the hashed password bytes
294 | let hashed_password = original_hash.hash.clone();
295 |
296 | // Test the `hash` method
297 | assert_eq!(original_hash.hash(), &hashed_password);
298 | }
299 |
300 | #[test]
301 | fn test_salt() {
302 | let password = "password123";
303 | let salt = "somesalt";
304 | let algo = "bcrypt";
305 |
306 | // Create a new Hash
307 | let original_hash = Hash::new(password, salt, algo).unwrap();
308 |
309 | // Convert the salt to bytes for comparison
310 | let salt_bytes = salt.as_bytes();
311 |
312 | // Test the `salt` method
313 | assert_eq!(original_hash.salt(), salt_bytes);
314 | }
315 |
316 | #[test]
317 | fn test_set_hash() {
318 | let password = "password123";
319 | let salt = "somesalt";
320 | let algo = "bcrypt";
321 |
322 | // Create a new Hash
323 | let mut original_hash =
324 | Hash::new(password, salt, algo).unwrap();
325 |
326 | // Create a new hash value
327 | let new_hash = vec![1, 2, 3, 4, 5];
328 |
329 | // Set the hash of the Hash struct to the new value
330 | original_hash.set_hash(&new_hash);
331 |
332 | // Test that the `hash` method returns the new hash value
333 | assert_eq!(original_hash.hash(), &new_hash);
334 | }
335 |
336 | #[test]
337 | fn test_set_salt() {
338 | let password = "password123";
339 | let salt = "somesalt";
340 | let algo = "bcrypt";
341 |
342 | // Create a new Hash
343 | let mut original_hash =
344 | Hash::new(password, salt, algo).unwrap();
345 |
346 | // Create a new salt value
347 | let new_salt = vec![1, 2, 3, 4, 5];
348 |
349 | // Set the salt of the Hash struct to the new value
350 | original_hash.set_salt(&new_salt);
351 |
352 | // Test that the `salt` method returns the new salt value
353 | assert_eq!(original_hash.salt(), &new_salt);
354 | }
355 | #[test]
356 | fn test_to_string_representation() {
357 | let password = "password123";
358 | let salt = "somesalt";
359 | let algo = "bcrypt";
360 |
361 | // Create a new Hash
362 | let original_hash = Hash::new(password, salt, algo).unwrap();
363 |
364 | // Get the string representation
365 | let string_repr = original_hash.to_string_representation();
366 |
367 | // Get the expected string representation
368 | let expected_repr = format!(
369 | "{}:{}",
370 | salt,
371 | original_hash
372 | .hash()
373 | .iter()
374 | .map(|b| format!("{:02x}", b))
375 | .collect::>()
376 | .join("")
377 | );
378 |
379 | assert_eq!(string_repr, expected_repr);
380 | }
381 | #[test]
382 | fn test_hash_display() {
383 | let password = "password123";
384 | let salt = "somesalt";
385 | let algo = "bcrypt";
386 |
387 | // Create a new Hash
388 | let original_hash = Hash::new(password, salt, algo).unwrap();
389 |
390 | // Test the Display implementation for Hash
391 | assert_eq!(
392 | format!("{}", original_hash),
393 | format!("Hash {{ hash: {:?} }}", original_hash.hash())
394 | );
395 | }
396 |
397 | #[test]
398 | fn test_hash_algorithm_display() {
399 | let algo = HashAlgorithm::Bcrypt;
400 |
401 | // Test the Display implementation for HashAlgorithm
402 | assert_eq!(format!("{}", algo), format!("{:?}", algo));
403 | }
404 |
405 | #[test]
406 | fn test_hash_algorithm_from_str() {
407 | let algo_str = "bcrypt";
408 | let expected_algo = HashAlgorithm::Bcrypt;
409 |
410 | // Test the FromStr implementation for HashAlgorithm
411 | assert_eq!(
412 | algo_str.parse::().unwrap(),
413 | expected_algo
414 | );
415 | }
416 |
417 | #[test]
418 | fn test_hash_algorithm_from_str_invalid() {
419 | let invalid_algo_str = "invalid";
420 |
421 | // Test the FromStr implementation for HashAlgorithm with an invalid string
422 | assert!(invalid_algo_str.parse::().is_err());
423 | }
424 |
425 | #[test]
426 | fn test_parse() {
427 | let password = "password123";
428 | let salt = "somesalt";
429 | let algo = "bcrypt";
430 |
431 | // Create a new Hash
432 | let original_hash = Hash::new(password, salt, algo).unwrap();
433 |
434 | // Convert the Hash to a JSON string
435 | let hash_json = serde_json::to_string(&original_hash).unwrap();
436 |
437 | // Parse the JSON string back into a Hash
438 | let parsed_hash = Hash::parse(&hash_json).unwrap();
439 |
440 | // Check that the parsed Hash is equal to the original
441 | assert_eq!(original_hash, parsed_hash);
442 | }
443 |
444 | #[test]
445 | fn test_parse_invalid() {
446 | let invalid_json = "invalid";
447 |
448 | // Try to parse the invalid JSON string
449 | assert!(Hash::parse(invalid_json).is_err());
450 | }
451 |
452 | #[test]
453 | fn test_parse_algorithm_argon2i() {
454 | let hash_str = "$argon2i$somehashstring";
455 | let algorithm = Hash::parse_algorithm(hash_str);
456 |
457 | assert_eq!(algorithm.unwrap(), HashAlgorithm::Argon2i);
458 | }
459 |
460 | #[test]
461 | fn test_parse_algorithm_bcrypt() {
462 | let hash_str = "$bcrypt$somehashstring";
463 | let algorithm = Hash::parse_algorithm(hash_str);
464 |
465 | assert_eq!(algorithm.unwrap(), HashAlgorithm::Bcrypt);
466 | }
467 |
468 | #[test]
469 | fn test_parse_algorithm_scrypt() {
470 | let hash_str = "$scrypt$somehashstring";
471 | let algorithm = Hash::parse_algorithm(hash_str);
472 |
473 | assert_eq!(algorithm.unwrap(), HashAlgorithm::Scrypt);
474 | }
475 |
476 | #[test]
477 | fn test_parse_algorithm_unsupported() {
478 | let hash_str = "$unsupported$somehashstring";
479 | let algorithm = Hash::parse_algorithm(hash_str);
480 |
481 | assert!(algorithm.is_err());
482 | assert_eq!(
483 | algorithm.err().unwrap(),
484 | "Unsupported hash algorithm: unsupported"
485 | );
486 | }
487 |
488 | #[test]
489 | fn test_parse_algorithm_invalid() {
490 | let hash_str = "invalidhashstring";
491 | let algorithm = Hash::parse_algorithm(hash_str);
492 |
493 | assert!(algorithm.is_err());
494 | assert_eq!(algorithm.err().unwrap(), "Invalid hash string");
495 | }
496 | }
497 |
--------------------------------------------------------------------------------
/tests/test_macros.rs:
--------------------------------------------------------------------------------
1 | // Copyright © 2023-2024 Hash (HSH) library. All rights reserved.
2 | // SPDX-License-Identifier: Apache-2.0 OR MIT
3 |
4 | #[cfg(test)]
5 | mod tests {
6 |
7 | // Importing hsh crate and all of its macros
8 | use hsh::models::hash::*;
9 | use hsh::models::hash_algorithm::HashAlgorithm;
10 | use hsh::{generate_hash, hash_length, new_hash};
11 | use hsh::{
12 | hsh_assert, hsh_contains, hsh_in_range, hsh_join, hsh_max,
13 | hsh_min, hsh_parse, hsh_print, hsh_print_vec, hsh_split,
14 | hsh_vec, match_algo, random_string, to_str_error,
15 | };
16 |
17 | #[test]
18 | #[should_panic(expected = "Assertion failed!")]
19 | fn macro_hsh_assert_fail() {
20 | // Test that hsh_assert! macro correctly triggers a panic when the argument is false
21 | hsh_assert!(false);
22 | }
23 |
24 | #[test]
25 | fn macro_hsh_assert() {
26 | // Test that hsh_assert! macro does not trigger a panic when the argument is true
27 | hsh_assert!(true);
28 | }
29 |
30 | #[test]
31 | fn macro_hsh_join() {
32 | // Test that hsh_join! macro correctly joins the string arguments together
33 | let s = hsh_join!(" ", "Hello", "world");
34 | assert_eq!(s, "Hello world");
35 | }
36 |
37 | #[test]
38 | fn macro_hsh_min() {
39 | // Test that hsh_min! macro correctly identifies the minimum value among the arguments
40 | assert_eq!(hsh_min!(10, 20, 30), 10);
41 | }
42 |
43 | #[test]
44 | fn macro_hsh_max() {
45 | // Test that hsh_max! macro correctly identifies the maximum value among the arguments
46 | assert_eq!(hsh_max!(10, 20, 30), 30);
47 | }
48 |
49 | #[test]
50 | fn macro_hsh_print() {
51 | // Test that hsh_print! macro correctly prints the argument
52 | hsh_print!("Hello, World!");
53 | }
54 |
55 | #[test]
56 | fn macro_hsh_print_vec() {
57 | // Test that hsh_print_vec! macro correctly prints the elements of the vector argument
58 | hsh_print_vec!(&[1, 2, 3]);
59 | }
60 |
61 | #[test]
62 | fn macro_hsh_split() {
63 | // Test that hsh_split! macro correctly splits the string argument into a vector of words
64 | let v = hsh_split!("Hello World");
65 | assert_eq!(v, vec!["Hello", "World"]);
66 | }
67 |
68 | #[test]
69 | fn macro_hsh_vec() {
70 | // Test that hsh_vec! macro correctly creates a vector from the arguments
71 | let v = hsh_vec!(1, 2, 3);
72 | assert_eq!(v, &[1, 2, 3]);
73 | }
74 |
75 | #[test]
76 | fn macro_hsh_contains() {
77 | // Test that hsh_contains! macro correctly checks if the first string contains the second
78 | assert!(hsh_contains!("Hello", "H"));
79 | assert!(!hsh_contains!("Hello", "x"));
80 | }
81 |
82 | #[test]
83 | fn macro_hsh_in_range() {
84 | let lower_bound = 0;
85 | let upper_bound = 100;
86 | let test_val1 = 10;
87 | let test_val2 = -10;
88 |
89 | assert!(hsh_in_range!(test_val1, lower_bound, upper_bound));
90 | assert!(!hsh_in_range!(test_val2, lower_bound, upper_bound));
91 | }
92 |
93 | #[test]
94 | fn macro_hsh_parse() {
95 | let input: Result = hsh_parse!("42");
96 | assert_eq!(input, Ok(42));
97 | }
98 |
99 | #[test]
100 | fn macro_to_str_error() {
101 | let result: Result<(), String> = Ok(());
102 | let error: Result<(), String> =
103 | Err("Error message".to_string());
104 |
105 | let result_str = to_str_error!(result);
106 | assert_eq!(result_str, Ok(()));
107 |
108 | let error_str = to_str_error!(error);
109 | assert_eq!(error_str, Err("Error message".to_string()));
110 | }
111 |
112 | #[test]
113 | fn macro_random_string() {
114 | let random = random_string!(10);
115 | assert_eq!(random.len(), 10);
116 | }
117 |
118 | #[test]
119 | fn macro_match_algo() {
120 | let algo_str = "bcrypt";
121 | let algo_result = match_algo!(algo_str);
122 | assert_eq!(algo_result, Ok(HashAlgorithm::Bcrypt));
123 |
124 | let unsupported_str = "md5";
125 | let unsupported_result = match_algo!(unsupported_str);
126 | assert_eq!(
127 | unsupported_result,
128 | Err("Unsupported hash algorithm: md5".to_string())
129 | );
130 | }
131 |
132 | #[test]
133 | fn macro_generate_hash() {
134 | let password = "password";
135 | let salt = "salt";
136 | let algo = "bcrypt";
137 | let hash_bytes = generate_hash!(password, salt, algo);
138 |
139 | assert!(hash_bytes.is_ok());
140 | }
141 |
142 | #[test]
143 | fn macro_new_hash() {
144 | let password = "password";
145 | let salt = "salt";
146 | let algo = "bcrypt";
147 | let hash = new_hash!(password, salt, algo);
148 |
149 | assert!(hash.is_ok());
150 | }
151 |
152 | #[test]
153 | fn macro_hash_length() {
154 | let password = "password";
155 | let salt = "salt";
156 | let algo = "bcrypt";
157 |
158 | let hash = new_hash!(password, salt, algo);
159 | assert!(hash.is_ok());
160 | let hash = hash.unwrap();
161 |
162 | let password_length = hash_length!(hash);
163 | assert_eq!(password_length, 60);
164 | }
165 | }
166 |
--------------------------------------------------------------------------------
/tests/test_main.rs:
--------------------------------------------------------------------------------
1 | // Copyright © 2023-2024 Hash (HSH) library. All rights reserved.
2 | // SPDX-License-Identifier: Apache-2.0 OR MIT
3 |
4 | #[cfg(test)]
5 | mod tests {
6 | use assert_cmd::prelude::*;
7 | use std::process::Command;
8 |
9 | #[test]
10 | fn test_run_with_hsh_test_mode() {
11 | let output = Command::cargo_bin("hsh")
12 | .unwrap()
13 | .env("HSH_TEST_MODE", "1")
14 | .output()
15 | .expect("Failed to execute command");
16 |
17 | // Assert that the command execution was not successful
18 | assert!(!output.status.success());
19 |
20 | // Assert that the error message was printed to stderr
21 | let stderr = String::from_utf8(output.stderr).unwrap();
22 | assert!(stderr.contains("Error running hsh: Simulated error"));
23 | }
24 |
25 | #[test]
26 | fn test_run_without_hsh_test_mode() {
27 | let output = Command::cargo_bin("hsh")
28 | .unwrap()
29 | .output()
30 | .expect("Failed to execute command");
31 |
32 | // Assert that the command execution was successful
33 | assert!(output.status.success());
34 |
35 | // Assert that the welcome messages were printed to stdout
36 | let stdout = String::from_utf8(output.stdout).unwrap();
37 | assert!(stdout.contains("Welcome to `HSH` 👋!"));
38 | assert!(stdout.contains("Quantum-Resistant Cryptographic Hash Library for Password Encryption and Verification."));
39 | }
40 |
41 | fn run_test_scenario() -> Result<(), Box> {
42 | // Simulate an error scenario
43 | // Return an error explicitly
44 | Err("Test error".into())
45 | }
46 |
47 | #[test]
48 | fn test_main() {
49 | // Test calling the `run()` function directly
50 | let result = run_test_scenario();
51 | assert!(result.is_err());
52 |
53 | // Test calling the `main()` function
54 | let output = Command::cargo_bin("hsh")
55 | .unwrap()
56 | .env("HSH_TEST_MODE", "1")
57 | .output()
58 | .expect("Failed to execute command");
59 |
60 | // Assert that the command execution was not successful
61 | assert!(!output.status.success());
62 |
63 | // Assert that the error message was printed to stderr
64 | let stderr = String::from_utf8(output.stderr).unwrap();
65 | assert!(stderr.contains("Error running hsh: Simulated error"));
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/tests/test_scrypt.rs:
--------------------------------------------------------------------------------
1 | // Copyright © 2023-2024 Hash (HSH) library. All rights reserved.
2 | // SPDX-License-Identifier: Apache-2.0 OR MIT
3 |
4 | #[cfg(test)]
5 | mod tests {
6 | use hsh::models::hash_algorithm::HashingAlgorithm;
7 |
8 | #[test]
9 | fn test_hash_password_success() {
10 | let password = "secure_password";
11 | let salt = "random_salt";
12 |
13 | let result = hsh::algorithms::scrypt::Scrypt::hash_password(
14 | password, salt,
15 | );
16 | assert!(result.is_ok());
17 | }
18 |
19 | #[test]
20 | fn test_same_salt_and_password_produce_same_hash() {
21 | let password = "password123";
22 | let salt = "salt123";
23 |
24 | let hash1_result =
25 | hsh::algorithms::scrypt::Scrypt::hash_password(
26 | password, salt,
27 | )
28 | .unwrap();
29 | let hash2_result =
30 | hsh::algorithms::scrypt::Scrypt::hash_password(
31 | password, salt,
32 | )
33 | .unwrap();
34 |
35 | assert_eq!(hash1_result, hash2_result);
36 | }
37 |
38 | #[test]
39 | fn test_different_salts_produce_different_hashes() {
40 | let password = "password123";
41 | let salt1 = "salt123";
42 | let salt2 = "another_salt123";
43 |
44 | let hash1_result =
45 | hsh::algorithms::scrypt::Scrypt::hash_password(
46 | password, salt1,
47 | )
48 | .unwrap();
49 | let hash2_result =
50 | hsh::algorithms::scrypt::Scrypt::hash_password(
51 | password, salt2,
52 | )
53 | .unwrap();
54 |
55 | assert_ne!(hash1_result, hash2_result);
56 | }
57 |
58 | #[test]
59 | fn test_different_passwords_produce_different_hashes() {
60 | let password1 = "password123";
61 | let password2 = "other_password123";
62 | let salt = "salt123";
63 |
64 | let hash1_result =
65 | hsh::algorithms::scrypt::Scrypt::hash_password(
66 | password1, salt,
67 | )
68 | .unwrap();
69 | let hash2_result =
70 | hsh::algorithms::scrypt::Scrypt::hash_password(
71 | password2, salt,
72 | )
73 | .unwrap();
74 |
75 | assert_ne!(hash1_result, hash2_result);
76 | }
77 | }
78 |
--------------------------------------------------------------------------------