solana_zk_sdk/zk_elgamal_proof_program/proof_data/
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(target_arch = "wasm32")]
9use wasm_bindgen::prelude::*;
10#[cfg(not(target_os = "solana"))]
11use {
12    crate::{
13        encryption::elgamal::ElGamalKeypair,
14        sigma_proofs::pubkey_validity::PubkeyValidityProof,
15        zk_elgamal_proof_program::{
16            errors::{ProofGenerationError, ProofVerificationError},
17            proof_data::errors::ProofDataError,
18        },
19    },
20    bytemuck::bytes_of,
21    merlin::Transcript,
22    std::convert::TryInto,
23};
24use {
25    crate::{
26        encryption::pod::elgamal::PodElGamalPubkey,
27        sigma_proofs::pod::PodPubkeyValidityProof,
28        zk_elgamal_proof_program::proof_data::{pod::impl_wasm_to_bytes, ProofType, ZkProofData},
29    },
30    bytemuck_derive::{Pod, Zeroable},
31};
32
33/// The instruction data that is needed for the `ProofInstruction::VerifyPubkeyValidity`
34/// instruction.
35///
36/// It includes the cryptographic proof as well as the context data information needed to verify
37/// the proof.
38#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
39#[derive(Clone, Copy, Pod, Zeroable)]
40#[repr(C)]
41pub struct PubkeyValidityProofData {
42    /// The context data for the public key validity proof
43    pub context: PubkeyValidityProofContext, // 32 bytes
44
45    /// Proof that the public key is well-formed
46    pub proof: PodPubkeyValidityProof, // 64 bytes
47}
48
49/// The context data needed to verify a pubkey validity proof.
50#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
51#[derive(Clone, Copy, Pod, Zeroable)]
52#[repr(C)]
53pub struct PubkeyValidityProofContext {
54    /// The public key to be proved
55    pub pubkey: PodElGamalPubkey, // 32 bytes
56}
57
58#[cfg(not(target_os = "solana"))]
59#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
60impl PubkeyValidityProofData {
61    pub fn new(keypair: &ElGamalKeypair) -> Result<Self, ProofGenerationError> {
62        let pod_pubkey = PodElGamalPubkey(keypair.pubkey().into());
63
64        let context = PubkeyValidityProofContext { pubkey: pod_pubkey };
65
66        let mut transcript = context.new_transcript();
67        let proof = PubkeyValidityProof::new(keypair, &mut transcript).into();
68
69        Ok(PubkeyValidityProofData { context, proof })
70    }
71}
72
73impl_wasm_to_bytes!(TYPE = PubkeyValidityProofData);
74
75impl ZkProofData<PubkeyValidityProofContext> for PubkeyValidityProofData {
76    const PROOF_TYPE: ProofType = ProofType::PubkeyValidity;
77
78    fn context_data(&self) -> &PubkeyValidityProofContext {
79        &self.context
80    }
81
82    #[cfg(not(target_os = "solana"))]
83    fn verify_proof(&self) -> Result<(), ProofVerificationError> {
84        let mut transcript = self.context.new_transcript();
85        let pubkey = self.context.pubkey.try_into()?;
86        let proof: PubkeyValidityProof = self.proof.try_into()?;
87        proof.verify(&pubkey, &mut transcript).map_err(|e| e.into())
88    }
89}
90
91#[allow(non_snake_case)]
92#[cfg(not(target_os = "solana"))]
93impl PubkeyValidityProofContext {
94    fn new_transcript(&self) -> Transcript {
95        let mut transcript = Transcript::new(b"pubkey-validity-instruction");
96        transcript.append_message(b"pubkey", bytes_of(&self.pubkey));
97        transcript
98    }
99}
100
101impl_wasm_to_bytes!(TYPE = PubkeyValidityProofContext);
102
103#[cfg(test)]
104mod test {
105    use super::*;
106
107    #[test]
108    fn test_pubkey_validity_instruction_correctness() {
109        let keypair = ElGamalKeypair::new_rand();
110
111        let pubkey_validity_data = PubkeyValidityProofData::new(&keypair).unwrap();
112        assert!(pubkey_validity_data.verify_proof().is_ok());
113    }
114}