This is an experimental implementation of KERI protocol that aims to be compatible with the vLEI ecosystem
The goal of this project is to build a "validator" component that allows to monitor KERI AIDs and maintain up to date key state.
It currently consists of two parts:
Kerilex- low-level functionality to parse and validate KELs, plus some ability to create and sign certain type of events.Watcher- building blocks that can be used to create a continuously running validator.
Alpha - expect continuous changes as I explore various ways to deal with asynchronous nature of KERI and its infrastructure components.
The Modules and their "shape" are changing as I try to find the optimal decomposition. Documentation is sparse and typespecs are not always defined.
- parses KERI 1.0 KELs -
icp,dip,rot,drtandixnmessages along with the typical CESR attachments - allows creation of
icp,rpy( endpoint),qrymessages along with signing. - Generates signers based on
CESRsalt, which allows to have signers identical to those generated bykeripy'skli. Watcherhas asynchronous qry/response component (Watcher.WitnessClient) that can send and process variousqrymessages and collects indexed response from amailboxWatcheralso hasOOBIprocessor that will take the output of aKerilex.KELparser.parseand, if all checks run though, will fillmnesiabased tables with the processed events and output a%KeyStateCache{}containing calculated key states ofAIDs that were included in theOOBIresponse.
- Elixir - 1.17 and OTP27
- dev version of
libsodium ctoolchain to compilelibsodiumnif- Rust to compile
blake3 - setup proper variables pointing to the installed libs
- E.g. for
mac, if usingbrew(works onm1/m3)LDFLAGS=-L/opt/homebrew/include C_INCLUDE_PATH=/opt/homebrew/include CPLUS_INCLUDE_PATH=/opt/homebrew/include LIBRARY_PATH=/opt/homebrew/lib
- E.g. for
from the project's root directory get and compile dependencies.
mix deps.get
mix deps.compileYou can either use the
iexto paly with the API or uselivebookto see how theWatcherfunctionality works.
mkdir -p tmp/db
iex -S mix:mnesia.stop
:mnesia.create_schema([node()])
:mnesia.start
Watcher.KeyStateStore.init_tables
alias Watcher.{OOBI.LogsProcessor, EventEscrow}
gleif_geda_kel = File.read!("test/data/gleif-kel-july-23-24") |> Kerilex.KELParser.parse
gleif_geda_kel |> LogsProcessor.process_kel(EventEscrow.new())output
18:23:26.910 [debug] [type: "icp", msg: "added event", result: "updated KEL", pre: "EDP1vHcw_wc4M__Fj53-cJaBnZZASd-aMTaSyWEQ-PC2", sn: 0]
18:23:26.912 [debug] [type: "rot", msg: "added event", result: "updated KEL", pre: "EDP1vHcw_wc4M__Fj53-cJaBnZZASd-aMTaSyWEQ-PC2", sn: 1]
18:23:26.913 [debug] [type: "rot", msg: "added event", result: "updated KEL", pre: "EDP1vHcw_wc4M__Fj53-cJaBnZZASd-aMTaSyWEQ-PC2", sn: 2]
18:23:26.914 [debug] [type: "dip", msg: "added event", result: "updated KEL", pre: "EINmHd5g7iV-UldkkkKyBIH052bIyxZNBn9pq-zNrYoS", sn: 0]
18:23:26.915 [debug] [type: "ixn", msg: "added event", result: "updated KEL", pre: "EINmHd5g7iV-UldkkkKyBIH052bIyxZNBn9pq-zNrYoS", sn: 1]
18:23:26.915 [debug] [type: "ixn", msg: "added event", result: "updated KEL", pre: "EINmHd5g7iV-UldkkkKyBIH052bIyxZNBn9pq-zNrYoS", sn: 2]
18:23:26.916 [debug] [type: "ixn", msg: "added event", result: "updated KEL", pre: "EINmHd5g7iV-UldkkkKyBIH052bIyxZNBn9pq-zNrYoS", sn: 3]
18:23:26.916 [debug] [type: "ixn", msg: "added event", result: "updated KEL", pre: "EINmHd5g7iV-UldkkkKyBIH052bIyxZNBn9pq-zNrYoS", sn: 4]
18:23:26.916 [debug] [type: "ixn", msg: "added event", result: "updated KEL", pre: "EINmHd5g7iV-UldkkkKyBIH052bIyxZNBn9pq-zNrYoS", sn: 5]
18:23:26.917 [debug] [type: "ixn", msg: "added event", result: "updated KEL", pre: "EINmHd5g7iV-UldkkkKyBIH052bIyxZNBn9pq-zNrYoS", sn: 6]
18:23:26.917 [debug] [type: "ixn", msg: "added event", result: "updated KEL", pre: "EINmHd5g7iV-UldkkkKyBIH052bIyxZNBn9pq-zNrYoS", sn: 7]
18:23:26.918 [debug] [type: "ixn", msg: "added event", result: "updated KEL", pre: "EINmHd5g7iV-UldkkkKyBIH052bIyxZNBn9pq-zNrYoS", sn: 8]
18:23:26.918 [debug] [type: "rpy", msg: "added event", result: "added witness", url: "http://65.21.253.212:5623/"]
18:23:26.918 [debug] [type: "rpy", msg: "added event", result: "added witness", url: "http://8.210.213.186:5623/"]
18:23:26.919 [debug] [type: "rpy", msg: "added event", result: "added witness", url: "http://51.79.54.121:5623/"]
18:23:26.919 [debug] [type: "rpy", msg: "added event", result: "added witness", url: "http://102.37.159.99:5623/"]
18:23:26.919 [debug] [type: "rpy", msg: "added event", result: "added witness", url: "http://54.233.109.129:5623/"]
18:23:26.919 [debug] [msg: "finished processing KEL messages", kel_length: 17]
{:ok, %Watcher.EventEscrow{store: %{}},
%Watcher.KeyStateCache{
cache: %{
"EDP1vHcw_wc4M__Fj53-cJaBnZZASd-aMTaSyWEQ-PC2" => %Watcher.KeyState{
pe: "ECphNWm1_jZOupeKh6C7TlBi81BlERqbnMpyqpnS4CJY",
te: "rot",
se: 2,
de: "EHsL1ldIafZC-M9-3RgLQB3m2_2F0aYIiNBGnTVoFDH2",
fs: "2024-10-25T16:23:26.910544Z",
k: ["DNLdWqTBKOhDO8YfE5uIaTvN-n_Jv20-5ZwK609BvG0b",
"DL68G7IW4zT2ryLRDziYiRyvwIDyq9xssVuZ3u6w-30Y",
"DH63RGGv_r8pQ5Di9MVblcofkBm0O8r6SUY0cqNAYqne"],
kt: %Kerilex.Crypto.WeightedKeyThreshold{
size: 3,
weights: [Ratio.new(1, 3), Ratio.new(1, 3), Ratio.new(1, 3)],
sum: Ratio.new(1, 1),
ind_ranges: [0..2]
},
n: ["EPHYDUnxDH7xcAim3aYvS9bvh7JmdBDKc__w2_McXr6I",
"EHgOexUh8AvN7rXblsSr6MJE5Gn1HPq5Mv9KFpCpllKN",
"ECH4pTtUI653ykKb_capPBkKF3RvBZRzyb5dPfuJCfOf",
"ELXXiPwoaWOVOTLMOAmg4IKkjFHFs3q2hsL9tHvuuC2D",
"EAcNrjXFeGay9qqMj96FIiDdXqdWjX17QXzdJvq58Zco",
"EF1IPGq_uF3FmywFdIQXSO4jy0QhtzREVMlPQ8PEy_As",
"EHGlZciB0cZ627-MJrQxyw5niNzN1nKnNMDaJO7sCEvF"],
nt: %Kerilex.Crypto.WeightedKeyThreshold{
size: 7,
weights: [Ratio.new(1, 3), Ratio.new(1, 3), Ratio.new(1, 3),
Ratio.new(1, 3), Ratio.new(1, 3), Ratio.new(1, 3), Ratio.new(1, 3)],
sum: Ratio.new(7, 3),
ind_ranges: [0..6]
},
b: ["BNfDO63ZpGc3xiFb0-jIOUnbr_bA-ixMva5cZb3s4BHB",
"BDwydI_FJJ-tvAtCl1tIu_VQqYTI3Q0JyHDhO1v2hZBt",
"BGYJwPAzjyJgsipO7GY9ZsBTeoUJrdzjI2w_5N-Nl6gG",
"BM4Ef3zlUzIAIx-VC8mXziIbtj-ZltM8Aor6TZzmTldj",
"BLo6wQR73-eH5v90at_Wt8Ep_0xfz05qBjM3_B1UtKbC"],
bt: 4,
c: ["EO"],
di: false,
last_event: {"rot", 2, "EHsL1ldIafZC-M9-3RgLQB3m2_2F0aYIiNBGnTVoFDH2"}
},
"EINmHd5g7iV-UldkkkKyBIH052bIyxZNBn9pq-zNrYoS" => %Watcher.KeyState{
pe: nil,
te: "dip",
se: 0,
de: "EINmHd5g7iV-UldkkkKyBIH052bIyxZNBn9pq-zNrYoS",
fs: "2024-10-25T16:23:26.914180Z",
k: ["DEO7QT90CzPeCubjcAgDlYI-yudt0c_4HeAb1_RbrGiF",
"DKu6Q_Qth7x-pztt11qXDr42B9aUjkp_v9Rq8-xXcQjF",
"DEiPSxcuILZFxJscr_Lt8fuiidhB_HrqKxoCbZr9tQfp",
"DIqrjqqwArsSHIX3n510DnSrYL9ULbYOpi14hEencBSC",
"DAB9Tl0T8-638H65GMFj2G7CAr4CoExZ5xH-U1ADldFP"],
kt: %Kerilex.Crypto.WeightedKeyThreshold{
size: 5,
weights: [Ratio.new(1, 2), Ratio.new(1, 2), Ratio.new(1, 2),
Ratio.new(1, 2), Ratio.new(1, 2)],
sum: Ratio.new(5, 2),
ind_ranges: [0..4]
},
n: ["EObLskWwczY3R-ALRPWiyyThtraelnbh6MMeJ_WcR3Gd",
"ENoI2e5f59xEF83joX__915Va-OIE7480wWyh2-8bJk7",
"EElSAVDf2vU8aoxN50eSMNm6MrQ-Hv_2xOWC02tFrS3M",
"EHX0Re-hExzl7mvLuRwQHEew-8oPOQh4rqXJNHBo9EyW",
"EBGeYe1_ZgN_ly0qVY-Y1FayZkNA5Yq9LTujrh2ylKbm"],
nt: %Kerilex.Crypto.WeightedKeyThreshold{
size: 5,
weights: [Ratio.new(1, 2), Ratio.new(1, 2), Ratio.new(1, 2),
Ratio.new(1, 2), Ratio.new(1, 2)],
sum: Ratio.new(5, 2),
ind_ranges: [0..4]
},
b: ["BDkq35LUU63xnFmfhljYYRY0ymkCg7goyeCxN30tsvmS",
"BLmvLSt1mDShWS67aJNP4gBVBhtOc3YEu8SytqVSsyfw",
"BHxz8CDS_mNxAhAxQe1qxdEIzS625HoYgEMgqjZH_g2X",
"BGYJwPAzjyJgsipO7GY9ZsBTeoUJrdzjI2w_5N-Nl6gG",
"BFl6k3UznzmEVuMpBOtUUiR2RO2NZkR3mKrZkNRaZedo"],
bt: 4,
c: [],
di: "EDP1vHcw_wc4M__Fj53-cJaBnZZASd-aMTaSyWEQ-PC2",
last_event: {"ixn", 8, "EDxDCjQoH82EgDEcSAU1SD__VKoebRUgr95nFweJxMgu"}
}
},
recoveries: []
}, 17}-
Install
Elixiras outlined above -
Install livebook
If you are not familiar with it,
livebookis analogous to the Python's Jupiter Notebook -
From the root directory of the
Kerilexrepo startiexas follows:iex --name kerilex@127.0.0.1 --cookie demo -S mix
-
Start
livebook -
Connect
livebookto the running node usingnameandcookieas parameters. -
open
experimental/demo/watcher.livemdfile.