func computeFillers(nodes []config.MixConfig, tuples []HeaderInitials) (string, error) {
	filler := ""
	minLen := headerLength - 32
	for i := 1; i < len(nodes); i++ {
		base := filler + strings.Repeat("\x00", K)
		kx, err := computeSharedSecretHash(tuples[i-1].SecretHash, []byte("hrhohrhohrhohrho"))
		if err != nil {
			return "", err
		}
		mx := strings.Repeat("\x00", minLen) + base
		xorVal, err := AesCtr(kx, []byte(mx))
		if err != nil {
			errMsg := fmt.Errorf("error in computeFillers - AES_CTR failed: %v", err)
			return "", errMsg
		}
		filler = BytesToString(xorVal)
		filler = filler[minLen:]
		minLen -= K
	}
	return filler, nil
}
TODO: computeFillers needs to be fixed
package sphinx
import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"errors"
	"fmt"
	"strings"
	"github.com/golang/protobuf/proto"
	"github.com/nymtech/nym-mixnet/config"
	"github.com/nymtech/nym-mixnet/flags"
	"golang.org/x/crypto/curve25519"
)
const (
	K            = 16
	headerLength = 192
)
func PackForwardMessage(path config.E2EPath, delays []float64, message []byte) (SphinxPacket, error) {
	nodes := []config.MixConfig{path.IngressProvider}
	nodes = append(nodes, path.Mixes...)
	nodes = append(nodes, path.EgressProvider)
	dest := path.Recipient
	headerInitials, header, err := createHeader(nodes, delays, dest)
	if err != nil {
		errMsg := fmt.Errorf("error in PackForwardMessage - createHeader failed: %v", err)
		return SphinxPacket{}, errMsg
	}
	payload, err := encapsulateContent(headerInitials, message)
	if err != nil {
		errMsg := fmt.Errorf("error in PackForwardMessage - encapsulateContent failed: %v", err)
		return SphinxPacket{}, errMsg
	}
	return SphinxPacket{Hdr: &header, Pld: payload}, nil
}
func createHeader(nodes []config.MixConfig,
	delays []float64,
	dest config.ClientConfig,
) ([]HeaderInitials, Header, error) {
	x, err := RandomElement()
	if err != nil {
		errMsg := fmt.Errorf("error in createHeader - Random failed: %v", err)
		return nil, Header{}, errMsg
	}
	headerInitials, err := getSharedSecrets(nodes, x)
	if err != nil {
		errMsg := fmt.Errorf("error in createHeader - getSharedSecrets failed: %v", err)
		return nil, Header{}, errMsg
	}
	if len(headerInitials) != len(nodes) {
		errMsg := fmt.Errorf("error in createHeader - wrong number of shared secrets failed: %v", err)
		return nil, Header{}, errMsg
	}
	commands := make([]Commands, len(nodes))
	for i := range nodes {
		var c Commands
		if i == len(nodes)-1 {
			c = Commands{Delay: delays[i], Flag: flags.LastHopFlag.Bytes()}
		} else {
			c = Commands{Delay: delays[i], Flag: flags.RelayFlag.Bytes()}
		}
		commands[i] = c
	}
	header, err := encapsulateHeader(headerInitials, nodes, commands, dest)
	if err != nil {
		errMsg := fmt.Errorf("error in createHeader - encapsulateHeader failed: %v", err)
		return nil, Header{}, errMsg
	}
	return headerInitials, header, nil
}
func encapsulateHeader(headerInitials []HeaderInitials,
	nodes []config.MixConfig,
	commands []Commands,
	destination config.ClientConfig,
) (Header, error) {
	finalHop := RoutingInfo{NextHop: &Hop{Id: destination.Id,
		Address: destination.Host + ":" + destination.Port,
		PubKey:  []byte{},
	}, RoutingCommands: &commands[len(commands)-1],
		NextHopMetaData: []byte{},
		Mac:             []byte{},
	}
	finalHopBytes, err := proto.Marshal(&finalHop)
	if err != nil {
		return Header{}, err
	}
	kdfRes, err := KDF(headerInitials[len(headerInitials)-1].SecretHash)
	if err != nil {
		return Header{}, err
	}
	encFinalHop, err := AesCtr(kdfRes, finalHopBytes)
	if err != nil {
		errMsg := fmt.Errorf("error in encapsulateHeader - AES_CTR encryption failed: %v", err)
		return Header{}, errMsg
	}
	mac, err := computeMac(kdfRes, encFinalHop)
	if err != nil {
		return Header{}, err
	}
	routingCommands := [][]byte{encFinalHop}
	var encRouting []byte
	for i := len(nodes) - 2; i >= 0; i-- {
		nextNode := nodes[i+1]
		routing := RoutingInfo{NextHop: &Hop{Id: nextNode.Id,
			Address: nextNode.Host + ":" + nextNode.Port,
			PubKey:  nodes[i+1].PubKey,
		}, RoutingCommands: &commands[i],
			NextHopMetaData: routingCommands[len(routingCommands)-1],
			Mac:             mac,
		}
		encKey, err := KDF(headerInitials[i].SecretHash)
		if err != nil {
			return Header{}, err
		}
		routingBytes, err := proto.Marshal(&routing)
		if err != nil {
			return Header{}, err
		}
		encRouting, err = AesCtr(encKey, routingBytes)
		if err != nil {
			return Header{}, err
		}
		routingCommands = append(routingCommands, encRouting)
		kdfResL, err := KDF(headerInitials[i].SecretHash)
		if err != nil {
			return Header{}, nil
		}
		mac, err = computeMac(kdfResL, encRouting)
		if err != nil {
			return Header{}, err
		}
	}
	return Header{Alpha: headerInitials[0].Alpha, Beta: encRouting, Mac: mac}, nil
}
func encapsulateContent(headerInitials []HeaderInitials, message []byte) ([]byte, error) {
	enc := message
	for i := len(headerInitials) - 1; i >= 0; i-- {
		sharedKey, err := KDF(headerInitials[i].SecretHash)
		if err != nil {
			return nil, err
		}
		enc, err = AesCtr(sharedKey, enc)
		if err != nil {
			errMsg := fmt.Errorf("error in encapsulateContent - AES_CTR encryption failed: %v", err)
			return nil, errMsg
		}
	}
	return enc, nil
}
func getSharedSecrets(nodes []config.MixConfig, initialVal *FieldElement) ([]HeaderInitials, error) {
	blindFactors := []*FieldElement{initialVal}
	tuples := make([]HeaderInitials, len(nodes))
	for i, n := range nodes {
		alpha := expoGroupBase(blindFactors)
		if len(n.PubKey) != PublicKeySize {
			errMsg := fmt.Errorf("invalid public key provided for node %v", i)
			return nil, errMsg
		}
		s := expo(BytesToPublicKey(n.PubKey).ToFieldElement(), blindFactors)
		aesS, err := KDF(s.Bytes())
		if err != nil {
			return nil, err
		}
		blinder, err := computeBlindingFactor(aesS)
		if err != nil {
			errMsg := fmt.Errorf("error in getSharedSecrets - computeBlindingFactor failed: %v", err)
			return nil, errMsg
		}
		blindFactors = append(blindFactors, blinder)
		tuples[i] = HeaderInitials{Alpha: alpha.Bytes(), Secret: s.Bytes(), Blinder: blinder.Bytes(), SecretHash: aesS}
	}
	return tuples, nil
}