Skip to content

Commit

Permalink
[zk-sdk] Add functions to derive ElGamalKeypair and AeKey from `S…
Browse files Browse the repository at this point in the history
…ignature` (solana-labs#1717)
  • Loading branch information
samkim-crypto authored and gregcusack committed Jun 14, 2024
1 parent a33c46f commit 2038d8a
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 14 deletions.
15 changes: 13 additions & 2 deletions zk-sdk/src/encryption/auth_encryption.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,22 @@ impl AeKey {
return Err(SignerError::Custom("Rejecting default signature".into()));
}

Ok(Self::seed_from_signature(&signature))
}

/// Derive an authenticated encryption key from a signature.
pub fn new_from_signature(signature: &Signature) -> Result<Self, Box<dyn error::Error>> {
let seed = Self::seed_from_signature(signature);
Self::from_seed(&seed)
}

/// Derive a seed from a signature used to generate an authenticated encryption key.
pub fn seed_from_signature(signature: &Signature) -> Vec<u8> {
let mut hasher = Sha3_512::new();
hasher.update(signature.as_ref());
hasher.update(signature);
let result = hasher.finalize();

Ok(result.to_vec())
result.to_vec()
}

/// Generates a random authenticated encryption key.
Expand Down
40 changes: 29 additions & 11 deletions zk-sdk/src/encryption/elgamal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ impl ElGamal {
/// Generates an ElGamal keypair.
///
/// This function is randomized. It internally samples a scalar element using `OsRng`.
#[allow(non_snake_case)]
fn keygen() -> ElGamalKeypair {
// secret scalar should be non-zero except with negligible probability
let mut s = Scalar::random(&mut OsRng);
Expand All @@ -70,7 +69,6 @@ impl ElGamal {
/// Generates an ElGamal keypair from a scalar input that determines the ElGamal private key.
///
/// This function panics if the input scalar is zero, which is not a valid key.
#[allow(non_snake_case)]
fn keygen_with_scalar(s: &Scalar) -> ElGamalKeypair {
let secret = ElGamalSecretKey(*s);
let public = ElGamalPubkey::new(&secret);
Expand Down Expand Up @@ -149,13 +147,19 @@ pub struct ElGamalKeypair {
impl ElGamalKeypair {
/// Create an ElGamal keypair from an ElGamal public key and an ElGamal secret key.
///
/// An ElGamal keypair should never be instantiated manually; `ElGamalKeypair::new_rand` or
/// `ElGamalKeypair::new_from_signer` should be used instead. This function exists to create
/// custom ElGamal keypairs for tests.
/// An ElGamal keypair should never be instantiated manually; `ElGamalKeypair::new`,
/// `ElGamalKeypair::new_rand` or `ElGamalKeypair::new_from_signer` should be used instead.
/// This function exists to create custom ElGamal keypairs for tests.
pub fn new_for_tests(public: ElGamalPubkey, secret: ElGamalSecretKey) -> Self {
Self { public, secret }
}

/// Convert an ElGamal secret key to an ElGamal keypair.
pub fn new(secret: ElGamalSecretKey) -> Self {
let public = ElGamalPubkey::new(&secret);
Self { public, secret }
}

/// Deterministically derives an ElGamal keypair from a Solana signer and a public seed.
///
/// This function exists for applications where a user may not wish to maintain a Solana signer
Expand All @@ -168,14 +172,18 @@ impl ElGamalKeypair {
/// wallets, the signing key is not exposed in the API. Therefore, this function uses a signer
/// to sign a public seed and the resulting signature is then hashed to derive an ElGamal
/// keypair.
#[allow(non_snake_case)]
pub fn new_from_signer(
signer: &dyn Signer,
public_seed: &[u8],
) -> Result<Self, Box<dyn error::Error>> {
let secret = ElGamalSecretKey::new_from_signer(signer, public_seed)?;
let public = ElGamalPubkey::new(&secret);
Ok(ElGamalKeypair { public, secret })
Ok(Self::new(secret))
}

/// Derive an ElGamal keypair from a signature.
pub fn new_from_signature(signature: &Signature) -> Result<Self, Box<dyn error::Error>> {
let secret = ElGamalSecretKey::new_from_signature(signature)?;
Ok(Self::new(secret))
}

/// Generates the public and secret keys for ElGamal encryption.
Expand Down Expand Up @@ -305,7 +313,6 @@ impl EncodableKeypair for ElGamalKeypair {
pub struct ElGamalPubkey(RistrettoPoint);
impl ElGamalPubkey {
/// Derives the `ElGamalPubkey` that uniquely corresponds to an `ElGamalSecretKey`.
#[allow(non_snake_case)]
pub fn new(secret: &ElGamalSecretKey) -> Self {
let s = &secret.0;
assert!(s != &Scalar::zero());
Expand Down Expand Up @@ -428,11 +435,23 @@ impl ElGamalSecretKey {
return Err(SignerError::Custom("Rejecting default signatures".into()));
}

Ok(Self::seed_from_signature(&signature))
}

/// Derive an ElGamal secret key from a signature.
pub fn new_from_signature(signature: &Signature) -> Result<Self, Box<dyn error::Error>> {
let seed = Self::seed_from_signature(signature);
let key = Self::from_seed(&seed)?;
Ok(key)
}

/// Derive an ElGamal secret key from a signature.
pub fn seed_from_signature(signature: &Signature) -> Vec<u8> {
let mut hasher = Sha3_512::new();
hasher.update(signature.as_ref());
let result = hasher.finalize();

Ok(result.to_vec())
result.to_vec()
}

/// Randomly samples an ElGamal secret key.
Expand Down Expand Up @@ -563,7 +582,6 @@ impl ConstantTimeEq for ElGamalSecretKey {
}

/// Ciphertext for the ElGamal encryption scheme.
#[allow(non_snake_case)]
#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
pub struct ElGamalCiphertext {
pub commitment: PedersenCommitment,
Expand Down
1 change: 0 additions & 1 deletion zk-sdk/src/encryption/pedersen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ impl Pedersen {
/// corresponding Pedersen commitment.
///
/// This function is deterministic.
#[allow(non_snake_case)]
pub fn with<T: Into<Scalar>>(amount: T, opening: &PedersenOpening) -> PedersenCommitment {
let x: Scalar = amount.into();
let r = opening.get_scalar();
Expand Down

0 comments on commit 2038d8a

Please sign in to comment.