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

Make signature verification customizable in the host module #2955

Merged
merged 9 commits into from
Nov 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions bin/light-base/src/json_rpc_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1588,6 +1588,9 @@ impl<TPlat: Platform> Background<TPlat> {
read_only_runtime_host::RuntimeHostVm::StorageRoot(storage_root) => {
runtime_call = storage_root.resume(runtime_call_lock.block_storage_root());
}
read_only_runtime_host::RuntimeHostVm::SignatureVerification(sig) => {
runtime_call = sig.verify_and_resume();
}
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions bin/light-base/src/json_rpc_service/chain_head.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,9 @@ impl<TPlat: Platform> Background<TPlat> {
}
.to_json_call_object_parameters(None);
}
runtime_host::RuntimeHostVm::SignatureVerification(sig) => {
runtime_call = sig.verify_and_resume();
}
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions bin/light-base/src/sync_service/parachain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1162,6 +1162,9 @@ async fn parahead<TPlat: Platform>(
read_only_runtime_host::RuntimeHostVm::StorageRoot(storage_root) => {
runtime_call = storage_root.resume(runtime_call_lock.block_storage_root());
}
read_only_runtime_host::RuntimeHostVm::SignatureVerification(sig) => {
runtime_call = sig.verify_and_resume();
}
}
};

Expand Down
4 changes: 4 additions & 0 deletions bin/wasm-node/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

### Fixed

- Fix the `ext_crypto_ecdsa_verify_version_1` and `ext_crypto_ecdsa_verify_prehashed_version_1` host functions mixing their parameters and thus always failing. ([#2955](https://github.com/paritytech/smoldot/pull/2955))

## 0.7.5 - 2022-10-31

### Fixed
Expand Down
3 changes: 3 additions & 0 deletions src/chain/chain_information/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,9 @@ impl ChainInformationBuild {
call, inner,
)))
}
read_only_runtime_host::RuntimeHostVm::SignatureVerification(sig) => {
call = sig.verify_and_resume();
}
}
}
}
Expand Down
393 changes: 284 additions & 109 deletions src/executor/host.rs

Large diffs are not rendered by default.

94 changes: 94 additions & 0 deletions src/executor/read_only_runtime_host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ pub enum RuntimeHostVm {
NextKey(NextKey),
/// Fetching the storage trie root is required in order to continue.
StorageRoot(StorageRoot),
/// Verifying whether a signature is correct is required in order to continue.
SignatureVerification(SignatureVerification),
}

impl RuntimeHostVm {
Expand All @@ -130,6 +132,7 @@ impl RuntimeHostVm {
RuntimeHostVm::StorageGet(inner) => inner.inner.vm.into_prototype(),
RuntimeHostVm::NextKey(inner) => inner.inner.vm.into_prototype(),
RuntimeHostVm::StorageRoot(inner) => inner.inner.vm.into_prototype(),
RuntimeHostVm::SignatureVerification(inner) => inner.inner.vm.into_prototype(),
}
}
}
Expand Down Expand Up @@ -247,6 +250,90 @@ impl StorageRoot {
}
}

/// Verifying whether a signature is correct is required in order to continue.
#[must_use]
pub struct SignatureVerification {
inner: Inner,
}

impl SignatureVerification {
/// Returns the message that the signature is expected to sign.
pub fn message(&'_ self) -> impl AsRef<[u8]> + '_ {
match self.inner.vm {
host::HostVm::SignatureVerification(ref sig) => sig.message(),
_ => unreachable!(),
}
}

/// Returns the signature.
///
/// > **Note**: Be aware that this signature is untrusted input and might not be part of the
/// > set of valid signatures.
pub fn signature(&'_ self) -> impl AsRef<[u8]> + '_ {
match self.inner.vm {
host::HostVm::SignatureVerification(ref sig) => sig.signature(),
_ => unreachable!(),
}
}

/// Returns the public key the signature is against.
///
/// > **Note**: Be aware that this public key is untrusted input and might not be part of the
/// > set of valid public keys.
pub fn public_key(&'_ self) -> impl AsRef<[u8]> + '_ {
match self.inner.vm {
host::HostVm::SignatureVerification(ref sig) => sig.public_key(),
_ => unreachable!(),
}
}

/// Verify the signature. Returns `true` if it is valid.
pub fn is_valid(&self) -> bool {
match self.inner.vm {
host::HostVm::SignatureVerification(ref sig) => sig.is_valid(),
_ => unreachable!(),
}
}

/// Verify the signature and resume execution.
pub fn verify_and_resume(mut self) -> RuntimeHostVm {
match self.inner.vm {
host::HostVm::SignatureVerification(sig) => self.inner.vm = sig.verify_and_resume(),
_ => unreachable!(),
}

self.inner.run()
}

/// Resume the execution assuming that the signature is valid.
///
/// > **Note**: You are strongly encouraged to call
/// > [`SignatureVerification::verify_and_resume`]. This function is meant to be
/// > used only in debugging situations.
pub fn resume_success(mut self) -> RuntimeHostVm {
match self.inner.vm {
host::HostVm::SignatureVerification(sig) => self.inner.vm = sig.resume_success(),
_ => unreachable!(),
}

self.inner.run()
}

/// Resume the execution assuming that the signature is invalid.
///
/// > **Note**: You are strongly encouraged to call
/// > [`SignatureVerification::verify_and_resume`]. This function is meant to be
/// > used only in debugging situations.
pub fn resume_failed(mut self) -> RuntimeHostVm {
match self.inner.vm {
host::HostVm::SignatureVerification(sig) => self.inner.vm = sig.resume_failed(),
_ => unreachable!(),
}

self.inner.run()
}
}

/// Implementation detail of the execution. Shared by all the variants of [`RuntimeHostVm`]
/// other than [`RuntimeHostVm::Finished`].
struct Inner {
Expand Down Expand Up @@ -290,6 +377,13 @@ impl Inner {
return RuntimeHostVm::NextKey(NextKey { inner: self });
}

host::HostVm::SignatureVerification(req) => {
self.vm = req.into();
return RuntimeHostVm::SignatureVerification(SignatureVerification {
inner: self,
});
}

host::HostVm::CallRuntimeVersion(req) => {
// TODO: make the user execute this ; see https://github.com/paritytech/smoldot/issues/144
// The code below compiles the provided WebAssembly runtime code, which is a
Expand Down
94 changes: 94 additions & 0 deletions src/executor/runtime_host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,8 @@ pub enum RuntimeHostVm {
PrefixKeys(PrefixKeys),
/// Fetching the key that follows a given one is required in order to continue.
NextKey(NextKey),
/// Verifying whether a signature is correct is required in order to continue.
SignatureVerification(SignatureVerification),
}

impl RuntimeHostVm {
Expand All @@ -177,6 +179,7 @@ impl RuntimeHostVm {
RuntimeHostVm::StorageGet(inner) => inner.inner.vm.into_prototype(),
RuntimeHostVm::PrefixKeys(inner) => inner.inner.vm.into_prototype(),
RuntimeHostVm::NextKey(inner) => inner.inner.vm.into_prototype(),
RuntimeHostVm::SignatureVerification(inner) => inner.inner.vm.into_prototype(),
}
}
}
Expand Down Expand Up @@ -464,6 +467,90 @@ impl NextKey {
}
}

/// Verifying whether a signature is correct is required in order to continue.
#[must_use]
pub struct SignatureVerification {
inner: Inner,
}

impl SignatureVerification {
/// Returns the message that the signature is expected to sign.
pub fn message(&'_ self) -> impl AsRef<[u8]> + '_ {
match self.inner.vm {
host::HostVm::SignatureVerification(ref sig) => sig.message(),
_ => unreachable!(),
}
}

/// Returns the signature.
///
/// > **Note**: Be aware that this signature is untrusted input and might not be part of the
/// > set of valid signatures.
pub fn signature(&'_ self) -> impl AsRef<[u8]> + '_ {
match self.inner.vm {
host::HostVm::SignatureVerification(ref sig) => sig.signature(),
_ => unreachable!(),
}
}

/// Returns the public key the signature is against.
///
/// > **Note**: Be aware that this public key is untrusted input and might not be part of the
/// > set of valid public keys.
pub fn public_key(&'_ self) -> impl AsRef<[u8]> + '_ {
match self.inner.vm {
host::HostVm::SignatureVerification(ref sig) => sig.public_key(),
_ => unreachable!(),
}
}

/// Verify the signature. Returns `true` if it is valid.
pub fn is_valid(&self) -> bool {
match self.inner.vm {
host::HostVm::SignatureVerification(ref sig) => sig.is_valid(),
_ => unreachable!(),
}
}

/// Verify the signature and resume execution.
pub fn verify_and_resume(mut self) -> RuntimeHostVm {
match self.inner.vm {
host::HostVm::SignatureVerification(sig) => self.inner.vm = sig.verify_and_resume(),
_ => unreachable!(),
}

self.inner.run()
}

/// Resume the execution assuming that the signature is valid.
///
/// > **Note**: You are strongly encouraged to call
/// > [`SignatureVerification::verify_and_resume`]. This function is meant to be
/// > used only in debugging situations.
pub fn resume_success(mut self) -> RuntimeHostVm {
match self.inner.vm {
host::HostVm::SignatureVerification(sig) => self.inner.vm = sig.resume_success(),
_ => unreachable!(),
}

self.inner.run()
}

/// Resume the execution assuming that the signature is invalid.
///
/// > **Note**: You are strongly encouraged to call
/// > [`SignatureVerification::verify_and_resume`]. This function is meant to be
/// > used only in debugging situations.
pub fn resume_failed(mut self) -> RuntimeHostVm {
match self.inner.vm {
host::HostVm::SignatureVerification(sig) => self.inner.vm = sig.resume_failed(),
_ => unreachable!(),
}

self.inner.run()
}
}

/// Implementation detail of the execution. Shared by all the variants of [`RuntimeHostVm`]
/// other than [`RuntimeHostVm::Finished`].
struct Inner {
Expand Down Expand Up @@ -654,6 +741,13 @@ impl Inner {
self.vm = req.resume();
}

host::HostVm::SignatureVerification(req) => {
self.vm = req.into();
return RuntimeHostVm::SignatureVerification(SignatureVerification {
inner: self,
});
}

host::HostVm::CallRuntimeVersion(req) => {
// TODO: make the user execute this ; see https://github.com/paritytech/smoldot/issues/144
// The code below compiles the provided WebAssembly runtime code, which is a
Expand Down
Loading