# FeistelCipher
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
```bash
mix igniter.install feistel_cipher
```
### Manual Installation
1. Add `feistel_cipher` to your list of dependencies in `mix.exs`:
```elixir
def deps do
[
{:feistel_cipher, "~> 0.1.0"}
]
end
```
2. Fetch the dependencies:
```bash
mix deps.get
```
3. Run the installer to generate the initial migration files:
```bash
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.
```elixir
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):
```elixir
# 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