PHP WebShell

Текущая директория: /opt/BitGoJS/modules/sdk-lib-mpc/src/shamir

Просмотр файла: shamir.ts

import crypto from 'crypto';
import { BaseCurve } from '../curves';
import { SplitSecret } from './types';
import { bigIntFromBufferLE, bigIntToBufferLE, clamp } from '../util';

export class Shamir {
  curve: BaseCurve;

  constructor(curve: BaseCurve) {
    this.curve = curve;
  }

  /**
   * Perform Shamir sharing on the secret `secret` to the degree `threshold - 1` split `numShares`
   * ways. The split secret requires `threshold` shares to be reconstructed.
   *
   * @param secret secret to split
   * @param threshold share threshold required to reconstruct secret
   * @param numShares total number of shares to split secret into
   * @param indices optional indices which can be used while generating the shares
   * @param salt optional salt which could be used while generating the shares
   * @returns Dictionary containing `shares`, a dictionary where each key is an int
   * in the range 1<=x<=numShares representing that share's free term, and `v`, an
   * array of proofs to be shared with all participants.
   */
  split(secret: bigint, threshold: number, numShares: number, indices?: Array<number>, salt = BigInt(0)): SplitSecret {
    let bigIndices: Array<bigint>;
    if (indices) {
      bigIndices = indices.map((i) => {
        if (i < 1) {
          throw new Error('Invalid value supplied for indices');
        }
        return BigInt(i);
      });
    } else {
      // make range(1, n + 1)
      bigIndices = Array(numShares)
        .fill(null)
        .map((_, i) => BigInt(i + 1));
    }
    if (threshold < 2) {
      throw new Error('Threshold cannot be less than two');
    }

    if (threshold > numShares) {
      throw new Error('Threshold cannot be greater than the total number of shares');
    }

    const coefs: bigint[] = [];
    const v: Array<bigint> = [];
    for (let ind = 0; ind < threshold - 1; ind++) {
      const coeff = clamp(
        bigIntFromBufferLE(crypto.createHmac('sha256', ind.toString(10)).update(bigIntToBufferLE(secret, 32)).digest())
      );
      coefs.push(coeff);
      v.unshift(this.curve.basePointMult(coeff));
    }
    coefs.push(secret);

    const shares: Record<number, bigint> = {};
    for (let ind = 0; ind < bigIndices.length; ind++) {
      const x = bigIndices[ind];
      let partial = coefs[0];
      for (let other = 1; other < coefs.length; other++) {
        partial = this.curve.scalarAdd(coefs[other], this.curve.scalarMult(partial, x));
      }
      shares[parseInt(x.toString(), 10)] = partial;
    }
    return { shares, v };
  }

  /**
   * Verify a VSS share.
   *
   * @param u Secret share received from other party.
   * @param v Verification values received from other party.
   * @param index Verifier's index.
   * @returns True on success; otherwise throws Error.
   */
  verify(u: bigint, v: Array<bigint>, index: number): boolean {
    if (v.length < 2) {
      throw new Error('Threshold cannot be less than two');
    }
    if (index < 1) {
      throw new Error('Invalid value supplied for index');
    }
    const i = BigInt(index);
    let x = v[0];
    let t = BigInt(1);
    for (const vsj of v.slice(1)) {
      t = this.curve.scalarMult(t, i);
      const vjt = this.curve.pointMultiply(vsj, t);
      x = this.curve.pointAdd(x, vjt);
    }
    const sigmaG = this.curve.basePointMult(u);
    if (x !== sigmaG) {
      throw new Error('Could not verify share');
    }
    return true;
  }

  /**
   * Reconstitute a secret from a dictionary of shares. The number of shares must
   * be equal to `t` to reconstitute the original secret.
   *
   * @param shares dictionary of shares. each key is the free term of the share
   * @returns secret
   */
  combine(shares: Record<number, bigint>): bigint {
    try {
      let s = BigInt(0);
      for (const i in shares) {
        const yi = shares[i];
        const xi = BigInt(i);
        let num = BigInt(1);
        let denum = BigInt(1);

        for (const j in shares) {
          const xj = BigInt(j);
          if (xi !== xj) {
            num = this.curve.scalarMult(num, xj);
          }
        }
        for (const j in shares) {
          const xj = BigInt(j);
          if (xi !== xj) {
            denum = this.curve.scalarMult(denum, this.curve.scalarSub(xj, xi));
          }
        }
        const inverted = this.curve.scalarInvert(denum);
        const innerMultiplied = this.curve.scalarMult(num, inverted);
        const multiplied = this.curve.scalarMult(innerMultiplied, yi);
        s = this.curve.scalarAdd(multiplied, s);
      }
      return s;
    } catch (error) {
      throw new Error('Failed to combine Shamir shares , ' + error);
    }
  }
}

Выполнить команду


Для локальной разработки. Не используйте в интернете!