Skip to content
This repository has been archived by the owner on Jan 10, 2025. It is now read-only.

[token-2022] Upgrade to zk-sdk #7148

Merged
merged 16 commits into from
Aug 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions libraries/pod/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,21 @@ license = "Apache-2.0"
edition = "2021"

[features]
serde-traits = ["dep:serde", "dep:base64"]
serde-traits = ["dep:serde"]
borsh = ["dep:borsh"]

[dependencies]
base64 = { version = "0.22.1", optional = true }
borsh = { version = "1.5.1", optional = true }
bytemuck = { version = "1.16.3" }
bytemuck_derive = { version = "1.7.0" }
serde = { version = "1.0.207", optional = true }
solana-program = "2.0.3"
solana-zk-token-sdk = "2.0.3"
solana-zk-sdk = "2.0.3"
spl-program-error = { version = "0.5.0", path = "../program-error" }

[dev-dependencies]
serde_json = "1.0.124"
base64 = { version = "0.22.1" }

[lib]
crate-type = ["cdylib", "lib"]
Expand Down
96 changes: 53 additions & 43 deletions libraries/pod/src/optional_keys.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
//! Optional pubkeys that can be used a `Pod`s
#[cfg(feature = "borsh")]
use borsh::{BorshDeserialize, BorshSchema, BorshSerialize};
use {
bytemuck_derive::{Pod, Zeroable},
solana_program::{program_error::ProgramError, program_option::COption, pubkey::Pubkey},
solana_zk_sdk::encryption::pod::elgamal::PodElGamalPubkey,
};
#[cfg(feature = "serde-traits")]
use {
base64::{prelude::BASE64_STANDARD, Engine},
serde::de::{Error, Unexpected, Visitor},
serde::{Deserialize, Deserializer, Serialize, Serializer},
std::{convert::TryFrom, fmt, str::FromStr},
};
use {
bytemuck_derive::{Pod, Zeroable},
solana_program::{program_error::ProgramError, program_option::COption, pubkey::Pubkey},
solana_zk_token_sdk::zk_token_elgamal::pod::ElGamalPubkey,
};

/// A Pubkey that encodes `None` as all `0`, meant to be usable as a Pod type,
/// similar to all NonZero* number types from the bytemuck library.
Expand Down Expand Up @@ -131,21 +130,21 @@ impl<'de> Deserialize<'de> for OptionalNonZeroPubkey {
/// type.
#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)]
#[repr(transparent)]
pub struct OptionalNonZeroElGamalPubkey(ElGamalPubkey);
pub struct OptionalNonZeroElGamalPubkey(PodElGamalPubkey);
impl OptionalNonZeroElGamalPubkey {
/// Checks equality between an OptionalNonZeroElGamalPubkey and an
/// ElGamalPubkey when interpreted as bytes.
pub fn equals(&self, other: &ElGamalPubkey) -> bool {
pub fn equals(&self, other: &PodElGamalPubkey) -> bool {
&self.0 == other
}
}
impl TryFrom<Option<ElGamalPubkey>> for OptionalNonZeroElGamalPubkey {
impl TryFrom<Option<PodElGamalPubkey>> for OptionalNonZeroElGamalPubkey {
type Error = ProgramError;
fn try_from(p: Option<ElGamalPubkey>) -> Result<Self, Self::Error> {
fn try_from(p: Option<PodElGamalPubkey>) -> Result<Self, Self::Error> {
match p {
None => Ok(Self(ElGamalPubkey::default())),
None => Ok(Self(PodElGamalPubkey::default())),
Some(elgamal_pubkey) => {
if elgamal_pubkey == ElGamalPubkey::default() {
if elgamal_pubkey == PodElGamalPubkey::default() {
Err(ProgramError::InvalidArgument)
} else {
Ok(Self(elgamal_pubkey))
Expand All @@ -154,26 +153,23 @@ impl TryFrom<Option<ElGamalPubkey>> for OptionalNonZeroElGamalPubkey {
}
}
}
impl From<OptionalNonZeroElGamalPubkey> for Option<ElGamalPubkey> {
impl From<OptionalNonZeroElGamalPubkey> for Option<PodElGamalPubkey> {
fn from(p: OptionalNonZeroElGamalPubkey) -> Self {
if p.0 == ElGamalPubkey::default() {
if p.0 == PodElGamalPubkey::default() {
None
} else {
Some(p.0)
}
}
}

#[cfg(any(feature = "serde-traits", test))]
const OPTIONAL_NONZERO_ELGAMAL_PUBKEY_LEN: usize = 32;

#[cfg(feature = "serde-traits")]
impl Serialize for OptionalNonZeroElGamalPubkey {
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
if self.0 == ElGamalPubkey::default() {
if self.0 == PodElGamalPubkey::default() {
s.serialize_none()
} else {
s.serialize_some(&self.0.to_string())
Expand All @@ -196,18 +192,7 @@ impl<'de> Visitor<'de> for OptionalNonZeroElGamalPubkeyVisitor {
where
E: Error,
{
let bytes = BASE64_STANDARD.decode(v).map_err(Error::custom)?;

if bytes.len() != OPTIONAL_NONZERO_ELGAMAL_PUBKEY_LEN {
return Err(Error::custom(format!(
"Length of base64 decoded bytes is not {}",
OPTIONAL_NONZERO_ELGAMAL_PUBKEY_LEN
)));
}

let mut array = [0; OPTIONAL_NONZERO_ELGAMAL_PUBKEY_LEN];
array.copy_from_slice(&bytes[0..OPTIONAL_NONZERO_ELGAMAL_PUBKEY_LEN]);
let elgamal_pubkey = ElGamalPubkey(array);
let elgamal_pubkey: PodElGamalPubkey = FromStr::from_str(v).map_err(Error::custom)?;
OptionalNonZeroElGamalPubkey::try_from(Some(elgamal_pubkey)).map_err(Error::custom)
}

Expand All @@ -231,7 +216,12 @@ impl<'de> Deserialize<'de> for OptionalNonZeroElGamalPubkey {

#[cfg(test)]
mod tests {
use {super::*, crate::bytemuck::pod_from_bytes, solana_program::pubkey::PUBKEY_BYTES};
use {
super::*,
crate::bytemuck::pod_from_bytes,
base64::{prelude::BASE64_STANDARD, Engine},
solana_program::pubkey::PUBKEY_BYTES,
};

#[test]
fn test_pod_non_zero_option() {
Expand Down Expand Up @@ -290,23 +280,41 @@ mod tests {
assert_eq!(optional_non_zero_pubkey_none, deserialized_none);
}

const OPTIONAL_NONZERO_ELGAMAL_PUBKEY_LEN: usize = 32;

// Unfortunately, the `solana-zk-sdk` does not expose a constructor interface
// to construct `PodRistrettoPoint` from bytes. As a work-around, encode the
// bytes as base64 string and then convert the string to a
// `PodElGamalCiphertext`.
//
// The constructor will be added (and this function removed) with
// `solana-zk-sdk` 2.1.
fn elgamal_pubkey_from_bytes(bytes: &[u8]) -> PodElGamalPubkey {
let string = BASE64_STANDARD.encode(bytes);
std::str::FromStr::from_str(&string).unwrap()
}

#[test]
fn test_pod_non_zero_elgamal_option() {
assert_eq!(
Some(ElGamalPubkey([1; OPTIONAL_NONZERO_ELGAMAL_PUBKEY_LEN])),
Option::<ElGamalPubkey>::from(OptionalNonZeroElGamalPubkey(ElGamalPubkey(
[1; OPTIONAL_NONZERO_ELGAMAL_PUBKEY_LEN]
)))
Some(elgamal_pubkey_from_bytes(
&[1; OPTIONAL_NONZERO_ELGAMAL_PUBKEY_LEN]
)),
Option::<PodElGamalPubkey>::from(OptionalNonZeroElGamalPubkey(
elgamal_pubkey_from_bytes(&[1; OPTIONAL_NONZERO_ELGAMAL_PUBKEY_LEN])
))
);
assert_eq!(
None,
Option::<ElGamalPubkey>::from(OptionalNonZeroElGamalPubkey(ElGamalPubkey(
[0; OPTIONAL_NONZERO_ELGAMAL_PUBKEY_LEN]
)))
Option::<PodElGamalPubkey>::from(OptionalNonZeroElGamalPubkey(
elgamal_pubkey_from_bytes(&[0; OPTIONAL_NONZERO_ELGAMAL_PUBKEY_LEN])
))
);

assert_eq!(
OptionalNonZeroElGamalPubkey(ElGamalPubkey([1; OPTIONAL_NONZERO_ELGAMAL_PUBKEY_LEN])),
OptionalNonZeroElGamalPubkey(elgamal_pubkey_from_bytes(
&[1; OPTIONAL_NONZERO_ELGAMAL_PUBKEY_LEN]
)),
*pod_from_bytes::<OptionalNonZeroElGamalPubkey>(
&[1; OPTIONAL_NONZERO_ELGAMAL_PUBKEY_LEN]
)
Expand All @@ -318,8 +326,9 @@ mod tests {
#[cfg(feature = "serde-traits")]
#[test]
fn test_pod_non_zero_elgamal_option_serde_some() {
let optional_non_zero_elgamal_pubkey_some =
OptionalNonZeroElGamalPubkey(ElGamalPubkey([1; OPTIONAL_NONZERO_ELGAMAL_PUBKEY_LEN]));
let optional_non_zero_elgamal_pubkey_some = OptionalNonZeroElGamalPubkey(
elgamal_pubkey_from_bytes(&[1; OPTIONAL_NONZERO_ELGAMAL_PUBKEY_LEN]),
);
let serialized_some =
serde_json::to_string(&optional_non_zero_elgamal_pubkey_some).unwrap();
assert_eq!(
Expand All @@ -335,8 +344,9 @@ mod tests {
#[cfg(feature = "serde-traits")]
#[test]
fn test_pod_non_zero_elgamal_option_serde_none() {
let optional_non_zero_elgamal_pubkey_none =
OptionalNonZeroElGamalPubkey(ElGamalPubkey([0; OPTIONAL_NONZERO_ELGAMAL_PUBKEY_LEN]));
let optional_non_zero_elgamal_pubkey_none = OptionalNonZeroElGamalPubkey(
elgamal_pubkey_from_bytes(&[0; OPTIONAL_NONZERO_ELGAMAL_PUBKEY_LEN]),
);
let serialized_none =
serde_json::to_string(&optional_non_zero_elgamal_pubkey_none).unwrap();
assert_eq!(&serialized_none, "null");
Expand Down
1 change: 1 addition & 0 deletions token/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ spl-token-2022 = { version = "4.0.0", path = "../program-2022", features = [
"no-entrypoint",
] }
spl-token-client = { version = "0.11.0", path = "../client" }
spl-token-confidential-transfer-proof-generation = { version = "0.1.0", path = "../confidential-transfer/proof-generation" }
spl-token-metadata-interface = { version = "0.4.0", path = "../../token-metadata/interface" }
spl-token-group-interface = { version = "0.3.0", path = "../../token-group/interface" }
spl-associated-token-account = { version = "4.0.0", path = "../../associated-token-account/program", features = [
Expand Down
Loading
Loading