verity_verify_remote/
ic.rs1use std::error::Error;
2
3use crate::config::Config;
4use candid::{CandidType, Decode};
5use ic_agent::{export::Principal, Agent};
6use serde::Deserialize;
7use verity_verify_local::{self, ecdsa::validate_ecdsa_signature, merkle::validate_merkle_tree};
8pub const DEFAULT_IC_GATEWAY_LOCAL: &str = "http://127.0.0.1:4943";
9pub const DEFAULT_IC_GATEWAY_MAINNET: &str = "https://icp0.io";
10pub const DEFAULT_IC_GATEWAY_MAINNET_TRAILING_SLASH: &str = "https://icp0.io/";
11
12pub struct Verifier {
13 pub agent: Agent,
14 pub canister: Principal,
15}
16
17#[derive(CandidType, Deserialize, Debug)]
18pub struct PublicKeyReply {
19 pub sec1_pk: String,
20 pub etherum_pk: String,
21}
22
23#[derive(CandidType, Deserialize, Debug, Clone)]
24pub struct VerificationResponse {
25 pub results: Vec<ProofResponse>,
26 pub root: String,
27 pub signature: String,
28}
29
30#[derive(CandidType, Deserialize, Debug, Clone)]
31pub enum ProofResponse {
32 SessionProof(String), FullProof(String), }
35
36impl ProofResponse {
37 pub fn get_content(&self) -> String {
39 match self {
40 ProofResponse::SessionProof(content) => content.clone(),
42 ProofResponse::FullProof(content) => content.clone(),
44 }
45 }
46}
47
48type CanisterResponseType = Result<VerificationResponse, String>;
49
50impl Verifier {
52 pub async fn from_config(config: &Config) -> anyhow::Result<Self> {
54 let agent = config.create_agent().await?;
55 Ok(Self {
56 agent,
57 canister: config.canister_principal,
58 })
59 }
60
61 async fn verify_canister_response(
64 &self,
65 verification_response: &VerificationResponse,
66 ) -> Result<bool, Box<dyn Error>> {
67 let signature_hex = &verification_response.signature;
69 let root_hash = &verification_response.root;
70 let leaves: Vec<String> = verification_response
71 .results
72 .iter()
73 .map(|proof_response| proof_response.get_content())
74 .collect();
75 let canister_public_key = self.get_public_key().await?;
76
77 let is_signature_valid =
79 validate_ecdsa_signature(signature_hex, &root_hash, &canister_public_key)?;
80 let is_merkle_valid = validate_merkle_tree(&leaves, root_hash);
81
82 let is_response_valid = is_signature_valid && is_merkle_valid;
84 Ok(is_response_valid)
85 }
86
87 pub async fn get_public_key(&self) -> Result<String, Box<dyn Error>> {
89 let method_name = "public_key";
90
91 let response = self
93 .agent
94 .update(&self.canister, method_name)
95 .with_arg(candid::encode_args(())?)
96 .call_and_wait()
97 .await?;
98
99 let public_key_response = Decode!(&response, PublicKeyReply)?;
100
101 Ok(public_key_response.etherum_pk)
102 }
103
104 pub async fn verify_proof(
106 &self,
107 string_proofs: Vec<String>,
108 notary_pub_key: String,
109 ) -> Result<VerificationResponse, Box<dyn Error>> {
110 let verifier_method = "verify_proof_direct";
111
112 let response = self
114 .agent
115 .update(&self.canister, verifier_method)
116 .with_arg(candid::encode_args((string_proofs, notary_pub_key))?)
117 .call_and_wait()
118 .await
119 .unwrap();
120
121 let verification_response = Decode!(&response, CanisterResponseType)??;
123
124 let is_response_valid = self
126 .verify_canister_response(&verification_response)
127 .await?;
128
129 assert!(is_response_valid, "INVALID_CANISTER_RESPONSE");
130
131 Ok(verification_response)
132 }
133}