Commit Graph

58 Commits

Author SHA1 Message Date
Kgothatso Ngako
3995cdefc6 feat: run a ChillDKG ritual over a NIP-17 group
Robust groups can now generate a FROST threshold key together. The
group's members are the participants, the room's creator is the
coordinator, and the whole protocol travels as gift-wrapped rumors on
the chat the group already has -- so there is no second transport to
build, operate or debug.

This is what the quorum has been reaching for since it was introduced.
Until now "t of n must approve" had no key to approve anything with;
ChillDKG produces one that no single member holds.

## Transport: seven rumor kinds (nostr/dkg/)

    coordinator --[ 30310 proposal      ]-> everyone
    participant --[ 30311 host key      ]-> everyone
    participant --[ 30312 round 1       ]-> everyone   ParticipantMsg1
    coordinator --[ 30313 coord round 1 ]-> everyone   CoordinatorMsg1
    participant --[ 30314 round 2       ]-> everyone   ParticipantMsg2
    coordinator --[ 30315 certificate   ]-> everyone   CoordinatorMsg2
    anyone      --[ 30316 failure       ]-> everyone   abort + reason

These only ever exist inside a NIP-17 gift wrap, so no relay sees them
unencrypted and the replaceable semantics normally implied by the 3xxxx
range never apply -- which is why they can sit next to the app's other
private kinds (30300-30309) without meaning anything different.

Every message is addressed to the whole group, even the two the protocol
only needs the coordinator to read. NIP-17 wraps per recipient anyway,
ChillDKG treats the coordinator as untrusted by construction, and having
every member observe the ritual is what makes a progress UI possible
without a side channel.

`DkgSessionIdTag` is on every message: a group may abandon an attempt and
start another, and a straggler from the dead one must be dropped rather
than mixed into the live session. `DkgThresholdTag` rides the proposal so
every participant validates the same SessionParams -- disagreement on `t`
fails the session instead of quietly producing a weaker key.

## Persistence: inputs, not state (database/model/Dkg*, schema v2)

DkgSession deliberately stores no protocol state. Reading EncPedPop
confirms randomness enters the participant steps only through the passed
`random`/`auxRand` arguments (`simplSeed = taggedHash("encpedpop seed",
seed + random + encContext)`), so every ChillDkg step is a pure function
of inputs. Keeping the two 32-byte randoms plus the received messages is
therefore enough to recompute any intermediate state on demand, and the
opaque ParticipantState/CoordinatorState objects -- which have no
serialization API -- never need to be persisted at all.

That is not a micro-optimisation. A DKG cannot finish unless all n
members take part, and chat users close apps mid-round; recomputation is
what lets a ritual resume instead of forcing the group to start over.

DkgParticipantMessage is keyed (sessionId, participantPublicKey, kind) so
a redelivered message overwrites rather than accumulates -- relays
redeliver, and a duplicated round-1 message would hand the coordinator a
participant list of the wrong length.

Database goes to version 2 with an AutoMigration: v2 only adds tables, so
Room generates it. Schema 2.json is exported alongside.

## Driving it (managers/ChillDkgRitualManager.kt)

State machine driven entirely by arriving messages: persist, then ask
whether the ritual can move. Because every step is recomputable there is
no long-lived session in memory to lose, and processing is idempotent --
a redelivered message re-runs a step that has already been taken and
changes nothing.

The coordinator is a participant too, so it records its own outbound
messages locally: its round-1 message has to be in its own aggregation
alongside everyone else's. Being the room's creator buys it no authority
here -- ChillDKG's coordinator relays but cannot learn secrets or bias
the key -- only the job of aggregating.

Two decisions worth knowing:

* Host keys are DERIVED, not reused. `sha256("mantra/chilldkg/host-key/v1"
  || nostrSeckey)`. Reusing the nostr identity key directly was the
  simpler option, but one secret serving two protocols means a flaw in
  either reaches the other. Deriving from the same seed keeps it
  recoverable from the wallet backup, which matters because ChillDKG
  needs the host secret key to recover a session's outputs and asking
  chat users to back up a second secret is how keys get lost.
* Participant order is a bytewise sort of the host public keys. ChillDKG
  fails outright if participants disagree on ordering, and a sort is the
  only order every device can derive independently from the same set.

Any ChillDkg exception ends the session for this device and is broadcast
as a 30316 so the rest of the group stops waiting, rather than leaving
every member on a spinner that will never resolve.

## Inbound (database/dao/NostrDao.kt)

One branch on the existing decrypted-gift-wrap dispatch, beside the
kind-14 and WelcomeEvent branches, handing ritual kinds to the manager.

## UI (ui/.../DkgRitualScreen.kt + view model, state, route)

Reached from chat room detail via "Shared Key", shown only for rooms with
no MLS state -- i.e. the NIP-17/robust ones. An MLS room has a single
admin and no group key to share, so the entry point would be a lie there.

The screen is a ladder of rounds with real counts ("3 of 5") rather than
a spinner. The unusual thing about a DKG, and the thing the UI has to get
across, is that it needs *everyone* at once; a count says who it is
waiting on, an indeterminate spinner says nothing. The coordinator gets
the start button, everyone else is told who they are waiting for, and a
failed ritual states plainly that no key was created and it is safe to
run again.

DkgSession.threshold finally gives the quorum somewhere to live. The
value chosen during group creation is still not persisted on ChatRoom,
so this screen re-asks with the same majority default rather than
inventing a different one; there is a TODO where that gap closes.

Verified:
  ./gradlew :composeApp:compileCommonMainKotlinMetadata
  ./gradlew :composeApp:compileDebugKotlinAndroid

Not runtime-verified: exercising a DKG needs several devices exchanging
live messages, and the library's own vector suite needs JDK 21.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-29 19:15:17 +02:00
Kgothatso Ngako
3a830d77d6 Add chat room id on mantra tables 2026-07-19 21:08:44 +02:00
Kgothatso Ngako
3640a77413 Add more associations 2026-07-19 20:58:11 +02:00
Kgothatso Ngako
03c3e56b26 Bug fix for translationChapter primary key 2026-07-19 19:49:07 +02:00
Kgothatso Ngako
ab4d24282d Add mantra models 2026-07-15 22:39:01 +02:00
Kgothatso Ngako
6cdddee424 Rename TorchDatabase to MantraDatabase 2026-07-15 01:19:53 +02:00
Kgothatso Ngako
1bf3ec32ac Process group member changes on commit 2026-07-14 00:31:13 +02:00
Kgothatso Ngako
f53b407e58 Add description to chat room 2026-07-12 21:49:59 +02:00
Kgothatso Ngako
c39b26c2e1 Bug fix for resyncing 2026-07-08 21:19:02 +02:00
Kgothatso Ngako
44f2e7c814 Add signature on MarmotGroupEvent 2026-07-08 20:20:04 +02:00
Kgothatso Ngako
06c726c543 Rename to nostrGroupId and add MarmotCommitResult 2026-07-06 17:03:48 +02:00
Kgothatso Ngako
e175c601d7 Bug fixes 2026-07-04 01:33:06 +02:00
Kgothatso Ngako
bbe77936ed Implement marmot ingestion 2026-07-03 15:02:31 +02:00
Kgothatso Ngako
aad97bdd9e Add deterministic id on MLS related models 2026-07-01 20:27:05 +02:00
Kgothatso Ngako
c47751ad55 Fix to get it to build 2026-06-23 13:59:17 +02:00
Kgothatso Ngako
0f8ee65033 Bug fix on marmot keypackage bundle (Buggy nsec) 2026-06-22 22:30:39 +02:00
Kgothatso Ngako
94723eca6a Pass through the marmot repository 2026-06-19 11:03:38 +03:00
Kgothatso Ngako
ef92a33f56 Bug fix on room creation 2026-06-18 17:54:09 +03:00
Kgothatso Ngako
ffd6450c3b Remove aux DB 2026-06-17 19:02:40 +03:00
Kgothatso Ngako
d20b69a749 Clean up the feed 2026-06-17 19:02:24 +03:00
Kgothatso Ngako
b8ca6b3419 Set receipt for synced messages 2026-06-06 04:35:43 +02:00
Kgothatso Ngako
f3c7e21fa3 Also send a giftWrapMessage to self for message history 2026-06-06 04:25:53 +02:00
Kgothatso Ngako
d140d1a917 Relay hints for chat participants 2026-06-04 14:53:58 +02:00
Kgothatso Ngako
ff7fe8bc4b Add chatMessage relations 2026-06-03 02:57:36 +02:00
Kgothatso Ngako
62582e7569 Introduce giftwrap work flow 2026-06-03 01:14:49 +02:00
Kgothatso Ngako
29f4df66f2 Message formatting 2026-06-02 01:59:00 +02:00
Kgothatso Ngako
29ec692fc4 getOrCreateChat using publicKey 2026-06-01 00:42:48 +02:00
Kgothatso Ngako
c8ba6a0bf0 Foundation for getOrCreate chat room 2026-05-31 20:29:09 +02:00
Kgothatso Ngako
7041fefbbd Add chatroom functionality 2026-05-18 22:52:09 +02:00
Kgothatso Ngako
b604751ab4 Add chat database models 2026-05-18 16:19:36 +02:00
Kgothatso Ngako
58a98f68ae Feed syncs events from twelveHours 2026-05-05 20:14:11 +02:00
Kgothatso Ngako
bbb9d18500 Improve sync 2026-05-05 13:37:38 +02:00
Kgothatso Ngako
2bdb5bc3bf Save nostrEventRelay association 2026-05-04 22:29:22 +02:00
Kgothatso Ngako
e8a42b0123 Introduce foundation for negentropy logic. 2026-05-04 18:12:11 +02:00
Kgothatso Ngako
b9cece869e Change how mentions are handled 2026-05-02 01:19:28 +02:00
Kgothatso Ngako
be3f4390ff Setting up relations 2026-04-30 18:43:18 +02:00
Kgothatso Ngako
c99e3a31c2 Add specific associations on quoted/repost/inreply to 2026-04-28 02:22:29 +02:00
Kgothatso Ngako
23aaa13199 Improve sync logic. 2026-04-22 22:31:03 +02:00
Kgothatso Ngako
2b693b832a Add connection/following/followers db model. 2026-04-22 02:55:22 +02:00
Kgothatso Ngako
4a2ddbc4f2 Correct the namespace and introduce an android specific namespace 2026-04-21 23:46:45 +02:00
Kgothatso Ngako
76858f9cf0 Add primal RelaySocketManager 2026-04-18 02:41:31 +02:00
Kgothatso Ngako
36facaf6a7 Show recent searches from local input 2026-04-02 00:18:29 +02:00
Kgothatso Ngako
b3b93008e5 Prep to show loading on pending sync 2026-04-01 01:47:24 +02:00
Kgothatso Ngako
b01088a74f Sync taggedEvent + taggedAuthor... 2026-03-31 21:01:11 +02:00
Kgothatso Ngako
c3c92d96ad Introduce taggedEvent + taggedAuthor... 2026-03-31 19:48:09 +02:00
Kgothatso Ngako
c1d7572d44 Handling reposts 2026-03-31 16:13:44 +02:00
Kgothatso Ngako
3cefeae5c1 Handle notifications and syncing 2026-03-31 14:29:11 +02:00
Kgothatso Ngako
2beed5e18a Have FilterArray.kt in persisted sync event 2026-03-31 13:44:45 +02:00
Kgothatso Ngako
4e23206537 Increase account creation functionality. 2026-03-30 20:38:01 +02:00
Kgothatso Ngako
63c2530075 Bug fix on infinite sync 2026-03-30 01:17:44 +02:00