From 1d5265b30cb5a01d4d14630027aec97fcf5c5cfb Mon Sep 17 00:00:00 2001 From: gabrielbosio Date: Thu, 19 Sep 2024 12:08:47 -0300 Subject: [PATCH 01/10] Add tests for empty proof and empty pub inputs --- batcher/aligned-batcher/src/mina/mod.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/batcher/aligned-batcher/src/mina/mod.rs b/batcher/aligned-batcher/src/mina/mod.rs index a396278ca..fcfc656a5 100644 --- a/batcher/aligned-batcher/src/mina/mod.rs +++ b/batcher/aligned-batcher/src/mina/mod.rs @@ -22,9 +22,9 @@ mod test { use super::verify_proof_integrity; const PROTOCOL_STATE_PROOF_BYTES: &[u8] = - include_bytes!("../../../../batcher/aligned/test_files/mina/protocol_state.proof"); + include_bytes!("../../../../scripts/test_files/mina/mina_state.proof"); const PROTOCOL_STATE_PUB_BYTES: &[u8] = - include_bytes!("../../../../batcher/aligned/test_files/mina/protocol_state.pub"); + include_bytes!("../../../../scripts/test_files/mina/mina_state.pub"); #[test] fn verify_proof_integrity_does_not_fail() { @@ -33,4 +33,14 @@ mod test { PROTOCOL_STATE_PUB_BYTES, )); } + + #[test] + fn verify_empty_proof() { + assert!(!verify_proof_integrity(&[], PROTOCOL_STATE_PUB_BYTES)); + } + + #[test] + fn verify_empty_pub_inputs() { + assert!(!verify_proof_integrity(PROTOCOL_STATE_PROOF_BYTES, &[])); + } } From 824a10b8adab972ae2f0d8b1a631ceee4b9393bc Mon Sep 17 00:00:00 2001 From: gabrielbosio Date: Thu, 19 Sep 2024 12:18:47 -0300 Subject: [PATCH 02/10] Add tests for empty inputs in Mina verifier --- operator/mina/mina_test.go | 40 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/operator/mina/mina_test.go b/operator/mina/mina_test.go index 4fba72c24..cbd979380 100644 --- a/operator/mina/mina_test.go +++ b/operator/mina/mina_test.go @@ -35,3 +35,43 @@ func TestMinaStateProofVerifies(t *testing.T) { t.Errorf("proof did not verify") } } + +func TestEmptyMinaStateProofDoesNotVerify(t *testing.T) { + fmt.Println(os.Getwd()) + + proofBuffer := make([]byte, mina.MAX_PROOF_SIZE) + + pubInputFile, err := os.Open("../../scripts/test_files/mina/mina_state.pub") + if err != nil { + t.Errorf("could not open mina state hash file") + } + pubInputBuffer := make([]byte, mina.MAX_PUB_INPUT_SIZE) + pubInputLen, err := pubInputFile.Read(pubInputBuffer) + if err != nil { + t.Errorf("could not read bytes from mina state hash") + } + + if mina.VerifyMinaState(([mina.MAX_PROOF_SIZE]byte)(proofBuffer), mina.MAX_PROOF_SIZE, ([mina.MAX_PUB_INPUT_SIZE]byte)(pubInputBuffer), uint(pubInputLen)) { + t.Errorf("empty proof should not verify but it did") + } +} + +func TestMinaStateProofWithEmptyPubInputDoesNotVerify(t *testing.T) { + fmt.Println(os.Getwd()) + proofFile, err := os.Open("../../scripts/test_files/mina/mina_state.proof") + if err != nil { + t.Errorf("could not open mina state proof file") + } + + proofBuffer := make([]byte, mina.MAX_PROOF_SIZE) + proofLen, err := proofFile.Read(proofBuffer) + if err != nil { + t.Errorf("could not read bytes from mina state proof file") + } + + pubInputBuffer := make([]byte, mina.MAX_PUB_INPUT_SIZE) + + if mina.VerifyMinaState(([mina.MAX_PROOF_SIZE]byte)(proofBuffer), uint(proofLen), ([mina.MAX_PUB_INPUT_SIZE]byte)(pubInputBuffer), mina.MAX_PUB_INPUT_SIZE) { + t.Errorf("proof with no public inputs should not verify but it did") + } +} From caf7e32da9ce42008f0078dc5098b3f1f3e0770e Mon Sep 17 00:00:00 2001 From: gabrielbosio Date: Thu, 19 Sep 2024 12:42:58 -0300 Subject: [PATCH 03/10] Update Mina test files --- scripts/test_files/mina/mina_state.proof | Bin 48342 -> 48342 bytes scripts/test_files/mina/mina_state.pub | Bin 1056 -> 1056 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/scripts/test_files/mina/mina_state.proof b/scripts/test_files/mina/mina_state.proof index c13ba0c52fb953dfb6ce7c6babaa7da9abbc1ce8..81b579ad192a4f3cc8ae7e8510aa50113ede961a 100644 GIT binary patch literal 48342 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 Izh2q@e{x#quK)l5 literal 48342 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 diff --git a/scripts/test_files/mina/mina_state.pub b/scripts/test_files/mina/mina_state.pub index 51ac31aa0ac9bd8188977f85c678bd58ca200675..6b7f457b72b161bc94067cd71df26e740f7ecfb9 100644 GIT binary patch literal 1056 zcmZoNyR%fQvCz?lk1_LT_`0L7OIy7EWt2@@(Es0|Q^&*lW@B9E75S&$>mM378|!X8 z`J$~dJk32s^+4mDLp}>tjs6I@J_@+d{pPWP?ylvtdV?5l@7)n5zDS{k=SpwF0UJIs zC9%T>J+9Fnvzp$;&AXsbW&il**$4A~yJ(t=*k?ahyso!mQS~M@RfY?zMBn|X;riij zTxF_Ty;|zI@`<187YNR~q<@Cjs?M>$`DrM}H#vdbix2*OI^lar_I3H1BNu{rLTB^# zxa6vA6W(xoUg}Qf$`&u9tjl~m#pC17^ZDBG8*`R@{#DFgQcx1uTCAgl9kvGwwz_j*eqQ?sF2j^wq&Rei{tKUoKXDjrC zHSWJ@I{Cz6w#agWn|^|a9>@8O!e>9b%jY{d z{=c+a_KM7$V<|QJ-w3W-`YC|%|L<8EnwkZkT2h(ms{0t5BQ%-_#IK-)n$bjm_WWoW z-zg#23$j)6Wfk0BbSHd1=jr)_d7E%$&p-3NyO$d_cqPw%>l|p`sO7vffHBeSdT)wW u`9>?H;Vv(w9y0UvH-Xa6+iC?Q+oxD%z3Z@1MmN+~omM;?;}* literal 1056 zcmV+*1mF8zoYkyVC%zF63>*_gWnlCt%z5ln_bQd<*`uG9EDtpoPo>I>X^YLgGGsLk z>s`J;kBiR`Y-*MFb#|#~n2tTRvzu6AM~eRp`;I@s1q&ma2;^D;ee{FiBVrJxWos?t ze3j!EI22 zz-vEm(rl}tPQ7zVew#ff@NdL^_J_jiDL$TjV7~ys{md-NUKPG@ciyCApu&rQzfX20 zMg~(-PnO>9bth2XFY+K5b5p2y+nm6g0Y%{0dTwhMMeo>pm>=}qL5s4(w0`OH^#ro41hViWc}=DcRvC*VHsnV3_H55`Pp;d z$^-5XyvnhQpM@J$ADx zB9J~xAxWx@nv{GotVozqo*9Tk9g=b}_h|Pe11~_ONQfj5gLp=$%|9IvqC!?F7zPcm zEb&^EWG&bvdUL-w%?TG6VM{hl!0@X8{Mg<+C?M7|tKh!Ort6DAXKh0NZPps%eKTMT zp2W7u!0;1xE(p%MY^Y>RZ%w6nqB#WFMl3C1(~?OgnDd;k^quVo96mFw_z~MSuKsxj=a2HOPhLqCoJ|Zo?C$$f(1CrXfR!POGQH#D5 z%O77?7G`8AntG~js5y7EjjIH!b^Ce>uTl~L-bNJ&_gIXS29HNLBybHijMG-)(A5=Y z=MyxSyas&g+)?r#3`@3D9I>$fsS`O^EbMDd{6-L}${9xil}Xkl8mSHLhi^xVoi5Y0 z1>o25Wypq7lWj9EC#G+|2#5oC1hKZDnrkg5HlHLK#X5!D7T^U@z9lZmjEnhX`zMR3 aTPa?ua#!0SHLd=QjR2_i-H7adbFx1Lmj1v1 From 664a8136666b93477fae6bf82ab189e5ef7e0d64 Mon Sep 17 00:00:00 2001 From: gabrielbosio Date: Thu, 19 Sep 2024 12:43:26 -0300 Subject: [PATCH 04/10] Test empty inputs in Mina FFI --- operator/mina/lib/src/lib.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/operator/mina/lib/src/lib.rs b/operator/mina/lib/src/lib.rs index 67c55e8ca..1d13df840 100644 --- a/operator/mina/lib/src/lib.rs +++ b/operator/mina/lib/src/lib.rs @@ -234,4 +234,34 @@ mod test { verify_mina_state_ffi(&proof_buffer, proof_size, &pub_input_buffer, pub_input_size); assert!(!result); } + + #[test] + fn empty_mina_state_proof_does_not_verify() { + let mut proof_buffer = [0u8; super::MAX_PROOF_SIZE]; + let proof_size = PROOF_BYTES.len(); + + let mut pub_input_buffer = [0u8; super::MAX_PUB_INPUT_SIZE]; + let pub_input_size = PUB_INPUT_BYTES.len(); + assert!(pub_input_size <= pub_input_buffer.len()); + pub_input_buffer[..pub_input_size].clone_from_slice(PUB_INPUT_BYTES); + + let result = + verify_mina_state_ffi(&proof_buffer, proof_size, &pub_input_buffer, pub_input_size); + assert!(!result); + } + + #[test] + fn valid_mina_state_proof_with_empty_pub_input_does_not_verify() { + let mut proof_buffer = [0u8; super::MAX_PROOF_SIZE]; + let proof_size = PROOF_BYTES.len(); + assert!(proof_size <= proof_buffer.len()); + proof_buffer[..proof_size].clone_from_slice(PROOF_BYTES); + + let mut pub_input_buffer = [0u8; super::MAX_PUB_INPUT_SIZE]; + let pub_input_size = PUB_INPUT_BYTES.len(); + + let result = + verify_mina_state_ffi(&proof_buffer, proof_size, &pub_input_buffer, pub_input_size); + assert!(!result); + } } From a67bb78f0a11aeedafd757fbbc33fdf557cb6109 Mon Sep 17 00:00:00 2001 From: gabrielbosio Date: Thu, 19 Sep 2024 12:54:14 -0300 Subject: [PATCH 05/10] Make unchanged mut vars immutable --- operator/mina/lib/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/operator/mina/lib/src/lib.rs b/operator/mina/lib/src/lib.rs index 1d13df840..f59e15d82 100644 --- a/operator/mina/lib/src/lib.rs +++ b/operator/mina/lib/src/lib.rs @@ -237,7 +237,7 @@ mod test { #[test] fn empty_mina_state_proof_does_not_verify() { - let mut proof_buffer = [0u8; super::MAX_PROOF_SIZE]; + let proof_buffer = [0u8; super::MAX_PROOF_SIZE]; let proof_size = PROOF_BYTES.len(); let mut pub_input_buffer = [0u8; super::MAX_PUB_INPUT_SIZE]; @@ -257,7 +257,7 @@ mod test { assert!(proof_size <= proof_buffer.len()); proof_buffer[..proof_size].clone_from_slice(PROOF_BYTES); - let mut pub_input_buffer = [0u8; super::MAX_PUB_INPUT_SIZE]; + let pub_input_buffer = [0u8; super::MAX_PUB_INPUT_SIZE]; let pub_input_size = PUB_INPUT_BYTES.len(); let result = From 6b14da0d9b5628c70d473d8398e8241006077557 Mon Sep 17 00:00:00 2001 From: gabrielbosio Date: Thu, 19 Sep 2024 13:07:26 -0300 Subject: [PATCH 06/10] Update Mina account test files --- .../mina_account/mina_account.proof | Bin 1588 -> 1832 bytes .../test_files/mina_account/mina_account.pub | Bin 64 -> 3496 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/scripts/test_files/mina_account/mina_account.proof b/scripts/test_files/mina_account/mina_account.proof index 12eecb298bee12c99c114aa65f079e4b4e76b918..bf82354d50505ccdaf2cb2a6781abb778e4aacf7 100644 GIT binary patch delta 1077 zcmdnOvx0AeNPUfB^@JIxSn{=$Vkaam7e0A2`h;)ut1nBhhveCc=&&0z0D%IC0D|&L zroHlt-~LytWvMx0P{m-ieiSy%B_X0mgy4zU4`nICXw}z7o;^_gNF2r)hSo(jfn&^5%MHy)`U}%4gY-6-x?i z`EPgcQpD*K-`&@(=QiKlX*BPf%S7|?{bq|!3UeqRJ3^(eW!0O&Mpr>Lr7z8=gI&w_ z=ly7zT|Vbl#r!Qvffi!OYD=w^WwUHuZe3XPNh~Mouj&u~t36QH!s)8Ob3)xivpYPt z;pFPyd0cDSzVc4}ukwBB@$V?n5uz7SXOpsR;hyJjAKmQ`+I;E0p2S1Od{OmDQ&=ae zM*rj6tib$*sXokequ23E!p}KRYw^#zA(>G7P2lPKg|dgX1m{H>7VKkYQ~)^u2tWZx z4A^2L-=^}(9jsIVs)1X?hRxNpDzbg~j{YRXnJJ z?1-Hnf7rGDx75DaS5}(-cvfDz9h=SZ-gf3#jmU=+y%cO2LG~+vjb&gk_;#l}FDalc z?p>|?mhLwPx7-Lnb=pKwd@q-2Q;UX;5=a?LZTvTX`JFlYnbt_(&(=#459p4!N}Z6K zx$XbufBAEd2Xi4iV(Z1cGgkxNOn86$>pfL%>pt*W7Q`-8vc9KVAJd|atXQhj z!&ZE5)0Wv`P7j-AUYvUM(zUfuwT{mhSo2Bq)U+vD$Z91e*)bbtJlf1q|ETED$MpYi zw2>7{uG+BXD(_46BNtt3FSRXwBgVT+&AmM5;)dqw?z&Chn#dt>Y4PC%)~9RaH}a}} zm~&Cc?2B-5vDQ}QCm)`#ef{I+Zx&>=E>6c^PS#@TbGv!sKvjWp!Y}UZdX)vN3MZzY zo>rl{ieCj;@zQw5-bKw1PaR~ttsF1AX1kci>&1qu0oJ^H>Oy-$c7c>KD1b=@hDA0k z4v$<{zbM}jCp0Pk;D^03->Q#`UJP0$Ul%?iw4m=qX;DT;t0pHj*r~m)} diff --git a/scripts/test_files/mina_account/mina_account.pub b/scripts/test_files/mina_account/mina_account.pub index c2a7f7d0a968c5f40d82eb17abad7d841b90187c..75f513491f59b9760eefa229c9404cc0f66d9084 100644 GIT binary patch literal 3496 zcmb1A51D!Tn?UL3ZM6cD?Nh9>-gVfh@~ms*mJez4;nX*6;AJ2ND1>=#^g4b?_&Mik zE&f?IBok`C2|RtjQ1;N4;Jiq~f_=;c3}Iv>pa8!#^8uXl?w?fJl2pI_ai)#etojs W#{ Date: Thu, 19 Sep 2024 13:14:03 -0300 Subject: [PATCH 07/10] Add Go tests for empty inputs in Mina account FFI --- operator/mina_account/mina_account_test.go | 39 ++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/operator/mina_account/mina_account_test.go b/operator/mina_account/mina_account_test.go index 0cdd18777..89e34fa50 100644 --- a/operator/mina_account/mina_account_test.go +++ b/operator/mina_account/mina_account_test.go @@ -35,3 +35,42 @@ func TestMinaStateProofVerifies(t *testing.T) { t.Errorf("proof did not verify") } } + +func TestEmptyMinaStateProofDoesNotVerify(t *testing.T) { + fmt.Println(os.Getwd()) + proofBuffer := make([]byte, mina_account.MAX_PROOF_SIZE) + + pubInputFile, err := os.Open("../../scripts/test_files/mina_account/mina_account.pub") + if err != nil { + t.Errorf("could not open mina account pub inputs file") + } + pubInputBuffer := make([]byte, mina_account.MAX_PUB_INPUT_SIZE) + pubInputLen, err := pubInputFile.Read(pubInputBuffer) + if err != nil { + t.Errorf("could not read bytes from mina account pub inputs hash") + } + + if mina_account.VerifyAccountInclusion(([mina_account.MAX_PROOF_SIZE]byte)(proofBuffer), mina_account.MAX_PROOF_SIZE, ([mina_account.MAX_PUB_INPUT_SIZE]byte)(pubInputBuffer), uint(pubInputLen)) { + t.Errorf("Empty proof should not verify but it did") + } +} + +func TestMinaStateProofWithEmptyPubInputDoesNotVerify(t *testing.T) { + fmt.Println(os.Getwd()) + proofFile, err := os.Open("../../scripts/test_files/mina_account/mina_account.proof") + if err != nil { + t.Errorf("could not open mina account proof file") + } + + proofBuffer := make([]byte, mina_account.MAX_PROOF_SIZE) + proofLen, err := proofFile.Read(proofBuffer) + if err != nil { + t.Errorf("could not read bytes from mina account proof file") + } + + pubInputBuffer := make([]byte, mina_account.MAX_PUB_INPUT_SIZE) + + if mina_account.VerifyAccountInclusion(([mina_account.MAX_PROOF_SIZE]byte)(proofBuffer), uint(proofLen), ([mina_account.MAX_PUB_INPUT_SIZE]byte)(pubInputBuffer), mina_account.MAX_PUB_INPUT_SIZE) { + t.Errorf("proof with empty public input should not verify but id did") + } +} From ad9aa0867dea5604f805d7c9832f694b9a51ac6c Mon Sep 17 00:00:00 2001 From: gabrielbosio Date: Thu, 19 Sep 2024 14:10:57 -0300 Subject: [PATCH 08/10] Test empty inputs in Mina Account Rust FFI --- operator/mina_account/lib/src/lib.rs | 70 ++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/operator/mina_account/lib/src/lib.rs b/operator/mina_account/lib/src/lib.rs index 971f6f651..2ff36d440 100644 --- a/operator/mina_account/lib/src/lib.rs +++ b/operator/mina_account/lib/src/lib.rs @@ -64,3 +64,73 @@ pub extern "C" fn verify_account_inclusion_ffi( verify_merkle_proof(leaf_hash, merkle_path, ledger_hash) } + +#[cfg(test)] +mod test { + + use super::*; + + const PROOF_BYTES: &[u8] = + include_bytes!("../../../../scripts/test_files/mina_account/mina_account.proof"); + const PUB_INPUT_BYTES: &[u8] = + include_bytes!("../../../../scripts/test_files/mina_account/mina_account.pub"); + + #[test] + fn valid_account_state_proof_verifies() { + let mut proof_buffer = [0u8; super::MAX_PROOF_SIZE]; + let proof_size = PROOF_BYTES.len(); + assert!(proof_size <= proof_buffer.len()); + proof_buffer[..proof_size].clone_from_slice(PROOF_BYTES); + + let mut pub_input_buffer = [0u8; super::MAX_PUB_INPUT_SIZE]; + let pub_input_size = PUB_INPUT_BYTES.len(); + assert!(pub_input_size <= pub_input_buffer.len()); + pub_input_buffer[..pub_input_size].clone_from_slice(PUB_INPUT_BYTES); + + let result = verify_account_inclusion_ffi( + &proof_buffer, + proof_size, + &pub_input_buffer, + pub_input_size, + ); + assert!(result); + } + + #[test] + fn empty_account_state_proof_does_not_verify() { + let proof_buffer = [0u8; super::MAX_PROOF_SIZE]; + let proof_size = PROOF_BYTES.len(); + + let mut pub_input_buffer = [0u8; super::MAX_PUB_INPUT_SIZE]; + let pub_input_size = PUB_INPUT_BYTES.len(); + assert!(pub_input_size <= pub_input_buffer.len()); + pub_input_buffer[..pub_input_size].clone_from_slice(PUB_INPUT_BYTES); + + let result = verify_account_inclusion_ffi( + &proof_buffer, + proof_size, + &pub_input_buffer, + pub_input_size, + ); + assert!(!result); + } + + #[test] + fn valid_account_state_proof_with_empty_pub_input_does_not_verify() { + let mut proof_buffer = [0u8; super::MAX_PROOF_SIZE]; + let proof_size = PROOF_BYTES.len(); + assert!(proof_size <= proof_buffer.len()); + proof_buffer[..proof_size].clone_from_slice(PROOF_BYTES); + + let pub_input_buffer = [0u8; super::MAX_PUB_INPUT_SIZE]; + let pub_input_size = PUB_INPUT_BYTES.len(); + + let result = verify_account_inclusion_ffi( + &proof_buffer, + proof_size, + &pub_input_buffer, + pub_input_size, + ); + assert!(!result); + } +} From 1c85ce2fc7fff1c8b83ed8d22fd597f3189f61fa Mon Sep 17 00:00:00 2001 From: gabrielbosio Date: Thu, 19 Sep 2024 14:50:33 -0300 Subject: [PATCH 09/10] Add checks for huge input sizes --- operator/mina/lib/src/lib.rs | 50 ++++++++++++++++++++++++++++ operator/mina_account/lib/src/lib.rs | 50 ++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+) diff --git a/operator/mina/lib/src/lib.rs b/operator/mina/lib/src/lib.rs index f59e15d82..e2c945113 100644 --- a/operator/mina/lib/src/lib.rs +++ b/operator/mina/lib/src/lib.rs @@ -33,6 +33,16 @@ pub extern "C" fn verify_mina_state_ffi( pub_input_buffer: &[u8; MAX_PUB_INPUT_SIZE], pub_input_len: usize, ) -> bool { + if proof_len > MAX_PROOF_SIZE { + eprintln!("Proof length argument is greater than max proof size"); + return false; + } + + if pub_input_len > MAX_PUB_INPUT_SIZE { + eprintln!("Public input length argument is greater than max public input size"); + return false; + } + let proof: MinaStateProof = match bincode::deserialize(&proof_buffer[..proof_len]) { Ok(proof) => proof, Err(err) => { @@ -264,4 +274,44 @@ mod test { verify_mina_state_ffi(&proof_buffer, proof_size, &pub_input_buffer, pub_input_size); assert!(!result); } + + #[test] + fn valid_mina_state_proof_with_greater_proof_size_does_not_verify() { + let mut proof_buffer = [0u8; super::MAX_PROOF_SIZE]; + let wrong_proof_size = super::MAX_PROOF_SIZE + 1; + proof_buffer[..PROOF_BYTES.len()].clone_from_slice(PROOF_BYTES); + + let mut pub_input_buffer = [0u8; super::MAX_PUB_INPUT_SIZE]; + let pub_input_size = PUB_INPUT_BYTES.len(); + assert!(pub_input_size <= pub_input_buffer.len()); + pub_input_buffer[..pub_input_size].clone_from_slice(PUB_INPUT_BYTES); + + let result = verify_mina_state_ffi( + &proof_buffer, + wrong_proof_size, + &pub_input_buffer, + pub_input_size, + ); + assert!(!result); + } + + #[test] + fn valid_mina_state_proof_with_greater_pub_input_size_does_not_verify() { + let mut proof_buffer = [0u8; super::MAX_PROOF_SIZE]; + let proof_size = PROOF_BYTES.len(); + assert!(proof_size <= proof_buffer.len()); + proof_buffer[..proof_size].clone_from_slice(PROOF_BYTES); + + let mut pub_input_buffer = [0u8; super::MAX_PUB_INPUT_SIZE]; + let wrong_pub_input_size = MAX_PUB_INPUT_SIZE + 1; + pub_input_buffer[..PUB_INPUT_BYTES.len()].clone_from_slice(PUB_INPUT_BYTES); + + let result = verify_mina_state_ffi( + &proof_buffer, + proof_size, + &pub_input_buffer, + wrong_pub_input_size, + ); + assert!(!result); + } } diff --git a/operator/mina_account/lib/src/lib.rs b/operator/mina_account/lib/src/lib.rs index 2ff36d440..258467131 100644 --- a/operator/mina_account/lib/src/lib.rs +++ b/operator/mina_account/lib/src/lib.rs @@ -19,6 +19,16 @@ pub extern "C" fn verify_account_inclusion_ffi( pub_input_buffer: &[u8; MAX_PUB_INPUT_SIZE], pub_input_len: usize, ) -> bool { + if proof_len > MAX_PROOF_SIZE { + eprintln!("Proof length argument is greater than max proof size"); + return false; + } + + if pub_input_len > MAX_PUB_INPUT_SIZE { + eprintln!("Public input length argument is greater than max public input size"); + return false; + } + let MinaAccountProof { merkle_path, account, @@ -133,4 +143,44 @@ mod test { ); assert!(!result); } + + #[test] + fn valid_account_state_proof_with_greater_proof_size_does_not_verify() { + let mut proof_buffer = [0u8; super::MAX_PROOF_SIZE]; + let wrong_proof_size = MAX_PROOF_SIZE + 1; + proof_buffer[..PROOF_BYTES.len()].clone_from_slice(PROOF_BYTES); + + let mut pub_input_buffer = [0u8; super::MAX_PUB_INPUT_SIZE]; + let pub_input_size = PUB_INPUT_BYTES.len(); + assert!(pub_input_size <= pub_input_buffer.len()); + pub_input_buffer[..pub_input_size].clone_from_slice(PUB_INPUT_BYTES); + + let result = verify_account_inclusion_ffi( + &proof_buffer, + wrong_proof_size, + &pub_input_buffer, + pub_input_size, + ); + assert!(!result); + } + + #[test] + fn valid_account_state_proof_with_greater_pub_input_size_does_not_verify() { + let mut proof_buffer = [0u8; super::MAX_PROOF_SIZE]; + let proof_size = PROOF_BYTES.len(); + assert!(proof_size <= proof_buffer.len()); + proof_buffer[..proof_size].clone_from_slice(PROOF_BYTES); + + let mut pub_input_buffer = [0u8; super::MAX_PUB_INPUT_SIZE]; + let wrong_pub_input_size = MAX_PUB_INPUT_SIZE + 1; + pub_input_buffer[..PUB_INPUT_BYTES.len()].clone_from_slice(PUB_INPUT_BYTES); + + let result = verify_account_inclusion_ffi( + &proof_buffer, + proof_size, + &pub_input_buffer, + wrong_pub_input_size, + ); + assert!(!result); + } } From e46b6f553362f491dcf9b1806c2e2cb8b016cde0 Mon Sep 17 00:00:00 2001 From: gabrielbosio Date: Thu, 19 Sep 2024 15:01:30 -0300 Subject: [PATCH 10/10] Refactor input size check --- operator/mina/lib/src/lib.rs | 25 ++++++++++++------------- operator/mina_account/lib/src/lib.rs | 12 ++++++------ 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/operator/mina/lib/src/lib.rs b/operator/mina/lib/src/lib.rs index e2c945113..fc31e89bf 100644 --- a/operator/mina/lib/src/lib.rs +++ b/operator/mina/lib/src/lib.rs @@ -33,31 +33,30 @@ pub extern "C" fn verify_mina_state_ffi( pub_input_buffer: &[u8; MAX_PUB_INPUT_SIZE], pub_input_len: usize, ) -> bool { - if proof_len > MAX_PROOF_SIZE { + let Some(proof_buffer_slice) = proof_buffer.get(..proof_len) else { eprintln!("Proof length argument is greater than max proof size"); return false; - } + }; - if pub_input_len > MAX_PUB_INPUT_SIZE { + let Some(pub_input_buffer_slice) = pub_input_buffer.get(..pub_input_len) else { eprintln!("Public input length argument is greater than max public input size"); return false; - } + }; - let proof: MinaStateProof = match bincode::deserialize(&proof_buffer[..proof_len]) { + let proof: MinaStateProof = match bincode::deserialize(proof_buffer_slice) { Ok(proof) => proof, Err(err) => { eprintln!("Failed to deserialize state proof: {}", err); return false; } }; - let pub_inputs: MinaStatePubInputs = - match bincode::deserialize(&pub_input_buffer[..pub_input_len]) { - Ok(pub_inputs) => pub_inputs, - Err(err) => { - eprintln!("Failed to deserialize state pub inputs: {}", err); - return false; - } - }; + let pub_inputs: MinaStatePubInputs = match bincode::deserialize(pub_input_buffer_slice) { + Ok(pub_inputs) => pub_inputs, + Err(err) => { + eprintln!("Failed to deserialize state pub inputs: {}", err); + return false; + } + }; // Checks the integrity of the public inputs, also checks if the states form a chain. let (candidate_tip_state, bridge_tip_state, candidate_tip_state_hash) = diff --git a/operator/mina_account/lib/src/lib.rs b/operator/mina_account/lib/src/lib.rs index 258467131..1b15c722d 100644 --- a/operator/mina_account/lib/src/lib.rs +++ b/operator/mina_account/lib/src/lib.rs @@ -19,20 +19,20 @@ pub extern "C" fn verify_account_inclusion_ffi( pub_input_buffer: &[u8; MAX_PUB_INPUT_SIZE], pub_input_len: usize, ) -> bool { - if proof_len > MAX_PROOF_SIZE { + let Some(proof_buffer_slice) = proof_buffer.get(..proof_len) else { eprintln!("Proof length argument is greater than max proof size"); return false; - } + }; - if pub_input_len > MAX_PUB_INPUT_SIZE { + let Some(pub_input_buffer_slice) = pub_input_buffer.get(..pub_input_len) else { eprintln!("Public input length argument is greater than max public input size"); return false; - } + }; let MinaAccountProof { merkle_path, account, - } = match bincode::deserialize(&proof_buffer[..proof_len]) { + } = match bincode::deserialize(proof_buffer_slice) { Ok(proof) => proof, Err(err) => { eprintln!("Failed to deserialize account proof: {}", err); @@ -42,7 +42,7 @@ pub extern "C" fn verify_account_inclusion_ffi( let MinaAccountPubInputs { ledger_hash, encoded_account, - } = match bincode::deserialize(&pub_input_buffer[..pub_input_len]) { + } = match bincode::deserialize(pub_input_buffer_slice) { Ok(pub_inputs) => pub_inputs, Err(err) => { eprintln!("Failed to deserialize account pub inputs: {}", err);