sha67 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
sha67-0.1.0/Cargo.lock ADDED
@@ -0,0 +1,370 @@
1
+ # This file is automatically @generated by Cargo.
2
+ # It is not intended for manual editing.
3
+ version = 4
4
+
5
+ [[package]]
6
+ name = "autocfg"
7
+ version = "1.5.1"
8
+ source = "registry+https://github.com/rust-lang/crates.io-index"
9
+ checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
10
+
11
+ [[package]]
12
+ name = "bitflags"
13
+ version = "2.11.1"
14
+ source = "registry+https://github.com/rust-lang/crates.io-index"
15
+ checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3"
16
+
17
+ [[package]]
18
+ name = "block-buffer"
19
+ version = "0.10.4"
20
+ source = "registry+https://github.com/rust-lang/crates.io-index"
21
+ checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
22
+ dependencies = [
23
+ "generic-array",
24
+ ]
25
+
26
+ [[package]]
27
+ name = "cfg-if"
28
+ version = "1.0.4"
29
+ source = "registry+https://github.com/rust-lang/crates.io-index"
30
+ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
31
+
32
+ [[package]]
33
+ name = "cpufeatures"
34
+ version = "0.2.17"
35
+ source = "registry+https://github.com/rust-lang/crates.io-index"
36
+ checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
37
+ dependencies = [
38
+ "libc",
39
+ ]
40
+
41
+ [[package]]
42
+ name = "crypto-common"
43
+ version = "0.1.7"
44
+ source = "registry+https://github.com/rust-lang/crates.io-index"
45
+ checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
46
+ dependencies = [
47
+ "generic-array",
48
+ "typenum",
49
+ ]
50
+
51
+ [[package]]
52
+ name = "digest"
53
+ version = "0.10.7"
54
+ source = "registry+https://github.com/rust-lang/crates.io-index"
55
+ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
56
+ dependencies = [
57
+ "block-buffer",
58
+ "crypto-common",
59
+ ]
60
+
61
+ [[package]]
62
+ name = "generic-array"
63
+ version = "0.14.7"
64
+ source = "registry+https://github.com/rust-lang/crates.io-index"
65
+ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
66
+ dependencies = [
67
+ "typenum",
68
+ "version_check",
69
+ ]
70
+
71
+ [[package]]
72
+ name = "heck"
73
+ version = "0.4.1"
74
+ source = "registry+https://github.com/rust-lang/crates.io-index"
75
+ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
76
+
77
+ [[package]]
78
+ name = "hex"
79
+ version = "0.4.3"
80
+ source = "registry+https://github.com/rust-lang/crates.io-index"
81
+ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
82
+
83
+ [[package]]
84
+ name = "indoc"
85
+ version = "2.0.7"
86
+ source = "registry+https://github.com/rust-lang/crates.io-index"
87
+ checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706"
88
+ dependencies = [
89
+ "rustversion",
90
+ ]
91
+
92
+ [[package]]
93
+ name = "libc"
94
+ version = "0.2.186"
95
+ source = "registry+https://github.com/rust-lang/crates.io-index"
96
+ checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
97
+
98
+ [[package]]
99
+ name = "lock_api"
100
+ version = "0.4.14"
101
+ source = "registry+https://github.com/rust-lang/crates.io-index"
102
+ checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
103
+ dependencies = [
104
+ "scopeguard",
105
+ ]
106
+
107
+ [[package]]
108
+ name = "memoffset"
109
+ version = "0.9.1"
110
+ source = "registry+https://github.com/rust-lang/crates.io-index"
111
+ checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
112
+ dependencies = [
113
+ "autocfg",
114
+ ]
115
+
116
+ [[package]]
117
+ name = "num-bigint"
118
+ version = "0.4.6"
119
+ source = "registry+https://github.com/rust-lang/crates.io-index"
120
+ checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
121
+ dependencies = [
122
+ "num-integer",
123
+ "num-traits",
124
+ "rand",
125
+ ]
126
+
127
+ [[package]]
128
+ name = "num-integer"
129
+ version = "0.1.46"
130
+ source = "registry+https://github.com/rust-lang/crates.io-index"
131
+ checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
132
+ dependencies = [
133
+ "num-traits",
134
+ ]
135
+
136
+ [[package]]
137
+ name = "num-traits"
138
+ version = "0.2.19"
139
+ source = "registry+https://github.com/rust-lang/crates.io-index"
140
+ checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
141
+ dependencies = [
142
+ "autocfg",
143
+ ]
144
+
145
+ [[package]]
146
+ name = "once_cell"
147
+ version = "1.21.4"
148
+ source = "registry+https://github.com/rust-lang/crates.io-index"
149
+ checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
150
+
151
+ [[package]]
152
+ name = "parking_lot"
153
+ version = "0.12.5"
154
+ source = "registry+https://github.com/rust-lang/crates.io-index"
155
+ checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
156
+ dependencies = [
157
+ "lock_api",
158
+ "parking_lot_core",
159
+ ]
160
+
161
+ [[package]]
162
+ name = "parking_lot_core"
163
+ version = "0.9.12"
164
+ source = "registry+https://github.com/rust-lang/crates.io-index"
165
+ checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
166
+ dependencies = [
167
+ "cfg-if",
168
+ "libc",
169
+ "redox_syscall",
170
+ "smallvec",
171
+ "windows-link",
172
+ ]
173
+
174
+ [[package]]
175
+ name = "portable-atomic"
176
+ version = "1.13.1"
177
+ source = "registry+https://github.com/rust-lang/crates.io-index"
178
+ checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
179
+
180
+ [[package]]
181
+ name = "proc-macro2"
182
+ version = "1.0.106"
183
+ source = "registry+https://github.com/rust-lang/crates.io-index"
184
+ checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
185
+ dependencies = [
186
+ "unicode-ident",
187
+ ]
188
+
189
+ [[package]]
190
+ name = "pyo3"
191
+ version = "0.21.2"
192
+ source = "registry+https://github.com/rust-lang/crates.io-index"
193
+ checksum = "a5e00b96a521718e08e03b1a622f01c8a8deb50719335de3f60b3b3950f069d8"
194
+ dependencies = [
195
+ "cfg-if",
196
+ "indoc",
197
+ "libc",
198
+ "memoffset",
199
+ "parking_lot",
200
+ "portable-atomic",
201
+ "pyo3-build-config",
202
+ "pyo3-ffi",
203
+ "pyo3-macros",
204
+ "unindent",
205
+ ]
206
+
207
+ [[package]]
208
+ name = "pyo3-build-config"
209
+ version = "0.21.2"
210
+ source = "registry+https://github.com/rust-lang/crates.io-index"
211
+ checksum = "7883df5835fafdad87c0d888b266c8ec0f4c9ca48a5bed6bbb592e8dedee1b50"
212
+ dependencies = [
213
+ "once_cell",
214
+ "target-lexicon",
215
+ ]
216
+
217
+ [[package]]
218
+ name = "pyo3-ffi"
219
+ version = "0.21.2"
220
+ source = "registry+https://github.com/rust-lang/crates.io-index"
221
+ checksum = "01be5843dc60b916ab4dad1dca6d20b9b4e6ddc8e15f50c47fe6d85f1fb97403"
222
+ dependencies = [
223
+ "libc",
224
+ "pyo3-build-config",
225
+ ]
226
+
227
+ [[package]]
228
+ name = "pyo3-macros"
229
+ version = "0.21.2"
230
+ source = "registry+https://github.com/rust-lang/crates.io-index"
231
+ checksum = "77b34069fc0682e11b31dbd10321cbf94808394c56fd996796ce45217dfac53c"
232
+ dependencies = [
233
+ "proc-macro2",
234
+ "pyo3-macros-backend",
235
+ "quote",
236
+ "syn",
237
+ ]
238
+
239
+ [[package]]
240
+ name = "pyo3-macros-backend"
241
+ version = "0.21.2"
242
+ source = "registry+https://github.com/rust-lang/crates.io-index"
243
+ checksum = "08260721f32db5e1a5beae69a55553f56b99bd0e1c3e6e0a5e8851a9d0f5a85c"
244
+ dependencies = [
245
+ "heck",
246
+ "proc-macro2",
247
+ "pyo3-build-config",
248
+ "quote",
249
+ "syn",
250
+ ]
251
+
252
+ [[package]]
253
+ name = "quote"
254
+ version = "1.0.45"
255
+ source = "registry+https://github.com/rust-lang/crates.io-index"
256
+ checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
257
+ dependencies = [
258
+ "proc-macro2",
259
+ ]
260
+
261
+ [[package]]
262
+ name = "rand"
263
+ version = "0.8.6"
264
+ source = "registry+https://github.com/rust-lang/crates.io-index"
265
+ checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a"
266
+ dependencies = [
267
+ "rand_core",
268
+ ]
269
+
270
+ [[package]]
271
+ name = "rand_core"
272
+ version = "0.6.4"
273
+ source = "registry+https://github.com/rust-lang/crates.io-index"
274
+ checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
275
+
276
+ [[package]]
277
+ name = "redox_syscall"
278
+ version = "0.5.18"
279
+ source = "registry+https://github.com/rust-lang/crates.io-index"
280
+ checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
281
+ dependencies = [
282
+ "bitflags",
283
+ ]
284
+
285
+ [[package]]
286
+ name = "rustversion"
287
+ version = "1.0.22"
288
+ source = "registry+https://github.com/rust-lang/crates.io-index"
289
+ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
290
+
291
+ [[package]]
292
+ name = "scopeguard"
293
+ version = "1.2.0"
294
+ source = "registry+https://github.com/rust-lang/crates.io-index"
295
+ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
296
+
297
+ [[package]]
298
+ name = "sha2"
299
+ version = "0.10.9"
300
+ source = "registry+https://github.com/rust-lang/crates.io-index"
301
+ checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
302
+ dependencies = [
303
+ "cfg-if",
304
+ "cpufeatures",
305
+ "digest",
306
+ ]
307
+
308
+ [[package]]
309
+ name = "sha67"
310
+ version = "0.1.0"
311
+ dependencies = [
312
+ "hex",
313
+ "num-bigint",
314
+ "num-traits",
315
+ "pyo3",
316
+ "sha2",
317
+ ]
318
+
319
+ [[package]]
320
+ name = "smallvec"
321
+ version = "1.15.1"
322
+ source = "registry+https://github.com/rust-lang/crates.io-index"
323
+ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
324
+
325
+ [[package]]
326
+ name = "syn"
327
+ version = "2.0.117"
328
+ source = "registry+https://github.com/rust-lang/crates.io-index"
329
+ checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
330
+ dependencies = [
331
+ "proc-macro2",
332
+ "quote",
333
+ "unicode-ident",
334
+ ]
335
+
336
+ [[package]]
337
+ name = "target-lexicon"
338
+ version = "0.12.16"
339
+ source = "registry+https://github.com/rust-lang/crates.io-index"
340
+ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
341
+
342
+ [[package]]
343
+ name = "typenum"
344
+ version = "1.20.1"
345
+ source = "registry+https://github.com/rust-lang/crates.io-index"
346
+ checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20"
347
+
348
+ [[package]]
349
+ name = "unicode-ident"
350
+ version = "1.0.24"
351
+ source = "registry+https://github.com/rust-lang/crates.io-index"
352
+ checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
353
+
354
+ [[package]]
355
+ name = "unindent"
356
+ version = "0.2.4"
357
+ source = "registry+https://github.com/rust-lang/crates.io-index"
358
+ checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3"
359
+
360
+ [[package]]
361
+ name = "version_check"
362
+ version = "0.9.5"
363
+ source = "registry+https://github.com/rust-lang/crates.io-index"
364
+ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
365
+
366
+ [[package]]
367
+ name = "windows-link"
368
+ version = "0.2.1"
369
+ source = "registry+https://github.com/rust-lang/crates.io-index"
370
+ checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
sha67-0.1.0/Cargo.toml ADDED
@@ -0,0 +1,22 @@
1
+ [package]
2
+ name = "sha67"
3
+ version = "0.1.0"
4
+ edition = "2024"
5
+
6
+ [lib]
7
+ name = "sha67"
8
+ crate-type = ["cdylib", "rlib"]
9
+
10
+ [dependencies]
11
+ pyo3 = { version = "0.21.2", features = ["extension-module", "abi3-py37"], optional = true }
12
+ sha2 = "0.10.8"
13
+ num-bigint = { version = "0.4.4", features = ["rand"] }
14
+ num-traits = "0.2.19"
15
+ hex = "0.4.3"
16
+
17
+ [features]
18
+ default = []
19
+ python = ["dep:pyo3"]
20
+
21
+ [package.metadata.maturin]
22
+ features = ["python"]
sha67-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,8 @@
1
+ Metadata-Version: 2.4
2
+ Name: sha67
3
+ Version: 0.1.0
4
+ Classifier: Programming Language :: Rust
5
+ Classifier: Programming Language :: Python :: Implementation :: CPython
6
+ Classifier: Topic :: Security :: Cryptography
7
+ Summary: Premium SHA-67 Hashing Cryptographic Module in Rust
8
+ Requires-Python: >=3.7
sha67-0.1.0/check.log ADDED
@@ -0,0 +1,222 @@
1
+ Checking sha67 v0.1.0 (/Users/lagos/code/sha67)
2
+ error[E0428]: the name `sha67` is defined multiple times
3
+ --> src/lib.rs:231:1
4
+ |
5
+ 153 | fn sha67(data: &Bound<'_, PyAny>) -> PyResult<String> {
6
+ | ----------------------------------------------------- previous definition of the value `sha67` here
7
+ ...
8
+ 231 | fn sha67(m: &Bound<'_, PyModule>) -> PyResult<()> {
9
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `sha67` redefined here
10
+ |
11
+ = note: `sha67` must be defined only once in the value namespace of this module
12
+
13
+ error[E0428]: the name `sha67` is defined multiple times
14
+ --> src/lib.rs:230:1
15
+ |
16
+ 152 | #[pyfunction]
17
+ | ------------- previous definition of the module `sha67` here
18
+ ...
19
+ 230 | #[pymodule]
20
+ | ^^^^^^^^^^^ `sha67` redefined here
21
+ |
22
+ = note: `sha67` must be defined only once in the type namespace of this module
23
+ = note: this error originates in the attribute macro `pymodule` (in Nightly builds, run with -Z macro-backtrace for more info)
24
+
25
+ error[E0425]: cannot find value `__PYO3_NAME` in module `sha67`
26
+ --> src/lib.rs:230:1
27
+ |
28
+ 230 | #[pymodule]
29
+ | ^^^^^^^^^^^ not found in `sha67`
30
+ |
31
+ = note: this error originates in the attribute macro `pymodule` (in Nightly builds, run with -Z macro-backtrace for more info)
32
+
33
+ error[E0599]: no function or associated item named `from_bytes_be_bound` found for struct `PyInt` in the current scope
34
+ --> src/lib.rs:135:34
35
+ |
36
+ 135 | let py_int = PyLong::from_bytes_be_bound(py, &bytes).unwrap();
37
+ | ^^^^^^^^^^^^^^^^^^^ function or associated item not found in `PyInt`
38
+
39
+ error[E0599]: no function or associated item named `from_bytes_be_bound` found for struct `PyInt` in the current scope
40
+ --> src/lib.rs:171:30
41
+ |
42
+ 171 | let py_int = PyLong::from_bytes_be_bound(py, &big_bytes).unwrap();
43
+ | ^^^^^^^^^^^^^^^^^^^ function or associated item not found in `PyInt`
44
+
45
+ error[E0599]: no function or associated item named `make_def` found for struct `sha67::MakeDef` in the current scope
46
+ --> src/lib.rs:230:1
47
+ |
48
+ 230 | #[pymodule]
49
+ | ^^^^^^^^^^^
50
+ | |
51
+ | function or associated item not found in `sha67::MakeDef`
52
+ | function or associated item `make_def` not found for this struct
53
+ |
54
+ = note: this error originates in the attribute macro `pymodule` (in Nightly builds, run with -Z macro-backtrace for more info)
55
+
56
+ error[E0277]: the trait bound `&pyo3::Bound<'_, pyo3::PyAny>: From<pyo3::impl_::pymethods::BoundRef<'_, '_, pyo3::prelude::PyModule>>` is not satisfied
57
+ --> src/lib.rs:230:1
58
+ |
59
+ 230 | #[pymodule]
60
+ | ^^^^^^^^^^^ the trait `From<pyo3::impl_::pymethods::BoundRef<'_, '_, pyo3::prelude::PyModule>>` is not implemented for `&pyo3::Bound<'_, pyo3::PyAny>`
61
+ |
62
+ help: the following other types implement trait `From<T>`
63
+ --> /Users/lagos/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/pyo3-0.21.2/src/impl_/pymethods.rs:545:1
64
+ |
65
+ 545 | impl<'a, 'py, T> From<BoundRef<'a, 'py, T>> for Bound<'py, T> {
66
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `pyo3::Bound<'_, T>`
67
+ ...
68
+ 552 | impl<'a, 'py, T> From<BoundRef<'a, 'py, T>> for &'a Bound<'py, T> {
69
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&pyo3::Bound<'_, T>`
70
+ = note: required for `pyo3::impl_::pymethods::BoundRef<'_, '_, pyo3::prelude::PyModule>` to implement `Into<&pyo3::Bound<'_, pyo3::PyAny>>`
71
+ = note: this error originates in the attribute macro `pymodule` (in Nightly builds, run with -Z macro-backtrace for more info)
72
+
73
+ error[E0308]: mismatched types
74
+ --> src/lib.rs:230:1
75
+ |
76
+ 230 | #[pymodule]
77
+ | ^^^^^^^^^^^
78
+ | |
79
+ | expected `Result<(), PyErr>`, found `Result<String, PyErr>`
80
+ | expected `Result<(), PyErr>` because of return type
81
+ |
82
+ = note: expected enum `Result<(), _>`
83
+ found enum `Result<String, _>`
84
+ = note: this error originates in the attribute macro `pymodule` (in Nightly builds, run with -Z macro-backtrace for more info)
85
+
86
+ warning[E0133]: call to unsafe function `pyo3::impl_::pymethods::BoundRef::<'a, 'py, pyo3::PyAny>::ref_from_ptr` is unsafe and requires unsafe block
87
+ --> src/lib.rs:81:15
88
+ |
89
+ 81 | fn update(&mut self, data: &Bound<'_, PyAny>) -> PyResult<()> {
90
+ | ^ call to unsafe function
91
+ |
92
+ = note: consult the function's documentation for information on how to avoid undefined behavior
93
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
94
+ = note: `#[warn(unsafe_op_in_unsafe_fn)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
95
+
96
+ warning[E0133]: call to unsafe function `pyo3::impl_::extract_argument::unwrap_required_argument` is unsafe and requires unsafe block
97
+ --> src/lib.rs:81:32
98
+ |
99
+ 81 | fn update(&mut self, data: &Bound<'_, PyAny>) -> PyResult<()> {
100
+ | ^ call to unsafe function
101
+ |
102
+ = note: consult the function's documentation for information on how to avoid undefined behavior
103
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
104
+
105
+ warning[E0133]: call to unsafe function `pyo3::impl_::pymethods::BoundRef::<'a, 'py, pyo3::PyAny>::ref_from_ptr` is unsafe and requires unsafe block
106
+ --> src/lib.rs:89:15
107
+ |
108
+ 89 | fn digest(&self) -> PyObject {
109
+ | ^ call to unsafe function
110
+ |
111
+ = note: consult the function's documentation for information on how to avoid undefined behavior
112
+ note: an unsafe function restricts its caller, but its body is safe by default
113
+ --> src/lib.rs:66:1
114
+ |
115
+ 66 | #[pymethods]
116
+ | ^^^^^^^^^^^^
117
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
118
+ = note: this warning originates in the attribute macro `pymethods` (in Nightly builds, run with -Z macro-backtrace for more info)
119
+
120
+ warning[E0133]: call to unsafe function `pyo3::impl_::pymethods::BoundRef::<'a, 'py, pyo3::PyAny>::ref_from_ptr` is unsafe and requires unsafe block
121
+ --> src/lib.rs:106:18
122
+ |
123
+ 106 | fn hexdigest(&self) -> String {
124
+ | ^ call to unsafe function
125
+ |
126
+ = note: consult the function's documentation for information on how to avoid undefined behavior
127
+ note: an unsafe function restricts its caller, but its body is safe by default
128
+ --> src/lib.rs:66:1
129
+ |
130
+ 66 | #[pymethods]
131
+ | ^^^^^^^^^^^^
132
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
133
+ = note: this warning originates in the attribute macro `pymethods` (in Nightly builds, run with -Z macro-backtrace for more info)
134
+
135
+ warning[E0133]: call to unsafe function `pyo3::impl_::pymethods::BoundRef::<'a, 'py, pyo3::PyAny>::ref_from_ptr` is unsafe and requires unsafe block
136
+ --> src/lib.rs:120:21
137
+ |
138
+ 120 | fn base67digest(&self) -> String {
139
+ | ^ call to unsafe function
140
+ |
141
+ = note: consult the function's documentation for information on how to avoid undefined behavior
142
+ note: an unsafe function restricts its caller, but its body is safe by default
143
+ --> src/lib.rs:66:1
144
+ |
145
+ 66 | #[pymethods]
146
+ | ^^^^^^^^^^^^
147
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
148
+ = note: this warning originates in the attribute macro `pymethods` (in Nightly builds, run with -Z macro-backtrace for more info)
149
+
150
+ warning[E0133]: call to unsafe function `pyo3::impl_::pymethods::BoundRef::<'a, 'py, pyo3::PyAny>::ref_from_ptr` is unsafe and requires unsafe block
151
+ --> src/lib.rs:128:18
152
+ |
153
+ 128 | fn intdigest(&self) -> PyObject {
154
+ | ^ call to unsafe function
155
+ |
156
+ = note: consult the function's documentation for information on how to avoid undefined behavior
157
+ note: an unsafe function restricts its caller, but its body is safe by default
158
+ --> src/lib.rs:66:1
159
+ |
160
+ 66 | #[pymethods]
161
+ | ^^^^^^^^^^^^
162
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
163
+ = note: this warning originates in the attribute macro `pymethods` (in Nightly builds, run with -Z macro-backtrace for more info)
164
+
165
+ warning[E0133]: call to unsafe function `pyo3::impl_::extract_argument::unwrap_required_argument` is unsafe and requires unsafe block
166
+ --> src/lib.rs:153:16
167
+ |
168
+ 153 | fn sha67(data: &Bound<'_, PyAny>) -> PyResult<String> {
169
+ | ^ call to unsafe function
170
+ |
171
+ = note: consult the function's documentation for information on how to avoid undefined behavior
172
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
173
+
174
+ warning[E0133]: call to unsafe function `pyo3::impl_::extract_argument::unwrap_required_argument` is unsafe and requires unsafe block
175
+ --> src/lib.rs:161:20
176
+ |
177
+ 161 | fn sha67_int(data: &Bound<'_, PyAny>) -> PyResult<PyObject> {
178
+ | ^ call to unsafe function
179
+ |
180
+ = note: consult the function's documentation for information on how to avoid undefined behavior
181
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
182
+
183
+ warning[E0133]: call to unsafe function `pyo3::impl_::extract_argument::unwrap_required_argument` is unsafe and requires unsafe block
184
+ --> src/lib.rs:178:22
185
+ |
186
+ 178 | fn sha67_bytes(data: &Bound<'_, PyAny>) -> PyResult<PyObject> {
187
+ | ^ call to unsafe function
188
+ |
189
+ = note: consult the function's documentation for information on how to avoid undefined behavior
190
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
191
+
192
+ warning[E0133]: call to unsafe function `pyo3::impl_::extract_argument::unwrap_required_argument` is unsafe and requires unsafe block
193
+ --> src/lib.rs:200:15
194
+ |
195
+ 200 | password: &Bound<'_, PyAny>,
196
+ | ^ call to unsafe function
197
+ |
198
+ = note: consult the function's documentation for information on how to avoid undefined behavior
199
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
200
+
201
+ warning[E0133]: call to unsafe function `pyo3::impl_::extract_argument::unwrap_required_argument` is unsafe and requires unsafe block
202
+ --> src/lib.rs:201:11
203
+ |
204
+ 201 | salt: &Bound<'_, PyAny>,
205
+ | ^ call to unsafe function
206
+ |
207
+ = note: consult the function's documentation for information on how to avoid undefined behavior
208
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
209
+
210
+ warning[E0133]: call to unsafe function `pyo3::impl_::extract_argument::unwrap_required_argument` is unsafe and requires unsafe block
211
+ --> src/lib.rs:202:17
212
+ |
213
+ 202 | iterations: u32,
214
+ | ^^^ call to unsafe function
215
+ |
216
+ = note: consult the function's documentation for information on how to avoid undefined behavior
217
+ = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
218
+
219
+ Some errors have detailed explanations: E0133, E0277, E0308, E0425, E0428, E0599.
220
+ For more information about an error, try `rustc --explain E0133`.
221
+ warning: `sha67` (lib) generated 12 warnings
222
+ error: could not compile `sha67` (lib) due to 8 previous errors; 12 warnings emitted
sha67-0.1.0/demo.py ADDED
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ SHA-67 Hashing Demonstration
4
+ This script shows how to import the Rust-compiled `sha67` library in Python
5
+ and use its various cryptographic utilities.
6
+ """
7
+
8
+ import sha67
9
+
10
+ def run_demo():
11
+ print("==================================================================")
12
+ print(" SHA-67 Python Bindings (Rust Extension) Demo ")
13
+ print("==================================================================")
14
+
15
+ test_input = "Hello, World!"
16
+ print(f"Input text: '{test_input}'\n")
17
+
18
+ # 1. Module-level Hashing
19
+ print("--- 1. Module-Level Functions ---")
20
+
21
+ # Base-67 hash string (exactly 67 characters)
22
+ hash_str = sha67.sha67(test_input)
23
+ print(f"sha67() string digest (67 chars):\n => {hash_str}")
24
+ assert len(hash_str) == 67
25
+
26
+ # Large integer hash value (modulo 67^67)
27
+ hash_int = sha67.sha67_int(test_input)
28
+ print(f"sha67_int() integer digest:\n => {hash_int}")
29
+ print(f" => Bit-length: {hash_int.bit_length()} bits")
30
+
31
+ # Raw byte representation (exactly 51 bytes)
32
+ hash_bytes = sha67.sha67_bytes(test_input)
33
+ print(f"sha67_bytes() raw bytes digest (51 bytes):\n => {hash_bytes.hex()}")
34
+ assert len(hash_bytes) == 51
35
+ print()
36
+
37
+ # 2. Hashlib-style class interface
38
+ print("--- 2. Hashlib-like Class Interface (sha67.SHA67) ---")
39
+ hasher = sha67.SHA67()
40
+ hasher.update("Hello, ")
41
+ hasher.update("World!")
42
+
43
+ print(f"base67digest(): {hasher.base67digest()}")
44
+ print(f"hexdigest(): {hasher.hexdigest()}")
45
+ print(f"digest() (hex): {hasher.digest().hex()}")
46
+ print(f"intdigest(): {hasher.intdigest()}")
47
+
48
+ # Assert equivalence between incremental and single-pass hash
49
+ assert hasher.base67digest() == hash_str
50
+ print("\n[✔] Incremental and single-pass hashes are identical!")
51
+ print()
52
+
53
+ # 3. Custom Iterative KDF (Key Derivation Function)
54
+ print("--- 3. Custom Key Derivation (PBKDF-SHA67) ---")
55
+ password = "supersecretpassword"
56
+ salt = "random_salt_123"
57
+ iterations = 10000
58
+
59
+ print(f"Deriving key for password='{password}', salt='{salt}', iterations={iterations}...")
60
+ derived_key = sha67.pbkdf_sha67(password, salt, iterations)
61
+ print(f"Derived Key (base-67 KDF):\n => {derived_key}")
62
+ assert len(derived_key) == 67
63
+ print("==================================================================")
64
+
65
+ if __name__ == "__main__":
66
+ run_demo()
@@ -0,0 +1,19 @@
1
+ [build-system]
2
+ requires = ["maturin>=1.0,<2.0"]
3
+ build-backend = "maturin"
4
+
5
+ [project]
6
+ name = "sha67"
7
+ version = "0.1.0"
8
+ description = "Premium SHA-67 Hashing Cryptographic Module in Rust"
9
+ requires-python = ">=3.7"
10
+ dependencies = []
11
+ classifiers = [
12
+ "Programming Language :: Rust",
13
+ "Programming Language :: Python :: Implementation :: CPython",
14
+ "Topic :: Security :: Cryptography",
15
+ ]
16
+
17
+ [tool.maturin]
18
+ bindings = "pyo3"
19
+ features = ["python"]
sha67-0.1.0/src/lib.rs ADDED
@@ -0,0 +1,295 @@
1
+ #![allow(unsafe_op_in_unsafe_fn)]
2
+
3
+ use num_bigint::BigUint;
4
+ use num_traits::{ToPrimitive, Zero};
5
+ use sha2::{Digest, Sha512};
6
+ use std::sync::OnceLock;
7
+
8
+ /// The custom 67-character alphabet for the base-67 encoding.
9
+ /// This includes all unreserved URI-safe characters (a-z, A-Z, 0-9, -, _, ., ~)
10
+ /// plus the exclamation mark (!) to reach exactly 67 symbols.
11
+ pub const ALPHABET: &[u8] = b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_.~!";
12
+
13
+ /// Thread-safe OnceLock to precompute and cache the modulo 67^67 value.
14
+ fn get_modulus() -> &'static BigUint {
15
+ static MODULUS: OnceLock<BigUint> = OnceLock::new();
16
+ MODULUS.get_or_init(|| {
17
+ let base = BigUint::from(67u32);
18
+ base.pow(67)
19
+ })
20
+ }
21
+
22
+ /// Converts a BigUint (< 67^67) into a base-67 string of exactly 67 characters,
23
+ /// padded with leading '0's as necessary.
24
+ pub fn biguint_to_base67(mut val: BigUint) -> String {
25
+ let mut digits = Vec::with_capacity(67);
26
+ let divisor = BigUint::from(67u32);
27
+
28
+ while !val.is_zero() {
29
+ let rem = &val % &divisor;
30
+ val /= &divisor;
31
+ let digit_idx = rem.to_usize().unwrap();
32
+ digits.push(ALPHABET[digit_idx] as char);
33
+ }
34
+
35
+ // Pad with the 0-th character of the alphabet (which is '0') to ensure exactly 67 characters
36
+ while digits.len() < 67 {
37
+ digits.push(ALPHABET[0] as char);
38
+ }
39
+
40
+ // Reverse to big-endian order (most significant digit first)
41
+ digits.reverse();
42
+ digits.into_iter().collect()
43
+ }
44
+
45
+ /// Compute the base-67 hash of the input data in Rust and return it as a 67-character string.
46
+ pub fn sha67_rust(data: &[u8]) -> String {
47
+ let mut hasher = Sha512::new();
48
+ hasher.update(data);
49
+ let hash_bytes = hasher.finalize();
50
+ let val = BigUint::from_bytes_be(&hash_bytes);
51
+ let reduced = val % get_modulus();
52
+ biguint_to_base67(reduced)
53
+ }
54
+
55
+ // =====================================================================
56
+ // Python Bindings (only compiled if python feature is enabled)
57
+ // =====================================================================
58
+
59
+ #[cfg(feature = "python")]
60
+ use pyo3::prelude::*;
61
+ #[cfg(feature = "python")]
62
+ use pyo3::types::{PyBytes, PyLong};
63
+ use std::borrow::Cow;
64
+
65
+ /// Helper function to extract a byte slice from a PyAny object,
66
+ /// supporting both Python `str` (UTF-8 encoded) and `bytes`.
67
+ #[cfg(feature = "python")]
68
+ fn get_bytes<'a>(data: &'a Bound<'a, PyAny>) -> PyResult<Cow<'a, [u8]>> {
69
+ if let Ok(s) = data.extract::<String>() {
70
+ Ok(Cow::Owned(s.into_bytes()))
71
+ } else if let Ok(b) = data.extract::<Vec<u8>>() {
72
+ Ok(Cow::Owned(b))
73
+ } else {
74
+ Err(pyo3::exceptions::PyTypeError::new_err(
75
+ "Expected data to be of type 'str' or 'bytes'",
76
+ ))
77
+ }
78
+ }
79
+
80
+ /// A Python class that mimics the standard hashlib interface for computing SHA-67 hashes.
81
+ #[cfg(feature = "python")]
82
+ #[pyclass]
83
+ #[derive(Clone)]
84
+ struct SHA67 {
85
+ state: Sha512,
86
+ }
87
+
88
+ #[cfg(feature = "python")]
89
+ #[pymethods]
90
+ impl SHA67 {
91
+ /// Creates a new SHA67 hasher. Can optionally be initialized with input data.
92
+ #[new]
93
+ fn new(data: Option<&Bound<'_, PyAny>>) -> PyResult<Self> {
94
+ let mut hasher = Sha512::new();
95
+ if let Some(d) = data {
96
+ let bytes = get_bytes(d)?;
97
+ hasher.update(bytes);
98
+ }
99
+ Ok(SHA67 { state: hasher })
100
+ }
101
+
102
+ /// Update the hash object with the bytes-like object or string.
103
+ /// Repeated calls are equivalent to a single call with the concatenation of all the arguments.
104
+ fn update(&mut self, data: &Bound<'_, PyAny>) -> PyResult<()> {
105
+ let bytes = get_bytes(data)?;
106
+ self.state.update(bytes);
107
+ Ok(())
108
+ }
109
+
110
+ /// Return the digest of the data passed to the update() method so far.
111
+ /// This is a 51-byte raw representation of the hash value modulo 67^67.
112
+ fn digest(&self) -> PyObject {
113
+ let hash_bytes = self.state.clone().finalize();
114
+ let val = BigUint::from_bytes_be(&hash_bytes);
115
+ let reduced = val % get_modulus();
116
+
117
+ let bytes = reduced.to_bytes_be();
118
+ // 67^67 fits in exactly 51 bytes (51 * 8 = 408 bits > 406.4 bits)
119
+ let mut padded = vec![0u8; 51];
120
+ let start = 51 - bytes.len();
121
+ padded[start..].copy_from_slice(&bytes);
122
+
123
+ Python::with_gil(|py| {
124
+ PyBytes::new_bound(py, &padded).into()
125
+ })
126
+ }
127
+
128
+ /// Return the digest of the data passed to the update() method so far as a hexadecimal string.
129
+ fn hexdigest(&self) -> String {
130
+ let hash_bytes = self.state.clone().finalize();
131
+ let val = BigUint::from_bytes_be(&hash_bytes);
132
+ let reduced = val % get_modulus();
133
+
134
+ let bytes = reduced.to_bytes_be();
135
+ let mut padded = vec![0u8; 51];
136
+ let start = 51 - bytes.len();
137
+ padded[start..].copy_from_slice(&bytes);
138
+
139
+ hex::encode(padded)
140
+ }
141
+
142
+ /// Return the digest of the data passed to the update() method so far as a base-67 string of exactly 67 characters.
143
+ fn base67digest(&self) -> String {
144
+ let hash_bytes = self.state.clone().finalize();
145
+ let val = BigUint::from_bytes_be(&hash_bytes);
146
+ let reduced = val % get_modulus();
147
+ biguint_to_base67(reduced)
148
+ }
149
+
150
+ /// Return the digest of the data passed to the update() method so far as a Python integer.
151
+ fn intdigest(&self) -> PyObject {
152
+ let hash_bytes = self.state.clone().finalize();
153
+ let val = BigUint::from_bytes_be(&hash_bytes);
154
+ let reduced = val % get_modulus();
155
+
156
+ let bytes = reduced.to_bytes_be();
157
+ Python::with_gil(|py| {
158
+ let py_bytes = PyBytes::new_bound(py, &bytes);
159
+ let py_int = py
160
+ .get_type_bound::<PyLong>()
161
+ .call_method1("from_bytes", (py_bytes, "big"))
162
+ .unwrap()
163
+ .downcast_into::<PyLong>()
164
+ .unwrap();
165
+ py_int.into()
166
+ })
167
+ }
168
+ }
169
+
170
+ /// Compute the base-67 hash of the input data and return it as a 67-character string.
171
+ #[cfg(feature = "python")]
172
+ #[pyfunction(name = "sha67")]
173
+ fn py_sha67(data: &Bound<'_, PyAny>) -> PyResult<String> {
174
+ let bytes = get_bytes(data)?;
175
+ Ok(sha67_rust(&bytes))
176
+ }
177
+
178
+ /// Compute the base-67 hash of the input data and return it as a Python integer.
179
+ #[cfg(feature = "python")]
180
+ #[pyfunction]
181
+ fn sha67_int(data: &Bound<'_, PyAny>) -> PyResult<PyObject> {
182
+ let bytes = get_bytes(data)?;
183
+ let mut hasher = Sha512::new();
184
+ hasher.update(&bytes);
185
+ let hash_bytes = hasher.finalize();
186
+ let val = BigUint::from_bytes_be(&hash_bytes);
187
+ let reduced = val % get_modulus();
188
+
189
+ let big_bytes = reduced.to_bytes_be();
190
+ Python::with_gil(|py| {
191
+ let py_bytes = PyBytes::new_bound(py, &big_bytes);
192
+ let py_int = py
193
+ .get_type_bound::<PyLong>()
194
+ .call_method1("from_bytes", (py_bytes, "big"))?
195
+ .downcast_into::<PyLong>()?;
196
+ Ok(py_int.into())
197
+ })
198
+ }
199
+
200
+ /// Compute the base-67 hash of the input data and return it as a 51-byte representation.
201
+ #[cfg(feature = "python")]
202
+ #[pyfunction]
203
+ fn sha67_bytes(data: &Bound<'_, PyAny>) -> PyResult<PyObject> {
204
+ let bytes = get_bytes(data)?;
205
+ let mut hasher = Sha512::new();
206
+ hasher.update(&bytes);
207
+ let hash_bytes = hasher.finalize();
208
+ let val = BigUint::from_bytes_be(&hash_bytes);
209
+ let reduced = val % get_modulus();
210
+
211
+ let big_bytes = reduced.to_bytes_be();
212
+ let mut padded = vec![0u8; 51];
213
+ let start = 51 - big_bytes.len();
214
+ padded[start..].copy_from_slice(&big_bytes);
215
+
216
+ Python::with_gil(|py| {
217
+ Ok(PyBytes::new_bound(py, &padded).into())
218
+ })
219
+ }
220
+
221
+ /// A custom iterative Key Derivation Function (KDF) using SHA-67.
222
+ /// This runs the base-67 hashing algorithm iteratively with salt stretching.
223
+ #[cfg(feature = "python")]
224
+ #[pyfunction]
225
+ fn pbkdf_sha67(
226
+ password: &Bound<'_, PyAny>,
227
+ salt: &Bound<'_, PyAny>,
228
+ iterations: u32,
229
+ ) -> PyResult<String> {
230
+ let password_bytes = get_bytes(password)?;
231
+ let salt_bytes = get_bytes(salt)?;
232
+
233
+ let mut state = password_bytes.to_vec();
234
+ state.extend_from_slice(&salt_bytes);
235
+
236
+ let mut current_hash = BigUint::zero();
237
+
238
+ for _ in 0..iterations {
239
+ let mut hasher = Sha512::new();
240
+ hasher.update(&state);
241
+ let hash_bytes = hasher.finalize();
242
+ let val = BigUint::from_bytes_be(&hash_bytes) % get_modulus();
243
+
244
+ current_hash ^= &val;
245
+
246
+ let base67_str = biguint_to_base67(val);
247
+ state = base67_str.into_bytes();
248
+ state.extend_from_slice(&password_bytes);
249
+ }
250
+
251
+ Ok(biguint_to_base67(current_hash))
252
+ }
253
+
254
+ /// The Python module defined via PyO3.
255
+ #[cfg(feature = "python")]
256
+ #[pymodule]
257
+ fn sha67(m: &Bound<'_, PyModule>) -> PyResult<()> {
258
+ m.add_function(wrap_pyfunction!(py_sha67, m)?)?;
259
+ m.add_function(wrap_pyfunction!(sha67_int, m)?)?;
260
+ m.add_function(wrap_pyfunction!(sha67_bytes, m)?)?;
261
+ m.add_function(wrap_pyfunction!(pbkdf_sha67, m)?)?;
262
+ m.add_class::<SHA67>()?;
263
+ Ok(())
264
+ }
265
+
266
+ // =====================================================================
267
+ // Rust Unit Tests
268
+ // =====================================================================
269
+
270
+ #[cfg(test)]
271
+ mod tests {
272
+ use super::*;
273
+
274
+ #[test]
275
+ fn test_alphabet_length() {
276
+ assert_eq!(ALPHABET.len(), 67);
277
+ }
278
+
279
+ #[test]
280
+ fn test_biguint_to_base67_zero() {
281
+ let val = BigUint::zero();
282
+ let s = biguint_to_base67(val);
283
+ assert_eq!(s.len(), 67);
284
+ assert!(s.chars().all(|c| c == '0'));
285
+ }
286
+
287
+ #[test]
288
+ fn test_sha67_rust_output_length() {
289
+ let hash = sha67_rust(b"hello world");
290
+ assert_eq!(hash.len(), 67);
291
+ for c in hash.chars() {
292
+ assert!(ALPHABET.contains(&(c as u8)));
293
+ }
294
+ }
295
+ }
@@ -0,0 +1,97 @@
1
+ use std::env;
2
+ use std::fs::File;
3
+ use std::io::{self, Read};
4
+ use sha67::sha67_rust;
5
+
6
+ fn print_help() {
7
+ println!("============================================================");
8
+ println!(" SHA-67 HASHER - 67^67 Cryptographic Modulo Hash ");
9
+ println!("============================================================");
10
+ println!("Computes a cryptographically secure 67-character hash using");
11
+ println!("SHA-512 mapped onto a base-67 alphabet modulo 67^67.");
12
+ println!();
13
+ println!("Usage:");
14
+ println!(" sha67 [option] <input>");
15
+ println!();
16
+ println!("Options:");
17
+ println!(" -s, --string <text> Hash the provided text string directly");
18
+ println!(" -f, --file <path> Hash the contents of the specified file");
19
+ println!(" -h, --help Show this help menu");
20
+ println!(" - Read from standard input (default if no argument)");
21
+ println!();
22
+ println!("Examples:");
23
+ println!(" sha67 -s \"Hello, World!\"");
24
+ println!(" sha67 my_document.txt");
25
+ println!(" echo -n \"cryptography\" | sha67");
26
+ println!("============================================================");
27
+ }
28
+
29
+ fn main() -> io::Result<()> {
30
+ let args: Vec<String> = env::args().collect();
31
+
32
+ // If no argument is provided, default to reading from stdin
33
+ if args.len() < 2 {
34
+ let mut buffer = Vec::new();
35
+ io::stdin().read_to_end(&mut buffer)?;
36
+ let hash = sha67_rust(&buffer);
37
+ println!("{}", hash);
38
+ return Ok(());
39
+ }
40
+
41
+ match args[1].as_str() {
42
+ "-h" | "--help" => {
43
+ print_help();
44
+ return Ok(());
45
+ }
46
+ "-s" | "--string" => {
47
+ if args.len() < 3 {
48
+ eprintln!("Error: Missing string argument after -s/--string");
49
+ std::process::exit(1);
50
+ }
51
+ let text = &args[2];
52
+ let hash = sha67_rust(text.as_bytes());
53
+ println!("{}", hash);
54
+ }
55
+ "-f" | "--file" => {
56
+ if args.len() < 3 {
57
+ eprintln!("Error: Missing file path argument after -f/--file");
58
+ std::process::exit(1);
59
+ }
60
+ let path = &args[2];
61
+ hash_file(path)?;
62
+ }
63
+ "-" => {
64
+ let mut buffer = Vec::new();
65
+ io::stdin().read_to_end(&mut buffer)?;
66
+ let hash = sha67_rust(&buffer);
67
+ println!("{}", hash);
68
+ }
69
+ other => {
70
+ // If the argument starts with '-' but wasn't caught, it's an invalid option
71
+ if other.starts_with('-') {
72
+ eprintln!("Error: Unknown option '{}'. Use -h or --help for details.", other);
73
+ std::process::exit(1);
74
+ }
75
+ // Otherwise, treat it as a file path directly (convenience shortcut)
76
+ hash_file(other)?;
77
+ }
78
+ }
79
+
80
+ Ok(())
81
+ }
82
+
83
+ fn hash_file(path: &str) -> io::Result<()> {
84
+ match File::open(path) {
85
+ Ok(mut file) => {
86
+ let mut buffer = Vec::new();
87
+ file.read_to_end(&mut buffer)?;
88
+ let hash = sha67_rust(&buffer);
89
+ println!("{} {}", hash, path);
90
+ Ok(())
91
+ }
92
+ Err(err) => {
93
+ eprintln!("Error reading file '{}': {}", path, err);
94
+ std::process::exit(1);
95
+ }
96
+ }
97
+ }