in akd/src/client.rs [187:331]
fn verify_single_update_proof<H: Hasher>(
root_hash: H::Digest,
vrf_pk: &VRFPublicKey,
previous_root_hash: Option<H::Digest>,
proof: UpdateProof<H>,
uname: &AkdLabel,
allow_tombstones: bool,
) -> Result<bool, AkdError> {
let epoch = proof.epoch;
let version = proof.version;
let existence_vrf_proof = proof.existence_vrf_proof;
let existence_at_ep_ref = &proof.existence_at_ep;
let existence_at_ep = existence_at_ep_ref;
let existence_at_ep_label = existence_at_ep_ref.label;
let previous_val_stale_at_ep = &proof.previous_val_stale_at_ep;
let non_existence_before_ep = &proof.non_existence_before_ep;
let (is_tombstone, value_hash_valid) = match (allow_tombstones, &proof.plaintext_value) {
(true, bytes) if bytes.0 == crate::TOMBSTONE => {
// A tombstone was encountered, we need to just take the
// hash of the value at "face value" since we don't have
// the real value available
(true, true)
}
(_, bytes) => {
// No tombstone so hash the value found, and compare to the existence proof's value
(
false,
hash_plaintext_value::<H>(bytes, &proof.commitment_proof)
== existence_at_ep.hash_val,
)
}
};
if !value_hash_valid {
return Err(AkdError::Directory(DirectoryError::VerifyKeyHistoryProof(
format!("Hash of plaintext value (v: {}) did not match expected hash in existence proof at epoch {}", version, epoch),
)));
}
// ***** PART 1 ***************************
// Verify the VRF and membership proof for the corresponding label for the version being updated to.
vrf_pk.verify_label::<H>(
uname,
false,
version,
&existence_vrf_proof,
existence_at_ep_label,
)?;
verify_membership(root_hash, existence_at_ep)?;
// ***** PART 2 ***************************
// Edge case here! We need to account for version = 1 where the previous version won't have a proof.
if version > 1 {
// Verify the membership proof the for stale label of the previous version
let err_str = format!(
"Staleness proof of user {:?}'s version {:?} at epoch {:?} is None",
uname,
(version - 1),
epoch
);
let previous_null_err = AkdError::Directory(DirectoryError::VerifyKeyHistoryProof(err_str));
let previous_val_stale_at_ep =
previous_val_stale_at_ep.as_ref().ok_or(previous_null_err)?;
verify_membership(root_hash, previous_val_stale_at_ep)?;
let vrf_err_str = format!(
"Staleness proof of user {:?}'s version {:?} at epoch {:?} is None",
uname,
(version - 1),
epoch
);
// Verify the VRF for the stale label corresponding to the previous version for this username
let vrf_previous_null_err =
AkdError::Directory(DirectoryError::VerifyKeyHistoryProof(vrf_err_str));
let previous_val_vrf_proof = proof
.previous_val_vrf_proof
.as_ref()
.ok_or(vrf_previous_null_err)?;
vrf_pk.verify_label::<H>(
uname,
true,
version - 1,
previous_val_vrf_proof,
previous_val_stale_at_ep.label,
)?;
}
// ***** PART 3 ***************************
// Verify that the current version was only added in this epoch and didn't exist before.
if epoch > 1 {
let root_hash = previous_root_hash.ok_or(AzksError::NoEpochGiven)?;
verify_nonmembership(
root_hash,
non_existence_before_ep.as_ref().ok_or_else(|| AkdError::Directory(DirectoryError::VerifyKeyHistoryProof(format!(
"Non-existence before this epoch proof of user {:?}'s version {:?} at epoch {:?} is None",
uname,
version,
epoch
))))?
)?;
}
// Get the least and greatest marker entries for the current version
let next_marker = get_marker_version(version) + 1;
let final_marker = get_marker_version(epoch);
// ***** PART 4 ***************************
// Verify the VRFs and non-membership of future entries, up to the next marker
for (i, ver) in (version + 1..(1 << next_marker)).enumerate() {
let pf = &proof.non_existence_of_next_few[i];
let vrf_pf = &proof.next_few_vrf_proofs[i];
let ver_label = pf.label;
vrf_pk.verify_label::<H>(uname, false, ver, vrf_pf, ver_label)?;
if !verify_nonmembership(root_hash, pf)? {
return Err(AkdError::Directory(
DirectoryError::VerifyKeyHistoryProof(
format!("Non-existence before epoch proof of user {:?}'s version {:?} at epoch {:?} does not verify",
uname, ver, epoch-1))));
}
}
// ***** PART 5 ***************************
// Verify the VRFs and non-membership proofs for future markers
for (i, pow) in (next_marker + 1..final_marker).enumerate() {
let ver = 1 << pow;
let pf = &proof.non_existence_of_future_markers[i];
let vrf_pf = &proof.future_marker_vrf_proofs[i];
let ver_label = pf.label;
vrf_pk.verify_label::<H>(uname, false, ver, vrf_pf, ver_label)?;
if !verify_nonmembership(root_hash, pf)? {
return Err(AkdError::Directory(
DirectoryError::VerifyKeyHistoryProof(
format!("Non-existence before epoch proof of user {:?}'s version {:?} at epoch {:?} does not verify",
uname, ver, epoch-1))));
}
}
// return indicator of if the value <=> hash mapping was verified
// or if the hash was simply taken at face-value. True = hash mapping verified
Ok(is_tombstone)
}