[Webfunds-commits] java/webfunds/token AbstractParams.java AbstractPrivateParams.java AbstractPublicParams.java BaseToken.java Constants.java Factory.java TokenBuilder.java TokenDead.java TokenException.java TokenKeyException.java TokenPacketException.java TokenSigner.java TokenSpender.java TokenVersionException.java TokenTest.java
Ian Grigg
iang@cypherpunks.ai
Sun, 1 Apr 2001 18:25:27 -0400 (AST)
iang 01/04/01 18:25:27
Modified: webfunds/token TokenTest.java
Added: webfunds/token/util Log.java
webfunds/token AbstractParams.java
AbstractPrivateParams.java
AbstractPublicParams.java BaseToken.java
Constants.java Factory.java TokenBuilder.java
TokenDead.java TokenException.java
TokenKeyException.java TokenPacketException.java
TokenSigner.java TokenSpender.java
TokenVersionException.java
Log:
3rd generation model for tokens
Revision Changes Path
1.1 java/webfunds/token/util/Log.java
Index: Log.java
===================================================================
/* $Id: Log.java,v 1.1 2001/04/01 22:25:23 iang Exp $
*
* Copyright (c) 2001 Systemics Inc. on behalf of
* The WebFunds Development Team. All Rights Reserved.
*/
package webfunds.token.util;
public final class Log
{
private Log() {}
/**
* @return the quantity from a coin size, which is always logarithmic,
* if outside range, -1 is returned.
*/
public static long log2qty(int log)
{
if (! (0 <= log && log <= 63) )
return -1;
if (log == 0)
return 0;
long q = 1;
while (--log > 0)
q <<= 1;
return q;
}
/**
* @return a single largest coin size from a quantity.
*/
public static int qty2log(long qty)
{
if (qty < 0)
throw new IllegalArgumentException("qty < 0: " + qty);
int i = 0;
while (qty != 0)
{
qty >>= 1;
i++;
}
return i;
}
/**
* @return an array representing the coin sizes
* required for this quantity
*/
public static int[] qty2coins(long qty)
{
if (qty < 0)
throw new IllegalArgumentException("qty < 0: " + qty);
int num = 0;
long q;
for (q = qty; q != 0; q >>= 1)
{
if ( (q & 01) == 01 )
num++;
}
int[] coins = new int[num];
int i = 0;
int size = 0;
for (q = qty; q != 0; q >>= 1)
{
size++;
if ( (q & 01) == 01 )
coins[i++] = size;
}
return coins;
}
////// Test Code /////////////////////////////////////
public static void main(String[] args)
{
if (log2qty(0) != 0)
throw new RuntimeException("log(0) != 0 : " + log2qty(0));
if (log2qty(1) != 1)
throw new RuntimeException("log(1) != 1 : " + log2qty(1));
if (log2qty(4) != 8)
throw new RuntimeException("log(4) != 8 : " + log2qty(4));
if (log2qty(63) != 4611686018427387904L)
throw new RuntimeException("log(63) != 4611686018427387904 : " +
log2qty(63));
if (qty2log(0) != 0)
throw new RuntimeException("qty(0) != 0 : " + qty2log(0));
if (qty2log(1) != 1)
throw new RuntimeException("qty(1) != 1 : " + qty2log(1));
if (qty2log(31) != 5)
throw new RuntimeException("qty(31) != 5 : " + qty2log(31));
if (qty2log(2147483647) != 31)
throw new RuntimeException("qty(2147483647) != 31 : " +
qty2log(2147483647));
if (qty2coins(0).length != 0)
throw new RuntimeException("coins(0) != 0 : " + qty2coins(0).length);
if (qty2coins(1).length != 1)
throw new RuntimeException("coins(1) != 1 : " + qty2coins(1).length);
if (qty2coins(16).length != 1)
throw new RuntimeException("coins(16) != 1 : " + qty2coins(16).length);
if (qty2coins(17).length != 2)
throw new RuntimeException("coins(17) != 2 : " + qty2coins(17).length);
if (qty2coins(19).length != 3)
throw new RuntimeException("coins(19) != 3 : " + qty2coins(19).length);
for (int i = 0; i <= 16; i++)
{
int log = qty2log(i);
long qty = log2qty(i);
System.out.print(i + ": " + log + "\t" + qty + "\t" +
qty2log(qty) + "\t" + log2qty(log));
int[] coins = qty2coins(i);
for (int j = coins.length - 1; j >= 0; j--)
System.out.print("\t" + coins[j]);
System.out.println("");
}
}
}
1.3 +59 -11 java/webfunds/token/TokenTest.java
Index: TokenTest.java
===================================================================
RCS file: /home/webfunds/cvsroot/java/webfunds/token/TokenTest.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- TokenTest.java 2001/01/24 20:25:26 1.2
+++ TokenTest.java 2001/04/01 22:25:25 1.3
@@ -1,4 +1,4 @@
-/* $Id: TokenTest.java,v 1.2 2001/01/24 20:25:26 iang Exp $
+/* $Id: TokenTest.java,v 1.3 2001/04/01 22:25:25 iang Exp $
*
* Copyright (c) 2000-2001 Systemics Inc on behalf of
* the WebFunds Development Team. All Rights Reserved.
@@ -30,29 +30,39 @@
private static PublicKey signkey;
protected static void logmsg(String s) { System.err.println(s); }
+
+ private static final String SIGN_ALG = "DSA";
- public static void generate() throws DataFormatException, Exception {
- // executed by Ivan
+ /**
+ * Make a Keypair for below tests.
+ */
+ private static KeyPair generateDSAKeyPair() throws Exception {
/*
- * Server generates a DSA sign key.
+ * Server generates a DSA sign key for signing params.
* Normally the application would use an
* already established key for signing.
*/
logmsg(". random");
sr.nextInt();
- KeyPairGenerator gen = KeyPairGenerator.getInstance("DSA");
+ KeyPairGenerator gen;
+ gen = KeyPairGenerator.getInstance(SIGN_ALG);
logmsg(". DSA key " + gen);
if (gen == null)
throw new Exception("KPG returned null?");
KeyPair pair = gen.generateKeyPair();
- if (pair == null)
- throw new Exception("generate returned null?");
+ return pair;
+ }
+
+ public static void generate(AbstractPrivateTokenParameters params)
+ throws DataFormatException, Exception {
+ // executed by Ivan
+
+ KeyPair pair = generateDSAKeyPair();
signkey = pair.getPublic();
// The real work
- logmsg(". Chaum params");
- ChaumPrivateTokenParameters params = new ChaumPrivateTokenParameters();
+ logmsg(". sign params");
params.generate(sr, denominations, currencyID, series, expiry);
params.sign(pair.getPrivate(), "DSA", null, sr);
@@ -62,6 +72,24 @@
privparams = params.encodePrivateData();
}
+ public static void generateChaum() throws DataFormatException, Exception {
+ // executed by Ivan
+
+ // The real work
+ logmsg(". Chaum params");
+ ChaumPrivateTokenParameters params = new ChaumPrivateTokenParameters();
+ generate(params);
+ }
+
+ public static void generateRandom() throws DataFormatException, Exception {
+ // executed by Ivan
+
+ // The real work
+ logmsg(". Random params");
+ RandomPrivateTokenParameters params = new RandomPrivateTokenParameters();
+ generate(params);
+ }
+
// Step 2: generating prototokens on the client
//.............................................................................
@@ -206,8 +234,28 @@
//.............................................................................
public static void main(String[] args) throws Exception {
- logmsg("generate");
- generate();
+ testRandom();
+ testChaum();
+ }
+
+ public static void testChaum() throws Exception {
+ logmsg("Chaum generate");
+ generateChaum();
+ logmsg("createprotos");
+ createprotos();
+ logmsg("signblinded");
+ signblinded();
+ logmsg("unblindsigned");
+ unblindsigned();
+ logmsg("transfercoinclient");
+ transfercoinclient();
+ logmsg("transfercoinsserver");
+ transfercoinsserver();
+ }
+
+ public static void testRandom() throws Exception {
+ logmsg("Random generate");
+ generateRandom();
logmsg("createprotos");
createprotos();
logmsg("signblinded");
1.1 java/webfunds/token/AbstractParams.java
Index: AbstractParams.java
===================================================================
/*
* $Id: AbstractParams.java,v 1.1 2001/04/01 22:25:24 iang Exp $
*
* Copyright (c) Systemics Inc 1995-2000 on behalf of
* the WebFunds Development Team. All Rights Reserved.
*/
package webfunds.token;
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 webfunds.utils.Hex;
import webfunds.utils.Support;
import webfunds.sox.Encodable;
import webfunds.sox.SOXPacketException;
import webfunds.token.util.Log;
/**
* Represents a Private (signing) key for a token
* {item, series, expiry, log} tuple.
*
* Refer to AbstractPublicParams for common methods.
*/
public abstract class AbstractParams
extends Encodable
{
/**
* The version number for this structure:
* 0: current
*/
public static final int PARAMS_VERSION = 0;
protected int version = PARAMS_VERSION;
public final int getVersion() { return version; }
/**
* The type of token of this class
* See Factory for current definitions.
*/
protected int type;
public int getType() { return type; }
/**
* The version of the subclass.
*
*/
protected int subversion;
public int getSubVersion() { return subversion; }
/**
* The quantity of the item that this token represents.
* Encoded in logarithm - base 2 of the quantity.
*
* Log Qty
* 0 0
* 1 1
* 2 2
* 3 4
* 4 8
*
* and so forth. -1 could be used for "not stated", meaning it is
* encoded in the magic parts (by use of certain key, for example).
*/
protected int log;
public int getLog() { return log; }
/**
* Note (1) that this may be derived information, the real
* token value may be encoded in the signature key or
* some other way.
*
* Note (2) that the unit of account is not encoded within
* the token, the higher layer code should remember that.
* See Payments for the encoded Item (a.k.a. Ricardian Contract).
*
* @return quantity of the item that this token represents,
* being 0 - n representing which bit,
* or -1 if "not so encoded"
*/
public long getQty() { return Log.log2qty(log); }
/**
* Tokens commonly come from a batch that is identified
* with a series label or an expiry date.
* These are interpreted by the subclass, may be ignored.
*/
protected long expiry;
public long getExpiry() { return expiry; }
protected byte[] series;
public byte[] getSeries() { return series; }
protected byte[] item;
public byte[] getItem() { return item; }
/**
* Create an uninitialised Private Params.
*
* @param subversion is the version of the parent coin class
* @param type of token, being the blinding or coin scheme
* @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
*/
AbstractParams(int subversion,
int tokenType,
byte[] series, long expiry,
byte[] item,
byte log)
{
this.type = tokenType;
this.subversion = subversion;
this.series = series;
this.expiry = expiry;
this.item = item;
this.log = log;
}
/**
* Reconstruct the object from a previously encoded byte array.
*
* @param buf the previously encoded object
* @excep TokenPacketException if the data is badly formatted
*/
public AbstractParams(byte[] buf)
throws TokenPacketException
{
try {
decode(buf);
} catch (SOXPacketException ex) {
throw new TokenPacketException("IOEx: " + ex);
}
}
/**
* Reconstruct the object from data in an input stream.
*
* @param is the input stream from which to read the data
* @excep TokenPacketException if the data is badly formatted
*/
public AbstractParams(InputStream is)
throws TokenPacketException
{
try {
decode(is);
} catch (IOException ex) { // compiler doesn't insist, but thrown!
throw new TokenPacketException("IOEx: " + ex);
}
}
/**
* Update this params 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);
int v = dis.readUnsignedByte();
if (v != PARAMS_VERSION)
throw new IOException /*TokenPacketException*/ ("Invalid version in token: "+
v + " != " + PARAMS_VERSION);
version = v;
/*
* Type and subversion should be interpreted by subclass.
*/
type = dis.readUnsignedByte();
subversion = dis.readUnsignedByte();
log = dis.readUnsignedByte();
expiry = dis.readInt();
series = readByteArray(dis);
item = readByteArray(dis);
}
/**
* Encode a params 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);
dos.writeByte(version);
dos.writeByte(type);
dos.writeByte(subversion);
dos.writeByte(log);
dos.writeInt((int)expiry);
writeByteArray(dos, series);
writeByteArray(dos, item);
}
////// Self-Test //////////////////////////////////
public String toString()
{
String s = vString();
s += " type: (" + type + ") " + Factory.getTypeString(type);
s += " qty: (" + log + ") " + Log.log2qty(log);
if (expiry > 0)
s += " exp: " + expiry;
if ((series != null) && (series.length > 0))
s += Hex.printable(series);
if ((item != null) && (item.length > 0))
s += Hex.data2hex(item);
return s;
}
public String vString()
{
return "V" + subversion + " (" + version + ")";
}
protected boolean equals(AbstractParams other)
{
if (other.version != version)
return false;
if (other.type != type)
return false;
if (other.subversion != subversion)
return false;
if (other.log != log)
return false;
if (other.expiry != expiry)
return false;
if (!Support.equals(series, other.series))
return false;
if (!Support.equals(item, other.item))
return false;
return true;
}
}
1.1 java/webfunds/token/AbstractPrivateParams.java
Index: AbstractPrivateParams.java
===================================================================
/*
* $Id: AbstractPrivateParams.java,v 1.1 2001/04/01 22:25:24 iang Exp $
*
* Copyright (c) Systemics Inc 1995-2000 on behalf of
* the WebFunds Development Team. All Rights Reserved.
*/
package webfunds.token;
import java.io.InputStream;
/**
* Represents a Private (signing) capability for a token
* where each capability includes a {item, series, expiry, log} tuple.
*
* Refer to AbstractPublicParams for common methods.
*/
public abstract class AbstractPrivateParams
extends AbstractParams
{
/**
* Create an uninitialised Private Params.
*/
public AbstractPrivateParams(int subversion,
int tokenType,
byte[] series, long expiry,
byte[] item,
byte log)
{
super(subversion,
tokenType,
series, expiry,
item,
log);
}
/**
* Reconstruct the object from a byte array.
*
* @param buf the previously encoded object
* @excep TokenPacketException if the data is badly formatted
*/
public AbstractPrivateParams(byte[] buf)
throws TokenPacketException
{
super(buf);
}
/**
* Reconstruct the object from data in an input stream.
*
* @param is the input stream from which to read the data
* @excep TokenPacketException if the data is badly formatted
*/
public AbstractPrivateParams(InputStream is)
throws TokenPacketException
{
super(is);
}
////// Self-Test //////////////////////////////////
public String vString()
{
return "priv V" + subversion + " (" + version + ")";
}
}
1.1 java/webfunds/token/AbstractPublicParams.java
Index: AbstractPublicParams.java
===================================================================
/*
* $Id: AbstractPublicParams.java,v 1.1 2001/04/01 22:25:24 iang Exp $
*
* Copyright (c) Systemics Inc 1995-2000 on behalf of
* the WebFunds Development Team. All Rights Reserved.
*/
package webfunds.token;
import java.io.InputStream;
/**
* This class represents a Public (verifying) key for a token.
*
*/
public abstract class AbstractPublicParams
extends AbstractParams
{
/**
* Create an uninitialised Public Params.
*
* @param subversion is the version of the parent coin class
* @param type of token, being the blinding or coin scheme
* @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 AbstractPublicParams(int subversion,
int tokenType,
byte[] series, long expiry,
byte[] item,
byte log)
{
super(subversion,
tokenType,
series, expiry,
item,
log);
}
/**
* 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 SOXPacketException The token data is badly formatted
*/
public AbstractPublicParams(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 SOXPacketException The token data is badly formatted
*/
public AbstractPublicParams(InputStream is)
throws TokenPacketException
{
super(is);
}
}
1.1 java/webfunds/token/BaseToken.java
Index: BaseToken.java
===================================================================
/*
* $Id: BaseToken.java,v 1.1 2001/04/01 22:25:24 iang Exp $
*
* Copyright (c) Systemics Inc 1995-2000 on behalf of
* the WebFunds Development Team. All Rights Reserved.
*/
package webfunds.token;
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.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.sox.Encodable;
import webfunds.sox.SOXPacketException;
import webfunds.token.utils.Log;
/**
* This class represents a token (a.k.a. coin) throughout its lifecycle.
* Token objects are usually created by means of a Withdrawal
* protocol between client and mint-capable SOXServer.
* They go through several phases, being potentially:
* proto
* signed
* blinded
* spent
* which are handled by extending classes as phases.
*/
public abstract class BaseToken
extends Encodable
{
/**
* The version number for BaseToken structure:
* 0: current
*/
public static final int TOK_ORIGINAL = 0;
private int version;
public final int getVersion() { return version; }
/**
* The Phase of the Token structure:
*
* The Token Phase structure is the immediately extending one:
* e.g., TokenBuilder, TokenSigner, TokenSpender, TokenDead.
*/
public static final int PHASE_BUILDER = 0, // not valued as yet
PHASE_SIGNER = 1, // at mint, valued
PHASE_SPEND = 2, // in spender
PHASE_DEAD = 3; // delete this
protected int phase;
public final int getPhase() { return phase; }
public String getPhaseString() {return isValidPhase()?ps[phase]:"? "+phase;}
public static final String[] ps = {"builder", "signer", "spender", "dead"};
public final boolean isValidPhase() { return ((0<=phase) && (phase<=3)); }
public final boolean isBuilder() { return state == PHASE_BUILDER; }
public final boolean isSigner() { return state == PHASE_SIGNER; }
public final boolean isSpender() { return state == PHASE_SPEND; }
public final boolean isDead() { return state == PHASE_DEAD; }
/**
* The version number for Token Phase structure is defined by
* the phase.
*/
protected int phaseVersion;
public final int getPhaseVersion() { return phaseVersion; }
/**
* The type of token of this class, e.g., Wagner.
* See Factory for current definitions.
*/
protected int type;
public int getType() { return type; }
/**
* The version of the subclass Token that sets the type.
*/
protected int subversion;
public int getSubVersion() { return subversion; }
/**
* The state that the token is the state machine within the phase.
* How it is set and advanced is up to the phase class.
* Only the low-order single unsigned byte is saved & restored.
*/
protected int state;
public int getState() { return state; }
public void setState(int state) { this.state = state; }
/**
* The quantity of the item that this token represents.
* Encoded in logarithm - base 2 of the quantity.
*
* Log Qty
* 0 0
* 1 1
* 2 2
* 3 4
* 4 8
*
* and so forth. -1 could be used for "not stated", meaning it is
* encoded in the magic parts (by use of certain key, for example).
*/
protected int log;
public int getLog() { return log; }
/**
* Note (1) that this may be derived information, the real
* token value may be encoded in the signature key or
* some other way.
*
* Note (2) that the unit of account is not encoded within
* the token, the higher layer code should remember that.
* See Payments for the encoded Item (a.k.a. Ricardian Contract).
*
* @return quantity of the item that this token represents,
* being 0 - n representing which bit,
* or -1 if "not so encoded"
*/
public long getQty() { return Log.log2qty(log); }
/**
* Tokens commonly come from a batch that is identified
* with a series label or an expiry date.
* These are interpreted by the subclass, may be ignored.
*/
protected long expiry;
public long getExpiry() { return expiry; }
protected byte[] series;
public byte[] getSeries() { return series; }
/**
* The item that this token relates to.
* Normally a Ricardian hash.
*/
protected byte[] item;
public byte[] getItem() { return item; }
/**
* Create an uninitialised token.
*/
public BaseToken()
{
this.version = TOK_ORIGINAL;
this.phase = PHASE_BUILDER;
}
/**
* 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 SOXPacketException The token data is badly formatted
*/
public BaseToken(byte[] buf)
throws TokenPacketException
{
try {
decode(buf);
} catch (SOXPacketException ex) {
throw new TokenPacketException("SOXPEx: " + ex);
}
}
/**
* 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 SOXPacketException The token data is badly formatted
*/
public BaseToken(InputStream is)
throws TokenPacketException
{
try {
decode(is);
} catch (IOException ex) { // compiler doesn't insist, but thrown!
throw new TokenPacketException("IOEx: " + ex);
}
}
// Init methods
//.............................................................................
private byte[] id = null;
/**
* Get the unique identifier that is used for checking against
* double-spending.
* Normally called by server on depositing.
* Only makes sense if in PHASE_SIGNER or later?
* Or useful as id in all phases?
*
* @return a byte array with the unique id, else null if not good state
public abstract byte[] getUniqueId();
*/
public byte[] getUniqueId()
{
return id ;
}
public final static String noMD = "Hash algorithm not found. Probably a "+
"provider problem.";
/**
* Calculate a unique id on a string of bytes.
* Hmm, does this mean anyone can set the id?
*/
public void setUniqueId(byte[] sourceData)
{
if (id != null) // once only
return ;
MessageDigest md;
try {
md = MessageDigest.getInstance(Constants.HASH_ALG);
} catch (NoSuchAlgorithmException nsae) {
throw new Panic(noMD);
}
id = md.digest(sourceData);
}
// Input/Output methods
//.............................................................................
/**
* 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 previously encoded token
*/
public void decode(InputStream is)
throws IOException
{
DataInputStream dis = new DataInputStream(is);
int v = dis.readUnsignedByte();
if (v != TOK_ORIGINAL)
throw new IOException("Invalid version in token: "+
v + " != " + TOK_ORIGINAL);
version = v;
/*
* Phase, phaseV, Type and subV should be interpreted by subclass.
*/
phase = dis.readUnsignedByte();
phaseVersion = dis.readUnsignedByte();
type = dis.readUnsignedByte();
subversion = dis.readUnsignedByte();
state = dis.readUnsignedByte();
log = dis.readUnsignedByte();
}
/**
* Encode a token as a byte array, suitable for
* saving state.
*
* @return byte[] the token in encoded form
*/
public void encode(OutputStream os)
throws IOException
{
DataOutputStream dos = new DataOutputStream(os);
dos.writeByte(version);
dos.writeByte(phase);
dos.writeByte(phaseVersion);
dos.writeByte(type);
dos.writeByte(subversion);
dos.writeByte(state);
dos.writeByte(log);
//expiry?
}
////// Self-Test //////////////////////////////////
public String toString()
{
String s = " phase == " + getPhaseString();
s += " state == " + state;
s += " " + vString();
return s;
}
public String vString()
{
return "V" + subversion + " (" + phaseVersion + "," + version + ")";
}
public boolean equals(java.lang.Object obj)
{
if (obj == null || !(obj instanceof BaseToken))
return false;
BaseToken other = (BaseToken)obj;
if (other.version != version)
return false;
if (other.phase != phase)
return false;
if (other.phaseVersion != phaseVersion)
return false;
if (other.type != type)
return false;
if (other.subversion != subversion)
return false;
if (other.state != state)
return false;
if (other.log != log)
return false;
if (other.expiry != expiry)
return false;
return true;
}
/* public abstract STATIC BaseToken example(); */
}
1.1 java/webfunds/token/Constants.java
Index: Constants.java
===================================================================
/* $Id: Constants.java,v 1.1 2001/04/01 22:25:24 iang Exp $
*
* Copyright (c) 2000-2001 Systemics Inc on behalf of
* the WebFunds Development Team. All Rights Reserved.
*/
package webfunds.token;
/**
* Constants for the tokens
*
* @version $Revision: 1.1 $
* @author Edwin Woudt <edwin@webfunds.org>
*/
public final class Constants {
private Constants() {} // static constants only
public static final int HASH_SIZE = 160/8;
public static final String HASH_ALG = "SHA-1";
}
1.1 java/webfunds/token/Factory.java
Index: Factory.java
===================================================================
/* $Id: Factory.java,v 1.1 2001/04/01 22:25:24 iang Exp $
*
* Copyright (c) 2001 Systemics Inc. on behalf of
* The WebFunds Development Team. All Rights Reserved.
*/
package webfunds.token;
import java.security.SecureRandom;
import webfunds.token.random.RandomPair;
import webfunds.token.chaum.ChaumPair;
public final class Factory
{
/**
* Each Token technology type gets a number.
*
* 0 and 1 are not Tokens, just there to make it compatible
* with the Payment types. May have to change when new
* Payment types are added.
*
* Use the numbers 100 - 110 for experimental methods,
* not to be used outside your own private circle.
* Once you are ready, ask the WebFunds team to allocate
* you a fixed number from the fixed blocks.
*/
public static final int NONE = 0,
SOX_CHEQUE = 1,
RANDOM_TOKEN = 2,
WAGNER_TOKEN = 3,
CHAUM_TOKEN = 4,
START_EXPERIMENTAL = 100,
END_EXPERIMENTAL = 110;
public static boolean isTokenPayment(int i) { return (2<=i) && (i<=4); }
public static final String[] typeNames = {
"None?",
"SOX Cheque?",
"Random Token",
"Wagner Token",
"Chaum Token"
};
/**
* A short string that can be used in an encoding.
* Used to generate Float account names.
*/
public static final String[] base64Type = {
null,
null,
"Random",
"Wagner",
"Chaum"
};
protected Factory() {}
public static BaseToken decode(byte[] buf)
throws TokenPacketException
{
if (buf == null)
throw new IllegalArgumentException("PaymentFactory.decode(null)");
int av = buf[0]; // abstract version 0;
int typ = buf[1]; // within factory, type of AbstractPayment
int sv = buf[2]; // within type of Token, subversion
String s = "av=" + av + ", tok-type=" + typ + ", sv=" + sv;
System.err.println("analysing token: " + s);
/*
* First, check if it is the old pre-factory form of payment.
* The first byte was zero for those, so the Factory version
* starts at 1.
*/
if (av != BaseToken.TOK_ORIGINAL)
throw new TokenPacketException("Not Token: " + s);
/*
* It's a Factory Token version.
* The second byte written by BaseToken determines
* which one to recover.
*/
BaseToken t;
/*
if (typ == RANDOM_TOKEN)
t = new RandomToken(buf);
else if (typ == WAGNER_TOKEN)
t = new WagnerToken(buf);
else if (typ == CHAUM_TOKEN)
t = new ChaumToken(buf);
else
*/
throw new TokenPacketException("Unknown FactoryPayment: " + s);
// return t;
}
/**
* Is this a valid type, at least according to the ones known
* about here?
*
* @return false if not a known type, else true
*/
public static boolean valid(int type)
{
if (type <= 1)
return false;
if (type >= 5)
return false;
return true ;
}
/**
* Return a diags string for this type.
*/
public static String getTypeString(int type)
{
if (!valid(type))
{
if ((START_EXPERIMENTAL <= type) && (type <= END_EXPERIMENTAL))
return "experimental " + " (" + type + ")";
return "<" + type + " invalid>";
}
return typeNames[type] + " (" + type + ")";
}
/**
* Return a the type number for this payment name.
* Meant for converting user-land strings to the number.
*
* @return the type number constant, or NONE if unknown
*/
public static int getType(String name)
{
if (name == null || name.length() < 0)
return NONE;
for (int i = 0; i < base64Type.length; i++)
{
if (name.equals(base64Type[i]))
return i;
}
for (int i = 0; i < typeNames.length; i++)
{
if (name.equals(typeNames[i]))
return i;
}
return NONE;
}
/**
* Get me a PairParams for some token series.
*/
public static ParamsPair createPair(int typ)
{
if (!valid(typ))
throw new IllegalArgumentException("PF.createKeyPair("+typ+"???)");
ParamsPair kp;
if (typ == RANDOM_TOKEN)
kp = new RandomPair();
/*
else if (typ == WAGNER_TOKEN)
kp = new WagnerPair();
*/
else if (typ == CHAUM_TOKEN)
kp = new ChaumPair();
else
throw new IllegalArgumentException("createKeyPair("+typ+")");
return kp;
}
/**
* Get me a ParamsPair for some token series.
*/
public static ParamsPair createPair(SecureRandom sr, int typ,
byte[] item,
byte[] series,
long expiry,
byte log)
throws TokenKeyException
{
if (series == null)
throw new IllegalArgumentException("PF.createKeyPair("+series+"?)");
if (item == null)
throw new IllegalArgumentException("PF.createKeyPair("+item+"??)");
if (log < 0)
throw new IllegalArgumentException("PF.createKeyPair("+log+"????)");
ParamsPair kp = createPair(typ);
kp.generate(sr, item, series, expiry, log);
return kp;
}
/**
* Get me a list of proto Tokens for a particular type.
* This is the first step in withdrawing coins.
* @throws IllegalArgumentException if typ unknown or amount < 0
*/
public static BaseToken[] getProtoTokens(int typ, long amount)
throws IllegalArgumentException
{
if (!valid(typ))
throw new IllegalArgumentException("PF.createKeyPair("+typ+"?)");
if (amount < 0)
throw new IllegalArgumentException("PF.createKeyPair("+amount+"?)");
BaseToken[] tokens = null;
/*
if (typ == RANDOM_TOKEN)
tokens = RandomProtoToken.getProtoTokens(amount);
else if (typ == WAGNER_TOKEN)
tokens = WagnerToken.getProtoTokens(amount);
else
if (typ == CHAUM_TOKEN)
tokens = ChaumProtoToken.getProtoTokens(amount);
else
throw new IllegalArgumentException("getProtoTokens("+typ+")");
*/
return tokens;
}
////// Test Code /////////////////////////////////////
public static int exampleType()
{
return RANDOM_TOKEN;
}
public static BaseToken example()
{
return example(exampleType());
}
public static BaseToken example(int type)
{
BaseToken t = null;
/*
if (type == RANDOM_TOKEN)
t = RandomToken.example();
else if (type == WAGNER_TOKEN)
t = WagnerToken(buf);
else if (type == CHAUM_TOKEN)
t = ChaumToken.example();
else
throw new RuntimeException("unknown AbstractPayment: " + type);
*/
return t;
}
}
1.1 java/webfunds/token/TokenBuilder.java
Index: TokenBuilder.java
===================================================================
/*
* $Id: TokenBuilder.java,v 1.1 2001/04/01 22:25:24 iang Exp $
*
* Copyright (c) Systemics Inc 1995-2000 on behalf of
* the WebFunds Development Team. All Rights Reserved.
*/
package webfunds.token;
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.security.SecureRandom;
import java.security.PrivateKey;
import java.security.KeyException;
import webfunds.utils.Hex;
import webfunds.sox.Encodable;
import webfunds.sox.SOXPacketException;
import webfunds.token.util.Log;
/**
* This class represents a proto token -- a coin before withdrawal.
*
*/
public abstract class TokenBuilder
extends BaseToken
{
/**
* The version number for this structure:
* 0: current
*/
public static final int BUILDER_ORIGINAL = 0;
/**
* The state that the token is in within this phase
* (generally made by the mint according to the protocol).
* How it is set and advanced is up to the higher layers.
* May be ignored, may use the following TOK numbers.
* Only the low-order single unsigned byte is saved & restored.
*/
public static final int TOK_RAW = 0, // empty, valueless
TOK_UNSAVED = 1, // blinded, unsaved
TOK_PROTO = 2; // clean, valueless
public boolean isRaw() { return state == TOK_RAW; }
public boolean isUnSaved() { return state == TOK_UNSAVED; }
public boolean isProto() { return state == TOK_PROTO; }
protected void setBlinded() { this.state = TOK_UNSAVED; }
/** Can be called to permit output for withdrawal. */
protected void setProto() { this.state = TOK_PROTO; }
/**
* User blinds a raw coin and turns it into a Protocoin.
* Some sort of signing process involved, done internally.
*
* Normally called by client (user), so it is standardised.
* How it is done is up to the individual type of token, but
* we hope we can limit it to this simple interface, as there
* are half a dozen different token crypto-schemes out there.
*
* The sub TokenBuilder needs to save any blinding params and
* acquire the signed information from the unblind call, below.
*
* @param sr is the source of randomness needed by some methods
* @param params includes the blinding paramaters from the mint
*/
public abstract void proto(SecureRandom sr, AbstractPublicParams params)
throws KeyException;
/**
* Called by extending class to save the params details.
*
* The series is unknown until signing (mint can use a different key).
* IS THIS TRUE? BLINDING FACTORS MUST BE KNOWN IN ADVANCE?
*
* @param params includes the blinding paramaters from the mint
* @except IllegalArgumentException if wrong extended params are passed
*/
protected void proto(AbstractPublicParams params)
{
this.type = params.getType();
this.subversion = params.getSubVersion();
this.log = params.getLog();
this.item = params.getItem();
this.expiry = 0;
this.series = null;
this.state = TOK_UNSAVED;
}
/**
* Create a list of proto-Tokens ready for withdrawal.
* This is a static call. See PaymentFactory.getProtoTokens()
*
* @param amount is the total quantity of value in the tokens
* @except SOXArgsException if amount is invalid
*
public static abstract BaseToken[] getProtoTokens(long amount)
throws SOXArgsException;
*/
/**
* Create an uninitialised token builder.
* Call prototype() with some params to make it a real proto-token.
*
* @param type of token, being the blinding or coin scheme
* @param subversion is the version of the parent coin class
* @param log the coin size, log base 2 of quantity
*/
public TokenBuilder()
{
super();
this.phase = PHASE_BUILDER;
this.phaseVersion = BUILDER_ORIGINAL;
this.state = TOK_RAW;
}
/**
* 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 SOXPacketException The token data is badly formatted
*/
public TokenBuilder(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 SOXPacketException The token data is badly formatted
*/
public TokenBuilder(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);
if (phase != PHASE_BUILDER)
throw new IOException("Invalid phase in token: "+
phase + " != " + PHASE_BUILDER);
if (phaseVersion != BUILDER_ORIGINAL)
throw new IOException("Invalid phase version in token: "+
phaseVersion + " != " + BUILDER_ORIGINAL);
}
/**
* 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);
}
////// Self-Test //////////////////////////////////
public String toString()
{
String s = super.toString();
if (isRaw())
return s;
s += " L: " + log + "\tQ: " + Log.log2qty(log);
return s;
}
}
1.1 java/webfunds/token/TokenDead.java
Index: TokenDead.java
===================================================================
/*
* $Id: TokenDead.java,v 1.1 2001/04/01 22:25:24 iang Exp $
*
* Copyright (c) Systemics Inc 1995-2000 on behalf of
* the WebFunds Development Team. All Rights Reserved.
*/
package webfunds.token;
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.security.SecureRandom;
import java.security.PrivateKey;
import java.security.KeyException;
import webfunds.utils.Hex;
import webfunds.sox.Encodable;
import webfunds.sox.SOXPacketException;
/**
* This class represents a dead token for recovery purposes.
* Once spent and the user no longer requires a record of
* the coin, this can be used as a place marker with no info.
* If found in recovery, kill it. Hmm. Should have an ID.
*/
public abstract class TokenDead
extends BaseToken
{
/**
* The version number for this structure:
* 0: current
*/
public static final int DEAD_ORIGINAL = 0;
/**
* The state that the token is in within this phase
* (generally made by the mint according to the protocol).
* How it is set and advanced is up to the higher layers.
* May be ignored, may use the following TOK numbers.
* Only the low-order single unsigned byte is saved & restored.
*/
public static final int TOK_DEAD = 0; // drop this one
/**
*
* @param uniqueId is the one to kill during recovery
*/
public abstract void dead(byte[] uniqueId);
/**
* Create an uninitialised token.
* Call prototype() with some params to make it a real proto-token.
*
* The series is unknown until signing (mint can use a different key).
*
* @param type of token, being the blinding or coin scheme
* @param subversion is the version of the parent coin class
* @param log the coin size, log base 2 of quantity
*/
public TokenDead()
{
super();
this.phase = PHASE_DEAD;
this.phaseVersion = DEAD_ORIGINAL;
this.state = TOK_DEAD;
}
/**
* 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 SOXPacketException The token data is badly formatted
*/
public TokenDead(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 SOXPacketException The token data is badly formatted
*/
public TokenDead(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);
if (phase != PHASE_DEAD)
throw new IOException("Invalid phase in token: "+
phase + " != " + PHASE_DEAD);
if (phaseVersion != DEAD_ORIGINAL)
throw new IOException("Invalid phase version in token: "+
phaseVersion + " != " + DEAD_ORIGINAL);
}
/**
* 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);
}
////// Self-Test //////////////////////////////////
public String toString()
{
String s = " state == " + state;
if (isDead())
return s;
return s;
}
}
1.1 java/webfunds/token/TokenException.java
Index: TokenException.java
===================================================================
/*
* $Id: TokenException.java,v 1.1 2001/04/01 22:25:24 iang Exp $
*
* Copyright (c) Systemics Ltd 1995-1999 on behalf of
* the WebFunds Development Team. All Rights Reserved.
*/
package webfunds.token;
/**
* This exception base class is inherited by all Token Exceptions.
* Model taken from SOXException.
*/
public class TokenException
extends Exception
{
protected int number;
public int getNumber() { return number; }
public String toString() { return "(" + number + ") " + super.toString(); }
/**
* Internal errors detected.
* Positive numbers are reserved for Token reply errors.
*/
public static final int UNKNOWN = -1,
NOT_SIGNED = -2,
LAST_ERROR = -2;
public boolean isNotSigned() { return (number == NOT_SIGNED); }
/**
* Is this in our recognised block?
* Not a complete test, there are some gaps.
*/
public static final boolean isTokenException(int errno)
{
if ( (LAST_ERROR <= errno) && (errno < -1) )
return true ;
return false ;
}
/**
* getNumber() will return 0
*/
public TokenException(String msg)
{
super(msg);
number = 0;
}
/**
* @param num is an error code, undefined here,
* extending classes to define, excepting 0 which means "it wasn't set"
*/
public TokenException(int num, String msg)
{
super(msg);
number = num;
}
}
1.1 java/webfunds/token/TokenKeyException.java
Index: TokenKeyException.java
===================================================================
/*
* $Id: TokenKeyException.java,v 1.1 2001/04/01 22:25:25 iang Exp $
*
* Copyright (c) Systemics Ltd 1995-1999 on behalf of
* the WebFunds Development Team. All Rights Reserved.
*/
package webfunds.token;
/**
* This exception class is thrown when a badly formatted
* local key is encountered.
* It is generally fatal, as indicates local keys are bad.
*
* It should not be thrown with respect to Server side.
*/
public class TokenKeyException
extends TokenException
{
public TokenKeyException(String msg) { super(UNKNOWN, msg); }
public TokenKeyException(int errno, String msg) { super(errno, msg); }
public TokenKeyException(int errno) { super(errno, ""); }
}
1.1 java/webfunds/token/TokenPacketException.java
Index: TokenPacketException.java
===================================================================
/*
* $Id: TokenPacketException.java,v 1.1 2001/04/01 22:25:25 iang Exp $
*
* Copyright (c) Systemics Ltd 1995-1999 on behalf of
* the WebFunds Development Team. All Rights Reserved.
*/
package webfunds.token;
/**
* This exception class is thrown when a badly formatted
* or unknown token is passed for decoding.
*
*/
public class TokenPacketException
extends TokenException
{
public TokenPacketException(String msg) { super(UNKNOWN, msg); }
public TokenPacketException(int errno, String msg) { super(errno, msg); }
public TokenPacketException(int errno) { super(errno, ""); }
}
1.1 java/webfunds/token/TokenSigner.java
Index: TokenSigner.java
===================================================================
/*
* $Id: TokenSigner.java,v 1.1 2001/04/01 22:25:25 iang Exp $
*
* Copyright (c) Systemics Inc 1995-2000 on behalf of
* the WebFunds Development Team. All Rights Reserved.
*/
package webfunds.token;
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.security.SecureRandom;
import webfunds.utils.Hex;
import webfunds.token.util.Log;
/**
* This class represents a proto token -- a coin before withdrawal.
*
*/
public abstract class TokenSigner
extends BaseToken
{
/**
* The version number for this structure:
* 0: current
*/
public static final int SIGNER_ORIGINAL = 0;
/**
* The state that the token is in within this phase
* (generally made by the mint according to the protocol).
* How it is set and advanced is up to the higher layers.
* May be ignored, may use the following TOK numbers.
* Only the low-order single unsigned byte is saved & restored.
*/
public static final int TOK_NEW = 0, // received
TOK_VERIFIED = 1, // user sig checked
TOK_SIGNED = 2, // now is cash
TOK_TRANS = 3; // accounted for
public boolean isNew() { return state == TOK_NEW; }
public boolean isVerified() { return state == TOK_VERIFIED; }
public boolean isSigned() { return state == TOK_SIGNED; }
public boolean isTransacted() { return state == TOK_TRANS; }
/**
* User blinds a raw coin and turns it into a Protocoin.
* Some sort of signing process involved, done internally.
*
* Normally called by mint (server), so it is standardised.
*
* @param params includes the blinding paramaters from the mint
*/
public abstract void sign(SecureRandom sr, AbstractPrivateParams params)
throws TokenKeyException;
protected void setSigned() { this.state = TOK_SIGNED; }
public void setTransacted() { this.state = TOK_TRANS; }
/**
* Create an uninitialised token.
* Call prototype() with some params to make it a real proto-token.
*
* The series is unknown until signing (mint can use a different key).
*
* @param type of token, being the blinding or coin scheme
* @param subversion is the version of the parent coin class
* @param log the coin size, log base 2 of quantity
*/
public TokenSigner()
{
super();
this.phase = PHASE_SIGNER;
this.phaseVersion = SIGNER_ORIGINAL;
this.state = TOK_NEW;
}
/**
* 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 SOXPacketException The token data is badly formatted
*/
public TokenSigner(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 SOXPacketException The token data is badly formatted
*/
public TokenSigner(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);
if (phase != PHASE_SIGNER)
throw new IOException("Invalid phase in token: "+
phase + " != " + PHASE_SIGNER);
if (phaseVersion != SIGNER_ORIGINAL)
throw new IOException("Invalid phase version in token: "+
phaseVersion + " != " + SIGNER_ORIGINAL);
}
/**
* 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);
}
////// Self-Test //////////////////////////////////
public String toString()
{
String s = " state == " + state;
s += " L: " + log + "\tQ: " + Log.log2qty(log);
return s;
}
}
1.1 java/webfunds/token/TokenSpender.java
Index: TokenSpender.java
===================================================================
/*
* $Id: TokenSpender.java,v 1.1 2001/04/01 22:25:25 iang Exp $
*
* Copyright (c) Systemics Inc 1995-2000 on behalf of
* the WebFunds Development Team. All Rights Reserved.
*/
package webfunds.token;
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.security.SecureRandom;
import webfunds.utils.Hex;
import webfunds.token.util.Log;
/**
* This class represents a valuable token -- a withdrawn coin that
* may or may not at this stage be spent.
*
*/
public abstract class TokenSpender
extends BaseToken
{
/**
* The version number for this structure:
* 0: current
*/
public static final int SPENDER_ORIGINAL = 0;
/**
* The state that the token is in within this phase
* (received, verified, spending, receipted.)
* How it is set and advanced is up to the higher layers.
* May be ignored, may use the following TOK numbers.
* Only the low-order single unsigned byte is saved & restored.
*/
public static final int TOK_START = 0, // received from mint
TOK_VERIFIED = 1, // signed by mint
TOK_SENT = 2, // seen by outsiders
TOK_CANCELLING= 3, // i spend too
TOK_RECEIPTED = 4; // receipt is in
public boolean isStart() { return state == TOK_START; }
public boolean isVerified() { return state == TOK_VERIFIED; }
public boolean isSent() { return state == TOK_SENT; }
public boolean isCancelling() { return state == TOK_CANCELLING; }
public boolean isReceipted() { return state == TOK_RECEIPTED; }
private byte[] token;
/**
* Mint returns a blinded, signed coin for Client to unblind and spend.
*
* Normally called by client (user), so it is standardised.
* How it is done is up to the individual type of token, but
* we hope we can limit it to this simple interface, as there
* are half a dozen different token crypto-schemes out there.
*
* The sub class needs to save the entire token data, even when
* spent to some place, until it is receipted.
*
* @param params includes the blinding paramaters from the mint
*/
public abstract void unblind(SecureRandom sr, byte[] token,
AbstractPublicParams params)
throws TokenKeyException;
public void unblind(byte[] token, AbstractPublicParams params)
throws TokenKeyException
{
this.state = TOK_VERIFIED;
}
public void setSent() { this.state = TOK_SENT; }
public void setCancelling() { this.state = TOK_CANCELLING; }
public void setReceipted() { this.state = TOK_RECEIPTED; }
/**
* Create an uninitialised token.
* Call prototype() with some params to make it a real proto-token.
*
* The series is unknown until signing (mint can use a different key).
*
* @param type of token, being the blinding or coin scheme
* @param subversion is the version of the parent coin class
* @param log the coin size, log base 2 of quantity
*/
public TokenSpender()
{
this.state = TOK_START;
}
/**
* 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 SOXPacketException The token data is badly formatted
*/
public TokenSpender(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 SOXPacketException The token data is badly formatted
*/
public TokenSpender(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);
if (phase != PHASE_SPEND)
throw new IOException("Invalid phase in token: "+
phase + " != " + PHASE_SPEND);
if (phaseVersion != SPENDER_ORIGINAL)
throw new IOException("Invalid phase version in token: "+
phaseVersion + " != " + SPENDER_ORIGINAL);
token = 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, token);
}
////// Self-Test //////////////////////////////////
public String toString()
{
String s = " state == " + state;
s += " L: " + log + "\tQ: " + Log.log2qty(log);
return s;
}
}
1.1 java/webfunds/token/TokenVersionException.java
Index: TokenVersionException.java
===================================================================
/*
* $Id: TokenVersionException.java,v 1.1 2001/04/01 22:25:25 iang Exp $
*
* Copyright (c) Systemics Ltd 1995-1999 on behalf of
* the WebFunds Development Team. All Rights Reserved.
*/
package webfunds.token;
/**
* This exception class is thrown when a token claims a version
* number that is unknown or unsupported.
*
*/
public class TokenVersionException
extends TokenException
{
public TokenVersionException(String msg) { super(UNKNOWN, msg); }
public TokenVersionException(int errno, String msg) { super(errno, msg); }
public TokenVersionException(int errno) { super(errno, ""); }
}