Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Explore sha256 conversion optimisation #245

Closed
wemeetagain opened this issue Mar 23, 2022 · 1 comment
Closed

Explore sha256 conversion optimisation #245

wemeetagain opened this issue Mar 23, 2022 · 1 comment

Comments

@wemeetagain
Copy link
Member

wemeetagain commented Mar 23, 2022

Is your feature request related to a problem? Please describe.

There's a 30% overhead cost converting things back a forth to wasm friendly formats

For context this is only really noticeable when loading states from disk where the full BeaconState has to be hashed. There the saving are in the order of 1s -> 0.7s. However when signing gossip messages the savings are not too significant. Maybe they will be to hash full large ExecutionPayloads.

Summary: cool optimization, not high priority

Describe the solution you'd like

enum HashInputType {
  HashObject,
  Uint8Array,
  Uint64,
}

type HashInput =
  | {type: HashInputType.HashObject; hashObject: HashObject}
  | {type: HashInputType.Uint8Array; uint8Array: Uint8Array}
  | {type: HashInputType.Uint64; uint64: number};

enum HashOutputType {
  HashObject,
  Uint8Array,
}

function setHashInput(input: HashInput, offset32: number): void {
  switch (input.type) {
    case HashInputType.HashObject: {
      const offset4 = offset32 * 8;
      const {hashObject} = input;
      inputUint32Array[offset4 + 0] = hashObject.h0;
      inputUint32Array[offset4 + 1] = hashObject.h1;
      inputUint32Array[offset4 + 2] = hashObject.h2;
      inputUint32Array[offset4 + 3] = hashObject.h3;
      inputUint32Array[offset4 + 4] = hashObject.h4;
      inputUint32Array[offset4 + 5] = hashObject.h5;
      inputUint32Array[offset4 + 6] = hashObject.h6;
      inputUint32Array[offset4 + 7] = hashObject.h7;
      break;
    }

    case HashInputType.Uint8Array: {
      inputUint8Array.set(input.uint8Array, offset32 * 32);
      break;
    }

    case HashInputType.Uint64: {
      const offset4 = offset32 * 8;
      const offset1 = offset32 * 32;
      inputDataView.setUint32(offset1, input.uint64 & 0xffffffff, true);
      inputDataView.setUint32(offset1 + 4, (input.uint64 / NUMBER_2_POW_32) & 0xffffffff, true);
      inputUint32Array[offset4 + 2] = 0;
      inputUint32Array[offset4 + 3] = 0;
      inputUint32Array[offset4 + 4] = 0;
      inputUint32Array[offset4 + 5] = 0;
      inputUint32Array[offset4 + 6] = 0;
      inputUint32Array[offset4 + 7] = 0;
    }
  }
}

export function digest64TypedData(
  input1: HashInput,
  input2: HashInput,
  outputType: HashOutputType.HashObject
): HashObject;

export function digest64TypedData(
  input1: HashInput,
  input2: HashInput,
  outputType: HashOutputType.Uint8Array
): Uint8Array;

/**
 * Digest 2 objects, each has 8 properties from h0 to h7.
 * The performance is a little bit better than digest64 due to the use of Uint32Array
 * and the memory is a little bit better than digest64 due to no temporary Uint8Array.
 * @returns
 */
export function digest64TypedData(
  input1: HashInput,
  input2: HashInput,
  outputType: HashOutputType
): HashObject | Uint8Array {
  setHashInput(input1, 0);
  setHashInput(input2, 1);

  ctx.digest64(wasmInputValue, wasmOutputValue);

  switch (outputType) {
    case HashOutputType.HashObject:
      // extracting numbers from Uint32Array causes more memory
      return byteArrayToHashObject(outputUint8Array);

    case HashOutputType.Uint8Array:
      // TODO: Benchmark fastest way to copy bytes
      return outputUint8Array.slice(0, 32);
  }
}

Additional context

From #244

@wemeetagain
Copy link
Member Author

may be something important to explore to support ChainSafe/lodestar#4005

@philknows philknows closed this as not planned Won't fix, can't repro, duplicate, stale Oct 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants