diff --git a/src/lem/circuit.rs b/src/lem/circuit.rs index 97088c7b0e..5e17e075ff 100644 --- a/src/lem/circuit.rs +++ b/src/lem/circuit.rs @@ -235,57 +235,39 @@ pub(crate) fn allocate_slot>( // Allocate the preimage because the image depends on it let mut preallocated_preimg = Vec::with_capacity(slot_type.preimg_size()); - - match slot_data { - SlotData::PtrVec(ptr_vec) => { - let mut component_idx = 0; - for ptr in ptr_vec { + slot_data + .vals + .iter() + .enumerate() + .for_each(|(component_idx, val)| match val { + Val::Pointer(ptr) => { let z_ptr = store.hash_ptr(ptr); - // allocate pointer tag preallocated_preimg.push(AllocatedNum::alloc_infallible( - cs.namespace(|| format!("component {component_idx} slot {slot}")), + cs.namespace(|| format!("component {component_idx} tag slot {slot}")), || z_ptr.tag_field(), )); - - component_idx += 1; - // allocate pointer hash preallocated_preimg.push(AllocatedNum::alloc_infallible( - cs.namespace(|| format!("component {component_idx} slot {slot}")), + cs.namespace(|| format!("component {component_idx} hash slot {slot}")), || *z_ptr.value(), )); - - component_idx += 1; } - } - SlotData::FPtr(f, ptr) => { - let f = store.expect_f(*f); - let z_ptr = store.hash_ptr(ptr); - // allocate first component - preallocated_preimg.push(AllocatedNum::alloc_infallible( - cs.namespace(|| format!("component 0 slot {slot}")), - || *f, - )); - // allocate second component - preallocated_preimg.push(AllocatedNum::alloc_infallible( - cs.namespace(|| format!("component 1 slot {slot}")), - || z_ptr.tag_field(), - )); - // allocate third component - preallocated_preimg.push(AllocatedNum::alloc_infallible( - cs.namespace(|| format!("component 2 slot {slot}")), - || *z_ptr.value(), - )); - } - SlotData::F(a) => { - let a = store.expect_f(*a); - preallocated_preimg.push(AllocatedNum::alloc_infallible( - cs.namespace(|| format!("component 0 slot {slot}")), - || *a, - )); - } - } + Val::Num(f) => { + let f = store.expect_f(*f); + preallocated_preimg.push(AllocatedNum::alloc_infallible( + cs.namespace(|| format!("component {component_idx} slot {slot}")), + || *f, + )); + } + Val::Boolean(b) => { + let f = if *b { F::ONE } else { F::ZERO }; + preallocated_preimg.push(AllocatedNum::alloc_infallible( + cs.namespace(|| format!("component {component_idx} slot {slot}")), + || f, + )); + } + }); // Allocate the image by calling the arithmetic function according // to the slot type diff --git a/src/lem/interpreter.rs b/src/lem/interpreter.rs index d887b4bcda..d94a65a886 100644 --- a/src/lem/interpreter.rs +++ b/src/lem/interpreter.rs @@ -2,8 +2,12 @@ use anyhow::{anyhow, bail, Result}; use std::collections::VecDeque; use super::{ - path::Path, pointers::Ptr, slot::SlotData, store::Store, var_map::VarMap, Block, Ctrl, Func, - Op, Tag, Var, + path::Path, + pointers::Ptr, + slot::{SlotData, Val}, + store::Store, + var_map::VarMap, + Block, Ctrl, Func, Op, Tag, Var, }; use crate::{ @@ -15,12 +19,6 @@ use crate::{ tag::ExprTag::{Comm, Num, Sym}, }; -#[derive(Clone)] -pub enum Val { - Pointer(Ptr), - Boolean(bool), -} - impl VarMap { fn get_many_ptr(&self, args: &[Var]) -> Result> { args.iter().map(|arg| self.get_ptr(arg)).collect() @@ -301,15 +299,15 @@ impl Block { let f = *store.expect_f(f_idx); let g = *store.expect_f(g_idx); let diff = f - g; - hints - .bit_decomp - .push(Some(SlotData::F(store.intern_f(f + f).0))); - hints - .bit_decomp - .push(Some(SlotData::F(store.intern_f(g + g).0))); - hints - .bit_decomp - .push(Some(SlotData::F(store.intern_f(diff + diff).0))); + hints.bit_decomp.push(Some(SlotData { + vals: vec![Val::Num(store.intern_f(f + f).0)], + })); + hints.bit_decomp.push(Some(SlotData { + vals: vec![Val::Num(store.intern_f(g + g).0)], + })); + hints.bit_decomp.push(Some(SlotData { + vals: vec![Val::Num(store.intern_f(diff + diff).0)], + })); let f = BaseNum::Scalar(f); let g = BaseNum::Scalar(g); f < g @@ -323,7 +321,9 @@ impl Block { let a = bindings.get_ptr(a)?; let c = if let Ptr::Atom(_, f_idx) = a { let f = *store.expect_f(f_idx); - hints.bit_decomp.push(Some(SlotData::F(f_idx))); + hints.bit_decomp.push(Some(SlotData { + vals: vec![Val::Num(f_idx)], + })); let b = if *n < 64 { (1 << *n) - 1 } else { u64::MAX }; store.intern_atom(Tag::Expr(Num), F::from_u64(f.to_u64_unchecked() & b)) } else { @@ -360,14 +360,16 @@ impl Block { let preimg_ptrs = bindings.get_many_ptr(preimg)?; let tgt_ptr = store.intern_2_ptrs(*tag, preimg_ptrs[0], preimg_ptrs[1]); bindings.insert_ptr(img.clone(), tgt_ptr); - hints.hash4.push(Some(SlotData::PtrVec(preimg_ptrs))); + let vals = preimg_ptrs.into_iter().map(Val::Pointer).collect(); + hints.hash4.push(Some(SlotData { vals })); } Op::Cons3(img, tag, preimg) => { let preimg_ptrs = bindings.get_many_ptr(preimg)?; let tgt_ptr = store.intern_3_ptrs(*tag, preimg_ptrs[0], preimg_ptrs[1], preimg_ptrs[2]); bindings.insert_ptr(img.clone(), tgt_ptr); - hints.hash6.push(Some(SlotData::PtrVec(preimg_ptrs))); + let vals = preimg_ptrs.into_iter().map(Val::Pointer).collect(); + hints.hash6.push(Some(SlotData { vals })); } Op::Cons4(img, tag, preimg) => { let preimg_ptrs = bindings.get_many_ptr(preimg)?; @@ -379,7 +381,8 @@ impl Block { preimg_ptrs[3], ); bindings.insert_ptr(img.clone(), tgt_ptr); - hints.hash8.push(Some(SlotData::PtrVec(preimg_ptrs))); + let vals = preimg_ptrs.into_iter().map(Val::Pointer).collect(); + hints.hash8.push(Some(SlotData { vals })); } Op::Decons2(preimg, img) => { let img_ptr = bindings.get_ptr(img)?; @@ -393,9 +396,8 @@ impl Block { for (var, ptr) in preimg.iter().zip(preimg_ptrs.iter()) { bindings.insert_ptr(var.clone(), *ptr); } - hints - .hash4 - .push(Some(SlotData::PtrVec(preimg_ptrs.to_vec()))); + let vals = preimg_ptrs.into_iter().map(Val::Pointer).collect(); + hints.hash4.push(Some(SlotData { vals })); } Op::Decons3(preimg, img) => { let img_ptr = bindings.get_ptr(img)?; @@ -409,9 +411,8 @@ impl Block { for (var, ptr) in preimg.iter().zip(preimg_ptrs.iter()) { bindings.insert_ptr(var.clone(), *ptr); } - hints - .hash6 - .push(Some(SlotData::PtrVec(preimg_ptrs.to_vec()))); + let vals = preimg_ptrs.into_iter().map(Val::Pointer).collect(); + hints.hash6.push(Some(SlotData { vals })); } Op::Decons4(preimg, img) => { let img_ptr = bindings.get_ptr(img)?; @@ -425,9 +426,8 @@ impl Block { for (var, ptr) in preimg.iter().zip(preimg_ptrs.iter()) { bindings.insert_ptr(var.clone(), *ptr); } - hints - .hash8 - .push(Some(SlotData::PtrVec(preimg_ptrs.to_vec()))); + let vals = preimg_ptrs.into_iter().map(Val::Pointer).collect(); + hints.hash8.push(Some(SlotData { vals })); } Op::Hide(tgt, sec, src) => { let src_ptr = bindings.get_ptr(src)?; @@ -436,9 +436,8 @@ impl Block { }; let secret = *store.expect_f(secret_idx); let tgt_ptr = store.hide(secret, src_ptr); - hints - .commitment - .push(Some(SlotData::FPtr(secret_idx, src_ptr))); + let vals = vec![Val::Num(secret_idx), Val::Pointer(src_ptr)]; + hints.commitment.push(Some(SlotData { vals })); bindings.insert_ptr(tgt.clone(), tgt_ptr); } Op::Open(tgt_secret, tgt_ptr, comm) => { @@ -455,7 +454,8 @@ impl Block { store.intern_atom(Tag::Expr(Num), secret), ); let secret_idx = store.intern_f(secret).0; - hints.commitment.push(Some(SlotData::FPtr(secret_idx, ptr))) + let vals = vec![Val::Num(secret_idx), Val::Pointer(ptr)]; + hints.commitment.push(Some(SlotData { vals })); } Op::Unit(f) => f(), } diff --git a/src/lem/slot.rs b/src/lem/slot.rs index 477b858345..266688257d 100644 --- a/src/lem/slot.rs +++ b/src/lem/slot.rs @@ -233,16 +233,32 @@ impl Block { } } +#[derive(Clone, Debug)] +/// The values a variable can take. `Num`s are pure field elements, much like `Ptr::Atom`, +/// but missing the tag. `Boolean`s are also field elements, but they are guaranteed to be +/// constrained to take only 0 or 1 values. +pub enum Val { + Pointer(Ptr), + Num(usize), + Boolean(bool), +} + /// Holds data to feed the slots #[derive(Clone, Debug)] -pub enum SlotData { - /// A sequence of pointers, holding hashing preimages - PtrVec(Vec), - /// An element of the finite field (cached in a `Store`) and a `Ptr` for - /// commitments - FPtr(usize, Ptr), - /// An element of the finite field (cached in a `Store`) for bit decompositions - F(usize), +pub struct SlotData { + pub vals: Vec, +} + +impl SlotData { + /// Size of the slot data in number of field elements + pub(crate) fn size(&self) -> usize { + self.vals.iter().fold(0, |acc, val| match val { + // Pointers are tag/hash pairs + Val::Pointer(..) => acc + 2, + // Numbers and booleans are single field elements + Val::Num(..) | Val::Boolean(..) => acc + 1, + }) + } } #[derive(Clone, Copy, PartialEq, Eq, Hash)] @@ -266,14 +282,7 @@ impl SlotType { } pub(crate) fn is_compatible(&self, slot_data: &SlotData) -> bool { - matches!( - (self, slot_data), - (Self::Hash4, SlotData::PtrVec(..)) - | (Self::Hash6, SlotData::PtrVec(..)) - | (Self::Hash8, SlotData::PtrVec(..)) - | (Self::Commitment, SlotData::FPtr(..)) - | (Self::BitDecomp, SlotData::F(..)) - ) + slot_data.size() == self.preimg_size() } }