Add tests

This commit is contained in:
Hongli Lai (Phusion) 2012-10-05 20:40:31 +02:00
parent 255d6ad9f1
commit e19966f329
14 changed files with 34490 additions and 24 deletions

1
.gitignore vendored
View file

@ -2,3 +2,4 @@
*.o *.o
*.bundle *.bundle
Makefile Makefile
test/test_vectors.rb

18
Makefile Normal file
View 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

View file

@ -1,6 +1,6 @@
# The SHA-3 (Keccak) extension for Ruby # 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 ## 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. # You can pass a hash length to the constructor.
digest = Digest::SHA3.new(224) 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.

View file

@ -13,6 +13,7 @@ Gem::Specification.new do |s|
s.files = Dir[ s.files = Dir[
"README.md", "README.md",
"LICENSE", "LICENSE",
"Makefile",
"digest-sha3.gemspec", "digest-sha3.gemspec",
"ext/**/*.{c,h,rb}", "ext/**/*.{c,h,rb}",
"lib/**/*" "lib/**/*"

View file

@ -11,9 +11,17 @@ typedef struct {
} RbSHA3; } RbSHA3;
static VALUE 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; RbSHA3 *ctx;
VALUE obj;
VALUE hashlen; VALUE hashlen;
int i_hashlen; int i_hashlen;
@ -22,18 +30,16 @@ rb_sha3_new(int argc, VALUE *argv, VALUE klass) {
} else { } else {
i_hashlen = NUM2INT(hashlen); i_hashlen = NUM2INT(hashlen);
} }
if (i_hashlen == 0) {
ctx = (RbSHA3 *) xmalloc(sizeof(RbSHA3));
obj = Data_Wrap_Struct(klass, 0, xfree, ctx);
ctx->bitlen = i_hashlen;
if (ctx->bitlen == 0) {
rb_raise(rb_eRuntimeError, "Unsupported hash length"); rb_raise(rb_eRuntimeError, "Unsupported hash length");
} }
Data_Get_Struct(self, RbSHA3, ctx);
ctx->bitlen = i_hashlen;
switch (Init(&ctx->state, i_hashlen)) { switch (Init(&ctx->state, i_hashlen)) {
case SUCCESS: case SUCCESS:
return obj; return self;
case FAIL: case FAIL:
rb_raise(rb_eRuntimeError, "Unknown error"); rb_raise(rb_eRuntimeError, "Unknown error");
return Qnil; return Qnil;
@ -47,19 +53,15 @@ rb_sha3_new(int argc, VALUE *argv, VALUE klass) {
} }
static VALUE static VALUE
rb_sha3_copy(VALUE copy, VALUE obj) { rb_sha3_initialize_copy(VALUE self, VALUE other) {
RbSHA3 *ctx_copy, *ctx_obj; RbSHA3 *ctx_self, *ctx_other;
Data_Get_Struct(copy, RbSHA3, ctx_copy); rb_check_frozen(self);
Data_Get_Struct(obj, RbSHA3, ctx_obj); Data_Get_Struct(self, RbSHA3, ctx_self);
if (copy == obj) { Data_Get_Struct(other, RbSHA3, ctx_other);
return copy; memcpy(&ctx_self->state, &ctx_other->state, sizeof(hashState));
} ctx_self->bitlen = ctx_other->bitlen;
rb_check_frozen(copy); return self;
memcpy(&ctx_copy->state, &ctx_obj->state, sizeof(hashState));
ctx_copy->bitlen = ctx_obj->bitlen;
return copy;
} }
static VALUE static VALUE
@ -123,8 +125,9 @@ void __attribute__((visibility("default")))
Init_sha3() { Init_sha3() {
mDigest = rb_define_module("Digest"); mDigest = rb_define_module("Digest");
cSHA3 = rb_define_class_under(mDigest, "SHA3", rb_cObject); cSHA3 = rb_define_class_under(mDigest, "SHA3", rb_cObject);
rb_define_singleton_method(cSHA3, "new", rb_sha3_new, -1); rb_define_alloc_func(cSHA3, rb_sha3_alloc);
rb_define_method(cSHA3, "initialize_copy", rb_sha3_copy, 1); 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, "reset", rb_sha3_reset, 0);
rb_define_method(cSHA3, "update", rb_sha3_update, 1); rb_define_method(cSHA3, "update", rb_sha3_update, 1);
rb_define_method(cSHA3, "<<", rb_sha3_update, 1); rb_define_method(cSHA3, "<<", rb_sha3_update, 1);

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
View file

@ -0,0 +1,3 @@
From KeccakKAT-3.zip
http://keccak.noekeon.org/KeccakKAT-3.zip

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

File diff suppressed because it is too large Load diff

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

File diff suppressed because it is too large Load diff

49
test/generate_tests.rb Normal file
View 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
View 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
View 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