Hints / Unconstrained Input #607
Replies: 7 comments 31 replies
-
Update (will fold into the main text later): The above is meant mostly for private IO. But the special memory region we have is for public io. So we'd want to add one for private IO, too. We can in principle use the same idea for public input, but we probably want to Merkle-ize that by default. The guest interface might look similar, but it would be rather different under the hood. |
Beta Was this translation helpful? Give feedback.
-
looks good for me. Just have one question: will there be a preset max total length of all unconstrained input? or as long as len(mem_map_io_region) + len(runtime_mem) <= mem_limit it is ok? |
Beta Was this translation helpful? Give feedback.
-
If I want to alloc |
Beta Was this translation helpful? Give feedback.
-
Have a question regarding e.g. read number of round in let round = sp1_zkvm::io::read::<u32>();
sp1_zkvm::io::commit::<u32>(&round); Does it means that |
Beta Was this translation helpful? Give feedback.
-
@kunxian-xia and me had a fruitful discussion about the approach outlined above that uses a prover initialised read-only memory region versus SP1's approach that mixes hints in with general read-write memory, but requires two system calls ( In SP1's system, if you want a 'hint' you first call Well, strictly speaking what I described above is enough to make the scheme work. But to make coordination between guest and host program simpler, SP1 has the (A host program that knows its guest program well enough, could do without Our VM is different: our circuits guarantee that general read-write memory that our Rust allocator has access to comes zeroed out from the factory. On the downside, that means we need an extra memory region for the prover to leave hints in. But we get (at least) two upsides:
|
Beta Was this translation helpful? Give feedback.
-
See #627 for public input / 'commit'. |
Beta Was this translation helpful? Give feedback.
-
@hero78119 See #631 for the same code that's on the branch, but easier to view all the changes at once. |
Beta Was this translation helpful? Give feedback.
-
This is an elaboration on #551
Guest's points of view
Inspired by SP1, we will give guests two functions to read unconstrained input (also knows as hints). The first is
read
, which reads in a value of a given type. The second isread_slice
, which reads in a byte array.There are two main differences to SP1:
rkyv
instead ofbincode
. That's becauserkyv
is a lot faster, and we are already using it insproll
. The bounds onT
inread
reflect that.rkyv
is zero-copy, and we want to take advantage of that.Just like in SP1, the host has two corresponding functions to create that input:
write
andwrite_slice
. From the user's point of view, they work exactly like you imagine they would.Under the hood
Like in SP1, the typed
read
is implemented inside the guest on top ofread_slice
: it's just a wrapper that deals with deserialisation for you. In SP1 it's implemented exactly how you'd expect. The same for us:read_slice
is a bit more involved:At the start of the memory-mapped region for hints we store information that lets us find the byte slice for each of the items we want to read. We keep a mutable index to the next item to read, and we increment it each time
read_slice
is called. We then return the byte slice for that item.Another technical note: in general our memory-mapped-io region will be larger than the buffer
rkvy
needs for its serialised data. In that case, we will conceptually add arbitrary padding (eg all zeroes) to the end of the buffer.Our design assumes that the memory-mapped-io region is read-only. That's a good idea for both performance and security anyway, but we can also tweak the design slightly to support read-write backing storage.
See #631 for a prototype implementation.
Beta Was this translation helpful? Give feedback.
All reactions