pub fn lift_x(m: SepticExtension<F>) -> (Self, u8, [F; 16], [F; 16]) {
        let perm = BabyBearPoseidon2::new().perm;
        for offset in 0..=255 {
            let m_trial = [
                m.0[0],
                m.0[1],
                m.0[2],
                m.0[3],
                m.0[4],
                m.0[5],
                m.0[6],
                F::from_canonical_u8(offset),
                F::zero(),
                F::zero(),
                F::zero(),
                F::zero(),
                F::zero(),
                F::zero(),
                F::zero(),
                F::zero(),
            ];

            let m_hash = perm
                .permute(m_trial.map(|x| BabyBear::from_canonical_u32(x.as_canonical_u32())))
                .map(|x| F::from_canonical_u32(x.as_canonical_u32()));
            let x_trial = SepticExtension(m_hash[..7].try_into().unwrap());

            let y_sq = Self::curve_formula(x_trial);
            if let Some(y) = y_sq.sqrt() {
                if y.is_exception() {
                    continue;
                }
                if y.is_send() {
                    return (Self { x: x_trial, y: -y }, offset, m_trial, m_hash);
                }
                return (Self { x: x_trial, y }, offset, m_trial, m_hash);
            }
        }
        panic!("curve point couldn't be found after 256 attempts");
    }
Lift an x coordinate into an elliptic curve.
As an x-coordinate may not be a valid one, we allow an additional value in `[0, 256)` to the
hash input. Also, we always return the curve point with y-coordinate within `[1,
(p-1)/2]`, where p is the characteristic. The returned values are the curve point, the
offset used, and the hash input and output.
crates/stark/src/septic_curve.rs