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.

130 lines
3.9 KiB

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