UpveraTechnology
UTR-26-11Research noteLive

Roots, not numbers

Upvera publishes its proof to show integrity without showing volume: each day file commits to every block sealed that day through a single root, and no public file carries a count, a name or a single private action.

Published
Updated
Reading
6 min
Plain text
/research/roots-not-numbers.md

#The tension

A public record of activity has two jobs that pull against each other. It has to be checkable by anyone, so that the platform cannot quietly rewrite its past. And it is made of what people did, and of how much a business is doing, which are not things to hand to the world.

The tension is sharper because of where the record goes. Upvera's day roots are committed to a public repository that blocks force pushes and deletions, and each one is timestamped with OpenTimestamps. What is written there stays, so every field had to be safe to publish forever, for every day and every person.

Almost nothing passes that test. What remains is roots.

#What a day file holds

A day file is canonical JSON (RFC 8785) with eight fields, and every one of them is a digest, a date, a type tag or a version:

Field What it is
t, v the record type and format version
day the UTC date
prev the digest of the previous day's file, so the days form a chain
root the Merkle root of the day's block digests
tip the digest of the day's last block
checkpoint a digest over every UPV balance at the end of the day
rules_hash the head of the rule registry at the end of the day

The live file is shown on the Day Roots report, byte for byte as it sits in the repository.

What is missing is deliberate. There is no number of blocks, no number of events and no number of UPV movements. A block count looks harmless, but it tracks how active a day was. A running total of events or movements would be worse: the difference between two days would become a permanent public series of how busy Upvera is, written to a channel that cannot be withdrawn. A file with counts would describe the business, not the record.

Integrity does not suffer. The root commits to every block of the day, and each block commits to every entry it sealed. Change one entry and its block digest changes, the day's root no longer matches, and every later prev breaks.

#Leaves built to be shown

The entries inside a block, its leaves, never go to the public channel. They are still built as if they might be shown, because a personal proof opens one of them to its owner, and a leaf that is safe to show is safe to keep.

  • Scoped aliases instead of people. The actor of an event is written as an HMAC of the person's reference and a scope, under a key Upvera holds. Within one startup the same person always has the same alias, so distinct supporters of that startup can be told apart. Across startups the aliases are unrelated, so one person's activity cannot be linked from startup to startup. A person's account identifier never enters a leaf.
  • Time to the minute. A leaf states the minute an event was observed. The exact moment, along with signature fields and other private details, is bound into a salted commitment: it is fixed and cannot change later, and only its owner is given the opening.
  • Salted contents. A plain digest of a small payload is easy to reverse by guessing. With two possible reactions to a known post, anyone could hash both and see which one matches. So a leaf carries a salted commitment to the payload, never the bare digest. Salts are derived from a secret key per event and are opened only to the event's owner.
  • Nothing to guess between siblings. Event identifiers are random, so the neighbouring digests that appear in someone's proof cannot be resolved by trying likely inputs.
  • One label per kind of object. Leaves, tree nodes, blocks and days are each hashed under their own label, so a digest of one kind of object can never be passed off as another. The tree follows the shape defined in RFC 6962 and kept in its successor, RFC 9162.

#Private activity

Some kinds of activity are private: views, saves and similar actions that say more about a person than about a startup. They are sealed into blocks like everything else, so the day's root commits to them too, and they cannot be added or removed later without breaking it. But no proof of a single private action is issued to anyone, and in public they appear only as counts that cover at least five people.

Some open kinds carry a private value. A Pass is seen only by the person who gave it, and no proof is issued for it.

#Headers stay inside

A block header says more than it seems to. Read in sequence, headers would add up to a minute-by-minute series of activity and UPV movements. So block headers are not published, and a personal proof carries only what is needed to check that one entry, only for closed days and in limited number.

#Erasure without breaking the chain

Because a leaf holds a salted commitment rather than the content itself, content can be removed without touching the leaf. When an account is deleted, everything that links the record to that person is removed. The leaves never held the person's identity, only an alias, so they stay exactly as they were, and every root that commits to them still verifies.

This is the reason the design separates what is sealed from what is shown. A record that sealed raw content would face a hard choice when someone asks to be forgotten: keep the content, or break the chain. This record does not have to choose.

#What each person can prove

On app.upvera.co, under Settings › Security › Proofs, a person can take a proof that one of their own open actions sits inside a closed day. The proof carries the leaf, its opening and the path up to the day. The verifier at upvera.co/dogrula, compiled to WebAssembly, fetches the day file from the public repository and checks the proof in the browser.

A proof about following another person does not name that person; it carries only what lets you recognize your own entry. Proofs of UPV receipts open only the person's own entries, are shown only inside the app and are not checked on the public page.

#Who checks the rest

Anyone can check three things: that the chain of day files is intact from genesis, that each file was timestamped when it says it was, and, for their own actions, that the action is inside a sealed day.

What the public cannot check is completeness: that every entry made it into a block. That needs the leaves, which stay private. Inside Upvera, an hourly watcher checks that every entry in a sealed range became a leaf and recomputes recent blocks from their sources, and an independent verifier with no database access recomputes the blocks and days from a locked copy. Both are Upvera's own. That is the balance this design strikes: the public gets integrity and personal inclusion, and the counts stay out of the public record.

#Limits

  • The aliases protect people from the public, not from Upvera, which holds the key.
  • Private actions cannot be proven individually, even by the person who took them.
  • A root proves that what was sealed has not changed. On its own, it does not prove that everything was sealed.
  • A timestamp proves that a file existed by a certain time. It says nothing about whether its contents are true.

#References