[hashcash] Re: libfastmint, makefile & how to integrate

  • From: Jonathan Morton <chromi@xxxxxxxxxxxxxxxxxxxxx>
  • To: hashcash@xxxxxxxxxxxxx
  • Date: Tue, 3 Aug 2004 10:47:22 +0100

output (on p4 3.06Ghz).

    Rate  Name (* machine default)

1715641 ANSI Compact 1-pipe
1639391 ANSI Standard 1-pipe
958085 ANSI Ultra-Compact 1-pipe
2379761 ANSI Compact 2-pipe
2078101 ANSI Standard 2-pipe
--- PowerPC Altivec Standard 1x4-pipe (Not available on this machine)
--- PowerPC Altivec Compact 2x4-pipe (Not available on this machine)
--- PowerPC Altivec Standard 2x4-pipe (Not available on this machine)
3278782 AMD64/x86 MMX Compact 1x2-pipe
4098477 AMD64/x86 MMX Standard 1x2-pipe *

Yes, that looks reasonable for the latest version. My most recent updates have been with date codes in the e-mail subject line, so they're easy to identify.


btw What would I have to do to call libfastmint when integrating.  I
took a look just now and the test seems hardcoded to :

static const char *test_string = "1:20:040404:foo@xxxxxxxx::0123456789a\bcdef:000000000";
static const int test_tail = 52; /* must be less than 56 */
static const int bit_stats[] = { 8, 10, 16, 20, 22, 24, 26, 28, 30, 0 };


which is then used to fill a char block[SHA1_INPUT_BYTES] = {0}; and
then the mint functions are called on that block:

                /* set up SHA-1 block */
                strncpy(block, test_string, SHA1_INPUT_BYTES);
                block[test_tail] = 0x80;
                memset(block+test_tail+1, 0, 59-test_tail);
                PUT_WORD(block+60, test_tail << 3);

which looks like the SHA1 padding setup.  What would the code look
like to call this with arbitrary email addresses and extensions?

Your analysis of the benchmark code is correct - it's a hard-coded run, specifically in order to get repeatable results. It is not intended as an example of how to call the code from a real application.


However, there's a third function at the bottom of libfastmint.c, which is intended for actually minting stamps. At present it doesn't take advantage of the optimised counting positions (I plan to correct this oversight), but it is much easier to call than you seem to expect. Here's the prototype:

unsigned int hashcash_fastmint(const int bits, const char *token, char **result);

To call it, a naive example (using the benchmark as an example source) would be:

        char *result = NULL;
        hashcash_fastmint(20, "1:20:040404:foo@xxxxxxxx::", &result);

As you can see, the whole string up to (but not including) the random field must be set up by the caller - this allows arbitrary extensions to be inserted and formatting options to be used as desired. Because this is only done once, it's not performance critical in the least, so write for maintainability. The fastmint code adds a suitable random field (using the best random source available, eg. /dev/urandom) and calculates the counter for you.

The passed string is not modified (or even parsed) - instead a new buffer is allocated and the result returned in that. Don't forget to free() it when done, if avoiding memory leakage is important.

The function returns the number of bits it was actually able to mint. In the event of an error (generally a bad minter core), this will be less than the number requested. On success, it will be equal or greater. This bit count is found from the libsha1 code that is used for verification, not from the minter core.

Note that it is not strictly required to initialise anything before calling either the benchmark or the minter, as both will do basic initialisation by themselves if necessary. The benchmark may be called (with verbosity 0 for silence) once before any number of minting sessions is conducted, if a more accurate core selection is required. (The benchmark may be re-run whenever desired, but the utility of this is questionable. I have found it usually gives very repeatable results.)

The minter is thread-safe and re-entrant *provided* it is already initialised, so feel free to use it in a multithreaded application. Obviously, you don't want to run the initialiser or the benchmark in parallel with anything. (NB: there is presently no way to benchmark the effect of Hyperthreading. Especially since I don't have any hardware that has this "feature". Conventional SMP benchmarks are easy - just multiply the single-threaded performance by the number of CPUs. If SMT benchmarking becomes important in future - I'm thinking mostly of Sun's Niagara here - I'll provide a modified benchmark routine that can multithread as required.)

Ideally, the minted token should be checked against a double-spend database. Collisions should be extremely rare, but avoiding them is reasonably cheap and fairly desirable.

Oh, and I actually need to test the fastmint function. To quote a famous computer scientist: "Beware of bugs in the above code. I have only proved it correct, not tested it." So, if you have problems, rest assured that I'll be running into the same problems really soon and that they will be fixed. The cores are fairly well tested via the benchmark - it's the front-end that might need adjusting.

--------------------------------------------------------------
from:     Jonathan "Chromatix" Morton
mail:     chromi@xxxxxxxxxxxxxxxxxxxxx
website:  http://www.chromatix.uklinux.net/
tagline:  The key to knowledge is not to rely on people to teach you it.


Other related posts:

  • » [hashcash] Re: libfastmint, makefile & how to integrate