-
Notifications
You must be signed in to change notification settings - Fork 3
Yulia/app data update #386
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
Conversation
- Updated project version to 1.0.0 in pyproject.toml and VERSION file. - Removed obsolete Juvix documentation files related to various node engines and subsystems to streamline the codebase. - Adjusted mkdocs.yml to reflect the changes in documentation structure.
Simplified the architecture section by removing the Node architecture details to reference it as a work-in-progress found in release v0.2.0. Updated tags in multiple documentation files, aligning them with the current scope of content and removing outdated references to the Node architecture. These changes aim to streamline the documentation by focusing on existing, fully developed components while acknowledging ongoing development work separately.
Added a note about the removal of node architecture in the latest release. The node architecture details are available in the v0.2.0 documentation, with plans to reintegrate it in the upcoming v2.0.0 release.
|
The preview of this PR has been deleted. |
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.
lgtm
Left a comment regarding the commitment to logicRef in logicVKOuter.
| |`discoveryPayload`|Contains the discovery-related data, for example, FMD ciphertext. If no discovery payload is expected to be verified, the field is left empty.| | ||
| |`externalCallPayload`|Contains the data associated with external calls. If no external calls are made or no external calldata has to be verified, the field is left empty.| | ||
| |`logicVKOuter`|`LogicVKOuterHash`|In the DP (data privacy only) case, contains `logicRef` associated with the corresponding resource. In the FP (data and function privacy) case, contains a hiding and binding commitment to `logicRef`. It can be said that in the DP case outer hash is an identity function and in the FP case it is instantiated by a hiding and binding commitment scheme.| | ||
| |`logicVKOuter`|In the DP (data privacy only) case, contains `logicRef` associated with the corresponding resource. In the FP (data and function privacy) case, contains a hiding and binding commitment to `logicRef`. It can be said that in the DP case outer hash is an identity function and in the FP case it is instantiated by a hiding and binding commitment scheme.| |
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.
Are you using logicVKOuter to unify the inner logic instance in DP with the outer instance in FP? In FP, it would be better to use a hiding and binding commitment to verifyingKey, which implicitly includes logicRef = hash(verifyingKey) — specifically, cm = commit(hash(verifyingKey), r). Alternatively, we can add the hash check explicitly. Since we can also retrieve logicRef from the inner instance's logicVKOuter in the outer circuit, we still need the hash check because the inner logicRef is not reliable for outer circuits. It could be ambiguous where the logicRef comes from if only a commitment to logicRef is provided.
In FP compliance, we commit to logicRef without requiring a hash.
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.
logicVKOuter corresponds to logicRef in the DP case (the one we pass to compliance to check against r.logicRef) and to a proper commitment in FP case. verifyingKey contains the actual field to be used to verify the proof
My impression is that it is just like we discussed it, but without the extra FP details (they will go to the risc0 spec)
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.
Minor thought in addition: what if the type of appdata will instead be:
Map(payload => List(Bitsring, DeletionCriterion))
where payload can be any of some encoding of strings resourcePayload, discoveryPayload, externalCallPayload, logicVKOuter, appPayload
That way "empty field" comment would make sense to me as that would mean that the key would just have an empty list attached.
We can then just decide which payload goes in which order for the circuit to process.
|
|
||
| |Name|Description| | ||
| |-|-| | ||
| |`resourcePayload`|Contains the resource-object-related data. For example, in the shielded case, it contains encrypted resource object. If no resource payload is expected to be verified, the field is left empty.| |
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.
What does "field left empty" mean? The datatype of appdata is a List(Bitstring, DeletionCriterion). I am unsure what the notion of "field" is here and what does "empty" mean here.
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.
Can you also elaborate on what "resource-object-related-data" is?
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.
You are right, it shouldn't be just empty. It should be some reserved bitstring sequence that basically means empty.
Resource-oject-related data is any data about the resource object that is required to be passed. In the shielded case it would be the encrypted resource object. It could also be resource object itself, without encryption.
| |Name|Description| | ||
| |-|-| | ||
| |`resourcePayload`|Contains the resource-object-related data. For example, in the shielded case, it contains encrypted resource object. If no resource payload is expected to be verified, the field is left empty.| | ||
| |`discoveryPayload`|Contains the discovery-related data, for example, FMD ciphertext. If no discovery payload is expected to be verified, the field is left empty.| |
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.
Similar here re "field empty".
| |-|-| | ||
| |`resourcePayload`|Contains the resource-object-related data. For example, in the shielded case, it contains encrypted resource object. If no resource payload is expected to be verified, the field is left empty.| | ||
| |`discoveryPayload`|Contains the discovery-related data, for example, FMD ciphertext. If no discovery payload is expected to be verified, the field is left empty.| | ||
| |`externalCallPayload`|Contains the data associated with external calls. If no external calls are made or no external calldata has to be verified, the field is left empty.| |
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.
Similar here re "field empty".
| |`resourcePayload`|Contains the resource-object-related data. For example, in the shielded case, it contains encrypted resource object. If no resource payload is expected to be verified, the field is left empty.| | ||
| |`discoveryPayload`|Contains the discovery-related data, for example, FMD ciphertext. If no discovery payload is expected to be verified, the field is left empty.| | ||
| |`externalCallPayload`|Contains the data associated with external calls. If no external calls are made or no external calldata has to be verified, the field is left empty.| | ||
| |`logicVKOuter`|In the DP (data privacy only) case, contains `logicRef` associated with the corresponding resource. In the FP (data and function privacy) case, contains a hiding and binding commitment to `logicRef`. It can be said that in the DP case outer hash is an identity function and in the FP case it is instantiated by a hiding and binding commitment scheme.| |
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.
Can you elaborate how that relates to the logicVKOuter in the Compliance Units?
Is it something extra to be checked in the verify?
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.
logicVKOuter is passed as input to the compliance proof to verify it is correctly computed from logicRef. It is the same field here and there. In the data privacy case (our only case currently), it is only used in compliance proof check. In the FP case, it would be passed as input to the outer circuit as well. Do you think it makes more sense to just keep it in compliance instance and get it from there for FP 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.
@XuyangSong would probably know better here
I think the only thing I can say is my general rule of thumb is: do not duplicate information when unneeded as that just introduces extra checks to make.
E.g. adding this to appdata instead of asking the verifier to put the corresponding logicVKOuter from the Compliance Units means that we either way need to search for it and make sure it corresponds.
Similarly to isConsumed, where we need to explicitly make sure that the tag appears in the correct position in the compliance unit to make sure all the semantics get satisfied.
Hopefully this makes sense.
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'll remove it
I agree that a map should be clearer. Let’s first check if it’s costly in circuits and Solidity. I’ll run some circuit tests. I believe @heueristik can confirm the cost in Solidity. |
The "maps" we use in solidity are just a list of 2-tuples, so should be fine. |
That makes sense as a solution to the problem, but wouldn't it be just easier to define an "empty" bitstring sequence that for the reserved fields mean that they are empty instead of layering the data structure? |
I mean the operations in the map, like get, insert, etc. |
I think that both things can be solutions to the problem. It would be a matter of practical utility. I would say that the proposal to make it a map with values being lists is twofold:
So in my proposal to make it a map we can instead just put Well, the point I guess I am trying to make is that this way the individual RMs can figure out how to put data there with greater ease. How does that sound @XuyangSong @vveiln |
The verifier would know that an empty hash is an empty parameter and just wouldn't pass it to the logic, the logic wouldn't have to see these inputs. I agree with the encoding point though, it also would offload the work from the circuit, which is always good. I'll change the format to the proposed one. |
|
@vveiln another idea I just had is maybe just make it a 5-tuple of lists? So the type would be Where each position is beforehand tied to one of the payloads? That way we don't have to worry about how to encode names of the fields and beforehand decide on the order all of this goes in to the instance |
|
I removed |
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.
Why are you deleting all those files? See the files changed
|
These changes were generated by git automatically. As I understand, this is the diff between main and v1.0.0 – all the files related to engines and such removed, but I might be wrong. |
Are we using a fixed array here? The struct would look like this: struct AppData ( [Vec<(Vec<u8>, DC)>; 4] )If only four entries are involved, do you think we can add the payload names to the struct? It seems better than relying on fixed positions. such as struct AppData {
resource_payload: Vec<(Vec<u8>, DC)>,
discovery_payload: Vec<(Vec<u8>, DC)>,
external_payload: Vec<(Vec<u8>, DC)>,
application_payload: Vec<(Vec<u8>, DC)>,
}If we plan to extend payloads to five or six in the future, the fixed array may not be suitable, and we can use a variable array instead, like: struct AppData (Vec<Vec<(Vec<u8>, DC)>>)Then developers need to remember the positions. |
I think this can be seen as an implementation detail. The struct you have can have the same semantics as the 4-tuple. Either way we have to order them in some way in order to know in which order to place them into the instance. In other words, I think we can make the appdata the struct you mentioned without needing to change the current spec. So I am ambivalent as to whether we change it to an ADT or just keep it like a tuple. But I actually would also like for the implementation to be a stuct on the Rust/Solidity side. |
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.
Sorry for vetoing the upgrade again, but I am unsure why we are putting the depth in the Action datatype. Could you elaborate on that?
Also, do we need to change anything for the Compliance Unit? It would be really nice if the compliance unit could accept variable-size commitment-accumulator.
| |-|-|-| | ||
| |`logicVerifierInputs`|`Map Tag LogicVerifierInputs`|For each resource tag, contains the associated logic proof and everything required to verify it. The structure of `LogicVerifierInputs` is further described below.| | ||
| |`complianceUnits`|`List ComplianceUnit`|The set of transaction's [[Compliance unit | compliance units]]| | ||
| |`actionTreeSize`||Determines the depth of the Merkle tree used to store input resources. If not specified, the depth is set to the smallest necessary to fit all the input resources.| |
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.
Should this be part of the action? Why do we need to let the user provide it?
Wouldn't it be the RM that decides beforehand whether it will use the smallest action tree needed or a fixed-size one based on the proving system it uses?
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.
Because we want the verifier to know the depth of the tree to build in case the depth is not set dynamically. It is added for compatibility with proving systems that do not support variable tree size like zkvms do.
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 have to think about that.
But also: what is the type of the input and what do we mean by "empty"?
Maybe we can decide on a type of integers and if the value is -1 we construct the least size one?
Or maybe we can just make it natural numbers? i.e. not include the option for it to be "empty"?
That way it's the higher-level interface which will compute that number if needed.
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 do think I now understand the usefulness of this for RMs that have proving systems that can only have fixed-size argments and hence support only fixed-size merkle proofs.
This way it's the application developer who decides how many resources can exist with the resource in the same action instead of us. E.g. currently we support only 16 resources per action, it is a cutoff based on the RM design as that's the tree which we construct
But now you submit the tree depth information yourself and hence determine the proof length that you expect
However, that does mean only apps which expect the same depth can be part of the same action
So every application can have different verifying keys based on which tree depth they expect
I dunno how much we would want that...
But for the veritable tree depth supporting proving systems, how does it help? I am unsure still
|
|
||
| The original order of the elements must be preserved at each step. | ||
|
|
||
| #### Witness |
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.
Outside of this PR but wanted to mention:
At some point we should probably change this page to reflect the part that we don't control the witness of the resource logics.
Moreover, parts 3 and 4 seem to imply that we put all the resources created and consumed into the witness info. However as we have discussed this actually rarely happens and we don't even have apps that have such witness structure.
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.
At some point we should probably change this page to reflect the part that we don't control the witness of the resource logics.
I'm not sure what you mean by that. We generally can't control anything that is provided by the user, but we specify what we expect to receive
Moreover, parts 3 and 4 seem to imply that we put all the resources created and consumed into the witness info. However as we have discussed this actually rarely happens and we don't even have apps that have such witness structure.
I'll add a note that passing all resource objects as witnesses is not necessary, but we can't say if it happens rarely in principle
This PR adds the following changes to the spec:
applicationDatastructure with four reserved fields: resourcePayload, discoveryPayload, externalPayload, and logicVKOuter hash.logicVKOuterfield inlogicVerifierInputswith a genericverifyingKeyand moveslogicVKOutertoappData, as described aboveisConsumedflag fromlogicVerifierInputsas in can be inferred from the compliance instance structureAll relevant changes are in this file: docs/arch/system/state/resource_machine/data_structures/action/index.juvix.md (everything else is some random stuff git made me do)