Class: SleepingKangaroo12::Digest

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

Overview

See README for more usage examples

Examples:

basic usage

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

Defined Under Namespace

Modules: Error Classes: FinalizationFailed, Finalized, UpdatingFailed

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(output_length: 32, key: nil) ⇒ Digest

Create a new Digest

Raises:

  • (::TypeError)


33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/sleeping_kangaroo12/digest.rb', line 33

def initialize(output_length: 32, key: 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)

  # id = SecureRandom.uuid
  @native_instance = Binding.init(output_length).tap do |pointer|
    ::ObjectSpace.define_finalizer(self, self.class._create_finalizer(pointer))
  end
  @output_length = output_length
  @key = key
  @finalized = false
  @result = nil
end

Class Method Details

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

Same as digest but encode the output in Base64 format



124
125
126
# File 'lib/sleeping_kangaroo12/digest.rb', line 124

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

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

Shortcut to calculate a raw digest

Examples:

basic usage

::SleepingKangaroo12::Digest.digest('some input')
#=> "m\x9FJ\xDA\xE9\x96\xD1X\xC5K\xE83e(x\x8C\xD3o\xFBh\xB2\x17W ,\xD5\xED!\xE4D\xAF\xDD"

with key (AKA: customization)

::SleepingKangaroo12::Digest.digest('some input', key: 'secret')
#=> "\x96\xE2K\xC4\xCF\xFFGF\xE1\x05\xB9\xF6f\xF0-\xF8\x1F\a\n\xFC\xD7\xC9\x91\n\xFC\xFB\xA6hOx\x99<"

controlled output length

::SleepingKangaroo12::Digest.digest('some input', output_length: 5)
#=> "m\x9FJ\xDA\xE9"


114
115
116
# File 'lib/sleeping_kangaroo12/digest.rb', line 114

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

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

Same as digest but encode the output in hexadecimal format



119
120
121
# File 'lib/sleeping_kangaroo12/digest.rb', line 119

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

Instance Method Details

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

Alias for #update



61
62
63
# File 'lib/sleeping_kangaroo12/digest.rb', line 61

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

#base64digestObject

Finalize and output a Base64-encoded hash



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

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

#digestObject

Finalize and output a binary hash



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/sleeping_kangaroo12/digest.rb', line 66

def digest
  @finalized = true
  return @_digest if @_digest

  data_buffer = ::FFI::MemoryPointer.new(:char, @output_length)
  customization_buffer, customization_size = @key.then do |key|
    next [::FFI::MemoryPointer.new(:char, 0), 0] unless key

    size = key.bytesize
    [::FFI::MemoryPointer.new(:char, size).tap do |buffer|
      buffer.put_bytes(0, key)
    end, size]
  end
  Binding.final(@native_instance, data_buffer, customization_buffer, customization_size).tap do |result|
    raise FinalizationFailed unless result.zero?
  end
  @_digest = data_buffer.get_bytes(0, @output_length)
end

#hexdigestObject

Finalize and output a hexadecimal-encoded hash



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

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

#update(data) ⇒ Object

Feed in the data

Raises:



49
50
51
52
53
54
55
56
57
58
# File 'lib/sleeping_kangaroo12/digest.rb', line 49

def update(data)
  raise Finalized if @finalized
  data_size = data.bytesize
  data_buffer = ::FFI::MemoryPointer.new(:char, data_size)
  data_buffer.put_bytes(0, data)
  Binding.update(@native_instance, data_buffer, data_size).tap do |result|
    raise UpdatingFailed unless result.zero?
  end
  self
end