diff options
Diffstat (limited to 'shard/lib')
-rw-r--r-- | shard/lib/data/signrev.ex | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/shard/lib/data/signrev.ex b/shard/lib/data/signrev.ex new file mode 100644 index 0000000..6360b53 --- /dev/null +++ b/shard/lib/data/signrev.ex @@ -0,0 +1,74 @@ +defmodule SData.SignRev do + @moduledoc""" + Implement a simple signed object with a revision number. + """ + + + defstruct [:term, :rev, :signed] + + @doc""" + New SignRev with an unsigned initial state (use this if initial state is deterministic/not signed). + """ + def new(init_term) do + %__MODULE__{term: init_term, rev: 0, signed: nil} + end + + @doc""" + New SignRev with a signed initial state. + """ + def new(init_term, pk) do + bin = SData.term_bin {0, init_term} + case Shard.Keys.sign(pk, bin) do + {:ok, signed} -> + {:ok, %__MODULE__{term: init_term, rev: 0, signed: signed}} + err -> err + end + end + + @doc""" + Get the current value of the SignRev. + """ + def get(sr) do + sr.term + end + + @doc""" + Update the SignRev with a new value and sign it with this pk + """ + def set(sr, new_term, pk) do + rev = sr.rev + 1 + bin = SData.term_bin {rev, new_term} + case Shard.Keys.sign(pk, bin) do + {:ok, signed} -> + {:ok, %__MODULE__{term: new_term, rev: rev, signed: signed}} + err -> err + end + end + + @doc""" + Get the signed binary for the SignRev. Just send the output of this + to a peer for him to update. + """ + def signed(sr) do + sr.signed + end + + @doc""" + Check that a signed binary is correct and merge it into the SignRev. + + Returns {true, new_sr} if an update happenned, {false, sr} otherwise. + """ + def merge(sr, signed, pk) do + case Shard.Keys.open(pk, signed) do + {:ok, bin} -> + {rev, new_term} = SData.term_unbin bin + if rev > sr.rev do + {true, %__MODULE__{term: new_term, rev: rev, signed: signed}} + else + {false, sr} + end + _ -> + {false, sr} + end + end +end |