Przeglądaj źródła

got significantly faster by utilizing the new types UNSIGNED32 and UNSIGNED64

git-svn-id: https://svn.inf.ethz.ch/svn/lecturers/a2/trunk@8593 8c9fc860-2736-0410-a75d-ab315db34111
eth.guenter 6 lat temu
rodzic
commit
cb422d990f
1 zmienionych plików z 54 dodań i 92 usunięć
  1. 54 92
      source/CryptoBigNumbers.Mod

+ 54 - 92
source/CryptoBigNumbers.Mod

@@ -13,7 +13,8 @@ CONST
 	BufferPoolSize = 16;
 
 TYPE
-	digits = POINTER TO ARRAY OF LONGINT;
+	BNdigit = UNSIGNED32;
+	digits = POINTER TO ARRAY OF BNdigit;
 
 	BigNumber* = OBJECT
 			VAR
@@ -25,7 +26,7 @@ TYPE
 				VAR n: LONGINT;
 				BEGIN
 					IF bitsize # 0 THEN
-						n := SHORT( (bitsize + 31) DIV 32 );
+						n := (bitsize + 31) DIV 32;
 						INC( n, (-n) MOD 16 );
 						NEW( d, n );
 					END;
@@ -37,7 +38,7 @@ TYPE
 				BEGIN
 					w := bits DIV 32;  b := bits MOD 32;  len := w;
 					IF b # 0 THEN  INC( len );
-						d[w] := S.VAL( LONGINT,  S.VAL( SET32, d[w] ) * {0..b} )
+						d[w] := S.VAL( UNSIGNED32,  S.VAL( SET32, d[w] ) * {0..b} )
 					END
 				END Mask;
 
@@ -70,7 +71,7 @@ TYPE
 
 
 				PROCEDURE Shift*( n: LONGINT );
-				VAR right: BOOLEAN;  w, bits, i, l: LONGINT;  a, b: LONGINT;
+				VAR right: BOOLEAN;  w, bits, i, l: LONGINT;  a, b: BNdigit;
 				BEGIN
 					IF len = 0 THEN  RETURN  END;
 					IF n < 0 THEN  right := TRUE;  n := ABS( n )  ELSE  right := FALSE  END;
@@ -142,7 +143,7 @@ TYPE
 				END Negate;
 	
 				PROCEDURE BitSize*( ): LONGINT;
-				VAR n, t: LONGINT;
+				VAR n: LONGINT; t: BNdigit;
 				BEGIN
 					IF len = 0 THEN  RETURN 0
 					ELSE  n := (len - 1) * 32
@@ -176,8 +177,8 @@ TYPE
 
 			END BigNumber;
 
-	dig2 = ARRAY 2 OF LONGINT;
-	dig3 = ARRAY 3 OF LONGINT;
+	dig2 = ARRAY 2 OF BNdigit;
+	dig3 = ARRAY 3 OF BNdigit;
 
 	Montgomery = OBJECT
 				VAR
@@ -231,28 +232,6 @@ VAR
 	randomgenerator: Random.Generator;
 
 
-	PROCEDURE max( a, b: LONGINT ): LONGINT;
-	BEGIN
-		IF a >= b THEN  RETURN a  ELSE  RETURN b  END;
-	END max;
-
-	PROCEDURE LessThan( x, y: LONGINT ): BOOLEAN;  (* unsigned < *)
-	VAR a, b: LONGINT;
-	BEGIN
-		a := LSH( x, -1 );  b := LSH( y, -1 );
-		IF a = b THEN  RETURN (x MOD 2) < (y MOD 2)  ELSE  RETURN a < b  END
-	END LessThan;
-
-	PROCEDURE LessOrEqual( x, y: LONGINT ): BOOLEAN;  (* unsigned <= *)
-	VAR a, b: LONGINT;
-	BEGIN
-		IF x = y THEN  RETURN TRUE
-		ELSE
-			a := LSH( x, -1 );  b := LSH( y, -1 );
-			IF a = b THEN  RETURN (x MOD 2) < (y MOD 2)  ELSE  RETURN a < b  END
-		END
-	END LessOrEqual;
-
 	PROCEDURE RandomBytes*( VAR buf: ARRAY OF CHAR;  p: LONGINT;  n: LONGINT );
 	VAR i: LONGINT;
 	BEGIN
@@ -348,7 +327,7 @@ VAR
 	(** Returns the value of b as a binary string 'data' starting at ofs.
 		The Length of 'data' must be longer or equal to 4*b.len + ofs. *)
 	PROCEDURE GetBinaryValue*( VAR b: BigNumber; VAR data: ARRAY OF CHAR; ofs: LONGINT );
-	VAR j, n, tmp: LONGINT;
+	VAR j, n: LONGINT;  tmp: BNdigit;
 	BEGIN
 		ASSERT( LEN( data ) >= 4 * b.len + ofs );
 		FOR n := b.len-1 TO 0 BY -1 DO
@@ -375,7 +354,7 @@ VAR
 		WHILE (i >= 0) & (a[i] = b[i]) DO  DEC( i )  END;
 		IF i < 0 THEN  RETURN 0
 		ELSE
-			IF LessThan( b[i], a[i] ) THEN  RETURN 1  ELSE  RETURN -1  END
+			IF b[i] < a[i] THEN  RETURN 1  ELSE  RETURN -1  END
 		END
 	END cmpd;
 
@@ -409,23 +388,21 @@ VAR
 		copy( a.d, b.d, a.len );  b.len := a.len
 	END Copy;
 
-	PROCEDURE Invert( x: LONGINT ): LONGINT;
+	PROCEDURE Invert( x: BNdigit ): BNdigit;
 	BEGIN
-		RETURN S.VAL( LONGINT, -S.VAL( SET32, x ) )
+		RETURN S.VAL( BNdigit, -S.VAL( SET32, x ) )
 	END Invert;
 
 	PROCEDURE add( a, b: digits; VAR c: digits;  al, bl: LONGINT;  VAR cl: LONGINT );
-	VAR i, n: LONGINT;  A, B, x: LONGINT;  carry: BOOLEAN;
+	VAR i, n: LONGINT;  A, B, x: BNdigit;  carry: BOOLEAN;
 	BEGIN
-		n := max( al, bl );  carry := FALSE;
+		n := MAX( al, bl );  carry := FALSE;
 		IF LEN( c^ ) < (n + 1) THEN  adjust( c, cl, n + 1 )  END;
 		FOR i := 0 TO n - 1 DO
 			IF i >= al THEN  A := 0  ELSE  A := a[i]  END;
 			IF i >= bl THEN  B := 0  ELSE  B := b[i]  END;
 			x := A + B;
-			IF carry THEN  INC( x );  carry := LessOrEqual( Invert( A ), B )  
-			ELSE  carry := LessThan( x, B )  
-			END;
+			IF carry THEN  INC( x );  carry := Invert(A) <= B  ELSE  carry := x < B  END;
 			c[i]:= x
 		END;
 		IF carry  THEN  c[n] := 1;  INC( n )  END;
@@ -433,15 +410,15 @@ VAR
 	END add;
 
 	PROCEDURE sub( a, b: digits;  VAR c: digits;  al, bl: LONGINT;  VAR cl: LONGINT );
-	VAR i, n: LONGINT;  A, B, x: LONGINT;  borrow: BOOLEAN;
+	VAR i, n: LONGINT;  A, B, x: BNdigit;  borrow: BOOLEAN;
 	BEGIN
-		n := max( al, bl );  borrow := FALSE;
+		n := MAX( al, bl );  borrow := FALSE;
 		IF LEN( c^ ) < n THEN  adjust( c, cl, n )  END;
 		FOR i := 0 TO n - 1 DO
 			IF i >= al THEN  A := 0  ELSE  A := a[i]  END;
 			IF i >= bl THEN  B := 0  ELSE  B := b[i]  END;
 			x := A - B;
-			IF borrow THEN  DEC( x );  borrow := LessOrEqual( A, B )  ELSE  borrow := LessThan( A, B )  END;
+			IF borrow THEN  DEC( x );  borrow := A <= B  ELSE  borrow := A < B  END;
 			c[i]:= x
 		END;
 		ASSERT( ~borrow );
@@ -453,7 +430,7 @@ VAR
 	VAR sd: digits;  l, sl: LONGINT;  c: BigNumber;
 	BEGIN
 		ASSERT( (a # NIL) & (b # NIL) );
-		l := max( a.len, b.len ) + 1;
+		l := MAX( a.len, b.len ) + 1;
 		NEW( c, l*32 );  sd := c.d;
 		IF a.neg = b.neg THEN  add( a.d, b.d, sd, a.len, b.len, sl );  c.neg := a.neg
 		ELSE
@@ -471,7 +448,7 @@ VAR
 	VAR sd: digits;  l, sl: LONGINT;  c: BigNumber;
 	BEGIN
 		ASSERT( (a # NIL) & (b # NIL) );
-		l := max( a.len, b.len ) + 1;
+		l := MAX( a.len, b.len ) + 1;
 		NEW( c, l*32 );  sd := c.d;
 		IF a.neg # b.neg THEN  add( a.d, b.d, sd, a.len, b.len, sl );  c.neg := a.neg
 		ELSE
@@ -486,29 +463,10 @@ VAR
 	END Sub;
 
 
-	PROCEDURE MulAdd( VAR high, low: LONGINT;  b, c, d: LONGINT );  	(* high | low := b * c + d *)
-	VAR bh, bl, ch, cl, u, t, sum: LONGINT;
-	BEGIN
-		bh := LSH( b, -16 );  bl := b MOD 10000H;
-		ch := LSH( c, -16 );  cl := c MOD 10000H;
-		low := bl*cl;  t := ch*bl;  u := cl*bh;  high := bh*ch;
-		INC( t, u );
-		IF LessThan( t, u ) THEN  INC( high, 10000H )  END;
-		u := t*10000H;  INC( low, u );
-		IF LessThan( low, u ) THEN  INC( high )  END;
-		INC( high, LSH( t, -16 ) );
-
-		sum := low + d;
-		IF LessThan( sum, low ) THEN  INC( high )  END;
-		low := sum
-	END MulAdd;
-
-
-
-	PROCEDURE mul( a, b: digits; VAR c: digits;  al, bl: LONGINT;  VAR cl: LONGINT );  (* c := a*b *)
+	PROCEDURE mul( a, b: digits; VAR c: digits;  al, bl: LONGINT;  VAR cl: LONGINT );  (* c = a*b *)
 	VAR
-		prod, sum, tmp, mulc: LONGINT;  addc: BOOLEAN;  i, j: LONGINT;  pl: LONGINT;
-		p: digits;
+		prod, sum, tmp, mulc: BNdigit;  addc: BOOLEAN;  i, j: LONGINT;  pl: LONGINT;
+		p: digits;  tmp64: UNSIGNED64;
 	BEGIN
 		pl := 0;  NEW( p, al + bl + 2 );
 		FOR i := 0 TO al + bl + 1 DO  p[i] := 0  END;	(* clear acc *)
@@ -516,10 +474,12 @@ VAR
 			mulc := 0;  addc := FALSE;  pl := i;
 			FOR j := 0 TO al - 1 DO
 				tmp := p[pl];
-				MulAdd( mulc, prod, a[j], b[i], mulc );
+				tmp64 := UNSIGNED64( a[j] )*b[i] + mulc;
+				prod := BNdigit( tmp64 MOD 100000000H );
+				mulc := BNdigit( tmp64 DIV 100000000H );
 				sum := prod + tmp;
-				IF addc THEN  INC( sum );  addc := LessOrEqual( Invert( prod ), tmp )
-				ELSE  addc := LessThan( sum, tmp )
+				IF addc THEN  INC( sum );  addc := Invert(prod) <= tmp
+				ELSE  addc := sum < tmp
 				END;
 				p[pl] := sum;  INC( pl );
 			END;
@@ -531,12 +491,14 @@ VAR
 		c := p;  cl := pl;  fixlen( c, cl );
 	END mul;
 
-	PROCEDURE muls( a: digits;  b: LONGINT; c: digits;  al: LONGINT;  VAR cl: LONGINT );  (* c := a * b *)
-	VAR carry: LONGINT;  i: LONGINT;
+	PROCEDURE muls( a: digits;  b: BNdigit; c: digits;  al: LONGINT;  VAR cl: LONGINT );  (* c = a*b *)
+	VAR carry: BNdigit;  tmp64: UNSIGNED64;  i: LONGINT;
 	BEGIN
 		carry := 0;  cl := al;
 		FOR i := 0 TO al - 1 DO
-			MulAdd( carry, c[i], a[i], b, carry );
+			tmp64 := UNSIGNED64( a[i] )*b + carry;
+			c[i] := BNdigit( tmp64 MOD 100000000H );
+			carry := BNdigit( tmp64 DIV 100000000H );
 		END;
 		IF carry # 0 THEN  c[cl] := carry;  INC( cl )  END
 	END muls;
@@ -556,12 +518,12 @@ VAR
 		RETURN c
 	END Mul;
 
-	PROCEDURE div64( CONST a: dig2;  VAR b: LONGINT ): LONGINT;   (* a div b *)
-	VAR bit: LONGINT;  q, r: LONGINT;  overflow: BOOLEAN;
+	PROCEDURE div64( CONST a: dig2;  VAR b: BNdigit ): LONGINT;   (* a div b *)
+	VAR bit, q: LONGINT;  r: BNdigit;  overflow: BOOLEAN;
 	BEGIN
 		IF a[1] = 0 THEN
-			IF (a[0] >= 0) & (b >= 0 ) THEN  RETURN a[0] DIV b
-			ELSIF LessThan( a[0], b ) THEN  RETURN 0
+			IF (a[0] < 80000000H) & (b < 80000000H ) THEN  RETURN LONGINT( a[0] DIV b )
+			ELSIF a[0] < b THEN  RETURN 0
 			ELSIF a[0] = b THEN  RETURN 1
 			END;
 			bit := 31
@@ -571,9 +533,9 @@ VAR
 		q := 0;  r := 0;
 		WHILE (bit >= 0) & ~(bit MOD 32 IN S.VAL( SET32, a[bit DIV 32]) ) DO  DEC( bit )  END;
 		WHILE bit >= 0 DO
-			overflow := r < 0;  r := ASH( r, 1 );
+			overflow := 31 IN S.VAL( SET32, r );  r := ASH( r, 1 );
 			IF bit MOD 32 IN S.VAL( SET32, a[bit DIV 32] ) THEN  INC( r )  END;
-			IF overflow OR LessOrEqual( b, r ) THEN  r := r - b;
+			IF overflow OR (b <= r) THEN  r := r - b;
 				IF bit < 32 THEN  INCL( S.VAL( SET32, q ), bit )  ELSE  q := -1  END;
 			END;
 			DEC( bit )
@@ -586,21 +548,21 @@ VAR
 
 		PROCEDURE ge( CONST a, b: dig2 ): BOOLEAN;
 		BEGIN
-			IF a[1] = b[1] THEN  RETURN ~LessThan( a[0], b[0] )
-			ELSE  RETURN ~LessThan( a[1], b[1] )
+			IF a[1] = b[1] THEN  RETURN a[0] >= b[0]
+			ELSE  RETURN a[1] >= b[1]
 			END
 		END ge;
 
 		PROCEDURE shift( VAR x: dig2 );
 		BEGIN
-			overflow := x[1] < 0;  x[1] := ASH( x[1], 1 );
-			IF x[0] < 0 THEN  INC( x[1] )  END;
+			overflow := 31 IN S.VAL( SET32, x[1] );  x[1] := ASH( x[1], 1 );
+			IF 31 IN S.VAL( SET32, x[0] ) THEN  INC( x[1] )  END;
 			x[0] := ASH( x[0], 1 );
 		END shift;
 
 	BEGIN
 		IF a[2] = 0 THEN
-			IF LessThan( a[1], b[1] ) THEN  RETURN 0  END;
+			IF a[1] < b[1] THEN  RETURN 0  END;
 			bit := 63
 		ELSE  bit := 95
 		END;
@@ -610,7 +572,7 @@ VAR
 			shift( r );	(* r := r*2 *)
 			IF bit MOD 32 IN S.VAL( SET32, a[bit DIV 32] ) THEN  INC( r[0] )  END;
 			IF overflow OR ge( r, b ) THEN
-				borrow := LessOrEqual( r[0], b[0] );  r[0] := r[0] - b[0];  r[1] := r[1] - b[1];
+				borrow := r[0] <= b[0];  r[0] := r[0] - b[0];  r[1] := r[1] - b[1];
 				IF borrow  THEN  DEC( r[1] )  END;
 				IF bit < 32 THEN  INCL( S.VAL( SET32, q ), bit )  ELSE  q := -1  END;
 			END;
@@ -619,8 +581,8 @@ VAR
 		RETURN q
 	END div96;
 
-	PROCEDURE Div2*( a, b: BigNumber;  VAR q, r: BigNumber );   (** q := a div b;  r := a mod b *)
-	VAR x: LONGINT;  td, sd, bd, qd: digits;  i, tail, bl, tl, sl, ql, qi: LONGINT;
+	PROCEDURE Div2*( a, b: BigNumber;  VAR q, r: BigNumber );   (** q = a div b;  r = a mod b *)
+	VAR td, sd, bd, qd: digits;  x, i, tail, bl, tl, sl, ql, qi: LONGINT;
 		t3: dig3;  t2, d0: dig2;
 		aq, ar: ADDRESS;
 	BEGIN
@@ -673,8 +635,8 @@ VAR
 		IF (r.len # 0) & a.neg THEN  q.Dec;  r := Sub( b, r )  END;
 	END Div2;
 
-	PROCEDURE ModWord*( VAR a: BigNumber;  b: LONGINT ): LONGINT;   (**  a mod b *)
-	VAR x: LONGINT;  td, sd, bd: digits;  tail, tl, sl, bl: LONGINT;  t2: dig2;
+	PROCEDURE ModWord*( VAR a: BigNumber;  b: BNdigit ): BNdigit;   (**  a mod b *)
+	VAR x: BNdigit;  td, sd, bd: digits;  tail, tl, sl, bl: LONGINT;  t2: dig2;
 	BEGIN
 		ASSERT( a # NIL );
 		td := GetBuffer();
@@ -859,7 +821,7 @@ VAR
 	VAR i: LONGINT;
 	BEGIN
 		IF b.neg THEN Out.String( "-" ) END;
-		IF b.len = 0 THEN  Out.String( " 00000000" )
+		IF b.len = 0 THEN  Out.String( "00000000" )
 		ELSE  i := b.len;
 			WHILE i > 0 DO
 				DEC( i );  Out.Hex( b.d[i], -8 );
@@ -899,20 +861,20 @@ VAR
 	(*--------------------------- File I/O ---------------------------------*)
 
 	PROCEDURE FileRead*( r: Streams.Reader;  VAR b: BigNumber );
-	VAR i, j: LONGINT;
+	VAR i, j, v: LONGINT;
 	BEGIN
 		r.RawLInt( j );
 		NEW( b, 32 * j );
 		b.len := j;
-		FOR i := 0 TO j - 1 DO  r.RawLInt( b.d[ i ] )  END
+		FOR i := 0 TO j - 1 DO  r.RawLInt( v ); b.d[ i ] := v  END
 	END FileRead;
 
 	PROCEDURE FileWrite*( w: Streams.Writer;  b: BigNumber );
-	VAR i, j: LONGINT;
+	VAR i, j, v: LONGINT;
 	BEGIN
 		j := b.len;
 		w.RawLInt( j );
-		FOR i := 0 TO j - 1 DO  w.RawLInt( b.d[ i ] )  END
+		FOR i := 0 TO j - 1 DO  w.RawLInt( v ); b.d[ i ] := v  END
 	END FileWrite;