commit 77931566c41dd82b17b8e69970d098f6827c9301
parent ff165b29fb21b99749460ae7e3fdca42a85c822b
Author: Jared Tobin <jared@jtobin.io>
Date: Sun, 22 Jun 2025 13:16:47 +0400
lib: vertical integration
Diffstat:
5 files changed, 80 insertions(+), 43 deletions(-)
diff --git a/README.md b/README.md
@@ -58,49 +58,37 @@ Haddocks (API documentation, etc.) are hosted at
The aim is best-in-class performance for pure, highly-auditable Haskell
code.
-Current benchmark figures on my mid-2020 MacBook Air look like (use
+Current benchmark figures on an M4 Silicon MacBook Air look like (use
`cabal bench` to run the benchmark suite):
```
benchmarking ppad-sha512/SHA512 (32B input)/hash
- time 1.116 μs (1.103 μs .. 1.130 μs)
- 0.999 R² (0.999 R² .. 0.999 R²)
- mean 1.142 μs (1.132 μs .. 1.154 μs)
- std dev 37.35 ns (30.15 ns .. 49.36 ns)
- variance introduced by outliers: 45% (moderately inflated)
+ time 957.1 ns (956.3 ns .. 957.7 ns)
+ 1.000 R² (1.000 R² .. 1.000 R²)
+ mean 956.1 ns (955.6 ns .. 956.6 ns)
+ std dev 1.714 ns (1.436 ns .. 2.174 ns)
benchmarking ppad-sha512/HMAC-SHA512 (32B input)/hmac
- time 4.943 μs (4.823 μs .. 5.086 μs)
- 0.997 R² (0.994 R² .. 1.000 R²)
- mean 4.878 μs (4.838 μs .. 4.946 μs)
- std dev 180.9 ns (105.1 ns .. 337.4 ns)
- variance introduced by outliers: 48% (moderately inflated)
+ time 3.460 μs (3.448 μs .. 3.475 μs)
+ 1.000 R² (1.000 R² .. 1.000 R²)
+ mean 3.474 μs (3.468 μs .. 3.478 μs)
+ std dev 16.60 ns (11.71 ns .. 24.66 ns)
```
-Compare this to Hackage's famous SHA package:
+Compare this to Hackage's venerable SHA package:
```
benchmarking ppad-sha512/SHA512 (32B input)/SHA.sha512
- time 2.371 μs (2.350 μs .. 2.401 μs)
- 0.999 R² (0.999 R² .. 1.000 R²)
- mean 2.422 μs (2.403 μs .. 2.443 μs)
- std dev 69.84 ns (51.04 ns .. 114.0 ns)
- variance introduced by outliers: 37% (moderately inflated)
+ time 1.437 μs (1.436 μs .. 1.437 μs)
+ 1.000 R² (1.000 R² .. 1.000 R²)
+ mean 1.440 μs (1.435 μs .. 1.452 μs)
+ std dev 23.57 ns (11.13 ns .. 43.08 ns)
benchmarking ppad-sha512/HMAC-SHA512 (32B input)/SHA.hmacSha512
- time 8.832 μs (8.714 μs .. 8.976 μs)
- 0.999 R² (0.998 R² .. 1.000 R²)
- mean 8.911 μs (8.834 μs .. 9.006 μs)
- std dev 278.9 ns (215.8 ns .. 365.1 ns)
- variance introduced by outliers: 37% (moderately inflated)
-```
-
-Or the relevant SHA-512-based functions from a library with similar
-aims, [noble-hashes][noble] (though with no HMAC-SHA512 benchmark
-available):
-
-```
-SHA512 32B x 217,296 ops/sec @ 4μs/op ± 2.00% (min: 3μs, max: 20ms)
+ time 5.164 μs (5.162 μs .. 5.166 μs)
+ 1.000 R² (1.000 R² .. 1.000 R²)
+ mean 5.159 μs (5.157 μs .. 5.161 μs)
+ std dev 6.522 ns (5.534 ns .. 7.662 ns)
```
## Security
diff --git a/flake.lock b/flake.lock
@@ -34,6 +34,37 @@
"type": "github"
}
},
+ "ppad-base16": {
+ "inputs": {
+ "flake-utils": [
+ "ppad-base16",
+ "ppad-nixpkgs",
+ "flake-utils"
+ ],
+ "nixpkgs": [
+ "ppad-base16",
+ "ppad-nixpkgs",
+ "nixpkgs"
+ ],
+ "ppad-nixpkgs": [
+ "ppad-nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1741625558,
+ "narHash": "sha256-ZBDXRD5fsVqA5bGrAlcnhiu67Eo50q0M9614nR3NBwY=",
+ "ref": "master",
+ "rev": "fb63457f2e894eda28250dfe65d0fcd1d195ac2f",
+ "revCount": 24,
+ "type": "git",
+ "url": "git://git.ppad.tech/base16.git"
+ },
+ "original": {
+ "ref": "master",
+ "type": "git",
+ "url": "git://git.ppad.tech/base16.git"
+ }
+ },
"ppad-nixpkgs": {
"inputs": {
"flake-utils": "flake-utils",
@@ -64,6 +95,7 @@
"ppad-nixpkgs",
"nixpkgs"
],
+ "ppad-base16": "ppad-base16",
"ppad-nixpkgs": "ppad-nixpkgs"
}
},
diff --git a/flake.nix b/flake.nix
@@ -7,11 +7,18 @@
url = "git://git.ppad.tech/nixpkgs.git";
ref = "master";
};
+ ppad-base16 = {
+ type = "git";
+ url = "git://git.ppad.tech/base16.git";
+ ref = "master";
+ inputs.ppad-nixpkgs.follows = "ppad-nixpkgs";
+ };
flake-utils.follows = "ppad-nixpkgs/flake-utils";
nixpkgs.follows = "ppad-nixpkgs/nixpkgs";
};
- outputs = { self, nixpkgs, flake-utils, ppad-nixpkgs }:
+ outputs = { self, nixpkgs, flake-utils, ppad-nixpkgs
+ , ppad-base16 }:
flake-utils.lib.eachDefaultSystem (system:
let
lib = "ppad-sha512";
@@ -19,8 +26,13 @@
pkgs = import nixpkgs { inherit system; };
hlib = pkgs.haskell.lib;
+ base16 = ppad-base16.packages.${system}.default;
+
hpkgs = pkgs.haskell.packages.ghc981.extend (new: old: {
- ${lib} = old.callCabal2nixWithOptions lib ./. "--enable-profiling" {};
+ ppad-base16 = base16;
+ ${lib} = old.callCabal2nixWithOptions lib ./. "--enable-profiling" {
+ ppad-base16 = new.ppad-base16;
+ };
});
cc = pkgs.stdenv.cc;
diff --git a/ppad-sha512.cabal b/ppad-sha512.cabal
@@ -43,8 +43,8 @@ test-suite sha512-tests
build-depends:
aeson
, base
- , base16-bytestring
, bytestring
+ , ppad-base16
, ppad-sha512
, tasty
, tasty-hunit
diff --git a/test/Main.hs b/test/Main.hs
@@ -36,11 +36,16 @@ execute_group W.MacTestGroup {..} =
where
msg = "keysize " <> show mtg_keySize <> ", tagsize " <> show mtg_tagSize
+decodeLenient :: BS.ByteString -> BS.ByteString
+decodeLenient bs = case B16.decode bs of
+ Nothing -> error "bang"
+ Just b -> b
+
execute :: Int -> W.MacTest -> TestTree
execute tag_size W.MacTest {..} = testCase t_msg $ do
- let key = B16.decodeLenient (TE.encodeUtf8 mt_key)
- msg = B16.decodeLenient (TE.encodeUtf8 mt_msg)
- pec = B16.decodeLenient (TE.encodeUtf8 mt_tag)
+ let key = decodeLenient (TE.encodeUtf8 mt_key)
+ msg = decodeLenient (TE.encodeUtf8 mt_msg)
+ pec = decodeLenient (TE.encodeUtf8 mt_tag)
out = BS.take bytes (SHA512.hmac key msg)
if mt_result == "invalid"
then assertBool "invalid" (pec /= out)
@@ -149,7 +154,7 @@ hv5_pec = "b47c933421ea2db149ad6e10fce6c7f93d0752380180ffd7f4629a712134831d77be6
-- https://datatracker.ietf.org/doc/html/rfc4231#section-4.1
hmv1_key :: BS.ByteString
-hmv1_key = B16.decodeLenient "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"
+hmv1_key = decodeLenient "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"
hmv1_put :: BS.ByteString
hmv1_put = "Hi There"
@@ -167,25 +172,25 @@ hmv2_pec :: BS.ByteString
hmv2_pec = "164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737"
hmv3_key :: BS.ByteString
-hmv3_key = B16.decodeLenient "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+hmv3_key = decodeLenient "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
hmv3_put :: BS.ByteString
-hmv3_put = B16.decodeLenient "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
+hmv3_put = decodeLenient "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
hmv3_pec :: BS.ByteString
hmv3_pec = "fa73b0089d56a284efb0f0756c890be9b1b5dbdd8ee81a3655f83e33b2279d39bf3e848279a722c806b485a47e67c807b946a337bee8942674278859e13292fb"
hmv4_key :: BS.ByteString
-hmv4_key = B16.decodeLenient "0102030405060708090a0b0c0d0e0f10111213141516171819"
+hmv4_key = decodeLenient "0102030405060708090a0b0c0d0e0f10111213141516171819"
hmv4_put :: BS.ByteString
-hmv4_put = B16.decodeLenient "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
+hmv4_put = decodeLenient "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
hmv4_pec :: BS.ByteString
hmv4_pec = "b0ba465637458c6990e5a8c5f61d4af7e576d97ff94b872de76f8050361ee3dba91ca5c11aa25eb4d679275cc5788063a5f19741120c4f2de2adebeb10a298dd"
hmv5_key :: BS.ByteString
-hmv5_key = B16.decodeLenient "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c"
+hmv5_key = decodeLenient "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c"
hmv5_put :: BS.ByteString
hmv5_put = "Test With Truncation"
@@ -194,7 +199,7 @@ hmv5_pec :: BS.ByteString
hmv5_pec = "415fad6271580a531d4179bc891d87a6"
hmv6_key :: BS.ByteString
-hmv6_key = B16.decodeLenient "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+hmv6_key = decodeLenient "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
hmv6_put :: BS.ByteString
hmv6_put = "Test Using Larger Than Block-Size Key - Hash Key First"