Skip to main content

Compute

Perform single or multi party computation using secrets stored in the network.

Single Party Computeโ€‹

Single party compute involves only one Party that provides inputs and receives outputs of a program. Single party compute examples are available in the Python Starter Repo core_concept_single_party_compute folder.

Example: addition_simple.pyโ€‹

The addition_simple example is a single party compute example that adds two secret integers. In the client code, the first secret integer is stored in the network ahead of time, and the second secret integer is provided at computation time.

examples_and_tutorials/core_concept_single_party_compute/addition_simple.py
    PrivateKey,
)
from dotenv import load_dotenv

home = os.getenv("HOME")
load_dotenv(f"{home}/.config/nillion/nillion-devnet.env")


# 1 Party running simple addition on 1 stored secret and 1 compute time secret
async def main():
# Use the devnet configuration generated by `nillion-devnet`
network = Network.from_config("devnet")

# Create payments config and set up Nillion wallet with a private key to pay for operations
nilchain_key: str = os.getenv("NILLION_NILCHAIN_PRIVATE_KEY_0") # type: ignore
payer = NilChainPayer(
network,
wallet_private_key=NilChainPrivateKey(bytes.fromhex(nilchain_key)),
gas_limit=10000000,
)

# Use a random key to identify ourselves
signing_key = PrivateKey()
client = await VmClient.create(signing_key, network, payer)
party_name = "Party1"
program_name = "addition_simple"
program_mir_path = f"../nada_programs/target/{program_name}.nada.bin"

# Adding funds to the client balance so the upcoming operations can be paid for
funds_amount = 3000000
print(f"๐Ÿ’ฐ Adding some funds to the client balance: {funds_amount} uNIL")
await client.add_funds(funds_amount)

##### STORE PROGRAM
print("-----STORE PROGRAM")

# Store program
program_mir = open(program_mir_path, "rb").read()
program_id = await client.store_program(program_name, program_mir).invoke()

# Print details about stored program
print(f"Stored program_id: {program_id}")

##### STORE SECRETS
print("-----STORE SECRETS")

# Create a secret
values = {
"my_int1": SecretInteger(500),
}

# Create a permissions object to attach to the stored secret
permissions = Permissions.defaults_for_user(client.user_id).allow_compute(
client.user_id, program_id
)

# Store a secret, passing in the receipt that shows proof of payment
values_id = await client.store_values(
values, ttl_days=5, permissions=permissions
).invoke()

# Print details about stored program
print(f"Stored secret values_id: {values_id}")

##### COMPUTE
print("-----COMPUTE")

# Bind the parties in the computation to the client to set input and output parties
input_bindings = [InputPartyBinding(party_name, client.user_id)]
output_bindings = [OutputPartyBinding(party_name, [client.user_id])]

# Create a computation time secret to use
compute_time_values = {"my_int2": SecretInteger(10)}

# Compute, passing in the compute time values as well as the previously uploaded value.
print(f"Invoking computation using program_id: {program_id} and secret values_id: {values_id}")
compute_id = await client.compute(
program_id,
input_bindings,
output_bindings,
values=compute_time_values,
value_ids=[values_id],
).invoke()

# Print compute result
print(f"The computation was sent to the network. compute_id: {compute_id}")
result = await client.retrieve_compute_results(compute_id).invoke()
print(f"โœ… Compute complete for compute_id {compute_id}")
print(f"๐Ÿ–ฅ๏ธ The result is {result}")
balance = await client.balance()
print(f"๐Ÿ’ฐ Final client balance: {balance.balance} Credits")
client.close()
return result


if __name__ == "__main__":
asyncio.run(main())


@pytest.mark.asyncio
async def test_main():
result = await main()
assert result == {"my_output": SecretInteger(510)}

Multi Party Computeโ€‹

Multi party compute involves more than one Party. These Parties collaborate to provide secret inputs and one Party receives outputs of the program.

The core_concept_multi_party_compute folder has a 3-step multi party compute example involving multiple parties providing secret inputs for computation of a program. The first party stores a secret, then N other parties store permissioned secrets giving the first party compute access. The first party computes with all secrets.

examples_and_tutorials/core_concept_multi_party_compute/README.md
# Multi Party Example

This is an example using the Nillion Python Client to store a program, and run multi party compute, computation involving secret inputs from multiple parties.

## Run the example

1. Ensure the `nillion-devnet` is running (this will write the local devnet configs to your machine, which will be picked up by the examples in this repo) or ensure you are reading the real network environments into the examples.

2. Ensure the multi party program you want to run (defined in `config.py`) is compiled, by running `nada build` in the `nada_programs` directory.

3. Run the scripts in number order, starting with `01_store_program.py`, check the ouputs of each script to get the
inputs to the next.
Feedback