diff --git a/g16ckt/src/gadgets/bn254/fp254impl.rs b/g16ckt/src/gadgets/bn254/fp254impl.rs index 39b2aa2..84a16f4 100644 --- a/g16ckt/src/gadgets/bn254/fp254impl.rs +++ b/g16ckt/src/gadgets/bn254/fp254impl.rs @@ -696,7 +696,11 @@ pub trait Fp254Impl { exp: &BigUint, ) -> BigIntWires { if exp.is_zero() { - return BigIntWires::new_constant(a.len(), &BigUint::one()).unwrap(); + // a^0 => 1 and Mont(1) => ark::Fq(R) + let r = ark_bn254::Fq::from(Self::montgomery_r_as_biguint()) + .into_bigint() + .into(); + return BigIntWires::new_constant(Self::N_BITS, &r).unwrap(); } if exp.is_one() { diff --git a/g16ckt/src/gadgets/bn254/fq.rs b/g16ckt/src/gadgets/bn254/fq.rs index 8f1cb04..d759ed1 100644 --- a/g16ckt/src/gadgets/bn254/fq.rs +++ b/g16ckt/src/gadgets/bn254/fq.rs @@ -680,6 +680,33 @@ pub(super) mod tests { assert_eq!(result.output_value.value, expected_c); } + #[test] + fn test_exp_by_constant_montgomery() { + let a_v = rnd(); + + // test for random input + let k = rnd().into_bigint(); + let expected_c = a_v.pow(k); + let input = FqInput::new([Fq::as_montgomery(a_v)]); + let result = + CircuitBuilder::streaming_execute::<_, _, FqOutput>(input, 10_000, |ctx, input| { + let [aa_wire] = input; + Fq::exp_by_constant_montgomery(ctx, aa_wire, &k.into()) + }); + assert_eq!(result.output_value.value, Fq::as_montgomery(expected_c)); + + // test for zero exponent + let k: ark_ff::BigInt<4> = ark_ff::BigInt::zero(); + let expected_c = a_v.pow(k); + let input = FqInput::new([Fq::as_montgomery(a_v)]); + let result = + CircuitBuilder::streaming_execute::<_, _, FqOutput>(input, 10_000, |ctx, input| { + let [aa_wire] = input; + Fq::exp_by_constant_montgomery(ctx, aa_wire, &k.into()) + }); + assert_eq!(result.output_value.value, Fq::as_montgomery(expected_c)); + } + #[test] fn test_fq_multiplexer() { let w = 1;