Transparent¶
Transparent Resource Machine Implementation Details per v0.25.0
Elixir typespec can be found here
Nock specification can here
Below, all instances of "a", "is , "is a" is to be interpreted as "of type" when describing encoded data types.
Primitive choices¶
Commitment Hash¶
We commit a resource compiled to Nock by jamming a resource and pre-pending the binary with "CM_":
Hoon Primitive¶
++ commit :: commit to a resource
|= =resource
^- commitment
(~(cat block 3) 'CM_' (jam resource))
Elixir Primitive¶
@spec commitment(Resource.t()) :: binary()
def commitment(resource = %Resource{}) do
binary_resource = resource |> to_noun() |> Nock.Jam.jam()
"CM_" <> binary_resource
end
Nullifier Hash¶
We nullify a resource compiled to Nock by jamming a resource and pre-pending the binary with "NF_":
Hoon Primitive¶
++ nullify :: nullify a resource
|= =resource
^- nullifier
(~(cat block 3) 'NF_' (jam resource))
Elixir Primitive¶
@spec nullifier(Resource.t()) :: binary()
def nullifier(resource = %Resource{}) do
binary_resource = resource |> to_noun() |> Nock.Jam.jam()
"NF_" <> binary_resource
end
Merkle Tree Hash¶
Our hash used for the Merkle Tree instantiation is sha 256
:
Hoon Primitive¶
Not instantiated.
Elixir Primitive¶
@spec sha256(iodata()) :: binary()
def sha256(a) do
:crypto.hash(:sha256, a)
end
Encoding choices¶
Public and Private Inputs¶
Hoon Encoding¶
The Hoon public-inputs
record with fields:
- commitments
- a list of atoms
- nullifiers
- a list of atoms
- self-tag
- an atom
- other-public
- a noun
The Hoon private-inputs
record with fields:
- committed-resources
- a list of resources
- nullified-resources
- a list of atoms
- other-private
- a noun
+$ public-inputs
$:
commitments=(list @)
nullifiers=(list @)
self-tag=@
other-public=*
==
+$ private-inputs
$:
committed-resources=(list resource)
nullified-resources=(list resource)
other-private=*
==
Elixir Encoding¶
Not instantiated.
Resource Logic¶
Hoon Encoding¶
The Hoon resource-logic
type:
- a boolean-valued function
+$ resource-logic
$~ =>(~ |=(* &))
$-([public-inputs private-inputs] ?)
Elixir Encoding¶
Not instantiated.
Resource¶
Hoon Encoding¶
The Hoon public-inputs
record with fields:
- label
- a UTF-8 Text
- logic
- a resource-logic
- ephemeral
- a boolean
- data
- a cell [a b]
where
- a
is an unsigned integer
- b
is an atom
- nullifier-key
- a 256-bit atom
- nonce
- a 256-bit atom
- rseed
- a string "fake"
+$ resource
$~ :*
label=*@t
logic=*resource-logic
ephemeral=|
quantity=`@u`1
data=*[@u @]
nullifier-key=*@I
nonce=*@I
rseed=%fake
==
$:
label=@t
logic=resource-logic
ephemeral=?
quantity=@u
data=[len=@u val=@]
nullifier-key=@I
nonce=@I
rseed=%fake
==
Elixir Encoding¶
The Elixir Resource.t()
record with fields:
- label
- a binary
- logic
- a Nock noun
- ephemeral
- a boolean
- quantity
- a non-negative integer
- data
- a binary
- nullifier_key
- 256-bit bitstring
- nonce
- 256-bit bitstring
- rseed
- bitstring
typedstruct enforce: true do
field(:label, binary(), default: "")
field(:logic, Noun.t(), default: [[1 | 0], 0 | 0])
field(:ephemeral, bool(), default: false)
field(:quantity, non_neg_integer(), default: 1)
field(:data, binary(), default: <<>>)
field(:nullifier_key, <<_::256>>, default: <<0::256>>)
field(:nonce, <<_::256>>, default: <<0::256>>)
field(:rseed, <<>>, default: <<>>)
end
Complicance Proof¶
Hoon Encoding¶
The Hoon compliance proof
type:
- a string "compliance"
+$ compliance-proof %compliance
Elixir Encoding¶
Not instantiated.
Logic Proof¶
Hoon Encoding¶
The Hoon logic-proof
type:
- a cell [a b]
where
- a
is a resource
- b
is a cell [c d]
where
- c
is public-inputs
- d
is private-inputs
+$ logic-proof
[resource=resource inputs=[public-inputs private-inputs]]
Elixir Encoding¶
The Elixir LogicProof.t()
record with fields:
- resource
- a Resource.t()
- commitments
- a set of binaries
- seen as a public input
- nullifiers
- a set of binaries
- seen as a public input
- self-tag
- a tuple {a, b}
where
- a is either :committed
or :nullified
- b is a binary
- seen as a public input
- other_public
- a Nock noun
- seen as a public input
- committed_plaintexts
- a set of Resource.t()
records
- seen as a private input
- nullified_plaintexts
- a set of Resource.t()
records
- seens as a private input
- other_private
- a Nock noun
- seen as a private input
typedstruct enforce: true do
field(:resource, Resource.t())
field(:commitments, MapSet.t(binary()), default: MapSet.new())
field(:nullifiers, MapSet.t(binary()), default: MapSet.new())
field(:self_tag, {:committed | :nullified, binary()})
field(:other_public, Noun.t(), default: <<>>)
field(:committed_plaintexts, MapSet.t(Resource.t()),
default: MapSet.new()
)
field(:nullified_plaintexts, MapSet.t(Resource.t()),
default: MapSet.new()
)
field(:other_private, Noun.t(), default: <<>>)
end
Proof¶
Hoon Encoding¶
The Hoon proof
type:
- either a compliance-proof
or logic-proof
+$ proof ?(compliance-proof logic-proof)
Elixir Encoding¶
Not instantiated.
Action¶
Hoon Encoding¶
The Hoon action
record with fields:
- commitments
- a list of atoms
- nullifiers
- a list of atoms
- proofs
- a list of proof
values
- app-data
- a cell
+$ action
$~ :*
commitments=~
nullifiers=~
proofs=~
app-data=**
==
$:
commitments=(list @)
nullifiers=(list @)
proofs=(list proof)
app-data=*
==
Elixir Encoding¶
The Elixir Action.t()
record with fields:
- commitments
- a set of binaries
- nullifiers
- a set of binaries
- proofs
- a set of Logic.Proof.t()
records
- app_data
- a binary
typedstruct enforce: true do
field(:commitments, MapSet.t(binary()), default: MapSet.new())
field(:nullifiers, MapSet.t(binary()), default: MapSet.new())
field(:proofs, MapSet.t(LogicProof.t()), default: MapSet.new())
field(:app_data, binary(), default: <<>>)
end
Delta¶
Hoon Encoding¶
The Hoon delta
type:
- an list of [a b]
where
- a
is a [c d]
where
- c
is a UTF-8 text
- d
is a resource-logic
- b
is a signed integer
+$ delta (list [[@t resource-logic] @s])
Elixir Encoding¶
The Elixir Delta.t()
type:
- a map from binaries to integers
@type Delta.t() :: %{binary() => integer()}
Transaction¶
Hoon Encoding¶
The Hoon transaction
record with fields:
- roots
- a list of atoms
- actions
- a list of action
records
- delta
- a delta
- delta-proof
- a string "delta"
+$ transaction
$~ :*
roots=~
actions=~
delta=*delta
delta-proof=%delta
==
$:
roots=(list @)
actions=(list action)
delta=delta
delta-proof=%delta
==
Elixir Encoding¶
The Elixir Transaction.t()
record with fields:
- roots
- a list of binaries
- actions
- a list of Action.t()
records
- delta
- a list of Delta.t()
values
- delta_proof
- bitstring
typedstruct enforce: true do
field(:roots, MapSet.t(binary()), default: MapSet.new())
field(:actions, MapSet.t(Action.t()), default: MapSet.new())
field(:delta, Delta.t(), default: %{})
field(:delta_proof, <<>>, default: <<>>)
end
Other decisions¶
Compliance Verification¶
@spec verify_tx_action_compliance(t()) :: true | {:error, String.t()}
def verify_tx_action_compliance(%Transaction{actions: actions}) do
failed =
actions
|> Enum.map(&Action.verify_correspondence/1)
|> Enum.reject(&(&1 == true))
Enum.empty?(failed) or
{:error, Enum.join(Enum.map(failed, &elem(&1, 1)), "\n")}
end
with verify_correspondence
defined as:
@spec verify_correspondence(t()) :: true | {:error, String.t()}
def verify_correspondence(action = %Action{}) do
# Bail out early, if there are more committed and nullified
# resources than there are actual resource proofs
if MapSet.size(action.proofs) <
MapSet.size(action.commitments) + MapSet.size(action.nullifiers) do
{:error,
"there are more commitments and nullifiers than actual logic proofs\n" <>
"#{inspect(action, pretty: true)}"}
else
# TODO Should I check that LogicProof.commitments =
# Action.commitments, as well as the nullifiers? Or can I assume
# that they are the same context. I could technically make it
# lie if I constructed it to lie, no?
failed_proofs =
action.proofs
|> Enum.map(fn proof = %LogicProof{} ->
cond do
not LogicProof.verify_resource_corresponds_to_tag(proof) ->
"Logic Proof failed, the resource's commitment\nullifier:\n" <>
"#{inspect(proof.resource, pretty: true)}\n" <>
"does not match the commitment/nullifier: #{inspect(proof.self_tag)}"
not verify_resource_is_accounted_for?(action, proof) ->
"The resource:\n" <>
"#{inspect(proof.resource, pretty: true)}\n" <>
"Is not found in the Action's commitment/nullifier set"
not verify_action_resources_correspond_to_proofs?(action, proof) ->
"Either the action's commitments:\n" <>
"#{inspect(action.commitments, pretty: true)}" <>
"does not match the proof's commitments:" <>
"#{inspect(proof.commitments, pretty: true)}" <>
"or the action's nullifiers:" <>
"#{inspect(action.nullifiers, pretty: true)}" <>
"does not match the proof's nullifiers:" <>
"#{inspect(proof.nullifiers, pretty: true)}"
true ->
true
end
end)
|> Enum.reject(&(&1 == true))
Enum.empty?(failed_proofs) ||
{:error,
"The following correspondence proofs failed:\n" <>
Enum.join(failed_proofs, "\n")}
end
end