def back_encrypt(self, authenticated=True): for i in range(5): priv_key = crypto.random_scalar() data = crypto.cn_fast_hash(crypto.encodeint( crypto.random_scalar())) * (i + 1) blob = chacha.encrypt_xmr(priv_key, data, authenticated=authenticated) plaintext = chacha.decrypt_xmr(priv_key, blob, authenticated=authenticated) self.assertEqual(data, plaintext) try: plaintext2 = chacha.decrypt_xmr( crypto.sc_add(priv_key, crypto.sc_init(1)), blob, authenticated=authenticated, ) if authenticated: self.fail("Signature error expected") else: self.assertNotEqual(data, plaintext2) except: if not authenticated: raise
def gen_creds(self): if self.creds: return for i in range(3): self.creds.append( AccountCreds.new_wallet(crypto.random_scalar(), crypto.random_scalar(), self.nettype)) return self.creds
def test_ge25519_double_scalarmult_vartime(self): for i in range(10): ap = crypto.random_scalar() A = crypto.scalarmult_base(ap) a = crypto.random_scalar() b = crypto.random_scalar() R = crypto.ge_double_scalarmult_base_vartime(a, A, b) R_exp = crypto.point_add(crypto.scalarmult(A, a), crypto.scalarmult_base(b)) self.assertTrue(crypto.point_eq(R, R_exp))
def gen_clsag_sig(self, ring_size=11, index=None): msg = bytearray(random.getrandbits(8) for _ in range(32)) amnt = crypto.sc_init(random.randint(0, 0xFFFFFF) + 12) priv = crypto.random_scalar() msk = crypto.random_scalar() alpha = crypto.random_scalar() P = crypto.scalarmult_base(priv) C = crypto.add_keys2(msk, amnt, crypto.xmr_H()) Cp = crypto.add_keys2(alpha, amnt, crypto.xmr_H()) ring = [] for i in range(ring_size - 1): tk = TmpKey( crypto.encodepoint( crypto.scalarmult_base(crypto.random_scalar())), crypto.encodepoint( crypto.scalarmult_base(crypto.random_scalar())), ) ring.append(tk) index = index if index is not None else random.randint(0, len(ring)) ring.insert(index, TmpKey(crypto.encodepoint(P), crypto.encodepoint(C))) ring2 = list(ring) mg_buffer = [] self.assertTrue( crypto.point_eq(crypto.scalarmult_base(priv), crypto.decodepoint(ring[index].dest))) self.assertTrue( crypto.point_eq( crypto.scalarmult_base(crypto.sc_sub(msk, alpha)), crypto.point_sub(crypto.decodepoint(ring[index].commitment), Cp), )) mlsag2.generate_clsag_simple( msg, ring, CtKey(dest=priv, mask=msk), alpha, Cp, index, mg_buffer, ) sD = crypto.decodepoint(mg_buffer[-1]) sc1 = crypto.decodeint(mg_buffer[-2]) scalars = [crypto.decodeint(x) for x in mg_buffer[1:-2]] H = crypto.new_point() sI = crypto.new_point() crypto.hash_to_point_into(H, crypto.encodepoint(P)) crypto.scalarmult_into(sI, H, priv) # I = p*H return msg, scalars, sc1, sI, sD, ring2, Cp
def gen_mlsag_rows(message, rv, pk, xx, kLRki, index, dsRows, rows, cols): """ MLSAG computation - the part with secret keys :param message: :param rv: :param pk: :param xx: :param kLRki: :param index: :param dsRows: :param rows: :param cols: :return: """ Ip = key_vector(dsRows) rv.II = key_vector(dsRows) alpha = key_vector(rows) rv.ss = key_matrix(rows, cols) hasher = hasher_message(message) for i in range(dsRows): hasher.update(crypto.encodepoint(pk[index][i])) if kLRki: alpha[i] = kLRki.k rv.II[i] = kLRki.ki hasher.update(crypto.encodepoint(kLRki.L)) hasher.update(crypto.encodepoint(kLRki.R)) else: Hi = crypto.hash_to_point(crypto.encodepoint( pk[index][i])) # originally hashToPoint() alpha[i] = crypto.random_scalar() aGi = crypto.scalarmult_base(alpha[i]) aHPi = crypto.scalarmult(Hi, alpha[i]) rv.II[i] = crypto.scalarmult(Hi, xx[i]) hasher.update(crypto.encodepoint(aGi)) hasher.update(crypto.encodepoint(aHPi)) Ip[i] = crypto.precomp(rv.II[i]) for i in range(dsRows, rows): alpha[i] = crypto.random_scalar() aGi = crypto.scalarmult_base(alpha[i]) hasher.update(crypto.encodepoint(pk[index][i])) hasher.update(crypto.encodepoint(aGi)) c_old = hasher.digest() c_old = crypto.decodeint(c_old) return c_old, Ip, alpha
def test_encrypt_base(self): for i in range(10): key = crypto.cn_fast_hash(crypto.encodeint(crypto.random_scalar())) data = crypto.cn_fast_hash(crypto.encodeint( crypto.random_scalar())) * (i + 1) ciphertext = chacha.encrypt(key, data) plaintext = chacha.decrypt(key, ciphertext) self.assertEqual(plaintext, data) plaintext2 = chacha.decrypt( key, bytes(int(ciphertext[0]) ^ 0xff) + ciphertext[1:]) self.assertNotEqual(plaintext2, data)
def compute_tx_key(spend_key_private, tx_prefix_hash, salt=None, rand_mult=None): """ :param spend_key_private: :param tx_prefix_hash: :param salt: :param rand_mult: :return: """ if not salt: salt = crypto.random_bytes(32) if not rand_mult: rand_mult_num = crypto.random_scalar() rand_mult = crypto.encodeint(rand_mult_num) else: rand_mult_num = crypto.decodeint(rand_mult) rand_inp = crypto.sc_add(spend_key_private, rand_mult_num) passwd = crypto.keccak_2hash(crypto.encodeint(rand_inp) + tx_prefix_hash) tx_key = crypto.compute_hmac(salt, passwd) # tx_key = crypto.pbkdf2(passwd, salt, count=100) return tx_key, salt, rand_mult
def gen_r(self): """ Generates a new transaction key pair. :return: """ self.r = crypto.random_scalar() self.r_pub = crypto.scalarmult_base(self.r)
async def init_transaction(self, tsx_data, tsx_ctr): """ Initializes a new transaction. :param tsx_data: :param tsx_ctr: :return: """ self.tsx_data = tsx_data self.gen_r() # Additional keys class_res = classify_subaddresses( tsx_data.outputs, tsx_data.change_dts.addr if tsx_data.change_dts else None ) num_stdaddresses, num_subaddresses, single_dest_subaddress = class_res # if this is a single-destination transfer to a subaddress, we set the tx pubkey to R=s*D if num_stdaddresses == 0 and num_subaddresses == 1: self.r_pub = crypto.ge_scalarmult( self.r, crypto.decodepoint(single_dest_subaddress.m_spend_public_key) ) self.need_additional_txkeys = num_subaddresses > 0 and ( num_stdaddresses > 0 or num_subaddresses > 1 ) if self.need_additional_txkeys: for _ in range(len(tsx_data.outputs)): self.additional_tx_keys.append(crypto.random_scalar()) # Extra processing, payment id self.tx.version = 2 self.tx.unlock_time = tsx_data.unlock_time await self.process_payment_id() await self.compute_hmac_keys(tsx_ctr)
def test_prove_2(self): bpi = bp.BulletProofBuilder() val = crypto.sc_init((1 << 30) - 1 + 16) mask = crypto.random_scalar() bp_res = bpi.prove(val, mask) bpi.verify(bp_res)
async def mlsag_prepare(self): Hi = None xin = None options = 0 if len(self.c_msg) > 1: options = 1 Hi = crypto.decodepoint(self._fetch()) if self.options & 0x40: xin = crypto.decodeint(self._fetch()) else: xin = crypto.decodeint(self._fetch_decrypt()) alpha = crypto.random_scalar() self._insert_encrypt(crypto.encodeint(alpha)) # ai.G self._insert(crypto.encodepoint(crypto.scalarmult_base(alpha))) if options: # ai * Hi self._insert(crypto.encodepoint(crypto.scalarmult(Hi, alpha))) # xin * Hi self._insert(crypto.encodepoint(crypto.scalarmult(Hi, xin))) return SW_OK
def scalar_gen_vector(n): """ Generates vector of scalars :param n: :return: """ return [crypto.random_scalar() for _ in range(0, n)]
def test_prove_random_masks(self): bpi = bp.BulletProofBuilder() bpi.use_det_masks = False # trully randomly generated mask vectors val = crypto.sc_init((1 << 30) - 1 + 16) mask = crypto.random_scalar() bp_res = bpi.prove(val, mask) bpi.verify(bp_res)
def gen_r(self, use_r=None): """ Generates a new transaction key pair. :param use_r: :return: """ self.r = crypto.random_scalar() if use_r is None else use_r self.r_pub = crypto.scalarmult_base(self.r)
def test_prove_testnet_2(self): self.skip_if_cannot_test() bpi = bp.BulletProofBuilder() val = crypto.sc_init((1 << 30) - 1 + 16) mask = crypto.random_scalar() bp_res = bpi.prove_testnet(val, mask) bpi.verify_testnet(bp_res)
def main(): """ Entry point :return: """ parser = argparse.ArgumentParser( description="Generate non-deterministic wallet credentials") parser.add_argument( "--testnet", dest="testnet", default=False, action="store_const", const=True, help="Testnet", ) parser.add_argument( "--stagenet", dest="stagenet", default=False, action="store_const", const=True, help="Testnet", ) args = parser.parse_args() network_type = monero.NetworkTypes.MAINNET if args.testnet: network_type = monero.NetworkTypes.TESTNET elif args.stagenet: network_type = monero.NetworkTypes.STAGENET priv_view = crypto.random_scalar() priv_spend = crypto.random_scalar() w = monero.AccountCreds.new_wallet(priv_view, priv_spend, network_type=network_type) print("Address: %s" % w.address.decode("utf8")) print("Private view key: %s" % binascii.hexlify(crypto.encodeint(priv_view)).decode("utf8")) print("Private spend key: %s" % binascii.hexlify(crypto.encodeint(priv_spend)).decode("utf8"))
async def open_tx(self): self.ctx_amount = sha256() self.account = self._fetch_u32() self.r = crypto.random_scalar() self.R = crypto.scalarmult_base(self.r) self._insert(crypto.encodepoint(self.R)) self._insert_encrypt(crypto.encodeint(self.r)) return SW_OK
def pttest2(N=10000): a = crypto.random_scalar() a8 = crypto.sc_mul(a, crypto.sc_init(8)) for i in range(1, N): ca = crypto.sc_mul(a8, crypto.sc_init(i)) A8 = crypto.scalarmult_base(ca) A8bin = crypto.encodepoint(A8) red = crypto.encodeint(crypto.decodeint(A8bin)) if red == A8bin: return i, red return None
def gen_schnorr_non_linkable(x, P1, P2, index): """ Generates simple Schnorr :param x: :param P1: :param P2: :param index: :return: """ a = crypto.random_scalar() L1 = crypto.scalarmult_base(a) s2 = crypto.random_scalar() c2 = crypto.cn_fast_hash(crypto.encodepoint(L1)) L2 = crypto.point_add( crypto.scalarmult_base(s2), crypto.scalarmult(P2 if index == 0 else P1, crypto.decodeint(c2)), ) c1 = crypto.cn_fast_hash(crypto.encodepoint(L2)) s1 = crypto.sc_mulsub(x, crypto.decodeint(c1), a) return (L1, s1, s2) if index == 0 else (L2, s2, s1)
def test_signature(self): for i in range(10): priv = crypto.random_scalar() data = crypto.cn_fast_hash(bytes(bytearray([i]))) c, r, pub = crypto.generate_signature(data, priv) res = crypto.check_signature(data, c, r, pub) self.assertEqual(res, 1) res2 = crypto.check_signature(data, crypto.sc_add(c, crypto.sc_init(1)), r, pub) self.assertEqual(res2, 0)
async def prove_range_bp(amount, last_mask=None): mask = last_mask if last_mask is not None else crypto.random_scalar() bp_proof = await prove_range_bp_batch([amount], [mask]) C = crypto.decodepoint(bp_proof.V[0]) C = crypto.point_mul8(C) gc.collect() # Return as struct as the hash(BP_struct) != hash(BP_serialized) # as the original hashing does not take vector lengths into account which are dynamic # in the serialization scheme (and thus extraneous) return C, mask, bp_proof
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 test_pointadd(self): a = crypto.random_scalar() A = crypto.scalarmult_base(a) A2 = crypto.point_add(A, A) A3 = crypto.point_add(A2, A) A4 = crypto.point_add(A3, A) A8 = crypto.scalarmult(A4, crypto.sc_init(2)) A8p = crypto.point_mul8(A) self.assertTrue(crypto.point_eq(A8p, A8)) self.assertTrue( crypto.point_eq(A4, crypto.scalarmult(A, crypto.sc_init(4)))) self.assertTrue( crypto.point_eq(A3, crypto.scalarmult(A, crypto.sc_init(3))))
def prove_range_orig(amount, last_mask=None, use_asnl=False): """ 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 :param use_asnl: use ASNL, used before Borromean, insecure :return: sumCi, mask, RangeSig. sumCi is Pedersen commitment on the amount value. sumCi = aG + amount*H mask is "a" from the Pedersent commitment above. """ bb = d2b(amount, ATOMS) # gives binary form of bb in "digits" binary digits logger.info("amount, amount in binary %s %s" % (amount, bb)) ai = [None] * len(bb) Ci = [None] * len(bb) CiH = [None] * len(bb) # this is like Ci - 2^i H H2 = crypto.gen_Hpow(ATOMS) a = crypto.sc_0() for i in range(0, ATOMS): ai[i] = crypto.random_scalar() if last_mask is not None and i == ATOMS - 1: ai[i] = crypto.sc_sub(last_mask, a) a = crypto.sc_add( a, ai[i] ) # creating the total mask since you have to pass this to receiver... if bb[i] == 0: Ci[i] = crypto.scalarmult_base(ai[i]) if bb[i] == 1: Ci[i] = crypto.point_add(crypto.scalarmult_base(ai[i]), H2[i]) CiH[i] = crypto.point_sub(Ci[i], H2[i]) A = xmrtypes.BoroSig() if use_asnl: A.s0, A.s1, A.ee = asnl.gen_asnl(ai, Ci, CiH, bb) else: A.s0, A.s1, A.ee = mlsag2.gen_borromean(ai, Ci, CiH, bb) R = xmrtypes.RangeSig() R.asig = A R.Ci = Ci C = sum_Ci(Ci) return C, a, R
async def commitment(self, in_amount): """ Computes Pedersen commitment - pseudo outs Here is slight deviation from the original protocol. We want that \\sum Alpha = \\sum A_{i,j} where A_{i,j} is a mask from range proof for output i, bit j. Previously this was computed in such a way that Alpha_{last} = \\sum A{i,j} - \\sum_{i=0}^{last-1} Alpha But we would prefer to compute commitment before range proofs so alphas are generated completely randomly and the last A mask is computed in this special way. Returns pseudo_out :return: """ alpha = crypto.random_scalar() self.sumpouts_alphas = crypto.sc_add(self.sumpouts_alphas, alpha) return alpha, crypto.gen_c(alpha, in_amount)
def ecdh_encode(unmasked, receiver_pk=None, derivation=None, v2=False, dest=None): """ Elliptic Curve Diffie-Helman: encodes and decodes the amount b and mask a where C= aG + bH :param unmasked: :param receiver_pk: :param derivation: :return: """ rv = xmrtypes.EcdhTuple() if dest is None else dest if derivation is None: esk = crypto.random_scalar() rv.senderPk = crypto.scalarmult_base(esk) derivation = crypto.encodepoint(crypto.scalarmult(receiver_pk, esk)) return ecdh_encdec(unmasked, None, derivation, v2=v2, enc=True, dest=rv)
async def compute_sec_keys(self, tsx_data, tsx_ctr): """ Generate master key H(TsxData || r || c_tsx) :return: """ from monero_glue.xmr.sub.keccak_hasher import get_keccak_writer from monero_serialize import xmrserialize writer = get_keccak_writer() ar1 = xmrserialize.Archive(writer, True) await ar1.message(tsx_data) await writer.awrite(crypto.encodeint(self.r)) await xmrserialize.dump_uvarint(writer, tsx_ctr) self.key_master = crypto.keccak_2hash( writer.get_digest() + crypto.encodeint(crypto.random_scalar()) ) self.key_hmac = crypto.keccak_2hash(b"hmac" + self.key_master) self.key_enc = crypto.keccak_2hash(b"enc" + self.key_master)
def ecdh_encode(unmasked, receiver_pk=None, derivation=None): """ Elliptic Curve Diffie-Helman: encodes and decodes the amount b and mask a where C= aG + bH :param unmasked: :param receiver_pk: :param derivation: :return: """ rv = xmrtypes.EcdhTuple() if derivation is None: esk = crypto.random_scalar() rv.senderPk = crypto.scalarmult_base(esk) derivation = crypto.encodepoint(crypto.scalarmult(receiver_pk, esk)) sec1 = crypto.hash_to_scalar(derivation) sec2 = crypto.hash_to_scalar(crypto.encodeint(sec1)) rv.mask = crypto.sc_add(unmasked.mask, sec1) rv.amount = crypto.sc_add(unmasked.amount, sec2) return rv
async def _set_out1_additional_keys(self, dst_entr): additional_txkey = None additional_txkey_priv = None if self.need_additional_txkeys: use_provided = self.num_dests() == len(self.additional_tx_private_keys) additional_txkey_priv = ( self.additional_tx_private_keys[self.out_idx] if use_provided else crypto.random_scalar() ) if dst_entr.is_subaddress: additional_txkey = crypto.ge_scalarmult( additional_txkey_priv, crypto.decodepoint(dst_entr.addr.m_spend_public_key), ) else: additional_txkey = crypto.ge_scalarmult_base(additional_txkey_priv) self.additional_tx_public_keys.append(crypto.encodepoint(additional_txkey)) if not use_provided: self.additional_tx_private_keys.append(additional_txkey_priv) return additional_txkey_priv
async def test_live_refresh(self): if self.should_test_only_tx() or not int( os.getenv("TREZOR_TEST_LIVE_REFRESH", '1')): self.skipTest("Live refresh skipped") creds = self.get_trezor_creds(0) await self.agent.live_refresh_start() for att in range(22): r = crypto.random_scalar() R = crypto.scalarmult_base(r) D = crypto.scalarmult(R, creds.view_key_private) subaddr = 0, att scalar_step1 = crypto.derive_secret_key(D, att, creds.spend_key_private) # step 2: add Hs(SubAddr || a || index_major || index_minor) if subaddr == (0, 0): scalar_step2 = scalar_step1 else: subaddr_sk = monero.get_subaddress_secret_key( creds.view_key_private, major=0, minor=att) scalar_step2 = crypto.sc_add(scalar_step1, subaddr_sk) pub_ver = crypto.scalarmult_base(scalar_step2) ki = monero.generate_key_image(crypto.encodepoint(pub_ver), scalar_step2) ki2 = await self.agent.live_refresh(creds.view_key_private, crypto.encodepoint(pub_ver), crypto.encodepoint(D), att, 0, att) if not crypto.point_eq(ki, ki2): raise ValueError("Key image inconsistent") time.sleep(0.1) await self.agent.live_refresh_final()