UNSAFE MODULEThis module provides polynomials of degree 64 with coefficients in the field Z(2).; Poly
The coefficients of a polynominal are in reverse (VAX) order: P(x) = x^64 + c[0]*x^63 + c[1]*x^62 + c[2]*x^61 + ... + c[62]*x + c[63]
The leading coefficient is not stored in the 64 bit representation of the basis polynomial. All other polynomials are residues MOD the basis, hence they don't have an x^64 term.
Here's the scoop: Most Significant -- Least Significant c[0] .... c[63] b0 .... b7 i0 .... i1
IMPORT Word; FROM PolyBasis IMPORT poly64, poly72, poly80, poly88, power, power8, power16, power24; CONST SigBits = 16_ffffffff; (* mask to grab 32 significant bits *) TYPE IntBytes = RECORD b0, b1, b2, b3: Byte END; TYPE IntPtr = UNTRACED REF Int32; TYPE DoublePoly = ARRAY [0..3] OF Int32; VAR init_done := FALSE; VAR little_endian := FALSE; VAR big_endian := FALSE; PROCEDURESum (READONLY p, q: T) : T = VAR r : T; BEGIN r[0] := Word.Xor (p[0], q[0]); r[1] := Word.Xor (p[1], q[1]); RETURN r; END Sum; PROCEDUREProduct (READONLY p, q: T) : T = (* returns (p * q MOD PolyBasis.P) *) VAR temp, accum : DoublePoly; z: Word.T; BEGIN (* zero the temporaries *) temp[0]:=0; temp[1]:=0; temp[2]:=0; temp[3]:=0; accum := temp; (* form the 128 bit product in accum *) temp[2] := p[0]; temp[3] := p[1]; FOR j := 1 TO 0 BY -1 DO z := q[j]; FOR i := 31 TO 0 BY -1 DO IF Word.And (z, Word.LeftShift (1, i)) # 0 THEN DoubleINC (accum, temp); END; DoubleTimesX (temp); END; END; (* collapse and return the accumulated result MOD P *) RETURN ComputeMod (ZERO, ADR (accum), BYTESIZE (accum)); END Product; PROCEDUREComputeMod (READONLY t: T; addr: ADDRESS; len: INTEGER): T =
This procedure assumes that the 'len' bytes beginning at address 'addr' define a polynomial, A(x), of degree '(8*len)'. The procedure returns '(init*x^(8*len) + A(x)) MOD PolyBasis.P'
VAR j, k: INTEGER; result := t; BEGIN IF (NOT init_done) THEN FindByteOrder () END; (* word align the source pointer *) j := LOOPHOLE (addr, INTEGER) MOD 4; IF (len >= 4) AND (j # 0) THEN j := 4 - j; result := ExtendBytes (result, addr, j); INC (addr, j); DEC (len, j); END; (* compute the bulk of the result a word at a time *) IF (len >= 4) THEN j := len MOD 4; k := len - j; IF (little_endian) THEN result := ExtendWords_LE (result, addr, k); ELSE result := ExtendWords_BE (result, addr, k); END; INC (addr, k); len := j; END; (* finish up the last few bytes *) IF (len > 0) THEN result := ExtendBytes (result, addr, len); END; RETURN result; END ComputeMod; PROCEDURE******* == Word.LeftShift PROCEDURE LSL (a, cnt : INTEGER) : INTEGER = (* return 'a' shifted 'cnt' bits to the left, zero filling from the rightFix32 (x: Word.T): Int32 = (* return the sign-extended bottom 32 bits of 'x' *) CONST Sign = 16_80000000; SignExtend = Word.LeftShift (Word.Not (0), 31); BEGIN IF Word.And (x, Sign) = 0 THEN RETURN Word.And (x, SigBits); ELSE RETURN Word.Or (SignExtend, Word.And (x, SigBits)); END; END Fix32; PROCEDUREExtendBytes (READONLY t: T; addr: ADDRESS; len: [1..3]): T = VAR cp : UNTRACED REF ARRAY [0..3] OF Byte := addr; n_bits : [8..24] := 8 * len; x_bits : [8..24] := 32 - n_bits; t0 : INTEGER := Word.And (t[0], SigBits); t0_x : INTEGER := Word.LeftShift (t0, x_bits); t0_n : INTEGER := Word.RightShift (t0, n_bits); t1 : INTEGER := Word.And (t[1], SigBits); t1_x : INTEGER := Word.LeftShift (t1, x_bits); t1_n : INTEGER := Word.RightShift (t1, n_bits); tmp : RECORD i: INTEGER; b: ARRAY [0..3] OF Byte; END; result : T; BEGIN result[0] := Fix32 (t0_x); result[1] := Fix32 (Word.Xor (t0_n, t1_x)); CASE len OF | 1 => tmp.b[0] := Word.Extract (t1_n, 0, 8); tmp.b[1] := Word.Extract (t1_n, 8, 8); tmp.b[2] := Word.Extract (t1_n, 16, 8); tmp.b[3] := cp[0]; | 2 => tmp.b[0] := Word.Extract (t1_n, 0, 8); tmp.b[1] := Word.Extract (t1_n, 8, 8); tmp.b[2] := cp[0]; tmp.b[3] := cp[1]; | 3 => tmp.b[0] := Word.Extract (t1_n, 0, 8); tmp.b[1] := cp[0]; tmp.b[2] := cp[1]; tmp.b[3] := cp[2]; END; IF (little_endian) THEN RETURN ExtendWords_LE (result, ADR (tmp.b[0]), BYTESIZE (tmp.b)); ELSE RETURN ExtendWords_BE (result, ADR (tmp.b[0]), BYTESIZE (tmp.b)); END; END ExtendBytes; PROCEDUREExtendWords_LE (READONLY p: T; source: ADDRESS; len: INTEGER): T = VAR ip : IntPtr := source; tmp : IntBytes; p0 : INTEGER := p[0]; p1 : INTEGER := p[1]; BEGIN WHILE (len > 0) DO (* split the low-order bytes *) LOOPHOLE (tmp, Int32) := p0; (* compute the new result *) p0 := Word.Xor (p1, Word.Xor (Word.Xor (poly88[tmp.b0][0], poly80[tmp.b1][0]), Word.Xor (poly72[tmp.b2][0], poly64[tmp.b3][0]))); p1 := Word.Xor (ip^, Word.Xor (Word.Xor (poly88[tmp.b0][1], poly80[tmp.b1][1]), Word.Xor (poly72[tmp.b2][1], poly64[tmp.b3][1]))); DEC (len, BYTESIZE (Int32)); INC (ip, ADRSIZE (ip^)); END; RETURN T {p0, p1}; END ExtendWords_LE; PROCEDUREExtendWords_BE (READONLY p: T; source: ADDRESS; len: INTEGER): T = VAR ip : IntPtr := source; tmp : IntBytes; p0 := p[0]; p1 := p[1]; x, y: Int32; BEGIN WHILE (len > 0) DO (* byte swap the input word -- inline *) y := ip^; LOOPHOLE (x, IntBytes).b0 := LOOPHOLE (y, IntBytes).b3; LOOPHOLE (x, IntBytes).b1 := LOOPHOLE (y, IntBytes).b2; LOOPHOLE (x, IntBytes).b2 := LOOPHOLE (y, IntBytes).b1; LOOPHOLE (x, IntBytes).b3 := LOOPHOLE (y, IntBytes).b0; (* split the low-order bytes *) LOOPHOLE (tmp, Int32) := p0; (* compute the new result *) p0 := Word.Xor (p1, Word.Xor (Word.Xor (poly88[tmp.b3][0], poly80[tmp.b2][0]), Word.Xor (poly72[tmp.b1][0], poly64[tmp.b0][0]))); p1 := Word.Xor (x, Word.Xor (Word.Xor (poly88[tmp.b3][1], poly80[tmp.b2][1]), Word.Xor (poly72[tmp.b1][1], poly64[tmp.b0][1]))); DEC (len, BYTESIZE (Int32)); INC (ip, ADRSIZE (ip^)); END; RETURN T {p0, p1}; END ExtendWords_BE; PROCEDUREPower (d: Card32) : T = (* returns x^d MOD PolyBasis.P *) VAR i : [0..15]; b0, b1, b2, b3: Byte; BEGIN IF (NOT init_done) THEN FindByteOrder () END; IF (little_endian) THEN b0 := LOOPHOLE (d, IntBytes).b0; b1 := LOOPHOLE (d, IntBytes).b1; b2 := LOOPHOLE (d, IntBytes).b2; b3 := LOOPHOLE (d, IntBytes).b3; ELSE b3 := LOOPHOLE (d, IntBytes).b0; b2 := LOOPHOLE (d, IntBytes).b1; b1 := LOOPHOLE (d, IntBytes).b2; b0 := LOOPHOLE (d, IntBytes).b3; END; (* find the non-zero bytes of 'd' *) i := 0; IF (b0 # 0) THEN i := 1; END; IF (b1 # 0) THEN INC (i,2); END; IF (b2 # 0) THEN INC (i,4); END; IF (b3 # 0) THEN INC (i,8); END; CASE i OF | 0 => RETURN ONE; | 1 => RETURN power [b0] | 2 => RETURN power8 [b1]; | 3 => RETURN Product (power8 [b1], power [b0]); | 4 => RETURN power16 [b2]; | 5 => RETURN Product (power16 [b2], power [b0]); | 6 => RETURN Product (power16 [b2], power8 [b1]); | 7 => RETURN Product (power16 [b2], Product (power8 [b1], power [b0])); | 8 => RETURN power24 [b3] | 9 => RETURN Product (power24 [b3], power [b0]); | 10 => RETURN Product (power24 [b3], power8 [b1]); | 11 => RETURN Product (power24 [b3], Product (power8 [b1], power [b0])); | 12 => RETURN Product (power24 [b3], power16 [b2]); | 13 => RETURN Product (power24 [b3], Product (power16 [b2], power [b0])); | 14 => RETURN Product (power24 [b3], Product(power16 [b2], power8 [b1])); | 15 => RETURN Product (Product (power24 [b3], power16 [b2]), Product (power8 [b1], power [b0])); END; END Power; PROCEDURETimesX (READONLY p : T) : T = (* return (p * X^1) *) VAR result : T; BEGIN result[0] := Word.RightShift (p[0], 1); IF Word.And (p[1], 1) # 0 THEN result[0] := Word.Or (result[0], FIRST (Int32)) END; result[1] := Word.RightShift (p[1], 1); RETURN result; END TimesX; PROCEDUREDoubleINC (VAR a,b : DoublePoly) = (* a := a + b *) BEGIN a[0] := Word.Xor (a[0], b[0]); a[1] := Word.Xor (a[1], b[1]); a[2] := Word.Xor (a[2], b[2]); a[3] := Word.Xor (a[3], b[3]); END DoubleINC; PROCEDUREDoubleTimesX (VAR a : DoublePoly) = (* a := a*x *) BEGIN a[0] := Word.RightShift (a[0], 1); IF Word.And (a[1], 1) # 0 THEN a[0] := Word.Or (a[0], FIRST (Int32)); END; a[1] := Word.RightShift (a[1], 1); IF Word.And (a[2], 1) # 0 THEN a[1] := Word.Or (a[1], FIRST (Int32)); END; a[2] := Word.RightShift (a[2], 1); IF Word.And (a[3], 1) # 0 THEN a[2] := Word.Or (a[2], FIRST (Int32)); END; a[3] := Word.RightShift (a[3], 1); END DoubleTimesX;
BEGIN RETURN Word.Shift (a, cnt); END LSL; ******)****** == Word.RightShift (a,cnt) = Word.Shift(a,-cnt) = LSR(a,cnt) PROCEDURE LSR (a, cnt : INTEGER) : INTEGER = (* return 'a' shifted 'cnt' bits to the right, zero filling from the left
BEGIN RETURN Word.Shift (a, -cnt); END LSR; *******)******* PROCEDURE ByteSwap (x: INTEGER): INTEGER = VAR z: INTEGER; BEGIN LOOPHOLE (z, IntBytes).b0 := LOOPHOLE (x, IntBytes).b3; LOOPHOLE (z, IntBytes).b1 := LOOPHOLE (x, IntBytes).b2; LOOPHOLE (z, IntBytes).b2 := LOOPHOLE (x, IntBytes).b1; LOOPHOLE (z, IntBytes).b3 := LOOPHOLE (x, IntBytes).b0; RETURN z; END ByteSwap; ********
PROCEDUREFindByteOrder () = VAR i : Int32 := 16_12345678; x := LOOPHOLE (i, IntBytes); a0 := Word.Extract (i, 0, 8); a1 := Word.Extract (i, 8, 8); a2 := Word.Extract (i, 16, 8); a3 := Word.Extract (i, 24, 8); BEGIN IF (a0 = x.b0) AND (a1 = x.b1) AND (a2 = x.b2) AND (a3 = x.b3) THEN little_endian := TRUE; ELSIF (a0 = x.b3) AND (a1 = x.b2) AND (a2 = x.b1) AND (a3 = x.b0) THEN big_endian := TRUE; ELSE (* unsupported byte ordering ... *) (* Process.Crash ("Poly.FindByteOrder: unknown byte order"); *) <*ASSERT FALSE*> END; init_done := TRUE; END FindByteOrder; PROCEDUREToBytes (READONLY t: T; VAR b: Bytes) = (* generate the bytes in little-endian order *) BEGIN b[0] := Word.Extract (t[0], 0, 8); b[1] := Word.Extract (t[0], 8, 8); b[2] := Word.Extract (t[0], 16, 8); b[3] := Word.Extract (t[0], 24, 8); b[4] := Word.Extract (t[1], 0, 8); b[5] := Word.Extract (t[1], 8, 8); b[6] := Word.Extract (t[1], 16, 8); b[7] := Word.Extract (t[1], 24, 8); END ToBytes; PROCEDUREFromBytes (READONLY b: Bytes; VAR t: T) = (* assume the bytes are in little-endian order *) BEGIN t[0] := Fix32 (Word.Or (Word.Or ( b[0], Word.LeftShift (b[1], 8)), Word.Or (Word.LeftShift (b[2], 16), Word.LeftShift (b[3], 24)))); t[1] := Fix32 (Word.Or (Word.Or ( b[4], Word.LeftShift (b[5], 8)), Word.Or (Word.LeftShift (b[6], 16), Word.LeftShift (b[7], 24)))); END FromBytes; BEGIN <* ASSERT BITSIZE (Int32) = 32 AND BITSIZE (CHAR) = 8 *> END Poly.