From 1acca158cb6056f23705bfdbc2682c62c2c61c87 Mon Sep 17 00:00:00 2001 From: tritoke Date: Wed, 31 Jul 2024 14:21:45 +0100 Subject: [PATCH] Add BLAKE3 --- Cargo.lock | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + src/lib.rs | 76 +++++++++++++++++++++++++++++--------------------- xoflib.pyi | 11 ++++++++ 4 files changed, 138 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fbf4a64..c5a197d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,18 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "arrayref" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d151e35f61089500b617991b791fc8bfd237ae50cd5950803758a179b41e67a" + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + [[package]] name = "ascon" version = "0.3.1" @@ -30,6 +42,21 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "blake3" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9ec96fe9a81b5e365f9db71fe00edc4fe4ca2cc7dcb7861f0603012a7caa210" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", + "digest", + "rayon-core", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -39,12 +66,24 @@ dependencies = [ "generic-array", ] +[[package]] +name = "cc" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc" + [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "constant_time_eq" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" + [[package]] name = "cpufeatures" version = "0.2.12" @@ -54,6 +93,31 @@ dependencies = [ "libc", ] +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + [[package]] name = "crypto-common" version = "0.1.6" @@ -72,6 +136,7 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", + "subtle", ] [[package]] @@ -246,6 +311,16 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + [[package]] name = "redox_syscall" version = "0.5.3" @@ -277,6 +352,12 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "syn" version = "2.0.72" @@ -387,6 +468,7 @@ name = "xoflib" version = "0.2.0" dependencies = [ "ascon-hash", + "blake3", "pyo3", "sha3", ] diff --git a/Cargo.toml b/Cargo.toml index 03514d1..4ddf87b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,3 +14,4 @@ crate-type = ["cdylib"] pyo3 = "0.21.0" sha3 = { version = "0.10.8", features = ["asm"] } ascon-hash = "0.2.0" +blake3 = { version = "1.5.3", features = ["rayon", "traits-preview"] } diff --git a/src/lib.rs b/src/lib.rs index 1b5d02d..a2c5bfc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ use ascon_hash::{AsconAXof, AsconAXofReader, AsconXof, AsconXofReaderCore}; +use blake3::{Hasher as Blake3, OutputReader as Blake3Reader}; use pyo3::{ buffer::PyBuffer, exceptions::{PyTypeError, PyValueError}, @@ -38,7 +39,14 @@ fn pybuffer_get_bytes_mut<'py>(data: &Bound<'py, PyAny>) -> PyResult<&'py mut [u macro_rules! impl_sponge_shaker_classes { // hasher is tt so we can pick the right kind of methods to generate - (hasher_name = $hasher:tt, pyclass_name = $class_name:literal, reader_name = $xof_reader:ident, rust_shaker_name = $shaker_name:ident, rust_sponge_name = $sponge_name:ident $(,)?) => { + ( + hasher_name = $hasher:tt, + pyclass_name = $class_name:literal, + reader_name = $xof_reader:ident, + rust_shaker_name = $shaker_name:ident, + rust_sponge_name = $sponge_name:ident, + example_hash = $example_hash:literal $(,)? + ) => { #[pyclass(module="xoflib", name=$class_name)] #[doc=concat!(stringify!($shaker_name), " implements absorption and finalization for the ", stringify!($hasher), " XOF")] struct $shaker_name { @@ -66,7 +74,7 @@ macro_rules! impl_sponge_shaker_classes { " >>> xof = ", impl_sponge_shaker_classes!(@docs_construct_hasher $hasher, $class_name), "\n", " >>> xof = xof.absorb(bytearray(b\"Ooh just a little bit more data\")).finalize()\n", " >>> xof.read(16).hex()\n", - " ", impl_sponge_shaker_classes!(@docs_example_hash $hasher), "\n", + " ", $example_hash, "\n", )] fn read<'py>(&mut self, py: Python<'py>, n: usize) -> PyResult> { PyBytes::new_bound_with(py, n, |bytes| { @@ -88,7 +96,7 @@ macro_rules! impl_sponge_shaker_classes { " >>> buf = bytearray(b\"\\0\" * 10)\n", " >>> xof.read_into(buf)\n", " >>> buf.hex()\n", - " ", impl_sponge_shaker_classes!(@docs_example_hash $hasher), "\n", + " ", $example_hash, "\n", )] fn read_into(&mut self, buf: &Bound<'_, PyAny>) -> PyResult<()> { self.xof.read(pybuffer_get_bytes_mut(buf)?); @@ -118,31 +126,6 @@ macro_rules! impl_sponge_shaker_classes { concat!($class_name, "(b\"bytes to absorb\")") }; - // "match" on the hasher and generate the correct hash for the example - (@docs_example_hash Shake128) => { - "'2c67a3c30e75de37d30e3f6d94e05a00'" - }; - - (@docs_example_hash Shake256) => { - "'82786e027034dccb6f41224c22a227c9'" - }; - - (@docs_example_hash TurboShake128) => { - "'b6be317e80aa741b9f0ac9330d584506'" - }; - - (@docs_example_hash TurboShake256) => { - "'2e9d18d326438ea968b071ab958f6260'" - }; - - (@docs_example_hash AsconXof) => { - "'202e12280fb6781470016dc067d3b213'" - }; - - (@docs_example_hash AsconAXof) => { - "'e3d5593d0e08c5a7c6cbf751fb817f0a'" - }; - // "match" on the TurboShakes and generate a unique __init__ for them with domain separation (@shaker_methods TurboShake128, $class_name:literal, $shaker_name:ident, $sponge_name:ident) => { impl_sponge_shaker_classes!(@turbo_shaker_methods TurboShake128Core, $class_name, $shaker_name, $sponge_name); @@ -286,7 +269,8 @@ impl_sponge_shaker_classes!( pyclass_name = "Shake128", reader_name = Shake128Reader, rust_shaker_name = Shaker128, - rust_sponge_name = Sponge128 + rust_sponge_name = Sponge128, + example_hash = "'2c67a3c30e75de37d30e3f6d94e05a00'", ); #[rustfmt::skip] impl_sponge_shaker_classes!( @@ -294,7 +278,8 @@ impl_sponge_shaker_classes!( pyclass_name = "Shake256", reader_name = Shake256Reader, rust_shaker_name = Shaker256, - rust_sponge_name = Sponge256 + rust_sponge_name = Sponge256, + example_hash = "'82786e027034dccb6f41224c22a227c9'", ); #[rustfmt::skip] impl_sponge_shaker_classes!( @@ -302,7 +287,8 @@ impl_sponge_shaker_classes!( pyclass_name = "TurboShake128", reader_name = TurboShake128Reader, rust_shaker_name = TurboShaker128, - rust_sponge_name = TurboSponge128 + rust_sponge_name = TurboSponge128, + example_hash = "'b6be317e80aa741b9f0ac9330d584506'", ); #[rustfmt::skip] impl_sponge_shaker_classes!( @@ -310,7 +296,8 @@ impl_sponge_shaker_classes!( pyclass_name = "TurboShake256", reader_name = TurboShake256Reader, rust_shaker_name = TurboShaker256, - rust_sponge_name = TurboSponge256 + rust_sponge_name = TurboSponge256, + example_hash = "'2e9d18d326438ea968b071ab958f6260'", ); #[rustfmt::skip] @@ -320,6 +307,7 @@ impl_sponge_shaker_classes!( reader_name = AsconXofReader, rust_shaker_name = Ascon, rust_sponge_name = AsconSponge, + example_hash = "'202e12280fb6781470016dc067d3b213'", ); #[rustfmt::skip] impl_sponge_shaker_classes!( @@ -328,6 +316,17 @@ impl_sponge_shaker_classes!( reader_name = AsconAXofReader, rust_shaker_name = AsconA, rust_sponge_name = AsconASponge, + example_hash = "'e3d5593d0e08c5a7c6cbf751fb817f0a'", +); + +#[rustfmt::skip] +impl_sponge_shaker_classes!( + hasher_name = Blake3, + pyclass_name = "Blake3", + reader_name = Blake3Reader, + rust_shaker_name = Blake3Xof, + rust_sponge_name = Blake3Sponge, + example_hash = "'79c528b01f9519031bb3ebfbb4d99ecb'", ); /// Construct a TurboSponge128 directly from `domain_sep` and `data` @@ -412,6 +411,14 @@ impl_sponge_constructor!( example_hash = "ae7ba96550a57300da1e2ba31335d922", ); +#[rustfmt::skip] +impl_sponge_constructor!( + function_name = blake3_xof, + xof = Blake3Xof, + sponge = Blake3Sponge, + example_hash = "not yet", +); + /// A Python package for the Shake extendable-output functions (XOFs): Shake128, /// Shake256 and the turbo variants built with pyO3 bindings to the sha3 Rust /// crate. @@ -439,5 +446,10 @@ fn xoflib(m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_function(wrap_pyfunction!(ascon_xof, m)?)?; m.add_function(wrap_pyfunction!(ascona_xof, m)?)?; + m.add_class::()?; + m.add_class::()?; + + m.add_function(wrap_pyfunction!(blake3_xof, m)?)?; + Ok(()) } diff --git a/xoflib.pyi b/xoflib.pyi index c6759b6..d4f3fee 100644 --- a/xoflib.pyi +++ b/xoflib.pyi @@ -68,3 +68,14 @@ class AsconASponge: def ascon_xof(input_bytes: Buffer) -> AsconXof: ... def ascona_xof(input_bytes: Buffer) -> AsconAXof: ... + +class Blake3: + def __init__(self, input_bytes: Buffer | None = None): ... + def absorb(self, input_bytes: Buffer) -> "AsconAXof": ... + def finalize(self) -> AsconSponge: ... + +class Blake3Sponge: + def read(self, n: int) -> bytes: ... + def read_into(self, buf: Buffer): ... + +def blake3_xof(input_bytes: Buffer) -> AsconXof: ...