Skip to content

feat: enforce semantics for Write Once Memory (WOM) #1560

@DavePearce

Description

@DavePearce

Summary

The semantics of a "write once memory" are exactly what it says on the tin. You cannot write more than once to the same address in a WOM. Attempting to do this should result in a machine panic. But, currently, the ZkC interpreter does not prevent this and allows invalid executions to continue.

Example

The following ZkC program is invalid and should result in a machine panic:

output out(address:u16) -> (byte:u8)

fn main(){
   out[0] = 1
   out[0] = 2 // <-- INVALID
}

With the following json input file:

{}

Then, currently, running this program gives the following:

> zkc exec test.json test.zkc
out = 0x02

Clearly, this violates the intended semantics of a "write once memory".

Approach

Let's consider two example programs:

Program A:

output out(address:u16) -> (byte:u8)

fn main(){
   out[0] = 1
   out[1] = 2 
}

Program B:

output out(address:u16) -> (byte:u8)

fn main(){
   out[1] = 2
   out[0] = 1 

The implementation for write-only memory lives in pkg/zkc/vm/internal/memory/wom.go. There are two different ways this implementation could be updated to enforce a write-once semantics:

  1. (strict) This approach requires every write to an output memory is for the next consecutive address. This would mean that "Program A" above is valid, but "Program B" is not.
  2. (non-strict) This approach is more relaxed and simply requires that writes to the same address with different values result are not permitted.

The difference between these two approaches comes down to the complexity of enforcing their semantics. Basically, option (1) is easier to implement than option (2).

Implementation for Option (1)

In this option, its pretty straightforward. Within our implementation of memory.WriteOnce we simply check that the write address matches the current size of the data array and, if not, cause a machine panic.

Implementation for Option (2)

This is harder to implement, but of course gives rise to more flexible implementations for constructing output. Its not clear whether this flexibility is needed or not. The rough idea would be this: alongside the existing data array we additionally maintain an written []bool array of the same size. This identifies addresses which have already been written. Thus, when a write occurs at address, we check whether written[address]==true or not. If it does, we issue a machine panic.

Metadata

Metadata

Assignees

Labels

constraintsIssues directly related to constraint generation.zkcIssues related to ZkC language

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions