const S = require('@emurgo/cardano-serialization-lib-nodejs'); //serialization-lib: https://github.com/Emurgo/cardano-serialization-lib
const MS = require('./message-signing/rust/pkg/emurgo_message_signing'); //message-signing: https://github.com/Emurgo/message-signing/blob/master/examples/rust/src/main.rs
// Example runs in Node.js (to verify in a browser, the libraries need to be imported asynchronously)
/**
*
* @param {string} address - hex encoded
* @param {string} payload - hex encoded
* @param {string} coseSign1Hex - hex encoded
*/
const verify = (address, payload, coseSign1Hex) => {
const coseSign1 = MS.COSESign1.from_bytes(Buffer.from(coseSign1Hex, 'hex'));
const payloadCose = coseSign1.payload();
if (verifyPayload(payload, payloadCose))
throw new Error('Payload does not match');
const protectedHeaders = coseSign1
.headers()
.protected()
.deserialized_headers();
const addressCose = S.Address.from_bytes(
protectedHeaders.header(MS.Label.new_text('address')).as_bytes()
);
const publicKeyCose = S.PublicKey.from_bytes(protectedHeaders.key_id());
if (!verifyAddress(address, addressCose, publicKeyCose))
throw new Error('Could not verify because of address mismatch');
const signature = S.Ed25519Signature.from_bytes(coseSign1.signature());
const data = coseSign1.signed_data().to_bytes();
return publicKeyCose.verify(data, signature);
};
const verifyPayload = (payload, payloadCose) => {
return Buffer.from(payloadCose, 'hex').compare(Buffer.from(payload, 'hex'));
};
const verifyAddress = (address, addressCose, publicKeyCose) => {
const checkAddress = S.Address.from_bytes(Buffer.from(address, 'hex'));
if (addressCose.to_bech32() !== checkAddress.to_bech32()) return false;
// check if BaseAddress
try {
const baseAddress = S.BaseAddress.from_address(addressCose);
//reconstruct address
const paymentKeyHash = publicKeyCose.hash();
const stakeKeyHash = baseAddress.stake_cred().to_keyhash();
const reconstructedAddress = S.BaseAddress.new(
checkAddress.network_id(),
S.StakeCredential.from_keyhash(paymentKeyHash),
S.StakeCredential.from_keyhash(stakeKeyHash)
);
if (
checkAddress.to_bech32() !== reconstructedAddress.to_address().to_bech32()
)
return false;
return true;
} catch (e) {}
// check if RewardAddress
try {
//reconstruct address
const stakeKeyHash = publicKeyCose.hash();
const reconstructedAddress = S.RewardAddress.new(
checkAddress.network_id(),
S.StakeCredential.from_keyhash(stakeKeyHash)
);
if (
checkAddress.to_bech32() !== reconstructedAddress.to_address().to_bech32()
)
return false;
return true;
} catch (e) {}
return false;
};
//test
verify(<address>, <payload>, <cose>) //: true or false