sha256

Pure Haskell SHA-256, HMAC-SHA256 (docs.ppad.tech/sha256).
git clone git://git.ppad.tech/sha256.git
Log | Files | Refs | README | LICENSE

README.md (6523B)


      1 # sha256
      2 
      3 [![](https://img.shields.io/hackage/v/ppad-sha256?color=blue)](https://hackage.haskell.org/package/ppad-sha256)
      4 ![](https://img.shields.io/badge/license-MIT-brightgreen)
      5 [![](https://img.shields.io/badge/haddock-sha256-lightblue)](https://docs.ppad.tech/sha256)
      6 
      7 A pure Haskell implementation of SHA-256 and HMAC-SHA256 on strict and
      8 lazy ByteStrings, as specified by RFC's [6234][r6234] and [2104][r2104].
      9 
     10 ## Usage
     11 
     12 A sample GHCi session:
     13 
     14 ```
     15   > :set -XOverloadedStrings
     16   >
     17   > -- import qualified
     18   > import qualified Crypto.Hash.SHA256 as SHA256
     19   >
     20   > -- 'hash' and 'hmac' operate on strict bytestrings
     21   >
     22   > let hash_s = SHA256.hash "strict bytestring input"
     23   > let hmac_s = SHA256.hmac "strict secret" "strict bytestring input"
     24   >
     25   > -- 'hash_lazy' and 'hmac_lazy' operate on lazy bytestrings
     26   > -- but note that the key for HMAC is always strict
     27   >
     28   > let hash_l = SHA256.hash_lazy "lazy bytestring input"
     29   > let hmac_l = SHA256.hmac_lazy "strict secret" "lazy bytestring input"
     30   >
     31   > -- results are always unformatted 256-bit (32-byte) strict bytestrings
     32   >
     33   > import qualified Data.ByteString as BS
     34   >
     35   > BS.take 10 hash_s
     36   "1\223\152Ha\USB\171V\a"
     37   > BS.take 10 hmac_l
     38   "\DELSOk\180\242\182'v\187"
     39   >
     40   > -- you can use third-party libraries for rendering if needed
     41   > -- e.g., using ppad-base16:
     42   >
     43   > import qualified Data.ByteString.Base16 as B16
     44   >
     45   > B16.encode hash_s
     46   "31df9848611f42ab5607ea9e6de84b05d5259085abb30a7917d85efcda42b0e3"
     47   > B16.encode hmac_l
     48   "7f534f6bb4f2b62776bba3d6466e384505f2ff89c91f39800d7a0d4623a4711e"
     49 ```
     50 
     51 ## Documentation
     52 
     53 Haddocks (API documentation, etc.) are hosted at
     54 [docs.ppad.tech/sha256][hadoc].
     55 
     56 ## Performance
     57 
     58 The aim is best-in-class performance for pure, highly-auditable Haskell
     59 code.
     60 
     61 Current benchmark figures on an M4 Silicon MacBook Air look like (use
     62 `cabal bench` to run the benchmark suite):
     63 
     64 ```
     65   benchmarking ppad-sha256/SHA256 (32B input)/hash
     66   time                 879.7 ns   (879.5 ns .. 879.9 ns)
     67                        1.000 R²   (1.000 R² .. 1.000 R²)
     68   mean                 880.1 ns   (879.5 ns .. 882.1 ns)
     69   std dev              3.504 ns   (994.6 ps .. 7.537 ns)
     70 
     71   benchmarking ppad-sha256/HMAC-SHA256 (32B input)/hmac
     72   time                 3.322 μs   (3.322 μs .. 3.322 μs)
     73                        1.000 R²   (1.000 R² .. 1.000 R²)
     74   mean                 3.321 μs   (3.317 μs .. 3.323 μs)
     75   std dev              10.53 ns   (4.987 ns .. 19.12 ns)
     76 ```
     77 
     78 Compare this to Hackage's venerable SHA package:
     79 
     80 ```
     81   benchmarking ppad-sha256/SHA256 (32B input)/SHA.sha256
     82   time                 1.415 μs   (1.414 μs .. 1.415 μs)
     83                        1.000 R²   (1.000 R² .. 1.000 R²)
     84   mean                 1.415 μs   (1.415 μs .. 1.415 μs)
     85   std dev              1.334 ns   (1.158 ns .. 1.576 ns)
     86 
     87   benchmarking ppad-sha256/HMAC-SHA256 (32B input)/SHA.hmacSha256
     88   time                 5.157 μs   (5.156 μs .. 5.158 μs)
     89                        1.000 R²   (1.000 R² .. 1.000 R²)
     90   mean                 5.158 μs   (5.157 μs .. 5.159 μs)
     91   std dev              2.947 ns   (2.413 ns .. 3.606 ns)
     92 ```
     93 
     94 Or the relevant SHA-256-based functions from a library with similar
     95 aims, [noble-hashes][noble]:
     96 
     97 ```
     98 SHA256 32B x 420,875 ops/sec @ 2μs/op ± 1.33% (min: 1μs, max: 3ms)
     99 HMAC-SHA256 32B x 97,304 ops/sec @ 10μs/op
    100 ```
    101 
    102 When reading a 1GB input from disk and testing it with `hash_lazy`, we
    103 get statistics like the following:
    104 
    105 ```
    106    2,310,899,616 bytes allocated in the heap
    107           93,800 bytes copied during GC
    108           78,912 bytes maximum residency (2 sample(s))
    109           35,776 bytes maximum slop
    110               10 MiB total memory in use (0 MiB lost due to fragmentation)
    111 
    112                                      Tot time (elapsed)  Avg pause  Max pause
    113   Gen  0       295 colls,     0 par    0.007s   0.008s     0.0000s    0.0001s
    114   Gen  1         2 colls,     0 par    0.000s   0.001s     0.0004s    0.0004s
    115 
    116   INIT    time    0.003s  (  0.003s elapsed)
    117   MUT     time   22.205s  ( 22.260s elapsed)
    118   GC      time    0.007s  (  0.009s elapsed)
    119   EXIT    time    0.000s  (  0.001s elapsed)
    120   Total   time   22.216s  ( 22.273s elapsed)
    121 
    122   %GC     time       0.0%  (0.0% elapsed)
    123 
    124   Alloc rate    104,073,382 bytes per MUT second
    125 
    126   Productivity 100.0% of total user, 99.9% of total elapsed
    127 ```
    128 
    129 SHA.sha256 gets more like:
    130 
    131 ```
    132   74,403,596,936 bytes allocated in the heap
    133       12,971,992 bytes copied during GC
    134           79,176 bytes maximum residency (2 sample(s))
    135           35,512 bytes maximum slop
    136                6 MiB total memory in use (0 MiB lost due to fragmentation)
    137 
    138                                      Tot time (elapsed)  Avg pause  Max pause
    139   Gen  0     17883 colls,     0 par    0.103s   0.148s     0.0000s    0.0001s
    140   Gen  1         2 colls,     0 par    0.000s   0.000s     0.0002s    0.0003s
    141 
    142   INIT    time    0.006s  (  0.006s elapsed)
    143   MUT     time   32.367s  ( 32.408s elapsed)
    144   GC      time    0.104s  (  0.149s elapsed)
    145   EXIT    time    0.000s  (  0.001s elapsed)
    146   Total   time   32.477s  ( 32.563s elapsed)
    147 
    148   %GC     time       0.0%  (0.0% elapsed)
    149 
    150   Alloc rate    2,298,740,250 bytes per MUT second
    151 
    152   Productivity  99.7% of total user, 99.5% of total elapsed
    153 ```
    154 
    155 ## Security
    156 
    157 This library aims at the maximum security achievable in a
    158 garbage-collected language under an optimizing compiler such as GHC, in
    159 which strict constant-timeness can be challenging to achieve.
    160 
    161 The HMAC-SHA256 functions within pass all [Wycheproof vectors][wyche],
    162 as well as various other useful unit test vectors found around the
    163 internet.
    164 
    165 If you discover any vulnerabilities, please disclose them via
    166 security@ppad.tech.
    167 
    168 ## Development
    169 
    170 You'll require [Nix][nixos] with [flake][flake] support enabled. Enter a
    171 development shell with:
    172 
    173 ```
    174 $ nix develop
    175 ```
    176 
    177 Then do e.g.:
    178 
    179 ```
    180 $ cabal repl ppad-sha256
    181 ```
    182 
    183 to get a REPL for the main library.
    184 
    185 ## Attribution
    186 
    187 This implementation has benefitted immensely from the [SHA][hacka]
    188 package available on Hackage, which was used as a reference during
    189 development. Many parts wound up being direct translations.
    190 
    191 [nixos]: https://nixos.org/
    192 [flake]: https://nixos.org/manual/nix/unstable/command-ref/new-cli/nix3-flake.html
    193 [hadoc]: https://docs.ppad.tech/sha256
    194 [hacka]: https://hackage.haskell.org/package/SHA
    195 [r6234]: https://datatracker.ietf.org/doc/html/rfc6234
    196 [r2104]: https://datatracker.ietf.org/doc/html/rfc2104
    197 [noble]: https://github.com/paulmillr/noble-hashes
    198 [wyche]: https://github.com/C2SP/wycheproof