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

Miden SDK proof-of-concept using Wasm component model #79

Merged
merged 15 commits into from
Jan 9, 2024
Merged
Show file tree
Hide file tree
Changes from 13 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
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 13 additions & 1 deletion Makefile.toml
Original file line number Diff line number Diff line change
Expand Up @@ -169,18 +169,30 @@ description = "Install wasm32-unknown-unknown target"
command = "rustup"
args = ["target", "add", "wasm32-unknown-unknown", "--toolchain", "${CARGO_MAKE_TOOLCHAIN}"]

[tasks.install-wasm-wasi-target]
category = "Test"
description = "Install wasm32-wasi target"
command = "rustup"
args = ["target", "add", "wasm32-wasi", "--toolchain", "${CARGO_MAKE_TOOLCHAIN}"]

[tasks.install-rust-src]
category = "Test"
description = "Install rust-src component"
command = "rustup"
args = ["component", "add", "rust-src", "--toolchain", "${CARGO_MAKE_TOOLCHAIN}"]

[tasks.install-cargo-component]
category = "Test"
description = "Install cargo-component extension"
command = "cargo"
args = ["install", "cargo-component"]

[tasks.test-rust]
category = "Test"
description = "Runs tests written in Rust"
command = "rustup"
args = ["run", "${CARGO_MAKE_TOOLCHAIN}", "cargo", "test", "@@remove-empty(CARGO_MAKE_CARGO_VERBOSE_FLAGS)", "@@split(CARGO_MAKE_CARGO_BUILD_TEST_FLAGS, )", "${@}"]
dependencies = ["install-wasm-target", "install-rust-src"]
dependencies = ["install-wasm-target", "install-wasm-wasi-target", "install-rust-src", "install-cargo-component"]

[tasks.test-filecheck]
category = "Test"
Expand Down
81 changes: 81 additions & 0 deletions sdk/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 26 additions & 0 deletions sdk/Cargo.toml
greenhat marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[package]
name = "miden-sdk"
version = "0.1.0"
rust-version = "1.71"
authors = ["Miden Team"]
description = "Miden SDK"
license = "MIT"
edition = "2021"
publish = false

# To keep it out of the root workspace since it cannot be built for a non-Wasm target
[workspace]

[dependencies]
cargo-component-bindings = "0.6.0"

[lib]
crate-type = ["cdylib"]

[package.metadata.component]
package = "component:miden"

[package.metadata.component.dependencies]

[profile.release]
panic = "abort"
3 changes: 3 additions & 0 deletions sdk/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#![no_std]

cargo_component_bindings::generate!();
132 changes: 132 additions & 0 deletions sdk/wit/miden.wit
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package miden:[email protected];

interface types {
/// Represents base field element in the field using Montgomery representation.
/// Internal values represent x * R mod M where R = 2^64 mod M and x in [0, M).
/// The backing type is `u64` but the internal values are always in the range [0, M).
/// Field modulus M = 2^64 - 2^32 + 1
type felt = u64;
/// A group of four field elements in the Miden base field.
type word = tuple<felt, felt, felt, felt>;

/// Unique identifier of an account.
///
/// Account ID consists of 1 field element (~64 bits). This field element uniquely identifies a
/// single account and also specifies the type of the underlying account. Specifically:
/// - The two most significant bits of the ID specify the type of the account:
/// - 00 - regular account with updatable code.
/// - 01 - regular account with immutable code.
/// - 10 - fungible asset faucet with immutable code.
/// - 11 - non-fungible asset faucet with immutable code.
/// - The third most significant bit of the ID specifies whether the account data is stored on-chain:
/// - 0 - full account data is stored on-chain.
/// - 1 - only the account hash is stored on-chain which serves as a commitment to the account state.
/// As such the three most significant bits fully describes the type of the account.
type account-id = felt;

/// Recipient of the note, i.e., hash(hash(hash(serial_num, [0; 4]), note_script_hash), input_hash)
type recipient = word;

type tag = felt;

/// A fungible asset
record fungible-asset {
/// Faucet ID of the faucet which issued the asset as well as the asset amount.
asset: account-id,
/// Asset amount is guaranteed to be 2^63 - 1 or smaller.
amount: u64
}

/// A commitment to a non-fungible asset.
///
/// A non-fungible asset consists of 4 field elements which are computed by hashing asset data
/// (which can be of arbitrary length) to produce: [d0, d1, d2, d3]. We then replace d1 with the
/// faucet_id that issued the asset: [d0, faucet_id, d2, d3]. We then set the most significant bit
/// of the most significant element to ZERO.
type non-fungible-asset = word;

/// A fungible or a non-fungible asset.
///
/// All assets are encoded using a single word (4 elements) such that it is easy to determine the
/// type of an asset both inside and outside Miden VM. Specifically:
/// Element 1 will be:
/// - ZERO for a fungible asset
/// - non-ZERO for a non-fungible asset
/// The most significant bit will be:
/// - ONE for a fungible asset
/// - ZERO for a non-fungible asset
///
/// The above properties guarantee that there can never be a collision between a fungible and a
/// non-fungible asset.
///
/// The methodology for constructing fungible and non-fungible assets is described below.
///
/// # Fungible assets
/// The most significant element of a fungible asset is set to the ID of the faucet which issued
/// the asset. This guarantees the properties described above (the first bit is ONE).
///
/// The least significant element is set to the amount of the asset. This amount cannot be greater
/// than 2^63 - 1 and thus requires 63-bits to store.
///
/// Elements 1 and 2 are set to ZERO.
///
/// It is impossible to find a collision between two fungible assets issued by different faucets as
/// the faucet_id is included in the description of the asset and this is guaranteed to be different
/// for each faucet as per the faucet creation logic.
///
/// # Non-fungible assets
/// The 4 elements of non-fungible assets are computed as follows:
/// - First the asset data is hashed. This compresses an asset of an arbitrary length to 4 field
/// elements: [d0, d1, d2, d3].
/// - d1 is then replaced with the faucet_id which issues the asset: [d0, faucet_id, d2, d3].
/// - Lastly, the most significant bit of d3 is set to ZERO.
///
/// It is impossible to find a collision between two non-fungible assets issued by different faucets
/// as the faucet_id is included in the description of the non-fungible asset and this is guaranteed
/// to be different as per the faucet creation logic. Collision resistance for non-fungible assets
/// issued by the same faucet is ~2^95.
variant asset {
fungible(fungible-asset),
non-fungible(non-fungible-asset),
}

/// Inputs of the currently executed note (4 words = 16 felts)
type note-inputs = tuple<felt, felt, felt, felt, felt, felt, felt, felt, felt, felt, felt, felt, felt, felt, felt, felt>;
greenhat marked this conversation as resolved.
Show resolved Hide resolved
}

interface tx-kernel {
use types.{asset, tag, recipient, note-inputs, account-id};

// Account-related functions

/// Get the id of the currently executing account
get-id: func() -> account-id;
/// Add the specified asset to the vault
add-asset: func(asset: asset) -> asset;
/// Remove the specified asset from the vault
remove-asset: func(asset: asset) -> asset;


// Note-related functions

/// Creates a new note.
/// asset is the asset to be included in the note.
/// tag is the tag to be included in the note.
/// recipient is the recipient of the note.
create-note: func(asset: asset, tag: tag, recipient: recipient);
/// Get the inputs of the currently executed note
get-inputs: func() -> note-inputs;
/// Get the assets of the currently executing note
get-assets: func() -> list<asset>;
}

/// Marker interface. Expected to be implemented by the account/wallet
interface account {}

interface note {
note-script: func();
}

world base-world {
export types;
}
1 change: 1 addition & 0 deletions tests/integration/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ miden-integration-tests-rust-fib = {path = "../rust-apps/fib"}
wasmprinter = "0.2.63"
sha2 = "0.10"
rustc-demangle = {version = "0.1.19", features = ["std"]}
cargo_metadata = "0.18"

[dev-dependencies]
proptest.workspace = true
Expand Down
Loading
Loading