PHP WebShell
Текущая директория: /opt/BitGoJS/modules/utxo-lib/src/bitgo/zcash
Просмотр файла: hashZip0244.ts
/**
* Implements hashing methods described in https://zips.z.cash/zip-0244.
* Only supports full transparent transactions without shielded inputs or outputs.
*/
import { Transaction, TxInput, TxOutput } from 'bitcoinjs-lib';
import { BufferWriter } from 'bitcoinjs-lib/src/bufferutils';
const blake2b = require('@bitgo/blake2b');
import { ZcashTransaction } from './ZcashTransaction';
import { varSliceSize } from '../UtxoTransaction';
type SignatureParams<TNumber extends number | bigint = number> = {
inIndex?: number;
prevOutScript: Buffer;
value: TNumber;
hashType: number;
};
/**
* Blake2b hashing algorithm for Zcash
* @param buffer
* @param personalization
* @returns 256-bit BLAKE2b hash
*/
export function getBlake2bHash(buffer: Buffer, personalization: string | Buffer): Buffer {
const out = Buffer.allocUnsafe(32);
personalization = Buffer.from(personalization);
return blake2b(out.length, null, null, personalization).update(buffer).digest(out);
}
function getHeaderDigest<TNumber extends number | bigint>(tx: ZcashTransaction<TNumber>): Buffer {
// https://zips.z.cash/zip-0244#t-1-header-digest
const mask = tx.overwintered ? 1 : 0;
const writer = BufferWriter.withCapacity(4 * 5);
writer.writeInt32(tx.version | (mask << 31)); // Set overwinter bit
writer.writeUInt32(tx.versionGroupId);
writer.writeUInt32(tx.consensusBranchId);
writer.writeUInt32(tx.locktime);
writer.writeUInt32(tx.expiryHeight);
return getBlake2bHash(writer.end(), 'ZTxIdHeadersHash');
}
export function getPrevoutsDigest<TNumber extends number | bigint>(
ins: TxInput[],
tag = 'ZTxIdPrevoutHash',
sigParams?: SignatureParams<TNumber>
): Buffer {
if (sigParams) {
if (sigParams.hashType & Transaction.SIGHASH_ANYONECANPAY) {
return getPrevoutsDigest([]);
}
}
const bufferWriter = new BufferWriter(Buffer.allocUnsafe(36 * ins.length));
ins.forEach(function (txIn) {
bufferWriter.writeSlice(txIn.hash);
bufferWriter.writeUInt32(txIn.index);
});
return getBlake2bHash(bufferWriter.end(), tag);
}
export function getSequenceDigest<TNumber extends number | bigint>(
ins: TxInput[],
tag = 'ZTxIdSequencHash',
sigParams?: SignatureParams<TNumber>
): Buffer {
// txid: https://zips.z.cash/zip-0244#t-2b-sequence-digest
// sig: https://zips.z.cash/zip-0244#s-2b-sequence-sig-digest
// https://github.com/zcash-hackworks/zcash-test-vectors/blob/dd8fdb/zip_0244.py#L263
if (sigParams) {
const { hashType } = sigParams;
if (
hashType & Transaction.SIGHASH_ANYONECANPAY ||
(hashType & 0x1f) === Transaction.SIGHASH_SINGLE ||
(hashType & 0x1f) === Transaction.SIGHASH_NONE
) {
return getSequenceDigest([]);
}
}
const bufferWriter = new BufferWriter(Buffer.allocUnsafe(4 * ins.length));
ins.forEach(function (txIn) {
bufferWriter.writeUInt32(txIn.sequence);
});
return getBlake2bHash(bufferWriter.end(), tag);
}
export function getOutputsDigest<TNumber extends number | bigint>(
outs: TxOutput<TNumber>[],
tag = 'ZTxIdOutputsHash',
sigParams?: SignatureParams<TNumber>
): Buffer {
// txid: https://zips.z.cash/zip-0244#t-2c-outputs-digest
// sig: https://zips.z.cash/zip-0244#s-2c-outputs-sig-digest
// https://github.com/zcash-hackworks/zcash-test-vectors/blob/dd8fdb/zip_0244.py#L275
if (sigParams) {
let { hashType } = sigParams;
hashType = hashType & 0x1f;
if (hashType === Transaction.SIGHASH_SINGLE) {
if (sigParams.inIndex === undefined) {
throw new Error();
}
if (outs[sigParams.inIndex] === undefined) {
return getOutputsDigest(outs);
}
return getOutputsDigest([outs[sigParams.inIndex]]);
}
if (hashType === Transaction.SIGHASH_NONE) {
return getOutputsDigest([]);
}
return getOutputsDigest(outs, tag);
}
// Find out the size of the outputs and write them
const txOutsSize = outs.reduce(function (sum, output) {
return sum + 8 + varSliceSize(output.script);
}, 0);
const bufferWriter = new BufferWriter(Buffer.allocUnsafe(txOutsSize));
outs.forEach(function (out) {
bufferWriter.writeUInt64(out.value);
bufferWriter.writeVarSlice(out.script);
});
return getBlake2bHash(bufferWriter.end(), tag);
}
function getTxinDigest<TNumber extends number | bigint>(input: TxInput, sigParams: SignatureParams<TNumber>) {
// https://zips.z.cash/zip-0244#s-2d-txin-sig-digest
// https://github.com/zcash-hackworks/zcash-test-vectors/blob/dd8fdb/zip_0244.py#L291
const writer = BufferWriter.withCapacity(
32 /* prevout hash */ +
4 /* prevout vin */ +
varSliceSize(sigParams.prevOutScript) +
8 /* value */ +
4 /* sequence */
);
writer.writeSlice(input.hash);
writer.writeUInt32(input.index);
writer.writeVarSlice(sigParams.prevOutScript);
writer.writeUInt64(sigParams.value);
writer.writeUInt32(input.sequence);
return getBlake2bHash(writer.end(), 'Zcash___TxInHash');
}
function getTransparentDigest<TNumber extends number | bigint>(
tx: { ins: TxInput[]; outs: TxOutput<TNumber>[] },
sigParams?: SignatureParams<TNumber>
): Buffer {
// txid: https://zips.z.cash/zip-0244#t-2-transparent-digest
// sig: https://zips.z.cash/zip-0244#s-2a-prevouts-sig-digest
if (sigParams) {
if (sigParams.inIndex === undefined) {
return getTransparentDigest(tx);
}
}
let buffer;
if (tx.ins.length || tx.outs.length) {
const writer = BufferWriter.withCapacity(32 * (sigParams ? 4 : 3));
writer.writeSlice(getPrevoutsDigest(tx.ins, undefined, sigParams));
writer.writeSlice(getSequenceDigest(tx.ins, undefined, sigParams));
writer.writeSlice(getOutputsDigest(tx.outs, undefined, sigParams));
if (sigParams) {
if (sigParams.inIndex === undefined) {
throw new Error();
}
writer.writeSlice(getTxinDigest(tx.ins[sigParams.inIndex], sigParams));
}
buffer = writer.end();
} else {
buffer = Buffer.of();
}
return getBlake2bHash(buffer, 'ZTxIdTranspaHash');
}
function getSaplingDigest<TNumber extends number | bigint>(tx: ZcashTransaction<TNumber>): Buffer {
// https://zips.z.cash/zip-0244#t-3-sapling-digest
return getBlake2bHash(Buffer.of(), 'ZTxIdSaplingHash');
}
function getOrchardDigest<TNumber extends number | bigint>(tx: ZcashTransaction<TNumber>): Buffer {
// https://zips.z.cash/zip-0244#t-4-orchard-digest
return getBlake2bHash(Buffer.of(), 'ZTxIdOrchardHash');
}
/**
* @param tx
* @param signatureParams - calculates txid when undefined
*/
function getDigest<TNumber extends number | bigint>(
tx: ZcashTransaction<TNumber>,
signatureParams?: SignatureParams<TNumber>
): Buffer {
// txid: https://zips.z.cash/zip-0244#id4
// sig: https://zips.z.cash/zip-0244#id13
const writer = BufferWriter.withCapacity(32 * 4);
writer.writeSlice(getHeaderDigest(tx));
writer.writeSlice(getTransparentDigest(tx, signatureParams));
writer.writeSlice(getSaplingDigest(tx));
writer.writeSlice(getOrchardDigest(tx));
const tag = 'ZcashTxHash_';
const personalization = BufferWriter.withCapacity(tag.length + 4 /* UInt32 */);
personalization.writeSlice(Buffer.from(tag));
personalization.writeUInt32(tx.consensusBranchId);
return getBlake2bHash(writer.end(), personalization.end());
}
export function getTxidDigest<TNumber extends number | bigint>(tx: ZcashTransaction<TNumber>): Buffer {
// https://zips.z.cash/zip-0244#id4
return getDigest(tx);
}
export function getSignatureDigest<TNumber extends number | bigint>(
tx: ZcashTransaction<TNumber>,
inIndex: number | undefined,
prevOutScript: Buffer,
value: TNumber,
hashType: number
): Buffer {
// https://zips.z.cash/zip-0244#id13
return getDigest(tx, {
inIndex,
prevOutScript,
value,
hashType,
});
}
Выполнить команду
Для локальной разработки. Не используйте в интернете!