fn verify_single_update_proof()

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)
}