Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: inclusion and non-inclusion proofs experiment #3255

Merged
merged 71 commits into from
Nov 29, 2023
Merged
Show file tree
Hide file tree
Changes from 69 commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
c37efa5
WIP
benesjan Nov 7, 2023
3da1c78
WIP
benesjan Nov 7, 2023
94f43be
WIP
benesjan Nov 7, 2023
32d2e39
minting
benesjan Nov 7, 2023
6343553
nullifying the note
benesjan Nov 7, 2023
ce3c4ab
fix after rebase
benesjan Nov 20, 2023
f159824
formatting
benesjan Nov 20, 2023
c98a5af
WIP
benesjan Nov 20, 2023
bbf4e66
fix: getPublicKeyAndPartialAddress in TypesOracle
benesjan Nov 20, 2023
e152b2c
WIP
benesjan Nov 20, 2023
af94bc9
WIP
benesjan Nov 20, 2023
e267f8d
WIP
benesjan Nov 20, 2023
7d2fab6
WIP
benesjan Nov 21, 2023
7cdd90e
WIP
benesjan Nov 21, 2023
3bf3036
fix
benesjan Nov 21, 2023
78eaadb
computing blocks hash
benesjan Nov 21, 2023
5528be5
WIP on verifying block hash
benesjan Nov 21, 2023
61a3682
fix
benesjan Nov 23, 2023
39b6011
feat: get_block_data.nr
benesjan Nov 23, 2023
227553f
finished get_block_data oracle
benesjan Nov 23, 2023
3635866
comment
benesjan Nov 24, 2023
71508b1
HistoricBlockData::block_hash()
benesjan Nov 24, 2023
eb5c260
renaming
benesjan Nov 24, 2023
508ab15
cleanup
benesjan Nov 24, 2023
cf14859
cleanup
benesjan Nov 24, 2023
b10f34c
running test in CI
benesjan Nov 24, 2023
38ba6b4
fix
benesjan Nov 24, 2023
ab2ba46
typo
benesjan Nov 24, 2023
1819c24
using blocks tree root from context
benesjan Nov 24, 2023
0016721
comment
benesjan Nov 24, 2023
61c6f85
fix
benesjan Nov 24, 2023
7360736
feat: note utils compute_siloed_nullifier
benesjan Nov 24, 2023
f407ce7
get_low_nullifier_membership_witness.nr
benesjan Nov 24, 2023
4b779af
updated get_low_nullifier_membership_witness.nr
benesjan Nov 24, 2023
1a5c4ab
WIP on proveNullifierNonInclusion
benesjan Nov 24, 2023
ec0d319
WIP
benesjan Nov 24, 2023
b9699d7
WIP
benesjan Nov 24, 2023
ff79a1f
naming fix
benesjan Nov 24, 2023
5533c1a
WIP
benesjan Nov 27, 2023
9e8890c
WIP
benesjan Nov 27, 2023
2329113
formatting
benesjan Nov 27, 2023
b298fc8
nullifier non-inclusion finished
benesjan Nov 27, 2023
4d4ecf1
updated comments
benesjan Nov 27, 2023
783b5ca
updated comments
benesjan Nov 27, 2023
5a1cbab
more consistent naming
benesjan Nov 27, 2023
9312223
overflow fix
benesjan Nov 27, 2023
c6881b0
WIP
benesjan Nov 27, 2023
976278c
fixes
benesjan Nov 27, 2023
4e29bb5
getPublicDataTreeSiblingPath
benesjan Nov 28, 2023
8dca2be
test fix
benesjan Nov 28, 2023
11bbc4d
refactor: constraining block data in a separate function
benesjan Nov 28, 2023
4b2f793
cleanup
benesjan Nov 28, 2023
17eb82d
docs fixes
benesjan Nov 28, 2023
5dd0a8b
Adding TODO
benesjan Nov 28, 2023
e10c3cb
clarified naming
benesjan Nov 28, 2023
fdca497
todo
benesjan Nov 28, 2023
acc1cb1
passing context instead of blocks tree root
benesjan Nov 28, 2023
e9769bb
forgotten TODO
benesjan Nov 28, 2023
a52985b
merkle tree id issue
benesjan Nov 28, 2023
cea9ae8
fixed TSDoc
benesjan Nov 28, 2023
c5a10e4
WIP on nullifier inclusion proof (currently broken)
benesjan Nov 28, 2023
3c89221
fix nullifier inclusion
benesjan Nov 28, 2023
df26f17
LowNullifierMembershipWitness > NullifierMembershipWitness
benesjan Nov 28, 2023
c90c3e2
test: nullifier non-inclusion proof failure case
benesjan Nov 29, 2023
1745153
feat: PrivateContext::get_block_data(...)
benesjan Nov 29, 2023
138c7ef
test: more failure cases
benesjan Nov 29, 2023
b8678ae
Merge branch 'master' into janb/liquidity-mining-experiment
benesjan Nov 29, 2023
b8a1e6c
TODOs
benesjan Nov 29, 2023
edf4628
clearer errors
benesjan Nov 29, 2023
da730d9
using Promise.all
benesjan Nov 29, 2023
52a9095
Merge branch 'master' into janb/liquidity-mining-experiment
benesjan Nov 29, 2023
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
13 changes: 13 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -676,6 +676,17 @@ jobs:
name: "Test"
command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_escrow_contract.test.ts

e2e-inclusion-proofs-contract:
docker:
- image: aztecprotocol/alpine-build-image
resource_class: small
steps:
- *checkout
- *setup_env
- run:
name: "Test"
command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_inclusion_proofs_contract.test.ts

e2e-pending-commitments-contract:
docker:
- image: aztecprotocol/alpine-build-image
Expand Down Expand Up @@ -1113,6 +1124,7 @@ workflows:
- e2e-public-to-private-messaging: *e2e_test
- e2e-account-contracts: *e2e_test
- e2e-escrow-contract: *e2e_test
- e2e-inclusion-proofs-contract: *e2e_test
- e2e-pending-commitments-contract: *e2e_test
- e2e-ordering: *e2e_test
- uniswap-trade-on-l1-from-l2: *e2e_test
Expand Down Expand Up @@ -1148,6 +1160,7 @@ workflows:
- e2e-public-to-private-messaging
- e2e-account-contracts
- e2e-escrow-contract
- e2e-inclusion-proofs-contract
- e2e-pending-commitments-contract
- e2e-ordering
- uniswap-trade-on-l1-from-l2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ template <typename NCT> struct HistoricBlockData {
nullifier_tree_root,
contract_tree_root,
l1_to_l2_messages_tree_root,
blocks_tree_root, // Note private_kernel_vk_tree_root, is not included yet as
blocks_tree_root, // TODO(#3441) Note private_kernel_vk_tree_root, is not included yet as
// it is not present in noir,
public_data_tree_root,
global_variables_hash };
Expand Down
77 changes: 75 additions & 2 deletions yarn-project/acir-simulator/src/acvm/oracle/oracle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import { AztecAddress } from '@aztec/foundation/aztec-address';
import { padArrayEnd } from '@aztec/foundation/collection';
import { Fr, Point } from '@aztec/foundation/fields';
import { createDebugLogger } from '@aztec/foundation/log';
import { UnencryptedL2Log } from '@aztec/types';
import { MerkleTreeId, UnencryptedL2Log } from '@aztec/types';

import { ACVMField } from '../acvm_types.js';
import { fromACVMField } from '../deserialize.js';
import { frToNumber, fromACVMField } from '../deserialize.js';
import {
toACVMField,
toAcvmCallPrivateStackItem,
Expand Down Expand Up @@ -46,6 +46,79 @@ export class Oracle {
return [publicKey.x, publicKey.y, partialAddress].map(toACVMField);
}

async getMembershipWitness(
[blockNumber]: ACVMField[],
[treeId]: ACVMField[],
[leafValue]: ACVMField[],
): Promise<ACVMField[]> {
const parsedBlockNumber = frToNumber(fromACVMField(blockNumber));
const parsedTreeId = frToNumber(fromACVMField(treeId));
const parsedLeafValue = fromACVMField(leafValue);

const witness = await this.typedOracle.getMembershipWitness(parsedBlockNumber, parsedTreeId, parsedLeafValue);
if (!witness) {
throw new Error(
`Leaf ${leafValue} not found in the tree ${MerkleTreeId[parsedTreeId]} at block ${parsedBlockNumber}.`,
);
}
return witness.map(toACVMField);
}

async getSiblingPath(
[blockNumber]: ACVMField[],
[treeId]: ACVMField[],
[leafIndex]: ACVMField[],
): Promise<ACVMField[]> {
const parsedBlockNumber = frToNumber(fromACVMField(blockNumber));
const parsedTreeId = frToNumber(fromACVMField(treeId));
const parsedLeafIndex = fromACVMField(leafIndex);

const path = await this.typedOracle.getSiblingPath(parsedBlockNumber, parsedTreeId, parsedLeafIndex);
return path.map(toACVMField);
}

async getNullifierMembershipWitness(
[blockNumber]: ACVMField[],
[nullifier]: ACVMField[], // nullifier, we try to find the witness for (to prove inclusion)
): Promise<ACVMField[]> {
const parsedBlockNumber = frToNumber(fromACVMField(blockNumber));
const parsedNullifier = fromACVMField(nullifier);

const witness = await this.typedOracle.getNullifierMembershipWitness(parsedBlockNumber, parsedNullifier);
if (!witness) {
throw new Error(
`Low nullifier witness not found for nullifier ${parsedNullifier} at block ${parsedBlockNumber}.`,
);
}
return witness.toFieldArray().map(toACVMField);
}

async getLowNullifierMembershipWitness(
[blockNumber]: ACVMField[],
[nullifier]: ACVMField[], // nullifier, we try to find the low nullifier witness for (to prove non-inclusion)
): Promise<ACVMField[]> {
const parsedBlockNumber = frToNumber(fromACVMField(blockNumber));
const parsedNullifier = fromACVMField(nullifier);

const witness = await this.typedOracle.getLowNullifierMembershipWitness(parsedBlockNumber, parsedNullifier);
if (!witness) {
throw new Error(
`Low nullifier witness not found for nullifier ${parsedNullifier} at block ${parsedBlockNumber}.`,
);
}
return witness.toFieldArray().map(toACVMField);
}

async getBlockData([blockNumber]: ACVMField[]): Promise<ACVMField[]> {
const parsedBlockNumber = frToNumber(fromACVMField(blockNumber));

const blockData = await this.typedOracle.getBlockData(parsedBlockNumber);
if (!blockData) {
throw new Error(`Block data not found for block ${parsedBlockNumber}.`);
}
return blockData.toArray().map(toACVMField);
}

async getAuthWitness([messageHash]: ACVMField[]): Promise<ACVMField[]> {
const messageHashField = fromACVMField(messageHash);
const witness = await this.typedOracle.getAuthWitness(messageHashField);
Expand Down
38 changes: 36 additions & 2 deletions yarn-project/acir-simulator/src/acvm/oracle/typed_oracle.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
import { PrivateCallStackItem, PublicCallRequest } from '@aztec/circuits.js';
import { HistoricBlockData, PrivateCallStackItem, PublicCallRequest } from '@aztec/circuits.js';
import { FunctionSelector } from '@aztec/foundation/abi';
import { AztecAddress } from '@aztec/foundation/aztec-address';
import { EthAddress } from '@aztec/foundation/eth-address';
import { Fr, GrumpkinScalar } from '@aztec/foundation/fields';
import { CompleteAddress, Note, PublicKey, UnencryptedL2Log } from '@aztec/types';
import {
CompleteAddress,
MerkleTreeId,
Note,
NullifierMembershipWitness,
PublicKey,
UnencryptedL2Log,
} from '@aztec/types';

/**
* Information about a note needed during execution.
Expand Down Expand Up @@ -72,6 +79,33 @@ export abstract class TypedOracle {
throw new Error('Not available.');
}

getPublicKeyAndPartialAddress(_address: AztecAddress): Promise<Fr[] | undefined> {
throw new Error('Not available.');
}

getMembershipWitness(_blockNumber: number, _treeId: MerkleTreeId, _leafValue: Fr): Promise<Fr[] | undefined> {
throw new Error('Not available.');
}

getSiblingPath(_blockNumber: number, _treeId: MerkleTreeId, _leafIndex: Fr): Promise<Fr[]> {
throw new Error('Not available.');
}

getNullifierMembershipWitness(_blockNumber: number, _nullifier: Fr): Promise<NullifierMembershipWitness | undefined> {
throw new Error('Not available.');
}

getLowNullifierMembershipWitness(
_blockNumber: number,
_nullifier: Fr,
): Promise<NullifierMembershipWitness | undefined> {
throw new Error('Not available.');
}

getBlockData(_blockNumber: number): Promise<HistoricBlockData | undefined> {
throw new Error('Not available.');
}

getCompleteAddress(_address: AztecAddress): Promise<CompleteAddress> {
throw new Error('Not available.');
}
Expand Down
45 changes: 45 additions & 0 deletions yarn-project/acir-simulator/src/client/db_oracle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { FunctionArtifact, FunctionDebugMetadata, FunctionSelector } from '@azte
import { AztecAddress } from '@aztec/foundation/aztec-address';
import { EthAddress } from '@aztec/foundation/eth-address';
import { Fr } from '@aztec/foundation/fields';
import { L2Block, MerkleTreeId, NullifierMembershipWitness } from '@aztec/types';

import { NoteData } from '../acvm/index.js';
import { CommitmentsDB } from '../public/index.js';
Expand Down Expand Up @@ -114,4 +115,48 @@ export interface DBOracle extends CommitmentsDB {
* @returns A Promise that resolves to a HistoricBlockData object.
*/
getHistoricBlockData(): Promise<HistoricBlockData>;

/**
* Fetch the index of the leaf in the respective tree
* @param blockNumber - The block number at which to get the leaf index.
* @param treeId - The id of the tree to search.
* @param leafValue - The leaf value buffer.
* @returns - The index of the leaf. Undefined if it does not exist in the tree.
*/
findLeafIndex(blockNumber: number, treeId: MerkleTreeId, leafValue: Fr): Promise<bigint | undefined>;

/**
* Fetch the sibling path of the leaf in the respective tree
* @param blockNumber - The block number at which to get the sibling path.
* @param treeId - The id of the tree to search.
* @param leafIndex - The index of the leaf.
* @returns - The sibling path of the leaf.
*/
getSiblingPath(blockNumber: number, treeId: MerkleTreeId, leafIndex: bigint): Promise<Fr[]>;
benesjan marked this conversation as resolved.
Show resolved Hide resolved

/**
* Returns a nullifier membership witness for a given nullifier at a given block.
* @param blockNumber - The block number at which to get the index.
* @param nullifier - Nullifier we try to find witness for.
* @returns The nullifier membership witness (if found).
*/
getNullifierMembershipWitness(blockNumber: number, nullifier: Fr): Promise<NullifierMembershipWitness | undefined>;

/**
* Returns a low nullifier membership witness for a given nullifier at a given block.
* @param blockNumber - The block number at which to get the index.
* @param nullifier - Nullifier we try to find the low nullifier witness for.
* @returns The low nullifier membership witness (if found).
* @remarks Low nullifier witness can be used to perform a nullifier non-inclusion proof by leveraging the "linked
* list structure" of leaves and proving that a lower nullifier is pointing to a bigger next value than the nullifier
* we are trying to prove non-inclusion for.
*/
getLowNullifierMembershipWitness(blockNumber: number, nullifier: Fr): Promise<NullifierMembershipWitness | undefined>;

/**
* Fetch a block corresponding to the given block number.
* @param blockNumber - The block number of a block to fetch.
* @returns - The block corresponding to the given block number. Undefined if it does not exist.
*/
getBlock(blockNumber: number): Promise<L2Block | undefined>;
}
82 changes: 80 additions & 2 deletions yarn-project/acir-simulator/src/client/view_data_oracle.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { HistoricBlockData, PublicKey } from '@aztec/circuits.js';
import { siloNullifier } from '@aztec/circuits.js/abis';
import { computeGlobalsHash, siloNullifier } from '@aztec/circuits.js/abis';
import { AztecAddress } from '@aztec/foundation/aztec-address';
import { Fr } from '@aztec/foundation/fields';
import { createDebugLogger } from '@aztec/foundation/log';
import { AuthWitness, AztecNode, CompleteAddress } from '@aztec/types';
import { AuthWitness, AztecNode, CompleteAddress, MerkleTreeId, NullifierMembershipWitness } from '@aztec/types';

import { NoteData, TypedOracle } from '../acvm/index.js';
import { DBOracle } from './db_oracle.js';
Expand Down Expand Up @@ -35,6 +35,84 @@ export class ViewDataOracle extends TypedOracle {
return this.db.getSecretKey(this.contractAddress, owner);
}

/**
* Fetches the index and sibling path of a leaf at a given block from a given tree.
* @param blockNumber - The block number at which to get the membership witness.
* @param treeId - Id of the tree to get the sibling path from.
* @param leafValue - The leaf value
* @returns The index and sibling path concatenated [index, sibling_path]
*/
public async getMembershipWitness(blockNumber: number, treeId: MerkleTreeId, leafValue: Fr): Promise<Fr[]> {
const index = await this.db.findLeafIndex(blockNumber, treeId, leafValue);
if (!index) {
throw new Error(`Leaf value: ${leafValue} not found in ${MerkleTreeId[treeId]}`);
}
const siblingPath = await this.db.getSiblingPath(blockNumber, treeId, index);
return [new Fr(index), ...siblingPath];
}

/**
* Fetches a sibling path at a given block and index from a tree specified by `treeId`.
* @param blockNumber - The block number at which to get the membership witness.
* @param treeId - Id of the tree to get the sibling path from.
* @param leafIndex - Index of the leaf to get sibling path for
* @returns The sibling path.
*/
public getSiblingPath(blockNumber: number, treeId: MerkleTreeId, leafIndex: Fr): Promise<Fr[]> {
return this.db.getSiblingPath(blockNumber, treeId, leafIndex.toBigInt());
}

/**
* Returns a nullifier membership witness for a given nullifier at a given block.
* @param blockNumber - The block number at which to get the index.
* @param nullifier - Nullifier we try to find witness for.
* @returns The nullifier membership witness (if found).
*/
public async getNullifierMembershipWitness(
blockNumber: number,
nullifier: Fr,
): Promise<NullifierMembershipWitness | undefined> {
return await this.db.getNullifierMembershipWitness(blockNumber, nullifier);
}

/**
* Returns a low nullifier membership witness for a given nullifier at a given block.
benesjan marked this conversation as resolved.
Show resolved Hide resolved
* @param blockNumber - The block number at which to get the index.
* @param nullifier - Nullifier we try to find the low nullifier witness for.
* @returns The low nullifier membership witness (if found).
* @remarks Low nullifier witness can be used to perform a nullifier non-inclusion proof by leveraging the "linked
* list structure" of leaves and proving that a lower nullifier is pointing to a bigger next value than the nullifier
* we are trying to prove non-inclusion for.
*/
public async getLowNullifierMembershipWitness(
blockNumber: number,
nullifier: Fr,
): Promise<NullifierMembershipWitness | undefined> {
return await this.db.getLowNullifierMembershipWitness(blockNumber, nullifier);
}

/**
* Fetches historic block data for a given block.
* @param blockNumber - The block number at which to get the historic block data.
* @returns Historic block data extracted from a block with block number `blockNumber`.
*/
public async getBlockData(blockNumber: number): Promise<HistoricBlockData | undefined> {
const block = await this.db.getBlock(blockNumber);
if (!block) {
return undefined;
}
return new HistoricBlockData(
block.endNoteHashTreeSnapshot.root,
block.endNullifierTreeSnapshot.root,
block.endContractTreeSnapshot.root,
block.endL1ToL2MessagesTreeSnapshot.root,
block.endHistoricBlocksTreeSnapshot.root,
new Fr(0), // TODO(#3441) privateKernelVkTreeRoot is not present in L2Block and it's not yet populated in noir
block.endPublicDataTreeRoot,
computeGlobalsHash(block.globalVariables),
);
}

/**
* Retrieve the complete address associated to a given address.
* @param address - Address to fetch the complete address for.
Expand Down
Loading