Skip to content

Commit 83d2f24

Browse files
Rework examples (#36)
Update examples
1 parent 465a98a commit 83d2f24

37 files changed

+716
-638
lines changed

examples/broadcasting/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,5 @@ def nada_main():
4343
# How to run the tutorial.
4444

4545
1. First, we need to compile the nada program running: `nada build`.
46-
2. Then, we can test our program is running with: `nada test`.
46+
2. (Optional) Then, we can test our program is running with: `nada test`.
47+
3. Finally, we can call our Nada program via the Nillion python client by running: `python3 main.py`

examples/broadcasting/config.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
"""Configuration variables"""
2+
3+
DIM = 3

examples/broadcasting/main.py

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
"""Broadcasting example script"""
2+
3+
import asyncio
4+
import os
5+
6+
import numpy as np
7+
import py_nillion_client as nillion
8+
from dotenv import load_dotenv
9+
10+
import nada_algebra.client as na_client
11+
# Import helper functions for creating nillion client and getting keys
12+
from examples.broadcasting.config import DIM
13+
from examples.common.nillion_client_helper import create_nillion_client
14+
from examples.common.nillion_keypath_helper import (getNodeKeyFromFile,
15+
getUserKeyFromFile)
16+
from examples.common.utils import compute, store_program, store_secrets
17+
18+
# Load environment variables from a .env file
19+
load_dotenv()
20+
21+
22+
# Main asynchronous function to coordinate the process
23+
async def main() -> None:
24+
"""Main nada program"""
25+
26+
print(f"USING: {DIM} dims")
27+
28+
cluster_id = os.getenv("NILLION_CLUSTER_ID")
29+
userkey = getUserKeyFromFile(os.getenv("NILLION_USERKEY_PATH_PARTY_1"))
30+
nodekey = getNodeKeyFromFile(os.getenv("NILLION_NODEKEY_PATH_PARTY_1"))
31+
client = create_nillion_client(userkey, nodekey)
32+
party_id = client.party_id
33+
user_id = client.user_id
34+
party_names = na_client.parties(3)
35+
program_name = "broadcasting"
36+
program_mir_path = f"target/{program_name}.nada.bin"
37+
38+
# Store the program
39+
program_id = await store_program(
40+
client, user_id, cluster_id, program_name, program_mir_path
41+
)
42+
43+
# Create and store secrets for two parties
44+
A = np.ones([DIM])
45+
C = np.ones([DIM])
46+
A_store_id = await store_secrets(
47+
client,
48+
cluster_id,
49+
program_id,
50+
party_id,
51+
party_names[0],
52+
A,
53+
"A",
54+
nillion.SecretInteger,
55+
)
56+
C_store_id = await store_secrets(
57+
client,
58+
cluster_id,
59+
program_id,
60+
party_id,
61+
party_names[0],
62+
C,
63+
"C",
64+
nillion.SecretInteger,
65+
)
66+
67+
B = np.ones([DIM])
68+
D = np.ones([DIM])
69+
B_store_id = await store_secrets(
70+
client,
71+
cluster_id,
72+
program_id,
73+
party_id,
74+
party_names[1],
75+
B,
76+
"B",
77+
nillion.SecretInteger,
78+
)
79+
D_store_id = await store_secrets(
80+
client,
81+
cluster_id,
82+
program_id,
83+
party_id,
84+
party_names[1],
85+
D,
86+
"D",
87+
nillion.SecretInteger,
88+
)
89+
90+
# Set up the compute bindings for the parties
91+
compute_bindings = nillion.ProgramBindings(program_id)
92+
93+
for party_name in party_names[:-1]:
94+
compute_bindings.add_input_party(party_name, party_id)
95+
compute_bindings.add_output_party(party_names[-1], party_id)
96+
97+
print(f"Computing using program {program_id}")
98+
print(
99+
f"Use secret store_id: {A_store_id}, {B_store_id}, {C_store_id}, {D_store_id}"
100+
)
101+
102+
computation_time_secrets = nillion.Secrets({"my_int2": nillion.SecretInteger(10)})
103+
104+
# Perform the computation and return the result
105+
result = await compute(
106+
client,
107+
cluster_id,
108+
compute_bindings,
109+
[A_store_id, B_store_id, C_store_id, D_store_id],
110+
computation_time_secrets,
111+
)
112+
return result
113+
114+
115+
# Run the main function if the script is executed directly
116+
if __name__ == "__main__":
117+
asyncio.run(main())

examples/broadcasting/network/compute.py

Lines changed: 0 additions & 119 deletions
This file was deleted.

examples/broadcasting/network/helpers/nillion_client_helper.py

Lines changed: 0 additions & 13 deletions
This file was deleted.

examples/broadcasting/network/helpers/nillion_keypath_helper.py

Lines changed: 0 additions & 11 deletions
This file was deleted.

examples/broadcasting/network/helpers/nillion_payments_helper.py

Lines changed: 0 additions & 13 deletions
This file was deleted.

examples/broadcasting/src/broadcasting.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
1-
from nada_dsl import *
1+
"""Broadcasting example program"""
2+
3+
from typing import List
4+
5+
from nada_dsl import Output, SecretInteger
26

3-
# Step 0: Nada Algebra is imported with this line
47
import nada_algebra as na
58

69

7-
def nada_main():
10+
def nada_main() -> List[Output]:
11+
"""
12+
Main Nada program.
13+
14+
Returns:
15+
List[Output]: List of Nada outputs.
16+
"""
817
# Step 1: We use Nada Algebra wrapper to create "Party0", "Party1" and "Party2"
918
parties = na.parties(3)
1019

@@ -24,5 +33,6 @@ def nada_main():
2433
# SIMD operations are performed on all the elements of the array.
2534
# The equivalent would be: for i in range(3): result += a[i] + b[i] - c[i] * d[i]
2635
result = a + b - c * d
27-
# Step 5: We can use result.output() to produce the output for Party2 and variable name "my_output"
36+
# Step 5: We can use result.output() to produce the output for Party2
37+
# and variable name "my_output"
2838
return result.output(parties[2], "my_output")
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
"""Client helpers"""
2+
3+
import os
4+
5+
import py_nillion_client as nillion
6+
7+
from examples.common.nillion_payments_helper import create_payments_config
8+
9+
10+
def create_nillion_client(userkey: str, nodekey: str) -> nillion.NillionClient:
11+
"""
12+
Creates Nillion network client from user and node key.
13+
14+
Args:
15+
userkey (str): User key.
16+
nodekey (str): Node key.
17+
18+
Returns:
19+
nillion.NillionClient: Nillion client object.
20+
"""
21+
bootnodes = [os.getenv("NILLION_BOOTNODE_MULTIADDRESS")]
22+
payments_config = create_payments_config()
23+
24+
return nillion.NillionClient(
25+
nodekey, bootnodes, nillion.ConnectionMode.relay(), userkey, payments_config
26+
)
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
"""Contains key helpers"""
2+
3+
import py_nillion_client as nillion
4+
5+
6+
def getUserKeyFromFile(userkey_filepath: str) -> nillion.UserKey:
7+
"""
8+
Loads user key from file.
9+
10+
Args:
11+
userkey_filepath (str): Path to user key file.
12+
13+
Returns:
14+
nillion.UserKey: User key.
15+
"""
16+
return nillion.UserKey.from_file(userkey_filepath)
17+
18+
19+
def getNodeKeyFromFile(nodekey_filepath: str) -> nillion.NodeKey:
20+
"""
21+
Loads node key from file.
22+
23+
Args:
24+
nodekey_filepath (str): Path to node key file.
25+
26+
Returns:
27+
nillion.NodeKey: Node key.
28+
"""
29+
return nillion.NodeKey.from_file(nodekey_filepath)

0 commit comments

Comments
 (0)