├── .github └── workflows │ └── sync-main-to-release.yaml ├── .gitignore ├── .nil-sdk.toml ├── LICENSE ├── README.md ├── quickstart └── client_code │ └── run_my_first_program.py ├── quickstart_complete ├── client_code │ └── secret_addition_complete.py └── nada_quickstart_programs │ ├── nada-project.toml │ ├── src │ └── secret_addition_complete.py │ ├── target │ └── secret_addition_complete.nada.bin │ └── tests │ └── secret_addition_complete.yaml └── requirements.txt /.github/workflows/sync-main-to-release.yaml: -------------------------------------------------------------------------------- 1 | name: sync 'main' branch to 'release' 2 | on: 3 | push: 4 | branches: 5 | - main 6 | 7 | permissions: write-all 8 | 9 | jobs: 10 | sync-branches: 11 | runs-on: ubuntu-latest 12 | name: sync main to release 13 | steps: 14 | 15 | - name: checkout 'release' 16 | uses: actions/checkout@v4 17 | with: 18 | ref: release 19 | 20 | - name: rebase onto 'main' 21 | id: rebase 22 | continue-on-error: true 23 | run: | 24 | git fetch origin main 25 | git rebase origin/main 26 | 27 | - name: push changes to 'release' 28 | if: success() && steps.rebase.outcome == 'success' 29 | run: | 30 | git push origin release --force-with-lease 31 | 32 | - name: open pr on rebase failure 33 | id: pull 34 | if: steps.rebase.outcome == 'failure' 35 | uses: TreTuna/sync-branches@1.4.0 36 | with: 37 | FROM_BRANCH: "main" 38 | TO_BRANCH: "release" 39 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 40 | PULL_REQUEST_TITLE: "chore: sync main -> release" 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/*.pyc 2 | **/__pycache__ 3 | nillion-venv/ 4 | permissions/.nillion-config.json 5 | examples_and_tutorials/nada_programs/target 6 | quickstart_complete/nada_quickstart_programs/target 7 | .env 8 | .idea 9 | .DS_Store 10 | *.key 11 | 12 | .venv -------------------------------------------------------------------------------- /.nil-sdk.toml: -------------------------------------------------------------------------------- 1 | version = "v0.9.0" -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Nillion 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Nillion Python Starter 2 | 3 | Welcome to the start of your Nillion developer journey. 4 | 5 | This repo corresponds to the Nillion Python quickstart. To get started with Nillion head over to the [Python QuickStart docs](https://docs.nillion.com/python-quickstart) and follow the quickstart guide. 6 | 7 | For more python examples, check out https://github.com/NillionNetwork/python-examples which contains the following: 8 | - core_concept_multi_party_compute 9 | - core_concept_permissions 10 | - core_concept_single_party_compute 11 | - core_concept_store_and_retrieve_secrets 12 | - millionaires_problem_example 13 | - nada_programs 14 | - voting_tutorial 15 | -------------------------------------------------------------------------------- /quickstart/client_code/run_my_first_program.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NillionNetwork/nillion-python-starter/fddab100439b38a1fb701a88d1c70fedd92ac287/quickstart/client_code/run_my_first_program.py -------------------------------------------------------------------------------- /quickstart_complete/client_code/secret_addition_complete.py: -------------------------------------------------------------------------------- 1 | """ 2 | In this example, we: 3 | 1. import packages we'll be using 4 | 2. connect to the local nillion-devnet 5 | 3. store the secret addition program 6 | 4. store a secret to be used in the computation 7 | 5. compute the secret addition program with the stored secret and another computation time secret 8 | 6. return the computation result 9 | """ 10 | 11 | import asyncio 12 | import os 13 | 14 | from nillion_client import ( 15 | InputPartyBinding, 16 | Network, 17 | NilChainPayer, 18 | NilChainPrivateKey, 19 | OutputPartyBinding, 20 | Permissions, 21 | SecretInteger, 22 | VmClient, 23 | PrivateKey, 24 | ) 25 | from dotenv import load_dotenv 26 | 27 | home = os.getenv("HOME") 28 | load_dotenv(f"{home}/.config/nillion/nillion-devnet.env") 29 | 30 | 31 | async def main(): 32 | # 2. Initial setup/config, then initialize the NillionClient against nillion-devnet 33 | # Use the devnet configuration generated by `nillion-devnet` 34 | network = Network.from_config("devnet") 35 | 36 | # Create payments config and set up Nillion wallet with a private key to pay for operations 37 | nilchain_key: str = os.getenv("NILLION_NILCHAIN_PRIVATE_KEY_0") # type: ignore 38 | payer = NilChainPayer( 39 | network, 40 | wallet_private_key=NilChainPrivateKey(bytes.fromhex(nilchain_key)), 41 | gas_limit=10000000, 42 | ) 43 | 44 | # Use a random key to identify ourselves 45 | signing_key = PrivateKey() 46 | client = await VmClient.create(signing_key, network, payer) 47 | party_name = "Party1" 48 | program_name = "secret_addition_complete" 49 | program_mir_path = f"../nada_quickstart_programs/target/{program_name}.nada.bin" 50 | 51 | # Adding funds to the client balance so the upcoming operations can be paid for 52 | funds_amount = 3000000 53 | print(f"💰 Adding some funds to the client balance: {funds_amount} uNIL") 54 | await client.add_funds(funds_amount) 55 | 56 | # 3. Store the program 57 | print("-----STORE PROGRAM") 58 | 59 | # Store program 60 | program_mir = open(program_mir_path, "rb").read() 61 | program_id = await client.store_program(program_name, program_mir).invoke() 62 | 63 | # Print details about stored program 64 | print(f"Stored program_id: {program_id}") 65 | 66 | # 4. Create the 1st secret, add permissions and store it in the network 67 | print("-----STORE SECRETS") 68 | 69 | # Create a secret 70 | values = { 71 | "my_int1": SecretInteger(500), 72 | } 73 | 74 | # Create a permissions object to attach to the stored secret 75 | permissions = Permissions.defaults_for_user(client.user_id).allow_compute( 76 | client.user_id, program_id 77 | ) 78 | 79 | # Store a secret 80 | values_id = await client.store_values( 81 | values, ttl_days=5, permissions=permissions 82 | ).invoke() 83 | 84 | # 5. Create compute bindings to set input and output parties, add a computation time secret and pay for & run the computation 85 | print("-----COMPUTE") 86 | 87 | # Bind the parties in the computation to the client to set input and output parties 88 | input_bindings = [InputPartyBinding(party_name, client.user_id)] 89 | output_bindings = [OutputPartyBinding(party_name, [client.user_id])] 90 | 91 | # Create a computation time secret to use 92 | compute_time_values = {"my_int2": SecretInteger(10)} 93 | 94 | # Compute, passing in the compute time values as well as the previously uploaded value. 95 | print(f"Invoking computation using program {program_id} and values id {values_id}") 96 | compute_id = await client.compute( 97 | program_id, 98 | input_bindings, 99 | output_bindings, 100 | values=compute_time_values, 101 | value_ids=[values_id], 102 | ).invoke() 103 | 104 | # 6. Return the computation result 105 | print(f"The computation was sent to the network. compute_id: {compute_id}") 106 | result = await client.retrieve_compute_results(compute_id).invoke() 107 | print(f"✅ Compute complete for compute_id {compute_id}") 108 | print(f"🖥️ The result is {result}") 109 | balance = await client.balance() 110 | print(f"💰 Final client balance: {balance.balance} Credits") 111 | client.close() 112 | return result 113 | 114 | 115 | if __name__ == "__main__": 116 | asyncio.run(main()) 117 | -------------------------------------------------------------------------------- /quickstart_complete/nada_quickstart_programs/nada-project.toml: -------------------------------------------------------------------------------- 1 | name = "quick_start_programs" 2 | version = "0.1.0" 3 | authors = [""] 4 | 5 | [[programs]] 6 | path = "src/secret_addition_complete.py" 7 | prime_size = 128 8 | -------------------------------------------------------------------------------- /quickstart_complete/nada_quickstart_programs/src/secret_addition_complete.py: -------------------------------------------------------------------------------- 1 | from nada_dsl import * 2 | def nada_main(): 3 | 4 | party1 = Party(name="Party1") 5 | 6 | my_int1 = SecretInteger(Input(name="my_int1", party=party1)) 7 | 8 | my_int2 = SecretInteger(Input(name="my_int2", party=party1)) 9 | 10 | new_int = my_int1 + my_int2 11 | 12 | return [Output(new_int, "my_output", party1)] -------------------------------------------------------------------------------- /quickstart_complete/nada_quickstart_programs/target/secret_addition_complete.nada.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NillionNetwork/nillion-python-starter/fddab100439b38a1fb701a88d1c70fedd92ac287/quickstart_complete/nada_quickstart_programs/target/secret_addition_complete.nada.bin -------------------------------------------------------------------------------- /quickstart_complete/nada_quickstart_programs/tests/secret_addition_complete.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | program: secret_addition_complete 3 | inputs: 4 | my_int1: 3 5 | my_int2: 3 6 | expected_outputs: 7 | my_output: 6 8 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | nillion-client==0.2.0 2 | nada-dsl==0.8.0 3 | python-dotenv==1.0.0 4 | --------------------------------------------------------------------------------