BLAKE3 Hash Function for Ada
2022 Ma_Sys.ma <email@example.com>
This repository provides an Ada implementation of the BLAKE3 Hash Function reference implementation (cf. https://github.com/BLAKE3-team/BLAKE3/blob/master/reference_impl/reference_impl.rs).
This implementation supports hashes and keyed hashes. It does not currently implement key derivation.
Like the reference implementation, this library is available under CC0 and can
hence be freely integrated. See
LICENSE.txt for details.
The following dependencies are required for building:
- Ada compiler (
- And build tool (
cd test_suite ant run
install -DsT lib/libblake3.so /usr/local/lib/x86_64-linux-gnu install -m 644 -DT lib/blake3.ali /usr/local/lib/x86_64-linux-gnu/ada/adalib/blake3 install -m 644 -DT lib/blake3.ads /usr/local/share/ada/adainclude/blake3
This repository contains multiple subdirectories for the various components of the library.
/bo-blake3-ada | +-- lib/ | | | +-- blake3.adb *** This is the implementation. *** | | | +-- blake3.ads *** Implementation header file. *** | | | +-- build.xml Build instructions | +-- sample/ | | | +-- blake3hello.adb Minimal example program. | +-- test_suite/ Test program to process test vectors. | +-- test_vectors/ Test vector data and scripts. | +-- util/ | | | +-- blake3ada.adb Commandline sample application. | | | +-- build.xml Build instructions for Linux. | +-- README.md This file. | +-- LICENSE.txt CC0 license. | +-- build.xml Recursive antfile build instructions.
The important subdirectory regarding the library is
lib. If you do not
need tests or example programs, it is sufficient to compile and use only the
files from that directory.
This sample program computes the hash over
Hello world. (hex
48656c6c6f20776f726c642e0a). You can find it in directory
with Blake3; with Ada.Text_IO; procedure Blake3Hello is package Output_Formatter is new Ada.Text_IO.Integer_IO(Integer); Ctx: Blake3.Hasher := Blake3.Init; begin Ctx.Update("Hello world."); declare Result: constant String := Ctx.Final; Hex: String := "16#00#"; begin for I in Result'Range loop Output_Formatter.Put(Hex, Character'Pos(Result(I)), 16); Ada.Text_IO.Put(if Hex(1) = ' ' then ("0" & Hex(5 .. 5)) else Hex(4 .. 5)); end loop; end; end Blake3Hello;
The main complexity of this program arises from the necessity to write the
output. Neither a direct binary output to stdout, nor an easy means to convert
to hexadecimal are available in Ada. As a comparatively short alternative to
using a lookup table, this sample program uses the formatting provided by
Ada.Text_IO.Integer_IO and then postprocesses the output to cut-off any
16# leading markers and account for the output right-alignment.
Using the installed Library
Assuming the library is already installed on your system, you can compile and run the sample program as follows:
gnatmake -o blake3hello blake3hello.adb \ -aO/usr/lib/x86_64-linux-gnu/ada/adalib/blake3 \ -aI/usr/share/ada/adainclude/blake3 \ -largs -lblake3 ./blake3hello
Using the Library without Installation
If the library is not installed on your system, it can be integrated using multiple different approaches.
The quickest way to get started is to just include the
blake3.adb files into the source tree. Here is what the directory structure
may look like then:
... | +-- sample/ | +-- blake3.adb | +-- blake3.ads | +-- blake3hello.adb | +-- build.xml ...
Compilation and invocation then become trivial:
cp ../lib/blake3.ad? . gnatmake -o blake3hello blake3.adb ./blake3hello
Inclusion from different directory
It may not be suitable to just copy-over the files. In this case, it is also possible to import the compiled library from a different directory. Assume that the library is compiled but not installed, then the file structure may look as follows:
... +-- lib/ | +-- blake3.adb | +-- blake3.ads | +-- blake3.ali | +-- build.xml | +-- libblake3.so | +-- sample/ | +-- blake3hello.adb | +-- build.xml ...
Compilation and invocation then have to account for the library not being installed as follows:
gnatmake -o blake3hello blake3hello.adb -aO../lib -aI../lib -largs -lblake3 LD_LIBRARY_PATH=$PWD/../lib ./blake3hello
type U8 is mod 2**8; type U32 is new Interfaces.Unsigned_32; type Octets is array (U32 range <>) of U8; subtype U8x32 is Octets(0..31); type Hasher is tagged limited private;
U8: This type is used to represent a single byte.
U32: This type is used to represent a 32 bit word.
Octets: This type is used to represent a byte string.
U8x32: This type is used to represent a 32 bytes byte string.
Hasher: This type is used to represent an opaque context of operation.
String: Strings are used as an alternative representation of byte strings. This allows interfacing with other code without forcing it to use the types supplied by this library. Conversion between Octets and Strings can be performed by using the
for Octet_Var'Address use String_Var'Address;syntax if necessary.
Hasher contexts provided by this API represent the state of hashing.
Final does not update the state in any way, it is possible to
Final multiple times without expecting a change in output.
Additionally, it is possible to call
Final, then perform multiple
invocations and then call
Final again. The output of the last
corresponds to the concatenation of all data supplied through preceding uses
Update on the same context.
It is currently not possible to reset the context to discard the old computation state. If entirely new data is to be processed, it is suggested to create an entirely new context for this purpose.
Functions and Procedures
A detailed description of the API functions follows after the overview excerpt
-- Initialize as hash function function Init return Hasher; -- Initialize as keyed hash function function Init(Key: in U8x32) return Hasher; function Init(Key: in String) return Hasher with Pre => Key'Length = Key_Len; -- Add data to process. Do not call with "empty" Strings procedure Update(Self: in out Hasher; Input: in String) with Pre => Input'Length > 0; procedure Update(Self: in out Hasher; Input: in Octets); -- Compute hash, Octets-based API allows variable-length output function Final(Self: in Hasher) return String; procedure Final(Self: in Hasher; Out_Slice: out Octets);
function Init return Hasher
This function creates a BLAKE3 context to be used as a hash function. It has to be called before using any of the other API functions.
function Init(Key: in) return Hasher
This variant of
Init creates a BLAKE3 context to be used as a
keyed hash function. The user is free to either supply an
or a 32-byte
String which the library then interprets as
without incurring a notable performance overhead.
procedure Update(Self: in out Hasher; Input: in)
Use this function to supply the data that is considered input into the
(optionally keyed) BLAKE3 hashing function. The user is free to supply the
Octets or a regular
String which the library then interprets
This API expects the minimum number of bytes supplied to
Update to be 1.
Do not call it with empty arrays or strings.
procedure Final(Self: in Hasher) return String
This function outputs the 32-byte hash corresponding to the concatenation of all
data supplied with
Update to the provided
Hasher context and returns it as
a string with binary data. If this String is to be written to a text format,
a conversion to hexadecimal representation is recommended. See
util/blake3ada.adb for an easy means to achieve such a conversion.
procedure Final(Self: in Hasher; Out_Slice: out Octets)
Final implementation uses the internal
for output. Additionally, by providing an
Out_Slice of different length,
different lengths of hashes can be output. Note that BLAKE3 supports arbitrarily
long outputs as needed.
Rationale and Usage Recommendation
This library was created out of the need to process data from a Rust program that relies on BLAKE3 for all of its hashing operations. This should not deter you from using it for creating new hashes in new programs with this library, too. However, you are advised to also consider chosing a more widely supported hash function in order to avoid being dependent on a single implementation.
Feel free to send patches with bugfixes or missing functionality directly to firstname.lastname@example.org. Include a note to confirm that you are OK with these patches being included under CC0. Please note that API breaks are only accepted if very strong reasons exist to motivate them.