microsoft / microsoft/cask

Compute and document odds of collision for various scenarios.

Open
#58 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C#
Stars
6
Forks
6
Avg merge
8d 10h
Merged PRs (30d)
4

Description

All information below reflects the latest CASK data reordering principles in #60.

The output below first reflects the odds of collision for a key of certain size in a delimited scenario. i.e., the chances of a false positive scanning data with a data sequence of valid length, valid for CASK, which consists exclusively of base64url printable characters.

The second output shows the expected changes of a false positive scanning a stream of non-delimited base64url-encoded bytes. In this scenario, the odds of a collision is additive for every character in the data stream. The data below computes odds for a speculative yottabyte (i.e., approximately 1 million petabytes) of endless, non-delimited base64url-encoded data (itself a pathological case and not expected in practice).

The 384-bit key odds below reflect the fixed data shared by all keys. 128- and 512-bit keys require 16 bits of additional padding in a fixed location (and a 256-bit key requires 8 bits) to bring the sensitive component size to a 3-byte boundary. These key sizes, therefore have reduced chances of a collision with random data.

128-bit key odds of collision : 1 in 1,972,027,143,425,536,081,081
128-bit key false positives scanning non-delimited 1 YB stream : 557 (~36k / 2 ^ 16)

256-bit key odds of collision : 1 in 7,703,231,029,006,000,316
256-bit key false positives scanning non-delimited 1 YB stream : 142,733 (~36k / 2 ^ 8)

384-bit key odds of collision : 1 in 30,090,746,207,054,688
384-bit key false positives scanning non-delimited 1 YB stream : 36,539,859

512-bit key odds of collision : 1 in 1,972,027,143,425,536,081,081
512-bit key false positives scanning 1 non-deliminated YB stream : 557 (~36k / 2 ^ 16)

public static void Main()
{
    // This data describes all encoded CASK base64 locations that
    // have a fixed number of possible values. For example, the
    // single encoded character 'Q' must exist at a well-known
    // location in the CASK base64 string (1 of 64 legal values).
    // The data that describes the optional data size is limited
    // to five possible values (A-E) of 64 (to indicate that there
    // are 0 - 4 three-byte optional data sizes.
    var fixedEncodedCaskCharacters = new BigInteger[]
    {
                1, // 'Q'
                1, // 'J'
                1, // 'J'
                1, // 'Q'
                1, // 'A' reserved
                4, // [B-E] secret size
                5, // [A-E] optional data size
                1, // 'A' reserved
                1, // 'A' reserved
                12, // Month
                31, // Day
                24, // Hour
                60, // Minute
                60, // Second
    };

    BigInteger numeratorProduct = 1;
    BigInteger denominatorProduct = 1;

    foreach (var numerator in fixedEncodedCaskCharacters)
    {
        numeratorProduct *= numerator;
    }

    foreach (var numerator in fixedEncodedCaskCharacters)
    {
        denominatorProduct *= 64;
    }

    //                               1K    1MB    1GB    1TB   1EB    1PB    1ZB    1YB
    BigInteger chunk = (BigInteger)1024 * 1024 * 1024 * 1024 * 1000 * 1000 * 1000 * 1000;
    string chunkSize = "YB";

    Console.WriteLine();

    // A 128-bit key (16 bytes) requires 2 bytes of padding to bring the
    // padded size to a multiple of 3 bytes (18). The final encoded padded 16
    // bits will consist of an encoded character with four trailing zero bits
    // (of which there are 4 possibilities) followed by two encoded zeros
    // ('AA').
    BigInteger result128bits = (denominatorProduct * 64 * 64 * 64) / (numeratorProduct * 4 * 1 * 1);
    BigInteger fps128BitsPerChunk = chunk / result128bits;
    Console.WriteLine($"128-bit key odds of collision : 1 in {result128bits:N0}");
    Console.WriteLine($"128-bit key false positives scanning non-delimited 1 {chunkSize} stream : {fps128BitsPerChunk:N0}");

    Console.WriteLine();

    // A 256-bit key (32 bytes) requires 1 byte of padding to bring the
    // padded size to a multiple of 3 bytes (33). The final two 6-bit
    // encoded values will consist of an encoded character with two trailing
    // zero bits (of which there are 16 possibilities) followed by an
    // encoded zero ('A').
    BigInteger result256bits = (denominatorProduct * 64 * 64) / (numeratorProduct * 16 * 1);
    BigInteger fps256BitsPerChunk = chunk / result256bits;
    Console.WriteLine($"256-bit key odds of collision : 1 in {result256bits:N0}");
    Console.WriteLine($"256-bit key false positives scanning non-delimited 1 {chunkSize} stream : {fps256BitsPerChunk:N0}");

    Console.WriteLine();

    BigInteger result384bits = denominatorProduct / numeratorProduct;
    BigInteger fps384BitsPerChunk = chunk / result384bits;
    Console.WriteLine($"384-bit key odds of collision : 1 in {result384bits:N0}");
    Console.WriteLine($"384-bit key false positives scanning non-delimited 1 {chunkSize} stream : {fps384BitsPerChunk:N0}");

    Console.WriteLine();

    // A 512-bit key (64 bytes) requires 2 bytes of padding to bring the
    // padded size to a multiple of 3 bytes (66). The final encoded padded 16
    // bits will consist of an encoded character with four trailing zero bits
    // (of which there are 4 possibilities) followed by two encoded zeros
    // ('AA').

    BigInteger result512bits = (denominatorProduct * 64 * 64 * 64) / (numeratorProduct * 4 * 1 * 1);
    BigInteger fps512BitsPerChunk = chunk / result512bits;
    Console.WriteLine($"512-bit key odds of collision : 1 in {result512bits:N0}");
    Console.WriteLine($"512-bit key false positives scanning 1 non-deliminated {chunkSize} stream : {fps512BitsPerChunk:N0}");
}

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reviewing the latest CASK data reordering principles in #60, then inspect the supplied C# BigInteger calculation for the delimited and non-delimited scenarios. Verify the reported collision odds and false-positive counts for the 128-, 256-, 384-, and 512-bit keys, and document the confirmed results.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
cryptography, documentation
Issue type
Documentation
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.