この記事の続きです
前回はAggregateTransactionmの署名を検証しました.ここではAggregateTransactionの署名者,つまりAggregateTransactionのアナウンスを行う者の検証を行なっただけで連署人の署名を検証することはできていません.AgregateTransacionではcomplete,Bondedのどちらの場合でも複数人による署名を行う,連署を行うことができます.そこで今回は前回の続きとして連署の検証を行なってみました.
連署は何に対して行なっているのか
SDKを追ってみたところ,連署はAggregateTransacionの親ハッシュを含んだ52バイトに対して行われていました.
つまり検証したい場合はこのハッシュを署名に使ったデータとすれば良いことになります.
通常のトランサクションの署名ではgenarationHashをデータの先頭に付与して行うのですが,連署ではgenerationHashの付与は行わないのがポイントの一つです.
#検証する
これまでは検証するデータとしてトランザクションの内容を使用して来ましたが,これをハッシュに置き換えてあげればOKです.あとは通常と同じように署名者の公開鍵,署名をtweetnaclの関数に入れてあげます.
function validateCosignature(cosignatureTx,hash){
try{
const signature = stringToUint8Array(cosignatureTx.signature);
const signerPublicKey = stringToUint8Array(cosignatureTx.signerPublicKey);
const validateData = stringToUint8Array(hash);
if (nacl.sign.detached.verify(validateData, signature, signerPublicKey)) return true;
else return false;
}catch(e){
console.log(e)
return false;
}
}
全文です
const xym = require('symbol-sdk');
const nacl = require("tweetnacl");
var networkGenerationHash = '';
var epochAdjustment = '';
var repo;
var node;
var networkType = xym.NetworkType.TEST_NET;
const privateKey = ''.padStart(64,"0");
//送信元アカウント
const listenAccount = xym.Account.createFromPrivateKey(
privateKey,
networkType,
);
const swapAccount = xym.Account.createFromPrivateKey(
"".padStart(64,"1"),
networkType
);
(async () => {
node = 'https://sym-test-09.opening-line.jp:3001';
repo = new xym.RepositoryFactoryHttp(node);
await getInfo()
// simpleTx()
swapTx()
})();
async function getInfo() {
epochAdjustment = await repo.getEpochAdjustment().toPromise();
networkGenerationHash = await repo.getGenerationHash().toPromise();
}
function swapTx(){
const tx = xym.TransferTransaction.create(
xym.Deadline.create(epochAdjustment),
listenAccount.address,
[],
xym.PlainMessage.create(""),
networkType
).toAggregate(listenAccount.publicAccount);
const tx2 = xym.TransferTransaction.create(
xym.Deadline.create(epochAdjustment),
listenAccount.address,
[],
xym.PlainMessage.create(""),
networkType
).toAggregate(swapAccount.publicAccount);
const agg = xym.AggregateTransaction.createComplete(
xym.Deadline.create(epochAdjustment),
[tx,tx2],
networkType,
[],
).setMaxFeeForAggregate(1);
const st = listenAccount.sign(agg, networkGenerationHash);
const cosig = xym.CosignatureTransaction.signTransactionHash(
swapAccount,st.hash
);
console.log(validateCosignature(cosig,st.hash));
}
function stringToUint8Array(str){
const buf = Buffer.from(str,"hex");
return bufferToUint8Array(buf);
}
function bufferToUint8Array(buf) {
const view = new Uint8Array(buf.length);
for (let i = 0; i < buf.length; ++i) {
view[i] = buf[i];
}
return view;
}
function validateCosignature(cosignatureTx,hash){
try{
const signature = stringToUint8Array(cosignatureTx.signature);
const signerPublicKey = stringToUint8Array(cosignatureTx.signerPublicKey);
const validateData = stringToUint8Array(hash);
if (nacl.sign.detached.verify(validateData, signature, signerPublicKey)) return true;
else return false;
}catch(e){
console.log(e)
return false;
}
}
自力で連署を作成する
今回は署名するデータがハッシュなので自力で連署を生成するのも結構簡単です.
const cosignature = nacl.sign.detached(bufferToUint8Array(Buffer.from(st.hash,"hex")),makeKeyPair(swapAccount));
function makeKeyPair(account){
const prikey = bufferToUint8Array(Buffer.from(account.privateKey,"hex"));
const pubkey = bufferToUint8Array(Buffer.from(account.publicKey,"hex"));
return new Uint8Array([...prikey, ...pubkey]);
}
オフライン環境での連署生成時の注意点
先に述べたように,連署はAggregateTransactionのハッシュに対して行われており,トランザクションのペイロードを全て相手に伝えなくても連署を行うことが可能です.これにより,Payloadが非常に長くなってしまう場合でもhashを伝えるだけで連署を行うことが可能です.
しかしながらこの方法を採用する場合,連署人はトランザクションの内容を知ることなく検証が行えてしまいます.また,ハッシュから元のトランザクションの内容を知ることは出来ません.このため,ハッシュに対してのみ連署を行うと”トランザクションの内容をみていないのに署名”といったセキュリティ的には非常によろしくない状態になります.
これ問題を解決するには,ペイロードからトランザクションハッシュを作成し,トランザクションを精査した上で署名を行うようにすればOKです
検証が不十分でした,アグリゲートの完全な検証についてはこちらを参考にしてください
const tx = xym.TransactionMapping.createFromPayload(
"***"
)
//hogehogeVerify()のようなTXの検証関数を作る
if(hogehogeVerify(tx))xym.CosignatureTransaction.signTransactionHash( tx.transactionInfo.hash)
オフラインで連署を行う際はハッシュに対して連署を行うのではなく,必ず相手からトランザクションのペイロードを受け取り,これを検証してから行うようにしましょう.