This is the basic protocol data structure. Each entity is represented by a rootkey. A rootkey is an ECDSA signing key using secp256k1 curve. For now, the rootkey can be either a zkID controller key or an Ethereum address prefixed with did:zk:.
This is an example of a root key: did:zk:0x2F460e375d0C657CfAeF5f486bA72A989ee4A506.
We borrow the event data structure from the Nostr protocol. The event data structure will be modified to use Keccak256 hash for event id calculation. An example event looks like this.
{
"id": <32-bytes lowercase hex-encoded keccak256 of the the serialized event data>
"rootkey": <rootkey of the event creator>,
"created_at": <unix timestamp in seconds>,
"kind": <integer>,
"tags": [
["e", <32-bytes hex of the id of another event>],
["r", <rootkey of an entity>],
... // other kinds of tags may be included later
],
"content": <arbitrary string>,
"sig": <signature using ECDSA on the keccak256 hash of the serialized event data, not the same as the "id" field.>,
"protocol": "eth-nostr"
}
To obtain the event.id, we keccak256 the serialized event. The serialization is done over the UTF-8 JSON-serialized string (with no white space or line breaks) of the following structure:
[
0,
<rootkey, as a (lowercase) hex string>,
<created_at, as a number>,
<kind, as a number>,
<tags, as an array of arrays of non-null strings>,
<content, as a string>
]
IMPORTANT: the contents to be signed is different from the id field as done in Nostr. We follow the EIP-191 standard and use the personal_sign method for event signature. This way, users can use a regular Ethereum wallet such as Metamask to sign the event message. The content to be signed for each event is:
"\x19Ethereum Signed Message:\n" + len(message) + event.id