pub fn try_sapling_output_recovery_with_ock<P: consensus::Parameters>(
    params: &P,
    height: BlockHeight,
    ock: &OutgoingCipherKey,
    cmu: &bls12_381::Scalar,
    epk: &jubjub::ExtendedPoint,
    enc_ciphertext: &[u8],
    out_ciphertext: &[u8],
) -> Option<(Note, PaymentAddress, MemoBytes)> {
    assert_eq!(enc_ciphertext.len(), ENC_CIPHERTEXT_SIZE);
    assert_eq!(out_ciphertext.len(), OUT_CIPHERTEXT_SIZE);

    let mut op = [0; OUT_CIPHERTEXT_SIZE];
    assert_eq!(
        ChachaPolyIetf::aead_cipher()
            .open_to(&mut op, &out_ciphertext, &[], ock.as_ref(), &[0u8; 12])
            .ok()?,
        OUT_PLAINTEXT_SIZE
    );

    let pk_d = {
        let pk_d = jubjub::SubgroupPoint::from_bytes(
            op[0..32].try_into().expect("slice is the correct length"),
        );
        if pk_d.is_none().into() {
            return None;
        }
        pk_d.unwrap()
    };

    let esk = jubjub::Fr::from_repr(
        op[32..OUT_PLAINTEXT_SIZE]
            .try_into()
            .expect("slice is the correct length"),
    )?;

    let shared_secret = sapling_ka_agree(&esk, &pk_d.into());
    let key = kdf_sapling(shared_secret, &epk);

    let mut plaintext = [0; ENC_CIPHERTEXT_SIZE];
    assert_eq!(
        ChachaPolyIetf::aead_cipher()
            .open_to(
                &mut plaintext,
                &enc_ciphertext,
                &[],
                key.as_bytes(),
                &[0u8; 12]
            )
            .ok()?,
        NOTE_PLAINTEXT_SIZE
    );

    // Check note plaintext version
    if !plaintext_version_is_valid(params, height, plaintext[0]) {
        return None;
    }

    let mut d = [0u8; 11];
    d.copy_from_slice(&plaintext[1..12]);

    let v = (&plaintext[12..20]).read_u64::<LittleEndian>().ok()?;

    let r: [u8; 32] = plaintext[20..COMPACT_NOTE_SIZE]
        .try_into()
        .expect("slice is the correct length");

    let rseed = if plaintext[0] == 0x01 {
        let rcm = jubjub::Fr::from_repr(r)?;
        Rseed::BeforeZip212(rcm)
    } else {
        Rseed::AfterZip212(r)
    };

    let memo = MemoBytes::from_bytes(&plaintext[COMPACT_NOTE_SIZE..NOTE_PLAINTEXT_SIZE]).unwrap();

    let diversifier = Diversifier(d);
    if (diversifier.g_d()? * esk).to_bytes() != epk.to_bytes() {
        // Published epk doesn't match calculated epk
        return None;
    }

    let to = PaymentAddress::from_parts(diversifier, pk_d)?;
    let note = to.create_note(v, rseed).unwrap();

    if note.cmu() != *cmu {
        // Published commitment doesn't match calculated commitment
        return None;
    }

    if let Some(derived_esk) = note.derive_esk() {
        if derived_esk != esk {
            return None;
        }
    }

    Some((note, to, memo))
}
/// Recovery of the full note plaintext by the sender.
///
/// Attempts to decrypt and validate the given `enc_ciphertext` using the given `ock`.
/// If successful, the corresponding Sapling note and memo are returned, along with the
/// `PaymentAddress` to which the note was sent.
///
/// Implements part of section 4.17.3 of the Zcash Protocol Specification.
/// For decryption using a Full Viewing Key see [`try_sapling_output_recovery`].
Recovery of the full note plaintext by the sender.
Attempts to decrypt and validate the given `enc_ciphertext` using the given `ock`.
If successful, the corresponding Sapling note and memo are returned, along with the
`PaymentAddress` to which the note was sent.

Implements part of section 4.17.3 of the Zcash Protocol Specification.
For decryption using a Full Viewing Key see [`try_sapling_output_recovery`].
Recovery of the full note plaintext by the sender . Attempts to decrypt and validate the given ` enc_ciphertext ` using the given ` ock ` . If successful the corresponding Sapling note and memo are returned along with the ` PaymentAddress ` to which the note was sent . Implements part of section 4 . 17 . 3 of the Zcash Protocol Specification . For decryption using a Full Viewing Key see [ ` try_sapling_output_recovery ` ] .
pub fn try_sapling_output_recovery_with_ock<P: consensus::Parameters>(
    params: &P,
    height: BlockHeight,
    ock: &OutgoingCipherKey,
    cmu: &bls12_381::Scalar,
    epk: &jubjub::ExtendedPoint,
    enc_ciphertext: &[u8],
    out_ciphertext: &[u8],
) -> Option<(Note, PaymentAddress, MemoBytes)> {
    assert_eq!(enc_ciphertext.len(), ENC_CIPHERTEXT_SIZE);
    assert_eq!(out_ciphertext.len(), OUT_CIPHERTEXT_SIZE);
    let mut op = [0; OUT_CIPHERTEXT_SIZE];
    assert_eq!(
        ChachaPolyIetf::aead_cipher()
            .open_to(&mut op, &out_ciphertext, &[], ock.as_ref(), &[0u8; 12])
            .ok()?,
        OUT_PLAINTEXT_SIZE
    );
    let pk_d = {
        let pk_d = jubjub::SubgroupPoint::from_bytes(
            op[0..32].try_into().expect("slice is the correct length"),
        );
        if pk_d.is_none().into() {
            return None;
        }
        pk_d.unwrap()
    };
    let esk = jubjub::Fr::from_repr(
        op[32..OUT_PLAINTEXT_SIZE]
            .try_into()
            .expect("slice is the correct length"),
    )?;
    let shared_secret = sapling_ka_agree(&esk, &pk_d.into());
    let key = kdf_sapling(shared_secret, &epk);
    let mut plaintext = [0; ENC_CIPHERTEXT_SIZE];
    assert_eq!(
        ChachaPolyIetf::aead_cipher()
            .open_to(
                &mut plaintext,
                &enc_ciphertext,
                &[],
                key.as_bytes(),
                &[0u8; 12]
            )
            .ok()?,
        NOTE_PLAINTEXT_SIZE
    );
    // Check note plaintext version
    if !plaintext_version_is_valid(params, height, plaintext[0]) {
        return None;
    }
    let mut d = [0u8; 11];
    d.copy_from_slice(&plaintext[1..12]);
    let v = (&plaintext[12..20]).read_u64::<LittleEndian>().ok()?;
    let r: [u8; 32] = plaintext[20..COMPACT_NOTE_SIZE]
        .try_into()
        .expect("slice is the correct length");
    let rseed = if plaintext[0] == 0x01 {
        let rcm = jubjub::Fr::from_repr(r)?;
        Rseed::BeforeZip212(rcm)
    } else {
        Rseed::AfterZip212(r)
    };
    let memo = MemoBytes::from_bytes(&plaintext[COMPACT_NOTE_SIZE..NOTE_PLAINTEXT_SIZE]).unwrap();
    let diversifier = Diversifier(d);
    if (diversifier.g_d()? * esk).to_bytes() != epk.to_bytes() {
        // Published epk doesn't match calculated epk
        return None;
    }
    let to = PaymentAddress::from_parts(diversifier, pk_d)?;
    let note = to.create_note(v, rseed).unwrap();
    if note.cmu() != *cmu {
        // Published commitment doesn't match calculated commitment
        return None;
    }
    if let Some(derived_esk) = note.derive_esk() {
        if derived_esk != esk {
            return None;
        }
    }
    Some((note, to, memo))
}
pub fn try_sapling_output_recovery_with_ock < P : consensus :: Parameters > ( params : & P , height : BlockHeight , ock : & OutgoingCipherKey , cmu : & bls12_381 :: Scalar , epk : & jubjub :: ExtendedPoint , enc_ciphertext : & [ u8 ] , out_ciphertext : & [ u8 ] , ) -> Option < ( Note , PaymentAddress , MemoBytes ) > { assert_eq ! ( enc_ciphertext len ( ) ENC_CIPHERTEXT_SIZE ) ; assert_eq ! ( out_ciphertext len ( ) OUT_CIPHERTEXT_SIZE ) ; let mut op = [ 0 ; OUT_CIPHERTEXT_SIZE ] ; assert_eq ! ( ChachaPolyIetf aead_cipher ( ) open_to ( mut op out_ciphertext [ ] ock as_ref ( ) [ 0u8 12 ] ) ok ( ) OUT_PLAINTEXT_SIZE ) ; let pk_d = { let pk_d = jubjub :: SubgroupPoint :: from_bytes ( op [ 0 .. 32 ] . try_into ( ) . expect ( " " ) , ) ; if pk_d . is_none ( ) . into ( ) { return None ; } pk_d . unwrap ( ) } ; let esk = jubjub :: Fr :: from_repr ( op [ 32 .. OUT_PLAINTEXT_SIZE ] . try_into ( ) . expect ( " " ) , ) ? ; let shared_secret = sapling_ka_agree ( & esk , & pk_d . into ( ) ) ; let key = kdf_sapling ( shared_secret , & epk ) ; let mut plaintext = [ 0 ; ENC_CIPHERTEXT_SIZE ] ; assert_eq ! ( ChachaPolyIetf aead_cipher ( ) open_to ( mut plaintext enc_ciphertext [ ] key as_bytes ( ) [ 0u8 12 ] ) ok ( ) NOTE_PLAINTEXT_SIZE ) ; // Check note plaintext version if ! plaintext_version_is_valid ( params , height , plaintext [ 0 ] ) { return None ; } let mut d = [ 0u8 ; 11 ] ; d . copy_from_slice ( & plaintext [ 1 .. 12 ] ) ; let v = ( & plaintext [ 12 .. 20 ] ) . read_u64 :: < LittleEndian > ( ) . ok ( ) ? ; let r : [ u8 ; 32 ] = plaintext [ 20 .. COMPACT_NOTE_SIZE ] . try_into ( ) . expect ( " " ) ; let rseed = if plaintext [ 0 ] == 0x01 { let rcm = jubjub :: Fr :: from_repr ( r ) ? ; Rseed :: BeforeZip212 ( rcm ) } else { Rseed :: AfterZip212 ( r ) } ; let memo = MemoBytes :: from_bytes ( & plaintext [ COMPACT_NOTE_SIZE .. NOTE_PLAINTEXT_SIZE ] ) . unwrap ( ) ; let diversifier = Diversifier ( d ) ; if ( diversifier . g_d ( ) ? * esk ) . to_bytes ( ) != epk . to_bytes ( ) { // Published epk doesn't match calculated epk return None ; } let to = PaymentAddress :: from_parts ( diversifier , pk_d ) ? ; let note = to . create_note ( v , rseed ) . unwrap ( ) ; if note . cmu ( ) != * cmu { // Published commitment doesn't match calculated commitment return None ; } if let Some ( derived_esk ) = note . derive_esk ( ) { if derived_esk != esk { return None ; } } Some ( ( note , to , memo ) ) }
Recovery of the full note plaintext by the sender.
Recovery of the full note plaintext by the sender .
params
&P
height
BlockHeight
ock
&OutgoingCipherKey
cmu
&bls12_381::Scalar
epk
&jubjub::ExtendedPoint
enc_ciphertext
&[u8]
out_ciphertext
&[u8]
params
&P
height
BlockHeight
ock
&OutgoingCipherKey
cmu
&bls12_381::Scalar
epk
&jubjub::ExtendedPoint
enc_ciphertext
&[u8]
out_ciphertext
&[u8]