-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #151 from 0xPolygonMiden/greenhat/i144-native-felt
[2/x] Native Miden VM felt type support as `Felt(f64)`
- Loading branch information
Showing
32 changed files
with
1,094 additions
and
298 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
# Developing Miden Programs In Rust | ||
|
||
This chapter will walk through how to develop Miden programs in Rust using the prelude and standard library provided by the `miden-prelude` crate (see the [README](https://github.com/0xPolygonMiden/compiler/sdk/prelude/README.md)). | ||
|
||
## Getting Started | ||
|
||
Import the prelude and standard library from the `miden-prelude` crate: | ||
|
||
```rust | ||
use miden_prelude::*; | ||
``` | ||
|
||
## Using `Felt` (field element) type | ||
|
||
The `Felt` type is a field element type that is used to represent the field element values of the Miden VM. | ||
|
||
To initialize a `Felt` value from an integer constant checking the range at compile time, use the `felt!` macro: | ||
|
||
```rust | ||
let a = felt!(42); | ||
``` | ||
|
||
Otherwise, use the `Felt::new` constructor: | ||
|
||
```rust | ||
let a = Felt::new(some_integer_var).unwrap(); | ||
``` | ||
|
||
The constructor returns an error if the value is not a valid field element, e.g. if it is not in the range `0..=M` where `M` is the modulus of the field (2^64 - 2^32 + 1). | ||
|
||
The `Felt` type implements the standard arithmetic operations, e.g. addition, subtraction, multiplication, division, etc. which are accessible through the standard Rust operators `+`, `-`, `*`, `/`, etc. All arithmetic operations are wrapping, i.e. performed modulo `M`. | ||
|
||
TODO: Add examples of using operations on `Felt` type and available functions (`assert*`, etc.). |
3 changes: 3 additions & 0 deletions
3
docs/src/guides/develop_miden_rollup_accounts_and_note_scripts_in_rust.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Developing Miden Rollup Accounts And Note Scripts In Rust | ||
|
||
This chapter will walk through how to develop Miden rollup accounts and note scripts in Rust using the Miden SDK crate. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
use std::vec; | ||
|
||
use miden_hir::{Felt, FunctionIdent, Immediate, InstBuilder, SourceSpan, Type::*, Value}; | ||
|
||
use crate::module::function_builder_ext::FunctionBuilderExt; | ||
|
||
pub(crate) const PRELUDE_INTRINSICS_FELT_MODULE_NAME: &str = "miden:prelude/intrinsics_felt"; | ||
|
||
/// Convert a call to a felt op intrinsic function into instruction(s) | ||
pub(crate) fn convert_felt_intrinsics( | ||
func_id: FunctionIdent, | ||
args: &[Value], | ||
builder: &mut FunctionBuilderExt<'_, '_, '_>, | ||
span: SourceSpan, | ||
) -> Vec<Value> { | ||
match func_id.function.as_symbol().as_str() { | ||
// Conversion operations | ||
"from_u64_unchecked" => { | ||
assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id); | ||
let inst = builder.ins().cast(args[0], Felt, span); | ||
vec![inst] | ||
} | ||
"as_u64" => { | ||
assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id); | ||
// we're casting to i64 instead of u64 because Wasm doesn't have u64 | ||
// and this value will be used in Wasm ops or local vars that expect i64 | ||
let inst = builder.ins().cast(args[0], I64, span); | ||
vec![inst] | ||
} | ||
// Arithmetic operations | ||
"add" => { | ||
assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id); | ||
let inst = builder.ins().add_unchecked(args[0], args[1], span); | ||
vec![inst] | ||
} | ||
"sub" => { | ||
assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id); | ||
let inst = builder.ins().sub_unchecked(args[0], args[1], span); | ||
vec![inst] | ||
} | ||
"mul" => { | ||
assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id); | ||
let inst = builder.ins().mul_unchecked(args[0], args[1], span); | ||
vec![inst] | ||
} | ||
"div" => { | ||
assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id); | ||
let inst = builder.ins().div_unchecked(args[0], args[1], span); | ||
vec![inst] | ||
} | ||
"neg" => { | ||
assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id); | ||
let inst = builder.ins().neg(args[0], span); | ||
vec![inst] | ||
} | ||
"inv" => { | ||
assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id); | ||
let inst = builder.ins().inv(args[0], span); | ||
vec![inst] | ||
} | ||
"pow2" => { | ||
assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id); | ||
let inst = builder.ins().pow2(args[0], span); | ||
vec![inst] | ||
} | ||
"exp" => { | ||
assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id); | ||
let inst = builder.ins().exp(args[0], args[1], span); | ||
vec![inst] | ||
} | ||
// Comparison operations | ||
"eq" => { | ||
assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id); | ||
let inst = builder.ins().eq(args[0], args[1], span); | ||
let cast = builder.ins().cast(inst, I32, span); | ||
vec![cast] | ||
} | ||
"gt" => { | ||
assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id); | ||
let inst = builder.ins().gt(args[0], args[1], span); | ||
let cast = builder.ins().cast(inst, I32, span); | ||
vec![cast] | ||
} | ||
"ge" => { | ||
assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id); | ||
let inst = builder.ins().gte(args[0], args[1], span); | ||
let cast = builder.ins().cast(inst, I32, span); | ||
vec![cast] | ||
} | ||
"lt" => { | ||
assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id); | ||
let inst = builder.ins().lt(args[0], args[1], span); | ||
let cast = builder.ins().cast(inst, I32, span); | ||
vec![cast] | ||
} | ||
"le" => { | ||
assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id); | ||
let inst = builder.ins().lte(args[0], args[1], span); | ||
let cast = builder.ins().cast(inst, I32, span); | ||
vec![cast] | ||
} | ||
"is_odd" => { | ||
assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id); | ||
let inst = builder.ins().is_odd(args[0], span); | ||
let cast = builder.ins().cast(inst, I32, span); | ||
vec![cast] | ||
} | ||
// Assert operations | ||
"assert" => { | ||
assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id); | ||
builder.ins().assert_eq_imm(Immediate::Felt(Felt::new(1)), args[0], span); | ||
vec![] | ||
} | ||
"assertz" => { | ||
assert_eq!(args.len(), 1, "{} takes exactly one argument", func_id); | ||
builder.ins().assert_eq_imm(Immediate::Felt(Felt::new(0)), args[0], span); | ||
vec![] | ||
} | ||
"assert_eq" => { | ||
assert_eq!(args.len(), 2, "{} takes exactly two arguments", func_id); | ||
builder.ins().assert_eq(args[0], args[1], span); | ||
vec![] | ||
} | ||
_ => panic!("No felt op intrinsics found for {}", func_id), | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
mod felt; | ||
|
||
use std::{collections::HashSet, sync::OnceLock}; | ||
|
||
use miden_hir::{FunctionIdent, SourceSpan, Symbol, Value}; | ||
|
||
use crate::module::function_builder_ext::FunctionBuilderExt; | ||
|
||
/// Check if the given module is a Miden module that contains intrinsics | ||
pub fn is_miden_intrinsics_module(module_id: Symbol) -> bool { | ||
modules().contains(module_id.as_str()) | ||
} | ||
|
||
fn modules() -> &'static HashSet<&'static str> { | ||
static MODULES: OnceLock<HashSet<&'static str>> = OnceLock::new(); | ||
MODULES.get_or_init(|| { | ||
let mut s = HashSet::default(); | ||
s.insert(felt::PRELUDE_INTRINSICS_FELT_MODULE_NAME); | ||
s | ||
}) | ||
} | ||
|
||
/// Convert a call to a Miden intrinsic function into instruction(s) | ||
pub fn convert_intrinsics_call( | ||
func_id: FunctionIdent, | ||
args: &[Value], | ||
builder: &mut FunctionBuilderExt, | ||
span: SourceSpan, | ||
) -> Vec<Value> { | ||
match func_id.module.as_symbol().as_str() { | ||
felt::PRELUDE_INTRINSICS_FELT_MODULE_NAME => { | ||
felt::convert_felt_intrinsics(func_id, args, builder, span) | ||
} | ||
_ => panic!("No intrinsics found for {}", func_id), | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.