Skip to content
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

Endo #128

Merged
merged 39 commits into from
Nov 3, 2021
Merged

Endo #128

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
ad8851b
Initial functions
DanieleDiBenedetto Feb 16, 2021
99ad511
Endomorphism implementation
phoinic Feb 22, 2021
8b10e09
Tweedle added to r1cs
phoinic Feb 22, 2021
cb4cc6e
Endomorphism implementation for all curves
phoinic Feb 22, 2021
9079f75
mnt6 feature removed from full
phoinic Feb 22, 2021
2ea76ad
Endo gadget experiments
phoinic Feb 28, 2021
5d629da
merge: endo branch merged with audit_fixes
phoinic Jul 13, 2021
5e408d8
endo mul gadget: first steps
phoinic Jul 15, 2021
20b0888
sc_testnet_2 initial commit
DanieleDiBenedetto Sep 2, 2021
2117d44
Merge branch 'proof_size_optimization' into endo
phoinic Sep 26, 2021
b29963e
Endo mul gadget implementation
phoinic Sep 30, 2021
e8b21bd
Fix endo_rep_to_scalar algorithm
phoinic Oct 3, 2021
7b5b53d
Merge branch 'sc_testnet_2' into endo_proof_size_opt
phoinic Oct 5, 2021
8030388
Updating UTs for endo gadget
phoinic Oct 5, 2021
bc56da4
Endo gadget optimization
phoinic Oct 5, 2021
468295a
Cleanup comments
phoinic Oct 5, 2021
8804cf2
Comment for endo_mul updated
phoinic Oct 5, 2021
42aee87
endo merge and optimization
phoinic Oct 9, 2021
d65e6f6
Added the Sage scripts for checking field parameters. With respect to…
Oct 11, 2021
e5b32f7
added endo mul inline docu
UlrichHaboeck75 Oct 18, 2021
7c7545a
Applied the changes suggested by Ulrich about endo_mul parameters.
Oct 19, 2021
1791773
Refactored endo mul native implementation
phoinic Oct 25, 2021
30e0c89
Refactored endo implementation
phoinic Oct 27, 2021
89904fc
Endo mul for 'short_weierstrass_projective' model
phoinic Oct 27, 2021
780ae5f
Additional implementations and bits paddings
phoinic Oct 27, 2021
5007fca
nonnative endo implementation
phoinic Oct 27, 2021
f9a9e44
Modified to check_curve_parameters.sage according to Ulrich's request…
Oct 27, 2021
690abe5
Modified to check_curve_parameters.sage according to Ulrich's request…
Oct 27, 2021
8cf7170
Modified to check_curve_parameters.sage according to Ulrich's request…
Oct 27, 2021
4c9232c
Merge branch 'endo' of https://github.com/HorizenOfficial/ginger-lib …
Oct 27, 2021
7fafe74
Endo generic test
phoinic Oct 28, 2021
40cb120
Merge branch 'rc/audit_chain' into endo_merge
phoinic Oct 28, 2021
116d558
Merge branch 'development' into endo_merge
phoinic Oct 28, 2021
5687c47
Generic endo mul UT optimized
phoinic Oct 28, 2021
6787407
Branch switched to endo
phoinic Oct 28, 2021
177e813
Sync with pc/marlin endo branches
phoinic Oct 28, 2021
bcd8fd6
additional inline doc
UlrichHaboeck75 Nov 2, 2021
3b51d3f
Resolved conflicts in check_curve_parameters.sage
Nov 3, 2021
42470dc
Parameter LAMBDA read from from the curve file, as requested by Ulrich.
Nov 3, 2021
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ Cargo.lock
*.orig
coeffs_*
msm_bases_*
*.py
2 changes: 1 addition & 1 deletion algebra/src/curves/bls12_377/g1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::{
biginteger::{BigInteger256, BigInteger384},
curves::models::{ModelParameters, SWModelParameters},
fields::{
bls12_377::{Fq, Fr},
bls12_377::*,
Field,
},
};
Expand Down
2 changes: 1 addition & 1 deletion algebra/src/curves/bls12_377/g2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::{
biginteger::{BigInteger256, BigInteger384},
curves::models::{ModelParameters, SWModelParameters},
fields::{
bls12_377::{Fq, Fq2, Fr},
bls12_377::*,
Field,
},
};
Expand Down
2 changes: 1 addition & 1 deletion algebra/src/curves/bls12_381/g1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::{
models::{ModelParameters, SWModelParameters},
},
fields::{
bls12_381::{Fq, Fr},
bls12_381::*,
Field,
},
};
Expand Down
2 changes: 1 addition & 1 deletion algebra/src/curves/bls12_381/g2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::{
models::{ModelParameters, SWModelParameters},
},
fields::{
bls12_381::{Fq, Fq2, Fr},
bls12_381::*,
Field,
},
};
Expand Down
72 changes: 68 additions & 4 deletions algebra/src/curves/check_curve_parameters.sage
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
# The following Sage script check the consistency of the following curves parameters:
#
# 1) P=(GENERATOR_X,GENERATOR_Y) must belongs to the curve of equation E: y^2 = x^3 + Ax + B
# 1) P=(GENERATOR_X,GENERATOR_Y) must belongs to the curve of equation E: y^2 = x^3 + Ax + B
# 2) P must have order equal to the MODULUS of the scalar field
# 3) COFACTOR must be equal to Order(E)/Order(P)
# 4) COFACTOR_INV must be the inverse of COFACTOR in the scalar Field
# 5) ENDO_COEFF must be a cube root in the base field.
# 6) ENDO_SCALAR must be a cube root in the scalar field and satisfy ENDO_SCALAR * (X, Y) == (ENDO_COEFF * X, Y)
# 7) The intersection of the plane lattice spanned by {(1, ENDO_SCALAR), (0, SCALAR_FIELD_MODULUS)} with the square [-A,A]^2 must be empty,
# where A = 2^(LAMBDA/2 + 1) + 2^(LAMBDA/2) + 1.
# Open Sage Shell in the corresponding folder and run the command
# "sage check_curve_paramaters sage [file_path_curve] [file_path_basefield] [file_path_scalarfield]".

Expand Down Expand Up @@ -65,10 +69,10 @@ scalar_field_name = re.findall(pattern, readfile)[0]
fn = "(?:" + base_field_name + "|" + scalar_field_name + ")" #fn = field name = "(:?Fr|Fq)". Useful declaration for the pattern

#### Reading the big integers list and extracting names and values
pattern = "const\s+(\w+):\s*" + fn + "\s*=\s*field_new!\(\s*" + fn + "\s*,\s*BigInteger\d*\s*\(\s*\[" + "([0-9a-fA-Fxu\s,]+)\s*" + "\]\s*\)"
pattern = "const\s+(\w+)[:\w\s]*=\s*field_new!\([\s\w,]*\(\s*\[" + "([0-9a-fA-Fxu\s,]+)\s*" + "\]\s*\)"
big_int_ls = re.findall(pattern,readfile) #####list of couples of the form ('[VARIABLE_NAME]',"[u64],..,[u64]")

big_int_names = [b[0] for b in big_int_ls]
big_int_names = [b[0] for b in big_int_ls]
big_int_values = [BigInteger_to_number(b[1]) for b in big_int_ls]

BigIntegerLen = BigInteger_len(big_int_ls[0][1])
Expand All @@ -87,6 +91,10 @@ for s in big_int_names:
pattern = "const\s+COFACTOR:\s*&'static\s*\[u64\]\s*=\s*&\[([0-9a-fA-Fxu\s,]+)\]\s*;"
COFACTOR = BigInteger_to_number(re.findall(pattern,readfile)[0])

####Reading the value of LAMBDA
pattern = "const\s+LAMBDA[:\w\s]*=\s*([\d]+)\s*;"
LAMBDA = int(re.findall(pattern,readfile)[0])

#######################################Reading the values from the file containing the Base Field parameters########################
filename = sys.argv[2]

Expand Down Expand Up @@ -163,4 +171,60 @@ else:
if Fr(COFACTOR) * Fr(COFACTOR_INV) == Fr(SCALAR_FIELD_R):
print("Correct. COFACTOR_INV is the inverse of COFACTOR in the the scalar field.")
else:
print("WARNING! COFACTOR_INV IS NOT THE INVERSE OF COFACTOR IN THE SCALAR FIELD!")
print("WARNING! COFACTOR_INV IS NOT THE INVERSE OF COFACTOR IN THE SCALAR FIELD!")
####### Checking the correctness of ENDO_COEFF and ENDO_FACTOR ############
endo_mul_is_used = False
if 'ENDO_COEFF' in locals() and 'ENDO_SCALAR' in locals():
zeta_q = Fq(ENDO_COEFF) * Fq(BASE_FIELD_R)**(-1)
if zeta_q**2 + zeta_q == Fq(-1):
endo_mul_is_used = True
print("Correct. ENDO_COEFF is a primitive cube root of unity.")
else:
print("WARNING! ENDO_COEFF IS NOT A PRIMITIVE CUBE ROOT OF UNITY.")
zeta_r = Fr(ENDO_SCALAR) * Fr(SCALAR_FIELD_R)**(-1)
if zeta_r**2 + zeta_r == Fr(-1):
print("Correct. ENDO_SCALAR is a primitive cube root of unity.")
else:
print("WARNING! ENDO_SCALAR IS NOT A PRIMITIVE CUBE ROOT OF UNITY.")


####### Checking the consistency of ENDO_COEFF and ENDO_SCALAR #############
if endo_mul_is_used:
Q = int(zeta_r) * P
if Q == E([zeta_q * X, Y]):
print("Correct. ENDO_COEFF and ENDO_SCALAR are consistent.")
else:
print("WARNING! ENDO_COEFF AND ENDO_SCALAR ARE NOT CONSISTENT!")


########## Checking that shortest vector in the lattice ([1,zeta_r),[0,r]) is long enough #########
## The Halo paper (https://eprint.iacr.org/2019/1021.pdf) proves the injectivity of the endo_mul map.
## The injectivity of the map (a,b) |-> a\zeta + b for a,b in [0,A] (essential for using add_unsafe)
## is equivalent the lattice condition below.
## a*zeta + b = a'*zeta_r + b' mod r for a,a',b,b' in [0,A]
## is equivalent to the fact that there are non-zero solutions to
## a * zeta_r = b mod r for a,b in [-A,A].
## Then it would exists c such that
## b = a * zeta_r + c * r.
## Any such solution correspond to a point of the lattice spanned by (1, zeta_r) and (0, r).
## (a, b) = (a, c) * (1 zeta_r)
## (0 r )
## The injectivity is equivalent to the fact that the intersection between this lattice and [-A, A]^2
## is trivial. To verify this we first compute a LLL reduced basis {v,w} and
## then check if at least one of v, w, v + w, v - w is belongs to such a square.
## If not, there can't be other lattice points in the square.
if endo_mul_is_used:
A = 2**(LAMBDA//2 + 1) + 2**(LAMBDA//2) + 1
L = Matrix([[1,Integer(zeta_r)],[0,SCALAR_FIELD_MODULUS]])
Lred = L.LLL()
set = [Lred.row(0), Lred.row(1), Lred.row(0) - Lred.row(1), Lred.row(0) + Lred.row(1)]
add_unsafe = True
for v in set:
if abs(v[0]) <= A and abs(v[1]) <= A:
add_unsafe = False
if add_unsafe:
print("We can use add_unsafe for endo_mul.")
else:
print("WARNING! WE CAN'T USE add_unsafe FOR endo_mul!")
else:
print("endo_mul is not used for this curve.")
2 changes: 1 addition & 1 deletion algebra/src/curves/mnt6/g1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::{
short_weierstrass_projective::{GroupAffine, GroupProjective},
AffineCurve,
},
fields::mnt6::{Fq, Fq3, Fr},
fields::mnt6::*,
};
use crate::{field_new, FromBytes};
use serde::{Deserialize, Serialize};
Expand Down
2 changes: 1 addition & 1 deletion algebra/src/curves/mnt6/g2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::{
short_weierstrass_projective::{GroupAffine, GroupProjective},
AffineCurve,
},
fields::mnt6::{Fq, Fq3, Fr},
fields::mnt6::*,
};
use crate::{field_new, FromBytes};
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
Expand Down
15 changes: 15 additions & 0 deletions algebra/src/curves/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,21 @@ pub trait AffineCurve:
fn mul_by_cofactor_inv(&self) -> Self;
}

/// The `EndoMulCurve` trait for curves that have a non-trivial endomorphism
/// `Phi` of the form `Phi(x,y) = (zeta*x,y)`.
pub trait EndoMulCurve: AffineCurve {
/// Apply `Phi`
fn apply_endomorphism(&self) -> Self;

/// Conversion of a bit sequence used in `endo_mul()` into its equivalent
/// scalar
fn endo_rep_to_scalar(bits: Vec<bool>) -> Result<Self::ScalarField, Error>;

/// Endomorphism-based multiplication of `&self` with `bits`, a little-endian
/// endomorphism representation.
fn endo_mul(&self, bits: Vec<bool>) -> Result<Self::Projective, Error>;
}

impl<C: ProjectiveCurve> Group for C {
type ScalarField = C::ScalarField;
#[must_use]
Expand Down
19 changes: 19 additions & 0 deletions algebra/src/curves/models/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,3 +122,22 @@ pub trait MontgomeryModelParameters: ModelParameters {

type TEModelParameters: TEModelParameters<BaseField = Self::BaseField>;
}

pub trait EndoMulParameters: SWModelParameters {
/// Parameters for endomorphism-based scalar multiplication [Halo](https://eprint.iacr.org/2019/1021).
/// A non-trivial cubic root of unity `ENDO_COEFF` for a curve endomorphism of the form
/// (x, y) -> (ENDO_COEFF * x, y).
const ENDO_COEFF: Self::BaseField;

/// The scalar representation `zeta_r` of `ENDO_COEFF`.
/// NOTE : If one wants to use the endo mul circuit with `lambda` many bits,
/// then `zeta_r` MUST satisfy the minimal distance property
/// D = min { d(n*zeta_r, m*zeta_r) : n,m in [0, T] } >= R + 1,
/// where `T = 2^{lambda/2 + 1} + 2^{lambda/2} - 1` is the output
/// bound for the coefficients a, b of the equivalent scalar
/// representation `a*zeta_r + b`.
const ENDO_SCALAR: Self::ScalarField;

/// Maximum number of bits for which security of endo mul is proven. MUST be an even number.
const LAMBDA: usize;
}
98 changes: 97 additions & 1 deletion algebra/src/curves/models/short_weierstrass_jacobian.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use crate::{
bytes::{FromBytes, ToBytes},
curves::{models::SWModelParameters as Parameters, AffineCurve, ProjectiveCurve},
curves::{models::{
SWModelParameters as Parameters,
EndoMulParameters as EndoParameters,
}, AffineCurve, ProjectiveCurve, EndoMulCurve},
fields::{BitIterator, Field, PrimeField, SquareRootField},
BitSerializationError, CanonicalDeserialize, CanonicalDeserializeWithFlags, CanonicalSerialize,
CanonicalSerializeWithFlags, Error, FromBytesChecked, FromCompressedBits, SWFlags,
Expand Down Expand Up @@ -295,6 +298,99 @@ impl<P: Parameters> AffineCurve for GroupAffine<P> {
}
}

DanieleDiBenedetto marked this conversation as resolved.
Show resolved Hide resolved
impl<P: EndoParameters> EndoMulCurve for GroupAffine<P> {
DanieleDiBenedetto marked this conversation as resolved.
Show resolved Hide resolved

fn apply_endomorphism(&self) -> Self {
let mut self_e = self.clone();
self_e.x.mul_assign(P::ENDO_COEFF);
self_e
}

fn endo_rep_to_scalar(bits: Vec<bool>) -> Result<Self::ScalarField, Error> {

let mut a : P::ScalarField = 2u64.into();
let mut b : P::ScalarField = 2u64.into();

let one = P::ScalarField::one();
let one_neg = one.neg();

let mut bits = bits;
if bits.len() % 2 == 1 {
bits.push(false);
}

if bits.len() > P::LAMBDA {
Err("Endo mul bits length exceeds LAMBDA")?
}

for i in (0..(bits.len() / 2)).rev() {
a.double_in_place();
b.double_in_place();

let s =
if bits[i * 2] {
&one
} else {
&one_neg
};

if bits[i * 2 + 1] {
a.add_assign(s);
} else {
b.add_assign(s);
}
}

Ok(a.mul(P::ENDO_SCALAR) + &b)
}

/// Endomorphism-based multiplication of a curve point
/// with a scalar in little-endian endomorphism representation.
fn endo_mul(&self, bits: Vec<bool>) -> Result<Self::Projective, Error> {

let self_neg = self.neg();

let self_e = self.apply_endomorphism();
let self_e_neg = self_e.neg();

let mut acc = self_e.into_projective();
acc.add_assign_mixed(&self);
acc.double_in_place();

let mut bits = bits;
if bits.len() % 2 == 1 {
bits.push(false);
}

if bits.len() > P::LAMBDA {
Err("Endo mul bits length exceeds LAMBDA")?
}

for i in (0..(bits.len() / 2)).rev() {

let s =
if bits[i * 2 + 1] {
if bits[i * 2] {
&self_e
} else {
&self_e_neg
}
} else {
if bits[i * 2] {
&self
} else {
&self_neg
}
};

acc.double_in_place();
acc.add_assign_mixed(s);
Comment on lines +386 to +387
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DDT92 Can we use, also for the primitive (and also for the normal double_and_add not necessarily only endo_mul), a double_and_add op (e.g. (Acc + P) + Acc) ? Will it be more efficient than doing 2Acc + P ?

}

Ok(acc)
}
}

impl<P: Parameters> SemanticallyValid for GroupAffine<P> {
fn is_valid(&self) -> bool {
self.x.is_valid() && self.y.is_valid() && self.group_membership_test()
Expand Down
Loading