Skip to content

Commit ea81432

Browse files
authored
Flag to save tee key to local file (#286)
* Flag to save tee key to lcoal file * fix error handling * lint * comments * atomic file creation and permission
1 parent 28f8cac commit ea81432

File tree

3 files changed

+96
-21
lines changed

3 files changed

+96
-21
lines changed

crates/op-rbuilder/src/flashtestations/args.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,14 @@ pub struct FlashtestationsArgs {
3333
)]
3434
pub debug_tee_key_seed: String,
3535

36+
/// Path to save ephemeral TEE key between restarts
37+
#[arg(
38+
long = "flashtestations.tee-key-path",
39+
env = "FLASHTESTATIONS_TEE_KEY_PATH",
40+
default_value = "/run/flashtestation.key"
41+
)]
42+
pub flashtestations_key_path: String,
43+
3644
// Remote url for attestations
3745
#[arg(
3846
long = "flashtestations.quote-provider",

crates/op-rbuilder/src/flashtestations/service.rs

Lines changed: 76 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
1-
use alloy_primitives::{Bytes, keccak256};
1+
use alloy_primitives::{B256, Bytes, keccak256};
22
use reth_node_builder::BuilderContext;
33
use reth_provider::StateProvider;
44
use reth_revm::State;
55
use revm::Database;
6-
use std::fmt::Debug;
6+
use std::{
7+
fmt::Debug,
8+
fs::{self, OpenOptions},
9+
io::Write,
10+
os::unix::fs::OpenOptionsExt,
11+
path::Path,
12+
};
713
use tracing::{info, warn};
814

915
use crate::{
@@ -12,7 +18,7 @@ use crate::{
1218
},
1319
primitives::reth::ExecutionInfo,
1420
traits::NodeBounds,
15-
tx_signer::{Signer, generate_ethereum_keypair, generate_key_from_seed},
21+
tx_signer::{Signer, generate_key_from_seed, generate_signer},
1622
};
1723

1824
use super::{
@@ -28,21 +34,16 @@ pub async fn bootstrap_flashtestations<Node>(
2834
where
2935
Node: NodeBounds,
3036
{
31-
let (private_key, public_key, address) = if args.debug {
32-
info!("Flashtestations debug mode enabled, generating debug key");
33-
// Generate deterministic key for debugging purposes
34-
generate_key_from_seed(&args.debug_tee_key_seed)
35-
} else {
36-
generate_ethereum_keypair()
37-
};
37+
let tee_service_signer = load_or_generate_tee_key(
38+
&args.flashtestations_key_path,
39+
args.debug,
40+
&args.debug_tee_key_seed,
41+
)?;
3842

39-
info!("Flashtestations key generated: {}", address);
40-
41-
let tee_service_signer = Signer {
42-
address,
43-
pubkey: public_key,
44-
secret: private_key,
45-
};
43+
info!(
44+
"Flashtestations TEE address: {}",
45+
tee_service_signer.address
46+
);
4647

4748
let funding_key = args
4849
.funding_key
@@ -135,6 +136,64 @@ where
135136
Ok(flashtestations_builder_tx)
136137
}
137138

139+
/// Load ephemeral TEE key from file, or generate and save a new one
140+
fn load_or_generate_tee_key(key_path: &str, debug: bool, debug_seed: &str) -> eyre::Result<Signer> {
141+
if debug {
142+
info!("Flashtestations debug mode enabled, generating debug key from seed");
143+
return Ok(generate_key_from_seed(debug_seed));
144+
}
145+
146+
let path = Path::new(key_path);
147+
148+
if let Some(signer) = load_tee_key(path) {
149+
return Ok(signer);
150+
}
151+
152+
// Generate new key
153+
info!("Generating new ephemeral TEE key");
154+
let signer = generate_signer();
155+
156+
let key_hex = hex::encode(signer.secret.secret_bytes());
157+
158+
// Create file with 0600 permissions atomically
159+
OpenOptions::new()
160+
.write(true)
161+
.create(true)
162+
.truncate(true)
163+
.mode(0o600)
164+
.open(path)
165+
.and_then(|mut file| file.write_all(key_hex.as_bytes()))
166+
.inspect_err(|e| warn!("Failed to write key to {}: {:?}", key_path, e))
167+
.ok();
168+
169+
Ok(signer)
170+
}
171+
172+
fn load_tee_key(path: &Path) -> Option<Signer> {
173+
// Try to load existing key
174+
if !path.exists() {
175+
return None;
176+
}
177+
178+
info!("Loading TEE key from {:?}", path);
179+
let key_hex = fs::read_to_string(path)
180+
.inspect_err(|e| warn!("failed to read key file: {:?}", e))
181+
.ok()?;
182+
183+
let secret_bytes = B256::try_from(
184+
hex::decode(key_hex.trim())
185+
.inspect_err(|e| warn!("failed to decode hex from file {:?}", e))
186+
.ok()?
187+
.as_slice(),
188+
)
189+
.inspect_err(|e| warn!("failed to parse key from file: {:?}", e))
190+
.ok()?;
191+
192+
Signer::try_from_secret(secret_bytes)
193+
.inspect_err(|e| warn!("failed to create signer from key: {:?}", e))
194+
.ok()
195+
}
196+
138197
#[derive(Debug, Clone)]
139198
pub struct FlashtestationsBuilderTx {}
140199

crates/op-rbuilder/src/tx_signer.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ impl FromStr for Signer {
7474
}
7575
}
7676

77-
pub fn generate_ethereum_keypair() -> (SecretKey, PublicKey, Address) {
77+
pub fn generate_signer() -> Signer {
7878
let secp = Secp256k1::new();
7979

8080
// Generate cryptographically secure random private key
@@ -86,7 +86,11 @@ pub fn generate_ethereum_keypair() -> (SecretKey, PublicKey, Address) {
8686
// Derive Ethereum address
8787
let address = public_key_to_address(&public_key);
8888

89-
(private_key, public_key, address)
89+
Signer {
90+
address,
91+
pubkey: public_key,
92+
secret: private_key,
93+
}
9094
}
9195

9296
/// Converts a public key to an Ethereum address
@@ -103,7 +107,7 @@ pub fn public_key_to_address(public_key: &PublicKey) -> Address {
103107

104108
// Generate a key deterministically from a seed for debug and testing
105109
// Do not use in production
106-
pub fn generate_key_from_seed(seed: &str) -> (SecretKey, PublicKey, Address) {
110+
pub fn generate_key_from_seed(seed: &str) -> Signer {
107111
// Hash the seed
108112
let mut hasher = Sha256::new();
109113
hasher.update(seed.as_bytes());
@@ -115,7 +119,11 @@ pub fn generate_key_from_seed(seed: &str) -> (SecretKey, PublicKey, Address) {
115119
let public_key = PublicKey::from_secret_key(&secp, &private_key);
116120
let address = public_key_to_address(&public_key);
117121

118-
(private_key, public_key, address)
122+
Signer {
123+
address,
124+
pubkey: public_key,
125+
secret: private_key,
126+
}
119127
}
120128

121129
#[cfg(test)]

0 commit comments

Comments
 (0)