/*
* Copyright 2014 Christopher Mann
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.uni_bonn.bit;
import org.bitcoinj.core.Address;
import org.bitcoinj.core.ECKey;
import org.bitcoinj.core.Wallet;
import org.bitcoinj.core.WalletExtension;
import org.bitcoinj.params.RegTestParams;
import org.apache.avro.io.BinaryDecoder;
import org.apache.avro.io.DecoderFactory;
import org.apache.avro.io.Encoder;
import org.apache.avro.io.EncoderFactory;
import org.apache.avro.reflect.AvroIgnore;
import org.apache.avro.reflect.ReflectDatumReader;
import org.apache.avro.reflect.ReflectDatumWriter;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
/**
* A {@link org.bitcoinj.core.WalletExtension} which stores the keys and parameters for the two-factor wallet.
* The contents of this class are stored on the disk as part of the serialization of the {@link org.bitcoinj.core.Wallet}.
*/
public class KeyShareWalletExtension implements WalletExtension {
private byte[] privateKey;
private byte[] otherPublicKey;
private PaillierKeyPair pkpDesktop;
private PaillierKeyPair pkpPhone;
private BCParameters desktopBCParameters;
private BCParameters phoneBCParameters;
@AvroIgnore
private Address address;
@Override
public String getWalletExtensionID() {
return "de.uni_bonn.bit.KeyShareWalletExtension";
}
@Override
public boolean isWalletExtensionMandatory() {
return false;
}
@Override
public byte[] serializeWalletExtension() {
ReflectDatumWriter<KeyShareWalletExtension> specificDatumWriter = new ReflectDatumWriter<>(KeyShareWalletExtension.class);
ByteArrayOutputStream bout = new ByteArrayOutputStream();
Encoder encoder = EncoderFactory.get().binaryEncoder(bout, null);
try {
specificDatumWriter.write(this, encoder);
encoder.flush();
bout.flush();
} catch (IOException e) {
throw new RuntimeException(e);
}
return bout.toByteArray();
}
@Override
public void deserializeWalletExtension(Wallet containingWallet, byte[] data) throws Exception {
ReflectDatumReader<KeyShareWalletExtension> datumReader = new ReflectDatumReader<>(KeyShareWalletExtension.class);
BinaryDecoder decoder = DecoderFactory.get().binaryDecoder(data, null);
KeyShareWalletExtension result = datumReader.read(null, decoder);
this.privateKey = result.privateKey;
this.otherPublicKey = result.otherPublicKey;
this.pkpDesktop = result.pkpDesktop;
this.pkpPhone = result.pkpPhone;
this.desktopBCParameters = result.desktopBCParameters;
this.phoneBCParameters = result.phoneBCParameters;
}
public ECKey getPrivateKey(){
return ECKey.fromPrivate(privateKey);
}
public ECKey getOtherPublicKey(){
return ECKey.fromPublicOnly(otherPublicKey);
}
public PaillierKeyPair getPkpDesktop(){
return pkpDesktop;
}
public PaillierKeyPair getPkpPhone(){
return pkpPhone;
}
public BCParameters getDesktopBCParameters(){
return desktopBCParameters;
}
public BCParameters getPhoneBCParameters(){
return phoneBCParameters;
}
public void setPrivateKey(ECKey privateKey) {
this.privateKey = privateKey.getPrivKeyBytes();
}
public void setOtherPublicKey(ECKey otherPublicKey) {
this.otherPublicKey = otherPublicKey.getPubKey();
}
public void setPkpDesktop(PaillierKeyPair pkpDesktop) {
this.pkpDesktop = pkpDesktop;
}
public void setPkpPhone(PaillierKeyPair pkpPhone) {
this.pkpPhone = pkpPhone;
}
public void setDesktopBCParameters(BCParameters desktopBCParameters) {
this.desktopBCParameters = desktopBCParameters;
}
public void setPhoneBCParameters(BCParameters phoneBCParameters) {
this.phoneBCParameters = phoneBCParameters;
}
public String getAddressAsString(){
return getAddress().toString();
}
public Address getAddress(){
if(address == null){
address = BitcoinECMathHelper.convertPointToPubKEy(
BitcoinECMathHelper.convertPubKeyToPoint(getOtherPublicKey())
.multiply(BitcoinECMathHelper.convertPrivKeyToBigInt(getPrivateKey())
)).toAddress(RegTestParams.get());
}
return address;
}
}