12.6. Worked example
The first block runs the packed operations: the bit accessors, XOR addition, the shift, and a gcd.
open Hex Hex.GF2Poly
namespace HexGF2Chapter
-- A monomial sets exactly one coefficient bit.
#guard (GF2Poly.monomial 5).degree = 5
#guard (GF2Poly.monomial 5).coeff 5 = true
#guard (GF2Poly.monomial 5).coeff 4 = false
-- Addition is XOR, so a polynomial added to
-- itself cancels to zero.
#guard (GF2Poly.monomial 3
+ GF2Poly.monomial 3).isZero = true
-- The leading term governs the degree of a sum.
#guard (GF2Poly.monomial 3
+ GF2Poly.monomial 5).degree = 5
-- Shifting left by k multiplies by x^k.
#guard ((GF2Poly.monomial 1).shiftLeft 3).toWords
= (GF2Poly.monomial 4).toWords
-- gcd(f, f) = f, up to the monic normalization
-- that holds automatically over F_2.
#guard (GF2Poly.gcd (GF2Poly.monomial 7)
(GF2Poly.monomial 7)).degree = 7
end HexGF2Chapter
The second block works inside the AES field GF(2⁸), presented by the
Rijndael modulus x⁸ + x⁴ + x³ + x + 1 (the word 0x1B above the
leading x⁸). The irreducibility of that modulus is the committed
theorem Hex.GF2Poly.aes_modulus_irreducible, so the field type
typechecks. The byte 0x53 and its inverse 0xCA are the standard AES
worked pair.
open Hex
namespace HexGF2Chapter
abbrev AES : Type :=
GF2n 8 0x1B (⊢ 0 < 8 All goals completed! 🐙) (⊢ 8 < 64 All goals completed! 🐙)
GF2Poly.aes_modulus_irreducible
def aes (w : UInt64) : AES := GF2n.reduce w
-- 0x53 and 0xCA are inverse bytes in AES's GF(2^8),
-- so their product is 1.
#guard ((aes 0x53) * (aes 0xCA)).val = 1
#guard ((aes 0x53)⁻¹).val = 0xCA
end HexGF2Chapter