-
Notifications
You must be signed in to change notification settings - Fork 3
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
Aard custom #49
Conversation
Make syntax and notation consistent with Rust source code.
Co-authored-by: Ahmad Afuni <[email protected]>
Co-authored-by: Ahmad Afuni <[email protected]>
Co-authored-by: Ahmad Afuni <[email protected]>
book/src/custom.md
Outdated
|
||
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. |
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.
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?
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.
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?
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.
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.
book/src/custom.md
Outdated
|
||
## 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. |
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.
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
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.
Sounds good to me
book/src/custom1.md
Outdated
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.) |
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.
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.
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.
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.
book/src/custom1b.md
Outdated
|
||
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, .... |
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.
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"
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.
But I think I like the term "wildcard" better than "tag".
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.
"Statement templates" is good
Equal(name_from_pod1, friend_from_pod2) | ||
``` | ||
|
||
## How to inherit local variables from a previous POD |
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.
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.
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.
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) ) |
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.
Maybe this file was committed by mistake?
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.
Yep, removed it
book/src/customexample.md
Outdated
> | ||
|
||
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< |
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.
This is a very interesting example to discuss the topic of arities in custom predicates.
This custom predicate has:
- The predicate has 4 arguments (that's what I was calling public in [Custom Statements] Custom Predicates with binary AND, OR #54)
- The predicate has 5 wildcards
- The predicate has 1 wildcard that doesn't come from a predicate argument (that's what I was calling private in [Custom Statements] Custom Predicates with binary AND, OR #54)
Co-authored-by: Eduard S. <[email protected]>
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? |
book/src/customexample.md
Outdated
``` | ||
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) |
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.
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)
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.
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.
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.
oh I see, thanks!
Yep, this is good |
initial PR for custom deduction docs