Skip to content

Commit

Permalink
finish
Browse files Browse the repository at this point in the history
  • Loading branch information
kroist committed Jan 9, 2025
1 parent b33159e commit 0b011d0
Show file tree
Hide file tree
Showing 14 changed files with 411 additions and 300 deletions.
6 changes: 3 additions & 3 deletions ts/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 0 additions & 3 deletions ts/shielder-sdk/.prettierrc.json

This file was deleted.

5 changes: 0 additions & 5 deletions ts/shielder-sdk/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,3 @@ echo -n "as const;" >> src/_generated/abi.ts

tsc --project tsconfig.json
tsc-alias -p tsconfig.json

# bundle shielder-wasm and update imports
mkdir -p dist/crates/shielder-wasm/
cp -r ../../crates/shielder-wasm/pkg dist/crates/shielder-wasm/
node update-imports.mjs
40 changes: 0 additions & 40 deletions ts/shielder-sdk/eslint.config.mjs

This file was deleted.

109 changes: 81 additions & 28 deletions ts/shielder-sdk/src/shielder/actions/deposit.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,80 @@
import { IContract, VersionRejectedByContract } from "@/chain/contract";
import { Scalar, scalarToBigint } from "@/crypto/scalar";
import {
CryptoClient,
DepositPubInputs,
Proof,
Scalar,
scalarToBigint
} from "shielder-sdk-crypto";
import { SendShielderTransaction } from "@/shielder/client";
import { Calldata } from "@/shielder/actions";
import { rawAction } from "@/shielder/actions/utils";
import { NoteAction } from "@/shielder/actions/utils";
import { AccountState } from "@/shielder/state";
import { DepositReturn } from "@/wasmClient";
import { wasmClientWorker } from "@/wasmClientWorker";
import { idHidingNonce } from "@/utils";

export interface DepositCalldata extends Calldata {
calldata: DepositReturn;
calldata: {
pubInputs: DepositPubInputs;
proof: Proof;
};
expectedContractVersion: `0x${string}`;
amount: bigint;
merkleRoot: Scalar;
}

export class DepositAction {
contract: IContract;
constructor(contract: IContract) {
export class DepositAction extends NoteAction {
private contract: IContract;
constructor(contract: IContract, cryptoClient: CryptoClient) {
super(cryptoClient);
this.contract = contract;
}

static #balanceChange(currentBalance: bigint, amount: bigint) {
return currentBalance + amount;
}

/**
* Return the updated state after depositing `amount` into `stateOld`.
* Does not perform the actual deposit on blockchain.
* @param stateOld
* @param amount amount to deposit
* @returns updated state
*/
static async rawDeposit(
async rawDeposit(
stateOld: AccountState,
amount: bigint
): Promise<AccountState | null> {
return await rawAction(stateOld, amount, this.#balanceChange);
return await this.rawAction(
stateOld,
amount,
(currentBalance: bigint, amount: bigint) => currentBalance + amount
);
}

async preparePubInputs(
state: AccountState,
amount: bigint,
nonce: Scalar,
nullifierOld: Scalar,
merkleRoot: Scalar
) {
const hId = await this.cryptoClient.hasher.poseidonHash([state.id]);
const idHiding = await this.cryptoClient.hasher.poseidonHash([hId, nonce]);

const hNullifierOld = await this.cryptoClient.hasher.poseidonHash([
nullifierOld
]);
const newState = await this.rawDeposit(state, amount);
if (newState === null) {
throw new Error(
"Failed to deposit, possibly due to insufficient balance"
);
}
const hNoteNew = newState.currentNote;
return {
hNullifierOld,
hNoteNew,
nonce,
idHiding,
merkleRoot,
value: Scalar.fromBigint(amount)
};
}

/**
Expand All @@ -50,9 +89,10 @@ export class DepositAction {
expectedContractVersion: `0x${string}`
): Promise<DepositCalldata> {
const lastNodeIndex = state.currentNoteIndex!;
const [path, merkleRoot] = await wasmClientWorker.merklePathAndRoot(
const [path, merkleRoot] = await this.merklePathAndRoot(
await this.contract.getMerklePath(lastNodeIndex)
);
const nonce = idHidingNonce();

if (state.currentNoteIndex === undefined) {
throw new Error("currentNoteIndex must be set");
Expand All @@ -61,35 +101,48 @@ export class DepositAction {
const time = Date.now();

const { nullifier: nullifierOld, trapdoor: trapdoorOld } =
await wasmClientWorker.getSecrets(state.id, state.nonce - 1n);
await this.cryptoClient.secretManager.getSecrets(
state.id,
Number(state.nonce - 1n)
);
const { nullifier: nullifierNew, trapdoor: trapdoorNew } =
await wasmClientWorker.getSecrets(state.id, state.nonce);

const accountBalanceNew = DepositAction.#balanceChange(
state.balance,
amount
);
await this.cryptoClient.secretManager.getSecrets(
state.id,
Number(state.nonce)
);

const calldata = await wasmClientWorker
.proveAndVerifyDeposit({
const proof = await this.cryptoClient.depositCircuit
.prove({
id: state.id,
nonce,
nullifierOld,
trapdoorOld,
accountBalanceOld: Scalar.fromBigint(state.balance),
merkleRoot,
path,
value: Scalar.fromBigint(amount),
nullifierNew,
trapdoorNew,
accountBalanceNew: Scalar.fromBigint(accountBalanceNew)
trapdoorNew
})
.catch((e) => {
console.error(e);
throw new Error(`Failed to prove deposit: ${e}`);
});
const pubInputs = await this.preparePubInputs(
state,
amount,
nonce,
nullifierOld,
merkleRoot
);
if (!(await this.cryptoClient.depositCircuit.verify(proof, pubInputs))) {
throw new Error("Deposit proof verification failed");
}
const provingTime = Date.now() - time;
return {
calldata,
calldata: {
pubInputs,
proof
},
expectedContractVersion,
provingTimeMillis: provingTime,
amount,
Expand Down
69 changes: 49 additions & 20 deletions ts/shielder-sdk/src/shielder/actions/newAccount.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,61 @@
import { IContract } from "@/chain/contract";
import { Scalar, scalarToBigint } from "@/crypto/scalar";
import {
CryptoClient,
NewAccountPubInputs,
Proof,
Scalar,
scalarToBigint
} from "shielder-sdk-crypto";
import { SendShielderTransaction } from "@/shielder/client";
import { rawAction } from "@/shielder/actions/utils";
import { NoteAction } from "@/shielder/actions/utils";
import { AccountState } from "@/shielder/state";
import { NewAccountReturn } from "@/wasmClient";
import { wasmClientWorker } from "@/wasmClientWorker";

export interface NewAccountCalldata {
calldata: NewAccountReturn;
calldata: {
pubInputs: NewAccountPubInputs;
proof: Proof;
};
expectedContractVersion: `0x${string}`;
provingTimeMillis: number;
amount: bigint;
}

export class NewAccountAction {
export class NewAccountAction extends NoteAction {
contract: IContract;
constructor(contract: IContract) {
constructor(contract: IContract, cryptoClient: CryptoClient) {
super(cryptoClient);
this.contract = contract;
}

static #balanceChange(currentBalance: bigint, amount: bigint) {
return amount;
}

/**
* Return the updated state after creating a new account with an initial deposit.
* Does not perform the actual account creation on blockchain.
* @param stateOld
* @param amount initial deposit
* @returns updated state
*/
static async rawNewAccount(
async rawNewAccount(
stateOld: AccountState,
amount: bigint
): Promise<AccountState | null> {
return await rawAction(stateOld, amount, NewAccountAction.#balanceChange);
return await this.rawAction(
stateOld,
amount,
(currentBalance: bigint, amount: bigint) => amount
);
}

async preparePubInputs(state: AccountState, amount: bigint) {
const hId = await this.cryptoClient.hasher.poseidonHash([state.id]);
const newState = await this.rawNewAccount(state, amount);

if (newState === null) {
throw new Error(
"Failed to create new account, possibly due to negative balance"
);
}
const hNote = newState.currentNote;
return { hId, hNote, initialDeposit: Scalar.fromBigint(amount) };
}

/**
Expand All @@ -48,13 +69,14 @@ export class NewAccountAction {
amount: bigint,
expectedContractVersion: `0x${string}`
): Promise<NewAccountCalldata> {
const { nullifier, trapdoor } = await wasmClientWorker.getSecrets(
state.id,
state.nonce
);
const { nullifier, trapdoor } =
await this.cryptoClient.secretManager.getSecrets(
state.id,
Number(state.nonce)
);
const time = Date.now();
const calldata = await wasmClientWorker
.proveAndVerifyNewAccount({
const proof = await this.cryptoClient.newAccountCircuit
.prove({
id: state.id,
nullifier,
trapdoor,
Expand All @@ -64,10 +86,17 @@ export class NewAccountAction {
console.error(e);
throw new Error(`Failed to prove new account: ${e}`);
});
const pubInputs = await this.preparePubInputs(state, amount);
if (!(await this.cryptoClient.newAccountCircuit.verify(proof, pubInputs))) {
throw new Error("New account proof verification failed");
}
const provingTime = Date.now() - time;
return {
expectedContractVersion,
calldata,
calldata: {
pubInputs,
proof
},
provingTimeMillis: provingTime,
amount
};
Expand Down
Loading

0 comments on commit 0b011d0

Please sign in to comment.