func RunDialRound(client *vrpc.Client, round uint32, onions [][]byte) error { spans := concurrency.Spans(len(onions), 4000) calls := make([]*vrpc.Call, len(spans)) concurrency.ParallelFor(len(calls), func(p *concurrency.P) { for i, ok := p.Next(); ok; i, ok = p.Next() { span := spans[i] calls[i] = &vrpc.Call{ Method: "DialService.Add", Args: &DialAddArgs{ Round: round, Onions: onions[span.Start : span.Start+span.Count], }, Reply: nil, } } }) if err := client.CallMany(calls); err != nil { return fmt.Errorf("Add: %s", err) } if err := client.Call("DialService.Close", round, nil); err != nil { return fmt.Errorf("Close: %s", err) } return nil }
func FillWithFakeSingles(dest [][]byte, nonce *[24]byte, nextKeys []*[32]byte) { concurrency.ParallelFor(len(dest), func(p *concurrency.P) { for i, ok := p.Next(); ok; i, ok = p.Next() { var exchange [SizeConvoExchange]byte rand.Read(exchange[:]) onion, _ := onionbox.Seal(exchange[:], nonce, nextKeys) dest[i] = onion } }) }
func FillWithFakeDoubles(dest [][]byte, nonce *[24]byte, nextKeys []*[32]byte) { concurrency.ParallelFor(len(dest)/2, func(p *concurrency.P) { for i, ok := p.Next(); ok; i, ok = p.Next() { var exchange1 [SizeConvoExchange]byte var exchange2 [SizeConvoExchange]byte rand.Read(exchange1[:]) copy(exchange2[0:16], exchange1[0:16]) rand.Read(exchange2[16:]) onion1, _ := onionbox.Seal(exchange1[:], nonce, nextKeys) onion2, _ := onionbox.Seal(exchange2[:], nonce, nextKeys) dest[i*2] = onion1 dest[i*2+1] = onion2 } }) }
func FillWithFakeIntroductions(dest [][]byte, noiseCounts []uint32, nonce *[24]byte, nextKeys []*[32]byte) { buckets := make([]int, len(dest)) idx := 0 for b, count := range noiseCounts { for i := uint32(0); i < count; i++ { buckets[idx] = b idx++ } } concurrency.ParallelFor(len(dest), func(p *concurrency.P) { for i, ok := p.Next(); ok; i, ok = p.Next() { var exchange [SizeDialExchange]byte binary.BigEndian.PutUint32(exchange[0:4], uint32(buckets[i])) rand.Read(exchange[4:]) onion, _ := onionbox.Seal(exchange[:], nonce, nextKeys) dest[i] = onion } }) }
func RunConvoRound(client *vrpc.Client, round uint32, onions [][]byte) ([][]byte, error) { openArgs := &ConvoOpenArgs{ Round: round, NumIncoming: len(onions), } if err := client.Call("ConvoService.Open", openArgs, nil); err != nil { return nil, fmt.Errorf("Open: %s", err) } spans := concurrency.Spans(len(onions), 4000) calls := make([]*vrpc.Call, len(spans)) concurrency.ParallelFor(len(calls), func(p *concurrency.P) { for i, ok := p.Next(); ok; i, ok = p.Next() { span := spans[i] calls[i] = &vrpc.Call{ Method: "ConvoService.Add", Args: &ConvoAddArgs{ Round: round, Offset: span.Start, Onions: onions[span.Start : span.Start+span.Count], }, Reply: nil, } } }) if err := client.CallMany(calls); err != nil { return nil, fmt.Errorf("Add: %s", err) } if err := client.Call("ConvoService.Close", round, nil); err != nil { return nil, fmt.Errorf("Close: %s", err) } concurrency.ParallelFor(len(calls), func(p *concurrency.P) { for i, ok := p.Next(); ok; i, ok = p.Next() { span := spans[i] calls[i] = &vrpc.Call{ Method: "ConvoService.Get", Args: &ConvoGetArgs{ Round: round, Offset: span.Start, Count: span.Count, }, Reply: new(ConvoGetResult), } } }) if err := client.CallMany(calls); err != nil { return nil, fmt.Errorf("Get: %s", err) } replies := make([][]byte, len(onions)) concurrency.ParallelFor(len(calls), func(p *concurrency.P) { for i, ok := p.Next(); ok; i, ok = p.Next() { span := spans[i] copy(replies[span.Start:span.Start+span.Count], calls[i].Reply.(*ConvoGetResult).Onions) } }) if err := client.Call("ConvoService.Delete", round, nil); err != nil { return nil, fmt.Errorf("Delete: %s", err) } return replies, nil }
func (srv *ConvoService) Close(Round uint32, _ *struct{}) error { log.WithFields(log.Fields{"service": "convo", "rpc": "Close", "round": Round}).Info() round, err := srv.getRound(Round, convoRoundOpen) if err != nil { return err } srv.filterIncoming(round) if !srv.LastServer { round.noiseWg.Wait() outgoing := append(round.incoming, round.noise...) round.noise = nil shuffler := shuffle.New(rand.Reader, len(outgoing)) shuffler.Shuffle(outgoing) if err := NewConvoRound(srv.Client, Round); err != nil { return fmt.Errorf("NewConvoRound: %s", err) } srv.Idle.Unlock() replies, err := RunConvoRound(srv.Client, Round, outgoing) if err != nil { return fmt.Errorf("RunConvoRound: %s", err) } shuffler.Unshuffle(replies) round.replies = replies[:round.numIncoming] } else { exchanges := make([]*ConvoExchange, len(round.incoming)) concurrency.ParallelFor(len(round.incoming), func(p *concurrency.P) { for i, ok := p.Next(); ok; i, ok = p.Next() { exchanges[i] = new(ConvoExchange) if err := exchanges[i].Unmarshal(round.incoming[i]); err != nil { log.WithFields(log.Fields{"bug": true, "call": "ConvoExchange.Unmarshal"}).Error(err) } } }) var singles, doubles int64 deadDrops := make(map[DeadDrop][]int) for i, ex := range exchanges { drop := deadDrops[ex.DeadDrop] if len(drop) == 0 { singles++ deadDrops[ex.DeadDrop] = append(drop, i) } else if len(drop) == 1 { singles-- doubles++ deadDrops[ex.DeadDrop] = append(drop, i) } } round.replies = make([][]byte, len(round.incoming)) concurrency.ParallelFor(len(exchanges), func(p *concurrency.P) { for i, ok := p.Next(); ok; i, ok = p.Next() { ex := exchanges[i] drop := deadDrops[ex.DeadDrop] if len(drop) == 1 { round.replies[i] = ex.EncryptedMessage[:] } if len(drop) == 2 { var k int if i == drop[0] { k = drop[1] } else { k = drop[0] } round.replies[i] = exchanges[k].EncryptedMessage[:] } } }) srv.Idle.Unlock() ac := &AccessCount{ Singles: singles, Doubles: doubles, } select { case srv.AccessCounts <- ac: default: } } round.status = convoRoundClosed return nil }