Skip to content

Commit 2db6ecf

Browse files
committed
intermediate bytecode: implement to_bytecode
1 parent 7e4ab83 commit 2db6ecf

File tree

9 files changed

+388
-4
lines changed

9 files changed

+388
-4
lines changed

crates/leanVm/src/bytecode/hint.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,13 @@ pub enum Hint {
4242
/// A list of memory locations or constants whose values should be printed.
4343
content: Vec<MemOrConstant>,
4444
},
45+
/// A hint for the prover to compute the modular inverse of a field element.
46+
Inverse {
47+
/// The value to be inverted.
48+
arg: MemOrConstant,
49+
/// The offset from `fp` where the result (`arg^-1`) will be stored. If `arg` is zero, zero is stored.
50+
res_offset: usize,
51+
},
4552
}
4653

4754
impl Hint {
@@ -119,6 +126,21 @@ impl Hint {
119126
.insert(((run_context.fp + *res_offset)? + i)?, bit)?;
120127
}
121128
}
129+
Self::Inverse { arg, res_offset } => {
130+
// Resolve the `arg` operand to a concrete field element.
131+
let value: F = run_context
132+
.value_from_mem_or_constant(arg, memory_manager)?
133+
.try_into()?;
134+
135+
// Compute the modular inverse. If the value is zero, the result is zero.
136+
let result = value.try_inverse().unwrap_or(F::ZERO);
137+
138+
// Compute the destination address: `fp + res_offset`.
139+
let res_addr = (run_context.fp + *res_offset)?;
140+
141+
// Write the result to the destination address in memory.
142+
memory_manager.memory.insert(res_addr, result)?;
143+
}
122144
Self::Print { .. } => {
123145
// TODO: implement
124146
// This is for debugging purposes only so this is not urgent for now.

crates/leanVm/src/bytecode/operand.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,16 @@ impl MemOrConstant {
3131
Self::MemoryAfterFp { offset } => (F::from_usize(*offset), F::ZERO),
3232
}
3333
}
34+
35+
/// Returns a constant operand with value `0`.
36+
#[must_use] pub const fn zero() -> Self {
37+
Self::Constant(F::ZERO)
38+
}
39+
40+
/// Returns a constant operand with value `1`.
41+
#[must_use] pub const fn one() -> Self {
42+
Self::Constant(F::ONE)
43+
}
3444
}
3545

3646
/// Represents a value that can be a memory location, the `fp` register itself, or a constant.

crates/leanVm/src/compiler/mod.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
use std::collections::BTreeMap;
2+
3+
use crate::lang::Label;
4+
5+
#[derive(Debug)]
6+
pub struct Compiler {
7+
pub memory_size_per_function: BTreeMap<String, usize>,
8+
pub label_to_pc: BTreeMap<Label, usize>,
9+
}

crates/leanVm/src/intermediate_bytecode/instruction.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ impl IntermediateInstruction {
116116
}
117117
}
118118

119-
pub fn is_hint(&self) -> bool {
119+
#[must_use] pub const fn is_hint(&self) -> bool {
120120
match self {
121121
Self::RequestMemory { .. }
122122
| Self::Print { .. }

crates/leanVm/src/intermediate_bytecode/intermediate_value.rs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
use std::fmt;
22

3-
use crate::lang::{ConstExpression, Label};
3+
use crate::{
4+
bytecode::operand::{MemOrConstant, MemOrFp},
5+
compiler::Compiler,
6+
constant::F,
7+
lang::{ConstExpression, Label},
8+
};
49

510
#[derive(Debug, Clone, PartialEq, Eq)]
611
pub enum IntermediateValue {
@@ -19,6 +24,37 @@ impl IntermediateValue {
1924
pub const fn is_constant(&self) -> bool {
2025
matches!(self, Self::Constant(_))
2126
}
27+
28+
pub fn try_into_mem_or_fp(&self, compiler: &Compiler) -> Result<MemOrFp, String> {
29+
match self {
30+
Self::MemoryAfterFp { offset } => Ok(MemOrFp::MemoryAfterFp {
31+
offset: offset.eval_const_expression_usize(compiler),
32+
}),
33+
Self::Fp => Ok(MemOrFp::Fp),
34+
Self::Constant(_) => Err(format!("Cannot convert {self:?} to MemOrFp")),
35+
}
36+
}
37+
38+
pub fn try_into_mem_or_constant(&self, compiler: &Compiler) -> Result<MemOrConstant, String> {
39+
if let Some(cst) = self.try_as_constant(compiler) {
40+
return Ok(MemOrConstant::Constant(cst));
41+
}
42+
if let Self::MemoryAfterFp { offset } = self {
43+
return Ok(MemOrConstant::MemoryAfterFp {
44+
offset: offset.eval_const_expression_usize(compiler),
45+
});
46+
}
47+
Err(format!("Cannot convert {self:?} to MemOrConstant"))
48+
}
49+
50+
#[must_use]
51+
pub fn try_as_constant(&self, compiler: &Compiler) -> Option<F> {
52+
if let Self::Constant(c) = self {
53+
Some(c.eval_const_expression(compiler))
54+
} else {
55+
None
56+
}
57+
}
2258
}
2359

2460
impl From<ConstExpression> for IntermediateValue {

0 commit comments

Comments
 (0)