rendezvous_test.gno
3.41 Kb · 103 lines
1package wesh
2
3import (
4 "encoding/hex"
5 "testing"
6
7 "gno.land/p/nt/uassert/v0"
8)
9
10// Reference vectors produced by running weshnet's own algorithm
11// (rendezvous.GenerateRendezvousPointForPeriod) against these inputs:
12// topic = accountPK, seed = seed, interval = 24h.
13const (
14 testAccountPKHex = "2152f8d19b791d24453242e15f2eab6cb7cffa7b6a5ed30097960e069881db12"
15 testSeedHex = "abababababababababababababababababababababababababababababababab"
16)
17
18func TestRoundPeriod(t *testing.T) {
19 cases := []struct {
20 name string
21 unixSec int64
22 interval int64
23 want int64
24 }{
25 {"epoch", 0, DefaultRotationInterval, 0},
26 {"exactly on a boundary", 1789171200, DefaultRotationInterval, 1789171200},
27 {"one second before the next", 1789257599, DefaultRotationInterval, 1789171200},
28 {"one second after a boundary", 1789171201, DefaultRotationInterval, 1789171200},
29 {"a negative interval is taken as positive", 1789257599, -DefaultRotationInterval, 1789171200},
30 {"an hourly interval", 1789174800 + 59, 3600, 1789174800},
31 }
32 for _, tc := range cases {
33 uassert.Equal(t, tc.want, RoundPeriod(tc.unixSec, tc.interval), tc.name)
34 }
35}
36
37func TestNextPeriod(t *testing.T) {
38 uassert.Equal(t, int64(1789257600), NextPeriod(1789171200, DefaultRotationInterval))
39 uassert.Equal(t, int64(1789257600), NextPeriod(1789257599, DefaultRotationInterval))
40}
41
42// TestRendezvousPointMatchesWeshnet pins the derivation against vectors
43// computed with weshnet's implementation. A divergence here means a gno-derived
44// rendezvous point would not match the one the account actually announces on,
45// which makes a published identity unverifiable.
46func TestRendezvousPointMatchesWeshnet(t *testing.T) {
47 pk := mustHex(t, testAccountPKHex)
48 seed := mustHex(t, testSeedHex)
49
50 cases := []struct {
51 name string
52 periodStart int64
53 want string
54 }{
55 {
56 "period 0",
57 0,
58 "04500fdede2a684f4e61cd67968b46ecdbf10d45604041bb7e0350572b8cc9cc",
59 },
60 {
61 "period starting 1789171200",
62 1789171200,
63 "aad2926c39dacabaabbbde48522d043557c8945b6a2dc7b08499c112c72587da",
64 },
65 }
66 for _, tc := range cases {
67 got := hex.EncodeToString(RendezvousPoint(pk, seed, tc.periodStart))
68 uassert.Equal(t, tc.want, got, tc.name)
69 }
70}
71
72// TestRendezvousPointAtIsStableWithinAPeriod is the property that makes
73// rotation useful: every instant inside one interval maps to the same point,
74// and the next interval maps somewhere unrelated.
75func TestRendezvousPointAtIsStableWithinAPeriod(t *testing.T) {
76 c := Contact{AccountPK: mustHex(t, testAccountPKHex), Seed: mustHex(t, testSeedHex)}
77
78 start, err := c.RendezvousPointAt(1789171200, DefaultRotationInterval)
79 uassert.NoError(t, err)
80 end, err := c.RendezvousPointAt(1789257599, DefaultRotationInterval)
81 uassert.NoError(t, err)
82 next, err := c.RendezvousPointAt(1789257600, DefaultRotationInterval)
83 uassert.NoError(t, err)
84
85 uassert.Equal(t, hex.EncodeToString(start), hex.EncodeToString(end),
86 "the point is stable for the whole period")
87 uassert.False(t, hex.EncodeToString(start) == hex.EncodeToString(next),
88 "the point rotates at the period boundary")
89}
90
91func TestRendezvousPointAtRejectsAnInvalidContact(t *testing.T) {
92 _, err := Contact{AccountPK: repeat(1, 32), Seed: repeat(2, 31)}.RendezvousPointAt(0, DefaultRotationInterval)
93 uassert.ErrorIs(t, err, ErrBadSeedLen)
94}
95
96func mustHex(t *testing.T, s string) []byte {
97 t.Helper()
98 b, err := hex.DecodeString(s)
99 if err != nil {
100 t.Fatalf("bad hex fixture: %v", err)
101 }
102 return b
103}