From 7589351369d455316b7d3d24fbfe40f02667d187 Mon Sep 17 00:00:00 2001 From: Dariusz Depta <141360751+DariuszDepta@users.noreply.github.com> Date: Fri, 3 Oct 2025 18:32:03 +0200 Subject: [PATCH 1/4] Added initial content. --- README.md | 2 +- Taskfile.yml | 2 +- docs/core/standard-library/_category_.json | 8 ++ .../cryptography/_category_.json | 8 ++ .../cryptography/cryptography.md | 75 +++++++++++++++++++ .../standard-library/math/_category_.json | 8 ++ docs/core/standard-library/math/decimals.md | 37 +++++++++ docs/core/standard-library/math/integers.md | 34 +++++++++ docs/core/standard-library/math/math.md | 42 +++++++++++ .../core/standard-library/standard-library.md | 8 ++ 10 files changed, 222 insertions(+), 2 deletions(-) create mode 100644 docs/core/standard-library/_category_.json create mode 100644 docs/core/standard-library/cryptography/_category_.json create mode 100644 docs/core/standard-library/cryptography/cryptography.md create mode 100644 docs/core/standard-library/math/_category_.json create mode 100644 docs/core/standard-library/math/decimals.md create mode 100644 docs/core/standard-library/math/integers.md create mode 100644 docs/core/standard-library/math/math.md create mode 100644 docs/core/standard-library/standard-library.md diff --git a/README.md b/README.md index 5f82e0c..f217d3f 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ You can just clone this repository and run the following commands: ```shell $ npm install -$ task serve +$ npm run start ``` You will now be able to visit the locally served website at http://localhost:3000/ diff --git a/Taskfile.yml b/Taskfile.yml index 89e4096..d09b620 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -10,7 +10,7 @@ tasks: - cmd: rm -rf .docusaurus - cmd: rm -rf build - serve: + start: desc: Start server locally cmds: - task: clean diff --git a/docs/core/standard-library/_category_.json b/docs/core/standard-library/_category_.json new file mode 100644 index 0000000..feae5c6 --- /dev/null +++ b/docs/core/standard-library/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "Standard library", + "position": 4, + "link": { + "type": "doc", + "id": "standard-library" + } +} diff --git a/docs/core/standard-library/cryptography/_category_.json b/docs/core/standard-library/cryptography/_category_.json new file mode 100644 index 0000000..0e3806b --- /dev/null +++ b/docs/core/standard-library/cryptography/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "Cryptography", + "position": 2, + "link": { + "type": "doc", + "id": "cryptography" + } +} diff --git a/docs/core/standard-library/cryptography/cryptography.md b/docs/core/standard-library/cryptography/cryptography.md new file mode 100644 index 0000000..f00c763 --- /dev/null +++ b/docs/core/standard-library/cryptography/cryptography.md @@ -0,0 +1,75 @@ +# Cryptography + +CosmWasm offers cryptographic primitives that are implemented as VM intrinsics. This means that they +are more efficient than implementations in contract code could be, saving you gas and code size. In +some cases they are also _impossible_ to implement in contract code, since some of them require a +random intermediate value and randomness is generally not exposed to contracts to ensure +deterministic execution. + +In the sidebar, you can find all the supported algorithms/curves along with documentation about +them. + +## Gas costs + +:::tip + +Note that these values are in CosmWasm Gas (which is not equivalent to Cosmos SDK Gas; rather, +CosmWasm Gas is eventually converted to Cosmos SDK Gas). For more info on gas [check this page]. + +::: + +### secp256k1 + +- Verify: 96_000_000 gas +- Recover public key: 194_000_000 gas + +### secp256r1 + +- Verify: 279_000_000 gas +- Recover public key: 592_000_000 gas + +### ed25519 + +- Verify: 35_000_000 gas +- Batch verify (multiple signatures; multiple keys): + - Base: 24_000_000 gas + - Per signature/key pair: 21_000_000 gas +- Batch verify (multiple signatures; one key): + - Base: 36_000_000 gas + - Per signature: 10_000_000 gas + +### BLS12-381 + +- Aggregate points to G1: + - Base: 68_000_000 gas + - Per point: 12_000_000 gas +- Aggregate points to G2: + - Base: 103_500_000 gas + - Per point: 24_500_000 gas +- Hash to G1: 563_000_000 gas +- Hash to G2: 871_000_000 gas +- Pairing equality: + - Base: 2_112_000_000 gas + - Per item: 163_000_000 gas + +You can also check these numbers in the [source code]. + +## Note on hash functions + +You'll notice that CosmWasm does not implement any hash functions as native functions, and we intend +to keep it that way. The reasoning for that is: + +- Hash functions are pretty much always cheap in terms of execution cost _and_ code size +- There are way too many hash functions out there, adding one would open the floodgates where we + would have to add more + - SHA-3 family, Keccak256, cSHAKE256, BLAKE2, BLAKE3, SHA-2 family, KangarooTwelve, etc. (and this + is just a small sample set to drive the point home) +- Benchmarking and pricing functions (and keeping those up-to-date) correctly is a lot of work +- We want to keep the API surface as small as possible for ease of maintenance + +Keep in mind that, thanks to Wasm being our execution environment, contract execution is quite fast. +In most cases the perceived need to move hashing into a host function is premature optimization and +not actually needed. + +[check this page]: ../../architecture/gas +[source code]: https://github.com/CosmWasm/cosmwasm/blob/main/packages/vm/src/environment.rs#L62-L101 diff --git a/docs/core/standard-library/math/_category_.json b/docs/core/standard-library/math/_category_.json new file mode 100644 index 0000000..d43753d --- /dev/null +++ b/docs/core/standard-library/math/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "Math", + "position": 1, + "link": { + "type": "doc", + "id": "math" + } +} diff --git a/docs/core/standard-library/math/decimals.md b/docs/core/standard-library/math/decimals.md new file mode 100644 index 0000000..6fdb83c --- /dev/null +++ b/docs/core/standard-library/math/decimals.md @@ -0,0 +1,37 @@ +--- +sidebar_position: 1 +--- + +# Decimals + +CosmWasm offers decimal types for handling fractional numbers. + +In contrast to floating point numbers, these datatypes do not suffer from the same precision issues. +This means that these decimal types are safe for use in financial calculations. + +Instead of storing numbers in the floating point format, which gives it a _floating_ amount of +decimal places, these decimal types have a fixed precision of 18 decimal places. + +:::tip + +Note that, due to how the decimal types are structured, the value ranges can seem a little weird. + +For example, 128-bit unsigned decimal value $1.0$ is represented by `Decimal(1_000_000_000_000_000_000)`. + +The maximal value of the 128-bit unsigned decimal is: +$$ +{2^{128} - 1 \over 10^{18}} = 340282366920938463463.374607431768211455 +$$ + +In practice, you don't really have to think about it, but it's something you should be aware of. + +::: + +Decimal types come in the following variants: + +| Length | Unsigned | Signed | +|---------|------------|------------------| +| 128-bit | Decimal | SignedDecimal | +| 256-bit | Decimal256 | SignedDecimal256 | + +Choose one of the types according to your needs and off you go! diff --git a/docs/core/standard-library/math/integers.md b/docs/core/standard-library/math/integers.md new file mode 100644 index 0000000..054883a --- /dev/null +++ b/docs/core/standard-library/math/integers.md @@ -0,0 +1,34 @@ +--- +sidebar_position: 2 +--- + +# Integers + +CosmWasm offers integer types starting at 64 bit precision, all the way up to 512 bits. + +Reasoning behind wrapping the primitive 64 bit type is the interaction with, for example, JavaScript +(same goes for parsers like `jq` or any parser that parses numbers into double precision floats). A +`u64` would normally serialize into a regular integer field in JSON. The issue here is that, due to +representing integers in form of double precision floats, JavaScript can only handle up to ~53 bit +numbers without potentially losing information. + +:::tip + +There is nothing wrong with using the primitive 64- and 128-bit types in your contract for +calculations. The issues mentioned here can only happen when you de-/serialize these values. + +::: + +Our wrapper fixes this by serializing numbers as strings, letting JavaScript clients deserialize +these numbers into their respective BigInteger types. + +The other integer types, which reach even higher amounts of precision, are serialized in the same way. + +Integers come in the following variants: + +| Length | Unsigned | Signed | +|---------|----------|--------| +| 64-bit | Uint64 | Int64 | +| 128-bit | Uint128 | Int128 | +| 256-bit | Uint256 | Int256 | +| 512-bit | Uint512 | Int512 | diff --git a/docs/core/standard-library/math/math.md b/docs/core/standard-library/math/math.md new file mode 100644 index 0000000..0ab021c --- /dev/null +++ b/docs/core/standard-library/math/math.md @@ -0,0 +1,42 @@ +# Math + +CosmWasm offers mathematical primitives for, you guessed it, mathematical operations. In contrast to +the Rust standard library, which is limited to 128-bit integers, we offer [integers] that exceed +that precision. [decimals] for fixed point math are also available. + +## Conversions + +The following overview shows how to convert between integers and decimals of different size. This +only shows the unsigned case but the signed types work the same way. + +```mermaid +graph TD + Decimal ---> |From| Decimal256 + Decimal256 ---> |TryFrom| Decimal + Uint128 ---> |"::from_atomics(n,0)"| Decimal + Decimal ---> |::to_uint_floor| Uint128 + Decimal ---> |::to_uint_ceil| Uint128 + Uint256 ---> |"::from_atomics(n,0)"| Decimal256 + Decimal256 ---> |::to_uint_floor| Uint256 + Decimal256 ---> |::to_uint_ceil| Uint256 +``` + +| | Decimal | Decimal256 | Uint64 | Uint128 | Uint256 | Uint512 | u64 | u128 | +|---------------:|:----------------------------------:|:----------------------------------:|:------:|:-------------------:|:-------------------:|:-------:|:---:|:----:| +| **Decimal** | = | TryFrom | | ::from_atomics(n,0) | | | | | +| **Decimal256** | From | = | | | ::from_atomics(n,0) | | | | +| **Uint64** | | | = | | | | | | +| **Uint128** | ::to_uint_floor
::to_uint_ceil | | | = | | | | | +| **Uint256** | | ::to_uint_floor
::to_uint_ceil | | | = | | | | +| **Uint512** | | | | | | = | | | +| **u64** | | | | | | | = | | +| **u128** | | | | | | | | = | + + +`From`/`TryFrom` refer to the +[Rust trait implementations](https://doc.rust-lang.org/rust-by-example/conversion/from_into.html). +`::to_*` are functions on the source type and `::new`/`::from_*` are functions on the destination +type. + +[integers]: ./math/integers +[decimals]: ./math/decimals diff --git a/docs/core/standard-library/standard-library.md b/docs/core/standard-library/standard-library.md new file mode 100644 index 0000000..756e4b1 --- /dev/null +++ b/docs/core/standard-library/standard-library.md @@ -0,0 +1,8 @@ +# Standard library + +CosmWasm offers a standard library providing a bunch of different components to write smart contracts. +In this section we will go over some components and functionality the standard library offers. + +A full list of all components along with documentation can be found on [docs.rs]. + +[docs.rs]: https://docs.rs/cosmwasm-std From 3b4ac405cc55d9a1ae441486951cc93e28a7da36 Mon Sep 17 00:00:00 2001 From: Dariusz Depta <141360751+DariuszDepta@users.noreply.github.com> Date: Fri, 3 Oct 2025 18:51:47 +0200 Subject: [PATCH 2/4] Updates. --- docs/core/standard-library/math/math.md | 45 ++++++++++++++++++++----- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/docs/core/standard-library/math/math.md b/docs/core/standard-library/math/math.md index 0ab021c..2d02f95 100644 --- a/docs/core/standard-library/math/math.md +++ b/docs/core/standard-library/math/math.md @@ -10,17 +10,44 @@ The following overview shows how to convert between integers and decimals of dif only shows the unsigned case but the signed types work the same way. ```mermaid -graph TD - Decimal ---> |From| Decimal256 - Decimal256 ---> |TryFrom| Decimal - Uint128 ---> |"::from_atomics(n,0)"| Decimal - Decimal ---> |::to_uint_floor| Uint128 - Decimal ---> |::to_uint_ceil| Uint128 - Uint256 ---> |"::from_atomics(n,0)"| Decimal256 - Decimal256 ---> |::to_uint_floor| Uint256 - Decimal256 ---> |::to_uint_ceil| Uint256 +graph LR + Decimal <---> Decimal256 + Uint64 <---> Uint128 + Uint64 <---> u64 + Uint128 <---> u128 + Uint128 <---> Decimal + Uint128 <---> Uint256 + Uint256 <---> Decimal256 + Uint512 <---> Uint256 + + subgraph "Rust integer types" + u64 + u128 + end + + subgraph "Integer types" + Uint64 + Uint128 + Uint256 + Uint512 + end + + subgraph "Decimal types" + Decimal + Decimal256 + end ``` +| Destination type | Source type: Decimal | +|-----------------:|:-----------------------------------| +| Decimal256 | From | +| Uint64 | | +| Uint128 | ::to_uint_floor
::to_uint_ceil | +| Uint256 | | +| Uint512 | | +| u64 | | +| u128 | | + | | Decimal | Decimal256 | Uint64 | Uint128 | Uint256 | Uint512 | u64 | u128 | |---------------:|:----------------------------------:|:----------------------------------:|:------:|:-------------------:|:-------------------:|:-------:|:---:|:----:| | **Decimal** | = | TryFrom | | ::from_atomics(n,0) | | | | | From a996160c0eebb8815293731188e13711f0ba0822 Mon Sep 17 00:00:00 2001 From: Dariusz Depta <141360751+DariuszDepta@users.noreply.github.com> Date: Mon, 6 Oct 2025 12:46:49 +0200 Subject: [PATCH 3/4] Fixed Math chapter. --- .../math/img/integer-decimal-conversions.png | Bin 0 -> 53254 bytes docs/core/standard-library/math/math.md | 55 +----------------- 2 files changed, 3 insertions(+), 52 deletions(-) create mode 100644 docs/core/standard-library/math/img/integer-decimal-conversions.png diff --git a/docs/core/standard-library/math/img/integer-decimal-conversions.png b/docs/core/standard-library/math/img/integer-decimal-conversions.png new file mode 100644 index 0000000000000000000000000000000000000000..9477eb623c10e091ac0377f78ef7248b1554dd7b GIT binary patch literal 53254 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 =t@!EWyp&r=aB%XxJ)-PD8X>^g}> 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 BjBNk_ literal 0 HcmV?d00001 diff --git a/docs/core/standard-library/math/math.md b/docs/core/standard-library/math/math.md index 2d02f95..1c5d525 100644 --- a/docs/core/standard-library/math/math.md +++ b/docs/core/standard-library/math/math.md @@ -9,61 +9,12 @@ that precision. [decimals] for fixed point math are also available. The following overview shows how to convert between integers and decimals of different size. This only shows the unsigned case but the signed types work the same way. -```mermaid -graph LR - Decimal <---> Decimal256 - Uint64 <---> Uint128 - Uint64 <---> u64 - Uint128 <---> u128 - Uint128 <---> Decimal - Uint128 <---> Uint256 - Uint256 <---> Decimal256 - Uint512 <---> Uint256 - - subgraph "Rust integer types" - u64 - u128 - end - - subgraph "Integer types" - Uint64 - Uint128 - Uint256 - Uint512 - end - - subgraph "Decimal types" - Decimal - Decimal256 - end -``` - -| Destination type | Source type: Decimal | -|-----------------:|:-----------------------------------| -| Decimal256 | From | -| Uint64 | | -| Uint128 | ::to_uint_floor
::to_uint_ceil | -| Uint256 | | -| Uint512 | | -| u64 | | -| u128 | | - -| | Decimal | Decimal256 | Uint64 | Uint128 | Uint256 | Uint512 | u64 | u128 | -|---------------:|:----------------------------------:|:----------------------------------:|:------:|:-------------------:|:-------------------:|:-------:|:---:|:----:| -| **Decimal** | = | TryFrom | | ::from_atomics(n,0) | | | | | -| **Decimal256** | From | = | | | ::from_atomics(n,0) | | | | -| **Uint64** | | | = | | | | | | -| **Uint128** | ::to_uint_floor
::to_uint_ceil | | | = | | | | | -| **Uint256** | | ::to_uint_floor
::to_uint_ceil | | | = | | | | -| **Uint512** | | | | | | = | | | -| **u64** | | | | | | | = | | -| **u128** | | | | | | | | = | - +![Integer decimal conversions overview](./img/integer-decimal-conversions.png) `From`/`TryFrom` refer to the [Rust trait implementations](https://doc.rust-lang.org/rust-by-example/conversion/from_into.html). `::to_*` are functions on the source type and `::new`/`::from_*` are functions on the destination type. -[integers]: ./math/integers -[decimals]: ./math/decimals +[integers]: ./integers +[decimals]: ./decimals From 67461047083f716e7a513103ac9d8be029b86393 Mon Sep 17 00:00:00 2001 From: Dariusz Depta <141360751+DariuszDepta@users.noreply.github.com> Date: Mon, 6 Oct 2025 12:54:26 +0200 Subject: [PATCH 4/4] Added cryptogrphy functions descriptions. --- .../cryptography/bls12-381.md | 65 +++++++++++++++++++ .../standard-library/cryptography/ed25519.md | 39 +++++++++++ .../standard-library/cryptography/k256.md | 60 +++++++++++++++++ .../standard-library/cryptography/p256.md | 57 ++++++++++++++++ 4 files changed, 221 insertions(+) create mode 100644 docs/core/standard-library/cryptography/bls12-381.md create mode 100644 docs/core/standard-library/cryptography/ed25519.md create mode 100644 docs/core/standard-library/cryptography/k256.md create mode 100644 docs/core/standard-library/cryptography/p256.md diff --git a/docs/core/standard-library/cryptography/bls12-381.md b/docs/core/standard-library/cryptography/bls12-381.md new file mode 100644 index 0000000..d71047f --- /dev/null +++ b/docs/core/standard-library/cryptography/bls12-381.md @@ -0,0 +1,65 @@ +--- +sidebar_position: 4 +--- + +# BLS12-381 + +BLS12-381 is a bit of a special curve. It is a pairing-friendly curve, allowing for fun things such +as aggregated signatures. At the moment, CosmWasm only supports signature verifications. In the +future we might add support for zero-knowledge proofs on this curve. + +Common examples where this curve is used are Ethereum block-headers and [drand] randomness beacons. + +## Example + +CosmWasm offers a byte-oriented API for signature verification. This API also doesn't care whether +the public key is part of the G1 or G2 group (same for the other components). They just have to +somehow fit together. + +## Verify on G1 + +Signature verification with public key in G1: + +```rust title="contract.rs" +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn query( + deps: Deps, + _env: Env, + msg: Bls12VerifyMsg, +) -> StdResult { + // Verify the signature. On chain! + let msg_hash = deps.api.bls12_381_hash_to_g2(HashFunction::Sha256, &msg.msg, &msg.dst)?; + let is_valid = deps.api.bls12_381_pairing_equality(&BLS12_381_G1_GENERATOR, &msg.signature, &msg.pubkey, &msg_hash)?; + let response = to_json_binary(&VerifyResponse { + is_valid + })?; + + Ok(response) +} +``` + +## Verify on G2 + +Signature verification with public key in G2 (See +https://hackmd.io/@benjaminion/bls12-381#Verification in combination with +https://hackmd.io/@benjaminion/bls12-381#Swapping-G1-and-G2): + +```rust title="contract.rs" +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn query( + deps: Deps, + _env: Env, + msg: Bls12VerifyMsg, +) -> StdResult { + // Verify the signature. On chain! + let msg_hash = deps.api.bls12_381_hash_to_g1(HashFunction::Sha256, &msg.msg, &msg.dst)?; + let is_valid = deps.api.bls12_381_pairing_equality(&msg.signature, &BLS12_381_G2_GENERATOR, &msg_hash, &msg.pubkey)?; + let response = to_json_binary(&VerifyResponse { + is_valid + })?; + + Ok(response) +} +``` + +[drand]: https://drand.love diff --git a/docs/core/standard-library/cryptography/ed25519.md b/docs/core/standard-library/cryptography/ed25519.md new file mode 100644 index 0000000..442f2bb --- /dev/null +++ b/docs/core/standard-library/cryptography/ed25519.md @@ -0,0 +1,39 @@ +--- +sidebar_position: 1 +--- + +# Ed25519 + +CosmWasm offers an API to verify and batch verify Ed25519 signatures. This is powerful, especially +since batch verifications require a random component which is impossible to implement in contract +code. + +Ed25519 is known to [have issues with inconsistent validation criteria], the API we offer follows +[ZIP215]. This means you will have no issues with signatures being valid in one place and invalid in +another. + +## Example + +```rust title="contract.rs" +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn query( + deps: Deps, + _env: Env, + msg: Ed25519VerifyMsg, +) -> StdResult { + let public_key = msg.public_key; + let signature = msg.signature; + let message = msg.message; + + // Verify the signature. On chain! + let is_valid = deps.api.ed25519_verify(&message, &signature, &public_key)?; + let response = to_json_binary(&VerifyResponse { + is_valid + })?; + + Ok(response) +} +``` + +[have issues with inconsistent validation criteria]: https://hdevalence.ca/blog/2020-10-04-its-25519am +[ZIP215]: https://zips.z.cash/zip-0215 diff --git a/docs/core/standard-library/cryptography/k256.md b/docs/core/standard-library/cryptography/k256.md new file mode 100644 index 0000000..9963da2 --- /dev/null +++ b/docs/core/standard-library/cryptography/k256.md @@ -0,0 +1,60 @@ +--- +title: K-256 +sidebar_position: 3 +--- + +# K256 (secp256k1) + +K256 is a Koblitz curve that is widely used in the blockchain space (e.g. Bitcoin and Ethereum). +CosmWasm offers the following APIs: + +- Signature verification +- Public key recovery + +## Example + +### Signature verification + +```rust title="contract.rs" +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn query( + deps: Deps, + _env: Env, + msg: EcdsaVerifyMsg, +) -> StdResult { + let public_key = msg.public_key; + let signature = msg.signature; + let message_hash = msg.message_hash; + + // Verify the signature. On chain! + let is_valid = deps.api.secp256k1_verify(&message_hash, &signature, &public_key)?; + let response = to_json_binary(&VerifyResponse { + is_valid + })?; + + Ok(response) +} +``` + +### Public key recovery + +```rust title="contract.rs" +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn query( + deps: Deps, + _env: Env, + msg: EcdsaRecoverMsg, +) -> StdResult { + let signature = msg.signature; + let message_hash = msg.message_hash; + let recovery_id = msg.recovery_id; + + // Recover the public key. On chain! + let public_key = deps.api.secp256k1_recover_pubkey(&message_hash, &signature, recovery_id)?; + let response = to_json_binary(&RecoveryResponse { + public_key: public_key.into(), + })?; + + Ok(response) +} +``` diff --git a/docs/core/standard-library/cryptography/p256.md b/docs/core/standard-library/cryptography/p256.md new file mode 100644 index 0000000..b90d272 --- /dev/null +++ b/docs/core/standard-library/cryptography/p256.md @@ -0,0 +1,57 @@ +--- +title: P-256 +sidebar_position: 2 +--- + +# P256 (secp256r1) + +P256 is one of NIST's prime-order elliptic curves. You may need this curve to implement protocols +such as WebAuthn. This is the main reason this curve was added to CosmWasm. + +## Example + +### Signature verification + +```rust title="contract.rs" +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn query( + deps: Deps, + _env: Env, + msg: EcdsaVerifyMsg, +) -> StdResult { + let public_key = msg.public_key; + let signature = msg.signature; + let message_hash = msg.message_hash; + + // Verify the signature. On chain! + let is_valid = deps.api.secp256r1_verify(&message_hash, &signature, &public_key)?; + let response = to_json_binary(&VerifyResponse { + is_valid + })?; + + Ok(response) +} +``` + +### Public key recovery + +```rust title="contract.rs" +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn query( + deps: Deps, + _env: Env, + msg: EcdsaRecoverMsg, +) -> StdResult { + let signature = msg.signature; + let message_hash = msg.message_hash; + let recovery_id = msg.recovery_id; + + // Recover the public key. On chain! + let public_key = deps.api.secp256r1_recover_pubkey(&message_hash, &signature, recovery_id)?; + let response = to_json_binary(&RecoveryResponse { + public_key: public_key.into(), + })?; + + Ok(response) +} +```