Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 41 additions & 12 deletions framework/src/main/java/org/tron/core/Wallet.java
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,8 @@ public class Wallet {
"BurnNewLeaf(uint256,bytes32,bytes32,bytes32,bytes32[21])"));
private static final byte[] SHIELDED_TRC20_LOG_TOPICS_BURN_TOKEN = Hash.sha3(ByteArray
.fromString("TokenBurn(address,uint256,bytes32[3])"));
private static final byte[] SHIELDED_TRC20_LOG_TOPICS_NOTE_SPENT = Hash.sha3(ByteArray
.fromString("NoteSpent(bytes32)"));
private static final String BROADCAST_TRANS_FAILED = "Broadcast transaction {} failed, {}.";

@Getter
Expand Down Expand Up @@ -3672,9 +3674,7 @@ public ShieldedTRC20Parameters createShieldedContractParameters(
builder.setTransparentToAddress(transparentToAddressTvm);
builder.setTransparentToAmount(toAmount);

Optional<byte[]> cipher = NoteEncryption.Encryption
.encryptBurnMessageByOvk(ovk, toAmount, transparentToAddress);
cipher.ifPresent(builder::setBurnCiphertext);
builder.setOvk(ovk);

ExpandedSpendingKey expsk = new ExpandedSpendingKey(ask, nsk, ovk);
GrpcAPI.SpendNoteTRC20 spendNote = shieldedSpends.get(0);
Expand Down Expand Up @@ -3799,9 +3799,7 @@ public ShieldedTRC20Parameters createShieldedContractParametersWithoutAsk(
System.arraycopy(transparentToAddress, 1, transparentToAddressTvm, 0, 20);
builder.setTransparentToAddress(transparentToAddressTvm);
builder.setTransparentToAmount(toAmount);
Optional<byte[]> cipher = NoteEncryption.Encryption
.encryptBurnMessageByOvk(ovk, toAmount, transparentToAddress);
cipher.ifPresent(builder::setBurnCiphertext);
builder.setOvk(ovk);
GrpcAPI.SpendNoteTRC20 spendNote = shieldedSpends.get(0);
buildShieldedTRC20InputWithAK(builder, spendNote, ak, nsk);
if (receiveSize == 1) {
Expand Down Expand Up @@ -3838,6 +3836,8 @@ private int getShieldedTRC20LogType(TransactionInfo.Log log, byte[] contractAddr
return 3;
} else if (Arrays.equals(topicsBytes, SHIELDED_TRC20_LOG_TOPICS_BURN_TOKEN)) {
return 4;
} else if (Arrays.equals(topicsBytes, SHIELDED_TRC20_LOG_TOPICS_NOTE_SPENT)) {
return 5;
}
}
return 0;
Expand Down Expand Up @@ -4001,7 +4001,8 @@ public DecryptNotesTRC20 scanShieldedTRC20NotesByIvk(

private Optional<DecryptNotesTRC20.NoteTx> getNoteTxFromLogListByOvk(
DecryptNotesTRC20.NoteTx.Builder builder,
TransactionInfo.Log log, byte[] ovk, int logType) throws ZksnarkException {
TransactionInfo.Log log, byte[] ovk, int logType, byte[] pendingNf)
throws ZksnarkException {
byte[] logData = log.getData().toByteArray();
if (!ArrayUtils.isEmpty(logData)) {
if (logType > 0 && logType < 4) {
Expand Down Expand Up @@ -4040,18 +4041,32 @@ private Optional<DecryptNotesTRC20.NoteTx> getNoteTxFromLogListByOvk(
}
}
} else if (logType == 4) {
//Data = toAddress(32) + value(32) + ciphertext(80) + padding(16)
// Data = toAddress(32) + value(32) + cipher(80) + nonce(12) + reserved/version(4)
if (logData.length < 64 + NoteEncryption.Encryption.BURN_CIPHER_RECORD_SIZE) {
return Optional.empty();
}
byte[] logToAddress = ByteArray.subArray(logData, 12, 32);
byte[] logAmountArray = ByteArray.subArray(logData, 32, 64);
byte[] cipher = ByteArray.subArray(logData, 64, 144);
byte[] nonceFromLog = ByteArray.subArray(logData, 144,
144 + NoteEncryption.Encryption.BURN_NONCE_LEN);
byte[] reservedFromLog = ByteArray.subArray(logData,
144 + NoteEncryption.Encryption.BURN_NONCE_LEN,
144 + NoteEncryption.Encryption.BURN_NONCE_LEN
+ NoteEncryption.Encryption.BURN_RESERVED_LEN);
BigInteger logAmount = ByteUtil.bytesToBigInteger(logAmountArray);
byte[] plaintext;
byte[] amountArray = new byte[32];
byte[] decryptedAddress = new byte[20];

Optional<byte[]> decryptedText = NoteEncryption.Encryption
.decryptBurnMessageByOvk(ovk, cipher);
.decryptBurnMessageByOvk(ovk, cipher, nonceFromLog, reservedFromLog, pendingNf);

if (decryptedText.isPresent()) {
plaintext = decryptedText.get();
if (plaintext[32] != Wallet.getAddressPreFixByte()) {
return Optional.empty();
}
System.arraycopy(plaintext, 0, amountArray, 0, 32);
System.arraycopy(plaintext, 33, decryptedAddress, 0, 20);
BigInteger decryptedAmount = ByteUtil.bytesToBigInteger(amountArray);
Expand Down Expand Up @@ -4091,15 +4106,24 @@ public DecryptNotesTRC20 scanShieldedTRC20NotesByOvk(long startNum, long endNum,
if (!Objects.isNull(logList)) {
Optional<DecryptNotesTRC20.NoteTx> noteTx;
int index = 0;
byte[] pendingNf = null;
for (TransactionInfo.Log log : logList) {
int logType = getShieldedTRC20LogType(log, shieldedTRC20ContractAddress);
if (logType > 0) {
if (logType == 5) {
byte[] logData = log.getData().toByteArray();
if (logData.length >= 32) {
pendingNf = ByteArray.subArray(logData, 0, 32);
}
} else if (logType > 0) {
noteBuilder = DecryptNotesTRC20.NoteTx.newBuilder();
noteBuilder.setTxid(ByteString.copyFrom(txid));
noteBuilder.setIndex(index);
index += 1;
noteTx = getNoteTxFromLogListByOvk(noteBuilder, log, ovk, logType);
noteTx = getNoteTxFromLogListByOvk(noteBuilder, log, ovk, logType, pendingNf);
noteTx.ifPresent(builder::addNoteTxs);
if (logType == 4) {
pendingNf = null;
}
}
}
}
Expand Down Expand Up @@ -4283,8 +4307,13 @@ public BytesMessage getTriggerInputForShieldedTRC20Contract(
parameterType);
if (parametersBuilder.getShieldedTRC20ParametersType() == ShieldedTRC20ParametersType.BURN) {
byte[] burnCiper = ByteArray.fromHexString(shieldedTRC20Parameters.getTriggerContractInput());
if (!ArrayUtils.isEmpty(burnCiper) && burnCiper.length == 80) {
if (!ArrayUtils.isEmpty(burnCiper)
&& burnCiper.length == NoteEncryption.Encryption.BURN_CIPHER_RECORD_SIZE) {
parametersBuilder.setBurnCiphertext(burnCiper);
} else if (!ArrayUtils.isEmpty(burnCiper) && burnCiper.length == 80) {
throw new ZksnarkException(
"legacy 80-byte burn cipher is deprecated and rejected; expected "
+ NoteEncryption.Encryption.BURN_CIPHER_RECORD_SIZE + "-byte burn record");
} else {
throw new ZksnarkException(
"invalid shielded TRC-20 contract parameters for burn trigger input");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.tron.core.zen.address.PaymentAddress;
import org.tron.core.zen.note.Note;
import org.tron.core.zen.note.NoteEncryption;
import org.tron.core.zen.note.NoteEncryption.Encryption;
import org.tron.core.zen.note.OutgoingPlaintext;
import org.tron.protos.contract.ShieldContract;
import org.tron.protos.contract.ShieldContract.ReceiveDescription;
Expand Down Expand Up @@ -61,7 +62,9 @@ public class ShieldedTRC20ParametersBuilder {
@Setter
private BigInteger transparentToAmount;
@Setter
private byte[] burnCiphertext = new byte[80];
private byte[] ovk;
@Setter
private byte[] burnCiphertext = new byte[Encryption.BURN_CIPHER_RECORD_SIZE];

public ShieldedTRC20ParametersBuilder() {

Expand Down Expand Up @@ -207,6 +210,9 @@ private ReceiveDescriptionCapsule generateOutputProof(ReceiveDescriptionInfo out

private void createSpendAuth(byte[] dataToBeSigned) throws ZksnarkException {
for (int i = 0; i < spends.size(); i++) {
if (spends.get(i).expsk == null) {
throw new ZksnarkException("missing expanded spending key for spend authorization");
}
byte[] result = new byte[64];
JLibrustzcash.librustzcashSaplingSpendSig(
new LibrustzcashParam.SpendSigParams(spends.get(i).expsk.getAsk(),
Expand Down Expand Up @@ -292,6 +298,25 @@ public ShieldedTRC20Parameters build(boolean withAsk) throws ZksnarkException {
SpendDescriptionInfo spend = spends.get(0);
spendDescription = generateSpendProof(spend, ctx).getInstance();
builder.addSpendDescription(spendDescription);

if (ovk == null && spend.expsk != null) {
ovk = spend.expsk.getOvk();
}
if (ovk == null) {
throw new ZksnarkException("missing ovk for burn encryption");
}
byte[] nf = spendDescription.getNullifier().toByteArray();
byte[] transparentToAddressTvm = normalizeTransparentToAddress(transparentToAddress);
byte[] addr21 = new byte[21];
addr21[0] = Wallet.getAddressPreFixByte();
System.arraycopy(transparentToAddressTvm, 0, addr21, 1, 20);
Optional<byte[]> cipherOpt = Encryption.encryptBurnMessageByOvk(
ovk, transparentToAmount, addr21, nf);
if (!cipherOpt.isPresent()) {
throw new ZksnarkException("encrypt burn message failed");
}
Comment thread
Federico2014 marked this conversation as resolved.
burnCiphertext = cipherOpt.get();

mergedBytes = ByteUtil.merge(shieldedTRC20Address,
encodeSpendDescriptionWithoutSpendAuthSig(spendDescription));
if (receives.size() == 1) {
Expand All @@ -302,7 +327,7 @@ public ShieldedTRC20Parameters build(boolean withAsk) throws ZksnarkException {
encodeCencCout(receiveDescription));
}
mergedBytes = ByteUtil
.merge(mergedBytes, transparentToAddress, ByteArray.fromLong(valueBalance));
.merge(mergedBytes, transparentToAddressTvm, ByteArray.fromLong(valueBalance));
value = transparentToAmount;
builder.setParameterType("burn");
break;
Expand Down Expand Up @@ -476,12 +501,10 @@ private String burnParamsToHexString(GrpcAPI.ShieldedTRC20Parameters burnParams,
throw new IllegalArgumentException("the value must be positive");
}

if (ArrayUtils.isEmpty(transparentToAddress)) {
throw new IllegalArgumentException("the transparent payTo address is null");
}
byte[] transparentToAddressTvm = normalizeTransparentToAddress(transparentToAddress);

payTo[11] = Wallet.getAddressPreFixByte();
System.arraycopy(transparentToAddress, 0, payTo, 12, 20);
System.arraycopy(transparentToAddressTvm, 0, payTo, 12, 20);
ShieldContract.SpendDescription spendDesc = burnParams.getSpendDescription(0);

byte[] spendAuthSign;
Expand All @@ -492,7 +515,6 @@ private String burnParamsToHexString(GrpcAPI.ShieldedTRC20Parameters burnParams,
}

byte[] mergedBytes;
byte[] zeros = new byte[16];
mergedBytes = ByteUtil.merge(
spendDesc.getNullifier().toByteArray(),
spendDesc.getAnchor().toByteArray(),
Expand All @@ -503,8 +525,7 @@ private String burnParamsToHexString(GrpcAPI.ShieldedTRC20Parameters burnParams,
ByteUtil.bigIntegerToBytes(value, 32),
burnParams.getBindingSignature().toByteArray(),
payTo,
burnCiphertext,
zeros
burnCiphertext
);

byte[] outputOffsetBytes; // 32
Expand All @@ -524,7 +545,7 @@ private String burnParamsToHexString(GrpcAPI.ShieldedTRC20Parameters burnParams,
coffsetBytes = ByteUtil.longTo32Bytes(mergedBytes.length + 32 * 3 + 32L * 9);
countBytes = ByteUtil.longTo32Bytes(1L);
ReceiveDescription recvDesc = burnParams.getReceiveDescription(0);
zeros = new byte[12];
byte[] zeros = new byte[12];
mergedBytes = ByteUtil
.merge(mergedBytes,
outputOffsetBytes,
Expand All @@ -542,6 +563,18 @@ private String burnParamsToHexString(GrpcAPI.ShieldedTRC20Parameters burnParams,
return Hex.toHexString(mergedBytes);
}

private byte[] normalizeTransparentToAddress(byte[] transparentToAddress) {
if (transparentToAddress != null && transparentToAddress.length == 20) {
return transparentToAddress;
}
if (transparentToAddress != null && transparentToAddress.length == 21) {
byte[] transparentToAddressTvm = new byte[20];
System.arraycopy(transparentToAddress, 1, transparentToAddressTvm, 0, 20);
return transparentToAddressTvm;
}
throw new IllegalArgumentException("invalid transparentToAddress for burn encryption");
}

public void addSpend(
ExpandedSpendingKey expsk,
Note note,
Expand Down
Loading
Loading