@ -2,20 +2,151 @@ from common import *
if not utils . BITCOIN_ONLY :
from apps . monero . xmr import bulletproof as bp , crypto , monero
from apps . monero . xmr . serialize_messages . tx_rsig_bulletproof import Bulletproof
from apps . monero . xmr . serialize_messages . tx_rsig_bulletproof import Bulletproof , BulletproofPlus
@unittest.skipUnless ( not utils . BITCOIN_ONLY , " altcoin " )
class TestMoneroBulletproof ( unittest . TestCase ) :
def test_1 ( self ) :
pass
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 )
def mask_consistency_check ( self , bpi ) :
sv = [ crypto . Scalar ( 123 ) ]
gamma = [ crypto . Scalar ( 432 ) ]
M , logM , aL , aR , V , gamma = bpi . prove_setup ( sv , gamma )
bpi. prove_setup ( sv , gamma )
x = bp . _ensure_dst_key ( )
y = bp . _ensure_dst_key ( )
@ -39,8 +170,8 @@ class TestMoneroBulletproof(unittest.TestCase):
ve1 = bp . _ensure_dst_key ( )
ve2 = bp . _ensure_dst_key ( )
bpi . vector_exponent ( aL, aR , ve1 )
bpi . vector_exponent ( aL, aR , ve2 )
bpi . vector_exponent ( bpi. aL, bpi . aR , ve1 )
bpi . vector_exponent ( bpi. aL, bpi . aR , ve2 )
bpi . vector_exponent ( sL , sR , ve1 )
bpi . vector_exponent ( sL , sR , ve2 )
@ -275,6 +406,38 @@ class TestMoneroBulletproof(unittest.TestCase):
b = unhexlify ( b " dfea0fe39d9a7c5497fd01e92fc7fa8b39cda75b340322f77e0cac15194aa007 " ) ,
t = unhexlify ( b " 0de43b393686af8dd0d89f4832a2995cda14e6288de9ecd2b4bf2fa39baba408 " )
)
def bproof_plus_1 ( 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 " ) ,
] ,
)
# fmt: on
def test_masks ( self ) :
@ -319,6 +482,31 @@ class TestMoneroBulletproof(unittest.TestCase):
with self . assertRaises ( Exception ) :
bpi . verify_batch ( [ self . bproof_2_invalid ( ) ] )
def test_verify_plus ( self ) :
bpi = bp . BulletProofPlusBuilder ( )
bpi . verify_batch ( [ self . bproof_plus_1 ( ) ] )
def test_prove_plus_ ( 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_8 ( self ) :
bpi = bp . BulletProofPlusBuilder ( )
sv = [ crypto . Scalar ( i * 123 + 45 ) for i in range ( 8 ) ]
gamma = [ crypto . Scalar ( i * 456 * 17 ) for i in range ( 8 ) ]
proof = bpi . prove_batch ( sv , gamma )
bpi . verify_batch ( [ proof ] )
def test_prove_random_masks ( self ) :
bpi = bp . BulletProofBuilder ( )
bpi . use_det_masks = False # trully randomly generated mask vectors