// Use strict "use strict"; // Classes // New proof builder class class NewProofBuilder extends ProofBuilder { // Public // Initialize initialize(extendedPrivateKey) { // Set self var self = this; // Return promise return new Promise(function(resolve, reject) { // Return deriving secret key from extended private key and root identifier return Crypto.deriveSecretKey(extendedPrivateKey, new BigNumber(0), new Identifier(Identifier.ROOT_SERIALIZED_IDENTIFIER), Crypto.SWITCH_TYPE_NONE).then(function(secretKey) { // Check if getting private hash from secret key was successful self.privateHash = Blake2b.compute(Crypto.NONCE_LENGTH, secretKey, new Uint8Array([])); if(self.privateHash !== Blake2b.OPERATION_FAILED) { // Securely clear secret key secretKey.fill(0); // Return getting root public key from extended private key return Crypto.rootPublicKey(extendedPrivateKey).then(function(publicKey) { // Check if getting rewind hash from public key was successful self.rewindHash = Blake2b.compute(Crypto.NONCE_LENGTH, publicKey, new Uint8Array([])); if(self.rewindHash !== Blake2b.OPERATION_FAILED) { // Securely clear public key publicKey.fill(0); // Resolve resolve(); } // Otherwise else { // Securely clear private hash self.privateHash.fill(0); // Securely clear public key publicKey.fill(0); // Reject error reject("Getting Rewind hash failed."); } // Catch errors }).catch(function(error) { // Securely clear private hash self.privateHash.fill(0); // Reject error reject(error); }); } // Otherwise else { // Securely clear secret key secretKey.fill(0); // Reject error reject("Getting private hash failed."); } // Catch errors }).catch(function(error) { // Reject error reject(error); }); }); } // Uninitialize uninitialize() { // Securely clear private hash this.privateHash.fill(0); // Securely clear rewind hash this.rewindHash.fill(0); } // Rewind nonce rewindNonce(commit) { // Set self var self = this; // Return promise return new Promise(function(resolve, reject) { // Check if getting nonce from rewind hash and commit was successful var nonce = Blake2b.compute(Crypto.NONCE_LENGTH, self.rewindHash, commit); if(nonce !== Blake2b.OPERATION_FAILED) { // Check if nonce is a valid secret key if(Secp256k1Zkp.isValidSecretKey(nonce) === true) { // Resolve nonce resolve(nonce); } // Otherwise else { // Securely clear nonce nonce.fill(0); // Reject error reject("Nonce is not a valid secret key."); } } // Otherwise else { // Reject error reject("Getting nonce failed."); } }); } // Private nonce privateNonce(commit) { // Set self var self = this; // Return promise return new Promise(function(resolve, reject) { // Check if getting nonce from private hash and commit was successful var nonce = Blake2b.compute(Crypto.NONCE_LENGTH, self.privateHash, commit); if(nonce !== Blake2b.OPERATION_FAILED) { // Check if nonce is a valid secret key if(Secp256k1Zkp.isValidSecretKey(nonce) === true) { // Resolve nonce resolve(nonce); } // Otherwise else { // Securely clear nonce nonce.fill(0); // Reject error reject("Nonce is not a valid secret key."); } } // Otherwise else { // Reject error reject("Getting nonce failed."); } }); } // Proof message proofMessage(identifier, switchType) { // Create message var message = new Uint8Array(NewProofBuilder.MESSAGE_LENGTH).fill(0); // Set message's switch type message[NewProofBuilder.MESSAGE_SWITCH_TYPE_INDEX] = switchType; // Set everything after message's switch type to the identifier's value message = Common.mergeArrays([ // Message switch type message.subarray(0, NewProofBuilder.MESSAGE_SWITCH_TYPE_INDEX + 1), // Identifier's value identifier.getValue().subarray(0, NewProofBuilder.MESSAGE_LENGTH - (NewProofBuilder.MESSAGE_SWITCH_TYPE_INDEX + 1)) ]); // Return message return message; } // Get output getOutput(extendedPrivateKey, amount, commit, message) { // Return promise return new Promise(function(resolve, reject) { // Check if message is valid if(message["length"] === NewProofBuilder.MESSAGE_LENGTH && Common.arraysAreEqual(message.subarray(0, NewProofBuilder.MESSAGE_HEADER_START["length"]), NewProofBuilder.MESSAGE_HEADER_START) === true) { // Get switch type from message var switchType = message[NewProofBuilder.MESSAGE_SWITCH_TYPE_INDEX]; // Check if switch type is valid if(switchType === Crypto.SWITCH_TYPE_NONE || switchType === Crypto.SWITCH_TYPE_REGULAR) { // Get depth from message var depth = message[NewProofBuilder.MESSAGE_DEPTH_INDEX]; // Try try { // Create identifier from depth and message var identifier = new Identifier(depth.toString(Common.HEX_NUMBER_BASE).padStart(Common.HEX_NUMBER_LENGTH, Common.HEX_NUMBER_PADDING) + Common.toHexString(message.subarray(NewProofBuilder.MESSAGE_HEADER_LENGTH))); } // Catch errors catch(error) { // Reject error reject("Identifier isn't valid."); // Return return; } // Return getting commit from extended private key, amount, identifier, and switch type return Crypto.commit(extendedPrivateKey, amount, identifier, switchType).then(function(computedCommit) { // Check if commit matches the computed commit if(Common.arraysAreEqual(commit, computedCommit) === true) { // Resolve output resolve([ // Identifier identifier, // Switch type switchType ]); } // Otherwise else { // Reject error reject("Output isn't valid."); } // Catch errors }).catch(function(error) { // Reject error reject(error); }); } // Otherwise else { // Reject error reject("Switch type isn't valid."); } } // Otherwise else { // Reject error reject("Message isn't valid."); } }); } // Private // Message header start static get MESSAGE_HEADER_START() { // Return message header start return new Uint8Array([0, 0]); } // Message switch type index static get MESSAGE_SWITCH_TYPE_INDEX() { // Return message switch type index return NewProofBuilder.MESSAGE_HEADER_START["length"]; } // Message depth index static get MESSAGE_DEPTH_INDEX() { // Return message depth index return NewProofBuilder.MESSAGE_SWITCH_TYPE_INDEX + 1; } // Message header length static get MESSAGE_HEADER_LENGTH() { // Return message header length return NewProofBuilder.MESSAGE_DEPTH_INDEX + 1; } // Message length static get MESSAGE_LENGTH() { // Return message length return NewProofBuilder.MESSAGE_HEADER_LENGTH + Identifier.MAX_DEPTH * Uint32Array["BYTES_PER_ELEMENT"]; } } // Main function // Set global object's new proof builder globalThis["NewProofBuilder"] = NewProofBuilder;