Module: Everywhere::Blake2b
- Defined in:
- lib/everywhere/blake2b.rb
Overview
Pure-Ruby BLAKE2b (RFC 7693), unkeyed, variable digest length.
OpenSSL only exposes the fixed BLAKE2b512 digest, but minisign's secret-key
checksum is BLAKE2b-256 — and a 2b-256 digest is NOT a truncation of 2b-512
(the output length is part of the parameter block). This implementation
covers any length; hot paths (hashing a whole artifact) should still prefer
Blake2b.digest64, which uses OpenSSL when available and only falls back
here.
Constant Summary collapse
- MASK =
0xFFFFFFFFFFFFFFFF- IV =
[ 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, 0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179 ].freeze
- SIGMA =
[ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3], [11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4], [7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8], [9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13], [2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9], [12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11], [13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10], [6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5], [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0] ].freeze
Class Method Summary collapse
- .compress(h, block, t, last) ⇒ Object
- .digest(data, outlen) ⇒ Object
-
.digest64_file(path) ⇒ Object
64-byte BLAKE2b of a file — minisign's prehash.
- .hexdigest(data, outlen) ⇒ Object
- .mix(v, a, b, c, d, x, y) ⇒ Object
- .rotr(x, n) ⇒ Object
Class Method Details
.compress(h, block, t, last) ⇒ Object
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/everywhere/blake2b.rb', line 81 def compress(h, block, t, last) m = block.unpack("Q<16") v = h + IV v[12] ^= t & MASK v[13] ^= (t >> 64) & MASK v[14] ^= MASK if last 12.times do |round| s = SIGMA[round % 10] mix(v, 0, 4, 8, 12, m[s[0]], m[s[1]]) mix(v, 1, 5, 9, 13, m[s[2]], m[s[3]]) mix(v, 2, 6, 10, 14, m[s[4]], m[s[5]]) mix(v, 3, 7, 11, 15, m[s[6]], m[s[7]]) mix(v, 0, 5, 10, 15, m[s[8]], m[s[9]]) mix(v, 1, 6, 11, 12, m[s[10]], m[s[11]]) mix(v, 2, 7, 8, 13, m[s[12]], m[s[13]]) mix(v, 3, 4, 9, 14, m[s[14]], m[s[15]]) end 8.times { |i| h[i] ^= v[i] ^ v[i + 8] } end |
.digest(data, outlen) ⇒ Object
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/everywhere/blake2b.rb', line 35 def digest(data, outlen) raise ArgumentError, "digest length must be 1..64" unless (1..64).cover?(outlen) data = data.to_s.b h = IV.dup h[0] ^= 0x01010000 ^ outlen # param block word 0: digest_length, fanout=1, depth=1 if data.empty? compress(h, ("\0" * 128).b, 0, true) else blocks = (data.bytesize + 127) / 128 blocks.times do |i| block = data.byteslice(i * 128, 128) if i == blocks - 1 compress(h, block.ljust(128, "\0"), data.bytesize, true) else compress(h, block, (i + 1) * 128, false) end end end h.pack("Q<8").byteslice(0, outlen) end |
.digest64_file(path) ⇒ Object
64-byte BLAKE2b of a file — minisign's prehash. Streams through OpenSSL's BLAKE2b512 when the linked OpenSSL provides it (it matches RFC 7693 with outlen 64), else falls back to the pure-Ruby path.
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/everywhere/blake2b.rb', line 64 def digest64_file(path) require "openssl" md = begin OpenSSL::Digest.new("BLAKE2b512") rescue StandardError nil end return digest(File.binread(path), 64) unless md File.open(path, "rb") do |io| while (chunk = io.read(1 << 20)) md << chunk end end md.digest end |
.hexdigest(data, outlen) ⇒ Object
59 |
# File 'lib/everywhere/blake2b.rb', line 59 def hexdigest(data, outlen) = digest(data, outlen).unpack1("H*") |
.mix(v, a, b, c, d, x, y) ⇒ Object
103 104 105 106 107 108 109 110 111 112 |
# File 'lib/everywhere/blake2b.rb', line 103 def mix(v, a, b, c, d, x, y) v[a] = (v[a] + v[b] + x) & MASK v[d] = rotr(v[d] ^ v[a], 32) v[c] = (v[c] + v[d]) & MASK v[b] = rotr(v[b] ^ v[c], 24) v[a] = (v[a] + v[b] + y) & MASK v[d] = rotr(v[d] ^ v[a], 16) v[c] = (v[c] + v[d]) & MASK v[b] = rotr(v[b] ^ v[c], 63) end |