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
|
*.o
|
||||||
*.bundle
|
*.bundle
|
||||||
Makefile
|
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
|
# 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.
|
||||||
|
|
|
@ -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/**/*"
|
||||||
|
|
|
@ -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
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