const Buffer = require('safe-buffer').Buffer
const Message = require('primea-message')
const Pipe = require('buffer-pipe')
const secp256k1 = require('secp256k1')
const leb128 = require('leb128').unsigned
const crypto = require('node-webcrypto-shim')
module.exports = class DfinityTx extends Message {
serialize (inculdeSig = this.signature.length !== 0) {
const args = [
leb128.encode(this.version),
this.to,
leb128.encode(this.caps),
leb128.encode(this.ticks),
leb128.encode(this.ticksPrice),
leb128.encode(this.nonce),
leb128.encode(this.data.length),
this.data,
inculdeSig ? this.signature : Buffer.from([]),
inculdeSig ? Buffer.from([this.recovery]) : Buffer.from([])
]
return Buffer.concat(args)
}
async sign (secretKey) {
const serialized = this.serialize(false)
const hash = await DfinityTx.hash(serialized)
const sig = secp256k1.sign(hash, secretKey)
this.signature = sig.signature
this.recovery = sig.recovery
return Buffer.concat([serialized, sig.signature, Buffer.from([sig.recovery])])
}
static hash (serialized) {
return crypto.subtle.digest({
name: 'SHA-256'
}, serialized).then(function (hash) {
// returns the hash as an ArrayBuffer
return new Uint8Array(hash)
})
}
static async validateSignature (serialized) {
const sig = serialized.slice(-65, -1)
const recovery = serialized[serialized.length - 1]
const hash = await DfinityTx.hash(serialized)
let publicKey
try {
publicKey = secp256k1.recover(hash, sig, recovery)
} catch (e) {
publicKey = false
}
return publicKey
}
static async deserialize (raw) {
const publicKey = await DfinityTx.validateSignature(raw)
const p = new Pipe(raw)
const json = {
version: leb128.read(p),
to: p.read(20),
caps: leb128.read(p),
ticks: leb128.read(p),
ticksPrice: leb128.read(p),
nonce: leb128.read(p),
data: p.read(leb128.read(p)),
signature: p.read(64),
recovery: p.buffer[0],
publicKey: publicKey
}
return new DfinityTx(json)
}
static get defaults () {
return {
version: 0,
to: new Uint8Array(20),
caps: 0,
ticks: 0,
ticksPrice: 0,
nonce: 0,
height: 0,
data: new Uint8Array([]),
publicKey: new Uint8Array(32),
signature: new Uint8Array([]),
recovery: 0
}
}
}
|