solana_zk_sdk/zk_elgamal_proof_program/state.rs
1use {
2 crate::zk_elgamal_proof_program::proof_data::{pod::PodProofType, ProofType},
3 bytemuck::{bytes_of, Pod, Zeroable},
4 num_traits::ToPrimitive,
5 solana_instruction::error::{InstructionError, InstructionError::InvalidAccountData},
6 solana_pubkey::Pubkey,
7 std::mem::size_of,
8};
9
10/// The on-chain state for a verified zero-knowledge proof statement.
11///
12/// In a zero-knowledge proof system, there is a distinction between a **proof** and a
13/// **statement**.
14/// - The **statement** consists of the public values that a proof is certifying. For example, in a
15/// `VerifyZeroCiphertext` instruction, the statement is the ElGamal ciphertext itself.
16/// - The **proof** is the cryptographic data that demonstrates the statement's validity without
17/// revealing any secret information.
18///
19/// A proof is ephemeral and is discarded after it is successfully verified by a proof
20/// instruction. However, the instruction can optionally store the verified public statement
21/// on-chain in a dedicated account. The `ProofContextState` struct defines the layout of this
22/// account.
23///
24/// Storing the statement on-chain acts as a verifiable receipt or certificate that a specific
25/// proof was successfully processed. This state can then be referenced by other on-chain programs.
26#[derive(Clone, Copy, Debug, PartialEq)]
27#[repr(C)]
28pub struct ProofContextState<T: Pod> {
29 /// The proof context authority that can close the account
30 pub context_state_authority: Pubkey,
31 /// The proof type for the context data
32 pub proof_type: PodProofType,
33 /// The proof context data
34 pub proof_context: T,
35}
36
37// `bytemuck::Pod` cannot be derived for generic structs unless the struct is marked
38// `repr(packed)`, which may cause unnecessary complications when referencing its fields. Directly
39// mark `ProofContextState` as `Zeroable` and `Pod` since none of its fields has an alignment
40// requirement greater than 1 and therefore, guaranteed to be `packed`.
41unsafe impl<T: Pod> Zeroable for ProofContextState<T> {}
42unsafe impl<T: Pod> Pod for ProofContextState<T> {}
43
44impl<T: Pod> ProofContextState<T> {
45 pub fn encode(
46 context_state_authority: &Pubkey,
47 proof_type: ProofType,
48 proof_context: &T,
49 ) -> Vec<u8> {
50 let mut buf = Vec::with_capacity(size_of::<Self>());
51 buf.extend_from_slice(context_state_authority.as_ref());
52 buf.push(ToPrimitive::to_u8(&proof_type).unwrap());
53 buf.extend_from_slice(bytes_of(proof_context));
54 buf
55 }
56
57 /// Interpret a slice as a `ProofContextState`.
58 ///
59 /// This function requires a generic parameter. To access only the generic-independent fields
60 /// in `ProofContextState` without a generic parameter, use
61 /// `ProofContextStateMeta::try_from_bytes` instead.
62 pub fn try_from_bytes(input: &[u8]) -> Result<&Self, InstructionError> {
63 bytemuck::try_from_bytes(input).map_err(|_| InvalidAccountData)
64 }
65}
66
67/// The `ProofContextState` without the proof context itself. This struct exists to facilitate the
68/// decoding of generic-independent fields in `ProofContextState`.
69#[derive(Clone, Copy, Debug, PartialEq, bytemuck_derive::Pod, bytemuck_derive::Zeroable)]
70#[repr(C)]
71pub struct ProofContextStateMeta {
72 /// The proof context authority that can close the account
73 pub context_state_authority: Pubkey,
74 /// The proof type for the context data
75 pub proof_type: PodProofType,
76}
77
78impl ProofContextStateMeta {
79 pub fn try_from_bytes(input: &[u8]) -> Result<&Self, InstructionError> {
80 input
81 .get(..size_of::<ProofContextStateMeta>())
82 .and_then(|data| bytemuck::try_from_bytes(data).ok())
83 .ok_or(InvalidAccountData)
84 }
85}