[Webfunds-commits] java/webfunds/token/chaum ChaumBlindedToken.java ChaumConstants.java ChaumPair.java ChaumPrivateParams.java ChaumProtoToken.java ChaumPublicParams.java

Ian Grigg iang@cypherpunks.ai
Sun, 1 Apr 2001 22:12:24 -0400 (AST)


iang        01/04/01 22:12:23

  Modified:    webfunds/token BaseToken.java TokenSigner.java
  Added:       webfunds/token ParamsPair.java
               webfunds/token/chaum ChaumBlindedToken.java
                        ChaumConstants.java ChaumPair.java
                        ChaumPrivateParams.java ChaumProtoToken.java
                        ChaumPublicParams.java
  Log:
  compiled Chaum implementation -- but not tested at all, and missing
  the TokenSpender and TokenDead extensions.

Revision  Changes    Path
1.3       +60 -2     java/webfunds/token/BaseToken.java

Index: BaseToken.java
===================================================================
RCS file: /home/webfunds/cvsroot/java/webfunds/token/BaseToken.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- BaseToken.java	2001/04/01 22:37:02	1.2
+++ BaseToken.java	2001/04/02 02:12:21	1.3
@@ -1,5 +1,5 @@
 /*
- * $Id: BaseToken.java,v 1.2 2001/04/01 22:37:02 iang Exp $
+ * $Id: BaseToken.java,v 1.3 2001/04/02 02:12:21 iang Exp $
  *
  * Copyright (c) Systemics Inc 1995-2000 on behalf of
  * the WebFunds Development Team.  All Rights Reserved.
@@ -13,14 +13,16 @@
 import java.io.OutputStream;
 import java.io.DataOutputStream;
 
+import java.math.BigInteger;
+
 import java.security.SecureRandom;
 import java.security.PrivateKey;
 import java.security.KeyException;
 import java.security.NoSuchAlgorithmException;
 import java.security.MessageDigest;
 
-import webfunds.utils.Hex;
-import webfunds.utils.Panic;
+import webfunds.util.Hex;
+import webfunds.util.Panic;
 
 import webfunds.sox.Encodable;
 import webfunds.sox.SOXPacketException;
@@ -303,7 +305,44 @@
     }
 
 
+    /*
+     *  Decode a BigInteger, as encoded below.
+     *
+     *  As most of the token schemes will work with
+     *  BigInts, it's worth including the calls here.
+     *
+     *  @param dis is the stream to read from
+     */
+    public BigInteger readBigInt(DataInputStream dis)
+        throws IOException
+    {
+        byte[] buf = Encodable.readByteArray(dis);
+ 
+        BigInteger big;
+        try {
+            big = new BigInteger(buf);
+        } catch (NumberFormatException ex) {
+            throw new IOException("NFE: " + ex);
+        }
 
+        return big;
+    } 
+        
+    /*
+     *  Encode a BigInteger as a byte array, suitable for
+     *  decoding above.   
+     *
+     *  @param dos is the stream to read from
+     */
+    public void writeBigInt(DataOutputStream dos, BigInteger big)
+        throws IOException
+    {
+        byte[] buf = big.toByteArray();
+        Encodable.writeByteArray(dos, buf);
+    }
+
+
+
 ////// Self-Test //////////////////////////////////
 
     public String toString()
@@ -344,6 +383,25 @@
         if (other.expiry != expiry)
             return false;
 
+        return true;
+    }
+
+    /**
+     *  Compare two BigIntegers, where either could be null.
+     *  @return true if (one == null == two) or (one.equals(two))
+     */
+    public static boolean equalsBigInt(BigInteger one, BigInteger two)
+    {
+        if (one == null)
+        {
+            if (two != null)
+                return false ;
+        }
+        else
+        {
+            if (!one.equals(two))
+                return false;
+        }
         return true;
     }
 



1.2       +2 -1      java/webfunds/token/TokenSigner.java

Index: TokenSigner.java
===================================================================
RCS file: /home/webfunds/cvsroot/java/webfunds/token/TokenSigner.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- TokenSigner.java	2001/04/01 22:25:25	1.1
+++ TokenSigner.java	2001/04/02 02:12:22	1.2
@@ -1,5 +1,5 @@
 /*
- * $Id: TokenSigner.java,v 1.1 2001/04/01 22:25:25 iang Exp $
+ * $Id: TokenSigner.java,v 1.2 2001/04/02 02:12:22 iang Exp $
  *
  * Copyright (c) Systemics Inc 1995-2000 on behalf of
  * the WebFunds Development Team.  All Rights Reserved.
@@ -15,7 +15,8 @@
 
 import java.security.SecureRandom;
 
-import webfunds.utils.Hex;
+import webfunds.util.Hex;
+import webfunds.util.Panic;
 
 import webfunds.token.util.Log;
 



1.1                  java/webfunds/token/ParamsPair.java

Index: ParamsPair.java
===================================================================
/*
 * $Id: ParamsPair.java,v 1.1 2001/04/02 02:12:21 iang Exp $
 *
 * Copyright (c) Systemics Inc 1995-2000 on behalf of
 * the WebFunds Development Team.  All Rights Reserved.
 */
package webfunds.token;

import java.security.SecureRandom;

/**
 *  Represents a pair of AbstractPrivateParams and AbstractPublicParams.
 *  Generation occurs here, and each is extracted separately.
 *
 *  This class is not encoded, rather the Private and Public
 *  parts are separately extracted and stored.
 *  The model is like KeyPair.
 */
public interface ParamsPair
{



    /**
     *  Create an uninitialised Pair.
     *  Call generate() with some params to make the contents.
    public ParamsPair();
     */

    /**
     *  Create an uninitialised Pair.
     *  Call generate() with some params to make the contents.
     *  Reusable.
     *
     *  @param item is the description of which instrument relates
     *  @param series is the short descriptor of which set of tokens this is
     *  @param expiry date on which this series will expire
     *  @param log the coin size, log base 2 of quantity
     */
    public void generate(SecureRandom sr,
                         byte[] item,
                         byte[] series, long expiry,
                         byte log)
    throws TokenKeyException;

    /**
     *  Get the private half of the pair, used for signing the token. 
     */
    public AbstractPrivateParams getPrivate();

    /**
     *  Get the public half of the pair, used for verifying the token. 
     */
    public AbstractPublicParams getPublic();
}



1.1                  java/webfunds/token/chaum/ChaumBlindedToken.java

Index: ChaumBlindedToken.java
===================================================================
/* $Id: ChaumBlindedToken.java,v 1.1 2001/04/02 02:12:22 iang Exp $
 *
 * Copyright (c) 2000-2001 Systemics Inc on behalf of
 * the WebFunds Development Team.  All Rights Reserved.
 */
package webfunds.token.chaum;

import java.io.InputStream;
import java.io.OutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;

import java.math.BigInteger;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

import webfunds.util.Panic;
import webfunds.util.Hex;

import webfunds.sox.Utils;

import webfunds.token.*;
import webfunds.token.DataFormatException;
import webfunds.token.TokenSigner;




/**
 *  This is the blinded-Token using Chaum blinding, as such
 *  it is in the process of being withdrawn, and currently
 *  (probably) in passage through the server.
 *
 *  @version $Revision: 1.1 $
 *  @author Edwin Woudt <edwin@webfunds.org>
 */
public final class ChaumBlindedToken extends TokenSigner {

    public static final int CHAUM_BLIND_V1 = 1;

// Instance variables
//.............................................................................

    private BigInteger blindedProtoToken = null;
    private BigInteger blindedSignedToken = null;

    /**
     *  XXX:  how to calculate this id?
     *
     *  @return a byte array with the unique id,
     *  else empty array if not right state
    public byte[] getUniqueId()
    {
        if (state == TOK_UNSAVED || state == TOK_PROTO)
            return new byte[0];

        return new byte[0];    // if not the right state, no id!
    }
     */

// Constructors
//.............................................................................
    /**
     *  Construct the token object, in RAW state.
     *
     */
    public ChaumBlindedToken()
    {
        super();
    }

    /**
     *  Construct a token object from a byte array
     *  that was previously returned from the encode()
     *  method of a token object.  That might be a ProtoToken.
     *
     *  @param token the previously encoded token
     *  @excep TokenPacketException The token data is badly formatted
     */
    public ChaumBlindedToken(byte[] buf)
        throws TokenPacketException
    {
        super(buf);
    }  

    /**
     *  Construct a token object from data in an input stream,
     *  where the data was previously returned from the encode()
     *  method of a token object.
     *
     *  @param is the input stream from which to read the token data
     *  @excep TokenPacketException The token data is badly formatted
     */
    public ChaumBlindedToken(InputStream is)
        throws TokenPacketException
    {
        super(is);
    }



// Processing methods
//.............................................................................

    /**
     *
     *  @return a byte array with the unique id, else null if not good state
     */
    public byte[] getUniqueId()
    {
        byte[] id = super.getUniqueId();
        if (id != null)
            return id;
        
        setUniqueId(blindedSignedToken.toByteArray());
        return super.getUniqueId();
    }



    public void sign(SecureRandom sr, AbstractPrivateParams privparams) 
    {
        if (!isVerified())
            throw new Panic("what state is " + state);

        if ( ! (privparams instanceof ChaumPrivateParams))
            throw new Panic("what is " + privparams.getClass());

        ChaumPrivateParams params = (ChaumPrivateParams)privparams;

        BigInteger n = params.getN();
        BigInteger d = params.getD();

        blindedSignedToken = blindedProtoToken.modPow(d, n);

        setSigned();
    }
    


// Input/Output methods
//.............................................................................

/*
    protected void decodeImpl(byte[] data, int start, int len)
    throws DataFormatException
    {
        blindedProtoToken = EncodeDecodeUtil.decodeMPI(data, start, len);
    }
*/


    public void decode(InputStream is)
        throws IOException
    {
        DataInputStream dis = new DataInputStream(is);

        super.decode(dis);

        if (type != Factory.CHAUM_TOKEN)
            throw new IOException("not my token: "+
                                type + " != " + Factory.CHAUM_TOKEN);
        if (subversion != CHAUM_BLIND_V1)
            throw new IOException("Invalid sub version in token: "+
                                subversion + " != " + CHAUM_BLIND_V1);

        if (isNew() || isVerified())
        {
            blindedProtoToken = readBigInt(dis);
        }
        else if (isSigned() || isTransacted())
        {
            blindedSignedToken = readBigInt(dis);
        }
        else
            throw new IOException("what state " + state + "?");
    }



    /**
     *  Encode a token as a byte array, suitable for
     *  sending to third parties for depositing, OR
     *  for saving to disk securely for later retry.
     *
     *  Note, it is the caller's responsibility to decide
     *  whether the token is correctly saved and is now
     *  fit for withdrawal (and thus, the caller can set
     *  state to TOK_PROTO).
     */
    public void encode(OutputStream os)
        throws IOException
    {
        DataOutputStream dos = new DataOutputStream(os);
        super.encode(dos);

        if (isNew() || isVerified())
        {
            writeBigInt(dos, blindedProtoToken);
        }
        else if (isSigned() || isTransacted())
        {
            writeBigInt(dos, blindedSignedToken);
        }
        else
            throw new IllegalArgumentException("what state " + state + "?");
    }



////// Self-Test //////////////////////////////////

    public boolean equals(Object object)
    {  
        if ( (object == null) || !(object instanceof ChaumBlindedToken) )
            return false;

        ChaumBlindedToken other = (ChaumBlindedToken)object;

//System.err.println("1: " + version + " " + other.version);
        if (!super.equals(other))
            return false;

        if (isNew() || isVerified())
        {
            if (!equalsBigInt(blindedProtoToken, other.blindedProtoToken))
                return false;
        }
        else if (isSigned() || isTransacted())
        {
            if (!equalsBigInt(blindedSignedToken, other.blindedSignedToken))
                return false;
        }
//System.err.println("4: ");

        return true ;
    }       

    /**
     * Convert this object to a human readable string
     */
    public String toString()
    {
        String s = "Chaum ChaumBlindedToken " + super.toString() + ": ";

        if (isNew() || isVerified())
        {
            s += "\tpT == " + blindedProtoToken + "\n";
        }
        else if (isSigned() || isTransacted())
        {
            s += "\tPt == " + blindedSignedToken + "\n";
        }
        else
            s += "\t what state is " + state + "?\n";

        return s;
    }

/*
    public String vString()
    {
        return "V" + version;
    }
*/

    public static ChaumBlindedToken example(AbstractPublicParams pp)
    {
        ChaumBlindedToken p = new ChaumBlindedToken();
        int state = Utils.exampleByte() % 4;
        p.state = state;

        if (p.isNew() || p.isVerified())
        {
            p.blindedProtoToken = Utils.examplePosBigInt();
        }
        else if (p.isSigned() || p.isTransacted())
        {
            p.blindedSignedToken = Utils.examplePosBigInt();
        }
        
        return p;
    }

    public static ChaumBlindedToken example()
    {
        ChaumPublicParams params = ChaumPublicParams.example();
        return example(params);
    }


    public static ChaumPublicParams getParams(String fname)
    {
        if (fname == null)
            return ChaumPublicParams.example();

        ChaumPublicParams params = null;
        try {
            FileInputStream fis = new FileInputStream(fname);
            params = new ChaumPublicParams(fis);
        } catch(Exception e) {
            e.printStackTrace();
            System.exit(1);
        }

        return params;
    }

    public static void main(String[] args)
    {
	int num = 2000;
	String type = "-c";
	String paramsFile = null;

	if (args.length > 0)
	{
	    int a = 0;
	    while (args[a].startsWith("-"))
	    {
	        String arg = args[a++];
                if (arg.equals("-t") || arg.equals("-i"))
                    type = arg;
                else if (arg.equals("-f"))
                    paramsFile = args[a++];
                
                if (a < args.length)
                    break;
	    }

            if (a < args.length)
	    {
		Integer i = null;
                try {
		    i = new Integer(args[a]);
		} catch (Exception e) {
		    e.printStackTrace();
		    System.exit(1);
		}
                num = i.intValue();
	    }
	}

        ChaumPublicParams params = getParams(paramsFile);

        try {
	    if (type.equals("-t") || type.equals("-i"))
	    {
		while (true)
		{
                    if (type.equals("-t"))
		        readWrite();
                    else if (type.equals("-i"))
		        input();
	        }
	    }
	    else
	    {
                for (int i = 0; i < num; i++)
	        {
                    if (type.equals("-c"))
		        cycle(params);
                    else if (type.equals("-o"))
		        output(params);
	        }
	    }
        } catch(Exception e) {
            e.printStackTrace();
            System.exit(1);
        }
	System.out.flush();          // last buffered lump still there
	System.out.close();
        System.exit(0);
    }

    protected static void cycle(ChaumPublicParams params)
        throws Exception
    {
	ChaumBlindedToken p = example(params);
        System.err.println("Writing: " + p);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        p.encode(baos);
        byte[] buf = baos.toByteArray();

        ChaumBlindedToken q = new ChaumBlindedToken(buf);
        if (!p.equals(q))
        {
            throw new RuntimeException("FAILED:\n\n"+q+"\n\n"+p+"\nEND\n");
        }
    }

    protected static void output(ChaumPublicParams params)
        throws Exception
    {
	ChaumBlindedToken b = example(params);
	b.encode(System.out);
    }

    protected static void readWrite()
        throws Exception
    {
	ChaumBlindedToken b = null;
	b = new ChaumBlindedToken(System.in);
        System.err.println("Read: " + b);
	b.encode(System.out);
    }

    protected static void input()
        throws Exception
    {
	ChaumBlindedToken b = null;
	b = new ChaumBlindedToken(System.in);
        System.err.println("Read: " + b);
    }

}



1.1                  java/webfunds/token/chaum/ChaumConstants.java

Index: ChaumConstants.java
===================================================================
/* $Id: ChaumConstants.java,v 1.1 2001/04/02 02:12:22 iang Exp $
 *
 * Copyright (c) 2000-2001 Systemics Inc on behalf of
 * the WebFunds Development Team.  All Rights Reserved.
 */
package webfunds.token.chaum;

/**
 * Constants for the Chaum blinding algorithm
 *
 * @version $Revision: 1.1 $
 * @author Edwin Woudt <edwin@webfunds.org>
 */
public final class ChaumConstants {

    private ChaumConstants() {} // static constants only
    
    // public static final int    KEY_SIZE    = 1024/8;
    public static final int    KEY_SIZE    = 384/8;   // TESTING!
    public static final int    RANDOM_SIZE =  160/8;
    public static final int    HASH_SIZE   =  160/8;
    public static final String HASH_ALG    = "SHA-1";
    public static final int    PRIME_CERTAINTY = 80;
    
    public static final byte   MAJOR_TOKEN_VERSION = 1;
    public static final byte   MINOR_TOKEN_VERSION = 0;
    public static final byte   MAJOR_PARAMS_VERSION = 1;
    public static final byte   MINOR_PARAMS_VERSION = 0;

}



1.1                  java/webfunds/token/chaum/ChaumPair.java

Index: ChaumPair.java
===================================================================
/*
 * $Id: ChaumPair.java,v 1.1 2001/04/02 02:12:22 iang Exp $
 *
 * Copyright (c) 1995-2000 Systemics Inc on behalf of
 * the WebFunds Development Team.  All Rights Reserved.
 */
package webfunds.token.chaum;
                         
import java.math.BigInteger;

import java.security.SecureRandom;

import webfunds.sox.Crypto;
import webfunds.sox.Utils;

import webfunds.token.AbstractPublicParams;
import webfunds.token.AbstractPrivateParams;
import webfunds.token.ParamsPair;
import webfunds.token.TokenKeyException;
      
/**
 *  Represents a Chaum key for a token,
 *  including private and public components,
 *  and the {item, series, expiry, log} tuple.
 *
 *  Refer to AbstractPublicParams for common methods.
 */
public class ChaumPair
    implements ParamsPair
{

    // private AbstractPrivateParams priv;
    // private AbstractPublicParams pub;

    /**
     *  Create an uninitialised Pair.
     *  Call generate() with some params to make the contents.
    public ChaumPair()
    {
    }
     */

    /**
     *  Create an uninitialised Chaum Pair.
     *
     *  @param item is the description of which instrument relates
     *  @param series is the short descriptor of which set of tokens this is
     *  @param expiry date on which this series will expire
     *  @param log the coin size, log base 2 of quantity
     */
    public void generate(SecureRandom sr,
                         byte[] item,
                         byte[] series, long expiry,
                         byte log)
    // throws TokenKeyException
    {
        this.item   = item;
        this.series = series;
        this.expiry = expiry;
        this.log    = log;

        generateImpl(sr);

    }


    /**
     *  Get the private half of the pair, used for signing the token.
     */
    // public AbstractPrivateParams getPrivate() { return priv; }
    public AbstractPrivateParams  getPrivate()   { return getPrivate(0); }

    /**
     *  Get the public half of the pair, used for verifying the token.
     */
    // public AbstractPublicParams getPublic() { return pub; }
    public AbstractPublicParams getPublic()  { return getPublic(0); }

////// Full Set //////////////////////////////////

    private BigInteger phi;   // temporary
    private BigInteger n, p, q;
    private BigInteger[] e, d;

    private BigInteger getE()                    { return getE(0); }
    private BigInteger getE(int i)               { return e[i]; }
    private BigInteger getD()                    { return getD(0); }
    private BigInteger getD(int i)               { return d[i]; }
    private BigInteger getP()                    { return p; }
    private BigInteger getQ()                    { return q; }

    private byte[] item;
    private byte[] series;
    private long   expiry;
    private byte   log;


    private void generateAlgorithmParamaters(SecureRandom sr) {
  
        // Part of the following code has been copied from the RSA key
        // generation code from the Cryptix JCE.

        BigInteger pMinus1, qMinus1;
        int keysize = ChaumConstants.KEY_SIZE * 8;  
        int pLen = keysize / 2;
        int qLen = keysize - pLen;
  
        do
        {
            p = new BigInteger(pLen, ChaumConstants.PRIME_CERTAINTY, sr);
            q = new BigInteger(qLen, ChaumConstants.PRIME_CERTAINTY, sr);
            n = p.multiply(q);
        }
        while( (p.compareTo(q) == 0) || (n.bitLength() != keysize) );
            
        pMinus1 = p.subtract(BigInteger.valueOf(1));
        qMinus1 = q.subtract(BigInteger.valueOf(1));
        phi     = pMinus1.multiply(qMinus1);
    }

    public void generateImpl(SecureRandom sr, int num) {
  

        // Part of the following code has been copied from the RSA key
        // generation code from the Cryptix JCE.

        generateAlgorithmParamaters(sr);         // n and phi
        d = new BigInteger[num];
        e = new BigInteger[num];

        long currentE = 65537; // 4th fermat number, starting point
         
        for (int i = 0; i < num; i++) {
            while (true) {
                try {
                    e[i] = BigInteger.valueOf(currentE);
                    currentE += 2;
                    d[i] = e[i].modInverse(phi);
                    break; // in case no exception is thrown, we found one
                } catch (ArithmeticException ae) {
                    // try again
                }
            }
        }
    }

    public void generateImpl(SecureRandom sr) {
  
        generateImpl(sr, 1);
    }


    public ChaumPublicParams getPublic(int i) {
  
        return new ChaumPublicParams(n, e[i],
                                      item, series, expiry, log);
    }

    public ChaumPrivateParams getPrivate(int i) {
  
        return new ChaumPrivateParams(n, d[i], p, q,
                                      item, series, expiry, log);
    }



////// Self-Test //////////////////////////////////


    public static ChaumPair example(SecureRandom sr,
                                    byte[] i, byte[] s, long exp, byte log)
    {
        ChaumPair cp = new ChaumPair();
        cp.generate(sr, i, s, exp, log);
        return cp;
    }

    private static SecureRandom sr = null;

    public static ChaumPair example()
    {
        byte[] item = Utils.exampleData(10);
        byte[] series = Utils.exampleData(4);
        long expiry = Utils.exampleLong();
        byte log = (byte) (Utils.exampleByte() & 0x7F);

        if (sr == null)
            sr = new SecureRandom();

        return example(sr, item, series, expiry, log);
    }

    public static void main(String[] args)
        throws Exception
    {
        ChaumPair ex = ChaumPair.example();
    }

}




1.1                  java/webfunds/token/chaum/ChaumPrivateParams.java

Index: ChaumPrivateParams.java
===================================================================
/*
 * $Id: ChaumPrivateParams.java,v 1.1 2001/04/02 02:12:22 iang Exp $
 *
 * Copyright (c) Systemics Inc 1995-2000 on behalf of
 * the WebFunds Development Team.  All Rights Reserved.
 */
package webfunds.token.chaum;

import java.io.InputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.DataInputStream;
import java.io.OutputStream;
import java.io.DataOutputStream;

import java.math.BigInteger;

import webfunds.token.AbstractPrivateParams;
import webfunds.token.Factory;
import webfunds.token.TokenPacketException;


/**
 *  This class represents a Private (minting) key for a CHAUM token,
 *  including the {item, series, expiry, log} tuple.
 *
 */
public class ChaumPrivateParams
    extends AbstractPrivateParams
{
    /**
     *  The version number for this structure:
     *         0:     current
     */
    public static final int CHAUM_PRIV_VERSION = 0;

    private BigInteger n, d, p, q;

    /* package */ BigInteger getN() { return n; }
    /* package */ BigInteger getD() { return d; }
    /* package */ BigInteger getP() { return p; }
    /* package */ BigInteger getQ() { return q; }

    /**
     *  Create a Private Params for Chaum Tokens.
     *
     *  @param item is the description of which instrument relates
     *  @param series is the short descriptor of which set of tokens this is
     *  @param expiry date on which this series will expire
     *  @param log the coin size, log base 2 of quantity
     */
    public ChaumPrivateParams(BigInteger n, BigInteger d,
                         BigInteger p, BigInteger q,
                         byte[] item,
                         byte[] series, long expiry,
                         byte log)
    {
        super(CHAUM_PRIV_VERSION, Factory.CHAUM_TOKEN,
              series, expiry, item, log);

        this.n = n;
        this.d = d;
        this.p = p;
        this.q = q;
    }

    /**
     *  Construct a token object from a byte array
     *  that was previously returned from the encode()
     *  method of a token object.
     *
     *  @param token the previously encoded token
     *  @excep TokenPacketException The token data is badly formatted
     */
    public ChaumPrivateParams(byte[] buf)
        throws TokenPacketException
    {
        super(buf);
    }

    /**
     *  Construct a token object from data in an input stream,
     *  where the data was previously returned from the encode()
     *  method of a token object.
     *
     *  @param is the input stream from which to read the token data
     *  @excep TokenPacketException The token data is badly formatted
     */
    public ChaumPrivateParams(InputStream is)
        throws TokenPacketException
    {
        super(is);
    }



    /**
     *  Update this token object with the values from
     *  a token encoded as a byte array (such as previously
     *  returned from the encode() method of a token object).
     *
     *  @param token the previosly encoded token
     */
    public void decode(InputStream is)
        throws IOException
    {
        DataInputStream dis = new DataInputStream(is);

        super.decode(dis);

        n = new BigInteger(1, readByteArray(dis));
        d = new BigInteger(1, readByteArray(dis));
        p = new BigInteger(1, readByteArray(dis));
        q = new BigInteger(1, readByteArray(dis));

    }

    /**
     * Encode a token as a byte array, suitable for
     * sending to third parties for depositing.
     * If the signature is not present, an unsigned
     * token will be encoded.
     *
     * @return byte[] the token in encoded form
     */
    public void encode(OutputStream os)
        throws IOException
    {
        DataOutputStream dos = new DataOutputStream(os);

        super.encode(dos);

        writeByteArray(dos, n.toByteArray());
        writeByteArray(dos, d.toByteArray());
        writeByteArray(dos, p.toByteArray());
        writeByteArray(dos, q.toByteArray());

    }



////// Self-Test //////////////////////////////////

    public String toString()
    {
        String s = super.toString(); 
        s += "\n" + n.toString() + "\n";
        s += "\n" + d.toString() + "\n";
        s += "\n" + p.toString() + "\n";
        s += "\n" + q.toString() + "\n";

        return s;
    }

    public boolean equals(java.lang.Object obj)
    {
        if (obj == null || !(obj instanceof ChaumPrivateParams))
            return false;

        ChaumPrivateParams other = (ChaumPrivateParams)obj;

        if (!super.equals(other))
            return false;
        if (!n.equals(other.n))
            return false;
        if (!d.equals(other.d))
            return false;
        if (!p.equals(other.p))
            return false;
        if (!q.equals(other.q))
            return false;

        return true;
    }


    /**
     *  Calling this example will mean the Public part is lost.
     */
    public static ChaumPrivateParams example()
    {
        ChaumPair cp = ChaumPair.example();
        return (ChaumPrivateParams) cp.getPrivate();
    }

}



1.1                  java/webfunds/token/chaum/ChaumProtoToken.java

Index: ChaumProtoToken.java
===================================================================
/* $Id: ChaumProtoToken.java,v 1.1 2001/04/02 02:12:23 iang Exp $
 *
 * Copyright (c) 2000-2001 Systemics Inc on behalf of
 * the WebFunds Development Team.  All Rights Reserved.
 */
package webfunds.token.chaum;

import java.io.InputStream;
import java.io.OutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;

import java.math.BigInteger;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

import webfunds.util.Panic;
import webfunds.util.Hex;

import webfunds.sox.Utils;

import webfunds.token.*;

/**
 *  This is the proto-Token using Chaum blinding, as such
 *  it is pre-withdrawal, and is only valuable if the withdrawal
 *  has been started.
 *
 *  @version $Revision: 1.1 $
 *  @author Edwin Woudt <edwin@webfunds.org>
 */
public final class ChaumProtoToken extends TokenBuilder {

    public static final int CHAUM_PROTO_V1 = 1;

// Instance variables
//.............................................................................

    private BigInteger protoToken = null;
    private BigInteger blindingFactor = null;
    private BigInteger blindedProtoToken = null;

    /**
     *
     *  @return a byte array with the unique id, else null if not good state
     */
    public byte[] getUniqueId()
    {
        byte[] id = super.getUniqueId();
        if (id != null)
            return id;

        if (isUnSaved() || isProto())
            return null;

        setUniqueId(blindedProtoToken.toByteArray());
        return super.getUniqueId();
    }

// Constructors
//.............................................................................
    /**
     *  Construct the token object, in RAW state.
     *
     */
    public ChaumProtoToken()
    {
        super();
    }

    /**
     *  Construct a token object from a byte array
     *  that was previously returned from the encode()
     *  method of a token object.
     *
     *  @param token the previously encoded token
     *  @excep TokenPacketException The token data is badly formatted
     */
    public ChaumProtoToken(byte[] buf)
        throws TokenPacketException
    {
        super(buf);
    }  

    /**
     *  Construct a token object from data in an input stream,
     *  where the data was previously returned from the encode()
     *  method of a token object.
     *
     *  @param is the input stream from which to read the token data
     *  @excep TokenPacketException The token data is badly formatted
     */
    public ChaumProtoToken(InputStream is)
        throws TokenPacketException
    {
        super(is);
    }



// Init methods
//.............................................................................

    /* package */ static byte[] hashAndExtend(byte[] id) {

        byte[] proto = new byte[ChaumConstants.KEY_SIZE];
        proto[0] = 0; // first byte always zero to avoid overflow errors

        System.arraycopy(id, 0, proto, 1, id.length);
        int pos = id.length+1;

        MessageDigest md;
        try {
            md = MessageDigest.getInstance(ChaumConstants.HASH_ALG);
        } catch (NoSuchAlgorithmException nsae) {
            throw new Panic(noMD);
        }

        while (pos < proto.length - ChaumConstants.HASH_SIZE) {
            md.reset();
            id = md.digest(id);
            System.arraycopy(id, 0, proto, pos, id.length);
            pos += id.length;
        }

        md.reset();
        id = md.digest(id);
        System.arraycopy(id, 0, proto, pos, proto.length - pos);

        return proto;

    }

    public void proto(SecureRandom sr,
                         AbstractPublicParams pp) {

        super.proto(pp);
        if ( ! (pp instanceof ChaumPublicParams) )
            throw new IllegalArgumentException("not chaum: " + pp.getClass());

        ChaumPublicParams params = (ChaumPublicParams)pp;

        byte[] id = new byte[ChaumConstants.RANDOM_SIZE];
        sr.nextBytes(id);

        byte[] proto = hashAndExtend(id);
        protoToken = new BigInteger(1, proto);

        byte[] blind = new byte[ChaumConstants.KEY_SIZE];
        sr.nextBytes(blind);
        blind[0] &= 0x7f;  // zero first bit to make it smaller than N
        blindingFactor = new BigInteger(1, blind);

        BigInteger n = params.getN();
        BigInteger e = params.getE();

        blindedProtoToken =
            protoToken.multiply(blindingFactor.modPow(e, n)).mod(n);
    }



// Input/Output methods
//.............................................................................

    public void decode(InputStream is)
        throws IOException
    {
        DataInputStream dis = new DataInputStream(is);

        super.decode(dis);

        if (type != Factory.CHAUM_TOKEN)
            throw new IOException("not my token: "+
                                type + " != " + Factory.CHAUM_TOKEN);
        if (subversion != CHAUM_PROTO_V1)
            throw new IOException("Invalid sub version in token: "+
                                subversion + " != " + CHAUM_PROTO_V1);

        if (isRaw())
            return ;

        if (isUnSaved())
        {
            protoToken = readBigInt(dis);
            blindingFactor = readBigInt(dis);
        }
        else if (isProto())
        {
            blindedProtoToken = readBigInt(dis);
        }
        else
            throw new IOException("what state " + state + "?");
    }



    /**
     *  Encode a token as a byte array, suitable for
     *  sending to third parties for depositing, OR
     *  for saving to disk securely for later retry.
     *
     *  Note, it is the caller's responsibility to decide
     *  whether the token is correctly saved and is now
     *  fit for withdrawal (and thus, the caller can set
     *  state to TOK_PROTO).
     */
    public void encode(OutputStream os)
        throws IOException
    {
        DataOutputStream dos = new DataOutputStream(os);
        super.encode(dos);

        if (isRaw())
            return ;

        if (isUnSaved())
        {
            writeBigInt(dos, protoToken);
            writeBigInt(dos, blindingFactor);
        }
        else if (isProto())
        {
            writeBigInt(dos, blindedProtoToken);
        }
        else
            throw new IllegalArgumentException("what state " + state + "?");
    }





////// Self-Test //////////////////////////////////

    public boolean equals(Object object)
    {  
        if ( (object == null) || !(object instanceof ChaumProtoToken) )
            return false;

        ChaumProtoToken other = (ChaumProtoToken)object;

//System.err.println("1: " + version + " " + other.version);
        if (!super.equals(other))
            return false;

        if (isRaw())
            return true ;

        if (isUnSaved())
        {
//System.err.println("1: ");
            if (!equalsBigInt(protoToken, other.protoToken))
                return false;

//System.err.println("2: ");
            if (!equalsBigInt(blindingFactor, other.blindingFactor))
                return false;
        }
        else if (isProto())
        {
//System.err.println("3: ");
            if (!equalsBigInt(blindedProtoToken, other.blindedProtoToken))
                return false;
        }
        else
            return false;
//System.err.println("4: ");

        return true ;
    }       

    /**
     * Convert this object to a human readable string
     */
    public String toString()
    {
        String s = "Chaum ChaumProtoToken " + super.toString() + ": ";

        if (state == TOK_RAW)
            return s;

        if (state == TOK_UNSAVED)
        {
            s += "\tpT == " + protoToken + "\n";
            s += "\tbF == " + blindingFactor + "\n";
        }
        else if (state == TOK_PROTO)
        {
            s += "\tPt == " + blindedProtoToken + "\n";
        }
        else
            s += "\t what state is " + state + "?\n";

        return s;
    }

/*
    public String vString()
    {
        return "V" + version;
    }
*/

    public static ChaumProtoToken example(AbstractPublicParams pp)
    {
        ChaumPublicParams params = (ChaumPublicParams) pp;
        ChaumProtoToken p = new ChaumProtoToken();
	p.proto(params);
        int state = Utils.exampleByte() % 3;

        if (state == TOK_RAW)
        {
            return p;                    // new is already raw
        }
        
        p.protoToken = Utils.examplePosBigInt();
        p.blindingFactor = Utils.examplePosBigInt();
        p.blindedProtoToken = Utils.examplePosBigInt();

        if (state == TOK_UNSAVED)   
        {   
            p.state = TOK_UNSAVED;
        }
        else if (state == TOK_PROTO)
        {
            p.setProto();
        }

        return p;
    }

    public static ChaumProtoToken example()
    {
        ChaumPublicParams params = ChaumPublicParams.example();
        return example(params);
    }


    public static ChaumPublicParams getParams(String fname)
    {
        if (fname == null)
            return ChaumPublicParams.example();

        ChaumPublicParams params = null;
        try {
            FileInputStream fis = new FileInputStream(fname);
            params = new ChaumPublicParams(fis);
        } catch(Exception e) {
            e.printStackTrace();
            System.exit(1);
        }

        return params;
    }

    public static void main(String[] args)
    {
	int num = 2000;
	String type = "-c";
	String paramsFile = null;

	if (args.length > 0)
	{
	    int a = 0;
	    while (args[a].startsWith("-"))
	    {
	        String arg = args[a++];
                if (arg.equals("-t") || arg.equals("-i"))
                    type = arg;
                else if (arg.equals("-f"))
                    paramsFile = args[a++];
                
                if (a < args.length)
                    break;
	    }

            if (a < args.length)
	    {
		Integer i = null;
                try {
		    i = new Integer(args[a]);
		} catch (Exception e) {
		    e.printStackTrace();
		    System.exit(1);
		}
                num = i.intValue();
	    }
	}

        ChaumPublicParams params = getParams(paramsFile);

        try {
	    if (type.equals("-t") || type.equals("-i"))
	    {
		while (true)
		{
                    if (type.equals("-t"))
		        readWrite();
                    else if (type.equals("-i"))
		        input();
	        }
	    }
	    else
	    {
                for (int i = 0; i < num; i++)
	        {
                    if (type.equals("-c"))
		        cycle(params);
                    else if (type.equals("-o"))
		        output(params);
	        }
	    }
        } catch(Exception e) {
            e.printStackTrace();
            System.exit(1);
        }
	System.out.flush();          // last buffered lump still there
	System.out.close();
        System.exit(0);
    }

    protected static void cycle(ChaumPublicParams params)
        throws Exception
    {
	ChaumProtoToken p = example(params);
        System.err.println("Writing: " + p);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        p.encode(baos);
        byte[] buf = baos.toByteArray();

        ChaumProtoToken q = new ChaumProtoToken(buf);
        if (!p.equals(q))
        {
            throw new Panic("FAILED:\n\n"+q+"\n\n"+p+"\nEND\n");
        }
    }

    protected static void output(ChaumPublicParams params)
        throws Exception
    {
	ChaumProtoToken b = example(params);
	b.encode(System.out);
    }

    protected static void readWrite()
        throws Exception
    {
	ChaumProtoToken b = null;
	b = new ChaumProtoToken(System.in);
        System.err.println("Read: " + b);
	b.encode(System.out);
    }

    protected static void input()
        throws Exception
    {
	ChaumProtoToken b = null;
	b = new ChaumProtoToken(System.in);
        System.err.println("Read: " + b);
    }

}



1.1                  java/webfunds/token/chaum/ChaumPublicParams.java

Index: ChaumPublicParams.java
===================================================================
/*
 * $Id: ChaumPublicParams.java,v 1.1 2001/04/02 02:12:23 iang Exp $
 *
 * Copyright (c) Systemics Inc 1995-2000 on behalf of
 * the WebFunds Development Team.  All Rights Reserved.
 */
package webfunds.token.chaum;

import java.io.InputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.DataInputStream;
import java.io.OutputStream;
import java.io.DataOutputStream;
import java.io.FileOutputStream;

import java.math.BigInteger;

import webfunds.token.AbstractPublicParams;
import webfunds.token.Factory;
import webfunds.token.TokenPacketException;

/**
 *  This class represents a Public (verifying) key for a CHAUM token.
 *
 */
public class ChaumPublicParams
    extends AbstractPublicParams
{
    /**
     *  The version number for this structure:
     *         0:     current
     */
    public static final byte CHAUM_PUB_VERSION = 0;

    private BigInteger n, e;

    /* package */ BigInteger getN() { return n; }
    /* package */ BigInteger getE() { return e; }

    /**
     *  Create a Public Params for Chaum Tokens.
     *
     *  @param item is the description of which instrument relates
     *  @param series is the short descriptor of which set of tokens this is
     *  @param expiry date on which this series will expire
     *  @param log the coin size, log base 2 of quantity
     */
    public ChaumPublicParams(BigInteger n, BigInteger e,
                         byte[] item,
                         byte[] series, long expiry,
                         byte log)
    {
        super(CHAUM_PUB_VERSION, Factory.CHAUM_TOKEN,
              series, expiry, item, log);

        this.n = n;
        this.e = e;
    }

    /**
     *  Construct a token object from a byte array
     *  that was previously returned from the encode()
     *  method of a token object.
     *
     *  @param token the previously encoded token
     *  @excep TokenPacketException The token data is badly formatted
     */
    public ChaumPublicParams(byte[] buf)
        throws TokenPacketException
    {
        super(buf);
    }

    /**
     *  Construct a token object from data in an input stream,
     *  where the data was previously returned from the encode()
     *  method of a token object.
     *
     *  @param is the input stream from which to read the token data
     *  @excep TokenPacketException The token data is badly formatted
     */
    public ChaumPublicParams(InputStream is)
        throws TokenPacketException
    {
        super(is);
    }



    /**
     *  Update this token object with the values from
     *  a token encoded as a byte array (such as previously
     *  returned from the encode() method of a token object).
     *
     *  @param token the previosly encoded token
     */
    public void decode(InputStream is)
        throws IOException
    {
        DataInputStream dis = new DataInputStream(is);

        super.decode(dis);

        n = new BigInteger(1, readByteArray(dis));
        e = new BigInteger(1, readByteArray(dis));

    }

    /**
     * Encode a token as a byte array, suitable for
     * sending to third parties for depositing.
     * If the signature is not present, an unsigned
     * token will be encoded.
     *
     * @return byte[] the token in encoded form
     */
    public void encode(OutputStream os)
        throws IOException
    {
        DataOutputStream dos = new DataOutputStream(os);

        writeByteArray(dos, n.toByteArray());
        writeByteArray(dos, e.toByteArray());

    }



////// Self-Test //////////////////////////////////

    public String toString()
    {
        String s = super.toString(); 
        s += "\n" + n.toString() + "\n";
        s += "\n" + e.toString() + "\n";

        return s;
    }

    public boolean equals(java.lang.Object obj)
    {
        if (obj == null || !(obj instanceof ChaumPublicParams))
            return false;

        ChaumPublicParams other = (ChaumPublicParams)obj;

        if (!super.equals(other))
            return false;
        if (!n.equals(other.n))
            return false;
        if (!e.equals(other.e))
            return false;

        return true;
    }


    /**
     *  Calling this example will mean the Private part is lost.
     */
    public static ChaumPublicParams example()
    {
        ChaumPair cp = ChaumPair.example();
        return (ChaumPublicParams) cp.getPublic();
    }

    public static void main(String[] args)
    {
        int num = 2000;
        String type = "-c";
        String paramsFile = null;

        if (args.length > 0)
        {
            int a = 0;
            while (args[a].startsWith("-"))
            {
                String arg = args[a++];
                if (arg.equals("-f"))
                    paramsFile = args[a++];

                if (a >= args.length)
                    break;
            }
        }

        if (paramsFile != null)
        {
            ChaumPublicParams params = example();
            FileOutputStream fos;
            try {
                fos = new FileOutputStream(paramsFile);
                params.encode(fos);
                fos.close();
            } catch(Exception e) {   
                e.printStackTrace();
                System.exit(1);
            }

        }
    }

}