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

Aard custom #49

Merged
merged 23 commits into from
Feb 24, 2025
Merged

Aard custom #49

merged 23 commits into from
Feb 24, 2025

Conversation

tideofwords
Copy link
Collaborator

initial PR for custom deduction docs

@arnaucube arnaucube added the deductions [tmp while we're specifying] deduction-related issues label Feb 12, 2025

When a custom predicate is introduced in a MainPod, it becomes available for use in that POD and all PODs that inherit[^inherit] from it.

A custom predicate can be defined either _nonrecursively_ or _recursively_ (as part of a "batch"). A nonrecursive custom predicate is defined in terms of previously defined predicates (whether custom or native). A "batch" of custom predicates can be defined _recursively_: the definition of any custom predicate in the batch can use both previously defined predicates and all the predicates in the batch.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

About the "batch" term. Can we discuss alternatives?
I've thought about "group" or "unit".

We could also use the terminology: a custom predicate is defined with conjunctions and disjunctions of statements. At the backend level this is achieved with sub-predicates that are either conjunctions or disjunctions. So with this naming there's no "batch", it's either a custom predicate (high level view) or sub-predicate (what you call a custom predicate that belongs to a batch).

Also, could we agree that a list of predicates that form a batch have a single top level predicate, which is the one that the user cares about?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing to "group".

In general, will the frontend allow combinations of conjunction and disjunction in a single custom predicate? As in
pred1:
AND(OR(pred2, pred3), pred4)?
This looks like a good idea.

In this case, of course we would also allow a recursive definition, like
pred1:
AND(OR(pred2, pred3), pred1).

If we require a single top-level predicate for each group, the user won't be able to make multiple predicates depend on each other recursively. I can't think of a natural use case where you would want that, but if the backend allows it, why disable it on the frontend?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing to "group".

In general, will the frontend allow combinations of conjunction and disjunction in a single custom predicate? As in pred1: AND(OR(pred2, pred3), pred4)? This looks like a good idea.

In this case, of course we would also allow a recursive definition, like pred1: AND(OR(pred2, pred3), pred1).

I also think this is a good idea for the frontend. Nevertheless I also think it's OK to start with a simpler version where we don't implement it yet and leave it as a TODO for later.

If we require a single top-level predicate for each group, the user won't be able to make multiple predicates depend on each other recursively. I can't think of a natural use case where you would want that, but if the backend allows it, why disable it on the frontend?

Why having a single top-level predicate in a group doesn't allow the user to have multiple predicates depend on each other recursively? Is it because those internal predicates don't have names that the user can refer to? If that's the case, I think the user could still give names to internal predicates during the build process to reference them, and still end up with a single top-level predicate in the group. Or is there any other reason?

I thought about assuming a single top-level predicate for each group because then we could say the top-level (entry-point) predicate always takes the same index in the group (let's say: 0). This would be a convention that could facilitate debugging.


## Custom predicates and their IDs

A custom predicate, like a built-in predicate, is identified by a _name_ on the front end and an _identifier_ on the back end. In the non-recursive case, the back-end identifier is defined as a hash of the definition of the custom predicate.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would propose that in the backend we don't distinguish recursive and non-recursive cases (or batched / non-batched). Instead all custom predicates have the recursivity capability. And if we don't need recursion we just make a batch of a single predicate.

Implementation wise that may mean that we make a merkle tree out of a single custom predicate and identify it with mt_root.0

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good to me

you have to provide the following witnesses in-circuit.

- Copy of the deduction rule
- Values for *1, *2, *3, *4, *5. (*1, *2, *4 should be OriginIDs for the three origins; *3 and *5 should be key names.)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we could skip the type checking in the circuit, considering that all of these values are encoded as 4 field elements in plonky2.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's right, you don't have to enforce type checking in-circuit (I think you can't anyway?), because the conditions can only be satisfied if the types are right.


The definition of a custom predicate might also be called an _operation_ or _deduction rule_. It includes two (or, potentially, say, five) input statements. The arguments to the input statements are decomposed as (origin, key) pairs: if statements are allowed to have arity at most 4, then the input statements in a deduction rule will have at most 8 arguments (4 origins and 4 keys). The same holds for the output statement.

Each argument (origin or key) to an input statement is either a wildcard or a literal. In the backend, the wildcard arguments will be identified as *1, *2, *3, ....
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would propose using the name "statement template" for statements we use to build a custom predicate.
The template would include the Predicate and the list of "template arguments" which would be what you call "wildcard".

I looked at two famous template libraries and they call this "wildcards" "tags"

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But I think I like the term "wildcard" better than "tag".

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Statement templates" is good

Equal(name_from_pod1, friend_from_pod2)
```

## How to inherit local variables from a previous POD
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would appreciate an example use-case to be added here https://github.com/0xPARC/pod2/blob/main/book/src/examples.md
which requires propagating keys from PODs, because I believe there are different ways to approach this propagation / inheritance of keys but I find it hard to reason if a particular way is good or not because I don't have a use-case to validate it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool, I'm adding "attested great boy pod", which reveals the names of the friends who have good boy pods.

book/src/notes Outdated
@@ -0,0 +1,6 @@
Ethdos(x, y, d) = OR ( EthdosBase(x, y, d), EthdosInd(x, y, d) )
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this file was committed by mistake?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, removed it

>

On the backend, this is converted to a rule where all the arguments are either wildcards or literals:
eth_friend(*1, *2, *3, *4) = and<
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a very interesting example to discuss the topic of arities in custom predicates.
This custom predicate has:

@ed255 ed255 mentioned this pull request Feb 18, 2025
@arnaucube arnaucube added this to the Milestone 2 milestone Feb 19, 2025
@arnaucube
Copy link
Collaborator

Since @ed255 is off for the next few weeks, is it ok @tideofwords if we merge this PR as a consolidation of the current spec that we're already implementing?
And when @ed255 comes back can check your answers and we can iterate if needed.

```
eth_friend(src_or, src_key, dst_or, dst_key) = and<
// there is an attestation pod that's a SIGNATURE POD
ValueOf(attestation_pod, "type", SIGNATURE)
Copy link
Collaborator

@arnaucube arnaucube Feb 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question, is the attestation_pod a 'private' argument? if so, should it need to be defined in some way at the predicate definition, something like
eth_friend(src_or, src_key, dst_or, dst_key, priv attestation_pod) = and<...?
(probably not with this syntax, but specifying somehow that the attestation_pod is an input to the template)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

attestation_pod is an argument to the operation, but not an argument to the predicate.

In other words:
When you do the operation in-circuit, you need to provide attestation_pod as a witness.
But in the list of statements, when you have an eth_friend statement, you don't show the attestation_pod there.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh I see, thanks!

@tideofwords
Copy link
Collaborator Author

Since @ed255 is off for the next few weeks, is it ok @tideofwords if we merge this PR as a consolidation of the current spec that we're already implementing? And when @ed255 comes back can check your answers and we can iterate if needed.

Yep, this is good

@tideofwords tideofwords merged commit d3bc892 into main Feb 24, 2025
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
deductions [tmp while we're specifying] deduction-related issues
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants