You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
We currently use the Serialize and Deserialize traits to convert Noir structs to/from arrays of fields. This is done in multiple places, typically to:
read/write a value to public storage
compute the hash of a value
send/recieve values in oracle calls
This is highly problematic because these use cases have radically different tradeoffs. When interacting with storage we want packed representations to minimize DA costs, which are custom and result in extra constraints/gas. Depending on the hash function used, it may similarly be desirable to spend constraints/gas compressing the input to then execute the hash over a smaller array. But when sending or receiving objects via oracles, size is entirely irrelevant: what we want instead is minimal constraints and gas, and to keep the method standard so that it can be replicated by the oracle resolver (PXE in our case).
This is currently causing issues: U128 is internally represented as two Field limbs that store u64s, but when serialized it is converted into a single field (reducing the array length from 2 to 1). However, if one tries to e.g. have a contract function receive a U128, the oracle resolvers will throw runtime errors as they realize the mismatch between the expected TS serialization and the one that is actually done in Noir. Other objects such as ScheduledDelayChange similarly perform tight packing in order to minimize storage requirements - this only works because they don't happen to be exposed to the oracles.
I think a reasonable path forward is to acknowledge these as two different use cases, and to split the serialization implementations. We could keep serialize for things like public storage etc, and have a second set of traits e.g. ToTsArray that must follow the standard serialization algorithm. Functions like pack/unpack would take TsArray wrappers instead of a plain Field array, and we'd detect errors that way. Eventually we could use #[derive] to automatically generate this trait, though I'd argue that manually rolling it out would already provide large benefits today.
The text was updated successfully, but these errors were encountered:
We currently use the
Serialize
andDeserialize
traits to convert Noir structs to/from arrays of fields. This is done in multiple places, typically to:This is highly problematic because these use cases have radically different tradeoffs. When interacting with storage we want packed representations to minimize DA costs, which are custom and result in extra constraints/gas. Depending on the hash function used, it may similarly be desirable to spend constraints/gas compressing the input to then execute the hash over a smaller array. But when sending or receiving objects via oracles, size is entirely irrelevant: what we want instead is minimal constraints and gas, and to keep the method standard so that it can be replicated by the oracle resolver (PXE in our case).
This is currently causing issues:
U128
is internally represented as twoField
limbs that storeu64
s, but when serialized it is converted into a single field (reducing the array length from 2 to 1). However, if one tries to e.g. have a contract function receive aU128
, the oracle resolvers will throw runtime errors as they realize the mismatch between the expected TS serialization and the one that is actually done in Noir. Other objects such asScheduledDelayChange
similarly perform tight packing in order to minimize storage requirements - this only works because they don't happen to be exposed to the oracles.I think a reasonable path forward is to acknowledge these as two different use cases, and to split the serialization implementations. We could keep
serialize
for things like public storage etc, and have a second set of traits e.g.ToTsArray
that must follow the standard serialization algorithm. Functions likepack
/unpack
would takeTsArray
wrappers instead of a plain Field array, and we'd detect errors that way. Eventually we could use#[derive]
to automatically generate this trait, though I'd argue that manually rolling it out would already provide large benefits today.The text was updated successfully, but these errors were encountered: