Skip to content

Commit

Permalink
Use NIF instead of WASM to gain performances
Browse files Browse the repository at this point in the history
  • Loading branch information
samuelmanzanera committed Jul 3, 2024
1 parent 41a5819 commit b9704b4
Show file tree
Hide file tree
Showing 38 changed files with 879 additions and 557 deletions.
Binary file removed .DS_Store
Binary file not shown.
88 changes: 88 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
name: Build precompiled NIFs

on:
push:
branches:
- master
tags:
- "*"

jobs:
build_release:
name: NIF ${{ matrix.nif }} - ${{ matrix.job.target }} (${{ matrix.job.os }})
runs-on: ${{ matrix.job.os }}
strategy:
fail-fast: false
matrix:
nif: ["2.16", "2.17"]
job:
- {
target: arm-unknown-linux-gnueabihf,
os: ubuntu-20.04,
use-cross: true,
}
- {
target: aarch64-unknown-linux-gnu,
os: ubuntu-20.04,
use-cross: true,
}
- {
target: aarch64-unknown-linux-musl,
os: ubuntu-20.04,
use-cross: true,
}
- { target: aarch64-apple-darwin, os: macos-14 }
- {
target: riscv64gc-unknown-linux-gnu,
os: ubuntu-20.04,
use-cross: true,
}
- { target: x86_64-apple-darwin, os: macos-14 }
- { target: x86_64-unknown-linux-gnu, os: ubuntu-20.04 }
- {
target: x86_64-unknown-linux-musl,
os: ubuntu-20.04,
use-cross: true,
}
- { target: x86_64-pc-windows-gnu, os: windows-2019 }
- { target: x86_64-pc-windows-msvc, os: windows-2019 }

steps:
- name: Checkout source code
uses: actions/checkout@v3

- name: Extract project version
shell: bash
run: |
# Get the project version from mix.exs
echo "PROJECT_VERSION=$(grep 'version:' mix.exs | cut -d '"' -f2)" >> $GITHUB_ENV
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
target: ${{ matrix.job.target }}

- name: Build the project
id: build-crate
uses: philss/[email protected]
with:
project-name: bls
project-version: ${{ env.PROJECT_VERSION }}
target: ${{ matrix.job.target }}
nif-version: ${{ matrix.nif }}
use-cross: ${{ matrix.job.use-cross }}
project-dir: "native/bls"

- name: Artifact upload
uses: actions/upload-artifact@v3
with:
name: ${{ steps.build-crate.outputs.file-name }}
path: ${{ steps.build-crate.outputs.file-path }}

- name: Publish archives and packages
uses: softprops/action-gh-release@v1
with:
files: |
${{ steps.build-crate.outputs.file-path }}
if: startsWith(github.ref, 'refs/tags/')
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,5 @@ bls_ex-*.tar

# Temporary files, for example, from tests.
/tmp/

.DS_Store
4 changes: 0 additions & 4 deletions config/config.exs

This file was deleted.

114 changes: 61 additions & 53 deletions lib/bls_ex.ex
Original file line number Diff line number Diff line change
@@ -1,72 +1,80 @@
defmodule BlsEx do
@moduledoc """
BlsEx provides utility to leverage BLS signatures through WASM
"""
alias __MODULE__.Keystore
BlsEx provides utility to leverage BLS signatures
@doc """
Verifies a single BLS signature
BLS scheme supports aggregation of public keys and aggregation of signatures.
## Examples
Here an full example of aggregated signature verification
iex> {:ok, pid} = BlsEx.Keystore.start_link(seed: "myseed")
iex> {:ok, public_key} = BlsEx.Keystore.get_public_key(pid)
iex> {:ok, signature} = BlsEx.Keystore.sign(pid, "hello")
iex> BlsEx.verify_signature(public_key, "hello", signature)
{:ok, true}
iex> seed = :crypto.hash(:sha512, "myseed")
iex> public_key1 = BlsEx.get_public_key(seed)
iex> signature1 = BlsEx.sign(seed, "hello")
iex> seed2 = :crypto.hash(:sha512, "myseed2")
iex> public_key2 = BlsEx.get_public_key(seed2)
iex> signature2 = BlsEx.sign(seed2, "hello")
iex> aggregated_signature = BlsEx.aggregate_signatures([signature1, signature2], [public_key1, public_key2])
iex> aggregated_public_key = BlsEx.aggregate_public_keys([public_key1, public_key2])
iex> BlsEx.verify_signature(aggregated_public_key, "hello", aggregated_signature)
true
"""
@spec verify_signature(public_key :: binary(), message :: binary(), signature :: binary()) ::
{:ok, boolean()} | {:error, any()}
defdelegate verify_signature(public_key, message, signature), to: __MODULE__.StandaloneWasm

@doc """
Aggregate BLS signatures
@version Mix.Project.config()[:version]

## Examples
use RustlerPrecompiled,
otp_app: :bls_ex,
crate: "bls",
base_url: "https://github.com/archethic-foundation/bls_ex/releases/download/#{@version}",
force_build: System.get_env("BLS_EX_BUILD") in ["1", "true"],
targets:
Enum.uniq(["aarch64-unknown-linux-musl" | RustlerPrecompiled.Config.default_targets()]),
version: @version

iex> {:ok, pid} = BlsEx.Keystore.start_link(seed: "myseed")
iex> {:ok, public_key1} = BlsEx.Keystore.get_public_key(pid)
iex> {:ok, signature1} = BlsEx.Keystore.sign(pid, "hello")
iex> {:ok, pid2} = BlsEx.Keystore.start_link(seed: "myseed2")
iex> {:ok, public_key2} = BlsEx.Keystore.get_public_key(pid2)
iex> {:ok, signature2} = BlsEx.Keystore.sign(pid2, "hello")
iex> BlsEx.aggregate_signatures([signature1, signature2], [public_key1, public_key2])
"""
@spec aggregate_signatures(signatures :: list(binary()), public_keys :: list(binary())) ::
{:ok, binary()} | {:error, any()}
defdelegate aggregate_signatures(signatures, public_keys), to: __MODULE__.StandaloneWasm
@type secret_key :: <<_::512>>
@type signature :: <<_::96>>
@type public_key :: <<_::48>>

@doc """
Aggregate BLS public keys
## Examples
Generate a public key from a secret key
"""
@spec get_public_key(secret_key :: secret_key()) :: public_key()
def get_public_key(secret_key) when is_binary(secret_key) and byte_size(secret_key) == 512,
do: :erlang.nif_error(:nif_not_loaded)

iex> {:ok, pid} = BlsEx.Keystore.start_link(seed: "myseed")
iex> {:ok, public_key1} = BlsEx.Keystore.get_public_key(pid)
iex> {:ok, pid2} = BlsEx.Keystore.start_link(seed: "myseed2")
iex> {:ok, public_key2} = BlsEx.Keystore.get_public_key(pid2)
iex> {:ok, _aggregated_public_key} = BlsEx.aggregated_public_keys([public_key1, public_key2])
@doc """
Sign a message using the given secret key
"""
@spec aggregated_public_keys(public_keys :: list(binary())) :: {:ok, binary()} | {:error, any()}
defdelegate aggregated_public_keys(public_keys), to: __MODULE__.StandaloneWasm
@spec sign(secret_key :: secret_key(), message :: binary()) :: signature()
def sign(secret_key, data)
when is_binary(secret_key) and byte_size(secret_key) == 512 and is_binary(data),
do: :erlang.nif_error(:nif_not_loaded)

@doc """
Verifies an aggregated BLS signature
Verifies a single BLS signature
"""
@spec verify_signature(
public_key :: public_key(),
message :: binary(),
signature :: signature()
) ::
boolean()
def verify_signature(public_key, message, signature)
when is_binary(public_key) and byte_size(public_key) == 48 and is_binary(message) and
is_binary(signature) and byte_size(signature) == 96,
do: :erlang.nif_error(:nif_not_loaded)

## Examples
@doc """
Aggregate a list of signatures
"""
@spec aggregate_signatures(list(signature()), list(public_key())) :: signature()
def aggregate_signatures(signatures, public_keys)
when is_list(signatures) and is_list(public_keys) and
length(signatures) == length(public_keys),
do: :erlang.nif_error(:nif_not_loaded)

iex> {:ok, pid} = BlsEx.Keystore.start_link(seed: "myseed")
iex> {:ok, public_key1} = BlsEx.Keystore.get_public_key(pid)
iex> {:ok, signature1} = BlsEx.Keystore.sign(pid, "hello")
iex> {:ok, pid2} = BlsEx.Keystore.start_link(seed: "myseed2")
iex> {:ok, public_key2} = BlsEx.Keystore.get_public_key(pid2)
iex> {:ok, signature2} = BlsEx.Keystore.sign(pid2, "hello")
iex> {:ok, aggregated_signature} = BlsEx.aggregate_signatures([signature1, signature2], [public_key1, public_key2])
iex> BlsEx.verify_aggregated_signature( [public_key1, public_key2], "hello", aggregated_signature)
{:ok, true}
@doc """
Aggregate a list of public keys
"""
@spec verify_aggregated_signature(list(binary()), binary(), binary()) ::
{:ok, boolean()} | {:error, any()}
defdelegate verify_aggregated_signature(public_keys, message, signature),
to: __MODULE__.StandaloneWasm
@spec aggregate_public_keys(list(public_key())) :: public_key()
def aggregate_public_keys(public_keys) when is_list(public_keys),
do: :erlang.nif_error(:nif_not_loaded)
end
13 changes: 0 additions & 13 deletions lib/bls_ex/application.ex

This file was deleted.

97 changes: 0 additions & 97 deletions lib/bls_ex/keystore.ex

This file was deleted.

Loading

0 comments on commit b9704b4

Please sign in to comment.