Skip to content

Commit

Permalink
Added tests for the signature signer verifier.
Browse files Browse the repository at this point in the history
jars are brought to the project for the test only.
  • Loading branch information
jennnijuju committed Dec 18, 2019
1 parent 7df525f commit eb6b5cd
Show file tree
Hide file tree
Showing 9 changed files with 230 additions and 2 deletions.
45 changes: 44 additions & 1 deletion build.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,51 @@
<property name="built-sources" value="${build-dir}/main"/>
<property name="built-jar" value="${workspace}/dist"/>
<property name="jar-name" value="offline-signer"/>


<property name="test" value="${workspace}/test"/>
<property name="test-reports" value="${workspace}/reports"/>
<property name="built-tests" value="${build-dir}/test"/>

<path id="classpath-test">
<pathelement location="${dependencies}/aion-types-22a3be9.jar"/>
<pathelement location="${dependencies}/util4j-674e4b5.jar"/>
<pathelement location="${dependencies}/guava-25.1-jre.jar"/>
<pathelement location="${dependencies}/junit-4.12.jar"/>
<pathelement location="${dependencies}/hamcrest-all-1.3.jar"/>
<pathelement location="${dependencies}/ed25519.jar"/>
<pathelement location="${dependencies}/modRlp.jar"/>
</path>

<target name="clean_build" depends="clean, build"/>

<target name="test_build" depends="clean_build">
<mkdir dir="${built-tests}"/>

<javac debug="true" debuglevel="source,lines,vars" includeantruntime="false" release="10"
srcdir="${test}" destdir="${built-tests}" includes="**/*.java,module-info.java">
<classpath>
<pathelement location="${built-sources}"/>
<path refid="classpath-test"/>
</classpath>
</javac>
</target>


<target name="test" depends="test_build">
<mkdir dir="${test-reports}"/>
<junit printsummary="on" haltonfailure="true" fork="true" dir="${workspace}">
<classpath>
<pathelement location="${built-sources}"/>
<pathelement location="${built-tests}"/>
<path refid="classpath-test"/>
</classpath>
<formatter type="plain" usefile="false"/>
<formatter type="xml"/>
<batchtest todir="${test-reports}">
<fileset dir="${test}" includes="**/*Test.java"/>
</batchtest>
</junit>
</target>

<target name="build">
<mkdir dir="${built-sources}"/>
Expand Down
Binary file added lib/aion-types-22a3be9.jar
Binary file not shown.
Binary file added lib/guava-25.1-jre.jar
Binary file not shown.
Binary file added lib/hamcrest-all-1.3.jar
Binary file not shown.
Binary file added lib/junit-4.12.jar
Binary file not shown.
Binary file added lib/util4j-674e4b5.jar
Binary file not shown.
2 changes: 1 addition & 1 deletion src/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
requires aion.rlp;

exports main;
}
}
125 changes: 125 additions & 0 deletions test/main/PrivateKey.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package main;

import main.crypto.Blake2b;
import net.i2p.crypto.eddsa.EdDSAPrivateKey;
import net.i2p.crypto.eddsa.KeyPairGenerator;
import net.i2p.crypto.eddsa.Utils;
import org.aion.util.conversions.Hex;
import java.nio.ByteBuffer;
import java.security.KeyPair;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Arrays;


public final class PrivateKey {
public static final int SIZE = 32;

private final byte[] key;
private final byte[] address;

/**
* Constructs a new private key consisting of the provided bytes.
*
* @param privateKeyBytes The bytes of the private key.
*/
private PrivateKey(byte[] privateKeyBytes) throws InvalidKeySpecException {
if (privateKeyBytes == null) {
throw new NullPointerException("private key bytes cannot be null");
}
if (privateKeyBytes.length != SIZE) {
throw new IllegalArgumentException("bytes of a private key must have a length of " + SIZE);
}
this.key = privateKeyBytes.clone();
this.address = deriveAddress(this.key);
}

public static PrivateKey fromBytes(byte[] privateKeyBytes) throws InvalidKeySpecException {
return new PrivateKey(privateKeyBytes);
}

public static PrivateKey random() {
try {
return new PrivateKey(generatePrivateKey());
} catch (InvalidKeySpecException e) {
// Hiding the checked exception because this should never actually happen here. We have
// complete control over these bytes and know they are generated in a sound way.
throw new RuntimeException(e.getMessage());
}
}

public byte[] copyOfUnderlyingBytes() {
return this.key.clone();
}

public byte[] getPublicAionAddress() {
return this.address;
}

@Override
public String toString() {
return "com.theoan.transactionbuilder.main.PrivateKey { 0x" + Hex.toHexString(this.key) + " }";
}

/**
* Returns true only if other is a com.theoan.transactionbuilder.main.PrivateKey with the same underlying bytes.
*
* @param other The other whose equality is to be tested.
* @return whether this is equal to other.
*/
@Override
public boolean equals(Object other) {
if (!(other instanceof PrivateKey)) {
return false;
} else if (other == this) {
return true;
}
return Arrays.equals(this.key, ((PrivateKey) other).key);
}

@Override
public int hashCode() {
return Arrays.hashCode(this.key);
}

public static byte[] generatePrivateKey() {
KeyPairGenerator keyPairGenerator = new KeyPairGenerator();
KeyPair pair = keyPairGenerator.generateKeyPair();
EdDSAPrivateKey privateKey = (EdDSAPrivateKey) pair.getPrivate();
return Utils.hexToBytes(Utils.bytesToHex(privateKey.getEncoded()).substring(32, 96));
}

private static byte[] deriveAddress(byte[] privateKeyBytes) throws InvalidKeySpecException {
if (privateKeyBytes == null) {
throw new NullPointerException("private key cannot be null");
}

if (privateKeyBytes.length != 32){
throw new IllegalArgumentException("private key mute be 32 bytes");
}

EdDSAPrivateKey privateKey = new EdDSAPrivateKey(new PKCS8EncodedKeySpec(addSkPrefix(Utils.bytesToHex(privateKeyBytes))));
byte[] publicKeyBytes = privateKey.getAbyte();

return computeA0Address(publicKeyBytes);
}

private static byte[] addSkPrefix(String skString){
String skEncoded = "302e020100300506032b657004220420" + skString;
return Utils.hexToBytes(skEncoded);
}

private static byte[] computeA0Address(byte[] publicKey) {
byte A0_IDENTIFIER = (byte) 0xa0;
ByteBuffer buf = ByteBuffer.allocate(32);
buf.put(A0_IDENTIFIER);
buf.put(blake256(publicKey), 1, 31);
return buf.array();
}

private static byte[] blake256(byte[] input) {
Blake2b digest = Blake2b.Digest.newInstance(32);
digest.update(input);
return digest.digest();
}
}
60 changes: 60 additions & 0 deletions test/main/VerifierTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package main;

import org.junit.Assert;
import org.junit.Test;

import java.math.BigInteger;

public class VerifierTest {
@Test
public void testMatchedSignerRegular() throws Exception{
PrivateKey random = PrivateKey.random();
byte[] signed = getSignedTransaction(random);
Assert.assertTrue(SignedTransactionVerifier.isSignerForRegularTransaction(signed, random.getPublicAionAddress()));

}

@Test
public void testUnMatchedSignerRegular() throws Exception{
PrivateKey expectedSigner = PrivateKey.random();
PrivateKey otherSigner = PrivateKey.random();
byte[] signed = getSignedTransaction(expectedSigner);
Assert.assertFalse(SignedTransactionVerifier.isSignerForRegularTransaction(signed, otherSigner.copyOfUnderlyingBytes()));

}

@Test
public void testMatchedSignerInvokable() throws Exception{
PrivateKey random = PrivateKey.random();
byte[] signed = getSignedInvokable(random);
Assert.assertTrue(SignedTransactionVerifier.isSignerForInvokableTransaction(signed, random.getPublicAionAddress()));

}

@Test
public void testUnMatchedSignerInvokable() throws Exception{
PrivateKey expectedSigner = PrivateKey.random();
PrivateKey otherSigner = PrivateKey.random();
byte[] signed = getSignedInvokable(expectedSigner);
Assert.assertFalse(SignedTransactionVerifier.isSignerForInvokableTransaction(signed, otherSigner.copyOfUnderlyingBytes()));

}

private byte[] getSignedInvokable(PrivateKey privateKey) throws Exception {
return new SignedInvokableTransactionBuilder().privateKey(privateKey.copyOfUnderlyingBytes())
.executor(PrivateKey.random().getPublicAionAddress())
.data(new byte[32])
.destination(PrivateKey.random().getPublicAionAddress())
.senderNonce(BigInteger.ZERO)
.buildSignedInvokableTransaction();
}

private byte[] getSignedTransaction(PrivateKey privateKey) throws Exception {
return new SignedTransactionBuilder().privateKey(privateKey.copyOfUnderlyingBytes())
.data(new byte[0])
.energyLimit(200000)
.energyPrice(10000000000L)
.senderNonce(BigInteger.ZERO)
.buildSignedTransaction();
}
}

0 comments on commit eb6b5cd

Please sign in to comment.