Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions crates/crypto/src/commitments/kzg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ use lambdaworks_math::{

#[derive(PartialEq, Clone, Debug)]
pub struct StructuredReferenceString<G1Point, G2Point> {
/// Vector of points in G1 encoding g1, s g1, s^2 g1, s^3 g1, ... s^n g1
pub powers_main_group: Vec<G1Point>,
/// Slice of points in G2 encoding g2, s g2
/// We could relax this to include more powers, but for most applications
/// this suffices
pub powers_secondary_group: [G2Point; 2],
}

Expand All @@ -23,6 +27,7 @@ where
G1Point: IsGroup,
G2Point: IsGroup,
{
/// Creates a new SRS from slices of G1points and a slice of length 2 of G2 points
pub fn new(powers_main_group: &[G1Point], powers_secondary_group: &[G2Point; 2]) -> Self {
Self {
powers_main_group: powers_main_group.into(),
Expand All @@ -37,6 +42,7 @@ where
G1Point: IsGroup + Deserializable,
G2Point: IsGroup + Deserializable,
{
/// Read SRS from file
pub fn from_file(file_path: &str) -> Result<Self, crate::errors::SrsFromFileError> {
let bytes = std::fs::read(file_path)?;
Ok(Self::deserialize(&bytes)?)
Expand All @@ -48,6 +54,7 @@ where
G1Point: IsGroup + AsBytes,
G2Point: IsGroup + AsBytes,
{
/// Serialize SRS
fn as_bytes(&self) -> Vec<u8> {
let mut serialized_data: Vec<u8> = Vec::new();
// First 4 bytes encodes protocol version
Expand Down Expand Up @@ -155,6 +162,9 @@ impl<const N: usize, F: IsPrimeField<RepresentativeType = UnsignedInteger<N>>, P
{
type Commitment = P::G1Point;

/// Given a polynomial and an SRS, creates a commitment to p(x), which corresponds to a G1 point
/// The commitment is p(s) g1, evaluated as \sum_i c_i srs.powers_main_group[i], where c_i are the coefficients
/// of the polynomial.
fn commit(&self, p: &Polynomial<FieldElement<F>>) -> Self::Commitment {
let coefficients: Vec<_> = p
.coefficients
Expand All @@ -168,6 +178,9 @@ impl<const N: usize, F: IsPrimeField<RepresentativeType = UnsignedInteger<N>>, P
.expect("`points` is sliced by `cs`'s length")
}

/// Creates an evaluation proof for the polynomial p at x equal to y.
/// This is a commitment to the quotient polynomial q(t) = (p(t) - y)/(t - x)
/// The commitment is simply q(s) g1, corresponding to a G1 point
fn open(
&self,
x: &FieldElement<F>,
Expand All @@ -179,6 +192,11 @@ impl<const N: usize, F: IsPrimeField<RepresentativeType = UnsignedInteger<N>>, P
self.commit(&poly_to_commit)
}

/// Verifies the correct evaluation of a polynomial p by providing a commitment to p,
/// the point x, the evaluation y (p(x) = y) and an evaluation proof (commitment to the quotient polynomial)
/// Basically, we want to show that, at secret point s, p(s) - y = (s - x) q(s)
/// It uses pairings to verify the above condition, e(cm(p) - yg1,g2)*(cm(q), sg2 - xg2)^-1
/// Returns true for valid evaluation
fn verify(
&self,
x: &FieldElement<F>,
Expand All @@ -203,6 +221,8 @@ impl<const N: usize, F: IsPrimeField<RepresentativeType = UnsignedInteger<N>>, P
e == Ok(FieldElement::one())
}

/// Creates an evaluation proof for several polynomials at a single point x. upsilon is used to
/// perform the random linear combination, using Horner's evaluation form
fn open_batch(
&self,
x: &FieldElement<F>,
Expand All @@ -225,6 +245,9 @@ impl<const N: usize, F: IsPrimeField<RepresentativeType = UnsignedInteger<N>>, P
self.open(x, &acc_y, &acc_polynomial)
}

/// Verifies an evaluation proof for the evaluation of a batch of polynomials at x, using upsilon to perform the random
/// linear combination
/// Outputs true if the evaluation is correct
fn verify_batch(
&self,
x: &FieldElement<F>,
Expand Down
8 changes: 8 additions & 0 deletions crates/crypto/src/commitments/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,20 @@ use lambdaworks_math::{
pub trait IsCommitmentScheme<F: IsField> {
type Commitment;

/// Create a commitment to a polynomial
fn commit(&self, p: &Polynomial<FieldElement<F>>) -> Self::Commitment;

/// Create an evaluation proof for a polynomial at x equal to y
/// p(x) = y
fn open(
&self,
x: &FieldElement<F>,
y: &FieldElement<F>,
p: &Polynomial<FieldElement<F>>,
) -> Self::Commitment;

/// Create an evaluation proof for a slice of polynomials at x equal to y_i
/// that is, we show that we evaluated correctly p_i (x) = y_i
fn open_batch(
&self,
x: &FieldElement<F>,
Expand All @@ -22,6 +28,7 @@ pub trait IsCommitmentScheme<F: IsField> {
upsilon: &FieldElement<F>,
) -> Self::Commitment;

/// Verify an evaluation proof given the commitment to p, the point x and the evaluation y
fn verify(
&self,
x: &FieldElement<F>,
Expand All @@ -30,6 +37,7 @@ pub trait IsCommitmentScheme<F: IsField> {
proof: &Self::Commitment,
) -> bool;

/// Verify an evaluation proof given the commitments to p, the point x and the evaluations ys
fn verify_batch(
&self,
x: &FieldElement<F>,
Expand Down
15 changes: 15 additions & 0 deletions crates/crypto/src/merkle_tree/merkle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ impl Display for Error {
#[cfg(feature = "std")]
impl std::error::Error for Error {}

/// The struct for the Merkle tree, consisting of the root and the nodes.
/// A typical tree would look like this
/// root
/// / \
/// leaf 12 leaf 34
/// / \ / \
/// leaf 1 leaf 2 leaf 3 leaf 4
/// The bottom leafs correspond to the hashes of the elements, while each upper
/// layer contains the hash of the concatenation of the daughter nodes.
#[derive(Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct MerkleTree<B: IsMerkleTreeBackend> {
Expand All @@ -30,6 +39,7 @@ impl<B> MerkleTree<B>
where
B: IsMerkleTreeBackend,
{
/// Create a Merkle tree from a slice of data
pub fn build(unhashed_leaves: &[B::Data]) -> Option<Self> {
if unhashed_leaves.is_empty() {
return None;
Expand All @@ -55,6 +65,9 @@ where
})
}

/// Returns a Merkle proof for the element/s at position pos
/// For example, give me an inclusion proof for the 3rd element in the
/// Merkle tree
pub fn get_proof_by_pos(&self, pos: usize) -> Option<Proof<B::Node>> {
let pos = pos + self.nodes.len() / 2;
let Ok(merkle_path) = self.build_merkle_path(pos) else {
Expand All @@ -64,10 +77,12 @@ where
self.create_proof(merkle_path)
}

/// Creates a proof from a Merkle pasth
fn create_proof(&self, merkle_path: Vec<B::Node>) -> Option<Proof<B::Node>> {
Some(Proof { merkle_path })
}

/// Returns the Merkle path for the element/s for the leaf at position pos
fn build_merkle_path(&self, pos: usize) -> Result<Vec<B::Node>, Error> {
let mut merkle_path = Vec::new();
let mut pos = pos;
Expand Down
1 change: 1 addition & 0 deletions crates/crypto/src/merkle_tree/proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub struct Proof<T: PartialEq + Eq> {
}

impl<T: PartialEq + Eq> Proof<T> {
/// Verifies a Merkle inclusion proof for the value contained at leaf index.
pub fn verify<B>(&self, root_hash: &B::Node, mut index: usize, value: &B::Data) -> bool
where
B: IsMerkleTreeBackend<Node = T>,
Expand Down
3 changes: 3 additions & 0 deletions crates/math/src/cyclic_group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,8 @@ pub trait IsGroup: Clone + PartialEq + Eq {
/// the notation of the particular group.
fn operate_with(&self, other: &Self) -> Self;

/// Provides the inverse of the group element.
/// This is the unique y such that for any x
/// x.operate_with(y) returns the neutral element
fn neg(&self) -> Self;
}
6 changes: 6 additions & 0 deletions crates/math/src/elliptic_curve/short_weierstrass/point.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,13 @@ impl<E: IsShortWeierstrass> ShortWeierstrassProjectivePoint<E> {
self.0.coordinates()
}

/// Returns the affine representation of the point [x, y, 1]
pub fn to_affine(&self) -> Self {
Self(self.0.to_affine())
}

/// Performs the group operation between a point and itself a + a = 2a in
/// additive notation
pub fn double(&self) -> Self {
if self.is_neutral_element() {
return self.clone();
Expand Down Expand Up @@ -112,6 +115,7 @@ impl<E: IsShortWeierstrass> ShortWeierstrassProjectivePoint<E> {
point.unwrap()
}
// https://hyperelliptic.org/EFD/g1p/data/shortw/projective/addition/madd-1998-cmo
/// More efficient than operate_with, but must ensure that other is in affine form
pub fn operate_with_affine(&self, other: &Self) -> Self {
if self.is_neutral_element() {
return other.clone();
Expand Down Expand Up @@ -477,6 +481,7 @@ impl<E: IsShortWeierstrass> ShortWeierstrassJacobianPoint<E> {
Self(self.0.to_affine())
}

/// Applies the group operation between a point and itself
pub fn double(&self) -> Self {
if self.is_neutral_element() {
return self.clone();
Expand Down Expand Up @@ -527,6 +532,7 @@ impl<E: IsShortWeierstrass> ShortWeierstrassJacobianPoint<E> {
}
}

/// More efficient than operate_with. Other should be in affine form!
pub fn operate_with_affine(&self, other: &Self) -> Self {
let [x1, y1, z1] = self.coordinates();
let [x2, y2, _z2] = other.coordinates();
Expand Down
14 changes: 14 additions & 0 deletions crates/math/src/elliptic_curve/short_weierstrass/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ pub trait IsShortWeierstrass: IsEllipticCurve + Clone + Debug {
/// `b` coefficient for the equation `y^2 = x^3 + a * x + b`.
fn b() -> FieldElement<Self::BaseField>;

/// Evaluates the residual of the Short Weierstrass equation
/// R = y^2 - x^3 - ax - b
/// If R == 0, then the point is in the curve
/// Use in affine coordinates
fn defining_equation(
x: &FieldElement<Self::BaseField>,
y: &FieldElement<Self::BaseField>,
Expand Down Expand Up @@ -49,13 +53,23 @@ pub trait Compress {
type G2Compressed;
type Error;

/// Gives a compressed representation of a G1 point in the elliptic curve
/// Providing the x coordinate and an additional bit provides a way of retrieving the
/// y coordinate by sending less information
#[cfg(feature = "alloc")]
fn compress_g1_point(point: &Self::G1Point) -> Self::G1Compressed;

/// Gives a compressed representation of a G2 point in the elliptic curve
/// Providing the x coordinate and an additional bit provides a way of retrieving the
/// y coordinate by sending less information
#[cfg(feature = "alloc")]
fn compress_g2_point(point: &Self::G2Point) -> Self::G2Compressed;

/// Given a slice of bytes, representing the x coordinate plus additional bits, recovers
/// the elliptic curve point in G1
fn decompress_g1_point(input_bytes: &mut [u8]) -> Result<Self::G1Point, Self::Error>;

/// Given a slice of bytes, representing the x coordinate plus additional bits, recovers
/// the elliptic curve point in G2
fn decompress_g2_point(input_bytes: &mut [u8]) -> Result<Self::G2Point, Self::Error>;
}
1 change: 1 addition & 0 deletions crates/math/src/elliptic_curve/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ pub trait IsPairing {
type OutputField: IsField;

/// Compute the product of the pairings for a list of point pairs.
/// More efficient than just calling the pairing for each pair of points individually
fn compute_batch(
pairs: &[(&Self::G1Point, &Self::G2Point)],
) -> Result<FieldElement<Self::OutputField>, PairingError>;
Expand Down
Loading
Loading