viff
view viff/runtime.py @ 1429:b2b8e4a74cd6
runtime: print statistics with --statistics option.
| author | Martin Geisler <mg@cs.au.dk> |
|---|---|
| date | Sun Jan 24 17:29:26 2010 +0100 (2 years ago) |
| parents | 2324d01c74e2 |
| children | 1772506977cc |
line source
1 # -*- coding: utf-8 -*-
2 #
3 # Copyright 2007, 2008, 2009 VIFF Development Team.
4 #
5 # This file is part of VIFF, the Virtual Ideal Functionality Framework.
6 #
7 # VIFF is free software: you can redistribute it and/or modify it
8 # under the terms of the GNU Lesser General Public License (LGPL) as
9 # published by the Free Software Foundation, either version 3 of the
10 # License, or (at your option) any later version.
11 #
12 # VIFF is distributed in the hope that it will be useful, but WITHOUT
13 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
15 # Public License for more details.
16 #
17 # You should have received a copy of the GNU Lesser General Public
18 # License along with VIFF. If not, see <http://www.gnu.org/licenses/>.
20 """VIFF runtime. This is where the virtual ideal functionality is
21 hiding! The runtime is responsible for sharing inputs, handling
22 communication, and running the calculations.
24 Each player participating in the protocol will instantiate a
25 :class:`Runtime` object and use it for the calculations.
27 The Runtime returns :class:`Share` objects for most operations, and
28 these can be added, subtracted, and multiplied as normal thanks to
29 overloaded arithmetic operators. The runtime will take care of
30 scheduling things correctly behind the scenes.
31 """
56 """A shared number.
58 The :class:`Runtime` operates on shares, represented by this class.
59 Shares are asynchronous in the sense that they promise to attain a
60 value at some point in the future.
62 Shares overload the arithmetic operations so that ``x = a + b``
63 will create a new share *x*, which will eventually contain the
64 sum of *a* and *b*. Each share is associated with a
65 :class:`Runtime` and the arithmetic operations simply call back to
66 that runtime.
67 """
70 """Initialize a share.
72 If an initial value is given, it will be passed to
73 :meth:`callback` right away.
74 """
100 """Addition."""
104 """Addition (reflected argument version)."""
108 """Subtraction."""
112 """Subtraction (reflected argument version)."""
116 """Multiplication."""
120 """Multiplication (reflected argument version)."""
124 """Exponentation to known integer exponents."""
128 """Exclusive-or."""
132 """Exclusive-or (reflected argument version)."""
136 """Strictly less-than comparison."""
137 # self < other <=> not (self >= other)
141 """Less-than or equal comparison."""
142 # self <= other <=> other >= self
146 """Strictly greater-than comparison."""
147 # self > other <=> not (other >= self)
151 """Greater-than or equal comparison."""
152 # self >= other
156 """Equality testing."""
160 """Negated equality testing."""
165 """Clone a share.
167 Works like :meth:`util.clone_deferred` except that it returns a new
168 :class:`Share` instead of a :class:`Deferred`.
169 """
180 """Create a share that waits on a number of other shares.
182 Roughly modelled after the Twisted :class:`DeferredList`
183 class. The advantage of this class is that it is a :class:`Share`
184 (not just a :class:`Deferred`) and that it can be made to trigger
185 when a certain threshold of the shares are ready. This example
186 shows how the :meth:`pprint` callback is triggered when *a* and
187 *c* are ready:
189 >>> from pprint import pprint
190 >>> from viff.field import GF256
191 >>> a = Share(None, GF256)
192 >>> b = Share(None, GF256)
193 >>> c = Share(None, GF256)
194 >>> shares = ShareList([a, b, c], threshold=2)
195 >>> shares.addCallback(pprint) # doctest: +ELLIPSIS
196 <ShareList at 0x...>
197 >>> a.callback(10)
198 >>> c.callback(20)
199 [(True, 10), None, (True, 20)]
201 The :meth:`pprint` function is called with a list of pairs. The first
202 component of each pair is a boolean indicating if the callback or
203 errback method was called on the corresponding :class:`Share`, and
204 the second component is the value given to the callback/errback.
206 If a threshold less than the full number of shares is used, some
207 of the pairs may be missing and :const:`None` is used instead. In
208 the example above the *b* share arrived later than *a* and *c*,
209 and so the list contains a :const:`None` on its place.
210 """
212 """Initialize a share list.
214 The list of shares must be non-empty and if a threshold is
215 given, it must hold that ``0 < threshold <= len(shares)``. The
216 default threshold is ``len(shares)``.
217 """
220 "Threshold out of range"
244 """Gather shares.
246 Roughly modelled after the Twisted :meth:`gatherResults`
247 function. It takes a list of shares and returns a new
248 :class:`Share` which will be triggered with a list of values,
249 namely the values from the initial shares:
251 >>> from pprint import pprint
252 >>> from viff.field import GF256
253 >>> a = Share(None, GF256)
254 >>> b = Share(None, GF256)
255 >>> shares = gather_shares([a, b])
256 >>> shares.addCallback(pprint) # doctest: +ELLIPSIS
257 <ShareList at 0x...>
258 >>> a.callback(10)
259 >>> b.callback(20)
260 [10, 20]
261 """
271 """Send and receive shares.
273 All players are connected by pair-wise connections and this
274 Twisted protocol is one such connection. It is used to send and
275 receive shares from one other player.
276 """
281 #: Data expected to be received in the future.
284 #: Statistics
296 """Called when a share is received.
298 The string received is unpacked into the program counter, and
299 a data part. The data is passed the appropriate Deferred in
300 :class:`self.incoming_data`.
301 """
303 # TODO: Handle ValueError if the string cannot be decoded.
310 # The player ID are stored in the serial number of the
311 # certificate -- this makes it easy to check that the
312 # player is who he claims to be.
342 """Send data to the peer.
344 The *program_counter* is a tuple of unsigned integers, the
345 *data_type* is an unsigned byte and *data* is a string.
347 The data is encoded as follows::
349 +---------+-----------+-----------+--------+--------------+
350 | pc_size | data_size | data_type | pc | data |
351 +---------+-----------+-----------+--------+--------------+
352 2 bytes 2 bytes 1 byte varies varies
354 The program counter takes up ``4 * pc_size`` bytes, the data
355 takes up ``data_size`` bytes.
356 """
367 """Send a share.
369 The program counter and the share are converted to bytes and
370 sent to the peer.
371 """
375 """Disconnect this protocol instance."""
386 """Called when a share is received.
388 The string received is unpacked into the program counter, and
389 a data part. The data is passed the appropriate Deferred in
390 :class:`self.incoming_data`.
391 """
408 """Send data to the self.id."""
412 """Disconnect this protocol instance."""
418 """Factory for creating SelfShareExchanger protocols."""
425 """Initialize the factory."""
439 """Factory for creating ShareExchanger protocols."""
446 """Initialize the factory."""
463 """Track calls to this method.
465 The decorated method will be replaced with a proxy method which
466 first tries to get the data needed from
467 :attr:`Runtime._pool`, and if that fails it falls back to the
468 original method. It also returns a flag to indicate whether the
469 data is from the pool.
471 The *generator* method is only used to record where the data
472 should be generated from, the method is not actually called. This
473 must be the name of the method (a string) and not the method
474 itself.
475 """
500 """Basic VIFF runtime with no crypto.
502 This runtime contains only the most basic operations needed such
503 as the program counter, the list of other players, etc.
504 """
506 @staticmethod
535 # Using __import__ since we do not use the module, we are
536 # only interested in the side-effect.
551 """Initialize runtime.
553 Initialized a runtime owned by the given, the threshold, and
554 optionally a set of options. The runtime has no network
555 connections and knows of no other players -- the
556 :func:`create_runtime` function should be used instead to
557 create a usable runtime.
558 """
560 #: ID of this player.
562 #: Shamir secret sharing threshold.
576 #: Pool of preprocessed data.
578 #: Description of needed preprocessed data.
581 #: Current program counter.
584 #: Connections to the other players.
585 #:
586 #: Mapping from from Player ID to :class:`ShareExchanger`
587 #: objects.
590 #: Number of known players.
591 #:
592 #: Equal to ``len(self.players)``, but storing it here is more
593 #: direct.
596 #: Information on players.
597 #:
598 #: Mapping from Player ID to :class:`Player` objects.
600 # Add ourselves, but with no protocol since we wont be
601 # communicating with ourselves.
606 #: Queue of deferreds and data.
609 #: Counter for calls of activate_reactor().
611 #: Record the recursion depth.
614 #: Recursion depth limit by experiment, including security margin.
616 #: Use deferred queues only if the ViffReactor is running.
625 """Shutdown the runtime.
627 All connections are closed and the runtime cannot be used
628 again after this has been called.
629 """
653 """Abort the execution due to an exception.
655 The *protocol* received bad data which resulted in *exc* being
656 raised when unpacking.
657 """
666 """Make the runtime wait for the variables given.
668 The runtime is shut down when all variables are calculated.
669 """
674 """Increment the program counter."""
678 """Fork the program counter."""
682 """Leave a fork of the program counter."""
686 """Schedule a callback on a deferred with the correct program
687 counter.
689 If a callback depends on the current program counter, then use
690 this method to schedule it instead of simply calling
691 addCallback directly. Simple callbacks that are independent of
692 the program counter can still be added directly to the
693 Deferred as usual.
695 Any extra arguments are passed to the callback as with
696 :meth:`addCallback`.
697 """
703 """Wrapper for a callback which ensures a correct PC."""
715 """Schedule a complex callback, i.e. a callback which blocks a
716 long time.
718 Consider that the deferred is forked, i.e. if the callback returns
719 something to be used afterwards, add further callbacks to the returned
720 deferred."""
737 """Introduce a synchronization point.
739 Returns a :class:`Deferred` which will trigger if and when all
740 other players have made their calls to :meth:`synchronize`. By
741 adding callbacks to the returned :class:`Deferred`, one can
742 divide a protocol execution into disjoint phases.
743 """
752 # Convert self.program_counter to a hashable value in order to
753 # use it as a key in self.protocols[peer_id].incoming_data.
761 # We have already received some data from the other side.
768 # We have not yet received anything from the other side.
773 """Exchange shares with another player.
775 We send the player our share and record a Deferred which will
776 trigger when the share from the other side arrives.
777 """
795 """Generate preprocess material.
797 The *program* specifies which methods to call and with which
798 arguments. The generator methods called must adhere to the
799 following interface:
801 - They must return a list of :class:`Deferred` instances.
803 - Every Deferred must yield an item of pre-processed data.
804 This can be value, a list or tuple of values, or a Deferred
805 (which will be converted to a value by Twisted), but NOT a
806 list of Deferreds. Use :meth:`gatherResults` to avoid the
807 latter.
809 The :meth:`~viff.active.TriplesPRSSMixin.generate_triples` method
810 is an example of a method fulfilling this interface.
811 """
814 # Update the pool with pairs of program counter and data.
840 """Input *number* to the computation.
842 The players listed in *inputters* must provide an input
843 number, everybody will receive a list with :class:`Share`
844 objects, one from each *inputter*. If only a single player is
845 listed in *inputters*, then a :class:`Share` is given back
846 directly.
847 """
851 """Open *share* to *receivers* (defaults to all players).
853 Returns a :class:`Share` to players with IDs in *receivers*
854 and :const:`None` to the remaining players.
855 """
859 """Secure addition.
861 At least one of the arguments must be a :class:`Share`, the
862 other can be a :class:`~viff.field.FieldElement` or a
863 (possible long) Python integer."""
867 """Secure multiplication.
869 At least one of the arguments must be a :class:`Share`, the
870 other can be a :class:`~viff.field.FieldElement` or a
871 (possible long) Python integer."""
875 """Put deferred and data into the queue if the ViffReactor is running.
876 Otherwise, just execute the callback."""
884 """Execute the callbacks of the deferreds in the queue.
886 If this function is not called via activate_reactor(), also
887 complex callbacks are executed."""
895 """Execute the callbacks of the deferreds in *queue*."""
902 """Activate the reactor to do actual communcation.
904 This is where the recursion happens."""
907 return
911 # setting the number to n makes the reactor called
912 # only every n-th time
917 # Record the maximal depth reached.
929 """Print the amount of transferred data for all connections."""
937 """Creates a new runtime class with *runtime_class* as a base
938 class mixing in the *mixins*. By default
939 :class:`viff.passive.PassiveRuntime` will be used.
940 """
942 # The import is put here because of circular depencencies
943 # between viff.runtime and viff.passive.
949 # The order is important: we want the most specific classes to
950 # go first so that they can override methods from later
951 # classes. We must also include at least one new-style class
952 # in bases -- we include it last to avoid overriding __init__
953 # from the other base classes.
958 """Create a :class:`Runtime` and connect to the other players.
960 This function should be used in normal programs instead of
961 instantiating the Runtime directly. This function makes sure that
962 the Runtime is correctly connected to the other players.
964 The return value is a Deferred which will trigger when the runtime
965 is ready. Add your protocol as a callback on this Deferred using
966 code like this::
968 def protocol(runtime):
969 a, b, c = runtime.shamir_share([1, 2, 3], Zp, input)
971 a = runtime.open(a)
972 b = runtime.open(b)
973 c = runtime.open(c)
975 dprint("Opened a: %s", a)
976 dprint("Opened b: %s", b)
977 dprint("Opened c: %s", c)
979 runtime.wait_for(a,b,c)
981 pre_runtime = create_runtime(id, players, 1)
982 pre_runtime.addCallback(protocol)
984 This is the general template which VIFF programs should follow.
985 Please see the example applications for more examples.
987 """
990 # Five times per second seems like a fair value. Besides, the
991 # kernel will track the peak memory usage for us anyway.
996 # The import is put here because of circular depencencies
997 # between viff.runtime and viff.passive.
1002 # To collect profiling information we monkey patch reactor.run
1003 # to do the collecting. It would be nicer to simply start the
1004 # profiler here and stop it upon shutdown, but this triggers
1005 # http://bugs.python.org/issue1375 since the start and stop
1006 # calls are in different stack frames.
1016 print
1023 # This will yield a Runtime when all protocols are connected.
1026 # Create a runtime that knows about no other players than itself.
1027 # It will eventually be returned in result when the factory has
1028 # determined that all needed protocols are ready.
1043 """Create new SSL context factory for *id*."""
1046 # TODO: Make the file names configurable.
1076 # We keep trying to listen on the port, but with an
1077 # exponentially increasing delay between each attempt.
1082 raise
1095 # Process the deferred queue after every reactor iteration.
