AlphaProof Code: Verifying Signal’s Security at the Machine-Code Level

Paper › LibsignalBinary/Specifications/LibsignalSpqrV1 › GF16.leanTier 2 · definitions

GF16.lean🔗

Tier 2 · definitions used by the computational proof 2 headline theorems depend on it 93 of 348 lines trusted trust banner B3, trusted in part source ↗

Read the definitions shown. Only the declarations that the headline statements use are shown, with the namespace, section, open and variable commands needed to read them. The collapsed runs are theorems, which Lean checks, and definitions that no headline statement uses.

Declarations on this page (24)

SPQR V1: GF(2^16) arithmetic (src/encoding/gf.rs)

Trusted in part. The theorems of Computational/Theorems/ use every definition in this file except reduce.REDUCE_BYTES, which is checked by Lean (see Computational/docs/TRUSTED_BASE.md).

Unaccelerated software specification of $\mathrm{GF}(2^{16}) = \mathbb{F}_2[x]/(x^{16} + x^{12} + x^3 + x + 1)$ (POLY = 0x1100b, taken under TokenInit, DEV-SPQR1): GF16 (ZERO, ONE, new, add, sub, constSub, mul, constMul, divImpl, div, constDiv), byte-table reduction (reduceFromByte, REDUCE_BYTES, reduceByteEntry, polyReduce), carryless multiplication (polyMul), and paired/slice scaling (mul2U16, parallelMult). All GF16 operations are panic- and overflow-free on u16 inputs; division computes self * other^(2^16 - 2) so division by 0 returns 0.

@[expose] public section
namespace CryptoVerification.LibsignalSpqrV1

Field polynomial and element type (src/encoding/gf.rs:7–18)

def POLYL37–39 ↗#

Irreducible polynomial $x^{16} + x^{12} + x^3 + x + 1$ for $\mathrm{GF}(2^{16})$ (pub const POLY: u32 = 0x1100b, src/encoding/gf.rs:7).

def POLY : BitVec 32 := 0x1100b#32

structure GF16L41–45 ↗#

Element of $\mathrm{GF}(2^{16})$ (pub struct GF16 { pub value: u16 }, src/encoding/gf.rs:16–18).

structure GF16 where value : BitVec 16 deriving DecidableEq, Repr, Inhabited
namespace GF16

def ZEROL49 ↗#

def ZERO : GF16 := ⟨0#16⟩

def ONEL51 ↗#

def ONE : GF16 := ⟨1#16⟩

def newL53 ↗#

def new (value : BitVec 16) : GF16 := ⟨value⟩

Addition and subtraction in $\mathrm{GF}(2^{16})$ (src/encoding/gf.rs:20–123, 565–569)

def addL57–58 ↗#

def add (self other : GF16) : GF16 := ⟨self.value ^^^ other.value⟩

def subL60–61 ↗#

def sub (self other : GF16) : GF16 := add self other

def constSubL63–64 ↗#

def constSub (self other : GF16) : GF16 := ⟨self.value ^^^ other.value⟩
end GF16
namespace reduce

def reduceFromByteLoopL72–82 ↗#

def reduceFromByteLoop : Nat → BitVec 8 → BitVec 32 → BitVec 32 | 0, _, out => out | i + 1, a, out => let mask : BitVec 8 := 1#8 <<< i if (mask &&& a) != 0#8 then let shiftedPoly : BitVec 32 := POLY <<< i let out' := out ^^^ shiftedPoly let a' := a ^^^ ((shiftedPoly >>> 16).truncate 8) reduceFromByteLoop i a' out' else reduceFromByteLoop i a out

def reduceFromByteL84–86 ↗#

reduce::reduce_from_byte(mut a: u8) -> u32 (src/encoding/gf.rs:502–515).

def reduceFromByte (a : BitVec 8) : BitVec 32 := reduceFromByteLoop 8 a 0#32
1 declaration not shown (lines 88–90): theorems, which Lean checks, or definitions that no headline statement uses

CryptoVerification.LibsignalSpqrV1.reduce.REDUCE_BYTES

def reduceByteEntryL92–93 ↗#

def reduceByteEntry (idx : BitVec 8) : BitVec 16 := (reduceFromByte idx).truncate 16

def polyReduceL95–104 ↗#

reduce::poly_reduce(v: u32) -> u16 (src/encoding/gf.rs:489–498): reduces a 32-bit carryless product modulo POLY = 0x1100b in two byte-table lookups.

def polyReduce (v : BitVec 32) : BitVec 16 := let i1 : BitVec 8 := (v >>> 24).truncate 8 let r1 : BitVec 32 := (reduceByteEntry i1).zeroExtend 32 let v1 : BitVec 32 := v ^^^ (r1 <<< 8) let i2 : BitVec 8 := (v1 >>> 16).truncate 8 let r2 : BitVec 32 := (reduceByteEntry i2).zeroExtend 32 let v2 : BitVec 32 := v1 ^^^ r2 v2.truncate 16
end reduce
namespace unaccelerated

def polyMulLoopL112–120 ↗#

def polyMulLoop (me : BitVec 32) (b : BitVec 16) : Nat → Nat → BitVec 32 → BitVec 32 | 0, _, acc => acc | fuel + 1, shift, acc => let acc' := if 0#16 != (b &&& (1#16 <<< shift)) then acc ^^^ (me <<< shift) else acc polyMulLoop me b fuel (shift + 1) acc'

def polyMulL122–124 ↗#

unaccelerated::poly_mul(a: u16, b: u16) -> u32 (src/encoding/gf.rs:381–427).

def polyMul (a b : BitVec 16) : BitVec 32 := polyMulLoop (a.zeroExtend 32) b 16 0 0#32

unaccelerated::mul(a: u16, b: u16) -> u16 (src/encoding/gf.rs:444–446).

def mul (a b : BitVec 16) : BitVec 16 := reduce.polyReduce (polyMul a b)
end unaccelerated

Pair multiplication, field multiplication, and division (src/encoding/gf.rs:125–225, 548–589)

def mul2U16L134–136 ↗#

mul2_u16 (src/encoding/gf.rs:216–225, unaccelerated path).

def mul2U16 (a b1 b2 : BitVec 16) : BitVec 16 × BitVec 16 := (unaccelerated.mul a b1, unaccelerated.mul a b2)

def parallelMultL138–144 ↗#

parallel_mult (src/encoding/gf.rs:201–214).

def parallelMult (a : GF16) : List GF16 → List GF16 | [] => [] | [x] => [⟨unaccelerated.mul x.value a.value⟩] | x1 :: x2 :: rest => let (r1, r2) := mul2U16 a.value x1.value x2.value ⟨r1⟩ :: ⟨r2⟩ :: parallelMult a rest
namespace GF16
def mul (self other : GF16) : GF16 := ⟨unaccelerated.mul self.value other.value⟩

def constMulL151–152 ↗#

def constMul (self other : GF16) : GF16 := ⟨unaccelerated.mul self.value other.value⟩

def divImplLoopL154–158 ↗#

def divImplLoop : Nat → BitVec 16 → BitVec 16 → BitVec 16 | 0, _, out => out | n + 1, square, out => let (square', out') := mul2U16 square square out divImplLoop n square' out'

def divImplL160–165 ↗#

GF16::div_impl (src/encoding/gf.rs:548–557): self * other^(2^16 - 2) (ZERO when other = ZERO).

def divImpl (self other : GF16) : GF16 := let square := (mul other other).value let out := self.value ⟨divImplLoop 15 square out⟩
def div (self other : GF16) : GF16 := divImpl self other

def constDivLoopL170–175 ↗#

def constDivLoop : Nat → GF16 → GF16 → GF16 | 0, _, out => out | n + 1, square, out => let square' := square.constMul square let out' := out.constMul square' constDivLoop n square' out'

def constDivL177–178 ↗#

def constDiv (self other : GF16) : GF16 := constDivLoop 15 other self
end GF16
20 declarations not shown (lines 184–346): theorems, which Lean checks, or definitions that no headline statement uses

CryptoVerification.LibsignalSpqrV1.test_gf_barrett_vector, CryptoVerification.LibsignalSpqrV1.test_reduce_bytes_spot, CryptoVerification.LibsignalSpqrV1.test_poly_reduce_multiples_of_poly, CryptoVerification.LibsignalSpqrV1.test_poly_reduce_low16_id, CryptoVerification.LibsignalSpqrV1.test_poly_reduce_monomials, CryptoVerification.LibsignalSpqrV1.test_gf16_add_sub, CryptoVerification.LibsignalSpqrV1.test_gf16_mul_zero_one, CryptoVerification.LibsignalSpqrV1.test_gf16_generator_wrap, CryptoVerification.LibsignalSpqrV1.test_gf16_ring_laws_sample, CryptoVerification.LibsignalSpqrV1.test_mul2_u16_and_parallel_mult, CryptoVerification.LibsignalSpqrV1.test_gf16_div_by_zero, CryptoVerification.LibsignalSpqrV1.test_gf16_div_zero_and_one, CryptoVerification.LibsignalSpqrV1.test_gf16_inv_generator, CryptoVerification.LibsignalSpqrV1.test_gf16_inverses_batch, CryptoVerification.LibsignalSpqrV1.test_gf16_mul_div_roundtrip, CryptoVerification.LibsignalSpqrV1.test_is_non_zero_all_u8, CryptoVerification.LibsignalSpqrV1.test_is_non_zero_aarch64_equiv, CryptoVerification.LibsignalSpqrV1.test_util_compare, CryptoVerification.LibsignalSpqrV1.test_gf16_concrete_mul_vectors, CryptoVerification.LibsignalSpqrV1.test_gf16_concrete_div_vectors

end CryptoVerification.LibsignalSpqrV1