From 654208769fbfb148321140841e74f08b8798c988 Mon Sep 17 00:00:00 2001 From: Ian Goldberg Date: Mon, 3 May 2021 14:59:55 -0400 Subject: [PATCH] Up the max level to 4 and add the ZKP for the max number of blockages allowed in the level up protocol --- crates/lox-library/src/proto/level_up.rs | 120 ++++++++++++++++-- .../lox-library/src/proto/trust_promotion.rs | 2 +- 2 files changed, 112 insertions(+), 10 deletions(-) diff --git a/crates/lox-library/src/proto/level_up.rs b/crates/lox-library/src/proto/level_up.rs index 1b6d924..9eafe96 100644 --- a/crates/lox-library/src/proto/level_up.rs +++ b/crates/lox-library/src/proto/level_up.rs @@ -57,20 +57,26 @@ use super::super::{CMZ_A, CMZ_A_TABLE, CMZ_B, CMZ_B_TABLE}; /// upgrade protocol when they're already at the max level; they will /// get a fresh invites_remaining batch, and reset their level_since /// field to today's date, but will remain in the max level. -pub const MAX_LEVEL: usize = 3; +pub const MAX_LEVEL: usize = 4; /// LEVEL_INTERVAL\[i\] for i >= 1 is the minimum number of days a user /// must be at trust level i before advancing to level i+1 (or as above, /// remain at level i if i == MAX_LEVEL). Note that the /// LEVEL_INTERVAL\[0\] entry is a dummy; the trust_promotion protocol /// is used instead of this one to move from level 0 to level 1. -pub const LEVEL_INTERVAL: [u32; MAX_LEVEL + 1] = [0, 14, 28, 56]; +pub const LEVEL_INTERVAL: [u32; MAX_LEVEL + 1] = [0, 14, 28, 56, 84]; /// LEVEL_INVITATIONS\[i\] for i >= 1 is the number of invitations a /// user will be eligible to issue upon advancing from level i to level /// i+1. Again the LEVEL_INVITATIONS\[0\] entry is a dummy, as for /// LEVEL_INTERVAL. -pub const LEVEL_INVITATIONS: [u32; MAX_LEVEL + 1] = [0, 2, 4, 6]; +pub const LEVEL_INVITATIONS: [u32; MAX_LEVEL + 1] = [0, 2, 4, 6, 8]; + +/// MAX_BLOCKAGES\[i\] for i >= 1 is the maximum number of bucket +/// blockages this credential is allowed to have recorded in order to +/// advance from level i to level i+1. Again the LEVEL_INVITATIONS\[0\] +/// entry is a dummy, as for LEVEL_INTERVAL. +pub const MAX_BLOCKAGES: [u32; MAX_LEVEL + 1] = [0, 4, 3, 2, 2]; pub struct Request { // Fields for blind showing the Lox credential @@ -88,8 +94,8 @@ pub struct Request { CBucket_reach: RistrettoPoint, CQ_reach: RistrettoPoint, - // Fields for the inequality proof (level_since + - // LEVEL_INTERVAL[level] <= today) + // Fields for the inequality proof + // level_since + LEVEL_INTERVAL[level] <= today CG1: RistrettoPoint, CG2: RistrettoPoint, CG3: RistrettoPoint, @@ -108,6 +114,14 @@ pub struct Request { CG7sq: RistrettoPoint, CG8sq: RistrettoPoint, + // Fields for the inequality proof + // blockages <= MAX_BLOCKAGES[level] + CH1: RistrettoPoint, + CH2: RistrettoPoint, + CH0sq: RistrettoPoint, + CH1sq: RistrettoPoint, + CH2sq: RistrettoPoint, + // Fields for user blinding of the Lox credential to be issued D: RistrettoPoint, EncIdClient: (RistrettoPoint, RistrettoPoint), @@ -158,14 +172,20 @@ define_proof! { g0, g1, g2, g3, g4, g5, g6, g7, g8, zg0, zg1, zg2, zg3, zg4, zg5, zg6, zg7, zg8, wg0, wg1, wg2, wg3, wg4, wg5, wg6, wg7, wg8, - yg0, yg1, yg2, yg3, yg4, yg5, yg6, yg7, yg8), + yg0, yg1, yg2, yg3, yg4, yg5, yg6, yg7, yg8, + h0, h1, h2, + zh0, zh1, zh2, + wh0, wh1, wh2, + yh0, yh1, yh2), (P, CBucket, CSince, CInvRemain, CBlockages, V, Xbucket, Xsince, Xinvremain, Xblockages, P_reach, CBucket_reach, V_reach, Xbucket_reach, D, EncIdClient0, EncIdClient1, EncBucket0, EncBucket1, EncBlockages0, EncBlockages1, CG0, CG1, CG2, CG3, CG4, CG5, CG6, CG7, CG8, - CG0sq, CG1sq, CG2sq, CG3sq, CG4sq, CG5sq, CG6sq, CG7sq, CG8sq), + CG0sq, CG1sq, CG2sq, CG3sq, CG4sq, CG5sq, CG6sq, CG7sq, CG8sq, + CH0, CH1, CH2, + CH0sq, CH1sq, CH2sq), (A, B) : // Blind showing of the Lox credential CBucket = (bucket*P + zbucket*A), @@ -184,7 +204,7 @@ define_proof! { EncBlockages0 = (eblockages*B), EncBlockages1 = (blockages*B + eblockages*D), // Prove CSince encodes a value at least LEVEL_INTERVAL - // days ago (at technically at most LEVEL_INTERVAL+511 days + // days ago (and technically at most LEVEL_INTERVAL+511 days // ago): first prove each of g0, ..., g8 is a bit by proving that // gi = gi^2 CG0 = (g0*P + zg0*A), CG0sq = (g0*CG0 + wg0*A), CG0sq = (g0*P + yg0*A), @@ -195,11 +215,20 @@ define_proof! { CG5 = (g5*P + zg5*A), CG5sq = (g5*CG5 + wg5*A), CG5sq = (g5*P + yg5*A), CG6 = (g6*P + zg6*A), CG6sq = (g6*CG6 + wg6*A), CG6sq = (g6*P + yg6*A), CG7 = (g7*P + zg7*A), CG7sq = (g7*CG7 + wg7*A), CG7sq = (g7*P + yg7*A), - CG8 = (g8*P + zg8*A), CG8sq = (g8*CG8 + wg8*A), CG8sq = (g8*P + yg8*A) + CG8 = (g8*P + zg8*A), CG8sq = (g8*CG8 + wg8*A), CG8sq = (g8*P + yg8*A), // Then we'll check that CSince + LEVEL_INTERVAL*P + CG0 + 2*CG1 // + 4*CG2 + 8*CG3 + ... + 256*CG8 = today*P by having the verifier // plug in today*P - (CSince + LEVEL_INTERVAL*P + 2*CG1 + 4*CG2 // + ... + 256*CG8) as its value of CG0. + + // Prove CBlockage encodes a value at most MAX_BLOCKAGES (and at least + // MAX_BLOCKAGES-7) + CH0 = (h0*P + zh0*A), CH0sq = (h0*CH0 + wh0*A), CH0sq = (h0*P + yh0*A), + CH1 = (h1*P + zh1*A), CH1sq = (h1*CH1 + wh1*A), CH1sq = (h1*P + yh1*A), + CH2 = (h2*P + zh2*A), CH2sq = (h2*CH2 + wh2*A), CH2sq = (h2*P + yh2*A) + // Then we'll check that CBlockage + CH0 + 2*CH1 + 4*CH2 = + // MAX_BLOCKAGES*P by having the verifier plug in MAX_BLOCKAGES*P - + // (CBlockage - 2*CH1 - 4*CH2) as its value of CH0. } define_proof! { @@ -271,6 +300,15 @@ pub fn request( if diffdays > 511 { return Err(ProofError::VerificationFailure); } + // The current number of blockages + let blockages: u32 = match scalar_u32(&lox_cred.blockages) { + Some(v) => v, + None => return Err(ProofError::VerificationFailure), + }; + if blockages > MAX_BLOCKAGES[trust_level as usize] { + return Err(ProofError::VerificationFailure); + } + let blockage_diff = MAX_BLOCKAGES[trust_level as usize] - blockages; // The buckets in the Lox and Bucket Reachability credentials have // to match if lox_cred.bucket != reach_cred.bucket { @@ -445,6 +483,37 @@ pub fn request( let CG7sq = g7 * P + &yg7 * Atable; let CG8sq = g8 * P + &yg8 * Atable; + // The range proof that 0 <= blockage_diff <= 7 + + // Extract the 3 bits from blockage_diff + let h0: Scalar = (blockage_diff & 1).into(); + let h1: Scalar = ((blockage_diff >> 1) & 1).into(); + let h2: Scalar = ((blockage_diff >> 2) & 1).into(); + + // Pick random factors for the Pedersen commitments + let wh0 = Scalar::random(&mut rng); + let zh1 = Scalar::random(&mut rng); + let wh1 = Scalar::random(&mut rng); + let zh2 = Scalar::random(&mut rng); + let wh2 = Scalar::random(&mut rng); + + // Compute zh0 to cancel things out as + // zh0 = -(zblockages + 2*zh1 + 4*zh2) + // but use Horner's method + let zh0 = -(scalar_dbl(&(scalar_dbl(&zh2) + zh1)) + zblockages); + + let yh0 = wh0 + h0 * zh0; + let yh1 = wh1 + h1 * zh1; + let yh2 = wh2 + h2 * zh2; + + let CH0 = h0 * P + &zh0 * Atable; + let CH1 = h1 * P + &zh1 * Atable; + let CH2 = h2 * P + &zh2 * Atable; + + let CH0sq = h0 * P + &yh0 * Atable; + let CH1sq = h1 * P + &yh1 * Atable; + let CH2sq = h2 * P + &yh2 * Atable; + // Construct the proof let mut transcript = Transcript::new(b"level upgrade request"); let piUser = requestproof::prove_compact( @@ -491,6 +560,12 @@ pub fn request( CG6sq: &CG6sq, CG7sq: &CG7sq, CG8sq: &CG8sq, + CH0: &CH0, + CH1: &CH1, + CH2: &CH2, + CH0sq: &CH0sq, + CH1sq: &CH1sq, + CH2sq: &CH2sq, bucket: &lox_cred.bucket, since: &lox_cred.level_since, invremain: &lox_cred.invites_remaining, @@ -543,6 +618,18 @@ pub fn request( yg6: &yg6, yg7: &yg7, yg8: &yg8, + h0: &h0, + h1: &h1, + h2: &h2, + zh0: &zh0, + zh1: &zh1, + zh2: &zh2, + wh0: &wh0, + wh1: &wh1, + wh2: &wh2, + yh0: &yh0, + yh1: &yh1, + yh2: &yh2, }, ) .0; @@ -581,6 +668,11 @@ pub fn request( CG6sq, CG7sq, CG8sq, + CH1, + CH2, + CH0sq, + CH1sq, + CH2sq, piUser, }, State { @@ -652,6 +744,10 @@ impl BridgeAuth { ) + req.CG1), ); + // Recompute CH0 using Horner's method + let mblk: Scalar = MAX_BLOCKAGES[level].into(); + let CH0prime = mblk * req.P - req.CBlockages - pt_dbl(&(pt_dbl(&req.CH2) + req.CH1)); + // Verify the ZKP let mut transcript = Transcript::new(b"level upgrade request"); requestproof::verify_compact( @@ -699,6 +795,12 @@ impl BridgeAuth { CG6sq: &req.CG6sq.compress(), CG7sq: &req.CG7sq.compress(), CG8sq: &req.CG8sq.compress(), + CH0: &CH0prime.compress(), + CH1: &req.CH1.compress(), + CH2: &req.CH2.compress(), + CH0sq: &req.CH0sq.compress(), + CH1sq: &req.CH1sq.compress(), + CH2sq: &req.CH2sq.compress(), }, )?; diff --git a/crates/lox-library/src/proto/trust_promotion.rs b/crates/lox-library/src/proto/trust_promotion.rs index 92a68c9..81ebab8 100644 --- a/crates/lox-library/src/proto/trust_promotion.rs +++ b/crates/lox-library/src/proto/trust_promotion.rs @@ -136,7 +136,7 @@ define_proof! { EncBucket1 = (bucket*B + ebucket*D), D = (d*B), // Prove CSince encodes a value at least UNTRUSTED_INTERVAL - // days ago (at technically at most UNTRUSTED_INTERVAL+511 days + // days ago (and technically at most UNTRUSTED_INTERVAL+511 days // ago): first prove each of g0, ..., g8 is a bit by proving that // gi = gi^2 CG0 = (g0*P + zg0*A), CG0sq = (g0*CG0 + wg0*A), CG0sq = (g0*P + yg0*A),