+ package pijul
+
+ import (
+ "fmt"
+
+ "filippo.io/edwards25519"
+ )
+
+ // A State represents a set of changes. It is calculated from the hashes of
+ // the changes, using the Edwards 25519 curve.
+ type State struct {
+ p edwards25519.Point
+ }
+
+ func (s State) String() string {
+ return base32Encoding.EncodeToString(append(s.p.Bytes(), 1))
+ }
+
+ func StateFromBase32(b32 string) (State, error) {
+ b, err := base32Encoding.DecodeString(b32)
+ if err != nil {
+ return State{}, err
+ }
+ if len(b) != 33 {
+ return State{}, fmt.Errorf("expected 33 bytes, got %d", len(b))
+ }
+ if b[32] != 1 {
+ return State{}, fmt.Errorf("expected Ed25519 state, got type %d", b[32])
+ }
+
+ var p edwards25519.Point
+ _, err = p.SetBytes(b[:32])
+ if err != nil {
+ return State{}, err
+ }
+ return State{p}, nil
+ }
+
+ func mustStateFromBase32(b32 string) State {
+ s, err := StateFromBase32(b32)
+ if err != nil {
+ panic(err)
+ }
+ return s
+ }
+
+ // EmptyState is the State that represents the empty set.
+ var EmptyState = mustStateFromBase32("LBTGMZTGMZTGMZTGMZTGMZTGMZTGMZTGMZTGMZTGMZTGMZTGMZTAC")
+
+ func (s State) Add(h Hash) State {
+ var wideBytes [64]byte
+ copy(wideBytes[:], h[:])
+ var scalar edwards25519.Scalar
+ scalar.SetUniformBytes(wideBytes[:])
+
+ p := s.p
+ p.ScalarMult(&scalar, &p)
+ return State{p}
+ }