From 9c41faf9bd6fba0cc577d3786883926bf66b2ab0 Mon Sep 17 00:00:00 2001 From: Paul Duncan Date: Sat, 24 Feb 2024 00:47:18 -0500 Subject: add tests/cavp-tests --- tests/gen-shake-tests.rb | 199 ----------------------------------------------- 1 file changed, 199 deletions(-) delete mode 100755 tests/gen-shake-tests.rb (limited to 'tests/gen-shake-tests.rb') diff --git a/tests/gen-shake-tests.rb b/tests/gen-shake-tests.rb deleted file mode 100755 index 55aec7c..0000000 --- a/tests/gen-shake-tests.rb +++ /dev/null @@ -1,199 +0,0 @@ -#!/usr/bin/env ruby -# frozen_string_literal: true - -# -# Generate SHAKE128 and SHAKE256 test functions from response files in -# SHAKE byte test vectors archive (`shakebytetestvectors.zip`) from the -# Cryptographic Algorithm Validation Program (CAVP). -# -# Usage: -# # download archive of byte test vectors -# wget https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/sha3/shakebytetestvectors.zip -# -# # run script to generate test functions on standard output -# tests/gen-shake-tests.rb path/to/shakebytetestvectors.zip -# - -# load libraries -require 'zip' - -# number of elements per line of test data -PER_LINE = 128 - -# TODO -ALGOS = [{ - name: 'SHAKE128', # algo name - fn: 'shake128', # function prefix - - # response files - rsp_files: %w{ - SHAKE128ShortMsg.rsp - SHAKE128LongMsg.rsp - SHAKE128VariableOut.rsp - }, -}, { - name: 'SHAKE256', # algo name - fn: 'shake256', # function prefix - - # response files - rsp_files: %w{ - SHAKE256ShortMsg.rsp - SHAKE256LongMsg.rsp - SHAKE256VariableOut.rsp - }, -}] - -# test vector template -TEST_TMPL = <d, %d, %d, %d, %d, %d }, -END_TEST_TMPL - -# test function template -FN_TMPL = <s tests from shakebytetestvectors.zip -static void test_%s_xof_cmvp(void) { - // data for tests - static const uint8_t DATA[] = { -%s - }; // total size = %d - - // response file names - static const char *RSP_FILES[] = { %s }; - - // test vectors - static const struct { - const size_t rsp_file_ofs, // offset of source file name in RSP_FILES - rsp_file_line, // line within rsp file - src_ofs, // message offset into DATA - src_len, // message length of data - exp_ofs, // expected output offset into DATA - exp_len; // expected output length - } TESTS[] = { -%s - }; - - // run tests - for (size_t i = 0; i < sizeof(TESTS) / sizeof(TESTS[0]); i++) { - // get expected result - const uint8_t * const exp = DATA + TESTS[i].exp_ofs; - const size_t exp_len = TESTS[i].exp_len; - - // hash data into "got" - uint8_t got[%d] = { 0 }; - %s_xof_once(DATA + TESTS[i].src_ofs, TESTS[i].src_len, got, exp_len); - - // check for expected result - if (memcmp(got, exp, exp_len)) { - // get response file name and test vector line - const char * const file_name = RSP_FILES[TESTS[i].rsp_file_ofs]; - const size_t file_line = TESTS[i].rsp_file_line; - - fprintf(stderr, "test_%s_xof_cmvp[%%zu, \\"%%s\\", line %%zu] failed:\\ngot = ", i, file_name, file_line); - dump_hex(stderr, got, exp_len); - fprintf(stderr, "\\nexp = "); - dump_hex(stderr, exp, exp_len); - fprintf(stderr, "\\n"); - } - } -} -END_FN_TMPL - -# parse hash of key/value pairs into test vector row -def parse(file, h, data_size, &block) - # parse hex-encoded message into array of bytes, then - # truncate message to "Len" bytes, if "Len" is specified - src = h[:Msg].scan(/../).map { |s| s.to_i(16) } - src = src[0, h[:Len].to_i] if h.key?(:Len) - src_ofs = data_size - - # parse hex-encoded expected output into array of bytes, then - # truncate expected output to "OutputLen" bytes, if "OutputLen" is - # specified - exp = h[:Output].scan(/../).map { |s| s.to_i(16) } - exp = exp[0, h[:OutputLen].to_i] if h.key?(:OutputLen) - exp_ofs = data_size + src.size - - # append message bytes and expected output bytes to data - block.call(src + exp) - - # return parsed entry - { - file: file, - line: h[:line], - - # message - src_ofs: src_ofs, - src_len: src.size, - - # expected output - exp_ofs: exp_ofs, - exp_len: exp.size, - } -end - -# get zip path from first command-line argument -zip_path = ARGV.shift -raise "Usage #$0 " unless zip_path - -# open zip file -Zip::File.open(zip_path, 'rb') do |zip| - ALGOS.each do |algo| - data = [] # test data (shared across all rsp files) - - # parse test vectors from rsp files - rows = algo[:rsp_files].each_with_object([]) do |rsp_file, rows| - curr = {} # current row - - # read lines from rsp file - lines = zip.glob(rsp_file).first.get_input_stream.readlines.to_a.map { |line| line.strip } - - # parse lines into rows - lines.size.times.each do |line_i| - case lines[line_i] - when /^(\w+) = (\w+)$/ - k, v = $1, $2 # extract key and value - curr[k.intern] = v - - # cache line number - curr[:line] = line_i unless curr[:line] - when '' - if curr.size > 0 - # parse current hash into test vector and add it to results - rows << parse(rsp_file, curr, data.size) { |bytes| data += bytes } - end - - curr = {} # clear current hash - end - end - end - - # get maximum length of expected output - # used to for size of "got" buffer in emitted code - max_exp_len = rows.reduce(0) { |r, row| row[:exp_len] > r ? row[:exp_len] : r } - - # get maximum number of lines of emitted static DATA array - num_lines = data.size / PER_LINE + ((data.size % PER_LINE) > 0 ? 1 : 0) - - # generate test function - puts(FN_TMPL % { - name: algo[:name], # algorithm name - fn: algo[:fn], # algorithm function prefix - - # test vector data - data: num_lines.times.map { |ofs| - " %s,\n" % [data[PER_LINE * ofs, PER_LINE].join(', ')] - }.join, - - # response file names - rsp_files: algo[:rsp_files].map { |file| '"%s"' % [file] }.join(', '), - - data_size: data.size, # total size of emitted DATA array, in bytes - max_exp_len: max_exp_len, # maximum expected output length, in bytes - - # test vectors - tests: rows.map { |row| - TEST_TMPL % row.merge({ file_pos: algo[:rsp_files].index(row[:file]) }) - }.join, - }) - end -end -- cgit v1.2.3