summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephane Glondu <steph@glondu.net>2020-11-07 12:00:10 +0100
committerStephane Glondu <steph@glondu.net>2020-11-07 12:00:10 +0100
commitc3a5c21db26e9634999edbb6bbfe9d2400cccfe7 (patch)
tree2e3ade5a9cfae0d405021c02e6bf6530ac7bf242
parent1cb150352152fe253d871467e50f942069b29141 (diff)
parentc5a87c30c742c1142b8bc6a2163f116707e0efdc (diff)
Update upstream source from tag 'upstream/1.16.1'
Update to upstream version '1.16.1' with Debian dir 4c91978f927d379dcec861b888db4cf17b232f95
-rw-r--r--.gitignore3
-rw-r--r--Changes8
-rw-r--r--Makefile41
-rw-r--r--README.md40
-rw-r--r--_oasis145
-rw-r--r--_tags122
-rwxr-xr-xconfigure67
-rw-r--r--cryptokit.opam35
-rw-r--r--dune-project24
-rw-r--r--setup.ml39
-rw-r--r--src/META12
-rw-r--r--src/api-cryptokit.odocl5
-rw-r--r--src/blake2.c314
-rw-r--r--src/blake2.h47
-rw-r--r--src/config/config_vars.ml.default7
-rw-r--r--src/config/dune7
-rw-r--r--src/config/flags.ml45
-rw-r--r--src/cryptokit.ml63
-rw-r--r--src/cryptokit.mldylib5
-rw-r--r--src/cryptokit.mli58
-rw-r--r--src/cryptokit.mllib5
-rw-r--r--src/dune41
-rw-r--r--src/libcryptokit_stubs.clib28
-rw-r--r--src/stubs-blake2.c75
-rw-r--r--src/stubs-zlib.c6
-rw-r--r--test/dune16
-rw-r--r--test/speedtest.ml6
-rw-r--r--test/test.ml86
28 files changed, 889 insertions, 461 deletions
diff --git a/.gitignore b/.gitignore
index ffcec6b..1d79768 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,6 @@ setup.data
setup.log
*.native
*~
+.merlin
+# This file is generated by the configure script
+src/config/config_vars.ml
diff --git a/Changes b/Changes
index c84f964..92a99f9 100644
--- a/Changes
+++ b/Changes
@@ -1,3 +1,11 @@
+Release 1.16.1:
+- Make the tests faster and more robust
+- Update dependencies and documentation.
+
+Release 1.16:
+- Use dune as the build system (contributed by Andrey Mokhov, PR #24)
+- Add BLAKE2b and BLAKE2s hash and MAC functions.
+
Release 1.15:
- Added constant-time `string_equal` and `bytes_equal` comparison functions
(execution time depends on the lengths of the strings but not on their
diff --git a/Makefile b/Makefile
deleted file mode 100644
index 3639f14..0000000
--- a/Makefile
+++ /dev/null
@@ -1,41 +0,0 @@
-# OASIS_START
-# DO NOT EDIT (digest: a3c674b4239234cbbe53afe090018954)
-
-SETUP = ocaml setup.ml
-
-build: setup.data
- $(SETUP) -build $(BUILDFLAGS)
-
-doc: setup.data build
- $(SETUP) -doc $(DOCFLAGS)
-
-test: setup.data build
- $(SETUP) -test $(TESTFLAGS)
-
-all:
- $(SETUP) -all $(ALLFLAGS)
-
-install: setup.data
- $(SETUP) -install $(INSTALLFLAGS)
-
-uninstall: setup.data
- $(SETUP) -uninstall $(UNINSTALLFLAGS)
-
-reinstall: setup.data
- $(SETUP) -reinstall $(REINSTALLFLAGS)
-
-clean:
- $(SETUP) -clean $(CLEANFLAGS)
-
-distclean:
- $(SETUP) -distclean $(DISTCLEANFLAGS)
-
-setup.data:
- $(SETUP) -configure $(CONFIGUREFLAGS)
-
-configure:
- $(SETUP) -configure $(CONFIGUREFLAGS)
-
-.PHONY: build doc test all install uninstall reinstall clean distclean configure
-
-# OASIS_STOP
diff --git a/README.md b/README.md
index af47c5e..14623cc 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@ The Cryptokit library for OCaml provides a variety of cryptographic primitives t
* Symmetric-key ciphers: AES, Chacha20, DES, Triple-DES, Blowfish, ARCfour, in ECB, CBC, CFB, OFB and counter modes.
* Public-key cryptography: RSA encryption and signature, Diffie-Hellman key agreement.
-* Hash functions and MACs: SHA-3, SHA-1, SHA-2, RIPEMD-160, MD5, and MACs based on AES and DES.
+* Hash functions and MACs: SHA-3, SHA-2, BLAKE2b, RIPEMD-160, and MACs based on AES and DES. (SHA-1 and MD5, despite being broken, are also provided for historical value.)
* Random number generation.
* Encodings and compression: base 64, hexadecimal, Zlib compression.
@@ -17,28 +17,38 @@ This library is distributed under the conditions of the GNU Library General Publ
## Requirements
* OCaml 4.02 or more recent.
-* The findlib/ocamlfind tool.
-* The OASIS tool.
+* The Dune build system, version 2.0 or more recent.
* The Zarith library, version 1.4 or more recent.
* The Zlib C library, version 1.1.3 or up is recommended. If it is not installed on your system (look for libz.a or libz.so), get it from http://www.gzip.org/, or indicate in the Makefile that you do not have it. If you are running Linux or BSD or MacOS, your distribution provides precompiled binaries for this library.
* If the operating system does not provide the `/dev/random` device for random number generation, consider installing the [EGD](http://egd.sourceforge.net/) entropy gathering daemon. Without `/dev/random` nor EGD, this library cannot generate cryptographically-strong random data nor RSA keys. The remainder of the library still works, though.
-## Installation
+## Build, test and install
+* To configure, run `./configure`. There are options to disable or enable some features (run `./configure --help` for a list), but the default configuration is fine most of the time.
+
+* To build, run `dune build`.
+
+* To execute a test, run `dune exec test/<name>.exe` where `<name>` can be `test`,
+ `prngtest` or `speedtest`, supplying additional command line arguments if needed.
+ The main test file `test/test.ml` is also included into the `runtest` alias, so it
+ can be executed simply by `dune test`.
+
+* To install, run `dune install`.
+
+## Using the library
+
+The package name is `cryptokit`. With Dune, use `(library cryptokit)`. With ocamlfind, do
```
-./configure --enable-tests
-make
-make test
-make install
+ ocamlfind ocamlopt -package cryptokit ... # for compilation
+ ocamlfind ocamlopt -package cryptokit -linkpkg ... # for linking
```
## Documentation
-See the extensive documentation comments in file src/cryptokit.mli.
-
-Compilation options: `ocamlfind ocamlopt -package cryptokit`...
+See the extensive documentation comments in file `src/cryptokit.mli`.
-Linking options: `ocamlfind ocamlopt -linkpkg -package cryptokit`...
+To build HTML documentation, run `dune build @doc`. The resulting index file is
+located at `_build/default/_doc/_html/cryptokit/Cryptokit/index.html`.
## Warnings and disclaimers
@@ -68,6 +78,8 @@ SHA-2 is implemented from scratch based on FIPS publication 180-2. It passes th
SHA-3 is based on the "readable" implementation of Keccak written by Markku-Juhani O. Saarinen <mjos@iki.fi>.
+BLAKE2b is implemented from scratch based on RFC 7693. The test vectors are taken from https://github.com/BLAKE2/BLAKE2/tree/master/testvectors; others were obtained with the b2sum program.
+
RIPEMD-160 is based on the reference implementation by A.Bosselaers. It passes the test vectors listed at http://www.esat.kuleuven.ac.be/~bosselae/ripemd160.html
MD5 uses the public-domain implementation by Colin Plumb that is also used in the OCaml runtime system for module Digest.
@@ -76,10 +88,10 @@ RSA encryption and decryption was implemented from scratch, using the Zarith OCa
RSA key generation uses GMP's `nextprime` function for probabilistic primality testing.
-The hardware RNG uses the RDRAND instruction of recent x86 processors, if supported. It is not available on other platforms.
+The hardware RNG uses the RDRAND instruction of recent x86 processors, if supported. It is not available on other platforms. A check is included to reject the broken RDRAND on AMD Ryzen 3000 processors (https://arstechnica.com/gadgets/2019/10/how-a-months-old-amd-microcode-bug-destroyed-my-weekend/).
The seeded PRNG is just the Chacha20 stream cipher encrypting the all-zeroes message. The seed is used as the Chacha20 key. An alternate seeded PRNG is provided, based on AES encryption of a 128-bit counter. Both PRNGs pass the Dieharder statistical tests. Still, better use the system RNG or the hardware RNG if high-quality random numbers are needed.
## Performance
-If you configure with the options `--enable-tests --enable-bench`, then do `make test`, a simple benchmark is performed and shows the speed of various operations from this library.
+If you run `dune exec test/speedtest.exe`, a simple benchmark is performed and shows the speed of various operations from this library.
diff --git a/_oasis b/_oasis
deleted file mode 100644
index b5fa73e..0000000
--- a/_oasis
+++ /dev/null
@@ -1,145 +0,0 @@
-OASISFormat: 0.4
-Name: cryptokit
-Version: 1.15
-Authors: Xavier Leroy
-License: LGPL-2 with OCaml linking exception
-BuildTools: ocamlbuild, ocamldoc
-Plugins: META (0.4), DevFiles (0.4)
-
-Synopsis: Cryptographic primitives
-Description:
- This library provides a variety of cryptographic primitives that can be used
- to implement cryptographic protocols in security-sensitive applications. The
- primitives provided include:
- .
- - Symmetric-key ciphers: AES, Chacha20, Blowfish, DES, Triple-DES, ARCfour,
- in ECB, CBC, CFB, OFB and counter modes.
- - Public-key cryptography: RSA encryption, Diffie-Hellman key agreement.
- - Hash functions and MACs: SHA-1, SHA-2, SHA-3, RIPEMD160, MD5,
- and MACs based on AES and DES.
- - Random number generation.
- - Encodings and compression: base 64, hexadecimal, Zlib compression.
- .
- Additional ciphers and hashes can easily be used in conjunction with
- the library. In particular, basic mechanisms such as chaining modes,
- output buffering, and padding are provided by generic classes that can
- easily be composed with user-provided ciphers. More generally, the library
- promotes a "Lego"-like style of constructing and composing
- transformations over character streams.
-
-Flag zlib
- Description: Enable ZLib
- Default$: !os_type(Win32)
-
-Flag hardwaresupport
- Description: Enable hardware support for AES and GCM (needs GCC or Clang)
- Default$: (architecture(amd64) || architecture(i386)) && !os_type(Win32)
-
-Library cryptokit
- Path: src
- Modules: CryptokitBignum, Cryptokit
- CSources: aesni.c,
- aesni.h,
- arcfour.c,
- arcfour.h,
- stubs-arcfour.c,
- blowfish.c,
- blowfish.h,
- stubs-blowfish.c,
- d3des.c,
- d3des.h,
- stubs-des.c,
- rijndael-alg-fst.c,
- rijndael-alg-fst.h,
- ripemd160.c,
- ripemd160.h,
- stubs-ripemd160.c,
- sha1.c,
- sha1.h,
- stubs-sha1.c,
- sha256.c,
- sha256.h,
- stubs-sha256.c,
- sha512.c,
- sha512.h,
- stubs-sha512.c,
- stubs-aes.c,
- stubs-md5.c,
- stubs-misc.c,
- stubs-rng.c,
- stubs-zlib.c,
- keccak.h,
- keccak.c,
- stubs-sha3.c,
- chacha20.h,
- chacha20.c,
- stubs-chacha20.c
- BuildDepends: unix, zarith
- CCOpt: -DCAML_NAME_SPACE
- if flag(zlib)
- CCOpt+: -DHAVE_ZLIB
- if system(win32) || system(win64)
- CCLib: zlib.lib
- else
- CCLib: -lz
- if system(win32) || system(win64)
- CCLib+: advapi32.lib
- else if system(mingw) || system(mingw64)
- CCLib+: -ladvapi32
- if flag(hardwaresupport)
- CCOpt+: -maes
-
-Executable test
- Path: test
- MainIs: test.ml
- CompiledObject: native
- BuildDepends: cryptokit
- Build$: flag(tests)
- Install: false
-
-Executable prngtest
- Path: test
- MainIs: prngtest.ml
- CompiledObject: native
- BuildDepends: cryptokit
- Build$: flag(tests)
- Install: false
-
-Test main
- Command: $test
- TestTools: test
-
-Flag bench
- Description: Build and run benchmark
- Default: false
-
-Executable speedtest
- Path: test
- MainIs: speedtest.ml
- CompiledObject: native
- BuildDepends: cryptokit
- Install: false
- Build$: flag(bench)
-
-Test bench
- Command: $speedtest
- Run$: flag(bench)
- TestTools: speedtest
-
-Document "api-cryptokit"
- Title: API reference for Cryptokit
- Type: ocamlbuild (0.3)
- InstallDir: $htmldir/cryptokit
- BuildTools+: ocamldoc
- XOCamlBuildPath: src/
- XOCamlbuildLibraries: cryptokit
-
-SourceRepository head
- Type: git
- Location: https://github.com/xavierleroy/cryptokit
- Browser: https://github.com/xavierleroy/cryptokit
-
-SourceRepository this
- Type: git
- Location: https://github.com/xavierleroy/cryptokit/releases/tag/release113
- Browser: https://github.com/xavierleroy/cryptokit/releases/tag/release113
diff --git a/_tags b/_tags
deleted file mode 100644
index e5e0082..0000000
--- a/_tags
+++ /dev/null
@@ -1,122 +0,0 @@
-# OASIS_START
-# DO NOT EDIT (digest: 62ba61e1d8ad56a1e96795f7c6fb78e2)
-# Ignore VCS directories, you can use the same kind of rule outside
-# OASIS_START/STOP if you want to exclude directories that contains
-# useless stuff for the build process
-true: annot, bin_annot
-<**/.svn>: -traverse
-<**/.svn>: not_hygienic
-".bzr": -traverse
-".bzr": not_hygienic
-".hg": -traverse
-".hg": not_hygienic
-".git": -traverse
-".git": not_hygienic
-"_darcs": -traverse
-"_darcs": not_hygienic
-# Library cryptokit
-"src/cryptokit.cmxs": use_cryptokit
-<src/*.ml{,i,y}>: oasis_library_cryptokit_ccopt
-"src/aesni.c": oasis_library_cryptokit_ccopt
-"src/arcfour.c": oasis_library_cryptokit_ccopt
-"src/stubs-arcfour.c": oasis_library_cryptokit_ccopt
-"src/blowfish.c": oasis_library_cryptokit_ccopt
-"src/stubs-blowfish.c": oasis_library_cryptokit_ccopt
-"src/d3des.c": oasis_library_cryptokit_ccopt
-"src/stubs-des.c": oasis_library_cryptokit_ccopt
-"src/rijndael-alg-fst.c": oasis_library_cryptokit_ccopt
-"src/ripemd160.c": oasis_library_cryptokit_ccopt
-"src/stubs-ripemd160.c": oasis_library_cryptokit_ccopt
-"src/sha1.c": oasis_library_cryptokit_ccopt
-"src/stubs-sha1.c": oasis_library_cryptokit_ccopt
-"src/sha256.c": oasis_library_cryptokit_ccopt
-"src/stubs-sha256.c": oasis_library_cryptokit_ccopt
-"src/sha512.c": oasis_library_cryptokit_ccopt
-"src/stubs-sha512.c": oasis_library_cryptokit_ccopt
-"src/stubs-aes.c": oasis_library_cryptokit_ccopt
-"src/stubs-md5.c": oasis_library_cryptokit_ccopt
-"src/stubs-misc.c": oasis_library_cryptokit_ccopt
-"src/stubs-rng.c": oasis_library_cryptokit_ccopt
-"src/stubs-zlib.c": oasis_library_cryptokit_ccopt
-"src/keccak.c": oasis_library_cryptokit_ccopt
-"src/stubs-sha3.c": oasis_library_cryptokit_ccopt
-"src/chacha20.c": oasis_library_cryptokit_ccopt
-"src/stubs-chacha20.c": oasis_library_cryptokit_ccopt
-<src/cryptokit.{cma,cmxa}>: oasis_library_cryptokit_cclib
-"src/libcryptokit_stubs.lib": oasis_library_cryptokit_cclib
-"src/dllcryptokit_stubs.dll": oasis_library_cryptokit_cclib
-"src/libcryptokit_stubs.a": oasis_library_cryptokit_cclib
-"src/dllcryptokit_stubs.so": oasis_library_cryptokit_cclib
-<src/cryptokit.{cma,cmxa}>: use_libcryptokit_stubs
-<src/*.ml{,i,y}>: pkg_unix
-<src/*.ml{,i,y}>: pkg_zarith
-"src/aesni.c": pkg_unix
-"src/aesni.c": pkg_zarith
-"src/arcfour.c": pkg_unix
-"src/arcfour.c": pkg_zarith
-"src/stubs-arcfour.c": pkg_unix
-"src/stubs-arcfour.c": pkg_zarith
-"src/blowfish.c": pkg_unix
-"src/blowfish.c": pkg_zarith
-"src/stubs-blowfish.c": pkg_unix
-"src/stubs-blowfish.c": pkg_zarith
-"src/d3des.c": pkg_unix
-"src/d3des.c": pkg_zarith
-"src/stubs-des.c": pkg_unix
-"src/stubs-des.c": pkg_zarith
-"src/rijndael-alg-fst.c": pkg_unix
-"src/rijndael-alg-fst.c": pkg_zarith
-"src/ripemd160.c": pkg_unix
-"src/ripemd160.c": pkg_zarith
-"src/stubs-ripemd160.c": pkg_unix
-"src/stubs-ripemd160.c": pkg_zarith
-"src/sha1.c": pkg_unix
-"src/sha1.c": pkg_zarith
-"src/stubs-sha1.c": pkg_unix
-"src/stubs-sha1.c": pkg_zarith
-"src/sha256.c": pkg_unix
-"src/sha256.c": pkg_zarith
-"src/stubs-sha256.c": pkg_unix
-"src/stubs-sha256.c": pkg_zarith
-"src/sha512.c": pkg_unix
-"src/sha512.c": pkg_zarith
-"src/stubs-sha512.c": pkg_unix
-"src/stubs-sha512.c": pkg_zarith
-"src/stubs-aes.c": pkg_unix
-"src/stubs-aes.c": pkg_zarith
-"src/stubs-md5.c": pkg_unix
-"src/stubs-md5.c": pkg_zarith
-"src/stubs-misc.c": pkg_unix
-"src/stubs-misc.c": pkg_zarith
-"src/stubs-rng.c": pkg_unix
-"src/stubs-rng.c": pkg_zarith
-"src/stubs-zlib.c": pkg_unix
-"src/stubs-zlib.c": pkg_zarith
-"src/keccak.c": pkg_unix
-"src/keccak.c": pkg_zarith
-"src/stubs-sha3.c": pkg_unix
-"src/stubs-sha3.c": pkg_zarith
-"src/chacha20.c": pkg_unix
-"src/chacha20.c": pkg_zarith
-"src/stubs-chacha20.c": pkg_unix
-"src/stubs-chacha20.c": pkg_zarith
-# Executable test
-"test/test.native": pkg_unix
-"test/test.native": pkg_zarith
-"test/test.native": use_cryptokit
-# Executable prngtest
-"test/prngtest.native": pkg_unix
-"test/prngtest.native": pkg_zarith
-"test/prngtest.native": use_cryptokit
-# Executable speedtest
-"test/speedtest.native": pkg_unix
-"test/speedtest.native": pkg_zarith
-"test/speedtest.native": use_cryptokit
-<test/*.ml{,i,y}>: pkg_unix
-<test/*.ml{,i,y}>: pkg_zarith
-<test/*.ml{,i,y}>: use_cryptokit
-# OASIS_STOP
-"build": not_hygienic
-"build": -traverse
-"src/cryptokit.cmxs": use_libcryptokit_stubs
-<*/*.cm{o,x}>: safe_string
diff --git a/configure b/configure
index 6acfaeb..0037908 100755
--- a/configure
+++ b/configure
@@ -1,27 +1,48 @@
-#!/bin/sh
+#!/usr/bin/env ocaml
+(* -*- tuareg -*- *)
-# OASIS_START
-# DO NOT EDIT (digest: dc86c2ad450f91ca10c931b6045d0499)
-set -e
+type 'a value =
+ | This of 'a
+ | Auto
-FST=true
-for i in "$@"; do
- if $FST; then
- set --
- FST=false
- fi
+let string_of_value to_string = function
+ | This a -> "This (" ^ to_string a ^ ")"
+ | Auto -> "Auto"
- case $i in
- --*=*)
- ARG=${i%%=*}
- VAL=${i##*=}
- set -- "$@" "$ARG" "$VAL"
- ;;
- *)
- set -- "$@" "$i"
- ;;
- esac
-done
+let () =
+ let declare_flag arg description =
+ let reference = ref Auto in
+ let args =
+ [ "--enable-" ^ arg, Arg.Unit (fun () -> reference := This true),
+ " Enable " ^ description
+ ; "--disable-" ^ arg, Arg.Unit (fun () -> reference := This false),
+ " Disable " ^ description
+ ]
+ in args, reference
+ in
+ let args_zlib, ref_zlib = declare_flag "zlib" "ZLib" in
+ let args_hardware_support, ref_hardware_support =
+ declare_flag "hardwaresupport"
+ "hardware support for AES and GCM (needs GCC or Clang)" in
+ Arg.parse
+ (Arg.align (args_zlib @ args_hardware_support))
+ (fun s -> raise (Arg.Bad (Printf.sprintf "don't know what to do with %S" s)))
+ "Usage: ./configure [OPTIONS]";
+ let oc = open_out_bin "src/config/config_vars.ml" in
+ Printf.fprintf oc {|
+type 'a value =
+ | This of 'a
+ | Auto
-ocaml setup.ml -configure "$@"
-# OASIS_STOP
+let enable_zlib = %s
+let enable_hardware_support = %s
+|}
+ (string_of_value string_of_bool !ref_zlib)
+ (string_of_value string_of_bool !ref_hardware_support);
+ close_out oc;
+ (* Below is a temporary workaround to make sure the configuration happens
+ every time this script is run. *)
+ (try
+ Sys.remove "_build/default/src/flags.sexp";
+ with _ -> ());
+ exit (Sys.command "dune build @configure --release")
diff --git a/cryptokit.opam b/cryptokit.opam
new file mode 100644
index 0000000..a5e6c09
--- /dev/null
+++ b/cryptokit.opam
@@ -0,0 +1,35 @@
+# This file is generated by dune, edit dune-project instead
+opam-version: "2.0"
+synopsis: "A library of cryptographic primitives"
+description: """
+Cryptokit includes block ciphers (AES, DES, 3DES), stream ciphers
+(ARCfour), public-key crypto (RSA, DH), hashes (SHA-1, SHA-256,
+SHA-3), MACs, compression, random number generation -- all presented
+with a compositional, extensible interface."""
+maintainer: ["Xavier Leroy <xavier.leroy@college-de-france.fr>"]
+authors: ["Xavier Leroy"]
+homepage: "https://github.com/xavierleroy/cryptokit"
+bug-reports: "https://github.com/xavierleroy/cryptokit/issues"
+depends: [
+ "ocaml" {>= "4.03.0"}
+ "dune" {>= "2.0"}
+ "dune-configurator"
+ "zarith" {>= "1.4"}
+ "conf-zlib"
+ "conf-gmp-powm-sec"
+]
+build: [
+ ["dune" "subst"] {pinned}
+ [
+ "dune"
+ "build"
+ "-p"
+ name
+ "-j"
+ jobs
+ "@install"
+ "@runtest" {with-test}
+ "@doc" {with-doc}
+ ]
+]
+dev-repo: "git+https://github.com/xavierleroy/cryptokit.git"
diff --git a/dune-project b/dune-project
new file mode 100644
index 0000000..65441b0
--- /dev/null
+++ b/dune-project
@@ -0,0 +1,24 @@
+(lang dune 2.0)
+(generate_opam_files true)
+
+(name cryptokit)
+(source (github xavierleroy/cryptokit))
+(authors "Xavier Leroy")
+(maintainers "Xavier Leroy <xavier.leroy@college-de-france.fr>")
+
+(package
+ (name cryptokit)
+ (synopsis "A library of cryptographic primitives")
+
+ (description "Cryptokit includes block ciphers (AES, DES, 3DES), stream ciphers
+(ARCfour), public-key crypto (RSA, DH), hashes (SHA-1, SHA-256,
+SHA-3), MACs, compression, random number generation -- all presented
+with a compositional, extensible interface.")
+
+ (depends
+ (ocaml (>= 4.03.0))
+ (dune (>= 2.0))
+ dune-configurator
+ (zarith (>= 1.4))
+ conf-zlib
+ conf-gmp-powm-sec))
diff --git a/setup.ml b/setup.ml
deleted file mode 100644
index a07ec9f..0000000
--- a/setup.ml
+++ /dev/null
@@ -1,39 +0,0 @@
-(* setup.ml generated for the first time by OASIS v0.4.6 *)
-
-(* OASIS_START *)
-(* DO NOT EDIT (digest: a426e2d026defb34183b787d31fbdcff) *)
-(******************************************************************************)
-(* OASIS: architecture for building OCaml libraries and applications *)
-(* *)
-(* Copyright (C) 2011-2016, Sylvain Le Gall *)
-(* Copyright (C) 2008-2011, OCamlCore SARL *)
-(* *)
-(* 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, with the OCaml static compilation *)
-(* exception. *)
-(* *)
-(* 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 file COPYING for more *)
-(* details. *)
-(* *)
-(* You should have received a copy of the GNU Lesser General Public License *)
-(* along with this library; if not, write to the Free Software Foundation, *)
-(* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *)
-(******************************************************************************)
-
-let () =
- try
- Topdirs.dir_directory (Sys.getenv "OCAML_TOPLEVEL_PATH")
- with Not_found -> ()
-;;
-#use "topfind";;
-#require "oasis.dynrun";;
-open OASISDynRun;;
-
-let setup_t = BaseCompat.Compat_0_4.adapt_setup_t setup_t
-open BaseCompat.Compat_0_4
-(* OASIS_STOP *)
-let () = setup ();;
diff --git a/src/META b/src/META
deleted file mode 100644
index 98a8e7d..0000000
--- a/src/META
+++ /dev/null
@@ -1,12 +0,0 @@
-# OASIS_START
-# DO NOT EDIT (digest: 0b7c5c15af8df30a424bef17dc87d1b1)
-version = "1.15"
-description = "Cryptographic primitives"
-requires = "unix zarith"
-archive(byte) = "cryptokit.cma"
-archive(byte, plugin) = "cryptokit.cma"
-archive(native) = "cryptokit.cmxa"
-archive(native, plugin) = "cryptokit.cmxs"
-exists_if = "cryptokit.cma"
-# OASIS_STOP
-
diff --git a/src/api-cryptokit.odocl b/src/api-cryptokit.odocl
deleted file mode 100644
index c8577fb..0000000
--- a/src/api-cryptokit.odocl
+++ /dev/null
@@ -1,5 +0,0 @@
-# OASIS_START
-# DO NOT EDIT (digest: f65b9dc92e3f638af8533b26ac90c400)
-CryptokitBignum
-Cryptokit
-# OASIS_STOP
diff --git a/src/blake2.c b/src/blake2.c
new file mode 100644
index 0000000..cdd0384
--- /dev/null
+++ b/src/blake2.c
@@ -0,0 +1,314 @@
+/***********************************************************************/
+/* */
+/* The Cryptokit library */
+/* */
+/* Xavier Leroy, Collège de France and Inria */
+/* */
+/* Copyright 2020 Institut National de Recherche en Informatique et */
+/* en Automatique. All rights reserved. This file is distributed */
+/* under the terms of the GNU Library General Public License, with */
+/* the special exception on linking described in file LICENSE. */
+/* */
+/***********************************************************************/
+
+/* BLAKE2 hashing */
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+#include "blake2.h"
+
+static const uint8_t BLAKE2_sigma[12][16] = {
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
+ { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
+ { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
+ { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
+ { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
+ { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
+ { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
+ { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
+ { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
+ { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 },
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
+ { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }
+};
+
+/* BLAKE2b */
+
+static inline uint64_t U8TO64LE(unsigned char * src)
+{
+ return (uint64_t) src[0] | ((uint64_t) src[1] << 8)
+ | ((uint64_t) src[2] << 16) | ((uint64_t) src[3] << 24)
+ | ((uint64_t) src[4] << 32) | ((uint64_t) src[5] << 40)
+ | ((uint64_t) src[6] << 48) | ((uint64_t) src[7] << 56);
+}
+
+static inline uint64_t ROTR64(uint64_t x, int amount)
+{
+ return (x >> amount) | (x << (64 - amount));
+}
+
+static const uint64_t blake2b_iv[8] = {
+ UINT64_C(0x6a09e667f3bcc908),
+ UINT64_C(0xbb67ae8584caa73b),
+ UINT64_C(0x3c6ef372fe94f82b),
+ UINT64_C(0xa54ff53a5f1d36f1),
+ UINT64_C(0x510e527fade682d1),
+ UINT64_C(0x9b05688c2b3e6c1f),
+ UINT64_C(0x1f83d9abfb41bd6b),
+ UINT64_C(0x5be0cd19137e2179)
+};
+
+#define MIX2B(a,b,c,d,x,y) \
+ do { \
+ a += b + x; \
+ d = ROTR64(d ^ a, 32); \
+ c += d; \
+ b = ROTR64(b ^ c, 24); \
+ a += b + y; \
+ d = ROTR64(d ^ a, 16); \
+ c += d; \
+ b = ROTR64(b ^ c, 63); \
+ } while(0) \
+
+static void blake2b_compress(struct blake2b * s, unsigned char * data,
+ unsigned int numbytes, int is_last_block)
+{
+ uint64_t v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15;
+ uint64_t m[16];
+ int i;
+ const uint8_t * sigma;
+
+ /* Update the length */
+ s->len[0] += numbytes;
+ if (s->len[0] < numbytes) s->len[1]++; /* carry */
+ /* Initialize work space */
+ v0 = s->h[0]; v1 = s->h[1];
+ v2 = s->h[2]; v3 = s->h[3];
+ v4 = s->h[4]; v5 = s->h[5];
+ v6 = s->h[6]; v7 = s->h[7];
+ v8 = blake2b_iv[0]; v9 = blake2b_iv[1];
+ v10 = blake2b_iv[2]; v11 = blake2b_iv[3];
+ v12 = blake2b_iv[4] ^ s->len[0];
+ v13 = blake2b_iv[5] ^ s->len[1];
+ v14 = is_last_block ? ~ blake2b_iv[6] : blake2b_iv[6];
+ v15 = blake2b_iv[7];
+ /* Convert data to 16 64-bit words */
+ for (i = 0; i < 16; i++) {
+ m[i] = U8TO64LE(data + i * 8);
+ }
+ /* Twelve rounds of mixing */
+ for (i = 0; i < 12; i++) {
+ sigma = BLAKE2_sigma[i];
+ MIX2B(v0, v4, v8, v12, m[sigma[0]], m[sigma[1]]);
+ MIX2B(v1, v5, v9, v13, m[sigma[2]], m[sigma[3]]);
+ MIX2B(v2, v6, v10, v14, m[sigma[4]], m[sigma[5]]);
+ MIX2B(v3, v7, v11, v15, m[sigma[6]], m[sigma[7]]);
+ MIX2B(v0, v5, v10, v15, m[sigma[8]], m[sigma[9]]);
+ MIX2B(v1, v6, v11, v12, m[sigma[10]], m[sigma[11]]);
+ MIX2B(v2, v7, v8, v13, m[sigma[12]], m[sigma[13]]);
+ MIX2B(v3, v4, v9, v14, m[sigma[14]], m[sigma[15]]);
+ }
+ /* Update state */
+ s->h[0] ^= v0 ^ v8; s->h[1] ^= v1 ^ v9;
+ s->h[2] ^= v2 ^ v10; s->h[3] ^= v3 ^ v11;
+ s->h[4] ^= v4 ^ v12; s->h[5] ^= v5 ^ v13;
+ s->h[6] ^= v6 ^ v14; s->h[7] ^= v7 ^ v15;
+}
+
+void blake2b_init(struct blake2b * s,
+ int hashlen, int keylen, unsigned char * key)
+{
+ int i;
+ assert (0 < hashlen && hashlen <= 64);
+ assert (0 <= keylen && keylen <= 64);
+ for (i = 0; i < 8; i++) s->h[i] = blake2b_iv[i];
+ s->h[0] ^= 0x01010000 | (keylen << 8) | hashlen;
+ s->len[0] = s->len[1] = 0;
+ s->numbytes = 0;
+ /* If key was supplied, pad to 128 bytes and prepend to message */
+ if (keylen > 0) {
+ memset(s->buffer, 0, BLAKE2b_BLOCKSIZE);
+ memcpy(s->buffer, key, keylen);
+ s->numbytes = BLAKE2b_BLOCKSIZE;
+ }
+}
+
+void blake2b_add_data(struct blake2b * s,
+ unsigned char * data, size_t len)
+{
+ int n;
+ /* If data was left in buffer, pad it with fresh data and compress */
+ if (s->numbytes > 0) {
+ n = BLAKE2b_BLOCKSIZE - s->numbytes;
+ if (len <= n) {
+ /* Not enough fresh data to compress. Buffer the data. */
+ memcpy(s->buffer + s->numbytes, data, len);
+ s->numbytes += len;
+ return;
+ }
+ memcpy(s->buffer + s->numbytes, data, n);
+ blake2b_compress(s, s->buffer, BLAKE2b_BLOCKSIZE, 0);
+ data += n; len -= n;
+ }
+ /* Process data by blocks of BLAKE2b_BLOCKSIZE */
+ while (len > BLAKE2b_BLOCKSIZE) {
+ blake2b_compress(s, data, BLAKE2b_BLOCKSIZE, 0);
+ data += BLAKE2b_BLOCKSIZE; len -= BLAKE2b_BLOCKSIZE;
+ }
+ /* Save remaining data */
+ memcpy(s->buffer, data, len);
+ s->numbytes = len;
+}
+
+void blake2b_final(struct blake2b * s, int hashlen, unsigned char * hash)
+{
+ unsigned int i;
+ assert (0 < hashlen && hashlen <= 64);
+ /* The final block is composed of the remaining data padded with zeros. */
+ memset(s->buffer + s->numbytes, 0, BLAKE2b_BLOCKSIZE - s->numbytes);
+ blake2b_compress(s, s->buffer, s->numbytes, 1);
+ /* Extract the hash */
+ for (i = 0; i < hashlen; i++) {
+ hash[i] = s->h[i / 8] >> (8 * (i % 8));
+ }
+}
+
+/* BLAKE2s */
+
+static inline uint32_t U8TO32LE(unsigned char * src)
+{
+ return (uint32_t) src[0] | ((uint32_t) src[1] << 8)
+ | ((uint32_t) src[2] << 16) | ((uint32_t) src[3] << 24);
+}
+
+static inline uint32_t ROTR32(uint32_t x, int amount)
+{
+ return (x >> amount) | (x << (32 - amount));
+}
+
+static const uint32_t blake2s_iv[8] = {
+ UINT32_C(0x6A09E667),
+ UINT32_C(0xBB67AE85),
+ UINT32_C(0x3C6EF372),
+ UINT32_C(0xA54FF53A),
+ UINT32_C(0x510E527F),
+ UINT32_C(0x9B05688C),
+ UINT32_C(0x1F83D9AB),
+ UINT32_C(0x5BE0CD19)
+};
+
+#define MIX2S(a,b,c,d,x,y) \
+ do { \
+ a += b + x; \
+ d = ROTR32(d ^ a, 16); \
+ c += d; \
+ b = ROTR32(b ^ c, 12); \
+ a += b + y; \
+ d = ROTR32(d ^ a, 8); \
+ c += d; \
+ b = ROTR32(b ^ c, 7); \
+ } while(0) \
+
+static void blake2s_compress(struct blake2s * s, unsigned char * data,
+ unsigned int numbytes, int is_last_block)
+{
+ uint32_t v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15;
+ uint32_t m[16];
+ int i;
+ const uint8_t * sigma;
+
+ /* Update the length */
+ s->len[0] += numbytes;
+ if (s->len[0] < numbytes) s->len[1]++; /* carry */
+ /* Initialize work space */
+ v0 = s->h[0]; v1 = s->h[1];
+ v2 = s->h[2]; v3 = s->h[3];
+ v4 = s->h[4]; v5 = s->h[5];
+ v6 = s->h[6]; v7 = s->h[7];
+ v8 = blake2s_iv[0]; v9 = blake2s_iv[1];
+ v10 = blake2s_iv[2]; v11 = blake2s_iv[3];
+ v12 = blake2s_iv[4] ^ s->len[0];
+ v13 = blake2s_iv[5] ^ s->len[1];
+ v14 = is_last_block ? ~ blake2s_iv[6] : blake2s_iv[6];
+ v15 = blake2s_iv[7];
+ /* Convert data to 16 32-bit words */
+ for (i = 0; i < 16; i++) {
+ m[i] = U8TO32LE(data + i * 4);
+ }
+ /* Ten rounds of mixing */
+ for (i = 0; i < 10; i++) {
+ sigma = BLAKE2_sigma[i];
+ MIX2S(v0, v4, v8, v12, m[sigma[0]], m[sigma[1]]);
+ MIX2S(v1, v5, v9, v13, m[sigma[2]], m[sigma[3]]);
+ MIX2S(v2, v6, v10, v14, m[sigma[4]], m[sigma[5]]);
+ MIX2S(v3, v7, v11, v15, m[sigma[6]], m[sigma[7]]);
+ MIX2S(v0, v5, v10, v15, m[sigma[8]], m[sigma[9]]);
+ MIX2S(v1, v6, v11, v12, m[sigma[10]], m[sigma[11]]);
+ MIX2S(v2, v7, v8, v13, m[sigma[12]], m[sigma[13]]);
+ MIX2S(v3, v4, v9, v14, m[sigma[14]], m[sigma[15]]);
+ }
+ /* Update state */
+ s->h[0] ^= v0 ^ v8; s->h[1] ^= v1 ^ v9;
+ s->h[2] ^= v2 ^ v10; s->h[3] ^= v3 ^ v11;
+ s->h[4] ^= v4 ^ v12; s->h[5] ^= v5 ^ v13;
+ s->h[6] ^= v6 ^ v14; s->h[7] ^= v7 ^ v15;
+}
+
+void blake2s_init(struct blake2s * s,
+ int hashlen, int keylen, unsigned char * key)
+{
+ int i;
+ assert (0 < hashlen && hashlen <= 32);
+ assert (0 <= keylen && keylen <= 32);
+ for (i = 0; i < 8; i++) s->h[i] = blake2s_iv[i];
+ s->h[0] ^= 0x01010000 | (keylen << 8) | hashlen;
+ s->len[0] = s->len[1] = 0;
+ s->numbytes = 0;
+ /* If key was supplied, pad to 64 bytes and prepend to message */
+ if (keylen > 0) {
+ memset(s->buffer, 0, BLAKE2s_BLOCKSIZE);
+ memcpy(s->buffer, key, keylen);
+ s->numbytes = BLAKE2s_BLOCKSIZE;
+ }
+}
+
+void blake2s_add_data(struct blake2s * s,
+ unsigned char * data, size_t len)
+{
+ int n;
+ /* If data was left in buffer, pad it with fresh data and compress */
+ if (s->numbytes > 0) {
+ n = BLAKE2s_BLOCKSIZE - s->numbytes;
+ if (len <= n) {
+ /* Not enough fresh data to compress. Buffer the data. */
+ memcpy(s->buffer + s->numbytes, data, len);
+ s->numbytes += len;
+ return;
+ }
+ memcpy(s->buffer + s->numbytes, data, n);
+ blake2s_compress(s, s->buffer, BLAKE2s_BLOCKSIZE, 0);
+ data += n; len -= n;
+ }
+ /* Process data by blocks of BLAKE2s_BLOCKSIZE */
+ while (len > BLAKE2s_BLOCKSIZE) {
+ blake2s_compress(s, data, BLAKE2s_BLOCKSIZE, 0);
+ data += BLAKE2s_BLOCKSIZE; len -= BLAKE2s_BLOCKSIZE;
+ }
+ /* Save remaining data */
+ memcpy(s->buffer, data, len);
+ s->numbytes = len;
+}
+
+void blake2s_final(struct blake2s * s, int hashlen, unsigned char * hash)
+{
+ unsigned int i;
+ assert (0 < hashlen && hashlen <= 32);
+ /* The final block is composed of the remaining data padded with zeros. */
+ memset(s->buffer + s->numbytes, 0, BLAKE2s_BLOCKSIZE - s->numbytes);
+ blake2s_compress(s, s->buffer, s->numbytes, 1);
+ /* Extract the hash */
+ for (i = 0; i < hashlen; i++) {
+ hash[i] = s->h[i / 4] >> (8 * (i % 4));
+ }
+}
diff --git a/src/blake2.h b/src/blake2.h
new file mode 100644
index 0000000..1693b33
--- /dev/null
+++ b/src/blake2.h
@@ -0,0 +1,47 @@
+/***********************************************************************/
+/* */
+/* The Cryptokit library */
+/* */
+/* Xavier Leroy, Collège de France and Inria */
+/* */
+/* Copyright 2020 Institut National de Recherche en Informatique et */
+/* en Automatique. All rights reserved. This file is distributed */
+/* under the terms of the GNU Library General Public License, with */
+/* the special exception on linking described in file LICENSE. */
+/* */
+/***********************************************************************/
+
+/* BLAKE2b hashing */
+
+#define BLAKE2b_BLOCKSIZE 128
+
+struct blake2b {
+ uint64_t h[8];
+ uint64_t len[2];
+ int numbytes;
+ unsigned char buffer[BLAKE2b_BLOCKSIZE];
+};
+
+extern void blake2b_init(struct blake2b * s,
+ int hashlen, int keylen, unsigned char * key);
+extern void blake2b_add_data(struct blake2b * s,
+ unsigned char * data, size_t len);
+extern void blake2b_final(struct blake2b * s,
+ int hashlen, unsigned char * hash);
+
+#define BLAKE2s_BLOCKSIZE 64
+
+struct blake2s {
+ uint32_t h[8];
+ uint32_t len[2];
+ int numbytes;
+ unsigned char buffer[BLAKE2s_BLOCKSIZE];
+};
+
+extern void blake2s_init(struct blake2s * s,
+ int hashlen, int keylen, unsigned char * key);
+extern void blake2s_add_data(struct blake2s * s,
+ unsigned char * data, size_t len);
+extern void blake2s_final(struct blake2s * s,
+ int hashlen, unsigned char * hash);
+
diff --git a/src/config/config_vars.ml.default b/src/config/config_vars.ml.default
new file mode 100644
index 0000000..1b56c41
--- /dev/null
+++ b/src/config/config_vars.ml.default
@@ -0,0 +1,7 @@
+type 'a value =
+ | This of 'a
+ | Auto
+
+let enable_zlib = Auto
+
+let enable_hardware_support = Auto
diff --git a/src/config/dune b/src/config/dune
new file mode 100644
index 0000000..ece93d5
--- /dev/null
+++ b/src/config/dune
@@ -0,0 +1,7 @@
+(executable
+ (name flags)
+ (libraries dune-configurator))
+
+(rule
+ (mode fallback)
+ (action (copy config_vars.ml.default config_vars.ml)))
diff --git a/src/config/flags.ml b/src/config/flags.ml
new file mode 100644
index 0000000..f8f2157
--- /dev/null
+++ b/src/config/flags.ml
@@ -0,0 +1,45 @@
+(* Compute compilation and linking flags *)
+
+open Config_vars
+
+module Configurator = Configurator.V1
+
+(* Compile and link a dummy C program with the given flags. *)
+let test ~cfg ~c_flags ~link_flags =
+ let test_program = "int main() { return 0; }" in
+ Configurator.c_test cfg test_program ~c_flags ~link_flags
+
+let () = Configurator.main ~name:"cryptokit" (fun cfg ->
+ let os_type = Configurator.ocaml_config_var_exn cfg "os_type" in
+ let system = Configurator.ocaml_config_var_exn cfg "system" in
+ let architecture = Configurator.ocaml_config_var_exn cfg "architecture" in
+ let zlib = match enable_zlib with
+ | This bool -> bool
+ | Auto -> os_type <> "Win32"
+ in
+ let hardware_support = match enable_hardware_support with
+ | This bool -> bool
+ | Auto -> (architecture = "amd64" || architecture = "i386")
+ && test ~cfg ~c_flags:[ "-maes" ] ~link_flags:[]
+ in
+ let append_if c y x = if c then x @ [ y ] else x in
+ let flags =
+ []
+ |> append_if zlib "-DHAVE_ZLIB"
+ |> append_if hardware_support "-maes"
+ in
+ let library_flags =
+ []
+ |> append_if (zlib && (system = "win32" || system = "win64")) "zlib.lib"
+ |> append_if (zlib && system <> "win32" && system <> "win64") "-lz"
+ |> append_if (system = "win32" || system = "win64") "advapi32.lib"
+ |> append_if (system = "mingw" || system = "mingw64") "-ladvapi32"
+ in
+ Configurator.Flags.write_sexp "flags.sexp" flags;
+ Configurator.Flags.write_sexp "library_flags.sexp" library_flags;
+ let describe_bool = function
+ | true -> "enabled"
+ | false -> "disabled"
+ in
+ Printf.printf "ZLib: ............................... %s\n" (describe_bool zlib);
+ Printf.printf "Hardware support for AES and GCM: ... %s\n" (describe_bool hardware_support))
diff --git a/src/cryptokit.ml b/src/cryptokit.ml
index d2fd91e..dcb2629 100644
--- a/src/cryptokit.ml
+++ b/src/cryptokit.ml
@@ -90,6 +90,12 @@ external ripemd160_final: bytes -> string = "caml_ripemd160_final"
external md5_init: unit -> bytes = "caml_md5_init"
external md5_update: bytes -> bytes -> int -> int -> unit = "caml_md5_update"
external md5_final: bytes -> string = "caml_md5_final"
+external blake2b_init: int -> string -> bytes = "caml_blake2b_init"
+external blake2b_update: bytes -> bytes -> int -> int -> unit = "caml_blake2b_update"
+external blake2b_final: bytes -> int -> string = "caml_blake2b_final"
+external blake2s_init: int -> string -> bytes = "caml_blake2s_init"
+external blake2s_update: bytes -> bytes -> int -> int -> unit = "caml_blake2s_update"
+external blake2s_final: bytes -> int -> string = "caml_blake2s_final"
(* Abstract transform type *)
@@ -1092,6 +1098,56 @@ class md5 =
let md5 () = new md5
+class blake2b sz key =
+ object(self)
+ val context =
+ if sz >= 8 && sz <= 512 && sz mod 8 = 0 && String.length key <= 64
+ then blake2b_init (sz / 8) key
+ else raise (Error Wrong_key_size)
+ method hash_size = sz / 8
+ method add_substring src ofs len =
+ if ofs < 0 || len < 0 || ofs > Bytes.length src - len
+ then invalid_arg "blake2b#add_substring";
+ blake2b_update context src ofs len
+ method add_string src =
+ blake2b_update context (Bytes.unsafe_of_string src) 0 (String.length src)
+ method add_char c =
+ self#add_string (String.make 1 c)
+ method add_byte b =
+ self#add_char (Char.unsafe_chr b)
+ method result = blake2b_final context (sz / 8)
+ method wipe =
+ wipe_bytes context
+ end
+
+let blake2b sz = new blake2b sz ""
+let blake2b512 () = new blake2b 512 ""
+
+class blake2s sz key =
+ object(self)
+ val context =
+ if sz >= 8 && sz <= 256 && sz mod 8 = 0 && String.length key <= 32
+ then blake2s_init (sz / 8) key
+ else raise (Error Wrong_key_size)
+ method hash_size = sz / 8
+ method add_substring src ofs len =
+ if ofs < 0 || len < 0 || ofs > Bytes.length src - len
+ then invalid_arg "blake2s#add_substring";
+ blake2s_update context src ofs len
+ method add_string src =
+ blake2s_update context (Bytes.unsafe_of_string src) 0 (String.length src)
+ method add_char c =
+ self#add_string (String.make 1 c)
+ method add_byte b =
+ self#add_char (Char.unsafe_chr b)
+ method result = blake2s_final context (sz / 8)
+ method wipe =
+ wipe_bytes context
+ end
+
+let blake2s sz = new blake2s sz ""
+let blake2s256 () = new blake2s 256 ""
+
end
(* High-level entry points for ciphers *)
@@ -1114,6 +1170,7 @@ let make_block_cipher ?(mode = CBC) ?pad ?iv dir block_cipher =
(ECB, _) -> block_cipher
| (CBC, Encrypt) -> new Block.cbc_encrypt ?iv block_cipher
| (CBC, Decrypt) -> new Block.cbc_decrypt ?iv block_cipher
+
| (CFB n, Encrypt) -> new Block.cfb_encrypt ?iv n block_cipher
| (CFB n, Decrypt) -> new Block.cfb_decrypt ?iv n block_cipher
| (OFB n, _) -> new Block.ofb ?iv n block_cipher
@@ -1212,6 +1269,12 @@ let hmac_sha512 key = new HMAC_SHA512.hmac key
let hmac_ripemd160 key = new HMAC_RIPEMD160.hmac key
let hmac_md5 key = new HMAC_MD5.hmac key
+let blake2b sz key = new Hash.blake2b sz key
+let blake2b512 key = new Hash.blake2b 512 key
+
+let blake2s sz key = new Hash.blake2s sz key
+let blake2s256 key = new Hash.blake2s 256 key
+
let aes ?iv ?pad key =
new Block.mac ?iv ?pad (new Block.aes_encrypt key)
let des ?iv ?pad key =
diff --git a/src/cryptokit.mldylib b/src/cryptokit.mldylib
deleted file mode 100644
index c8577fb..0000000
--- a/src/cryptokit.mldylib
+++ /dev/null
@@ -1,5 +0,0 @@
-# OASIS_START
-# DO NOT EDIT (digest: f65b9dc92e3f638af8533b26ac90c400)
-CryptokitBignum
-Cryptokit
-# OASIS_STOP
diff --git a/src/cryptokit.mli b/src/cryptokit.mli
index 3cb58ed..0392eca 100644
--- a/src/cryptokit.mli
+++ b/src/cryptokit.mli
@@ -11,8 +11,6 @@
(* *)
(***********************************************************************)
-(* $Id$ *)
-
(** The Cryptokit library provides a variety of cryptographic primitives
that can be used to implement cryptographic protocols in
security-sensitive applications. The primitives provided include:
@@ -23,11 +21,6 @@
and MACs based on AES and DES.
- Random number generation.
- Encodings and compression: base 64, hexadecimal, Zlib compression.
-
- To use this library, link with
- [ocamlc unix.cma nums.cma cryptokit.cma]
- or
- [ocamlopt unix.cmxa nums.cmxa cryptokit.cmxa].
*)
(** {1 General-purpose abstract interfaces} *)
@@ -603,6 +596,22 @@ module Hash : sig
val sha512: unit -> hash
(** SHA-512 is SHA-2 specialized to 512 bit hashes (64 bytes). *)
+ val blake2b: int -> hash
+ (** The BLAKE2b hash function produces hashes of length 1 to 64 bytes.
+ The parameter is the desired size of the hash, in bits.
+ It must be between 8 and 512, and a multiple of 8. *)
+
+ val blake2b512: unit -> hash
+ (** BLAKE2b512 is BLAKE2b specialized to 512 bit hashes (64 bytes). *)
+
+ val blake2s: int -> hash
+ (** The BLAKE2s hash function produces hashes of length 1 to 32 bytes.
+ The parameter is the desired size of the hash, in bits.
+ It must be between 8 and 256, and a multiple of 8. *)
+
+ val blake2s256: unit -> hash
+ (** BLAKE2s256 is BLAKE2s specialized to 256 bit hashes (32 bytes). *)
+
val ripemd160: unit -> hash
(** RIPEMD-160 produces 160-bit hashes (20 bytes). *)
@@ -631,9 +640,10 @@ end
and if it matches the transmitted MAC, be reasonably certain that
the text was authentified by someone who possesses the secret key.
- The module [MAC] provides five MAC functions based on the hashes
- SHA-1, SHA256, SHA512, RIPEMD160 and MD5, and five MAC functions based on
- the block ciphers AES, DES, and Triple-DES. *)
+ The module [MAC] provides six MAC functions based on the hashes
+ BLAKE2b, SHA-1, SHA256, SHA512, RIPEMD160 and MD5,
+ and five MAC functions based on the block ciphers AES, DES, and Triple-DES.
+*)
module MAC: sig
val hmac_sha1: string -> hash
@@ -669,6 +679,34 @@ module MAC: sig
long. The [key] argument is the MAC key; it can have any length,
but a minimal length of 16 bytes is recommended. *)
+ val blake2b: int -> string -> hash
+ (** [blake2b sz key] is the BLAKE2b keyed hash function.
+ The returned hash values have length 1 to 64 bytes.
+ The [sz] is the desired size of the hash, in bits.
+ It must be between 8 and 512, and a multiple of 8.
+ The [key] argument is the MAC key. It must have length 64 at most.
+ A length of 64 bytes is recommended. *)
+
+ val blake2b512: string -> hash
+ (** [blake2b512 key] is the BLAKE2b keyed hash function specialized
+ to 512 byte hashes (64 bytes).
+ The [key] argument is the MAC key. It must have length 64 at most.
+ A length of 64 bytes is recommended. *)
+
+ val blake2s: int -> string -> hash
+ (** [blake2s sz key] is the BLAKE2s keyed hash function.
+ The returned hash values have length 1 to 32 bytes.
+ The [sz] is the desired size of the hash, in bits.
+ It must be between 8 and 256, and a multiple of 8.
+ The [key] argument is the MAC key. It must have length 32 at most.
+ A length of 32 bytes is recommended. *)
+
+ val blake2s256: string -> hash
+ (** [blake2s256 key] is the BLAKE2s keyed hash function specialized
+ to 256 byte hashes (32 bytes).
+ The [key] argument is the MAC key. It must have length 32 at most.
+ A length of 32 bytes is recommended. *)
+
val aes_cmac: ?iv:string -> string -> hash
(** [aes_cmac key] returns a MAC based on AES encryption in CMAC mode,
also known as OMAC1 mode. The input data is encrypted using
diff --git a/src/cryptokit.mllib b/src/cryptokit.mllib
deleted file mode 100644
index c8577fb..0000000
--- a/src/cryptokit.mllib
+++ /dev/null
@@ -1,5 +0,0 @@
-# OASIS_START
-# DO NOT EDIT (digest: f65b9dc92e3f638af8533b26ac90c400)
-CryptokitBignum
-Cryptokit
-# OASIS_STOP
diff --git a/src/dune b/src/dune
new file mode 100644
index 0000000..a6642bc
--- /dev/null
+++ b/src/dune
@@ -0,0 +1,41 @@
+(library (name cryptokit) (public_name cryptokit)
+ (libraries unix zarith)
+ (modules CryptokitBignum Cryptokit)
+ (foreign_stubs
+ (language c)
+ (flags -DCAML_NAME_SPACE (:include flags.sexp))
+ (names aesni
+ arcfour
+ stubs-arcfour
+ blowfish
+ stubs-blowfish
+ d3des
+ stubs-des
+ rijndael-alg-fst
+ ripemd160
+ stubs-ripemd160
+ sha1
+ stubs-sha1
+ sha256
+ stubs-sha256
+ sha512
+ stubs-sha512
+ stubs-aes
+ stubs-md5
+ stubs-misc
+ stubs-rng
+ stubs-zlib
+ keccak
+ stubs-sha3
+ chacha20
+ stubs-chacha20
+ blake2
+ stubs-blake2))
+ (c_library_flags (:include library_flags.sexp))
+ (flags :standard -safe-string -w -7 -w -27 -w -37))
+
+; compute flags
+(rule
+ (alias configure)
+ (targets flags.sexp library_flags.sexp)
+ (action (run config/flags.exe)))
diff --git a/src/libcryptokit_stubs.clib b/src/libcryptokit_stubs.clib
deleted file mode 100644
index 94cc08d..0000000
--- a/src/libcryptokit_stubs.clib
+++ /dev/null
@@ -1,28 +0,0 @@
-# OASIS_START
-# DO NOT EDIT (digest: c7ac7a160eaa5e93a581a4efbe9317de)
-aesni.o
-arcfour.o
-stubs-arcfour.o
-blowfish.o
-stubs-blowfish.o
-d3des.o
-stubs-des.o
-rijndael-alg-fst.o
-ripemd160.o
-stubs-ripemd160.o
-sha1.o
-stubs-sha1.o
-sha256.o
-stubs-sha256.o
-sha512.o
-stubs-sha512.o
-stubs-aes.o
-stubs-md5.o
-stubs-misc.o
-stubs-rng.o
-stubs-zlib.o
-keccak.o
-stubs-sha3.o
-chacha20.o
-stubs-chacha20.o
-# OASIS_STOP
diff --git a/src/stubs-blake2.c b/src/stubs-blake2.c
new file mode 100644
index 0000000..2ccd1d3
--- /dev/null
+++ b/src/stubs-blake2.c
@@ -0,0 +1,75 @@
+/***********************************************************************/
+/* */
+/* The Cryptokit library */
+/* */
+/* Xavier Leroy, Collège de France and Inria */
+/* */
+/* Copyright 2020 Institut National de Recherche en Informatique et */
+/* en Automatique. All rights reserved. This file is distributed */
+/* under the terms of the GNU Library General Public License, with */
+/* the special exception on linking described in file LICENSE. */
+/* */
+/***********************************************************************/
+
+#include <stdint.h>
+#include <string.h>
+#include <caml/mlvalues.h>
+#include <caml/memory.h>
+#include <caml/alloc.h>
+#include "blake2.h"
+
+#define blake2b_val(v) ((struct blake2b *) String_val(v))
+
+CAMLprim value caml_blake2b_init(value hashlen, value key)
+{
+ value ctx = caml_alloc_string(sizeof(struct blake2b));
+ blake2b_init(blake2b_val(ctx),
+ Int_val(hashlen),
+ caml_string_length(key), &Byte_u(key, 0));
+ return ctx;
+}
+
+CAMLprim value caml_blake2b_update(value ctx, value src, value ofs, value len)
+{
+ blake2b_add_data(blake2b_val(ctx),
+ &Byte_u(src, Long_val(ofs)), Long_val(len));
+ return Val_unit;
+}
+
+CAMLprim value caml_blake2b_final(value ctx, value hashlen)
+{
+ CAMLparam1(ctx);
+ CAMLlocal1(res);
+ int len = Int_val(hashlen);
+ res = caml_alloc_string(len);
+ blake2b_final(blake2b_val(ctx), len, &Byte_u(res, 0));
+ CAMLreturn(res);
+}
+
+#define blake2s_val(v) ((struct blake2s *) String_val(v))
+
+CAMLprim value caml_blake2s_init(value hashlen, value key)
+{
+ value ctx = caml_alloc_string(sizeof(struct blake2s));
+ blake2s_init(blake2s_val(ctx),
+ Int_val(hashlen),
+ caml_string_length(key), &Byte_u(key, 0));
+ return ctx;
+}
+
+CAMLprim value caml_blake2s_update(value ctx, value src, value ofs, value len)
+{
+ blake2s_add_data(blake2s_val(ctx),
+ &Byte_u(src, Long_val(ofs)), Long_val(len));
+ return Val_unit;
+}
+
+CAMLprim value caml_blake2s_final(value ctx, value hashlen)
+{
+ CAMLparam1(ctx);
+ CAMLlocal1(res);
+ int len = Int_val(hashlen);
+ res = caml_alloc_string(len);
+ blake2s_final(blake2s_val(ctx), len, &Byte_u(res, 0));
+ CAMLreturn(res);
+}
diff --git a/src/stubs-zlib.c b/src/stubs-zlib.c
index 1d9af34..dd84dba 100644
--- a/src/stubs-zlib.c
+++ b/src/stubs-zlib.c
@@ -186,12 +186,12 @@ static void caml_zlib_not_supported(void)
if (caml_zlib_error_exn == NULL) {
caml_zlib_error_exn = caml_named_value("Cryptokit.Error");
if (caml_zlib_error_exn == NULL)
- invalid_argument("Exception Cryptokit.Error not initialized");
+ caml_invalid_argument("Exception Cryptokit.Error not initialized");
}
- bucket = alloc_small(2, 0);
+ bucket = caml_alloc_small(2, 0);
Field(bucket, 0) = *caml_zlib_error_exn;
Field(bucket, 1) = Val_int(12); /* Compression_not_supported */
- mlraise(bucket);
+ caml_raise(bucket);
}
CAMLprim
diff --git a/test/dune b/test/dune
new file mode 100644
index 0000000..3e89187
--- /dev/null
+++ b/test/dune
@@ -0,0 +1,16 @@
+(test
+ (name test)
+ (modules test)
+ (libraries cryptokit)
+ (flags :standard -w -35))
+
+(executable
+ (name prngtest)
+ (modules prngtest)
+ (libraries cryptokit))
+
+(executable
+ (name speedtest)
+ (modules speedtest)
+ (libraries cryptokit)
+ (flags :standard -w -35))
diff --git a/test/speedtest.ml b/test/speedtest.ml
index 0552d90..8a3ea59 100644
--- a/test/speedtest.ml
+++ b/test/speedtest.ml
@@ -108,8 +108,12 @@ let _ =
(hash (Hash.sha3 384) 4000000 16);
time_fn "SHA-3 512, 64_000_000 bytes, 16-byte chunks"
(hash (Hash.sha3 512) 4000000 16);
+ time_fn "BLAKE2b 512, 64_000_000 bytes, 16-byte chunks"
+ (hash (Hash.blake2b 512) 4000000 16);
+ time_fn "BLAKE2s 256, 64_000_000 bytes, 16-byte chunks"
+ (hash (Hash.blake2s 256) 4000000 16);
time_fn "RIPEMD-160, 64_000_000 bytes, 16-byte chunks"
- (hash (Hash.sha256()) 4000000 16);
+ (hash (Hash.ripemd160()) 4000000 16);
time_fn "MD5, 64_000_000 bytes, 16-byte chunks"
(hash (Hash.md5()) 4000000 16);
time_fn "AES CMAC, 64_000_000 bytes, 16-byte chunks"
diff --git a/test/test.ml b/test/test.ml
index d5b7690..8ebfaff 100644
--- a/test/test.ml
+++ b/test/test.ml
@@ -41,6 +41,10 @@ let test test_number answer correct_answer =
printf " %d..." test_number
end
+(* Whether to run the most expensive tests or not *)
+
+let long_tests = ref false
+
(* Useful auxiliaries *)
let hex s = transform_string (Hexa.decode()) s
@@ -318,6 +322,7 @@ let _ =
(hex "84983E441C3BD26EBAAE4AA1F95129E5E54670F1");
test 6 (hash_million_a (Hash.sha1()))
(hex "34AA973CD4C4DAA4F61EEB2BDBAD27316534016F");
+ if !long_tests then
test 99 (hash_extremely_long (Hash.sha1()))
(hex "7789f0c9 ef7bfc40 d9331114 3dfbe69e 2017f592")
@@ -346,6 +351,7 @@ let _ =
(hex "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1");
test 4 (hash_million_a (Hash.sha2 256))
(hex "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0");
+ if !long_tests then
test 99 (hash_extremely_long (Hash.sha256()))
(hex "50e72a0e 26442fe2 552dc393 8ac58658 228c0cbf b1d2ca87 2ae43526 6fcd055e")
@@ -376,6 +382,7 @@ let _ =
(hex "8e959b75dae313da 8cf4f72814fc143f 8f7779c6eb9f7fa1 7299aeadb6889018 501d289e4900f7e4 331b99dec4b5433a c7d329eeb6dd2654 5e96e55b874be909");
test 5 (hash_million_a (Hash.sha2 512))
(hex "e718483d0ce76964 4e2e42c7bc15b463 8e1f98b13b204428 5632a803afa973eb de0ff244877ea60a 4cb0432ce577c31b eb009c5c2c49aa2e 4eadb217ad8cc09b");
+ if !long_tests then
test 99 (hash_extremely_long (Hash.sha2 512))
(hex "b47c933421ea2db1 49ad6e10fce6c7f9 3d0752380180ffd7 f4629a712134831d 77be6091b819ed35 2c2967a2e2d4fa50 50723c9630691f1a 05a7281dbe6c1086")
@@ -427,6 +434,7 @@ let _ =
(hex "eee9e24d78c18553 37983451df97c8ad 9eedf256c6334f8e 948d252d5e0e7684 7aa0774ddb90a842 190d2c558b4b8340");
test 20 (hash_million_a (Hash.sha3 512))
(hex "3c3a876da14034ab 60627c077bb98f7e 120a2a5370212dff b3385a18d4f38859 ed311d0a9d5141ce 9cc5c66ee689b266 a8aa18ace8282a0e 0db596c90b0a7b87");
+ if !long_tests then
test 99 (hash_extremely_long (Hash.sha3 512))
(hex "235ffd53504ef836 a1342b488f483b39 6eabbfe642cf78ee 0d31feec788b23d0 d18d5c339550dd59 58a500d4b95363da 1b5fa18affc1bab2 292dc63b7d85097c")
@@ -479,11 +487,67 @@ let _ =
(hex "2c23146a63a29acf 99e73b88f8c24eaa 7dc60aa771780ccc 006afbfa8fe2479b 2dd2b21362337441 ac12b515911957ff");
test 20 (hash 512 s)
(hex "0eab42de4c3ceb92 35fc91acffe746b2 9c29a8c366b7c60e 4e67c466f36a4304 c00fa9caf9d87976 ba469bcbe06713b4 35f091ef2769fb16 0cdab33d3670680e");
+ if !long_tests then
test 98 (hash_extremely_long (Hash.keccak 256))
(hex "5f313c39963dcf79 2b5470d4ade9f3a3 56a3e4021748690a 958372e2b06f82a4");
+ if !long_tests then
test 99 (hash_extremely_long (Hash.keccak 512))
(hex "3e122edaf3739823 1cfaca4c7c216c9d 66d5b899ec1d7ac6 17c40c7261906a45 fc01617a021e5da3 bd8d4182695b5cb7 85a28237cbb16759 0e34718e56d8aab8")
+(* BLAKE2b *)
+
+let _ =
+ testing_function "BLAKE2b-512";
+ let hash s = hash_string (Hash.blake2b512 ()) s in
+ test 1 (hash "")
+ (hex "786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce");
+ test 2 (hash "abc")
+ (hex "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923");
+ test 3 (hash "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu")
+ (hex "ce741ac5930fe346811175c5227bb7bfcd47f42612fae46c0809514f9e0e3a11ee1773287147cdeaeedff50709aa716341fe65240f4ad6777d6bfaf9726e5e52")
+
+let _ =
+ testing_function "BLAKE2b-512 (keyed)";
+ let mkstring n = String.init n (fun i -> Char.chr i) in
+ let key = mkstring 0x40 in
+ let hash s = hash_string (MAC.blake2b512 key) s in
+ List.iter
+ (fun (len, result) -> test len (hash (mkstring len)) (hex result))
+ [
+0, "10ebb67700b1868efb4417987acf4690ae9d972fb7a590c2f02871799aaa4786b5e996e8f0f4eb981fc214b005f42d2ff4233499391653df7aefcbc13fc51568";
+1, "961f6dd1e4dd30f63901690c512e78e4b45e4742ed197c3c5e45c549fd25f2e4187b0bc9fe30492b16b0d0bc4ef9b0f34c7003fac09a5ef1532e69430234cebd";
+2, "da2cfbe2d8409a0f38026113884f84b50156371ae304c4430173d08a99d9fb1b983164a3770706d537f49e0c916d9f32b95cc37a95b99d857436f0232c88a965";
+3, "33d0825dddf7ada99b0e7e307104ad07ca9cfd9692214f1561356315e784f3e5a17e364ae9dbb14cb2036df932b77f4b292761365fb328de7afdc6d8998f5fc1";
+4, "beaa5a3d08f3807143cf621d95cd690514d0b49efff9c91d24b59241ec0eefa5f60196d407048bba8d2146828ebcb0488d8842fd56bb4f6df8e19c4b4daab8ac";
+5, "098084b51fd13deae5f4320de94a688ee07baea2800486689a8636117b46c1f4c1f6af7f74ae7c857600456a58a3af251dc4723a64cc7c0a5ab6d9cac91c20bb";
+6, "6044540d560853eb1c57df0077dd381094781cdb9073e5b1b3d3f6c7829e12066bbaca96d989a690de72ca3133a83652ba284a6d62942b271ffa2620c9e75b1f";
+7, "7a8cfe9b90f75f7ecb3acc053aaed6193112b6f6a4aeeb3f65d3de541942deb9e2228152a3c4bbbe72fc3b12629528cfbb09fe630f0474339f54abf453e2ed52";
+128, "72065ee4dd91c2d8509fa1fc28a37c7fc9fa7d5b3f8ad3d0d7a25626b57b1b44788d4caf806290425f9890a3a2a35a905ab4b37acfd0da6e4517b2525c9651e4";
+192, "8d6cf87c08380d2d1506eee46fd4222d21d8c04e585fbfd08269c98f702833a156326a0724656400ee09351d57b440175e2a5de93cc5f80db6daf83576cf75fa";
+255, "142709d62e28fcccd0af97fad0f8465b971e82201dc51070faa0372aa43e92484be1c1e73ba10906d5d1853db6a4106e0a7bf9800d373d6dee2d46d62ef2a461"
+ ]
+
+let _ =
+ testing_function "BLAKE2s-256 (keyed)";
+ let mkstring n = String.init n (fun i -> Char.chr i) in
+ let key = mkstring 0x20 in
+ let hash s = hash_string (MAC.blake2s256 key) s in
+ List.iter
+ (fun (len, result) -> test len (hash (mkstring len)) (hex result))
+ [
+0, "48a8997da407876b3d79c0d92325ad3b89cbb754d86ab71aee047ad345fd2c49";
+1, "40d15fee7c328830166ac3f918650f807e7e01e177258cdc0a39b11f598066f1";
+2, "6bb71300644cd3991b26ccd4d274acd1adeab8b1d7914546c1198bbe9fc9d803";
+3, "1d220dbe2ee134661fdf6d9e74b41704710556f2f6e5a091b227697445dbea6b";
+4, "f6c3fbadb4cc687a0064a5be6e791bec63b868ad62fba61b3757ef9ca52e05b2";
+5, "49c1f21188dfd769aea0e911dd6b41f14dab109d2b85977aa3088b5c707e8598";
+6, "fdd8993dcd43f696d44f3cea0ff35345234ec8ee083eb3cada017c7f78c17143";
+7, "e6c8125637438d0905b749f46560ac89fd471cf8692e28fab982f73f019b83a9";
+128, "0c311f38c35a4fb90d651c289d486856cd1413df9b0677f53ece2cd9e477c60a";
+192, "5950d39a23e1545f301270aa1a12f2e6c453776e4d6355de425cc153f9818867";
+255, "3fb735061abc519dfe979e54c1ee5bfad0a9d858b3315bad34bde999efd724dd"
+ ]
+
(* RIPEMD-160 *)
let _ =
testing_function "RIPEMD-160";
@@ -904,14 +968,20 @@ let chisquare b =
let t = Char.code (Bytes.get b i) in
freq.(t) <- freq.(t) + 1
done;
- let t = Array.fold_left (fun s x -> let x = float x in s +. x *. x) 0.0 freq
- and r = float r
- and n = float n in
- let sr = 2.0 *. sqrt r in
- abs_float ((r *. t /. n) -. n -. r) <= sr
-
-let test_rng ?(len = 100000) (r: Random.rng) =
- let b = Bytes.create len in
+ let expected = float n /. float r in
+ let t =
+ Array.fold_left
+ (fun s x -> let d = float x -. expected in d *. d +. s)
+ 0.0 freq in
+ let chi2 = t /. expected in
+ let degfree = float r -. 1.0 in
+ (* The degree of freedom is high, so we approximate as a normal
+ distribution with mean equal to degfree and variance 2 * degfree.
+ Four sigmas correspond to a 99.9936% confidence interval. *)
+ chi2 <= degfree +. 4.0 *. sqrt (2.0 *. degfree)
+
+let test_rng ?(len = 10000) (r: Random.rng) =
+ let b = Bytes.make len '\000' in
r#random_bytes b 0 len;
r#wipe;
printf "chi^2 %s\n"