Module: Familia::SecureIdentifier

Included in:
Familia
Defined in:
lib/familia/secure_identifier.rb

Constant Summary collapse

HEX_LENGTHS =

Fast lookup for hex (base 16) - our most common case Avoids calculation overhead for 99% of ID generation

{
  256 => 64,  # SHA-256 equivalent entropy
  128 => 32,  # UUID equivalent entropy
  64  => 16,  # Compact ID
}.freeze

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.min_length_for_bits(bits, base) ⇒ Integer

Get minimum character length needed to encode bits of entropy in base

Parameters:

  • bits (Integer)

    Number of bits of entropy needed

  • base (Integer)

    Numeric base (2-36)

Returns:

  • (Integer)

    Minimum string length required



122
123
124
125
126
127
# File 'lib/familia/secure_identifier.rb', line 122

def self.min_length_for_bits(bits, base)
  return HEX_LENGTHS[bits] if base == 16 && HEX_LENGTHS.key?(bits)

  @length_cache ||= {}
  @length_cache[[bits, base]] ||= (bits * Math.log(2) / Math.log(base)).ceil
end

Instance Method Details

#generate_hex_idString

Generates a 256-bit cryptographically secure hexadecimal identifier.

Returns:

  • (String)

    A 64-character hex string representing 256 bits of entropy.



12
13
14
# File 'lib/familia/secure_identifier.rb', line 12

def generate_hex_id
  SecureRandom.hex(32)
end

#generate_hex_trace_idString

Note:

64 bits provides ~18 quintillion values, sufficient for request tracing.

Generates a 64-bit cryptographically secure hexadecimal trace identifier.

Returns:

  • (String)

    A 16-character hex string representing 64 bits of entropy.



20
21
22
# File 'lib/familia/secure_identifier.rb', line 20

def generate_hex_trace_id
  SecureRandom.hex(8)
end

#generate_id(base = 36) ⇒ String

Generates a cryptographically secure identifier, encoded in the specified base. By default, this creates a compact, URL-safe base-36 string.

Examples:

Generate a 256-bit ID in base-36 (default)

generate_id # => "25nkfebno45yy36z47ffxef2a7vpg4qk06ylgxzwgpnz4q3os4"

Generate a 256-bit ID in base-16 (hexadecimal)

generate_id(16) # => "568bdb582bc5042bf435d3f126cf71593981067463709c880c91df1ad9777a34"

Parameters:

  • base (Integer) (defaults to: 36)

    The base for encoding the output string (2-36, default: 36).

Returns:

  • (String)

    A secure identifier.



36
37
38
39
# File 'lib/familia/secure_identifier.rb', line 36

def generate_id(base = 36)
  target_length = SecureIdentifier.min_length_for_bits(256, base)
  generate_hex_id.to_i(16).to_s(base).rjust(target_length, '0')
end

#generate_trace_id(base = 36) ⇒ String

Generates a short, secure trace identifier, encoded in the specified base. Suitable for tracing, logging, and other ephemeral use cases.

Examples:

Generate a 64-bit short ID in base-36 (default)

generate_trace_id # => "lh7uap704unf"

Generate a 64-bit short ID in base-16 (hexadecimal)

generate_trace_id(16) # => "94cf9f8cfb0eb692"

Parameters:

  • base (Integer) (defaults to: 36)

    The base for encoding the output string (2-36, default: 36).

Returns:

  • (String)

    A secure short identifier.



53
54
55
56
# File 'lib/familia/secure_identifier.rb', line 53

def generate_trace_id(base = 36)
  target_length = SecureIdentifier.min_length_for_bits(64, base)
  generate_hex_trace_id.to_i(16).to_s(base).rjust(target_length, '0')
end

#shorten_to_external_id(hex_id, base: 36) ⇒ String

Note:

This is useful for creating shorter, public-facing IDs from secure internal ones.

Truncates a 256-bit hexadecimal ID to 128 bits and encodes it in a given base. This function takes the most significant bits from the hex string to maintain randomness while creating a shorter, deterministic identifier that’s safe for outdoor use.

Examples:

Create a shorter external ID from a full 256-bit internal ID

hex_id = generate_hex_id
external_id = shorten_to_external_id(hex_id)

Parameters:

  • hex_id (String)

    A 64-character hexadecimal string (representing 256 bits).

  • base (Integer) (defaults to: 36)

    The base for encoding the output string (2-36, default: 36).

Returns:

  • (String)

    A 128-bit identifier, encoded in the specified base.



87
88
89
90
91
# File 'lib/familia/secure_identifier.rb', line 87

def shorten_to_external_id(hex_id, base: 36)
  target_length = SecureIdentifier.min_length_for_bits(128, base)
  truncated = hex_id.to_i(16) >> (256 - 128) # Always 128 bits
  truncated.to_s(base).rjust(target_length, '0')
end

#shorten_to_trace_id(hex_id, base: 36) ⇒ String

Truncates a 256-bit hexadecimal ID to 64 bits and encodes it in a given base. These short, deterministic IDs are useful for secure logging. By inputting the full hexadecimal string, you can generate a consistent short ID that allows tracking an entity through logs without exposing the entity’s full identifier..

Parameters:

  • hex_id (String)

    A 64-character hexadecimal string (representing 256 bits).

  • base (Integer) (defaults to: 36)

    The base for encoding the output string (2-36, default: 36).

Returns:

  • (String)

    A 64-bit identifier, encoded in the specified base.



66
67
68
69
70
# File 'lib/familia/secure_identifier.rb', line 66

def shorten_to_trace_id(hex_id, base: 36)
  target_length = SecureIdentifier.min_length_for_bits(64, base)
  truncated = hex_id.to_i(16) >> (256 - 64) # Always 64 bits
  truncated.to_s(base).rjust(target_length, '0')
end