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.
@@ -2,6 +2,6 @@ require 'digest'
2
2
 
3
3
  module Digest
4
4
  class XXHash < Digest::Class
5
- VERSION = "0.1.0"
5
+ VERSION = "0.2.2"
6
6
  end
7
7
  end
@@ -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
- $stdout.puts "#{bit_size}|#{msg_method}|#{msg_length}|#{seed}|#{"%08x" % sum}"
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
- $stdout.puts "#{bit_size}|#{msg_method}|#{msg_length}|#{seed}|#{"%016x" % sum}"
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!.must_equal digest
36
- klass.new.reset.update("ab").update("cd").digest!.must_equal 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!.must_equal hexdigest
42
- klass.new.reset.update("ab").update("cd").hexdigest!.must_equal 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!.must_equal idigest
48
- klass.new.reset.update("ab").update("cd").idigest!.must_equal 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
- digest_enc = digest.unpack('H*').pop
51
- hexdigest.must_equal digest_enc
50
+ digest_hex = digest.unpack('H*').pop
51
+ _(hexdigest).must_equal digest_hex
52
52
 
53
- idigest_enc = "%08x" % idigest
54
- hexdigest.must_equal idigest_enc
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
- bit_size, msg_method, msg_length, seed, sum = csv
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 specified message generation method in 'test.vectors', line #{line_num}."
68
+ raise "Invalid message generation method specified in test.vectors:#{line_num}: #{msg_method}"
69
69
  end
70
70
 
71
- case bit_size.to_i
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 bit size in 'test.vectors', line #{line_num}."
81
+ raise "Invalid algorithm specified in test.vectors:#{line_num}: #{algo}"
78
82
  end
79
83
 
80
- describe klass do
81
- describe "using #{msg_method}(#{msg_length}) as message generator, and #{seed} as seed" do
82
- it "should produce #{sum}" do
83
- klass.hexdigest(msg, seed).must_equal sum
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