Current section
Files
Jump to
Current section
Files
lib/mix/tasks/optimushash.seed.ex
defmodule Mix.Tasks.OptimusHash.Seed do
@moduledoc """
Generates the required configuration for using OptimusHash. This task is intended
to be run only once.
## Example
mix ecto.dump
## Command line options
* `--bits` - does not compile applications before dumping
* `--no-deps-check` - does not check depedendencies before dumping
"""
import Mix.Generator
use Mix.Task
use Bitwise
@shortdoc "Generates a set of configuration values for OptimusHash"
@switches [
bits: [:integer]
]
def run(args) do
case OptionParser.parse!(args, strict: @switches) do
{opts, arguments} ->
max_size = Keyword.get(opts, :bits, 31)
if max_size < 16 do
Mix.raise("Using less than 16bits is not recommended")
end
prime =
case List.first(arguments) do
nil ->
try do
{result, 0} =
System.cmd("openssl", ["prime", "-generate", "-bits", "#{max_size}"])
case Integer.parse(result) do
{number, _} ->
number
:error ->
Mix.raise(
"expected a valid integer as a prime, got: #{inspect(List.first(arguments))}"
)
end
rescue
_ ->
Mix.raise(
"Failed to generate a prime using 'openssl prime -generate -bits #{max_size}'. " <>
"You can either install 'openssl' and run the command again or get a prime " <>
"from somewhere else (e.g. http://primes.utm.edu/lists/small/millions/). " <>
"You should independently verify that your number is in fact a prime number. " <>
"To run the command again use: mix optimus_hash.seed --bits #{max_size} YOUR_PRIME"
)
end
_ ->
case Integer.parse(List.first(arguments)) do
{number, _} ->
number
:error ->
Mix.raise(
"expected a valid integer as a prime, got: #{inspect(List.first(arguments))}"
)
end
end
max_id = trunc(:math.pow(2, max_size)) - 1
mod_inverse = OptimusHash.Helpers.mod_inverse(prime, max_id + 1)
random =
ceil(max_size / 8)
|> :crypto.strong_rand_bytes()
|> :binary.decode_unsigned()
|> band(max_id)
OptimusHash.new(
prime: prime,
mod_inverse: mod_inverse,
random: random,
max_size: max_size
)
code =
Code.format_string!(
code_inline_template(%{
prime: prime,
mod_inverse: mod_inverse,
random: random,
max_size: max_size
})
)
Mix.shell().info("""
Configuration:
- prime: #{prime}
- mod_inverse: #{mod_inverse}
- random: #{random}
- max_size: #{max_size}
Code:
```
#{code}
```
""")
end
end
embed_template(:code_inline, """
OptimusHash.new(
prime: <%= @prime %>,
mod_inverse: <%= @mod_inverse %>,
random: <%= @random %>,
max_size: <%= @max_size %>
)
""")
end