Zulip Chat Archive
Stream: lean4
Topic: Using bv_decide
Wrenna Robson (Sep 30 2025 at 17:09):
The following proof looks primed for using bv_decide i.e. this is something I just want to throw at a SMT solver! But it doesn't seem to work. Regular decide does, though - it is true.
def mulTwo (x : BitVec 8) : BitVec 8 :=
let b7 := x[7]
let x := x <<< 1
if b7 then x ^^^ 0x1B else x
def mulTwo' (x : BitVec 8) : BitVec 8 :=
let b7 := x[7]
BitVec.ofFnBE ![x[6], x[5], x[4], x[3].xor b7, x[2].xor b7, x[1], x[0].xor b7, b7]
theorem mulTwo_eq_mulTwo' : ∀ x, mulTwo x = mulTwo' x := sorry
What am I doing wrong?
Henrik Böving (Sep 30 2025 at 17:10):
bv_decide canot have knowledge of BitVec.ofFnBE its in batteries
Wrenna Robson (Sep 30 2025 at 17:11):
Right. Is there a way I can specify that bit vector in a way it will understand or do I have to built it from scratch? What is allowed?
Henrik Böving (Sep 30 2025 at 17:12):
bv_decide is supposed to work with all operations on bitvectors that core defines, if your simp set is powerful enough to dumb down BitVec.ofFnBE to that it will be fine
Wrenna Robson (Sep 30 2025 at 17:17):
Hmm
Wrenna Robson (Sep 30 2025 at 17:17):
def mulTwo (x : BitVec 8) : BitVec 8 :=
let b7 := x[7]
let x := x <<< 1
if b7 then x ^^^ 0x1B else x
open BitVec in
def mulTwo' (x : BitVec 8) : BitVec 8 :=
let b7 := x[7]
shiftConcat (shiftConcat (shiftConcat (shiftConcat
(shiftConcat (shiftConcat (shiftConcat (shiftConcat 0 x[6]) x[5]) x[4]) (x[3].xor b7))
(x[2].xor b7)) x[1]) (x[0].xor b7)) b7
theorem mulTwo_eq_mulTwo' : ∀ x : BitVec 8, mulTwo x = mulTwo' x := by
unfold mulTwo mulTwo'
bv_decide -- nope
theorem mulTwo_eq_mulTwo'_decide : ∀ x : BitVec 8, mulTwo x = mulTwo' x := by
unfold mulTwo mulTwo'
decide -- yep
Wrenna Robson (Sep 30 2025 at 17:17):
shiftConcat is in core, I think.
Wrenna Robson (Sep 30 2025 at 17:17):
So what is forbidden here
Henrik Böving (Sep 30 2025 at 17:24):
That's an oversight in the coverage of bv_decide, feel free to open an issue about the fact that I missed shiftConcat and concat.
Henrik Böving (Sep 30 2025 at 17:24):
theorem mulTwo_eq_mulTwo' : ∀ x : BitVec 8, mulTwo x = mulTwo' x := by
unfold mulTwo mulTwo'
simp only [BitVec.shiftConcat, BitVec.concat]
bv_decide
works
Wrenna Robson (Sep 30 2025 at 17:24):
Aha!
Wrenna Robson (Sep 30 2025 at 17:25):
Thank you :)
Wrenna Robson (Sep 30 2025 at 17:25):
I open an issue in core's repo?
Henrik Böving (Sep 30 2025 at 17:25):
Yes
Wrenna Robson (Sep 30 2025 at 17:25):
I'll get on that.
Henrik Böving (Sep 30 2025 at 17:27):
You could even fix it yourself i you're interested in that?
Henrik Böving (Sep 30 2025 at 17:29):
You'd have to prove a lemma such as docs#BitVec.twoPow_eq for shiftConcat and concat and then tag it here https://github.com/leanprover/lean4/blob/master/src/Std/Tactic/BVDecide/Normalize/BitVec.lean#L153 with bv_normalize + add your thing as a test.
Wrenna Robson (Sep 30 2025 at 17:31):
I will try to figure out how to do that. For BitVec.ofFnBE which I used originally, the issue seems to be that Fin.foldr is too crunchy for it to reason about.
Henrik Böving (Sep 30 2025 at 17:32):
Yes Fin.foldr requires higher order reasoning, that's not doable. However when applied to a constant Fin.foldr should be sufficiently symbolically evaluatable using the simp set to make it vanish
Wrenna Robson (Sep 30 2025 at 17:33):
It looks like BitVec.cons might also be missing.
Wrenna Robson (Sep 30 2025 at 17:33):
def mulTwo'' (x : BitVec 8) : BitVec 8 :=
let b7 := x[7]
BitVec.ofBoolListBE [x[6], x[5], x[4], x[3].xor b7, x[2].xor b7, x[1], x[0].xor b7, b7]
theorem mulTwo_eq_mulTwo'' : ∀ x : BitVec 8, mulTwo x = mulTwo'' x := by
unfold mulTwo mulTwo''
simp only [BitVec.ofBoolListBE, BitVec.cons]
bv_decide
Henrik Böving (Sep 30 2025 at 17:33):
Could be, I mostly focused on the operations that are present in SMT-LIB as those are the ones people most commonly use and all the other ones can usually be expressed in terms of them.
Wrenna Robson (Sep 30 2025 at 17:34):
Yeah that is fair. I could look up an AES implementation and see how people normally do this operation anyway.
Henrik Böving (Sep 30 2025 at 17:35):
Oh they most likely extend and then shift + or
Henrik Böving (Sep 30 2025 at 17:35):
just how you would do it in C
Wrenna Robson (Sep 30 2025 at 17:35):
Makes sense.
Wrenna Robson (Sep 30 2025 at 18:04):
BitVec.fill as well I think.
Henrik Böving (Sep 30 2025 at 18:04):
Didn't even know we had that one lol
Wrenna Robson (Sep 30 2025 at 18:05):
Have managed to proof via bitsmashing that muliplication over Galois-256 is commutative so that is nice though.
François G. Dorais (Sep 30 2025 at 23:18):
If there's a way to improve BitVec.ofFnBE etc in Batteries so that it fits better with bv_decide, I would be happy to hear! I've been doing a little GF work and GF2 linear algebra for myself, which is why I added these functions but I never had time to tune the API.
Wrenna Robson (Oct 01 2025 at 00:34):
Oh cool, yeah pretty much me too.
Wrenna Robson (Oct 01 2025 at 00:34):
Would be good to compare notes...
Wrenna Robson (Oct 01 2025 at 00:35):
Actually proving it obeys the field axioms seems quite challenging and I was hoping maybe I could just bit blast my way through the problem.
Henrik Böving (Oct 01 2025 at 09:21):
@Wrenna Robson do you still plan on submitting an issue and/or PR?
Wrenna Robson (Oct 01 2025 at 09:21):
Yes, I just haven't yet!
Wrenna Robson (Oct 01 2025 at 09:21):
I finished at 7PM yesterday so slow start this morning
Last updated: Dec 20 2025 at 21:32 UTC