[PATCH 7/8] g10/armor: optimize binary to radix64 conversion

Jussi Kivilinna jussi.kivilinna at iki.fi
Sat Oct 27 23:06:15 CEST 2018


* g10/armor.c (bintoasc): Change to read-only.
(initialize): Use const pointer for 'bintoasc'.
(armor_output_buf_as_radix64): New function for faster binary to
radix64 conversion.
(armor_filter): Use new conversion function.
--

This patch adds faster binary to radix64 conversion to speed up
armored encryption.

Benchmark results below, tested on Intel Core i7-4790K (turbo off).
Encrypted 2 GiB through pipe to ramfs file using AES128. Decrypt
ramfs file out through pipe to /dev/null.

before patch-set
----------------
               gpg process
armor:         user time    pipe transfer rate
 encrypt-aead:  13.8         140 MB/s
 decrypt-aead:  30.6         68 MB/s
 encrypt-cfb:   17.4         114 MB/s
 decrypt-cfb:   32.6         64 MB/s

after (decrypt+iobuf+crc+radix64 opt)
-------------------------------------
               gpg process
armor:         user time    pipe transfer rate
 encrypt-aead:  2.7          523 MB/s
 encrypt-cfb:   6.7          264 MB/s

Signed-off-by: Jussi Kivilinna <jussi.kivilinna at iki.fi>
---
 0 files changed

diff --git a/g10/armor.c b/g10/armor.c
index 9da135a2b..95293d91c 100644
--- a/g10/armor.c
+++ b/g10/armor.c
@@ -37,9 +37,9 @@
 
 #define MAX_LINELEN 20000
 
-static byte bintoasc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-			 "abcdefghijklmnopqrstuvwxyz"
-			 "0123456789+/";
+static const byte bintoasc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                               "abcdefghijklmnopqrstuvwxyz"
+                               "0123456789+/";
 static byte asctobin[256]; /* runtime initialized */
 static int is_initialized;
 
@@ -169,7 +169,8 @@ static void
 initialize(void)
 {
     u32 i;
-    byte *s;
+    const byte *s;
+
     /* build the helptable for radix64 to bin conversion */
     for(i=0; i < 256; i++ )
 	asctobin[i] = 255; /* used to detect invalid characters */
@@ -1003,6 +1004,121 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn,
     return rc;
 }
 
+static void
+armor_output_buf_as_radix64 (armor_filter_context_t *afx, IOBUF a,
+			     byte *buf, size_t size)
+{
+  byte radbuf[sizeof (afx->radbuf)];
+  byte outbuf[64 + sizeof (afx->eol)];
+  unsigned int eollen = strlen (afx->eol);
+  u32 in, in2;
+  int idx, idx2;
+  int i;
+
+  idx = afx->idx;
+  idx2 = afx->idx2;
+  memcpy (radbuf, afx->radbuf, sizeof (afx->radbuf));
+
+  if (size && (idx || idx2))
+    {
+      /* preload eol to outbuf buffer */
+      memcpy (outbuf + 4, afx->eol, sizeof (afx->eol));
+
+      for (; size && (idx || idx2); buf++, size--)
+	{
+	  radbuf[idx++] = *buf;
+	  if (idx > 2)
+	    {
+	      idx = 0;
+	      in = (u32)radbuf[0] << (2 * 8);
+	      in |= (u32)radbuf[1] << (1 * 8);
+	      in |= (u32)radbuf[2] << (0 * 8);
+	      outbuf[0] = bintoasc[(in >> 18) & 077];
+	      outbuf[1] = bintoasc[(in >> 12) & 077];
+	      outbuf[2] = bintoasc[(in >> 6) & 077];
+	      outbuf[3] = bintoasc[(in >> 0) & 077];
+	      if (++idx2 >= (64/4))
+		{ /* pgp doesn't like 72 here */
+		  idx2=0;
+		  iobuf_write (a, outbuf, 4 + eollen);
+		}
+	      else
+		{
+		  iobuf_write (a, outbuf, 4);
+		}
+	    }
+	}
+    }
+
+  if (size >= (64/4)*3)
+    {
+      /* preload eol to outbuf buffer */
+      memcpy (outbuf + 64, afx->eol, sizeof(afx->eol));
+
+      do
+	{
+	  /* idx and idx2 == 0 */
+
+	  for (i = 0; i < (64/8); i++)
+	    {
+	      in = (u32)buf[0] << (2 * 8);
+	      in |= (u32)buf[1] << (1 * 8);
+	      in |= (u32)buf[2] << (0 * 8);
+	      in2 = (u32)buf[3] << (2 * 8);
+	      in2 |= (u32)buf[4] << (1 * 8);
+	      in2 |= (u32)buf[5] << (0 * 8);
+	      outbuf[i*8+0] = bintoasc[(in >> 18) & 077];
+	      outbuf[i*8+1] = bintoasc[(in >> 12) & 077];
+	      outbuf[i*8+2] = bintoasc[(in >> 6) & 077];
+	      outbuf[i*8+3] = bintoasc[(in >> 0) & 077];
+	      outbuf[i*8+4] = bintoasc[(in2 >> 18) & 077];
+	      outbuf[i*8+5] = bintoasc[(in2 >> 12) & 077];
+	      outbuf[i*8+6] = bintoasc[(in2 >> 6) & 077];
+	      outbuf[i*8+7] = bintoasc[(in2 >> 0) & 077];
+	      buf+=6;
+	      size-=6;
+	    }
+
+	  /* pgp doesn't like 72 here */
+	  iobuf_write (a, outbuf, 64 + eollen);
+	}
+      while (size >= (64/4)*3);
+
+      /* restore eol for tail handling */
+      if (size)
+	memcpy (outbuf + 4, afx->eol, sizeof (afx->eol));
+    }
+
+  for (; size; buf++, size--)
+    {
+      radbuf[idx++] = *buf;
+      if (idx > 2)
+	{
+	  idx = 0;
+	  in = (u32)radbuf[0] << (2 * 8);
+	  in |= (u32)radbuf[1] << (1 * 8);
+	  in |= (u32)radbuf[2] << (0 * 8);
+	  outbuf[0] = bintoasc[(in >> 18) & 077];
+	  outbuf[1] = bintoasc[(in >> 12) & 077];
+	  outbuf[2] = bintoasc[(in >> 6) & 077];
+	  outbuf[3] = bintoasc[(in >> 0) & 077];
+	  if (++idx2 >= (64/4))
+	    { /* pgp doesn't like 72 here */
+	      idx2=0;
+	      iobuf_write (a, outbuf, 4 + eollen);
+	    }
+	  else
+	    {
+	      iobuf_write (a, outbuf, 4);
+	    }
+	}
+    }
+
+  memcpy (afx->radbuf, radbuf, sizeof (afx->radbuf));
+  afx->idx = idx;
+  afx->idx2 = idx2;
+}
+
 /****************
  * This filter is used to handle the armor stuff
  */
@@ -1012,7 +1128,7 @@ armor_filter( void *opaque, int control,
 {
     size_t size = *ret_len;
     armor_filter_context_t *afx = opaque;
-    int rc=0, i, c;
+    int rc=0, c;
     byte radbuf[3];
     int  idx, idx2;
     size_t n=0;
@@ -1196,37 +1312,11 @@ armor_filter( void *opaque, int control,
 	    afx->idx2 = 0;
 	    gcry_md_reset (afx->crc_md);
 	}
-	idx = afx->idx;
-	idx2 = afx->idx2;
-	for(i=0; i < idx; i++ )
-	    radbuf[i] = afx->radbuf[i];
-
-	if( size )
-	  gcry_md_write (afx->crc_md, buf, size);
-
-	for( ; size; buf++, size-- ) {
-	    radbuf[idx++] = *buf;
-	    if( idx > 2 ) {
-		idx = 0;
-		c = bintoasc[(*radbuf >> 2) & 077];
-		iobuf_put(a, c);
-		c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077];
-		iobuf_put(a, c);
-		c = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
-		iobuf_put(a, c);
-		c = bintoasc[radbuf[2]&077];
-		iobuf_put(a, c);
-		if( ++idx2 >= (64/4) )
-		  { /* pgp doesn't like 72 here */
-		    iobuf_writestr(a,afx->eol);
-		    idx2=0;
-		  }
-	    }
-	}
-	for(i=0; i < idx; i++ )
-	    afx->radbuf[i] = radbuf[i];
-	afx->idx = idx;
-	afx->idx2 = idx2;
+
+	if( size ) {
+	    gcry_md_write (afx->crc_md, buf, size);
+	    armor_output_buf_as_radix64 (afx, a, buf, size);
+        }
     }
     else if( control == IOBUFCTRL_INIT )
       {




More information about the Gnupg-devel mailing list