Key Event Receipt Infrastructure - the spec and implementation of the KERI protocol
KERI’s rotation mechanism involves committing to the next Key Configuration while you rotate from the previous Configuration to the current Configuration. This commitment is a digest of the Configuration, such that the Public Keys in the Configuration are hidden. Finally, the Rotation event which changes these keys must be signed by the keys which were previously in the commitment and are now revealed in the event. This Pre-Rotation scheme is designed to:
The Key Configuration used to generate nxt
consists of two elements:
sith
: integer or set of integers describing how many signatures are required from keys in the set, for Events to be considered properly signed, serialized as a plain hex string.keys
): the set of Public Keys used to verify the signatures on Events, serialized in fully-qualified prefix form.Example:
{
"sith": "2",
"keys": [
"BrHLayDN-mXKv62DAjFLX1_Y5yEUe0vA9YPe_ihiKYHE",
"BujP_71bmWFVcvFmkE9uS8BTZ54GIstZ20nj_UloF8Rk",
"B8T4xkb8En6o0Uo5ZImco1_08gT5zcYnXzizUPVNzicw"
]
}
In order to commit to the configuration, each of the elements must be combined in a cryptographic digest. The process for this is as follows:
D
from the set of self-addressing derivation methodssith
integer as a hex string (lower-case, no leading zeros or 0x
)keys
in their serialized prefix formsith_d
from D(sith)
key_n
in keys
, get key_n_d
from D(key_n)
to create the set of digests digests
sith_d
and each element d
in digests
, get the raw bytes of the digest (without the derivation code) and XOR them all together to make xor_raw
xor_raw
to base64 URL safe form without padding and prepend the derivation code of D
In contrast to a simple concatenate-and-digest approach, the XOR method has two advantages:
nxt
commitment without being intercepted, as they can be hashed and concealed prior to transmission.The following example shows the nxt creation process in Python:.
sith = 2
keys = ['BrHLayDN-mXKv62DAjFLX1_Y5yEUe0vA9YPe_ihiKYHE',
'BujP_71bmWFVcvFmkE9uS8BTZ54GIstZ20nj_UloF8Rk',
'B8T4xkb8En6o0Uo5ZImco1_08gT5zcYnXzizUPVNzicw']
# convert sith to hex string no leading zeros
sith = '2'
# Blake3_256 sith digest, fully qualified prefix form
sithdig = 'EgT6bcpFB5_OFr6Ci0N8-bDeJ5Cf_5K7vVmpWW8jy_j0'
# raw binary unqualified in string escaped form
sithdig == b"\x81>\x9br\x91A\xe7\xf3\x85\xaf\xa0\xa2\xd0\xdf>l7\x89\xe4'\xff\xe4\xae\xefVjV[\xc8\xf2\xfe="
# convert keys to digests
# fully qualified Base64 digests
keydigs == ['EmB26yMzroICh-opKNdkYyP000kwevU18WQI95JaJDjY',
'EO4CXp8gs0yJg1fFhJLs5hH6neqJwhFEY7vrJEdPe87I',
'ELWWZEyBpjrfM1UU0n31KIyIXllrCoLEOI5UHD9x7WxI']
# raw binary (unqualifed) digests in string escaped form
keydigs =[b'\x98\x1d\xba\xc8\xcc\xeb\xa0\x80\xa1\xfa\x8aJ5\xd9\x18\xc8\xfd4\xd2L\x1e\xbdM|Y\x02=\xe4\x96\x89\x0e6',
b';\x80\x97\xa7\xc8,\xd3"`\xd5\xf1a$\xbb9\x84~\xa7z\xa2p\x84Q\x18\xee\xfa\xc9\x11\xd3\xde\xf3\xb2',
b'-e\x99\x13 i\x8e\xb7\xcc\xd5E4\x9f}J#"\x17\x96Z\xc2\xa0\xb1\x0e#\x95\x07\x0f\xdc{[\x12']
# now combine with XOR the raw versions of all four digests, sith plus three keys. In python must first convert to integers in order to use XOR = ^
raw = sithdig ^ keydig[0] ^ keydig[1] ^ keydig[2]
# now convert raw to fully qualified with derivation code for the digest algorithm
# in this case Blake3_256
nxt = 'E' + base64(raw)
assert nxt = 'ED8YvDrXvGuaIVZ69XsBVA5YN2pNTfQOFwgeloVHeWKs'