From b7edf7d9ca8b049b5cb63fbb637624e0acd5c241 Mon Sep 17 00:00:00 2001 From: Benjamin Wenger <ben@elixxir.ioo> Date: Thu, 14 Apr 2022 09:30:33 -0700 Subject: [PATCH] improced docs --- cmix/sendCmix.go | 2 +- cmix/sendManyCmix.go | 2 +- single/listener.go | 5 ++++ single/message/request.go | 8 ++++++ single/receivedRequest.go | 7 +++-- single/request.go | 57 ++++++++++++++++++++++++++++++++----- single/responseProcessor.go | 5 +++- 7 files changed, 73 insertions(+), 13 deletions(-) diff --git a/cmix/sendCmix.go b/cmix/sendCmix.go index 409ac2dfb..8b1737e0f 100644 --- a/cmix/sendCmix.go +++ b/cmix/sendCmix.go @@ -32,7 +32,7 @@ import ( "time" ) -// SendCMIX sends a "raw" cMix message payload to the provided recipient. +// Send sends a "raw" cMix message payload to the provided recipient. // Returns the round ID of the round the payload was sent or an error if it // fails. // This does not have end-to-end encryption on it and is used exclusively as diff --git a/cmix/sendManyCmix.go b/cmix/sendManyCmix.go index 6e67eff24..4d634b8ca 100644 --- a/cmix/sendManyCmix.go +++ b/cmix/sendManyCmix.go @@ -41,7 +41,7 @@ type TargetedCmixMessage struct { Mac []byte } -// SendManyCMIX sends many "raw" cMix message payloads to the provided +// SendMany sends many "raw" cMix message payloads to the provided // recipients all in the same round. // Returns the round ID of the round the payloads was sent or an error if it // fails. diff --git a/single/listener.go b/single/listener.go index cf49e7868..d2f17233a 100644 --- a/single/listener.go +++ b/single/listener.go @@ -32,6 +32,11 @@ type listener struct { net cmix.Client } +// Listen allows a server to listen for single use requests. It will register +// a service relative to the tag and myID as the identifier. Only a single +// listener can be active for a tag-myID pair, and error will return if that +// is violated. When requests are receved, they will be called on the +// Receiver interface. func Listen(tag string, myId *id.ID, privkey *cyclic.Int, net cmix.Client, e2eGrp *cyclic.Group, cb Receiver) Listener { diff --git a/single/message/request.go b/single/message/request.go index a09d07223..60f372e8b 100644 --- a/single/message/request.go +++ b/single/message/request.go @@ -55,6 +55,10 @@ func NewRequest(externalPayloadSize, pubKeySize int) Request { return tm } +func GetRequestPayloadSize(externalPayloadSize, pubKeySize int) uint { + return uint(externalPayloadSize - transmitMessageVersionSize - pubKeySize) +} + // mapRequest builds a message mapped to the passed in data. It is // mapped by reference; a copy is not made. func mapRequest(data []byte, pubKeySize int) Request { @@ -160,6 +164,10 @@ func NewRequestPayload(payloadSize int, payload []byte, maxMsgs uint8) RequestPa return mp } +func GetRequestContentsSize(payloadSize uint) uint { + return payloadSize - transmitPlMinSize +} + // mapRequestPayload builds a message payload mapped to the passed in // data. It is mapped by reference; a copy is not made. func mapRequestPayload(data []byte) RequestPayload { diff --git a/single/receivedRequest.go b/single/receivedRequest.go index 7ac766881..c425cc9dd 100644 --- a/single/receivedRequest.go +++ b/single/receivedRequest.go @@ -66,7 +66,10 @@ func (r Request) String() string { r.dhKey.Text(10), r.tag, r.maxParts) } -// +// Respond is used to respond to the request. It sends a payload up to +// r.GetMaxResponseLength(). It will chunk the message into multiple +// cmix messages if it is too long for a single message. It will fail +// If a single cmix message cannot be sent. func (r Request) Respond(payload []byte, cmixParams cmix.CMIXParams, timeout time.Duration) ([]id.Round, error) { // make sure this has only been run once @@ -108,8 +111,6 @@ func (r Request) Respond(payload []byte, cmixParams cmix.CMIXParams, failed := uint32(0) for i := 0; i < len(parts); i++ { - // fixme: handle the case where a send fails, also on failures, - // unset use go func(j int) { defer wg.Done() partFP, ecrPart, mac := cyphers[j].Encrypt(parts[j]) diff --git a/single/request.go b/single/request.go index c464eec42..cd8a5c04a 100644 --- a/single/request.go +++ b/single/request.go @@ -21,20 +21,61 @@ import ( "time" ) +// Response interface allows for callbacks to type Response interface { Callback(payload []byte, receptionID receptionID.EphemeralIdentity, round rounds.Round, err error) } type RequestParams struct { - Timeout time.Duration - MaxMessages uint8 - CmixParam cmix.CMIXParams + Timeout time.Duration + MaxResponseMessages uint8 + CmixParam cmix.CMIXParams } +func GetDefaultRequestParams() RequestParams { + return RequestParams{ + Timeout: 30 * time.Second, + MaxResponseMessages: 255, + CmixParam: cmix.GetDefaultCMIXParams(), + } +} + +// GetMaxRequestSize returns the max size of a request payload +func GetMaxRequestSize(net cmix.Client, e2eGrp *cyclic.Group) uint { + payloadSize := message.GetRequestPayloadSize(net.GetMaxMessageLength(), + e2eGrp.GetP().ByteLen()) + return message.GetRequestContentsSize(payloadSize) +} + +/* Single is a system which allows for an end to end encrypted anonymous + request to be sent to another cmix client, and for them to respond. The + system allows for communication over the mixnet without an interactive + key negotiation because the payload inherently carries the negotiation with + it. When sending a new request, a client create a new discreet log Dh keypair + as well as a new ID. As a result of the fact that the client never + identifies itself, the system allows the client to stay anonymous while + contacting the remote. +*/ + +// TransmitRequest Sends a request to the recipient with the given tag containing +// the given payload. The request is identified as coming from a new user ID and +// the recipient of the request responds to that address. As a result, this request +// does not reveal the identity of the sender, +// the current implementation only allows for a cing cmix request payload. +// Because the request payload itself must include negotiation materials, it is +// limited to just a few thousand bits of payload, and will return an error if +// the payload is too large. GetMaxRequestSize() can be used to get this max +// size +// The network follower must be running and healthy to transmit func TransmitRequest(recipient contact.Contact, tag string, payload []byte, callback Response, param RequestParams, net cmix.Client, rng csprng.Source, e2eGrp *cyclic.Group) (id.Round, receptionID.EphemeralIdentity, error) { + if !net.IsHealthy() { + return 0, receptionID.EphemeralIdentity{}, errors.New("Cannot " + + "send singe use when network is not healthy") + } + // get address ID address space size; this blocks until the address space // size is set for the first time addressSize := net.GetAddressSpace() @@ -50,7 +91,7 @@ func TransmitRequest(recipient contact.Contact, tag string, payload []byte, request := message.NewRequest(net.GetMaxMessageLength(), e2eGrp.GetP().ByteLen()) requestPayload := message.NewRequestPayload(request.GetPayloadSize(), - payload, param.MaxMessages) + payload, param.MaxResponseMessages) // Generate new user ID and address ID var sendingID receptionID.EphemeralIdentity @@ -73,7 +114,7 @@ func TransmitRequest(recipient contact.Contact, tag string, payload []byte, request.SetPayload(encryptedPayload) //register the response pickup - collator := message.NewCollator(param.MaxMessages) + collator := message.NewCollator(param.MaxResponseMessages) timeoutKillChan := make(chan bool) callbackOnce := sync.Once{} wrapper := func(payload []byte, receptionID receptionID.EphemeralIdentity, @@ -88,9 +129,9 @@ func TransmitRequest(recipient contact.Contact, tag string, payload []byte, }) } - cyphers := makeCyphers(dhKey, param.MaxMessages) + cyphers := makeCyphers(dhKey, param.MaxResponseMessages) - for i := uint8(0); i < param.MaxMessages; i++ { + for i := uint8(0); i < param.MaxResponseMessages; i++ { processor := responceProcessor{ sendingID: sendingID, c: collator, @@ -196,6 +237,8 @@ func makeIDs(msg message.RequestPayload, publicKey *cyclic.Int, }, nil } +// waitForTimeout is a long running thread which handles timing out a request. +// It can be canceled by channel func waitForTimeout(kill chan bool, callback callbackWrapper, timeout time.Duration) { timer := time.NewTimer(timeout) select { diff --git a/single/responseProcessor.go b/single/responseProcessor.go index 9eb56ef2b..7fca2e88b 100644 --- a/single/responseProcessor.go +++ b/single/responseProcessor.go @@ -12,7 +12,8 @@ import ( type callbackWrapper func(payload []byte, receptionID receptionID.EphemeralIdentity, round rounds.Round, err error) -//by fingerprint +// responceProcessor Message.Processor interface registered with cmix.Client. +// One is registered for each potential fingerprint. type responceProcessor struct { sendingID receptionID.EphemeralIdentity c *message.Collator @@ -22,6 +23,8 @@ type responceProcessor struct { recipient *contact.Contact } +// Process decrypts a response part and adds it to the collator - returning +// a full response to the callback when all parts are received. func (rsp *responceProcessor) Process(ecrMsg format.Message, receptionID receptionID.EphemeralIdentity, round rounds.Round) { -- GitLab