move privateaccountkind to program module

This commit is contained in:
Sergio Chouhy 2026-05-07 01:38:41 -03:00
parent 755b49654e
commit d4334c4694
4 changed files with 78 additions and 79 deletions

View File

@ -9,87 +9,15 @@ use serde::{Deserialize, Serialize};
pub use shared_key_derivation::{EphemeralPublicKey, EphemeralSecretKey, ViewingPublicKey};
use crate::{
Commitment, Identifier,
Commitment,
account::Account,
program::{PdaSeed, ProgramId},
program::PrivateAccountKind,
};
#[cfg(feature = "host")]
pub mod shared_key_derivation;
pub type Scalar = [u8; 32];
/// Discriminates the type of private account a ciphertext belongs to, carrying the data needed
/// to reconstruct the account's [`AccountId`] on the receiver side.
///
/// [`AccountId`]: crate::account::AccountId
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum PrivateAccountKind {
Regular(Identifier),
Pda {
program_id: ProgramId,
seed: PdaSeed,
identifier: Identifier,
},
}
impl PrivateAccountKind {
/// Regular(ident): 0x00 || ident (16 LE) || [0u8; 64]
/// Pda { program_id, seed, ident }: 0x01 || program_id (32 LE) || seed (32) || ident (16 LE)
pub const HEADER_LEN: usize = 81;
#[must_use]
pub fn identifier(&self) -> Identifier {
match self {
Self::Regular(identifier) => *identifier,
Self::Pda { identifier, .. } => *identifier,
}
}
#[must_use]
pub fn to_header_bytes(&self) -> [u8; Self::HEADER_LEN] {
let mut bytes = [0u8; Self::HEADER_LEN];
match self {
Self::Regular(identifier) => {
bytes[0] = 0x00;
bytes[1..17].copy_from_slice(&identifier.to_le_bytes());
// bytes[17..81] are zero padding
}
Self::Pda { program_id, seed, identifier } => {
bytes[0] = 0x01;
for (i, &word) in program_id.iter().enumerate() {
bytes[1 + i * 4..1 + (i + 1) * 4].copy_from_slice(&word.to_le_bytes());
}
bytes[33..65].copy_from_slice(seed.as_bytes());
bytes[65..81].copy_from_slice(&identifier.to_le_bytes());
}
}
bytes
}
#[cfg(feature = "host")]
#[must_use]
pub fn from_header_bytes(bytes: &[u8; Self::HEADER_LEN]) -> Option<Self> {
match bytes[0] {
0x00 => {
let identifier = Identifier::from_le_bytes(bytes[1..17].try_into().unwrap());
Some(Self::Regular(identifier))
}
0x01 => {
let mut program_id = [0u32; 8];
for (i, word) in program_id.iter_mut().enumerate() {
*word = u32::from_le_bytes(
bytes[1 + i * 4..1 + (i + 1) * 4].try_into().unwrap(),
);
}
let seed = PdaSeed::new(bytes[33..65].try_into().unwrap());
let identifier = Identifier::from_le_bytes(bytes[65..81].try_into().unwrap());
Some(Self::Pda { program_id, seed, identifier })
}
_ => None,
}
}
}
#[derive(Serialize, Deserialize, Clone, Copy)]
pub struct SharedSecretKey(pub [u8; 32]);
@ -198,7 +126,7 @@ impl EncryptionScheme {
#[cfg(test)]
mod tests {
use super::*;
use crate::account::{Account, AccountId};
use crate::{account::{Account, AccountId}, program::PdaSeed};
#[test]
fn encrypt_same_length_for_account_and_pda() {

View File

@ -10,7 +10,8 @@ pub use commitment::{
Commitment, CommitmentSetDigest, DUMMY_COMMITMENT, DUMMY_COMMITMENT_HASH, MembershipProof,
compute_digest_for_path,
};
pub use encryption::{EncryptionScheme, PrivateAccountKind, SharedSecretKey};
pub use encryption::{EncryptionScheme, SharedSecretKey};
pub use program::PrivateAccountKind;
pub use nullifier::{Identifier, Nullifier, NullifierPublicKey, NullifierSecretKey};
pub mod account;

View File

@ -8,7 +8,6 @@ use serde::{Deserialize, Serialize};
use crate::{
BlockId, Identifier, NullifierPublicKey, Timestamp,
account::{Account, AccountId, AccountWithMetadata},
encryption::PrivateAccountKind,
};
pub const DEFAULT_PROGRAM_ID: ProgramId = [0; 8];
@ -49,6 +48,78 @@ impl AsRef<[u8]> for PdaSeed {
}
}
/// Discriminates the type of private account a ciphertext belongs to, carrying the data needed
/// to reconstruct the account's [`AccountId`] on the receiver side.
///
/// [`AccountId`]: crate::account::AccountId
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum PrivateAccountKind {
Regular(Identifier),
Pda {
program_id: ProgramId,
seed: PdaSeed,
identifier: Identifier,
},
}
impl PrivateAccountKind {
/// Regular(ident): 0x00 || ident (16 LE) || [0u8; 64]
/// Pda { program_id, seed, ident }: 0x01 || program_id (32 LE) || seed (32) || ident (16 LE)
pub const HEADER_LEN: usize = 81;
#[must_use]
pub fn identifier(&self) -> Identifier {
match self {
Self::Regular(identifier) => *identifier,
Self::Pda { identifier, .. } => *identifier,
}
}
#[must_use]
pub fn to_header_bytes(&self) -> [u8; Self::HEADER_LEN] {
let mut bytes = [0u8; Self::HEADER_LEN];
match self {
Self::Regular(identifier) => {
bytes[0] = 0x00;
bytes[1..17].copy_from_slice(&identifier.to_le_bytes());
// bytes[17..81] are zero padding
}
Self::Pda { program_id, seed, identifier } => {
bytes[0] = 0x01;
for (i, &word) in program_id.iter().enumerate() {
bytes[1 + i * 4..1 + (i + 1) * 4].copy_from_slice(&word.to_le_bytes());
}
bytes[33..65].copy_from_slice(seed.as_bytes());
bytes[65..81].copy_from_slice(&identifier.to_le_bytes());
}
}
bytes
}
#[cfg(feature = "host")]
#[must_use]
pub fn from_header_bytes(bytes: &[u8; Self::HEADER_LEN]) -> Option<Self> {
match bytes[0] {
0x00 => {
let identifier = Identifier::from_le_bytes(bytes[1..17].try_into().unwrap());
Some(Self::Regular(identifier))
}
0x01 => {
let mut program_id = [0u32; 8];
for (i, word) in program_id.iter_mut().enumerate() {
*word = u32::from_le_bytes(
bytes[1 + i * 4..1 + (i + 1) * 4].try_into().unwrap(),
);
}
let seed = PdaSeed::new(bytes[33..65].try_into().unwrap());
let identifier = Identifier::from_le_bytes(bytes[65..81].try_into().unwrap());
Some(Self::Pda { program_id, seed, identifier })
}
_ => None,
}
}
}
impl AccountId {
/// Derives an [`AccountId`] for a public PDA from the program ID and seed.
#[must_use]

View File

@ -179,8 +179,7 @@ mod tests {
Commitment, DUMMY_COMMITMENT_HASH, EncryptionScheme, Nullifier,
PrivacyPreservingCircuitOutput, SharedSecretKey,
account::{Account, AccountId, AccountWithMetadata, Nonce, data::Data},
encryption::PrivateAccountKind,
program::PdaSeed,
program::{PdaSeed, PrivateAccountKind},
};
fn decrypt_kind(