1package wesh23import "encoding/binary"45// DefaultRotationInterval is weshnet's rendezvous rotation period, in seconds6// (rendezvous.DefaultRotationInterval = 24h). The rendezvous point an account7// announces on changes once per interval, so an observer who learns one point8// does not learn every future one.9const DefaultRotationInterval int64 = 864001011// 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 = -interval16 }17 if interval == 0 {18 panic("wesh: rotation interval must not be zero")19 }20 return (unixSec / interval) * interval21}2223// 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 = -interval28 }29 return RoundPeriod(unixSec, interval) + interval30}3132// RendezvousPoint derives the rotating DHT topic an account announces on33// 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 and40// the public rendezvous seed as the seed (see swiper.WatchTopic in41// contact_request_manager.go), which is what [Contact.RendezvousPointAt] does.42//43// Deriving this on chain is what makes a published identity checkable: anyone44// can confirm that the seed in the directory really is the one the account is45// 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...)5051 buf := make([]byte, 8)52 binary.BigEndian.PutUint64(buf, uint64(periodStart))5354 return HMACSHA256(key, buf)55}5657// RendezvousPointAt returns the contact's rendezvous point for the rotation58// period containing unixSec.59func (c Contact) RendezvousPointAt(unixSec, interval int64) ([]byte, error) {60 if err := c.Validate(); err != nil {61 return nil, err62 }63 return RendezvousPoint(c.AccountPK, c.Seed, RoundPeriod(unixSec, interval)), nil64}65Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.