package primitives

import (
	"golang.org/x/crypto/ed25519"
	"golang.org/x/crypto/sha3"
)

// Perform3DH encapsulates a triple-diffie-hellman key exchange.
// In this exchange Alice and Bob both hold longterm identity keypairs
// Both Alice and Bob generate an additional ephemeral key pair:
// Three Diffie Hellman exchanges are then performed:
// Alice Long Term <-> Bob Ephemeral
// Alice Ephemeral <-> Bob Long Term
// Alice Ephemeral <-> Bob Ephemeral
//
// Through this, a unique session key is derived. The exchange is offline-deniable (in the context of Tapir and Onion Service)
func Perform3DH(longtermIdentity *Identity, ephemeralIdentity *Identity, remoteLongTermPublicKey ed25519.PublicKey, remoteEphemeralPublicKey ed25519.PublicKey, outbound bool) ([32]byte, error) {
	// 3DH Handshake
	l2e, err1 := longtermIdentity.EDH(remoteEphemeralPublicKey)
	e2l, err2 := ephemeralIdentity.EDH(remoteLongTermPublicKey)
	e2e, err3 := ephemeralIdentity.EDH(remoteEphemeralPublicKey)

	if err1 != nil || err2 != nil || err3 != nil {
		return [32]byte{}, err1
	}

	// We need to define an order for the result concatenation so that both sides derive the same key.
	var result [96]byte
	if outbound {
		copy(result[0:32], l2e)
		copy(result[32:64], e2l)
		copy(result[64:96], e2e)
	} else {
		copy(result[0:32], e2l)
		copy(result[32:64], l2e)
		copy(result[64:96], e2e)
	}
	return sha3.Sum256(result[:]), nil
}
