Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
c7df096
Adding cookbook
naiemk-coti May 4, 2026
8a15d96
Adding toc to the pod-cookbook
naiemk-coti May 5, 2026
667e31d
Merge branch 'main' into main
naiemk-coti May 5, 2026
344f038
GITBOOK-104: No subject
gmesika-coti May 6, 2026
04d0529
Update COTI Node Ecosystem documentation
gmesika-coti May 13, 2026
38e6b61
Refactor COTI Node Ecosystem documentation
gmesika-coti May 13, 2026
16741ad
Enhance COTI Node Ecosystem documentation
gmesika-coti May 13, 2026
5f2c9ef
Update COTI Node Ecosystem documentation to reflect testnet URLs
gmesika-coti May 13, 2026
7111575
GITBOOK-106: No subject
gmesika-coti May 13, 2026
46b7258
GITBOOK-107: No subject
gmesika-coti May 13, 2026
71009e7
WIP on main
gmesika-coti May 13, 2026
f86c06c
Enhance COTI Node Ecosystem documentation
gmesika-coti May 13, 2026
c45f2f6
Refine COTI Node Ecosystem documentation
gmesika-coti May 13, 2026
7efb617
Add new images and enhance FQDN setup documentation
gmesika-coti May 13, 2026
8966e93
Update eligibility criteria in documentation and image
gmesika-coti May 13, 2026
43aaa01
Update dashboard images and enhance README content
gmesika-coti May 13, 2026
055c6b7
Add new image for Edit Node flow and update documentation
gmesika-coti May 13, 2026
6712d58
Update COTI Node Ecosystem documentation for certified OS requirements
gmesika-coti May 13, 2026
70e947a
Update installation documentation to standardize command options
gmesika-coti May 13, 2026
1e9dccc
docs: add Private Messaging Quickstart for sending and receiving mess…
vladi-coti May 12, 2026
1115d97
docs: add Private Messaging Dogfood Report and update related documen…
vladi-coti May 12, 2026
75ab101
docs: update quickstart guide for private messaging to simplify walle…
vladi-coti May 12, 2026
d631a45
docs: enhance quickstart guide for private messaging with additional …
vladi-coti May 12, 2026
fd584a5
docs: add installable private messaging skills
vladi-coti May 13, 2026
bcfd2c2
docs(private-messaging): one-line bootstrap path
vladi-coti May 14, 2026
95bbbc3
docs: add Smart Contract Audit Report for Coti
gmesika-coti May 18, 2026
a10072d
GITBOOK-108: No subject
gmesika-coti May 18, 2026
db3c156
GITBOOK-109: No subject
gmesika-coti May 18, 2026
f3209c0
GITBOOK-110: No subject
gmesika-coti May 18, 2026
4091544
GITBOOK-111: No subject
gmesika-coti May 18, 2026
351e842
docs: reorganize Support and Community section in SUMMARY.md
gmesika-coti May 20, 2026
01921b3
docs: update COTI Snap setup guide with new last updated date and cla…
gmesika-coti May 20, 2026
8546a90
docs: update installation guides to reflect changes in command flags …
gmesika-coti Jun 1, 2026
7fe4086
docs: clarify FRPC and Nginx configurations in installation guides, e…
gmesika-coti Jun 1, 2026
e548702
docs: update server requirements and installation guides to reflect U…
gmesika-coti Jun 2, 2026
3fa97ac
docs: enhance installation guides with detailed commands for Linux, m…
gmesika-coti Jun 2, 2026
278c73e
GITBOOK-112: No subject
gmesika-coti Jun 2, 2026
a92beb4
docs: update installation guides to standardize `<network>` placehold…
gmesika-coti Jun 2, 2026
726721e
docs: expand manual-full-node.md with detailed instructions for setti…
gmesika-coti Jun 2, 2026
44b9548
docs: add comprehensive documentation for private messaging, includin…
vladi-coti Jun 3, 2026
d4e3f27
docs: enhance private messaging documentation with new guidelines for…
vladi-coti Jun 7, 2026
1394446
Merge branch 'coti-io:main' into main
naiemk-coti Jun 15, 2026
56cda9c
Update PoD with latest MpcCore
naiemk-coti Jun 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 14 additions & 6 deletions privacy-on-demand/cookbook-private-investor-allocations.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ The public version is useful because it gives you a known baseline: owner assign
- A Solidity toolchain such as Hardhat or Foundry.
- A Sepolia wallet with test ETH for deploys, transactions, and PoD request fees.
- Node.js 18+ for scripts.
- The PoD SDK package: `npm install "@coti/pod-sdk"`.
- The PoD SDK package: `npm install "@coti/pod-sdk"` (ships the vendored `MpcCore.sol` under `@coti/pod-sdk/contracts/utils/mpc/`, so the COTI‑side contract no longer needs the `@coti-io/coti-contracts` package).
- The COTI client crypto package: `npm install "@coti-io/coti-sdk-typescript@^1.0.7"` (provides `decryptUint256({ ciphertextHigh, ciphertextLow }, key)` for the 256‑bit ciphertext shape).
- A way for users to complete PoD onboarding and obtain their account AES key for local decryption.

Before implementing the private version, read:
Expand Down Expand Up @@ -411,21 +412,26 @@ const encryptedAllocation = await CotiPodCrypto.encrypt(

If you use `PodContract.encryptAndCallMethod`, you can pass the plaintext string plus `DataType.itUint256`; the SDK encrypts and encodes the argument before sending the transaction. If the browser or backend already encrypted the value, use `callMethod` with the ciphertext JSON.

Investors decrypt only the ciphertext that was off-boarded to them.
Investors decrypt only the ciphertext that was off-boarded to them. Because `ctUint256` is a struct, the contract read returns a tuple `{ ciphertextHigh, ciphertextLow }`:

```typescript
const ct = await sepoliaAllocations.readResultByRequest(requestId);
const ctHex = typeof ct === "bigint" ? "0x" + ct.toString(16) : String(ct);
const raw = await sepoliaAllocations.readResultByRequest(requestId);
const ct = {
ciphertextHigh: BigInt(raw.ciphertextHigh ?? raw[0]),
ciphertextLow: BigInt(raw.ciphertextLow ?? raw[1]),
};

const plain = CotiPodCrypto.decrypt(
ctHex,
ct,
accountAesKeyFromOnboarding,
DataType.Uint256
);

console.log("private allocation:", plain);
```

Under the hood, the 256‑bit decrypt path calls `decryptUint256({ ciphertextHigh, ciphertextLow }, key)` from `@coti-io/coti-sdk-typescript` (`^1.0.7`). Narrower lanes (`Uint64`, `Uint128`) still take a single ciphertext word.

> **Warning:** Never log, persist, or transmit the account AES key as ordinary application data. Treat it as user-controlled key material.

## Part 7: Allocate and read private allocations
Expand Down Expand Up @@ -482,6 +488,8 @@ function onSetAllocationCompleted(bytes memory resultData) external onlyInbox {

For investor reads, the investor asks COTI to off-board their allocation to their address. The callback stores `ctUint256`, and the investor decrypts locally with their account AES key.

`ctUint256` is a Solidity **struct** with two `ctUint128` limbs (`ciphertextHigh`, `ciphertextLow`), so the decoded local needs a `memory` location and the storage mapping holds the two‑limb tuple.

```solidity
mapping(bytes32 => ctUint256) public allocationReadResults;

Expand All @@ -490,7 +498,7 @@ function onAllocationRead(bytes memory resultData) external onlyInbox {
require(callerChain == COTI_TESTNET_CHAIN_ID && callerContract == cotiAllocationPeer, "not allowed");

bytes32 requestId = IInbox(inbox).inboxSourceRequestId();
ctUint256 allocation = abi.decode(resultData, (ctUint256));
ctUint256 memory allocation = abi.decode(resultData, (ctUint256));

allocationReadResults[requestId] = allocation;
}
Expand Down
13 changes: 12 additions & 1 deletion privacy-on-demand/for-developers-mapping-to-the-sdk.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,21 @@ Then deep dives:
| **Callback guard** | [InboxUser.sol](https://github.com/cotitech-io/coti-pod-sdk/blob/main/contracts/InboxUser.sol) (`onlyInbox`) — see [Features](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/03-features.md). |
| **PodLib** | [PodLib.sol](https://github.com/cotitech-io/coti-pod-sdk/blob/main/contracts/mpc/PodLib.sol) and width-specific libraries (`PodLib64`, `PodLib128`, `PodLib256`). |
| **PodUser / presets** | [PodUser.sol](https://github.com/cotitech-io/coti-pod-sdk/blob/main/contracts/mpc/PodUser.sol), network mixins such as [PodUserSepolia.sol](https://github.com/cotitech-io/coti-pod-sdk/blob/main/contracts/mpc/PodUserSepolia.sol) in [Getting started](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/04-getting-started.md). |
| **Types (`it*`, `ct*`, `gt*`)** | [MpcCore.sol](https://github.com/cotitech-io/coti-pod-sdk/blob/main/contracts/utils/mpc/MpcCore.sol) and [Data types](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/contracts/01-it-ct-gt-data-types.md). |
| **Types (`it*`, `ct*`, `gt*`)** | Vendored [MpcCore.sol](https://github.com/cotitech-io/coti-pod-sdk/blob/main/contracts/utils/mpc/MpcCore.sol) (and `MpcInterface.sol`) inside the PoD SDK — no separate `@coti-io/coti-contracts` package is needed for PoD apps. See [Data types](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/contracts/01-it-ct-gt-data-types.md). |
| **Custom COTI calls** | [MpcAbiCodec.sol](https://github.com/cotitech-io/coti-pod-sdk/blob/main/contracts/mpccodec/MpcAbiCodec.sol) and the **custom mode** section of [Writing privacy contracts](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/05-writing-privacy-contracts-on-ethereum.md). |
| **Client crypto** | [coti-pod-crypto.ts](https://github.com/cotitech-io/coti-pod-sdk/blob/main/src/coti-pod-crypto.ts) via `CotiPodCrypto` ([TypeScript integration](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/06-typescript-integration-ux-development.md)). |

## Type model at a glance

The PoD SDK ships **`MpcCore.sol`** under `@coti/pod-sdk/contracts/utils/mpc/`. In the current revision:

- **`gtUint8` … `gtUint256` and `gtBool`** are **user‑defined value types** (`type gtUint256 is uint256`). Pass and assign them like `uint256` — **no `memory` / `calldata` on `gt*` parameters or locals**.
- **`ctUint8` … `ctUint128`** are also user‑defined value types (single `uint256` word).
- **`ctUint256`** is a **struct** `{ ctUint128 ciphertextHigh; ctUint128 ciphertextLow; }` — decoded locals and callback variables must use a `memory` location, and off‑chain reads return the two limbs as a tuple.
- **`itUint*`** (user encrypted inputs, `ciphertext + signature`), **`utUint*`** (dual‑ciphertext), **`gtString`** and **`ctString`** remain structs — keep their `calldata` / `memory` locations.

If you previously imported from **`@coti-io/coti-contracts`** in PoD code, switch the import to **`@coti/pod-sdk/contracts/utils/mpc/MpcCore.sol`**. Off‑chain decryption uses **`@coti-io/coti-sdk-typescript@^1.0.7`**, which exposes `decryptUint256({ ciphertextHigh, ciphertextLow }, accountAesKey)` for the 256‑bit lane.

## Implementation checklist (condensed)

Derived from the SDK’s [Writing privacy contracts](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/05-writing-privacy-contracts-on-ethereum.md) and [Async execution](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/05a-async-execution.md):
Expand Down
2 changes: 1 addition & 1 deletion privacy-on-demand/tutorial-custom-logic.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ The COTI contract **inherits `InboxUser`**, so only the Inbox can enter `receive
pragma solidity ^0.8.19;

import "../InboxUserCotiTestnet.sol";
import "@coti-io/coti-contracts/contracts/utils/mpc/MpcCore.sol";
import "@coti/pod-sdk/contracts/utils/mpc/MpcCore.sol";

contract DirectMessageCotiSide is InboxUserCotiTestnet {
function receiveMessage(gtString calldata message, address sender, address recipient) external onlyInbox {
Expand Down
31 changes: 18 additions & 13 deletions privacy-on-demand/tutorial-private-adder-sepolia.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ contract PrivateAdder is PodLib, PodUserSepolia {
requestId = inbox.inboxRequestId();
}

ctUint256 sum = abi.decode(data, (ctUint256));
ctUint256 memory sum = abi.decode(data, (ctUint256));
sumByRequest[requestId] = sum;
statusByRequest[requestId] = RequestStatus.Completed;
emit AddCompleted(requestId);
Expand All @@ -105,6 +105,7 @@ contract PrivateAdder is PodLib, PodUserSepolia {

- **`onDefaultMpcError`** is implemented on `PodLibBase` and forwards failures to **`ErrorRemoteCall`** on `PodUser`. Your UI can listen for that event to mark a request failed.
- **`addCallback`** must stay **`onlyInbox`** so random accounts cannot forge results.
- **`ctUint256`** is a Solidity **struct** `{ ctUint128 ciphertextHigh; ctUint128 ciphertextLow; }`, so the decoded local must use a `memory` location and the storage mapping holds the two‑limb tuple. The narrower garbled / ciphertext types (`gtUint8…gtUint256`, `gtBool`, and `ctUint8…ctUint128`) are **user‑defined value types** — pass and assign them like `uint256` (no `memory` / `calldata`). Encrypted-input wrappers such as **`itUint256`** stay structs and keep their `calldata` / `memory` location as before.

## Step 3: Compile and deploy on Sepolia

Expand Down Expand Up @@ -145,8 +146,10 @@ import {
import { ethers } from "ethers";

// Minimal ABI fragment — prefer the full artifact from your build (Hardhat / Foundry).
// itUint256 = { ctUint256 ciphertext; bytes signature }, and ctUint256 = { uint256 ciphertextHigh; uint256 ciphertextLow }
// so each `itUint256` parameter encodes as ((uint256,uint256),bytes).
const privateAdderAbi = [
"function add((uint256 ciphertext,bytes signature),(uint256 ciphertext,bytes signature),uint256) payable returns (bytes32)",
"function add(((uint256,uint256),bytes),((uint256,uint256),bytes),uint256) payable returns (bytes32)",
] as const;

const pod = new PodContract(
Expand Down Expand Up @@ -206,35 +209,37 @@ Private addition is **asynchronous**: the sum appears only after the Inbox invok

## Step 7: Read the encrypted sum and decrypt locally

After status is **Completed**, read **`sumByRequest(requestId)`**. The value is **`ctUint256`** (ciphertext), not plaintext.
After status is **Completed**, read **`sumByRequest(requestId)`**. The value is **`ctUint256`** (ciphertext), not plaintext. Because **`ctUint256`** is a Solidity **struct** with two `ctUint128` limbs, the contract read returns a tuple `{ ciphertextHigh, ciphertextLow }` (each is a single `uint256`).

```typescript
import { CotiPodCrypto, DataType } from "@coti/pod-sdk";

// accountAesKey: hex string from your app’s COTI onboarding flow (never log it)

const ct = await privateAdder.sumByRequest(requestId); // bytes32 from extractRequestIds or return value
const ctHex =
typeof ct === "bigint"
? "0x" + ct.toString(16)
: String(ct);
const raw = await privateAdder.sumByRequest(requestId);
// ethers / viem return the struct as a tuple — normalize to { ciphertextHigh, ciphertextLow }
const ct = {
ciphertextHigh: BigInt(raw.ciphertextHigh ?? raw[0]),
ciphertextLow: BigInt(raw.ciphertextLow ?? raw[1]),
};

const decryptedString = CotiPodCrypto.decrypt(
ctHex,
ct,
accountAesKey,
DataType.Uint64
DataType.Uint256
);

console.log("sum (plaintext string):", decryptedString);
// Expect "30" for plainA=10 and plainB=20
```

`CotiPodCrypto.decrypt` delegates to `@coti-io/coti-sdk-typescript` and expects a **scalar ciphertext** as a **hex string** for `Uint64`, plus the user’s **AES key** (see SDK source [coti-pod-crypto.ts](https://github.com/cotitech-io/coti-pod-sdk/blob/main/src/coti-pod-crypto.ts)).
`CotiPodCrypto.decrypt` delegates to **`@coti-io/coti-sdk-typescript`** (`^1.0.7`), which now exposes `decryptUint256({ ciphertextHigh, ciphertextLow }, accountAesKey)` for the 256‑bit lane. Narrower lanes (`Uint64`, `Uint128`, …) still take a single `uint256` ciphertext as a `bigint` or `0x`‑prefixed hex string (see SDK source [coti-pod-crypto.ts](https://github.com/cotitech-io/coti-pod-sdk/blob/main/src/coti-pod-crypto.ts)).

## Step 8: Sanity checks and next steps

- **Callback decode** must stay **`(ctUint256)`** — changing the executor op or COTI-side behavior without updating the decode tuple will corrupt storage reads.
- **Type lane** — This contract uses **`add256`** with **`itUint256`** / **`ctUint256`** on chain. **`CotiPodCrypto.decrypt`** still takes a **`DataType`** for the scalar decode; keep **`DataType.Uint64`** (or **`Uint256`**, etc.) aligned with how your app and onboarding produce the ciphertext for this flow, per your installed SDK.
- **Callback decode** must stay **`(ctUint256)`** — and the local must use `memory` because `ctUint256` is a struct. Changing the executor op or COTI-side behavior without updating the decode tuple will corrupt storage reads.
- **Type lane** — This contract uses **`add256`** with **`itUint256`** / **`ctUint256`** on chain, so pass **`DataType.Uint256`** to `CotiPodCrypto.decrypt` and feed it the **`{ ciphertextHigh, ciphertextLow }`** tuple read from the contract. Narrower lanes (`Uint64`, `Uint128`) still take a single ciphertext word.
- **Type model** — In the current `MpcCore.sol`, `gtUint*`, `gtBool`, and `ctUint8…ctUint128` are **user‑defined value types** (`type X is uint256`) — drop `memory` / `calldata` on them. `ctUint256` is a struct (two `ctUint128` limbs); `itUint*` / `utUint*` are also still structs, so keep `calldata` / `memory` on those.
- **Production**: add tests for non-Inbox callers on `addCallback`, under-funded `msg.value`, and decrypt failures; follow the [first production checklist](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/04-getting-started.md) in Getting started.

## Reference links
Expand Down
27 changes: 24 additions & 3 deletions privacy-on-demand/typescript-pod-sdk.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,39 @@ Use these helpers from a wallet script, backend service, or dApp frontend once y
- You can also pass a full encryption service URL.
- `DataType` distinguishes plaintext types (`Uint64`, `String`, etc.) from **`it*`** types that become ciphertext tuples on chain.

`CotiPodCrypto.decrypt` uses the user's **account AES key** and `@coti-io/coti-sdk-typescript` under the hood.
`CotiPodCrypto.decrypt` uses the user's **account AES key** and **`@coti-io/coti-sdk-typescript`** (`^1.0.7`) under the hood.

```typescript
import { CotiPodCrypto, DataType } from "@coti/pod-sdk";

// Encrypt plaintext for Solidity itUint256 parameters
const enc = await CotiPodCrypto.encrypt("42", "testnet", DataType.itUint256);

// Decrypt scalar ciphertext read from contract storage
const plain = CotiPodCrypto.decrypt("0x...", accountAesKeyFromOnboarding, DataType.Uint64);
// Decrypt a narrow scalar ciphertext (one uint256 word) read from contract storage
const plain64 = CotiPodCrypto.decrypt("0x...", accountAesKeyFromOnboarding, DataType.Uint64);

// Decrypt a ctUint256 value (a struct with two ctUint128 limbs)
const plain256 = CotiPodCrypto.decrypt(
{ ciphertextHigh, ciphertextLow },
accountAesKeyFromOnboarding,
DataType.Uint256
);
```

### Ciphertext shape in the current `MpcCore.sol`

After the gt‑type upgrade, the on‑chain types you read back have these shapes:

| Type | Solidity | Off‑chain shape |
| -------------------------- | --------------------------------------------------------- | ---------------------------------------------- |
| `gtUint8` … `gtUint256`, `gtBool` | User‑defined value type (`type … is uint256`), no `memory`/`calldata` | n/a — never crosses the chain boundary |
| `ctUint8` … `ctUint128` | User‑defined value type | single `uint256` word |
| `ctUint256` | Struct `{ ctUint128 ciphertextHigh; ctUint128 ciphertextLow; }` | tuple `{ ciphertextHigh, ciphertextLow }` (each `bigint`) |
| `itUint*` / `utUint*` | Struct (ciphertext + signature, unchanged) | tuple / object |
| `gtString` / `ctString` | Struct (array of `gtUint64` / `ctUint64`, unchanged) | array of words |

When you read a `ctUint256` value via ethers or viem, the storage getter returns the two limbs as a tuple — normalize it to `{ ciphertextHigh, ciphertextLow }` before passing it to `CotiPodCrypto.decrypt` (or to `decryptUint256` from `@coti-io/coti-sdk-typescript`). The narrower `ct*` lanes can still be passed as a `bigint` or `0x`‑prefixed hex string.

## Gas estimation and method calls (`PodContract`)

`PodContract` wraps `ethers.Contract` with PoD-aware helpers:
Expand Down