Files and formats
The kinds of file the app and the command line read and write. Versioned formats carry their version inside the file.
Entries
An entry is a canonical JSON object with exactly seven members:
| Member | Content |
|---|---|
spec | The spec name, zikaron/1 |
entryType | The type: genesis, history, grant, revocation, adoption, succession, annotation, or any agreed new type |
author | The author’s address, in lowercase hexadecimal |
seq | The sequence number, from 0 |
prev | The ID of the entry before; null for the first |
body | The body, by type |
sig | A 65-byte EIP-191 signature |
An entry’s ID is the SHA-256 of all its bytes. The canonical form: compact, members sorted by bytes, integers in decimal, hexadecimal always lowercase. See law §3 and §4.
The command line’s ledger folder
A plain folder with one file per entry, each named with the entry ID’s 64 hexadecimal digits plus .entry. This is the folder zikaron reads and writes.
The machine folder
One per machine. Its default location is ~/.zikaron-desk.d/; the pointer file ~/.zikaron-desk can point it elsewhere: one line holding an absolute path, ending in a newline, with mode 0600. Where an earlier version kept it at ~/Library/Application Support/ZIKARON, the app keeps using that folder and migrates once.
| File | Content |
|---|---|
keys-anchor.json | The key store, format zikaron-desk/keybox/3, mode 0600; the wrong-try count is kept here too |
identities-anchor.json | The identity registry, encrypted |
machine.json | Machine settings, format zikaron-desk/machine/1, plain, read before unlocking |
kits/index.json | The record kit index, plain; see below |
records/index.json | File names and locations at signing, encrypted |
set-aside/ | Sealed files whose master key is gone, closed for good, kept byte for byte and numbered flat 1, 2, 3; when the folder exists, set-aside-2, -3 |
The machine folder is found from HOME. The app uses its own key store alone and leaves the system keychain as it is.
Data folders
One for each role of each identity, by default inside the machine folder, with the role subfolder author (Recorder) or grantee (User). Inside are four subfolders:
ledger/- The ledger, one encrypted file per entry.
kits/- Exported record kits, grant files, credentials and snapshots, and the terms files kept at signing (
kits/terms/). grants-held/- Received grants, each with the verdict of its last re-verification; grant files received are in
grants-held/files/. settings/- Settings
desk.json, the pending queuequeue.json, the last ledger checklast-audit.json, and the lockwriter.lockthat lets one window write.
Data folder names and the file names in the ledger are rewritten under a local names key, which keeps addresses and entry IDs out of the file names; contents are encrypted file by file. To let another tool read a ledger, export a ledger mirror.
Encryption of local data
The local data key is derived from the master key with HKDF-SHA256 (info string zikaron/local/v1), and the names key uses the info string zikaron/names/v1. Each file is encrypted on its own with XChaCha20-Poly1305:
"zikaron-local/1\n" · kind length (1 byte) · kind · version (u16 big-endian) · nonce (24 bytes) · ciphertext and tagEverything before the nonce is associated data, so a file is bound to its kind and format version. Writes go to a temporary file first, then rename into place.
The key store
The master key and each identity’s keys are sealed in keys-anchor.json: the passcode derives a key through scrypt (N=262144, r=8, p=1), encryption is AES-128-CTR, and a keccak MAC checks it. The passcode is 8 ASCII letters or digits; after 5 wrong tries in a row it locks, and recovery is the way on.
Whole-machine backups
File name zikaron-backup-YYYY-MM-DD.zikaron (UTC date); a second export on the same day is numbered -2, -3. The first line is zikaron-backup/1, and the second is a canonical JSON header: app, created, format, kdf (scrypt’s N, r, p and a 32-byte salt) and nonce. The body’s key is derived from the backup password with scrypt (N=262144, r=8, p=1), and the body is encrypted with XChaCha20-Poly1305, with the two header lines as associated data.
A backup holds the identity registry, each identity’s keys, every encrypted local file (opened, then placed inside), the record of the primary identity and machine.json. The master key, the passcode and the wrong-try count stay on the machine; plain exports (record kits, the index, credentials, grant files, mirrors, key files) stay outside the backup too.
Key files
A standard Ethereum keystore (V3): scrypt (N=262144, r=8, p=1) and aes-128-ctr, named UTC--<time>--<40-hex address>, mode 0600, encrypted with the file password set at export (at least 8 characters). After writing, the app reads it back and checks its format and address, and the export counts once they match.
Record kits
A folder whose format is set by zikaron.kit/1 §7:
kit-3fa9c2e1/
manifest.json the manifest
entries/<64 hex>.zk1 entries, one file each
files/<path> original files and attachments
files/verify.md verification notes for the receiver
proofs/<path> on-chain proofsThe manifest lists every entry’s ID, every file’s path, size and SHA-256, and the transaction behind each proof; a file in the kit outside the manifest fails the check. The kit ID is the SHA-256 of the manifest’s bytes. Paths inside a kit use a-z, 0-9, ., _ and - alone; when attachments were renamed, files/zikaron-names.json maps original names to kit names, and the rename rule is <rewritten name>-<first eight of the original name’s SHA-256>.<extension>.
The exported folder is named kit- plus the first eight characters of the content fingerprint of the chosen record with the lowest sequence number; when the choice holds other entries alone it is kit, and a taken name is numbered -2, -3.
The record kit index
kits/index.json in the machine folder, format name zikaron.kits-index/1, kept plain so that other apps on the same machine can read it; see Integration. Each exported kit gets one row, and exporting again to the same path replaces that row:
| Field | Content |
|---|---|
id | The kit ID |
created | The moment of export, in Unix seconds |
root | The ID of the ledger’s creation entry |
path | The kit’s absolute path |
contents | The content fingerprints of the originals in the kit |
note_md | The note |
link | The fetch address (the kit’s https address online), optional |
Grant codes and credentials
The text zikaron-grant: followed by one or more segments joined by .. Each segment is a grant entry’s canonical bytes in base64url, padding left off; with several segments, they run from the original author’s grant to the current one. The whole is capped at 2,953 bytes, exactly the capacity of one QR code (version 40, byte mode, error correction level L). The format is in zikaron.kit/1 §6.
A credential folder is named badge- plus the first ten characters of the grant ID; inside, badge.txt is the text as it is, and badge.svg is its QR code.
Grant files
Extension .zkgrant, named grant- plus the first ten characters of the grant ID. It is a container: the first line is zikaron-kit-file/1, and each item after it is written as “path in the kit, newline, decimal length, newline, bytes, newline”, the manifest first and the rest in byte order. It is capped at 64 MiB in all and 4096 items. Inside are:
manifest.json;entries/*.zk1: the entries of every hop in the grant chain, together with the issuer’s ledger when the grant is in this role’s ledger;files/zikaron-grant.txt(the grant code),files/terms/…(the terms files),files/verify.md, and optionallyfiles/publish.txt(the published address set in the data folder that exported the grant file).
Ledger mirrors
<chosen folder>/ZIKARON-backup/<40-hex address>/<author|grantee>/
mirror.json kind desk-mirror, version 1
entries/<64 hex> entry bytes, named by ID alone
held/<path> received grants and so onWhen the folder already holds an older mirror, only the new entries are added. To use it as the command line’s --ledger folder, copy the files in entries/ into an empty folder and add .entry to each file name.
Derivation paths
Agreed literals
bytes-sha256/1- The mark of how a record was made, one for files, folders and Git repositories alike, meaning the content fingerprint is the SHA-256 of a run of bytes. For a file, the bytes are the whole file; for a folder, the canonical JSON
{"files":[{"path":…,"sha256":…}…]}sorted by relative path (symbolic links and special files are skipped and counted, and an empty folder is refused); for a Git repository, the current commit object’s bytes without thecommit <length>\0header, the same asgit cat-file commit HEAD | shasum -a 256. Thetoolchainpaired with it is the SHA-256 of this literal itself:0xb7f3c4a226684d6da684b0ac82d36ed5bcba7bb61d09c955bff9437f84a52a4d. retraction- The type name of a deletion entry. In the body,
subjectis required: the ID of a record in this ledger,0xfollowed by 64 lowercase hexadecimal digits;note_mdis optional. Other tools list it as an unknown type (UNKNOWN_TYPE) and the ledger’s verdict stays as it was; this app’s reading lives inzikaron_glue::retraction, shared by the app and the command line. for- An extra member in a record’s body:
app,identity(hex20) andref, with an optionalseat. Once any of them is filled in, the first three are required. upstream- An extra member in a grant’s body, holding the ID of the upstream grant; zikaron.kit/1 reads it as a sublicense.