< Summary

Information
Class: ArturRios.Util.Hashing.HashConfiguration
Assembly: ArturRios.Util
File(s): /home/ci/agent/workspace/dotnet-util-docs_main/app/src/Hashing/HashConfiguration.cs
Line coverage
100%
Covered lines: 18
Uncovered lines: 0
Coverable lines: 18
Total lines: 86
Line coverage: 100%
Branch coverage
100%
Covered branches: 2
Total branches: 2
Branch coverage: 100%
Method coverage
100%
Covered methods: 6
Fully covered methods: 6
Total methods: 6
Method coverage: 100%
Full method coverage: 100%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
get_DegreeOfParallelism()100%11100%
get_NumberOfIterations()100%11100%
get_MemoryToUseInKb()100%11100%
Positive(...)100%11100%
EnoughForLanes(...)100%22100%

File(s)

/home/ci/agent/workspace/dotnet-util-docs_main/app/src/Hashing/HashConfiguration.cs

#LineLine coverage
 1namespace ArturRios.Util.Hashing;
 2
 3/// <summary>
 4/// Configuration values for controlling Argon2id hashing cost parameters.
 5/// </summary>
 6/// <remarks>
 7/// The defaults are deliberately expensive: a single hash reserves
 8/// <see cref="DefaultMemoryToUseInKb"/> kilobytes (roughly 600 MB) across
 9/// <see cref="DefaultDegreeOfParallelism"/> lanes. That is appropriate for a login path that runs rarely,
 10/// but a server hashing many secrets concurrently will exhaust its memory long before its CPU, so size the
 11/// parameters against the expected concurrency. Note that changing them invalidates existing hashes:
 12/// a stored hash can only be verified with the configuration it was produced with.
 13/// </remarks>
 14/// <param name="degreeOfParallelism">Number of threads (lanes) to use; defaults to <see cref="DefaultDegreeOfParallelis
 15/// <param name="numberOfIterations">Number of iterations; defaults to <see cref="DefaultNumberOfIterations"/>.</param>
 16/// <param name="memoryToUseInKb">Memory size in kilobytes; defaults to <see cref="DefaultMemoryToUseInKb"/>.</param>
 17/// <exception cref="ArgumentOutOfRangeException">
 18/// Any supplied value is less than one, or the memory is smaller than four kilobytes per lane
 19/// (<c>4 × degreeOfParallelism</c>), which Argon2 cannot run with: the hash used to fail only later, inside
 20/// <see cref="Hash"/>, with an <see cref="AggregateException"/>.
 21/// </exception>
 3322public class HashConfiguration(
 3323    int? degreeOfParallelism = null,
 3324    int? numberOfIterations = null,
 3325    int? memoryToUseInKb = null)
 26{
 27    /// <summary>
 28    /// Default parallelism (threads) used when unspecified.
 29    /// </summary>
 30    public const int DefaultDegreeOfParallelism = 16;
 31
 32    /// <summary>
 33    /// Default recommended minimum iteration count.
 34    /// </summary>
 35    public const int DefaultNumberOfIterations = 4;
 36
 37    /// <summary>
 38    /// Default memory cost (600 MB) expressed in kilobytes.
 39    /// </summary>
 40    public const int DefaultMemoryToUseInKb = 600000;
 41
 42    /// <summary>
 43    /// Gets the configured degree of parallelism.
 44    /// </summary>
 2345    public int DegreeOfParallelism { get; } =
 4346        Positive(degreeOfParallelism ?? DefaultDegreeOfParallelism, nameof(degreeOfParallelism));
 47
 48    /// <summary>
 49    /// Gets the configured number of iterations.
 50    /// </summary>
 2351    public int NumberOfIterations { get; } =
 4152        Positive(numberOfIterations ?? DefaultNumberOfIterations, nameof(numberOfIterations));
 53
 54    /// <summary>
 55    /// Gets the configured memory usage in kilobytes.
 56    /// </summary>
 6257    public int MemoryToUseInKb { get; } = EnoughForLanes(
 3958        Positive(memoryToUseInKb ?? DefaultMemoryToUseInKb, nameof(memoryToUseInKb)),
 3959        degreeOfParallelism ?? DefaultDegreeOfParallelism);
 60
 61    /// <summary>
 62    /// Rejects cost parameters Argon2 cannot honour.
 63    /// </summary>
 64    private static int Positive(int value, string parameterName)
 65    {
 12366        ArgumentOutOfRangeException.ThrowIfLessThan(value, 1, parameterName);
 67
 11768        return value;
 69    }
 70
 71    /// <summary>
 72    /// Rejects a memory size too small to give every lane the four 1 KB blocks Argon2 requires.
 73    /// </summary>
 74    private static int EnoughForLanes(int memoryToUseInKb, int degreeOfParallelism)
 75    {
 3776        var minimum = 4L * degreeOfParallelism;
 77
 3778        if (memoryToUseInKb < minimum)
 79        {
 480            throw new ArgumentOutOfRangeException(nameof(memoryToUseInKb), memoryToUseInKb,
 481                $"Memory must be at least 4 KB per degree of parallelism ({minimum} KB for {degreeOfParallelism}).");
 82        }
 83
 3384        return memoryToUseInKb;
 85    }
 86}