UNPKG

wowok

Version:

Wowok Blockchain TypeScript API

1 lines 7.25 kB
import{generateMLKEMKeyPair,mlkemEncapsulate,mlkemDecapsulate,hkdfDerive,concatBytes}from'./crypto.js';import{encodeShards,decodeShards,unpackChunk,DATA_SHARDS}from'./erasure.js';import{CHAIN_KEY_SIZE,MESSAGE_KEY_SIZE,MLKEM_PUBLIC_KEY_SIZE,MLKEM_CIPHERTEXT_SIZE}from'./types.js';const SPQR_CYCLE_INTERVAL=0x32;export function initSPQR(){return{'cycleId':0x0,'sendingPQKeys':null,'sendingChunks':[],'sendingChunkIndex':0x0,'sendingPhase':'idle','receivedChunks':new Map(),'receivingPhase':'idle','expectedTotalChunks':0x0,'receivedSharedSecret':null,'currentSPQRKey':new Uint8Array(MESSAGE_KEY_SIZE),'spqrChainKey':new Uint8Array(CHAIN_KEY_SIZE),'spqrMessageCount':0x0};}export function spqrGetNextChunk(a,b){const c=cloneSPQRState(a);if(c['sendingPhase']==='idle'&&b>0x0&&b%SPQR_CYCLE_INTERVAL===0x0){c['cycleId']+=0x1,c['sendingPQKeys']=generateMLKEMKeyPair(),c['sendingPhase']='sending_pk';const f=encodeShards(c['sendingPQKeys']['publicKey']);c['sendingChunks']=f,c['sendingChunkIndex']=0x0;}if(c['sendingPhase']==='idle')return{'chunk':null,'newState':c};if(c['sendingChunkIndex']>=c['sendingChunks']['length']){if(c['sendingPhase']==='sending_pk')c['sendingPhase']='waiting_for_ct',c['sendingChunkIndex']=0x0,c['sendingChunks']=[];else{if(c['sendingPhase']==='sending_ct_pk')return c['sendingPhase']='idle',c['sendingPQKeys']=null,c['sendingChunks']=[],c['sendingChunkIndex']=0x0,{'chunk':null,'newState':c};}}if(c['sendingPhase']==='waiting_for_ct')return{'chunk':null,'newState':c};const d=c['sendingChunks'][c['sendingChunkIndex']],e={'cycleId':c['cycleId'],'chunkIndex':c['sendingChunkIndex'],'totalChunks':c['sendingChunks']['length'],'data':d};return c['sendingChunkIndex']+=0x1,{'chunk':e,'newState':c};}export function spqrProcessReceivedChunks(a,b){const c=cloneSPQRState(a);for(const d of b){c['receivingPhase']==='idle'&&(c['receivingPhase']='receiving_ct',c['expectedTotalChunks']=d['totalChunks'],c['receivedChunks']=new Map());if(d['cycleId']!==c['cycleId'])continue;c['receivedChunks']['set'](d['chunkIndex'],d['data']);}if(c['receivingPhase']==='receiving_ct'&&c['receivedChunks']['size']>=DATA_SHARDS){const e=decodeShards(c['receivedChunks'],c['expectedTotalChunks']),f=e['slice'](0x0,MLKEM_CIPHERTEXT_SIZE);if(c['sendingPQKeys']){const g=mlkemDecapsulate(f,c['sendingPQKeys']['secretKey']);return c['receivedSharedSecret']=g,c['currentSPQRKey']=hkdfDerive(concatBytes(c['currentSPQRKey'],g),new TextEncoder()['encode']('WowokSPQRUpdate'),MESSAGE_KEY_SIZE),c['receivingPhase']='done',c['receivedChunks']=new Map(),{'newState':c,'completed':!![]};}}return{'newState':c,'completed':![]};}export function spqrOnPeerPQPKReceived(a,b){const c=cloneSPQRState(a),{ciphertext:d,sharedSecret:e}=mlkemEncapsulate(b);c['currentSPQRKey']=hkdfDerive(concatBytes(c['currentSPQRKey'],e),new TextEncoder()['encode']('WowokSPQRUpdate'),MESSAGE_KEY_SIZE);const f=encodeShards(d);return c['sendingChunks']=f,c['sendingChunkIndex']=0x0,c['sendingPhase']='sending_ct_pk',{'newState':c,'ctChunks':f};}export function spqrReceiveChunk(a,b){const c=cloneSPQRState(a),d=unpackChunk(b);c['receivingPhase']==='idle'&&(c['receivingPhase']='receiving_pk',c['expectedTotalChunks']=d['totalChunks'],c['receivedChunks']=new Map(),c['cycleId']=d['cycleId']);if(d['cycleId']!==c['cycleId'])return{'newState':c,'peerPQPKReady':![],'peerPQPK':null,'shouldSendCT':![]};c['receivedChunks']['set'](d['chunkIndex'],d['data']);if(c['receivingPhase']==='receiving_pk'&&c['receivedChunks']['size']>=DATA_SHARDS){const e=decodeShards(c['receivedChunks'],c['expectedTotalChunks']),f=e['slice'](0x0,MLKEM_PUBLIC_KEY_SIZE);return c['receivingPhase']='receiving_ct',c['receivedChunks']=new Map(),{'newState':c,'peerPQPKReady':!![],'peerPQPK':f,'shouldSendCT':!![]};}if(c['receivingPhase']==='receiving_ct'&&c['receivedChunks']['size']>=DATA_SHARDS){const g=decodeShards(c['receivedChunks'],c['expectedTotalChunks']),h=g['slice'](0x0,MLKEM_CIPHERTEXT_SIZE);if(c['sendingPQKeys']){const i=mlkemDecapsulate(h,c['sendingPQKeys']['secretKey']);c['currentSPQRKey']=hkdfDerive(concatBytes(c['currentSPQRKey'],i),new TextEncoder()['encode']('WowokSPQRUpdate'),MESSAGE_KEY_SIZE),c['receivingPhase']='done',c['receivedChunks']=new Map(),c['sendingPQKeys']=null,c['sendingPhase']='idle',c['sendingChunks']=[],c['sendingChunkIndex']=0x0;}return{'newState':c,'peerPQPKReady':![],'peerPQPK':null,'shouldSendCT':![]};}return{'newState':c,'peerPQPKReady':![],'peerPQPK':null,'shouldSendCT':![]};}export function spqrGetCurrentKey(a){return a['currentSPQRKey'];}function cloneSPQRState(a){return{'cycleId':a['cycleId'],'sendingPQKeys':a['sendingPQKeys']?{'publicKey':new Uint8Array(a['sendingPQKeys']['publicKey']),'secretKey':new Uint8Array(a['sendingPQKeys']['secretKey'])}:null,'sendingChunks':a['sendingChunks']['map'](b=>new Uint8Array(b)),'sendingChunkIndex':a['sendingChunkIndex'],'sendingPhase':a['sendingPhase'],'receivedChunks':new Map(a['receivedChunks']),'receivingPhase':a['receivingPhase'],'expectedTotalChunks':a['expectedTotalChunks'],'receivedSharedSecret':a['receivedSharedSecret']?new Uint8Array(a['receivedSharedSecret']):null,'currentSPQRKey':new Uint8Array(a['currentSPQRKey']),'spqrChainKey':new Uint8Array(a['spqrChainKey']),'spqrMessageCount':a['spqrMessageCount']};}export function serializeSPQRState(a){const b={};for(const [c,d]of a['receivedChunks']){b[c['toString']()]=Buffer['from'](d)['toString']('base64');}return{'cycleId':a['cycleId'],'sendingPQPublicKey':a['sendingPQKeys']?Buffer['from'](a['sendingPQKeys']['publicKey'])['toString']('base64'):null,'sendingPQSecretKey':a['sendingPQKeys']?Buffer['from'](a['sendingPQKeys']['secretKey'])['toString']('base64'):null,'sendingChunks':a['sendingChunks']['map'](e=>Buffer['from'](e)['toString']('base64')),'sendingChunkIndex':a['sendingChunkIndex'],'sendingPhase':a['sendingPhase'],'receivedChunks':b,'receivingPhase':a['receivingPhase'],'expectedTotalChunks':a['expectedTotalChunks'],'receivedSharedSecret':a['receivedSharedSecret']?Buffer['from'](a['receivedSharedSecret'])['toString']('base64'):null,'currentSPQRKey':Buffer['from'](a['currentSPQRKey'])['toString']('base64'),'spqrChainKey':Buffer['from'](a['spqrChainKey'])['toString']('base64'),'spqrMessageCount':a['spqrMessageCount']};}export function deserializeSPQRState(a){const b=new Map();for(const [c,d]of Object['entries'](a['receivedChunks'])){b['set'](parseInt(c),new Uint8Array(Buffer['from'](d,'base64')));}return{'cycleId':a['cycleId'],'sendingPQKeys':a['sendingPQPublicKey']&&a['sendingPQSecretKey']?{'publicKey':new Uint8Array(Buffer['from'](a['sendingPQPublicKey'],'base64')),'secretKey':new Uint8Array(Buffer['from'](a['sendingPQSecretKey'],'base64'))}:null,'sendingChunks':a['sendingChunks']['map'](e=>new Uint8Array(Buffer['from'](e,'base64'))),'sendingChunkIndex':a['sendingChunkIndex'],'sendingPhase':a['sendingPhase'],'receivedChunks':b,'receivingPhase':a['receivingPhase'],'expectedTotalChunks':a['expectedTotalChunks'],'receivedSharedSecret':a['receivedSharedSecret']?new Uint8Array(Buffer['from'](a['receivedSharedSecret'],'base64')):null,'currentSPQRKey':new Uint8Array(Buffer['from'](a['currentSPQRKey'],'base64')),'spqrChainKey':new Uint8Array(Buffer['from'](a['spqrChainKey'],'base64')),'spqrMessageCount':a['spqrMessageCount']};}