async def get_pre_mlsag_hash(rv): """ Generates final message for the Ring CT signature :param rv: :type rv: RctSig :return: """ from monero_glue.xmr.sub.keccak_hasher import get_keccak_writer from monero_serialize.xmrtypes import RctType kc_master = HashWrapper(crypto.get_keccak()) kc_master.update(rv.message) is_simple = rv.type in [ RctType.Simple, RctType.Bulletproof, RctType.Bulletproof2 ] outputs = len(rv.ecdhInfo) inputs = 0 if rv.type == RctType.Simple: inputs = len(rv.pseudoOuts) elif rv.type in [RctType.Bulletproof, RctType.Bulletproof2]: inputs = len(rv.p.pseudoOuts) kwriter = get_keccak_writer() ar = xmrserialize.Archive(kwriter, True) await rv.serialize_rctsig_base(ar, inputs, outputs) c_hash = kwriter.get_digest() kc_master.update(c_hash) kc = crypto.get_keccak() if rv.type in [RctType.Bulletproof, RctType.Bulletproof2]: for p in rv.p.bulletproofs: kc.update(p.A) kc.update(p.S) kc.update(p.T1) kc.update(p.T2) kc.update(p.taux) kc.update(p.mu) for i in range(len(p.L)): kc.update(p.L[i]) for i in range(len(p.R)): kc.update(p.R[i]) kc.update(p.a) kc.update(p.b) kc.update(p.t) else: for r in rv.p.rangeSigs: for i in range(64): kc.update(r.asig.s0[i]) for i in range(64): kc.update(r.asig.s1[i]) kc.update(r.asig.ee) for i in range(64): kc.update(r.Ci[i]) c_hash = kc.digest() kc_master.update(c_hash) return kc_master.digest()
def __init__(self, state=None): from monero_glue.xmr.sub.keccak_hasher import HashWrapper, KeccakArchive self.is_simple = state[0] if state else None self.state = state[1] if state else 0 self.kc_master = HashWrapper(state[2] if state else crypto.get_keccak()) self.rsig_hasher = state[3] if state else crypto.get_keccak() self.rtcsig_hasher = None if state: self.rtcsig_hasher = KeccakArchive(state[4]) if state[4] else None else: self.rtcsig_hasher = KeccakArchive()
async def mlsag_prehash_finalize(self): H = None proof = None message = None if self.options & IN_OPTION_MORE_COMMAND: H = self._fetch() self.ctx_h.update(H) self.ctx_commitment.update(H) else: H = self.ctx_commitment.digest() if not common.ct_equal(H, self.C): raise ValueError(SW_SECURITY_COMMITMENT_CHAIN_CONTROL) H = self.ctx_h.digest() message = self._fetch() proof = self._fetch() self.ctx_h = crypto.get_keccak() self.ctx_h.update(message) self.ctx_h.update(H) self.ctx_h.update(proof) self.H = self.ctx_h.digest() self._insert(self.H) return SW_OK
def ver_borromean(P1, P2, s0, s1, ee): """ Verify range proof signature, Borromean (c.f. gmax/andytoshi's paper) :param P1: :param P2: :param s0: :param s1: :param ee: :return: """ n = len(P1) Lv1 = key_vector(n) for ii in range(n): LL = crypto.add_keys2(s0[ii], ee, P1[ii]) chash = crypto.hash_to_scalar(crypto.encodepoint(LL)) Lv1[ii] = crypto.add_keys2(s1[ii], chash, P2[ii]) kck = crypto.get_keccak() for ii in range(n): kck.update(crypto.encodepoint(Lv1[ii])) # ee_computed = crypto.hash_to_scalar(crypto.encodepoint(Lv1)) ee_computed = crypto.decodeint(kck.digest()) return crypto.sc_eq(ee_computed, ee)
async def generate_commitment(outputs): """ Generates num, hash commitment for initial message for ki syc :param outputs: :type outputs: list[xmrtypes.TransferDetails] :return: """ hashes = [] sub_indices = collections.defaultdict(lambda: set()) for out in outputs: sub_indices[out.m_subaddr_index.major].add(out.m_subaddr_index.minor) num = 0 kck = crypto.get_keccak() iter = await yield_key_image_data(outputs) for rr in iter: # type: MoneroTransferDetails hash = compute_hash(rr) kck.update(hash) num += 1 final_hash = kck.digest() indices = [] for major in sub_indices: indices.append( MoneroSubAddressIndicesList(account=major, minor_indices=list( sub_indices[major]))) return MoneroKeyImageExportInitRequest(num=num, hash=final_hash, subs=indices)
async def abort_tx(self): self.r = None self.R = None self.ctx_h = crypto.get_keccak() self.ctx_amount = sha256() self.ctx_commitment = sha256() return SW_OK
def get_keccak_writer(ctx=None): """ Creates new fresh async Keccak writer :param ctx: :return: """ return AHashWriter( HashWrapper(crypto.get_keccak() if ctx is None else ctx))
def hasher_message(message): """ Returns incremental hasher for MLSAG :param message: :return: """ ctx = common.HashWrapper(crypto.get_keccak()) ctx.update(message) return ctx
def __init__(self, ctx=None, iface=None, creds=None): self.ctx = ctx self.iface = iface # type: trezor_iface.TrezorInterface self.creds = creds # type: monero.AccountCreds self.num = 0 self.c_idx = -1 self.hash = None self.blocked = None self.enc_key = None self.subaddresses = {} self.hasher = common.HashWrapper(crypto.get_keccak())
async def mlsag_hash(self): if self.c_p2 == 1: self.ctx_h = crypto.get_keccak() msg = self.H else: msg = self._fetch() self.ctx_h.update(msg) if self.options & 0x80 == 0: c = self.ctx_h.digest() self.c = crypto.decodeint(c) self._insert(crypto.encodeint(self.c)) return SW_OK
async def mlsag_prehash_init(self): if self.c_p2 == 1: self.KV = self.ctx_amount.digest() self.ctx_amount = sha256() self.ctx_commitment = sha256() self.ctx_h = crypto.get_keccak() self.ctx_h.update(self.c_msg[self.c_offset:]) if self.sig_mode == TRANSACTION_CREATE_REAL and self.c_p2 == 1: self._fetch_u8() fee = load_uvarint_b(self._fetch_view()) # TODO: await layout.require_confirm_fee(self.ctx, fee) return SW_OK
def compute_hash(rr): """ Hash over output to ki-sync :param rr: :type rr: TransferDetails :return: """ kck = crypto.get_keccak() kck.update(rr.out_key) kck.update(rr.tx_pub_key) if rr.additional_tx_pub_keys: for x in rr.additional_tx_pub_keys: kck.update(x) kck.update(xmrserialize.dump_uvarint_b(rr.internal_output_index)) return kck.digest()
def gen_borromean(x, P1, P2, indices): """ Generates Borromean signature for range proofs. :return: """ n = len(P1) alpha = key_zero_vector(n) s1 = key_zero_vector(n) kck = crypto.get_keccak() # ee computation for ii in range(n): alpha[ii] = crypto.random_scalar() L = crypto.scalarmult_base(alpha[ii]) if indices[ii] == 0: s1[ii] = crypto.random_scalar() c = crypto.hash_to_scalar(crypto.encodepoint(L)) L = crypto.add_keys2(s1[ii], c, P2[ii]) kck.update(crypto.encodepoint(L)) else: kck.update(crypto.encodepoint(L)) ee = crypto.decodeint(kck.digest()) del kck s0 = key_zero_vector(n) for jj in range(n): if not indices[jj]: s0[jj] = crypto.sc_mulsub(x[jj], ee, alpha[jj]) else: s0[jj] = crypto.random_scalar() LL = crypto.add_keys2(s0[jj], ee, P1[jj]) cc = crypto.hash_to_scalar(crypto.encodepoint(LL)) s1[jj] = crypto.sc_mulsub(x[jj], cc, alpha[jj]) return s0, s1, ee
def verify_clsag(msg, ss, sc1, sI, sD, pubs, C_offset): n = len(pubs) c = crypto.new_scalar() D_8 = crypto.new_point() tmp_bf = bytearray(32) C_offset_bf = crypto.encodepoint(C_offset) crypto.sc_copy(c, sc1) crypto.point_mul8_into(D_8, sD) hsh_P = crypto.get_keccak() # domain, I, D, P, C, C_offset hsh_C = crypto.get_keccak() # domain, I, D, P, C, C_offset hsh_P.update(_HASH_KEY_CLSAG_AGG_0) hsh_C.update(_HASH_KEY_CLSAG_AGG_1) def hsh_PC(x): hsh_P.update(x) hsh_C.update(x) for x in pubs: hsh_PC(x.dest) for x in pubs: hsh_PC(x.commitment) hsh_PC(crypto.encodepoint_into(tmp_bf, sI)) hsh_PC(crypto.encodepoint_into(tmp_bf, sD)) hsh_PC(C_offset_bf) mu_P = crypto.decodeint(hsh_P.digest()) mu_C = crypto.decodeint(hsh_C.digest()) c_to_hash = crypto.get_keccak() # domain, P, C, C_offset, message, L, R c_to_hash.update(_HASH_KEY_CLSAG_ROUND) for i in range(len(pubs)): c_to_hash.update(pubs[i].dest) for i in range(len(pubs)): c_to_hash.update(pubs[i].commitment) c_to_hash.update(C_offset_bf) c_to_hash.update(msg) c_p = crypto.new_scalar() c_c = crypto.new_scalar() L = crypto.new_point() R = crypto.new_point() tmp_pt = crypto.new_point() i = 0 while i < n: crypto.sc_mul_into(c_p, mu_P, c) crypto.sc_mul_into(c_c, mu_C, c) C_P = crypto.point_sub( crypto.decodepoint_into(tmp_pt, pubs[i].commitment), C_offset) crypto.add_keys2_into(L, ss[i], c_p, crypto.decodepoint_into(tmp_pt, pubs[i].dest)) crypto.point_add_into(L, L, crypto.scalarmult_into(tmp_pt, C_P, c_c)) HP = crypto.hash_to_point(pubs[i].dest) crypto.add_keys3_into(R, ss[i], HP, c_p, sI) crypto.point_add_into(R, R, crypto.scalarmult_into(tmp_pt, D_8, c_c)) chasher = c_to_hash.copy() chasher.update(crypto.encodepoint_into(tmp_bf, L)) chasher.update(crypto.encodepoint_into(tmp_bf, R)) crypto.decodeint_into(c, chasher.digest()) i += 1 res = crypto.sc_sub(c, sc1) if not crypto.sc_eq(res, crypto.sc_0()): raise ValueError("Signature error")
def _generate_clsag( message: bytes, P: List[bytes], p: Sc25519, C_nonzero: List[bytes], z: Sc25519, Cout: Ge25519, index: int, mg_buff: List[bytes], ) -> List[bytes]: sI = crypto.new_point() # sig.I sD = crypto.new_point() # sig.D sc1 = crypto.new_scalar() # sig.c1 a = crypto.random_scalar() H = crypto.new_point() D = crypto.new_point() Cout_bf = crypto.encodepoint(Cout) tmp_sc = crypto.new_scalar() tmp = crypto.new_point() tmp_bf = bytearray(32) crypto.hash_to_point_into(H, P[index]) crypto.scalarmult_into(sI, H, p) # I = p*H crypto.scalarmult_into(D, H, z) # D = z*H crypto.sc_mul_into(tmp_sc, z, crypto.sc_inv_eight()) # 1/8*z crypto.scalarmult_into(sD, H, tmp_sc) # sig.D = 1/8*z*H sD = crypto.encodepoint(sD) hsh_P = crypto.get_keccak() # domain, I, D, P, C, C_offset hsh_C = crypto.get_keccak() # domain, I, D, P, C, C_offset hsh_P.update(_HASH_KEY_CLSAG_AGG_0) hsh_C.update(_HASH_KEY_CLSAG_AGG_1) def hsh_PC(x): nonlocal hsh_P, hsh_C hsh_P.update(x) hsh_C.update(x) for x in P: hsh_PC(x) for x in C_nonzero: hsh_PC(x) hsh_PC(crypto.encodepoint_into(tmp_bf, sI)) hsh_PC(sD) hsh_PC(Cout_bf) mu_P = crypto.decodeint(hsh_P.digest()) mu_C = crypto.decodeint(hsh_C.digest()) del (hsh_PC, hsh_P, hsh_C) c_to_hash = crypto.get_keccak() # domain, P, C, C_offset, message, aG, aH c_to_hash.update(_HASH_KEY_CLSAG_ROUND) for i in range(len(P)): c_to_hash.update(P[i]) for i in range(len(P)): c_to_hash.update(C_nonzero[i]) c_to_hash.update(Cout_bf) c_to_hash.update(message) chasher = c_to_hash.copy() crypto.scalarmult_base_into(tmp, a) chasher.update(crypto.encodepoint_into(tmp_bf, tmp)) # aG crypto.scalarmult_into(tmp, H, a) chasher.update(crypto.encodepoint_into(tmp_bf, tmp)) # aH c = crypto.decodeint(chasher.digest()) del (chasher, H) L = crypto.new_point() R = crypto.new_point() c_p = crypto.new_scalar() c_c = crypto.new_scalar() i = (index + 1) % len(P) if i == 0: crypto.sc_copy(sc1, c) mg_buff.append(xmrserialize.dump_uvarint_b(len(P))) for _ in range(len(P)): mg_buff.append(bytearray(32)) while i != index: crypto.random_scalar_into(tmp_sc) crypto.encodeint_into(mg_buff[i + 1], tmp_sc) crypto.sc_mul_into(c_p, mu_P, c) crypto.sc_mul_into(c_c, mu_C, c) # L = tmp_sc * G + c_P * P[i] + c_c * C[i] crypto.add_keys2_into(L, tmp_sc, c_p, crypto.decodepoint_into(tmp, P[i])) crypto.decodepoint_into(tmp, C_nonzero[i]) # C = C_nonzero - Cout crypto.point_sub_into(tmp, tmp, Cout) crypto.scalarmult_into(tmp, tmp, c_c) crypto.point_add_into(L, L, tmp) # R = tmp_sc * HP + c_p * I + c_c * D crypto.hash_to_point_into(tmp, P[i]) crypto.add_keys3_into(R, tmp_sc, tmp, c_p, sI) crypto.point_add_into(R, R, crypto.scalarmult_into(tmp, D, c_c)) chasher = c_to_hash.copy() chasher.update(crypto.encodepoint_into(tmp_bf, L)) chasher.update(crypto.encodepoint_into(tmp_bf, R)) crypto.decodeint_into(c, chasher.digest()) P[i] = None C_nonzero[i] = None i = (i + 1) % len(P) if i == 0: crypto.sc_copy(sc1, c) # if i & 3 == 0: # gc.collect() # Final scalar = a - c * (mu_P * p + mu_c * Z) crypto.sc_mul_into(tmp_sc, mu_P, p) crypto.sc_muladd_into(tmp_sc, mu_C, z, tmp_sc) crypto.sc_mulsub_into(tmp_sc, c, tmp_sc, a) crypto.encodeint_into(mg_buff[index + 1], tmp_sc) mg_buff.append(crypto.encodeint(sc1)) mg_buff.append(sD) return mg_buff
def prove_range_chunked(amount, last_mask=None): a = crypto.sc_init(0) si = crypto.sc_init(0) c = crypto.sc_init(0) ee = crypto.sc_init(0) tmp_ai = crypto.sc_init(0) tmp_alpha = crypto.sc_init(0) C_acc = crypto.identity() C_h = crypto.xmr_H() C_tmp = crypto.identity() L = crypto.identity() Zero = crypto.identity() kck = crypto.get_keccak() ai = bytearray(32 * 64) alphai = bytearray(32 * 64) buff = bytearray(32) Cis = bytearray(32 * 64) s0s = bytearray(32 * 64) s1s = bytearray(32 * 64) ee_bin = bytearray(32) for ii in range(64): crypto.random_scalar_into(tmp_ai) if last_mask is not None and ii == 63: crypto.sc_sub_into(tmp_ai, last_mask, a) crypto.sc_add_into(a, a, tmp_ai) crypto.random_scalar_into(tmp_alpha) crypto.scalarmult_base_into(L, tmp_alpha) crypto.scalarmult_base_into(C_tmp, tmp_ai) # C_tmp += &Zero if BB(ii) == 0 else &C_h crypto.point_add_into(C_tmp, C_tmp, Zero if ((amount >> ii) & 1) == 0 else C_h) crypto.point_add_into(C_acc, C_acc, C_tmp) # Set Ci[ii] to sigs crypto.encodepoint_into(Cis, C_tmp, ii << 5) crypto.encodeint_into(ai, tmp_ai, ii << 5) crypto.encodeint_into(alphai, tmp_alpha, ii << 5) if ((amount >> ii) & 1) == 0: crypto.random_scalar_into(si) crypto.encodepoint_into(buff, L) crypto.hash_to_scalar_into(c, buff) crypto.point_sub_into(C_tmp, C_tmp, C_h) crypto.add_keys2_into(L, si, c, C_tmp) crypto.encodeint_into(s1s, si, ii << 5) crypto.encodepoint_into(buff, L) kck.update(buff) crypto.point_double_into(C_h, C_h) # Compute ee tmp_ee = kck.digest() crypto.decodeint_into(ee, tmp_ee) del (tmp_ee, kck) C_h = crypto.xmr_H() gc.collect() # Second pass, s0, s1 for ii in range(64): crypto.decodeint_into(tmp_alpha, alphai, ii << 5) crypto.decodeint_into(tmp_ai, ai, ii << 5) if ((amount >> ii) & 1) == 0: crypto.sc_mulsub_into(si, tmp_ai, ee, tmp_alpha) crypto.encodeint_into(s0s, si, ii << 5) else: crypto.random_scalar_into(si) crypto.encodeint_into(s0s, si, ii << 5) crypto.decodepoint_into(C_tmp, Cis, ii << 5) crypto.add_keys2_into(L, si, ee, C_tmp) crypto.encodepoint_into(buff, L) crypto.hash_to_scalar_into(c, buff) crypto.sc_mulsub_into(si, tmp_ai, c, tmp_alpha) crypto.encodeint_into(s1s, si, ii << 5) crypto.point_double_into(C_h, C_h) crypto.encodeint_into(ee_bin, ee) del (ai, alphai, buff, tmp_ai, tmp_alpha, si, c, ee, C_tmp, C_h, L, Zero) gc.collect() return C_acc, a, [s0s, s1s, ee_bin, Cis]
def prove_range_mem(amount, last_mask=None): """ Memory optimized range proof. Gives C, and mask such that \sumCi = C c.f. http:#eprint.iacr.org/2015/1098 section 5.1 Ci is a commitment to either 0 or 2^i, i=0,...,63 thus this proves that "amount" is in [0, 2^ATOMS] mask is a such that C = aG + bH, and b = amount :param amount: :param last_mask: ai[ATOMS-1] will be computed as \sum_{i=0}^{ATOMS-2} a_i - last_mask :return: sumCi, mask, RangeSig. sumCi is Pedersen commitment on the amount value. sumCi = aG + amount*H mask is "a" from the Pedersent commitment above. """ n = ATOMS bb = d2b(amount, n) # gives binary form of bb in "digits" binary digits ai = [None] * len(bb) Ci = [None] * len(bb) a = crypto.sc_0() C = crypto.identity() alpha = mlsag2.key_zero_vector(n) s1 = mlsag2.key_zero_vector(n) c_H = crypto.xmr_H() kck = crypto.get_keccak() # ee computation # First pass, generates: ai, alpha, Ci, ee, s1 for ii in range(n): ai[ii] = crypto.random_scalar() if last_mask is not None and ii == ATOMS - 1: ai[ii] = crypto.sc_sub(last_mask, a) a = crypto.sc_add( a, ai[ii] ) # creating the total mask since you have to pass this to receiver... alpha[ii] = crypto.random_scalar() L = crypto.scalarmult_base(alpha[ii]) if bb[ii] == 0: Ci[ii] = crypto.scalarmult_base(ai[ii]) else: Ci[ii] = crypto.point_add(crypto.scalarmult_base(ai[ii]), c_H) C = crypto.point_add(C, Ci[ii]) if bb[ii] == 0: s1[ii] = crypto.random_scalar() c = crypto.hash_to_scalar(crypto.encodepoint(L)) L = crypto.add_keys2(s1[ii], c, crypto.point_sub(Ci[ii], c_H)) kck.update(crypto.encodepoint(L)) else: kck.update(crypto.encodepoint(L)) c_H = crypto.point_double(c_H) # Compute ee, memory cleanup ee = crypto.decodeint(kck.digest()) del kck # Second phase computes: s0, s1 c_H = crypto.xmr_H() s0 = mlsag2.key_zero_vector(n) for jj in range(n): if not bb[jj]: s0[jj] = crypto.sc_mulsub(ai[jj], ee, alpha[jj]) else: s0[jj] = crypto.random_scalar() LL = crypto.add_keys2(s0[jj], ee, Ci[jj]) cc = crypto.hash_to_scalar(crypto.encodepoint(LL)) s1[jj] = crypto.sc_mulsub(ai[jj], cc, alpha[jj]) c_H = crypto.point_double(c_H) A = xmrtypes.BoroSig() A.s0, A.s1, A.ee = s0, s1, ee R = xmrtypes.RangeSig() R.asig = A R.Ci = Ci return C, a, R
def _state_init(self): self.ctx_f = crypto.get_keccak() self.ctx_h = crypto.get_keccak() self.ctx_amount = sha256() self.ctx_commitment = sha256()