FeistelCipher

View Source

Database functions for Feistel cipher.

This library provides Mix tasks and Ecto migrations to set up and manage Feistel cipher functions and triggers in your PostgreSQL database. Feistel cipher can be used to generate reversible, non-sequential IDs from sequential numbers.

Installation

You can install FeistelCipher using igniter or by manually adding it to your dependencies.

Using igniter

mix igniter.install feistel_cipher

Manual Installation

  1. Add feistel_cipher to your list of dependencies in mix.exs:

    def deps do
      [
        {:feistel_cipher, "~> 0.1.0"}
      ]
    end
  2. Fetch the dependencies:

    mix deps.get
    
  3. Run the installer to generate the initial migration files:

    mix feistel_cipher.install
    

    This command will generate a migration file in your priv/repo/migrations directory. You can customize the installation with the following options:

    • --repo or -r: Specify the Ecto repo for FeistelCipher to use (e.g., MyApp.Repo). Defaults to YourApp.Repo.
    • --prefix or -p: Specify a schema prefix for the FeistelCipher functions (e.g., my_app_prefix). Defaults to public.

Example Ecto Schema

Below is an example of an Ecto schema for a table that uses a Feistel cipher. In this common setup:

  • The seq column is a BIGSERIAL (auto-incrementing integer) in the database, serving as the source for the Feistel cipher.
  • The id column is a BIGINT primary key, and its value is automatically generated by a database trigger using the seq column.
defmodule MyApp.MyTable do
  use Ecto.Schema

  # Defines `id` as the primary key (typically BIGINT in the DB).
  # `autogenerate: true` indicates that its value is set by a database trigger
  # based on the Feistel cipher of the `seq` column, not by a DB sequence directly on `id`.
  @primary_key {:id, :id, autogenerate: true}
  @foreign_key_type :id # For foreign keys referencing this table's `id`.

  schema "my_table" do
    # `seq` is the source for the Feistel cipher. In the database, this is typically a BIGSERIAL column.
    # Ecto's `:id` type with `autogenerate: true` here reflects the auto-incrementing nature
    # of a BIGSERIAL column when mapped in Ecto for a non-primary key field.
    field :seq, :id, autogenerate: true

    # The `id` field itself (the primary key) is implicitly defined by @primary_key.
    # Its value will be populated by the Feistel cipher trigger.

    timestamps()
  end
end

When creating the actual database table via a migration:

  • You would define seq as BIGSERIAL.
  • You would define id as BIGINT and set it as the primary key. The Ecto schema above reflects how Ecto maps these PostgreSQL types and their behaviors. The feistel_cipher trigger will take the auto-generated seq value and populate the id column with the Feistel-ciphered value.

Creating Triggers for Tables

To automatically encrypt a source column into a target column for a specific table, you can create a database trigger. The FeistelCipher.Migration.up_sql_for_table/2 function helps generate the necessary SQL.

For example, if you have a table named posts with a seq column (source) and you want to store the Feistel ciphered ID in an id column (target):

# Example: priv/repo/migrations/YYYYMMDDHHMMSS_add_posts_feistel_trigger.exs
defmodule MyApp.Repo.Migrations.AddPostsFeistelTrigger do
  use Ecto.Migration

  def up do
    # Default bits: 62
    execute FeistelCipher.Migration.up_sql_for_table("posts", bits: 40, source: "seq", target: "id")
  end

  def down do
    execute FeistelCipher.Migration.down_sql_for_table("posts", bits: 40, source: "seq", target: "id")
  end
end

Then run mix ecto.migrate to apply the migration.

The up_sql_for_table/2 function accepts the following options:

  • table: (String, required) The name of the table.
  • source: (String, required) The name of the source column containing the bigint integer (typically from a BIGSERIAL column like seq).
  • target: (String, required) The name of the target column to store the encrypted integer (typically the BIGINT primary key like id).
  • bits: (Integer, optional) The number of bits for the Feistel cipher. Must be an even number, 62 or less. Defaults to 62.

The trigger will automatically populate the target column when a new row is inserted. It also prevents manual modification of the target column on update.

License

MIT