diff --git a/sphinx.go b/sphinx.go index 9b7a97a..c136261 100644 --- a/sphinx.go +++ b/sphinx.go @@ -4,6 +4,7 @@ import ( "bytes" "crypto/hmac" "crypto/sha256" + "errors" "fmt" "io" "math/big" @@ -784,3 +785,42 @@ func (t *Tx) Commit() ([]ProcessedPacket, *ReplaySet, error) { return t.packets, rs, err } + +// ProcessOnionPacketWithExternalSigner uses an external sharedSecretGenerator +func (r *Router) ProcessOnionPacketWithExternalSigner( + onionPkt *OnionPacket, + assocData []byte, + incomingCltv uint32, + sharedSecretGenerator func(dhKey *btcec.PublicKey) (Hash256, error), +) (*ProcessedPacket, error) { + + if sharedSecretGenerator == nil { + return nil, errors.New("no sharedSecretGenerator") + } + + // Compute the shared secret for this onion packet. + sharedSecret, err := sharedSecretGenerator(onionPkt.EphemeralKey) + if err != nil { + return nil, err + } + + // Additionally, compute the hash prefix of the shared secret, which + // will serve as an identifier for detecting replayed packets. + hashPrefix := hashSharedSecret(&sharedSecret) + + // Continue to optimistically process this packet, deferring replay + // protection until the end to reduce the penalty of multiple IO + // operations. + packet, err := processOnionPacket(onionPkt, &sharedSecret, assocData, r) + if err != nil { + return nil, err + } + + // Atomically compare this hash prefix with the contents of the on-disk + // log, persisting it only if this entry was not detected as a replay. + if err := r.log.Put(hashPrefix, incomingCltv); err != nil { + return nil, err + } + + return packet, nil +}