fn verify_single_update_proof()

in akd_client/src/verify.rs [229:393]


fn verify_single_update_proof(
    root_hash: Digest,
    vrf_public_key: &[u8],
    previous_root_hash: Option<Digest>,
    proof: UpdateProof,
    uname: &AkdLabel,
    allow_tombstone: bool,
) -> Result<bool, VerificationError> {
    let epoch = proof.epoch;
    let _plaintext_value = &proof.plaintext_value;
    let version = proof.version;

    let existence_at_ep_ref = &proof.existence_at_ep;
    let existence_at_ep = existence_at_ep_ref;

    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_tombstone, &proof.plaintext_value) {
        (true, bytes) if bytes == 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(bytes, &proof.commitment_proof) == existence_at_ep.hash_val,
            )
        }
    };
    if !value_hash_valid {
        return Err(verify_error!(
            HistoryProof,
            bool,
            "Hash of plaintext value did not match existence proof hash".to_string()
        ));
    }

    // ***** PART 1 ***************************
    // Verify the VRF and membership proof for the corresponding label for the version being updated to.
    #[cfg(feature = "vrf")]
    {
        verify_vrf(
            vrf_public_key,
            uname,
            false,
            version,
            &proof.existence_vrf_proof,
            existence_at_ep_ref.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 = VerificationError {
            error_message: err_str,
            error_type: VerificationErrorType::HistoryProof,
        };
        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)?;

        #[cfg(feature = "vrf")]
        {
            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 = VerificationError {
                error_message: vrf_err_str,
                error_type: VerificationErrorType::HistoryProof,
            };
            let previous_val_vrf_proof = proof
                .previous_val_vrf_proof
                .as_ref()
                .ok_or(vrf_previous_null_err)?;

            verify_vrf(
                vrf_public_key,
                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(VerificationError {
            error_message: "No previous root hash given".to_string(),
            error_type: VerificationErrorType::HistoryProof,
        })?;
        verify_nonmembership(
            root_hash,
            non_existence_before_ep.as_ref().ok_or_else(|| VerificationError {error_message: format!(
                "Non-existence before this epoch proof of user {:?}'s version {:?} at epoch {:?} is None",
                uname,
                version,
                epoch
            ), error_type: VerificationErrorType::HistoryProof})?
        )?;
    }

    // Get the least and greatest marker entries for the current version
    let next_marker = crate::utils::get_marker_version(version) + 1;
    let final_marker = crate::utils::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];
        #[cfg(feature = "vrf")]
        {
            let vrf_pf = &proof.next_few_vrf_proofs[i];
            let ver_label = pf.label;
            verify_vrf(vrf_public_key, uname, false, ver, vrf_pf, ver_label)?;
        }
        if !verify_nonmembership(root_hash, pf)? {
            return Err(VerificationError {error_message:
                    format!("Non-existence before epoch proof of user {:?}'s version {:?} at epoch {:?} does not verify",
                    uname, ver, epoch-1), error_type: VerificationErrorType::HistoryProof});
        }
    }

    // ***** 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];
        #[cfg(feature = "vrf")]
        {
            let vrf_pf = &proof.future_marker_vrf_proofs[i];
            let ver_label = pf.label;
            verify_vrf(vrf_public_key, uname, false, ver, vrf_pf, ver_label)?;
        }
        if !verify_nonmembership(root_hash, pf)? {
            return Err(VerificationError {error_message:
                    format!("Non-existence before epoch proof of user {:?}'s version {:?} at epoch {:?} does not verify",
                    uname, ver, epoch-1), error_type: VerificationErrorType::HistoryProof});
        }
    }

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