basis.go raw
1 package crypto
2
3 import (
4 "sort"
5
6 "git.mleku.dev/mleku/dendrite/pkg/lattice"
7 "git.mleku.dev/mleku/dendrite/pkg/ratio"
8 "git.mleku.dev/mleku/dendrite/pkg/spore"
9 )
10
11 // Basis is the public description of a lattice's constraint structure.
12 // It contains enough information to nucleate a lattice (encrypt)
13 // but not enough to read the bonding pattern (decrypt).
14 type Basis struct {
15 // Dimension is the number of constraint sites.
16 Dimension int
17
18 // Tags enumerates the constraint type tags in sorted order.
19 Tags []string
20
21 // Distribution records sites per tag.
22 Distribution []spore.TagCount
23
24 // Connectivity records average neighbor count per tag.
25 Connectivity []spore.TagRatio
26
27 // PermDist records how nodes distribute across S_3 permutations.
28 PermDist [6]int
29
30 // ProjDist records how nodes distribute across 64 projection configs.
31 ProjDist [64]int
32
33 // Modulus for any modular arithmetic.
34 Modulus ratio.Ratio
35 }
36
37 // FromLattice extracts the public basis from a live lattice.
38 func FromLattice(l *lattice.Lattice, modulus ratio.Ratio) *Basis {
39 s := spore.Extract(l)
40 return fromSporeInternal(s, modulus)
41 }
42
43 // FromSpore reconstructs a basis from a spore's fingerprint.
44 func FromSpore(s *spore.Spore, modulus ratio.Ratio) *Basis {
45 return fromSporeInternal(s, modulus)
46 }
47
48 func fromSporeInternal(s *spore.Spore, modulus ratio.Ratio) *Basis {
49 b := &Basis{
50 Dimension: s.TotalNodes,
51 Distribution: make([]spore.TagCount, len(s.TypeSignature)),
52 Connectivity: make([]spore.TagRatio, len(s.Connectivity)),
53 PermDist: s.PermDist,
54 ProjDist: s.ProjDist,
55 Modulus: modulus,
56 }
57
58 copy(b.Distribution, s.TypeSignature)
59 copy(b.Connectivity, s.Connectivity)
60
61 // Extract and sort tags.
62 tags := make([]string, len(s.TypeSignature))
63 for i, tc := range s.TypeSignature {
64 tags[i] = tc.Tag
65 }
66 sort.Strings(tags)
67 b.Tags = tags
68
69 return b
70 }
71
72 // Equal checks structural equality of two bases.
73 func (b *Basis) Equal(other *Basis) bool {
74 if b.Dimension != other.Dimension {
75 return false
76 }
77 if len(b.Tags) != len(other.Tags) {
78 return false
79 }
80 for i, t := range b.Tags {
81 if t != other.Tags[i] {
82 return false
83 }
84 }
85 if len(b.Distribution) != len(other.Distribution) {
86 return false
87 }
88 for i, d := range b.Distribution {
89 if d.Tag != other.Distribution[i].Tag || d.Count != other.Distribution[i].Count {
90 return false
91 }
92 }
93 if b.PermDist != other.PermDist {
94 return false
95 }
96 if b.ProjDist != other.ProjDist {
97 return false
98 }
99 if !b.Modulus.Equal(other.Modulus) {
100 return false
101 }
102 return true
103 }
104
105 // TagCount returns the site count for a given tag, or 0 if not found.
106 func (b *Basis) TagCount(tag string) int {
107 for _, d := range b.Distribution {
108 if d.Tag == tag {
109 return d.Count
110 }
111 }
112 return 0
113 }
114