Skip to content

Commit

Permalink
in mem oracle verify function
Browse files Browse the repository at this point in the history
  • Loading branch information
zobront committed Jun 27, 2024
1 parent eea0485 commit 79cf245
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 0 deletions.
2 changes: 2 additions & 0 deletions zkvm-client/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ fn main() {
let kv_store_bytes: Vec<u8> = sp1_zkvm::io::read_vec();
let oracle = Arc::new(InMemoryOracle::from_raw_bytes(kv_store_bytes));

oracle.verify().expect("key value verification failed");

// If we are compiling for online mode, create a caching oracle that speaks to the
// fetcher via hints, and gather boot info from this oracle.
} else {
Expand Down
117 changes: 117 additions & 0 deletions zkvm-client/src/oracle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,120 @@ impl HintWriterClient for InMemoryOracle {
Ok(())
}
}


#[derive(Default)]
struct Blob {
// TODO: Advantage / disadvantage of using FixedBytes?
commitment: FixedBytes<48>,
// TODO: Import and use Blob type from kona-derive?
data: FixedBytes<4096>,
kzg_proof: FixedBytes<48>,
}

impl InMemoryOracle {
pub fn verify(&self) -> Result<()> {
let mut blobs: HashMap<FixedBytes<48>, Blob> = HashMap::new();

for (key, value) in self.cache.iter() {
match key.key_type() {

// These are public values so verification happens in Solidity.
PreimageKeyType::Local => {
// no-op
},
// Validate that the hash of the value (with keccak key added) equals the key.
PreimageKeyType::Keccak256 => {
let derived_key = PreimageKey::new(keccak256(value).into(), PreimageKeyType::Keccak256);
assert_eq!(*key, derived_key, "zkvm keccak constraint failed!");
},
// Unimplemented.
PreimageKeyType::GlobalGeneric => {
unimplemented!();
},
// Validate that the hash of the value (with sha256 key added) equals the key.
PreimageKeyType::Sha256 => {
let derived_key: [u8; 32] = Sha256::digest(value).into();
// TODO: Confirm we don't need `derived_key[0] = 0x01; // VERSIONED_HASH_VERSION_KZG` because it's overwritten by PreimageKey
let derived_key = PreimageKey::new(derived_key, PreimageKeyType::Sha256);
assert_eq!(*key, derived_key, "zkvm sha256 constraint failed!");
},
// Aggregate blobs and proofs in memory and verify after loop.
PreimageKeyType::Blob => {
let blob_data_key = PreimageKey::new(
<PreimageKey as Into<[u8;32]>>::into(*key),
PreimageKeyType::Keccak256
);

if let Some(blob_data) = self.cache.get(&blob_data_key) {
let commitment: FixedBytes<48> = blob_data[..48].try_into().unwrap();
let element: [u8; 8] = blob_data[72..].try_into().unwrap();
let element: u64 = u64::from_be_bytes(element);

// TODO: This requires upstream kona changes to save these values in L1Blob hint.
if element == 4096 {
// kzg_proof[0..32]
blobs
.entry(commitment)
.or_insert(Blob::default())
.kzg_proof[..32]
.copy_from_slice(value);
continue;
} else if element == 4097 {
// kzg_proof[32..48]
blobs
.entry(commitment)
.or_insert(Blob::default())
.kzg_proof[32..]
.copy_from_slice(&value[..16]);
continue;
}

// Add the 32 bytes of blob data into the correct spot in the blob.
blobs
.entry(commitment)
.or_insert(Blob::default())
.data
.get_mut((element as usize) << 5..(element as usize + 1) << 5)
.map(|slice| {
if slice.iter().all(|&byte| byte == 0) {
slice.copy_from_slice(value);
Ok(())
} else {
return Err(anyhow!("trying to overwrite existing blob data"));
}
});
} else {
return Err(anyhow!("blob data not found"));
}
},
PreimageKeyType::Precompile => {
// Convert the Precompile type to a Keccak type. This is the key to get the hint data.
let hint_data_key = PreimageKey::new(
<PreimageKey as Into<[u8;32]>>::into(*key),
PreimageKeyType::Keccak256
);

// Look up the hint data in the cache. It should always exist, because we only
// set Precompile KV pairs along with Keccak KV pairs for the hint data.
if let Some(hint_data) = self.cache.get(&hint_data_key) {
// Insert validation logic for accelerated precompiles.
} else {
return Err(anyhow!("precompile hint data not found"));
}
}
}
}

// Verify reconstructed blobs.
for (commitment, blob) in blobs.iter() {
// kzg::verify_blob_kzg_proof(&blob.data, commitment, &blob.kzg_proof)
// .map_err(|e| format!("blob verification failed for {:?}: {}", commitment, e))?;

// TODO: Would this allow us to leave 000...000 segments in blobs that were not empty and prove that?
// May need to track to ensure each blob element has been included.
}

Ok(())
}
}

0 comments on commit 79cf245

Please sign in to comment.