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/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/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/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) +} +``` 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/img/integer-decimal-conversions.png b/docs/core/standard-library/math/img/integer-decimal-conversions.png new file mode 100644 index 0000000..9477eb6 Binary files /dev/null and b/docs/core/standard-library/math/img/integer-decimal-conversions.png differ 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..1c5d525 --- /dev/null +++ b/docs/core/standard-library/math/math.md @@ -0,0 +1,20 @@ +# 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. + +![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]: ./integers +[decimals]: ./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