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

Enable libraries to define event handlers #1647

Open
wants to merge 25 commits into
base: next
Choose a base branch
from

Conversation

plafer
Copy link
Contributor

@plafer plafer commented Jan 30, 2025

Closes #1584

Also moves the Falcon signature event handling to the standard library.

This is a rough implementation as discussed in #1584, which still requires some cleanup

Copy link
Contributor

@bobbinth bobbinth left a comment

Choose a reason for hiding this comment

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

Looks good! Thank you! Not a review yet, but I left some comments inline.

@@ -7,6 +7,8 @@ const.J=77321994752
const.M=12289
const.SQUARE_NORM_BOUND=34034726

const.EVENT_FALCON_SIG_TO_STACK=3419226139
Copy link
Contributor

Choose a reason for hiding this comment

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

How did we choose this value?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It was chosen randomly, like the other system events. This basically makes collisions with user-defined events improbable.

@plafer plafer force-pushed the plafer-1584-event-handlers branch from 4c2a284 to 608bc41 Compare January 31, 2025 19:14
Copy link
Contributor

@bobbinth bobbinth left a comment

Choose a reason for hiding this comment

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

Left a few small comments after taking a quick look.

@plafer
Copy link
Contributor Author

plafer commented Feb 3, 2025

The biggest issue with libraries not having to depend on miden-processor is in moving the EventHandler trait, specifically because it uses ProcessState, which is inherently a processor type.

I explored creating an analogous ProcessState trait in core, but ultimately things get messy when we combine Box<dyn EventHandler>, the lifetime parameter of ProcessState, and the fact that traits used with dyn cannot have methods with a generic P: ProcessState parameter. My current conclusion is that the "cleanest" way to move it to core is to make ProcessState trait again, effectively undoing the work done in #1571. The biggest downside of this solution is that we then need to use a generic P: ProcessState everywhere like we had before, which IMO is much less clean that what we have today. And actually it's a bit worst than that, since EventHandler::on_event cannot be generic, so we need to make trait EventHandler<P> generic, and that generic parameter propagates to make a bunch of other traits/types generic over P as well.

So if my understanding is correct, we have to choose between the lesser of 2 evils:

  1. if libraries want to define event handlers, then they have to depend on miden-processor
  2. have ProcessState be a trait again, and all the messiness described above.

Unless I'm missing something, I feel like option (1) is cleaner, especially since not all libraries will need to define event handlers. This also means we can avoid moving all the advice provider types to core if we don't want to.

cc @bobbinth

@plafer plafer marked this pull request as ready for review February 3, 2025 21:41
@bobbinth
Copy link
Contributor

bobbinth commented Feb 4, 2025

So if my understanding is correct, we have to choose between the lesser of 2 evils:

  1. if libraries want to define event handlers, then they have to depend on miden-processor
  2. have ProcessState be a trait again, and all the messiness described above.

Yes, agreed that option 1 is the way to go (for this PR at least). And I actually don't think it is all that "evil". Yes, would have been nice to move this into the core, but since event handlers need to know about processor-specific things, makes sense that stdlib and other similar crates need to depend on the processor.

We could re-evaluate bringing back the ProcessState struct in the future - though, as you mention, this results in another host of issues (including the need for runtime borrow_mut()). Maybe there is a clean way to handle them, but definitely not worth investigating as a part of this PR.

@plafer
Copy link
Contributor Author

plafer commented Feb 4, 2025

Yes, would have been nice to move this into the core, but since event handlers need to know about processor-specific things, makes sense that stdlib and other similar crates need to depend on the processor.

Agreed.

We could re-evaluate bringing back the ProcessState struct in the future

Actually, since we allow stdlib to depend on miden-processor, then no change is needed to ProcessState - as it is right now on this branch.

And therefore the PR is ready for final review.

Copy link
Contributor

@bobbinth bobbinth left a comment

Choose a reason for hiding this comment

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

Looks good! Thank you! Didn't get to do a full review yet - but I left some comments inline.

@@ -32,6 +32,7 @@ processor = { package = "miden-processor", path = "../processor", version = "0.1
"testing",
] }
prover = { package = "miden-prover", path = "../prover", version = "0.13", default-features = false }
stdlib = { package = "miden-stdlib", path = "../stdlib", version = "0.13", default-features = false }
Copy link
Contributor

@bobbinth bobbinth Feb 4, 2025

Choose a reason for hiding this comment

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

Maybe not for this PR, but is there a way not to make test-utils dependent on stdlib? Maybe this could be done by adding something like host_libraries: Vec<dyn HostLibrary> field to the Test struct?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Unfortunately, not really, since HostLibrary is not trait object safe (due to get_event_handlers() being generic)

@@ -79,6 +79,6 @@ fn assert_eq_fail() {

#[test]
fn emit() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Question: why did we need to change this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I just changed the event that is emitted to be 1 instead of 42, since I installed a NoopEventHandler to event 1 by default in Test::execute(), but not 42

Comment on lines 13 to 14
use processor::{EventHandler, HostLibrary, ProcessState};
use vm_core::{AdviceProvider, AdviceProviderError, AdviceSource, Felt, Word};
Copy link
Contributor

Choose a reason for hiding this comment

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

AdviceProvider, AdviceProviderError, AdviceSource, Felt, Word should all be re-exported from the processor, right? I'd probably import them from there and then get rid of the vm_core dependency.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

Comment on lines 143 to 161
/// A trait for signing messages using the Falcon signature scheme.
///
/// This trait is used by [FalconSigToStackEventHandler] to sign messages using the Falcon signature
/// scheme.
///
/// It is recommended to use [dsa::falcon_sign] to implement this trait once the private key has
/// been fetched from a user-defined location.
pub trait FalconSigner<A>: Send + Sync {
/// Signs the message using the Falcon signature scheme, and returns the signature as a
/// `Vec<Felt>`.
fn sign_message(
&self,
pub_key: Word,
msg: Word,
advice_provider: &A,
) -> Result<Vec<Felt>, Box<dyn Error + Send + Sync + 'static>>
where
A: AdviceProvider;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

We are including the advice provider into the interface so that we could read the private key from it, right? I'm wondering if we could avoid this if we convert this trait into a closure - e.g., something like:

type FalconSigner = Box<dyn Fn(Word, Word) -> Vec<Felt>>;

And then in the FalconSigToStackEventHandler::on_event() we'd just invoke this closure capturing the private key we get from the advice provider.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

But this would force implementations to getting the private key from the advice provider, which is what we're trying to avoid (e.g. in miden-base we get it from somewhere else).

I also abstracted away the signing part to give the option to e.g. sign with a hardware device - and exposed dsa::falcon_sign() for convenience otherwise.

Copy link
Contributor

Choose a reason for hiding this comment

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

But this would force implementations to getting the private key from the advice provider,

No, the idea here is for the closure to take only 2 parameters: a public key and a message (the two words). The private key would be captured by the closure from the context. We are doing something similar in the client - though there, it is a bit more complex because the closures need to be async.

Comment on lines 37 to 40
pub use processor::{
crypto, math, utils, AdviceInputs, Digest, ExecutionError, Host, InputError, MemAdviceProvider,
StackInputs, StackOutputs, Word,
crypto, math, utils, Digest, ExecutionError, Host, InputError, MemAdviceProvider, StackInputs,
StackOutputs, Word,
};
Copy link
Contributor

Choose a reason for hiding this comment

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

I would still re-export AdviceInputs from here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

@plafer plafer requested a review from bobbinth February 5, 2025 12:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants