secure
Secure aggregation.
Classes
SecureShare
class SecureShare(prime_q: int = 2305843009213693951, precision: int = 10000000000):
Additive, replicated, secret sharing algorithm responsible for secure averaging.
This secret sharing implementation is 'additive' because the secret can be reconstructed by taking the sum of all the shares it is split into, and 'replicated' because each party receives more than one share.
The algorithm works as follows: 1. First every worker shares a securely generated random number (between 0 and
prime_q
) with every other worker such that every worker ends up with one
number from every other worker. These numbers are known as shares as they will
form part of the secret (the state dictionary) which will be shared. 2. The values in the state dictionary are then converted to positive integer
field elements of a finite field bounded by prime_q
. 3. The random numbers generated are used to compute a final share for every
value in the state dictionary. This final share has the same shape as the secret
state dictionary. 4. This final share is then reconstructed using the shares retrieved from the
other workers. At this point, the final share from each worker is meaningless
until averaged with every other state dictionary. 5. This final share is sent to the modeller where it will be averaged with the
state dictionaries from all the other workers (all the while in the finite field
space). 6. After averaging, the state dictionaries are finally decoded back to floating
point numpy arrays.
The relationships between individual elements in the tensors are preserved in this implementation since our shares are scalars rather than vectors. Therefore, whilst the secret itself cannot be reconstructed, some properties of the secret can be deciphered e.g. which element is the largest/smallest, etc.
Arguments
prime_q
: Large prime number used in secure aggregation. This should be a few orders of magnitude larger than the precision so that when we add encoded finite field elements with one another, we do not breach the limits of the finite field. Defaults to 2^61 -1 (the largest Mersenne 64 bit Mersenne prime number - for ease).precision
: Degree of precision for floating points in secure aggregation i.e. the number of digits after the decimal point that we want to keep. Defaults to 10^10.
Attributes
prime_q
: Large prime number used in secure aggregation.precision
: Degree of precision for floating points in secure aggregation.
Ancestors
- bitfount.federated.secure._BaseSecureShare
- bitfount.types._BaseSerializableObjectMixIn
Variables
- static
fields_dict : ClassVar[dict[str, marshmallow.fields.Field]]
- static
nested_fields : ClassVar[dict[str, collections.abc.Mapping[str, Any]]]
Methods
average_and_decode_state_dicts
def average_and_decode_state_dicts( self, state_dicts: list[dict[str, np.ndarray]],) ‑> dict:
Averages and decodes multiple encrypted state dictionaries.
Computes the mean of all the state_dicts
before decoding the averaged result
and returning it. This is called on the Modeller side after receiving the state
dictionaries from all the workers.
Arguments
state_dicts
: list of encoded state dictionaries as numpy arrays.
Returns A dictionary of averaged and decoded state dictionaries.
do_secure_aggregation
async def do_secure_aggregation( self, state_dict: Union[_Weights, Mapping[str, np.ndarray]], mailbox: _InterPodWorkerMailbox,) ‑> dict:
Performs secure aggregation.
This is called on the Pod side before sending the state dict to the Modeller.
Arguments
state_dict
: A dictionary of tensors or numpy arrays to be securely aggregated.mailbox
: A mailbox to send and receive messages from other workers.
Returns A dictionary of encoded numpy arrays.