You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

120 lines
3.5 KiB

3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
  1. use ark_circom::{ethereum, CircomBuilder, CircomConfig};
  2. use ark_std::rand::thread_rng;
  3. use color_eyre::Result;
  4. use ark_bn254::{Bn254, Fr};
  5. use ark_crypto_primitives::snark::SNARK;
  6. use ark_groth16::Groth16;
  7. use ethers::{
  8. contract::ContractError,
  9. prelude::abigen,
  10. providers::{Http, Middleware, Provider},
  11. utils::Anvil,
  12. };
  13. use std::{convert::TryFrom, sync::Arc};
  14. #[tokio::test]
  15. async fn solidity_verifier() -> Result<()> {
  16. let cfg = CircomConfig::<Fr>::new(
  17. "./test-vectors/mycircuit.wasm",
  18. "./test-vectors/mycircuit.r1cs",
  19. )?;
  20. let mut builder = CircomBuilder::new(cfg);
  21. builder.push_input("a", 3);
  22. builder.push_input("b", 11);
  23. // create an empty instance for setting it up
  24. let circom = builder.setup();
  25. let mut rng = thread_rng();
  26. let params = Groth16::<Bn254>::generate_random_parameters_with_reduction(circom, &mut rng)?;
  27. let circom = builder.build()?;
  28. let inputs = circom.get_public_inputs().unwrap();
  29. let proof = Groth16::<Bn254>::prove(&params, circom, &mut rng)?;
  30. // launch the network & compile the verifier
  31. let anvil = Anvil::new().spawn();
  32. let acc = anvil.addresses()[0];
  33. let provider = Provider::<Http>::try_from(anvil.endpoint())?;
  34. let provider = provider.with_sender(acc);
  35. let provider = Arc::new(provider);
  36. // deploy the verifier
  37. let contract = Groth16Verifier::deploy(provider.clone(), ())?
  38. .send()
  39. .await?;
  40. // check the proof
  41. let verified = contract
  42. .check_proof(proof, params.vk, inputs.as_slice())
  43. .await?;
  44. assert!(verified);
  45. Ok(())
  46. }
  47. // We need to implement the conversion from the Ark-Circom's internal Ethereum types to
  48. // the ones expected by the abigen'd types. Could we maybe provide a convenience
  49. // macro for these, given that there's room for implementation error?
  50. abigen!(Groth16Verifier, "./tests/verifier_artifact.json");
  51. use groth_16_verifier::{G1Point, G2Point, Proof, VerifyingKey};
  52. impl From<ethereum::G1> for G1Point {
  53. fn from(src: ethereum::G1) -> Self {
  54. Self { x: src.x, y: src.y }
  55. }
  56. }
  57. impl From<ethereum::G2> for G2Point {
  58. fn from(src: ethereum::G2) -> Self {
  59. // We should use the `.as_tuple()` method which handles converting
  60. // the G2 elements to have the second limb first
  61. let src = src.as_tuple();
  62. Self { x: src.0, y: src.1 }
  63. }
  64. }
  65. impl From<ethereum::Proof> for Proof {
  66. fn from(src: ethereum::Proof) -> Self {
  67. Self {
  68. a: src.a.into(),
  69. b: src.b.into(),
  70. c: src.c.into(),
  71. }
  72. }
  73. }
  74. impl From<ethereum::VerifyingKey> for VerifyingKey {
  75. fn from(src: ethereum::VerifyingKey) -> Self {
  76. Self {
  77. alfa_1: src.alpha1.into(),
  78. beta_2: src.beta2.into(),
  79. gamma_2: src.gamma2.into(),
  80. delta_2: src.delta2.into(),
  81. ic: src.ic.into_iter().map(|i| i.into()).collect(),
  82. }
  83. }
  84. }
  85. impl<M: Middleware> Groth16Verifier<M> {
  86. async fn check_proof<
  87. I: Into<ethereum::Inputs>,
  88. P: Into<ethereum::Proof>,
  89. VK: Into<ethereum::VerifyingKey>,
  90. >(
  91. &self,
  92. proof: P,
  93. vk: VK,
  94. inputs: I,
  95. ) -> Result<bool, ContractError<M>> {
  96. // convert into the expected format by the contract
  97. let proof = proof.into().into();
  98. let vk = vk.into().into();
  99. let inputs = inputs.into().0;
  100. // query the contract
  101. let res = self.verify(inputs, proof, vk).call().await?;
  102. Ok(res)
  103. }
  104. }