Skip to main content

Compute

Blind computation requires three elements:

  1. Storing of a Program (via self or by someone else)
  2. Invoking the program with your parameters
  3. Retrieving the computed results

Note: in order to use these functions, you (as the developer) should have created Nada programs to interact with. See this guide if you have not done this process.

useNilStoreProgram

To store a program, you would have computed a XXX.nada.bin file after you built a successful nada program. You will need to upload this file via the FileReader to upload the program. The mutation.execute({ name, program }) part should automatically take in your program + name.

examples-nextjs/app/components/store-program.tsx
"use client";

import { useNilStoreProgram } from "@nillion/client-react-hooks";
import { type FC, useRef, useState } from "react";

export const StoreProgram: FC = () => {
const mutation = useNilStoreProgram();
const [name, setName] = useState("");
const [program, setProgram] = useState<Uint8Array | null>(null);
const programDefined = name && program;

const fileInputRef = useRef<HTMLInputElement>(null);

let id = "";
if (mutation.isSuccess) {
id = mutation.data;
} else if (mutation.isError) {
id = mutation.error.message;
}

function handleFileChange(event: React.ChangeEvent<HTMLInputElement>): void {
const file = event.target.files?.[0];
if (file) {
setName(file.name);
const reader = new FileReader();
reader.onload = (e) => {
const content = e.target?.result;
if (content) {
setProgram(new Uint8Array(content as ArrayBuffer));
}
};
reader.readAsArrayBuffer(file);
}
}

function handleClick(): void {
if (!program) throw new Error("Expected `program` to be undefined");
mutation.execute({ name, program });
}

return (
<div>
<h2>Store Program</h2>
<ol>
<li>Status: {mutation.status}</li>
<li>Name: {name}</li>
<li>
Program:{" "}
<input type="file" ref={fileInputRef} onChange={handleFileChange} />
</li>
<li>Program Id: {id}</li>
</ol>
<button type="button" disabled={!programDefined} onClick={handleClick}>
Execute
</button>
</div>
);
};

useNilInvokeCompute

To invoke a program, you pass in the programId of the program you have uploaded with considerations of the inputs you want to provide in your options. computeTimeValues with respect to name and value are what you want to adjust.

const options = {
programId,
inputBindings: [{ party: "Party1", user: client.id }],
outputBindings: [{ party: "Party1", users: [client.id] }],
valueIds: [],
computeTimeValues: [
{
name: "A",
value: NadaValue.new_secret_integer("10"),
},
{
name: "B",
value: NadaValue.new_secret_integer("4"),
},
],
};
examples-nextjs/app/components/invoke-compute.tsx
"use client";

import {
useNilInvokeCompute,
useNilOverwritePermissions,
useNillion,
} from "@nillion/client-react-hooks";
import { NadaValue, ProgramId, Uuid } from "@nillion/client-vms";
import { type ChangeEvent, type FC, useState } from "react";

export const InvokeCompute: FC = () => {
const { client } = useNillion();
const mutation = useNilInvokeCompute();
const [programId, setProgramId] = useState("");
const isValidProgramId = ProgramId.safeParse(programId).success;

function handleChange(event: ChangeEvent<HTMLInputElement>): void {
setProgramId(event.target.value);
}

function handleClick(): void {
// Assumes addition_division.py
const options = {
programId,
inputBindings: [{ party: "Party1", user: client.id }],
outputBindings: [{ party: "Party1", users: [client.id] }],
valueIds: [],
computeTimeValues: [
{
name: "A",
value: NadaValue.new_secret_integer("10"),
},
{
name: "B",
value: NadaValue.new_secret_integer("4"),
},
],
};
mutation.execute(options);
}

let resultId = "";
if (mutation.isSuccess) {
resultId = mutation.data;
} else if (mutation.isError) {
resultId = mutation.error.message;
}

return (
<div>
<h2>Invoke Compute</h2>
<ol>
<li>Status: {mutation.status}</li>
<li>
Program id:{" "}
<input type="text" value={programId} onChange={handleChange} />
</li>
<li>Compute result id: {resultId}</li>
</ol>
<button type="button" disabled={!isValidProgramId} onClick={handleClick}>
Execute
</button>
</div>
);
};

useNilRetrieveComputeResults

To retrieve, you simply pass in the id from the previous invocation.

examples-nextjs/app/components/retrieve-compute-results.tsx
"use client";

import {
useNilInvokeCompute,
useNilOverwritePermissions,
useNilRetrieveComputeResults,
} from "@nillion/client-react-hooks";
import { Uuid } from "@nillion/client-vms";
import { type ChangeEvent, type FC, useState } from "react";

export const RetrieveComputeResults: FC = () => {
const mutation = useNilRetrieveComputeResults();
const [id, setId] = useState("");
const isValidUuid = Uuid.safeParse(id).success;

let data = "";
if (mutation.isSuccess) {
// stringify cannot handle BigInts
data = data = JSON.stringify(mutation.data, (_, v) =>
typeof v === "bigint" ? v.toString() : v,
);
} else if (mutation.isError) {
data = mutation.error.message;
}

function handleChange(event: ChangeEvent<HTMLInputElement>): void {
setId(event.target.value);
}

function handleClick(): void {
const options = { id };
mutation.execute(options);
}

return (
<div>
<h2>Retrieve Compute Results</h2>
<ol>
<li>Status: {mutation.status}</li>
<li>
Result Id: <input type="text" value={id} onChange={handleChange} />
</li>
<li>Results: {data}</li>
</ol>
<button type="button" disabled={!isValidUuid} onClick={handleClick}>
Execute
</button>
</div>
);
};
Feedback