Copyright (C) 1994, Digital Equipment Corp.
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[0] := p[0]; temp[1] := p[1]; FOR j := 0 TO 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 Fix32 (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;
PROCEDURE ExtendBytes (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;
PROCEDURE ExtendWords_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;
PROCEDURE ExtendWords_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;
PROCEDURE Power (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;
PROCEDURE TimesX (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;
PROCEDURE DoubleINC (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;
PROCEDURE DoubleTimesX (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;
******* == Word.LeftShift
PROCEDURE LSL (a, cnt : INTEGER) : INTEGER =
(* return 'a' shifted 'cnt' bits to the left, zero filling from the right
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.