Class: UncleBlake3::Digest

Inherits:
Object
  • Object
show all
Defined in:
lib/uncle_blake3/digest.rb

Overview

See README for more usage examples

Examples:

basic usage

digest = ::UncleBlake3::Digest.new(output_length: 10)
digest << 'some input'
digest << 'some more input'
digest.hexdigest
#=> "d709fca62bbf74099e87"

Defined Under Namespace

Modules: Error Classes: ArgumentError, TypeError

Constant Summary collapse

KEY_LENGTH =
Binding.key_length
DEFAULT_OUTPUT_LENGTH =
Binding.default_output_length

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(output_length: DEFAULT_OUTPUT_LENGTH, key: nil, key_seed: nil) ⇒ Digest

Create a new Digest

Raises:



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/uncle_blake3/digest.rb', line 32

def initialize(output_length: DEFAULT_OUTPUT_LENGTH, key: nil, key_seed: nil)
  raise TypeError, 'Hash length is not an Integer' unless output_length.is_a?(::Integer)
  raise ArgumentError, 'Hash length out of range' unless (1...(1 << 20)).include?(output_length)
  raise TypeError, 'Key is not a String' if !key.nil? && !key.is_a?(::String)
  raise ArgumentError, 'Key length mismatched' unless key.nil? || (key.bytesize == KEY_LENGTH)
  raise TypeError, 'Key seed is not a String' if !key_seed.nil? && !key_seed.is_a?(::String)
  @native_instance = if !key && !key_seed
    Binding.init
  elsif key && key_seed
    raise ::ArgumentError, 'Both key and key_seed available at the same time; please pick only one.'
  elsif key
    key_buffer = ::FFI::MemoryPointer.new(:uint8, KEY_LENGTH)
    key_buffer.put_bytes(0, key)
    Binding.init_with_key(key_buffer)
  elsif key_seed
    seed_size = key_seed.bytesize
    seed_buffer = ::FFI::MemoryPointer.new(:uint8, seed_size)
    seed_buffer.put_bytes(0, key_seed)
    Binding.init_with_key_seed(seed_buffer, seed_size)
  else
    raise ::ArgumentError, 'Unknown mode of operation'
  end.tap do |pointer|
    ::ObjectSpace.define_finalizer(self, self.class._create_finalizer(pointer))
  end
  @output_length = output_length
  invalidate_cache
end

Class Method Details

.base64digest(*args, **kwargs) ⇒ Object

Same as digest but encode the output in Base64 format



135
136
137
# File 'lib/uncle_blake3/digest.rb', line 135

def base64digest(*args, **kwargs)
  _generic_digest(*args, **kwargs, &:base64digest)
end

.digest(*args, **kwargs) ⇒ Object

Shortcut to calculate a raw digest

Examples:

basic usage

::UncleBlake3::Digest.digest('some input')
#=> "{7\x00\f\x00EZ\xBD \x9A\x9A\x02\xDDH|>({\xC6\xA1\x9DNA\xEB\x81\xC8K\x85\x9E\xBF\x87;"

with key derived from seed

::UncleBlake3::Digest.digest('some input', key_seed: 'secret')
#=> "\xA7d\x13c)e\e`>\x9D\e\xB0\x9E\xF9\xA6\x82F:\xA8w;\xB0!\xBC*l\xF3w\x83\x85\xCA\x1E"

with raw key (fixed-length key)

::UncleBlake3::Digest.digest('some input', key: '0123456789abcdef0123456789abcdef')
#=> "8Z\x89+\x1A}\x0E\xBBI\xD4)\xC5\x9A\x8A\x17\x13[\xB7\x1DO\x98\xE8\xEF\x06\xD58\x83c\xC3u\x13\xE1"

controlled output length

::UncleBlake3::Digest.digest('some input', output_length: 5)
#=> "{7\x00\f\x00"


125
126
127
# File 'lib/uncle_blake3/digest.rb', line 125

def digest(*args, **kwargs)
  _generic_digest(*args, **kwargs, &:digest)
end

.hexdigest(*args, **kwargs) ⇒ Object

Same as digest but encode the output in hexadecimal format



130
131
132
# File 'lib/uncle_blake3/digest.rb', line 130

def hexdigest(*args, **kwargs)
  _generic_digest(*args, **kwargs, &:hexdigest)
end

Instance Method Details

#<<(*args, **kwargs) ⇒ Object

Alias for #update



72
73
74
# File 'lib/uncle_blake3/digest.rb', line 72

def <<(*args, **kwargs)
  update(*args, **kwargs)
end

#base64digestObject

Finalize and output a Base64-encoded hash



91
92
93
# File 'lib/uncle_blake3/digest.rb', line 91

def base64digest
  @_base64digest_cache ||= ::Base64.strict_encode64(digest)
end

#digestObject

Finalize and output a binary hash



77
78
79
80
81
82
83
# File 'lib/uncle_blake3/digest.rb', line 77

def digest
  @_digest_cache ||= begin
    data_buffer = ::FFI::MemoryPointer.new(:uint8, @output_length)
    Binding.final(@native_instance, data_buffer, @output_length)
    data_buffer.get_bytes(0, @output_length)
  end
end

#hexdigestObject

Finalize and output a hexadecimal-encoded hash



86
87
88
# File 'lib/uncle_blake3/digest.rb', line 86

def hexdigest
  @_hexdigest_cache ||= digest.unpack1('H*')
end

#update(data) ⇒ Object

Feed in the data



61
62
63
64
65
66
67
68
69
# File 'lib/uncle_blake3/digest.rb', line 61

def update(data)
  data_size = data.bytesize
  data_buffer = ::FFI::MemoryPointer.new(:uint8, data_size)
  data_buffer.put_bytes(0, data)
  Binding.update(@native_instance, data_buffer, data_size)
  self
ensure
  invalidate_cache
end