Table of Contents

DeferredFinalBlockHashAlgorithm Class

Definition

Namespace
Bodu.Security.Cryptography
Assembly
Bodu.Security.Cryptography.dll
Package
Bodu.Security.Cryptography 1.2.0
Source
DeferredFinalBlockHashAlgorithm.cs

Base class for hash algorithms that defer compression of the final full block until HashFinal() so that a finalization flag may be raised on the last compression call (the Blake-family shape). Owns the defer-on-full-block buffering loop and the zero-pad-then-finalize orchestration; the residual buffer, running byte counter, and disposal latch are inherited from BufferedBlockHashAlgorithm.

public abstract class DeferredFinalBlockHashAlgorithm : BufferedBlockHashAlgorithm, ICryptoTransform, IDisposable
Inheritance
DeferredFinalBlockHashAlgorithm
Implements
Derived
Inherited Members
Extension Methods

Examples

// Consume through a concrete BLAKE-family derivative - the base class defers the final
// block until HashFinal so the compression call can carry isFinal: true.
using HashAlgorithm hash = new Blake3();
byte[] digest = hash.ComputeHash("hello"u8.ToArray());

// Streaming use - the deferral remains transparent across TransformBlock calls.
using HashAlgorithm streaming = new Blake2s();
streaming.TransformBlock(buffer1, 0, buffer1.Length, null, 0);
streaming.TransformBlock(buffer2, 0, buffer2.Length, null, 0);
streaming.TransformFinalBlock(Array.Empty<byte>(), 0, 0);
byte[] result = streaming.Hash!;

Remarks

Unlike Merkle–Damgård hashes, Blake-family compression functions take a per-block byte counter and an isFinal flag. The final compression call must carry both the actual total byte count of the message and isFinal: true. This base class implements the consequent invariant: a block that fills the residual buffer exactly is not compressed at the point it is filled, because the algorithm cannot yet tell whether the caller will supply more data. Compression of that block is deferred until either (a) the next HashCore(ReadOnlySpan<byte>) call provides at least one more byte (in which case the pending block is compressed with isFinal: false) or (b) HashFinal() is called (in which case the pending block is compressed with isFinal: true).

The inherited Bodu.Security.Cryptography.BufferedBlockHashAlgorithm._totalBytes field stores the total number of bytes already compressed (i.e. consumed from the residual buffer by previous ProcessBlock(ReadOnlySpan<byte>, ulong, bool) calls). Bytes still held in the residual buffer are not included in this total — they contribute to the counter only at the moment they are compressed.

Derived classes must implement the following:

When to derive from this class. Pick DeferredFinalBlockHashAlgorithm for the BLAKE family and any other algorithm whose compression function takes an explicit "is this the final block?" flag rather than padding the trailing partial block with a length encoding - Blake3 is the canonical user. For BLAKE2-style hashes that also accept an optional secret key (Blake2b, Blake2s) derive from KeyedDeferredFinalBlockHashAlgorithm, which adds RFC 7693 key-block handling on top of this base. For Merkle-Damgård hashes (SHA-2, Tiger, Whirlpool) use BlockHashAlgorithm.

Constructors

DeferredFinalBlockHashAlgorithm(int)

Initializes a new instance of the DeferredFinalBlockHashAlgorithm class with the specified input block size.

protected DeferredFinalBlockHashAlgorithm(int blockSize)

Parameters

blockSize int

The fixed size, in bits, of each block consumed by the algorithm. Must be a positive multiple of 8.

Exceptions

ArgumentOutOfRangeException

Thrown when blockSize is less than or equal to zero.

Methods

HashCore(ReadOnlySpan<byte>)

Consumes the supplied input span using the deferred-final-block buffering rule. At the start of every iteration of the inner loop, if the residual buffer is already full and the caller has supplied at least one more byte, the held block is compressed with isFinal: false and the counter is advanced before the new byte is copied in. Compression of a block that fills the buffer exactly is otherwise deferred to HashFinal() so that isFinal: true may be raised on it.

protected override void HashCore(ReadOnlySpan<byte> source)

Parameters

source ReadOnlySpan<byte>

The input bytes to consume. May be empty, partial, exact-block, or multi-block in length.

Exceptions

ObjectDisposedException

The algorithm instance has been disposed.

CryptographicUnexpectedOperationException

On target frameworks prior to .NET 6, the hash algorithm has already been finalized and cannot accept more input.

HashFinal()

Finalizes the hash computation. Zero-pads the residual buffer (if not already full) up to the block size, performs the final compression with isFinal: true and a counter equal to the total bytes consumed ( Bodu.Security.Cryptography.BufferedBlockHashAlgorithm._totalBytes plus the residual byte count), and returns the digest produced by ProcessFinalBlock().

protected override byte[] HashFinal()

Returns

byte[]

The computed hash bytes as produced by ProcessFinalBlock().

Exceptions

ObjectDisposedException

The algorithm instance has been disposed.

CryptographicUnexpectedOperationException

On target frameworks prior to .NET 6, the hash computation has already been finalized.

ProcessBlock(ReadOnlySpan<byte>, ulong, bool)

Compresses a single full block of input using the algorithm's internal compression function.

protected abstract void ProcessBlock(ReadOnlySpan<byte> block, ulong totalBytesIncludingThisBlock, bool isFinal)

Parameters

block ReadOnlySpan<byte>

The input block to compress. Always exactly BlockSize bytes long, possibly zero-padded by HashFinal() when isFinal is true.

totalBytesIncludingThisBlock ulong

The cumulative byte count including the bytes in block being compressed. For mid-stream blocks this equals the previous total plus BlockSize; for the final compression it equals the previous total plus the residual byte count (which may be in the range [0, BlockSize / 8]).

isFinal bool

true for the last compression call (raised by HashFinal()); otherwise false. Algorithms that maintain a finalization flag should consult this parameter rather than tracking message length internally.

Remarks

Implementations must not retain a reference to the supplied span beyond the call — the underlying buffer is the inherited residual buffer and may be overwritten by subsequent input.

ProcessFinalBlock()

Extracts the digest from the algorithm's chaining variables after ProcessBlock(ReadOnlySpan<byte>, ulong, bool) has been called with isFinal: true for the last time.

protected abstract byte[] ProcessFinalBlock()

Returns

byte[]

A byte array containing the final computed hash value.

Remarks

This method is invoked once per HashFinal() call, immediately after the final compression. It reads from the internal hash state and serializes the result to a byte array in the format expected by consumers of the algorithm (typically little-endian for Blake-family hashes).

Applies to

ProductVersions
.NET8, 10

See Also