You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
trezor-firmware/core/tests/test_apps.monero.bulletproo...

294 lines
12 KiB

from common import * # isort:skip
if not utils.BITCOIN_ONLY:
from apps.monero.xmr import bulletproof as bp
from apps.monero.xmr import crypto
from apps.monero.xmr.serialize_messages.tx_rsig_bulletproof import BulletproofPlus
@unittest.skipUnless(not utils.BITCOIN_ONLY, "altcoin")
class TestMoneroBulletproof(unittest.TestCase):
def test_square_multiply(self):
for x in [2, 3, 16, 17, 31, 32]:
ss = crypto.random_scalar()
s1 = crypto.sc_copy(None, ss)
s2 = crypto.sc_copy(None, ss)
for i in range(1, x):
crypto.sc_mul_into(s1, s1, ss)
bp._sc_square_mult(s2, ss, x)
self.assertEqual(
crypto.encodeint_into(None, s1), crypto.encodeint_into(None, s2)
)
def test_dvct_skips(self):
z_sq = unhexlify(
b"e0408b528e9d35ccb8386b87f39b85c724740644f4db412483a8852cdb3ceb00"
)
d_vct0 = bp.VctD(64, 8, z_sq, raw=True)
d_vct1 = bp.VctD(64, 8, z_sq, raw=True)
tmp = crypto.Scalar()
# Linear scan vs jump
for i in range(65):
tmp = d_vct0[i]
self.assertEqual(
crypto.encodeint_into(None, tmp), crypto.encodeint_into(None, d_vct1[64])
)
# Jumping around
_ = d_vct0[128]
self.assertEqual(
crypto.encodeint_into(None, d_vct0[64]),
crypto.encodeint_into(None, d_vct1[64]),
)
# Sync on the same jump
self.assertEqual(
crypto.encodeint_into(None, d_vct0[65]),
crypto.encodeint_into(None, d_vct1[65]),
)
self.assertEqual(
crypto.encodeint_into(None, d_vct0[65]),
crypto.encodeint_into(None, d_vct1[65]),
)
# Jump vs linear again, move_one vs move_more
for i in range(1, 10):
tmp = d_vct0[65 + i]
self.assertEqual(
crypto.encodeint_into(None, tmp), crypto.encodeint_into(None, d_vct1[74])
)
_ = d_vct0[85]
_ = d_vct1[89] # different jump sizes, internal state management test
self.assertEqual(
crypto.encodeint_into(None, d_vct0[95]),
crypto.encodeint_into(None, d_vct1[95]),
)
_ = d_vct0[319] # move_one mults by z_sq then; enforce z component updates
self.assertEqual(
crypto.encodeint_into(None, d_vct0[320]),
crypto.encodeint_into(None, d_vct1[320]),
)
tmp = crypto.sc_copy(None, d_vct0[64]) # another jump back and forth
_ = d_vct0[127]
self.assertEqual(
crypto.encodeint_into(None, d_vct0[64]), crypto.encodeint_into(None, tmp)
)
_ = d_vct0[0]
_ = d_vct1[0]
_ = d_vct0[64]
self.assertEqual(
crypto.encodeint_into(None, d_vct0[5]),
crypto.encodeint_into(None, d_vct1[5]),
)
def test_pow_back_skips(self):
MN = 128
y = unhexlify(
"60421950bee0aab949e63336db1eb9532dba6b4599c5cd9fb1dbde909114100e"
)
y_sc = crypto.decodeint_into(None, y)
yinv = bp._invert(None, y)
y_to_MN_1 = bp._sc_square_mult(None, y_sc, MN - 1)
ymax = crypto.sc_mul_into(None, y_to_MN_1, y_sc) ## y**MN
ymax2 = bp._sc_square_mult(None, y_sc, MN)
self.assertEqual(
crypto.encodeint_into(None, ymax), crypto.encodeint_into(None, ymax2)
)
size = MN + 1
ypow_back = bp.KeyVPowersBackwards(size, y, x_inv=yinv, x_max=ymax, raw=True)
self.assertEqual(
crypto.encodeint_into(None, ymax),
crypto.encodeint_into(None, ypow_back[MN]),
)
for i in range(10):
_ = ypow_back[MN - i]
self.assertEqual(
crypto.encodeint_into(None, ypow_back[MN - 9]),
crypto.encodeint_into(None, bp._sc_square_mult(None, y_sc, MN - 9)),
)
self.assertEqual(
crypto.encodeint_into(None, ypow_back[MN - 19]),
crypto.encodeint_into(None, bp._sc_square_mult(None, y_sc, MN - 19)),
)
self.assertEqual(
crypto.encodeint_into(None, ypow_back[MN - 65]),
crypto.encodeint_into(None, bp._sc_square_mult(None, y_sc, MN - 65)),
)
self.assertEqual(
crypto.encodeint_into(None, ypow_back[MN - 14]),
crypto.encodeint_into(None, bp._sc_square_mult(None, y_sc, MN - 14)),
)
tmp = crypto.sc_copy(None, ypow_back[MN - 64]) # another jump back and forth
_ = ypow_back[MN - 127]
self.assertEqual(
crypto.encodeint_into(None, ypow_back[MN - 64]),
crypto.encodeint_into(None, tmp),
)
self.assertEqual(
crypto.encodeint_into(None, ypow_back[MN - 64]),
crypto.encodeint_into(None, bp._sc_square_mult(None, y_sc, MN - 64)),
)
def test_bpp_bprime(self):
N, M = 64, 4
MN = N * M
y = unhexlify(
b"60421950bee0aab949e63336db1eb9532dba6b4599c5cd9fb1dbde909114100e"
)
z = unhexlify(
b"e0408b528e9d35ccb8386b87f39b85c724740644f4db412483a8852cdb3ceb00"
)
zc = crypto.decodeint_into(None, z)
z_sq = bp._sc_mul(None, z, z)
sv = [1234, 8789, 4455, 6697]
sv = [crypto.encodeint_into(None, crypto.Scalar(x)) for x in sv]
num_inp = len(sv)
sc_zero = crypto.decodeint_into_noreduce(None, bp._ZERO)
sc_mone = crypto.decodeint_into_noreduce(None, bp._MINUS_ONE)
def e_xL(idx, d=None):
j, i = idx // bp._BP_N, idx % bp._BP_N
r = None
if j >= num_inp:
r = sc_mone
elif sv[j][i // 8] & (1 << i % 8):
r = sc_zero
else:
r = sc_mone
if d:
return crypto.sc_copy(d, r)
return r
aR = bp.KeyVEval(MN, lambda i, d: e_xL(i, d), raw=True)
d_vct = bp.VctD(N, M, z_sq, raw=True)
ypow_back = bp.KeyVPowersBackwards(MN + 1, y, raw=True)
aR1_sc1 = crypto.Scalar()
def aR1_fnc(i, d):
crypto.sc_add_into(aR1_sc1, aR.to(i), zc)
crypto.sc_muladd_into(aR1_sc1, d_vct[i], ypow_back[MN - i], aR1_sc1)
return crypto.encodeint_into(d, aR1_sc1)
bprime = bp.KeyVEval(MN, aR1_fnc, raw=False) # aR1
b64 = bp._copy_key(None, bprime.to(64))
b65 = bp._copy_key(None, bprime.to(65))
b128 = bp._copy_key(None, bprime.to(128))
b65_2 = bp._copy_key(None, bprime.to(65))
b64_2 = bp._copy_key(None, bprime.to(64))
_ = bprime[89]
b128_2 = bp._copy_key(None, bprime.to(128))
self.assertEqual(b64, b64_2)
self.assertEqual(b65, b65_2)
self.assertEqual(b128, b128_2)
# fmt: off
def bproof_plus_2(self):
return BulletproofPlus(
V=[
unhexlify(b"e0dae61095ac728a15d4d9754f1f9f956c22d4fa2deee2c0ff1def031b083e02"),
unhexlify(b"5b424ecb1f8ea02351d324296a34a0608ecc104610feaad06e6002f61992bfe1"),
],
A=unhexlify(b"6ae6f16a6b01cf494fb2cf368573365293f76c624cfc11152d648479238e9319"),
A1=unhexlify(b"33ad318a44df6f14a945e6d051911ab9a24841457d15d62bd1436fb3edc8a193"),
B=unhexlify(b"5f56531cb8e78dbb3450f1d599a6d4c7f5e4c04ee3e7015643c19a528bcbb109"),
r1=unhexlify(b"40ad8a9c6b3bdd95c7fb8605e50135050e64f1ce29d1c4b37b1271e658354500"),
s1=unhexlify(b"aed959c770499134aaa7e099f566dac56ee12959d797b62a3d8d1037b790b806"),
d1=unhexlify(b"395a1e8d3df8e90e716fdeaa493090782c8db922337d09a36b50c1f02cd8e100"),
L=[unhexlify(b"ed2d768bb9c8b5a9fa24c90b5831d3cceb3e78cef45eba90e52f89a2b3c859d2"),
unhexlify(b"7f25cc8e211783e9c1b80dd13ee286943da0ec07bd33291536639432758f6927"),
unhexlify(b"7bae3d31f4e2a6d78d74d2bcb6d0656e4222161423d635f7ce08805e96cec83e"),
unhexlify(b"c87f949f70cf569c4baa332612305733fd19a2262490c55ec88c16a68d7b5e7d"),
unhexlify(b"34d06caf0d02129ebcc8bf318da8f6a0ddfaf2c7cb85f4144726561cefc86dcd"),
unhexlify(b"ab3effd3a2706591774e013c76f5b8ece9e58abf7efc0a11b479f9d2a89d0c55"),
unhexlify(b"ebf8d34e6643533bf73b13d2dd56aeaf2113fb3017d39bc6db6a2f71bc1d53f1"),
],
R=[unhexlify(b"27e146e61e88944246dcd90ddb4284923c7fdc6fd6a187ed2efa3dcb8c380346"),
unhexlify(b"fab99152d48d835b9a01cdbec46301db0f57ca091f6cbaa0b45c8498f18babe1"),
unhexlify(b"8467f87acd7be026a27ed798cca6cc1526b0f805ac534a9c5162a9cd75460011"),
unhexlify(b"f421fa4bda1dba042ca56c6bdce313dc8d18cee084d722af47447ce54b6ff8df"),
unhexlify(b"8dd5dabc0ad67c83f42668e96bf5ee6741bcd8e661eda1e8ce6a23d84cf0b5b5"),
unhexlify(b"fcf20a7775699b0456542930b2374b233fb3f8f79e1911428157631a20b3c3ad"),
unhexlify(b"66e477bd93dabb184e2738829320bf8e60f6b4b476ca0fbc1013af28e8de34c1"),
],
)
def bproof_plus_2_invalid(self):
return BulletproofPlus(
V=[
unhexlify(b"e0dae61095ac728a15d4d9754f1f9f956c22d4fa2deee2c0ff1def031b083e02"),
unhexlify(b"5b424ecb1f8ea02351d324296a34a0608ecc104610feaad06e6002f61992bfe1"),
],
A=unhexlify(b"6ae6f16a6b01cf494fb2cf368573365293f76c624cfc11152d648479238e9309"),
A1=unhexlify(b"33ad318a44df6f14a945e6d051911ab9a24841457d15d62bd1436fb3edc8a193"),
B=unhexlify(b"5f56531cb8e78dbb3450f1d599a6d4c7f5e4c04ee3e7015643c19a528bcbb109"),
r1=unhexlify(b"40ad8a9c6b3bdd95c7fb8605e50135050e64f1ce29d1c4b37b1271e658354500"),
s1=unhexlify(b"aed959c770499134aaa7e099f566dac56ee12959d797b62a3d8d1037b790b806"),
d1=unhexlify(b"395a1e8d3df8e90e716fdeaa493090782c8db922337d09a36b50c1f02cd8e100"),
L=[unhexlify(b"ed2d768bb9c8b5a9fa24c90b5831d3cceb3e78cef45eba90e52f89a2b3c859d2"),
unhexlify(b"7f25cc8e211783e9c1b80dd13ee286943da0ec07bd33291536639432758f6927"),
unhexlify(b"7bae3d31f4e2a6d78d74d2bcb6d0656e4222161423d635f7ce08805e96cec83e"),
unhexlify(b"c87f949f70cf569c4baa332612305733fd19a2262490c55ec88c16a68d7b5e7d"),
unhexlify(b"34d06caf0d02129ebcc8bf318da8f6a0ddfaf2c7cb85f4144726561cefc86dcd"),
unhexlify(b"ab3effd3a2706591774e013c76f5b8ece9e58abf7efc0a11b479f9d2a89d0c55"),
unhexlify(b"ebf8d34e6643533bf73b13d2dd56aeaf2113fb3017d39bc6db6a2f71bc1d53f1"),
],
R=[unhexlify(b"27e146e61e88944246dcd90ddb4284923c7fdc6fd6a187ed2efa3dcb8c380346"),
unhexlify(b"fab99152d48d835b9a01cdbec46301db0f57ca091f6cbaa0b45c8498f18babe1"),
unhexlify(b"8467f87acd7be026a27ed798cca6cc1526b0f805ac534a9c5162a9cd75460011"),
unhexlify(b"f421fa4bda1dba042ca56c6bdce313dc8d18cee084d722af47447ce54b6ff8df"),
unhexlify(b"8dd5dabc0ad67c83f42668e96bf5ee6741bcd8e661eda1e8ce6a23d84cf0b5b5"),
unhexlify(b"fcf20a7775699b0456542930b2374b233fb3f8f79e1911428157631a20b3c3ad"),
unhexlify(b"66e477bd93dabb184e2738829320bf8e60f6b4b476ca0fbc1013af28e8de34c1"),
],
)
# fmt: on
def test_verify_plus(self):
bpi = bp.BulletProofPlusBuilder()
bpi.verify_batch([self.bproof_plus_2()])
bpi.verify_batch([self.bproof_plus_2(), self.bproof_plus_2()])
with self.assertRaises(Exception):
bpi.verify_batch([self.bproof_plus_2_invalid()])
def test_prove_plus_1(self):
bpi = bp.BulletProofPlusBuilder()
sv = [crypto.Scalar(123)]
gamma = [crypto.Scalar(456)]
proof = bpi.prove_batch(sv, gamma)
bpi.verify_batch([proof])
def test_prove_plus_2(self):
bpi = bp.BulletProofPlusBuilder()
sv = [crypto.Scalar(123), crypto.Scalar(768)]
gamma = [crypto.Scalar(456), crypto.Scalar(901)]
proof = bpi.prove_batch(sv, gamma)
bpi.verify_batch([proof])
def test_prove_plus_16(self):
bpi = bp.BulletProofPlusBuilder()
sv = [crypto.Scalar(i * 123 + 45) for i in range(16)]
gamma = [crypto.Scalar(i * 456 * 17) for i in range(16)]
proof = bpi.prove_batch(sv, gamma)
bpi.verify_batch([proof])
if __name__ == "__main__":
unittest.main()