digest-xxhash 0.1.0 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE +1 -1
- data/README.md +44 -12
- data/Rakefile +13 -2
- data/digest-xxhash.gemspec +9 -5
- data/ext/digest/xxhash/ext.c +572 -144
- data/ext/digest/xxhash/extconf.rb +20 -0
- data/ext/digest/xxhash/utils.h +15 -4
- data/ext/digest/xxhash/xxhash.h +5607 -157
- data/lib/digest/xxhash/version.rb +1 -1
- data/test/produce-vectors-with-ruby-xxhash.rb +5 -4
- data/test/produce-vectors-with-xxhsum.rb +112 -0
- data/test/test.rb +64 -33
- data/test/test.vectors +960 -462
- data/test/xxhsum.c.c0e86bc0.diff +424 -0
- metadata +33 -12
- data/.travis.yml +0 -6
- data/appveyor.yml +0 -19
- data/ext/digest/xxhash/xxhash.c +0 -888
@@ -1,5 +1,8 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
+
# This script does not produce test vectors for XXH3_64bits and XXH3_128bits but
|
4
|
+
# its output for XXH32 and XXH64 can be compared to xxhsum's.
|
5
|
+
|
3
6
|
require 'ruby-xxhash'
|
4
7
|
|
5
8
|
rijndael_sbox = [
|
@@ -60,14 +63,12 @@ end
|
|
60
63
|
if bit_size == 32
|
61
64
|
["00000000"].concat(_32bit_seeds_cycles.next).each do |seed|
|
62
65
|
sum = XXhash.xxh32(msg, seed.to_i(16))
|
63
|
-
|
64
|
-
$stdout.flush
|
66
|
+
puts "#{bit_size}|#{msg_method}|#{msg_length}|seed|#{seed}|#{"%08x" % sum}"
|
65
67
|
end
|
66
68
|
else
|
67
69
|
["0000000000000000"].concat(_64bit_seeds).each do |seed|
|
68
70
|
sum = XXhash.xxh64(msg, seed.to_i(16))
|
69
|
-
|
70
|
-
$stdout.flush
|
71
|
+
puts "#{bit_size}|#{msg_method}|#{msg_length}|seed|#{seed}|#{"%016x" % sum}"
|
71
72
|
end
|
72
73
|
end
|
73
74
|
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'open3'
|
4
|
+
|
5
|
+
rijndael_sbox = [
|
6
|
+
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
|
7
|
+
0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
|
8
|
+
0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
|
9
|
+
0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
|
10
|
+
0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
|
11
|
+
0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
|
12
|
+
0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
|
13
|
+
0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
|
14
|
+
0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
|
15
|
+
0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
|
16
|
+
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
|
17
|
+
0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
|
18
|
+
0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
|
19
|
+
0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
|
20
|
+
0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
|
21
|
+
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
|
22
|
+
]
|
23
|
+
|
24
|
+
_32bit_seeds = rijndael_sbox.each_slice(4).map{ |e| e.map{ |f| "%02x" % f }.join }.to_a
|
25
|
+
_32bit_seeds_cycles = _32bit_seeds.cycle.each_slice(32)
|
26
|
+
_64bit_seeds = rijndael_sbox.each_slice(8).map{ |e| e.map{ |f| "%02x" % f }.join }.to_a
|
27
|
+
_secrets = rijndael_sbox.take(144).each_slice(3).map{ |e| e.permutation.to_a }
|
28
|
+
.then{ |e| e.shift.zip(*e) }.map{ |e| e.flatten.map{ |f| "%02x" %f }.join }
|
29
|
+
|
30
|
+
def get_repeated_0x00_to_0xff(length)
|
31
|
+
hex = (0..0xff).to_a.map{ |e| sprintf "%2x", e }.join
|
32
|
+
str = [hex].pack('H*')
|
33
|
+
cycles = (Float(length) / str.size).ceil
|
34
|
+
[str].cycle(cycles).to_a.join[0...length]
|
35
|
+
end
|
36
|
+
|
37
|
+
def produce_vectors(algo, algo_index, seed_type, seed_or_secret, msg, msg_method_used)
|
38
|
+
seed_opt = seed_type == :secret ? 'S' : 's'
|
39
|
+
cmd = ["./xxhsum", "-H#{algo_index}", "-#{seed_opt}#{seed_or_secret}"]
|
40
|
+
output, status = Open3.capture2(*cmd, binmode: true, stdin_data: msg)
|
41
|
+
exit 1 unless status.success?
|
42
|
+
sum = output.sub(/\s.*/, '')
|
43
|
+
puts "#{algo}|#{msg_method_used}|#{msg.length}|#{seed_type.to_s}|#{seed_or_secret}|#{sum}"
|
44
|
+
end
|
45
|
+
|
46
|
+
['32', '64', 'xxh3-64', 'xxh3-128'].map do |algo|
|
47
|
+
[
|
48
|
+
[algo, 'null', 0],
|
49
|
+
[algo, '0x00_to_0xff', 17 ** 0],
|
50
|
+
[algo, '0x00_to_0xff', 17 ** 1],
|
51
|
+
[algo, '0x00_to_0xff', 17 ** 2],
|
52
|
+
[algo, '0x00_to_0xff', 17 ** 3],
|
53
|
+
[algo, '0x00_to_0xff', 17 ** 4],
|
54
|
+
[algo, '0x00_to_0xff', 17 ** 5]
|
55
|
+
]
|
56
|
+
end.flatten(1).each do |algo, msg_method, msg_length|
|
57
|
+
case msg_method
|
58
|
+
when 'null'
|
59
|
+
msg = ''
|
60
|
+
when '0x00_to_0xff'
|
61
|
+
msg = get_repeated_0x00_to_0xff(msg_length)
|
62
|
+
else
|
63
|
+
raise "Invalid message generation method."
|
64
|
+
end
|
65
|
+
|
66
|
+
case algo
|
67
|
+
when '32'
|
68
|
+
["00000000"].concat(_32bit_seeds_cycles.next).each do |seed|
|
69
|
+
produce_vectors(algo, 0, :seed, seed, msg, msg_method)
|
70
|
+
end
|
71
|
+
when '64'
|
72
|
+
["0000000000000000"].concat(_64bit_seeds).each do |seed|
|
73
|
+
produce_vectors(algo, 1, :seed, seed, msg, msg_method)
|
74
|
+
end
|
75
|
+
when 'xxh3-64'
|
76
|
+
["0000000000000000"].concat(_64bit_seeds).each do |seed|
|
77
|
+
produce_vectors(algo, 3, :seed, seed, msg, msg_method)
|
78
|
+
end
|
79
|
+
when 'xxh3-128'
|
80
|
+
["0000000000000000"].concat(_64bit_seeds).each do |seed|
|
81
|
+
produce_vectors(algo, 2, :seed, seed, msg, msg_method)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
['xxh3-64', 'xxh3-128'].map do |algo|
|
87
|
+
[
|
88
|
+
[algo, 'null', 0],
|
89
|
+
[algo, '0x00_to_0xff', 17 ** 0],
|
90
|
+
[algo, '0x00_to_0xff', 17 ** 5]
|
91
|
+
]
|
92
|
+
end.flatten(1).each do |algo, msg_method, msg_length|
|
93
|
+
case msg_method
|
94
|
+
when 'null'
|
95
|
+
msg = ''
|
96
|
+
when '0x00_to_0xff'
|
97
|
+
msg = get_repeated_0x00_to_0xff(msg_length)
|
98
|
+
else
|
99
|
+
raise "Invalid message generation method."
|
100
|
+
end
|
101
|
+
|
102
|
+
case algo
|
103
|
+
when 'xxh3-64'
|
104
|
+
_secrets.each do |secret|
|
105
|
+
produce_vectors(algo, 3, :secret, secret, msg, msg_method)
|
106
|
+
end
|
107
|
+
when 'xxh3-128'
|
108
|
+
_secrets.each do |secret|
|
109
|
+
produce_vectors(algo, 2, :secret, secret, msg, msg_method)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
data/test/test.rb
CHANGED
@@ -17,47 +17,47 @@ def get_repeated_0x00_to_0xff(length)
|
|
17
17
|
[str].cycle(cycles).to_a.join[0...length]
|
18
18
|
end
|
19
19
|
|
20
|
-
[Digest::XXH32, Digest::XXH64].each do |klass|
|
20
|
+
[Digest::XXH32, Digest::XXH64, Digest::XXH3_64bits, Digest::XXH3_128bits].each do |klass|
|
21
21
|
describe klass do
|
22
22
|
it "produces correct types of digest outputs" do
|
23
|
-
klass.digest("").must_be_instance_of String
|
24
|
-
klass.hexdigest("").must_be_instance_of String
|
25
|
-
klass.idigest("").must_be_kind_of Integer
|
26
|
-
klass.new.digest("").must_be_instance_of String
|
27
|
-
klass.new.hexdigest("").must_be_instance_of String
|
28
|
-
klass.new.idigest("").must_be_kind_of Integer
|
23
|
+
_(klass.digest("")).must_be_instance_of String
|
24
|
+
_(klass.hexdigest("")).must_be_instance_of String
|
25
|
+
_(klass.idigest("")).must_be_kind_of Integer
|
26
|
+
_(klass.new.digest("")).must_be_instance_of String
|
27
|
+
_(klass.new.hexdigest("")).must_be_instance_of String
|
28
|
+
_(klass.new.idigest("")).must_be_kind_of Integer
|
29
29
|
end
|
30
30
|
|
31
31
|
it "produces similar output with its digest, hexdigest and idigest methods" do
|
32
32
|
digest = klass.digest("abcd")
|
33
|
-
klass.new.digest("abcd").must_equal digest
|
34
|
-
klass.new.update("ab").update("cd").digest.must_equal digest
|
35
|
-
klass.new.update("ab").update("cd").digest
|
36
|
-
klass.new.reset.update("ab").update("cd").digest
|
33
|
+
_(klass.new.digest("abcd")).must_equal digest
|
34
|
+
_(klass.new.update("ab").update("cd").digest).must_equal digest
|
35
|
+
_(klass.new.update("ab").update("cd").digest!).must_equal digest
|
36
|
+
_(klass.new.reset.update("ab").update("cd").digest!).must_equal digest
|
37
37
|
|
38
38
|
hexdigest = klass.hexdigest("abcd")
|
39
|
-
klass.new.hexdigest("abcd").must_equal hexdigest
|
40
|
-
klass.new.update("ab").update("cd").hexdigest.must_equal hexdigest
|
41
|
-
klass.new.update("ab").update("cd").hexdigest
|
42
|
-
klass.new.reset.update("ab").update("cd").hexdigest
|
39
|
+
_(klass.new.hexdigest("abcd")).must_equal hexdigest
|
40
|
+
_(klass.new.update("ab").update("cd").hexdigest).must_equal hexdigest
|
41
|
+
_(klass.new.update("ab").update("cd").hexdigest!).must_equal hexdigest
|
42
|
+
_(klass.new.reset.update("ab").update("cd").hexdigest!).must_equal hexdigest
|
43
43
|
|
44
44
|
idigest = klass.idigest("abcd")
|
45
|
-
klass.new.idigest("abcd").must_equal idigest
|
46
|
-
klass.new.update("ab").update("cd").idigest.must_equal idigest
|
47
|
-
klass.new.update("ab").update("cd").idigest
|
48
|
-
klass.new.reset.update("ab").update("cd").idigest
|
45
|
+
_(klass.new.idigest("abcd")).must_equal idigest
|
46
|
+
_(klass.new.update("ab").update("cd").idigest).must_equal idigest
|
47
|
+
_(klass.new.update("ab").update("cd").idigest!).must_equal idigest
|
48
|
+
_(klass.new.reset.update("ab").update("cd").idigest!).must_equal idigest
|
49
49
|
|
50
|
-
|
51
|
-
hexdigest.must_equal
|
50
|
+
digest_hex = digest.unpack('H*').pop
|
51
|
+
_(hexdigest).must_equal digest_hex
|
52
52
|
|
53
|
-
|
54
|
-
hexdigest.must_equal
|
53
|
+
idigest_hex = "%08x" % idigest
|
54
|
+
_(hexdigest).must_equal idigest_hex
|
55
55
|
end
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
59
59
|
CSV.foreach(File.join(TEST_DIR, 'test.vectors'), col_sep: '|').with_index(1) do |csv, line_num|
|
60
|
-
|
60
|
+
algo, msg_method, msg_length, seed_type, seed_or_secret, sum = csv
|
61
61
|
|
62
62
|
case msg_method
|
63
63
|
when 'null'
|
@@ -65,23 +65,54 @@ CSV.foreach(File.join(TEST_DIR, 'test.vectors'), col_sep: '|').with_index(1) do
|
|
65
65
|
when '0x00_to_0xff'
|
66
66
|
msg = get_repeated_0x00_to_0xff(msg_length.to_i)
|
67
67
|
else
|
68
|
-
raise "Invalid
|
68
|
+
raise "Invalid message generation method specified in test.vectors:#{line_num}: #{msg_method}"
|
69
69
|
end
|
70
70
|
|
71
|
-
case
|
72
|
-
when 32
|
71
|
+
case algo
|
72
|
+
when '32'
|
73
73
|
klass = Digest::XXH32
|
74
|
-
when 64
|
74
|
+
when '64'
|
75
75
|
klass = Digest::XXH64
|
76
|
+
when 'xxh3-64'
|
77
|
+
klass = Digest::XXH3_64bits
|
78
|
+
when 'xxh3-128'
|
79
|
+
klass = Digest::XXH3_128bits
|
76
80
|
else
|
77
|
-
raise "Invalid specified
|
81
|
+
raise "Invalid algorithm specified in test.vectors:#{line_num}: #{algo}"
|
78
82
|
end
|
79
83
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
+
case seed_type
|
85
|
+
when 'seed'
|
86
|
+
describe klass do
|
87
|
+
describe "using #{msg_method}(#{msg_length}) as message generator, and #{seed_or_secret} as seed" do
|
88
|
+
it "should produce #{sum}" do
|
89
|
+
_(klass.hexdigest(msg, seed_or_secret)).must_equal sum
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
when 'secret'
|
94
|
+
describe klass do
|
95
|
+
describe "using #{msg_method}(#{msg_length}) as message generator, and #{seed_or_secret} as secret" do
|
96
|
+
it "should produce #{sum}" do
|
97
|
+
secret_str = [seed_or_secret].pack('H*')
|
98
|
+
_(klass.new.reset_with_secret(secret_str).update(msg).hexdigest).must_equal sum
|
99
|
+
end
|
84
100
|
end
|
85
101
|
end
|
102
|
+
else
|
103
|
+
raise "Invalid seed type specified in test.vectors:#{line_num}: #{seed_type}"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe Digest::XXHash::XXH3_SECRET_SIZE_MIN do
|
108
|
+
it "should be 136" do
|
109
|
+
# Documentation should be updated to reflect the new value if this fails.
|
110
|
+
_(Digest::XXHash::XXH3_SECRET_SIZE_MIN).must_equal 136
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
describe Digest::XXHash do
|
115
|
+
it "must have VERSION constant" do
|
116
|
+
_(Digest::XXHash.constants).must_include :VERSION
|
86
117
|
end
|
87
118
|
end
|