40 lines
1.4 KiB

package primitives
import (
// 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