w3f_plonk_common/
cond_select.rs1use ark_ec::short_weierstrass::{Projective as SwProjective, SWCurveConfig};
13use ark_ec::twisted_edwards::{Projective as TeProjective, TECurveConfig};
14use ark_ff::{BigInt, Field, Fp, FpConfig};
15use ark_std::marker::PhantomData;
16use subtle::ConditionallySelectable;
17
18pub use subtle::Choice;
19
20pub trait IntoChoice {
25 fn into_choice(self) -> Choice;
26}
27
28impl IntoChoice for Choice {
29 fn into_choice(self) -> Choice {
30 self
31 }
32}
33
34impl IntoChoice for bool {
35 fn into_choice(self) -> Choice {
36 Choice::from(self as u8)
37 }
38}
39
40pub fn bit_to_field<F: Field + CondSelect>(bit: bool) -> F {
42 F::select(bit, &F::one(), &F::zero())
43}
44
45pub trait CondSelect: Sized {
47 fn select(bit: impl IntoChoice, if_true: &Self, if_false: &Self) -> Self;
48}
49
50impl<P: FpConfig<N>, const N: usize> CondSelect for Fp<P, N> {
51 fn select(bit: impl IntoChoice, if_true: &Self, if_false: &Self) -> Self {
52 let limbs =
53 <[u64; N]>::conditional_select(&if_false.0 .0, &if_true.0 .0, bit.into_choice());
54 Fp(BigInt(limbs), PhantomData)
55 }
56}
57
58impl<C: TECurveConfig> CondSelect for TeProjective<C>
59where
60 C::BaseField: CondSelect,
61{
62 fn select(bit: impl IntoChoice, if_true: &Self, if_false: &Self) -> Self {
63 let choice = bit.into_choice();
64 Self::new_unchecked(
65 CondSelect::select(choice, &if_true.x, &if_false.x),
66 CondSelect::select(choice, &if_true.y, &if_false.y),
67 CondSelect::select(choice, &if_true.t, &if_false.t),
68 CondSelect::select(choice, &if_true.z, &if_false.z),
69 )
70 }
71}
72
73impl<C: SWCurveConfig> CondSelect for SwProjective<C>
74where
75 C::BaseField: CondSelect,
76{
77 fn select(bit: impl IntoChoice, if_true: &Self, if_false: &Self) -> Self {
78 let choice = bit.into_choice();
79 Self::new_unchecked(
80 CondSelect::select(choice, &if_true.x, &if_false.x),
81 CondSelect::select(choice, &if_true.y, &if_false.y),
82 CondSelect::select(choice, &if_true.z, &if_false.z),
83 )
84 }
85}
86
87#[cfg(test)]
88mod tests {
89 use super::*;
90 use ark_ed_on_bls12_381_bandersnatch::{EdwardsProjective, Fq};
91 use ark_std::{test_rng, UniformRand};
92
93 #[test]
94 fn bit_lift_is_exact() {
95 assert_eq!(bit_to_field::<Fq>(false), Fq::from(0));
96 assert_eq!(bit_to_field::<Fq>(true), Fq::from(1));
97 }
98
99 #[test]
103 fn select_returns_exact_operand() {
104 let rng = &mut test_rng();
105 let a = Fq::rand(rng);
106 let b = Fq::rand(rng);
107 assert_eq!(Fq::select(true, &a, &b), a);
108 assert_eq!(Fq::select(false, &a, &b), b);
109
110 let p = EdwardsProjective::rand(rng);
111 let q = EdwardsProjective::rand(rng);
112 let s = EdwardsProjective::select(true, &p, &q);
113 assert_eq!((s.x, s.y, s.t, s.z), (p.x, p.y, p.t, p.z));
114 let s = EdwardsProjective::select(false, &p, &q);
115 assert_eq!((s.x, s.y, s.t, s.z), (q.x, q.y, q.t, q.z));
116 }
117}