Fractal Social Hierarchy UTXO System with Universal Basic Income by Demurrage and One Person One Unit of Stake

A population register and a UTXO payment layer. The register is a social hierarchy: your superior attested your identity. The hierarchy maps onto existing civil registration — countries, municipalities, individuals — but supports any trust model, from tribal to national. Being registered gives you universal basic income, claimable as UTXO. Coins lose value continuously at ~1.7% per period (~20% per year). A person holding exactly 1 token neither gains nor loses — the UBI exactly compensates the demurrage. Each UTXO pays a small rent per slot for occupying state. The people vote for block validators. Each vote is a hash commitment. One vote is drawn randomly each block — the selected validator reveals the preimage, which seeds the random selection of the next. The secret votes prevent DoS attacks on block producers and provide the random number generator, all in one.


People Tree

Node

Node {
  node_id     hash            — permanent, SHA256(creator_id || creator_nonce); creator is parent (Add) or old root (Crown)
  owners      []pubkey        — max 8, who can sign for this node
  threshold   uint8           — number of signatures required
  leaf        bool
  child_trie  hash            — trie of children, keyed by node_id, value is H(Node)
  nonce       uint
  last_claim  uint            — last claimed period number
  count       uint            — person count (0 = org, 1 = person, N = group)
  tree_count  uint            — total persons in subtree
}

A node is a person, a group of persons, or an organization.

A person contributes 1 to count. A group represents multiple persons as a single node (contributes N, max 8). An org is a non-person entity (contributes 0 — no UBI). For persons and groups: count == len(owners) — one key per person. For persons: threshold = 1. For groups: threshold in 1..count. Orgs may have up to max_owners owners independently of count.

node_id = SHA256(creator_id || creator_nonce) is permanent and never changes. The creator is the parent (Add) or the old root (Crown). Operations reference nodes by node_id. Validators maintain an index from node_id to position in the tree. The genesis root's node_id is set at genesis.

tree_count is the total number of persons in the subtree, aggregated upward. Population = root.tree_count. A node's own person contribution is count.

leaf — if true, the node cannot have children. Set by the parent at creation.

H(Node) = SHA-256(node_id || owners || threshold || leaf || child_trie || nonce || last_claim || count || tree_count).

UBI

Each period, each person can claim a fixed UBI payment equal to the demurrage on one token:

UBIPerPeriod = TOKEN × DemurragePerPeriod = 1 700 000

A person holding exactly one token receives as much in UBI as they lose to demurrage — the system is neutral at one token per person.

A person claims UBIPerPeriod × contribution per period. A group of 5 claims 5×. An org: nothing.

Add

Add {
  parent_id   hash          — node_id of the parent
  nonce       uint            — parent's nonce
  owners      []pubkey        — new child's owners
  threshold   uint8
  leaf        bool
  count       uint
  sigs        []sig           — parent's owners sign (threshold)
}

Parent adds child. node_id = SHA256(parent_id || nonce). last_claim = current period. Increment parent's nonce. Recompute tree_count upward. The child can Leave if it does not accept its position.

Remove

Remove {
  parent_id   hash            — node_id of the parent
  child_id    hash            — node_id of the child to remove
  nonce       uint            — parent's nonce
  sigs        []sig           — parent's owners sign (threshold)
}

Child and its entire subtree are deleted from the tree. Increment parent's nonce. Recompute tree_count upward.

Move

Move {
  child_id    hash            — node_id of the child
  new_parent_id hash          — node_id of the new parent
  nonce       uint            — new parent's nonce
  deadline    uint
  consent     []sig           — child's owners sign (threshold): deadline + new_parent_id
  sigs        []sig           — new parent's owners sign (threshold)
}

Moves a child (and its entire subtree) from its current parent to a new parent. The child must not be the root. The new parent must not be the child itself or in the child's subtree — this prevents cycles. The old parent is looked up from the tree. State is preserved: last_claim, nonce, subtree — nothing is reset. Increment new parent's nonce. Recompute tree_count upward for both old and new parent.

Leave

Leave {
  child_id    hash            — node_id of the child
  nonce       uint            — child's nonce
  sigs        []sig           — child's owners sign (threshold)
}

Same as Remove but initiated by the child. The child must not be the root. The parent is looked up from the tree. Recompute tree_count upward.

Crown

Crown {
  old_root_id   hash
  old_root_nonce uint
  new_owners  []pubkey        — new root's owners
  new_thresh  uint8
  new_count   uint
  sigs        []sig           — current root signs (threshold)
}

Creates a new root above the current root. Only the current root can perform this. The new node's node_id = SHA256(old_root_id || old_root_nonce). The old root becomes a child of the new root. leaf = false. last_claim = current period. Increment old root's nonce. Recompute tree_count.

Rekey

Rekey {
  node_id     hash
  nonce       uint
  new_owners  []pubkey        — new owner set
  new_thresh  uint8           — new threshold
  sigs        []sig           — current owners sign (threshold)
}

Changes a node's owners and threshold. Constraints: len(new_owners) ≤ max_owners, 1 ≤ new_thresh ≤ len(new_owners). For persons and groups: len(new_owners) == count. For persons: new_thresh = 1. Increment nonce.


UTXO Layer

Output

Output {
  owners      []pubkey        — max 8, public keys (for sig verification)
  threshold   uint8           — number of signatures required
  amount      uint64
  slot        uint32          — slot at creation
}

Identified by (tx_hash, index) where tx_hash = SHA256(signing_message || sigs). Trie key: SHA256(tx_hash || index). This applies to all outputs: Transfer (index per output), Claim UBI and vote tokens (index per owner). Fee outputs use tx_hash = SHA256(number). Spent outputs are removed from the set.

Demurrage

Coins lose value continuously at 1.7% per period (~20% per year, half-life ~40 periods). The nominal amount stored in a coin entry never changes; its effective value is computed when the entry is used, from the number of slots elapsed since it was created:

t = current_slot − entry.slot
effective(entry) = decay(entry.amount, t)

decay is exponentiation by squaring. A single constant defines the curve — the per-slot factor in 63-bit fixed point, so that 40 320 slots retain 0.983 — and the powers 2^i are derived from it by repeated squaring at startup:

Decay[0]   = 9223368114598617273          — floor(2^63 × 0.983^(1 / SlotsPerPeriod))
Decay[i+1] = (Decay[i] × Decay[i]) >> 63     i = 0 .. 25

decay(amount, t):
    if t ≥ 2^27: return 0
    x = amount                        — 128-bit intermediate
    for i in 0 .. 26:
        if bit i of t is set:
            x = (x × Decay[i]) >> 63
    return x

Decay[i] is what a coin retains after 2^i slots; t written in binary selects which factors to multiply. All products fit in 128 bits. At most 27 multiplications per input, all integer, so every node computes the same value.

Rent

Each UTXO pays rent for occupying state. Rent is a fixed number of base units per slot since creation, using the same t as demurrage:

rent(entry) = t >> RentShift

A UTXO's spendable value is effective value minus accumulated rent (saturating at zero):

spendable(entry) = max(effective(entry) − rent(entry), 0)

The rate is one base unit per 1 024 slots (~17 hours), ~39 base units per period.

Pruning

An output is prunable when rent meets or exceeds its effective value:

prunable(entry) = rent(entry) >= effective(entry)

Pruning deletes the entry from the coin trie. Any remaining effective value is added to the block fee. Only the block's validator may include Prune operations.

A 1 UBI entry retains 80% after one year and 11% after ten; rent overtakes the remaining value after ~292 periods (~22 years).

Transfer

Transfer {
  inputs      []Outpoint
  outputs     []Output
  sigs        []sig           — one per input (threshold signatures for multisig)
}

Outpoint {
  tx          hash
  index       uint
}

Spends UTXOs and creates new ones. Each input is signed by its owners — different owners can participate in the same transaction.

Validation: each input exists and is unspent. Each output amount > 0. Sum of output amounts ≤ sum of input spendable values. Difference is the transaction fee.

Processing: remove spent inputs from the coin trie. Create new outputs with slot = current slot.

Fees

Transaction fees are accumulated during the block and split 50-50 between the validator and the voter (the selected election entry's trie key). Odd unit to validator. Fee UTXOs use tx_hash = SHA256(number), index 0 for validator, 1 for voter. Each fee UTXO is {owners: [address], threshold: 1, amount: share, slot: current_slot}. A fee UTXO is only created when its share is > 0.

Claim

Claim {
  node_id     hash
  nonce       uint
  sigs        []sig           — node's owners sign (threshold)
}

Claims UBI and vote tokens. Node must exist in the tree with count > 0. last_claim must be < current period. Mints one UBI UTXO per owner in coin_trie: {owners: [owners[i]], threshold: 1, amount: UBIPerPeriod, slot: current_slot}. Creates one election token per owner in token_trie, each {owner: owners[i], mixed: 0}. Owner *i* receives output index *i* in both tries: SHA256(tx_hash ‖ i). The tries are separate key spaces, so identical IDs do not collide. Sets last_claim to current period. Increments nonce. Allowed in both phases — tokens claimed after the lock are not usable for voting but UBI is unconditional.


Trie Construction

All tries (coin, election, token) are binary Merkle tries. Path navigation follows the key bit-by-bit, MSB first. Left child = 0, right child = 1.

Leaf hash:       SHA256(key || value), or SHA256(key) for entries without value
Branch hash:     SHA256(bit_position || left_hash || right_hash)
Empty trie root: [32]byte{0}

bit_position (uint8) is the key bit where the branch diverges. This commits the branch to its position in the trie, preventing proof providers from misrepresenting the trie structure.

The election trie branches include a count aggregate: SHA256(bit_position || count || left_hash || right_hash). All entries are committed, so count = total entries. Insert to a key that diverges from an existing leaf splices in a new branch at that bit position. Delete removes the leaf and collapses the parent if only one child remains.


Consensus

Block Production

Blocks are produced at fixed time intervals — one slot per interval. slot increments by 1 per slot interval; skipped slots leave gaps. time = genesis_time + slot × SlotSeconds. number increments by 1 per block. Each slot has one validator selected via the election trie.

If the selected candidate is offline, the slot is skipped and rand = H(prev_rand || 0) — same formula with a zero nonce. The same removal rule as selection applies: the entry is removed only if count > remaining_slots_in_period. Fork choice: the chain with the most blocks wins. Blocks before the previous period boundary are final — no reorg is accepted past that point.

The genesis header includes an election_trie[0] with at least one committed vote. This is sufficient for the initial validator to produce blocks until the population votes for the next.

Election

Validator selection operates in fixed-length periods of 4 weeks. Each period, vote tokens are claimed into token_trie, mixed for anonymity, and committed into election_trie[1]. At the end of the period, election_trie[1] rotates to election_trie[0] and election_trie[1] and token_trie are cleared. One entry is selected each block — its candidate validates that block.

Token Trie

Stores vote tokens, keyed by SHA256(tx_hash || index). Entry: {owner, mixed}. All tokens have amount=1. mixed starts at 0 from a Claim and increments with each mix. Claim creates entries here. Mix shuffles them. Vote consumes them into election_trie[1].

Election Trie

Each internal node carries the count of entries in its subtree. The root gives the total — the pool size for RNG selection.

Entries are keyed by the voter's address (the token owner after mixing). The value is a commit: H(validator || nonce). The commit hides which validator the voter chose until block production.

Mix

Shuffles vote tokens for anonymity. 1-to-1: number of inputs = number of outputs.

Inputs: existing entries in token_trie. One signature per input, by the entry's owner.

Outputs: {owner, mixed} back into token_trie. Constraint: each output's mixed is between 1 and max_mix. Constraint: sum(output mixed) ≥ sum(input mixed) + count(outputs).

Only allowed in the open phase.

Vote

Converts one token into a committed vote entry.

Vote {
  token       outpoint        — token in token_trie
  commit      hash            — H(validator || nonce)
  sig         sig             — signed by token's owner
}

Consumes the token from token_trie. Creates one entry in election_trie[1] keyed by token.owner with value commit.

Only allowed in the open phase.

The voter shares the nonce with the validator off-chain — the validator needs it to produce a block when the entry is selected. A zero nonce is technically possible but a random nonce is recommended for DoS protection. If the nonce is not shared, the slot is skipped.

Activation

Each period has two phases. In the first half, token_trie and election_trie[1] are open — tokens can be mixed and committed. At the midpoint, both lock. Claims (UBI + vote tokens) are allowed in both phases — late tokens simply cannot be used for voting. At the end of the period, election_trie[1] becomes election_trie[0], and election_trie[1] and token_trie are cleared.

The lock-to-activation gap ensures no one can predict which position the RNG will select.

Selection

rand mod count selects a position. The trie's cumulative sums enable traversal to the selected entry.

The selected entry's key is the voter (who receives half the fees). The validator reveals the preimage in the header: H(header.validator || header.nonce) == entry.commit. Since the commit hides which validator owns each slot, targeted DoS attacks on upcoming block producers are not possible. rand = H(prev_rand || header.nonce).

If count > remaining_slots_in_period, the entry is removed from the trie after selection. Otherwise, the entry stays — allowing it to be selected again. This ensures the pool never empties: at small populations, each person is selected multiple times; at large populations, entries are consumed and each person is selected at most once.

Header

Header {
  number        uint            — block count since genesis
  slot          uint            — slot number since genesis
  time          uint
  tx_trie       hash
  coin_trie     hash
  token_trie    hash
  election_trie [2]hash
  people_tree   hash
  rand          hash            — H(prev_rand ‖ nonce)
  prev          hash
  validator     pubkey
  nonce         hash            — election commit preimage
  sig           sig             — signed by validator
}

people_tree is the Merkle root of the node tree. coin_trie is the root of the coin trie. token_trie stores vote tokens. election_trie[0] is the active election trie. election_trie[1] is the next period's committed entries. tx_trie commits to the set of operations in the block — keyed by tx_hash = SHA256(serialized_operation). There is no transaction chaining: state changes made by one operation are not visible to another in the same block. All operations validate against pre-block state. At most one people tree operation per node per block. number starts at 0. time is deterministic from slot: each slot is SlotSeconds apart.


Civil Registration Compatibility

The tree structure maps onto existing population registration infrastructure. A country, region, municipality, or village can be an org node with its citizens as children. The hierarchy does not prescribe a specific administrative structure — any nesting of individuals, groups, and organizations works.


Governance

The root node controls the top of the people tree. Adding a new level above the root is done via Crown — the current root signs the operation and becomes a child of the new root. Replacing the root against its will is a social hard fork: participants agree off-chain, the people_tree root in the header is updated at a coordinated block height, and the chain continues. The majority chain retains the network's value. No on-chain governance mechanism is required.


Signing Messages

The opcode prefix prevents cross-operation replay. All fields are big-endian.

Transfer:        SHA256(0x00 || SHA256(inputs) || SHA256(outputs))
Mix:             SHA256(0x01 || SHA256(inputs) || SHA256(outputs))
Vote:            SHA256(0x02 || token_outpoint || commit)
Add:             SHA256(0x03 || parent_id || nonce || SHA256(owners) || threshold || leaf || count)
Remove:          SHA256(0x04 || parent_id || nonce || child_id)
Move (parent):   SHA256(0x05 || new_parent_id || nonce || child_id)
Move (consent):  SHA256(0x05 || new_parent_id || deadline || child_id)
Leave:           SHA256(0x06 || child_id || nonce)
Crown:           SHA256(0x07 || old_root_id || old_root_nonce || SHA256(new_owners) || new_thresh || new_count)
Rekey:           SHA256(0x08 || node_id || nonce || SHA256(new_owners) || new_thresh)
Claim:           SHA256(0x09 || node_id || nonce)

Unsigned operations:

Prune:           SHA256(0xFF || utxo_id)

Primitives

SHA-256, Ed25519. Amounts are unsigned 64-bit integers. All fields are big-endian. Variable-length fields are serialized with a uint8 length prefix. All signatures include an opcode.

Signatures in a Transfer are a flat list consumed per input in input order. Each input requires exactly threshold signatures, matched against that input's owners in ascending owner-index order. Duplicate owner matches or extra signatures are rejected.

ConstantValueDescription
TOKEN10^8Base units per token (8 decimals)
SlotsPerPeriod403204 weeks in minutes
SlotSeconds60Block interval in seconds
PeriodSeconds2419200SlotsPerPeriod × SlotSeconds
DemurragePerPeriod1.7%0.983 per period, ~20% per year
DecayShift63Fixed-point bits in decay()
Decay092233681145986172732^63 × 0.983^(1/SlotsPerPeriod)
UBIPerPeriod1700000TOKEN × DemurragePerPeriod
max_mix10Maximum mixing depth for vote tokens
max_owners8Maximum owners per Node or Output
MaxBlockSizeconsensusMaximum block size in bytes
RentShift10Rent = 1 base unit per 1 024 slots

period = slot / SlotsPerPeriod (integer division).