diff --git a/pkg/wire/onion.go b/pkg/wire/onion.go index 97f71cd8..8d42ca4e 100644 --- a/pkg/wire/onion.go +++ b/pkg/wire/onion.go @@ -135,8 +135,8 @@ func SendPurchase(nBytes uint64, client *node.Node, // their section at the top, moves the next layer header to the top and pads the // remainder with noise, so it always looks like the first hop, // indistinguishable. -func SendExit(payload slice.Bytes, port uint16, client node.Node, - hop [5]node.Node, set signer.KeySet) types.Onion { +func SendExit(payload slice.Bytes, port uint16, client *node.Node, + hop [5]*node.Node, set *signer.KeySet) types.Onion { var replies [3]*prv.Key for i := range replies { @@ -152,6 +152,7 @@ func SendExit(payload slice.Bytes, port uint16, client node.Node, pubs[1] = hop[4].PayloadKey pubs[2] = hop[3].PayloadKey return OnionSkins{}. + Forward(hop[0].AddrPort). OnionSkin(address.FromPubKey(hop[0].HeaderKey), set.Next()). Forward(hop[1].AddrPort). OnionSkin(address.FromPubKey(hop[1].HeaderKey), set.Next()). diff --git a/pkg/wire/onion_test.go b/pkg/wire/onion_test.go index 29bc999d..4984875c 100644 --- a/pkg/wire/onion_test.go +++ b/pkg/wire/onion_test.go @@ -9,10 +9,13 @@ import ( "github.com/Indra-Labs/indra/pkg/key/signer" "github.com/Indra-Labs/indra/pkg/node" "github.com/Indra-Labs/indra/pkg/nonce" + "github.com/Indra-Labs/indra/pkg/sha256" "github.com/Indra-Labs/indra/pkg/slice" + "github.com/Indra-Labs/indra/pkg/testutils" "github.com/Indra-Labs/indra/pkg/types" "github.com/Indra-Labs/indra/pkg/wire/cipher" "github.com/Indra-Labs/indra/pkg/wire/confirmation" + "github.com/Indra-Labs/indra/pkg/wire/exit" "github.com/Indra-Labs/indra/pkg/wire/forward" "github.com/Indra-Labs/indra/pkg/wire/layer" "github.com/Indra-Labs/indra/pkg/wire/purchase" @@ -28,11 +31,9 @@ func PeelForward(t *testing.T, b slice.Bytes, var e error if on, e = PeelOnion(b, c); check(e) { t.Error(e) - t.FailNow() } if fwd, ok = on.(*forward.OnionSkin); !ok { t.Error("did not unwrap expected type", reflect.TypeOf(fwd)) - t.FailNow() } return } @@ -45,11 +46,9 @@ func PeelOnionSkin(t *testing.T, b slice.Bytes, var e error if on, e = PeelOnion(b, c); check(e) { t.Error(e) - t.FailNow() } if l, ok = on.(*layer.OnionSkin); !ok { t.Error("did not unwrap expected type", reflect.TypeOf(l)) - t.FailNow() } return } @@ -62,11 +61,9 @@ func PeelConfirmation(t *testing.T, b slice.Bytes, var on types.Onion if on, e = PeelOnion(b, c); check(e) { t.Error(e) - t.FailNow() } if cn, ok = on.(*confirmation.OnionSkin); !ok { t.Error("did not unwrap expected type", reflect.TypeOf(on)) - t.FailNow() } return } @@ -79,11 +76,9 @@ func PeelPurchase(t *testing.T, b slice.Bytes, var on types.Onion if on, e = PeelOnion(b, c); check(e) { t.Error(e) - t.FailNow() } if pr, ok = on.(*purchase.OnionSkin); !ok { t.Error("did not unwrap expected type", reflect.TypeOf(on)) - t.FailNow() } return } @@ -96,10 +91,25 @@ func PeelReply(t *testing.T, b slice.Bytes, var on types.Onion if on, e = PeelOnion(b, c); check(e) { t.Error(e) - t.FailNow() } if rp, ok = on.(*reply.OnionSkin); !ok { t.Error("did not unwrap expected type", reflect.TypeOf(on)) + } + return +} + +func PeelExit(t *testing.T, b slice.Bytes, + c *slice.Cursor) (ex *exit.OnionSkin) { + + var ok bool + var e error + var on types.Onion + if on, e = PeelOnion(b, c); check(e) { + t.Error(e) + t.FailNow() + } + if ex, ok = on.(*exit.OnionSkin); !ok { + t.Error("did not unwrap expected type", reflect.TypeOf(on)) t.FailNow() } return @@ -407,3 +417,107 @@ func TestSendPurchase(t *testing.T) { PeelOnionSkin(t, b, c).Decrypt(client.HeaderPriv, b, c) } + +func TestSendExit(t *testing.T) { + log2.CodeLoc = true + _, ks, e := signer.New() + if check(e) { + t.Error(e) + t.FailNow() + } + var hop [5]*node.Node + for i := range hop { + prv1, prv2 := GetTwoPrvKeys(t) + pub1, pub2 := pub.Derive(prv1), pub.Derive(prv2) + hop[i], _ = node.New(slice.GenerateRandomAddrPortIPv4(), + pub1, pub2, prv1, prv2, nil) + } + cprv1, cprv2 := GetTwoPrvKeys(t) + cpub1, cpub2 := pub.Derive(cprv1), pub.Derive(cprv2) + var client *node.Node + client, _ = node.New(slice.GenerateRandomAddrPortIPv4(), + cpub1, cpub2, cprv1, cprv2, nil) + port := uint16(rand.Uint32()) + var message slice.Bytes + var hash sha256.Hash + message, hash, e = testutils.GenerateTestMessage(2502) + on := SendExit(message, port, client, hop, ks) + b := EncodeOnion(on) + c := slice.NewCursor() + + // Forward(hop[0].AddrPort). + f0 := PeelForward(t, b, c) + if hop[0].AddrPort.String() != f0.AddrPort.String() { + t.Errorf("failed to unwrap expected: '%s', got '%s'", + hop[0].AddrPort.String(), f0.AddrPort.String()) + t.FailNow() + } + + // OnionSkin(address.FromPubKey(hop[0].HeaderKey), set.Next()). + PeelOnionSkin(t, b, c).Decrypt(hop[0].HeaderPriv, b, c) + + // Forward(hop[1].AddrPort). + f1 := PeelForward(t, b, c) + if hop[1].AddrPort.String() != f1.AddrPort.String() { + t.Errorf("failed to unwrap expected: '%s', got '%s'", + hop[0].AddrPort.String(), f1.AddrPort.String()) + t.FailNow() + } + + // OnionSkin(address.FromPubKey(hop[1].HeaderKey), set.Next()). + PeelOnionSkin(t, b, c).Decrypt(hop[1].HeaderPriv, b, c) + + // Forward(hop[2].AddrPort). + f2 := PeelForward(t, b, c) + if hop[2].AddrPort.String() != f2.AddrPort.String() { + t.Errorf("failed to unwrap expected: '%s', got '%s'", + hop[1].AddrPort.String(), f1.AddrPort.String()) + t.FailNow() + } + + // OnionSkin(address.FromPubKey(hop[2].HeaderKey), set.Next()). + PeelOnionSkin(t, b, c).Decrypt(hop[2].HeaderPriv, b, c) + + // Exit(port, prvs, pubs, payload). + pr := PeelExit(t, b, c) + if pr.Port != port { + t.Errorf("failed to retrieve original purchase nBytes") + t.FailNow() + } + mh := sha256.Single(pr.Bytes) + if mh != hash { + t.Errorf("exit message not correctly decoded") + t.FailNow() + } + + // Reply(hop[3].AddrPort). + rp1 := PeelReply(t, b, c) + if rp1.AddrPort.String() != hop[3].AddrPort.String() { + t.Errorf("failed to retrieve first reply hop") + t.FailNow() + } + + // OnionSkin(address.FromPubKey(hop[3].HeaderKey), replies[0]). + PeelOnionSkin(t, b, c).Decrypt(hop[3].HeaderPriv, b, c) + + // Reply(hop[4].AddrPort). + rp2 := PeelReply(t, b, c) + if rp2.AddrPort.String() != hop[4].AddrPort.String() { + t.Errorf("failed to retrieve first reply hop") + t.FailNow() + } + + // OnionSkin(address.FromPubKey(hop[4].HeaderKey), replies[1]). + PeelOnionSkin(t, b, c).Decrypt(hop[4].HeaderPriv, b, c) + + // Reply(client.AddrPort). + rp3 := PeelReply(t, b, c) + if rp3.AddrPort.String() != client.AddrPort.String() { + t.Errorf("failed to retrieve first reply hop") + t.FailNow() + } + + // OnionSkin(address.FromPubKey(client.HeaderKey), replies[2]). + PeelOnionSkin(t, b, c).Decrypt(client.HeaderPriv, b, c) + +} diff --git a/version.go b/version.go index f672746c..2ca1b603 100644 --- a/version.go +++ b/version.go @@ -10,11 +10,11 @@ var ( // GitRef is the gitref, as in refs/heads/branchname. GitRef = "refs/heads/main" // ParentGitCommit is the commit hash of the parent HEAD. - ParentGitCommit = "d0f01299850523d31a346ebb568a513612c75a9a" + ParentGitCommit = "c0f78dd95dffe2d6bebe6e219bc6954ea10ab5f7" // BuildTime stores the time when the current binary was built. - BuildTime = "2022-12-27T17:54:58Z" + BuildTime = "2022-12-27T18:05:32Z" // SemVer lists the (latest) git tag on the build. - SemVer = "v0.0.245" + SemVer = "v0.0.246" // PathBase is the path base returned from runtime caller. PathBase = "/home/loki/src/github.com/Indra-Labs/indra/" // Major is the major number from the tag. @@ -22,7 +22,7 @@ var ( // Minor is the minor number from the tag. Minor = 0 // Patch is the patch version number from the tag. - Patch = 245 + Patch = 246 ) // Version returns a pretty printed version information string.