digest-xxhash 0.1.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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