mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-01-09 14:48:08 -05:00
zkas: Rename "stack" to "heap".
"stack" is a misnomer, and the behavior of the zkVM is more heap-like than stack-like when doing an analogy with general computing.
This commit is contained in:
@@ -21,7 +21,7 @@ use anyhow::{anyhow, Result};
|
||||
use darkfi::{
|
||||
tx::Transaction,
|
||||
util::parse::encode_base10,
|
||||
zk::{halo2::Field, proof::ProvingKey, vm::ZkCircuit, vm_stack::empty_witnesses, Proof},
|
||||
zk::{halo2::Field, proof::ProvingKey, vm::ZkCircuit, vm_heap::empty_witnesses, Proof},
|
||||
zkas::ZkBinary,
|
||||
};
|
||||
use darkfi_money_contract::{
|
||||
|
||||
@@ -20,7 +20,7 @@ use anyhow::{anyhow, Result};
|
||||
use darkfi::{
|
||||
tx::Transaction,
|
||||
util::parse::decode_base10,
|
||||
zk::{proof::ProvingKey, vm::ZkCircuit, vm_stack::empty_witnesses},
|
||||
zk::{proof::ProvingKey, vm::ZkCircuit, vm_heap::empty_witnesses},
|
||||
zkas::ZkBinary,
|
||||
};
|
||||
use darkfi_money_contract::{
|
||||
|
||||
@@ -20,7 +20,7 @@ use anyhow::{anyhow, Result};
|
||||
use darkfi::{
|
||||
tx::Transaction,
|
||||
util::parse::{decode_base10, encode_base10},
|
||||
zk::{halo2::Field, proof::ProvingKey, vm::ZkCircuit, vm_stack::empty_witnesses},
|
||||
zk::{halo2::Field, proof::ProvingKey, vm::ZkCircuit, vm_heap::empty_witnesses},
|
||||
zkas::ZkBinary,
|
||||
};
|
||||
use darkfi_dao_contract::dao_model::DaoBulla;
|
||||
|
||||
@@ -32,7 +32,7 @@ use chrono::Utc;
|
||||
use darkfi::{
|
||||
runtime::vm_runtime::SMART_CONTRACT_ZKAS_DB_NAME,
|
||||
tx::Transaction,
|
||||
zk::{halo2::Field, proof::ProvingKey, vm::ZkCircuit, vm_stack::empty_witnesses},
|
||||
zk::{halo2::Field, proof::ProvingKey, vm::ZkCircuit, vm_heap::empty_witnesses},
|
||||
zkas::ZkBinary,
|
||||
};
|
||||
use darkfi_money_contract::{
|
||||
|
||||
@@ -9,9 +9,9 @@ Our programs consist of four sections: `constant`, `literal`,
|
||||
same. Additionally, there is an optional section called `.debug`
|
||||
which can hold debug info related to the binary.
|
||||
|
||||
We currently keep all variables on one stack, and literals on another
|
||||
stack. Therefore before each `STACK_INDEX` we prepend `STACK_TYPE` so
|
||||
the VM is able to know which stack it should do lookup from.
|
||||
We currently keep all variables on one heap, and literals on another
|
||||
heap. Therefore before each `HEAP_INDEX` we prepend `HEAP_TYPE` so
|
||||
the VM is able to know which heap it should do lookup from.
|
||||
|
||||
The compiled binary blob has the following layout:
|
||||
|
||||
@@ -32,8 +32,8 @@ WITNESS_TYPE
|
||||
WITNESS_TYPE
|
||||
...
|
||||
.circuit
|
||||
OPCODE ARG_NUM STACK_TYPE STACK_INDEX ... STACK_TYPE STACK_INDEX
|
||||
OPCODE ARG_NUM STACK_TYPE STACK_INDEX ... STACK_TYPE STACK_INDEX
|
||||
OPCODE ARG_NUM HEAP_TYPE HEAP_INDEX ... HEAP_TYPE HEAP_INDEX
|
||||
OPCODE ARG_NUM HEAP_TYPE HEAP_INDEX ... HEAP_TYPE HEAP_INDEX
|
||||
...
|
||||
.debug
|
||||
TBD
|
||||
@@ -78,7 +78,7 @@ The string is serialized with variable-integer encoding.
|
||||
|
||||
The constants in the `.constant` section are declared with their type
|
||||
and name, so that the VM knows how to search for the builtin constant
|
||||
and add it to the stack.
|
||||
and add it to the heap.
|
||||
|
||||
### `.literal`
|
||||
|
||||
@@ -90,7 +90,7 @@ could be extended with signed integers, and strings.
|
||||
### `.witness`
|
||||
|
||||
The `.witness` section holds the circuit witness values in the form
|
||||
of `WITNESS_TYPE`. Their stack index is incremented for each witness
|
||||
of `WITNESS_TYPE`. Their heap index is incremented for each witness
|
||||
as they're kept in order like in the source file. The witnesses
|
||||
that are of the same type as the circuit itself (typically `Base`)
|
||||
will be loaded into the circuit as _private values_ using the Halo2
|
||||
@@ -103,7 +103,7 @@ The `.circuit` section holds the procedural logic of the ZK proof.
|
||||
In here we have statements with opcodes that are executed as
|
||||
understood by the VM. The statements are in the form of:
|
||||
|
||||
> `OPCODE ARG_NUM STACK_TYPE STACK_INDEX ... STACK_TYPE STACK_INDEX`
|
||||
> `OPCODE ARG_NUM HEAP_TYPE HEAP_INDEX ... HEAP_TYPE HEAP_INDEX`
|
||||
|
||||
where:
|
||||
|
||||
@@ -112,14 +112,14 @@ where:
|
||||
| `OPCODE` | The opcode we wish to execute |
|
||||
| `ARG_NUM` | The number of arguments given to this opcode |
|
||||
| | (Note the VM should be checking the correctness of this as well) |
|
||||
| `STACK_TYPE` | Type of the stack to do lookup from (variables or literals) |
|
||||
| | (This is prepended to every `STACK_INDEX`) |
|
||||
| `STACK_INDEX` | The location of the argument on the stack. |
|
||||
| `HEAP_TYPE` | Type of the heap to do lookup from (variables or literals) |
|
||||
| | (This is prepended to every `HEAP_INDEX`) |
|
||||
| `HEAP_INDEX` | The location of the argument on the heap. |
|
||||
| | (This is supposed to be repeated `ARG_NUM` times) |
|
||||
|
||||
|
||||
In case an opcode has a return value, the value shall be pushed to
|
||||
the stack and become available for later references.
|
||||
the heap and become available for later references.
|
||||
|
||||
### `.debug`
|
||||
|
||||
@@ -168,8 +168,8 @@ TBD
|
||||
| `LessThanStrict` | Strictly compare if `Base` a is lesser than `Base` b |
|
||||
| `LessThanLoose` | Loosely compare if `Base` a is lesser than `Base` b |
|
||||
| `BoolCheck` | Enforce that a `Base` fits in a boolean value (either 0 or 1) |
|
||||
| `ConstrainEqualBase` | Constrain equality of two `Base` elements from the stack |
|
||||
| `ConstrainEqualPoint`| Constrain equality of two `EcPoint` elements from the stack |
|
||||
| `ConstrainEqualBase` | Constrain equality of two `Base` elements from the heap |
|
||||
| `ConstrainEqualPoint`| Constrain equality of two `EcPoint` elements from the heap |
|
||||
| `ConstrainInstance` | Constrain a `Base` to a Circuit's Public Input. |
|
||||
|
||||
### Built-in Opcode Wrappers
|
||||
|
||||
@@ -22,7 +22,7 @@ use darkfi::{
|
||||
zk::{
|
||||
proof::{Proof, ProvingKey, VerifyingKey},
|
||||
vm::{Witness, ZkCircuit},
|
||||
vm_stack::empty_witnesses,
|
||||
vm_heap::empty_witnesses,
|
||||
},
|
||||
zkas::decoder::ZkBinary,
|
||||
Result,
|
||||
|
||||
@@ -22,7 +22,7 @@ use darkfi::{
|
||||
zk::{
|
||||
proof::{Proof, ProvingKey, VerifyingKey},
|
||||
vm::{Witness, ZkCircuit},
|
||||
vm_stack::empty_witnesses,
|
||||
vm_heap::empty_witnesses,
|
||||
},
|
||||
zkas::decoder::ZkBinary,
|
||||
Result,
|
||||
|
||||
@@ -37,7 +37,7 @@ use crate::{
|
||||
zk::{
|
||||
proof::{Proof, ProvingKey},
|
||||
vm::ZkCircuit,
|
||||
vm_stack::Witness,
|
||||
vm_heap::Witness,
|
||||
},
|
||||
zkas::ZkBinary,
|
||||
Result,
|
||||
|
||||
@@ -53,7 +53,7 @@ use crate::{
|
||||
zk::{
|
||||
proof::{ProvingKey, VerifyingKey},
|
||||
vm::ZkCircuit,
|
||||
vm_stack::empty_witnesses,
|
||||
vm_heap::empty_witnesses,
|
||||
},
|
||||
zkas::ZkBinary,
|
||||
Error, Result,
|
||||
|
||||
@@ -20,8 +20,9 @@
|
||||
pub mod vm;
|
||||
pub use vm::ZkCircuit;
|
||||
|
||||
pub mod vm_stack;
|
||||
pub use vm_stack::{empty_witnesses, Witness};
|
||||
/// VM heap variable definitions and utility functions
|
||||
pub mod vm_heap;
|
||||
pub use vm_heap::{empty_witnesses, Witness};
|
||||
|
||||
/// ZK gadget implementations
|
||||
pub mod gadget;
|
||||
|
||||
184
src/zk/vm.rs
184
src/zk/vm.rs
@@ -48,7 +48,7 @@ use halo2_proofs::{
|
||||
};
|
||||
use log::{error, trace};
|
||||
|
||||
pub use super::vm_stack::{StackVar, Witness};
|
||||
pub use super::vm_heap::{HeapVar, Witness};
|
||||
use super::{
|
||||
assign_free_advice,
|
||||
gadget::{
|
||||
@@ -59,7 +59,7 @@ use super::{
|
||||
},
|
||||
};
|
||||
use crate::zkas::{
|
||||
types::{LitType, StackType},
|
||||
types::{HeapType, LitType},
|
||||
Opcode, ZkBinary,
|
||||
};
|
||||
|
||||
@@ -111,7 +111,7 @@ pub struct ZkCircuit {
|
||||
constants: Vec<String>,
|
||||
witnesses: Vec<Witness>,
|
||||
literals: Vec<(LitType, String)>,
|
||||
opcodes: Vec<(Opcode, Vec<(StackType, usize)>)>,
|
||||
opcodes: Vec<(Opcode, Vec<(HeapType, usize)>)>,
|
||||
}
|
||||
|
||||
impl ZkCircuit {
|
||||
@@ -291,12 +291,12 @@ impl Circuit<pallas::Base> for ZkCircuit {
|
||||
// VM Setup
|
||||
//====================
|
||||
|
||||
// Our stack which holds every variable we reference and create.
|
||||
let mut stack: Vec<StackVar> = vec![];
|
||||
// Our heap which holds every variable we reference and create.
|
||||
let mut heap: Vec<HeapVar> = vec![];
|
||||
|
||||
// Our stack which holds all the literal values we have in the circuit.
|
||||
// Our heap which holds all the literal values we have in the circuit.
|
||||
// For now, we only support u64.
|
||||
let mut litstack: Vec<u64> = vec![];
|
||||
let mut litheap: Vec<u64> = vec![];
|
||||
|
||||
// Offset for public inputs
|
||||
let mut public_inputs_offset = 0;
|
||||
@@ -346,29 +346,29 @@ impl Circuit<pallas::Base> for ZkCircuit {
|
||||
Value::known(pallas::Base::one()),
|
||||
)?;
|
||||
|
||||
// Lookup and push constants onto the stack
|
||||
// Lookup and push constants onto the heap
|
||||
for constant in &self.constants {
|
||||
trace!(
|
||||
target: "zk::vm",
|
||||
"Pushing constant `{}` to stack index {}",
|
||||
"Pushing constant `{}` to heap address {}",
|
||||
constant.as_str(),
|
||||
stack.len()
|
||||
heap.len()
|
||||
);
|
||||
match constant.as_str() {
|
||||
"VALUE_COMMIT_VALUE" => {
|
||||
let vcv = ValueCommitV;
|
||||
let vcv = FixedPointShort::from_inner(ecc_chip.clone(), vcv);
|
||||
stack.push(StackVar::EcFixedPointShort(vcv));
|
||||
heap.push(HeapVar::EcFixedPointShort(vcv));
|
||||
}
|
||||
"VALUE_COMMIT_RANDOM" => {
|
||||
let vcr = OrchardFixedBasesFull::ValueCommitR;
|
||||
let vcr = FixedPoint::from_inner(ecc_chip.clone(), vcr);
|
||||
stack.push(StackVar::EcFixedPoint(vcr));
|
||||
heap.push(HeapVar::EcFixedPoint(vcr));
|
||||
}
|
||||
"NULLIFIER_K" => {
|
||||
let nfk = NullifierK;
|
||||
let nfk = FixedPointBaseField::from_inner(ecc_chip.clone(), nfk);
|
||||
stack.push(StackVar::EcFixedPointBase(nfk));
|
||||
heap.push(HeapVar::EcFixedPointBase(nfk));
|
||||
}
|
||||
|
||||
_ => {
|
||||
@@ -378,12 +378,12 @@ impl Circuit<pallas::Base> for ZkCircuit {
|
||||
}
|
||||
}
|
||||
|
||||
// Load the literals onto the literal stack.
|
||||
// Load the literals onto the literal heap
|
||||
// N.B. Only uint64 is supported right now.
|
||||
for literal in &self.literals {
|
||||
match literal.0 {
|
||||
LitType::Uint64 => match literal.1.parse::<u64>() {
|
||||
Ok(v) => litstack.push(v),
|
||||
Ok(v) => litheap.push(v),
|
||||
Err(e) => {
|
||||
error!(target: "zk::vm", "Failed converting u64 literal: {}", e);
|
||||
return Err(plonk::Error::Synthesis)
|
||||
@@ -396,7 +396,7 @@ impl Circuit<pallas::Base> for ZkCircuit {
|
||||
}
|
||||
}
|
||||
|
||||
// Push the witnesses onto the stack, and potentially, if the witness
|
||||
// Push the witnesses onto the heap, and potentially, if the witness
|
||||
// is in the Base field (like the entire circuit is), load it into a
|
||||
// table cell.
|
||||
for witness in &self.witnesses {
|
||||
@@ -409,8 +409,8 @@ impl Circuit<pallas::Base> for ZkCircuit {
|
||||
w.as_ref().map(|cm| cm.to_affine()),
|
||||
)?;
|
||||
|
||||
trace!(target: "zk::vm", "Pushing EcPoint to stack index {}", stack.len());
|
||||
stack.push(StackVar::EcPoint(point));
|
||||
trace!(target: "zk::vm", "Pushing EcPoint to heap address {}", heap.len());
|
||||
heap.push(HeapVar::EcPoint(point));
|
||||
}
|
||||
|
||||
Witness::EcNiPoint(w) => {
|
||||
@@ -421,8 +421,8 @@ impl Circuit<pallas::Base> for ZkCircuit {
|
||||
w.as_ref().map(|cm| cm.to_affine()),
|
||||
)?;
|
||||
|
||||
trace!(target: "zk::vm", "Pushing EcNiPoint to stack index {}", stack.len());
|
||||
stack.push(StackVar::EcNiPoint(point));
|
||||
trace!(target: "zk::vm", "Pushing EcNiPoint to heap address {}", heap.len());
|
||||
heap.push(HeapVar::EcNiPoint(point));
|
||||
}
|
||||
|
||||
Witness::EcFixedPoint(_) => {
|
||||
@@ -438,16 +438,16 @@ impl Circuit<pallas::Base> for ZkCircuit {
|
||||
*w,
|
||||
)?;
|
||||
|
||||
trace!(target: "zk::vm", "Pushing Base to stack index {}", stack.len());
|
||||
stack.push(StackVar::Base(base));
|
||||
trace!(target: "zk::vm", "Pushing Base to heap address {}", heap.len());
|
||||
heap.push(HeapVar::Base(base));
|
||||
}
|
||||
|
||||
Witness::Scalar(w) => {
|
||||
// NOTE: Because the type in `halo2_gadgets` does not have a `Clone`
|
||||
// impl, we push scalars as-is to the stack. They get witnessed
|
||||
// impl, we push scalars as-is to the heap. They get witnessed
|
||||
// when they get used.
|
||||
trace!(target: "zk::vm", "Pushing Scalar to stack index {}", stack.len());
|
||||
stack.push(StackVar::Scalar(*w));
|
||||
trace!(target: "zk::vm", "Pushing Scalar to heap address {}", heap.len());
|
||||
heap.push(HeapVar::Scalar(*w));
|
||||
}
|
||||
|
||||
Witness::MerklePath(w) => {
|
||||
@@ -455,18 +455,18 @@ impl Circuit<pallas::Base> for ZkCircuit {
|
||||
let path: Value<[pallas::Base; MERKLE_DEPTH_ORCHARD]> =
|
||||
w.map(|typed_path| gen_const_array(|i| typed_path[i].inner()));
|
||||
|
||||
trace!(target: "zk::vm", "Pushing MerklePath to stack index {}", stack.len());
|
||||
stack.push(StackVar::MerklePath(path));
|
||||
trace!(target: "zk::vm", "Pushing MerklePath to heap address {}", heap.len());
|
||||
heap.push(HeapVar::MerklePath(path));
|
||||
}
|
||||
|
||||
Witness::Uint32(w) => {
|
||||
trace!(target: "zk::vm", "Pushing Uint32 to stack index {}", stack.len());
|
||||
stack.push(StackVar::Uint32(*w));
|
||||
trace!(target: "zk::vm", "Pushing Uint32 to heap address {}", heap.len());
|
||||
heap.push(HeapVar::Uint32(*w));
|
||||
}
|
||||
|
||||
Witness::Uint64(w) => {
|
||||
trace!(target: "zk::vm", "Pushing Uint64 to stack index {}", stack.len());
|
||||
stack.push(StackVar::Uint64(*w));
|
||||
trace!(target: "zk::vm", "Pushing Uint64 to heap address {}", heap.len());
|
||||
heap.push(HeapVar::Uint64(*w));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -482,15 +482,15 @@ impl Circuit<pallas::Base> for ZkCircuit {
|
||||
let args = &opcode.1;
|
||||
|
||||
let lhs: Point<pallas::Affine, EccChip<OrchardFixedBases>> =
|
||||
stack[args[0].1].clone().into();
|
||||
heap[args[0].1].clone().into();
|
||||
|
||||
let rhs: Point<pallas::Affine, EccChip<OrchardFixedBases>> =
|
||||
stack[args[1].1].clone().into();
|
||||
heap[args[1].1].clone().into();
|
||||
|
||||
let ret = lhs.add(layouter.namespace(|| "EcAdd()"), &rhs)?;
|
||||
|
||||
trace!(target: "zk::vm", "Pushing result to stack index {}", stack.len());
|
||||
stack.push(StackVar::EcPoint(ret));
|
||||
trace!(target: "zk::vm", "Pushing result to heap address {}", heap.len());
|
||||
heap.push(HeapVar::EcPoint(ret));
|
||||
}
|
||||
|
||||
Opcode::EcMul => {
|
||||
@@ -498,18 +498,18 @@ impl Circuit<pallas::Base> for ZkCircuit {
|
||||
let args = &opcode.1;
|
||||
|
||||
let lhs: FixedPoint<pallas::Affine, EccChip<OrchardFixedBases>> =
|
||||
stack[args[1].1].clone().into();
|
||||
heap[args[1].1].clone().into();
|
||||
|
||||
let rhs = ScalarFixed::new(
|
||||
ecc_chip.clone(),
|
||||
layouter.namespace(|| "EcMul: ScalarFixed::new()"),
|
||||
stack[args[0].1].clone().into(),
|
||||
heap[args[0].1].clone().into(),
|
||||
)?;
|
||||
|
||||
let (ret, _) = lhs.mul(layouter.namespace(|| "EcMul()"), rhs)?;
|
||||
|
||||
trace!(target: "zk::vm", "Pushing result to stack index {}", stack.len());
|
||||
stack.push(StackVar::EcPoint(ret));
|
||||
trace!(target: "zk::vm", "Pushing result to heap address {}", heap.len());
|
||||
heap.push(HeapVar::EcPoint(ret));
|
||||
}
|
||||
|
||||
Opcode::EcMulVarBase => {
|
||||
@@ -517,9 +517,9 @@ impl Circuit<pallas::Base> for ZkCircuit {
|
||||
let args = &opcode.1;
|
||||
|
||||
let lhs: NonIdentityPoint<pallas::Affine, EccChip<OrchardFixedBases>> =
|
||||
stack[args[1].1].clone().into();
|
||||
heap[args[1].1].clone().into();
|
||||
|
||||
let rhs: AssignedCell<Fp, Fp> = stack[args[0].1].clone().into();
|
||||
let rhs: AssignedCell<Fp, Fp> = heap[args[0].1].clone().into();
|
||||
let rhs = ScalarVar::from_base(
|
||||
ecc_chip.clone(),
|
||||
layouter.namespace(|| "EcMulVarBase::from_base()"),
|
||||
@@ -528,8 +528,8 @@ impl Circuit<pallas::Base> for ZkCircuit {
|
||||
|
||||
let (ret, _) = lhs.mul(layouter.namespace(|| "EcMulVarBase()"), rhs)?;
|
||||
|
||||
trace!(target: "zk::vm", "Pushing result to stack index {}", stack.len());
|
||||
stack.push(StackVar::EcPoint(ret));
|
||||
trace!(target: "zk::vm", "Pushing result to heap address {}", heap.len());
|
||||
heap.push(HeapVar::EcPoint(ret));
|
||||
}
|
||||
|
||||
Opcode::EcMulBase => {
|
||||
@@ -537,14 +537,14 @@ impl Circuit<pallas::Base> for ZkCircuit {
|
||||
let args = &opcode.1;
|
||||
|
||||
let lhs: FixedPointBaseField<pallas::Affine, EccChip<OrchardFixedBases>> =
|
||||
stack[args[1].1].clone().into();
|
||||
heap[args[1].1].clone().into();
|
||||
|
||||
let rhs: AssignedCell<Fp, Fp> = stack[args[0].1].clone().into();
|
||||
let rhs: AssignedCell<Fp, Fp> = heap[args[0].1].clone().into();
|
||||
|
||||
let ret = lhs.mul(layouter.namespace(|| "EcMulBase()"), rhs)?;
|
||||
|
||||
trace!(target: "zk::vm", "Pushing result to stack index {}", stack.len());
|
||||
stack.push(StackVar::EcPoint(ret));
|
||||
trace!(target: "zk::vm", "Pushing result to heap address {}", heap.len());
|
||||
heap.push(HeapVar::EcPoint(ret));
|
||||
}
|
||||
|
||||
Opcode::EcMulShort => {
|
||||
@@ -552,18 +552,18 @@ impl Circuit<pallas::Base> for ZkCircuit {
|
||||
let args = &opcode.1;
|
||||
|
||||
let lhs: FixedPointShort<pallas::Affine, EccChip<OrchardFixedBases>> =
|
||||
stack[args[1].1].clone().into();
|
||||
heap[args[1].1].clone().into();
|
||||
|
||||
let rhs = ScalarFixedShort::new(
|
||||
ecc_chip.clone(),
|
||||
layouter.namespace(|| "EcMulShort: ScalarFixedShort::new()"),
|
||||
(stack[args[0].1].clone().into(), one.clone()),
|
||||
(heap[args[0].1].clone().into(), one.clone()),
|
||||
)?;
|
||||
|
||||
let (ret, _) = lhs.mul(layouter.namespace(|| "EcMulShort()"), rhs)?;
|
||||
|
||||
trace!(target: "zk::vm", "Pushing result to stack index {}", stack.len());
|
||||
stack.push(StackVar::EcPoint(ret));
|
||||
trace!(target: "zk::vm", "Pushing result to heap address {}", heap.len());
|
||||
heap.push(HeapVar::EcPoint(ret));
|
||||
}
|
||||
|
||||
Opcode::EcGetX => {
|
||||
@@ -571,12 +571,12 @@ impl Circuit<pallas::Base> for ZkCircuit {
|
||||
let args = &opcode.1;
|
||||
|
||||
let point: Point<pallas::Affine, EccChip<OrchardFixedBases>> =
|
||||
stack[args[0].1].clone().into();
|
||||
heap[args[0].1].clone().into();
|
||||
|
||||
let ret = point.inner().x();
|
||||
|
||||
trace!(target: "zk::vm", "Pushing result to stack index {}", stack.len());
|
||||
stack.push(StackVar::Base(ret));
|
||||
trace!(target: "zk::vm", "Pushing result to heap address {}", heap.len());
|
||||
heap.push(HeapVar::Base(ret));
|
||||
}
|
||||
|
||||
Opcode::EcGetY => {
|
||||
@@ -584,12 +584,12 @@ impl Circuit<pallas::Base> for ZkCircuit {
|
||||
let args = &opcode.1;
|
||||
|
||||
let point: Point<pallas::Affine, EccChip<OrchardFixedBases>> =
|
||||
stack[args[0].1].clone().into();
|
||||
heap[args[0].1].clone().into();
|
||||
|
||||
let ret = point.inner().y();
|
||||
|
||||
trace!(target: "zk::vm", "Pushing result to stack index {}", stack.len());
|
||||
stack.push(StackVar::Base(ret));
|
||||
trace!(target: "zk::vm", "Pushing result to heap address {}", heap.len());
|
||||
heap.push(HeapVar::Base(ret));
|
||||
}
|
||||
|
||||
Opcode::PoseidonHash => {
|
||||
@@ -600,7 +600,7 @@ impl Circuit<pallas::Base> for ZkCircuit {
|
||||
Vec::with_capacity(args.len());
|
||||
|
||||
for idx in args {
|
||||
poseidon_message.push(stack[idx.1].clone().into());
|
||||
poseidon_message.push(heap[idx.1].clone().into());
|
||||
}
|
||||
|
||||
macro_rules! poseidon_hash {
|
||||
@@ -624,8 +624,8 @@ impl Circuit<pallas::Base> for ZkCircuit {
|
||||
|
||||
let $cell: AssignedCell<Fp, Fp> = $output.into();
|
||||
|
||||
trace!(target: "zk::vm", "Pushing hash to stack index {}", stack.len());
|
||||
stack.push(StackVar::Base($cell));
|
||||
trace!(target: "zk::vm", "Pushing hash to heap address {}", heap.len());
|
||||
heap.push(HeapVar::Base($cell));
|
||||
};
|
||||
}
|
||||
|
||||
@@ -650,9 +650,9 @@ impl Circuit<pallas::Base> for ZkCircuit {
|
||||
trace!(target: "zk::vm", "Executing `MerkleRoot{:?}` opcode", opcode.1);
|
||||
let args = &opcode.1;
|
||||
|
||||
let leaf_pos = stack[args[0].1].clone().into();
|
||||
let merkle_path = stack[args[1].1].clone().into();
|
||||
let leaf = stack[args[2].1].clone().into();
|
||||
let leaf_pos = heap[args[0].1].clone().into();
|
||||
let merkle_path = heap[args[1].1].clone().into();
|
||||
let leaf = heap[args[2].1].clone().into();
|
||||
|
||||
let merkle_inputs = MerklePath::construct(
|
||||
[config.merkle_chip_1(), config.merkle_chip_2()],
|
||||
@@ -664,55 +664,55 @@ impl Circuit<pallas::Base> for ZkCircuit {
|
||||
let root = merkle_inputs
|
||||
.calculate_root(layouter.namespace(|| "MerkleRoot()"), leaf)?;
|
||||
|
||||
trace!(target: "zk::vm", "Pushing merkle root to stack index {}", stack.len());
|
||||
stack.push(StackVar::Base(root));
|
||||
trace!(target: "zk::vm", "Pushing merkle root to heap address {}", heap.len());
|
||||
heap.push(HeapVar::Base(root));
|
||||
}
|
||||
|
||||
Opcode::BaseAdd => {
|
||||
trace!(target: "zk::vm", "Executing `BaseAdd{:?}` opcode", opcode.1);
|
||||
let args = &opcode.1;
|
||||
|
||||
let lhs = &stack[args[0].1].clone().into();
|
||||
let rhs = &stack[args[1].1].clone().into();
|
||||
let lhs = &heap[args[0].1].clone().into();
|
||||
let rhs = &heap[args[1].1].clone().into();
|
||||
|
||||
let sum = arith_chip.add(layouter.namespace(|| "BaseAdd()"), lhs, rhs)?;
|
||||
|
||||
trace!(target: "zk::vm", "Pushing sum to stack index {}", stack.len());
|
||||
stack.push(StackVar::Base(sum));
|
||||
trace!(target: "zk::vm", "Pushing sum to heap address {}", heap.len());
|
||||
heap.push(HeapVar::Base(sum));
|
||||
}
|
||||
|
||||
Opcode::BaseMul => {
|
||||
trace!(target: "zk::vm", "Executing `BaseSub{:?}` opcode", opcode.1);
|
||||
let args = &opcode.1;
|
||||
|
||||
let lhs = &stack[args[0].1].clone().into();
|
||||
let rhs = &stack[args[1].1].clone().into();
|
||||
let lhs = &heap[args[0].1].clone().into();
|
||||
let rhs = &heap[args[1].1].clone().into();
|
||||
|
||||
let product = arith_chip.mul(layouter.namespace(|| "BaseMul()"), lhs, rhs)?;
|
||||
|
||||
trace!(target: "zk::vm", "Pushing product to stack index {}", stack.len());
|
||||
stack.push(StackVar::Base(product));
|
||||
trace!(target: "zk::vm", "Pushing product to heap address {}", heap.len());
|
||||
heap.push(HeapVar::Base(product));
|
||||
}
|
||||
|
||||
Opcode::BaseSub => {
|
||||
trace!(target: "zk::vm", "Executing `BaseSub{:?}` opcode", opcode.1);
|
||||
let args = &opcode.1;
|
||||
|
||||
let lhs = &stack[args[0].1].clone().into();
|
||||
let rhs = &stack[args[1].1].clone().into();
|
||||
let lhs = &heap[args[0].1].clone().into();
|
||||
let rhs = &heap[args[1].1].clone().into();
|
||||
|
||||
let difference =
|
||||
arith_chip.sub(layouter.namespace(|| "BaseSub()"), lhs, rhs)?;
|
||||
|
||||
trace!(target: "zk::vm", "Pushing difference to stack index {}", stack.len());
|
||||
stack.push(StackVar::Base(difference));
|
||||
trace!(target: "zk::vm", "Pushing difference to heap address {}", heap.len());
|
||||
heap.push(HeapVar::Base(difference));
|
||||
}
|
||||
|
||||
Opcode::WitnessBase => {
|
||||
trace!(target: "zk::vm", "Executing `WitnessBase{:?}` opcode", opcode.1);
|
||||
//let args = &opcode.1;
|
||||
|
||||
let lit = litstack[literals_offset];
|
||||
let lit = litheap[literals_offset];
|
||||
literals_offset += 1;
|
||||
|
||||
let witness = assign_free_advice(
|
||||
@@ -721,18 +721,18 @@ impl Circuit<pallas::Base> for ZkCircuit {
|
||||
Value::known(pallas::Base::from(lit)),
|
||||
)?;
|
||||
|
||||
trace!(target: "zk::vm", "Pushing assignment to stack index {}", stack.len());
|
||||
stack.push(StackVar::Base(witness));
|
||||
trace!(target: "zk::vm", "Pushing assignment to heap address {}", heap.len());
|
||||
heap.push(HeapVar::Base(witness));
|
||||
}
|
||||
|
||||
Opcode::RangeCheck => {
|
||||
trace!(target: "zk::vm", "Executing `RangeCheck{:?}` opcode", opcode.1);
|
||||
let args = &opcode.1;
|
||||
|
||||
let lit = litstack[literals_offset];
|
||||
let lit = litheap[literals_offset];
|
||||
literals_offset += 1;
|
||||
|
||||
let arg = stack[args[1].1].clone();
|
||||
let arg = heap[args[1].1].clone();
|
||||
|
||||
match lit {
|
||||
64 => {
|
||||
@@ -760,8 +760,8 @@ impl Circuit<pallas::Base> for ZkCircuit {
|
||||
trace!(target: "zk::vm", "Executing `LessThanStrict{:?}` opcode", opcode.1);
|
||||
let args = &opcode.1;
|
||||
|
||||
let a = stack[args[0].1].clone().into();
|
||||
let b = stack[args[1].1].clone().into();
|
||||
let a = heap[args[0].1].clone().into();
|
||||
let b = heap[args[1].1].clone().into();
|
||||
|
||||
lessthan_chip.copy_less_than(
|
||||
layouter.namespace(|| "copy a<b check"),
|
||||
@@ -776,8 +776,8 @@ impl Circuit<pallas::Base> for ZkCircuit {
|
||||
trace!(target: "zk::vm", "Executing `LessThanLoose{:?}` opcode", opcode.1);
|
||||
let args = &opcode.1;
|
||||
|
||||
let a = stack[args[0].1].clone().into();
|
||||
let b = stack[args[1].1].clone().into();
|
||||
let a = heap[args[0].1].clone().into();
|
||||
let b = heap[args[1].1].clone().into();
|
||||
|
||||
lessthan_chip.copy_less_than(
|
||||
layouter.namespace(|| "copy a<b check"),
|
||||
@@ -792,7 +792,7 @@ impl Circuit<pallas::Base> for ZkCircuit {
|
||||
trace!(target: "zk::vm", "Executing `BoolCheck{:?}` opcode", opcode.1);
|
||||
let args = &opcode.1;
|
||||
|
||||
let w = stack[args[0].1].clone().into();
|
||||
let w = heap[args[0].1].clone().into();
|
||||
|
||||
boolcheck_chip
|
||||
.small_range_check(layouter.namespace(|| "copy boolean check"), w)?;
|
||||
@@ -802,8 +802,8 @@ impl Circuit<pallas::Base> for ZkCircuit {
|
||||
trace!(target: "zk::vm", "Executing `ConstrainEqualBase{:?}` opcode", opcode.1);
|
||||
let args = &opcode.1;
|
||||
|
||||
let lhs: AssignedCell<Fp, Fp> = stack[args[0].1].clone().into();
|
||||
let rhs: AssignedCell<Fp, Fp> = stack[args[1].1].clone().into();
|
||||
let lhs: AssignedCell<Fp, Fp> = heap[args[0].1].clone().into();
|
||||
let rhs: AssignedCell<Fp, Fp> = heap[args[1].1].clone().into();
|
||||
|
||||
layouter.assign_region(
|
||||
|| "constrain witnessed base equality",
|
||||
@@ -816,10 +816,10 @@ impl Circuit<pallas::Base> for ZkCircuit {
|
||||
let args = &opcode.1;
|
||||
|
||||
let lhs: Point<pallas::Affine, EccChip<OrchardFixedBases>> =
|
||||
stack[args[0].1].clone().into();
|
||||
heap[args[0].1].clone().into();
|
||||
|
||||
let rhs: Point<pallas::Affine, EccChip<OrchardFixedBases>> =
|
||||
stack[args[1].1].clone().into();
|
||||
heap[args[1].1].clone().into();
|
||||
|
||||
lhs.constrain_equal(
|
||||
layouter.namespace(|| "constrain ec point equality"),
|
||||
@@ -831,7 +831,7 @@ impl Circuit<pallas::Base> for ZkCircuit {
|
||||
trace!(target: "zk::vm", "Executing `ConstrainInstance{:?}` opcode", opcode.1);
|
||||
let args = &opcode.1;
|
||||
|
||||
let var: AssignedCell<Fp, Fp> = stack[args[0].1].clone().into();
|
||||
let var: AssignedCell<Fp, Fp> = heap[args[0].1].clone().into();
|
||||
|
||||
layouter.constrain_instance(
|
||||
var.cell(),
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
//! VM stack type abstractions
|
||||
//! VM heap type abstractions
|
||||
use darkfi_sdk::crypto::{constants::OrchardFixedBases, MerkleNode};
|
||||
use halo2_gadgets::ecc::{
|
||||
chip::EccChip, FixedPoint, FixedPointBaseField, FixedPointShort, NonIdentityPoint, Point,
|
||||
@@ -71,7 +71,7 @@ pub fn empty_witnesses(zkbin: &ZkBinary) -> Vec<Witness> {
|
||||
/// These represent the witness types inside the circuit
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum StackVar {
|
||||
pub enum HeapVar {
|
||||
EcPoint(Point<pallas::Affine, EccChip<OrchardFixedBases>>),
|
||||
EcNiPoint(NonIdentityPoint<pallas::Affine, EccChip<OrchardFixedBases>>),
|
||||
EcFixedPoint(FixedPoint<pallas::Affine, EccChip<OrchardFixedBases>>),
|
||||
@@ -87,10 +87,10 @@ pub enum StackVar {
|
||||
// TODO: Make this not panic (try_from)
|
||||
macro_rules! impl_from {
|
||||
($variant:ident, $fortype:ty) => {
|
||||
impl From<StackVar> for $fortype {
|
||||
fn from(value: StackVar) -> Self {
|
||||
impl From<HeapVar> for $fortype {
|
||||
fn from(value: HeapVar) -> Self {
|
||||
match value {
|
||||
StackVar::$variant(v) => v,
|
||||
HeapVar::$variant(v) => v,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
@@ -32,7 +32,7 @@ pub struct Analyzer {
|
||||
pub witnesses: Vec<Witness>,
|
||||
pub statements: Vec<Statement>,
|
||||
pub literals: Vec<Literal>,
|
||||
pub stack: Vec<Variable>,
|
||||
pub heap: Vec<Variable>,
|
||||
error: ErrorEmitter,
|
||||
}
|
||||
|
||||
@@ -49,15 +49,15 @@ impl Analyzer {
|
||||
let lines: Vec<String> = source.as_str().lines().map(|x| x.to_string()).collect();
|
||||
let error = ErrorEmitter::new("Semantic", filename, lines);
|
||||
|
||||
Self { constants, witnesses, statements, literals: vec![], stack: vec![], error }
|
||||
Self { constants, witnesses, statements, literals: vec![], heap: vec![], error }
|
||||
}
|
||||
|
||||
pub fn analyze_types(&mut self) {
|
||||
// To work around the pedantic safety, we'll make new vectors and then
|
||||
// replace the `statements` and `stack` vectors from the `Analyzer`
|
||||
// replace the `statements` and `heap` vectors from the `Analyzer`
|
||||
// object when we are done.
|
||||
let mut statements = vec![];
|
||||
let mut stack = vec![];
|
||||
let mut heap = vec![];
|
||||
|
||||
for statement in &self.statements {
|
||||
//println!("{:?}", statement);
|
||||
@@ -120,7 +120,7 @@ impl Analyzer {
|
||||
// convert it to another statement that will get executed
|
||||
// before this one. An important assumption is that this
|
||||
// opcode has a return value. When executed we will push
|
||||
// this value onto the stack and use it as a reference to
|
||||
// this value onto the heap and use it as a reference to
|
||||
// the actual statement we're parsing at this moment.
|
||||
// TODO: FIXME: This needs a recursive algorithm, as this
|
||||
// only allows a single nested function.
|
||||
@@ -238,16 +238,16 @@ impl Analyzer {
|
||||
// Add this to the list of statements.
|
||||
statements.push(s);
|
||||
|
||||
// We replace self.stack here so we can do proper stack lookups.
|
||||
stack.push(v.clone());
|
||||
self.stack = stack.clone();
|
||||
// We replace self.heap here so we can do proper heap lookups.
|
||||
heap.push(v.clone());
|
||||
self.heap = heap.clone();
|
||||
|
||||
//println!("{:#?}", stack);
|
||||
//println!("{:#?}", heap);
|
||||
//println!("{:#?}", statements);
|
||||
continue
|
||||
} // <-- Arg::Func
|
||||
|
||||
// The literals get pushed on their own "stack", and
|
||||
// The literals get pushed on their own "heap", and
|
||||
// then the compiler will reference them by their own
|
||||
// index when it comes to running the statement that
|
||||
// requires the literal type.
|
||||
@@ -336,27 +336,27 @@ impl Analyzer {
|
||||
stmt.rhs = rhs;
|
||||
|
||||
// In case this statement is an assignment, we will push its
|
||||
// result on the stack.
|
||||
// result on the heap.
|
||||
if statement.typ == StatementType::Assign {
|
||||
let mut var = statement.lhs.clone().unwrap();
|
||||
var.typ = return_types[0];
|
||||
stmt.lhs = Some(var.clone());
|
||||
stack.push(var.clone());
|
||||
self.stack = stack.clone();
|
||||
heap.push(var.clone());
|
||||
self.heap = heap.clone();
|
||||
}
|
||||
|
||||
//println!("{:#?}", stmt);
|
||||
statements.push(stmt);
|
||||
} // <-- for statement in &self.statements
|
||||
|
||||
// Here we replace the self.statements and self.stack with what we
|
||||
// Here we replace the self.statements and self.heap with what we
|
||||
// built so far. These can be used later on by the compiler after
|
||||
// this function is finished.
|
||||
self.statements = statements;
|
||||
self.stack = stack;
|
||||
self.heap = heap;
|
||||
|
||||
//println!("=================STATEMENTS===============\n{:#?}", self.statements);
|
||||
//println!("===================STACK==================\n{:#?}", self.stack);
|
||||
//println!("====================HEAP==================\n{:#?}", self.heap);
|
||||
//println!("==================LITERALS================\n{:#?}", self.literals);
|
||||
}
|
||||
|
||||
@@ -369,7 +369,7 @@ impl Analyzer {
|
||||
return Some(Var::Witness(r))
|
||||
}
|
||||
|
||||
if let Some(r) = self.lookup_stack(name) {
|
||||
if let Some(r) = self.lookup_heap(name) {
|
||||
return Some(Var::Variable(r))
|
||||
}
|
||||
|
||||
@@ -396,8 +396,8 @@ impl Analyzer {
|
||||
None
|
||||
}
|
||||
|
||||
fn lookup_stack(&self, name: &str) -> Option<Variable> {
|
||||
for i in &self.stack {
|
||||
fn lookup_heap(&self, name: &str) -> Option<Variable> {
|
||||
for i in &self.heap {
|
||||
if i.name == name {
|
||||
return Some(i.clone())
|
||||
}
|
||||
@@ -407,22 +407,22 @@ impl Analyzer {
|
||||
}
|
||||
|
||||
pub fn analyze_semantic(&mut self) {
|
||||
let mut stack = vec![];
|
||||
let mut heap = vec![];
|
||||
|
||||
println!("Loading constants...\n-----");
|
||||
for i in &self.constants {
|
||||
println!("Adding `{}` to stack", i.name);
|
||||
stack.push(&i.name);
|
||||
println!("Adding `{}` to heap", i.name);
|
||||
heap.push(&i.name);
|
||||
Analyzer::pause();
|
||||
}
|
||||
println!("Stack:\n{:#?}\n-----", stack);
|
||||
println!("Heap:\n{:#?}\n-----", heap);
|
||||
println!("Loading witnesses...\n-----");
|
||||
for i in &self.witnesses {
|
||||
println!("Adding `{}` to stack", i.name);
|
||||
stack.push(&i.name);
|
||||
println!("Adding `{}` to heap", i.name);
|
||||
heap.push(&i.name);
|
||||
Analyzer::pause();
|
||||
}
|
||||
println!("Stack:\n{:#?}\n-----", stack);
|
||||
println!("Heap:\n{:#?}\n-----", heap);
|
||||
println!("Loading circuit...");
|
||||
for i in &self.statements {
|
||||
let mut argnames = vec![];
|
||||
@@ -441,12 +441,12 @@ impl Analyzer {
|
||||
|
||||
for arg in &i.rhs {
|
||||
if let Arg::Var(arg) = arg {
|
||||
print!("Looking up `{}` on the stack... ", arg.name);
|
||||
if let Some(index) = stack.iter().position(|&r| r == &arg.name) {
|
||||
println!("Found at stack index {}", index);
|
||||
print!("Looking up `{}` on the heap... ", arg.name);
|
||||
if let Some(index) = heap.iter().position(|&r| r == &arg.name) {
|
||||
println!("Found at heap index {}", index);
|
||||
} else {
|
||||
self.error.abort(
|
||||
&format!("Could not find `{}` on the stack", arg.name),
|
||||
&format!("Could not find `{}` on the heap", arg.name),
|
||||
arg.line,
|
||||
arg.column,
|
||||
);
|
||||
@@ -462,9 +462,9 @@ impl Analyzer {
|
||||
}
|
||||
match i.typ {
|
||||
StatementType::Assign => {
|
||||
println!("Pushing result as `{}` to stack", &i.lhs.as_ref().unwrap().name);
|
||||
stack.push(&i.lhs.as_ref().unwrap().name);
|
||||
println!("Stack:\n{:#?}\n-----", stack);
|
||||
println!("Pushing result as `{}` to heap", &i.lhs.as_ref().unwrap().name);
|
||||
heap.push(&i.lhs.as_ref().unwrap().name);
|
||||
println!("Heap:\n{:#?}\n-----", heap);
|
||||
}
|
||||
StatementType::Call => {
|
||||
println!("-----");
|
||||
|
||||
@@ -23,7 +23,7 @@ use darkfi_serial::{serialize, VarInt};
|
||||
use super::{
|
||||
ast::{Arg, Constant, Literal, Statement, StatementType, Witness},
|
||||
error::ErrorEmitter,
|
||||
types::StackType,
|
||||
types::HeapType,
|
||||
};
|
||||
|
||||
/// Version of the binary
|
||||
@@ -71,40 +71,40 @@ impl Compiler {
|
||||
// Write the circuit's namespace
|
||||
bincode.extend_from_slice(&serialize(&self.namespace));
|
||||
|
||||
// Temporaty stack vector for lookups
|
||||
let mut tmp_stack = vec![];
|
||||
// Temporary heap vector for lookups
|
||||
let mut tmp_heap = vec![];
|
||||
|
||||
// In the .constant section of the binary, we write the constant's type,
|
||||
// and the name so the VM can look it up from `src/crypto/constants/`.
|
||||
bincode.extend_from_slice(b".constant");
|
||||
for i in &self.constants {
|
||||
tmp_stack.push(i.name.as_str());
|
||||
tmp_heap.push(i.name.as_str());
|
||||
bincode.push(i.typ as u8);
|
||||
bincode.extend_from_slice(&serialize(&i.name));
|
||||
}
|
||||
|
||||
// Currently, our literals are only Uint64 types, in the binary we'll
|
||||
// add them here in the .literal section. In the VM, they will be on
|
||||
// their own stack, used for reference by opcodes.
|
||||
// their own heap, used for reference by opcodes.
|
||||
bincode.extend_from_slice(b".literal");
|
||||
for i in &self.literals {
|
||||
bincode.push(i.typ as u8);
|
||||
bincode.extend_from_slice(&serialize(&i.name));
|
||||
}
|
||||
|
||||
// In the .witness section, we write all our witness types, on the stack
|
||||
// In the .witness section, we write all our witness types, on the heap
|
||||
// they're in order of appearance.
|
||||
bincode.extend_from_slice(b".witness");
|
||||
for i in &self.witnesses {
|
||||
tmp_stack.push(i.name.as_str());
|
||||
tmp_heap.push(i.name.as_str());
|
||||
bincode.push(i.typ as u8);
|
||||
}
|
||||
|
||||
bincode.extend_from_slice(b".circuit");
|
||||
for i in &self.statements {
|
||||
match i.typ {
|
||||
StatementType::Assign => tmp_stack.push(&i.lhs.as_ref().unwrap().name),
|
||||
// In case of a simple call, we don't append anything to the stack
|
||||
StatementType::Assign => tmp_heap.push(&i.lhs.as_ref().unwrap().name),
|
||||
// In case of a simple call, we don't append anything to the heap
|
||||
StatementType::Call => {}
|
||||
// TODO: FIXME: unreachable is reached with missing semicolons in the code
|
||||
_ => unreachable!(),
|
||||
@@ -116,21 +116,21 @@ impl Compiler {
|
||||
for arg in &i.rhs {
|
||||
match arg {
|
||||
Arg::Var(arg) => {
|
||||
if let Some(found) = Compiler::lookup_stack(&tmp_stack, &arg.name) {
|
||||
bincode.push(StackType::Var as u8);
|
||||
if let Some(found) = Compiler::lookup_heap(&tmp_heap, &arg.name) {
|
||||
bincode.push(HeapType::Var as u8);
|
||||
bincode.extend_from_slice(&serialize(&VarInt(found as u64)));
|
||||
continue
|
||||
}
|
||||
|
||||
self.error.abort(
|
||||
&format!("Failed finding a stack reference for `{}`", arg.name),
|
||||
&format!("Failed finding a heap reference for `{}`", arg.name),
|
||||
arg.line,
|
||||
arg.column,
|
||||
);
|
||||
}
|
||||
Arg::Lit(lit) => {
|
||||
if let Some(found) = Compiler::lookup_literal(&self.literals, &lit.name) {
|
||||
bincode.push(StackType::Lit as u8);
|
||||
bincode.push(HeapType::Lit as u8);
|
||||
bincode.extend_from_slice(&serialize(&VarInt(found as u64)));
|
||||
continue
|
||||
}
|
||||
@@ -156,8 +156,8 @@ impl Compiler {
|
||||
bincode
|
||||
}
|
||||
|
||||
fn lookup_stack(stack: &[&str], name: &str) -> Option<usize> {
|
||||
for (idx, n) in stack.iter().enumerate() {
|
||||
fn lookup_heap(heap: &[&str], name: &str) -> Option<usize> {
|
||||
for (idx, n) in heap.iter().enumerate() {
|
||||
if n == &name {
|
||||
return Some(idx)
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
use darkfi_serial::{deserialize_partial, VarInt};
|
||||
|
||||
use super::{compiler::MAGIC_BYTES, types::StackType, LitType, Opcode, VarType};
|
||||
use super::{compiler::MAGIC_BYTES, types::HeapType, LitType, Opcode, VarType};
|
||||
use crate::{Error::ZkasDecoderError as ZkasErr, Result};
|
||||
|
||||
/// A ZkBinary decoded from compiled zkas code.
|
||||
@@ -29,7 +29,7 @@ pub struct ZkBinary {
|
||||
pub constants: Vec<(VarType, String)>,
|
||||
pub literals: Vec<(LitType, String)>,
|
||||
pub witnesses: Vec<VarType>,
|
||||
pub opcodes: Vec<(Opcode, Vec<(StackType, usize)>)>,
|
||||
pub opcodes: Vec<(Opcode, Vec<(HeapType, usize)>)>,
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/questions/35901547/how-can-i-find-a-subsequence-in-a-u8-slice
|
||||
@@ -177,7 +177,7 @@ impl ZkBinary {
|
||||
}
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
fn parse_circuit(bytes: &[u8]) -> Result<Vec<(Opcode, Vec<(StackType, usize)>)>> {
|
||||
fn parse_circuit(bytes: &[u8]) -> Result<Vec<(Opcode, Vec<(HeapType, usize)>)>> {
|
||||
let mut opcodes = vec![];
|
||||
|
||||
let mut iter_offset = 0;
|
||||
@@ -198,20 +198,17 @@ impl ZkBinary {
|
||||
|
||||
let mut args = vec![];
|
||||
for _ in 0..arg_num.0 {
|
||||
let stack_type = bytes[iter_offset];
|
||||
let heap_type = bytes[iter_offset];
|
||||
iter_offset += 1;
|
||||
let (stack_index, offset) = deserialize_partial::<VarInt>(&bytes[iter_offset..])?;
|
||||
let (heap_index, offset) = deserialize_partial::<VarInt>(&bytes[iter_offset..])?;
|
||||
iter_offset += offset;
|
||||
let stack_type = match StackType::from_repr(stack_type) {
|
||||
let heap_type = match HeapType::from_repr(heap_type) {
|
||||
Some(v) => v,
|
||||
None => {
|
||||
return Err(ZkasErr(format!(
|
||||
"Could not decode StackType from {}",
|
||||
stack_type
|
||||
)))
|
||||
return Err(ZkasErr(format!("Could not decode HeapType from {}", heap_type)))
|
||||
}
|
||||
};
|
||||
args.push((stack_type, stack_index.0 as usize)); // FIXME, why?
|
||||
args.push((heap_type, heap_index.0 as usize)); // FIXME, why?
|
||||
}
|
||||
|
||||
opcodes.push((opcode, args));
|
||||
|
||||
@@ -263,7 +263,7 @@ impl Parser {
|
||||
// Grab tokens for each statement
|
||||
for i in circuit_tokens[2..circuit_tokens.len() - 1].iter() {
|
||||
if i.token_type == TokenType::Semicolon {
|
||||
// Push completed statement to the stack
|
||||
// Push completed statement to the heap
|
||||
circuit_stmts.push(circuit_stmt.clone());
|
||||
circuit_stmt = vec![];
|
||||
continue
|
||||
@@ -610,7 +610,7 @@ impl Parser {
|
||||
//
|
||||
// constrain_instance(ec_get_x(token_commit));
|
||||
//
|
||||
// The inner call's result would still get pushed on the stack,
|
||||
// The inner call's result would still get pushed on the heap,
|
||||
// but it will not be accessible in any other scope.
|
||||
//
|
||||
// In certain opcodes, we also support literal types, and the
|
||||
@@ -620,7 +620,7 @@ impl Parser {
|
||||
// zero = witness_base(0);
|
||||
//
|
||||
// The literal type is used only in the function call's scope, but
|
||||
// the result is then accessible on the stack to be used by further
|
||||
// the result is then accessible on the heap to be used by further
|
||||
// computation.
|
||||
//
|
||||
// Regarding multiple return values from opcodes, this is perhaps
|
||||
@@ -788,7 +788,7 @@ impl Parser {
|
||||
// Recurse this function to get the params of the nested one.
|
||||
let args = self.parse_function_call(arg, iter);
|
||||
|
||||
// Then we assign a "fake" variable that serves as a stack
|
||||
// Then we assign a "fake" variable that serves as a heap
|
||||
// reference.
|
||||
let var = Variable {
|
||||
name: format!("_op_inner_{}_{}", arg.line, arg.column),
|
||||
|
||||
@@ -16,15 +16,15 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/// Stack types in bincode & vm
|
||||
/// Heap types in bincode & vm
|
||||
#[derive(Clone, Debug)]
|
||||
#[repr(u8)]
|
||||
pub enum StackType {
|
||||
pub enum HeapType {
|
||||
Var = 0x00,
|
||||
Lit = 0x01,
|
||||
}
|
||||
|
||||
impl StackType {
|
||||
impl HeapType {
|
||||
pub fn from_repr(b: u8) -> Option<Self> {
|
||||
match b {
|
||||
0x00 => Some(Self::Var),
|
||||
|
||||
@@ -36,7 +36,7 @@ use darkfi::{
|
||||
zk::{
|
||||
proof::{ProvingKey, VerifyingKey},
|
||||
vm::ZkCircuit,
|
||||
vm_stack::{empty_witnesses, Witness},
|
||||
vm_heap::{empty_witnesses, Witness},
|
||||
Proof,
|
||||
},
|
||||
zkas::ZkBinary,
|
||||
|
||||
@@ -36,7 +36,7 @@ use darkfi::{
|
||||
zk::{
|
||||
proof::{ProvingKey, VerifyingKey},
|
||||
vm::ZkCircuit,
|
||||
vm_stack::{empty_witnesses, Witness},
|
||||
vm_heap::{empty_witnesses, Witness},
|
||||
Proof,
|
||||
},
|
||||
zkas::ZkBinary,
|
||||
|
||||
Reference in New Issue
Block a user