1010//
1111// Example usage:
1212//
13- // // Create a label readable by everyone
13+ // // Create a label readable by everyone (public)
1414// universe := UniversalReaders[string]()
15- // publicReaders := NewFiniteReaderSetFromSlice([]string{"alice", "bob"})
16- // label, _ := NewPowersetLattice(publicReaders, universe)
15+ // label, _ := NewPowersetLattice(universe, universe)
1716//
1817// // Create a label for specific readers only
1918// finiteUniverse := NewFiniteReaderSetFromSlice([]string{"alice", "bob", "charlie"})
@@ -25,6 +24,7 @@ package ifc
2524import (
2625 "encoding/json"
2726 "fmt"
27+ "sort"
2828 "strings"
2929)
3030
@@ -90,7 +90,7 @@ func (f *FiniteReaderSet[T]) IsSubset(other ReaderSet[T]) bool {
9090 }
9191 otherFinite , ok := other .(* FiniteReaderSet [T ])
9292 if ! ok {
93- return false
93+ panic ( fmt . Sprintf ( "unsupported ReaderSet implementation: %T" , other ))
9494 }
9595 for member := range f .members {
9696 if _ , exists := otherFinite .members [member ]; ! exists {
@@ -106,7 +106,7 @@ func (f *FiniteReaderSet[T]) Union(other ReaderSet[T]) ReaderSet[T] {
106106 }
107107 otherFinite , ok := other .(* FiniteReaderSet [T ])
108108 if ! ok {
109- return f
109+ panic ( fmt . Sprintf ( "unsupported ReaderSet implementation: %T" , other ))
110110 }
111111 union := make (map [T ]struct {}, len (f .members )+ len (otherFinite .members ))
112112 for member := range f .members {
@@ -124,7 +124,7 @@ func (f *FiniteReaderSet[T]) Intersection(other ReaderSet[T]) ReaderSet[T] {
124124 }
125125 otherFinite , ok := other .(* FiniteReaderSet [T ])
126126 if ! ok {
127- return NewFiniteReaderSet [ T ]( make ( map [ T ] struct {} ))
127+ panic ( fmt . Sprintf ( "unsupported ReaderSet implementation: %T" , other ))
128128 }
129129 intersection := make (map [T ]struct {})
130130 for member := range f .members {
@@ -139,15 +139,18 @@ func (f *FiniteReaderSet[T]) String() string {
139139 if len (f .members ) == 0 {
140140 return "FiniteReaderSet({})"
141141 }
142+ strs := make ([]string , 0 , len (f .members ))
143+ for member := range f .members {
144+ strs = append (strs , fmt .Sprintf ("%v" , member ))
145+ }
146+ sort .Strings (strs )
142147 var b strings.Builder
143148 b .WriteString ("FiniteReaderSet({" )
144- first := true
145- for member := range f .members {
146- if ! first {
149+ for i , s := range strs {
150+ if i > 0 {
147151 b .WriteString (", " )
148152 }
149- first = false
150- fmt .Fprintf (& b , "%v" , member )
153+ b .WriteString (s )
151154 }
152155 b .WriteString ("})" )
153156 return b .String ()
@@ -192,23 +195,45 @@ func copySet[T comparable](in map[T]struct{}) map[T]struct{} {
192195}
193196
194197func (p * PowersetLattice [T ]) Leq (other * PowersetLattice [T ]) bool {
198+ p .mustMatchUniverse (other )
195199 return p .subset .IsSubset (other .subset )
196200}
197201
198202func (p * PowersetLattice [T ]) Join (other * PowersetLattice [T ]) * PowersetLattice [T ] {
203+ p .mustMatchUniverse (other )
199204 return & PowersetLattice [T ]{
200205 subset : p .subset .Union (other .subset ),
201206 universe : p .universe ,
202207 }
203208}
204209
205210func (p * PowersetLattice [T ]) Meet (other * PowersetLattice [T ]) * PowersetLattice [T ] {
211+ p .mustMatchUniverse (other )
206212 return & PowersetLattice [T ]{
207213 subset : p .subset .Intersection (other .subset ),
208214 universe : p .universe ,
209215 }
210216}
211217
218+ func (p * PowersetLattice [T ]) mustMatchUniverse (other * PowersetLattice [T ]) {
219+ pUniv := p .universe .IsUniversal ()
220+ oUniv := other .universe .IsUniversal ()
221+ if pUniv != oUniv {
222+ panic (fmt .Sprintf ("universe mismatch: %s vs %s" , p .universe , other .universe ))
223+ }
224+ if pUniv {
225+ return
226+ }
227+ pFinite , pOK := p .universe .(* FiniteReaderSet [T ])
228+ oFinite , oOK := other .universe .(* FiniteReaderSet [T ])
229+ if ! pOK || ! oOK {
230+ panic (fmt .Sprintf ("universe mismatch: %T vs %T" , p .universe , other .universe ))
231+ }
232+ if ! pFinite .IsSubset (oFinite ) || ! oFinite .IsSubset (pFinite ) {
233+ panic (fmt .Sprintf ("universe mismatch: %s vs %s" , p .universe , other .universe ))
234+ }
235+ }
236+
212237func (p * PowersetLattice [T ]) String () string {
213238 return fmt .Sprintf ("Powerset(%s)" , p .subset .String ())
214239}
@@ -318,6 +343,7 @@ func (l ReadersSecurityLabel) GetReaders() []string {
318343 for reader := range finiteSet .members {
319344 readers = append (readers , reader )
320345 }
346+ sort .Strings (readers )
321347 return readers
322348}
323349
@@ -396,7 +422,7 @@ func (l *ReadersSecurityLabel) UnmarshalJSON(data []byte) error {
396422 return nil
397423}
398424
399- // ReadersSecurityLabelFromDict creates an ReadersSecurityLabel from a dictionary format.
425+ // ReadersSecurityLabelFromDict creates a ReadersSecurityLabel from a dictionary format.
400426func ReadersSecurityLabelFromDict (dict map [string ]any ) ReadersSecurityLabel {
401427 // Parse integrity
402428 integrityStr := "high"
0 commit comments