Some code for deterministic addresses - needs tests
This commit is contained in:
parent
32ea3517fe
commit
f70c15da38
@ -31,6 +31,7 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.List;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.*;
|
||||
@ -128,6 +129,18 @@ public class BitmessageContext {
|
||||
return chan;
|
||||
}
|
||||
|
||||
public List<BitmessageAddress> createDeterministicAddresses(
|
||||
String passphrase, int numberOfAddresses, int version, int stream, boolean shorter) {
|
||||
List<BitmessageAddress> result = BitmessageAddress.deterministic(
|
||||
passphrase, numberOfAddresses, version, stream, shorter);
|
||||
for (int i = 0; i < result.size(); i++) {
|
||||
BitmessageAddress address = result.get(i);
|
||||
address.setAlias(passphrase + " (" + (i + 1) + ")");
|
||||
ctx.getAddressRepository().save(address);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void broadcast(final BitmessageAddress from, final String subject, final String message) {
|
||||
Plaintext msg = new Plaintext.Builder(BROADCAST)
|
||||
.from(from)
|
||||
|
@ -29,7 +29,9 @@ import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static ch.dissem.bitmessage.utils.Decode.bytes;
|
||||
@ -41,6 +43,8 @@ import static ch.dissem.bitmessage.utils.Singleton.security;
|
||||
* holding private keys.
|
||||
*/
|
||||
public class BitmessageAddress implements Serializable {
|
||||
private static final long serialVersionUID = 2386328540805994064L;
|
||||
|
||||
private final long version;
|
||||
private final long stream;
|
||||
private final byte[] ripe;
|
||||
@ -115,6 +119,16 @@ public class BitmessageAddress implements Serializable {
|
||||
return result;
|
||||
}
|
||||
|
||||
public static List<BitmessageAddress> deterministic(String passphrase, int numberOfAddresses,
|
||||
int version, int stream, boolean shorter) {
|
||||
List<BitmessageAddress> result = new ArrayList<>(numberOfAddresses);
|
||||
List<PrivateKey> privateKeys = PrivateKey.deterministic(passphrase, numberOfAddresses, version, stream, shorter);
|
||||
for (PrivateKey pk : privateKeys) {
|
||||
result.add(new BitmessageAddress(pk));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public BitmessageAddress(PrivateKey privateKey) {
|
||||
this(privateKey.getPubkey());
|
||||
this.privateKey = privateKey;
|
||||
|
@ -25,6 +25,8 @@ import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class InventoryVector implements Streamable, Serializable {
|
||||
private static final long serialVersionUID = -7349009673063348719L;
|
||||
|
||||
/**
|
||||
* Hash of the object
|
||||
*/
|
||||
@ -42,7 +44,7 @@ public class InventoryVector implements Streamable, Serializable {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return hash != null ? Arrays.hashCode(hash) : 0;
|
||||
return hash == null ? 0 : Arrays.hashCode(hash);
|
||||
}
|
||||
|
||||
public byte[] getHash() {
|
||||
|
@ -20,6 +20,8 @@ import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
public class Label implements Serializable {
|
||||
private static final long serialVersionUID = 831782893630994914L;
|
||||
|
||||
private Object id;
|
||||
private String label;
|
||||
private Type type;
|
||||
|
@ -31,6 +31,8 @@ import java.util.Arrays;
|
||||
* A node's address. It's written in IPv6 format.
|
||||
*/
|
||||
public class NetworkAddress implements Streamable {
|
||||
private static final long serialVersionUID = 2500120578167100300L;
|
||||
|
||||
private long time;
|
||||
|
||||
/**
|
||||
|
@ -26,6 +26,8 @@ import ch.dissem.bitmessage.utils.Decode;
|
||||
import ch.dissem.bitmessage.utils.Encode;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static ch.dissem.bitmessage.utils.Singleton.security;
|
||||
|
||||
@ -34,7 +36,10 @@ import static ch.dissem.bitmessage.utils.Singleton.security;
|
||||
* {@link Pubkey} object.
|
||||
*/
|
||||
public class PrivateKey implements Streamable {
|
||||
private static final long serialVersionUID = 8562555470709110558L;
|
||||
|
||||
public static final int PRIVATE_KEY_SIZE = 32;
|
||||
|
||||
private final byte[] privateSigningKey;
|
||||
private final byte[] privateEncryptionKey;
|
||||
|
||||
@ -70,29 +75,72 @@ public class PrivateKey implements Streamable {
|
||||
}
|
||||
|
||||
public PrivateKey(long version, long stream, String passphrase) {
|
||||
try {
|
||||
byte[] signingKey;
|
||||
int signingKeyNonce = 0;
|
||||
byte[] encryptionKey;
|
||||
int encryptionKeyNonce = 1;
|
||||
byte[] passPhraseBytes = passphrase.getBytes("UTF-8");
|
||||
byte[] ripe;
|
||||
do {
|
||||
signingKey = Bytes.truncate(security().sha512(passPhraseBytes, Encode.varInt(signingKeyNonce)), 32);
|
||||
encryptionKey = Bytes.truncate(security().sha512(passPhraseBytes, Encode.varInt(encryptionKeyNonce)), 32);
|
||||
byte[] publicSigningKey = security().createPublicKey(signingKey);
|
||||
byte[] publicEncryptionKey = security().createPublicKey(encryptionKey);
|
||||
ripe = security().ripemd160(security().sha512(publicSigningKey, publicEncryptionKey));
|
||||
this(new Builder(version, stream, false).seed(passphrase).generate());
|
||||
}
|
||||
|
||||
signingKeyNonce += 2;
|
||||
encryptionKeyNonce += 2;
|
||||
} while (ripe[0] != 0);
|
||||
this.privateSigningKey = signingKey;
|
||||
this.privateEncryptionKey = encryptionKey;
|
||||
this.pubkey = security().createPubkey(version, stream, privateSigningKey, privateEncryptionKey, 0, 0);
|
||||
} catch (IOException e) {
|
||||
throw new ApplicationException(e);
|
||||
private PrivateKey(Builder builder) {
|
||||
this.privateSigningKey = builder.privSK;
|
||||
this.privateEncryptionKey = builder.privEK;
|
||||
this.pubkey = Factory.createPubkey(builder.version, builder.stream, builder.pubSK, builder.pubEK, 0, 0);
|
||||
}
|
||||
|
||||
private static class Builder {
|
||||
final long version;
|
||||
final long stream;
|
||||
final boolean shorter;
|
||||
|
||||
byte[] seed;
|
||||
long nextNonce;
|
||||
|
||||
byte[] privSK, privEK;
|
||||
byte[] pubSK, pubEK;
|
||||
|
||||
private Builder(long version, long stream, boolean shorter) {
|
||||
this.version = version;
|
||||
this.stream = stream;
|
||||
this.shorter = shorter;
|
||||
}
|
||||
|
||||
Builder seed(String passphrase) {
|
||||
try {
|
||||
seed = passphrase.getBytes("UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new ApplicationException(e);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
Builder generate() {
|
||||
try {
|
||||
long signingKeyNonce = nextNonce;
|
||||
long encryptionKeyNonce = nextNonce + 1;
|
||||
byte[] ripe;
|
||||
do {
|
||||
privEK = Bytes.truncate(security().sha512(seed, Encode.varInt(encryptionKeyNonce)), 32);
|
||||
privSK = Bytes.truncate(security().sha512(seed, Encode.varInt(signingKeyNonce)), 32);
|
||||
pubSK = security().createPublicKey(privSK);
|
||||
pubEK = security().createPublicKey(privEK);
|
||||
ripe = security().ripemd160(security().sha512(pubSK, pubEK));
|
||||
|
||||
signingKeyNonce += 2;
|
||||
encryptionKeyNonce += 2;
|
||||
} while (ripe[0] != 0 || (shorter && ripe[1] != 0));
|
||||
nextNonce = signingKeyNonce;
|
||||
} catch (IOException e) {
|
||||
throw new ApplicationException(e);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public static List<PrivateKey> deterministic(String passphrase, int numberOfAddresses, long version, long stream, boolean shorter) {
|
||||
List<PrivateKey> result = new ArrayList<>(numberOfAddresses);
|
||||
Builder builder = new Builder(version, stream, shorter).seed(passphrase);
|
||||
for (int i = 0; i < numberOfAddresses; i++) {
|
||||
builder.generate();
|
||||
result.add(new PrivateKey(builder));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static PrivateKey read(InputStream is) throws IOException {
|
||||
|
@ -31,7 +31,7 @@ import static java.util.Arrays.copyOfRange;
|
||||
*/
|
||||
public class Base58 {
|
||||
private static final int[] INDEXES = new int[128];
|
||||
private static char[] ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".toCharArray();
|
||||
private static final char[] ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".toCharArray();
|
||||
|
||||
static {
|
||||
for (int i = 0; i < INDEXES.length; i++) {
|
||||
|
Loading…
Reference in New Issue
Block a user