-
Notifications
You must be signed in to change notification settings - Fork 112
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add low degree exponent interpolation proof #119
Closed
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
2b5c6b4
Impl From<u16> for BigInt
d469b0b
Add Polynomial
138f41d
Add the proof
076b59c
Update travis config
83699f4
Bump version
8882430
Rename coef0 to const_term + update docs
8aed496
Add sample_exact and sample_exact_with_fixed_const
369d50c
Rename LdeiProveError -> LdeiProofError
4f84e8a
Move polynomial into secret_sharing module
b5f322e
LDEI prove takes witness and statement
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,25 @@ | ||
language: rust | ||
cache: cargo | ||
rust: | ||
- stable | ||
rust: stable | ||
virt: lxd | ||
|
||
before_script: | ||
- rustup component add rustfmt-preview clippy | ||
- cargo fmt --all -- --check | ||
- cargo clippy -- -D clippy::all | ||
env: | ||
- BIGINT_BACKEND=rust-gmp-kzen | ||
- BIGINT_BACKEND=num-bigint | ||
|
||
before_install: | ||
- rustup component add rustfmt clippy | ||
|
||
script: | ||
- cargo build --verbose | ||
- cargo test --verbose | ||
- cargo build --verbose --no-default-features --features $BIGINT_BACKEND | ||
- cargo test --verbose --no-default-features --features $BIGINT_BACKEND | ||
- if [[ "$BIGINT_BACKEND" = "rust-gmp-kzen" ]]; then cargo fmt --all -- --check; fi | ||
- if [[ "$BIGINT_BACKEND" = "rust-gmp-kzen" ]]; then cargo clippy -- -D clippy::all; fi | ||
|
||
deploy: | ||
provider: cargo | ||
token: | ||
secure: "FE6A1XRyJtTK92rV3y5e0go+FDKn1HpJbYkHOacDqabTkUluXrCTw3ERFcQQ13QZdc9xkxoAs7roKp8ivl0Xg1IJCzI+yLb0ZR6YcYebKEqd06YFbBmejjvMsyyZHKPTQmroe+tBwcA1IqLLcAY8vmY5EGhJTsGUhovIomw1RvqM6gu9yUwII/sF0a5gqY761cJd4QoLlWTb1Er7DqZxoU9drhWAJQP7sLsspjLu6dOyWzb0A2mTmnek+iuVnt9mGPtjGk4FcNPGbEmNu3UPOVuXcyibFPIALEWrH0ouZB7E9k312g45LucSeKSimgQYQBNAzdsnkKyBwyTpGuaosGnMbI7mhoi3visV21RTbw61N05dmZTYb4VAMcx+93TslKMDv5nmIlUmKxULNRBSTPPtrg0/X7KuKaoHVstrxx0ohd8GFwGYQBB64mQaOxFBhoy//prpHjhFl+1cti4JHyaHFSV/PfaryvUfRg4q2Dlq1HP+ey5cPRPbwfpSO1RmXlIDWe21ncRnKSpgMHTPBzYNtil+gZyzHl5X4ZLvLCaHsZwZQPMFB+otlabFaS1caqkk1F1fHMrj8NMak/snb2IyUJqXgQivqzEn38G3k9/QHeQXhNVwyGDtdWV51P9XfXFpxrEuuWlXF56ABiWcF7bY7Y3DeCbnFNLkVkGZYvY=" | ||
on: | ||
tags: true | ||
condition: '"$TRAVIS_TAG" =~ ^v[0-9.]+$ && "$BIGINT_BACKEND" = "rust-gmp-kzen"' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
230 changes: 230 additions & 0 deletions
230
src/cryptographic_primitives/proofs/low_degree_exponent_interpolation.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,230 @@ | ||
use std::fmt; | ||
|
||
use derivative::Derivative; | ||
use thiserror::Error; | ||
|
||
use crate::cryptographic_primitives::hashing::traits::Hash; | ||
use crate::cryptographic_primitives::proofs::ProofError; | ||
use crate::cryptographic_primitives::secret_sharing::Polynomial; | ||
use crate::elliptic::curves::traits::ECPoint; | ||
|
||
/// The prover private polynomial | ||
#[derive(Derivative)] | ||
#[derivative(Clone(bound = "P::Scalar: Clone"))] | ||
#[derivative(Debug(bound = "P::Scalar: fmt::Debug"))] | ||
pub struct LdeiWitness<P: ECPoint> { | ||
pub w: Polynomial<P>, | ||
} | ||
|
||
/// Claims that there's polynomial `w(x)` of degree `deg(w) <= degree`, and | ||
/// `forall i. x[i] = g[i] * alpha[i]` (and the prover knows `w(x)`) | ||
#[derive(Derivative)] | ||
#[derivative(Clone(bound = "P: Clone, P::Scalar: Clone"))] | ||
#[derivative(Debug(bound = "P: fmt::Debug, P::Scalar: fmt::Debug"))] | ||
pub struct LdeiStatement<P: ECPoint> { | ||
pub alpha: Vec<P::Scalar>, | ||
pub g: Vec<P>, | ||
pub x: Vec<P>, | ||
pub d: u16, | ||
} | ||
|
||
impl<P> LdeiStatement<P> | ||
where | ||
P: ECPoint + Clone, | ||
P::Scalar: Clone + PartialEq, | ||
{ | ||
/// Takes [witness](LdeiWitness) (ie. secret polynomial `w(x)`), list of scalars `alpha`, | ||
/// list of generators `g`, number `d`. Produces LdeiStatement consisting of `alpha`, `g`, `d`, | ||
/// and list `x` such as `x_i = g_i * w(alpha_i)` | ||
pub fn new( | ||
witness: &LdeiWitness<P>, | ||
alpha: Vec<P::Scalar>, | ||
g: Vec<P>, | ||
d: u16, | ||
) -> Result<Self, InvalidLdeiStatement> { | ||
if g.len() != alpha.len() { | ||
return Err(InvalidLdeiStatement::AlphaLengthDoesntMatchG); | ||
} | ||
if witness.w.degree() > d { | ||
return Err(InvalidLdeiStatement::PolynomialDegreeMoreThanD); | ||
} | ||
if !ensure_list_is_pairwise_distinct(&alpha) { | ||
return Err(InvalidLdeiStatement::AlphaNotPairwiseDistinct); | ||
} | ||
Ok(Self { | ||
x: g.iter() | ||
.zip(&alpha) | ||
.map(|(g, a)| g.clone() * witness.w.evaluate(a)) | ||
.collect(), | ||
alpha, | ||
g, | ||
d, | ||
}) | ||
} | ||
} | ||
|
||
#[derive(Derivative)] | ||
#[derivative(Clone(bound = "P: Clone, P::Scalar: Clone"))] | ||
#[derivative(Debug(bound = "P: fmt::Debug, P::Scalar: fmt::Debug"))] | ||
pub struct LdeiProof<P: ECPoint> { | ||
pub a: Vec<P>, | ||
pub e: P::Scalar, | ||
pub z: Polynomial<P>, | ||
} | ||
|
||
impl<P> LdeiProof<P> | ||
where | ||
P: ECPoint + Clone + PartialEq, | ||
P::Scalar: Clone + PartialEq, | ||
{ | ||
/// Constructs [LdeiStatement] and proves it correctness | ||
/// | ||
/// ## Protocol | ||
/// | ||
/// The prover samples `u(X) ← Z_q[X]` with `deg(u) ≤ d` and computes `a_i = g_i^u(alpha_i)` | ||
/// for all `i ∈ [m]`, in addition to `e = H(g_1,...,g_m,x_1,...,x_m,a_1,...,a_m)`, and | ||
/// `z(X) = u(X) − e · w(X)`. The proof is `(a_1,...,a_m,e,z)`. | ||
#[allow(clippy::many_single_char_names)] | ||
pub fn prove<H>( | ||
witness: &LdeiWitness<P>, | ||
statement: &LdeiStatement<P>, | ||
) -> Result<LdeiProof<P>, InvalidLdeiStatement> | ||
where | ||
H: Hash, | ||
{ | ||
if statement.alpha.len() != statement.g.len() { | ||
return Err(InvalidLdeiStatement::AlphaLengthDoesntMatchG); | ||
} | ||
if witness.w.degree() > statement.d { | ||
return Err(InvalidLdeiStatement::PolynomialDegreeMoreThanD); | ||
} | ||
if !ensure_list_is_pairwise_distinct(&statement.alpha) { | ||
return Err(InvalidLdeiStatement::AlphaNotPairwiseDistinct); | ||
} | ||
|
||
let x_expected: Vec<P> = statement | ||
.g | ||
.iter() | ||
.zip(&statement.alpha) | ||
.map(|(g, a)| g.clone() * witness.w.evaluate(a)) | ||
.collect(); | ||
if statement.x != x_expected { | ||
return Err(InvalidLdeiStatement::ListOfXDoesntMatchExpectedValue); | ||
} | ||
|
||
let u = Polynomial::<P>::sample(statement.d); | ||
let a: Vec<P> = statement | ||
.g | ||
.iter() | ||
.zip(&statement.alpha) | ||
.map(|(g, a)| g.clone() * u.evaluate(a)) | ||
.collect(); | ||
|
||
let hash_input: Vec<&P> = statement.g.iter().chain(&statement.x).chain(&a).collect(); | ||
let e = H::create_hash_from_ge::<P>(hash_input.as_slice()); | ||
|
||
let z = &u - &(&witness.w * &e); | ||
|
||
Ok(LdeiProof { a, e, z }) | ||
} | ||
|
||
/// Verifies correctness of a statement | ||
/// | ||
/// ## Protocol | ||
/// | ||
/// The verifier checks that `e = H(g1,...,gm,x1,...,xm,a1,...,am)`, that | ||
/// `deg(z) ≤ d`, and that `a_i = g_i^z(αlpha_i) * x_i^e` for all i, and accepts if all of this is | ||
/// true, otherwise rejects. | ||
pub fn verify<H>(&self, statement: &LdeiStatement<P>) -> Result<(), ProofError> | ||
where | ||
H: Hash, | ||
{ | ||
let hash_input: Vec<&P> = statement | ||
.g | ||
.iter() | ||
.chain(&statement.x) | ||
.chain(&self.a) | ||
.collect(); | ||
let e = H::create_hash_from_ge::<P>(hash_input.as_slice()); | ||
if e != self.e { | ||
return Err(ProofError); | ||
} | ||
if self.z.degree() > statement.d { | ||
return Err(ProofError); | ||
} | ||
|
||
let expected_a: Vec<_> = statement | ||
.g | ||
.iter() | ||
.zip(&statement.alpha) | ||
.zip(&statement.x) | ||
.map(|((g, a), x)| g.clone() * self.z.evaluate(&a) + x.clone() * e.clone()) | ||
.collect(); | ||
|
||
if self.a == expected_a { | ||
Ok(()) | ||
} else { | ||
Err(ProofError) | ||
} | ||
} | ||
} | ||
|
||
/// Indicates that statement is not valid or doesn't match a witness | ||
#[derive(Debug, Error)] | ||
pub enum InvalidLdeiStatement { | ||
#[error("`alpha`s are not pairwise distinct")] | ||
AlphaNotPairwiseDistinct, | ||
#[error("alpha.len() != g.len()")] | ||
AlphaLengthDoesntMatchG, | ||
#[error("deg(w) > d")] | ||
PolynomialDegreeMoreThanD, | ||
#[error("`statement.x` doesn't match expected value")] | ||
ListOfXDoesntMatchExpectedValue, | ||
} | ||
|
||
fn ensure_list_is_pairwise_distinct<S: PartialEq>(list: &[S]) -> bool { | ||
for (i, x1) in list.iter().enumerate() { | ||
for (j, x2) in list.iter().enumerate() { | ||
if i != j && x1 == x2 { | ||
return false; | ||
} | ||
} | ||
} | ||
true | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use std::iter; | ||
|
||
use crate::arithmetic::BigInt; | ||
use crate::cryptographic_primitives::hashing::hash_sha256::HSha256; | ||
use crate::elliptic::curves::traits::ECScalar; | ||
use crate::test_for_all_curves; | ||
|
||
use super::*; | ||
|
||
test_for_all_curves!(correctly_proofs); | ||
fn correctly_proofs<P>() | ||
where | ||
P: ECPoint + Clone + PartialEq, | ||
P::Scalar: ECScalar + Clone + PartialEq, | ||
{ | ||
let d = 5; | ||
let poly = Polynomial::<P>::sample_exact(5); | ||
let witness = LdeiWitness { w: poly }; | ||
|
||
let alpha: Vec<P::Scalar> = (1..=10).map(|i| ECScalar::from(&BigInt::from(i))).collect(); | ||
let g: Vec<P> = iter::repeat_with(ECScalar::new_random) | ||
.map(|x| P::generator() * x) | ||
.take(10) | ||
.collect(); | ||
|
||
let statement = LdeiStatement::new(&witness, alpha, g, d).unwrap(); | ||
|
||
let proof = LdeiProof::prove::<HSha256>(&witness, &statement).expect("failed to prove"); | ||
proof | ||
.verify::<HSha256>(&statement) | ||
.expect("failed to validate proof"); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are you sure the generators are not supposed to be picked at random such that there is no way to compute
x
such thatg_i = x g_j
?for example see how we generate the generator vector in bulletproofs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The line you commented doesn't choose generators — it chooses list of α (a list of pairwise distinct scalar from Setup phase of the proof). Line below chooses generators completely at random. I agree that correlation like
g_i = x g_j
could potentially lead to vulnerabilitiesThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no idea why I picked that line :)
so will you change it ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah I found what code you're referring to — generate_random_point. Are you ok with me moving this function to
curv::elliptic::curves:: generate_random_point
?