diff --git a/halo2_gadgets/src/ecc.rs b/halo2_gadgets/src/ecc.rs index 4325cc3e39..8cb9ce4d57 100644 --- a/halo2_gadgets/src/ecc.rs +++ b/halo2_gadgets/src/ecc.rs @@ -929,7 +929,7 @@ pub(crate) mod tests { include_str!("vk_ecc_chip").replace("\r\n", "\n") ); } - test_proof_size(k, circuit, params, vk) + test_proof_size(k, circuit, ¶ms, &vk) } #[test] diff --git a/halo2_gadgets/src/sinsemilla.rs b/halo2_gadgets/src/sinsemilla.rs index 0d585e42c2..b9e2b6418e 100644 --- a/halo2_gadgets/src/sinsemilla.rs +++ b/halo2_gadgets/src/sinsemilla.rs @@ -783,7 +783,7 @@ pub(crate) mod tests { include_str!("vk_sinsemilla_chip").replace("\r\n", "\n") ); } - test_proof_size(11, circuit, params, vk) + test_proof_size(11, circuit, ¶ms, &vk) } #[test] diff --git a/halo2_gadgets/src/sinsemilla/merkle.rs b/halo2_gadgets/src/sinsemilla/merkle.rs index 4d6a0f2517..345877ec24 100644 --- a/halo2_gadgets/src/sinsemilla/merkle.rs +++ b/halo2_gadgets/src/sinsemilla/merkle.rs @@ -422,7 +422,7 @@ pub mod tests { } // Test that the proof size is as expected. - test_proof_size(k, circuit, params, vk) + test_proof_size(k, circuit, ¶ms, &vk) } #[test] diff --git a/halo2_gadgets/src/utilities/circuit_proof_test_case_short_range_check.bin b/halo2_gadgets/src/utilities/circuit_proof_test_case_short_range_check.bin new file mode 100644 index 0000000000..61d4e7caab Binary files /dev/null and b/halo2_gadgets/src/utilities/circuit_proof_test_case_short_range_check.bin differ diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs index 782a7d234b..29a3073d47 100644 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities/lookup_range_check.rs @@ -456,7 +456,7 @@ pub(crate) mod tests { }; use pasta_curves::pallas; - use crate::utilities::test_circuit::{read_test_case, test_proof_size, write_test_case, Proof}; + use crate::utilities::test_circuit::{read_test_case, test_proof_size, write_test_case, Proof, read_all_proofs, write_all_test_case}; use halo2_proofs::poly::commitment::Params; use pasta_curves::vesta::Affine; use std::{convert::TryInto, fs, marker::PhantomData}; @@ -597,12 +597,13 @@ pub(crate) mod tests { } // Test that the proof size is as expected. - test_proof_size(11, circuit, params, vk) + test_proof_size(11, circuit, ¶ms, &vk) } } #[test] fn short_range_check() { + #[derive(Clone, Copy)] struct MyCircuit { element: Value, num_bits: usize, @@ -647,7 +648,23 @@ pub(crate) mod tests { } } + + if std::env::var_os("CIRCUIT_TEST_GENERATE_NEW_PROOF").is_some() { + } + else { + // Parse the hardcoded proof test case. + let proofs= { + let test_case_bytes = fs::read("src/utilities/circuit_proof_test_case_short_range_check.bin").unwrap(); + read_all_proofs(&test_case_bytes[..]).expect("proof must be valid") + }; + } + + // Setup phase: generate parameters + let params: Params = Params::new(11); + let mut proofs = Vec::new(); + // Edge case: zero bits + // case 0 { let circuit: MyCircuit = MyCircuit { element: Value::known(pallas::Base::ZERO), @@ -656,8 +673,7 @@ pub(crate) mod tests { let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); assert_eq!(prover.verify(), Ok(())); - // Setup phase: generate parameters, vk for the circuit. - let params: Params = Params::new(11); + // generate vk let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); // Test that the pinned verification key (representing the circuit) @@ -666,15 +682,37 @@ pub(crate) mod tests { //panic!("{:#?}", vk.pinned()); assert_eq!( format!("{:#?}\n", vk.pinned()), - include_str!("vk_short_range_check").replace("\r\n", "\n") + include_str!("vk_short_range_check_0").replace("\r\n", "\n") ); } - // Test that the proof size is as expected. - test_proof_size(11, circuit, params, vk) + test_proof_size(11, circuit.clone(), ¶ms, &vk); + + // serialized_proof_test_case + { + if std::env::var_os("CIRCUIT_TEST_GENERATE_NEW_PROOF").is_some() { + let proof = Proof::create(&vk, ¶ms, circuit).unwrap(); + assert!(proof.verify(&vk, ¶ms).is_ok()); + proofs.push(proof.clone()); + } + else { + match proofs.get(0) { + Some(proof) => { + println!("proof={:?}", proof); + + assert_eq!(proof.as_ref().len(), 1888); + assert!(proof.verify(&vk, ¶ms).is_ok()); + } + None => println!("Index out of bounds"), + } + } + } + + } // Edge case: K bits + // case 1 { let circuit: MyCircuit = MyCircuit { element: Value::known(pallas::Base::from((1 << K) - 1)), @@ -682,9 +720,46 @@ pub(crate) mod tests { }; let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); assert_eq!(prover.verify(), Ok(())); + + // generate vk + let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); + + // Test that the pinned verification key (representing the circuit) + // is as expected. Which indicates the layouters are the same. + { + //panic!("{:#?}", vk.pinned()); + assert_eq!( + format!("{:#?}\n", vk.pinned()), + include_str!("vk_short_range_check_1").replace("\r\n", "\n") + ); + } + // Test that the proof size is as expected. + test_proof_size(11, circuit.clone(), ¶ms, &vk); + + // serialized_proof_test_case + { + if std::env::var_os("CIRCUIT_TEST_GENERATE_NEW_PROOF").is_some() { + let proof = Proof::create(&vk, ¶ms, circuit).unwrap(); + assert!(proof.verify(&vk, ¶ms).is_ok()); + proofs.push(proof.clone()); + } + else { + match proofs.get(1) { + Some(proof) => { + println!("proof={:?}", proof); + + assert_eq!(proof.as_ref().len(), 1888); + assert!(proof.verify(&vk, ¶ms).is_ok()); + } + None => println!("Index out of bounds"), + } + } + } + } // Element within `num_bits` + // case 2 { let circuit: MyCircuit = MyCircuit { element: Value::known(pallas::Base::from((1 << 6) - 1)), @@ -692,6 +767,52 @@ pub(crate) mod tests { }; let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); assert_eq!(prover.verify(), Ok(())); + + // generate vk + let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); + + // Test that the pinned verification key (representing the circuit) + // is as expected. Which indicates the layouters are the same. + { + //panic!("{:#?}", vk.pinned()); + assert_eq!( + format!("{:#?}\n", vk.pinned()), + include_str!("vk_short_range_check_2").replace("\r\n", "\n") + ); + } + // Test that the proof size is as expected. + test_proof_size(11, circuit.clone(), ¶ms, &vk); + + // serialized_proof_test_case + { + if std::env::var_os("CIRCUIT_TEST_GENERATE_NEW_PROOF").is_some() { + let proof = Proof::create(&vk, ¶ms, circuit).unwrap(); + assert!(proof.verify(&vk, ¶ms).is_ok()); + proofs.push(proof.clone()); + } + else { + match proofs.get(2) { + Some(proof) => { + println!("proof={:?}", proof); + + assert_eq!(proof.as_ref().len(), 1888); + assert!(proof.verify(&vk, ¶ms).is_ok()); + } + None => println!("Index out of bounds"), + } + } + } + } + + if std::env::var_os("CIRCUIT_TEST_GENERATE_NEW_PROOF").is_some() { + let create_proof = || -> std::io::Result<()> { + + let file = std::fs::File::create( + "src/utilities/circuit_proof_test_case_short_range_check.bin" + )?; + write_all_test_case(file, &proofs) + }; + create_proof().expect("should be able to write new proof"); } // Element larger than `num_bits` but within K bits @@ -711,6 +832,8 @@ pub(crate) mod tests { }, }]) ); + + } // Element larger than K bits @@ -739,6 +862,8 @@ pub(crate) mod tests { }, ]) ); + + } // Element which is not within `num_bits`, but which has a shifted value within @@ -767,6 +892,8 @@ pub(crate) mod tests { }, }]) ); + + } } } diff --git a/halo2_gadgets/src/utilities/test_circuit.rs b/halo2_gadgets/src/utilities/test_circuit.rs index 5066e3f1f5..f7618e3970 100644 --- a/halo2_gadgets/src/utilities/test_circuit.rs +++ b/halo2_gadgets/src/utilities/test_circuit.rs @@ -1,5 +1,6 @@ //! functions used for circuit test +use std::io; use halo2_proofs::plonk; use halo2_proofs::plonk::{Circuit, SingleVerifier, VerifyingKey}; use halo2_proofs::poly::commitment::Params; @@ -53,12 +54,12 @@ impl Proof { } } -#[allow(dead_code)] +/// test the proof size. pub(crate) fn test_proof_size( k: u32, circuit: C, - params: Params, - vk: VerifyingKey, + params: &Params, + vk: &VerifyingKey, ) where C: Circuit, { @@ -67,9 +68,9 @@ pub(crate) fn test_proof_size( halo2_proofs::dev::CircuitCost::::measure(k, &circuit); let expected_proof_size = usize::from(circuit_cost.proof_size(1)); - let proof = Proof::create(&vk, ¶ms, circuit).unwrap(); + let proof = Proof::create(vk, params, circuit).unwrap(); - assert!(proof.verify(&vk, ¶ms).is_ok()); + assert!(proof.verify(vk, params).is_ok()); assert_eq!(proof.as_ref().len(), expected_proof_size); } @@ -87,3 +88,25 @@ pub fn read_test_case(mut r: R) -> std::io::Result { Ok(proof) } + +/// write multiple proofs to a file +pub(crate) fn write_all_test_case( + mut w: W, + proofs: &Vec, +) -> std::io::Result<()> { + for proof in proofs { + w.write_all(proof.as_ref())?; + } + Ok(()) +} + +/// read multiple proofs from a file +pub fn read_all_proofs(mut r: R) -> io::Result> { + let mut proofs = Vec::new(); + let mut buffer = vec![0u8; 1888]; + + while let Ok(()) = r.read_exact(&mut buffer) { + proofs.push(Proof::new(buffer.clone())); + } + Ok(proofs) +} \ No newline at end of file diff --git a/halo2_gadgets/src/utilities/vk_short_range_check b/halo2_gadgets/src/utilities/vk_short_range_check_0 similarity index 100% rename from halo2_gadgets/src/utilities/vk_short_range_check rename to halo2_gadgets/src/utilities/vk_short_range_check_0 diff --git a/halo2_gadgets/src/utilities/vk_short_range_check_1 b/halo2_gadgets/src/utilities/vk_short_range_check_1 new file mode 100644 index 0000000000..d17acb3106 --- /dev/null +++ b/halo2_gadgets/src/utilities/vk_short_range_check_1 @@ -0,0 +1,244 @@ +PinnedVerificationKey { + base_modulus: "0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001", + scalar_modulus: "0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001", + domain: PinnedEvaluationDomain { + k: 11, + extended_k: 14, + omega: 0x181b50ad5f32119e31cbd395426d600b7a9b88bcaaa1c24eef28545aada17813, + }, + cs: PinnedConstraintSystem { + num_fixed_columns: 5, + num_advice_columns: 1, + num_instance_columns: 0, + num_selectors: 3, + gates: [ + Product( + Fixed { + query_index: 4, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Sum( + Product( + Scaled( + Advice { + query_index: 2, + column_index: 0, + rotation: Rotation( + -1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000400, + ), + Advice { + query_index: 1, + column_index: 0, + rotation: Rotation( + 1, + ), + }, + ), + Negated( + Advice { + query_index: 0, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ], + advice_queries: [ + ( + Column { + index: 0, + column_type: Advice, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 0, + column_type: Advice, + }, + Rotation( + 1, + ), + ), + ( + Column { + index: 0, + column_type: Advice, + }, + Rotation( + -1, + ), + ), + ], + instance_queries: [], + fixed_queries: [ + ( + Column { + index: 1, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 0, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 2, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 3, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 4, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ], + permutation: Argument { + columns: [ + Column { + index: 1, + column_type: Fixed, + }, + Column { + index: 0, + column_type: Advice, + }, + ], + }, + lookups: [ + Argument { + input_expressions: [ + Product( + Fixed { + query_index: 2, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + Sum( + Product( + Fixed { + query_index: 3, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Sum( + Advice { + query_index: 0, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 1, + column_index: 0, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000400, + ), + ), + ), + ), + Product( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 3, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + ), + Advice { + query_index: 0, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ], + table_expressions: [ + Fixed { + query_index: 1, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ], + }, + ], + constants: [ + Column { + index: 1, + column_type: Fixed, + }, + ], + minimum_degree: None, + }, + fixed_commitments: [ + (0x05f5862cad2888855bc3c1843a9eff57b11b592d9eb0e13354256661387f5231, 0x32236b14df85bf5f532a930232cb23a5c56ef7d67aaeed8bcb8fc10ea132cbd6), + (0x369f0b3422178fecf6e9a4fc7224622da26e8b5c74fb9aca5864c9f72e30bd5c, 0x2d7892875c06c460c9c9f66449103e7b6ef2871fb0a4e39b9af90e938c8e291b), + (0x0980acedb0fd2c02718002125bf80f969175d1f90d1320f9f3d5e2ac584e0212, 0x235c651fefd49e387ef9a6293a428810994974d218c4757ca3f9c0971ae25767), + (0x2bbc94ef7b22aebef24f9a4b0cc1831882548b605171366017d45c3e6fd92075, 0x082b801a6e176239943bfb759fb02138f47a5c8cc4aa7fa0af559fde4e3abd97), + (0x28d1c924953bc53f232465943d25fd085f85727ae4e2d26249207da1e59559e2, 0x184d19e00f109c4dacf8026c6e0fc4181178b32a236828047c46d9d61eab90fa), + ], + permutation: VerifyingKey { + commitments: [ + (0x3b7b93d7540327328791a14933d8f3345abd943eb35b67a8a4bd2eb72e2a707a, 0x26fff57a6fa3c01dd0d739fc56479303b4302d6baa6f1da06f4013419c40e10c), + (0x3fdf7a15a0d2378accc11f704f4ba4a487b542ace83c7f5a8551b569a3b9a380, 0x34253920878d15d6fe1b5198c31bdd670d32e81621e9fcd569d582e596ed0af5), + ], + }, +} diff --git a/halo2_gadgets/src/utilities/vk_short_range_check_2 b/halo2_gadgets/src/utilities/vk_short_range_check_2 new file mode 100644 index 0000000000..8187051b09 --- /dev/null +++ b/halo2_gadgets/src/utilities/vk_short_range_check_2 @@ -0,0 +1,244 @@ +PinnedVerificationKey { + base_modulus: "0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001", + scalar_modulus: "0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001", + domain: PinnedEvaluationDomain { + k: 11, + extended_k: 14, + omega: 0x181b50ad5f32119e31cbd395426d600b7a9b88bcaaa1c24eef28545aada17813, + }, + cs: PinnedConstraintSystem { + num_fixed_columns: 5, + num_advice_columns: 1, + num_instance_columns: 0, + num_selectors: 3, + gates: [ + Product( + Fixed { + query_index: 4, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + Sum( + Product( + Scaled( + Advice { + query_index: 2, + column_index: 0, + rotation: Rotation( + -1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000400, + ), + Advice { + query_index: 1, + column_index: 0, + rotation: Rotation( + 1, + ), + }, + ), + Negated( + Advice { + query_index: 0, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ], + advice_queries: [ + ( + Column { + index: 0, + column_type: Advice, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 0, + column_type: Advice, + }, + Rotation( + 1, + ), + ), + ( + Column { + index: 0, + column_type: Advice, + }, + Rotation( + -1, + ), + ), + ], + instance_queries: [], + fixed_queries: [ + ( + Column { + index: 1, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 0, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 2, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 3, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 4, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ], + permutation: Argument { + columns: [ + Column { + index: 1, + column_type: Fixed, + }, + Column { + index: 0, + column_type: Advice, + }, + ], + }, + lookups: [ + Argument { + input_expressions: [ + Product( + Fixed { + query_index: 2, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + Sum( + Product( + Fixed { + query_index: 3, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Sum( + Advice { + query_index: 0, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Negated( + Scaled( + Advice { + query_index: 1, + column_index: 0, + rotation: Rotation( + 1, + ), + }, + 0x0000000000000000000000000000000000000000000000000000000000000400, + ), + ), + ), + ), + Product( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Fixed { + query_index: 3, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + ), + Advice { + query_index: 0, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ], + table_expressions: [ + Fixed { + query_index: 1, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ], + }, + ], + constants: [ + Column { + index: 1, + column_type: Fixed, + }, + ], + minimum_degree: None, + }, + fixed_commitments: [ + (0x05f5862cad2888855bc3c1843a9eff57b11b592d9eb0e13354256661387f5231, 0x32236b14df85bf5f532a930232cb23a5c56ef7d67aaeed8bcb8fc10ea132cbd6), + (0x2ca6650c6fcad471c1c9d29e9115516064a1fe096af3b13821cf1fe7fee088eb, 0x18e61f68d5978b837a3e2295fe7ae7ca672268a519394f41aabd085aadc1221d), + (0x0980acedb0fd2c02718002125bf80f969175d1f90d1320f9f3d5e2ac584e0212, 0x235c651fefd49e387ef9a6293a428810994974d218c4757ca3f9c0971ae25767), + (0x2bbc94ef7b22aebef24f9a4b0cc1831882548b605171366017d45c3e6fd92075, 0x082b801a6e176239943bfb759fb02138f47a5c8cc4aa7fa0af559fde4e3abd97), + (0x28d1c924953bc53f232465943d25fd085f85727ae4e2d26249207da1e59559e2, 0x184d19e00f109c4dacf8026c6e0fc4181178b32a236828047c46d9d61eab90fa), + ], + permutation: VerifyingKey { + commitments: [ + (0x3b7b93d7540327328791a14933d8f3345abd943eb35b67a8a4bd2eb72e2a707a, 0x26fff57a6fa3c01dd0d739fc56479303b4302d6baa6f1da06f4013419c40e10c), + (0x3fdf7a15a0d2378accc11f704f4ba4a487b542ace83c7f5a8551b569a3b9a380, 0x34253920878d15d6fe1b5198c31bdd670d32e81621e9fcd569d582e596ed0af5), + ], + }, +}