<commit_before>package ch.uzh.csg.paymentlib.paymentrequest;

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;

import ch.uzh.csg.nfclib.util.Utils;
import ch.uzh.csg.paymentlib.exceptions.IllegalArgumentException;
import ch.uzh.csg.paymentlib.exceptions.NotSignedException;

//TODO: javadoc
public class PaymentRequest {
	private int version;
	private SignatureAlgorithm signatureAlgorithm;
	
	private String usernamePayer;
	private String usernamePayee;
	
	private Currency currency;
	private long amount;
	private long timestamp;
	private int keyNumber;
	
	/*
	 * payload and signature are not serialized but only hold references in
	 * order to save cpu time
	 */
	private byte[] payload;
	private byte[] signature;
	
	private PaymentRequest() {
	}
	
	public PaymentRequest(SignatureAlgorithm signatureAlgorithm, String usernamePayer, String usernamePayee, Currency currency, long amount, long timestamp, int keyNumber) throws IllegalArgumentException, UnsupportedEncodingException {
		this(1, signatureAlgorithm, usernamePayer, usernamePayee, currency, amount, timestamp, keyNumber);
	}
	
	protected PaymentRequest(int version, SignatureAlgorithm signatureAlgorithm, String usernamePayer, String usernamePayee, Currency currency, long amount, long timestamp, int keyNumber) throws IllegalArgumentException, UnsupportedEncodingException {
		checkParameters(version, signatureAlgorithm, usernamePayer, usernamePayee, currency, amount, timestamp, keyNumber);
		
		this.version = version;
		this.signatureAlgorithm = signatureAlgorithm;
		this.usernamePayer = usernamePayer;
		this.usernamePayee = usernamePayee;
		this.currency = currency;
		this.amount = amount;
		this.timestamp = timestamp;
		this.keyNumber = keyNumber;
		
		setPayload();
	}

	private void checkParameters(int version, SignatureAlgorithm signatureAlgorithm, String usernamePayer, String usernamePayee, Currency currency, long amount, long timestamp, int keyNumber) throws IllegalArgumentException {
		if (version <= 0 || version > 255)
			throw new IllegalArgumentException("The version number must be between 1 and 255.");
		
		if (signatureAlgorithm == null)
			throw new IllegalArgumentException("The signature algorithm cannot be null.");
		
		if (usernamePayer == null || usernamePayer.length() == 0 || usernamePayer.length() > 255)
			throw new IllegalArgumentException("The payers's username cannot be null, empty, or longer than 255 characters.");
		
		if (usernamePayee == null || usernamePayee.length() == 0 || usernamePayee.length() > 255)
			throw new IllegalArgumentException("The payee's username cannot be null, empty, or longer than 255 characters.");
		
		if (currency == null)
			throw new IllegalArgumentException("The currency cannot be null.");
		
		if (amount <= 0)
			throw new IllegalArgumentException("The amount must be greatern than 0.");
		
		if (timestamp <= 0)
			throw new IllegalArgumentException("The timestamp must be greatern than 0.");
		
		if (keyNumber <= 0 || keyNumber > 255)
			throw new IllegalArgumentException("The key number must be between 1 and 255.");
	}
	
	private void setPayload() throws UnsupportedEncodingException {
		byte[] usernamePayerBytes = usernamePayer.getBytes("UTF-8");
		byte[] usernamePayeeBytes = usernamePayee.getBytes("UTF-8");
		byte[] amountBytes = Utils.getLongAsBytes(amount);
		byte[] timestampBytes = Utils.getLongAsBytes(timestamp);
		
		int length = 1+1+1+usernamePayerBytes.length+1+usernamePayeeBytes.length+1+8+8+1;
		byte[] payload = new byte[length];
		
		int index = 0;
		
		payload[index++] = (byte) version;
		payload[index++] = signatureAlgorithm.getCode();
		payload[index++] = (byte) usernamePayerBytes.length;
		for (byte b : usernamePayerBytes) {
			payload[index++] = b;
		}
		payload[index++] = (byte) usernamePayeeBytes.length;
		for (byte b : usernamePayeeBytes) {
			payload[index++] = b;
		}
		payload[index++] = currency.getCode();
		for (byte b : amountBytes) {
			payload[index++] = b;
		}
		for (byte b : timestampBytes) {
			payload[index++] = b;
		}
		payload[index++] = (byte) keyNumber;
		
		this.payload = payload;
	}
	
	protected int getVersion() {
		return version;
	}

	protected SignatureAlgorithm getSignatureAlgorithm() {
		return signatureAlgorithm;
	}

	protected String getUsernamePayer() {
		return usernamePayer;
	}

	protected String getUsernamePayee() {
		return usernamePayee;
	}

	protected Currency getCurrency() {
		return currency;
	}

	protected long getAmount() {
		return amount;
	}

	protected long getTimestamp() {
		return timestamp;
	}

	protected int getKeyNumber() {
		return keyNumber;
	}
	
	protected byte[] getPayload() {
		return payload;
	}
	
	protected byte[] getSignature() throws NotSignedException {
		if (signature == null)
			throw new NotSignedException();
		
		return signature;
	}
	
	public void sign(PrivateKey privateKey) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException, UnsupportedEncodingException {
		Signature sig = Signature.getInstance(signatureAlgorithm.getSignatureAlgorithm());
		sig.initSign(privateKey);
		sig.update(payload);
		signature = sig.sign();
	}
	
	public boolean verify(PublicKey publicKey) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException, NotSignedException {
		if (signature == null)
			throw new NotSignedException();
		
		Signature sig = Signature.getInstance(signatureAlgorithm.getSignatureAlgorithm());
		sig.initVerify(publicKey);
		sig.update(this.payload);<commit_msg>Added encoding comment to PaymentRequest.<commit_after>package ch.uzh.csg.paymentlib.paymentrequest;

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;

import ch.uzh.csg.nfclib.util.Utils;
import ch.uzh.csg.paymentlib.exceptions.IllegalArgumentException;
import ch.uzh.csg.paymentlib.exceptions.NotSignedException;

//TODO: javadoc
public class PaymentRequest {
	private int version;
	private SignatureAlgorithm signatureAlgorithm;
	
	private String usernamePayer;
	private String usernamePayee;
	
	private Currency currency;
	private long amount;
	private long timestamp;
	private int keyNumber;
	
	/*
	 * payload and signature are not serialized but only hold references in
	 * order to save cpu time
	 */
	private byte[] payload;
	private byte[] signature;
	
	private PaymentRequest() {
	}
	
	public PaymentRequest(SignatureAlgorithm signatureAlgorithm, String usernamePayer, String usernamePayee, Currency currency, long amount, long timestamp, int keyNumber) throws IllegalArgumentException, UnsupportedEncodingException {
		this(1, signatureAlgorithm, usernamePayer, usernamePayee, currency, amount, timestamp, keyNumber);
	}
	
	protected PaymentRequest(int version, SignatureAlgorithm signatureAlgorithm, String usernamePayer, String usernamePayee, Currency currency, long amount, long timestamp, int keyNumber) throws IllegalArgumentException, UnsupportedEncodingException {
		checkParameters(version, signatureAlgorithm, usernamePayer, usernamePayee, currency, amount, timestamp, keyNumber);
		
		this.version = version;
		this.signatureAlgorithm = signatureAlgorithm;
		this.usernamePayer = usernamePayer;
		this.usernamePayee = usernamePayee;
		this.currency = currency;
		this.amount = amount;
		this.timestamp = timestamp;
		this.keyNumber = keyNumber;
		
		setPayload();
	}

	private void checkParameters(int version, SignatureAlgorithm signatureAlgorithm, String usernamePayer, String usernamePayee, Currency currency, long amount, long timestamp, int keyNumber) throws IllegalArgumentException {
		if (version <= 0 || version > 255)
			throw new IllegalArgumentException("The version number must be between 1 and 255.");
		
		if (signatureAlgorithm == null)
			throw new IllegalArgumentException("The signature algorithm cannot be null.");
		
		if (usernamePayer == null || usernamePayer.length() == 0 || usernamePayer.length() > 255)
			throw new IllegalArgumentException("The payers's username cannot be null, empty, or longer than 255 characters.");
		
		if (usernamePayee == null || usernamePayee.length() == 0 || usernamePayee.length() > 255)
			throw new IllegalArgumentException("The payee's username cannot be null, empty, or longer than 255 characters.");
		
		if (currency == null)
			throw new IllegalArgumentException("The currency cannot be null.");
		
		if (amount <= 0)
			throw new IllegalArgumentException("The amount must be greatern than 0.");
		
		if (timestamp <= 0)
			throw new IllegalArgumentException("The timestamp must be greatern than 0.");
		
		if (keyNumber <= 0 || keyNumber > 255)
			throw new IllegalArgumentException("The key number must be between 1 and 255.");
	}
	
	private void setPayload() throws UnsupportedEncodingException {
		byte[] usernamePayerBytes = usernamePayer.getBytes("UTF-8");
		byte[] usernamePayeeBytes = usernamePayee.getBytes("UTF-8");
		byte[] amountBytes = Utils.getLongAsBytes(amount);
		byte[] timestampBytes = Utils.getLongAsBytes(timestamp);
		
		//version + signatureAlgorithm.getCode() + usernamePayer.length + usernamePayer + usernamePayee.length + usernamePayee + currency.getCode() + amount + timestamp + keyNumber
		int length = 1+1+1+usernamePayerBytes.length+1+usernamePayeeBytes.length+1+8+8+1;
		byte[] payload = new byte[length];
		
		int index = 0;
		
		payload[index++] = (byte) version;
		payload[index++] = signatureAlgorithm.getCode();
		payload[index++] = (byte) usernamePayerBytes.length;
		for (byte b : usernamePayerBytes) {
			payload[index++] = b;
		}
		payload[index++] = (byte) usernamePayeeBytes.length;
		for (byte b : usernamePayeeBytes) {
			payload[index++] = b;
		}
		payload[index++] = currency.getCode();
		for (byte b : amountBytes) {
			payload[index++] = b;
		}
		for (byte b : timestampBytes) {
			payload[index++] = b;
		}
		payload[index++] = (byte) keyNumber;
		
		this.payload = payload;
	}
	
	protected int getVersion() {
		return version;
	}

	protected SignatureAlgorithm getSignatureAlgorithm() {
		return signatureAlgorithm;
	}

	protected String getUsernamePayer() {
		return usernamePayer;
	}

	protected String getUsernamePayee() {
		return usernamePayee;
	}

	protected Currency getCurrency() {
		return currency;
	}

	protected long getAmount() {
		return amount;
	}

	protected long getTimestamp() {
		return timestamp;
	}

	protected int getKeyNumber() {
		return keyNumber;
	}
	
	protected byte[] getPayload() {
		return payload;
	}
	
	protected byte[] getSignature() {
		return signature;
	}
	
	public void sign(PrivateKey privateKey) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException, UnsupportedEncodingException {
		Signature sig = Signature.getInstance(signatureAlgorithm.getSignatureAlgorithm());
		sig.initSign(privateKey);
		sig.update(payload);
		signature = sig.sign();
	}
	
	public boolean verify(PublicKey publicKey) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException, NotSignedException {
		if (signature == null)
			throw new NotSignedException();
		
		Signature sig = Signature.getInstance(signatureAlgorithm.getSignatureAlgorithm());
		sig.initVerify(publicKey);
		sig.update(this.payload);
{'fraction_non_alphanumeric': 0.09697338667594364, 'fraction_numerical': 0.008001391546355888, 'mean_word_length': 5.195581896551724, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2408872', 'n_tokens_mistral': 3433, 'n_tokens_neox': 3009, 'n_words': 909}