2015-09-10 13:21:47

by Corentin Labbe

[permalink] [raw]
Subject: crypto: Remove duplicate code of SG helpers functions


Hello

This patch series try to remove some duplicate code of some SG helpers functions.
The first three patch replace custom functions by already in-tree helper functions.

The fourth add a new functions "sg_nents_for_len2" who is the same as
sg_nents_for_len with an additionnal arguments.
Note that I do not like the name, but I do not find any good name.

The last three patch use sg_nents_for_len2 for removing custom functions.

I send those patch as RFC since I do not own any of those hardware to test.

Regards


2015-09-10 13:21:38

by Corentin Labbe

[permalink] [raw]
Subject: [PATCH 3/7] crypto: sahara replace sahara_sg_length with sg_nents_for_len

Signed-off-by: LABBE Corentin <[email protected]>
---
drivers/crypto/sahara.c | 30 +++---------------------------
1 file changed, 3 insertions(+), 27 deletions(-)

diff --git a/drivers/crypto/sahara.c b/drivers/crypto/sahara.c
index 820dc3a..cea2411 100644
--- a/drivers/crypto/sahara.c
+++ b/drivers/crypto/sahara.c
@@ -274,30 +274,6 @@ static u32 sahara_aes_data_link_hdr(struct sahara_dev *dev)
SAHARA_HDR_CHA_SKHA | SAHARA_HDR_PARITY_BIT;
}

-static int sahara_sg_length(struct scatterlist *sg,
- unsigned int total)
-{
- int sg_nb;
- unsigned int len;
- struct scatterlist *sg_list;
-
- sg_nb = 0;
- sg_list = sg;
-
- while (total) {
- len = min(sg_list->length, total);
-
- sg_nb++;
- total -= len;
-
- sg_list = sg_next(sg_list);
- if (!sg_list)
- total = 0;
- }
-
- return sg_nb;
-}
-
static char *sahara_err_src[16] = {
"No error",
"Header error",
@@ -502,8 +478,8 @@ static int sahara_hw_descriptor_create(struct sahara_dev *dev)
idx++;
}

- dev->nb_in_sg = sahara_sg_length(dev->in_sg, dev->total);
- dev->nb_out_sg = sahara_sg_length(dev->out_sg, dev->total);
+ dev->nb_in_sg = sg_nents_for_len(dev->in_sg, dev->total);
+ dev->nb_out_sg = sg_nents_for_len(dev->out_sg, dev->total);
if ((dev->nb_in_sg + dev->nb_out_sg) > SAHARA_MAX_HW_LINK) {
dev_err(dev->device, "not enough hw links (%d)\n",
dev->nb_in_sg + dev->nb_out_sg);
@@ -818,7 +794,7 @@ static int sahara_sha_hw_links_create(struct sahara_dev *dev,

dev->in_sg = rctx->in_sg;

- dev->nb_in_sg = sahara_sg_length(dev->in_sg, rctx->total);
+ dev->nb_in_sg = sg_nents_for_len(dev->in_sg, rctx->total);
if ((dev->nb_in_sg) > SAHARA_MAX_HW_LINK) {
dev_err(dev->device, "not enough hw links (%d)\n",
dev->nb_in_sg + dev->nb_out_sg);
--
2.4.6

2015-09-10 13:21:51

by Corentin Labbe

[permalink] [raw]
Subject: [PATCH 5/7] crypto: talitos replace sg_count with sg_nents_for_len2

Signed-off-by: LABBE Corentin <[email protected]>
---
drivers/crypto/talitos.c | 34 ++++++++--------------------------
1 file changed, 8 insertions(+), 26 deletions(-)

diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
index 3b20a1b..aca6a6a 100644
--- a/drivers/crypto/talitos.c
+++ b/drivers/crypto/talitos.c
@@ -1234,26 +1234,6 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq,
}

/*
- * derive number of elements in scatterlist
- */
-static int sg_count(struct scatterlist *sg_list, int nbytes, bool *chained)
-{
- struct scatterlist *sg = sg_list;
- int sg_nents = 0;
-
- *chained = false;
- while (nbytes > 0 && sg) {
- sg_nents++;
- nbytes -= sg->length;
- if (!sg_is_last(sg) && (sg + 1)->length == 0)
- *chained = true;
- sg = sg_next(sg);
- }
-
- return sg_nents;
-}
-
-/*
* allocate and map the extended descriptor
*/
static struct talitos_edesc *talitos_edesc_alloc(struct device *dev,
@@ -1287,16 +1267,17 @@ static struct talitos_edesc *talitos_edesc_alloc(struct device *dev,
iv_dma = dma_map_single(dev, iv, ivsize, DMA_TO_DEVICE);

if (!dst || dst == src) {
- src_nents = sg_count(src, assoclen + cryptlen + authsize,
- &src_chained);
+ src_nents = sg_nents_for_len2(src,
+ assoclen + cryptlen + authsize,
+ &src_chained);
src_nents = (src_nents == 1) ? 0 : src_nents;
dst_nents = dst ? src_nents : 0;
} else { /* dst && dst != src*/
- src_nents = sg_count(src, assoclen + cryptlen +
+ src_nents = sg_nents_for_len2(src, assoclen + cryptlen +
(encrypt ? 0 : authsize),
&src_chained);
src_nents = (src_nents == 1) ? 0 : src_nents;
- dst_nents = sg_count(dst, assoclen + cryptlen +
+ dst_nents = sg_nents_for_len2(dst, assoclen + cryptlen +
(encrypt ? authsize : 0),
&dst_chained);
dst_nents = (dst_nents == 1) ? 0 : dst_nents;
@@ -1902,7 +1883,8 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
if (!req_ctx->last && (nbytes + req_ctx->nbuf <= blocksize)) {
/* Buffer up to one whole block */
sg_copy_to_buffer(areq->src,
- sg_count(areq->src, nbytes, &chained),
+ sg_nents_for_len2(areq->src, nbytes,
+ &chained),
req_ctx->buf + req_ctx->nbuf, nbytes);
req_ctx->nbuf += nbytes;
return 0;
@@ -1935,7 +1917,7 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
req_ctx->psrc = areq->src;

if (to_hash_later) {
- int nents = sg_count(areq->src, nbytes, &chained);
+ int nents = sg_nents_for_len2(areq->src, nbytes, &chained);
sg_pcopy_to_buffer(areq->src, nents,
req_ctx->bufnext,
to_hash_later,
--
2.4.6

2015-09-10 13:21:39

by Corentin Labbe

[permalink] [raw]
Subject: [PATCH 4/7] lib: introduce sg_nents_for_len2

Some driver use a modified version of sg_nents_for_len with an
additional parameter bool *chained for knowing if the scatterlist is
chained or not.

So, for removing duplicate code, add sg_nents_for_len2 in
lib/scatterlist.c

Signed-off-by: LABBE Corentin <[email protected]>
---
include/linux/scatterlist.h | 1 +
lib/scatterlist.c | 39 +++++++++++++++++++++++++++++++++++++++
2 files changed, 40 insertions(+)

diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h
index 556ec1e..316c5c4 100644
--- a/include/linux/scatterlist.h
+++ b/include/linux/scatterlist.h
@@ -243,6 +243,7 @@ static inline void *sg_virt(struct scatterlist *sg)

int sg_nents(struct scatterlist *sg);
int sg_nents_for_len(struct scatterlist *sg, u64 len);
+int sg_nents_for_len2(struct scatterlist *sg, u64 len, bool *chained);
struct scatterlist *sg_next(struct scatterlist *);
struct scatterlist *sg_last(struct scatterlist *s, unsigned int);
void sg_init_table(struct scatterlist *, unsigned int);
diff --git a/lib/scatterlist.c b/lib/scatterlist.c
index bafa993..0d1f746 100644
--- a/lib/scatterlist.c
+++ b/lib/scatterlist.c
@@ -90,6 +90,45 @@ int sg_nents_for_len(struct scatterlist *sg, u64 len)
EXPORT_SYMBOL(sg_nents_for_len);

/**
+ * sg_nents_for_len - return total count of entries in scatterlist
+ * needed to satisfy the supplied length
+ * @sg: The scatterlist
+ * @len: The total required length
+ * @chained A pointer where to store if SG is chaind or not
+ *
+ * Description:
+ * Determines the number of entries in sg that are required to meet
+ * the supplied length, taking into acount chaining as well
+ *
+ * Returns:
+ * the number of sg entries needed, negative error on failure
+ *
+ **/
+int sg_nents_for_len2(struct scatterlist *sg, u64 len, bool *chained)
+{
+ int nents;
+ u64 total;
+
+ if (chained)
+ *chained = false;
+
+ if (!len)
+ return 0;
+
+ for (nents = 0, total = 0; sg; sg = sg_next(sg)) {
+ nents++;
+ total += sg->length;
+ if (!sg_is_last(sg) && (sg + 1)->length == 0 && chained)
+ *chained = true;
+ if (total >= len)
+ return nents;
+ }
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL(sg_nents_for_len2);
+
+/**
* sg_last - return the last scatterlist entry in a list
* @sgl: First entry in the scatterlist
* @nents: Number of entries in the scatterlist
--
2.4.6

2015-09-10 13:21:42

by Corentin Labbe

[permalink] [raw]
Subject: [PATCH 7/7] crypto: caam replace __sg_count with sg_nents_for_len2

Signed-off-by: LABBE Corentin <[email protected]>
---
drivers/crypto/caam/caamhash.c | 14 ++++++++------
drivers/crypto/caam/sg_sw_sec4.h | 20 +-------------------
2 files changed, 9 insertions(+), 25 deletions(-)

diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c
index 94433b9..b429595 100644
--- a/drivers/crypto/caam/caamhash.c
+++ b/drivers/crypto/caam/caamhash.c
@@ -797,8 +797,9 @@ static int ahash_update_ctx(struct ahash_request *req)
to_hash = in_len - *next_buflen;

if (to_hash) {
- src_nents = __sg_count(req->src, req->nbytes - (*next_buflen),
- &chained);
+ src_nents = sg_nents_for_len2(req->src,
+ req->nbytes - (*next_buflen),
+ &chained);
sec4_sg_src_index = 1 + (*buflen ? 1 : 0);
sec4_sg_bytes = (sec4_sg_src_index + src_nents) *
sizeof(struct sec4_sg_entry);
@@ -1000,7 +1001,7 @@ static int ahash_finup_ctx(struct ahash_request *req)
int ret = 0;
int sh_len;

- src_nents = __sg_count(req->src, req->nbytes, &chained);
+ src_nents = sg_nents_for_len2(req->src, req->nbytes, &chained);
sec4_sg_src_index = 1 + (buflen ? 1 : 0);
sec4_sg_bytes = (sec4_sg_src_index + src_nents) *
sizeof(struct sec4_sg_entry);
@@ -1236,8 +1237,9 @@ static int ahash_update_no_ctx(struct ahash_request *req)
to_hash = in_len - *next_buflen;

if (to_hash) {
- src_nents = __sg_count(req->src, req->nbytes - (*next_buflen),
- &chained);
+ src_nents = sg_nents_for_len2(req->src,
+ req->nbytes - (*next_buflen),
+ &chained);
sec4_sg_bytes = (1 + src_nents) *
sizeof(struct sec4_sg_entry);

@@ -1347,7 +1349,7 @@ static int ahash_finup_no_ctx(struct ahash_request *req)
int sh_len;
int ret = 0;

- src_nents = __sg_count(req->src, req->nbytes, &chained);
+ src_nents = sg_nents_for_len2(req->src, req->nbytes, &chained);
sec4_sg_src_index = 2;
sec4_sg_bytes = (sec4_sg_src_index + src_nents) *
sizeof(struct sec4_sg_entry);
diff --git a/drivers/crypto/caam/sg_sw_sec4.h b/drivers/crypto/caam/sg_sw_sec4.h
index 18cd6d1..a486efc 100644
--- a/drivers/crypto/caam/sg_sw_sec4.h
+++ b/drivers/crypto/caam/sg_sw_sec4.h
@@ -69,29 +69,11 @@ static inline struct sec4_sg_entry *sg_to_sec4_sg_len(
return sec4_sg_ptr - 1;
}

-/* count number of elements in scatterlist */
-static inline int __sg_count(struct scatterlist *sg_list, int nbytes,
- bool *chained)
-{
- struct scatterlist *sg = sg_list;
- int sg_nents = 0;
-
- while (nbytes > 0) {
- sg_nents++;
- nbytes -= sg->length;
- if (!sg_is_last(sg) && (sg + 1)->length == 0)
- *chained = true;
- sg = sg_next(sg);
- }
-
- return sg_nents;
-}
-
/* derive number of elements in scatterlist, but return 0 for 1 */
static inline int sg_count(struct scatterlist *sg_list, int nbytes,
bool *chained)
{
- int sg_nents = __sg_count(sg_list, nbytes, chained);
+ int sg_nents = sg_nents_for_len2(sg_list, nbytes, chained);

if (likely(sg_nents == 1))
return 0;
--
2.4.6

2015-09-10 13:21:41

by Corentin Labbe

[permalink] [raw]
Subject: [PATCH 6/7] crypto: qce replace qce_countsg with sg_nents_for_len2

Signed-off-by: LABBE Corentin <[email protected]>
---
drivers/crypto/qce/ablkcipher.c | 4 ++--
drivers/crypto/qce/dma.c | 19 -------------------
drivers/crypto/qce/dma.h | 1 -
drivers/crypto/qce/sha.c | 2 +-
4 files changed, 3 insertions(+), 23 deletions(-)

diff --git a/drivers/crypto/qce/ablkcipher.c b/drivers/crypto/qce/ablkcipher.c
index ad592de..0c589e7 100644
--- a/drivers/crypto/qce/ablkcipher.c
+++ b/drivers/crypto/qce/ablkcipher.c
@@ -80,10 +80,10 @@ qce_ablkcipher_async_req_handle(struct crypto_async_request *async_req)
dir_src = diff_dst ? DMA_TO_DEVICE : DMA_BIDIRECTIONAL;
dir_dst = diff_dst ? DMA_FROM_DEVICE : DMA_BIDIRECTIONAL;

- rctx->src_nents = qce_countsg(req->src, req->nbytes,
+ rctx->src_nents = sg_nents_for_len2(req->src, req->nbytes,
&rctx->src_chained);
if (diff_dst) {
- rctx->dst_nents = qce_countsg(req->dst, req->nbytes,
+ rctx->dst_nents = sg_nents_for_len2(req->dst, req->nbytes,
&rctx->dst_chained);
} else {
rctx->dst_nents = rctx->src_nents;
diff --git a/drivers/crypto/qce/dma.c b/drivers/crypto/qce/dma.c
index 378cb76..c18aaca 100644
--- a/drivers/crypto/qce/dma.c
+++ b/drivers/crypto/qce/dma.c
@@ -87,25 +87,6 @@ void qce_unmapsg(struct device *dev, struct scatterlist *sg, int nents,
dma_unmap_sg(dev, sg, nents, dir);
}

-int qce_countsg(struct scatterlist *sglist, int nbytes, bool *chained)
-{
- struct scatterlist *sg = sglist;
- int nents = 0;
-
- if (chained)
- *chained = false;
-
- while (nbytes > 0 && sg) {
- nents++;
- nbytes -= sg->length;
- if (!sg_is_last(sg) && (sg + 1)->length == 0 && chained)
- *chained = true;
- sg = sg_next(sg);
- }
-
- return nents;
-}
-
struct scatterlist *
qce_sgtable_add(struct sg_table *sgt, struct scatterlist *new_sgl)
{
diff --git a/drivers/crypto/qce/dma.h b/drivers/crypto/qce/dma.h
index 65bedb8..4653e2d8 100644
--- a/drivers/crypto/qce/dma.h
+++ b/drivers/crypto/qce/dma.h
@@ -49,7 +49,6 @@ int qce_dma_prep_sgs(struct qce_dma_data *dma, struct scatterlist *sg_in,
dma_async_tx_callback cb, void *cb_param);
void qce_dma_issue_pending(struct qce_dma_data *dma);
int qce_dma_terminate_all(struct qce_dma_data *dma);
-int qce_countsg(struct scatterlist *sg_list, int nbytes, bool *chained);
void qce_unmapsg(struct device *dev, struct scatterlist *sg, int nents,
enum dma_data_direction dir, bool chained);
int qce_mapsg(struct device *dev, struct scatterlist *sg, int nents,
diff --git a/drivers/crypto/qce/sha.c b/drivers/crypto/qce/sha.c
index be2f504..86fae62 100644
--- a/drivers/crypto/qce/sha.c
+++ b/drivers/crypto/qce/sha.c
@@ -92,7 +92,7 @@ static int qce_ahash_async_req_handle(struct crypto_async_request *async_req)
rctx->authklen = AES_KEYSIZE_128;
}

- rctx->src_nents = qce_countsg(req->src, req->nbytes,
+ rctx->src_nents = sg_nents_for_len2(req->src, req->nbytes,
&rctx->src_chained);
ret = qce_mapsg(qce->dev, req->src, rctx->src_nents, DMA_TO_DEVICE,
rctx->src_chained);
--
2.4.6

2015-09-10 13:21:36

by Corentin Labbe

[permalink] [raw]
Subject: [PATCH 1/7] crypto: bfin: replace sg_count by sg_nents

The sg_count function in bfin_crc.c is the same function as sg_nents.
Remove the duplicate code and use sg_nents() instead.

Signed-off-by: LABBE Corentin <[email protected]>
---
drivers/crypto/bfin_crc.c | 25 +++----------------------
1 file changed, 3 insertions(+), 22 deletions(-)

diff --git a/drivers/crypto/bfin_crc.c b/drivers/crypto/bfin_crc.c
index 2f0b333..95b7396 100644
--- a/drivers/crypto/bfin_crc.c
+++ b/drivers/crypto/bfin_crc.c
@@ -96,26 +96,6 @@ struct bfin_crypto_crc_ctx {
u32 key;
};

-
-/*
- * derive number of elements in scatterlist
- */
-static int sg_count(struct scatterlist *sg_list)
-{
- struct scatterlist *sg = sg_list;
- int sg_nents = 1;
-
- if (sg_list == NULL)
- return 0;
-
- while (!sg_is_last(sg)) {
- sg_nents++;
- sg = sg_next(sg);
- }
-
- return sg_nents;
-}
-
/*
* get element in scatter list by given index
*/
@@ -160,7 +140,7 @@ static int bfin_crypto_crc_init(struct ahash_request *req)
}
spin_unlock_bh(&crc_list.lock);

- if (sg_count(req->src) > CRC_MAX_DMA_DESC) {
+ if (sg_nents(req->src) > CRC_MAX_DMA_DESC) {
dev_dbg(ctx->crc->dev, "init: requested sg list is too big > %d\n",
CRC_MAX_DMA_DESC);
return -EINVAL;
@@ -376,7 +356,8 @@ static int bfin_crypto_crc_handle_queue(struct bfin_crypto_crc *crc,
ctx->sg = req->src;

/* Chop crc buffer size to multiple of 32 bit */
- nsg = ctx->sg_nents = sg_count(ctx->sg);
+ nsg = sg_nents(ctx->sg);
+ ctx->sg_nents = nsg;
ctx->sg_buflen = ctx->buflast_len + req->nbytes;
ctx->bufnext_len = ctx->sg_buflen % 4;
ctx->sg_buflen &= ~0x3;
--
2.4.6

2015-09-10 13:21:37

by Corentin Labbe

[permalink] [raw]
Subject: [PATCH 2/7] crypto: amcc replace get_sg_count by sg_nents_for_len

The get_sg_count function of amcc is the same as sg_nents_for_len from
lib/scatterlist.c

Signed-off-by: LABBE Corentin <[email protected]>
---
drivers/crypto/amcc/crypto4xx_core.c | 22 +---------------------
1 file changed, 1 insertion(+), 21 deletions(-)

diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c
index 192a8fa..27288fc 100644
--- a/drivers/crypto/amcc/crypto4xx_core.c
+++ b/drivers/crypto/amcc/crypto4xx_core.c
@@ -740,26 +740,6 @@ void crypto4xx_return_pd(struct crypto4xx_device *dev,
pd_uinfo->state = PD_ENTRY_FREE;
}

-/*
- * derive number of elements in scatterlist
- * Shamlessly copy from talitos.c
- */
-static int get_sg_count(struct scatterlist *sg_list, int nbytes)
-{
- struct scatterlist *sg = sg_list;
- int sg_nents = 0;
-
- while (nbytes) {
- sg_nents++;
- if (sg->length > nbytes)
- break;
- nbytes -= sg->length;
- sg = sg_next(sg);
- }
-
- return sg_nents;
-}
-
static u32 get_next_gd(u32 current)
{
if (current != PPC4XX_LAST_GD)
@@ -800,7 +780,7 @@ u32 crypto4xx_build_pd(struct crypto_async_request *req,
u32 gd_idx = 0;

/* figure how many gd is needed */
- num_gd = get_sg_count(src, datalen);
+ num_gd = sg_nents_for_len(src, datalen);
if (num_gd == 1)
num_gd = 0;

--
2.4.6

2015-09-18 11:53:05

by Herbert Xu

[permalink] [raw]
Subject: Re: [PATCH 4/7] lib: introduce sg_nents_for_len2

On Thu, Sep 10, 2015 at 03:21:39PM +0200, LABBE Corentin wrote:
> Some driver use a modified version of sg_nents_for_len with an
> additional parameter bool *chained for knowing if the scatterlist is
> chained or not.
>
> So, for removing duplicate code, add sg_nents_for_len2 in
> lib/scatterlist.c

This name is rather awkward. Perhaps sg_nents_len_chained?

Thanks,
--
Email: Herbert Xu <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

2015-09-18 12:20:52

by Corentin Labbe

[permalink] [raw]
Subject: Re: [PATCH 4/7] lib: introduce sg_nents_for_len2

On Fri, Sep 18, 2015 at 07:53:00PM +0800, Herbert Xu wrote:
> On Thu, Sep 10, 2015 at 03:21:39PM +0200, LABBE Corentin wrote:
> > Some driver use a modified version of sg_nents_for_len with an
> > additional parameter bool *chained for knowing if the scatterlist is
> > chained or not.
> >
> > So, for removing duplicate code, add sg_nents_for_len2 in
> > lib/scatterlist.c
>
> This name is rather awkward. Perhaps sg_nents_len_chained?

Perfect, thanks

I will send the modified patch series with this function name soon.

Regards

2015-09-18 12:22:17

by Herbert Xu

[permalink] [raw]
Subject: Re: [PATCH 4/7] lib: introduce sg_nents_for_len2

On Fri, Sep 18, 2015 at 02:20:48PM +0200, LABBE Corentin wrote:
>
> I will send the modified patch series with this function name soon.

You only need to resend patches 4-7.

Thanks,
--
Email: Herbert Xu <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

2015-09-18 12:42:34

by Corentin Labbe

[permalink] [raw]
Subject: Re: [PATCH 4/7] lib: introduce sg_nents_for_len2

On Fri, Sep 18, 2015 at 08:22:13PM +0800, Herbert Xu wrote:
> On Fri, Sep 18, 2015 at 02:20:48PM +0200, LABBE Corentin wrote:
> >
> > I will send the modified patch series with this function name soon.
>
> You only need to resend patches 4-7.
>

Since I have used badly get_maintainer.pl, I need to resend all patchs with all proper recipient.
And I have respelled some patch. (like for sahara which have an empty commit log).

Regards

2015-09-18 12:43:38

by Herbert Xu

[permalink] [raw]
Subject: Re: [PATCH 4/7] lib: introduce sg_nents_for_len2

On Fri, Sep 18, 2015 at 02:42:34PM +0200, LABBE Corentin wrote:
> Since I have used badly get_maintainer.pl, I need to resend all patchs with all proper recipient.
> And I have respelled some patch. (like for sahara which have an empty commit log).

OK.

Cheers,
--
Email: Herbert Xu <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt