mirror of
https://git.wownero.com/wownero/wownero.git
synced 2024-12-22 17:48:52 +00:00
Merge pull request #2883
c83d0b3e
add bulletproofs from v7 on testnet (moneromooo-monero)8620ef0a
bulletproofs: switch H/G in Pedersen commitments to match rct (moneromooo-monero)d58835b2
integrate bulletproofs into monero (moneromooo-monero)90b8d9f2
add bulletproofs to the build, with basic unit tests (moneromooo-monero)fe120264
perf_timer: add non scoped start/stop timer defines (moneromooo-monero)ada42914
add a version of ge_double_scalarmult_precomp_vartime with A precomp (moneromooo-monero)d43eef6d
ringct: add a version of addKeys which returns the result (moneromooo-monero)7ff07928
sc_mul and sc_muladd (luigi1111)3d0b54bd
epee: add do while(0) around brace statement in a macro (moneromooo-monero)
This commit is contained in:
commit
782a84f7b4
@ -169,7 +169,7 @@ namespace debug
|
||||
|
||||
|
||||
#define ASSERT_MES_AND_THROW(message) {LOG_ERROR(message); std::stringstream ss; ss << message; throw std::runtime_error(ss.str());}
|
||||
#define CHECK_AND_ASSERT_THROW_MES(expr, message) {if(!(expr)) ASSERT_MES_AND_THROW(message);}
|
||||
#define CHECK_AND_ASSERT_THROW_MES(expr, message) do {if(!(expr)) ASSERT_MES_AND_THROW(message);} while(0)
|
||||
|
||||
|
||||
#ifndef CHECK_AND_ASSERT
|
||||
|
@ -94,5 +94,8 @@ void set_performance_timer_log_level(el::Level level);
|
||||
#define PERF_TIMER_UNIT_L(name, unit, l) tools::PerformanceTimer pt_##name(#name, unit, l)
|
||||
#define PERF_TIMER(name) PERF_TIMER_UNIT(name, 1000)
|
||||
#define PERF_TIMER_L(name, l) PERF_TIMER_UNIT_L(name, 1000, l)
|
||||
#define PERF_TIMER_START_UNIT(name, unit) tools::PerformanceTimer *pt_##name = new tools::PerformanceTimer(#name, unit, el::Level::Info)
|
||||
#define PERF_TIMER_START(name) PERF_TIMER_START_UNIT(name, 1000)
|
||||
#define PERF_TIMER_STOP(name) do { delete pt_##name; pt_##name = NULL; } while(0)
|
||||
|
||||
}
|
||||
|
@ -2000,17 +2000,15 @@ void ge_scalarmult(ge_p2 *r, const unsigned char *a, const ge_p3 *A) {
|
||||
}
|
||||
}
|
||||
|
||||
void ge_double_scalarmult_precomp_vartime(ge_p2 *r, const unsigned char *a, const ge_p3 *A, const unsigned char *b, const ge_dsmp Bi) {
|
||||
void ge_double_scalarmult_precomp_vartime2(ge_p2 *r, const unsigned char *a, const ge_dsmp Ai, const unsigned char *b, const ge_dsmp Bi) {
|
||||
signed char aslide[256];
|
||||
signed char bslide[256];
|
||||
ge_dsmp Ai; /* A, 3A, 5A, 7A, 9A, 11A, 13A, 15A */
|
||||
ge_p1p1 t;
|
||||
ge_p3 u;
|
||||
int i;
|
||||
|
||||
slide(aslide, a);
|
||||
slide(bslide, b);
|
||||
ge_dsm_precomp(Ai, A);
|
||||
|
||||
ge_p2_0(r);
|
||||
|
||||
@ -2041,6 +2039,13 @@ void ge_double_scalarmult_precomp_vartime(ge_p2 *r, const unsigned char *a, cons
|
||||
}
|
||||
}
|
||||
|
||||
void ge_double_scalarmult_precomp_vartime(ge_p2 *r, const unsigned char *a, const ge_p3 *A, const unsigned char *b, const ge_dsmp Bi) {
|
||||
ge_dsmp Ai; /* A, 3A, 5A, 7A, 9A, 11A, 13A, 15A */
|
||||
|
||||
ge_dsm_precomp(Ai, A);
|
||||
ge_double_scalarmult_precomp_vartime2(r, a, Ai, b, Bi);
|
||||
}
|
||||
|
||||
void ge_mul8(ge_p1p1 *r, const ge_p2 *t) {
|
||||
ge_p2 u;
|
||||
ge_p2_dbl(r, t);
|
||||
@ -2898,6 +2903,658 @@ void sc_mulsub(unsigned char *s, const unsigned char *a, const unsigned char *b,
|
||||
s[31] = s11 >> 17;
|
||||
}
|
||||
|
||||
//copied from above and modified
|
||||
/*
|
||||
Input:
|
||||
a[0]+256*a[1]+...+256^31*a[31] = a
|
||||
b[0]+256*b[1]+...+256^31*b[31] = b
|
||||
|
||||
Output:
|
||||
s[0]+256*s[1]+...+256^31*s[31] = (ab) mod l
|
||||
where l = 2^252 + 27742317777372353535851937790883648493.
|
||||
*/
|
||||
void sc_mul(unsigned char *s, const unsigned char *a, const unsigned char *b) {
|
||||
int64_t a0 = 2097151 & load_3(a);
|
||||
int64_t a1 = 2097151 & (load_4(a + 2) >> 5);
|
||||
int64_t a2 = 2097151 & (load_3(a + 5) >> 2);
|
||||
int64_t a3 = 2097151 & (load_4(a + 7) >> 7);
|
||||
int64_t a4 = 2097151 & (load_4(a + 10) >> 4);
|
||||
int64_t a5 = 2097151 & (load_3(a + 13) >> 1);
|
||||
int64_t a6 = 2097151 & (load_4(a + 15) >> 6);
|
||||
int64_t a7 = 2097151 & (load_3(a + 18) >> 3);
|
||||
int64_t a8 = 2097151 & load_3(a + 21);
|
||||
int64_t a9 = 2097151 & (load_4(a + 23) >> 5);
|
||||
int64_t a10 = 2097151 & (load_3(a + 26) >> 2);
|
||||
int64_t a11 = (load_4(a + 28) >> 7);
|
||||
int64_t b0 = 2097151 & load_3(b);
|
||||
int64_t b1 = 2097151 & (load_4(b + 2) >> 5);
|
||||
int64_t b2 = 2097151 & (load_3(b + 5) >> 2);
|
||||
int64_t b3 = 2097151 & (load_4(b + 7) >> 7);
|
||||
int64_t b4 = 2097151 & (load_4(b + 10) >> 4);
|
||||
int64_t b5 = 2097151 & (load_3(b + 13) >> 1);
|
||||
int64_t b6 = 2097151 & (load_4(b + 15) >> 6);
|
||||
int64_t b7 = 2097151 & (load_3(b + 18) >> 3);
|
||||
int64_t b8 = 2097151 & load_3(b + 21);
|
||||
int64_t b9 = 2097151 & (load_4(b + 23) >> 5);
|
||||
int64_t b10 = 2097151 & (load_3(b + 26) >> 2);
|
||||
int64_t b11 = (load_4(b + 28) >> 7);
|
||||
int64_t s0;
|
||||
int64_t s1;
|
||||
int64_t s2;
|
||||
int64_t s3;
|
||||
int64_t s4;
|
||||
int64_t s5;
|
||||
int64_t s6;
|
||||
int64_t s7;
|
||||
int64_t s8;
|
||||
int64_t s9;
|
||||
int64_t s10;
|
||||
int64_t s11;
|
||||
int64_t s12;
|
||||
int64_t s13;
|
||||
int64_t s14;
|
||||
int64_t s15;
|
||||
int64_t s16;
|
||||
int64_t s17;
|
||||
int64_t s18;
|
||||
int64_t s19;
|
||||
int64_t s20;
|
||||
int64_t s21;
|
||||
int64_t s22;
|
||||
int64_t s23;
|
||||
int64_t carry0;
|
||||
int64_t carry1;
|
||||
int64_t carry2;
|
||||
int64_t carry3;
|
||||
int64_t carry4;
|
||||
int64_t carry5;
|
||||
int64_t carry6;
|
||||
int64_t carry7;
|
||||
int64_t carry8;
|
||||
int64_t carry9;
|
||||
int64_t carry10;
|
||||
int64_t carry11;
|
||||
int64_t carry12;
|
||||
int64_t carry13;
|
||||
int64_t carry14;
|
||||
int64_t carry15;
|
||||
int64_t carry16;
|
||||
int64_t carry17;
|
||||
int64_t carry18;
|
||||
int64_t carry19;
|
||||
int64_t carry20;
|
||||
int64_t carry21;
|
||||
int64_t carry22;
|
||||
|
||||
s0 = a0*b0;
|
||||
s1 = (a0*b1 + a1*b0);
|
||||
s2 = (a0*b2 + a1*b1 + a2*b0);
|
||||
s3 = (a0*b3 + a1*b2 + a2*b1 + a3*b0);
|
||||
s4 = (a0*b4 + a1*b3 + a2*b2 + a3*b1 + a4*b0);
|
||||
s5 = (a0*b5 + a1*b4 + a2*b3 + a3*b2 + a4*b1 + a5*b0);
|
||||
s6 = (a0*b6 + a1*b5 + a2*b4 + a3*b3 + a4*b2 + a5*b1 + a6*b0);
|
||||
s7 = (a0*b7 + a1*b6 + a2*b5 + a3*b4 + a4*b3 + a5*b2 + a6*b1 + a7*b0);
|
||||
s8 = (a0*b8 + a1*b7 + a2*b6 + a3*b5 + a4*b4 + a5*b3 + a6*b2 + a7*b1 + a8*b0);
|
||||
s9 = (a0*b9 + a1*b8 + a2*b7 + a3*b6 + a4*b5 + a5*b4 + a6*b3 + a7*b2 + a8*b1 + a9*b0);
|
||||
s10 = (a0*b10 + a1*b9 + a2*b8 + a3*b7 + a4*b6 + a5*b5 + a6*b4 + a7*b3 + a8*b2 + a9*b1 + a10*b0);
|
||||
s11 = (a0*b11 + a1*b10 + a2*b9 + a3*b8 + a4*b7 + a5*b6 + a6*b5 + a7*b4 + a8*b3 + a9*b2 + a10*b1 + a11*b0);
|
||||
s12 = (a1*b11 + a2*b10 + a3*b9 + a4*b8 + a5*b7 + a6*b6 + a7*b5 + a8*b4 + a9*b3 + a10*b2 + a11*b1);
|
||||
s13 = (a2*b11 + a3*b10 + a4*b9 + a5*b8 + a6*b7 + a7*b6 + a8*b5 + a9*b4 + a10*b3 + a11*b2);
|
||||
s14 = (a3*b11 + a4*b10 + a5*b9 + a6*b8 + a7*b7 + a8*b6 + a9*b5 + a10*b4 + a11*b3);
|
||||
s15 = (a4*b11 + a5*b10 + a6*b9 + a7*b8 + a8*b7 + a9*b6 + a10*b5 + a11*b4);
|
||||
s16 = (a5*b11 + a6*b10 + a7*b9 + a8*b8 + a9*b7 + a10*b6 + a11*b5);
|
||||
s17 = (a6*b11 + a7*b10 + a8*b9 + a9*b8 + a10*b7 + a11*b6);
|
||||
s18 = (a7*b11 + a8*b10 + a9*b9 + a10*b8 + a11*b7);
|
||||
s19 = (a8*b11 + a9*b10 + a10*b9 + a11*b8);
|
||||
s20 = (a9*b11 + a10*b10 + a11*b9);
|
||||
s21 = (a10*b11 + a11*b10);
|
||||
s22 = a11*b11;
|
||||
s23 = 0;
|
||||
|
||||
carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
|
||||
carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
|
||||
carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
|
||||
carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
|
||||
carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
|
||||
carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
|
||||
carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21;
|
||||
carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21;
|
||||
carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21;
|
||||
carry18 = (s18 + (1<<20)) >> 21; s19 += carry18; s18 -= carry18 << 21;
|
||||
carry20 = (s20 + (1<<20)) >> 21; s21 += carry20; s20 -= carry20 << 21;
|
||||
carry22 = (s22 + (1<<20)) >> 21; s23 += carry22; s22 -= carry22 << 21;
|
||||
|
||||
carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
|
||||
carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
|
||||
carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
|
||||
carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
|
||||
carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
|
||||
carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
|
||||
carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21;
|
||||
carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21;
|
||||
carry17 = (s17 + (1<<20)) >> 21; s18 += carry17; s17 -= carry17 << 21;
|
||||
carry19 = (s19 + (1<<20)) >> 21; s20 += carry19; s19 -= carry19 << 21;
|
||||
carry21 = (s21 + (1<<20)) >> 21; s22 += carry21; s21 -= carry21 << 21;
|
||||
|
||||
s11 += s23 * 666643;
|
||||
s12 += s23 * 470296;
|
||||
s13 += s23 * 654183;
|
||||
s14 -= s23 * 997805;
|
||||
s15 += s23 * 136657;
|
||||
s16 -= s23 * 683901;
|
||||
|
||||
s10 += s22 * 666643;
|
||||
s11 += s22 * 470296;
|
||||
s12 += s22 * 654183;
|
||||
s13 -= s22 * 997805;
|
||||
s14 += s22 * 136657;
|
||||
s15 -= s22 * 683901;
|
||||
|
||||
s9 += s21 * 666643;
|
||||
s10 += s21 * 470296;
|
||||
s11 += s21 * 654183;
|
||||
s12 -= s21 * 997805;
|
||||
s13 += s21 * 136657;
|
||||
s14 -= s21 * 683901;
|
||||
|
||||
s8 += s20 * 666643;
|
||||
s9 += s20 * 470296;
|
||||
s10 += s20 * 654183;
|
||||
s11 -= s20 * 997805;
|
||||
s12 += s20 * 136657;
|
||||
s13 -= s20 * 683901;
|
||||
|
||||
s7 += s19 * 666643;
|
||||
s8 += s19 * 470296;
|
||||
s9 += s19 * 654183;
|
||||
s10 -= s19 * 997805;
|
||||
s11 += s19 * 136657;
|
||||
s12 -= s19 * 683901;
|
||||
|
||||
s6 += s18 * 666643;
|
||||
s7 += s18 * 470296;
|
||||
s8 += s18 * 654183;
|
||||
s9 -= s18 * 997805;
|
||||
s10 += s18 * 136657;
|
||||
s11 -= s18 * 683901;
|
||||
|
||||
carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
|
||||
carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
|
||||
carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
|
||||
carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21;
|
||||
carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21;
|
||||
carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21;
|
||||
|
||||
carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
|
||||
carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
|
||||
carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
|
||||
carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21;
|
||||
carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21;
|
||||
|
||||
s5 += s17 * 666643;
|
||||
s6 += s17 * 470296;
|
||||
s7 += s17 * 654183;
|
||||
s8 -= s17 * 997805;
|
||||
s9 += s17 * 136657;
|
||||
s10 -= s17 * 683901;
|
||||
|
||||
s4 += s16 * 666643;
|
||||
s5 += s16 * 470296;
|
||||
s6 += s16 * 654183;
|
||||
s7 -= s16 * 997805;
|
||||
s8 += s16 * 136657;
|
||||
s9 -= s16 * 683901;
|
||||
|
||||
s3 += s15 * 666643;
|
||||
s4 += s15 * 470296;
|
||||
s5 += s15 * 654183;
|
||||
s6 -= s15 * 997805;
|
||||
s7 += s15 * 136657;
|
||||
s8 -= s15 * 683901;
|
||||
|
||||
s2 += s14 * 666643;
|
||||
s3 += s14 * 470296;
|
||||
s4 += s14 * 654183;
|
||||
s5 -= s14 * 997805;
|
||||
s6 += s14 * 136657;
|
||||
s7 -= s14 * 683901;
|
||||
|
||||
s1 += s13 * 666643;
|
||||
s2 += s13 * 470296;
|
||||
s3 += s13 * 654183;
|
||||
s4 -= s13 * 997805;
|
||||
s5 += s13 * 136657;
|
||||
s6 -= s13 * 683901;
|
||||
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
s12 = 0;
|
||||
|
||||
carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
|
||||
carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
|
||||
carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
|
||||
carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
|
||||
carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
|
||||
carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
|
||||
|
||||
carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
|
||||
carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
|
||||
carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
|
||||
carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
|
||||
carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
|
||||
carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
|
||||
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
s12 = 0;
|
||||
|
||||
carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
|
||||
carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
|
||||
carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
|
||||
carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
|
||||
carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
|
||||
carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
|
||||
carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
|
||||
carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
|
||||
carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
|
||||
carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
|
||||
carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
|
||||
carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21;
|
||||
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
|
||||
carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
|
||||
carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
|
||||
carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
|
||||
carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
|
||||
carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
|
||||
carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
|
||||
carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
|
||||
carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
|
||||
carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
|
||||
carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
|
||||
carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
|
||||
|
||||
s[0] = s0 >> 0;
|
||||
s[1] = s0 >> 8;
|
||||
s[2] = (s0 >> 16) | (s1 << 5);
|
||||
s[3] = s1 >> 3;
|
||||
s[4] = s1 >> 11;
|
||||
s[5] = (s1 >> 19) | (s2 << 2);
|
||||
s[6] = s2 >> 6;
|
||||
s[7] = (s2 >> 14) | (s3 << 7);
|
||||
s[8] = s3 >> 1;
|
||||
s[9] = s3 >> 9;
|
||||
s[10] = (s3 >> 17) | (s4 << 4);
|
||||
s[11] = s4 >> 4;
|
||||
s[12] = s4 >> 12;
|
||||
s[13] = (s4 >> 20) | (s5 << 1);
|
||||
s[14] = s5 >> 7;
|
||||
s[15] = (s5 >> 15) | (s6 << 6);
|
||||
s[16] = s6 >> 2;
|
||||
s[17] = s6 >> 10;
|
||||
s[18] = (s6 >> 18) | (s7 << 3);
|
||||
s[19] = s7 >> 5;
|
||||
s[20] = s7 >> 13;
|
||||
s[21] = s8 >> 0;
|
||||
s[22] = s8 >> 8;
|
||||
s[23] = (s8 >> 16) | (s9 << 5);
|
||||
s[24] = s9 >> 3;
|
||||
s[25] = s9 >> 11;
|
||||
s[26] = (s9 >> 19) | (s10 << 2);
|
||||
s[27] = s10 >> 6;
|
||||
s[28] = (s10 >> 14) | (s11 << 7);
|
||||
s[29] = s11 >> 1;
|
||||
s[30] = s11 >> 9;
|
||||
s[31] = s11 >> 17;
|
||||
}
|
||||
|
||||
//copied from above and modified
|
||||
/*
|
||||
Input:
|
||||
a[0]+256*a[1]+...+256^31*a[31] = a
|
||||
b[0]+256*b[1]+...+256^31*b[31] = b
|
||||
c[0]+256*c[1]+...+256^31*c[31] = c
|
||||
|
||||
Output:
|
||||
s[0]+256*s[1]+...+256^31*s[31] = (c+ab) mod l
|
||||
where l = 2^252 + 27742317777372353535851937790883648493.
|
||||
*/
|
||||
|
||||
void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b, const unsigned char *c) {
|
||||
int64_t a0 = 2097151 & load_3(a);
|
||||
int64_t a1 = 2097151 & (load_4(a + 2) >> 5);
|
||||
int64_t a2 = 2097151 & (load_3(a + 5) >> 2);
|
||||
int64_t a3 = 2097151 & (load_4(a + 7) >> 7);
|
||||
int64_t a4 = 2097151 & (load_4(a + 10) >> 4);
|
||||
int64_t a5 = 2097151 & (load_3(a + 13) >> 1);
|
||||
int64_t a6 = 2097151 & (load_4(a + 15) >> 6);
|
||||
int64_t a7 = 2097151 & (load_3(a + 18) >> 3);
|
||||
int64_t a8 = 2097151 & load_3(a + 21);
|
||||
int64_t a9 = 2097151 & (load_4(a + 23) >> 5);
|
||||
int64_t a10 = 2097151 & (load_3(a + 26) >> 2);
|
||||
int64_t a11 = (load_4(a + 28) >> 7);
|
||||
int64_t b0 = 2097151 & load_3(b);
|
||||
int64_t b1 = 2097151 & (load_4(b + 2) >> 5);
|
||||
int64_t b2 = 2097151 & (load_3(b + 5) >> 2);
|
||||
int64_t b3 = 2097151 & (load_4(b + 7) >> 7);
|
||||
int64_t b4 = 2097151 & (load_4(b + 10) >> 4);
|
||||
int64_t b5 = 2097151 & (load_3(b + 13) >> 1);
|
||||
int64_t b6 = 2097151 & (load_4(b + 15) >> 6);
|
||||
int64_t b7 = 2097151 & (load_3(b + 18) >> 3);
|
||||
int64_t b8 = 2097151 & load_3(b + 21);
|
||||
int64_t b9 = 2097151 & (load_4(b + 23) >> 5);
|
||||
int64_t b10 = 2097151 & (load_3(b + 26) >> 2);
|
||||
int64_t b11 = (load_4(b + 28) >> 7);
|
||||
int64_t c0 = 2097151 & load_3(c);
|
||||
int64_t c1 = 2097151 & (load_4(c + 2) >> 5);
|
||||
int64_t c2 = 2097151 & (load_3(c + 5) >> 2);
|
||||
int64_t c3 = 2097151 & (load_4(c + 7) >> 7);
|
||||
int64_t c4 = 2097151 & (load_4(c + 10) >> 4);
|
||||
int64_t c5 = 2097151 & (load_3(c + 13) >> 1);
|
||||
int64_t c6 = 2097151 & (load_4(c + 15) >> 6);
|
||||
int64_t c7 = 2097151 & (load_3(c + 18) >> 3);
|
||||
int64_t c8 = 2097151 & load_3(c + 21);
|
||||
int64_t c9 = 2097151 & (load_4(c + 23) >> 5);
|
||||
int64_t c10 = 2097151 & (load_3(c + 26) >> 2);
|
||||
int64_t c11 = (load_4(c + 28) >> 7);
|
||||
int64_t s0;
|
||||
int64_t s1;
|
||||
int64_t s2;
|
||||
int64_t s3;
|
||||
int64_t s4;
|
||||
int64_t s5;
|
||||
int64_t s6;
|
||||
int64_t s7;
|
||||
int64_t s8;
|
||||
int64_t s9;
|
||||
int64_t s10;
|
||||
int64_t s11;
|
||||
int64_t s12;
|
||||
int64_t s13;
|
||||
int64_t s14;
|
||||
int64_t s15;
|
||||
int64_t s16;
|
||||
int64_t s17;
|
||||
int64_t s18;
|
||||
int64_t s19;
|
||||
int64_t s20;
|
||||
int64_t s21;
|
||||
int64_t s22;
|
||||
int64_t s23;
|
||||
int64_t carry0;
|
||||
int64_t carry1;
|
||||
int64_t carry2;
|
||||
int64_t carry3;
|
||||
int64_t carry4;
|
||||
int64_t carry5;
|
||||
int64_t carry6;
|
||||
int64_t carry7;
|
||||
int64_t carry8;
|
||||
int64_t carry9;
|
||||
int64_t carry10;
|
||||
int64_t carry11;
|
||||
int64_t carry12;
|
||||
int64_t carry13;
|
||||
int64_t carry14;
|
||||
int64_t carry15;
|
||||
int64_t carry16;
|
||||
int64_t carry17;
|
||||
int64_t carry18;
|
||||
int64_t carry19;
|
||||
int64_t carry20;
|
||||
int64_t carry21;
|
||||
int64_t carry22;
|
||||
|
||||
s0 = c0 + a0*b0;
|
||||
s1 = c1 + (a0*b1 + a1*b0);
|
||||
s2 = c2 + (a0*b2 + a1*b1 + a2*b0);
|
||||
s3 = c3 + (a0*b3 + a1*b2 + a2*b1 + a3*b0);
|
||||
s4 = c4 + (a0*b4 + a1*b3 + a2*b2 + a3*b1 + a4*b0);
|
||||
s5 = c5 + (a0*b5 + a1*b4 + a2*b3 + a3*b2 + a4*b1 + a5*b0);
|
||||
s6 = c6 + (a0*b6 + a1*b5 + a2*b4 + a3*b3 + a4*b2 + a5*b1 + a6*b0);
|
||||
s7 = c7 + (a0*b7 + a1*b6 + a2*b5 + a3*b4 + a4*b3 + a5*b2 + a6*b1 + a7*b0);
|
||||
s8 = c8 + (a0*b8 + a1*b7 + a2*b6 + a3*b5 + a4*b4 + a5*b3 + a6*b2 + a7*b1 + a8*b0);
|
||||
s9 = c9 + (a0*b9 + a1*b8 + a2*b7 + a3*b6 + a4*b5 + a5*b4 + a6*b3 + a7*b2 + a8*b1 + a9*b0);
|
||||
s10 = c10 + (a0*b10 + a1*b9 + a2*b8 + a3*b7 + a4*b6 + a5*b5 + a6*b4 + a7*b3 + a8*b2 + a9*b1 + a10*b0);
|
||||
s11 = c11 + (a0*b11 + a1*b10 + a2*b9 + a3*b8 + a4*b7 + a5*b6 + a6*b5 + a7*b4 + a8*b3 + a9*b2 + a10*b1 + a11*b0);
|
||||
s12 = (a1*b11 + a2*b10 + a3*b9 + a4*b8 + a5*b7 + a6*b6 + a7*b5 + a8*b4 + a9*b3 + a10*b2 + a11*b1);
|
||||
s13 = (a2*b11 + a3*b10 + a4*b9 + a5*b8 + a6*b7 + a7*b6 + a8*b5 + a9*b4 + a10*b3 + a11*b2);
|
||||
s14 = (a3*b11 + a4*b10 + a5*b9 + a6*b8 + a7*b7 + a8*b6 + a9*b5 + a10*b4 + a11*b3);
|
||||
s15 = (a4*b11 + a5*b10 + a6*b9 + a7*b8 + a8*b7 + a9*b6 + a10*b5 + a11*b4);
|
||||
s16 = (a5*b11 + a6*b10 + a7*b9 + a8*b8 + a9*b7 + a10*b6 + a11*b5);
|
||||
s17 = (a6*b11 + a7*b10 + a8*b9 + a9*b8 + a10*b7 + a11*b6);
|
||||
s18 = (a7*b11 + a8*b10 + a9*b9 + a10*b8 + a11*b7);
|
||||
s19 = (a8*b11 + a9*b10 + a10*b9 + a11*b8);
|
||||
s20 = (a9*b11 + a10*b10 + a11*b9);
|
||||
s21 = (a10*b11 + a11*b10);
|
||||
s22 = a11*b11;
|
||||
s23 = 0;
|
||||
|
||||
carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
|
||||
carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
|
||||
carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
|
||||
carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
|
||||
carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
|
||||
carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
|
||||
carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21;
|
||||
carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21;
|
||||
carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21;
|
||||
carry18 = (s18 + (1<<20)) >> 21; s19 += carry18; s18 -= carry18 << 21;
|
||||
carry20 = (s20 + (1<<20)) >> 21; s21 += carry20; s20 -= carry20 << 21;
|
||||
carry22 = (s22 + (1<<20)) >> 21; s23 += carry22; s22 -= carry22 << 21;
|
||||
|
||||
carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
|
||||
carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
|
||||
carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
|
||||
carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
|
||||
carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
|
||||
carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
|
||||
carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21;
|
||||
carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21;
|
||||
carry17 = (s17 + (1<<20)) >> 21; s18 += carry17; s17 -= carry17 << 21;
|
||||
carry19 = (s19 + (1<<20)) >> 21; s20 += carry19; s19 -= carry19 << 21;
|
||||
carry21 = (s21 + (1<<20)) >> 21; s22 += carry21; s21 -= carry21 << 21;
|
||||
|
||||
s11 += s23 * 666643;
|
||||
s12 += s23 * 470296;
|
||||
s13 += s23 * 654183;
|
||||
s14 -= s23 * 997805;
|
||||
s15 += s23 * 136657;
|
||||
s16 -= s23 * 683901;
|
||||
|
||||
s10 += s22 * 666643;
|
||||
s11 += s22 * 470296;
|
||||
s12 += s22 * 654183;
|
||||
s13 -= s22 * 997805;
|
||||
s14 += s22 * 136657;
|
||||
s15 -= s22 * 683901;
|
||||
|
||||
s9 += s21 * 666643;
|
||||
s10 += s21 * 470296;
|
||||
s11 += s21 * 654183;
|
||||
s12 -= s21 * 997805;
|
||||
s13 += s21 * 136657;
|
||||
s14 -= s21 * 683901;
|
||||
|
||||
s8 += s20 * 666643;
|
||||
s9 += s20 * 470296;
|
||||
s10 += s20 * 654183;
|
||||
s11 -= s20 * 997805;
|
||||
s12 += s20 * 136657;
|
||||
s13 -= s20 * 683901;
|
||||
|
||||
s7 += s19 * 666643;
|
||||
s8 += s19 * 470296;
|
||||
s9 += s19 * 654183;
|
||||
s10 -= s19 * 997805;
|
||||
s11 += s19 * 136657;
|
||||
s12 -= s19 * 683901;
|
||||
|
||||
s6 += s18 * 666643;
|
||||
s7 += s18 * 470296;
|
||||
s8 += s18 * 654183;
|
||||
s9 -= s18 * 997805;
|
||||
s10 += s18 * 136657;
|
||||
s11 -= s18 * 683901;
|
||||
|
||||
carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
|
||||
carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
|
||||
carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
|
||||
carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21;
|
||||
carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21;
|
||||
carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21;
|
||||
|
||||
carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
|
||||
carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
|
||||
carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
|
||||
carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21;
|
||||
carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21;
|
||||
|
||||
s5 += s17 * 666643;
|
||||
s6 += s17 * 470296;
|
||||
s7 += s17 * 654183;
|
||||
s8 -= s17 * 997805;
|
||||
s9 += s17 * 136657;
|
||||
s10 -= s17 * 683901;
|
||||
|
||||
s4 += s16 * 666643;
|
||||
s5 += s16 * 470296;
|
||||
s6 += s16 * 654183;
|
||||
s7 -= s16 * 997805;
|
||||
s8 += s16 * 136657;
|
||||
s9 -= s16 * 683901;
|
||||
|
||||
s3 += s15 * 666643;
|
||||
s4 += s15 * 470296;
|
||||
s5 += s15 * 654183;
|
||||
s6 -= s15 * 997805;
|
||||
s7 += s15 * 136657;
|
||||
s8 -= s15 * 683901;
|
||||
|
||||
s2 += s14 * 666643;
|
||||
s3 += s14 * 470296;
|
||||
s4 += s14 * 654183;
|
||||
s5 -= s14 * 997805;
|
||||
s6 += s14 * 136657;
|
||||
s7 -= s14 * 683901;
|
||||
|
||||
s1 += s13 * 666643;
|
||||
s2 += s13 * 470296;
|
||||
s3 += s13 * 654183;
|
||||
s4 -= s13 * 997805;
|
||||
s5 += s13 * 136657;
|
||||
s6 -= s13 * 683901;
|
||||
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
s12 = 0;
|
||||
|
||||
carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
|
||||
carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
|
||||
carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
|
||||
carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
|
||||
carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
|
||||
carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
|
||||
|
||||
carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
|
||||
carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
|
||||
carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
|
||||
carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
|
||||
carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
|
||||
carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
|
||||
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
s12 = 0;
|
||||
|
||||
carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
|
||||
carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
|
||||
carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
|
||||
carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
|
||||
carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
|
||||
carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
|
||||
carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
|
||||
carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
|
||||
carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
|
||||
carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
|
||||
carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
|
||||
carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21;
|
||||
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
|
||||
carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
|
||||
carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
|
||||
carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
|
||||
carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
|
||||
carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
|
||||
carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
|
||||
carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
|
||||
carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
|
||||
carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
|
||||
carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
|
||||
carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
|
||||
|
||||
s[0] = s0 >> 0;
|
||||
s[1] = s0 >> 8;
|
||||
s[2] = (s0 >> 16) | (s1 << 5);
|
||||
s[3] = s1 >> 3;
|
||||
s[4] = s1 >> 11;
|
||||
s[5] = (s1 >> 19) | (s2 << 2);
|
||||
s[6] = s2 >> 6;
|
||||
s[7] = (s2 >> 14) | (s3 << 7);
|
||||
s[8] = s3 >> 1;
|
||||
s[9] = s3 >> 9;
|
||||
s[10] = (s3 >> 17) | (s4 << 4);
|
||||
s[11] = s4 >> 4;
|
||||
s[12] = s4 >> 12;
|
||||
s[13] = (s4 >> 20) | (s5 << 1);
|
||||
s[14] = s5 >> 7;
|
||||
s[15] = (s5 >> 15) | (s6 << 6);
|
||||
s[16] = s6 >> 2;
|
||||
s[17] = s6 >> 10;
|
||||
s[18] = (s6 >> 18) | (s7 << 3);
|
||||
s[19] = s7 >> 5;
|
||||
s[20] = s7 >> 13;
|
||||
s[21] = s8 >> 0;
|
||||
s[22] = s8 >> 8;
|
||||
s[23] = (s8 >> 16) | (s9 << 5);
|
||||
s[24] = s9 >> 3;
|
||||
s[25] = s9 >> 11;
|
||||
s[26] = (s9 >> 19) | (s10 << 2);
|
||||
s[27] = s10 >> 6;
|
||||
s[28] = (s10 >> 14) | (s11 << 7);
|
||||
s[29] = s11 >> 1;
|
||||
s[30] = s11 >> 9;
|
||||
s[31] = s11 >> 17;
|
||||
}
|
||||
|
||||
/* Assumes that a != INT64_MIN */
|
||||
static int64_t signum(int64_t a) {
|
||||
return (a >> 63) - ((-a) >> 63);
|
||||
|
@ -128,6 +128,7 @@ void sc_reduce(unsigned char *);
|
||||
|
||||
void ge_scalarmult(ge_p2 *, const unsigned char *, const ge_p3 *);
|
||||
void ge_double_scalarmult_precomp_vartime(ge_p2 *, const unsigned char *, const ge_p3 *, const unsigned char *, const ge_dsmp);
|
||||
void ge_double_scalarmult_precomp_vartime2(ge_p2 *, const unsigned char *, const ge_dsmp, const unsigned char *, const ge_dsmp);
|
||||
void ge_mul8(ge_p1p1 *, const ge_p2 *);
|
||||
extern const fe fe_ma2;
|
||||
extern const fe fe_ma;
|
||||
@ -141,6 +142,8 @@ void sc_reduce32(unsigned char *);
|
||||
void sc_add(unsigned char *, const unsigned char *, const unsigned char *);
|
||||
void sc_sub(unsigned char *, const unsigned char *, const unsigned char *);
|
||||
void sc_mulsub(unsigned char *, const unsigned char *, const unsigned char *, const unsigned char *);
|
||||
void sc_mul(unsigned char *, const unsigned char *, const unsigned char *);
|
||||
void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b, const unsigned char *c);
|
||||
int sc_check(const unsigned char *);
|
||||
int sc_isnonzero(const unsigned char *); /* Doesn't normalize */
|
||||
|
||||
|
@ -211,6 +211,23 @@ namespace boost
|
||||
a & x.Ci;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, rct::Bulletproof &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.V;
|
||||
a & x.A;
|
||||
a & x.S;
|
||||
a & x.T1;
|
||||
a & x.T2;
|
||||
a & x.taux;
|
||||
a & x.mu;
|
||||
a & x.L;
|
||||
a & x.R;
|
||||
a & x.a;
|
||||
a & x.b;
|
||||
a & x.t;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, rct::boroSig &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
@ -263,11 +280,11 @@ namespace boost
|
||||
a & x.type;
|
||||
if (x.type == rct::RCTTypeNull)
|
||||
return;
|
||||
if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple)
|
||||
if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeFullBulletproof && x.type != rct::RCTTypeSimple && x.type != rct::RCTTypeSimpleBulletproof)
|
||||
throw boost::archive::archive_exception(boost::archive::archive_exception::other_exception, "Unsupported rct type");
|
||||
// a & x.message; message is not serialized, as it can be reconstructed from the tx data
|
||||
// a & x.mixRing; mixRing is not serialized, as it can be reconstructed from the offsets
|
||||
if (x.type == rct::RCTTypeSimple)
|
||||
if (x.type == rct::RCTTypeSimple || x.type == rct::RCTTypeSimpleBulletproof)
|
||||
a & x.pseudoOuts;
|
||||
a & x.ecdhInfo;
|
||||
serializeOutPk(a, x.outPk, ver);
|
||||
@ -278,6 +295,8 @@ namespace boost
|
||||
inline void serialize(Archive &a, rct::rctSigPrunable &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.rangeSigs;
|
||||
if (x.rangeSigs.empty())
|
||||
a & x.bulletproofs;
|
||||
a & x.MGs;
|
||||
}
|
||||
|
||||
@ -287,17 +306,19 @@ namespace boost
|
||||
a & x.type;
|
||||
if (x.type == rct::RCTTypeNull)
|
||||
return;
|
||||
if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple)
|
||||
if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeFullBulletproof && x.type != rct::RCTTypeSimple && x.type != rct::RCTTypeSimpleBulletproof)
|
||||
throw boost::archive::archive_exception(boost::archive::archive_exception::other_exception, "Unsupported rct type");
|
||||
// a & x.message; message is not serialized, as it can be reconstructed from the tx data
|
||||
// a & x.mixRing; mixRing is not serialized, as it can be reconstructed from the offsets
|
||||
if (x.type == rct::RCTTypeSimple)
|
||||
if (x.type == rct::RCTTypeSimple || x.type == rct::RCTTypeSimpleBulletproof)
|
||||
a & x.pseudoOuts;
|
||||
a & x.ecdhInfo;
|
||||
serializeOutPk(a, x.outPk, ver);
|
||||
a & x.txnFee;
|
||||
//--------------
|
||||
a & x.p.rangeSigs;
|
||||
if (x.p.rangeSigs.empty())
|
||||
a & x.p.bulletproofs;
|
||||
a & x.p.MGs;
|
||||
}
|
||||
}
|
||||
|
@ -127,6 +127,7 @@ static const struct {
|
||||
{ 5, 802660, 0, 1472415036 + 86400*180 }, // add 5 months on testnet to shut the update warning up since there's a large gap to v6
|
||||
|
||||
{ 6, 971400, 0, 1501709789 },
|
||||
{ 7, 1057028, 0, 1512211236 },
|
||||
};
|
||||
static const uint64_t testnet_hard_fork_version_1_till = 624633;
|
||||
|
||||
@ -2387,8 +2388,10 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
|
||||
LOG_PRINT_L3("Blockchain::" << __func__);
|
||||
CRITICAL_REGION_LOCAL(m_blockchain_lock);
|
||||
|
||||
const uint8_t hf_version = m_hardfork->get_current_version();
|
||||
|
||||
// from hard fork 2, we forbid dust and compound outputs
|
||||
if (m_hardfork->get_current_version() >= 2) {
|
||||
if (hf_version >= 2) {
|
||||
for (auto &o: tx.vout) {
|
||||
if (tx.version == 1)
|
||||
{
|
||||
@ -2401,7 +2404,7 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
|
||||
}
|
||||
|
||||
// in a v2 tx, all outputs must have 0 amount
|
||||
if (m_hardfork->get_current_version() >= 3) {
|
||||
if (hf_version >= 3) {
|
||||
if (tx.version >= 2) {
|
||||
for (auto &o: tx.vout) {
|
||||
if (o.amount != 0) {
|
||||
@ -2413,7 +2416,7 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
|
||||
}
|
||||
|
||||
// from v4, forbid invalid pubkeys
|
||||
if (m_hardfork->get_current_version() >= 4) {
|
||||
if (hf_version >= 4) {
|
||||
for (const auto &o: tx.vout) {
|
||||
if (o.target.type() == typeid(txout_to_key)) {
|
||||
const txout_to_key& out_to_key = boost::get<txout_to_key>(o.target);
|
||||
@ -2425,6 +2428,16 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
|
||||
}
|
||||
}
|
||||
|
||||
// from v7, allow bulletproofs
|
||||
if (hf_version < 7 || !m_testnet) {
|
||||
if (!tx.rct_signatures.p.bulletproofs.empty())
|
||||
{
|
||||
MERROR("Bulletproofs are not allowed before v7 or on mainnet");
|
||||
tvc.m_invalid_output = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
@ -2450,7 +2463,7 @@ bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_pr
|
||||
rv.message = rct::hash2rct(tx_prefix_hash);
|
||||
|
||||
// mixRing - full and simple store it in opposite ways
|
||||
if (rv.type == rct::RCTTypeFull)
|
||||
if (rv.type == rct::RCTTypeFull || rv.type == rct::RCTTypeFullBulletproof)
|
||||
{
|
||||
rv.mixRing.resize(pubkeys[0].size());
|
||||
for (size_t m = 0; m < pubkeys[0].size(); ++m)
|
||||
@ -2464,7 +2477,7 @@ bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_pr
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (rv.type == rct::RCTTypeSimple)
|
||||
else if (rv.type == rct::RCTTypeSimple || rv.type == rct::RCTTypeSimpleBulletproof)
|
||||
{
|
||||
rv.mixRing.resize(pubkeys.size());
|
||||
for (size_t n = 0; n < pubkeys.size(); ++n)
|
||||
@ -2482,14 +2495,14 @@ bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_pr
|
||||
}
|
||||
|
||||
// II
|
||||
if (rv.type == rct::RCTTypeFull)
|
||||
if (rv.type == rct::RCTTypeFull || rv.type == rct::RCTTypeFullBulletproof)
|
||||
{
|
||||
rv.p.MGs.resize(1);
|
||||
rv.p.MGs[0].II.resize(tx.vin.size());
|
||||
for (size_t n = 0; n < tx.vin.size(); ++n)
|
||||
rv.p.MGs[0].II[n] = rct::ki2rct(boost::get<txin_to_key>(tx.vin[n]).k_image);
|
||||
}
|
||||
else if (rv.type == rct::RCTTypeSimple)
|
||||
else if (rv.type == rct::RCTTypeSimple || rv.type == rct::RCTTypeSimpleBulletproof)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(rv.p.MGs.size() == tx.vin.size(), false, "Bad MGs size");
|
||||
for (size_t n = 0; n < tx.vin.size(); ++n)
|
||||
@ -2753,7 +2766,9 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
|
||||
MERROR_VER("Null rct signature on non-coinbase tx");
|
||||
return false;
|
||||
}
|
||||
case rct::RCTTypeSimple: {
|
||||
case rct::RCTTypeSimple:
|
||||
case rct::RCTTypeSimpleBulletproof:
|
||||
{
|
||||
// check all this, either recontructed (so should really pass), or not
|
||||
{
|
||||
if (pubkeys.size() != rv.mixRing.size())
|
||||
@ -2809,7 +2824,9 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
|
||||
}
|
||||
break;
|
||||
}
|
||||
case rct::RCTTypeFull: {
|
||||
case rct::RCTTypeFull:
|
||||
case rct::RCTTypeFullBulletproof:
|
||||
{
|
||||
// check all this, either recontructed (so should really pass), or not
|
||||
{
|
||||
bool size_matches = true;
|
||||
|
@ -625,6 +625,22 @@ namespace cryptonote
|
||||
}
|
||||
for (size_t n = 0; n < tx.rct_signatures.outPk.size(); ++n)
|
||||
rv.outPk[n].dest = rct::pk2rct(boost::get<txout_to_key>(tx.vout[n].target).key);
|
||||
|
||||
const bool bulletproof = rv.type == rct::RCTTypeFullBulletproof || rv.type == rct::RCTTypeSimpleBulletproof;
|
||||
if (bulletproof)
|
||||
{
|
||||
if (rv.p.bulletproofs.size() != tx.vout.size())
|
||||
{
|
||||
LOG_PRINT_L1("WRONG TRANSACTION BLOB, Bad bulletproofs size in tx " << tx_hash << ", rejected");
|
||||
tvc.m_verifivation_failed = true;
|
||||
return false;
|
||||
}
|
||||
for (size_t n = 0; n < rv.outPk.size(); ++n)
|
||||
{
|
||||
rv.p.bulletproofs[n].V.resize(1);
|
||||
rv.p.bulletproofs[n].V[0] = rv.outPk[n].mask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (keeped_by_block && get_blockchain_storage().is_within_compiled_block_hash_area())
|
||||
@ -828,6 +844,7 @@ namespace cryptonote
|
||||
MERROR_VER("Unexpected Null rctSig type");
|
||||
return false;
|
||||
case rct::RCTTypeSimple:
|
||||
case rct::RCTTypeSimpleBulletproof:
|
||||
if (!rct::verRctSimple(rv, true))
|
||||
{
|
||||
MERROR_VER("rct signature semantics check failed");
|
||||
@ -835,6 +852,7 @@ namespace cryptonote
|
||||
}
|
||||
break;
|
||||
case rct::RCTTypeFull:
|
||||
case rct::RCTTypeFullBulletproof:
|
||||
if (!rct::verRct(rv, true))
|
||||
{
|
||||
MERROR_VER("rct signature semantics check failed");
|
||||
|
@ -160,7 +160,7 @@ namespace cryptonote
|
||||
return destinations[0].addr.m_view_public_key;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys, bool rct)
|
||||
bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys, bool rct, bool bulletproof)
|
||||
{
|
||||
std::vector<rct::key> amount_keys;
|
||||
tx.set_null();
|
||||
@ -552,9 +552,9 @@ namespace cryptonote
|
||||
get_transaction_prefix_hash(tx, tx_prefix_hash);
|
||||
rct::ctkeyV outSk;
|
||||
if (use_simple_rct)
|
||||
tx.rct_signatures = rct::genRctSimple(rct::hash2rct(tx_prefix_hash), inSk, destinations, inamounts, outamounts, amount_in - amount_out, mixRing, amount_keys, index, outSk);
|
||||
tx.rct_signatures = rct::genRctSimple(rct::hash2rct(tx_prefix_hash), inSk, destinations, inamounts, outamounts, amount_in - amount_out, mixRing, amount_keys, index, outSk, bulletproof);
|
||||
else
|
||||
tx.rct_signatures = rct::genRct(rct::hash2rct(tx_prefix_hash), inSk, destinations, outamounts, mixRing, amount_keys, sources[0].real_output, outSk); // same index assumption
|
||||
tx.rct_signatures = rct::genRct(rct::hash2rct(tx_prefix_hash), inSk, destinations, outamounts, mixRing, amount_keys, sources[0].real_output, outSk, bulletproof); // same index assumption
|
||||
|
||||
CHECK_AND_ASSERT_MES(tx.vout.size() == outSk.size(), false, "outSk size does not match vout");
|
||||
|
||||
|
@ -88,7 +88,7 @@ namespace cryptonote
|
||||
//---------------------------------------------------------------
|
||||
crypto::public_key get_destination_view_key_pub(const std::vector<tx_destination_entry> &destinations, const account_keys &sender_keys);
|
||||
bool construct_tx(const account_keys& sender_account_keys, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time);
|
||||
bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys, bool rct = false);
|
||||
bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys, bool rct = false, bool bulletproof = false);
|
||||
|
||||
bool generate_genesis_block(
|
||||
block& bl
|
||||
|
@ -30,14 +30,16 @@ set(ringct_sources
|
||||
rctOps.cpp
|
||||
rctSigs.cpp
|
||||
rctTypes.cpp
|
||||
rctCryptoOps.c)
|
||||
rctCryptoOps.c
|
||||
bulletproofs.cc)
|
||||
|
||||
set(ringct_headers)
|
||||
|
||||
set(ringct_private_headers
|
||||
rctOps.h
|
||||
rctSigs.h
|
||||
rctTypes.h)
|
||||
rctTypes.h
|
||||
bulletproofs.h)
|
||||
|
||||
monero_private_headers(ringct
|
||||
${crypto_private_headers})
|
||||
@ -51,4 +53,5 @@ target_link_libraries(ringct
|
||||
cncrypto
|
||||
cryptonote_basic
|
||||
PRIVATE
|
||||
${OPENSSL_LIBRARIES}
|
||||
${EXTRA_LIBRARIES})
|
||||
|
761
src/ringct/bulletproofs.cc
Normal file
761
src/ringct/bulletproofs.cc
Normal file
@ -0,0 +1,761 @@
|
||||
// Copyright (c) 2017, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Adapted from Java code by Sarang Noether
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include "misc_log_ex.h"
|
||||
#include "common/perf_timer.h"
|
||||
extern "C"
|
||||
{
|
||||
#include "crypto/crypto-ops.h"
|
||||
}
|
||||
#include "rctOps.h"
|
||||
#include "bulletproofs.h"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "bulletproofs"
|
||||
|
||||
//#define DEBUG_BP
|
||||
|
||||
#define PERF_TIMER_START_BP(x) PERF_TIMER_START_UNIT(x, 1000000)
|
||||
|
||||
namespace rct
|
||||
{
|
||||
|
||||
static rct::key vector_exponent(const rct::keyV &a, const rct::keyV &b);
|
||||
static rct::keyV vector_powers(rct::key x, size_t n);
|
||||
static rct::key inner_product(const rct::keyV &a, const rct::keyV &b);
|
||||
|
||||
static constexpr size_t maxN = 64;
|
||||
static rct::key Hi[maxN], Gi[maxN];
|
||||
static ge_dsmp Gprecomp[64], Hprecomp[64];
|
||||
static const rct::key TWO = { {0x02, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 } };
|
||||
static const rct::keyV oneN = vector_powers(rct::identity(), maxN);
|
||||
static const rct::keyV twoN = vector_powers(TWO, maxN);
|
||||
static const rct::key ip12 = inner_product(oneN, twoN);
|
||||
static boost::mutex init_mutex;
|
||||
|
||||
static rct::key get_exponent(const rct::key &base, size_t idx)
|
||||
{
|
||||
static const std::string salt("bulletproof");
|
||||
std::string hashed = std::string((const char*)base.bytes, sizeof(base)) + salt + tools::get_varint_data(idx);
|
||||
return rct::hashToPoint(rct::hash2rct(crypto::cn_fast_hash(hashed.data(), hashed.size())));
|
||||
}
|
||||
|
||||
static void init_exponents()
|
||||
{
|
||||
boost::lock_guard<boost::mutex> lock(init_mutex);
|
||||
|
||||
static bool init_done = false;
|
||||
if (init_done)
|
||||
return;
|
||||
for (size_t i = 0; i < maxN; ++i)
|
||||
{
|
||||
Hi[i] = get_exponent(rct::H, i * 2);
|
||||
rct::precomp(Hprecomp[i], Hi[i]);
|
||||
Gi[i] = get_exponent(rct::H, i * 2 + 1);
|
||||
rct::precomp(Gprecomp[i], Gi[i]);
|
||||
}
|
||||
init_done = true;
|
||||
}
|
||||
|
||||
/* Given two scalar arrays, construct a vector commitment */
|
||||
static rct::key vector_exponent(const rct::keyV &a, const rct::keyV &b)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(a.size() == b.size(), "Incompatible sizes of a and b");
|
||||
CHECK_AND_ASSERT_THROW_MES(a.size() <= maxN, "Incompatible sizes of a and maxN");
|
||||
rct::key res = rct::identity();
|
||||
for (size_t i = 0; i < a.size(); ++i)
|
||||
{
|
||||
rct::key term;
|
||||
rct::addKeys3(term, a[i], Gprecomp[i], b[i], Hprecomp[i]);
|
||||
rct::addKeys(res, res, term);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Compute a custom vector-scalar commitment */
|
||||
static rct::key vector_exponent_custom(const rct::keyV &A, const rct::keyV &B, const rct::keyV &a, const rct::keyV &b)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(A.size() == B.size(), "Incompatible sizes of A and B");
|
||||
CHECK_AND_ASSERT_THROW_MES(a.size() == b.size(), "Incompatible sizes of a and b");
|
||||
CHECK_AND_ASSERT_THROW_MES(a.size() == A.size(), "Incompatible sizes of a and A");
|
||||
CHECK_AND_ASSERT_THROW_MES(a.size() <= maxN, "Incompatible sizes of a and maxN");
|
||||
rct::key res = rct::identity();
|
||||
for (size_t i = 0; i < a.size(); ++i)
|
||||
{
|
||||
rct::key term;
|
||||
#if 0
|
||||
// we happen to know where A and B might fall, so don't bother checking the rest
|
||||
ge_dsmp *Acache = NULL, *Bcache = NULL;
|
||||
ge_dsmp Acache_custom[1], Bcache_custom[1];
|
||||
if (Gi[i] == A[i])
|
||||
Acache = Gprecomp + i;
|
||||
else if (i<32 && Gi[i+32] == A[i])
|
||||
Acache = Gprecomp + i + 32;
|
||||
else
|
||||
{
|
||||
rct::precomp(Acache_custom[0], A[i]);
|
||||
Acache = Acache_custom;
|
||||
}
|
||||
if (i == 0 && B[i] == Hi[0])
|
||||
Bcache = Hprecomp;
|
||||
else
|
||||
{
|
||||
rct::precomp(Bcache_custom[0], B[i]);
|
||||
Bcache = Bcache_custom;
|
||||
}
|
||||
rct::addKeys3(term, a[i], *Acache, b[i], *Bcache);
|
||||
#else
|
||||
ge_dsmp Acache, Bcache;
|
||||
rct::precomp(Bcache, B[i]);
|
||||
rct::addKeys3(term, a[i], A[i], b[i], Bcache);
|
||||
#endif
|
||||
rct::addKeys(res, res, term);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Given a scalar, construct a vector of powers */
|
||||
static rct::keyV vector_powers(rct::key x, size_t n)
|
||||
{
|
||||
rct::keyV res(n);
|
||||
if (n == 0)
|
||||
return res;
|
||||
res[0] = rct::identity();
|
||||
if (n == 1)
|
||||
return res;
|
||||
res[1] = x;
|
||||
for (size_t i = 2; i < n; ++i)
|
||||
{
|
||||
sc_mul(res[i].bytes, res[i-1].bytes, x.bytes);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Given two scalar arrays, construct the inner product */
|
||||
static rct::key inner_product(const rct::keyV &a, const rct::keyV &b)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(a.size() == b.size(), "Incompatible sizes of a and b");
|
||||
rct::key res = rct::zero();
|
||||
for (size_t i = 0; i < a.size(); ++i)
|
||||
{
|
||||
sc_muladd(res.bytes, a[i].bytes, b[i].bytes, res.bytes);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Given two scalar arrays, construct the Hadamard product */
|
||||
static rct::keyV hadamard(const rct::keyV &a, const rct::keyV &b)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(a.size() == b.size(), "Incompatible sizes of a and b");
|
||||
rct::keyV res(a.size());
|
||||
for (size_t i = 0; i < a.size(); ++i)
|
||||
{
|
||||
sc_mul(res[i].bytes, a[i].bytes, b[i].bytes);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Given two curvepoint arrays, construct the Hadamard product */
|
||||
static rct::keyV hadamard2(const rct::keyV &a, const rct::keyV &b)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(a.size() == b.size(), "Incompatible sizes of a and b");
|
||||
rct::keyV res(a.size());
|
||||
for (size_t i = 0; i < a.size(); ++i)
|
||||
{
|
||||
rct::addKeys(res[i], a[i], b[i]);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Add two vectors */
|
||||
static rct::keyV vector_add(const rct::keyV &a, const rct::keyV &b)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(a.size() == b.size(), "Incompatible sizes of a and b");
|
||||
rct::keyV res(a.size());
|
||||
for (size_t i = 0; i < a.size(); ++i)
|
||||
{
|
||||
sc_add(res[i].bytes, a[i].bytes, b[i].bytes);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Subtract two vectors */
|
||||
static rct::keyV vector_subtract(const rct::keyV &a, const rct::keyV &b)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(a.size() == b.size(), "Incompatible sizes of a and b");
|
||||
rct::keyV res(a.size());
|
||||
for (size_t i = 0; i < a.size(); ++i)
|
||||
{
|
||||
sc_sub(res[i].bytes, a[i].bytes, b[i].bytes);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Multiply a scalar and a vector */
|
||||
static rct::keyV vector_scalar(const rct::keyV &a, const rct::key &x)
|
||||
{
|
||||
rct::keyV res(a.size());
|
||||
for (size_t i = 0; i < a.size(); ++i)
|
||||
{
|
||||
sc_mul(res[i].bytes, a[i].bytes, x.bytes);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Exponentiate a curve vector by a scalar */
|
||||
static rct::keyV vector_scalar2(const rct::keyV &a, const rct::key &x)
|
||||
{
|
||||
rct::keyV res(a.size());
|
||||
for (size_t i = 0; i < a.size(); ++i)
|
||||
{
|
||||
rct::scalarmultKey(res[i], a[i], x);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static rct::key switch_endianness(rct::key k)
|
||||
{
|
||||
std::reverse(k.bytes, k.bytes + sizeof(k));
|
||||
return k;
|
||||
}
|
||||
|
||||
/* Compute the inverse of a scalar, the stupid way */
|
||||
static rct::key invert(const rct::key &x)
|
||||
{
|
||||
rct::key inv;
|
||||
|
||||
BN_CTX *ctx = BN_CTX_new();
|
||||
BIGNUM *X = BN_new();
|
||||
BIGNUM *L = BN_new();
|
||||
BIGNUM *I = BN_new();
|
||||
|
||||
BN_bin2bn(switch_endianness(x).bytes, sizeof(rct::key), X);
|
||||
BN_bin2bn(switch_endianness(rct::curveOrder()).bytes, sizeof(rct::key), L);
|
||||
|
||||
CHECK_AND_ASSERT_THROW_MES(BN_mod_inverse(I, X, L, ctx), "Failed to invert");
|
||||
|
||||
const int len = BN_num_bytes(I);
|
||||
CHECK_AND_ASSERT_THROW_MES((size_t)len <= sizeof(rct::key), "Invalid number length");
|
||||
inv = rct::zero();
|
||||
BN_bn2bin(I, inv.bytes);
|
||||
std::reverse(inv.bytes, inv.bytes + len);
|
||||
|
||||
BN_free(I);
|
||||
BN_free(L);
|
||||
BN_free(X);
|
||||
BN_CTX_free(ctx);
|
||||
|
||||
#ifdef DEBUG_BP
|
||||
rct::key tmp;
|
||||
sc_mul(tmp.bytes, inv.bytes, x.bytes);
|
||||
CHECK_AND_ASSERT_THROW_MES(tmp == rct::identity(), "invert failed");
|
||||
#endif
|
||||
return inv;
|
||||
}
|
||||
|
||||
/* Compute the slice of a vector */
|
||||
static rct::keyV slice(const rct::keyV &a, size_t start, size_t stop)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(start < a.size(), "Invalid start index");
|
||||
CHECK_AND_ASSERT_THROW_MES(stop <= a.size(), "Invalid stop index");
|
||||
CHECK_AND_ASSERT_THROW_MES(start < stop, "Invalid start/stop indices");
|
||||
rct::keyV res(stop - start);
|
||||
for (size_t i = start; i < stop; ++i)
|
||||
{
|
||||
res[i - start] = a[i];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Given a value v (0..2^N-1) and a mask gamma, construct a range proof */
|
||||
Bulletproof bulletproof_PROVE(const rct::key &sv, const rct::key &gamma)
|
||||
{
|
||||
init_exponents();
|
||||
|
||||
PERF_TIMER_UNIT(PROVE, 1000000);
|
||||
|
||||
constexpr size_t logN = 6; // log2(64)
|
||||
constexpr size_t N = 1<<logN;
|
||||
|
||||
rct::key V;
|
||||
rct::keyV aL(N), aR(N);
|
||||
|
||||
PERF_TIMER_START_BP(PROVE_v);
|
||||
rct::addKeys2(V, gamma, sv, rct::H);
|
||||
PERF_TIMER_STOP(PROVE_v);
|
||||
|
||||
PERF_TIMER_START_BP(PROVE_aLaR);
|
||||
for (size_t i = N; i-- > 0; )
|
||||
{
|
||||
if (sv[i/8] & (((uint64_t)1)<<(i%8)))
|
||||
{
|
||||
aL[i] = rct::identity();
|
||||
}
|
||||
else
|
||||
{
|
||||
aL[i] = rct::zero();
|
||||
}
|
||||
sc_sub(aR[i].bytes, aL[i].bytes, rct::identity().bytes);
|
||||
}
|
||||
PERF_TIMER_STOP(PROVE_aLaR);
|
||||
|
||||
|
||||
// DEBUG: Test to ensure this recovers the value
|
||||
#ifdef DEBUG_BP
|
||||
uint64_t test_aL = 0, test_aR = 0;
|
||||
for (size_t i = 0; i < N; ++i)
|
||||
{
|
||||
if (aL[i] == rct::identity())
|
||||
test_aL += ((uint64_t)1)<<i;
|
||||
if (aR[i] == rct::zero())
|
||||
test_aR += ((uint64_t)1)<<i;
|
||||
}
|
||||
uint64_t v_test = 0;
|
||||
for (int n = 0; n < 8; ++n) v_test |= (((uint64_t)sv[n]) << (8*n));
|
||||
CHECK_AND_ASSERT_THROW_MES(test_aL == v_test, "test_aL failed");
|
||||
CHECK_AND_ASSERT_THROW_MES(test_aR == v_test, "test_aR failed");
|
||||
#endif
|
||||
|
||||
PERF_TIMER_START_BP(PROVE_step1);
|
||||
// PAPER LINES 38-39
|
||||
rct::key alpha = rct::skGen();
|
||||
rct::key ve = vector_exponent(aL, aR);
|
||||
rct::key A;
|
||||
rct::addKeys(A, ve, rct::scalarmultBase(alpha));
|
||||
|
||||
// PAPER LINES 40-42
|
||||
rct::keyV sL = rct::skvGen(N), sR = rct::skvGen(N);
|
||||
rct::key rho = rct::skGen();
|
||||
ve = vector_exponent(sL, sR);
|
||||
rct::key S;
|
||||
rct::addKeys(S, ve, rct::scalarmultBase(rho));
|
||||
|
||||
// PAPER LINES 43-45
|
||||
rct::keyV hashed;
|
||||
hashed.push_back(A);
|
||||
hashed.push_back(S);
|
||||
rct::key y = rct::hash_to_scalar(hashed);
|
||||
rct::key z = rct::hash_to_scalar(y);
|
||||
|
||||
// Polynomial construction before PAPER LINE 46
|
||||
rct::key t0 = rct::zero();
|
||||
rct::key t1 = rct::zero();
|
||||
rct::key t2 = rct::zero();
|
||||
|
||||
const auto yN = vector_powers(y, N);
|
||||
|
||||
rct::key ip1y = inner_product(oneN, yN);
|
||||
rct::key tmp;
|
||||
sc_muladd(t0.bytes, z.bytes, ip1y.bytes, t0.bytes);
|
||||
|
||||
rct::key zsq;
|
||||
sc_mul(zsq.bytes, z.bytes, z.bytes);
|
||||
sc_muladd(t0.bytes, zsq.bytes, sv.bytes, t0.bytes);
|
||||
|
||||
rct::key k = rct::zero();
|
||||
sc_mulsub(k.bytes, zsq.bytes, ip1y.bytes, k.bytes);
|
||||
|
||||
rct::key zcu;
|
||||
sc_mul(zcu.bytes, zsq.bytes, z.bytes);
|
||||
sc_mulsub(k.bytes, zcu.bytes, ip12.bytes, k.bytes);
|
||||
sc_add(t0.bytes, t0.bytes, k.bytes);
|
||||
|
||||
// DEBUG: Test the value of t0 has the correct form
|
||||
#ifdef DEBUG_BP
|
||||
rct::key test_t0 = rct::zero();
|
||||
rct::key iph = inner_product(aL, hadamard(aR, yN));
|
||||
sc_add(test_t0.bytes, test_t0.bytes, iph.bytes);
|
||||
rct::key ips = inner_product(vector_subtract(aL, aR), yN);
|
||||
sc_muladd(test_t0.bytes, z.bytes, ips.bytes, test_t0.bytes);
|
||||
rct::key ipt = inner_product(twoN, aL);
|
||||
sc_muladd(test_t0.bytes, zsq.bytes, ipt.bytes, test_t0.bytes);
|
||||
sc_add(test_t0.bytes, test_t0.bytes, k.bytes);
|
||||
CHECK_AND_ASSERT_THROW_MES(t0 == test_t0, "t0 check failed");
|
||||
#endif
|
||||
PERF_TIMER_STOP(PROVE_step1);
|
||||
|
||||
PERF_TIMER_START_BP(PROVE_step2);
|
||||
const auto HyNsR = hadamard(yN, sR);
|
||||
const auto vpIz = vector_scalar(oneN, z);
|
||||
const auto vp2zsq = vector_scalar(twoN, zsq);
|
||||
const auto aL_vpIz = vector_subtract(aL, vpIz);
|
||||
const auto aR_vpIz = vector_add(aR, vpIz);
|
||||
|
||||
rct::key ip1 = inner_product(aL_vpIz, HyNsR);
|
||||
sc_add(t1.bytes, t1.bytes, ip1.bytes);
|
||||
|
||||
rct::key ip2 = inner_product(sL, vector_add(hadamard(yN, aR_vpIz), vp2zsq));
|
||||
sc_add(t1.bytes, t1.bytes, ip2.bytes);
|
||||
|
||||
rct::key ip3 = inner_product(sL, HyNsR);
|
||||
sc_add(t2.bytes, t2.bytes, ip3.bytes);
|
||||
|
||||
// PAPER LINES 47-48
|
||||
rct::key tau1 = rct::skGen(), tau2 = rct::skGen();
|
||||
|
||||
rct::key T1 = rct::addKeys(rct::scalarmultKey(rct::H, t1), rct::scalarmultBase(tau1));
|
||||
rct::key T2 = rct::addKeys(rct::scalarmultKey(rct::H, t2), rct::scalarmultBase(tau2));
|
||||
|
||||
// PAPER LINES 49-51
|
||||
hashed.clear();
|
||||
hashed.push_back(z);
|
||||
hashed.push_back(T1);
|
||||
hashed.push_back(T2);
|
||||
rct::key x = rct::hash_to_scalar(hashed);
|
||||
|
||||
// PAPER LINES 52-53
|
||||
rct::key taux = rct::zero();
|
||||
sc_mul(taux.bytes, tau1.bytes, x.bytes);
|
||||
rct::key xsq;
|
||||
sc_mul(xsq.bytes, x.bytes, x.bytes);
|
||||
sc_muladd(taux.bytes, tau2.bytes, xsq.bytes, taux.bytes);
|
||||
sc_muladd(taux.bytes, gamma.bytes, zsq.bytes, taux.bytes);
|
||||
rct::key mu;
|
||||
sc_muladd(mu.bytes, x.bytes, rho.bytes, alpha.bytes);
|
||||
|
||||
// PAPER LINES 54-57
|
||||
rct::keyV l = vector_add(aL_vpIz, vector_scalar(sL, x));
|
||||
rct::keyV r = vector_add(hadamard(yN, vector_add(aR_vpIz, vector_scalar(sR, x))), vp2zsq);
|
||||
PERF_TIMER_STOP(PROVE_step2);
|
||||
|
||||
PERF_TIMER_START_BP(PROVE_step3);
|
||||
rct::key t = inner_product(l, r);
|
||||
|
||||
// DEBUG: Test if the l and r vectors match the polynomial forms
|
||||
#ifdef DEBUG_BP
|
||||
rct::key test_t;
|
||||
sc_muladd(test_t.bytes, t1.bytes, x.bytes, t0.bytes);
|
||||
sc_muladd(test_t.bytes, t2.bytes, xsq.bytes, test_t.bytes);
|
||||
CHECK_AND_ASSERT_THROW_MES(test_t == t, "test_t check failed");
|
||||
#endif
|
||||
|
||||
// PAPER LINES 32-33
|
||||
hashed.clear();
|
||||
hashed.push_back(x);
|
||||
hashed.push_back(taux);
|
||||
hashed.push_back(mu);
|
||||
hashed.push_back(t);
|
||||
rct::key x_ip = rct::hash_to_scalar(hashed);
|
||||
|
||||
// These are used in the inner product rounds
|
||||
size_t nprime = N;
|
||||
rct::keyV Gprime(N);
|
||||
rct::keyV Hprime(N);
|
||||
rct::keyV aprime(N);
|
||||
rct::keyV bprime(N);
|
||||
const rct::key yinv = invert(y);
|
||||
rct::key yinvpow = rct::identity();
|
||||
for (size_t i = 0; i < N; ++i)
|
||||
{
|
||||
Gprime[i] = Gi[i];
|
||||
Hprime[i] = scalarmultKey(Hi[i], yinvpow);
|
||||
sc_mul(yinvpow.bytes, yinvpow.bytes, yinv.bytes);
|
||||
aprime[i] = l[i];
|
||||
bprime[i] = r[i];
|
||||
}
|
||||
rct::keyV L(logN);
|
||||
rct::keyV R(logN);
|
||||
int round = 0;
|
||||
rct::keyV w(logN); // this is the challenge x in the inner product protocol
|
||||
PERF_TIMER_STOP(PROVE_step3);
|
||||
|
||||
PERF_TIMER_START_BP(PROVE_step4);
|
||||
// PAPER LINE 13
|
||||
while (nprime > 1)
|
||||
{
|
||||
// PAPER LINE 15
|
||||
nprime /= 2;
|
||||
|
||||
// PAPER LINES 16-17
|
||||
rct::key cL = inner_product(slice(aprime, 0, nprime), slice(bprime, nprime, bprime.size()));
|
||||
rct::key cR = inner_product(slice(aprime, nprime, aprime.size()), slice(bprime, 0, nprime));
|
||||
|
||||
// PAPER LINES 18-19
|
||||
L[round] = vector_exponent_custom(slice(Gprime, nprime, Gprime.size()), slice(Hprime, 0, nprime), slice(aprime, 0, nprime), slice(bprime, nprime, bprime.size()));
|
||||
sc_mul(tmp.bytes, cL.bytes, x_ip.bytes);
|
||||
rct::addKeys(L[round], L[round], rct::scalarmultKey(rct::H, tmp));
|
||||
R[round] = vector_exponent_custom(slice(Gprime, 0, nprime), slice(Hprime, nprime, Hprime.size()), slice(aprime, nprime, aprime.size()), slice(bprime, 0, nprime));
|
||||
sc_mul(tmp.bytes, cR.bytes, x_ip.bytes);
|
||||
rct::addKeys(R[round], R[round], rct::scalarmultKey(rct::H, tmp));
|
||||
|
||||
// PAPER LINES 21-22
|
||||
hashed.clear();
|
||||
if (round == 0)
|
||||
{
|
||||
hashed.push_back(L[0]);
|
||||
hashed.push_back(R[0]);
|
||||
w[0] = rct::hash_to_scalar(hashed);
|
||||
}
|
||||
else
|
||||
{
|
||||
hashed.push_back(w[round - 1]);
|
||||
hashed.push_back(L[round]);
|
||||
hashed.push_back(R[round]);
|
||||
w[round] = rct::hash_to_scalar(hashed);
|
||||
}
|
||||
|
||||
// PAPER LINES 24-25
|
||||
const rct::key winv = invert(w[round]);
|
||||
Gprime = hadamard2(vector_scalar2(slice(Gprime, 0, nprime), winv), vector_scalar2(slice(Gprime, nprime, Gprime.size()), w[round]));
|
||||
Hprime = hadamard2(vector_scalar2(slice(Hprime, 0, nprime), w[round]), vector_scalar2(slice(Hprime, nprime, Hprime.size()), winv));
|
||||
|
||||
// PAPER LINES 28-29
|
||||
aprime = vector_add(vector_scalar(slice(aprime, 0, nprime), w[round]), vector_scalar(slice(aprime, nprime, aprime.size()), winv));
|
||||
bprime = vector_add(vector_scalar(slice(bprime, 0, nprime), winv), vector_scalar(slice(bprime, nprime, bprime.size()), w[round]));
|
||||
|
||||
++round;
|
||||
}
|
||||
PERF_TIMER_STOP(PROVE_step4);
|
||||
|
||||
// PAPER LINE 58 (with inclusions from PAPER LINE 8 and PAPER LINE 20)
|
||||
return Bulletproof(V, A, S, T1, T2, taux, mu, L, R, aprime[0], bprime[0], t);
|
||||
}
|
||||
|
||||
Bulletproof bulletproof_PROVE(uint64_t v, const rct::key &gamma)
|
||||
{
|
||||
// vG + gammaH
|
||||
PERF_TIMER_START_BP(PROVE_v);
|
||||
rct::key sv = rct::zero();
|
||||
sv.bytes[0] = v & 255;
|
||||
sv.bytes[1] = (v >> 8) & 255;
|
||||
sv.bytes[2] = (v >> 16) & 255;
|
||||
sv.bytes[3] = (v >> 24) & 255;
|
||||
sv.bytes[4] = (v >> 32) & 255;
|
||||
sv.bytes[5] = (v >> 40) & 255;
|
||||
sv.bytes[6] = (v >> 48) & 255;
|
||||
sv.bytes[7] = (v >> 56) & 255;
|
||||
PERF_TIMER_STOP(PROVE_v);
|
||||
return bulletproof_PROVE(sv, gamma);
|
||||
}
|
||||
|
||||
/* Given a range proof, determine if it is valid */
|
||||
bool bulletproof_VERIFY(const Bulletproof &proof)
|
||||
{
|
||||
init_exponents();
|
||||
|
||||
CHECK_AND_ASSERT_MES(proof.L.size() == proof.R.size(), false, "Mismatched L and R sizes");
|
||||
CHECK_AND_ASSERT_MES(proof.L.size() > 0, false, "Empty proof");
|
||||
CHECK_AND_ASSERT_MES(proof.L.size() == 6, false, "Proof is not for 64 bits");
|
||||
|
||||
const size_t logN = proof.L.size();
|
||||
const size_t N = 1 << logN;
|
||||
|
||||
// Reconstruct the challenges
|
||||
PERF_TIMER_START_BP(VERIFY);
|
||||
PERF_TIMER_START_BP(VERIFY_start);
|
||||
rct::keyV hashed;
|
||||
hashed.push_back(proof.A);
|
||||
hashed.push_back(proof.S);
|
||||
rct::key y = rct::hash_to_scalar(hashed);
|
||||
rct::key z = rct::hash_to_scalar(y);
|
||||
hashed.clear();
|
||||
hashed.push_back(z);
|
||||
hashed.push_back(proof.T1);
|
||||
hashed.push_back(proof.T2);
|
||||
rct::key x = rct::hash_to_scalar(hashed);
|
||||
PERF_TIMER_STOP(VERIFY_start);
|
||||
|
||||
PERF_TIMER_START_BP(VERIFY_line_60);
|
||||
// Reconstruct the challenges
|
||||
hashed.clear();
|
||||
hashed.push_back(x);
|
||||
hashed.push_back(proof.taux);
|
||||
hashed.push_back(proof.mu);
|
||||
hashed.push_back(proof.t);
|
||||
rct::key x_ip = hash_to_scalar(hashed);
|
||||
PERF_TIMER_STOP(VERIFY_line_60);
|
||||
|
||||
PERF_TIMER_START_BP(VERIFY_line_61);
|
||||
// PAPER LINE 61
|
||||
rct::key L61Left = rct::addKeys(rct::scalarmultBase(proof.taux), rct::scalarmultKey(rct::H, proof.t));
|
||||
|
||||
rct::key k = rct::zero();
|
||||
const auto yN = vector_powers(y, N);
|
||||
rct::key ip1y = inner_product(oneN, yN);
|
||||
rct::key zsq;
|
||||
sc_mul(zsq.bytes, z.bytes, z.bytes);
|
||||
rct::key tmp, tmp2;
|
||||
sc_mulsub(k.bytes, zsq.bytes, ip1y.bytes, k.bytes);
|
||||
rct::key zcu;
|
||||
sc_mul(zcu.bytes, zsq.bytes, z.bytes);
|
||||
sc_mulsub(k.bytes, zcu.bytes, ip12.bytes, k.bytes);
|
||||
PERF_TIMER_STOP(VERIFY_line_61);
|
||||
|
||||
PERF_TIMER_START_BP(VERIFY_line_61rl);
|
||||
sc_muladd(tmp.bytes, z.bytes, ip1y.bytes, k.bytes);
|
||||
rct::key L61Right = rct::scalarmultKey(rct::H, tmp);
|
||||
|
||||
CHECK_AND_ASSERT_MES(proof.V.size() == 1, false, "proof.V does not have exactly one element");
|
||||
tmp = rct::scalarmultKey(proof.V[0], zsq);
|
||||
rct::addKeys(L61Right, L61Right, tmp);
|
||||
|
||||
tmp = rct::scalarmultKey(proof.T1, x);
|
||||
rct::addKeys(L61Right, L61Right, tmp);
|
||||
|
||||
rct::key xsq;
|
||||
sc_mul(xsq.bytes, x.bytes, x.bytes);
|
||||
tmp = rct::scalarmultKey(proof.T2, xsq);
|
||||
rct::addKeys(L61Right, L61Right, tmp);
|
||||
PERF_TIMER_STOP(VERIFY_line_61rl);
|
||||
|
||||
if (!(L61Right == L61Left))
|
||||
{
|
||||
MERROR("Verification failure at step 1");
|
||||
return false;
|
||||
}
|
||||
|
||||
PERF_TIMER_START_BP(VERIFY_line_62);
|
||||
// PAPER LINE 62
|
||||
rct::key P = rct::addKeys(proof.A, rct::scalarmultKey(proof.S, x));
|
||||
PERF_TIMER_STOP(VERIFY_line_62);
|
||||
|
||||
// Compute the number of rounds for the inner product
|
||||
const size_t rounds = proof.L.size();
|
||||
CHECK_AND_ASSERT_MES(rounds > 0, false, "Zero rounds");
|
||||
|
||||
PERF_TIMER_START_BP(VERIFY_line_21_22);
|
||||
// PAPER LINES 21-22
|
||||
// The inner product challenges are computed per round
|
||||
rct::keyV w(rounds);
|
||||
hashed.clear();
|
||||
hashed.push_back(proof.L[0]);
|
||||
hashed.push_back(proof.R[0]);
|
||||
w[0] = rct::hash_to_scalar(hashed);
|
||||
for (size_t i = 1; i < rounds; ++i)
|
||||
{
|
||||
hashed.clear();
|
||||
hashed.push_back(w[i-1]);
|
||||
hashed.push_back(proof.L[i]);
|
||||
hashed.push_back(proof.R[i]);
|
||||
w[i] = rct::hash_to_scalar(hashed);
|
||||
}
|
||||
PERF_TIMER_STOP(VERIFY_line_21_22);
|
||||
|
||||
PERF_TIMER_START_BP(VERIFY_line_24_25);
|
||||
// Basically PAPER LINES 24-25
|
||||
// Compute the curvepoints from G[i] and H[i]
|
||||
rct::key inner_prod = rct::identity();
|
||||
rct::key yinvpow = rct::identity();
|
||||
rct::key ypow = rct::identity();
|
||||
|
||||
PERF_TIMER_START_BP(VERIFY_line_24_25_invert);
|
||||
const rct::key yinv = invert(y);
|
||||
rct::keyV winv(rounds);
|
||||
for (size_t i = 0; i < rounds; ++i)
|
||||
winv[i] = invert(w[i]);
|
||||
PERF_TIMER_STOP(VERIFY_line_24_25_invert);
|
||||
|
||||
for (size_t i = 0; i < N; ++i)
|
||||
{
|
||||
// Convert the index to binary IN REVERSE and construct the scalar exponent
|
||||
rct::key g_scalar = proof.a;
|
||||
rct::key h_scalar;
|
||||
sc_mul(h_scalar.bytes, proof.b.bytes, yinvpow.bytes);
|
||||
|
||||
for (size_t j = rounds; j-- > 0; )
|
||||
{
|
||||
size_t J = w.size() - j - 1;
|
||||
|
||||
if ((i & (((size_t)1)<<j)) == 0)
|
||||
{
|
||||
sc_mul(g_scalar.bytes, g_scalar.bytes, winv[J].bytes);
|
||||
sc_mul(h_scalar.bytes, h_scalar.bytes, w[J].bytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
sc_mul(g_scalar.bytes, g_scalar.bytes, w[J].bytes);
|
||||
sc_mul(h_scalar.bytes, h_scalar.bytes, winv[J].bytes);
|
||||
}
|
||||
}
|
||||
|
||||
// Adjust the scalars using the exponents from PAPER LINE 62
|
||||
sc_add(g_scalar.bytes, g_scalar.bytes, z.bytes);
|
||||
sc_mul(tmp.bytes, zsq.bytes, twoN[i].bytes);
|
||||
sc_muladd(tmp.bytes, z.bytes, ypow.bytes, tmp.bytes);
|
||||
sc_mulsub(h_scalar.bytes, tmp.bytes, yinvpow.bytes, h_scalar.bytes);
|
||||
|
||||
// Now compute the basepoint's scalar multiplication
|
||||
// Each of these could be written as a multiexp operation instead
|
||||
rct::addKeys3(tmp, g_scalar, Gprecomp[i], h_scalar, Hprecomp[i]);
|
||||
rct::addKeys(inner_prod, inner_prod, tmp);
|
||||
|
||||
if (i != N-1)
|
||||
{
|
||||
sc_mul(yinvpow.bytes, yinvpow.bytes, yinv.bytes);
|
||||
sc_mul(ypow.bytes, ypow.bytes, y.bytes);
|
||||
}
|
||||
}
|
||||
PERF_TIMER_STOP(VERIFY_line_24_25);
|
||||
|
||||
PERF_TIMER_START_BP(VERIFY_line_26);
|
||||
// PAPER LINE 26
|
||||
rct::key pprime;
|
||||
sc_sub(tmp.bytes, rct::zero().bytes, proof.mu.bytes);
|
||||
rct::addKeys(pprime, P, rct::scalarmultBase(tmp));
|
||||
|
||||
for (size_t i = 0; i < rounds; ++i)
|
||||
{
|
||||
sc_mul(tmp.bytes, w[i].bytes, w[i].bytes);
|
||||
sc_mul(tmp2.bytes, winv[i].bytes, winv[i].bytes);
|
||||
#if 1
|
||||
ge_dsmp cacheL, cacheR;
|
||||
rct::precomp(cacheL, proof.L[i]);
|
||||
rct::precomp(cacheR, proof.R[i]);
|
||||
rct::addKeys3(tmp, tmp, cacheL, tmp2, cacheR);
|
||||
rct::addKeys(pprime, pprime, tmp);
|
||||
#else
|
||||
rct::addKeys(pprime, pprime, rct::scalarmultKey(proof.L[i], tmp));
|
||||
rct::addKeys(pprime, pprime, rct::scalarmultKey(proof.R[i], tmp2));
|
||||
#endif
|
||||
}
|
||||
sc_mul(tmp.bytes, proof.t.bytes, x_ip.bytes);
|
||||
rct::addKeys(pprime, pprime, rct::scalarmultKey(rct::H, tmp));
|
||||
PERF_TIMER_STOP(VERIFY_line_26);
|
||||
|
||||
PERF_TIMER_START_BP(VERIFY_step2_check);
|
||||
sc_mul(tmp.bytes, proof.a.bytes, proof.b.bytes);
|
||||
sc_mul(tmp.bytes, tmp.bytes, x_ip.bytes);
|
||||
tmp = rct::scalarmultKey(rct::H, tmp);
|
||||
rct::addKeys(tmp, tmp, inner_prod);
|
||||
PERF_TIMER_STOP(VERIFY_step2_check);
|
||||
if (!(pprime == tmp))
|
||||
{
|
||||
MERROR("Verification failure at step 2");
|
||||
return false;
|
||||
}
|
||||
|
||||
PERF_TIMER_STOP(VERIFY);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
47
src/ringct/bulletproofs.h
Normal file
47
src/ringct/bulletproofs.h
Normal file
@ -0,0 +1,47 @@
|
||||
// Copyright (c) 2017, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Adapted from Java code by Sarang Noether
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef BULLETPROOFS_H
|
||||
#define BULLETPROOFS_H
|
||||
|
||||
#include "rctTypes.h"
|
||||
|
||||
namespace rct
|
||||
{
|
||||
|
||||
Bulletproof bulletproof_PROVE(const rct::key &v, const rct::key &gamma);
|
||||
Bulletproof bulletproof_PROVE(uint64_t v, const rct::key &gamma);
|
||||
bool bulletproof_VERIFY(const Bulletproof &proof);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -220,6 +220,11 @@ namespace rct {
|
||||
ge_p3_tobytes(AB.bytes, &A2);
|
||||
}
|
||||
|
||||
rct::key addKeys(const key &A, const key &B) {
|
||||
key k;
|
||||
addKeys(k, A, B);
|
||||
return k;
|
||||
}
|
||||
|
||||
//addKeys1
|
||||
//aGB = aG + B where a is a scalar, G is the basepoint, and B is a point
|
||||
@ -257,6 +262,15 @@ namespace rct {
|
||||
ge_tobytes(aAbB.bytes, &rv);
|
||||
}
|
||||
|
||||
//addKeys3
|
||||
//aAbB = a*A + b*B where a, b are scalars, A, B are curve points
|
||||
//A and B must be input after applying "precomp"
|
||||
void addKeys3(key &aAbB, const key &a, const ge_dsmp A, const key &b, const ge_dsmp B) {
|
||||
ge_p2 rv;
|
||||
ge_double_scalarmult_precomp_vartime2(&rv, a.bytes, A, b.bytes, B);
|
||||
ge_tobytes(aAbB.bytes, &rv);
|
||||
}
|
||||
|
||||
|
||||
//subtract Keys (subtracts curve points)
|
||||
//AB = A - B where A, B are curve points
|
||||
|
@ -123,6 +123,7 @@ namespace rct {
|
||||
|
||||
//for curve points: AB = A + B
|
||||
void addKeys(key &AB, const key &A, const key &B);
|
||||
rct::key addKeys(const key &A, const key &B);
|
||||
//aGB = aG + B where a is a scalar, G is the basepoint, and B is a point
|
||||
void addKeys1(key &aGB, const key &a, const key & B);
|
||||
//aGbB = aG + bB where a, b are scalars, G is the basepoint and B is a point
|
||||
@ -133,6 +134,7 @@ namespace rct {
|
||||
//aAbB = a*A + b*B where a, b are scalars, A, B are curve points
|
||||
//B must be input after applying "precomp"
|
||||
void addKeys3(key &aAbB, const key &a, const key &A, const key &b, const ge_dsmp B);
|
||||
void addKeys3(key &aAbB, const key &a, const ge_dsmp A, const key &b, const ge_dsmp B);
|
||||
//AB = A - B where A, B are curve points
|
||||
void subKeys(key &AB, const key &A, const key &B);
|
||||
//checks if A, B are equal as curve points
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "common/threadpool.h"
|
||||
#include "common/util.h"
|
||||
#include "rctSigs.h"
|
||||
#include "bulletproofs.h"
|
||||
#include "cryptonote_basic/cryptonote_format_utils.h"
|
||||
|
||||
using namespace crypto;
|
||||
@ -42,6 +43,15 @@ using namespace std;
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "ringct"
|
||||
|
||||
namespace rct {
|
||||
Bulletproof proveRangeBulletproof(key &C, key &mask, uint64_t amount)
|
||||
{
|
||||
mask = rct::skGen();
|
||||
Bulletproof proof = bulletproof_PROVE(amount, mask);
|
||||
CHECK_AND_ASSERT_THROW_MES(proof.V.size() == 1, "V has not exactly one element");
|
||||
C = proof.V[0];
|
||||
return proof;
|
||||
}
|
||||
|
||||
//Borromean (c.f. gmax/andytoshi's paper)
|
||||
boroSig genBorromean(const key64 x, const key64 P1, const key64 P2, const bits indices) {
|
||||
key64 L[2], alpha;
|
||||
@ -335,16 +345,41 @@ namespace rct {
|
||||
hashes.push_back(hash2rct(h));
|
||||
|
||||
keyV kv;
|
||||
kv.reserve((64*3+1) * rv.p.rangeSigs.size());
|
||||
for (auto r: rv.p.rangeSigs)
|
||||
if (rv.type == RCTTypeSimpleBulletproof || rv.type == RCTTypeFullBulletproof)
|
||||
{
|
||||
for (size_t n = 0; n < 64; ++n)
|
||||
kv.push_back(r.asig.s0[n]);
|
||||
for (size_t n = 0; n < 64; ++n)
|
||||
kv.push_back(r.asig.s1[n]);
|
||||
kv.push_back(r.asig.ee);
|
||||
for (size_t n = 0; n < 64; ++n)
|
||||
kv.push_back(r.Ci[n]);
|
||||
kv.reserve((6*2+10) * rv.p.bulletproofs.size());
|
||||
for (const auto &p: rv.p.bulletproofs)
|
||||
{
|
||||
for (size_t n = 0; n < p.V.size(); ++n)
|
||||
kv.push_back(p.V[n]);
|
||||
kv.push_back(p.A);
|
||||
kv.push_back(p.S);
|
||||
kv.push_back(p.T1);
|
||||
kv.push_back(p.T2);
|
||||
kv.push_back(p.taux);
|
||||
kv.push_back(p.mu);
|
||||
for (size_t n = 0; n < p.L.size(); ++n)
|
||||
kv.push_back(p.L[n]);
|
||||
for (size_t n = 0; n < p.R.size(); ++n)
|
||||
kv.push_back(p.R[n]);
|
||||
kv.push_back(p.a);
|
||||
kv.push_back(p.b);
|
||||
kv.push_back(p.t);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
kv.reserve((64*3+1) * rv.p.rangeSigs.size());
|
||||
for (const auto &r: rv.p.rangeSigs)
|
||||
{
|
||||
for (size_t n = 0; n < 64; ++n)
|
||||
kv.push_back(r.asig.s0[n]);
|
||||
for (size_t n = 0; n < 64; ++n)
|
||||
kv.push_back(r.asig.s1[n]);
|
||||
kv.push_back(r.asig.ee);
|
||||
for (size_t n = 0; n < 64; ++n)
|
||||
kv.push_back(r.Ci[n]);
|
||||
}
|
||||
}
|
||||
hashes.push_back(cn_fast_hash(kv));
|
||||
return cn_fast_hash(hashes);
|
||||
@ -563,7 +598,7 @@ namespace rct {
|
||||
// must know the destination private key to find the correct amount, else will return a random number
|
||||
// Note: For txn fees, the last index in the amounts vector should contain that
|
||||
// Thus the amounts vector will be "one" longer than the destinations vectort
|
||||
rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector<xmr_amount> & amounts, const ctkeyM &mixRing, const keyV &amount_keys, unsigned int index, ctkeyV &outSk) {
|
||||
rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector<xmr_amount> & amounts, const ctkeyM &mixRing, const keyV &amount_keys, unsigned int index, ctkeyV &outSk, bool bulletproof) {
|
||||
CHECK_AND_ASSERT_THROW_MES(amounts.size() == destinations.size() || amounts.size() == destinations.size() + 1, "Different number of amounts/destinations");
|
||||
CHECK_AND_ASSERT_THROW_MES(amount_keys.size() == destinations.size(), "Different number of amount_keys/destinations");
|
||||
CHECK_AND_ASSERT_THROW_MES(index < mixRing.size(), "Bad index into mixRing");
|
||||
@ -572,10 +607,13 @@ namespace rct {
|
||||
}
|
||||
|
||||
rctSig rv;
|
||||
rv.type = RCTTypeFull;
|
||||
rv.type = bulletproof ? RCTTypeFullBulletproof : RCTTypeFull;
|
||||
rv.message = message;
|
||||
rv.outPk.resize(destinations.size());
|
||||
rv.p.rangeSigs.resize(destinations.size());
|
||||
if (bulletproof)
|
||||
rv.p.bulletproofs.resize(destinations.size());
|
||||
else
|
||||
rv.p.rangeSigs.resize(destinations.size());
|
||||
rv.ecdhInfo.resize(destinations.size());
|
||||
|
||||
size_t i = 0;
|
||||
@ -585,8 +623,14 @@ namespace rct {
|
||||
//add destination to sig
|
||||
rv.outPk[i].dest = copy(destinations[i]);
|
||||
//compute range proof
|
||||
rv.p.rangeSigs[i] = proveRange(rv.outPk[i].mask, outSk[i].mask, amounts[i]);
|
||||
if (bulletproof)
|
||||
rv.p.bulletproofs[i] = proveRangeBulletproof(rv.outPk[i].mask, outSk[i].mask, amounts[i]);
|
||||
else
|
||||
rv.p.rangeSigs[i] = proveRange(rv.outPk[i].mask, outSk[i].mask, amounts[i]);
|
||||
#ifdef DBG
|
||||
if (bulletproof)
|
||||
CHECK_AND_ASSERT_THROW_MES(bulletproof_VERIFY(rv.p.bulletproofs[i]), "bulletproof_VERIFY failed on newly created proof");
|
||||
else
|
||||
CHECK_AND_ASSERT_THROW_MES(verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]), "verRange failed on newly created proof");
|
||||
#endif
|
||||
|
||||
@ -618,12 +662,12 @@ namespace rct {
|
||||
ctkeyM mixRing;
|
||||
ctkeyV outSk;
|
||||
tie(mixRing, index) = populateFromBlockchain(inPk, mixin);
|
||||
return genRct(message, inSk, destinations, amounts, mixRing, amount_keys, index, outSk);
|
||||
return genRct(message, inSk, destinations, amounts, mixRing, amount_keys, index, outSk, false);
|
||||
}
|
||||
|
||||
//RCT simple
|
||||
//for post-rct only
|
||||
rctSig genRctSimple(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector<xmr_amount> &inamounts, const vector<xmr_amount> &outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const keyV &amount_keys, const std::vector<unsigned int> & index, ctkeyV &outSk) {
|
||||
rctSig genRctSimple(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector<xmr_amount> &inamounts, const vector<xmr_amount> &outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const keyV &amount_keys, const std::vector<unsigned int> & index, ctkeyV &outSk, bool bulletproof) {
|
||||
CHECK_AND_ASSERT_THROW_MES(inamounts.size() > 0, "Empty inamounts");
|
||||
CHECK_AND_ASSERT_THROW_MES(inamounts.size() == inSk.size(), "Different number of inamounts/inSk");
|
||||
CHECK_AND_ASSERT_THROW_MES(outamounts.size() == destinations.size(), "Different number of amounts/destinations");
|
||||
@ -635,10 +679,13 @@ namespace rct {
|
||||
}
|
||||
|
||||
rctSig rv;
|
||||
rv.type = RCTTypeSimple;
|
||||
rv.type = bulletproof ? RCTTypeSimpleBulletproof : RCTTypeSimple;
|
||||
rv.message = message;
|
||||
rv.outPk.resize(destinations.size());
|
||||
rv.p.rangeSigs.resize(destinations.size());
|
||||
if (bulletproof)
|
||||
rv.p.bulletproofs.resize(destinations.size());
|
||||
else
|
||||
rv.p.rangeSigs.resize(destinations.size());
|
||||
rv.ecdhInfo.resize(destinations.size());
|
||||
|
||||
size_t i;
|
||||
@ -650,10 +697,16 @@ namespace rct {
|
||||
//add destination to sig
|
||||
rv.outPk[i].dest = copy(destinations[i]);
|
||||
//compute range proof
|
||||
rv.p.rangeSigs[i] = proveRange(rv.outPk[i].mask, outSk[i].mask, outamounts[i]);
|
||||
#ifdef DBG
|
||||
verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]);
|
||||
#endif
|
||||
if (bulletproof)
|
||||
rv.p.bulletproofs[i] = proveRangeBulletproof(rv.outPk[i].mask, outSk[i].mask, outamounts[i]);
|
||||
else
|
||||
rv.p.rangeSigs[i] = proveRange(rv.outPk[i].mask, outSk[i].mask, outamounts[i]);
|
||||
#ifdef DBG
|
||||
if (bulletproof)
|
||||
CHECK_AND_ASSERT_THROW_MES(bulletproof_VERIFY(rv.p.bulletproofs[i]), "bulletproof_VERIFY failed on newly created proof");
|
||||
else
|
||||
CHECK_AND_ASSERT_THROW_MES(verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]), "verRange failed on newly created proof");
|
||||
#endif
|
||||
|
||||
sc_add(sumout.bytes, outSk[i].mask.bytes, sumout.bytes);
|
||||
|
||||
@ -699,7 +752,7 @@ namespace rct {
|
||||
mixRing[i].resize(mixin+1);
|
||||
index[i] = populateFromBlockchainSimple(mixRing[i], inPk[i], mixin);
|
||||
}
|
||||
return genRctSimple(message, inSk, destinations, inamounts, outamounts, txnFee, mixRing, amount_keys, index, outSk);
|
||||
return genRctSimple(message, inSk, destinations, inamounts, outamounts, txnFee, mixRing, amount_keys, index, outSk, false);
|
||||
}
|
||||
|
||||
//RingCT protocol
|
||||
@ -714,10 +767,13 @@ namespace rct {
|
||||
// must know the destination private key to find the correct amount, else will return a random number
|
||||
bool verRct(const rctSig & rv, bool semantics) {
|
||||
PERF_TIMER(verRct);
|
||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull, false, "verRct called on non-full rctSig");
|
||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull || rv.type == RCTTypeFullBulletproof, false, "verRct called on non-full rctSig");
|
||||
if (semantics)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.p.rangeSigs.size(), false, "Mismatched sizes of outPk and rv.p.rangeSigs");
|
||||
if (rv.type == RCTTypeFullBulletproof)
|
||||
CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.p.bulletproofs.size(), false, "Mismatched sizes of outPk and rv.p.bulletproofs");
|
||||
else
|
||||
CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.p.rangeSigs.size(), false, "Mismatched sizes of outPk and rv.p.rangeSigs");
|
||||
CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.ecdhInfo.size(), false, "Mismatched sizes of outPk and rv.ecdhInfo");
|
||||
CHECK_AND_ASSERT_MES(rv.p.MGs.size() == 1, false, "full rctSig has not one MG");
|
||||
}
|
||||
@ -736,7 +792,10 @@ namespace rct {
|
||||
DP("range proofs verified?");
|
||||
for (size_t i = 0; i < rv.outPk.size(); i++) {
|
||||
tpool.submit(&waiter, [&, i] {
|
||||
results[i] = verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]);
|
||||
if (rv.p.rangeSigs.empty())
|
||||
results[i] = bulletproof_VERIFY(rv.p.bulletproofs[i]);
|
||||
else
|
||||
results[i] = verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]);
|
||||
});
|
||||
}
|
||||
waiter.wait();
|
||||
@ -776,10 +835,13 @@ namespace rct {
|
||||
{
|
||||
PERF_TIMER(verRctSimple);
|
||||
|
||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple, false, "verRctSimple called on non simple rctSig");
|
||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeSimpleBulletproof, false, "verRctSimple called on non simple rctSig");
|
||||
if (semantics)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.p.rangeSigs.size(), false, "Mismatched sizes of outPk and rv.p.rangeSigs");
|
||||
if (rv.type == RCTTypeSimpleBulletproof)
|
||||
CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.p.bulletproofs.size(), false, "Mismatched sizes of outPk and rv.p.bulletproofs");
|
||||
else
|
||||
CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.p.rangeSigs.size(), false, "Mismatched sizes of outPk and rv.p.rangeSigs");
|
||||
CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.ecdhInfo.size(), false, "Mismatched sizes of outPk and rv.ecdhInfo");
|
||||
CHECK_AND_ASSERT_MES(rv.pseudoOuts.size() == rv.p.MGs.size(), false, "Mismatched sizes of rv.pseudoOuts and rv.p.MGs");
|
||||
}
|
||||
@ -820,7 +882,10 @@ namespace rct {
|
||||
results.resize(rv.outPk.size());
|
||||
for (size_t i = 0; i < rv.outPk.size(); i++) {
|
||||
tpool.submit(&waiter, [&, i] {
|
||||
results[i] = verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]);
|
||||
if (rv.p.rangeSigs.empty())
|
||||
results[i] = bulletproof_VERIFY(rv.p.bulletproofs[i]);
|
||||
else
|
||||
results[i] = verRange(rv.outPk[i].mask, rv.p.rangeSigs[i]);
|
||||
});
|
||||
}
|
||||
waiter.wait();
|
||||
@ -869,9 +934,17 @@ namespace rct {
|
||||
// uses the attached ecdh info to find the amounts represented by each output commitment
|
||||
// must know the destination private key to find the correct amount, else will return a random number
|
||||
xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, key & mask) {
|
||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull, false, "decodeRct called on non-full rctSig");
|
||||
CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.ecdhInfo.size(), "Mismatched sizes of rv.outPk and rv.ecdhInfo");
|
||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull || rv.type == RCTTypeFullBulletproof, false, "decodeRct called on non-full rctSig");
|
||||
CHECK_AND_ASSERT_THROW_MES(i < rv.ecdhInfo.size(), "Bad index");
|
||||
if (rv.type == RCTTypeFullBulletproof)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(rv.p.bulletproofs.size() == rv.ecdhInfo.size(), "Mismatched sizes of rv.p.bulletproofs and rv.ecdhInfo");
|
||||
CHECK_AND_ASSERT_THROW_MES(rv.p.bulletproofs[i].V.size() == 1, "Unexpected sizes of rv.p.bulletproofs[i].V");
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.ecdhInfo.size(), "Mismatched sizes of rv.outPk and rv.ecdhInfo");
|
||||
}
|
||||
|
||||
//mask amount and mask
|
||||
ecdhTuple ecdh_info = rv.ecdhInfo[i];
|
||||
@ -897,16 +970,24 @@ namespace rct {
|
||||
}
|
||||
|
||||
xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, key &mask) {
|
||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple, false, "decodeRct called on non simple rctSig");
|
||||
CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.ecdhInfo.size(), "Mismatched sizes of rv.outPk and rv.ecdhInfo");
|
||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeSimpleBulletproof, false, "decodeRct called on non simple rctSig");
|
||||
CHECK_AND_ASSERT_THROW_MES(i < rv.ecdhInfo.size(), "Bad index");
|
||||
if (rv.type == RCTTypeSimpleBulletproof)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(rv.p.bulletproofs.size() == rv.ecdhInfo.size(), "Mismatched sizes of rv.p.bulletproofs and rv.ecdhInfo");
|
||||
CHECK_AND_ASSERT_THROW_MES(rv.p.bulletproofs[i].V.size() == 1, "Unexpected sizes of rv.p.bulletproofs[i].V");
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.ecdhInfo.size(), "Mismatched sizes of rv.outPk and rv.ecdhInfo");
|
||||
}
|
||||
|
||||
//mask amount and mask
|
||||
ecdhTuple ecdh_info = rv.ecdhInfo[i];
|
||||
ecdhDecode(ecdh_info, sk);
|
||||
mask = ecdh_info.mask;
|
||||
key amount = ecdh_info.amount;
|
||||
key C = rv.outPk[i].mask;
|
||||
key C = (rv.type == RCTTypeSimpleBulletproof) ? rv.p.bulletproofs[i].V.front() : rv.outPk[i].mask;
|
||||
DP("C");
|
||||
DP(C);
|
||||
key Ctmp;
|
||||
|
@ -118,10 +118,10 @@ namespace rct {
|
||||
//decodeRct: (c.f. http://eprint.iacr.org/2015/1098 section 5.1.1)
|
||||
// uses the attached ecdh info to find the amounts represented by each output commitment
|
||||
// must know the destination private key to find the correct amount, else will return a random number
|
||||
rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const std::vector<xmr_amount> & amounts, const ctkeyM &mixRing, const keyV &amount_keys, unsigned int index, ctkeyV &outSk);
|
||||
rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const std::vector<xmr_amount> & amounts, const ctkeyM &mixRing, const keyV &amount_keys, unsigned int index, ctkeyV &outSk, bool bulletproof);
|
||||
rctSig genRct(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const std::vector<xmr_amount> & amounts, const keyV &amount_keys, const int mixin);
|
||||
rctSig genRctSimple(const key & message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const std::vector<xmr_amount> & inamounts, const std::vector<xmr_amount> & outamounts, const keyV &amount_keys, xmr_amount txnFee, unsigned int mixin);
|
||||
rctSig genRctSimple(const key & message, const ctkeyV & inSk, const keyV & destinations, const std::vector<xmr_amount> & inamounts, const std::vector<xmr_amount> & outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const keyV &amount_keys, const std::vector<unsigned int> & index, ctkeyV &outSk);
|
||||
rctSig genRctSimple(const key & message, const ctkeyV & inSk, const keyV & destinations, const std::vector<xmr_amount> & inamounts, const std::vector<xmr_amount> & outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const keyV &amount_keys, const std::vector<unsigned int> & index, ctkeyV &outSk, bool bulletproof);
|
||||
bool verRct(const rctSig & rv, bool semantics);
|
||||
static inline bool verRct(const rctSig & rv) { return verRct(rv, true) && verRct(rv, false); }
|
||||
bool verRctSimple(const rctSig & rv, bool semantics);
|
||||
|
@ -161,6 +161,39 @@ namespace rct {
|
||||
FIELD(Ci)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct Bulletproof
|
||||
{
|
||||
rct::keyV V;
|
||||
rct::key A, S, T1, T2;
|
||||
rct::key taux, mu;
|
||||
rct::keyV L, R;
|
||||
rct::key a, b, t;
|
||||
|
||||
Bulletproof() {}
|
||||
Bulletproof(const rct::key &V, const rct::key &A, const rct::key &S, const rct::key &T1, const rct::key &T2, const rct::key &taux, const rct::key &mu, const rct::keyV &L, const rct::keyV &R, const rct::key &a, const rct::key &b, const rct::key &t):
|
||||
V({V}), A(A), S(S), T1(T1), T2(T2), taux(taux), mu(mu), L(L), R(R), a(a), b(b), t(t) {}
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
// Commitments aren't saved, they're restored via outPk
|
||||
// FIELD(V)
|
||||
FIELD(A)
|
||||
FIELD(S)
|
||||
FIELD(T1)
|
||||
FIELD(T2)
|
||||
FIELD(taux)
|
||||
FIELD(mu)
|
||||
FIELD(L)
|
||||
FIELD(R)
|
||||
FIELD(a)
|
||||
FIELD(b)
|
||||
FIELD(t)
|
||||
|
||||
if (L.empty() || L.size() != R.size())
|
||||
return false;
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
//A container to hold all signatures necessary for RingCT
|
||||
// rangeSigs holds all the rangeproof data of a transaction
|
||||
// MG holds the MLSAG signature of a transaction
|
||||
@ -172,6 +205,8 @@ namespace rct {
|
||||
RCTTypeNull = 0,
|
||||
RCTTypeFull = 1,
|
||||
RCTTypeSimple = 2,
|
||||
RCTTypeFullBulletproof = 3,
|
||||
RCTTypeSimpleBulletproof = 4,
|
||||
};
|
||||
struct rctSigBase {
|
||||
uint8_t type;
|
||||
@ -189,13 +224,13 @@ namespace rct {
|
||||
FIELD(type)
|
||||
if (type == RCTTypeNull)
|
||||
return true;
|
||||
if (type != RCTTypeFull && type != RCTTypeSimple)
|
||||
if (type != RCTTypeFull && type != RCTTypeFullBulletproof && type != RCTTypeSimple && type != RCTTypeSimpleBulletproof)
|
||||
return false;
|
||||
VARINT_FIELD(txnFee)
|
||||
// inputs/outputs not saved, only here for serialization help
|
||||
// FIELD(message) - not serialized, it can be reconstructed
|
||||
// FIELD(mixRing) - not serialized, it can be reconstructed
|
||||
if (type == RCTTypeSimple)
|
||||
if (type == RCTTypeSimple || type == RCTTypeSimpleBulletproof)
|
||||
{
|
||||
ar.tag("pseudoOuts");
|
||||
ar.begin_array();
|
||||
@ -241,6 +276,7 @@ namespace rct {
|
||||
};
|
||||
struct rctSigPrunable {
|
||||
std::vector<rangeSig> rangeSigs;
|
||||
std::vector<Bulletproof> bulletproofs;
|
||||
std::vector<mgSig> MGs; // simple rct has N, full has 1
|
||||
|
||||
template<bool W, template <bool> class Archive>
|
||||
@ -248,26 +284,44 @@ namespace rct {
|
||||
{
|
||||
if (type == RCTTypeNull)
|
||||
return true;
|
||||
if (type != RCTTypeFull && type != RCTTypeSimple)
|
||||
if (type != RCTTypeFull && type != RCTTypeFullBulletproof && type != RCTTypeSimple && type != RCTTypeSimpleBulletproof)
|
||||
return false;
|
||||
ar.tag("rangeSigs");
|
||||
ar.begin_array();
|
||||
PREPARE_CUSTOM_VECTOR_SERIALIZATION(outputs, rangeSigs);
|
||||
if (rangeSigs.size() != outputs)
|
||||
return false;
|
||||
for (size_t i = 0; i < outputs; ++i)
|
||||
if (type == RCTTypeSimpleBulletproof || type == RCTTypeFullBulletproof)
|
||||
{
|
||||
FIELDS(rangeSigs[i])
|
||||
if (outputs - i > 1)
|
||||
ar.delimit_array();
|
||||
ar.tag("bp");
|
||||
ar.begin_array();
|
||||
PREPARE_CUSTOM_VECTOR_SERIALIZATION(outputs, bulletproofs);
|
||||
if (bulletproofs.size() != outputs)
|
||||
return false;
|
||||
for (size_t i = 0; i < outputs; ++i)
|
||||
{
|
||||
FIELDS(bulletproofs[i])
|
||||
if (outputs - i > 1)
|
||||
ar.delimit_array();
|
||||
}
|
||||
ar.end_array();
|
||||
}
|
||||
else
|
||||
{
|
||||
ar.tag("rangeSigs");
|
||||
ar.begin_array();
|
||||
PREPARE_CUSTOM_VECTOR_SERIALIZATION(outputs, rangeSigs);
|
||||
if (rangeSigs.size() != outputs)
|
||||
return false;
|
||||
for (size_t i = 0; i < outputs; ++i)
|
||||
{
|
||||
FIELDS(rangeSigs[i])
|
||||
if (outputs - i > 1)
|
||||
ar.delimit_array();
|
||||
}
|
||||
ar.end_array();
|
||||
}
|
||||
ar.end_array();
|
||||
|
||||
ar.tag("MGs");
|
||||
ar.begin_array();
|
||||
// we keep a byte for size of MGs, because we don't know whether this is
|
||||
// a simple or full rct signature, and it's starting to annoy the hell out of me
|
||||
size_t mg_elements = type == RCTTypeSimple ? inputs : 1;
|
||||
size_t mg_elements = (type == RCTTypeSimple || type == RCTTypeSimpleBulletproof) ? inputs : 1;
|
||||
PREPARE_CUSTOM_VECTOR_SERIALIZATION(mg_elements, MGs);
|
||||
if (MGs.size() != mg_elements)
|
||||
return false;
|
||||
@ -285,7 +339,7 @@ namespace rct {
|
||||
for (size_t j = 0; j < mixin + 1; ++j)
|
||||
{
|
||||
ar.begin_array();
|
||||
size_t mg_ss2_elements = (type == RCTTypeSimple ? 1 : inputs) + 1;
|
||||
size_t mg_ss2_elements = ((type == RCTTypeSimple || type == RCTTypeSimpleBulletproof) ? 1 : inputs) + 1;
|
||||
PREPARE_CUSTOM_VECTOR_SERIALIZATION(mg_ss2_elements, MGs[i].ss[j]);
|
||||
if (MGs[i].ss[j].size() != mg_ss2_elements)
|
||||
return false;
|
||||
@ -464,6 +518,7 @@ VARIANT_TAG(debug_archive, rct::mgSig, "rct::mgSig");
|
||||
VARIANT_TAG(debug_archive, rct::rangeSig, "rct::rangeSig");
|
||||
VARIANT_TAG(debug_archive, rct::boroSig, "rct::boroSig");
|
||||
VARIANT_TAG(debug_archive, rct::rctSig, "rct::rctSig");
|
||||
VARIANT_TAG(debug_archive, rct::Bulletproof, "rct::bulletproof");
|
||||
|
||||
VARIANT_TAG(binary_archive, rct::key, 0x90);
|
||||
VARIANT_TAG(binary_archive, rct::key64, 0x91);
|
||||
@ -477,6 +532,7 @@ VARIANT_TAG(binary_archive, rct::mgSig, 0x98);
|
||||
VARIANT_TAG(binary_archive, rct::rangeSig, 0x99);
|
||||
VARIANT_TAG(binary_archive, rct::boroSig, 0x9a);
|
||||
VARIANT_TAG(binary_archive, rct::rctSig, 0x9b);
|
||||
VARIANT_TAG(binary_archive, rct::Bulletproof, 0x9c);
|
||||
|
||||
VARIANT_TAG(json_archive, rct::key, "rct_key");
|
||||
VARIANT_TAG(json_archive, rct::key64, "rct_key64");
|
||||
@ -490,5 +546,6 @@ VARIANT_TAG(json_archive, rct::mgSig, "rct_mgSig");
|
||||
VARIANT_TAG(json_archive, rct::rangeSig, "rct_rangeSig");
|
||||
VARIANT_TAG(json_archive, rct::boroSig, "rct_boroSig");
|
||||
VARIANT_TAG(json_archive, rct::rctSig, "rct_rctSig");
|
||||
VARIANT_TAG(json_archive, rct::Bulletproof, "rct_bulletproof");
|
||||
|
||||
#endif /* RCTTYPES_H */
|
||||
|
@ -1007,6 +1007,7 @@ void toJsonValue(rapidjson::Document& doc, const rct::rctSigPrunable& sig, rapid
|
||||
val.SetObject();
|
||||
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, rangeSigs, sig.rangeSigs);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, bulletproofs, sig.bulletproofs);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, MGs, sig.MGs);
|
||||
}
|
||||
|
||||
@ -1018,6 +1019,7 @@ void fromJsonValue(const rapidjson::Value& val, rct::rctSigPrunable& sig)
|
||||
}
|
||||
|
||||
GET_FROM_JSON_OBJECT(val, sig.rangeSigs, rangeSigs);
|
||||
GET_FROM_JSON_OBJECT(val, sig.bulletproofs, bulletproofs);
|
||||
GET_FROM_JSON_OBJECT(val, sig.MGs, MGs);
|
||||
}
|
||||
|
||||
@ -1052,6 +1054,45 @@ void fromJsonValue(const rapidjson::Value& val, rct::rangeSig& sig)
|
||||
}
|
||||
}
|
||||
|
||||
void toJsonValue(rapidjson::Document& doc, const rct::Bulletproof& p, rapidjson::Value& val)
|
||||
{
|
||||
val.SetObject();
|
||||
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, V, p.V);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, A, p.A);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, S, p.S);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, T1, p.T1);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, T2, p.T2);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, taux, p.taux);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, mu, p.mu);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, L, p.L);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, R, p.R);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, a, p.a);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, b, p.b);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, t, p.t);
|
||||
}
|
||||
|
||||
void fromJsonValue(const rapidjson::Value& val, rct::Bulletproof& p)
|
||||
{
|
||||
if (!val.IsObject())
|
||||
{
|
||||
throw WRONG_TYPE("json object");
|
||||
}
|
||||
|
||||
GET_FROM_JSON_OBJECT(val, p.V, V);
|
||||
GET_FROM_JSON_OBJECT(val, p.A, A);
|
||||
GET_FROM_JSON_OBJECT(val, p.S, S);
|
||||
GET_FROM_JSON_OBJECT(val, p.T1, T1);
|
||||
GET_FROM_JSON_OBJECT(val, p.T2, T2);
|
||||
GET_FROM_JSON_OBJECT(val, p.taux, taux);
|
||||
GET_FROM_JSON_OBJECT(val, p.mu, mu);
|
||||
GET_FROM_JSON_OBJECT(val, p.L, L);
|
||||
GET_FROM_JSON_OBJECT(val, p.R, R);
|
||||
GET_FROM_JSON_OBJECT(val, p.a, a);
|
||||
GET_FROM_JSON_OBJECT(val, p.b, b);
|
||||
GET_FROM_JSON_OBJECT(val, p.t, t);
|
||||
}
|
||||
|
||||
void toJsonValue(rapidjson::Document& doc, const rct::boroSig& sig, rapidjson::Value& val)
|
||||
{
|
||||
val.SetObject();
|
||||
|
@ -274,6 +274,9 @@ void fromJsonValue(const rapidjson::Value& val, rct::rctSigPrunable& sig);
|
||||
void toJsonValue(rapidjson::Document& doc, const rct::rangeSig& sig, rapidjson::Value& val);
|
||||
void fromJsonValue(const rapidjson::Value& val, rct::rangeSig& sig);
|
||||
|
||||
void toJsonValue(rapidjson::Document& doc, const rct::Bulletproof& p, rapidjson::Value& val);
|
||||
void fromJsonValue(const rapidjson::Value& val, rct::Bulletproof& p);
|
||||
|
||||
void toJsonValue(rapidjson::Document& doc, const rct::boroSig& sig, rapidjson::Value& val);
|
||||
void fromJsonValue(const rapidjson::Value& val, rct::boroSig& sig);
|
||||
|
||||
|
@ -456,7 +456,7 @@ void drop_from_short_history(std::list<crypto::hash> &short_chain_history, size_
|
||||
}
|
||||
}
|
||||
|
||||
size_t estimate_rct_tx_size(int n_inputs, int mixin, int n_outputs, size_t extra_size)
|
||||
size_t estimate_rct_tx_size(int n_inputs, int mixin, int n_outputs, size_t extra_size, bool bulletproof)
|
||||
{
|
||||
size_t size = 0;
|
||||
|
||||
@ -480,7 +480,10 @@ size_t estimate_rct_tx_size(int n_inputs, int mixin, int n_outputs, size_t extra
|
||||
size += 1;
|
||||
|
||||
// rangeSigs
|
||||
size += (2*64*32+32+64*32) * n_outputs;
|
||||
if (bulletproof)
|
||||
size += ((2*6 + 4 + 5)*32 + 3) * n_outputs;
|
||||
else
|
||||
size += (2*64*32+32+64*32) * n_outputs;
|
||||
|
||||
// MGs
|
||||
size += n_inputs * (64 * (mixin+1) + 32);
|
||||
@ -501,14 +504,22 @@ size_t estimate_rct_tx_size(int n_inputs, int mixin, int n_outputs, size_t extra
|
||||
return size;
|
||||
}
|
||||
|
||||
size_t estimate_tx_size(bool use_rct, int n_inputs, int mixin, int n_outputs, size_t extra_size)
|
||||
size_t estimate_tx_size(bool use_rct, int n_inputs, int mixin, int n_outputs, size_t extra_size, bool bulletproof)
|
||||
{
|
||||
if (use_rct)
|
||||
return estimate_rct_tx_size(n_inputs, mixin, n_outputs + 1, extra_size);
|
||||
return estimate_rct_tx_size(n_inputs, mixin, n_outputs + 1, extra_size, bulletproof);
|
||||
else
|
||||
return n_inputs * (mixin+1) * APPROXIMATE_INPUT_BYTES + extra_size;
|
||||
}
|
||||
|
||||
uint8_t get_bulletproof_fork(bool testnet)
|
||||
{
|
||||
if (testnet)
|
||||
return 7;
|
||||
else
|
||||
return 255; // TODO
|
||||
}
|
||||
|
||||
} //namespace
|
||||
|
||||
namespace tools
|
||||
@ -812,8 +823,10 @@ static uint64_t decodeRct(const rct::rctSig & rv, const crypto::key_derivation &
|
||||
switch (rv.type)
|
||||
{
|
||||
case rct::RCTTypeSimple:
|
||||
case rct::RCTTypeSimpleBulletproof:
|
||||
return rct::decodeRctSimple(rv, rct::sk2rct(scalar1), i, mask);
|
||||
case rct::RCTTypeFull:
|
||||
case rct::RCTTypeFullBulletproof:
|
||||
return rct::decodeRct(rv, rct::sk2rct(scalar1), i, mask);
|
||||
default:
|
||||
LOG_ERROR("Unsupported rct type: " << rv.type);
|
||||
@ -3763,9 +3776,10 @@ bool wallet2::sign_tx(unsigned_tx_set &exported_txs, const std::string &signed_f
|
||||
LOG_PRINT_L1(" " << (n+1) << ": " << sd.sources.size() << " inputs, ring size " << sd.sources[0].outputs.size());
|
||||
signed_txes.ptx.push_back(pending_tx());
|
||||
tools::wallet2::pending_tx &ptx = signed_txes.ptx.back();
|
||||
bool bulletproof = sd.use_rct && !ptx.tx.rct_signatures.p.bulletproofs.empty();
|
||||
crypto::secret_key tx_key;
|
||||
std::vector<crypto::secret_key> additional_tx_keys;
|
||||
bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sd.sources, sd.splitted_dsts, sd.change_dts.addr, sd.extra, ptx.tx, sd.unlock_time, tx_key, additional_tx_keys, sd.use_rct);
|
||||
bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sd.sources, sd.splitted_dsts, sd.change_dts.addr, sd.extra, ptx.tx, sd.unlock_time, tx_key, additional_tx_keys, sd.use_rct, bulletproof);
|
||||
THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sd.sources, sd.splitted_dsts, sd.unlock_time, m_testnet);
|
||||
// we don't test tx size, because we don't know the current limit, due to not having a blockchain,
|
||||
// and it's a bit pointless to fail there anyway, since it'd be a (good) guess only. We sign anyway,
|
||||
@ -4066,7 +4080,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions(std::vector<crypto
|
||||
pending_tx ptx;
|
||||
|
||||
// loop until fee is met without increasing tx size to next KB boundary.
|
||||
const size_t estimated_tx_size = estimate_tx_size(false, unused_transfers_indices.size(), fake_outs_count, dst_vector.size(), extra.size());
|
||||
const size_t estimated_tx_size = estimate_tx_size(false, unused_transfers_indices.size(), fake_outs_count, dst_vector.size(), extra.size(), false);
|
||||
uint64_t needed_fee = calculate_fee(fee_per_kb, estimated_tx_size, fee_multiplier);
|
||||
do
|
||||
{
|
||||
@ -4648,7 +4662,7 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent
|
||||
|
||||
void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry> dsts, const std::vector<size_t>& selected_transfers, size_t fake_outputs_count,
|
||||
std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs,
|
||||
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, cryptonote::transaction& tx, pending_tx &ptx)
|
||||
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, cryptonote::transaction& tx, pending_tx &ptx, bool bulletproof)
|
||||
{
|
||||
using namespace cryptonote;
|
||||
// throw if attempting a transaction with no destinations
|
||||
@ -4764,7 +4778,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
|
||||
crypto::secret_key tx_key;
|
||||
std::vector<crypto::secret_key> additional_tx_keys;
|
||||
LOG_PRINT_L2("constructing tx");
|
||||
bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sources, splitted_dsts, change_dts.addr, extra, tx, unlock_time, tx_key, additional_tx_keys, true);
|
||||
bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sources, splitted_dsts, change_dts.addr, extra, tx, unlock_time, tx_key, additional_tx_keys, true, bulletproof);
|
||||
LOG_PRINT_L2("constructed tx, r="<<r);
|
||||
THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, dsts, unlock_time, m_testnet);
|
||||
THROW_WALLET_EXCEPTION_IF(upper_transaction_size_limit <= get_object_blobsize(tx), error::tx_too_big, tx, upper_transaction_size_limit);
|
||||
@ -5432,6 +5446,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
|
||||
uint64_t needed_fee, available_for_fee = 0;
|
||||
uint64_t upper_transaction_size_limit = get_upper_transaction_size_limit();
|
||||
const bool use_rct = use_fork_rules(4, 0);
|
||||
const bool bulletproof = use_fork_rules(get_bulletproof_fork(m_testnet), 0);
|
||||
|
||||
const uint64_t fee_per_kb = get_per_kb_fee();
|
||||
const uint64_t fee_multiplier = get_fee_multiplier(priority, get_fee_algorithm());
|
||||
@ -5567,7 +5582,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
|
||||
{
|
||||
// this is used to build a tx that's 1 or 2 inputs, and 2 outputs, which
|
||||
// will get us a known fee.
|
||||
uint64_t estimated_fee = calculate_fee(fee_per_kb, estimate_rct_tx_size(2, fake_outs_count, 2, extra.size()), fee_multiplier);
|
||||
uint64_t estimated_fee = calculate_fee(fee_per_kb, estimate_rct_tx_size(2, fake_outs_count, 2, extra.size(), bulletproof), fee_multiplier);
|
||||
preferred_inputs = pick_preferred_rct_inputs(needed_money + estimated_fee, subaddr_account, subaddr_indices);
|
||||
if (!preferred_inputs.empty())
|
||||
{
|
||||
@ -5670,7 +5685,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
|
||||
}
|
||||
else
|
||||
{
|
||||
while (!dsts.empty() && dsts[0].amount <= available_amount && estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size(), extra.size()) < TX_SIZE_TARGET(upper_transaction_size_limit))
|
||||
while (!dsts.empty() && dsts[0].amount <= available_amount && estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size(), extra.size(), bulletproof) < TX_SIZE_TARGET(upper_transaction_size_limit))
|
||||
{
|
||||
// we can fully pay that destination
|
||||
LOG_PRINT_L2("We can fully pay " << get_account_address_as_str(m_testnet, dsts[0].is_subaddress, dsts[0].addr) <<
|
||||
@ -5682,7 +5697,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
|
||||
++original_output_index;
|
||||
}
|
||||
|
||||
if (available_amount > 0 && !dsts.empty() && estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size(), extra.size()) < TX_SIZE_TARGET(upper_transaction_size_limit)) {
|
||||
if (available_amount > 0 && !dsts.empty() && estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size(), extra.size(), bulletproof) < TX_SIZE_TARGET(upper_transaction_size_limit)) {
|
||||
// we can partially fill that destination
|
||||
LOG_PRINT_L2("We can partially pay " << get_account_address_as_str(m_testnet, dsts[0].is_subaddress, dsts[0].addr) <<
|
||||
" for " << print_money(available_amount) << "/" << print_money(dsts[0].amount));
|
||||
@ -5706,7 +5721,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
|
||||
}
|
||||
else
|
||||
{
|
||||
const size_t estimated_rct_tx_size = estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size(), extra.size());
|
||||
const size_t estimated_rct_tx_size = estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size(), extra.size(), bulletproof);
|
||||
try_tx = dsts.empty() || (estimated_rct_tx_size >= TX_SIZE_TARGET(upper_transaction_size_limit));
|
||||
}
|
||||
}
|
||||
@ -5715,14 +5730,14 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
|
||||
cryptonote::transaction test_tx;
|
||||
pending_tx test_ptx;
|
||||
|
||||
const size_t estimated_tx_size = estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size(), extra.size());
|
||||
const size_t estimated_tx_size = estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size(), extra.size(), bulletproof);
|
||||
needed_fee = calculate_fee(fee_per_kb, estimated_tx_size, fee_multiplier);
|
||||
|
||||
LOG_PRINT_L2("Trying to create a tx now, with " << tx.dsts.size() << " outputs and " <<
|
||||
tx.selected_transfers.size() << " inputs");
|
||||
if (use_rct)
|
||||
transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra,
|
||||
test_tx, test_ptx);
|
||||
test_tx, test_ptx, bulletproof);
|
||||
else
|
||||
transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra,
|
||||
detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx);
|
||||
@ -5765,7 +5780,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
|
||||
while (needed_fee > test_ptx.fee) {
|
||||
if (use_rct)
|
||||
transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra,
|
||||
test_tx, test_ptx);
|
||||
test_tx, test_ptx, bulletproof);
|
||||
else
|
||||
transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra,
|
||||
detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx);
|
||||
@ -5917,6 +5932,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
|
||||
std::vector<std::vector<get_outs_entry>> outs;
|
||||
|
||||
const bool use_rct = fake_outs_count > 0 && use_fork_rules(4, 0);
|
||||
const bool bulletproof = use_fork_rules(get_bulletproof_fork(m_testnet), 0);
|
||||
const uint64_t fee_per_kb = get_per_kb_fee();
|
||||
const uint64_t fee_multiplier = get_fee_multiplier(priority, get_fee_algorithm());
|
||||
|
||||
@ -5955,14 +5971,14 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
|
||||
// here, check if we need to sent tx and start a new one
|
||||
LOG_PRINT_L2("Considering whether to create a tx now, " << tx.selected_transfers.size() << " inputs, tx limit "
|
||||
<< upper_transaction_size_limit);
|
||||
const size_t estimated_rct_tx_size = estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size() + 1, extra.size());
|
||||
const size_t estimated_rct_tx_size = estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size() + 1, extra.size(), bulletproof);
|
||||
bool try_tx = (unused_dust_indices.empty() && unused_transfers_indices.empty()) || ( estimated_rct_tx_size >= TX_SIZE_TARGET(upper_transaction_size_limit));
|
||||
|
||||
if (try_tx) {
|
||||
cryptonote::transaction test_tx;
|
||||
pending_tx test_ptx;
|
||||
|
||||
const size_t estimated_tx_size = estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size(), extra.size());
|
||||
const size_t estimated_tx_size = estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size(), extra.size(), bulletproof);
|
||||
needed_fee = calculate_fee(fee_per_kb, estimated_tx_size, fee_multiplier);
|
||||
|
||||
tx.dsts.push_back(tx_destination_entry(1, address, is_subaddress));
|
||||
@ -5971,7 +5987,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
|
||||
tx.selected_transfers.size() << " outputs");
|
||||
if (use_rct)
|
||||
transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra,
|
||||
test_tx, test_ptx);
|
||||
test_tx, test_ptx, bulletproof);
|
||||
else
|
||||
transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra,
|
||||
detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx);
|
||||
@ -5988,7 +6004,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
|
||||
tx.dsts[0].amount = available_for_fee - needed_fee;
|
||||
if (use_rct)
|
||||
transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra,
|
||||
test_tx, test_ptx);
|
||||
test_tx, test_ptx, bulletproof);
|
||||
else
|
||||
transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra,
|
||||
detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx);
|
||||
|
@ -536,7 +536,7 @@ namespace tools
|
||||
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction& tx, pending_tx &ptx);
|
||||
void transfer_selected_rct(std::vector<cryptonote::tx_destination_entry> dsts, const std::vector<size_t>& selected_transfers, size_t fake_outputs_count,
|
||||
std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs,
|
||||
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, cryptonote::transaction& tx, pending_tx &ptx);
|
||||
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, cryptonote::transaction& tx, pending_tx &ptx, bool bulletproof);
|
||||
|
||||
void commit_tx(pending_tx& ptx_vector);
|
||||
void commit_tx(std::vector<pending_tx>& ptx_vector);
|
||||
|
@ -132,7 +132,7 @@ bool gen_rct_tx_validation_base::generate_with(std::vector<test_event_entry>& ev
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to generate key derivation");
|
||||
crypto::secret_key amount_key;
|
||||
crypto::derivation_to_scalar(derivation, o, amount_key);
|
||||
if (rct_txes[n].rct_signatures.type == rct::RCTTypeSimple)
|
||||
if (rct_txes[n].rct_signatures.type == rct::RCTTypeSimple || rct_txes[n].rct_signatures.type == rct::RCTTypeSimpleBulletproof)
|
||||
rct::decodeRctSimple(rct_txes[n].rct_signatures, rct::sk2rct(amount_key), o, rct_tx_masks[o+n*4]);
|
||||
else
|
||||
rct::decodeRct(rct_txes[n].rct_signatures, rct::sk2rct(amount_key), o, rct_tx_masks[o+n*4]);
|
||||
|
@ -80,7 +80,7 @@ public:
|
||||
{
|
||||
if (rct)
|
||||
{
|
||||
if (m_tx.rct_signatures.type == rct::RCTTypeFull)
|
||||
if (m_tx.rct_signatures.type == rct::RCTTypeFull || m_tx.rct_signatures.type == rct::RCTTypeFullBulletproof)
|
||||
return rct::verRct(m_tx.rct_signatures);
|
||||
else
|
||||
return rct::verRctSimple(m_tx.rct_signatures);
|
||||
|
@ -34,6 +34,7 @@ set(unit_tests_sources
|
||||
blockchain_db.cpp
|
||||
block_queue.cpp
|
||||
block_reward.cpp
|
||||
bulletproofs.cpp
|
||||
canonical_amounts.cpp
|
||||
chacha8.cpp
|
||||
checkpoints.cpp
|
||||
|
71
tests/unit_tests/bulletproofs.cpp
Normal file
71
tests/unit_tests/bulletproofs.cpp
Normal file
@ -0,0 +1,71 @@
|
||||
// Copyright (c) 2017, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "ringct/rctOps.h"
|
||||
#include "ringct/bulletproofs.h"
|
||||
|
||||
TEST(bulletproofs, valid_zero)
|
||||
{
|
||||
rct::Bulletproof proof = bulletproof_PROVE(0, rct::skGen());
|
||||
ASSERT_TRUE(rct::bulletproof_VERIFY(proof));
|
||||
}
|
||||
|
||||
TEST(bulletproofs, valid_max)
|
||||
{
|
||||
rct::Bulletproof proof = bulletproof_PROVE(0xffffffffffffffff, rct::skGen());
|
||||
ASSERT_TRUE(rct::bulletproof_VERIFY(proof));
|
||||
}
|
||||
|
||||
TEST(bulletproofs, valid_random)
|
||||
{
|
||||
for (int n = 0; n < 8; ++n)
|
||||
{
|
||||
rct::Bulletproof proof = bulletproof_PROVE(crypto::rand<uint64_t>(), rct::skGen());
|
||||
ASSERT_TRUE(rct::bulletproof_VERIFY(proof));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(bulletproofs, invalid_8)
|
||||
{
|
||||
rct::key invalid_amount = rct::zero();
|
||||
invalid_amount[8] = 1;
|
||||
rct::Bulletproof proof = bulletproof_PROVE(invalid_amount, rct::skGen());
|
||||
ASSERT_FALSE(rct::bulletproof_VERIFY(proof));
|
||||
}
|
||||
|
||||
TEST(bulletproofs, invalid_31)
|
||||
{
|
||||
rct::key invalid_amount = rct::zero();
|
||||
invalid_amount[31] = 1;
|
||||
rct::Bulletproof proof = bulletproof_PROVE(invalid_amount, rct::skGen());
|
||||
ASSERT_FALSE(rct::bulletproof_VERIFY(proof));
|
||||
}
|
Loading…
Reference in New Issue
Block a user