Open
Description
Forgive the slop.
In short:
- signatures do NOT have salt/nonce
- hashes are DOUBLE
- hashes are NOT reversed when signed (the "serialized" form is a lie)
- signatures are NOT reversed
The transition has 2 forms:
- null sigs (signed by each identity key, and the asset lock key)
- full sigs (includes all signature data)
let textEncoder = new TextEncoder();
let Secp256k1 = require("@dashincubator/secp256k1");
async function sha256(data) {
let hashBuffer = await crypto.subtle.digest("SHA-256", data);
let hashBytes = new Uint8Array(hashBuffer);
return hashBytes;
}
function toHex(bytes) {
return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join(
"",
);
}
let Bytes = {};
/** @typedef {String} Hex */
/**
* @param {Hex} hex
*/
Bytes.hexToBytes = function (hex) {
let bufLen = hex.length / 2;
let bytes = new Uint8Array(bufLen);
let i = 0;
let index = 0;
let lastIndex = hex.length - 2;
for (;;) {
if (i > lastIndex) {
break;
}
let h = hex.substr(i, 2);
let b = parseInt(h, 16);
let nan = isNaN(b);
if (nan) {
throw new Error(`'${h}' could not be parsed as hex`);
}
bytes[index] = b;
i += 2;
index += 1;
}
return bytes;
};
let KeyUtils = {};
/**
* @param {Uint8Array} privKeyBytes
* @param {Uint8Array} doubleHashBytes
* @returns {Promise<Uint8Array>} - magic signature
*/
KeyUtils.magicSign = async function (privKeyBytes, doubleHashBytes) {
let MAGIC_OFFSET = 27 + 4; // 27 because bitcoin, 4 because "compressed" key
let testing = true;
let sigOpts = { canonical: true, der: false, recovered: true };
if (!testing) {
Object.assign({ extraEntropy: true });
}
let recoverySig = await Secp256k1.sign(
doubleHashBytes,
privKeyBytes,
sigOpts,
);
let magicSig = new Uint8Array(65);
let recovery = MAGIC_OFFSET + recoverySig[1];
// the magic byte is prepended (the signature is NOT reversed)
magicSig[0] = recovery;
magicSig.set(recoverySig[0], 1);
return magicSig;
};
async function runTest() {
let keyHex =
"561349d51e3682f542adf609a95e579caf2974e823c7cf283d9bab001b2e4f7e";
let privKeyBytes = Bytes.hexToBytes(keyHex);
// let input = "";
// let data = textEncoder.encode(input);
let input =
"0300040000000000000021037c004626332a6411dee452f556930c7415375a198b496967a8f6e07fd2ab2da80001000002000021037c004626332a6411dee452f556930c7415375a198b496967a8f6e07fd2ab2da80002000001000021037c004626332a6411dee452f556930c7415375a198b496967a8f6e07fd2ab2da80003000301000021037c004626332a6411dee452f556930c7415375a198b496967a8f6e07fd2ab2da800c60101c555131b64551385a270635f3bfb89f55784f402ad9bb4424917f8e9021dcd47010000001c834865e59455ef2033cd45d43d7315c79930b23204fec487437297707e0c079c1274f2b2686154cef2c798a7e1f4a5311aab4ee3a97a215c84c99d2d000000850db91ccff5879c898039fcfbe4f3453dcfeb46e332455dce77815291c236a0560bd67fea231b10e916e8bf11d891db0fcd01261dcbefb6077b4cdec40913ac7740f8b65bad6700a4548de22f818f1a684edf7c97e9cb196ff89765e950e462f00300080001c555131b64551385a270635f3bfb89f55784f402ad9bb4424917f8e9021dcd47010000006b4830450221008e46aee96b107b1407c29170b6c75d2bc1a45d7099ef4ae62c911513926f371a022074d9d0060071d8daae60de6926a8d27ee38556cd2ba3466069cb5bc577ea841c812103916e3f05d84deaeeb37a97b35ae8e94aa6447cea52159bbd7918a49bbcdfe4beffffffff0200e1f50500000000026a00e1428c1d000000001976a9149aa6e68be50ebd57c7521aab16b3deb45539685388ac0000000024010100e1f505000000001976a91406f42511fae21580b0ad82e101523ca060c4c6d188ac0000";
let data = Bytes.hexToBytes(input);
let expectedOutputStr =
//"56944c5d3f98413ef45cf54545538103cc9f298e0575820ad3591376e2e0f65d";
"5cd6e6496d81d285df139834c05c87e438ce9b73874d3f074aebbc249e032638";
let firstHash = await sha256(data);
let secondHash = await sha256(firstHash);
// Reverse the result
// let reversedHash = secondHash.reverse();
// Convert to hex string
let resultHex = toHex(secondHash);
// let resultHex = toHex(reversedHash);
console.log("Computed Hex:", resultHex);
console.log("Matches Expected:", resultHex === expectedOutputStr);
let sig = await KeyUtils.magicSign(privKeyBytes, secondHash);
let sigHex = toHex(sig);
console.log(sigHex);
}
runTest();
Metadata
Metadata
Assignees
Labels
No labels