From a84e2beca7004640e6e70b95a4a8e220d6be5399 Mon Sep 17 00:00:00 2001 From: Oliver He Date: Thu, 10 Oct 2024 19:53:01 -0400 Subject: [PATCH] Add federated keyless to the rust sdk (#14905) * Add federated keyless support to rust sdk * update * update local account generator * fix --- Cargo.lock | 1 + .../src/emitter/local_account_generator.rs | 8 +- sdk/Cargo.toml | 1 + sdk/src/types.rs | 332 +++++++++++++++--- testsuite/smoke-test/src/keyless.rs | 103 ++++-- types/src/keyless/test_utils.rs | 52 +-- types/src/transaction/authenticator.rs | 8 + 7 files changed, 401 insertions(+), 104 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 73f7e4ecc3e55..e6096f45511dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3704,6 +3704,7 @@ dependencies = [ "once_cell", "rand 0.7.3", "rand_core 0.5.1", + "serde", "serde_json", "tiny-bip39", "tokio", diff --git a/crates/transaction-emitter-lib/src/emitter/local_account_generator.rs b/crates/transaction-emitter-lib/src/emitter/local_account_generator.rs index 6033d7a49856e..db6c9383c023e 100644 --- a/crates/transaction-emitter-lib/src/emitter/local_account_generator.rs +++ b/crates/transaction-emitter-lib/src/emitter/local_account_generator.rs @@ -2,7 +2,9 @@ use anyhow::bail; // Copyright © Aptos Foundation // SPDX-License-Identifier: Apache-2.0 use aptos_crypto::ed25519::Ed25519PrivateKey; -use aptos_sdk::types::{AccountKey, EphemeralKeyPair, KeylessAccount, LocalAccount}; +use aptos_sdk::types::{ + AccountKey, EphemeralKeyPair, EphemeralPrivateKey, KeylessAccount, LocalAccount, +}; use aptos_transaction_generator_lib::ReliableTransactionSubmitter; use aptos_types::keyless::{Claims, OpenIdSig, Pepper, ZeroKnowledgeSig}; use async_trait::async_trait; @@ -141,7 +143,9 @@ impl LocalAccountGenerator for KeylessAccountGenerator { // Cloning is disabled outside #[cfg(test)] let serialized: &[u8] = &(self.ephemeral_secret_key.to_bytes()); - let esk = Ed25519PrivateKey::try_from(serialized)?; + let esk = EphemeralPrivateKey::Ed25519 { + inner_private_key: Ed25519PrivateKey::try_from(serialized)?, + }; let keyless_account = KeylessAccount::new( &self.iss, diff --git a/sdk/Cargo.toml b/sdk/Cargo.toml index ee2105cbebd55..ed87ebb322a59 100644 --- a/sdk/Cargo.toml +++ b/sdk/Cargo.toml @@ -26,6 +26,7 @@ ed25519-dalek-bip32 = { workspace = true } hex = { workspace = true } move-core-types = { workspace = true } rand_core = { workspace = true } +serde = { workspace = true } serde_json = { workspace = true } tiny-bip39 = { workspace = true } diff --git a/sdk/src/types.rs b/sdk/src/types.rs index 9464ac593fff0..8bf98ac47f441 100644 --- a/sdk/src/types.rs +++ b/sdk/src/types.rs @@ -1,12 +1,13 @@ // Copyright © Aptos Foundation // Parts of the project are originally copyright © Meta Platforms, Inc. // SPDX-License-Identifier: Apache-2.0 - use crate::{ crypto::{ ed25519::{Ed25519PrivateKey, Ed25519PublicKey}, + hash::CryptoHash, signing_message, traits::Uniform, + CryptoMaterialError, }, transaction_builder::TransactionBuilder, types::{ @@ -15,7 +16,7 @@ use crate::{ }, }; use anyhow::{Context, Result}; -use aptos_crypto::{ed25519::Ed25519Signature, PrivateKey, SigningKey}; +use aptos_crypto::{ed25519::Ed25519Signature, secp256r1_ecdsa, PrivateKey, SigningKey}; use aptos_ledger::AptosLedgerError; pub use aptos_types::*; use aptos_types::{ @@ -28,6 +29,8 @@ use aptos_types::{ }; use bip39::{Language, Mnemonic, Seed}; use ed25519_dalek_bip32::{DerivationPath, ExtendedSecretKey}; +use keyless::FederatedKeylessPublicKey; +use serde::{Deserialize, Serialize}; use std::{ str::FromStr, sync::atomic::{AtomicU64, Ordering}, @@ -38,7 +41,7 @@ use std::{ enum LocalAccountAuthenticator { PrivateKey(AccountKey), Keyless(KeylessAccount), - // TODO: Add support for keyless authentication + FederatedKeyless(FederatedKeylessAccount), } impl LocalAccountAuthenticator { @@ -49,26 +52,40 @@ impl LocalAccountAuthenticator { .expect("Signing a txn can't fail") .into_inner(), LocalAccountAuthenticator::Keyless(keyless_account) => { - let proof = keyless_account.zk_sig.proof; - let txn_and_zkp = TransactionAndProof { - message: txn.clone(), - proof: Some(proof), - }; - - let esk = &keyless_account.ephemeral_key_pair.private_key; - let ephemeral_signature = - EphemeralSignature::ed25519(esk.sign(&txn_and_zkp).unwrap()); - - let sig = KeylessSignature { - cert: EphemeralCertificate::ZeroKnowledgeSig(keyless_account.zk_sig.clone()), - jwt_header_json: keyless_account.jwt_header_json.clone(), - exp_date_secs: keyless_account.ephemeral_key_pair.expiry_date_secs, - ephemeral_pubkey: keyless_account.ephemeral_key_pair.public_key.clone(), - ephemeral_signature, - }; - + let sig = self.build_keyless_signature(txn.clone(), &keyless_account); SignedTransaction::new_keyless(txn, keyless_account.public_key.clone(), sig) }, + LocalAccountAuthenticator::FederatedKeyless(federated_keyless_account) => { + let sig = self.build_keyless_signature(txn.clone(), &federated_keyless_account); + SignedTransaction::new_federated_keyless( + txn, + federated_keyless_account.public_key.clone(), + sig, + ) + }, + } + } + + fn build_keyless_signature( + &self, + txn: RawTransaction, + account: &impl CommonKeylessAccount, + ) -> KeylessSignature { + let proof = account.zk_sig().proof; + let txn_and_zkp = TransactionAndProof { + message: txn, + proof: Some(proof), + }; + + let esk = account.ephem_private_key(); + let ephemeral_signature = esk.sign(&txn_and_zkp).unwrap(); + + KeylessSignature { + cert: EphemeralCertificate::ZeroKnowledgeSig(account.zk_sig().clone()), + jwt_header_json: account.jwt_header_json().clone(), + exp_date_secs: account.expiry_date_secs(), + ephemeral_pubkey: account.ephem_public_key().clone(), + ephemeral_signature, } } } @@ -123,6 +140,18 @@ impl LocalAccount { } } + pub fn new_federated_keyless( + address: AccountAddress, + federated_keyless_account: FederatedKeylessAccount, + sequence_number: u64, + ) -> Self { + Self { + address, + auth: LocalAccountAuthenticator::FederatedKeyless(federated_keyless_account), + sequence_number: AtomicU64::new(sequence_number), + } + } + /// Recover an account from derive path (e.g. m/44'/637'/0'/0'/0') and mnemonic phrase, pub fn from_derive_path( derive_path: &str, @@ -242,6 +271,7 @@ impl LocalAccount { match &self.auth { LocalAccountAuthenticator::PrivateKey(key) => key.private_key(), LocalAccountAuthenticator::Keyless(_) => todo!(), + LocalAccountAuthenticator::FederatedKeyless(_) => todo!(), } } @@ -249,6 +279,7 @@ impl LocalAccount { match &self.auth { LocalAccountAuthenticator::PrivateKey(key) => key.public_key(), LocalAccountAuthenticator::Keyless(_) => todo!(), + LocalAccountAuthenticator::FederatedKeyless(_) => todo!(), } } @@ -258,6 +289,9 @@ impl LocalAccount { LocalAccountAuthenticator::Keyless(keyless_account) => { keyless_account.authentication_key() }, + LocalAccountAuthenticator::FederatedKeyless(federated_keyless_account) => { + federated_keyless_account.authentication_key() + }, } } @@ -282,6 +316,7 @@ impl LocalAccount { match &mut self.auth { LocalAccountAuthenticator::PrivateKey(key) => std::mem::replace(key, new_key.into()), LocalAccountAuthenticator::Keyless(_) => todo!(), + LocalAccountAuthenticator::FederatedKeyless(_) => todo!(), } } @@ -468,9 +503,56 @@ impl From for AccountKey { } } +#[derive(Debug, Eq, PartialEq, Deserialize)] +pub enum EphemeralPrivateKey { + Ed25519 { + inner_private_key: Ed25519PrivateKey, + }, + Secp256r1Ecdsa { + inner_private_key: secp256r1_ecdsa::PrivateKey, + }, +} + +impl EphemeralPrivateKey { + pub fn public_key(&self) -> EphemeralPublicKey { + match self { + EphemeralPrivateKey::Ed25519 { inner_private_key } => { + EphemeralPublicKey::ed25519(inner_private_key.public_key()) + }, + EphemeralPrivateKey::Secp256r1Ecdsa { inner_private_key } => { + EphemeralPublicKey::secp256r1_ecdsa(inner_private_key.public_key()) + }, + } + } +} + +impl TryFrom<&[u8]> for EphemeralPrivateKey { + type Error = CryptoMaterialError; + + fn try_from(bytes: &[u8]) -> Result { + bcs::from_bytes::(bytes) + .map_err(|_e| CryptoMaterialError::DeserializationError) + } +} + +impl EphemeralPrivateKey { + pub fn sign( + &self, + message: &T, + ) -> Result { + match self { + EphemeralPrivateKey::Ed25519 { inner_private_key } => Ok(EphemeralSignature::ed25519( + inner_private_key.sign(message)?, + )), + EphemeralPrivateKey::Secp256r1Ecdsa { + inner_private_key: _, + } => todo!(), + } + } +} #[derive(Debug)] pub struct EphemeralKeyPair { - private_key: Ed25519PrivateKey, + private_key: EphemeralPrivateKey, public_key: EphemeralPublicKey, #[allow(dead_code)] nonce: String, @@ -481,11 +563,11 @@ pub struct EphemeralKeyPair { impl EphemeralKeyPair { pub fn new( - private_key: Ed25519PrivateKey, + private_key: EphemeralPrivateKey, expiry_date_secs: u64, blinder: Vec, ) -> Result { - let epk = EphemeralPublicKey::ed25519(private_key.public_key()); + let epk = private_key.public_key(); let nonce = OpenIdSig::reconstruct_oauth_nonce( &blinder, expiry_date_secs, @@ -507,14 +589,15 @@ impl EphemeralKeyPair { pub struct KeylessAccount { public_key: KeylessPublicKey, ephemeral_key_pair: EphemeralKeyPair, - #[allow(dead_code)] - uid_key: String, - #[allow(dead_code)] - uid_val: String, - #[allow(dead_code)] - aud: String, - #[allow(dead_code)] - pepper: Pepper, + zk_sig: ZeroKnowledgeSig, + jwt_header_json: String, + jwt: Option, +} + +#[derive(Debug)] +pub struct FederatedKeylessAccount { + public_key: FederatedKeylessPublicKey, + ephemeral_key_pair: EphemeralKeyPair, zk_sig: ZeroKnowledgeSig, jwt_header_json: String, jwt: Option, @@ -531,18 +614,10 @@ impl KeylessAccount { pepper: Pepper, zk_sig: ZeroKnowledgeSig, ) -> Result { - let idc = IdCommitment::new_from_preimage(&pepper, aud, uid_key, uid_val)?; - let public_key = KeylessPublicKey { - iss_val: iss.to_owned(), - idc, - }; + let public_key = create_keyless_public_key(iss, aud, uid_key, uid_val, &pepper)?; Ok(Self { public_key, ephemeral_key_pair, - uid_key: uid_key.to_string(), - uid_val: uid_val.to_string(), - aud: aud.to_string(), - pepper, zk_sig, jwt_header_json: jwt_header_json.to_string(), jwt: None, @@ -556,28 +631,23 @@ impl KeylessAccount { pepper: Option, zk_sig: Option, ) -> Result { - let parts: Vec<&str> = jwt.split('.').collect(); - let header_bytes = base64::decode(parts.first().context("jwt malformed")?)?; - let jwt_header_json = String::from_utf8(header_bytes)?; - let jwt_payload_json = - base64::decode_config(parts.get(1).context("jwt malformed")?, base64::URL_SAFE)?; - let claims: Claims = serde_json::from_slice(&jwt_payload_json)?; - + let claims = extract_claims_from_jwt(jwt)?; let uid_key = uid_key.unwrap_or("sub").to_string(); let uid_val = claims.get_uid_val(&uid_key)?; let aud = claims.oidc_claims.aud; - let account = Self::new( + let mut account = Self::new( &claims.oidc_claims.iss, &aud, &uid_key, &uid_val, - &jwt_header_json, + &extract_header_json_from_jwt(jwt)?, ephemeral_key_pair, pepper.expect("pepper fetch not implemented"), zk_sig.expect("proof fetch not implemented"), )?; - Ok(account.set_jwt(jwt)) + account.jwt = Some(jwt.to_string()); + Ok(account) } pub fn authentication_key(&self) -> AuthenticationKey { @@ -587,10 +657,164 @@ impl KeylessAccount { pub fn public_key(&self) -> &KeylessPublicKey { &self.public_key } +} + +impl FederatedKeylessAccount { + pub fn new( + iss: &str, + aud: &str, + uid_key: &str, + uid_val: &str, + jwt_header_json: &str, + ephemeral_key_pair: EphemeralKeyPair, + pepper: Pepper, + zk_sig: ZeroKnowledgeSig, + jwk_addr: AccountAddress, + ) -> Result { + let public_key = + create_federated_public_key(iss, aud, uid_key, uid_val, &pepper, jwk_addr)?; + Ok(Self { + public_key, + ephemeral_key_pair, + zk_sig, + jwt_header_json: jwt_header_json.to_string(), + jwt: None, + }) + } + + pub fn new_from_jwt( + jwt: &str, + ephemeral_key_pair: EphemeralKeyPair, + jwk_addr: AccountAddress, + uid_key: Option<&str>, + pepper: Option, + zk_sig: Option, + ) -> Result { + let claims = extract_claims_from_jwt(jwt)?; + let uid_key = uid_key.unwrap_or("sub").to_string(); + let uid_val = claims.get_uid_val(&uid_key)?; + let aud = claims.oidc_claims.aud; + + let mut account = Self::new( + &claims.oidc_claims.iss, + &aud, + &uid_key, + &uid_val, + &extract_header_json_from_jwt(jwt)?, + ephemeral_key_pair, + pepper.expect("pepper fetch not implemented"), + zk_sig.expect("proof fetch not implemented"), + jwk_addr, + )?; + account.jwt = Some(jwt.to_string()); + Ok(account) + } + + pub fn authentication_key(&self) -> AuthenticationKey { + AuthenticationKey::any_key(AnyPublicKey::federated_keyless(self.public_key.clone())) + } + + pub fn public_key(&self) -> &FederatedKeylessPublicKey { + &self.public_key + } +} + +fn create_keyless_public_key( + iss: &str, + aud: &str, + uid_key: &str, + uid_val: &str, + pepper: &Pepper, +) -> Result { + let idc = IdCommitment::new_from_preimage(pepper, aud, uid_key, uid_val)?; + Ok(KeylessPublicKey { + iss_val: iss.to_owned(), + idc, + }) +} + +fn create_federated_public_key( + iss: &str, + aud: &str, + uid_key: &str, + uid_val: &str, + pepper: &Pepper, + jwk_addr: AccountAddress, +) -> Result { + let idc = IdCommitment::new_from_preimage(pepper, aud, uid_key, uid_val)?; + Ok(FederatedKeylessPublicKey { + pk: KeylessPublicKey { + iss_val: iss.to_owned(), + idc, + }, + jwk_addr, + }) +} + +pub fn extract_claims_from_jwt(jwt: &str) -> Result { + let parts: Vec<&str> = jwt.split('.').collect(); + let jwt_payload_json = + base64::decode_config(parts.get(1).context("jwt malformed")?, base64::URL_SAFE)?; + let claims: Claims = serde_json::from_slice(&jwt_payload_json)?; + Ok(claims) +} + +pub fn extract_header_json_from_jwt(jwt: &str) -> Result { + let parts: Vec<&str> = jwt.split('.').collect(); + let header_bytes = base64::decode(parts.first().context("jwt malformed")?)?; + + Ok(String::from_utf8(header_bytes)?) +} + +trait CommonKeylessAccount { + fn zk_sig(&self) -> &ZeroKnowledgeSig; + fn ephem_private_key(&self) -> &EphemeralPrivateKey; + fn ephem_public_key(&self) -> &EphemeralPublicKey; + fn jwt_header_json(&self) -> &String; + fn expiry_date_secs(&self) -> u64; +} + +impl CommonKeylessAccount for &KeylessAccount { + fn zk_sig(&self) -> &ZeroKnowledgeSig { + &self.zk_sig + } + + fn ephem_private_key(&self) -> &EphemeralPrivateKey { + &self.ephemeral_key_pair.private_key + } + + fn ephem_public_key(&self) -> &EphemeralPublicKey { + &self.ephemeral_key_pair.public_key + } + + fn jwt_header_json(&self) -> &String { + &self.jwt_header_json + } + + fn expiry_date_secs(&self) -> u64 { + self.ephemeral_key_pair.expiry_date_secs + } +} + +impl CommonKeylessAccount for &FederatedKeylessAccount { + fn zk_sig(&self) -> &ZeroKnowledgeSig { + &self.zk_sig + } + + fn ephem_private_key(&self) -> &EphemeralPrivateKey { + &self.ephemeral_key_pair.private_key + } + + fn ephem_public_key(&self) -> &EphemeralPublicKey { + &self.ephemeral_key_pair.public_key + } + + fn jwt_header_json(&self) -> &String { + &self.jwt_header_json + } - pub fn set_jwt(mut self, jwt: &str) -> Self { - self.jwt = Some(jwt.to_string()); - self + fn expiry_date_secs(&self) -> u64 { + self.ephemeral_key_pair.expiry_date_secs } } diff --git a/testsuite/smoke-test/src/keyless.rs b/testsuite/smoke-test/src/keyless.rs index d7af6aafb1175..6e847afbc5dc5 100644 --- a/testsuite/smoke-test/src/keyless.rs +++ b/testsuite/smoke-test/src/keyless.rs @@ -10,7 +10,9 @@ use aptos_crypto::{ use aptos_forge::{AptosPublicInfo, LocalSwarm, NodeExt, Swarm, SwarmExt}; use aptos_logger::{debug, info}; use aptos_rest_client::Client; -use aptos_sdk::types::{EphemeralKeyPair, KeylessAccount, LocalAccount}; +use aptos_sdk::types::{ + EphemeralKeyPair, EphemeralPrivateKey, FederatedKeylessAccount, KeylessAccount, LocalAccount, +}; use aptos_types::{ jwks::{ jwk::{JWKMoveStruct, JWK}, @@ -21,11 +23,11 @@ use aptos_types::{ get_public_inputs_hash, test_utils::{ self, get_groth16_sig_and_pk_for_upgraded_vk, get_sample_aud, get_sample_epk_blinder, - get_sample_esk, get_sample_exp_date, get_sample_groth16_sig_and_fed_pk, - get_sample_groth16_sig_and_pk, get_sample_groth16_sig_and_pk_no_extra_field, - get_sample_iss, get_sample_jwk, get_sample_jwt_header_json, get_sample_jwt_token, - get_sample_openid_sig_and_pk, get_sample_pepper, get_sample_tw_sk, get_sample_uid_key, - get_sample_uid_val, get_sample_zk_sig, get_upgraded_vk, + get_sample_esk, get_sample_exp_date, get_sample_groth16_sig_and_pk, + get_sample_groth16_sig_and_pk_no_extra_field, get_sample_iss, get_sample_jwk, + get_sample_jwt_header_json, get_sample_jwt_token, get_sample_openid_sig_and_pk, + get_sample_pepper, get_sample_tw_sk, get_sample_uid_key, get_sample_uid_val, + get_sample_zk_sig, get_upgraded_vk, }, AnyKeylessPublicKey, Configuration, EphemeralCertificate, Groth16ProofAndStatement, Groth16VerificationKey, KeylessPublicKey, KeylessSignature, TransactionAndProof, @@ -248,7 +250,7 @@ async fn federated_keyless_scenario( install_fed_jwk: bool, expect_txn_succeed: bool, ) { - let (tw_sk, config, jwk, swarm, mut cli, _) = setup_local_net_inner(set_feature_flag).await; + let (_tw_sk, _config, _jwk, swarm, mut cli, _) = setup_local_net_inner(set_feature_flag).await; let root_addr = swarm.chain_info().root_account().address(); let _root_idx = cli.add_account_with_address_to_cli(swarm.root_key(), root_addr); @@ -317,19 +319,63 @@ script {{ assert_eq!(Some(true), txn_result.unwrap().success); } - // For simplicity we use the root account as the jwk owner. - let (sig, pk) = get_sample_groth16_sig_and_fed_pk(root_addr); let mut info = swarm.aptos_public_info(); - let signed_txn = sign_transaction_any_keyless_pk( - &mut info, - sig.clone(), - AnyKeylessPublicKey::Federated(pk), - &jwk, - &config, - Some(&tw_sk), - 1, + + let esk = EphemeralPrivateKey::Ed25519 { + inner_private_key: get_sample_esk(), + }; + let ephemeral_key_pair = + EphemeralKeyPair::new(esk, get_sample_exp_date(), get_sample_epk_blinder()).unwrap(); + let federated_keyless_account = FederatedKeylessAccount::new_from_jwt( + &get_sample_jwt_token(), + ephemeral_key_pair, + root_addr, + None, + Some(get_sample_pepper()), + Some(get_sample_zk_sig()), ) - .await; + .unwrap(); + + let federated_keyless_public_key = federated_keyless_account.public_key().clone(); + + let local_account = LocalAccount::new_federated_keyless( + federated_keyless_account + .authentication_key() + .account_address(), + federated_keyless_account, + 0, + ); + + // If the account does not exist, create it. + if info.account_exists(local_account.address()).await.is_err() { + info!( + "{} account does not exist. Creating...", + local_account.address().to_hex_literal() + ); + info.sync_root_account_sequence_number().await; + info.create_user_account_with_any_key(&AnyPublicKey::FederatedKeyless { + public_key: federated_keyless_public_key, + }) + .await + .unwrap(); + info.mint(local_account.address(), 10_000_000_000) + .await + .unwrap(); + } + info.sync_root_account_sequence_number().await; + let recipient = info + .create_and_fund_user_account(20_000_000_000) + .await + .unwrap(); + + let txn_builder = info + .transaction_factory() + .payload(aptos_stdlib::aptos_coin_transfer( + recipient.address(), + 1_000_000, + )); + + let signed_txn = local_account.sign_with_transaction_builder(txn_builder); let result = swarm .aptos_public_info() @@ -384,10 +430,11 @@ async fn test_keyless_no_training_wheels_groth16_verifies() { async fn test_keyless_groth16_verifies_using_rust_sdk() { let (_tw_sk, _, _, swarm, mut cli, root_idx) = setup_local_net().await; - let blinder = get_sample_epk_blinder(); - let exp_date = get_sample_exp_date(); - let esk = get_sample_esk(); - let ephemeral_key_pair = EphemeralKeyPair::new(esk, exp_date, blinder).unwrap(); + let esk = EphemeralPrivateKey::Ed25519 { + inner_private_key: get_sample_esk(), + }; + let ephemeral_key_pair = + EphemeralKeyPair::new(esk, get_sample_exp_date(), get_sample_epk_blinder()).unwrap(); let mut info = swarm.aptos_public_info(); let keyless_account = KeylessAccount::new( @@ -443,15 +490,15 @@ async fn test_keyless_groth16_verifies_using_rust_sdk() { async fn test_keyless_groth16_verifies_using_rust_sdk_from_jwt() { let (_tw_sk, _, _, swarm, mut cli, root_idx) = setup_local_net().await; - let jwt = get_sample_jwt_token(); - let blinder = get_sample_epk_blinder(); - let exp_date = get_sample_exp_date(); - let esk = get_sample_esk(); - let ephemeral_key_pair = EphemeralKeyPair::new(esk, exp_date, blinder).unwrap(); + let esk = EphemeralPrivateKey::Ed25519 { + inner_private_key: get_sample_esk(), + }; + let ephemeral_key_pair = + EphemeralKeyPair::new(esk, get_sample_exp_date(), get_sample_epk_blinder()).unwrap(); let mut info = swarm.aptos_public_info(); let keyless_account = KeylessAccount::new_from_jwt( - &jwt, + &get_sample_jwt_token(), ephemeral_key_pair, None, Some(get_sample_pepper()), diff --git a/types/src/keyless/test_utils.rs b/types/src/keyless/test_utils.rs index 250175d9428b2..c8babbd5913af 100644 --- a/types/src/keyless/test_utils.rs +++ b/types/src/keyless/test_utils.rs @@ -113,13 +113,41 @@ pub fn get_sample_groth16_zkp_and_statement() -> Groth16ProofAndStatement { pub fn get_sample_zk_sig() -> ZeroKnowledgeSig { let proof = *SAMPLE_PROOF; - ZeroKnowledgeSig { + let mut zks = ZeroKnowledgeSig { proof: proof.into(), extra_field: Some(SAMPLE_JWT_EXTRA_FIELD.to_string()), exp_horizon_secs: SAMPLE_EXP_HORIZON_SECS, override_aud_val: None, training_wheels_signature: None, - } + }; + + let sig = KeylessSignature { + cert: EphemeralCertificate::ZeroKnowledgeSig(zks.clone()), + jwt_header_json: SAMPLE_JWT_HEADER_JSON.to_string(), + exp_date_secs: SAMPLE_EXP_DATE, + ephemeral_pubkey: SAMPLE_EPK.clone(), + ephemeral_signature: DUMMY_EPHEMERAL_SIGNATURE.clone(), + }; + + let public_inputs_hash = fr_to_bytes_le( + &get_public_inputs_hash( + &sig, + &SAMPLE_PK.clone(), + &SAMPLE_JWK, + &Configuration::new_for_testing(), + ) + .unwrap(), + ); + + let proof_and_statement = Groth16ProofAndStatement { + proof, + public_inputs_hash, + }; + + zks.training_wheels_signature = Some(EphemeralSignature::ed25519( + get_sample_tw_sk().sign(&proof_and_statement).unwrap(), + )); + zks } /// Note: Does not have a valid ephemeral signature. Use the SAMPLE_ESK to compute one over the @@ -169,15 +197,7 @@ pub fn get_random_simulated_groth16_sig_and_pk() -> ( /// Note: Does not have a valid ephemeral signature. Use the SAMPLE_ESK to compute one over the /// desired TXN. pub fn get_sample_groth16_sig_and_pk() -> (KeylessSignature, KeylessPublicKey) { - let proof = *SAMPLE_PROOF; - - let zks = ZeroKnowledgeSig { - proof: proof.into(), - extra_field: Some(SAMPLE_JWT_EXTRA_FIELD.to_string()), - exp_horizon_secs: SAMPLE_EXP_HORIZON_SECS, - override_aud_val: None, - training_wheels_signature: None, - }; + let zks = get_sample_zk_sig(); let sig = KeylessSignature { cert: EphemeralCertificate::ZeroKnowledgeSig(zks.clone()), @@ -193,15 +213,7 @@ pub fn get_sample_groth16_sig_and_pk() -> (KeylessSignature, KeylessPublicKey) { pub fn get_sample_groth16_sig_and_fed_pk( jwk_addr: AccountAddress, ) -> (KeylessSignature, FederatedKeylessPublicKey) { - let proof = *SAMPLE_PROOF; - - let zks = ZeroKnowledgeSig { - proof: proof.into(), - extra_field: Some(SAMPLE_JWT_EXTRA_FIELD.to_string()), - exp_horizon_secs: SAMPLE_EXP_HORIZON_SECS, - override_aud_val: None, - training_wheels_signature: None, - }; + let zks = get_sample_zk_sig(); let sig = KeylessSignature { cert: EphemeralCertificate::ZeroKnowledgeSig(zks.clone()), diff --git a/types/src/transaction/authenticator.rs b/types/src/transaction/authenticator.rs index f61f698b1ef89..f5237eef056df 100644 --- a/types/src/transaction/authenticator.rs +++ b/types/src/transaction/authenticator.rs @@ -1164,6 +1164,10 @@ impl EphemeralSignature { Self::Ed25519 { signature } } + pub fn web_authn(signature: PartialAuthenticatorAssertionResponse) -> Self { + Self::WebAuthn { signature } + } + pub fn verify( &self, message: &T, @@ -1228,6 +1232,10 @@ impl EphemeralPublicKey { Self::Ed25519 { public_key } } + pub fn secp256r1_ecdsa(public_key: secp256r1_ecdsa::PublicKey) -> Self { + Self::Secp256r1Ecdsa { public_key } + } + pub fn to_bytes(&self) -> Vec { bcs::to_bytes(self).expect("Only unhandleable errors happen here.") }