-
Notifications
You must be signed in to change notification settings - Fork 266
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
refactor: Update function selector computation #2001
Changes from all commits
c8e7913
3af400a
e6eeb2b
0a4b2fd
92c0b18
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
import { ABIType, FunctionAbi } from '@aztec/foundation/abi'; | ||
import { ABIParameter, ABIType, FunctionAbi } from '@aztec/foundation/abi'; | ||
import { Fr } from '@aztec/foundation/fields'; | ||
|
||
/** | ||
|
@@ -86,3 +86,53 @@ class ReturnValuesDecoder { | |
export function decodeReturnValues(abi: FunctionAbi, returnValues: Fr[]) { | ||
return new ReturnValuesDecoder(abi, returnValues.slice()).decode(); | ||
} | ||
|
||
/** | ||
* Decodes the signature of a function from the name and parameters. | ||
*/ | ||
export class FunctionSignatureDecoder { | ||
constructor(private name: string, private parameters: ABIParameter[]) {} | ||
Comment on lines
+93
to
+94
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 know this is a matter of personal preference, but I prefer to export plain functions rather than classes with a "do" method. A user of this API just wants to 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. Added |
||
|
||
/** | ||
* Decodes a single function parameter for the function signature. | ||
* @param param - The parameter to decode. | ||
* @returns A string representing the parameter type. | ||
*/ | ||
private decodeParameter(param: ABIType): string { | ||
switch (param.kind) { | ||
case 'field': | ||
return 'Field'; | ||
case 'integer': | ||
if (param.sign === 'signed') { | ||
throw new Error('Unsupported type: signed integer'); | ||
} | ||
return `u${param.width}`; | ||
case 'boolean': | ||
return 'bool'; | ||
case 'array': | ||
return `[${this.decodeParameter(param.type)};${param.length}]`; | ||
case 'struct': | ||
return `(${param.fields.map(field => `${this.decodeParameter(field.type)}`).join(',')})`; | ||
default: | ||
throw new Error(`Unsupported type: ${param.kind}`); | ||
} | ||
} | ||
|
||
/** | ||
* Decodes all the parameters and build the function signature | ||
* @returns The function signature. | ||
*/ | ||
public decode(): string { | ||
return `${this.name}(${this.parameters.map(param => this.decodeParameter(param.type)).join(',')})`; | ||
} | ||
} | ||
|
||
/** | ||
* Decodes a function signature from the name and parameters. | ||
* @param name - The name of the function- | ||
* @param parameters - The parameters of the function. | ||
* @returns - The function signature. | ||
*/ | ||
export function decodeFunctionSignature(name: string, parameters: ABIParameter[]) { | ||
return new FunctionSignatureDecoder(name, parameters).decode(); | ||
} |
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.
despite the convinience, computing the selector is something that should be done at compile time, and not at runtime. A malicious app could alter the source code / calls being made without changing the verification key.
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 sandbox a malicious actor can do whatever they want. Calling other functions are also done through oracles where it could just return success independent of what happens. This is essentially just a helper to compute an input to another function that is completely controlled by a possibly malicious app so not sure it changes much 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.
I may be missing something, but I agree with @Maddiaa0 on this one. Calling other functions as you say can also return anything, but we then have a kernel circuit that ensures that the oracle behaved properly. But it's true it doesn't affect the security of sandbox as it is today.
I'm fine merging this, but we should add an issue to replace it with a Noir-only implementation in the future (ie before testnet).
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 suppose if the sought-after pattern is to have the selector be a parameter to the function, then an oracle is ok. It would be akin to this Solidity pseudocode (because I've forgotten how to write solidity):
But if a user actually wants to always call a specific selector, then an oracle call is dangerous, because it isn't constrained:
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.
Allowing users to take over control flow is almost always a death-sin in solidity. I agree with both @spalladino and @Maddiaa0 that having an oracle is horrible, but since you can take over whenever through some of the other execution it seemed like a solution that was usable for this problem. #1550 should get rid of it, it is just used temporarily because it is too shit to compute selectors by hand when you want self-calls etc.