Add proof of level 3 or 4, bucket. (Still needs to be debugged.)
This commit is contained in:
parent
a6c5d789e7
commit
9cd9e3fab7
|
@ -4,8 +4,8 @@ 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
|
||||
- bucket: blinded (but proven to be bucket in provided bucket*H)
|
||||
- trust_level: blinded (but proven to be 3 or higher)
|
||||
- level_since: blinded
|
||||
- invites_remaining: blinded
|
||||
- blockages: blinded
|
||||
|
@ -13,79 +13,99 @@ The user presents their current Lox credential:
|
|||
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."
|
||||
Due to the way the level proof is implemented, this protocol has
|
||||
hardcoded assumptions that the level is 3-4.
|
||||
|
||||
Right now, this doesn't work.
|
||||
|
||||
*/
|
||||
|
||||
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 sha2::Sha512;
|
||||
use std::convert::TryInto;
|
||||
|
||||
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,
|
||||
CLevel: RistrettoPoint,
|
||||
CSince: RistrettoPoint,
|
||||
CInvRemain: RistrettoPoint,
|
||||
CBlockages: RistrettoPoint,
|
||||
CQ: RistrettoPoint,
|
||||
|
||||
// Fields for proving which bucket we have
|
||||
H: RistrettoPoint,
|
||||
BP: RistrettoPoint,
|
||||
|
||||
// Fields for proving 3 <= trust_level <= 4
|
||||
// CG can be computed by verifier
|
||||
CGsq: 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),
|
||||
(id, bucket, level, since, invremain, blockages,
|
||||
zid, zbucket, zlevel, zsince, zinvremain, zblockages, negzQ,
|
||||
g, zg, wg, yg),
|
||||
(P, CId, CBucket, CLevel, CSince, CInvRemain, CBlockages,
|
||||
V, Xid, Xbucket, Xlevel, Xsince, Xinvremain, Xblockages,
|
||||
H, BP, CG, CGsq),
|
||||
(A):
|
||||
// Blind showing of the Lox credential
|
||||
CId = (id*P + zid*A),
|
||||
CBucket = (bucket*P + zbucket*A),
|
||||
CLevel = (level*P + zlevel*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)
|
||||
V = (zid*Xid + zbucket*Xbucket + zlevel*Xlevel + zsince*Xsince + zinvremain*Xinvremain + zblockages*Xblockages + negzQ*A),
|
||||
// Prove bucket is same bucket used in BP
|
||||
BP = (bucket*H),
|
||||
// Prove CLevel encodes a value of 3 or 4
|
||||
// First prove g is a bit by proving that g = g^2
|
||||
CG = (g*P + zg*A), CGsq = (g*CG + wg*A), CGsq = (g*P + yg*A)
|
||||
// The verifier will compute CG = CLevel - 3P
|
||||
}
|
||||
|
||||
pub fn request(
|
||||
lox_cred: &cred::Lox,
|
||||
lox_pub: &IssuerPubKey,
|
||||
) -> Result<(Request, State), ProofError> {
|
||||
) -> Result<Request, ProofError> {
|
||||
let A: &RistrettoPoint = &CMZ_A;
|
||||
let Atable: &RistrettoBasepointTable = &CMZ_A_TABLE;
|
||||
|
||||
// TODO: Where should this go? For efficiency, this should probably be global
|
||||
let today: u32 = time::OffsetDateTime::now_utc().date()
|
||||
.to_julian_day()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
let H: RistrettoPoint = RistrettoPoint::hash_from_bytes::<Sha512>(format!("PR Generator H for {}",today).as_bytes());
|
||||
let Htable: RistrettoBasepointTable = RistrettoBasepointTable::create(&H);
|
||||
|
||||
// Ensure that the credential can be correctly shown: it must be the case
|
||||
// that trust_level >= MIN_TRUST_LEVEL
|
||||
// that trust_level is 3 or 4
|
||||
let level: u32 = match scalar_u32(&lox_cred.trust_level) {
|
||||
Some(v) => v,
|
||||
None => return Err(ProofError::VerificationFailure),
|
||||
};
|
||||
if level < MIN_TRUST_LEVEL {
|
||||
// level must be 3 + one bit or we need to add more bits
|
||||
if level < 3 || level > 4 {
|
||||
return Err(ProofError::VerificationFailure);
|
||||
}
|
||||
|
||||
|
@ -100,11 +120,13 @@ pub fn request(
|
|||
// Form Pedersen commitments to the blinded attributes
|
||||
let zid = Scalar::random(&mut rng);
|
||||
let zbucket = Scalar::random(&mut rng);
|
||||
let zlevel = 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 CLevel = lox_cred.trust_level * P + &zlevel * 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;
|
||||
|
@ -119,11 +141,36 @@ pub fn request(
|
|||
// Compute the "error factor"
|
||||
let V = zid * lox_pub.X[1]
|
||||
+ zbucket * lox_pub.X[2]
|
||||
+ zlevel * lox_pub.X[3]
|
||||
+ zsince * lox_pub.X[4]
|
||||
+ zinvremain * lox_pub.X[5]
|
||||
+ zblockages * lox_pub.X[6]
|
||||
+ &negzQ * Atable;
|
||||
|
||||
// Compute BP for proving knowledge of bucket
|
||||
let BP = &lox_cred.bucket * &Htable;
|
||||
|
||||
// Proof that 3 <= trust_level
|
||||
|
||||
let g: Scalar = (level - 3).into();
|
||||
|
||||
// Pick random factor for the Pedersen commitment
|
||||
let wg = Scalar::random(&mut rng);
|
||||
|
||||
// zg equals zlevel so that
|
||||
// 3*P + CG
|
||||
// = 3*P + (g*P + zg*A)
|
||||
// = (3+g)*P + zlevel*A
|
||||
// = level*P + zlevel*A
|
||||
// = CLevel
|
||||
let zg = zlevel;
|
||||
|
||||
let yg = wg + g * zg;
|
||||
|
||||
let CG = g * P + &zg * Atable;
|
||||
|
||||
let CGsq = g * P + &yg * Atable;
|
||||
|
||||
// Construct the proof
|
||||
let mut transcript = Transcript::new(b"proof of level 3 cred");
|
||||
let piUser = requestproof::prove_compact(
|
||||
|
@ -133,73 +180,84 @@ pub fn request(
|
|||
P: &P,
|
||||
CId: &CId,
|
||||
CBucket: &CBucket,
|
||||
CLevel: &CLevel,
|
||||
CSince: &CSince,
|
||||
CInvRemain: &CInvRemain,
|
||||
CBlockages: &CBlockages,
|
||||
V: &V,
|
||||
Xid: &lox_pub.X[1],
|
||||
Xbucket: &lox_pub.X[2],
|
||||
Xlevel: &lox_pub.X[3],
|
||||
Xsince: &lox_pub.X[4],
|
||||
Xinvremain: &lox_pub.X[5],
|
||||
Xblockages: &lox_pub.X[6],
|
||||
H: &H,
|
||||
BP: &BP,
|
||||
CG: &CG,
|
||||
CGsq: &CGsq,
|
||||
id: &lox_cred.id,
|
||||
bucket: &lox_cred.bucket,
|
||||
level: &lox_cred.trust_level,
|
||||
since: &lox_cred.level_since,
|
||||
invremain: &lox_cred.invites_remaining,
|
||||
blockages: &lox_cred.blockages,
|
||||
zid: &zid,
|
||||
zbucket: &zbucket,
|
||||
zlevel: &zlevel,
|
||||
zsince: &zsince,
|
||||
zinvremain: &zinvremain,
|
||||
zblockages: &zblockages,
|
||||
negzQ: &negzQ,
|
||||
g: &g,
|
||||
zg: &zg,
|
||||
wg: &wg,
|
||||
yg: &yg,
|
||||
},
|
||||
)
|
||||
.0;
|
||||
|
||||
Ok((
|
||||
Ok(
|
||||
Request {
|
||||
P,
|
||||
CId,
|
||||
CBucket,
|
||||
level: lox_cred.trust_level,
|
||||
CLevel,
|
||||
CSince,
|
||||
CInvRemain,
|
||||
CBlockages,
|
||||
CQ,
|
||||
H,
|
||||
BP,
|
||||
CGsq,
|
||||
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> {
|
||||
pub fn handle_positive_report(&mut self, req: Request) -> Result<(), 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 {
|
||||
if req.P.is_identity() {
|
||||
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
|
||||
let Vprime = self.lox_priv.x[0] * req.P
|
||||
+ self.lox_priv.x[1] * req.CId
|
||||
+ self.lox_priv.x[2] * req.CBucket
|
||||
+ self.lox_priv.x[3] * req.CLevel
|
||||
+ self.lox_priv.x[4] * req.CSince
|
||||
+ self.lox_priv.x[5] * req.CInvRemain
|
||||
+ self.lox_priv.x[6] * req.CBlockages
|
||||
- req.CQ;
|
||||
|
||||
// Recompute CG
|
||||
let CG = req.CLevel - Scalar::from(3 as u8) * req.P;
|
||||
|
||||
// TODO: Failure happens in verify_compact
|
||||
// Verify the zkp
|
||||
let mut transcript = Transcript::new(b"positive report request");
|
||||
|
@ -211,23 +269,24 @@ impl BridgeAuth {
|
|||
P: &req.P.compress(),
|
||||
CId: &req.CId.compress(),
|
||||
CBucket: &req.CBucket.compress(),
|
||||
CLevel: &req.CLevel.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(),
|
||||
Xlevel: &self.lox_pub.X[3].compress(),
|
||||
Xsince: &self.lox_pub.X[4].compress(),
|
||||
Xinvremain: &self.lox_pub.X[5].compress(),
|
||||
Xblockages: &self.lox_pub.X[6].compress(),
|
||||
H: &req.H.compress(),
|
||||
BP: &req.BP.compress(),
|
||||
CG: &CG.compress(),
|
||||
CGsq: &req.CGsq.compress(),
|
||||
},
|
||||
)?;
|
||||
|
||||
Ok(Response {})
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle the response to the request, returning true if the proof is valid.
|
||||
pub fn handle_response(_state: State, _resp: Response) -> Result<(), ProofError> {
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -374,21 +374,18 @@ impl TestHarness {
|
|||
|
||||
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 req = 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();
|
||||
self.ba.handle_positive_report(decoded).unwrap();
|
||||
let resp_t = resp_start.elapsed();
|
||||
let resp_len = encoded_resp.len();
|
||||
let resp_len = 0;
|
||||
|
||||
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 {
|
||||
|
@ -1405,6 +1402,17 @@ fn test_positive_report() {
|
|||
|
||||
// Submit positive report
|
||||
let _pr_perf_stat = th.positive_report(&cred3);
|
||||
|
||||
// Time passes
|
||||
th.advance_days(60);
|
||||
|
||||
// Go up to level 4
|
||||
let (_four_perf_stat, cred4) = th.level_up(&cred3);
|
||||
assert!(scalar_u32(&cred4.trust_level).unwrap() == 4);
|
||||
assert!(th.ba.verify_lox(&cred4));
|
||||
|
||||
// Submit positive report
|
||||
let _pr_perf_stat2 = th.positive_report(&cred4);
|
||||
}
|
||||
|
||||
fn print_test_results(perf_stat: PerfStat) {
|
||||
|
|
Loading…
Reference in New Issue