verity_verify_remote/
ic.rsuse std::error::Error;
use crate::config::Config;
use candid::{CandidType, Decode};
use ic_agent::{export::Principal, Agent};
use serde::Deserialize;
use verity_verify_local::{self, ecdsa::validate_ecdsa_signature, merkle::validate_merkle_tree};
pub const DEFAULT_IC_GATEWAY_LOCAL: &str = "http://127.0.0.1:4943";
pub const DEFAULT_IC_GATEWAY_MAINNET: &str = "https://icp0.io";
pub const DEFAULT_IC_GATEWAY_MAINNET_TRAILING_SLASH: &str = "https://icp0.io/";
pub struct Verifier {
pub agent: Agent,
pub canister: Principal,
}
#[derive(CandidType, Deserialize, Debug)]
pub struct PublicKeyReply {
pub sec1_pk: String,
pub etherum_pk: String,
}
#[derive(CandidType, Deserialize, Debug, Clone)]
pub struct VerificationResponse {
pub results: Vec<ProofResponse>,
pub root: String,
pub signature: String,
}
#[derive(CandidType, Deserialize, Debug, Clone)]
pub enum ProofResponse {
SessionProof(String), FullProof(String), }
impl ProofResponse {
pub fn get_content(&self) -> String {
match self {
ProofResponse::SessionProof(content) => content.clone(),
ProofResponse::FullProof(content) => content.clone(),
}
}
}
type CanisterResponseType = Result<VerificationResponse, String>;
impl Verifier {
pub async fn from_config(config: &Config) -> anyhow::Result<Self> {
let agent = config.create_agent().await?;
Ok(Self {
agent,
canister: config.canister_principal,
})
}
async fn verify_canister_response(
&self,
verification_response: &VerificationResponse,
) -> Result<bool, Box<dyn Error>> {
let signature_hex = &verification_response.signature;
let root_hash = &verification_response.root;
let leaves: Vec<String> = verification_response
.results
.iter()
.map(|proof_response| proof_response.get_content())
.collect();
let canister_public_key = self.get_public_key().await?;
let is_signature_valid =
validate_ecdsa_signature(signature_hex, &root_hash, &canister_public_key)?;
let is_merkle_valid = validate_merkle_tree(&leaves, root_hash);
let is_response_valid = is_signature_valid && is_merkle_valid;
Ok(is_response_valid)
}
pub async fn get_public_key(&self) -> Result<String, Box<dyn Error>> {
let method_name = "public_key";
let response = self
.agent
.update(&self.canister, method_name)
.with_arg(candid::encode_args(())?)
.call_and_wait()
.await?;
let public_key_response = Decode!(&response, PublicKeyReply)?;
Ok(public_key_response.etherum_pk)
}
pub async fn verify_proof(
&self,
string_proofs: Vec<String>,
notary_pub_key: String,
) -> Result<VerificationResponse, Box<dyn Error>> {
let verifier_method = "verify_proof_direct";
let response = self
.agent
.update(&self.canister, verifier_method)
.with_arg(candid::encode_args((string_proofs, notary_pub_key))?)
.call_and_wait()
.await
.unwrap();
let verification_response = Decode!(&response, CanisterResponseType)??;
let is_response_valid = self
.verify_canister_response(&verification_response)
.await?;
assert!(is_response_valid, "INVALID_CANISTER_RESPONSE");
Ok(verification_response)
}
}