use halo2_base::utils::BigPrimeField;
use halo2_base::{gates::GateInstructions, utils::CurveAffineExt, AssignedValue, Context};
use crate::bigint::{big_is_equal, big_less_than, FixedOverflowInteger, ProperCrtUint};
use crate::fields::{fp::FpChip, FieldChip};
use super::{fixed_base, scalar_multiply, EcPoint, EccChip};
pub fn ecdsa_verify_no_pubkey_check<F: BigPrimeField, CF: BigPrimeField, SF: BigPrimeField, GA>(
chip: &EccChip<F, FpChip<F, CF>>,
ctx: &mut Context<F>,
pubkey: EcPoint<F, <FpChip<F, CF> as FieldChip<F>>::FieldPoint>,
r: ProperCrtUint<F>,
s: ProperCrtUint<F>,
msghash: ProperCrtUint<F>,
var_window_bits: usize,
fixed_window_bits: usize,
) -> AssignedValue<F>
where
GA: CurveAffineExt<Base = CF, ScalarExt = SF>,
{
let base_chip = chip.field_chip;
let scalar_chip =
FpChip::<F, SF>::new(base_chip.range, base_chip.limb_bits, base_chip.num_limbs);
let n = scalar_chip.p.to_biguint().unwrap();
let n = FixedOverflowInteger::from_native(&n, scalar_chip.num_limbs, scalar_chip.limb_bits);
let n = n.assign(ctx);
let r_valid = scalar_chip.is_soft_nonzero(ctx, &r);
let s_valid = scalar_chip.is_soft_nonzero(ctx, &s);
let u1 = scalar_chip.divide_unsafe(ctx, msghash, &s);
let u2 = scalar_chip.divide_unsafe(ctx, &r, s);
let u1_mul = fixed_base::scalar_multiply(
base_chip,
ctx,
&GA::generator(),
u1.limbs().to_vec(),
base_chip.limb_bits,
fixed_window_bits,
);
let u2_mul = scalar_multiply::<_, _, GA>(
base_chip,
ctx,
pubkey,
u2.limbs().to_vec(),
base_chip.limb_bits,
var_window_bits,
);
let x_eq = base_chip.is_equal(ctx, &u1_mul.x, &u2_mul.x);
let x_neq = base_chip.gate().not(ctx, x_eq);
let y_eq = base_chip.is_equal(ctx, &u1_mul.y, &u2_mul.y);
let u1g_u2pk_not_neg = base_chip.gate().or(ctx, x_neq, y_eq);
let sum = chip.sum::<GA>(ctx, [u1_mul, u2_mul]);
let x1 = scalar_chip.enforce_less_than(ctx, sum.x);
let equal_check = big_is_equal::assign(base_chip.gate(), ctx, x1.0, r);
let u1_small = big_less_than::assign(
base_chip.range(),
ctx,
u1,
n.clone(),
base_chip.limb_bits,
base_chip.limb_bases[1],
);
let u2_small = big_less_than::assign(
base_chip.range(),
ctx,
u2,
n,
base_chip.limb_bits,
base_chip.limb_bases[1],
);
let res1 = base_chip.gate().and(ctx, r_valid, s_valid);
let res2 = base_chip.gate().and(ctx, res1, u1_small);
let res3 = base_chip.gate().and(ctx, res2, u2_small);
let res4 = base_chip.gate().and(ctx, res3, u1g_u2pk_not_neg);
let res5 = base_chip.gate().and(ctx, res4, equal_check);
res5
}