#[allow(non_snake_case)]
pub mod migration {
    use super::*;
    use sigma_compiler::*;
    use group::GroupEncoding;
    pub type Scalar = <Lox as CMZCredential>::Scalar;
    pub type Point = <Lox as CMZCredential>::Point;
    #[serde_as]
    #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
    pub struct Request {
        #[serde_as(as = "SerdePoint")]
        pub C_iss_cred_N: Point,
        #[serde_as(as = "SerdePoint")]
        pub P_show_cred_L: Point,
        #[serde_as(as = "SerdePoint")]
        pub CQ_show_cred_L: Point,
        #[serde_as(as = "SerdeScalar")]
        pub show_Rattr_L_id: Scalar,
        #[serde_as(as = "SerdeScalar")]
        pub show_Rattr_L_trust_level: Scalar,
        #[serde_as(as = "SerdePoint")]
        pub C_show_Hattr_L_level_since: Point,
        #[serde_as(as = "SerdeScalar")]
        pub show_Rattr_L_invites_remaining: Scalar,
        #[serde_as(as = "SerdeScalar")]
        pub show_Rattr_L_blockages: Scalar,
        #[serde_as(as = "SerdePoint")]
        pub C_show_Hattr_L_bucket: Point,
        #[serde_as(as = "SerdePoint")]
        pub P_show_cred_M: Point,
        #[serde_as(as = "SerdePoint")]
        pub CQ_show_cred_M: Point,
        #[serde_as(as = "SerdeScalar")]
        pub show_Rattr_M_lox_id: Scalar,
        #[serde_as(as = "SerdePoint")]
        pub C_show_Hattr_M_to_bucket: Point,
        #[serde_as(as = "SerdePoint")]
        pub C_show_Hattr_M_from_bucket: Point,
        #[serde(with = "serde_bytes")]
        pub cli_proof: Vec<u8>,
    }
    impl TryFrom<&[u8]> for Request {
        type Error = bincode::Error;
        fn try_from(bytes: &[u8]) -> bincode::Result<Request> {
            bincode::deserialize::<Request>(bytes)
        }
    }
    impl From<&Request> for Vec<u8> {
        fn from(req: &Request) -> Vec<u8> {
            bincode::serialize(req).unwrap()
        }
    }
    impl Request {
        pub fn as_bytes(&self) -> Vec<u8> {
            self.into()
        }
    }
    #[serde_as]
    #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
    pub struct Reply {
        #[serde_as(as = "SerdeScalar")]
        pub iss_Jattr_N_id: Scalar,
        #[serde_as(as = "SerdeScalar")]
        pub iss_Sattr_N_level_since: Scalar,
        #[serde_as(as = "SerdePoint")]
        pub P_iss_cred_N: Point,
        #[serde_as(as = "SerdePoint")]
        pub R_iss_cred_N: Point,
        #[serde(with = "serde_bytes")]
        pub iss_proof: Vec<u8>,
    }
    impl TryFrom<&[u8]> for Reply {
        type Error = bincode::Error;
        fn try_from(bytes: &[u8]) -> bincode::Result<Reply> {
            bincode::deserialize::<Reply>(bytes)
        }
    }
    impl From<&Reply> for Vec<u8> {
        fn from(rep: &Reply) -> Vec<u8> {
            bincode::serialize(rep).unwrap()
        }
    }
    impl Reply {
        pub fn as_bytes(&self) -> Vec<u8> {
            self.into()
        }
    }
    sigma_compiler! {
        client_proof < Point >, (rand s_iss_cred_N, rand zQ_show_cred_L, rand
        z_show_Hattr_L_level_since, rand z_show_Hattr_L_bucket, rand zQ_show_cred_M, rand
        z_show_Hattr_M_to_bucket, rand z_show_Hattr_M_from_bucket, iss_Jattr_N_id,
        iss_Hattr_N_bucket, show_Hattr_L_level_since, show_Hattr_L_bucket,
        show_Hattr_M_to_bucket, show_Hattr_M_from_bucket, pub iss_Iattr_N_trust_level,
        pub iss_Iattr_N_invites_remaining, pub iss_Iattr_N_blockages, pub
        show_Rattr_L_id, pub show_Rattr_L_trust_level, pub
        show_Rattr_L_invites_remaining, pub show_Rattr_L_blockages, pub
        show_Rattr_M_lox_id, pub show_Iattr_M_migration_type,), (cind X_iss_Jattr_N_id,
        cind X_iss_Hattr_N_bucket, cind P_show_cred_L, cind X_show_Hattr_L_level_since,
        cind X_show_Hattr_L_bucket, cind P_show_cred_M, cind X_show_Hattr_M_to_bucket,
        cind X_show_Hattr_M_from_bucket, C_iss_cred_N, V_show_cred_L,
        C_show_Hattr_L_level_since, C_show_Hattr_L_bucket, V_show_cred_M,
        C_show_Hattr_M_to_bucket, C_show_Hattr_M_from_bucket, cind const A_generator,
        cind const B_generator,), show_Rattr_L_id = show_Rattr_M_lox_id,
        show_Hattr_L_bucket = show_Hattr_M_from_bucket, iss_Hattr_N_bucket =
        show_Hattr_M_to_bucket, C_iss_cred_N = s_iss_cred_N * A_generator +
        iss_Jattr_N_id * X_iss_Jattr_N_id + iss_Hattr_N_bucket * X_iss_Hattr_N_bucket,
        C_show_Hattr_L_level_since = show_Hattr_L_level_since * P_show_cred_L +
        z_show_Hattr_L_level_since * A_generator, C_show_Hattr_L_bucket =
        show_Hattr_L_bucket * P_show_cred_L + z_show_Hattr_L_bucket * A_generator,
        V_show_cred_L = zQ_show_cred_L * B_generator + z_show_Hattr_L_level_since *
        X_show_Hattr_L_level_since + z_show_Hattr_L_bucket * X_show_Hattr_L_bucket,
        C_show_Hattr_M_to_bucket = show_Hattr_M_to_bucket * P_show_cred_M +
        z_show_Hattr_M_to_bucket * A_generator, C_show_Hattr_M_from_bucket =
        show_Hattr_M_from_bucket * P_show_cred_M + z_show_Hattr_M_from_bucket *
        A_generator, V_show_cred_M = zQ_show_cred_M * B_generator +
        z_show_Hattr_M_to_bucket * X_show_Hattr_M_to_bucket + z_show_Hattr_M_from_bucket
        * X_show_Hattr_M_from_bucket,
    }
    sigma_compiler! {
        issuer_proof < Point >, (rand b_iss_cred_N, x0_iss_cred_N,), (P_iss_cred_N,
        X0_iss_cred_N, K_iss_cred_N, R_iss_cred_N, cind const A_generator, cind const
        B_generator,), P_iss_cred_N = b_iss_cred_N * A_generator, X0_iss_cred_N =
        x0_iss_cred_N * B_generator, R_iss_cred_N = x0_iss_cred_N * P_iss_cred_N +
        b_iss_cred_N * K_iss_cred_N,
    }
    #[serde_as]
    #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
    pub struct ClientState {
        #[serde(with = "serde_bytes")]
        pub iss_proof_sessid: Vec<u8>,
        pub pubkey_iss_cred_N: CMZPubkey<Point>,
        #[serde_as(as = "SerdeScalar")]
        pub iss_Jattr_N_id: Scalar,
        #[serde_as(as = "SerdeScalar")]
        pub iss_Iattr_N_trust_level: Scalar,
        #[serde_as(as = "SerdeScalar")]
        pub iss_Iattr_N_invites_remaining: Scalar,
        #[serde_as(as = "SerdeScalar")]
        pub iss_Iattr_N_blockages: Scalar,
        #[serde_as(as = "SerdeScalar")]
        pub iss_Hattr_N_bucket: Scalar,
        #[serde_as(as = "SerdeScalar")]
        pub s_iss_cred_N: Scalar,
        #[serde_as(as = "SerdePoint")]
        pub C_iss_cred_N: Point,
    }
    impl TryFrom<&[u8]> for ClientState {
        type Error = bincode::Error;
        fn try_from(bytes: &[u8]) -> bincode::Result<ClientState> {
            bincode::deserialize::<ClientState>(bytes)
        }
    }
    impl From<&ClientState> for Vec<u8> {
        fn from(req: &ClientState) -> Vec<u8> {
            bincode::serialize(req).unwrap()
        }
    }
    impl ClientState {
        pub fn as_bytes(&self) -> Vec<u8> {
            self.into()
        }
    }
    pub fn prepare(
        rng: &mut (impl CryptoRng + RngCore),
        session_id: &[u8],
        show_cred_L: &Lox,
        show_cred_M: &Migration,
        iss_cred_N: Lox,
    ) -> Result<(Request, ClientState), CMZError> {
        let bp = cmz_basepoints::<Point>();
        let mut cli_proof_sessid: Vec<u8> = Vec::new();
        cli_proof_sessid.extend(b"cli_");
        cli_proof_sessid.extend(session_id);
        let mut iss_proof_sessid: Vec<u8> = Vec::new();
        iss_proof_sessid.extend(b"iss_");
        iss_proof_sessid.extend(session_id);
        let s_iss_cred_N = <Scalar as ff::Field>::random(&mut *rng);
        let mut C_iss_cred_N = bp.mulA(&s_iss_cred_N);
        let A_generator = bp.A();
        let B_generator = bp.B();
        if iss_cred_N.get_pubkey().X.len() != Lox::num_attrs() {
            return Err(CMZError::PubkeyMissing("N"));
        }
        if iss_cred_N.get_pubkey().Xr.is_some() != true {
            return Err(CMZError::WrongProtocol("N"));
        }
        let pubkey_iss_cred_N = iss_cred_N.get_pubkey().clone();
        let iss_Jattr_N_id = <Scalar as ff::Field>::random(&mut *rng);
        let X_iss_Jattr_N_id = pubkey_iss_cred_N.X[Lox::attr_num("id")];
        C_iss_cred_N += iss_Jattr_N_id * X_iss_Jattr_N_id;
        let iss_Iattr_N_trust_level = iss_cred_N
            .trust_level
            .ok_or(CMZError::ImplicitAttrCliMissing("N", "trust_level"))?;
        let iss_Iattr_N_invites_remaining = iss_cred_N
            .invites_remaining
            .ok_or(CMZError::ImplicitAttrCliMissing("N", "invites_remaining"))?;
        let iss_Iattr_N_blockages = iss_cred_N
            .blockages
            .ok_or(CMZError::ImplicitAttrCliMissing("N", "blockages"))?;
        let iss_Hattr_N_bucket = iss_cred_N
            .bucket
            .ok_or(CMZError::HideAttrMissing("N", "bucket"))?;
        let X_iss_Hattr_N_bucket = pubkey_iss_cred_N.X[Lox::attr_num("bucket")];
        C_iss_cred_N += iss_Hattr_N_bucket * X_iss_Hattr_N_bucket;
        if show_cred_L.get_pubkey().X.len() != Lox::num_attrs() {
            return Err(CMZError::PubkeyMissing("L"));
        }
        if show_cred_L.get_pubkey().Xr.is_some() != true {
            return Err(CMZError::WrongProtocol("L"));
        }
        let t_show_cred_L = <Scalar as ff::Field>::random(&mut *rng);
        let P_show_cred_L = t_show_cred_L * show_cred_L.MAC.P;
        let Q_show_cred_L = t_show_cred_L * show_cred_L.MAC.Q;
        let zQ_show_cred_L = <Scalar as ff::Field>::random(&mut *rng);
        let CQ_show_cred_L = Q_show_cred_L - bp.mulB(&zQ_show_cred_L);
        let mut V_show_cred_L = bp.mulB(&zQ_show_cred_L);
        let show_Rattr_L_id = show_cred_L
            .id
            .ok_or(CMZError::RevealAttrMissing("L", "id"))?;
        let show_Rattr_L_trust_level = show_cred_L
            .trust_level
            .ok_or(CMZError::RevealAttrMissing("L", "trust_level"))?;
        let show_Hattr_L_level_since = show_cred_L
            .level_since
            .ok_or(CMZError::HideAttrMissing("L", "level_since"))?;
        let z_show_Hattr_L_level_since = <Scalar as ff::Field>::random(&mut *rng);
        let C_show_Hattr_L_level_since = show_Hattr_L_level_since * P_show_cred_L
            + bp.mulA(&z_show_Hattr_L_level_since);
        let X_show_Hattr_L_level_since = show_cred_L.pubkey_X("level_since");
        V_show_cred_L += z_show_Hattr_L_level_since * X_show_Hattr_L_level_since;
        let show_Rattr_L_invites_remaining = show_cred_L
            .invites_remaining
            .ok_or(CMZError::RevealAttrMissing("L", "invites_remaining"))?;
        let show_Rattr_L_blockages = show_cred_L
            .blockages
            .ok_or(CMZError::RevealAttrMissing("L", "blockages"))?;
        let show_Hattr_L_bucket = show_cred_L
            .bucket
            .ok_or(CMZError::HideAttrMissing("L", "bucket"))?;
        let z_show_Hattr_L_bucket = <Scalar as ff::Field>::random(&mut *rng);
        let C_show_Hattr_L_bucket = show_Hattr_L_bucket * P_show_cred_L
            + bp.mulA(&z_show_Hattr_L_bucket);
        let X_show_Hattr_L_bucket = show_cred_L.pubkey_X("bucket");
        V_show_cred_L += z_show_Hattr_L_bucket * X_show_Hattr_L_bucket;
        if show_cred_M.get_pubkey().X.len() != Migration::num_attrs() {
            return Err(CMZError::PubkeyMissing("M"));
        }
        if show_cred_M.get_pubkey().Xr.is_some() != true {
            return Err(CMZError::WrongProtocol("M"));
        }
        let t_show_cred_M = <Scalar as ff::Field>::random(&mut *rng);
        let P_show_cred_M = t_show_cred_M * show_cred_M.MAC.P;
        let Q_show_cred_M = t_show_cred_M * show_cred_M.MAC.Q;
        let zQ_show_cred_M = <Scalar as ff::Field>::random(&mut *rng);
        let CQ_show_cred_M = Q_show_cred_M - bp.mulB(&zQ_show_cred_M);
        let mut V_show_cred_M = bp.mulB(&zQ_show_cred_M);
        let show_Rattr_M_lox_id = show_cred_M
            .lox_id
            .ok_or(CMZError::RevealAttrMissing("M", "lox_id"))?;
        let show_Hattr_M_to_bucket = show_cred_M
            .to_bucket
            .ok_or(CMZError::HideAttrMissing("M", "to_bucket"))?;
        let z_show_Hattr_M_to_bucket = <Scalar as ff::Field>::random(&mut *rng);
        let C_show_Hattr_M_to_bucket = show_Hattr_M_to_bucket * P_show_cred_M
            + bp.mulA(&z_show_Hattr_M_to_bucket);
        let X_show_Hattr_M_to_bucket = show_cred_M.pubkey_X("to_bucket");
        V_show_cred_M += z_show_Hattr_M_to_bucket * X_show_Hattr_M_to_bucket;
        let show_Hattr_M_from_bucket = show_cred_M
            .from_bucket
            .ok_or(CMZError::HideAttrMissing("M", "from_bucket"))?;
        let z_show_Hattr_M_from_bucket = <Scalar as ff::Field>::random(&mut *rng);
        let C_show_Hattr_M_from_bucket = show_Hattr_M_from_bucket * P_show_cred_M
            + bp.mulA(&z_show_Hattr_M_from_bucket);
        let X_show_Hattr_M_from_bucket = show_cred_M.pubkey_X("from_bucket");
        V_show_cred_M += z_show_Hattr_M_from_bucket * X_show_Hattr_M_from_bucket;
        let show_Iattr_M_migration_type = show_cred_M
            .migration_type
            .ok_or(CMZError::ImplicitAttrCliMissing("M", "migration_type"))?;
        let cli_proof_instance = client_proof::Instance {
            C_iss_cred_N,
            V_show_cred_L,
            C_show_Hattr_L_level_since,
            C_show_Hattr_L_bucket,
            V_show_cred_M,
            C_show_Hattr_M_to_bucket,
            C_show_Hattr_M_from_bucket,
            A_generator,
            B_generator,
            X_iss_Jattr_N_id,
            X_iss_Hattr_N_bucket,
            P_show_cred_L,
            X_show_Hattr_L_level_since,
            X_show_Hattr_L_bucket,
            P_show_cred_M,
            X_show_Hattr_M_to_bucket,
            X_show_Hattr_M_from_bucket,
            iss_Iattr_N_trust_level,
            iss_Iattr_N_invites_remaining,
            iss_Iattr_N_blockages,
            show_Rattr_L_id,
            show_Rattr_L_trust_level,
            show_Rattr_L_invites_remaining,
            show_Rattr_L_blockages,
            show_Rattr_M_lox_id,
            show_Iattr_M_migration_type,
        };
        let cli_proof_witness = client_proof::Witness {
            s_iss_cred_N,
            zQ_show_cred_L,
            z_show_Hattr_L_level_since,
            z_show_Hattr_L_bucket,
            zQ_show_cred_M,
            z_show_Hattr_M_to_bucket,
            z_show_Hattr_M_from_bucket,
            iss_Jattr_N_id,
            iss_Hattr_N_bucket,
            show_Hattr_L_level_since,
            show_Hattr_L_bucket,
            show_Hattr_M_to_bucket,
            show_Hattr_M_from_bucket,
        };
        let cli_proof = client_proof::prove(
                &cli_proof_instance,
                &cli_proof_witness,
                &cli_proof_sessid,
                rng,
            )
            .unwrap();
        Ok((
            Request {
                C_iss_cred_N,
                P_show_cred_L,
                CQ_show_cred_L,
                show_Rattr_L_id,
                show_Rattr_L_trust_level,
                C_show_Hattr_L_level_since,
                show_Rattr_L_invites_remaining,
                show_Rattr_L_blockages,
                C_show_Hattr_L_bucket,
                P_show_cred_M,
                CQ_show_cred_M,
                show_Rattr_M_lox_id,
                C_show_Hattr_M_to_bucket,
                C_show_Hattr_M_from_bucket,
                cli_proof,
            },
            ClientState {
                iss_proof_sessid,
                pubkey_iss_cred_N,
                iss_Jattr_N_id,
                iss_Iattr_N_trust_level,
                iss_Iattr_N_invites_remaining,
                iss_Iattr_N_blockages,
                iss_Hattr_N_bucket,
                s_iss_cred_N,
                C_iss_cred_N,
            },
        ))
    }
    impl ClientState {
        pub fn finalize(self, reply: Reply) -> Result<Lox, (CMZError, Self)> {
            let bp = cmz_basepoints::<Point>();
            let mut iss_cred_N = Lox::default();
            let mut K_iss_cred_N = self.C_iss_cred_N
                + self.pubkey_iss_cred_N.Xr.unwrap();
            let A_generator = bp.A();
            let B_generator = bp.B();
            iss_cred_N.set_pubkey(&self.pubkey_iss_cred_N);
            let iss_Jattr_N_id = reply.iss_Jattr_N_id;
            iss_cred_N.id = Some(self.iss_Jattr_N_id + reply.iss_Jattr_N_id);
            K_iss_cred_N += (iss_Jattr_N_id * iss_cred_N.pubkey_X("id"));
            iss_cred_N.trust_level = Some(self.iss_Iattr_N_trust_level);
            K_iss_cred_N
                += (iss_cred_N.trust_level.unwrap()
                    * iss_cred_N.pubkey_X("trust_level"));
            iss_cred_N.level_since = Some(reply.iss_Sattr_N_level_since);
            K_iss_cred_N
                += (iss_cred_N.level_since.unwrap()
                    * iss_cred_N.pubkey_X("level_since"));
            iss_cred_N.invites_remaining = Some(self.iss_Iattr_N_invites_remaining);
            K_iss_cred_N
                += (iss_cred_N.invites_remaining.unwrap()
                    * iss_cred_N.pubkey_X("invites_remaining"));
            iss_cred_N.blockages = Some(self.iss_Iattr_N_blockages);
            K_iss_cred_N
                += (iss_cred_N.blockages.unwrap() * iss_cred_N.pubkey_X("blockages"));
            iss_cred_N.bucket = Some(self.iss_Hattr_N_bucket);
            let P_iss_cred_N = reply.P_iss_cred_N;
            let X0_iss_cred_N = iss_cred_N.get_pubkey().X0.unwrap();
            let R_iss_cred_N = reply.R_iss_cred_N;
            iss_cred_N.MAC.P = P_iss_cred_N;
            iss_cred_N.MAC.Q = reply.R_iss_cred_N
                - self.s_iss_cred_N * reply.P_iss_cred_N;
            let iss_proof_instance = issuer_proof::Instance {
                P_iss_cred_N,
                X0_iss_cred_N,
                K_iss_cred_N,
                R_iss_cred_N,
                A_generator,
                B_generator,
            };
            if issuer_proof::verify(
                    &iss_proof_instance,
                    &reply.iss_proof,
                    &self.iss_proof_sessid,
                )
                .is_err()
            {
                return Err((CMZError::IssProofFailed, self));
            }
            Ok(iss_cred_N)
        }
    }
    pub fn handle<F, A>(
        rng: &mut (impl CryptoRng + RngCore),
        session_id: &[u8],
        request: Request,
        fill_creds: F,
        authorize: A,
    ) -> Result<(Reply, (Lox, Migration, Lox)), CMZError>
    where
        F: FnOnce(&mut Lox, &mut Migration, &mut Lox) -> Result<(), CMZError>,
        A: FnOnce(&Lox, &Migration, &Lox) -> Result<(), CMZError>,
    {
        let bp = cmz_basepoints::<Point>();
        let mut cli_proof_sessid: Vec<u8> = Vec::new();
        cli_proof_sessid.extend(b"cli_");
        cli_proof_sessid.extend(session_id);
        let mut iss_proof_sessid: Vec<u8> = Vec::new();
        iss_proof_sessid.extend(b"iss_");
        iss_proof_sessid.extend(session_id);
        let mut show_cred_L = Lox::default();
        let mut show_cred_M = Migration::default();
        let mut iss_cred_N = Lox::default();
        let A_generator = bp.A();
        let B_generator = bp.B();
        let iss_Jattr_N_id = <Scalar as ff::Field>::random(&mut *rng);
        let show_Rattr_L_id = request.show_Rattr_L_id;
        show_cred_L.id = Some(show_Rattr_L_id);
        let show_Rattr_L_trust_level = request.show_Rattr_L_trust_level;
        show_cred_L.trust_level = Some(show_Rattr_L_trust_level);
        let show_Rattr_L_invites_remaining = request.show_Rattr_L_invites_remaining;
        show_cred_L.invites_remaining = Some(show_Rattr_L_invites_remaining);
        let show_Rattr_L_blockages = request.show_Rattr_L_blockages;
        show_cred_L.blockages = Some(show_Rattr_L_blockages);
        let show_Rattr_M_lox_id = request.show_Rattr_M_lox_id;
        show_cred_M.lox_id = Some(show_Rattr_M_lox_id);
        fill_creds(&mut show_cred_L, &mut show_cred_M, &mut iss_cred_N)?;
        let C_iss_cred_N = request.C_iss_cred_N;
        let mut K_iss_cred_N = C_iss_cred_N + iss_cred_N.get_pubkey().Xr.unwrap();
        if iss_cred_N.get_privkey().x.len() != Lox::num_attrs() {
            return Err(CMZError::PrivkeyMissing("N"));
        }
        if iss_cred_N.get_privkey().muCMZ != true {
            return Err(CMZError::WrongProtocol("N"));
        }
        let X_iss_Jattr_N_id = iss_cred_N.pubkey_X("id");
        K_iss_cred_N += (iss_Jattr_N_id * iss_cred_N.pubkey_X("id"));
        let iss_Iattr_N_trust_level = iss_cred_N
            .trust_level
            .ok_or(CMZError::ImplicitAttrIssMissing("N", "trust_level"))?;
        K_iss_cred_N += (iss_Iattr_N_trust_level * iss_cred_N.pubkey_X("trust_level"));
        let iss_Sattr_N_level_since = iss_cred_N
            .level_since
            .ok_or(CMZError::SetAttrMissing("N", "level_since"))?;
        K_iss_cred_N += (iss_Sattr_N_level_since * iss_cred_N.pubkey_X("level_since"));
        let iss_Iattr_N_invites_remaining = iss_cred_N
            .invites_remaining
            .ok_or(CMZError::ImplicitAttrIssMissing("N", "invites_remaining"))?;
        K_iss_cred_N
            += (iss_Iattr_N_invites_remaining
                * iss_cred_N.pubkey_X("invites_remaining"));
        let iss_Iattr_N_blockages = iss_cred_N
            .blockages
            .ok_or(CMZError::ImplicitAttrIssMissing("N", "blockages"))?;
        K_iss_cred_N += (iss_Iattr_N_blockages * iss_cred_N.pubkey_X("blockages"));
        let X_iss_Hattr_N_bucket = iss_cred_N.pubkey_X("bucket");
        if show_cred_L.get_privkey().x.len() != Lox::num_attrs() {
            return Err(CMZError::PrivkeyMissing("L"));
        }
        if show_cred_L.get_privkey().muCMZ != true {
            return Err(CMZError::WrongProtocol("L"));
        }
        let P_show_cred_L = request.P_show_cred_L;
        if bool::from(P_show_cred_L.is_identity()) {
            return Err(CMZError::CliProofFailed);
        }
        let mut V_show_cred_L = -request.CQ_show_cred_L;
        let mut q_show_cred_L = show_cred_L.get_privkey().x0
            + show_cred_L.get_privkey().xr;
        q_show_cred_L += show_Rattr_L_id * show_cred_L.privkey_x("id");
        q_show_cred_L += show_Rattr_L_trust_level * show_cred_L.privkey_x("trust_level");
        let C_show_Hattr_L_level_since = request.C_show_Hattr_L_level_since;
        let X_show_Hattr_L_level_since = show_cred_L.pubkey_X("level_since");
        V_show_cred_L
            += show_cred_L.privkey_x("level_since") * C_show_Hattr_L_level_since;
        q_show_cred_L
            += show_Rattr_L_invites_remaining
                * show_cred_L.privkey_x("invites_remaining");
        q_show_cred_L += show_Rattr_L_blockages * show_cred_L.privkey_x("blockages");
        let C_show_Hattr_L_bucket = request.C_show_Hattr_L_bucket;
        let X_show_Hattr_L_bucket = show_cred_L.pubkey_X("bucket");
        V_show_cred_L += show_cred_L.privkey_x("bucket") * C_show_Hattr_L_bucket;
        V_show_cred_L += q_show_cred_L * P_show_cred_L;
        if show_cred_M.get_privkey().x.len() != Migration::num_attrs() {
            return Err(CMZError::PrivkeyMissing("M"));
        }
        if show_cred_M.get_privkey().muCMZ != true {
            return Err(CMZError::WrongProtocol("M"));
        }
        let P_show_cred_M = request.P_show_cred_M;
        if bool::from(P_show_cred_M.is_identity()) {
            return Err(CMZError::CliProofFailed);
        }
        let mut V_show_cred_M = -request.CQ_show_cred_M;
        let mut q_show_cred_M = show_cred_M.get_privkey().x0
            + show_cred_M.get_privkey().xr;
        q_show_cred_M += show_Rattr_M_lox_id * show_cred_M.privkey_x("lox_id");
        let C_show_Hattr_M_to_bucket = request.C_show_Hattr_M_to_bucket;
        let X_show_Hattr_M_to_bucket = show_cred_M.pubkey_X("to_bucket");
        V_show_cred_M += show_cred_M.privkey_x("to_bucket") * C_show_Hattr_M_to_bucket;
        let C_show_Hattr_M_from_bucket = request.C_show_Hattr_M_from_bucket;
        let X_show_Hattr_M_from_bucket = show_cred_M.pubkey_X("from_bucket");
        V_show_cred_M
            += show_cred_M.privkey_x("from_bucket") * C_show_Hattr_M_from_bucket;
        let show_Iattr_M_migration_type = show_cred_M
            .migration_type
            .ok_or(CMZError::ImplicitAttrIssMissing("M", "migration_type"))?;
        q_show_cred_M
            += show_Iattr_M_migration_type * show_cred_M.privkey_x("migration_type");
        V_show_cred_M += q_show_cred_M * P_show_cred_M;
        let cli_proof_instance = client_proof::Instance {
            C_iss_cred_N,
            V_show_cred_L,
            C_show_Hattr_L_level_since,
            C_show_Hattr_L_bucket,
            V_show_cred_M,
            C_show_Hattr_M_to_bucket,
            C_show_Hattr_M_from_bucket,
            A_generator,
            B_generator,
            X_iss_Jattr_N_id,
            X_iss_Hattr_N_bucket,
            P_show_cred_L,
            X_show_Hattr_L_level_since,
            X_show_Hattr_L_bucket,
            P_show_cred_M,
            X_show_Hattr_M_to_bucket,
            X_show_Hattr_M_from_bucket,
            iss_Iattr_N_trust_level,
            iss_Iattr_N_invites_remaining,
            iss_Iattr_N_blockages,
            show_Rattr_L_id,
            show_Rattr_L_trust_level,
            show_Rattr_L_invites_remaining,
            show_Rattr_L_blockages,
            show_Rattr_M_lox_id,
            show_Iattr_M_migration_type,
        };
        if client_proof::verify(
                &cli_proof_instance,
                &request.cli_proof,
                &cli_proof_sessid,
            )
            .is_err()
        {
            return Err(CMZError::CliProofFailed);
        }
        authorize(&show_cred_L, &show_cred_M, &iss_cred_N)?;
        let b_iss_cred_N = <Scalar as ff::Field>::random(&mut *rng);
        let P_iss_cred_N = bp.mulA(&b_iss_cred_N);
        iss_cred_N.MAC.P = P_iss_cred_N;
        let x0_iss_cred_N = iss_cred_N.get_privkey().x0;
        let X0_iss_cred_N = iss_cred_N.get_pubkey().X0.unwrap();
        let R_iss_cred_N = b_iss_cred_N * (bp.mulA(&x0_iss_cred_N) + K_iss_cred_N);
        let iss_proof_instance = issuer_proof::Instance {
            P_iss_cred_N,
            X0_iss_cred_N,
            K_iss_cred_N,
            R_iss_cred_N,
            A_generator,
            B_generator,
        };
        let iss_proof_witness = issuer_proof::Witness {
            b_iss_cred_N,
            x0_iss_cred_N,
        };
        let iss_proof = issuer_proof::prove(
                &iss_proof_instance,
                &iss_proof_witness,
                &iss_proof_sessid,
                rng,
            )
            .unwrap();
        Ok((
            Reply {
                iss_Jattr_N_id,
                iss_Sattr_N_level_since,
                P_iss_cred_N,
                R_iss_cred_N,
                iss_proof,
            },
            (show_cred_L, show_cred_M, iss_cred_N),
        ))
    }
}

