• R/O
  • HTTP
  • SSH
  • HTTPS

bytom-java-sdk: 提交

Official Java SDK for Bytom


Commit MetaInfo

修订版501037d1bb26d7c896b3a522b4db1e70b9d135d3 (tree)
时间2019-03-20 15:53:39
作者shenao78 <shenao.78@163....>
Commitershenao78

Log Message

refactor

更改概述

差异

--- a/tx-signer/README.md
+++ b/tx-signer/README.md
@@ -76,7 +76,7 @@ Need 3 Parameters:
7676
7777 ```java
7878
79-//utxo json to input public Transaction.AnnotatedInput btmUtxoToInput() {
79+AnnotatedBaseInput
8080 String utxoJson = "{\n" +
8181 " \"id\": \"cf2f5c7340490d33d535a680dc8d95bb66fcccbf1045706484621cc067b982ae\",\n" +
8282 " \"amount\": 70000000,\n" +
--- a/tx-signer/src/main/java/com/google/crypto/tink/subtle/Ed25519.java
+++ b/tx-signer/src/main/java/com/google/crypto/tink/subtle/Ed25519.java
@@ -889,7 +889,7 @@ public final class Ed25519 {
889889 * Input:
890890 * s[0]+256*s[1]+...+256^63*s[63] = s
891891 * <p>
892- * Output:
892+ * OutputEntry:
893893 * s[0]+256*s[1]+...+256^31*s[31] = s mod l
894894 * where l = 2^252 + 27742317777372353535851937790883648493.
895895 * Overwrites s in place.
@@ -1250,7 +1250,7 @@ public final class Ed25519 {
12501250 * b[0]+256*b[1]+...+256^31*b[31] = b
12511251 * c[0]+256*c[1]+...+256^31*c[31] = c
12521252 * <p>
1253- * Output:
1253+ * OutputEntry:
12541254 * s[0]+256*s[1]+...+256^31*s[31] = (ab+c) mod l
12551255 * where l = 2^252 + 27742317777372353535851937790883648493.
12561256 */
--- /dev/null
+++ b/tx-signer/src/main/java/io/bytom/api/BIPProtocol.java
@@ -0,0 +1,7 @@
1+package io.bytom.api;
2+
3+public enum BIPProtocol {
4+
5+ BIP32,
6+ BIP44
7+}
--- /dev/null
+++ b/tx-signer/src/main/java/io/bytom/api/BaseInput.java
@@ -0,0 +1,107 @@
1+package io.bytom.api;
2+
3+import io.bytom.common.Utils;
4+import io.bytom.types.*;
5+import java.io.IOException;
6+import java.util.Map;
7+
8+public abstract class BaseInput {
9+
10+ public static final int ISSUANCE_INPUT_TYPE = 0;
11+ public static final int SPEND_INPUT_TYPE = 1;
12+
13+ private String inputID;
14+
15+ /**
16+ * The number of units of the asset being issued or spent.
17+ */
18+ private long amount;
19+
20+ /**
21+ * The id of the asset being issued or spent.
22+ */
23+ private String assetId;
24+
25+ /**
26+ * The program which must be satisfied to transfer this output.
27+ */
28+ private String program;
29+
30+ private int vmVersion;
31+
32+ private int keyIndex;
33+
34+ private WitnessComponent witnessComponent = new WitnessComponent();
35+
36+ public BaseInput() {
37+ this.vmVersion = 1;
38+ }
39+
40+ public abstract InputEntry convertInputEntry(Map<Hash, Entry> entryMap, int index);
41+
42+ public abstract byte[] serializeInput() throws IOException;
43+
44+ public abstract void buildWitness(String txID) throws Exception;
45+
46+ @Override
47+ public String toString() {
48+ return Utils.serializer.toJson(this);
49+ }
50+
51+
52+ public AssetAmount getAssetAmount() {
53+ return new AssetAmount(new AssetID(this.assetId), this.amount);
54+ }
55+
56+ public void setRootPrivateKey(String prvKey) {
57+ witnessComponent.setRootPrivateKey(prvKey);
58+ }
59+
60+ public String getInputID() {
61+ return inputID;
62+ }
63+
64+ public int getKeyIndex() {
65+ return keyIndex;
66+ }
67+
68+ public int getVmVersion() {
69+ return vmVersion;
70+ }
71+
72+ public String getProgram() {
73+ return program;
74+ }
75+
76+ public String getAssetId() {
77+ return assetId;
78+ }
79+
80+ public long getAmount() {
81+ return amount;
82+ }
83+
84+ public void setInputID(String inputID) {
85+ this.inputID = inputID;
86+ }
87+
88+ public void setAmount(long amount) {
89+ this.amount = amount;
90+ }
91+
92+ public void setAssetId(String assetId) {
93+ this.assetId = assetId;
94+ }
95+
96+ public void setProgram(String program) {
97+ this.program = program;
98+ }
99+
100+ public void setKeyIndex(int keyIndex) {
101+ this.keyIndex = keyIndex;
102+ }
103+
104+ public WitnessComponent getWitnessComponent() {
105+ return witnessComponent;
106+ }
107+}
--- /dev/null
+++ b/tx-signer/src/main/java/io/bytom/api/IssuanceInput.java
@@ -0,0 +1,104 @@
1+package io.bytom.api;
2+
3+import io.bytom.common.DerivePrivateKey;
4+import io.bytom.common.ExpandedPrivateKey;
5+import io.bytom.common.Utils;
6+import io.bytom.types.*;
7+import io.bytom.util.SHA3Util;
8+import org.bouncycastle.util.encoders.Hex;
9+import java.io.ByteArrayOutputStream;
10+import java.io.IOException;
11+import java.security.SecureRandom;
12+import java.util.Map;
13+
14+public class IssuanceInput extends BaseInput {
15+
16+ private String nonce;
17+
18+ private String assetDefinition;
19+
20+ public IssuanceInput() {}
21+
22+ @Override
23+ public InputEntry convertInputEntry(Map<Hash, Entry> entryMap, int index) {
24+ if (this.nonce == null) {
25+ SecureRandom sr = new SecureRandom();
26+ byte[] randBytes = new byte[8];
27+ sr.nextBytes(randBytes);
28+ this.nonce = Hex.toHexString(randBytes);
29+ }
30+
31+ Hash nonceHash = new Hash(SHA3Util.hashSha256(Hex.decode(this.nonce)));
32+ Hash assetDefHash = new Hash(this.assetDefinition);
33+ AssetAmount value = this.getAssetAmount();
34+
35+ Issue issuance = new Issue(nonceHash, value, index);
36+ Program pro = new Program(this.getVmVersion(), Hex.decode(this.getProgram()));
37+ issuance.assetDefinition = new AssetDefinition(assetDefHash, pro);
38+ return issuance;
39+ }
40+
41+ @Override
42+ public byte[] serializeInput() throws IOException {
43+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
44+ //assetVersion
45+ Utils.writeVarint(1, stream);
46+ //写入 type nonce assetId amount
47+ ByteArrayOutputStream issueInfo = new ByteArrayOutputStream();
48+ //写入 input.type==00 issue
49+ Utils.writeVarint(ISSUANCE_INPUT_TYPE, issueInfo);
50+ //写入 8个字节的随机数
51+ Utils.writeVarStr(Hex.decode(nonce), issueInfo);
52+ issueInfo.write(Hex.decode(getAssetId()));
53+ Utils.writeVarint(getAmount(), issueInfo);
54+ stream.write(issueInfo.toByteArray().length);
55+ stream.write(issueInfo.toByteArray());
56+
57+ ByteArrayOutputStream issueInfo1 = new ByteArrayOutputStream();
58+ //未知
59+ Utils.writeVarint(1, issueInfo1);
60+ //写入assetDefine
61+ Utils.writeVarStr(Hex.decode(assetDefinition), issueInfo1);
62+ //vm.version
63+ Utils.writeVarint(1, issueInfo1);
64+ //controlProgram
65+ Utils.writeVarStr(Hex.decode(getProgram()), issueInfo1);
66+
67+ //inputWitness
68+ if (null != getWitnessComponent()) {
69+ ByteArrayOutputStream witnessStream = new ByteArrayOutputStream();
70+ //arguments
71+ int witnessSize = getWitnessComponent().size();
72+ //arguments的length
73+ Utils.writeVarint(witnessSize, witnessStream);
74+ for (int i = 0; i < witnessSize; i++) {
75+ String witness = getWitnessComponent().getWitness(i);
76+ Utils.writeVarStr(Hex.decode(witness), witnessStream);
77+ }
78+ issueInfo1.write(witnessStream.toByteArray());
79+ }
80+ stream.write(issueInfo1.toByteArray().length - 1);
81+ stream.write(issueInfo1.toByteArray());
82+ return stream.toByteArray();
83+ }
84+
85+ @Override
86+ public void buildWitness(String txID) throws Exception {
87+ String rootPrivateKey = getWitnessComponent().getRootPrivateKey();
88+ byte[] childPrivateKey = DerivePrivateKey.bip32derivePrvKey(rootPrivateKey, getKeyIndex(), TransactionSigner.AssetKeySpace);
89+
90+ byte[] message = Utils.hashFn(Hex.decode(getInputID()), Hex.decode(txID));
91+ byte[] expandedPrivateKey = ExpandedPrivateKey.expandedPrivateKey(childPrivateKey);
92+ byte[] sig = Signer.ed25519InnerSign(expandedPrivateKey, message);
93+
94+ getWitnessComponent().appendWitness(Hex.toHexString(sig));
95+ }
96+
97+ public void setNonce(String nonce) {
98+ this.nonce = nonce;
99+ }
100+
101+ public void setAssetDefinition(String assetDefinition) {
102+ this.assetDefinition = assetDefinition;
103+ }
104+}
--- a/tx-signer/src/main/java/io/bytom/api/MapTransaction.java
+++ /dev/null
@@ -1,110 +0,0 @@
1-package io.bytom.api;
2-
3-import io.bytom.types.*;
4-import io.bytom.util.SHA3Util;
5-import org.bouncycastle.util.encoders.Hex;
6-
7-import java.security.SecureRandom;
8-import java.util.ArrayList;
9-import java.util.HashMap;
10-import java.util.List;
11-import java.util.Map;
12-
13-public class MapTransaction {
14-
15- public static Transaction mapTx(Transaction tx) {
16- Map<Hash, Entry> entryMap = new HashMap<>();
17- ValueSource[] muxSources = new ValueSource[tx.inputs.size()];
18- List<Spend> spends = new ArrayList<>();
19- List<Issue> issuances = new ArrayList<>();
20- try {
21- for (int i = 0; i < tx.inputs.size(); i++) {
22- Transaction.AnnotatedInput input = tx.inputs.get(i);
23- switch (input.type) {
24- case 1: {
25- Program pro = new Program(input.type, Hex.decode(input.controlProgram));
26- AssetID assetID = new AssetID(input.assetId);
27- AssetAmount assetAmount = new AssetAmount(assetID, input.amount);
28- Hash sourceID = new Hash(input.sourceId);
29- ValueSource src = new ValueSource(sourceID, assetAmount, input.sourcePosition);
30-
31- Output prevout = new Output(src, pro, 0);
32- Hash prevoutID = addEntry(entryMap, prevout);
33- Spend spend = new Spend(prevoutID, i);
34- Hash spendID = addEntry(entryMap, spend);
35- input.inputID = spendID.toString();
36-
37- muxSources[i] = new ValueSource(spendID, assetAmount, 0);
38- spends.add(spend);
39- break;
40- }
41- case 0: {
42- if (input.nonce == null) {
43- SecureRandom sr = new SecureRandom();
44- byte[] randBytes = new byte[8];
45- sr.nextBytes(randBytes);
46- input.nonce = Hex.toHexString(randBytes);
47- }
48- Hash nonceHash = new Hash(SHA3Util.hashSha256(Hex.decode(input.nonce)));
49- Hash assetDefHash = new Hash(input.assetDefinition);
50- AssetID assetID = new AssetID(input.assetId);
51- AssetAmount value = new AssetAmount(assetID, input.amount);
52-
53- Issue issuance = new Issue(nonceHash, value, i);
54- Program pro = new Program(input.type, Hex.decode(input.controlProgram));
55- issuance.assetDefinition = new AssetDefinition(assetDefHash, pro);
56- Hash issuanceID = addEntry(entryMap, issuance);
57- input.inputID = issuanceID.toString();
58- muxSources[i] = new ValueSource(issuanceID, value, 0);
59- issuances.add(issuance);
60- break;
61- }
62- }
63- }
64- Mux mux = new Mux(muxSources, new Program(1, new byte[]{0x51}));
65- Hash muxID = addEntry(entryMap, mux);
66- for (Spend spend : spends) {
67- Output spendOutput = (Output) entryMap.get(spend.spentOutputID);
68- spend.setDestination(muxID, spendOutput.source.value, spend.ordinal);
69- }
70- for (Issue issue : issuances) {
71- issue.setDestination(muxID, issue.assetAmount, issue.ordinal);
72- }
73-
74- List<Hash> resultIDList = new ArrayList<>();
75- for (int i = 0; i < tx.outputs.size(); i++) {
76- Transaction.AnnotatedOutput output = tx.outputs.get(i);
77-
78- AssetAmount amount = new AssetAmount(new AssetID(output.assetId), output.amount);
79- ValueSource src = new ValueSource(muxID, amount, i);
80- Hash resultID;
81- if (output.controlProgram.startsWith("6a")&&output.controlProgram.length()>0) {
82- Retirement retirement = new Retirement(src, i);
83- resultID = addEntry(entryMap, retirement);
84- } else {
85- Program prog = new Program(1, Hex.decode(output.controlProgram));
86- Output oup = new Output(src, prog, i);
87- resultID = addEntry(entryMap, oup);
88- }
89- resultIDList.add(resultID);
90- output.id = resultID.toString();
91-
92- ValueDestination destination = new ValueDestination(resultID, src.value, 0);
93- mux.witnessDestinations.add(destination);
94- }
95-
96- TxHeader txHeader = new TxHeader(tx.version, tx.size, tx.timeRange, resultIDList.toArray(new Hash[]{}));
97- Hash txID = addEntry(entryMap, txHeader);
98- tx.txID = txID.toString();
99- } catch (Exception e) {
100- throw new RuntimeException(e);
101- }
102- return tx;
103- }
104-
105- private static Hash addEntry(Map<Hash, Entry> entryMap, Entry entry) {
106- Hash id = entry.entryID();
107- entryMap.put(id, entry);
108- return id;
109- }
110-}
--- /dev/null
+++ b/tx-signer/src/main/java/io/bytom/api/Output.java
@@ -0,0 +1,108 @@
1+package io.bytom.api;
2+
3+import io.bytom.common.Utils;
4+import org.bouncycastle.util.encoders.Hex;
5+import java.io.ByteArrayOutputStream;
6+import java.io.IOException;
7+import java.util.Map;
8+
9+public class Output {
10+
11+ /**
12+ * address
13+ */
14+ public String address;
15+
16+ /**
17+ * The number of units of the asset being controlled.
18+ */
19+ public long amount;
20+
21+ /**
22+ * The definition of the asset being controlled (possibly null).
23+ */
24+ public Map<String, Object> assetDefinition;
25+
26+ /**
27+ * The id of the asset being controlled.
28+ */
29+ public String assetId;
30+
31+ /**
32+ * The control program which must be satisfied to transfer this output.
33+ */
34+ public String controlProgram;
35+
36+ /**
37+ * The id of the output.
38+ */
39+ public String id;
40+
41+ /**
42+ * The output's position in a transaction's list of outputs.
43+ */
44+ public Integer position;
45+
46+ public Output(String assetId, long amount, String controlProgram) {
47+ this.assetId = assetId;
48+ this.amount = amount;
49+ this.controlProgram = controlProgram;
50+ }
51+
52+ public byte[] serializeOutput() throws IOException {
53+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
54+
55+ //assetVersion
56+ Utils.writeVarint(1, stream); //AssetVersion是否默认为1
57+ //outputCommit
58+ ByteArrayOutputStream outputCommitSteam = new ByteArrayOutputStream();
59+ //assetId
60+ outputCommitSteam.write(Hex.decode(assetId));
61+ //amount
62+ Utils.writeVarint(amount, outputCommitSteam);
63+ //vmVersion
64+ Utils.writeVarint(1, outputCommitSteam); //db中获取vm_version
65+ //controlProgram
66+ Utils.writeVarStr(Hex.decode(controlProgram), outputCommitSteam);
67+
68+ byte[] dataOutputCommit = outputCommitSteam.toByteArray();
69+ //outputCommit的length
70+ Utils.writeVarint(dataOutputCommit.length, stream);
71+ stream.write(dataOutputCommit);
72+
73+ //outputWitness
74+ Utils.writeVarint(0, stream);
75+ return stream.toByteArray();
76+ }
77+
78+ /**
79+ * The type the output.<br>
80+ * Possible values are "control" and "retire".
81+ */
82+ public String type;
83+
84+ public Output setAddress(String address) {
85+ this.address = address;
86+ return this;
87+ }
88+
89+ public Output setAmount(long amount) {
90+ this.amount = amount;
91+ return this;
92+ }
93+
94+ public Output setAssetId(String assetId) {
95+ this.assetId = assetId;
96+ return this;
97+ }
98+
99+ public Output setControlProgram(String controlProgram) {
100+ this.controlProgram = controlProgram;
101+ return this;
102+ }
103+
104+ public Output setPosition(Integer position) {
105+ this.position = position;
106+ return this;
107+ }
108+}
--- a/tx-signer/src/main/java/io/bytom/api/SignTransaction.java
+++ /dev/null
@@ -1,310 +0,0 @@
1-package io.bytom.api;
2-
3-import io.bytom.common.DerivePrivateKey;
4-import io.bytom.common.DeriveXpub;
5-import io.bytom.common.ExpandedPrivateKey;
6-import io.bytom.common.Utils;
7-import org.bouncycastle.jcajce.provider.digest.SHA3;
8-import org.bouncycastle.util.encoders.Hex;
9-
10-import java.io.ByteArrayOutputStream;
11-import java.io.IOException;
12-import java.math.BigInteger;
13-import java.security.InvalidKeyException;
14-import java.security.NoSuchAlgorithmException;
15-import java.security.SignatureException;
16-
17-
18-/**
19- * Created by liqiang on 2018/10/24.
20- */
21-public class SignTransaction {
22-
23- private final String OP_TXSIGHASH = "ae";
24- private final String OP_CHECKMULTISIG = "ad";
25-
26- public String serializeTransaction(Transaction tx) {
27- String txSign = null;
28- //开始序列化
29- ByteArrayOutputStream stream = new ByteArrayOutputStream();
30- try {
31- stream.write(7);
32- // version
33- if (null != tx.version)
34- Utils.writeVarint(tx.version, stream);
35- if (null != tx.timeRange)
36- Utils.writeVarint(tx.timeRange, stream);
37- //inputs
38- if (null != tx.inputs && tx.inputs.size() > 0) {
39- Utils.writeVarint(tx.inputs.size(), stream);
40- for (Transaction.AnnotatedInput input : tx.inputs) {
41- if (input.type == 1) {
42- //assertVersion
43- Utils.writeVarint(tx.version, stream); //AssetVersion是否默认为1
44-
45- //inputCommitment
46- ByteArrayOutputStream inputCommitStream = new ByteArrayOutputStream();
47- //spend type flag
48- Utils.writeVarint(input.type, inputCommitStream);
49- //spendCommitment
50- ByteArrayOutputStream spendCommitSteam = new ByteArrayOutputStream();
51- spendCommitSteam.write(Hex.decode(input.sourceId)); //计算muxID
52- spendCommitSteam.write(Hex.decode(input.assetId));
53- Utils.writeVarint(input.amount, spendCommitSteam);
54- //sourcePosition
55- Utils.writeVarint(input.sourcePosition, spendCommitSteam); //db中获取position
56- //vmVersion
57- Utils.writeVarint(1, spendCommitSteam); //db中获取vm_version
58- //controlProgram
59- Utils.writeVarStr(Hex.decode(input.controlProgram), spendCommitSteam);
60-
61- byte[] dataSpendCommit = spendCommitSteam.toByteArray();
62-
63- Utils.writeVarint(dataSpendCommit.length, inputCommitStream);
64- inputCommitStream.write(dataSpendCommit);
65- byte[] dataInputCommit = inputCommitStream.toByteArray();
66- //inputCommit的length
67- Utils.writeVarint(dataInputCommit.length, stream);
68- stream.write(dataInputCommit);
69-
70- //inputWitness
71- if (null != input.witnessComponent) {
72- ByteArrayOutputStream witnessStream = new ByteArrayOutputStream();
73- //arguments
74- int lenSigs = input.witnessComponent.signatures.length;
75- //arguments的length
76- Utils.writeVarint(lenSigs, witnessStream);
77- for (int i = 0; i < lenSigs; i++) {
78- String sig = input.witnessComponent.signatures[i];
79- Utils.writeVarStr(Hex.decode(sig), witnessStream);
80- }
81- byte[] dataWitnessComponets = witnessStream.toByteArray();
82- //witness的length
83- Utils.writeVarint(dataWitnessComponets.length, stream);
84- stream.write(dataWitnessComponets);
85- }
86- }
87- if (input.type == 0) {
88- //assetVersion
89- Utils.writeVarint(01, stream);
90- //写入 type nonce assetId amount
91- ByteArrayOutputStream issueInfo = new ByteArrayOutputStream();
92- //写入 input.type==00 issue
93- Utils.writeVarint(input.type, issueInfo);
94- //写入 8个字节的随机数
95- Utils.writeVarStr(Hex.decode(input.nonce), issueInfo);
96- issueInfo.write(Hex.decode(input.assetId));
97- Utils.writeVarint(input.amount, issueInfo);
98- stream.write(issueInfo.toByteArray().length);
99- stream.write(issueInfo.toByteArray());
100-
101- ByteArrayOutputStream issueInfo1 = new ByteArrayOutputStream();
102- //未知
103- Utils.writeVarint(1, issueInfo1);
104- //写入assetDefine
105- Utils.writeVarStr(Hex.decode(input.assetDefinition), issueInfo1);
106- //vm.version
107- Utils.writeVarint(1, issueInfo1);
108- //controlProgram
109- Utils.writeVarStr(Hex.decode(input.controlProgram), issueInfo1);
110-
111- //inputWitness
112- if (null != input.witnessComponent) {
113- ByteArrayOutputStream witnessStream = new ByteArrayOutputStream();
114- //arguments
115- int lenSigs = input.witnessComponent.signatures.length;
116- //arguments的length
117- Utils.writeVarint(lenSigs, witnessStream);
118- for (int i = 0; i < lenSigs; i++) {
119- String sig = input.witnessComponent.signatures[i];
120- Utils.writeVarStr(Hex.decode(sig), witnessStream);
121- }
122-// byte[] dataWitnessComponets = witnessStream.toByteArray();
123- //witness的length
124-// Utils.writeVarint(dataWitnessComponets.length, issueInfo1);
125-
126- issueInfo1.write(witnessStream.toByteArray());
127- }
128- stream.write(issueInfo1.toByteArray().length - 1);
129- stream.write(issueInfo1.toByteArray());
130-
131- }
132- }
133- }
134-
135- //outputs
136- if (null != tx.outputs && tx.outputs.size() > 0) {
137- Utils.writeVarint(tx.outputs.size(), stream);
138- for (Transaction.AnnotatedOutput output : tx.outputs) {
139- //assertVersion
140- Utils.writeVarint(tx.version, stream); //AssetVersion是否默认为1
141- //outputCommit
142- ByteArrayOutputStream outputCommitSteam = new ByteArrayOutputStream();
143- //assetId
144- outputCommitSteam.write(Hex.decode(output.assetId));
145- //amount
146- Utils.writeVarint(output.amount, outputCommitSteam);
147- //vmVersion
148- Utils.writeVarint(1, outputCommitSteam); //db中获取vm_version
149- //controlProgram
150- Utils.writeVarStr(Hex.decode(output.controlProgram), outputCommitSteam);
151-
152- byte[] dataOutputCommit = outputCommitSteam.toByteArray();
153- //outputCommit的length
154- Utils.writeVarint(dataOutputCommit.length, stream);
155- stream.write(dataOutputCommit);
156-
157- //outputWitness
158- Utils.writeVarint(0, stream);
159- }
160- }
161-
162- byte[] data = stream.toByteArray();
163- txSign = Hex.toHexString(data);
164-
165- } catch (IOException e) {
166- throw new RuntimeException(e);
167- }
168- return txSign;
169- }
170-
171- public Integer getTransactionSize(Transaction tx) {
172- String result = serializeTransaction(tx);
173- return Hex.decode(result).length;
174- }
175-
176- //签名组装witness
177- public Transaction buildWitness(Transaction transaction, int index, byte[] privateKeyBytes) {
178-
179- Transaction.AnnotatedInput input = transaction.inputs.get(index);
180- if (null == input.witnessComponent)
181-
182- if (null != input) {
183- try {
184- input.witnessComponent = new Transaction.InputWitnessComponent();
185- byte[] message = hashFn(Hex.decode(input.inputID), Hex.decode(transaction.txID));
186- byte[] expandedPrivateKey = ExpandedPrivateKey.ExpandedPrivateKey(privateKeyBytes);
187- byte[] sig = Signer.Ed25519InnerSign(expandedPrivateKey, message);
188-
189- switch (input.type) {
190- case 1: {
191- input.witnessComponent.signatures = new String[2];
192- input.witnessComponent.signatures[0] = Hex.toHexString(sig);
193- byte[] deriveXpub = DeriveXpub.deriveXpub(privateKeyBytes);
194- String pubKey = Hex.toHexString(deriveXpub).substring(0, 64);
195- input.witnessComponent.signatures[1] = pubKey;
196- break;
197- }
198- case 0: {
199- input.witnessComponent.signatures = new String[1];
200- input.witnessComponent.signatures[0] = Hex.toHexString(sig);
201- break;
202- }
203- }
204-
205- } catch (Exception e) {
206- throw new RuntimeException(e);
207- }
208- } else {
209- System.out.println("build witness failed.");
210- }
211- return transaction;
212- }
213-
214- //多签单输入
215- public void buildWitness(Transaction transaction, int index, String[] privateKeys) {
216- Transaction.AnnotatedInput input = transaction.inputs.get(index);
217- if (null == input.witnessComponent)
218- input.witnessComponent = new Transaction.InputWitnessComponent();
219- try {
220-
221- //TODO 多签issue
222- StringBuilder sb = new StringBuilder(OP_TXSIGHASH);
223- input.witnessComponent.signatures = new String[privateKeys.length + 1];
224- for (int i = 0; i < privateKeys.length; i++) {
225- System.out.println(input.isChange());
226- byte[] key = DerivePrivateKey.derivePrivateKey(privateKeys[i], 1, input.isChange(), input.getControlProgramIndex());
227- byte[] message = hashFn(Hex.decode(input.inputID), Hex.decode(transaction.txID));
228- byte[] expandedPrivateKey = ExpandedPrivateKey.ExpandedPrivateKey(key);
229- byte[] sig = Signer.Ed25519InnerSign(expandedPrivateKey, message);
230- input.witnessComponent.signatures[i] = Hex.toHexString(sig);
231- byte[] deriveXpub = DeriveXpub.deriveXpub(expandedPrivateKey);
232- String publicKey = Hex.toHexString(deriveXpub).substring(0, 64);
233- sb.append(Integer.toString(Hex.decode(publicKey).length,16)).append(publicKey);
234- }
235- //TODO 签名数跟公钥数量不同
236- sb.append(Utils.pushDataInt(privateKeys.length)); //should be nrequired
237- sb.append(Utils.pushDataInt(privateKeys.length));
238- sb.append(OP_CHECKMULTISIG);
239- input.witnessComponent.signatures[privateKeys.length] = sb.toString();
240-
241- } catch (Exception e) {
242- throw new RuntimeException(e);
243- }
244-
245- }
246-
247- public static byte[] hashFn(byte[] hashedInputHex, byte[] txID) {
248-
249- SHA3.Digest256 digest256 = new SHA3.Digest256();
250- // data = hashedInputHex + txID
251- ByteArrayOutputStream out = new ByteArrayOutputStream();
252- out.write(hashedInputHex, 0, hashedInputHex.length);
253- out.write(txID, 0, txID.length);
254- byte[] data = out.toByteArray();
255- return digest256.digest(data);
256- }
257-
258-
259- public Transaction generateSignatures(Transaction Transaction, BigInteger[] keys) {
260- Transaction.AnnotatedInput input = Transaction.inputs.get(0);
261- input.witnessComponent.signatures = new String[keys.length];
262- for (int i = 0; i < keys.length; i++) {
263- if (null != input) {
264- try {
265- byte[] message = hashFn(Hex.decode(input.inputID), Hex.decode(Transaction.txID));
266- byte[] expandedPrv = Utils.BigIntegerToBytes(keys[i]);
267- byte[] priKey = ExpandedPrivateKey.ExpandedPrivateKey(expandedPrv);
268- byte[] sig = Signer.Ed25519InnerSign(priKey, message);
269- input.witnessComponent.signatures[i] = Hex.toHexString(sig);
270-
271- } catch (Exception e) {
272- e.printStackTrace();
273- }
274- } else {
275- System.out.println("generate signatures failed.");
276- }
277- }
278- return Transaction;
279- }
280-
281- //根据主私钥对交易签名,生成序列化的rawTransaction
282- public String rawTransaction(String rootPrivateKey, Transaction tx) throws NoSuchAlgorithmException, SignatureException, InvalidKeyException {
283- byte[] privateChild;
284- for (int i = 0; i < tx.inputs.size(); i++) {
285- if (tx.inputs.get(i).type == 1) {
286- privateChild = DerivePrivateKey.derivePrivateKey(rootPrivateKey, 1, tx.inputs.get(i).isChange(), tx.inputs.get(i).getControlProgramIndex());
287- } else {
288- privateChild = DerivePrivateKey.derivePrivateKey(rootPrivateKey, tx.inputs.get(i).getKeyIndex());
289- }
290- buildWitness(tx, i, privateChild);
291- }
292- return serializeTransaction(tx);
293- }
294-
295- //多签
296- public String rawTransaction(String[] rootPrivateKey, Transaction tx) throws NoSuchAlgorithmException, SignatureException, InvalidKeyException {
297- String privateChild;
298- for (int i = 0; i < tx.inputs.size(); i++) {
299- if (tx.inputs.get(i).controlProgram.length() != 44) {
300- buildWitness(tx, i, rootPrivateKey);
301- }
302-
303- }
304- return serializeTransaction(tx);
305- }
306-
307-
308-}
309-
310-
--- a/tx-signer/src/main/java/io/bytom/api/Signer.java
+++ b/tx-signer/src/main/java/io/bytom/api/Signer.java
@@ -10,8 +10,7 @@ import java.util.Arrays;
1010
1111 public class Signer {
1212
13- public static byte[] Ed25519InnerSign(byte[] privateKey, byte[] message)
14- throws SignatureException, NoSuchAlgorithmException, InvalidKeyException {
13+ public static byte[] ed25519InnerSign(byte[] privateKey, byte[] message) throws NoSuchAlgorithmException {
1514 MessageDigest md = MessageDigest.getInstance("SHA-512");
1615 byte[] digestData = new byte[32 + message.length];
1716 int digestDataIndex = 0;
--- /dev/null
+++ b/tx-signer/src/main/java/io/bytom/api/SpendInput.java
@@ -0,0 +1,136 @@
1+package io.bytom.api;
2+
3+import io.bytom.common.*;
4+import io.bytom.types.*;
5+import org.bouncycastle.util.encoders.Hex;
6+import java.io.ByteArrayOutputStream;
7+import java.io.IOException;
8+import java.util.Map;
9+
10+public class SpendInput extends BaseInput {
11+
12+ private String sourceId;
13+
14+ private long sourcePosition;
15+
16+ private boolean change;
17+
18+ private int controlProgramIndex;
19+
20+ private BIPProtocol bipProtocol;
21+
22+ public SpendInput() {}
23+
24+ public SpendInput(String assetID, long amount, String controlProgram) {
25+ this.setAssetId(assetID);
26+ this.setAmount(amount);
27+ this.setProgram(controlProgram);
28+ this.bipProtocol = BIPProtocol.BIP44;
29+ }
30+
31+ @Override
32+ public InputEntry convertInputEntry(Map<Hash, Entry> entryMap, int index) {
33+ Program pro = new Program(this.getVmVersion(), Hex.decode(this.getProgram()));
34+ AssetAmount assetAmount = this.getAssetAmount();
35+ Hash sourceID = new Hash(this.sourceId);
36+ ValueSource src = new ValueSource(sourceID, assetAmount, this.sourcePosition);
37+
38+ OutputEntry prevout = new OutputEntry(src, pro, 0);
39+ Hash prevOutID = prevout.entryID();
40+ entryMap.put(prevOutID, prevout);
41+ return new Spend(prevOutID, index);
42+ }
43+
44+ @Override
45+ public byte[] serializeInput() throws IOException {
46+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
47+ //assetVersion
48+ Utils.writeVarint(1, stream); //AssetVersion是否默认为1
49+
50+ //inputCommitment
51+ ByteArrayOutputStream inputCommitStream = new ByteArrayOutputStream();
52+ //spend type flag
53+ Utils.writeVarint(SPEND_INPUT_TYPE, inputCommitStream);
54+ //spendCommitment
55+ ByteArrayOutputStream spendCommitSteam = new ByteArrayOutputStream();
56+ spendCommitSteam.write(Hex.decode(sourceId)); //计算muxID
57+ spendCommitSteam.write(Hex.decode(getAssetId()));
58+ Utils.writeVarint(getAmount(), spendCommitSteam);
59+ //sourcePosition
60+ Utils.writeVarint(sourcePosition, spendCommitSteam); //db中获取position
61+ //vmVersion
62+ Utils.writeVarint(1, spendCommitSteam); //db中获取vm_version
63+ //controlProgram
64+ Utils.writeVarStr(Hex.decode(getProgram()), spendCommitSteam);
65+
66+ byte[] dataSpendCommit = spendCommitSteam.toByteArray();
67+
68+ Utils.writeVarint(dataSpendCommit.length, inputCommitStream);
69+ inputCommitStream.write(dataSpendCommit);
70+ byte[] dataInputCommit = inputCommitStream.toByteArray();
71+ //inputCommit的length
72+ Utils.writeVarint(dataInputCommit.length, stream);
73+ stream.write(dataInputCommit);
74+
75+ //inputWitness
76+ if (null != getWitnessComponent()) {
77+ ByteArrayOutputStream witnessStream = new ByteArrayOutputStream();
78+ //arguments
79+ int witnessSize = getWitnessComponent().size();
80+ //arguments的length
81+ Utils.writeVarint(witnessSize, witnessStream);
82+ for (int i = 0; i < witnessSize; i++) {
83+ String witness = getWitnessComponent().getWitness(i);
84+ Utils.writeVarStr(Hex.decode(witness), witnessStream);
85+ }
86+ byte[] dataWitnessComponents = witnessStream.toByteArray();
87+ //witness的length
88+ Utils.writeVarint(dataWitnessComponents.length, stream);
89+ stream.write(dataWitnessComponents);
90+ }
91+ return stream.toByteArray();
92+ }
93+
94+ @Override
95+ public void buildWitness(String txID) throws Exception {
96+ String rootPrvKey = getWitnessComponent().getRootPrivateKey();
97+
98+ byte[] privateChild;
99+ if (bipProtocol == BIPProtocol.BIP44) {
100+ privateChild = DerivePrivateKey.bip44derivePrvKey(rootPrvKey, TransactionSigner.AccountKeySpace, change, controlProgramIndex);
101+ } else {
102+ privateChild = DerivePrivateKey.bip32derivePrvKey(rootPrvKey, getKeyIndex(), TransactionSigner.AccountKeySpace, controlProgramIndex);
103+ }
104+
105+ byte[] message = Utils.hashFn(Hex.decode(getInputID()), Hex.decode(txID));
106+ byte[] expandedPrivateKey = ExpandedPrivateKey.expandedPrivateKey(privateChild);
107+ byte[] sig = Signer.ed25519InnerSign(expandedPrivateKey, message);
108+
109+ getWitnessComponent().appendWitness(Hex.toHexString(sig));
110+
111+ byte[] deriveXpub = DeriveXpub.deriveXpub(privateChild);
112+ String pubKey = Hex.toHexString(deriveXpub).substring(0, 64);
113+
114+ getWitnessComponent().appendWitness(pubKey);
115+ }
116+
117+ public void setSourceId(String sourceId) {
118+ this.sourceId = sourceId;
119+ }
120+
121+ public void setSourcePosition(long sourcePosition) {
122+ this.sourcePosition = sourcePosition;
123+ }
124+
125+ public void setChange(boolean change) {
126+ this.change = change;
127+ }
128+
129+ public void setControlProgramIndex(int controlProgramIndex) {
130+ this.controlProgramIndex = controlProgramIndex;
131+ }
132+
133+ public void setBipProtocol(BIPProtocol bipProtocol) {
134+ this.bipProtocol = bipProtocol;
135+ }
136+}
\ No newline at end of file
--- a/tx-signer/src/main/java/io/bytom/api/Transaction.java
+++ b/tx-signer/src/main/java/io/bytom/api/Transaction.java
@@ -1,14 +1,11 @@
11 package io.bytom.api;
22
3-import com.google.gson.annotations.SerializedName;
4-import io.bytom.common.ParameterizedTypeImpl;
5-import io.bytom.common.SuccessRespon;
63 import io.bytom.common.Utils;
7-import io.bytom.exception.BytomException;
8-import io.bytom.http.Client;
9-import org.apache.log4j.Logger;
4+import io.bytom.types.*;
5+import org.bouncycastle.util.encoders.Hex;
106
11-import java.lang.reflect.Type;
7+import java.io.ByteArrayOutputStream;
8+import java.io.IOException;
129 import java.util.ArrayList;
1310 import java.util.HashMap;
1411 import java.util.List;
@@ -20,7 +17,6 @@ import java.util.Map;
2017
2118 public class Transaction {
2219
23- @SerializedName("tx_id")
2420 public String txID;
2521 /**
2622 * version
@@ -33,321 +29,170 @@ public class Transaction {
3329 /**
3430 * time_range
3531 */
36- @SerializedName("time_range")
3732 public Integer timeRange;
3833
3934 /**
40- * status
41- */
42- public Integer fee;
43-
44- /**
4535 * List of specified inputs for a transaction.
4636 */
47- public List<AnnotatedInput> inputs;
37+ public List<BaseInput> inputs;
4838
4939 /**
5040 * List of specified outputs for a transaction.
5141 */
52- public List<AnnotatedOutput> outputs;
53-
54- // public InputWitnessComponent inputWitnessComponent;
55- private static Logger logger = Logger.getLogger(Transaction.class);
56-
57- public String toJson() {
58- return Utils.serializer.toJson(this);
42+ public List<Output> outputs;
43+
44+ public Transaction(Builder builder) {
45+ this.inputs = builder.inputs;
46+ this.outputs = builder.outputs;
47+ this.version = builder.version;
48+ this.size = builder.size;
49+ this.timeRange = builder.timeRange;
50+ mapTx();
51+ sign();
5952 }
6053
61- public static Transaction fromJson(String json) {
62- return Utils.serializer.fromJson(json, Transaction.class);
63- }
64-
65- public static Transaction fromSuccessRespon(String json) {
66- Type responType = new ParameterizedTypeImpl(SuccessRespon.class, new Class[]{Transaction.class});
67- SuccessRespon<Transaction> result = Utils.serializer.fromJson(json, responType);
68- return result.dataObject;
69- }
54+ public static class Builder {
7055
71- public static Transaction decode(Client client, String txId) throws BytomException {
72- Map<String, Object> req = new HashMap<String, Object>();
73- req.put("raw_transaction", txId);
74- Transaction Transaction =
75- client.request("decode-raw-transaction", req, Transaction.class);
56+ private String txID;
7657
77- logger.info("decode-raw-transaction:");
78- logger.info(Transaction.toJson());
58+ private Integer version = 1;
7959
80- return Transaction;
81- }
60+ private Integer size = 0;
8261
83- public static class Builder {
84- @SerializedName("tx_id")
85- public String txID;
86- public Integer version;
87- public Integer size;
88- @SerializedName("time_range")
89- public Integer timeRange;
62+ private Integer timeRange;
9063
91- Transaction tx;
92- List<AnnotatedInput> inputs;
93- List<AnnotatedOutput> outputs;
64+ private List<BaseInput> inputs;
65+ private List<Output> outputs;
9466
9567 public Builder() {
9668 this.inputs = new ArrayList<>();
9769 this.outputs = new ArrayList<>();
9870 }
9971
100- public Builder addInput(AnnotatedInput input) {
72+ public Builder addInput(BaseInput input) {
10173 this.inputs.add(input);
10274 return this;
10375 }
10476
105- public Builder addOutput(AnnotatedOutput output) {
77+ public Builder addOutput(Output output) {
10678 this.outputs.add(output);
10779 return this;
10880 }
10981
110-
111- public Transaction build(Integer version, Integer timeRange, Integer size) {
112- tx = new Transaction();
113- tx.inputs = this.inputs;
114- tx.outputs = this.outputs;
115- tx.version = version;
116- tx.timeRange = timeRange;
117- tx.size = size;
118- return tx;
119- }
120-
121- public Transaction build(int timeRange) {
122- tx = new Transaction();
123- tx.inputs = this.inputs;
124- tx.outputs = this.outputs;
125- tx.version = 1;
126- tx.size = 0;
127- tx.timeRange = timeRange;
128- return tx;
129- }
130- }
131-
132- public static class AnnotatedInput {
133-
134- @SerializedName("input_id")
135- public String inputID;
136- /**
137- * address
138- */
139- public String address;
140-
141- /**
142- * The number of units of the asset being issued or spent.
143- */
144- public long amount;
145-
146- // /**
147-// * The definition of the asset being issued or spent (possibly null).
148-// */
149-// @SerializedName("asset_definition")
150-// private Map<String, Object> assetDefinition;
151- @SerializedName("asset_definition")
152- public String assetDefinition;
153-
154- /**
155- * The id of the asset being issued or spent.
156- */
157- @SerializedName("asset_id")
158- public String assetId;
159-
160- /**
161- * The control program which must be satisfied to transfer this output.
162- */
163- @SerializedName("control_program")
164- public String controlProgram;
165-
166- /**
167- * The id of the output consumed by this input. Null if the input is an
168- * issuance.
169- */
170- @SerializedName("spent_output_id")
171- public String spentOutputId;
172-
173- /**
174- * The type of the input.<br>
175- * Possible values are "issue" and "spend".
176- */
177- public int type;
178-
179- public String sourceId;
180-
181- public long sourcePosition;
182-
183- public String nonce;
184-
185- private int controlProgramIndex;
186- private boolean change;
187-
188- public int keyIndex;
189- public String chainPath;
190-
191- @SerializedName("witness_component")
192- public InputWitnessComponent witnessComponent;
193-
194- @Override
195- public String toString() {
196- return Utils.serializer.toJson(this);
197- }
198-
199- public int getControlProgramIndex() {
200- return controlProgramIndex;
201- }
202-
203- public AnnotatedInput setControlProgramIndex(int controlProgramIndex) {
204- this.controlProgramIndex = controlProgramIndex;
82+ public Builder setTimeRange(int timeRange) {
83+ this.timeRange = timeRange;
20584 return this;
20685 }
20786
208- public boolean isChange() {
209- return change;
210- }
211-
212- public AnnotatedInput setChange(boolean change) {
213- this.change = change;
214- return this;
215- }
216-
217- public AnnotatedInput setAmount(long amount) {
218- this.amount = amount;
219- return this;
87+ public Transaction build() {
88+ return new Transaction(this);
22089 }
221-
222- public AnnotatedInput setAssetId(String assetId) {
223- this.assetId = assetId;
224- return this;
225- }
226-
227- public AnnotatedInput setControlProgram(String controlProgram) {
228- this.controlProgram = controlProgram;
229- return this;
230- }
231-
232- public AnnotatedInput setType(int type) {
233- this.type = type;
234- return this;
235- }
236-
237- public AnnotatedInput setSourceId(String sourceId) {
238- this.sourceId = sourceId;
239- return this;
240- }
241-
242- public AnnotatedInput setSourcePosition(long sourcePosition) {
243- this.sourcePosition = sourcePosition;
244- return this;
245- }
246-
247- public AnnotatedInput setNonce(String nonce) {
248- this.nonce = nonce;
249- return this;
250- }
251-
252- public AnnotatedInput setAssetDefinition(String assetDefinition) {
253- this.assetDefinition = assetDefinition;
254- return this;
255- }
256-
257- public int getKeyIndex() {
258- return keyIndex;
259- }
260-
261- public AnnotatedInput setKeyIndex(int keyIndex) {
262- this.keyIndex = keyIndex;
263- return this;
264- }
265-
26690 }
26791
268- public static class AnnotatedOutput {
269-
270- /**
271- * address
272- */
273- public String address;
274-
275- /**
276- * The number of units of the asset being controlled.
277- */
278- public long amount;
279-
280- /**
281- * The definition of the asset being controlled (possibly null).
282- */
283- @SerializedName("asset_definition")
284- public Map<String, Object> assetDefinition;
285-
286- /**
287- * The id of the asset being controlled.
288- */
289- @SerializedName("asset_id")
290- public String assetId;
291-
292- /**
293- * The control program which must be satisfied to transfer this output.
294- */
295- @SerializedName("control_program")
296- public String controlProgram;
297-
298- /**
299- * The id of the output.
300- */
301- @SerializedName("id")
302- public String id;
303-
304- /**
305- * The output's position in a transaction's list of outputs.
306- */
307- public Integer position;
308-
309- /**
310- * The type the output.<br>
311- * Possible values are "control" and "retire".
312- */
313- public String type;
314-
315- public AnnotatedOutput setAddress(String address) {
316- this.address = address;
317- return this;
318- }
319-
320- public AnnotatedOutput setAmount(long amount) {
321- this.amount = amount;
322- return this;
323- }
324-
325- public AnnotatedOutput setAssetId(String assetId) {
326- this.assetId = assetId;
327- return this;
92+ private void sign() {
93+ for (BaseInput input : inputs) {
94+ try {
95+ input.buildWitness(txID);
96+ } catch (Exception e) {
97+ e.printStackTrace();
98+ throw new RuntimeException(e);
99+ }
328100 }
101+ }
329102
330- public AnnotatedOutput setControlProgram(String controlProgram) {
331- this.controlProgram = controlProgram;
332- return this;
333- }
103+ public String rawTransaction() {
104+ String rawTransaction;
105+ //开始序列化
106+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
107+ try {
108+ stream.write(7);
109+ // version
110+ if (null != version)
111+ Utils.writeVarint(version, stream);
112+ if (null != timeRange)
113+ Utils.writeVarint(timeRange, stream);
114+ //inputs
115+ if (null != inputs && inputs.size() > 0) {
116+ Utils.writeVarint(inputs.size(), stream);
117+ for (BaseInput input : inputs) {
118+ System.out.println(Hex.toHexString(input.serializeInput()));
119+ stream.write(input.serializeInput());
120+ }
121+ }
122+
123+ //outputs
124+ if (null != outputs && outputs.size() > 0) {
125+ Utils.writeVarint(outputs.size(), stream);
126+ for (Output output : outputs) {
127+ stream.write(output.serializeOutput());
128+ }
129+ }
130+ byte[] data = stream.toByteArray();
131+ rawTransaction = Hex.toHexString(data);
132+ } catch (IOException e) {
133+ throw new RuntimeException(e);
134+ }
135+ return rawTransaction;
136+ }
334137
335- public AnnotatedOutput setPosition(Integer position) {
336- this.position = position;
337- return this;
138+ private void mapTx() {
139+ Map<Hash, Entry> entryMap = new HashMap<>();
140+ ValueSource[] muxSources = new ValueSource[inputs.size()];
141+ List<InputEntry> inputEntries = new ArrayList<>();
142+
143+ try {
144+ for (int i = 0; i < inputs.size(); i++) {
145+ BaseInput input = inputs.get(i);
146+ InputEntry inputEntry = input.convertInputEntry(entryMap, i);
147+ Hash spendID = addEntry(entryMap, inputEntry);
148+ input.setInputID(spendID.toString());
149+
150+ muxSources[i] = new ValueSource(spendID, input.getAssetAmount(), 0);
151+ inputEntries.add(inputEntry);
152+ }
153+
154+ Mux mux = new Mux(muxSources, new Program(1, new byte[]{0x51}));
155+ Hash muxID = addEntry(entryMap, mux);
156+ for (InputEntry inputEntry : inputEntries) {
157+ inputEntry.setDestination(muxID, inputEntry.ordinal, entryMap);
158+ }
159+
160+ List<Hash> resultIDList = new ArrayList<>();
161+ for (int i = 0; i < outputs.size(); i++) {
162+ Output output = outputs.get(i);
163+
164+ AssetAmount amount = new AssetAmount(new AssetID(output.assetId), output.amount);
165+ ValueSource src = new ValueSource(muxID, amount, i);
166+
167+ Hash resultID;
168+ if (output.controlProgram.startsWith("6a")) {
169+ Retirement retirement = new Retirement(src, i);
170+ resultID = addEntry(entryMap, retirement);
171+ } else {
172+ Program prog = new Program(1, Hex.decode(output.controlProgram));
173+ OutputEntry oup = new OutputEntry(src, prog, i);
174+ resultID = addEntry(entryMap, oup);
175+ }
176+
177+ resultIDList.add(resultID);
178+ output.id = resultID.toString();
179+
180+ ValueDestination destination = new ValueDestination(resultID, src.value, 0);
181+ mux.witnessDestinations.add(destination);
182+ }
183+
184+ TxHeader txHeader = new TxHeader(version, size, timeRange, resultIDList.toArray(new Hash[]{}));
185+ Hash txID = addEntry(entryMap, txHeader);
186+ this.txID = txID.toString();
187+
188+ } catch (Exception e) {
189+ throw new RuntimeException(e);
338190 }
339191 }
340192
341- /**
342- * A single witness component, holding information that will become the input
343- * witness.
344- */
345- public static class InputWitnessComponent {
346-
347- /**
348- * The list of signatures made with the specified keys (null unless type is
349- * "signature").
350- */
351- public String[] signatures;
193+ private Hash addEntry(Map<Hash, Entry> entryMap, Entry entry) {
194+ Hash id = entry.entryID();
195+ entryMap.put(id, entry);
196+ return id;
352197 }
353198 }
--- /dev/null
+++ b/tx-signer/src/main/java/io/bytom/api/TransactionSigner.java
@@ -0,0 +1,12 @@
1+package io.bytom.api;
2+
3+/**
4+ * Created by liqiang on 2018/10/24.
5+ */
6+public class TransactionSigner {
7+
8+ public static final byte AssetKeySpace = 0;
9+ public static final byte AccountKeySpace = 1;
10+}
11+
12+
--- a/tx-signer/src/main/java/io/bytom/api/UTXO.java
+++ b/tx-signer/src/main/java/io/bytom/api/UTXO.java
@@ -61,15 +61,15 @@ public class UTXO {
6161 return Utils.serializer.fromJson(json, UTXO.class);
6262 }
6363
64- public static Transaction.AnnotatedInput utxoToAnnotatedInput(UTXO utxo) {
65- Transaction.AnnotatedInput annotatedInput = new Transaction.AnnotatedInput();
66- annotatedInput.setAmount(utxo.amount);
67- annotatedInput.setControlProgram(utxo.program);
68- annotatedInput.setChange(utxo.change);
69- annotatedInput.setAssetId(utxo.assetId);
70- annotatedInput.setControlProgramIndex(utxo.controlProgramIndex);
71- annotatedInput.setSourceId(utxo.sourceId);
72- annotatedInput.setSourcePosition(utxo.sourcePos);
73- return annotatedInput;
64+ public SpendInput toSpendAnnotatedInput() {
65+ SpendInput spendInput = new SpendInput();
66+ spendInput.setAmount(amount);
67+ spendInput.setProgram(program);
68+ spendInput.setChange(change);
69+ spendInput.setAssetId(assetId);
70+ spendInput.setControlProgramIndex(controlProgramIndex);
71+ spendInput.setSourceId(sourceId);
72+ spendInput.setSourcePosition(sourcePos);
73+ return spendInput;
7474 }
7575 }
--- /dev/null
+++ b/tx-signer/src/main/java/io/bytom/api/WitnessComponent.java
@@ -0,0 +1,43 @@
1+package io.bytom.api;
2+
3+import java.util.ArrayList;
4+import java.util.List;
5+
6+/**
7+ * A single witness component, holding information that will become the input
8+ * witness.
9+ */
10+public class WitnessComponent {
11+
12+ /**
13+ * The list of witnesses made with the specified keys (null unless type is
14+ * "signature").
15+ */
16+ private List<String> witnesses;
17+
18+ private String rootPrivateKey;
19+
20+ public WitnessComponent() {
21+ witnesses = new ArrayList<>();
22+ }
23+
24+ public int size() {
25+ return witnesses.size();
26+ }
27+
28+ public String getWitness(int index) {
29+ return witnesses.get(index);
30+ }
31+
32+ public void appendWitness(String witness) {
33+ witnesses.add(witness);
34+ }
35+
36+ public String getRootPrivateKey() {
37+ return rootPrivateKey;
38+ }
39+
40+ public void setRootPrivateKey(String rootPrivateKey) {
41+ this.rootPrivateKey = rootPrivateKey;
42+ }
43+}
\ No newline at end of file
--- a/tx-signer/src/main/java/io/bytom/common/Constants.java
+++ /dev/null
@@ -1,13 +0,0 @@
1-package io.bytom.common;
2-
3-/**
4- * Created by liqiang on 2018/10/17.
5- */
6-public class Constants {
7-
8- public static int INPUT_TYPE_ISSUANCE = 0;
9-
10- public static int INPUT_TYPE_SPEND = 1;
11-
12- public static int INPUT_TYPE_COINBASE = 2;
13-}
--- a/tx-signer/src/main/java/io/bytom/common/DerivePrivateKey.java
+++ b/tx-signer/src/main/java/io/bytom/common/DerivePrivateKey.java
@@ -10,25 +10,23 @@ import java.security.SignatureException;
1010 public class DerivePrivateKey {
1111 //bip44 派生子秘钥
1212 //accountIndex 默认为1
13- public static byte[] derivePrivateKey(String rootPriv, int accountIndex, boolean change, int programIndex) throws NoSuchAlgorithmException, SignatureException, InvalidKeyException {
14- byte[] xprv = Hex.decode(rootPriv);
13+ public static byte[] bip44derivePrvKey(String rootPriv, int accountIndex, boolean change, int programIndex) throws NoSuchAlgorithmException, SignatureException, InvalidKeyException {
1514 byte[][] paths = PathUtil.getBip44Path(accountIndex, change, programIndex);
16- byte[] res = xprv;
15+ byte[] res = Hex.decode(rootPriv);
1716 for (int i = 0; i < paths.length; i++) {
1817 byte[] xpub = DeriveXpub.deriveXpub(res);
19- res = NonHardenedChild.NHchild(paths[i], res, xpub);
18+ res = NonHardenedChild.nhChild(paths[i], res, xpub);
2019 }
2120 return res;
2221 }
2322
2423 //BIP32 派生子秘钥 issue 需要用到BIP32派生规则
25- public static byte[] derivePrivateKey(String rootPrivateKey, int keyIndex) throws NoSuchAlgorithmException, SignatureException, InvalidKeyException {
26- byte[] xprv = Hex.decode(rootPrivateKey);
27- byte[] res = xprv;
28- byte[][] paths = PathUtil.getBip32Path(keyIndex);
24+ public static byte[] bip32derivePrvKey(String rootPrivateKey, int accountIndex, byte keySpace, long ...programIndex) throws NoSuchAlgorithmException, SignatureException, InvalidKeyException {
25+ byte[] res = Hex.decode(rootPrivateKey);
26+ byte[][] paths = PathUtil.getBip32Path(keySpace, accountIndex, programIndex);
2927 for (int i = 0; i < paths.length; i++) {
3028 byte[] xpub = DeriveXpub.deriveXpub(res);
31- res = NonHardenedChild.NHchild(paths[i], res, xpub);
29+ res = NonHardenedChild.nhChild(paths[i], res, xpub);
3230 }
3331 return res;
3432 }
--- a/tx-signer/src/main/java/io/bytom/common/DeriveXpub.java
+++ b/tx-signer/src/main/java/io/bytom/common/DeriveXpub.java
@@ -6,18 +6,11 @@ public class DeriveXpub {
66 public static byte[] deriveXpub(byte[] xprv) {
77 byte[] xpub = new byte[xprv.length];
88 byte[] scalar = new byte[xprv.length / 2];
9-// for (int i = 0; i < xprv.length / 2; i++) {
10-// scalar[i] = xprv[i];
11-// }
9+
1210 System.arraycopy(xprv, 0, scalar, 0, xprv.length / 2);
1311 byte[] buf = Ed25519.scalarMultWithBaseToBytes(scalar);
14-// for (int i = 0; i < buf.length; i++) {
15-// xpub[i] = buf[i];
16-// }
12+
1713 System.arraycopy(buf, 0, xpub, 0, buf.length);
18-// for (int i = xprv.length / 2; i < xprv.length; i++) {
19-// xpub[i] = xprv[i];
20-// }
2114 System.arraycopy(xprv, xprv.length / 2, xpub, xprv.length / 2, xprv.length / 2);
2215 return xpub;
2316 }
--- a/tx-signer/src/main/java/io/bytom/common/ExpandedPrivateKey.java
+++ b/tx-signer/src/main/java/io/bytom/common/ExpandedPrivateKey.java
@@ -9,7 +9,7 @@ import java.security.NoSuchAlgorithmException;
99 import java.security.SignatureException;
1010
1111 public class ExpandedPrivateKey {
12- public static byte[] HMacSha512(byte[] data, byte[] key)
12+ public static byte[] hmacSha512(byte[] data, byte[] key)
1313 throws SignatureException, NoSuchAlgorithmException, InvalidKeyException {
1414 SecretKeySpec signingKey = new SecretKeySpec(key, "HmacSHA512");
1515 Mac mac = Mac.getInstance("HmacSHA512");
@@ -17,10 +17,10 @@ public class ExpandedPrivateKey {
1717 return mac.doFinal(data);
1818 }
1919
20- public static byte[] ExpandedPrivateKey(byte[] data)
20+ public static byte[] expandedPrivateKey(byte[] data)
2121 throws SignatureException, NoSuchAlgorithmException, InvalidKeyException {
2222 // "457870616e64" is "Expand" hex.
23- byte[] res = HMacSha512(data, Hex.decode("457870616e64"));
23+ byte[] res = hmacSha512(data, Hex.decode("457870616e64"));
2424 for (int i = 0; i <= 31; i++) {
2525 res[i] = data[i];
2626 }
--- a/tx-signer/src/main/java/io/bytom/common/NonHardenedChild.java
+++ b/tx-signer/src/main/java/io/bytom/common/NonHardenedChild.java
@@ -11,7 +11,7 @@ import java.security.SignatureException;
1111
1212 public class NonHardenedChild {
1313
14- private static byte[] HMacSha512(byte[] data, byte[] key)
14+ private static byte[] hmacSha512(byte[] data, byte[] key)
1515 throws NoSuchAlgorithmException, InvalidKeyException {
1616 SecretKeySpec signingKey = new SecretKeySpec(key, "HmacSHA512");
1717 Mac mac = Mac.getInstance("HmacSHA512");
@@ -19,7 +19,7 @@ public class NonHardenedChild {
1919 return mac.doFinal(data);
2020 }
2121
22- public static byte[] NHchild(byte[] path, byte[] xprv, byte[] xpub) throws NoSuchAlgorithmException, SignatureException, InvalidKeyException {
22+ public static byte[] nhChild(byte[] path, byte[] xprv, byte[] xpub) throws NoSuchAlgorithmException, SignatureException, InvalidKeyException {
2323 // begin build data
2424 ByteArrayOutputStream out = new ByteArrayOutputStream();
2525 out.write('N');
@@ -34,7 +34,7 @@ public class NonHardenedChild {
3434 // end build key
3535
3636 // doFinal()
37- byte[] res = HMacSha512(data, key);
37+ byte[] res = hmacSha512(data, key);
3838
3939 //begin operate res[:32]
4040 byte[] f = new byte[res.length / 2];
@@ -76,7 +76,7 @@ public class NonHardenedChild {
7676 byte[] res = xprv;
7777 for (int i = 0; i < hpaths.length; i++) {
7878 byte[] xpub = DeriveXpub.deriveXpub(res);
79- res = NonHardenedChild.NHchild(paths[i], res, xpub);
79+ res = NonHardenedChild.nhChild(paths[i], res, xpub);
8080 }
8181 return res;
8282 }
--- a/tx-signer/src/main/java/io/bytom/common/Utils.java
+++ b/tx-signer/src/main/java/io/bytom/common/Utils.java
@@ -3,6 +3,7 @@ package io.bytom.common;
33 import com.google.gson.Gson;
44 import com.google.gson.GsonBuilder;
55 import io.bytom.types.ExpandedKeys;
6+import org.bouncycastle.jcajce.provider.digest.SHA3;
67 import org.bouncycastle.util.encoders.Hex;
78
89 import java.io.ByteArrayOutputStream;
@@ -76,7 +77,7 @@ public class Utils {
7677 }
7778
7879 public static ExpandedKeys expandedPriKey(String priKey, String key) throws NoSuchAlgorithmException, SignatureException, InvalidKeyException {
79- byte[] hashPriKey = ExpandedPrivateKey.HMacSha512(Hex.decode(priKey), key.getBytes());
80+ byte[] hashPriKey = ExpandedPrivateKey.hmacSha512(Hex.decode(priKey), key.getBytes());
8081 //begin operate res[:32]
8182 byte[] f = new byte[hashPriKey.length / 2];
8283 System.arraycopy(hashPriKey, 0, f, 0, hashPriKey.length / 2);
@@ -101,4 +102,15 @@ public class Utils {
101102 return null;
102103
103104 }
105+
106+ public static byte[] hashFn(byte[] hashedInputHex, byte[] txID) {
107+
108+ SHA3.Digest256 digest256 = new SHA3.Digest256();
109+ // data = hashedInputHex + txID
110+ ByteArrayOutputStream out = new ByteArrayOutputStream();
111+ out.write(hashedInputHex, 0, hashedInputHex.length);
112+ out.write(txID, 0, txID.length);
113+ byte[] data = out.toByteArray();
114+ return digest256.digest(data);
115+ }
104116 }
--- /dev/null
+++ b/tx-signer/src/main/java/io/bytom/common/VMUtil.java
@@ -0,0 +1,100 @@
1+package io.bytom.common;
2+
3+import java.io.ByteArrayOutputStream;
4+import java.io.IOException;
5+
6+public class VMUtil {
7+
8+ private static final byte OP_0 = (byte) 0x00;
9+ private static final byte OP_1 = (byte) 0x51;
10+ private static final byte OP_PUSHDATA1 = (byte) 0x4c;
11+ private static final byte OP_PUSHDATA2 = (byte) 0x4d;
12+ private static final byte OP_PUSHDATA4 = (byte) 0x43;
13+ private static final byte OP_TXSIGHASH = (byte) 0xae;
14+ private static final byte OP_CHECKMULTISIG = (byte) 0xad;
15+
16+ public static byte[] p2spMultiSigProgram(byte[][] pubKeys, int nRequired) {
17+ checkMultiSigParams(nRequired, pubKeys.length);
18+ ByteArrayOutputStream program = new ByteArrayOutputStream();
19+ program.write(OP_TXSIGHASH);
20+
21+ for (byte[] pubKey : pubKeys) {
22+ try {
23+ program.write(pushDataBytes(pubKey));
24+ program.write(pushDataInt64(nRequired));
25+ program.write(pushDataInt64(pubKeys.length));
26+ } catch (IOException e) {
27+ e.printStackTrace();
28+ }
29+ }
30+ program.write(OP_CHECKMULTISIG);
31+ return program.toByteArray();
32+ }
33+
34+ private static void checkMultiSigParams(int nRequired, int nPubkeys) {
35+ if (nRequired < 0 || nPubkeys < 0 || nRequired > nPubkeys || (nRequired == 0 && nPubkeys > 0)) {
36+ throw new IllegalArgumentException();
37+ }
38+ }
39+
40+ private static byte[] pushDataBytes(byte[] data) {
41+ int len = data.length;
42+ if (len == 0) {
43+ return new byte[] {OP_0};
44+ }
45+ if (len <= 75) {
46+ byte[] dest = new byte[1 + len];
47+ dest[0] = (byte) len;
48+ System.arraycopy(data, 0, dest, 1, len);
49+ return dest;
50+ }
51+ if (len < 256) {
52+ byte[] dest = new byte[2 + len];
53+ dest[0] = OP_PUSHDATA1;
54+ dest[1] = (byte) len;
55+ System.arraycopy(data, 0, dest, 2, len);
56+ return dest;
57+ }
58+ if (len < 65536) {
59+ byte[] dest = new byte[3 + len];
60+ dest[0] = OP_PUSHDATA2;
61+ dest[1] = (byte) len;
62+ dest[2] = (byte) (len >> 8);
63+ System.arraycopy(data, 0, dest, 3, len);
64+ return dest;
65+ }
66+ byte[] dest = new byte[5 + len];
67+ dest[0] = OP_PUSHDATA4;
68+ dest[1] = (byte) len;
69+ dest[2] = (byte) (len >> 8);
70+ dest[3] = (byte) (len >> 16);
71+ dest[4] = (byte) (len >> 24);
72+ System.arraycopy(data, 0, dest, 5, len);
73+ return dest;
74+ }
75+
76+ private static byte[] pushDataInt64(long n) {
77+ if (n == 0) {
78+ return new byte[] {OP_0};
79+ }
80+ if (n >= 1 && n <= 16) {
81+ return new byte[] {(byte) (OP_1 + (byte) n - 1)};
82+ }
83+ return pushDataBytes(int64Bytes(n));
84+ }
85+
86+ private static byte[] int64Bytes(long n) {
87+ byte[] bytes = new byte[8];
88+ int i = 0;
89+ while (n != 0) {
90+ bytes[i] = (byte) n;
91+ n >>= 8;
92+ i++;
93+ }
94+ byte[] res = new byte[i];
95+ System.arraycopy(bytes, 0, res, 0, i);
96+ return res;
97+ }
98+
99+}
100+
--- a/tx-signer/src/main/java/io/bytom/types/Asset.java
+++ b/tx-signer/src/main/java/io/bytom/types/Asset.java
@@ -69,7 +69,7 @@ public class Asset {
6969 }
7070
7171 private String computeIssueProgram(String rootKey, int keyIndex) throws NoSuchAlgorithmException, SignatureException, InvalidKeyException {
72- byte[] derivePrivateKey = DerivePrivateKey.derivePrivateKey(rootKey, keyIndex);
72+ byte[] derivePrivateKey = DerivePrivateKey.bip32derivePrvKey(rootKey, keyIndex, (byte) 0, 1);
7373 byte[] deriveXpub = DeriveXpub.deriveXpub(derivePrivateKey);
7474
7575 String issueProgram = "ae20" + Hex.toHexString(deriveXpub).substring(0, 64) + "5151ad";
--- /dev/null
+++ b/tx-signer/src/main/java/io/bytom/types/InputEntry.java
@@ -0,0 +1,10 @@
1+package io.bytom.types;
2+
3+import java.util.Map;
4+
5+public abstract class InputEntry extends Entry {
6+
7+ public int ordinal;
8+
9+ public abstract void setDestination(Hash id, long pos, Map<Hash, Entry> entryMap);
10+}
--- a/tx-signer/src/main/java/io/bytom/types/Issue.java
+++ b/tx-signer/src/main/java/io/bytom/types/Issue.java
@@ -1,11 +1,11 @@
11 package io.bytom.types;
22
33 import java.io.ByteArrayOutputStream;
4+import java.util.Map;
45
5-public class Issue extends Entry {
6+public class Issue extends InputEntry {
67 public Hash nonceHash;
78 public AssetAmount assetAmount;
8- public int ordinal;
99 public AssetDefinition assetDefinition;
1010 public ValueDestination witnessDestination;
1111
@@ -15,8 +15,9 @@ public class Issue extends Entry {
1515 this.ordinal = ordinal;
1616 }
1717
18- public void setDestination(Hash id, AssetAmount val, long pos) {
19- this.witnessDestination = new ValueDestination(id, val, pos);
18+ @Override
19+ public void setDestination(Hash id, long pos, Map<Hash, Entry> entryMap) {
20+ this.witnessDestination = new ValueDestination(id, this.assetAmount, pos);
2021 }
2122
2223 @Override
--- a/tx-signer/src/main/java/io/bytom/types/Output.java
+++ b/tx-signer/src/main/java/io/bytom/types/OutputEntry.java
@@ -2,7 +2,7 @@ package io.bytom.types;
22
33 import java.io.ByteArrayOutputStream;
44
5-public class Output extends Entry {
5+public class OutputEntry extends Entry {
66
77 public ValueSource source;
88
@@ -10,13 +10,13 @@ public class Output extends Entry {
1010
1111 public Integer ordinal;
1212
13- public Output() {
13+ public OutputEntry() {
1414 this.source = new ValueSource();
1515 this.controlProgram = new Program();
1616 }
1717
1818
19- public Output(ValueSource source, Program controlProgram, Integer ordinal) {
19+ public OutputEntry(ValueSource source, Program controlProgram, Integer ordinal) {
2020 this.source = source;
2121 this.controlProgram = controlProgram;
2222 this.ordinal = ordinal;
--- a/tx-signer/src/main/java/io/bytom/types/Spend.java
+++ b/tx-signer/src/main/java/io/bytom/types/Spend.java
@@ -1,8 +1,9 @@
11 package io.bytom.types;
22
33 import java.io.ByteArrayOutputStream;
4+import java.util.Map;
45
5-public class Spend extends Entry {
6+public class Spend extends InputEntry {
67
78 public Hash spentOutputID;
89
@@ -17,8 +18,10 @@ public class Spend extends Entry {
1718 this.ordinal = ordinal;
1819 }
1920
20- public void setDestination(Hash id, AssetAmount val, long pos) {
21- this.witnessDestination = new ValueDestination(id, val, pos);
21+ @Override
22+ public void setDestination(Hash id, long pos, Map<Hash, Entry> entryMap) {
23+ OutputEntry spendOutput = (OutputEntry) entryMap.get(this.spentOutputID);
24+ this.witnessDestination = new ValueDestination(id, spendOutput.source.value, pos);
2225 }
2326
2427 @Override
--- a/tx-signer/src/main/java/io/bytom/util/PathUtil.java
+++ b/tx-signer/src/main/java/io/bytom/util/PathUtil.java
@@ -32,23 +32,27 @@ public class PathUtil {
3232 if (change) {
3333 changeStr = "01000000";
3434 }
35- byte[][] paths = new byte[][]{
35+ return new byte[][]{
3636 Hex.decode("2c000000"),
3737 Hex.decode("99000000"),
3838 Hex.decode(accountIndexStr),
3939 Hex.decode(changeStr),
4040 Hex.decode(programIndexStr),
4141 };
42- return paths;
4342 }
4443
45- public static byte[][] getBip32Path(int accountIndex) {
44+ public static byte[][] getBip32Path(byte keySpace, long accountIndex, long ...itemIndexes) {
4645 byte[] signerPath = new byte[9];
47- byte[] path = ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN).putInt(accountIndex).array();
46+ signerPath[0] = keySpace;
47+ byte[] path = ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN).putLong(accountIndex).array();
4848 System.arraycopy(path, 0, signerPath, 1, 8);
49- byte[][] paths = new byte[][]{
50- signerPath
51- };
52- return paths;
49+
50+ byte[][] res = new byte[1 + itemIndexes.length][];
51+ res[0] = signerPath;
52+ for (int i = 0; i < itemIndexes.length; i++) {
53+ path = ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN).putLong(itemIndexes[i]).array();
54+ res[i + 1] = path;
55+ }
56+ return res;
5357 }
5458 }
--- a/tx-signer/src/test/java/io/bytom/AppTest.java
+++ b/tx-signer/src/test/java/io/bytom/AppTest.java
@@ -1,83 +1,132 @@
11 package io.bytom;
22
33 import io.bytom.api.*;
4-import io.bytom.exception.BytomException;
5-import io.bytom.http.Client;
64 import org.bouncycastle.util.encoders.Hex;
75 import org.junit.Test;
86
9-import java.security.InvalidKeyException;
10-import java.security.NoSuchAlgorithmException;
11-import java.security.SignatureException;
12-
137 public class AppTest {
148 String rootKey = "38d2c44314c401b3ea7c23c54e12c36a527aee46a7f26b82443a46bf40583e439dea25de09b0018b35a741d8cd9f6ec06bc11db49762617485f5309ab72a12d4";
159 String btmAssetID = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";
1610
1711
1812 @Test
19- public void testSpend() throws NoSuchAlgorithmException, SignatureException, InvalidKeyException {
20- Transaction.AnnotatedInput input = btmUtxoToInput();
21- Transaction Transaction = new Transaction.Builder()
22-// .addInput(new Transaction.AnnotatedInput().setType(1).setAssetId(btmAssetID).setAmount(880000000).setControlProgram("001414d362694eacfa110dc20dec77d610d22340f95b").
23-// setChange(false).setControlProgramIndex(2).setSourceId("fc43933d1c601b2503b033e31d3bacfa5c40ccb2ff0be6e94d8332462e0928a3").setSourcePosition(0))
24- .addInput(input.setType(1))
25- .addOutput(new Transaction.AnnotatedOutput().setAssetId(btmAssetID).setAmount(49100000).setControlProgram("001414d362694eacfa110dc20dec77d610d22340f95b"))
26- .addOutput(new Transaction.AnnotatedOutput().setAssetId(btmAssetID).setAmount(10000000).setControlProgram("0020fa56ca7d47f8528e68e120d0e052885faeb9d090d238fa4266bdde21b137513c"))
27- .build(200000);
28- io.bytom.api.Transaction transaction = MapTransaction.mapTx(Transaction);
29- SignTransaction signTransaction = new SignTransaction();
30- String rawTransaction = signTransaction.rawTransaction(rootKey, transaction);
31- System.out.println(rawTransaction);
13+ public void testSpendBIP44() {
14+ SpendInput input = new SpendInput(btmAssetID, 9800000000L, "0014cb9f2391bafe2bc1159b2c4c8a0f17ba1b4dd94e");
15+ input.setSourcePosition(2);
16+ input.setSourceId("4b5cb973f5bef4eadde4c89b92ee73312b940e84164da0594149554cc8a2adea");
17+ input.setChange(true);
18+ input.setControlProgramIndex(457);
19+ input.setKeyIndex(1);
20+ input.setRootPrivateKey("4864bae85cf38bfbb347684abdbc01e311a24f99e2c7fe94f3c071d9c83d8a5a349722316972e382c339b79b7e1d83a565c6b3e7cf46847733a47044ae493257");
21+
22+ Transaction tx = new Transaction.Builder()
23+ .addInput(input)
24+ .addOutput(new Output(btmAssetID, 8800000000L, "0014a82f02bc37bc5ed87d5f9fca02f8a6a7d89cdd5c"))
25+ .addOutput(new Output(btmAssetID, 900000000L, "00200824e931fb806bd77fdcd291aad3bd0a4493443a4120062bd659e64a3e0bac66"))
26+ .setTimeRange(0)
27+ .build();
28+
29+ String rawTransaction = tx.rawTransaction();
30+ assert rawTransaction.equals("070100010160015e4b5cb973f5bef4eadde4c89b92ee73312b940e84164da0594149554cc8a2adeaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80c480c1240201160014cb9f2391bafe2bc1159b2c4c8a0f17ba1b4dd94e6302401cb779288be890a28c5209036da1a27d9fe74a51c38e0a10db4817bcf4fd05f68580239eea7dcabf19f144c77bf13d3674b5139aa51a99ba58118386c190af0e20bcbe020b05e1b7d0825953d92bf47897be08cd7751a37adb95d6a2e5224f55ab02013dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80b095e42001160014a82f02bc37bc5ed87d5f9fca02f8a6a7d89cdd5c000149ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80d293ad03012200200824e931fb806bd77fdcd291aad3bd0a4493443a4120062bd659e64a3e0bac6600");
31+ }
32+
33+ @Test
34+ public void testSpendBIP32() {
35+ SpendInput input = new SpendInput(btmAssetID, 11718900000L, "0014085a02ecdf934a56343aa59a3dec9d9feb86ee43");
36+ input.setSourceId("5ac79a73db78e5c9215b37cb752f0147d1157c542bb4884908ceb97abc33fe0a");
37+ input.setSourcePosition(0);
38+ input.setRootPrivateKey("4864bae85cf38bfbb347684abdbc01e311a24f99e2c7fe94f3c071d9c83d8a5a349722316972e382c339b79b7e1d83a565c6b3e7cf46847733a47044ae493257");
39+ input.setChange(true);
40+ input.setKeyIndex(1);
41+ input.setBipProtocol(BIPProtocol.BIP32);
42+ input.setControlProgramIndex(447);
43+
44+ Transaction tx = new Transaction.Builder()
45+ .addInput(input)
46+ .addOutput(new Output(btmAssetID, 1718900000L, "001409a0961e9b592a944ca3ded0ef9403fdb25b3793"))
47+ .addOutput(new Output(btmAssetID, 9900000000L, "00145ade29df622cc68d0473aa1a20fb89690451c66e"))
48+ .setTimeRange(0)
49+ .build();
50+
51+ String rawTx = tx.rawTransaction();
52+ assert rawTx.equals("070100010160015e5ac79a73db78e5c9215b37cb752f0147d1157c542bb4884908ceb97abc33fe0affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0f280d42b0001160014085a02ecdf934a56343aa59a3dec9d9feb86ee43630240e37864ef905e943deb97e58b861c97f04f07c1d33b1ce4f1b6edddff0c8956a57d86fc922c45446cd38ea613fc3c9b7d5a2596f3dca7a7212f6da55b9515110420a29601468f08c57ca9c383d28736a9d5c7737cd483126d8db3d85490fe497b3502013dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0aad1b3060116001409a0961e9b592a944ca3ded0ef9403fdb25b379300013dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8086d8f024011600145ade29df622cc68d0473aa1a20fb89690451c66e00");
3253 }
3354
3455 //issue asset
3556 @Test
36- public void testIssue() throws NoSuchAlgorithmException, SignatureException, InvalidKeyException {
37-
38- String issueAssetId = "a680606d49daae62ef9cb03263ca82a0b1e3184bb6311ea52a5189207f718789";
39- String program = "ae204cae24c2cec15491e70fc554026469496e373df9b9970b23acac8b782da0822d5151ad";
40- String assetDefine = "7b0a202022646563696d616c73223a20382c0a2020226465736372697074696f6e223a207b7d2c0a2020226e616d65223a2022222c0a20202273796d626f6c223a2022220a7d";
41- Transaction.AnnotatedInput input = btmUtxoToInput();
42- Transaction Transaction = new Transaction.Builder()
43- .addInput(new Transaction.AnnotatedInput().setType(0).setAssetId(issueAssetId).setControlProgram(program).setAmount(100000000).setAssetDefinition(assetDefine).setChange(false).setKeyIndex(13))
44-// .addInput(new Transaction.AnnotatedInput().setType(1).setAssetId(btmAssetID).setAmount(880000000).setControlProgram("001414d362694eacfa110dc20dec77d610d22340f95b").
45-// setChange(false).setControlProgramIndex(2).setSourceId("fc43933d1c601b2503b033e31d3bacfa5c40ccb2ff0be6e94d8332462e0928a3").setSourcePosition(0))
46- .addInput(input.setType(1))
47- .addOutput(new Transaction.AnnotatedOutput().setAssetId(issueAssetId).setAmount(100000000).setControlProgram("001414d362694eacfa110dc20dec77d610d22340f95b"))
48-// .addOutput(new Transaction.AnnotatedOutput().setAssetId(btmAssetID).setAmount(870000000).setControlProgram("001414d362694eacfa110dc20dec77d610d22340f95b"))
49- .build(2000000);
50- MapTransaction.mapTx(Transaction);
51- SignTransaction sign = new SignTransaction();
52- String rawTransaction = sign.rawTransaction(rootKey, Transaction);
53- System.out.println(rawTransaction);
57+ public void testIssue() {
58+ IssuanceInput issuanceInput = new IssuanceInput();
59+ issuanceInput.setAssetId("7b38dc897329a288ea31031724f5c55bcafec80468a546955023380af2faad14");
60+ issuanceInput.setAmount(100000000000L);
61+ issuanceInput.setProgram("ae2054a71277cc162eb3eb21b5bd9fe54402829a53b294deaed91692a2cd8a081f9c5151ad");
62+ issuanceInput.setNonce("ac9d5a527f5ab00a");
63+ issuanceInput.setKeyIndex(5);
64+ issuanceInput.setAssetDefinition("7b0a202022646563696d616c73223a20382c0a2020226465736372697074696f6e223a207b7d2c0a2020226e616d65223a2022222c0a20202273796d626f6c223a2022220a7d");
65+ issuanceInput.setRootPrivateKey("4864bae85cf38bfbb347684abdbc01e311a24f99e2c7fe94f3c071d9c83d8a5a349722316972e382c339b79b7e1d83a565c6b3e7cf46847733a47044ae493257");
66+
67+ SpendInput spendInput = new SpendInput(btmAssetID, 9800000000L, "0014cb9f2391bafe2bc1159b2c4c8a0f17ba1b4dd94e");
68+ spendInput.setBipProtocol(BIPProtocol.BIP32);
69+ spendInput.setKeyIndex(1);
70+ spendInput.setChange(true);
71+ spendInput.setSourceId("4b5cb973f5bef4eadde4c89b92ee73312b940e84164da0594149554cc8a2adea");
72+ spendInput.setSourcePosition(2);
73+ spendInput.setControlProgramIndex(457);
74+ spendInput.setRootPrivateKey("4864bae85cf38bfbb347684abdbc01e311a24f99e2c7fe94f3c071d9c83d8a5a349722316972e382c339b79b7e1d83a565c6b3e7cf46847733a47044ae493257");
75+
76+ Transaction tx = new Transaction.Builder()
77+ .addInput(issuanceInput)
78+ .addInput(spendInput)
79+ .addOutput(new Output("7b38dc897329a288ea31031724f5c55bcafec80468a546955023380af2faad14", 100000000000L, "001437e1aec83a4e6587ca9609e4e5aa728db7007449"))
80+ .addOutput(new Output(btmAssetID, 9700000000L, "00148be1104e04734e5edaba5eea2e85793896b77c56"))
81+ .setTimeRange(0)
82+ .build();
83+
84+ String rawTx = tx.rawTransaction();
85+ assert rawTx.equals("0701000201300008ac9d5a527f5ab00a7b38dc897329a288ea31031724f5c55bcafec80468a546955023380af2faad1480d0dbc3f402b001467b0a202022646563696d616c73223a20382c0a2020226465736372697074696f6e223a207b7d2c0a2020226e616d65223a2022222c0a20202273796d626f6c223a2022220a7d0125ae2054a71277cc162eb3eb21b5bd9fe54402829a53b294deaed91692a2cd8a081f9c5151ad01401ba3a3f2d3e9887e20da8d43666cc1602bb5421ffea9d2b4d7df9816fc174a43b25fb00db4775b10b679a8b5f8aa28555ebb8fb49f6275d43283daf8f5ac340d0160015e4b5cb973f5bef4eadde4c89b92ee73312b940e84164da0594149554cc8a2adeaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80c480c1240201160014cb9f2391bafe2bc1159b2c4c8a0f17ba1b4dd94e630240341c875fc815dc13ad811c9aa7c7af28a5c78765f77fd5a36dac263278fd605ae0553e34a1e645148370b7b397142ddbcd67ba33483279ab9894169b51e4f101201381d35e235813ad1e62f9a602c82abee90565639cc4573568206b55bcd2aed902013e7b38dc897329a288ea31031724f5c55bcafec80468a546955023380af2faad1480d0dbc3f4020116001437e1aec83a4e6587ca9609e4e5aa728db700744900013dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8082a99124011600148be1104e04734e5edaba5eea2e85793896b77c5600");
5486 }
5587
5688
5789 //retire asset
5890 @Test
59- public void testRetire() throws NoSuchAlgorithmException, SignatureException, InvalidKeyException {
91+ public void testRetire() {
6092 String arbitrary = "77656c636f6d65efbc8ce6aca2e8bf8ee69da5e588b0e58e9fe5ad90e4b896e7958c";
6193 String retireControlProgram = "6a"+Integer.toString(Hex.decode(arbitrary).length,16)+arbitrary;
6294 String assetId1 = "207265909236260b30942a6b00e30ceb769e0e58156b6482bac64117619c9dcf";
95+
96+ SpendInput input1 = new SpendInput(btmAssetID, 289100000, "0014f1dc52048f439ac7fd74f8106a21da78f00de48f");
97+ input1.setRootPrivateKey(rootKey);
98+ input1.setChange(true);
99+ input1.setControlProgramIndex(41);
100+ input1.setSourceId("0b2cff11d1d056d95237a5f2d06059e5395e86f60e69c1e8201ea624911c0c65");
101+ input1.setSourcePosition(0);
102+
103+ SpendInput input2 = new SpendInput(assetId1, 70000000000L, "0014bb8a039726df1b649738e9973db14a4b4fd4becf");
104+ input2.setRootPrivateKey(rootKey);
105+ input2.setChange(true);
106+ input2.setControlProgramIndex(26);
107+ input2.setSourceId("be0ac837e832c34a02968e54dab4f95cbeceb9fb01cd378310f6ea32219ee29b");
108+ input2.setSourcePosition(1);
109+
110+ Output output1 = new Output(btmAssetID, 279100000, "001414d362694eacfa110dc20dec77d610d22340f95b");
111+ Output output2 = new Output(assetId1, 10000000000L, retireControlProgram);
112+ Output output3 = new Output(assetId1, 60000000000L, "0014bb8a039726df1b649738e9973db14a4b4fd4becf");
113+
63114 Transaction transaction = new Transaction.Builder()
64- .addInput(new Transaction.AnnotatedInput().setType(1).setAssetId(btmAssetID).setAmount(289100000).setControlProgram("0014f1dc52048f439ac7fd74f8106a21da78f00de48f").
65- setChange(true).setControlProgramIndex(41).setSourceId("0b2cff11d1d056d95237a5f2d06059e5395e86f60e69c1e8201ea624911c0c65").setSourcePosition(0))
66- .addInput(new Transaction.AnnotatedInput().setType(1).setAssetId(assetId1).setAmount(70000000000l).setControlProgram("0014bb8a039726df1b649738e9973db14a4b4fd4becf").
67- setChange(true).setControlProgramIndex(26).setSourceId("be0ac837e832c34a02968e54dab4f95cbeceb9fb01cd378310f6ea32219ee29b").setSourcePosition(1))
68- .addOutput(new Transaction.AnnotatedOutput().setAssetId(btmAssetID).setAmount(279100000).setControlProgram("001414d362694eacfa110dc20dec77d610d22340f95b"))
69- .addOutput(new Transaction.AnnotatedOutput().setAssetId(assetId1).setAmount(10000000000l).setControlProgram(retireControlProgram))
70- .addOutput(new Transaction.AnnotatedOutput().setAssetId(assetId1).setAmount(60000000000l).setControlProgram("0014bb8a039726df1b649738e9973db14a4b4fd4becf"))
71- .build(2000000);
72- MapTransaction.mapTx(transaction);
73- SignTransaction sign = new SignTransaction();
74- String rawTransaction = sign.rawTransaction(rootKey, transaction);
75- System.out.println(rawTransaction);
115+ .addInput(input1)
116+ .addInput(input2)
117+ .addOutput(output1)
118+ .addOutput(output2)
119+ .addOutput(output3)
120+ .setTimeRange(2000000)
121+ .build();
122+
123+ String rawTransaction = transaction.rawTransaction();
124+ assert rawTransaction.equals("070180897a020160015e0b2cff11d1d056d95237a5f2d06059e5395e86f60e69c1e8201ea624911c0c65ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0a1ed89010001160014f1dc52048f439ac7fd74f8106a21da78f00de48f6302401660121218ab96d9f22cce712541ca34c53f4da40450669854341ca9624ad1cf10d1bfc96449fad5406224afd253ccfbdeab683f7ec7f9ee8f45e47a0c58500f2031ecc1bdd5fb9b40016358340b87646ea39faf55c0c105205cfdfdc6184725f40161015fbe0ac837e832c34a02968e54dab4f95cbeceb9fb01cd378310f6ea32219ee29b207265909236260b30942a6b00e30ceb769e0e58156b6482bac64117619c9dcf80f8cce284020101160014bb8a039726df1b649738e9973db14a4b4fd4becf630240d7b7f1c2ca1048fd6798234f2a1e895762f83e802507a008eff52605611b67390a74eaf228b76f5589ff109b2c20eaa65fad6de2e5ab8a25b54267b607df970b20a71547e1064b5edaad92cdce6b0ace832836ba28fdeaf0b83010bed247fe927c03013dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0f48a85010116001414d362694eacfa110dc20dec77d610d22340f95b00014b207265909236260b30942a6b00e30ceb769e0e58156b6482bac64117619c9dcf80c8afa02501246a2277656c636f6d65efbc8ce6aca2e8bf8ee69da5e588b0e58e9fe5ad90e4b896e7958c00013e207265909236260b30942a6b00e30ceb769e0e58156b6482bac64117619c9dcf80b09dc2df0101160014bb8a039726df1b649738e9973db14a4b4fd4becf00");
76125 }
77126
78127
79128 //utxo
80- private Transaction.AnnotatedInput btmUtxoToInput() {
129+ private SpendInput btmUtxoToInput() {
81130 String utxoJson = "\n" +
82131 "{\n" +
83132 " \"id\": \"687e3c3ca1ee8139e57f43697db6aaeac95b10c75b828ef2fad30abe7d047e6a\",\n" +
@@ -97,63 +146,6 @@ public class AppTest {
97146 " \"derive_rule\": 0\n" +
98147 "}";
99148 UTXO utxo = UTXO.fromJson(utxoJson);
100- Transaction.AnnotatedInput input = UTXO.utxoToAnnotatedInput(utxo);
101- return input;
102- }
103-
104- private Transaction.AnnotatedInput otherAssetUtxoToInput() {
105- String utxoJson = "\n" +
106- "{\n" +
107- " \"id\": \"a1b729714a9ad74108999b6d2f3628c6eea2bd41d7132fca93f56c3f7c12904e\",\n" +
108- " \"amount\": 89900000000,\n" +
109- " \"address\": \"tm1qstadkjjxp7nn3eegdxc38nvur82z37ek2pq2ul\",\n" +
110- " \"program\": \"001482fadb4a460fa738e72869b113cd9c19d428fb36\",\n" +
111- " \"change\": true,\n" +
112- " \"highest\": 139905,\n" +
113- " \"account_alias\": \"wyjbtm\",\n" +
114- " \"asset_id\": \"207265909236260b30942a6b00e30ceb769e0e58156b6482bac64117619c9dcf\",\n" +
115- " \"asset_alias\": \"TEST3\",\n" +
116- " \"account_id\": \"0NNSS39M00A02\",\n" +
117- " \"control_program_index\": 32,\n" +
118- " \"source_id\": \"2886e635442f2f003e1d211f3264520ffb5239944d718bc834925a0cc0798980\",\n" +
119- " \"source_pos\": 1,\n" +
120- " \"valid_height\": 0,\n" +
121- " \"derive_rule\": 0\n" +
122- "}";
123- UTXO utxo = UTXO.fromJson(utxoJson);
124- Transaction.AnnotatedInput input = UTXO.utxoToAnnotatedInput(utxo);
125- return input;
126- }
127-
128- // submit rawTransaction
129- @Test
130- public void SubmitTransaction() throws BytomException {
131- Client client = TestUtil.generateClient();
132- String raw = "070180897a020160015e0b2cff11d1d056d95237a5f2d06059e5395e86f60e69c1e8201ea624911c0c65ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0a1ed89010001160014f1dc52048f439ac7fd74f8106a21da78f00de48f6302401660121218ab96d9f22cce712541ca34c53f4da40450669854341ca9624ad1cf10d1bfc96449fad5406224afd253ccfbdeab683f7ec7f9ee8f45e47a0c58500f2031ecc1bdd5fb9b40016358340b87646ea39faf55c0c105205cfdfdc6184725f40161015fbe0ac837e832c34a02968e54dab4f95cbeceb9fb01cd378310f6ea32219ee29b207265909236260b30942a6b00e30ceb769e0e58156b6482bac64117619c9dcf80f8cce284020101160014bb8a039726df1b649738e9973db14a4b4fd4becf630240d7b7f1c2ca1048fd6798234f2a1e895762f83e802507a008eff52605611b67390a74eaf228b76f5589ff109b2c20eaa65fad6de2e5ab8a25b54267b607df970b20a71547e1064b5edaad92cdce6b0ace832836ba28fdeaf0b83010bed247fe927c03013dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0f48a85010116001414d362694eacfa110dc20dec77d610d22340f95b00014b207265909236260b30942a6b00e30ceb769e0e58156b6482bac64117619c9dcf80c8afa02501246a2277656c636f6d65efbc8ce6aca2e8bf8ee69da5e588b0e58e9fe5ad90e4b896e7958c00013e207265909236260b30942a6b00e30ceb769e0e58156b6482bac64117619c9dcf80b09dc2df0101160014bb8a039726df1b649738e9973db14a4b4fd4becf00";
133- SubmitTransaction.SubmitResponse submitResponse = SubmitTransaction.submitRawTransaction(client, raw);
134- System.out.println(submitResponse.tx_id);
135- }
136-
137-
138- //单输入多签
139- @Test
140- public void testMutiSpend(){
141- Transaction.AnnotatedInput input = btmUtxoToInput();
142- Transaction Transaction = new Transaction.Builder()
143-// .addInput(new Transaction.AnnotatedInput().setType(1).setAssetId(btmAssetID).setAmount(880000000).setControlProgram("001414d362694eacfa110dc20dec77d610d22340f95b").
144-// setChange(false).setControlProgramIndex(2).setSourceId("fc43933d1c601b2503b033e31d3bacfa5c40ccb2ff0be6e94d8332462e0928a3").setSourcePosition(0))
145- .addInput(input.setType(1))
146- .addOutput(new Transaction.AnnotatedOutput().setAssetId(btmAssetID).setAmount(80000000).setControlProgram("00204d505f3bb98a6022fa37e387204dba3b2917cf6df4d41c5622485c55b1b17813"))
147- .addOutput(new Transaction.AnnotatedOutput().setAssetId(btmAssetID).setAmount(10000000).setControlProgram("001414d362694eacfa110dc20dec77d610d22340f95b"))
148- .build(200000);
149- Transaction transaction = MapTransaction.mapTx(Transaction);
150- SignTransaction signTransaction = new SignTransaction();
151- String[] rootKeys = new String[3];
152- rootKeys[0] = "38d2c44314c401b3ea7c23c54e12c36a527aee46a7f26b82443a46bf40583e439dea25de09b0018b35a741d8cd9f6ec06bc11db49762617485f5309ab72a12d4";
153- rootKeys[1] = "50a23bf6200b8a98afc049a7d0296a619e2ee27fa0d6d4d271ca244b280b324347627e543cc079614642c7b88c78ce38092430b01d124663e8b84026aefefde1";
154- rootKeys[2] = "00e4bf1251fb5aa37aa2a11dec6c0db5cec3f17aa312dbddb30e06957a32ae503ebcdfd4ad5e29be21ee9ec336e939eb72439cf6d99c785268c8f3d71c1be877";
155- signTransaction.buildWitness(transaction, 0, rootKeys);
156- String raw = signTransaction.serializeTransaction(transaction);
157- System.out.println(raw);
149+ return utxo.toSpendAnnotatedInput();
158150 }
159151 }
--- a/tx-signer/src/test/java/io/bytom/api/SignerTest.java
+++ b/tx-signer/src/test/java/io/bytom/api/SignerTest.java
@@ -1,8 +1,5 @@
11 package io.bytom.api;
22
3-import io.bytom.common.DerivePrivateKey;
4-import io.bytom.common.DeriveXpub;
5-import io.bytom.common.ExpandedPrivateKey;
63 import org.bouncycastle.util.encoders.Hex;
74 import org.junit.Test;
85
@@ -18,7 +15,7 @@ public class SignerTest {
1815 String childXprv = "e8c0965af60563c4cabcf2e947b1cd955c4f501eb946ffc8c3447e5ec8a6335398a3720b3f96077fa187fdde48fe7dc293984b196f5e292ef8ed78fdbd8ed954";
1916 String expandedXprv = "20849f14bbe212d1b8917da2e1eda9afc4c21e9dd0a47f1e169a3326d45ae443236f54b987369e86ed78eb2b0a2def89a69ec69ca1059e2efe045796dc583d91";
2017 String hashedMessage = "99ab9ebdba106466371467b036d56a0e54ad2a6035e365a6103ba97ab553fd52";
21- byte[] sig = Signer.Ed25519InnerSign(Hex.decode(expandedXprv), Hex.decode(hashedMessage));
18+ byte[] sig = Signer.ed25519InnerSign(Hex.decode(expandedXprv), Hex.decode(hashedMessage));
2219 System.out.println("sig:" + Hex.toHexString(sig));
2320 //expected: e628e980c690d9ef4ca8a2edee1654a6b401edc4f1af7bda3ffd97fe412522c3bab671dd4e51d0aeeb64f8d761fbdb03e296ab0c1dcbed4eafa504f412a98100
2421 }
--- a/tx-signer/src/test/java/io/bytom/common/DerivePrivateKeyTest.java
+++ b/tx-signer/src/test/java/io/bytom/common/DerivePrivateKeyTest.java
@@ -11,7 +11,7 @@ public class DerivePrivateKeyTest {
1111 @Test
1212 public void testBip44Key() throws NoSuchAlgorithmException, SignatureException, InvalidKeyException {
1313 String rootKey = "38d2c44314c401b3ea7c23c54e12c36a527aee46a7f26b82443a46bf40583e439dea25de09b0018b35a741d8cd9f6ec06bc11db49762617485f5309ab72a12d4";
14- byte[] derivePrivateKey = DerivePrivateKey.derivePrivateKey(rootKey, 1, false, 2);
14+ byte[] derivePrivateKey = DerivePrivateKey.bip44derivePrvKey(rootKey, 1, false, 2);
1515 System.out.println(Hex.toHexString(derivePrivateKey));
1616 //expected 48c65f40d860723e71b03988a22edc9ad00ae0deae992e79fb3b812edb5c3e43e78065bf46d0e8ad922cdae600fd2c2a6239b8f1f504f8f255460c6fcce023ff
1717 }
@@ -19,7 +19,7 @@ public class DerivePrivateKeyTest {
1919 @Test
2020 public void testBip32Key() throws NoSuchAlgorithmException, SignatureException, InvalidKeyException {
2121 String rootKey = "38d2c44314c401b3ea7c23c54e12c36a527aee46a7f26b82443a46bf40583e439dea25de09b0018b35a741d8cd9f6ec06bc11db49762617485f5309ab72a12d4";
22- byte[] derivePrivateKey = DerivePrivateKey.derivePrivateKey(rootKey, 2);
22+ byte[] derivePrivateKey = DerivePrivateKey.bip32derivePrvKey(rootKey, 2, (byte) 0);
2323 System.out.println(Hex.toHexString(derivePrivateKey));
2424 //expected 2806f655e862ffc550c2dcaa5057e02e0a1c7c714a4c5a1823bd83f060593e43f5fef4fced766de36cb7ea8ca51cebac7830d54dca1929e669a4a7c3dc7b9dcc
2525 }
@@ -27,7 +27,7 @@ public class DerivePrivateKeyTest {
2727 @Test
2828 public void testBip32PublicKey() throws NoSuchAlgorithmException, SignatureException, InvalidKeyException {
2929 String rootKey = "38d2c44314c401b3ea7c23c54e12c36a527aee46a7f26b82443a46bf40583e439dea25de09b0018b35a741d8cd9f6ec06bc11db49762617485f5309ab72a12d4";
30- byte[] derivePrivateKey = DerivePrivateKey.derivePrivateKey(rootKey, 14);
30+ byte[] derivePrivateKey = DerivePrivateKey.bip32derivePrvKey(rootKey, 14, (byte) 0);
3131 byte[] deriveXpub = DeriveXpub.deriveXpub(derivePrivateKey);
3232 System.out.println(Hex.toHexString(deriveXpub).substring(0, 64));
3333 //expected 2806f655e862ffc550c2dcaa5057e02e0a1c7c714a4c5a1823bd83f060593e43f5fef4fced766de36cb7ea8ca51cebac7830d54dca1929e669a4a7c3dc7b9dcc
--- a/tx-signer/src/test/java/io/bytom/common/ExpandedPrivateKeyTest.java
+++ b/tx-signer/src/test/java/io/bytom/common/ExpandedPrivateKeyTest.java
@@ -13,7 +13,7 @@ public class ExpandedPrivateKeyTest {
1313 @Test
1414 public void testExpandedKey() throws NoSuchAlgorithmException, SignatureException, InvalidKeyException {
1515 String childXprv = "e8c0965af60563c4cabcf2e947b1cd955c4f501eb946ffc8c3447e5ec8a6335398a3720b3f96077fa187fdde48fe7dc293984b196f5e292ef8ed78fdbd8ed954";
16- byte[] z = ExpandedPrivateKey.ExpandedPrivateKey(Hex.decode(childXprv));
16+ byte[] z = ExpandedPrivateKey.expandedPrivateKey(Hex.decode(childXprv));
1717 System.out.println(Hex.toHexString(z));
1818 //expect: e8c0965af60563c4cabcf2e947b1cd955c4f501eb946ffc8c3447e5ec8a633535b899d45316cd83e027913d3ff3dc52f6a951a686fd2b750099e1f7c70cb98c3
1919 // e8c0965af60563c4cabcf2e947b1cd955c4f501eb946ffc8c3447e5ec8a633535b899d45316cd83e027913d3ff3dc52f6a951a686fd2b750099e1f7c70cb98c3
--- a/tx-signer/src/test/java/io/bytom/common/NonHardenedChildTest.java
+++ b/tx-signer/src/test/java/io/bytom/common/NonHardenedChildTest.java
@@ -24,9 +24,8 @@ public class NonHardenedChildTest {
2424 for (int i = 0; i < hpaths.length; i++) {
2525 byte[] xpub = DeriveXpub.deriveXpub(res);
2626 // System.out.println("xpub: "+Hex.toHexString(xpub));
27- res = NonHardenedChild.NHchild(paths[i], res, xpub);
27+ res = NonHardenedChild.nhChild(paths[i], res, xpub);
2828 }
29- System.out.println("res: " + Hex.toHexString(res));
3029 //expected: e8c0965af60563c4cabcf2e947b1cd955c4f501eb946ffc8c3447e5ec8a6335398a3720b3f96077fa187fdde48fe7dc293984b196f5e292ef8ed78fdbd8ed954
3130 // e8c0965af60563c4cabcf2e947b1cd955c4f501eb946ffc8c3447e5ec8a6335398a3720b3f96077fa187fdde48fe7dc293984b196f5e292ef8ed78fdbd8ed954
3231 }
@@ -36,7 +35,6 @@ public class NonHardenedChildTest {
3635 String hxprv = "10fdbc41a4d3b8e5a0f50dd3905c1660e7476d4db3dbd9454fa4347500a633531c487e8174ffc0cfa76c3be6833111a9b8cd94446e37a76ee18bb21a7d6ea66b";
3736 String[] hpaths = {"010400000000000000", "0100000000000000"};
3837 byte[] childXprv = NonHardenedChild.child(Hex.decode(hxprv), hpaths);
39- System.out.println("childXprv: " + Hex.toHexString(childXprv));
4038 //expected: e8c0965af60563c4cabcf2e947b1cd955c4f501eb946ffc8c3447e5ec8a6335398a3720b3f96077fa187fdde48fe7dc293984b196f5e292ef8ed78fdbd8ed954
4139 // e8c0965af60563c4cabcf2e947b1cd955c4f501eb946ffc8c3447e5ec8a6335398a3720b3f96077fa187fdde48fe7dc293984b196f5e292ef8ed78fdbd8ed954
4240 }
Show on old repository browser