Begin work on LV3+ proof for Troll patrol positive reports
This commit is contained in:
parent
0041116e65
commit
a6c5d789e7
|
@ -999,6 +999,7 @@ pub mod proto {
|
|||
pub mod level_up;
|
||||
pub mod migration;
|
||||
pub mod open_invite;
|
||||
pub mod positive_report;
|
||||
pub mod redeem_invite;
|
||||
pub mod trust_promotion;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,233 @@
|
|||
/*! A module to allow a user to prove they have trust level 3 or greater
|
||||
and a particular bucket. This is used by Troll Patrol for positive
|
||||
reports (indicating that a bridge has been accessed).
|
||||
|
||||
The user presents their current Lox credential:
|
||||
- id: blinded
|
||||
- bucket: blinded (but proven to be beta in provided beta*H)
|
||||
- trust_level: revealed to be 3 or higher
|
||||
- level_since: blinded
|
||||
- invites_remaining: blinded
|
||||
- blockages: blinded
|
||||
|
||||
This protocol does not expose the credential's ID and does not issue a
|
||||
new Lox credential. The user does not receive a response.
|
||||
|
||||
Right now, this doesn't work. Also, it doesn't yet check the user's bucket,
|
||||
so it's just "Prove that the user's level is at least 3."
|
||||
|
||||
*/
|
||||
|
||||
use curve25519_dalek::ristretto::{RistrettoBasepointTable, RistrettoPoint};
|
||||
use curve25519_dalek::scalar::Scalar;
|
||||
use curve25519_dalek::traits::IsIdentity;
|
||||
|
||||
use lox_zkp::{CompactProof, ProofError, Transcript};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::super::cred;
|
||||
use super::super::scalar_u32;
|
||||
use super::super::{BridgeAuth, IssuerPubKey};
|
||||
use super::super::{CMZ_A, CMZ_A_TABLE};
|
||||
|
||||
pub const MIN_TRUST_LEVEL: u32 = 3;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Request {
|
||||
// Fields for blind showing the Lox credential
|
||||
P: RistrettoPoint,
|
||||
CId: RistrettoPoint,
|
||||
CBucket: RistrettoPoint,
|
||||
level: Scalar,
|
||||
CSince: RistrettoPoint,
|
||||
CInvRemain: RistrettoPoint,
|
||||
CBlockages: RistrettoPoint,
|
||||
CQ: RistrettoPoint,
|
||||
|
||||
// The combined lox_zkp
|
||||
piUser: CompactProof,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct State {
|
||||
level: Scalar,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Response {}
|
||||
|
||||
define_proof! {
|
||||
requestproof,
|
||||
"Positive Report Request",
|
||||
(id, bucket, since, invremain, blockages, zid, zbucket, zsince, zinvremain, zblockages, negzQ),
|
||||
(P, CId, CBucket, CSince, CInvRemain, CBlockages, V, Xid, Xbucket, Xsince, Xinvremain, Xblockages),//, H, HBucket),
|
||||
(A):
|
||||
// Blind showing of the Lox credential
|
||||
CId = (id*P + zid*A),
|
||||
CBucket = (bucket*P + zbucket*A),
|
||||
CSince = (since*P + zsince*A),
|
||||
CInvRemain = (invremain*P + zinvremain*A),
|
||||
CBlockages = (blockages*P + zblockages*A),
|
||||
V = (zid*Xid + zbucket*Xbucket + zsince*Xsince + zinvremain*Xinvremain + zblockages*Xblockages + negzQ*A)
|
||||
}
|
||||
|
||||
pub fn request(
|
||||
lox_cred: &cred::Lox,
|
||||
lox_pub: &IssuerPubKey,
|
||||
) -> Result<(Request, State), ProofError> {
|
||||
let A: &RistrettoPoint = &CMZ_A;
|
||||
let Atable: &RistrettoBasepointTable = &CMZ_A_TABLE;
|
||||
|
||||
// Ensure that the credential can be correctly shown: it must be the case
|
||||
// that trust_level >= MIN_TRUST_LEVEL
|
||||
let level: u32 = match scalar_u32(&lox_cred.trust_level) {
|
||||
Some(v) => v,
|
||||
None => return Err(ProofError::VerificationFailure),
|
||||
};
|
||||
if level < MIN_TRUST_LEVEL {
|
||||
return Err(ProofError::VerificationFailure);
|
||||
}
|
||||
|
||||
// Blind showing the Lox credential
|
||||
|
||||
// Reblind P and Q
|
||||
let mut rng = rand::thread_rng();
|
||||
let t = Scalar::random(&mut rng);
|
||||
let P = t * lox_cred.P;
|
||||
let Q = t * lox_cred.Q;
|
||||
|
||||
// Form Pedersen commitments to the blinded attributes
|
||||
let zid = Scalar::random(&mut rng);
|
||||
let zbucket = Scalar::random(&mut rng);
|
||||
let zsince = Scalar::random(&mut rng);
|
||||
let zinvremain = Scalar::random(&mut rng);
|
||||
let zblockages = Scalar::random(&mut rng);
|
||||
let CId = lox_cred.id * P + &zid * Atable;
|
||||
let CBucket = lox_cred.bucket * P + &zbucket * Atable;
|
||||
let CSince = lox_cred.level_since * P + &zsince * Atable;
|
||||
let CInvRemain = lox_cred.invites_remaining * P + &zinvremain * Atable;
|
||||
let CBlockages = lox_cred.blockages * P + &zblockages * Atable;
|
||||
|
||||
// Form a Pedersen commitment to the MAC Q
|
||||
// We flip the sign of zQ from that of the Hyphae paper so that
|
||||
// the lox_zkp has a "+" instead of a "-", as that's what the lox_zkp
|
||||
// macro supports.
|
||||
let negzQ = Scalar::random(&mut rng);
|
||||
let CQ = Q - &negzQ * Atable;
|
||||
|
||||
// Compute the "error factor"
|
||||
let V = zid * lox_pub.X[1]
|
||||
+ zbucket * lox_pub.X[2]
|
||||
+ zsince * lox_pub.X[4]
|
||||
+ zinvremain * lox_pub.X[5]
|
||||
+ zblockages * lox_pub.X[6]
|
||||
+ &negzQ * Atable;
|
||||
|
||||
// Construct the proof
|
||||
let mut transcript = Transcript::new(b"proof of level 3 cred");
|
||||
let piUser = requestproof::prove_compact(
|
||||
&mut transcript,
|
||||
requestproof::ProveAssignments {
|
||||
A,
|
||||
P: &P,
|
||||
CId: &CId,
|
||||
CBucket: &CBucket,
|
||||
CSince: &CSince,
|
||||
CInvRemain: &CInvRemain,
|
||||
CBlockages: &CBlockages,
|
||||
V: &V,
|
||||
Xid: &lox_pub.X[1],
|
||||
Xbucket: &lox_pub.X[2],
|
||||
Xsince: &lox_pub.X[4],
|
||||
Xinvremain: &lox_pub.X[5],
|
||||
Xblockages: &lox_pub.X[6],
|
||||
id: &lox_cred.id,
|
||||
bucket: &lox_cred.bucket,
|
||||
since: &lox_cred.level_since,
|
||||
invremain: &lox_cred.invites_remaining,
|
||||
blockages: &lox_cred.blockages,
|
||||
zid: &zid,
|
||||
zbucket: &zbucket,
|
||||
zsince: &zsince,
|
||||
zinvremain: &zinvremain,
|
||||
zblockages: &zblockages,
|
||||
negzQ: &negzQ,
|
||||
},
|
||||
)
|
||||
.0;
|
||||
|
||||
Ok((
|
||||
Request {
|
||||
P,
|
||||
CId,
|
||||
CBucket,
|
||||
level: lox_cred.trust_level,
|
||||
CSince,
|
||||
CInvRemain,
|
||||
CBlockages,
|
||||
CQ,
|
||||
piUser,
|
||||
},
|
||||
State {
|
||||
level: lox_cred.trust_level,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
impl BridgeAuth {
|
||||
/// Receive a positive report request
|
||||
pub fn handle_positive_report(&mut self, req: Request) -> Result<Response, ProofError> {
|
||||
let A: &RistrettoPoint = &CMZ_A;
|
||||
|
||||
let level: u32 = match scalar_u32(&req.level) {
|
||||
Some(v) => v,
|
||||
None => return Err(ProofError::VerificationFailure),
|
||||
};
|
||||
|
||||
if req.P.is_identity() || level < MIN_TRUST_LEVEL {
|
||||
return Err(ProofError::VerificationFailure);
|
||||
}
|
||||
|
||||
// Recompute the "error factor" using knowledge of our own
|
||||
// (the issuer's) private key instead of knowledge of the
|
||||
// hidden attributes
|
||||
let Vprime = (self.lox_priv.x[0] + self.lox_priv.x[3] * req.level) * req.P
|
||||
+ self.lox_priv.x[1] * req.CId
|
||||
+ self.lox_priv.x[2] * req.CBucket
|
||||
+ self.lox_priv.x[4] * req.CSince
|
||||
+ self.lox_priv.x[5] * req.CInvRemain
|
||||
+ self.lox_priv.x[6] * req.CBlockages
|
||||
- req.CQ;
|
||||
|
||||
// TODO: Failure happens in verify_compact
|
||||
// Verify the zkp
|
||||
let mut transcript = Transcript::new(b"positive report request");
|
||||
requestproof::verify_compact(
|
||||
&req.piUser,
|
||||
&mut transcript,
|
||||
requestproof::VerifyAssignments {
|
||||
A: &A.compress(),
|
||||
P: &req.P.compress(),
|
||||
CId: &req.CId.compress(),
|
||||
CBucket: &req.CBucket.compress(),
|
||||
CSince: &req.CSince.compress(),
|
||||
CInvRemain: &req.CInvRemain.compress(),
|
||||
CBlockages: &req.CBlockages.compress(),
|
||||
V: &Vprime.compress(),
|
||||
Xid: &self.lox_pub.X[1].compress(),
|
||||
Xbucket: &self.lox_pub.X[2].compress(),
|
||||
Xsince: &self.lox_pub.X[4].compress(),
|
||||
Xinvremain: &self.lox_pub.X[5].compress(),
|
||||
Xblockages: &self.lox_pub.X[6].compress(),
|
||||
},
|
||||
)?;
|
||||
|
||||
Ok(Response {})
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle the response to the request, returning true if the proof is valid.
|
||||
pub fn handle_response(_state: State, _resp: Response) -> Result<(), ProofError> {
|
||||
Ok(())
|
||||
}
|
|
@ -371,6 +371,34 @@ impl TestHarness {
|
|||
cred,
|
||||
)
|
||||
}
|
||||
|
||||
fn positive_report(&mut self, cred: &cred::Lox) -> PerfStat {
|
||||
let req_start = Instant::now();
|
||||
let (req, state) = positive_report::request(cred, &self.ba.lox_pub).unwrap();
|
||||
let encoded: Vec<u8> = bincode::serialize(&req).unwrap();
|
||||
let req_t = req_start.elapsed();
|
||||
let req_len = encoded.len();
|
||||
|
||||
let resp_start = Instant::now();
|
||||
let decoded = bincode::deserialize(&encoded[..]).unwrap();
|
||||
let resp = self.ba.handle_positive_report(decoded).unwrap();
|
||||
let encoded_resp: Vec<u8> = bincode::serialize(&resp).unwrap();
|
||||
let resp_t = resp_start.elapsed();
|
||||
let resp_len = encoded_resp.len();
|
||||
|
||||
let resp_handle_start = Instant::now();
|
||||
let decode_resp = bincode::deserialize(&encoded_resp[..]).unwrap();
|
||||
positive_report::handle_response(state, decode_resp).unwrap();
|
||||
let resp_handle_t = resp_handle_start.elapsed();
|
||||
|
||||
PerfStat {
|
||||
req_len,
|
||||
resp_len,
|
||||
req_t,
|
||||
resp_t,
|
||||
resp_handle_t,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1342,6 +1370,43 @@ fn test_blockage_migration() {
|
|||
assert!(th.ba.verify_lox(&cred4));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_positive_report() {
|
||||
let mut th = TestHarness::new();
|
||||
|
||||
// Join an untrusted user
|
||||
let cred = th.open_invite().1 .0;
|
||||
|
||||
// Time passes
|
||||
th.advance_days(47);
|
||||
|
||||
// Go up to level 1
|
||||
let (_mperf_stat, migcred) = th.trust_promotion(&cred);
|
||||
let (_perf_stat, cred1) = th.level0_migration(&cred, &migcred);
|
||||
assert!(scalar_u32(&cred1.trust_level).unwrap() == 1);
|
||||
|
||||
// Time passes
|
||||
th.advance_days(20);
|
||||
|
||||
// Go up to level 2
|
||||
let (_two_perf_stat, cred2) = th.level_up(&cred1);
|
||||
assert!(scalar_u32(&cred2.trust_level).unwrap() == 2);
|
||||
// println!("cred2 = {:?}", cred2);
|
||||
assert!(th.ba.verify_lox(&cred2));
|
||||
|
||||
// Time passes
|
||||
th.advance_days(29);
|
||||
|
||||
// Go up to level 3
|
||||
let (_three_perf_stat, cred3) = th.level_up(&cred2);
|
||||
assert!(scalar_u32(&cred3.trust_level).unwrap() == 3);
|
||||
// println!("cred3 = {:?}", cred3);
|
||||
assert!(th.ba.verify_lox(&cred3));
|
||||
|
||||
// Submit positive report
|
||||
let _pr_perf_stat = th.positive_report(&cred3);
|
||||
}
|
||||
|
||||
fn print_test_results(perf_stat: PerfStat) {
|
||||
println!("Request size = {:?} bytes", perf_stat.req_len);
|
||||
println!("Request time = {:?}", perf_stat.req_t);
|
||||
|
|
Loading…
Reference in New Issue