joeblack.git

commit d2fe5233366e54fa9f8aa9d37542cbe382eb9e13

Author: Adam <git@apiote.xyz>

[NOPALOAD] embed will

 decoder/joeblack.go | 24 
 encode | 2 
 encoder/joeblack.go | 103 ++-
 encoder/vendor/apiote.xyz/p/go-dirty/README | 1 
 encoder/vendor/apiote.xyz/p/go-dirty/array.go | 76 ++
 encoder/vendor/apiote.xyz/p/go-dirty/const.go | 59 +
 encoder/vendor/apiote.xyz/p/go-dirty/errors.go | 95 ++
 encoder/vendor/apiote.xyz/p/go-dirty/example.drt | 27 
 encoder/vendor/apiote.xyz/p/go-dirty/main.go | 72 ++
 encoder/vendor/apiote.xyz/p/go-dirty/number.go | 180 +++++
 encoder/vendor/apiote.xyz/p/go-dirty/string.go | 123 +++
 encoder/vendor/apiote.xyz/p/go-dirty/struct.go | 202 ++++++
 encoder/vendor/apiote.xyz/p/go-dirty/tokeniser.go | 270 ++++++++
 encoder/vendor/git.sr.ht/~sircmpwn/go-bare/.build.yml | 12 
 encoder/vendor/git.sr.ht/~sircmpwn/go-bare/.gitignore | 3 
 encoder/vendor/git.sr.ht/~sircmpwn/go-bare/LICENSE | 13 
 encoder/vendor/git.sr.ht/~sircmpwn/go-bare/README.md | 130 +++
 encoder/vendor/git.sr.ht/~sircmpwn/go-bare/errors.go | 17 
 encoder/vendor/git.sr.ht/~sircmpwn/go-bare/limit.go | 55 +
 encoder/vendor/git.sr.ht/~sircmpwn/go-bare/marshal.go | 308 +++++++++
 encoder/vendor/git.sr.ht/~sircmpwn/go-bare/package.go | 8 
 encoder/vendor/git.sr.ht/~sircmpwn/go-bare/reader.go | 188 +++++
 encoder/vendor/git.sr.ht/~sircmpwn/go-bare/unions.go | 76 ++
 encoder/vendor/git.sr.ht/~sircmpwn/go-bare/unmarshal.go | 359 +++++++++++
 encoder/vendor/git.sr.ht/~sircmpwn/go-bare/varint.go | 27 
 encoder/vendor/git.sr.ht/~sircmpwn/go-bare/writer.go | 116 +++
 encoder/vendor/github.com/codahale/sss/.gitignore | 1 
 encoder/vendor/github.com/codahale/sss/.travis.yml | 9 
 encoder/vendor/github.com/codahale/sss/LICENSE | 21 
 encoder/vendor/github.com/codahale/sss/README.md | 11 
 encoder/vendor/github.com/codahale/sss/gf256.go | 81 ++
 encoder/vendor/github.com/codahale/sss/polynomial.go | 67 ++
 encoder/vendor/github.com/codahale/sss/sss.go | 120 +++
 encoder/vendor/modules.txt | 9 
 index.html | 41 
 payload | 1 
 shared/shared.go | 52 +


diff --git a/decoder/joeblack.go b/decoder/joeblack.go
index 6072629ff187aec8225dee73201cded4e781f628..5a4b4df6283a2c99c7339a277f6de3c8e8ca676c 100644
--- a/decoder/joeblack.go
+++ b/decoder/joeblack.go
@@ -37,8 +37,8 @@ }
 
 // args:: shares :[sharesNum]string...
 func decodeSSS(this js.Value, args []js.Value) any {
-	if len(args) != sharesNum {
-		return fmt.Sprintf("ERR: Invalid number of arguments given %d, expected %d\n", len(args), sharesNum)
+	if len(args) != sharesNum { // +1
+		return fmt.Sprintf("ERR: Invalid number of arguments given %d, expected %d\n", len(args), sharesNum) // +1
 	}
 	shares := map[byte][]byte{}
 	for i := 0; i < sharesNum; i++ {
@@ -49,6 +49,7 @@ 			return fmt.Sprintf("ERR: while decoding words: %v", err)
 		}
 		shareNum := shareBytes[len(shareBytes)-1]
 		shareBytes = shareBytes[:len(shareBytes)-1]
+		//todo last argument is burnt sha512sums of shares; if it matches any => return Err
 		shares[shareNum] = shareBytes
 	}
 	return base64.StdEncoding.EncodeToString(sss.Combine(shares))
@@ -84,10 +85,10 @@ 	rawPayload, err := base64.StdEncoding.DecodeString(args[1].String())
 	if err != nil {
 		return fmt.Sprintf("ERR: while decoding base64 payload: %v", err)
 	}
-	payload := Payload{}
-	payload.Keys = make([][]byte, 2)
-	l1 := rawPayload[0]
-	l2 := rawPayload[l1+1]
+	payload, err := unmarshal(rawPayload)
+	if err != nil {
+		return fmt.Sprintf("ERR: while unmarshalling: %v", err)
+	}
 	var key []byte
 	var keyNum int
 	if isPaperKey {
@@ -96,13 +97,10 @@ 	} else {
 		keyNum = 0
 	}
 
-	payload.Keys[0] = rawPayload[1 : l1+1]
-	payload.Keys[1] = rawPayload[l1+2 : l1+2+l2]
 	key, err = decrypt(payload.Keys[keyNum], wordsKey)
 	if err != nil {
 		return fmt.Sprintf("ERR: while decrypting key: %v", err)
 	}
-	payload.Secrets = rawPayload[l1+2+l2:]
 	rawSecrets, err := decrypt(payload.Secrets, key)
 	if err != nil {
 		return fmt.Sprintf("ERR: while decrypting secrets: %v", err)
@@ -113,6 +111,12 @@ 	if err != nil {
 		return fmt.Sprintf("ERR: while unmarshalling secrets: %v", err)
 	}
 
+	will, err := decrypt(payload.Will, key)
+	if err != nil {
+		return fmt.Sprintf("ERR: while decrypting will: %v", err)
+	}
+	willB64 := base64.StdEncoding.EncodeToString(will)
+
 	export := ""
 	secretsLen := len(secrets)
 	for i, secret := range secrets {
@@ -130,5 +134,5 @@ 		if i+1 < secretsLen {
 			export += fmt.Sprintln("---")
 		}
 	}
-	return export
+	return willB64 + "|" + export
 }




diff --git a/encode b/encode
index 57bed3045da6dcca1d57fecd09f188859d62c783..b32d50d97fc608206a328f8de74daedae74767d0 100755
--- a/encode
+++ b/encode
@@ -4,7 +4,7 @@
 eeze -E >encoder/secrets.dirty
 mv payload encoder/payload
 cd encoder
-joeblack -r
+./joeblack -r
 shred -fuz secrets.dirty
 cd ../
 mv encoder/payload .




diff --git a/encoder/joeblack.go b/encoder/joeblack.go
index c84275d6fc2c2b26d2213e78594cd478bd00eb42..2de225378b630aabb830e9ecfb2cc3a869174cf8 100644
--- a/encoder/joeblack.go
+++ b/encoder/joeblack.go
@@ -5,12 +5,13 @@ 	"bufio"
 	"crypto/rand"
 	"encoding/base64"
 	"fmt"
-	"github.com/codahale/sss"
 	"io"
 	"os"
+	//"strconv"
 
 	"apiote.xyz/p/go-dirty"
 	"git.sr.ht/~sircmpwn/go-bare"
+	"github.com/codahale/sss"
 )
 
 func main() {
@@ -29,13 +30,31 @@ 		wordlistRev[wordlist[i]] = i
 	}
 
 	recreate := false
+	add := false
+	//var already int64 = 0
 	if len(os.Args) > 1 && os.Args[1] == "-r" {
 		recreate = true
 	}
+	if len(os.Args) > 2 && os.Args[1] == "-a" {
+		add = true
+		//already, _ = strconv.ParseInt(os.Args[2], 10, 8)
+	}
 
 	payload := Payload{}
 	key := [32]byte{}
-	if !recreate {
+	sssKey := [32]byte{}
+	paperKey := [32]byte{}
+	if !recreate && !add {
+		_, err = io.ReadFull(rand.Reader, sssKey[:])
+		if err != nil {
+			fmt.Printf("while creating sss key: %v\n", err)
+			os.Exit(1)
+		}
+		_, err = io.ReadFull(rand.Reader, paperKey[:])
+		if err != nil {
+			fmt.Printf("while creating paperkey: %v\n", err)
+			os.Exit(1)
+		}
 		_, err = io.ReadFull(rand.Reader, key[:])
 		if err != nil {
 			fmt.Printf("while creating key: %v\n", err)
@@ -47,7 +66,7 @@ 		if err != nil {
 			fmt.Printf("while reading paper key: %v\n", err)
 			os.Exit(1)
 		}
-		paperKey, err := fromWords(paperKeyWords, wordlistRev)
+		pK, err := fromWords(paperKeyWords, wordlistRev)
 		if err != nil {
 			fmt.Printf("while decoding paper key: %v\n", err)
 			os.Exit(1)
@@ -58,38 +77,38 @@ 			fmt.Printf("while opening payload: %v\n", err)
 			os.Exit(1)
 		}
 		defer payloadFile.Close()
-		reader := base64.NewDecoder(base64.StdEncoding, payloadFile)
 
-		payload.Keys = make([][]byte, 2)
-		l := make([]byte, 1)
-		_, err = io.ReadFull(reader, l)
+		payloadB64, err := io.ReadAll(payloadFile)
 		if err != nil {
-			fmt.Printf("while reading key[0] length: %v\n", err)
+			fmt.Printf("while reading payload: %v\n", err)
 			os.Exit(1)
 		}
-		payload.Keys[0] = make([]byte, l[0])
-		_, err = io.ReadFull(reader, payload.Keys[0])
+
+		payloadBytes, err := base64.StdEncoding.DecodeString(string(payloadB64))
 		if err != nil {
-			fmt.Printf("while reading key[0]: %v\n", err)
+			fmt.Printf("while de-base64-ing payload: %v\n", err)
 			os.Exit(1)
 		}
-		_, err = io.ReadFull(reader, l)
+
+		payload, err = unmarshal(payloadBytes)
 		if err != nil {
-			fmt.Printf("while reading key[1] length: %v\n", err)
+			fmt.Printf("while unmarshaling payload: %v\n", err)
 			os.Exit(1)
 		}
-		payload.Keys[1] = make([]byte, l[0])
-		_, err = io.ReadFull(reader, payload.Keys[1])
+
+		k, err := decrypt(payload.Keys[1], pK)
 		if err != nil {
-			fmt.Printf("while reading key[1]: %v\n", err)
+			fmt.Printf("while decrypting paperKeyEnc: %v\n", err)
 			os.Exit(1)
 		}
-		k, err := decrypt(payload.Keys[1], paperKey)
+		sk, err := decrypt(payload.Keys[2], pK)
 		if err != nil {
 			fmt.Printf("while decrypting paperKeyEnc: %v\n", err)
 			os.Exit(1)
 		}
 		copy(key[:], k)
+		copy(sssKey[:], sk)
+		copy(paperKey[:], pK)
 	}
 
 	secrets := []Secret{}
@@ -112,46 +131,58 @@ 		fmt.Printf("while marshalling secrets: %v\n", err)
 		os.Exit(1)
 	}
 
+	will, err := os.Open("will.pdf")
+	if err != nil {
+		fmt.Printf("while opening will: %v\n", err)
+		os.Exit(1)
+	}
+	defer will.Close()
+
+	willBytes, err := io.ReadAll(will)
+	if err != nil {
+		fmt.Printf("while reading will: %v\n", err)
+		os.Exit(1)
+	}
+
 	payload.Secrets, err = encrypt(bareSecrets, key[:])
+	payload.Will, err = encrypt(willBytes, key[:])
 
-	if !recreate {
-		sssKey := [32]byte{}
-		_, err = io.ReadFull(rand.Reader, sssKey[:])
+	if add {
+		/* todo
+		shares, err := sss.Add(1, 3, byte(already), sssKey[:]) // for x =byte(1); x<=n+already; x++
 		if err != nil {
-			fmt.Printf("while creating sss key: %v\n", err)
+			fmt.Printf("while spliting: %v\n", err)
 			os.Exit(1)
 		}
-		paperKey := [32]byte{}
-		_, err = io.ReadFull(rand.Reader, paperKey[:])
-		if err != nil {
-			fmt.Printf("while creating paperkey: %v\n", err)
-			os.Exit(1)
-		}
+		fmt.Println(toWords(shares[already], wordlist))
+		*/
+	} else if !recreate {
 		sssKeyEnc, err := encrypt(key[:], sssKey[:])
 		paperKeyEnc, err := encrypt(key[:], paperKey[:])
+		sssKeyPaperEnc, err := encrypt(sssKey[:], paperKey[:])
+		payload.Keys = [][]byte{}
 		payload.Keys = append(payload.Keys, sssKeyEnc)
 		payload.Keys = append(payload.Keys, paperKeyEnc)
+		payload.Keys = append(payload.Keys, sssKeyPaperEnc)
 
 		shares, err := sss.Split(5, 3, sssKey[:])
 		if err != nil {
 			fmt.Printf("while spliting: %v\n", err)
 			os.Exit(1)
 		}
-		for i, share := range shares {
-			share = append(share, byte(i))
+		for x, share := range shares {
+			share = append(share, x)
 			fmt.Println(toWords(share, wordlist))
 		}
 		fmt.Println("")
 		fmt.Println(toWords(paperKey[:], wordlist))
 	}
 
-
-	payloadBytes := []byte{}
-	payloadBytes = append(payloadBytes, byte(len(payload.Keys[0])))
-	payloadBytes = append(payloadBytes, payload.Keys[0]...)
-	payloadBytes = append(payloadBytes, byte(len(payload.Keys[1])))
-	payloadBytes = append(payloadBytes, payload.Keys[1]...)
-	payloadBytes = append(payloadBytes, payload.Secrets...)
+	payloadBytes, err := bare.Marshal(&payload)
+	if err != nil {
+		fmt.Printf("while marshaling: %v\n", err)
+		os.Exit(1)
+	}
 	payloadB64 := base64.StdEncoding.EncodeToString(payloadBytes)
 	os.WriteFile("payload", []byte(payloadB64), 0o644)
 }




diff --git a/encoder/vendor/apiote.xyz/p/go-dirty/README b/encoder/vendor/apiote.xyz/p/go-dirty/README
new file mode 100644
index 0000000000000000000000000000000000000000..8b137891791fe96927ad78e64b0aad7bded08bdc
--- /dev/null
+++ b/encoder/vendor/apiote.xyz/p/go-dirty/README
@@ -0,0 +1 @@
+




diff --git a/encoder/vendor/apiote.xyz/p/go-dirty/array.go b/encoder/vendor/apiote.xyz/p/go-dirty/array.go
new file mode 100644
index 0000000000000000000000000000000000000000..76f9f224ab6a0fbb7e850096cca5d28815a7e872
--- /dev/null
+++ b/encoder/vendor/apiote.xyz/p/go-dirty/array.go
@@ -0,0 +1,76 @@
+package dirty
+
+import (
+	"bufio"
+)
+
+type Array []Element
+
+func (Array) isElement() {}
+func (Array) getType() ElementType {
+	return ElemArray
+}
+
+type Element interface {
+	isElement()
+	getType() ElementType
+}
+
+type ElementType int
+
+const (
+	ElemArray ElementType = iota
+	ElemString
+	ElemConst
+	ElemInt
+	ElemFloat
+)
+
+func loadArray(r *bufio.Reader) ([]Element, error) {
+	topArray := []Element{}
+	for {
+		t, err := nextToken(r)
+		if err != nil {
+			return []Element{}, err
+		}
+		//debugf("in LoadArray got %+v\n", t)
+
+		switch t.ttype {
+		case LBRACKET:
+			//debugf("in LoadArray loading array\n")
+			array, err := loadArray(r)
+			if err != nil {
+				return []Element{}, err
+			}
+			topArray = append(topArray, Array(array))
+		case RBRACKET:
+			//debugf("in LoadArray closing\n")
+			return topArray, nil
+			// todo atoms
+		case COMMENT:
+			continue
+		case STRING:
+			//debugf("in LoadArray adding string\n")
+			topArray = append(topArray, String(t.t))
+		case STRING_RAW:
+			//debugf("in LoadArray adding raw string\n")
+			topArray = append(topArray, String(t.t))
+		case CONST:
+			//debugf("in LoadArray adding const\n")
+			topArray = append(topArray, NewConst(t.t))
+		case NUMBER:
+			//debugf("in LoadArray adding number %+v, %d\n", t, *t.i)
+			if t.i != nil {
+				topArray = append(topArray, Int(*t.i))
+			}
+		case FLOAT:
+			//debugf("in LoadArray adding float %+v, %f\n", t, *t.f)
+			if t.f != nil {
+				topArray = append(topArray, Float(*t.f))
+			}
+		default:
+			//debugln("loadArray")
+			return []Element{}, NewSyntaxError(t, []token{})
+		}
+	}
+}




diff --git a/encoder/vendor/apiote.xyz/p/go-dirty/const.go b/encoder/vendor/apiote.xyz/p/go-dirty/const.go
new file mode 100644
index 0000000000000000000000000000000000000000..1712b7fc43a3e70830b957080846c8b5cd41fbc9
--- /dev/null
+++ b/encoder/vendor/apiote.xyz/p/go-dirty/const.go
@@ -0,0 +1,59 @@
+package dirty
+
+import (
+	"fmt"
+)
+
+type Const int
+
+const (
+	TRUE Const = iota
+	FALSE
+	NULL
+)
+
+func NewConst(s string) Const {
+	if s == "true" {
+		return TRUE
+	}
+	if s == "false" {
+		return FALSE
+	}
+	if s == "null" {
+		return NULL
+	}
+	panic("invalid const " + s)
+}
+
+func (Const) isElement() {}
+func (Const) getType() ElementType {
+	return ElemConst
+}
+func (c Const) String() string {
+	if c == TRUE {
+		return "true"
+	}
+	if c == FALSE {
+		return "false"
+	}
+	if c == NULL {
+		return "null"
+	}
+	panic(fmt.Sprintf("invalid const %d", c))
+}
+func (c Const) Bool() bool {
+	if c == TRUE {
+		return true
+	} else if c == FALSE {
+		return false
+	} else {
+		panic("Const is not bool")
+	}
+}
+
+func parseConst(t token) (token, error) {
+	if t.t != "true" && t.t != "false" && t.t != "null" {
+		return token{}, NewConstError(t.t)
+	}
+	return t, nil
+}




diff --git a/encoder/vendor/apiote.xyz/p/go-dirty/errors.go b/encoder/vendor/apiote.xyz/p/go-dirty/errors.go
new file mode 100644
index 0000000000000000000000000000000000000000..fc568d94db43b1ceb7317b827594eb0ae602bd1a
--- /dev/null
+++ b/encoder/vendor/apiote.xyz/p/go-dirty/errors.go
@@ -0,0 +1,95 @@
+package dirty
+
+import (
+	"fmt"
+)
+
+type SyntaxError struct {
+	found    token
+	expected []token
+}
+
+func NewSyntaxError(found token, expected []token) SyntaxError {
+	return SyntaxError{found: found, expected: expected}
+}
+func (se SyntaxError) Error() string {
+	return fmt.Sprintf("expected %v; got %v\n", se.expected, se.found)
+}
+
+type UnterminatedError struct {
+	ttype string
+	t     string
+}
+
+func NewUnterminatedError(ttype string, t string) UnterminatedError {
+	return UnterminatedError{ttype: ttype, t: t}
+}
+func (e UnterminatedError) Error() string {
+	return fmt.Sprintf("unterminated %s ‘%s’\n", e.ttype, e.t)
+}
+
+type InvalidCharError struct {
+	r rune
+}
+
+func NewInvalidCharError(r rune) InvalidCharError {
+	return InvalidCharError{r: r}
+}
+func (e InvalidCharError) Error() string {
+	return fmt.Sprintf("invalid character ‘%d’\n", e.r)
+}
+
+type CommaError struct {
+	s string
+}
+
+func NewCommaError(s string) CommaError {
+	return CommaError{s: s}
+}
+func (e CommaError) Error() string {
+	return fmt.Sprintf("comma in wrong place in ‘%s’\n", e.s)
+}
+
+type InvalidCodepointError struct {
+	c string
+}
+
+func NewInvalidCodepointError(c string) InvalidCodepointError {
+	return InvalidCodepointError{c: c}
+}
+func (e InvalidCodepointError) Error() string {
+	return fmt.Sprintf("invalid codepoint ‘%s’\n", e.c)
+}
+
+type ConstError struct {
+	t string
+}
+
+func NewConstError(t string) ConstError {
+	return ConstError{t: t}
+}
+func (e ConstError) Error() string {
+	return fmt.Sprintf("malformed const ‘%s’\n", e.t)
+}
+
+type EscapeError struct {
+	char rune
+}
+
+func NewEscapeError(char rune) EscapeError {
+	return EscapeError{char: char}
+}
+func (e EscapeError) Error() string {
+	return fmt.Sprintf("invalid escape sequence \\%v\n", e.char)
+}
+
+type RawStringError struct {
+	s string
+}
+
+func NewRawStringError(s string) RawStringError {
+	return RawStringError{s: s}
+}
+func (e RawStringError) Error() string {
+	return e.s
+}




diff --git a/encoder/vendor/apiote.xyz/p/go-dirty/example.drt b/encoder/vendor/apiote.xyz/p/go-dirty/example.drt
new file mode 100644
index 0000000000000000000000000000000000000000..b91ea27c2ce4c6b707d552842542a756cf649cde
--- /dev/null
+++ b/encoder/vendor/apiote.xyz/p/go-dirty/example.drt
@@ -0,0 +1,27 @@
+(
+	('map' # array of pairs
+		(
+			('π' 3.14) 
+			('e' 2.73)
+			('h' 10,000·) # dozenal = 12^4 in decimal
+			('one' 1) # decimal integer
+			('positivity' true)
+			('negativity' false)
+			('i don’t know' null)
+			('256' 0xff)
+			('7' 0b111)
+			(7 'is not the same')
+			#(0b111 'but this would be')
+			('execute' 0o755)
+			('ice point' 16↋7·6)
+			('dozenal digits' (1· 2· 3· 4· 5· 6· 7· 8· 9· ↊· ↋·))
+			('dozenal negative' -10·1)
+			('escaped' 'i won\'t say but i will \tit\nand this will be in new line')
+			('scientific' (7e27 7e-27))
+			('cold' -10)
+			('imagine' (10+8i 8-10i ↊·+8·i 8·-↊·i))
+		)
+	)
+	('array' (1 2 3 'some text'))
+	('mapception' (('one' 1) ('two' 2)))
+)




diff --git a/encoder/vendor/apiote.xyz/p/go-dirty/main.go b/encoder/vendor/apiote.xyz/p/go-dirty/main.go
new file mode 100644
index 0000000000000000000000000000000000000000..13a26554b376c2c710bc95c9541ab8dc3000c18a
--- /dev/null
+++ b/encoder/vendor/apiote.xyz/p/go-dirty/main.go
@@ -0,0 +1,72 @@
+package dirty
+
+import (
+	"bufio"
+	"fmt"
+	"io"
+	"reflect"
+)
+
+const DEBUG bool = true // build -X
+
+func debugf(format string, a ...interface{}) {
+	if DEBUG {
+		fmt.Printf(format, a...)
+	}
+}
+func debugln(a ...interface{}) {
+	if DEBUG {
+		fmt.Println(a...)
+	}
+}
+
+// todo func LoadArray()
+func Load(r io.Reader) (Array, error) {
+	scanner := bufio.NewReader(r)
+	array := []Element{}
+	comment := token{ttype: COMMENT}
+	lbrack := token{ttype: LBRACKET}
+	eof := token{ttype: EOF}
+	expected := lbrack
+	for {
+		t, err := nextToken(scanner)
+		//debugf("in Load got %+v\n", t)
+		if err != nil {
+			return []Element{}, err
+		}
+		if t == comment {
+			continue
+		} else if t == lbrack {
+			if expected != lbrack {
+				//debugln("expected lbrac")
+				return []Element{}, NewSyntaxError(t, []token{expected})
+			}
+			//debugf("in Load loading array\n")
+			array, err = loadArray(scanner)
+			if err != nil {
+				return Array{}, err
+			}
+			expected = eof
+		} else if t == eof {
+			if expected != eof {
+				//debugln("expected eof")
+				return []Element{}, NewSyntaxError(t, []token{expected})
+			}
+			//debugf("in Load eofing\n")
+			return array, nil
+		} else {
+			//debugln("garbage")
+			return []Element{}, NewSyntaxError(t, []token{expected})
+		}
+	}
+}
+
+// todo func Load()
+func LoadStruct(r io.Reader, s interface{}) error {
+	array, err := Load(r)
+	if err != nil {
+		return err
+	}
+	v := reflect.ValueOf(s).Elem()
+	return convertStruct(array, v)
+}




diff --git a/encoder/vendor/apiote.xyz/p/go-dirty/number.go b/encoder/vendor/apiote.xyz/p/go-dirty/number.go
new file mode 100644
index 0000000000000000000000000000000000000000..0ebd92eccba900079e8821bb9b6de6c46214c718
--- /dev/null
+++ b/encoder/vendor/apiote.xyz/p/go-dirty/number.go
@@ -0,0 +1,180 @@
+package dirty
+
+import (
+	"math"
+	"strconv"
+	"strings"
+)
+
+type Int int
+
+func (Int) isElement() {}
+func (Int) getType() ElementType {
+	return ElemInt
+}
+func (i Int) String() string {
+	return strconv.FormatInt(int64(i), 10)
+}
+
+type Float float64
+
+func (Float) isElement() {}
+func (Float) getType() ElementType {
+	return ElemFloat
+}
+func (i Float) String() string {
+	return strconv.FormatFloat(float64(i), 'f', -1, 64)
+}
+
+func convertDozenal(d string) string {
+	result := ""
+	for _, c := range d {
+		if c == '↊' {
+			result += "a"
+		} else if c == '↋' {
+			result += "b"
+		} else if c == '·' {
+			result += "."
+		} else {
+			result += string(c)
+		}
+	}
+	return result
+}
+
+func parseNumber(t token) (token, error) {
+	l := len(t.t)
+	if (in('.', []rune(t.t)) && t.t[l-1] != '.') || (in('·', []rune(t.t)) && t.t[l-1] != '·') {
+		return parseFloat(t)
+	} else if in('e', []rune(t.t)) && t.t[0] != '0' {
+		return parseEngFloat(t)
+	} else {
+		return parseInt(t)
+	}
+}
+
+func parseFloat(t token) (token, error) {
+	t.ttype = FLOAT
+	if in('·', []rune(t.t)) {
+		number := strings.SplitN(convertDozenal(t.t), ".", 2)
+		whole, err := strconv.ParseInt(number[0], 12, 64)
+		if err != nil {
+			return token{}, err
+		}
+		fraction, err := strconv.ParseUint(number[1], 12, 64)
+		if err != nil {
+			return token{}, err
+		}
+
+		t.t = ""
+		w := float64(whole)
+		if fraction != 0 {
+			var sign float64
+			if w < 0 {
+				sign = -1.0
+			} else {
+				sign = 1.0
+			}
+			l := math.Floor(math.Log10((float64(fraction))/math.Log10(12)) + 1)
+			w += (float64(fraction) / math.Pow(12, l)) * sign
+		}
+		t.f = &w
+		return t, nil
+	} else {
+		f, err := strconv.ParseFloat(t.t, 64)
+		t.t = ""
+		t.f = &f
+		return t, err
+	}
+}
+
+func parseEngFloat(t token) (token, error) {
+	t.ttype = FLOAT
+	number := strings.SplitN(t.t, "e", 2)
+	a, err := strconv.ParseFloat(number[0], 64)
+	if err != nil {
+		return token{}, err
+	}
+	b, err := strconv.ParseInt(number[1], 10, 64)
+	if err != nil {
+		return token{}, err
+	}
+	num := a * math.Pow10(int(b))
+	t.t = ""
+	t.f = &num
+	return t, nil
+}
+
+func parseComma(num string, z int) (string, error) {
+	num2 := ""
+	prevIsComma := false
+	lastComma := -1
+	zeroes := ""
+	for i := 0; i < z; i++ {
+		zeroes += "0"
+	}
+	for i, d := range num {
+		if d == ',' {
+			if prevIsComma {
+				num2 += zeroes
+			} else if !((i-lastComma) == z+1 || lastComma == -1) {
+				return "", NewCommaError(num)
+			}
+			lastComma = i
+		} else {
+			num2 += string(d)
+		}
+		prevIsComma = d == ','
+	}
+	return num2, nil
+}
+
+func parseInt(t token) (token, error) {
+	num2 := t.t
+	base := 10
+
+	if t.t[0] == '0' && t.t[1] == 'b' {
+		num := t.t[2:]
+		if num[0] == ',' {
+			num = "1" + num
+		}
+
+		var err error = nil
+		num2, err = parseComma(num, 8)
+		if err != nil {
+			return token{}, err
+		}
+
+		num2 = "0b" + num2
+		base = 0
+	}
+	if t.t[0] == '0' && t.t[1] == 'o' {
+		num2 = t.t
+		base = 0
+	}
+	if t.t[0] == '0' && t.t[1] == 'x' {
+		num2 = t.t
+		base = 0
+	}
+	if in('·', []rune(t.t)) {
+		num, err := parseComma(t.t, 3) // 4?
+		if err != nil {
+			return token{}, err
+		}
+		num2 = convertDozenal(num)
+		num2 = num2[:len(num2)-1]
+		base = 12
+	}
+	if in('.', []rune(t.t)) {
+		num2 = t.t[:len(t.t)-1]
+		var err error = nil
+		parseComma(num2, 3)
+		if err != nil {
+			return token{}, err
+		}
+		base = 10
+	}
+	result, err := strconv.ParseInt(num2, base, 64)
+	t.i = &result
+	return t, err
+}




diff --git a/encoder/vendor/apiote.xyz/p/go-dirty/string.go b/encoder/vendor/apiote.xyz/p/go-dirty/string.go
new file mode 100644
index 0000000000000000000000000000000000000000..f951eb0e8f8341be44abd531ac5a82fd64d25131
--- /dev/null
+++ b/encoder/vendor/apiote.xyz/p/go-dirty/string.go
@@ -0,0 +1,123 @@
+package dirty
+
+import (
+	"strconv"
+	"unicode/utf8"
+)
+
+type String string
+
+func (String) isElement() {}
+func (String) getType() ElementType {
+	return ElemString
+}
+func (s String) String() string {
+	return "‘" + string(s) + "’"
+}
+
+func parseString(t token) (token, error) {
+	result := ""
+	ucode := ""
+	mode := 0
+	for _, r := range t.t {
+		if mode == 0 {
+			if r < 0x20 || r == 0x7f || (r >= 0x80 && r <= 0x9f) {
+				return token{}, NewInvalidCharError(rune(r))
+			}
+			if r == '\\' {
+				mode = '\\'
+				continue
+			}
+			result += string(rune(r))
+		} else if mode == '\\' {
+			switch r {
+			case 'n':
+				result += "\n"
+				mode = 0
+			case '\'':
+				result += "'"
+				mode = 0
+			case 'r':
+				result += "\r"
+				mode = 0
+			case 't':
+				result += "\t"
+				mode = 0
+			case '\\':
+				result += "\\"
+				mode = 0
+			case 'u':
+				mode = 'u'
+			case 'U':
+				mode = 'U'
+			default:
+				return token{}, NewEscapeError(r)
+			}
+		} else if mode == 'u' {
+			ucode += string(rune(r))
+			if len(ucode) == 4 {
+				mode = 0
+				char, err := parseUnicode(ucode)
+				ucode = ""
+				if err != nil {
+					return token{}, err
+				}
+				result += char
+			}
+		} else if mode == 'U' {
+			ucode += string(rune(r))
+			if len(ucode) == 8 {
+				mode = 0
+				char, err := parseUnicode(ucode)
+				ucode = ""
+				if err != nil {
+					return token{}, err
+				}
+				result += char
+			}
+		}
+	}
+	t.t = result
+	return t, nil
+}
+
+func parseUnicode(ucode string) (string, error) {
+	var (
+		b []byte
+		r rune
+	)
+	codepoint, err := strconv.ParseInt(ucode, 16, 64)
+	if err != nil {
+		return "", err
+	}
+	switch {
+	case codepoint < 0x7f:
+		b = []byte{byte(codepoint)}
+		// todo check r, s for error
+		r, _ = utf8.DecodeRune(b)
+	case codepoint < 0x7ff:
+		b = []byte{
+			byte((codepoint>>6)&0b00011111 | 0b11000000),
+			byte(codepoint&0b00111111 | 0b10000000),
+		}
+		r, _ = utf8.DecodeRune(b)
+	case codepoint < 0xffff:
+		b = []byte{
+			byte((codepoint>>12)&0b00001111 | 0b11100000),
+			byte((codepoint>>6)&0b00111111 | 0b10000000),
+			byte(codepoint&0b00111111 | 0b10000000),
+		}
+		r, _ = utf8.DecodeRune(b)
+	case codepoint < 0x1fffff:
+		b = []byte{
+			byte((codepoint>>18)&0b00000111 | 0b11110000),
+			byte((codepoint>>12)&0b00111111 | 0b10000000),
+			byte((codepoint>>6)&0b00111111 | 0b10000000),
+			byte(codepoint&0b00111111 | 0b10000000),
+		}
+		r, _ = utf8.DecodeRune(b)
+	default:
+		return "", InvalidCodepointError{ucode}
+	}
+	return string(r), nil
+}




diff --git a/encoder/vendor/apiote.xyz/p/go-dirty/struct.go b/encoder/vendor/apiote.xyz/p/go-dirty/struct.go
new file mode 100644
index 0000000000000000000000000000000000000000..661ba1d3117d22586eed1ed33588f01b8d6593ce
--- /dev/null
+++ b/encoder/vendor/apiote.xyz/p/go-dirty/struct.go
@@ -0,0 +1,202 @@
+package dirty
+
+import (
+	"fmt"
+	"reflect"
+	"unicode"
+)
+
+func getStructPair(e Element) Array {
+	if e.getType() != ElemArray && len(e.(Array)) != 2 {
+		// todo error: not a pair
+		fmt.Println("not a pair")
+		return nil
+	}
+	return e.(Array)
+}
+
+func getStructFieldName(pair Array) string {
+	k := reflect.TypeOf(pair[0]).Kind()
+	if k != reflect.String {
+		// todo error: name not string
+		fmt.Println("name not string")
+		return ""
+	}
+	fieldName := string(pair[0].(String))
+	runes := []rune(fieldName)
+	runes[0] = unicode.ToUpper(runes[0])
+	fieldName = string(runes)
+	return fieldName
+}
+
+func getStructMapKey(pair Array, mk reflect.Kind) reflect.Value {
+	sk := reflect.ValueOf(pair[0]).Type().String()
+	if (sk == "dirty.String" && mk != reflect.String) ||
+		(sk == "dirty.Int" && mk != reflect.Int && mk != reflect.Int8 &&
+			mk != reflect.Int16 && mk != reflect.Int32 && mk != reflect.Int64 &&
+			mk != reflect.Uint && mk != reflect.Uint8 &&
+			mk != reflect.Uint16 && mk != reflect.Uint32 && mk != reflect.Uint64) ||
+		(sk == "dirty.Const" && mk != reflect.Bool) /*test sk ==dirty.Const but not dirty::Bool */ {
+		// todo error
+		fmt.Printf("pair[0] (%v) not map key (%v)\n", sk, mk)
+		return reflect.ValueOf(nil)
+	}
+	switch mk {
+	case reflect.String:
+		return reflect.ValueOf(string(pair[0].(String)))
+	case reflect.Bool:
+		return reflect.ValueOf(pair[0].(Const).Bool())
+	case reflect.Uint:
+		return reflect.ValueOf(uint(pair[0].(Int)))
+	case reflect.Uint8:
+		return reflect.ValueOf(uint8(pair[0].(Int)))
+	case reflect.Uint16:
+		return reflect.ValueOf(uint16(pair[0].(Int)))
+	case reflect.Uint32:
+		return reflect.ValueOf(uint32(pair[0].(Int)))
+	case reflect.Uint64:
+		return reflect.ValueOf(uint64(pair[0].(Int)))
+	case reflect.Int:
+		return reflect.ValueOf(int(pair[0].(Int)))
+	case reflect.Int8:
+		return reflect.ValueOf(int8(pair[0].(Int)))
+	case reflect.Int16:
+		return reflect.ValueOf(int16(pair[0].(Int)))
+	case reflect.Int32:
+		return reflect.ValueOf(int32(pair[0].(Int)))
+	case reflect.Int64:
+		return reflect.ValueOf(int64(pair[0].(Int)))
+	default:
+		return reflect.ValueOf(nil)
+	}
+}
+
+func setStructValue(value Element, f reflect.Value) error {
+	switch value.getType() {
+	case ElemArray:
+		err := convertStruct(value.(Array), f)
+		if err != nil {
+			return err
+		}
+	case ElemConst:
+		if value == NULL && f.Kind() == reflect.Ptr {
+			// do nothing; default value is nil
+		} else if (value == TRUE || value == FALSE) && f.Kind() == reflect.Bool {
+			f.SetBool(value.(Const).Bool())
+		} else {
+			// todo error: type mismatch
+			fmt.Println("type mismatch")
+			return nil
+		}
+	case ElemFloat:
+		if f.Kind() == reflect.Float64 || f.Kind() == reflect.Float32 {
+			f.SetFloat(float64(value.(Float)))
+		} else {
+			// todo error: type mismatch
+			fmt.Println("type mismatch")
+			return nil
+		}
+	case ElemInt:
+		if f.Kind() == reflect.Int || f.Kind() == reflect.Int8 || f.Kind() == reflect.Int16 || f.Kind() == reflect.Int32 || f.Kind() == reflect.Int64 {
+			f.SetInt(int64(value.(Int)))
+		} else {
+			// todo error: type mismatch
+			fmt.Println("type mismatch")
+			return nil
+		}
+	case ElemString:
+		if f.Kind() == reflect.String {
+			f.SetString(string(value.(String)))
+		} else {
+			// todo error: type mismatch
+			fmt.Println("type mismatch")
+			return nil
+		}
+	default:
+		// todo error: unknown type
+		fmt.Println("unknown type")
+		return nil
+	}
+	return nil
+}
+
+func convertStruct(array Array, s reflect.Value) error {
+	kind := s.Kind()
+	if kind == reflect.Struct {
+		for _, e := range array {
+			pair := getStructPair(e)
+			fieldName := getStructFieldName(pair)
+
+			f := s.FieldByName(fieldName)
+			if !f.IsValid() {
+				// todo error no such field
+				fmt.Println("no such field", fieldName)
+				return nil
+			}
+			if f.Kind() == reflect.Ptr && pair[1] != NULL {
+				f.Set(reflect.New(f.Type().Elem()))
+				f = f.Elem()
+			}
+			setStructValue(pair[1], f)
+		}
+		//fmt.Printf("%+v\n", s)
+		return nil
+	}
+	if kind == reflect.Slice {
+		elemType := s.Type().Elem()
+		if s.Len() != 0 {
+			// todo error slice not empty
+			fmt.Println("slice len != 0")
+			return nil
+		}
+		capacity := s.Cap()
+		s.SetLen(capacity)
+		s2 := s
+		for i, e := range array {
+			if i < capacity {
+				f := s2.Index(i)
+				setStructValue(e, f)
+			} else {
+				f := reflect.New(elemType).Elem()
+				setStructValue(e, f)
+				s2 = reflect.Append(s2, f)
+			}
+		}
+		s.Set(s2)
+		//fmt.Printf("%+v\n", s)
+		return nil
+	}
+	if kind == reflect.Array {
+		if s.Len() != len(array) {
+			// todo error array len not Array len
+			fmt.Println("array len not length of Array")
+			return nil
+		}
+		for i, e := range array {
+			f := s.Index(i)
+			setStructValue(e, f)
+		}
+		//fmt.Printf("%+v\n", s)
+		return nil
+	}
+	if kind == reflect.Map {
+		keyType := s.Type().Key()
+		keyKind := keyType.Kind()
+		valueType := s.Type().Elem()
+		for _, e := range array {
+			pair := getStructPair(e)
+			k := getStructMapKey(pair, keyKind)
+			v := reflect.New(valueType).Elem()
+			setStructValue(pair[1], v)
+			if s.IsNil() {
+				var mapType = reflect.MapOf(keyType, valueType)
+				s.Set(reflect.MakeMapWithSize(mapType, 0))
+			}
+			s.SetMapIndex(k, v)
+		}
+		//fmt.Printf("%+v\n", s)
+		return nil
+	}
+	//fmt.Println(kind)
+	return nil
+}




diff --git a/encoder/vendor/apiote.xyz/p/go-dirty/tokeniser.go b/encoder/vendor/apiote.xyz/p/go-dirty/tokeniser.go
new file mode 100644
index 0000000000000000000000000000000000000000..30b8c54627e720b2c99febbc9eeb96623d89a913
--- /dev/null
+++ b/encoder/vendor/apiote.xyz/p/go-dirty/tokeniser.go
@@ -0,0 +1,270 @@
+package dirty
+
+import (
+	"bufio"
+	"fmt"
+	"io"
+)
+
+// todo use reader.Peek()
+var skipped rune = 0
+
+type tokenType int
+
+const (
+	UNKNOWN tokenType = iota
+	LBRACKET
+	RBRACKET
+	STRING
+	STRING_RAW
+	NUMBER
+	FLOAT
+	CONST
+	COMMENT
+	EOF
+)
+
+type token struct {
+	ttype tokenType
+	t     string
+	i     *int64
+	f     *float64
+}
+
+func nextToken(reader *bufio.Reader) (token, error) {
+	t, finished, e := nextToken_initial(reader)
+	if finished || e != nil {
+		return t, e
+	}
+	t, e = nextToken_rest(reader, t)
+	return t, e
+}
+func nextToken_initial(reader *bufio.Reader) (token, bool, error) {
+	var (
+		r   rune  = 0
+		err error = nil
+		t   token
+	)
+
+initialTokenLoop:
+	for {
+		if skipped != 0 {
+			r = skipped
+			skipped = 0
+		} else {
+			r, _, err = reader.ReadRune()
+		}
+		//debugf("%c\n", r)
+		if err != nil {
+			if err == io.EOF {
+				t := token{ttype: EOF}
+				return t, true, nil
+			}
+			return token{}, true, fmt.Errorf("while reading: %w", err)
+		}
+		switch {
+		case r == '(':
+			return token{ttype: LBRACKET}, true, nil
+		case r == ')':
+			return token{ttype: RBRACKET}, true, nil
+		case r == '#':
+			t = token{ttype: COMMENT}
+			break initialTokenLoop
+		case r == '`':
+			t = token{ttype: STRING_RAW}
+			break initialTokenLoop
+		case r == '\'':
+			t = token{ttype: STRING}
+			break initialTokenLoop
+		case r == 't':
+			t = token{ttype: CONST, t: "t"}
+			break initialTokenLoop
+		case r == 'f':
+			t = token{ttype: CONST, t: "f"}
+			break initialTokenLoop
+		case r == 'n':
+			t = token{ttype: CONST, t: "n"}
+			break initialTokenLoop
+		case in(r, []rune{'1', '2', '3', '4', '5', '6', '7', '8', '9', '↊', '↋', '-', '.', '·', ','}):
+			t = token{ttype: NUMBER, t: string(r)}
+			break initialTokenLoop
+		case r == '0':
+			r, _, err = reader.ReadRune()
+			//debugf("%c\n", r)
+			if err != nil {
+				if err == io.EOF {
+					t := token{ttype: EOF}
+					return t, true, nil
+				}
+				return token{}, true, fmt.Errorf("while reading: %w", err)
+			}
+			switch r {
+			case 'b':
+				t = token{ttype: NUMBER, t: "0b"}
+				break initialTokenLoop
+			case 'o':
+				t = token{ttype: NUMBER, t: "0o"}
+				break initialTokenLoop
+			case 'x':
+				t = token{ttype: NUMBER, t: "0x"}
+				break initialTokenLoop
+			default:
+				skipped = r
+				var zero int64 = 0
+				return token{ttype: NUMBER, i: &zero}, true, nil
+			}
+		case in(r, []rune{' ', '\t', '\n', '\r'}):
+			continue
+		default:
+			return token{}, true, nil
+		}
+	}
+	return t, false, err
+}
+
+func nextToken_rest(reader *bufio.Reader, t token) (token, error) {
+	var (
+		r                   rune
+		err                 error  = nil
+		escaping            bool   = false
+		stringRawIndent     string = ""
+		stringRawIndentSkip string = ""
+		stringRawState      int    = 0 // todo enum
+	)
+
+tokenLoop:
+	for {
+		if skipped != 0 {
+			r = skipped
+			skipped = 0
+		} else {
+			r, _, err = reader.ReadRune()
+		}
+		//debugf("%c\n", r)
+		// todo line, column
+		if err != nil {
+			if err == io.EOF {
+				if t.ttype == STRING || t.ttype == STRING_RAW {
+					return token{}, NewUnterminatedError("string", t.t)
+				} else {
+					return token{ttype: EOF}, nil
+				}
+			}
+			return token{}, fmt.Errorf("while reading: %w", err)
+		}
+
+		switch t.ttype {
+		case COMMENT:
+			if r != '\n' {
+				t.t += string(r)
+			} else {
+				break tokenLoop
+			}
+		case STRING:
+			if !escaping && r == '\'' {
+				t, err = parseString(t)
+				if err != nil {
+					return token{}, err
+				}
+				break tokenLoop
+			} else if r == '\n' {
+				return token{}, NewUnterminatedError("string", t.t)
+			} else {
+				t.t += string(r)
+			}
+			if escaping {
+				escaping = false
+			} else if r == '\\' {
+				escaping = true
+			}
+		case STRING_RAW:
+			if stringRawState == 0 {
+				if r != '\n' {
+					return token{}, NewRawStringError("missing new line after opening `")
+				} else {
+					stringRawState = 1
+					continue
+				}
+			}
+			if stringRawState == 1 {
+				if r == ' ' || r == '\t' {
+					stringRawIndent += string(r)
+				} else {
+					stringRawState = 2
+					t.t += string(r)
+				}
+				continue
+			}
+			if stringRawState == 2 {
+				// fixme assumes lines ending with \n; get to end of line
+				if r == '\n' {
+					stringRawState = 3
+					stringRawIndentSkip = ""
+				}
+				t.t += string(r)
+				continue
+			}
+			if stringRawState == 3 {
+				if len(stringRawIndentSkip) == 0 && r == '`' {
+					break tokenLoop
+				}
+				if len(stringRawIndentSkip) < len(stringRawIndent) {
+					stringRawIndentSkip += string(r)
+				} else {
+					if stringRawIndent != stringRawIndentSkip {
+						// todo convert whitespace to escape codes
+						return token{}, NewRawStringError("Indent ‘" + stringRawIndent + "’ does not begin with ‘" + stringRawIndentSkip + "’")
+					}
+					skipped = r
+					stringRawState = 2
+				}
+			}
+		case CONST:
+			if t.t[0] == 't' && in(r, []rune{'r', 'u', 'e'}) && len(t.t) < 4 {
+				t.t += string(r)
+				continue
+			}
+			if t.t[0] == 'f' && in(r, []rune{'a', 'l', 's', 'e'}) && len(t.t) < 5 {
+				t.t += string(r)
+				continue
+			}
+			if in(r, []rune{'u', 'l'}) && len(t.t) < 4 {
+				t.t += string(r)
+				continue
+			}
+			skipped = r
+			t, err = parseConst(t)
+			break tokenLoop
+		case NUMBER:
+			if t.t[0] == '0' && t.t[1] == 'b' && in(r, []rune{'0', '1', ','}) {
+				t.t += string(r)
+				continue
+			}
+			if t.t[0] == '0' && t.t[1] == 'o' && in(r, []rune{'0', '1', '2', '3', '4', '5', '6', '7'}) {
+				t.t += string(r)
+				continue
+			}
+			if t.t[0] == '0' && t.t[1] == 'x' && in(r, []rune{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'A', 'B', 'C', 'D', 'E', 'F'}) {
+				t.t += string(r)
+				continue
+			}
+			if in(r, []rune{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '↊', '↋', ',', '.', '·', 'e', '-'}) {
+				t.t += string(r)
+				continue
+			}
+			skipped = r
+			t, err = parseNumber(t) // todo errors that are not CommaError <- NumberError
+			break tokenLoop
+		}
+	}
+	return t, err
+}
+
+func in(c rune, expected []rune) bool {
+	for _, e := range expected {
+		if c == e {
+			return true
+		}
+	}
+	return false
+}




diff --git a/encoder/vendor/git.sr.ht/~sircmpwn/go-bare/.build.yml b/encoder/vendor/git.sr.ht/~sircmpwn/go-bare/.build.yml
new file mode 100644
index 0000000000000000000000000000000000000000..deb41fba899c2f8289b8d3bdbff9c1478c41703b
--- /dev/null
+++ b/encoder/vendor/git.sr.ht/~sircmpwn/go-bare/.build.yml
@@ -0,0 +1,12 @@
+image: alpine/edge
+packages:
+- go
+sources:
+- https://git.sr.ht/~sircmpwn/go-bare
+tasks:
+- gen: |
+    cd go-bare
+    go generate ./...
+- test: |
+    cd go-bare
+    go test ./...




diff --git a/encoder/vendor/git.sr.ht/~sircmpwn/go-bare/.gitignore b/encoder/vendor/git.sr.ht/~sircmpwn/go-bare/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..4a99827bd09c3743a43edc030083daf71aea8afa
--- /dev/null
+++ b/encoder/vendor/git.sr.ht/~sircmpwn/go-bare/.gitignore
@@ -0,0 +1,3 @@
+*.test
+*.prof
+*.log
\ No newline at end of file




diff --git a/encoder/vendor/git.sr.ht/~sircmpwn/go-bare/LICENSE b/encoder/vendor/git.sr.ht/~sircmpwn/go-bare/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..39354f5f05c4ebe0c4214d6ecbd98ac4a130ca88
--- /dev/null
+++ b/encoder/vendor/git.sr.ht/~sircmpwn/go-bare/LICENSE
@@ -0,0 +1,13 @@
+Copyright 2020 Drew DeVault
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.




diff --git a/encoder/vendor/git.sr.ht/~sircmpwn/go-bare/README.md b/encoder/vendor/git.sr.ht/~sircmpwn/go-bare/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..7739ac00fbc55fb4afa7f6532ace925180a97752
--- /dev/null
+++ b/encoder/vendor/git.sr.ht/~sircmpwn/go-bare/README.md
@@ -0,0 +1,130 @@
+# go-bare [![godocs.io](https://godocs.io/git.sr.ht/~sircmpwn/go-bare?status.svg)](https://godocs.io/git.sr.ht/~sircmpwn/go-bare) [![builds.sr.ht status](https://builds.sr.ht/~sircmpwn/go-bare.svg)](https://builds.sr.ht/~sircmpwn/go-bare?)
+
+An implementation of the [BARE](https://baremessages.org) message format
+for Go.
+
+**Status**
+
+This mostly works, but you may run into some edge cases with union types.
+
+## Code generation
+
+An example is provided in the `examples` directory. Here is a basic
+introduction:
+
+```
+$ cat schema.bare
+type Address {
+	address: [4]string
+	city: string
+	state: string
+	country: string
+}
+$ go run git.sr.ht/~sircmpwn/go-bare/cmd/gen -p models schema.bare models/gen.go
+```
+
+Then you can write something like the following:
+
+```go
+import "models"
+
+/* ... */
+
+bytes := []byte{ /* ... */ }
+var addr Address
+err := addr.Decode(bytes)
+```
+
+You can also add custom types and skip generating them by passing the `-s
+TypeName` flag to gen, then providing your own implementation. For example, to
+rig up time.Time with a custom "Time" BARE type, add this to your BARE schema:
+
+```
+type Time string
+```
+
+Then pass `-s Time` to gen, and provide your own implementation of Time in the
+same package. See `examples/time.go` for an example of such an implementation.
+
+## Marshal usage
+
+For many use-cases, it may be more convenient to write your types manually and
+use Marshal and Unmarshal directly. If you choose this approach, you may also
+use `git.sr.ht/~sircmpwn/go-bare/schema.SchemaFor` to generate a BARE schema
+language document describing your structs.
+
+```go
+package main
+
+import (
+    "fmt"
+    "git.sr.ht/~sircmpwn/go-bare"
+)
+
+// type Coordinates {
+//    x: int
+//    y: int
+//    z: int
+//    q: optional<int>
+// }
+type Coordinates struct {
+    X uint
+    Y uint
+    Z uint
+    Q *uint
+}
+
+func main() {
+    var coords Coordinates
+    payload := []byte{0x01, 0x02, 0x03, 0x01, 0x04}
+    err := bare.Unmarshal(payload, &coords)
+    if err != nil {
+        panic(err)
+    }
+    fmt.Printf("coords: %d, %d, %d (%d)\n",
+        coords.X, coords.Y, coords.Z, *coords.Q) /* coords: 1, 2, 3 (4) */
+}
+```
+
+### Unions
+
+To use union types, you need to define an interface to represent the union of
+possible values, and this interface needs to implement `bare.Union`:
+
+```go
+type Person interface {
+	Union
+}
+```
+
+Then, for each possible union type, implement the interface:
+
+```go
+type Employee struct { /* ... */ }
+func (e Employee) IsUnion() {}
+
+type Customer struct { /* ... */ }
+func (c Customer) IsUnion() {}
+```
+
+The IsUnion function is necessary to make the type compatible with the Union
+interface. Then, to marshal and unmarshal using this union type, you need to
+tell go-bare about your union:
+
+```go
+func init() {
+    // The first argument is a pointer of the union interface, and the
+    // subsequent arguments are values of each possible subtype, in ascending
+    // order of union tag:
+    bare.RegisterUnion((*Person)(nil)).
+      Member(*new(Employee), 0).
+      Member(*new(Customer), 1)
+}
+```
+
+This is all done for you if you use code generation.
+
+## Contributing, getting help
+
+Send patches and questions to
+[~sircmpwn/public-inbox@lists.sr.ht](mailto:~sircmpwn/public-inbox@lists.sr.ht)




diff --git a/encoder/vendor/git.sr.ht/~sircmpwn/go-bare/errors.go b/encoder/vendor/git.sr.ht/~sircmpwn/go-bare/errors.go
new file mode 100644
index 0000000000000000000000000000000000000000..f2c406c189e1db325dc0eb7c922e601af5ba0bc6
--- /dev/null
+++ b/encoder/vendor/git.sr.ht/~sircmpwn/go-bare/errors.go
@@ -0,0 +1,17 @@
+package bare
+
+import (
+	"errors"
+	"fmt"
+	"reflect"
+)
+
+var ErrInvalidStr = errors.New("String contains invalid UTF-8 sequences")
+
+type UnsupportedTypeError struct {
+	Type reflect.Type
+}
+
+func (e *UnsupportedTypeError) Error() string {
+	return fmt.Sprintf("Unsupported type for marshaling: %s\n", e.Type.String())
+}




diff --git a/encoder/vendor/git.sr.ht/~sircmpwn/go-bare/limit.go b/encoder/vendor/git.sr.ht/~sircmpwn/go-bare/limit.go
new file mode 100644
index 0000000000000000000000000000000000000000..6024745f3f067acb124a7e147ad6beffbb011ad2
--- /dev/null
+++ b/encoder/vendor/git.sr.ht/~sircmpwn/go-bare/limit.go
@@ -0,0 +1,55 @@
+package bare
+
+import (
+	"errors"
+	"io"
+)
+
+var (
+	maxUnmarshalBytes uint64 = 1024 * 1024 * 32 /* 32 MiB */
+	maxArrayLength    uint64 = 1024 * 4         /* 4096 elements */
+	maxMapSize        uint64 = 1024
+)
+
+// MaxUnmarshalBytes sets the maximum size of a message decoded by unmarshal.
+// By default, this is set to 32 MiB.
+func MaxUnmarshalBytes(bytes uint64) {
+	maxUnmarshalBytes = bytes
+}
+
+// MaxArrayLength sets maximum number of elements in array. Defaults to 4096 elements
+func MaxArrayLength(length uint64) {
+	maxArrayLength = length
+}
+
+// MaxMapSize sets maximum size of map. Defaults to 1024 key/value pairs
+func MaxMapSize(size uint64) {
+	maxMapSize = size
+}
+
+// Use MaxUnmarshalBytes to prevent this error from occuring on messages which
+// are large by design.
+var ErrLimitExceeded = errors.New("Maximum message size exceeded")
+
+// Identical to io.LimitedReader, except it returns our custom error instead of
+// EOF if the limit is reached.
+type limitedReader struct {
+	R io.Reader
+	N uint64
+}
+
+func (l *limitedReader) Read(p []byte) (n int, err error) {
+	if l.N <= 0 {
+		return 0, ErrLimitExceeded
+	}
+	if uint64(len(p)) > l.N {
+		p = p[0:l.N]
+	}
+	n, err = l.R.Read(p)
+	l.N -= uint64(n)
+	return
+}
+
+func newLimitedReader(r io.Reader) *limitedReader {
+	return &limitedReader{r, maxUnmarshalBytes}
+}




diff --git a/encoder/vendor/git.sr.ht/~sircmpwn/go-bare/marshal.go b/encoder/vendor/git.sr.ht/~sircmpwn/go-bare/marshal.go
new file mode 100644
index 0000000000000000000000000000000000000000..03467700bc73222971f86f5ab2fac85654f243a7
--- /dev/null
+++ b/encoder/vendor/git.sr.ht/~sircmpwn/go-bare/marshal.go
@@ -0,0 +1,308 @@
+package bare
+
+import (
+	"bytes"
+	"errors"
+	"fmt"
+	"reflect"
+	"sync"
+)
+
+// A type which implements this interface will be responsible for marshaling
+// itself when encountered.
+type Marshalable interface {
+	Marshal(w *Writer) error
+}
+
+var encoderBufferPool = sync.Pool{
+	New: func() interface{} {
+		buf := &bytes.Buffer{}
+		buf.Grow(32)
+		return buf
+	},
+}
+
+// Marshals a value (val, which must be a pointer) into a BARE message.
+//
+// The encoding of each struct field can be customized by the format string
+// stored under the "bare" key in the struct field's tag.
+//
+// As a special case, if the field tag is "-", the field is always omitted.
+func Marshal(val interface{}) ([]byte, error) {
+	// reuse buffers from previous serializations
+	b := encoderBufferPool.Get().(*bytes.Buffer)
+	defer func() {
+		b.Reset()
+		encoderBufferPool.Put(b)
+	}()
+
+	w := NewWriter(b)
+	err := MarshalWriter(w, val)
+
+	msg := make([]byte, b.Len())
+	copy(msg, b.Bytes())
+
+	return msg, err
+}
+
+// Marshals a value (val, which must be a pointer) into a BARE message and
+// writes it to a Writer. See Marshal for details.
+func MarshalWriter(w *Writer, val interface{}) error {
+	t := reflect.TypeOf(val)
+	v := reflect.ValueOf(val)
+	if t.Kind() != reflect.Ptr {
+		return errors.New("Expected val to be pointer type")
+	}
+
+	return getEncoder(t.Elem())(w, v.Elem())
+}
+
+type encodeFunc func(w *Writer, v reflect.Value) error
+
+var encodeFuncCache sync.Map // map[reflect.Type]encodeFunc
+
+// get decoder from cache
+func getEncoder(t reflect.Type) encodeFunc {
+	if f, ok := encodeFuncCache.Load(t); ok {
+		return f.(encodeFunc)
+	}
+
+	f := encoderFunc(t)
+	encodeFuncCache.Store(t, f)
+	return f
+}
+
+var marshalableInterface = reflect.TypeOf((*Unmarshalable)(nil)).Elem()
+
+func encoderFunc(t reflect.Type) encodeFunc {
+	if reflect.PtrTo(t).Implements(marshalableInterface) {
+		return func(w *Writer, v reflect.Value) error {
+			uv := v.Addr().Interface().(Marshalable)
+			return uv.Marshal(w)
+		}
+	}
+
+	if t.Kind() == reflect.Interface && t.Implements(unionInterface) {
+		return encodeUnion(t)
+	}
+
+	switch t.Kind() {
+	case reflect.Ptr:
+		return encodeOptional(t.Elem())
+	case reflect.Struct:
+		return encodeStruct(t)
+	case reflect.Array:
+		return encodeArray(t)
+	case reflect.Slice:
+		return encodeSlice(t)
+	case reflect.Map:
+		return encodeMap(t)
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+		return encodeUint
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		return encodeInt
+	case reflect.Float32, reflect.Float64:
+		return encodeFloat
+	case reflect.Bool:
+		return encodeBool
+	case reflect.String:
+		return encodeString
+	}
+
+	return func(w *Writer, v reflect.Value) error {
+		return &UnsupportedTypeError{v.Type()}
+	}
+}
+
+func encodeOptional(t reflect.Type) encodeFunc {
+	return func(w *Writer, v reflect.Value) error {
+		if v.IsNil() {
+			return w.WriteBool(false)
+		}
+
+		if err := w.WriteBool(true); err != nil {
+			return err
+		}
+
+		return getEncoder(t)(w, v.Elem())
+	}
+}
+
+func encodeStruct(t reflect.Type) encodeFunc {
+	n := t.NumField()
+	encoders := make([]encodeFunc, n)
+	for i := 0; i < n; i++ {
+		field := t.Field(i)
+		if field.Tag.Get("bare") == "-" {
+			continue
+		}
+		encoders[i] = getEncoder(field.Type)
+	}
+
+	return func(w *Writer, v reflect.Value) error {
+		for i := 0; i < n; i++ {
+			if encoders[i] == nil {
+				continue
+			}
+			err := encoders[i](w, v.Field(i))
+			if err != nil {
+				return err
+			}
+		}
+		return nil
+	}
+}
+
+func encodeArray(t reflect.Type) encodeFunc {
+	f := getEncoder(t.Elem())
+	len := t.Len()
+
+	return func(w *Writer, v reflect.Value) error {
+		for i := 0; i < len; i++ {
+			if err := f(w, v.Index(i)); err != nil {
+				return err
+			}
+		}
+		return nil
+	}
+}
+
+func encodeSlice(t reflect.Type) encodeFunc {
+	elem := t.Elem()
+	f := getEncoder(elem)
+
+	return func(w *Writer, v reflect.Value) error {
+		if err := w.WriteUint(uint64(v.Len())); err != nil {
+			return err
+		}
+
+		for i := 0; i < v.Len(); i++ {
+			if err := f(w, v.Index(i)); err != nil {
+				return err
+			}
+		}
+		return nil
+	}
+}
+
+func encodeMap(t reflect.Type) encodeFunc {
+	keyType := t.Key()
+	keyf := getEncoder(keyType)
+
+	valueType := t.Elem()
+	valf := getEncoder(valueType)
+
+	return func(w *Writer, v reflect.Value) error {
+		if err := w.WriteUint(uint64(v.Len())); err != nil {
+			return err
+		}
+
+		iter := v.MapRange()
+		for iter.Next() {
+			if err := keyf(w, iter.Key()); err != nil {
+				return err
+			}
+			if err := valf(w, iter.Value()); err != nil {
+				return err
+			}
+		}
+		return nil
+	}
+}
+
+func encodeUnion(t reflect.Type) encodeFunc {
+	ut, ok := unionRegistry[t]
+	if !ok {
+		return func(w *Writer, v reflect.Value) error {
+			return fmt.Errorf("Union type %s is not registered", t.Name())
+		}
+	}
+
+	encoders := make(map[uint64]encodeFunc)
+	for tag, t := range ut.types {
+		encoders[tag] = getEncoder(t)
+	}
+
+	return func(w *Writer, v reflect.Value) error {
+		t := v.Elem().Type()
+		if t.Kind() == reflect.Ptr {
+			// If T is a valid union value type, *T is valid too.
+			t = t.Elem()
+			v = v.Elem()
+		}
+		tag, ok := ut.tags[t]
+		if !ok {
+			return fmt.Errorf("Invalid union value: %s", v.Elem().String())
+		}
+
+		if err := w.WriteUint(tag); err != nil {
+			return err
+		}
+
+		return encoders[tag](w, v.Elem())
+	}
+}
+
+func encodeUint(w *Writer, v reflect.Value) error {
+	switch getIntKind(v.Type()) {
+	case reflect.Uint:
+		return w.WriteUint(v.Uint())
+
+	case reflect.Uint8:
+		return w.WriteU8(uint8(v.Uint()))
+
+	case reflect.Uint16:
+		return w.WriteU16(uint16(v.Uint()))
+
+	case reflect.Uint32:
+		return w.WriteU32(uint32(v.Uint()))
+
+	case reflect.Uint64:
+		return w.WriteU64(uint64(v.Uint()))
+	}
+
+	panic("not uint")
+}
+
+func encodeInt(w *Writer, v reflect.Value) error {
+	switch getIntKind(v.Type()) {
+	case reflect.Int:
+		return w.WriteInt(v.Int())
+
+	case reflect.Int8:
+		return w.WriteI8(int8(v.Int()))
+
+	case reflect.Int16:
+		return w.WriteI16(int16(v.Int()))
+
+	case reflect.Int32:
+		return w.WriteI32(int32(v.Int()))
+
+	case reflect.Int64:
+		return w.WriteI64(int64(v.Int()))
+	}
+
+	panic("not int")
+}
+
+func encodeFloat(w *Writer, v reflect.Value) error {
+	switch v.Type().Kind() {
+	case reflect.Float32:
+		return w.WriteF32(float32(v.Float()))
+	case reflect.Float64:
+		return w.WriteF64(v.Float())
+	}
+
+	panic("not float")
+}
+
+func encodeBool(w *Writer, v reflect.Value) error {
+	return w.WriteBool(v.Bool())
+}
+
+func encodeString(w *Writer, v reflect.Value) error {
+	if v.Kind() != reflect.String {
+		panic("not string")
+	}
+	return w.WriteString(v.String())
+}




diff --git a/encoder/vendor/git.sr.ht/~sircmpwn/go-bare/package.go b/encoder/vendor/git.sr.ht/~sircmpwn/go-bare/package.go
new file mode 100644
index 0000000000000000000000000000000000000000..3851c539124d15a0a94e5677cf3c056c090b7652
--- /dev/null
+++ b/encoder/vendor/git.sr.ht/~sircmpwn/go-bare/package.go
@@ -0,0 +1,8 @@
+// An implementation of the BARE message format for Go.
+//
+// https://git.sr.ht/~sircmpwn/bare
+//
+// See the git repository for usage examples:
+//
+// https://git.sr.ht/~sircmpwn/go-bare
+package bare




diff --git a/encoder/vendor/git.sr.ht/~sircmpwn/go-bare/reader.go b/encoder/vendor/git.sr.ht/~sircmpwn/go-bare/reader.go
new file mode 100644
index 0000000000000000000000000000000000000000..6186373926c697b4efaa227789e3f582839ea4be
--- /dev/null
+++ b/encoder/vendor/git.sr.ht/~sircmpwn/go-bare/reader.go
@@ -0,0 +1,188 @@
+package bare
+
+import (
+	"encoding/binary"
+	"fmt"
+	"io"
+	"math"
+	"unicode/utf8"
+)
+
+type byteReader interface {
+	io.Reader
+	io.ByteReader
+}
+
+// A Reader for BARE primitive types.
+type Reader struct {
+	base    byteReader
+	scratch [8]byte
+}
+
+type simpleByteReader struct {
+	io.Reader
+	scratch [1]byte
+}
+
+func (r simpleByteReader) ReadByte() (byte, error) {
+	// using reference type here saves us allocations
+	_, err := r.Read(r.scratch[:])
+	return r.scratch[0], err
+}
+
+// Returns a new BARE primitive reader wrapping the given io.Reader.
+func NewReader(base io.Reader) *Reader {
+	br, ok := base.(byteReader)
+	if !ok {
+		br = simpleByteReader{Reader: base}
+	}
+	return &Reader{base: br}
+}
+
+func (r *Reader) ReadUint() (uint64, error) {
+	x, err := binary.ReadUvarint(r.base)
+	if err != nil {
+		return x, err
+	}
+	return x, nil
+}
+
+func (r *Reader) ReadU8() (uint8, error) {
+	return r.base.ReadByte()
+}
+
+func (r *Reader) ReadU16() (uint16, error) {
+	var i uint16
+	if _, err := io.ReadAtLeast(r.base, r.scratch[:2], 2); err != nil {
+		return i, err
+	}
+	return binary.LittleEndian.Uint16(r.scratch[:]), nil
+}
+
+func (r *Reader) ReadU32() (uint32, error) {
+	var i uint32
+	if _, err := io.ReadAtLeast(r.base, r.scratch[:4], 4); err != nil {
+		return i, err
+	}
+	return binary.LittleEndian.Uint32(r.scratch[:]), nil
+}
+
+func (r *Reader) ReadU64() (uint64, error) {
+	var i uint64
+	if _, err := io.ReadAtLeast(r.base, r.scratch[:8], 8); err != nil {
+		return i, err
+	}
+	return binary.LittleEndian.Uint64(r.scratch[:]), nil
+}
+
+func (r *Reader) ReadInt() (int64, error) {
+	return binary.ReadVarint(r.base)
+}
+
+func (r *Reader) ReadI8() (int8, error) {
+	b, err := r.base.ReadByte()
+	return int8(b), err
+}
+
+func (r *Reader) ReadI16() (int16, error) {
+	var i int16
+	if _, err := io.ReadAtLeast(r.base, r.scratch[:2], 2); err != nil {
+		return i, err
+	}
+	return int16(binary.LittleEndian.Uint16(r.scratch[:])), nil
+}
+
+func (r *Reader) ReadI32() (int32, error) {
+	var i int32
+	if _, err := io.ReadAtLeast(r.base, r.scratch[:4], 4); err != nil {
+		return i, err
+	}
+	return int32(binary.LittleEndian.Uint32(r.scratch[:])), nil
+}
+
+func (r *Reader) ReadI64() (int64, error) {
+	var i int64
+	if _, err := io.ReadAtLeast(r.base, r.scratch[:], 8); err != nil {
+		return i, err
+	}
+	return int64(binary.LittleEndian.Uint64(r.scratch[:])), nil
+}
+
+func (r *Reader) ReadF32() (float32, error) {
+	u, err := r.ReadU32()
+	f := math.Float32frombits(u)
+	if math.IsNaN(float64(f)) {
+		return 0.0, fmt.Errorf("NaN is not permitted in BARE floats")
+	}
+	return f, err
+}
+
+func (r *Reader) ReadF64() (float64, error) {
+	u, err := r.ReadU64()
+	f := math.Float64frombits(u)
+	if math.IsNaN(f) {
+		return 0.0, fmt.Errorf("NaN is not permitted in BARE floats")
+	}
+	return f, err
+}
+
+func (r *Reader) ReadBool() (bool, error) {
+	b, err := r.ReadU8()
+	if err != nil {
+		return false, err
+	}
+
+	if b > 1 {
+		return false, fmt.Errorf("Invalid bool value: %#x", b)
+	}
+
+	return b == 1, nil
+}
+
+func (r *Reader) ReadString() (string, error) {
+	buf, err := r.ReadData()
+	if err != nil {
+		return "", err
+	}
+	if !utf8.Valid(buf) {
+		return "", ErrInvalidStr
+	}
+	return string(buf), nil
+}
+
+// Reads a fixed amount of arbitrary data, defined by the length of the slice.
+func (r *Reader) ReadDataFixed(dest []byte) error {
+	var amt int = 0
+	for amt < len(dest) {
+		n, err := r.base.Read(dest[amt:])
+		if err != nil {
+			return err
+		}
+		amt += n
+	}
+	return nil
+}
+
+// Reads arbitrary data whose length is read from the message.
+func (r *Reader) ReadData() ([]byte, error) {
+	l, err := r.ReadUint()
+	if err != nil {
+		return nil, err
+	}
+	if l >= maxUnmarshalBytes {
+		return nil, ErrLimitExceeded
+	}
+	buf := make([]byte, l)
+	var amt uint64 = 0
+	for amt < l {
+		n, err := r.base.Read(buf[amt:])
+		amt += uint64(n)
+		if amt == l {
+			break
+		}
+		if err != nil {
+			return nil, err
+		}
+	}
+	return buf, nil
+}




diff --git a/encoder/vendor/git.sr.ht/~sircmpwn/go-bare/unions.go b/encoder/vendor/git.sr.ht/~sircmpwn/go-bare/unions.go
new file mode 100644
index 0000000000000000000000000000000000000000..a9f624c73819455d1c73acf2e3efd4b04b42a347
--- /dev/null
+++ b/encoder/vendor/git.sr.ht/~sircmpwn/go-bare/unions.go
@@ -0,0 +1,76 @@
+package bare
+
+import (
+	"fmt"
+	"reflect"
+)
+
+// Any type which is a union member must implement this interface. You must
+// also call RegisterUnion for go-bare to marshal or unmarshal messages which
+// utilize your union type.
+type Union interface {
+	IsUnion()
+}
+
+type UnionTags struct {
+	iface reflect.Type
+	tags  map[reflect.Type]uint64
+	types map[uint64]reflect.Type
+}
+
+var unionInterface = reflect.TypeOf((*Union)(nil)).Elem()
+var unionRegistry map[reflect.Type]*UnionTags
+
+func init() {
+	unionRegistry = make(map[reflect.Type]*UnionTags)
+}
+
+// Registers a union type in this context. Pass the union interface and the
+// list of types associated with it, sorted ascending by their union tag.
+func RegisterUnion(iface interface{}) *UnionTags {
+	ity := reflect.TypeOf(iface).Elem()
+	if _, ok := unionRegistry[ity]; ok {
+		panic(fmt.Errorf("Type %s has already been registered", ity.Name()))
+	}
+
+	if !ity.Implements(reflect.TypeOf((*Union)(nil)).Elem()) {
+		panic(fmt.Errorf("Type %s does not implement bare.Union", ity.Name()))
+	}
+
+	utypes := &UnionTags{
+		iface: ity,
+		tags:  make(map[reflect.Type]uint64),
+		types: make(map[uint64]reflect.Type),
+	}
+	unionRegistry[ity] = utypes
+	return utypes
+}
+
+func (ut *UnionTags) Member(t interface{}, tag uint64) *UnionTags {
+	ty := reflect.TypeOf(t)
+	if !ty.AssignableTo(ut.iface) {
+		panic(fmt.Errorf("Type %s does not implement interface %s",
+			ty.Name(), ut.iface.Name()))
+	}
+	if _, ok := ut.tags[ty]; ok {
+		panic(fmt.Errorf("Type %s is already registered for union %s",
+			ty.Name(), ut.iface.Name()))
+	}
+	if _, ok := ut.types[tag]; ok {
+		panic(fmt.Errorf("Tag %d is already registered for union %s",
+			tag, ut.iface.Name()))
+	}
+	ut.tags[ty] = tag
+	ut.types[tag] = ty
+	return ut
+}
+
+func (ut *UnionTags) TagFor(v interface{}) (uint64, bool) {
+	tag, ok := ut.tags[reflect.TypeOf(v)]
+	return tag, ok
+}
+
+func (ut *UnionTags) TypeFor(tag uint64) (reflect.Type, bool) {
+	t, ok := ut.types[tag]
+	return t, ok
+}




diff --git a/encoder/vendor/git.sr.ht/~sircmpwn/go-bare/unmarshal.go b/encoder/vendor/git.sr.ht/~sircmpwn/go-bare/unmarshal.go
new file mode 100644
index 0000000000000000000000000000000000000000..614cecaae2ea0a9d77c6aa2c8589362ea7f9de34
--- /dev/null
+++ b/encoder/vendor/git.sr.ht/~sircmpwn/go-bare/unmarshal.go
@@ -0,0 +1,359 @@
+package bare
+
+import (
+	"bytes"
+	"errors"
+	"fmt"
+	"io"
+	"reflect"
+	"sync"
+)
+
+// A type which implements this interface will be responsible for unmarshaling
+// itself when encountered.
+type Unmarshalable interface {
+	Unmarshal(r *Reader) error
+}
+
+// Unmarshals a BARE message into val, which must be a pointer to a value of
+// the message type.
+func Unmarshal(data []byte, val interface{}) error {
+	b := bytes.NewReader(data)
+	r := NewReader(b)
+	return UnmarshalBareReader(r, val)
+}
+
+// Unmarshals a BARE message into value (val, which must be a pointer), from a
+// reader. See Unmarshal for details.
+func UnmarshalReader(r io.Reader, val interface{}) error {
+	r = newLimitedReader(r)
+	return UnmarshalBareReader(NewReader(r), val)
+}
+
+type decodeFunc func(r *Reader, v reflect.Value) error
+
+var decodeFuncCache sync.Map // map[reflect.Type]decodeFunc
+
+func UnmarshalBareReader(r *Reader, val interface{}) error {
+	t := reflect.TypeOf(val)
+	v := reflect.ValueOf(val)
+	if t.Kind() != reflect.Ptr {
+		return errors.New("Expected val to be pointer type")
+	}
+
+	return getDecoder(t.Elem())(r, v.Elem())
+}
+
+// get decoder from cache
+func getDecoder(t reflect.Type) decodeFunc {
+	if f, ok := decodeFuncCache.Load(t); ok {
+		return f.(decodeFunc)
+	}
+
+	f := decoderFunc(t)
+	decodeFuncCache.Store(t, f)
+	return f
+}
+
+var unmarshalableInterface = reflect.TypeOf((*Unmarshalable)(nil)).Elem()
+
+func decoderFunc(t reflect.Type) decodeFunc {
+	if reflect.PtrTo(t).Implements(unmarshalableInterface) {
+		return func(r *Reader, v reflect.Value) error {
+			uv := v.Addr().Interface().(Unmarshalable)
+			return uv.Unmarshal(r)
+		}
+	}
+
+	if t.Kind() == reflect.Interface && t.Implements(unionInterface) {
+		return decodeUnion(t)
+	}
+
+	switch t.Kind() {
+	case reflect.Ptr:
+		return decodeOptional(t.Elem())
+	case reflect.Struct:
+		return decodeStruct(t)
+	case reflect.Array:
+		return decodeArray(t)
+	case reflect.Slice:
+		return decodeSlice(t)
+	case reflect.Map:
+		return decodeMap(t)
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+		return decodeUint
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		return decodeInt
+	case reflect.Float32, reflect.Float64:
+		return decodeFloat
+	case reflect.Bool:
+		return decodeBool
+	case reflect.String:
+		return decodeString
+	}
+
+	return func(r *Reader, v reflect.Value) error {
+		return &UnsupportedTypeError{v.Type()}
+	}
+}
+
+func decodeOptional(t reflect.Type) decodeFunc {
+	return func(r *Reader, v reflect.Value) error {
+		s, err := r.ReadU8()
+		if err != nil {
+			return err
+		}
+
+		if s > 1 {
+			return fmt.Errorf("Invalid optional value: %#x", s)
+		}
+
+		if s == 0 {
+			return nil
+		}
+
+		v.Set(reflect.New(t))
+		return getDecoder(t)(r, v.Elem())
+	}
+}
+
+func decodeStruct(t reflect.Type) decodeFunc {
+	n := t.NumField()
+	decoders := make([]decodeFunc, n)
+	for i := 0; i < n; i++ {
+		field := t.Field(i)
+		if field.Tag.Get("bare") == "-" {
+			continue
+		}
+		decoders[i] = getDecoder(field.Type)
+	}
+
+	return func(r *Reader, v reflect.Value) error {
+		for i := 0; i < n; i++ {
+			if decoders[i] == nil {
+				continue
+			}
+			err := decoders[i](r, v.Field(i))
+			if err != nil {
+				return err
+			}
+		}
+		return nil
+	}
+}
+
+func decodeArray(t reflect.Type) decodeFunc {
+	f := getDecoder(t.Elem())
+	len := t.Len()
+
+	return func(r *Reader, v reflect.Value) error {
+		for i := 0; i < len; i++ {
+			err := f(r, v.Index(i))
+			if err != nil {
+				return err
+			}
+		}
+		return nil
+	}
+}
+
+func decodeSlice(t reflect.Type) decodeFunc {
+	elem := t.Elem()
+	f := getDecoder(elem)
+
+	return func(r *Reader, v reflect.Value) error {
+		len, err := r.ReadUint()
+		if err != nil {
+			return err
+		}
+
+		if len > maxArrayLength {
+			return fmt.Errorf("Array length %d exceeds configured limit of %d", len, maxArrayLength)
+		}
+
+		v.Set(reflect.MakeSlice(t, int(len), int(len)))
+
+		for i := 0; i < int(len); i++ {
+			if err := f(r, v.Index(i)); err != nil {
+				return err
+			}
+		}
+		return nil
+	}
+}
+
+func decodeMap(t reflect.Type) decodeFunc {
+	keyType := t.Key()
+	keyf := getDecoder(keyType)
+
+	valueType := t.Elem()
+	valf := getDecoder(valueType)
+
+	return func(r *Reader, v reflect.Value) error {
+		size, err := r.ReadUint()
+		if err != nil {
+			return err
+		}
+
+		if size > maxMapSize {
+			return fmt.Errorf("Map size %d exceeds configured limit of %d", size, maxMapSize)
+		}
+
+		v.Set(reflect.MakeMapWithSize(t, int(size)))
+
+		key := reflect.New(keyType).Elem()
+		value := reflect.New(valueType).Elem()
+
+		for i := uint64(0); i < size; i++ {
+			if err := keyf(r, key); err != nil {
+				return err
+			}
+
+			if v.MapIndex(key).Kind() > reflect.Invalid {
+				return fmt.Errorf("Encountered duplicate map key: %v", key.Interface())
+			}
+
+			if err := valf(r, value); err != nil {
+				return err
+			}
+
+			v.SetMapIndex(key, value)
+		}
+		return nil
+	}
+}
+
+func decodeUnion(t reflect.Type) decodeFunc {
+	ut, ok := unionRegistry[t]
+	if !ok {
+		return func(r *Reader, v reflect.Value) error {
+			return fmt.Errorf("Union type %s is not registered", t.Name())
+		}
+	}
+
+	decoders := make(map[uint64]decodeFunc)
+	for tag, t := range ut.types {
+		t := t
+		f := getDecoder(t)
+
+		decoders[tag] = func(r *Reader, v reflect.Value) error {
+			nv := reflect.New(t)
+			if err := f(r, nv.Elem()); err != nil {
+				return err
+			}
+
+			v.Set(nv)
+			return nil
+		}
+	}
+
+	return func(r *Reader, v reflect.Value) error {
+		tag, err := r.ReadUint()
+		if err != nil {
+			return err
+		}
+
+		if f, ok := decoders[tag]; ok {
+			return f(r, v)
+		}
+
+		return fmt.Errorf("Invalid union tag %d for type %s", tag, t.Name())
+	}
+}
+
+func decodeUint(r *Reader, v reflect.Value) error {
+	var err error
+	switch getIntKind(v.Type()) {
+	case reflect.Uint:
+		var u uint64
+		u, err = r.ReadUint()
+		v.SetUint(u)
+
+	case reflect.Uint8:
+		var u uint8
+		u, err = r.ReadU8()
+		v.SetUint(uint64(u))
+
+	case reflect.Uint16:
+		var u uint16
+		u, err = r.ReadU16()
+		v.SetUint(uint64(u))
+	case reflect.Uint32:
+		var u uint32
+		u, err = r.ReadU32()
+		v.SetUint(uint64(u))
+
+	case reflect.Uint64:
+		var u uint64
+		u, err = r.ReadU64()
+		v.SetUint(uint64(u))
+
+	default:
+		panic("not an uint")
+	}
+
+	return err
+}
+
+func decodeInt(r *Reader, v reflect.Value) error {
+	var err error
+	switch getIntKind(v.Type()) {
+	case reflect.Int:
+		var i int64
+		i, err = r.ReadInt()
+		v.SetInt(i)
+
+	case reflect.Int8:
+		var i int8
+		i, err = r.ReadI8()
+		v.SetInt(int64(i))
+
+	case reflect.Int16:
+		var i int16
+		i, err = r.ReadI16()
+		v.SetInt(int64(i))
+	case reflect.Int32:
+		var i int32
+		i, err = r.ReadI32()
+		v.SetInt(int64(i))
+
+	case reflect.Int64:
+		var i int64
+		i, err = r.ReadI64()
+		v.SetInt(int64(i))
+
+	default:
+		panic("not an int")
+	}
+
+	return err
+}
+
+func decodeFloat(r *Reader, v reflect.Value) error {
+	var err error
+	switch v.Type().Kind() {
+	case reflect.Float32:
+		var f float32
+		f, err = r.ReadF32()
+		v.SetFloat(float64(f))
+	case reflect.Float64:
+		var f float64
+		f, err = r.ReadF64()
+		v.SetFloat(f)
+	default:
+		panic("not a float")
+	}
+	return err
+}
+
+func decodeBool(r *Reader, v reflect.Value) error {
+	b, err := r.ReadBool()
+	v.SetBool(b)
+	return err
+}
+
+func decodeString(r *Reader, v reflect.Value) error {
+	s, err := r.ReadString()
+	v.SetString(s)
+	return err
+}




diff --git a/encoder/vendor/git.sr.ht/~sircmpwn/go-bare/varint.go b/encoder/vendor/git.sr.ht/~sircmpwn/go-bare/varint.go
new file mode 100644
index 0000000000000000000000000000000000000000..f5043fb63df96bdaa8b8f7b07dd767118210a86e
--- /dev/null
+++ b/encoder/vendor/git.sr.ht/~sircmpwn/go-bare/varint.go
@@ -0,0 +1,27 @@
+package bare
+
+import (
+	"reflect"
+)
+
+// Int is a variable-length encoded signed integer.
+type Int int64
+
+// Uint is a variable-length encoded unsigned integer.
+type Uint uint64
+
+var (
+	intType  = reflect.TypeOf(Int(0))
+	uintType = reflect.TypeOf(Uint(0))
+)
+
+func getIntKind(t reflect.Type) reflect.Kind {
+	switch t {
+	case intType:
+		return reflect.Int
+	case uintType:
+		return reflect.Uint
+	default:
+		return t.Kind()
+	}
+}




diff --git a/encoder/vendor/git.sr.ht/~sircmpwn/go-bare/writer.go b/encoder/vendor/git.sr.ht/~sircmpwn/go-bare/writer.go
new file mode 100644
index 0000000000000000000000000000000000000000..8c54441f25e68579f43160525bfbda20419ee2af
--- /dev/null
+++ b/encoder/vendor/git.sr.ht/~sircmpwn/go-bare/writer.go
@@ -0,0 +1,116 @@
+package bare
+
+import (
+	"encoding/binary"
+	"fmt"
+	"io"
+	"math"
+)
+
+// A Writer for BARE primitive types.
+type Writer struct {
+	base    io.Writer
+	scratch [binary.MaxVarintLen64]byte
+}
+
+// Returns a new BARE primitive writer wrapping the given io.Writer.
+func NewWriter(base io.Writer) *Writer {
+	return &Writer{base: base}
+}
+
+func (w *Writer) WriteUint(i uint64) error {
+	n := binary.PutUvarint(w.scratch[:], i)
+	_, err := w.base.Write(w.scratch[:n])
+	return err
+}
+
+func (w *Writer) WriteU8(i uint8) error {
+	return binary.Write(w.base, binary.LittleEndian, i)
+}
+
+func (w *Writer) WriteU16(i uint16) error {
+	return binary.Write(w.base, binary.LittleEndian, i)
+}
+
+func (w *Writer) WriteU32(i uint32) error {
+	return binary.Write(w.base, binary.LittleEndian, i)
+}
+
+func (w *Writer) WriteU64(i uint64) error {
+	return binary.Write(w.base, binary.LittleEndian, i)
+}
+
+func (w *Writer) WriteInt(i int64) error {
+	var buf [binary.MaxVarintLen64]byte
+	n := binary.PutVarint(buf[:], i)
+	_, err := w.base.Write(buf[:n])
+	return err
+}
+
+func (w *Writer) WriteI8(i int8) error {
+	return binary.Write(w.base, binary.LittleEndian, i)
+}
+
+func (w *Writer) WriteI16(i int16) error {
+	return binary.Write(w.base, binary.LittleEndian, i)
+}
+
+func (w *Writer) WriteI32(i int32) error {
+	return binary.Write(w.base, binary.LittleEndian, i)
+}
+
+func (w *Writer) WriteI64(i int64) error {
+	return binary.Write(w.base, binary.LittleEndian, i)
+}
+
+func (w *Writer) WriteF32(f float32) error {
+	if math.IsNaN(float64(f)) {
+		return fmt.Errorf("NaN is not permitted in BARE floats")
+	}
+	return binary.Write(w.base, binary.LittleEndian, f)
+}
+
+func (w *Writer) WriteF64(f float64) error {
+	if math.IsNaN(f) {
+		return fmt.Errorf("NaN is not permitted in BARE floats")
+	}
+	return binary.Write(w.base, binary.LittleEndian, f)
+}
+
+func (w *Writer) WriteBool(b bool) error {
+	return binary.Write(w.base, binary.LittleEndian, b)
+}
+
+func (w *Writer) WriteString(str string) error {
+	return w.WriteData([]byte(str))
+}
+
+// Writes a fixed amount of arbitrary data, defined by the length of the slice.
+func (w *Writer) WriteDataFixed(data []byte) error {
+	var amt int = 0
+	for amt < len(data) {
+		n, err := w.base.Write(data[amt:])
+		if err != nil {
+			return err
+		}
+		amt += n
+	}
+	return nil
+}
+
+// Writes arbitrary data whose length is encoded into the message.
+func (w *Writer) WriteData(data []byte) error {
+	err := w.WriteUint(uint64(len(data)))
+	if err != nil {
+		return err
+	}
+	var amt int = 0
+	for amt < len(data) {
+		n, err := w.base.Write(data[amt:])
+		if err != nil {
+			return err
+		}
+		amt += n
+	}
+	return nil
+}




diff --git a/encoder/vendor/github.com/codahale/sss/.gitignore b/encoder/vendor/github.com/codahale/sss/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..c56069fe260287c46fab3178e697b9c41b48ef60
--- /dev/null
+++ b/encoder/vendor/github.com/codahale/sss/.gitignore
@@ -0,0 +1 @@
+*.test
\ No newline at end of file




diff --git a/encoder/vendor/github.com/codahale/sss/.travis.yml b/encoder/vendor/github.com/codahale/sss/.travis.yml
new file mode 100644
index 0000000000000000000000000000000000000000..46cc6e78c8a8bbf39fc4c5289e2063f62d800285
--- /dev/null
+++ b/encoder/vendor/github.com/codahale/sss/.travis.yml
@@ -0,0 +1,9 @@
+language: go
+go:
+  - 1.3.3
+notifications:
+  # See http://about.travis-ci.org/docs/user/build-configuration/ to learn more
+  # about configuring notification recipients and more.
+  email:
+    recipients:
+      - coda.hale@gmail.com




diff --git a/encoder/vendor/github.com/codahale/sss/LICENSE b/encoder/vendor/github.com/codahale/sss/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..f9835c241fc479b1a3ca6e71bbb1f6305e7be0bc
--- /dev/null
+++ b/encoder/vendor/github.com/codahale/sss/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Coda Hale
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.




diff --git a/encoder/vendor/github.com/codahale/sss/README.md b/encoder/vendor/github.com/codahale/sss/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..f6590122f7e84468365d39b5deddbbbd63290a67
--- /dev/null
+++ b/encoder/vendor/github.com/codahale/sss/README.md
@@ -0,0 +1,11 @@
+# sss (Shamir's Secret Sharing)
+
+[![Build Status](https://travis-ci.org/codahale/sss.png?branch=master)](https://travis-ci.org/codahale/sss)
+
+A pure Go implementation of
+[Shamir's Secret Sharing algorithm](http://en.wikipedia.org/wiki/Shamir's_Secret_Sharing)
+over GF(2^8).
+
+Inspired by @hbs's [Python implementation](https://github.com/hbs/PySSSS).
+
+For documentation, check [godoc](http://godoc.org/github.com/codahale/sss).




diff --git a/encoder/vendor/github.com/codahale/sss/gf256.go b/encoder/vendor/github.com/codahale/sss/gf256.go
new file mode 100644
index 0000000000000000000000000000000000000000..bff81ae3cb4f563bd8e8bf7b118f852b14eca2ac
--- /dev/null
+++ b/encoder/vendor/github.com/codahale/sss/gf256.go
@@ -0,0 +1,81 @@
+package sss
+
+func mul(e, a byte) byte {
+	if e == 0 || a == 0 {
+		return 0
+	}
+	return exp[(int(log[e])+int(log[a]))%255]
+}
+
+func div(e, a byte) byte {
+	if a == 0 {
+		panic("div by zero")
+	}
+
+	if e == 0 {
+		return 0
+	}
+
+	p := (int(log[e]) - int(log[a])) % 255
+	if p < 0 {
+		p += 255
+	}
+
+	return exp[p]
+}
+
+const (
+	fieldSize = 256 // 2^8
+)
+
+var (
+	// 0x11b prime polynomial and 0x03 as generator
+	exp = [fieldSize]byte{
+		0x01, 0x03, 0x05, 0x0f, 0x11, 0x33, 0x55, 0xff, 0x1a, 0x2e, 0x72, 0x96,
+		0xa1, 0xf8, 0x13, 0x35, 0x5f, 0xe1, 0x38, 0x48, 0xd8, 0x73, 0x95, 0xa4,
+		0xf7, 0x02, 0x06, 0x0a, 0x1e, 0x22, 0x66, 0xaa, 0xe5, 0x34, 0x5c, 0xe4,
+		0x37, 0x59, 0xeb, 0x26, 0x6a, 0xbe, 0xd9, 0x70, 0x90, 0xab, 0xe6, 0x31,
+		0x53, 0xf5, 0x04, 0x0c, 0x14, 0x3c, 0x44, 0xcc, 0x4f, 0xd1, 0x68, 0xb8,
+		0xd3, 0x6e, 0xb2, 0xcd, 0x4c, 0xd4, 0x67, 0xa9, 0xe0, 0x3b, 0x4d, 0xd7,
+		0x62, 0xa6, 0xf1, 0x08, 0x18, 0x28, 0x78, 0x88, 0x83, 0x9e, 0xb9, 0xd0,
+		0x6b, 0xbd, 0xdc, 0x7f, 0x81, 0x98, 0xb3, 0xce, 0x49, 0xdb, 0x76, 0x9a,
+		0xb5, 0xc4, 0x57, 0xf9, 0x10, 0x30, 0x50, 0xf0, 0x0b, 0x1d, 0x27, 0x69,
+		0xbb, 0xd6, 0x61, 0xa3, 0xfe, 0x19, 0x2b, 0x7d, 0x87, 0x92, 0xad, 0xec,
+		0x2f, 0x71, 0x93, 0xae, 0xe9, 0x20, 0x60, 0xa0, 0xfb, 0x16, 0x3a, 0x4e,
+		0xd2, 0x6d, 0xb7, 0xc2, 0x5d, 0xe7, 0x32, 0x56, 0xfa, 0x15, 0x3f, 0x41,
+		0xc3, 0x5e, 0xe2, 0x3d, 0x47, 0xc9, 0x40, 0xc0, 0x5b, 0xed, 0x2c, 0x74,
+		0x9c, 0xbf, 0xda, 0x75, 0x9f, 0xba, 0xd5, 0x64, 0xac, 0xef, 0x2a, 0x7e,
+		0x82, 0x9d, 0xbc, 0xdf, 0x7a, 0x8e, 0x89, 0x80, 0x9b, 0xb6, 0xc1, 0x58,
+		0xe8, 0x23, 0x65, 0xaf, 0xea, 0x25, 0x6f, 0xb1, 0xc8, 0x43, 0xc5, 0x54,
+		0xfc, 0x1f, 0x21, 0x63, 0xa5, 0xf4, 0x07, 0x09, 0x1b, 0x2d, 0x77, 0x99,
+		0xb0, 0xcb, 0x46, 0xca, 0x45, 0xcf, 0x4a, 0xde, 0x79, 0x8b, 0x86, 0x91,
+		0xa8, 0xe3, 0x3e, 0x42, 0xc6, 0x51, 0xf3, 0x0e, 0x12, 0x36, 0x5a, 0xee,
+		0x29, 0x7b, 0x8d, 0x8c, 0x8f, 0x8a, 0x85, 0x94, 0xa7, 0xf2, 0x0d, 0x17,
+		0x39, 0x4b, 0xdd, 0x7c, 0x84, 0x97, 0xa2, 0xfd, 0x1c, 0x24, 0x6c, 0xb4,
+		0xc7, 0x52, 0xf6, 0x01,
+	}
+	log = [fieldSize]byte{
+		0x00, 0x00, 0x19, 0x01, 0x32, 0x02, 0x1a, 0xc6, 0x4b, 0xc7, 0x1b, 0x68,
+		0x33, 0xee, 0xdf, 0x03, 0x64, 0x04, 0xe0, 0x0e, 0x34, 0x8d, 0x81, 0xef,
+		0x4c, 0x71, 0x08, 0xc8, 0xf8, 0x69, 0x1c, 0xc1, 0x7d, 0xc2, 0x1d, 0xb5,
+		0xf9, 0xb9, 0x27, 0x6a, 0x4d, 0xe4, 0xa6, 0x72, 0x9a, 0xc9, 0x09, 0x78,
+		0x65, 0x2f, 0x8a, 0x05, 0x21, 0x0f, 0xe1, 0x24, 0x12, 0xf0, 0x82, 0x45,
+		0x35, 0x93, 0xda, 0x8e, 0x96, 0x8f, 0xdb, 0xbd, 0x36, 0xd0, 0xce, 0x94,
+		0x13, 0x5c, 0xd2, 0xf1, 0x40, 0x46, 0x83, 0x38, 0x66, 0xdd, 0xfd, 0x30,
+		0xbf, 0x06, 0x8b, 0x62, 0xb3, 0x25, 0xe2, 0x98, 0x22, 0x88, 0x91, 0x10,
+		0x7e, 0x6e, 0x48, 0xc3, 0xa3, 0xb6, 0x1e, 0x42, 0x3a, 0x6b, 0x28, 0x54,
+		0xfa, 0x85, 0x3d, 0xba, 0x2b, 0x79, 0x0a, 0x15, 0x9b, 0x9f, 0x5e, 0xca,
+		0x4e, 0xd4, 0xac, 0xe5, 0xf3, 0x73, 0xa7, 0x57, 0xaf, 0x58, 0xa8, 0x50,
+		0xf4, 0xea, 0xd6, 0x74, 0x4f, 0xae, 0xe9, 0xd5, 0xe7, 0xe6, 0xad, 0xe8,
+		0x2c, 0xd7, 0x75, 0x7a, 0xeb, 0x16, 0x0b, 0xf5, 0x59, 0xcb, 0x5f, 0xb0,
+		0x9c, 0xa9, 0x51, 0xa0, 0x7f, 0x0c, 0xf6, 0x6f, 0x17, 0xc4, 0x49, 0xec,
+		0xd8, 0x43, 0x1f, 0x2d, 0xa4, 0x76, 0x7b, 0xb7, 0xcc, 0xbb, 0x3e, 0x5a,
+		0xfb, 0x60, 0xb1, 0x86, 0x3b, 0x52, 0xa1, 0x6c, 0xaa, 0x55, 0x29, 0x9d,
+		0x97, 0xb2, 0x87, 0x90, 0x61, 0xbe, 0xdc, 0xfc, 0xbc, 0x95, 0xcf, 0xcd,
+		0x37, 0x3f, 0x5b, 0xd1, 0x53, 0x39, 0x84, 0x3c, 0x41, 0xa2, 0x6d, 0x47,
+		0x14, 0x2a, 0x9e, 0x5d, 0x56, 0xf2, 0xd3, 0xab, 0x44, 0x11, 0x92, 0xd9,
+		0x23, 0x20, 0x2e, 0x89, 0xb4, 0x7c, 0xb8, 0x26, 0x77, 0x99, 0xe3, 0xa5,
+		0x67, 0x4a, 0xed, 0xde, 0xc5, 0x31, 0xfe, 0x18, 0x0d, 0x63, 0x8c, 0x80,
+		0xc0, 0xf7, 0x70, 0x07,
+	}
+)




diff --git a/encoder/vendor/github.com/codahale/sss/polynomial.go b/encoder/vendor/github.com/codahale/sss/polynomial.go
new file mode 100644
index 0000000000000000000000000000000000000000..b8b183a443103daacb57773d82c3efca1a97a206
--- /dev/null
+++ b/encoder/vendor/github.com/codahale/sss/polynomial.go
@@ -0,0 +1,67 @@
+package sss
+
+import "io"
+
+// the degree of the polynomial
+func degree(p []byte) int {
+	return len(p) - 1
+}
+
+// evaluate the polynomial at the given point
+func eval(p []byte, x byte) (result byte) {
+	// Horner's scheme
+	for i := 1; i <= len(p); i++ {
+		result = mul(result, x) ^ p[len(p)-i]
+	}
+	return
+}
+
+// generates a random n-degree polynomial w/ a given x-intercept
+func generate(degree byte, x byte, rand io.Reader) ([]byte, error) {
+	result := make([]byte, degree+1)
+	result[0] = x
+
+	buf := make([]byte, degree-1)
+	if _, err := io.ReadFull(rand, buf); err != nil {
+		return nil, err
+	}
+
+	for i := byte(1); i < degree; i++ {
+		result[i] = buf[i-1]
+	}
+
+	// the Nth term can't be zero, or else it's a (N-1) degree polynomial
+	for {
+		buf = make([]byte, 1)
+		if _, err := io.ReadFull(rand, buf); err != nil {
+			return nil, err
+		}
+
+		if buf[0] != 0 {
+			result[degree] = buf[0]
+			return result, nil
+		}
+	}
+}
+
+// an input/output pair
+type pair struct {
+	x, y byte
+}
+
+// Lagrange interpolation
+func interpolate(points []pair, x byte) (value byte) {
+	for i, a := range points {
+		weight := byte(1)
+		for j, b := range points {
+			if i != j {
+				top := x ^ b.x
+				bottom := a.x ^ b.x
+				factor := div(top, bottom)
+				weight = mul(weight, factor)
+			}
+		}
+		value = value ^ mul(weight, a.y)
+	}
+	return
+}




diff --git a/encoder/vendor/github.com/codahale/sss/sss.go b/encoder/vendor/github.com/codahale/sss/sss.go
new file mode 100644
index 0000000000000000000000000000000000000000..9221889e5f7d4624eeabf391b8226ae1c673f03e
--- /dev/null
+++ b/encoder/vendor/github.com/codahale/sss/sss.go
@@ -0,0 +1,120 @@
+// Package sss implements Shamir's Secret Sharing algorithm over GF(2^8).
+//
+// Shamir's Secret Sharing algorithm allows you to securely share a secret with
+// N people, allowing the recovery of that secret if K of those people combine
+// their shares.
+//
+// It begins by encoding a secret as a number (e.g., 42), and generating N
+// random polynomial equations of degree K-1 which have an X-intercept equal to
+// the secret. Given K=3, the following equations might be generated:
+//
+//	f1(x) =  78x^2 +  19x + 42
+//	f2(x) = 128x^2 + 171x + 42
+//	f3(x) = 121x^2 +   3x + 42
+//	f4(x) =  91x^2 +  95x + 42
+//	etc.
+//
+// These polynomials are then evaluated for values of X > 0:
+//
+//	f1(1) =  139
+//	f2(2) =  896
+//	f3(3) = 1140
+//	f4(4) = 1783
+//	etc.
+//
+// These (x, y) pairs are the shares given to the parties. In order to combine
+// shares to recover the secret, these (x, y) pairs are used as the input points
+// for Lagrange interpolation, which produces a polynomial which matches the
+// given points. This polynomial can be evaluated for f(0), producing the secret
+// value--the common x-intercept for all the generated polynomials.
+//
+// If fewer than K shares are combined, the interpolated polynomial will be
+// wrong, and the result of f(0) will not be the secret.
+//
+// This package constructs polynomials over the field GF(2^8) for each byte of
+// the secret, allowing for fast splitting and combining of anything which can
+// be encoded as bytes.
+//
+// This package has not been audited by cryptography or security professionals.
+package sss
+
+import (
+	"crypto/rand"
+	"errors"
+)
+
+var (
+	// ErrInvalidCount is returned when the count parameter is invalid.
+	ErrInvalidCount = errors.New("N must be >= K")
+	// ErrInvalidThreshold is returned when the threshold parameter is invalid.
+	ErrInvalidThreshold = errors.New("K must be > 1")
+)
+
+func Add(already, k byte, secret []byte) (byte, []byte, error) {
+	if k <= 1 {
+		return 0, nil, ErrInvalidThreshold
+	}
+
+	share := []byte{}
+	x := already + byte(1)
+
+	for _, b := range secret {
+		p, err := generate(k-1, b, rand.Reader)
+		if err != nil {
+			return 0, nil, err
+		}
+		share = append(share, eval(p, x))
+	}
+	return x, share, nil
+}
+
+// Split the given secret into N shares of which K are required to recover the
+// secret. Returns a map of share IDs (1-255) to shares.
+func Split(n, k byte, secret []byte) (map[byte][]byte, error) {
+	if k <= 1 {
+		return nil, ErrInvalidThreshold
+	}
+
+	if n < k {
+		return nil, ErrInvalidCount
+	}
+
+	shares := make(map[byte][]byte, n)
+
+	for _, b := range secret {
+		p, err := generate(k-1, b, rand.Reader)
+		if err != nil {
+			return nil, err
+		}
+
+		for x := byte(1); x <= n; x++ {
+			shares[x] = append(shares[x], eval(p, x))
+		}
+	}
+
+	return shares, nil
+}
+
+// Combine the given shares into the original secret.
+//
+// N.B.: There is no way to know whether the returned value is, in fact, the
+// original secret.
+func Combine(shares map[byte][]byte) []byte {
+	var secret []byte
+	for _, v := range shares {
+		secret = make([]byte, len(v))
+		break
+	}
+
+	points := make([]pair, len(shares))
+	for i := range secret {
+		p := 0
+		for k, v := range shares {
+			points[p] = pair{x: k, y: v[i]}
+			p++
+		}
+		secret[i] = interpolate(points, 0)
+	}
+
+	return secret
+}




diff --git a/encoder/vendor/modules.txt b/encoder/vendor/modules.txt
new file mode 100644
index 0000000000000000000000000000000000000000..68d4d3e8d0722f73ab48df67afaaf3b0e1179946
--- /dev/null
+++ b/encoder/vendor/modules.txt
@@ -0,0 +1,9 @@
+# apiote.xyz/p/go-dirty v0.0.0-20211218161334-e486e7b5cf43
+## explicit; go 1.16
+apiote.xyz/p/go-dirty
+# git.sr.ht/~sircmpwn/go-bare v0.0.0-20210406120253-ab86bc2846d9
+## explicit; go 1.14
+git.sr.ht/~sircmpwn/go-bare
+# github.com/codahale/sss v0.0.0-20160501174526-0cb9f6d3f7f1
+## explicit
+github.com/codahale/sss




diff --git a/index.html b/index.html
index 5545bdfe18f02ab0e731d91dfb82b6abaa874aba..c8ac1701bbedb306093b2a037a14ccd5864f55ed 100644
--- a/index.html
+++ b/index.html
@@ -24,7 +24,8 @@ 				if (share2.value == '' && share3.value == '') {
 					key = decodePaperKey(share1.value);
 					isPaperKey = true;
 				} else {
-					key = decodeSSS(share1.value, share2.value, share3.value)
+				//fetch ('burnt') ==>
+					key = decodeSSS(share1.value, share2.value, share3.value) //, burnt
 				}
 				if (key.startsWith('ERR: ')) {
 					alert(key);
@@ -40,19 +41,35 @@ 					if (payload.startsWith('ERR: ')) {
 						alert(payload);
 						return;
 					}
-					let secrets = decryptPayload(key, payload, isPaperKey);
-					if (secrets.startsWith('ERR: ')) {
-						alert(secrets);
+					let will_secrets_res = decryptPayload(key, payload, isPaperKey);
+					if (will_secrets_res.startsWith('ERR: ')) {
+						alert(will_secrets);
 						return;
 					}
-					let element = document.createElement('a');
-					let blob = new Blob([secrets], {type: 'text/plain'});
-					element.setAttribute('href', URL.createObjectURL(blob));
-					element.setAttribute('download', 'secrets');
-					element.style.display = 'none';
-					document.body.appendChild(element);
-					element.click();
-					document.body.removeChild(element);
+					let will_secrets = will_secrets_res.split('|');
+					let will = will_secrets[0];
+					let secrets = will_secrets.slice(1).join('|');
+
+					let secretsA = document.createElement('a');
+					let secretsBlob = new Blob([secrets], {type: 'text/plain'});
+					secretsA.setAttribute('href', URL.createObjectURL(secretsBlob));
+					secretsA.setAttribute('download', 'secrets.txt');
+					secretsA.style.display = 'none';
+					document.body.appendChild(secretsA);
+					secretsA.click();
+					document.body.removeChild(secretsA);
+
+					let willA = document.createElement('a');
+					let byteArray = Uint8Array.from(
+						atob(will).split('').map(char => char.charCodeAt(0))
+					);
+					let willBlob =  new Blob([byteArray], { type: 'application/pdf' });
+					willA.setAttribute('href', URL.createObjectURL(willBlob));
+					willA.setAttribute('download', 'will.pdf');
+					willA.style.display = 'none';
+					document.body.appendChild(willA);
+					willA.click();
+					document.body.removeChild(willA);
 				});
 			}
 		</script>




diff --git a/joeblack.wasm b/joeblack.wasm
index 9be92ac7b63df009ee1817b5ee86209ead113f4d..e3218a0cca5de827379ecd45e5ca5638cda0d080 100755
Binary files a/joeblack.wasm and b/joeblack.wasm differ




diff --git a/payload b/payload
deleted file mode 100644
index a05e1de891fc9a02b0c256f6fb25b62ba6e49838..0000000000000000000000000000000000000000
--- a/payload
+++ /dev/null
@@ -1 +0,0 @@
-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
\ No newline at end of file




diff --git a/shared/shared.go b/shared/shared.go
index 430b7ff9565223eda45a5d77ae67811dd965657c..18b2ea03ca2c0b71caebb9e8819be998876c0a20 100644
--- a/shared/shared.go
+++ b/shared/shared.go
@@ -1,6 +1,7 @@
 package main
 
 import (
+	"bytes"
 	"crypto/aes"
 	"crypto/cipher"
 	"crypto/rand"
@@ -9,6 +10,8 @@ 	"fmt"
 	"io"
 	"math/big"
 	"strings"
+
+	"git.sr.ht/~sircmpwn/go-bare"
 )
 
 type SecretEntry struct {
@@ -20,6 +23,55 @@
 type Payload struct {
 	Keys    [][]byte
 	Secrets []byte
+	Will    []byte
+}
+
+func unmarshal(b []byte) (Payload, error) {
+	bare.MaxArrayLength(30720)
+	payload := Payload{
+		Keys: [][]byte{},
+	}
+	buffer := bytes.NewBuffer(b)
+	r := bare.NewReader(buffer)
+	k, err := r.ReadUint()
+	if err != nil {
+		return payload, fmt.Errorf("while reading Keys length: %w", err)
+	}
+	var i uint64 = 0
+	for ; i < k; i++ {
+		l, err := r.ReadUint()
+		if err != nil {
+			return payload, fmt.Errorf("while reading Keys[%d] length: %w", i, err)
+		}
+		data := make([]byte, l)
+		err = r.ReadDataFixed(data)
+		if err != nil {
+			return payload, fmt.Errorf("while reading Keys[%d]: %w", i, err)
+		}
+		payload.Keys = append(payload.Keys, data)
+	}
+	l, err := r.ReadUint()
+	if err != nil {
+		return payload, fmt.Errorf("while reading Secrets length: %w", err)
+	}
+	data := make([]byte, l)
+	err = r.ReadDataFixed(data)
+	if err != nil {
+		return payload, fmt.Errorf("while reading Secrets: %w", err)
+	}
+	payload.Secrets = data
+	l, err = r.ReadUint()
+	if err != nil {
+		return payload, fmt.Errorf("while reading Will length: %w", err)
+	}
+	data = make([]byte, l)
+	err = r.ReadDataFixed(data)
+	if err != nil {
+		return payload, fmt.Errorf("while reading Will: %w", err)
+	}
+	payload.Will = data
+
+	return payload, nil
 }
 
 func encrypt(plaintext, key []byte) ([]byte, error) {