diff --git a/chord/id.go b/chord/id.go new file mode 100644 index 0000000..59480c2 --- /dev/null +++ b/chord/id.go @@ -0,0 +1,44 @@ +package chord + +import ( + "bytes" + "crypto/sha1" + "net/netip" +) + +type ID [20]byte + +func addrID(addr netip.AddrPort) ID { + if !addr.IsValid() { + return ID{} + } + b := make([]byte, 0, len("[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%enp5s0]:65535")) + b = addr.AppendTo(b) + return keyID(b) +} + +func keyID[T string | []byte](key T) ID { + s := sha1.Sum([]byte(key)) + return s +} + +// contains reports whether a clockwise traversal through the hash space +// starting immediately after left reaches x no later than it reaches right. +func contains(left, right, x ID) bool { + lr := bytes.Compare(left[:], right[:]) + lx := bytes.Compare(left[:], x[:]) + xr := bytes.Compare(x[:], right[:]) + switch { + case lr < 0: + // left is less than right, so the interval does not cross the origin. + // | L-----R | + return (lx < 0) == (xr <= 0) + case lr > 0: + // The interval crosses the origin. + // |-----R L-----| + return (lx < 0) != (xr <= 0) + default: + // The interval is the entire hash space. + return true + } +} diff --git a/chord/id_test.go b/chord/id_test.go new file mode 100644 index 0000000..c55019c --- /dev/null +++ b/chord/id_test.go @@ -0,0 +1,30 @@ +package chord + +import "testing" + +func TestContains(t *testing.T) { + true := [][3]ID{ + {{1}, {1}, {0}}, + {{1}, {1}, {1}}, + {{1}, {1}, {2}}, + {{1}, {2}, {2}}, + {{1}, {3}, {2}}, + {{3}, {1}, {1}}, + {{3}, {1}, {0}}, + } + false := [][3]ID{ + {{1}, {2}, {0}}, + {{1}, {2}, {3}}, + {{3}, {1}, {2}}, + } + for _, c := range true { + if !contains(c[0], c[1], c[2]) { + t.Errorf("%02x not found inside %02x - %02x", c[2], c[0], c[1]) + } + } + for _, c := range false { + if contains(c[0], c[1], c[2]) { + t.Errorf("%02x found inside %02x - %02x", c[2], c[0], c[1]) + } + } +}