-
Notifications
You must be signed in to change notification settings - Fork 57
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
Enable collection of secp256k1_verify and secp256r1_verify operators #501
base: main
Are you sure you want to change the base?
Conversation
ba4d756
to
cfc1b03
Compare
Pull Request Test Coverage Report for Build 12057164038Details
💛 - Coveralls |
src/run_program.rs
Outdated
#[cfg(feature = "pre-eval")] | ||
pre_eval: Option<PreEval>, | ||
#[cfg(feature = "pre-eval")] | ||
posteval_stack: Vec<Box<PostEval>>, | ||
collected_ops: Option<Vec<CollectedOp>>, |
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 have reservations about making more complex this code which is already a bit too complex and nasty. You might be able to implement this functionality with pre_eval
, and you can surely do it by creating a new separate "wallet/debugging" dialect where you can override the opcodes you need.
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.
Good point, a new dialect might be cleaner
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.
The only issue is the apply op function takes an immutable reference. Maybe we should maybe dialects mutable? Alternatively it could use a RefCell or Mutex I suppose, but that seems unideal
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've done a similar thing with the python api without mutable dialects here, but I guess pyo3
is essentially RefCell
-like objects everywhere. Might be worth trying it both ways: mutable dialects and with a RefCell
to see what is easiest. RefCell
is usually kind of a bad smell because if you make a mistake, you get a runtime error instead of a compile error. But I think in this case, it should be pretty easy to avoid a runtime error so RefCell
might be the least intrusive without being too gross.
This is a great observation and there are some great ideas 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.
I would prefer a solution (which I believe Richard suggested) where you make a new Dialect
class that collects all the public keys and messages, and forwards everything to the default ChiaDialect
.
I think that would make this feature the most contained.
Could even make it wrap a generic inner dialect. I'll give this a shot |
This new implementation uses a custom Dialect and RefCell, since it requires no changes to the existing code. This raises the question of whether this should be part of the core CLVM crate or if it should just be part of the wallet code (or chia-wallet-sdk)? As is, it can be done already externally without any changes. If we make |
src/run_program.rs
Outdated
@@ -1580,4 +1581,35 @@ mod tests { | |||
|
|||
assert_eq!(result.unwrap().0, cost); | |||
} | |||
|
|||
#[test] |
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.
Is it possible to move this to collect_dialect.rs
? It'd be nice to have no changes to run_program.rs
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.
Yeah I'll move it
src/secp_ops.rs
Outdated
@@ -7,8 +7,8 @@ use k256::ecdsa::{Signature as K1Signature, VerifyingKey as K1VerifyingKey}; | |||
use p256::ecdsa::signature::hazmat::PrehashVerifier; | |||
use p256::ecdsa::{Signature as P1Signature, VerifyingKey as P1VerifyingKey}; | |||
|
|||
const SECP256R1_VERIFY_COST: Cost = 1850000; | |||
const SECP256K1_VERIFY_COST: Cost = 1300000; | |||
pub const SECP256R1_VERIFY_COST: Cost = 1850000; |
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.
Prob don't need this change anymore.
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.
Actually, I guess you 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 wonder if all of the costs should be defined in one place, like src/costs.rs
and exported publicly, for consistency?
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.
To avoid changing the public API on accident, I changed it to pub(crate)
for now.
let response = self.dialect.op(allocator, op, args, max_cost, extensions); | ||
|
||
let op_len = allocator.atom_len(op); | ||
if op_len != 4 { |
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 nice trick to restrict to these new opcode, but it deserves a comment at least since it may cause surprising things to happen if we add additional length four operators in future.
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.
Yeah and frankly I should probably capture BLS opcodes too.
This can be implemented externally to clvm_rs so barring a more general solution I'm going to leave this for now. |
With BLS signatures, you can simply run a puzzle with its solution to figure out all of the public key and message pairs that need to be signed, since they're included in the list of output conditions.
However, the secp256k1 and secp256r1 opcodes will fail at runtime if the signature passed into the solution doesn't match, instead of returning the expected values in conditions.
This PR enables a similar workflow by adding a new
run_program_with_signatures
function that skips and collects these operators and returns them in a list. Instead of failing the program, they will be treated as if they were successful in validating the signature, to allow the rest of the program to proceed. You can iterate the list of collected ops to find the public keys, messages, and signatures needed for signing.The only problem with this is you need a way to update the original solution afterward to use the new signatures (and then you could run it for real to see if it actually worked). This is the responsibility of the code consuming this API, and can potentially be done in two ways:
I believe this PR will enable considerable simplification of wallet code, if my assumptions are correct.