Skip to content

Instantly share code, notes, and snippets.

@planethouki
Last active February 10, 2019 06:11
Show Gist options
  • Save planethouki/d69a26c9e326c716da83abec02a4bc3e to your computer and use it in GitHub Desktop.
Save planethouki/d69a26c9e326c716da83abec02a4bc3e to your computer and use it in GitHub Desktop.
nem catapult バイトレベルで理解する その3 トランザクション署名 ref: https://qiita.com/planethouki/items/932d96ee17bd4f305368
function clamp(d) {
d[0] &= 248;
d[31] &= 127;
d[31] |= 64;
}
signingBytes = byteBuffer.slice(4 + 64 + 32);
S = ( r + H(\underline{R},\underline{A},M)a) \mod q
# node sign.js
publicKey: 5D9513282B65A12A1B68DCB67DB64245721F7AE7822BE441FE813173803C512C
signature: D44CB8AA79C52D82EA1B7CE8CAB86ACD4CA65B83DEF6177C42D86574798AE380368C6AC3FF458FC6185572063AA7E4584A16ADA15311D3E1B2B65EE913FD0F0B
# node sign2.js
Transfer Transaction
signature: 0DF013F373DEA45571A2A21F4B116E81D6DF1CBD1BAE5BCED13998FED1D464B3E77DDA83B2B8B7C8EC97C9E57C5216E0E66631AD32E99081A276A2A0AAD6510F
payload : 0DF013F373DEA45571A2A21F4B116E81D6DF1CBD1BAE5BCED13998FED1D464B3E77DDA83B2B8B7C8EC97C9E57C5216E0E66631AD32E99081A276A2A0AAD6510F
Aggregate Complete Transaction
signature: 5617D4F7F26F79E1F6C40FA017BBC60405A3E7670C276037FBE9CC1143861359A10B3EB5344E26ABDF7D84DA7E4EF86FBF23482D5A62CBEC90332C0F8493260F
payload : 5617D4F7F26F79E1F6C40FA017BBC60405A3E7670C276037FBE9CC1143861359A10B3EB5344E26ABDF7D84DA7E4EF86FBF23482D5A62CBEC90332C0F8493260F
Aggregate Bonded Transaction
signature: FFC49BBEB3E1A0459F63738D9A92353C53F5FAD07E8E8C02B31F95699E45EF917C552E9BA071CA0DCA13531EC803B425399018422DC554A3EFEFE43997B15005
payload : FFC49BBEB3E1A0459F63738D9A92353C53F5FAD07E8E8C02B31F95699E45EF917C552E9BA071CA0DCA13531EC803B425399018422DC554A3EFEFE43997B15005
LockFunds Transaction
signature: 4051A3278DC8CFF59E344FA8C02E5810C4C8A155FC6B7927910C6E1879E6A16FDB9F1B555DE9E05B0BDE74B5669E771A84D24D779B1D85C66387BEADA524FF0A
payload : 4051A3278DC8CFF59E344FA8C02E5810C4C8A155FC6B7927910C6E1879E6A16FDB9F1B555DE9E05B0BDE74B5669E771A84D24D779B1D85C66387BEADA524FF0A
SecretLock Transaction
signature: 30D1F7287CA6CF553C121FFF7661AE7450A36F8F0ED26884FCDEC9888184854E4523D50F3B7ED639E4799FB7BF8192346E2EC01A400814FE2A299C3EA3D4CB07
payload : 30D1F7287CA6CF553C121FFF7661AE7450A36F8F0ED26884FCDEC9888184854E4523D50F3B7ED639E4799FB7BF8192346E2EC01A400814FE2A299C3EA3D4CB07
SecretProof Transaction
signature: 1183B8A224C04FF32B4BD9D33E5EC28561C05D34D8DDD42B1EE8780F032AE29EBA9D997D5F00BCBE3040A08D30AC1400C0BCFF94849654F4C171FB3FDD297008
payload : 1183B8A224C04FF32B4BD9D33E5EC28561C05D34D8DDD42B1EE8780F032AE29EBA9D997D5F00BCBE3040A08D30AC1400C0BCFF94849654F4C171FB3FDD297008
ModifyMultisigAccount Transaction
signature: AB60D2C78391F0BE75978E0A7423139F184EBAD4F09EA0E39A98DACA27A85AC7CEF70C7258F14B41896F3D2783CBCE94F18AAEE9D93075DAE0DD955A642F4303
payload : AB60D2C78391F0BE75978E0A7423139F184EBAD4F09EA0E39A98DACA27A85AC7CEF70C7258F14B41896F3D2783CBCE94F18AAEE9D93075DAE0DD955A642F4303
RegisterNamespace Transaction
signature: FA3A9341B7DF2F49B45E0D9DCD17F93F6974A4356F235766C05964F7D3817298F10E5DB69B7E7BE9C3F9665A2FFFD5C880A237121FB00A38737D2CA87409760A
payload : FA3A9341B7DF2F49B45E0D9DCD17F93F6974A4356F235766C05964F7D3817298F10E5DB69B7E7BE9C3F9665A2FFFD5C880A237121FB00A38737D2CA87409760A
ModifyMultisigAccount Transaction
signature: 89EB7F8D6208C74041C9B6595B1BF0FA85C4C613E1D0C41FC9DD22451AE673A97AA382AB5A17B266E70DA8B17AD8DA26B01A488AF8F99CBB1B85FAB2E453B50B
payload : 89EB7F8D6208C74041C9B6595B1BF0FA85C4C613E1D0C41FC9DD22451AE673A97AA382AB5A17B266E70DA8B17AD8DA26B01A488AF8F99CBB1B85FAB2E453B50B
MosaicSupplyChange Transaction
signature: AF3E70D9441A49E494B7E07CD1C102A1A5F4AB72658842A3882D6BE3FB02FD6E51762B4D08949590B1A5F1D8979A309B1513126F2A3390758B1C3A61DD240009
payload : AF3E70D9441A49E494B7E07CD1C102A1A5F4AB72658842A3882D6BE3FB02FD6E51762B4D08949590B1A5F1D8979A309B1513126F2A3390758B1C3A61DD240009
Cosignature Transaction
signature: 716FAE6B5BB67FCB7971093A7CE11B71B3E3D38BF3AB9DDE01D5857E311BD9E5656F6157C703F8A183CA732CDED34C5EAD1F75656D454F355A7658C024EB9907
payload : 716FAE6B5BB67FCB7971093A7CE11B71B3E3D38BF3AB9DDE01D5857E311BD9E5656F6157C703F8A183CA732CDED34C5EAD1F75656D454F355A7658C024EB9907
\begin{align}
H(k) &= (h_0,h_1,\dots,h_{511}) \\
a &= 2^{254}+\sum_{3\leq i \leq 254}{2^ih_i}
\end{align}
a = (0, 0, 0, h_4,\dots,h_{253},1,0)
r = H(h_{256},\dots,h_{511},M)
const h = new Uint8Array(Hash_Size);
hasher.reset();
hasher.update(signature.subarray(0, Half_Signature_Size));
hasher.update(pk);
hasher.update(m);
hasher.finalize(h);
c.reduce(h);
// muladd
const x = new Float64Array(Hash_Size);
array.copy(x, r, Half_Hash_Size);
for (let i = 0; i < Half_Hash_Size; ++i) {
for (let j = 0; j < Half_Hash_Size; ++j)
x[i + j] += h[i] * d[j];
}
c.modL(signature.subarray(Half_Signature_Size), x);
encodedSChecker.requireValid(signature.subarray(Half_Signature_Size));
return signature;
const nem2lib = require("nem2-library");
/*
private: 7808B5B53ECF24E40BE17B8EC3D0EB5F7C3F3D938E0D95A415F855AD4C27B2A4
public: 5D9513282B65A12A1B68DCB67DB64245721F7AE7822BE441FE813173803C512C
address: SBWEUWON6IBHCW5IC4EI6V6SMTVJGCJWGLF57UGK
*/
const signData = `03905441809698000000000077A6015D1000000090758EB47C28D6143BAA3DE6A8D9C319B503A1BFD8E789E9E20100030043B884C898706C138096980000000000C319EE771243D835002D31010000000029CF5FD941AD25D58096980000000000`;
const privateKey = '7808B5B53ECF24E40BE17B8EC3D0EB5F7C3F3D938E0D95A415F855AD4C27B2A4';
const keypair = nem2lib.KeyPair.createKeyPairFromPrivateKeyString(privateKey);
const signature = nem2lib.KeyPair.sign(keypair, signData);
console.log('publicKey: ' + nem2lib.convert.uint8ToHex(keypair.publicKey));
console.log('signature: ' + nem2lib.convert.uint8ToHex(signature));
const nem2lib = require("nem2-library");
const nem2Sdk = require("nem2-sdk");
const crypto = require("crypto");
const jssha3 = require('js-sha3');
const Address = nem2Sdk.Address,
Deadline = nem2Sdk.Deadline,
Account = nem2Sdk.Account,
UInt64 = nem2Sdk.UInt64,
NetworkType = nem2Sdk.NetworkType,
PlainMessage = nem2Sdk.PlainMessage,
TransferTransaction = nem2Sdk.TransferTransaction,
Mosaic = nem2Sdk.Mosaic,
MosaicId = nem2Sdk.MosaicId,
TransactionHttp = nem2Sdk.TransactionHttp,
AccountHttp = nem2Sdk.AccountHttp,
MosaicHttp = nem2Sdk.MosaicHttp,
NamespaceHttp = nem2Sdk.NamespaceHttp,
MosaicService = nem2Sdk.MosaicService,
XEM = nem2Sdk.XEM,
AggregateTransaction = nem2Sdk.AggregateTransaction,
PublicAccount = nem2Sdk.PublicAccount,
LockFundsTransaction = nem2Sdk.LockFundsTransaction,
Listener = nem2Sdk.Listener,
CosignatureTransaction = nem2Sdk.CosignatureTransaction,
SecretLockTransaction = nem2Sdk.SecretLockTransaction,
SecretProofTransaction = nem2Sdk.SecretProofTransaction,
HashType = nem2Sdk.HashType
ModifyMultisigAccountTransaction = nem2Sdk.ModifyMultisigAccountTransaction,
MultisigCosignatoryModificationType = nem2Sdk.MultisigCosignatoryModificationType,
MultisigCosignatoryModification = nem2Sdk.MultisigCosignatoryModification,
RegisterNamespaceTransaction = nem2Sdk.RegisterNamespaceTransaction,
MosaicDefinitionTransaction = nem2Sdk.MosaicDefinitionTransaction,
MosaicSupplyChangeTransaction = nem2Sdk.MosaicSupplyChangeTransaction,
MosaicProperties = nem2Sdk.MosaicProperties,
MosaicSupplyType = nem2Sdk.MosaicSupplyType;
const sha3_512 = jssha3.sha3_512;
/*
Alice:
private: 7808B5B53ECF24E40BE17B8EC3D0EB5F7C3F3D938E0D95A415F855AD4C27B2A4
public: 5D9513282B65A12A1B68DCB67DB64245721F7AE7822BE441FE813173803C512C
address: SBWEUWON6IBHCW5IC4EI6V6SMTVJGCJWGLF57UGK
Bob:
private: 31B96EEB0C7FD6F8FB6B4ED09A9EB142A42B194AFBEB9EB52F0B79889F22326E
public: 3390BF02D2BB59C8722297FF998CE89183D0906E469873284C091A5CDC22FD57
address: SB2Y5ND4FDLBIO5KHXTKRWODDG2QHIN73DTYT2PC
Multisig:
private: E0BC90AA55A8D78A1DC8CE203A95C31A62E1EAF43D7BF94379709B79D90E0545
public: 4CA83B9053C907AC7D9A5A0C26895489C8D07ADC57EF9AF1B8045775E0C91D31
address: SBHAN5NVIMDZBYTYPBIHCZ5I5EZZO2WSGJ6PGKFI
*/
const signAndDisplay = (signData, privateKey) => {
const keypair = nem2lib.KeyPair.createKeyPairFromPrivateKeyString(privateKey);
const signature = nem2lib.KeyPair.sign(keypair, signData);
console.log('signature: ' + nem2lib.convert.uint8ToHex(signature));
};
const payloadDisplay = (sinedTransaction) => {
console.log('payload : ' + sinedTransaction.payload.substring(8,136));
};
const alicePrivateKey = '7808B5B53ECF24E40BE17B8EC3D0EB5F7C3F3D938E0D95A415F855AD4C27B2A4';
const aliceAccount = Account.createFromPrivateKey(alicePrivateKey,NetworkType.MIJIN_TEST);
const bobPrivateKey = '31B96EEB0C7FD6F8FB6B4ED09A9EB142A42B194AFBEB9EB52F0B79889F22326E';
const bobAccount = Account.createFromPrivateKey(bobPrivateKey,NetworkType.MIJIN_TEST);
const multisigPrivateKey = 'E0BC90AA55A8D78A1DC8CE203A95C31A62E1EAF43D7BF94379709B79D90E0545';
const multisigAccount = Account.createFromPrivateKey(multisigPrivateKey,NetworkType.MIJIN_TEST);
// ***************************************************
// Transfer Transaction
// ***************************************************
// Alice to Bob
const transferTransaction = TransferTransaction.create(
Deadline.create(),
bobAccount.address,
[new Mosaic(new MosaicId('nem:xem'), UInt64.fromUint(10000000))],
PlainMessage.create(''),
NetworkType.MIJIN_TEST,
);
const signedTransferTransaction = aliceAccount.sign(transferTransaction);
console.log('Transfer Transaction');
signAndDisplay(signedTransferTransaction.payload.substring(200), alicePrivateKey);
payloadDisplay(signedTransferTransaction);
// ***************************************************
// Aggregate Complete Transaction
// ***************************************************
// Alice to Alice
const transferTransaction2 = TransferTransaction.create(
Deadline.create(),
aliceAccount.address,
[new Mosaic(new MosaicId('nem:xem'), UInt64.fromUint(10000000))],
PlainMessage.create(''),
NetworkType.MIJIN_TEST,
);
const aggregateCompleteTransaction = AggregateTransaction.createComplete(
Deadline.create(),
[
transferTransaction.toAggregate(aliceAccount.publicAccount), // Alice to Bob
transferTransaction2.toAggregate(aliceAccount.publicAccount) // Alice to Alice
],
NetworkType.MIJIN_TEST,
[]
);
const signedAggregateCompleteTransaction = aliceAccount.sign(aggregateCompleteTransaction);
console.log('Aggregate Complete Transaction');
signAndDisplay(signedAggregateCompleteTransaction.payload.substring(200), alicePrivateKey);
payloadDisplay(signedAggregateCompleteTransaction);
// ***************************************************
// Aggregate Bonded Transaction
// ***************************************************
// Bob to Alice
const transferTransaction3 = TransferTransaction.create(
Deadline.create(),
aliceAccount.address,
[new Mosaic(new MosaicId('nem:xem'), UInt64.fromUint(10000000))],
PlainMessage.create(''),
NetworkType.MIJIN_TEST,
);
const aggregateBondedTransaction = AggregateTransaction.createBonded(Deadline.create(),
[
transferTransaction.toAggregate(aliceAccount.publicAccount), // Alice to Bob
transferTransaction3.toAggregate(bobAccount.publicAccount), // Bob to Alice
],
NetworkType.MIJIN_TEST
);
const sinedAggregateBondedTransaction = aliceAccount.sign(aggregateBondedTransaction);
console.log('Aggregate Bonded Transaction');
signAndDisplay(sinedAggregateBondedTransaction.payload.substring(200), alicePrivateKey);
payloadDisplay(sinedAggregateBondedTransaction);
// ***************************************************
// LockFunds Transaction
// ***************************************************
const lockFundsTransaction = LockFundsTransaction.create(
Deadline.create(),
new Mosaic( new MosaicId('nem:xem'), UInt64.fromUint(10000000)),
UInt64.fromUint(480),
sinedAggregateBondedTransaction,
NetworkType.MIJIN_TEST
);
const signedLockFundsTransaction = aliceAccount.sign(lockFundsTransaction);
console.log('LockFunds Transaction');
signAndDisplay(signedLockFundsTransaction.payload.substring(200), alicePrivateKey);
payloadDisplay(signedLockFundsTransaction);
// ***************************************************
// SecretLock Transaction
// ***************************************************
const random = crypto.randomBytes(10);
const hash = sha3_512.create();
const secret = hash.update(random).hex().toUpperCase();
const proof = random.toString('hex');
// Alice to Alice
const secretLockTransaction = SecretLockTransaction.create(
Deadline.create(),
new Mosaic( new MosaicId('nem:xem'), UInt64.fromUint(10000000)),
UInt64.fromUint(60), //officially 96h
HashType.SHA3_512,
secret,
aliceAccount.address,
NetworkType.MIJIN_TEST
);
const signedSecretLockTransaction = aliceAccount.sign(secretLockTransaction);
console.log('SecretLock Transaction');
signAndDisplay(signedSecretLockTransaction.payload.substring(200), alicePrivateKey);
payloadDisplay(signedSecretLockTransaction);
// ***************************************************
// SecretProof Transaction
// ***************************************************
const secretProofTransaction = SecretProofTransaction.create(
Deadline.create(),
HashType.SHA3_512,
secret,
proof,
NetworkType.MIJIN_TEST
);
const signedSecretProofTransaction = aliceAccount.sign(secretProofTransaction);
console.log('SecretProof Transaction');
signAndDisplay(signedSecretProofTransaction.payload.substring(200), alicePrivateKey);
payloadDisplay(signedSecretProofTransaction);
// ***************************************************
// ModifyMultisigAccount Transaction
// ***************************************************
const modifyMultisigAccountTransaction = ModifyMultisigAccountTransaction.create(
Deadline.create(),
2,
1,
[
new MultisigCosignatoryModification(
MultisigCosignatoryModificationType.Add,
aliceAccount.publicAccount,
),
new MultisigCosignatoryModification(
MultisigCosignatoryModificationType.Add,
bobAccount.publicAccount,
)],
NetworkType.MIJIN_TEST
);
const signedModifyMultisigAccountTransaction = multisigAccount.sign(modifyMultisigAccountTransaction);
console.log('ModifyMultisigAccount Transaction');
signAndDisplay(signedModifyMultisigAccountTransaction.payload.substring(200), multisigPrivateKey);
payloadDisplay(signedModifyMultisigAccountTransaction);
// ***************************************************
// RegisterNamespace Transaction
// ***************************************************
const registerNamespaceTransaction = RegisterNamespaceTransaction.createRootNamespace(
Deadline.create(),
'mynamespace',
UInt64.fromUint(1000),
NetworkType.MIJIN_TEST,
);
const signedRegisterNamespaceTransaction = aliceAccount.sign(registerNamespaceTransaction);
console.log('RegisterNamespace Transaction');
signAndDisplay(signedRegisterNamespaceTransaction.payload.substring(200), alicePrivateKey);
payloadDisplay(signedRegisterNamespaceTransaction);
// ***************************************************
// ModifyMultisigAccount Transaction
// ***************************************************
const mosaicDefinitionTransaction = MosaicDefinitionTransaction.create(
Deadline.create(),
'mymosaic',
'mynamespace',
MosaicProperties.create({
supplyMutable: true,
transferable: true,
levyMutable: false,
divisibility: 0,
duration: UInt64.fromUint(1000),
}),
NetworkType.MIJIN_TEST,
);
const signedMosaicDefinitionTransaction = aliceAccount.sign(mosaicDefinitionTransaction);
console.log('ModifyMultisigAccount Transaction');
signAndDisplay(signedMosaicDefinitionTransaction.payload.substring(200), alicePrivateKey);
payloadDisplay(signedMosaicDefinitionTransaction);
// ***************************************************
// MosaicSupplyChange Transaction
// ***************************************************
const mosaicSupplyChangeTransaction = MosaicSupplyChangeTransaction.create(
Deadline.create(),
mosaicDefinitionTransaction.mosaicId,
MosaicSupplyType.Increase,
UInt64.fromUint(1000000),
NetworkType.MIJIN_TEST,
);
const signedMosaicSupplyChangeTransaction = aliceAccount.sign(mosaicSupplyChangeTransaction);
console.log('MosaicSupplyChange Transaction');
signAndDisplay(signedMosaicSupplyChangeTransaction.payload.substring(200), alicePrivateKey);
payloadDisplay(signedMosaicSupplyChangeTransaction);
// ***************************************************
// Cosignature Transaction
// ***************************************************
const accountHttp = new AccountHttp('http://localhost:3000');
const transactionHttp = new TransactionHttp('http://localhost:3000');
setTimeout(() => {
transactionHttp.announce(signedLockFundsTransaction).subscribe(
x => x,
err => console.error(err)
)}
, 0);
setTimeout(() => {
transactionHttp.announceAggregateBonded(sinedAggregateBondedTransaction).subscribe(
x => x,
err => console.error(err)
)}
, 20000);
console.log('Cosignature Transaction');
signAndDisplay(sinedAggregateBondedTransaction.hash, bobPrivateKey);
const cosignAggregateBondedTransaction = (transaction, account) => {
const cosignatureTransaction = CosignatureTransaction.create(transaction);
const signedTransaction = account.signCosignatureTransaction(cosignatureTransaction);
console.log('payload : ' + signedTransaction.signature);
return signedTransaction;
};
setTimeout(() => {
accountHttp.aggregateBondedTransactions(bobAccount.publicAccount)
.flatMap((_) => _)
.filter((_) => !_.signedByAccount(bobAccount.publicAccount))
.map(transaction => cosignAggregateBondedTransaction(transaction, bobAccount))
.flatMap(cosignatureSignedTransaction => transactionHttp.announceAggregateBondedCosignature(cosignatureSignedTransaction))
.subscribe(x => x,
err => console.error(err));
}
, 21000);
/**
* @param {KeyPair } keyPair KeyPair instance
* @returns {module:model/TransactionPayload} - Signed Transaction Payload
*/
signTransaction(keyPair) {
const byteBuffer = this.serialize();
const signingBytes = byteBuffer.slice(4 + 64 + 32);
const keyPairEncoded = KeyPair.createKeyPairFromPrivateKeyString(keyPair.privateKey);
const signature = Array.from(KeyPair.sign(keyPair, new Uint8Array(signingBytes)));
const signedTransactionBuffer = byteBuffer
.splice(0, 4)
.concat(signature)
.concat(Array.from(keyPairEncoded.publicKey))
.concat(byteBuffer
.splice(64 + 32, byteBuffer.length));
const payload = convert.uint8ToHex(signedTransactionBuffer);
return {
payload,
hash: VerifiableTransaction.createTransactionHash(payload)
};
}
serialize() {
return this.schema.serialize(Array.from(this.bytes));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment