Skip to content

Checksum Verifier — Ruby source

Drag and drop a file to compute its MD5, SHA-1, SHA-256, and SHA-512 checksums. Paste an expected hash to verify integrity - detect tampered or corrupted downloads instantly. Runs entirely in your browser.

This is the Ruby implementation — the same logic the interactive tool runs, in a shareable, citable form.

# Checksum Verifier — MD5 / SHA-1 / SHA-256 / SHA-512 checksums + verification.
#
# Language: Ruby (3.1+, standard library only)
# Source:   CosmoDev polyglot showcase port of the Checksum Verifier tool,
#           ported from src/lib/checksum-verifier.ts (the canonical TypeScript
#           implementation).
# License:  display source — part of CosmoDev's polyglot tool pages.
#
# The TS reference hand-rolls MD5 (RFC 1321) because the Web Crypto API does
# not ship MD5; Ruby's standard library does, so this port uses Digest
# directly for all four algorithms.

require 'digest'

module ChecksumVerifier
  ChecksumResult = Struct.new(:md5, :sha1, :sha256, :sha512, keyword_init: true)

  SHA_BY_NAME = {
    'SHA-1'   => Digest::SHA1,
    'SHA-256' => Digest::SHA256,
    'SHA-512' => Digest::SHA512
  }.freeze

  # Detect the algorithm from the hex length:
  # 32=MD5, 40=SHA-1, 64=SHA-256, 128=SHA-512.
  LENGTH_TO_ALGO = {
    32 => 'md5',
    40 => 'sha1',
    64 => 'sha256',
    128 => 'sha512'
  }.freeze

  class << self
    # Create an incremental MD5 hasher (RFC 1321). The returned Digest object
    # responds to #update — call repeatedly for chunked input, no length
    # limit — and #hexdigest (pad, append the 64-bit length, lowercase hex).
    # MD5 is only for integrity checks - not security.
    def create_md5
      Digest::MD5.new
    end

    # One-shot MD5 of a binary String, as lowercase hex.
    def md5(data)
      Digest::MD5.hexdigest(data)
    end

    # Digest a buffer with SHA-1 / SHA-256 / SHA-512 and return lowercase hex.
    def sha_hex(algorithm, data)
      klass = SHA_BY_NAME[algorithm] ||
              raise(ArgumentError, "Unsupported algorithm: #{algorithm}")
      klass.hexdigest(data)
    end

    # Compute all four checksums of a buffer.
    def compute_checksums(data)
      ChecksumResult.new(
        md5: md5(data),
        sha1: sha_hex('SHA-1', data),
        sha256: sha_hex('SHA-256', data),
        sha512: sha_hex('SHA-512', data)
      )
    end

    # Normalize a pasted hash: drop whitespace and `:` grouping, lowercase.
    def normalize_hash(hash)
      hash.strip.gsub(/[\s:]/, '').downcase
    end

    # Detect the algorithm from the hex length; nil when the string is not a
    # recognizable hex hash of a supported length.
    def detect_hash_algorithm(hash)
      h = normalize_hash(hash)
      return nil unless h.match?(/\A[0-9a-f]+\z/)

      LENGTH_TO_ALGO[h.length]
    end

    # Compare an expected hash against a computed result. Returns nil when
    # the expected string is not a recognizable hex hash of a supported
    # length, else { algorithm:, match: }.
    def verify_checksum(expected, result)
      algorithm = detect_hash_algorithm(expected)
      return nil unless algorithm

      { algorithm: algorithm, match: normalize_hash(expected) == result[algorithm.to_sym] }
    end
  end
end

Also available in 8 other languages

Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →