Phillip Lang Martinez
2 months ago
9 changed files with 781 additions and 22 deletions
Binary file not shown.
@ -0,0 +1,145 @@
|
||||
// @ts-nocheck
|
||||
|
||||
import { QORT_DECIMALS, TX_TYPES } from '../constants/constants' |
||||
import nacl from '../deps/nacl-fast' |
||||
import Base58 from '../deps/Base58' |
||||
import utils from '../utils/utils' |
||||
|
||||
export default class ChatBase { |
||||
static get utils() { |
||||
return utils |
||||
} |
||||
|
||||
static get nacl() { |
||||
return nacl |
||||
} |
||||
|
||||
static get Base58() { |
||||
return Base58 |
||||
} |
||||
|
||||
constructor() { |
||||
this.fee = 0 |
||||
this.groupID = 0 |
||||
this.tests = [ |
||||
() => { |
||||
if (!(this._type >= 1 && this._type in TX_TYPES)) { |
||||
return 'Invalid type: ' + this.type |
||||
} |
||||
return true |
||||
}, |
||||
() => { |
||||
if (this._fee < 0) { |
||||
return 'Invalid fee: ' + this._fee / QORT_DECIMALS |
||||
} |
||||
return true |
||||
}, |
||||
() => { |
||||
if (this._groupID < 0 || !Number.isInteger(this._groupID)) { |
||||
return 'Invalid groupID: ' + this._groupID |
||||
} |
||||
return true |
||||
}, |
||||
() => { |
||||
if (!(new Date(this._timestamp)).getTime() > 0) { |
||||
return 'Invalid timestamp: ' + this._timestamp |
||||
} |
||||
return true |
||||
}, |
||||
() => { |
||||
if (!(this._lastReference instanceof Uint8Array && this._lastReference.byteLength == 64)) { |
||||
return 'Invalid last reference: ' + this._lastReference |
||||
} |
||||
return true |
||||
}, |
||||
() => { |
||||
if (!(this._keyPair)) { |
||||
return 'keyPair must be specified' |
||||
} |
||||
if (!(this._keyPair.publicKey instanceof Uint8Array && this._keyPair.publicKey.byteLength === 32)) { |
||||
return 'Invalid publicKey' |
||||
} |
||||
if (!(this._keyPair.privateKey instanceof Uint8Array && this._keyPair.privateKey.byteLength === 64)) { |
||||
return 'Invalid privateKey' |
||||
} |
||||
return true |
||||
} |
||||
] |
||||
} |
||||
|
||||
set keyPair(keyPair) { |
||||
this._keyPair = keyPair |
||||
} |
||||
|
||||
set type(type) { |
||||
this.typeText = TX_TYPES[type] |
||||
this._type = type |
||||
this._typeBytes = this.constructor.utils.int32ToBytes(this._type) |
||||
} |
||||
|
||||
set groupID(groupID) { |
||||
this._groupID = groupID |
||||
this._groupIDBytes = this.constructor.utils.int32ToBytes(this._groupID) |
||||
} |
||||
|
||||
set timestamp(timestamp) { |
||||
this._timestamp = timestamp |
||||
this._timestampBytes = this.constructor.utils.int64ToBytes(this._timestamp) |
||||
} |
||||
|
||||
set fee(fee) { |
||||
this._fee = fee * QORT_DECIMALS |
||||
this._feeBytes = this.constructor.utils.int64ToBytes(this._fee) |
||||
} |
||||
|
||||
set lastReference(lastReference) { |
||||
this._lastReference = lastReference instanceof Uint8Array ? lastReference : this.constructor.Base58.decode(lastReference) |
||||
} |
||||
|
||||
get params() { |
||||
return [ |
||||
this._typeBytes, |
||||
this._timestampBytes, |
||||
this._groupIDBytes, |
||||
this._lastReference, |
||||
this._keyPair.publicKey |
||||
] |
||||
} |
||||
|
||||
get chatBytes() { |
||||
const isValid = this.validParams() |
||||
if (!isValid.valid) { |
||||
throw new Error(isValid.message) |
||||
} |
||||
|
||||
let result = new Uint8Array() |
||||
|
||||
this.params.forEach(item => { |
||||
result = this.constructor.utils.appendBuffer(result, item) |
||||
}) |
||||
|
||||
this._chatBytes = result |
||||
|
||||
return this._chatBytes |
||||
} |
||||
|
||||
validParams() { |
||||
let finalResult = { |
||||
valid: true |
||||
} |
||||
|
||||
this.tests.some(test => { |
||||
const result = test() |
||||
if (result !== true) { |
||||
finalResult = { |
||||
valid: false, |
||||
message: result |
||||
} |
||||
return true |
||||
} |
||||
}) |
||||
|
||||
return finalResult |
||||
} |
||||
|
||||
} |
@ -0,0 +1,92 @@
|
||||
// @ts-nocheck
|
||||
|
||||
import ChatBase from './ChatBase' |
||||
import nacl from '../deps/nacl-fast' |
||||
import ed2curve from '../deps/ed2curve' |
||||
import { Sha256 } from 'asmcrypto.js' |
||||
import { CHAT_REFERENCE_FEATURE_TRIGGER_TIMESTAMP } from '../constants/constants' |
||||
|
||||
export default class ChatTransaction extends ChatBase { |
||||
constructor() { |
||||
super() |
||||
this.type = 18 |
||||
this.fee = 0 |
||||
} |
||||
|
||||
set recipientPublicKey(recipientPublicKey) { |
||||
this._base58RecipientPublicKey = recipientPublicKey instanceof Uint8Array ? this.constructor.Base58.encode(recipientPublicKey) : recipientPublicKey |
||||
this._recipientPublicKey = this.constructor.Base58.decode(this._base58RecipientPublicKey) |
||||
} |
||||
|
||||
set proofOfWorkNonce(proofOfWorkNonce) { |
||||
this._proofOfWorkNonce = this.constructor.utils.int32ToBytes(proofOfWorkNonce) |
||||
} |
||||
|
||||
set recipient(recipient) { |
||||
this._recipient = recipient instanceof Uint8Array ? recipient : this.constructor.Base58.decode(recipient) |
||||
this._hasReceipient = new Uint8Array(1) |
||||
this._hasReceipient[0] = 1 |
||||
} |
||||
|
||||
set hasChatReference(hasChatReference) { |
||||
this._hasChatReference = new Uint8Array(1) |
||||
this._hasChatReference[0] = hasChatReference |
||||
} |
||||
|
||||
set chatReference(chatReference) { |
||||
this._chatReference = chatReference instanceof Uint8Array ? chatReference : this.constructor.Base58.decode(chatReference) |
||||
} |
||||
|
||||
set message(message) { |
||||
this.messageText = message; |
||||
this._message = this.constructor.utils.stringtoUTF8Array(message) |
||||
this._messageLength = this.constructor.utils.int32ToBytes(this._message.length) |
||||
} |
||||
|
||||
set isEncrypted(isEncrypted) { |
||||
this._isEncrypted = new Uint8Array(1) |
||||
this._isEncrypted[0] = isEncrypted |
||||
|
||||
if (isEncrypted === 1) { |
||||
const convertedPrivateKey = ed2curve.convertSecretKey(this._keyPair.privateKey) |
||||
const convertedPublicKey = ed2curve.convertPublicKey(this._recipientPublicKey) |
||||
const sharedSecret = new Uint8Array(32) |
||||
nacl.lowlevel.crypto_scalarmult(sharedSecret, convertedPrivateKey, convertedPublicKey) |
||||
|
||||
this._chatEncryptionSeed = new Sha256().process(sharedSecret).finish().result |
||||
this._encryptedMessage = nacl.secretbox(this._message, this._lastReference.slice(0, 24), this._chatEncryptionSeed) |
||||
} |
||||
|
||||
this._myMessage = isEncrypted === 1 ? this._encryptedMessage : this._message |
||||
this._myMessageLenth = isEncrypted === 1 ? this.constructor.utils.int32ToBytes(this._myMessage.length) : this._messageLength |
||||
} |
||||
|
||||
set isText(isText) { |
||||
this._isText = new Uint8Array(1) |
||||
this._isText[0] = isText |
||||
} |
||||
|
||||
get params() { |
||||
const params = super.params |
||||
params.push( |
||||
this._proofOfWorkNonce, |
||||
this._hasReceipient, |
||||
this._recipient, |
||||
this._myMessageLenth, |
||||
this._myMessage, |
||||
this._isEncrypted, |
||||
this._isText, |
||||
this._feeBytes |
||||
) |
||||
|
||||
// After the feature trigger timestamp we need to include chat reference
|
||||
if (new Date(this._timestamp).getTime() >= CHAT_REFERENCE_FEATURE_TRIGGER_TIMESTAMP) { |
||||
params.push(this._hasChatReference) |
||||
|
||||
if (this._hasChatReference[0] == 1) { |
||||
params.push(this._chatReference) |
||||
} |
||||
} |
||||
return params |
||||
} |
||||
} |
@ -0,0 +1,40 @@
|
||||
// @ts-nocheck
|
||||
|
||||
import nacl from '../deps/nacl-fast' |
||||
import utils from '../utils/utils' |
||||
|
||||
export const signChat = (chatBytes, nonce, keyPair) => { |
||||
|
||||
if (!chatBytes) { |
||||
throw new Error('Chat Bytes not defined') |
||||
} |
||||
|
||||
if (!nonce) { |
||||
throw new Error('Nonce not defined') |
||||
} |
||||
|
||||
if (!keyPair) { |
||||
throw new Error('keyPair not defined') |
||||
} |
||||
|
||||
const _nonce = utils.int32ToBytes(nonce) |
||||
|
||||
if (chatBytes.length === undefined) { |
||||
const _chatBytesBuffer = Object.keys(chatBytes).map(function (key) { return chatBytes[key]; }) |
||||
|
||||
const chatBytesBuffer = new Uint8Array(_chatBytesBuffer) |
||||
chatBytesBuffer.set(_nonce, 112) |
||||
|
||||
const signature = nacl.sign.detached(chatBytesBuffer, keyPair.privateKey) |
||||
|
||||
return utils.appendBuffer(chatBytesBuffer, signature) |
||||
} else { |
||||
const chatBytesBuffer = new Uint8Array(chatBytes) |
||||
chatBytesBuffer.set(_nonce, 112) |
||||
|
||||
const signature = nacl.sign.detached(chatBytesBuffer, keyPair.privateKey) |
||||
|
||||
return utils.appendBuffer(chatBytesBuffer, signature) |
||||
} |
||||
} |
||||
|
Loading…
Reference in new issue