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
}
encapsulateHeader layer encrypts the meta-data of the packet, containing information about the
sequence of nodes the packet should traverse before reaching the destination, and message authentication codes,
given the pre-computed shared keys which are used for encryption.
encapsulateHeader returns the Header, or an error if any internal cryptographic of parsing operation failed.
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
}