[Webfunds-commits] java/webfunds/sox AbstractPayment.java AccountId.java DepositRequest.java Payment.java PaymentFactory.java RandomToken.java Receipt.java Token.java TokenPayment.java ValueAccount.java
Ian Grigg
iang@cypherpunks.ai
Thu, 9 Nov 2000 09:13:52 -0400 (AST)
iang 00/11/09 09:13:52
Modified: webfunds/sox AbstractPayment.java AccountId.java
DepositRequest.java Payment.java
PaymentFactory.java RandomToken.java Receipt.java
Token.java TokenPayment.java ValueAccount.java
Log:
rewrote substantial parts to get it into WebFunds.
Revision Changes Path
1.2 +37 -2 java/webfunds/sox/AbstractPayment.java
Index: AbstractPayment.java
===================================================================
RCS file: /home/webfunds/cvsroot/java/webfunds/sox/AbstractPayment.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- AbstractPayment.java 2000/08/05 13:05:39 1.1
+++ AbstractPayment.java 2000/11/09 13:13:49 1.2
@@ -1,5 +1,5 @@
/*
- * $Id: AbstractPayment.java,v 1.1 2000/08/05 13:05:39 iang Exp $
+ * $Id: AbstractPayment.java,v 1.2 2000/11/09 13:13:49 iang Exp $
*
* Copyright (c) Systemics Inc 1995-2000 on behalf of
* the WebFunds Development Team. All Rights Reserved.
@@ -61,7 +61,42 @@
protected int subversion;
public int getSubVersion() { return subversion; }
+ /**
+ * Get the account from which the transaction is drawn,
+ * should be overridden for sourced payments.
+ */
+ public AccountId getSource() { return AccountId.BEARER; }
+
+ /**
+ * Get the account to which the payment is made,
+ * should be overridden for targetted payments.
+ */
+ public AccountId getTarget() { return AccountId.BEARER; }
+ public boolean isBearer() { return true; }
+
+ /**
+ * The identifer for this payment. This is used locally for
+ * storage and uniqueness, and may be used by the extending
+ * payment for idempotency, or stripped off as desired.
+ */
+ protected String paymentId;
+ /**
+ * Get the Payment Id.
+ * should be overridden for identified payments.
+ */
+ public String getId() { return paymentId; }
+
+ /**
+ * Get the date from which the payment is valid.
+ */
+ public long getValidFrom() { return 0; }
+
+ /**
+ * Get the date to which the payment is valid
+ */
+ public long getValidTill() { return Long.MAX_VALUE; }
+
/**
* The type of item (or "currency") of this payment.
@@ -78,7 +113,7 @@
public ItemId getItem() { return item; }
/**
- * The quantity of the item to be transferred between accounts
+ * The quantity of the item represented by this payment.
*/
protected long qty;
public long getQty() { return qty; }
1.20 +4 -2 java/webfunds/sox/AccountId.java
Index: AccountId.java
===================================================================
RCS file: /home/webfunds/cvsroot/java/webfunds/sox/AccountId.java,v
retrieving revision 1.19
retrieving revision 1.20
diff -u -r1.19 -r1.20
--- AccountId.java 2000/08/05 13:00:56 1.19
+++ AccountId.java 2000/11/09 13:13:50 1.20
@@ -1,4 +1,4 @@
-/* $Id: AccountId.java,v 1.19 2000/08/05 13:00:56 iang Exp $
+/* $Id: AccountId.java,v 1.20 2000/11/09 13:13:50 iang Exp $
*
* Copyright (c) Systemics Inc. 1995-2000 on behalf of
* the WebFunds Development Team. All Rights Reserved.
@@ -14,7 +14,7 @@
* This class represents an Account identifier,
* which is the standard way of referring to an account.
*
- * @version $Revision: 1.19 $
+ * @version $Revision: 1.20 $
*/
public class AccountId extends Id
{
@@ -44,6 +44,8 @@
return this.id == null || this.id.length == 0;
}
+
+ public static final AccountId BEARER = new AccountId(); // empty is bearer
public boolean equals(Object object)
{
1.26 +34 -35 java/webfunds/sox/DepositRequest.java
Index: DepositRequest.java
===================================================================
RCS file: /home/webfunds/cvsroot/java/webfunds/sox/DepositRequest.java,v
retrieving revision 1.25
retrieving revision 1.26
diff -u -r1.25 -r1.26
--- DepositRequest.java 2000/10/14 01:36:59 1.25
+++ DepositRequest.java 2000/11/09 13:13:50 1.26
@@ -1,5 +1,5 @@
/*
- * $Id: DepositRequest.java,v 1.25 2000/10/14 01:36:59 iang Exp $
+ * $Id: DepositRequest.java,v 1.26 2000/11/09 13:13:50 iang Exp $
*
* Copyright (c) Systemics Ltd 1995-1999 on behalf of
* the WebFunds Development Team. All Rights Reserved.
@@ -44,8 +44,10 @@
/**
* The payment to be deposited
* (as originally created by the payer)
+ * (was Payment).
*/
- protected Payment payment;
+ protected AbstractPayment payment;
+ protected byte[] payBuf;
/**
* An identifier for this deposit request
@@ -70,7 +72,8 @@
/**
* Get the payment to be deposited
*/
- public Payment getPayment() { return payment; }
+ public Payment getPayment() { return (Payment)payment; } // old
+ public AbstractPayment getPay() { return payment; } // v >= 3
/**
* Get the identifier on the payment, as originally created by the payer
@@ -103,13 +106,13 @@
/**
* Get the date from which the payment is valid
- */
public long getPaymentValidFrom() { return payment.getValidFrom(); }
+ */
/**
* Get the date to which the payment is valid
- */
public long getPaymentValidTill() { return payment.getValidTill(); }
+ */
/**
* Get the description on the payment
@@ -179,12 +182,22 @@
* @param depositId the deposit request identifier (must be unique)
* @param desc depositor's description of what this transaction is for
*/
- public DepositRequest(String requestId, AccountId acc, Payment payment, String depositId, byte[] desc)
+ public DepositRequest(String requestId, AccountId acc,
+ AbstractPayment payment,
+ String depositId, byte[] desc)
{
super(requestId, acc);
this.payment = payment;
this.depositId = depositId;
depositDesc = desc;
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try {
+ payment.encode(baos);
+ } catch (IOException ex) {
+ throw new IllegalArgumentException("DR pay: " + ex);
+ }
+ this.payBuf = baos.toByteArray();
}
/**
@@ -236,28 +249,21 @@
DataOutputStream dos = new DataOutputStream(os);
super.encode(dos);
-// will I need this???
-// encode_payload(dos);
-// }
-//
-// protected void encode_payload(DecodeOutputStream dos)
-// throws IOException
-// {
-// /* DataOutputStream dos = new DataOutputStream(os); ??? */
-
- // New! for version == 2 && super.version == 3
+ // New for version == 2 && super.version == 3
if (req_version >= REQ_SUBS_ADD_V)
dos.writeByte(version);
- payment.encode(dos);
- writeString(dos, depositId);
- writeByteArray(dos, depositDesc);
-
if (version >= DEPOSIT_WITHDRAW) // New! I can jump technologies...
{
dos.writeByte(typeOfPayment);
dos.writeByte(protocolState);
+ writeByteArray(dos, payBuf);
}
+ else
+ payment.encode(dos);
+
+ writeString(dos, depositId);
+ writeByteArray(dos, depositDesc);
}
@@ -276,15 +282,6 @@
DataInputStream dis = new DataInputStream(is);
super.decode(dis);
-// will I need this???
-// decode_payload(dis);
-// }
-//
-// protected void decode_payload(DataInputStream is)
-// throws IOException, SOXPacketException
-// {
-// /* DataInputStream dis = new DataInputStream(is); ??? */
-
/*
* the problem here being that all receipts include the
* deposit, which will need to be recovered, as long as
@@ -294,22 +291,24 @@
if (req_version >= REQ_SUBS_ADD_V) // parent, adds my version num
{
v = dis.readUnsignedByte();
- if (! ((DEPOSIT_LOCAL_VERS <= v) && (v <=DEPOSIT_WITHDRAW)) )
+ if (! ((DEPOSIT_LOCAL_VERS <= v) && (v <= DEPOSIT_WITHDRAW)) )
throw new SOXPacketException("Invalid version in DepositR:" +
v + " != {"+DEPOSIT_LOCAL_VERS+","+DEPOSIT_WITHDRAW+"}");
version = v; // remember this for sig checks
}
- payment = new Payment(dis);
- depositId = readString(dis);
-
- depositDesc = readByteArray(dis);
-
if (version >= DEPOSIT_WITHDRAW) // New! I can jump technologies...
{
typeOfPayment = dis.readUnsignedByte();
protocolState = dis.readUnsignedByte();
+ payBuf = readByteArray(dis);
+ payment = PaymentFactory.decode(payBuf);
}
+ else
+ payment = new Payment(dis);
+
+ depositId = readString(dis);
+ depositDesc = readByteArray(dis);
}
public String toAscii()
1.24 +4 -4 java/webfunds/sox/Payment.java
Index: Payment.java
===================================================================
RCS file: /home/webfunds/cvsroot/java/webfunds/sox/Payment.java,v
retrieving revision 1.23
retrieving revision 1.24
diff -u -r1.23 -r1.24
--- Payment.java 2000/10/14 01:28:11 1.23
+++ Payment.java 2000/11/09 13:13:50 1.24
@@ -1,5 +1,5 @@
/*
- * $Id: Payment.java,v 1.23 2000/10/14 01:28:11 iang Exp $
+ * $Id: Payment.java,v 1.24 2000/11/09 13:13:50 iang Exp $
*
* Copyright (c) Systemics Inc 1995-2000 on behalf of
* the WebFunds Development Team. All Rights Reserved.
@@ -55,9 +55,9 @@
/**
- * The identifer for this payment
- */
+ * The identifer for this payment - now in AbstractPayment.
protected String paymentId;
+ */
/**
* The account from which the payment is drawn
@@ -100,8 +100,8 @@
* excluding six magic characters:
*
* -|:{}#
- */
public String getId() { return paymentId; }
+ */
/**
* Get the account from which the transaction is drawn
1.5 +115 -1 java/webfunds/sox/PaymentFactory.java
Index: PaymentFactory.java
===================================================================
RCS file: /home/webfunds/cvsroot/java/webfunds/sox/PaymentFactory.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- PaymentFactory.java 2000/10/14 01:28:48 1.4
+++ PaymentFactory.java 2000/11/09 13:13:50 1.5
@@ -1,4 +1,4 @@
-/* $Id: PaymentFactory.java,v 1.4 2000/10/14 01:28:48 iang Exp $
+/* $Id: PaymentFactory.java,v 1.5 2000/11/09 13:13:50 iang Exp $
*
* Copyright (c) Systemics Inc. 1995-2000 on behalf of
* The WebFunds Development Team. All Rights Reserved.
@@ -98,4 +98,118 @@
}
return typeNames[type] + " (" + type + ")";
}
+
+
+ /**
+ * @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;
+ }
+
+ 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.2 +190 -25 java/webfunds/sox/RandomToken.java
Index: RandomToken.java
===================================================================
RCS file: /home/webfunds/cvsroot/java/webfunds/sox/RandomToken.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- RandomToken.java 2000/08/05 13:05:39 1.1
+++ RandomToken.java 2000/11/09 13:13:50 1.2
@@ -1,5 +1,5 @@
/*
- * $Id: RandomToken.java,v 1.1 2000/08/05 13:05:39 iang Exp $
+ * $Id: RandomToken.java,v 1.2 2000/11/09 13:13:50 iang Exp $
*
* Copyright (c) Systemics Inc 1995-2000 on behalf of
* the WebFunds Development Team. All Rights Reserved.
@@ -10,7 +10,16 @@
import java.io.OutputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.KeyException;
+import java.security.SecureRandom;
+
+import webfunds.utils.Hex;
+
/**
* This class represents a Big Random Number Token.
*
@@ -32,27 +41,50 @@
/**
* The type of token encoded by this class.
+ */
+ public static final int RANDOM_TYPE = PaymentFactory.RANDOM_TOKEN;
+
+
+
+ /**
+ * The signature on the token (generally made by the mint).
+ * How it is made and verified is coded within the crypto-system
+ * as found in sign().
+ */
+ protected byte[] sig;
+ /**
+ * @return the signature on the token (never null)
*/
- public static final int RANDOM_TYPE = 1;
+ public byte[] getSignature() { return sig; }
+ /**
+ * The token payload (generally made by the client).
+ * How it is made and verified is coded within the crypto-scheme
+ * as found in prototype().
+ */
+ protected byte[] token;
+ /**
+ * @return the token payload (never null)
+ */
+ public byte[] getPayload() { return token; }
+
+
+
/**
* Create a RandomToken
*
- * @param byte[] random big random number (cannot be null)
- * @param qty is the amount (of unit of account) this token represents
- * @param expiry the Java time when this (batch) expires
+ * @param log the coin size, log base 2 of quantity
*/
- public RandomToken(byte[] random, long qty, long expiry)
+ public RandomToken(int log)
{
- super(RANDOM_TYPE, SUB_VERSION, qty, expiry);
+ super(RANDOM_TYPE, SUB_VERSION, log);
- setPayload(random);
- if (random.length > 0)
- setState(TOK_VALID);
+ this.sig = this.token = new byte[0];
}
+
public RandomToken(byte[] paymentData)
throws SOXPacketException
{
@@ -67,6 +99,92 @@
/**
+ * Make a set of Tokens that can handle a quantity.
+ * Simply calls qty2coins() then uses those sizes.
+ */
+ public static Token[] getProtoTokens(long qty)
+ {
+ return getProtoTokens( PaymentFactory.qty2coins(qty) );
+ }
+
+ /**
+ * Make a set of Tokens matched to a set of coin sizes.
+ */
+ public static Token[] getProtoTokens(int[] coins)
+ {
+ int len = coins.length;
+ Token[] tokens = new Token[len];
+
+ for (int i = 0; i < len; i++)
+ {
+ int size = coins[i]; // log size of this coin
+ RandomToken token = new RandomToken(size);
+ token.prototype(); // set up the random stuff
+ tokens[i] = token;
+ }
+ return tokens;
+ }
+
+
+
+///////// Phases //////////////////////////////////////////////
+
+ public void sign(PrivateKey key, long expiry)
+ throws KeyException
+ {
+ this.expiry = expiry;
+ sig = Crypto.sign(key, token);
+ state = TOK_SIGNED;
+ }
+
+ private void cheatSign(long expiry) // for example(), no key needed
+ {
+ this.expiry = expiry;
+ sig = Utils.exampleData(20);
+ state = TOK_SIGNED;
+ }
+
+ public boolean verify(PublicKey key)
+ throws KeyException
+ {
+ return Crypto.verify(key, token, sig);
+ }
+
+
+
+ /**
+ * Create the prototype coin.
+ * Normally called by client, no standard paramaters.
+ */
+ public void prototype()
+ {
+ SecureRandom sr = Crypto.getSecureRandom();
+ token = new byte[20]; // SHA1 sized, whatever
+ sr.nextBytes(token);
+ state = TOK_PROTO;
+ }
+
+ private void cheatProto() // for example(), quicker
+ {
+ token = Utils.exampleData(20);
+ state = TOK_PROTO;
+ }
+
+ /**
+ * Unblind the signed coin, revealing the signed, private coin.
+ * Normally called by client, no standard paramaters.
+ */
+ public void unblind()
+ {
+ state = TOK_UNBLIND;
+ }
+
+
+
+
+///////// Wire //////////////////////////////////////////////
+
+ /**
* Update this payment object with the values from
* a payment encoded as a byte array (such as previously
* returned from the encode() method of a payment object).
@@ -79,16 +197,22 @@
public void decode(InputStream is)
throws IOException, SOXPacketException
{
- super.decode(is);
+ DataInputStream dis = new DataInputStream(is);
+ super.decode(dis);
+
if (subversion != SUB_VERSION)
throw new SOXPacketException("Invalid subversion in token: "+
subversion + " != " + SUB_VERSION);
if (type != RANDOM_TYPE)
throw new SOXPacketException("not RandomToken (" +subversion+ ")");
+
+ // we have to save expiry if we want it
+ expiry = dis.readLong();
- /* nothing to add */
+ sig = readByteArray(dis); // always returns array
+ token = readByteArray(dis);
}
/**
@@ -102,9 +226,14 @@
public void encode(OutputStream os)
throws IOException
{
- super.encode(os);
+ DataOutputStream dos = new DataOutputStream(os);
- /* nothing to add */
+ super.encode(dos);
+
+ dos.writeLong(expiry);
+
+ writeByteArray(dos, sig);
+ writeByteArray(dos, token);
}
@@ -113,32 +242,68 @@
public String toString()
{
- return "RandomToken " + vString() + " T" + type + ": " + super.toString();
+ String s = "RandomToken " + vString() + " T" + type + ":\n";
+ s += super.toString();
+ if (isRaw())
+ return s;
+ s += "\n tok: " + Hex.data2hex(token);
+ if (isProto())
+ return s;
+ s += "\n sig: " + Hex.data2hex(sig) +"\n";
+ return s;
}
public static RandomToken example()
{
byte b = Utils.exampleByte();
- long expiry = Utils.exampleLong(); // might be expired
+ if (b < 0)
+ b = (byte)-b;
+ byte log = (byte) (b % 64);
- long qty = Utils.exampleLong();
- if (qty < 0)
- qty = -qty;
-
byte[] random;
random = Utils.exampleData();
RandomToken obj;
- obj = new RandomToken(random, expiry, qty);
+ obj = new RandomToken(log); // in TOK_RAW state
+ b = Utils.exampleByte();
/* initialised in TOK_VALID */
- if ((b & 0x30) == 0x30)
- obj.setState(TOK_SPENT);
- else if ((b & 0xB0) == 0xB0)
- obj.setState(TOK_PROTO);
+ if ((b & 0x3) >= 1)
+ {
+ obj.cheatProto();
+ }
+
+ if ((b & 0x3) >= 2)
+ {
+ long expiry = Utils.exampleLong(); // might be expired
+ if (expiry < 0)
+ expiry = -expiry;
+ obj.cheatSign(expiry);
+ }
+
+ if ((b & 0x3) >= 2)
+ obj.setState(b & 0x7);
return obj;
}
+
+ public boolean equals(java.lang.Object obj)
+ {
+ if (obj == null || !super.equals(obj))
+ return false;
+ if (!(obj instanceof RandomToken))
+ return false;
+
+ RandomToken other = (RandomToken)obj;
+
+ if (!Utils.byteEquals(sig, other.getSignature()))
+ return false ;
+ if (!Utils.byteEquals(token, other.getPayload()))
+ return false ;
+
+ return true;
+ }
+
public static void main(String[] args)
{
1.41 +33 -20 java/webfunds/sox/Receipt.java
Index: Receipt.java
===================================================================
RCS file: /home/webfunds/cvsroot/java/webfunds/sox/Receipt.java,v
retrieving revision 1.40
retrieving revision 1.41
diff -u -r1.40 -r1.41
--- Receipt.java 2000/10/14 01:31:06 1.40
+++ Receipt.java 2000/11/09 13:13:50 1.41
@@ -1,5 +1,5 @@
/*
- * $Id: Receipt.java,v 1.40 2000/10/14 01:31:06 iang Exp $
+ * $Id: Receipt.java,v 1.41 2000/11/09 13:13:50 iang Exp $
*
* Copyright (c) Systemics Ltd 1995-1999 on behalf of
* the WebFunds Development Team. All Rights Reserved.
@@ -44,8 +44,8 @@
protected DepositRequest depositRequest;
protected byte[] depositRequestData;
- protected AbstractPayment protoPayment;
- protected byte[] protoPaymentData;
+ protected AbstractPayment exPayment;
+ protected byte[] exPaymentData;
protected ItemId item;
protected long qty;
@@ -76,12 +76,20 @@
public Payment getPayment() { return depositRequest.getPayment(); }
/**
- * Get the Proto-Payment if the original request was a WithdrawalRequest.
+ * Get the Payment that was deposited.
*/
- public AbstractPayment getProtoPayment() { return protoPayment; }
- public void setProtoPayment(AbstractPayment p) { protoPayment = p; }
+ public AbstractPayment getPay() { return depositRequest.getPay(); }
/**
+ * Get the Exchange Payment if the original request
+ * was a WithdrawalRequest. This will be a proto
+ * payment to start off with, and the mint will
+ * replace it with a signed payment.
+ */
+ public AbstractPayment getExchangePayment() { return exPayment; }
+ public void setExchangePayment(AbstractPayment p) { exPayment = p; }
+
+ /**
* Get the DepositRequest object that was used to deposit the payment
*
* The DepositRequest is the signed object
@@ -276,8 +284,10 @@
// Unix backends truncate the time.
// The result is a timestamp that is seconds multiplied by a 1000.
//
- long from = req.getPaymentValidFrom() - 999;
- long till = req.getPaymentValidTill();
+ AbstractPayment p = req.getPay();
+ long from = p.getValidFrom() / 1000;
+ from *= 1000;
+ long till = p.getValidTill();
long time = getTimestamp();
if ( ! (from < time && time < till) &&
@@ -287,8 +297,8 @@
" not in "+from+","+till);
}
- protoPayment = null;
- protoPaymentData = null;
+ exPayment = null;
+ exPaymentData = null;
flags = 0;
}
@@ -307,10 +317,10 @@
public Receipt(byte[] receiptData)
throws SOXPacketException
{
- PrintWriter temp = debug;
- debug = null;
+// PrintWriter temp = debug;
+// debug = null;
decode(receiptData);
- debug = temp;
+// debug = temp;
}
/**
@@ -424,8 +434,8 @@
flags = dis.readLong();
//
- // Perl code shoves a one byte Message Digest Type in front of hashes.
- // See OpenPGP for the types.
+ // Perl code shoves a one byte (OpenPGP) Message Digest Type
+ // in front of hashes.
//
int hash_type = dis.readUnsignedByte();
if (MD_SHA1 != hash_type)
@@ -455,8 +465,8 @@
if (version >= RECEIPT_PROTO && isWithdrawalReceipt())
{
- protoPaymentData = readByteArray(dis);
- protoPayment = new Payment(protoPaymentData);
+ exPaymentData = readByteArray(dis);
+ exPayment = new Payment(exPaymentData);
}
sig = readByteArray(dis);
@@ -552,7 +562,7 @@
// written as array, as original might vary on encode()
writeByteArray(dos, depositRequestData);
if (version >= RECEIPT_PROTO && isWithdrawalReceipt())
- writeByteArray(dos, protoPaymentData);
+ writeByteArray(dos, exPaymentData);
}
/**
@@ -622,9 +632,12 @@
DepositRequest req = DepositRequest.example();
//System.err.println("Payment: " + req.getPayment());
+
+ AbstractPayment p = req.getPay();
+ long from = p.getValidFrom() / 1000;
+ from *= 1000;
+ long till = p.getValidTill();
- long from = req.getPaymentValidFrom() - 999;
- long till = req.getPaymentValidTill();
long relTime = Utils.exampleLong();
if (relTime < 0) relTime = -relTime;
relTime = relTime % (till - from);
1.2 +92 -48 java/webfunds/sox/Token.java
Index: Token.java
===================================================================
RCS file: /home/webfunds/cvsroot/java/webfunds/sox/Token.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- Token.java 2000/08/05 13:05:39 1.1
+++ Token.java 2000/11/09 13:13:50 1.2
@@ -1,5 +1,5 @@
/*
- * $Id: Token.java,v 1.1 2000/08/05 13:05:39 iang Exp $
+ * $Id: Token.java,v 1.2 2000/11/09 13:13:50 iang Exp $
*
* Copyright (c) Systemics Inc 1995-2000 on behalf of
* the WebFunds Development Team. All Rights Reserved.
@@ -13,7 +13,9 @@
import java.io.OutputStream;
import java.io.DataOutputStream;
-// import java.security.PublicKey;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.KeyException;
import webfunds.utils.Hex;
@@ -67,16 +69,42 @@
public int getState() { return state; }
public void setState(int state) { this.state = state; }
- public static final int TOK_PROTO = 0,
- TOK_VALID = 1,
- TOK_SIGNED = 2,
- TOK_BLIND = 3,
- TOK_SPENT = 4;
+ public static final int TOK_RAW = 0, // empty, valueless
+ TOK_PROTO = 1, // clean, valueless
+ TOK_SIGNED = 2, // by mint, has value
+ TOK_UNBLIND = 3, // untraceable form
+
+ TOK_RECEIVED = 4, // spent to me
+ TOK_SPENT = 5, // spent to other
+ TOK_SETTLED = 6, // complete
+
+ TOK_VALID = 10; // mint wants to sign
+
+ public boolean isRaw() { return state == TOK_RAW; }
+ public boolean isProto() { return state == TOK_PROTO; }
+ public boolean isSigned() { return state == TOK_SIGNED; }
+ public boolean isUnblinded() { return state == TOK_UNBLIND; }
+ public boolean isReceived() { return state == TOK_RECEIVED; }
+ public boolean isSpent() { return state == TOK_SPENT; }
+ public boolean isSettled() { return state == TOK_SETTLED; }
/**
* 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 long qty;
+ protected int log;
+ public long getLog() { return log; }
+
/**
* Note (1) that this may be derived information, the real
* token value may be encoded in the signature key or
@@ -86,9 +114,11 @@
* 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.
+ * @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 qty; }
+ public long getQty() { return PaymentFactory.log2qty(log); }
/**
* Tokens commonly come from a batch with a defined expiry date.
@@ -102,21 +132,21 @@
* (generally made by the mint according to the protocol).
* How it is made and verified is up to the higher layers.
* May be ignored (for technical reasons, cannot be null).
- */
protected byte[] token;
+ */
/**
* @return the token payload (never null)
- */
public byte[] getPayload() { return token; }
+ */
/**
* @param a new payload for this token (null becomes empty array)
- */
public void setPayload(byte[] b)
{
if (b == null)
b = new byte[0];
this.token = b;
}
+ */
/**
* The signature on the token
@@ -131,40 +161,66 @@
public byte[] getSignature() { return sig; }
/**
* @param a new signature on this token (null becomes empty array)
- */
public void setSignature(byte[] sig)
{
if (sig == null)
sig = new byte[0];
this.sig = sig;
}
+ */
+
/**
* Check to see if this token is signed.
* NOTE: This does not check the validity of the signature,
* only that this token has one.
* @return boolean true if this token has a signature
- */
public boolean isSigned() { return (sig.length > 0); }
+ */
+ /**
+ * Sign a protocoin.
+ * Normally called by server (mint), 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.
+ *
+ * @param expiry the Java time when this (batch) expires
+ * @param key is the signing key of the mint
+ */
+ public abstract void sign(PrivateKey key, long expiry)
+ throws KeyException;
+ /**
+ * Sign a protocoin.
+ * Normally called by client to check the coin is signed,
+ * matched pair with sign() so it can be a standardised call.
+ *
+ * @param key is the signer's public key (of the mint)
+ */
+ public abstract boolean verify(PublicKey key)
+ throws KeyException;
+
+
+
/**
- * Create an unsigned token.
+ * Create an uninitialised token.
+ * Call prototype() with some params to make it a real proto-token.
*
- * @param desc a description of what this token is for (optional)
- * @param qty the number of items of which the token is for
- * @param expiry the Java time till which the token is valid
+ * @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 Token(int type, int subversion, long qty, long expiry)
+ public Token(int type, int subversion, int log)
{
this.type = type;
this.subversion = subversion;
- this.qty = qty;
- this.expiry = expiry;
+ this.log = log;
- this.state = TOK_PROTO;
+ this.expiry = 0;
+ this.state = TOK_RAW;
- this.sig = this.token = new byte[0];
+ // this.sig = this.token = new byte[0];
}
/**
@@ -175,10 +231,10 @@
* @param token the previously encoded token
* @excep SOXPacketException The token data is badly formatted
*/
- public Token(byte[] token)
+ public Token(byte[] buf)
throws SOXPacketException
{
- decode(token);
+ decode(buf);
}
/**
@@ -234,11 +290,7 @@
state = dis.readUnsignedByte();
- qty = dis.readLong();
- expiry = dis.readLong();
-
- sig = readByteArray(dis); // always returns array
- token = readByteArray(dis);
+ log = dis.readUnsignedByte();
}
@@ -259,11 +311,7 @@
dos.writeByte(subversion);
dos.writeByte(state);
- dos.writeLong(qty);
- dos.writeLong(expiry);
-
- writeByteArray(dos, sig);
- writeByteArray(dos, token);
+ dos.writeByte(log);
}
@@ -272,12 +320,13 @@
public String toString()
{
- String s = ""; /* does not say what object, leave to subclass */
-
- s += " Q: " + qty;
- s += " exp: " + expiry + "\n";
- s += " sig: " + Hex.data2hex(sig) +"\n";
- s += " tok: " + Hex.data2hex(token) +"\n";
+ String s = " state == " + state;
+ if (isRaw())
+ return s;
+ s += " L: " + log + "\tQ: " + PaymentFactory.log2qty(log);
+ if (isProto())
+ return s;
+ s += " exp: " + expiry + "\n";
return s;
}
@@ -296,15 +345,10 @@
if (other.state != state)
return false;
- if (other.qty != qty)
+ if (other.log != log)
return false;
if (other.expiry != expiry)
return false;
-
- if (!Utils.byteEquals(sig, other.getSignature()))
- return false ;
- if (!Utils.byteEquals(token, other.getPayload()))
- return false ;
return true;
}
1.2 +25 -13 java/webfunds/sox/TokenPayment.java
Index: TokenPayment.java
===================================================================
RCS file: /home/webfunds/cvsroot/java/webfunds/sox/TokenPayment.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- TokenPayment.java 2000/08/05 13:05:39 1.1
+++ TokenPayment.java 2000/11/09 13:13:50 1.2
@@ -1,5 +1,5 @@
/*
- * $Id: TokenPayment.java,v 1.1 2000/08/05 13:05:39 iang Exp $
+ * $Id: TokenPayment.java,v 1.2 2000/11/09 13:13:50 iang Exp $
*
* Copyright (c) Systemics Inc 1995-2000 on behalf of
* the WebFunds Development Team. All Rights Reserved.
@@ -51,20 +51,20 @@
/**
* The account from which the payment was drawn.
* This is meaningless in a token concept, just here for
- * informational purposes.
+ * informational purposes. A client would probably strip
+ * this on sending it out.
*/
protected AccountId source;
/** Get the account from which the transaction is drawn */
- public AccountId getSource() { return source; }
+ public AccountId getSource() { return source; }
+ public void setSource(AccountId id) { source = id; }
- /**
- * The account to which the payment is made out.
- * This is meaningless in a token concept, just here for
- * informational purposes.
- */
- public AccountId getTarget() { return new AccountId(); }
- /** @return true if the payment is made out to BEARER (always true) */
+ /*
+ * The account to which the payment is made out is always BEARER,
+ * so AbstractPayment covers that fine.
+ public AccountId getTarget() { return AccountId.BEARER; }
public boolean isBearer() { return true; }
+ */
/**
* List of Tokens.
@@ -73,6 +73,10 @@
/** Get the tokens within the payment */
public Token[] getTokens() { return tokens; }
+ /**
+ * Set the paymentId, so that you can strip it clean on export.
+ */
+ public void setId(String id) { paymentId = id; }
/**
@@ -85,17 +89,22 @@
* The items is indicated so that a pointer to a valid SOXServer
* can be determined at the receiving end.
*
+ * Validity times are ignored here, although real token systems
+ * do have times involved.
+ *
* @param source the source account, can be empty / null
* @param item the item for which the payment is for
* @param desc a description of what this payment is for (null ==> empty)
* @param tokens an array of tokens, cannot be null or contain nulls,
* may be empty
+ * @param pid identifier for local storage only
*/
public TokenPayment(
+ String pid,
AccountId source,
ItemId item,
- byte[] desc,
- Token[] tokens
+ Token[] tokens,
+ byte[] desc
)
{
super(PF_VERSION, TOKEN_TYPE, TOKEN_VERSION, item, 0, desc);
@@ -107,6 +116,8 @@
source = new AccountId();
this.source = source;
+ this.paymentId = pid;
+
this.tokens = tokens;
if (tokens == null)
@@ -294,6 +305,7 @@
byte[] desc = Utils.exampleData();
if ((b & 0xF0) == 0xF0)
desc = null;
+ String pid = Utils.exampleString();
AccountId ac = AccountId.example();
if ((b & 0xD0) == 0xD0)
@@ -307,7 +319,7 @@
tokens[i] = RandomToken.example();
TokenPayment obj;
- obj = new TokenPayment(ac, item, desc, tokens);
+ obj = new TokenPayment(pid, ac, item, tokens, desc);
return obj;
}
1.21 +45 -10 java/webfunds/sox/ValueAccount.java
Index: ValueAccount.java
===================================================================
RCS file: /home/webfunds/cvsroot/java/webfunds/sox/ValueAccount.java,v
retrieving revision 1.20
retrieving revision 1.21
diff -u -r1.20 -r1.21
--- ValueAccount.java 2000/10/14 01:50:45 1.20
+++ ValueAccount.java 2000/11/09 13:13:50 1.21
@@ -1,5 +1,5 @@
/*
- * $Id: ValueAccount.java,v 1.20 2000/10/14 01:50:45 iang Exp $
+ * $Id: ValueAccount.java,v 1.21 2000/11/09 13:13:50 iang Exp $
*
* Copyright (c) Systemics Ltd 1995-1999 on behalf of
* the WebFunds Development Team. All Rights Reserved.
@@ -409,21 +409,27 @@
}
/**
- * Create a rollover. This causes all funds to transfer to the
- * target and the source to *FROZEN* .... Not working yet!
+ * No real need for this, let caller do it directly?
*
- * @param target the target account where all funds end up for all subs
- * @param qty the number of items of which the payment is for
- * @param desc a description of what this payment is for (optional)
- * @param validity the payment is valid for validity seconds (from now)
- */
- public Payment createRollover(AccountId target, byte[] desc, long validity)
+ * Create a rollover payment. This causes all funds to transfer to the
+ * target and the source to be *FROZEN* at the issuer ....
+ * Not working yet!
+ *
+ * We don't use the word freeze because accounts also get frozen
+ * here.
+ *
+ * @param target the target account where all funds end up for all subs
+ * @param qty the number of items of which the payment is for
+ * @param desc a description of what this payment is for (optional)
+ * @param validity the payment is valid for validity seconds (from now)
+ public Payment createRollover(AccountId target, byte[] desc, long validTill)
throws SOXSubAccountException
{
long now = System.currentTimeMillis();
long validTill = now + validity*1000;
return createPayment(target, 0, desc, true, now, validTill, null);
}
+ */
/**
* Create a payment, with all params specified.
@@ -435,7 +441,9 @@
* @param from the time from which the payment is valid
* @param till the time at which the payment will expire
* @param pid a unique payment identifier, replaced if empty
- */
+
+What is the point of a Date Conversion method? Make the caller do that.
+
public Payment createPayment(AccountId target, long qty, byte[] desc,
boolean changekey, Date from, Date till,
String pid)
@@ -467,6 +475,7 @@
logmsg("PAYMENT IS SIGNED: " + signed);
return payment;
}
+ */
/**
* Create a payment, with all params specified.
@@ -508,6 +517,32 @@
boolean signed = payment.verify(acct.getPublicKey());
logmsg("PAYMENT IS SIGNED: " + signed);
+ return payment;
+ }
+
+ /**
+ * Create a proto token payment.
+ * A little different to normal payments, as there are
+ * no special needs like signing, so this call is not needed.
+ *
+ * @param tokens the individual tokens or coins that need withdrawing
+ * @param desc a description of what this payment is for (optional)
+ * @param pid a unique payment identifier, replaced if empty
+ */
+ public TokenPayment createTokenPayment(Token[] tokens,
+ byte[] desc,
+ String pid)
+ throws SOXSubAccountException
+ {
+ checkFrozen("createTokenPayment");
+
+ if (pid == null || pid.length() == 0)
+ pid = "P" + System.currentTimeMillis();
+
+ TokenPayment payment = new TokenPayment(pid, acct.getId(),
+ itemId, tokens,
+ desc);
+
return payment;
}