Skip to content

Commit 650b339

Browse files
authored
Merge pull request #1011 from openmina/fix-panic
Include the encrypted private key in `failed_block_proof_*.binprot`
2 parents 104abee + 8ed6685 commit 650b339

File tree

7 files changed

+139
-25
lines changed

7 files changed

+139
-25
lines changed

Cargo.lock

Lines changed: 6 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ledger/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ reqwest = { version = "0.11.24", features = ["blocking"] }
9090
rand_pcg = "0.3"
9191
rand_seeder = "0.2"
9292
tuple-map = "0.4.0"
93+
rsa = "0.9"
9394

9495
[target.'cfg(target_family = "wasm")'.dev-dependencies]
9596
wasm-bindgen-test = "0.3.0"

ledger/src/proofs/transaction.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4142,6 +4142,7 @@ pub(super) mod tests {
41424142
use mina_p2p_messages::binprot::{
41434143
self,
41444144
macros::{BinProtRead, BinProtWrite},
4145+
BinProtRead,
41454146
};
41464147

41474148
use crate::{
@@ -4721,6 +4722,67 @@ pub(super) mod tests {
47214722
let _sum = dbg!(sha256_sum(&proof_json));
47224723
}
47234724

4725+
#[test]
4726+
#[ignore]
4727+
fn make_rsa_key() {
4728+
use rsa::pkcs1::{EncodeRsaPrivateKey, EncodeRsaPublicKey};
4729+
use rsa::pkcs8::LineEnding::LF;
4730+
use rsa::{RsaPrivateKey, RsaPublicKey};
4731+
4732+
let mut rng = rand::thread_rng();
4733+
let bits = 2048;
4734+
let priv_key = RsaPrivateKey::new(&mut rng, bits).expect("failed to generate a key");
4735+
let pub_key = RsaPublicKey::from(&priv_key);
4736+
4737+
let priv_key = priv_key.to_pkcs1_pem(LF).unwrap();
4738+
let priv_key: &str = priv_key.as_ref();
4739+
println!("private:\n{}", priv_key);
4740+
4741+
let pub_key = pub_key.to_pkcs1_pem(LF).unwrap();
4742+
println!("public:\n{}", pub_key);
4743+
}
4744+
4745+
#[test]
4746+
fn add_private_key_to_block_proof_input() {
4747+
use mina_p2p_messages::binprot::BinProtWrite;
4748+
use rsa::pkcs1::DecodeRsaPrivateKey;
4749+
use rsa::Pkcs1v15Encrypt;
4750+
4751+
#[derive(binprot::macros::BinProtRead)]
4752+
struct DumpBlockProof {
4753+
input: Box<v2::ProverExtendBlockchainInputStableV2>,
4754+
key: Vec<u8>,
4755+
}
4756+
4757+
let rsa_private_key = {
4758+
let Ok(string) = std::fs::read_to_string("~/.openmina/debug/rsa.priv") else {
4759+
eprintln!("Missing private key");
4760+
return;
4761+
};
4762+
rsa::RsaPrivateKey::from_pkcs1_pem(&string).unwrap()
4763+
};
4764+
4765+
let DumpBlockProof { mut input, key } = {
4766+
let Ok(data) = std::fs::read("/tmp/block_proof.binprot") else {
4767+
eprintln!("Missing block proof");
4768+
return;
4769+
};
4770+
DumpBlockProof::binprot_read(&mut data.as_slice()).unwrap()
4771+
};
4772+
4773+
let producer_private_key = {
4774+
let producer_private_key = rsa_private_key.decrypt(Pkcs1v15Encrypt, &key).unwrap();
4775+
v2::SignatureLibPrivateKeyStableV1::binprot_read(&mut producer_private_key.as_slice())
4776+
.unwrap()
4777+
};
4778+
4779+
input.prover_state.producer_private_key = producer_private_key;
4780+
4781+
let mut file = std::fs::File::create("/tmp/block_proof_with_key.binprot").unwrap();
4782+
input.binprot_write(&mut file).unwrap();
4783+
file.sync_all().unwrap();
4784+
}
4785+
47244786
#[test]
47254787
fn test_proofs() {
47264788
let base_dir = Path::new(env!("CARGO_MANIFEST_DIR"))

node/account/src/secret_key.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,12 @@ impl From<AccountSecretKey> for Keypair {
132132
}
133133
}
134134

135+
impl From<&AccountSecretKey> for SignatureLibPrivateKeyStableV1 {
136+
fn from(value: &AccountSecretKey) -> Self {
137+
Self(BigInt::from_bytes(value.to_bytes()))
138+
}
139+
}
140+
135141
impl From<AccountSecretKey> for SignatureLibPrivateKeyStableV1 {
136142
fn from(value: AccountSecretKey) -> Self {
137143
Self(BigInt::from_bytes(value.to_bytes()))

node/common/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ ark-ff = { workspace = true }
2222

2323
node = { path = "../../node", features = ["replay"] }
2424
openmina-core = { path = "../../core" }
25+
rsa = "0.9"
2526

2627
[target.'cfg(target_family = "wasm")'.dependencies]
2728
redux = { workspace = true }

node/common/src/service/block_producer/mod.rs

Lines changed: 54 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,16 @@ use ledger::proofs::{
66
block::BlockParams, generate_block_proof, provers::BlockProver, transaction::ProofError,
77
};
88
use mina_p2p_messages::{
9-
binprot::BinProtWrite,
10-
v2::{MinaBaseProofStableV2, ProverExtendBlockchainInputStableV2, StateHash},
9+
bigint::BigInt,
10+
binprot::{self, BinProtWrite},
11+
v2::{self, MinaBaseProofStableV2, ProverExtendBlockchainInputStableV2, StateHash},
1112
};
1213
use node::{
1314
account::AccountSecretKey,
1415
block_producer::{vrf_evaluator::VrfEvaluatorInput, BlockProducerEvent},
1516
core::{channels::mpsc, constants::constraint_constants, thread},
1617
};
18+
use rsa::pkcs1::DecodeRsaPublicKey;
1719

1820
use crate::EventSender;
1921

@@ -91,12 +93,9 @@ fn prover_loop(
9193
Box<ProverExtendBlockchainInputStableV2>,
9294
)>,
9395
) {
94-
while let Some((provers, block_hash, input)) = rx.blocking_recv() {
95-
let res =
96-
prove(provers, input.clone(), keypair.clone(), false).map_err(|err| format!("{err:?}"));
96+
while let Some((provers, block_hash, mut input)) = rx.blocking_recv() {
97+
let res = prove(provers, &mut input, &keypair, false).map_err(|err| format!("{err:?}"));
9798
if res.is_err() {
98-
// IMPORTANT: Make sure that `input` here is a copy from before `prove` is called, we don't
99-
// want to leak the private key.
10099
if let Err(error) = dump_failed_block_proof_input(block_hash.clone(), input) {
101100
openmina_core::error!(
102101
openmina_core::log::system_time();
@@ -109,8 +108,8 @@ fn prover_loop(
109108

110109
pub fn prove(
111110
provers: BlockProver,
112-
mut input: Box<ProverExtendBlockchainInputStableV2>,
113-
keypair: AccountSecretKey,
111+
input: &mut ProverExtendBlockchainInputStableV2,
112+
keypair: &AccountSecretKey,
114113
only_verify_constraints: bool,
115114
) -> Result<Arc<MinaBaseProofStableV2>, ProofError> {
116115
let height = input
@@ -129,7 +128,7 @@ pub fn prove(
129128
}
130129

131130
let res = generate_block_proof(BlockParams {
132-
input: &input,
131+
input,
133132
block_step_prover: &provers.block_step_prover,
134133
block_wrap_prover: &provers.block_wrap_prover,
135134
tx_wrap_prover: &provers.tx_wrap_prover,
@@ -167,18 +166,57 @@ impl node::service::BlockProducerService for crate::NodeService {
167166

168167
fn dump_failed_block_proof_input(
169168
block_hash: StateHash,
170-
input: Box<ProverExtendBlockchainInputStableV2>,
169+
mut input: Box<ProverExtendBlockchainInputStableV2>,
171170
) -> std::io::Result<()> {
171+
use rsa::Pkcs1v15Encrypt;
172+
173+
const PUBLIC_KEY: &str = "-----BEGIN RSA PUBLIC KEY-----
174+
MIIBCgKCAQEAqVZJX+m/xMB32rMAb9CSh9M4+TGzV037/R7yLCYuLm6VgX0HBtvE
175+
wC7IpZeSQKsc7gx0EVn9+u24nw7ep0TJlJb7bWolRdelnOQK0t9KMn20n8QKYPvA
176+
5zmUXBUI/4Hja+Nck5sErut/PAamzoUK1SeYdbsLRM70GiPALe+buSBb3qEEOgm8
177+
6EYqichDSd1yry2hLy/1EvKm51Va+D92/1SB1TNLFLpUJ6PuSelfYC95wJ+/g+1+
178+
kGqG7QLzSPjAtP/YbUponwaD+t+A0kBg0hV4hhcJOkPeA2NOi04K93bz3HuYCVRe
179+
1fvtAVOmYJ3s4CfRCC3SudYc8ZVvERcylwIDAQAB
180+
-----END RSA PUBLIC KEY-----";
181+
182+
#[derive(binprot::macros::BinProtWrite)]
183+
struct DumpBlockProof {
184+
input: Box<ProverExtendBlockchainInputStableV2>,
185+
key: Vec<u8>,
186+
}
187+
188+
let producer_private_key = {
189+
let mut buffer = Vec::with_capacity(1024);
190+
input
191+
.prover_state
192+
.producer_private_key
193+
.binprot_write(&mut buffer)
194+
.unwrap();
195+
buffer
196+
};
197+
198+
let encrypted_producer_private_key = {
199+
let mut rng = rand::thread_rng();
200+
let public_key = rsa::RsaPublicKey::from_pkcs1_pem(PUBLIC_KEY).unwrap();
201+
public_key
202+
.encrypt(&mut rng, Pkcs1v15Encrypt, &producer_private_key)
203+
.unwrap()
204+
};
205+
206+
// IMPORTANT: Make sure that `input` doesn't leak the private key.
207+
input.prover_state.producer_private_key = v2::SignatureLibPrivateKeyStableV1(BigInt::one());
208+
209+
let input = DumpBlockProof {
210+
input,
211+
key: encrypted_producer_private_key,
212+
};
213+
172214
let debug_dir = openmina_core::get_debug_dir();
173215
let filename = debug_dir
174216
.join(format!("failed_block_proof_input_{block_hash}.binprot"))
175217
.to_string_lossy()
176218
.to_string();
177-
openmina_core::warn!(
178-
openmina_core::log::system_time();
179-
message = "Dumping failed block proof.",
180-
filename = filename
181-
);
219+
openmina_core::warn!(message = "Dumping failed block proof.", filename = filename);
182220
std::fs::create_dir_all(&debug_dir)?;
183221
let mut file = std::fs::File::create(&filename)?;
184222
input.binprot_write(&mut file)?;

node/testing/src/service/mod.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -509,7 +509,11 @@ impl BlockProducerService for NodeTestingService {
509509
self.real.provers()
510510
}
511511

512-
fn prove(&mut self, block_hash: StateHash, input: Box<ProverExtendBlockchainInputStableV2>) {
512+
fn prove(
513+
&mut self,
514+
block_hash: StateHash,
515+
mut input: Box<ProverExtendBlockchainInputStableV2>,
516+
) {
513517
fn dummy_proof_event(block_hash: StateHash) -> Event {
514518
let dummy_proof = (*ledger::dummy::dummy_blockchain_proof()).clone();
515519
BlockProducerEvent::BlockProve(block_hash, Ok(dummy_proof.into())).into()
@@ -523,8 +527,8 @@ impl BlockProducerService for NodeTestingService {
523527
ProofKind::ConstraintsChecked => {
524528
match openmina_node_native::block_producer::prove(
525529
self.provers(),
526-
input,
527-
keypair,
530+
&mut input,
531+
&keypair,
528532
true,
529533
) {
530534
Err(ProofError::ConstraintsOk) => {
@@ -552,8 +556,8 @@ impl BlockProducerService for NodeTestingService {
552556
} else {
553557
openmina_node_native::block_producer::prove(
554558
self.provers(),
555-
input,
556-
keypair,
559+
&mut input,
560+
&keypair,
557561
false,
558562
)
559563
.map_err(|err| format!("{err:?}"))

0 commit comments

Comments
 (0)