mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Add Poly1305 Universal Hashing Algorithm (MAC) (#2639)
* Add Poly1305 Universal Hashing Algorithm (MAC)
This commit is contained in:
212
test/unit/stdlib/hash/poly1305.c3
Normal file
212
test/unit/stdlib/hash/poly1305.c3
Normal file
@@ -0,0 +1,212 @@
|
||||
// Copyright (c) 2025 Zack Puhl <github@xmit.xyz>. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license
|
||||
// a copy of which can be found in the LICENSE_STDLIB file.
|
||||
//
|
||||
// Poly1305 code dedicated from repo: https://github.com/NotsoanoNimus/chacha20_aead.c3l (but massively cleaned)
|
||||
module std::hash::poly1305_test;
|
||||
import std::hash::poly1305;
|
||||
|
||||
macro @run(char[] plaintext, char[poly1305::KEY_SIZE] key, char[poly1305::TAG_SIZE] expected_tag) @private
|
||||
{
|
||||
char[poly1305::TAG_SIZE] tag = poly1305::hash(plaintext, key);
|
||||
test::@check(tag == expected_tag, "`poly1305::hash()`: Did not get expected tag.");
|
||||
}
|
||||
|
||||
|
||||
// Actual tests go here...
|
||||
//
|
||||
// You should check out RFC 8439 for more information.
|
||||
// NOTE: from RFC tests, `len - 1` (or `[..^1]`) is used to get rid of the string's null-terminator per test requirements.
|
||||
//
|
||||
// Extra tests taken from Google's BoringSSL:
|
||||
// https://github.com/google/boringssl/blob/main/crypto/poly1305/poly1305_tests.txt
|
||||
module std::hash::poly1305_test @test;
|
||||
import std::hash::poly1305;
|
||||
import std::math;
|
||||
|
||||
fn void rfc8439_s2_5_2() => @run(
|
||||
"Cryptographic Forum Research Group"[..^1],
|
||||
{ 0x85, 0xd6, 0xbe, 0x78, 0x57, 0x55, 0x6d, 0x33, 0x7f, 0x44, 0x52, 0xfe, 0x42, 0xd5, 0x06, 0xa8, 0x01, 0x03, 0x80, 0x8a, 0xfb, 0x0d, 0xb2, 0xfd, 0x4a, 0xbf, 0xf6, 0xaf, 0x41, 0x49, 0xf5, 0x1b },
|
||||
{ 0xa8, 0x06, 0x1d, 0xc1, 0x30, 0x51, 0x36, 0xc6, 0xc2, 0x2b, 0x8b, 0xaf, 0x0c, 0x01, 0x27, 0xa9 }
|
||||
);
|
||||
|
||||
fn void rfc8439_sA_3_1() => @run(
|
||||
((char[64]){ [0..63] = 0 })[..], // 64 null bytes
|
||||
{}, // empty key
|
||||
{ [0..15] = 0 }, // empty tag is expected
|
||||
);
|
||||
|
||||
fn void rfc8439_sA_3_2() => @run(
|
||||
`Any submission to the IETF intended by the Contributor for publication as all or part of an IETF Internet-Draft or RFC and any statement made within the context of an IETF activity is considered an "IETF Contribution". Such statements include oral statements in IETF sessions, as well as written and electronic communications made at any time or place, which are addressed to`[..^1],
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0xe5, 0xf6, 0xb5, 0xc5, 0xe0, 0x60, 0x70, 0xf0, 0xef, 0xca, 0x96, 0x22, 0x7a, 0x86, 0x3e },
|
||||
{ 0x36, 0xe5, 0xf6, 0xb5, 0xc5, 0xe0, 0x60, 0x70, 0xf0, 0xef, 0xca, 0x96, 0x22, 0x7a, 0x86, 0x3e }
|
||||
);
|
||||
|
||||
fn void rfc8439_sA_3_3() => @run(
|
||||
`Any submission to the IETF intended by the Contributor for publication as all or part of an IETF Internet-Draft or RFC and any statement made within the context of an IETF activity is considered an "IETF Contribution". Such statements include oral statements in IETF sessions, as well as written and electronic communications made at any time or place, which are addressed to`[..^1],
|
||||
{ 0x36, 0xe5, 0xf6, 0xb5, 0xc5, 0xe0, 0x60, 0x70, 0xf0, 0xef, 0xca, 0x96, 0x22, 0x7a, 0x86, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0xf3, 0x47, 0x7e, 0x7c, 0xd9, 0x54, 0x17, 0xaf, 0x89, 0xa6, 0xb8, 0x79, 0x4c, 0x31, 0x0c, 0xf0 }
|
||||
);
|
||||
|
||||
fn void rfc8439_sA_3_4() => @run(
|
||||
"'Twas brillig, and the slithy toves\nDid gyre and gimble in the wabe:\nAll mimsy were the borogoves,\nAnd the mome raths outgrabe."[..^1],
|
||||
{ 0x1c, 0x92, 0x40, 0xa5, 0xeb, 0x55, 0xd3, 0x8a, 0xf3, 0x33, 0x88, 0x86, 0x04, 0xf6, 0xb5, 0xf0, 0x47, 0x39, 0x17, 0xc1, 0x40, 0x2b, 0x80, 0x09, 0x9d, 0xca, 0x5c, 0xbc, 0x20, 0x70, 0x75, 0xc0 },
|
||||
{ 0x45, 0x41, 0x66, 0x9a, 0x7e, 0xaa, 0xee, 0x61, 0xe7, 0x08, 0xdc, 0x7c, 0xbc, 0xc5, 0xeb, 0x62 },
|
||||
);
|
||||
|
||||
// RFC NOTE: If one uses 130-bit partial reduction, does the code handle the case where partially reduced final result is not fully reduced?
|
||||
fn void rfc8439_sA_3_5() => @run(
|
||||
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
|
||||
{ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
|
||||
);
|
||||
|
||||
// RFC NOTE: What happens if addition of s overflows module 2^128?
|
||||
fn void rfc8439_sA_3_6() => @run(
|
||||
{ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
|
||||
{ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
|
||||
);
|
||||
|
||||
// RFC NOTE: What happens if data limb is all ones and there is carry from lower limb?
|
||||
fn void rfc8439_sA_3_7() => @run(
|
||||
{
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
},
|
||||
{ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
|
||||
);
|
||||
|
||||
// RFC NOTE: What happens if final result from polynomial part is exactly 2^130-5?
|
||||
fn void rfc8439_sA_3_8() => @run(
|
||||
{
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xfb, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
},
|
||||
{ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
|
||||
);
|
||||
|
||||
// RFC NOTE: What happens if final result from polynomial part is exactly 2^130-6?
|
||||
fn void rfc8439_sA_3_9() => @run(
|
||||
{ 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
|
||||
{ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }
|
||||
);
|
||||
|
||||
// RFC NOTE: What happens if 5*H+L-type reduction produces 131-bit intermediate result?
|
||||
fn void rfc8439_sA_3_10() => @run(
|
||||
{
|
||||
0xe3, 0x35, 0x94, 0xd7, 0x50, 0x5e, 0x43, 0xb9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x33, 0x94, 0xd7, 0x50, 0x5e, 0x43, 0x79, 0xcd, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
},
|
||||
{ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
|
||||
);
|
||||
|
||||
// RFC NOTE: What happens if 5*H+L-type reduction produces 131-bit final result?
|
||||
fn void rfc8439_sA_3_11() => @run(
|
||||
{
|
||||
0xe3, 0x35, 0x94, 0xd7, 0x50, 0x5e, 0x43, 0xb9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x33, 0x94, 0xd7, 0x50, 0x5e, 0x43, 0x79, 0xcd, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
},
|
||||
{ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
|
||||
);
|
||||
|
||||
fn void boringssl_misc_regressions_1() => @run(
|
||||
x'cccccccccccccccccccccccccccccccccccccccccccccccccc80ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccceccccccccccccccccccccccccccccccccccccc5cccccccccccccccccccccccccccccccccccccccccce3ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccaccccccccccccccccccccce6cccccccccc000000afccccccccccccccccccfffffff5000000000000000000000000000000000000000000000000000000ffffffe70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000719205a8521dfc',
|
||||
x'7f1b02640000000000000000000000000000000000000000cccccccccccccccc',
|
||||
x'8559b876eceed66eb37798c0457baff9'
|
||||
);
|
||||
|
||||
fn void boringssl_misc_regressions_2() => @run(
|
||||
x'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa000000000000000000800264',
|
||||
x'e00016000000000000000000000000000000aaaaaaaaaaaaaaaaaaaaaaaaaaaa',
|
||||
x'00bd1258978e205444c9aaaa82006fed'
|
||||
);
|
||||
|
||||
fn void boringssl_misc_regressions_3() => @run(
|
||||
x'02fc',
|
||||
x'0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c',
|
||||
x'06120c0c0c0c0c0c0c0c0c0c0c0c0c0c'
|
||||
);
|
||||
|
||||
fn void boringssl_misc_regressions_4() => @run(
|
||||
x'7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7a7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b5c7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b6e7b007b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7a7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b5c7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b7b6e7b001300000000b300000000000000000000000000000000000000000000f20000000000000000000000000000000000002000efff0009000000000000000000000000100000000009000000640000000000000000000000001300000000b300000000000000000000000000000000000000000000f20000000000000000000000000000000000002000efff00090000000000000000007a000010000000000900000064000000000000000000000000000000000000000000000000fc',
|
||||
x'00ff000000000000000000000000000000000000001e00000000000000007b7b',
|
||||
x'33205bbf9e9f8f7212ab9e2ab9b7e4a5'
|
||||
);
|
||||
|
||||
fn void boringssl_misc_regressions_5() => @run(
|
||||
x'89dab80b7717c1db5db437860a3f70218e93e1b8f461fb677f16f35f6f87e2a91c99bc3a47ace47640cc95c345be5ecca5a3523c35cc01893af0b64a620334270372ec12482d1b1e363561698a578b359803495bb4e2ef1930b17a5190b580f141300df30adbeca28f6427a8bc1a999fd51c554a017d095d8c3e3127daf9f595',
|
||||
x'2d773be37adb1e4d683bf0075e79c4ee037918535a7f99ccb7040fb5f5f43aea',
|
||||
x'c85d15ed44c378d6b00e23064c7bcd51'
|
||||
);
|
||||
|
||||
|
||||
// Streaming tests.
|
||||
fn void boringssl_misc_regressions_1_streamed()
|
||||
{
|
||||
char[poly1305::KEY_SIZE] key = x'7f1b02640000000000000000000000000000000000000000cccccccccccccccc';
|
||||
Poly1305 p @noinit;
|
||||
p.init(key);
|
||||
p.update(x'cccccccccccccccccccccccccccccccccccccccccccccccccc');
|
||||
p.update(x'80ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccce');
|
||||
p.update(x'cc');
|
||||
p.update(x'ccccccccccccccccccccccccccccccccccc5cccccccccccccccccccccccccccccccccccccccccce3ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccac');
|
||||
p.update(x'cccccccccccccccccccce6cccccccccc000000afccccccccccccccccccfffffff5000000000000000000000000000000000000000000000000000000ffffffe7');
|
||||
p.update(x'0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000');
|
||||
p.update(x'719205a8521d');
|
||||
p.update(x'fc');
|
||||
test::@check(p.final() == x'8559b876eceed66eb37798c0457baff9', "Unequal Stream vs. Fixed hash.");
|
||||
}
|
||||
|
||||
fn void boringssl_misc_regressions_5_streamed()
|
||||
{
|
||||
char[poly1305::KEY_SIZE] key = x'2d773be37adb1e4d683bf0075e79c4ee037918535a7f99ccb7040fb5f5f43aea';
|
||||
Poly1305 p @noinit;
|
||||
p.init(key);
|
||||
p.update(x'89dab80b7717c1db5db437860a3f70218e93e1b8');
|
||||
p.update(x'f461');
|
||||
p.update(x'fb677f16f35f6f87e2a91c99bc3a47ace47640cc95c345be5ecca5a3523c35cc01893af0b64a620334270372ec12482d1b1e363561698a578b359803495bb4e2ef1930');
|
||||
p.update(x'b17a5190b580f141300df30adbeca28f6427a8bc1a999fd51c554a017d095d8c3e3127daf9f595');
|
||||
test::@check(p.final() == x'c85d15ed44c378d6b00e23064c7bcd51', "Unequal Stream vs. Fixed hash.");
|
||||
}
|
||||
|
||||
|
||||
// Equivalencies.
|
||||
const TEST_ITERATIONS = 2050;
|
||||
fn void equivalencies()
|
||||
{
|
||||
Lcg64Random rand;
|
||||
random::seed(&rand, 0x1337_aaa6_f4a0_1337);
|
||||
|
||||
char[poly1305::KEY_SIZE] key = x'2d773be37adb1e4d683bf0075e79c4ee037918535a7f99ccb7040fb5f5f43aea';
|
||||
char[TEST_ITERATIONS] plain = { [0..(TEST_ITERATIONS - 1)] = rand.next_byte() };
|
||||
|
||||
usz j = 0;
|
||||
for (usz i = 2; i < TEST_ITERATIONS; ++i, j = 0)
|
||||
{
|
||||
Poly1305 p @noinit;
|
||||
p.init(key);
|
||||
while (j < i)
|
||||
{
|
||||
usz jump = max(1, min(rand.next_byte(), i - 1 - j));
|
||||
p.update(plain[j:jump]);
|
||||
j += jump;
|
||||
}
|
||||
|
||||
char[poly1305::TAG_SIZE] streamed = p.final();
|
||||
char[poly1305::TAG_SIZE] fixed = poly1305::tag(plain[:i], key);
|
||||
|
||||
test::@check(streamed == fixed, "Streamed vs. Fixed for random inputs not equal at index %d", i);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user