-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
490 additions
and
168 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
defmodule Anoma.Delta do | ||
@moduledoc false | ||
|
||
@type t() :: %{binary() => non_neg_integer()} | ||
|
||
def add(d1, d2) do | ||
Map.merge(d1, d2, fn _k, v1, v2 -> v1 + v2 end) | ||
|> Map.reject(fn {_k, v} -> v == 0 end) | ||
end | ||
|
||
def sub(d1, d2) do | ||
Map.merge(d1, d2, fn _k, v1, v2 -> v1 - v2 end) | ||
|> Map.reject(fn {_k, v} -> v == 0 end) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
defmodule Anoma.Proof do | ||
@moduledoc false | ||
|
||
use TypedStruct | ||
|
||
# a transparent resource logic proof is just the resource | ||
typedstruct enforce: true do | ||
field(:resource, Anoma.Resource.t()) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
defmodule Anoma.ProofRecord do | ||
@moduledoc false | ||
|
||
alias __MODULE__ | ||
use TypedStruct | ||
|
||
alias Anoma.Proof | ||
|
||
typedstruct enforce: true do | ||
field(:proof, Anoma.Proof.t(), default: nil) | ||
end | ||
|
||
def prove(resource) do | ||
%ProofRecord{ | ||
proof: %Proof{ | ||
resource: resource | ||
} | ||
} | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,61 +1,165 @@ | ||
defmodule Anoma.Resource do | ||
@moduledoc """ | ||
Ι represent a resource | ||
Ι represent a resource. | ||
Do not create with `%Anoma.Resource{}` directly, instead use | ||
`%{Anoma.Resource.new | ...}` for random nonce and seed. | ||
""" | ||
|
||
alias __MODULE__ | ||
use TypedStruct | ||
|
||
typedstruct do | ||
# TODO Should we make this a sexp or a logic? | ||
field(:logic, Anoma.Logic.t(), default: 0) | ||
field(:quantity, integer(), enforce: true) | ||
field(:value, binary(), default: <<>>) | ||
# also known as dynamic data | ||
field(:suffix, binary(), default: <<>>) | ||
# also known as static data | ||
field(:prefix, binary(), default: <<>>) | ||
field(:data, any(), default: <<>>) | ||
alias Anoma.Sign | ||
|
||
typedstruct enforce: true do | ||
# resource logic | ||
field(:logic, Noun.t(), default: [[1 | 0], 0 | 0]) | ||
# fungibility label | ||
field(:label, binary(), default: <<>>) | ||
# quantity | ||
field(:quantity, non_neg_integer(), default: 0) | ||
# arbitrary data | ||
field(:data, binary(), default: <<>>) | ||
# ephemerality flag | ||
field(:eph, bool(), default: false) | ||
# resource nonce | ||
field(:nonce, <<_::256>>, default: <<0::256>>) | ||
# nullifier public key | ||
field(:npk, Sign.ed25519_public(), default: <<0::256>>) | ||
# random seed | ||
field(:rseed, <<_::256>>, default: <<0::256>>) | ||
end | ||
|
||
@doc "New blank resource. Randomized nonce and seed." | ||
def new do | ||
nonce = :crypto.strong_rand_bytes(32) | ||
rseed = :crypto.strong_rand_bytes(32) | ||
%Resource{nonce: nonce, rseed: rseed} | ||
end | ||
|
||
@doc """ | ||
Helper to pass in the npk for initializing a valid but meaningless | ||
resource. | ||
""" | ||
def new_with_npk(npk) do | ||
%{new() | npk: npk} | ||
end | ||
|
||
@doc "A commitment to the given resource." | ||
def commitment(resource = %Resource{}) do | ||
"committo" <> :erlang.term_to_binary(resource) | ||
end | ||
|
||
@doc """ | ||
The nullifier of the given resource. | ||
(It's up to the caller to use the right secret.) | ||
""" | ||
def nullifier(resource = %Resource{}, secret) do | ||
("annullo" <> :erlang.term_to_binary(resource)) | ||
|> Sign.sign(secret) | ||
end | ||
|
||
@spec denomination(t()) :: binary() | ||
def denomination(denom) do | ||
Anoma.Serializer.serialize([denom.logic, denom.prefix]) | ||
@doc """ | ||
The kind of the given resource (labelled logic). | ||
""" | ||
def kind(resource = %Resource{}) do | ||
:erlang.term_to_binary(resource.logic) <> :erlang.term_to_binary(resource.label) | ||
end | ||
|
||
@doc """ | ||
Create an empty resource with a given quantity | ||
The delta of the given resource (kind and quantity). | ||
""" | ||
@spec new(integer()) :: t() | ||
def new(num) do | ||
%Resource{quantity: num} | ||
def delta(resource = %Resource{}) do | ||
%{kind(resource) => resource.quantity} | ||
end | ||
|
||
def transparent_committed_resource(commitment) do | ||
with "committo" <> committed_resource_bytes <- commitment do | ||
{:ok, :erlang.binary_to_term(committed_resource_bytes)} | ||
else | ||
_ -> :error | ||
end | ||
end | ||
|
||
@doc """ | ||
Whether a commitment commits to a given resource. | ||
""" | ||
def commits_to(commitment, resource) do | ||
with {:ok, committed_resource} <- transparent_committed_resource(commitment) do | ||
committed_resource == resource | ||
else | ||
_ -> false | ||
end | ||
end | ||
|
||
I help create a completely empty resource, with a given term as the | ||
suffix. | ||
def commits_to_any(commitment, resources) do | ||
Enum.any?(resources, fn r -> commitment |> commits_to(r) end) | ||
end | ||
|
||
This is mainly helpful in testing, as we can create unique empty | ||
resources. | ||
@doc """ | ||
Whether a nullifier nullifies a given resource. | ||
""" | ||
def nullifies(nullifier, resource) do | ||
with {:ok, verified_nullifier} <- Sign.verify(nullifier, resource.npk), | ||
"annullo" <> nullified_resource_bytes <- verified_nullifier do | ||
:erlang.binary_to_term(nullified_resource_bytes) == resource | ||
else | ||
_ -> false | ||
end | ||
end | ||
|
||
## Parameters | ||
def nullifies_any(nullifier, resources) do | ||
Enum.any?(resources, fn r -> nullifier |> nullifies(r) end) | ||
end | ||
|
||
- `suffix` - any term that will be turned into a binary for testing | ||
def run_resource_logic(transaction, resource) do | ||
logic = resource.logic | ||
result = Nock.nock(logic, [9, 2, 0 | 1]) | ||
IO.inspect(result, label: "nock result") | ||
|
||
## Output | ||
case result do | ||
{:ok, 0} -> | ||
true | ||
|
||
- The empty resource | ||
_ -> | ||
false | ||
end | ||
end | ||
|
||
@doc """ | ||
The resource as a noun. | ||
""" | ||
@spec make_empty(term()) :: t() | ||
def make_empty(suffix) do | ||
%Resource{quantity: 0, suffix: :erlang.term_to_binary(suffix)} | ||
def to_noun(resource = %Resource{}) do | ||
[ | ||
resource.logic, | ||
Noun.atom_binary_to_integer(resource.label), | ||
resource.quantity, | ||
Noun.atom_binary_to_integer(resource.data), | ||
if resource.eph do | ||
0 | ||
else | ||
1 | ||
end, | ||
Noun.atom_binary_to_integer(resource.nonce), | ||
Noun.atom_binary_to_integer(resource.npk) | ||
| Noun.atom_binary_to_integer(resource.rseed) | ||
] | ||
end | ||
end | ||
|
||
defimpl Anoma.Intent, for: Anoma.Resource do | ||
def is_intent(_data) do | ||
true | ||
def from_noun([logic, label, quantity, data, eph, nonce, npk | rseed]) do | ||
%Resource{ | ||
logic: logic, | ||
label: Noun.atom_integer_to_binary(label), | ||
quantity: quantity, | ||
data: Noun.atom_integer_to_binary(data), | ||
eph: | ||
case eph do | ||
0 -> true | ||
1 -> false | ||
end, | ||
nonce: Noun.atom_integer_to_binary(nonce), | ||
npk: Noun.atom_integer_to_binary(npk), | ||
rseed: Noun.atom_integer_to_binary(rseed) | ||
} | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
defmodule Anoma.Sign do | ||
@moduledoc false | ||
|
||
@type ed25519_public() :: <<_::256>> | ||
@type ed25519_secret() :: <<_::512>> | ||
|
||
@spec new_keypair() :: %{public: ed25519_public(), secret: ed25519_secret()} | ||
def new_keypair do | ||
:enacl.crypto_sign_ed25519_keypair() | ||
end | ||
|
||
@spec sign(binary(), ed25519_secret()) :: binary() | ||
def sign(message, secret) do | ||
:enacl.sign(message, secret) | ||
end | ||
|
||
@spec verify(binary, ed25519_public()) :: binary() | ||
def verify(signed_message, public) do | ||
:enacl.sign_open(signed_message, public) | ||
end | ||
end |
Oops, something went wrong.