Power

This section demonstrates raising secret-shared values to a power. As always, this is computed element-wise on arrays of any shape.

Note that for this function, we are raising secret-shared values to a public, unencoded, integer power that is known to all players. The results are secret shared, maintaining the privacy of the inputs.

In this case, we raise a vector of values \([-1, 2, 3.4, -2.3]\) to the power 3, returning \([-1, 8, 39.304, -12.167]\)

[1]:
import logging

import numpy

from cicada.additive import AdditiveProtocolSuite
from cicada.communicator import SocketCommunicator
from cicada.logging import Logger

logging.basicConfig(level=logging.INFO)

def main(communicator):
    log = Logger(logging.getLogger(), communicator)
    protocol = AdditiveProtocolSuite(communicator)

    base = numpy.array([-1, 2, 3.4, -2.3]) if communicator.rank == 0 else None
    exponent = numpy.array(3, dtype=int)

    log.info(f"Player {communicator.rank} base: {base}", src=0)
    log.info(f"Player {communicator.rank} exponent: {exponent}")

    base_share = protocol.share(src=0, secret=base, shape=(4,))
    power_share = protocol.power(base_share, exponent)
    power = protocol.reveal(power_share)
    log.info(f"Player {communicator.rank} power: {power}")

SocketCommunicator.run(world_size=3, fn=main);
INFO:root:Player 0 base: [-1.   2.   3.4 -2.3]
INFO:root:Player 0 exponent: 3
INFO:root:Player 1 exponent: 3
INFO:root:Player 2 exponent: 3
INFO:root:Player 0 power: [ -1.           8.          39.30377197 -12.16679382]
INFO:root:Player 1 power: [ -1.           8.          39.30377197 -12.16679382]
INFO:root:Player 2 power: [ -1.           8.          39.30377197 -12.16679382]

Note that the results 39.30381775 and -12.16680908 are slightly off due to the limited precision of our fixed point encoding.