mirror of
https://github.com/SabreTools/SabreTools.Hashing.git
synced 2026-02-06 13:47:32 +00:00
Compare commits
238 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a334ffc25a | ||
|
|
3211f1a218 | ||
|
|
3c451b8570 | ||
|
|
ecd52b1a0e | ||
|
|
0075b9b1ad | ||
|
|
214b449e5e | ||
|
|
0bb3e541be | ||
|
|
d91220a2e4 | ||
|
|
e60a1fbe3c | ||
|
|
978a3847de | ||
|
|
48da4cd88e | ||
|
|
458499eea4 | ||
|
|
47cb600f3f | ||
|
|
d42af9b95d | ||
|
|
8672fea581 | ||
|
|
a5b36a8329 | ||
|
|
b83cafebf1 | ||
|
|
2b7f09f06f | ||
|
|
2a37f8c03a | ||
|
|
51c3ecec4b | ||
|
|
97a1338cab | ||
|
|
a808c9ba3c | ||
|
|
53e28df7f8 | ||
|
|
bdde3bad16 | ||
|
|
32491ccaae | ||
|
|
ae3fc9ef56 | ||
|
|
8d52187a03 | ||
|
|
720a3a4c2b | ||
|
|
0872d8c927 | ||
|
|
1619046d11 | ||
|
|
4fda55d4d1 | ||
|
|
349a414ff3 | ||
|
|
05617c5c7e | ||
|
|
cce8a18b03 | ||
|
|
cbaa79b284 | ||
|
|
32cd0e73ed | ||
|
|
95589df904 | ||
|
|
fd612f939a | ||
|
|
8e3a0f77e9 | ||
|
|
40cfa78be4 | ||
|
|
4d92c7cd23 | ||
|
|
acf1e3ec71 | ||
|
|
10027f78e3 | ||
|
|
187932b091 | ||
|
|
89dbe0460f | ||
|
|
365ee9019f | ||
|
|
e117892f37 | ||
|
|
1e11e9abb8 | ||
|
|
1d2985023d | ||
|
|
cfddb3dab4 | ||
|
|
08512abc59 | ||
|
|
71a330cf68 | ||
|
|
ad8d119905 | ||
|
|
c82a6dc39b | ||
|
|
414759cbd2 | ||
|
|
142ca6f327 | ||
|
|
8dee2e2501 | ||
|
|
240098dd03 | ||
|
|
15a022eca5 | ||
|
|
0ede92a5d9 | ||
|
|
0c3815e17c | ||
|
|
8f5bff0375 | ||
|
|
dc3cb0be5d | ||
|
|
f7346b20e1 | ||
|
|
f971fcf5c8 | ||
|
|
4e0da77cb4 | ||
|
|
7776112ec6 | ||
|
|
c65184689d | ||
|
|
704e08b5ed | ||
|
|
99f770ce81 | ||
|
|
e5fea69815 | ||
|
|
80448302e8 | ||
|
|
434a10d3db | ||
|
|
4ea5f95b5e | ||
|
|
381dffccf9 | ||
|
|
d4885d389d | ||
|
|
f0adc62394 | ||
|
|
d7790ac4e1 | ||
|
|
70b145c633 | ||
|
|
4e9d7fc927 | ||
|
|
ba7a1cd8b7 | ||
|
|
165bbdfd72 | ||
|
|
4a9fc1a144 | ||
|
|
563d293f4b | ||
|
|
39c2451354 | ||
|
|
b8ec4ac9c4 | ||
|
|
adc918ea8a | ||
|
|
186f8a1ece | ||
|
|
d8cb2e2955 | ||
|
|
83f008919c | ||
|
|
72a98e3e03 | ||
|
|
32fe421af4 | ||
|
|
3382c20217 | ||
|
|
6700f603f2 | ||
|
|
e1c1c8322d | ||
|
|
7b9580c991 | ||
|
|
75e536df4f | ||
|
|
3e18ddce9f | ||
|
|
f4d5e88f0a | ||
|
|
a5f7e7d91d | ||
|
|
2e3e16e8ae | ||
|
|
8fa100eb89 | ||
|
|
bf1cfa0e1f | ||
|
|
4e86e0ef86 | ||
|
|
d57396612f | ||
|
|
1b06751c68 | ||
|
|
89582a56ac | ||
|
|
ac1cacc247 | ||
|
|
27276ce05d | ||
|
|
841f5708a3 | ||
|
|
6df184fa4e | ||
|
|
d9cf9fd3b2 | ||
|
|
21b49921ac | ||
|
|
d1b60f7951 | ||
|
|
bb9d4155d2 | ||
|
|
5b66eaf253 | ||
|
|
7c4d6a6862 | ||
|
|
79c10cf2fb | ||
|
|
ffc6bc045d | ||
|
|
7a43f6c0de | ||
|
|
d096cbf07e | ||
|
|
bb67c3e2f3 | ||
|
|
f2e5033bb4 | ||
|
|
0f7d373751 | ||
|
|
8231ab18a6 | ||
|
|
bd8055b7d5 | ||
|
|
bd0f76ef08 | ||
|
|
70e79a68eb | ||
|
|
a087abf3d3 | ||
|
|
bd363ca1ec | ||
|
|
e4a53f3d62 | ||
|
|
1401775c15 | ||
|
|
a3ba52adee | ||
|
|
544d6f1cc8 | ||
|
|
62da665c07 | ||
|
|
8480ec8d92 | ||
|
|
c763d402d9 | ||
|
|
7c090b76c0 | ||
|
|
2be7850b9e | ||
|
|
611a0934ae | ||
|
|
16826f4c8b | ||
|
|
4732de1268 | ||
|
|
f74c9ddffd | ||
|
|
58f2475099 | ||
|
|
1d1fe196cf | ||
|
|
2af987bb1d | ||
|
|
effb2f9db6 | ||
|
|
b728aa77c7 | ||
|
|
fefdcd72a3 | ||
|
|
5d25a017eb | ||
|
|
c0643e3bca | ||
|
|
65a57f6c60 | ||
|
|
9c27523612 | ||
|
|
5ed7ad7802 | ||
|
|
41be02c57d | ||
|
|
0ec9c1f91d | ||
|
|
de8e510f71 | ||
|
|
82f051354f | ||
|
|
7559ba2edc | ||
|
|
4a408ded7e | ||
|
|
3469d424af | ||
|
|
3fa04bba65 | ||
|
|
f135693c7e | ||
|
|
0d6806cf59 | ||
|
|
4dde900195 | ||
|
|
a383bb39a6 | ||
|
|
92554705cc | ||
|
|
c5e4cb1495 | ||
|
|
9bb8a07c32 | ||
|
|
7878591107 | ||
|
|
6f536b8e2a | ||
|
|
dee69d1d88 | ||
|
|
0e8694cc90 | ||
|
|
a7f8e0664a | ||
|
|
b1e4546697 | ||
|
|
51d1a81e08 | ||
|
|
1a941b44fc | ||
|
|
ea601eed8d | ||
|
|
c1a9e007c5 | ||
|
|
fb83427c91 | ||
|
|
57f9aa9133 | ||
|
|
dbcb654f8a | ||
|
|
16d3472fc6 | ||
|
|
aced21c9f0 | ||
|
|
2a81a65f99 | ||
|
|
9819a5975a | ||
|
|
e36cd9bf3c | ||
|
|
4eec52241e | ||
|
|
98c646d579 | ||
|
|
d8da0d6312 | ||
|
|
d259dca9ab | ||
|
|
188483b4d1 | ||
|
|
6b33bec6e2 | ||
|
|
1fc4c13683 | ||
|
|
2ef3a6f254 | ||
|
|
827239a08a | ||
|
|
c1e847c1cf | ||
|
|
f01d801421 | ||
|
|
483a74f8c9 | ||
|
|
d0660472eb | ||
|
|
5718c62157 | ||
|
|
63eff1ab18 | ||
|
|
7de1c6464f | ||
|
|
f900eca029 | ||
|
|
cb3585ae49 | ||
|
|
9610e1756f | ||
|
|
45d0e2dde1 | ||
|
|
389c609a9d | ||
|
|
71d88d3467 | ||
|
|
3905905301 | ||
|
|
adc03c90eb | ||
|
|
4c006317be | ||
|
|
21498f6d52 | ||
|
|
2dcf0e7eea | ||
|
|
0cf07ae13a | ||
|
|
74d74fdfae | ||
|
|
9e48cca1a3 | ||
|
|
23679266b4 | ||
|
|
992e22cc76 | ||
|
|
5cfe0dcb09 | ||
|
|
3ebb489f23 | ||
|
|
94b9e91718 | ||
|
|
445c3473d9 | ||
|
|
d8bc77a938 | ||
|
|
10406fa90c | ||
|
|
08f5ae5b8b | ||
|
|
e5010f1856 | ||
|
|
d6b00b1a42 | ||
|
|
8aa10ff06b | ||
|
|
7eeb11261b | ||
|
|
a0fc83b617 | ||
|
|
fbc81459ee | ||
|
|
7d53e07e90 | ||
|
|
e83c31b89c | ||
|
|
ca08f97336 | ||
|
|
bd1e23dad4 | ||
|
|
b22f3d2743 | ||
|
|
23ed4e9849 |
167
.editorconfig
Normal file
167
.editorconfig
Normal file
@@ -0,0 +1,167 @@
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# C# files
|
||||
[*.cs]
|
||||
|
||||
# Indentation and spacing
|
||||
charset = utf-8
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
tab_width = 4
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
# New line preferences
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
max_line_length = unset
|
||||
|
||||
# using directive preferences
|
||||
csharp_using_directive_placement = outside_namespace
|
||||
dotnet_diagnostic.IDE0005.severity = error
|
||||
|
||||
# Code-block preferences
|
||||
csharp_style_namespace_declarations = block_scoped
|
||||
csharp_style_prefer_method_group_conversion = true
|
||||
csharp_style_prefer_top_level_statements = false
|
||||
|
||||
# Expression-level preferences
|
||||
csharp_prefer_simple_default_expression = true
|
||||
csharp_style_inlined_variable_declaration = true
|
||||
csharp_style_unused_value_assignment_preference = discard_variable
|
||||
csharp_style_unused_value_expression_statement_preference = discard_variable
|
||||
dotnet_diagnostic.IDE0001.severity = warning
|
||||
dotnet_diagnostic.IDE0002.severity = warning
|
||||
dotnet_diagnostic.IDE0004.severity = warning
|
||||
dotnet_diagnostic.IDE0010.severity = error
|
||||
dotnet_diagnostic.IDE0051.severity = warning
|
||||
dotnet_diagnostic.IDE0052.severity = warning
|
||||
dotnet_diagnostic.IDE0072.severity = warning
|
||||
dotnet_diagnostic.IDE0080.severity = warning
|
||||
dotnet_diagnostic.IDE0100.severity = error
|
||||
dotnet_diagnostic.IDE0110.severity = error
|
||||
dotnet_diagnostic.IDE0120.severity = warning
|
||||
dotnet_diagnostic.IDE0121.severity = warning
|
||||
dotnet_diagnostic.IDE0240.severity = error
|
||||
dotnet_diagnostic.IDE0241.severity = error
|
||||
dotnet_style_coalesce_expression = true
|
||||
dotnet_style_namespace_match_folder = false
|
||||
dotnet_style_null_propagation = true
|
||||
dotnet_style_prefer_auto_properties = true
|
||||
dotnet_style_prefer_collection_expression = when_types_loosely_match
|
||||
dotnet_style_prefer_is_null_check_over_reference_equality_method = true
|
||||
dotnet_style_prefer_compound_assignment = true
|
||||
csharp_style_prefer_simple_property_accessors = true
|
||||
dotnet_style_prefer_simplified_interpolation = true
|
||||
dotnet_style_prefer_simplified_boolean_expressions = true
|
||||
csharp_style_prefer_unbound_generic_type_in_nameof = true
|
||||
|
||||
# Field preferences
|
||||
dotnet_diagnostic.IDE0044.severity = warning
|
||||
dotnet_style_readonly_field = true
|
||||
|
||||
# Language keyword vs. framework types preferences
|
||||
dotnet_diagnostic.IDE0049.severity = error
|
||||
dotnet_style_predefined_type_for_locals_parameters_members = true
|
||||
dotnet_style_predefined_type_for_member_access = true
|
||||
|
||||
# Modifier preferences
|
||||
csharp_prefer_static_local_function = true
|
||||
csharp_style_prefer_readonly_struct = true
|
||||
dotnet_diagnostic.IDE0036.severity = warning
|
||||
dotnet_diagnostic.IDE0040.severity = error
|
||||
dotnet_diagnostic.IDE0380.severity = error
|
||||
dotnet_style_require_accessibility_modifiers = always
|
||||
|
||||
# New-line preferences
|
||||
dotnet_diagnostic.IDE2000.severity = warning
|
||||
dotnet_diagnostic.IDE2002.severity = warning
|
||||
dotnet_diagnostic.IDE2003.severity = warning
|
||||
dotnet_diagnostic.IDE2004.severity = warning
|
||||
dotnet_diagnostic.IDE2005.severity = warning
|
||||
dotnet_diagnostic.IDE2006.severity = warning
|
||||
csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = false
|
||||
csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = false
|
||||
csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = false
|
||||
csharp_style_allow_blank_lines_between_consecutive_braces_experimental = false
|
||||
dotnet_style_allow_multiple_blank_lines_experimental = false
|
||||
dotnet_style_allow_statement_immediately_after_block_experimental = false
|
||||
|
||||
# Null-checking preferences
|
||||
csharp_style_conditional_delegate_call = true
|
||||
|
||||
# Parameter preferences
|
||||
dotnet_code_quality_unused_parameters = all
|
||||
dotnet_diagnostic.IDE0280.severity = error
|
||||
|
||||
# Parentheses preferences
|
||||
dotnet_diagnostic.IDE0047.severity = warning
|
||||
dotnet_diagnostic.IDE0048.severity = warning
|
||||
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity
|
||||
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity
|
||||
dotnet_style_parentheses_in_other_operators = always_for_clarity
|
||||
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity
|
||||
|
||||
# Pattern-matching preferences
|
||||
dotnet_diagnostic.IDE0019.severity = warning
|
||||
dotnet_diagnostic.IDE0020.severity = warning
|
||||
dotnet_diagnostic.IDE0038.severity = warning
|
||||
dotnet_diagnostic.IDE0066.severity = none
|
||||
dotnet_diagnostic.IDE0083.severity = warning
|
||||
dotnet_diagnostic.IDE0260.severity = warning
|
||||
csharp_style_pattern_matching_over_as_with_null_check = true
|
||||
csharp_style_pattern_matching_over_is_with_cast_check = true
|
||||
csharp_style_prefer_not_pattern = true
|
||||
csharp_style_prefer_pattern_matching = true
|
||||
|
||||
# this. and Me. preferences
|
||||
dotnet_style_qualification_for_event = false
|
||||
dotnet_style_qualification_for_field = false
|
||||
dotnet_style_qualification_for_method = false
|
||||
dotnet_style_qualification_for_property = false
|
||||
|
||||
# var preferences
|
||||
csharp_style_var_for_built_in_types = false
|
||||
csharp_style_var_when_type_is_apparent = true
|
||||
|
||||
# .NET formatting options
|
||||
dotnet_separate_import_directive_groups = false
|
||||
dotnet_sort_system_directives_first = true
|
||||
|
||||
# C# formatting options
|
||||
csharp_indent_block_contents = true
|
||||
csharp_indent_braces = false
|
||||
csharp_indent_case_contents = true
|
||||
csharp_indent_case_contents_when_block = false
|
||||
csharp_indent_labels = one_less_than_current
|
||||
csharp_indent_switch_labels = true
|
||||
csharp_new_line_before_catch = true
|
||||
csharp_new_line_before_else = true
|
||||
csharp_new_line_before_finally = true
|
||||
csharp_new_line_before_members_in_anonymous_types = true
|
||||
csharp_new_line_before_members_in_object_initializers = true
|
||||
csharp_new_line_before_open_brace = all
|
||||
csharp_new_line_between_query_expression_clauses = true
|
||||
csharp_preserve_single_line_blocks = true
|
||||
csharp_preserve_single_line_statements = true
|
||||
csharp_space_after_cast = false
|
||||
csharp_space_after_colon_in_inheritance_clause = true
|
||||
csharp_space_after_comma = true
|
||||
csharp_space_after_dot = false
|
||||
csharp_space_after_keywords_in_control_flow_statements = true
|
||||
csharp_space_after_semicolon_in_for_statement = true
|
||||
csharp_space_around_binary_operators = before_and_after
|
||||
csharp_space_around_declaration_statements = false
|
||||
csharp_space_before_colon_in_inheritance_clause = true
|
||||
csharp_space_before_comma = false
|
||||
csharp_space_before_dot = false
|
||||
csharp_space_before_open_square_brackets = false
|
||||
csharp_space_before_semicolon_in_for_statement = false
|
||||
csharp_space_between_empty_square_brackets = false
|
||||
csharp_space_between_method_call_empty_parameter_list_parentheses = false
|
||||
csharp_space_between_method_call_name_and_opening_parenthesis = false
|
||||
csharp_space_between_method_call_parameter_list_parentheses = false
|
||||
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
|
||||
csharp_space_between_method_declaration_parameter_list_parentheses = false
|
||||
csharp_space_between_parentheses = false
|
||||
csharp_space_between_square_brackets = false
|
||||
27
.github/ISSUE_TEMPLATE/feature-request.md
vendored
Normal file
27
.github/ISSUE_TEMPLATE/feature-request.md
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
---
|
||||
name: Feature Request
|
||||
about: For when you know better than me what you want
|
||||
title: "[Request]"
|
||||
labels: enhancement
|
||||
assignees: mnadareski
|
||||
|
||||
---
|
||||
|
||||
**Before You Submit**
|
||||
|
||||
- Remember to try the [latest WIP build](https://github.com/SabreTools/SabreTools.Hashing/releases/tag/rolling) to see if the feature already exists.
|
||||
- Check [previous issues](https://github.com/SabreTools/SabreTools.Hashing/issues) to see if any of those are related to what you're about to ask for.
|
||||
|
||||
If none of those apply, then continue...
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
21
.github/ISSUE_TEMPLATE/informational.md
vendored
Normal file
21
.github/ISSUE_TEMPLATE/informational.md
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
---
|
||||
name: Info
|
||||
about: Something you need to tell me
|
||||
title: "[Info]"
|
||||
labels: question
|
||||
assignees: mnadareski
|
||||
|
||||
---
|
||||
|
||||
**Before You Submit**
|
||||
|
||||
- Remember to try the [latest WIP build](https://github.com/SabreTools/SabreTools.Hashing/releases/tag/rolling) to see if the feature already exists.
|
||||
- Check [previous issues](https://github.com/SabreTools/SabreTools.Hashing/issues) to see if any of those are related to what you're about to ask for.
|
||||
|
||||
If none of those apply, then continue...
|
||||
|
||||
**Is your information related to one of the checksums/hashes supported or something that isn't a bug in the code? Please describe.**
|
||||
A clear and concise description of what the information is. Ex. With the latest build of Hasher, it [...]
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the information here.
|
||||
45
.github/ISSUE_TEMPLATE/issue-report.md
vendored
Normal file
45
.github/ISSUE_TEMPLATE/issue-report.md
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
---
|
||||
name: Issue Report
|
||||
about: Tell me what's wrong, seriously
|
||||
title: "[Problem]"
|
||||
labels: bug
|
||||
assignees: mnadareski
|
||||
|
||||
---
|
||||
|
||||
**Before You Submit**
|
||||
|
||||
- Remember to try the [latest WIP build](https://github.com/SabreTools/SabreTools.Hashing/releases/tag/rolling) to see if the issue has already been addressed.
|
||||
- Check multiple inputs to help narrow down the issue
|
||||
|
||||
If all of those fail, then continue...
|
||||
|
||||
**Version**
|
||||
What version are you using?
|
||||
|
||||
- [ ] Stable release (version here)
|
||||
- [ ] WIP release (version here)
|
||||
|
||||
**Build**
|
||||
What runtime version are you using?
|
||||
|
||||
- [ ] .NET 10 running on (Operating System)
|
||||
|
||||
**Describe the issue**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
|
||||
1. Create the '...' hasher
|
||||
2. Run the hasher with '....'
|
||||
3. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
48
.github/workflows/build_and_test.yml
vendored
Normal file
48
.github/workflows/build_and_test.yml
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
name: Build and Test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["main"]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v5
|
||||
with:
|
||||
dotnet-version: |
|
||||
8.0.x
|
||||
9.0.x
|
||||
10.0.x
|
||||
|
||||
- name: Run tests
|
||||
run: dotnet test
|
||||
|
||||
- name: Run publish script
|
||||
run: ./publish-nix.sh -d
|
||||
|
||||
- name: Update rolling tag
|
||||
run: |
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git tag -f rolling
|
||||
git push origin :refs/tags/rolling || true
|
||||
git push origin rolling --force
|
||||
|
||||
- name: Upload to rolling
|
||||
uses: ncipollo/release-action@v1.20.0
|
||||
with:
|
||||
allowUpdates: True
|
||||
artifacts: "*.nupkg,*.snupkg,*.zip"
|
||||
body: "Last built commit: ${{ github.sha }}"
|
||||
name: "Rolling Release"
|
||||
prerelease: True
|
||||
replacesArtifacts: True
|
||||
tag: "rolling"
|
||||
updateOnlyUnreleased: True
|
||||
49
.github/workflows/build_nupkg.yml
vendored
49
.github/workflows/build_nupkg.yml
vendored
@@ -1,49 +0,0 @@
|
||||
name: Nuget Pack
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 8.0.x
|
||||
|
||||
- name: Restore dependencies
|
||||
run: dotnet restore
|
||||
|
||||
- name: Build library
|
||||
run: dotnet build
|
||||
|
||||
- name: Run tests
|
||||
run: dotnet test
|
||||
|
||||
- name: Pack
|
||||
run: dotnet pack
|
||||
|
||||
- name: Upload build
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: 'Nuget Package'
|
||||
path: 'SabreTools.Hashing/bin/Release/*.nupkg'
|
||||
|
||||
- name: Upload to rolling
|
||||
uses: ncipollo/release-action@v1.14.0
|
||||
with:
|
||||
allowUpdates: True
|
||||
artifacts: 'SabreTools.Hashing/bin/Release/*.nupkg'
|
||||
body: 'Last built commit: ${{ github.sha }}'
|
||||
name: 'Rolling Release'
|
||||
prerelease: True
|
||||
replacesArtifacts: True
|
||||
tag: "rolling"
|
||||
updateOnlyUnreleased: True
|
||||
31
.github/workflows/check_pr.yml
vendored
31
.github/workflows/check_pr.yml
vendored
@@ -3,18 +3,21 @@ name: Build PR
|
||||
on: [pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 8.0.x
|
||||
|
||||
- name: Build
|
||||
run: dotnet build
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- name: Run tests
|
||||
run: dotnet test
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v5
|
||||
with:
|
||||
dotnet-version: |
|
||||
8.0.x
|
||||
9.0.x
|
||||
10.0.x
|
||||
|
||||
- name: Build
|
||||
run: dotnet build
|
||||
|
||||
- name: Run tests
|
||||
run: dotnet test
|
||||
|
||||
28
.vscode/launch.json
vendored
Normal file
28
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
// Use IntelliSense to find out which attributes exist for C# debugging
|
||||
// Use hover for the description of the existing attributes
|
||||
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": ".NET Core Launch",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
// If you have changed target frameworks, make sure to update the program path.
|
||||
"program": "${workspaceFolder}/Hasher/bin/Debug/net10.0/Hasher.dll",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}",
|
||||
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
|
||||
"console": "internalConsole",
|
||||
"stopAtEntry": false,
|
||||
"justMyCode": false
|
||||
},
|
||||
{
|
||||
"name": ".NET Core Attach",
|
||||
"type": "coreclr",
|
||||
"request": "attach",
|
||||
"processId": "${command:pickProcess}"
|
||||
}
|
||||
]
|
||||
}
|
||||
52
Hasher/Features/ListFeature.cs
Normal file
52
Hasher/Features/ListFeature.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using SabreTools.CommandLine;
|
||||
using SabreTools.Hashing;
|
||||
|
||||
namespace Hasher.Features
|
||||
{
|
||||
internal sealed class ListFeature : Feature
|
||||
{
|
||||
#region Feature Definition
|
||||
|
||||
public const string DisplayName = "list";
|
||||
|
||||
private static readonly string[] _flags = ["--list"];
|
||||
|
||||
private const string _description = "List all available hashes and quit";
|
||||
|
||||
#endregion
|
||||
|
||||
public ListFeature()
|
||||
: base(DisplayName, _flags, _description)
|
||||
{
|
||||
RequiresInputs = false;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
/// TODO: Print all supported variants of names?
|
||||
public override bool Execute()
|
||||
{
|
||||
Console.WriteLine("Hash Name Parameter Name ");
|
||||
Console.WriteLine("--------------------------------------------------------------");
|
||||
|
||||
var hashTypes = (HashType[])Enum.GetValues(typeof(HashType));
|
||||
foreach (var hashType in hashTypes)
|
||||
{
|
||||
// Derive the parameter name
|
||||
string paramName = $"{hashType}";
|
||||
paramName = paramName.Replace("-", string.Empty);
|
||||
paramName = paramName.Replace(" ", string.Empty);
|
||||
paramName = paramName.Replace("/", "_");
|
||||
paramName = paramName.Replace("\\", "_");
|
||||
paramName = paramName.ToLowerInvariant();
|
||||
|
||||
Console.WriteLine($"{hashType.GetHashName()?.PadRight(39, ' ')} {paramName}");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool VerifyInputs() => true;
|
||||
}
|
||||
}
|
||||
170
Hasher/Features/MainFeature.cs
Normal file
170
Hasher/Features/MainFeature.cs
Normal file
@@ -0,0 +1,170 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using SabreTools.CommandLine;
|
||||
using SabreTools.CommandLine.Inputs;
|
||||
using SabreTools.Hashing;
|
||||
|
||||
namespace Hasher.Features
|
||||
{
|
||||
internal sealed class MainFeature : Feature
|
||||
{
|
||||
#region Feature Definition
|
||||
|
||||
public const string DisplayName = "main";
|
||||
|
||||
/// <remarks>Flags are unused</remarks>
|
||||
private static readonly string[] _flags = [];
|
||||
|
||||
/// <remarks>Description is unused</remarks>
|
||||
private const string _description = "";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Inputs
|
||||
|
||||
private const string _debugName = "debug";
|
||||
internal readonly FlagInput DebugInput = new(_debugName, ["-d", "--debug"], "Enable debug mode");
|
||||
|
||||
private const string _typeName = "type";
|
||||
internal readonly StringListInput TypeInput = new(_typeName, ["-t", "--type"], "Select included hashes");
|
||||
|
||||
#endregion
|
||||
|
||||
public MainFeature()
|
||||
: base(DisplayName, _flags, _description)
|
||||
{
|
||||
RequiresInputs = true;
|
||||
|
||||
Add(DebugInput);
|
||||
Add(TypeInput);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Execute()
|
||||
{
|
||||
// Get the required variables
|
||||
bool debug = GetBoolean(_debugName);
|
||||
List<HashType> hashTypes = GetHashTypes(GetStringList(_typeName));
|
||||
|
||||
// Loop through all of the input files
|
||||
for (int i = 0; i < Inputs.Count; i++)
|
||||
{
|
||||
string arg = Inputs[i];
|
||||
PrintPathHashes(arg, hashTypes, debug);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool VerifyInputs() => true;
|
||||
|
||||
/// <summary>
|
||||
/// Derive a list of hash types from a list of strings
|
||||
/// </summary>
|
||||
private static List<HashType> GetHashTypes(List<string> types)
|
||||
{
|
||||
List<HashType> hashTypes = [];
|
||||
if (types.Count == 0)
|
||||
{
|
||||
hashTypes.Add(HashType.CRC32);
|
||||
hashTypes.Add(HashType.MD5);
|
||||
hashTypes.Add(HashType.SHA1);
|
||||
hashTypes.Add(HashType.SHA256);
|
||||
}
|
||||
else if (types.Contains("all"))
|
||||
{
|
||||
hashTypes = [.. (HashType[])Enum.GetValues(typeof(HashType))];
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (string typeString in types)
|
||||
{
|
||||
HashType? hashType = typeString.GetHashType();
|
||||
if (hashType is not null && !hashTypes.Contains(hashType.Value))
|
||||
hashTypes.Add(item: hashType.Value);
|
||||
}
|
||||
}
|
||||
|
||||
return hashTypes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wrapper to print hashes for a single path
|
||||
/// </summary>
|
||||
/// <param name="path">File or directory path</param>
|
||||
/// <param name="hashTypes">Set of hashes to retrieve</param>
|
||||
/// <param name="debug">Enable debug output</param>
|
||||
private static void PrintPathHashes(string path, List<HashType> hashTypes, bool debug)
|
||||
{
|
||||
Console.WriteLine($"Checking possible path: {path}");
|
||||
|
||||
// Check if the file or directory exists
|
||||
if (File.Exists(path))
|
||||
{
|
||||
PrintFileHashes(path, hashTypes, debug);
|
||||
}
|
||||
else if (Directory.Exists(path))
|
||||
{
|
||||
foreach (string file in Directory.GetFiles(path, "*", SearchOption.AllDirectories))
|
||||
{
|
||||
PrintFileHashes(file, hashTypes, debug);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"{path} does not exist, skipping...");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Print information for a single file, if possible
|
||||
/// </summary>
|
||||
/// <param name="file">File path</param>
|
||||
/// <param name="hashTypes">Set of hashes to retrieve</param>
|
||||
/// <param name="debug">Enable debug output</param>
|
||||
private static void PrintFileHashes(string file, List<HashType> hashTypes, bool debug)
|
||||
{
|
||||
Console.WriteLine($"Attempting to hash {file}, this may take a while...");
|
||||
Console.WriteLine();
|
||||
|
||||
// If the file doesn't exist
|
||||
if (!File.Exists(file))
|
||||
{
|
||||
Console.WriteLine($"{file} does not exist, skipping...");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Get all file hashes for flexibility
|
||||
var hashes = HashTool.GetFileHashes(file);
|
||||
if (hashes is null)
|
||||
{
|
||||
if (debug) Console.WriteLine($"Hashes for {file} could not be retrieved");
|
||||
return;
|
||||
}
|
||||
|
||||
// Output subset of available hashes
|
||||
var builder = new StringBuilder();
|
||||
foreach (HashType hashType in hashTypes)
|
||||
{
|
||||
// TODO: Make helper to pretty-print hash type names
|
||||
if (hashes.TryGetValue(hashType, out string? hash) && hash is not null)
|
||||
builder.AppendLine($"{hashType}: {hash}");
|
||||
}
|
||||
|
||||
// Create and print the output data
|
||||
string hashData = builder.ToString();
|
||||
Console.WriteLine(hashData);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(debug ? ex : "[Exception opening file, please try again]");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
37
Hasher/Hasher.csproj
Normal file
37
Hasher/Hasher.csproj
Normal file
@@ -0,0 +1,37 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0;net9.0;net10.0</TargetFrameworks>
|
||||
<OutputType>Exe</OutputType>
|
||||
<CheckEolTargetFramework>false</CheckEolTargetFramework>
|
||||
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
|
||||
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<Version>1.6.0</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Support All Frameworks -->
|
||||
<PropertyGroup Condition="$(TargetFramework.StartsWith(`net2`)) OR $(TargetFramework.StartsWith(`net3`)) OR $(TargetFramework.StartsWith(`net4`))">
|
||||
<RuntimeIdentifiers>win-x86;win-x64</RuntimeIdentifiers>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="$(TargetFramework.StartsWith(`netcoreapp`)) OR $(TargetFramework.StartsWith(`net5`))">
|
||||
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64</RuntimeIdentifiers>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="$(TargetFramework.StartsWith(`net6`)) OR $(TargetFramework.StartsWith(`net7`)) OR $(TargetFramework.StartsWith(`net8`)) OR $(TargetFramework.StartsWith(`net9`)) OR $(TargetFramework.StartsWith(`net10`))">
|
||||
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64;osx-arm64</RuntimeIdentifiers>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="$(RuntimeIdentifier.StartsWith(`osx-arm`))">
|
||||
<TargetFrameworks>net6.0;net7.0;net8.0;net9.0;net10.0</TargetFrameworks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SabreTools.Hashing\SabreTools.Hashing.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SabreTools.CommandLine" Version="[1.4.0]" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
87
Hasher/Program.cs
Normal file
87
Hasher/Program.cs
Normal file
@@ -0,0 +1,87 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Hasher.Features;
|
||||
using SabreTools.CommandLine;
|
||||
using SabreTools.CommandLine.Features;
|
||||
|
||||
namespace Hasher
|
||||
{
|
||||
public static class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
// Create the command set
|
||||
var mainFeature = new MainFeature();
|
||||
var commandSet = CreateCommands(mainFeature);
|
||||
|
||||
// If we have no args, show the help and quit
|
||||
if (args is null || args.Length == 0)
|
||||
{
|
||||
commandSet.OutputAllHelp();
|
||||
return;
|
||||
}
|
||||
|
||||
// Cache the first argument and starting index
|
||||
string featureName = args[0];
|
||||
|
||||
// Try processing the standalone arguments
|
||||
var topLevel = commandSet.GetTopLevel(featureName);
|
||||
switch (topLevel)
|
||||
{
|
||||
// Standalone Options
|
||||
case Help help: help.ProcessArgs(args, 0, commandSet); return;
|
||||
case ListFeature lf: lf.Execute(); return;
|
||||
|
||||
// Default Behavior
|
||||
default:
|
||||
if (!mainFeature.ProcessArgs(args, 0))
|
||||
{
|
||||
commandSet.OutputAllHelp();
|
||||
return;
|
||||
}
|
||||
else if (!mainFeature.VerifyInputs())
|
||||
{
|
||||
Console.Error.WriteLine("At least one input is required");
|
||||
commandSet.OutputAllHelp();
|
||||
return;
|
||||
}
|
||||
|
||||
mainFeature.Execute();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create the command set for the program
|
||||
/// </summary>
|
||||
private static CommandSet CreateCommands(MainFeature mainFeature)
|
||||
{
|
||||
List<string> header = [
|
||||
"File Hashing Program",
|
||||
string.Empty,
|
||||
"Hasher <options> file|directory ...",
|
||||
string.Empty,
|
||||
];
|
||||
|
||||
List<string> footer = [
|
||||
string.Empty,
|
||||
"If no hash types are provided, this tool will default to",
|
||||
"outputting CRC-32, MD5, SHA-1, and SHA-256.",
|
||||
"Optionally, all supported hashes can be output by",
|
||||
"specifying a value of 'all'.",
|
||||
];
|
||||
|
||||
var commandSet = new CommandSet(header, footer);
|
||||
|
||||
// Standalone Options
|
||||
commandSet.Add(new Help(["-?", "-h", "--help"]));
|
||||
commandSet.Add(new ListFeature());
|
||||
|
||||
// Hasher Options
|
||||
commandSet.Add(mainFeature.DebugInput);
|
||||
commandSet.Add(mainFeature.TypeInput);
|
||||
|
||||
return commandSet;
|
||||
}
|
||||
}
|
||||
}
|
||||
7
LICENSE
Normal file
7
LICENSE
Normal file
@@ -0,0 +1,7 @@
|
||||
Copyright (c) 2018-2025 Matt Nadareski
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
60
README.MD
60
README.MD
@@ -1,14 +1,60 @@
|
||||
# SabreTools.Hashing
|
||||
|
||||
This library comprises of methods and helpers to simplify the process of getting checksums and hashes from both files and streams. See the following table for information about where each of the various components comes from:
|
||||
[](https://github.com/SabreTools/SabreTools.Hashing/actions/workflows/build_and_test.yml)
|
||||
|
||||
This library comprises of methods and helpers to simplify the process of getting checksums and hashes from both files and streams.
|
||||
|
||||
Find the link to the Nuget package [here](https://www.nuget.org/packages/SabreTools.Hashing).
|
||||
|
||||
## Releases
|
||||
|
||||
For the most recent stable build, download the latest release here: [Releases Page](https://github.com/SabreTools/SabreTools.Hashing/releases)
|
||||
|
||||
For the latest WIP build here: [Rolling Release](https://github.com/SabreTools/SabreTools.Hashing/releases/rolling)
|
||||
|
||||
## Hasher
|
||||
|
||||
**Hasher** is a reference implementation for hashing and checksumming features of the library, packaged as a standalone executable for all supported platforms. It will attempt to select the correct hashing types based on input and then print the calculated values to standard output.
|
||||
|
||||
```text
|
||||
Hasher <options> file|directory ...
|
||||
|
||||
Available options:
|
||||
-?, -h, --help Show this help
|
||||
--list List all available hashes and quit
|
||||
-d, --debug Enable debug mode
|
||||
-t=, --type= Select included hashes
|
||||
|
||||
If no hash types are provided, this tool will default to
|
||||
outputting CRC-32, MD5, SHA-1, and SHA-256.
|
||||
Optionally, all supported hashes can be output by
|
||||
specifying a value of 'all'.
|
||||
```
|
||||
|
||||
## Internal Implementations
|
||||
|
||||
All hash and checksum types here have been written to ensure compatibility across all .NET versions. Some may have been adapted to ensure this compatibility. These can be treated as reference implementations, not always optimized.
|
||||
|
||||
| Hash / Checksum Type | Notes |
|
||||
| --- | --- |
|
||||
| Adler-32 | Based on the [zlib source code](https://github.com/madler/zlib/blob/v1.2.11/adler32.c) |
|
||||
| CRC | All CRC values documented [here](https://reveng.sourceforge.io/crc-catalogue/all.htm) except for CRC-82 due to bit-length restrictions |
|
||||
| Fletcher | 16-, 32-, and 64-bit variants |
|
||||
| FNV | 32-, and 64-bit variants; 0, 1, and 1a algorithms |
|
||||
| Message Digest | MD2 and MD4 only |
|
||||
| RIPEMD | 128-, 160-, 256-, and 320-bit variants |
|
||||
| SpamSum | Based on the [SSDEEP source code](https://github.com/ssdeep-project/ssdeep/blob/master/fuzzy.c) |
|
||||
| Tiger | 128-, 160-, and 192-bit variants; 3- and 4-pass; `0x01` and `0x80` (Tiger2) pad-initialized |
|
||||
| xxHash | xxHash-32 and xxHash-64 only |
|
||||
|
||||
## External Implementations
|
||||
|
||||
External implementations of hash and checksum types may not be compatible with all .NET versions. Please see the table below for more information about support.
|
||||
|
||||
| Source | Hash / Checksum Types | Notes |
|
||||
| --- | --- | --- |
|
||||
| [Aaru.Checksums](https://github.com/aaru-dps/Aaru.Checksums) | Adler-32, CRC-16 (CCITT and IBM polynomials), CRC-32, CRC-64 (Normal and Reversed Polynomials), Fletcher-16, Fletcher-32, SpamSum | Some code tweaks made to support older .NET versions, CRC-32 implementation used in `net20`, `net35`, `net40`, and `net452` |
|
||||
| [Blake3.NET](https://github.com/xoofx/Blake3.NET) | BLAKE3 | Used in `net7.0` and above |
|
||||
| [Compress](https://github.com/RomVault/RVWorld/tree/master/Compress) | N/A | Used for threaded hashing |
|
||||
| [CRC32](https://gitlab.com/eugene77/CRC32) | CRC-32 (Multiple implementations) | |
|
||||
| [System.IO.Hashing](https://www.nuget.org/packages/System.IO.Hashing) | CRC-32, CRC-64 (Normal Polynomial), xxHash32, xxHash64, XXH3, XXH128 | Used in `net462` and above |
|
||||
| [System.Security.Cryptography](https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography) | MD5, RIPEMD160 (.NET Framework only), SHA-1, SHA-256, SHA-384, SHA-512, SHA3-256, SHA3-384, SHA3-512, SHAKE128, SHAKE256 | Built-in library; SHA3-256, SHA3-384, SHA3-512, SHAKE128, and SHAKE256 are `net8.0` and above only for [supported platforms](https://learn.microsoft.com/en-us/dotnet/standard/security/cross-platform-cryptography) |
|
||||
| [System.IO.Hashing](https://www.nuget.org/packages/System.IO.Hashing) | XXH3, XXH128 | Used in `net462` and above |
|
||||
| [System.Security.Cryptography](https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography) | MD5, SHA-1, SHA-256, SHA-384, SHA-512, SHA3-256, SHA3-384, SHA3-512, SHAKE128, SHAKE256 | Built-in library; SHA3-256, SHA3-384, SHA3-512, SHAKE128, and SHAKE256 are `net8.0` and above only for [supported platforms](https://learn.microsoft.com/en-us/dotnet/standard/security/cross-platform-cryptography) |
|
||||
|
||||
Find the link to the Nuget package [here](https://www.nuget.org/packages/SabreTools.Hashing).
|
||||
**Note:** If all you care about is performance, I encourage you to forego this library and use the ones listed above directly instead.
|
||||
|
||||
@@ -7,94 +7,55 @@ namespace SabreTools.Hashing.Test
|
||||
{
|
||||
public class CompressedStreamTests
|
||||
{
|
||||
private static readonly string _hashFilePath = Path.Combine(Environment.CurrentDirectory, "TestData", "file-to-hash.zip");
|
||||
/// <summary>
|
||||
/// Path to PKZIP archive containing a single compressed file to hash
|
||||
/// </summary>
|
||||
private static readonly string _singleGzipFilePath
|
||||
= Path.Combine(Environment.CurrentDirectory, "TestData", "file-to-hash.bin.gz");
|
||||
|
||||
#region Known File Information
|
||||
/// <summary>
|
||||
/// Path to PKZIP archive containing a single compressed file to hash
|
||||
/// </summary>
|
||||
private static readonly string _singleZipFilePath
|
||||
= Path.Combine(Environment.CurrentDirectory, "TestData", "file-to-hash.zip");
|
||||
|
||||
private const long _hashFileSize = 125;
|
||||
private const string _adler32 = "08562d95";
|
||||
#if NET7_0_OR_GREATER
|
||||
private const string _blake3 = "d4bd7ca6f1ebea9580d9381106b248eb5b6069170d0bfd00b17d659fcd10dcdc";
|
||||
#endif
|
||||
private const string _crc16_ccitt = "482d";
|
||||
private const string _crc16_ibm = "7573";
|
||||
private const string _crc32 = "ba02a660";
|
||||
private const string _crc64 = "a0e0009c18b5338d";
|
||||
private const string _crc64_reversed = "fb49044e8331f6e5";
|
||||
private const string _fletcher16 = "46c1";
|
||||
private const string _fletcher32 = "073f2d94";
|
||||
private const string _md5 = "b722871eaa950016296184d026c5dec9";
|
||||
#if NETFRAMEWORK
|
||||
private const string _ripemd160 = "346361e1d7fdb836650cecdb842b0dbe660eed66";
|
||||
#endif
|
||||
private const string _sha1 = "eea1ee2d801d830c4bdad4df3c8da6f9f52d1a9f";
|
||||
private const string _sha256 = "fdb02dee8c319c52087382c45f099c90d0b6cc824850aff28c1bfb2884b7b855";
|
||||
private const string _sha384 = "e276c49618fff25bc1fe2e0659cd0ef0e7c1186563b063e07c52323b9899f3ce9b091be04d6208444b3ef1265e879074";
|
||||
private const string _sha512 = "15d69514eb628c2403e945a7cafd1d27e557f6e336c69b63ea17e7ed9d256cc374ee662f09305836d6de37fdae59d83883b982aa8446e4ff26346b6b6b50b240";
|
||||
#if NET8_0_OR_GREATER
|
||||
private const string _sha3_256 = "1d76459e68c865b5911ada5104067cc604c5c60b345c4e81b3905e916a43c868";
|
||||
private const string _sha3_384 = "1bcbed87b73f25c0adf486c3afbf0ea3105763c387af3f8b2bd79b0a1964d42832b1d7c6a2225f9153ead26f442e8b67";
|
||||
private const string _sha3_512 = "89852144df37c58d01f5912124f1942dd00bac0346eb3971943416699c3094cff087fb42c356019c3d91f8e8f55b9254c8caec48e9414af6817297d06725ffeb";
|
||||
private const string _shake128 = "e5f88d0db79a71c39490beb9ebac21eaf4a5d6368438fca20f5e4ce77cfee9aa";
|
||||
private const string _shake256 = "24d9e83198bbc7baf4dcd293bfc35ae3fff05399786c37318f1b1ef85f41970c66926f8a2a1f912d96e2d8e45535af88a301a1c200697437c1a65d7e980344bc";
|
||||
#endif
|
||||
private const string _spamsum = "3:hMCPQCE6AFQxWyENFACBE+rW6Tj7SMQmKozr9MVERkL:hZRdxZENFs+rPSromekL";
|
||||
#if NET462_OR_GREATER || NETCOREAPP
|
||||
private const string _xxhash32 = "8e331daa";
|
||||
private const string _xxhash64 = "082bf6f0a49e1e18";
|
||||
private const string _xxhash3 = "040474eb0eda9ff2";
|
||||
private const string _xxhash128 = "d934b4b4a5e1e11baeef8012fbcd11e8";
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
/// <summary>
|
||||
/// Path to PKZIP archive containing a multiple compressed files to hash
|
||||
/// </summary>
|
||||
private static readonly string _multiZipFilePath
|
||||
= Path.Combine(Environment.CurrentDirectory, "TestData", "file-to-hash-multi.zip");
|
||||
|
||||
[Fact]
|
||||
public void GetStreamHashesTest()
|
||||
public void GetSingleGzipStreamHashesTest()
|
||||
{
|
||||
var zipFile = ZipFile.OpenRead(_hashFilePath);
|
||||
var fileStream = zipFile.Entries[0].Open();
|
||||
var hashDict = HashTool.GetStreamHashes(fileStream);
|
||||
var gzipStream = new GZipStream(File.OpenRead(_singleGzipFilePath), CompressionMode.Decompress);
|
||||
var hashDict = HashTool.GetStreamHashesAndSize(gzipStream, out long actualSize);
|
||||
TestHelper.ValidateSize(actualSize);
|
||||
TestHelper.ValidateHashes(hashDict);
|
||||
}
|
||||
|
||||
Assert.NotNull(hashDict);
|
||||
Assert.Equal(_adler32, hashDict![HashType.Adler32]);
|
||||
#if NET7_0_OR_GREATER
|
||||
Assert.Equal(_blake3, hashDict[HashType.BLAKE3]);
|
||||
#endif
|
||||
Assert.Equal(_crc16_ccitt, hashDict[HashType.CRC16_CCITT]);
|
||||
Assert.Equal(_crc16_ibm, hashDict[HashType.CRC16_IBM]);
|
||||
Assert.Equal(_crc32, hashDict[HashType.CRC32]);
|
||||
Assert.Equal(_crc32, hashDict[HashType.CRC32_ISO]);
|
||||
Assert.Equal(_crc32, hashDict[HashType.CRC32_Naive]);
|
||||
Assert.Equal(_crc32, hashDict[HashType.CRC32_Optimized]);
|
||||
Assert.Equal(_crc32, hashDict[HashType.CRC32_Parallel]);
|
||||
Assert.Equal(_crc64, hashDict[HashType.CRC64]);
|
||||
Assert.Equal(_crc64_reversed, hashDict[HashType.CRC64_Reversed]);
|
||||
Assert.Equal(_fletcher16, hashDict[HashType.Fletcher16]);
|
||||
Assert.Equal(_fletcher32, hashDict[HashType.Fletcher32]);
|
||||
Assert.Equal(_md5, hashDict[HashType.MD5]);
|
||||
Assert.Equal(_sha1, hashDict[HashType.SHA1]);
|
||||
Assert.Equal(_sha256, hashDict[HashType.SHA256]);
|
||||
Assert.Equal(_sha384, hashDict[HashType.SHA384]);
|
||||
Assert.Equal(_sha512, hashDict[HashType.SHA512]);
|
||||
#if NET8_0_OR_GREATER
|
||||
if (System.Security.Cryptography.SHA3_256.IsSupported)
|
||||
Assert.Equal(_sha3_256, hashDict[HashType.SHA3_256]);
|
||||
if (System.Security.Cryptography.SHA3_384.IsSupported)
|
||||
Assert.Equal(_sha3_384, hashDict[HashType.SHA3_384]);
|
||||
if (System.Security.Cryptography.SHA3_512.IsSupported)
|
||||
Assert.Equal(_sha3_512, hashDict[HashType.SHA3_512]);
|
||||
if (System.Security.Cryptography.Shake128.IsSupported)
|
||||
Assert.Equal(_shake128, hashDict[HashType.SHAKE128]);
|
||||
if (System.Security.Cryptography.Shake256.IsSupported)
|
||||
Assert.Equal(_shake256, hashDict[HashType.SHAKE256]);
|
||||
#endif
|
||||
Assert.Equal(_spamsum, hashDict[HashType.SpamSum]);
|
||||
#if NET462_OR_GREATER || NETCOREAPP
|
||||
Assert.Equal(_xxhash32, hashDict[HashType.XxHash32]);
|
||||
Assert.Equal(_xxhash64, hashDict[HashType.XxHash64]);
|
||||
Assert.Equal(_xxhash3, hashDict[HashType.XxHash3]);
|
||||
Assert.Equal(_xxhash128, hashDict[HashType.XxHash128]);
|
||||
#endif
|
||||
[Fact]
|
||||
public void GetSingleDeflateStreamHashesTest()
|
||||
{
|
||||
var zipFile = ZipFile.OpenRead(_singleZipFilePath);
|
||||
var fileStream = zipFile.Entries[0].Open();
|
||||
var hashDict = HashTool.GetStreamHashesAndSize(fileStream, out long actualSize);
|
||||
TestHelper.ValidateSize(actualSize);
|
||||
TestHelper.ValidateHashes(hashDict);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMultiDeflateStreamHashesTest()
|
||||
{
|
||||
var zipFile = ZipFile.OpenRead(_multiZipFilePath);
|
||||
|
||||
for (int i = 0; i < zipFile.Entries.Count; i++)
|
||||
{
|
||||
var fileStream = zipFile.Entries[i].Open();
|
||||
var hashDict = HashTool.GetStreamHashesAndSize(fileStream, out long actualSize);
|
||||
TestHelper.ValidateSize(actualSize);
|
||||
TestHelper.ValidateHashes(hashDict);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,155 +6,89 @@ namespace SabreTools.Hashing.Test
|
||||
{
|
||||
public class HashToolTests
|
||||
{
|
||||
private static readonly string _hashFilePath = Path.Combine(Environment.CurrentDirectory, "TestData", "file-to-hash.bin");
|
||||
/// <summary>
|
||||
/// Path to the uncompressed file to hash
|
||||
/// </summary>
|
||||
private static readonly string _hashFilePath
|
||||
= Path.Combine(Environment.CurrentDirectory, "TestData", "file-to-hash.bin");
|
||||
|
||||
#region Known File Information
|
||||
/// <summary>
|
||||
/// Get an array of all hash types
|
||||
/// </summary>
|
||||
public static TheoryData<HashType> AllHashTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
var values = Enum.GetValues<HashType>();
|
||||
var set = new TheoryData<HashType>();
|
||||
foreach (var value in values)
|
||||
{
|
||||
set.Add(value);
|
||||
}
|
||||
|
||||
private const long _hashFileSize = 125;
|
||||
private const string _adler32 = "08562d95";
|
||||
#if NET7_0_OR_GREATER
|
||||
private const string _blake3 = "d4bd7ca6f1ebea9580d9381106b248eb5b6069170d0bfd00b17d659fcd10dcdc";
|
||||
#endif
|
||||
private const string _crc16_ccitt = "482d";
|
||||
private const string _crc16_ibm = "7573";
|
||||
private const string _crc32 = "ba02a660";
|
||||
private const string _crc64 = "a0e0009c18b5338d";
|
||||
private const string _crc64_reversed = "fb49044e8331f6e5";
|
||||
private const string _fletcher16 = "46c1";
|
||||
private const string _fletcher32 = "073f2d94";
|
||||
private const string _md5 = "b722871eaa950016296184d026c5dec9";
|
||||
#if NETFRAMEWORK
|
||||
private const string _ripemd160 = "346361e1d7fdb836650cecdb842b0dbe660eed66";
|
||||
#endif
|
||||
private const string _sha1 = "eea1ee2d801d830c4bdad4df3c8da6f9f52d1a9f";
|
||||
private const string _sha256 = "fdb02dee8c319c52087382c45f099c90d0b6cc824850aff28c1bfb2884b7b855";
|
||||
private const string _sha384 = "e276c49618fff25bc1fe2e0659cd0ef0e7c1186563b063e07c52323b9899f3ce9b091be04d6208444b3ef1265e879074";
|
||||
private const string _sha512 = "15d69514eb628c2403e945a7cafd1d27e557f6e336c69b63ea17e7ed9d256cc374ee662f09305836d6de37fdae59d83883b982aa8446e4ff26346b6b6b50b240";
|
||||
#if NET8_0_OR_GREATER
|
||||
private const string _sha3_256 = "1d76459e68c865b5911ada5104067cc604c5c60b345c4e81b3905e916a43c868";
|
||||
private const string _sha3_384 = "1bcbed87b73f25c0adf486c3afbf0ea3105763c387af3f8b2bd79b0a1964d42832b1d7c6a2225f9153ead26f442e8b67";
|
||||
private const string _sha3_512 = "89852144df37c58d01f5912124f1942dd00bac0346eb3971943416699c3094cff087fb42c356019c3d91f8e8f55b9254c8caec48e9414af6817297d06725ffeb";
|
||||
private const string _shake128 = "e5f88d0db79a71c39490beb9ebac21eaf4a5d6368438fca20f5e4ce77cfee9aa";
|
||||
private const string _shake256 = "24d9e83198bbc7baf4dcd293bfc35ae3fff05399786c37318f1b1ef85f41970c66926f8a2a1f912d96e2d8e45535af88a301a1c200697437c1a65d7e980344bc";
|
||||
#endif
|
||||
private const string _spamsum = "3:hMCPQCE6AFQxWyENFACBE+rW6Tj7SMQmKozr9MVERkL:hZRdxZENFs+rPSromekL";
|
||||
#if NET462_OR_GREATER || NETCOREAPP
|
||||
private const string _xxhash32 = "8e331daa";
|
||||
private const string _xxhash64 = "082bf6f0a49e1e18";
|
||||
private const string _xxhash3 = "040474eb0eda9ff2";
|
||||
private const string _xxhash128 = "d934b4b4a5e1e11baeef8012fbcd11e8";
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
return set;
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetStandardHashesTest()
|
||||
public void GetStandardHashesFileTest()
|
||||
{
|
||||
bool gotHashes = HashTool.GetStandardHashes(_hashFilePath, out long actualSize, out string? crc32, out string? md5, out string? sha1);
|
||||
|
||||
Assert.True(gotHashes);
|
||||
Assert.Equal(_hashFileSize, actualSize);
|
||||
Assert.Equal(_crc32, crc32);
|
||||
Assert.Equal(_md5, md5);
|
||||
Assert.Equal(_sha1, sha1);
|
||||
TestHelper.ValidateSize(actualSize);
|
||||
TestHelper.ValidateHash(HashType.CRC32, crc32);
|
||||
TestHelper.ValidateHash(HashType.MD5, md5);
|
||||
TestHelper.ValidateHash(HashType.SHA1, sha1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFileHashesTest()
|
||||
public void GetStandardHashesArrayTest()
|
||||
{
|
||||
byte[] fileBytes = File.ReadAllBytes(_hashFilePath);
|
||||
bool gotHashes = HashTool.GetStandardHashes(fileBytes, out long actualSize, out string? crc32, out string? md5, out string? sha1);
|
||||
|
||||
Assert.True(gotHashes);
|
||||
TestHelper.ValidateSize(actualSize);
|
||||
TestHelper.ValidateHash(HashType.CRC32, crc32);
|
||||
TestHelper.ValidateHash(HashType.MD5, md5);
|
||||
TestHelper.ValidateHash(HashType.SHA1, sha1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetStandardHashesStreamTest()
|
||||
{
|
||||
var fileStream = File.OpenRead(_hashFilePath);
|
||||
bool gotHashes = HashTool.GetStandardHashes(fileStream, out long actualSize, out string? crc32, out string? md5, out string? sha1);
|
||||
|
||||
Assert.True(gotHashes);
|
||||
TestHelper.ValidateSize(actualSize);
|
||||
TestHelper.ValidateHash(HashType.CRC32, crc32);
|
||||
TestHelper.ValidateHash(HashType.MD5, md5);
|
||||
TestHelper.ValidateHash(HashType.SHA1, sha1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFileHashesParallelTest()
|
||||
{
|
||||
var hashDict = HashTool.GetFileHashes(_hashFilePath);
|
||||
TestHelper.ValidateHashes(hashDict);
|
||||
}
|
||||
|
||||
Assert.NotNull(hashDict);
|
||||
Assert.Equal(_adler32, hashDict![HashType.Adler32]);
|
||||
#if NET7_0_OR_GREATER
|
||||
Assert.Equal(_blake3, hashDict[HashType.BLAKE3]);
|
||||
#endif
|
||||
Assert.Equal(_crc16_ccitt, hashDict[HashType.CRC16_CCITT]);
|
||||
Assert.Equal(_crc16_ibm, hashDict[HashType.CRC16_IBM]);
|
||||
Assert.Equal(_crc32, hashDict[HashType.CRC32]);
|
||||
Assert.Equal(_crc32, hashDict[HashType.CRC32_ISO]);
|
||||
Assert.Equal(_crc32, hashDict[HashType.CRC32_Naive]);
|
||||
Assert.Equal(_crc32, hashDict[HashType.CRC32_Optimized]);
|
||||
Assert.Equal(_crc32, hashDict[HashType.CRC32_Parallel]);
|
||||
Assert.Equal(_crc64, hashDict[HashType.CRC64]);
|
||||
Assert.Equal(_crc64_reversed, hashDict[HashType.CRC64_Reversed]);
|
||||
Assert.Equal(_fletcher16, hashDict[HashType.Fletcher16]);
|
||||
Assert.Equal(_fletcher32, hashDict[HashType.Fletcher32]);
|
||||
Assert.Equal(_md5, hashDict[HashType.MD5]);
|
||||
#if NETFRAMEWORK
|
||||
Assert.Equal(_ripemd160, hashDict[HashType.RIPEMD160]);
|
||||
#endif
|
||||
Assert.Equal(_sha1, hashDict[HashType.SHA1]);
|
||||
Assert.Equal(_sha256, hashDict[HashType.SHA256]);
|
||||
Assert.Equal(_sha384, hashDict[HashType.SHA384]);
|
||||
Assert.Equal(_sha512, hashDict[HashType.SHA512]);
|
||||
#if NET8_0_OR_GREATER
|
||||
if (System.Security.Cryptography.SHA3_256.IsSupported)
|
||||
Assert.Equal(_sha3_256, hashDict[HashType.SHA3_256]);
|
||||
if (System.Security.Cryptography.SHA3_384.IsSupported)
|
||||
Assert.Equal(_sha3_384, hashDict[HashType.SHA3_384]);
|
||||
if (System.Security.Cryptography.SHA3_512.IsSupported)
|
||||
Assert.Equal(_sha3_512, hashDict[HashType.SHA3_512]);
|
||||
if (System.Security.Cryptography.Shake128.IsSupported)
|
||||
Assert.Equal(_shake128, hashDict[HashType.SHAKE128]);
|
||||
if (System.Security.Cryptography.Shake256.IsSupported)
|
||||
Assert.Equal(_shake256, hashDict[HashType.SHAKE256]);
|
||||
#endif
|
||||
Assert.Equal(_spamsum, hashDict[HashType.SpamSum]);
|
||||
#if NET462_OR_GREATER || NETCOREAPP
|
||||
Assert.Equal(_xxhash32, hashDict[HashType.XxHash32]);
|
||||
Assert.Equal(_xxhash64, hashDict[HashType.XxHash64]);
|
||||
Assert.Equal(_xxhash3, hashDict[HashType.XxHash3]);
|
||||
Assert.Equal(_xxhash128, hashDict[HashType.XxHash128]);
|
||||
#endif
|
||||
[Theory]
|
||||
[MemberData(nameof(AllHashTypes))]
|
||||
public void GetFileHashesSerialTest(HashType hashType)
|
||||
{
|
||||
var hashValue = HashTool.GetFileHash(_hashFilePath, hashType);
|
||||
TestHelper.ValidateHash(hashType, hashValue);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFileHashesAndSizeTest()
|
||||
{
|
||||
var hashDict = HashTool.GetFileHashesAndSize(_hashFilePath, out long actualSize);
|
||||
|
||||
Assert.Equal(_hashFileSize, actualSize);
|
||||
Assert.NotNull(hashDict);
|
||||
Assert.Equal(_adler32, hashDict![HashType.Adler32]);
|
||||
#if NET7_0_OR_GREATER
|
||||
Assert.Equal(_blake3, hashDict[HashType.BLAKE3]);
|
||||
#endif
|
||||
Assert.Equal(_crc16_ccitt, hashDict[HashType.CRC16_CCITT]);
|
||||
Assert.Equal(_crc16_ibm, hashDict[HashType.CRC16_IBM]);
|
||||
Assert.Equal(_crc32, hashDict[HashType.CRC32]);
|
||||
Assert.Equal(_crc32, hashDict[HashType.CRC32_ISO]);
|
||||
Assert.Equal(_crc32, hashDict[HashType.CRC32_Naive]);
|
||||
Assert.Equal(_crc32, hashDict[HashType.CRC32_Optimized]);
|
||||
Assert.Equal(_crc32, hashDict[HashType.CRC32_Parallel]);
|
||||
Assert.Equal(_crc64, hashDict[HashType.CRC64]);
|
||||
Assert.Equal(_crc64_reversed, hashDict[HashType.CRC64_Reversed]);
|
||||
Assert.Equal(_fletcher16, hashDict[HashType.Fletcher16]);
|
||||
Assert.Equal(_fletcher32, hashDict[HashType.Fletcher32]);
|
||||
Assert.Equal(_md5, hashDict[HashType.MD5]);
|
||||
Assert.Equal(_sha1, hashDict[HashType.SHA1]);
|
||||
Assert.Equal(_sha256, hashDict[HashType.SHA256]);
|
||||
Assert.Equal(_sha384, hashDict[HashType.SHA384]);
|
||||
Assert.Equal(_sha512, hashDict[HashType.SHA512]);
|
||||
#if NET8_0_OR_GREATER
|
||||
if (System.Security.Cryptography.SHA3_256.IsSupported)
|
||||
Assert.Equal(_sha3_256, hashDict[HashType.SHA3_256]);
|
||||
if (System.Security.Cryptography.SHA3_384.IsSupported)
|
||||
Assert.Equal(_sha3_384, hashDict[HashType.SHA3_384]);
|
||||
if (System.Security.Cryptography.SHA3_512.IsSupported)
|
||||
Assert.Equal(_sha3_512, hashDict[HashType.SHA3_512]);
|
||||
if (System.Security.Cryptography.Shake128.IsSupported)
|
||||
Assert.Equal(_shake128, hashDict[HashType.SHAKE128]);
|
||||
if (System.Security.Cryptography.Shake256.IsSupported)
|
||||
Assert.Equal(_shake256, hashDict[HashType.SHAKE256]);
|
||||
#endif
|
||||
Assert.Equal(_spamsum, hashDict[HashType.SpamSum]);
|
||||
#if NET462_OR_GREATER || NETCOREAPP
|
||||
Assert.Equal(_xxhash32, hashDict[HashType.XxHash32]);
|
||||
Assert.Equal(_xxhash64, hashDict[HashType.XxHash64]);
|
||||
Assert.Equal(_xxhash3, hashDict[HashType.XxHash3]);
|
||||
Assert.Equal(_xxhash128, hashDict[HashType.XxHash128]);
|
||||
#endif
|
||||
TestHelper.ValidateSize(actualSize);
|
||||
TestHelper.ValidateHashes(hashDict);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -162,47 +96,16 @@ namespace SabreTools.Hashing.Test
|
||||
{
|
||||
byte[] fileBytes = File.ReadAllBytes(_hashFilePath);
|
||||
var hashDict = HashTool.GetByteArrayHashes(fileBytes);
|
||||
TestHelper.ValidateHashes(hashDict);
|
||||
}
|
||||
|
||||
Assert.NotNull(hashDict);
|
||||
Assert.Equal(_adler32, hashDict![HashType.Adler32]);
|
||||
#if NET7_0_OR_GREATER
|
||||
Assert.Equal(_blake3, hashDict[HashType.BLAKE3]);
|
||||
#endif
|
||||
Assert.Equal(_crc16_ccitt, hashDict[HashType.CRC16_CCITT]);
|
||||
Assert.Equal(_crc16_ibm, hashDict[HashType.CRC16_IBM]);
|
||||
Assert.Equal(_crc32, hashDict[HashType.CRC32]);
|
||||
Assert.Equal(_crc32, hashDict[HashType.CRC32_ISO]);
|
||||
Assert.Equal(_crc32, hashDict[HashType.CRC32_Naive]);
|
||||
Assert.Equal(_crc32, hashDict[HashType.CRC32_Optimized]);
|
||||
Assert.Equal(_crc32, hashDict[HashType.CRC32_Parallel]);
|
||||
Assert.Equal(_crc64, hashDict[HashType.CRC64]);
|
||||
Assert.Equal(_crc64_reversed, hashDict[HashType.CRC64_Reversed]);
|
||||
Assert.Equal(_fletcher16, hashDict[HashType.Fletcher16]);
|
||||
Assert.Equal(_fletcher32, hashDict[HashType.Fletcher32]);
|
||||
Assert.Equal(_md5, hashDict[HashType.MD5]);
|
||||
Assert.Equal(_sha1, hashDict[HashType.SHA1]);
|
||||
Assert.Equal(_sha256, hashDict[HashType.SHA256]);
|
||||
Assert.Equal(_sha384, hashDict[HashType.SHA384]);
|
||||
Assert.Equal(_sha512, hashDict[HashType.SHA512]);
|
||||
#if NET8_0_OR_GREATER
|
||||
if (System.Security.Cryptography.SHA3_256.IsSupported)
|
||||
Assert.Equal(_sha3_256, hashDict[HashType.SHA3_256]);
|
||||
if (System.Security.Cryptography.SHA3_384.IsSupported)
|
||||
Assert.Equal(_sha3_384, hashDict[HashType.SHA3_384]);
|
||||
if (System.Security.Cryptography.SHA3_512.IsSupported)
|
||||
Assert.Equal(_sha3_512, hashDict[HashType.SHA3_512]);
|
||||
if (System.Security.Cryptography.Shake128.IsSupported)
|
||||
Assert.Equal(_shake128, hashDict[HashType.SHAKE128]);
|
||||
if (System.Security.Cryptography.Shake256.IsSupported)
|
||||
Assert.Equal(_shake256, hashDict[HashType.SHAKE256]);
|
||||
#endif
|
||||
Assert.Equal(_spamsum, hashDict[HashType.SpamSum]);
|
||||
#if NET462_OR_GREATER || NETCOREAPP
|
||||
Assert.Equal(_xxhash32, hashDict[HashType.XxHash32]);
|
||||
Assert.Equal(_xxhash64, hashDict[HashType.XxHash64]);
|
||||
Assert.Equal(_xxhash3, hashDict[HashType.XxHash3]);
|
||||
Assert.Equal(_xxhash128, hashDict[HashType.XxHash128]);
|
||||
#endif
|
||||
[Fact]
|
||||
public void GetByteArrayHashesAndSizeTest()
|
||||
{
|
||||
byte[] fileBytes = File.ReadAllBytes(_hashFilePath);
|
||||
var hashDict = HashTool.GetByteArrayHashesAndSize(fileBytes, out long actualSize);
|
||||
TestHelper.ValidateSize(actualSize);
|
||||
TestHelper.ValidateHashes(hashDict);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -210,47 +113,16 @@ namespace SabreTools.Hashing.Test
|
||||
{
|
||||
var fileStream = File.OpenRead(_hashFilePath);
|
||||
var hashDict = HashTool.GetStreamHashes(fileStream);
|
||||
TestHelper.ValidateHashes(hashDict);
|
||||
}
|
||||
|
||||
Assert.NotNull(hashDict);
|
||||
Assert.Equal(_adler32, hashDict![HashType.Adler32]);
|
||||
#if NET7_0_OR_GREATER
|
||||
Assert.Equal(_blake3, hashDict[HashType.BLAKE3]);
|
||||
#endif
|
||||
Assert.Equal(_crc16_ccitt, hashDict[HashType.CRC16_CCITT]);
|
||||
Assert.Equal(_crc16_ibm, hashDict[HashType.CRC16_IBM]);
|
||||
Assert.Equal(_crc32, hashDict[HashType.CRC32]);
|
||||
Assert.Equal(_crc32, hashDict[HashType.CRC32_ISO]);
|
||||
Assert.Equal(_crc32, hashDict[HashType.CRC32_Naive]);
|
||||
Assert.Equal(_crc32, hashDict[HashType.CRC32_Optimized]);
|
||||
Assert.Equal(_crc32, hashDict[HashType.CRC32_Parallel]);
|
||||
Assert.Equal(_crc64, hashDict[HashType.CRC64]);
|
||||
Assert.Equal(_crc64_reversed, hashDict[HashType.CRC64_Reversed]);
|
||||
Assert.Equal(_fletcher16, hashDict[HashType.Fletcher16]);
|
||||
Assert.Equal(_fletcher32, hashDict[HashType.Fletcher32]);
|
||||
Assert.Equal(_md5, hashDict[HashType.MD5]);
|
||||
Assert.Equal(_sha1, hashDict[HashType.SHA1]);
|
||||
Assert.Equal(_sha256, hashDict[HashType.SHA256]);
|
||||
Assert.Equal(_sha384, hashDict[HashType.SHA384]);
|
||||
Assert.Equal(_sha512, hashDict[HashType.SHA512]);
|
||||
#if NET8_0_OR_GREATER
|
||||
if (System.Security.Cryptography.SHA3_256.IsSupported)
|
||||
Assert.Equal(_sha3_256, hashDict[HashType.SHA3_256]);
|
||||
if (System.Security.Cryptography.SHA3_384.IsSupported)
|
||||
Assert.Equal(_sha3_384, hashDict[HashType.SHA3_384]);
|
||||
if (System.Security.Cryptography.SHA3_512.IsSupported)
|
||||
Assert.Equal(_sha3_512, hashDict[HashType.SHA3_512]);
|
||||
if (System.Security.Cryptography.Shake128.IsSupported)
|
||||
Assert.Equal(_shake128, hashDict[HashType.SHAKE128]);
|
||||
if (System.Security.Cryptography.Shake256.IsSupported)
|
||||
Assert.Equal(_shake256, hashDict[HashType.SHAKE256]);
|
||||
#endif
|
||||
Assert.Equal(_spamsum, hashDict[HashType.SpamSum]);
|
||||
#if NET462_OR_GREATER || NETCOREAPP
|
||||
Assert.Equal(_xxhash32, hashDict[HashType.XxHash32]);
|
||||
Assert.Equal(_xxhash64, hashDict[HashType.XxHash64]);
|
||||
Assert.Equal(_xxhash3, hashDict[HashType.XxHash3]);
|
||||
Assert.Equal(_xxhash128, hashDict[HashType.XxHash128]);
|
||||
#endif
|
||||
[Fact]
|
||||
public void GetStreamHashesAndSizeTest()
|
||||
{
|
||||
var fileStream = File.OpenRead(_hashFilePath);
|
||||
var hashDict = HashTool.GetStreamHashesAndSize(fileStream, out long actualSize);
|
||||
TestHelper.ValidateSize(actualSize);
|
||||
TestHelper.ValidateHashes(hashDict);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,44 +1,39 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net462;net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<CheckEolTargetFramework>false</CheckEolTargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks>
|
||||
<CheckEolTargetFramework>false</CheckEolTargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="TestData\*" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="TestData\*" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="TestData\*">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="TestData\*">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Support for old .NET versions -->
|
||||
<ItemGroup Condition="$(TargetFramework.StartsWith(`net462`)) OR $(TargetFramework.StartsWith(`net6`)) OR $(TargetFramework.StartsWith(`net7`)) OR $(TargetFramework.StartsWith(`net8`))">
|
||||
<PackageReference Include="System.IO.Compression" Version="4.3.0" />
|
||||
<PackageReference Include="xunit" Version="2.6.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.4">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.4">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
|
||||
<PackageReference Include="xunit" Version="2.9.3" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SabreTools.Hashing\SabreTools.Hashing.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SabreTools.Hashing\SabreTools.Hashing.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
</Project>
|
||||
45
SabreTools.Hashing.Test/SpamSumTests.cs
Normal file
45
SabreTools.Hashing.Test/SpamSumTests.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.Hashing.Test
|
||||
{
|
||||
public class SpamSumTests
|
||||
{
|
||||
[Theory]
|
||||
// Invalid inputs
|
||||
[InlineData(null, null, -1)]
|
||||
[InlineData(null, "3:hMCPQCE6AFQxWyENFACBE+rW6Tj7SMQmKozr9MVERkL:hZRdxZENFs+rPSromekL", -1)]
|
||||
[InlineData("3:hMCPQCE6AFQxWyENFACBE+rW6Tj7SMQmKozr9MVERkL:hZRdxZENFs+rPSromekL", null, -1)]
|
||||
[InlineData("", "", -1)]
|
||||
[InlineData("3:hMCPQCE6AFQxWyENFACBE+rW6Tj7SMQmKozr9MVERkL:hZRdxZENFs+rPSromekL", "", -1)]
|
||||
[InlineData("", "3:hMCPQCE6AFQxWyENFACBE+rW6Tj7SMQmKozr9MVERkL:hZRdxZENFs+rPSromekL", -1)]
|
||||
// Small data
|
||||
[InlineData("6:l+lq/MtlM8pJ0gt6lXWogE61UlT1Uqj1akMD5n:l+l6Mtl/n0gtOXmEuUl5UqpakM9n", "6:mTj3qJskr+V+1o21+n0rtD2noPWKlAyjllZmMt6120EK+wlsS6T1oLwXuk4tk7:m/bk/1oQrJL3jTu20EK+wlsp5oO4tk7", 0)]
|
||||
[InlineData("6:mTj3qJskr+V+1o21+n0rtD2noPWKlAyjllZmMt6120EK+wlsS6T1oLwXuk4tk7:m/bk/1oQrJL3jTu20EK+wlsp5oO4tk7", "6:l+lq/MtlM8pJ0gt6lXWogE61UlT1Uqj1akMD5n:l+l6Mtl/n0gtOXmEuUl5UqpakM9n", 0)]
|
||||
[InlineData("3:hMCPQCE6AFQxWyENFACBE+rW6Tj7SMQmKozr9MVERkL:hZRdxZENFs+rPSromekL", "3:hMCERJAFQxWyENFACBE+rW6Tj7SMQmKozr9MVERkL:huRJdxZENFs+rPSromekL", 41)]
|
||||
[InlineData("3:hMCERJAFQxWyENFACBE+rW6Tj7SMQmKozr9MVERkL:huRJdxZENFs+rPSromekL", "3:hMCPQCE6AFQxWyENFACBE+rW6Tj7SMQmKozr9MVERkL:hZRdxZENFs+rPSromekL", 41)]
|
||||
[InlineData("12:Y+VH/3Ckg3xqMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMn:xHqVwMMMMMMMMMMMMMMMMMMMMMMMMMM0", "12:Oqkg3xqMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMu:OqVwMMMMMMMMMMMMMMMMMMMMMMMMMMMd", 44)]
|
||||
[InlineData("12:Oqkg3xqMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMu:OqVwMMMMMMMMMMMMMMMMMMMMMMMMMMMd", "12:Y+VH/3Ckg3xqMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMn:xHqVwMMMMMMMMMMMMMMMMMMMMMMMMMM0", 44)]
|
||||
// Large data
|
||||
[InlineData("196608:Gbxf3F4OQK3IuUGM8Ylv1kqCLuDKeo5cRld6iZL6HAGpX7g08WCWDc4NNgs4NEv:qcgxU+UxR2gl5qAGpXjHDcCNgs4N", "196608:EqKRzGWxtDOadbDCbZStQxNy+fox3UgOYorlhjolL0K1WJj5lYA:EbNf76db9xNVox3MRlh+sf", 0)]
|
||||
[InlineData("196608:EqKRzGWxtDOadbDCbZStQxNy+fox3UgOYorlhjolL0K1WJj5lYA:EbNf76db9xNVox3MRlh+sf", "196608:Gbxf3F4OQK3IuUGM8Ylv1kqCLuDKeo5cRld6iZL6HAGpX7g08WCWDc4NNgs4NEv:qcgxU+UxR2gl5qAGpXjHDcCNgs4N", 0)]
|
||||
[InlineData("24576:p+QxhkAcV6cUdRxczoy3NmO0ne3HFVjSeQ229SVjeONr+v:YQ/q6baz5Nqe3H2eQzStBa", "24576:fCQxhkAcV6cUdRxczoyVQQFDSVRNihk24vXDj20sq:6Q/q6bazwMgRNihk24jtsq", 54)]
|
||||
[InlineData("24576:fCQxhkAcV6cUdRxczoyVQQFDSVRNihk24vXDj20sq:6Q/q6bazwMgRNihk24jtsq", "24576:p+QxhkAcV6cUdRxczoy3NmO0ne3HFVjSeQ229SVjeONr+v:YQ/q6baz5Nqe3H2eQzStBa", 54)]
|
||||
// Duplicate sequence truncation
|
||||
[InlineData("500:AAAAAAAAAAAAAAAAAAAAAAAAyENFACBE+rW6Tj7SMQmK:4", "500:AAAyENFACBE+rW6Tj7SMQmK:4", 100)]
|
||||
// Trailing data ignored
|
||||
[InlineData("6:l+lq/MtlM8pJ0gt6lXWogE61UlT1Uqj1akMD5n:l+l6Mtl/n0gtOXmEuUl5UqpakM9n,ANYTHING", "6:mTj3qJskr+V+1o21+n0rtD2noPWKlAyjllZmMt6120EK+wlsS6T1oLwXuk4tk7:m/bk/1oQrJL3jTu20EK+wlsp5oO4tk7,NOTHING", 0)]
|
||||
[InlineData("6:mTj3qJskr+V+1o21+n0rtD2noPWKlAyjllZmMt6120EK+wlsS6T1oLwXuk4tk7:m/bk/1oQrJL3jTu20EK+wlsp5oO4tk7,NOTHING", "6:l+lq/MtlM8pJ0gt6lXWogE61UlT1Uqj1akMD5n:l+l6Mtl/n0gtOXmEuUl5UqpakM9n,ANYTHING", 0)]
|
||||
// Rolling window - larger than 7
|
||||
[InlineData("500:7SMQmKa:3", "500:7SMQmKr:3", 0)]
|
||||
// Rolling window - smaller than 7
|
||||
[InlineData("500:7QmKa:3", "500:7QmKr:3", 0)]
|
||||
// Blocksize differences
|
||||
[InlineData("9287:hMCPQCE6AFQxWyENFACBE+rW6Tj7SMQmKozr9MVERkL:hZRdxZENFs+rPSromekL", "5893:hMCPQCE6AFQxWyENFACBE+rW6Tj7SMQmKozr9MVERkL:hZRdxZENFs+rPSromekL", 0)]
|
||||
[InlineData("3:hMCPQCE6AFQxWyENFACBE+rW6Tj7SMQmKozr9MVERkL:hZRdxZENFs+rPSromekL", "3:hMCPQCE6AFQxWyENFACBE+rW6Tj7SMQmKozr9MVERkL:hZRdxZENFs+rPSromekL", 100)]
|
||||
public void FuzzyCompareTest(string? stringOne, string? stringTwo, int expected)
|
||||
{
|
||||
var result = SpamSum.SpamSum.FuzzyCompare(stringOne, stringTwo);
|
||||
Assert.Equal(expected, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
SabreTools.Hashing.Test/TestData/file-to-hash-multi.zip
Normal file
BIN
SabreTools.Hashing.Test/TestData/file-to-hash-multi.zip
Normal file
Binary file not shown.
BIN
SabreTools.Hashing.Test/TestData/file-to-hash.bin.gz
Normal file
BIN
SabreTools.Hashing.Test/TestData/file-to-hash.bin.gz
Normal file
Binary file not shown.
248
SabreTools.Hashing.Test/TestHelper.cs
Normal file
248
SabreTools.Hashing.Test/TestHelper.cs
Normal file
@@ -0,0 +1,248 @@
|
||||
using System.Collections.Generic;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.Hashing.Test
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class for tests
|
||||
/// </summary>
|
||||
/// CRC values confirmed with <see href="https://emn178.github.io/online-tools/crc/"/>
|
||||
internal static class TestHelper
|
||||
{
|
||||
#region Known File Information
|
||||
|
||||
private const long _hashFileSize = 125;
|
||||
|
||||
private static readonly Dictionary<HashType, string> _knownHashes = new()
|
||||
{
|
||||
{HashType.Adler32, "08562d95"},
|
||||
|
||||
#if NET7_0_OR_GREATER
|
||||
{HashType.BLAKE3, "d4bd7ca6f1ebea9580d9381106b248eb5b6069170d0bfd00b17d659fcd10dcdc"},
|
||||
#endif
|
||||
|
||||
{HashType.CRC1_ZERO, "0"},
|
||||
{HashType.CRC1_ONE, "1"},
|
||||
|
||||
{HashType.CRC3_GSM, "4"},
|
||||
{HashType.CRC3_ROHC, "3"},
|
||||
|
||||
{HashType.CRC4_G704, "6"},
|
||||
{HashType.CRC4_INTERLAKEN, "0"},
|
||||
|
||||
{HashType.CRC5_EPCC1G2, "1f"},
|
||||
{HashType.CRC5_G704, "06"},
|
||||
{HashType.CRC5_USB, "0a"},
|
||||
|
||||
{HashType.CRC6_CDMA2000A, "3c"},
|
||||
{HashType.CRC6_CDMA2000B, "12"},
|
||||
{HashType.CRC6_DARC, "0f"},
|
||||
{HashType.CRC6_G704, "09"},
|
||||
{HashType.CRC6_GSM, "21"},
|
||||
|
||||
{HashType.CRC7_MMC, "2f"},
|
||||
{HashType.CRC7_ROHC, "68"},
|
||||
{HashType.CRC7_UMTS, "66"},
|
||||
|
||||
{HashType.CRC8, "fc"},
|
||||
{HashType.CRC8_AUTOSAR, "ca"},
|
||||
{HashType.CRC8_BLUETOOTH, "00"},
|
||||
{HashType.CRC8_CDMA2000, "2d"},
|
||||
{HashType.CRC8_DARC, "35"},
|
||||
{HashType.CRC8_DVBS2, "5c"},
|
||||
{HashType.CRC8_GSMA, "d8"},
|
||||
{HashType.CRC8_GSMB, "f3"},
|
||||
{HashType.CRC8_HITAG, "aa"},
|
||||
{HashType.CRC8_I4321, "a9"},
|
||||
{HashType.CRC8_ICODE, "61"},
|
||||
{HashType.CRC8_LTE, "d7"},
|
||||
{HashType.CRC8_MAXIMDOW, "bd"},
|
||||
{HashType.CRC8_MIFAREMAD, "9b"},
|
||||
{HashType.CRC8_NRSC5, "e2"},
|
||||
{HashType.CRC8_OPENSAFETY, "fc"},
|
||||
{HashType.CRC8_ROHC, "17"},
|
||||
{HashType.CRC8_SAEJ1850, "55"},
|
||||
{HashType.CRC8_SMBUS, "fc"},
|
||||
{HashType.CRC8_TECH3250, "7d"},
|
||||
{HashType.CRC8_WCDMA, "c6"},
|
||||
|
||||
{HashType.CRC10_ATM, "26b"},
|
||||
{HashType.CRC10_CDMA2000, "14f"},
|
||||
{HashType.CRC10_GSM, "0e7"},
|
||||
|
||||
{HashType.CRC11_FLEXRAY, "18b"},
|
||||
{HashType.CRC11_UMTS, "347"},
|
||||
|
||||
{HashType.CRC12_CDMA2000, "f9c"},
|
||||
{HashType.CRC12_DECT, "d62"},
|
||||
{HashType.CRC12_GSM, "975"},
|
||||
{HashType.CRC12_UMTS, "46b"},
|
||||
|
||||
{HashType.CRC13_BBC, "074f"},
|
||||
|
||||
{HashType.CRC14_DARC, "0add"},
|
||||
{HashType.CRC14_GSM, "0c7d"},
|
||||
|
||||
{HashType.CRC15_CAN, "66c3"},
|
||||
{HashType.CRC15_MPT1327, "013b"},
|
||||
|
||||
{HashType.CRC16, "7573"},
|
||||
{HashType.CRC16_ARC, "7573"},
|
||||
{HashType.CRC16_CDMA2000, "8b5f"},
|
||||
{HashType.CRC16_CMS, "1a37"},
|
||||
{HashType.CRC16_DDS110, "241d"},
|
||||
{HashType.CRC16_DECTR, "7390"},
|
||||
{HashType.CRC16_DECTX, "7391"},
|
||||
{HashType.CRC16_DNP, "4bbb"},
|
||||
{HashType.CRC16_EN13757, "e28b"},
|
||||
{HashType.CRC16_GENIBUS, "b65d"},
|
||||
{HashType.CRC16_GSM, "482d"},
|
||||
{HashType.CRC16_IBM3740, "49a2"},
|
||||
{HashType.CRC16_IBMSDLC, "4f52"},
|
||||
{HashType.CRC16_ISOIEC144433A, "85cd"},
|
||||
{HashType.CRC16_KERMIT, "bed2"},
|
||||
{HashType.CRC16_LJ1200, "3533"},
|
||||
{HashType.CRC16_M17, "5223"},
|
||||
{HashType.CRC16_MAXIMDOW, "8a8c"},
|
||||
{HashType.CRC16_MCRF4XX, "b0ad"},
|
||||
{HashType.CRC16_MODBUS, "9e54"},
|
||||
{HashType.CRC16_NRSC5, "4857"},
|
||||
{HashType.CRC16_OPENSAFETYA, "abcd"},
|
||||
{HashType.CRC16_OPENSAFETYB, "76f4"},
|
||||
{HashType.CRC16_PROFIBUS, "3099"},
|
||||
{HashType.CRC16_RIELLO, "23e0"},
|
||||
{HashType.CRC16_SPIFUJITSU, "f98b"},
|
||||
{HashType.CRC16_T10DIF, "2642"},
|
||||
{HashType.CRC16_TELEDISK, "7e05"},
|
||||
{HashType.CRC16_TMS37157, "dba0"},
|
||||
{HashType.CRC16_UMTS, "fee0"},
|
||||
{HashType.CRC16_USB, "61ab"},
|
||||
{HashType.CRC16_XMODEM, "b7d2"},
|
||||
|
||||
{HashType.CRC17_CANFD, "0706d"},
|
||||
|
||||
{HashType.CRC21_CANFD, "117d4b"},
|
||||
|
||||
{HashType.CRC24_BLE, "2969f2"},
|
||||
{HashType.CRC24_FLEXRAYA, "ce9dc7"},
|
||||
{HashType.CRC24_FLEXRAYB, "0f49d7"},
|
||||
{HashType.CRC24_INTERLAKEN, "fb4725"},
|
||||
{HashType.CRC24_LTEA, "675e55"},
|
||||
{HashType.CRC24_LTEB, "c91203"},
|
||||
{HashType.CRC24_OPENPGP, "0c6012"},
|
||||
{HashType.CRC24_OS9, "610e21"},
|
||||
|
||||
{HashType.CRC30_CDMA, "2ce682b2"},
|
||||
|
||||
{HashType.CRC31_PHILIPS, "247c3cbe"},
|
||||
|
||||
{HashType.CRC32, "ba02a660"},
|
||||
{HashType.CRC32_AIXM, "6174a75a"},
|
||||
{HashType.CRC32_AUTOSAR, "c050428e"},
|
||||
{HashType.CRC32_BASE91D, "e741ba25"},
|
||||
{HashType.CRC32_BZIP2, "18aa4603"},
|
||||
{HashType.CRC32_CDROMEDC, "b8ced467"},
|
||||
{HashType.CRC32_CKSUM, "f27b3c27"},
|
||||
{HashType.CRC32_DVDROMEDC, "b538afc0"},
|
||||
{HashType.CRC32_ISCSI, "544d37db"},
|
||||
{HashType.CRC32_ISOHDLC, "ba02a660"},
|
||||
{HashType.CRC32_JAMCRC, "45fd599f"},
|
||||
{HashType.CRC32_MEF, "d9d98444"},
|
||||
{HashType.CRC32_MPEG2, "e755b9fc"},
|
||||
{HashType.CRC32_XFER, "55bdf222"},
|
||||
|
||||
{HashType.CRC40_GSM, "c9843306eb"},
|
||||
|
||||
{HashType.CRC64, "8d33b5189c00e0a0"},
|
||||
{HashType.CRC64_ECMA182, "8d33b5189c00e0a0"},
|
||||
{HashType.CRC64_GOISO, "6c3bf747ccfa1e3b"},
|
||||
{HashType.CRC64_MS, "799edc0db430d7be"},
|
||||
{HashType.CRC64_NVME, "9242023bbcf6bbf9"},
|
||||
{HashType.CRC64_REDIS, "408dab12b9f45dad"},
|
||||
{HashType.CRC64_WE, "91812be748f941c4"},
|
||||
{HashType.CRC64_XZ, "fb49044e8331f6e5"},
|
||||
|
||||
{HashType.Fletcher16, "46c1"},
|
||||
{HashType.Fletcher32, "073f2d94"},
|
||||
{HashType.Fletcher64, "000b073400002d94"},
|
||||
|
||||
{HashType.FNV0_32, "33d28b00"},
|
||||
{HashType.FNV0_64, "778e818addd23280"},
|
||||
{HashType.FNV1_32, "ac09cbeb"},
|
||||
{HashType.FNV1_64, "23229308c1f9252b"},
|
||||
{HashType.FNV1a_32, "9086769b"},
|
||||
{HashType.FNV1a_64, "399dd1cd965b73db"},
|
||||
|
||||
{HashType.MekaCrc, "0a0a0b1174052f22"},
|
||||
|
||||
{HashType.MD2, "362e1a6931668e6a9de5c159c52c71b5"},
|
||||
{HashType.MD4, "61bef59d7a754874fccbd67b4ec2fb10"},
|
||||
{HashType.MD5, "b722871eaa950016296184d026c5dec9"},
|
||||
|
||||
{HashType.RIPEMD128, "6356cc18225245de3ca9afcb4fa22ce6"},
|
||||
{HashType.RIPEMD160, "346361e1d7fdb836650cecdb842b0dbe660eed66"},
|
||||
{HashType.RIPEMD256, "c2fe11922529651bc615be3d8a296820b6681ecaed5ce051439c86bf3d942276"},
|
||||
{HashType.RIPEMD320, "a523bec87b0738f89d8ae5cf0edd3ee9c7b9811f1051e32893e32e820db33841b9d5042e738d20c9"},
|
||||
|
||||
{HashType.SHA1, "eea1ee2d801d830c4bdad4df3c8da6f9f52d1a9f"},
|
||||
{HashType.SHA256, "fdb02dee8c319c52087382c45f099c90d0b6cc824850aff28c1bfb2884b7b855"},
|
||||
{HashType.SHA384, "e276c49618fff25bc1fe2e0659cd0ef0e7c1186563b063e07c52323b9899f3ce9b091be04d6208444b3ef1265e879074"},
|
||||
{HashType.SHA512, "15d69514eb628c2403e945a7cafd1d27e557f6e336c69b63ea17e7ed9d256cc374ee662f09305836d6de37fdae59d83883b982aa8446e4ff26346b6b6b50b240"},
|
||||
#if NET8_0_OR_GREATER
|
||||
{HashType.SHA3_256, "1d76459e68c865b5911ada5104067cc604c5c60b345c4e81b3905e916a43c868"},
|
||||
{HashType.SHA3_384, "1bcbed87b73f25c0adf486c3afbf0ea3105763c387af3f8b2bd79b0a1964d42832b1d7c6a2225f9153ead26f442e8b67"},
|
||||
{HashType.SHA3_512, "89852144df37c58d01f5912124f1942dd00bac0346eb3971943416699c3094cff087fb42c356019c3d91f8e8f55b9254c8caec48e9414af6817297d06725ffeb"},
|
||||
{HashType.SHAKE128, "e5f88d0db79a71c39490beb9ebac21eaf4a5d6368438fca20f5e4ce77cfee9aa"},
|
||||
{HashType.SHAKE256, "24d9e83198bbc7baf4dcd293bfc35ae3fff05399786c37318f1b1ef85f41970c66926f8a2a1f912d96e2d8e45535af88a301a1c200697437c1a65d7e980344bc"},
|
||||
#endif
|
||||
|
||||
{HashType.SpamSum, "3:hMCPQCE6AFQxWyENFACBE+rW6Tj7SMQmKozr9MVERkL:hZRdxZENFs+rPSromekL"},
|
||||
|
||||
{HashType.Tiger128_3, "afc7ac1c3c031b675562f917b59f0885"},
|
||||
{HashType.Tiger128_4, "e7609126923009f733cd0fcbc5a733fa"},
|
||||
{HashType.Tiger160_3, "afc7ac1c3c031b675562f917b59f088533405e1a"},
|
||||
{HashType.Tiger160_4, "e7609126923009f733cd0fcbc5a733fa4f4ccf7a"},
|
||||
{HashType.Tiger192_3, "afc7ac1c3c031b675562f917b59f088533405e1a2f72912d"},
|
||||
{HashType.Tiger192_4, "e7609126923009f733cd0fcbc5a733fa4f4ccf7ab7c0e2a3"},
|
||||
{HashType.Tiger2_128_3, "b26271774e66519b1c746f210e0be05c"},
|
||||
{HashType.Tiger2_128_4, "f1df540d3f2521b87a957c9b2b00fc7c"},
|
||||
{HashType.Tiger2_160_3, "b26271774e66519b1c746f210e0be05c4fd9efde"},
|
||||
{HashType.Tiger2_160_4, "f1df540d3f2521b87a957c9b2b00fc7c589306dc"},
|
||||
{HashType.Tiger2_192_3, "b26271774e66519b1c746f210e0be05c4fd9efde26e46e89"},
|
||||
{HashType.Tiger2_192_4, "f1df540d3f2521b87a957c9b2b00fc7c589306dcf094acb5"},
|
||||
|
||||
{HashType.XxHash32, "aa1d338e"},
|
||||
{HashType.XxHash64, "181e9ea4f0f62b08"},
|
||||
#if NET462_OR_GREATER || NETCOREAPP
|
||||
{HashType.XxHash3, "f29fda0eeb740404"},
|
||||
{HashType.XxHash128, "e811cdfb1280efae1be1e1a5b4b434d9"},
|
||||
#endif
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Validate the hashes in a hash dictionary
|
||||
/// </summary>
|
||||
public static void ValidateHashes(Dictionary<HashType, string?>? hashDict)
|
||||
{
|
||||
Assert.NotNull(hashDict);
|
||||
foreach (var hashType in _knownHashes.Keys)
|
||||
{
|
||||
ValidateHash(hashType, hashDict![hashType]);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validate a single hash
|
||||
/// </summary>
|
||||
public static void ValidateHash(HashType hashType, string? hashValue)
|
||||
=> Assert.Equal(_knownHashes[hashType], hashValue);
|
||||
|
||||
/// <summary>
|
||||
/// Validate the file size
|
||||
/// </summary>
|
||||
public static void ValidateSize(long fileSize)
|
||||
=> Assert.Equal(_hashFileSize, fileSize);
|
||||
}
|
||||
}
|
||||
48
SabreTools.Hashing.Test/ZeroHashTests.cs
Normal file
48
SabreTools.Hashing.Test/ZeroHashTests.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.Hashing.Test
|
||||
{
|
||||
public class ZeroHashTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Get an array of all hash types
|
||||
/// </summary>
|
||||
public static TheoryData<HashType> AllHashTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
var values = Enum.GetValues<HashType>();
|
||||
var set = new TheoryData<HashType>();
|
||||
foreach (var value in values)
|
||||
{
|
||||
set.Add(value);
|
||||
}
|
||||
|
||||
return set;
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(AllHashTypes))]
|
||||
public void GetZeroByteHashes(HashType hashType)
|
||||
{
|
||||
var expected = ZeroHash.GetBytes(hashType);
|
||||
var actual = HashTool.GetByteArrayHashArray([], hashType);
|
||||
|
||||
Assert.NotNull(actual);
|
||||
Assert.Equal(expected.Length, actual.Length);
|
||||
Assert.True(actual.SequenceEqual(expected));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(AllHashTypes))]
|
||||
public void GetZeroStringHashes(HashType hashType)
|
||||
{
|
||||
var expected = ZeroHash.GetString(hashType);
|
||||
var actual = HashTool.GetByteArrayHash([], hashType);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,22 +7,56 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SabreTools.Hashing", "Sabre
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SabreTools.Hashing.Test", "SabreTools.Hashing.Test\SabreTools.Hashing.Test.csproj", "{A2BCBFDE-685B-4817-B724-050A99E02601}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hasher", "Hasher\Hasher.csproj", "{5DAC74F2-22AB-409B-B828-2FD3851586A3}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{F7E34528-080E-4E60-B9D1-8ADF70A24BB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F7E34528-080E-4E60-B9D1-8ADF70A24BB0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F7E34528-080E-4E60-B9D1-8ADF70A24BB0}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{F7E34528-080E-4E60-B9D1-8ADF70A24BB0}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{F7E34528-080E-4E60-B9D1-8ADF70A24BB0}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{F7E34528-080E-4E60-B9D1-8ADF70A24BB0}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{F7E34528-080E-4E60-B9D1-8ADF70A24BB0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F7E34528-080E-4E60-B9D1-8ADF70A24BB0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F7E34528-080E-4E60-B9D1-8ADF70A24BB0}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{F7E34528-080E-4E60-B9D1-8ADF70A24BB0}.Release|x64.Build.0 = Release|Any CPU
|
||||
{F7E34528-080E-4E60-B9D1-8ADF70A24BB0}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{F7E34528-080E-4E60-B9D1-8ADF70A24BB0}.Release|x86.Build.0 = Release|Any CPU
|
||||
{A2BCBFDE-685B-4817-B724-050A99E02601}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A2BCBFDE-685B-4817-B724-050A99E02601}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A2BCBFDE-685B-4817-B724-050A99E02601}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{A2BCBFDE-685B-4817-B724-050A99E02601}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{A2BCBFDE-685B-4817-B724-050A99E02601}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{A2BCBFDE-685B-4817-B724-050A99E02601}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{A2BCBFDE-685B-4817-B724-050A99E02601}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A2BCBFDE-685B-4817-B724-050A99E02601}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A2BCBFDE-685B-4817-B724-050A99E02601}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{A2BCBFDE-685B-4817-B724-050A99E02601}.Release|x64.Build.0 = Release|Any CPU
|
||||
{A2BCBFDE-685B-4817-B724-050A99E02601}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{A2BCBFDE-685B-4817-B724-050A99E02601}.Release|x86.Build.0 = Release|Any CPU
|
||||
{5DAC74F2-22AB-409B-B828-2FD3851586A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5DAC74F2-22AB-409B-B828-2FD3851586A3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5DAC74F2-22AB-409B-B828-2FD3851586A3}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{5DAC74F2-22AB-409B-B828-2FD3851586A3}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{5DAC74F2-22AB-409B-B828-2FD3851586A3}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{5DAC74F2-22AB-409B-B828-2FD3851586A3}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{5DAC74F2-22AB-409B-B828-2FD3851586A3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5DAC74F2-22AB-409B-B828-2FD3851586A3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5DAC74F2-22AB-409B-B828-2FD3851586A3}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{5DAC74F2-22AB-409B-B828-2FD3851586A3}.Release|x64.Build.0 = Release|Any CPU
|
||||
{5DAC74F2-22AB-409B-B828-2FD3851586A3}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{5DAC74F2-22AB-409B-B828-2FD3851586A3}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
@@ -1,217 +0,0 @@
|
||||
// /***************************************************************************
|
||||
// Aaru Data Preservation Suite
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : neon.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
// The Chromium Authors
|
||||
//
|
||||
// Component : Checksums.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Compute Adler32 checksum using NEON vectorization.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2023 Natalia Portillo
|
||||
// Copyright 2017 The Chromium Authors. All rights reserved.
|
||||
// ****************************************************************************/
|
||||
|
||||
#if NET5_0_OR_GREATER
|
||||
using System.Runtime.Intrinsics;
|
||||
using System.Runtime.Intrinsics.Arm;
|
||||
|
||||
namespace Aaru.Checksums.Adler32;
|
||||
|
||||
static class Neon
|
||||
{
|
||||
internal static void Step(ref ushort preSum1, ref ushort preSum2, byte[] buf, uint len)
|
||||
{
|
||||
/*
|
||||
* Split Adler-32 into component sums.
|
||||
*/
|
||||
uint s1 = preSum1;
|
||||
uint s2 = preSum2;
|
||||
|
||||
var bufPos = 0;
|
||||
|
||||
/*
|
||||
* Process the data in blocks.
|
||||
*/
|
||||
const uint blockSize = 1 << 5;
|
||||
uint blocks = len / blockSize;
|
||||
len -= blocks * blockSize;
|
||||
|
||||
while(blocks != 0)
|
||||
{
|
||||
uint n = Adler32Context.NMAX / blockSize; /* The NMAX constraint. */
|
||||
|
||||
if(n > blocks)
|
||||
n = blocks;
|
||||
|
||||
blocks -= n;
|
||||
/*
|
||||
* Process n blocks of data. At most NMAX data bytes can be
|
||||
* processed before s2 must be reduced modulo ADLER_MODULE.
|
||||
*/
|
||||
var vS2 = Vector128.Create(s1 * n, 0, 0, 0);
|
||||
var vS1 = Vector128.Create(0u, 0, 0, 0);
|
||||
Vector128<ushort> vColumnSum1 = AdvSimd.DuplicateToVector128((ushort)0);
|
||||
Vector128<ushort> vColumnSum2 = AdvSimd.DuplicateToVector128((ushort)0);
|
||||
Vector128<ushort> vColumnSum3 = AdvSimd.DuplicateToVector128((ushort)0);
|
||||
Vector128<ushort> vColumnSum4 = AdvSimd.DuplicateToVector128((ushort)0);
|
||||
|
||||
do
|
||||
{
|
||||
/*
|
||||
* Load 32 input bytes.
|
||||
*/
|
||||
var bytes1 = Vector128.Create(buf[bufPos], buf[bufPos + 1], buf[bufPos + 2], buf[bufPos + 3],
|
||||
buf[bufPos + 4], buf[bufPos + 5], buf[bufPos + 6], buf[bufPos + 7],
|
||||
buf[bufPos + 8], buf[bufPos + 9], buf[bufPos + 10], buf[bufPos + 11],
|
||||
buf[bufPos + 12], buf[bufPos + 13], buf[bufPos + 14], buf[bufPos + 15]);
|
||||
|
||||
bufPos += 16;
|
||||
|
||||
var bytes2 = Vector128.Create(buf[bufPos], buf[bufPos + 1], buf[bufPos + 2], buf[bufPos + 3],
|
||||
buf[bufPos + 4], buf[bufPos + 5], buf[bufPos + 6], buf[bufPos + 7],
|
||||
buf[bufPos + 8], buf[bufPos + 9], buf[bufPos + 10], buf[bufPos + 11],
|
||||
buf[bufPos + 12], buf[bufPos + 13], buf[bufPos + 14], buf[bufPos + 15]);
|
||||
|
||||
bufPos += 16;
|
||||
/*
|
||||
* Add previous block byte sum to v_s2.
|
||||
*/
|
||||
vS2 = AdvSimd.Add(vS2, vS1);
|
||||
|
||||
/*
|
||||
* Horizontally add the bytes for s1.
|
||||
*/
|
||||
vS1 =
|
||||
AdvSimd.AddPairwiseWideningAndAdd(vS1,
|
||||
AdvSimd.
|
||||
AddPairwiseWideningAndAdd(AdvSimd.AddPairwiseWidening(bytes1),
|
||||
bytes2));
|
||||
|
||||
/*
|
||||
* Vertically add the bytes for s2.
|
||||
*/
|
||||
vColumnSum1 = AdvSimd.AddWideningLower(vColumnSum1, bytes1.GetLower());
|
||||
vColumnSum2 = AdvSimd.AddWideningLower(vColumnSum2, bytes1.GetUpper());
|
||||
vColumnSum3 = AdvSimd.AddWideningLower(vColumnSum3, bytes2.GetLower());
|
||||
vColumnSum4 = AdvSimd.AddWideningLower(vColumnSum4, bytes2.GetUpper());
|
||||
} while(--n != 0);
|
||||
|
||||
vS2 = AdvSimd.ShiftLeftLogical(vS2, 5);
|
||||
|
||||
/*
|
||||
* Multiply-add bytes by [ 32, 31, 30, ... ] for s2.
|
||||
*/
|
||||
vS2 = AdvSimd.MultiplyWideningLowerAndAdd(vS2, vColumnSum1.GetLower(),
|
||||
Vector64.Create((ushort)32, 31, 30, 29));
|
||||
|
||||
vS2 = AdvSimd.MultiplyWideningLowerAndAdd(vS2, vColumnSum1.GetUpper(),
|
||||
Vector64.Create((ushort)28, 27, 26, 25));
|
||||
|
||||
vS2 = AdvSimd.MultiplyWideningLowerAndAdd(vS2, vColumnSum2.GetLower(),
|
||||
Vector64.Create((ushort)24, 23, 22, 21));
|
||||
|
||||
vS2 = AdvSimd.MultiplyWideningLowerAndAdd(vS2, vColumnSum2.GetUpper(),
|
||||
Vector64.Create((ushort)20, 19, 18, 17));
|
||||
|
||||
vS2 = AdvSimd.MultiplyWideningLowerAndAdd(vS2, vColumnSum3.GetLower(),
|
||||
Vector64.Create((ushort)16, 15, 14, 13));
|
||||
|
||||
vS2 = AdvSimd.MultiplyWideningLowerAndAdd(vS2, vColumnSum3.GetUpper(),
|
||||
Vector64.Create((ushort)12, 11, 10, 9));
|
||||
|
||||
vS2 = AdvSimd.MultiplyWideningLowerAndAdd(vS2, vColumnSum4.GetLower(), Vector64.Create((ushort)8, 7, 6, 5));
|
||||
|
||||
vS2 = AdvSimd.MultiplyWideningLowerAndAdd(vS2, vColumnSum4.GetUpper(), Vector64.Create((ushort)4, 3, 2, 1));
|
||||
|
||||
/*
|
||||
* Sum epi32 ints v_s1(s2) and accumulate in s1(s2).
|
||||
*/
|
||||
Vector64<uint> sum1 = AdvSimd.AddPairwise(vS1.GetLower(), vS1.GetUpper());
|
||||
Vector64<uint> sum2 = AdvSimd.AddPairwise(vS2.GetLower(), vS2.GetUpper());
|
||||
Vector64<uint> s1S2 = AdvSimd.AddPairwise(sum1, sum2);
|
||||
s1 += AdvSimd.Extract(s1S2, 0);
|
||||
s2 += AdvSimd.Extract(s1S2, 1);
|
||||
/*
|
||||
* Reduce.
|
||||
*/
|
||||
s1 %= Adler32Context.ADLER_MODULE;
|
||||
s2 %= Adler32Context.ADLER_MODULE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle leftover data.
|
||||
*/
|
||||
if(len != 0)
|
||||
{
|
||||
if(len >= 16)
|
||||
{
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
len -= 16;
|
||||
}
|
||||
|
||||
while(len-- != 0)
|
||||
s2 += s1 += buf[bufPos++];
|
||||
|
||||
if(s1 >= Adler32Context.ADLER_MODULE)
|
||||
s1 -= Adler32Context.ADLER_MODULE;
|
||||
|
||||
s2 %= Adler32Context.ADLER_MODULE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the recombined sums.
|
||||
*/
|
||||
preSum1 = (ushort)(s1 & 0xFFFF);
|
||||
preSum2 = (ushort)(s2 & 0xFFFF);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,194 +0,0 @@
|
||||
// /***************************************************************************
|
||||
// Aaru Data Preservation Suite
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : ssse3.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
// The Chromium Authors
|
||||
//
|
||||
// Component : Checksums.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Compute Adler32 checksum using SSSE3 vectorization.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2023 Natalia Portillo
|
||||
// Copyright 2017 The Chromium Authors. All rights reserved.
|
||||
// ****************************************************************************/
|
||||
|
||||
#if NETCOREAPP3_1_OR_GREATER
|
||||
using System;
|
||||
using System.Runtime.Intrinsics;
|
||||
using System.Runtime.Intrinsics.X86;
|
||||
|
||||
namespace Aaru.Checksums.Adler32;
|
||||
|
||||
static class Ssse3
|
||||
{
|
||||
internal static void Step(ref ushort sum1, ref ushort sum2, byte[] buf, uint len)
|
||||
{
|
||||
uint s1 = sum1;
|
||||
uint s2 = sum2;
|
||||
var bufPos = 0;
|
||||
|
||||
/*
|
||||
* Process the data in blocks.
|
||||
*/
|
||||
const uint blockSize = 1 << 5;
|
||||
uint blocks = len / blockSize;
|
||||
len -= blocks * blockSize;
|
||||
|
||||
while(blocks != 0)
|
||||
{
|
||||
uint n = Adler32Context.NMAX / blockSize; /* The NMAX constraint. */
|
||||
|
||||
if(n > blocks)
|
||||
n = blocks;
|
||||
|
||||
blocks -= n;
|
||||
|
||||
Vector128<byte> tap1 = Vector128.Create(32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17).
|
||||
AsByte();
|
||||
|
||||
Vector128<byte> tap2 = Vector128.Create(16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1).AsByte();
|
||||
Vector128<byte> zero = Vector128.Create(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0).AsByte();
|
||||
var ones = Vector128.Create(1, 1, 1, 1, 1, 1, 1, 1);
|
||||
/*
|
||||
* Process n blocks of data. At most NMAX data bytes can be
|
||||
* processed before s2 must be reduced modulo BASE.
|
||||
*/
|
||||
var vPs = Vector128.Create(s1 * n, 0, 0, 0);
|
||||
var vS2 = Vector128.Create(s2, 0, 0, 0);
|
||||
var vS1 = Vector128.Create(0u, 0, 0, 0);
|
||||
|
||||
do
|
||||
{
|
||||
/*
|
||||
* Load 32 input bytes.
|
||||
*/
|
||||
var bytes1 = Vector128.Create(BitConverter.ToUInt32(buf, bufPos),
|
||||
BitConverter.ToUInt32(buf, bufPos + 4),
|
||||
BitConverter.ToUInt32(buf, bufPos + 8),
|
||||
BitConverter.ToUInt32(buf, bufPos + 12));
|
||||
|
||||
bufPos += 16;
|
||||
|
||||
var bytes2 = Vector128.Create(BitConverter.ToUInt32(buf, bufPos),
|
||||
BitConverter.ToUInt32(buf, bufPos + 4),
|
||||
BitConverter.ToUInt32(buf, bufPos + 8),
|
||||
BitConverter.ToUInt32(buf, bufPos + 12));
|
||||
|
||||
bufPos += 16;
|
||||
|
||||
/*
|
||||
* Add previous block byte sum to v_ps.
|
||||
*/
|
||||
vPs = Sse2.Add(vPs, vS1);
|
||||
/*
|
||||
* Horizontally add the bytes for s1, multiply-adds the
|
||||
* bytes by [ 32, 31, 30, ... ] for s2.
|
||||
*/
|
||||
vS1 = Sse2.Add(vS1, Sse2.SumAbsoluteDifferences(bytes1.AsByte(), zero).AsUInt32());
|
||||
|
||||
Vector128<short> mad1 =
|
||||
System.Runtime.Intrinsics.X86.Ssse3.MultiplyAddAdjacent(bytes1.AsByte(), tap1.AsSByte());
|
||||
|
||||
vS2 = Sse2.Add(vS2, Sse2.MultiplyAddAdjacent(mad1.AsInt16(), ones.AsInt16()).AsUInt32());
|
||||
vS1 = Sse2.Add(vS1, Sse2.SumAbsoluteDifferences(bytes2.AsByte(), zero).AsUInt32());
|
||||
|
||||
Vector128<short> mad2 =
|
||||
System.Runtime.Intrinsics.X86.Ssse3.MultiplyAddAdjacent(bytes2.AsByte(), tap2.AsSByte());
|
||||
|
||||
vS2 = Sse2.Add(vS2, Sse2.MultiplyAddAdjacent(mad2.AsInt16(), ones.AsInt16()).AsUInt32());
|
||||
} while(--n != 0);
|
||||
|
||||
vS2 = Sse2.Add(vS2, Sse2.ShiftLeftLogical(vPs, 5));
|
||||
/*
|
||||
* Sum epi32 ints v_s1(s2) and accumulate in s1(s2).
|
||||
*/
|
||||
vS1 = Sse2.Add(vS1, Sse2.Shuffle(vS1, 177));
|
||||
vS1 = Sse2.Add(vS1, Sse2.Shuffle(vS1, 78));
|
||||
s1 += (uint)Sse2.ConvertToInt32(vS1.AsInt32());
|
||||
vS2 = Sse2.Add(vS2, Sse2.Shuffle(vS2, 177));
|
||||
vS2 = Sse2.Add(vS2, Sse2.Shuffle(vS2, 78));
|
||||
s2 = (uint)Sse2.ConvertToInt32(vS2.AsInt32());
|
||||
/*
|
||||
* Reduce.
|
||||
*/
|
||||
s1 %= Adler32Context.ADLER_MODULE;
|
||||
s2 %= Adler32Context.ADLER_MODULE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle leftover data.
|
||||
*/
|
||||
if(len != 0)
|
||||
{
|
||||
if(len >= 16)
|
||||
{
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
len -= 16;
|
||||
}
|
||||
|
||||
while(len-- != 0)
|
||||
s2 += s1 += buf[bufPos++];
|
||||
|
||||
if(s1 >= Adler32Context.ADLER_MODULE)
|
||||
s1 -= Adler32Context.ADLER_MODULE;
|
||||
|
||||
s2 %= Adler32Context.ADLER_MODULE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the recombined sums.
|
||||
*/
|
||||
sum1 = (ushort)(s1 & 0xFFFF);
|
||||
sum2 = (ushort)(s2 & 0xFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,434 +0,0 @@
|
||||
// /***************************************************************************
|
||||
// Aaru Data Preservation Suite
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Adler32Context.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Checksums.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Implements an Adler-32 algorithm.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2023 Natalia Portillo
|
||||
// Copyright (C) 1995-2011 Mark Adler
|
||||
// Copyright (C) Jean-loup Gailly
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
#if NET5_0_OR_GREATER
|
||||
using System.Runtime.Intrinsics.Arm;
|
||||
#endif
|
||||
using System.Text;
|
||||
#if NETCOREAPP3_1_OR_GREATER
|
||||
using Aaru.Checksums.Adler32;
|
||||
#endif
|
||||
using Aaru.CommonTypes.Interfaces;
|
||||
using Aaru.Helpers;
|
||||
#if NETCOREAPP3_1_OR_GREATER
|
||||
using Ssse3 = System.Runtime.Intrinsics.X86.Ssse3;
|
||||
#endif
|
||||
|
||||
namespace Aaru.Checksums;
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>Implements the Adler-32 algorithm</summary>
|
||||
[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")]
|
||||
public sealed class Adler32Context : IChecksum
|
||||
{
|
||||
internal const ushort ADLER_MODULE = 65521;
|
||||
internal const uint NMAX = 5552;
|
||||
readonly IntPtr _nativeContext;
|
||||
readonly bool _useNative;
|
||||
ushort _sum1, _sum2;
|
||||
|
||||
/// <summary>Initializes the Adler-32 sums</summary>
|
||||
public Adler32Context()
|
||||
{
|
||||
_sum1 = 1;
|
||||
_sum2 = 0;
|
||||
|
||||
if(!Native.IsSupported)
|
||||
return;
|
||||
|
||||
_nativeContext = adler32_init();
|
||||
_useNative = _nativeContext != IntPtr.Zero;
|
||||
}
|
||||
|
||||
#region IChecksum Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => "Adler-32";
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Id => new("D69CF1E7-4A7B-4605-9291-3A1BE4C2951F");
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Author => "Natalia Portillo";
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>Updates the hash with data.</summary>
|
||||
/// <param name="data">Data buffer.</param>
|
||||
/// <param name="len">Length of buffer to hash.</param>
|
||||
public void Update(byte[] data, uint len) => Step(ref _sum1, ref _sum2, data, len, _useNative, _nativeContext);
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>Updates the hash with data.</summary>
|
||||
/// <param name="data">Data buffer.</param>
|
||||
public void Update(byte[] data) => Update(data, (uint)data.Length);
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>Returns a byte array of the hash value.</summary>
|
||||
public byte[] Final()
|
||||
{
|
||||
var finalSum = (uint)(_sum2 << 16 | _sum1);
|
||||
|
||||
if(!_useNative)
|
||||
return BigEndianBitConverter.GetBytes(finalSum);
|
||||
|
||||
adler32_final(_nativeContext, ref finalSum);
|
||||
adler32_free(_nativeContext);
|
||||
|
||||
return BigEndianBitConverter.GetBytes(finalSum);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>Returns a hexadecimal representation of the hash value.</summary>
|
||||
public string End()
|
||||
{
|
||||
var finalSum = (uint)(_sum2 << 16 | _sum1);
|
||||
|
||||
if(_useNative)
|
||||
{
|
||||
adler32_final(_nativeContext, ref finalSum);
|
||||
adler32_free(_nativeContext);
|
||||
}
|
||||
|
||||
var adlerOutput = new StringBuilder();
|
||||
|
||||
for(var i = 0; i < BigEndianBitConverter.GetBytes(finalSum).Length; i++)
|
||||
adlerOutput.Append(BigEndianBitConverter.GetBytes(finalSum)[i].ToString("x2"));
|
||||
|
||||
return adlerOutput.ToString();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
|
||||
static extern IntPtr adler32_init();
|
||||
|
||||
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
|
||||
static extern int adler32_update(IntPtr ctx, byte[] data, uint len);
|
||||
|
||||
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
|
||||
static extern int adler32_final(IntPtr ctx, ref uint checksum);
|
||||
|
||||
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
|
||||
static extern void adler32_free(IntPtr ctx);
|
||||
|
||||
static void Step(ref ushort preSum1, ref ushort preSum2, byte[] data, uint len, bool useNative,
|
||||
IntPtr nativeContext)
|
||||
{
|
||||
if(useNative)
|
||||
{
|
||||
adler32_update(nativeContext, data, len);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#if NETCOREAPP3_1_OR_GREATER
|
||||
if(Ssse3.IsSupported)
|
||||
{
|
||||
Adler32.Ssse3.Step(ref preSum1, ref preSum2, data, len);
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NET5_0_OR_GREATER
|
||||
if(AdvSimd.IsSupported)
|
||||
{
|
||||
Neon.Step(ref preSum1, ref preSum2, data, len);
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint sum1 = preSum1;
|
||||
uint sum2 = preSum2;
|
||||
var dataOff = 0;
|
||||
|
||||
switch(len)
|
||||
{
|
||||
/* in case user likes doing a byte at a time, keep it fast */
|
||||
case 1:
|
||||
{
|
||||
sum1 += data[dataOff];
|
||||
|
||||
if(sum1 >= ADLER_MODULE)
|
||||
sum1 -= ADLER_MODULE;
|
||||
|
||||
sum2 += sum1;
|
||||
|
||||
if(sum2 >= ADLER_MODULE)
|
||||
sum2 -= ADLER_MODULE;
|
||||
|
||||
preSum1 = (ushort)(sum1 & 0xFFFF);
|
||||
preSum2 = (ushort)(sum2 & 0xFFFF);
|
||||
|
||||
return;
|
||||
}
|
||||
/* in case short lengths are provided, keep it somewhat fast */
|
||||
case < 16:
|
||||
{
|
||||
while(len-- > 0)
|
||||
{
|
||||
sum1 += data[dataOff++];
|
||||
sum2 += sum1;
|
||||
}
|
||||
|
||||
if(sum1 >= ADLER_MODULE)
|
||||
sum1 -= ADLER_MODULE;
|
||||
|
||||
sum2 %= ADLER_MODULE; /* only added so many ADLER_MODULE's */
|
||||
preSum1 = (ushort)(sum1 & 0xFFFF);
|
||||
preSum2 = (ushort)(sum2 & 0xFFFF);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* do length NMAX blocks -- requires just one modulo operation */
|
||||
while(len >= NMAX)
|
||||
{
|
||||
len -= NMAX;
|
||||
uint n = NMAX / 16;
|
||||
|
||||
do
|
||||
{
|
||||
sum1 += data[dataOff];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 1];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 2];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 2 + 1];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 4];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 4 + 1];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 4 + 2];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 4 + 2 + 1];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 8];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 8 + 1];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 8 + 2];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 8 + 2 + 1];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 8 + 4];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 8 + 4 + 1];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 8 + 4 + 2];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 8 + 4 + 2 + 1];
|
||||
sum2 += sum1;
|
||||
|
||||
/* 16 sums unrolled */
|
||||
dataOff += 16;
|
||||
} while(--n != 0);
|
||||
|
||||
sum1 %= ADLER_MODULE;
|
||||
sum2 %= ADLER_MODULE;
|
||||
}
|
||||
|
||||
/* do remaining bytes (less than NMAX, still just one modulo) */
|
||||
if(len != 0)
|
||||
{
|
||||
/* avoid modulos if none remaining */
|
||||
while(len >= 16)
|
||||
{
|
||||
len -= 16;
|
||||
sum1 += data[dataOff];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 1];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 2];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 2 + 1];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 4];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 4 + 1];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 4 + 2];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 4 + 2 + 1];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 8];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 8 + 1];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 8 + 2];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 8 + 2 + 1];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 8 + 4];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 8 + 4 + 1];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 8 + 4 + 2];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 8 + 4 + 2 + 1];
|
||||
sum2 += sum1;
|
||||
|
||||
dataOff += 16;
|
||||
}
|
||||
|
||||
while(len-- != 0)
|
||||
{
|
||||
sum1 += data[dataOff++];
|
||||
sum2 += sum1;
|
||||
}
|
||||
|
||||
sum1 %= ADLER_MODULE;
|
||||
sum2 %= ADLER_MODULE;
|
||||
}
|
||||
|
||||
preSum1 = (ushort)(sum1 & 0xFFFF);
|
||||
preSum2 = (ushort)(sum2 & 0xFFFF);
|
||||
}
|
||||
|
||||
/// <summary>Gets the hash of a file</summary>
|
||||
/// <param name="filename">File path.</param>
|
||||
public static byte[] File(string filename)
|
||||
{
|
||||
File(filename, out byte[] hash);
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
|
||||
/// <param name="filename">File path.</param>
|
||||
/// <param name="hash">Byte array of the hash value.</param>
|
||||
public static string File(string filename, out byte[] hash)
|
||||
{
|
||||
bool useNative = Native.IsSupported;
|
||||
IntPtr nativeContext = IntPtr.Zero;
|
||||
|
||||
if(useNative)
|
||||
{
|
||||
nativeContext = adler32_init();
|
||||
|
||||
if(nativeContext == IntPtr.Zero)
|
||||
useNative = false;
|
||||
}
|
||||
|
||||
var fileStream = new FileStream(filename, FileMode.Open);
|
||||
|
||||
ushort localSum1 = 1;
|
||||
ushort localSum2 = 0;
|
||||
|
||||
var buffer = new byte[65536];
|
||||
int read = fileStream.EnsureRead(buffer, 0, 65536);
|
||||
|
||||
while(read > 0)
|
||||
{
|
||||
Step(ref localSum1, ref localSum2, buffer, (uint)read, useNative, nativeContext);
|
||||
read = fileStream.EnsureRead(buffer, 0, 65536);
|
||||
}
|
||||
|
||||
var finalSum = (uint)(localSum2 << 16 | localSum1);
|
||||
|
||||
if(useNative)
|
||||
{
|
||||
adler32_final(nativeContext, ref finalSum);
|
||||
adler32_free(nativeContext);
|
||||
}
|
||||
|
||||
hash = BigEndianBitConverter.GetBytes(finalSum);
|
||||
|
||||
var adlerOutput = new StringBuilder();
|
||||
|
||||
foreach(byte h in hash)
|
||||
adlerOutput.Append(h.ToString("x2"));
|
||||
|
||||
fileStream.Close();
|
||||
|
||||
return adlerOutput.ToString();
|
||||
}
|
||||
|
||||
/// <summary>Gets the hash of the specified data buffer.</summary>
|
||||
/// <param name="data">Data buffer.</param>
|
||||
/// <param name="len">Length of the data buffer to hash.</param>
|
||||
/// <param name="hash">Byte array of the hash value.</param>
|
||||
public static string Data(byte[] data, uint len, out byte[] hash)
|
||||
{
|
||||
bool useNative = Native.IsSupported;
|
||||
IntPtr nativeContext = IntPtr.Zero;
|
||||
|
||||
if(useNative)
|
||||
{
|
||||
nativeContext = adler32_init();
|
||||
|
||||
if(nativeContext == IntPtr.Zero)
|
||||
useNative = false;
|
||||
}
|
||||
|
||||
ushort localSum1 = 1;
|
||||
ushort localSum2 = 0;
|
||||
|
||||
Step(ref localSum1, ref localSum2, data, len, useNative, nativeContext);
|
||||
|
||||
var finalSum = (uint)(localSum2 << 16 | localSum1);
|
||||
|
||||
if(useNative)
|
||||
{
|
||||
adler32_final(nativeContext, ref finalSum);
|
||||
adler32_free(nativeContext);
|
||||
}
|
||||
|
||||
hash = BigEndianBitConverter.GetBytes(finalSum);
|
||||
|
||||
var adlerOutput = new StringBuilder();
|
||||
|
||||
foreach(byte h in hash)
|
||||
adlerOutput.Append(h.ToString("x2"));
|
||||
|
||||
return adlerOutput.ToString();
|
||||
}
|
||||
|
||||
/// <summary>Gets the hash of the specified data buffer.</summary>
|
||||
/// <param name="data">Data buffer.</param>
|
||||
/// <param name="hash">Byte array of the hash value.</param>
|
||||
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
|
||||
}
|
||||
@@ -1,274 +0,0 @@
|
||||
// /***************************************************************************
|
||||
// Aaru Data Preservation Suite
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : CRC16CCITTContext.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Checksums.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Implements a CRC16 algorithm with the CCITT polynomial.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2023 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Aaru.Checksums;
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>Implements the CRC16 algorithm with CCITT polynomial and seed</summary>
|
||||
[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")]
|
||||
public sealed class CRC16CcittContext : Crc16Context
|
||||
{
|
||||
/// <summary>CCITT CRC16 polynomial</summary>
|
||||
public const ushort CRC16_CCITT_POLY = 0x8408;
|
||||
/// <summary>CCITT CRC16 seed</summary>
|
||||
public const ushort CRC16_CCITT_SEED = 0x0000;
|
||||
static readonly ushort[][] _ccittCrc16Table =
|
||||
{
|
||||
new ushort[]
|
||||
{
|
||||
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C,
|
||||
0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318,
|
||||
0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4,
|
||||
0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630,
|
||||
0x76D7, 0x66F6, 0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, 0x48C4,
|
||||
0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969,
|
||||
0xA90A, 0xB92B, 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC, 0xFBBF,
|
||||
0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
|
||||
0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13,
|
||||
0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, 0x9188, 0x81A9,
|
||||
0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046,
|
||||
0x6067, 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1, 0x1290, 0x22F3, 0x32D2,
|
||||
0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2,
|
||||
0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E,
|
||||
0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E,
|
||||
0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
|
||||
0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1,
|
||||
0x1AD0, 0x2AB3, 0x3A92, 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07,
|
||||
0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9,
|
||||
0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
|
||||
},
|
||||
new ushort[]
|
||||
{
|
||||
0x0000, 0x3331, 0x6662, 0x5553, 0xCCC4, 0xFFF5, 0xAAA6, 0x9997, 0x89A9, 0xBA98, 0xEFCB, 0xDCFA, 0x456D,
|
||||
0x765C, 0x230F, 0x103E, 0x0373, 0x3042, 0x6511, 0x5620, 0xCFB7, 0xFC86, 0xA9D5, 0x9AE4, 0x8ADA, 0xB9EB,
|
||||
0xECB8, 0xDF89, 0x461E, 0x752F, 0x207C, 0x134D, 0x06E6, 0x35D7, 0x6084, 0x53B5, 0xCA22, 0xF913, 0xAC40,
|
||||
0x9F71, 0x8F4F, 0xBC7E, 0xE92D, 0xDA1C, 0x438B, 0x70BA, 0x25E9, 0x16D8, 0x0595, 0x36A4, 0x63F7, 0x50C6,
|
||||
0xC951, 0xFA60, 0xAF33, 0x9C02, 0x8C3C, 0xBF0D, 0xEA5E, 0xD96F, 0x40F8, 0x73C9, 0x269A, 0x15AB, 0x0DCC,
|
||||
0x3EFD, 0x6BAE, 0x589F, 0xC108, 0xF239, 0xA76A, 0x945B, 0x8465, 0xB754, 0xE207, 0xD136, 0x48A1, 0x7B90,
|
||||
0x2EC3, 0x1DF2, 0x0EBF, 0x3D8E, 0x68DD, 0x5BEC, 0xC27B, 0xF14A, 0xA419, 0x9728, 0x8716, 0xB427, 0xE174,
|
||||
0xD245, 0x4BD2, 0x78E3, 0x2DB0, 0x1E81, 0x0B2A, 0x381B, 0x6D48, 0x5E79, 0xC7EE, 0xF4DF, 0xA18C, 0x92BD,
|
||||
0x8283, 0xB1B2, 0xE4E1, 0xD7D0, 0x4E47, 0x7D76, 0x2825, 0x1B14, 0x0859, 0x3B68, 0x6E3B, 0x5D0A, 0xC49D,
|
||||
0xF7AC, 0xA2FF, 0x91CE, 0x81F0, 0xB2C1, 0xE792, 0xD4A3, 0x4D34, 0x7E05, 0x2B56, 0x1867, 0x1B98, 0x28A9,
|
||||
0x7DFA, 0x4ECB, 0xD75C, 0xE46D, 0xB13E, 0x820F, 0x9231, 0xA100, 0xF453, 0xC762, 0x5EF5, 0x6DC4, 0x3897,
|
||||
0x0BA6, 0x18EB, 0x2BDA, 0x7E89, 0x4DB8, 0xD42F, 0xE71E, 0xB24D, 0x817C, 0x9142, 0xA273, 0xF720, 0xC411,
|
||||
0x5D86, 0x6EB7, 0x3BE4, 0x08D5, 0x1D7E, 0x2E4F, 0x7B1C, 0x482D, 0xD1BA, 0xE28B, 0xB7D8, 0x84E9, 0x94D7,
|
||||
0xA7E6, 0xF2B5, 0xC184, 0x5813, 0x6B22, 0x3E71, 0x0D40, 0x1E0D, 0x2D3C, 0x786F, 0x4B5E, 0xD2C9, 0xE1F8,
|
||||
0xB4AB, 0x879A, 0x97A4, 0xA495, 0xF1C6, 0xC2F7, 0x5B60, 0x6851, 0x3D02, 0x0E33, 0x1654, 0x2565, 0x7036,
|
||||
0x4307, 0xDA90, 0xE9A1, 0xBCF2, 0x8FC3, 0x9FFD, 0xACCC, 0xF99F, 0xCAAE, 0x5339, 0x6008, 0x355B, 0x066A,
|
||||
0x1527, 0x2616, 0x7345, 0x4074, 0xD9E3, 0xEAD2, 0xBF81, 0x8CB0, 0x9C8E, 0xAFBF, 0xFAEC, 0xC9DD, 0x504A,
|
||||
0x637B, 0x3628, 0x0519, 0x10B2, 0x2383, 0x76D0, 0x45E1, 0xDC76, 0xEF47, 0xBA14, 0x8925, 0x991B, 0xAA2A,
|
||||
0xFF79, 0xCC48, 0x55DF, 0x66EE, 0x33BD, 0x008C, 0x13C1, 0x20F0, 0x75A3, 0x4692, 0xDF05, 0xEC34, 0xB967,
|
||||
0x8A56, 0x9A68, 0xA959, 0xFC0A, 0xCF3B, 0x56AC, 0x659D, 0x30CE, 0x03FF
|
||||
},
|
||||
new ushort[]
|
||||
{
|
||||
0x0000, 0x3730, 0x6E60, 0x5950, 0xDCC0, 0xEBF0, 0xB2A0, 0x8590, 0xA9A1, 0x9E91, 0xC7C1, 0xF0F1, 0x7561,
|
||||
0x4251, 0x1B01, 0x2C31, 0x4363, 0x7453, 0x2D03, 0x1A33, 0x9FA3, 0xA893, 0xF1C3, 0xC6F3, 0xEAC2, 0xDDF2,
|
||||
0x84A2, 0xB392, 0x3602, 0x0132, 0x5862, 0x6F52, 0x86C6, 0xB1F6, 0xE8A6, 0xDF96, 0x5A06, 0x6D36, 0x3466,
|
||||
0x0356, 0x2F67, 0x1857, 0x4107, 0x7637, 0xF3A7, 0xC497, 0x9DC7, 0xAAF7, 0xC5A5, 0xF295, 0xABC5, 0x9CF5,
|
||||
0x1965, 0x2E55, 0x7705, 0x4035, 0x6C04, 0x5B34, 0x0264, 0x3554, 0xB0C4, 0x87F4, 0xDEA4, 0xE994, 0x1DAD,
|
||||
0x2A9D, 0x73CD, 0x44FD, 0xC16D, 0xF65D, 0xAF0D, 0x983D, 0xB40C, 0x833C, 0xDA6C, 0xED5C, 0x68CC, 0x5FFC,
|
||||
0x06AC, 0x319C, 0x5ECE, 0x69FE, 0x30AE, 0x079E, 0x820E, 0xB53E, 0xEC6E, 0xDB5E, 0xF76F, 0xC05F, 0x990F,
|
||||
0xAE3F, 0x2BAF, 0x1C9F, 0x45CF, 0x72FF, 0x9B6B, 0xAC5B, 0xF50B, 0xC23B, 0x47AB, 0x709B, 0x29CB, 0x1EFB,
|
||||
0x32CA, 0x05FA, 0x5CAA, 0x6B9A, 0xEE0A, 0xD93A, 0x806A, 0xB75A, 0xD808, 0xEF38, 0xB668, 0x8158, 0x04C8,
|
||||
0x33F8, 0x6AA8, 0x5D98, 0x71A9, 0x4699, 0x1FC9, 0x28F9, 0xAD69, 0x9A59, 0xC309, 0xF439, 0x3B5A, 0x0C6A,
|
||||
0x553A, 0x620A, 0xE79A, 0xD0AA, 0x89FA, 0xBECA, 0x92FB, 0xA5CB, 0xFC9B, 0xCBAB, 0x4E3B, 0x790B, 0x205B,
|
||||
0x176B, 0x7839, 0x4F09, 0x1659, 0x2169, 0xA4F9, 0x93C9, 0xCA99, 0xFDA9, 0xD198, 0xE6A8, 0xBFF8, 0x88C8,
|
||||
0x0D58, 0x3A68, 0x6338, 0x5408, 0xBD9C, 0x8AAC, 0xD3FC, 0xE4CC, 0x615C, 0x566C, 0x0F3C, 0x380C, 0x143D,
|
||||
0x230D, 0x7A5D, 0x4D6D, 0xC8FD, 0xFFCD, 0xA69D, 0x91AD, 0xFEFF, 0xC9CF, 0x909F, 0xA7AF, 0x223F, 0x150F,
|
||||
0x4C5F, 0x7B6F, 0x575E, 0x606E, 0x393E, 0x0E0E, 0x8B9E, 0xBCAE, 0xE5FE, 0xD2CE, 0x26F7, 0x11C7, 0x4897,
|
||||
0x7FA7, 0xFA37, 0xCD07, 0x9457, 0xA367, 0x8F56, 0xB866, 0xE136, 0xD606, 0x5396, 0x64A6, 0x3DF6, 0x0AC6,
|
||||
0x6594, 0x52A4, 0x0BF4, 0x3CC4, 0xB954, 0x8E64, 0xD734, 0xE004, 0xCC35, 0xFB05, 0xA255, 0x9565, 0x10F5,
|
||||
0x27C5, 0x7E95, 0x49A5, 0xA031, 0x9701, 0xCE51, 0xF961, 0x7CF1, 0x4BC1, 0x1291, 0x25A1, 0x0990, 0x3EA0,
|
||||
0x67F0, 0x50C0, 0xD550, 0xE260, 0xBB30, 0x8C00, 0xE352, 0xD462, 0x8D32, 0xBA02, 0x3F92, 0x08A2, 0x51F2,
|
||||
0x66C2, 0x4AF3, 0x7DC3, 0x2493, 0x13A3, 0x9633, 0xA103, 0xF853, 0xCF63
|
||||
},
|
||||
new ushort[]
|
||||
{
|
||||
0x0000, 0x76B4, 0xED68, 0x9BDC, 0xCAF1, 0xBC45, 0x2799, 0x512D, 0x85C3, 0xF377, 0x68AB, 0x1E1F, 0x4F32,
|
||||
0x3986, 0xA25A, 0xD4EE, 0x1BA7, 0x6D13, 0xF6CF, 0x807B, 0xD156, 0xA7E2, 0x3C3E, 0x4A8A, 0x9E64, 0xE8D0,
|
||||
0x730C, 0x05B8, 0x5495, 0x2221, 0xB9FD, 0xCF49, 0x374E, 0x41FA, 0xDA26, 0xAC92, 0xFDBF, 0x8B0B, 0x10D7,
|
||||
0x6663, 0xB28D, 0xC439, 0x5FE5, 0x2951, 0x787C, 0x0EC8, 0x9514, 0xE3A0, 0x2CE9, 0x5A5D, 0xC181, 0xB735,
|
||||
0xE618, 0x90AC, 0x0B70, 0x7DC4, 0xA92A, 0xDF9E, 0x4442, 0x32F6, 0x63DB, 0x156F, 0x8EB3, 0xF807, 0x6E9C,
|
||||
0x1828, 0x83F4, 0xF540, 0xA46D, 0xD2D9, 0x4905, 0x3FB1, 0xEB5F, 0x9DEB, 0x0637, 0x7083, 0x21AE, 0x571A,
|
||||
0xCCC6, 0xBA72, 0x753B, 0x038F, 0x9853, 0xEEE7, 0xBFCA, 0xC97E, 0x52A2, 0x2416, 0xF0F8, 0x864C, 0x1D90,
|
||||
0x6B24, 0x3A09, 0x4CBD, 0xD761, 0xA1D5, 0x59D2, 0x2F66, 0xB4BA, 0xC20E, 0x9323, 0xE597, 0x7E4B, 0x08FF,
|
||||
0xDC11, 0xAAA5, 0x3179, 0x47CD, 0x16E0, 0x6054, 0xFB88, 0x8D3C, 0x4275, 0x34C1, 0xAF1D, 0xD9A9, 0x8884,
|
||||
0xFE30, 0x65EC, 0x1358, 0xC7B6, 0xB102, 0x2ADE, 0x5C6A, 0x0D47, 0x7BF3, 0xE02F, 0x969B, 0xDD38, 0xAB8C,
|
||||
0x3050, 0x46E4, 0x17C9, 0x617D, 0xFAA1, 0x8C15, 0x58FB, 0x2E4F, 0xB593, 0xC327, 0x920A, 0xE4BE, 0x7F62,
|
||||
0x09D6, 0xC69F, 0xB02B, 0x2BF7, 0x5D43, 0x0C6E, 0x7ADA, 0xE106, 0x97B2, 0x435C, 0x35E8, 0xAE34, 0xD880,
|
||||
0x89AD, 0xFF19, 0x64C5, 0x1271, 0xEA76, 0x9CC2, 0x071E, 0x71AA, 0x2087, 0x5633, 0xCDEF, 0xBB5B, 0x6FB5,
|
||||
0x1901, 0x82DD, 0xF469, 0xA544, 0xD3F0, 0x482C, 0x3E98, 0xF1D1, 0x8765, 0x1CB9, 0x6A0D, 0x3B20, 0x4D94,
|
||||
0xD648, 0xA0FC, 0x7412, 0x02A6, 0x997A, 0xEFCE, 0xBEE3, 0xC857, 0x538B, 0x253F, 0xB3A4, 0xC510, 0x5ECC,
|
||||
0x2878, 0x7955, 0x0FE1, 0x943D, 0xE289, 0x3667, 0x40D3, 0xDB0F, 0xADBB, 0xFC96, 0x8A22, 0x11FE, 0x674A,
|
||||
0xA803, 0xDEB7, 0x456B, 0x33DF, 0x62F2, 0x1446, 0x8F9A, 0xF92E, 0x2DC0, 0x5B74, 0xC0A8, 0xB61C, 0xE731,
|
||||
0x9185, 0x0A59, 0x7CED, 0x84EA, 0xF25E, 0x6982, 0x1F36, 0x4E1B, 0x38AF, 0xA373, 0xD5C7, 0x0129, 0x779D,
|
||||
0xEC41, 0x9AF5, 0xCBD8, 0xBD6C, 0x26B0, 0x5004, 0x9F4D, 0xE9F9, 0x7225, 0x0491, 0x55BC, 0x2308, 0xB8D4,
|
||||
0xCE60, 0x1A8E, 0x6C3A, 0xF7E6, 0x8152, 0xD07F, 0xA6CB, 0x3D17, 0x4BA3
|
||||
},
|
||||
new ushort[]
|
||||
{
|
||||
0x0000, 0xAA51, 0x4483, 0xEED2, 0x8906, 0x2357, 0xCD85, 0x67D4, 0x022D, 0xA87C, 0x46AE, 0xECFF, 0x8B2B,
|
||||
0x217A, 0xCFA8, 0x65F9, 0x045A, 0xAE0B, 0x40D9, 0xEA88, 0x8D5C, 0x270D, 0xC9DF, 0x638E, 0x0677, 0xAC26,
|
||||
0x42F4, 0xE8A5, 0x8F71, 0x2520, 0xCBF2, 0x61A3, 0x08B4, 0xA2E5, 0x4C37, 0xE666, 0x81B2, 0x2BE3, 0xC531,
|
||||
0x6F60, 0x0A99, 0xA0C8, 0x4E1A, 0xE44B, 0x839F, 0x29CE, 0xC71C, 0x6D4D, 0x0CEE, 0xA6BF, 0x486D, 0xE23C,
|
||||
0x85E8, 0x2FB9, 0xC16B, 0x6B3A, 0x0EC3, 0xA492, 0x4A40, 0xE011, 0x87C5, 0x2D94, 0xC346, 0x6917, 0x1168,
|
||||
0xBB39, 0x55EB, 0xFFBA, 0x986E, 0x323F, 0xDCED, 0x76BC, 0x1345, 0xB914, 0x57C6, 0xFD97, 0x9A43, 0x3012,
|
||||
0xDEC0, 0x7491, 0x1532, 0xBF63, 0x51B1, 0xFBE0, 0x9C34, 0x3665, 0xD8B7, 0x72E6, 0x171F, 0xBD4E, 0x539C,
|
||||
0xF9CD, 0x9E19, 0x3448, 0xDA9A, 0x70CB, 0x19DC, 0xB38D, 0x5D5F, 0xF70E, 0x90DA, 0x3A8B, 0xD459, 0x7E08,
|
||||
0x1BF1, 0xB1A0, 0x5F72, 0xF523, 0x92F7, 0x38A6, 0xD674, 0x7C25, 0x1D86, 0xB7D7, 0x5905, 0xF354, 0x9480,
|
||||
0x3ED1, 0xD003, 0x7A52, 0x1FAB, 0xB5FA, 0x5B28, 0xF179, 0x96AD, 0x3CFC, 0xD22E, 0x787F, 0x22D0, 0x8881,
|
||||
0x6653, 0xCC02, 0xABD6, 0x0187, 0xEF55, 0x4504, 0x20FD, 0x8AAC, 0x647E, 0xCE2F, 0xA9FB, 0x03AA, 0xED78,
|
||||
0x4729, 0x268A, 0x8CDB, 0x6209, 0xC858, 0xAF8C, 0x05DD, 0xEB0F, 0x415E, 0x24A7, 0x8EF6, 0x6024, 0xCA75,
|
||||
0xADA1, 0x07F0, 0xE922, 0x4373, 0x2A64, 0x8035, 0x6EE7, 0xC4B6, 0xA362, 0x0933, 0xE7E1, 0x4DB0, 0x2849,
|
||||
0x8218, 0x6CCA, 0xC69B, 0xA14F, 0x0B1E, 0xE5CC, 0x4F9D, 0x2E3E, 0x846F, 0x6ABD, 0xC0EC, 0xA738, 0x0D69,
|
||||
0xE3BB, 0x49EA, 0x2C13, 0x8642, 0x6890, 0xC2C1, 0xA515, 0x0F44, 0xE196, 0x4BC7, 0x33B8, 0x99E9, 0x773B,
|
||||
0xDD6A, 0xBABE, 0x10EF, 0xFE3D, 0x546C, 0x3195, 0x9BC4, 0x7516, 0xDF47, 0xB893, 0x12C2, 0xFC10, 0x5641,
|
||||
0x37E2, 0x9DB3, 0x7361, 0xD930, 0xBEE4, 0x14B5, 0xFA67, 0x5036, 0x35CF, 0x9F9E, 0x714C, 0xDB1D, 0xBCC9,
|
||||
0x1698, 0xF84A, 0x521B, 0x3B0C, 0x915D, 0x7F8F, 0xD5DE, 0xB20A, 0x185B, 0xF689, 0x5CD8, 0x3921, 0x9370,
|
||||
0x7DA2, 0xD7F3, 0xB027, 0x1A76, 0xF4A4, 0x5EF5, 0x3F56, 0x9507, 0x7BD5, 0xD184, 0xB650, 0x1C01, 0xF2D3,
|
||||
0x5882, 0x3D7B, 0x972A, 0x79F8, 0xD3A9, 0xB47D, 0x1E2C, 0xF0FE, 0x5AAF
|
||||
},
|
||||
new ushort[]
|
||||
{
|
||||
0x0000, 0x45A0, 0x8B40, 0xCEE0, 0x06A1, 0x4301, 0x8DE1, 0xC841, 0x0D42, 0x48E2, 0x8602, 0xC3A2, 0x0BE3,
|
||||
0x4E43, 0x80A3, 0xC503, 0x1A84, 0x5F24, 0x91C4, 0xD464, 0x1C25, 0x5985, 0x9765, 0xD2C5, 0x17C6, 0x5266,
|
||||
0x9C86, 0xD926, 0x1167, 0x54C7, 0x9A27, 0xDF87, 0x3508, 0x70A8, 0xBE48, 0xFBE8, 0x33A9, 0x7609, 0xB8E9,
|
||||
0xFD49, 0x384A, 0x7DEA, 0xB30A, 0xF6AA, 0x3EEB, 0x7B4B, 0xB5AB, 0xF00B, 0x2F8C, 0x6A2C, 0xA4CC, 0xE16C,
|
||||
0x292D, 0x6C8D, 0xA26D, 0xE7CD, 0x22CE, 0x676E, 0xA98E, 0xEC2E, 0x246F, 0x61CF, 0xAF2F, 0xEA8F, 0x6A10,
|
||||
0x2FB0, 0xE150, 0xA4F0, 0x6CB1, 0x2911, 0xE7F1, 0xA251, 0x6752, 0x22F2, 0xEC12, 0xA9B2, 0x61F3, 0x2453,
|
||||
0xEAB3, 0xAF13, 0x7094, 0x3534, 0xFBD4, 0xBE74, 0x7635, 0x3395, 0xFD75, 0xB8D5, 0x7DD6, 0x3876, 0xF696,
|
||||
0xB336, 0x7B77, 0x3ED7, 0xF037, 0xB597, 0x5F18, 0x1AB8, 0xD458, 0x91F8, 0x59B9, 0x1C19, 0xD2F9, 0x9759,
|
||||
0x525A, 0x17FA, 0xD91A, 0x9CBA, 0x54FB, 0x115B, 0xDFBB, 0x9A1B, 0x459C, 0x003C, 0xCEDC, 0x8B7C, 0x433D,
|
||||
0x069D, 0xC87D, 0x8DDD, 0x48DE, 0x0D7E, 0xC39E, 0x863E, 0x4E7F, 0x0BDF, 0xC53F, 0x809F, 0xD420, 0x9180,
|
||||
0x5F60, 0x1AC0, 0xD281, 0x9721, 0x59C1, 0x1C61, 0xD962, 0x9CC2, 0x5222, 0x1782, 0xDFC3, 0x9A63, 0x5483,
|
||||
0x1123, 0xCEA4, 0x8B04, 0x45E4, 0x0044, 0xC805, 0x8DA5, 0x4345, 0x06E5, 0xC3E6, 0x8646, 0x48A6, 0x0D06,
|
||||
0xC547, 0x80E7, 0x4E07, 0x0BA7, 0xE128, 0xA488, 0x6A68, 0x2FC8, 0xE789, 0xA229, 0x6CC9, 0x2969, 0xEC6A,
|
||||
0xA9CA, 0x672A, 0x228A, 0xEACB, 0xAF6B, 0x618B, 0x242B, 0xFBAC, 0xBE0C, 0x70EC, 0x354C, 0xFD0D, 0xB8AD,
|
||||
0x764D, 0x33ED, 0xF6EE, 0xB34E, 0x7DAE, 0x380E, 0xF04F, 0xB5EF, 0x7B0F, 0x3EAF, 0xBE30, 0xFB90, 0x3570,
|
||||
0x70D0, 0xB891, 0xFD31, 0x33D1, 0x7671, 0xB372, 0xF6D2, 0x3832, 0x7D92, 0xB5D3, 0xF073, 0x3E93, 0x7B33,
|
||||
0xA4B4, 0xE114, 0x2FF4, 0x6A54, 0xA215, 0xE7B5, 0x2955, 0x6CF5, 0xA9F6, 0xEC56, 0x22B6, 0x6716, 0xAF57,
|
||||
0xEAF7, 0x2417, 0x61B7, 0x8B38, 0xCE98, 0x0078, 0x45D8, 0x8D99, 0xC839, 0x06D9, 0x4379, 0x867A, 0xC3DA,
|
||||
0x0D3A, 0x489A, 0x80DB, 0xC57B, 0x0B9B, 0x4E3B, 0x91BC, 0xD41C, 0x1AFC, 0x5F5C, 0x971D, 0xD2BD, 0x1C5D,
|
||||
0x59FD, 0x9CFE, 0xD95E, 0x17BE, 0x521E, 0x9A5F, 0xDFFF, 0x111F, 0x54BF
|
||||
},
|
||||
new ushort[]
|
||||
{
|
||||
0x0000, 0xB861, 0x60E3, 0xD882, 0xC1C6, 0x79A7, 0xA125, 0x1944, 0x93AD, 0x2BCC, 0xF34E, 0x4B2F, 0x526B,
|
||||
0xEA0A, 0x3288, 0x8AE9, 0x377B, 0x8F1A, 0x5798, 0xEFF9, 0xF6BD, 0x4EDC, 0x965E, 0x2E3F, 0xA4D6, 0x1CB7,
|
||||
0xC435, 0x7C54, 0x6510, 0xDD71, 0x05F3, 0xBD92, 0x6EF6, 0xD697, 0x0E15, 0xB674, 0xAF30, 0x1751, 0xCFD3,
|
||||
0x77B2, 0xFD5B, 0x453A, 0x9DB8, 0x25D9, 0x3C9D, 0x84FC, 0x5C7E, 0xE41F, 0x598D, 0xE1EC, 0x396E, 0x810F,
|
||||
0x984B, 0x202A, 0xF8A8, 0x40C9, 0xCA20, 0x7241, 0xAAC3, 0x12A2, 0x0BE6, 0xB387, 0x6B05, 0xD364, 0xDDEC,
|
||||
0x658D, 0xBD0F, 0x056E, 0x1C2A, 0xA44B, 0x7CC9, 0xC4A8, 0x4E41, 0xF620, 0x2EA2, 0x96C3, 0x8F87, 0x37E6,
|
||||
0xEF64, 0x5705, 0xEA97, 0x52F6, 0x8A74, 0x3215, 0x2B51, 0x9330, 0x4BB2, 0xF3D3, 0x793A, 0xC15B, 0x19D9,
|
||||
0xA1B8, 0xB8FC, 0x009D, 0xD81F, 0x607E, 0xB31A, 0x0B7B, 0xD3F9, 0x6B98, 0x72DC, 0xCABD, 0x123F, 0xAA5E,
|
||||
0x20B7, 0x98D6, 0x4054, 0xF835, 0xE171, 0x5910, 0x8192, 0x39F3, 0x8461, 0x3C00, 0xE482, 0x5CE3, 0x45A7,
|
||||
0xFDC6, 0x2544, 0x9D25, 0x17CC, 0xAFAD, 0x772F, 0xCF4E, 0xD60A, 0x6E6B, 0xB6E9, 0x0E88, 0xABF9, 0x1398,
|
||||
0xCB1A, 0x737B, 0x6A3F, 0xD25E, 0x0ADC, 0xB2BD, 0x3854, 0x8035, 0x58B7, 0xE0D6, 0xF992, 0x41F3, 0x9971,
|
||||
0x2110, 0x9C82, 0x24E3, 0xFC61, 0x4400, 0x5D44, 0xE525, 0x3DA7, 0x85C6, 0x0F2F, 0xB74E, 0x6FCC, 0xD7AD,
|
||||
0xCEE9, 0x7688, 0xAE0A, 0x166B, 0xC50F, 0x7D6E, 0xA5EC, 0x1D8D, 0x04C9, 0xBCA8, 0x642A, 0xDC4B, 0x56A2,
|
||||
0xEEC3, 0x3641, 0x8E20, 0x9764, 0x2F05, 0xF787, 0x4FE6, 0xF274, 0x4A15, 0x9297, 0x2AF6, 0x33B2, 0x8BD3,
|
||||
0x5351, 0xEB30, 0x61D9, 0xD9B8, 0x013A, 0xB95B, 0xA01F, 0x187E, 0xC0FC, 0x789D, 0x7615, 0xCE74, 0x16F6,
|
||||
0xAE97, 0xB7D3, 0x0FB2, 0xD730, 0x6F51, 0xE5B8, 0x5DD9, 0x855B, 0x3D3A, 0x247E, 0x9C1F, 0x449D, 0xFCFC,
|
||||
0x416E, 0xF90F, 0x218D, 0x99EC, 0x80A8, 0x38C9, 0xE04B, 0x582A, 0xD2C3, 0x6AA2, 0xB220, 0x0A41, 0x1305,
|
||||
0xAB64, 0x73E6, 0xCB87, 0x18E3, 0xA082, 0x7800, 0xC061, 0xD925, 0x6144, 0xB9C6, 0x01A7, 0x8B4E, 0x332F,
|
||||
0xEBAD, 0x53CC, 0x4A88, 0xF2E9, 0x2A6B, 0x920A, 0x2F98, 0x97F9, 0x4F7B, 0xF71A, 0xEE5E, 0x563F, 0x8EBD,
|
||||
0x36DC, 0xBC35, 0x0454, 0xDCD6, 0x64B7, 0x7DF3, 0xC592, 0x1D10, 0xA571
|
||||
},
|
||||
new ushort[]
|
||||
{
|
||||
0x0000, 0x47D3, 0x8FA6, 0xC875, 0x0F6D, 0x48BE, 0x80CB, 0xC718, 0x1EDA, 0x5909, 0x917C, 0xD6AF, 0x11B7,
|
||||
0x5664, 0x9E11, 0xD9C2, 0x3DB4, 0x7A67, 0xB212, 0xF5C1, 0x32D9, 0x750A, 0xBD7F, 0xFAAC, 0x236E, 0x64BD,
|
||||
0xACC8, 0xEB1B, 0x2C03, 0x6BD0, 0xA3A5, 0xE476, 0x7B68, 0x3CBB, 0xF4CE, 0xB31D, 0x7405, 0x33D6, 0xFBA3,
|
||||
0xBC70, 0x65B2, 0x2261, 0xEA14, 0xADC7, 0x6ADF, 0x2D0C, 0xE579, 0xA2AA, 0x46DC, 0x010F, 0xC97A, 0x8EA9,
|
||||
0x49B1, 0x0E62, 0xC617, 0x81C4, 0x5806, 0x1FD5, 0xD7A0, 0x9073, 0x576B, 0x10B8, 0xD8CD, 0x9F1E, 0xF6D0,
|
||||
0xB103, 0x7976, 0x3EA5, 0xF9BD, 0xBE6E, 0x761B, 0x31C8, 0xE80A, 0xAFD9, 0x67AC, 0x207F, 0xE767, 0xA0B4,
|
||||
0x68C1, 0x2F12, 0xCB64, 0x8CB7, 0x44C2, 0x0311, 0xC409, 0x83DA, 0x4BAF, 0x0C7C, 0xD5BE, 0x926D, 0x5A18,
|
||||
0x1DCB, 0xDAD3, 0x9D00, 0x5575, 0x12A6, 0x8DB8, 0xCA6B, 0x021E, 0x45CD, 0x82D5, 0xC506, 0x0D73, 0x4AA0,
|
||||
0x9362, 0xD4B1, 0x1CC4, 0x5B17, 0x9C0F, 0xDBDC, 0x13A9, 0x547A, 0xB00C, 0xF7DF, 0x3FAA, 0x7879, 0xBF61,
|
||||
0xF8B2, 0x30C7, 0x7714, 0xAED6, 0xE905, 0x2170, 0x66A3, 0xA1BB, 0xE668, 0x2E1D, 0x69CE, 0xFD81, 0xBA52,
|
||||
0x7227, 0x35F4, 0xF2EC, 0xB53F, 0x7D4A, 0x3A99, 0xE35B, 0xA488, 0x6CFD, 0x2B2E, 0xEC36, 0xABE5, 0x6390,
|
||||
0x2443, 0xC035, 0x87E6, 0x4F93, 0x0840, 0xCF58, 0x888B, 0x40FE, 0x072D, 0xDEEF, 0x993C, 0x5149, 0x169A,
|
||||
0xD182, 0x9651, 0x5E24, 0x19F7, 0x86E9, 0xC13A, 0x094F, 0x4E9C, 0x8984, 0xCE57, 0x0622, 0x41F1, 0x9833,
|
||||
0xDFE0, 0x1795, 0x5046, 0x975E, 0xD08D, 0x18F8, 0x5F2B, 0xBB5D, 0xFC8E, 0x34FB, 0x7328, 0xB430, 0xF3E3,
|
||||
0x3B96, 0x7C45, 0xA587, 0xE254, 0x2A21, 0x6DF2, 0xAAEA, 0xED39, 0x254C, 0x629F, 0x0B51, 0x4C82, 0x84F7,
|
||||
0xC324, 0x043C, 0x43EF, 0x8B9A, 0xCC49, 0x158B, 0x5258, 0x9A2D, 0xDDFE, 0x1AE6, 0x5D35, 0x9540, 0xD293,
|
||||
0x36E5, 0x7136, 0xB943, 0xFE90, 0x3988, 0x7E5B, 0xB62E, 0xF1FD, 0x283F, 0x6FEC, 0xA799, 0xE04A, 0x2752,
|
||||
0x6081, 0xA8F4, 0xEF27, 0x7039, 0x37EA, 0xFF9F, 0xB84C, 0x7F54, 0x3887, 0xF0F2, 0xB721, 0x6EE3, 0x2930,
|
||||
0xE145, 0xA696, 0x618E, 0x265D, 0xEE28, 0xA9FB, 0x4D8D, 0x0A5E, 0xC22B, 0x85F8, 0x42E0, 0x0533, 0xCD46,
|
||||
0x8A95, 0x5357, 0x1484, 0xDCF1, 0x9B22, 0x5C3A, 0x1BE9, 0xD39C, 0x944F
|
||||
}
|
||||
};
|
||||
|
||||
/// <summary>Initializes an instance of the CRC16 with CCITT polynomial and seed.</summary>
|
||||
/// <inheritdoc />
|
||||
public CRC16CcittContext() : base(CRC16_CCITT_POLY, CRC16_CCITT_SEED, _ccittCrc16Table, true) {}
|
||||
|
||||
public new string Name => "CRC-16 (CCITT)";
|
||||
public new Guid Id => new("4C3BD0D5-24BD-4D45-BC19-A90A5AA5CC9D");
|
||||
public new string Author => "Natalia Portillo";
|
||||
|
||||
/// <summary>Gets the hash of a file</summary>
|
||||
/// <param name="filename">File path.</param>
|
||||
public static byte[] File(string filename)
|
||||
{
|
||||
File(filename, out byte[] hash);
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
|
||||
/// <param name="filename">File path.</param>
|
||||
/// <param name="hash">Byte array of the hash value.</param>
|
||||
public static string File(string filename, out byte[] hash) =>
|
||||
File(filename, out hash, CRC16_CCITT_POLY, CRC16_CCITT_SEED, _ccittCrc16Table, true);
|
||||
|
||||
/// <summary>Gets the hash of the specified data buffer.</summary>
|
||||
/// <param name="data">Data buffer.</param>
|
||||
/// <param name="len">Length of the data buffer to hash.</param>
|
||||
/// <param name="hash">Byte array of the hash value.</param>
|
||||
public static string Data(byte[] data, uint len, out byte[] hash) =>
|
||||
Data(data, len, out hash, CRC16_CCITT_POLY, CRC16_CCITT_SEED, _ccittCrc16Table, true);
|
||||
|
||||
/// <summary>Gets the hash of the specified data buffer.</summary>
|
||||
/// <param name="data">Data buffer.</param>
|
||||
/// <param name="hash">Byte array of the hash value.</param>
|
||||
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
|
||||
|
||||
/// <summary>Calculates the CCITT CRC16 of the specified buffer with the specified parameters</summary>
|
||||
/// <param name="buffer">Buffer</param>
|
||||
public static ushort Calculate(byte[] buffer) =>
|
||||
Calculate(buffer, CRC16_CCITT_POLY, CRC16_CCITT_SEED, _ccittCrc16Table, true);
|
||||
}
|
||||
@@ -1,649 +0,0 @@
|
||||
// /***************************************************************************
|
||||
// Aaru Data Preservation Suite
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : CRC16Context.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Checksums.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Implements a CRC16 algorithm.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2023 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Aaru.CommonTypes.Interfaces;
|
||||
using Aaru.Helpers;
|
||||
|
||||
namespace Aaru.Checksums;
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>Implements a CRC16 algorithm</summary>
|
||||
public class Crc16Context : IChecksum
|
||||
{
|
||||
readonly ushort _finalSeed;
|
||||
readonly bool _inverse;
|
||||
readonly IntPtr _nativeContext;
|
||||
readonly ushort[][]? _table;
|
||||
readonly bool _useCcitt;
|
||||
readonly bool _useIbm;
|
||||
readonly bool _useNative;
|
||||
ushort _hashInt;
|
||||
|
||||
/// <summary>Initializes the CRC16 table with a custom polynomial and seed</summary>
|
||||
public Crc16Context(ushort polynomial, ushort seed, ushort[][] table, bool inverse)
|
||||
{
|
||||
_hashInt = seed;
|
||||
_finalSeed = seed;
|
||||
_inverse = inverse;
|
||||
|
||||
_useNative = Native.IsSupported;
|
||||
|
||||
_useCcitt = polynomial == CRC16CcittContext.CRC16_CCITT_POLY &&
|
||||
seed == CRC16CcittContext.CRC16_CCITT_SEED &&
|
||||
inverse;
|
||||
|
||||
_useIbm = polynomial == CRC16IbmContext.CRC16_IBM_POLY && seed == CRC16IbmContext.CRC16_IBM_SEED && !inverse;
|
||||
|
||||
if(_useCcitt && _useNative)
|
||||
{
|
||||
_nativeContext = crc16_ccitt_init();
|
||||
_useNative = _nativeContext != IntPtr.Zero;
|
||||
}
|
||||
else if(_useIbm && _useNative)
|
||||
{
|
||||
_nativeContext = crc16_init();
|
||||
_useNative = _nativeContext != IntPtr.Zero;
|
||||
}
|
||||
else
|
||||
_useNative = false;
|
||||
|
||||
if(!_useNative)
|
||||
_table = table ?? GenerateTable(polynomial, inverse);
|
||||
}
|
||||
|
||||
#region IChecksum Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => "CRC-16";
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Id => new("D69CF1E7-4A7B-4605-9291-3A1BE4C2951F");
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Author => "Natalia Portillo";
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>Updates the hash with data.</summary>
|
||||
/// <param name="data">Data buffer.</param>
|
||||
/// <param name="len">Length of buffer to hash.</param>
|
||||
public void Update(byte[] data, uint len)
|
||||
{
|
||||
switch(_useNative)
|
||||
{
|
||||
case true when _useCcitt:
|
||||
crc16_ccitt_update(_nativeContext, data, len);
|
||||
|
||||
break;
|
||||
case true when _useIbm:
|
||||
crc16_update(_nativeContext, data, len);
|
||||
|
||||
break;
|
||||
default:
|
||||
{
|
||||
if(_inverse)
|
||||
StepInverse(ref _hashInt, _table!, data, len);
|
||||
else
|
||||
Step(ref _hashInt, _table!, data, len);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>Updates the hash with data.</summary>
|
||||
/// <param name="data">Data buffer.</param>
|
||||
public void Update(byte[] data) => Update(data, (uint)data.Length);
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>Returns a byte array of the hash value.</summary>
|
||||
public byte[] Final()
|
||||
{
|
||||
ushort crc = 0;
|
||||
|
||||
switch(_useNative)
|
||||
{
|
||||
case true when _useCcitt:
|
||||
crc16_ccitt_final(_nativeContext, ref crc);
|
||||
crc16_ccitt_free(_nativeContext);
|
||||
|
||||
break;
|
||||
case true when _useIbm:
|
||||
crc16_final(_nativeContext, ref crc);
|
||||
crc16_free(_nativeContext);
|
||||
|
||||
break;
|
||||
default:
|
||||
{
|
||||
if(_inverse)
|
||||
crc = (ushort)~(_hashInt ^ _finalSeed);
|
||||
else
|
||||
crc = (ushort)(_hashInt ^ _finalSeed);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return BigEndianBitConverter.GetBytes(crc);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>Returns a hexadecimal representation of the hash value.</summary>
|
||||
public string End()
|
||||
{
|
||||
var crc16Output = new StringBuilder();
|
||||
ushort final = 0;
|
||||
|
||||
switch(_useNative)
|
||||
{
|
||||
case true when _useCcitt:
|
||||
crc16_ccitt_final(_nativeContext, ref final);
|
||||
crc16_ccitt_free(_nativeContext);
|
||||
|
||||
break;
|
||||
case true when _useIbm:
|
||||
crc16_final(_nativeContext, ref final);
|
||||
crc16_free(_nativeContext);
|
||||
|
||||
break;
|
||||
default:
|
||||
{
|
||||
if(_inverse)
|
||||
final = (ushort)~(_hashInt ^ _finalSeed);
|
||||
else
|
||||
final = (ushort)(_hashInt ^ _finalSeed);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
byte[] finalBytes = BigEndianBitConverter.GetBytes(final);
|
||||
|
||||
foreach(byte t in finalBytes)
|
||||
crc16Output.Append(t.ToString("x2"));
|
||||
|
||||
return crc16Output.ToString();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
|
||||
static extern IntPtr crc16_init();
|
||||
|
||||
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
|
||||
static extern int crc16_update(IntPtr ctx, byte[] data, uint len);
|
||||
|
||||
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
|
||||
static extern int crc16_final(IntPtr ctx, ref ushort crc);
|
||||
|
||||
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
|
||||
static extern void crc16_free(IntPtr ctx);
|
||||
|
||||
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
|
||||
static extern IntPtr crc16_ccitt_init();
|
||||
|
||||
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
|
||||
static extern int crc16_ccitt_update(IntPtr ctx, byte[] data, uint len);
|
||||
|
||||
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
|
||||
static extern int crc16_ccitt_final(IntPtr ctx, ref ushort crc);
|
||||
|
||||
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
|
||||
static extern void crc16_ccitt_free(IntPtr ctx);
|
||||
|
||||
static void Step(ref ushort previousCrc, ushort[][] table, byte[] data, uint len)
|
||||
{
|
||||
// Unroll according to Intel slicing by uint8_t
|
||||
// http://www.intel.com/technology/comms/perfnet/download/CRC_generators.pdf
|
||||
// http://sourceforge.net/projects/slicing-by-8/
|
||||
|
||||
var currentPos = 0;
|
||||
const int unroll = 4;
|
||||
const int bytesAtOnce = 8 * unroll;
|
||||
|
||||
ushort crc = previousCrc;
|
||||
|
||||
while(len >= bytesAtOnce)
|
||||
{
|
||||
int unrolling;
|
||||
|
||||
for(unrolling = 0; unrolling < unroll; unrolling++)
|
||||
{
|
||||
// TODO: What trick is Microsoft doing here that's faster than arithmetic conversion
|
||||
uint one = BitConverter.ToUInt32(data, currentPos) ^ crc;
|
||||
currentPos += 4;
|
||||
var two = BitConverter.ToUInt32(data, currentPos);
|
||||
currentPos += 4;
|
||||
|
||||
crc = (ushort)(table[0][two >> 24 & 0xFF] ^
|
||||
table[1][two >> 16 & 0xFF] ^
|
||||
table[2][two >> 8 & 0xFF] ^
|
||||
table[3][two & 0xFF] ^
|
||||
table[4][one >> 24 & 0xFF] ^
|
||||
table[5][one >> 16 & 0xFF] ^
|
||||
table[6][one >> 8 & 0xFF] ^
|
||||
table[7][one & 0xFF]);
|
||||
}
|
||||
|
||||
len -= bytesAtOnce;
|
||||
}
|
||||
|
||||
while(len-- != 0)
|
||||
crc = (ushort)(crc >> 8 ^ table[0][crc & 0xFF ^ data[currentPos++]]);
|
||||
|
||||
previousCrc = crc;
|
||||
}
|
||||
|
||||
static void StepInverse(ref ushort previousCrc, ushort[][] table, byte[] data, uint len)
|
||||
{
|
||||
// Unroll according to Intel slicing by uint8_t
|
||||
// http://www.intel.com/technology/comms/perfnet/download/CRC_generators.pdf
|
||||
// http://sourceforge.net/projects/slicing-by-8/
|
||||
|
||||
var currentPos = 0;
|
||||
const int unroll = 4;
|
||||
const int bytesAtOnce = 8 * unroll;
|
||||
|
||||
ushort crc = previousCrc;
|
||||
|
||||
while(len >= bytesAtOnce)
|
||||
{
|
||||
int unrolling;
|
||||
|
||||
for(unrolling = 0; unrolling < unroll; unrolling++)
|
||||
{
|
||||
crc = (ushort)(table[7][data[currentPos + 0] ^ crc >> 8] ^
|
||||
table[6][data[currentPos + 1] ^ crc & 0xFF] ^
|
||||
table[5][data[currentPos + 2]] ^
|
||||
table[4][data[currentPos + 3]] ^
|
||||
table[3][data[currentPos + 4]] ^
|
||||
table[2][data[currentPos + 5]] ^
|
||||
table[1][data[currentPos + 6]] ^
|
||||
table[0][data[currentPos + 7]]);
|
||||
|
||||
currentPos += 8;
|
||||
}
|
||||
|
||||
len -= bytesAtOnce;
|
||||
}
|
||||
|
||||
while(len-- != 0)
|
||||
crc = (ushort)(crc << 8 ^ table[0][crc >> 8 ^ data[currentPos++]]);
|
||||
|
||||
previousCrc = crc;
|
||||
}
|
||||
|
||||
static ushort[][] GenerateTable(ushort polynomial, bool inverseTable)
|
||||
{
|
||||
var table = new ushort[8][];
|
||||
|
||||
for(var i = 0; i < 8; i++)
|
||||
table[i] = new ushort[256];
|
||||
|
||||
if(!inverseTable)
|
||||
{
|
||||
for(uint i = 0; i < 256; i++)
|
||||
{
|
||||
uint entry = i;
|
||||
|
||||
for(var j = 0; j < 8; j++)
|
||||
{
|
||||
if((entry & 1) == 1)
|
||||
entry = entry >> 1 ^ polynomial;
|
||||
else
|
||||
entry >>= 1;
|
||||
}
|
||||
|
||||
table[0][i] = (ushort)entry;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(uint i = 0; i < 256; i++)
|
||||
{
|
||||
uint entry = i << 8;
|
||||
|
||||
for(uint j = 0; j < 8; j++)
|
||||
{
|
||||
if((entry & 0x8000) > 0)
|
||||
entry = entry << 1 ^ polynomial;
|
||||
else
|
||||
entry <<= 1;
|
||||
|
||||
table[0][i] = (ushort)entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(var slice = 1; slice < 8; slice++)
|
||||
for(var i = 0; i < 256; i++)
|
||||
{
|
||||
if(inverseTable)
|
||||
table[slice][i] = (ushort)(table[slice - 1][i] << 8 ^ table[0][table[slice - 1][i] >> 8]);
|
||||
else
|
||||
table[slice][i] = (ushort)(table[slice - 1][i] >> 8 ^ table[0][table[slice - 1][i] & 0xFF]);
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
|
||||
/// <param name="filename">File path.</param>
|
||||
/// <param name="hash">Byte array of the hash value.</param>
|
||||
/// <param name="polynomial">CRC polynomial</param>
|
||||
/// <param name="seed">CRC seed</param>
|
||||
/// <param name="table">CRC lookup table</param>
|
||||
/// <param name="inverse">Is CRC inverted?</param>
|
||||
public static string File(string filename, out byte[] hash, ushort polynomial, ushort seed, ushort[][] table,
|
||||
bool inverse)
|
||||
{
|
||||
bool useNative = Native.IsSupported;
|
||||
|
||||
bool useCcitt = polynomial == CRC16CcittContext.CRC16_CCITT_POLY &&
|
||||
seed == CRC16CcittContext.CRC16_CCITT_SEED &&
|
||||
inverse;
|
||||
|
||||
bool useIbm = polynomial == CRC16IbmContext.CRC16_IBM_POLY &&
|
||||
seed == CRC16IbmContext.CRC16_IBM_SEED &&
|
||||
!inverse;
|
||||
|
||||
IntPtr nativeContext = IntPtr.Zero;
|
||||
|
||||
var fileStream = new FileStream(filename, FileMode.Open);
|
||||
|
||||
ushort localHashInt = seed;
|
||||
|
||||
switch(useNative)
|
||||
{
|
||||
case true when useCcitt:
|
||||
nativeContext = crc16_ccitt_init();
|
||||
useNative = nativeContext != IntPtr.Zero;
|
||||
|
||||
break;
|
||||
case true when useIbm:
|
||||
nativeContext = crc16_init();
|
||||
useNative = nativeContext != IntPtr.Zero;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
ushort[][] localTable = table ?? GenerateTable(polynomial, inverse);
|
||||
|
||||
var buffer = new byte[65536];
|
||||
int read = fileStream.EnsureRead(buffer, 0, 65536);
|
||||
|
||||
while(read > 0)
|
||||
{
|
||||
switch(useNative)
|
||||
{
|
||||
case true when useCcitt:
|
||||
crc16_ccitt_update(nativeContext, buffer, (uint)read);
|
||||
|
||||
break;
|
||||
case true when useIbm:
|
||||
crc16_update(nativeContext, buffer, (uint)read);
|
||||
|
||||
break;
|
||||
default:
|
||||
{
|
||||
if(inverse)
|
||||
StepInverse(ref localHashInt, localTable, buffer, (uint)read);
|
||||
else
|
||||
Step(ref localHashInt, localTable, buffer, (uint)read);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
read = fileStream.EnsureRead(buffer, 0, 65536);
|
||||
}
|
||||
|
||||
localHashInt ^= seed;
|
||||
|
||||
switch(useNative)
|
||||
{
|
||||
case true when useCcitt:
|
||||
crc16_ccitt_final(nativeContext, ref localHashInt);
|
||||
crc16_ccitt_free(nativeContext);
|
||||
|
||||
break;
|
||||
case true when useIbm:
|
||||
crc16_final(nativeContext, ref localHashInt);
|
||||
crc16_free(nativeContext);
|
||||
|
||||
break;
|
||||
default:
|
||||
{
|
||||
if(inverse)
|
||||
localHashInt = (ushort)~localHashInt;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
hash = BigEndianBitConverter.GetBytes(localHashInt);
|
||||
|
||||
var crc16Output = new StringBuilder();
|
||||
|
||||
foreach(byte h in hash)
|
||||
crc16Output.Append(h.ToString("x2"));
|
||||
|
||||
fileStream.Close();
|
||||
|
||||
return crc16Output.ToString();
|
||||
}
|
||||
|
||||
/// <summary>Gets the hash of the specified data buffer.</summary>
|
||||
/// <param name="data">Data buffer.</param>
|
||||
/// <param name="len">Length of the data buffer to hash.</param>
|
||||
/// <param name="hash">Byte array of the hash value.</param>
|
||||
/// <param name="polynomial">CRC polynomial</param>
|
||||
/// <param name="seed">CRC seed</param>
|
||||
/// <param name="table">CRC lookup table</param>
|
||||
/// <param name="inverse">Is CRC inverted?</param>
|
||||
public static string Data(byte[] data, uint len, out byte[] hash, ushort polynomial, ushort seed, ushort[][] table,
|
||||
bool inverse)
|
||||
{
|
||||
bool useNative = Native.IsSupported;
|
||||
|
||||
bool useCcitt = polynomial == CRC16CcittContext.CRC16_CCITT_POLY &&
|
||||
seed == CRC16CcittContext.CRC16_CCITT_SEED &&
|
||||
inverse;
|
||||
|
||||
bool useIbm = polynomial == CRC16IbmContext.CRC16_IBM_POLY &&
|
||||
seed == CRC16IbmContext.CRC16_IBM_SEED &&
|
||||
!inverse;
|
||||
|
||||
IntPtr nativeContext = IntPtr.Zero;
|
||||
|
||||
ushort localHashInt = seed;
|
||||
|
||||
switch(useNative)
|
||||
{
|
||||
case true when useCcitt:
|
||||
nativeContext = crc16_ccitt_init();
|
||||
useNative = nativeContext != IntPtr.Zero;
|
||||
|
||||
break;
|
||||
case true when useIbm:
|
||||
nativeContext = crc16_init();
|
||||
useNative = nativeContext != IntPtr.Zero;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
ushort[][] localTable = table ?? GenerateTable(polynomial, inverse);
|
||||
|
||||
switch(useNative)
|
||||
{
|
||||
case true when useCcitt:
|
||||
crc16_ccitt_update(nativeContext, data, len);
|
||||
|
||||
break;
|
||||
case true when useIbm:
|
||||
crc16_update(nativeContext, data, len);
|
||||
|
||||
break;
|
||||
default:
|
||||
{
|
||||
if(inverse)
|
||||
StepInverse(ref localHashInt, localTable, data, len);
|
||||
else
|
||||
Step(ref localHashInt, localTable, data, len);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
localHashInt ^= seed;
|
||||
|
||||
switch(useNative)
|
||||
{
|
||||
case true when useCcitt:
|
||||
crc16_ccitt_final(nativeContext, ref localHashInt);
|
||||
crc16_ccitt_free(nativeContext);
|
||||
|
||||
break;
|
||||
case true when useIbm:
|
||||
crc16_final(nativeContext, ref localHashInt);
|
||||
crc16_free(nativeContext);
|
||||
|
||||
break;
|
||||
default:
|
||||
{
|
||||
if(inverse)
|
||||
localHashInt = (ushort)~localHashInt;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
hash = BigEndianBitConverter.GetBytes(localHashInt);
|
||||
|
||||
var crc16Output = new StringBuilder();
|
||||
|
||||
foreach(byte h in hash)
|
||||
crc16Output.Append(h.ToString("x2"));
|
||||
|
||||
return crc16Output.ToString();
|
||||
}
|
||||
|
||||
/// <summary>Calculates the CRC16 of the specified buffer with the specified parameters</summary>
|
||||
/// <param name="buffer">Buffer</param>
|
||||
/// <param name="polynomial">Polynomial</param>
|
||||
/// <param name="seed">Seed</param>
|
||||
/// <param name="table">Pre-generated lookup table</param>
|
||||
/// <param name="inverse">Inverse CRC</param>
|
||||
/// <returns>CRC16</returns>
|
||||
public static ushort Calculate(byte[] buffer, ushort polynomial, ushort seed, ushort[][] table, bool inverse)
|
||||
{
|
||||
bool useNative = Native.IsSupported;
|
||||
|
||||
bool useCcitt = polynomial == CRC16CcittContext.CRC16_CCITT_POLY &&
|
||||
seed == CRC16CcittContext.CRC16_CCITT_SEED &&
|
||||
inverse;
|
||||
|
||||
bool useIbm = polynomial == CRC16IbmContext.CRC16_IBM_POLY &&
|
||||
seed == CRC16IbmContext.CRC16_IBM_SEED &&
|
||||
!inverse;
|
||||
|
||||
IntPtr nativeContext = IntPtr.Zero;
|
||||
|
||||
ushort localHashInt = seed;
|
||||
|
||||
switch(useNative)
|
||||
{
|
||||
case true when useCcitt:
|
||||
nativeContext = crc16_ccitt_init();
|
||||
useNative = nativeContext != IntPtr.Zero;
|
||||
|
||||
break;
|
||||
case true when useIbm:
|
||||
nativeContext = crc16_init();
|
||||
useNative = nativeContext != IntPtr.Zero;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
ushort[][] localTable = table ?? GenerateTable(polynomial, inverse);
|
||||
|
||||
switch(useNative)
|
||||
{
|
||||
case true when useCcitt:
|
||||
crc16_ccitt_update(nativeContext, buffer, (uint)buffer.Length);
|
||||
|
||||
break;
|
||||
case true when useIbm:
|
||||
crc16_update(nativeContext, buffer, (uint)buffer.Length);
|
||||
|
||||
break;
|
||||
default:
|
||||
{
|
||||
if(inverse)
|
||||
StepInverse(ref localHashInt, localTable, buffer, (uint)buffer.Length);
|
||||
else
|
||||
Step(ref localHashInt, localTable, buffer, (uint)buffer.Length);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
localHashInt ^= seed;
|
||||
|
||||
switch(useNative)
|
||||
{
|
||||
case true when useCcitt:
|
||||
crc16_ccitt_final(nativeContext, ref localHashInt);
|
||||
crc16_ccitt_free(nativeContext);
|
||||
|
||||
break;
|
||||
case true when useIbm:
|
||||
crc16_final(nativeContext, ref localHashInt);
|
||||
crc16_free(nativeContext);
|
||||
|
||||
break;
|
||||
default:
|
||||
{
|
||||
if(inverse)
|
||||
localHashInt = (ushort)~localHashInt;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return localHashInt;
|
||||
}
|
||||
}
|
||||
@@ -1,276 +0,0 @@
|
||||
// /***************************************************************************
|
||||
// Aaru Data Preservation Suite
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : CRC16IBMContext.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Checksums.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Implements a CRC16 algorithm with the IBM polynomial.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2023 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Aaru.Checksums;
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>Implements the CRC16 algorithm with IBM polynomial and seed</summary>
|
||||
[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")]
|
||||
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
|
||||
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
|
||||
public sealed class CRC16IbmContext : Crc16Context
|
||||
{
|
||||
internal const ushort CRC16_IBM_POLY = 0xA001;
|
||||
internal const ushort CRC16_IBM_SEED = 0x0000;
|
||||
|
||||
static readonly ushort[][] _ibmCrc16Table =
|
||||
{
|
||||
new ushort[]
|
||||
{
|
||||
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500,
|
||||
0xC5C1, 0xC481, 0x0440, 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, 0x0A00, 0xCAC1,
|
||||
0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81,
|
||||
0x1A40, 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, 0x1400, 0xD4C1, 0xD581, 0x1540,
|
||||
0xD701, 0x17C0, 0x1680, 0xD641, 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, 0xF001,
|
||||
0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0,
|
||||
0x3480, 0xF441, 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, 0xFA01, 0x3AC0, 0x3B80,
|
||||
0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
|
||||
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700,
|
||||
0xE7C1, 0xE681, 0x2640, 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, 0xA001, 0x60C0,
|
||||
0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480,
|
||||
0xA441, 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, 0xAA01, 0x6AC0, 0x6B80, 0xAB41,
|
||||
0x6900, 0xA9C1, 0xA881, 0x6840, 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, 0xBE01,
|
||||
0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1,
|
||||
0xB681, 0x7640, 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, 0x5000, 0x90C1, 0x9181,
|
||||
0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
|
||||
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901,
|
||||
0x59C0, 0x5880, 0x9841, 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, 0x4E00, 0x8EC1,
|
||||
0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680,
|
||||
0x8641, 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
|
||||
},
|
||||
new ushort[]
|
||||
{
|
||||
0x0000, 0x9001, 0x6001, 0xF000, 0xC002, 0x5003, 0xA003, 0x3002, 0xC007, 0x5006, 0xA006, 0x3007, 0x0005,
|
||||
0x9004, 0x6004, 0xF005, 0xC00D, 0x500C, 0xA00C, 0x300D, 0x000F, 0x900E, 0x600E, 0xF00F, 0x000A, 0x900B,
|
||||
0x600B, 0xF00A, 0xC008, 0x5009, 0xA009, 0x3008, 0xC019, 0x5018, 0xA018, 0x3019, 0x001B, 0x901A, 0x601A,
|
||||
0xF01B, 0x001E, 0x901F, 0x601F, 0xF01E, 0xC01C, 0x501D, 0xA01D, 0x301C, 0x0014, 0x9015, 0x6015, 0xF014,
|
||||
0xC016, 0x5017, 0xA017, 0x3016, 0xC013, 0x5012, 0xA012, 0x3013, 0x0011, 0x9010, 0x6010, 0xF011, 0xC031,
|
||||
0x5030, 0xA030, 0x3031, 0x0033, 0x9032, 0x6032, 0xF033, 0x0036, 0x9037, 0x6037, 0xF036, 0xC034, 0x5035,
|
||||
0xA035, 0x3034, 0x003C, 0x903D, 0x603D, 0xF03C, 0xC03E, 0x503F, 0xA03F, 0x303E, 0xC03B, 0x503A, 0xA03A,
|
||||
0x303B, 0x0039, 0x9038, 0x6038, 0xF039, 0x0028, 0x9029, 0x6029, 0xF028, 0xC02A, 0x502B, 0xA02B, 0x302A,
|
||||
0xC02F, 0x502E, 0xA02E, 0x302F, 0x002D, 0x902C, 0x602C, 0xF02D, 0xC025, 0x5024, 0xA024, 0x3025, 0x0027,
|
||||
0x9026, 0x6026, 0xF027, 0x0022, 0x9023, 0x6023, 0xF022, 0xC020, 0x5021, 0xA021, 0x3020, 0xC061, 0x5060,
|
||||
0xA060, 0x3061, 0x0063, 0x9062, 0x6062, 0xF063, 0x0066, 0x9067, 0x6067, 0xF066, 0xC064, 0x5065, 0xA065,
|
||||
0x3064, 0x006C, 0x906D, 0x606D, 0xF06C, 0xC06E, 0x506F, 0xA06F, 0x306E, 0xC06B, 0x506A, 0xA06A, 0x306B,
|
||||
0x0069, 0x9068, 0x6068, 0xF069, 0x0078, 0x9079, 0x6079, 0xF078, 0xC07A, 0x507B, 0xA07B, 0x307A, 0xC07F,
|
||||
0x507E, 0xA07E, 0x307F, 0x007D, 0x907C, 0x607C, 0xF07D, 0xC075, 0x5074, 0xA074, 0x3075, 0x0077, 0x9076,
|
||||
0x6076, 0xF077, 0x0072, 0x9073, 0x6073, 0xF072, 0xC070, 0x5071, 0xA071, 0x3070, 0x0050, 0x9051, 0x6051,
|
||||
0xF050, 0xC052, 0x5053, 0xA053, 0x3052, 0xC057, 0x5056, 0xA056, 0x3057, 0x0055, 0x9054, 0x6054, 0xF055,
|
||||
0xC05D, 0x505C, 0xA05C, 0x305D, 0x005F, 0x905E, 0x605E, 0xF05F, 0x005A, 0x905B, 0x605B, 0xF05A, 0xC058,
|
||||
0x5059, 0xA059, 0x3058, 0xC049, 0x5048, 0xA048, 0x3049, 0x004B, 0x904A, 0x604A, 0xF04B, 0x004E, 0x904F,
|
||||
0x604F, 0xF04E, 0xC04C, 0x504D, 0xA04D, 0x304C, 0x0044, 0x9045, 0x6045, 0xF044, 0xC046, 0x5047, 0xA047,
|
||||
0x3046, 0xC043, 0x5042, 0xA042, 0x3043, 0x0041, 0x9040, 0x6040, 0xF041
|
||||
},
|
||||
new ushort[]
|
||||
{
|
||||
0x0000, 0xC051, 0xC0A1, 0x00F0, 0xC141, 0x0110, 0x01E0, 0xC1B1, 0xC281, 0x02D0, 0x0220, 0xC271, 0x03C0,
|
||||
0xC391, 0xC361, 0x0330, 0xC501, 0x0550, 0x05A0, 0xC5F1, 0x0440, 0xC411, 0xC4E1, 0x04B0, 0x0780, 0xC7D1,
|
||||
0xC721, 0x0770, 0xC6C1, 0x0690, 0x0660, 0xC631, 0xCA01, 0x0A50, 0x0AA0, 0xCAF1, 0x0B40, 0xCB11, 0xCBE1,
|
||||
0x0BB0, 0x0880, 0xC8D1, 0xC821, 0x0870, 0xC9C1, 0x0990, 0x0960, 0xC931, 0x0F00, 0xCF51, 0xCFA1, 0x0FF0,
|
||||
0xCE41, 0x0E10, 0x0EE0, 0xCEB1, 0xCD81, 0x0DD0, 0x0D20, 0xCD71, 0x0CC0, 0xCC91, 0xCC61, 0x0C30, 0xD401,
|
||||
0x1450, 0x14A0, 0xD4F1, 0x1540, 0xD511, 0xD5E1, 0x15B0, 0x1680, 0xD6D1, 0xD621, 0x1670, 0xD7C1, 0x1790,
|
||||
0x1760, 0xD731, 0x1100, 0xD151, 0xD1A1, 0x11F0, 0xD041, 0x1010, 0x10E0, 0xD0B1, 0xD381, 0x13D0, 0x1320,
|
||||
0xD371, 0x12C0, 0xD291, 0xD261, 0x1230, 0x1E00, 0xDE51, 0xDEA1, 0x1EF0, 0xDF41, 0x1F10, 0x1FE0, 0xDFB1,
|
||||
0xDC81, 0x1CD0, 0x1C20, 0xDC71, 0x1DC0, 0xDD91, 0xDD61, 0x1D30, 0xDB01, 0x1B50, 0x1BA0, 0xDBF1, 0x1A40,
|
||||
0xDA11, 0xDAE1, 0x1AB0, 0x1980, 0xD9D1, 0xD921, 0x1970, 0xD8C1, 0x1890, 0x1860, 0xD831, 0xE801, 0x2850,
|
||||
0x28A0, 0xE8F1, 0x2940, 0xE911, 0xE9E1, 0x29B0, 0x2A80, 0xEAD1, 0xEA21, 0x2A70, 0xEBC1, 0x2B90, 0x2B60,
|
||||
0xEB31, 0x2D00, 0xED51, 0xEDA1, 0x2DF0, 0xEC41, 0x2C10, 0x2CE0, 0xECB1, 0xEF81, 0x2FD0, 0x2F20, 0xEF71,
|
||||
0x2EC0, 0xEE91, 0xEE61, 0x2E30, 0x2200, 0xE251, 0xE2A1, 0x22F0, 0xE341, 0x2310, 0x23E0, 0xE3B1, 0xE081,
|
||||
0x20D0, 0x2020, 0xE071, 0x21C0, 0xE191, 0xE161, 0x2130, 0xE701, 0x2750, 0x27A0, 0xE7F1, 0x2640, 0xE611,
|
||||
0xE6E1, 0x26B0, 0x2580, 0xE5D1, 0xE521, 0x2570, 0xE4C1, 0x2490, 0x2460, 0xE431, 0x3C00, 0xFC51, 0xFCA1,
|
||||
0x3CF0, 0xFD41, 0x3D10, 0x3DE0, 0xFDB1, 0xFE81, 0x3ED0, 0x3E20, 0xFE71, 0x3FC0, 0xFF91, 0xFF61, 0x3F30,
|
||||
0xF901, 0x3950, 0x39A0, 0xF9F1, 0x3840, 0xF811, 0xF8E1, 0x38B0, 0x3B80, 0xFBD1, 0xFB21, 0x3B70, 0xFAC1,
|
||||
0x3A90, 0x3A60, 0xFA31, 0xF601, 0x3650, 0x36A0, 0xF6F1, 0x3740, 0xF711, 0xF7E1, 0x37B0, 0x3480, 0xF4D1,
|
||||
0xF421, 0x3470, 0xF5C1, 0x3590, 0x3560, 0xF531, 0x3300, 0xF351, 0xF3A1, 0x33F0, 0xF241, 0x3210, 0x32E0,
|
||||
0xF2B1, 0xF181, 0x31D0, 0x3120, 0xF171, 0x30C0, 0xF091, 0xF061, 0x3030
|
||||
},
|
||||
new ushort[]
|
||||
{
|
||||
0x0000, 0xFC01, 0xB801, 0x4400, 0x3001, 0xCC00, 0x8800, 0x7401, 0x6002, 0x9C03, 0xD803, 0x2402, 0x5003,
|
||||
0xAC02, 0xE802, 0x1403, 0xC004, 0x3C05, 0x7805, 0x8404, 0xF005, 0x0C04, 0x4804, 0xB405, 0xA006, 0x5C07,
|
||||
0x1807, 0xE406, 0x9007, 0x6C06, 0x2806, 0xD407, 0xC00B, 0x3C0A, 0x780A, 0x840B, 0xF00A, 0x0C0B, 0x480B,
|
||||
0xB40A, 0xA009, 0x5C08, 0x1808, 0xE409, 0x9008, 0x6C09, 0x2809, 0xD408, 0x000F, 0xFC0E, 0xB80E, 0x440F,
|
||||
0x300E, 0xCC0F, 0x880F, 0x740E, 0x600D, 0x9C0C, 0xD80C, 0x240D, 0x500C, 0xAC0D, 0xE80D, 0x140C, 0xC015,
|
||||
0x3C14, 0x7814, 0x8415, 0xF014, 0x0C15, 0x4815, 0xB414, 0xA017, 0x5C16, 0x1816, 0xE417, 0x9016, 0x6C17,
|
||||
0x2817, 0xD416, 0x0011, 0xFC10, 0xB810, 0x4411, 0x3010, 0xCC11, 0x8811, 0x7410, 0x6013, 0x9C12, 0xD812,
|
||||
0x2413, 0x5012, 0xAC13, 0xE813, 0x1412, 0x001E, 0xFC1F, 0xB81F, 0x441E, 0x301F, 0xCC1E, 0x881E, 0x741F,
|
||||
0x601C, 0x9C1D, 0xD81D, 0x241C, 0x501D, 0xAC1C, 0xE81C, 0x141D, 0xC01A, 0x3C1B, 0x781B, 0x841A, 0xF01B,
|
||||
0x0C1A, 0x481A, 0xB41B, 0xA018, 0x5C19, 0x1819, 0xE418, 0x9019, 0x6C18, 0x2818, 0xD419, 0xC029, 0x3C28,
|
||||
0x7828, 0x8429, 0xF028, 0x0C29, 0x4829, 0xB428, 0xA02B, 0x5C2A, 0x182A, 0xE42B, 0x902A, 0x6C2B, 0x282B,
|
||||
0xD42A, 0x002D, 0xFC2C, 0xB82C, 0x442D, 0x302C, 0xCC2D, 0x882D, 0x742C, 0x602F, 0x9C2E, 0xD82E, 0x242F,
|
||||
0x502E, 0xAC2F, 0xE82F, 0x142E, 0x0022, 0xFC23, 0xB823, 0x4422, 0x3023, 0xCC22, 0x8822, 0x7423, 0x6020,
|
||||
0x9C21, 0xD821, 0x2420, 0x5021, 0xAC20, 0xE820, 0x1421, 0xC026, 0x3C27, 0x7827, 0x8426, 0xF027, 0x0C26,
|
||||
0x4826, 0xB427, 0xA024, 0x5C25, 0x1825, 0xE424, 0x9025, 0x6C24, 0x2824, 0xD425, 0x003C, 0xFC3D, 0xB83D,
|
||||
0x443C, 0x303D, 0xCC3C, 0x883C, 0x743D, 0x603E, 0x9C3F, 0xD83F, 0x243E, 0x503F, 0xAC3E, 0xE83E, 0x143F,
|
||||
0xC038, 0x3C39, 0x7839, 0x8438, 0xF039, 0x0C38, 0x4838, 0xB439, 0xA03A, 0x5C3B, 0x183B, 0xE43A, 0x903B,
|
||||
0x6C3A, 0x283A, 0xD43B, 0xC037, 0x3C36, 0x7836, 0x8437, 0xF036, 0x0C37, 0x4837, 0xB436, 0xA035, 0x5C34,
|
||||
0x1834, 0xE435, 0x9034, 0x6C35, 0x2835, 0xD434, 0x0033, 0xFC32, 0xB832, 0x4433, 0x3032, 0xCC33, 0x8833,
|
||||
0x7432, 0x6031, 0x9C30, 0xD830, 0x2431, 0x5030, 0xAC31, 0xE831, 0x1430
|
||||
},
|
||||
new ushort[]
|
||||
{
|
||||
0x0000, 0xC03D, 0xC079, 0x0044, 0xC0F1, 0x00CC, 0x0088, 0xC0B5, 0xC1E1, 0x01DC, 0x0198, 0xC1A5, 0x0110,
|
||||
0xC12D, 0xC169, 0x0154, 0xC3C1, 0x03FC, 0x03B8, 0xC385, 0x0330, 0xC30D, 0xC349, 0x0374, 0x0220, 0xC21D,
|
||||
0xC259, 0x0264, 0xC2D1, 0x02EC, 0x02A8, 0xC295, 0xC781, 0x07BC, 0x07F8, 0xC7C5, 0x0770, 0xC74D, 0xC709,
|
||||
0x0734, 0x0660, 0xC65D, 0xC619, 0x0624, 0xC691, 0x06AC, 0x06E8, 0xC6D5, 0x0440, 0xC47D, 0xC439, 0x0404,
|
||||
0xC4B1, 0x048C, 0x04C8, 0xC4F5, 0xC5A1, 0x059C, 0x05D8, 0xC5E5, 0x0550, 0xC56D, 0xC529, 0x0514, 0xCF01,
|
||||
0x0F3C, 0x0F78, 0xCF45, 0x0FF0, 0xCFCD, 0xCF89, 0x0FB4, 0x0EE0, 0xCEDD, 0xCE99, 0x0EA4, 0xCE11, 0x0E2C,
|
||||
0x0E68, 0xCE55, 0x0CC0, 0xCCFD, 0xCCB9, 0x0C84, 0xCC31, 0x0C0C, 0x0C48, 0xCC75, 0xCD21, 0x0D1C, 0x0D58,
|
||||
0xCD65, 0x0DD0, 0xCDED, 0xCDA9, 0x0D94, 0x0880, 0xC8BD, 0xC8F9, 0x08C4, 0xC871, 0x084C, 0x0808, 0xC835,
|
||||
0xC961, 0x095C, 0x0918, 0xC925, 0x0990, 0xC9AD, 0xC9E9, 0x09D4, 0xCB41, 0x0B7C, 0x0B38, 0xCB05, 0x0BB0,
|
||||
0xCB8D, 0xCBC9, 0x0BF4, 0x0AA0, 0xCA9D, 0xCAD9, 0x0AE4, 0xCA51, 0x0A6C, 0x0A28, 0xCA15, 0xDE01, 0x1E3C,
|
||||
0x1E78, 0xDE45, 0x1EF0, 0xDECD, 0xDE89, 0x1EB4, 0x1FE0, 0xDFDD, 0xDF99, 0x1FA4, 0xDF11, 0x1F2C, 0x1F68,
|
||||
0xDF55, 0x1DC0, 0xDDFD, 0xDDB9, 0x1D84, 0xDD31, 0x1D0C, 0x1D48, 0xDD75, 0xDC21, 0x1C1C, 0x1C58, 0xDC65,
|
||||
0x1CD0, 0xDCED, 0xDCA9, 0x1C94, 0x1980, 0xD9BD, 0xD9F9, 0x19C4, 0xD971, 0x194C, 0x1908, 0xD935, 0xD861,
|
||||
0x185C, 0x1818, 0xD825, 0x1890, 0xD8AD, 0xD8E9, 0x18D4, 0xDA41, 0x1A7C, 0x1A38, 0xDA05, 0x1AB0, 0xDA8D,
|
||||
0xDAC9, 0x1AF4, 0x1BA0, 0xDB9D, 0xDBD9, 0x1BE4, 0xDB51, 0x1B6C, 0x1B28, 0xDB15, 0x1100, 0xD13D, 0xD179,
|
||||
0x1144, 0xD1F1, 0x11CC, 0x1188, 0xD1B5, 0xD0E1, 0x10DC, 0x1098, 0xD0A5, 0x1010, 0xD02D, 0xD069, 0x1054,
|
||||
0xD2C1, 0x12FC, 0x12B8, 0xD285, 0x1230, 0xD20D, 0xD249, 0x1274, 0x1320, 0xD31D, 0xD359, 0x1364, 0xD3D1,
|
||||
0x13EC, 0x13A8, 0xD395, 0xD681, 0x16BC, 0x16F8, 0xD6C5, 0x1670, 0xD64D, 0xD609, 0x1634, 0x1760, 0xD75D,
|
||||
0xD719, 0x1724, 0xD791, 0x17AC, 0x17E8, 0xD7D5, 0x1540, 0xD57D, 0xD539, 0x1504, 0xD5B1, 0x158C, 0x15C8,
|
||||
0xD5F5, 0xD4A1, 0x149C, 0x14D8, 0xD4E5, 0x1450, 0xD46D, 0xD429, 0x1414
|
||||
},
|
||||
new ushort[]
|
||||
{
|
||||
0x0000, 0xD101, 0xE201, 0x3300, 0x8401, 0x5500, 0x6600, 0xB701, 0x4801, 0x9900, 0xAA00, 0x7B01, 0xCC00,
|
||||
0x1D01, 0x2E01, 0xFF00, 0x9002, 0x4103, 0x7203, 0xA302, 0x1403, 0xC502, 0xF602, 0x2703, 0xD803, 0x0902,
|
||||
0x3A02, 0xEB03, 0x5C02, 0x8D03, 0xBE03, 0x6F02, 0x6007, 0xB106, 0x8206, 0x5307, 0xE406, 0x3507, 0x0607,
|
||||
0xD706, 0x2806, 0xF907, 0xCA07, 0x1B06, 0xAC07, 0x7D06, 0x4E06, 0x9F07, 0xF005, 0x2104, 0x1204, 0xC305,
|
||||
0x7404, 0xA505, 0x9605, 0x4704, 0xB804, 0x6905, 0x5A05, 0x8B04, 0x3C05, 0xED04, 0xDE04, 0x0F05, 0xC00E,
|
||||
0x110F, 0x220F, 0xF30E, 0x440F, 0x950E, 0xA60E, 0x770F, 0x880F, 0x590E, 0x6A0E, 0xBB0F, 0x0C0E, 0xDD0F,
|
||||
0xEE0F, 0x3F0E, 0x500C, 0x810D, 0xB20D, 0x630C, 0xD40D, 0x050C, 0x360C, 0xE70D, 0x180D, 0xC90C, 0xFA0C,
|
||||
0x2B0D, 0x9C0C, 0x4D0D, 0x7E0D, 0xAF0C, 0xA009, 0x7108, 0x4208, 0x9309, 0x2408, 0xF509, 0xC609, 0x1708,
|
||||
0xE808, 0x3909, 0x0A09, 0xDB08, 0x6C09, 0xBD08, 0x8E08, 0x5F09, 0x300B, 0xE10A, 0xD20A, 0x030B, 0xB40A,
|
||||
0x650B, 0x560B, 0x870A, 0x780A, 0xA90B, 0x9A0B, 0x4B0A, 0xFC0B, 0x2D0A, 0x1E0A, 0xCF0B, 0xC01F, 0x111E,
|
||||
0x221E, 0xF31F, 0x441E, 0x951F, 0xA61F, 0x771E, 0x881E, 0x591F, 0x6A1F, 0xBB1E, 0x0C1F, 0xDD1E, 0xEE1E,
|
||||
0x3F1F, 0x501D, 0x811C, 0xB21C, 0x631D, 0xD41C, 0x051D, 0x361D, 0xE71C, 0x181C, 0xC91D, 0xFA1D, 0x2B1C,
|
||||
0x9C1D, 0x4D1C, 0x7E1C, 0xAF1D, 0xA018, 0x7119, 0x4219, 0x9318, 0x2419, 0xF518, 0xC618, 0x1719, 0xE819,
|
||||
0x3918, 0x0A18, 0xDB19, 0x6C18, 0xBD19, 0x8E19, 0x5F18, 0x301A, 0xE11B, 0xD21B, 0x031A, 0xB41B, 0x651A,
|
||||
0x561A, 0x871B, 0x781B, 0xA91A, 0x9A1A, 0x4B1B, 0xFC1A, 0x2D1B, 0x1E1B, 0xCF1A, 0x0011, 0xD110, 0xE210,
|
||||
0x3311, 0x8410, 0x5511, 0x6611, 0xB710, 0x4810, 0x9911, 0xAA11, 0x7B10, 0xCC11, 0x1D10, 0x2E10, 0xFF11,
|
||||
0x9013, 0x4112, 0x7212, 0xA313, 0x1412, 0xC513, 0xF613, 0x2712, 0xD812, 0x0913, 0x3A13, 0xEB12, 0x5C13,
|
||||
0x8D12, 0xBE12, 0x6F13, 0x6016, 0xB117, 0x8217, 0x5316, 0xE417, 0x3516, 0x0616, 0xD717, 0x2817, 0xF916,
|
||||
0xCA16, 0x1B17, 0xAC16, 0x7D17, 0x4E17, 0x9F16, 0xF014, 0x2115, 0x1215, 0xC314, 0x7415, 0xA514, 0x9614,
|
||||
0x4715, 0xB815, 0x6914, 0x5A14, 0x8B15, 0x3C14, 0xED15, 0xDE15, 0x0F14
|
||||
},
|
||||
new ushort[]
|
||||
{
|
||||
0x0000, 0xC010, 0xC023, 0x0033, 0xC045, 0x0055, 0x0066, 0xC076, 0xC089, 0x0099, 0x00AA, 0xC0BA, 0x00CC,
|
||||
0xC0DC, 0xC0EF, 0x00FF, 0xC111, 0x0101, 0x0132, 0xC122, 0x0154, 0xC144, 0xC177, 0x0167, 0x0198, 0xC188,
|
||||
0xC1BB, 0x01AB, 0xC1DD, 0x01CD, 0x01FE, 0xC1EE, 0xC221, 0x0231, 0x0202, 0xC212, 0x0264, 0xC274, 0xC247,
|
||||
0x0257, 0x02A8, 0xC2B8, 0xC28B, 0x029B, 0xC2ED, 0x02FD, 0x02CE, 0xC2DE, 0x0330, 0xC320, 0xC313, 0x0303,
|
||||
0xC375, 0x0365, 0x0356, 0xC346, 0xC3B9, 0x03A9, 0x039A, 0xC38A, 0x03FC, 0xC3EC, 0xC3DF, 0x03CF, 0xC441,
|
||||
0x0451, 0x0462, 0xC472, 0x0404, 0xC414, 0xC427, 0x0437, 0x04C8, 0xC4D8, 0xC4EB, 0x04FB, 0xC48D, 0x049D,
|
||||
0x04AE, 0xC4BE, 0x0550, 0xC540, 0xC573, 0x0563, 0xC515, 0x0505, 0x0536, 0xC526, 0xC5D9, 0x05C9, 0x05FA,
|
||||
0xC5EA, 0x059C, 0xC58C, 0xC5BF, 0x05AF, 0x0660, 0xC670, 0xC643, 0x0653, 0xC625, 0x0635, 0x0606, 0xC616,
|
||||
0xC6E9, 0x06F9, 0x06CA, 0xC6DA, 0x06AC, 0xC6BC, 0xC68F, 0x069F, 0xC771, 0x0761, 0x0752, 0xC742, 0x0734,
|
||||
0xC724, 0xC717, 0x0707, 0x07F8, 0xC7E8, 0xC7DB, 0x07CB, 0xC7BD, 0x07AD, 0x079E, 0xC78E, 0xC881, 0x0891,
|
||||
0x08A2, 0xC8B2, 0x08C4, 0xC8D4, 0xC8E7, 0x08F7, 0x0808, 0xC818, 0xC82B, 0x083B, 0xC84D, 0x085D, 0x086E,
|
||||
0xC87E, 0x0990, 0xC980, 0xC9B3, 0x09A3, 0xC9D5, 0x09C5, 0x09F6, 0xC9E6, 0xC919, 0x0909, 0x093A, 0xC92A,
|
||||
0x095C, 0xC94C, 0xC97F, 0x096F, 0x0AA0, 0xCAB0, 0xCA83, 0x0A93, 0xCAE5, 0x0AF5, 0x0AC6, 0xCAD6, 0xCA29,
|
||||
0x0A39, 0x0A0A, 0xCA1A, 0x0A6C, 0xCA7C, 0xCA4F, 0x0A5F, 0xCBB1, 0x0BA1, 0x0B92, 0xCB82, 0x0BF4, 0xCBE4,
|
||||
0xCBD7, 0x0BC7, 0x0B38, 0xCB28, 0xCB1B, 0x0B0B, 0xCB7D, 0x0B6D, 0x0B5E, 0xCB4E, 0x0CC0, 0xCCD0, 0xCCE3,
|
||||
0x0CF3, 0xCC85, 0x0C95, 0x0CA6, 0xCCB6, 0xCC49, 0x0C59, 0x0C6A, 0xCC7A, 0x0C0C, 0xCC1C, 0xCC2F, 0x0C3F,
|
||||
0xCDD1, 0x0DC1, 0x0DF2, 0xCDE2, 0x0D94, 0xCD84, 0xCDB7, 0x0DA7, 0x0D58, 0xCD48, 0xCD7B, 0x0D6B, 0xCD1D,
|
||||
0x0D0D, 0x0D3E, 0xCD2E, 0xCEE1, 0x0EF1, 0x0EC2, 0xCED2, 0x0EA4, 0xCEB4, 0xCE87, 0x0E97, 0x0E68, 0xCE78,
|
||||
0xCE4B, 0x0E5B, 0xCE2D, 0x0E3D, 0x0E0E, 0xCE1E, 0x0FF0, 0xCFE0, 0xCFD3, 0x0FC3, 0xCFB5, 0x0FA5, 0x0F96,
|
||||
0xCF86, 0xCF79, 0x0F69, 0x0F5A, 0xCF4A, 0x0F3C, 0xCF2C, 0xCF1F, 0x0F0F
|
||||
},
|
||||
new ushort[]
|
||||
{
|
||||
0x0000, 0xCCC1, 0xD981, 0x1540, 0xF301, 0x3FC0, 0x2A80, 0xE641, 0xA601, 0x6AC0, 0x7F80, 0xB341, 0x5500,
|
||||
0x99C1, 0x8C81, 0x4040, 0x0C01, 0xC0C0, 0xD580, 0x1941, 0xFF00, 0x33C1, 0x2681, 0xEA40, 0xAA00, 0x66C1,
|
||||
0x7381, 0xBF40, 0x5901, 0x95C0, 0x8080, 0x4C41, 0x1802, 0xD4C3, 0xC183, 0x0D42, 0xEB03, 0x27C2, 0x3282,
|
||||
0xFE43, 0xBE03, 0x72C2, 0x6782, 0xAB43, 0x4D02, 0x81C3, 0x9483, 0x5842, 0x1403, 0xD8C2, 0xCD82, 0x0143,
|
||||
0xE702, 0x2BC3, 0x3E83, 0xF242, 0xB202, 0x7EC3, 0x6B83, 0xA742, 0x4103, 0x8DC2, 0x9882, 0x5443, 0x3004,
|
||||
0xFCC5, 0xE985, 0x2544, 0xC305, 0x0FC4, 0x1A84, 0xD645, 0x9605, 0x5AC4, 0x4F84, 0x8345, 0x6504, 0xA9C5,
|
||||
0xBC85, 0x7044, 0x3C05, 0xF0C4, 0xE584, 0x2945, 0xCF04, 0x03C5, 0x1685, 0xDA44, 0x9A04, 0x56C5, 0x4385,
|
||||
0x8F44, 0x6905, 0xA5C4, 0xB084, 0x7C45, 0x2806, 0xE4C7, 0xF187, 0x3D46, 0xDB07, 0x17C6, 0x0286, 0xCE47,
|
||||
0x8E07, 0x42C6, 0x5786, 0x9B47, 0x7D06, 0xB1C7, 0xA487, 0x6846, 0x2407, 0xE8C6, 0xFD86, 0x3147, 0xD706,
|
||||
0x1BC7, 0x0E87, 0xC246, 0x8206, 0x4EC7, 0x5B87, 0x9746, 0x7107, 0xBDC6, 0xA886, 0x6447, 0x6008, 0xACC9,
|
||||
0xB989, 0x7548, 0x9309, 0x5FC8, 0x4A88, 0x8649, 0xC609, 0x0AC8, 0x1F88, 0xD349, 0x3508, 0xF9C9, 0xEC89,
|
||||
0x2048, 0x6C09, 0xA0C8, 0xB588, 0x7949, 0x9F08, 0x53C9, 0x4689, 0x8A48, 0xCA08, 0x06C9, 0x1389, 0xDF48,
|
||||
0x3909, 0xF5C8, 0xE088, 0x2C49, 0x780A, 0xB4CB, 0xA18B, 0x6D4A, 0x8B0B, 0x47CA, 0x528A, 0x9E4B, 0xDE0B,
|
||||
0x12CA, 0x078A, 0xCB4B, 0x2D0A, 0xE1CB, 0xF48B, 0x384A, 0x740B, 0xB8CA, 0xAD8A, 0x614B, 0x870A, 0x4BCB,
|
||||
0x5E8B, 0x924A, 0xD20A, 0x1ECB, 0x0B8B, 0xC74A, 0x210B, 0xEDCA, 0xF88A, 0x344B, 0x500C, 0x9CCD, 0x898D,
|
||||
0x454C, 0xA30D, 0x6FCC, 0x7A8C, 0xB64D, 0xF60D, 0x3ACC, 0x2F8C, 0xE34D, 0x050C, 0xC9CD, 0xDC8D, 0x104C,
|
||||
0x5C0D, 0x90CC, 0x858C, 0x494D, 0xAF0C, 0x63CD, 0x768D, 0xBA4C, 0xFA0C, 0x36CD, 0x238D, 0xEF4C, 0x090D,
|
||||
0xC5CC, 0xD08C, 0x1C4D, 0x480E, 0x84CF, 0x918F, 0x5D4E, 0xBB0F, 0x77CE, 0x628E, 0xAE4F, 0xEE0F, 0x22CE,
|
||||
0x378E, 0xFB4F, 0x1D0E, 0xD1CF, 0xC48F, 0x084E, 0x440F, 0x88CE, 0x9D8E, 0x514F, 0xB70E, 0x7BCF, 0x6E8F,
|
||||
0xA24E, 0xE20E, 0x2ECF, 0x3B8F, 0xF74E, 0x110F, 0xDDCE, 0xC88E, 0x044F
|
||||
}
|
||||
};
|
||||
|
||||
/// <summary>Initializes an instance of the CRC16 with IBM polynomial and seed.</summary>
|
||||
/// <inheritdoc />
|
||||
public CRC16IbmContext() : base(CRC16_IBM_POLY, CRC16_IBM_SEED, _ibmCrc16Table, false) {}
|
||||
|
||||
/// <inheritdoc />
|
||||
public new string Name => "CRC-16 (IBM)";
|
||||
|
||||
/// <inheritdoc />
|
||||
public new Guid Id => new("0470433E-0C78-4C37-8C9F-BD8E72340E78");
|
||||
|
||||
/// <inheritdoc />
|
||||
public new string Author => "Natalia Portillo";
|
||||
|
||||
/// <summary>Gets the hash of a file</summary>
|
||||
/// <param name="filename">File path.</param>
|
||||
// ReSharper disable once ReturnTypeCanBeEnumerable.Global
|
||||
public static byte[] File(string filename)
|
||||
{
|
||||
File(filename, out byte[] hash);
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
|
||||
/// <param name="filename">File path.</param>
|
||||
/// <param name="hash">Byte array of the hash value.</param>
|
||||
public static string File(string filename, out byte[] hash) =>
|
||||
File(filename, out hash, CRC16_IBM_POLY, CRC16_IBM_SEED, _ibmCrc16Table, false);
|
||||
|
||||
/// <summary>Gets the hash of the specified data buffer.</summary>
|
||||
/// <param name="data">Data buffer.</param>
|
||||
/// <param name="len">Length of the data buffer to hash.</param>
|
||||
/// <param name="hash">Byte array of the hash value.</param>
|
||||
public static string Data(byte[] data, uint len, out byte[] hash) =>
|
||||
Data(data, len, out hash, CRC16_IBM_POLY, CRC16_IBM_SEED, _ibmCrc16Table, false);
|
||||
|
||||
/// <summary>Gets the hash of the specified data buffer.</summary>
|
||||
/// <param name="data">Data buffer.</param>
|
||||
/// <param name="hash">Byte array of the hash value.</param>
|
||||
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
|
||||
}
|
||||
@@ -1,136 +0,0 @@
|
||||
// /***************************************************************************
|
||||
// Aaru Data Preservation Suite
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : arm_simd.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
// The Chromium Authors
|
||||
//
|
||||
// Component : Checksums.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Compute CRC32 checksum using ARM special instructions..
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2023 Natalia Portillo
|
||||
// Copyright 2017 The Chromium Authors. All rights reserved.
|
||||
// ****************************************************************************/
|
||||
|
||||
#if NET5_0_OR_GREATER
|
||||
using System;
|
||||
using System.Runtime.Intrinsics.Arm;
|
||||
|
||||
namespace Aaru.Checksums.CRC32;
|
||||
|
||||
static class ArmSimd
|
||||
{
|
||||
internal static uint Step64(byte[] buf, long len, uint crc)
|
||||
{
|
||||
uint c = crc;
|
||||
|
||||
var bufPos = 0;
|
||||
|
||||
while(len >= 64)
|
||||
{
|
||||
c = Crc32.Arm64.ComputeCrc32(c, BitConverter.ToUInt64(buf, bufPos));
|
||||
bufPos += 8;
|
||||
c = Crc32.Arm64.ComputeCrc32(c, BitConverter.ToUInt64(buf, bufPos));
|
||||
bufPos += 8;
|
||||
c = Crc32.Arm64.ComputeCrc32(c, BitConverter.ToUInt64(buf, bufPos));
|
||||
bufPos += 8;
|
||||
c = Crc32.Arm64.ComputeCrc32(c, BitConverter.ToUInt64(buf, bufPos));
|
||||
bufPos += 8;
|
||||
c = Crc32.Arm64.ComputeCrc32(c, BitConverter.ToUInt64(buf, bufPos));
|
||||
bufPos += 8;
|
||||
c = Crc32.Arm64.ComputeCrc32(c, BitConverter.ToUInt64(buf, bufPos));
|
||||
bufPos += 8;
|
||||
c = Crc32.Arm64.ComputeCrc32(c, BitConverter.ToUInt64(buf, bufPos));
|
||||
bufPos += 8;
|
||||
c = Crc32.Arm64.ComputeCrc32(c, BitConverter.ToUInt64(buf, bufPos));
|
||||
bufPos += 8;
|
||||
len -= 64;
|
||||
}
|
||||
|
||||
while(len >= 8)
|
||||
{
|
||||
c = Crc32.Arm64.ComputeCrc32(c, BitConverter.ToUInt64(buf, bufPos));
|
||||
bufPos += 8;
|
||||
len -= 8;
|
||||
}
|
||||
|
||||
while(len-- > 0)
|
||||
c = Crc32.ComputeCrc32(c, buf[bufPos++]);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
internal static uint Step32(byte[] buf, long len, uint crc)
|
||||
{
|
||||
uint c = crc;
|
||||
|
||||
var bufPos = 0;
|
||||
|
||||
while(len >= 32)
|
||||
{
|
||||
c = Crc32.ComputeCrc32(c, BitConverter.ToUInt32(buf, bufPos));
|
||||
bufPos += 4;
|
||||
c = Crc32.ComputeCrc32(c, BitConverter.ToUInt32(buf, bufPos));
|
||||
bufPos += 4;
|
||||
c = Crc32.ComputeCrc32(c, BitConverter.ToUInt32(buf, bufPos));
|
||||
bufPos += 4;
|
||||
c = Crc32.ComputeCrc32(c, BitConverter.ToUInt32(buf, bufPos));
|
||||
bufPos += 4;
|
||||
c = Crc32.ComputeCrc32(c, BitConverter.ToUInt32(buf, bufPos));
|
||||
bufPos += 4;
|
||||
c = Crc32.ComputeCrc32(c, BitConverter.ToUInt32(buf, bufPos));
|
||||
bufPos += 4;
|
||||
c = Crc32.ComputeCrc32(c, BitConverter.ToUInt32(buf, bufPos));
|
||||
bufPos += 4;
|
||||
c = Crc32.ComputeCrc32(c, BitConverter.ToUInt32(buf, bufPos));
|
||||
bufPos += 4;
|
||||
len -= 32;
|
||||
}
|
||||
|
||||
while(len >= 4)
|
||||
{
|
||||
c = Crc32.ComputeCrc32(c, BitConverter.ToUInt32(buf, bufPos));
|
||||
bufPos += 4;
|
||||
len -= 4;
|
||||
}
|
||||
|
||||
while(len-- > 0)
|
||||
c = Crc32.ComputeCrc32(c, buf[bufPos++]);
|
||||
|
||||
return c;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,227 +0,0 @@
|
||||
// /***************************************************************************
|
||||
// Aaru Data Preservation Suite
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : clmul.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
// Wajdi Feghali <wajdi.k.feghali@intel.com>
|
||||
// Jim Guilford <james.guilford@intel.com>
|
||||
// Vinodh Gopal <vinodh.gopal@intel.com>
|
||||
// Erdinc Ozturk <erdinc.ozturk@intel.com>
|
||||
// Jim Kukunas <james.t.kukunas@linux.intel.com>
|
||||
// Marian Beermann
|
||||
//
|
||||
// Component : Checksums.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Compute the CRC32 using a parallelized folding approach with the PCLMULQDQ
|
||||
// instruction.
|
||||
//
|
||||
// A white paper describing this algorithm can be found at:
|
||||
// http://www.intel.com/content/dam/www/public/us/en/documents/white-papers/fast-crc-computation-generic-polynomials-pclmulqdq-paper.pdf
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from
|
||||
// the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2023 Natalia Portillo
|
||||
// Copyright (c) 2016 Marian Beermann (add support for initial value, restructuring)
|
||||
// Copyright (C) 2013 Intel Corporation. All rights reserved.
|
||||
// ****************************************************************************/
|
||||
|
||||
#if NETCOREAPP3_1_OR_GREATER
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.Intrinsics;
|
||||
using System.Runtime.Intrinsics.X86;
|
||||
|
||||
namespace Aaru.Checksums.CRC32;
|
||||
|
||||
static class Clmul
|
||||
{
|
||||
static readonly uint[] _crcK =
|
||||
{
|
||||
0xccaa009e, 0x00000000, /* rk1 */ 0x751997d0, 0x00000001, /* rk2 */ 0xccaa009e, 0x00000000, /* rk5 */
|
||||
0x63cd6124, 0x00000001, /* rk6 */ 0xf7011640, 0x00000001, /* rk7 */ 0xdb710640, 0x00000001 /* rk8 */
|
||||
};
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
static void Fold4(ref Vector128<uint> xmmCRC0, ref Vector128<uint> xmmCRC1, ref Vector128<uint> xmmCRC2,
|
||||
ref Vector128<uint> xmmCRC3)
|
||||
{
|
||||
var xmmFold4 = Vector128.Create(0xc6e41596, 0x00000001, 0x54442bd4, 0x00000001);
|
||||
|
||||
Vector128<uint> xTmp0 = xmmCRC0;
|
||||
Vector128<uint> xTmp1 = xmmCRC1;
|
||||
Vector128<uint> xTmp2 = xmmCRC2;
|
||||
Vector128<uint> xTmp3 = xmmCRC3;
|
||||
|
||||
xmmCRC0 = Pclmulqdq.CarrylessMultiply(xmmCRC0.AsUInt64(), xmmFold4.AsUInt64(), 0x01).AsUInt32();
|
||||
xTmp0 = Pclmulqdq.CarrylessMultiply(xTmp0.AsUInt64(), xmmFold4.AsUInt64(), 0x10).AsUInt32();
|
||||
Vector128<float> psCRC0 = xmmCRC0.AsSingle();
|
||||
Vector128<float> psT0 = xTmp0.AsSingle();
|
||||
Vector128<float> psRes0 = Sse.Xor(psCRC0, psT0);
|
||||
|
||||
xmmCRC1 = Pclmulqdq.CarrylessMultiply(xmmCRC1.AsUInt64(), xmmFold4.AsUInt64(), 0x01).AsUInt32();
|
||||
xTmp1 = Pclmulqdq.CarrylessMultiply(xTmp1.AsUInt64(), xmmFold4.AsUInt64(), 0x10).AsUInt32();
|
||||
Vector128<float> psCRC1 = xmmCRC1.AsSingle();
|
||||
Vector128<float> psT1 = xTmp1.AsSingle();
|
||||
Vector128<float> psRes1 = Sse.Xor(psCRC1, psT1);
|
||||
|
||||
xmmCRC2 = Pclmulqdq.CarrylessMultiply(xmmCRC2.AsUInt64(), xmmFold4.AsUInt64(), 0x01).AsUInt32();
|
||||
xTmp2 = Pclmulqdq.CarrylessMultiply(xTmp2.AsUInt64(), xmmFold4.AsUInt64(), 0x10).AsUInt32();
|
||||
Vector128<float> psCRC2 = xmmCRC2.AsSingle();
|
||||
Vector128<float> psT2 = xTmp2.AsSingle();
|
||||
Vector128<float> psRes2 = Sse.Xor(psCRC2, psT2);
|
||||
|
||||
xmmCRC3 = Pclmulqdq.CarrylessMultiply(xmmCRC3.AsUInt64(), xmmFold4.AsUInt64(), 0x01).AsUInt32();
|
||||
xTmp3 = Pclmulqdq.CarrylessMultiply(xTmp3.AsUInt64(), xmmFold4.AsUInt64(), 0x10).AsUInt32();
|
||||
Vector128<float> psCRC3 = xmmCRC3.AsSingle();
|
||||
Vector128<float> psT3 = xTmp3.AsSingle();
|
||||
Vector128<float> psRes3 = Sse.Xor(psCRC3, psT3);
|
||||
|
||||
xmmCRC0 = psRes0.AsUInt32();
|
||||
xmmCRC1 = psRes1.AsUInt32();
|
||||
xmmCRC2 = psRes2.AsUInt32();
|
||||
xmmCRC3 = psRes3.AsUInt32();
|
||||
}
|
||||
|
||||
internal static uint Step(byte[] src, long len, uint initialCRC)
|
||||
{
|
||||
Vector128<uint> xmmInitial = Sse2.ConvertScalarToVector128UInt32(initialCRC);
|
||||
Vector128<uint> xmmCRC0 = Sse2.ConvertScalarToVector128UInt32(0x9db42487);
|
||||
Vector128<uint> xmmCRC1 = Vector128<uint>.Zero;
|
||||
Vector128<uint> xmmCRC2 = Vector128<uint>.Zero;
|
||||
Vector128<uint> xmmCRC3 = Vector128<uint>.Zero;
|
||||
var bufPos = 0;
|
||||
|
||||
var first = true;
|
||||
|
||||
/* fold 512 to 32 step variable declarations for ISO-C90 compat. */
|
||||
var xmmMask = Vector128.Create(0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000);
|
||||
var xmmMask2 = Vector128.Create(0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF);
|
||||
|
||||
while((len -= 64) >= 0)
|
||||
{
|
||||
var xmmT0 = Vector128.Create(BitConverter.ToUInt32(src, bufPos), BitConverter.ToUInt32(src, bufPos + 4),
|
||||
BitConverter.ToUInt32(src, bufPos + 8),
|
||||
BitConverter.ToUInt32(src, bufPos + 12));
|
||||
|
||||
bufPos += 16;
|
||||
|
||||
var xmmT1 = Vector128.Create(BitConverter.ToUInt32(src, bufPos), BitConverter.ToUInt32(src, bufPos + 4),
|
||||
BitConverter.ToUInt32(src, bufPos + 8),
|
||||
BitConverter.ToUInt32(src, bufPos + 12));
|
||||
|
||||
bufPos += 16;
|
||||
|
||||
var xmmT2 = Vector128.Create(BitConverter.ToUInt32(src, bufPos), BitConverter.ToUInt32(src, bufPos + 4),
|
||||
BitConverter.ToUInt32(src, bufPos + 8),
|
||||
BitConverter.ToUInt32(src, bufPos + 12));
|
||||
|
||||
bufPos += 16;
|
||||
|
||||
var xmmT3 = Vector128.Create(BitConverter.ToUInt32(src, bufPos), BitConverter.ToUInt32(src, bufPos + 4),
|
||||
BitConverter.ToUInt32(src, bufPos + 8),
|
||||
BitConverter.ToUInt32(src, bufPos + 12));
|
||||
|
||||
bufPos += 16;
|
||||
|
||||
if(first)
|
||||
{
|
||||
first = false;
|
||||
xmmT0 = Sse2.Xor(xmmT0, xmmInitial);
|
||||
}
|
||||
|
||||
Fold4(ref xmmCRC0, ref xmmCRC1, ref xmmCRC2, ref xmmCRC3);
|
||||
|
||||
xmmCRC0 = Sse2.Xor(xmmCRC0, xmmT0);
|
||||
xmmCRC1 = Sse2.Xor(xmmCRC1, xmmT1);
|
||||
xmmCRC2 = Sse2.Xor(xmmCRC2, xmmT2);
|
||||
xmmCRC3 = Sse2.Xor(xmmCRC3, xmmT3);
|
||||
}
|
||||
|
||||
/* fold 512 to 32 */
|
||||
|
||||
/*
|
||||
* k1
|
||||
*/
|
||||
var crcFold = Vector128.Create(_crcK[0], _crcK[1], _crcK[2], _crcK[3]);
|
||||
|
||||
Vector128<uint> xTmp0 = Pclmulqdq.CarrylessMultiply(xmmCRC0.AsUInt64(), crcFold.AsUInt64(), 0x10).AsUInt32();
|
||||
|
||||
xmmCRC0 = Pclmulqdq.CarrylessMultiply(xmmCRC0.AsUInt64(), crcFold.AsUInt64(), 0x01).AsUInt32();
|
||||
xmmCRC1 = Sse2.Xor(xmmCRC1, xTmp0);
|
||||
xmmCRC1 = Sse2.Xor(xmmCRC1, xmmCRC0);
|
||||
|
||||
Vector128<uint> xTmp1 = Pclmulqdq.CarrylessMultiply(xmmCRC1.AsUInt64(), crcFold.AsUInt64(), 0x10).AsUInt32();
|
||||
|
||||
xmmCRC1 = Pclmulqdq.CarrylessMultiply(xmmCRC1.AsUInt64(), crcFold.AsUInt64(), 0x01).AsUInt32();
|
||||
xmmCRC2 = Sse2.Xor(xmmCRC2, xTmp1);
|
||||
xmmCRC2 = Sse2.Xor(xmmCRC2, xmmCRC1);
|
||||
|
||||
Vector128<uint> xTmp2 = Pclmulqdq.CarrylessMultiply(xmmCRC2.AsUInt64(), crcFold.AsUInt64(), 0x10).AsUInt32();
|
||||
|
||||
xmmCRC2 = Pclmulqdq.CarrylessMultiply(xmmCRC2.AsUInt64(), crcFold.AsUInt64(), 0x01).AsUInt32();
|
||||
xmmCRC3 = Sse2.Xor(xmmCRC3, xTmp2);
|
||||
xmmCRC3 = Sse2.Xor(xmmCRC3, xmmCRC2);
|
||||
|
||||
/*
|
||||
* k5
|
||||
*/
|
||||
crcFold = Vector128.Create(_crcK[4], _crcK[5], _crcK[6], _crcK[7]);
|
||||
|
||||
xmmCRC0 = xmmCRC3;
|
||||
xmmCRC3 = Pclmulqdq.CarrylessMultiply(xmmCRC3.AsUInt64(), crcFold.AsUInt64(), 0).AsUInt32();
|
||||
xmmCRC0 = Sse2.ShiftRightLogical128BitLane(xmmCRC0, 8);
|
||||
xmmCRC3 = Sse2.Xor(xmmCRC3, xmmCRC0);
|
||||
|
||||
xmmCRC0 = xmmCRC3;
|
||||
xmmCRC3 = Sse2.ShiftLeftLogical128BitLane(xmmCRC3, 4);
|
||||
xmmCRC3 = Pclmulqdq.CarrylessMultiply(xmmCRC3.AsUInt64(), crcFold.AsUInt64(), 0x10).AsUInt32();
|
||||
xmmCRC3 = Sse2.Xor(xmmCRC3, xmmCRC0);
|
||||
xmmCRC3 = Sse2.And(xmmCRC3, xmmMask2);
|
||||
|
||||
/*
|
||||
* k7
|
||||
*/
|
||||
xmmCRC1 = xmmCRC3;
|
||||
xmmCRC2 = xmmCRC3;
|
||||
crcFold = Vector128.Create(_crcK[8], _crcK[9], _crcK[10], _crcK[11]);
|
||||
|
||||
xmmCRC3 = Pclmulqdq.CarrylessMultiply(xmmCRC3.AsUInt64(), crcFold.AsUInt64(), 0).AsUInt32();
|
||||
xmmCRC3 = Sse2.Xor(xmmCRC3, xmmCRC2);
|
||||
xmmCRC3 = Sse2.And(xmmCRC3, xmmMask);
|
||||
|
||||
xmmCRC2 = xmmCRC3;
|
||||
xmmCRC3 = Pclmulqdq.CarrylessMultiply(xmmCRC3.AsUInt64(), crcFold.AsUInt64(), 0x10).AsUInt32();
|
||||
xmmCRC3 = Sse2.Xor(xmmCRC3, xmmCRC2);
|
||||
xmmCRC3 = Sse2.Xor(xmmCRC3, xmmCRC1);
|
||||
|
||||
/*
|
||||
* could just as well write xmm_crc3[2], doing a movaps and truncating, but
|
||||
* no real advantage - it's a tiny bit slower per call, while no additional CPUs
|
||||
* would be supported by only requiring SSSE3 and CLMUL instead of SSE4.1 + CLMUL
|
||||
*/
|
||||
return ~Sse41.Extract(xmmCRC3, 2);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,671 +0,0 @@
|
||||
// /***************************************************************************
|
||||
// Aaru Data Preservation Suite
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : CRC32Context.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Checksums.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Implements a CRC32 algorithm.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2023 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
#if NET5_0_OR_GREATER
|
||||
using System.Runtime.Intrinsics.Arm;
|
||||
#endif
|
||||
#if NETCOREAPP3_1_OR_GREATER
|
||||
using System.Runtime.Intrinsics.X86;
|
||||
#endif
|
||||
using System.Text;
|
||||
#if NETCOREAPP3_1_OR_GREATER
|
||||
using Aaru.Checksums.CRC32;
|
||||
#endif
|
||||
using Aaru.CommonTypes.Interfaces;
|
||||
using Aaru.Helpers;
|
||||
|
||||
namespace Aaru.Checksums;
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>Implements a CRC32 algorithm</summary>
|
||||
[SuppressMessage("ReSharper", "UnusedMember.Global")]
|
||||
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
|
||||
[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")]
|
||||
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
|
||||
public sealed class Crc32Context : IChecksum
|
||||
{
|
||||
const uint CRC32_ISO_POLY = 0xEDB88320;
|
||||
const uint CRC32_ISO_SEED = 0xFFFFFFFF;
|
||||
|
||||
internal static readonly uint[][] ISOCrc32Table =
|
||||
{
|
||||
new uint[]
|
||||
{
|
||||
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832,
|
||||
0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
|
||||
0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A,
|
||||
0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
|
||||
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3,
|
||||
0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
|
||||
0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
|
||||
0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
|
||||
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4,
|
||||
0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
|
||||
0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074,
|
||||
0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
|
||||
0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525,
|
||||
0x206F85B3, 0xB966D409, 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
|
||||
0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
|
||||
0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
|
||||
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76,
|
||||
0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
|
||||
0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6,
|
||||
0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
|
||||
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7,
|
||||
0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
|
||||
0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7,
|
||||
0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
|
||||
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278,
|
||||
0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
|
||||
0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330,
|
||||
0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
|
||||
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
|
||||
},
|
||||
new uint[]
|
||||
{
|
||||
0x00000000, 0x191B3141, 0x32366282, 0x2B2D53C3, 0x646CC504, 0x7D77F445, 0x565AA786, 0x4F4196C7, 0xC8D98A08,
|
||||
0xD1C2BB49, 0xFAEFE88A, 0xE3F4D9CB, 0xACB54F0C, 0xB5AE7E4D, 0x9E832D8E, 0x87981CCF, 0x4AC21251, 0x53D92310,
|
||||
0x78F470D3, 0x61EF4192, 0x2EAED755, 0x37B5E614, 0x1C98B5D7, 0x05838496, 0x821B9859, 0x9B00A918, 0xB02DFADB,
|
||||
0xA936CB9A, 0xE6775D5D, 0xFF6C6C1C, 0xD4413FDF, 0xCD5A0E9E, 0x958424A2, 0x8C9F15E3, 0xA7B24620, 0xBEA97761,
|
||||
0xF1E8E1A6, 0xE8F3D0E7, 0xC3DE8324, 0xDAC5B265, 0x5D5DAEAA, 0x44469FEB, 0x6F6BCC28, 0x7670FD69, 0x39316BAE,
|
||||
0x202A5AEF, 0x0B07092C, 0x121C386D, 0xDF4636F3, 0xC65D07B2, 0xED705471, 0xF46B6530, 0xBB2AF3F7, 0xA231C2B6,
|
||||
0x891C9175, 0x9007A034, 0x179FBCFB, 0x0E848DBA, 0x25A9DE79, 0x3CB2EF38, 0x73F379FF, 0x6AE848BE, 0x41C51B7D,
|
||||
0x58DE2A3C, 0xF0794F05, 0xE9627E44, 0xC24F2D87, 0xDB541CC6, 0x94158A01, 0x8D0EBB40, 0xA623E883, 0xBF38D9C2,
|
||||
0x38A0C50D, 0x21BBF44C, 0x0A96A78F, 0x138D96CE, 0x5CCC0009, 0x45D73148, 0x6EFA628B, 0x77E153CA, 0xBABB5D54,
|
||||
0xA3A06C15, 0x888D3FD6, 0x91960E97, 0xDED79850, 0xC7CCA911, 0xECE1FAD2, 0xF5FACB93, 0x7262D75C, 0x6B79E61D,
|
||||
0x4054B5DE, 0x594F849F, 0x160E1258, 0x0F152319, 0x243870DA, 0x3D23419B, 0x65FD6BA7, 0x7CE65AE6, 0x57CB0925,
|
||||
0x4ED03864, 0x0191AEA3, 0x188A9FE2, 0x33A7CC21, 0x2ABCFD60, 0xAD24E1AF, 0xB43FD0EE, 0x9F12832D, 0x8609B26C,
|
||||
0xC94824AB, 0xD05315EA, 0xFB7E4629, 0xE2657768, 0x2F3F79F6, 0x362448B7, 0x1D091B74, 0x04122A35, 0x4B53BCF2,
|
||||
0x52488DB3, 0x7965DE70, 0x607EEF31, 0xE7E6F3FE, 0xFEFDC2BF, 0xD5D0917C, 0xCCCBA03D, 0x838A36FA, 0x9A9107BB,
|
||||
0xB1BC5478, 0xA8A76539, 0x3B83984B, 0x2298A90A, 0x09B5FAC9, 0x10AECB88, 0x5FEF5D4F, 0x46F46C0E, 0x6DD93FCD,
|
||||
0x74C20E8C, 0xF35A1243, 0xEA412302, 0xC16C70C1, 0xD8774180, 0x9736D747, 0x8E2DE606, 0xA500B5C5, 0xBC1B8484,
|
||||
0x71418A1A, 0x685ABB5B, 0x4377E898, 0x5A6CD9D9, 0x152D4F1E, 0x0C367E5F, 0x271B2D9C, 0x3E001CDD, 0xB9980012,
|
||||
0xA0833153, 0x8BAE6290, 0x92B553D1, 0xDDF4C516, 0xC4EFF457, 0xEFC2A794, 0xF6D996D5, 0xAE07BCE9, 0xB71C8DA8,
|
||||
0x9C31DE6B, 0x852AEF2A, 0xCA6B79ED, 0xD37048AC, 0xF85D1B6F, 0xE1462A2E, 0x66DE36E1, 0x7FC507A0, 0x54E85463,
|
||||
0x4DF36522, 0x02B2F3E5, 0x1BA9C2A4, 0x30849167, 0x299FA026, 0xE4C5AEB8, 0xFDDE9FF9, 0xD6F3CC3A, 0xCFE8FD7B,
|
||||
0x80A96BBC, 0x99B25AFD, 0xB29F093E, 0xAB84387F, 0x2C1C24B0, 0x350715F1, 0x1E2A4632, 0x07317773, 0x4870E1B4,
|
||||
0x516BD0F5, 0x7A468336, 0x635DB277, 0xCBFAD74E, 0xD2E1E60F, 0xF9CCB5CC, 0xE0D7848D, 0xAF96124A, 0xB68D230B,
|
||||
0x9DA070C8, 0x84BB4189, 0x03235D46, 0x1A386C07, 0x31153FC4, 0x280E0E85, 0x674F9842, 0x7E54A903, 0x5579FAC0,
|
||||
0x4C62CB81, 0x8138C51F, 0x9823F45E, 0xB30EA79D, 0xAA1596DC, 0xE554001B, 0xFC4F315A, 0xD7626299, 0xCE7953D8,
|
||||
0x49E14F17, 0x50FA7E56, 0x7BD72D95, 0x62CC1CD4, 0x2D8D8A13, 0x3496BB52, 0x1FBBE891, 0x06A0D9D0, 0x5E7EF3EC,
|
||||
0x4765C2AD, 0x6C48916E, 0x7553A02F, 0x3A1236E8, 0x230907A9, 0x0824546A, 0x113F652B, 0x96A779E4, 0x8FBC48A5,
|
||||
0xA4911B66, 0xBD8A2A27, 0xF2CBBCE0, 0xEBD08DA1, 0xC0FDDE62, 0xD9E6EF23, 0x14BCE1BD, 0x0DA7D0FC, 0x268A833F,
|
||||
0x3F91B27E, 0x70D024B9, 0x69CB15F8, 0x42E6463B, 0x5BFD777A, 0xDC656BB5, 0xC57E5AF4, 0xEE530937, 0xF7483876,
|
||||
0xB809AEB1, 0xA1129FF0, 0x8A3FCC33, 0x9324FD72
|
||||
},
|
||||
new uint[]
|
||||
{
|
||||
0x00000000, 0x01C26A37, 0x0384D46E, 0x0246BE59, 0x0709A8DC, 0x06CBC2EB, 0x048D7CB2, 0x054F1685, 0x0E1351B8,
|
||||
0x0FD13B8F, 0x0D9785D6, 0x0C55EFE1, 0x091AF964, 0x08D89353, 0x0A9E2D0A, 0x0B5C473D, 0x1C26A370, 0x1DE4C947,
|
||||
0x1FA2771E, 0x1E601D29, 0x1B2F0BAC, 0x1AED619B, 0x18ABDFC2, 0x1969B5F5, 0x1235F2C8, 0x13F798FF, 0x11B126A6,
|
||||
0x10734C91, 0x153C5A14, 0x14FE3023, 0x16B88E7A, 0x177AE44D, 0x384D46E0, 0x398F2CD7, 0x3BC9928E, 0x3A0BF8B9,
|
||||
0x3F44EE3C, 0x3E86840B, 0x3CC03A52, 0x3D025065, 0x365E1758, 0x379C7D6F, 0x35DAC336, 0x3418A901, 0x3157BF84,
|
||||
0x3095D5B3, 0x32D36BEA, 0x331101DD, 0x246BE590, 0x25A98FA7, 0x27EF31FE, 0x262D5BC9, 0x23624D4C, 0x22A0277B,
|
||||
0x20E69922, 0x2124F315, 0x2A78B428, 0x2BBADE1F, 0x29FC6046, 0x283E0A71, 0x2D711CF4, 0x2CB376C3, 0x2EF5C89A,
|
||||
0x2F37A2AD, 0x709A8DC0, 0x7158E7F7, 0x731E59AE, 0x72DC3399, 0x7793251C, 0x76514F2B, 0x7417F172, 0x75D59B45,
|
||||
0x7E89DC78, 0x7F4BB64F, 0x7D0D0816, 0x7CCF6221, 0x798074A4, 0x78421E93, 0x7A04A0CA, 0x7BC6CAFD, 0x6CBC2EB0,
|
||||
0x6D7E4487, 0x6F38FADE, 0x6EFA90E9, 0x6BB5866C, 0x6A77EC5B, 0x68315202, 0x69F33835, 0x62AF7F08, 0x636D153F,
|
||||
0x612BAB66, 0x60E9C151, 0x65A6D7D4, 0x6464BDE3, 0x662203BA, 0x67E0698D, 0x48D7CB20, 0x4915A117, 0x4B531F4E,
|
||||
0x4A917579, 0x4FDE63FC, 0x4E1C09CB, 0x4C5AB792, 0x4D98DDA5, 0x46C49A98, 0x4706F0AF, 0x45404EF6, 0x448224C1,
|
||||
0x41CD3244, 0x400F5873, 0x4249E62A, 0x438B8C1D, 0x54F16850, 0x55330267, 0x5775BC3E, 0x56B7D609, 0x53F8C08C,
|
||||
0x523AAABB, 0x507C14E2, 0x51BE7ED5, 0x5AE239E8, 0x5B2053DF, 0x5966ED86, 0x58A487B1, 0x5DEB9134, 0x5C29FB03,
|
||||
0x5E6F455A, 0x5FAD2F6D, 0xE1351B80, 0xE0F771B7, 0xE2B1CFEE, 0xE373A5D9, 0xE63CB35C, 0xE7FED96B, 0xE5B86732,
|
||||
0xE47A0D05, 0xEF264A38, 0xEEE4200F, 0xECA29E56, 0xED60F461, 0xE82FE2E4, 0xE9ED88D3, 0xEBAB368A, 0xEA695CBD,
|
||||
0xFD13B8F0, 0xFCD1D2C7, 0xFE976C9E, 0xFF5506A9, 0xFA1A102C, 0xFBD87A1B, 0xF99EC442, 0xF85CAE75, 0xF300E948,
|
||||
0xF2C2837F, 0xF0843D26, 0xF1465711, 0xF4094194, 0xF5CB2BA3, 0xF78D95FA, 0xF64FFFCD, 0xD9785D60, 0xD8BA3757,
|
||||
0xDAFC890E, 0xDB3EE339, 0xDE71F5BC, 0xDFB39F8B, 0xDDF521D2, 0xDC374BE5, 0xD76B0CD8, 0xD6A966EF, 0xD4EFD8B6,
|
||||
0xD52DB281, 0xD062A404, 0xD1A0CE33, 0xD3E6706A, 0xD2241A5D, 0xC55EFE10, 0xC49C9427, 0xC6DA2A7E, 0xC7184049,
|
||||
0xC25756CC, 0xC3953CFB, 0xC1D382A2, 0xC011E895, 0xCB4DAFA8, 0xCA8FC59F, 0xC8C97BC6, 0xC90B11F1, 0xCC440774,
|
||||
0xCD866D43, 0xCFC0D31A, 0xCE02B92D, 0x91AF9640, 0x906DFC77, 0x922B422E, 0x93E92819, 0x96A63E9C, 0x976454AB,
|
||||
0x9522EAF2, 0x94E080C5, 0x9FBCC7F8, 0x9E7EADCF, 0x9C381396, 0x9DFA79A1, 0x98B56F24, 0x99770513, 0x9B31BB4A,
|
||||
0x9AF3D17D, 0x8D893530, 0x8C4B5F07, 0x8E0DE15E, 0x8FCF8B69, 0x8A809DEC, 0x8B42F7DB, 0x89044982, 0x88C623B5,
|
||||
0x839A6488, 0x82580EBF, 0x801EB0E6, 0x81DCDAD1, 0x8493CC54, 0x8551A663, 0x8717183A, 0x86D5720D, 0xA9E2D0A0,
|
||||
0xA820BA97, 0xAA6604CE, 0xABA46EF9, 0xAEEB787C, 0xAF29124B, 0xAD6FAC12, 0xACADC625, 0xA7F18118, 0xA633EB2F,
|
||||
0xA4755576, 0xA5B73F41, 0xA0F829C4, 0xA13A43F3, 0xA37CFDAA, 0xA2BE979D, 0xB5C473D0, 0xB40619E7, 0xB640A7BE,
|
||||
0xB782CD89, 0xB2CDDB0C, 0xB30FB13B, 0xB1490F62, 0xB08B6555, 0xBBD72268, 0xBA15485F, 0xB853F606, 0xB9919C31,
|
||||
0xBCDE8AB4, 0xBD1CE083, 0xBF5A5EDA, 0xBE9834ED
|
||||
},
|
||||
new uint[]
|
||||
{
|
||||
0x00000000, 0xB8BC6765, 0xAA09C88B, 0x12B5AFEE, 0x8F629757, 0x37DEF032, 0x256B5FDC, 0x9DD738B9, 0xC5B428EF,
|
||||
0x7D084F8A, 0x6FBDE064, 0xD7018701, 0x4AD6BFB8, 0xF26AD8DD, 0xE0DF7733, 0x58631056, 0x5019579F, 0xE8A530FA,
|
||||
0xFA109F14, 0x42ACF871, 0xDF7BC0C8, 0x67C7A7AD, 0x75720843, 0xCDCE6F26, 0x95AD7F70, 0x2D111815, 0x3FA4B7FB,
|
||||
0x8718D09E, 0x1ACFE827, 0xA2738F42, 0xB0C620AC, 0x087A47C9, 0xA032AF3E, 0x188EC85B, 0x0A3B67B5, 0xB28700D0,
|
||||
0x2F503869, 0x97EC5F0C, 0x8559F0E2, 0x3DE59787, 0x658687D1, 0xDD3AE0B4, 0xCF8F4F5A, 0x7733283F, 0xEAE41086,
|
||||
0x525877E3, 0x40EDD80D, 0xF851BF68, 0xF02BF8A1, 0x48979FC4, 0x5A22302A, 0xE29E574F, 0x7F496FF6, 0xC7F50893,
|
||||
0xD540A77D, 0x6DFCC018, 0x359FD04E, 0x8D23B72B, 0x9F9618C5, 0x272A7FA0, 0xBAFD4719, 0x0241207C, 0x10F48F92,
|
||||
0xA848E8F7, 0x9B14583D, 0x23A83F58, 0x311D90B6, 0x89A1F7D3, 0x1476CF6A, 0xACCAA80F, 0xBE7F07E1, 0x06C36084,
|
||||
0x5EA070D2, 0xE61C17B7, 0xF4A9B859, 0x4C15DF3C, 0xD1C2E785, 0x697E80E0, 0x7BCB2F0E, 0xC377486B, 0xCB0D0FA2,
|
||||
0x73B168C7, 0x6104C729, 0xD9B8A04C, 0x446F98F5, 0xFCD3FF90, 0xEE66507E, 0x56DA371B, 0x0EB9274D, 0xB6054028,
|
||||
0xA4B0EFC6, 0x1C0C88A3, 0x81DBB01A, 0x3967D77F, 0x2BD27891, 0x936E1FF4, 0x3B26F703, 0x839A9066, 0x912F3F88,
|
||||
0x299358ED, 0xB4446054, 0x0CF80731, 0x1E4DA8DF, 0xA6F1CFBA, 0xFE92DFEC, 0x462EB889, 0x549B1767, 0xEC277002,
|
||||
0x71F048BB, 0xC94C2FDE, 0xDBF98030, 0x6345E755, 0x6B3FA09C, 0xD383C7F9, 0xC1366817, 0x798A0F72, 0xE45D37CB,
|
||||
0x5CE150AE, 0x4E54FF40, 0xF6E89825, 0xAE8B8873, 0x1637EF16, 0x048240F8, 0xBC3E279D, 0x21E91F24, 0x99557841,
|
||||
0x8BE0D7AF, 0x335CB0CA, 0xED59B63B, 0x55E5D15E, 0x47507EB0, 0xFFEC19D5, 0x623B216C, 0xDA874609, 0xC832E9E7,
|
||||
0x708E8E82, 0x28ED9ED4, 0x9051F9B1, 0x82E4565F, 0x3A58313A, 0xA78F0983, 0x1F336EE6, 0x0D86C108, 0xB53AA66D,
|
||||
0xBD40E1A4, 0x05FC86C1, 0x1749292F, 0xAFF54E4A, 0x322276F3, 0x8A9E1196, 0x982BBE78, 0x2097D91D, 0x78F4C94B,
|
||||
0xC048AE2E, 0xD2FD01C0, 0x6A4166A5, 0xF7965E1C, 0x4F2A3979, 0x5D9F9697, 0xE523F1F2, 0x4D6B1905, 0xF5D77E60,
|
||||
0xE762D18E, 0x5FDEB6EB, 0xC2098E52, 0x7AB5E937, 0x680046D9, 0xD0BC21BC, 0x88DF31EA, 0x3063568F, 0x22D6F961,
|
||||
0x9A6A9E04, 0x07BDA6BD, 0xBF01C1D8, 0xADB46E36, 0x15080953, 0x1D724E9A, 0xA5CE29FF, 0xB77B8611, 0x0FC7E174,
|
||||
0x9210D9CD, 0x2AACBEA8, 0x38191146, 0x80A57623, 0xD8C66675, 0x607A0110, 0x72CFAEFE, 0xCA73C99B, 0x57A4F122,
|
||||
0xEF189647, 0xFDAD39A9, 0x45115ECC, 0x764DEE06, 0xCEF18963, 0xDC44268D, 0x64F841E8, 0xF92F7951, 0x41931E34,
|
||||
0x5326B1DA, 0xEB9AD6BF, 0xB3F9C6E9, 0x0B45A18C, 0x19F00E62, 0xA14C6907, 0x3C9B51BE, 0x842736DB, 0x96929935,
|
||||
0x2E2EFE50, 0x2654B999, 0x9EE8DEFC, 0x8C5D7112, 0x34E11677, 0xA9362ECE, 0x118A49AB, 0x033FE645, 0xBB838120,
|
||||
0xE3E09176, 0x5B5CF613, 0x49E959FD, 0xF1553E98, 0x6C820621, 0xD43E6144, 0xC68BCEAA, 0x7E37A9CF, 0xD67F4138,
|
||||
0x6EC3265D, 0x7C7689B3, 0xC4CAEED6, 0x591DD66F, 0xE1A1B10A, 0xF3141EE4, 0x4BA87981, 0x13CB69D7, 0xAB770EB2,
|
||||
0xB9C2A15C, 0x017EC639, 0x9CA9FE80, 0x241599E5, 0x36A0360B, 0x8E1C516E, 0x866616A7, 0x3EDA71C2, 0x2C6FDE2C,
|
||||
0x94D3B949, 0x090481F0, 0xB1B8E695, 0xA30D497B, 0x1BB12E1E, 0x43D23E48, 0xFB6E592D, 0xE9DBF6C3, 0x516791A6,
|
||||
0xCCB0A91F, 0x740CCE7A, 0x66B96194, 0xDE0506F1
|
||||
},
|
||||
new uint[]
|
||||
{
|
||||
0x00000000, 0x3D6029B0, 0x7AC05360, 0x47A07AD0, 0xF580A6C0, 0xC8E08F70, 0x8F40F5A0, 0xB220DC10, 0x30704BC1,
|
||||
0x0D106271, 0x4AB018A1, 0x77D03111, 0xC5F0ED01, 0xF890C4B1, 0xBF30BE61, 0x825097D1, 0x60E09782, 0x5D80BE32,
|
||||
0x1A20C4E2, 0x2740ED52, 0x95603142, 0xA80018F2, 0xEFA06222, 0xD2C04B92, 0x5090DC43, 0x6DF0F5F3, 0x2A508F23,
|
||||
0x1730A693, 0xA5107A83, 0x98705333, 0xDFD029E3, 0xE2B00053, 0xC1C12F04, 0xFCA106B4, 0xBB017C64, 0x866155D4,
|
||||
0x344189C4, 0x0921A074, 0x4E81DAA4, 0x73E1F314, 0xF1B164C5, 0xCCD14D75, 0x8B7137A5, 0xB6111E15, 0x0431C205,
|
||||
0x3951EBB5, 0x7EF19165, 0x4391B8D5, 0xA121B886, 0x9C419136, 0xDBE1EBE6, 0xE681C256, 0x54A11E46, 0x69C137F6,
|
||||
0x2E614D26, 0x13016496, 0x9151F347, 0xAC31DAF7, 0xEB91A027, 0xD6F18997, 0x64D15587, 0x59B17C37, 0x1E1106E7,
|
||||
0x23712F57, 0x58F35849, 0x659371F9, 0x22330B29, 0x1F532299, 0xAD73FE89, 0x9013D739, 0xD7B3ADE9, 0xEAD38459,
|
||||
0x68831388, 0x55E33A38, 0x124340E8, 0x2F236958, 0x9D03B548, 0xA0639CF8, 0xE7C3E628, 0xDAA3CF98, 0x3813CFCB,
|
||||
0x0573E67B, 0x42D39CAB, 0x7FB3B51B, 0xCD93690B, 0xF0F340BB, 0xB7533A6B, 0x8A3313DB, 0x0863840A, 0x3503ADBA,
|
||||
0x72A3D76A, 0x4FC3FEDA, 0xFDE322CA, 0xC0830B7A, 0x872371AA, 0xBA43581A, 0x9932774D, 0xA4525EFD, 0xE3F2242D,
|
||||
0xDE920D9D, 0x6CB2D18D, 0x51D2F83D, 0x167282ED, 0x2B12AB5D, 0xA9423C8C, 0x9422153C, 0xD3826FEC, 0xEEE2465C,
|
||||
0x5CC29A4C, 0x61A2B3FC, 0x2602C92C, 0x1B62E09C, 0xF9D2E0CF, 0xC4B2C97F, 0x8312B3AF, 0xBE729A1F, 0x0C52460F,
|
||||
0x31326FBF, 0x7692156F, 0x4BF23CDF, 0xC9A2AB0E, 0xF4C282BE, 0xB362F86E, 0x8E02D1DE, 0x3C220DCE, 0x0142247E,
|
||||
0x46E25EAE, 0x7B82771E, 0xB1E6B092, 0x8C869922, 0xCB26E3F2, 0xF646CA42, 0x44661652, 0x79063FE2, 0x3EA64532,
|
||||
0x03C66C82, 0x8196FB53, 0xBCF6D2E3, 0xFB56A833, 0xC6368183, 0x74165D93, 0x49767423, 0x0ED60EF3, 0x33B62743,
|
||||
0xD1062710, 0xEC660EA0, 0xABC67470, 0x96A65DC0, 0x248681D0, 0x19E6A860, 0x5E46D2B0, 0x6326FB00, 0xE1766CD1,
|
||||
0xDC164561, 0x9BB63FB1, 0xA6D61601, 0x14F6CA11, 0x2996E3A1, 0x6E369971, 0x5356B0C1, 0x70279F96, 0x4D47B626,
|
||||
0x0AE7CCF6, 0x3787E546, 0x85A73956, 0xB8C710E6, 0xFF676A36, 0xC2074386, 0x4057D457, 0x7D37FDE7, 0x3A978737,
|
||||
0x07F7AE87, 0xB5D77297, 0x88B75B27, 0xCF1721F7, 0xF2770847, 0x10C70814, 0x2DA721A4, 0x6A075B74, 0x576772C4,
|
||||
0xE547AED4, 0xD8278764, 0x9F87FDB4, 0xA2E7D404, 0x20B743D5, 0x1DD76A65, 0x5A7710B5, 0x67173905, 0xD537E515,
|
||||
0xE857CCA5, 0xAFF7B675, 0x92979FC5, 0xE915E8DB, 0xD475C16B, 0x93D5BBBB, 0xAEB5920B, 0x1C954E1B, 0x21F567AB,
|
||||
0x66551D7B, 0x5B3534CB, 0xD965A31A, 0xE4058AAA, 0xA3A5F07A, 0x9EC5D9CA, 0x2CE505DA, 0x11852C6A, 0x562556BA,
|
||||
0x6B457F0A, 0x89F57F59, 0xB49556E9, 0xF3352C39, 0xCE550589, 0x7C75D999, 0x4115F029, 0x06B58AF9, 0x3BD5A349,
|
||||
0xB9853498, 0x84E51D28, 0xC34567F8, 0xFE254E48, 0x4C059258, 0x7165BBE8, 0x36C5C138, 0x0BA5E888, 0x28D4C7DF,
|
||||
0x15B4EE6F, 0x521494BF, 0x6F74BD0F, 0xDD54611F, 0xE03448AF, 0xA794327F, 0x9AF41BCF, 0x18A48C1E, 0x25C4A5AE,
|
||||
0x6264DF7E, 0x5F04F6CE, 0xED242ADE, 0xD044036E, 0x97E479BE, 0xAA84500E, 0x4834505D, 0x755479ED, 0x32F4033D,
|
||||
0x0F942A8D, 0xBDB4F69D, 0x80D4DF2D, 0xC774A5FD, 0xFA148C4D, 0x78441B9C, 0x4524322C, 0x028448FC, 0x3FE4614C,
|
||||
0x8DC4BD5C, 0xB0A494EC, 0xF704EE3C, 0xCA64C78C
|
||||
},
|
||||
new uint[]
|
||||
{
|
||||
0x00000000, 0xCB5CD3A5, 0x4DC8A10B, 0x869472AE, 0x9B914216, 0x50CD91B3, 0xD659E31D, 0x1D0530B8, 0xEC53826D,
|
||||
0x270F51C8, 0xA19B2366, 0x6AC7F0C3, 0x77C2C07B, 0xBC9E13DE, 0x3A0A6170, 0xF156B2D5, 0x03D6029B, 0xC88AD13E,
|
||||
0x4E1EA390, 0x85427035, 0x9847408D, 0x531B9328, 0xD58FE186, 0x1ED33223, 0xEF8580F6, 0x24D95353, 0xA24D21FD,
|
||||
0x6911F258, 0x7414C2E0, 0xBF481145, 0x39DC63EB, 0xF280B04E, 0x07AC0536, 0xCCF0D693, 0x4A64A43D, 0x81387798,
|
||||
0x9C3D4720, 0x57619485, 0xD1F5E62B, 0x1AA9358E, 0xEBFF875B, 0x20A354FE, 0xA6372650, 0x6D6BF5F5, 0x706EC54D,
|
||||
0xBB3216E8, 0x3DA66446, 0xF6FAB7E3, 0x047A07AD, 0xCF26D408, 0x49B2A6A6, 0x82EE7503, 0x9FEB45BB, 0x54B7961E,
|
||||
0xD223E4B0, 0x197F3715, 0xE82985C0, 0x23755665, 0xA5E124CB, 0x6EBDF76E, 0x73B8C7D6, 0xB8E41473, 0x3E7066DD,
|
||||
0xF52CB578, 0x0F580A6C, 0xC404D9C9, 0x4290AB67, 0x89CC78C2, 0x94C9487A, 0x5F959BDF, 0xD901E971, 0x125D3AD4,
|
||||
0xE30B8801, 0x28575BA4, 0xAEC3290A, 0x659FFAAF, 0x789ACA17, 0xB3C619B2, 0x35526B1C, 0xFE0EB8B9, 0x0C8E08F7,
|
||||
0xC7D2DB52, 0x4146A9FC, 0x8A1A7A59, 0x971F4AE1, 0x5C439944, 0xDAD7EBEA, 0x118B384F, 0xE0DD8A9A, 0x2B81593F,
|
||||
0xAD152B91, 0x6649F834, 0x7B4CC88C, 0xB0101B29, 0x36846987, 0xFDD8BA22, 0x08F40F5A, 0xC3A8DCFF, 0x453CAE51,
|
||||
0x8E607DF4, 0x93654D4C, 0x58399EE9, 0xDEADEC47, 0x15F13FE2, 0xE4A78D37, 0x2FFB5E92, 0xA96F2C3C, 0x6233FF99,
|
||||
0x7F36CF21, 0xB46A1C84, 0x32FE6E2A, 0xF9A2BD8F, 0x0B220DC1, 0xC07EDE64, 0x46EAACCA, 0x8DB67F6F, 0x90B34FD7,
|
||||
0x5BEF9C72, 0xDD7BEEDC, 0x16273D79, 0xE7718FAC, 0x2C2D5C09, 0xAAB92EA7, 0x61E5FD02, 0x7CE0CDBA, 0xB7BC1E1F,
|
||||
0x31286CB1, 0xFA74BF14, 0x1EB014D8, 0xD5ECC77D, 0x5378B5D3, 0x98246676, 0x852156CE, 0x4E7D856B, 0xC8E9F7C5,
|
||||
0x03B52460, 0xF2E396B5, 0x39BF4510, 0xBF2B37BE, 0x7477E41B, 0x6972D4A3, 0xA22E0706, 0x24BA75A8, 0xEFE6A60D,
|
||||
0x1D661643, 0xD63AC5E6, 0x50AEB748, 0x9BF264ED, 0x86F75455, 0x4DAB87F0, 0xCB3FF55E, 0x006326FB, 0xF135942E,
|
||||
0x3A69478B, 0xBCFD3525, 0x77A1E680, 0x6AA4D638, 0xA1F8059D, 0x276C7733, 0xEC30A496, 0x191C11EE, 0xD240C24B,
|
||||
0x54D4B0E5, 0x9F886340, 0x828D53F8, 0x49D1805D, 0xCF45F2F3, 0x04192156, 0xF54F9383, 0x3E134026, 0xB8873288,
|
||||
0x73DBE12D, 0x6EDED195, 0xA5820230, 0x2316709E, 0xE84AA33B, 0x1ACA1375, 0xD196C0D0, 0x5702B27E, 0x9C5E61DB,
|
||||
0x815B5163, 0x4A0782C6, 0xCC93F068, 0x07CF23CD, 0xF6999118, 0x3DC542BD, 0xBB513013, 0x700DE3B6, 0x6D08D30E,
|
||||
0xA65400AB, 0x20C07205, 0xEB9CA1A0, 0x11E81EB4, 0xDAB4CD11, 0x5C20BFBF, 0x977C6C1A, 0x8A795CA2, 0x41258F07,
|
||||
0xC7B1FDA9, 0x0CED2E0C, 0xFDBB9CD9, 0x36E74F7C, 0xB0733DD2, 0x7B2FEE77, 0x662ADECF, 0xAD760D6A, 0x2BE27FC4,
|
||||
0xE0BEAC61, 0x123E1C2F, 0xD962CF8A, 0x5FF6BD24, 0x94AA6E81, 0x89AF5E39, 0x42F38D9C, 0xC467FF32, 0x0F3B2C97,
|
||||
0xFE6D9E42, 0x35314DE7, 0xB3A53F49, 0x78F9ECEC, 0x65FCDC54, 0xAEA00FF1, 0x28347D5F, 0xE368AEFA, 0x16441B82,
|
||||
0xDD18C827, 0x5B8CBA89, 0x90D0692C, 0x8DD55994, 0x46898A31, 0xC01DF89F, 0x0B412B3A, 0xFA1799EF, 0x314B4A4A,
|
||||
0xB7DF38E4, 0x7C83EB41, 0x6186DBF9, 0xAADA085C, 0x2C4E7AF2, 0xE712A957, 0x15921919, 0xDECECABC, 0x585AB812,
|
||||
0x93066BB7, 0x8E035B0F, 0x455F88AA, 0xC3CBFA04, 0x089729A1, 0xF9C19B74, 0x329D48D1, 0xB4093A7F, 0x7F55E9DA,
|
||||
0x6250D962, 0xA90C0AC7, 0x2F987869, 0xE4C4ABCC
|
||||
},
|
||||
new uint[]
|
||||
{
|
||||
0x00000000, 0xA6770BB4, 0x979F1129, 0x31E81A9D, 0xF44F2413, 0x52382FA7, 0x63D0353A, 0xC5A73E8E, 0x33EF4E67,
|
||||
0x959845D3, 0xA4705F4E, 0x020754FA, 0xC7A06A74, 0x61D761C0, 0x503F7B5D, 0xF64870E9, 0x67DE9CCE, 0xC1A9977A,
|
||||
0xF0418DE7, 0x56368653, 0x9391B8DD, 0x35E6B369, 0x040EA9F4, 0xA279A240, 0x5431D2A9, 0xF246D91D, 0xC3AEC380,
|
||||
0x65D9C834, 0xA07EF6BA, 0x0609FD0E, 0x37E1E793, 0x9196EC27, 0xCFBD399C, 0x69CA3228, 0x582228B5, 0xFE552301,
|
||||
0x3BF21D8F, 0x9D85163B, 0xAC6D0CA6, 0x0A1A0712, 0xFC5277FB, 0x5A257C4F, 0x6BCD66D2, 0xCDBA6D66, 0x081D53E8,
|
||||
0xAE6A585C, 0x9F8242C1, 0x39F54975, 0xA863A552, 0x0E14AEE6, 0x3FFCB47B, 0x998BBFCF, 0x5C2C8141, 0xFA5B8AF5,
|
||||
0xCBB39068, 0x6DC49BDC, 0x9B8CEB35, 0x3DFBE081, 0x0C13FA1C, 0xAA64F1A8, 0x6FC3CF26, 0xC9B4C492, 0xF85CDE0F,
|
||||
0x5E2BD5BB, 0x440B7579, 0xE27C7ECD, 0xD3946450, 0x75E36FE4, 0xB044516A, 0x16335ADE, 0x27DB4043, 0x81AC4BF7,
|
||||
0x77E43B1E, 0xD19330AA, 0xE07B2A37, 0x460C2183, 0x83AB1F0D, 0x25DC14B9, 0x14340E24, 0xB2430590, 0x23D5E9B7,
|
||||
0x85A2E203, 0xB44AF89E, 0x123DF32A, 0xD79ACDA4, 0x71EDC610, 0x4005DC8D, 0xE672D739, 0x103AA7D0, 0xB64DAC64,
|
||||
0x87A5B6F9, 0x21D2BD4D, 0xE47583C3, 0x42028877, 0x73EA92EA, 0xD59D995E, 0x8BB64CE5, 0x2DC14751, 0x1C295DCC,
|
||||
0xBA5E5678, 0x7FF968F6, 0xD98E6342, 0xE86679DF, 0x4E11726B, 0xB8590282, 0x1E2E0936, 0x2FC613AB, 0x89B1181F,
|
||||
0x4C162691, 0xEA612D25, 0xDB8937B8, 0x7DFE3C0C, 0xEC68D02B, 0x4A1FDB9F, 0x7BF7C102, 0xDD80CAB6, 0x1827F438,
|
||||
0xBE50FF8C, 0x8FB8E511, 0x29CFEEA5, 0xDF879E4C, 0x79F095F8, 0x48188F65, 0xEE6F84D1, 0x2BC8BA5F, 0x8DBFB1EB,
|
||||
0xBC57AB76, 0x1A20A0C2, 0x8816EAF2, 0x2E61E146, 0x1F89FBDB, 0xB9FEF06F, 0x7C59CEE1, 0xDA2EC555, 0xEBC6DFC8,
|
||||
0x4DB1D47C, 0xBBF9A495, 0x1D8EAF21, 0x2C66B5BC, 0x8A11BE08, 0x4FB68086, 0xE9C18B32, 0xD82991AF, 0x7E5E9A1B,
|
||||
0xEFC8763C, 0x49BF7D88, 0x78576715, 0xDE206CA1, 0x1B87522F, 0xBDF0599B, 0x8C184306, 0x2A6F48B2, 0xDC27385B,
|
||||
0x7A5033EF, 0x4BB82972, 0xEDCF22C6, 0x28681C48, 0x8E1F17FC, 0xBFF70D61, 0x198006D5, 0x47ABD36E, 0xE1DCD8DA,
|
||||
0xD034C247, 0x7643C9F3, 0xB3E4F77D, 0x1593FCC9, 0x247BE654, 0x820CEDE0, 0x74449D09, 0xD23396BD, 0xE3DB8C20,
|
||||
0x45AC8794, 0x800BB91A, 0x267CB2AE, 0x1794A833, 0xB1E3A387, 0x20754FA0, 0x86024414, 0xB7EA5E89, 0x119D553D,
|
||||
0xD43A6BB3, 0x724D6007, 0x43A57A9A, 0xE5D2712E, 0x139A01C7, 0xB5ED0A73, 0x840510EE, 0x22721B5A, 0xE7D525D4,
|
||||
0x41A22E60, 0x704A34FD, 0xD63D3F49, 0xCC1D9F8B, 0x6A6A943F, 0x5B828EA2, 0xFDF58516, 0x3852BB98, 0x9E25B02C,
|
||||
0xAFCDAAB1, 0x09BAA105, 0xFFF2D1EC, 0x5985DA58, 0x686DC0C5, 0xCE1ACB71, 0x0BBDF5FF, 0xADCAFE4B, 0x9C22E4D6,
|
||||
0x3A55EF62, 0xABC30345, 0x0DB408F1, 0x3C5C126C, 0x9A2B19D8, 0x5F8C2756, 0xF9FB2CE2, 0xC813367F, 0x6E643DCB,
|
||||
0x982C4D22, 0x3E5B4696, 0x0FB35C0B, 0xA9C457BF, 0x6C636931, 0xCA146285, 0xFBFC7818, 0x5D8B73AC, 0x03A0A617,
|
||||
0xA5D7ADA3, 0x943FB73E, 0x3248BC8A, 0xF7EF8204, 0x519889B0, 0x6070932D, 0xC6079899, 0x304FE870, 0x9638E3C4,
|
||||
0xA7D0F959, 0x01A7F2ED, 0xC400CC63, 0x6277C7D7, 0x539FDD4A, 0xF5E8D6FE, 0x647E3AD9, 0xC209316D, 0xF3E12BF0,
|
||||
0x55962044, 0x90311ECA, 0x3646157E, 0x07AE0FE3, 0xA1D90457, 0x579174BE, 0xF1E67F0A, 0xC00E6597, 0x66796E23,
|
||||
0xA3DE50AD, 0x05A95B19, 0x34414184, 0x92364A30
|
||||
},
|
||||
new uint[]
|
||||
{
|
||||
0x00000000, 0xCCAA009E, 0x4225077D, 0x8E8F07E3, 0x844A0EFA, 0x48E00E64, 0xC66F0987, 0x0AC50919, 0xD3E51BB5,
|
||||
0x1F4F1B2B, 0x91C01CC8, 0x5D6A1C56, 0x57AF154F, 0x9B0515D1, 0x158A1232, 0xD92012AC, 0x7CBB312B, 0xB01131B5,
|
||||
0x3E9E3656, 0xF23436C8, 0xF8F13FD1, 0x345B3F4F, 0xBAD438AC, 0x767E3832, 0xAF5E2A9E, 0x63F42A00, 0xED7B2DE3,
|
||||
0x21D12D7D, 0x2B142464, 0xE7BE24FA, 0x69312319, 0xA59B2387, 0xF9766256, 0x35DC62C8, 0xBB53652B, 0x77F965B5,
|
||||
0x7D3C6CAC, 0xB1966C32, 0x3F196BD1, 0xF3B36B4F, 0x2A9379E3, 0xE639797D, 0x68B67E9E, 0xA41C7E00, 0xAED97719,
|
||||
0x62737787, 0xECFC7064, 0x205670FA, 0x85CD537D, 0x496753E3, 0xC7E85400, 0x0B42549E, 0x01875D87, 0xCD2D5D19,
|
||||
0x43A25AFA, 0x8F085A64, 0x562848C8, 0x9A824856, 0x140D4FB5, 0xD8A74F2B, 0xD2624632, 0x1EC846AC, 0x9047414F,
|
||||
0x5CED41D1, 0x299DC2ED, 0xE537C273, 0x6BB8C590, 0xA712C50E, 0xADD7CC17, 0x617DCC89, 0xEFF2CB6A, 0x2358CBF4,
|
||||
0xFA78D958, 0x36D2D9C6, 0xB85DDE25, 0x74F7DEBB, 0x7E32D7A2, 0xB298D73C, 0x3C17D0DF, 0xF0BDD041, 0x5526F3C6,
|
||||
0x998CF358, 0x1703F4BB, 0xDBA9F425, 0xD16CFD3C, 0x1DC6FDA2, 0x9349FA41, 0x5FE3FADF, 0x86C3E873, 0x4A69E8ED,
|
||||
0xC4E6EF0E, 0x084CEF90, 0x0289E689, 0xCE23E617, 0x40ACE1F4, 0x8C06E16A, 0xD0EBA0BB, 0x1C41A025, 0x92CEA7C6,
|
||||
0x5E64A758, 0x54A1AE41, 0x980BAEDF, 0x1684A93C, 0xDA2EA9A2, 0x030EBB0E, 0xCFA4BB90, 0x412BBC73, 0x8D81BCED,
|
||||
0x8744B5F4, 0x4BEEB56A, 0xC561B289, 0x09CBB217, 0xAC509190, 0x60FA910E, 0xEE7596ED, 0x22DF9673, 0x281A9F6A,
|
||||
0xE4B09FF4, 0x6A3F9817, 0xA6959889, 0x7FB58A25, 0xB31F8ABB, 0x3D908D58, 0xF13A8DC6, 0xFBFF84DF, 0x37558441,
|
||||
0xB9DA83A2, 0x7570833C, 0x533B85DA, 0x9F918544, 0x111E82A7, 0xDDB48239, 0xD7718B20, 0x1BDB8BBE, 0x95548C5D,
|
||||
0x59FE8CC3, 0x80DE9E6F, 0x4C749EF1, 0xC2FB9912, 0x0E51998C, 0x04949095, 0xC83E900B, 0x46B197E8, 0x8A1B9776,
|
||||
0x2F80B4F1, 0xE32AB46F, 0x6DA5B38C, 0xA10FB312, 0xABCABA0B, 0x6760BA95, 0xE9EFBD76, 0x2545BDE8, 0xFC65AF44,
|
||||
0x30CFAFDA, 0xBE40A839, 0x72EAA8A7, 0x782FA1BE, 0xB485A120, 0x3A0AA6C3, 0xF6A0A65D, 0xAA4DE78C, 0x66E7E712,
|
||||
0xE868E0F1, 0x24C2E06F, 0x2E07E976, 0xE2ADE9E8, 0x6C22EE0B, 0xA088EE95, 0x79A8FC39, 0xB502FCA7, 0x3B8DFB44,
|
||||
0xF727FBDA, 0xFDE2F2C3, 0x3148F25D, 0xBFC7F5BE, 0x736DF520, 0xD6F6D6A7, 0x1A5CD639, 0x94D3D1DA, 0x5879D144,
|
||||
0x52BCD85D, 0x9E16D8C3, 0x1099DF20, 0xDC33DFBE, 0x0513CD12, 0xC9B9CD8C, 0x4736CA6F, 0x8B9CCAF1, 0x8159C3E8,
|
||||
0x4DF3C376, 0xC37CC495, 0x0FD6C40B, 0x7AA64737, 0xB60C47A9, 0x3883404A, 0xF42940D4, 0xFEEC49CD, 0x32464953,
|
||||
0xBCC94EB0, 0x70634E2E, 0xA9435C82, 0x65E95C1C, 0xEB665BFF, 0x27CC5B61, 0x2D095278, 0xE1A352E6, 0x6F2C5505,
|
||||
0xA386559B, 0x061D761C, 0xCAB77682, 0x44387161, 0x889271FF, 0x825778E6, 0x4EFD7878, 0xC0727F9B, 0x0CD87F05,
|
||||
0xD5F86DA9, 0x19526D37, 0x97DD6AD4, 0x5B776A4A, 0x51B26353, 0x9D1863CD, 0x1397642E, 0xDF3D64B0, 0x83D02561,
|
||||
0x4F7A25FF, 0xC1F5221C, 0x0D5F2282, 0x079A2B9B, 0xCB302B05, 0x45BF2CE6, 0x89152C78, 0x50353ED4, 0x9C9F3E4A,
|
||||
0x121039A9, 0xDEBA3937, 0xD47F302E, 0x18D530B0, 0x965A3753, 0x5AF037CD, 0xFF6B144A, 0x33C114D4, 0xBD4E1337,
|
||||
0x71E413A9, 0x7B211AB0, 0xB78B1A2E, 0x39041DCD, 0xF5AE1D53, 0x2C8E0FFF, 0xE0240F61, 0x6EAB0882, 0xA201081C,
|
||||
0xA8C40105, 0x646E019B, 0xEAE10678, 0x264B06E6
|
||||
}
|
||||
};
|
||||
|
||||
readonly uint _finalSeed;
|
||||
readonly IntPtr _nativeContext;
|
||||
readonly uint[][]? _table;
|
||||
readonly bool _useIso;
|
||||
readonly bool _useNative;
|
||||
uint _hashInt;
|
||||
|
||||
/// <summary>Initializes the CRC32 table and seed as CRC32-ISO</summary>
|
||||
public Crc32Context()
|
||||
{
|
||||
_hashInt = CRC32_ISO_SEED;
|
||||
_finalSeed = CRC32_ISO_SEED;
|
||||
_table = ISOCrc32Table;
|
||||
_useIso = true;
|
||||
|
||||
if(!Native.IsSupported)
|
||||
return;
|
||||
|
||||
_nativeContext = crc32_init();
|
||||
_useNative = _nativeContext != IntPtr.Zero;
|
||||
}
|
||||
|
||||
/// <summary>Initializes the CRC32 table with a custom polynomial and seed</summary>
|
||||
public Crc32Context(uint polynomial, uint seed)
|
||||
{
|
||||
_hashInt = seed;
|
||||
_finalSeed = seed;
|
||||
_useIso = polynomial == CRC32_ISO_POLY && seed == CRC32_ISO_SEED;
|
||||
|
||||
if(Native.IsSupported && _useIso)
|
||||
{
|
||||
_nativeContext = crc32_init();
|
||||
_useNative = _nativeContext != IntPtr.Zero;
|
||||
}
|
||||
else
|
||||
_table = GenerateTable(polynomial);
|
||||
}
|
||||
|
||||
#region IChecksum Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => "CRC-32";
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Id => new("BCC4E18A-79CD-4B52-8A57-2B599E5176B3");
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Author => "Natalia Portillo";
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>Updates the hash with data.</summary>
|
||||
/// <param name="data">Data buffer.</param>
|
||||
/// <param name="len">Length of buffer to hash.</param>
|
||||
public void Update(byte[] data, uint len) =>
|
||||
Step(ref _hashInt, _table!, data, len, _useIso, _useNative, _nativeContext);
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>Updates the hash with data.</summary>
|
||||
/// <param name="data">Data buffer.</param>
|
||||
public void Update(byte[] data) => Update(data, (uint)data.Length);
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>Returns a byte array of the hash value.</summary>
|
||||
public byte[] Final()
|
||||
{
|
||||
uint crc = _hashInt ^ _finalSeed;
|
||||
|
||||
if(!_useNative || !_useIso)
|
||||
return BigEndianBitConverter.GetBytes(crc);
|
||||
|
||||
crc32_final(_nativeContext, ref crc);
|
||||
crc32_free(_nativeContext);
|
||||
|
||||
return BigEndianBitConverter.GetBytes(crc);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>Returns a hexadecimal representation of the hash value.</summary>
|
||||
public string End()
|
||||
{
|
||||
uint crc = _hashInt ^ _finalSeed;
|
||||
|
||||
var crc32Output = new StringBuilder();
|
||||
|
||||
if(_useNative && _useIso)
|
||||
{
|
||||
crc32_final(_nativeContext, ref crc);
|
||||
crc32_free(_nativeContext);
|
||||
}
|
||||
|
||||
for(var i = 0; i < BigEndianBitConverter.GetBytes(crc).Length; i++)
|
||||
crc32Output.Append(BigEndianBitConverter.GetBytes(crc)[i].ToString("x2"));
|
||||
|
||||
return crc32Output.ToString();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
|
||||
static extern IntPtr crc32_init();
|
||||
|
||||
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
|
||||
static extern int crc32_update(IntPtr ctx, byte[] data, uint len);
|
||||
|
||||
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
|
||||
static extern int crc32_final(IntPtr ctx, ref uint crc);
|
||||
|
||||
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
|
||||
static extern void crc32_free(IntPtr ctx);
|
||||
|
||||
static uint[][] GenerateTable(uint polynomial)
|
||||
{
|
||||
var table = new uint[8][];
|
||||
|
||||
for(var i = 0; i < 8; i++)
|
||||
table[i] = new uint[256];
|
||||
|
||||
for(var i = 0; i < 256; i++)
|
||||
{
|
||||
var entry = (uint)i;
|
||||
|
||||
for(var j = 0; j < 8; j++)
|
||||
{
|
||||
if((entry & 1) == 1)
|
||||
entry = entry >> 1 ^ polynomial;
|
||||
else
|
||||
entry >>= 1;
|
||||
}
|
||||
|
||||
table[0][i] = entry;
|
||||
}
|
||||
|
||||
for(var slice = 1; slice < 8; slice++)
|
||||
for(var i = 0; i < 256; i++)
|
||||
table[slice][i] = table[slice - 1][i] >> 8 ^ table[0][table[slice - 1][i] & 0xFF];
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
static void Step(ref uint previousCrc, uint[][] table, byte[] data, uint len, bool useIso, bool useNative,
|
||||
IntPtr nativeContext)
|
||||
{
|
||||
if(useNative && useIso)
|
||||
{
|
||||
crc32_update(nativeContext, data, len);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var currentPos = 0;
|
||||
|
||||
if(useIso)
|
||||
{
|
||||
#if NETCOREAPP3_1_OR_GREATER
|
||||
if(Pclmulqdq.IsSupported && Sse41.IsSupported && Ssse3.IsSupported && Sse2.IsSupported)
|
||||
{
|
||||
// Only works in blocks of 16 bytes
|
||||
uint blocks = len / 64;
|
||||
|
||||
if(blocks > 0)
|
||||
{
|
||||
previousCrc = ~Clmul.Step(data, blocks * 64, ~previousCrc);
|
||||
|
||||
currentPos = (int)(blocks * 64);
|
||||
len -= blocks * 64;
|
||||
}
|
||||
|
||||
if(len == 0)
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NET5_0_OR_GREATER
|
||||
if(Crc32.Arm64.IsSupported)
|
||||
{
|
||||
previousCrc = ArmSimd.Step64(data, len, previousCrc);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(Crc32.IsSupported)
|
||||
{
|
||||
previousCrc = ArmSimd.Step32(data, len, previousCrc);
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Unroll according to Intel slicing by uint8_t
|
||||
// http://www.intel.com/technology/comms/perfnet/download/CRC_generators.pdf
|
||||
// http://sourceforge.net/projects/slicing-by-8/
|
||||
const int unroll = 4;
|
||||
const int bytesAtOnce = 8 * unroll;
|
||||
uint crc = previousCrc;
|
||||
|
||||
while(len >= bytesAtOnce)
|
||||
{
|
||||
int unrolling;
|
||||
|
||||
for(unrolling = 0; unrolling < unroll; unrolling++)
|
||||
{
|
||||
uint one = BitConverter.ToUInt32(data, currentPos) ^ crc;
|
||||
currentPos += 4;
|
||||
var two = BitConverter.ToUInt32(data, currentPos);
|
||||
currentPos += 4;
|
||||
|
||||
crc = table[0][two >> 24 & 0xFF] ^
|
||||
table[1][two >> 16 & 0xFF] ^
|
||||
table[2][two >> 8 & 0xFF] ^
|
||||
table[3][two & 0xFF] ^
|
||||
table[4][one >> 24 & 0xFF] ^
|
||||
table[5][one >> 16 & 0xFF] ^
|
||||
table[6][one >> 8 & 0xFF] ^
|
||||
table[7][one & 0xFF];
|
||||
}
|
||||
|
||||
len -= bytesAtOnce;
|
||||
}
|
||||
|
||||
while(len-- != 0)
|
||||
crc = crc >> 8 ^ table[0][crc & 0xFF ^ data[currentPos++]];
|
||||
|
||||
previousCrc = crc;
|
||||
}
|
||||
|
||||
/// <summary>Gets the hash of a file</summary>
|
||||
/// <param name="filename">File path.</param>
|
||||
// ReSharper disable once ReturnTypeCanBeEnumerable.Global
|
||||
public static byte[] File(string filename)
|
||||
{
|
||||
File(filename, out byte[] hash);
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
|
||||
/// <param name="filename">File path.</param>
|
||||
/// <param name="hash">Byte array of the hash value.</param>
|
||||
public static string File(string filename, out byte[] hash) =>
|
||||
File(filename, out hash, CRC32_ISO_POLY, CRC32_ISO_SEED);
|
||||
|
||||
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
|
||||
/// <param name="filename">File path.</param>
|
||||
/// <param name="hash">Byte array of the hash value.</param>
|
||||
/// <param name="polynomial">CRC polynomial</param>
|
||||
/// <param name="seed">CRC seed</param>
|
||||
public static string File(string filename, out byte[] hash, uint polynomial, uint seed)
|
||||
{
|
||||
bool useIso = polynomial == CRC32_ISO_POLY && seed == CRC32_ISO_SEED;
|
||||
bool useNative = Native.IsSupported;
|
||||
IntPtr nativeContext = IntPtr.Zero;
|
||||
|
||||
if(useNative && useIso)
|
||||
{
|
||||
nativeContext = crc32_init();
|
||||
useNative = nativeContext != IntPtr.Zero;
|
||||
}
|
||||
|
||||
var fileStream = new FileStream(filename, FileMode.Open);
|
||||
|
||||
uint localHashInt = seed;
|
||||
|
||||
uint[][] localTable = GenerateTable(polynomial);
|
||||
|
||||
var buffer = new byte[65536];
|
||||
int read = fileStream.EnsureRead(buffer, 0, 65536);
|
||||
|
||||
while(read > 0)
|
||||
{
|
||||
Step(ref localHashInt, localTable, buffer, (uint)read, useIso, useNative, nativeContext);
|
||||
|
||||
read = fileStream.EnsureRead(buffer, 0, 65536);
|
||||
}
|
||||
|
||||
localHashInt ^= seed;
|
||||
|
||||
if(useNative && useIso)
|
||||
{
|
||||
crc32_final(nativeContext, ref localHashInt);
|
||||
crc32_free(nativeContext);
|
||||
}
|
||||
|
||||
hash = BigEndianBitConverter.GetBytes(localHashInt);
|
||||
|
||||
var crc32Output = new StringBuilder();
|
||||
|
||||
foreach(byte h in hash)
|
||||
crc32Output.Append(h.ToString("x2"));
|
||||
|
||||
fileStream.Close();
|
||||
|
||||
return crc32Output.ToString();
|
||||
}
|
||||
|
||||
/// <summary>Gets the hash of the specified data buffer.</summary>
|
||||
/// <param name="data">Data buffer.</param>
|
||||
/// <param name="len">Length of the data buffer to hash.</param>
|
||||
/// <param name="hash">Byte array of the hash value.</param>
|
||||
public static string Data(byte[] data, uint len, out byte[] hash) =>
|
||||
Data(data, len, out hash, CRC32_ISO_POLY, CRC32_ISO_SEED);
|
||||
|
||||
/// <summary>Gets the hash of the specified data buffer.</summary>
|
||||
/// <param name="data">Data buffer.</param>
|
||||
/// <param name="len">Length of the data buffer to hash.</param>
|
||||
/// <param name="hash">Byte array of the hash value.</param>
|
||||
/// <param name="polynomial">CRC polynomial</param>
|
||||
/// <param name="seed">CRC seed</param>
|
||||
public static string Data(byte[] data, uint len, out byte[] hash, uint polynomial, uint seed)
|
||||
{
|
||||
bool useIso = polynomial == CRC32_ISO_POLY && seed == CRC32_ISO_SEED;
|
||||
bool useNative = Native.IsSupported;
|
||||
IntPtr nativeContext = IntPtr.Zero;
|
||||
|
||||
if(useNative && useIso)
|
||||
{
|
||||
nativeContext = crc32_init();
|
||||
useNative = nativeContext != IntPtr.Zero;
|
||||
}
|
||||
|
||||
uint localHashInt = seed;
|
||||
|
||||
uint[][] localTable = GenerateTable(polynomial);
|
||||
|
||||
Step(ref localHashInt, localTable, data, len, useIso, useNative, nativeContext);
|
||||
|
||||
localHashInt ^= seed;
|
||||
|
||||
if(useNative && useIso)
|
||||
{
|
||||
crc32_final(nativeContext, ref localHashInt);
|
||||
crc32_free(nativeContext);
|
||||
}
|
||||
|
||||
hash = BigEndianBitConverter.GetBytes(localHashInt);
|
||||
|
||||
var crc32Output = new StringBuilder();
|
||||
|
||||
foreach(byte h in hash)
|
||||
crc32Output.Append(h.ToString("x2"));
|
||||
|
||||
return crc32Output.ToString();
|
||||
}
|
||||
|
||||
/// <summary>Gets the hash of the specified data buffer.</summary>
|
||||
/// <param name="data">Data buffer.</param>
|
||||
/// <param name="hash">Byte array of the hash value.</param>
|
||||
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
// /***************************************************************************
|
||||
// Aaru Data Preservation Suite
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : clmul.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Checksums.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Compute the CRC64 using a parallelized folding approach with the PCLMULQDQ
|
||||
// instruction.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This file is under the public domain:
|
||||
// https://github.com/rawrunprotected/crc
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2023 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
#if NETCOREAPP3_1_OR_GREATER
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.Intrinsics;
|
||||
using System.Runtime.Intrinsics.X86;
|
||||
|
||||
namespace Aaru.Checksums.CRC64;
|
||||
|
||||
static class Clmul
|
||||
{
|
||||
static readonly byte[] _shuffleMasks =
|
||||
{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x8f, 0x8e,
|
||||
0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80
|
||||
};
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
static void ShiftRight128(Vector128<ulong> initial, uint n, out Vector128<ulong> outLeft,
|
||||
out Vector128<ulong> outRight)
|
||||
{
|
||||
uint maskPos = 16 - n;
|
||||
|
||||
var maskA = Vector128.Create(_shuffleMasks[maskPos], _shuffleMasks[maskPos + 1], _shuffleMasks[maskPos + 2],
|
||||
_shuffleMasks[maskPos + 3], _shuffleMasks[maskPos + 4], _shuffleMasks[maskPos + 5],
|
||||
_shuffleMasks[maskPos + 6], _shuffleMasks[maskPos + 7], _shuffleMasks[maskPos + 8],
|
||||
_shuffleMasks[maskPos + 9], _shuffleMasks[maskPos + 10],
|
||||
_shuffleMasks[maskPos + 11], _shuffleMasks[maskPos + 12],
|
||||
_shuffleMasks[maskPos + 13], _shuffleMasks[maskPos + 14],
|
||||
_shuffleMasks[maskPos + 15]);
|
||||
|
||||
Vector128<byte> maskB = Sse2.Xor(maskA, Sse2.CompareEqual(Vector128<byte>.Zero, Vector128<byte>.Zero));
|
||||
|
||||
outLeft = Ssse3.Shuffle(initial.AsByte(), maskB).AsUInt64();
|
||||
outRight = Ssse3.Shuffle(initial.AsByte(), maskA).AsUInt64();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
static Vector128<ulong> Fold(Vector128<ulong> input, Vector128<ulong> foldConstants) =>
|
||||
Sse2.Xor(Pclmulqdq.CarrylessMultiply(input, foldConstants, 0x00),
|
||||
Pclmulqdq.CarrylessMultiply(input, foldConstants, 0x11));
|
||||
|
||||
internal static ulong Step(ulong crc, byte[] data, uint length)
|
||||
{
|
||||
var bufPos = 16;
|
||||
const ulong k1 = 0xe05dd497ca393ae4;
|
||||
const ulong k2 = 0xdabe95afc7875f40;
|
||||
const ulong mu = 0x9c3e466c172963d5;
|
||||
const ulong pol = 0x92d8af2baf0e1e85;
|
||||
var foldConstants1 = Vector128.Create(k1, k2);
|
||||
var foldConstants2 = Vector128.Create(mu, pol);
|
||||
var initialCrc = Vector128.Create(~crc, 0);
|
||||
length -= 16;
|
||||
|
||||
// Initial CRC can simply be added to data
|
||||
ShiftRight128(initialCrc, 0, out Vector128<ulong> crc0, out Vector128<ulong> crc1);
|
||||
|
||||
Vector128<ulong> accumulator =
|
||||
Sse2.Xor(Fold(Sse2.Xor(crc0, Vector128.Create(BitConverter.ToUInt64(data, 0), BitConverter.ToUInt64(data, 8))), foldConstants1),
|
||||
crc1);
|
||||
|
||||
while(length >= 32)
|
||||
{
|
||||
accumulator =
|
||||
Fold(Sse2.Xor(Vector128.Create(BitConverter.ToUInt64(data, bufPos), BitConverter.ToUInt64(data, bufPos + 8)), accumulator),
|
||||
foldConstants1);
|
||||
|
||||
length -= 16;
|
||||
bufPos += 16;
|
||||
}
|
||||
|
||||
Vector128<ulong> p = Sse2.Xor(accumulator,
|
||||
Vector128.Create(BitConverter.ToUInt64(data, bufPos),
|
||||
BitConverter.ToUInt64(data, bufPos + 8)));
|
||||
|
||||
Vector128<ulong> r = Sse2.Xor(Pclmulqdq.CarrylessMultiply(p, foldConstants1, 0x10),
|
||||
Sse2.ShiftRightLogical128BitLane(p, 8));
|
||||
|
||||
// Final Barrett reduction
|
||||
Vector128<ulong> t1 = Pclmulqdq.CarrylessMultiply(r, foldConstants2, 0x00);
|
||||
|
||||
Vector128<ulong> t2 =
|
||||
Sse2.Xor(Sse2.Xor(Pclmulqdq.CarrylessMultiply(t1, foldConstants2, 0x10), Sse2.ShiftLeftLogical128BitLane(t1, 8)),
|
||||
r);
|
||||
|
||||
return ~((ulong)Sse41.Extract(t2.AsUInt32(), 3) << 32 | Sse41.Extract(t2.AsUInt32(), 2));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,608 +0,0 @@
|
||||
// /***************************************************************************
|
||||
// Aaru Data Preservation Suite
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : CRC64Context.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Checksums.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Implements a CRC64 algorithm.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2023 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
#if NETCOREAPP3_1_OR_GREATER
|
||||
using System.Runtime.Intrinsics.X86;
|
||||
#endif
|
||||
using System.Text;
|
||||
#if NETCOREAPP3_1_OR_GREATER
|
||||
using Aaru.Checksums.CRC64;
|
||||
#endif
|
||||
using Aaru.CommonTypes.Interfaces;
|
||||
using Aaru.Helpers;
|
||||
|
||||
namespace Aaru.Checksums;
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>Implements a CRC64 algorithm</summary>
|
||||
[SuppressMessage("ReSharper", "UnusedMember.Global")]
|
||||
[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")]
|
||||
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
|
||||
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
|
||||
public sealed class Crc64Context : IChecksum
|
||||
{
|
||||
/// <summary>ECMA CRC64 polynomial</summary>
|
||||
const ulong CRC64_ECMA_POLY = 0xC96C5795D7870F42;
|
||||
/// <summary>ECMA CRC64 seed</summary>
|
||||
const ulong CRC64_ECMA_SEED = 0xFFFFFFFFFFFFFFFF;
|
||||
|
||||
static readonly ulong[][] _ecmaCrc64Table =
|
||||
{
|
||||
new ulong[]
|
||||
{
|
||||
0x0000000000000000, 0xB32E4CBE03A75F6F, 0xF4843657A840A05B, 0x47AA7AE9ABE7FF34, 0x7BD0C384FF8F5E33,
|
||||
0xC8FE8F3AFC28015C, 0x8F54F5D357CFFE68, 0x3C7AB96D5468A107, 0xF7A18709FF1EBC66, 0x448FCBB7FCB9E309,
|
||||
0x0325B15E575E1C3D, 0xB00BFDE054F94352, 0x8C71448D0091E255, 0x3F5F08330336BD3A, 0x78F572DAA8D1420E,
|
||||
0xCBDB3E64AB761D61, 0x7D9BA13851336649, 0xCEB5ED8652943926, 0x891F976FF973C612, 0x3A31DBD1FAD4997D,
|
||||
0x064B62BCAEBC387A, 0xB5652E02AD1B6715, 0xF2CF54EB06FC9821, 0x41E11855055BC74E, 0x8A3A2631AE2DDA2F,
|
||||
0x39146A8FAD8A8540, 0x7EBE1066066D7A74, 0xCD905CD805CA251B, 0xF1EAE5B551A2841C, 0x42C4A90B5205DB73,
|
||||
0x056ED3E2F9E22447, 0xB6409F5CFA457B28, 0xFB374270A266CC92, 0x48190ECEA1C193FD, 0x0FB374270A266CC9,
|
||||
0xBC9D3899098133A6, 0x80E781F45DE992A1, 0x33C9CD4A5E4ECDCE, 0x7463B7A3F5A932FA, 0xC74DFB1DF60E6D95,
|
||||
0x0C96C5795D7870F4, 0xBFB889C75EDF2F9B, 0xF812F32EF538D0AF, 0x4B3CBF90F69F8FC0, 0x774606FDA2F72EC7,
|
||||
0xC4684A43A15071A8, 0x83C230AA0AB78E9C, 0x30EC7C140910D1F3, 0x86ACE348F355AADB, 0x3582AFF6F0F2F5B4,
|
||||
0x7228D51F5B150A80, 0xC10699A158B255EF, 0xFD7C20CC0CDAF4E8, 0x4E526C720F7DAB87, 0x09F8169BA49A54B3,
|
||||
0xBAD65A25A73D0BDC, 0x710D64410C4B16BD, 0xC22328FF0FEC49D2, 0x85895216A40BB6E6, 0x36A71EA8A7ACE989,
|
||||
0x0ADDA7C5F3C4488E, 0xB9F3EB7BF06317E1, 0xFE5991925B84E8D5, 0x4D77DD2C5823B7BA, 0x64B62BCAEBC387A1,
|
||||
0xD7986774E864D8CE, 0x90321D9D438327FA, 0x231C512340247895, 0x1F66E84E144CD992, 0xAC48A4F017EB86FD,
|
||||
0xEBE2DE19BC0C79C9, 0x58CC92A7BFAB26A6, 0x9317ACC314DD3BC7, 0x2039E07D177A64A8, 0x67939A94BC9D9B9C,
|
||||
0xD4BDD62ABF3AC4F3, 0xE8C76F47EB5265F4, 0x5BE923F9E8F53A9B, 0x1C4359104312C5AF, 0xAF6D15AE40B59AC0,
|
||||
0x192D8AF2BAF0E1E8, 0xAA03C64CB957BE87, 0xEDA9BCA512B041B3, 0x5E87F01B11171EDC, 0x62FD4976457FBFDB,
|
||||
0xD1D305C846D8E0B4, 0x96797F21ED3F1F80, 0x2557339FEE9840EF, 0xEE8C0DFB45EE5D8E, 0x5DA24145464902E1,
|
||||
0x1A083BACEDAEFDD5, 0xA9267712EE09A2BA, 0x955CCE7FBA6103BD, 0x267282C1B9C65CD2, 0x61D8F8281221A3E6,
|
||||
0xD2F6B4961186FC89, 0x9F8169BA49A54B33, 0x2CAF25044A02145C, 0x6B055FEDE1E5EB68, 0xD82B1353E242B407,
|
||||
0xE451AA3EB62A1500, 0x577FE680B58D4A6F, 0x10D59C691E6AB55B, 0xA3FBD0D71DCDEA34, 0x6820EEB3B6BBF755,
|
||||
0xDB0EA20DB51CA83A, 0x9CA4D8E41EFB570E, 0x2F8A945A1D5C0861, 0x13F02D374934A966, 0xA0DE61894A93F609,
|
||||
0xE7741B60E174093D, 0x545A57DEE2D35652, 0xE21AC88218962D7A, 0x5134843C1B317215, 0x169EFED5B0D68D21,
|
||||
0xA5B0B26BB371D24E, 0x99CA0B06E7197349, 0x2AE447B8E4BE2C26, 0x6D4E3D514F59D312, 0xDE6071EF4CFE8C7D,
|
||||
0x15BB4F8BE788911C, 0xA6950335E42FCE73, 0xE13F79DC4FC83147, 0x521135624C6F6E28, 0x6E6B8C0F1807CF2F,
|
||||
0xDD45C0B11BA09040, 0x9AEFBA58B0476F74, 0x29C1F6E6B3E0301B, 0xC96C5795D7870F42, 0x7A421B2BD420502D,
|
||||
0x3DE861C27FC7AF19, 0x8EC62D7C7C60F076, 0xB2BC941128085171, 0x0192D8AF2BAF0E1E, 0x4638A2468048F12A,
|
||||
0xF516EEF883EFAE45, 0x3ECDD09C2899B324, 0x8DE39C222B3EEC4B, 0xCA49E6CB80D9137F, 0x7967AA75837E4C10,
|
||||
0x451D1318D716ED17, 0xF6335FA6D4B1B278, 0xB199254F7F564D4C, 0x02B769F17CF11223, 0xB4F7F6AD86B4690B,
|
||||
0x07D9BA1385133664, 0x4073C0FA2EF4C950, 0xF35D8C442D53963F, 0xCF273529793B3738, 0x7C0979977A9C6857,
|
||||
0x3BA3037ED17B9763, 0x888D4FC0D2DCC80C, 0x435671A479AAD56D, 0xF0783D1A7A0D8A02, 0xB7D247F3D1EA7536,
|
||||
0x04FC0B4DD24D2A59, 0x3886B22086258B5E, 0x8BA8FE9E8582D431, 0xCC0284772E652B05, 0x7F2CC8C92DC2746A,
|
||||
0x325B15E575E1C3D0, 0x8175595B76469CBF, 0xC6DF23B2DDA1638B, 0x75F16F0CDE063CE4, 0x498BD6618A6E9DE3,
|
||||
0xFAA59ADF89C9C28C, 0xBD0FE036222E3DB8, 0x0E21AC88218962D7, 0xC5FA92EC8AFF7FB6, 0x76D4DE52895820D9,
|
||||
0x317EA4BB22BFDFED, 0x8250E80521188082, 0xBE2A516875702185, 0x0D041DD676D77EEA, 0x4AAE673FDD3081DE,
|
||||
0xF9802B81DE97DEB1, 0x4FC0B4DD24D2A599, 0xFCEEF8632775FAF6, 0xBB44828A8C9205C2, 0x086ACE348F355AAD,
|
||||
0x34107759DB5DFBAA, 0x873E3BE7D8FAA4C5, 0xC094410E731D5BF1, 0x73BA0DB070BA049E, 0xB86133D4DBCC19FF,
|
||||
0x0B4F7F6AD86B4690, 0x4CE50583738CB9A4, 0xFFCB493D702BE6CB, 0xC3B1F050244347CC, 0x709FBCEE27E418A3,
|
||||
0x3735C6078C03E797, 0x841B8AB98FA4B8F8, 0xADDA7C5F3C4488E3, 0x1EF430E13FE3D78C, 0x595E4A08940428B8,
|
||||
0xEA7006B697A377D7, 0xD60ABFDBC3CBD6D0, 0x6524F365C06C89BF, 0x228E898C6B8B768B, 0x91A0C532682C29E4,
|
||||
0x5A7BFB56C35A3485, 0xE955B7E8C0FD6BEA, 0xAEFFCD016B1A94DE, 0x1DD181BF68BDCBB1, 0x21AB38D23CD56AB6,
|
||||
0x9285746C3F7235D9, 0xD52F0E859495CAED, 0x6601423B97329582, 0xD041DD676D77EEAA, 0x636F91D96ED0B1C5,
|
||||
0x24C5EB30C5374EF1, 0x97EBA78EC690119E, 0xAB911EE392F8B099, 0x18BF525D915FEFF6, 0x5F1528B43AB810C2,
|
||||
0xEC3B640A391F4FAD, 0x27E05A6E926952CC, 0x94CE16D091CE0DA3, 0xD3646C393A29F297, 0x604A2087398EADF8,
|
||||
0x5C3099EA6DE60CFF, 0xEF1ED5546E415390, 0xA8B4AFBDC5A6ACA4, 0x1B9AE303C601F3CB, 0x56ED3E2F9E224471,
|
||||
0xE5C372919D851B1E, 0xA26908783662E42A, 0x114744C635C5BB45, 0x2D3DFDAB61AD1A42, 0x9E13B115620A452D,
|
||||
0xD9B9CBFCC9EDBA19, 0x6A978742CA4AE576, 0xA14CB926613CF817, 0x1262F598629BA778, 0x55C88F71C97C584C,
|
||||
0xE6E6C3CFCADB0723, 0xDA9C7AA29EB3A624, 0x69B2361C9D14F94B, 0x2E184CF536F3067F, 0x9D36004B35545910,
|
||||
0x2B769F17CF112238, 0x9858D3A9CCB67D57, 0xDFF2A94067518263, 0x6CDCE5FE64F6DD0C, 0x50A65C93309E7C0B,
|
||||
0xE388102D33392364, 0xA4226AC498DEDC50, 0x170C267A9B79833F, 0xDCD7181E300F9E5E, 0x6FF954A033A8C131,
|
||||
0x28532E49984F3E05, 0x9B7D62F79BE8616A, 0xA707DB9ACF80C06D, 0x14299724CC279F02, 0x5383EDCD67C06036,
|
||||
0xE0ADA17364673F59
|
||||
},
|
||||
new ulong[]
|
||||
{
|
||||
0x0000000000000000, 0x54E979925CD0F10D, 0xA9D2F324B9A1E21A, 0xFD3B8AB6E5711317, 0xC17D4962DC4DDAB1,
|
||||
0x959430F0809D2BBC, 0x68AFBA4665EC38AB, 0x3C46C3D4393CC9A6, 0x10223DEE1795ABE7, 0x44CB447C4B455AEA,
|
||||
0xB9F0CECAAE3449FD, 0xED19B758F2E4B8F0, 0xD15F748CCBD87156, 0x85B60D1E9708805B, 0x788D87A87279934C,
|
||||
0x2C64FE3A2EA96241, 0x20447BDC2F2B57CE, 0x74AD024E73FBA6C3, 0x899688F8968AB5D4, 0xDD7FF16ACA5A44D9,
|
||||
0xE13932BEF3668D7F, 0xB5D04B2CAFB67C72, 0x48EBC19A4AC76F65, 0x1C02B80816179E68, 0x3066463238BEFC29,
|
||||
0x648F3FA0646E0D24, 0x99B4B516811F1E33, 0xCD5DCC84DDCFEF3E, 0xF11B0F50E4F32698, 0xA5F276C2B823D795,
|
||||
0x58C9FC745D52C482, 0x0C2085E60182358F, 0x4088F7B85E56AF9C, 0x14618E2A02865E91, 0xE95A049CE7F74D86,
|
||||
0xBDB37D0EBB27BC8B, 0x81F5BEDA821B752D, 0xD51CC748DECB8420, 0x28274DFE3BBA9737, 0x7CCE346C676A663A,
|
||||
0x50AACA5649C3047B, 0x0443B3C41513F576, 0xF9783972F062E661, 0xAD9140E0ACB2176C, 0x91D78334958EDECA,
|
||||
0xC53EFAA6C95E2FC7, 0x380570102C2F3CD0, 0x6CEC098270FFCDDD, 0x60CC8C64717DF852, 0x3425F5F62DAD095F,
|
||||
0xC91E7F40C8DC1A48, 0x9DF706D2940CEB45, 0xA1B1C506AD3022E3, 0xF558BC94F1E0D3EE, 0x086336221491C0F9,
|
||||
0x5C8A4FB0484131F4, 0x70EEB18A66E853B5, 0x2407C8183A38A2B8, 0xD93C42AEDF49B1AF, 0x8DD53B3C839940A2,
|
||||
0xB193F8E8BAA58904, 0xE57A817AE6757809, 0x18410BCC03046B1E, 0x4CA8725E5FD49A13, 0x8111EF70BCAD5F38,
|
||||
0xD5F896E2E07DAE35, 0x28C31C54050CBD22, 0x7C2A65C659DC4C2F, 0x406CA61260E08589, 0x1485DF803C307484,
|
||||
0xE9BE5536D9416793, 0xBD572CA48591969E, 0x9133D29EAB38F4DF, 0xC5DAAB0CF7E805D2, 0x38E121BA129916C5,
|
||||
0x6C0858284E49E7C8, 0x504E9BFC77752E6E, 0x04A7E26E2BA5DF63, 0xF99C68D8CED4CC74, 0xAD75114A92043D79,
|
||||
0xA15594AC938608F6, 0xF5BCED3ECF56F9FB, 0x088767882A27EAEC, 0x5C6E1E1A76F71BE1, 0x6028DDCE4FCBD247,
|
||||
0x34C1A45C131B234A, 0xC9FA2EEAF66A305D, 0x9D135778AABAC150, 0xB177A9428413A311, 0xE59ED0D0D8C3521C,
|
||||
0x18A55A663DB2410B, 0x4C4C23F46162B006, 0x700AE020585E79A0, 0x24E399B2048E88AD, 0xD9D81304E1FF9BBA,
|
||||
0x8D316A96BD2F6AB7, 0xC19918C8E2FBF0A4, 0x9570615ABE2B01A9, 0x684BEBEC5B5A12BE, 0x3CA2927E078AE3B3,
|
||||
0x00E451AA3EB62A15, 0x540D28386266DB18, 0xA936A28E8717C80F, 0xFDDFDB1CDBC73902, 0xD1BB2526F56E5B43,
|
||||
0x85525CB4A9BEAA4E, 0x7869D6024CCFB959, 0x2C80AF90101F4854, 0x10C66C44292381F2, 0x442F15D675F370FF,
|
||||
0xB9149F60908263E8, 0xEDFDE6F2CC5292E5, 0xE1DD6314CDD0A76A, 0xB5341A8691005667, 0x480F903074714570,
|
||||
0x1CE6E9A228A1B47D, 0x20A02A76119D7DDB, 0x744953E44D4D8CD6, 0x8972D952A83C9FC1, 0xDD9BA0C0F4EC6ECC,
|
||||
0xF1FF5EFADA450C8D, 0xA51627688695FD80, 0x582DADDE63E4EE97, 0x0CC4D44C3F341F9A, 0x308217980608D63C,
|
||||
0x646B6E0A5AD82731, 0x9950E4BCBFA93426, 0xCDB99D2EE379C52B, 0x90FB71CAD654A0F5, 0xC41208588A8451F8,
|
||||
0x392982EE6FF542EF, 0x6DC0FB7C3325B3E2, 0x518638A80A197A44, 0x056F413A56C98B49, 0xF854CB8CB3B8985E,
|
||||
0xACBDB21EEF686953, 0x80D94C24C1C10B12, 0xD43035B69D11FA1F, 0x290BBF007860E908, 0x7DE2C69224B01805,
|
||||
0x41A405461D8CD1A3, 0x154D7CD4415C20AE, 0xE876F662A42D33B9, 0xBC9F8FF0F8FDC2B4, 0xB0BF0A16F97FF73B,
|
||||
0xE4567384A5AF0636, 0x196DF93240DE1521, 0x4D8480A01C0EE42C, 0x71C2437425322D8A, 0x252B3AE679E2DC87,
|
||||
0xD810B0509C93CF90, 0x8CF9C9C2C0433E9D, 0xA09D37F8EEEA5CDC, 0xF4744E6AB23AADD1, 0x094FC4DC574BBEC6,
|
||||
0x5DA6BD4E0B9B4FCB, 0x61E07E9A32A7866D, 0x350907086E777760, 0xC8328DBE8B066477, 0x9CDBF42CD7D6957A,
|
||||
0xD073867288020F69, 0x849AFFE0D4D2FE64, 0x79A1755631A3ED73, 0x2D480CC46D731C7E, 0x110ECF10544FD5D8,
|
||||
0x45E7B682089F24D5, 0xB8DC3C34EDEE37C2, 0xEC3545A6B13EC6CF, 0xC051BB9C9F97A48E, 0x94B8C20EC3475583,
|
||||
0x698348B826364694, 0x3D6A312A7AE6B799, 0x012CF2FE43DA7E3F, 0x55C58B6C1F0A8F32, 0xA8FE01DAFA7B9C25,
|
||||
0xFC177848A6AB6D28, 0xF037FDAEA72958A7, 0xA4DE843CFBF9A9AA, 0x59E50E8A1E88BABD, 0x0D0C771842584BB0,
|
||||
0x314AB4CC7B648216, 0x65A3CD5E27B4731B, 0x989847E8C2C5600C, 0xCC713E7A9E159101, 0xE015C040B0BCF340,
|
||||
0xB4FCB9D2EC6C024D, 0x49C73364091D115A, 0x1D2E4AF655CDE057, 0x216889226CF129F1, 0x7581F0B03021D8FC,
|
||||
0x88BA7A06D550CBEB, 0xDC53039489803AE6, 0x11EA9EBA6AF9FFCD, 0x4503E72836290EC0, 0xB8386D9ED3581DD7,
|
||||
0xECD1140C8F88ECDA, 0xD097D7D8B6B4257C, 0x847EAE4AEA64D471, 0x794524FC0F15C766, 0x2DAC5D6E53C5366B,
|
||||
0x01C8A3547D6C542A, 0x5521DAC621BCA527, 0xA81A5070C4CDB630, 0xFCF329E2981D473D, 0xC0B5EA36A1218E9B,
|
||||
0x945C93A4FDF17F96, 0x6967191218806C81, 0x3D8E608044509D8C, 0x31AEE56645D2A803, 0x65479CF41902590E,
|
||||
0x987C1642FC734A19, 0xCC956FD0A0A3BB14, 0xF0D3AC04999F72B2, 0xA43AD596C54F83BF, 0x59015F20203E90A8,
|
||||
0x0DE826B27CEE61A5, 0x218CD888524703E4, 0x7565A11A0E97F2E9, 0x885E2BACEBE6E1FE, 0xDCB7523EB73610F3,
|
||||
0xE0F191EA8E0AD955, 0xB418E878D2DA2858, 0x492362CE37AB3B4F, 0x1DCA1B5C6B7BCA42, 0x5162690234AF5051,
|
||||
0x058B1090687FA15C, 0xF8B09A268D0EB24B, 0xAC59E3B4D1DE4346, 0x901F2060E8E28AE0, 0xC4F659F2B4327BED,
|
||||
0x39CDD344514368FA, 0x6D24AAD60D9399F7, 0x414054EC233AFBB6, 0x15A92D7E7FEA0ABB, 0xE892A7C89A9B19AC,
|
||||
0xBC7BDE5AC64BE8A1, 0x803D1D8EFF772107, 0xD4D4641CA3A7D00A, 0x29EFEEAA46D6C31D, 0x7D0697381A063210,
|
||||
0x712612DE1B84079F, 0x25CF6B4C4754F692, 0xD8F4E1FAA225E585, 0x8C1D9868FEF51488, 0xB05B5BBCC7C9DD2E,
|
||||
0xE4B2222E9B192C23, 0x1989A8987E683F34, 0x4D60D10A22B8CE39, 0x61042F300C11AC78, 0x35ED56A250C15D75,
|
||||
0xC8D6DC14B5B04E62, 0x9C3FA586E960BF6F, 0xA0796652D05C76C9, 0xF4901FC08C8C87C4, 0x09AB957669FD94D3,
|
||||
0x5D42ECE4352D65DE
|
||||
},
|
||||
new ulong[]
|
||||
{
|
||||
0x0000000000000000, 0x3F0BE14A916A6DCB, 0x7E17C29522D4DB96, 0x411C23DFB3BEB65D, 0xFC2F852A45A9B72C,
|
||||
0xC3246460D4C3DAE7, 0x823847BF677D6CBA, 0xBD33A6F5F6170171, 0x6A87A57F245D70DD, 0x558C4435B5371D16,
|
||||
0x149067EA0689AB4B, 0x2B9B86A097E3C680, 0x96A8205561F4C7F1, 0xA9A3C11FF09EAA3A, 0xE8BFE2C043201C67,
|
||||
0xD7B4038AD24A71AC, 0xD50F4AFE48BAE1BA, 0xEA04ABB4D9D08C71, 0xAB18886B6A6E3A2C, 0x94136921FB0457E7,
|
||||
0x2920CFD40D135696, 0x162B2E9E9C793B5D, 0x57370D412FC78D00, 0x683CEC0BBEADE0CB, 0xBF88EF816CE79167,
|
||||
0x80830ECBFD8DFCAC, 0xC19F2D144E334AF1, 0xFE94CC5EDF59273A, 0x43A76AAB294E264B, 0x7CAC8BE1B8244B80,
|
||||
0x3DB0A83E0B9AFDDD, 0x02BB49749AF09016, 0x38C63AD73E7BDDF1, 0x07CDDB9DAF11B03A, 0x46D1F8421CAF0667,
|
||||
0x79DA19088DC56BAC, 0xC4E9BFFD7BD26ADD, 0xFBE25EB7EAB80716, 0xBAFE7D685906B14B, 0x85F59C22C86CDC80,
|
||||
0x52419FA81A26AD2C, 0x6D4A7EE28B4CC0E7, 0x2C565D3D38F276BA, 0x135DBC77A9981B71, 0xAE6E1A825F8F1A00,
|
||||
0x9165FBC8CEE577CB, 0xD079D8177D5BC196, 0xEF72395DEC31AC5D, 0xEDC9702976C13C4B, 0xD2C29163E7AB5180,
|
||||
0x93DEB2BC5415E7DD, 0xACD553F6C57F8A16, 0x11E6F50333688B67, 0x2EED1449A202E6AC, 0x6FF1379611BC50F1,
|
||||
0x50FAD6DC80D63D3A, 0x874ED556529C4C96, 0xB845341CC3F6215D, 0xF95917C370489700, 0xC652F689E122FACB,
|
||||
0x7B61507C1735FBBA, 0x446AB136865F9671, 0x057692E935E1202C, 0x3A7D73A3A48B4DE7, 0x718C75AE7CF7BBE2,
|
||||
0x4E8794E4ED9DD629, 0x0F9BB73B5E236074, 0x30905671CF490DBF, 0x8DA3F084395E0CCE, 0xB2A811CEA8346105,
|
||||
0xF3B432111B8AD758, 0xCCBFD35B8AE0BA93, 0x1B0BD0D158AACB3F, 0x2400319BC9C0A6F4, 0x651C12447A7E10A9,
|
||||
0x5A17F30EEB147D62, 0xE72455FB1D037C13, 0xD82FB4B18C6911D8, 0x9933976E3FD7A785, 0xA6387624AEBDCA4E,
|
||||
0xA4833F50344D5A58, 0x9B88DE1AA5273793, 0xDA94FDC5169981CE, 0xE59F1C8F87F3EC05, 0x58ACBA7A71E4ED74,
|
||||
0x67A75B30E08E80BF, 0x26BB78EF533036E2, 0x19B099A5C25A5B29, 0xCE049A2F10102A85, 0xF10F7B65817A474E,
|
||||
0xB01358BA32C4F113, 0x8F18B9F0A3AE9CD8, 0x322B1F0555B99DA9, 0x0D20FE4FC4D3F062, 0x4C3CDD90776D463F,
|
||||
0x73373CDAE6072BF4, 0x494A4F79428C6613, 0x7641AE33D3E60BD8, 0x375D8DEC6058BD85, 0x08566CA6F132D04E,
|
||||
0xB565CA530725D13F, 0x8A6E2B19964FBCF4, 0xCB7208C625F10AA9, 0xF479E98CB49B6762, 0x23CDEA0666D116CE,
|
||||
0x1CC60B4CF7BB7B05, 0x5DDA28934405CD58, 0x62D1C9D9D56FA093, 0xDFE26F2C2378A1E2, 0xE0E98E66B212CC29,
|
||||
0xA1F5ADB901AC7A74, 0x9EFE4CF390C617BF, 0x9C4505870A3687A9, 0xA34EE4CD9B5CEA62, 0xE252C71228E25C3F,
|
||||
0xDD592658B98831F4, 0x606A80AD4F9F3085, 0x5F6161E7DEF55D4E, 0x1E7D42386D4BEB13, 0x2176A372FC2186D8,
|
||||
0xF6C2A0F82E6BF774, 0xC9C941B2BF019ABF, 0x88D5626D0CBF2CE2, 0xB7DE83279DD54129, 0x0AED25D26BC24058,
|
||||
0x35E6C498FAA82D93, 0x74FAE74749169BCE, 0x4BF1060DD87CF605, 0xE318EB5CF9EF77C4, 0xDC130A1668851A0F,
|
||||
0x9D0F29C9DB3BAC52, 0xA204C8834A51C199, 0x1F376E76BC46C0E8, 0x203C8F3C2D2CAD23, 0x6120ACE39E921B7E,
|
||||
0x5E2B4DA90FF876B5, 0x899F4E23DDB20719, 0xB694AF694CD86AD2, 0xF7888CB6FF66DC8F, 0xC8836DFC6E0CB144,
|
||||
0x75B0CB09981BB035, 0x4ABB2A430971DDFE, 0x0BA7099CBACF6BA3, 0x34ACE8D62BA50668, 0x3617A1A2B155967E,
|
||||
0x091C40E8203FFBB5, 0x4800633793814DE8, 0x770B827D02EB2023, 0xCA382488F4FC2152, 0xF533C5C265964C99,
|
||||
0xB42FE61DD628FAC4, 0x8B2407574742970F, 0x5C9004DD9508E6A3, 0x639BE59704628B68, 0x2287C648B7DC3D35,
|
||||
0x1D8C270226B650FE, 0xA0BF81F7D0A1518F, 0x9FB460BD41CB3C44, 0xDEA84362F2758A19, 0xE1A3A228631FE7D2,
|
||||
0xDBDED18BC794AA35, 0xE4D530C156FEC7FE, 0xA5C9131EE54071A3, 0x9AC2F254742A1C68, 0x27F154A1823D1D19,
|
||||
0x18FAB5EB135770D2, 0x59E69634A0E9C68F, 0x66ED777E3183AB44, 0xB15974F4E3C9DAE8, 0x8E5295BE72A3B723,
|
||||
0xCF4EB661C11D017E, 0xF045572B50776CB5, 0x4D76F1DEA6606DC4, 0x727D1094370A000F, 0x3361334B84B4B652,
|
||||
0x0C6AD20115DEDB99, 0x0ED19B758F2E4B8F, 0x31DA7A3F1E442644, 0x70C659E0ADFA9019, 0x4FCDB8AA3C90FDD2,
|
||||
0xF2FE1E5FCA87FCA3, 0xCDF5FF155BED9168, 0x8CE9DCCAE8532735, 0xB3E23D8079394AFE, 0x64563E0AAB733B52,
|
||||
0x5B5DDF403A195699, 0x1A41FC9F89A7E0C4, 0x254A1DD518CD8D0F, 0x9879BB20EEDA8C7E, 0xA7725A6A7FB0E1B5,
|
||||
0xE66E79B5CC0E57E8, 0xD96598FF5D643A23, 0x92949EF28518CC26, 0xAD9F7FB81472A1ED, 0xEC835C67A7CC17B0,
|
||||
0xD388BD2D36A67A7B, 0x6EBB1BD8C0B17B0A, 0x51B0FA9251DB16C1, 0x10ACD94DE265A09C, 0x2FA73807730FCD57,
|
||||
0xF8133B8DA145BCFB, 0xC718DAC7302FD130, 0x8604F9188391676D, 0xB90F185212FB0AA6, 0x043CBEA7E4EC0BD7,
|
||||
0x3B375FED7586661C, 0x7A2B7C32C638D041, 0x45209D785752BD8A, 0x479BD40CCDA22D9C, 0x789035465CC84057,
|
||||
0x398C1699EF76F60A, 0x0687F7D37E1C9BC1, 0xBBB45126880B9AB0, 0x84BFB06C1961F77B, 0xC5A393B3AADF4126,
|
||||
0xFAA872F93BB52CED, 0x2D1C7173E9FF5D41, 0x121790397895308A, 0x530BB3E6CB2B86D7, 0x6C0052AC5A41EB1C,
|
||||
0xD133F459AC56EA6D, 0xEE3815133D3C87A6, 0xAF2436CC8E8231FB, 0x902FD7861FE85C30, 0xAA52A425BB6311D7,
|
||||
0x9559456F2A097C1C, 0xD44566B099B7CA41, 0xEB4E87FA08DDA78A, 0x567D210FFECAA6FB, 0x6976C0456FA0CB30,
|
||||
0x286AE39ADC1E7D6D, 0x176102D04D7410A6, 0xC0D5015A9F3E610A, 0xFFDEE0100E540CC1, 0xBEC2C3CFBDEABA9C,
|
||||
0x81C922852C80D757, 0x3CFA8470DA97D626, 0x03F1653A4BFDBBED, 0x42ED46E5F8430DB0, 0x7DE6A7AF6929607B,
|
||||
0x7F5DEEDBF3D9F06D, 0x40560F9162B39DA6, 0x014A2C4ED10D2BFB, 0x3E41CD0440674630, 0x83726BF1B6704741,
|
||||
0xBC798ABB271A2A8A, 0xFD65A96494A49CD7, 0xC26E482E05CEF11C, 0x15DA4BA4D78480B0, 0x2AD1AAEE46EEED7B,
|
||||
0x6BCD8931F5505B26, 0x54C6687B643A36ED, 0xE9F5CE8E922D379C, 0xD6FE2FC403475A57, 0x97E20C1BB0F9EC0A,
|
||||
0xA8E9ED51219381C1
|
||||
},
|
||||
new ulong[]
|
||||
{
|
||||
0x0000000000000000, 0x1DEE8A5E222CA1DC, 0x3BDD14BC445943B8, 0x26339EE26675E264, 0x77BA297888B28770,
|
||||
0x6A54A326AA9E26AC, 0x4C673DC4CCEBC4C8, 0x5189B79AEEC76514, 0xEF7452F111650EE0, 0xF29AD8AF3349AF3C,
|
||||
0xD4A9464D553C4D58, 0xC947CC137710EC84, 0x98CE7B8999D78990, 0x8520F1D7BBFB284C, 0xA3136F35DD8ECA28,
|
||||
0xBEFDE56BFFA26BF4, 0x4C300AC98DC40345, 0x51DE8097AFE8A299, 0x77ED1E75C99D40FD, 0x6A03942BEBB1E121,
|
||||
0x3B8A23B105768435, 0x2664A9EF275A25E9, 0x0057370D412FC78D, 0x1DB9BD5363036651, 0xA34458389CA10DA5,
|
||||
0xBEAAD266BE8DAC79, 0x98994C84D8F84E1D, 0x8577C6DAFAD4EFC1, 0xD4FE714014138AD5, 0xC910FB1E363F2B09,
|
||||
0xEF2365FC504AC96D, 0xF2CDEFA2726668B1, 0x986015931B88068A, 0x858E9FCD39A4A756, 0xA3BD012F5FD14532,
|
||||
0xBE538B717DFDE4EE, 0xEFDA3CEB933A81FA, 0xF234B6B5B1162026, 0xD4072857D763C242, 0xC9E9A209F54F639E,
|
||||
0x771447620AED086A, 0x6AFACD3C28C1A9B6, 0x4CC953DE4EB44BD2, 0x5127D9806C98EA0E, 0x00AE6E1A825F8F1A,
|
||||
0x1D40E444A0732EC6, 0x3B737AA6C606CCA2, 0x269DF0F8E42A6D7E, 0xD4501F5A964C05CF, 0xC9BE9504B460A413,
|
||||
0xEF8D0BE6D2154677, 0xF26381B8F039E7AB, 0xA3EA36221EFE82BF, 0xBE04BC7C3CD22363, 0x9837229E5AA7C107,
|
||||
0x85D9A8C0788B60DB, 0x3B244DAB87290B2F, 0x26CAC7F5A505AAF3, 0x00F95917C3704897, 0x1D17D349E15CE94B,
|
||||
0x4C9E64D30F9B8C5F, 0x5170EE8D2DB72D83, 0x7743706F4BC2CFE7, 0x6AADFA3169EE6E3B, 0xA218840D981E1391,
|
||||
0xBFF60E53BA32B24D, 0x99C590B1DC475029, 0x842B1AEFFE6BF1F5, 0xD5A2AD7510AC94E1, 0xC84C272B3280353D,
|
||||
0xEE7FB9C954F5D759, 0xF391339776D97685, 0x4D6CD6FC897B1D71, 0x50825CA2AB57BCAD, 0x76B1C240CD225EC9,
|
||||
0x6B5F481EEF0EFF15, 0x3AD6FF8401C99A01, 0x273875DA23E53BDD, 0x010BEB384590D9B9, 0x1CE5616667BC7865,
|
||||
0xEE288EC415DA10D4, 0xF3C6049A37F6B108, 0xD5F59A785183536C, 0xC81B102673AFF2B0, 0x9992A7BC9D6897A4,
|
||||
0x847C2DE2BF443678, 0xA24FB300D931D41C, 0xBFA1395EFB1D75C0, 0x015CDC3504BF1E34, 0x1CB2566B2693BFE8,
|
||||
0x3A81C88940E65D8C, 0x276F42D762CAFC50, 0x76E6F54D8C0D9944, 0x6B087F13AE213898, 0x4D3BE1F1C854DAFC,
|
||||
0x50D56BAFEA787B20, 0x3A78919E8396151B, 0x27961BC0A1BAB4C7, 0x01A58522C7CF56A3, 0x1C4B0F7CE5E3F77F,
|
||||
0x4DC2B8E60B24926B, 0x502C32B8290833B7, 0x761FAC5A4F7DD1D3, 0x6BF126046D51700F, 0xD50CC36F92F31BFB,
|
||||
0xC8E24931B0DFBA27, 0xEED1D7D3D6AA5843, 0xF33F5D8DF486F99F, 0xA2B6EA171A419C8B, 0xBF586049386D3D57,
|
||||
0x996BFEAB5E18DF33, 0x848574F57C347EEF, 0x76489B570E52165E, 0x6BA611092C7EB782, 0x4D958FEB4A0B55E6,
|
||||
0x507B05B56827F43A, 0x01F2B22F86E0912E, 0x1C1C3871A4CC30F2, 0x3A2FA693C2B9D296, 0x27C12CCDE095734A,
|
||||
0x993CC9A61F3718BE, 0x84D243F83D1BB962, 0xA2E1DD1A5B6E5B06, 0xBF0F57447942FADA, 0xEE86E0DE97859FCE,
|
||||
0xF3686A80B5A93E12, 0xD55BF462D3DCDC76, 0xC8B57E3CF1F07DAA, 0xD6E9A7309F3239A7, 0xCB072D6EBD1E987B,
|
||||
0xED34B38CDB6B7A1F, 0xF0DA39D2F947DBC3, 0xA1538E481780BED7, 0xBCBD041635AC1F0B, 0x9A8E9AF453D9FD6F,
|
||||
0x876010AA71F55CB3, 0x399DF5C18E573747, 0x24737F9FAC7B969B, 0x0240E17DCA0E74FF, 0x1FAE6B23E822D523,
|
||||
0x4E27DCB906E5B037, 0x53C956E724C911EB, 0x75FAC80542BCF38F, 0x6814425B60905253, 0x9AD9ADF912F63AE2,
|
||||
0x873727A730DA9B3E, 0xA104B94556AF795A, 0xBCEA331B7483D886, 0xED6384819A44BD92, 0xF08D0EDFB8681C4E,
|
||||
0xD6BE903DDE1DFE2A, 0xCB501A63FC315FF6, 0x75ADFF0803933402, 0x6843755621BF95DE, 0x4E70EBB447CA77BA,
|
||||
0x539E61EA65E6D666, 0x0217D6708B21B372, 0x1FF95C2EA90D12AE, 0x39CAC2CCCF78F0CA, 0x24244892ED545116,
|
||||
0x4E89B2A384BA3F2D, 0x536738FDA6969EF1, 0x7554A61FC0E37C95, 0x68BA2C41E2CFDD49, 0x39339BDB0C08B85D,
|
||||
0x24DD11852E241981, 0x02EE8F674851FBE5, 0x1F0005396A7D5A39, 0xA1FDE05295DF31CD, 0xBC136A0CB7F39011,
|
||||
0x9A20F4EED1867275, 0x87CE7EB0F3AAD3A9, 0xD647C92A1D6DB6BD, 0xCBA943743F411761, 0xED9ADD965934F505,
|
||||
0xF07457C87B1854D9, 0x02B9B86A097E3C68, 0x1F5732342B529DB4, 0x3964ACD64D277FD0, 0x248A26886F0BDE0C,
|
||||
0x7503911281CCBB18, 0x68ED1B4CA3E01AC4, 0x4EDE85AEC595F8A0, 0x53300FF0E7B9597C, 0xEDCDEA9B181B3288,
|
||||
0xF02360C53A379354, 0xD610FE275C427130, 0xCBFE74797E6ED0EC, 0x9A77C3E390A9B5F8, 0x879949BDB2851424,
|
||||
0xA1AAD75FD4F0F640, 0xBC445D01F6DC579C, 0x74F1233D072C2A36, 0x691FA96325008BEA, 0x4F2C37814375698E,
|
||||
0x52C2BDDF6159C852, 0x034B0A458F9EAD46, 0x1EA5801BADB20C9A, 0x38961EF9CBC7EEFE, 0x257894A7E9EB4F22,
|
||||
0x9B8571CC164924D6, 0x866BFB923465850A, 0xA05865705210676E, 0xBDB6EF2E703CC6B2, 0xEC3F58B49EFBA3A6,
|
||||
0xF1D1D2EABCD7027A, 0xD7E24C08DAA2E01E, 0xCA0CC656F88E41C2, 0x38C129F48AE82973, 0x252FA3AAA8C488AF,
|
||||
0x031C3D48CEB16ACB, 0x1EF2B716EC9DCB17, 0x4F7B008C025AAE03, 0x52958AD220760FDF, 0x74A614304603EDBB,
|
||||
0x69489E6E642F4C67, 0xD7B57B059B8D2793, 0xCA5BF15BB9A1864F, 0xEC686FB9DFD4642B, 0xF186E5E7FDF8C5F7,
|
||||
0xA00F527D133FA0E3, 0xBDE1D8233113013F, 0x9BD246C15766E35B, 0x863CCC9F754A4287, 0xEC9136AE1CA42CBC,
|
||||
0xF17FBCF03E888D60, 0xD74C221258FD6F04, 0xCAA2A84C7AD1CED8, 0x9B2B1FD69416ABCC, 0x86C59588B63A0A10,
|
||||
0xA0F60B6AD04FE874, 0xBD188134F26349A8, 0x03E5645F0DC1225C, 0x1E0BEE012FED8380, 0x383870E3499861E4,
|
||||
0x25D6FABD6BB4C038, 0x745F4D278573A52C, 0x69B1C779A75F04F0, 0x4F82599BC12AE694, 0x526CD3C5E3064748,
|
||||
0xA0A13C6791602FF9, 0xBD4FB639B34C8E25, 0x9B7C28DBD5396C41, 0x8692A285F715CD9D, 0xD71B151F19D2A889,
|
||||
0xCAF59F413BFE0955, 0xECC601A35D8BEB31, 0xF1288BFD7FA74AED, 0x4FD56E9680052119, 0x523BE4C8A22980C5,
|
||||
0x74087A2AC45C62A1, 0x69E6F074E670C37D, 0x386F47EE08B7A669, 0x2581CDB02A9B07B5, 0x03B253524CEEE5D1,
|
||||
0x1E5CD90C6EC2440D
|
||||
}
|
||||
};
|
||||
|
||||
readonly ulong _finalSeed;
|
||||
readonly IntPtr _nativeContext;
|
||||
readonly ulong[][]? _table;
|
||||
readonly bool _useEcma;
|
||||
readonly bool _useNative;
|
||||
ulong _hashInt;
|
||||
|
||||
/// <summary>Initializes the CRC64 table and seed as CRC64-ECMA</summary>
|
||||
public Crc64Context()
|
||||
{
|
||||
_hashInt = CRC64_ECMA_SEED;
|
||||
_table = _ecmaCrc64Table;
|
||||
_finalSeed = CRC64_ECMA_SEED;
|
||||
_useEcma = true;
|
||||
|
||||
if(!Native.IsSupported)
|
||||
return;
|
||||
|
||||
_nativeContext = crc64_init();
|
||||
_useNative = _nativeContext != IntPtr.Zero;
|
||||
}
|
||||
|
||||
/// <summary>Initializes the CRC16 table with a custom polynomial and seed</summary>
|
||||
public Crc64Context(ulong polynomial, ulong seed)
|
||||
{
|
||||
_hashInt = seed;
|
||||
_finalSeed = seed;
|
||||
_useEcma = polynomial == CRC64_ECMA_POLY && seed == CRC64_ECMA_SEED;
|
||||
|
||||
if(Native.IsSupported && _useEcma)
|
||||
{
|
||||
_nativeContext = crc64_init();
|
||||
_useNative = _nativeContext != IntPtr.Zero;
|
||||
}
|
||||
else
|
||||
_table = GenerateTable(polynomial);
|
||||
}
|
||||
|
||||
#region IChecksum Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => "CRC-64 (ECMA)";
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Id => new("D0C0D902-420A-45DA-A235-9D48BEE4B1CE");
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Author => "Natalia Portillo";
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>Updates the hash with data.</summary>
|
||||
/// <param name="data">Data buffer.</param>
|
||||
/// <param name="len">Length of buffer to hash.</param>
|
||||
public void Update(byte[] data, uint len) =>
|
||||
Step(ref _hashInt, _table!, data, len, _useEcma, _useNative, _nativeContext);
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>Updates the hash with data.</summary>
|
||||
/// <param name="data">Data buffer.</param>
|
||||
public void Update(byte[] data) => Update(data, (uint)data.Length);
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>Returns a byte array of the hash value.</summary>
|
||||
public byte[] Final()
|
||||
{
|
||||
ulong crc = _hashInt ^ _finalSeed;
|
||||
|
||||
if(!_useNative || !_useEcma)
|
||||
return BigEndianBitConverter.GetBytes(crc);
|
||||
|
||||
crc64_final(_nativeContext, ref crc);
|
||||
crc64_free(_nativeContext);
|
||||
|
||||
return BigEndianBitConverter.GetBytes(crc);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>Returns a hexadecimal representation of the hash value.</summary>
|
||||
public string End()
|
||||
{
|
||||
ulong crc = _hashInt ^ _finalSeed;
|
||||
|
||||
var crc64Output = new StringBuilder();
|
||||
|
||||
if(_useNative && _useEcma)
|
||||
{
|
||||
crc64_final(_nativeContext, ref crc);
|
||||
crc64_free(_nativeContext);
|
||||
}
|
||||
|
||||
for(var i = 0; i < BigEndianBitConverter.GetBytes(crc).Length; i++)
|
||||
crc64Output.Append(BigEndianBitConverter.GetBytes(crc)[i].ToString("x2"));
|
||||
|
||||
return crc64Output.ToString();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
|
||||
static extern IntPtr crc64_init();
|
||||
|
||||
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
|
||||
static extern int crc64_update(IntPtr ctx, byte[] data, uint len);
|
||||
|
||||
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
|
||||
static extern int crc64_final(IntPtr ctx, ref ulong crc);
|
||||
|
||||
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
|
||||
static extern void crc64_free(IntPtr ctx);
|
||||
|
||||
static ulong[][] GenerateTable(ulong polynomial)
|
||||
{
|
||||
var table = new ulong[8][];
|
||||
|
||||
for(var i = 0; i < 8; i++)
|
||||
table[i] = new ulong[256];
|
||||
|
||||
for(var i = 0; i < 256; i++)
|
||||
{
|
||||
var entry = (ulong)i;
|
||||
|
||||
for(var j = 0; j < 8; j++)
|
||||
{
|
||||
if((entry & 1) == 1)
|
||||
entry = entry >> 1 ^ polynomial;
|
||||
else
|
||||
entry >>= 1;
|
||||
}
|
||||
|
||||
table[0][i] = entry;
|
||||
}
|
||||
|
||||
for(var slice = 1; slice < 4; slice++)
|
||||
for(var i = 0; i < 256; i++)
|
||||
table[slice][i] = table[slice - 1][i] >> 8 ^ table[0][table[slice - 1][i] & 0xFF];
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
static void Step(ref ulong previousCrc, ulong[][] table, byte[] data, uint len, bool useEcma, bool useNative,
|
||||
IntPtr nativeContext)
|
||||
{
|
||||
if(useNative && useEcma)
|
||||
{
|
||||
crc64_update(nativeContext, data, len);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var dataOff = 0;
|
||||
|
||||
#if NETCOREAPP3_1_OR_GREATER
|
||||
if(useEcma && Pclmulqdq.IsSupported && Sse41.IsSupported && Ssse3.IsSupported && Sse2.IsSupported)
|
||||
{
|
||||
// Only works in blocks of 32 bytes
|
||||
uint blocks = len / 32;
|
||||
|
||||
if(blocks > 0)
|
||||
{
|
||||
previousCrc = ~Clmul.Step(~previousCrc, data, blocks * 32);
|
||||
|
||||
dataOff = (int)(blocks * 32);
|
||||
len -= blocks * 32;
|
||||
}
|
||||
|
||||
if(len == 0)
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Unroll according to Intel slicing by uint8_t
|
||||
// http://www.intel.com/technology/comms/perfnet/download/CRC_generators.pdf
|
||||
// http://sourceforge.net/projects/slicing-by-8/
|
||||
|
||||
ulong crc = previousCrc;
|
||||
|
||||
if(len > 4)
|
||||
{
|
||||
long limit = dataOff + (len & ~(uint)3);
|
||||
len &= 3;
|
||||
|
||||
while(dataOff < limit)
|
||||
{
|
||||
var tmp = (uint)(crc ^ BitConverter.ToUInt32(data, dataOff));
|
||||
dataOff += 4;
|
||||
|
||||
crc = table[3][tmp & 0xFF] ^
|
||||
table[2][tmp >> 8 & 0xFF] ^
|
||||
crc >> 32 ^
|
||||
table[1][tmp >> 16 & 0xFF] ^
|
||||
table[0][tmp >> 24];
|
||||
}
|
||||
}
|
||||
|
||||
while(len-- != 0)
|
||||
crc = table[0][data[dataOff++] ^ crc & 0xFF] ^ crc >> 8;
|
||||
|
||||
previousCrc = crc;
|
||||
}
|
||||
|
||||
/// <summary>Gets the hash of a file</summary>
|
||||
/// <param name="filename">File path.</param>
|
||||
// ReSharper disable once ReturnTypeCanBeEnumerable.Global
|
||||
public static byte[] File(string filename)
|
||||
{
|
||||
File(filename, out byte[] localHash);
|
||||
|
||||
return localHash;
|
||||
}
|
||||
|
||||
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
|
||||
/// <param name="filename">File path.</param>
|
||||
/// <param name="hash">Byte array of the hash value.</param>
|
||||
public static string File(string filename, out byte[] hash) =>
|
||||
File(filename, out hash, CRC64_ECMA_POLY, CRC64_ECMA_SEED);
|
||||
|
||||
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
|
||||
/// <param name="filename">File path.</param>
|
||||
/// <param name="hash">Byte array of the hash value.</param>
|
||||
/// <param name="polynomial">CRC polynomial</param>
|
||||
/// <param name="seed">CRC seed</param>
|
||||
public static string File(string filename, out byte[] hash, ulong polynomial, ulong seed)
|
||||
{
|
||||
bool useEcma = polynomial == CRC64_ECMA_POLY && seed == CRC64_ECMA_SEED;
|
||||
bool useNative = Native.IsSupported;
|
||||
IntPtr nativeContext = IntPtr.Zero;
|
||||
|
||||
if(useNative && useEcma)
|
||||
{
|
||||
nativeContext = crc64_init();
|
||||
useNative = nativeContext != IntPtr.Zero;
|
||||
}
|
||||
|
||||
var fileStream = new FileStream(filename, FileMode.Open);
|
||||
|
||||
ulong localHashInt = seed;
|
||||
|
||||
ulong[][] localTable = GenerateTable(polynomial);
|
||||
|
||||
var buffer = new byte[65536];
|
||||
int read = fileStream.EnsureRead(buffer, 0, 65536);
|
||||
|
||||
while(read > 0)
|
||||
{
|
||||
Step(ref localHashInt, localTable, buffer, (uint)read, useEcma, useNative, nativeContext);
|
||||
|
||||
read = fileStream.EnsureRead(buffer, 0, 65536);
|
||||
}
|
||||
|
||||
localHashInt ^= seed;
|
||||
|
||||
if(useNative && useEcma)
|
||||
{
|
||||
crc64_final(nativeContext, ref localHashInt);
|
||||
crc64_free(nativeContext);
|
||||
}
|
||||
|
||||
hash = BigEndianBitConverter.GetBytes(localHashInt);
|
||||
|
||||
var crc64Output = new StringBuilder();
|
||||
|
||||
foreach(byte h in hash)
|
||||
crc64Output.Append(h.ToString("x2"));
|
||||
|
||||
fileStream.Close();
|
||||
|
||||
return crc64Output.ToString();
|
||||
}
|
||||
|
||||
/// <summary>Gets the hash of the specified data buffer.</summary>
|
||||
/// <param name="data">Data buffer.</param>
|
||||
/// <param name="len">Length of the data buffer to hash.</param>
|
||||
/// <param name="hash">Byte array of the hash value.</param>
|
||||
public static string Data(byte[] data, uint len, out byte[] hash) =>
|
||||
Data(data, len, out hash, CRC64_ECMA_POLY, CRC64_ECMA_SEED);
|
||||
|
||||
/// <summary>Gets the hash of the specified data buffer.</summary>
|
||||
/// <param name="data">Data buffer.</param>
|
||||
/// <param name="len">Length of the data buffer to hash.</param>
|
||||
/// <param name="hash">Byte array of the hash value.</param>
|
||||
/// <param name="polynomial">CRC polynomial</param>
|
||||
/// <param name="seed">CRC seed</param>
|
||||
public static string Data(byte[] data, uint len, out byte[] hash, ulong polynomial, ulong seed)
|
||||
{
|
||||
bool useEcma = polynomial == CRC64_ECMA_POLY && seed == CRC64_ECMA_SEED;
|
||||
bool useNative = Native.IsSupported;
|
||||
IntPtr nativeContext = IntPtr.Zero;
|
||||
|
||||
if(useNative && useEcma)
|
||||
{
|
||||
nativeContext = crc64_init();
|
||||
useNative = nativeContext != IntPtr.Zero;
|
||||
}
|
||||
|
||||
ulong localHashInt = seed;
|
||||
|
||||
ulong[][] localTable = GenerateTable(polynomial);
|
||||
|
||||
Step(ref localHashInt, localTable, data, len, useEcma, useNative, nativeContext);
|
||||
|
||||
localHashInt ^= seed;
|
||||
|
||||
if(useNative && useEcma)
|
||||
{
|
||||
crc64_final(nativeContext, ref localHashInt);
|
||||
crc64_free(nativeContext);
|
||||
}
|
||||
|
||||
hash = BigEndianBitConverter.GetBytes(localHashInt);
|
||||
|
||||
var crc64Output = new StringBuilder();
|
||||
|
||||
foreach(byte h in hash)
|
||||
crc64Output.Append(h.ToString("x2"));
|
||||
|
||||
return crc64Output.ToString();
|
||||
}
|
||||
|
||||
/// <summary>Gets the hash of the specified data buffer.</summary>
|
||||
/// <param name="data">Data buffer.</param>
|
||||
/// <param name="hash">Byte array of the hash value.</param>
|
||||
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
|
||||
}
|
||||
@@ -1,219 +0,0 @@
|
||||
// /***************************************************************************
|
||||
// Aaru Data Preservation Suite
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : neon.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
// The Chromium Authors
|
||||
//
|
||||
// Component : Checksums.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Compute Fletcher32 checksum using NEON vectorization.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2023 Natalia Portillo
|
||||
// Copyright 2017 The Chromium Authors. All rights reserved.
|
||||
// ****************************************************************************/
|
||||
|
||||
#if NET5_0_OR_GREATER
|
||||
using System.Runtime.Intrinsics;
|
||||
using System.Runtime.Intrinsics.Arm;
|
||||
|
||||
namespace Aaru.Checksums.Fletcher32;
|
||||
|
||||
static class Neon
|
||||
{
|
||||
internal static void Step(ref ushort preSum1, ref ushort preSum2, byte[] buf, uint len)
|
||||
{
|
||||
/*
|
||||
* Split Fletcher-32 into component sums.
|
||||
*/
|
||||
uint s1 = preSum1;
|
||||
uint s2 = preSum2;
|
||||
|
||||
var bufPos = 0;
|
||||
|
||||
/*
|
||||
* Process the data in blocks.
|
||||
*/
|
||||
const uint block_Size = 1 << 5;
|
||||
uint blocks = len / block_Size;
|
||||
len -= blocks * block_Size;
|
||||
|
||||
while(blocks != 0)
|
||||
{
|
||||
uint n = Fletcher32Context.NMAX / block_Size; /* The NMAX constraint. */
|
||||
|
||||
if(n > blocks)
|
||||
n = blocks;
|
||||
|
||||
blocks -= n;
|
||||
/*
|
||||
* Process n blocks of data. At most NMAX data bytes can be
|
||||
* processed before s2 must be reduced modulo FLETCHER_MODULE.
|
||||
*/
|
||||
var v_S2 = Vector128.Create(s1 * n, 0, 0, 0);
|
||||
var v_S1 = Vector128.Create(0u, 0, 0, 0);
|
||||
Vector128<ushort> v_Column_Sum_1 = AdvSimd.DuplicateToVector128((ushort)0);
|
||||
Vector128<ushort> v_Column_Sum_2 = AdvSimd.DuplicateToVector128((ushort)0);
|
||||
Vector128<ushort> v_Column_Sum_3 = AdvSimd.DuplicateToVector128((ushort)0);
|
||||
Vector128<ushort> v_Column_Sum_4 = AdvSimd.DuplicateToVector128((ushort)0);
|
||||
|
||||
do
|
||||
{
|
||||
/*
|
||||
* Load 32 input bytes.
|
||||
*/
|
||||
var bytes1 = Vector128.Create(buf[bufPos], buf[bufPos + 1], buf[bufPos + 2], buf[bufPos + 3],
|
||||
buf[bufPos + 4], buf[bufPos + 5], buf[bufPos + 6], buf[bufPos + 7],
|
||||
buf[bufPos + 8], buf[bufPos + 9], buf[bufPos + 10], buf[bufPos + 11],
|
||||
buf[bufPos + 12], buf[bufPos + 13], buf[bufPos + 14], buf[bufPos + 15]);
|
||||
|
||||
bufPos += 16;
|
||||
|
||||
var bytes2 = Vector128.Create(buf[bufPos], buf[bufPos + 1], buf[bufPos + 2], buf[bufPos + 3],
|
||||
buf[bufPos + 4], buf[bufPos + 5], buf[bufPos + 6], buf[bufPos + 7],
|
||||
buf[bufPos + 8], buf[bufPos + 9], buf[bufPos + 10], buf[bufPos + 11],
|
||||
buf[bufPos + 12], buf[bufPos + 13], buf[bufPos + 14], buf[bufPos + 15]);
|
||||
|
||||
bufPos += 16;
|
||||
/*
|
||||
* Add previous block byte sum to v_s2.
|
||||
*/
|
||||
v_S2 = AdvSimd.Add(v_S2, v_S1);
|
||||
|
||||
/*
|
||||
* Horizontally add the bytes for s1.
|
||||
*/
|
||||
v_S1 =
|
||||
AdvSimd.AddPairwiseWideningAndAdd(v_S1,
|
||||
AdvSimd.
|
||||
AddPairwiseWideningAndAdd(AdvSimd.AddPairwiseWidening(bytes1),
|
||||
bytes2));
|
||||
|
||||
/*
|
||||
* Vertically add the bytes for s2.
|
||||
*/
|
||||
v_Column_Sum_1 = AdvSimd.AddWideningLower(v_Column_Sum_1, bytes1.GetLower());
|
||||
v_Column_Sum_2 = AdvSimd.AddWideningLower(v_Column_Sum_2, bytes1.GetUpper());
|
||||
v_Column_Sum_3 = AdvSimd.AddWideningLower(v_Column_Sum_3, bytes2.GetLower());
|
||||
v_Column_Sum_4 = AdvSimd.AddWideningLower(v_Column_Sum_4, bytes2.GetUpper());
|
||||
} while(--n != 0);
|
||||
|
||||
v_S2 = AdvSimd.ShiftLeftLogical(v_S2, 5);
|
||||
|
||||
/*
|
||||
* Multiply-add bytes by [ 32, 31, 30, ... ] for s2.
|
||||
*/
|
||||
v_S2 = AdvSimd.MultiplyWideningLowerAndAdd(v_S2, v_Column_Sum_1.GetLower(),
|
||||
Vector64.Create((ushort)32, 31, 30, 29));
|
||||
|
||||
v_S2 = AdvSimd.MultiplyWideningLowerAndAdd(v_S2, v_Column_Sum_1.GetUpper(),
|
||||
Vector64.Create((ushort)28, 27, 26, 25));
|
||||
|
||||
v_S2 = AdvSimd.MultiplyWideningLowerAndAdd(v_S2, v_Column_Sum_2.GetLower(),
|
||||
Vector64.Create((ushort)24, 23, 22, 21));
|
||||
|
||||
v_S2 = AdvSimd.MultiplyWideningLowerAndAdd(v_S2, v_Column_Sum_2.GetUpper(),
|
||||
Vector64.Create((ushort)20, 19, 18, 17));
|
||||
|
||||
v_S2 = AdvSimd.MultiplyWideningLowerAndAdd(v_S2, v_Column_Sum_3.GetLower(),
|
||||
Vector64.Create((ushort)16, 15, 14, 13));
|
||||
|
||||
v_S2 = AdvSimd.MultiplyWideningLowerAndAdd(v_S2, v_Column_Sum_3.GetUpper(),
|
||||
Vector64.Create((ushort)12, 11, 10, 9));
|
||||
|
||||
v_S2 = AdvSimd.MultiplyWideningLowerAndAdd(v_S2, v_Column_Sum_4.GetLower(),
|
||||
Vector64.Create((ushort)8, 7, 6, 5));
|
||||
|
||||
v_S2 = AdvSimd.MultiplyWideningLowerAndAdd(v_S2, v_Column_Sum_4.GetUpper(),
|
||||
Vector64.Create((ushort)4, 3, 2, 1));
|
||||
|
||||
/*
|
||||
* Sum epi32 ints v_s1(s2) and accumulate in s1(s2).
|
||||
*/
|
||||
Vector64<uint> sum1 = AdvSimd.AddPairwise(v_S1.GetLower(), v_S1.GetUpper());
|
||||
Vector64<uint> sum2 = AdvSimd.AddPairwise(v_S2.GetLower(), v_S2.GetUpper());
|
||||
Vector64<uint> s1S2 = AdvSimd.AddPairwise(sum1, sum2);
|
||||
s1 += AdvSimd.Extract(s1S2, 0);
|
||||
s2 += AdvSimd.Extract(s1S2, 1);
|
||||
/*
|
||||
* Reduce.
|
||||
*/
|
||||
s1 %= Fletcher32Context.FLETCHER_MODULE;
|
||||
s2 %= Fletcher32Context.FLETCHER_MODULE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle leftover data.
|
||||
*/
|
||||
if(len != 0)
|
||||
{
|
||||
if(len >= 16)
|
||||
{
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
len -= 16;
|
||||
}
|
||||
|
||||
while(len-- != 0)
|
||||
s2 += s1 += buf[bufPos++];
|
||||
|
||||
if(s1 >= Fletcher32Context.FLETCHER_MODULE)
|
||||
s1 -= Fletcher32Context.FLETCHER_MODULE;
|
||||
|
||||
s2 %= Fletcher32Context.FLETCHER_MODULE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the recombined sums.
|
||||
*/
|
||||
preSum1 = (ushort)(s1 & 0xFFFF);
|
||||
preSum2 = (ushort)(s2 & 0xFFFF);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,193 +0,0 @@
|
||||
// /***************************************************************************
|
||||
// Aaru Data Preservation Suite
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : ssse3.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
// The Chromium Authors
|
||||
//
|
||||
// Component : Checksums.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Compute Fletcher32 checksum using SSSE3 vectorization.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2023 Natalia Portillo
|
||||
// Copyright 2017 The Chromium Authors. All rights reserved.
|
||||
// ****************************************************************************/
|
||||
|
||||
#if NETCOREAPP3_1_OR_GREATER
|
||||
using System;
|
||||
using System.Runtime.Intrinsics;
|
||||
using System.Runtime.Intrinsics.X86;
|
||||
|
||||
namespace Aaru.Checksums.Fletcher32;
|
||||
|
||||
static class Ssse3
|
||||
{
|
||||
internal static void Step(ref ushort sum1, ref ushort sum2, byte[] buf, uint len)
|
||||
{
|
||||
uint s1 = sum1;
|
||||
uint s2 = sum2;
|
||||
var bufPos = 0;
|
||||
|
||||
/*
|
||||
* Process the data in blocks.
|
||||
*/
|
||||
const uint block_Size = 1 << 5;
|
||||
uint blocks = len / block_Size;
|
||||
len -= blocks * block_Size;
|
||||
|
||||
while(blocks != 0)
|
||||
{
|
||||
uint n = Fletcher32Context.NMAX / block_Size; /* The NMAX constraint. */
|
||||
|
||||
if(n > blocks)
|
||||
n = blocks;
|
||||
|
||||
blocks -= n;
|
||||
|
||||
Vector128<byte> tap1 = Vector128.Create(32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17).
|
||||
AsByte();
|
||||
|
||||
Vector128<byte> tap2 = Vector128.Create(16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1).AsByte();
|
||||
Vector128<byte> zero = Vector128.Create(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0).AsByte();
|
||||
var ones = Vector128.Create(1, 1, 1, 1, 1, 1, 1, 1);
|
||||
/*
|
||||
* Process n blocks of data. At most NMAX data bytes can be
|
||||
* processed before s2 must be reduced modulo BASE.
|
||||
*/
|
||||
var v_Ps = Vector128.Create(s1 * n, 0, 0, 0);
|
||||
var v_S2 = Vector128.Create(s2, 0, 0, 0);
|
||||
var v_S1 = Vector128.Create(0u, 0, 0, 0);
|
||||
|
||||
do
|
||||
{
|
||||
/*
|
||||
* Load 32 input bytes.
|
||||
*/
|
||||
var bytes1 = Vector128.Create(BitConverter.ToUInt32(buf, bufPos),
|
||||
BitConverter.ToUInt32(buf, bufPos + 4),
|
||||
BitConverter.ToUInt32(buf, bufPos + 8),
|
||||
BitConverter.ToUInt32(buf, bufPos + 12));
|
||||
|
||||
bufPos += 16;
|
||||
|
||||
var bytes2 = Vector128.Create(BitConverter.ToUInt32(buf, bufPos),
|
||||
BitConverter.ToUInt32(buf, bufPos + 4),
|
||||
BitConverter.ToUInt32(buf, bufPos + 8),
|
||||
BitConverter.ToUInt32(buf, bufPos + 12));
|
||||
|
||||
bufPos += 16;
|
||||
|
||||
/*
|
||||
* Add previous block byte sum to v_ps.
|
||||
*/
|
||||
v_Ps = Sse2.Add(v_Ps, v_S1);
|
||||
/*
|
||||
* Horizontally add the bytes for s1, multiply-adds the
|
||||
* bytes by [ 32, 31, 30, ... ] for s2.
|
||||
*/
|
||||
v_S1 = Sse2.Add(v_S1, Sse2.SumAbsoluteDifferences(bytes1.AsByte(), zero).AsUInt32());
|
||||
|
||||
Vector128<short> mad1 =
|
||||
System.Runtime.Intrinsics.X86.Ssse3.MultiplyAddAdjacent(bytes1.AsByte(), tap1.AsSByte());
|
||||
|
||||
v_S2 = Sse2.Add(v_S2, Sse2.MultiplyAddAdjacent(mad1.AsInt16(), ones.AsInt16()).AsUInt32());
|
||||
v_S1 = Sse2.Add(v_S1, Sse2.SumAbsoluteDifferences(bytes2.AsByte(), zero).AsUInt32());
|
||||
|
||||
Vector128<short> mad2 =
|
||||
System.Runtime.Intrinsics.X86.Ssse3.MultiplyAddAdjacent(bytes2.AsByte(), tap2.AsSByte());
|
||||
|
||||
v_S2 = Sse2.Add(v_S2, Sse2.MultiplyAddAdjacent(mad2.AsInt16(), ones.AsInt16()).AsUInt32());
|
||||
} while(--n != 0);
|
||||
|
||||
v_S2 = Sse2.Add(v_S2, Sse2.ShiftLeftLogical(v_Ps, 5));
|
||||
/*
|
||||
* Sum epi32 ints v_s1(s2) and accumulate in s1(s2).
|
||||
*/
|
||||
v_S1 = Sse2.Add(v_S1, Sse2.Shuffle(v_S1, 177));
|
||||
v_S1 = Sse2.Add(v_S1, Sse2.Shuffle(v_S1, 78));
|
||||
s1 += (uint)Sse2.ConvertToInt32(v_S1.AsInt32());
|
||||
v_S2 = Sse2.Add(v_S2, Sse2.Shuffle(v_S2, 177));
|
||||
v_S2 = Sse2.Add(v_S2, Sse2.Shuffle(v_S2, 78));
|
||||
s2 = (uint)Sse2.ConvertToInt32(v_S2.AsInt32());
|
||||
/*
|
||||
* Reduce.
|
||||
*/
|
||||
s1 %= Fletcher32Context.FLETCHER_MODULE;
|
||||
s2 %= Fletcher32Context.FLETCHER_MODULE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle leftover data.
|
||||
*/
|
||||
if(len != 0)
|
||||
{
|
||||
if(len >= 16)
|
||||
{
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
s2 += s1 += buf[bufPos++];
|
||||
len -= 16;
|
||||
}
|
||||
|
||||
while(len-- != 0)
|
||||
s2 += s1 += buf[bufPos++];
|
||||
|
||||
if(s1 >= Fletcher32Context.FLETCHER_MODULE)
|
||||
s1 -= Fletcher32Context.FLETCHER_MODULE;
|
||||
|
||||
s2 %= Fletcher32Context.FLETCHER_MODULE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the recombined sums.
|
||||
*/
|
||||
sum1 = (ushort)(s1 & 0xFFFF);
|
||||
sum2 = (ushort)(s2 & 0xFFFF);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,777 +0,0 @@
|
||||
// /***************************************************************************
|
||||
// Aaru Data Preservation Suite
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : FletcherContext.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Checksums.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Implements Fletcher-32 and Fletcher-16 algorithms.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2023 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
// Disabled because the speed is abnormally slow
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
#if NET5_0_OR_GREATER
|
||||
using System.Runtime.Intrinsics.Arm;
|
||||
#endif
|
||||
using System.Text;
|
||||
#if NETCOREAPP3_1_OR_GREATER
|
||||
using Aaru.Checksums.Fletcher32;
|
||||
#endif
|
||||
using Aaru.CommonTypes.Interfaces;
|
||||
using Aaru.Helpers;
|
||||
#if NETCOREAPP3_1_OR_GREATER
|
||||
using Ssse3 = System.Runtime.Intrinsics.X86.Ssse3;
|
||||
#endif
|
||||
|
||||
namespace Aaru.Checksums;
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>Implements the Fletcher-32 algorithm</summary>
|
||||
[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")]
|
||||
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
|
||||
[SuppressMessage("ReSharper", "UnusedMember.Global")]
|
||||
public sealed class Fletcher32Context : IChecksum
|
||||
{
|
||||
internal const ushort FLETCHER_MODULE = 0xFFFF;
|
||||
internal const uint NMAX = 5552;
|
||||
readonly IntPtr _nativeContext;
|
||||
readonly bool _useNative;
|
||||
ushort _sum1, _sum2;
|
||||
|
||||
/// <summary>Initializes the Fletcher-32 sums</summary>
|
||||
public Fletcher32Context()
|
||||
{
|
||||
_sum1 = 0xFFFF;
|
||||
_sum2 = 0xFFFF;
|
||||
|
||||
if(!Native.IsSupported)
|
||||
return;
|
||||
|
||||
_nativeContext = fletcher32_init();
|
||||
_useNative = _nativeContext != IntPtr.Zero;
|
||||
}
|
||||
|
||||
#region IChecksum Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => "Fletcher-32";
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Id => new("0E51B39F-C5E6-4CED-9E59-BA5A42B3B2F4");
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Author => "Natalia Portillo";
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>Updates the hash with data.</summary>
|
||||
/// <param name="data">Data buffer.</param>
|
||||
/// <param name="len">Length of buffer to hash.</param>
|
||||
public void Update(byte[] data, uint len) => Step(ref _sum1, ref _sum2, data, len, _useNative, _nativeContext);
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>Updates the hash with data.</summary>
|
||||
/// <param name="data">Data buffer.</param>
|
||||
public void Update(byte[] data) => Update(data, (uint)data.Length);
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>Returns a byte array of the hash value.</summary>
|
||||
public byte[] Final()
|
||||
{
|
||||
var finalSum = (uint)(_sum2 << 16 | _sum1);
|
||||
|
||||
if(!_useNative)
|
||||
return BigEndianBitConverter.GetBytes(finalSum);
|
||||
|
||||
fletcher32_final(_nativeContext, ref finalSum);
|
||||
fletcher32_free(_nativeContext);
|
||||
|
||||
return BigEndianBitConverter.GetBytes(finalSum);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>Returns a hexadecimal representation of the hash value.</summary>
|
||||
public string End()
|
||||
{
|
||||
var finalSum = (uint)(_sum2 << 16 | _sum1);
|
||||
|
||||
if(_useNative)
|
||||
{
|
||||
fletcher32_final(_nativeContext, ref finalSum);
|
||||
fletcher32_free(_nativeContext);
|
||||
}
|
||||
|
||||
var fletcherOutput = new StringBuilder();
|
||||
|
||||
for(var i = 0; i < BigEndianBitConverter.GetBytes(finalSum).Length; i++)
|
||||
fletcherOutput.Append(BigEndianBitConverter.GetBytes(finalSum)[i].ToString("x2"));
|
||||
|
||||
return fletcherOutput.ToString();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
|
||||
static extern IntPtr fletcher32_init();
|
||||
|
||||
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
|
||||
static extern int fletcher32_update(IntPtr ctx, byte[] data, uint len);
|
||||
|
||||
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
|
||||
static extern int fletcher32_final(IntPtr ctx, ref uint crc);
|
||||
|
||||
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
|
||||
static extern void fletcher32_free(IntPtr ctx);
|
||||
|
||||
static void Step(ref ushort previousSum1, ref ushort previousSum2, byte[] data, uint len, bool useNative,
|
||||
IntPtr nativeContext)
|
||||
{
|
||||
if(useNative)
|
||||
{
|
||||
fletcher32_update(nativeContext, data, len);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#if NETCOREAPP3_1_OR_GREATER
|
||||
if(Ssse3.IsSupported)
|
||||
{
|
||||
Fletcher32.Ssse3.Step(ref previousSum1, ref previousSum2, data, len);
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NET5_0_OR_GREATER
|
||||
if(AdvSimd.IsSupported)
|
||||
{
|
||||
Neon.Step(ref previousSum1, ref previousSum2, data, len);
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint sum1 = previousSum1;
|
||||
uint sum2 = previousSum2;
|
||||
var dataOff = 0;
|
||||
|
||||
switch(len)
|
||||
{
|
||||
/* in case user likes doing a byte at a time, keep it fast */
|
||||
case 1:
|
||||
{
|
||||
sum1 += data[dataOff];
|
||||
|
||||
if(sum1 >= FLETCHER_MODULE)
|
||||
sum1 -= FLETCHER_MODULE;
|
||||
|
||||
sum2 += sum1;
|
||||
|
||||
if(sum2 >= FLETCHER_MODULE)
|
||||
sum2 -= FLETCHER_MODULE;
|
||||
|
||||
previousSum1 = (ushort)(sum1 & 0xFFFF);
|
||||
previousSum2 = (ushort)(sum2 & 0xFFFF);
|
||||
|
||||
return;
|
||||
}
|
||||
/* in case short lengths are provided, keep it somewhat fast */
|
||||
case < 16:
|
||||
{
|
||||
while(len-- > 0)
|
||||
{
|
||||
sum1 += data[dataOff++];
|
||||
sum2 += sum1;
|
||||
}
|
||||
|
||||
if(sum1 >= FLETCHER_MODULE)
|
||||
sum1 -= FLETCHER_MODULE;
|
||||
|
||||
sum2 %= FLETCHER_MODULE; /* only added so many FLETCHER_MODULE's */
|
||||
previousSum1 = (ushort)(sum1 & 0xFFFF);
|
||||
previousSum2 = (ushort)(sum2 & 0xFFFF);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* do length NMAX blocks -- requires just one modulo operation */
|
||||
while(len >= NMAX)
|
||||
{
|
||||
len -= NMAX;
|
||||
uint n = NMAX / 16;
|
||||
|
||||
do
|
||||
{
|
||||
sum1 += data[dataOff];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 1];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 2];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 2 + 1];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 4];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 4 + 1];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 4 + 2];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 4 + 2 + 1];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 8];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 8 + 1];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 8 + 2];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 8 + 2 + 1];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 8 + 4];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 8 + 4 + 1];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 8 + 4 + 2];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 8 + 4 + 2 + 1];
|
||||
sum2 += sum1;
|
||||
|
||||
/* 16 sums unrolled */
|
||||
dataOff += 16;
|
||||
} while(--n != 0);
|
||||
|
||||
sum1 %= FLETCHER_MODULE;
|
||||
sum2 %= FLETCHER_MODULE;
|
||||
}
|
||||
|
||||
/* do remaining bytes (less than NMAX, still just one modulo) */
|
||||
if(len != 0)
|
||||
{
|
||||
/* avoid modulos if none remaining */
|
||||
while(len >= 16)
|
||||
{
|
||||
len -= 16;
|
||||
sum1 += data[dataOff];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 1];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 2];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 2 + 1];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 4];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 4 + 1];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 4 + 2];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 4 + 2 + 1];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 8];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 8 + 1];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 8 + 2];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 8 + 2 + 1];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 8 + 4];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 8 + 4 + 1];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 8 + 4 + 2];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 8 + 4 + 2 + 1];
|
||||
sum2 += sum1;
|
||||
|
||||
dataOff += 16;
|
||||
}
|
||||
|
||||
while(len-- != 0)
|
||||
{
|
||||
sum1 += data[dataOff++];
|
||||
sum2 += sum1;
|
||||
}
|
||||
|
||||
sum1 %= FLETCHER_MODULE;
|
||||
sum2 %= FLETCHER_MODULE;
|
||||
}
|
||||
|
||||
previousSum1 = (ushort)(sum1 & 0xFFFF);
|
||||
previousSum2 = (ushort)(sum2 & 0xFFFF);
|
||||
}
|
||||
|
||||
/// <summary>Gets the hash of a file</summary>
|
||||
/// <param name="filename">File path.</param>
|
||||
public static byte[] File(string filename)
|
||||
{
|
||||
File(filename, out byte[] hash);
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
|
||||
/// <param name="filename">File path.</param>
|
||||
/// <param name="hash">Byte array of the hash value.</param>
|
||||
public static string File(string filename, out byte[] hash)
|
||||
{
|
||||
bool useNative = Native.IsSupported;
|
||||
IntPtr nativeContext = IntPtr.Zero;
|
||||
|
||||
if(useNative)
|
||||
{
|
||||
nativeContext = fletcher32_init();
|
||||
|
||||
if(nativeContext == IntPtr.Zero)
|
||||
useNative = false;
|
||||
}
|
||||
|
||||
var fileStream = new FileStream(filename, FileMode.Open);
|
||||
|
||||
ushort localSum1 = 0xFFFF;
|
||||
ushort localSum2 = 0xFFFF;
|
||||
|
||||
var buffer = new byte[65536];
|
||||
int read = fileStream.EnsureRead(buffer, 0, 65536);
|
||||
|
||||
while(read > 0)
|
||||
{
|
||||
Step(ref localSum1, ref localSum2, buffer, (uint)read, useNative, nativeContext);
|
||||
|
||||
read = fileStream.EnsureRead(buffer, 0, 65536);
|
||||
}
|
||||
|
||||
var finalSum = (uint)(localSum2 << 16 | localSum1);
|
||||
|
||||
if(useNative)
|
||||
{
|
||||
fletcher32_final(nativeContext, ref finalSum);
|
||||
fletcher32_free(nativeContext);
|
||||
}
|
||||
|
||||
hash = BigEndianBitConverter.GetBytes(finalSum);
|
||||
|
||||
var fletcherOutput = new StringBuilder();
|
||||
|
||||
foreach(byte h in hash)
|
||||
fletcherOutput.Append(h.ToString("x2"));
|
||||
|
||||
fileStream.Close();
|
||||
|
||||
return fletcherOutput.ToString();
|
||||
}
|
||||
|
||||
/// <summary>Gets the hash of the specified data buffer.</summary>
|
||||
/// <param name="data">Data buffer.</param>
|
||||
/// <param name="len">Length of the data buffer to hash.</param>
|
||||
/// <param name="hash">Byte array of the hash value.</param>
|
||||
public static string Data(byte[] data, uint len, out byte[] hash)
|
||||
{
|
||||
bool useNative = Native.IsSupported;
|
||||
IntPtr nativeContext = IntPtr.Zero;
|
||||
|
||||
if(useNative)
|
||||
{
|
||||
nativeContext = fletcher32_init();
|
||||
|
||||
if(nativeContext == IntPtr.Zero)
|
||||
useNative = false;
|
||||
}
|
||||
|
||||
ushort localSum1 = 0xFFFF;
|
||||
ushort localSum2 = 0xFFFF;
|
||||
|
||||
Step(ref localSum1, ref localSum2, data, len, useNative, nativeContext);
|
||||
|
||||
var finalSum = (uint)(localSum2 << 16 | localSum1);
|
||||
|
||||
if(useNative)
|
||||
{
|
||||
fletcher32_final(nativeContext, ref finalSum);
|
||||
fletcher32_free(nativeContext);
|
||||
}
|
||||
|
||||
hash = BigEndianBitConverter.GetBytes(finalSum);
|
||||
|
||||
var adlerOutput = new StringBuilder();
|
||||
|
||||
foreach(byte h in hash)
|
||||
adlerOutput.Append(h.ToString("x2"));
|
||||
|
||||
return adlerOutput.ToString();
|
||||
}
|
||||
|
||||
/// <summary>Gets the hash of the specified data buffer.</summary>
|
||||
/// <param name="data">Data buffer.</param>
|
||||
/// <param name="hash">Byte array of the hash value.</param>
|
||||
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>Implements the Fletcher-16 algorithm</summary>
|
||||
[SuppressMessage("ReSharper", "UnusedMember.Global")]
|
||||
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
|
||||
[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")]
|
||||
public sealed class Fletcher16Context : IChecksum
|
||||
{
|
||||
const byte FLETCHER_MODULE = 0xFF;
|
||||
const byte NMAX = 22;
|
||||
|
||||
readonly IntPtr _nativeContext;
|
||||
readonly bool _useNative;
|
||||
byte _sum1, _sum2;
|
||||
|
||||
/// <summary>Initializes the Fletcher-16 sums</summary>
|
||||
public Fletcher16Context()
|
||||
{
|
||||
_sum1 = 0xFF;
|
||||
_sum2 = 0xFF;
|
||||
|
||||
if(!Native.IsSupported)
|
||||
return;
|
||||
|
||||
_nativeContext = fletcher16_init();
|
||||
_useNative = _nativeContext != IntPtr.Zero;
|
||||
}
|
||||
|
||||
#region IChecksum Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => "Fletcher-16";
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Id => new("80C51F1D-71F8-4741-A0CF-18FA8102EE4B");
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Author => "Natalia Portillo";
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>Updates the hash with data.</summary>
|
||||
/// <param name="data">Data buffer.</param>
|
||||
/// <param name="len">Length of buffer to hash.</param>
|
||||
public void Update(byte[] data, uint len) => Step(ref _sum1, ref _sum2, data, len, _useNative, _nativeContext);
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>Updates the hash with data.</summary>
|
||||
/// <param name="data">Data buffer.</param>
|
||||
public void Update(byte[] data) => Update(data, (uint)data.Length);
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>Returns a byte array of the hash value.</summary>
|
||||
public byte[] Final()
|
||||
{
|
||||
var finalSum = (ushort)(_sum2 << 8 | _sum1);
|
||||
|
||||
if(!_useNative)
|
||||
return BigEndianBitConverter.GetBytes(finalSum);
|
||||
|
||||
fletcher16_final(_nativeContext, ref finalSum);
|
||||
fletcher16_free(_nativeContext);
|
||||
|
||||
return BigEndianBitConverter.GetBytes(finalSum);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>Returns a hexadecimal representation of the hash value.</summary>
|
||||
public string End()
|
||||
{
|
||||
var finalSum = (ushort)(_sum2 << 8 | _sum1);
|
||||
|
||||
if(_useNative)
|
||||
{
|
||||
fletcher16_final(_nativeContext, ref finalSum);
|
||||
fletcher16_free(_nativeContext);
|
||||
}
|
||||
|
||||
var fletcherOutput = new StringBuilder();
|
||||
|
||||
for(var i = 0; i < BigEndianBitConverter.GetBytes(finalSum).Length; i++)
|
||||
fletcherOutput.Append(BigEndianBitConverter.GetBytes(finalSum)[i].ToString("x2"));
|
||||
|
||||
return fletcherOutput.ToString();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
|
||||
static extern IntPtr fletcher16_init();
|
||||
|
||||
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
|
||||
static extern int fletcher16_update(IntPtr ctx, byte[] data, uint len);
|
||||
|
||||
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
|
||||
static extern int fletcher16_final(IntPtr ctx, ref ushort checksum);
|
||||
|
||||
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
|
||||
static extern void fletcher16_free(IntPtr ctx);
|
||||
|
||||
static void Step(ref byte previousSum1, ref byte previousSum2, byte[] data, uint len, bool useNative,
|
||||
IntPtr nativeContext)
|
||||
{
|
||||
if(useNative)
|
||||
{
|
||||
fletcher16_update(nativeContext, data, len);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
uint sum1 = previousSum1;
|
||||
uint sum2 = previousSum2;
|
||||
var dataOff = 0;
|
||||
|
||||
switch(len)
|
||||
{
|
||||
/* in case user likes doing a byte at a time, keep it fast */
|
||||
case 1:
|
||||
{
|
||||
sum1 += data[dataOff];
|
||||
|
||||
if(sum1 >= FLETCHER_MODULE)
|
||||
sum1 -= FLETCHER_MODULE;
|
||||
|
||||
sum2 += sum1;
|
||||
|
||||
if(sum2 >= FLETCHER_MODULE)
|
||||
sum2 -= FLETCHER_MODULE;
|
||||
|
||||
previousSum1 = (byte)(sum1 & 0xFF);
|
||||
previousSum2 = (byte)(sum2 & 0xFF);
|
||||
|
||||
return;
|
||||
}
|
||||
/* in case short lengths are provided, keep it somewhat fast */
|
||||
case < 11:
|
||||
{
|
||||
while(len-- > 0)
|
||||
{
|
||||
sum1 += data[dataOff++];
|
||||
sum2 += sum1;
|
||||
}
|
||||
|
||||
if(sum1 >= FLETCHER_MODULE)
|
||||
sum1 -= FLETCHER_MODULE;
|
||||
|
||||
sum2 %= FLETCHER_MODULE; /* only added so many FLETCHER_MODULE's */
|
||||
previousSum1 = (byte)(sum1 & 0xFF);
|
||||
previousSum2 = (byte)(sum2 & 0xFF);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* do length NMAX blocks -- requires just one modulo operation */
|
||||
while(len >= NMAX)
|
||||
{
|
||||
len -= NMAX;
|
||||
uint n = NMAX / 11;
|
||||
|
||||
do
|
||||
{
|
||||
sum1 += data[dataOff];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 1];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 2];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 2 + 1];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 4];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 4 + 1];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 4 + 2];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 4 + 2 + 1];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 8];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 8 + 1];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 8 + 2];
|
||||
sum2 += sum1;
|
||||
|
||||
/* 11 sums unrolled */
|
||||
dataOff += 11;
|
||||
} while(--n != 0);
|
||||
|
||||
sum1 %= FLETCHER_MODULE;
|
||||
sum2 %= FLETCHER_MODULE;
|
||||
}
|
||||
|
||||
/* do remaining bytes (less than NMAX, still just one modulo) */
|
||||
if(len != 0)
|
||||
{
|
||||
/* avoid modulos if none remaining */
|
||||
while(len >= 11)
|
||||
{
|
||||
len -= 11;
|
||||
sum1 += data[dataOff];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 1];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 2];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 2 + 1];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 4];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 4 + 1];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 4 + 2];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 4 + 2 + 1];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 8];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 8 + 1];
|
||||
sum2 += sum1;
|
||||
sum1 += data[dataOff + 8 + 2];
|
||||
sum2 += sum1;
|
||||
|
||||
dataOff += 11;
|
||||
}
|
||||
|
||||
while(len-- != 0)
|
||||
{
|
||||
sum1 += data[dataOff++];
|
||||
sum2 += sum1;
|
||||
}
|
||||
|
||||
sum1 %= FLETCHER_MODULE;
|
||||
sum2 %= FLETCHER_MODULE;
|
||||
}
|
||||
|
||||
previousSum1 = (byte)(sum1 & 0xFF);
|
||||
previousSum2 = (byte)(sum2 & 0xFF);
|
||||
}
|
||||
|
||||
/// <summary>Gets the hash of a file</summary>
|
||||
/// <param name="filename">File path.</param>
|
||||
public static byte[] File(string filename)
|
||||
{
|
||||
File(filename, out byte[] hash);
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
|
||||
/// <param name="filename">File path.</param>
|
||||
/// <param name="hash">Byte array of the hash value.</param>
|
||||
public static string File(string filename, out byte[] hash)
|
||||
{
|
||||
bool useNative = Native.IsSupported;
|
||||
IntPtr nativeContext = IntPtr.Zero;
|
||||
|
||||
if(useNative)
|
||||
{
|
||||
nativeContext = fletcher16_init();
|
||||
|
||||
if(nativeContext == IntPtr.Zero)
|
||||
useNative = false;
|
||||
}
|
||||
|
||||
var fileStream = new FileStream(filename, FileMode.Open);
|
||||
|
||||
byte localSum1 = 0xFF;
|
||||
byte localSum2 = 0xFF;
|
||||
|
||||
var buffer = new byte[65536];
|
||||
int read = fileStream.EnsureRead(buffer, 0, 65536);
|
||||
|
||||
while(read > 0)
|
||||
{
|
||||
Step(ref localSum1, ref localSum2, buffer, (uint)read, useNative, nativeContext);
|
||||
|
||||
read = fileStream.EnsureRead(buffer, 0, 65536);
|
||||
}
|
||||
|
||||
var finalSum = (ushort)(localSum2 << 8 | localSum1);
|
||||
|
||||
if(useNative)
|
||||
{
|
||||
fletcher16_final(nativeContext, ref finalSum);
|
||||
fletcher16_free(nativeContext);
|
||||
}
|
||||
|
||||
hash = BigEndianBitConverter.GetBytes(finalSum);
|
||||
|
||||
var fletcherOutput = new StringBuilder();
|
||||
|
||||
foreach(byte h in hash)
|
||||
fletcherOutput.Append(h.ToString("x2"));
|
||||
|
||||
fileStream.Close();
|
||||
|
||||
return fletcherOutput.ToString();
|
||||
}
|
||||
|
||||
/// <summary>Gets the hash of the specified data buffer.</summary>
|
||||
/// <param name="data">Data buffer.</param>
|
||||
/// <param name="len">Length of the data buffer to hash.</param>
|
||||
/// <param name="hash">Byte array of the hash value.</param>
|
||||
public static string Data(byte[] data, uint len, out byte[] hash)
|
||||
{
|
||||
bool useNative = Native.IsSupported;
|
||||
IntPtr nativeContext = IntPtr.Zero;
|
||||
|
||||
if(useNative)
|
||||
{
|
||||
nativeContext = fletcher16_init();
|
||||
|
||||
if(nativeContext == IntPtr.Zero)
|
||||
useNative = false;
|
||||
}
|
||||
|
||||
byte localSum1 = 0xFF;
|
||||
byte localSum2 = 0xFF;
|
||||
|
||||
Step(ref localSum1, ref localSum2, data, len, useNative, nativeContext);
|
||||
|
||||
var finalSum = (ushort)(localSum2 << 8 | localSum1);
|
||||
|
||||
if(useNative)
|
||||
{
|
||||
fletcher16_final(nativeContext, ref finalSum);
|
||||
fletcher16_free(nativeContext);
|
||||
}
|
||||
|
||||
hash = BigEndianBitConverter.GetBytes(finalSum);
|
||||
|
||||
var adlerOutput = new StringBuilder();
|
||||
|
||||
foreach(byte h in hash)
|
||||
adlerOutput.Append(h.ToString("x2"));
|
||||
|
||||
return adlerOutput.ToString();
|
||||
}
|
||||
|
||||
/// <summary>Gets the hash of the specified data buffer.</summary>
|
||||
/// <param name="data">Data buffer.</param>
|
||||
/// <param name="hash">Byte array of the hash value.</param>
|
||||
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
// /***************************************************************************
|
||||
// Aaru Data Preservation Suite
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Native.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Checksums.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Checks that Aaru.Checksums.Native library is available and usable.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2023 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Aaru.Checksums;
|
||||
|
||||
/// <summary>Handles native implementations of compression algorithms</summary>
|
||||
public static class Native
|
||||
{
|
||||
static bool _checked;
|
||||
static bool _supported;
|
||||
|
||||
/// <summary>Set to return native as never supported</summary>
|
||||
public static bool ForceManaged { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If set to <c>true</c> the native library was found and loaded correctly and its reported version is
|
||||
/// compatible.
|
||||
/// </summary>
|
||||
public static bool IsSupported
|
||||
{
|
||||
get
|
||||
{
|
||||
if(ForceManaged)
|
||||
return false;
|
||||
|
||||
if(_checked)
|
||||
return _supported;
|
||||
|
||||
ulong version;
|
||||
_checked = true;
|
||||
|
||||
try
|
||||
{
|
||||
version = get_acn_version();
|
||||
}
|
||||
catch
|
||||
{
|
||||
_supported = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Check version compatibility
|
||||
_supported = version >= 0x06000000;
|
||||
|
||||
return _supported;
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport("libAaru.Checksums.Native", SetLastError = true)]
|
||||
static extern ulong get_acn_version();
|
||||
}
|
||||
@@ -1,579 +0,0 @@
|
||||
// /***************************************************************************
|
||||
// Aaru Data Preservation Suite
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : SpamSumContext.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Checksums.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Implements the SpamSum fuzzy hashing algorithm.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2023 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
// Based on ssdeep
|
||||
// Copyright (C) 2002 Andrew Tridgell <tridge@samba.org>
|
||||
// Copyright (C) 2006 ManTech International Corporation
|
||||
// Copyright (C) 2013 Helmut Grohne <helmut@subdivi.de>
|
||||
//
|
||||
// Earlier versions of this code were named fuzzy.c and can be found at:
|
||||
// http://www.samba.org/ftp/unpacked/junkcode/spamsum/
|
||||
// http://ssdeep.sf.net/
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using Aaru.CommonTypes.Interfaces;
|
||||
|
||||
namespace Aaru.Checksums;
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>Implements the SpamSum fuzzy hashing algorithm.</summary>
|
||||
[SuppressMessage("ReSharper", "UnusedMember.Global")]
|
||||
[SuppressMessage("ReSharper", "UnusedParameter.Global")]
|
||||
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
|
||||
[SuppressMessage("ReSharper", "MemberCanBeInternal")]
|
||||
[SuppressMessage("ReSharper", "OutParameterValueIsAlwaysDiscarded.Global")]
|
||||
internal sealed class SpamSumContext : IChecksum
|
||||
{
|
||||
const uint ROLLING_WINDOW = 7;
|
||||
const uint MIN_BLOCKSIZE = 3;
|
||||
const uint HASH_PRIME = 0x01000193;
|
||||
const uint HASH_INIT = 0x28021967;
|
||||
const uint NUM_BLOCKHASHES = 31;
|
||||
const uint SPAMSUM_LENGTH = 64;
|
||||
const uint FUZZY_MAX_RESULT = 2 * SPAMSUM_LENGTH + 20;
|
||||
|
||||
//"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
#if NET20 || NET35 || NET40
|
||||
readonly byte[] _b64 = Encoding.UTF8.GetBytes("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
|
||||
#else
|
||||
readonly byte[] _b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"u8.ToArray();
|
||||
#endif
|
||||
FuzzyState _self;
|
||||
|
||||
/// <summary>Initializes the SpamSum structures</summary>
|
||||
public SpamSumContext()
|
||||
{
|
||||
_self = new FuzzyState
|
||||
{
|
||||
Bh = new BlockhashContext[NUM_BLOCKHASHES]
|
||||
};
|
||||
|
||||
for (var i = 0; i < NUM_BLOCKHASHES; i++)
|
||||
_self.Bh[i].Digest = new byte[SPAMSUM_LENGTH];
|
||||
|
||||
_self.Bhstart = 0;
|
||||
_self.Bhend = 1;
|
||||
_self.Bh[0].H = HASH_INIT;
|
||||
_self.Bh[0].Halfh = HASH_INIT;
|
||||
_self.Bh[0].Digest[0] = 0;
|
||||
_self.Bh[0].Halfdigest = 0;
|
||||
_self.Bh[0].Dlen = 0;
|
||||
_self.TotalSize = 0;
|
||||
roll_init();
|
||||
}
|
||||
|
||||
#region IChecksum Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => "SpamSum";
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Id => new("DA692981-3291-47D8-B8B9-A87F0605F6E9");
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Author => "Natalia Portillo";
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>Updates the hash with data.</summary>
|
||||
/// <param name="data">Data buffer.</param>
|
||||
/// <param name="len">Length of buffer to hash.</param>
|
||||
public void Update(byte[] data, uint len)
|
||||
{
|
||||
_self.TotalSize += len;
|
||||
|
||||
for (var i = 0; i < len; i++)
|
||||
fuzzy_engine_step(data[i]);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>Updates the hash with data.</summary>
|
||||
/// <param name="data">Data buffer.</param>
|
||||
public void Update(byte[] data) => Update(data, (uint)data.Length);
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>Returns a byte array of the hash value.</summary>
|
||||
public byte[] Final()
|
||||
{
|
||||
FuzzyDigest(out byte[] result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>Returns a base64 representation of the hash value.</summary>
|
||||
public string End()
|
||||
{
|
||||
FuzzyDigest(out byte[] result);
|
||||
|
||||
return CToString(result);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#if NET452_OR_GREATER || NETCOREAPP
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#endif
|
||||
void roll_init() => _self.Roll = new RollState
|
||||
{
|
||||
Window = new byte[ROLLING_WINDOW]
|
||||
};
|
||||
|
||||
/*
|
||||
* a rolling hash, based on the Adler checksum. By using a rolling hash
|
||||
* we can perform auto resynchronisation after inserts/deletes
|
||||
|
||||
* internally, h1 is the sum of the bytes in the window and h2
|
||||
* is the sum of the bytes times the index
|
||||
|
||||
* h3 is a shift/xor based rolling hash, and is mostly needed to ensure that
|
||||
* we can cope with large blocksize values
|
||||
*/
|
||||
#if NET452_OR_GREATER || NETCOREAPP
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#endif
|
||||
void roll_hash(byte c)
|
||||
{
|
||||
_self.Roll.H2 -= _self.Roll.H1;
|
||||
_self.Roll.H2 += ROLLING_WINDOW * c;
|
||||
|
||||
_self.Roll.H1 += c;
|
||||
_self.Roll.H1 -= _self.Roll.Window[_self.Roll.N % ROLLING_WINDOW];
|
||||
|
||||
_self.Roll.Window[_self.Roll.N % ROLLING_WINDOW] = c;
|
||||
_self.Roll.N++;
|
||||
|
||||
/* The original spamsum AND'ed this value with 0xFFFFFFFF which
|
||||
* in theory should have no effect. This AND has been removed
|
||||
* for performance (jk) */
|
||||
_self.Roll.H3 <<= 5;
|
||||
_self.Roll.H3 ^= c;
|
||||
}
|
||||
|
||||
#if NET452_OR_GREATER || NETCOREAPP
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#endif
|
||||
uint roll_sum() => _self.Roll.H1 + _self.Roll.H2 + _self.Roll.H3;
|
||||
|
||||
/* A simple non-rolling hash, based on the FNV hash. */
|
||||
#if NET452_OR_GREATER || NETCOREAPP
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#endif
|
||||
static uint sum_hash(byte c, uint h) => h * HASH_PRIME ^ c;
|
||||
|
||||
#if NET452_OR_GREATER || NETCOREAPP
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#endif
|
||||
static uint SSDEEP_BS(uint index) => MIN_BLOCKSIZE << (int)index;
|
||||
|
||||
#if NET452_OR_GREATER || NETCOREAPP
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#endif
|
||||
void fuzzy_try_fork_blockhash()
|
||||
{
|
||||
switch (_self.Bhend)
|
||||
{
|
||||
case >= NUM_BLOCKHASHES:
|
||||
return;
|
||||
|
||||
// assert
|
||||
case 0:
|
||||
throw new Exception("Assertion failed");
|
||||
}
|
||||
|
||||
uint obh = _self.Bhend - 1;
|
||||
uint nbh = _self.Bhend;
|
||||
_self.Bh[nbh].H = _self.Bh[obh].H;
|
||||
_self.Bh[nbh].Halfh = _self.Bh[obh].Halfh;
|
||||
_self.Bh[nbh].Digest[0] = 0;
|
||||
_self.Bh[nbh].Halfdigest = 0;
|
||||
_self.Bh[nbh].Dlen = 0;
|
||||
++_self.Bhend;
|
||||
}
|
||||
|
||||
#if NET452_OR_GREATER || NETCOREAPP
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#endif
|
||||
void fuzzy_try_reduce_blockhash()
|
||||
{
|
||||
if (_self.Bhstart >= _self.Bhend)
|
||||
throw new Exception("Assertion failed");
|
||||
|
||||
if (_self.Bhend - _self.Bhstart < 2)
|
||||
/* Need at least two working hashes. */
|
||||
return;
|
||||
|
||||
if ((ulong)SSDEEP_BS(_self.Bhstart) * SPAMSUM_LENGTH >= _self.TotalSize)
|
||||
/* Initial blocksize estimate would select this or a smaller
|
||||
* blocksize. */
|
||||
return;
|
||||
|
||||
if (_self.Bh[_self.Bhstart + 1].Dlen < SPAMSUM_LENGTH / 2)
|
||||
/* Estimate adjustment would select this blocksize. */
|
||||
return;
|
||||
|
||||
/* At this point we are clearly no longer interested in the
|
||||
* start_blocksize. Get rid of it. */
|
||||
++_self.Bhstart;
|
||||
}
|
||||
|
||||
#if NET452_OR_GREATER || NETCOREAPP
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#endif
|
||||
void fuzzy_engine_step(byte c)
|
||||
{
|
||||
uint i;
|
||||
/* At each character we update the rolling hash and the normal hashes.
|
||||
* When the rolling hash hits a reset value then we emit a normal hash
|
||||
* as a element of the signature and reset the normal hash. */
|
||||
roll_hash(c);
|
||||
ulong h = roll_sum();
|
||||
|
||||
for (i = _self.Bhstart; i < _self.Bhend; ++i)
|
||||
{
|
||||
_self.Bh[i].H = sum_hash(c, _self.Bh[i].H);
|
||||
_self.Bh[i].Halfh = sum_hash(c, _self.Bh[i].Halfh);
|
||||
}
|
||||
|
||||
for (i = _self.Bhstart; i < _self.Bhend; ++i)
|
||||
{
|
||||
/* With growing blocksize almost no runs fail the next test. */
|
||||
if (h % SSDEEP_BS(i) != SSDEEP_BS(i) - 1)
|
||||
/* Once this condition is false for one bs, it is
|
||||
* automatically false for all further bs. I.e. if
|
||||
* h === -1 (mod 2*bs) then h === -1 (mod bs). */
|
||||
break;
|
||||
|
||||
/* We have hit a reset point. We now emit hashes which are
|
||||
* based on all characters in the piece of the message between
|
||||
* the last reset point and this one */
|
||||
if (0 == _self.Bh[i].Dlen)
|
||||
fuzzy_try_fork_blockhash();
|
||||
|
||||
_self.Bh[i].Digest[_self.Bh[i].Dlen] = _b64[_self.Bh[i].H % 64];
|
||||
_self.Bh[i].Halfdigest = _b64[_self.Bh[i].Halfh % 64];
|
||||
|
||||
if (_self.Bh[i].Dlen < SPAMSUM_LENGTH - 1)
|
||||
{
|
||||
/* We can have a problem with the tail overflowing. The
|
||||
* easiest way to cope with this is to only reset the
|
||||
* normal hash if we have room for more characters in
|
||||
* our signature. This has the effect of combining the
|
||||
* last few pieces of the message into a single piece
|
||||
* */
|
||||
_self.Bh[i].Digest[++_self.Bh[i].Dlen] = 0;
|
||||
_self.Bh[i].H = HASH_INIT;
|
||||
|
||||
if (_self.Bh[i].Dlen >= SPAMSUM_LENGTH / 2)
|
||||
continue;
|
||||
|
||||
_self.Bh[i].Halfh = HASH_INIT;
|
||||
_self.Bh[i].Halfdigest = 0;
|
||||
}
|
||||
else
|
||||
fuzzy_try_reduce_blockhash();
|
||||
}
|
||||
}
|
||||
|
||||
// CLAUNIA: Flags seems to never be used in ssdeep, so I just removed it for code simplicity
|
||||
#if NET452_OR_GREATER || NETCOREAPP
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#endif
|
||||
void FuzzyDigest(out byte[] result)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
uint bi = _self.Bhstart;
|
||||
uint h = roll_sum();
|
||||
var remain = (int)(FUZZY_MAX_RESULT - 1); /* Exclude terminating '\0'. */
|
||||
result = new byte[FUZZY_MAX_RESULT];
|
||||
|
||||
/* Verify that our elimination was not overeager. */
|
||||
if (!(bi == 0 || (ulong)SSDEEP_BS(bi) / 2 * SPAMSUM_LENGTH < _self.TotalSize))
|
||||
throw new Exception("Assertion failed");
|
||||
|
||||
/* Initial blocksize guess. */
|
||||
while ((ulong)SSDEEP_BS(bi) * SPAMSUM_LENGTH < _self.TotalSize)
|
||||
{
|
||||
++bi;
|
||||
|
||||
if (bi >= NUM_BLOCKHASHES)
|
||||
throw new OverflowException("The input exceeds data types");
|
||||
}
|
||||
|
||||
/* Adapt blocksize guess to actual digest length. */
|
||||
while (bi >= _self.Bhend)
|
||||
--bi;
|
||||
|
||||
while (bi > _self.Bhstart && _self.Bh[bi].Dlen < SPAMSUM_LENGTH / 2)
|
||||
--bi;
|
||||
|
||||
if (bi > 0 && _self.Bh[bi].Dlen < SPAMSUM_LENGTH / 2)
|
||||
throw new Exception("Assertion failed");
|
||||
|
||||
sb.Append($"{SSDEEP_BS(bi)}:");
|
||||
int i = Encoding.ASCII.GetBytes(sb.ToString()).Length;
|
||||
|
||||
if (i <= 0)
|
||||
/* Maybe snprintf has set errno here? */
|
||||
throw new OverflowException("The input exceeds data types");
|
||||
|
||||
if (i >= remain)
|
||||
throw new Exception("Assertion failed");
|
||||
|
||||
remain -= i;
|
||||
|
||||
Array.Copy(Encoding.ASCII.GetBytes(sb.ToString()), 0, result, 0, i);
|
||||
|
||||
int resultOff = i;
|
||||
|
||||
i = (int)_self.Bh[bi].Dlen;
|
||||
|
||||
if (i > remain)
|
||||
throw new Exception("Assertion failed");
|
||||
|
||||
Array.Copy(_self.Bh[bi].Digest, 0, result, resultOff, i);
|
||||
resultOff += i;
|
||||
remain -= i;
|
||||
|
||||
if (h != 0)
|
||||
{
|
||||
if (remain <= 0)
|
||||
throw new Exception("Assertion failed");
|
||||
|
||||
result[resultOff] = _b64[_self.Bh[bi].H % 64];
|
||||
|
||||
if (i < 3 ||
|
||||
result[resultOff] != result[resultOff - 1] ||
|
||||
result[resultOff] != result[resultOff - 2] ||
|
||||
result[resultOff] != result[resultOff - 3])
|
||||
{
|
||||
++resultOff;
|
||||
--remain;
|
||||
}
|
||||
}
|
||||
else if (_self.Bh[bi].Digest[i] != 0)
|
||||
{
|
||||
if (remain <= 0)
|
||||
throw new Exception("Assertion failed");
|
||||
|
||||
result[resultOff] = _self.Bh[bi].Digest[i];
|
||||
|
||||
if (i < 3 ||
|
||||
result[resultOff] != result[resultOff - 1] ||
|
||||
result[resultOff] != result[resultOff - 2] ||
|
||||
result[resultOff] != result[resultOff - 3])
|
||||
{
|
||||
++resultOff;
|
||||
--remain;
|
||||
}
|
||||
}
|
||||
|
||||
if (remain <= 0)
|
||||
throw new Exception("Assertion failed");
|
||||
|
||||
result[resultOff++] = 0x3A; // ':'
|
||||
--remain;
|
||||
|
||||
if (bi < _self.Bhend - 1)
|
||||
{
|
||||
++bi;
|
||||
i = (int)_self.Bh[bi].Dlen;
|
||||
|
||||
if (i > remain)
|
||||
throw new Exception("Assertion failed");
|
||||
|
||||
Array.Copy(_self.Bh[bi].Digest, 0, result, resultOff, i);
|
||||
resultOff += i;
|
||||
remain -= i;
|
||||
|
||||
if (h != 0)
|
||||
{
|
||||
if (remain <= 0)
|
||||
throw new Exception("Assertion failed");
|
||||
|
||||
h = _self.Bh[bi].Halfh;
|
||||
result[resultOff] = _b64[h % 64];
|
||||
|
||||
if (i < 3 ||
|
||||
result[resultOff] != result[resultOff - 1] ||
|
||||
result[resultOff] != result[resultOff - 2] ||
|
||||
result[resultOff] != result[resultOff - 3])
|
||||
{
|
||||
++resultOff;
|
||||
--remain;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
i = _self.Bh[bi].Halfdigest;
|
||||
|
||||
if (i != 0)
|
||||
{
|
||||
if (remain <= 0)
|
||||
throw new Exception("Assertion failed");
|
||||
|
||||
result[resultOff] = (byte)i;
|
||||
|
||||
if (i < 3 ||
|
||||
result[resultOff] != result[resultOff - 1] ||
|
||||
result[resultOff] != result[resultOff - 2] ||
|
||||
result[resultOff] != result[resultOff - 3])
|
||||
{
|
||||
++resultOff;
|
||||
--remain;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (h != 0)
|
||||
{
|
||||
if (_self.Bh[bi].Dlen != 0)
|
||||
throw new Exception("Assertion failed");
|
||||
|
||||
if (remain <= 0)
|
||||
throw new Exception("Assertion failed");
|
||||
|
||||
result[resultOff++] = _b64[_self.Bh[bi].H % 64];
|
||||
/* No need to bother with FUZZY_FLAG_ELIMSEQ, because this
|
||||
* digest has length 1. */
|
||||
--remain;
|
||||
}
|
||||
|
||||
result[resultOff] = 0;
|
||||
}
|
||||
|
||||
/// <summary>Gets the hash of a file</summary>
|
||||
/// <param name="filename">File path.</param>
|
||||
public static byte[] File(string filename) =>
|
||||
throw new NotImplementedException("SpamSum does not have a binary representation.");
|
||||
|
||||
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
|
||||
/// <param name="filename">File path.</param>
|
||||
/// <param name="hash">Byte array of the hash value.</param>
|
||||
public static string File(string filename, out byte[] hash) =>
|
||||
throw new NotImplementedException("Not yet implemented.");
|
||||
|
||||
/// <summary>Gets the hash of the specified data buffer.</summary>
|
||||
/// <param name="data">Data buffer.</param>
|
||||
/// <param name="len">Length of the data buffer to hash.</param>
|
||||
/// <param name="hash">null</param>
|
||||
/// <returns>Base64 representation of SpamSum $blocksize:$hash:$hash</returns>
|
||||
public static string Data(byte[] data, uint len, out byte[]? hash)
|
||||
{
|
||||
var fuzzyContext = new SpamSumContext();
|
||||
|
||||
fuzzyContext.Update(data, len);
|
||||
|
||||
hash = null;
|
||||
|
||||
return fuzzyContext.End();
|
||||
}
|
||||
|
||||
/// <summary>Gets the hash of the specified data buffer.</summary>
|
||||
/// <param name="data">Data buffer.</param>
|
||||
/// <param name="hash">null</param>
|
||||
/// <returns>Base64 representation of SpamSum $blocksize:$hash:$hash</returns>
|
||||
public static string Data(byte[] data, out byte[]? hash) => Data(data, (uint)data.Length, out hash);
|
||||
|
||||
// Converts an ASCII null-terminated string to .NET string
|
||||
#if NET452_OR_GREATER || NETCOREAPP
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#endif
|
||||
static string CToString(byte[] cString)
|
||||
{
|
||||
var count = 0;
|
||||
|
||||
// ReSharper disable once LoopCanBeConvertedToQuery
|
||||
// LINQ is six times slower
|
||||
foreach (byte c in cString)
|
||||
{
|
||||
if (c == 0)
|
||||
break;
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
return Encoding.ASCII.GetString(cString, 0, count);
|
||||
}
|
||||
|
||||
#region Nested type: BlockhashContext
|
||||
|
||||
/* A blockhash contains a signature state for a specific (implicit) blocksize.
|
||||
* The blocksize is given by SSDEEP_BS(index). The h and halfh members are the
|
||||
* FNV hashes, where halfh stops to be reset after digest is SPAMSUM_LENGTH/2
|
||||
* long. The halfh hash is needed be able to truncate digest for the second
|
||||
* output hash to stay compatible with ssdeep output. */
|
||||
struct BlockhashContext
|
||||
{
|
||||
public uint H;
|
||||
public uint Halfh;
|
||||
public byte[] Digest;
|
||||
|
||||
// SPAMSUM_LENGTH
|
||||
public byte Halfdigest;
|
||||
public uint Dlen;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: FuzzyState
|
||||
|
||||
struct FuzzyState
|
||||
{
|
||||
public uint Bhstart;
|
||||
public uint Bhend;
|
||||
public BlockhashContext[] Bh;
|
||||
|
||||
//NUM_BLOCKHASHES
|
||||
public ulong TotalSize;
|
||||
public RollState Roll;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: RollState
|
||||
|
||||
struct RollState
|
||||
{
|
||||
public byte[] Window;
|
||||
|
||||
// ROLLING_WINDOW
|
||||
public uint H1;
|
||||
public uint H2;
|
||||
public uint H3;
|
||||
public uint N;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
// /***************************************************************************
|
||||
// Aaru Data Preservation Suite
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : IChecksum.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Checksums.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Provides an interface for implementing checksums and hashes.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2023 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
|
||||
namespace Aaru.CommonTypes.Interfaces;
|
||||
|
||||
/// <summary>Defines the interface to implement a checksum or hashing algorithm</summary>
|
||||
internal interface IChecksum
|
||||
{
|
||||
/// <summary>Plugin author</summary>
|
||||
string Author { get; }
|
||||
|
||||
/// <summary>Plugin name.</summary>
|
||||
string Name { get; }
|
||||
|
||||
/// <summary>Plugin UUID.</summary>
|
||||
Guid Id { get; }
|
||||
|
||||
/// <summary>Updates the hash with data.</summary>
|
||||
/// <param name="data">Data buffer.</param>
|
||||
/// <param name="len">Length of buffer to hash.</param>
|
||||
void Update(byte[] data, uint len);
|
||||
|
||||
/// <summary>Updates the hash with data.</summary>
|
||||
/// <param name="data">Data buffer.</param>
|
||||
void Update(byte[] data);
|
||||
|
||||
/// <summary>Returns a byte array of the hash value.</summary>
|
||||
byte[] Final();
|
||||
|
||||
/// <summary>Returns a hexadecimal representation of the hash value.</summary>
|
||||
string End();
|
||||
}
|
||||
@@ -1,324 +0,0 @@
|
||||
// /***************************************************************************
|
||||
// Aaru Data Preservation Suite
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : BigEndianBitConverter.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Helpers.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Override of System.BitConverter that knows how to handle big-endian.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2023 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Aaru.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts base data types to an array of bytes, and an array of bytes to base data types. All info taken from
|
||||
/// the meta data of System.BitConverter. This implementation allows for Endianness consideration.
|
||||
/// </summary>
|
||||
public static class BigEndianBitConverter
|
||||
{
|
||||
/// <summary>Converts the specified double-precision floating point number to a 64-bit signed integer.</summary>
|
||||
/// <param name="value">The number to convert.</param>
|
||||
/// <returns>A 64-bit signed integer whose value is equivalent to value.</returns>
|
||||
/// <exception cref="NotImplementedException">It is not currently implemented</exception>
|
||||
public static long DoubleToInt64Bits(double value) => throw new NotImplementedException();
|
||||
|
||||
/// <summary>Returns the specified Boolean value as an array of bytes.</summary>
|
||||
/// <param name="value">A Boolean value.</param>
|
||||
/// <returns>An array of bytes with length 1.</returns>
|
||||
public static byte[] GetBytes(bool value) => BitConverter.GetBytes(value).Reverse().ToArray();
|
||||
|
||||
/// <summary>Returns the specified Unicode character value as an array of bytes.</summary>
|
||||
/// <param name="value">A character to convert.</param>
|
||||
/// <returns>An array of bytes with length 2.</returns>
|
||||
public static byte[] GetBytes(char value) => BitConverter.GetBytes(value).Reverse().ToArray();
|
||||
|
||||
/// <summary>Returns the specified double-precision floating point value as an array of bytes.</summary>
|
||||
/// <param name="value">The number to convert.</param>
|
||||
/// <returns>An array of bytes with length 8.</returns>
|
||||
public static byte[] GetBytes(double value) => BitConverter.GetBytes(value).Reverse().ToArray();
|
||||
|
||||
/// <summary>Returns the specified single-precision floating point value as an array of bytes.</summary>
|
||||
/// <param name="value">The number to convert.</param>
|
||||
/// <returns>An array of bytes with length 4.</returns>
|
||||
public static byte[] GetBytes(float value) => BitConverter.GetBytes(value).Reverse().ToArray();
|
||||
|
||||
/// <summary>Returns the specified 32-bit signed integer value as an array of bytes.</summary>
|
||||
/// <param name="value">The number to convert.</param>
|
||||
/// <returns>An array of bytes with length 4.</returns>
|
||||
public static byte[] GetBytes(int value) => BitConverter.GetBytes(value).Reverse().ToArray();
|
||||
|
||||
/// <summary>Returns the specified 64-bit signed integer value as an array of bytes.</summary>
|
||||
/// <param name="value">The number to convert.</param>
|
||||
/// <returns>An array of bytes with length 8.</returns>
|
||||
public static byte[] GetBytes(long value) => BitConverter.GetBytes(value).Reverse().ToArray();
|
||||
|
||||
/// <summary>Returns the specified 16-bit signed integer value as an array of bytes.</summary>
|
||||
/// <param name="value">The number to convert.</param>
|
||||
/// <returns>An array of bytes with length 2.</returns>
|
||||
public static byte[] GetBytes(short value) => BitConverter.GetBytes(value).Reverse().ToArray();
|
||||
|
||||
/// <summary>Returns the specified 32-bit unsigned integer value as an array of bytes.</summary>
|
||||
/// <param name="value">The number to convert.</param>
|
||||
/// <returns>An array of bytes with length 4.</returns>
|
||||
public static byte[] GetBytes(uint value) => BitConverter.GetBytes(value).Reverse().ToArray();
|
||||
|
||||
/// <summary>Returns the specified 64-bit unsigned integer value as an array of bytes.</summary>
|
||||
/// <param name="value">The number to convert.</param>
|
||||
/// <returns>An array of bytes with length 8.</returns>
|
||||
public static byte[] GetBytes(ulong value) => BitConverter.GetBytes(value).Reverse().ToArray();
|
||||
|
||||
/// <summary>Returns the specified 16-bit unsigned integer value as an array of bytes.</summary>
|
||||
/// <param name="value">The number to convert.</param>
|
||||
/// <returns>An array of bytes with length 2.</returns>
|
||||
public static byte[] GetBytes(ushort value) => BitConverter.GetBytes(value).Reverse().ToArray();
|
||||
|
||||
/// <summary>Converts the specified 64-bit signed integer to a double-precision floating point number.</summary>
|
||||
/// <param name="value">The number to convert.</param>
|
||||
/// <returns>A double-precision floating point number whose value is equivalent to value.</returns>
|
||||
public static double Int64BitsToDouble(long value) => throw new NotImplementedException();
|
||||
|
||||
/// <summary>Returns a Boolean value converted from one byte at a specified position in a byte array.</summary>
|
||||
/// <param name="value">An array of bytes.</param>
|
||||
/// <param name="startIndex">The starting position within value.</param>
|
||||
/// <returns>true if the byte at <see cref="startIndex" /> in value is nonzero; otherwise, false.</returns>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||
/// <see cref="startIndex" /> is less than zero or greater than the
|
||||
/// length of value minus 1.
|
||||
/// </exception>
|
||||
public static bool ToBoolean(byte[] value, int startIndex) => throw new NotImplementedException();
|
||||
|
||||
/// <summary>Returns a Unicode character converted from two bytes at a specified position in a byte array.</summary>
|
||||
/// <param name="value">An array.</param>
|
||||
/// <param name="startIndex">The starting position within value.</param>
|
||||
/// <returns>A character formed by two bytes beginning at <see cref="startIndex" />.</returns>
|
||||
/// <exception cref="System.ArgumentException"><see cref="startIndex" /> equals the length of value minus 1.</exception>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||
/// <see cref="startIndex" /> is less than zero or greater than the
|
||||
/// length of value minus 1.
|
||||
/// </exception>
|
||||
public static char ToChar(byte[] value, int startIndex) => throw new NotImplementedException();
|
||||
|
||||
/// <summary>
|
||||
/// Returns a double-precision floating point number converted from eight bytes at a specified position in a byte
|
||||
/// array.
|
||||
/// </summary>
|
||||
/// <param name="value">An array of bytes.</param>
|
||||
/// <param name="startIndex">The starting position within value.</param>
|
||||
/// <returns>A double precision floating point number formed by eight bytes beginning at <see cref="startIndex" />.</returns>
|
||||
/// <exception cref="System.ArgumentException">
|
||||
/// <see cref="startIndex" /> is greater than or equal to the length of value
|
||||
/// minus 7, and is less than or equal to the length of value minus 1.
|
||||
/// </exception>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||
/// <see cref="startIndex" /> is less than zero or greater than the
|
||||
/// length of value minus 1.
|
||||
/// </exception>
|
||||
public static double ToDouble(byte[] value, int startIndex) => throw new NotImplementedException();
|
||||
|
||||
/// <summary>Returns a 16-bit signed integer converted from two bytes at a specified position in a byte array.</summary>
|
||||
/// <param name="value">An array of bytes.</param>
|
||||
/// <param name="startIndex">The starting position within value.</param>
|
||||
/// <returns>A 16-bit signed integer formed by two bytes beginning at <see cref="startIndex" />.</returns>
|
||||
/// <exception cref="System.ArgumentException"><see cref="startIndex" /> equals the length of value minus 1.</exception>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||
/// startIndex is less than zero or greater than the length of value
|
||||
/// minus 1.
|
||||
/// </exception>
|
||||
public static short ToInt16(byte[] value, int startIndex) =>
|
||||
BitConverter.ToInt16(value.Reverse().ToArray(), value.Length - sizeof(short) - startIndex);
|
||||
|
||||
/// <summary>Returns a 32-bit signed integer converted from four bytes at a specified position in a byte array.</summary>
|
||||
/// <param name="value">An array of bytes.</param>
|
||||
/// <param name="startIndex">The starting position within value.</param>
|
||||
/// <returns>A 32-bit signed integer formed by four bytes beginning at <see cref="startIndex" />.</returns>
|
||||
/// <exception cref="System.ArgumentException">
|
||||
/// <see cref="startIndex" /> is greater than or equal to the length of value
|
||||
/// minus 3, and is less than or equal to the length of value minus 1.
|
||||
/// </exception>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||
/// startIndex is less than zero or greater than the length of value
|
||||
/// minus 1.
|
||||
/// </exception>
|
||||
public static int ToInt32(byte[] value, int startIndex) =>
|
||||
BitConverter.ToInt32(value.Reverse().ToArray(), value.Length - sizeof(int) - startIndex);
|
||||
|
||||
/// <summary>Returns a 64-bit signed integer converted from eight bytes at a specified position in a byte array.</summary>
|
||||
/// <param name="value">An array of bytes.</param>
|
||||
/// <param name="startIndex">The starting position within value.</param>
|
||||
/// <returns>A 64-bit signed integer formed by eight bytes beginning at <see cref="startIndex" />.</returns>
|
||||
/// <exception cref="System.ArgumentException">
|
||||
/// <see cref="startIndex" /> is greater than or equal to the length of value
|
||||
/// minus 7, and is less than or equal to the length of value minus 1.
|
||||
/// </exception>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||
/// <see cref="startIndex" /> is less than zero or greater than the
|
||||
/// length of value minus 1.
|
||||
/// </exception>
|
||||
public static long ToInt64(byte[] value, int startIndex) =>
|
||||
BitConverter.ToInt64(value.Reverse().ToArray(), value.Length - sizeof(long) - startIndex);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a single-precision floating point number converted from four bytes at a specified position in a byte
|
||||
/// array.
|
||||
/// </summary>
|
||||
/// <param name="value">An array of bytes.</param>
|
||||
/// <param name="startIndex">The starting position within value.</param>
|
||||
/// <returns>A single-precision floating point number formed by four bytes beginning at <see cref="startIndex" />.</returns>
|
||||
/// <exception cref="System.ArgumentException">
|
||||
/// <see cref="startIndex" /> is greater than or equal to the length of value
|
||||
/// minus 3, and is less than or equal to the length of value minus 1.
|
||||
/// </exception>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||
/// <see cref="startIndex" /> is less than zero or greater than the
|
||||
/// length of value minus 1.
|
||||
/// </exception>
|
||||
public static float ToSingle(byte[] value, int startIndex) =>
|
||||
BitConverter.ToSingle(value.Reverse().ToArray(), value.Length - sizeof(float) - startIndex);
|
||||
|
||||
/// <summary>
|
||||
/// Converts the numeric value of each element of a specified array of bytes to its equivalent hexadecimal string
|
||||
/// representation.
|
||||
/// </summary>
|
||||
/// <param name="value">An array of bytes.</param>
|
||||
/// <returns>
|
||||
/// A System.String of hexadecimal pairs separated by hyphens, where each pair represents the corresponding
|
||||
/// element in value; for example, "7F-2C-4A".
|
||||
/// </returns>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
public static string ToString(byte[] value) => BitConverter.ToString(value.Reverse().ToArray());
|
||||
|
||||
/// <summary>
|
||||
/// Converts the numeric value of each element of a specified subarray of bytes to its equivalent hexadecimal
|
||||
/// string representation.
|
||||
/// </summary>
|
||||
/// <param name="value">An array of bytes.</param>
|
||||
/// <param name="startIndex">The starting position within value.</param>
|
||||
/// <returns>
|
||||
/// A System.String of hexadecimal pairs separated by hyphens, where each pair represents the corresponding
|
||||
/// element in a subarray of value; for example, "7F-2C-4A".
|
||||
/// </returns>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||
/// startIndex is less than zero or greater than the length of value
|
||||
/// minus 1.
|
||||
/// </exception>
|
||||
public static string ToString(byte[] value, int startIndex) =>
|
||||
BitConverter.ToString(value.Reverse().ToArray(), startIndex);
|
||||
|
||||
/// <summary>
|
||||
/// Converts the numeric value of each element of a specified subarray of bytes to its equivalent hexadecimal
|
||||
/// string representation.
|
||||
/// </summary>
|
||||
/// <param name="value">An array of bytes.</param>
|
||||
/// <param name="startIndex">The starting position within value.</param>
|
||||
/// <param name="length">The number of array elements in value to convert.</param>
|
||||
/// <returns>
|
||||
/// A System.String of hexadecimal pairs separated by hyphens, where each pair represents the corresponding
|
||||
/// element in a subarray of value; for example, "7F-2C-4A".
|
||||
/// </returns>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||
/// startIndex or length is less than zero. -or- startIndex is greater
|
||||
/// than zero and is greater than or equal to the length of value.
|
||||
/// </exception>
|
||||
/// <exception cref="System.ArgumentException">
|
||||
/// The combination of startIndex and length does not specify a position within
|
||||
/// value; that is, the startIndex parameter is greater than the length of value minus the length parameter.
|
||||
/// </exception>
|
||||
public static string ToString(byte[] value, int startIndex, int length) =>
|
||||
BitConverter.ToString(value.Reverse().ToArray(), startIndex, length);
|
||||
|
||||
/// <summary>Returns a 16-bit unsigned integer converted from two bytes at a specified position in a byte array.</summary>
|
||||
/// <param name="value">The array of bytes.</param>
|
||||
/// <param name="startIndex">The starting position within value.</param>
|
||||
/// <returns>A 16-bit unsigned integer formed by two bytes beginning at startIndex.</returns>
|
||||
/// <exception cref="System.ArgumentException">startIndex equals the length of value minus 1.</exception>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||
/// startIndex is less than zero or greater than the length of value
|
||||
/// minus 1.
|
||||
/// </exception>
|
||||
public static ushort ToUInt16(byte[] value, int startIndex) =>
|
||||
BitConverter.ToUInt16(value.Reverse().ToArray(), value.Length - sizeof(ushort) - startIndex);
|
||||
|
||||
/// <summary>Returns a 32-bit unsigned integer converted from four bytes at a specified position in a byte array.</summary>
|
||||
/// <param name="value">An array of bytes.</param>
|
||||
/// <param name="startIndex">The starting position within value.</param>
|
||||
/// <returns>A 32-bit unsigned integer formed by four bytes beginning at startIndex.</returns>
|
||||
/// <exception cref="System.ArgumentException">
|
||||
/// startIndex is greater than or equal to the length of value minus 3, and is
|
||||
/// less than or equal to the length of value minus 1.
|
||||
/// </exception>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||
/// startIndex is less than zero or greater than the length of value
|
||||
/// minus 1.
|
||||
/// </exception>
|
||||
public static uint ToUInt32(byte[] value, int startIndex) =>
|
||||
BitConverter.ToUInt32(value.Reverse().ToArray(), value.Length - sizeof(uint) - startIndex);
|
||||
|
||||
/// <summary>Returns a 64-bit unsigned integer converted from eight bytes at a specified position in a byte array.</summary>
|
||||
/// <param name="value">An array of bytes.</param>
|
||||
/// <param name="startIndex">The starting position within value.</param>
|
||||
/// <returns>A 64-bit unsigned integer formed by the eight bytes beginning at startIndex.</returns>
|
||||
/// <exception cref="System.ArgumentException">
|
||||
/// startIndex is greater than or equal to the length of value minus 7, and is
|
||||
/// less than or equal to the length of value minus 1.
|
||||
/// </exception>
|
||||
/// <exception cref="System.ArgumentNullException">value is null.</exception>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||
/// startIndex is less than zero or greater than the length of value
|
||||
/// minus 1.
|
||||
/// </exception>
|
||||
public static ulong ToUInt64(byte[] value, int startIndex) =>
|
||||
BitConverter.ToUInt64(value.Reverse().ToArray(), value.Length - sizeof(ulong) - startIndex);
|
||||
|
||||
/// <summary>Converts a big endian byte array representation of a GUID into the .NET Guid structure</summary>
|
||||
/// <param name="value">Byte array containing a GUID in big endian</param>
|
||||
/// <param name="startIndex">Start of the byte array to process</param>
|
||||
/// <returns>Processed Guid</returns>
|
||||
public static Guid ToGuid(byte[] value, int startIndex) => new Guid(ToUInt32(value, 0 + startIndex),
|
||||
ToUInt16(value, 4 + startIndex),
|
||||
ToUInt16(value, 6 + startIndex),
|
||||
value[8 + startIndex + 0],
|
||||
value[8 + startIndex + 1],
|
||||
value[8 + startIndex + 2],
|
||||
value[8 + startIndex + 3],
|
||||
value[8 + startIndex + 5],
|
||||
value[8 + startIndex + 5],
|
||||
value[8 + startIndex + 6],
|
||||
value[8 + startIndex + 7]);
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
// /***************************************************************************
|
||||
// Aaru Data Preservation Suite
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Extensions.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Helpers.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Provides class extensions.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2023 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.IO;
|
||||
|
||||
namespace Aaru.Helpers;
|
||||
|
||||
public static class Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// When overridden in a derived class, reads a sequence of bytes from the current stream and advances the
|
||||
/// position within the stream by the number of bytes read.<br /> Guarantees the whole count of bytes is read or EOF is
|
||||
/// found
|
||||
/// </summary>
|
||||
/// <param name="s">Stream to extend</param>
|
||||
/// <param name="buffer">
|
||||
/// An array of bytes. When this method returns, the buffer contains the specified byte array with the
|
||||
/// values between <see cref="offset" /> and (<see cref="offset" /> + <see cref="count" /> - 1) replaced by the bytes
|
||||
/// read from the current source.
|
||||
/// </param>
|
||||
/// <param name="offset">
|
||||
/// The zero-based byte offset in <see cref="buffer" /> at which to begin storing the data read from
|
||||
/// the current stream.
|
||||
/// </param>
|
||||
/// <param name="count">The maximum number of bytes to be read from the current stream.</param>
|
||||
/// <returns>
|
||||
/// The total number of bytes read into the buffer. This can be less than the number of bytes requested if the end
|
||||
/// of the stream has been reached.
|
||||
/// </returns>
|
||||
public static int EnsureRead(this Stream s, byte[] buffer, int offset, int count)
|
||||
{
|
||||
var pos = 0;
|
||||
int read;
|
||||
|
||||
do
|
||||
{
|
||||
read = s.Read(buffer, pos + offset, count - pos);
|
||||
pos += read;
|
||||
} while(read > 0);
|
||||
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace CRC32
|
||||
{
|
||||
public class NaiveCRC
|
||||
{
|
||||
private const uint kPoly = 0xEDB88320;
|
||||
private const uint kInit = 0xFFFFFFFF;
|
||||
private static readonly uint[] Table;
|
||||
|
||||
static NaiveCRC()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
Table = new uint[256];
|
||||
for (uint i = 0; i < 256; i++)
|
||||
{
|
||||
uint r = i;
|
||||
for (int j = 0; j < 8; j++)
|
||||
r = (r >> 1) ^ (kPoly & ~((r & 1) - 1));
|
||||
Table[i] = r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private uint value;
|
||||
|
||||
public NaiveCRC()
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
value = kInit;
|
||||
}
|
||||
|
||||
public int Value
|
||||
{
|
||||
get { return (int)~value; }
|
||||
}
|
||||
|
||||
public void UpdateByte(byte b)
|
||||
{
|
||||
value = (value >> 8) ^ Table[(byte)value ^ b];
|
||||
}
|
||||
|
||||
public void Update(byte[] data, int offset, int count)
|
||||
{
|
||||
if (count < 0) throw new ArgumentOutOfRangeException("count");
|
||||
while (count-- != 0)
|
||||
value = (value >> 8) ^ Table[(byte)value ^ data[offset++]];
|
||||
}
|
||||
|
||||
static public int Compute(byte[] data, int offset, int count)
|
||||
{
|
||||
var crc = new NaiveCRC();
|
||||
crc.Update(data, offset, count);
|
||||
return crc.Value;
|
||||
}
|
||||
|
||||
static public int Compute(byte[] data)
|
||||
{
|
||||
return Compute(data, 0, data.Length);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012-2015 Eugene Larchenko (el6345@gmail.com)
|
||||
* This code is licensed under the MIT License.
|
||||
* See the file LICENSE_MIT for the license details.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace CRC32
|
||||
{
|
||||
public class OptimizedCRC
|
||||
{
|
||||
private const uint kPoly = 0xEDB88320;
|
||||
private const uint kInit = 0xFFFFFFFF;
|
||||
private const int NUM_TABLES = 8;
|
||||
private static readonly uint[] Table;
|
||||
|
||||
static OptimizedCRC()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
Table = new uint[256 * NUM_TABLES];
|
||||
int i;
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
uint r = (uint)i;
|
||||
for (int j = 0; j < 8; j++)
|
||||
r = (r >> 1) ^ (kPoly & ~((r & 1) - 1));
|
||||
Table[i] = r;
|
||||
}
|
||||
for (; i < 256 * NUM_TABLES; i++)
|
||||
{
|
||||
uint r = Table[i - 256];
|
||||
Table[i] = Table[r & 0xFF] ^ (r >> 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private uint value;
|
||||
|
||||
public OptimizedCRC()
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
value = kInit;
|
||||
}
|
||||
|
||||
public int Value
|
||||
{
|
||||
get { return (int)~value; }
|
||||
}
|
||||
|
||||
public void Update(byte[] data, int offset, int count)
|
||||
{
|
||||
new ArraySegment<byte>(data, offset, count); // check arguments
|
||||
if (count <= 0) return;
|
||||
|
||||
var table = OptimizedCRC.Table;
|
||||
|
||||
uint crc = value;
|
||||
|
||||
for (; (offset & 7) != 0 && count != 0; count--)
|
||||
crc = (crc >> 8) ^ table[(byte)crc ^ data[offset++]];
|
||||
|
||||
if (count >= 8)
|
||||
{
|
||||
int end = (count - 8) & ~7;
|
||||
count -= end;
|
||||
end += offset;
|
||||
|
||||
while (offset != end)
|
||||
{
|
||||
crc ^= (uint)(data[offset] + (data[offset + 1] << 8) + (data[offset + 2] << 16) + (data[offset + 3] << 24));
|
||||
uint high = (uint)(data[offset + 4] + (data[offset + 5] << 8) + (data[offset + 6] << 16) + (data[offset + 7] << 24));
|
||||
offset += 8;
|
||||
|
||||
crc = table[(byte)crc + 0x700]
|
||||
^ table[(byte)(crc >>= 8) + 0x600]
|
||||
^ table[(byte)(crc >>= 8) + 0x500]
|
||||
^ table[/*(byte)*/(crc >> 8) + 0x400]
|
||||
^ table[(byte)(high) + 0x300]
|
||||
^ table[(byte)(high >>= 8) + 0x200]
|
||||
^ table[(byte)(high >>= 8) + 0x100]
|
||||
^ table[/*(byte)*/(high >> 8) + 0x000];
|
||||
}
|
||||
}
|
||||
|
||||
while (count-- != 0)
|
||||
crc = (crc >> 8) ^ table[(byte)crc ^ data[offset++]];
|
||||
|
||||
value = crc;
|
||||
}
|
||||
|
||||
static public int Compute(byte[] data, int offset, int count)
|
||||
{
|
||||
var crc = new OptimizedCRC();
|
||||
crc.Update(data, offset, count);
|
||||
return crc.Value;
|
||||
}
|
||||
|
||||
static public int Compute(byte[] data)
|
||||
{
|
||||
return Compute(data, 0, data.Length);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,302 +0,0 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2012-2015 Eugene Larchenko (el6345@gmail.com)
|
||||
* This code is licensed under the Microsoft Public License (MS-PL).
|
||||
* See the file LICENSE_MSPL for the license details.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace CRC32
|
||||
{
|
||||
public class ParallelCRC
|
||||
{
|
||||
private const uint kPoly = 0xEDB88320;
|
||||
private const uint kInit = 0xFFFFFFFF;
|
||||
private const int NUM_TABLES = 8;
|
||||
private static readonly uint[] Table;
|
||||
|
||||
private const int ThreadCost = 512 * 1024;
|
||||
private static readonly int ProcessorCount = Environment.ProcessorCount;
|
||||
|
||||
static ParallelCRC()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
Table = new uint[256 * NUM_TABLES];
|
||||
int i;
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
uint r = (uint)i;
|
||||
for (int j = 0; j < 8; j++)
|
||||
r = (r >> 1) ^ (kPoly & ~((r & 1) - 1));
|
||||
Table[i] = r;
|
||||
}
|
||||
for (; i < 256 * NUM_TABLES; i++)
|
||||
{
|
||||
uint r = Table[i - 256];
|
||||
Table[i] = Table[r & 0xFF] ^ (r >> 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private uint value;
|
||||
|
||||
public ParallelCRC()
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset CRC
|
||||
/// </summary>
|
||||
public void Init()
|
||||
{
|
||||
value = kInit;
|
||||
}
|
||||
|
||||
public int Value
|
||||
{
|
||||
get { return (int)~value; }
|
||||
}
|
||||
|
||||
public void Update(byte[] data, int offset, int count)
|
||||
{
|
||||
new ArraySegment<byte>(data, offset, count); // check arguments
|
||||
|
||||
// quick elimination
|
||||
if (count <= ThreadCost || ProcessorCount <= 1)
|
||||
{
|
||||
value = ProcessBlock(value, data, offset, count);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// choose optimal number of threads to use
|
||||
|
||||
int threadCount = ProcessorCount;
|
||||
L0:
|
||||
int bytesPerThread = (count + threadCount - 1) / threadCount;
|
||||
if (bytesPerThread < (ThreadCost >> 1))
|
||||
{
|
||||
threadCount--;
|
||||
goto L0;
|
||||
}
|
||||
|
||||
|
||||
// create jobs chain
|
||||
|
||||
// threadCount >= 2
|
||||
Job? lastJob = null;
|
||||
while (count > bytesPerThread)
|
||||
{
|
||||
var job = new Job(new ArraySegment<byte>(data, offset, bytesPerThread), this, lastJob);
|
||||
ThreadPool.QueueUserWorkItem(job.Start);
|
||||
offset += bytesPerThread;
|
||||
count -= bytesPerThread;
|
||||
lastJob = job;
|
||||
}
|
||||
|
||||
// lastJob != null
|
||||
var lastBlockCRC = ProcessBlock(kInit, data, offset, count);
|
||||
lastJob?.WaitAndDispose();
|
||||
value = Combine(value, lastBlockCRC, count);
|
||||
}
|
||||
|
||||
private static uint ProcessBlock(uint crc, byte[] data, int offset, int count)
|
||||
{
|
||||
/*
|
||||
* A copy of OptimizedCRC.cs
|
||||
*/
|
||||
|
||||
if (count < 0) throw new ArgumentOutOfRangeException("count");
|
||||
if (count == 0) return crc;
|
||||
|
||||
var table = ParallelCRC.Table;
|
||||
|
||||
for (; (offset & 7) != 0 && count != 0; count--)
|
||||
crc = (crc >> 8) ^ table[(byte)crc ^ data[offset++]];
|
||||
|
||||
if (count >= 8)
|
||||
{
|
||||
int end = (count - 8) & ~7;
|
||||
count -= end;
|
||||
end += offset;
|
||||
|
||||
while (offset != end)
|
||||
{
|
||||
crc ^= (uint)(data[offset] + (data[offset + 1] << 8) + (data[offset + 2] << 16) + (data[offset + 3] << 24));
|
||||
uint high = (uint)(data[offset + 4] + (data[offset + 5] << 8) + (data[offset + 6] << 16) + (data[offset + 7] << 24));
|
||||
offset += 8;
|
||||
|
||||
crc = table[(byte)crc + 0x700]
|
||||
^ table[(byte)(crc >>= 8) + 0x600]
|
||||
^ table[(byte)(crc >>= 8) + 0x500]
|
||||
^ table[/*(byte)*/(crc >> 8) + 0x400]
|
||||
^ table[(byte)(high) + 0x300]
|
||||
^ table[(byte)(high >>= 8) + 0x200]
|
||||
^ table[(byte)(high >>= 8) + 0x100]
|
||||
^ table[/*(byte)*/(high >> 8) + 0x000];
|
||||
}
|
||||
}
|
||||
|
||||
while (count-- != 0)
|
||||
crc = (crc >> 8) ^ table[(byte)crc ^ data[offset++]];
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
static public int Compute(byte[] data, int offset, int count)
|
||||
{
|
||||
var crc = new ParallelCRC();
|
||||
crc.Update(data, offset, count);
|
||||
return crc.Value;
|
||||
}
|
||||
|
||||
static public int Compute(byte[] data)
|
||||
{
|
||||
return Compute(data, 0, data.Length);
|
||||
}
|
||||
|
||||
#region Combining
|
||||
|
||||
// Copyright (c) 2011 Dino Chiesa.
|
||||
// This module is (refactored) part of DotNetZip, a zipfile class library.
|
||||
// This code is licensed under the Microsoft Public License.
|
||||
// See the file LICENSE_MSPL for the license details.
|
||||
// More info on: http://dotnetzip.codeplex.com
|
||||
|
||||
/// <summary>
|
||||
/// Combine sums of two segments.
|
||||
/// This function is thread-safe.
|
||||
/// </summary>
|
||||
private static uint Combine(uint crc1, uint crc2, int length2)
|
||||
{
|
||||
// Note: this function is thread-safe even though it references static fields
|
||||
|
||||
if (length2 <= 0) return crc1;
|
||||
if (crc1 == kInit) return crc2;
|
||||
|
||||
if (even_cache == null)
|
||||
{
|
||||
Prepare_even_odd_Cache();
|
||||
}
|
||||
|
||||
uint[] even = even_cache?.ToArray() ?? [];
|
||||
uint[] odd = odd_cache?.ToArray() ?? [];
|
||||
|
||||
crc1 = ~crc1;
|
||||
crc2 = ~crc2;
|
||||
|
||||
uint len2 = (uint)length2;
|
||||
|
||||
// apply len2 zeros to crc1 (first square will put the operator for one
|
||||
// zero byte, eight zero bits, in even)
|
||||
do
|
||||
{
|
||||
// apply zeros operator for this bit of len2
|
||||
gf2_matrix_square(even, odd);
|
||||
|
||||
if ((len2 & 1) != 0) crc1 = gf2_matrix_times(even, crc1);
|
||||
len2 >>= 1;
|
||||
|
||||
if (len2 == 0) break;
|
||||
|
||||
// another iteration of the loop with odd and even swapped
|
||||
gf2_matrix_square(odd, even);
|
||||
if ((len2 & 1) != 0) crc1 = gf2_matrix_times(odd, crc1);
|
||||
len2 >>= 1;
|
||||
} while (len2 != 0);
|
||||
|
||||
crc1 ^= crc2;
|
||||
return ~crc1;
|
||||
}
|
||||
|
||||
private static uint[]? even_cache = null;
|
||||
private static uint[]? odd_cache;
|
||||
|
||||
private static void Prepare_even_odd_Cache()
|
||||
{
|
||||
var even = new uint[32]; // even-power-of-two zeros operator
|
||||
var odd = new uint[32]; // odd-power-of-two zeros operator
|
||||
|
||||
// put operator for one zero bit in odd
|
||||
odd[0] = kPoly; // the CRC-32 polynomial
|
||||
for (int i = 1; i < 32; i++) odd[i] = 1U << (i - 1);
|
||||
|
||||
// put operator for two zero bits in even
|
||||
gf2_matrix_square(even, odd);
|
||||
|
||||
// put operator for four zero bits in odd
|
||||
gf2_matrix_square(odd, even);
|
||||
|
||||
odd_cache = odd;
|
||||
even_cache = even;
|
||||
}
|
||||
|
||||
/// <param name="matrix">will not be modified</param>
|
||||
private static uint gf2_matrix_times(uint[] matrix, uint vec)
|
||||
{
|
||||
uint sum = 0;
|
||||
int i = 0;
|
||||
while (vec != 0)
|
||||
{
|
||||
if ((vec & 1) != 0) sum ^= matrix[i];
|
||||
vec >>= 1;
|
||||
i++;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
/// <param name="square">this array will be modified!</param>
|
||||
/// <param name="mat">will not be modified</param>
|
||||
private static void gf2_matrix_square(uint[] square, uint[] mat)
|
||||
{
|
||||
for (int i = 0; i < 32; i++)
|
||||
square[i] = gf2_matrix_times(mat, mat[i]);
|
||||
}
|
||||
|
||||
#endregion Combining
|
||||
|
||||
class Job
|
||||
{
|
||||
private ArraySegment<byte> data;
|
||||
private Job? previousJob;
|
||||
private ParallelCRC accumulator;
|
||||
|
||||
private ManualResetEvent? finished;
|
||||
|
||||
public Job(ArraySegment<byte> data, ParallelCRC accumulator, Job? previousJob)
|
||||
{
|
||||
this.data = data;
|
||||
this.accumulator = accumulator;
|
||||
this.previousJob = previousJob;
|
||||
this.finished = new ManualResetEvent(false);
|
||||
}
|
||||
|
||||
public void Start(object? arg)
|
||||
{
|
||||
var crc = ProcessBlock(kInit, data.Array!, data.Offset, data.Count);
|
||||
if (previousJob != null) previousJob.WaitAndDispose();
|
||||
accumulator.value = Combine(accumulator.value, crc, data.Count);
|
||||
finished?.Set();
|
||||
}
|
||||
|
||||
public void WaitAndDispose()
|
||||
{
|
||||
finished?.WaitOne();
|
||||
Dispose();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (finished != null) finished.Close();
|
||||
finished = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
144
SabreTools.Hashing/Checksum/Adler32.cs
Normal file
144
SabreTools.Hashing/Checksum/Adler32.cs
Normal file
@@ -0,0 +1,144 @@
|
||||
using System;
|
||||
using static SabreTools.Hashing.Checksum.Constants;
|
||||
|
||||
namespace SabreTools.Hashing.Checksum
|
||||
{
|
||||
/// <see href="https://github.com/madler/zlib/blob/v1.2.11/adler32.c"/>
|
||||
public class Adler32 : ChecksumBase<uint>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 32;
|
||||
|
||||
public Adler32()
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset the internal hashing state
|
||||
/// </summary>
|
||||
public override void Initialize()
|
||||
{
|
||||
_hash = 1;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void HashCore(byte[] data, int offset, int length)
|
||||
{
|
||||
// Split Adler-32 into component sums
|
||||
uint sum2 = (_hash >> 16) & 0xffff;
|
||||
_hash &= 0xffff;
|
||||
|
||||
// In case user likes doing a byte at a time, keep it fast
|
||||
if (length == 1)
|
||||
{
|
||||
_hash += data[offset];
|
||||
if (_hash >= A32BASE)
|
||||
_hash -= A32BASE;
|
||||
|
||||
sum2 += _hash;
|
||||
if (sum2 >= A32BASE)
|
||||
sum2 -= A32BASE;
|
||||
|
||||
_hash |= sum2 << 16;
|
||||
return;
|
||||
}
|
||||
|
||||
// In case short lengths are provided, keep it somewhat fast
|
||||
if (length < 16)
|
||||
{
|
||||
while (length-- > 0)
|
||||
{
|
||||
_hash += data[offset]++;
|
||||
sum2 += _hash;
|
||||
}
|
||||
|
||||
if (_hash >= A32BASE)
|
||||
_hash -= A32BASE;
|
||||
|
||||
// Only added so many BASE's
|
||||
sum2 %= A32BASE;
|
||||
_hash |= sum2 << 16;
|
||||
return;
|
||||
}
|
||||
|
||||
// Do length NMAX blocks -- requires just one modulo operation
|
||||
while (length >= A32NMAX)
|
||||
{
|
||||
// NMAX is divisible by 16
|
||||
length -= A32NMAX;
|
||||
uint n = A32NMAX / 16;
|
||||
do
|
||||
{
|
||||
_hash += data[offset + 0]; sum2 += _hash;
|
||||
_hash += data[offset + 1]; sum2 += _hash;
|
||||
_hash += data[offset + 2]; sum2 += _hash;
|
||||
_hash += data[offset + 3]; sum2 += _hash;
|
||||
_hash += data[offset + 4]; sum2 += _hash;
|
||||
_hash += data[offset + 5]; sum2 += _hash;
|
||||
_hash += data[offset + 6]; sum2 += _hash;
|
||||
_hash += data[offset + 7]; sum2 += _hash;
|
||||
_hash += data[offset + 8]; sum2 += _hash;
|
||||
_hash += data[offset + 9]; sum2 += _hash;
|
||||
_hash += data[offset + 10]; sum2 += _hash;
|
||||
_hash += data[offset + 11]; sum2 += _hash;
|
||||
_hash += data[offset + 12]; sum2 += _hash;
|
||||
_hash += data[offset + 13]; sum2 += _hash;
|
||||
_hash += data[offset + 14]; sum2 += _hash;
|
||||
_hash += data[offset + 15]; sum2 += _hash;
|
||||
|
||||
offset += 16;
|
||||
} while (--n > 0);
|
||||
}
|
||||
|
||||
// Do remaining bytes (less than NMAX, still just one modulo)
|
||||
if (length > 0)
|
||||
{
|
||||
// Avoid modulos if none remaining
|
||||
while (length >= 16)
|
||||
{
|
||||
length -= 16;
|
||||
|
||||
_hash += data[offset + 0]; sum2 += _hash;
|
||||
_hash += data[offset + 1]; sum2 += _hash;
|
||||
_hash += data[offset + 2]; sum2 += _hash;
|
||||
_hash += data[offset + 3]; sum2 += _hash;
|
||||
_hash += data[offset + 4]; sum2 += _hash;
|
||||
_hash += data[offset + 5]; sum2 += _hash;
|
||||
_hash += data[offset + 6]; sum2 += _hash;
|
||||
_hash += data[offset + 7]; sum2 += _hash;
|
||||
_hash += data[offset + 8]; sum2 += _hash;
|
||||
_hash += data[offset + 9]; sum2 += _hash;
|
||||
_hash += data[offset + 10]; sum2 += _hash;
|
||||
_hash += data[offset + 11]; sum2 += _hash;
|
||||
_hash += data[offset + 12]; sum2 += _hash;
|
||||
_hash += data[offset + 13]; sum2 += _hash;
|
||||
_hash += data[offset + 14]; sum2 += _hash;
|
||||
_hash += data[offset + 15]; sum2 += _hash;
|
||||
|
||||
offset += 16;
|
||||
}
|
||||
|
||||
while (length-- > 0)
|
||||
{
|
||||
_hash += data[offset++];
|
||||
sum2 += _hash;
|
||||
}
|
||||
|
||||
_hash %= A32BASE;
|
||||
sum2 %= A32BASE;
|
||||
}
|
||||
|
||||
// Return recombined sums
|
||||
_hash |= sum2 << 16;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
byte[] hashArr = BitConverter.GetBytes(_hash);
|
||||
Array.Reverse(hashArr);
|
||||
return hashArr;
|
||||
}
|
||||
}
|
||||
}
|
||||
22
SabreTools.Hashing/Checksum/BitOperations.cs
Normal file
22
SabreTools.Hashing/Checksum/BitOperations.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
namespace SabreTools.Hashing.Checksum
|
||||
{
|
||||
internal static class BitOperations
|
||||
{
|
||||
/// <summary>
|
||||
/// Clamp a value to a certain bit width and convert to a byte array
|
||||
/// </summary>
|
||||
public static byte[] ClampValueToBytes(ulong value, int bitWidth)
|
||||
{
|
||||
value &= ulong.MaxValue >> (64 - bitWidth);
|
||||
byte[] bytes = new byte[(bitWidth + 7) / 8];
|
||||
|
||||
for (int i = 0; i < bytes.Length; i++)
|
||||
{
|
||||
bytes[i] = (byte)value;
|
||||
value >>= 8;
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
50
SabreTools.Hashing/Checksum/ChecksumBase.cs
Normal file
50
SabreTools.Hashing/Checksum/ChecksumBase.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using System;
|
||||
|
||||
namespace SabreTools.Hashing.Checksum
|
||||
{
|
||||
/// <summary>
|
||||
/// Common base class for Fletcher checksums
|
||||
/// </summary>
|
||||
public abstract class ChecksumBase : System.Security.Cryptography.HashAlgorithm
|
||||
{
|
||||
// No common, untyped functionality
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Common base class for checksums
|
||||
/// </summary>
|
||||
public abstract class ChecksumBase<T> : ChecksumBase where T : struct
|
||||
{
|
||||
/// <summary>
|
||||
/// The current value of the hash
|
||||
/// </summary>
|
||||
protected T _hash;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Initialize()
|
||||
{
|
||||
_hash = default;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
byte[] hashArr = _hash switch
|
||||
{
|
||||
short s => BitConverter.GetBytes(s),
|
||||
ushort s => BitConverter.GetBytes(s),
|
||||
|
||||
int i => BitConverter.GetBytes(i),
|
||||
uint i => BitConverter.GetBytes(i),
|
||||
|
||||
long l => BitConverter.GetBytes(l),
|
||||
ulong l => BitConverter.GetBytes(l),
|
||||
|
||||
_ => [],
|
||||
};
|
||||
|
||||
Array.Reverse(hashArr);
|
||||
return hashArr;
|
||||
}
|
||||
}
|
||||
}
|
||||
33
SabreTools.Hashing/Checksum/Constants.cs
Normal file
33
SabreTools.Hashing/Checksum/Constants.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
namespace SabreTools.Hashing.Checksum
|
||||
{
|
||||
internal static class Constants
|
||||
{
|
||||
#region Adler-32
|
||||
|
||||
/// <summary>
|
||||
/// Largest prime smaller than 65536
|
||||
/// </summary>
|
||||
public const ushort A32BASE = 65521;
|
||||
|
||||
/// <summary>
|
||||
/// NMAX is the largest n such that 255n(n+1)/2 + (n+1)(<see cref="A32BASE">-1) <= 2^32-1
|
||||
/// </summary>
|
||||
public const ushort A32NMAX = 5552;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Fletcher-32
|
||||
|
||||
/// <summary>
|
||||
/// Max value for a single half of a Fletcher-32 checksum
|
||||
/// </summary>
|
||||
public const ushort F32BASE = 0xffff;
|
||||
|
||||
/// <summary>
|
||||
/// Max value for a single half of a Fletcher-64 checksum
|
||||
/// </summary>
|
||||
public const uint F64BASE = 0xffffffff;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
59
SabreTools.Hashing/Checksum/Crc.cs
Normal file
59
SabreTools.Hashing/Checksum/Crc.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using static SabreTools.Hashing.HashOperations;
|
||||
|
||||
namespace SabreTools.Hashing.Checksum
|
||||
{
|
||||
public class Crc : ChecksumBase<ulong>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => Def.Width;
|
||||
|
||||
/// <summary>
|
||||
/// Definition used to create the runner
|
||||
/// </summary>
|
||||
public readonly CrcDefinition Def;
|
||||
|
||||
/// <summary>
|
||||
/// Table used for calculation steps
|
||||
/// </summary>
|
||||
private readonly CrcTable _table;
|
||||
|
||||
public Crc(CrcDefinition def)
|
||||
{
|
||||
// Check for a valid bit width
|
||||
if (def.Width < 0 || def.Width > 64)
|
||||
throw new ArgumentOutOfRangeException(nameof(def));
|
||||
|
||||
Def = def;
|
||||
_table = new CrcTable(def);
|
||||
_hash = def.ReflectIn ? ReverseBits(def.Init, def.Width) : def.Init;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Initialize()
|
||||
{
|
||||
_hash = Def.Init;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void HashCore(byte[] data, int offset, int length)
|
||||
=> _table.TransformBlock(ref _hash, data, offset, length);
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
// Create a copy of the hash
|
||||
ulong localHash = _hash;
|
||||
|
||||
// Handle mutual reflection
|
||||
if (Def.ReflectIn ^ Def.ReflectOut)
|
||||
localHash = ReverseBits(localHash, Def.Width);
|
||||
|
||||
// Handle XOR
|
||||
localHash ^= Def.XorOut;
|
||||
|
||||
// Process the value and return
|
||||
return BitOperations.ClampValueToBytes(localHash, Def.Width);
|
||||
}
|
||||
}
|
||||
}
|
||||
65
SabreTools.Hashing/Checksum/CrcDefinition.cs
Normal file
65
SabreTools.Hashing/Checksum/CrcDefinition.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
namespace SabreTools.Hashing.Checksum
|
||||
{
|
||||
/// <see href="https://reveng.sourceforge.io/crc-catalogue/all.htm#crc.legend"/>
|
||||
public class CrcDefinition
|
||||
{
|
||||
/// <summary>
|
||||
/// The name assigned to the model in this Catalogue.
|
||||
/// </summary>
|
||||
public string? Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of bit cells in the linear feedback shift register;
|
||||
/// the degree of the generator polynomial, less one.
|
||||
/// </summary>
|
||||
public int Width { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The generator polynomial that sets the feedback tap positions of
|
||||
/// the shift register. poly is written in the hexadecimal, direct
|
||||
/// notation found in MSB-first code. The least significant bit
|
||||
/// corresponds to the inward end of the shift register, and is always
|
||||
/// set. The highest-order term is omitted.
|
||||
/// </summary>
|
||||
public ulong Poly { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The settings of the bit cells at the start of each calculation,
|
||||
/// before reading the first message bit. init is written in the
|
||||
/// hexadecimal, direct notation found in MSB-first code. The least
|
||||
/// significant bit corresponds to the inward end of the shift register.
|
||||
/// </summary>
|
||||
public ulong Init { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If equal to false, specifies that the characters of the message
|
||||
/// are read bit-by-bit, most significant bit (MSB) first; if equal to
|
||||
/// true, the characters are read bit-by-bit, least significant bit (LSB)
|
||||
/// first. Each sampled message bit is then XORed with the bit being
|
||||
/// simultaneously shifted out of the register at the most significant
|
||||
/// end, and the result is passed to the feedback taps.
|
||||
/// </summary>
|
||||
public bool ReflectIn { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If equal to false, specifies that the contents of the register after
|
||||
/// reading the last message bit are unreflected before presentation;
|
||||
/// if equal to true, it specifies that they are reflected,
|
||||
/// character-by-character, before presentation. For the purpose of this
|
||||
/// definition, the reflection is performed by swapping the content of
|
||||
/// each cell with that of the cell an equal distance from the opposite
|
||||
/// end of the register; the characters of the CRC are then true images
|
||||
/// of parts of the reflected register, the character containing the
|
||||
/// original MSB always appearing first.
|
||||
/// </summary>
|
||||
public bool ReflectOut { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The XOR value applied to the contents of the register after the last
|
||||
/// message bit has been read and after the optional reflection. xorout
|
||||
/// is written in hexadecimal notation, having the same endianness as
|
||||
/// the CRC such that its true image appears in the characters of the CRC.
|
||||
/// </summary>
|
||||
public ulong XorOut { get; set; }
|
||||
}
|
||||
}
|
||||
333
SabreTools.Hashing/Checksum/CrcTable.cs
Normal file
333
SabreTools.Hashing/Checksum/CrcTable.cs
Normal file
@@ -0,0 +1,333 @@
|
||||
using static SabreTools.Hashing.HashOperations;
|
||||
|
||||
namespace SabreTools.Hashing.Checksum
|
||||
{
|
||||
internal class CrcTable
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates if CRC should be processed bitwise instead of bytewise
|
||||
/// </summary>
|
||||
private bool Bitwise => _definition.Width < 8;
|
||||
|
||||
/// <summary>
|
||||
/// Number of bits to process at a time
|
||||
/// </summary>
|
||||
private int BitsPerStep => Bitwise ? 1 : 8;
|
||||
|
||||
/// <summary>
|
||||
/// Bit shift based on the CRC width
|
||||
/// </summary>
|
||||
private int BitShift => _definition.Width - BitsPerStep;
|
||||
|
||||
/// <summary>
|
||||
/// Bit mask based on the CRC width
|
||||
/// </summary>
|
||||
private ulong BitMask => 1UL << (_definition.Width - 1);
|
||||
|
||||
/// <summary>
|
||||
/// Mapping table
|
||||
/// </summary>
|
||||
private readonly ulong[,] _table;
|
||||
|
||||
/// <summary>
|
||||
/// Definition used to build the table
|
||||
/// </summary>
|
||||
private readonly CrcDefinition _definition;
|
||||
|
||||
/// <summary>
|
||||
/// Number of slices in the optimized table
|
||||
/// </summary>
|
||||
private const int SliceCount = 8;
|
||||
|
||||
public CrcTable(CrcDefinition def)
|
||||
{
|
||||
// Initialize the internal
|
||||
_definition = def;
|
||||
_table = new ulong[SliceCount, 1 << BitsPerStep];
|
||||
|
||||
// Build the standard table
|
||||
for (uint i = 0; i < (1 << BitsPerStep); i++)
|
||||
{
|
||||
// Get the starting value for this index
|
||||
ulong point = i;
|
||||
if (!Bitwise && def.ReflectIn)
|
||||
point = ReverseBits(point, BitsPerStep);
|
||||
|
||||
// Shift to account for storage
|
||||
point <<= _definition.Width - BitsPerStep;
|
||||
|
||||
// Accumulate the value
|
||||
for (int j = 0; j < BitsPerStep; j++)
|
||||
{
|
||||
if ((point & BitMask) > 0UL)
|
||||
point = (point << 1) ^ def.Poly;
|
||||
else
|
||||
point <<= 1;
|
||||
}
|
||||
|
||||
// Reflect if necessary
|
||||
if (def.ReflectIn)
|
||||
point = ReverseBits(point, def.Width);
|
||||
|
||||
// Shift back to account for storage
|
||||
point &= ulong.MaxValue >> (64 - def.Width);
|
||||
|
||||
// Assign to the table
|
||||
_table[0, i] = point;
|
||||
}
|
||||
|
||||
// Skip building the optimized table for bitwise processing
|
||||
if (Bitwise)
|
||||
return;
|
||||
|
||||
// Build the optimized table for non-bitwise processing
|
||||
for (int i = 1; i < SliceCount; i++)
|
||||
{
|
||||
// Build each slice from the previous
|
||||
for (int j = 0; j < 1 << BitsPerStep; j++)
|
||||
{
|
||||
ulong last = _table[i - 1, j];
|
||||
if (_definition.ReflectIn)
|
||||
_table[i, j] = (last >> BitsPerStep) ^ _table[0, (byte)last];
|
||||
else
|
||||
_table[i, j] = (last << BitsPerStep) ^ _table[0, (byte)(last >> BitShift)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hash a block of data and append it to the existing hash
|
||||
/// </summary>
|
||||
/// <param name="hash">Current hash value, updated on run</param>
|
||||
/// <param name="data">Byte array representing the data</param>
|
||||
/// <param name="offset">Offset in the byte array to include</param>
|
||||
/// <param name="length">Length of the data to hash</param>
|
||||
public void TransformBlock(ref ulong hash, byte[] data, int offset, int length)
|
||||
{
|
||||
// Empty data just returns
|
||||
if (data.Length == 0)
|
||||
return;
|
||||
|
||||
// Check for valid offset and length
|
||||
if (offset > data.Length)
|
||||
throw new System.ArgumentOutOfRangeException(nameof(offset));
|
||||
else if (offset + length > data.Length)
|
||||
throw new System.ArgumentOutOfRangeException(nameof(length));
|
||||
|
||||
// Try transforming fast first
|
||||
if (TransformBlockFast(ref hash, data, offset, length))
|
||||
return;
|
||||
|
||||
// Process the data byte-wise
|
||||
for (int i = offset; i < offset + length; i++)
|
||||
{
|
||||
PerformChecksumStep(ref hash, data, i);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform a single checksum step
|
||||
/// </summary>
|
||||
/// <param name="hash">Current hash value, updated on run</param>
|
||||
/// <param name="data">Byte array representing the data</param>
|
||||
/// <param name="offset">Offset in the data to process</param>
|
||||
private void PerformChecksumStep(ref ulong hash, byte[] data, int offset)
|
||||
{
|
||||
// Per-bit processing
|
||||
if (Bitwise)
|
||||
{
|
||||
for (int b = 0; b < 8; b++)
|
||||
{
|
||||
if (_definition.ReflectIn)
|
||||
hash = (hash >> 1) ^ _table[0, (byte)(hash & 1) ^ ((byte)(data[offset] >> b) & 1)];
|
||||
else
|
||||
hash = (hash << 1) ^ _table[0, (byte)((hash >> BitShift) & 1) ^ ((byte)(data[offset] >> (7 - b)) & 1)];
|
||||
}
|
||||
}
|
||||
|
||||
// Per-byte processing
|
||||
else
|
||||
{
|
||||
if (_definition.ReflectIn)
|
||||
hash = (hash >> 8) ^ _table[0, (byte)hash ^ data[offset]];
|
||||
else
|
||||
hash = (hash << 8) ^ _table[0, ((byte)(hash >> BitShift)) ^ data[offset]];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform an optimized transform step
|
||||
/// </summary>
|
||||
private bool TransformBlockFast(ref ulong hash, byte[] data, int offset, int length)
|
||||
{
|
||||
// Bitwise transformations are not optimized
|
||||
if (Bitwise)
|
||||
return false;
|
||||
|
||||
// All reflection-in implementations share an optimized path
|
||||
if (_definition.Width < 64 && _definition.ReflectIn)
|
||||
{
|
||||
TransformBlockFast8Reflect(ref hash, data, offset, length);
|
||||
return true;
|
||||
}
|
||||
else if (_definition.Width >= 64 && _definition.ReflectIn)
|
||||
{
|
||||
TransformBlockFast4Reflect(ref hash, data, offset, length);
|
||||
return true;
|
||||
}
|
||||
|
||||
// CRC-32 with no reflection-in has can be optimized
|
||||
if (_definition.Width == 32 && !_definition.ReflectIn)
|
||||
{
|
||||
TransformBlockFast8NoReflect(ref hash, data, offset, length);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Optimized transformation for CRC with reflection
|
||||
/// </summary>
|
||||
/// <remarks>Reads 4 bytes at a time</remarks>
|
||||
private void TransformBlockFast4Reflect(ref ulong hash, byte[] data, int offset, int length)
|
||||
{
|
||||
// Process on a copy of the hash
|
||||
ulong local = hash;
|
||||
|
||||
// Process aligned data
|
||||
if (length > 4)
|
||||
{
|
||||
long end = offset + (length & ~(uint)3);
|
||||
length &= 3;
|
||||
|
||||
while (offset < end)
|
||||
{
|
||||
ulong low = local ^ (uint)(
|
||||
data[offset + 0]
|
||||
+ (data[offset + 1] << 8)
|
||||
+ (data[offset + 2] << 16)
|
||||
+ (data[offset + 3] << 24));
|
||||
offset += 4;
|
||||
|
||||
local = _table[3, (byte)low]
|
||||
^ _table[2, (byte)(low >> 8)]
|
||||
^ _table[1, (byte)(low >> 16)]
|
||||
^ _table[0, (byte)(low >> 24)]
|
||||
^ (local >> 32);
|
||||
}
|
||||
}
|
||||
|
||||
// Process unaligned data
|
||||
while (length-- != 0)
|
||||
{
|
||||
PerformChecksumStep(ref local, data, offset++);
|
||||
}
|
||||
|
||||
// Assign the new hash value
|
||||
hash = local;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Optimized transformation for CRC with reflection
|
||||
/// </summary>
|
||||
/// <remarks>Reads 8 bytes at a time</remarks>
|
||||
private void TransformBlockFast8Reflect(ref ulong hash, byte[] data, int offset, int length)
|
||||
{
|
||||
// Process on a copy of the hash
|
||||
ulong local = hash;
|
||||
|
||||
// Process aligned data
|
||||
if (length > 8)
|
||||
{
|
||||
long end = offset + (length & ~(uint)7);
|
||||
length &= 7;
|
||||
|
||||
while (offset < end)
|
||||
{
|
||||
ulong low = local ^ (uint)(
|
||||
data[offset + 0]
|
||||
+ (data[offset + 1] << 8)
|
||||
+ (data[offset + 2] << 16)
|
||||
+ (data[offset + 3] << 24));
|
||||
ulong high = (uint)(
|
||||
data[offset + 4]
|
||||
+ (data[offset + 5] << 8)
|
||||
+ (data[offset + 6] << 16)
|
||||
+ (data[offset + 7] << 24));
|
||||
offset += 8;
|
||||
|
||||
local = _table[7, (byte)low]
|
||||
^ _table[6, (byte)(low >> 8)]
|
||||
^ _table[5, (byte)(low >> 16)]
|
||||
^ _table[4, (byte)(low >> 24)]
|
||||
^ _table[3, (byte)high]
|
||||
^ _table[2, (byte)(high >> 8)]
|
||||
^ _table[1, (byte)(high >> 16)]
|
||||
^ _table[0, (byte)(high >> 24)]
|
||||
^ (local >> 32);
|
||||
}
|
||||
}
|
||||
|
||||
// Process unaligned data
|
||||
while (length-- != 0)
|
||||
{
|
||||
PerformChecksumStep(ref local, data, offset++);
|
||||
}
|
||||
|
||||
// Assign the new hash value
|
||||
hash = local;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Optimized transformation for 32-bit CRC with no reflection
|
||||
/// </summary>
|
||||
/// <remarks>Reads 8 bytes at a time</remarks>
|
||||
private void TransformBlockFast8NoReflect(ref ulong hash, byte[] data, int offset, int length)
|
||||
{
|
||||
// Process on a copy of the hash
|
||||
ulong local = hash;
|
||||
|
||||
// Process aligned data
|
||||
if (length > 8)
|
||||
{
|
||||
long end = offset + (length & ~(uint)7);
|
||||
length &= 7;
|
||||
|
||||
while (offset < end)
|
||||
{
|
||||
ulong low = local ^ (uint)(
|
||||
data[offset + 3]
|
||||
+ (data[offset + 2] << 8)
|
||||
+ (data[offset + 1] << 16)
|
||||
+ (data[offset + 0] << 24));
|
||||
ulong high = (uint)(
|
||||
data[offset + 7]
|
||||
+ (data[offset + 6] << 8)
|
||||
+ (data[offset + 5] << 16)
|
||||
+ (data[offset + 4] << 24));
|
||||
offset += 8;
|
||||
|
||||
local = _table[4, (byte)low]
|
||||
^ _table[5, (byte)(low >> 8)]
|
||||
^ _table[6, (byte)(low >> 16)]
|
||||
^ _table[7, (byte)(low >> 24)]
|
||||
^ _table[0, (byte)high]
|
||||
^ _table[1, (byte)(high >> 8)]
|
||||
^ _table[2, (byte)(high >> 16)]
|
||||
^ _table[3, (byte)(high >> 24)]
|
||||
^ (local << 32);
|
||||
}
|
||||
}
|
||||
|
||||
// Process unaligned data
|
||||
while (length-- != 0)
|
||||
{
|
||||
PerformChecksumStep(ref local, data, offset++);
|
||||
}
|
||||
|
||||
// Assign the new hash value
|
||||
hash = local;
|
||||
}
|
||||
}
|
||||
}
|
||||
44
SabreTools.Hashing/Checksum/Fletcher16.cs
Normal file
44
SabreTools.Hashing/Checksum/Fletcher16.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
namespace SabreTools.Hashing.Checksum
|
||||
{
|
||||
/// <see href="https://en.wikipedia.org/wiki/Fletcher%27s_checksum#Optimizations"/>
|
||||
public class Fletcher16 : ChecksumBase<ushort>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 16;
|
||||
|
||||
public Fletcher16()
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void HashCore(byte[] data, int offset, int length)
|
||||
{
|
||||
// Split the existing hash
|
||||
uint c0 = (uint)(_hash & 0x00ff);
|
||||
uint c1 = (uint)((_hash >> 8) & 0x00ff);
|
||||
|
||||
// Found by solving for c1 overflow:
|
||||
// n > 0 and n * (n+1) / 2 * (2^8-1) < (2^32-1).
|
||||
while (length > 0)
|
||||
{
|
||||
int blocklen = length;
|
||||
if (blocklen > 5802)
|
||||
blocklen = 5802;
|
||||
|
||||
length -= blocklen;
|
||||
do
|
||||
{
|
||||
c0 += data[offset++];
|
||||
c1 += c0;
|
||||
} while (--blocklen > 0);
|
||||
|
||||
c0 %= 255;
|
||||
c1 %= 255;
|
||||
}
|
||||
|
||||
// Return recombined sums
|
||||
_hash = (ushort)((c1 << 8) | c0);
|
||||
}
|
||||
}
|
||||
}
|
||||
128
SabreTools.Hashing/Checksum/Fletcher32.cs
Normal file
128
SabreTools.Hashing/Checksum/Fletcher32.cs
Normal file
@@ -0,0 +1,128 @@
|
||||
using static SabreTools.Hashing.Checksum.Constants;
|
||||
|
||||
namespace SabreTools.Hashing.Checksum
|
||||
{
|
||||
/// <see href="https://en.wikipedia.org/wiki/Fletcher%27s_checksum#Optimizations"/>
|
||||
/// <remarks>Uses an Adler-32-like implementation instead of the above</remarks>
|
||||
public class Fletcher32 : ChecksumBase<uint>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 32;
|
||||
|
||||
public Fletcher32()
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void HashCore(byte[] data, int offset, int length)
|
||||
{
|
||||
// Split Fletcher-32 into component sums
|
||||
uint c0 = _hash & 0xffff;
|
||||
uint c1 = (_hash >> 16) & 0xffff;
|
||||
|
||||
// In case user likes doing a byte at a time, keep it fast
|
||||
if (length == 1)
|
||||
{
|
||||
c0 += data[offset];
|
||||
if (c0 >= F32BASE)
|
||||
c0 -= F32BASE;
|
||||
|
||||
c1 += c0;
|
||||
if (c1 >= F32BASE)
|
||||
c1 -= F32BASE;
|
||||
|
||||
_hash = (c1 << 16) | c0;
|
||||
return;
|
||||
}
|
||||
|
||||
// In case short lengths are provided, keep it somewhat fast
|
||||
if (length < 16)
|
||||
{
|
||||
while (length-- > 0)
|
||||
{
|
||||
c0 += data[offset]++;
|
||||
c1 += c0;
|
||||
}
|
||||
|
||||
if (c0 >= F32BASE)
|
||||
c0 -= F32BASE;
|
||||
|
||||
// Only added so many BASE's
|
||||
c1 %= F32BASE;
|
||||
_hash = (c1 << 16) | c0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Do length NMAX blocks -- requires just one modulo operation
|
||||
while (length >= A32NMAX)
|
||||
{
|
||||
// NMAX is divisible by 16
|
||||
length -= A32NMAX;
|
||||
uint n = A32NMAX / 16;
|
||||
do
|
||||
{
|
||||
c0 += data[offset + 0]; c1 += c0;
|
||||
c0 += data[offset + 1]; c1 += c0;
|
||||
c0 += data[offset + 2]; c1 += c0;
|
||||
c0 += data[offset + 3]; c1 += c0;
|
||||
c0 += data[offset + 4]; c1 += c0;
|
||||
c0 += data[offset + 5]; c1 += c0;
|
||||
c0 += data[offset + 6]; c1 += c0;
|
||||
c0 += data[offset + 7]; c1 += c0;
|
||||
c0 += data[offset + 8]; c1 += c0;
|
||||
c0 += data[offset + 9]; c1 += c0;
|
||||
c0 += data[offset + 10]; c1 += c0;
|
||||
c0 += data[offset + 11]; c1 += c0;
|
||||
c0 += data[offset + 12]; c1 += c0;
|
||||
c0 += data[offset + 13]; c1 += c0;
|
||||
c0 += data[offset + 14]; c1 += c0;
|
||||
c0 += data[offset + 15]; c1 += c0;
|
||||
|
||||
offset += 16;
|
||||
} while (--n > 0);
|
||||
}
|
||||
|
||||
// Do remaining bytes (less than NMAX, still just one modulo)
|
||||
if (length > 0)
|
||||
{
|
||||
// Avoid modulos if none remaining
|
||||
while (length >= 16)
|
||||
{
|
||||
length -= 16;
|
||||
|
||||
c0 += data[offset + 0]; c1 += c0;
|
||||
c0 += data[offset + 1]; c1 += c0;
|
||||
c0 += data[offset + 2]; c1 += c0;
|
||||
c0 += data[offset + 3]; c1 += c0;
|
||||
c0 += data[offset + 4]; c1 += c0;
|
||||
c0 += data[offset + 5]; c1 += c0;
|
||||
c0 += data[offset + 6]; c1 += c0;
|
||||
c0 += data[offset + 7]; c1 += c0;
|
||||
c0 += data[offset + 8]; c1 += c0;
|
||||
c0 += data[offset + 9]; c1 += c0;
|
||||
c0 += data[offset + 10]; c1 += c0;
|
||||
c0 += data[offset + 11]; c1 += c0;
|
||||
c0 += data[offset + 12]; c1 += c0;
|
||||
c0 += data[offset + 13]; c1 += c0;
|
||||
c0 += data[offset + 14]; c1 += c0;
|
||||
c0 += data[offset + 15]; c1 += c0;
|
||||
|
||||
offset += 16;
|
||||
}
|
||||
|
||||
while (length-- > 0)
|
||||
{
|
||||
c0 += data[offset++];
|
||||
c1 += c0;
|
||||
}
|
||||
|
||||
c0 %= F32BASE;
|
||||
c1 %= F32BASE;
|
||||
}
|
||||
|
||||
// Return recombined sums
|
||||
_hash = (c1 << 16) | c0;
|
||||
}
|
||||
}
|
||||
}
|
||||
128
SabreTools.Hashing/Checksum/Fletcher64.cs
Normal file
128
SabreTools.Hashing/Checksum/Fletcher64.cs
Normal file
@@ -0,0 +1,128 @@
|
||||
using static SabreTools.Hashing.Checksum.Constants;
|
||||
|
||||
namespace SabreTools.Hashing.Checksum
|
||||
{
|
||||
/// <see href="https://en.wikipedia.org/wiki/Fletcher%27s_checksum#Optimizations"/>
|
||||
/// <remarks>Uses an Adler-32-like implementation instead of the above</remarks>
|
||||
public class Fletcher64 : ChecksumBase<ulong>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 64;
|
||||
|
||||
public Fletcher64()
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void HashCore(byte[] data, int offset, int length)
|
||||
{
|
||||
// Split Fletcher-64 into component sums
|
||||
ulong c0 = _hash & 0xffffffff;
|
||||
ulong c1 = (_hash >> 32) & 0xffffffff;
|
||||
|
||||
// In case user likes doing a byte at a time, keep it fast
|
||||
if (length == 1)
|
||||
{
|
||||
c0 += data[offset];
|
||||
if (c0 >= F64BASE)
|
||||
c0 -= F64BASE;
|
||||
|
||||
c1 += c0;
|
||||
if (c1 >= F64BASE)
|
||||
c1 -= F64BASE;
|
||||
|
||||
_hash = (c1 << 32) | c0;
|
||||
return;
|
||||
}
|
||||
|
||||
// In case short lengths are provided, keep it somewhat fast
|
||||
if (length < 16)
|
||||
{
|
||||
while (length-- > 0)
|
||||
{
|
||||
c0 += data[offset]++;
|
||||
c1 += c0;
|
||||
}
|
||||
|
||||
if (c0 >= F64BASE)
|
||||
c0 -= F64BASE;
|
||||
|
||||
// Only added so many BASE's
|
||||
c1 %= F64BASE;
|
||||
_hash = (c1 << 32) | c0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Do length NMAX blocks -- requires just one modulo operation
|
||||
while (length >= A32NMAX)
|
||||
{
|
||||
// NMAX is divisible by 16
|
||||
length -= A32NMAX;
|
||||
uint n = A32NMAX / 16;
|
||||
do
|
||||
{
|
||||
c0 += data[offset + 0]; c1 += c0;
|
||||
c0 += data[offset + 1]; c1 += c0;
|
||||
c0 += data[offset + 2]; c1 += c0;
|
||||
c0 += data[offset + 3]; c1 += c0;
|
||||
c0 += data[offset + 4]; c1 += c0;
|
||||
c0 += data[offset + 5]; c1 += c0;
|
||||
c0 += data[offset + 6]; c1 += c0;
|
||||
c0 += data[offset + 7]; c1 += c0;
|
||||
c0 += data[offset + 8]; c1 += c0;
|
||||
c0 += data[offset + 9]; c1 += c0;
|
||||
c0 += data[offset + 10]; c1 += c0;
|
||||
c0 += data[offset + 11]; c1 += c0;
|
||||
c0 += data[offset + 12]; c1 += c0;
|
||||
c0 += data[offset + 13]; c1 += c0;
|
||||
c0 += data[offset + 14]; c1 += c0;
|
||||
c0 += data[offset + 15]; c1 += c0;
|
||||
|
||||
offset += 16;
|
||||
} while (--n > 0);
|
||||
}
|
||||
|
||||
// Do remaining bytes (less than NMAX, still just one modulo)
|
||||
if (length > 0)
|
||||
{
|
||||
// Avoid modulos if none remaining
|
||||
while (length >= 16)
|
||||
{
|
||||
length -= 16;
|
||||
|
||||
c0 += data[offset + 0]; c1 += c0;
|
||||
c0 += data[offset + 1]; c1 += c0;
|
||||
c0 += data[offset + 2]; c1 += c0;
|
||||
c0 += data[offset + 3]; c1 += c0;
|
||||
c0 += data[offset + 4]; c1 += c0;
|
||||
c0 += data[offset + 5]; c1 += c0;
|
||||
c0 += data[offset + 6]; c1 += c0;
|
||||
c0 += data[offset + 7]; c1 += c0;
|
||||
c0 += data[offset + 8]; c1 += c0;
|
||||
c0 += data[offset + 9]; c1 += c0;
|
||||
c0 += data[offset + 10]; c1 += c0;
|
||||
c0 += data[offset + 11]; c1 += c0;
|
||||
c0 += data[offset + 12]; c1 += c0;
|
||||
c0 += data[offset + 13]; c1 += c0;
|
||||
c0 += data[offset + 14]; c1 += c0;
|
||||
c0 += data[offset + 15]; c1 += c0;
|
||||
|
||||
offset += 16;
|
||||
}
|
||||
|
||||
while (length-- > 0)
|
||||
{
|
||||
c0 += data[offset++];
|
||||
c1 += c0;
|
||||
}
|
||||
|
||||
c0 %= F64BASE;
|
||||
c1 %= F64BASE;
|
||||
}
|
||||
|
||||
// Return recombined sums
|
||||
_hash = (c1 << 32) | c0;
|
||||
}
|
||||
}
|
||||
}
|
||||
46
SabreTools.Hashing/Checksum/MekaCrc.cs
Normal file
46
SabreTools.Hashing/Checksum/MekaCrc.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
|
||||
namespace SabreTools.Hashing.Checksum
|
||||
{
|
||||
/// <see href="https://github.com/ocornut/meka/blob/master/meka/srcs/checksum.cpp"/>
|
||||
public class MekaCrc : ChecksumBase<ulong>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 64;
|
||||
|
||||
public MekaCrc()
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset the internal hashing state
|
||||
/// </summary>
|
||||
public override void Initialize()
|
||||
{
|
||||
_hash = 0;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
/// <remarks>The original code limits the maximum processed size to 8KiB</remarks>
|
||||
protected override void HashCore(byte[] data, int offset, int length)
|
||||
{
|
||||
// Read the current hash into a byte array
|
||||
byte[] temp = BitConverter.GetBytes(_hash);
|
||||
|
||||
// Loop over the input and process
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
byte v = data[offset + i];
|
||||
unchecked
|
||||
{
|
||||
temp[v & 7]++;
|
||||
temp[v >> 5]++;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert the hash back into a value
|
||||
_hash = BitConverter.ToUInt64(temp, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
1704
SabreTools.Hashing/Checksum/StandardDefinitions.cs
Normal file
1704
SabreTools.Hashing/Checksum/StandardDefinitions.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,80 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
|
||||
namespace Compress.ThreadReaders
|
||||
{
|
||||
internal sealed class ThreadLoadBuffer : IDisposable
|
||||
{
|
||||
private readonly AutoResetEvent _waitEvent;
|
||||
private readonly AutoResetEvent _outEvent;
|
||||
private readonly Thread _tWorker;
|
||||
|
||||
private byte[]? _buffer;
|
||||
private int _size;
|
||||
private readonly Stream _ds;
|
||||
private bool _finished;
|
||||
public bool errorState;
|
||||
|
||||
public int SizeRead;
|
||||
|
||||
public ThreadLoadBuffer(Stream ds)
|
||||
{
|
||||
_waitEvent = new AutoResetEvent(false);
|
||||
_outEvent = new AutoResetEvent(false);
|
||||
_finished = false;
|
||||
_ds = ds;
|
||||
errorState = false;
|
||||
|
||||
_tWorker = new Thread(MainLoop);
|
||||
_tWorker.Start();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_waitEvent.Close();
|
||||
_outEvent.Close();
|
||||
}
|
||||
|
||||
private void MainLoop()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
_waitEvent.WaitOne();
|
||||
if (_finished)
|
||||
{
|
||||
break;
|
||||
}
|
||||
try
|
||||
{
|
||||
if (_buffer != null)
|
||||
SizeRead = _ds.Read(_buffer, 0, _size);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
errorState = true;
|
||||
}
|
||||
_outEvent.Set();
|
||||
}
|
||||
}
|
||||
|
||||
public void Trigger(byte[] buffer, int size)
|
||||
{
|
||||
_buffer = buffer;
|
||||
_size = size;
|
||||
_waitEvent.Set();
|
||||
}
|
||||
|
||||
public void Wait()
|
||||
{
|
||||
_outEvent.WaitOne();
|
||||
}
|
||||
|
||||
public void Finish()
|
||||
{
|
||||
_finished = true;
|
||||
_waitEvent.Set();
|
||||
_tWorker.Join();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,60 +5,6 @@ namespace SabreTools.Hashing
|
||||
#region 0-byte file constants
|
||||
|
||||
public const long SizeZero = 0;
|
||||
public const string CRCZero = "00000000";
|
||||
public static readonly byte[] CRCZeroBytes = [0x00, 0x00, 0x00, 0x00];
|
||||
public const string MD5Zero = "d41d8cd98f00b204e9800998ecf8427e";
|
||||
public static readonly byte[] MD5ZeroBytes = [ 0xd4, 0x1d, 0x8c, 0xd9,
|
||||
0x8f, 0x00, 0xb2, 0x04,
|
||||
0xe9, 0x80, 0x09, 0x98,
|
||||
0xec, 0xf8, 0x42, 0x7e ];
|
||||
public const string SHA1Zero = "da39a3ee5e6b4b0d3255bfef95601890afd80709";
|
||||
public static readonly byte[] SHA1ZeroBytes = [ 0xda, 0x39, 0xa3, 0xee,
|
||||
0x5e, 0x6b, 0x4b, 0x0d,
|
||||
0x32, 0x55, 0xbf, 0xef,
|
||||
0x95, 0x60, 0x18, 0x90,
|
||||
0xaf, 0xd8, 0x07, 0x09 ];
|
||||
public const string SHA256Zero = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad";
|
||||
public static readonly byte[] SHA256ZeroBytes = [ 0xba, 0x78, 0x16, 0xbf,
|
||||
0x8f, 0x01, 0xcf, 0xea,
|
||||
0x41, 0x41, 0x40, 0xde,
|
||||
0x5d, 0xae, 0x22, 0x23,
|
||||
0xb0, 0x03, 0x61, 0xa3,
|
||||
0x96, 0x17, 0x7a, 0x9c,
|
||||
0xb4, 0x10, 0xff, 0x61,
|
||||
0xf2, 0x00, 0x15, 0xad ];
|
||||
public const string SHA384Zero = "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7";
|
||||
public static readonly byte[] SHA384ZeroBytes = [ 0xcb, 0x00, 0x75, 0x3f,
|
||||
0x45, 0xa3, 0x5e, 0x8b,
|
||||
0xb5, 0xa0, 0x3d, 0x69,
|
||||
0x9a, 0xc6, 0x50, 0x07,
|
||||
0x27, 0x2c, 0x32, 0xab,
|
||||
0x0e, 0xde, 0xd1, 0x63,
|
||||
0x1a, 0x8b, 0x60, 0x5a,
|
||||
0x43, 0xff, 0x5b, 0xed,
|
||||
0x80, 0x86, 0x07, 0x2b,
|
||||
0xa1, 0xe7, 0xcc, 0x23,
|
||||
0x58, 0xba, 0xec, 0xa1,
|
||||
0x34, 0xc8, 0x25, 0xa7 ];
|
||||
public const string SHA512Zero = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f";
|
||||
public static readonly byte[] SHA512ZeroBytes = [ 0xdd, 0xaf, 0x35, 0xa1,
|
||||
0x93, 0x61, 0x7a, 0xba,
|
||||
0xcc, 0x41, 0x73, 0x49,
|
||||
0xae, 0x20, 0x41, 0x31,
|
||||
0x12, 0xe6, 0xfa, 0x4e,
|
||||
0x89, 0xa9, 0x7e, 0xa2,
|
||||
0x0a, 0x9e, 0xee, 0xe6,
|
||||
0x4b, 0x55, 0xd3, 0x9a,
|
||||
0x21, 0x92, 0x99, 0x2a,
|
||||
0x27, 0x4f, 0xc1, 0xa8,
|
||||
0x36, 0xba, 0x3c, 0x23,
|
||||
0xa3, 0xfe, 0xeb, 0xbd,
|
||||
0x45, 0x4d, 0x44, 0x23,
|
||||
0x64, 0x3c, 0xe8, 0x0e,
|
||||
0x2a, 0x9a, 0xc9, 0x4f,
|
||||
0xa5, 0x4c, 0xa4, 0x9f ];
|
||||
public const string SpamSumZero = "QXX";
|
||||
public static readonly byte[] SpamSumZeroBytes = [0x51, 0x58, 0x58];
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -73,4 +19,4 @@ namespace SabreTools.Hashing
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,182 @@
|
||||
namespace SabreTools.Hashing.Tiger
|
||||
namespace SabreTools.Hashing.CryptographicHash
|
||||
{
|
||||
/// <summary>
|
||||
/// Tiger S boxes
|
||||
/// </summary>
|
||||
public static class SBoxes
|
||||
internal static class Constants
|
||||
{
|
||||
public static readonly ulong[] Table =
|
||||
// <see href="https://datatracker.ietf.org/doc/html/rfc1115"/>
|
||||
#region MD2
|
||||
|
||||
/// <summary>
|
||||
/// S-Boxes
|
||||
/// </summary>
|
||||
public static readonly byte[] MD2SBox =
|
||||
[
|
||||
0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, 0x3D, 0x36, 0x54, 0xA1, 0xEC, 0xF0, 0x06, 0x13,
|
||||
0x62, 0xA7, 0x05, 0xF3, 0xC0, 0xC7, 0x73, 0x8C, 0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C, 0x82, 0xCA,
|
||||
0x1E, 0x9B, 0x57, 0x3C, 0xFD, 0xD4, 0xE0, 0x16, 0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12,
|
||||
0xBE, 0x4E, 0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49, 0xA0, 0xFB, 0xF5, 0x8E, 0xBB, 0x2F, 0xEE, 0x7A,
|
||||
0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2, 0x07, 0x3F, 0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21,
|
||||
0x80, 0x7F, 0x5D, 0x9A, 0x5A, 0x90, 0x32, 0x27, 0x35, 0x3E, 0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03,
|
||||
0xFF, 0x19, 0x30, 0xB3, 0x48, 0xA5, 0xB5, 0xD1, 0xD7, 0x5E, 0x92, 0x2A, 0xAC, 0x56, 0xAA, 0xC6,
|
||||
0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6, 0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1,
|
||||
0x45, 0x9D, 0x70, 0x59, 0x64, 0x71, 0x87, 0x20, 0x86, 0x5B, 0xCF, 0x65, 0xE6, 0x2D, 0xA8, 0x02,
|
||||
0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0, 0xB9, 0xF6, 0x1C, 0x46, 0x61, 0x69, 0x34, 0x40, 0x7E, 0x0F,
|
||||
0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A, 0xC3, 0x5C, 0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26,
|
||||
0x2C, 0x53, 0x0D, 0x6E, 0x85, 0x28, 0x84, 0x09, 0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81, 0x4D, 0x52,
|
||||
0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA, 0x24, 0xE1, 0x7B, 0x08, 0x0C, 0xBD, 0xB1, 0x4A,
|
||||
0x78, 0x88, 0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D, 0xE9, 0xCB, 0xD5, 0xFE, 0x3B, 0x00, 0x1D, 0x39,
|
||||
0xF2, 0xEF, 0xB7, 0x0E, 0x66, 0x58, 0xD0, 0xE4, 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A,
|
||||
0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, 0xDB, 0x99, 0x8D, 0x33, 0x9F, 0x11, 0x83, 0x14,
|
||||
];
|
||||
|
||||
#endregion
|
||||
|
||||
// <see href="https://datatracker.ietf.org/doc/html/rfc1320"/>
|
||||
#region MD4
|
||||
|
||||
public const uint MD4SeedA = 0x67452301;
|
||||
public const uint MD4SeedB = 0xefcdab89;
|
||||
public const uint MD4SeedC = 0x98badcfe;
|
||||
public const uint MD4SeedD = 0x10325476;
|
||||
|
||||
public const uint MD4Round1 = 0x00000000;
|
||||
public const uint MD4Round2 = 0x5A827999;
|
||||
public const uint MD4Round3 = 0x6ED9EBA1;
|
||||
|
||||
#endregion
|
||||
|
||||
// <see href="https://cdn.standards.iteh.ai/samples/39876/10f9f9f4bb614eaaaeba7e157e183ca3/ISO-IEC-10118-3-2004.pdf"/>
|
||||
#region RIPEMD-128 / RIPEMD-256
|
||||
|
||||
public const uint RMD128Round00To15 = 0x00000000;
|
||||
public const uint RMD128Round16To31 = 0x5A827999;
|
||||
public const uint RMD128Round32To47 = 0x6ED9EBA1;
|
||||
public const uint RMD128Round48To63 = 0x8F1BBCDC;
|
||||
|
||||
public const uint RMD128RoundPrime00To15 = 0x50A28BE6;
|
||||
public const uint RMD128RoundPrime16To31 = 0x5C4DD124;
|
||||
public const uint RMD128RoundPrime32To47 = 0x6D703EF3;
|
||||
public const uint RMD128RoundPrime48To63 = 0x00000000;
|
||||
|
||||
public const uint RMD128Y0 = 0x67452301;
|
||||
public const uint RMD128Y1 = 0xEFCDAB89;
|
||||
public const uint RMD128Y2 = 0x98BADCFE;
|
||||
public const uint RMD128Y3 = 0x10325476;
|
||||
public const uint RMD256Y4 = 0x76543210;
|
||||
public const uint RMD256Y5 = 0xFEDCBA98;
|
||||
public const uint RMD256Y6 = 0x89ABCDEF;
|
||||
public const uint RMD256Y7 = 0x01234567;
|
||||
|
||||
#endregion
|
||||
|
||||
// <see href="https://cdn.standards.iteh.ai/samples/39876/10f9f9f4bb614eaaaeba7e157e183ca3/ISO-IEC-10118-3-2004.pdf"/>
|
||||
#region RIPEMD-160 / RIPEMD-320
|
||||
|
||||
public const uint RMD160Round00To15 = 0x00000000;
|
||||
public const uint RMD160Round16To31 = 0x5A827999;
|
||||
public const uint RMD160Round32To47 = 0x6ED9EBA1;
|
||||
public const uint RMD160Round48To63 = 0x8F1BBCDC;
|
||||
public const uint RMD160Round64To79 = 0xA953FD4E;
|
||||
|
||||
public const uint RMD160RoundPrime00To15 = 0x50A28BE6;
|
||||
public const uint RMD160RoundPrime16To31 = 0x5C4DD124;
|
||||
public const uint RMD160RoundPrime32To47 = 0x6D703EF3;
|
||||
public const uint RMD160RoundPrime48To63 = 0x7A6D76E9;
|
||||
public const uint RMD160RoundPrime64To79 = 0x00000000;
|
||||
|
||||
public const uint RMD160Y0 = 0x67452301;
|
||||
public const uint RMD160Y1 = 0xEFCDAB89;
|
||||
public const uint RMD160Y2 = 0x98BADCFE;
|
||||
public const uint RMD160Y3 = 0x10325476;
|
||||
public const uint RMD160Y4 = 0xC3D2E1F0;
|
||||
public const uint RMD320Y5 = 0x76543210;
|
||||
public const uint RMD320Y6 = 0xFEDCBA98;
|
||||
public const uint RMD320Y7 = 0x89ABCDEF;
|
||||
public const uint RMD320Y8 = 0x01234567;
|
||||
public const uint RMD320Y9 = 0x3C2D1E0F;
|
||||
|
||||
/// <summary>
|
||||
/// t_i
|
||||
/// </summary>
|
||||
public static readonly byte[] RMD160Ti =
|
||||
[
|
||||
11, 14, 15, 12, 5, 8, 7, 9,
|
||||
11, 13, 14, 15, 6, 7, 9, 8,
|
||||
7, 6, 8, 13, 11, 9, 7, 15,
|
||||
7, 12, 15, 9, 11, 7, 13, 12,
|
||||
11, 13, 6, 7, 14, 9, 13, 15,
|
||||
14, 8, 13, 6, 5, 12, 7, 5,
|
||||
11, 12, 14, 15, 14, 15, 9, 8,
|
||||
9, 14, 5, 6, 8, 6, 5, 12,
|
||||
9, 15, 5, 11, 6, 8, 13, 12,
|
||||
5, 12, 13, 14, 11, 8, 5, 6,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// t'_i
|
||||
/// </summary>
|
||||
public static readonly byte[] RMD160Tpi =
|
||||
[
|
||||
8, 9, 9, 11, 13, 15, 15, 5,
|
||||
7, 7, 8, 11, 14, 14, 12, 6,
|
||||
9, 13, 15, 7, 12, 8, 9, 11,
|
||||
7, 7, 12, 7, 6, 15, 13, 11,
|
||||
9, 7, 15, 11, 8, 6, 6, 14,
|
||||
12, 13, 5, 14, 13, 13, 7, 5,
|
||||
15, 5, 8, 11, 14, 14, 6, 14,
|
||||
6, 9, 12, 9, 12, 5, 15, 8,
|
||||
8, 5, 12, 9, 12, 5, 14, 6,
|
||||
8, 13, 6, 5, 15, 13, 11, 11,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// a_i
|
||||
/// </summary>
|
||||
public static readonly byte[] RMD160Ai =
|
||||
[
|
||||
0, 1, 2, 3, 4, 5, 6, 7,
|
||||
8, 9, 10, 11, 12, 13, 14, 15,
|
||||
7, 4, 13, 1, 10, 6, 15, 3,
|
||||
12, 0, 9, 5, 2, 14, 11, 8,
|
||||
3, 10, 14, 4, 9, 15, 8, 1,
|
||||
2, 7, 0, 6, 13, 11, 5, 12,
|
||||
1, 9, 11, 10, 0, 8, 12, 4,
|
||||
13, 3, 7, 15, 14, 5, 6, 2,
|
||||
4, 0, 5, 9, 7, 12, 2, 10,
|
||||
14, 1, 3, 8, 11, 6, 15, 13,
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// a'_i
|
||||
/// </summary>
|
||||
public static readonly byte[] RMD160Api =
|
||||
[
|
||||
5, 14, 7, 0, 9, 2, 11, 4,
|
||||
13, 6, 15, 8, 1, 10, 3, 12,
|
||||
6, 11, 3, 7, 0, 13, 5, 10,
|
||||
14, 15, 8, 12, 4, 9, 1, 2,
|
||||
15, 5, 1, 3, 7, 14, 6, 9,
|
||||
11, 8, 12, 2, 10, 0, 4, 13,
|
||||
8, 6, 4, 1, 3, 11, 15, 0,
|
||||
5, 12, 2, 13, 9, 7, 10, 14,
|
||||
12, 15, 10, 4, 1, 5, 8, 7,
|
||||
6, 2, 13, 14, 0, 3, 9, 11,
|
||||
];
|
||||
|
||||
#endregion
|
||||
|
||||
/// <see href="https://biham.cs.technion.ac.il/Reports/Tiger//>
|
||||
#region Tiger-128 / Tiger-160 / Tiger-192
|
||||
|
||||
public const ulong TigerSeedA = 0x0123456789ABCDEF;
|
||||
|
||||
public const ulong TigerSeedB = 0xFEDCBA9876543210;
|
||||
|
||||
public const ulong TigerSeedC = 0xF096A5B4C3B2E187;
|
||||
|
||||
/// <summary>
|
||||
/// S-Boxes
|
||||
/// </summary>
|
||||
public static readonly ulong[] TigerSBox =
|
||||
[
|
||||
0x02AAB17CF7E90C5E /* 0 */, 0xAC424B03E243A8EC /* 1 */,
|
||||
0x72CD5BE30DD5FCD3 /* 2 */, 0x6D019B93F6F97F3A /* 3 */,
|
||||
@@ -520,5 +691,7 @@ namespace SabreTools.Hashing.Tiger
|
||||
0xCD56D9430EA8280E /* 1020 */, 0xC12591D7535F5065 /* 1021 */,
|
||||
0xC83223F1720AEF96 /* 1022 */, 0xC3A0396F7363A51F /* 1023 */
|
||||
];
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
169
SabreTools.Hashing/CryptographicHash/MD2.cs
Normal file
169
SabreTools.Hashing/CryptographicHash/MD2.cs
Normal file
@@ -0,0 +1,169 @@
|
||||
using System;
|
||||
using static SabreTools.Hashing.CryptographicHash.Constants;
|
||||
|
||||
namespace SabreTools.Hashing.CryptographicHash
|
||||
{
|
||||
/// <see href="https://datatracker.ietf.org/doc/html/rfc1115"/>
|
||||
public class MD2 : MessageDigestBase<uint>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 128;
|
||||
|
||||
/// <summary>
|
||||
/// Buffer for forming digest in
|
||||
/// </summary>
|
||||
/// <remarks>At the end, D[0...15] form the message digest</remarks>
|
||||
private readonly byte[] _digest = new byte[48];
|
||||
|
||||
/// <summary>
|
||||
/// Checksum register
|
||||
/// </summary>
|
||||
private readonly byte[] _checksum = new byte[16];
|
||||
|
||||
/// <summary>
|
||||
/// Number of bytes handled, modulo 16
|
||||
/// </summary>
|
||||
private byte _byteCount;
|
||||
|
||||
/// <summary>
|
||||
/// Last checksum char saved
|
||||
/// </summary>
|
||||
private byte _lastByte;
|
||||
|
||||
public MD2() : base()
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void ResetImpl()
|
||||
{
|
||||
Array.Clear(_digest, 0, _digest.Length);
|
||||
Array.Clear(_checksum, 0, _checksum.Length);
|
||||
_byteCount = 0;
|
||||
_lastByte = 0;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void HashCore(byte[] data, int offset, int length)
|
||||
{
|
||||
// Figure out how much buffer is needed
|
||||
int bufferLen = 16 - _byteCount;
|
||||
|
||||
// If there is buffer to fill and it will meet the limit
|
||||
if (_byteCount > 0 && _byteCount + length >= 16)
|
||||
{
|
||||
// Fill the buffer from the input
|
||||
for (int i = 0; i < bufferLen; i++)
|
||||
{
|
||||
// Add new character to buffer
|
||||
_digest[16 + _byteCount] = data[offset + i];
|
||||
_digest[32 + _byteCount] = (byte)(data[offset + i] ^ _digest[_byteCount]);
|
||||
|
||||
// Update checksum register C and value L
|
||||
_lastByte = _checksum[_byteCount] ^= MD2SBox[0xff & (data[offset + i] ^ _lastByte)];
|
||||
|
||||
// Increment i by one modulo 16
|
||||
_byteCount = (byte)((_byteCount + 1) & 15);
|
||||
}
|
||||
|
||||
// Set the new values
|
||||
offset += bufferLen;
|
||||
length -= bufferLen;
|
||||
|
||||
// Run the update
|
||||
Update();
|
||||
}
|
||||
|
||||
/// Process any standalone blocks
|
||||
while (length >= 16)
|
||||
{
|
||||
// Fill the buffer from the input
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
// Add new character to buffer
|
||||
_digest[16 + _byteCount] = data[offset + i];
|
||||
_digest[32 + _byteCount] = (byte)(data[offset + i] ^ _digest[_byteCount]);
|
||||
|
||||
// Update checksum register C and value L
|
||||
_lastByte = _checksum[_byteCount] ^= MD2SBox[0xff & (data[offset + i] ^ _lastByte)];
|
||||
|
||||
// Increment i by one modulo 16
|
||||
_byteCount = (byte)((_byteCount + 1) & 15);
|
||||
}
|
||||
|
||||
// Set the new values
|
||||
offset += 16;
|
||||
length -= 16;
|
||||
|
||||
// Run the update
|
||||
Update();
|
||||
}
|
||||
|
||||
// Save the remainder in the buffer
|
||||
if (length > 0)
|
||||
{
|
||||
// Fill the buffer from the input
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
// Add new character to buffer
|
||||
_digest[16 + _byteCount] = data[offset + i];
|
||||
_digest[32 + _byteCount] = (byte)(data[offset + i] ^ _digest[_byteCount]);
|
||||
|
||||
// Update checksum register C and value L
|
||||
_lastByte = _checksum[_byteCount] ^= MD2SBox[0xff & (data[offset + i] ^ _lastByte)];
|
||||
|
||||
// Increment i by one modulo 16
|
||||
_byteCount = (byte)((_byteCount + 1) & 15);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
// Determine the pad length
|
||||
byte padLength = (byte)(16 - _byteCount);
|
||||
|
||||
// Pad the block
|
||||
byte[] padding = new byte[padLength];
|
||||
#if NETFRAMEWORK || NETSTANDARD2_0
|
||||
for (int i = 0; i < padLength; i++)
|
||||
{
|
||||
padding[i] = padLength;
|
||||
}
|
||||
#else
|
||||
Array.Fill(padding, padLength);
|
||||
#endif
|
||||
|
||||
// Pad the block
|
||||
HashCore(padding, 0, padLength);
|
||||
HashCore(_checksum, 0, _checksum.Length);
|
||||
|
||||
// Get the hash
|
||||
var hash = new byte[16];
|
||||
Array.Copy(_digest, hash, 16);
|
||||
return hash;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The routine MDUPDATE updates the message digest context buffer to
|
||||
/// account for the presence of the character c in the message whose
|
||||
/// digest is being computed. This routine will be called for each
|
||||
/// message byte in turn.
|
||||
/// </summary>
|
||||
/// <remarks>The following is a more efficient version of the loop</remarks>
|
||||
private void Update()
|
||||
{
|
||||
byte t = 0;
|
||||
for (byte j = 0; j < 18; j++)
|
||||
{
|
||||
for (byte i = 0; i < 48; i++)
|
||||
{
|
||||
t = _digest[i] = (byte)(_digest[i] ^ MD2SBox[t]);
|
||||
}
|
||||
|
||||
t += j;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
214
SabreTools.Hashing/CryptographicHash/MD4.cs
Normal file
214
SabreTools.Hashing/CryptographicHash/MD4.cs
Normal file
@@ -0,0 +1,214 @@
|
||||
using System;
|
||||
using static SabreTools.Hashing.CryptographicHash.Constants;
|
||||
using static SabreTools.Hashing.HashOperations;
|
||||
|
||||
namespace SabreTools.Hashing.CryptographicHash
|
||||
{
|
||||
/// <see href="https://datatracker.ietf.org/doc/html/rfc1320"/>
|
||||
public class MD4 : MessageDigestBase<uint>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 128;
|
||||
|
||||
/// <summary>
|
||||
/// Set of 4 32-bit numbers representing the hash state
|
||||
/// </summary>
|
||||
private readonly uint[] _state = new uint[4];
|
||||
|
||||
public MD4() : base()
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void ResetImpl()
|
||||
{
|
||||
_state[0] = MD4SeedA;
|
||||
_state[1] = MD4SeedB;
|
||||
_state[2] = MD4SeedC;
|
||||
_state[3] = MD4SeedD;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void HashCore(byte[] data, int offset, int length)
|
||||
{
|
||||
// Figure out how much buffer is needed
|
||||
int bufferLen = (int)(_totalBytes & 0x3f);
|
||||
|
||||
// Increment the processed byte count
|
||||
_totalBytes += length;
|
||||
|
||||
// If there is buffer to fill and it will meet the limit
|
||||
if (bufferLen > 0 && bufferLen + length >= 64)
|
||||
{
|
||||
// Fill the buffer from the input
|
||||
Array.Copy(data, offset, _buffer, bufferLen, 64 - bufferLen);
|
||||
|
||||
// Set the new values
|
||||
offset += 64 - bufferLen;
|
||||
length -= 64 - bufferLen;
|
||||
|
||||
// Split the buffer for the round
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
_block[i] = ReadLE32(_buffer, i * 4);
|
||||
}
|
||||
|
||||
// Run the round
|
||||
Round();
|
||||
bufferLen = 0;
|
||||
}
|
||||
|
||||
/// Process any standalone blocks
|
||||
while (length >= 64)
|
||||
{
|
||||
// Fill the buffer from the input
|
||||
Array.Copy(data, offset, _buffer, 0, 64);
|
||||
|
||||
// Set the new values
|
||||
offset += 64;
|
||||
length -= 64;
|
||||
|
||||
// Split the buffer for the round
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
_block[i] = ReadLE32(_buffer, i * 4);
|
||||
}
|
||||
|
||||
// Run the round
|
||||
Round();
|
||||
}
|
||||
|
||||
// Save the remainder in the buffer
|
||||
if (length > 0)
|
||||
Array.Copy(data, offset, _buffer, bufferLen, length);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
// Determine the pad length
|
||||
int padLength = 64 - (int)(_totalBytes & 0x3f);
|
||||
if (padLength <= 8)
|
||||
padLength += 64;
|
||||
|
||||
// Get the total byte count in bits
|
||||
long totalBitCount = _totalBytes * 8;
|
||||
|
||||
// Prebuild the padding
|
||||
var padding = new byte[padLength];
|
||||
padding[0] = 0x80;
|
||||
padding[padLength - 1] = (byte)((totalBitCount >> 56) & 0xff);
|
||||
padding[padLength - 2] = (byte)((totalBitCount >> 48) & 0xff);
|
||||
padding[padLength - 3] = (byte)((totalBitCount >> 40) & 0xff);
|
||||
padding[padLength - 4] = (byte)((totalBitCount >> 32) & 0xff);
|
||||
padding[padLength - 5] = (byte)((totalBitCount >> 24) & 0xff);
|
||||
padding[padLength - 6] = (byte)((totalBitCount >> 16) & 0xff);
|
||||
padding[padLength - 7] = (byte)((totalBitCount >> 8) & 0xff);
|
||||
padding[padLength - 8] = (byte)((totalBitCount >> 0) & 0xff);
|
||||
|
||||
// Pad the block
|
||||
HashCore(padding, 0, padding.Length);
|
||||
|
||||
// Get the hash
|
||||
var hash = new byte[16];
|
||||
int hashOffset = 0;
|
||||
|
||||
// Assemble the hash array
|
||||
for (int i = 0; i < _state.Length; i++)
|
||||
{
|
||||
byte[] segment = BitConverter.GetBytes(_state[i]);
|
||||
Array.Copy(segment, 0, hash, hashOffset, 4);
|
||||
hashOffset += 4;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform one round of updates on the cached values
|
||||
/// </summary>
|
||||
private void Round()
|
||||
{
|
||||
// Setup values
|
||||
uint a = _state[0];
|
||||
uint b = _state[1];
|
||||
uint c = _state[2];
|
||||
uint d = _state[3];
|
||||
|
||||
// Round 1
|
||||
a = RotateLeft32(a + F(b, c, d) + _block[0] + MD4Round1, 3);
|
||||
d = RotateLeft32(d + F(a, b, c) + _block[1] + MD4Round1, 7);
|
||||
c = RotateLeft32(c + F(d, a, b) + _block[2] + MD4Round1, 11);
|
||||
b = RotateLeft32(b + F(c, d, a) + _block[3] + MD4Round1, 19);
|
||||
a = RotateLeft32(a + F(b, c, d) + _block[4] + MD4Round1, 3);
|
||||
d = RotateLeft32(d + F(a, b, c) + _block[5] + MD4Round1, 7);
|
||||
c = RotateLeft32(c + F(d, a, b) + _block[6] + MD4Round1, 11);
|
||||
b = RotateLeft32(b + F(c, d, a) + _block[7] + MD4Round1, 19);
|
||||
a = RotateLeft32(a + F(b, c, d) + _block[8] + MD4Round1, 3);
|
||||
d = RotateLeft32(d + F(a, b, c) + _block[9] + MD4Round1, 7);
|
||||
c = RotateLeft32(c + F(d, a, b) + _block[10] + MD4Round1, 11);
|
||||
b = RotateLeft32(b + F(c, d, a) + _block[11] + MD4Round1, 19);
|
||||
a = RotateLeft32(a + F(b, c, d) + _block[12] + MD4Round1, 3);
|
||||
d = RotateLeft32(d + F(a, b, c) + _block[13] + MD4Round1, 7);
|
||||
c = RotateLeft32(c + F(d, a, b) + _block[14] + MD4Round1, 11);
|
||||
b = RotateLeft32(b + F(c, d, a) + _block[15] + MD4Round1, 19);
|
||||
|
||||
// Round 2
|
||||
a = RotateLeft32(a + G(b, c, d) + _block[0] + MD4Round2, 3);
|
||||
d = RotateLeft32(d + G(a, b, c) + _block[4] + MD4Round2, 5);
|
||||
c = RotateLeft32(c + G(d, a, b) + _block[8] + MD4Round2, 9);
|
||||
b = RotateLeft32(b + G(c, d, a) + _block[12] + MD4Round2, 13);
|
||||
a = RotateLeft32(a + G(b, c, d) + _block[1] + MD4Round2, 3);
|
||||
d = RotateLeft32(d + G(a, b, c) + _block[5] + MD4Round2, 5);
|
||||
c = RotateLeft32(c + G(d, a, b) + _block[9] + MD4Round2, 9);
|
||||
b = RotateLeft32(b + G(c, d, a) + _block[13] + MD4Round2, 13);
|
||||
a = RotateLeft32(a + G(b, c, d) + _block[2] + MD4Round2, 3);
|
||||
d = RotateLeft32(d + G(a, b, c) + _block[6] + MD4Round2, 5);
|
||||
c = RotateLeft32(c + G(d, a, b) + _block[10] + MD4Round2, 9);
|
||||
b = RotateLeft32(b + G(c, d, a) + _block[14] + MD4Round2, 13);
|
||||
a = RotateLeft32(a + G(b, c, d) + _block[3] + MD4Round2, 3);
|
||||
d = RotateLeft32(d + G(a, b, c) + _block[7] + MD4Round2, 5);
|
||||
c = RotateLeft32(c + G(d, a, b) + _block[11] + MD4Round2, 9);
|
||||
b = RotateLeft32(b + G(c, d, a) + _block[15] + MD4Round2, 13);
|
||||
|
||||
// Round 3
|
||||
a = RotateLeft32(a + H(b, c, d) + _block[0] + MD4Round3, 3);
|
||||
d = RotateLeft32(d + H(a, b, c) + _block[8] + MD4Round3, 9);
|
||||
c = RotateLeft32(c + H(d, a, b) + _block[4] + MD4Round3, 11);
|
||||
b = RotateLeft32(b + H(c, d, a) + _block[12] + MD4Round3, 15);
|
||||
a = RotateLeft32(a + H(b, c, d) + _block[2] + MD4Round3, 3);
|
||||
d = RotateLeft32(d + H(a, b, c) + _block[10] + MD4Round3, 9);
|
||||
c = RotateLeft32(c + H(d, a, b) + _block[6] + MD4Round3, 11);
|
||||
b = RotateLeft32(b + H(c, d, a) + _block[14] + MD4Round3, 15);
|
||||
a = RotateLeft32(a + H(b, c, d) + _block[1] + MD4Round3, 3);
|
||||
d = RotateLeft32(d + H(a, b, c) + _block[9] + MD4Round3, 9);
|
||||
c = RotateLeft32(c + H(d, a, b) + _block[5] + MD4Round3, 11);
|
||||
b = RotateLeft32(b + H(c, d, a) + _block[13] + MD4Round3, 15);
|
||||
a = RotateLeft32(a + H(b, c, d) + _block[3] + MD4Round3, 3);
|
||||
d = RotateLeft32(d + H(a, b, c) + _block[11] + MD4Round3, 9);
|
||||
c = RotateLeft32(c + H(d, a, b) + _block[7] + MD4Round3, 11);
|
||||
b = RotateLeft32(b + H(c, d, a) + _block[15] + MD4Round3, 15);
|
||||
|
||||
// Update stored values
|
||||
_state[0] += a;
|
||||
_state[1] += b;
|
||||
_state[2] += c;
|
||||
_state[3] += d;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Auxiliary function F
|
||||
/// </summary>
|
||||
private static uint F(uint x, uint y, uint z) => (x & y) | (~x & z);
|
||||
|
||||
/// <summary>
|
||||
/// Auxiliary function G
|
||||
/// </summary>
|
||||
private static uint G(uint x, uint y, uint z) => (x & y) | (x & z) | (y & z);
|
||||
|
||||
/// <summary>
|
||||
/// Auxiliary function H
|
||||
/// </summary>
|
||||
private static uint H(uint x, uint y, uint z) => x ^ y ^ z;
|
||||
}
|
||||
}
|
||||
62
SabreTools.Hashing/CryptographicHash/MessageDigestBase.cs
Normal file
62
SabreTools.Hashing/CryptographicHash/MessageDigestBase.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using System;
|
||||
|
||||
namespace SabreTools.Hashing.CryptographicHash
|
||||
{
|
||||
public abstract class MessageDigestBase : System.Security.Cryptography.HashAlgorithm
|
||||
{
|
||||
/// <summary>
|
||||
/// Total number of bytes processed
|
||||
/// </summary>
|
||||
protected long _totalBytes;
|
||||
|
||||
/// <summary>
|
||||
/// Internal byte buffer to accumulate before <see cref="_block"/>
|
||||
/// </summary>
|
||||
protected readonly byte[] _buffer = new byte[64];
|
||||
|
||||
/// <summary>
|
||||
/// Reset additional values
|
||||
/// </summary>
|
||||
protected abstract void ResetImpl();
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected abstract override void HashCore(byte[] array, int ibStart, int cbSize);
|
||||
}
|
||||
|
||||
public abstract class MessageDigestBase<T> : MessageDigestBase where T : struct
|
||||
{
|
||||
/// <summary>
|
||||
/// Internal buffer for processing
|
||||
/// </summary>
|
||||
protected readonly T[] _block;
|
||||
|
||||
public MessageDigestBase()
|
||||
{
|
||||
if (typeof(T) == typeof(short) || typeof(T) == typeof(ushort))
|
||||
_block = new T[32];
|
||||
else if (typeof(T) == typeof(int) || typeof(T) == typeof(uint))
|
||||
_block = new T[16];
|
||||
else if (typeof(T) == typeof(long) || typeof(T) == typeof(ulong))
|
||||
_block = new T[8];
|
||||
|
||||
else
|
||||
throw new InvalidOperationException();
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Initialize()
|
||||
{
|
||||
// Reset the seed values
|
||||
ResetImpl();
|
||||
|
||||
// Reset the byte count
|
||||
_totalBytes = 0;
|
||||
|
||||
// Reset the buffers
|
||||
Array.Clear(_buffer, 0, _buffer.Length);
|
||||
Array.Clear(_block, 0, _block.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
447
SabreTools.Hashing/CryptographicHash/RipeMD128.cs
Normal file
447
SabreTools.Hashing/CryptographicHash/RipeMD128.cs
Normal file
@@ -0,0 +1,447 @@
|
||||
using System;
|
||||
using static SabreTools.Hashing.CryptographicHash.Constants;
|
||||
using static SabreTools.Hashing.HashOperations;
|
||||
|
||||
namespace SabreTools.Hashing.CryptographicHash
|
||||
{
|
||||
/// <see href="https://cdn.standards.iteh.ai/samples/39876/10f9f9f4bb614eaaaeba7e157e183ca3/ISO-IEC-10118-3-2004.pdf"/>
|
||||
/// <see href="https://homes.esat.kuleuven.be/~bosselae/ripemd160/pdf/AB-9601/AB-9601.pdf"/>
|
||||
public class RipeMD128 : MessageDigestBase<uint>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 128;
|
||||
|
||||
/// <summary>
|
||||
/// Set of 4 32-bit numbers representing the hash state
|
||||
/// </summary>
|
||||
private readonly uint[] _state = new uint[4];
|
||||
|
||||
public RipeMD128() : base()
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void ResetImpl()
|
||||
{
|
||||
_state[0] = RMD128Y0;
|
||||
_state[1] = RMD128Y1;
|
||||
_state[2] = RMD128Y2;
|
||||
_state[3] = RMD128Y3;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void HashCore(byte[] data, int offset, int length)
|
||||
{
|
||||
// Figure out how much buffer is needed
|
||||
int bufferLen = (int)(_totalBytes & 0x3f);
|
||||
|
||||
// Increment the processed byte count
|
||||
_totalBytes += length;
|
||||
|
||||
// If there is buffer to fill and it will meet the limit
|
||||
if (bufferLen > 0 && bufferLen + length >= 64)
|
||||
{
|
||||
// Fill the buffer from the input
|
||||
Array.Copy(data, offset, _buffer, bufferLen, 64 - bufferLen);
|
||||
|
||||
// Set the new values
|
||||
offset += 64 - bufferLen;
|
||||
length -= 64 - bufferLen;
|
||||
|
||||
// Split the buffer for the round
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
_block[i] = ReadLE32(_buffer, i * 4);
|
||||
}
|
||||
|
||||
// Run the round
|
||||
Round();
|
||||
bufferLen = 0;
|
||||
}
|
||||
|
||||
/// Process any standalone blocks
|
||||
while (length >= 64)
|
||||
{
|
||||
// Fill the buffer from the input
|
||||
Array.Copy(data, offset, _buffer, 0, 64);
|
||||
|
||||
// Set the new values
|
||||
offset += 64;
|
||||
length -= 64;
|
||||
|
||||
// Split the buffer for the round
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
_block[i] = ReadLE32(_buffer, i * 4);
|
||||
}
|
||||
|
||||
// Run the round
|
||||
Round();
|
||||
}
|
||||
|
||||
// Save the remainder in the buffer
|
||||
if (length > 0)
|
||||
Array.Copy(data, offset, _buffer, bufferLen, length);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
// Determine the pad length
|
||||
int padLength = 64 - (int)(_totalBytes & 0x3f);
|
||||
if (padLength <= 8)
|
||||
padLength += 64;
|
||||
|
||||
// Get the total byte count in bits
|
||||
long totalBitCount = _totalBytes * 8;
|
||||
|
||||
// Prebuild the padding
|
||||
var padding = new byte[padLength];
|
||||
padding[0] = 0x80;
|
||||
padding[padLength - 1] = (byte)((totalBitCount >> 56) & 0xff);
|
||||
padding[padLength - 2] = (byte)((totalBitCount >> 48) & 0xff);
|
||||
padding[padLength - 3] = (byte)((totalBitCount >> 40) & 0xff);
|
||||
padding[padLength - 4] = (byte)((totalBitCount >> 32) & 0xff);
|
||||
padding[padLength - 5] = (byte)((totalBitCount >> 24) & 0xff);
|
||||
padding[padLength - 6] = (byte)((totalBitCount >> 16) & 0xff);
|
||||
padding[padLength - 7] = (byte)((totalBitCount >> 8) & 0xff);
|
||||
padding[padLength - 8] = (byte)((totalBitCount >> 0) & 0xff);
|
||||
|
||||
// Pad the block
|
||||
HashCore(padding, 0, padding.Length);
|
||||
|
||||
// Get the hash
|
||||
var hash = new byte[16];
|
||||
int hashOffset = 0;
|
||||
|
||||
// Assemble the hash array
|
||||
for (int i = 0; i < _state.Length; i++)
|
||||
{
|
||||
byte[] segment = BitConverter.GetBytes(_state[i]);
|
||||
Array.Copy(segment, 0, hash, hashOffset, 4);
|
||||
hashOffset += 4;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform one round of updates on the cached values
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The official specification for RIPEMD-128 includes tables
|
||||
/// and instructions that represent a loop. Most standard implementations
|
||||
/// use the unrolled version of that loop to make it more efficient.
|
||||
///
|
||||
/// The below code started with the looped version but has been converted
|
||||
/// to the more standard implementation instead.
|
||||
/// </remarks>
|
||||
private void Round()
|
||||
{
|
||||
// Setup values
|
||||
uint x0 = _state[0], xp0 = _state[0];
|
||||
uint x1 = _state[1], xp1 = _state[1];
|
||||
uint x2 = _state[2], xp2 = _state[2];
|
||||
uint x3 = _state[3], xp3 = _state[3];
|
||||
|
||||
#region Rounds 0-15
|
||||
|
||||
// Round 0
|
||||
x0 = RotateLeft32(x0 + G00_15(x1, x2, x3) + _block[0] + RMD128Round00To15, 11);
|
||||
xp0 = RotateLeft32(xp0 + G48_63(xp1, xp2, xp3) + _block[5] + RMD128RoundPrime00To15, 8);
|
||||
|
||||
// Round 1
|
||||
x3 = RotateLeft32(x3 + G00_15(x0, x1, x2) + _block[1] + RMD128Round00To15, 14);
|
||||
xp3 = RotateLeft32(xp3 + G48_63(xp0, xp1, xp2) + _block[14] + RMD128RoundPrime00To15, 9);
|
||||
|
||||
// Round 2
|
||||
x2 = RotateLeft32(x2 + G00_15(x3, x0, x1) + _block[2] + RMD128Round00To15, 15);
|
||||
xp2 = RotateLeft32(xp2 + G48_63(xp3, xp0, xp1) + _block[7] + RMD128RoundPrime00To15, 9);
|
||||
|
||||
// Round 3
|
||||
x1 = RotateLeft32(x1 + G00_15(x2, x3, x0) + _block[3] + RMD128Round00To15, 12);
|
||||
xp1 = RotateLeft32(xp1 + G48_63(xp2, xp3, xp0) + _block[0] + RMD128RoundPrime00To15, 11);
|
||||
|
||||
// Round 4
|
||||
x0 = RotateLeft32(x0 + G00_15(x1, x2, x3) + _block[4] + RMD128Round00To15, 5);
|
||||
xp0 = RotateLeft32(xp0 + G48_63(xp1, xp2, xp3) + _block[9] + RMD128RoundPrime00To15, 13);
|
||||
|
||||
// Round 5
|
||||
x3 = RotateLeft32(x3 + G00_15(x0, x1, x2) + _block[5] + RMD128Round00To15, 8);
|
||||
xp3 = RotateLeft32(xp3 + G48_63(xp0, xp1, xp2) + _block[2] + RMD128RoundPrime00To15, 15);
|
||||
|
||||
// Round 6
|
||||
x2 = RotateLeft32(x2 + G00_15(x3, x0, x1) + _block[6] + RMD128Round00To15, 7);
|
||||
xp2 = RotateLeft32(xp2 + G48_63(xp3, xp0, xp1) + _block[11] + RMD128RoundPrime00To15, 15);
|
||||
|
||||
// Round 7
|
||||
x1 = RotateLeft32(x1 + G00_15(x2, x3, x0) + _block[7] + RMD128Round00To15, 9);
|
||||
xp1 = RotateLeft32(xp1 + G48_63(xp2, xp3, xp0) + _block[4] + RMD128RoundPrime00To15, 5);
|
||||
|
||||
// Round 8
|
||||
x0 = RotateLeft32(x0 + G00_15(x1, x2, x3) + _block[8] + RMD128Round00To15, 11);
|
||||
xp0 = RotateLeft32(xp0 + G48_63(xp1, xp2, xp3) + _block[13] + RMD128RoundPrime00To15, 7);
|
||||
|
||||
// Round 9
|
||||
x3 = RotateLeft32(x3 + G00_15(x0, x1, x2) + _block[9] + RMD128Round00To15, 13);
|
||||
xp3 = RotateLeft32(xp3 + G48_63(xp0, xp1, xp2) + _block[6] + RMD128RoundPrime00To15, 7);
|
||||
|
||||
// Round 10
|
||||
x2 = RotateLeft32(x2 + G00_15(x3, x0, x1) + _block[10] + RMD128Round00To15, 14);
|
||||
xp2 = RotateLeft32(xp2 + G48_63(xp3, xp0, xp1) + _block[15] + RMD128RoundPrime00To15, 8);
|
||||
|
||||
// Round 11
|
||||
x1 = RotateLeft32(x1 + G00_15(x2, x3, x0) + _block[11] + RMD128Round00To15, 15);
|
||||
xp1 = RotateLeft32(xp1 + G48_63(xp2, xp3, xp0) + _block[8] + RMD128RoundPrime00To15, 11);
|
||||
|
||||
// Round 12
|
||||
x0 = RotateLeft32(x0 + G00_15(x1, x2, x3) + _block[12] + RMD128Round00To15, 6);
|
||||
xp0 = RotateLeft32(xp0 + G48_63(xp1, xp2, xp3) + _block[1] + RMD128RoundPrime00To15, 14);
|
||||
|
||||
// Round 13
|
||||
x3 = RotateLeft32(x3 + G00_15(x0, x1, x2) + _block[13] + RMD128Round00To15, 7);
|
||||
xp3 = RotateLeft32(xp3 + G48_63(xp0, xp1, xp2) + _block[10] + RMD128RoundPrime00To15, 14);
|
||||
|
||||
// Round 14
|
||||
x2 = RotateLeft32(x2 + G00_15(x3, x0, x1) + _block[14] + RMD128Round00To15, 9);
|
||||
xp2 = RotateLeft32(xp2 + G48_63(xp3, xp0, xp1) + _block[3] + RMD128RoundPrime00To15, 12);
|
||||
|
||||
// Round 15
|
||||
x1 = RotateLeft32(x1 + G00_15(x2, x3, x0) + _block[15] + RMD128Round00To15, 8);
|
||||
xp1 = RotateLeft32(xp1 + G48_63(xp2, xp3, xp0) + _block[12] + RMD128RoundPrime00To15, 6);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Rounds 16-31
|
||||
|
||||
// Round 16
|
||||
x0 = RotateLeft32(x0 + G16_31(x1, x2, x3) + _block[7] + RMD128Round16To31, 7);
|
||||
xp0 = RotateLeft32(xp0 + G32_47(xp1, xp2, xp3) + _block[6] + RMD128RoundPrime16To31, 9);
|
||||
|
||||
// Round 17
|
||||
x3 = RotateLeft32(x3 + G16_31(x0, x1, x2) + _block[4] + RMD128Round16To31, 6);
|
||||
xp3 = RotateLeft32(xp3 + G32_47(xp0, xp1, xp2) + _block[11] + RMD128RoundPrime16To31, 13);
|
||||
|
||||
// Round 18
|
||||
x2 = RotateLeft32(x2 + G16_31(x3, x0, x1) + _block[13] + RMD128Round16To31, 8);
|
||||
xp2 = RotateLeft32(xp2 + G32_47(xp3, xp0, xp1) + _block[3] + RMD128RoundPrime16To31, 15);
|
||||
|
||||
// Round 19
|
||||
x1 = RotateLeft32(x1 + G16_31(x2, x3, x0) + _block[1] + RMD128Round16To31, 13);
|
||||
xp1 = RotateLeft32(xp1 + G32_47(xp2, xp3, xp0) + _block[7] + RMD128RoundPrime16To31, 7);
|
||||
|
||||
// Round 20
|
||||
x0 = RotateLeft32(x0 + G16_31(x1, x2, x3) + _block[10] + RMD128Round16To31, 11);
|
||||
xp0 = RotateLeft32(xp0 + G32_47(xp1, xp2, xp3) + _block[0] + RMD128RoundPrime16To31, 12);
|
||||
|
||||
// Round 21
|
||||
x3 = RotateLeft32(x3 + G16_31(x0, x1, x2) + _block[6] + RMD128Round16To31, 9);
|
||||
xp3 = RotateLeft32(xp3 + G32_47(xp0, xp1, xp2) + _block[13] + RMD128RoundPrime16To31, 8);
|
||||
|
||||
// Round 22
|
||||
x2 = RotateLeft32(x2 + G16_31(x3, x0, x1) + _block[15] + RMD128Round16To31, 7);
|
||||
xp2 = RotateLeft32(xp2 + G32_47(xp3, xp0, xp1) + _block[5] + RMD128RoundPrime16To31, 9);
|
||||
|
||||
// Round 23
|
||||
x1 = RotateLeft32(x1 + G16_31(x2, x3, x0) + _block[3] + RMD128Round16To31, 15);
|
||||
xp1 = RotateLeft32(xp1 + G32_47(xp2, xp3, xp0) + _block[10] + RMD128RoundPrime16To31, 11);
|
||||
|
||||
// Round 24
|
||||
x0 = RotateLeft32(x0 + G16_31(x1, x2, x3) + _block[12] + RMD128Round16To31, 7);
|
||||
xp0 = RotateLeft32(xp0 + G32_47(xp1, xp2, xp3) + _block[14] + RMD128RoundPrime16To31, 7);
|
||||
|
||||
// Round 25
|
||||
x3 = RotateLeft32(x3 + G16_31(x0, x1, x2) + _block[0] + RMD128Round16To31, 12);
|
||||
xp3 = RotateLeft32(xp3 + G32_47(xp0, xp1, xp2) + _block[15] + RMD128RoundPrime16To31, 7);
|
||||
|
||||
// Round 26
|
||||
x2 = RotateLeft32(x2 + G16_31(x3, x0, x1) + _block[9] + RMD128Round16To31, 15);
|
||||
xp2 = RotateLeft32(xp2 + G32_47(xp3, xp0, xp1) + _block[8] + RMD128RoundPrime16To31, 12);
|
||||
|
||||
// Round 27
|
||||
x1 = RotateLeft32(x1 + G16_31(x2, x3, x0) + _block[5] + RMD128Round16To31, 9);
|
||||
xp1 = RotateLeft32(xp1 + G32_47(xp2, xp3, xp0) + _block[12] + RMD128RoundPrime16To31, 7);
|
||||
|
||||
// Round 28
|
||||
x0 = RotateLeft32(x0 + G16_31(x1, x2, x3) + _block[2] + RMD128Round16To31, 11);
|
||||
xp0 = RotateLeft32(xp0 + G32_47(xp1, xp2, xp3) + _block[4] + RMD128RoundPrime16To31, 6);
|
||||
|
||||
// Round 29
|
||||
x3 = RotateLeft32(x3 + G16_31(x0, x1, x2) + _block[14] + RMD128Round16To31, 7);
|
||||
xp3 = RotateLeft32(xp3 + G32_47(xp0, xp1, xp2) + _block[9] + RMD128RoundPrime16To31, 15);
|
||||
|
||||
// Round 30
|
||||
x2 = RotateLeft32(x2 + G16_31(x3, x0, x1) + _block[11] + RMD128Round16To31, 13);
|
||||
xp2 = RotateLeft32(xp2 + G32_47(xp3, xp0, xp1) + _block[1] + RMD128RoundPrime16To31, 13);
|
||||
|
||||
// Round 31
|
||||
x1 = RotateLeft32(x1 + G16_31(x2, x3, x0) + _block[8] + RMD128Round16To31, 12);
|
||||
xp1 = RotateLeft32(xp1 + G32_47(xp2, xp3, xp0) + _block[2] + RMD128RoundPrime16To31, 11);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Rounds 32-47
|
||||
|
||||
// Round 32
|
||||
x0 = RotateLeft32(x0 + G32_47(x1, x2, x3) + _block[3] + RMD128Round32To47, 11);
|
||||
xp0 = RotateLeft32(xp0 + G16_31(xp1, xp2, xp3) + _block[15] + RMD128RoundPrime32To47, 9);
|
||||
|
||||
// Round 33
|
||||
x3 = RotateLeft32(x3 + G32_47(x0, x1, x2) + _block[10] + RMD128Round32To47, 13);
|
||||
xp3 = RotateLeft32(xp3 + G16_31(xp0, xp1, xp2) + _block[5] + RMD128RoundPrime32To47, 7);
|
||||
|
||||
// Round 34
|
||||
x2 = RotateLeft32(x2 + G32_47(x3, x0, x1) + _block[14] + RMD128Round32To47, 6);
|
||||
xp2 = RotateLeft32(xp2 + G16_31(xp3, xp0, xp1) + _block[1] + RMD128RoundPrime32To47, 15);
|
||||
|
||||
// Round 35
|
||||
x1 = RotateLeft32(x1 + G32_47(x2, x3, x0) + _block[4] + RMD128Round32To47, 7);
|
||||
xp1 = RotateLeft32(xp1 + G16_31(xp2, xp3, xp0) + _block[3] + RMD128RoundPrime32To47, 11);
|
||||
|
||||
// Round 36
|
||||
x0 = RotateLeft32(x0 + G32_47(x1, x2, x3) + _block[9] + RMD128Round32To47, 14);
|
||||
xp0 = RotateLeft32(xp0 + G16_31(xp1, xp2, xp3) + _block[7] + RMD128RoundPrime32To47, 8);
|
||||
|
||||
// Round 37
|
||||
x3 = RotateLeft32(x3 + G32_47(x0, x1, x2) + _block[15] + RMD128Round32To47, 9);
|
||||
xp3 = RotateLeft32(xp3 + G16_31(xp0, xp1, xp2) + _block[14] + RMD128RoundPrime32To47, 6);
|
||||
|
||||
// Round 38
|
||||
x2 = RotateLeft32(x2 + G32_47(x3, x0, x1) + _block[8] + RMD128Round32To47, 13);
|
||||
xp2 = RotateLeft32(xp2 + G16_31(xp3, xp0, xp1) + _block[6] + RMD128RoundPrime32To47, 6);
|
||||
|
||||
// Round 39
|
||||
x1 = RotateLeft32(x1 + G32_47(x2, x3, x0) + _block[1] + RMD128Round32To47, 15);
|
||||
xp1 = RotateLeft32(xp1 + G16_31(xp2, xp3, xp0) + _block[9] + RMD128RoundPrime32To47, 14);
|
||||
|
||||
// Round 40
|
||||
x0 = RotateLeft32(x0 + G32_47(x1, x2, x3) + _block[2] + RMD128Round32To47, 14);
|
||||
xp0 = RotateLeft32(xp0 + G16_31(xp1, xp2, xp3) + _block[11] + RMD128RoundPrime32To47, 12);
|
||||
|
||||
// Round 41
|
||||
x3 = RotateLeft32(x3 + G32_47(x0, x1, x2) + _block[7] + RMD128Round32To47, 8);
|
||||
xp3 = RotateLeft32(xp3 + G16_31(xp0, xp1, xp2) + _block[8] + RMD128RoundPrime32To47, 13);
|
||||
|
||||
// Round 42
|
||||
x2 = RotateLeft32(x2 + G32_47(x3, x0, x1) + _block[0] + RMD128Round32To47, 13);
|
||||
xp2 = RotateLeft32(xp2 + G16_31(xp3, xp0, xp1) + _block[12] + RMD128RoundPrime32To47, 5);
|
||||
|
||||
// Round 43
|
||||
x1 = RotateLeft32(x1 + G32_47(x2, x3, x0) + _block[6] + RMD128Round32To47, 6);
|
||||
xp1 = RotateLeft32(xp1 + G16_31(xp2, xp3, xp0) + _block[2] + RMD128RoundPrime32To47, 14);
|
||||
|
||||
// Round 44
|
||||
x0 = RotateLeft32(x0 + G32_47(x1, x2, x3) + _block[13] + RMD128Round32To47, 5);
|
||||
xp0 = RotateLeft32(xp0 + G16_31(xp1, xp2, xp3) + _block[10] + RMD128RoundPrime32To47, 13);
|
||||
|
||||
// Round 45
|
||||
x3 = RotateLeft32(x3 + G32_47(x0, x1, x2) + _block[11] + RMD128Round32To47, 12);
|
||||
xp3 = RotateLeft32(xp3 + G16_31(xp0, xp1, xp2) + _block[0] + RMD128RoundPrime32To47, 13);
|
||||
|
||||
// Round 46
|
||||
x2 = RotateLeft32(x2 + G32_47(x3, x0, x1) + _block[5] + RMD128Round32To47, 7);
|
||||
xp2 = RotateLeft32(xp2 + G16_31(xp3, xp0, xp1) + _block[4] + RMD128RoundPrime32To47, 7);
|
||||
|
||||
// Round 47
|
||||
x1 = RotateLeft32(x1 + G32_47(x2, x3, x0) + _block[12] + RMD128Round32To47, 5);
|
||||
xp1 = RotateLeft32(xp1 + G16_31(xp2, xp3, xp0) + _block[13] + RMD128RoundPrime32To47, 5);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Rounds 48-63
|
||||
|
||||
// Round 48
|
||||
x0 = RotateLeft32(x0 + G48_63(x1, x2, x3) + _block[1] + RMD128Round48To63, 11);
|
||||
xp0 = RotateLeft32(xp0 + G00_15(xp1, xp2, xp3) + _block[8] + RMD128RoundPrime48To63, 15);
|
||||
|
||||
// Round 49
|
||||
x3 = RotateLeft32(x3 + G48_63(x0, x1, x2) + _block[9] + RMD128Round48To63, 12);
|
||||
xp3 = RotateLeft32(xp3 + G00_15(xp0, xp1, xp2) + _block[6] + RMD128RoundPrime48To63, 5);
|
||||
|
||||
// Round 50
|
||||
x2 = RotateLeft32(x2 + G48_63(x3, x0, x1) + _block[11] + RMD128Round48To63, 14);
|
||||
xp2 = RotateLeft32(xp2 + G00_15(xp3, xp0, xp1) + _block[4] + RMD128RoundPrime48To63, 8);
|
||||
|
||||
// Round 51
|
||||
x1 = RotateLeft32(x1 + G48_63(x2, x3, x0) + _block[10] + RMD128Round48To63, 15);
|
||||
xp1 = RotateLeft32(xp1 + G00_15(xp2, xp3, xp0) + _block[1] + RMD128RoundPrime48To63, 11);
|
||||
|
||||
// Round 52
|
||||
x0 = RotateLeft32(x0 + G48_63(x1, x2, x3) + _block[0] + RMD128Round48To63, 14);
|
||||
xp0 = RotateLeft32(xp0 + G00_15(xp1, xp2, xp3) + _block[3] + RMD128RoundPrime48To63, 14);
|
||||
|
||||
// Round 53
|
||||
x3 = RotateLeft32(x3 + G48_63(x0, x1, x2) + _block[8] + RMD128Round48To63, 15);
|
||||
xp3 = RotateLeft32(xp3 + G00_15(xp0, xp1, xp2) + _block[11] + RMD128RoundPrime48To63, 14);
|
||||
|
||||
// Round 54
|
||||
x2 = RotateLeft32(x2 + G48_63(x3, x0, x1) + _block[12] + RMD128Round48To63, 9);
|
||||
xp2 = RotateLeft32(xp2 + G00_15(xp3, xp0, xp1) + _block[15] + RMD128RoundPrime48To63, 6);
|
||||
|
||||
// Round 55
|
||||
x1 = RotateLeft32(x1 + G48_63(x2, x3, x0) + _block[4] + RMD128Round48To63, 8);
|
||||
xp1 = RotateLeft32(xp1 + G00_15(xp2, xp3, xp0) + _block[0] + RMD128RoundPrime48To63, 14);
|
||||
|
||||
// Round 56
|
||||
x0 = RotateLeft32(x0 + G48_63(x1, x2, x3) + _block[13] + RMD128Round48To63, 9);
|
||||
xp0 = RotateLeft32(xp0 + G00_15(xp1, xp2, xp3) + _block[5] + RMD128RoundPrime48To63, 6);
|
||||
|
||||
// Round 57
|
||||
x3 = RotateLeft32(x3 + G48_63(x0, x1, x2) + _block[3] + RMD128Round48To63, 14);
|
||||
xp3 = RotateLeft32(xp3 + G00_15(xp0, xp1, xp2) + _block[12] + RMD128RoundPrime48To63, 9);
|
||||
|
||||
// Round 58
|
||||
x2 = RotateLeft32(x2 + G48_63(x3, x0, x1) + _block[7] + RMD128Round48To63, 5);
|
||||
xp2 = RotateLeft32(xp2 + G00_15(xp3, xp0, xp1) + _block[2] + RMD128RoundPrime48To63, 12);
|
||||
|
||||
// Round 59
|
||||
x1 = RotateLeft32(x1 + G48_63(x2, x3, x0) + _block[15] + RMD128Round48To63, 6);
|
||||
xp1 = RotateLeft32(xp1 + G00_15(xp2, xp3, xp0) + _block[13] + RMD128RoundPrime48To63, 9);
|
||||
|
||||
// Round 60
|
||||
x0 = RotateLeft32(x0 + G48_63(x1, x2, x3) + _block[14] + RMD128Round48To63, 8);
|
||||
xp0 = RotateLeft32(xp0 + G00_15(xp1, xp2, xp3) + _block[9] + RMD128RoundPrime48To63, 12);
|
||||
|
||||
// Round 61
|
||||
x3 = RotateLeft32(x3 + G48_63(x0, x1, x2) + _block[5] + RMD128Round48To63, 6);
|
||||
xp3 = RotateLeft32(xp3 + G00_15(xp0, xp1, xp2) + _block[7] + RMD128RoundPrime48To63, 5);
|
||||
|
||||
// Round 62
|
||||
x2 = RotateLeft32(x2 + G48_63(x3, x0, x1) + _block[6] + RMD128Round48To63, 5);
|
||||
xp2 = RotateLeft32(xp2 + G00_15(xp3, xp0, xp1) + _block[10] + RMD128RoundPrime48To63, 15);
|
||||
|
||||
// Round 63
|
||||
x1 = RotateLeft32(x1 + G48_63(x2, x3, x0) + _block[2] + RMD128Round48To63, 12);
|
||||
xp1 = RotateLeft32(xp1 + G00_15(xp2, xp3, xp0) + _block[14] + RMD128RoundPrime48To63, 8);
|
||||
|
||||
#endregion
|
||||
|
||||
// Avalanche values
|
||||
xp3 += x2 + _state[1];
|
||||
_state[1] = _state[2] + x3 + xp0;
|
||||
_state[2] = _state[3] + x0 + xp1;
|
||||
_state[3] = _state[0] + x1 + xp2;
|
||||
_state[0] = xp3;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Round operation [0, 15]
|
||||
/// </summary>
|
||||
private static uint G00_15(uint x, uint y, uint z) => x ^ y ^ z;
|
||||
|
||||
/// <summary>
|
||||
/// Round operation [16, 31]
|
||||
/// </summary>
|
||||
private static uint G16_31(uint x, uint y, uint z) => (x & y) | (~x & z);
|
||||
|
||||
/// <summary>
|
||||
/// Round operation [32, 47]
|
||||
/// </summary>
|
||||
private static uint G32_47(uint x, uint y, uint z) => (x | ~y) ^ z;
|
||||
|
||||
/// <summary>
|
||||
/// Round operation [48, 63]
|
||||
/// </summary>
|
||||
private static uint G48_63(uint x, uint y, uint z) => (x & z) | (y & ~z);
|
||||
}
|
||||
}
|
||||
683
SabreTools.Hashing/CryptographicHash/RipeMD160.cs
Normal file
683
SabreTools.Hashing/CryptographicHash/RipeMD160.cs
Normal file
@@ -0,0 +1,683 @@
|
||||
using System;
|
||||
using static SabreTools.Hashing.CryptographicHash.Constants;
|
||||
using static SabreTools.Hashing.HashOperations;
|
||||
|
||||
namespace SabreTools.Hashing.CryptographicHash
|
||||
{
|
||||
/// <see href="https://cdn.standards.iteh.ai/samples/39876/10f9f9f4bb614eaaaeba7e157e183ca3/ISO-IEC-10118-3-2004.pdf"/>
|
||||
/// <see href="https://homes.esat.kuleuven.be/~bosselae/ripemd160/pdf/AB-9601/AB-9601.pdf"/>
|
||||
public class RipeMD160 : MessageDigestBase<uint>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 160;
|
||||
|
||||
/// <summary>
|
||||
/// Set of 5 32-bit numbers representing the hash state
|
||||
/// </summary>
|
||||
private readonly uint[] _state = new uint[5];
|
||||
|
||||
public RipeMD160() : base()
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void ResetImpl()
|
||||
{
|
||||
_state[0] = RMD160Y0;
|
||||
_state[1] = RMD160Y1;
|
||||
_state[2] = RMD160Y2;
|
||||
_state[3] = RMD160Y3;
|
||||
_state[4] = RMD160Y4;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void HashCore(byte[] data, int offset, int length)
|
||||
{
|
||||
// Figure out how much buffer is needed
|
||||
int bufferLen = (int)(_totalBytes & 0x3f);
|
||||
|
||||
// Increment the processed byte count
|
||||
_totalBytes += length;
|
||||
|
||||
// If there is buffer to fill and it will meet the limit
|
||||
if (bufferLen > 0 && bufferLen + length >= 64)
|
||||
{
|
||||
// Fill the buffer from the input
|
||||
Array.Copy(data, offset, _buffer, bufferLen, 64 - bufferLen);
|
||||
|
||||
// Set the new values
|
||||
offset += 64 - bufferLen;
|
||||
length -= 64 - bufferLen;
|
||||
|
||||
// Split the buffer for the round
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
_block[i] = ReadLE32(_buffer, i * 4);
|
||||
}
|
||||
|
||||
// Run the round
|
||||
Round();
|
||||
bufferLen = 0;
|
||||
}
|
||||
|
||||
/// Process any standalone blocks
|
||||
while (length >= 64)
|
||||
{
|
||||
// Fill the buffer from the input
|
||||
Array.Copy(data, offset, _buffer, 0, 64);
|
||||
|
||||
// Set the new values
|
||||
offset += 64;
|
||||
length -= 64;
|
||||
|
||||
// Split the buffer for the round
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
_block[i] = ReadLE32(_buffer, i * 4);
|
||||
}
|
||||
|
||||
// Run the round
|
||||
Round();
|
||||
}
|
||||
|
||||
// Save the remainder in the buffer
|
||||
if (length > 0)
|
||||
Array.Copy(data, offset, _buffer, bufferLen, length);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
// Determine the pad length
|
||||
int padLength = 64 - (int)(_totalBytes & 0x3f);
|
||||
if (padLength <= 8)
|
||||
padLength += 64;
|
||||
|
||||
// Get the total byte count in bits
|
||||
long totalBitCount = _totalBytes * 8;
|
||||
|
||||
// Prebuild the padding
|
||||
var padding = new byte[padLength];
|
||||
padding[0] = 0x80;
|
||||
padding[padLength - 1] = (byte)((totalBitCount >> 56) & 0xff);
|
||||
padding[padLength - 2] = (byte)((totalBitCount >> 48) & 0xff);
|
||||
padding[padLength - 3] = (byte)((totalBitCount >> 40) & 0xff);
|
||||
padding[padLength - 4] = (byte)((totalBitCount >> 32) & 0xff);
|
||||
padding[padLength - 5] = (byte)((totalBitCount >> 24) & 0xff);
|
||||
padding[padLength - 6] = (byte)((totalBitCount >> 16) & 0xff);
|
||||
padding[padLength - 7] = (byte)((totalBitCount >> 8) & 0xff);
|
||||
padding[padLength - 8] = (byte)((totalBitCount >> 0) & 0xff);
|
||||
|
||||
// Pad the block
|
||||
HashCore(padding, 0, padding.Length);
|
||||
|
||||
// Get the hash
|
||||
var hash = new byte[20];
|
||||
int hashOffset = 0;
|
||||
|
||||
// Assemble the hash array
|
||||
for (int i = 0; i < _state.Length; i++)
|
||||
{
|
||||
byte[] segment = BitConverter.GetBytes(_state[i]);
|
||||
Array.Copy(segment, 0, hash, hashOffset, 4);
|
||||
hashOffset += 4;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform one round of updates on the cached values
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The official specification for RIPEMD-160 includes tables
|
||||
/// and instructions that represent a loop. Most standard implementations
|
||||
/// use the unrolled version of that loop to make it more efficient.
|
||||
///
|
||||
/// The below code started with the looped version but has been converted
|
||||
/// to the more standard implementation instead.
|
||||
/// </remarks>
|
||||
private void Round()
|
||||
{
|
||||
// Setup values
|
||||
uint x0 = _state[0], xp0 = _state[0];
|
||||
uint x1 = _state[1], xp1 = _state[1];
|
||||
uint x2 = _state[2], xp2 = _state[2];
|
||||
uint x3 = _state[3], xp3 = _state[3];
|
||||
uint x4 = _state[4], xp4 = _state[4];
|
||||
|
||||
#region Rounds 0-15
|
||||
|
||||
// Round 0
|
||||
x0 = RotateLeft32(x0 + G00_15(x1, x2, x3) + _block[0] + RMD160Round00To15, 11) + x4;
|
||||
x2 = RotateLeft32(x2, 10);
|
||||
xp0 = RotateLeft32(xp0 + G64_79(xp1, xp2, xp3) + _block[5] + RMD160RoundPrime00To15, 8) + xp4;
|
||||
xp2 = RotateLeft32(xp2, 10);
|
||||
|
||||
// Round 1
|
||||
x4 = RotateLeft32(x4 + G00_15(x0, x1, x2) + _block[1] + RMD160Round00To15, 14) + x3;
|
||||
x1 = RotateLeft32(x1, 10);
|
||||
xp4 = RotateLeft32(xp4 + G64_79(xp0, xp1, xp2) + _block[14] + RMD160RoundPrime00To15, 9) + xp3;
|
||||
xp1 = RotateLeft32(xp1, 10);
|
||||
|
||||
// Round 2
|
||||
x3 = RotateLeft32(x3 + G00_15(x4, x0, x1) + _block[2] + RMD160Round00To15, 15) + x2;
|
||||
x0 = RotateLeft32(x0, 10);
|
||||
xp3 = RotateLeft32(xp3 + G64_79(xp4, xp0, xp1) + _block[7] + RMD160RoundPrime00To15, 9) + xp2;
|
||||
xp0 = RotateLeft32(xp0, 10);
|
||||
|
||||
// Round 3
|
||||
x2 = RotateLeft32(x2 + G00_15(x3, x4, x0) + _block[3] + RMD160Round00To15, 12) + x1;
|
||||
x4 = RotateLeft32(x4, 10);
|
||||
xp2 = RotateLeft32(xp2 + G64_79(xp3, xp4, xp0) + _block[0] + RMD160RoundPrime00To15, 11) + xp1;
|
||||
xp4 = RotateLeft32(xp4, 10);
|
||||
|
||||
// Round 4
|
||||
x1 = RotateLeft32(x1 + G00_15(x2, x3, x4) + _block[4] + RMD160Round00To15, 5) + x0;
|
||||
x3 = RotateLeft32(x3, 10);
|
||||
xp1 = RotateLeft32(xp1 + G64_79(xp2, xp3, xp4) + _block[9] + RMD160RoundPrime00To15, 13) + xp0;
|
||||
xp3 = RotateLeft32(xp3, 10);
|
||||
|
||||
// Round 5
|
||||
x0 = RotateLeft32(x0 + G00_15(x1, x2, x3) + _block[5] + RMD160Round00To15, 8) + x4;
|
||||
x2 = RotateLeft32(x2, 10);
|
||||
xp0 = RotateLeft32(xp0 + G64_79(xp1, xp2, xp3) + _block[2] + RMD160RoundPrime00To15, 15) + xp4;
|
||||
xp2 = RotateLeft32(xp2, 10);
|
||||
|
||||
// Round 6
|
||||
x4 = RotateLeft32(x4 + G00_15(x0, x1, x2) + _block[6] + RMD160Round00To15, 7) + x3;
|
||||
x1 = RotateLeft32(x1, 10);
|
||||
xp4 = RotateLeft32(xp4 + G64_79(xp0, xp1, xp2) + _block[11] + RMD160RoundPrime00To15, 15) + xp3;
|
||||
xp1 = RotateLeft32(xp1, 10);
|
||||
|
||||
// Round 7
|
||||
x3 = RotateLeft32(x3 + G00_15(x4, x0, x1) + _block[7] + RMD160Round00To15, 9) + x2;
|
||||
x0 = RotateLeft32(x0, 10);
|
||||
xp3 = RotateLeft32(xp3 + G64_79(xp4, xp0, xp1) + _block[4] + RMD160RoundPrime00To15, 5) + xp2;
|
||||
xp0 = RotateLeft32(xp0, 10);
|
||||
|
||||
// Round 8
|
||||
x2 = RotateLeft32(x2 + G00_15(x3, x4, x0) + _block[8] + RMD160Round00To15, 11) + x1;
|
||||
x4 = RotateLeft32(x4, 10);
|
||||
xp2 = RotateLeft32(xp2 + G64_79(xp3, xp4, xp0) + _block[13] + RMD160RoundPrime00To15, 7) + xp1;
|
||||
xp4 = RotateLeft32(xp4, 10);
|
||||
|
||||
// Round 9
|
||||
x1 = RotateLeft32(x1 + G00_15(x2, x3, x4) + _block[9] + RMD160Round00To15, 13) + x0;
|
||||
x3 = RotateLeft32(x3, 10);
|
||||
xp1 = RotateLeft32(xp1 + G64_79(xp2, xp3, xp4) + _block[6] + RMD160RoundPrime00To15, 7) + xp0;
|
||||
xp3 = RotateLeft32(xp3, 10);
|
||||
|
||||
// Round 10
|
||||
x0 = RotateLeft32(x0 + G00_15(x1, x2, x3) + _block[10] + RMD160Round00To15, 14) + x4;
|
||||
x2 = RotateLeft32(x2, 10);
|
||||
xp0 = RotateLeft32(xp0 + G64_79(xp1, xp2, xp3) + _block[15] + RMD160RoundPrime00To15, 8) + xp4;
|
||||
xp2 = RotateLeft32(xp2, 10);
|
||||
|
||||
// Round 11
|
||||
x4 = RotateLeft32(x4 + G00_15(x0, x1, x2) + _block[11] + RMD160Round00To15, 15) + x3;
|
||||
x1 = RotateLeft32(x1, 10);
|
||||
xp4 = RotateLeft32(xp4 + G64_79(xp0, xp1, xp2) + _block[8] + RMD160RoundPrime00To15, 11) + xp3;
|
||||
xp1 = RotateLeft32(xp1, 10);
|
||||
|
||||
// Round 12
|
||||
x3 = RotateLeft32(x3 + G00_15(x4, x0, x1) + _block[12] + RMD160Round00To15, 6) + x2;
|
||||
x0 = RotateLeft32(x0, 10);
|
||||
xp3 = RotateLeft32(xp3 + G64_79(xp4, xp0, xp1) + _block[1] + RMD160RoundPrime00To15, 14) + xp2;
|
||||
xp0 = RotateLeft32(xp0, 10);
|
||||
|
||||
// Round 13
|
||||
x2 = RotateLeft32(x2 + G00_15(x3, x4, x0) + _block[13] + RMD160Round00To15, 7) + x1;
|
||||
x4 = RotateLeft32(x4, 10);
|
||||
xp2 = RotateLeft32(xp2 + G64_79(xp3, xp4, xp0) + _block[10] + RMD160RoundPrime00To15, 14) + xp1;
|
||||
xp4 = RotateLeft32(xp4, 10);
|
||||
|
||||
// Round 14
|
||||
x1 = RotateLeft32(x1 + G00_15(x2, x3, x4) + _block[14] + RMD160Round00To15, 9) + x0;
|
||||
x3 = RotateLeft32(x3, 10);
|
||||
xp1 = RotateLeft32(xp1 + G64_79(xp2, xp3, xp4) + _block[3] + RMD160RoundPrime00To15, 12) + xp0;
|
||||
xp3 = RotateLeft32(xp3, 10);
|
||||
|
||||
// Round 15
|
||||
x0 = RotateLeft32(x0 + G00_15(x1, x2, x3) + _block[15] + RMD160Round00To15, 8) + x4;
|
||||
x2 = RotateLeft32(x2, 10);
|
||||
xp0 = RotateLeft32(xp0 + G64_79(xp1, xp2, xp3) + _block[12] + RMD160RoundPrime00To15, 6) + xp4;
|
||||
xp2 = RotateLeft32(xp2, 10);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Rounds 16-31
|
||||
|
||||
// Round 16
|
||||
x4 = RotateLeft32(x4 + G16_31(x0, x1, x2) + _block[7] + RMD160Round16To31, 7) + x3;
|
||||
x1 = RotateLeft32(x1, 10);
|
||||
xp4 = RotateLeft32(xp4 + G48_63(xp0, xp1, xp2) + _block[6] + RMD160RoundPrime16To31, 9) + xp3;
|
||||
xp1 = RotateLeft32(xp1, 10);
|
||||
|
||||
// Round 17
|
||||
x3 = RotateLeft32(x3 + G16_31(x4, x0, x1) + _block[4] + RMD160Round16To31, 6) + x2;
|
||||
x0 = RotateLeft32(x0, 10);
|
||||
xp3 = RotateLeft32(xp3 + G48_63(xp4, xp0, xp1) + _block[11] + RMD160RoundPrime16To31, 13) + xp2;
|
||||
xp0 = RotateLeft32(xp0, 10);
|
||||
|
||||
// Round 18
|
||||
x2 = RotateLeft32(x2 + G16_31(x3, x4, x0) + _block[13] + RMD160Round16To31, 8) + x1;
|
||||
x4 = RotateLeft32(x4, 10);
|
||||
xp2 = RotateLeft32(xp2 + G48_63(xp3, xp4, xp0) + _block[3] + RMD160RoundPrime16To31, 15) + xp1;
|
||||
xp4 = RotateLeft32(xp4, 10);
|
||||
|
||||
// Round 19
|
||||
x1 = RotateLeft32(x1 + G16_31(x2, x3, x4) + _block[1] + RMD160Round16To31, 13) + x0;
|
||||
x3 = RotateLeft32(x3, 10);
|
||||
xp1 = RotateLeft32(xp1 + G48_63(xp2, xp3, xp4) + _block[7] + RMD160RoundPrime16To31, 7) + xp0;
|
||||
xp3 = RotateLeft32(xp3, 10);
|
||||
|
||||
// Round 20
|
||||
x0 = RotateLeft32(x0 + G16_31(x1, x2, x3) + _block[10] + RMD160Round16To31, 11) + x4;
|
||||
x2 = RotateLeft32(x2, 10);
|
||||
xp0 = RotateLeft32(xp0 + G48_63(xp1, xp2, xp3) + _block[0] + RMD160RoundPrime16To31, 12) + xp4;
|
||||
xp2 = RotateLeft32(xp2, 10);
|
||||
|
||||
// Round 21
|
||||
x4 = RotateLeft32(x4 + G16_31(x0, x1, x2) + _block[6] + RMD160Round16To31, 9) + x3;
|
||||
x1 = RotateLeft32(x1, 10);
|
||||
xp4 = RotateLeft32(xp4 + G48_63(xp0, xp1, xp2) + _block[13] + RMD160RoundPrime16To31, 8) + xp3;
|
||||
xp1 = RotateLeft32(xp1, 10);
|
||||
|
||||
// Round 22
|
||||
x3 = RotateLeft32(x3 + G16_31(x4, x0, x1) + _block[15] + RMD160Round16To31, 7) + x2;
|
||||
x0 = RotateLeft32(x0, 10);
|
||||
xp3 = RotateLeft32(xp3 + G48_63(xp4, xp0, xp1) + _block[5] + RMD160RoundPrime16To31, 9) + xp2;
|
||||
xp0 = RotateLeft32(xp0, 10);
|
||||
|
||||
// Round 23
|
||||
x2 = RotateLeft32(x2 + G16_31(x3, x4, x0) + _block[3] + RMD160Round16To31, 15) + x1;
|
||||
x4 = RotateLeft32(x4, 10);
|
||||
xp2 = RotateLeft32(xp2 + G48_63(xp3, xp4, xp0) + _block[10] + RMD160RoundPrime16To31, 11) + xp1;
|
||||
xp4 = RotateLeft32(xp4, 10);
|
||||
|
||||
// Round 24
|
||||
x1 = RotateLeft32(x1 + G16_31(x2, x3, x4) + _block[12] + RMD160Round16To31, 7) + x0;
|
||||
x3 = RotateLeft32(x3, 10);
|
||||
xp1 = RotateLeft32(xp1 + G48_63(xp2, xp3, xp4) + _block[14] + RMD160RoundPrime16To31, 7) + xp0;
|
||||
xp3 = RotateLeft32(xp3, 10);
|
||||
|
||||
// Round 25
|
||||
x0 = RotateLeft32(x0 + G16_31(x1, x2, x3) + _block[0] + RMD160Round16To31, 12) + x4;
|
||||
x2 = RotateLeft32(x2, 10);
|
||||
xp0 = RotateLeft32(xp0 + G48_63(xp1, xp2, xp3) + _block[15] + RMD160RoundPrime16To31, 7) + xp4;
|
||||
xp2 = RotateLeft32(xp2, 10);
|
||||
|
||||
// Round 26
|
||||
x4 = RotateLeft32(x4 + G16_31(x0, x1, x2) + _block[9] + RMD160Round16To31, 15) + x3;
|
||||
x1 = RotateLeft32(x1, 10);
|
||||
xp4 = RotateLeft32(xp4 + G48_63(xp0, xp1, xp2) + _block[8] + RMD160RoundPrime16To31, 12) + xp3;
|
||||
xp1 = RotateLeft32(xp1, 10);
|
||||
|
||||
// Round 27
|
||||
x3 = RotateLeft32(x3 + G16_31(x4, x0, x1) + _block[5] + RMD160Round16To31, 9) + x2;
|
||||
x0 = RotateLeft32(x0, 10);
|
||||
xp3 = RotateLeft32(xp3 + G48_63(xp4, xp0, xp1) + _block[12] + RMD160RoundPrime16To31, 7) + xp2;
|
||||
xp0 = RotateLeft32(xp0, 10);
|
||||
|
||||
// Round 28
|
||||
x2 = RotateLeft32(x2 + G16_31(x3, x4, x0) + _block[2] + RMD160Round16To31, 11) + x1;
|
||||
x4 = RotateLeft32(x4, 10);
|
||||
xp2 = RotateLeft32(xp2 + G48_63(xp3, xp4, xp0) + _block[4] + RMD160RoundPrime16To31, 6) + xp1;
|
||||
xp4 = RotateLeft32(xp4, 10);
|
||||
|
||||
// Round 29
|
||||
x1 = RotateLeft32(x1 + G16_31(x2, x3, x4) + _block[14] + RMD160Round16To31, 7) + x0;
|
||||
x3 = RotateLeft32(x3, 10);
|
||||
xp1 = RotateLeft32(xp1 + G48_63(xp2, xp3, xp4) + _block[9] + RMD160RoundPrime16To31, 15) + xp0;
|
||||
xp3 = RotateLeft32(xp3, 10);
|
||||
|
||||
// Round 30
|
||||
x0 = RotateLeft32(x0 + G16_31(x1, x2, x3) + _block[11] + RMD160Round16To31, 13) + x4;
|
||||
x2 = RotateLeft32(x2, 10);
|
||||
xp0 = RotateLeft32(xp0 + G48_63(xp1, xp2, xp3) + _block[1] + RMD160RoundPrime16To31, 13) + xp4;
|
||||
xp2 = RotateLeft32(xp2, 10);
|
||||
|
||||
// Round 31
|
||||
x4 = RotateLeft32(x4 + G16_31(x0, x1, x2) + _block[8] + RMD160Round16To31, 12) + x3;
|
||||
x1 = RotateLeft32(x1, 10);
|
||||
xp4 = RotateLeft32(xp4 + G48_63(xp0, xp1, xp2) + _block[2] + RMD160RoundPrime16To31, 11) + xp3;
|
||||
xp1 = RotateLeft32(xp1, 10);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Rounds 32-47
|
||||
|
||||
// Round 32
|
||||
x3 = RotateLeft32(x3 + G32_47(x4, x0, x1) + _block[3] + RMD160Round32To47, 11) + x2;
|
||||
x0 = RotateLeft32(x0, 10);
|
||||
xp3 = RotateLeft32(xp3 + G32_47(xp4, xp0, xp1) + _block[15] + RMD160RoundPrime32To47, 9) + xp2;
|
||||
xp0 = RotateLeft32(xp0, 10);
|
||||
|
||||
// Round 33
|
||||
x2 = RotateLeft32(x2 + G32_47(x3, x4, x0) + _block[10] + RMD160Round32To47, 13) + x1;
|
||||
x4 = RotateLeft32(x4, 10);
|
||||
xp2 = RotateLeft32(xp2 + G32_47(xp3, xp4, xp0) + _block[5] + RMD160RoundPrime32To47, 7) + xp1;
|
||||
xp4 = RotateLeft32(xp4, 10);
|
||||
|
||||
// Round 34
|
||||
x1 = RotateLeft32(x1 + G32_47(x2, x3, x4) + _block[14] + RMD160Round32To47, 6) + x0;
|
||||
x3 = RotateLeft32(x3, 10);
|
||||
xp1 = RotateLeft32(xp1 + G32_47(xp2, xp3, xp4) + _block[1] + RMD160RoundPrime32To47, 15) + xp0;
|
||||
xp3 = RotateLeft32(xp3, 10);
|
||||
|
||||
// Round 35
|
||||
x0 = RotateLeft32(x0 + G32_47(x1, x2, x3) + _block[4] + RMD160Round32To47, 7) + x4;
|
||||
x2 = RotateLeft32(x2, 10);
|
||||
xp0 = RotateLeft32(xp0 + G32_47(xp1, xp2, xp3) + _block[3] + RMD160RoundPrime32To47, 11) + xp4;
|
||||
xp2 = RotateLeft32(xp2, 10);
|
||||
|
||||
// Round 36
|
||||
x4 = RotateLeft32(x4 + G32_47(x0, x1, x2) + _block[9] + RMD160Round32To47, 14) + x3;
|
||||
x1 = RotateLeft32(x1, 10);
|
||||
xp4 = RotateLeft32(xp4 + G32_47(xp0, xp1, xp2) + _block[7] + RMD160RoundPrime32To47, 8) + xp3;
|
||||
xp1 = RotateLeft32(xp1, 10);
|
||||
|
||||
// Round 37
|
||||
x3 = RotateLeft32(x3 + G32_47(x4, x0, x1) + _block[15] + RMD160Round32To47, 9) + x2;
|
||||
x0 = RotateLeft32(x0, 10);
|
||||
xp3 = RotateLeft32(xp3 + G32_47(xp4, xp0, xp1) + _block[14] + RMD160RoundPrime32To47, 6) + xp2;
|
||||
xp0 = RotateLeft32(xp0, 10);
|
||||
|
||||
// Round 38
|
||||
x2 = RotateLeft32(x2 + G32_47(x3, x4, x0) + _block[8] + RMD160Round32To47, 13) + x1;
|
||||
x4 = RotateLeft32(x4, 10);
|
||||
xp2 = RotateLeft32(xp2 + G32_47(xp3, xp4, xp0) + _block[6] + RMD160RoundPrime32To47, 6) + xp1;
|
||||
xp4 = RotateLeft32(xp4, 10);
|
||||
|
||||
// Round 39
|
||||
x1 = RotateLeft32(x1 + G32_47(x2, x3, x4) + _block[1] + RMD160Round32To47, 15) + x0;
|
||||
x3 = RotateLeft32(x3, 10);
|
||||
xp1 = RotateLeft32(xp1 + G32_47(xp2, xp3, xp4) + _block[9] + RMD160RoundPrime32To47, 14) + xp0;
|
||||
xp3 = RotateLeft32(xp3, 10);
|
||||
|
||||
// Round 40
|
||||
x0 = RotateLeft32(x0 + G32_47(x1, x2, x3) + _block[2] + RMD160Round32To47, 14) + x4;
|
||||
x2 = RotateLeft32(x2, 10);
|
||||
xp0 = RotateLeft32(xp0 + G32_47(xp1, xp2, xp3) + _block[11] + RMD160RoundPrime32To47, 12) + xp4;
|
||||
xp2 = RotateLeft32(xp2, 10);
|
||||
|
||||
// Round 41
|
||||
x4 = RotateLeft32(x4 + G32_47(x0, x1, x2) + _block[7] + RMD160Round32To47, 8) + x3;
|
||||
x1 = RotateLeft32(x1, 10);
|
||||
xp4 = RotateLeft32(xp4 + G32_47(xp0, xp1, xp2) + _block[8] + RMD160RoundPrime32To47, 13) + xp3;
|
||||
xp1 = RotateLeft32(xp1, 10);
|
||||
|
||||
// Round 42
|
||||
x3 = RotateLeft32(x3 + G32_47(x4, x0, x1) + _block[0] + RMD160Round32To47, 13) + x2;
|
||||
x0 = RotateLeft32(x0, 10);
|
||||
xp3 = RotateLeft32(xp3 + G32_47(xp4, xp0, xp1) + _block[12] + RMD160RoundPrime32To47, 5) + xp2;
|
||||
xp0 = RotateLeft32(xp0, 10);
|
||||
|
||||
// Round 43
|
||||
x2 = RotateLeft32(x2 + G32_47(x3, x4, x0) + _block[6] + RMD160Round32To47, 6) + x1;
|
||||
x4 = RotateLeft32(x4, 10);
|
||||
xp2 = RotateLeft32(xp2 + G32_47(xp3, xp4, xp0) + _block[2] + RMD160RoundPrime32To47, 14) + xp1;
|
||||
xp4 = RotateLeft32(xp4, 10);
|
||||
|
||||
// Round 44
|
||||
x1 = RotateLeft32(x1 + G32_47(x2, x3, x4) + _block[13] + RMD160Round32To47, 5) + x0;
|
||||
x3 = RotateLeft32(x3, 10);
|
||||
xp1 = RotateLeft32(xp1 + G32_47(xp2, xp3, xp4) + _block[10] + RMD160RoundPrime32To47, 13) + xp0;
|
||||
xp3 = RotateLeft32(xp3, 10);
|
||||
|
||||
// Round 45
|
||||
x0 = RotateLeft32(x0 + G32_47(x1, x2, x3) + _block[11] + RMD160Round32To47, 12) + x4;
|
||||
x2 = RotateLeft32(x2, 10);
|
||||
xp0 = RotateLeft32(xp0 + G32_47(xp1, xp2, xp3) + _block[0] + RMD160RoundPrime32To47, 13) + xp4;
|
||||
xp2 = RotateLeft32(xp2, 10);
|
||||
|
||||
// Round 46
|
||||
x4 = RotateLeft32(x4 + G32_47(x0, x1, x2) + _block[5] + RMD160Round32To47, 7) + x3;
|
||||
x1 = RotateLeft32(x1, 10);
|
||||
xp4 = RotateLeft32(xp4 + G32_47(xp0, xp1, xp2) + _block[4] + RMD160RoundPrime32To47, 7) + xp3;
|
||||
xp1 = RotateLeft32(xp1, 10);
|
||||
|
||||
// Round 47
|
||||
x3 = RotateLeft32(x3 + G32_47(x4, x0, x1) + _block[12] + RMD160Round32To47, 5) + x2;
|
||||
x0 = RotateLeft32(x0, 10);
|
||||
xp3 = RotateLeft32(xp3 + G32_47(xp4, xp0, xp1) + _block[13] + RMD160RoundPrime32To47, 5) + xp2;
|
||||
xp0 = RotateLeft32(xp0, 10);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Rounds 48-63
|
||||
|
||||
// Round 48
|
||||
x2 = RotateLeft32(x2 + G48_63(x3, x4, x0) + _block[1] + RMD160Round48To63, 11) + x1;
|
||||
x4 = RotateLeft32(x4, 10);
|
||||
xp2 = RotateLeft32(xp2 + G16_31(xp3, xp4, xp0) + _block[8] + RMD160RoundPrime48To63, 15) + xp1;
|
||||
xp4 = RotateLeft32(xp4, 10);
|
||||
|
||||
// Round 49
|
||||
x1 = RotateLeft32(x1 + G48_63(x2, x3, x4) + _block[9] + RMD160Round48To63, 12) + x0;
|
||||
x3 = RotateLeft32(x3, 10);
|
||||
xp1 = RotateLeft32(xp1 + G16_31(xp2, xp3, xp4) + _block[6] + RMD160RoundPrime48To63, 5) + xp0;
|
||||
xp3 = RotateLeft32(xp3, 10);
|
||||
|
||||
// Round 50
|
||||
x0 = RotateLeft32(x0 + G48_63(x1, x2, x3) + _block[11] + RMD160Round48To63, 14) + x4;
|
||||
x2 = RotateLeft32(x2, 10);
|
||||
xp0 = RotateLeft32(xp0 + G16_31(xp1, xp2, xp3) + _block[4] + RMD160RoundPrime48To63, 8) + xp4;
|
||||
xp2 = RotateLeft32(xp2, 10);
|
||||
|
||||
// Round 51
|
||||
x4 = RotateLeft32(x4 + G48_63(x0, x1, x2) + _block[10] + RMD160Round48To63, 15) + x3;
|
||||
x1 = RotateLeft32(x1, 10);
|
||||
xp4 = RotateLeft32(xp4 + G16_31(xp0, xp1, xp2) + _block[1] + RMD160RoundPrime48To63, 11) + xp3;
|
||||
xp1 = RotateLeft32(xp1, 10);
|
||||
|
||||
// Round 52
|
||||
x3 = RotateLeft32(x3 + G48_63(x4, x0, x1) + _block[0] + RMD160Round48To63, 14) + x2;
|
||||
x0 = RotateLeft32(x0, 10);
|
||||
xp3 = RotateLeft32(xp3 + G16_31(xp4, xp0, xp1) + _block[3] + RMD160RoundPrime48To63, 14) + xp2;
|
||||
xp0 = RotateLeft32(xp0, 10);
|
||||
|
||||
// Round 53
|
||||
x2 = RotateLeft32(x2 + G48_63(x3, x4, x0) + _block[8] + RMD160Round48To63, 15) + x1;
|
||||
x4 = RotateLeft32(x4, 10);
|
||||
xp2 = RotateLeft32(xp2 + G16_31(xp3, xp4, xp0) + _block[11] + RMD160RoundPrime48To63, 14) + xp1;
|
||||
xp4 = RotateLeft32(xp4, 10);
|
||||
|
||||
// Round 54
|
||||
x1 = RotateLeft32(x1 + G48_63(x2, x3, x4) + _block[12] + RMD160Round48To63, 9) + x0;
|
||||
x3 = RotateLeft32(x3, 10);
|
||||
xp1 = RotateLeft32(xp1 + G16_31(xp2, xp3, xp4) + _block[15] + RMD160RoundPrime48To63, 6) + xp0;
|
||||
xp3 = RotateLeft32(xp3, 10);
|
||||
|
||||
// Round 55
|
||||
x0 = RotateLeft32(x0 + G48_63(x1, x2, x3) + _block[4] + RMD160Round48To63, 8) + x4;
|
||||
x2 = RotateLeft32(x2, 10);
|
||||
xp0 = RotateLeft32(xp0 + G16_31(xp1, xp2, xp3) + _block[0] + RMD160RoundPrime48To63, 14) + xp4;
|
||||
xp2 = RotateLeft32(xp2, 10);
|
||||
|
||||
// Round 56
|
||||
x4 = RotateLeft32(x4 + G48_63(x0, x1, x2) + _block[13] + RMD160Round48To63, 9) + x3;
|
||||
x1 = RotateLeft32(x1, 10);
|
||||
xp4 = RotateLeft32(xp4 + G16_31(xp0, xp1, xp2) + _block[5] + RMD160RoundPrime48To63, 6) + xp3;
|
||||
xp1 = RotateLeft32(xp1, 10);
|
||||
|
||||
// Round 57
|
||||
x3 = RotateLeft32(x3 + G48_63(x4, x0, x1) + _block[3] + RMD160Round48To63, 14) + x2;
|
||||
x0 = RotateLeft32(x0, 10);
|
||||
xp3 = RotateLeft32(xp3 + G16_31(xp4, xp0, xp1) + _block[12] + RMD160RoundPrime48To63, 9) + xp2;
|
||||
xp0 = RotateLeft32(xp0, 10);
|
||||
|
||||
// Round 58
|
||||
x2 = RotateLeft32(x2 + G48_63(x3, x4, x0) + _block[7] + RMD160Round48To63, 5) + x1;
|
||||
x4 = RotateLeft32(x4, 10);
|
||||
xp2 = RotateLeft32(xp2 + G16_31(xp3, xp4, xp0) + _block[2] + RMD160RoundPrime48To63, 12) + xp1;
|
||||
xp4 = RotateLeft32(xp4, 10);
|
||||
|
||||
// Round 59
|
||||
x1 = RotateLeft32(x1 + G48_63(x2, x3, x4) + _block[15] + RMD160Round48To63, 6) + x0;
|
||||
x3 = RotateLeft32(x3, 10);
|
||||
xp1 = RotateLeft32(xp1 + G16_31(xp2, xp3, xp4) + _block[13] + RMD160RoundPrime48To63, 9) + xp0;
|
||||
xp3 = RotateLeft32(xp3, 10);
|
||||
|
||||
// Round 60
|
||||
x0 = RotateLeft32(x0 + G48_63(x1, x2, x3) + _block[14] + RMD160Round48To63, 8) + x4;
|
||||
x2 = RotateLeft32(x2, 10);
|
||||
xp0 = RotateLeft32(xp0 + G16_31(xp1, xp2, xp3) + _block[9] + RMD160RoundPrime48To63, 12) + xp4;
|
||||
xp2 = RotateLeft32(xp2, 10);
|
||||
|
||||
// Round 61
|
||||
x4 = RotateLeft32(x4 + G48_63(x0, x1, x2) + _block[5] + RMD160Round48To63, 6) + x3;
|
||||
x1 = RotateLeft32(x1, 10);
|
||||
xp4 = RotateLeft32(xp4 + G16_31(xp0, xp1, xp2) + _block[7] + RMD160RoundPrime48To63, 5) + xp3;
|
||||
xp1 = RotateLeft32(xp1, 10);
|
||||
|
||||
// Round 62
|
||||
x3 = RotateLeft32(x3 + G48_63(x4, x0, x1) + _block[6] + RMD160Round48To63, 5) + x2;
|
||||
x0 = RotateLeft32(x0, 10);
|
||||
xp3 = RotateLeft32(xp3 + G16_31(xp4, xp0, xp1) + _block[10] + RMD160RoundPrime48To63, 15) + xp2;
|
||||
xp0 = RotateLeft32(xp0, 10);
|
||||
|
||||
// Round 63
|
||||
x2 = RotateLeft32(x2 + G48_63(x3, x4, x0) + _block[2] + RMD160Round48To63, 12) + x1;
|
||||
x4 = RotateLeft32(x4, 10);
|
||||
xp2 = RotateLeft32(xp2 + G16_31(xp3, xp4, xp0) + _block[14] + RMD160RoundPrime48To63, 8) + xp1;
|
||||
xp4 = RotateLeft32(xp4, 10);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Rounds 64-79
|
||||
|
||||
// Round 64
|
||||
x1 = RotateLeft32(x1 + G64_79(x2, x3, x4) + _block[4] + RMD160Round64To79, 9) + x0;
|
||||
x3 = RotateLeft32(x3, 10);
|
||||
xp1 = RotateLeft32(xp1 + G00_15(xp2, xp3, xp4) + _block[12] + RMD160RoundPrime64To79, 8) + xp0;
|
||||
xp3 = RotateLeft32(xp3, 10);
|
||||
|
||||
// Round 65
|
||||
x0 = RotateLeft32(x0 + G64_79(x1, x2, x3) + _block[0] + RMD160Round64To79, 15) + x4;
|
||||
x2 = RotateLeft32(x2, 10);
|
||||
xp0 = RotateLeft32(xp0 + G00_15(xp1, xp2, xp3) + _block[15] + RMD160RoundPrime64To79, 5) + xp4;
|
||||
xp2 = RotateLeft32(xp2, 10);
|
||||
|
||||
// Round 66
|
||||
x4 = RotateLeft32(x4 + G64_79(x0, x1, x2) + _block[5] + RMD160Round64To79, 5) + x3;
|
||||
x1 = RotateLeft32(x1, 10);
|
||||
xp4 = RotateLeft32(xp4 + G00_15(xp0, xp1, xp2) + _block[10] + RMD160RoundPrime64To79, 12) + xp3;
|
||||
xp1 = RotateLeft32(xp1, 10);
|
||||
|
||||
// Round 67
|
||||
x3 = RotateLeft32(x3 + G64_79(x4, x0, x1) + _block[9] + RMD160Round64To79, 11) + x2;
|
||||
x0 = RotateLeft32(x0, 10);
|
||||
xp3 = RotateLeft32(xp3 + G00_15(xp4, xp0, xp1) + _block[4] + RMD160RoundPrime64To79, 9) + xp2;
|
||||
xp0 = RotateLeft32(xp0, 10);
|
||||
|
||||
// Round 68
|
||||
x2 = RotateLeft32(x2 + G64_79(x3, x4, x0) + _block[7] + RMD160Round64To79, 6) + x1;
|
||||
x4 = RotateLeft32(x4, 10);
|
||||
xp2 = RotateLeft32(xp2 + G00_15(xp3, xp4, xp0) + _block[1] + RMD160RoundPrime64To79, 12) + xp1;
|
||||
xp4 = RotateLeft32(xp4, 10);
|
||||
|
||||
// Round 69
|
||||
x1 = RotateLeft32(x1 + G64_79(x2, x3, x4) + _block[12] + RMD160Round64To79, 8) + x0;
|
||||
x3 = RotateLeft32(x3, 10);
|
||||
xp1 = RotateLeft32(xp1 + G00_15(xp2, xp3, xp4) + _block[5] + RMD160RoundPrime64To79, 5) + xp0;
|
||||
xp3 = RotateLeft32(xp3, 10);
|
||||
|
||||
// Round 70
|
||||
x0 = RotateLeft32(x0 + G64_79(x1, x2, x3) + _block[2] + RMD160Round64To79, 13) + x4;
|
||||
x2 = RotateLeft32(x2, 10);
|
||||
xp0 = RotateLeft32(xp0 + G00_15(xp1, xp2, xp3) + _block[8] + RMD160RoundPrime64To79, 14) + xp4;
|
||||
xp2 = RotateLeft32(xp2, 10);
|
||||
|
||||
// Round 71
|
||||
x4 = RotateLeft32(x4 + G64_79(x0, x1, x2) + _block[10] + RMD160Round64To79, 12) + x3;
|
||||
x1 = RotateLeft32(x1, 10);
|
||||
xp4 = RotateLeft32(xp4 + G00_15(xp0, xp1, xp2) + _block[7] + RMD160RoundPrime64To79, 6) + xp3;
|
||||
xp1 = RotateLeft32(xp1, 10);
|
||||
|
||||
// Round 72
|
||||
x3 = RotateLeft32(x3 + G64_79(x4, x0, x1) + _block[14] + RMD160Round64To79, 5) + x2;
|
||||
x0 = RotateLeft32(x0, 10);
|
||||
xp3 = RotateLeft32(xp3 + G00_15(xp4, xp0, xp1) + _block[6] + RMD160RoundPrime64To79, 8) + xp2;
|
||||
xp0 = RotateLeft32(xp0, 10);
|
||||
|
||||
// Round 73
|
||||
x2 = RotateLeft32(x2 + G64_79(x3, x4, x0) + _block[1] + RMD160Round64To79, 12) + x1;
|
||||
x4 = RotateLeft32(x4, 10);
|
||||
xp2 = RotateLeft32(xp2 + G00_15(xp3, xp4, xp0) + _block[2] + RMD160RoundPrime64To79, 13) + xp1;
|
||||
xp4 = RotateLeft32(xp4, 10);
|
||||
|
||||
// Round 74
|
||||
x1 = RotateLeft32(x1 + G64_79(x2, x3, x4) + _block[3] + RMD160Round64To79, 13) + x0;
|
||||
x3 = RotateLeft32(x3, 10);
|
||||
xp1 = RotateLeft32(xp1 + G00_15(xp2, xp3, xp4) + _block[13] + RMD160RoundPrime64To79, 6) + xp0;
|
||||
xp3 = RotateLeft32(xp3, 10);
|
||||
|
||||
// Round 75
|
||||
x0 = RotateLeft32(x0 + G64_79(x1, x2, x3) + _block[8] + RMD160Round64To79, 14) + x4;
|
||||
x2 = RotateLeft32(x2, 10);
|
||||
xp0 = RotateLeft32(xp0 + G00_15(xp1, xp2, xp3) + _block[14] + RMD160RoundPrime64To79, 5) + xp4;
|
||||
xp2 = RotateLeft32(xp2, 10);
|
||||
|
||||
// Round 76
|
||||
x4 = RotateLeft32(x4 + G64_79(x0, x1, x2) + _block[11] + RMD160Round64To79, 11) + x3;
|
||||
x1 = RotateLeft32(x1, 10);
|
||||
xp4 = RotateLeft32(xp4 + G00_15(xp0, xp1, xp2) + _block[0] + RMD160RoundPrime64To79, 15) + xp3;
|
||||
xp1 = RotateLeft32(xp1, 10);
|
||||
|
||||
// Round 77
|
||||
x3 = RotateLeft32(x3 + G64_79(x4, x0, x1) + _block[6] + RMD160Round64To79, 8) + x2;
|
||||
x0 = RotateLeft32(x0, 10);
|
||||
xp3 = RotateLeft32(xp3 + G00_15(xp4, xp0, xp1) + _block[3] + RMD160RoundPrime64To79, 13) + xp2;
|
||||
xp0 = RotateLeft32(xp0, 10);
|
||||
|
||||
// Round 78
|
||||
x2 = RotateLeft32(x2 + G64_79(x3, x4, x0) + _block[15] + RMD160Round64To79, 5) + x1;
|
||||
x4 = RotateLeft32(x4, 10);
|
||||
xp2 = RotateLeft32(xp2 + G00_15(xp3, xp4, xp0) + _block[9] + RMD160RoundPrime64To79, 11) + xp1;
|
||||
xp4 = RotateLeft32(xp4, 10);
|
||||
|
||||
// Round 79
|
||||
x1 = RotateLeft32(x1 + G64_79(x2, x3, x4) + _block[13] + RMD160Round64To79, 6) + x0;
|
||||
x3 = RotateLeft32(x3, 10);
|
||||
xp1 = RotateLeft32(xp1 + G00_15(xp2, xp3, xp4) + _block[11] + RMD160RoundPrime64To79, 11) + xp0;
|
||||
xp3 = RotateLeft32(xp3, 10);
|
||||
|
||||
#endregion
|
||||
|
||||
// Avalanche values
|
||||
xp3 += x2 + _state[1];
|
||||
_state[1] = _state[2] + x3 + xp4;
|
||||
_state[2] = _state[3] + x4 + xp0;
|
||||
_state[3] = _state[4] + x0 + xp1;
|
||||
_state[4] = _state[0] + x1 + xp2;
|
||||
_state[0] = xp3;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Round operation [0, 15]
|
||||
/// </summary>
|
||||
private static uint G00_15(uint x, uint y, uint z) => x ^ y ^ z;
|
||||
|
||||
/// <summary>
|
||||
/// Round operation [16, 31]
|
||||
/// </summary>
|
||||
private static uint G16_31(uint x, uint y, uint z) => (x & y) | (~x & z);
|
||||
|
||||
/// <summary>
|
||||
/// Round operation [32, 47]
|
||||
/// </summary>
|
||||
private static uint G32_47(uint x, uint y, uint z) => (x | ~y) ^ z;
|
||||
|
||||
/// <summary>
|
||||
/// Round operation [48, 63]
|
||||
/// </summary>
|
||||
private static uint G48_63(uint x, uint y, uint z) => (x & z) | (y & ~z);
|
||||
|
||||
/// <summary>
|
||||
/// Round operation [64, 79]
|
||||
/// </summary>
|
||||
private static uint G64_79(uint x, uint y, uint z) => x ^ (y | ~z);
|
||||
}
|
||||
}
|
||||
467
SabreTools.Hashing/CryptographicHash/RipeMD256.cs
Normal file
467
SabreTools.Hashing/CryptographicHash/RipeMD256.cs
Normal file
@@ -0,0 +1,467 @@
|
||||
using System;
|
||||
using static SabreTools.Hashing.CryptographicHash.Constants;
|
||||
using static SabreTools.Hashing.HashOperations;
|
||||
|
||||
namespace SabreTools.Hashing.CryptographicHash
|
||||
{
|
||||
/// <see href="https://cdn.standards.iteh.ai/samples/39876/10f9f9f4bb614eaaaeba7e157e183ca3/ISO-IEC-10118-3-2004.pdf"/>
|
||||
/// <see href="https://homes.esat.kuleuven.be/~bosselae/ripemd160/pdf/AB-9601/AB-9601.pdf"/>
|
||||
public class RipeMD256 : MessageDigestBase<uint>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 256;
|
||||
|
||||
/// <summary>
|
||||
/// Set of 4 32-bit numbers representing the hash state
|
||||
/// </summary>
|
||||
private readonly uint[] _state = new uint[8];
|
||||
|
||||
public RipeMD256() : base()
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void ResetImpl()
|
||||
{
|
||||
_state[0] = RMD128Y0;
|
||||
_state[1] = RMD128Y1;
|
||||
_state[2] = RMD128Y2;
|
||||
_state[3] = RMD128Y3;
|
||||
_state[4] = RMD256Y4;
|
||||
_state[5] = RMD256Y5;
|
||||
_state[6] = RMD256Y6;
|
||||
_state[7] = RMD256Y7;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void HashCore(byte[] data, int offset, int length)
|
||||
{
|
||||
// Figure out how much buffer is needed
|
||||
int bufferLen = (int)(_totalBytes & 0x3f);
|
||||
|
||||
// Increment the processed byte count
|
||||
_totalBytes += length;
|
||||
|
||||
// If there is buffer to fill and it will meet the limit
|
||||
if (bufferLen > 0 && bufferLen + length >= 64)
|
||||
{
|
||||
// Fill the buffer from the input
|
||||
Array.Copy(data, offset, _buffer, bufferLen, 64 - bufferLen);
|
||||
|
||||
// Set the new values
|
||||
offset += 64 - bufferLen;
|
||||
length -= 64 - bufferLen;
|
||||
|
||||
// Split the buffer for the round
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
_block[i] = ReadLE32(_buffer, i * 4);
|
||||
}
|
||||
|
||||
// Run the round
|
||||
Round();
|
||||
bufferLen = 0;
|
||||
}
|
||||
|
||||
/// Process any standalone blocks
|
||||
while (length >= 64)
|
||||
{
|
||||
// Fill the buffer from the input
|
||||
Array.Copy(data, offset, _buffer, 0, 64);
|
||||
|
||||
// Set the new values
|
||||
offset += 64;
|
||||
length -= 64;
|
||||
|
||||
// Split the buffer for the round
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
_block[i] = ReadLE32(_buffer, i * 4);
|
||||
}
|
||||
|
||||
// Run the round
|
||||
Round();
|
||||
}
|
||||
|
||||
// Save the remainder in the buffer
|
||||
if (length > 0)
|
||||
Array.Copy(data, offset, _buffer, bufferLen, length);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
// Determine the pad length
|
||||
int padLength = 64 - (int)(_totalBytes & 0x3f);
|
||||
if (padLength <= 8)
|
||||
padLength += 64;
|
||||
|
||||
// Get the total byte count in bits
|
||||
long totalBitCount = _totalBytes * 8;
|
||||
|
||||
// Prebuild the padding
|
||||
var padding = new byte[padLength];
|
||||
padding[0] = 0x80;
|
||||
padding[padLength - 1] = (byte)((totalBitCount >> 56) & 0xff);
|
||||
padding[padLength - 2] = (byte)((totalBitCount >> 48) & 0xff);
|
||||
padding[padLength - 3] = (byte)((totalBitCount >> 40) & 0xff);
|
||||
padding[padLength - 4] = (byte)((totalBitCount >> 32) & 0xff);
|
||||
padding[padLength - 5] = (byte)((totalBitCount >> 24) & 0xff);
|
||||
padding[padLength - 6] = (byte)((totalBitCount >> 16) & 0xff);
|
||||
padding[padLength - 7] = (byte)((totalBitCount >> 8) & 0xff);
|
||||
padding[padLength - 8] = (byte)((totalBitCount >> 0) & 0xff);
|
||||
|
||||
// Pad the block
|
||||
HashCore(padding, 0, padding.Length);
|
||||
|
||||
// Get the hash
|
||||
var hash = new byte[32];
|
||||
int hashOffset = 0;
|
||||
|
||||
// Assemble the hash array
|
||||
for (int i = 0; i < _state.Length; i++)
|
||||
{
|
||||
byte[] segment = BitConverter.GetBytes(_state[i]);
|
||||
Array.Copy(segment, 0, hash, hashOffset, 4);
|
||||
hashOffset += 4;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform one round of updates on the cached values
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The official specification for RIPEMD-128 includes tables
|
||||
/// and instructions that represent a loop. Most standard implementations
|
||||
/// use the unrolled version of that loop to make it more efficient.
|
||||
///
|
||||
/// The below code started with the looped version but has been converted
|
||||
/// to the more standard implementation instead.
|
||||
/// </remarks>
|
||||
private void Round()
|
||||
{
|
||||
// Setup values
|
||||
uint x0 = _state[0], xp0 = _state[4];
|
||||
uint x1 = _state[1], xp1 = _state[5];
|
||||
uint x2 = _state[2], xp2 = _state[6];
|
||||
uint x3 = _state[3], xp3 = _state[7];
|
||||
uint t;
|
||||
|
||||
#region Rounds 0-15
|
||||
|
||||
// Round 0
|
||||
x0 = RotateLeft32(x0 + G00_15(x1, x2, x3) + _block[0] + RMD128Round00To15, 11);
|
||||
xp0 = RotateLeft32(xp0 + G48_63(xp1, xp2, xp3) + _block[5] + RMD128RoundPrime00To15, 8);
|
||||
|
||||
// Round 1
|
||||
x3 = RotateLeft32(x3 + G00_15(x0, x1, x2) + _block[1] + RMD128Round00To15, 14);
|
||||
xp3 = RotateLeft32(xp3 + G48_63(xp0, xp1, xp2) + _block[14] + RMD128RoundPrime00To15, 9);
|
||||
|
||||
// Round 2
|
||||
x2 = RotateLeft32(x2 + G00_15(x3, x0, x1) + _block[2] + RMD128Round00To15, 15);
|
||||
xp2 = RotateLeft32(xp2 + G48_63(xp3, xp0, xp1) + _block[7] + RMD128RoundPrime00To15, 9);
|
||||
|
||||
// Round 3
|
||||
x1 = RotateLeft32(x1 + G00_15(x2, x3, x0) + _block[3] + RMD128Round00To15, 12);
|
||||
xp1 = RotateLeft32(xp1 + G48_63(xp2, xp3, xp0) + _block[0] + RMD128RoundPrime00To15, 11);
|
||||
|
||||
// Round 4
|
||||
x0 = RotateLeft32(x0 + G00_15(x1, x2, x3) + _block[4] + RMD128Round00To15, 5);
|
||||
xp0 = RotateLeft32(xp0 + G48_63(xp1, xp2, xp3) + _block[9] + RMD128RoundPrime00To15, 13);
|
||||
|
||||
// Round 5
|
||||
x3 = RotateLeft32(x3 + G00_15(x0, x1, x2) + _block[5] + RMD128Round00To15, 8);
|
||||
xp3 = RotateLeft32(xp3 + G48_63(xp0, xp1, xp2) + _block[2] + RMD128RoundPrime00To15, 15);
|
||||
|
||||
// Round 6
|
||||
x2 = RotateLeft32(x2 + G00_15(x3, x0, x1) + _block[6] + RMD128Round00To15, 7);
|
||||
xp2 = RotateLeft32(xp2 + G48_63(xp3, xp0, xp1) + _block[11] + RMD128RoundPrime00To15, 15);
|
||||
|
||||
// Round 7
|
||||
x1 = RotateLeft32(x1 + G00_15(x2, x3, x0) + _block[7] + RMD128Round00To15, 9);
|
||||
xp1 = RotateLeft32(xp1 + G48_63(xp2, xp3, xp0) + _block[4] + RMD128RoundPrime00To15, 5);
|
||||
|
||||
// Round 8
|
||||
x0 = RotateLeft32(x0 + G00_15(x1, x2, x3) + _block[8] + RMD128Round00To15, 11);
|
||||
xp0 = RotateLeft32(xp0 + G48_63(xp1, xp2, xp3) + _block[13] + RMD128RoundPrime00To15, 7);
|
||||
|
||||
// Round 9
|
||||
x3 = RotateLeft32(x3 + G00_15(x0, x1, x2) + _block[9] + RMD128Round00To15, 13);
|
||||
xp3 = RotateLeft32(xp3 + G48_63(xp0, xp1, xp2) + _block[6] + RMD128RoundPrime00To15, 7);
|
||||
|
||||
// Round 10
|
||||
x2 = RotateLeft32(x2 + G00_15(x3, x0, x1) + _block[10] + RMD128Round00To15, 14);
|
||||
xp2 = RotateLeft32(xp2 + G48_63(xp3, xp0, xp1) + _block[15] + RMD128RoundPrime00To15, 8);
|
||||
|
||||
// Round 11
|
||||
x1 = RotateLeft32(x1 + G00_15(x2, x3, x0) + _block[11] + RMD128Round00To15, 15);
|
||||
xp1 = RotateLeft32(xp1 + G48_63(xp2, xp3, xp0) + _block[8] + RMD128RoundPrime00To15, 11);
|
||||
|
||||
// Round 12
|
||||
x0 = RotateLeft32(x0 + G00_15(x1, x2, x3) + _block[12] + RMD128Round00To15, 6);
|
||||
xp0 = RotateLeft32(xp0 + G48_63(xp1, xp2, xp3) + _block[1] + RMD128RoundPrime00To15, 14);
|
||||
|
||||
// Round 13
|
||||
x3 = RotateLeft32(x3 + G00_15(x0, x1, x2) + _block[13] + RMD128Round00To15, 7);
|
||||
xp3 = RotateLeft32(xp3 + G48_63(xp0, xp1, xp2) + _block[10] + RMD128RoundPrime00To15, 14);
|
||||
|
||||
// Round 14
|
||||
x2 = RotateLeft32(x2 + G00_15(x3, x0, x1) + _block[14] + RMD128Round00To15, 9);
|
||||
xp2 = RotateLeft32(xp2 + G48_63(xp3, xp0, xp1) + _block[3] + RMD128RoundPrime00To15, 12);
|
||||
|
||||
// Round 15
|
||||
x1 = RotateLeft32(x1 + G00_15(x2, x3, x0) + _block[15] + RMD128Round00To15, 8);
|
||||
xp1 = RotateLeft32(xp1 + G48_63(xp2, xp3, xp0) + _block[12] + RMD128RoundPrime00To15, 6);
|
||||
|
||||
// Swap set 1
|
||||
t = x0; x0 = xp0; xp0 = t;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Rounds 16-31
|
||||
|
||||
// Round 16
|
||||
x0 = RotateLeft32(x0 + G16_31(x1, x2, x3) + _block[7] + RMD128Round16To31, 7);
|
||||
xp0 = RotateLeft32(xp0 + G32_47(xp1, xp2, xp3) + _block[6] + RMD128RoundPrime16To31, 9);
|
||||
|
||||
// Round 17
|
||||
x3 = RotateLeft32(x3 + G16_31(x0, x1, x2) + _block[4] + RMD128Round16To31, 6);
|
||||
xp3 = RotateLeft32(xp3 + G32_47(xp0, xp1, xp2) + _block[11] + RMD128RoundPrime16To31, 13);
|
||||
|
||||
// Round 18
|
||||
x2 = RotateLeft32(x2 + G16_31(x3, x0, x1) + _block[13] + RMD128Round16To31, 8);
|
||||
xp2 = RotateLeft32(xp2 + G32_47(xp3, xp0, xp1) + _block[3] + RMD128RoundPrime16To31, 15);
|
||||
|
||||
// Round 19
|
||||
x1 = RotateLeft32(x1 + G16_31(x2, x3, x0) + _block[1] + RMD128Round16To31, 13);
|
||||
xp1 = RotateLeft32(xp1 + G32_47(xp2, xp3, xp0) + _block[7] + RMD128RoundPrime16To31, 7);
|
||||
|
||||
// Round 20
|
||||
x0 = RotateLeft32(x0 + G16_31(x1, x2, x3) + _block[10] + RMD128Round16To31, 11);
|
||||
xp0 = RotateLeft32(xp0 + G32_47(xp1, xp2, xp3) + _block[0] + RMD128RoundPrime16To31, 12);
|
||||
|
||||
// Round 21
|
||||
x3 = RotateLeft32(x3 + G16_31(x0, x1, x2) + _block[6] + RMD128Round16To31, 9);
|
||||
xp3 = RotateLeft32(xp3 + G32_47(xp0, xp1, xp2) + _block[13] + RMD128RoundPrime16To31, 8);
|
||||
|
||||
// Round 22
|
||||
x2 = RotateLeft32(x2 + G16_31(x3, x0, x1) + _block[15] + RMD128Round16To31, 7);
|
||||
xp2 = RotateLeft32(xp2 + G32_47(xp3, xp0, xp1) + _block[5] + RMD128RoundPrime16To31, 9);
|
||||
|
||||
// Round 23
|
||||
x1 = RotateLeft32(x1 + G16_31(x2, x3, x0) + _block[3] + RMD128Round16To31, 15);
|
||||
xp1 = RotateLeft32(xp1 + G32_47(xp2, xp3, xp0) + _block[10] + RMD128RoundPrime16To31, 11);
|
||||
|
||||
// Round 24
|
||||
x0 = RotateLeft32(x0 + G16_31(x1, x2, x3) + _block[12] + RMD128Round16To31, 7);
|
||||
xp0 = RotateLeft32(xp0 + G32_47(xp1, xp2, xp3) + _block[14] + RMD128RoundPrime16To31, 7);
|
||||
|
||||
// Round 25
|
||||
x3 = RotateLeft32(x3 + G16_31(x0, x1, x2) + _block[0] + RMD128Round16To31, 12);
|
||||
xp3 = RotateLeft32(xp3 + G32_47(xp0, xp1, xp2) + _block[15] + RMD128RoundPrime16To31, 7);
|
||||
|
||||
// Round 26
|
||||
x2 = RotateLeft32(x2 + G16_31(x3, x0, x1) + _block[9] + RMD128Round16To31, 15);
|
||||
xp2 = RotateLeft32(xp2 + G32_47(xp3, xp0, xp1) + _block[8] + RMD128RoundPrime16To31, 12);
|
||||
|
||||
// Round 27
|
||||
x1 = RotateLeft32(x1 + G16_31(x2, x3, x0) + _block[5] + RMD128Round16To31, 9);
|
||||
xp1 = RotateLeft32(xp1 + G32_47(xp2, xp3, xp0) + _block[12] + RMD128RoundPrime16To31, 7);
|
||||
|
||||
// Round 28
|
||||
x0 = RotateLeft32(x0 + G16_31(x1, x2, x3) + _block[2] + RMD128Round16To31, 11);
|
||||
xp0 = RotateLeft32(xp0 + G32_47(xp1, xp2, xp3) + _block[4] + RMD128RoundPrime16To31, 6);
|
||||
|
||||
// Round 29
|
||||
x3 = RotateLeft32(x3 + G16_31(x0, x1, x2) + _block[14] + RMD128Round16To31, 7);
|
||||
xp3 = RotateLeft32(xp3 + G32_47(xp0, xp1, xp2) + _block[9] + RMD128RoundPrime16To31, 15);
|
||||
|
||||
// Round 30
|
||||
x2 = RotateLeft32(x2 + G16_31(x3, x0, x1) + _block[11] + RMD128Round16To31, 13);
|
||||
xp2 = RotateLeft32(xp2 + G32_47(xp3, xp0, xp1) + _block[1] + RMD128RoundPrime16To31, 13);
|
||||
|
||||
// Round 31
|
||||
x1 = RotateLeft32(x1 + G16_31(x2, x3, x0) + _block[8] + RMD128Round16To31, 12);
|
||||
xp1 = RotateLeft32(xp1 + G32_47(xp2, xp3, xp0) + _block[2] + RMD128RoundPrime16To31, 11);
|
||||
|
||||
// Swap set 2
|
||||
t = x1; x1 = xp1; xp1 = t;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Rounds 32-47
|
||||
|
||||
// Round 32
|
||||
x0 = RotateLeft32(x0 + G32_47(x1, x2, x3) + _block[3] + RMD128Round32To47, 11);
|
||||
xp0 = RotateLeft32(xp0 + G16_31(xp1, xp2, xp3) + _block[15] + RMD128RoundPrime32To47, 9);
|
||||
|
||||
// Round 33
|
||||
x3 = RotateLeft32(x3 + G32_47(x0, x1, x2) + _block[10] + RMD128Round32To47, 13);
|
||||
xp3 = RotateLeft32(xp3 + G16_31(xp0, xp1, xp2) + _block[5] + RMD128RoundPrime32To47, 7);
|
||||
|
||||
// Round 34
|
||||
x2 = RotateLeft32(x2 + G32_47(x3, x0, x1) + _block[14] + RMD128Round32To47, 6);
|
||||
xp2 = RotateLeft32(xp2 + G16_31(xp3, xp0, xp1) + _block[1] + RMD128RoundPrime32To47, 15);
|
||||
|
||||
// Round 35
|
||||
x1 = RotateLeft32(x1 + G32_47(x2, x3, x0) + _block[4] + RMD128Round32To47, 7);
|
||||
xp1 = RotateLeft32(xp1 + G16_31(xp2, xp3, xp0) + _block[3] + RMD128RoundPrime32To47, 11);
|
||||
|
||||
// Round 36
|
||||
x0 = RotateLeft32(x0 + G32_47(x1, x2, x3) + _block[9] + RMD128Round32To47, 14);
|
||||
xp0 = RotateLeft32(xp0 + G16_31(xp1, xp2, xp3) + _block[7] + RMD128RoundPrime32To47, 8);
|
||||
|
||||
// Round 37
|
||||
x3 = RotateLeft32(x3 + G32_47(x0, x1, x2) + _block[15] + RMD128Round32To47, 9);
|
||||
xp3 = RotateLeft32(xp3 + G16_31(xp0, xp1, xp2) + _block[14] + RMD128RoundPrime32To47, 6);
|
||||
|
||||
// Round 38
|
||||
x2 = RotateLeft32(x2 + G32_47(x3, x0, x1) + _block[8] + RMD128Round32To47, 13);
|
||||
xp2 = RotateLeft32(xp2 + G16_31(xp3, xp0, xp1) + _block[6] + RMD128RoundPrime32To47, 6);
|
||||
|
||||
// Round 39
|
||||
x1 = RotateLeft32(x1 + G32_47(x2, x3, x0) + _block[1] + RMD128Round32To47, 15);
|
||||
xp1 = RotateLeft32(xp1 + G16_31(xp2, xp3, xp0) + _block[9] + RMD128RoundPrime32To47, 14);
|
||||
|
||||
// Round 40
|
||||
x0 = RotateLeft32(x0 + G32_47(x1, x2, x3) + _block[2] + RMD128Round32To47, 14);
|
||||
xp0 = RotateLeft32(xp0 + G16_31(xp1, xp2, xp3) + _block[11] + RMD128RoundPrime32To47, 12);
|
||||
|
||||
// Round 41
|
||||
x3 = RotateLeft32(x3 + G32_47(x0, x1, x2) + _block[7] + RMD128Round32To47, 8);
|
||||
xp3 = RotateLeft32(xp3 + G16_31(xp0, xp1, xp2) + _block[8] + RMD128RoundPrime32To47, 13);
|
||||
|
||||
// Round 42
|
||||
x2 = RotateLeft32(x2 + G32_47(x3, x0, x1) + _block[0] + RMD128Round32To47, 13);
|
||||
xp2 = RotateLeft32(xp2 + G16_31(xp3, xp0, xp1) + _block[12] + RMD128RoundPrime32To47, 5);
|
||||
|
||||
// Round 43
|
||||
x1 = RotateLeft32(x1 + G32_47(x2, x3, x0) + _block[6] + RMD128Round32To47, 6);
|
||||
xp1 = RotateLeft32(xp1 + G16_31(xp2, xp3, xp0) + _block[2] + RMD128RoundPrime32To47, 14);
|
||||
|
||||
// Round 44
|
||||
x0 = RotateLeft32(x0 + G32_47(x1, x2, x3) + _block[13] + RMD128Round32To47, 5);
|
||||
xp0 = RotateLeft32(xp0 + G16_31(xp1, xp2, xp3) + _block[10] + RMD128RoundPrime32To47, 13);
|
||||
|
||||
// Round 45
|
||||
x3 = RotateLeft32(x3 + G32_47(x0, x1, x2) + _block[11] + RMD128Round32To47, 12);
|
||||
xp3 = RotateLeft32(xp3 + G16_31(xp0, xp1, xp2) + _block[0] + RMD128RoundPrime32To47, 13);
|
||||
|
||||
// Round 46
|
||||
x2 = RotateLeft32(x2 + G32_47(x3, x0, x1) + _block[5] + RMD128Round32To47, 7);
|
||||
xp2 = RotateLeft32(xp2 + G16_31(xp3, xp0, xp1) + _block[4] + RMD128RoundPrime32To47, 7);
|
||||
|
||||
// Round 47
|
||||
x1 = RotateLeft32(x1 + G32_47(x2, x3, x0) + _block[12] + RMD128Round32To47, 5);
|
||||
xp1 = RotateLeft32(xp1 + G16_31(xp2, xp3, xp0) + _block[13] + RMD128RoundPrime32To47, 5);
|
||||
|
||||
// Swap set 3
|
||||
t = x2; x2 = xp2; xp2 = t;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Rounds 48-63
|
||||
|
||||
// Round 48
|
||||
x0 = RotateLeft32(x0 + G48_63(x1, x2, x3) + _block[1] + RMD128Round48To63, 11);
|
||||
xp0 = RotateLeft32(xp0 + G00_15(xp1, xp2, xp3) + _block[8] + RMD128RoundPrime48To63, 15);
|
||||
|
||||
// Round 49
|
||||
x3 = RotateLeft32(x3 + G48_63(x0, x1, x2) + _block[9] + RMD128Round48To63, 12);
|
||||
xp3 = RotateLeft32(xp3 + G00_15(xp0, xp1, xp2) + _block[6] + RMD128RoundPrime48To63, 5);
|
||||
|
||||
// Round 50
|
||||
x2 = RotateLeft32(x2 + G48_63(x3, x0, x1) + _block[11] + RMD128Round48To63, 14);
|
||||
xp2 = RotateLeft32(xp2 + G00_15(xp3, xp0, xp1) + _block[4] + RMD128RoundPrime48To63, 8);
|
||||
|
||||
// Round 51
|
||||
x1 = RotateLeft32(x1 + G48_63(x2, x3, x0) + _block[10] + RMD128Round48To63, 15);
|
||||
xp1 = RotateLeft32(xp1 + G00_15(xp2, xp3, xp0) + _block[1] + RMD128RoundPrime48To63, 11);
|
||||
|
||||
// Round 52
|
||||
x0 = RotateLeft32(x0 + G48_63(x1, x2, x3) + _block[0] + RMD128Round48To63, 14);
|
||||
xp0 = RotateLeft32(xp0 + G00_15(xp1, xp2, xp3) + _block[3] + RMD128RoundPrime48To63, 14);
|
||||
|
||||
// Round 53
|
||||
x3 = RotateLeft32(x3 + G48_63(x0, x1, x2) + _block[8] + RMD128Round48To63, 15);
|
||||
xp3 = RotateLeft32(xp3 + G00_15(xp0, xp1, xp2) + _block[11] + RMD128RoundPrime48To63, 14);
|
||||
|
||||
// Round 54
|
||||
x2 = RotateLeft32(x2 + G48_63(x3, x0, x1) + _block[12] + RMD128Round48To63, 9);
|
||||
xp2 = RotateLeft32(xp2 + G00_15(xp3, xp0, xp1) + _block[15] + RMD128RoundPrime48To63, 6);
|
||||
|
||||
// Round 55
|
||||
x1 = RotateLeft32(x1 + G48_63(x2, x3, x0) + _block[4] + RMD128Round48To63, 8);
|
||||
xp1 = RotateLeft32(xp1 + G00_15(xp2, xp3, xp0) + _block[0] + RMD128RoundPrime48To63, 14);
|
||||
|
||||
// Round 56
|
||||
x0 = RotateLeft32(x0 + G48_63(x1, x2, x3) + _block[13] + RMD128Round48To63, 9);
|
||||
xp0 = RotateLeft32(xp0 + G00_15(xp1, xp2, xp3) + _block[5] + RMD128RoundPrime48To63, 6);
|
||||
|
||||
// Round 57
|
||||
x3 = RotateLeft32(x3 + G48_63(x0, x1, x2) + _block[3] + RMD128Round48To63, 14);
|
||||
xp3 = RotateLeft32(xp3 + G00_15(xp0, xp1, xp2) + _block[12] + RMD128RoundPrime48To63, 9);
|
||||
|
||||
// Round 58
|
||||
x2 = RotateLeft32(x2 + G48_63(x3, x0, x1) + _block[7] + RMD128Round48To63, 5);
|
||||
xp2 = RotateLeft32(xp2 + G00_15(xp3, xp0, xp1) + _block[2] + RMD128RoundPrime48To63, 12);
|
||||
|
||||
// Round 59
|
||||
x1 = RotateLeft32(x1 + G48_63(x2, x3, x0) + _block[15] + RMD128Round48To63, 6);
|
||||
xp1 = RotateLeft32(xp1 + G00_15(xp2, xp3, xp0) + _block[13] + RMD128RoundPrime48To63, 9);
|
||||
|
||||
// Round 60
|
||||
x0 = RotateLeft32(x0 + G48_63(x1, x2, x3) + _block[14] + RMD128Round48To63, 8);
|
||||
xp0 = RotateLeft32(xp0 + G00_15(xp1, xp2, xp3) + _block[9] + RMD128RoundPrime48To63, 12);
|
||||
|
||||
// Round 61
|
||||
x3 = RotateLeft32(x3 + G48_63(x0, x1, x2) + _block[5] + RMD128Round48To63, 6);
|
||||
xp3 = RotateLeft32(xp3 + G00_15(xp0, xp1, xp2) + _block[7] + RMD128RoundPrime48To63, 5);
|
||||
|
||||
// Round 62
|
||||
x2 = RotateLeft32(x2 + G48_63(x3, x0, x1) + _block[6] + RMD128Round48To63, 5);
|
||||
xp2 = RotateLeft32(xp2 + G00_15(xp3, xp0, xp1) + _block[10] + RMD128RoundPrime48To63, 15);
|
||||
|
||||
// Round 63
|
||||
x1 = RotateLeft32(x1 + G48_63(x2, x3, x0) + _block[2] + RMD128Round48To63, 12);
|
||||
xp1 = RotateLeft32(xp1 + G00_15(xp2, xp3, xp0) + _block[14] + RMD128RoundPrime48To63, 8);
|
||||
|
||||
// Swap set 4
|
||||
t = x3; x3 = xp3; xp3 = t;
|
||||
|
||||
#endregion
|
||||
|
||||
// Avalanche values
|
||||
_state[0] += x0;
|
||||
_state[1] += x1;
|
||||
_state[2] += x2;
|
||||
_state[3] += x3;
|
||||
_state[4] += xp0;
|
||||
_state[5] += xp1;
|
||||
_state[6] += xp2;
|
||||
_state[7] += xp3;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Round operation [0, 15]
|
||||
/// </summary>
|
||||
private static uint G00_15(uint x, uint y, uint z) => x ^ y ^ z;
|
||||
|
||||
/// <summary>
|
||||
/// Round operation [16, 31]
|
||||
/// </summary>
|
||||
private static uint G16_31(uint x, uint y, uint z) => (x & y) | (~x & z);
|
||||
|
||||
/// <summary>
|
||||
/// Round operation [32, 47]
|
||||
/// </summary>
|
||||
private static uint G32_47(uint x, uint y, uint z) => (x | ~y) ^ z;
|
||||
|
||||
/// <summary>
|
||||
/// Round operation [48, 63]
|
||||
/// </summary>
|
||||
private static uint G48_63(uint x, uint y, uint z) => (x & z) | (y & ~z);
|
||||
}
|
||||
}
|
||||
708
SabreTools.Hashing/CryptographicHash/RipeMD320.cs
Normal file
708
SabreTools.Hashing/CryptographicHash/RipeMD320.cs
Normal file
@@ -0,0 +1,708 @@
|
||||
using System;
|
||||
using static SabreTools.Hashing.CryptographicHash.Constants;
|
||||
using static SabreTools.Hashing.HashOperations;
|
||||
|
||||
namespace SabreTools.Hashing.CryptographicHash
|
||||
{
|
||||
/// <see href="https://cdn.standards.iteh.ai/samples/39876/10f9f9f4bb614eaaaeba7e157e183ca3/ISO-IEC-10118-3-2004.pdf"/>
|
||||
/// <see href="https://homes.esat.kuleuven.be/~bosselae/ripemd160/pdf/AB-9601/AB-9601.pdf"/>
|
||||
public class RipeMD320 : MessageDigestBase<uint>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 320;
|
||||
|
||||
/// <summary>
|
||||
/// Set of 10 32-bit numbers representing the hash state
|
||||
/// </summary>
|
||||
private readonly uint[] _state = new uint[10];
|
||||
|
||||
public RipeMD320() : base()
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void ResetImpl()
|
||||
{
|
||||
_state[0] = RMD160Y0;
|
||||
_state[1] = RMD160Y1;
|
||||
_state[2] = RMD160Y2;
|
||||
_state[3] = RMD160Y3;
|
||||
_state[4] = RMD160Y4;
|
||||
_state[5] = RMD320Y5;
|
||||
_state[6] = RMD320Y6;
|
||||
_state[7] = RMD320Y7;
|
||||
_state[8] = RMD320Y8;
|
||||
_state[9] = RMD320Y9;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void HashCore(byte[] data, int offset, int length)
|
||||
{
|
||||
// Figure out how much buffer is needed
|
||||
int bufferLen = (int)(_totalBytes & 0x3f);
|
||||
|
||||
// Increment the processed byte count
|
||||
_totalBytes += length;
|
||||
|
||||
// If there is buffer to fill and it will meet the limit
|
||||
if (bufferLen > 0 && bufferLen + length >= 64)
|
||||
{
|
||||
// Fill the buffer from the input
|
||||
Array.Copy(data, offset, _buffer, bufferLen, 64 - bufferLen);
|
||||
|
||||
// Set the new values
|
||||
offset += 64 - bufferLen;
|
||||
length -= 64 - bufferLen;
|
||||
|
||||
// Split the buffer for the round
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
_block[i] = ReadLE32(_buffer, i * 4);
|
||||
}
|
||||
|
||||
// Run the round
|
||||
Round();
|
||||
bufferLen = 0;
|
||||
}
|
||||
|
||||
/// Process any standalone blocks
|
||||
while (length >= 64)
|
||||
{
|
||||
// Fill the buffer from the input
|
||||
Array.Copy(data, offset, _buffer, 0, 64);
|
||||
|
||||
// Set the new values
|
||||
offset += 64;
|
||||
length -= 64;
|
||||
|
||||
// Split the buffer for the round
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
_block[i] = ReadLE32(_buffer, i * 4);
|
||||
}
|
||||
|
||||
// Run the round
|
||||
Round();
|
||||
}
|
||||
|
||||
// Save the remainder in the buffer
|
||||
if (length > 0)
|
||||
Array.Copy(data, offset, _buffer, bufferLen, length);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
// Determine the pad length
|
||||
int padLength = 64 - (int)(_totalBytes & 0x3f);
|
||||
if (padLength <= 8)
|
||||
padLength += 64;
|
||||
|
||||
// Get the total byte count in bits
|
||||
long totalBitCount = _totalBytes * 8;
|
||||
|
||||
// Prebuild the padding
|
||||
var padding = new byte[padLength];
|
||||
padding[0] = 0x80;
|
||||
padding[padLength - 1] = (byte)((totalBitCount >> 56) & 0xff);
|
||||
padding[padLength - 2] = (byte)((totalBitCount >> 48) & 0xff);
|
||||
padding[padLength - 3] = (byte)((totalBitCount >> 40) & 0xff);
|
||||
padding[padLength - 4] = (byte)((totalBitCount >> 32) & 0xff);
|
||||
padding[padLength - 5] = (byte)((totalBitCount >> 24) & 0xff);
|
||||
padding[padLength - 6] = (byte)((totalBitCount >> 16) & 0xff);
|
||||
padding[padLength - 7] = (byte)((totalBitCount >> 8) & 0xff);
|
||||
padding[padLength - 8] = (byte)((totalBitCount >> 0) & 0xff);
|
||||
|
||||
// Pad the block
|
||||
HashCore(padding, 0, padding.Length);
|
||||
|
||||
// Get the hash
|
||||
var hash = new byte[40];
|
||||
int hashOffset = 0;
|
||||
|
||||
// Assemble the hash array
|
||||
for (int i = 0; i < _state.Length; i++)
|
||||
{
|
||||
byte[] segment = BitConverter.GetBytes(_state[i]);
|
||||
Array.Copy(segment, 0, hash, hashOffset, 4);
|
||||
hashOffset += 4;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform one round of updates on the cached values
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The official specification for RIPEMD-160 includes tables
|
||||
/// and instructions that represent a loop. Most standard implementations
|
||||
/// use the unrolled version of that loop to make it more efficient.
|
||||
///
|
||||
/// The below code started with the looped version but has been converted
|
||||
/// to the more standard implementation instead.
|
||||
/// </remarks>
|
||||
private void Round()
|
||||
{
|
||||
// Setup values
|
||||
uint x0 = _state[0], xp0 = _state[5];
|
||||
uint x1 = _state[1], xp1 = _state[6];
|
||||
uint x2 = _state[2], xp2 = _state[7];
|
||||
uint x3 = _state[3], xp3 = _state[8];
|
||||
uint x4 = _state[4], xp4 = _state[9];
|
||||
uint t;
|
||||
|
||||
#region Rounds 0-15
|
||||
|
||||
// Round 0
|
||||
x0 = RotateLeft32(x0 + G00_15(x1, x2, x3) + _block[0] + RMD160Round00To15, 11) + x4;
|
||||
x2 = RotateLeft32(x2, 10);
|
||||
xp0 = RotateLeft32(xp0 + G64_79(xp1, xp2, xp3) + _block[5] + RMD160RoundPrime00To15, 8) + xp4;
|
||||
xp2 = RotateLeft32(xp2, 10);
|
||||
|
||||
// Round 1
|
||||
x4 = RotateLeft32(x4 + G00_15(x0, x1, x2) + _block[1] + RMD160Round00To15, 14) + x3;
|
||||
x1 = RotateLeft32(x1, 10);
|
||||
xp4 = RotateLeft32(xp4 + G64_79(xp0, xp1, xp2) + _block[14] + RMD160RoundPrime00To15, 9) + xp3;
|
||||
xp1 = RotateLeft32(xp1, 10);
|
||||
|
||||
// Round 2
|
||||
x3 = RotateLeft32(x3 + G00_15(x4, x0, x1) + _block[2] + RMD160Round00To15, 15) + x2;
|
||||
x0 = RotateLeft32(x0, 10);
|
||||
xp3 = RotateLeft32(xp3 + G64_79(xp4, xp0, xp1) + _block[7] + RMD160RoundPrime00To15, 9) + xp2;
|
||||
xp0 = RotateLeft32(xp0, 10);
|
||||
|
||||
// Round 3
|
||||
x2 = RotateLeft32(x2 + G00_15(x3, x4, x0) + _block[3] + RMD160Round00To15, 12) + x1;
|
||||
x4 = RotateLeft32(x4, 10);
|
||||
xp2 = RotateLeft32(xp2 + G64_79(xp3, xp4, xp0) + _block[0] + RMD160RoundPrime00To15, 11) + xp1;
|
||||
xp4 = RotateLeft32(xp4, 10);
|
||||
|
||||
// Round 4
|
||||
x1 = RotateLeft32(x1 + G00_15(x2, x3, x4) + _block[4] + RMD160Round00To15, 5) + x0;
|
||||
x3 = RotateLeft32(x3, 10);
|
||||
xp1 = RotateLeft32(xp1 + G64_79(xp2, xp3, xp4) + _block[9] + RMD160RoundPrime00To15, 13) + xp0;
|
||||
xp3 = RotateLeft32(xp3, 10);
|
||||
|
||||
// Round 5
|
||||
x0 = RotateLeft32(x0 + G00_15(x1, x2, x3) + _block[5] + RMD160Round00To15, 8) + x4;
|
||||
x2 = RotateLeft32(x2, 10);
|
||||
xp0 = RotateLeft32(xp0 + G64_79(xp1, xp2, xp3) + _block[2] + RMD160RoundPrime00To15, 15) + xp4;
|
||||
xp2 = RotateLeft32(xp2, 10);
|
||||
|
||||
// Round 6
|
||||
x4 = RotateLeft32(x4 + G00_15(x0, x1, x2) + _block[6] + RMD160Round00To15, 7) + x3;
|
||||
x1 = RotateLeft32(x1, 10);
|
||||
xp4 = RotateLeft32(xp4 + G64_79(xp0, xp1, xp2) + _block[11] + RMD160RoundPrime00To15, 15) + xp3;
|
||||
xp1 = RotateLeft32(xp1, 10);
|
||||
|
||||
// Round 7
|
||||
x3 = RotateLeft32(x3 + G00_15(x4, x0, x1) + _block[7] + RMD160Round00To15, 9) + x2;
|
||||
x0 = RotateLeft32(x0, 10);
|
||||
xp3 = RotateLeft32(xp3 + G64_79(xp4, xp0, xp1) + _block[4] + RMD160RoundPrime00To15, 5) + xp2;
|
||||
xp0 = RotateLeft32(xp0, 10);
|
||||
|
||||
// Round 8
|
||||
x2 = RotateLeft32(x2 + G00_15(x3, x4, x0) + _block[8] + RMD160Round00To15, 11) + x1;
|
||||
x4 = RotateLeft32(x4, 10);
|
||||
xp2 = RotateLeft32(xp2 + G64_79(xp3, xp4, xp0) + _block[13] + RMD160RoundPrime00To15, 7) + xp1;
|
||||
xp4 = RotateLeft32(xp4, 10);
|
||||
|
||||
// Round 9
|
||||
x1 = RotateLeft32(x1 + G00_15(x2, x3, x4) + _block[9] + RMD160Round00To15, 13) + x0;
|
||||
x3 = RotateLeft32(x3, 10);
|
||||
xp1 = RotateLeft32(xp1 + G64_79(xp2, xp3, xp4) + _block[6] + RMD160RoundPrime00To15, 7) + xp0;
|
||||
xp3 = RotateLeft32(xp3, 10);
|
||||
|
||||
// Round 10
|
||||
x0 = RotateLeft32(x0 + G00_15(x1, x2, x3) + _block[10] + RMD160Round00To15, 14) + x4;
|
||||
x2 = RotateLeft32(x2, 10);
|
||||
xp0 = RotateLeft32(xp0 + G64_79(xp1, xp2, xp3) + _block[15] + RMD160RoundPrime00To15, 8) + xp4;
|
||||
xp2 = RotateLeft32(xp2, 10);
|
||||
|
||||
// Round 11
|
||||
x4 = RotateLeft32(x4 + G00_15(x0, x1, x2) + _block[11] + RMD160Round00To15, 15) + x3;
|
||||
x1 = RotateLeft32(x1, 10);
|
||||
xp4 = RotateLeft32(xp4 + G64_79(xp0, xp1, xp2) + _block[8] + RMD160RoundPrime00To15, 11) + xp3;
|
||||
xp1 = RotateLeft32(xp1, 10);
|
||||
|
||||
// Round 12
|
||||
x3 = RotateLeft32(x3 + G00_15(x4, x0, x1) + _block[12] + RMD160Round00To15, 6) + x2;
|
||||
x0 = RotateLeft32(x0, 10);
|
||||
xp3 = RotateLeft32(xp3 + G64_79(xp4, xp0, xp1) + _block[1] + RMD160RoundPrime00To15, 14) + xp2;
|
||||
xp0 = RotateLeft32(xp0, 10);
|
||||
|
||||
// Round 13
|
||||
x2 = RotateLeft32(x2 + G00_15(x3, x4, x0) + _block[13] + RMD160Round00To15, 7) + x1;
|
||||
x4 = RotateLeft32(x4, 10);
|
||||
xp2 = RotateLeft32(xp2 + G64_79(xp3, xp4, xp0) + _block[10] + RMD160RoundPrime00To15, 14) + xp1;
|
||||
xp4 = RotateLeft32(xp4, 10);
|
||||
|
||||
// Round 14
|
||||
x1 = RotateLeft32(x1 + G00_15(x2, x3, x4) + _block[14] + RMD160Round00To15, 9) + x0;
|
||||
x3 = RotateLeft32(x3, 10);
|
||||
xp1 = RotateLeft32(xp1 + G64_79(xp2, xp3, xp4) + _block[3] + RMD160RoundPrime00To15, 12) + xp0;
|
||||
xp3 = RotateLeft32(xp3, 10);
|
||||
|
||||
// Round 15
|
||||
x0 = RotateLeft32(x0 + G00_15(x1, x2, x3) + _block[15] + RMD160Round00To15, 8) + x4;
|
||||
x2 = RotateLeft32(x2, 10);
|
||||
xp0 = RotateLeft32(xp0 + G64_79(xp1, xp2, xp3) + _block[12] + RMD160RoundPrime00To15, 6) + xp4;
|
||||
xp2 = RotateLeft32(xp2, 10);
|
||||
|
||||
// Swap set 1
|
||||
t = x0; x0 = xp0; xp0 = t;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Rounds 16-31
|
||||
|
||||
// Round 16
|
||||
x4 = RotateLeft32(x4 + G16_31(x0, x1, x2) + _block[7] + RMD160Round16To31, 7) + x3;
|
||||
x1 = RotateLeft32(x1, 10);
|
||||
xp4 = RotateLeft32(xp4 + G48_63(xp0, xp1, xp2) + _block[6] + RMD160RoundPrime16To31, 9) + xp3;
|
||||
xp1 = RotateLeft32(xp1, 10);
|
||||
|
||||
// Round 17
|
||||
x3 = RotateLeft32(x3 + G16_31(x4, x0, x1) + _block[4] + RMD160Round16To31, 6) + x2;
|
||||
x0 = RotateLeft32(x0, 10);
|
||||
xp3 = RotateLeft32(xp3 + G48_63(xp4, xp0, xp1) + _block[11] + RMD160RoundPrime16To31, 13) + xp2;
|
||||
xp0 = RotateLeft32(xp0, 10);
|
||||
|
||||
// Round 18
|
||||
x2 = RotateLeft32(x2 + G16_31(x3, x4, x0) + _block[13] + RMD160Round16To31, 8) + x1;
|
||||
x4 = RotateLeft32(x4, 10);
|
||||
xp2 = RotateLeft32(xp2 + G48_63(xp3, xp4, xp0) + _block[3] + RMD160RoundPrime16To31, 15) + xp1;
|
||||
xp4 = RotateLeft32(xp4, 10);
|
||||
|
||||
// Round 19
|
||||
x1 = RotateLeft32(x1 + G16_31(x2, x3, x4) + _block[1] + RMD160Round16To31, 13) + x0;
|
||||
x3 = RotateLeft32(x3, 10);
|
||||
xp1 = RotateLeft32(xp1 + G48_63(xp2, xp3, xp4) + _block[7] + RMD160RoundPrime16To31, 7) + xp0;
|
||||
xp3 = RotateLeft32(xp3, 10);
|
||||
|
||||
// Round 20
|
||||
x0 = RotateLeft32(x0 + G16_31(x1, x2, x3) + _block[10] + RMD160Round16To31, 11) + x4;
|
||||
x2 = RotateLeft32(x2, 10);
|
||||
xp0 = RotateLeft32(xp0 + G48_63(xp1, xp2, xp3) + _block[0] + RMD160RoundPrime16To31, 12) + xp4;
|
||||
xp2 = RotateLeft32(xp2, 10);
|
||||
|
||||
// Round 21
|
||||
x4 = RotateLeft32(x4 + G16_31(x0, x1, x2) + _block[6] + RMD160Round16To31, 9) + x3;
|
||||
x1 = RotateLeft32(x1, 10);
|
||||
xp4 = RotateLeft32(xp4 + G48_63(xp0, xp1, xp2) + _block[13] + RMD160RoundPrime16To31, 8) + xp3;
|
||||
xp1 = RotateLeft32(xp1, 10);
|
||||
|
||||
// Round 22
|
||||
x3 = RotateLeft32(x3 + G16_31(x4, x0, x1) + _block[15] + RMD160Round16To31, 7) + x2;
|
||||
x0 = RotateLeft32(x0, 10);
|
||||
xp3 = RotateLeft32(xp3 + G48_63(xp4, xp0, xp1) + _block[5] + RMD160RoundPrime16To31, 9) + xp2;
|
||||
xp0 = RotateLeft32(xp0, 10);
|
||||
|
||||
// Round 23
|
||||
x2 = RotateLeft32(x2 + G16_31(x3, x4, x0) + _block[3] + RMD160Round16To31, 15) + x1;
|
||||
x4 = RotateLeft32(x4, 10);
|
||||
xp2 = RotateLeft32(xp2 + G48_63(xp3, xp4, xp0) + _block[10] + RMD160RoundPrime16To31, 11) + xp1;
|
||||
xp4 = RotateLeft32(xp4, 10);
|
||||
|
||||
// Round 24
|
||||
x1 = RotateLeft32(x1 + G16_31(x2, x3, x4) + _block[12] + RMD160Round16To31, 7) + x0;
|
||||
x3 = RotateLeft32(x3, 10);
|
||||
xp1 = RotateLeft32(xp1 + G48_63(xp2, xp3, xp4) + _block[14] + RMD160RoundPrime16To31, 7) + xp0;
|
||||
xp3 = RotateLeft32(xp3, 10);
|
||||
|
||||
// Round 25
|
||||
x0 = RotateLeft32(x0 + G16_31(x1, x2, x3) + _block[0] + RMD160Round16To31, 12) + x4;
|
||||
x2 = RotateLeft32(x2, 10);
|
||||
xp0 = RotateLeft32(xp0 + G48_63(xp1, xp2, xp3) + _block[15] + RMD160RoundPrime16To31, 7) + xp4;
|
||||
xp2 = RotateLeft32(xp2, 10);
|
||||
|
||||
// Round 26
|
||||
x4 = RotateLeft32(x4 + G16_31(x0, x1, x2) + _block[9] + RMD160Round16To31, 15) + x3;
|
||||
x1 = RotateLeft32(x1, 10);
|
||||
xp4 = RotateLeft32(xp4 + G48_63(xp0, xp1, xp2) + _block[8] + RMD160RoundPrime16To31, 12) + xp3;
|
||||
xp1 = RotateLeft32(xp1, 10);
|
||||
|
||||
// Round 27
|
||||
x3 = RotateLeft32(x3 + G16_31(x4, x0, x1) + _block[5] + RMD160Round16To31, 9) + x2;
|
||||
x0 = RotateLeft32(x0, 10);
|
||||
xp3 = RotateLeft32(xp3 + G48_63(xp4, xp0, xp1) + _block[12] + RMD160RoundPrime16To31, 7) + xp2;
|
||||
xp0 = RotateLeft32(xp0, 10);
|
||||
|
||||
// Round 28
|
||||
x2 = RotateLeft32(x2 + G16_31(x3, x4, x0) + _block[2] + RMD160Round16To31, 11) + x1;
|
||||
x4 = RotateLeft32(x4, 10);
|
||||
xp2 = RotateLeft32(xp2 + G48_63(xp3, xp4, xp0) + _block[4] + RMD160RoundPrime16To31, 6) + xp1;
|
||||
xp4 = RotateLeft32(xp4, 10);
|
||||
|
||||
// Round 29
|
||||
x1 = RotateLeft32(x1 + G16_31(x2, x3, x4) + _block[14] + RMD160Round16To31, 7) + x0;
|
||||
x3 = RotateLeft32(x3, 10);
|
||||
xp1 = RotateLeft32(xp1 + G48_63(xp2, xp3, xp4) + _block[9] + RMD160RoundPrime16To31, 15) + xp0;
|
||||
xp3 = RotateLeft32(xp3, 10);
|
||||
|
||||
// Round 30
|
||||
x0 = RotateLeft32(x0 + G16_31(x1, x2, x3) + _block[11] + RMD160Round16To31, 13) + x4;
|
||||
x2 = RotateLeft32(x2, 10);
|
||||
xp0 = RotateLeft32(xp0 + G48_63(xp1, xp2, xp3) + _block[1] + RMD160RoundPrime16To31, 13) + xp4;
|
||||
xp2 = RotateLeft32(xp2, 10);
|
||||
|
||||
// Round 31
|
||||
x4 = RotateLeft32(x4 + G16_31(x0, x1, x2) + _block[8] + RMD160Round16To31, 12) + x3;
|
||||
x1 = RotateLeft32(x1, 10);
|
||||
xp4 = RotateLeft32(xp4 + G48_63(xp0, xp1, xp2) + _block[2] + RMD160RoundPrime16To31, 11) + xp3;
|
||||
xp1 = RotateLeft32(xp1, 10);
|
||||
|
||||
// Swap set 2
|
||||
t = x1; x1 = xp1; xp1 = t;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Rounds 32-47
|
||||
|
||||
// Round 32
|
||||
x3 = RotateLeft32(x3 + G32_47(x4, x0, x1) + _block[3] + RMD160Round32To47, 11) + x2;
|
||||
x0 = RotateLeft32(x0, 10);
|
||||
xp3 = RotateLeft32(xp3 + G32_47(xp4, xp0, xp1) + _block[15] + RMD160RoundPrime32To47, 9) + xp2;
|
||||
xp0 = RotateLeft32(xp0, 10);
|
||||
|
||||
// Round 33
|
||||
x2 = RotateLeft32(x2 + G32_47(x3, x4, x0) + _block[10] + RMD160Round32To47, 13) + x1;
|
||||
x4 = RotateLeft32(x4, 10);
|
||||
xp2 = RotateLeft32(xp2 + G32_47(xp3, xp4, xp0) + _block[5] + RMD160RoundPrime32To47, 7) + xp1;
|
||||
xp4 = RotateLeft32(xp4, 10);
|
||||
|
||||
// Round 34
|
||||
x1 = RotateLeft32(x1 + G32_47(x2, x3, x4) + _block[14] + RMD160Round32To47, 6) + x0;
|
||||
x3 = RotateLeft32(x3, 10);
|
||||
xp1 = RotateLeft32(xp1 + G32_47(xp2, xp3, xp4) + _block[1] + RMD160RoundPrime32To47, 15) + xp0;
|
||||
xp3 = RotateLeft32(xp3, 10);
|
||||
|
||||
// Round 35
|
||||
x0 = RotateLeft32(x0 + G32_47(x1, x2, x3) + _block[4] + RMD160Round32To47, 7) + x4;
|
||||
x2 = RotateLeft32(x2, 10);
|
||||
xp0 = RotateLeft32(xp0 + G32_47(xp1, xp2, xp3) + _block[3] + RMD160RoundPrime32To47, 11) + xp4;
|
||||
xp2 = RotateLeft32(xp2, 10);
|
||||
|
||||
// Round 36
|
||||
x4 = RotateLeft32(x4 + G32_47(x0, x1, x2) + _block[9] + RMD160Round32To47, 14) + x3;
|
||||
x1 = RotateLeft32(x1, 10);
|
||||
xp4 = RotateLeft32(xp4 + G32_47(xp0, xp1, xp2) + _block[7] + RMD160RoundPrime32To47, 8) + xp3;
|
||||
xp1 = RotateLeft32(xp1, 10);
|
||||
|
||||
// Round 37
|
||||
x3 = RotateLeft32(x3 + G32_47(x4, x0, x1) + _block[15] + RMD160Round32To47, 9) + x2;
|
||||
x0 = RotateLeft32(x0, 10);
|
||||
xp3 = RotateLeft32(xp3 + G32_47(xp4, xp0, xp1) + _block[14] + RMD160RoundPrime32To47, 6) + xp2;
|
||||
xp0 = RotateLeft32(xp0, 10);
|
||||
|
||||
// Round 38
|
||||
x2 = RotateLeft32(x2 + G32_47(x3, x4, x0) + _block[8] + RMD160Round32To47, 13) + x1;
|
||||
x4 = RotateLeft32(x4, 10);
|
||||
xp2 = RotateLeft32(xp2 + G32_47(xp3, xp4, xp0) + _block[6] + RMD160RoundPrime32To47, 6) + xp1;
|
||||
xp4 = RotateLeft32(xp4, 10);
|
||||
|
||||
// Round 39
|
||||
x1 = RotateLeft32(x1 + G32_47(x2, x3, x4) + _block[1] + RMD160Round32To47, 15) + x0;
|
||||
x3 = RotateLeft32(x3, 10);
|
||||
xp1 = RotateLeft32(xp1 + G32_47(xp2, xp3, xp4) + _block[9] + RMD160RoundPrime32To47, 14) + xp0;
|
||||
xp3 = RotateLeft32(xp3, 10);
|
||||
|
||||
// Round 40
|
||||
x0 = RotateLeft32(x0 + G32_47(x1, x2, x3) + _block[2] + RMD160Round32To47, 14) + x4;
|
||||
x2 = RotateLeft32(x2, 10);
|
||||
xp0 = RotateLeft32(xp0 + G32_47(xp1, xp2, xp3) + _block[11] + RMD160RoundPrime32To47, 12) + xp4;
|
||||
xp2 = RotateLeft32(xp2, 10);
|
||||
|
||||
// Round 41
|
||||
x4 = RotateLeft32(x4 + G32_47(x0, x1, x2) + _block[7] + RMD160Round32To47, 8) + x3;
|
||||
x1 = RotateLeft32(x1, 10);
|
||||
xp4 = RotateLeft32(xp4 + G32_47(xp0, xp1, xp2) + _block[8] + RMD160RoundPrime32To47, 13) + xp3;
|
||||
xp1 = RotateLeft32(xp1, 10);
|
||||
|
||||
// Round 42
|
||||
x3 = RotateLeft32(x3 + G32_47(x4, x0, x1) + _block[0] + RMD160Round32To47, 13) + x2;
|
||||
x0 = RotateLeft32(x0, 10);
|
||||
xp3 = RotateLeft32(xp3 + G32_47(xp4, xp0, xp1) + _block[12] + RMD160RoundPrime32To47, 5) + xp2;
|
||||
xp0 = RotateLeft32(xp0, 10);
|
||||
|
||||
// Round 43
|
||||
x2 = RotateLeft32(x2 + G32_47(x3, x4, x0) + _block[6] + RMD160Round32To47, 6) + x1;
|
||||
x4 = RotateLeft32(x4, 10);
|
||||
xp2 = RotateLeft32(xp2 + G32_47(xp3, xp4, xp0) + _block[2] + RMD160RoundPrime32To47, 14) + xp1;
|
||||
xp4 = RotateLeft32(xp4, 10);
|
||||
|
||||
// Round 44
|
||||
x1 = RotateLeft32(x1 + G32_47(x2, x3, x4) + _block[13] + RMD160Round32To47, 5) + x0;
|
||||
x3 = RotateLeft32(x3, 10);
|
||||
xp1 = RotateLeft32(xp1 + G32_47(xp2, xp3, xp4) + _block[10] + RMD160RoundPrime32To47, 13) + xp0;
|
||||
xp3 = RotateLeft32(xp3, 10);
|
||||
|
||||
// Round 45
|
||||
x0 = RotateLeft32(x0 + G32_47(x1, x2, x3) + _block[11] + RMD160Round32To47, 12) + x4;
|
||||
x2 = RotateLeft32(x2, 10);
|
||||
xp0 = RotateLeft32(xp0 + G32_47(xp1, xp2, xp3) + _block[0] + RMD160RoundPrime32To47, 13) + xp4;
|
||||
xp2 = RotateLeft32(xp2, 10);
|
||||
|
||||
// Round 46
|
||||
x4 = RotateLeft32(x4 + G32_47(x0, x1, x2) + _block[5] + RMD160Round32To47, 7) + x3;
|
||||
x1 = RotateLeft32(x1, 10);
|
||||
xp4 = RotateLeft32(xp4 + G32_47(xp0, xp1, xp2) + _block[4] + RMD160RoundPrime32To47, 7) + xp3;
|
||||
xp1 = RotateLeft32(xp1, 10);
|
||||
|
||||
// Round 47
|
||||
x3 = RotateLeft32(x3 + G32_47(x4, x0, x1) + _block[12] + RMD160Round32To47, 5) + x2;
|
||||
x0 = RotateLeft32(x0, 10);
|
||||
xp3 = RotateLeft32(xp3 + G32_47(xp4, xp0, xp1) + _block[13] + RMD160RoundPrime32To47, 5) + xp2;
|
||||
xp0 = RotateLeft32(xp0, 10);
|
||||
|
||||
// Swap set 3
|
||||
t = x2; x2 = xp2; xp2 = t;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Rounds 48-63
|
||||
|
||||
// Round 48
|
||||
x2 = RotateLeft32(x2 + G48_63(x3, x4, x0) + _block[1] + RMD160Round48To63, 11) + x1;
|
||||
x4 = RotateLeft32(x4, 10);
|
||||
xp2 = RotateLeft32(xp2 + G16_31(xp3, xp4, xp0) + _block[8] + RMD160RoundPrime48To63, 15) + xp1;
|
||||
xp4 = RotateLeft32(xp4, 10);
|
||||
|
||||
// Round 49
|
||||
x1 = RotateLeft32(x1 + G48_63(x2, x3, x4) + _block[9] + RMD160Round48To63, 12) + x0;
|
||||
x3 = RotateLeft32(x3, 10);
|
||||
xp1 = RotateLeft32(xp1 + G16_31(xp2, xp3, xp4) + _block[6] + RMD160RoundPrime48To63, 5) + xp0;
|
||||
xp3 = RotateLeft32(xp3, 10);
|
||||
|
||||
// Round 50
|
||||
x0 = RotateLeft32(x0 + G48_63(x1, x2, x3) + _block[11] + RMD160Round48To63, 14) + x4;
|
||||
x2 = RotateLeft32(x2, 10);
|
||||
xp0 = RotateLeft32(xp0 + G16_31(xp1, xp2, xp3) + _block[4] + RMD160RoundPrime48To63, 8) + xp4;
|
||||
xp2 = RotateLeft32(xp2, 10);
|
||||
|
||||
// Round 51
|
||||
x4 = RotateLeft32(x4 + G48_63(x0, x1, x2) + _block[10] + RMD160Round48To63, 15) + x3;
|
||||
x1 = RotateLeft32(x1, 10);
|
||||
xp4 = RotateLeft32(xp4 + G16_31(xp0, xp1, xp2) + _block[1] + RMD160RoundPrime48To63, 11) + xp3;
|
||||
xp1 = RotateLeft32(xp1, 10);
|
||||
|
||||
// Round 52
|
||||
x3 = RotateLeft32(x3 + G48_63(x4, x0, x1) + _block[0] + RMD160Round48To63, 14) + x2;
|
||||
x0 = RotateLeft32(x0, 10);
|
||||
xp3 = RotateLeft32(xp3 + G16_31(xp4, xp0, xp1) + _block[3] + RMD160RoundPrime48To63, 14) + xp2;
|
||||
xp0 = RotateLeft32(xp0, 10);
|
||||
|
||||
// Round 53
|
||||
x2 = RotateLeft32(x2 + G48_63(x3, x4, x0) + _block[8] + RMD160Round48To63, 15) + x1;
|
||||
x4 = RotateLeft32(x4, 10);
|
||||
xp2 = RotateLeft32(xp2 + G16_31(xp3, xp4, xp0) + _block[11] + RMD160RoundPrime48To63, 14) + xp1;
|
||||
xp4 = RotateLeft32(xp4, 10);
|
||||
|
||||
// Round 54
|
||||
x1 = RotateLeft32(x1 + G48_63(x2, x3, x4) + _block[12] + RMD160Round48To63, 9) + x0;
|
||||
x3 = RotateLeft32(x3, 10);
|
||||
xp1 = RotateLeft32(xp1 + G16_31(xp2, xp3, xp4) + _block[15] + RMD160RoundPrime48To63, 6) + xp0;
|
||||
xp3 = RotateLeft32(xp3, 10);
|
||||
|
||||
// Round 55
|
||||
x0 = RotateLeft32(x0 + G48_63(x1, x2, x3) + _block[4] + RMD160Round48To63, 8) + x4;
|
||||
x2 = RotateLeft32(x2, 10);
|
||||
xp0 = RotateLeft32(xp0 + G16_31(xp1, xp2, xp3) + _block[0] + RMD160RoundPrime48To63, 14) + xp4;
|
||||
xp2 = RotateLeft32(xp2, 10);
|
||||
|
||||
// Round 56
|
||||
x4 = RotateLeft32(x4 + G48_63(x0, x1, x2) + _block[13] + RMD160Round48To63, 9) + x3;
|
||||
x1 = RotateLeft32(x1, 10);
|
||||
xp4 = RotateLeft32(xp4 + G16_31(xp0, xp1, xp2) + _block[5] + RMD160RoundPrime48To63, 6) + xp3;
|
||||
xp1 = RotateLeft32(xp1, 10);
|
||||
|
||||
// Round 57
|
||||
x3 = RotateLeft32(x3 + G48_63(x4, x0, x1) + _block[3] + RMD160Round48To63, 14) + x2;
|
||||
x0 = RotateLeft32(x0, 10);
|
||||
xp3 = RotateLeft32(xp3 + G16_31(xp4, xp0, xp1) + _block[12] + RMD160RoundPrime48To63, 9) + xp2;
|
||||
xp0 = RotateLeft32(xp0, 10);
|
||||
|
||||
// Round 58
|
||||
x2 = RotateLeft32(x2 + G48_63(x3, x4, x0) + _block[7] + RMD160Round48To63, 5) + x1;
|
||||
x4 = RotateLeft32(x4, 10);
|
||||
xp2 = RotateLeft32(xp2 + G16_31(xp3, xp4, xp0) + _block[2] + RMD160RoundPrime48To63, 12) + xp1;
|
||||
xp4 = RotateLeft32(xp4, 10);
|
||||
|
||||
// Round 59
|
||||
x1 = RotateLeft32(x1 + G48_63(x2, x3, x4) + _block[15] + RMD160Round48To63, 6) + x0;
|
||||
x3 = RotateLeft32(x3, 10);
|
||||
xp1 = RotateLeft32(xp1 + G16_31(xp2, xp3, xp4) + _block[13] + RMD160RoundPrime48To63, 9) + xp0;
|
||||
xp3 = RotateLeft32(xp3, 10);
|
||||
|
||||
// Round 60
|
||||
x0 = RotateLeft32(x0 + G48_63(x1, x2, x3) + _block[14] + RMD160Round48To63, 8) + x4;
|
||||
x2 = RotateLeft32(x2, 10);
|
||||
xp0 = RotateLeft32(xp0 + G16_31(xp1, xp2, xp3) + _block[9] + RMD160RoundPrime48To63, 12) + xp4;
|
||||
xp2 = RotateLeft32(xp2, 10);
|
||||
|
||||
// Round 61
|
||||
x4 = RotateLeft32(x4 + G48_63(x0, x1, x2) + _block[5] + RMD160Round48To63, 6) + x3;
|
||||
x1 = RotateLeft32(x1, 10);
|
||||
xp4 = RotateLeft32(xp4 + G16_31(xp0, xp1, xp2) + _block[7] + RMD160RoundPrime48To63, 5) + xp3;
|
||||
xp1 = RotateLeft32(xp1, 10);
|
||||
|
||||
// Round 62
|
||||
x3 = RotateLeft32(x3 + G48_63(x4, x0, x1) + _block[6] + RMD160Round48To63, 5) + x2;
|
||||
x0 = RotateLeft32(x0, 10);
|
||||
xp3 = RotateLeft32(xp3 + G16_31(xp4, xp0, xp1) + _block[10] + RMD160RoundPrime48To63, 15) + xp2;
|
||||
xp0 = RotateLeft32(xp0, 10);
|
||||
|
||||
// Round 63
|
||||
x2 = RotateLeft32(x2 + G48_63(x3, x4, x0) + _block[2] + RMD160Round48To63, 12) + x1;
|
||||
x4 = RotateLeft32(x4, 10);
|
||||
xp2 = RotateLeft32(xp2 + G16_31(xp3, xp4, xp0) + _block[14] + RMD160RoundPrime48To63, 8) + xp1;
|
||||
xp4 = RotateLeft32(xp4, 10);
|
||||
|
||||
// Swap set 4
|
||||
t = x3; x3 = xp3; xp3 = t;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Rounds 64-79
|
||||
|
||||
// Round 64
|
||||
x1 = RotateLeft32(x1 + G64_79(x2, x3, x4) + _block[4] + RMD160Round64To79, 9) + x0;
|
||||
x3 = RotateLeft32(x3, 10);
|
||||
xp1 = RotateLeft32(xp1 + G00_15(xp2, xp3, xp4) + _block[12] + RMD160RoundPrime64To79, 8) + xp0;
|
||||
xp3 = RotateLeft32(xp3, 10);
|
||||
|
||||
// Round 65
|
||||
x0 = RotateLeft32(x0 + G64_79(x1, x2, x3) + _block[0] + RMD160Round64To79, 15) + x4;
|
||||
x2 = RotateLeft32(x2, 10);
|
||||
xp0 = RotateLeft32(xp0 + G00_15(xp1, xp2, xp3) + _block[15] + RMD160RoundPrime64To79, 5) + xp4;
|
||||
xp2 = RotateLeft32(xp2, 10);
|
||||
|
||||
// Round 66
|
||||
x4 = RotateLeft32(x4 + G64_79(x0, x1, x2) + _block[5] + RMD160Round64To79, 5) + x3;
|
||||
x1 = RotateLeft32(x1, 10);
|
||||
xp4 = RotateLeft32(xp4 + G00_15(xp0, xp1, xp2) + _block[10] + RMD160RoundPrime64To79, 12) + xp3;
|
||||
xp1 = RotateLeft32(xp1, 10);
|
||||
|
||||
// Round 67
|
||||
x3 = RotateLeft32(x3 + G64_79(x4, x0, x1) + _block[9] + RMD160Round64To79, 11) + x2;
|
||||
x0 = RotateLeft32(x0, 10);
|
||||
xp3 = RotateLeft32(xp3 + G00_15(xp4, xp0, xp1) + _block[4] + RMD160RoundPrime64To79, 9) + xp2;
|
||||
xp0 = RotateLeft32(xp0, 10);
|
||||
|
||||
// Round 68
|
||||
x2 = RotateLeft32(x2 + G64_79(x3, x4, x0) + _block[7] + RMD160Round64To79, 6) + x1;
|
||||
x4 = RotateLeft32(x4, 10);
|
||||
xp2 = RotateLeft32(xp2 + G00_15(xp3, xp4, xp0) + _block[1] + RMD160RoundPrime64To79, 12) + xp1;
|
||||
xp4 = RotateLeft32(xp4, 10);
|
||||
|
||||
// Round 69
|
||||
x1 = RotateLeft32(x1 + G64_79(x2, x3, x4) + _block[12] + RMD160Round64To79, 8) + x0;
|
||||
x3 = RotateLeft32(x3, 10);
|
||||
xp1 = RotateLeft32(xp1 + G00_15(xp2, xp3, xp4) + _block[5] + RMD160RoundPrime64To79, 5) + xp0;
|
||||
xp3 = RotateLeft32(xp3, 10);
|
||||
|
||||
// Round 70
|
||||
x0 = RotateLeft32(x0 + G64_79(x1, x2, x3) + _block[2] + RMD160Round64To79, 13) + x4;
|
||||
x2 = RotateLeft32(x2, 10);
|
||||
xp0 = RotateLeft32(xp0 + G00_15(xp1, xp2, xp3) + _block[8] + RMD160RoundPrime64To79, 14) + xp4;
|
||||
xp2 = RotateLeft32(xp2, 10);
|
||||
|
||||
// Round 71
|
||||
x4 = RotateLeft32(x4 + G64_79(x0, x1, x2) + _block[10] + RMD160Round64To79, 12) + x3;
|
||||
x1 = RotateLeft32(x1, 10);
|
||||
xp4 = RotateLeft32(xp4 + G00_15(xp0, xp1, xp2) + _block[7] + RMD160RoundPrime64To79, 6) + xp3;
|
||||
xp1 = RotateLeft32(xp1, 10);
|
||||
|
||||
// Round 72
|
||||
x3 = RotateLeft32(x3 + G64_79(x4, x0, x1) + _block[14] + RMD160Round64To79, 5) + x2;
|
||||
x0 = RotateLeft32(x0, 10);
|
||||
xp3 = RotateLeft32(xp3 + G00_15(xp4, xp0, xp1) + _block[6] + RMD160RoundPrime64To79, 8) + xp2;
|
||||
xp0 = RotateLeft32(xp0, 10);
|
||||
|
||||
// Round 73
|
||||
x2 = RotateLeft32(x2 + G64_79(x3, x4, x0) + _block[1] + RMD160Round64To79, 12) + x1;
|
||||
x4 = RotateLeft32(x4, 10);
|
||||
xp2 = RotateLeft32(xp2 + G00_15(xp3, xp4, xp0) + _block[2] + RMD160RoundPrime64To79, 13) + xp1;
|
||||
xp4 = RotateLeft32(xp4, 10);
|
||||
|
||||
// Round 74
|
||||
x1 = RotateLeft32(x1 + G64_79(x2, x3, x4) + _block[3] + RMD160Round64To79, 13) + x0;
|
||||
x3 = RotateLeft32(x3, 10);
|
||||
xp1 = RotateLeft32(xp1 + G00_15(xp2, xp3, xp4) + _block[13] + RMD160RoundPrime64To79, 6) + xp0;
|
||||
xp3 = RotateLeft32(xp3, 10);
|
||||
|
||||
// Round 75
|
||||
x0 = RotateLeft32(x0 + G64_79(x1, x2, x3) + _block[8] + RMD160Round64To79, 14) + x4;
|
||||
x2 = RotateLeft32(x2, 10);
|
||||
xp0 = RotateLeft32(xp0 + G00_15(xp1, xp2, xp3) + _block[14] + RMD160RoundPrime64To79, 5) + xp4;
|
||||
xp2 = RotateLeft32(xp2, 10);
|
||||
|
||||
// Round 76
|
||||
x4 = RotateLeft32(x4 + G64_79(x0, x1, x2) + _block[11] + RMD160Round64To79, 11) + x3;
|
||||
x1 = RotateLeft32(x1, 10);
|
||||
xp4 = RotateLeft32(xp4 + G00_15(xp0, xp1, xp2) + _block[0] + RMD160RoundPrime64To79, 15) + xp3;
|
||||
xp1 = RotateLeft32(xp1, 10);
|
||||
|
||||
// Round 77
|
||||
x3 = RotateLeft32(x3 + G64_79(x4, x0, x1) + _block[6] + RMD160Round64To79, 8) + x2;
|
||||
x0 = RotateLeft32(x0, 10);
|
||||
xp3 = RotateLeft32(xp3 + G00_15(xp4, xp0, xp1) + _block[3] + RMD160RoundPrime64To79, 13) + xp2;
|
||||
xp0 = RotateLeft32(xp0, 10);
|
||||
|
||||
// Round 78
|
||||
x2 = RotateLeft32(x2 + G64_79(x3, x4, x0) + _block[15] + RMD160Round64To79, 5) + x1;
|
||||
x4 = RotateLeft32(x4, 10);
|
||||
xp2 = RotateLeft32(xp2 + G00_15(xp3, xp4, xp0) + _block[9] + RMD160RoundPrime64To79, 11) + xp1;
|
||||
xp4 = RotateLeft32(xp4, 10);
|
||||
|
||||
// Round 79
|
||||
x1 = RotateLeft32(x1 + G64_79(x2, x3, x4) + _block[13] + RMD160Round64To79, 6) + x0;
|
||||
x3 = RotateLeft32(x3, 10);
|
||||
xp1 = RotateLeft32(xp1 + G00_15(xp2, xp3, xp4) + _block[11] + RMD160RoundPrime64To79, 11) + xp0;
|
||||
xp3 = RotateLeft32(xp3, 10);
|
||||
|
||||
// Swap set 5
|
||||
t = x4; x4 = xp4; xp4 = t;
|
||||
|
||||
#endregion
|
||||
|
||||
// Avalanche values
|
||||
_state[0] += x0;
|
||||
_state[1] += x1;
|
||||
_state[2] += x2;
|
||||
_state[3] += x3;
|
||||
_state[4] += x4;
|
||||
_state[5] += xp0;
|
||||
_state[6] += xp1;
|
||||
_state[7] += xp2;
|
||||
_state[8] += xp3;
|
||||
_state[9] += xp4;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Round operation [0, 15]
|
||||
/// </summary>
|
||||
private static uint G00_15(uint x, uint y, uint z) => x ^ y ^ z;
|
||||
|
||||
/// <summary>
|
||||
/// Round operation [16, 31]
|
||||
/// </summary>
|
||||
private static uint G16_31(uint x, uint y, uint z) => (x & y) | (~x & z);
|
||||
|
||||
/// <summary>
|
||||
/// Round operation [32, 47]
|
||||
/// </summary>
|
||||
private static uint G32_47(uint x, uint y, uint z) => (x | ~y) ^ z;
|
||||
|
||||
/// <summary>
|
||||
/// Round operation [48, 63]
|
||||
/// </summary>
|
||||
private static uint G48_63(uint x, uint y, uint z) => (x & z) | (y & ~z);
|
||||
|
||||
/// <summary>
|
||||
/// Round operation [64, 79]
|
||||
/// </summary>
|
||||
private static uint G64_79(uint x, uint y, uint z) => x ^ (y | ~z);
|
||||
}
|
||||
}
|
||||
28
SabreTools.Hashing/CryptographicHash/Tiger128_3.cs
Normal file
28
SabreTools.Hashing/CryptographicHash/Tiger128_3.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
|
||||
namespace SabreTools.Hashing.CryptographicHash
|
||||
{
|
||||
/// <summary>
|
||||
/// 3-pass variant of Tiger-128
|
||||
/// </summary>
|
||||
public class Tiger128_3 : TigerHashBase
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 128;
|
||||
|
||||
public Tiger128_3() : base()
|
||||
{
|
||||
_passes = 3;
|
||||
_padStart = 0x01;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
byte[] hash = base.HashFinal();
|
||||
byte[] trimmedHash = new byte[16];
|
||||
Array.Copy(hash, trimmedHash, 16);
|
||||
return trimmedHash;
|
||||
}
|
||||
}
|
||||
}
|
||||
28
SabreTools.Hashing/CryptographicHash/Tiger128_4.cs
Normal file
28
SabreTools.Hashing/CryptographicHash/Tiger128_4.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
|
||||
namespace SabreTools.Hashing.CryptographicHash
|
||||
{
|
||||
/// <summary>
|
||||
/// 4-pass variant of Tiger-128
|
||||
/// </summary>
|
||||
public class Tiger128_4 : TigerHashBase
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 128;
|
||||
|
||||
public Tiger128_4() : base()
|
||||
{
|
||||
_passes = 4;
|
||||
_padStart = 0x01;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
byte[] hash = base.HashFinal();
|
||||
byte[] trimmedHash = new byte[16];
|
||||
Array.Copy(hash, trimmedHash, 16);
|
||||
return trimmedHash;
|
||||
}
|
||||
}
|
||||
}
|
||||
28
SabreTools.Hashing/CryptographicHash/Tiger160_3.cs
Normal file
28
SabreTools.Hashing/CryptographicHash/Tiger160_3.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
|
||||
namespace SabreTools.Hashing.CryptographicHash
|
||||
{
|
||||
/// <summary>
|
||||
/// 3-pass variant of Tiger-160
|
||||
/// </summary>
|
||||
public class Tiger160_3 : TigerHashBase
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 160;
|
||||
|
||||
public Tiger160_3() : base()
|
||||
{
|
||||
_passes = 3;
|
||||
_padStart = 0x01;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
byte[] hash = base.HashFinal();
|
||||
byte[] trimmedHash = new byte[20];
|
||||
Array.Copy(hash, trimmedHash, 20);
|
||||
return trimmedHash;
|
||||
}
|
||||
}
|
||||
}
|
||||
28
SabreTools.Hashing/CryptographicHash/Tiger160_4.cs
Normal file
28
SabreTools.Hashing/CryptographicHash/Tiger160_4.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
|
||||
namespace SabreTools.Hashing.CryptographicHash
|
||||
{
|
||||
/// <summary>
|
||||
/// 4-pass variant of Tiger-160
|
||||
/// </summary>
|
||||
public class Tiger160_4 : TigerHashBase
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 160;
|
||||
|
||||
public Tiger160_4() : base()
|
||||
{
|
||||
_passes = 4;
|
||||
_padStart = 0x01;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
byte[] hash = base.HashFinal();
|
||||
byte[] trimmedHash = new byte[20];
|
||||
Array.Copy(hash, trimmedHash, 20);
|
||||
return trimmedHash;
|
||||
}
|
||||
}
|
||||
}
|
||||
17
SabreTools.Hashing/CryptographicHash/Tiger192_3.cs
Normal file
17
SabreTools.Hashing/CryptographicHash/Tiger192_3.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
namespace SabreTools.Hashing.CryptographicHash
|
||||
{
|
||||
/// <summary>
|
||||
/// 3-pass variant of Tiger-192
|
||||
/// </summary>
|
||||
public class Tiger192_3 : TigerHashBase
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 192;
|
||||
|
||||
public Tiger192_3() : base()
|
||||
{
|
||||
_passes = 3;
|
||||
_padStart = 0x01;
|
||||
}
|
||||
}
|
||||
}
|
||||
17
SabreTools.Hashing/CryptographicHash/Tiger192_4.cs
Normal file
17
SabreTools.Hashing/CryptographicHash/Tiger192_4.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
namespace SabreTools.Hashing.CryptographicHash
|
||||
{
|
||||
/// <summary>
|
||||
/// 4-pass variant of Tiger-192
|
||||
/// </summary>
|
||||
public class Tiger192_4 : TigerHashBase
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 192;
|
||||
|
||||
public Tiger192_4() : base()
|
||||
{
|
||||
_passes = 4;
|
||||
_padStart = 0x01;
|
||||
}
|
||||
}
|
||||
}
|
||||
28
SabreTools.Hashing/CryptographicHash/Tiger2_128_3.cs
Normal file
28
SabreTools.Hashing/CryptographicHash/Tiger2_128_3.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
|
||||
namespace SabreTools.Hashing.CryptographicHash
|
||||
{
|
||||
/// <summary>
|
||||
/// 3-pass variant of Tiger2-128
|
||||
/// </summary>
|
||||
public class Tiger2_128_3 : TigerHashBase
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 128;
|
||||
|
||||
public Tiger2_128_3() : base()
|
||||
{
|
||||
_passes = 3;
|
||||
_padStart = 0x80;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
byte[] hash = base.HashFinal();
|
||||
byte[] trimmedHash = new byte[16];
|
||||
Array.Copy(hash, trimmedHash, 16);
|
||||
return trimmedHash;
|
||||
}
|
||||
}
|
||||
}
|
||||
28
SabreTools.Hashing/CryptographicHash/Tiger2_128_4.cs
Normal file
28
SabreTools.Hashing/CryptographicHash/Tiger2_128_4.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
|
||||
namespace SabreTools.Hashing.CryptographicHash
|
||||
{
|
||||
/// <summary>
|
||||
/// 4-pass variant of Tiger2-128
|
||||
/// </summary>
|
||||
public class Tiger2_128_4 : TigerHashBase
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 128;
|
||||
|
||||
public Tiger2_128_4() : base()
|
||||
{
|
||||
_passes = 4;
|
||||
_padStart = 0x80;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
byte[] hash = base.HashFinal();
|
||||
byte[] trimmedHash = new byte[16];
|
||||
Array.Copy(hash, trimmedHash, 16);
|
||||
return trimmedHash;
|
||||
}
|
||||
}
|
||||
}
|
||||
28
SabreTools.Hashing/CryptographicHash/Tiger2_160_3.cs
Normal file
28
SabreTools.Hashing/CryptographicHash/Tiger2_160_3.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
|
||||
namespace SabreTools.Hashing.CryptographicHash
|
||||
{
|
||||
/// <summary>
|
||||
/// 3-pass variant of Tiger2-160
|
||||
/// </summary>
|
||||
public class Tiger2_160_3 : TigerHashBase
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 160;
|
||||
|
||||
public Tiger2_160_3() : base()
|
||||
{
|
||||
_passes = 3;
|
||||
_padStart = 0x80;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
byte[] hash = base.HashFinal();
|
||||
byte[] trimmedHash = new byte[20];
|
||||
Array.Copy(hash, trimmedHash, 20);
|
||||
return trimmedHash;
|
||||
}
|
||||
}
|
||||
}
|
||||
28
SabreTools.Hashing/CryptographicHash/Tiger2_160_4.cs
Normal file
28
SabreTools.Hashing/CryptographicHash/Tiger2_160_4.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
|
||||
namespace SabreTools.Hashing.CryptographicHash
|
||||
{
|
||||
/// <summary>
|
||||
/// 4-pass variant of Tiger2-160
|
||||
/// </summary>
|
||||
public class Tiger2_160_4 : TigerHashBase
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 160;
|
||||
|
||||
public Tiger2_160_4() : base()
|
||||
{
|
||||
_passes = 4;
|
||||
_padStart = 0x80;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
byte[] hash = base.HashFinal();
|
||||
byte[] trimmedHash = new byte[20];
|
||||
Array.Copy(hash, trimmedHash, 20);
|
||||
return trimmedHash;
|
||||
}
|
||||
}
|
||||
}
|
||||
17
SabreTools.Hashing/CryptographicHash/Tiger2_192_3.cs
Normal file
17
SabreTools.Hashing/CryptographicHash/Tiger2_192_3.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
namespace SabreTools.Hashing.CryptographicHash
|
||||
{
|
||||
/// <summary>
|
||||
/// 3-pass variant of Tiger2-192
|
||||
/// </summary>
|
||||
public class Tiger2_192_3 : TigerHashBase
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 192;
|
||||
|
||||
public Tiger2_192_3() : base()
|
||||
{
|
||||
_passes = 3;
|
||||
_padStart = 0x80;
|
||||
}
|
||||
}
|
||||
}
|
||||
17
SabreTools.Hashing/CryptographicHash/Tiger2_192_4.cs
Normal file
17
SabreTools.Hashing/CryptographicHash/Tiger2_192_4.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
namespace SabreTools.Hashing.CryptographicHash
|
||||
{
|
||||
/// <summary>
|
||||
/// 4-pass variant of Tiger2-192
|
||||
/// </summary>
|
||||
public class Tiger2_192_4 : TigerHashBase
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 192;
|
||||
|
||||
public Tiger2_192_4() : base()
|
||||
{
|
||||
_passes = 4;
|
||||
_padStart = 0x80;
|
||||
}
|
||||
}
|
||||
}
|
||||
237
SabreTools.Hashing/CryptographicHash/TigerHashBase.cs
Normal file
237
SabreTools.Hashing/CryptographicHash/TigerHashBase.cs
Normal file
@@ -0,0 +1,237 @@
|
||||
using System;
|
||||
using static SabreTools.Hashing.CryptographicHash.Constants;
|
||||
using static SabreTools.Hashing.HashOperations;
|
||||
|
||||
namespace SabreTools.Hashing.CryptographicHash
|
||||
{
|
||||
/// <see href="https://biham.cs.technion.ac.il/Reports/Tiger//>
|
||||
public abstract class TigerHashBase : MessageDigestBase<ulong>
|
||||
{
|
||||
/// <summary>
|
||||
/// Number of passes (minimum 3)
|
||||
/// </summary>
|
||||
protected int _passes;
|
||||
|
||||
/// <summary>
|
||||
/// Byte to start padding with
|
||||
/// </summary>
|
||||
protected byte _padStart;
|
||||
|
||||
/// <summary>
|
||||
/// Set of 3 64-bit numbers representing the hash state
|
||||
/// </summary>
|
||||
private readonly ulong[] _state = new ulong[3];
|
||||
|
||||
public TigerHashBase() : base()
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void ResetImpl()
|
||||
{
|
||||
_state[0] = TigerSeedA;
|
||||
_state[1] = TigerSeedB;
|
||||
_state[2] = TigerSeedC;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void HashCore(byte[] data, int offset, int length)
|
||||
{
|
||||
// Figure out how much buffer is needed
|
||||
int bufferLen = (int)(_totalBytes & 0x3f);
|
||||
|
||||
// Increment the processed byte count
|
||||
_totalBytes += length;
|
||||
|
||||
// If there is buffer to fill and it will meet the limit
|
||||
if (bufferLen > 0 && bufferLen + length >= 64)
|
||||
{
|
||||
// Fill the buffer from the input
|
||||
Array.Copy(data, offset, _buffer, bufferLen, 64 - bufferLen);
|
||||
|
||||
// Set the new values
|
||||
offset += 64 - bufferLen;
|
||||
length -= 64 - bufferLen;
|
||||
|
||||
// Split the buffer for the round
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
_block[i] = ReadLE64(_buffer, i * 8);
|
||||
}
|
||||
|
||||
// Run the round
|
||||
Compress();
|
||||
bufferLen = 0;
|
||||
}
|
||||
|
||||
/// Process any standalone blocks
|
||||
while (length >= 64)
|
||||
{
|
||||
// Fill the buffer from the input
|
||||
Array.Copy(data, offset, _buffer, 0, 64);
|
||||
|
||||
// Set the new values
|
||||
offset += 64;
|
||||
length -= 64;
|
||||
|
||||
// Split the buffer for the round
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
_block[i] = ReadLE64(_buffer, i * 8);
|
||||
}
|
||||
|
||||
// Run the round
|
||||
Compress();
|
||||
}
|
||||
|
||||
// Save the remainder in the buffer
|
||||
if (length > 0)
|
||||
Array.Copy(data, offset, _buffer, bufferLen, length);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
// Determine the pad length
|
||||
int padLength = 64 - (int)(_totalBytes & 0x3f);
|
||||
if (padLength <= 8)
|
||||
padLength += 64;
|
||||
|
||||
// Get the total byte count in bits
|
||||
long totalBitCount = _totalBytes * 8;
|
||||
|
||||
// Prebuild the padding
|
||||
var padding = new byte[padLength];
|
||||
padding[0] = _padStart;
|
||||
padding[padLength - 1] = (byte)((totalBitCount >> 56) & 0xff);
|
||||
padding[padLength - 2] = (byte)((totalBitCount >> 48) & 0xff);
|
||||
padding[padLength - 3] = (byte)((totalBitCount >> 40) & 0xff);
|
||||
padding[padLength - 4] = (byte)((totalBitCount >> 32) & 0xff);
|
||||
padding[padLength - 5] = (byte)((totalBitCount >> 24) & 0xff);
|
||||
padding[padLength - 6] = (byte)((totalBitCount >> 16) & 0xff);
|
||||
padding[padLength - 7] = (byte)((totalBitCount >> 8) & 0xff);
|
||||
padding[padLength - 8] = (byte)((totalBitCount >> 0) & 0xff);
|
||||
|
||||
// Pad the block
|
||||
HashCore(padding, 0, padding.Length);
|
||||
|
||||
// Get the hash
|
||||
var hash = new byte[24];
|
||||
int hashOffset = 0;
|
||||
|
||||
// Assemble the hash array
|
||||
for (int i = 0; i < _state.Length; i++)
|
||||
{
|
||||
byte[] segment = BitConverter.GetBytes(_state[i]);
|
||||
Array.Copy(segment, 0, hash, hashOffset, 8);
|
||||
hashOffset += 8;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform one round of updates on the cached values
|
||||
/// </summary>
|
||||
private void Compress()
|
||||
{
|
||||
// Save current values [save_abc]
|
||||
ulong aa = _state[0];
|
||||
ulong bb = _state[1];
|
||||
ulong cc = _state[2];
|
||||
|
||||
// Pass 1 [pass(a, b, c, 5)]
|
||||
Pass(ref _state[0], ref _state[1], ref _state[2], 5);
|
||||
|
||||
// Avalanche [key_schedule]
|
||||
KeySchedule();
|
||||
|
||||
// Pass 2 [pass(c, a, b, 7)]
|
||||
Pass(ref _state[2], ref _state[0], ref _state[1], 7);
|
||||
|
||||
// Avalanche [key_schedule]
|
||||
KeySchedule();
|
||||
|
||||
// Pass 3 [pass(b, c, a, 9)]
|
||||
Pass(ref _state[1], ref _state[2], ref _state[0], 9);
|
||||
|
||||
// Perform correct set of extra passes
|
||||
for (int pass_no = 3; pass_no < _passes; pass_no++)
|
||||
{
|
||||
// Avalanche [key_schedule]
|
||||
KeySchedule();
|
||||
|
||||
// Pass N [pass(a, b, c, 9)]
|
||||
Pass(ref _state[0], ref _state[1], ref _state[2], 9);
|
||||
|
||||
// Rotate
|
||||
ulong tmpa = _state[0];
|
||||
_state[0] = _state[2];
|
||||
_state[2] = _state[1];
|
||||
_state[1] = tmpa;
|
||||
}
|
||||
|
||||
// Update stored values [feedforward]
|
||||
_state[0] ^= aa;
|
||||
_state[1] -= bb;
|
||||
_state[2] += cc;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// pass(a,b,c,mul)
|
||||
/// </summary>
|
||||
private void Pass(ref ulong a, ref ulong b, ref ulong c, int mul)
|
||||
{
|
||||
Round(ref a, ref b, ref c, _block[0], mul);
|
||||
Round(ref b, ref c, ref a, _block[1], mul);
|
||||
Round(ref c, ref a, ref b, _block[2], mul);
|
||||
Round(ref a, ref b, ref c, _block[3], mul);
|
||||
Round(ref b, ref c, ref a, _block[4], mul);
|
||||
Round(ref c, ref a, ref b, _block[5], mul);
|
||||
Round(ref a, ref b, ref c, _block[6], mul);
|
||||
Round(ref b, ref c, ref a, _block[7], mul);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// round(a,b,c,x,mul)
|
||||
/// </summary>
|
||||
private static void Round(ref ulong a, ref ulong b, ref ulong c, ulong x, int mul)
|
||||
{
|
||||
c ^= x;
|
||||
|
||||
a -= TigerSBox[((c >> (0 * 8)) & 0xFF) + (0 * 256)]
|
||||
^ TigerSBox[((c >> (2 * 8)) & 0xFF) + (1 * 256)]
|
||||
^ TigerSBox[((c >> (4 * 8)) & 0xFF) + (2 * 256)]
|
||||
^ TigerSBox[((c >> (6 * 8)) & 0xFF) + (3 * 256)];
|
||||
b += TigerSBox[((c >> (1 * 8)) & 0xFF) + (3 * 256)]
|
||||
^ TigerSBox[((c >> (3 * 8)) & 0xFF) + (2 * 256)]
|
||||
^ TigerSBox[((c >> (5 * 8)) & 0xFF) + (1 * 256)]
|
||||
^ TigerSBox[((c >> (7 * 8)) & 0xFF) + (0 * 256)];
|
||||
|
||||
unchecked { b *= (ulong)mul; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// key_schedule
|
||||
/// </summary>
|
||||
private void KeySchedule()
|
||||
{
|
||||
_block[0] -= _block[7] ^ 0xA5A5A5A5A5A5A5A5;
|
||||
_block[1] ^= _block[0];
|
||||
_block[2] += _block[1];
|
||||
_block[3] -= _block[2] ^ ((~_block[1]) << 19);
|
||||
_block[4] ^= _block[3];
|
||||
_block[5] += _block[4];
|
||||
_block[6] -= _block[5] ^ ((~_block[4]) >> 23);
|
||||
_block[7] ^= _block[6];
|
||||
_block[0] += _block[7];
|
||||
_block[1] -= _block[0] ^ ((~_block[7]) << 19);
|
||||
_block[2] ^= _block[1];
|
||||
_block[3] += _block[2];
|
||||
_block[4] -= _block[3] ^ ((~_block[2]) >> 23);
|
||||
_block[5] ^= _block[4];
|
||||
_block[6] += _block[5];
|
||||
_block[7] -= _block[6] ^ 0x0123456789ABCDEF;
|
||||
}
|
||||
}
|
||||
}
|
||||
9
SabreTools.Hashing/ExtensionAttribute.cs
Normal file
9
SabreTools.Hashing/ExtensionAttribute.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
#if NET20
|
||||
|
||||
namespace System.Runtime.CompilerServices
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method)]
|
||||
internal sealed class ExtensionAttribute : Attribute {}
|
||||
}
|
||||
|
||||
#endif
|
||||
447
SabreTools.Hashing/Extensions.cs
Normal file
447
SabreTools.Hashing/Extensions.cs
Normal file
@@ -0,0 +1,447 @@
|
||||
namespace SabreTools.Hashing
|
||||
{
|
||||
public static class Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the name of a given hash type, if possible
|
||||
/// </summary>
|
||||
/// TODO: This should be automated instead of hardcoded
|
||||
public static string? GetHashName(this HashType hashType)
|
||||
{
|
||||
return hashType switch
|
||||
{
|
||||
HashType.Adler32 => "Mark Adler's 32-bit checksum",
|
||||
|
||||
#if NET7_0_OR_GREATER
|
||||
HashType.BLAKE3 => "BLAKE3 512-bit digest",
|
||||
#endif
|
||||
|
||||
HashType.CRC1_ZERO => "CRC-1/ZERO [Parity bit with 0 start]",
|
||||
HashType.CRC1_ONE => "CRC-1/ONE [Parity bit with 1 start]",
|
||||
|
||||
HashType.CRC3_GSM => "CRC-3/GSM",
|
||||
HashType.CRC3_ROHC => "CRC-3/ROHC",
|
||||
|
||||
HashType.CRC4_G704 => "CRC-4/G-704 [CRC-4/ITU]",
|
||||
HashType.CRC4_INTERLAKEN => "CRC-4/INTERLAKEN",
|
||||
|
||||
HashType.CRC5_EPCC1G2 => "CRC-5/EPC-C1G2 [CRC-5/EPC]",
|
||||
HashType.CRC5_G704 => "CRC-5/G-704 [CRC-5/ITU]",
|
||||
HashType.CRC5_USB => "CRC-5/USB",
|
||||
|
||||
HashType.CRC6_CDMA2000A => "CRC-6/CDMA2000-A",
|
||||
HashType.CRC6_CDMA2000B => "CRC-6/CDMA2000-B",
|
||||
HashType.CRC6_DARC => "CRC-6/DARC",
|
||||
HashType.CRC6_G704 => "CRC-6/G-704 [CRC-6/ITU]",
|
||||
HashType.CRC6_GSM => "CRC-6/GSM",
|
||||
|
||||
HashType.CRC7_MMC => "CRC-7/MMC [CRC-7]",
|
||||
HashType.CRC7_ROHC => "CRC-7/ROHC",
|
||||
HashType.CRC7_UMTS => "CRC-7/UMTS",
|
||||
|
||||
HashType.CRC8 => "CRC-8",
|
||||
HashType.CRC8_AUTOSAR => "CRC-8/AUTOSAR",
|
||||
HashType.CRC8_BLUETOOTH => "CRC-8/BLUETOOTH",
|
||||
HashType.CRC8_CDMA2000 => "CRC-8/CDMA2000",
|
||||
HashType.CRC8_DARC => "CRC-8/DARC",
|
||||
HashType.CRC8_DVBS2 => "CRC-8/DVB-S2",
|
||||
HashType.CRC8_GSMA => "CRC-8/GSM-A",
|
||||
HashType.CRC8_GSMB => "CRC-8/GSM-B",
|
||||
HashType.CRC8_HITAG => "CRC-8/HITAG",
|
||||
HashType.CRC8_I4321 => "CRC-8/I-432-1 [CRC-8/ITU]",
|
||||
HashType.CRC8_ICODE => "CRC-8/I-CODE",
|
||||
HashType.CRC8_LTE => "CRC-8/LTE",
|
||||
HashType.CRC8_MAXIMDOW => "CRC-8/MAXIM-DOW [CRC-8/MAXIM, DOW-CRC]",
|
||||
HashType.CRC8_MIFAREMAD => "CRC-8/MIFARE-MAD",
|
||||
HashType.CRC8_NRSC5 => "CRC-8/NRSC-5",
|
||||
HashType.CRC8_OPENSAFETY => "CRC-8/OPENSAFETY",
|
||||
HashType.CRC8_ROHC => "CRC-8/ROHC",
|
||||
HashType.CRC8_SAEJ1850 => "CRC-8/SAE-J1850",
|
||||
HashType.CRC8_SMBUS => "CRC-8/SMBUS [CRC-8]",
|
||||
HashType.CRC8_TECH3250 => "CRC-8/TECH-3250 [CRC-8/AES, CRC-8/EBU]",
|
||||
HashType.CRC8_WCDMA => "CRC-8/WCDMA",
|
||||
|
||||
HashType.CRC10_ATM => "CRC-10/ATM [CRC-10, CRC-10/I-610]",
|
||||
HashType.CRC10_CDMA2000 => "CRC-10/CDMA2000",
|
||||
HashType.CRC10_GSM => "CRC-10/GSM",
|
||||
|
||||
HashType.CRC11_FLEXRAY => "CRC-11/FLEXRAY [CRC-11]",
|
||||
HashType.CRC11_UMTS => "CRC-11/UMTS",
|
||||
|
||||
HashType.CRC12_CDMA2000 => "CRC-12/CDMA2000",
|
||||
HashType.CRC12_DECT => "CRC-12/DECT [X-CRC-12]",
|
||||
HashType.CRC12_GSM => "CRC-12/GSM",
|
||||
HashType.CRC12_UMTS => "CRC-12/UMTS [CRC-12/3GPP]",
|
||||
|
||||
HashType.CRC13_BBC => "CRC-13/BBC",
|
||||
|
||||
HashType.CRC14_DARC => "CRC-14/DARC",
|
||||
HashType.CRC14_GSM => "CRC-14/GSM",
|
||||
|
||||
HashType.CRC15_CAN => "CRC-15/CAN [CRC-15]",
|
||||
HashType.CRC15_MPT1327 => "CRC-15/MPT1327",
|
||||
|
||||
HashType.CRC16 => "CRC-16",
|
||||
HashType.CRC16_ARC => "CRC-16/ARC [ARC, CRC-16, CRC-16/LHA, CRC-IBM]",
|
||||
HashType.CRC16_CDMA2000 => "CRC-16/CDMA2000",
|
||||
HashType.CRC16_CMS => "CRC-16/CMS",
|
||||
HashType.CRC16_DDS110 => "CRC-16/DDS-110",
|
||||
HashType.CRC16_DECTR => "CRC-16/DECT-R [R-CRC-16]",
|
||||
HashType.CRC16_DECTX => "CRC-16/DECT-X [X-CRC-16]",
|
||||
HashType.CRC16_DNP => "CRC-16/DNP",
|
||||
HashType.CRC16_EN13757 => "CRC-16/EN-13757",
|
||||
HashType.CRC16_GENIBUS => "CRC-16/GENIBUS [CRC-16/DARC, CRC-16/EPC, CRC-16/EPC-C1G2, CRC-16/I-CODE]",
|
||||
HashType.CRC16_GSM => "CRC-16/GSM",
|
||||
HashType.CRC16_IBM3740 => "CRC-16/IBM-3740 [CRC-16/AUTOSAR, CRC-16/CCITT-FALSE]",
|
||||
HashType.CRC16_IBMSDLC => "CRC-16/IBM-SDLC [CRC-16/ISO-HDLC, CRC-16/ISO-IEC-14443-3-B, CRC-16/X-25, CRC-B, X-25]",
|
||||
HashType.CRC16_ISOIEC144433A => "CRC-16/ISO-IEC-14443-3-A [CRC-A]",
|
||||
HashType.CRC16_KERMIT => "CRC-16/KERMIT [CRC-16/BLUETOOTH, CRC-16/CCITT, CRC-16/CCITT-TRUE, CRC-16/V-41-LSB, CRC-CCITT, KERMIT]",
|
||||
HashType.CRC16_LJ1200 => "CRC-16/LJ1200",
|
||||
HashType.CRC16_M17 => "CRC-16/M17",
|
||||
HashType.CRC16_MAXIMDOW => "CRC-16/MAXIM-DOW [CRC-16/MAXIM]",
|
||||
HashType.CRC16_MCRF4XX => "CRC-16/MCRF4XX",
|
||||
HashType.CRC16_MODBUS => "CRC-16/MODBUS [MODBUS]",
|
||||
HashType.CRC16_NRSC5 => "CRC-16/NRSC-5",
|
||||
HashType.CRC16_OPENSAFETYA => "CRC-16/OPENSAFETY-A",
|
||||
HashType.CRC16_OPENSAFETYB => "CRC-16/OPENSAFETY-B",
|
||||
HashType.CRC16_PROFIBUS => "CRC-16/PROFIBUS [CRC-16/IEC-61158-2]",
|
||||
HashType.CRC16_RIELLO => "CRC-16/RIELLO",
|
||||
HashType.CRC16_SPIFUJITSU => "CRC-16/SPI-FUJITSU [CRC-16/AUG-CCITT]",
|
||||
HashType.CRC16_T10DIF => "CRC-16/T10-DIF",
|
||||
HashType.CRC16_TELEDISK => "CRC-16/TELEDISK",
|
||||
HashType.CRC16_TMS37157 => "CRC-16/TMS37157",
|
||||
HashType.CRC16_UMTS => "CRC-16/UMTS [CRC-16/BUYPASS, CRC-16/VERIFONE]",
|
||||
HashType.CRC16_USB => "CRC-16/USB",
|
||||
HashType.CRC16_XMODEM => "CRC-16/XMODEM [CRC-16/ACORN, CRC-16/LTE, CRC-16/V-41-MSB, XMODEM, ZMODEM]",
|
||||
|
||||
HashType.CRC17_CANFD => "CRC-17/CAN-FD",
|
||||
|
||||
HashType.CRC21_CANFD => "CRC-21/CAN-FD",
|
||||
|
||||
HashType.CRC24_BLE => "CRC-24/BLE",
|
||||
HashType.CRC24_FLEXRAYA => "CRC-24/FLEXRAY-A",
|
||||
HashType.CRC24_FLEXRAYB => "CRC-24/FLEXRAY-B",
|
||||
HashType.CRC24_INTERLAKEN => "CRC-24/INTERLAKEN",
|
||||
HashType.CRC24_LTEA => "CRC-24/LTE-A",
|
||||
HashType.CRC24_LTEB => "CRC-24/LTE-B",
|
||||
HashType.CRC24_OPENPGP => "CRC-24/OPENPGP",
|
||||
HashType.CRC24_OS9 => "CRC-24/OS-9",
|
||||
|
||||
HashType.CRC30_CDMA => "CRC-30/CDMA",
|
||||
|
||||
HashType.CRC31_PHILIPS => "CRC-31/PHILIPS",
|
||||
|
||||
HashType.CRC32 => "CRC-32",
|
||||
HashType.CRC32_AIXM => "CRC-32/AIXM",
|
||||
HashType.CRC32_AUTOSAR => "CRC-32/AUTOSAR",
|
||||
HashType.CRC32_BASE91D => "CRC-32/BASE91-D",
|
||||
HashType.CRC32_BZIP2 => "BZIP2",
|
||||
HashType.CRC32_CDROMEDC => "CRC-32/CD-ROM-EDC",
|
||||
HashType.CRC32_CKSUM => "CRC-32/CKSUM",
|
||||
HashType.CRC32_DVDROMEDC => "CRC-32/DVD-ROM-EDC",
|
||||
HashType.CRC32_ISCSI => "CRC-32/ISCSI",
|
||||
HashType.CRC32_ISOHDLC => "CRC-32/ISO-HDLC",
|
||||
HashType.CRC32_JAMCRC => "CRC-32/JAMCRC",
|
||||
HashType.CRC32_MEF => "CRC-32/MEF",
|
||||
HashType.CRC32_MPEG2 => "CRC-32/MPEG-2",
|
||||
HashType.CRC32_XFER => "CRC-32/XFER",
|
||||
|
||||
HashType.CRC40_GSM => "CRC-40/GSM",
|
||||
|
||||
HashType.CRC64 => "CRC-64",
|
||||
HashType.CRC64_ECMA182 => "CRC-64/ECMA-182, Microsoft implementation",
|
||||
HashType.CRC64_GOISO => "CRC-64/GO-ISO",
|
||||
HashType.CRC64_MS => "CRC-64/MS",
|
||||
HashType.CRC64_NVME => "CRC-64/NVME",
|
||||
HashType.CRC64_REDIS => "CRC-64/REDIS",
|
||||
HashType.CRC64_WE => "CRC-64/WE",
|
||||
HashType.CRC64_XZ => "CRC-64/XZ",
|
||||
|
||||
HashType.Fletcher16 => "John G. Fletcher's 16-bit checksum",
|
||||
HashType.Fletcher32 => "John G. Fletcher's 32-bit checksum",
|
||||
HashType.Fletcher64 => "John G. Fletcher's 64-bit checksum",
|
||||
|
||||
HashType.FNV0_32 => "FNV hash (Variant 0, 32-bit)",
|
||||
HashType.FNV0_64 => "FNV hash (Variant 0, 64-bit)",
|
||||
HashType.FNV1_32 => "FNV hash (Variant 1, 32-bit)",
|
||||
HashType.FNV1_64 => "FNV hash (Variant 1, 64-bit)",
|
||||
HashType.FNV1a_32 => "FNV hash (Variant 1a, 32-bit)",
|
||||
HashType.FNV1a_64 => "FNV hash (Variant 1a, 64-bit)",
|
||||
|
||||
HashType.MekaCrc => "Custom MEKA checksum",
|
||||
|
||||
HashType.MD2 => "MD2 message-digest algorithm",
|
||||
HashType.MD4 => "MD4 message-digest algorithm",
|
||||
HashType.MD5 => "MD5 message-digest algorithm",
|
||||
|
||||
HashType.RIPEMD128 => "RIPEMD-128 hash",
|
||||
HashType.RIPEMD160 => "RIPEMD-160 hash",
|
||||
HashType.RIPEMD256 => "RIPEMD-256 hash",
|
||||
HashType.RIPEMD320 => "RIPEMD-320 hash",
|
||||
|
||||
HashType.SHA1 => "SHA-1 hash",
|
||||
HashType.SHA256 => "SHA-256 hash",
|
||||
HashType.SHA384 => "SHA-384 hash",
|
||||
HashType.SHA512 => "SHA-512 hash",
|
||||
#if NET8_0_OR_GREATER
|
||||
HashType.SHA3_256 => "SHA3-256 hash",
|
||||
HashType.SHA3_384 => "SHA3-384 hash",
|
||||
HashType.SHA3_512 => "SHA3-512 hash",
|
||||
HashType.SHAKE128 => "SHAKE128 SHA-3 family hash (256-bit)",
|
||||
HashType.SHAKE256 => "SHAKE256 SHA-3 family hash (512-bit)",
|
||||
#endif
|
||||
|
||||
HashType.SpamSum => "spamsum fuzzy hash",
|
||||
|
||||
HashType.Tiger128_3 => "Tiger 128-bit hash, 3 passes",
|
||||
HashType.Tiger128_4 => "Tiger 128-bit hash, 4 passes",
|
||||
HashType.Tiger160_3 => "Tiger 160-bit hash, 3 passes",
|
||||
HashType.Tiger160_4 => "Tiger 160-bit hash, 4 passes",
|
||||
HashType.Tiger192_3 => "Tiger 192-bit hash, 3 passes",
|
||||
HashType.Tiger192_4 => "Tiger 192-bit hash, 4 passes",
|
||||
HashType.Tiger2_128_3 => "Tiger2 128-bit hash, 3 passes",
|
||||
HashType.Tiger2_128_4 => "Tiger2 128-bit hash, 4 passes",
|
||||
HashType.Tiger2_160_3 => "Tiger2 160-bit hash, 3 passes",
|
||||
HashType.Tiger2_160_4 => "Tiger2 160-bit hash, 4 passes",
|
||||
HashType.Tiger2_192_3 => "Tiger2 192-bit hash, 3 passes",
|
||||
HashType.Tiger2_192_4 => "Tiger2 192-bit hash, 4 passes",
|
||||
|
||||
HashType.XxHash32 => "xxHash32 hash",
|
||||
HashType.XxHash64 => "xxHash64 hash",
|
||||
#if NET462_OR_GREATER || NETCOREAPP
|
||||
HashType.XxHash3 => "XXH3 64-bit hash",
|
||||
HashType.XxHash128 => "XXH128 128-bit hash",
|
||||
#endif
|
||||
|
||||
_ => $"{hashType}",
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the hash type associated to a string, if possible
|
||||
/// </summary>
|
||||
/// TODO: This should be automated instead of hardcoded
|
||||
public static HashType? GetHashType(this string? str)
|
||||
{
|
||||
// Ignore invalid strings
|
||||
if (string.IsNullOrEmpty(str))
|
||||
return null;
|
||||
|
||||
// Normalize the string before matching
|
||||
str = str!.Replace("-", string.Empty);
|
||||
str = str.Replace(" ", string.Empty);
|
||||
str = str.Replace("/", "_");
|
||||
str = str.Replace("\\", "_");
|
||||
str = str.ToLowerInvariant();
|
||||
|
||||
// Match based on potential names
|
||||
return str switch
|
||||
{
|
||||
"adler" or "adler32" => HashType.Adler32,
|
||||
|
||||
#if NET7_0_OR_GREATER
|
||||
"blake3" => HashType.BLAKE3,
|
||||
#endif
|
||||
|
||||
"crc1_0" or "crc1_zero" => HashType.CRC1_ZERO,
|
||||
"crc1_1" or "crc1_one" => HashType.CRC1_ONE,
|
||||
|
||||
"crc3_gsm" => HashType.CRC3_GSM,
|
||||
"crc3_rohc" => HashType.CRC3_ROHC,
|
||||
|
||||
"crc4_g704" or "crc4_itu" => HashType.CRC4_G704,
|
||||
"crc4_interlaken" => HashType.CRC4_INTERLAKEN,
|
||||
|
||||
"crc5_epc" or "crc5_epcc1g2" => HashType.CRC5_EPCC1G2,
|
||||
"crc5_g704" or "crc5_itu" => HashType.CRC5_G704,
|
||||
"crc5_usb" => HashType.CRC5_USB,
|
||||
|
||||
"crc6_cdma2000a" => HashType.CRC6_CDMA2000A,
|
||||
"crc6_cdma2000b" => HashType.CRC6_CDMA2000B,
|
||||
"crc6_darc" => HashType.CRC6_DARC,
|
||||
"crc6_g704" or "crc6_itu" => HashType.CRC6_G704,
|
||||
"crc6_gsm" => HashType.CRC6_GSM,
|
||||
|
||||
"crc7" or "crc7_mmc" => HashType.CRC7_MMC,
|
||||
"crc7_rohc" => HashType.CRC7_ROHC,
|
||||
"crc7_umts" => HashType.CRC7_UMTS,
|
||||
|
||||
"crc8" => HashType.CRC8,
|
||||
"crc8_autosar" => HashType.CRC8_AUTOSAR,
|
||||
"crc8_bluetooth" => HashType.CRC8_BLUETOOTH,
|
||||
"crc8_cdma2000" => HashType.CRC8_CDMA2000,
|
||||
"crc8_darc" => HashType.CRC8_DARC,
|
||||
"crc8_dvbs2" => HashType.CRC8_DVBS2,
|
||||
"crc8_gsma" => HashType.CRC8_GSMA,
|
||||
"crc8_gsmb" => HashType.CRC8_GSMB,
|
||||
"crc8_hitag" => HashType.CRC8_HITAG,
|
||||
"crc8_i4321" or "crc8_itu" => HashType.CRC8_I4321,
|
||||
"crc8_icode" => HashType.CRC8_ICODE,
|
||||
"crc8_lte" => HashType.CRC8_LTE,
|
||||
"crc8_maximdow" or "crc8_maxim" or "dowcrc" => HashType.CRC8_MAXIMDOW,
|
||||
"crc8_mifaremad" => HashType.CRC8_MIFAREMAD,
|
||||
"crc8_nrsc5" => HashType.CRC8_NRSC5,
|
||||
"crc8_opensafety" => HashType.CRC8_OPENSAFETY,
|
||||
"crc8_rohc" => HashType.CRC8_ROHC,
|
||||
"crc8_saej1850" => HashType.CRC8_SAEJ1850,
|
||||
"crc8_smbus" => HashType.CRC8_SMBUS,
|
||||
"crc8_tech3250" or "crc8_aes" or "crc8_ebu" => HashType.CRC8_TECH3250,
|
||||
"crc8_wcdma" => HashType.CRC8_WCDMA,
|
||||
|
||||
"crc10_atm" or "crc10" or "crc10_i610" => HashType.CRC10_ATM,
|
||||
"crc10_cdma2000" => HashType.CRC10_CDMA2000,
|
||||
"crc10_gsm" => HashType.CRC10_GSM,
|
||||
|
||||
"crc11_flexray" or "crc11" => HashType.CRC11_FLEXRAY,
|
||||
"crc11_umts" => HashType.CRC11_UMTS,
|
||||
|
||||
"crc12_cdma2000" => HashType.CRC12_CDMA2000,
|
||||
"crc12_dect" or "xcrc12" => HashType.CRC12_DECT,
|
||||
"crc12_gsm" => HashType.CRC12_GSM,
|
||||
"crc12_umts" or "crc12_3gpp" => HashType.CRC12_UMTS,
|
||||
|
||||
"crc13_bbc" => HashType.CRC13_BBC,
|
||||
|
||||
"crc14_darc" => HashType.CRC14_DARC,
|
||||
"crc14_gsm" => HashType.CRC14_GSM,
|
||||
|
||||
"crc15_can" or "crc15" => HashType.CRC15_CAN,
|
||||
"crc15_mpt1327" => HashType.CRC15_MPT1327,
|
||||
|
||||
"crc16" => HashType.CRC16,
|
||||
"crc16_arc" or "arc" or "crc16_lha" or "crcibm" => HashType.CRC16_ARC,
|
||||
"crc16_cdma2000" => HashType.CRC16_CDMA2000,
|
||||
"crc16_cms" => HashType.CRC16_CMS,
|
||||
"crc16_dds110" => HashType.CRC16_DDS110,
|
||||
"crc16_dectr" or "rcrc16" => HashType.CRC16_DECTR,
|
||||
"crc16_dectx" or "xcrc16" => HashType.CRC16_DECTX,
|
||||
"crc16_dnp" => HashType.CRC16_DNP,
|
||||
"crc16_en13757" => HashType.CRC16_EN13757,
|
||||
"crc16_genibus" or "crc16_darc" or "crc16_epc" or "crc16_epcc1g2" or "crc16_icode" => HashType.CRC16_GENIBUS,
|
||||
"crc16_gsm" => HashType.CRC16_GSM,
|
||||
"crc16_ibm3740" or "crc16_autosar" or "crc16_cittfalse" => HashType.CRC16_IBM3740,
|
||||
"crc16_ibmsdlc" or "crc16_isohdlc" or "crc16_isoiec144433b" or "crc16_x25" or "crcb" or "x25" => HashType.CRC16_IBMSDLC,
|
||||
"crc16_isoiec144433a" or "crca" => HashType.CRC16_ISOIEC144433A,
|
||||
"crc16_kermit" or "crc16_bluetooth" or "crc16_ccitt" or "crc16_ccitttrue" or "crc16_v41lsb" or "crcccitt" or "kermit" => HashType.CRC16_KERMIT,
|
||||
"crc16_lj1200" => HashType.CRC16_LJ1200,
|
||||
"crc16_m17" => HashType.CRC16_M17,
|
||||
"crc16_maximdow" or "crc16_maxim" => HashType.CRC16_MAXIMDOW,
|
||||
"crc16_mcrf4xx" => HashType.CRC16_MCRF4XX,
|
||||
"crc16_modbus" or "modbus" => HashType.CRC16_MODBUS,
|
||||
"crc16_nrsc5" => HashType.CRC16_NRSC5,
|
||||
"crc16_opensafetya" => HashType.CRC16_OPENSAFETYA,
|
||||
"crc16_opensafetyb" => HashType.CRC16_OPENSAFETYB,
|
||||
"crc16_profibus" or "crc16_iec611582" => HashType.CRC16_PROFIBUS,
|
||||
"crc16_riello" => HashType.CRC16_RIELLO,
|
||||
"crc16_spifujitsu" or "crc16_augccitt" => HashType.CRC16_SPIFUJITSU,
|
||||
"crc16_t10dif" => HashType.CRC16_T10DIF,
|
||||
"crc16_teledisk" => HashType.CRC16_TELEDISK,
|
||||
"crc16_tms37157" => HashType.CRC16_TMS37157,
|
||||
"crc16_umts" or "crc16_buypass" or "crc16_verifone" => HashType.CRC16_UMTS,
|
||||
"crc16_usb" => HashType.CRC16_USB,
|
||||
"crc16_xmodem" or "crc16_acorn" or "crc16_lte" or "crc16_v41msb" or "xmodem" or "zmodem" => HashType.CRC16_XMODEM,
|
||||
|
||||
"crc17_canfd" => HashType.CRC17_CANFD,
|
||||
|
||||
"crc21_canfd" => HashType.CRC21_CANFD,
|
||||
|
||||
"crc24_ble" => HashType.CRC24_BLE,
|
||||
"crc24_flexraya" => HashType.CRC24_FLEXRAYA,
|
||||
"crc24_flexrayb" => HashType.CRC24_FLEXRAYB,
|
||||
"crc24_interlaken" => HashType.CRC24_INTERLAKEN,
|
||||
"crc24_ltea" => HashType.CRC24_LTEA,
|
||||
"crc24_lteb" => HashType.CRC24_LTEB,
|
||||
"crc24_openpgp" => HashType.CRC24_OPENPGP,
|
||||
"crc24_os9" => HashType.CRC24_OS9,
|
||||
|
||||
"crc30_cdma" => HashType.CRC30_CDMA,
|
||||
|
||||
"crc31_philips" => HashType.CRC31_PHILIPS,
|
||||
|
||||
"crc32" => HashType.CRC32,
|
||||
"crc32_aixm" => HashType.CRC32_AIXM,
|
||||
"crc32_autosar" => HashType.CRC32_AUTOSAR,
|
||||
"crc32_base91d" => HashType.CRC32_BASE91D,
|
||||
"crc32_bzip2" => HashType.CRC32_BZIP2,
|
||||
"crc32_cdromedc" => HashType.CRC32_CDROMEDC,
|
||||
"crc32_cksum" => HashType.CRC32_CKSUM,
|
||||
"crc32_dvdromedc" => HashType.CRC32_DVDROMEDC,
|
||||
"crc32_iscsi" => HashType.CRC32_ISCSI,
|
||||
"crc32_isohdlc" => HashType.CRC32_ISOHDLC,
|
||||
"crc32_jamcrc" => HashType.CRC32_JAMCRC,
|
||||
"crc32_mef" => HashType.CRC32_MEF,
|
||||
"crc32_mpeg2" => HashType.CRC32_MPEG2,
|
||||
"crc32_xfer" => HashType.CRC32_XFER,
|
||||
|
||||
"crc40_gsm" => HashType.CRC40_GSM,
|
||||
|
||||
"crc64" => HashType.CRC64,
|
||||
"crc64_ecma182" => HashType.CRC64_ECMA182,
|
||||
"crc64_goiso" => HashType.CRC64_GOISO,
|
||||
"crc64_ms" => HashType.CRC64_MS,
|
||||
"crc64_nvme" => HashType.CRC64_NVME,
|
||||
"crc64_redis" => HashType.CRC64_REDIS,
|
||||
"crc64_we" => HashType.CRC64_WE,
|
||||
"crc64_xz" => HashType.CRC64_XZ,
|
||||
|
||||
"fletcher16" => HashType.Fletcher16,
|
||||
"fletcher32" => HashType.Fletcher32,
|
||||
"fletcher64" => HashType.Fletcher64,
|
||||
|
||||
"fnv0_32" => HashType.FNV0_32,
|
||||
"fnv0_64" => HashType.FNV0_64,
|
||||
"fnv1_32" => HashType.FNV1_32,
|
||||
"fnv1_64" => HashType.FNV1_64,
|
||||
"fnv1a_32" => HashType.FNV1a_32,
|
||||
"fnv1a_64" => HashType.FNV1a_64,
|
||||
|
||||
"meka" or "mekacrc" or "meka_crc" => HashType.MekaCrc,
|
||||
|
||||
"md2" => HashType.MD2,
|
||||
"md4" => HashType.MD4,
|
||||
"md5" => HashType.MD5,
|
||||
|
||||
"ripemd128" => HashType.RIPEMD128,
|
||||
"ripemd160" => HashType.RIPEMD160,
|
||||
"ripemd256" => HashType.RIPEMD256,
|
||||
"ripemd320" => HashType.RIPEMD320,
|
||||
|
||||
"sha1" => HashType.SHA1,
|
||||
"sha256" => HashType.SHA256,
|
||||
"sha384" => HashType.SHA384,
|
||||
"sha512" => HashType.SHA512,
|
||||
#if NET8_0_OR_GREATER
|
||||
"sha3_256" => HashType.SHA3_256,
|
||||
"sha3_384" => HashType.SHA3_384,
|
||||
"sha3_512" => HashType.SHA3_512,
|
||||
"shake128" => HashType.SHAKE128,
|
||||
"shake256" => HashType.SHAKE256,
|
||||
#endif
|
||||
|
||||
"spamsum" => HashType.SpamSum,
|
||||
|
||||
"tiger128_3" => HashType.Tiger128_3,
|
||||
"tiger128_4" => HashType.Tiger128_4,
|
||||
"tiger160_3" => HashType.Tiger160_3,
|
||||
"tiger160_4" => HashType.Tiger160_4,
|
||||
"tiger192_3" => HashType.Tiger192_3,
|
||||
"tiger192_4" => HashType.Tiger192_4,
|
||||
"tiger2_128_3" => HashType.Tiger2_128_3,
|
||||
"tiger2_128_4" => HashType.Tiger2_128_4,
|
||||
"tiger2_160_3" => HashType.Tiger2_160_3,
|
||||
"tiger2_160_4" => HashType.Tiger2_160_4,
|
||||
"tiger2_192_3" => HashType.Tiger2_192_3,
|
||||
"tiger2_192_4" => HashType.Tiger2_192_4,
|
||||
|
||||
"xxh" or "xxh32" or "xxh_32" or "xxhash" or "xxhash32" or "xxhash_32" => HashType.XxHash32,
|
||||
"xxh64" or "xxh_64" or "xxhash64" or "xxhash_64" => HashType.XxHash64,
|
||||
#if NET462_OR_GREATER || NETCOREAPP
|
||||
"xxh3" or "xxh3_64" or "xxhash3" or "xxhash_3" => HashType.XxHash3,
|
||||
"xxh128" or "xxh_128" or "xxhash128" or "xxhash_128" => HashType.XxHash128,
|
||||
#endif
|
||||
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
181
SabreTools.Hashing/HashOperations.cs
Normal file
181
SabreTools.Hashing/HashOperations.cs
Normal file
@@ -0,0 +1,181 @@
|
||||
using System;
|
||||
|
||||
namespace SabreTools.Hashing
|
||||
{
|
||||
internal static class HashOperations
|
||||
{
|
||||
#region Conversions
|
||||
|
||||
/// <summary>
|
||||
/// Convert a byte array to a hex string
|
||||
/// </summary>
|
||||
/// <param name="bytes">Byte array to convert</param>
|
||||
/// <returns>Hex string representing the byte array</returns>
|
||||
/// <link>http://stackoverflow.com/questions/311165/how-do-you-convert-byte-array-to-hexadecimal-string-and-vice-versa</link>
|
||||
public static string? ByteArrayToString(byte[]? bytes)
|
||||
{
|
||||
// If we get null in, we send null out
|
||||
if (bytes is null)
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
string hex = BitConverter.ToString(bytes);
|
||||
return hex.Replace("-", string.Empty).ToLowerInvariant();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert a byte array to a UInt64
|
||||
/// </summary>
|
||||
/// <param name="bytes">Byte array to convert</param>
|
||||
/// <returns>UInt64 representing the byte array</returns>
|
||||
/// <link>https://stackoverflow.com/questions/66750224/how-to-convert-a-byte-array-of-any-size-to-ulong-in-c</link>
|
||||
public static ulong BytesToUInt64(byte[]? bytes)
|
||||
{
|
||||
// If we get null in, we send 0 out
|
||||
if (bytes is null)
|
||||
return default;
|
||||
|
||||
ulong result = 0;
|
||||
for (int i = 0; i < bytes.Length; i++)
|
||||
{
|
||||
result |= (ulong)bytes[i] << (i * 8);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Read Big-Endian
|
||||
|
||||
/// <summary>
|
||||
/// 32-bit big-endian read
|
||||
/// </summary>
|
||||
public static uint ReadBE32(byte[] data, int offset)
|
||||
{
|
||||
return (uint)(data[offset + 3]
|
||||
| (data[offset + 2] << 8)
|
||||
| (data[offset + 1] << 16)
|
||||
| (data[offset + 0] << 24));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 64-bit big-endian read
|
||||
/// </summary>
|
||||
public static ulong ReadBE64(byte[] data, int offset)
|
||||
{
|
||||
return data[offset + 7]
|
||||
| ((ulong)data[offset + 6] << 8)
|
||||
| ((ulong)data[offset + 5] << 16)
|
||||
| ((ulong)data[offset + 4] << 24)
|
||||
| ((ulong)data[offset + 3] << 32)
|
||||
| ((ulong)data[offset + 2] << 40)
|
||||
| ((ulong)data[offset + 1] << 48)
|
||||
| ((ulong)data[offset + 0] << 56);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Read Litte-Endian
|
||||
|
||||
/// <summary>
|
||||
/// 32-bit little-endian read
|
||||
/// </summary>
|
||||
public static uint ReadLE32(byte[] data, int offset)
|
||||
{
|
||||
return (uint)(data[offset + 0]
|
||||
| (data[offset + 1] << 8)
|
||||
| (data[offset + 2] << 16)
|
||||
| (data[offset + 3] << 24));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 64-bit little-endian read
|
||||
/// </summary>
|
||||
public static ulong ReadLE64(byte[] data, int offset)
|
||||
{
|
||||
return data[offset + 0]
|
||||
| ((ulong)data[offset + 1] << 8)
|
||||
| ((ulong)data[offset + 2] << 16)
|
||||
| ((ulong)data[offset + 3] << 24)
|
||||
| ((ulong)data[offset + 4] << 32)
|
||||
| ((ulong)data[offset + 5] << 40)
|
||||
| ((ulong)data[offset + 6] << 48)
|
||||
| ((ulong)data[offset + 7] << 56);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Reverse
|
||||
|
||||
/// <summary>
|
||||
/// Reverse the endianness of a value
|
||||
/// </summary>
|
||||
public static ulong ReverseBits(ulong value, int bitWidth)
|
||||
{
|
||||
ulong reverse = 0;
|
||||
for (int i = 0; i < bitWidth; i++)
|
||||
{
|
||||
reverse <<= 1;
|
||||
reverse |= value & 1;
|
||||
value >>= 1;
|
||||
}
|
||||
|
||||
return reverse;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Rotate
|
||||
|
||||
/// <summary>
|
||||
/// 32-bit rotate left.
|
||||
/// </summary>
|
||||
public static uint RotateLeft32(uint x, int r)
|
||||
=> (x << r) | (x >> (32 - r));
|
||||
|
||||
/// <summary>
|
||||
/// 64-bit rotate left.
|
||||
/// </summary>
|
||||
public static ulong RotateLeft64(ulong x, int r)
|
||||
=> (x << r) | (x >> (64 - r));
|
||||
|
||||
#endregion
|
||||
|
||||
#region Swap
|
||||
|
||||
/// <summary>
|
||||
/// A 32-bit byteswap.
|
||||
/// </summary>
|
||||
public static uint Swap32(uint x)
|
||||
{
|
||||
return ((x << 24) & 0xff000000)
|
||||
| ((x << 8) & 0x00ff0000)
|
||||
| ((x >> 8) & 0x0000ff00)
|
||||
| ((x >> 24) & 0x000000ff);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A 64-bit byteswap.
|
||||
/// </summary>
|
||||
public static ulong Swap64(ulong x)
|
||||
{
|
||||
return ((x << 56) & 0xff00000000000000)
|
||||
| ((x << 40) & 0x00ff000000000000)
|
||||
| ((x << 24) & 0x0000ff0000000000)
|
||||
| ((x << 8) & 0x000000ff00000000)
|
||||
| ((x >> 8) & 0x00000000ff000000)
|
||||
| ((x >> 24) & 0x0000000000ff0000)
|
||||
| ((x >> 40) & 0x000000000000ff00)
|
||||
| ((x >> 56) & 0x00000000000000ff);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
#if NET40_OR_GREATER || NETCOREAPP
|
||||
#if NET40_OR_GREATER || NETCOREAPP || NETSTANDARD2_0_OR_GREATER
|
||||
using System.Threading.Tasks;
|
||||
#endif
|
||||
using Compress.ThreadReaders;
|
||||
|
||||
namespace SabreTools.Hashing
|
||||
{
|
||||
@@ -13,10 +12,16 @@ namespace SabreTools.Hashing
|
||||
/// </summary>
|
||||
public static class HashTool
|
||||
{
|
||||
#region Standard Hashes
|
||||
|
||||
/// <summary>
|
||||
/// Get CRC-32, MD5, and SHA-1 hashes from an input file path
|
||||
/// </summary>
|
||||
/// <param name="filename">Path to the input file</param>
|
||||
/// <param name="size">Calculated file size on success, -1 on error</param>
|
||||
/// <param name="crc32">CRC-32 for the input file</param>
|
||||
/// <param name="md5">MD5 for the input file</param>
|
||||
/// <param name="sha1">SHA-1 for the input file</param>
|
||||
/// <returns>True if hashing was successful, false otherwise</returns>
|
||||
public static bool GetStandardHashes(string filename, out long size, out string? crc32, out string? md5, out string? sha1)
|
||||
{
|
||||
@@ -26,7 +31,7 @@ namespace SabreTools.Hashing
|
||||
// Get all file hashes
|
||||
HashType[] standardHashTypes = [HashType.CRC32, HashType.MD5, HashType.SHA1];
|
||||
var fileHashes = GetFileHashesAndSize(filename, standardHashTypes, out size);
|
||||
if (fileHashes == null)
|
||||
if (fileHashes is null)
|
||||
return false;
|
||||
|
||||
// Assign the file hashes and return
|
||||
@@ -36,6 +41,62 @@ namespace SabreTools.Hashing
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get CRC-32, MD5, and SHA-1 hashes from an input byte array
|
||||
/// </summary>
|
||||
/// <param name="array">Input byte array</param>
|
||||
/// <param name="size">Calculated file size on success, -1 on error</param>
|
||||
/// <param name="crc32">CRC-32 for the input file</param>
|
||||
/// <param name="md5">MD5 for the input file</param>
|
||||
/// <param name="sha1">SHA-1 for the input file</param>
|
||||
/// <returns>True if hashing was successful, false otherwise</returns>
|
||||
public static bool GetStandardHashes(byte[] array, out long size, out string? crc32, out string? md5, out string? sha1)
|
||||
{
|
||||
// Set all initial values
|
||||
crc32 = null; md5 = null; sha1 = null;
|
||||
|
||||
// Get all file hashes
|
||||
HashType[] standardHashTypes = [HashType.CRC32, HashType.MD5, HashType.SHA1];
|
||||
var fileHashes = GetByteArrayHashesAndSize(array, standardHashTypes, out size);
|
||||
if (fileHashes is null)
|
||||
return false;
|
||||
|
||||
// Assign the file hashes and return
|
||||
crc32 = fileHashes[HashType.CRC32];
|
||||
md5 = fileHashes[HashType.MD5];
|
||||
sha1 = fileHashes[HashType.SHA1];
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get CRC-32, MD5, and SHA-1 hashes from an input stream
|
||||
/// </summary>
|
||||
/// <param name="stream">Input stream</param>
|
||||
/// <param name="size">Calculated file size on success, -1 on error</param>
|
||||
/// <param name="crc32">CRC-32 for the input file</param>
|
||||
/// <param name="md5">MD5 for the input file</param>
|
||||
/// <param name="sha1">SHA-1 for the input file</param>
|
||||
/// <returns>True if hashing was successful, false otherwise</returns>
|
||||
public static bool GetStandardHashes(Stream stream, out long size, out string? crc32, out string? md5, out string? sha1)
|
||||
{
|
||||
// Set all initial values
|
||||
crc32 = null; md5 = null; sha1 = null;
|
||||
|
||||
// Get all file hashes
|
||||
HashType[] standardHashTypes = [HashType.CRC32, HashType.MD5, HashType.SHA1];
|
||||
var fileHashes = GetStreamHashesAndSize(stream, standardHashTypes, out size);
|
||||
if (fileHashes is null)
|
||||
return false;
|
||||
|
||||
// Assign the file hashes and return
|
||||
crc32 = fileHashes[HashType.CRC32];
|
||||
md5 = fileHashes[HashType.MD5];
|
||||
sha1 = fileHashes[HashType.SHA1];
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region File Hashes Without Size
|
||||
|
||||
/// <summary>
|
||||
@@ -61,10 +122,7 @@ namespace SabreTools.Hashing
|
||||
/// <param name="hashType">Hash type to get from the file</param>
|
||||
/// <returns>Hash on success, null on error</returns>
|
||||
public static string? GetFileHash(string filename, HashType hashType)
|
||||
{
|
||||
var hashes = GetFileHashes(filename, [hashType]);
|
||||
return hashes?[hashType];
|
||||
}
|
||||
=> GetFileHashAndSize(filename, hashType, out _);
|
||||
|
||||
/// <summary>
|
||||
/// Get a hash from an input file path
|
||||
@@ -73,10 +131,7 @@ namespace SabreTools.Hashing
|
||||
/// <param name="hashType">Hash type to get from the file</param>
|
||||
/// <returns>Hash on success, null on error</returns>
|
||||
public static byte[]? GetFileHashArray(string filename, HashType hashType)
|
||||
{
|
||||
var hashes = GetFileHashArrays(filename, [hashType]);
|
||||
return hashes?[hashType];
|
||||
}
|
||||
=> GetFileHashArrayAndSize(filename, hashType, out _);
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes from an input file path
|
||||
@@ -104,6 +159,7 @@ namespace SabreTools.Hashing
|
||||
/// Get hashes and size from an input file path
|
||||
/// </summary>
|
||||
/// <param name="filename">Path to the input file</param>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<HashType, string?>? GetFileHashesAndSize(string filename, out long size)
|
||||
{
|
||||
@@ -118,6 +174,7 @@ namespace SabreTools.Hashing
|
||||
/// Get hashes and size from an input file path
|
||||
/// </summary>
|
||||
/// <param name="filename">Path to the input file</param>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<HashType, byte[]?>? GetFileHashArraysAndSize(string filename, out long size)
|
||||
{
|
||||
@@ -133,6 +190,7 @@ namespace SabreTools.Hashing
|
||||
/// </summary>
|
||||
/// <param name="filename">Path to the input file</param>
|
||||
/// <param name="hashType">Hash type to get from the file</param>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Hash and size on success, null on error</returns>
|
||||
public static string? GetFileHashAndSize(string filename, HashType hashType, out long size)
|
||||
{
|
||||
@@ -145,6 +203,7 @@ namespace SabreTools.Hashing
|
||||
/// </summary>
|
||||
/// <param name="filename">Path to the input file</param>
|
||||
/// <param name="hashType">Hash type to get from the file</param>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Hash and size on success, null on error</returns>
|
||||
public static byte[]? GetFileHashArrayAndSize(string filename, HashType hashType, out long size)
|
||||
{
|
||||
@@ -157,6 +216,7 @@ namespace SabreTools.Hashing
|
||||
/// </summary>
|
||||
/// <param name="filename">Path to the input file</param>
|
||||
/// <param name="hashTypes">Array of hash types to get from the file</param>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<HashType, string?>? GetFileHashesAndSize(string filename, HashType[] hashTypes, out long size)
|
||||
{
|
||||
@@ -167,14 +227,11 @@ namespace SabreTools.Hashing
|
||||
return null;
|
||||
}
|
||||
|
||||
// Set the file size
|
||||
size = new FileInfo(filename).Length;
|
||||
|
||||
// Open the input file
|
||||
var input = File.OpenRead(filename);
|
||||
|
||||
// Return the hashes from the stream
|
||||
return GetStreamHashes(input, hashTypes);
|
||||
return GetStreamHashesAndSize(input, hashTypes, out size);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -182,6 +239,7 @@ namespace SabreTools.Hashing
|
||||
/// </summary>
|
||||
/// <param name="filename">Path to the input file</param>
|
||||
/// <param name="hashTypes">Array of hash types to get from the file</param>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<HashType, byte[]?>? GetFileHashArraysAndSize(string filename, HashType[] hashTypes, out long size)
|
||||
{
|
||||
@@ -192,19 +250,16 @@ namespace SabreTools.Hashing
|
||||
return null;
|
||||
}
|
||||
|
||||
// Set the file size
|
||||
size = new FileInfo(filename).Length;
|
||||
|
||||
// Open the input file
|
||||
var input = File.OpenRead(filename);
|
||||
|
||||
// Return the hashes from the stream
|
||||
return GetStreamHashArrays(input, hashTypes);
|
||||
return GetStreamHashArraysAndSize(input, hashTypes, out size);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Byte Array Hashes
|
||||
#region Byte Array Hashes Without Size
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes from an input byte array
|
||||
@@ -212,13 +267,7 @@ namespace SabreTools.Hashing
|
||||
/// <param name="input">Byte array to hash</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<HashType, string?>? GetByteArrayHashes(byte[] input)
|
||||
{
|
||||
// Create a hash array for all entries
|
||||
HashType[] hashTypes = (HashType[])Enum.GetValues(typeof(HashType));
|
||||
|
||||
// Return the hashes from the stream
|
||||
return GetStreamHashes(new MemoryStream(input), hashTypes);
|
||||
}
|
||||
=> GetByteArrayHashesAndSize(input, out _);
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes from an input byte array
|
||||
@@ -226,13 +275,7 @@ namespace SabreTools.Hashing
|
||||
/// <param name="input">Byte array to hash</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<HashType, byte[]?>? GetByteArrayHashArrays(byte[] input)
|
||||
{
|
||||
// Create a hash array for all entries
|
||||
HashType[] hashTypes = (HashType[])Enum.GetValues(typeof(HashType));
|
||||
|
||||
// Return the hashes from the stream
|
||||
return GetStreamHashArrays(new MemoryStream(input), hashTypes);
|
||||
}
|
||||
=> GetByteArrayHashArraysAndSize(input, out _);
|
||||
|
||||
/// <summary>
|
||||
/// Get a hash from an input byte array
|
||||
@@ -241,10 +284,7 @@ namespace SabreTools.Hashing
|
||||
/// <param name="hashType">Hash type to get from the file</param>
|
||||
/// <returns>Hash on success, null on error</returns>
|
||||
public static string? GetByteArrayHash(byte[] input, HashType hashType)
|
||||
{
|
||||
var hashes = GetStreamHashes(new MemoryStream(input), [hashType]);
|
||||
return hashes?[hashType];
|
||||
}
|
||||
=> GetByteArrayHashAndSize(input, hashType, out _);
|
||||
|
||||
/// <summary>
|
||||
/// Get a hash from an input byte array
|
||||
@@ -253,10 +293,7 @@ namespace SabreTools.Hashing
|
||||
/// <param name="hashType">Hash type to get from the file</param>
|
||||
/// <returns>Hash on success, null on error</returns>
|
||||
public static byte[]? GetByteArrayHashArray(byte[] input, HashType hashType)
|
||||
{
|
||||
var hashes = GetStreamHashArrays(new MemoryStream(input), [hashType]);
|
||||
return hashes?[hashType];
|
||||
}
|
||||
=> GetByteArrayHashArrayAndSize(input, hashType, out _);
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes from an input byte array
|
||||
@@ -265,7 +302,7 @@ namespace SabreTools.Hashing
|
||||
/// <param name="hashTypes">Array of hash types to get from the file</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<HashType, string?>? GetByteArrayHashes(byte[] input, HashType[] hashTypes)
|
||||
=> GetStreamHashes(new MemoryStream(input), hashTypes);
|
||||
=> GetByteArrayHashesAndSize(input, hashTypes, out _);
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes from an input byte array
|
||||
@@ -274,78 +311,294 @@ namespace SabreTools.Hashing
|
||||
/// <param name="hashTypes">Array of hash types to get from the file</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<HashType, byte[]?>? GetByteArrayHashArrays(byte[] input, HashType[] hashTypes)
|
||||
=> GetStreamHashArrays(new MemoryStream(input), hashTypes);
|
||||
=> GetByteArrayHashArraysAndSize(input, hashTypes, out _);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Stream Hashes
|
||||
#region Byte Array Hashes With Size
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes from an input byte array
|
||||
/// </summary>
|
||||
/// <param name="input">Byte array to hash</param>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<HashType, string?>? GetByteArrayHashesAndSize(byte[] input, out long size)
|
||||
{
|
||||
// Create a hash array for all entries
|
||||
HashType[] hashTypes = (HashType[])Enum.GetValues(typeof(HashType));
|
||||
|
||||
// Return the hashes from the stream
|
||||
return GetStreamHashesAndSize(new MemoryStream(input), hashTypes, out size);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes from an input byte array
|
||||
/// </summary>
|
||||
/// <param name="input">Byte array to hash</param>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<HashType, byte[]?>? GetByteArrayHashArraysAndSize(byte[] input, out long size)
|
||||
{
|
||||
// Create a hash array for all entries
|
||||
HashType[] hashTypes = (HashType[])Enum.GetValues(typeof(HashType));
|
||||
|
||||
// Return the hashes from the stream
|
||||
return GetStreamHashArraysAndSize(new MemoryStream(input), hashTypes, out size);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a hash from an input byte array
|
||||
/// </summary>
|
||||
/// <param name="input">Byte array to hash</param>
|
||||
/// <param name="hashType">Hash type to get from the file</param>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Hash on success, null on error</returns>
|
||||
public static string? GetByteArrayHashAndSize(byte[] input, HashType hashType, out long size)
|
||||
{
|
||||
var hashes = GetStreamHashesAndSize(new MemoryStream(input), [hashType], out size);
|
||||
return hashes?[hashType];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a hash from an input byte array
|
||||
/// </summary>
|
||||
/// <param name="input">Byte array to hash</param>
|
||||
/// <param name="hashType">Hash type to get from the file</param>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Hash on success, null on error</returns>
|
||||
public static byte[]? GetByteArrayHashArrayAndSize(byte[] input, HashType hashType, out long size)
|
||||
{
|
||||
var hashes = GetStreamHashArraysAndSize(new MemoryStream(input), [hashType], out size);
|
||||
return hashes?[hashType];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes from an input byte array
|
||||
/// </summary>
|
||||
/// <param name="input">Byte array to hash</param>
|
||||
/// <param name="hashTypes">Array of hash types to get from the file</param>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<HashType, string?>? GetByteArrayHashesAndSize(byte[] input, HashType[] hashTypes, out long size)
|
||||
=> GetStreamHashesAndSize(new MemoryStream(input), hashTypes, out size);
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes from an input byte array
|
||||
/// </summary>
|
||||
/// <param name="input">Byte array to hash</param>
|
||||
/// <param name="hashTypes">Array of hash types to get from the file</param>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<HashType, byte[]?>? GetByteArrayHashArraysAndSize(byte[] input, HashType[] hashTypes, out long size)
|
||||
=> GetStreamHashArraysAndSize(new MemoryStream(input), hashTypes, out size);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Stream Hashes Without Size
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes from an input Stream
|
||||
/// </summary>
|
||||
/// <param name="input">Stream to hash</param>
|
||||
/// <param name="leaveOpen">Indicates if the source stream should be left open after hashing</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<HashType, string?>? GetStreamHashes(Stream input, bool leaveOpen = false)
|
||||
{
|
||||
// Create a hash array for all entries
|
||||
HashType[] hashTypes = (HashType[])Enum.GetValues(typeof(HashType));
|
||||
|
||||
// Get the output hashes
|
||||
return GetStreamHashes(input, hashTypes, leaveOpen);
|
||||
}
|
||||
=> GetStreamHashesAndSize(input, leaveOpen, out _);
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes from an input Stream
|
||||
/// </summary>
|
||||
/// <param name="input">Stream to hash</param>
|
||||
/// <param name="leaveOpen">Indicates if the source stream should be left open after hashing</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<HashType, byte[]?>? GetStreamHashArrays(Stream input, bool leaveOpen = false)
|
||||
{
|
||||
// Create a hash array for all entries
|
||||
HashType[] hashTypes = (HashType[])Enum.GetValues(typeof(HashType));
|
||||
|
||||
// Get the output hashes
|
||||
return GetStreamHashArrays(input, hashTypes, leaveOpen);
|
||||
}
|
||||
=> GetStreamHashArraysAndSize(input, leaveOpen, out _);
|
||||
|
||||
/// <summary>
|
||||
/// Get a hash and size from an input Stream
|
||||
/// Get a hash from an input Stream
|
||||
/// </summary>
|
||||
/// <param name="input">Stream to hash</param>
|
||||
/// <param name="hashType">Hash type to get from the file</param>
|
||||
/// <param name="leaveOpen">Indicates if the source stream should be left open after hashing</param>
|
||||
/// <returns>Hash on success, null on error</returns>
|
||||
public static string? GetStreamHash(Stream input, HashType hashType, bool leaveOpen = false)
|
||||
{
|
||||
var hashes = GetStreamHashes(input, [hashType], leaveOpen);
|
||||
return hashes?[hashType];
|
||||
}
|
||||
=> GetStreamHashAndSize(input, hashType, leaveOpen, out _);
|
||||
|
||||
/// <summary>
|
||||
/// Get a hash and size from an input Stream
|
||||
/// Get a hash from an input Stream
|
||||
/// </summary>
|
||||
/// <param name="input">Stream to hash</param>
|
||||
/// <param name="hashType">Hash type to get from the file</param>
|
||||
/// <param name="leaveOpen">Indicates if the source stream should be left open after hashing</param>
|
||||
/// <returns>Hash on success, null on error</returns>
|
||||
public static byte[]? GetStreamHashArray(Stream input, HashType hashType, bool leaveOpen = false)
|
||||
{
|
||||
var hashes = GetStreamHashArrays(input, [hashType], leaveOpen);
|
||||
return hashes?[hashType];
|
||||
}
|
||||
=> GetStreamHashArrayAndSize(input, hashType, leaveOpen, out _);
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes from an input Stream
|
||||
/// </summary>
|
||||
/// <param name="input">Stream to hash</param>
|
||||
/// <param name="hashTypes">Array of hash types to get from the file</param>
|
||||
/// <param name="leaveOpen">Indicates if the source stream should be left open after hashing</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<HashType, string?>? GetStreamHashes(Stream input, HashType[] hashTypes, bool leaveOpen = false)
|
||||
=> GetStreamHashesAndSize(input, hashTypes, leaveOpen, out _);
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes from an input Stream
|
||||
/// </summary>
|
||||
/// <param name="input">Stream to hash</param>
|
||||
/// <param name="hashTypes">Array of hash types to get from the file</param>
|
||||
/// <param name="leaveOpen">Indicates if the source stream should be left open after hashing</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<HashType, byte[]?>? GetStreamHashArrays(Stream input, HashType[] hashTypes, bool leaveOpen = false)
|
||||
=> GetStreamHashArraysAndSize(input, hashTypes, leaveOpen, out _);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Stream Hashes With Size
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes and size from an input Stream
|
||||
/// </summary>
|
||||
/// <param name="input">Stream to hash</param>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<HashType, string?>? GetStreamHashesAndSize(Stream input, out long size)
|
||||
=> GetStreamHashesAndSize(input, leaveOpen: false, out size);
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes and size from an input Stream
|
||||
/// </summary>
|
||||
/// <param name="input">Stream to hash</param>
|
||||
/// <param name="leaveOpen">Indicates if the source stream should be left open after hashing</param>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<HashType, string?>? GetStreamHashesAndSize(Stream input, bool leaveOpen, out long size)
|
||||
{
|
||||
// Create a hash array for all entries
|
||||
HashType[] hashTypes = (HashType[])Enum.GetValues(typeof(HashType));
|
||||
|
||||
// Get the output hashes
|
||||
return GetStreamHashesAndSize(input, hashTypes, leaveOpen, out size);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes and size from an input Stream
|
||||
/// </summary>
|
||||
/// <param name="input">Stream to hash</param>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<HashType, byte[]?>? GetStreamHashArraysAndSize(Stream input, out long size)
|
||||
=> GetStreamHashArraysAndSize(input, leaveOpen: false, out size);
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes and size from an input Stream
|
||||
/// </summary>
|
||||
/// <param name="input">Stream to hash</param>
|
||||
/// <param name="leaveOpen">Indicates if the source stream should be left open after hashing</param>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<HashType, byte[]?>? GetStreamHashArraysAndSize(Stream input, bool leaveOpen, out long size)
|
||||
{
|
||||
// Create a hash array for all entries
|
||||
HashType[] hashTypes = (HashType[])Enum.GetValues(typeof(HashType));
|
||||
|
||||
// Get the output hashes
|
||||
return GetStreamHashArraysAndSize(input, hashTypes, leaveOpen, out size);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a hash and size from an input Stream
|
||||
/// </summary>
|
||||
/// <param name="input">Stream to hash</param>
|
||||
/// <param name="hashType">Hash type to get from the file</param>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Hash on success, null on error</returns>
|
||||
public static string? GetStreamHashAndSize(Stream input, HashType hashType, out long size)
|
||||
=> GetStreamHashAndSize(input, hashType, leaveOpen: false, out size);
|
||||
|
||||
/// <summary>
|
||||
/// Get a hash and size from an input Stream
|
||||
/// </summary>
|
||||
/// <param name="input">Stream to hash</param>
|
||||
/// <param name="hashType">Hash type to get from the file</param>
|
||||
/// <param name="leaveOpen">Indicates if the source stream should be left open after hashing</param>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Hash on success, null on error</returns>
|
||||
public static string? GetStreamHashAndSize(Stream input, HashType hashType, bool leaveOpen, out long size)
|
||||
{
|
||||
var hashes = GetStreamHashesAndSize(input, [hashType], leaveOpen, out size);
|
||||
return hashes?[hashType];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a hash and size from an input Stream
|
||||
/// </summary>
|
||||
/// <param name="input">Stream to hash</param>
|
||||
/// <param name="hashType">Hash type to get from the file</param>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Hash on success, null on error</returns>
|
||||
public static byte[]? GetStreamHashArrayAndSize(Stream input, HashType hashType, out long size)
|
||||
=> GetStreamHashArrayAndSize(input, hashType, leaveOpen: false, out size);
|
||||
|
||||
/// <summary>
|
||||
/// Get a hash and size from an input Stream
|
||||
/// </summary>
|
||||
/// <param name="input">Stream to hash</param>
|
||||
/// <param name="hashType">Hash type to get from the file</param>
|
||||
/// <param name="leaveOpen">Indicates if the source stream should be left open after hashing</param>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Hash on success, null on error</returns>
|
||||
public static byte[]? GetStreamHashArrayAndSize(Stream input, HashType hashType, bool leaveOpen, out long size)
|
||||
{
|
||||
var hashes = GetStreamHashArraysAndSize(input, [hashType], leaveOpen, out size);
|
||||
return hashes?[hashType];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes and size from an input Stream
|
||||
/// </summary>
|
||||
/// <param name="input">Stream to hash</param>
|
||||
/// <param name="hashTypes">Array of hash types to get from the file</param>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<HashType, string?>? GetStreamHashesAndSize(Stream input, HashType[] hashTypes, out long size)
|
||||
=> GetStreamHashesAndSize(input, hashTypes, leaveOpen: false, out size);
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes and size from an input Stream
|
||||
/// </summary>
|
||||
/// <param name="input">Stream to hash</param>
|
||||
/// <param name="hashTypes">Array of hash types to get from the file</param>
|
||||
/// <param name="leaveOpen">Indicates if the source stream should be left open after hashing</param>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<HashType, string?>? GetStreamHashesAndSize(Stream input, HashType[] hashTypes, bool leaveOpen, out long size)
|
||||
{
|
||||
// Create the output dictionary
|
||||
var hashDict = new Dictionary<HashType, string?>();
|
||||
|
||||
try
|
||||
{
|
||||
// Shortcut if we have a 0-byte input
|
||||
if (input.Length == 0)
|
||||
{
|
||||
foreach (var hashType in hashTypes)
|
||||
{
|
||||
hashDict[hashType] = ZeroHash.GetString(hashType);
|
||||
}
|
||||
|
||||
size = 0;
|
||||
return hashDict;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
// Run the hashing
|
||||
var hashers = GetStreamHashesInternal(input, hashTypes, leaveOpen);
|
||||
if (hashers == null)
|
||||
var hashers = GetStreamHashesInternal(input, hashTypes, leaveOpen, out size);
|
||||
if (hashers is null)
|
||||
return null;
|
||||
|
||||
// Get the results
|
||||
@@ -364,21 +617,47 @@ namespace SabreTools.Hashing
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes from an input Stream
|
||||
/// Get hashes and size from an input Stream
|
||||
/// </summary>
|
||||
/// <param name="input">Stream to hash</param>
|
||||
/// <param name="hashTypes">Array of hash types to get from the file</param>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<HashType, byte[]?>? GetStreamHashArrays(Stream input, HashType[] hashTypes, bool leaveOpen = false)
|
||||
public static Dictionary<HashType, byte[]?>? GetStreamHashArraysAndSize(Stream input, HashType[] hashTypes, out long size)
|
||||
=> GetStreamHashArraysAndSize(input, hashTypes, leaveOpen: false, out size);
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes and size from an input Stream
|
||||
/// </summary>
|
||||
/// <param name="input">Stream to hash</param>
|
||||
/// <param name="hashTypes">Array of hash types to get from the file</param>
|
||||
/// <param name="leaveOpen">Indicates if the source stream should be left open after hashing</param>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns>Dictionary containing hashes on success, null on error</returns>
|
||||
public static Dictionary<HashType, byte[]?>? GetStreamHashArraysAndSize(Stream input, HashType[] hashTypes, bool leaveOpen, out long size)
|
||||
{
|
||||
// Create the output dictionary
|
||||
var hashDict = new Dictionary<HashType, byte[]?>();
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
// Shortcut if we have a 0-byte input
|
||||
if (input.Length == 0)
|
||||
{
|
||||
foreach (var hashType in hashTypes)
|
||||
{
|
||||
hashDict[hashType] = ZeroHash.GetBytes(hashType);
|
||||
}
|
||||
|
||||
size = 0;
|
||||
return hashDict;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
// Run the hashing
|
||||
var hashers = GetStreamHashesInternal(input, hashTypes, leaveOpen);
|
||||
if (hashers == null)
|
||||
var hashers = GetStreamHashesInternal(input, hashTypes, leaveOpen, out size);
|
||||
if (hashers is null)
|
||||
return null;
|
||||
|
||||
// Get the results
|
||||
@@ -397,16 +676,18 @@ namespace SabreTools.Hashing
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get hashes from an input stream
|
||||
/// Get hashes and size from an input Stream
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <param name="hashTypes"></param>
|
||||
/// <param name="leaveOpen"></param>
|
||||
/// <param name="input">Stream to hash</param>
|
||||
/// <param name="hashTypes">Array of hash types to get from the file</param>
|
||||
/// <param name="leaveOpen">Indicates if the source stream should be left open after hashing</param>
|
||||
/// <param name="size">Amount of bytes read during hashing</param>
|
||||
/// <returns></returns>
|
||||
private static Dictionary<HashType, HashWrapper>? GetStreamHashesInternal(Stream input, HashType[] hashTypes, bool leaveOpen)
|
||||
private static Dictionary<HashType, HashWrapper>? GetStreamHashesInternal(Stream input, HashType[] hashTypes, bool leaveOpen, out long size)
|
||||
{
|
||||
// Create the output dictionary
|
||||
// Create the output dictionary and size counter
|
||||
var hashDict = new Dictionary<HashType, string?>();
|
||||
size = 0;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -419,29 +700,19 @@ namespace SabreTools.Hashing
|
||||
hashers[hashType] = new HashWrapper(hashType);
|
||||
}
|
||||
|
||||
// Initialize the hashing helpers
|
||||
var loadBuffer = new ThreadLoadBuffer(input);
|
||||
// Create the buffer for holding data
|
||||
int buffersize = 3 * 1024 * 1024;
|
||||
byte[] buffer0 = new byte[buffersize];
|
||||
byte[] buffer1 = new byte[buffersize];
|
||||
byte[] buffer = new byte[buffersize];
|
||||
int lastRead;
|
||||
|
||||
/*
|
||||
Please note that some of the following code is adapted from
|
||||
RomVault. This is a modified version of how RomVault does
|
||||
threaded hashing. As such, some of the terminology and code
|
||||
is the same, though variable names and comments may have
|
||||
been tweaked to better fit this code base.
|
||||
*/
|
||||
|
||||
// Pre load the first buffer
|
||||
int lastRead = input.Read(buffer0, 0, buffersize);
|
||||
bool bufferSelect = true;
|
||||
|
||||
while (lastRead > 0)
|
||||
// Hash the input data in blocks
|
||||
do
|
||||
{
|
||||
// Trigger the buffer load on the second buffer
|
||||
loadBuffer.Trigger(bufferSelect ? buffer1 : buffer0, buffersize);
|
||||
byte[] buffer = bufferSelect ? buffer0 : buffer1;
|
||||
// Load the buffer and hold the number of bytes read
|
||||
lastRead = input.Read(buffer, 0, buffersize);
|
||||
size += lastRead;
|
||||
if (lastRead == 0)
|
||||
break;
|
||||
|
||||
#if NET20 || NET35
|
||||
// Run hashers sequentially on each chunk
|
||||
@@ -453,28 +724,20 @@ namespace SabreTools.Hashing
|
||||
// Run hashers in parallel on each chunk
|
||||
Parallel.ForEach(hashers, h => h.Value.Process(buffer, 0, lastRead));
|
||||
#endif
|
||||
|
||||
// Wait for the load buffer worker, if needed
|
||||
if (loadBuffer.SizeRead > 0)
|
||||
loadBuffer.Wait();
|
||||
|
||||
// Setup for the next hashing step
|
||||
lastRead = loadBuffer.SizeRead;
|
||||
bufferSelect = !bufferSelect;
|
||||
}
|
||||
while (lastRead > 0);
|
||||
|
||||
// Finalize all hashing helpers
|
||||
loadBuffer.Finish();
|
||||
#if NET20 || NET35
|
||||
// Finalize all hashing helpers sequentially
|
||||
foreach (var h in hashers)
|
||||
{
|
||||
h.Value.Terminate();
|
||||
}
|
||||
#else
|
||||
// Finalize all hashing helpers in parallel
|
||||
Parallel.ForEach(hashers, h => h.Value.Terminate());
|
||||
#endif
|
||||
|
||||
loadBuffer.Dispose();
|
||||
return hashers;
|
||||
}
|
||||
catch (IOException)
|
||||
@@ -490,4 +753,4 @@ namespace SabreTools.Hashing
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,51 +17,698 @@ namespace SabreTools.Hashing
|
||||
BLAKE3,
|
||||
#endif
|
||||
|
||||
// <summary>
|
||||
/// CRC 16-bit checksum using the CCITT polynomial
|
||||
/// </summary>
|
||||
CRC16_CCITT,
|
||||
#region CRC
|
||||
|
||||
// <summary>
|
||||
/// CRC 16-bit checksum using the IBM polynomial
|
||||
#region CRC-1
|
||||
|
||||
/// <summary>
|
||||
/// CRC 1-bit checksum (CRC-1/ZERO [Parity bit with 0 start])
|
||||
/// </summary>
|
||||
CRC16_IBM,
|
||||
CRC1_ZERO,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 1-bit checksum (CRC-1/ONE [Parity bit with 1 start])
|
||||
/// </summary>
|
||||
CRC1_ONE,
|
||||
|
||||
#endregion
|
||||
|
||||
#region CRC-3
|
||||
|
||||
/// <summary>
|
||||
/// CRC 3-bit checksum (CRC-3/GSM)
|
||||
/// </summary>
|
||||
CRC3_GSM,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 3-bit checksum (CRC-3/ROHC)
|
||||
/// </summary>
|
||||
CRC3_ROHC,
|
||||
|
||||
#endregion
|
||||
|
||||
#region CRC-4
|
||||
|
||||
/// <summary>
|
||||
/// CRC 4-bit checksum (CRC-4/G-704 [CRC-4/ITU])
|
||||
/// </summary>
|
||||
CRC4_G704,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 4-bit checksum (CRC-4/INTERLAKEN)
|
||||
/// </summary>
|
||||
CRC4_INTERLAKEN,
|
||||
|
||||
#endregion
|
||||
|
||||
#region CRC-5
|
||||
|
||||
/// <summary>
|
||||
/// CRC 5-bit checksum (CRC-5/EPC-C1G2 [CRC-5/EPC])
|
||||
/// </summary>
|
||||
CRC5_EPCC1G2,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 5-bit checksum (CRC-5/G-704 [CRC-5/ITU])
|
||||
/// </summary>
|
||||
CRC5_G704,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 5-bit checksum (CRC-5/USB)
|
||||
/// </summary>
|
||||
CRC5_USB,
|
||||
|
||||
#endregion
|
||||
|
||||
#region CRC-6
|
||||
|
||||
/// <summary>
|
||||
/// CRC 6-bit checksum (CRC-6/CDMA2000-A)
|
||||
/// </summary>
|
||||
CRC6_CDMA2000A,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 6-bit checksum (CRC-6/CDMA2000-B)
|
||||
/// </summary>
|
||||
CRC6_CDMA2000B,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 6-bit checksum (CRC-6/DARC)
|
||||
/// </summary>
|
||||
CRC6_DARC,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 6-bit checksum (CRC-6/G-704 [CRC-6/ITU])
|
||||
/// </summary>
|
||||
CRC6_G704,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 6-bit checksum (CRC-6/GSM)
|
||||
/// </summary>
|
||||
CRC6_GSM,
|
||||
|
||||
#endregion
|
||||
|
||||
#region CRC-7
|
||||
|
||||
/// <summary>
|
||||
/// CRC 7-bit checksum (CRC-7/MMC [CRC-7])
|
||||
/// </summary>
|
||||
CRC7_MMC,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 7-bit checksum (CRC-7/ROHC)
|
||||
/// </summary>
|
||||
CRC7_ROHC,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 7-bit checksum (CRC-7/UMTS)
|
||||
/// </summary>
|
||||
CRC7_UMTS,
|
||||
|
||||
#endregion
|
||||
|
||||
#region CRC-8
|
||||
|
||||
/// <summary>
|
||||
/// CRC 8-bit checksum
|
||||
/// </summary>
|
||||
/// <remarks>Identical to <see cref="CRC8_SMBUS"/>
|
||||
CRC8,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 8-bit checksum (CRC-8/AUTOSAR)
|
||||
/// </summary>
|
||||
CRC8_AUTOSAR,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 8-bit checksum (CRC-8/BLUETOOTH)
|
||||
/// </summary>
|
||||
CRC8_BLUETOOTH,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 8-bit checksum (CRC-8/CDMA2000)
|
||||
/// </summary>
|
||||
CRC8_CDMA2000,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 8-bit checksum (CRC-8/DARC)
|
||||
/// </summary>
|
||||
CRC8_DARC,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 8-bit checksum (CRC-8/DVB-S2)
|
||||
/// </summary>
|
||||
CRC8_DVBS2,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 8-bit checksum (CRC-8/GSM-A)
|
||||
/// </summary>
|
||||
CRC8_GSMA,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 8-bit checksum (CRC-8/GSM-B)
|
||||
/// </summary>
|
||||
CRC8_GSMB,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 8-bit checksum (CRC-8/HITAG)
|
||||
/// </summary>
|
||||
CRC8_HITAG,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 8-bit checksum (CRC-8/I-432-1 [CRC-8/ITU])
|
||||
/// </summary>
|
||||
CRC8_I4321,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 8-bit checksum (CRC-8/I-CODE)
|
||||
/// </summary>
|
||||
CRC8_ICODE,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 8-bit checksum (CRC-8/LTE)
|
||||
/// </summary>
|
||||
CRC8_LTE,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 8-bit checksum (CRC-8/MAXIM-DOW [CRC-8/MAXIM, DOW-CRC])
|
||||
/// </summary>
|
||||
CRC8_MAXIMDOW,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 8-bit checksum (CRC-8/MIFARE-MAD)
|
||||
/// </summary>
|
||||
CRC8_MIFAREMAD,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 8-bit checksum (CRC-8/NRSC-5)
|
||||
/// </summary>
|
||||
CRC8_NRSC5,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 8-bit checksum (CRC-8/OPENSAFETY)
|
||||
/// </summary>
|
||||
CRC8_OPENSAFETY,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 8-bit checksum (CRC-8/ROHC)
|
||||
/// </summary>
|
||||
CRC8_ROHC,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 8-bit checksum (CRC-8/SAE-J1850)
|
||||
/// </summary>
|
||||
CRC8_SAEJ1850,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 8-bit checksum (CRC-8/SMBUS [CRC-8])
|
||||
/// </summary>
|
||||
CRC8_SMBUS,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 8-bit checksum (CRC-8/TECH-3250 [CRC-8/AES, CRC-8/EBU])
|
||||
/// </summary>
|
||||
CRC8_TECH3250,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 8-bit checksum (CRC-8/WCDMA)
|
||||
/// </summary>
|
||||
CRC8_WCDMA,
|
||||
|
||||
#endregion
|
||||
|
||||
#region CRC-10
|
||||
|
||||
/// <summary>
|
||||
/// CRC 10-bit checksum (CRC-10/ATM [CRC-10, CRC-10/I-610])
|
||||
/// </summary>
|
||||
CRC10_ATM,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 10-bit checksum (CRC-10/CDMA2000)
|
||||
/// </summary>
|
||||
CRC10_CDMA2000,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 10-bit checksum (CRC-10/GSM)
|
||||
/// </summary>
|
||||
CRC10_GSM,
|
||||
|
||||
#endregion
|
||||
|
||||
#region CRC-11
|
||||
|
||||
/// <summary>
|
||||
/// CRC 11-bit checksum (CRC-11/FLEXRAY [CRC-11])
|
||||
/// </summary>
|
||||
CRC11_FLEXRAY,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 11-bit checksum (CRC-11/UMTS)
|
||||
/// </summary>
|
||||
CRC11_UMTS,
|
||||
|
||||
#endregion
|
||||
|
||||
#region CRC-12
|
||||
|
||||
/// <summary>
|
||||
/// CRC 12-bit checksum (CRC-12/CDMA2000)
|
||||
/// </summary>
|
||||
CRC12_CDMA2000,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 12-bit checksum (CRC-12/DECT [X-CRC-12])
|
||||
/// </summary>
|
||||
CRC12_DECT,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 12-bit checksum (CRC-12/GSM)
|
||||
/// </summary>
|
||||
CRC12_GSM,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 12-bit checksum (CRC-12/UMTS [CRC-12/3GPP])
|
||||
/// </summary>
|
||||
CRC12_UMTS,
|
||||
|
||||
#endregion
|
||||
|
||||
#region CRC-13
|
||||
|
||||
/// <summary>
|
||||
/// CRC 13-bit checksum (CRC-13/BBC)
|
||||
/// </summary>
|
||||
CRC13_BBC,
|
||||
|
||||
#endregion
|
||||
|
||||
#region CRC-14
|
||||
|
||||
/// <summary>
|
||||
/// CRC 14-bit checksum (CRC-14/DARC)
|
||||
/// </summary>
|
||||
CRC14_DARC,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 14-bit checksum (CRC-14/GSM)
|
||||
/// </summary>
|
||||
CRC14_GSM,
|
||||
|
||||
#endregion
|
||||
|
||||
#region CRC-15
|
||||
|
||||
/// <summary>
|
||||
/// CRC 15-bit checksum (CRC-15/CAN [CRC-15])
|
||||
/// </summary>
|
||||
CRC15_CAN,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 15-bit checksum (CRC-15/MPT1327)
|
||||
/// </summary>
|
||||
CRC15_MPT1327,
|
||||
|
||||
#endregion
|
||||
|
||||
#region CRC-16
|
||||
|
||||
/// <summary>
|
||||
/// CRC 16-bit checksum
|
||||
/// </summary>
|
||||
/// <remarks>Identical to <see cref="CRC16_ARC"/>
|
||||
CRC16,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 16-bit checksum (CRC-16/ARC [ARC, CRC-16, CRC-16/LHA, CRC-IBM])
|
||||
/// </summary>
|
||||
CRC16_ARC,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 16-bit checksum (CRC-16/CDMA2000)
|
||||
/// </summary>
|
||||
CRC16_CDMA2000,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 16-bit checksum (CRC-16/CMS)
|
||||
/// </summary>
|
||||
CRC16_CMS,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 16-bit checksum (CRC-16/DDS-110)
|
||||
/// </summary>
|
||||
CRC16_DDS110,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 16-bit checksum (CRC-16/DECT-R [R-CRC-16])
|
||||
/// </summary>
|
||||
CRC16_DECTR,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 16-bit checksum (CRC-16/DECT-X [X-CRC-16])
|
||||
/// </summary>
|
||||
CRC16_DECTX,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 16-bit checksum (CRC-16/DNP)
|
||||
/// </summary>
|
||||
CRC16_DNP,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 16-bit checksum (CRC-16/EN-13757)
|
||||
/// </summary>
|
||||
CRC16_EN13757,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 16-bit checksum (CRC-16/GENIBUS [CRC-16/DARC, CRC-16/EPC, CRC-16/EPC-C1G2, CRC-16/I-CODE])
|
||||
/// </summary>
|
||||
CRC16_GENIBUS,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 16-bit checksum (CRC-16/GSM)
|
||||
/// </summary>
|
||||
CRC16_GSM,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 16-bit checksum (CRC-16/IBM-3740 [CRC-16/AUTOSAR, CRC-16/CCITT-FALSE])
|
||||
/// </summary>
|
||||
CRC16_IBM3740,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 16-bit checksum (CRC-16/IBM-SDLC [CRC-16/ISO-HDLC, CRC-16/ISO-IEC-14443-3-B, CRC-16/X-25, CRC-B, X-25])
|
||||
/// </summary>
|
||||
CRC16_IBMSDLC,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 16-bit checksum (CRC-16/ISO-IEC-14443-3-A [CRC-A])
|
||||
/// </summary>
|
||||
CRC16_ISOIEC144433A,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 16-bit checksum (CRC-16/KERMIT [CRC-16/BLUETOOTH, CRC-16/CCITT, CRC-16/CCITT-TRUE, CRC-16/V-41-LSB, CRC-CCITT, KERMIT])
|
||||
/// </summary>
|
||||
CRC16_KERMIT,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 16-bit checksum (CRC-16/LJ1200)
|
||||
/// </summary>
|
||||
CRC16_LJ1200,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 16-bit checksum (CRC-16/M17)
|
||||
/// </summary>
|
||||
CRC16_M17,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 16-bit checksum (CRC-16/MAXIM-DOW [CRC-16/MAXIM])
|
||||
/// </summary>
|
||||
CRC16_MAXIMDOW,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 16-bit checksum (CRC-16/MCRF4XX)
|
||||
/// </summary>
|
||||
CRC16_MCRF4XX,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 16-bit checksum (CRC-16/MODBUS [MODBUS])
|
||||
/// </summary>
|
||||
CRC16_MODBUS,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 16-bit checksum (CRC-16/NRSC-5)
|
||||
/// </summary>
|
||||
CRC16_NRSC5,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 16-bit checksum (CRC-16/OPENSAFETY-A)
|
||||
/// </summary>
|
||||
CRC16_OPENSAFETYA,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 16-bit checksum (CRC-16/OPENSAFETY-B)
|
||||
/// </summary>
|
||||
CRC16_OPENSAFETYB,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 16-bit checksum (CRC-16/PROFIBUS [CRC-16/IEC-61158-2])
|
||||
/// </summary>
|
||||
CRC16_PROFIBUS,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 16-bit checksum (CRC-16/RIELLO)
|
||||
/// </summary>
|
||||
CRC16_RIELLO,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 16-bit checksum (CRC-16/SPI-FUJITSU [CRC-16/AUG-CCITT])
|
||||
/// </summary>
|
||||
CRC16_SPIFUJITSU,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 16-bit checksum (CRC-16/T10-DIF)
|
||||
/// </summary>
|
||||
CRC16_T10DIF,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 16-bit checksum (CRC-16/TELEDISK)
|
||||
/// </summary>
|
||||
CRC16_TELEDISK,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 16-bit checksum (CRC-16/TMS37157)
|
||||
/// </summary>
|
||||
CRC16_TMS37157,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 16-bit checksum (CRC-16/UMTS [CRC-16/BUYPASS, CRC-16/VERIFONE])
|
||||
/// </summary>
|
||||
CRC16_UMTS,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 16-bit checksum (CRC-16/USB)
|
||||
/// </summary>
|
||||
CRC16_USB,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 16-bit checksum (CRC-16/XMODEM [CRC-16/ACORN, CRC-16/LTE, CRC-16/V-41-MSB, XMODEM, ZMODEM])
|
||||
/// </summary>
|
||||
CRC16_XMODEM,
|
||||
|
||||
#endregion
|
||||
|
||||
#region CRC-17
|
||||
|
||||
/// <summary>
|
||||
/// CRC 17-bit checksum (CRC-17/CAN-FD)
|
||||
/// </summary>
|
||||
CRC17_CANFD,
|
||||
|
||||
#endregion
|
||||
|
||||
#region CRC-21
|
||||
|
||||
/// <summary>
|
||||
/// CRC 21-bit checksum (CRC-21/CAN-FD)
|
||||
/// </summary>
|
||||
CRC21_CANFD,
|
||||
|
||||
#endregion
|
||||
|
||||
#region CRC-24
|
||||
|
||||
/// <summary>
|
||||
/// CRC 24-bit checksum (CRC-24/BLE)
|
||||
/// </summary>
|
||||
CRC24_BLE,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 24-bit checksum (CRC-24/FLEXRAY-A)
|
||||
/// </summary>
|
||||
CRC24_FLEXRAYA,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 24-bit checksum (CRC-24/FLEXRAY-B)
|
||||
/// </summary>
|
||||
CRC24_FLEXRAYB,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 24-bit checksum (CRC-24/INTERLAKEN)
|
||||
/// </summary>
|
||||
CRC24_INTERLAKEN,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 24-bit checksum (CRC-24/LTE-A)
|
||||
/// </summary>
|
||||
CRC24_LTEA,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 24-bit checksum (CRC-24/LTE-B)
|
||||
/// </summary>
|
||||
CRC24_LTEB,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 24-bit checksum (CRC-24/OPENPGP)
|
||||
/// </summary>
|
||||
CRC24_OPENPGP,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 24-bit checksum (CRC-24/OS-9)
|
||||
/// </summary>
|
||||
CRC24_OS9,
|
||||
|
||||
#endregion
|
||||
|
||||
#region CRC-30
|
||||
|
||||
/// <summary>
|
||||
/// CRC 30-bit checksum (CRC-30/CDMA)
|
||||
/// </summary>
|
||||
CRC30_CDMA,
|
||||
|
||||
#endregion
|
||||
|
||||
#region CRC-31
|
||||
|
||||
/// <summary>
|
||||
/// CRC 31-bit checksum (CRC-31/PHILIPS)
|
||||
/// </summary>
|
||||
CRC31_PHILIPS,
|
||||
|
||||
#endregion
|
||||
|
||||
#region CRC-32
|
||||
|
||||
/// <summary>
|
||||
/// CRC 32-bit checksum
|
||||
/// </summary>
|
||||
/// <remarks>Same as CRC32_ISO in .NET Framework 4.5.2 and lower</remarks>
|
||||
/// <remarks>Identical to <see cref="CRC32_ISOHDLC"/>
|
||||
CRC32,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 32-bit checksum (ISO implementation)
|
||||
/// CRC 32-bit checksum (CRC-32/AIXM)
|
||||
/// </summary>
|
||||
CRC32_ISO,
|
||||
CRC32_AIXM,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 32-bit checksum (NaiveCRC implementation)
|
||||
/// CRC 32-bit checksum (CRC-32/AUTOSAR)
|
||||
/// </summary>
|
||||
CRC32_Naive,
|
||||
CRC32_AUTOSAR,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 32-bit checksum (OptimizedCRC implementation)
|
||||
/// CRC 32-bit checksum (CRC-32/BASE91-D)
|
||||
/// </summary>
|
||||
CRC32_Optimized,
|
||||
CRC32_BASE91D,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 32-bit checksum (ParallelCRC implementation)
|
||||
/// CRC 32-bit checksum (BZIP2)
|
||||
/// </summary>
|
||||
CRC32_Parallel,
|
||||
CRC32_BZIP2,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 64-bit checksum (0x42F0E1EBA9EA3693 polynomial)
|
||||
/// CRC 32-bit checksum (CRC-32/CD-ROM-EDC)
|
||||
/// </summary>
|
||||
CRC32_CDROMEDC,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 32-bit checksum (CRC-32/CKSUM)
|
||||
/// </summary>
|
||||
CRC32_CKSUM,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 32-bit checksum (CRC-32/DVD-ROM-EDC)
|
||||
/// </summary>
|
||||
CRC32_DVDROMEDC,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 32-bit checksum (CRC-32/ISCSI)
|
||||
/// </summary>
|
||||
CRC32_ISCSI,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 32-bit checksum (CRC-32/ISO-HDLC)
|
||||
/// </summary>
|
||||
CRC32_ISOHDLC,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 32-bit checksum (CRC-32/JAMCRC)
|
||||
/// </summary>
|
||||
CRC32_JAMCRC,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 32-bit checksum (CRC-32/MEF)
|
||||
/// </summary>
|
||||
CRC32_MEF,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 32-bit checksum (CRC-32/MPEG-2)
|
||||
/// </summary>
|
||||
CRC32_MPEG2,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 32-bit checksum (CRC-32/XFER)
|
||||
/// </summary>
|
||||
CRC32_XFER,
|
||||
|
||||
#endregion
|
||||
|
||||
#region CRC-40
|
||||
|
||||
/// <summary>
|
||||
/// CRC 40-bit checksum (CRC-40/GSM)
|
||||
/// </summary>
|
||||
CRC40_GSM,
|
||||
|
||||
#endregion
|
||||
|
||||
#region CRC-64
|
||||
|
||||
/// <summary>
|
||||
/// CRC 64-bit checksum
|
||||
/// </summary>
|
||||
/// <remarks>Identical to <see cref="CRC64_ECMA182"/>
|
||||
CRC64,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 64-bit checksum (0xC96C5795D7870F42 polynomial)
|
||||
/// CRC 64-bit checksum (CRC-64/ECMA-182, Microsoft implementation)
|
||||
/// </summary>
|
||||
CRC64_Reversed,
|
||||
CRC64_ECMA182,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 64-bit checksum (CRC-64/GO-ISO)
|
||||
/// </summary>
|
||||
CRC64_GOISO,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 64-bit checksum (CRC-64/MS)
|
||||
/// </summary>
|
||||
CRC64_MS,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 64-bit checksum (CRC-64/NVME)
|
||||
/// </summary>
|
||||
CRC64_NVME,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 64-bit checksum (CRC-64/REDIS)
|
||||
/// </summary>
|
||||
CRC64_REDIS,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 64-bit checksum (CRC-64/WE)
|
||||
/// </summary>
|
||||
CRC64_WE,
|
||||
|
||||
/// <summary>
|
||||
/// CRC 64-bit checksum (CRC-64/XZ)
|
||||
/// </summary>
|
||||
CRC64_XZ,
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region Fletcher
|
||||
|
||||
/// <summary>
|
||||
/// John G. Fletcher's 16-bit checksum
|
||||
@@ -74,16 +721,95 @@ namespace SabreTools.Hashing
|
||||
Fletcher32,
|
||||
|
||||
/// <summary>
|
||||
/// MD5 hash
|
||||
/// John G. Fletcher's 64-bit checksum
|
||||
/// </summary>
|
||||
Fletcher64,
|
||||
|
||||
#endregion
|
||||
|
||||
#region FNV
|
||||
|
||||
/// <summary>
|
||||
/// FNV hash (Variant 0, 32-bit)
|
||||
/// </summary>
|
||||
FNV0_32,
|
||||
|
||||
/// <summary>
|
||||
/// FNV hash (Variant 0, 64-bit)
|
||||
/// </summary>
|
||||
FNV0_64,
|
||||
|
||||
/// <summary>
|
||||
/// FNV hash (Variant 1, 32-bit)
|
||||
/// </summary>
|
||||
FNV1_32,
|
||||
|
||||
/// <summary>
|
||||
/// FNV hash (Variant 1, 64-bit)
|
||||
/// </summary>
|
||||
FNV1_64,
|
||||
|
||||
/// <summary>
|
||||
/// FNV hash (Variant 1a, 32-bit)
|
||||
/// </summary>
|
||||
FNV1a_32,
|
||||
|
||||
/// <summary>
|
||||
/// FNV hash (Variant 1a, 64-bit)
|
||||
/// </summary>
|
||||
FNV1a_64,
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Custom checksum used by MEKA
|
||||
/// </summary>
|
||||
MekaCrc,
|
||||
|
||||
#region Message Digest
|
||||
|
||||
/// <summary>
|
||||
/// MD2 message-digest algorithm
|
||||
/// </summary>
|
||||
MD2,
|
||||
|
||||
/// <summary>
|
||||
/// MD4 message-digest algorithm
|
||||
/// </summary>
|
||||
MD4,
|
||||
|
||||
/// <summary>
|
||||
/// MD5 message-digest algorithm
|
||||
/// </summary>
|
||||
MD5,
|
||||
|
||||
#if NETFRAMEWORK
|
||||
#endregion
|
||||
|
||||
#region RIPEMD
|
||||
|
||||
/// <summary>
|
||||
/// RIPEMD160 hash
|
||||
/// RIPEMD-128 hash
|
||||
/// </summary>
|
||||
RIPEMD128,
|
||||
|
||||
/// <summary>
|
||||
/// RIPEMD-160 hash
|
||||
/// </summary>
|
||||
RIPEMD160,
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// RIPEMD-256 hash
|
||||
/// </summary>
|
||||
RIPEMD256,
|
||||
|
||||
/// <summary>
|
||||
/// RIPEMD-320 hash
|
||||
/// </summary>
|
||||
RIPEMD320,
|
||||
|
||||
#endregion
|
||||
|
||||
#region SHA
|
||||
|
||||
/// <summary>
|
||||
/// SHA-1 hash
|
||||
@@ -119,7 +845,7 @@ namespace SabreTools.Hashing
|
||||
/// <summary>
|
||||
/// SHA3-512 hash
|
||||
/// </summary>
|
||||
SHA3_512,
|
||||
SHA3_512,
|
||||
|
||||
/// <summary>
|
||||
/// SHAKE128 SHA-3 family hash
|
||||
@@ -134,12 +860,79 @@ namespace SabreTools.Hashing
|
||||
SHAKE256,
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// spamsum fuzzy hash
|
||||
/// </summary>
|
||||
SpamSum,
|
||||
|
||||
#if NET462_OR_GREATER || NETCOREAPP
|
||||
#region Tiger
|
||||
|
||||
/// <summary>
|
||||
/// Tiger 128-bit hash, 3 passes
|
||||
/// </summary>
|
||||
Tiger128_3,
|
||||
|
||||
/// <summary>
|
||||
/// Tiger 128-bit hash, 4 passes
|
||||
/// </summary>
|
||||
Tiger128_4,
|
||||
|
||||
/// <summary>
|
||||
/// Tiger 160-bit hash, 3 passes
|
||||
/// </summary>
|
||||
Tiger160_3,
|
||||
|
||||
/// <summary>
|
||||
/// Tiger 160-bit hash, 4 passes
|
||||
/// </summary>
|
||||
Tiger160_4,
|
||||
|
||||
/// <summary>
|
||||
/// Tiger 192-bit hash, 3 passes
|
||||
/// </summary>
|
||||
Tiger192_3,
|
||||
|
||||
/// <summary>
|
||||
/// Tiger 192-bit hash, 4 passes
|
||||
/// </summary>
|
||||
Tiger192_4,
|
||||
|
||||
/// <summary>
|
||||
/// Tiger2 128-bit hash, 3 passes
|
||||
/// </summary>
|
||||
Tiger2_128_3,
|
||||
|
||||
/// <summary>
|
||||
/// Tiger2 128-bit hash, 4 passes
|
||||
/// </summary>
|
||||
Tiger2_128_4,
|
||||
|
||||
/// <summary>
|
||||
/// Tiger2 160-bit hash, 3 passes
|
||||
/// </summary>
|
||||
Tiger2_160_3,
|
||||
|
||||
/// <summary>
|
||||
/// Tiger2 160-bit hash, 4 passes
|
||||
/// </summary>
|
||||
Tiger2_160_4,
|
||||
|
||||
/// <summary>
|
||||
/// Tiger2 192-bit hash, 3 passes
|
||||
/// </summary>
|
||||
Tiger2_192_3,
|
||||
|
||||
/// <summary>
|
||||
/// Tiger2 192-bit hash, 4 passes
|
||||
/// </summary>
|
||||
Tiger2_192_4,
|
||||
|
||||
#endregion
|
||||
|
||||
#region xxHash
|
||||
|
||||
/// <summary>
|
||||
/// xxHash32 hash
|
||||
/// </summary>
|
||||
@@ -150,6 +943,7 @@ namespace SabreTools.Hashing
|
||||
/// </summary>
|
||||
XxHash64,
|
||||
|
||||
#if NET462_OR_GREATER || NETCOREAPP
|
||||
/// <summary>
|
||||
/// XXH3 64-bit hash
|
||||
/// </summary>
|
||||
@@ -160,5 +954,7 @@ namespace SabreTools.Hashing
|
||||
/// </summary>
|
||||
XxHash128,
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,9 @@
|
||||
using System;
|
||||
#if NET462_OR_GREATER || NETCOREAPP
|
||||
using System.IO.Hashing;
|
||||
#endif
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using Aaru.Checksums;
|
||||
using Aaru.CommonTypes.Interfaces;
|
||||
#if NET7_0_OR_GREATER
|
||||
using Blake3;
|
||||
#endif
|
||||
using CRC32;
|
||||
using SabreTools.Hashing.Checksum;
|
||||
using SabreTools.Hashing.CryptographicHash;
|
||||
using SabreTools.Hashing.NonCryptographicHash;
|
||||
using static SabreTools.Hashing.HashOperations;
|
||||
|
||||
namespace SabreTools.Hashing
|
||||
{
|
||||
@@ -23,52 +17,38 @@ namespace SabreTools.Hashing
|
||||
/// <summary>
|
||||
/// Hash type associated with the current state
|
||||
/// </summary>
|
||||
#if NETFRAMEWORK || NETCOREAPP3_1
|
||||
public HashType HashType { get; private set; }
|
||||
#else
|
||||
public HashType HashType { get; init; }
|
||||
#endif
|
||||
public readonly HashType HashType;
|
||||
|
||||
/// <summary>
|
||||
/// Current hash in bytes
|
||||
/// </summary>
|
||||
public byte[]? CurrentHashBytes
|
||||
public byte[]? CurrentHashBytes => _hasher switch
|
||||
{
|
||||
get
|
||||
{
|
||||
return _hasher switch
|
||||
{
|
||||
HashAlgorithm ha => ha.Hash,
|
||||
IChecksum ic => ic.Final(),
|
||||
NaiveCRC ncrc => BitConverter.GetBytes(ncrc.Value).Reverse().ToArray(),
|
||||
HashAlgorithm ha => ha.Hash,
|
||||
#if NET462_OR_GREATER || NETCOREAPP
|
||||
NonCryptographicHashAlgorithm ncha => ncha.GetCurrentHash().Reverse().ToArray(),
|
||||
System.IO.Hashing.NonCryptographicHashAlgorithm ncha => ncha.GetCurrentHash(),
|
||||
#endif
|
||||
OptimizedCRC ocrc => BitConverter.GetBytes(ocrc.Value).Reverse().ToArray(),
|
||||
ParallelCRC pcrc => BitConverter.GetBytes(pcrc.Value).Reverse().ToArray(),
|
||||
#if NET8_0_OR_GREATER
|
||||
Shake128 s128 => s128.GetCurrentHash(32),
|
||||
Shake256 s256 => s256.GetCurrentHash(64),
|
||||
Shake128 s128 => s128.GetCurrentHash(32),
|
||||
Shake256 s256 => s256.GetCurrentHash(64),
|
||||
#endif
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
}
|
||||
_ => null,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Current hash as a string
|
||||
/// </summary>
|
||||
public string? CurrentHashString
|
||||
public string? CurrentHashString => _hasher switch
|
||||
{
|
||||
get
|
||||
{
|
||||
return _hasher switch
|
||||
{
|
||||
IChecksum ic => ic.End(),
|
||||
_ => ByteArrayToString(CurrentHashBytes),
|
||||
};
|
||||
}
|
||||
}
|
||||
// Needed due to variable bit widths
|
||||
Crc cr => GetCRCVariableLengthString(cr),
|
||||
|
||||
// Needed due to Base64 text output
|
||||
SpamSum.SpamSum ss => GetSpamSumBase64String(ss),
|
||||
|
||||
// Everything else are direct conversions
|
||||
_ => ByteArrayToString(CurrentHashBytes),
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -77,14 +57,8 @@ namespace SabreTools.Hashing
|
||||
/// <summary>
|
||||
/// Internal hasher being used for processing
|
||||
/// </summary>
|
||||
/// <remarks>May be either a HashAlgorithm or NonCryptographicHashAlgorithm</remarks>
|
||||
private object? _hasher;
|
||||
|
||||
/// <summary>
|
||||
/// Non-reversed CRC-64 polynomial
|
||||
/// </summary>
|
||||
private const ulong CRC64_ECMA_POLY_NORMAL = 0x42F0E1EBA9EA3693;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
@@ -95,7 +69,7 @@ namespace SabreTools.Hashing
|
||||
/// <param name="hashType">Hash type to instantiate</param>
|
||||
public HashWrapper(HashType hashType)
|
||||
{
|
||||
this.HashType = hashType;
|
||||
HashType = hashType;
|
||||
GetHasher();
|
||||
}
|
||||
|
||||
@@ -106,33 +80,175 @@ namespace SabreTools.Hashing
|
||||
{
|
||||
_hasher = HashType switch
|
||||
{
|
||||
HashType.Adler32 => new Adler32Context(),
|
||||
HashType.Adler32 => new Adler32(),
|
||||
|
||||
#if NET7_0_OR_GREATER
|
||||
HashType.BLAKE3 => new Blake3HashAlgorithm(),
|
||||
HashType.BLAKE3 => new Blake3.Blake3HashAlgorithm(),
|
||||
#endif
|
||||
HashType.CRC16_CCITT => new CRC16CcittContext(),
|
||||
HashType.CRC16_IBM => new CRC16IbmContext(),
|
||||
#if NET462_OR_GREATER || NETCOREAPP
|
||||
HashType.CRC32 => new Crc32(),
|
||||
#else
|
||||
HashType.CRC32 => new Crc32Context(),
|
||||
#endif
|
||||
HashType.CRC32_ISO => new Crc32Context(),
|
||||
HashType.CRC32_Naive => new NaiveCRC(),
|
||||
HashType.CRC32_Optimized => new OptimizedCRC(),
|
||||
HashType.CRC32_Parallel => new ParallelCRC(),
|
||||
#if NET462_OR_GREATER || NETCOREAPP
|
||||
HashType.CRC64 => new Crc64(),
|
||||
#else
|
||||
HashType.CRC64 => new Crc64Context(CRC64_ECMA_POLY_NORMAL, 0xFFFFFFFFFFFFFFFF),
|
||||
#endif
|
||||
HashType.CRC64_Reversed => new Crc64Context(),
|
||||
HashType.Fletcher16 => new Fletcher16Context(),
|
||||
HashType.Fletcher32 => new Fletcher32Context(),
|
||||
|
||||
HashType.CRC1_ZERO => new Crc(StandardDefinitions.CRC1_ZERO),
|
||||
HashType.CRC1_ONE => new Crc(StandardDefinitions.CRC1_ONE),
|
||||
|
||||
HashType.CRC3_GSM => new Crc(StandardDefinitions.CRC3_GSM),
|
||||
HashType.CRC3_ROHC => new Crc(StandardDefinitions.CRC3_ROHC),
|
||||
|
||||
HashType.CRC4_G704 => new Crc(StandardDefinitions.CRC4_G704),
|
||||
HashType.CRC4_INTERLAKEN => new Crc(StandardDefinitions.CRC4_INTERLAKEN),
|
||||
|
||||
HashType.CRC5_EPCC1G2 => new Crc(StandardDefinitions.CRC5_EPCC1G2),
|
||||
HashType.CRC5_G704 => new Crc(StandardDefinitions.CRC5_G704),
|
||||
HashType.CRC5_USB => new Crc(StandardDefinitions.CRC5_USB),
|
||||
|
||||
HashType.CRC6_CDMA2000A => new Crc(StandardDefinitions.CRC6_CDMA2000A),
|
||||
HashType.CRC6_CDMA2000B => new Crc(StandardDefinitions.CRC6_CDMA2000B),
|
||||
HashType.CRC6_DARC => new Crc(StandardDefinitions.CRC6_DARC),
|
||||
HashType.CRC6_G704 => new Crc(StandardDefinitions.CRC6_G704),
|
||||
HashType.CRC6_GSM => new Crc(StandardDefinitions.CRC6_GSM),
|
||||
|
||||
HashType.CRC7_MMC => new Crc(StandardDefinitions.CRC7_MMC),
|
||||
HashType.CRC7_ROHC => new Crc(StandardDefinitions.CRC7_ROHC),
|
||||
HashType.CRC7_UMTS => new Crc(StandardDefinitions.CRC7_UMTS),
|
||||
|
||||
HashType.CRC8 => new Crc(StandardDefinitions.CRC8_SMBUS),
|
||||
HashType.CRC8_AUTOSAR => new Crc(StandardDefinitions.CRC8_AUTOSAR),
|
||||
HashType.CRC8_BLUETOOTH => new Crc(StandardDefinitions.CRC8_BLUETOOTH),
|
||||
HashType.CRC8_CDMA2000 => new Crc(StandardDefinitions.CRC8_CDMA2000),
|
||||
HashType.CRC8_DARC => new Crc(StandardDefinitions.CRC8_DARC),
|
||||
HashType.CRC8_DVBS2 => new Crc(StandardDefinitions.CRC8_DVBS2),
|
||||
HashType.CRC8_GSMA => new Crc(StandardDefinitions.CRC8_GSMA),
|
||||
HashType.CRC8_GSMB => new Crc(StandardDefinitions.CRC8_GSMB),
|
||||
HashType.CRC8_HITAG => new Crc(StandardDefinitions.CRC8_HITAG),
|
||||
HashType.CRC8_I4321 => new Crc(StandardDefinitions.CRC8_I4321),
|
||||
HashType.CRC8_ICODE => new Crc(StandardDefinitions.CRC8_ICODE),
|
||||
HashType.CRC8_LTE => new Crc(StandardDefinitions.CRC8_LTE),
|
||||
HashType.CRC8_MAXIMDOW => new Crc(StandardDefinitions.CRC8_MAXIMDOW),
|
||||
HashType.CRC8_MIFAREMAD => new Crc(StandardDefinitions.CRC8_MIFAREMAD),
|
||||
HashType.CRC8_NRSC5 => new Crc(StandardDefinitions.CRC8_NRSC5),
|
||||
HashType.CRC8_OPENSAFETY => new Crc(StandardDefinitions.CRC8_OPENSAFETY),
|
||||
HashType.CRC8_ROHC => new Crc(StandardDefinitions.CRC8_ROHC),
|
||||
HashType.CRC8_SAEJ1850 => new Crc(StandardDefinitions.CRC8_SAEJ1850),
|
||||
HashType.CRC8_SMBUS => new Crc(StandardDefinitions.CRC8_SMBUS),
|
||||
HashType.CRC8_TECH3250 => new Crc(StandardDefinitions.CRC8_TECH3250),
|
||||
HashType.CRC8_WCDMA => new Crc(StandardDefinitions.CRC8_WCDMA),
|
||||
|
||||
HashType.CRC10_ATM => new Crc(StandardDefinitions.CRC10_ATM),
|
||||
HashType.CRC10_CDMA2000 => new Crc(StandardDefinitions.CRC10_CDMA2000),
|
||||
HashType.CRC10_GSM => new Crc(StandardDefinitions.CRC10_GSM),
|
||||
|
||||
HashType.CRC11_FLEXRAY => new Crc(StandardDefinitions.CRC11_FLEXRAY),
|
||||
HashType.CRC11_UMTS => new Crc(StandardDefinitions.CRC11_UMTS),
|
||||
|
||||
HashType.CRC12_CDMA2000 => new Crc(StandardDefinitions.CRC12_CDMA2000),
|
||||
HashType.CRC12_DECT => new Crc(StandardDefinitions.CRC12_DECT),
|
||||
HashType.CRC12_GSM => new Crc(StandardDefinitions.CRC12_GSM),
|
||||
HashType.CRC12_UMTS => new Crc(StandardDefinitions.CRC12_UMTS),
|
||||
|
||||
HashType.CRC13_BBC => new Crc(StandardDefinitions.CRC13_BBC),
|
||||
|
||||
HashType.CRC14_DARC => new Crc(StandardDefinitions.CRC14_DARC),
|
||||
HashType.CRC14_GSM => new Crc(StandardDefinitions.CRC14_GSM),
|
||||
|
||||
HashType.CRC15_CAN => new Crc(StandardDefinitions.CRC15_CAN),
|
||||
HashType.CRC15_MPT1327 => new Crc(StandardDefinitions.CRC15_MPT1327),
|
||||
|
||||
HashType.CRC16 => new Crc(StandardDefinitions.CRC16_ARC),
|
||||
HashType.CRC16_ARC => new Crc(StandardDefinitions.CRC16_ARC),
|
||||
HashType.CRC16_CDMA2000 => new Crc(StandardDefinitions.CRC16_CDMA2000),
|
||||
HashType.CRC16_CMS => new Crc(StandardDefinitions.CRC16_CMS),
|
||||
HashType.CRC16_DDS110 => new Crc(StandardDefinitions.CRC16_DDS110),
|
||||
HashType.CRC16_DECTR => new Crc(StandardDefinitions.CRC16_DECTR),
|
||||
HashType.CRC16_DECTX => new Crc(StandardDefinitions.CRC16_DECTX),
|
||||
HashType.CRC16_DNP => new Crc(StandardDefinitions.CRC16_DNP),
|
||||
HashType.CRC16_EN13757 => new Crc(StandardDefinitions.CRC16_EN13757),
|
||||
HashType.CRC16_GENIBUS => new Crc(StandardDefinitions.CRC16_GENIBUS),
|
||||
HashType.CRC16_GSM => new Crc(StandardDefinitions.CRC16_GSM),
|
||||
HashType.CRC16_IBM3740 => new Crc(StandardDefinitions.CRC16_IBM3740),
|
||||
HashType.CRC16_IBMSDLC => new Crc(StandardDefinitions.CRC16_IBMSDLC),
|
||||
HashType.CRC16_ISOIEC144433A => new Crc(StandardDefinitions.CRC16_ISOIEC144433A),
|
||||
HashType.CRC16_KERMIT => new Crc(StandardDefinitions.CRC16_KERMIT),
|
||||
HashType.CRC16_LJ1200 => new Crc(StandardDefinitions.CRC16_LJ1200),
|
||||
HashType.CRC16_M17 => new Crc(StandardDefinitions.CRC16_M17),
|
||||
HashType.CRC16_MAXIMDOW => new Crc(StandardDefinitions.CRC16_MAXIMDOW),
|
||||
HashType.CRC16_MCRF4XX => new Crc(StandardDefinitions.CRC16_MCRF4XX),
|
||||
HashType.CRC16_MODBUS => new Crc(StandardDefinitions.CRC16_MODBUS),
|
||||
HashType.CRC16_NRSC5 => new Crc(StandardDefinitions.CRC16_NRSC5),
|
||||
HashType.CRC16_OPENSAFETYA => new Crc(StandardDefinitions.CRC16_OPENSAFETYA),
|
||||
HashType.CRC16_OPENSAFETYB => new Crc(StandardDefinitions.CRC16_OPENSAFETYB),
|
||||
HashType.CRC16_PROFIBUS => new Crc(StandardDefinitions.CRC16_PROFIBUS),
|
||||
HashType.CRC16_RIELLO => new Crc(StandardDefinitions.CRC16_RIELLO),
|
||||
HashType.CRC16_SPIFUJITSU => new Crc(StandardDefinitions.CRC16_SPIFUJITSU),
|
||||
HashType.CRC16_T10DIF => new Crc(StandardDefinitions.CRC16_T10DIF),
|
||||
HashType.CRC16_TELEDISK => new Crc(StandardDefinitions.CRC16_TELEDISK),
|
||||
HashType.CRC16_TMS37157 => new Crc(StandardDefinitions.CRC16_TMS37157),
|
||||
HashType.CRC16_UMTS => new Crc(StandardDefinitions.CRC16_UMTS),
|
||||
HashType.CRC16_USB => new Crc(StandardDefinitions.CRC16_USB),
|
||||
HashType.CRC16_XMODEM => new Crc(StandardDefinitions.CRC16_XMODEM),
|
||||
|
||||
HashType.CRC17_CANFD => new Crc(StandardDefinitions.CRC17_CANFD),
|
||||
|
||||
HashType.CRC21_CANFD => new Crc(StandardDefinitions.CRC21_CANFD),
|
||||
|
||||
HashType.CRC24_BLE => new Crc(StandardDefinitions.CRC24_BLE),
|
||||
HashType.CRC24_FLEXRAYA => new Crc(StandardDefinitions.CRC24_FLEXRAYA),
|
||||
HashType.CRC24_FLEXRAYB => new Crc(StandardDefinitions.CRC24_FLEXRAYB),
|
||||
HashType.CRC24_INTERLAKEN => new Crc(StandardDefinitions.CRC24_INTERLAKEN),
|
||||
HashType.CRC24_LTEA => new Crc(StandardDefinitions.CRC24_LTEA),
|
||||
HashType.CRC24_LTEB => new Crc(StandardDefinitions.CRC24_LTEB),
|
||||
HashType.CRC24_OPENPGP => new Crc(StandardDefinitions.CRC24_OPENPGP),
|
||||
HashType.CRC24_OS9 => new Crc(StandardDefinitions.CRC24_OS9),
|
||||
|
||||
HashType.CRC30_CDMA => new Crc(StandardDefinitions.CRC30_CDMA),
|
||||
|
||||
HashType.CRC31_PHILIPS => new Crc(StandardDefinitions.CRC31_PHILIPS),
|
||||
|
||||
HashType.CRC32 => new Crc(StandardDefinitions.CRC32_ISOHDLC),
|
||||
HashType.CRC32_AIXM => new Crc(StandardDefinitions.CRC32_AIXM),
|
||||
HashType.CRC32_AUTOSAR => new Crc(StandardDefinitions.CRC32_AUTOSAR),
|
||||
HashType.CRC32_BASE91D => new Crc(StandardDefinitions.CRC32_BASE91D),
|
||||
HashType.CRC32_BZIP2 => new Crc(StandardDefinitions.CRC32_BZIP2),
|
||||
HashType.CRC32_CDROMEDC => new Crc(StandardDefinitions.CRC32_CDROMEDC),
|
||||
HashType.CRC32_CKSUM => new Crc(StandardDefinitions.CRC32_CKSUM),
|
||||
HashType.CRC32_DVDROMEDC => new Crc(StandardDefinitions.CRC32_DVDROMEDC),
|
||||
HashType.CRC32_ISCSI => new Crc(StandardDefinitions.CRC32_ISCSI),
|
||||
HashType.CRC32_ISOHDLC => new Crc(StandardDefinitions.CRC32_ISOHDLC),
|
||||
HashType.CRC32_JAMCRC => new Crc(StandardDefinitions.CRC32_JAMCRC),
|
||||
HashType.CRC32_MEF => new Crc(StandardDefinitions.CRC32_MEF),
|
||||
HashType.CRC32_MPEG2 => new Crc(StandardDefinitions.CRC32_MPEG2),
|
||||
HashType.CRC32_XFER => new Crc(StandardDefinitions.CRC32_XFER),
|
||||
|
||||
HashType.CRC40_GSM => new Crc(StandardDefinitions.CRC40_GSM),
|
||||
|
||||
HashType.CRC64 => new Crc(StandardDefinitions.CRC64_ECMA182),
|
||||
HashType.CRC64_ECMA182 => new Crc(StandardDefinitions.CRC64_ECMA182),
|
||||
HashType.CRC64_GOISO => new Crc(StandardDefinitions.CRC64_GOISO),
|
||||
HashType.CRC64_MS => new Crc(StandardDefinitions.CRC64_MS),
|
||||
HashType.CRC64_NVME => new Crc(StandardDefinitions.CRC64_NVME),
|
||||
HashType.CRC64_REDIS => new Crc(StandardDefinitions.CRC64_REDIS),
|
||||
HashType.CRC64_WE => new Crc(StandardDefinitions.CRC64_WE),
|
||||
HashType.CRC64_XZ => new Crc(StandardDefinitions.CRC64_XZ),
|
||||
|
||||
HashType.Fletcher16 => new Fletcher16(),
|
||||
HashType.Fletcher32 => new Fletcher32(),
|
||||
HashType.Fletcher64 => new Fletcher64(),
|
||||
|
||||
HashType.FNV0_32 => new FNV0_32(),
|
||||
HashType.FNV0_64 => new FNV0_64(),
|
||||
HashType.FNV1_32 => new FNV1_32(),
|
||||
HashType.FNV1_64 => new FNV1_64(),
|
||||
HashType.FNV1a_32 => new FNV1a_32(),
|
||||
HashType.FNV1a_64 => new FNV1a_64(),
|
||||
|
||||
HashType.MekaCrc => new MekaCrc(),
|
||||
|
||||
HashType.MD2 => new MD2(),
|
||||
HashType.MD4 => new MD4(),
|
||||
HashType.MD5 => MD5.Create(),
|
||||
#if NETFRAMEWORK
|
||||
HashType.RIPEMD160 => RIPEMD160.Create(),
|
||||
#endif
|
||||
|
||||
HashType.RIPEMD128 => new RipeMD128(),
|
||||
HashType.RIPEMD160 => new RipeMD160(),
|
||||
HashType.RIPEMD256 => new RipeMD256(),
|
||||
HashType.RIPEMD320 => new RipeMD320(),
|
||||
|
||||
HashType.SHA1 => SHA1.Create(),
|
||||
HashType.SHA256 => SHA256.Create(),
|
||||
HashType.SHA384 => SHA384.Create(),
|
||||
@@ -144,12 +260,27 @@ namespace SabreTools.Hashing
|
||||
HashType.SHAKE128 => Shake128.IsSupported ? new Shake128() : null,
|
||||
HashType.SHAKE256 => Shake256.IsSupported ? new Shake256() : null,
|
||||
#endif
|
||||
HashType.SpamSum => new SpamSumContext(),
|
||||
#if NET462_OR_GREATER || NETCOREAPP
|
||||
|
||||
HashType.SpamSum => new SpamSum.SpamSum(),
|
||||
|
||||
HashType.Tiger128_3 => new Tiger128_3(),
|
||||
HashType.Tiger128_4 => new Tiger128_4(),
|
||||
HashType.Tiger160_3 => new Tiger160_3(),
|
||||
HashType.Tiger160_4 => new Tiger160_4(),
|
||||
HashType.Tiger192_3 => new Tiger192_3(),
|
||||
HashType.Tiger192_4 => new Tiger192_4(),
|
||||
HashType.Tiger2_128_3 => new Tiger2_128_3(),
|
||||
HashType.Tiger2_128_4 => new Tiger2_128_4(),
|
||||
HashType.Tiger2_160_3 => new Tiger2_160_3(),
|
||||
HashType.Tiger2_160_4 => new Tiger2_160_4(),
|
||||
HashType.Tiger2_192_3 => new Tiger2_192_3(),
|
||||
HashType.Tiger2_192_4 => new Tiger2_192_4(),
|
||||
|
||||
HashType.XxHash32 => new XxHash32(),
|
||||
HashType.XxHash64 => new XxHash64(),
|
||||
HashType.XxHash3 => new XxHash3(),
|
||||
HashType.XxHash128 => new XxHash128(),
|
||||
#if NET462_OR_GREATER || NETCOREAPP
|
||||
HashType.XxHash3 => new System.IO.Hashing.XxHash3(),
|
||||
HashType.XxHash128 => new System.IO.Hashing.XxHash128(),
|
||||
#endif
|
||||
_ => null,
|
||||
};
|
||||
@@ -177,41 +308,27 @@ namespace SabreTools.Hashing
|
||||
ha.TransformBlock(buffer, offset, size, null, 0);
|
||||
break;
|
||||
|
||||
case IChecksum ic:
|
||||
byte[] icBuffer = GetArraySegment(buffer, offset, size);
|
||||
ic.Update(icBuffer);
|
||||
break;
|
||||
|
||||
case NaiveCRC nc:
|
||||
nc.Update(buffer, offset, size);
|
||||
break;
|
||||
|
||||
#if NET462_OR_GREATER || NETCOREAPP
|
||||
case NonCryptographicHashAlgorithm ncha:
|
||||
case System.IO.Hashing.NonCryptographicHashAlgorithm ncha:
|
||||
var nchaBufferSpan = new ReadOnlySpan<byte>(buffer, offset, size);
|
||||
ncha.Append(nchaBufferSpan);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case OptimizedCRC oc:
|
||||
oc.Update(buffer, offset, size);
|
||||
break;
|
||||
|
||||
case ParallelCRC pc:
|
||||
pc.Update(buffer, offset, size);
|
||||
break;
|
||||
|
||||
#if NET8_0_OR_GREATER
|
||||
case Shake128 s128:
|
||||
var s128BufferSpan = new ReadOnlySpan<byte>(buffer, offset, size);
|
||||
s128.AppendData(s128BufferSpan);
|
||||
break;
|
||||
|
||||
case Shake256 s256:
|
||||
var s256BufferSpan = new ReadOnlySpan<byte>(buffer, offset, size);
|
||||
s256.AppendData(s256BufferSpan);
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
// No-op
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,63 +344,43 @@ namespace SabreTools.Hashing
|
||||
case HashAlgorithm ha:
|
||||
ha.TransformFinalBlock(emptyBuffer, 0, 0);
|
||||
break;
|
||||
|
||||
case NaiveCRC nc:
|
||||
nc.Update([], 0, 0);
|
||||
break;
|
||||
|
||||
case OptimizedCRC oc:
|
||||
oc.Update([], 0, 0);
|
||||
break;
|
||||
|
||||
case ParallelCRC pc:
|
||||
pc.Update([], 0, 0);
|
||||
default:
|
||||
// No-op
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helpers
|
||||
|
||||
/// <summary>
|
||||
/// Convert a byte array to a hex string
|
||||
/// Get the variable-length string representing a CRC value
|
||||
/// </summary>
|
||||
/// <param name="bytes">Byte array to convert</param>
|
||||
/// <returns>Hex string representing the byte array</returns>
|
||||
/// <link>http://stackoverflow.com/questions/311165/how-do-you-convert-byte-array-to-hexadecimal-string-and-vice-versa</link>
|
||||
private static string? ByteArrayToString(byte[]? bytes)
|
||||
/// <param name="cr">Crc to get the value from</param>
|
||||
/// <returns>String representing the CRC, null on error</returns>
|
||||
private static string? GetCRCVariableLengthString(Crc cr)
|
||||
{
|
||||
// If we get null in, we send null out
|
||||
if (bytes == null)
|
||||
// Ignore null values
|
||||
if (cr.Hash is null)
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
string hex = BitConverter.ToString(bytes);
|
||||
return hex.Replace("-", string.Empty).ToLowerInvariant();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
// Get the total number of characters needed
|
||||
ulong hash = BytesToUInt64(cr.Hash);
|
||||
int length = (cr.Def.Width / 4) + (cr.Def.Width % 4 > 0 ? 1 : 0);
|
||||
return hash.ToString($"x{length}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a segment from the array based on an offset and size
|
||||
/// Get the Base64 representation of a SpamSum value
|
||||
/// </summary>
|
||||
private static byte[] GetArraySegment(byte[] buffer, int offset, int size)
|
||||
/// <param name="ss">SpamSum to get the value from</param>
|
||||
/// <returns>String representing the SpamSum, null on error</returns>
|
||||
private static string? GetSpamSumBase64String(SpamSum.SpamSum ss)
|
||||
{
|
||||
#if NET452_OR_GREATER || NETCOREAPP
|
||||
var icBufferSpan = new ReadOnlySpan<byte>(buffer, offset, size);
|
||||
byte[] trimmedBuffer = icBufferSpan.ToArray();
|
||||
#else
|
||||
byte[] trimmedBuffer = new byte[size];
|
||||
Array.Copy(buffer, offset, trimmedBuffer, 0, size);
|
||||
#endif
|
||||
return trimmedBuffer;
|
||||
// Ignore null values
|
||||
if (ss.Hash is null)
|
||||
return null;
|
||||
|
||||
return System.Text.Encoding.ASCII.GetString(ss.Hash);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
43
SabreTools.Hashing/NonCryptographicHash/Constants.cs
Normal file
43
SabreTools.Hashing/NonCryptographicHash/Constants.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
namespace SabreTools.Hashing.NonCryptographicHash
|
||||
{
|
||||
internal static class Constants
|
||||
{
|
||||
#region FNV
|
||||
|
||||
public const uint FNV32Basis = 0x811c9dc5;
|
||||
public const ulong FNV64Basis = 0xcbf29ce484222325;
|
||||
|
||||
public const uint FNV32Prime = 0x01000193;
|
||||
public const ulong FNV64Prime = 0x00000100000001b3;
|
||||
|
||||
#endregion
|
||||
|
||||
#region xxHash-32
|
||||
|
||||
public const uint XXH_PRIME32_1 = 0x9E3779B1;
|
||||
|
||||
public const uint XXH_PRIME32_2 = 0x85EBCA77;
|
||||
|
||||
public const uint XXH_PRIME32_3 = 0xC2B2AE3D;
|
||||
|
||||
public const uint XXH_PRIME32_4 = 0x27D4EB2F;
|
||||
|
||||
public const uint XXH_PRIME32_5 = 0x165667B1;
|
||||
|
||||
#endregion
|
||||
|
||||
#region xxHash-64
|
||||
|
||||
public const ulong XXH_PRIME64_1 = 0x9E3779B185EBCA87;
|
||||
|
||||
public const ulong XXH_PRIME64_2 = 0xC2B2AE3D27D4EB4F;
|
||||
|
||||
public const ulong XXH_PRIME64_3 = 0x165667B19E3779F9;
|
||||
|
||||
public const ulong XXH_PRIME64_4 = 0x85EBCA77C2B2AE63;
|
||||
|
||||
public const ulong XXH_PRIME64_5 = 0x27D4EB2F165667C5;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
26
SabreTools.Hashing/NonCryptographicHash/FNV0_32.cs
Normal file
26
SabreTools.Hashing/NonCryptographicHash/FNV0_32.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using static SabreTools.Hashing.NonCryptographicHash.Constants;
|
||||
|
||||
namespace SabreTools.Hashing.NonCryptographicHash
|
||||
{
|
||||
public class FNV0_32 : FnvBase<uint>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 32;
|
||||
|
||||
public FNV0_32()
|
||||
{
|
||||
_basis = 0;
|
||||
_prime = FNV32Prime;
|
||||
Initialize();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void HashCore(byte[] data, int offset, int length)
|
||||
{
|
||||
for (int i = offset; length > 0; i++, length--)
|
||||
{
|
||||
_hash = (_hash * _prime) ^ data[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
26
SabreTools.Hashing/NonCryptographicHash/FNV0_64.cs
Normal file
26
SabreTools.Hashing/NonCryptographicHash/FNV0_64.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using static SabreTools.Hashing.NonCryptographicHash.Constants;
|
||||
|
||||
namespace SabreTools.Hashing.NonCryptographicHash
|
||||
{
|
||||
public class FNV0_64 : FnvBase<ulong>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 64;
|
||||
|
||||
public FNV0_64()
|
||||
{
|
||||
_basis = 0;
|
||||
_prime = FNV64Prime;
|
||||
Initialize();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void HashCore(byte[] data, int offset, int length)
|
||||
{
|
||||
for (int i = offset; length > 0; i++, length--)
|
||||
{
|
||||
_hash = (_hash * _prime) ^ data[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
26
SabreTools.Hashing/NonCryptographicHash/FNV1_32.cs
Normal file
26
SabreTools.Hashing/NonCryptographicHash/FNV1_32.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using static SabreTools.Hashing.NonCryptographicHash.Constants;
|
||||
|
||||
namespace SabreTools.Hashing.NonCryptographicHash
|
||||
{
|
||||
public class FNV1_32 : FnvBase<uint>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 32;
|
||||
|
||||
public FNV1_32()
|
||||
{
|
||||
_basis = FNV32Basis;
|
||||
_prime = FNV32Prime;
|
||||
Initialize();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void HashCore(byte[] data, int offset, int length)
|
||||
{
|
||||
for (int i = offset; length > 0; i++, length--)
|
||||
{
|
||||
_hash = (_hash * _prime) ^ data[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
26
SabreTools.Hashing/NonCryptographicHash/FNV1_64.cs
Normal file
26
SabreTools.Hashing/NonCryptographicHash/FNV1_64.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using static SabreTools.Hashing.NonCryptographicHash.Constants;
|
||||
|
||||
namespace SabreTools.Hashing.NonCryptographicHash
|
||||
{
|
||||
public class FNV1_64 : FnvBase<ulong>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 64;
|
||||
|
||||
public FNV1_64()
|
||||
{
|
||||
_basis = FNV64Basis;
|
||||
_prime = FNV64Prime;
|
||||
Initialize();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void HashCore(byte[] data, int offset, int length)
|
||||
{
|
||||
for (int i = offset; length > 0; i++, length--)
|
||||
{
|
||||
_hash = (_hash * _prime) ^ data[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
26
SabreTools.Hashing/NonCryptographicHash/FNV1a_32.cs
Normal file
26
SabreTools.Hashing/NonCryptographicHash/FNV1a_32.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using static SabreTools.Hashing.NonCryptographicHash.Constants;
|
||||
|
||||
namespace SabreTools.Hashing.NonCryptographicHash
|
||||
{
|
||||
public class FNV1a_32 : FnvBase<uint>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 32;
|
||||
|
||||
public FNV1a_32()
|
||||
{
|
||||
_basis = FNV32Basis;
|
||||
_prime = FNV32Prime;
|
||||
Initialize();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void HashCore(byte[] data, int offset, int length)
|
||||
{
|
||||
for (int i = offset; length > 0; i++, length--)
|
||||
{
|
||||
_hash = (_hash ^ data[i]) * _prime;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
26
SabreTools.Hashing/NonCryptographicHash/FNV1a_64.cs
Normal file
26
SabreTools.Hashing/NonCryptographicHash/FNV1a_64.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using static SabreTools.Hashing.NonCryptographicHash.Constants;
|
||||
|
||||
namespace SabreTools.Hashing.NonCryptographicHash
|
||||
{
|
||||
public class FNV1a_64 : FnvBase<ulong>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 64;
|
||||
|
||||
public FNV1a_64()
|
||||
{
|
||||
_basis = FNV64Basis;
|
||||
_prime = FNV64Prime;
|
||||
Initialize();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void HashCore(byte[] data, int offset, int length)
|
||||
{
|
||||
for (int i = offset; length > 0; i++, length--)
|
||||
{
|
||||
_hash = (_hash ^ data[i]) * _prime;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
60
SabreTools.Hashing/NonCryptographicHash/FnvBase.cs
Normal file
60
SabreTools.Hashing/NonCryptographicHash/FnvBase.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using System;
|
||||
|
||||
namespace SabreTools.Hashing.NonCryptographicHash
|
||||
{
|
||||
/// <summary>
|
||||
/// Common base class for FNV non-cryptographic hashes
|
||||
/// </summary>
|
||||
public abstract class FnvBase : System.Security.Cryptography.HashAlgorithm
|
||||
{
|
||||
// No common, untyped functionality
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Common base class for FNV non-cryptographic hashes
|
||||
/// </summary>
|
||||
public abstract class FnvBase<T> : FnvBase where T : struct
|
||||
{
|
||||
/// <summary>
|
||||
/// Initial value to use
|
||||
/// </summary>
|
||||
protected T _basis;
|
||||
|
||||
/// <summary>
|
||||
/// Round prime to use
|
||||
/// </summary>
|
||||
protected T _prime;
|
||||
|
||||
/// <summary>
|
||||
/// The current value of the hash
|
||||
/// </summary>
|
||||
protected T _hash;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Initialize()
|
||||
{
|
||||
_hash = _basis;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
byte[] hashArr = _hash switch
|
||||
{
|
||||
short s => BitConverter.GetBytes(s),
|
||||
ushort s => BitConverter.GetBytes(s),
|
||||
|
||||
int i => BitConverter.GetBytes(i),
|
||||
uint i => BitConverter.GetBytes(i),
|
||||
|
||||
long l => BitConverter.GetBytes(l),
|
||||
ulong l => BitConverter.GetBytes(l),
|
||||
|
||||
_ => [],
|
||||
};
|
||||
|
||||
Array.Reverse(hashArr);
|
||||
return hashArr;
|
||||
}
|
||||
}
|
||||
}
|
||||
46
SabreTools.Hashing/NonCryptographicHash/XxHash32.cs
Normal file
46
SabreTools.Hashing/NonCryptographicHash/XxHash32.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
|
||||
namespace SabreTools.Hashing.NonCryptographicHash
|
||||
{
|
||||
public class XxHash32 : System.Security.Cryptography.HashAlgorithm
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 32;
|
||||
|
||||
/// <summary>
|
||||
/// The 32-bit seed to alter the hash result predictably.
|
||||
/// </summary>
|
||||
private readonly uint _seed;
|
||||
|
||||
/// <summary>
|
||||
/// Internal xxHash-32 state
|
||||
/// </summary>
|
||||
private readonly XxHash32State _state;
|
||||
|
||||
public XxHash32(uint seed = 0)
|
||||
{
|
||||
_seed = seed;
|
||||
_state = new XxHash32State();
|
||||
_state.Reset(seed);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Initialize()
|
||||
{
|
||||
_state.Reset(_seed);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void HashCore(byte[] data, int offset, int length)
|
||||
=> _state.Update(data, offset, length);
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
uint hash = _state.Digest();
|
||||
byte[] hashArr = BitConverter.GetBytes(hash);
|
||||
Array.Reverse(hashArr);
|
||||
return hashArr;
|
||||
}
|
||||
}
|
||||
}
|
||||
204
SabreTools.Hashing/NonCryptographicHash/XxHash32State.cs
Normal file
204
SabreTools.Hashing/NonCryptographicHash/XxHash32State.cs
Normal file
@@ -0,0 +1,204 @@
|
||||
using System;
|
||||
using static SabreTools.Hashing.HashOperations;
|
||||
using static SabreTools.Hashing.NonCryptographicHash.Constants;
|
||||
|
||||
namespace SabreTools.Hashing.NonCryptographicHash
|
||||
{
|
||||
/// <summary>
|
||||
/// Structure for xxHash-32 streaming API.
|
||||
/// </summary>
|
||||
/// <see href="https://github.com/Cyan4973/xxHash/blob/dev/xxhash.h"/>
|
||||
internal class XxHash32State
|
||||
{
|
||||
/// <summary>
|
||||
/// Total length hashed, modulo 2^32
|
||||
/// </summary>
|
||||
private uint _totalLen32;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the hash is >= 16 (handles <see cref="_totalLen32"/> overflow)
|
||||
/// </summary>
|
||||
private bool _largeLen;
|
||||
|
||||
/// <summary>
|
||||
/// Accumulator lanes
|
||||
/// </summary>
|
||||
private readonly uint[] _acc = new uint[4];
|
||||
|
||||
/// <summary>
|
||||
/// Internal buffer for partial reads. Treated as unsigned char[16].
|
||||
/// </summary>
|
||||
private readonly byte[] _mem32 = new byte[16];
|
||||
|
||||
/// <summary>
|
||||
/// Amount of data in <see cref="_mem32">
|
||||
/// </summary>
|
||||
private int _memsize;
|
||||
|
||||
/// <summary>
|
||||
/// Resets to begin a new hash
|
||||
/// </summary>
|
||||
/// <param name="seed">The 32-bit seed to alter the hash result predictably.</param>
|
||||
public void Reset(uint seed)
|
||||
{
|
||||
_totalLen32 = 0;
|
||||
_largeLen = false;
|
||||
|
||||
unchecked
|
||||
{
|
||||
_acc[0] = seed + XXH_PRIME32_1 + XXH_PRIME32_2;
|
||||
_acc[1] = seed + XXH_PRIME32_2;
|
||||
_acc[2] = seed + 0;
|
||||
_acc[3] = seed - XXH_PRIME32_1;
|
||||
}
|
||||
|
||||
Array.Clear(_mem32, 0, _mem32.Length);
|
||||
_memsize = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Consumes a block of input
|
||||
/// </summary>
|
||||
/// <param name="data">Byte array representing the data</param>
|
||||
/// <param name="offset">Offset in the byte array to include</param>
|
||||
/// <param name="length">Length of the data to hash</param>
|
||||
public void Update(byte[] data, int offset, int length)
|
||||
{
|
||||
int bEnd = offset + length;
|
||||
|
||||
_totalLen32 += (uint)length;
|
||||
_largeLen |= (length >= 16) | (_totalLen32 >= 16);
|
||||
|
||||
// Fill in tmp buffer
|
||||
if (_memsize + length < 16)
|
||||
{
|
||||
Array.Copy(data, offset, _mem32, _memsize, length);
|
||||
_memsize += length;
|
||||
return;
|
||||
}
|
||||
|
||||
// Some data left from previous update
|
||||
if (_memsize > 0)
|
||||
{
|
||||
Array.Copy(data, offset, _mem32, _memsize, 16 - _memsize);
|
||||
|
||||
int p32 = 0;
|
||||
_acc[0] = Round(_acc[0], ReadLE32(_mem32, p32)); p32 += 4;
|
||||
_acc[1] = Round(_acc[1], ReadLE32(_mem32, p32)); p32 += 4;
|
||||
_acc[2] = Round(_acc[2], ReadLE32(_mem32, p32)); p32 += 4;
|
||||
_acc[3] = Round(_acc[3], ReadLE32(_mem32, p32));
|
||||
|
||||
offset += 16 - _memsize;
|
||||
_memsize = 0;
|
||||
}
|
||||
|
||||
if (offset <= bEnd - 16)
|
||||
{
|
||||
int limit = bEnd - 16;
|
||||
do
|
||||
{
|
||||
_acc[0] = Round(_acc[0], ReadLE32(data, offset)); offset += 4;
|
||||
_acc[1] = Round(_acc[1], ReadLE32(data, offset)); offset += 4;
|
||||
_acc[2] = Round(_acc[2], ReadLE32(data, offset)); offset += 4;
|
||||
_acc[3] = Round(_acc[3], ReadLE32(data, offset)); offset += 4;
|
||||
} while (offset <= limit);
|
||||
}
|
||||
|
||||
if (offset < bEnd)
|
||||
{
|
||||
Array.Copy(data, offset, _mem32, 0, bEnd - offset);
|
||||
_memsize = bEnd - offset;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the calculated hash value
|
||||
/// </summary>
|
||||
/// <returns>The calculated 32-bit xxHash32 value from that state.</returns>
|
||||
public uint Digest()
|
||||
{
|
||||
uint hash;
|
||||
|
||||
if (_largeLen)
|
||||
{
|
||||
hash = RotateLeft32(_acc[0], 1)
|
||||
+ RotateLeft32(_acc[1], 7)
|
||||
+ RotateLeft32(_acc[2], 12)
|
||||
+ RotateLeft32(_acc[3], 18);
|
||||
}
|
||||
else
|
||||
{
|
||||
hash = _acc[2] /* == seed */ + XXH_PRIME32_5;
|
||||
}
|
||||
|
||||
hash += _totalLen32;
|
||||
return Finalize(hash, _mem32, 0, _memsize);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Normal stripe processing routine.
|
||||
///
|
||||
/// This shuffles the bits so that any bit from <paramref name="input"/> impacts
|
||||
/// several bits in <paramref name="acc"/>.
|
||||
/// </summary>
|
||||
/// <param name="acc">The accumulator lane.</param>
|
||||
/// <param name="input">The stripe of input to mix.</param>
|
||||
/// <returns>The mixed accumulator lane.</returns>
|
||||
private static uint Round(uint acc, uint input)
|
||||
{
|
||||
acc += input * XXH_PRIME32_2;
|
||||
acc = RotateLeft32(acc, 13);
|
||||
acc *= XXH_PRIME32_1;
|
||||
return acc;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Mixes all bits to finalize the hash.
|
||||
///
|
||||
/// The final mix ensures that all input bits have a chance to impact any bit in
|
||||
/// the output digest, resulting in an unbiased distribution.
|
||||
/// </summary>
|
||||
private static uint Avalanche(uint hash)
|
||||
{
|
||||
hash ^= hash >> 15;
|
||||
hash *= XXH_PRIME32_2;
|
||||
hash ^= hash >> 13;
|
||||
hash *= XXH_PRIME32_3;
|
||||
hash ^= hash >> 16;
|
||||
return hash;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processes the last 0-15 bytes of @p ptr.
|
||||
///
|
||||
/// There may be up to 15 bytes remaining to consume from the input.
|
||||
/// This final stage will digest them to ensure that all input bytes are present
|
||||
/// in the final mix.
|
||||
/// </summary>
|
||||
/// <param name="hash">The hash to finalize.</param>
|
||||
/// <param name="data">The remaining input.</param>
|
||||
/// <param name="offset">The pointer to the remaining input.</param>
|
||||
/// <param name="length">The remaining length, modulo 16.</param>
|
||||
/// <returns>The finalized hash.</returns>
|
||||
private static uint Finalize(uint hash, byte[] data, int offset, int length)
|
||||
{
|
||||
length &= 15;
|
||||
while (length >= 4)
|
||||
{
|
||||
hash += ReadLE32(data, offset) * XXH_PRIME32_3;
|
||||
offset += 4;
|
||||
hash = RotateLeft32(hash, 17) * XXH_PRIME32_4;
|
||||
length -= 4;
|
||||
}
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
hash += data[offset++] * XXH_PRIME32_5;
|
||||
hash = RotateLeft32(hash, 11) * XXH_PRIME32_1;
|
||||
--length;
|
||||
}
|
||||
|
||||
return Avalanche(hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
46
SabreTools.Hashing/NonCryptographicHash/XxHash64.cs
Normal file
46
SabreTools.Hashing/NonCryptographicHash/XxHash64.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
|
||||
namespace SabreTools.Hashing.NonCryptographicHash
|
||||
{
|
||||
public class XxHash64 : System.Security.Cryptography.HashAlgorithm
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override int HashSize => 64;
|
||||
|
||||
/// <summary>
|
||||
/// The 64-bit seed to alter the hash result predictably.
|
||||
/// </summary>
|
||||
private readonly uint _seed;
|
||||
|
||||
/// <summary>
|
||||
/// Internal xxHash-64 state
|
||||
/// </summary>
|
||||
private readonly XxHash64State _state;
|
||||
|
||||
public XxHash64(uint seed = 0)
|
||||
{
|
||||
_seed = seed;
|
||||
_state = new XxHash64State();
|
||||
_state.Reset(seed);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Initialize()
|
||||
{
|
||||
_state.Reset(_seed);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void HashCore(byte[] data, int offset, int length)
|
||||
=> _state.Update(data, offset, length);
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override byte[] HashFinal()
|
||||
{
|
||||
ulong hash = _state.Digest();
|
||||
byte[] hashArr = BitConverter.GetBytes(hash);
|
||||
Array.Reverse(hashArr);
|
||||
return hashArr;
|
||||
}
|
||||
}
|
||||
}
|
||||
219
SabreTools.Hashing/NonCryptographicHash/XxHash64State.cs
Normal file
219
SabreTools.Hashing/NonCryptographicHash/XxHash64State.cs
Normal file
@@ -0,0 +1,219 @@
|
||||
using System;
|
||||
using static SabreTools.Hashing.HashOperations;
|
||||
using static SabreTools.Hashing.NonCryptographicHash.Constants;
|
||||
|
||||
namespace SabreTools.Hashing.NonCryptographicHash
|
||||
{
|
||||
/// <summary>
|
||||
/// Structure for xxHash-64 streaming API.
|
||||
/// </summary>
|
||||
/// <see href="https://github.com/Cyan4973/xxHash/blob/dev/xxhash.h"/>
|
||||
internal class XxHash64State
|
||||
{
|
||||
/// <summary>
|
||||
/// Total length hashed. This is always 64-bit.
|
||||
/// </summary>
|
||||
private ulong _totalLen;
|
||||
|
||||
/// <summary>
|
||||
/// Accumulator lanes
|
||||
/// </summary>
|
||||
private readonly ulong[] _acc = new ulong[4];
|
||||
|
||||
/// <summary>
|
||||
/// Internal buffer for partial reads. Treated as unsigned char[32].
|
||||
/// </summary>
|
||||
private readonly byte[] _mem64 = new byte[32];
|
||||
|
||||
/// <summary>
|
||||
/// Amount of data in <see cref="_mem64">
|
||||
/// </summary>
|
||||
private int _memsize;
|
||||
|
||||
/// <summary>
|
||||
/// Resets to begin a new hash
|
||||
/// </summary>
|
||||
/// <param name="seed">The 64-bit seed to alter the hash result predictably.</param>
|
||||
public void Reset(ulong seed)
|
||||
{
|
||||
_totalLen = 0;
|
||||
|
||||
unchecked
|
||||
{
|
||||
_acc[0] = seed + XXH_PRIME64_1 + XXH_PRIME64_2;
|
||||
_acc[1] = seed + XXH_PRIME64_2;
|
||||
_acc[2] = seed + 0;
|
||||
_acc[3] = seed - XXH_PRIME64_1;
|
||||
}
|
||||
|
||||
Array.Clear(_mem64, 0, _mem64.Length);
|
||||
_memsize = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Consumes a block of input
|
||||
/// </summary>
|
||||
/// <param name="data">Byte array representing the data</param>
|
||||
/// <param name="offset">Offset in the byte array to include</param>
|
||||
/// <param name="length">Length of the data to hash</param>
|
||||
public void Update(byte[] data, int offset, int length)
|
||||
{
|
||||
int bEnd = offset + length;
|
||||
|
||||
_totalLen += (ulong)length;
|
||||
|
||||
// Fill in tmp buffer
|
||||
if (_memsize + length < 32)
|
||||
{
|
||||
Array.Copy(data, offset, _mem64, _memsize, length);
|
||||
_memsize += length;
|
||||
return;
|
||||
}
|
||||
|
||||
// Some data left from previous update
|
||||
if (_memsize > 0)
|
||||
{
|
||||
Array.Copy(data, offset, _mem64, _memsize, 32 - _memsize);
|
||||
|
||||
int p64 = 0;
|
||||
_acc[0] = Round(_acc[0], ReadLE64(_mem64, p64)); p64 += 8;
|
||||
_acc[1] = Round(_acc[1], ReadLE64(_mem64, p64)); p64 += 8;
|
||||
_acc[2] = Round(_acc[2], ReadLE64(_mem64, p64)); p64 += 8;
|
||||
_acc[3] = Round(_acc[3], ReadLE64(_mem64, p64));
|
||||
|
||||
offset += 32 - _memsize;
|
||||
_memsize = 0;
|
||||
}
|
||||
|
||||
if (offset <= bEnd - 32)
|
||||
{
|
||||
int limit = bEnd - 32;
|
||||
do
|
||||
{
|
||||
_acc[0] = Round(_acc[0], ReadLE64(data, offset)); offset += 8;
|
||||
_acc[1] = Round(_acc[1], ReadLE64(data, offset)); offset += 8;
|
||||
_acc[2] = Round(_acc[2], ReadLE64(data, offset)); offset += 8;
|
||||
_acc[3] = Round(_acc[3], ReadLE64(data, offset)); offset += 8;
|
||||
} while (offset <= limit);
|
||||
}
|
||||
|
||||
if (offset < bEnd)
|
||||
{
|
||||
Array.Copy(data, offset, _mem64, 0, bEnd - offset);
|
||||
_memsize = bEnd - offset;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the calculated hash value
|
||||
/// </summary>
|
||||
/// <returns>The calculated 64-bit xxHash64 value from that state.</returns>
|
||||
public ulong Digest()
|
||||
{
|
||||
ulong h64;
|
||||
|
||||
if (_totalLen >= 32)
|
||||
{
|
||||
h64 = RotateLeft64(_acc[0], 1)
|
||||
+ RotateLeft64(_acc[1], 7)
|
||||
+ RotateLeft64(_acc[2], 12)
|
||||
+ RotateLeft64(_acc[3], 18);
|
||||
h64 = MergeRound(h64, _acc[0]);
|
||||
h64 = MergeRound(h64, _acc[1]);
|
||||
h64 = MergeRound(h64, _acc[2]);
|
||||
h64 = MergeRound(h64, _acc[3]);
|
||||
}
|
||||
else
|
||||
{
|
||||
h64 = _acc[2] /*seed*/ + XXH_PRIME64_5;
|
||||
}
|
||||
|
||||
h64 += _totalLen;
|
||||
return Finalize(h64, _mem64, 0, (int)_totalLen);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Normal stripe processing routine.
|
||||
///
|
||||
/// This shuffles the bits so that any bit from @p input impacts
|
||||
/// several bits in @p acc.
|
||||
/// </summary>
|
||||
/// <param name="acc">The accumulator lane.</param>
|
||||
/// <param name="input">The stripe of input to mix.</param>
|
||||
/// <returns>The mixed accumulator lane.</returns>
|
||||
private static ulong Round(ulong acc, ulong input)
|
||||
{
|
||||
acc += unchecked(input * XXH_PRIME64_2);
|
||||
acc = RotateLeft64(acc, 31);
|
||||
acc *= XXH_PRIME64_1;
|
||||
return acc;
|
||||
}
|
||||
|
||||
private static ulong MergeRound(ulong acc, ulong val)
|
||||
{
|
||||
val = Round(0, val);
|
||||
acc ^= val;
|
||||
acc = (acc * XXH_PRIME64_1) + XXH_PRIME64_4;
|
||||
return acc;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processes the last 0-31 bytes of @p ptr.
|
||||
///
|
||||
/// There may be up to 31 bytes remaining to consume from the input.
|
||||
/// This final stage will digest them to ensure that all input bytes are present
|
||||
/// in the final mix.
|
||||
/// </summary>
|
||||
/// <param name="hash">The hash to finalize.</param>
|
||||
/// <param name="data">The pointer to the remaining input.</param>
|
||||
/// <param name="offset">The pointer to the remaining input.</param>
|
||||
/// <param name="length">The remaining length, modulo 32.</param>
|
||||
/// <param name="align">Whether @p ptr is aligned.</param>
|
||||
/// <returns>The finalized hash</returns>
|
||||
private static ulong Finalize(ulong hash, byte[] data, int offset, int length)
|
||||
{
|
||||
length &= 31;
|
||||
while (length >= 8)
|
||||
{
|
||||
ulong k1 = Round(0, ReadLE64(data, offset));
|
||||
offset += 8;
|
||||
hash ^= k1;
|
||||
hash = (RotateLeft64(hash, 27) * XXH_PRIME64_1) + XXH_PRIME64_4;
|
||||
length -= 8;
|
||||
}
|
||||
|
||||
if (length >= 4)
|
||||
{
|
||||
hash ^= ReadLE32(data, offset) * XXH_PRIME64_1;
|
||||
offset += 4;
|
||||
hash = (RotateLeft64(hash, 23) * XXH_PRIME64_2) + XXH_PRIME64_3;
|
||||
length -= 4;
|
||||
}
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
hash ^= data[offset++] * XXH_PRIME64_5;
|
||||
hash = RotateLeft64(hash, 11) * XXH_PRIME64_1;
|
||||
--length;
|
||||
}
|
||||
|
||||
return Avalanche(hash);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Mixes all bits to finalize the hash.
|
||||
///
|
||||
/// The final mix ensures that all input bits have a chance to impact any bit in
|
||||
/// the output digest, resulting in an unbiased distribution.
|
||||
/// </summary>
|
||||
private static ulong Avalanche(ulong hash)
|
||||
{
|
||||
hash ^= hash >> 33;
|
||||
hash *= XXH_PRIME64_2;
|
||||
hash ^= hash >> 29;
|
||||
hash *= XXH_PRIME64_3;
|
||||
hash ^= hash >> 32;
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,54 +1,37 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- Assembly Properties -->
|
||||
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64</RuntimeIdentifiers>
|
||||
<CheckEolTargetFramework>false</CheckEolTargetFramework>
|
||||
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<Version>1.2.1</Version>
|
||||
<WarningsNotAsErrors>NU5104</WarningsNotAsErrors>
|
||||
<PropertyGroup>
|
||||
<!-- Assembly Properties -->
|
||||
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0;net9.0;net10.0;netstandard2.0;netstandard2.1</TargetFrameworks>
|
||||
<CheckEolTargetFramework>false</CheckEolTargetFramework>
|
||||
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<Version>1.6.0</Version>
|
||||
|
||||
<!-- Package Properties -->
|
||||
<Authors>Matt Nadareski</Authors>
|
||||
<Copyright>Copyright (c)2016-2024 Matt Nadareski</Copyright>
|
||||
<PackageProjectUrl>https://github.com/SabreTools/</PackageProjectUrl>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
<RepositoryUrl>https://github.com/SabreTools/SabreTools.Hashing</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<PackageTags>hash hashing checksum checksumming crc md5 sha1</PackageTags>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
</PropertyGroup>
|
||||
<!-- Package Properties -->
|
||||
<Authors>Matt Nadareski</Authors>
|
||||
<Copyright>Copyright (c)2016-2025 Matt Nadareski</Copyright>
|
||||
<PackageProjectUrl>https://github.com/SabreTools/</PackageProjectUrl>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
<RepositoryUrl>https://github.com/SabreTools/SabreTools.Hashing</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<PackageTags>hash hashing checksum checksumming crc md5 sha1</PackageTags>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="../README.md" Pack="true" PackagePath="" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="../README.md" Pack="true" PackagePath="" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Support for old .NET versions -->
|
||||
<ItemGroup Condition="$(TargetFramework.StartsWith(`net2`)) OR $(TargetFramework.StartsWith(`net3`))">
|
||||
<PackageReference Include="Net30.LinqBridge" Version="1.3.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="$(TargetFramework.StartsWith(`net2`)) OR $(TargetFramework.StartsWith(`net3`)) OR $(TargetFramework.StartsWith(`net40`))">
|
||||
<PackageReference Include="MinAsyncBridge" Version="0.12.4" />
|
||||
<PackageReference Include="MinTasksExtensionsBridge" Version="0.3.4" />
|
||||
<PackageReference Include="MinThreadingBridge" Version="0.11.4" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="$(TargetFramework.StartsWith(`net45`)) OR $(TargetFramework.StartsWith(`net46`)) OR $(TargetFramework.StartsWith(`net47`)) OR $(TargetFramework.StartsWith(`net48`))">
|
||||
<PackageReference Include="System.Memory" Version="4.5.5" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="!$(TargetFramework.StartsWith(`net2`)) AND !$(TargetFramework.StartsWith(`net3`)) AND !$(TargetFramework.StartsWith(`net40`)) AND !$(TargetFramework.StartsWith(`net45`))">
|
||||
<PackageReference Include="System.IO.Hashing" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="$(TargetFramework.StartsWith(`net7`)) OR $(TargetFramework.StartsWith(`net8`))">
|
||||
<PackageReference Include="Blake3" Version="1.1.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Aaru.Checksums.Native" Version="6.0.0-alpha9"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Blake3" Version="1.1.0" Condition="$(TargetFramework.StartsWith(`net7`))" />
|
||||
<PackageReference Include="Blake3" Version="2.0.0" Condition="$(TargetFramework.StartsWith(`net8`)) OR $(TargetFramework.StartsWith(`net9`)) OR $(TargetFramework.StartsWith(`net10`))" />
|
||||
<PackageReference Include="System.IO.Hashing" Version="10.0.0" Condition="!$(TargetFramework.StartsWith(`net2`)) AND !$(TargetFramework.StartsWith(`net3`)) AND !$(TargetFramework.StartsWith(`net40`)) AND !$(TargetFramework.StartsWith(`net45`))" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
</Project>
|
||||
45
SabreTools.Hashing/SpamSum/BlockhashContext.cs
Normal file
45
SabreTools.Hashing/SpamSum/BlockhashContext.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using static SabreTools.Hashing.SpamSum.Constants;
|
||||
|
||||
namespace SabreTools.Hashing.SpamSum
|
||||
{
|
||||
/// <summary>
|
||||
/// A blockhash contains a signature state for a specific (implicit) blocksize.
|
||||
/// The blocksize is given by <see cref="SSDEEP_BS(uint)"/>
|
||||
/// </summary>
|
||||
/// <see href="https://github.com/ssdeep-project/ssdeep/blob/master/fuzzy.c"/>
|
||||
internal class BlockhashContext
|
||||
{
|
||||
/// <summary>
|
||||
/// Current digest length
|
||||
/// </summary>
|
||||
public uint DIndex { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Current message digest
|
||||
/// </summary>
|
||||
public byte[] Digest { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Digest value at <see cref="HalfH"/>
|
||||
/// </summary>
|
||||
public byte HalfDigest { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Partial FNV hash
|
||||
/// </summary>
|
||||
public byte H { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Partial FNV hash reset after <see cref="Digest"/> is
|
||||
/// <see cref="SPAMSUM_LENGTH"/> / 2 long. This is needed
|
||||
/// to be able to truncate digest for the second output hash
|
||||
/// to stay compatible with ssdeep output.
|
||||
/// </summary>
|
||||
public byte HalfH { get; set; }
|
||||
|
||||
public BlockhashContext()
|
||||
{
|
||||
Digest = new byte[SPAMSUM_LENGTH];
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user