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