Exemple #1
0
def checkTemplate(rpc: RPC, mnemonic: str, req: Dict[str, Any],
                  inputs: List[Dict[str, Any]],
                  outputs: List[Dict[str, Any]]) -> None:
    template: Dict[str, Any] = rpc.call("personal", "getTransactionTemplate",
                                        req)
    if template["type"] != "Send":
        raise TestError("Template isn't of type Send.")
    if sortUTXOs(template["inputs"]) != sortUTXOs(inputs):
        raise TestError("Template inputs aren't as expected.")
    if template["outputs"] != outputs:
        raise TestError("Template outputs are incorrect.")

    keys: List[bytes] = []
    for inputJSON in template["inputs"]:
        key: bytes
        if inputJSON["change"]:
            key = getChangePublicKey(mnemonic, "", inputJSON["index"])
        else:
            key = getPublicKey(mnemonic, "", inputJSON["index"])
        if key not in keys:
            keys.append(key)

    if template["publicKey"] != Ristretto.aggregate(
        [Ristretto.RistrettoPoint(key)
         for key in keys]).serialize().hex().upper():
        if len(keys) == 1:
            raise TestError(
                "Template public key isn't correct when only a single key is present."
            )
        raise TestError("Public key aggregation isn't correct.")
Exemple #2
0
def deriveKeyAndChainCode(
  secret: bytes,
  path: List[int]
) -> Tuple[bytes, bytes]:
  k: bytes = hashlib.sha512(secret).digest()
  kL: bytes = Ristretto.RistrettoScalar(k[:32]).serialize()
  kR: bytes = k[32:]
  k = kL + kR

  #Parent public key/chain code.
  A: bytes = Ristretto.RistrettoScalar(kL).toPoint().serialize()
  c: bytes = hashlib.sha256(bytes([1]) + secret).digest()

  #Derive each child.
  for i in path:
    iBytes: bytes = i.to_bytes(4, "little")
    Z: bytes
    if i < HARDENED_THRESHOLD:
      Z = hmac512(c, bytes([2]) + A + iBytes)
      c = hmac512(c, bytes([3]) + A + iBytes)[32:]
    else:
      Z = hmac512(c, bytes([0]) + k + iBytes)
      c = hmac512(c, bytes([1]) + k + iBytes)[32:]

    zR: bytes = Z[32:]
    #This performs a mod l on kL which the BIP32-Ed25519 doesn't specify. That said, it's required to form a valid private key.
    scalar: Ristretto.Scalar = (
      Ristretto.RistrettoScalar(int.from_bytes(Z[:32], "little")) +
      Ristretto.RistrettoScalar(int.from_bytes(kL, "little"))
    )
    if scalar.underlying == mpz(0):
      raise Exception("Invalid child.")
    kL = scalar.serialize()
    kR = ((int.from_bytes(zR, "little") + int.from_bytes(kR, "little")) % (1 << 256)).to_bytes(32, "little")
    k = kL + kR

    A = Ristretto.RistrettoPoint(scalar.toPoint()).serialize()

  return (k, c)