-
Notifications
You must be signed in to change notification settings - Fork 305
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
Changes from 2 commits
c37efa5
3da1c78
94f43be
32d2e39
6343553
ce3c4ab
f159824
c98a5af
bbf4e66
e152b2c
af94bc9
e267f8d
7d2fab6
7cdd90e
3bf3036
78eaadb
5528be5
61a3682
39b6011
227553f
3635866
71508b1
eb5c260
508ab15
cf14859
b10f34c
38ba6b4
ab2ba46
1819c24
0016721
61c6f85
7360736
f407ce7
4b779af
1a5c4ab
ec0d319
b9699d7
ff79a1f
5533c1a
9e8890c
2329113
b298fc8
4d4ecf1
783b5ca
5a1cbab
9312223
c6881b0
976278c
4e29bb5
8dca2be
11bbc4d
4b2f793
17eb82d
5dd0a8b
e10c3cb
fdca497
acc1cb1
e9769bb
a52985b
cea9ae8
c5a10e4
3c89221
df26f17
c90c3e2
1745153
138c7ef
b8678ae
b8a1e6c
edf4628
da730d9
52a9095
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
import { AccountWallet, CompleteAddress, PXE } from '@aztec/aztec.js'; | ||
import { AccountWallet, AztecAddress, CompleteAddress, Fr, PXE } from '@aztec/aztec.js'; | ||
import { InclusionProofsContract } from '@aztec/noir-contracts/types'; | ||
|
||
import { jest } from '@jest/globals'; | ||
|
@@ -29,7 +29,7 @@ describe('e2e_inclusion_proofs_contract', () => { | |
|
||
afterAll(() => teardown()); | ||
|
||
it('creates a note and proves its existence', async () => { | ||
it('proves note existence and its nullifier non-existence and nullifier non-existence failure case', async () => { | ||
// Owner of a note | ||
const owner = accounts[0].address; | ||
{ | ||
|
@@ -48,14 +48,16 @@ describe('e2e_inclusion_proofs_contract', () => { | |
// Prove note inclusion in a given block. | ||
// We prove the note existence at current block number because we don't currently have historical data | ||
const blockNumber = await pxe.getBlockNumber(); | ||
await contract.methods.proveNoteInclusion(owner, blockNumber).send().wait(); | ||
const ignoredCommitment = 0; // Not ignored only when the note doesn't exist | ||
await contract.methods.proveNoteInclusion(owner, blockNumber, ignoredCommitment).send().wait(); | ||
} | ||
|
||
{ | ||
// Prove that the note has not been nullified | ||
// We prove the note existence at current block number because we don't currently have historical data | ||
const blockNumber = await pxe.getBlockNumber(); | ||
await contract.methods.proveNullifierNonInclusion(owner, blockNumber, 0).send().wait(); | ||
const ignoredNullifier = 0; // Not ignored only when the note doesn't exist | ||
await contract.methods.proveNullifierNonInclusion(owner, blockNumber, ignoredNullifier).send().wait(); | ||
} | ||
|
||
{ | ||
|
@@ -75,16 +77,44 @@ describe('e2e_inclusion_proofs_contract', () => { | |
} | ||
}); | ||
|
||
it('note existence failure case', async () => { | ||
// Owner of a note | ||
const owner = AztecAddress.random(); | ||
|
||
const blockNumber = await pxe.getBlockNumber(); | ||
const randomNoteCommitment = Fr.random(); | ||
await expect( | ||
contract.methods.proveNoteInclusion(owner, blockNumber, randomNoteCommitment).send().wait(), | ||
).rejects.toThrow(/Leaf value: 0x[0-9a-fA-F]+ not found in tree/); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. UX thing - why are the error messages so different from each other? If it isn't tooo much work, Can all of them be consistent: For note failure - Actually Jan for nullifier tree inclusion, do we check against the low nullifier witness? For nullifier noninclusion failure - `nullifier exists in the nullifier tree. Low nullifier [value].next_value is [nullifier] There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Made the errors clearer in edf4628 For the note inclusion failure case it's having the same error is a bit tricky because there it fails in the oracle call and not when doing assertions and that's because in sparse tree and indexed tree you never fail to get a membership witness.
No, for nullifier inclusion I just do standard membership proof. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the standard to do it the low nullifier way in the rest of the codebase? I have not worked with indexed tree much before |
||
}); | ||
|
||
it('proves an existence of a public value in private context', async () => { | ||
const blockNumber = await pxe.getBlockNumber(); | ||
await contract.methods.provePublicValueInclusion(publicValue, blockNumber).send().wait(); | ||
}); | ||
|
||
it('public value existence failure case', async () => { | ||
const blockNumber = await pxe.getBlockNumber(); | ||
const randomPublicValue = Fr.random(); | ||
await expect( | ||
contract.methods.provePublicValueInclusion(randomPublicValue, blockNumber).send().wait(), | ||
).rejects.toThrow(/Proving membership of a value in public data tree failed/); | ||
}); | ||
|
||
it('proves existence of a nullifier in private context', async () => { | ||
benesjan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const blockNumber = await pxe.getBlockNumber(); | ||
const block = await pxe.getBlock(blockNumber); | ||
const nullifier = block?.newNullifiers[0]; | ||
|
||
await contract.methods.proveNullifierInclusion(nullifier!, blockNumber).send().wait(); | ||
}); | ||
|
||
it('nullifier existence failure case', async () => { | ||
const blockNumber = await pxe.getBlockNumber(); | ||
const randomNullifier = Fr.random(); | ||
|
||
await expect(contract.methods.proveNullifierInclusion(randomNullifier, blockNumber).send().wait()).rejects.toThrow( | ||
/Low nullifier witness not found for nullifier 0x[0-9a-fA-F]+ at block/, | ||
); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -101,23 +101,29 @@ contract InclusionProofs { | |
fn proveNoteInclusion( | ||
benesjan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
owner: AztecAddress, | ||
block_number: Field, // The block at which we'll prove that the note exists | ||
spare_commitment: Field, // This is only used when the note is not found --> used to test the failure case | ||
) { | ||
// TODO: assert that block number is less than the block number of context.block_data | ||
// --> This will either require a new oracle method that returns block_data.global_variables_hash preimage | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would prefer the oracle for one main reason: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But having the oracle would result in more hashing because I would have to hash there the preimage to check that it matches the globals hash. Don't you think having a function There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What about |
||
// or modifying the private context so that we somehow expose it. | ||
|
||
// 1) Get historic block data from oracle and ensure that the block hash is included in the current blocks tree | ||
// root. | ||
let block_data = get_block_data(block_number, context); | ||
let block_data = context.get_block_data(block_number); | ||
|
||
// 2) Get the note from PXE. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The amount of boiler plate for this is quite wild. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the only thing that isnt boilerplate is the actual commitment itself, this could probably be moved into a method to be reused? Potentially bolted onto the context There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that manually calling the compute_unique_siloed_note_hash function is not common enough to justify bolting it onto context. But getting a first note from a set and unwrapping it seems very common. Should we expand
would look like this:
WDYT? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you would need to have some filter or sort in there for the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @iAmMichaelConnor I am not really rooting for doing this now as it's not clear yet if this is a common usecase. |
||
let private_values = storage.private_values.at(owner.address); | ||
let options = NoteGetterOptions::new().select(1, owner.address).set_limit(1); | ||
let notes = private_values.get_notes(options); | ||
let note = notes[0].unwrap(); | ||
let maybe_note = notes[0]; | ||
|
||
// 3) Compute the commitment from the note | ||
let note_commitment = note_utils::compute_unique_siloed_note_hash(ValueNoteMethods, note); | ||
let note_commitment = if maybe_note.is_some() { | ||
note_utils::compute_unique_siloed_note_hash(ValueNoteMethods, maybe_note.unwrap_unchecked()) | ||
} else { | ||
// Note was not found so we will use the spare commitment | ||
spare_commitment | ||
}; | ||
|
||
// 4) Get the membership witness of the note in the note hash tree | ||
let note_hash_tree_id = 2; // TODO(#3443) | ||
|
@@ -146,7 +152,7 @@ contract InclusionProofs { | |
|
||
// 1) Get historic block data from oracle and ensure that the block hash is included in the current blocks tree | ||
// root. | ||
let block_data = get_block_data(block_number, context); | ||
let block_data = context.get_block_data(block_number); | ||
|
||
// 2) Get the note from PXE | ||
let private_values = storage.private_values.at(owner.address); | ||
|
@@ -217,7 +223,7 @@ contract InclusionProofs { | |
|
||
// 1) Get historic block data from oracle and ensure that the block hash is included in the current blocks tree | ||
// root. | ||
let block_data = get_block_data(block_number, context); | ||
let block_data = context.get_block_data(block_number); | ||
|
||
// 2) Get the membership witness of the nullifier | ||
let witness = get_nullifier_membership_witness(block_number, nullifier); | ||
|
@@ -249,7 +255,7 @@ contract InclusionProofs { | |
|
||
// 1) Get historic block data from oracle and ensure that the block hash is included in the current blocks tree | ||
// root. | ||
let block_data = get_block_data(block_number, context); | ||
let block_data = context.get_block_data(block_number); | ||
|
||
// 2) Compute the public value leaf index. | ||
// We have to compute the leaf index here because unlike in the case of note commitments, public values are | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how is this failure case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the test I nullify the note and I try to prove the nullifier non-inclusion again.