solana_zk_token_sdk/instruction/
pubkey_validity.rs

1//! The public-key validity proof instruction.
2//!
3//! A public-key validity proof system is defined with respect to an ElGamal public key. The proof
4//! certifies that a given public key is a valid ElGamal public key (i.e. the prover knows a
5//! corresponding secret key). To generate the proof, a prover must provide the secret key for the
6//! public key.
7
8#[cfg(not(target_os = "solana"))]
9use {
10    crate::{
11        encryption::elgamal::ElGamalKeypair,
12        errors::{ProofGenerationError, ProofVerificationError},
13        sigma_proofs::pubkey_proof::PubkeyValidityProof,
14        transcript::TranscriptProtocol,
15    },
16    merlin::Transcript,
17    std::convert::TryInto,
18};
19use {
20    crate::{
21        instruction::{ProofType, ZkProofData},
22        zk_token_elgamal::pod,
23    },
24    bytemuck_derive::{Pod, Zeroable},
25};
26
27/// The instruction data that is needed for the `ProofInstruction::VerifyPubkeyValidity`
28/// instruction.
29///
30/// It includes the cryptographic proof as well as the context data information needed to verify
31/// the proof.
32#[derive(Clone, Copy, Pod, Zeroable)]
33#[repr(C)]
34pub struct PubkeyValidityData {
35    /// The context data for the public key validity proof
36    pub context: PubkeyValidityProofContext, // 32 bytes
37
38    /// Proof that the public key is well-formed
39    pub proof: pod::PubkeyValidityProof, // 64 bytes
40}
41
42/// The context data needed to verify a pubkey validity proof.
43#[derive(Clone, Copy, Pod, Zeroable)]
44#[repr(C)]
45pub struct PubkeyValidityProofContext {
46    /// The public key to be proved
47    pub pubkey: pod::ElGamalPubkey, // 32 bytes
48}
49
50#[cfg(not(target_os = "solana"))]
51impl PubkeyValidityData {
52    pub fn new(keypair: &ElGamalKeypair) -> Result<Self, ProofGenerationError> {
53        let pod_pubkey = pod::ElGamalPubkey(keypair.pubkey().into());
54
55        let context = PubkeyValidityProofContext { pubkey: pod_pubkey };
56
57        let mut transcript = context.new_transcript();
58        let proof = PubkeyValidityProof::new(keypair, &mut transcript).into();
59
60        Ok(PubkeyValidityData { context, proof })
61    }
62}
63
64impl ZkProofData<PubkeyValidityProofContext> for PubkeyValidityData {
65    const PROOF_TYPE: ProofType = ProofType::PubkeyValidity;
66
67    fn context_data(&self) -> &PubkeyValidityProofContext {
68        &self.context
69    }
70
71    #[cfg(not(target_os = "solana"))]
72    fn verify_proof(&self) -> Result<(), ProofVerificationError> {
73        let mut transcript = self.context.new_transcript();
74        let pubkey = self.context.pubkey.try_into()?;
75        let proof: PubkeyValidityProof = self.proof.try_into()?;
76        proof.verify(&pubkey, &mut transcript).map_err(|e| e.into())
77    }
78}
79
80#[allow(non_snake_case)]
81#[cfg(not(target_os = "solana"))]
82impl PubkeyValidityProofContext {
83    fn new_transcript(&self) -> Transcript {
84        let mut transcript = Transcript::new(b"PubkeyProof");
85        transcript.append_pubkey(b"pubkey", &self.pubkey);
86        transcript
87    }
88}
89
90#[cfg(test)]
91mod test {
92    use super::*;
93
94    #[test]
95    fn test_pubkey_validity_instruction_correctness() {
96        let keypair = ElGamalKeypair::new_rand();
97
98        let pubkey_validity_data = PubkeyValidityData::new(&keypair).unwrap();
99        assert!(pubkey_validity_data.verify_proof().is_ok());
100    }
101}