UNPKG

wowok

Version:

Wowok Blockchain TypeScript API

1 lines 8.32 kB
import{falcon512padded}from'@noble/post-quantum/falcon.js';import{sha256}from'@noble/hashes/sha256';import{randomBytes}from'@noble/hashes/utils';function verifyFalcon512(a,b,c){try{return falcon512padded['verify'](c,b,a);}catch{return![];}}export function hashSha256(a){return sha256(a);}export function hashMessage(a){const b=sha256(new TextEncoder()['encode'](a));return bytesToHex(b);}export function hashPlaintext(a,b,c,d,e){let f=a;e!==undefined&&e>=0x0&&(f+=e['toString']());f+=b['toString']();c&&(f+=c);d&&(f+=d);const g=sha256(new TextEncoder()['encode'](f));return'0x'+bytesToHex(g);}export function generateNonce(){return bytesToHex(randomBytes(0x10));}export function bytesToBase64(a){return Buffer['from'](a)['toString']('base64');}export function base64ToBytes(a){return new Uint8Array(Buffer['from'](a,'base64'));}export function bytesToHex(a){return Buffer['from'](a)['toString']('hex');}export function hexToBytes(a){return new Uint8Array(Buffer['from'](a,'hex'));}export function arrayBufferToUint8Array(a){return new Uint8Array(a);}export function uint8ArrayToArrayBuffer(a){const b=a['buffer']['slice'](a['byteOffset'],a['byteOffset']+a['byteLength']);return b;}export function bufferEqual(c,d){if(c['byteLength']!==d['byteLength'])return![];const e=new Uint8Array(c),f=new Uint8Array(d);for(let g=0x0;g<e['length'];g++){if(e[g]!==f[g])return![];}return!![];}export function calculateMerkleLeafHash(a,b){const c=new TextEncoder()['encode'](a),d=new ArrayBuffer(0x8),e=new DataView(d);e['setBigUint64'](0x0,BigInt(b),!![]);const f=new Uint8Array(d),g=new Uint8Array(c['length']+f['length']);g['set'](c),g['set'](f,c['length']);const h=sha256(g);return'0x'+bytesToHex(h);}export function merkleHash(a,b){const c=hexToBytes(a['replace'](/^0x/,'')),d=hexToBytes(b['replace'](/^0x/,'')),e=new Uint8Array(c['length']+d['length']);return e['set'](c),e['set'](d,c['length']),'0x'+bytesToHex(sha256(e));}export function computeNewRoot(a,b,c){const d=new TextEncoder()['encode'](a),e=new TextEncoder()['encode'](b),f=new ArrayBuffer(0x4),g=new DataView(f);g['setUint32'](0x0,c,!![]);const h=new Uint8Array(f),i=new Uint8Array(d['length']+e['length']+h['length']);return i['set'](d),i['set'](e,d['length']),i['set'](h,d['length']+e['length']),'0x'+bytesToHex(sha256(i));}export function verifyMerkleProof(a,b){let c=a;for(let d=0x0;d<b['siblings']['length'];d++){b['indices'][d]===0x0?c=merkleHash(c,b['siblings'][d]):c=merkleHash(b['siblings'][d],c);}return c===b['root'];}export function verifyMerkleChain(a,b){if(a['length']===0x0)return{'valid':!![]};const c=[...a]['sort']((f,g)=>f['leafIndex']-g['leafIndex']),d=b||'0x'+'0'['repeat'](0x40);let e=d;for(const f of c){if(f['prevRoot']['toLowerCase']()!==e['toLowerCase']())return{'valid':![],'error':'Root\x20chain\x20broken\x20at\x20leafIndex\x20'+f['leafIndex']+':\x20expected\x20prevRoot\x20'+e+',\x20got\x20'+f['prevRoot'],'expectedRoot':e,'actualRoot':f['prevRoot']};const g=verifySingleMerkleRoot(f['prevRoot'],f['newRoot'],f['plaintextHash'],f['serverTimestamp'],f['leafIndex']);if(!g['valid'])return{'valid':![],'error':g['error']+'\x20at\x20leafIndex\x20'+f['leafIndex'],'expectedRoot':g['expectedRoot'],'actualRoot':g['actualRoot']};e=f['newRoot'];}return{'valid':!![]};}export function verifySingleMerkleRoot(a,b,c,d,e){if(!a)return{'valid':![],'error':'Missing\x20prevRoot'};if(!b)return{'valid':![],'error':'Missing\x20newRoot'};if(!c)return{'valid':![],'error':'Missing\x20plaintextHash'};if(d===undefined||d===null)return{'valid':![],'error':'Missing\x20serverTimestamp'};if(e===undefined||e===null)return{'valid':![],'error':'Missing\x20leafIndex'};const f=calculateMerkleLeafHash(c,d),g=computeNewRoot(a,f,e);if(g['toLowerCase']()!==b['toLowerCase']())return{'valid':![],'error':'Root\x20computation\x20mismatch:\x20expected\x20'+g+',\x20got\x20'+b,'expectedRoot':g,'actualRoot':b};return{'valid':!![]};}export function verifyMessage(a){const {messageId:b,plaintext:c,plaintextHash:d,createdAt:e,guardAddress:f,passportAddress:g,lastReceivedLeafIndex:h,serverSignature:i,serverPublicKey:j,merkleMetadata:k}=a,l=hashPlaintext(c,e,f,g,h),m=n=>{return n['toLowerCase']()['replace'](/^0x/,'');};if(m(l)!==m(d))return{'valid':![],'error':'Plaintext\x20hash\x20mismatch\x20for\x20message\x20'+b+':\x20expected\x20'+d+',\x20got\x20'+l,'failedCheck':'plaintext'};if(k){if(k['proofSiblings']&&k['proofIndices']){const p=calculateMerkleLeafHash(d,k['serverTimestamp']),q=verifyMerkleProof(p,{'root':k['newRoot'],'siblings':k['proofSiblings'],'indices':k['proofIndices']});if(!q)return{'valid':![],'error':'Merkle\x20proof\x20verification\x20failed\x20for\x20message\x20'+b,'failedCheck':'merkle'};}const n=k['serverTimestamp'];if(!n)return{'valid':![],'error':'Missing\x20server\x20timestamp\x20for\x20Merkle\x20root\x20verification\x20in\x20message\x20'+b,'failedCheck':'merkle'};if(!k['prevRoot'])return{'valid':![],'error':'Missing\x20prevRoot\x20for\x20Merkle\x20root\x20verification\x20in\x20message\x20'+b,'failedCheck':'merkle'};const o=verifySingleMerkleRoot(k['prevRoot'],k['newRoot'],d,n,k['leafIndex']);if(!o['valid'])return{'valid':![],'error':'Merkle\x20root\x20verification\x20failed\x20for\x20message\x20'+b+':\x20'+o['error'],'failedCheck':'merkle'};}if(i&&j){const r=k?.['serverTimestamp'];if(!r)return{'valid':![],'error':'Missing\x20server\x20timestamp\x20for\x20signature\x20verification\x20in\x20message\x20'+b,'failedCheck':'merkle'};if(!k?.['newRoot'])return{'valid':![],'error':'Missing\x20newRoot\x20for\x20signature\x20verification\x20in\x20message\x20'+b,'failedCheck':'merkle'};if(!k?.['prevRoot'])return{'valid':![],'error':'Missing\x20prevRoot\x20for\x20signature\x20verification\x20in\x20message\x20'+b,'failedCheck':'merkle'};const s=k['prevRoot']+':'+k['newRoot']+':'+r+':'+j,t=verifyFalcon512Signature(j,s,i);if(!t)return{'valid':![],'error':'Server\x20signature\x20verification\x20failed\x20for\x20message\x20'+b,'failedCheck':'merkle'};}return{'valid':!![]};}export function verifyFalcon512Signature(a,b,c){try{const d=hexToBytes(a['replace']('0x','')),e=hexToBytes(c['replace']('0x','')),f=new TextEncoder()['encode'](b);return verifyFalcon512(d,f,e);}catch{return![];}}export function verifyWtsMessages(a){if(a['length']===0x0)return{'valid':!![]};const b=[...a]['sort']((d,e)=>d['leafIndex']-e['leafIndex']);for(let d=0x0;d<b['length'];d++){const e=b[d];if(e['plaintext']!=null){const f=hashPlaintext(e['plaintext']||'',e['clientTimestamp'],e['guardAddress'],e['passportAddress'],e['lastReceivedLeafIndex']);if(f['toLowerCase']()!==e['plaintextHash']['toLowerCase']())return{'valid':![],'error':'Plaintext\x20hash\x20mismatch\x20for\x20message\x20'+e['id']+'\x20at\x20index\x20'+d,'failedMessageIndex':d,'failedCheck':'plaintext'};}if(e['merkleProof']){const g=calculateMerkleLeafHash(e['plaintextHash'],e['timestamp']),h=verifyMerkleProof(g,{'root':e['merkleRoot'],'siblings':e['merkleProof']['siblings'],'indices':e['merkleProof']['indices']});if(!h)return{'valid':![],'error':'Merkle\x20proof\x20verification\x20failed\x20for\x20message\x20'+e['id']+'\x20at\x20index\x20'+d,'failedMessageIndex':d,'failedCheck':'merkle'};}if(e['serverSignature']&&e['serverPublicKey']){if(!e['merkleRoot'])return{'valid':![],'error':'Missing\x20merkleRoot\x20for\x20message\x20'+e['id']+'\x20at\x20index\x20'+d,'failedMessageIndex':d,'failedCheck':'merkle'};if(!e['timestamp'])return{'valid':![],'error':'Missing\x20timestamp\x20for\x20message\x20'+e['id']+'\x20at\x20index\x20'+d,'failedMessageIndex':d,'failedCheck':'merkle'};if(!e['prevRoot'])return{'valid':![],'error':'Missing\x20prevRoot\x20for\x20message\x20'+e['id']+'\x20at\x20index\x20'+d,'failedMessageIndex':d,'failedCheck':'merkle'};const j=e['prevRoot']+':'+e['merkleRoot']+':'+e['timestamp']+':'+e['serverPublicKey'],k=verifyFalcon512Signature(e['serverPublicKey'],j,e['serverSignature']);if(!k)return{'valid':![],'error':'Server\x20signature\x20verification\x20failed\x20for\x20message\x20'+e['id']+'\x20at\x20index\x20'+d,'failedMessageIndex':d,'failedCheck':'merkle'};}}const c=verifyMerkleChain(b['map'](l=>({'leafIndex':l['leafIndex'],'prevRoot':l['merkleRoot'],'newRoot':l['merkleRoot'],'plaintextHash':l['plaintextHash'],'serverTimestamp':l['timestamp']})));if(!c['valid'])return{'valid':![],'error':c['error'],'failedCheck':'chain'};return{'valid':!![]};}