Module: BSV::Primitives::Hex

Defined in:
lib/bsv/primitives/hex.rb

Overview

Strict hex encoding/decoding utilities.

Ruby’s Array#pack(‘H*’) silently drops non-hex characters and truncates odd-length strings. This module rejects both, raising ArgumentError on invalid input so consumer-facing parse paths fail loudly rather than producing garbage.

Internal paths that serialise/deserialise trusted hex (e.g. round-tripping our own unpack1(‘H*’) output) can continue using pack(‘H*’) directly — the validation overhead isn’t warranted when the hex is known-good.

Examples:

BSV::Primitives::Hex.decode('deadbeef')          #=> "\xDE\xAD\xBE\xEF"
BSV::Primitives::Hex.decode('nope')              #=> ArgumentError
BSV::Primitives::Hex.decode('abc')               #=> ArgumentError (odd length)
BSV::Primitives::Hex.encode("\xDE\xAD")          #=> "dead"

Class Method Summary collapse

Class Method Details

.decode(str, name: 'hex value') ⇒ String

Decode a hex string to binary bytes.

Parameters:

  • str (String)

    hex string (must be even-length, hex-only)

  • name (String) (defaults to: 'hex value')

    label for the error message

Returns:

  • (String)

    binary string (ASCII-8BIT encoding)

Raises:

  • (ArgumentError)

    if str is not valid hex



63
64
65
66
# File 'lib/bsv/primitives/hex.rb', line 63

def self.decode(str, name: 'hex value')
  validate!(str, name: name)
  [str].pack('H*')
end

.encode(bytes) ⇒ String

Encode binary bytes as lowercase hex.

Parameters:

  • bytes (String)

    binary data

Returns:

  • (String)

    lowercase hex string (UTF-8 encoding)



72
73
74
# File 'lib/bsv/primitives/hex.rb', line 72

def self.encode(bytes)
  bytes.unpack1('H*')
end

.valid?(str) ⇒ Boolean

Test whether str is valid hex (even-length, hex-only).

Parameters:

  • str (String)

Returns:

  • (Boolean)


32
33
34
35
36
# File 'lib/bsv/primitives/hex.rb', line 32

def self.valid?(str)
  str.is_a?(String) && str.match?(HEX_RE)
rescue Encoding::CompatibilityError
  false
end

.validate!(str, name: 'hex value') ⇒ String

Validate str as hex, raising on failure.

Parameters:

  • str (String)
  • name (String) (defaults to: 'hex value')

    label for the error message (e.g. ‘txid’)

Returns:

  • (String)

    the input string (pass-through for chaining)

Raises:

  • (ArgumentError)

    if str is not valid hex



44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/bsv/primitives/hex.rb', line 44

def self.validate!(str, name: 'hex value')
  return str if valid?(str)

  reason = if !str.is_a?(String)
             "expected String, got #{str.class}"
           elsif str.length.odd?
             'odd length'
           else
             'contains non-hex characters'
           end
  raise ArgumentError, "invalid #{name}: #{reason} (#{str.inspect})"
end