use crate::allocator::{Allocator, NodePtr};
use crate::chia_dialect::ClvmFlags;
use crate::cost::{Cost, check_cost};
use crate::error::EvalErr;
use crate::op_utils::{atom, get_args};
use crate::reduction::{Reduction, Response};
use k256::ecdsa::{Signature as K1Signature, VerifyingKey as K1VerifyingKey};
use p256::ecdsa::signature::hazmat::PrehashVerifier;
use p256::ecdsa::{Signature as P1Signature, VerifyingKey as P1VerifyingKey};
const SECP256R1_VERIFY_COST: Cost = 1850000;
const SECP256K1_VERIFY_COST: Cost = 1300000;
pub fn op_secp256r1_verify(
a: &mut Allocator,
input: NodePtr,
max_cost: Cost,
_flags: ClvmFlags,
) -> Response {
let cost = SECP256R1_VERIFY_COST;
check_cost(cost, max_cost)?;
let [pubkey, msg, sig] = get_args::<3>(a, input, "secp256r1_verify")?;
let pubkey = atom(a, pubkey, "secp256r1_verify pubkey")?;
let verifier = P1VerifyingKey::from_sec1_bytes(pubkey.as_ref()).map_err(|_| {
EvalErr::InvalidOpArg(input, "secp256r1_verify: pubkey is not valid".to_string())
})?;
let msg = atom(a, msg, "secp256r1_verify msg")?;
if msg.as_ref().len() != 32 {
Err(EvalErr::InvalidOpArg(
input,
"secp256r1_verify: message digest is not 32 bytes".to_string(),
))?;
}
let sig = atom(a, sig, "secp256r1_verify sig")?;
let sig = P1Signature::from_slice(sig.as_ref()).map_err(|_| {
EvalErr::InvalidOpArg(
input,
"secp256r1_verify: signature is not valid".to_string(),
)
})?;
let result = verifier.verify_prehash(msg.as_ref(), &sig);
if result.is_err() {
Err(EvalErr::Secp256Failed(input))?
} else {
Ok(Reduction(cost, a.nil()))
}
}
pub fn op_secp256k1_verify(
a: &mut Allocator,
input: NodePtr,
max_cost: Cost,
_flags: ClvmFlags,
) -> Response {
let cost = SECP256K1_VERIFY_COST;
check_cost(cost, max_cost)?;
let [pubkey, msg, sig] = get_args::<3>(a, input, "secp256k1_verify")?;
let pubkey = atom(a, pubkey, "secp256k1_verify pubkey")?;
let verifier = K1VerifyingKey::from_sec1_bytes(pubkey.as_ref()).map_err(|_| {
EvalErr::InvalidOpArg(input, "secp256k1_verify: pubkey is not valid".to_string())
})?;
let msg = atom(a, msg, "secp256k1_verify msg")?;
if msg.as_ref().len() != 32 {
Err(EvalErr::InvalidOpArg(
input,
"secp256k1_verify: message digest is not 32 bytes".to_string(),
))?;
}
let sig = atom(a, sig, "secp256k1_verify sig")?;
let sig = K1Signature::from_slice(sig.as_ref()).map_err(|_| {
EvalErr::InvalidOpArg(
input,
"secp256k1_verify: signature is not valid".to_string(),
)
})?;
let result = verifier.verify_prehash(msg.as_ref(), &sig);
if result.is_err() {
Err(EvalErr::Secp256Failed(input))?
} else {
Ok(Reduction(cost, a.nil()))
}
}