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