rendezvous.gno
2.25 Kb · 64 lines
1package wesh
2
3import "encoding/binary"
4
5// DefaultRotationInterval is weshnet's rendezvous rotation period, in seconds
6// (rendezvous.DefaultRotationInterval = 24h). The rendezvous point an account
7// announces on changes once per interval, so an observer who learns one point
8// does not learn every future one.
9const DefaultRotationInterval int64 = 86400
10
11// RoundPeriod returns the start of the rotation period containing unixSec.
12// Mirrors weshnet's rendezvous.RoundTimePeriod.
13func RoundPeriod(unixSec, interval int64) int64 {
14 if interval < 0 {
15 interval = -interval
16 }
17 if interval == 0 {
18 panic("wesh: rotation interval must not be zero")
19 }
20 return (unixSec / interval) * interval
21}
22
23// NextPeriod returns the start of the period after the one containing unixSec.
24// Mirrors weshnet's rendezvous.NextTimePeriod.
25func NextPeriod(unixSec, interval int64) int64 {
26 if interval < 0 {
27 interval = -interval
28 }
29 return RoundPeriod(unixSec, interval) + interval
30}
31
32// RendezvousPoint derives the rotating DHT topic an account announces on
33// during the period starting at periodStart.
34//
35// It reproduces weshnet's rendezvous.GenerateRendezvousPointForPeriod exactly:
36//
37// HMAC-SHA256(key = topic ‖ seed, msg = big-endian uint64(periodStart))
38//
39// For contact requests, weshnet passes the account public key as the topic and
40// the public rendezvous seed as the seed (see swiper.WatchTopic in
41// contact_request_manager.go), which is what [Contact.RendezvousPointAt] does.
42//
43// Deriving this on chain is what makes a published identity checkable: anyone
44// can confirm that the seed in the directory really is the one the account is
45// announcing under, without trusting the directory.
46func RendezvousPoint(topic, seed []byte, periodStart int64) []byte {
47 key := make([]byte, 0, len(topic)+len(seed))
48 key = append(key, topic...)
49 key = append(key, seed...)
50
51 buf := make([]byte, 8)
52 binary.BigEndian.PutUint64(buf, uint64(periodStart))
53
54 return HMACSHA256(key, buf)
55}
56
57// RendezvousPointAt returns the contact's rendezvous point for the rotation
58// period containing unixSec.
59func (c Contact) RendezvousPointAt(unixSec, interval int64) ([]byte, error) {
60 if err := c.Validate(); err != nil {
61 return nil, err
62 }
63 return RendezvousPoint(c.AccountPK, c.Seed, RoundPeriod(unixSec, interval)), nil
64}