Skip to content

Commit

Permalink
Add SHAKE vectors
Browse files Browse the repository at this point in the history
Add a separate module for SHAKE vectors, including a protobuf
descriptor and classes, a parsing script, and the source files.

The protobuf uses the new format with some differences from the one
included in the SHA module: we combine the tests from ShortMsg, LongMsg,
and VariableOut files into the `tests` field, and add the `mc_test`
field containing the Monte-Carlo test. This way, all tests for a given
algorithm and orientation fit in one single instance of ShakeVectors.

Note that users of these vectors (us) are expected to check whether this
is a valid test before using it, as sources other than NIST CAVP are not
expected to provide this one.
  • Loading branch information
JulioLoayzaM committed Feb 12, 2025
1 parent 5f013d4 commit 82faf14
Show file tree
Hide file tree
Showing 21 changed files with 47,226 additions and 0 deletions.
408 changes: 408 additions & 0 deletions crypto_condor/vectors/_shake/cavp/bit/SHAKE128LongMsg.rsp

Large diffs are not rendered by default.

411 changes: 411 additions & 0 deletions crypto_condor/vectors/_shake/cavp/bit/SHAKE128Monte.rsp

Large diffs are not rendered by default.

10,764 changes: 10,764 additions & 0 deletions crypto_condor/vectors/_shake/cavp/bit/SHAKE128ShortMsg.rsp

Large diffs are not rendered by default.

4,694 changes: 4,694 additions & 0 deletions crypto_condor/vectors/_shake/cavp/bit/SHAKE128VariableOut.rsp

Large diffs are not rendered by default.

408 changes: 408 additions & 0 deletions crypto_condor/vectors/_shake/cavp/bit/SHAKE256LongMsg.rsp

Large diffs are not rendered by default.

411 changes: 411 additions & 0 deletions crypto_condor/vectors/_shake/cavp/bit/SHAKE256Monte.rsp

Large diffs are not rendered by default.

8,716 changes: 8,716 additions & 0 deletions crypto_condor/vectors/_shake/cavp/bit/SHAKE256ShortMsg.rsp

Large diffs are not rendered by default.

4,984 changes: 4,984 additions & 0 deletions crypto_condor/vectors/_shake/cavp/bit/SHAKE256VariableOut.rsp

Large diffs are not rendered by default.

408 changes: 408 additions & 0 deletions crypto_condor/vectors/_shake/cavp/byte/SHAKE128LongMsg.rsp

Large diffs are not rendered by default.

411 changes: 411 additions & 0 deletions crypto_condor/vectors/_shake/cavp/byte/SHAKE128Monte.rsp

Large diffs are not rendered by default.

1,356 changes: 1,356 additions & 0 deletions crypto_condor/vectors/_shake/cavp/byte/SHAKE128ShortMsg.rsp

Large diffs are not rendered by default.

5,639 changes: 5,639 additions & 0 deletions crypto_condor/vectors/_shake/cavp/byte/SHAKE128VariableOut.rsp

Large diffs are not rendered by default.

408 changes: 408 additions & 0 deletions crypto_condor/vectors/_shake/cavp/byte/SHAKE256LongMsg.rsp

Large diffs are not rendered by default.

411 changes: 411 additions & 0 deletions crypto_condor/vectors/_shake/cavp/byte/SHAKE256Monte.rsp

Large diffs are not rendered by default.

1,100 changes: 1,100 additions & 0 deletions crypto_condor/vectors/_shake/cavp/byte/SHAKE256ShortMsg.rsp

Large diffs are not rendered by default.

6,239 changes: 6,239 additions & 0 deletions crypto_condor/vectors/_shake/cavp/byte/SHAKE256VariableOut.rsp

Large diffs are not rendered by default.

18 changes: 18 additions & 0 deletions crypto_condor/vectors/_shake/shake.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"SHAKE256": {
"byte": [
"cavp-SHAKE256-byte.pb2"
],
"bit": [
"cavp-SHAKE256-bit.pb2"
]
},
"SHAKE128": {
"byte": [
"cavp-SHAKE128-byte.pb2"
],
"bit": [
"cavp-SHAKE128-bit.pb2"
]
}
}
62 changes: 62 additions & 0 deletions crypto_condor/vectors/_shake/shake.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
syntax = "proto3";

package crypto_condor;

// A single SHAKE test vector.
message ShakeTest {
// The test ID, unique in its set of vectors.
int32 id = 1;
// The type of test. One of: valid, invalid, acceptable.
string type = 2;
// A comment on the test.
string comment = 3;
// Flags that categorize this test.
repeated string flags = 4;

// The input message.
bytes msg = 5;
// The resulting digest.
bytes out = 6;
}

// A Monte-Carlo test -- refer to SHA3VS from CAVP for usage instructions.
message ShakeMcTest {
// The test ID, unique in its set of vectors.
int32 id = 1;
// The type of test. One of: valid, invalid, acceptable.
string type = 2;
// A comment on the test.
string comment = 3;
// Flags that categorize this test.
repeated string flags = 4;

// The initial message.
bytes seed = 5;
// A dictionary of checkpoints: the indexes are the keys, the checkpoints
// are the values.
map<int32, bytes> checkpoints = 6;
}

// A set of SHAKE test vectors.
message ShakeVectors {
// The source of the test vectors.
string source = 1;
// Description of the source.
string source_desc = 2;
// The URL of the source.
string source_url = 3;
// Whether these are compliance test vectors or not.
bool compliance = 4;
// A dictionary of test flags and their description.
map<string, string> notes = 5;
// The test vectors.
repeated ShakeTest tests = 6;
// The Monte-Carlo test. This field is used for NIST CAVP tests and is not required.
// Users of this class are expected to check the presence of this field.
ShakeMcTest mc_test = 7;

// The SHAKE variant.
string algorithm = 8;
// The orientation of the implementation: bit- or byte-oriented.
string orientation = 9;
}
142 changes: 142 additions & 0 deletions crypto_condor/vectors/_shake/shake_import.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
"""Module to import SHAKE test vectors.
.. caution::
This module is intended for developers of this tool, as it's only used for
testing and packaging, has hard-coded filenames, and uses relative paths.
"""

import json
from collections import defaultdict
from pathlib import Path

from crypto_condor.vectors._shake.shake_pb2 import ShakeVectors

VECTORS_DIR = Path("crypto_condor/vectors/_shake")


def parse_cavp(algorithm: str, orientation: str):
"""Parses SHAKE test vectors from NIST CAVP."""
assert algorithm in {"SHAKE128", "SHAKE256"}
assert orientation in {"bit", "byte"}
file = VECTORS_DIR / "cavp" / orientation / f"{algorithm}ShortMsg.rsp"
blocks = file.read_text().split("\n\n")
file = VECTORS_DIR / "cavp" / orientation / f"{algorithm}LongMsg.rsp"
blocks += file.read_text().split("\n\n")
file = VECTORS_DIR / "cavp" / orientation / f"{algorithm}VariableOut.rsp"
blocks += file.read_text().split("\n\n")

vectors = ShakeVectors(
source="NIST CAVP",
source_desc="Vectors from the ShortMsg and LongMsg files.",
source_url="https://csrc.nist.gov/Projects/Cryptographic-Algorithm-Validation-Program/Secure-Hashing#sha3vsha3vss",
compliance=True,
algorithm=algorithm,
orientation=orientation,
)

count = 0
for block in blocks:
block = block.strip()
if not block or block.startswith(("#", "[")):
continue

count += 1

test = vectors.tests.add()
test.id = count
test.type = "valid"

is_null = False
lines = block.split("\n")
for line in lines:
key, value = line.split(" = ")
match key:
case "Len":
is_null = int(value) == 0
case "Msg":
if is_null:
test.msg = b""
is_null = False
else:
test.msg = bytes.fromhex(value)
case "Output":
test.out = bytes.fromhex(value)
case "COUNT":
# Since we are combining the files we do not use the included count.
continue
case "Outputlen":
# We recompute the output length at runtime from the output.
continue
case _:
raise ValueError("Unknown key '%s'" % key)

# Now parse Monte-Carlo vectors.
file = VECTORS_DIR / "cavp" / orientation / f"{algorithm}Monte.rsp"
blocks = file.read_text().split("\n\n")

vectors.mc_test.id = 1
vectors.mc_test.type = "valid"
vectors.mc_test.flags.extend(["MonteCarlo"])

count = 0
for block in blocks:
block = block.strip()
if block.startswith(("[", "#")) or not block:
continue

for line in block.split("\n"):
key, value = line.split(" = ")
match key:
case "Msg":
vectors.mc_test.seed = bytes.fromhex(value)
case "COUNT":
count = int(value)
case "Output":
vectors.mc_test.checkpoints[count] = bytes.fromhex(value)
case "Outputlen":
continue
case _:
raise ValueError(f"Unknown key {key}")

# Finally, write the vectors to a file.
file = VECTORS_DIR / "pb2" / f"cavp-{algorithm}-{orientation}.pb2"
file.write_bytes(vectors.SerializeToString())


def generate_json() -> None:
"""Generates the JSON file categorizing test vectors."""
pb2_dir = VECTORS_DIR / "pb2"
vectors: dict[str, dict[str, list[str]]] = defaultdict(lambda: defaultdict(list))

for file in pb2_dir.iterdir():
_vec = ShakeVectors()
_vec.ParseFromString(file.read_bytes())
vectors[_vec.algorithm][_vec.orientation].append(file.name)

out = VECTORS_DIR / "shake.json"
with out.open("w") as fp:
json.dump(vectors, fp, indent=2)


def main():
"""Imports SHA test vectors."""
pb2_dir = VECTORS_DIR / "pb2"
pb2_dir.mkdir(exist_ok=True)

params = [
(algo, orient)
for algo in {"SHAKE128", "SHAKE256"}
for orient in {"bit", "byte"}
]

for algo, orient in params:
parse_cavp(algo, orient)

generate_json()

imported_marker = VECTORS_DIR / "shake.imported"
imported_marker.touch()


if __name__ == "__main__":
main()
48 changes: 48 additions & 0 deletions crypto_condor/vectors/_shake/shake_pb2.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 82faf14

Please sign in to comment.