# encoding: binary
# frozen_string_literal: true

module RbNaCl
  # Cryptographic hash functions
  #
  # Cryptographic hash functions take a variable length message and compute a
  # fixed length string, the message digest. Even a small change in the input
  # data should produce a large change in the digest, and it is 'very difficult'
  # to create two messages with the same digest.
  #
  # A cryptographic hash can be used for checking the integrity of data, but
  # there is no secret involved in the hashing, so anyone can create the hash of
  # a given message.
  #
  # RbNaCl provides the SHA-256,SHA-512 as well as the Blake2b hash functions.
  module Hash
    # Returns the SHA-256 hash of the given data
    #
    # There's no streaming done, just pass in the data and be done with it.
    #
    # @param [#to_str] data The data, as a collection of bytes
    #
    # @raise [CryptoError] If the hashing fails for some reason.
    #
    # @return [String] The SHA-256 hash digest as raw bytes
    def self.sha256(data)
      data   = data.to_str
      digest = Util.zeros(SHA256::BYTES)
      SHA256.hash_sha256(digest, data, data.bytesize) || raise(CryptoError, "Hashing failed!")
      digest
    end

    # Returns the SHA-512 hash of the given data
    #
    # There's no streaming done, just pass in the data and be done with it.
    #
    # @param [#to_str] data The data, as a collection of bytes
    #
    # @raise [CryptoError] If the hashing fails for some reason.
    #
    # @return [String] The SHA-512 hash digest as raw bytes
    def self.sha512(data)
      digest = Util.zeros(SHA512::BYTES)
      SHA512.hash_sha512(digest, data, data.bytesize) || raise(CryptoError, "Hashing failed!")
      digest
    end

    # Returns the Blake2b hash of the given data
    #
    # There's no streaming done, just pass in the data and be done with it.
    # This method returns a 64-byte hash by default.
    #
    # @param [String] data The data, as a collection of bytes
    # @option options [Fixnum]   digest_size Size in bytes (1-64, default 64)
    # @option options [String]   key 64-byte (or less) key for keyed mode
    # @option options [String]   salt  Provide a salt to support randomised hashing.
    #                                  This is mixed into the parameters block to start the hashing.
    # @option options [Personal] personal Provide personalisation string to allow pinning a hash for a particular purpose.
    #                                     This is mixed into the parameters block to start the hashing
    #
    # @raise [CryptoError] If the hashing fails for some reason.
    #
    # @return [String] The Blake2b hash digest as raw bytes
    def self.blake2b(data, options = {})
      Blake2b.digest(data, options)
    end
  end
end
