Add tests
This commit is contained in:
parent
255d6ad9f1
commit
e19966f329
14 changed files with 34490 additions and 24 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -2,3 +2,4 @@
|
|||
*.o
|
||||
*.bundle
|
||||
Makefile
|
||||
test/test_vectors.rb
|
||||
|
|
18
Makefile
Normal file
18
Makefile
Normal file
|
@ -0,0 +1,18 @@
|
|||
.phony: all clean test
|
||||
|
||||
all: ext/digest/Makefile
|
||||
make -C ext/digest
|
||||
|
||||
ext/digest/Makefile: ext/digest/extconf.rb
|
||||
cd ext/digest && ruby extconf.rb
|
||||
|
||||
clean:
|
||||
if [[ -f ext/digest/Makefile ]]; then make -C ext/digest clean; fi
|
||||
rm -f ext/digest/Makefile
|
||||
rm -f test/test_vectors.rb
|
||||
|
||||
test: all test/test_vectors.rb
|
||||
ruby test/test_all.rb
|
||||
|
||||
test/test_vectors.rb: test/generate_tests.rb test/data/*
|
||||
ruby test/generate_tests.rb > test/test_vectors.rb
|
10
README.md
10
README.md
|
@ -1,6 +1,6 @@
|
|||
# The SHA-3 (Keccak) extension for Ruby
|
||||
|
||||
This Ruby extension implements the SHA-3 (Keccak) cryptographic hashing algorithm. It is based on the reference C implementation, version 3.2. The exposed interface is almost identical to that of the `digest` standard library.
|
||||
This Ruby extension implements the SHA-3 ([Keccak](http://keccak.noekeon.org/)) cryptographic hashing algorithm. It is based on the reference C implementation, version 3.2. The exposed interface is almost identical to that of the `digest` standard library.
|
||||
|
||||
## Installation
|
||||
|
||||
|
@ -30,3 +30,11 @@ Keccak supports 5 hash lengths: 224-bit, 256-bit, 384-bit, 512-bit and variable
|
|||
|
||||
# You can pass a hash length to the constructor.
|
||||
digest = Digest::SHA3.new(224)
|
||||
|
||||
## Running the test suite
|
||||
|
||||
Run the test suite as follows:
|
||||
|
||||
make test
|
||||
|
||||
A part of the test suite is automatically generated from Keccak's reference test suite.
|
||||
|
|
|
@ -13,6 +13,7 @@ Gem::Specification.new do |s|
|
|||
s.files = Dir[
|
||||
"README.md",
|
||||
"LICENSE",
|
||||
"Makefile",
|
||||
"digest-sha3.gemspec",
|
||||
"ext/**/*.{c,h,rb}",
|
||||
"lib/**/*"
|
||||
|
|
|
@ -11,9 +11,17 @@ typedef struct {
|
|||
} RbSHA3;
|
||||
|
||||
static VALUE
|
||||
rb_sha3_new(int argc, VALUE *argv, VALUE klass) {
|
||||
rb_sha3_alloc(VALUE klass) {
|
||||
RbSHA3 *ctx;
|
||||
|
||||
ctx = (RbSHA3 *) xmalloc(sizeof(RbSHA3));
|
||||
ctx->bitlen = -1;
|
||||
return Data_Wrap_Struct(klass, 0, xfree, ctx);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
rb_sha3_initialize(int argc, VALUE *argv, VALUE self) {
|
||||
RbSHA3 *ctx;
|
||||
VALUE obj;
|
||||
VALUE hashlen;
|
||||
int i_hashlen;
|
||||
|
||||
|
@ -22,18 +30,16 @@ rb_sha3_new(int argc, VALUE *argv, VALUE klass) {
|
|||
} else {
|
||||
i_hashlen = NUM2INT(hashlen);
|
||||
}
|
||||
|
||||
ctx = (RbSHA3 *) xmalloc(sizeof(RbSHA3));
|
||||
obj = Data_Wrap_Struct(klass, 0, xfree, ctx);
|
||||
ctx->bitlen = i_hashlen;
|
||||
|
||||
if (ctx->bitlen == 0) {
|
||||
if (i_hashlen == 0) {
|
||||
rb_raise(rb_eRuntimeError, "Unsupported hash length");
|
||||
}
|
||||
|
||||
Data_Get_Struct(self, RbSHA3, ctx);
|
||||
ctx->bitlen = i_hashlen;
|
||||
|
||||
switch (Init(&ctx->state, i_hashlen)) {
|
||||
case SUCCESS:
|
||||
return obj;
|
||||
return self;
|
||||
case FAIL:
|
||||
rb_raise(rb_eRuntimeError, "Unknown error");
|
||||
return Qnil;
|
||||
|
@ -47,19 +53,15 @@ rb_sha3_new(int argc, VALUE *argv, VALUE klass) {
|
|||
}
|
||||
|
||||
static VALUE
|
||||
rb_sha3_copy(VALUE copy, VALUE obj) {
|
||||
RbSHA3 *ctx_copy, *ctx_obj;
|
||||
rb_sha3_initialize_copy(VALUE self, VALUE other) {
|
||||
RbSHA3 *ctx_self, *ctx_other;
|
||||
|
||||
Data_Get_Struct(copy, RbSHA3, ctx_copy);
|
||||
Data_Get_Struct(obj, RbSHA3, ctx_obj);
|
||||
if (copy == obj) {
|
||||
return copy;
|
||||
}
|
||||
rb_check_frozen(copy);
|
||||
|
||||
memcpy(&ctx_copy->state, &ctx_obj->state, sizeof(hashState));
|
||||
ctx_copy->bitlen = ctx_obj->bitlen;
|
||||
return copy;
|
||||
rb_check_frozen(self);
|
||||
Data_Get_Struct(self, RbSHA3, ctx_self);
|
||||
Data_Get_Struct(other, RbSHA3, ctx_other);
|
||||
memcpy(&ctx_self->state, &ctx_other->state, sizeof(hashState));
|
||||
ctx_self->bitlen = ctx_other->bitlen;
|
||||
return self;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
|
@ -123,8 +125,9 @@ void __attribute__((visibility("default")))
|
|||
Init_sha3() {
|
||||
mDigest = rb_define_module("Digest");
|
||||
cSHA3 = rb_define_class_under(mDigest, "SHA3", rb_cObject);
|
||||
rb_define_singleton_method(cSHA3, "new", rb_sha3_new, -1);
|
||||
rb_define_method(cSHA3, "initialize_copy", rb_sha3_copy, 1);
|
||||
rb_define_alloc_func(cSHA3, rb_sha3_alloc);
|
||||
rb_define_method(cSHA3, "initialize", rb_sha3_initialize, -1);
|
||||
rb_define_method(cSHA3, "initialize_copy", rb_sha3_initialize_copy, 1);
|
||||
rb_define_method(cSHA3, "reset", rb_sha3_reset, 0);
|
||||
rb_define_method(cSHA3, "update", rb_sha3_update, 1);
|
||||
rb_define_method(cSHA3, "<<", rb_sha3_update, 1);
|
||||
|
|
1543
test/data/LongMsgKAT_224.txt
Executable file
1543
test/data/LongMsgKAT_224.txt
Executable file
File diff suppressed because one or more lines are too long
3
test/data/README
Normal file
3
test/data/README
Normal file
|
@ -0,0 +1,3 @@
|
|||
From KeccakKAT-3.zip
|
||||
|
||||
http://keccak.noekeon.org/KeccakKAT-3.zip
|
8195
test/data/ShortMsgKAT_224.txt
Executable file
8195
test/data/ShortMsgKAT_224.txt
Executable file
File diff suppressed because it is too large
Load diff
8195
test/data/ShortMsgKAT_256.txt
Executable file
8195
test/data/ShortMsgKAT_256.txt
Executable file
File diff suppressed because it is too large
Load diff
8195
test/data/ShortMsgKAT_384.txt
Executable file
8195
test/data/ShortMsgKAT_384.txt
Executable file
File diff suppressed because it is too large
Load diff
8195
test/data/ShortMsgKAT_512.txt
Executable file
8195
test/data/ShortMsgKAT_512.txt
Executable file
File diff suppressed because it is too large
Load diff
49
test/generate_tests.rb
Normal file
49
test/generate_tests.rb
Normal file
|
@ -0,0 +1,49 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
# This will generate a test suite.
|
||||
# Based on python-sha3's test suite.
|
||||
|
||||
FILES = [
|
||||
['test/data/ShortMsgKAT_224.txt', 224],
|
||||
['test/data/ShortMsgKAT_256.txt', 256],
|
||||
['test/data/ShortMsgKAT_384.txt', 384],
|
||||
['test/data/ShortMsgKAT_512.txt', 512],
|
||||
['test/data/LongMsgKAT_224.txt', 224],
|
||||
]
|
||||
|
||||
def generate
|
||||
puts %Q{
|
||||
# encoding: binary
|
||||
# This file generated by generate_tests.rb
|
||||
|
||||
require 'test/unit'
|
||||
|
||||
class SHA3Tests < Test::Unit::TestCase
|
||||
}
|
||||
|
||||
FILES.each do |path, hashlen|
|
||||
contents = File.read(path).split('Len = ')
|
||||
contents.each do |test|
|
||||
lines = test.split("\n")
|
||||
if !lines.empty? && lines[0] !~ /^#/
|
||||
length = lines[0].to_i
|
||||
if length % 8 == 0 && length != 0
|
||||
msg_raw = [lines[1].split(' = ').last].pack("H*")
|
||||
md = lines[2].split(' = ').last.downcase
|
||||
name = File.basename(path).split('.')[0]
|
||||
puts %Q{
|
||||
def test_#{name}_#{length}
|
||||
inst = Digest::SHA3.new(#{hashlen})
|
||||
inst.update(#{msg_raw.inspect})
|
||||
assert_equal #{md.inspect}, inst.hexdigest
|
||||
end
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
puts "end"
|
||||
end
|
||||
|
||||
generate
|
5
test/test_all.rb
Normal file
5
test/test_all.rb
Normal file
|
@ -0,0 +1,5 @@
|
|||
$LOAD_PATH.unshift(File.expand_path("lib"))
|
||||
$LOAD_PATH.unshift(File.expand_path("ext"))
|
||||
require 'digest/sha3'
|
||||
require File.expand_path('test/test_usage')
|
||||
require File.expand_path('test/test_vectors')
|
55
test/test_usage.rb
Normal file
55
test/test_usage.rb
Normal file
|
@ -0,0 +1,55 @@
|
|||
require 'test/unit'
|
||||
|
||||
class SHA3UsageTest < Test::Unit::TestCase
|
||||
def init(hashsize = 512)
|
||||
@digest = Digest::SHA3.new(hashsize)
|
||||
end
|
||||
|
||||
def test_copy
|
||||
a = init(224)
|
||||
a.update('foo')
|
||||
b = a.dup
|
||||
assert_equal b.digest, a.digest
|
||||
b.update('bar')
|
||||
assert_not_equal b.digest, a.digest
|
||||
end
|
||||
|
||||
def test_class_methods
|
||||
assert_equal 'a9cab59eb40a10b246290f2d6086e32e3689faf1d26b470c899f2802',
|
||||
Digest::SHA3.hexdigest("\xcc", 224)
|
||||
end
|
||||
|
||||
def test_update
|
||||
a = init(224)
|
||||
a.update("\xcc")
|
||||
assert_equal 'a9cab59eb40a10b246290f2d6086e32e3689faf1d26b470c899f2802', a.hexdigest
|
||||
end
|
||||
|
||||
def test_updates
|
||||
a = init(224)
|
||||
a.update("\x21")
|
||||
a.update("\xf1\x34")
|
||||
a.update("\xac\x57")
|
||||
assert_equal '5573da2b02216a860389a581f6e9fb8d805e9e02f6fa911701eee298', a.hexdigest
|
||||
end
|
||||
|
||||
def test_empty_224
|
||||
a = init(224)
|
||||
assert_equal 'f71837502ba8e10837bdd8d365adb85591895602fc552b48b7390abd', a.hexdigest
|
||||
end
|
||||
|
||||
def test_empty_256
|
||||
a = init(256)
|
||||
assert_equal 'c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470', a.hexdigest
|
||||
end
|
||||
|
||||
def test_empty_384
|
||||
a = init(384)
|
||||
assert_equal '2c23146a63a29acf99e73b88f8c24eaa7dc60aa771780ccc006afbfa8fe2479b2dd2b21362337441ac12b515911957ff', a.hexdigest()
|
||||
end
|
||||
|
||||
def test_empty_512
|
||||
a = init(512)
|
||||
assert_equal '0eab42de4c3ceb9235fc91acffe746b29c29a8c366b7c60e4e67c466f36a4304c00fa9caf9d87976ba469bcbe06713b435f091ef2769fb160cdab33d3670680e', a.hexdigest
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue