From 91213b3d4409d0ff528e72c5a23eec305d111dec Mon Sep 17 00:00:00 2001 From: M Alghazwi Date: Tue, 8 Jul 2025 11:41:52 +0200 Subject: [PATCH] add sponge tests for Monolith --- proof-input/tests/sponge.rs | 323 +++++++++++++++++++++++------------- 1 file changed, 209 insertions(+), 114 deletions(-) diff --git a/proof-input/tests/sponge.rs b/proof-input/tests/sponge.rs index 1afcf45..4fdeec0 100644 --- a/proof-input/tests/sponge.rs +++ b/proof-input/tests/sponge.rs @@ -1,21 +1,34 @@ use plonky2::field::types::Field; -use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; +use plonky2::plonk::config::{AlgebraicHasher, GenericConfig, Hasher, PoseidonGoldilocksConfig}; +use plonky2_field::goldilocks_field::GoldilocksField; use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2Hash; +use plonky2::hash::hash_types::NUM_HASH_OUT_ELTS; +use plonky2::iop::target::Target; +use plonky2::iop::witness::{PartialWitness, WitnessWrite}; +use plonky2::plonk::circuit_builder::CircuitBuilder; +use plonky2::plonk::circuit_data::CircuitConfig; +use proof_input::hash::sponge::{hash_n_with_padding, hash_bytes}; // test types pub const D: usize = 2; -pub type C = PoseidonGoldilocksConfig; -pub type F = >::F; -pub type H = Poseidon2Hash; +pub type F = GoldilocksField; struct TestCase { n: usize, digest: [u64; 4], } +/// Generate a byte sequence [1, 2, ..., n] +fn byte_seq(n: usize) -> Vec { + let mut seq = Vec::with_capacity(n); + for i in 0..n { + seq.push((i + 1) as u8); + } + seq +} // test cases from https://github.com/codex-storage/nim-goldilocks-hash/blob/main/tests/goldilocks_hash/poseidon2/spongeTestCases.nim -static FIELD_TEST_CASES: &[TestCase] = &[ +static POSEIDON2_FIELD_TEST_CASES: &[TestCase] = &[ TestCase { n: 0, digest: [0x509f3a747e4a6fca, 0xd6f21d91afb92eb3, 0xf65ef4075dcfb169, 0xbceaf22e0cd21b3d] }, TestCase { n: 1, digest: [0xfa286adad207c7ea, 0x97d864ff2e89415e, 0xcf002b28585bd945, 0x95ec163fbdd0792e] }, TestCase { n: 2, digest: [0xe4b779622cbb574f, 0x1fe4b1bc9a0c9fc7, 0x40051ada5252de9b, 0xb351345b1894a59f] }, @@ -45,7 +58,37 @@ static FIELD_TEST_CASES: &[TestCase] = &[ TestCase { n: 80, digest: [0x23ae45602324f628, 0x0dc16b33f43209c5, 0x2455376f83b1aeff, 0xd5470f22ec2113bc] }, ]; -static BYTES_TEST_CASES: &[TestCase] = &[ +static MONOLITH_FIELD_TEST_CASES: &[TestCase] = &[ + TestCase { n: 0, digest: [0xd47c5fbae9096559u64, 0xee882b9337378620u64, 0xc392c8614fc3aa09u64, 0x28fa56b792eb577cu64] }, + TestCase { n: 1, digest: [0xbd2b3a8a876c057bu64, 0x571f86d703ab22d3u64, 0xd3800a8192720938u64, 0xff4e91ae72e439cau64] }, + TestCase { n: 2, digest: [0x734df0e5728ce6b3u64, 0x99aced42682b5a2au64, 0xe8b66ad078279825u64, 0x9941b88ae257f341u64] }, + TestCase { n: 3, digest: [0xa6433cb12ba62d52u64, 0x1629e21393900ebfu64, 0x4476301fc4f47f81u64, 0x000e9e55ae70c696u64] }, + TestCase { n: 4, digest: [0x884602191b4a865fu64, 0xb77eb3239a710d56u64, 0x61eeb379d3cde9f1u64, 0xf2ee5db1c5183c06u64] }, + TestCase { n: 5, digest: [0x13464401497bc0d6u64, 0x8ce82497cc9a4b2eu64, 0xf2fd40929bb97a7bu64, 0x881c1c52cbfd9f9bu64] }, + TestCase { n: 6, digest: [0xb19b615bb7a98de4u64, 0x75c00a67ab6ff17au64, 0xc05f61c793da97fdu64, 0x0e447f619a0eaf07u64] }, + TestCase { n: 7, digest: [0x765b2887f8537171u64, 0x50b4dfeffd4d49d5u64, 0xb50b5c206a05fd2au64, 0x77228853b07f9b3fu64] }, + TestCase { n: 8, digest: [0x73d29f1b00757d2bu64, 0x03e6160b3f7ed271u64, 0x5ff50af82978c93bu64, 0x1507a55e93e53fd0u64] }, + TestCase { n: 9, digest: [0x6b6639736cc33412u64, 0x13c3223859d2ec55u64, 0xa598be339d131a5eu64, 0x5248819c0cc46c59u64] }, + TestCase { n: 10, digest: [0x751f4254110c0e68u64, 0xc675b0209833e442u64, 0x71ae9952b81f4b25u64, 0xf93d2e2ed2ea41fdu64] }, + TestCase { n: 11, digest: [0x996a2bc62c21e532u64, 0x38271bd59cd6933du64, 0x26090c447278edb4u64, 0xec57edebfdc5a78eu64] }, + TestCase { n: 12, digest: [0x01e4744707a0de6au64, 0xbb28342b330ad160u64, 0x323a772ab3258cedu64, 0x23fa246d8fb1a32du64] }, + TestCase { n: 13, digest: [0xb0826250221ac267u64, 0xba2943c78fe7b327u64, 0x79dbde0324103615u64, 0xa321a157a35651c1u64] }, + TestCase { n: 14, digest: [0x21861f0f8f3613cfu64, 0xa81565899d61ba44u64, 0x32e974dd9a68ceccu64, 0x9770cb4f04d59d56u64] }, + TestCase { n: 15, digest: [0x56b40e590d508a8eu64, 0xed203ebcb5827ee1u64, 0x87028b8115caabe9u64, 0xb0c3625d8ce2d87cu64] }, + TestCase { n: 16, digest: [0x31a5cba06f373379u64, 0xd105f5a4db31aa39u64, 0xcfcb6d7ad0ac35bfu64, 0xb27c9fbe10785cd7u64] }, + TestCase { n: 17, digest: [0x168dc7f64443bb42u64, 0xa43b954af0438342u64, 0x9ee5475ec0b42203u64, 0x3d7f53b6355bd5ffu64] }, + TestCase { n: 18, digest: [0x51348a77a8dc0bc2u64, 0x7388a29f8156fd8eu64, 0x5ae41ca4b7826796u64, 0x5bb858d7460f9b59u64] }, + TestCase { n: 19, digest: [0xa5b7420df52838c1u64, 0x533e1509647c9fa1u64, 0x9651947c57cf4dcfu64, 0x103f08964038b9f9u64] }, + TestCase { n: 20, digest: [0x55a717e33b97b557u64, 0x7b4026e2d656a6ebu64, 0x18c401420a0242d4u64, 0x7186b16167404ba3u64] }, + TestCase { n: 21, digest: [0xff93bf59fc306d6du64, 0x5ab6423e9993bfe1u64, 0xa91c4da9b2734002u64, 0x4d05843fb1884c0eu64] }, + TestCase { n: 22, digest: [0xbcb54583ec543ca1u64, 0x4c9ef6b0d21178fcu64, 0x8fa173cf5b146e4eu64, 0xf1ff0fc009c96625u64] }, + TestCase { n: 23, digest: [0x987da4c2b745c0afu64, 0xaa95bfa45db48494u64, 0x936e1442355c708bu64, 0xa74c3dfd4b0e9e0cu64] }, + TestCase { n: 24, digest: [0xe9f92f57a196aeb5u64, 0xf3fa8aaa35362bc4u64, 0x6d529e2243620d8du64, 0xbe6f05be1de9d92du64] }, + TestCase { n: 25, digest: [0xfaf815dd45b7ff2au64, 0x8f618b4bf8674be9u64, 0x25ce53df6ff85ba6u64, 0xa4c870702e47d0ebu64] }, + TestCase { n: 80, digest: [0x2f610bed75395897u64, 0x9ae07b486f21fcf5u64, 0xc506265e839283a4u64, 0x619636360bbecda5u64] }, +]; + +static POSEIDON2_BYTES_TEST_CASES: &[TestCase] = &[ TestCase { n: 0, digest: [0xa71efb792775af71, 0x2064465f503cb64b, 0xaaf2462603add4e4, 0x624af691db1f31b4] }, TestCase { n: 1, digest: [0x1460da7415280afd, 0x52839224731ae02d, 0xffe03215cd2aeb33, 0x763f0e72ce5a0540] }, TestCase { n: 2, digest: [0x467db61976fa1ae6, 0xbf2ade5297a35d4c, 0x169ac5af6fd80e9c, 0xcdd2fa4b14069298] }, @@ -75,126 +118,178 @@ static BYTES_TEST_CASES: &[TestCase] = &[ TestCase { n: 80, digest: [0xafd9328d3ee58953, 0x9daeb0e58fb7b0fc, 0x5f77e81b398edb3e, 0xb1a0dc7115ec3789] }, ]; -#[cfg(test)] -mod sponge_tests { - use super::*; - use proof_input::hash::sponge::{hash_n_with_padding, hash_bytes}; +static MONOLITH_BYTE_TEST_CASES: &[TestCase] = &[ + TestCase { n: 0, digest: [0x3443a96d7eaaf60du64, 0x14255b96f0092ab9u64, 0xcb64323ad7041011u64, 0x59f2ba0ebe02827du64] }, + TestCase { n: 1, digest: [0x0521794b1f6be4ecu64, 0x80f548060fadef35u64, 0xa5f7e3ad50bc15feu64, 0x3a83615c39b58140u64] }, + TestCase { n: 2, digest: [0xdb67947161e6705fu64, 0x02fd26a0d53d25a9u64, 0x2cf5c1f7a04b03c1u64, 0x1d78d66f44463dc5u64] }, + TestCase { n: 3, digest: [0x9b0c81110b510ebbu64, 0xf58790e70f9eab04u64, 0x6d9870e90d3b75a8u64, 0xc4ac327fa437f68du64] }, + TestCase { n: 4, digest: [0x3e949c46300b9c91u64, 0xb4634e57944cd5c7u64, 0x385c5c9455fc5c08u64, 0xf28ac62e0aa8c7acu64] }, + TestCase { n: 5, digest: [0x2a95903729d63d09u64, 0xec003aa5a2a1f54eu64, 0x03d555c457c2b909u64, 0x0643510bcd8467e8u64] }, + TestCase { n: 6, digest: [0x2a3c56e354f17defu64, 0xa9b18e3f30ca6450u64, 0x028373b89071f71fu64, 0x352be1798ee7de0eu64] }, + TestCase { n: 7, digest: [0x6d3596df0e38e63bu64, 0x4bf577ccf370dfb4u64, 0xf76e5d89f1d1dd5eu64, 0xd94a6d6f389c90dbu64] }, + TestCase { n: 8, digest: [0x4c7efa0715eb4ef9u64, 0x0952db0d01f64627u64, 0xd54b1e9eacb669eeu64, 0xecc7efd2174195ccu64] }, + TestCase { n: 9, digest: [0x5be81d45ca944ca9u64, 0x0cda9df1f63875f5u64, 0x23fbd8b8e820b96au64, 0x45d73ef08942a623u64] }, + TestCase { n: 10, digest: [0x1c0424ebab41510au64, 0xbfb82e664aabc43fu64, 0x37064df8b8739f95u64, 0xbd3df9c8c6f3f8b6u64] }, + TestCase { n: 11, digest: [0x2ccbd3d34bd4cd90u64, 0x124f23b8dc3271fcu64, 0xe015995b5f806003u64, 0xe9d02abf7666fd78u64] }, + TestCase { n: 12, digest: [0x4d19df925c93d7c0u64, 0xee01d6c870835514u64, 0xd423d71aeb3fb1a1u64, 0xf1660868b7dcc6ddu64] }, + TestCase { n: 13, digest: [0xd5aead5da0f1efcdu64, 0xe18f585eb3e0ebe6u64, 0xa8688fd3b06c959du64, 0xbe3b39dc37e81461u64] }, + TestCase { n: 14, digest: [0xff436bb5bdf34d56u64, 0x0938d4fe67ffe812u64, 0xe55d07afc99e1e08u64, 0x24385333292f4c8cu64] }, + TestCase { n: 15, digest: [0x729276b36fd1e880u64, 0xc28ad09142788753u64, 0x5825a598f66ad284u64, 0x54390583aaf9227du64] }, + TestCase { n: 16, digest: [0x9cfcd49462643e31u64, 0x268f4ce0f742f78bu64, 0xc5df066c71df396du64, 0x2feee3d5121fb3c1u64] }, + TestCase { n: 17, digest: [0x9fc04357cc207311u64, 0x9e320b5216a755abu64, 0x8d6ebaa263f4cfffu64, 0x0282948c7b0473ccu64] }, + TestCase { n: 18, digest: [0xd71f3eaa3be0e871u64, 0x59bc2ad3c0f3e40eu64, 0x3b3f285302f6be26u64, 0xd42595778e4857c3u64] }, + TestCase { n: 19, digest: [0x3ad9e6eda7ed6385u64, 0x77dea4e2a0f50776u64, 0xd6dace6ece5103e2u64, 0x024637ecef939fa1u64] }, + TestCase { n: 20, digest: [0xf4d171927ea5541fu64, 0xe8f14721b29c6aa0u64, 0x8746284b085cbb1cu64, 0x327bb32b2e66ec9eu64] }, + TestCase { n: 21, digest: [0xe39ecb4ea44409f5u64, 0x0c2dfc7446b45c23u64, 0xaa7ab53ef3ccfd90u64, 0x2773da7bca69e59bu64] }, + TestCase { n: 22, digest: [0x31958113cd57dcc4u64, 0xf39ff7b43cc171e0u64, 0x53bd115071515ac9u64, 0xe55acd4246ddc18eu64] }, + TestCase { n: 23, digest: [0xa3676fff478bd925u64, 0xfae6f5cc63d811c2u64, 0x6aa0453077fe063fu64, 0x01796f7425d2ccf2u64] }, + TestCase { n: 24, digest: [0x90dea16ce1903980u64, 0x9ec4a3200922506fu64, 0xfd38dfa3000178c4u64, 0x9ca5a2a697ba83f5u64] }, + TestCase { n: 25, digest: [0xc1497219666e1679u64, 0xc1ee0a7f9783ca57u64, 0xaa18e5be9bae4620u64, 0x2ec6e94f451f687cu64] }, + TestCase { n: 80, digest: [0xfdac23be1db05688u64, 0x3500b25390dc35e8u64, 0x9c3c23f6bb99f87bu64, 0x403b038b4878c1c0u64] }, +]; - /// Generate a byte sequence [1, 2, ..., n], wrapping at 256. - fn byte_seq(n: usize) -> Vec { - let mut seq = Vec::with_capacity(n); - for i in 0..n { - seq.push((i + 1) as u8); - } - seq - } +// ------------------------------------Generic test functions---------------------------------------- - #[test] - fn test_sponge_field_hash_rate_8() { +fn test_sponge_field_hash_rate_8>(test_cases: &[TestCase]) { + for test_case in test_cases { + let n = test_case.n; + let expected_digest = test_case.digest; - for test_case in FIELD_TEST_CASES { - let n = test_case.n; - let expected_digest = test_case.digest; + // Generate inputs + let inputs: Vec = (0..n) + .map(|i| F::from_canonical_u64(i as u64 + 1)) + .collect(); - // Generate inputs - let inputs: Vec = (0..n) - .map(|i| F::from_canonical_u64(i as u64 + 1)) - .collect(); + // Call the sponge function + let output = hash_n_with_padding::(&inputs); - // Call the sponge function - let output = hash_n_with_padding::(&inputs); - - // Compare the outputs - for (i, &out_elem) in output.elements.iter().enumerate() { - let expected_elem = F::from_canonical_u64(expected_digest[i]); - assert_eq!( - out_elem, - expected_elem, - "Mismatch at test case n={}, output element {}", - n, - i - ); - } - } - } - - #[test] - fn test_sponge_bytes_hash_rate_8() { - - for test_case in BYTES_TEST_CASES { - let n = test_case.n; - let expected_digest = test_case.digest; - - // Generate inputs - let inputs = byte_seq(n); - - // Call the sponge function - let output = hash_bytes::(&inputs); - println!("n = {}", n); - - // Compare the outputs - for (i, &out_elem) in output.elements.iter().enumerate() { - let expected_elem = F::from_canonical_u64(expected_digest[i]); - assert_eq!( - out_elem, - expected_elem, - "Mismatch at test case n={}, output element {}", - n, - i - ); - } + // Compare the outputs + for (i, &out_elem) in output.elements.iter().enumerate() { + let expected_elem = F::from_canonical_u64(expected_digest[i]); + assert_eq!( + out_elem, + expected_elem, + "Mismatch at test case n={}, output element {}", + n, + i + ); } } } -#[cfg(test)] -mod sponge_circuit_tests { - use super::*; - use plonky2::hash::hash_types::NUM_HASH_OUT_ELTS; - use plonky2::iop::target::Target; - use plonky2::iop::witness::{PartialWitness, WitnessWrite}; - use plonky2::plonk::circuit_builder::CircuitBuilder; - use plonky2::plonk::circuit_data::{CircuitConfig}; - use codex_plonky2_circuits::circuits::sponge::hash_n_with_padding; +fn test_sponge_bytes_hash_rate_8>(test_cases: &[TestCase]) { + for test_case in test_cases { + let n = test_case.n; + let expected_digest = test_case.digest; - #[test] - fn test_sponge_field_hash_rate_8_circuit() { + // Generate inputs + let inputs = byte_seq(n); - // if more tests are added, update this, but it would be slow - let number_of_tests = 3; - for test in FIELD_TEST_CASES { - if test.n > number_of_tests { - return; - } - let config = CircuitConfig::standard_recursion_config(); - let mut builder = CircuitBuilder::::new(config); - let inputs: Vec = (0..test.n).map(|_| builder.add_virtual_target()).collect(); - let hash = hash_n_with_padding::(&mut builder, inputs.clone()).unwrap(); - builder.register_public_inputs(&hash.elements); + // Call the sponge function + let output = hash_bytes::(&inputs); + println!("n = {}", n); - let mut pw = PartialWitness::::new(); - for (i, input) in inputs.iter().enumerate() { - pw.set_target(*input, F::from_canonical_u64(i as u64 + 1)).expect("set_target"); - } - - let data = builder.build::(); - let proof = data.prove(pw).unwrap(); - assert!(data.verify(proof.clone()).is_ok()); - - // Construct the expected digest - let expected_digest = - [ - F::from_canonical_u64(test.digest[0]), - F::from_canonical_u64(test.digest[1]), - F::from_canonical_u64(test.digest[2]), - F::from_canonical_u64(test.digest[3]), - ]; - - let output_vals = proof.public_inputs; - assert_eq!(output_vals.len(), NUM_HASH_OUT_ELTS); - for (i, &val) in output_vals.iter().enumerate() { - assert_eq!(val, expected_digest[i]); - } + // Compare the outputs + for (i, &out_elem) in output.elements.iter().enumerate() { + let expected_elem = F::from_canonical_u64(expected_digest[i]); + assert_eq!( + out_elem, + expected_elem, + "Mismatch at test case n={}, output element {}", + n, + i + ); } } } + +fn test_sponge_field_hash_rate_8_circuit, H: AlgebraicHasher>(config: CircuitConfig, test_cases: &[TestCase]) { + // if more tests are added, update this, but it would be slow + let number_of_tests = 3; + for test in test_cases { + if test.n > number_of_tests { + return; + } + let mut builder = CircuitBuilder::::new(config.clone()); + let inputs: Vec = (0..test.n).map(|_| builder.add_virtual_target()).collect(); + let hash = codex_plonky2_circuits::circuits::sponge::hash_n_with_padding::(&mut builder, inputs.clone()).unwrap(); + builder.register_public_inputs(&hash.elements); + + let mut pw = PartialWitness::::new(); + for (i, input) in inputs.iter().enumerate() { + pw.set_target(*input, F::from_canonical_u64(i as u64 + 1)).expect("set_target"); + } + + let data = builder.build::(); + let proof = data.prove(pw).unwrap(); + assert!(data.verify(proof.clone()).is_ok()); + + // Construct the expected digest + let expected_digest = + [ + F::from_canonical_u64(test.digest[0]), + F::from_canonical_u64(test.digest[1]), + F::from_canonical_u64(test.digest[2]), + F::from_canonical_u64(test.digest[3]), + ]; + + let output_vals = proof.public_inputs; + assert_eq!(output_vals.len(), NUM_HASH_OUT_ELTS); + for (i, &val) in output_vals.iter().enumerate() { + assert_eq!(val, expected_digest[i]); + } + } +} + +//------------------------------------Poseidon2 tests-------------------------------------------- +#[cfg(test)] +mod poseidon2_sponge_tests { + use super::*; + use plonky2::plonk::circuit_data::CircuitConfig; + + pub type C = PoseidonGoldilocksConfig; + pub type H = Poseidon2Hash; + + #[test] + fn test_poseidon2_sponge_field_hash_rate_8() { + test_sponge_field_hash_rate_8::(POSEIDON2_FIELD_TEST_CASES); + } + + #[test] + fn test_poseidon2_sponge_bytes_hash_rate_8() { + test_sponge_bytes_hash_rate_8::(POSEIDON2_BYTES_TEST_CASES); + } + + #[test] + fn test_poseidon2_sponge_field_hash_rate_8_circuit() { + let config = CircuitConfig::standard_recursion_config(); + test_sponge_field_hash_rate_8_circuit::(config, POSEIDON2_FIELD_TEST_CASES); + } +} + +// ------------------------------------Monolith tests-------------------------------------------- +#[cfg(test)] +mod monolith_sponge_tests { + use super::*; + use plonky2_monolith::gates::generate_config_for_monolith_gate; + use plonky2_monolith::monolith_hash::MonolithHash; + + pub type C = PoseidonGoldilocksConfig; + pub type H = MonolithHash; + + #[test] + fn test_monolith_sponge_field_hash_rate_8() { + test_sponge_field_hash_rate_8::(MONOLITH_FIELD_TEST_CASES); + } + + #[test] + fn test_monolith_sponge_bytes_hash_rate_8() { + test_sponge_bytes_hash_rate_8::(MONOLITH_BYTE_TEST_CASES); + } + + #[test] + fn test_monolith_sponge_field_hash_rate_8_circuit() { + let config = generate_config_for_monolith_gate::(); + test_sponge_field_hash_rate_8_circuit::(config, MONOLITH_FIELD_TEST_CASES); + } +} \ No newline at end of file