[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);
}
}
}
}