def ver_range(C=None, rsig=None, use_bulletproof=False, decode=True): """ Verifies that \sum Ci = C and that each Ci is a commitment to 0 or 2^i :param C: :param rsig: :param use_bulletproof: bulletproof :param decode: decodes encoded range proof :return: """ n = ATOMS CiH = [None] * n C_tmp = crypto.identity() c_H = crypto.xmr_H() if decode and not use_bulletproof: rsig = monero.recode_rangesig(rsig, encode=False, copy=True) if not use_bulletproof: for i in range(0, n): CiH[i] = crypto.point_sub(rsig.Ci[i], c_H) C_tmp = crypto.point_add(C_tmp, rsig.Ci[i]) c_H = crypto.point_double(c_H) if C is not None and not crypto.point_eq(C_tmp, C): return 0 if use_bulletproof: bp = bulletproof.BulletProofBuilder() return bp.verify(rsig) return mlsag2.ver_borromean(rsig.Ci, CiH, rsig.asig.s0, rsig.asig.s1, rsig.asig.ee)
def ver_range(C=None, rsig=None, use_asnl=False, decode=True): """ Verifies that \sum Ci = C and that each Ci is a commitment to 0 or 2^i :param C: :param rsig: :param use_asnl: use ASNL, used before Borromean, insecure! :param decode: decodes encoded range proof :return: """ n = ATOMS CiH = [None] * n C_tmp = crypto.identity() c_H = crypto.gen_H() if decode: rsig = monero.recode_rangesig(rsig, encode=False, copy=True) for i in range(0, n): CiH[i] = crypto.point_sub(rsig.Ci[i], c_H) C_tmp = crypto.point_add(C_tmp, rsig.Ci[i]) c_H = crypto.point_double(c_H) if C is not None and not crypto.point_eq(C_tmp, C): return 0 if use_asnl: return asnl.ver_asnl(rsig.Ci, CiH, rsig.asig.s0, rsig.asig.s1, rsig.asig.ee) else: return mlsag2.ver_borromean(rsig.Ci, CiH, rsig.asig.s0, rsig.asig.s1, rsig.asig.ee)
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